feat hypr keybind helper via quickshell; fix nvim plugins (not completly done yet)
This commit is contained in:
@@ -22,26 +22,27 @@ local notdnd = "uwsm app -- swaync-client -d"
|
||||
local nothide = "uwsm app -- swaync-client --hide-latest"
|
||||
|
||||
-- First-class launchers
|
||||
hl.bind(mainMod .. " + Return", hl.dsp.exec_cmd(terminal))
|
||||
hl.bind(mainMod .. " + SHIFT + Return", hl.dsp.exec_cmd(term_tmux))
|
||||
hl.bind(mainMod .. " + CTRL + Return", hl.dsp.exec_cmd(term_tmux_append))
|
||||
hl.bind(mainMod .. " + F1", hl.dsp.exec_cmd("hypr-show-binds"))
|
||||
hl.bind(mainMod .. " + E", hl.dsp.exec_cmd(filemanager))
|
||||
hl.bind(mainMod .. " + W", hl.dsp.exec_cmd(browser))
|
||||
hl.bind(mainMod .. " + SHIFT + W", hl.dsp.exec_cmd(browserprv))
|
||||
hl.bind(mainMod .. " + CTRL + W", hl.dsp.exec_cmd(altbrowser))
|
||||
hl.bind(mainMod .. " + ALT + W", hl.dsp.exec_cmd(browsernewinst))
|
||||
hl.bind(mainMod .. " + Space", hl.dsp.exec_cmd(launcher))
|
||||
hl.bind(mainMod .. " + Return", hl.dsp.exec_cmd(terminal), { description = "Terminal" })
|
||||
hl.bind(mainMod .. " + SHIFT + Return", hl.dsp.exec_cmd(term_tmux), { description = "Terminal (tmux)" })
|
||||
hl.bind(mainMod .. " + CTRL + Return", hl.dsp.exec_cmd(term_tmux_append), { description = "Terminal (attach tmux)" })
|
||||
hl.bind(mainMod .. " + F1", hl.dsp.exec_cmd("qs ipc call keybinds toggle"), { description = "Show keybinds" })
|
||||
hl.bind(mainMod .. " + ALT + F1", hl.dsp.exec_cmd("hypr-show-binds"), { description = "Show raw binds (owlry)" })
|
||||
hl.bind(mainMod .. " + E", hl.dsp.exec_cmd(filemanager), { description = "File manager" })
|
||||
hl.bind(mainMod .. " + W", hl.dsp.exec_cmd(browser), { description = "Browser" })
|
||||
hl.bind(mainMod .. " + SHIFT + W", hl.dsp.exec_cmd(browserprv), { description = "Browser (private)" })
|
||||
hl.bind(mainMod .. " + CTRL + W", hl.dsp.exec_cmd(altbrowser), { description = "Chromium" })
|
||||
hl.bind(mainMod .. " + ALT + W", hl.dsp.exec_cmd(browsernewinst),{ description = "Firefox (new instance)" })
|
||||
hl.bind(mainMod .. " + Space", hl.dsp.exec_cmd(launcher), { description = "App launcher" })
|
||||
|
||||
-- Secondary launchers
|
||||
hl.bind(mainMod .. " + SHIFT + E", hl.dsp.exec_cmd(editor))
|
||||
hl.bind(mainMod .. " + CTRL + E", hl.dsp.exec_cmd(alteditor))
|
||||
hl.bind(mainMod .. " + X", hl.dsp.exec_cmd(taskman))
|
||||
hl.bind(mainMod .. " + C", hl.dsp.exec_cmd(clipman))
|
||||
hl.bind(mainMod .. " + F4", hl.dsp.exec_cmd(soundctl))
|
||||
hl.bind(mainMod .. " + SHIFT + E", hl.dsp.exec_cmd(editor), { description = "Neovim" })
|
||||
hl.bind(mainMod .. " + CTRL + E", hl.dsp.exec_cmd(alteditor), { description = "Zed editor" })
|
||||
hl.bind(mainMod .. " + X", hl.dsp.exec_cmd(taskman), { description = "Task manager" })
|
||||
hl.bind(mainMod .. " + C", hl.dsp.exec_cmd(clipman), { description = "Clipboard history" })
|
||||
hl.bind(mainMod .. " + F4", hl.dsp.exec_cmd(soundctl), { description = "Audio mixer" })
|
||||
|
||||
-- Quick Workspaces submap
|
||||
hl.bind(mainMod .. " + A", hl.dsp.submap("quickws"))
|
||||
hl.bind(mainMod .. " + A", hl.dsp.submap("quickws"), { description = "Quick workspace jump" })
|
||||
hl.define_submap("quickws", function()
|
||||
hl.bind("z", function() hl.dispatch(hl.dsp.focus({ workspace = 1 })); hl.dispatch(hl.dsp.submap("reset")) end)
|
||||
hl.bind("d", function() hl.dispatch(hl.dsp.focus({ workspace = 2 })); hl.dispatch(hl.dsp.submap("reset")) end)
|
||||
@@ -54,35 +55,35 @@ hl.define_submap("quickws", function()
|
||||
end)
|
||||
|
||||
-- Notifications
|
||||
hl.bind(mainMod .. " + grave", hl.dsp.exec_cmd(notcenter))
|
||||
hl.bind(mainMod .. " + SHIFT + grave", hl.dsp.exec_cmd(notdnd))
|
||||
hl.bind(mainMod .. " + CTRL + grave", hl.dsp.exec_cmd(nothide))
|
||||
hl.bind(mainMod .. " + grave", hl.dsp.exec_cmd(notcenter), { description = "Notification center" })
|
||||
hl.bind(mainMod .. " + SHIFT + grave", hl.dsp.exec_cmd(notdnd), { description = "Toggle do-not-disturb" })
|
||||
hl.bind(mainMod .. " + CTRL + grave", hl.dsp.exec_cmd(nothide), { description = "Hide latest notification" })
|
||||
|
||||
-- Session
|
||||
hl.bind(mainMod .. " + Pause", hl.dsp.exec_cmd("hyprlock"))
|
||||
hl.bind(mainMod .. " + SHIFT + Pause", hl.dsp.exec_cmd("owlry-power-menu"))
|
||||
hl.bind(mainMod .. " + End", hl.dsp.exec_cmd("hyprlock"))
|
||||
hl.bind(mainMod .. " + SHIFT + End", hl.dsp.exec_cmd("owlry-power-menu"))
|
||||
hl.bind(mainMod .. " + Pause", hl.dsp.exec_cmd("hyprlock"), { description = "Lock screen" })
|
||||
hl.bind(mainMod .. " + SHIFT + Pause", hl.dsp.exec_cmd("owlry-power-menu"), { description = "Power menu" })
|
||||
hl.bind(mainMod .. " + End", hl.dsp.exec_cmd("hyprlock"), { description = "Lock screen" })
|
||||
hl.bind(mainMod .. " + SHIFT + End", hl.dsp.exec_cmd("owlry-power-menu"), { description = "Power menu" })
|
||||
|
||||
-- Window management
|
||||
hl.bind(mainMod .. " + Q", hl.dsp.window.close())
|
||||
hl.bind(mainMod .. " + SHIFT + Q", hl.dsp.window.kill())
|
||||
hl.bind(mainMod .. " + F", hl.dsp.window.float())
|
||||
hl.bind(mainMod .. " + SHIFT + F", hl.dsp.window.fullscreen({ action = "toggle" }))
|
||||
hl.bind(mainMod .. " + P", hl.dsp.window.pin())
|
||||
hl.bind(mainMod .. " + U", hl.dsp.focus({ urgent_or_last = true }))
|
||||
hl.bind(mainMod .. " + V", hl.dsp.window.center())
|
||||
hl.bind(mainMod .. " + Q", hl.dsp.window.close(), { description = "Close window" })
|
||||
hl.bind(mainMod .. " + SHIFT + Q", hl.dsp.window.kill(), { description = "Kill window" })
|
||||
hl.bind(mainMod .. " + F", hl.dsp.window.float(), { description = "Toggle float" })
|
||||
hl.bind(mainMod .. " + SHIFT + F", hl.dsp.window.fullscreen({ action = "toggle" }), { description = "Toggle fullscreen" })
|
||||
hl.bind(mainMod .. " + P", hl.dsp.window.pin(), { description = "Pin window" })
|
||||
hl.bind(mainMod .. " + U", hl.dsp.focus({ urgent_or_last = true }), { description = "Focus urgent / last" })
|
||||
hl.bind(mainMod .. " + V", hl.dsp.window.center(), { description = "Center window" })
|
||||
|
||||
-- Special workspaces
|
||||
hl.bind(mainMod .. " + SHIFT + Space", hl.dsp.workspace.toggle_special())
|
||||
hl.bind(mainMod .. " + CTRL + Space", hl.dsp.window.move({ workspace = "special" }))
|
||||
hl.bind(mainMod .. " + N", hl.dsp.workspace.toggle_special("passwordmgr"))
|
||||
hl.bind(mainMod .. " + SHIFT + Space", hl.dsp.workspace.toggle_special(), { description = "Toggle scratchpad" })
|
||||
hl.bind(mainMod .. " + CTRL + Space", hl.dsp.window.move({ workspace = "special" }), { description = "Move to scratchpad" })
|
||||
hl.bind(mainMod .. " + N", hl.dsp.workspace.toggle_special("passwordmgr"), { description = "Password manager scratchpad" })
|
||||
|
||||
-- Monitor focus
|
||||
hl.bind(mainMod .. " + I", hl.dsp.focus({ monitor = "l" }))
|
||||
hl.bind(mainMod .. " + O", hl.dsp.focus({ monitor = "r" }))
|
||||
hl.bind(mainMod .. " + SHIFT + I", hl.dsp.workspace.move({ monitor = "l" }))
|
||||
hl.bind(mainMod .. " + SHIFT + O", hl.dsp.workspace.move({ monitor = "r" }))
|
||||
hl.bind(mainMod .. " + I", hl.dsp.focus({ monitor = "l" }), { description = "Focus left monitor" })
|
||||
hl.bind(mainMod .. " + O", hl.dsp.focus({ monitor = "r" }), { description = "Focus right monitor" })
|
||||
hl.bind(mainMod .. " + SHIFT + I", hl.dsp.workspace.move({ monitor = "l" }), { description = "Move workspace to left monitor" })
|
||||
hl.bind(mainMod .. " + SHIFT + O", hl.dsp.workspace.move({ monitor = "r" }), { description = "Move workspace to right monitor" })
|
||||
|
||||
-- ─── Workspace layout state ───────────────────────────────────────────────────
|
||||
local ws_layouts = {}
|
||||
@@ -176,8 +177,8 @@ local function resize_h(sign)
|
||||
end
|
||||
|
||||
-- Layout
|
||||
hl.bind(mainMod .. " + comma", ws_toggle_ms)
|
||||
hl.bind(mainMod .. " + period", ws_cycle)
|
||||
hl.bind(mainMod .. " + comma", ws_toggle_ms, { description = "Toggle master/scroll layout" })
|
||||
hl.bind(mainMod .. " + period", ws_cycle, { description = "Cycle workspace layout" })
|
||||
|
||||
-- Split ratio (ALT+1-9 = 10%-90%, ALT+0 = 95%)
|
||||
-- mfact exact for master/custom layouts, colresize for built-in scrolling
|
||||
@@ -214,11 +215,11 @@ local function layout_ratio_delta(delta)
|
||||
end
|
||||
end
|
||||
for i = 1, 9 do
|
||||
hl.bind(mainMod .. " + ALT + " .. i, layout_ratio(i / 10))
|
||||
hl.bind(mainMod .. " + ALT + " .. i, layout_ratio(i / 10), { description = "Split ratio " .. (i * 10) .. "%" })
|
||||
end
|
||||
hl.bind(mainMod .. " + ALT + 0", layout_ratio(0.95))
|
||||
hl.bind(mainMod .. " + ALT + comma", layout_ratio_delta(-0.05))
|
||||
hl.bind(mainMod .. " + ALT + period", layout_ratio_delta(0.05))
|
||||
hl.bind(mainMod .. " + ALT + 0", layout_ratio(0.95), { description = "Split ratio 95%" })
|
||||
hl.bind(mainMod .. " + ALT + comma", layout_ratio_delta(-0.05), { description = "Split ratio -5%" })
|
||||
hl.bind(mainMod .. " + ALT + period", layout_ratio_delta(0.05), { description = "Split ratio +5%" })
|
||||
|
||||
-- Scrolling layout: resize ALL columns
|
||||
for i = 1, 9 do
|
||||
@@ -227,13 +228,13 @@ for i = 1, 9 do
|
||||
if hl.get_config("general.layout") == "scrolling" then
|
||||
hl.dispatch(hl.dsp.layout("colresize all " .. ratio))
|
||||
end
|
||||
end)
|
||||
end, { description = "All columns " .. (i * 10) .. "% (scrolling)" })
|
||||
end
|
||||
hl.bind(mainMod .. " + CTRL + ALT + 0", function()
|
||||
if hl.get_config("general.layout") == "scrolling" then
|
||||
hl.dispatch(hl.dsp.layout("colresize all 0.95"))
|
||||
end
|
||||
end)
|
||||
end, { description = "All columns 95% (scrolling)" })
|
||||
|
||||
-- Smart Gaps Toggle
|
||||
hl.bind(mainMod .. " + SHIFT + G", function()
|
||||
@@ -246,7 +247,7 @@ hl.bind(mainMod .. " + SHIFT + G", function()
|
||||
hl.config({ general = { gaps_in = 5, gaps_out = 5 } })
|
||||
hl.notification.create({ text = "Gaps: ON", timeout = 2000, icon = "ok" })
|
||||
end
|
||||
end)
|
||||
end, { description = "Toggle gaps" })
|
||||
|
||||
-- Global Focus Notification (Lua Event)
|
||||
hl.on("window.active", function(w)
|
||||
@@ -256,19 +257,19 @@ hl.on("window.active", function(w)
|
||||
end)
|
||||
|
||||
-- Vim-like navigation
|
||||
hl.bind(mainMod .. " + H", hl.dsp.focus({ direction = "l" }))
|
||||
hl.bind(mainMod .. " + L", hl.dsp.focus({ direction = "r" }))
|
||||
hl.bind(mainMod .. " + K", hl.dsp.focus({ direction = "u" }))
|
||||
hl.bind(mainMod .. " + J", hl.dsp.focus({ direction = "d" }))
|
||||
hl.bind(mainMod .. " + H", hl.dsp.focus({ direction = "l" }), { description = "Focus left" })
|
||||
hl.bind(mainMod .. " + L", hl.dsp.focus({ direction = "r" }), { description = "Focus right" })
|
||||
hl.bind(mainMod .. " + K", hl.dsp.focus({ direction = "u" }), { description = "Focus up" })
|
||||
hl.bind(mainMod .. " + J", hl.dsp.focus({ direction = "d" }), { description = "Focus down" })
|
||||
|
||||
-- Move window (layout-aware)
|
||||
hl.bind(mainMod .. " + SHIFT + H", move_window("l"))
|
||||
hl.bind(mainMod .. " + SHIFT + L", move_window("r"))
|
||||
hl.bind(mainMod .. " + SHIFT + K", move_window("u"))
|
||||
hl.bind(mainMod .. " + SHIFT + J", move_window("d"))
|
||||
hl.bind(mainMod .. " + SHIFT + H", move_window("l"), { description = "Move window left" })
|
||||
hl.bind(mainMod .. " + SHIFT + L", move_window("r"), { description = "Move window right" })
|
||||
hl.bind(mainMod .. " + SHIFT + K", move_window("u"), { description = "Move window up" })
|
||||
hl.bind(mainMod .. " + SHIFT + J", move_window("d"), { description = "Move window down" })
|
||||
|
||||
-- Resize submap
|
||||
hl.bind(mainMod .. " + R", hl.dsp.submap("resize"))
|
||||
hl.bind(mainMod .. " + R", hl.dsp.submap("resize"), { description = "Resize mode" })
|
||||
hl.define_submap("resize", function()
|
||||
hl.bind("h", hl.dsp.window.resize({ x = -25, y = 0, relative = true }), { repeating = true })
|
||||
hl.bind("l", hl.dsp.window.resize({ x = 25, y = 0, relative = true }), { repeating = true })
|
||||
@@ -283,7 +284,7 @@ hl.define_submap("resize", function()
|
||||
end)
|
||||
|
||||
-- Zoom submap
|
||||
hl.bind(mainMod .. " + M", hl.dsp.submap("zoom"))
|
||||
hl.bind(mainMod .. " + M", hl.dsp.submap("zoom"), { description = "Zoom mode" })
|
||||
hl.define_submap("zoom", function()
|
||||
hl.bind("equal", hl.dsp.exec_cmd("hypr-zoom-step +0.2"))
|
||||
hl.bind("minus", hl.dsp.exec_cmd("hypr-zoom-step -0.2"))
|
||||
@@ -293,16 +294,16 @@ hl.define_submap("zoom", function()
|
||||
end)
|
||||
|
||||
-- Workspace cycling
|
||||
hl.bind(mainMod .. " + Tab", hl.dsp.focus({ workspace = "m+1" }))
|
||||
hl.bind(mainMod .. " + SHIFT + Tab", hl.dsp.focus({ workspace = "m-1" }))
|
||||
hl.bind(mainMod .. " + Tab", hl.dsp.focus({ workspace = "m+1" }), { description = "Next workspace" })
|
||||
hl.bind(mainMod .. " + SHIFT + Tab", hl.dsp.focus({ workspace = "m-1" }), { description = "Previous workspace" })
|
||||
|
||||
-- Switch Workspaces 1-10 (IDs 21-30 in setup)
|
||||
for i = 1, 9 do
|
||||
hl.bind(mainMod .. " + " .. i, hl.dsp.focus({ workspace = 20 + i }))
|
||||
hl.bind(mainMod .. " + SHIFT + " .. i, hl.dsp.window.move({ workspace = 20 + i }))
|
||||
hl.bind(mainMod .. " + " .. i, hl.dsp.focus({ workspace = 20 + i }), { description = "Workspace " .. i })
|
||||
hl.bind(mainMod .. " + SHIFT + " .. i, hl.dsp.window.move({ workspace = 20 + i }), { description = "Move to workspace " .. i })
|
||||
end
|
||||
hl.bind(mainMod .. " + 0", hl.dsp.focus({ workspace = 30 }))
|
||||
hl.bind(mainMod .. " + SHIFT + 0", hl.dsp.window.move({ workspace = 30 }))
|
||||
hl.bind(mainMod .. " + 0", hl.dsp.focus({ workspace = 30 }), { description = "Workspace 10" })
|
||||
hl.bind(mainMod .. " + SHIFT + 0", hl.dsp.window.move({ workspace = 30 }), { description = "Move to workspace 10" })
|
||||
|
||||
-- Groups
|
||||
local function smart_group(dir)
|
||||
@@ -315,31 +316,31 @@ local function smart_group(dir)
|
||||
end
|
||||
end
|
||||
|
||||
hl.bind(mainMod .. " + G", hl.dsp.group.toggle())
|
||||
hl.bind(mainMod .. " + CTRL + G", hl.dsp.window.move({ out_of_group = true }))
|
||||
hl.bind(mainMod .. " + CTRL + H", hl.dsp.group.prev())
|
||||
hl.bind(mainMod .. " + CTRL + L", hl.dsp.group.next())
|
||||
hl.bind(mainMod .. " + CTRL + J", hl.dsp.group.move_window({ forward = true }))
|
||||
hl.bind(mainMod .. " + CTRL + K", hl.dsp.group.move_window({ forward = false }))
|
||||
hl.bind(mainMod .. " + CTRL + SHIFT + H", function() smart_group("l") end)
|
||||
hl.bind(mainMod .. " + CTRL + SHIFT + J", function() smart_group("d") end)
|
||||
hl.bind(mainMod .. " + CTRL + SHIFT + K", function() smart_group("u") end)
|
||||
hl.bind(mainMod .. " + CTRL + SHIFT + L", function() smart_group("r") end)
|
||||
hl.bind(mainMod .. " + Z", hl.dsp.group.next())
|
||||
hl.bind(mainMod .. " + SHIFT + Z", hl.dsp.group.prev())
|
||||
hl.bind(mainMod .. " + G", hl.dsp.group.toggle(), { description = "Toggle group" })
|
||||
hl.bind(mainMod .. " + CTRL + G", hl.dsp.window.move({ out_of_group = true }), { description = "Leave group" })
|
||||
hl.bind(mainMod .. " + CTRL + H", hl.dsp.group.prev(), { description = "Group: previous tab" })
|
||||
hl.bind(mainMod .. " + CTRL + L", hl.dsp.group.next(), { description = "Group: next tab" })
|
||||
hl.bind(mainMod .. " + CTRL + J", hl.dsp.group.move_window({ forward = true }), { description = "Group: move tab forward" })
|
||||
hl.bind(mainMod .. " + CTRL + K", hl.dsp.group.move_window({ forward = false }), { description = "Group: move tab back" })
|
||||
hl.bind(mainMod .. " + CTRL + SHIFT + H", function() smart_group("l") end, { description = "Smart group left" })
|
||||
hl.bind(mainMod .. " + CTRL + SHIFT + J", function() smart_group("d") end, { description = "Smart group down" })
|
||||
hl.bind(mainMod .. " + CTRL + SHIFT + K", function() smart_group("u") end, { description = "Smart group up" })
|
||||
hl.bind(mainMod .. " + CTRL + SHIFT + L", function() smart_group("r") end, { description = "Smart group right" })
|
||||
hl.bind(mainMod .. " + Z", hl.dsp.group.next(), { description = "Group: next tab" })
|
||||
hl.bind(mainMod .. " + SHIFT + Z", hl.dsp.group.prev(), { description = "Group: previous tab" })
|
||||
|
||||
-- Layout-aware navigation
|
||||
hl.bind(mainMod .. " + ALT + H", nav("l"))
|
||||
hl.bind(mainMod .. " + ALT + L", nav("r"))
|
||||
hl.bind(mainMod .. " + ALT + J", nav("d"))
|
||||
hl.bind(mainMod .. " + ALT + K", nav("u"))
|
||||
hl.bind(mainMod .. " + ALT + Tab", nav("r"))
|
||||
hl.bind(mainMod .. " + ALT + SHIFT + Tab", nav("l"))
|
||||
hl.bind(mainMod .. " + ALT + SHIFT + J", resize_h("-"))
|
||||
hl.bind(mainMod .. " + ALT + SHIFT + K", resize_h("+"))
|
||||
hl.bind(mainMod .. " + ALT + H", nav("l"), { description = "Nav left (layout-aware)" })
|
||||
hl.bind(mainMod .. " + ALT + L", nav("r"), { description = "Nav right (layout-aware)" })
|
||||
hl.bind(mainMod .. " + ALT + J", nav("d"), { description = "Nav down / add master" })
|
||||
hl.bind(mainMod .. " + ALT + K", nav("u"), { description = "Nav up / remove master" })
|
||||
hl.bind(mainMod .. " + ALT + Tab", nav("r"), { description = "Nav right (layout-aware)" })
|
||||
hl.bind(mainMod .. " + ALT + SHIFT + Tab", nav("l"), { description = "Nav left (layout-aware)" })
|
||||
hl.bind(mainMod .. " + ALT + SHIFT + J", resize_h("-"), { description = "Shrink split" })
|
||||
hl.bind(mainMod .. " + ALT + SHIFT + K", resize_h("+"), { description = "Grow split" })
|
||||
|
||||
-- Mouse binds
|
||||
hl.bind(mainMod .. " + mouse:272", hl.dsp.window.drag(), { mouse = true })
|
||||
hl.bind(mainMod .. " + mouse:272", hl.dsp.window.drag(), { mouse = true })
|
||||
hl.bind(mainMod .. " + mouse:273", hl.dsp.window.resize(), { mouse = true })
|
||||
|
||||
-- master-scroll slave scrolling (mouse wheel + bracket fallback)
|
||||
@@ -360,22 +361,22 @@ local function layout_scroll(dir)
|
||||
end
|
||||
hl.bind(mainMod .. " + mouse_down", layout_scroll("scrollup"), { mouse = true })
|
||||
hl.bind(mainMod .. " + mouse_up", layout_scroll("scrolldown"), { mouse = true })
|
||||
hl.bind(mainMod .. " + bracketright", layout_scroll("scrolldown"))
|
||||
hl.bind(mainMod .. " + bracketleft", layout_scroll("scrollup"))
|
||||
hl.bind(mainMod .. " + bracketright", layout_scroll("scrolldown"), { description = "Scroll slave pane down" })
|
||||
hl.bind(mainMod .. " + bracketleft", layout_scroll("scrollup"), { description = "Scroll slave pane up" })
|
||||
|
||||
-- Screenshots
|
||||
hl.bind("Print", hl.dsp.exec_cmd("grimblast --notify copy screen"))
|
||||
hl.bind(mainMod .. " + Print", hl.dsp.exec_cmd("owlry-screenshot-menu"))
|
||||
hl.bind("SHIFT + Print", hl.dsp.exec_cmd("uwsm app -- kitty --class=scrrec -e wf-recorder -f ~/Videos/scrrec.mkv -y -g \"$(slurp)\""))
|
||||
hl.bind("Print", hl.dsp.exec_cmd("grimblast --notify copy screen"), { description = "Screenshot: full screen" })
|
||||
hl.bind(mainMod .. " + Print", hl.dsp.exec_cmd("owlry-screenshot-menu"), { description = "Screenshot menu" })
|
||||
hl.bind("SHIFT + Print", hl.dsp.exec_cmd("uwsm app -- kitty --class=scrrec -e wf-recorder -f ~/Videos/scrrec.mkv -y -g \"$(slurp)\""), { description = "Screen record selection" })
|
||||
|
||||
-- Multimedia
|
||||
hl.bind("XF86AudioRaiseVolume", hl.dsp.exec_cmd("wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%+"), { repeating = true })
|
||||
hl.bind("XF86AudioLowerVolume", hl.dsp.exec_cmd("wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%-"), { repeating = true })
|
||||
hl.bind("XF86AudioMute", hl.dsp.exec_cmd("wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle"), { locked = true })
|
||||
hl.bind("SHIFT + XF86AudioRaiseVolume", hl.dsp.exec_cmd("wpctl set-volume @DEFAULT_AUDIO_SOURCE@ 5%+"), { repeating = true })
|
||||
hl.bind("SHIFT + XF86AudioLowerVolume", hl.dsp.exec_cmd("wpctl set-volume @DEFAULT_AUDIO_SOURCE@ 5%-"), { repeating = true })
|
||||
hl.bind("SHIFT + XF86AudioMute", hl.dsp.exec_cmd("wpctl set-mute @DEFAULT_AUDIO_SOURCE@ toggle"), { locked = true })
|
||||
hl.bind("XF86AudioPlay", hl.dsp.exec_cmd("playerctl play-pause"), { locked = true })
|
||||
hl.bind("XF86AudioPause", hl.dsp.exec_cmd("playerctl play-pause"), { locked = true })
|
||||
hl.bind("XF86AudioNext", hl.dsp.exec_cmd("playerctl next"), { locked = true })
|
||||
hl.bind("XF86AudioPrev", hl.dsp.exec_cmd("playerctl previous"), { locked = true })
|
||||
hl.bind("XF86AudioRaiseVolume", hl.dsp.exec_cmd("wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%+"), { repeating = true, description = "Volume up" })
|
||||
hl.bind("XF86AudioLowerVolume", hl.dsp.exec_cmd("wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%-"), { repeating = true, description = "Volume down" })
|
||||
hl.bind("XF86AudioMute", hl.dsp.exec_cmd("wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle"), { locked = true, description = "Mute" })
|
||||
hl.bind("SHIFT + XF86AudioRaiseVolume", hl.dsp.exec_cmd("wpctl set-volume @DEFAULT_AUDIO_SOURCE@ 5%+"), { repeating = true, description = "Mic volume up" })
|
||||
hl.bind("SHIFT + XF86AudioLowerVolume", hl.dsp.exec_cmd("wpctl set-volume @DEFAULT_AUDIO_SOURCE@ 5%-"), { repeating = true, description = "Mic volume down" })
|
||||
hl.bind("SHIFT + XF86AudioMute", hl.dsp.exec_cmd("wpctl set-mute @DEFAULT_AUDIO_SOURCE@ toggle"),{ locked = true, description = "Mic mute" })
|
||||
hl.bind("XF86AudioPlay", hl.dsp.exec_cmd("playerctl play-pause"), { locked = true, description = "Play/pause" })
|
||||
hl.bind("XF86AudioPause", hl.dsp.exec_cmd("playerctl play-pause"), { locked = true, description = "Play/pause" })
|
||||
hl.bind("XF86AudioNext", hl.dsp.exec_cmd("playerctl next"), { locked = true, description = "Next track" })
|
||||
hl.bind("XF86AudioPrev", hl.dsp.exec_cmd("playerctl previous"), { locked = true, description = "Previous track" })
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
-- Source-visible editing by default; toggle with <leader>uc
|
||||
vim.opt_local.conceallevel = 0
|
||||
|
||||
-- Spell-check (tweak languages to your needs)
|
||||
vim.opt_local.spell = true
|
||||
vim.opt_local.spelllang = { "en_gb", "de_de", "fr" }
|
||||
|
||||
@@ -3,7 +3,7 @@ vim.lsp.config("texlab", {
|
||||
texlab = {
|
||||
build = {
|
||||
executable = "latexmk",
|
||||
args = { "-pdf", "-interaction=nonstopmode", "-synctex=1", "%f" },
|
||||
args = { "-lualatex", "-interaction=nonstopmode", "-synctex=1", "%f" },
|
||||
onSave = false,
|
||||
forwardSearchAfter = false,
|
||||
},
|
||||
|
||||
@@ -60,3 +60,19 @@ opt.completeopt = { "menu", "menuone", "noselect" }
|
||||
opt.mouse = "a"
|
||||
opt.fileencoding = "utf-8"
|
||||
opt.shortmess:append("c")
|
||||
|
||||
vim.diagnostic.config({
|
||||
virtual_text = { prefix = "●", source = "if_many" },
|
||||
float = { border = "rounded", source = true },
|
||||
signs = {
|
||||
text = {
|
||||
[vim.diagnostic.severity.ERROR] = " ",
|
||||
[vim.diagnostic.severity.WARN] = " ",
|
||||
[vim.diagnostic.severity.HINT] = " ",
|
||||
[vim.diagnostic.severity.INFO] = " ",
|
||||
},
|
||||
},
|
||||
underline = true,
|
||||
update_in_insert = false,
|
||||
severity_sort = true,
|
||||
})
|
||||
|
||||
@@ -57,6 +57,7 @@ return {
|
||||
html = { "prettier" },
|
||||
css = { "prettier" },
|
||||
markdown = { "prettier" },
|
||||
tex = { "latexindent" },
|
||||
["jinja.html"] = { "djlint" },
|
||||
},
|
||||
format_on_save = {
|
||||
@@ -65,4 +66,21 @@ return {
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
-- Doc-stub generation: JSDoc, Javadoc, rustdoc
|
||||
{
|
||||
"danymat/neogen",
|
||||
cmd = "Neogen",
|
||||
keys = {
|
||||
{ "<leader>lg", function() require("neogen").generate() end, desc = "Generate doc" },
|
||||
},
|
||||
opts = {
|
||||
snippet_engine = "luasnip",
|
||||
languages = {
|
||||
java = { template = { annotation_convention = "javadoc" } },
|
||||
typescript = { template = { annotation_convention = "tsdoc" } },
|
||||
rust = { template = { annotation_convention = "rustdoc" } },
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -147,6 +147,9 @@ return {
|
||||
local map = vim.keymap.set
|
||||
map("n", "<leader>uw", function() vim.opt.wrap = not vim.wo.wrap end, { desc = "Toggle wrap" })
|
||||
map("n", "<leader>uf", "zA", { desc = "Toggle all folds" })
|
||||
map("n", "<leader>uc", function()
|
||||
vim.opt_local.conceallevel = vim.o.conceallevel == 0 and 2 or 0
|
||||
end, { desc = "Toggle conceal" })
|
||||
end,
|
||||
},
|
||||
|
||||
|
||||
@@ -5,22 +5,23 @@ return {
|
||||
ft = { "tex", "plaintex", "bib" },
|
||||
init = function()
|
||||
-- Must be set before vimtex loads
|
||||
vim.g.vimtex_view_method = "zathura"
|
||||
-- zathura-synctex: Wayland-native viewer (DBus forward search, hyprctl focus, no xdotool)
|
||||
vim.g.vimtex_view_method = "general"
|
||||
vim.g.vimtex_view_general_viewer = "zathura-synctex"
|
||||
vim.g.vimtex_view_general_options = "--synctex-forward @line:@col:@tex @pdf"
|
||||
vim.g.vimtex_compiler_method = "latexmk"
|
||||
vim.g.vimtex_compiler_latexmk_engines = { _ = "-lualatex" }
|
||||
vim.g.vimtex_compiler_latexmk = {
|
||||
options = {
|
||||
"-pdf",
|
||||
"-shell-escape",
|
||||
"-verbose",
|
||||
"-file-line-error",
|
||||
"-synctex=1",
|
||||
"-interaction=nonstopmode",
|
||||
"-lualatex",
|
||||
},
|
||||
}
|
||||
-- Disable vimtex completion (blink.cmp handles it via cmp-vimtex)
|
||||
vim.g.vimtex_complete_enabled = 0
|
||||
-- Disable vimtex's own syntax (use treesitter instead, with vim regex fallback)
|
||||
-- Must stay 1: cmp-vimtex uses VimTeX's completion engine for \begin/\end items
|
||||
vim.g.vimtex_complete_enabled = 1
|
||||
vim.g.vimtex_syntax_enabled = 1
|
||||
vim.g.vimtex_syntax_conceal_disable = 0
|
||||
end,
|
||||
|
||||
@@ -0,0 +1,368 @@
|
||||
import Quickshell
|
||||
import Quickshell.Io
|
||||
import Quickshell.Hyprland
|
||||
import Quickshell.Wayland
|
||||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
import QtQuick.Controls
|
||||
import "../shared" as Shared
|
||||
|
||||
Scope {
|
||||
id: root
|
||||
|
||||
property bool keybindsVisible: false
|
||||
property bool animating: false
|
||||
property int activeTab: 0
|
||||
property var allBinds: []
|
||||
property var filteredBinds: []
|
||||
property string targetMonitor: Shared.Config.monitor
|
||||
|
||||
readonly property var tabMasks: [64, 65, 68, 72]
|
||||
readonly property var tabLabels: ["SUPER", "SUPER+SHIFT", "SUPER+CTRL", "SUPER+ALT"]
|
||||
|
||||
IpcHandler {
|
||||
target: "keybinds"
|
||||
function toggle(): void { root.toggle() }
|
||||
}
|
||||
|
||||
function toggle() {
|
||||
if (root.keybindsVisible) {
|
||||
root.keybindsVisible = false
|
||||
closeTimer.restart()
|
||||
} else {
|
||||
root.targetMonitor = Hyprland.focusedMonitor?.name ?? Shared.Config.monitor
|
||||
root.animating = true
|
||||
root.activeTab = 0
|
||||
root.keybindsVisible = true
|
||||
bindsProc.running = false
|
||||
bindsProc.running = true
|
||||
}
|
||||
}
|
||||
|
||||
function updateFilter() {
|
||||
const mask = root.tabMasks[root.activeTab]
|
||||
root.filteredBinds = root.allBinds.filter(function(b) {
|
||||
return b.modmask === mask
|
||||
&& !b.mouse
|
||||
&& b.submap === ""
|
||||
&& !b.key.startsWith("_")
|
||||
})
|
||||
}
|
||||
|
||||
function formatKey(k) {
|
||||
if (k.length === 1) return k.toUpperCase()
|
||||
const pretty = {
|
||||
"Return": "↵",
|
||||
"BackSpace": "⌫",
|
||||
"Tab": "⇥",
|
||||
"space": "Space",
|
||||
"Prior": "PgUp",
|
||||
"Next": "PgDn",
|
||||
"comma": ",",
|
||||
"period": ".",
|
||||
"semicolon": ";",
|
||||
"apostrophe": "'",
|
||||
"grave": "`",
|
||||
"minus": "-",
|
||||
"equal": "=",
|
||||
"bracketleft": "[",
|
||||
"bracketright": "]",
|
||||
"backslash": "\\",
|
||||
"slash": "/",
|
||||
}
|
||||
return pretty[k] ?? (k.length > 10 ? k.slice(0, 9) + "…" : k)
|
||||
}
|
||||
|
||||
function formatAction(b) {
|
||||
if (b.has_description && b.description !== "") return b.description
|
||||
if (b.dispatcher === "exec") {
|
||||
let a = b.arg
|
||||
let idx = a.indexOf("-- ")
|
||||
let cmd = idx >= 0 ? a.slice(idx + 3) : a
|
||||
return cmd.length > 48 ? cmd.slice(0, 45) + "…" : cmd
|
||||
}
|
||||
let s = b.dispatcher + (b.arg ? " " + b.arg : "")
|
||||
return s.length > 48 ? s.slice(0, 45) + "…" : s
|
||||
}
|
||||
|
||||
onAllBindsChanged: updateFilter()
|
||||
onActiveTabChanged: updateFilter()
|
||||
|
||||
Timer {
|
||||
id: closeTimer
|
||||
interval: 220
|
||||
onTriggered: root.animating = false
|
||||
}
|
||||
|
||||
|
||||
Process {
|
||||
id: bindsProc
|
||||
command: ["hyprctl", "binds", "-j"]
|
||||
stdout: StdioCollector {
|
||||
onStreamFinished: {
|
||||
try { root.allBinds = JSON.parse(this.text) } catch(e) {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Variants {
|
||||
model: Quickshell.screens
|
||||
|
||||
delegate: Component {
|
||||
PanelWindow {
|
||||
required property var modelData
|
||||
screen: modelData
|
||||
|
||||
WlrLayershell.namespace: "quickshell:keybinds"
|
||||
WlrLayershell.layer: WlrLayer.Overlay
|
||||
surfaceFormat { opaque: false }
|
||||
exclusionMode: ExclusionMode.Ignore
|
||||
focusable: true
|
||||
|
||||
visible: modelData.name === root.targetMonitor
|
||||
&& (root.keybindsVisible || root.animating)
|
||||
|
||||
anchors { top: true; bottom: true; left: true; right: true }
|
||||
color: "transparent"
|
||||
|
||||
// Dim backdrop
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
color: Qt.rgba(0, 0, 0, 0.45)
|
||||
opacity: root.keybindsVisible ? 1.0 : 0.0
|
||||
Behavior on opacity { NumberAnimation { duration: 180; easing.type: Easing.OutCubic } }
|
||||
}
|
||||
|
||||
// Click on backdrop to close
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: {
|
||||
root.keybindsVisible = false
|
||||
closeTimer.restart()
|
||||
}
|
||||
}
|
||||
|
||||
// Card
|
||||
Rectangle {
|
||||
id: card
|
||||
anchors.centerIn: parent
|
||||
width: 760
|
||||
height: 560
|
||||
z: 1
|
||||
radius: Shared.Theme.radiusNormal
|
||||
color: Shared.Theme.popoutBackground
|
||||
border.width: 1
|
||||
border.color: Shared.Theme.borderSubtle
|
||||
focus: true
|
||||
|
||||
opacity: root.keybindsVisible ? 1.0 : 0.0
|
||||
scale: root.keybindsVisible ? 1.0 : 0.97
|
||||
|
||||
Behavior on opacity { NumberAnimation { duration: 180; easing.type: Easing.OutCubic } }
|
||||
Behavior on scale { NumberAnimation { duration: 220; easing.type: Easing.OutCubic } }
|
||||
|
||||
Keys.onEscapePressed: {
|
||||
root.keybindsVisible = false
|
||||
closeTimer.restart()
|
||||
}
|
||||
|
||||
// Consume clicks so backdrop doesn't close
|
||||
MouseArea { anchors.fill: parent; z: -1 }
|
||||
|
||||
ColumnLayout {
|
||||
anchors.fill: parent
|
||||
anchors.margins: Shared.Theme.popoutPadding
|
||||
spacing: Shared.Theme.popoutSpacing
|
||||
|
||||
// ── Header ──────────────────────────────
|
||||
RowLayout {
|
||||
Layout.fillWidth: true
|
||||
spacing: 12
|
||||
|
||||
// Icon badge — styled like the key chips
|
||||
Rectangle {
|
||||
implicitWidth: 34
|
||||
implicitHeight: 28
|
||||
radius: 6
|
||||
color: Qt.alpha(Shared.Theme.accent, Shared.Theme.opacityLight)
|
||||
border.width: 1
|
||||
border.color: Qt.alpha(Shared.Theme.accent, 0.35)
|
||||
|
||||
Text {
|
||||
anchors.centerIn: parent
|
||||
text: "⌨"
|
||||
color: Shared.Theme.accent
|
||||
font.pixelSize: 16
|
||||
font.family: Shared.Theme.fontFamily
|
||||
}
|
||||
}
|
||||
|
||||
Text {
|
||||
text: "Keybinds"
|
||||
color: Shared.Theme.text
|
||||
font.pixelSize: Shared.Theme.fontLarge
|
||||
font.family: Shared.Theme.fontFamily
|
||||
font.bold: true
|
||||
}
|
||||
|
||||
Item { Layout.fillWidth: true }
|
||||
|
||||
Text {
|
||||
text: "ESC / click outside to close"
|
||||
color: Shared.Theme.overlay0
|
||||
font.pixelSize: Shared.Theme.fontSmall
|
||||
font.family: Shared.Theme.fontFamily
|
||||
}
|
||||
}
|
||||
|
||||
// ── Tabs ────────────────────────────────
|
||||
RowLayout {
|
||||
Layout.fillWidth: true
|
||||
spacing: 6
|
||||
|
||||
Repeater {
|
||||
model: root.tabLabels
|
||||
|
||||
Rectangle {
|
||||
required property string modelData
|
||||
required property int index
|
||||
|
||||
readonly property bool current: root.activeTab === index
|
||||
|
||||
implicitHeight: 30
|
||||
implicitWidth: tabText.implicitWidth + 20
|
||||
radius: Shared.Theme.radiusSmall
|
||||
color: current
|
||||
? Qt.alpha(Shared.Theme.accent, Shared.Theme.opacityLight)
|
||||
: Qt.alpha(Shared.Theme.surface0, 0.5)
|
||||
border.width: 1
|
||||
border.color: current
|
||||
? Qt.alpha(Shared.Theme.accent, Shared.Theme.opacityMedium)
|
||||
: Shared.Theme.borderSubtle
|
||||
|
||||
Behavior on color { ColorAnimation { duration: 120 } }
|
||||
Behavior on border.color { ColorAnimation { duration: 120 } }
|
||||
|
||||
Text {
|
||||
id: tabText
|
||||
anchors.centerIn: parent
|
||||
text: modelData
|
||||
color: parent.current ? Shared.Theme.accent : Shared.Theme.subtext0
|
||||
font.pixelSize: Shared.Theme.fontSmall
|
||||
font.family: Shared.Theme.fontFamily
|
||||
font.bold: parent.current
|
||||
|
||||
Behavior on color { ColorAnimation { duration: 120 } }
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: root.activeTab = index
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Item { Layout.fillWidth: true }
|
||||
|
||||
Text {
|
||||
text: root.filteredBinds.length + " binds"
|
||||
color: Shared.Theme.overlay0
|
||||
font.pixelSize: Shared.Theme.fontSmall
|
||||
font.family: Shared.Theme.fontFamily
|
||||
}
|
||||
}
|
||||
|
||||
// ── Divider ─────────────────────────────
|
||||
Rectangle {
|
||||
Layout.fillWidth: true
|
||||
implicitHeight: 1
|
||||
color: Shared.Theme.borderSubtle
|
||||
}
|
||||
|
||||
// ── Bind list ───────────────────────────
|
||||
ListView {
|
||||
id: bindsList
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
model: root.filteredBinds
|
||||
clip: true
|
||||
spacing: 2
|
||||
boundsBehavior: Flickable.StopAtBounds
|
||||
|
||||
ScrollBar.vertical: ScrollBar {
|
||||
policy: ScrollBar.AsNeeded
|
||||
width: 6
|
||||
}
|
||||
|
||||
delegate: Rectangle {
|
||||
required property var modelData
|
||||
required property int index
|
||||
|
||||
width: bindsList.width - 8
|
||||
implicitHeight: 34
|
||||
radius: Shared.Theme.radiusSmall
|
||||
color: rowMouse.containsMouse
|
||||
? Qt.alpha(Shared.Theme.surface0, 0.6)
|
||||
: "transparent"
|
||||
|
||||
Behavior on color { ColorAnimation { duration: 80 } }
|
||||
|
||||
RowLayout {
|
||||
anchors.fill: parent
|
||||
anchors.leftMargin: 8
|
||||
anchors.rightMargin: 8
|
||||
spacing: 12
|
||||
|
||||
Rectangle {
|
||||
implicitHeight: 22
|
||||
implicitWidth: Math.max(keyLabel.implicitWidth + 14, 36)
|
||||
radius: 5
|
||||
color: Qt.alpha(Shared.Theme.accent, Shared.Theme.opacityLight)
|
||||
border.width: 1
|
||||
border.color: Qt.alpha(Shared.Theme.accent, 0.25)
|
||||
|
||||
Text {
|
||||
id: keyLabel
|
||||
anchors.centerIn: parent
|
||||
text: root.formatKey(modelData.key)
|
||||
color: Shared.Theme.accent
|
||||
font.pixelSize: Shared.Theme.fontSmall
|
||||
font.family: Shared.Theme.fontFamily
|
||||
font.bold: true
|
||||
}
|
||||
}
|
||||
|
||||
Text {
|
||||
Layout.fillWidth: true
|
||||
text: root.formatAction(modelData)
|
||||
color: Shared.Theme.text
|
||||
font.pixelSize: Shared.Theme.fontSize
|
||||
font.family: Shared.Theme.fontFamily
|
||||
elide: Text.ElideRight
|
||||
}
|
||||
|
||||
Text {
|
||||
visible: modelData.dispatcher !== "exec"
|
||||
&& modelData.dispatcher !== ""
|
||||
&& modelData.dispatcher !== "lua"
|
||||
text: modelData.dispatcher
|
||||
color: Shared.Theme.overlay0
|
||||
font.pixelSize: Shared.Theme.fontSmall
|
||||
font.family: Shared.Theme.fontFamily
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: rowMouse
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,10 +4,12 @@ import Quickshell
|
||||
import "notifications"
|
||||
import "osd"
|
||||
import "lock"
|
||||
import "keybinds"
|
||||
|
||||
ShellRoot {
|
||||
NotificationDaemon { id: notifDaemon }
|
||||
Bar { notifModel: notifDaemon.trackedNotifications; notifDaemon: notifDaemon }
|
||||
Osd {}
|
||||
IdleScreen { id: idleScreen }
|
||||
KeybindsWindow {}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
#!/usr/bin/env bash
|
||||
# Wayland-native VimTeX viewer: Zathura + DBus forward search + hyprctl focus
|
||||
# No xdotool required.
|
||||
#
|
||||
# VimTeX config:
|
||||
# vimtex_view_method = "general"
|
||||
# vimtex_view_general_viewer = "zathura-synctex"
|
||||
# vimtex_view_general_options = "--synctex-forward @line:@col:@tex @pdf"
|
||||
|
||||
synctex=""
|
||||
if [[ "${1:-}" == "--synctex-forward" ]]; then
|
||||
synctex="$2"
|
||||
pdf="$(realpath "$3")"
|
||||
else
|
||||
pdf="$(realpath "$1")"
|
||||
fi
|
||||
|
||||
# Inverse search reuses the nvim socket inherited from the calling nvim instance
|
||||
inverse="nvim --server ${NVIM} --remote-send ':VimtexInverseSearch %{line}:%{column} \"%{input}\"\\<cr\\>'"
|
||||
|
||||
# Find a zathura process that has this exact PDF path in its cmdline
|
||||
find_pid() {
|
||||
for p in $(pgrep -x zathura 2>/dev/null); do
|
||||
tr '\0' '\n' < "/proc/$p/cmdline" 2>/dev/null | grep -qxF "$pdf" \
|
||||
&& echo "$p" && return
|
||||
done
|
||||
}
|
||||
|
||||
pid="$(find_pid)"
|
||||
|
||||
if [[ -n "$pid" ]]; then
|
||||
# Window already open: forward search via DBus, then focus
|
||||
if [[ -n "$synctex" ]]; then
|
||||
line="${synctex%%:*}"
|
||||
rest="${synctex#*:}"; col="${rest%%:*}"; input="${rest#*:}"
|
||||
gdbus call --session \
|
||||
--dest "org.pwmt.zathura.PID-${pid}" \
|
||||
--object-path /org/pwmt/zathura \
|
||||
--method org.pwmt.zathura.SynctexView \
|
||||
"$input" "$line" "$col" >/dev/null 2>&1 || true
|
||||
fi
|
||||
hyprctl dispatch "hl.dsp.focus({ window = \"pid:${pid}\" })" >/dev/null 2>&1 || true
|
||||
else
|
||||
# Open fresh zathura with inverse search hook
|
||||
if [[ -n "$synctex" ]]; then
|
||||
zathura -x "$inverse" --synctex-forward "$synctex" "$pdf" &
|
||||
else
|
||||
zathura -x "$inverse" "$pdf" &
|
||||
fi
|
||||
zpid=$!
|
||||
# Give the window ~400ms to map, then focus it
|
||||
(sleep 0.4 && hyprctl dispatch "hl.dsp.focus({ window = \"pid:${zpid}\" })" >/dev/null 2>&1) &
|
||||
fi
|
||||
Reference in New Issue
Block a user