From b6c665f02fa30986a2385d58cba90e8e9ea73497 Mon Sep 17 00:00:00 2001 From: Tovi Jaeschke-Rogers Date: Mon, 10 Nov 2025 08:20:24 +1030 Subject: [PATCH] feat: add river config --- .config/kanshi/config | 27 ++++ .config/keyd/default.conf | 7 + .config/keyd/normal.conf | 5 + .config/keyd/swapped.conf | 6 + .config/nvim/lua/core/autocmd.lua | 11 ++ .config/nvim/lua/lsp/servers/tsserver.lua | 12 -- .config/nvim/lua/plugins/diffview.lua | 4 + .config/river/init | 158 ++++++++++++++++++++++ .config/river/scripts/toggle-caps-esc.sh | 14 ++ .config/waybar/config.jsonc | 145 +------------------- .config/waybar/style.css | 134 ++++-------------- 11 files changed, 268 insertions(+), 255 deletions(-) create mode 100644 .config/kanshi/config create mode 100644 .config/keyd/default.conf create mode 100644 .config/keyd/normal.conf create mode 100644 .config/keyd/swapped.conf create mode 100644 .config/nvim/lua/plugins/diffview.lua create mode 100755 .config/river/init create mode 100755 .config/river/scripts/toggle-caps-esc.sh diff --git a/.config/kanshi/config b/.config/kanshi/config new file mode 100644 index 0000000..baf9a3a --- /dev/null +++ b/.config/kanshi/config @@ -0,0 +1,27 @@ +# Triple monitor setup (2 external + laptop) +profile docked { + output "ASUSTek COMPUTER INC VY249HGR SALMRS003158" mode 1920x1080@60Hz position 2880,0 + output "ASUSTek COMPUTER INC VY249HGR SALMRS003212" mode 1920x1080@60Hz position 4800,0 + output "Samsung Display Corp. 0x419F" mode 2880x1800@120Hz position 3979,1080 scale 1.648438 +} + +# Laptop only +profile laptop { + output "Samsung Display Corp. 0x419F" mode 2880x1800@120Hz position 0,0 scale 1.648438 +} + +# Left external only +profile left-external { + output "ASUSTek COMPUTER INC VY249HGR SALMRS003158" mode 1920x1080@60Hz position 0,0 +} + +# Right external only +profile right-external { + output "ASUSTek COMPUTER INC VY249HGR SALMRS003212" mode 1920x1080@60Hz position 0,0 +} + +# Both externals, no laptop +profile dual-external { + output "ASUSTek COMPUTER INC VY249HGR SALMRS003158" mode 1920x1080@60Hz position 0,0 + output "ASUSTek COMPUTER INC VY249HGR SALMRS003212" mode 1920x1080@60Hz position 1920,0 +} diff --git a/.config/keyd/default.conf b/.config/keyd/default.conf new file mode 100644 index 0000000..17468e7 --- /dev/null +++ b/.config/keyd/default.conf @@ -0,0 +1,7 @@ +[ids] +* + +[main] +# Swap capslock and escape by default +capslock = esc +esc = capslock diff --git a/.config/keyd/normal.conf b/.config/keyd/normal.conf new file mode 100644 index 0000000..fa20da6 --- /dev/null +++ b/.config/keyd/normal.conf @@ -0,0 +1,5 @@ +[ids] +* + +[main] +# Nothing remapped diff --git a/.config/keyd/swapped.conf b/.config/keyd/swapped.conf new file mode 100644 index 0000000..5a2b213 --- /dev/null +++ b/.config/keyd/swapped.conf @@ -0,0 +1,6 @@ +[ids] +* + +[main] +capslock = esc +esc = capslock diff --git a/.config/nvim/lua/core/autocmd.lua b/.config/nvim/lua/core/autocmd.lua index 6e36ece..05d51bf 100644 --- a/.config/nvim/lua/core/autocmd.lua +++ b/.config/nvim/lua/core/autocmd.lua @@ -1,5 +1,16 @@ vim.api.nvim_set_hl(0, "YankColor", { fg = "#C8C093", bg = "#000000", ctermfg = 59, ctermbg = 41 }) +-- Use double backslashes +vim.api.nvim_set_hl(0, 'InvisibleChar', { bg = '#ff0000', fg = '#ffffff' }) + +vim.api.nvim_create_autocmd({'BufEnter', 'BufWritePost', 'TextChanged', 'InsertLeave'}, { + group = vim.api.nvim_create_augroup('InvisibleChars', { clear = true }), + callback = function() + vim.fn.clearmatches() + vim.fn.matchadd('InvisibleChar', '\\%u2028\\|\\%u200b\\|\\%u200c\\|\\%u200d\\|\\%u2029\\|\\%ufeff') + end +}) + local aucmd_dict = { VimEnter = { { diff --git a/.config/nvim/lua/lsp/servers/tsserver.lua b/.config/nvim/lua/lsp/servers/tsserver.lua index f36452f..16d4ad7 100644 --- a/.config/nvim/lua/lsp/servers/tsserver.lua +++ b/.config/nvim/lua/lsp/servers/tsserver.lua @@ -42,24 +42,12 @@ local function get_tsserver_cmd(root_dir) return { tsserver, '--stdio' } end - -- Check for local typescript-language-server in node_modules - tsserver = root_dir .. '/node_modules/.bin/tsserver' - if vim.loop.fs_stat(tsserver) then - return { tsserver, '--stdio' } - end - -- Check frontend/node_modules tsserver = root_dir .. '/frontend/node_modules/.bin/typescript-language-server' if vim.loop.fs_stat(tsserver) then return { tsserver, '--stdio' } end - -- Check frontend/node_modules - tsserver = root_dir .. '/frontend/node_modules/.bin/tsserver' - if vim.loop.fs_stat(tsserver) then - return { tsserver, '--stdio' } - end - -- Fallback to Mason return { vim.fn.expand('~/.local/share/nvim/mason/bin/typescript-language-server'), '--stdio' } end diff --git a/.config/nvim/lua/plugins/diffview.lua b/.config/nvim/lua/plugins/diffview.lua new file mode 100644 index 0000000..0aa847e --- /dev/null +++ b/.config/nvim/lua/plugins/diffview.lua @@ -0,0 +1,4 @@ +return { + "sindrets/diffview.nvim", + opts = {}, +} diff --git a/.config/river/init b/.config/river/init new file mode 100755 index 0000000..8944483 --- /dev/null +++ b/.config/river/init @@ -0,0 +1,158 @@ +#!/bin/sh + +riverctl map normal Super+Shift Return spawn alacritty +riverctl map normal Super P spawn "wofi --show drun" + +riverctl map normal Super T spawn ~/.config/river/scripts/toggle-caps-esc.sh + +# Super+Q to close the focused view +riverctl map normal Super Q close + +# Super+Shift+E to exit river +riverctl map normal Super+Shift E exit + +# Super+J and Super+K to focus the next/previous view in the layout stack +riverctl map normal Super J focus-view next +riverctl map normal Super K focus-view previous + +# Super+Shift+J and Super+Shift+K to swap the focused view with the next/previous +# view in the layout stack +riverctl map normal Super+Shift J swap next +riverctl map normal Super+Shift K swap previous + +# Super+Period and Super+Comma to focus the next/previous output +riverctl map normal Super Period focus-output next +riverctl map normal Super Comma focus-output previous + +# Super+Shift+{Period,Comma} to send the focused view to the next/previous output +riverctl map normal Super+Shift Period send-to-output next +riverctl map normal Super+Shift Comma send-to-output previous + +# Super+Return to bump the focused view to the top of the layout stack +riverctl map normal Super Return zoom + +# Super+H and Super+L to decrease/increase the main ratio of rivertile(1) +riverctl map normal Super H send-layout-cmd rivertile "main-ratio -0.05" +riverctl map normal Super L send-layout-cmd rivertile "main-ratio +0.05" + +# Super+Shift+H and Super+Shift+L to increment/decrement the main count of rivertile(1) +riverctl map normal Super+Shift H send-layout-cmd rivertile "main-count +1" +riverctl map normal Super+Shift L send-layout-cmd rivertile "main-count -1" + +# Super+Alt+{H,J,K,L} to move views +riverctl map normal Super+Alt H move left 100 +riverctl map normal Super+Alt J move down 100 +riverctl map normal Super+Alt K move up 100 +riverctl map normal Super+Alt L move right 100 + +# Super+Alt+Control+{H,J,K,L} to snap views to screen edges +riverctl map normal Super+Alt+Control H snap left +riverctl map normal Super+Alt+Control J snap down +riverctl map normal Super+Alt+Control K snap up +riverctl map normal Super+Alt+Control L snap right + +# Super+Alt+Shift+{H,J,K,L} to resize views +riverctl map normal Super+Alt+Shift H resize horizontal -100 +riverctl map normal Super+Alt+Shift J resize vertical 100 +riverctl map normal Super+Alt+Shift K resize vertical -100 +riverctl map normal Super+Alt+Shift L resize horizontal 100 + +# Super + Left Mouse Button to move views +riverctl map-pointer normal Super BTN_LEFT move-view + +# Super + Right Mouse Button to resize views +riverctl map-pointer normal Super BTN_RIGHT resize-view + +# Super + Middle Mouse Button to toggle float +riverctl map-pointer normal Super BTN_MIDDLE toggle-float + +for i in $(seq 1 9) +do + tags=$((1 << ($i - 1))) + + # Super+[1-9] to focus tag [0-8] + riverctl map normal Super $i set-focused-tags $tags + + # Super+Shift+[1-9] to tag focused view with tag [0-8] + riverctl map normal Super+Shift $i set-view-tags $tags + + # Super+Control+[1-9] to toggle focus of tag [0-8] + riverctl map normal Super+Control $i toggle-focused-tags $tags + + # Super+Shift+Control+[1-9] to toggle tag [0-8] of focused view + riverctl map normal Super+Shift+Control $i toggle-view-tags $tags +done + +# Super+0 to focus all tags +# Super+Shift+0 to tag focused view with all tags +all_tags=$(((1 << 32) - 1)) +riverctl map normal Super 0 set-focused-tags $all_tags +riverctl map normal Super+Shift 0 set-view-tags $all_tags + +# Super+Space to toggle float +riverctl map normal Super Space toggle-float + +# Super+F to toggle fullscreen +riverctl map normal Super F toggle-fullscreen + +# Super+{Up,Right,Down,Left} to change layout orientation +riverctl map normal Super Up send-layout-cmd rivertile "main-location top" +riverctl map normal Super Right send-layout-cmd rivertile "main-location right" +riverctl map normal Super Down send-layout-cmd rivertile "main-location bottom" +riverctl map normal Super Left send-layout-cmd rivertile "main-location left" + +# Declare a passthrough mode. This mode has only a single mapping to return to +# normal mode. This makes it useful for testing a nested wayland compositor +riverctl declare-mode passthrough + +# Super+F11 to enter passthrough mode +riverctl map normal Super F11 enter-mode passthrough + +# Super+F11 to return to normal mode +riverctl map passthrough Super F11 enter-mode normal + +# Various media key mapping examples for both normal and locked mode which do +# not have a modifier +for mode in normal locked +do + # Eject the optical drive (well if you still have one that is) + riverctl map $mode None XF86Eject spawn 'eject -T' + + # Control pulse audio volume with pamixer (https://github.com/cdemoulins/pamixer) + riverctl map $mode None XF86AudioRaiseVolume spawn 'pamixer -i 5' + riverctl map $mode None XF86AudioLowerVolume spawn 'pamixer -d 5' + riverctl map $mode None XF86AudioMute spawn 'pamixer --toggle-mute' + + # Control MPRIS aware media players with playerctl (https://github.com/altdesktop/playerctl) + riverctl map $mode None XF86AudioMedia spawn 'playerctl play-pause' + riverctl map $mode None XF86AudioPlay spawn 'playerctl play-pause' + riverctl map $mode None XF86AudioPrev spawn 'playerctl previous' + riverctl map $mode None XF86AudioNext spawn 'playerctl next' + + # Control screen backlight brightness with brightnessctl (https://github.com/Hummer12007/brightnessctl) + riverctl map $mode None XF86MonBrightnessUp spawn 'brightnessctl set +5%' + riverctl map $mode None XF86MonBrightnessDown spawn 'brightnessctl set 5%-' +done + +# Set background and border color +riverctl background-color 0x000000 +riverctl border-color-focused 0x5ea1ff +riverctl border-color-unfocused 0x3c4048 + +# Set keyboard repeat rate +riverctl set-repeat 50 300 + +# Make all views with an app-id that starts with "float" and title "foo" start floating. +riverctl rule-add -app-id 'float*' -title 'foo' float + +# Make all views with app-id "bar" and any title use client-side decorations +riverctl rule-add -app-id "bar" csd + +# Set the default layout generator to be rivertile and start it. +# River will send the process group of the init executable SIGTERM on exit. +riverctl default-layout rivertile +rivertile -view-padding 6 -outer-padding 6 & + +waybar & + +kanshi & diff --git a/.config/river/scripts/toggle-caps-esc.sh b/.config/river/scripts/toggle-caps-esc.sh new file mode 100755 index 0000000..1c78e57 --- /dev/null +++ b/.config/river/scripts/toggle-caps-esc.sh @@ -0,0 +1,14 @@ +#!/bin/bash + +# Check if keyd is using the swapped config +if pgrep -f "keyd.*default.conf" > /dev/null && keyd list | grep -q "capslock = esc"; then + # Currently swapped, switch to normal config + sudo cp ~/.config/keyd/normal.conf ~/.config/keyd/default.conf + sudo keyd reload + notify-send "Keyboard Layout" "Caps Lock and Escape returned to normal" -i input-keyboard +else + # Not swapped, switch to swapped config + sudo cp ~/.config/keyd/swapped.conf ~/.config/keyd/default.conf + sudo keyd reload + notify-send "Keyboard Layout" "Caps Lock and Escape swapped" -i input-keyboard +fi diff --git a/.config/waybar/config.jsonc b/.config/waybar/config.jsonc index 3601351..e220ede 100644 --- a/.config/waybar/config.jsonc +++ b/.config/waybar/config.jsonc @@ -1,144 +1,13 @@ -// -*- mode: jsonc -*- { "layer": "top", - "mode": "dock", - "position": "top", // (top|bottom|left|right) - "height": 40, // (to be removed for auto height) - "width": "auto", - "spacing": 3, // Gaps between modules - "margin": 0, - "fixed-center": true, - "reload_style_on_change": true, - "modules-left": [ - "hyprland/workspaces", - "hyprland/submap", - ], - "modules-center": [ - "clock" - ], - "modules-right": [ - "pulseaudio", - "temperature", - "network", - "backlight", - "battery", - "tray" - ], - "keyboard-state": { - "numlock": true, - "capslock": true, - "format": "{icon} {name}", - "format-icons": { - "locked": "", - "unlocked": "" - } - }, - "tray": { - "icon-size": 24, - "show-passive-items": true, - "spacing": 10 + "modules-left": ["river/tags"], + "modules-center": ["clock"], + "modules-right": ["battery", "network", "pulseaudio"], + + "river/tags": { + "num-tags": 9 }, "clock": { - "interval": 1, - "format": "{:%A %d. %b %T}", - "tooltip-format": "{calendar}", - "calendar": { - "format": { - "today": "{}" - } - } - }, - "temperature": { - "interval": 1000, - "critical-threshold": 80, - "format": "{temperatureC}°C" - }, - "backlight": { - "format": "{icon}", - "tooltip-format": "{icon} {percent}", - "format-icons": [ - "󰌶", - "󱩎", - "󱩏", - "󱩐", - "󱩑", - "󱩒", - "󱩓", - "󱩔", - "󱩕", - "󱩖", - "󰛨" - ] - }, - "battery": { - "states": { - // "good": 95, - "warning": 30, - "critical": 15 - }, - "format": "{icon}", - "format-full": "{icon}", - "format-charging": "{icon} ", - "format-plugged": "{icon} ", - "format-alt": "{icon}", - "format-icons": [ - "", - "", - "", - "", - "" - ] - }, - "power-profiles-daemon": { - "format": "{icon}", - "tooltip-format": "Power profile: {profile}\nDriver: {driver}", - "tooltip": true, - "format-icons": { - "default": "", - "performance": "", - "balanced": "", - "power-saver": "" - } - }, - "network": { - "interval": 1000, - "format-wifi": "{icon}", - "format-ethernet": "{ipaddr}/{cidr} ", - "tooltip-format": "{essid}\n{ifname} via {gwaddr}\n{ipaddr}/{cidr}", - "format-linked": "{ifname} (No IP) ", - "format-disconnected": "󰤭", - "format-alt": "{essid}", - "format-icons": [ - "󰤯", - "󰤟", - "󰤢", - "󰤥", - "󰤨" - ] - }, - "pulseaudio": { - "format": "{icon} {format_source}", - "format-muted": " {format_source}", - "format-source": "", - "format-source-muted": " ", - "format-bluetooth": "{icon} {format_source}", - "format-bluetooth-muted": "{icon} {format_source}", - "format-icons": { - "headphone": "", - "hands-free": "", - "headset": "󰋎", - "phone": " ", - "portable": " ", - "car": "", - "default": [ - "", - "", - "" - ] - }, - "tooltip-format": "{icon} {volume}%\n{format_source}", - "ignored-sinks": [ - "Easy Effects Sink" - ] + "format": "{:%a %d %b %H:%M}" } } diff --git a/.config/waybar/style.css b/.config/waybar/style.css index 4ccf423..5766f8e 100644 --- a/.config/waybar/style.css +++ b/.config/waybar/style.css @@ -1,130 +1,54 @@ * { - border: none; - border-radius: 0; - font-family: JetBrainsMono NerdFont, Roboto, Helvetica, Arial, sans-serif; - font-size: 14px; - min-height: 0; + font-family: "JetBrainsMono NerdFont"; + font-size: 13px; + border: none; + border-radius: 0; } window#waybar { - background: rgba(0, 0, 0, 0.6); - color: white; + background: #000000; + color: #ffffff; } -button { - margin: 3px; - padding: 3px; +#tags button { + padding: 0 5px; + color: #ffffff; + background: transparent; + border-bottom: 2px solid transparent; } -tooltip { - background: rgba(0, 0, 0, 0.202);/*rgba(43, 48, 59, 0.5);*/ - border: 4px solid white; - border-radius: 10px; +#tags button.occupied { + color: #8c9098; + border-bottom: 2px solid #8c9098; } -tooltip label { - color: white; +#tags button.focused { + color: #000000; + background: #5ea1ff; } -#workspaces button { - margin: 0; - padding: 0; - - background: transparent; - color: #888888; -} - -#workspaces button.active { - color: white; -} - -#mode, -#clock, -#battery, -#pulseaudio, -#temperature, -#language, -#backlight, -#network, -#tray, -#custom-weather { - padding: 0 10px; -} - -#scratchpad, -#window { - margin-left: 6px; - margin-right: 6px; -} - -#custom-weather.sunny { - color: rgb(215, 215, 0); -} - -#custom-weather.lightrain { - color: lightblue; -} - -#custom-weather.rain, -#custom-weather.heavyrain { - color: blue; -} - -#custom-weather.cloudy, -#custom-weather.fog { - color: gray; -} - -#window { - color: darkred; -} - -#language { - color: cadetblue; -} - -#pulseaudio { - color: darkcyan; -} - -#network { - color: coral; -} - -#temperature { - color: rgb(91, 191, 225); -} - -#backlight { - color: rgb(255, 255, 61); +#tags button:hover { + background: #1a1a1a; } #clock { - color: aqua; + padding: 0 10px; + color: #ffffff; } -#battery { - color: rgb(147, 63, 225); +#battery, #network, #pulseaudio { + padding: 0 10px; + color: #ffffff; } #battery.charging { - color: #26A65B; + color: #5ea1ff; } -@keyframes blink { - to { - color: white; - } +#battery.warning { + color: #ffaa00; } -#battery.warning:not(.charging), -#temperature.critical, -#workspaces button.urgent, -#mode { - color: #ff0000; - animation-name: blink; - animation-duration: 0.5s; - animation-timing-function: steps(2); - animation-iteration-count: infinite; - animation-direction: alternate; +#battery.critical { + color: #ff5555; }