mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2026-06-07 19:59:14 -04:00
refactor(Hyprland): updates to Lua syntax/dispatchers
This commit is contained in:
@@ -493,6 +493,31 @@ func splitHyprlandAction(action string) (dispatcher, params string) {
|
|||||||
return strings.ToLower(strings.TrimSpace(action[:idx])), strings.TrimSpace(action[idx+1:])
|
return strings.ToLower(strings.TrimSpace(action[:idx])), strings.TrimSpace(action[idx+1:])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func isKnownHyprlandDispatcher(dispatcher string) bool {
|
||||||
|
switch dispatcher {
|
||||||
|
case "exec", "execr", "spawn",
|
||||||
|
"killactive", "forcekillactive", "closewindow", "killwindow",
|
||||||
|
"signal", "signalwindow", "togglefloating", "setfloating", "settiled",
|
||||||
|
"workspace", "renameworkspace", "fullscreen", "fullscreenstate", "fakefullscreen",
|
||||||
|
"movetoworkspace", "movetoworkspacesilent", "pseudo", "movefocus",
|
||||||
|
"movewindow", "swapwindow", "centerwindow", "togglegroup", "changegroupactive",
|
||||||
|
"movegroupwindow", "focusmonitor", "movecursortocorner", "movecursor",
|
||||||
|
"workspaceopt", "exit", "movecurrentworkspacetomonitor", "focusworkspaceoncurrentmonitor",
|
||||||
|
"moveworkspacetomonitor", "togglespecialworkspace", "forcerendererreload",
|
||||||
|
"resizeactive", "moveactive", "cyclenext", "focuswindowbyclass", "focuswindow",
|
||||||
|
"tagwindow", "toggleswallow", "submap", "pass", "sendshortcut", "sendkeystate",
|
||||||
|
"layoutmsg", "splitratio", "dpms", "movewindowpixel", "resizewindowpixel",
|
||||||
|
"swapnext", "swapactiveworkspaces", "pin", "mouse", "bringactivetotop",
|
||||||
|
"alterzorder", "focusurgentorlast", "focuscurrentorlast", "lockgroups",
|
||||||
|
"lockactivegroup", "moveintogroup", "moveoutofgroup", "movewindoworgroup",
|
||||||
|
"moveintoorcreategroup", "setignoregrouplock", "denywindowfromgroup", "event",
|
||||||
|
"global", "setprop", "forceidle":
|
||||||
|
return true
|
||||||
|
default:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func firstParam(params string) (head, rest string) {
|
func firstParam(params string) (head, rest string) {
|
||||||
params = strings.TrimSpace(params)
|
params = strings.TrimSpace(params)
|
||||||
if params == "" {
|
if params == "" {
|
||||||
@@ -551,29 +576,181 @@ func dispatcherActiveMoveResize(funcName, params string) string {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func dispatcherWindowMoveResize(funcName, params string) string {
|
||||||
|
geometry, window := splitCommaParams(params)
|
||||||
|
x, y, relative, ok := xyParams(geometry)
|
||||||
|
if !ok {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
if !isBareLuaNumber(x) || !isBareLuaNumber(y) {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
fields := []luaField{
|
||||||
|
luaNumberOrStringField("x", x),
|
||||||
|
luaNumberOrStringField("y", y),
|
||||||
|
luaBoolField("relative", relative),
|
||||||
|
}
|
||||||
|
if window != "" {
|
||||||
|
fields = append(fields, luaStringField("window", window))
|
||||||
|
}
|
||||||
|
return luaDispatcherTableCall(funcName, fields...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func splitCommaParams(params string) (left, right string) {
|
||||||
|
left = strings.TrimSpace(params)
|
||||||
|
if idx := strings.Index(left, ","); idx >= 0 {
|
||||||
|
right = strings.TrimSpace(left[idx+1:])
|
||||||
|
left = strings.TrimSpace(left[:idx])
|
||||||
|
}
|
||||||
|
return left, right
|
||||||
|
}
|
||||||
|
|
||||||
|
func luaHyprctlDispatchFunction(action string) string {
|
||||||
|
return fmt.Sprintf(`function() hl.exec_cmd(%s) end`, strconv.Quote("hyprctl dispatch "+strings.TrimSpace(action)))
|
||||||
|
}
|
||||||
|
|
||||||
|
func luaToggleActionValue(params string) string {
|
||||||
|
switch strings.ToLower(strings.TrimSpace(params)) {
|
||||||
|
case "on", "enable", "enabled", "set", "lock":
|
||||||
|
return "on"
|
||||||
|
case "off", "disable", "disabled", "unset", "unlock":
|
||||||
|
return "off"
|
||||||
|
default:
|
||||||
|
return "toggle"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func dispatcherToggleTableCall(funcName, params string) string {
|
||||||
|
return luaDispatcherTableCall(funcName, luaStringField("action", luaToggleActionValue(params)))
|
||||||
|
}
|
||||||
|
|
||||||
|
func dispatcherCycleNext(params string) string {
|
||||||
|
params = strings.TrimSpace(strings.ToLower(params))
|
||||||
|
if params == "" {
|
||||||
|
return `hl.dsp.window.cycle_next()`
|
||||||
|
}
|
||||||
|
fields := []luaField{}
|
||||||
|
for _, field := range strings.Fields(params) {
|
||||||
|
switch field {
|
||||||
|
case "prev", "previous", "b":
|
||||||
|
fields = append(fields, luaBoolField("next", false))
|
||||||
|
case "next", "f":
|
||||||
|
fields = append(fields, luaBoolField("next", true))
|
||||||
|
case "tiled":
|
||||||
|
fields = append(fields, luaBoolField("tiled", true))
|
||||||
|
case "floating":
|
||||||
|
fields = append(fields, luaBoolField("floating", true))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(fields) == 0 {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return luaDispatcherTableCall("hl.dsp.window.cycle_next", fields...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func dispatcherSwapNext(params string) string {
|
||||||
|
switch strings.ToLower(strings.TrimSpace(params)) {
|
||||||
|
case "prev", "previous", "b":
|
||||||
|
return `hl.dsp.window.swap({ prev = true })`
|
||||||
|
default:
|
||||||
|
return `hl.dsp.window.swap({ next = true })`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func dispatcherGroupActive(params string) string {
|
||||||
|
switch strings.ToLower(strings.TrimSpace(params)) {
|
||||||
|
case "f", "next", "forward":
|
||||||
|
return `hl.dsp.group.next()`
|
||||||
|
case "b", "prev", "previous", "backward":
|
||||||
|
return `hl.dsp.group.prev()`
|
||||||
|
}
|
||||||
|
if isBareLuaNumber(params) {
|
||||||
|
return luaDispatcherTableCall("hl.dsp.group.active", luaNumberOrStringField("index", params))
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func dispatcherMoveGroupWindow(params string) string {
|
||||||
|
switch strings.ToLower(strings.TrimSpace(params)) {
|
||||||
|
case "b", "prev", "previous", "backward":
|
||||||
|
return `hl.dsp.group.move_window({ forward = false })`
|
||||||
|
default:
|
||||||
|
return `hl.dsp.group.move_window({ forward = true })`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func dispatcherCursorMove(params string) string {
|
||||||
|
x, y, _, ok := xyParams(params)
|
||||||
|
if !ok || !isBareLuaNumber(x) || !isBareLuaNumber(y) {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return luaDispatcherTableCall("hl.dsp.cursor.move", luaNumberOrStringField("x", x), luaNumberOrStringField("y", y))
|
||||||
|
}
|
||||||
|
|
||||||
|
func dispatcherSignal(params string) string {
|
||||||
|
signal, window := firstParam(params)
|
||||||
|
if signal == "" || !isBareLuaNumber(signal) {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
fields := []luaField{luaNumberOrStringField("signal", signal)}
|
||||||
|
if window != "" {
|
||||||
|
fields = append(fields, luaStringField("window", window))
|
||||||
|
}
|
||||||
|
return luaDispatcherTableCall("hl.dsp.window.signal", fields...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func dispatcherSignalWindow(params string) string {
|
||||||
|
window, rest := firstParam(params)
|
||||||
|
signal, _ := firstParam(rest)
|
||||||
|
if signal == "" || !isBareLuaNumber(signal) {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
fields := []luaField{luaNumberOrStringField("signal", signal)}
|
||||||
|
if window != "" {
|
||||||
|
fields = append(fields, luaStringField("window", window))
|
||||||
|
}
|
||||||
|
return luaDispatcherTableCall("hl.dsp.window.signal", fields...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func dispatcherTagWindow(params string) string {
|
||||||
|
tag, window := firstParam(params)
|
||||||
|
if tag == "" {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
fields := []luaField{luaStringField("tag", tag)}
|
||||||
|
if window != "" {
|
||||||
|
fields = append(fields, luaStringField("window", window))
|
||||||
|
}
|
||||||
|
return luaDispatcherTableCall("hl.dsp.window.tag", fields...)
|
||||||
|
}
|
||||||
|
|
||||||
func luaActionStringFromKnownHyprlandAction(action string) (string, bool) {
|
func luaActionStringFromKnownHyprlandAction(action string) (string, bool) {
|
||||||
dispatcher, params := splitHyprlandAction(action)
|
dispatcher, params := splitHyprlandAction(action)
|
||||||
switch dispatcher {
|
switch dispatcher {
|
||||||
case "spawn", "exec":
|
case "spawn", "exec":
|
||||||
return fmt.Sprintf(`hl.dsp.exec_cmd(%s)`, strconv.Quote(params)), true
|
return fmt.Sprintf(`hl.dsp.exec_cmd(%s)`, strconv.Quote(params)), true
|
||||||
|
case "execr":
|
||||||
|
return fmt.Sprintf(`hl.dsp.exec_raw(%s)`, strconv.Quote(params)), true
|
||||||
case "killactive":
|
case "killactive":
|
||||||
return `hl.dsp.window.kill()`, true
|
return `hl.dsp.window.kill()`, true
|
||||||
|
case "forcekillactive":
|
||||||
|
return `hl.dsp.window.kill()`, true
|
||||||
case "closewindow":
|
case "closewindow":
|
||||||
if params == "" {
|
if params == "" {
|
||||||
return `hl.dsp.window.close()`, true
|
return `hl.dsp.window.close()`, true
|
||||||
}
|
}
|
||||||
return fmt.Sprintf(`hl.dsp.window.close(%s)`, strconv.Quote(params)), true
|
return luaDispatcherTableCall("hl.dsp.window.close", luaStringField("window", params)), true
|
||||||
case "killwindow":
|
case "killwindow":
|
||||||
if params == "" {
|
if params == "" {
|
||||||
return `hl.dsp.window.kill()`, true
|
return `hl.dsp.window.kill()`, true
|
||||||
}
|
}
|
||||||
return fmt.Sprintf(`hl.dsp.window.kill(%s)`, strconv.Quote(params)), true
|
return luaDispatcherTableCall("hl.dsp.window.kill", luaStringField("window", params)), true
|
||||||
case "togglefloating":
|
case "togglefloating":
|
||||||
return `hl.dsp.window.float({ action = "toggle" })`, true
|
return dispatcherToggleTableCall("hl.dsp.window.float", "toggle"), true
|
||||||
case "setfloating":
|
case "setfloating":
|
||||||
return `hl.dsp.window.float({ action = "set" })`, true
|
return dispatcherToggleTableCall("hl.dsp.window.float", "on"), true
|
||||||
case "settiled":
|
case "settiled":
|
||||||
return `hl.dsp.window.float({ action = "unset" })`, true
|
return dispatcherToggleTableCall("hl.dsp.window.float", "off"), true
|
||||||
case "fullscreen":
|
case "fullscreen":
|
||||||
mode := strings.TrimSpace(params)
|
mode := strings.TrimSpace(params)
|
||||||
switch mode {
|
switch mode {
|
||||||
@@ -582,6 +759,7 @@ func luaActionStringFromKnownHyprlandAction(action string) (string, bool) {
|
|||||||
case "1":
|
case "1":
|
||||||
return `hl.dsp.window.fullscreen({ mode = "maximized", action = "toggle" })`, true
|
return `hl.dsp.window.fullscreen({ mode = "maximized", action = "toggle" })`, true
|
||||||
}
|
}
|
||||||
|
return luaHyprctlDispatchFunction(action), true
|
||||||
case "fullscreenstate":
|
case "fullscreenstate":
|
||||||
internal, rest := firstParam(params)
|
internal, rest := firstParam(params)
|
||||||
client, _ := firstParam(rest)
|
client, _ := firstParam(rest)
|
||||||
@@ -591,10 +769,15 @@ func luaActionStringFromKnownHyprlandAction(action string) (string, bool) {
|
|||||||
luaNumberOrStringField("client", client),
|
luaNumberOrStringField("client", client),
|
||||||
), true
|
), true
|
||||||
}
|
}
|
||||||
|
case "fakefullscreen":
|
||||||
|
return luaHyprctlDispatchFunction(action), true
|
||||||
case "pin":
|
case "pin":
|
||||||
if params == "" {
|
if params == "" {
|
||||||
return `hl.dsp.window.pin()`, true
|
return `hl.dsp.window.pin()`, true
|
||||||
}
|
}
|
||||||
|
return dispatcherToggleTableCall("hl.dsp.window.pin", params), true
|
||||||
|
case "pseudo":
|
||||||
|
return dispatcherToggleTableCall("hl.dsp.window.pseudo", params), true
|
||||||
case "centerwindow":
|
case "centerwindow":
|
||||||
return `hl.dsp.window.center()`, true
|
return `hl.dsp.window.center()`, true
|
||||||
case "resizewindow":
|
case "resizewindow":
|
||||||
@@ -612,14 +795,28 @@ func luaActionStringFromKnownHyprlandAction(action string) (string, bool) {
|
|||||||
return "", false
|
return "", false
|
||||||
}
|
}
|
||||||
return luaDispatcherTableCall("hl.dsp.window.swap", luaStringField("direction", params)), true
|
return luaDispatcherTableCall("hl.dsp.window.swap", luaStringField("direction", params)), true
|
||||||
|
case "swapnext":
|
||||||
|
return dispatcherSwapNext(params), true
|
||||||
case "resizeactive":
|
case "resizeactive":
|
||||||
if expr := dispatcherActiveMoveResize("hl.dsp.window.resize", params); expr != "" {
|
if expr := dispatcherActiveMoveResize("hl.dsp.window.resize", params); expr != "" {
|
||||||
return expr, true
|
return expr, true
|
||||||
}
|
}
|
||||||
|
return luaHyprctlDispatchFunction(action), true
|
||||||
case "moveactive":
|
case "moveactive":
|
||||||
if expr := dispatcherActiveMoveResize("hl.dsp.window.move", params); expr != "" {
|
if expr := dispatcherActiveMoveResize("hl.dsp.window.move", params); expr != "" {
|
||||||
return expr, true
|
return expr, true
|
||||||
}
|
}
|
||||||
|
return luaHyprctlDispatchFunction(action), true
|
||||||
|
case "resizewindowpixel":
|
||||||
|
if expr := dispatcherWindowMoveResize("hl.dsp.window.resize", params); expr != "" {
|
||||||
|
return expr, true
|
||||||
|
}
|
||||||
|
return luaHyprctlDispatchFunction(action), true
|
||||||
|
case "movewindowpixel":
|
||||||
|
if expr := dispatcherWindowMoveResize("hl.dsp.window.move", params); expr != "" {
|
||||||
|
return expr, true
|
||||||
|
}
|
||||||
|
return luaHyprctlDispatchFunction(action), true
|
||||||
case "workspace":
|
case "workspace":
|
||||||
if params == "" {
|
if params == "" {
|
||||||
return "", false
|
return "", false
|
||||||
@@ -662,6 +859,8 @@ func luaActionStringFromKnownHyprlandAction(action string) (string, bool) {
|
|||||||
if workspace != "" && monitor != "" {
|
if workspace != "" && monitor != "" {
|
||||||
return luaDispatcherTableCall("hl.dsp.workspace.move", luaStringField("workspace", workspace), luaStringField("monitor", monitor)), true
|
return luaDispatcherTableCall("hl.dsp.workspace.move", luaStringField("workspace", workspace), luaStringField("monitor", monitor)), true
|
||||||
}
|
}
|
||||||
|
case "workspaceopt":
|
||||||
|
return luaHyprctlDispatchFunction(action), true
|
||||||
case "swapactiveworkspaces":
|
case "swapactiveworkspaces":
|
||||||
monitor1, rest := firstParam(params)
|
monitor1, rest := firstParam(params)
|
||||||
monitor2, _ := firstParam(rest)
|
monitor2, _ := firstParam(rest)
|
||||||
@@ -680,14 +879,25 @@ func luaActionStringFromKnownHyprlandAction(action string) (string, bool) {
|
|||||||
if params != "" {
|
if params != "" {
|
||||||
return luaDispatcherTableCall("hl.dsp.focus", luaStringField("window", params)), true
|
return luaDispatcherTableCall("hl.dsp.focus", luaStringField("window", params)), true
|
||||||
}
|
}
|
||||||
|
case "focuswindowbyclass":
|
||||||
|
if params != "" {
|
||||||
|
return luaDispatcherTableCall("hl.dsp.focus", luaStringField("window", "class:"+params)), true
|
||||||
|
}
|
||||||
case "focuscurrentorlast":
|
case "focuscurrentorlast":
|
||||||
return `hl.dsp.focus({ last = true })`, true
|
return `hl.dsp.focus({ last = true })`, true
|
||||||
case "focusurgentorlast":
|
case "focusurgentorlast":
|
||||||
return `hl.dsp.focus({ urgent_or_last = true })`, true
|
return `hl.dsp.focus({ urgent_or_last = true })`, true
|
||||||
|
case "cyclenext":
|
||||||
|
if expr := dispatcherCycleNext(params); expr != "" {
|
||||||
|
return expr, true
|
||||||
|
}
|
||||||
|
return luaHyprctlDispatchFunction(action), true
|
||||||
case "layoutmsg":
|
case "layoutmsg":
|
||||||
if params != "" {
|
if params != "" {
|
||||||
return fmt.Sprintf(`hl.dsp.layout(%s)`, strconv.Quote(params)), true
|
return fmt.Sprintf(`hl.dsp.layout(%s)`, strconv.Quote(params)), true
|
||||||
}
|
}
|
||||||
|
case "splitratio":
|
||||||
|
return luaHyprctlDispatchFunction(action), true
|
||||||
case "alterzorder":
|
case "alterzorder":
|
||||||
mode, window := firstParam(params)
|
mode, window := firstParam(params)
|
||||||
if mode != "" {
|
if mode != "" {
|
||||||
@@ -707,6 +917,22 @@ func luaActionStringFromKnownHyprlandAction(action string) (string, bool) {
|
|||||||
luaStringField("value", value),
|
luaStringField("value", value),
|
||||||
), true
|
), true
|
||||||
}
|
}
|
||||||
|
case "bringactivetotop":
|
||||||
|
return `hl.dsp.window.bring_to_top()`, true
|
||||||
|
case "toggleswallow":
|
||||||
|
return `hl.dsp.window.toggle_swallow()`, true
|
||||||
|
case "signal":
|
||||||
|
if expr := dispatcherSignal(params); expr != "" {
|
||||||
|
return expr, true
|
||||||
|
}
|
||||||
|
case "signalwindow":
|
||||||
|
if expr := dispatcherSignalWindow(params); expr != "" {
|
||||||
|
return expr, true
|
||||||
|
}
|
||||||
|
case "tagwindow":
|
||||||
|
if expr := dispatcherTagWindow(params); expr != "" {
|
||||||
|
return expr, true
|
||||||
|
}
|
||||||
case "dpms":
|
case "dpms":
|
||||||
dpmsAction := strings.TrimSpace(params)
|
dpmsAction := strings.TrimSpace(params)
|
||||||
switch dpmsAction {
|
switch dpmsAction {
|
||||||
@@ -753,8 +979,57 @@ func luaActionStringFromKnownHyprlandAction(action string) (string, bool) {
|
|||||||
}
|
}
|
||||||
return luaDispatcherTableCall("hl.dsp.send_key_state", fields...), true
|
return luaDispatcherTableCall("hl.dsp.send_key_state", fields...), true
|
||||||
}
|
}
|
||||||
|
case "movecursortocorner":
|
||||||
|
if params != "" && isBareLuaNumber(params) {
|
||||||
|
return luaDispatcherTableCall("hl.dsp.cursor.move_to_corner", luaNumberOrStringField("corner", params)), true
|
||||||
|
}
|
||||||
|
case "movecursor":
|
||||||
|
if expr := dispatcherCursorMove(params); expr != "" {
|
||||||
|
return expr, true
|
||||||
|
}
|
||||||
case "togglegroup":
|
case "togglegroup":
|
||||||
return `hl.dsp.group.toggle()`, true
|
return `hl.dsp.group.toggle()`, true
|
||||||
|
case "changegroupactive":
|
||||||
|
if expr := dispatcherGroupActive(params); expr != "" {
|
||||||
|
return expr, true
|
||||||
|
}
|
||||||
|
return luaHyprctlDispatchFunction(action), true
|
||||||
|
case "movegroupwindow":
|
||||||
|
return dispatcherMoveGroupWindow(params), true
|
||||||
|
case "moveintogroup":
|
||||||
|
if params != "" {
|
||||||
|
return luaDispatcherTableCall("hl.dsp.window.move", luaStringField("into_group", params)), true
|
||||||
|
}
|
||||||
|
case "moveintoorcreategroup":
|
||||||
|
if params != "" {
|
||||||
|
return luaDispatcherTableCall("hl.dsp.window.move", luaStringField("into_or_create_group", params)), true
|
||||||
|
}
|
||||||
|
case "moveoutofgroup":
|
||||||
|
if params != "" {
|
||||||
|
return luaDispatcherTableCall("hl.dsp.window.move", luaStringField("out_of_group", params)), true
|
||||||
|
}
|
||||||
|
return luaDispatcherTableCall("hl.dsp.window.move", luaBoolField("out_of_group", true)), true
|
||||||
|
case "movewindoworgroup":
|
||||||
|
if params != "" {
|
||||||
|
return luaDispatcherTableCall("hl.dsp.window.move", luaStringField("direction", params), luaBoolField("group_aware", true)), true
|
||||||
|
}
|
||||||
|
case "lockgroups":
|
||||||
|
return dispatcherToggleTableCall("hl.dsp.group.lock", params), true
|
||||||
|
case "lockactivegroup":
|
||||||
|
return dispatcherToggleTableCall("hl.dsp.group.lock_active", params), true
|
||||||
|
case "denywindowfromgroup":
|
||||||
|
return dispatcherToggleTableCall("hl.dsp.window.deny_from_group", params), true
|
||||||
|
case "setignoregrouplock":
|
||||||
|
return luaHyprctlDispatchFunction(action), true
|
||||||
|
case "forcerendererreload":
|
||||||
|
return `hl.dsp.force_renderer_reload()`, true
|
||||||
|
case "forceidle":
|
||||||
|
if params != "" && isBareLuaNumber(params) {
|
||||||
|
return fmt.Sprintf(`hl.dsp.force_idle(%s)`, params), true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if isKnownHyprlandDispatcher(dispatcher) {
|
||||||
|
return luaHyprctlDispatchFunction(action), true
|
||||||
}
|
}
|
||||||
return "", false
|
return "", false
|
||||||
}
|
}
|
||||||
@@ -764,7 +1039,7 @@ func luaActionStringFromHyprlangAction(action string) string {
|
|||||||
if expr, ok := luaActionStringFromKnownHyprlandAction(action); ok {
|
if expr, ok := luaActionStringFromKnownHyprlandAction(action); ok {
|
||||||
return expr
|
return expr
|
||||||
}
|
}
|
||||||
return fmt.Sprintf(`hl.dispatch(%s)`, strconv.Quote(action))
|
return action
|
||||||
}
|
}
|
||||||
|
|
||||||
func luaExprToInternalAction(expr string) string {
|
func luaExprToInternalAction(expr string) string {
|
||||||
|
|||||||
@@ -882,23 +882,20 @@ func parseLuaStringLiteral(line string, i int) (value string, next int, ok bool)
|
|||||||
return "", i, false
|
return "", i, false
|
||||||
}
|
}
|
||||||
|
|
||||||
// parseLuaFirstArgExpr parses a single Lua expression starting at i, stopping when parentheses
|
// parseLuaFirstArgExpr parses a single Lua expression starting at i, stopping at
|
||||||
// opened from the first '(' are balanced (handles nested () and {} and double-quoted strings).
|
// the next top-level comma. It handles nested calls/tables and inline functions.
|
||||||
func parseLuaFirstArgExpr(line string, start int) (expr string, next int, ok bool) {
|
func parseLuaFirstArgExpr(line string, start int) (expr string, next int, ok bool) {
|
||||||
start = skipLuaWS(line, start)
|
start = skipLuaWS(line, start)
|
||||||
if start >= len(line) {
|
if start >= len(line) {
|
||||||
return "", start, false
|
return "", start, false
|
||||||
}
|
}
|
||||||
// Find first '(' of the call (e.g. hl.dsp.exec_cmd(...)
|
i := start
|
||||||
firstParen := strings.IndexByte(line[start:], '(')
|
parenDepth := 0
|
||||||
if firstParen < 0 {
|
braceDepth := 0
|
||||||
return "", start, false
|
bracketDepth := 0
|
||||||
}
|
functionDepth := 0
|
||||||
i := start + firstParen
|
|
||||||
depth := 0
|
|
||||||
inStr := byte(0)
|
inStr := byte(0)
|
||||||
esc := false
|
esc := false
|
||||||
exprStart := start
|
|
||||||
for ; i < len(line); i++ {
|
for ; i < len(line); i++ {
|
||||||
c := line[i]
|
c := line[i]
|
||||||
if inStr != 0 {
|
if inStr != 0 {
|
||||||
@@ -915,19 +912,66 @@ func parseLuaFirstArgExpr(line string, start int) (expr string, next int, ok boo
|
|||||||
}
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
if c == '[' && i+1 < len(line) && line[i+1] == '[' {
|
||||||
|
if end := strings.Index(line[i+2:], "]]"); end >= 0 {
|
||||||
|
i += end + 3
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
return "", start, false
|
||||||
|
}
|
||||||
|
if luaWordAt(line, i, "function") {
|
||||||
|
functionDepth++
|
||||||
|
i += len("function") - 1
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if luaWordAt(line, i, "end") && functionDepth > 0 {
|
||||||
|
functionDepth--
|
||||||
|
i += len("end") - 1
|
||||||
|
continue
|
||||||
|
}
|
||||||
switch c {
|
switch c {
|
||||||
case '"', '\'':
|
case '"', '\'':
|
||||||
inStr = c
|
inStr = c
|
||||||
case '(':
|
case '(':
|
||||||
depth++
|
parenDepth++
|
||||||
case ')':
|
case ')':
|
||||||
depth--
|
if parenDepth > 0 {
|
||||||
if depth == 0 {
|
parenDepth--
|
||||||
return strings.TrimSpace(line[exprStart : i+1]), i + 1, true
|
}
|
||||||
|
case '{':
|
||||||
|
braceDepth++
|
||||||
|
case '}':
|
||||||
|
if braceDepth > 0 {
|
||||||
|
braceDepth--
|
||||||
|
}
|
||||||
|
case '[':
|
||||||
|
bracketDepth++
|
||||||
|
case ']':
|
||||||
|
if bracketDepth > 0 {
|
||||||
|
bracketDepth--
|
||||||
|
}
|
||||||
|
case ',':
|
||||||
|
if parenDepth == 0 && braceDepth == 0 && bracketDepth == 0 && functionDepth == 0 {
|
||||||
|
return strings.TrimSpace(line[start:i]), i, true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return "", start, false
|
expr = strings.TrimSpace(line[start:i])
|
||||||
|
return expr, i, expr != ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func luaWordAt(line string, idx int, word string) bool {
|
||||||
|
if idx < 0 || idx+len(word) > len(line) || line[idx:idx+len(word)] != word {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
before := idx == 0 || !isLuaIdentByte(line[idx-1])
|
||||||
|
afterIdx := idx + len(word)
|
||||||
|
after := afterIdx >= len(line) || !isLuaIdentByte(line[afterIdx])
|
||||||
|
return before && after
|
||||||
|
}
|
||||||
|
|
||||||
|
func isLuaIdentByte(c byte) bool {
|
||||||
|
return c == '_' || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9')
|
||||||
}
|
}
|
||||||
|
|
||||||
// parseLuaBindInvocation parses one hl.bind("KEY", expr [, opts]) on a single line.
|
// parseLuaBindInvocation parses one hl.bind("KEY", expr [, opts]) on a single line.
|
||||||
@@ -1012,19 +1056,28 @@ func luaExprToDispatcherParams(expr string) (dispatcher, params string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
return "exec", strings.TrimSpace(strings.TrimPrefix(expr, "hl.dsp.exec_cmd"))
|
return "exec", strings.TrimSpace(strings.TrimPrefix(expr, "hl.dsp.exec_cmd"))
|
||||||
|
case strings.HasPrefix(expr, "hl.dsp.exec_raw("):
|
||||||
|
return "execr", luaCallStringArgValue(expr, "hl.dsp.exec_raw")
|
||||||
case strings.HasPrefix(expr, "hl.dispatch("):
|
case strings.HasPrefix(expr, "hl.dispatch("):
|
||||||
if arg := luaCallStringArgValue(expr, "hl.dispatch"); arg != "" {
|
if arg := luaCallStringArgValue(expr, "hl.dispatch"); arg != "" {
|
||||||
return splitDispatchCommand(arg)
|
return splitDispatchCommand(arg)
|
||||||
}
|
}
|
||||||
return "", ""
|
return "", ""
|
||||||
|
case strings.Contains(expr, "hl.exec_cmd("):
|
||||||
|
if arg := luaEmbeddedCallStringArgValue(expr, "hl.exec_cmd"); strings.HasPrefix(arg, "hyprctl dispatch ") {
|
||||||
|
return splitDispatchCommand(strings.TrimSpace(strings.TrimPrefix(arg, "hyprctl dispatch ")))
|
||||||
|
}
|
||||||
case strings.HasPrefix(expr, "hl.dsp.window.close("):
|
case strings.HasPrefix(expr, "hl.dsp.window.close("):
|
||||||
|
if window := luaTableStringField(expr, "window"); window != "" {
|
||||||
|
return "closewindow", window
|
||||||
|
}
|
||||||
if arg := luaCallStringArgValue(expr, "hl.dsp.window.close"); arg != "" {
|
if arg := luaCallStringArgValue(expr, "hl.dsp.window.close"); arg != "" {
|
||||||
return "closewindow", arg
|
return "closewindow", arg
|
||||||
}
|
}
|
||||||
return "closewindow", ""
|
return "closewindow", ""
|
||||||
case strings.HasPrefix(expr, "hl.dsp.window.kill("):
|
case strings.HasPrefix(expr, "hl.dsp.window.kill("):
|
||||||
if luaTableBoolFieldValue(expr, "force") {
|
if window := luaTableStringField(expr, "window"); window != "" {
|
||||||
return "forcekillactive", ""
|
return "killwindow", window
|
||||||
}
|
}
|
||||||
if arg := luaCallStringArgValue(expr, "hl.dsp.window.kill"); arg != "" {
|
if arg := luaCallStringArgValue(expr, "hl.dsp.window.kill"); arg != "" {
|
||||||
return "killwindow", arg
|
return "killwindow", arg
|
||||||
@@ -1043,23 +1096,50 @@ func luaExprToDispatcherParams(expr string) (dispatcher, params string) {
|
|||||||
client := luaStringValue(luaTableScalarField(expr, "client"))
|
client := luaStringValue(luaTableScalarField(expr, "client"))
|
||||||
return joinDispatcherParams("fullscreenstate", internal, client)
|
return joinDispatcherParams("fullscreenstate", internal, client)
|
||||||
case strings.HasPrefix(expr, "hl.dsp.window.float("):
|
case strings.HasPrefix(expr, "hl.dsp.window.float("):
|
||||||
switch luaTableStringField(expr, "action") {
|
switch luaToggleActionToLegacy(luaTableStringField(expr, "action")) {
|
||||||
case "set":
|
case "on":
|
||||||
return "setfloating", ""
|
return "setfloating", ""
|
||||||
case "unset":
|
case "off":
|
||||||
return "settiled", ""
|
return "settiled", ""
|
||||||
default:
|
default:
|
||||||
return "togglefloating", ""
|
return "togglefloating", ""
|
||||||
}
|
}
|
||||||
|
case strings.HasPrefix(expr, "hl.dsp.window.pseudo("):
|
||||||
|
action := luaToggleActionToLegacy(luaTableStringField(expr, "action"))
|
||||||
|
if action == "" || action == "toggle" {
|
||||||
|
return "pseudo", ""
|
||||||
|
}
|
||||||
|
return "pseudo", action
|
||||||
case strings.HasPrefix(expr, "hl.dsp.window.pin("):
|
case strings.HasPrefix(expr, "hl.dsp.window.pin("):
|
||||||
if action := luaTableStringField(expr, "action"); action != "" && action != "toggle" {
|
if action := luaToggleActionToLegacy(luaTableStringField(expr, "action")); action != "" && action != "toggle" {
|
||||||
return "pin", action
|
return "pin", action
|
||||||
}
|
}
|
||||||
return "pin", ""
|
return "pin", ""
|
||||||
case strings.Contains(expr, "hl.dsp.window.center()"):
|
case strings.Contains(expr, "hl.dsp.window.center()"):
|
||||||
return "centerwindow", ""
|
return "centerwindow", ""
|
||||||
|
case strings.Contains(expr, "hl.dsp.window.bring_to_top()"):
|
||||||
|
return "bringactivetotop", ""
|
||||||
|
case strings.Contains(expr, "hl.dsp.window.toggle_swallow()"):
|
||||||
|
return "toggleswallow", ""
|
||||||
case strings.Contains(expr, "hl.dsp.group.toggle()"):
|
case strings.Contains(expr, "hl.dsp.group.toggle()"):
|
||||||
return "togglegroup", ""
|
return "togglegroup", ""
|
||||||
|
case strings.Contains(expr, "hl.dsp.group.next()"):
|
||||||
|
return "changegroupactive", "f"
|
||||||
|
case strings.Contains(expr, "hl.dsp.group.prev()"):
|
||||||
|
return "changegroupactive", "b"
|
||||||
|
case strings.HasPrefix(expr, "hl.dsp.group.active("):
|
||||||
|
return "changegroupactive", luaStringValue(luaTableScalarField(expr, "index"))
|
||||||
|
case strings.HasPrefix(expr, "hl.dsp.group.move_window("):
|
||||||
|
if forward, ok := luaTableBoolField(expr, "forward"); ok && !forward {
|
||||||
|
return "movegroupwindow", "b"
|
||||||
|
}
|
||||||
|
return "movegroupwindow", "f"
|
||||||
|
case strings.HasPrefix(expr, "hl.dsp.group.lock_active("):
|
||||||
|
return "lockactivegroup", luaToggleActionToLockArg(luaTableStringField(expr, "action"))
|
||||||
|
case strings.HasPrefix(expr, "hl.dsp.group.lock("):
|
||||||
|
return "lockgroups", luaToggleActionToLockArg(luaTableStringField(expr, "action"))
|
||||||
|
case strings.HasPrefix(expr, "hl.dsp.window.deny_from_group("):
|
||||||
|
return "denywindowfromgroup", luaToggleActionToLegacy(luaTableStringField(expr, "action"))
|
||||||
case strings.HasPrefix(expr, "hl.dsp.focus("):
|
case strings.HasPrefix(expr, "hl.dsp.focus("):
|
||||||
switch {
|
switch {
|
||||||
case luaTableStringField(expr, "direction") != "":
|
case luaTableStringField(expr, "direction") != "":
|
||||||
@@ -1093,8 +1173,23 @@ func luaExprToDispatcherParams(expr string) (dispatcher, params string) {
|
|||||||
if raw, ok := luaTableBoolField(expr, "relative"); ok && !raw {
|
if raw, ok := luaTableBoolField(expr, "relative"); ok && !raw {
|
||||||
prefix = "exact "
|
prefix = "exact "
|
||||||
}
|
}
|
||||||
return "moveactive", prefix + x + " " + y
|
params := prefix + x + " " + y
|
||||||
|
if window := luaTableStringField(expr, "window"); window != "" {
|
||||||
|
return "movewindowpixel", params + "," + window
|
||||||
|
}
|
||||||
|
return "moveactive", params
|
||||||
|
case luaTableStringField(expr, "into_group") != "":
|
||||||
|
return "moveintogroup", luaTableStringField(expr, "into_group")
|
||||||
|
case luaTableStringField(expr, "into_or_create_group") != "":
|
||||||
|
return "moveintoorcreategroup", luaTableStringField(expr, "into_or_create_group")
|
||||||
|
case luaTableBoolFieldValue(expr, "out_of_group"):
|
||||||
|
return "moveoutofgroup", ""
|
||||||
|
case luaTableStringField(expr, "out_of_group") != "":
|
||||||
|
return "moveoutofgroup", luaTableStringField(expr, "out_of_group")
|
||||||
case luaTableStringField(expr, "direction") != "":
|
case luaTableStringField(expr, "direction") != "":
|
||||||
|
if luaTableBoolFieldValue(expr, "group_aware") {
|
||||||
|
return "movewindoworgroup", luaTableStringField(expr, "direction")
|
||||||
|
}
|
||||||
return "movewindow", luaTableStringField(expr, "direction")
|
return "movewindow", luaTableStringField(expr, "direction")
|
||||||
case luaTableStringField(expr, "monitor") != "":
|
case luaTableStringField(expr, "monitor") != "":
|
||||||
return "movewindow", "mon:" + luaTableStringField(expr, "monitor")
|
return "movewindow", "mon:" + luaTableStringField(expr, "monitor")
|
||||||
@@ -1123,10 +1218,41 @@ func luaExprToDispatcherParams(expr string) (dispatcher, params string) {
|
|||||||
if relative, ok := luaTableBoolField(expr, "relative"); ok && !relative {
|
if relative, ok := luaTableBoolField(expr, "relative"); ok && !relative {
|
||||||
prefix = "exact "
|
prefix = "exact "
|
||||||
}
|
}
|
||||||
return "resizeactive", prefix + x + " " + y
|
params := prefix + x + " " + y
|
||||||
|
if window := luaTableStringField(expr, "window"); window != "" {
|
||||||
|
return "resizewindowpixel", params + "," + window
|
||||||
|
}
|
||||||
|
return "resizeactive", params
|
||||||
}
|
}
|
||||||
case strings.HasPrefix(expr, "hl.dsp.window.swap("):
|
case strings.HasPrefix(expr, "hl.dsp.window.swap("):
|
||||||
|
switch {
|
||||||
|
case luaTableBoolFieldValue(expr, "next"):
|
||||||
|
return "swapnext", ""
|
||||||
|
case luaTableBoolFieldValue(expr, "prev"):
|
||||||
|
return "swapnext", "prev"
|
||||||
|
}
|
||||||
return "swapwindow", luaTableStringField(expr, "direction")
|
return "swapwindow", luaTableStringField(expr, "direction")
|
||||||
|
case strings.HasPrefix(expr, "hl.dsp.window.cycle_next("):
|
||||||
|
parts := []string{}
|
||||||
|
if next, ok := luaTableBoolField(expr, "next"); ok && !next {
|
||||||
|
parts = append(parts, "prev")
|
||||||
|
}
|
||||||
|
if luaTableBoolFieldValue(expr, "tiled") {
|
||||||
|
parts = append(parts, "tiled")
|
||||||
|
}
|
||||||
|
if luaTableBoolFieldValue(expr, "floating") {
|
||||||
|
parts = append(parts, "floating")
|
||||||
|
}
|
||||||
|
return "cyclenext", strings.Join(parts, " ")
|
||||||
|
case strings.HasPrefix(expr, "hl.dsp.window.signal("):
|
||||||
|
signal := luaStringValue(luaTableScalarField(expr, "signal"))
|
||||||
|
window := luaTableStringField(expr, "window")
|
||||||
|
if window != "" {
|
||||||
|
return joinDispatcherParams("signalwindow", window, signal)
|
||||||
|
}
|
||||||
|
return "signal", signal
|
||||||
|
case strings.HasPrefix(expr, "hl.dsp.window.tag("):
|
||||||
|
return joinDispatcherParams("tagwindow", luaTableStringField(expr, "tag"), luaTableStringField(expr, "window"))
|
||||||
case strings.HasPrefix(expr, "hl.dsp.window.alter_zorder("):
|
case strings.HasPrefix(expr, "hl.dsp.window.alter_zorder("):
|
||||||
mode := luaTableStringField(expr, "mode")
|
mode := luaTableStringField(expr, "mode")
|
||||||
if mode == "" {
|
if mode == "" {
|
||||||
@@ -1182,12 +1308,20 @@ func luaExprToDispatcherParams(expr string) (dispatcher, params string) {
|
|||||||
return joinDispatcherParams("sendshortcut", luaTableModsField(expr), luaTableStringField(expr, "key"), luaTableStringField(expr, "window"))
|
return joinDispatcherParams("sendshortcut", luaTableModsField(expr), luaTableStringField(expr, "key"), luaTableStringField(expr, "window"))
|
||||||
case strings.HasPrefix(expr, "hl.dsp.send_key_state("):
|
case strings.HasPrefix(expr, "hl.dsp.send_key_state("):
|
||||||
return joinDispatcherParams("sendkeystate", luaTableModsField(expr), luaTableStringField(expr, "key"), luaTableStringField(expr, "state"), luaTableStringField(expr, "window"))
|
return joinDispatcherParams("sendkeystate", luaTableModsField(expr), luaTableStringField(expr, "key"), luaTableStringField(expr, "state"), luaTableStringField(expr, "window"))
|
||||||
|
case strings.HasPrefix(expr, "hl.dsp.cursor.move_to_corner("):
|
||||||
|
return "movecursortocorner", luaStringValue(luaTableScalarField(expr, "corner"))
|
||||||
|
case strings.HasPrefix(expr, "hl.dsp.cursor.move("):
|
||||||
|
return joinDispatcherParams("movecursor", luaStringValue(luaTableScalarField(expr, "x")), luaStringValue(luaTableScalarField(expr, "y")))
|
||||||
|
case strings.Contains(expr, "hl.dsp.force_renderer_reload()"):
|
||||||
|
return "forcerendererreload", ""
|
||||||
|
case strings.HasPrefix(expr, "hl.dsp.force_idle("):
|
||||||
|
return "forceidle", luaCallScalarArgValue(expr, "hl.dsp.force_idle")
|
||||||
case strings.Contains(expr, "hl.dsp.exit()"):
|
case strings.Contains(expr, "hl.dsp.exit()"):
|
||||||
return "exit", ""
|
return "exit", ""
|
||||||
default:
|
default:
|
||||||
return "exec", "hyprctl dispatch lua:" + expr
|
return expr, ""
|
||||||
}
|
}
|
||||||
return "exec", "hyprctl dispatch lua:" + expr
|
return expr, ""
|
||||||
}
|
}
|
||||||
|
|
||||||
func splitDispatchCommand(command string) (dispatcher, params string) {
|
func splitDispatchCommand(command string) (dispatcher, params string) {
|
||||||
@@ -1213,6 +1347,53 @@ func joinDispatcherParams(dispatcher string, values ...string) (string, string)
|
|||||||
return dispatcher, strings.Join(parts, " ")
|
return dispatcher, strings.Join(parts, " ")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func luaEmbeddedCallStringArgValue(expr, funcName string) string {
|
||||||
|
idx := strings.Index(expr, funcName+"(")
|
||||||
|
if idx < 0 {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return luaCallStringArgValue(expr[idx:], funcName)
|
||||||
|
}
|
||||||
|
|
||||||
|
func luaCallScalarArgValue(callExpr, funcName string) string {
|
||||||
|
callExpr = strings.TrimSpace(callExpr)
|
||||||
|
prefix := funcName + "("
|
||||||
|
if !strings.HasPrefix(callExpr, prefix) {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
inner := strings.TrimSpace(callExpr[len(prefix):])
|
||||||
|
if inner == "" {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
if s := luaCallStringArgValue(callExpr, funcName); s != "" {
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
re := regexp.MustCompile(`^-?\d+(?:\.\d+)?`)
|
||||||
|
return re.FindString(inner)
|
||||||
|
}
|
||||||
|
|
||||||
|
func luaToggleActionToLegacy(action string) string {
|
||||||
|
switch strings.ToLower(strings.TrimSpace(action)) {
|
||||||
|
case "on", "enable", "enabled", "set", "lock":
|
||||||
|
return "on"
|
||||||
|
case "off", "disable", "disabled", "unset", "unlock":
|
||||||
|
return "off"
|
||||||
|
default:
|
||||||
|
return "toggle"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func luaToggleActionToLockArg(action string) string {
|
||||||
|
switch luaToggleActionToLegacy(action) {
|
||||||
|
case "on":
|
||||||
|
return "lock"
|
||||||
|
case "off":
|
||||||
|
return "unlock"
|
||||||
|
default:
|
||||||
|
return "toggle"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func extractLuaCallStringArg(callExpr, funcName string) string {
|
func extractLuaCallStringArg(callExpr, funcName string) string {
|
||||||
callExpr = strings.TrimSpace(callExpr)
|
callExpr = strings.TrimSpace(callExpr)
|
||||||
prefix := funcName + "("
|
prefix := funcName + "("
|
||||||
|
|||||||
@@ -74,15 +74,31 @@ func TestHyprlandLuaBindRoundTripHelpers(t *testing.T) {
|
|||||||
{`hl.dispatch("workspace 2")`, "workspace", "2"},
|
{`hl.dispatch("workspace 2")`, "workspace", "2"},
|
||||||
{`hl.dispatch([[customdispatcher arg one]])`, "customdispatcher", "arg one"},
|
{`hl.dispatch([[customdispatcher arg one]])`, "customdispatcher", "arg one"},
|
||||||
{`hl.dsp.window.fullscreen({ mode = "maximized", action = "toggle" })`, "fullscreen", "1"},
|
{`hl.dsp.window.fullscreen({ mode = "maximized", action = "toggle" })`, "fullscreen", "1"},
|
||||||
|
{`hl.dsp.window.float({ action = "on" })`, "setfloating", ""},
|
||||||
|
{`hl.dsp.window.close({ window = "class:^(kitty)$" })`, "closewindow", "class:^(kitty)$"},
|
||||||
{`hl.dsp.focus({ workspace = "e+1" })`, "workspace", "e+1"},
|
{`hl.dsp.focus({ workspace = "e+1" })`, "workspace", "e+1"},
|
||||||
{`hl.dsp.focus({ workspace = "2", on_current_monitor = true })`, "focusworkspaceoncurrentmonitor", "2"},
|
{`hl.dsp.focus({ workspace = "2", on_current_monitor = true })`, "focusworkspaceoncurrentmonitor", "2"},
|
||||||
{`hl.dsp.window.move({ monitor = "l" })`, "movewindow", "mon:l"},
|
{`hl.dsp.window.move({ monitor = "l" })`, "movewindow", "mon:l"},
|
||||||
|
{`hl.dsp.window.move({ direction = "r", group_aware = true })`, "movewindoworgroup", "r"},
|
||||||
|
{`hl.dsp.window.move({ into_group = "l" })`, "moveintogroup", "l"},
|
||||||
|
{`hl.dsp.window.move({ out_of_group = true })`, "moveoutofgroup", ""},
|
||||||
{`hl.dsp.window.move({ workspace = "special:magic", follow = false })`, "movetoworkspacesilent", "special:magic"},
|
{`hl.dsp.window.move({ workspace = "special:magic", follow = false })`, "movetoworkspacesilent", "special:magic"},
|
||||||
{`hl.dsp.window.resize({ x = -100, y = 0, relative = true })`, "resizeactive", "-100 0"},
|
{`hl.dsp.window.resize({ x = -100, y = 0, relative = true })`, "resizeactive", "-100 0"},
|
||||||
{`hl.dsp.window.resize({ x = 1280, y = 720, relative = false })`, "resizeactive", "exact 1280 720"},
|
{`hl.dsp.window.resize({ x = 1280, y = 720, relative = false })`, "resizeactive", "exact 1280 720"},
|
||||||
|
{`hl.dsp.window.resize({ x = 100, y = 50, relative = true, window = "class:^(app)$" })`, "resizewindowpixel", "100 50,class:^(app)$"},
|
||||||
|
{`hl.dsp.window.cycle_next({ next = false, tiled = true })`, "cyclenext", "prev tiled"},
|
||||||
|
{`hl.dsp.group.next()`, "changegroupactive", "f"},
|
||||||
|
{`hl.dsp.group.prev()`, "changegroupactive", "b"},
|
||||||
|
{`hl.dsp.group.active({ index = 2 })`, "changegroupactive", "2"},
|
||||||
|
{`hl.dsp.group.move_window({ forward = false })`, "movegroupwindow", "b"},
|
||||||
|
{`hl.dsp.group.lock({ action = "on" })`, "lockgroups", "lock"},
|
||||||
|
{`hl.dsp.group.lock_active({ action = "off" })`, "lockactivegroup", "unlock"},
|
||||||
|
{`hl.dsp.window.deny_from_group({ action = "toggle" })`, "denywindowfromgroup", "toggle"},
|
||||||
|
{`function() hl.exec_cmd("hyprctl dispatch splitratio +0.1") end`, "splitratio", "+0.1"},
|
||||||
{`hl.dsp.layout("togglesplit")`, "layoutmsg", "togglesplit"},
|
{`hl.dsp.layout("togglesplit")`, "layoutmsg", "togglesplit"},
|
||||||
{`hl.dsp.dpms({ action = "toggle" })`, "dpms", "toggle"},
|
{`hl.dsp.dpms({ action = "toggle" })`, "dpms", "toggle"},
|
||||||
{`hl.dsp.workspace.rename({ workspace = "1", name = "work" })`, "renameworkspace", "1 work"},
|
{`hl.dsp.workspace.rename({ workspace = "1", name = "work" })`, "renameworkspace", "1 work"},
|
||||||
|
{`hl.dsp.no_op()`, "hl.dsp.no_op()", ""},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
@@ -126,6 +142,21 @@ hl.bind("SUPER + N", hl.dsp.exec_cmd("dms ipc call notepad toggle"), { descripti
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestWriteLuaBindLineLeavesCustomLuaDispatcherRaw(t *testing.T) {
|
||||||
|
var sb strings.Builder
|
||||||
|
writeLuaBindLine(&sb, &hyprlandOverrideBind{
|
||||||
|
Key: "Super+u",
|
||||||
|
Action: "hl.dsp.no_op()",
|
||||||
|
Description: "Custom Lua",
|
||||||
|
})
|
||||||
|
|
||||||
|
want := `hl.unbind("SUPER + U")
|
||||||
|
hl.bind("SUPER + U", hl.dsp.no_op(), { description = "Custom Lua" })`
|
||||||
|
if got := strings.TrimSpace(sb.String()); got != want {
|
||||||
|
t.Fatalf("writeLuaBindLine() = %q, want %q", got, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestLuaActionStringFromHyprlangActionUsesNativeDispatchers(t *testing.T) {
|
func TestLuaActionStringFromHyprlangActionUsesNativeDispatchers(t *testing.T) {
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
action string
|
action string
|
||||||
@@ -138,6 +169,22 @@ func TestLuaActionStringFromHyprlangActionUsesNativeDispatchers(t *testing.T) {
|
|||||||
{"resizeactive exact 1280 720", `hl.dsp.window.resize({ x = 1280, y = 720, relative = false })`},
|
{"resizeactive exact 1280 720", `hl.dsp.window.resize({ x = 1280, y = 720, relative = false })`},
|
||||||
{"dpms toggle", `hl.dsp.dpms({ action = "toggle" })`},
|
{"dpms toggle", `hl.dsp.dpms({ action = "toggle" })`},
|
||||||
{"renameworkspace 1 work", `hl.dsp.workspace.rename({ workspace = "1", name = "work" })`},
|
{"renameworkspace 1 work", `hl.dsp.workspace.rename({ workspace = "1", name = "work" })`},
|
||||||
|
{"changegroupactive f", `hl.dsp.group.next()`},
|
||||||
|
{"changegroupactive b", `hl.dsp.group.prev()`},
|
||||||
|
{"changegroupactive 2", `hl.dsp.group.active({ index = 2 })`},
|
||||||
|
{"moveintogroup l", `hl.dsp.window.move({ into_group = "l" })`},
|
||||||
|
{"moveoutofgroup", `hl.dsp.window.move({ out_of_group = true })`},
|
||||||
|
{"movewindoworgroup r", `hl.dsp.window.move({ direction = "r", group_aware = true })`},
|
||||||
|
{"movegroupwindow b", `hl.dsp.group.move_window({ forward = false })`},
|
||||||
|
{"lockgroups lock", `hl.dsp.group.lock({ action = "on" })`},
|
||||||
|
{"lockactivegroup unlock", `hl.dsp.group.lock_active({ action = "off" })`},
|
||||||
|
{"denywindowfromgroup toggle", `hl.dsp.window.deny_from_group({ action = "toggle" })`},
|
||||||
|
{"cyclenext prev", `hl.dsp.window.cycle_next({ next = false })`},
|
||||||
|
{"setfloating", `hl.dsp.window.float({ action = "on" })`},
|
||||||
|
{"settiled", `hl.dsp.window.float({ action = "off" })`},
|
||||||
|
{"bringactivetotop", `hl.dsp.window.bring_to_top()`},
|
||||||
|
{"toggleswallow", `hl.dsp.window.toggle_swallow()`},
|
||||||
|
{"forceidle 300", `hl.dsp.force_idle(300)`},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
@@ -155,20 +202,34 @@ func TestLuaActionStringFromHyprlangActionUsesNativeDispatchers(t *testing.T) {
|
|||||||
|
|
||||||
func TestLuaActionStringFallsBackForUnsupportedResizePercentages(t *testing.T) {
|
func TestLuaActionStringFallsBackForUnsupportedResizePercentages(t *testing.T) {
|
||||||
got := luaActionStringFromHyprlangAction("resizeactive exact 100% 100%")
|
got := luaActionStringFromHyprlangAction("resizeactive exact 100% 100%")
|
||||||
want := `hl.dispatch("resizeactive exact 100% 100%")`
|
want := `function() hl.exec_cmd("hyprctl dispatch resizeactive exact 100% 100%") end`
|
||||||
if got != want {
|
if got != want {
|
||||||
t.Fatalf("luaActionStringFromHyprlangAction() = %q, want %q", got, want)
|
t.Fatalf("luaActionStringFromHyprlangAction() = %q, want %q", got, want)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestLuaActionStringFallsBackToDispatchWithoutHyprctl(t *testing.T) {
|
func TestParseLuaBindLineHandlesFunctionDispatcherFallback(t *testing.T) {
|
||||||
got := luaActionStringFromHyprlangAction("customdispatcher USER_INPUT")
|
line := `hl.bind("SUPER + R", function() hl.exec_cmd("hyprctl dispatch resizeactive exact 100% 100%") end, { description = "Unsupported Resize" })`
|
||||||
want := `hl.dispatch("customdispatcher USER_INPUT")`
|
got, ok := parseLuaBindOverrideLine(line)
|
||||||
|
if !ok {
|
||||||
|
t.Fatalf("expected line to parse")
|
||||||
|
}
|
||||||
|
if got.Action != "resizeactive exact 100% 100%" {
|
||||||
|
t.Fatalf("Action = %q, want resizeactive exact 100%% 100%%", got.Action)
|
||||||
|
}
|
||||||
|
if got.Description != "Unsupported Resize" {
|
||||||
|
t.Fatalf("Description = %q, want Unsupported Resize", got.Description)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestLuaActionStringLeavesCustomLuaDispatcherRaw(t *testing.T) {
|
||||||
|
got := luaActionStringFromHyprlangAction("hl.dsp.no_op()")
|
||||||
|
want := `hl.dsp.no_op()`
|
||||||
if got != want {
|
if got != want {
|
||||||
t.Fatalf("luaActionStringFromHyprlangAction() = %q, want %q", got, want)
|
t.Fatalf("luaActionStringFromHyprlangAction() = %q, want %q", got, want)
|
||||||
}
|
}
|
||||||
if strings.Contains(got, "hyprctl dispatch") {
|
if strings.Contains(got, "hl.dispatch") || strings.Contains(got, "hyprctl dispatch") {
|
||||||
t.Fatalf("expected hl.dispatch fallback without hyprctl dispatch wrapper, got %q", got)
|
t.Fatalf("expected custom Lua dispatcher expression to stay raw, got %q", got)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1416,7 +1416,7 @@ Item {
|
|||||||
id: customCompositorField
|
id: customCompositorField
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.preferredHeight: root._inputHeight
|
Layout.preferredHeight: root._inputHeight
|
||||||
placeholderText: I18n.tr("e.g., focus-workspace 3, resize-column -10")
|
placeholderText: KeybindsService.currentProvider === "hyprland" ? I18n.tr("e.g., hl.dsp.focus({ workspace = \"3\" })") : I18n.tr("e.g., focus-workspace 3, resize-column -10")
|
||||||
text: root._actionType === "compositor" ? root.editAction : ""
|
text: root._actionType === "compositor" ? root.editAction : ""
|
||||||
onTextChanged: {
|
onTextChanged: {
|
||||||
if (root._actionType !== "compositor")
|
if (root._actionType !== "compositor")
|
||||||
|
|||||||
Reference in New Issue
Block a user