diff options
| author | 2026-04-21 01:23:18 +0100 | |
|---|---|---|
| committer | 2026-04-21 01:23:18 +0100 | |
| commit | d00bf2cb2d5087164fa509a4f20a2be62a519044 (patch) | |
| tree | e788986ca341fa7a9d7327b48c58d2e0c0c43115 /dot_config | |
| parent | 9b2af4dd6c73ea57cc921f41120db7a2700e806d (diff) | |
| download | dotfiles-d00bf2cb2d5087164fa509a4f20a2be62a519044.tar.gz dotfiles-d00bf2cb2d5087164fa509a4f20a2be62a519044.tar.bz2 dotfiles-d00bf2cb2d5087164fa509a4f20a2be62a519044.zip | |
refactor: restructure to chezmoi source state
Rename home/ contents to chezmoi naming conventions:
- dot_ prefix for dotfiles and dot-dirs
- private_dot_ for .gnupg and .ssh directories
- private_ for 0600 files (nym.pub)
- executable_ for scripts in .local/bin and display-toggle.sh
- symlink_ for mimeapps.list symlink
Diffstat (limited to 'dot_config')
74 files changed, 3972 insertions, 0 deletions
diff --git a/dot_config/MangoHud/MangoHud.conf b/dot_config/MangoHud/MangoHud.conf new file mode 100644 index 0000000..322ad92 --- /dev/null +++ b/dot_config/MangoHud/MangoHud.conf @@ -0,0 +1,10 @@ +cpu_stats +cpu_temp +gpu_stats +gpu_temp +frame_timing +font_size=16 +position=bottom-right +ram +vram +background_alpha=0.8 diff --git a/dot_config/aerc/aerc.conf b/dot_config/aerc/aerc.conf new file mode 100644 index 0000000..25deb62 --- /dev/null +++ b/dot_config/aerc/aerc.conf @@ -0,0 +1,32 @@ +[ui] +styleset-name=gruvbox +fuzzy-complete=true +reverse-msglist-order=true +threading-enabled=true +show-thread-context=true + +[compose] +address-book-cmd=khard email --remove-first-line --parsable %s +file-picker-cmd=fzf --multi --query=%s +empty-subject-warning=true +no-attachment-warning=^[^>]*attach(ed|ment) + +[multipart-converters] +text/html=pandoc -f markdown -t html --standalone + +[filters] +text/plain=colorize +text/calendar=calendar +message/delivery-status=colorize +message/rfc822=colorize +text/html=html | colorize +text/*=bat -fP --file-name="$AERC_FILENAME" +application/x-sh=bat -fP -l sh +.headers=colorize + +[openers] +x-scheme-handler/http*=librewolf +text/html=librewolf + +[hooks] +mail-received=notify-send "[$AERC_ACCOUNT/$AERC_FOLDER] New mail from $AERC_FROM_NAME" "$AERC_SUBJECT" diff --git a/dot_config/aerc/binds.conf b/dot_config/aerc/binds.conf new file mode 100644 index 0000000..145efd9 --- /dev/null +++ b/dot_config/aerc/binds.conf @@ -0,0 +1,165 @@ +# Binds are of the form <key sequence> = <command to run> +# To use '=' in a key sequence, substitute it with "Eq": "<Ctrl+Eq>" +# If you wish to bind #, you can wrap the key sequence in quotes: "#" = quit +<C-p> = :prev-tab<Enter> +<C-PgUp> = :prev-tab<Enter> +<C-n> = :next-tab<Enter> +<C-PgDn> = :next-tab<Enter> +<C-t> = :term<Enter> +? = :help keys<Enter> +<C-c> = :prompt 'Quit?' quit<Enter> +<C-q> = :prompt 'Quit?' quit<Enter> + +[messages] +q = :quit<Enter> +h = :quit<Enter> + +j = :next<Enter> +<Down> = :next<Enter> +<C-d> = :next 50%<Enter> +<C-f> = :next 100%<Enter> +<PgDn> = :next 100%<Enter> + +k = :prev<Enter> +<Up> = :prev<Enter> +<C-u> = :prev 50%<Enter> +<C-b> = :prev 100%<Enter> +<PgUp> = :prev 100%<Enter> +g = :select 0<Enter> +G = :select -1<Enter> + +J = :next-folder<Enter> +<C-Down> = :next-folder<Enter> +K = :prev-folder<Enter> +<C-Up> = :prev-folder<Enter> +H = :collapse-folder<Enter> +<C-Left> = :collapse-folder<Enter> +L = :expand-folder<Enter> +<C-Right> = :expand-folder<Enter> + +v = :mark -t<Enter> +<Space> = :mark -t<Enter>:next<Enter> +V = :mark -v<Enter> + +T = :toggle-threads<Enter> +zc = :fold<Enter> +zo = :unfold<Enter> + +<Enter> = :view<Enter> +d = :prompt 'Really delete this message?' 'delete-message'<Enter> +D = :delete<Enter> +a = :archive flat<Enter> +A = :unmark -a<Enter>:mark -T<Enter>:archive flat<Enter> + +C = :compose<Enter> +m = :compose<Enter> + +rr = :reply -a<Enter> +rq = :reply -aq<Enter> +Rr = :reply<Enter> +Rq = :reply -q<Enter> + +c = :cf<space> +$ = :term<space> +! = :term<space> +| = :pipe<space> + +/ = :search<space> +\ = :filter<space> +n = :next-result<Enter> +N = :prev-result<Enter> +<Esc> = :clear<Enter> + +s = :split<Enter> +S = :vsplit<Enter> + +[messages:folder=Drafts] +<Enter> = :recall<Enter> + +[view] +/ = :toggle-key-passthrough<Enter>/ +q = :close<Enter> +h = :close<Enter> +O = :open<Enter> +o = :open<Enter> +S = :save<space> +| = :pipe<space> +D = :delete<Enter> +A = :archive flat<Enter> +s = :flag -t<Enter> + +<C-l> = :open-link <space> + +f = :forward<Enter> +rr = :reply -a<Enter> +rq = :reply -aq<Enter> +Rr = :reply<Enter> +Rq = :reply -q<Enter> + +H = :toggle-headers<Enter> +<C-k> = :prev-part<Enter> +<C-Up> = :prev-part<Enter> +<C-j> = :next-part<Enter> +<C-Down> = :next-part<Enter> +J = :next<Enter> +<C-Right> = :next<Enter> +K = :prev<Enter> +<C-Left> = :prev<Enter> + +[view::passthrough] +$noinherit = true +$ex = <C-x> +<Esc> = :toggle-key-passthrough<Enter> + +[compose] +# Keybindings used when the embedded terminal is not selected in the compose +# view +$noinherit = true +$ex = <C-x> +<C-k> = :prev-field<Enter> +<C-Up> = :prev-field<Enter> +<C-j> = :next-field<Enter> +<C-Down> = :next-field<Enter> +<A-p> = :switch-account -p<Enter> +<C-Left> = :switch-account -p<Enter> +<A-n> = :switch-account -n<Enter> +<C-Right> = :switch-account -n<Enter> +<tab> = :next-field<Enter> +<backtab> = :prev-field<Enter> +<C-p> = :prev-tab<Enter> +<C-PgUp> = :prev-tab<Enter> +<C-n> = :next-tab<Enter> +<C-PgDn> = :next-tab<Enter> + +[compose::editor] +# Keybindings used when the embedded terminal is selected in the compose view +$noinherit = true +$ex = <C-x> +<C-k> = :prev-field<Enter> +<C-Up> = :prev-field<Enter> +<C-j> = :next-field<Enter> +<C-Down> = :next-field<Enter> +<C-p> = :prev-tab<Enter> +<C-PgUp> = :prev-tab<Enter> +<C-n> = :next-tab<Enter> +<C-PgDn> = :next-tab<Enter> + +[compose::review] +# Keybindings used when reviewing a message to be sent +y = :send<Enter> +n = :abort<Enter> +v = :preview<Enter> +p = :postpone<Enter> +q = :choose -o d discard abort -o p postpone postpone<Enter> +e = :edit<Enter> +a = :attach<space> +d = :detach<space> + +[terminal] +$noinherit = true +$ex = <C-x> + +<C-p> = :prev-tab<Enter> +<C-n> = :next-tab<Enter> +<C-PgUp> = :prev-tab<Enter> +<C-PgDn> = :next-tab<Enter> diff --git a/dot_config/bat/config b/dot_config/bat/config new file mode 100644 index 0000000..c0afe26 --- /dev/null +++ b/dot_config/bat/config @@ -0,0 +1,25 @@ +# This is `bat`s configuration file. Each line either contains a comment or +# a command-line option that you want to pass to `bat` by default. You can +# run `bat --help` to get a list of all possible configuration options. + +# Specify desired highlighting theme (e.g. "TwoDark"). Run `bat --list-themes` +# for a list of all available themes +--theme="gruvbox-dark" + +# Enable this to use italic text on the terminal. This is not supported on all +# terminal emulators (like tmux, by default): +#--italic-text=always + +# Uncomment the following line to disable automatic paging: +#--paging=never + +# Uncomment the following line if you are using less version >= 551 and want to +# enable mouse scrolling support in `bat` when running inside tmux. This might +# disable text selection, unless you press shift. +#--pager="less --RAW-CONTROL-CHARS --quit-if-one-screen --mouse" + +# Syntax mappings: map a certain filename pattern to a language. +# Example 1: use the C++ syntax for .ino files +# Example 2: Use ".gitignore"-style highlighting for ".ignore" files +#--map-syntax "*.ino:C++" +#--map-syntax ".ignore:Git Ignore" diff --git a/dot_config/cargo/config.toml b/dot_config/cargo/config.toml new file mode 100644 index 0000000..0ef993e --- /dev/null +++ b/dot_config/cargo/config.toml @@ -0,0 +1,6 @@ +[target.x86_64-unknown-linux-gnu] +linker = "clang" +rustflags = ["-C", "target-cpu=native", "-C", "link-arg=-fuse-ld=mold"] + +[build] +rustc-wrapper = "sccache" diff --git a/dot_config/ccache/ccache.conf b/dot_config/ccache/ccache.conf new file mode 100644 index 0000000..99d2c37 --- /dev/null +++ b/dot_config/ccache/ccache.conf @@ -0,0 +1,2 @@ +max_size = 0 +reshare = true diff --git a/dot_config/clangd/config.yaml b/dot_config/clangd/config.yaml new file mode 100644 index 0000000..a50287d --- /dev/null +++ b/dot_config/clangd/config.yaml @@ -0,0 +1,23 @@ +--- +Index: + StandardLibrary: Yes +Diagnostics: + ClangTidy: + FastCheckFilter: None + UnusedIncludes: Strict + # MissingIncludes: Strict + Includes: + AnalyzeAngledIncludes: Yes +InlayHints: + Enabled: Yes + BlockEnd: Yes + DefaultArguments: Yes +Hover: + ShowAKA: Yes +# --- +# If: +# PathMatch: ~/llvm-project/.* +# Index: +# External: +# Server: clangd.devel.appentra.com:5900 +# MountPoint: /home/ruifm/work/pw-project diff --git a/dot_config/fd/ignore b/dot_config/fd/ignore new file mode 100644 index 0000000..2d2ecd6 --- /dev/null +++ b/dot_config/fd/ignore @@ -0,0 +1 @@ +.git/ diff --git a/dot_config/fontconfig/fonts.conf b/dot_config/fontconfig/fonts.conf new file mode 100644 index 0000000..63eac54 --- /dev/null +++ b/dot_config/fontconfig/fonts.conf @@ -0,0 +1,35 @@ +<?xml version="1.0"?> +<!DOCTYPE fontconfig SYSTEM "fonts.dtd"> +<fontconfig> + +<alias> + <family>monospace</family> + <prefer> + <family>Fira Code</family> + <family>DejaVu Sans Mono</family> + <family>Inconsolata</family> + </prefer> + </alias> + + <alias> + <family>sans-serif</family> + <prefer> + <family>DejaVu Sans</family> + <family>Droid Sans</family> + <family>Ubuntu</family> + <family>Helvetica</family> + </prefer> + </alias> + + <alias> + <family>serif</family> + <prefer> + <family>Latin Modern Math</family> + <family>DejaVu Serif</family> + <family>CMU Serif</family> + <family>Latin Modern Roman</family> + <family>Computer Modern</family> + </prefer> + </alias> + +</fontconfig> diff --git a/dot_config/fuzzel/fuzzel.ini b/dot_config/fuzzel/fuzzel.ini new file mode 100644 index 0000000..b1ea0bb --- /dev/null +++ b/dot_config/fuzzel/fuzzel.ini @@ -0,0 +1,20 @@ +[main] +font=mono:size=8 +width=60 +lines=15 +list-executables-in-path=yes +terminal=ghostty -e + +[colors] +background=282828ff +text=ebdbb2ff +prompt=fabd2fff +input=ebdbb2ff +match=fb4934ff +selection=fabd2fff +selection-text=282828ff +border=fabd2fff + +[border] +width=1 +radius=0 diff --git a/dot_config/gamemode.ini b/dot_config/gamemode.ini new file mode 100644 index 0000000..d6a5189 --- /dev/null +++ b/dot_config/gamemode.ini @@ -0,0 +1,7 @@ +[general] +reaper_freq=5 +desiredgov=performance +defaultgov=performance +softrealtime=off +renice=0 +ioprio=0 diff --git a/dot_config/gdb/gdbearlyinit b/dot_config/gdb/gdbearlyinit new file mode 100644 index 0000000..b73aa96 --- /dev/null +++ b/dot_config/gdb/gdbearlyinit @@ -0,0 +1 @@ +set startup-quietly on diff --git a/dot_config/gdb/gdbinit b/dot_config/gdb/gdbinit new file mode 100644 index 0000000..8a2852c --- /dev/null +++ b/dot_config/gdb/gdbinit @@ -0,0 +1,6 @@ +set debuginfod enabled on +set confirm off +set print pretty on +set follow-fork-mode child +set auto-load local-gdbinit on +set auto-load safe-path / diff --git a/dot_config/ghostty/config b/dot_config/ghostty/config new file mode 100644 index 0000000..18bb644 --- /dev/null +++ b/dot_config/ghostty/config @@ -0,0 +1,37 @@ +# Theme (verify: ghostty +list-themes | grep -i gruvbox) +theme = Gruvbox Dark + +# Cursor — block blink; disable shell integration cursor override +cursor-style = block +cursor-style-blink = true +shell-integration-features = no-cursor + +# OSC 52 clipboard for zellij (default is "ask" which prompts each time) +clipboard-read = allow + +# Bell — request urgency hint on BEL so sway/waybar highlight the workspace +bell-features = attention,title + +# Window — no decorations (sway manages windows) +window-decoration = none +confirm-close-surface = false +resize-overlay = never + +# Disable built-in tab/split keybinds (zellij handles multiplexing) +keybind = ctrl+shift+t=unbind +keybind = ctrl+shift+n=unbind +keybind = ctrl+shift+o=unbind +keybind = ctrl+shift+enter=unbind +keybind = ctrl+shift+page_up=unbind +keybind = ctrl+shift+page_down=unbind + +# Scroll keybinds (for use outside zellij) +keybind = ctrl+shift+up=scroll_page_lines:-1 +keybind = ctrl+shift+down=scroll_page_lines:1 +# Copy URL under cursor to clipboard (works inside zellij without mouse) +keybind = ctrl+shift+u=copy_url_to_clipboard + +keybind = alt+u=scroll_page_up +keybind = alt+d=scroll_page_down +keybind = alt+g=scroll_to_top +keybind = alt+shift+g=scroll_to_bottom diff --git a/dot_config/git/attributes b/dot_config/git/attributes new file mode 100644 index 0000000..a9faf44 --- /dev/null +++ b/dot_config/git/attributes @@ -0,0 +1,26 @@ +*.java merge=mergiraf +*.rs merge=mergiraf +*.go merge=mergiraf +*.js merge=mergiraf +*.jsx merge=mergiraf +*.json merge=mergiraf +*.yml merge=mergiraf +*.yaml merge=mergiraf +*.toml merge=mergiraf +*.html merge=mergiraf +*.htm merge=mergiraf +*.xhtml merge=mergiraf +*.xml merge=mergiraf +*.c merge=mergiraf +*.h merge=mergiraf +*.cc merge=mergiraf +*.cpp merge=mergiraf +*.hpp merge=mergiraf +*.cs merge=mergiraf +*.dart merge=mergiraf +*.scala merge=mergiraf +*.sbt merge=mergiraf +*.ts merge=mergiraf +*.tsx merge=mergiraf +*.py merge=mergiraf +*.lua merge=mergiraf diff --git a/dot_config/git/config b/dot_config/git/config new file mode 100644 index 0000000..87947d0 --- /dev/null +++ b/dot_config/git/config @@ -0,0 +1,135 @@ +[user] + email = sommerfeld@sommerfeld.dev + name = sommerfeld + signingkey = 3298945F717C85F8 +[push] + autoSetupRemote = true + followTags = true + gpgSign = if-asked +[core] + whitespace = trailing-space,cr-at-eol + pager = delta +[branch] + sort=-committerdate +[diff] + tool = nvimdiff + algorithm = histogram + colorMoved = default + colorMovedWS = allow-indentation-change + mnemonicPrefix = true + relative = true + renameLimit = 10000 +[difftool] + prompt = false + trustExitCode = true +[pager] + difftool = true +[difftool "nvimdiff"] + cmd = $EDITOR -d $LOCAL $REMOTE +[difftool "difftastic"] + cmd = difft "$MERGED" "$LOCAL" "abcdef1" "100644" "$REMOTE" "abcdef2" "100644" +[rebase] + autoStash = true + autoSquash = true + updateRefs = true +[fetch] + recurseSubmodules = on-demand + prune = true +[rerere] + enabled = true +[pull] + ff = only +[merge] + tool = conflictmarker + conflictstyle = zdiff3 +[merge "mergiraf"] + name = mergiraf + driver = mergiraf merge --git %O %A %B -s %S -x %X -y %Y -p %P +[mergetool] + keepBackup = false +[mergetool "conflictmarker"] + cmd = $EDITOR "$MERGED" +[commit] + gpgsign = true +[tag] + gpgSign = true +[status] + short = true + branch = true + showUntrackedFiles = all + showStash = true + submoduleSummary = true +[help] + autocorrect = prompt +[log] + abbrevCommit = true + date = short +[interactive] + singleKey = true + diffFilter = delta --color-only +[advice] + detachedHead = false + skippedCherryPicks = false +[column] + ui = auto +[format] + pretty = oneline +[delta] + navigate = true + features = gruvmax-fang zebra-dark + dark = true + side-by-side = true + line-numbers = true + relative-paths = true + hyperlinks = true +[absorb] + autoStageIfNothingStaged = true +[alias] + ghost-rebase = "!sh -c 'b=$0; u=${1:-origin/master}; wt=$(mktemp -d -t rebwt.XXXXXX); git worktree add -f "$wt" "$b"; git -C "$wt" rebase "$u" || echo "Rebase incomplete"; git worktree remove --force "$wt"'" + a = add + ab=absorb --and-rebase + b = branch -vv + bd = branch -D + c = commit + ca = commit --amend --no-edit + cp = cherry-pick + d = diff + dft = -c diff.external=difft diff + dl = -c diff.external=difft log -p --ext-diff + ds = -c diff.external=difft show --ext-diff + dt = difftool + f = fetch + fa = fetch --all + ff = merge --ff-only + find-merge = "!sh -c 'commit=$0 && branch=${1:-HEAD} && (git rev-list $commit..$branch --ancestry-path | cat -n; git rev-list $commit..$branch --first-parent | cat -n) | sort -k2 -s | uniq -f1 -d | sort -n | tail -1 | cut -f2'" + fmt = clang-format -f + fp = push --force-with-lease + gone = !git for-each-ref --format '%(refname:short) %(upstream:track)' | awk '$2 == \"[gone]\" {print $1}' | xargs -r git branch -D + l = log + lg = log --graph --oneline + lm = log --pretty=medium + m = merge + mt = mergetool + p = push + r = rebase + re = remote -v + ri = rebase -i + rt = restore + s = status + st = status --no-short + staged = diff --cached + sub = submodule + subf = submodule foreach + sw = switch + swc = switch -c + swd = switch -d + unstage = reset HEAD -- + update=!git fetch && git merge --ff-only +[includeIf "gitdir:/home/*/work/"] + path = config-work +[includeIf "gitdir:~/doxfiles/.git"] + path = config-personal +[includeIf "gitdir:~/dev/copilot/.git"] + path = config-personal +[includeIf "gitdir:~/dev/personal/"] + path = config-personal diff --git a/dot_config/git/ignore b/dot_config/git/ignore new file mode 100644 index 0000000..07d5ee0 --- /dev/null +++ b/dot_config/git/ignore @@ -0,0 +1,21 @@ +*.mod +*.tar.gz +*.tar.zst +*.zip +.SRCINFO +**/.cache/clangd/index/ +__pycache__/ +build*/ +/compile_commands.json +node_modules/ +.env/ +.venv/ +env/ +venv/ +.gdbinit +.lldbinit +.nvim.lua +.nvim/ +.ignore +/tablegen_compile_commands.yml +.git.copilot diff --git a/dot_config/gtk-3.0/gtk.css b/dot_config/gtk-3.0/gtk.css new file mode 100644 index 0000000..d506506 --- /dev/null +++ b/dot_config/gtk-3.0/gtk.css @@ -0,0 +1,36 @@ +.window-frame, .window-frame:backdrop { + box-shadow: 0 0 0 black; + border-style: none; + margin: 0; + border-radius: 0; +} + +.titlebar { + border-radius: 0; +} + +.window-frame.csd.popup { + box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2), 0 0 0 1px rgba(0, 0, 0, 0.13); +} + +.header-bar { + background-image: none; + background-color: #ededed; + box-shadow: none; +} +headerbar .title { + opacity: 0; +} +/* Always use background color */ +window { + background-color: @theme_bg_color; +} + +/* Fix tooltip background override */ +.tooltip { + background-color: rgba(0, 0, 0, 0.8); +} + +.tooltip * { + background-color: transparent; +} diff --git a/dot_config/gtk-3.0/settings.ini b/dot_config/gtk-3.0/settings.ini new file mode 100644 index 0000000..4339296 --- /dev/null +++ b/dot_config/gtk-3.0/settings.ini @@ -0,0 +1,17 @@ +[Settings] +gtk-theme-name=Adwaita +gtk-icon-theme-name=Adwaita +gtk-font-name=Sans 11 +gtk-cursor-theme-name=Adwaita +gtk-cursor-theme-size=0 +gtk-enable-event-sounds=0 +gtk-enable-input-feedback-sounds=0 +gtk-enable-primary-paste=false +gtk-xft-antialias=1 +gtk-menu-popup-delay = 0 +gtk-xft-hinting=1 +gtk-xft-hintstyle=hintfull +gtk-xft-rgba=rgb +gtk-decoration-layout=menu: +gtk-application-prefer-dark-theme=1 +gtk-error-bell = 0 diff --git a/dot_config/ipython/profile_default/ipython_config.py b/dot_config/ipython/profile_default/ipython_config.py new file mode 100644 index 0000000..1ff9f35 --- /dev/null +++ b/dot_config/ipython/profile_default/ipython_config.py @@ -0,0 +1,5 @@ +c.InteractiveShell.banner1 = "" +c.InteractiveShell.colors = "Linux" +c.InteractiveShell.enable_html_pager = True +c.TerminalInteractiveShell.confirm_exit = False +c.TerminalInteractiveShell.extra_open_editor_shortcuts = True diff --git a/dot_config/lsd/config.yaml b/dot_config/lsd/config.yaml new file mode 100644 index 0000000..2421130 --- /dev/null +++ b/dot_config/lsd/config.yaml @@ -0,0 +1,20 @@ +# == Blocks == +# This specifies the columns and their order when using the long and the tree +# layout. +# Possible values: permission, user, group, size, size_value, date, name, inode +blocks: + - permission + - user + - group + - size + - date + - name + +# == Icons == +icons: + # When to use icons. + # When "classic" is set, this is set to "never". + # Possible values: always, auto, never + when: never + +layout: oneline diff --git a/dot_config/mako/config b/dot_config/mako/config new file mode 100644 index 0000000..161f357 --- /dev/null +++ b/dot_config/mako/config @@ -0,0 +1,21 @@ +font=mono 8 +background-color=#282828 +text-color=#ebdbb2 +border-color=#fabd2f +border-size=1 +border-radius=0 +padding=8 +margin=4 +width=300 +default-timeout=5000 +anchor=top-right + +[urgency=low] +border-color=#8ec07c + +[urgency=normal] +border-color=#fabd2f + +[urgency=critical] +border-color=#fb4934 +default-timeout=0 diff --git a/dot_config/mimeapps.list b/dot_config/mimeapps.list new file mode 100644 index 0000000..bd3a703 --- /dev/null +++ b/dot_config/mimeapps.list @@ -0,0 +1,101 @@ +[Default Applications] +audio/x-vorbis+ogg=mpv.desktop +audio/aac=mpv.desktop +audio/x-aac=mpv.desktop +audio/m4a=mpv.desktop +audio/x-m4a=mpv.desktop +audio/mp1=mpv.desktop +audio/x-mp1=mpv.desktop +audio/mp2=mpv.desktop +audio/x-mp2=mpv.desktop +audio/mp3=mpv.desktop +audio/x-mp3=mpv.desktop +audio/mpeg=mpv.desktop +audio/x-mpeg=mpv.desktop +audio/mpegurl=mpv.desktop +audio/x-mpegurl=mpv.desktop +audio/mpg=mpv.desktop +audio/x-mpg=mpv.desktop +audio/rn-mpeg=mpv.desktop +audio/ogg=mpv.desktop +audio/scpls=mpv.desktop +audio/x-scpls=mpv.desktop +audio/vnd.rn-realaudio=mpv.desktop +audio/wav=mpv.desktop +audio/x-pn-windows-pcm=mpv.desktop +audio/x-realaudio=mpv.desktop +audio/x-pn-realaudio=mpv.desktop +audio/x-ms-wma=mpv.desktop +audio/x-pls=mpv.desktop +audio/x-wav=mpv.desktop +audio/x-flac=mpv.desktop +audio/x-shorten=mpv.desktop +audio/x-ape=mpv.desktop +audio/x-wavpack=mpv.desktop +audio/x-tta=mpv.desktop +audio/AMR=mpv.desktop +audio/ac3=mpv.desktop +audio/flac=mpv.desktop +audio/mp4=mpv.desktop +video/x-ogm+ogg=mpv.desktop +video/mpeg=mpv.desktop +video/x-mpeg=mpv.desktop +video/x-mpeg2=mpv.desktop +video/mp4=mpv.desktop +video/msvideo=mpv.desktop +video/x-msvideo=mpv.desktop +video/ogg=mpv.desktop +video/quicktime=mpv.desktop +video/vnd.rn-realvideo=mpv.desktop +video/x-ms-afs=mpv.desktop +video/x-ms-asf=mpv.desktop +video/x-ms-wmv=mpv.desktop +video/x-ms-wmx=mpv.desktop +video/x-ms-wvxvideo=mpv.desktop +video/x-avi=mpv.desktop +video/x-fli=mpv.desktop +video/x-flv=mpv.desktop +video/x-theora=mpv.desktop +video/x-matroska=mpv.desktop +video/webm=mpv.desktop +video/mp2t=mpv.desktop +image/x-nikon-nef=imv.desktop +image/jpeg=imv.desktop +image/png=imv.desktop +image/gif=mpv.desktop +image/svg+xml=librewolf.desktop +text/markdown=nvim.desktop +text/plain=nvim.desktop +text/x-python=nvim.desktop +text/x-chdr=nvim.desktop +text/x-tex=nvim.desktop +application/x-shellscript=nvim.desktop +application/x-bittorrent=transmission.desktop +application/pdf=org.pwmt.zathura-pdf-mupdf.desktop +application/postscript=zathura-pdf-poppler.desktop;org.pwmt.zathura-pdf-mupdf.desktop +application/rss+xml=rss.desktop +x-scheme-handler/magnet=transmission.desktop +x-scheme-handler/mailto=mail.desktop +application/msword-template=xdot.desktop +x-scheme-handler/http=librewolf.desktop +x-scheme-handler/https=librewolf.desktop +x-scheme-handler/chrome=librewolf.desktop +text/html=librewolf.desktop +application/x-extension-htm=librewolf.desktop +application/x-extension-html=librewolf.desktop +application/x-extension-shtml=librewolf.desktop +application/xhtml+xml=librewolf.desktop +application/x-extension-xhtml=librewolf.desktop +application/x-extension-xht=librewolf.desktop + +[Added Associations] +x-scheme-handler/http=librewolf.desktop; +x-scheme-handler/https=librewolf.desktop; +x-scheme-handler/chrome=librewolf.desktop; +text/html=librewolf.desktop; +application/x-extension-htm=librewolf.desktop; +application/x-extension-html=librewolf.desktop; +application/x-extension-shtml=librewolf.desktop; +application/xhtml+xml=librewolf.desktop; +application/x-extension-xhtml=librewolf.desktop; +application/x-extension-xht=librewolf.desktop; diff --git a/dot_config/mpv/input.conf b/dot_config/mpv/input.conf new file mode 100644 index 0000000..679c4a2 --- /dev/null +++ b/dot_config/mpv/input.conf @@ -0,0 +1,96 @@ +# mpv keybindings +# +# Location of user-defined bindings: ~/.config/mpv/input.conf +# +# Lines starting with # are comments. Use SHARP to assign the # key. +# Copy this file and uncomment and edit the bindings you want to change. +# +# List of commands and further details: DOCS/man/input.rst +# List of special keys: --input-keylist +# Keybindings testing mode: mpv --input-test --force-window --idle +# +# Use 'ignore' to unbind a key fully (e.g. 'ctrl+a ignore'). +# +# Strings need to be quoted and escaped: +# KEY show-text "This is a single backslash: \\ and a quote: \" !" +# +# You can use modifier-key combinations like Shift+Left or Ctrl+Alt+x with +# the modifiers Shift, Ctrl, Alt and Meta (may not work on the terminal). +# +# The default keybindings are hardcoded into the mpv binary. +# You can disable them completely with: --no-input-default-bindings + +# Mouse wheels, touchpad or other input devices that have axes +# if the input devices supports precise scrolling it will also scale the +# numeric value accordingly +WHEEL_UP ignore +WHEEL_DOWN ignore +WHEEL_LEFT ignore +WHEEL_RIGHT ignore + +## Seek units are in seconds, but note that these are limited by keyframes +RIGHT seek 5 +LEFT seek -5 +UP seek 60 +DOWN seek -60 +# Do smaller, always exact (non-keyframe-limited), seeks with shift. +# Don't show them on the OSD (no-osd). +Shift+RIGHT no-osd seek 1 exact +Shift+LEFT no-osd seek -1 exact +Shift+UP no-osd seek 5 exact +Shift+DOWN no-osd seek -5 exact +# Skip to previous/next subtitle (subject to some restrictions; see manpage) +Ctrl+LEFT no-osd sub-seek -1 +Ctrl+RIGHT no-osd sub-seek 1 +# Adjust timing to previous/next subtitle +#Ctrl+Shift+LEFT sub-step -1 +#Ctrl+Shift+RIGHT sub-step 1 +[ multiply speed 1/1.1 # scale playback speed +] multiply speed 1.1 +{ multiply speed 0.5 +} multiply speed 2.0 +BS set speed 1.0 # reset speed to normal +Shift+BS revert-seek # undo previous (or marked) seek +q quit +Q quit-watch-later +ESC set fullscreen no +f cycle fullscreen # toggle fullscreen +p cycle pause # toggle pause/playback mode +> frame-step # advance one frame and pause +< frame-back-step # go back by one frame and pause +SPACE cycle pause +O no-osd cycle-values osd-level 3 1 # cycle through OSD mode +o show-progress +P show-progress +i script-binding stats/display-stats +I script-binding stats/display-stats-toggle +` script-binding console/enable +. script-binding console/enable +# z add sub-delay -0.1 # subtract 100 ms delay from subs +# Z add sub-delay +0.1 # add +#ctrl++ add audio-delay 0.100 # this changes audio/video sync +#ctrl+- add audio-delay -0.100 +9 add volume -2 +0 add volume 2 +m cycle mute +v cycle sub-visibility +s cycle sub # cycle through subtitles +S cycle sub down # ...backwards +PLAY cycle pause +PAUSE cycle pause +PLAYPAUSE cycle pause +PLAYONLY set pause no +PAUSEONLY set pause yes +STOP quit +FORWARD seek 60 +REWIND seek -60 +NEXT playlist-next +PREV playlist-prev +VOLUME_UP add volume 2 +VOLUME_DOWN add volume -2 +MUTE cycle mute +CLOSE_WIN quit +CLOSE_WIN {encode} quit 4 +L cycle-values loop-file "inf" "no" # toggle infinite looping +ctrl+c quit 4 +DEL script-binding osc/visibility # cycle OSC display diff --git a/dot_config/mpv/mpv.conf b/dot_config/mpv/mpv.conf new file mode 100644 index 0000000..890cbe3 --- /dev/null +++ b/dot_config/mpv/mpv.conf @@ -0,0 +1,110 @@ +# vim: syntax=config + + +########### +# General # +########### + +input-ipc-server=/tmp/mpvsocket # listen for IPC on this socket +save-position-on-quit # handled by a script + +# no-border # no window title bar +msg-module # prepend module name to log messages +msg-color # color log messages on terminal +term-osd-bar # display a progress bar on the terminal +use-filedir-conf # look for additional config files in the directory of the opened file +#pause # no autoplay +keep-open # keep the player open when a file's end is reached +cursor-autohide=100 # autohide the curser after 1s +prefetch-playlist=yes +force-seekable=yes + +hls-bitrate=max # use max quality for HLS streams +# not interested in getting videos with a resolution higher than 1080p +ytdl-format=bv*[height<=1080]+ba/b[height<=1080] +no-input-default-bindings +script-opts=ytdl_hook-ytdl_path=yt-dlp + +[default] + +#########c +# Cache # +######### + +# Configure the cache to be really big (multiple GBs) +# We have a lot of memory, so why not use it for something + +cache=yes +# cache-default=1000000 # size in KB +# cache-backbuffer=250000 # size in KB +demuxer-max-bytes=1147483647 # ~1 GiB in bytes + +############# +# Subtitles # +############# + +sub-auto=fuzzy # external subs don't have to match the file name exactly to autoload +sub-file-paths-append=ass # search for external subs in these relative subdirectories +sub-file-paths-append=srt +sub-file-paths-append=sub +sub-file-paths-append=subs +sub-file-paths-append=subtitles +sub-file-paths-append=subtitle +sub-file-paths-append=Ass # search for external subs in these relative subdirectories +sub-file-paths-append=ASS # search for external subs in these relative subdirectories +sub-file-paths-append=Srt +sub-file-paths-append=SRT +sub-file-paths-append=Sub +sub-file-paths-append=SUB +sub-file-paths-append=Subs +sub-file-paths-append=SUBS +sub-file-paths-append=Subtitles +sub-file-paths-append=SUBTITLES +sub-file-paths-append=Subtitle +sub-file-paths-append=SUBTITLE + + +#demuxer-mkv-subtitle-preroll # try to correctly show embedded subs when seeking +#embeddedfonts=yes # use embedded fonts for SSA/ASS subs +#sub-fix-timing=no # do not try to fix gaps (which might make it worse in some cases) +#sub-ass-force-style=Kerning=yes # allows you to override style parameters of ASS scripts +#sub-use-margins +#sub-ass-force-margins + +############# +# Languages # +############# + +slang=en,eng # automatically select these subtitles (decreasing priority) +# lang=en,eng # automatically select these audio tracks (decreasing priority) + + +######### +# Audio # +######### + +audio-file-auto=fuzzy # external audio doesn't has to match the file name exactly to autoload +audio-pitch-correction=yes # automatically insert scaletempo when playing with higher speed +volume-max=200 # maximum volume in %, everything above 100 results in amplification +volume=100 # default volume, 100 = unchanged + + +################ +# Video Output # +################ + +hwdec=auto-safe + +[no-spoiler] +osd-level=0 +no-osc +no-osd-bar +no-term-osd-bar +quiet +sub-auto=no + +[hq] +profile=high-quality +video-sync=display-resample +interpolation +tscale=oversample diff --git a/dot_config/mpv/scripts/webtorrent-hook.lua b/dot_config/mpv/scripts/webtorrent-hook.lua new file mode 100644 index 0000000..80d991f --- /dev/null +++ b/dot_config/mpv/scripts/webtorrent-hook.lua @@ -0,0 +1,138 @@ +-- TODO prefetch if next in playlist? +-- TODO handle torrent with multiple video files (if webtorrent can print json) +-- - don't close kill webtorrent while still videos unplayed? or in playlist? +-- - store titles/info when starting webtorrent and check stream-open-filename +-- for any item in playlist to see if it matches stored entry + +local settings = { + close_webtorrent = true, + remove_files = true, + download_directory = "/tmp/webtorrent", + webtorrent_flags = "", + webtorrent_verbosity = "speed" +} + +(require "mp.options").read_options(settings, "webtorrent-hook") + +local open_videos = {} + +-- http://lua-users.org/wiki/StringRecipes +local function ends_with(str, ending) + return ending == "" or str:sub(-#ending) == ending +end + +-- https://stackoverflow.com/questions/132397/get-back-the-output-of-os-execute-in-lua +function os.capture(cmd, decolorize, raw) + if decolorize then + -- https://github.com/webtorrent/webtorrent-cli/issues/132 + -- TODO webtorrent should have a way to just print json information with + -- no colors + -- https://stackoverflow.com/questions/19296667/remove-ansi-color-codes-from-a-text-file-using-bash/30938702#30938702 + cmd = cmd .. " | sed -r 's/\\x1B\\[(([0-9]{1,2})?(;)?([0-9]{1,2})?)?[m,K,H,f,J]//g'" + end + local f = assert(io.popen(cmd, 'r')) + local s = assert(f:read('*a')) + f:close() + if raw then return s end + s = string.gsub(s, '^%s+', '') + s = string.gsub(s, '%s+$', '') + -- s = string.gsub(s, '[\n\r]+', ' ') + return s +end + +function read_file(file) + local fh = assert(io.open(file, "rb")) + local contents = fh:read("*all") + fh:close() + return contents +end + +function play_torrent() + local url = mp.get_property("stream-open-filename") + if (url:find("magnet:") == 1 or url:find("peerflix://") == 1 + or url:find("webtorrent://") == 1 or ends_with(url, "torrent")) then + if url:find("webtorrent://") == 1 then + url = url:sub(14) + end + if url:find("peerflix://") == 1 then + url = url:sub(12) + end + + os.execute("mkdir -p " .. settings.download_directory) + -- don't reuse files (so multiple mpvs works) + local output_file = settings.download_directory + .. "/webtorrent-output-" .. mp.get_time() .. ".log" + -- --keep-seeding is to prevent webtorrent from quitting once the download + -- is done + local webtorrent_command = "webtorrent " + .. settings.webtorrent_flags + .. " --out '" .. settings.download_directory .. "' --keep-seeding \"" + .. url .. "\" > " .. output_file .. " 2>&1 & echo $!" + mp.msg.info("Starting webtorrent server") + mp.msg.info(webtorrent_command) + local pid = os.capture(webtorrent_command) + mp.msg.info("Waiting for webtorrent server") + + local url_command = "tail -f " .. output_file + .. " | awk '/Server running at:/ {print $4; exit}'" + local url = os.capture(url_command, true) + mp.msg.info("Webtorrent server is up") + + local title_command = "awk '/(Seeding|Downloading): / " + .. "{gsub(/(Seeding|Downloading): /, \"\"); print; exit}' " + .. output_file + local title = os.capture(title_command, true) + mp.msg.info("Setting media title to: " .. title) + mp.set_property("force-media-title", title) + + local path + if title then + path = settings.download_directory .. "/\"" .. title .. "\"" + end + open_videos[url] = {title=title,path=path,pid=pid} + + mp.set_property("stream-open-filename", url) + + if settings.webtorrent_verbosity == "speed" then + local printer_pid + local printer_pid_file = settings.download_directory + .. "/webtorrent-printer-" .. mp.get_time() .. ".pid" + os.execute("tail -f " .. output_file + .. " | awk '/Speed:/' ORS='\r' & echo -n $! > " + .. printer_pid_file) + printer_pid = read_file(printer_pid_file) + mp.register_event("file-loaded", + function() + os.execute("kill " .. printer_pid) + end + ) + end + end +end + +function webtorrent_cleanup() + local url = mp.get_property("stream-open-filename") + if settings.close_webtorrent and open_videos[url] then + local title = open_videos[url].title + local path = open_videos[url].path + local pid = open_videos[url].pid + + if pid then + mp.msg.info("Closing webtorrent for " .. title .. " with pid " .. pid) + os.execute("kill " .. pid) + end + + if settings.remove_files then + if path then + mp.msg.info("Removing media file for " .. title .. " with path " .. path) + os.execute("rm -r " .. path) + end + end + + open_videos[url] = {} + end +end + +mp.add_hook("on_load", 50, play_torrent) + +mp.add_hook("on_unload", 10, webtorrent_cleanup) diff --git a/dot_config/npm/npmrc b/dot_config/npm/npmrc new file mode 100644 index 0000000..ddb589b --- /dev/null +++ b/dot_config/npm/npmrc @@ -0,0 +1,3 @@ +prefix=${XDG_DATA_HOME}/npm +cache=${XDG_CACHE_HOME}/npm +tmp=${XDG_RUNTIME_DIR}/npm diff --git a/dot_config/nvim/after/ftplugin/gitcommit.lua b/dot_config/nvim/after/ftplugin/gitcommit.lua new file mode 100644 index 0000000..e670035 --- /dev/null +++ b/dot_config/nvim/after/ftplugin/gitcommit.lua @@ -0,0 +1,3 @@ +vim.wo.spell = true +vim.b.undo_ftplugin = (vim.b.undo_ftplugin or "") .. "|setlocal spell<" +vim.cmd([[match ErrorMsg /\%1l.\%>50v/]]) diff --git a/dot_config/nvim/after/ftplugin/gitrebase.lua b/dot_config/nvim/after/ftplugin/gitrebase.lua new file mode 100644 index 0000000..1bfcd69 --- /dev/null +++ b/dot_config/nvim/after/ftplugin/gitrebase.lua @@ -0,0 +1,16 @@ +local function nvmap(l, r, desc) + vim.keymap.set( + { "n", "v" }, + l, + ":" .. r .. "<CR>", + { buffer = 0, desc = "[G]it rebase " .. desc } + ) +end + +nvmap("gc", "Cycle", "[C]ycle") +nvmap("gp", "Pick", "[P]ick") +nvmap("ge", "Edit", "[E]dit") +nvmap("gf", "Fixup", "[F]ixup") +nvmap("gd", "Drop", "[D]rop") +nvmap("gs", "Squash", "[S]quash") +nvmap("gr", "Reword", "[R]eword") diff --git a/dot_config/nvim/after/ftplugin/mail.lua b/dot_config/nvim/after/ftplugin/mail.lua new file mode 100644 index 0000000..9fe1500 --- /dev/null +++ b/dot_config/nvim/after/ftplugin/mail.lua @@ -0,0 +1 @@ +vim.wo.spell = true diff --git a/dot_config/nvim/after/ftplugin/markdown.lua b/dot_config/nvim/after/ftplugin/markdown.lua new file mode 100644 index 0000000..9fe1500 --- /dev/null +++ b/dot_config/nvim/after/ftplugin/markdown.lua @@ -0,0 +1 @@ +vim.wo.spell = true diff --git a/dot_config/nvim/after/ftplugin/text.lua b/dot_config/nvim/after/ftplugin/text.lua new file mode 100644 index 0000000..2179c42 --- /dev/null +++ b/dot_config/nvim/after/ftplugin/text.lua @@ -0,0 +1,3 @@ +vim.wo.spell = true +vim.bo.formatoptions = vim.bo.formatoptions .. "t" +vim.bo.commentstring = "# %s" diff --git a/dot_config/nvim/after/lsp/clangd.lua b/dot_config/nvim/after/lsp/clangd.lua new file mode 100644 index 0000000..e9868ae --- /dev/null +++ b/dot_config/nvim/after/lsp/clangd.lua @@ -0,0 +1,57 @@ +local function validate_bufnr(bufnr) + vim.validate("bufnr", bufnr, "number") + return bufnr == 0 and vim.api.nvim_get_current_buf() or bufnr +end + +local function switch_source_header_splitcmd(bufnr, splitcmd) + local method_name = "textDocument/switchSourceHeader" + bufnr = validate_bufnr(bufnr) + local client = vim.lsp.get_clients({ bufnr = bufnr, name = "clangd" })[1] + if not client then + return vim.notify( + ("method %s is not supported by any servers active on the current buffer"):format( + method_name + ) + ) + end + local params = vim.lsp.util.make_text_document_params(bufnr) + client.request(method_name, params, function(err, result) + if err then + error(tostring(err)) + end + if not result then + vim.notify("corresponding file cannot be determined") + return + end + vim.api.nvim_cmd({ + cmd = splitcmd, + args = { vim.uri_to_fname(result) }, + }, {}) + end, bufnr) +end + +return { + capabilities = { + offsetEncoding = { "utf-16" }, + }, + on_attach = function(_, bufnr) + local function nmap(l, r, desc) + vim.keymap.set("n", l, r, { buffer = bufnr, desc = desc }) + end + nmap("gH", function() + switch_source_header_splitcmd(bufnr, "edit") + end, "[G]o to [H]eader") + nmap("gvH", function() + switch_source_header_splitcmd(bufnr, "vsplit") + end, "[G]o in a [V]ertical split to [H]eader") + nmap("gxH", function() + switch_source_header_splitcmd(bufnr, "split") + end, "[G]o in a [X]horizontal split to [H]eader") + nmap("gtH", function() + switch_source_header_splitcmd(bufnr, "tabedit") + end, "[G]o in a [T]ab to [H]eader") + end, + init_options = { + clangdFileStatus = true, + }, +} diff --git a/dot_config/nvim/after/lsp/fortls.lua b/dot_config/nvim/after/lsp/fortls.lua new file mode 100644 index 0000000..8899dd2 --- /dev/null +++ b/dot_config/nvim/after/lsp/fortls.lua @@ -0,0 +1,10 @@ +return { + cmd = { + "fortls", + "--notify_init", + "--hover_signature", + "--hover_language=fortran", + "--use_signature_help", + "--autocomplete_no_snippets", + }, +} diff --git a/dot_config/nvim/after/lsp/lua_ls.lua b/dot_config/nvim/after/lsp/lua_ls.lua new file mode 100644 index 0000000..af0e681 --- /dev/null +++ b/dot_config/nvim/after/lsp/lua_ls.lua @@ -0,0 +1,9 @@ +return { + settings = { + Lua = { + diagnostics = { + disable = { "missing-fields" }, + }, + }, + }, +} diff --git a/dot_config/nvim/filetype.lua b/dot_config/nvim/filetype.lua new file mode 100644 index 0000000..51f8646 --- /dev/null +++ b/dot_config/nvim/filetype.lua @@ -0,0 +1,14 @@ +vim.filetype.add({ + extension = { + eml = "mail", + inc = "cpp", + def = "cpp", + Jenkinsfile = "groovy", + }, + filename = { + [".devcontainer.json"] = "jsonc", + }, + pattern = { + [".*/.github/workflows/.*%.ya?ml"] = "yaml.ghaction", + }, +}) diff --git a/dot_config/nvim/init.lua b/dot_config/nvim/init.lua new file mode 100644 index 0000000..fc3271b --- /dev/null +++ b/dot_config/nvim/init.lua @@ -0,0 +1,126 @@ +require("config.options") + +_G.P = function(v) + print(vim.inspect(v)) + return v +end + +-- Pre-load globals (must be set before plugins load) +vim.g.copilot_nes_debounce = 500 + +-- Build hooks for plugins that need post-install steps +vim.api.nvim_create_autocmd("User", { + pattern = "PackChanged", + callback = function(ev) + if ev.data.kind ~= "install" and ev.data.kind ~= "update" then + return + end + if ev.data.spec.name == "markdown-preview.nvim" then + vim.system({ "yarn", "install" }, { cwd = ev.data.path .. "/app" }) + end + end, +}) + +local gh = function(x) + return "https://github.com/" .. x +end + +vim.pack.add({ + -- UI + gh("ellisonleao/gruvbox.nvim"), + gh("saghen/blink.indent"), + gh("nvim-lualine/lualine.nvim"), + gh("AndreM222/copilot-lualine"), + + -- Treesitter + { src = gh("nvim-treesitter/nvim-treesitter"), version = "main" }, + gh("RRethy/nvim-treesitter-endwise"), + gh("nvim-treesitter/nvim-treesitter-context"), + gh("JoosepAlviste/nvim-ts-context-commentstring"), + gh("aaronik/treewalker.nvim"), + gh("LiadOz/nvim-dap-repl-highlights"), + + -- Completion + gh("saghen/blink.compat"), + { src = gh("saghen/blink.cmp"), version = vim.version.range("*") }, + gh("rafamadriz/friendly-snippets"), + gh("fang2hou/blink-copilot"), + gh("rcarriga/cmp-dap"), + gh("xzbdmw/colorful-menu.nvim"), + { src = gh("saghen/blink.pairs"), version = vim.version.range("*") }, + { src = gh("saghen/blink.download"), version = "main" }, + + -- Editing + gh("nmac427/guess-indent.nvim"), + gh("kylechui/nvim-surround"), + gh("chrisgrieser/nvim-various-textobjs"), + gh("monaqa/dial.nvim"), + gh("ThePrimeagen/refactoring.nvim"), + gh("nvim-lua/plenary.nvim"), + + -- Git + gh("akinsho/git-conflict.nvim"), + gh("NeogitOrg/neogit"), + gh("ruifm/gitlinker.nvim"), + gh("lewis6991/gitsigns.nvim"), + + -- LSP + gh("folke/lazydev.nvim"), + gh("neovim/nvim-lspconfig"), + gh("j-hui/fidget.nvim"), + gh("williamboman/mason.nvim"), + gh("williamboman/mason-lspconfig.nvim"), + gh("WhoIsSethDaniel/mason-tool-installer.nvim"), + gh("stevearc/conform.nvim"), + gh("mrcjkb/rustaceanvim"), + gh("mfussenegger/nvim-lint"), + gh("rachartier/tiny-inline-diagnostic.nvim"), + + -- Debug + { src = gh("miroshQa/debugmaster.nvim"), version = "dashboard" }, + gh("mfussenegger/nvim-dap"), + gh("theHamsta/nvim-dap-virtual-text"), + gh("jay-babu/mason-nvim-dap.nvim"), + + -- Runner + gh("stevearc/overseer.nvim"), + + -- Search + { src = gh("ibhagwan/fzf-lua"), version = "main" }, + + -- Session + gh("rmagatti/auto-session"), + + -- AI + gh("zbirenbaum/copilot.lua"), + gh("copilotlsp-nvim/copilot-lsp"), + + -- Misc + gh("iamcco/markdown-preview.nvim"), + gh("mrjones2014/smart-splits.nvim"), + gh("folke/which-key.nvim"), + gh("stevearc/quicker.nvim"), + gh("stevearc/oil.nvim"), +}, { confirm = false }) + +-- Colorscheme (must be set immediately after plugins are on rtp) +require("gruvbox").setup({}) +vim.o.background = "dark" +vim.cmd.colorscheme("gruvbox") + +-- Plugin configurations (order matters for dependencies) +require("plugins.ui") +require("plugins.treesitter") +require("plugins.completion") +require("plugins.editing") +require("plugins.git") +require("plugins.lsp") +require("plugins.debug") +require("plugins.runner") +require("plugins.search") +require("plugins.session") +require("plugins.ai") +require("plugins.init") + +require("config.keymaps") +require("config.autocmds") diff --git a/dot_config/nvim/lua/config/autocmds.lua b/dot_config/nvim/lua/config/autocmds.lua new file mode 100644 index 0000000..2d1ea9b --- /dev/null +++ b/dot_config/nvim/lua/config/autocmds.lua @@ -0,0 +1,128 @@ +local function augroup(name) + return vim.api.nvim_create_augroup(name, { clear = true }) +end + +local autocmd = vim.api.nvim_create_autocmd + +-- Check if we need to reload the file when it changed +autocmd({ "FocusGained", "TermClose", "TermLeave" }, { + group = augroup("checktime"), + callback = function() + if vim.o.buftype ~= "nofile" then + vim.cmd("checktime") + end + end, +}) + +-- Highlight on yank +autocmd("TextYankPost", { + group = augroup("highlight_yank"), + callback = vim.hl.on_yank, +}) + +-- go to last loc when opening a buffer +autocmd("BufReadPost", { + group = augroup("last_loc"), + callback = function(event) + local exclude = { "gitcommit" } + local buf = event.buf + if + vim.tbl_contains(exclude, vim.bo[buf].filetype) or vim.b[buf].last_loc + then + return + end + vim.b[buf].last_loc = true + local mark = vim.api.nvim_buf_get_mark(buf, '"') + local lcount = vim.api.nvim_buf_line_count(buf) + if mark[1] > 0 and mark[1] <= lcount then + pcall(vim.api.nvim_win_set_cursor, 0, mark) + end + end, +}) + +-- close some filetypes with <q> +autocmd("FileType", { + group = augroup("close_with_q"), + pattern = { + "PlenaryTestPopup", + "checkhealth", + "dbout", + "gitsigns-blame", + "help", + "lspinfo", + "notify", + "qf", + "startuptime", + }, + callback = function(event) + vim.bo[event.buf].buflisted = false + vim.schedule(function() + vim.keymap.set("n", "q", function() + vim.cmd("close") + pcall(vim.api.nvim_buf_delete, event.buf, { force = true }) + end, { + buffer = event.buf, + silent = true, + desc = "Quit buffer", + }) + end) + end, +}) + +-- make it easier to close man-files when opened inline +autocmd("FileType", { + group = augroup("man_unlisted"), + pattern = { "man" }, + callback = function(event) + vim.bo[event.buf].buflisted = false + end, +}) + +-- Auto create dir when saving a file, in case some intermediate directory does not exist +autocmd({ "BufWritePre" }, { + group = augroup("auto_create_dir"), + callback = function(event) + if event.match:match("^%w%w+:[\\/][\\/]") then + return + end + local file = vim.uv.fs_realpath(event.match) or event.match + vim.fn.mkdir(vim.fn.fnamemodify(file, ":p:h"), "p") + end, +}) + +autocmd("BufWritePost", { + group = augroup("sway"), + pattern = "*/sway/config", + command = "!swaymsg reload", +}) +autocmd("BufWritePost", { + group = augroup("waybar"), + pattern = "*/waybar/*", + command = "!killall -SIGUSR2 waybar", +}) +autocmd("BufWritePost", { + group = augroup("xdg-user-dirs"), + pattern = "user-dirs.dirs,user-dirs.locale", + command = "!xdg-user-dirs-update", +}) +autocmd("BufWritePost", { + group = augroup("mako"), + pattern = "*/mako/config", + command = "!makoctl reload", +}) +autocmd("BufWritePost", { + group = augroup("fc-cache"), + pattern = "fonts.conf", + command = "!fc-cache", +}) + +autocmd("FileType", { + group = augroup("treesitter_start"), + pattern = { "*" }, + callback = function() + if pcall(vim.treesitter.start) then + vim.wo.foldexpr = "v:lua.vim.treesitter.foldexpr()" + vim.bo.indentexpr = "v:lua.vim.treesitter.indentexpr()" + end + end, +}) diff --git a/dot_config/nvim/lua/config/keymaps.lua b/dot_config/nvim/lua/config/keymaps.lua new file mode 100644 index 0000000..366a37e --- /dev/null +++ b/dot_config/nvim/lua/config/keymaps.lua @@ -0,0 +1,136 @@ +local function map(mode, l, r, desc) + vim.keymap.set(mode, l, r, { desc = desc }) +end +local function cmd(mode, l, r, desc) + map(mode, l, "<cmd>" .. r .. "<cr>", desc) +end +local function cmdi(mode, l, r, desc) + map(mode, l, ":" .. r, desc) +end +local function nmap(l, r, desc) + map("n", l, r, desc) +end +local function vmap(l, r, desc) + map("v", l, r, desc) +end +local function nvmap(l, r, desc) + map({ "n", "v" }, l, r, desc) +end +local function ncmd(l, r, desc) + cmd("n", l, r, desc) +end +local function ncmdi(l, r, desc) + cmdi("n", l, r, desc) +end +local function vcmdi(l, r, desc) + cmdi("v", l, r, desc) +end + +ncmd("<esc>", "nohlsearch") + +-- highlight last inserted text +nmap("gV", "`[v`]") + +nmap("<down>", "<c-e>") +nmap("<up>", "<c-y>") + +-- paste over selection without clobbering registers +vmap("p", '"_dP') + +-- Find and Replace binds +ncmdi("<localleader>s", "%s/") +vcmdi("<localleader>s", "s/") + +ncmd("<leader>x", "wall") +ncmd("<leader>z", "wqall") +ncmd("<leader>q", "quitall") + +vim.keymap.set( + "t", + "<esc><esc>", + "<c-\\><c-n>", + { silent = true, noremap = true, desc = "Exit terminal mode" } +) + +nmap("[w", function() + vim.diagnostic.jump({ + count = -vim.v.count1, + severity = { min = vim.diagnostic.severity.WARN }, + }) +end) +nmap("]w", function() + vim.diagnostic.jump({ + count = vim.v.count1, + severity = { min = vim.diagnostic.severity.WARN }, + }) +end) +nmap("[e", function() + vim.diagnostic.jump({ + count = -vim.v.count1, + severity = vim.diagnostic.severity.ERROR, + }) +end) +nmap("]e", function() + vim.diagnostic.jump({ + count = vim.v.count1, + severity = vim.diagnostic.severity.ERROR, + }) +end) + +nmap("yp", function() + vim.fn.setreg("+", vim.fn.expand("%")) +end, "[Y]ank [P]ath") + +local doas_exec = function(_cmd) + vim.fn.inputsave() + local password = vim.fn.inputsecret("Password: ") + vim.fn.inputrestore() + if not password or #password == 0 then + vim.notify("Invalid password, doas aborted", vim.log.levels.WARN) + return false + end + local out = vim.fn.system(string.format("doas -S %s", _cmd), password .. "\n") + if vim.v.shell_error ~= 0 then + print("\r\n") + vim.notify(out, vim.log.levels.ERROR) + return false + end + return true +end + +vim.api.nvim_create_user_command("DoasWrite", function(opts) + local tmpfile = vim.fn.tempname() + local filepath + if #opts.fargs == 1 then + filepath = opts.fargs[1] + else + filepath = vim.fn.expand("%") + end + if not filepath or #filepath == 0 then + vim.notify("E32: No file name", vim.log.levels.ERROR) + return + end + -- `bs=1048576` is equivalent to `bs=1M` for GNU dd or `bs=1m` for BSD dd + -- Both `bs=1M` and `bs=1m` are non-POSIX + local _cmd = string.format( + "dd if=%s of=%s bs=1048576", + vim.fn.shellescape(tmpfile), + vim.fn.shellescape(filepath) + ) + -- no need to check error as this fails the entire function + vim.api.nvim_exec2(string.format("write! %s", tmpfile), { output = true }) + if doas_exec(_cmd) then + -- refreshes the buffer and prints the "written" message + vim.cmd.checktime() + -- exit command mode + vim.api.nvim_feedkeys( + vim.api.nvim_replace_termcodes("<Esc>", true, false, true), + "n", + true + ) + end + vim.fn.delete(tmpfile) +end, { + nargs = "?", + desc = "Write using doas permissions", +}) diff --git a/dot_config/nvim/lua/config/options.lua b/dot_config/nvim/lua/config/options.lua new file mode 100644 index 0000000..b2409b5 --- /dev/null +++ b/dot_config/nvim/lua/config/options.lua @@ -0,0 +1,114 @@ +local opt = vim.o + +-- Persistence +opt.undofile = true -- persist undo history across sessions +opt.swapfile = false -- no swap files; rely on undofile for recovery + +-- Gutter +opt.number = true -- show line numbers +opt.cursorline = true -- highlight current line +opt.signcolumn = "auto:2" -- up to 2 sign columns, auto-hide when empty +opt.laststatus = 3 -- single global statusline + +-- Indentation (defaults; guess-indent overrides per-buffer) +opt.expandtab = true -- spaces instead of tabs +opt.shiftround = true -- round indent to shiftwidth multiples +opt.shiftwidth = 0 -- follow tabstop value +opt.softtabstop = -1 -- follow shiftwidth value +opt.tabstop = 4 -- 4-space tabs + +-- Search +opt.gdefault = true -- substitute all matches per line by default +opt.ignorecase = true -- case-insensitive search +opt.smartcase = true -- ...unless query has uppercase + +-- Splits +opt.splitbelow = true -- horizontal splits open below +opt.splitright = true -- vertical splits open right +opt.splitkeep = "screen" -- keep text position stable on split + +-- Line wrapping +opt.linebreak = true -- wrap at word boundaries +opt.breakindent = true -- indent wrapped lines +opt.textwidth = 80 -- wrap column for formatting +opt.colorcolumn = "+1" -- highlight column after textwidth +vim.opt.formatoptions:remove("t") -- don't auto-wrap text while typing + +-- Messages +opt.messagesopt = "wait:5000,history:500" -- message display timing and history depth + +vim.opt.shortmess:append({ a = true }) -- abbreviate all file messages + +-- Timing +opt.updatetime = 250 -- CursorHold delay (ms); affects gitsigns, diagnostics +opt.timeoutlen = 300 -- key sequence timeout (ms); affects which-key popup delay + +-- Completion and scrolling +vim.opt.completeopt = { "menuone", "noselect", "popup", "fuzzy", "nearest" } +opt.scrolloff = 999 -- keep cursor vertically centered +opt.sidescrolloff = 5 -- horizontal scroll margin + +-- Clipboard (deferred to avoid blocking startup on clipboard detection) +vim.schedule(function() + opt.clipboard = vim.env.SSH_TTY and "" or "unnamedplus" +end) + +opt.mouse = "a" -- enable mouse in all modes + +vim.opt.wildmode = { "longest", "full" } -- cmdline completion: longest match, then full menu + +vim.opt.cpoptions:remove({ "_" }) -- cw changes to end of word (not compatible vi behavior) + +-- Visible whitespace +vim.opt.listchars = { + tab = "> ", + space = "·", + extends = ">", + precedes = "<", + nbsp = "+", +} +opt.list = true -- show whitespace characters + +opt.confirm = true -- confirm before closing unsaved buffers + +opt.virtualedit = "block" -- allow cursor past end of line in visual block +opt.spelloptions = "camel" -- treat camelCase words as separate words for spell check + +-- Disable unused providers +vim.g.loaded_node_provider = 0 +vim.g.loaded_perl_provider = 0 +vim.g.loaded_python3_provider = 0 + +-- Diff +vim.opt.diffopt:append({ + hiddenoff = true, -- disable diff on hidden buffers + iblank = true, -- ignore blank line changes + iwhiteall = true, -- ignore all whitespace changes + algorithm = "histogram", -- better diff algorithm +}) + +-- Use ripgrep for :grep +if vim.fn.executable("rg") then + opt.grepprg = "rg\\ --vimgrep" + opt.grepformat = "%f:%l:%c:%m" +end + +-- Popup and window borders +opt.pumblend = 20 -- popup menu transparency +opt.pumborder = "rounded" +opt.winborder = "rounded" -- default border for floating windows + +-- Folding: set up treesitter-based folds but start with them closed. +-- Autocmd in autocmds.lua sets foldexpr per-buffer when treesitter is available. +vim.o.foldmethod = "expr" +vim.o.foldenable = false + +vim.g.mapleader = " " +vim.g.maplocalleader = "," + +-- Session persistence (for auto-session) +opt.sessionoptions = + "blank,buffers,curdir,help,tabpages,winsize,winpos,terminal,localoptions" + +opt.exrc = true -- source project-local .nvim.lua files + diff --git a/dot_config/nvim/lua/plugins/ai.lua b/dot_config/nvim/lua/plugins/ai.lua new file mode 100644 index 0000000..8c213b5 --- /dev/null +++ b/dot_config/nvim/lua/plugins/ai.lua @@ -0,0 +1,34 @@ +require("copilot").setup({ + suggestion = { enabled = false }, + panel = { enabled = false }, + server_opts_overrides = { + settings = { + telemetry = { + telemetryLevel = "off", + }, + }, + }, + nes = { + enabled = true, + keymap = { + accept_and_goto = "<leader>p", + accept = false, + dismiss = "<Esc>", + }, + }, +}) + +-- Accept NES in insert mode (copilot.lua only binds normal mode) +vim.keymap.set("i", "<C-f>", function() + local ok, nes = pcall(require, "copilot-lsp.nes") + if ok and nes.apply_pending_nes() then + return + end + -- Fallback: native <C-f> (scroll window forward) + local key = vim.api.nvim_replace_termcodes("<C-f>", true, false, true) + vim.api.nvim_feedkeys(key, "n", false) +end, { desc = "Accept Copilot NES / scroll forward" }) + +vim.keymap.set("n", "<leader>tc", function() + require("copilot.command").toggle() +end, { desc = "[T]oggle [C]opilot attachment" }) diff --git a/dot_config/nvim/lua/plugins/completion.lua b/dot_config/nvim/lua/plugins/completion.lua new file mode 100644 index 0000000..df24a5d --- /dev/null +++ b/dot_config/nvim/lua/plugins/completion.lua @@ -0,0 +1,86 @@ +require("blink.compat").setup({}) + +require("blink.cmp").setup({ + keymap = { + preset = "cmdline", + ["<CR>"] = { "accept", "fallback" }, + }, + appearance = { + use_nvim_cmp_as_default = true, + }, + completion = { + menu = { + draw = { + columns = { { "kind_icon" }, { "label", gap = 1 } }, + components = { + label = { + text = function(ctx) + return require("colorful-menu").blink_components_text(ctx) + end, + highlight = function(ctx) + return require("colorful-menu").blink_components_highlight(ctx) + end, + }, + }, + }, + }, + list = { + selection = { + preselect = function() + return not require("blink.cmp").snippet_active({ direction = 1 }) + end, + }, + }, + documentation = { auto_show = true }, + }, + signature = { + enabled = true, + trigger = { + enabled = true, + show_on_keyword = true, + show_on_insert = true, + }, + }, + sources = { + default = { "lazydev", "lsp", "copilot", "snippets", "path", "buffer" }, + per_filetype = { + ["dap-repl"] = { "dap" }, + }, + providers = { + path = { + opts = { + get_cwd = vim.fn.getcwd, + }, + }, + copilot = { + name = "copilot", + module = "blink-copilot", + score_offset = 100, + async = true, + }, + lazydev = { + name = "LazyDev", + module = "lazydev.integrations.blink", + score_offset = 100, + }, + dap = { name = "dap", module = "blink.compat.source" }, + }, + }, +}) + +require("blink.pairs").setup({ + mappings = { + disabled_filetypes = {}, + }, + highlights = { + groups = { + "BlinkIndentOrange", + "BlinkIndentViolet", + "BlinkIndentBlue", + "BlinkIndentRed", + "BlinkIndentCyan", + "BlinkIndentYellow", + "BlinkIndentGreen", + }, + }, +}) diff --git a/dot_config/nvim/lua/plugins/debug.lua b/dot_config/nvim/lua/plugins/debug.lua new file mode 100644 index 0000000..bef0d1c --- /dev/null +++ b/dot_config/nvim/lua/plugins/debug.lua @@ -0,0 +1,75 @@ +vim.keymap.set("n", "<leader>td", function() + require("debugmaster").mode.toggle() +end, { desc = "[T]oggle [D]ebug mode" }) + +local dap = require("dap") + +local function get_env_vars() + local variables = vim.fn.environ() + table.insert(variables, { ASAN_OPTIONS = "detect_leaks=0" }) + return variables +end + +dap.adapters.lldb = { + type = "executable", + command = "lldb-dap", + name = "lldb", + env = get_env_vars, +} +dap.adapters.gdb = { + type = "executable", + command = "gdb", + args = { "--interpreter=dap" }, + env = get_env_vars, +} +dap.adapters.codelldb = { + type = "executable", + command = "codelldb", + env = get_env_vars, +} + +local function get_program() + local _program + vim.ui.input({ + prompt = "Program: ", + complete = "file_in_path", + }, function(res) + _program = res + end) + return vim.fn.system("which " .. _program):gsub("\n$", "") +end + +local function get_args() + local _args + vim.ui.input({ + prompt = "Args: ", + default = vim.fn.getreg("+"), + complete = "file", + }, function(res) + _args = res + end) + return require("dap.utils").splitstr(_args) +end + +dap.configurations.cpp = { + { + name = "codelldb Launch", + type = "codelldb", + request = "launch", + cwd = "${workspaceFolder}", + program = get_program, + args = get_args, + stopOnEntry = true, + console = "integratedTerminal", + }, +} + +dap.configurations.c = dap.configurations.cpp +dap.configurations.rust = dap.configurations.cpp + +require("nvim-dap-virtual-text").setup({}) +require("mason-nvim-dap").setup({ + automatic_installation = false, + handlers = {}, + ensure_installed = {}, +}) diff --git a/dot_config/nvim/lua/plugins/editing.lua b/dot_config/nvim/lua/plugins/editing.lua new file mode 100644 index 0000000..5175516 --- /dev/null +++ b/dot_config/nvim/lua/plugins/editing.lua @@ -0,0 +1,61 @@ +require("guess-indent").setup({}) + +require("various-textobjs").setup({ + keymaps = { + useDefaults = true, + }, +}) + +-- dial.nvim: enhanced increment/decrement on standard vim keys +vim.keymap.set("n", "<C-a>", function() + return require("dial.map").inc_normal() +end, { expr = true, desc = "Increment" }) +vim.keymap.set("n", "<C-x>", function() + return require("dial.map").dec_normal() +end, { expr = true, desc = "Decrement" }) +vim.keymap.set("v", "<C-a>", function() + return require("dial.map").inc_visual() +end, { expr = true, desc = "Increment" }) +vim.keymap.set("v", "<C-x>", function() + return require("dial.map").dec_visual() +end, { expr = true, desc = "Decrement" }) +vim.keymap.set("v", "g<C-a>", function() + return require("dial.map").inc_gvisual() +end, { expr = true, desc = "Increment (sequential)" }) +vim.keymap.set("v", "g<C-x>", function() + return require("dial.map").dec_gvisual() +end, { expr = true, desc = "Decrement (sequential)" }) + +-- refactoring.nvim +require("refactoring").setup({}) + +vim.keymap.set("x", "<leader>re", function() + require("refactoring").refactor("Extract Function") +end, { desc = "[R]efactor [E]xtract function" }) +vim.keymap.set("x", "<leader>rf", function() + require("refactoring").refactor("Extract Function To File") +end, { desc = "[R]efactor extract function to [F]ile" }) +vim.keymap.set("x", "<leader>rv", function() + require("refactoring").refactor("Extract Variable") +end, { desc = "[R]efactor extract [V]ariable" }) +vim.keymap.set("n", "<leader>rI", function() + require("refactoring").refactor("Inline Function") +end, { desc = "[R]efactor [I]nline function" }) +vim.keymap.set({ "x", "n" }, "<leader>ri", function() + require("refactoring").refactor("Inline Variable") +end, { desc = "[R]efactor [I]nline variable" }) +vim.keymap.set("n", "<leader>rb", function() + require("refactoring").refactor("Extract Block") +end, { desc = "[R]efactor extract [B]lock" }) +vim.keymap.set("n", "<leader>rB", function() + require("refactoring").refactor("Extract Block To File") +end, { desc = "[R]efactor extract [B]lock to file" }) +vim.keymap.set("n", "<leader>rp", function() + require("refactoring").debug.printf({}) +end, { desc = "[R]efactor [P]rint" }) +vim.keymap.set({ "x", "n" }, "<leader>rV", function() + require("refactoring").debug.print_var({}) +end, { desc = "[R]efactor [P]rint [V]ariable" }) +vim.keymap.set("n", "<leader>rc", function() + require("refactoring").debug.cleanup({}) +end, { desc = "[R]efactor [C]leanup" }) diff --git a/dot_config/nvim/lua/plugins/git.lua b/dot_config/nvim/lua/plugins/git.lua new file mode 100644 index 0000000..b052c33 --- /dev/null +++ b/dot_config/nvim/lua/plugins/git.lua @@ -0,0 +1,123 @@ +require("git-conflict").setup({ + disable_diagnostics = true, + default_mappings = { + next = "]x", + prev = "[x", + }, +}) + +require("neogit").setup({ + disable_commit_confirmation = true, + kind = "split", + console_timeout = 5000, + auto_show_console = false, +}) + +vim.keymap.set("n", "<leader>go", function() + require("neogit").open() +end, { desc = "neo[G]it [O]pen" }) + +require("gitlinker").setup({ + callbacks = { + ["git.sommerfeld.dev"] = function(url_data) + local url = require("gitlinker.hosts").get_base_https_url(url_data) + url = url .. "/tree/" .. url_data.file .. "?id=" .. url_data.rev + if url_data.lstart then + url = url .. "#n" .. url_data.lstart + end + return url + end, + }, +}) + +vim.keymap.set("n", "<leader>gy", function() + require("gitlinker").get_buf_range_url("n") +end) +vim.keymap.set("v", "<leader>gy", function() + require("gitlinker").get_buf_range_url("v") +end) + +require("gitsigns").setup({ + signs = { + change = { show_count = true }, + delete = { show_count = true }, + topdelete = { show_count = true }, + changedelete = { show_count = true }, + }, + numhl = true, + on_attach = function(bufnr) + local gs = require("gitsigns") + local function map(mode, l, r, desc) + vim.keymap.set(mode, l, r, { buffer = bufnr, desc = desc }) + end + local function nmap(l, r, desc) + map("n", l, r, desc) + end + local function vmap(l, r, desc) + map("v", l, r, desc) + end + -- Navigation + nmap("]c", function() + if vim.wo.diff then + vim.cmd.normal({ "]c", bang = true }) + else + gs.nav_hunk("next") + end + end, "Jump to next git [c]hange") + + nmap("[c", function() + if vim.wo.diff then + vim.cmd.normal({ "[c", bang = true }) + else + gs.nav_hunk("prev") + end + end, "Jump to previous git [c]hange") + + -- Actions + nmap("<leader>hs", gs.stage_hunk, "git [s]tage hunk") + nmap("<leader>hr", gs.reset_hunk, "git [r]eset hunk") + vmap("<leader>hs", function() + gs.stage_hunk({ vim.fn.line("."), vim.fn.line("v") }) + end, "git [s]tage hunk") + vmap("<leader>hr", function() + gs.reset_hunk({ vim.fn.line("."), vim.fn.line("v") }) + end, "git [r]eset hunk") + nmap("<leader>hS", gs.stage_buffer, "git [S]tage buffer") + nmap("<leader>hR", gs.reset_buffer, "git [R]eset buffer") + nmap("<leader>hp", gs.preview_hunk, "git [p]review hunk") + nmap("<leader>hb", function() + gs.blame_line({ full = true }) + end, "git [b]lame line") + nmap( + "<leader>tb", + gs.toggle_current_line_blame, + "[T]oggle git show [b]lame line" + ) + nmap("<leader>hd", gs.diffthis, "git [d]iff against index") + nmap("<leader>hD", function() + gs.diffthis("~") + end, "git [D]iff against last commit") + nmap("<leader>hc", gs.change_base, "git [C]hange base to index") + nmap("<leader>hC", function() + gs.change_base("~") + end, "git [C]hange base to HEAD") + nmap( + "<leader>tgd", + gs.preview_hunk_inline, + "[T]oggle [G]it show [D]eleted" + ) + nmap("<leader>tgw", gs.toggle_word_diff, "[T]oggle [G]it [W]ord diff") + nmap( + "<leader>tgl", + gs.toggle_linehl, + "[T]oggle [G]it [L]ine highlighting" + ) + -- Text object + map( + { "o", "x" }, + "ih", + ":<C-U>Gitsigns select_hunk<CR>", + "git [H]unk text object" + ) + end, +}) diff --git a/dot_config/nvim/lua/plugins/init.lua b/dot_config/nvim/lua/plugins/init.lua new file mode 100644 index 0000000..b106b6e --- /dev/null +++ b/dot_config/nvim/lua/plugins/init.lua @@ -0,0 +1,58 @@ +-- Seamless navigation between neovim splits and zellij panes +require("smart-splits").setup({}) +vim.keymap.set("n", "<C-h>", require("smart-splits").move_cursor_left, { desc = "Move to left split/pane" }) +vim.keymap.set("n", "<C-j>", require("smart-splits").move_cursor_down, { desc = "Move to below split/pane" }) +vim.keymap.set("n", "<C-k>", require("smart-splits").move_cursor_up, { desc = "Move to above split/pane" }) +vim.keymap.set("n", "<C-l>", require("smart-splits").move_cursor_right, { desc = "Move to right split/pane" }) + +require("which-key").setup({ + spec = { + { "g", group = "[G]oto" }, + { "yo", group = "Toggle options" }, + { "]", group = "Navigate to next" }, + { "[", group = "Navigate to previous" }, + { "<leader>c", group = "[C]ode", mode = { "n", "x" } }, + { "<leader>g", group = "[G]it" }, + { "<leader>h", group = "Git [H]unk", mode = { "n", "v" } }, + { "<leader>o", group = "[O]verseer" }, + { "<leader>r", group = "[R]efactor" }, + { "<leader>w", group = "[W]orkspace" }, + { "<leader>t", group = "[T]oggle" }, + }, +}) + +vim.keymap.set("n", "<leader>?", function() + require("which-key").show({ global = false }) +end, { desc = "Buffer Local Keymaps (which-key)" }) + +require("quicker").setup({ + keys = { + { + ">", + function() + require("quicker").expand({ + before = 2, + after = 2, + add_to_existing = true, + }) + end, + desc = "Expand quickfix context", + }, + { + "<", + function() + require("quicker").collapse() + end, + desc = "Collapse quickfix context", + }, + }, +}) + +vim.keymap.set("n", "<leader>tq", function() + require("quicker").toggle() +end, { desc = "[T]oggle [Q]uickfix" }) +vim.keymap.set("n", "<leader>tl", function() + require("quicker").toggle({ loclist = true }) +end, { desc = "[T]oggle [L]oclist" }) + +require("oil").setup({}) diff --git a/dot_config/nvim/lua/plugins/lsp.lua b/dot_config/nvim/lua/plugins/lsp.lua new file mode 100644 index 0000000..ddd5bea --- /dev/null +++ b/dot_config/nvim/lua/plugins/lsp.lua @@ -0,0 +1,280 @@ +require("lazydev").setup({ + library = { + { path = "${3rd}/luv/library", words = { "vim%.uv" } }, + }, +}) + +vim.lsp.enable("just") +pcall(vim.lsp.enable, "tblgen_lsp_server") + +require("fidget").setup({}) +require("mason").setup({}) +require("mason-lspconfig").setup({ + ensure_installed = {}, + automatic_installation = false, + handlers = { + function(server_name) + vim.lsp.enable(server_name) + end, + }, +}) +require("mason-tool-installer").setup({ + ensure_installed = { + "actionlint", + "autotools-language-server", + "basedpyright", + "bash-language-server", + "clangd", + "codelldb", + "codespell", + "css-lsp", + "dockerfile-language-server", + "gh", + "gh-actions-language-server", + "groovy-language-server", + "hadolint", + "html-lsp", + "jq", + "json-lsp", + "jsonlint", + "just-lsp", + "lua-language-server", + "markdownlint", + "mdformat", + "neocmakelsp", + "nginx-config-formatter", + "nginx-language-server", + "npm-groovy-lint", + "prettier", + "ruff", + "rust-analyzer", + "shellcheck", + "shellharden", + "shfmt", + "stylelint", + "stylua", + "systemd-lsp", + "systemdlint", + "typescript-language-server", + "typos", + "yaml-language-server", + "yamllint", + "yq", + }, +}) + +vim.api.nvim_create_autocmd("LspAttach", { + group = vim.api.nvim_create_augroup("lsp-attach", { clear = true }), + callback = function(event) + local bufnr = event.buf + + local function map(mode, l, r, desc) + vim.keymap.set(mode, l, r, { buffer = bufnr, desc = "LSP: " .. desc }) + end + local function nmap(l, r, desc) + map("n", l, r, desc) + end + nmap("<c-]>", vim.lsp.buf.definition, "Goto definition") + nmap("gD", vim.lsp.buf.declaration, "[G]oto [D]eclaration") + + local fzf = require("fzf-lua") + nmap("gd", fzf.lsp_definitions, "[G]oto [D]efinition") + nmap("gvd", function() + fzf.lsp_definitions({ jump1_action = fzf.actions.file_vsplit }) + end, "[G]oto in a [V]ertical split to [D]efinition") + nmap("gxd", function() + fzf.lsp_definitions({ jump1_action = fzf.actions.file_split }) + end, "[G]oto in a [X]horizontal split to [D]efinition") + nmap("gtd", function() + fzf.lsp_definitions({ jump1_action = fzf.actions.file_tabedit }) + end, "[G]oto in a [T]ab to [D]efinition") + nmap("gvt", function() + fzf.lsp_typedefs({ jump1_action = fzf.actions.file_vsplit }) + end, "[G]oto in a [V]ertical split to [T]ype definition") + nmap("gxt", function() + fzf.lsp_typedefs({ jump1_action = fzf.actions.file_split }) + end, "[G]oto in a [X]horizontal split to [T]ype definition") + nmap("gtt", function() + fzf.lsp_typedefs({ jump1_action = fzf.actions.file_tabedit }) + end, "[G]oto in a [T]ab to [T]ype definition") + nmap("gri", fzf.lsp_implementations, "[G]oto [I]mplementation") + nmap("grvi", function() + fzf.lsp_implementations({ jump1_action = fzf.actions.file_vsplit }) + end, "[G]oto in a [V]ertical split to [I]mplementation") + nmap("grxi", function() + fzf.lsp_implementations({ jump1_action = fzf.actions.file_split }) + end, "[G]oto in a [X]horizontal split to [I]mplementation") + nmap("grti", function() + fzf.lsp_implementations({ jump1_action = fzf.actions.file_tabedit }) + end, "[G]oto in a [T]ab to [I]mplementation") + nmap("grr", fzf.lsp_references, "[G]oto [R]eferences") + nmap("gvr", function() + fzf.lsp_references({ jump1_action = fzf.actions.file_vsplit }) + end, "[G]oto in a [V]ertical split to [R]eferences") + nmap("gxr", function() + fzf.lsp_references({ jump1_action = fzf.actions.file_split }) + end, "[G]oto in a [X]horizontal split to [R]eferences") + nmap("gtr", function() + fzf.lsp_references({ jump1_action = fzf.actions.file_tabedit }) + end, "[G]oto in a [T]ab to [R]eferences") + nmap("<leader>ci", fzf.lsp_incoming_calls, "[C]ode [I]ncoming calls") + nmap("<leader>co", fzf.lsp_outgoing_calls, "[C]ode [O]utgoing calls") + nmap("gO", fzf.lsp_document_symbols, "d[O]ocument symbols") + nmap( + "<leader>ws", + fzf.lsp_live_workspace_symbols, + "[W]orkspace [S]ymbols" + ) + nmap( + "<leader>wd", + fzf.diagnostics_workspace, + "[W]orkspace [D]iagnostics" + ) + + local client = vim.lsp.get_client_by_id(event.data.client_id) + if + client + and client:supports_method( + vim.lsp.protocol.Methods.textDocument_documentHighlight, + event.buf + ) + then + local highlight_augroup = + vim.api.nvim_create_augroup("lsp-highlight", { clear = false }) + vim.api.nvim_create_autocmd({ "CursorHold", "CursorHoldI" }, { + buffer = event.buf, + group = highlight_augroup, + callback = vim.lsp.buf.document_highlight, + }) + + vim.api.nvim_create_autocmd({ "CursorMoved", "CursorMovedI" }, { + buffer = event.buf, + group = highlight_augroup, + callback = vim.lsp.buf.clear_references, + }) + + vim.api.nvim_create_autocmd("LspDetach", { + group = vim.api.nvim_create_augroup( + "lsp-detach", + { clear = true } + ), + callback = function(event2) + vim.lsp.buf.clear_references() + vim.api.nvim_clear_autocmds({ + group = "lsp-highlight", + buffer = event2.buf, + }) + end, + }) + end + + if + client + and client:supports_method( + vim.lsp.protocol.Methods.textDocument_codeLens, + event.buf + ) + then + vim.lsp.codelens.enable(true, { bufnr = bufnr }) + end + + if + client + and client:supports_method( + vim.lsp.protocol.Methods.textDocument_inlayHint, + event.buf + ) + then + nmap("<leader>th", function() + vim.lsp.inlay_hint.enable( + not vim.lsp.inlay_hint.is_enabled(event.buf) + ) + end, "[T]oggle Inlay [H]ints") + end + end, +}) + +require("conform").setup({ + formatters_by_ft = { + awk = { "gawk" }, + bash = { "shfmt" }, + cmake = { "cmake_format" }, + css = { "prettier", "stylelint" }, + groovy = { "npm-groovy-lint" }, + html = { "prettier" }, + javascript = { "prettier" }, + typescript = { "prettier" }, + jenkins = { "npm-groovy-lint" }, + json = { "jq", "jsonlint" }, + jsonc = { "prettier" }, + just = { "just" }, + markdown = { "mdformat" }, + nginx = { "nginxfmt" }, + lua = { "stylua" }, + python = { "ruff_format", "ruff_fix", "ruff_organize_imports" }, + rust = { "rustfmt" }, + sh = { "shfmt", "shellcheck", "shellharden" }, + yaml = { "yamllint" }, + zsh = { "shfmt", "shellcheck", "shellharden" }, + }, + default_format_opts = { + lsp_format = "fallback", + }, + formatters = { + shfmt = { + prepend_args = { "-i", "2" }, + }, + }, +}) +vim.o.formatexpr = "v:lua.require'conform'.formatexpr()" + +vim.keymap.set("", "<leader>f", function() + require("conform").format({ async = true, lsp_fallback = true }) +end, { desc = "[F]ormat buffer" }) + +local lint = require("lint") +lint.linters_by_ft = { + css = { "stylelint" }, + dockerfile = { "hadolint" }, + groovy = { "npm-groovy-lint" }, + jenkins = { "npm-groovy-lint" }, + json = { "jsonlint" }, + markdown = { "markdownlint" }, + makefile = { "checkmake" }, + systemd = { "systemdlint" }, + yaml = { "yamllint", "yq" }, + ghaction = { "actionlint" }, + zsh = { "zsh" }, + ["*"] = { "codespell", "typos" }, +} +vim.api.nvim_create_autocmd({ "BufReadPost", "BufWritePost" }, { + group = vim.api.nvim_create_augroup("lint", { clear = true }), + callback = function() + if vim.opt_local.modifiable:get() then + lint.try_lint() + end + end, +}) + +require("tiny-inline-diagnostic").setup({ + options = { + show_source = { + if_many = true, + }, + set_arrow_to_diag_color = true, + multilines = { + enabled = true, + }, + show_all_diags_on_cursorline = true, + enable_on_select = true, + break_line = { + enabled = true, + }, + severity = { + vim.diagnostic.severity.ERROR, + vim.diagnostic.severity.WARN, + vim.diagnostic.severity.INFO, + vim.diagnostic.severity.HINT, + }, + }, +}) diff --git a/dot_config/nvim/lua/plugins/runner.lua b/dot_config/nvim/lua/plugins/runner.lua new file mode 100644 index 0000000..28e4e5f --- /dev/null +++ b/dot_config/nvim/lua/plugins/runner.lua @@ -0,0 +1,77 @@ +local overseer = require("overseer") +overseer.setup({}) +overseer.add_template_hook({ name = ".*" }, function(task_defn, util) + util.add_component(task_defn, { + "open_output", + on_start = "never", + on_complete = "failure", + direction = "vertical", + }) +end) + +vim.keymap.set("n", "<leader>to", function() + overseer.toggle() +end, { desc = "[T]oggle [O]verseer" }) +vim.keymap.set("n", "<leader>ob", function() + overseer.run_task({ name = "just build", disallow_prompt = true }) +end, { desc = "[O]verseer [B]uild" }) +vim.keymap.set("n", "<leader>oB", function() + overseer.run_task({ name = "just build" }) +end, { desc = "[O]verseer [B]uild" }) +vim.keymap.set("n", "<leader>ot", function() + overseer.run_task({ name = "just test", disallow_prompt = true }) +end, { desc = "[O]verseer [J]ust [T]est" }) +vim.keymap.set("n", "<leader>oT", function() + overseer.run_task({ name = "just test" }) +end, { desc = "[O]verseer [J]ust [T]est" }) +vim.keymap.set("n", "<leader>of", function() + overseer.run_task({ + name = "just test", + disallow_prompt = true, + params = { target = vim.fn.expand("%") }, + }) +end, { desc = "[O]verseer test [F]ile" }) +vim.keymap.set("n", "<leader>oF", function() + overseer.run_task({ + name = "just test", + params = { target = vim.fn.expand("%") }, + }) +end, { desc = "[O]verseer test [F]ile" }) +vim.keymap.set("n", "<leader>od", function() + overseer.run_task({ + name = "just debug=true test", + disallow_prompt = true, + params = { target = vim.fn.expand("%") }, + }) +end, { desc = "[O]verseer [d]ebug test file" }) +vim.keymap.set("n", "<leader>oD", function() + overseer.run_task({ + name = "just debug=true test", + params = { target = vim.fn.expand("%") }, + }) +end, { desc = "[O]verseer [D]ebug test file" }) +vim.keymap.set("n", "<leader>oa", function() + overseer.run_task({ + name = "just test_autofix", + disallow_prompt = true, + params = { target = vim.fn.expand("%") }, + }) +end, { desc = "[O]verseer [A]utofix" }) +vim.keymap.set("n", "<leader>or", function() + overseer.run_task() +end, { desc = "[O]verseer [R]un" }) +vim.keymap.set("n", "<leader>os", function() + vim.cmd("OverseerShell") +end, { desc = "[O]verseer [S]hell" }) +vim.keymap.set("n", "<leader>ol", function() + local tasks = overseer.list_tasks({ + sort = function(a, b) + return a.id > b.id + end, + }) + if vim.tbl_isempty(tasks) then + vim.notify("No tasks found", vim.log.levels.WARN) + else + overseer.run_action(tasks[1], "restart") + end +end, { desc = "[O]verseer run [L]ast" }) diff --git a/dot_config/nvim/lua/plugins/search.lua b/dot_config/nvim/lua/plugins/search.lua new file mode 100644 index 0000000..a36cddc --- /dev/null +++ b/dot_config/nvim/lua/plugins/search.lua @@ -0,0 +1,60 @@ +local fzflua = require("fzf-lua") +fzflua.setup({ + keymap = { + builtin = { + true, + ["<M-p>"] = "toggle-preview", + }, + }, + grep = { + hidden = true, + RIPGREP_CONFIG_PATH = "~/.config/ripgrep/ripgreprc", + }, + lsp = { + includeDeclaration = false, + }, + actions = { + files = { + true, + ["ctrl-x"] = fzflua.actions.file_split, + }, + }, +}) +fzflua.register_ui_select() + +vim.keymap.set("n", "<localleader>b", function() + fzflua.buffers() +end, { desc = "fzf-lua [B]uffers" }) +vim.keymap.set("n", "<localleader>/", function() + fzflua.live_grep() +end, { desc = "fzf-lua live grep" }) +vim.keymap.set("n", "<localleader>f", function() + fzflua.files() +end, { desc = "fzf-lua [F]iles" }) +vim.keymap.set("n", "<leader><leader>", function() + fzflua.global() +end, { desc = "fzf-lua global picker" }) +vim.keymap.set("n", "<localleader>d", function() + fzflua.diagnostics() +end, { desc = "fzf-lua [D]iagnostics" }) +vim.keymap.set("n", "<localleader>r", function() + fzflua.resume() +end, { desc = "fzf-lua [R]esume" }) +vim.keymap.set("n", "<localleader>gc", function() + fzflua.git_bcommits() +end, { desc = "[G]it buffer [C]commits" }) +vim.keymap.set("v", "<localleader>gc", function() + fzflua.git_bcommits_range() +end, { desc = "[G]it [C]commits for selected range" }) +vim.keymap.set("n", "<localleader>gC", function() + fzflua.git_commits() +end, { desc = "[G]it (all) [C]commits" }) +vim.keymap.set("n", "<localleader>gb", function() + fzflua.git_branches() +end, { desc = "[G]it [B]ranches" }) +vim.keymap.set("n", "<localleader>gs", function() + fzflua.git_status() +end, { desc = "[G]it [S]tatus" }) +vim.keymap.set("n", "<localleader>gS", function() + fzflua.git_stash() +end, { desc = "[G]it [S]tash" }) diff --git a/dot_config/nvim/lua/plugins/session.lua b/dot_config/nvim/lua/plugins/session.lua new file mode 100644 index 0000000..a094727 --- /dev/null +++ b/dot_config/nvim/lua/plugins/session.lua @@ -0,0 +1,77 @@ +local function get_cwd_as_name() + local dir = vim.fn.getcwd(0) + return dir:gsub("[^A-Za-z0-9]", "_") +end +local overseer = require("overseer") + +require("auto-session").setup({ + use_git_branch = true, + pre_save_cmds = { + function() + overseer.save_task_bundle( + get_cwd_as_name(), + nil, + { on_conflict = "overwrite" } + ) + end, + }, + pre_restore_cmds = { + function() + for _, task in ipairs(overseer.list_tasks({})) do + task:dispose(true) + end + end, + }, + post_restore_cmds = { + function() + overseer.load_task_bundle( + get_cwd_as_name(), + { ignore_missing = true, autostart = false } + ) + end, + }, + save_extra_data = function(_) + local ok, breakpoints = pcall(require, "dap.breakpoints") + if not ok or not breakpoints then + return + end + + local bps = {} + local breakpoints_by_buf = breakpoints.get() + for buf, buf_bps in pairs(breakpoints_by_buf) do + bps[vim.api.nvim_buf_get_name(buf)] = buf_bps + end + if vim.tbl_isempty(bps) then + return + end + local extra_data = { + breakpoints = bps, + } + return vim.fn.json_encode(extra_data) + end, + + restore_extra_data = function(_, extra_data) + local json = vim.fn.json_decode(extra_data) + + if json.breakpoints then + local ok, breakpoints = pcall(require, "dap.breakpoints") + + if not ok or not breakpoints then + return + end + vim.notify("restoring breakpoints") + for buf_name, buf_bps in pairs(json.breakpoints) do + for _, bp in pairs(buf_bps) do + local line = bp.line + local opts = { + condition = bp.condition, + log_message = bp.logMessage, + hit_condition = bp.hitCondition, + } + breakpoints.set(opts, vim.fn.bufnr(buf_name), line) + end + end + end + end, + suppressed_dirs = { "~/", "/" }, +}) diff --git a/dot_config/nvim/lua/plugins/treesitter.lua b/dot_config/nvim/lua/plugins/treesitter.lua new file mode 100644 index 0000000..a4a488c --- /dev/null +++ b/dot_config/nvim/lua/plugins/treesitter.lua @@ -0,0 +1,83 @@ +require("treewalker").setup({}) + +vim.keymap.set({ "n", "v" }, "<a-k>", "<cmd>Treewalker Up<cr>", { silent = true, desc = "Moves up to the previous neighbor node" }) +vim.keymap.set({ "n", "v" }, "<a-j>", "<cmd>Treewalker Down<cr>", { silent = true, desc = "Moves up to the next neighbor node" }) +vim.keymap.set({ "n", "v" }, "<a-h>", "<cmd>Treewalker Left<cr>", { silent = true, desc = "Moves to the first ancestor node that's on a different line from the current node" }) +vim.keymap.set({ "n", "v" }, "<a-l>", "<cmd>Treewalker Right<cr>", { silent = true, desc = "Moves to the next node down that's indented further than the current node" }) +vim.keymap.set("n", "<s-a-k>", "<cmd>Treewalker SwapUp<cr>", { silent = true, desc = "Swaps the highest node on the line upwards in the document" }) +vim.keymap.set("n", "<s-a-j>", "<cmd>Treewalker SwapDown<cr>", { silent = true, desc = "Swaps the biggest node on the line downward in the document" }) +vim.keymap.set("n", "<s-a-h>", "<cmd>Treewalker SwapLeft<cr>", { silent = true, desc = "Swap the node under the cursor with its previous neighbor" }) +vim.keymap.set("n", "<s-a-l>", "<cmd>Treewalker SwapRight<cr>", { silent = true, desc = "Swap the node under the cursor with its next neighbor" }) + +require("nvim-treesitter").install({ + "awk", + "bash", + "c", + "cmake", + "comment", + "cpp", + "css", + "csv", + "diff", + "dockerfile", + "doxygen", + "editorconfig", + "fortran", + "git_config", + "git_rebase", + "gitattributes", + "gitcommit", + "gitignore", + "groovy", + "gpg", + "hlsplaylist", + "html", + "http", + "ini", + "javascript", + "jq", + "jsdoc", + "json", + "just", + "llvm", + "lua", + "luadoc", + "luap", + "make", + "markdown", + "markdown_inline", + "query", + "passwd", + "printf", + "python", + "regex", + "readline", + "requirements", + "rust", + "sql", + "ssh_config", + "strace", + "tablegen", + "todotxt", + "toml", + "typescript", + "vim", + "vimdoc", + "xcompose", + "xml", + "xresources", + "yaml", +}) + +require("nvim-dap-repl-highlights").setup({}) +require("treesitter-context").setup({}) + +require("ts_context_commentstring").setup({ + enable_autocmd = false, +}) +local get_option = vim.filetype.get_option +vim.filetype.get_option = function(filetype, option) + return option == "commentstring" + and require("ts_context_commentstring.internal").calculate_commentstring() + or get_option(filetype, option) +end diff --git a/dot_config/nvim/lua/plugins/ui.lua b/dot_config/nvim/lua/plugins/ui.lua new file mode 100644 index 0000000..50a2114 --- /dev/null +++ b/dot_config/nvim/lua/plugins/ui.lua @@ -0,0 +1,58 @@ +-- blink.indent (gruvbox setup is in init.lua) +require("blink.indent").setup({ + scope = { + highlights = { + "BlinkIndentOrange", + "BlinkIndentViolet", + "BlinkIndentBlue", + "BlinkIndentRed", + "BlinkIndentCyan", + "BlinkIndentYellow", + "BlinkIndentGreen", + }, + underline = { + enabled = true, + highlights = { + "BlinkIndentOrangeUnderline", + "BlinkIndentVioletUnderline", + "BlinkIndentBlueUnderline", + "BlinkIndentRedUnderline", + "BlinkIndentCyanUnderline", + "BlinkIndentYellowUnderline", + "BlinkIndentGreenUnderline", + }, + }, + }, +}) + +require("lualine").setup({ + options = { + icons_enabled = false, + theme = "gruvbox_dark", + component_separators = "", + section_separators = "|", + disabled_filetypes = { + winbar = { + "dap-view", + "dap-repl", + "dap-view-term", + }, + }, + }, + sections = { + lualine_a = { "filetype", { "filename", path = 1 } }, + lualine_b = { "%l/%L:%c:%o" }, + lualine_c = { "diff" }, + lualine_x = { "searchcount", "selectioncount" }, + lualine_y = { "overseer", "copilot" }, + lualine_z = { "diagnostics" }, + }, + inactive_sections = { + lualine_a = {}, + lualine_b = {}, + lualine_c = { "filename" }, + lualine_x = {}, + lualine_y = {}, + lualine_z = {}, + }, +}) diff --git a/dot_config/nvim/nvim-pack-lock.json b/dot_config/nvim/nvim-pack-lock.json new file mode 100644 index 0000000..6b17553 --- /dev/null +++ b/dot_config/nvim/nvim-pack-lock.json @@ -0,0 +1,222 @@ +{ + "plugins": { + "auto-session": { + "rev": "62437532b38495551410b3f377bcf4aaac574ebe", + "src": "https://github.com/rmagatti/auto-session" + }, + "blink-copilot": { + "rev": "7ad8209b2f880a2840c94cdcd80ab4dc511d4f39", + "src": "https://github.com/fang2hou/blink-copilot" + }, + "blink.cmp": { + "rev": "78336bc89ee5365633bcf754d93df01678b5c08f", + "src": "https://github.com/saghen/blink.cmp", + "version": ">=0.0.0" + }, + "blink.compat": { + "rev": "1454f14a8d855a578ceeba77c62538fa1459a67c", + "src": "https://github.com/saghen/blink.compat" + }, + "blink.download": { + "rev": "a459c8fbf51359902971874b5ebe05f6602db8b4", + "src": "https://github.com/saghen/blink.download", + "version": "'main'" + }, + "blink.indent": { + "rev": "9c80820ca77218a8d28e70075d6f44a1609911fe", + "src": "https://github.com/saghen/blink.indent" + }, + "blink.pairs": { + "rev": "4e43012356d33a26f69eae475f746fbe9f325f44", + "src": "https://github.com/saghen/blink.pairs", + "version": ">=0.0.0" + }, + "cmp-dap": { + "rev": "ea92773e84c0ad3288c3bc5e452ac91559669087", + "src": "https://github.com/rcarriga/cmp-dap" + }, + "colorful-menu.nvim": { + "rev": "b51a659459df8d078201aefc995db8175ed55e84", + "src": "https://github.com/xzbdmw/colorful-menu.nvim" + }, + "conform.nvim": { + "rev": "086a40dc7ed8242c03be9f47fbcee68699cc2395", + "src": "https://github.com/stevearc/conform.nvim" + }, + "copilot-lsp": { + "rev": "1b6d8273594643f51bb4c0c1d819bdb21b42159d", + "src": "https://github.com/copilotlsp-nvim/copilot-lsp" + }, + "copilot-lualine": { + "rev": "222e90bd8dcdf16ca1efc4e784416afb5f011c31", + "src": "https://github.com/AndreM222/copilot-lualine" + }, + "copilot.lua": { + "rev": "ad7e729e9a6348f7da482be0271d452dbc4c8e2c", + "src": "https://github.com/zbirenbaum/copilot.lua" + }, + "debugmaster.nvim": { + "rev": "c2a07077bebfb97bc8dd4ab300d7734a453683e3", + "src": "https://github.com/miroshQa/debugmaster.nvim", + "version": "'dashboard'" + }, + "dial.nvim": { + "rev": "f2634758455cfa52a8acea6f142dcd6271a1bf57", + "src": "https://github.com/monaqa/dial.nvim" + }, + "fidget.nvim": { + "rev": "889e2e96edef4e144965571d46f7a77bcc4d0ddf", + "src": "https://github.com/j-hui/fidget.nvim" + }, + "friendly-snippets": { + "rev": "6cd7280adead7f586db6fccbd15d2cac7e2188b9", + "src": "https://github.com/rafamadriz/friendly-snippets" + }, + "fzf-lua": { + "rev": "5bf93b12f70c7cc89a2cc6ee026b82f111815be8", + "src": "https://github.com/ibhagwan/fzf-lua", + "version": "'main'" + }, + "git-conflict.nvim": { + "rev": "a1badcd070d176172940eb55d9d59029dad1c5a6", + "src": "https://github.com/akinsho/git-conflict.nvim" + }, + "gitlinker.nvim": { + "rev": "cc59f732f3d043b626c8702cb725c82e54d35c25", + "src": "https://github.com/ruifm/gitlinker.nvim" + }, + "gitsigns.nvim": { + "rev": "8d82c240f190fc33723d48c308ccc1ed8baad69d", + "src": "https://github.com/lewis6991/gitsigns.nvim" + }, + "gruvbox.nvim": { + "rev": "154eb5ff5b96d0641307113fa385eaf0d36d9796", + "src": "https://github.com/ellisonleao/gruvbox.nvim" + }, + "guess-indent.nvim": { + "rev": "84a4987ff36798c2fc1169cbaff67960aed9776f", + "src": "https://github.com/nmac427/guess-indent.nvim" + }, + "lazydev.nvim": { + "rev": "ff2cbcba459b637ec3fd165a2be59b7bbaeedf0d", + "src": "https://github.com/folke/lazydev.nvim" + }, + "lualine.nvim": { + "rev": "a905eeebc4e63fdc48b5135d3bf8aea5618fb21c", + "src": "https://github.com/nvim-lualine/lualine.nvim" + }, + "markdown-preview.nvim": { + "rev": "a923f5fc5ba36a3b17e289dc35dc17f66d0548ee", + "src": "https://github.com/iamcco/markdown-preview.nvim" + }, + "mason-lspconfig.nvim": { + "rev": "0a3b42c3e503df87aef6d6513e13148381495c3a", + "src": "https://github.com/williamboman/mason-lspconfig.nvim" + }, + "mason-nvim-dap.nvim": { + "rev": "9a10e096703966335bd5c46c8c875d5b0690dade", + "src": "https://github.com/jay-babu/mason-nvim-dap.nvim" + }, + "mason-tool-installer.nvim": { + "rev": "443f1ef8b5e6bf47045cb2217b6f748a223cf7dc", + "src": "https://github.com/WhoIsSethDaniel/mason-tool-installer.nvim" + }, + "mason.nvim": { + "rev": "b03fb0f20bc1d43daf558cda981a2be22e73ac42", + "src": "https://github.com/williamboman/mason.nvim" + }, + "neogit": { + "rev": "e06745228600a585b88726fc9fba44a373c15a47", + "src": "https://github.com/NeogitOrg/neogit" + }, + "nvim-dap": { + "rev": "45a69eba683a2c448dd9ecfc4de89511f0646b5f", + "src": "https://github.com/mfussenegger/nvim-dap" + }, + "nvim-dap-repl-highlights": { + "rev": "f31deba47fe3ee6ff8d2f13d9dbd06b2d1ae06b5", + "src": "https://github.com/LiadOz/nvim-dap-repl-highlights" + }, + "nvim-dap-virtual-text": { + "rev": "fbdb48c2ed45f4a8293d0d483f7730d24467ccb6", + "src": "https://github.com/theHamsta/nvim-dap-virtual-text" + }, + "nvim-lint": { + "rev": "eab58b48eb11d7745c11c505e0f3057165902461", + "src": "https://github.com/mfussenegger/nvim-lint" + }, + "nvim-lspconfig": { + "rev": "d10ce09e42bb0ca8600fd610c3bb58676e61208d", + "src": "https://github.com/neovim/nvim-lspconfig" + }, + "nvim-surround": { + "rev": "9291040de8cd8a4439eb64c441e8d5d2bf884a5a", + "src": "https://github.com/kylechui/nvim-surround" + }, + "nvim-treesitter": { + "rev": "4916d6592ede8c07973490d9322f187e07dfefac", + "src": "https://github.com/nvim-treesitter/nvim-treesitter", + "version": "'main'" + }, + "nvim-treesitter-context": { + "rev": "b0c45cefe2c8f7b55fc46f34e563bc428ef99636", + "src": "https://github.com/nvim-treesitter/nvim-treesitter-context" + }, + "nvim-treesitter-endwise": { + "rev": "8fe8a95630f4f2c72a87ba1927af649e0bfaa244", + "src": "https://github.com/RRethy/nvim-treesitter-endwise" + }, + "nvim-ts-context-commentstring": { + "rev": "6141a40173c6efa98242dc951ed4b6f892c97027", + "src": "https://github.com/JoosepAlviste/nvim-ts-context-commentstring" + }, + "nvim-various-textobjs": { + "rev": "ad78e9d925c95d675b32dd7ba6d253f96ce063fe", + "src": "https://github.com/chrisgrieser/nvim-various-textobjs" + }, + "oil.nvim": { + "rev": "0fcc83805ad11cf714a949c98c605ed717e0b83e", + "src": "https://github.com/stevearc/oil.nvim" + }, + "overseer.nvim": { + "rev": "f818eefff81f4b12fb7cf236f1b6c16768a2fcbc", + "src": "https://github.com/stevearc/overseer.nvim" + }, + "plenary.nvim": { + "rev": "74b06c6c75e4eeb3108ec01852001636d85a932b", + "src": "https://github.com/nvim-lua/plenary.nvim" + }, + "quicker.nvim": { + "rev": "063cc44da1eef8681bbd653b29d3bc961780886a", + "src": "https://github.com/stevearc/quicker.nvim" + }, + "refactoring.nvim": { + "rev": "6784b54587e6d8a6b9ea199318512170ffb9e418", + "src": "https://github.com/ThePrimeagen/refactoring.nvim" + }, + "rustaceanvim": { + "rev": "2497c7b2a61d4eb5dad716371a64ea82fb068bee", + "src": "https://github.com/mrcjkb/rustaceanvim" + }, + "smart-splits.nvim": { + "rev": "ba2850ff3d3b09785a7105c69d06a12117d4b97d", + "src": "https://github.com/mrjones2014/smart-splits.nvim" + }, + "tiny-inline-diagnostic.nvim": { + "rev": "57a0eb84b2008c76e77930639890d9874195b1e1", + "src": "https://github.com/rachartier/tiny-inline-diagnostic.nvim" + }, + "tmux.nvim": { + "rev": "32ceaf2793582955ef9576809730878c4d2d9426", + "src": "https://github.com/aserowy/tmux.nvim" + }, + "treewalker.nvim": { + "rev": "6fbceceb8966620da8970b727b6daa358b982805", + "src": "https://github.com/aaronik/treewalker.nvim" + }, + "which-key.nvim": { + "rev": "3aab2147e74890957785941f0c1ad87d0a44c15a", + "src": "https://github.com/folke/which-key.nvim" + } + } +} diff --git a/dot_config/pacman/makepkg.conf b/dot_config/pacman/makepkg.conf new file mode 100644 index 0000000..7233660 --- /dev/null +++ b/dot_config/pacman/makepkg.conf @@ -0,0 +1,9 @@ +CFLAGS="-march=native -Ofast -pipe -fomit-frame-pointer" +RUSTFLAGS="-C opt-level=2 -C target-cpu=native" +MAKEFLAGS="-j4" +BUILDDIR=/tmp/makepkg +COMPRESSGZ=(pigz -c -f -n) +COMPRESSBZ2=(pbzip2 -c -f) +COMPRESSXZ=(xz -c -z - --threads=0) +COMPRESSZST=(zstd -c -z -q - --threads=0) +PKGEXT='.pkg.tar.zst' diff --git a/dot_config/paru/paru.conf b/dot_config/paru/paru.conf new file mode 100644 index 0000000..57cb11b --- /dev/null +++ b/dot_config/paru/paru.conf @@ -0,0 +1,25 @@ +# +# /etc/paru.conf +# ~/.config/paru/paru.conf +# +# See the paru.conf(5) manpage for options + +# +# GENERAL OPTIONS +# +[options] +PgpFetch +Devel +Provides +DevelSuffixes = -git -cvs -svn -bzr -darcs -always +# BottomUp +RemoveMake +#SudoLoop +#UseAsk +CombinedUpgrade +BatchInstall +# UpgradeMenu +NewsOnUpgrade +CleanAfter +SaveChanges +NoWarn = sommerfeld-* diff --git a/dot_config/ripgrep/ripgreprc b/dot_config/ripgrep/ripgreprc new file mode 100644 index 0000000..f808311 --- /dev/null +++ b/dot_config/ripgrep/ripgreprc @@ -0,0 +1,4 @@ +--hidden +--follow +--smart-case +--glob=!.git diff --git a/dot_config/sh/inputrc b/dot_config/sh/inputrc new file mode 100644 index 0000000..e770fea --- /dev/null +++ b/dot_config/sh/inputrc @@ -0,0 +1,20 @@ +$include /etc/inputrc + +set enable-keypad on +set bell-style none +set show-all-if-ambiguous on + +# Color files by types +set colored-stats On +# Append char to indicate type +set visible-stats On +# Mark symlinked directories +set mark-symlinked-directories On +# Color the common prefix +set colored-completion-prefix On +# Color the common prefix in menu-complete +set menu-complete-display-prefix On + +set echo-control-characters off + +set enable-bracketed-paste on diff --git a/dot_config/streamlink/config b/dot_config/streamlink/config new file mode 100644 index 0000000..6916230 --- /dev/null +++ b/dot_config/streamlink/config @@ -0,0 +1,3 @@ +player=mpv +default-stream=best +twitch-disable-reruns diff --git a/dot_config/sway/config b/dot_config/sway/config new file mode 100644 index 0000000..bbd2eb0 --- /dev/null +++ b/dot_config/sway/config @@ -0,0 +1,157 @@ +# ── Variables ───────────────────────────────────────────────────────────────── +set $mod Mod4 +set $term ghostty +set $menu fuzzel + +# ── Appearance ──────────────────────────────────────────────────────────────── +font mono 8 +default_border pixel 1 +default_floating_border pixel 1 +gaps inner 0 +gaps outer 0 + +# Gruvbox dark colors +# class border bg text indicator child_border +client.focused #fabd2f #282828 #ebdbb2 #fabd2f #fabd2f +client.focused_inactive #3c3836 #282828 #928374 #3c3836 #3c3836 +client.unfocused #3c3836 #282828 #928374 #3c3836 #3c3836 +client.urgent #fb4934 #282828 #ebdbb2 #fb4934 #fb4934 + +# ── Input ───────────────────────────────────────────────────────────────────── +input type:keyboard { + xkb_layout us + xkb_options caps:escape + repeat_delay 300 + repeat_rate 50 +} + +input type:touchpad { + tap enabled + natural_scroll enabled + dwt enabled +} + +# ── Behavior ────────────────────────────────────────────────────────────────── +focus_follows_mouse yes +seat * hide_cursor 3000 + +# ── Output ──────────────────────────────────────────────────────────────────── +output * bg #282828 solid_color + +# ── Window rules ────────────────────────────────────────────────────────────── +for_window [class="feh"] floating enable +for_window [app_id="imv"] floating enable +for_window [class="Tor Browser"] floating enable + +# ── Standard keybinds (sway defaults) ───────────────────────────────────────── +bindsym $mod+Return exec $term +bindsym $mod+Shift+q kill +bindsym $mod+d exec $menu + +# Navigation +bindsym $mod+h focus left +bindsym $mod+j focus down +bindsym $mod+k focus up +bindsym $mod+l focus right + +# Move windows +bindsym $mod+Shift+h move left +bindsym $mod+Shift+j move down +bindsym $mod+Shift+k move up +bindsym $mod+Shift+l move right + +# Workspaces +bindsym $mod+1 workspace number 1 +bindsym $mod+2 workspace number 2 +bindsym $mod+3 workspace number 3 +bindsym $mod+4 workspace number 4 +bindsym $mod+5 workspace number 5 +bindsym $mod+6 workspace number 6 +bindsym $mod+7 workspace number 7 +bindsym $mod+8 workspace number 8 +bindsym $mod+9 workspace number 9 +bindsym $mod+0 workspace number 10 + +bindsym $mod+Shift+1 move container to workspace number 1 +bindsym $mod+Shift+2 move container to workspace number 2 +bindsym $mod+Shift+3 move container to workspace number 3 +bindsym $mod+Shift+4 move container to workspace number 4 +bindsym $mod+Shift+5 move container to workspace number 5 +bindsym $mod+Shift+6 move container to workspace number 6 +bindsym $mod+Shift+7 move container to workspace number 7 +bindsym $mod+Shift+8 move container to workspace number 8 +bindsym $mod+Shift+9 move container to workspace number 9 +bindsym $mod+Shift+0 move container to workspace number 10 + +# Layout +bindsym $mod+b splith +bindsym $mod+v splitv +bindsym $mod+s layout stacking +bindsym $mod+w layout tabbed +bindsym $mod+e layout toggle split +bindsym $mod+f fullscreen +bindsym $mod+Shift+space floating toggle +bindsym $mod+space focus mode_toggle +bindsym $mod+a focus parent + +# Scratchpad +bindsym $mod+Shift+minus move scratchpad +bindsym $mod+minus scratchpad show + +# Resize mode +mode "resize" { + bindsym h resize shrink width 10px + bindsym j resize grow height 10px + bindsym k resize shrink height 10px + bindsym l resize grow width 10px + bindsym Escape mode "default" + bindsym Return mode "default" +} +bindsym $mod+r mode "resize" + +# Reload / exit +bindsym $mod+Shift+c reload +bindsym $mod+Shift+e exec swaynag -t warning -m 'Exit sway?' -B 'Yes' 'swaymsg exit' + +# ── Personal keybinds ───────────────────────────────────────────────────────── + +# Workspace cycling +bindsym $mod+Tab workspace next_on_output +bindsym $mod+Shift+Tab workspace prev_on_output + +# Volume +bindsym XF86AudioRaiseVolume exec pactl set-sink-volume @DEFAULT_SINK@ +5% +bindsym XF86AudioLowerVolume exec pactl set-sink-volume @DEFAULT_SINK@ -5% +bindsym XF86AudioMute exec pactl set-sink-mute @DEFAULT_SINK@ toggle +bindsym $mod+Shift+m exec pactl set-sink-mute @DEFAULT_SINK@ toggle +bindsym $mod+m exec pactl set-source-mute @DEFAULT_SOURCE@ toggle + +# Media +bindsym XF86AudioPlay exec playerctl play-pause +bindsym XF86AudioNext exec playerctl next +bindsym XF86AudioPrev exec playerctl previous + +# Screenshots +bindsym Print exec grim -g "$(slurp)" ~/pics/screenshots/$(date +%Y-%m-%d-%H-%M-%S).png +bindsym Shift+Print exec grim ~/pics/screenshots/$(date +%Y-%m-%d-%H-%M-%S).png + +# Lock & pause +bindsym $mod+Shift+s exec "playerctl -a pause; swaylock -f -c 282828" + +# Notifications +bindsym $mod+n exec makoctl dismiss +bindsym $mod+Shift+n exec makoctl dismiss --all + +# Display mode switching +bindsym --no-repeat F7 exec ~/.config/sway/display-toggle.sh + +# ── Bar ─────────────────────────────────────────────────────────────────────── +bar { + swaybar_command waybar +} + +# ── Autostart ───────────────────────────────────────────────────────────────── +exec systemctl --user import-environment WAYLAND_DISPLAY SWAYSOCK XDG_CURRENT_DESKTOP +exec dbus-update-activation-environment --systemd WAYLAND_DISPLAY SWAYSOCK XDG_CURRENT_DESKTOP +exec mako +exec "sleep 2 && ~/.config/sway/display-toggle.sh init" diff --git a/dot_config/sway/executable_display-toggle.sh b/dot_config/sway/executable_display-toggle.sh new file mode 100755 index 0000000..f39bf9b --- /dev/null +++ b/dot_config/sway/executable_display-toggle.sh @@ -0,0 +1,45 @@ +#!/bin/sh +# Toggle display mode: laptop-off ↔ side-by-side +# Bound to F7 in sway config; also runs at startup with "init" + +STATE_FILE="${XDG_RUNTIME_DIR:-/tmp}/display-mode" + +OUTPUTS=$(swaymsg -t get_outputs -r) +LAPTOP=$(echo "$OUTPUTS" | jq -r '[.[] | select(.name | test("^eDP")) | .name] | first // empty') +EXTERNAL=$(echo "$OUTPUTS" | jq -r '[.[] | select(.name | test("^eDP") | not) | .name] | first // empty') + +if [ -z "$EXTERNAL" ]; then + [ -z "$1" ] && notify-send "Display" "No external display connected" + exit 0 +fi + +[ -z "$LAPTOP" ] && exit 0 + +LAPTOP_WIDTH=$(echo "$OUTPUTS" | jq -r ".[] | select(.name == \"$LAPTOP\") | .current_mode.width // .modes[0].width") +[ -z "$LAPTOP_WIDTH" ] && LAPTOP_WIDTH=1920 + +if [ "$1" = "init" ]; then + NEXT="laptop-off" +else + CURRENT=$(cat "$STATE_FILE" 2>/dev/null || echo "laptop-off") + case "$CURRENT" in + laptop-off) NEXT="side-by-side" ;; + *) NEXT="laptop-off" ;; + esac +fi + +case "$NEXT" in + laptop-off) + swaymsg output "$LAPTOP" disable || true + swaymsg output "$EXTERNAL" enable || true + swaymsg workspace number 1 || true + echo "laptop-off" > "$STATE_FILE" + [ -z "$1" ] && notify-send "Display" "Laptop screen off" + ;; + side-by-side) + swaymsg output "$LAPTOP" enable pos 0 0 || true + swaymsg output "$EXTERNAL" enable pos "$LAPTOP_WIDTH" 0 || true + echo "side-by-side" > "$STATE_FILE" + [ -z "$1" ] && notify-send "Display" "Side by side" + ;; +esac diff --git a/dot_config/systemd/user/bridge.service.d/override.conf b/dot_config/systemd/user/bridge.service.d/override.conf new file mode 100644 index 0000000..3938b3c --- /dev/null +++ b/dot_config/systemd/user/bridge.service.d/override.conf @@ -0,0 +1,2 @@ +[Service] +Environment="PASSWORD_STORE_DIR=%h/.local/share/password-store"
\ No newline at end of file diff --git a/dot_config/systemd/user/vdirsyncer.service.d/override.conf b/dot_config/systemd/user/vdirsyncer.service.d/override.conf new file mode 100644 index 0000000..6bc6060 --- /dev/null +++ b/dot_config/systemd/user/vdirsyncer.service.d/override.conf @@ -0,0 +1,2 @@ +[Service] +Environment="PASSWORD_STORE_DIR=%h/.local/share/password-store" diff --git a/dot_config/user-dirs.dirs b/dot_config/user-dirs.dirs new file mode 100644 index 0000000..6dd2f73 --- /dev/null +++ b/dot_config/user-dirs.dirs @@ -0,0 +1,8 @@ +XDG_DESKTOP_DIR="$HOME/" +XDG_DOCUMENTS_DIR="$HOME/docs" +XDG_DOWNLOAD_DIR="$HOME/dl" +XDG_MUSIC_DIR="$HOME/" +XDG_PICTURES_DIR="$HOME/pics" +XDG_PUBLICSHARE_DIR="$HOME/" +XDG_TEMPLATES_DIR="$HOME/" +XDG_VIDEOS_DIR="$HOME/vids" diff --git a/dot_config/user-dirs.locale b/dot_config/user-dirs.locale new file mode 100644 index 0000000..3e0b419 --- /dev/null +++ b/dot_config/user-dirs.locale @@ -0,0 +1 @@ +en_US
\ No newline at end of file diff --git a/dot_config/waybar/config.jsonc b/dot_config/waybar/config.jsonc new file mode 100644 index 0000000..f3b0813 --- /dev/null +++ b/dot_config/waybar/config.jsonc @@ -0,0 +1,67 @@ +{ + "layer": "top", + "height": 24, + "spacing": 0, + + "modules-left": ["sway/workspaces", "sway/mode"], + "modules-center": ["sway/window"], + "modules-right": ["pulseaudio", "cpu", "memory", "temperature", "network", "battery", "clock", "tray"], + + "sway/workspaces": { + "disable-scroll": true + }, + + "sway/window": { + "max-length": 60 + }, + + "cpu": { + "format": "CPU {usage}%", + "interval": 5, + "tooltip": false + }, + + "memory": { + "format": "MEM {}%", + "interval": 10, + "tooltip-format": "{used:0.1f}G / {total:0.1f}G" + }, + + "temperature": { + "format": "{temperatureC}°C", + "critical-threshold": 80 + }, + + "network": { + "format-wifi": "{essid} ({signalStrength}%)", + "format-ethernet": "{ifname}", + "format-disconnected": "disconnected", + "tooltip-format": "{ifname}: {ipaddr}/{cidr}" + }, + + "battery": { + "format": "BAT {capacity}%", + "format-charging": "CHR {capacity}%", + "format-plugged": "PLG {capacity}%", + "states": { + "warning": 30, + "critical": 15 + } + }, + + "pulseaudio": { + "format": "VOL {volume}%", + "format-muted": "MUTE", + "scroll-step": 5, + "on-click": "pactl set-sink-mute @DEFAULT_SINK@ toggle" + }, + + "clock": { + "format": "{:%a %d %b %H:%M}", + "tooltip-format": "{:%Y-%m-%d %H:%M:%S}" + }, + + "tray": { + "spacing": 8 + } +} diff --git a/dot_config/waybar/style.css b/dot_config/waybar/style.css new file mode 100644 index 0000000..44df159 --- /dev/null +++ b/dot_config/waybar/style.css @@ -0,0 +1,71 @@ +* { + font-family: mono; + font-size: 8pt; +} + +window#waybar { + background-color: #282828; + color: #ebdbb2; + border-bottom: 1px solid #3c3836; +} + +#workspaces button { + padding: 0 5px; + color: #928374; + background-color: transparent; + border: none; + border-radius: 0; +} + +#workspaces button.focused { + color: #ebdbb2; + background-color: #3c3836; + border-bottom: 2px solid #fabd2f; +} + +#workspaces button.urgent { + color: #ebdbb2; + background-color: #fb4934; +} + +#mode { + color: #fabd2f; + font-weight: bold; +} + +#clock, +#battery, +#cpu, +#memory, +#temperature, +#network, +#pulseaudio, +#tray { + padding: 0 6px; +} + +#battery.warning { + color: #fabd2f; +} + +#battery.critical { + color: #fb4934; +} + +#temperature.critical { + color: #fb4934; +} + +#pulseaudio.muted { + color: #928374; +} + +tooltip { + background-color: #3c3836; + border: 1px solid #504945; + border-radius: 0; +} + +tooltip label { + color: #ebdbb2; +} diff --git a/dot_config/wget/wgetrc b/dot_config/wget/wgetrc new file mode 100644 index 0000000..a378bfd --- /dev/null +++ b/dot_config/wget/wgetrc @@ -0,0 +1 @@ +hsts-file = ~/.local/share/wget-hsts diff --git a/dot_config/yazi/keymap.toml b/dot_config/yazi/keymap.toml new file mode 100644 index 0000000..b7ed5c7 --- /dev/null +++ b/dot_config/yazi/keymap.toml @@ -0,0 +1,9 @@ +[mgr] +prepend_keymap = [ + { on = "!", run = 'shell "$SHELL" --block', desc = "Open shell here" }, + { on = [ "g", "r" ], run = 'shell -- ya emit cd "$(git rev-parse --show-toplevel 2>/dev/null || echo .)"', desc = "Go to git root" }, + { on = [ "g", "." ], run = "cd ~/dotfiles", desc = "Go to dotfiles" }, + { on = [ "g", "x" ], run = "cd ~/doxfiles", desc = "Go to doxfiles" }, + { on = [ "g", "s" ], run = "cd ~/sync", desc = "Go to sync" }, + { on = [ "g", "S" ], run = "cd ~/pics/screenshots", desc = "Go to screenshots" }, +] diff --git a/dot_config/yazi/yazi.toml b/dot_config/yazi/yazi.toml new file mode 100644 index 0000000..793ca59 --- /dev/null +++ b/dot_config/yazi/yazi.toml @@ -0,0 +1,5 @@ +[mgr] +show_hidden = true +scrolloff = 10 +linemode = "mtime" +title_format = "Yazi: {cwd}" diff --git a/dot_config/yt-dlp/config b/dot_config/yt-dlp/config new file mode 100644 index 0000000..16dcbd7 --- /dev/null +++ b/dot_config/yt-dlp/config @@ -0,0 +1,9 @@ +# ignore unavailable videos +-i +# not interested in getting videos with a resolution higher than 1080p +-f bv*[height<=1080]+ba/b[height<=1080] +--sub-lang en,eng,pt,pt_pt,es,es_es +--embed-subs + +--embed-thumbnail +--embed-metadata diff --git a/dot_config/zathura/zathurarc b/dot_config/zathura/zathurarc new file mode 100644 index 0000000..c3e8d6f --- /dev/null +++ b/dot_config/zathura/zathurarc @@ -0,0 +1,4 @@ +set selection-clipboard clipboard +set incremental-search true +set window-title-basename true +set zoom-center true diff --git a/dot_config/zellij/config.kdl b/dot_config/zellij/config.kdl new file mode 100644 index 0000000..87ba6d1 --- /dev/null +++ b/dot_config/zellij/config.kdl @@ -0,0 +1,81 @@ +// Gruvbox dark theme (built-in) +theme "gruvbox-dark" + +// Session resurrection +serialize_pane_viewport true + +// Scrollback +scroll_buffer_size 50000 + +// Clipboard: copy to system clipboard on selection (OSC 52) +copy_on_select true + +// Auto-attach to existing session with the same name instead of erroring +attach_to_session true + +// Disable startup popups that overwrite stow-managed config when dismissed +show_startup_tips false +show_release_notes false + +// Clean UI: no pane borders, compact single-line status bar +pane_frames false +default_layout "compact" + +// Custom keybindings (merged with defaults) +keybinds { + shared_except "locked" { + // Direct tab access (Alt+number) + bind "Alt 1" { GoToTab 1; } + bind "Alt 2" { GoToTab 2; } + bind "Alt 3" { GoToTab 3; } + bind "Alt 4" { GoToTab 4; } + bind "Alt 5" { GoToTab 5; } + bind "Alt 6" { GoToTab 6; } + bind "Alt 7" { GoToTab 7; } + bind "Alt 8" { GoToTab 8; } + bind "Alt 9" { GoToTab 9; } + + // Tab management + bind "Alt t" { NewTab; } + bind "Alt [" { GoToPreviousTab; } + bind "Alt ]" { GoToNextTab; } + + // Pane management + bind "Alt w" { ToggleFocusFullscreen; } + bind "Alt x" { CloseFocus; } + bind "Alt e" { EditScrollback; } + + // Session + bind "Alt q" { Detach; } + + // Quick resize without entering resize mode + bind "Alt -" { Resize "Decrease"; } + bind "Alt =" { Resize "Increase"; } + + // Seamless vim/zellij pane navigation (requires smart-splits.nvim) + bind "Ctrl h" { + MessagePlugin "https://github.com/hiasr/vim-zellij-navigator/releases/download/0.3.0/vim-zellij-navigator.wasm" { + name "move_focus" + payload "left" + } + } + bind "Ctrl j" { + MessagePlugin "https://github.com/hiasr/vim-zellij-navigator/releases/download/0.3.0/vim-zellij-navigator.wasm" { + name "move_focus" + payload "down" + } + } + bind "Ctrl k" { + MessagePlugin "https://github.com/hiasr/vim-zellij-navigator/releases/download/0.3.0/vim-zellij-navigator.wasm" { + name "move_focus" + payload "up" + } + } + bind "Ctrl l" { + MessagePlugin "https://github.com/hiasr/vim-zellij-navigator/releases/download/0.3.0/vim-zellij-navigator.wasm" { + name "move_focus" + payload "right" + } + } + } +} diff --git a/dot_config/zsh/dot_zprofile b/dot_config/zsh/dot_zprofile new file mode 100644 index 0000000..30b5b21 --- /dev/null +++ b/dot_config/zsh/dot_zprofile @@ -0,0 +1,116 @@ +# Login shell configuration — sourced once per session by zsh. +# Sets environment variables, XDG paths, tool config, and host-specific overrides. + +# Guard against double-sourcing (e.g. nested login shells) +[[ -n $__ZPROFILE_SOURCED ]] && return +__ZPROFILE_SOURCED=1 + +# ── PATH ────────────────────────────────────────────────────────────────────── +typeset -U path # deduplicate PATH entries +path=("$HOME/.local/bin" "$HOME/.local/share/nvim/mason/bin" $path) + +# ── XDG Base Directories ───────────────────────────────────────────────────── +export XDG_CONFIG_HOME="$HOME/.config" +export XDG_DATA_HOME="$HOME/.local/share" +export XDG_STATE_HOME="$HOME/.local/state" +export XDG_CACHE_HOME="$HOME/.cache" + +# ── Locale ──────────────────────────────────────────────────────────────────── +export LANG=en_US.UTF-8 + +# ── Terminal ────────────────────────────────────────────────────────────────── +case $TERM in + *256color|*truecolor) export COLORTERM=24bit ;; +esac + +export TERMINAL='ghostty' +export BROWSER='linkhandler' +export OPENER='xdg-open' + +# ── Editors ─────────────────────────────────────────────────────────────────── +export EDITOR='nvim' +export VISUAL='nvim' +export DIFFPROG='nvim -d' +export MANPAGER='nvim +Man!' +export MANWIDTH=999 + +# ── less ────────────────────────────────────────────────────────────────────── +export LESS="-F --RAW-CONTROL-CHARS" +[[ -r /usr/bin/source-highlight-esc.sh ]] && export LESSOPEN="| /usr/bin/source-highlight-esc.sh %s" + +# ── GPG / SSH ───────────────────────────────────────────────────────────────── +unset SSH_AGENT_PID +export SSH_AUTH_SOCK="$(gpgconf --list-dirs agent-ssh-socket)" + +# ── FZF ─────────────────────────────────────────────────────────────────────── +export FZF_DEFAULT_COMMAND="fd --type file --follow --hidden --exclude .git --color=always" +export FZF_CTRL_T_COMMAND="$FZF_DEFAULT_COMMAND" +export FZF_DIRS_COMMAND="fd --type d --follow --hidden --exclude .git --color=always" +export FZF_DEFAULT_OPTS="--ansi --layout=reverse --inline-info --cycle --color=dark --color=fg:-1,bg:-1,hl:#5fff87,fg+:-1,bg+:-1,hl+:#ffaf5f --color=info:#af87ff,prompt:#5fff87,pointer:#ff87d7,marker:#ff87d7,spinner:#ff87d7" +export FZF_CTRL_T_OPTS="--preview 'bat --color=always --style=numbers --line-range=:500 {}' --select-1 --exit-0" +export FZF_CTRL_R_OPTS="--preview 'echo {}' --preview-window down:3:hidden:wrap --bind '?:toggle-preview' --sort --exact" +export FZF_ALT_C_OPTS="--preview 'tree -C {} | head -200'" + +# ── Git prompt ──────────────────────────────────────────────────────────────── +export GIT_PS1_SHOWDIRTYSTATE=1 +export GIT_PS1_SHOWSTASHSTATE=1 +unset GIT_PS1_SHOWUNTRACKEDFILES +export GIT_PS1_SHOWUPSTREAM="verbose" +export GIT_PS1_SHOWCONFLICTSTATE="yes" +export GIT_PS1_DESCRIBE_STYLE="branch" +export GIT_PS1_SHOWCOLORHINTS=1 +export GIT_PS1_HIDE_IF_PWD_IGNORED=1 + +# ── GCC ─────────────────────────────────────────────────────────────────────── +export GCC_COLORS='error=01;31:warning=01;35:note=01;36:caret=01;32:locus=01:quote=01' + +# ── Java ────────────────────────────────────────────────────────────────────── +# System AA fonts, GTK L&F, XDG prefs dir, GTK2 for compatibility +export _JAVA_OPTIONS="-Dawt.useSystemAAFontSettings=on -Dswing.aatext=true -Dswing.defaultlaf=com.sun.java.swing.plaf.gtk.GTKLookAndFeel -Djava.util.prefs.userRoot=$XDG_CONFIG_HOME/java -Djdk.gtk.version=2" +# Fix for non-reparenting WMs (sway, dwm, etc.) +export _JAVA_AWT_WM_NONREPARENTING=1 + +# ── Miscellaneous ───────────────────────────────────────────────────────────── +export QT_QPA_PLATFORMTHEME=qt6ct +export NO_AT_BRIDGE=1 # suppress GTK accessibility bus warnings +export DOCKER_HOST="unix://$XDG_RUNTIME_DIR/podman/podman.sock" +export INPUTRC="$XDG_CONFIG_HOME/sh/inputrc" + +# ── Wayland ─────────────────────────────────────────────────────────────────── +export XDG_CURRENT_DESKTOP=sway +export MOZ_ENABLE_WAYLAND=1 + +# ── XDG cleanup: keep $HOME tidy ───────────────────────────────────────────── +# https://wiki.archlinux.org/title/XDG_Base_Directory#Partial +export CARGO_HOME="$XDG_DATA_HOME/cargo" +export CUDA_CACHE_PATH="$XDG_CACHE_HOME/nv" +export GOPATH="$XDG_DATA_HOME/go" +export GRADLE_USER_HOME="$XDG_DATA_HOME/gradle" +export NODE_REPL_HISTORY="$XDG_DATA_HOME/node_repl_history" +export PASSWORD_STORE_DIR="$XDG_DATA_HOME/password-store" +export RUFF_CACHE_DIR="$XDG_CACHE_HOME/ruff" +export RUSTUP_HOME="$XDG_DATA_HOME/rustup" +export WGETRC="$XDG_CONFIG_HOME/wget/wgetrc" +export WINEPREFIX="$XDG_DATA_HOME/wineprefixes/default" + +# ── Host-specific ───────────────────────────────────────────────────────────── +case $(uname -n) in + halley2) + export LIBVA_DRIVER_NAME="iHD" + export MESA_LOADER_DRIVER_OVERRIDE="iris" + export VAAPI_MPEG4_ENABLED=true + ;; + hercules) + export OCL_ICD_VENDORS=nvidia + [[ -r "$XDG_CONFIG_HOME/sh/work-envrc" ]] && source "$XDG_CONFIG_HOME/sh/work-envrc" + ;; +esac + +# ── Secrets (from pass) ────────────────────────────────────────────────────── +(( $+commands[pass] )) && export FIRECRAWL_API_KEY="$(pass show copilot/firecrawl-api-key)" + +# ── Auto-start sway on VT1 ──────────────────────────────────────────────────── +if [[ -z $WAYLAND_DISPLAY && $XDG_VTNR == 1 ]]; then + export XDG_SESSION_TYPE=wayland + exec sway +fi diff --git a/dot_config/zsh/dot_zshrc b/dot_config/zsh/dot_zshrc new file mode 100644 index 0000000..fad4bca --- /dev/null +++ b/dot_config/zsh/dot_zshrc @@ -0,0 +1,322 @@ +# Interactive zsh configuration. + +# ── Terminal ────────────────────────────────────────────────────────────────── +stty -ixon # disable XON/XOFF flow control (frees Ctrl-S/Ctrl-Q) +ttyctl -f # freeze terminal state; programs can't leave it broken + +# ── Options ─────────────────────────────────────────────────────────────────── +# Note: appendhistory, nomatch, notify are zsh defaults — not set here. +setopt autocd # cd by typing directory name +setopt extendedglob # extended glob patterns (#, ~, ^) +setopt interactivecomments # allow # comments in interactive shell +setopt rmstarsilent # don't confirm rm * +setopt prompt_subst # expand variables/functions in prompt +setopt auto_pushd # cd pushes old dir onto stack (cd -<TAB> to browse) +setopt pushd_ignore_dups # don't push duplicate dirs onto stack +unsetopt beep # no terminal bell + +# ── History ─────────────────────────────────────────────────────────────────── +HISTFILE="$XDG_STATE_HOME/zsh/history" +HISTSIZE=50000 +SAVEHIST=50000 +setopt extended_history # save timestamp and duration per entry +setopt share_history # share history across concurrent sessions +setopt hist_ignore_all_dups # remove older duplicate when adding new entry +setopt hist_find_no_dups # skip duplicates when searching history +setopt hist_reduce_blanks # trim superfluous whitespace from entries +setopt hist_ignore_space # commands starting with space are not saved + +# ── Emacs keybindings ───────────────────────────────────────────────────────── +bindkey -e + +# ── Prompt ──────────────────────────────────────────────────────────────────── +autoload -Uz colors && colors +source /usr/share/git/completion/git-prompt.sh +PROMPT='%B%{$fg[green]%}%n%{$reset_color%}@%{$fg[cyan]%}%m%{$reset_color%}:%b%{$fg[yellow]%}%~%{$reset_color%}$(__git_ps1 " (%s)")%(?..[%{$fg[red]%}%?%{$reset_color%}]) %(!.#.>) ' + +# ── Completion ──────────────────────────────────────────────────────────────── +fpath=($XDG_DATA_HOME/zsh/completion $fpath) +autoload -Uz compinit && compinit -d "$XDG_CACHE_HOME/zsh/zcompdump" + +zstyle ':completion:*' menu select # arrow-key driven menu for ambiguous completions +zstyle ':completion:*' completer _expand_alias _complete _ignored _match _approximate +# │ │ │ │ └ fuzzy match (typo tolerance) +# │ │ │ └ try pattern matching +# │ │ └ include normally hidden completions +# │ └ standard completion +# └ expand aliases before completing +zstyle ':completion:*:default' list-colors ${(s.:.)LS_COLORS} # colorize file completions like ls +zstyle ':completion:*' use-cache on # cache completions (speeds up pip, dpkg, etc.) +zstyle ':completion:*' cache-path "$XDG_CACHE_HOME/zsh" +zstyle ':completion:*:match:*' original only # only show original when pattern-matching +zstyle ':completion:*:functions' ignored-patterns '_*' # hide internal completion functions +zstyle ':completion:*:*:kill:*' menu yes select # interactive menu for kill completion +zstyle ':completion:*:kill:*' force-list always # always show process list for kill +zstyle ':completion:*:cd:*' ignore-parents parent pwd # cd never completes . or .. +zstyle ':completion::complete:*' gain-privileges 1 # use doas/sudo for privileged completions +zstyle -e ':completion:*:approximate:*' \ + max-errors 'reply=($((($#PREFIX+$#SUFFIX)/3))numeric)' # allow 1 typo per 3 chars typed + +_comp_options+=(globdots) # include hidden files in completion + +# ── Terminal key setup ───────────────────────────────────────────────────────── +# Application mode ensures terminfo values are valid during line editing. +# Without this, some terminals send wrong sequences for special keys. +if (( ${+terminfo[smkx]} && ${+terminfo[rmkx]} )); then + autoload -Uz add-zle-hook-widget + function zle_application_mode_start { echoti smkx } + function zle_application_mode_stop { echoti rmkx } + add-zle-hook-widget -Uz zle-line-init zle_application_mode_start + add-zle-hook-widget -Uz zle-line-finish zle_application_mode_stop +fi + +# Up/Down stored for history-substring-search bindings (set after plugin source) +typeset -g -A key +key[Up]="${terminfo[kcuu1]}" +key[Down]="${terminfo[kcud1]}" + +# ── Custom keybindings ──────────────────────────────────────────────────────── +bindkey \^U backward-kill-line + +# Word navigation (Ctrl-Right also accepts autosuggestion word-by-word — fish-like) +bindkey '^[[1;5C' forward-word # Ctrl-Right +bindkey '^[[1;5D' backward-word # Ctrl-Left +bindkey '^[[1;3C' forward-word # Alt-Right +bindkey '^[[1;3D' backward-word # Alt-Left +bindkey '^H' backward-kill-word # Ctrl-Backspace +bindkey '^[[3;5~' kill-word # Ctrl-Delete + +# Ctrl-Z: toggle foreground/background (no need to type 'fg') +toggle-fg-bg() { + if (( ${#jobstates} )); then + zle .push-input + BUFFER="fg" + zle .accept-line + else + zle .push-input + zle .clear-screen + fi +} +zle -N toggle-fg-bg +bindkey '^Z' toggle-fg-bg + +# Ctrl-D exits even on non-empty line +exit_zsh() { exit } +zle -N exit_zsh +bindkey '^D' exit_zsh + +# Ctrl-X Ctrl-E: edit command in $EDITOR +autoload -Uz edit-command-line +zle -N edit-command-line +bindkey "^X^E" edit-command-line + +# Ctrl-Y: copy current command line to clipboard (OSC 52 — terminal-native) +copy-line-to-clipboard() { printf '\033]52;c;%s\a' "$(echo -n "$BUFFER" | base64)" } +zle -N copy-line-to-clipboard +bindkey '^Y' copy-line-to-clipboard + +# ── Word style ──────────────────────────────────────────────────────────────── +# Ctrl-W/Alt-B/Alt-F use shell quoting rules for word boundaries +autoload -Uz select-word-style +select-word-style shell + +# ── Smart dot expansion ─────────────────────────────────────────────────────── +# Typing .. automatically expands: ... → ../.. , .... → ../../.. , etc. +rationalise-dot() { + if [[ $LBUFFER = *.. ]]; then + LBUFFER+=/.. + else + LBUFFER+=. + fi +} +zle -N rationalise-dot +bindkey . rationalise-dot + +# ── Window title ────────────────────────────────────────────────────────────── +autoload -Uz add-zsh-hook + +xterm_title_precmd() { print -Pn -- '\e]2;%~\a' } +xterm_title_preexec() { print -Pn -- '\e]2;%~ %# ' && print -n -- "${(q)1}\a" } + +if [[ "$TERM" == (xterm-ghostty|st*|screen*|xterm*|rxvt*|tmux*|putty*|konsole*|gnome*) ]]; then + add-zsh-hook -Uz precmd xterm_title_precmd + add-zsh-hook -Uz preexec xterm_title_preexec +fi + +# ── Zellij tab naming (dir:cmd like tmux) ──────────────────────────────────── +if [[ -n "$ZELLIJ" ]]; then + _zellij_dir() { [[ "$PWD" == "$HOME" ]] && echo '~' || echo "${PWD##*/}"; } + _zellij_tab_idx() { echo $(( $(zellij action current-tab-info 2>/dev/null | grep -oP 'position: \K\d+') + 1 )); } + _zellij_tab_precmd() { zellij action rename-tab "$(_zellij_tab_idx):$(_zellij_dir)" 2>/dev/null; } + _zellij_tab_preexec() { zellij action rename-tab "$(_zellij_tab_idx):$(_zellij_dir):${1%% *}" 2>/dev/null; } + add-zsh-hook precmd _zellij_tab_precmd + add-zsh-hook preexec _zellij_tab_preexec +fi + +# ── Recent directories ──────────────────────────────────────────────────────── +autoload -Uz chpwd_recent_dirs cdr +add-zsh-hook chpwd chpwd_recent_dirs +[[ -d ${XDG_STATE_HOME}/zsh ]] || mkdir -p "${XDG_STATE_HOME}/zsh" +zstyle ':chpwd:*' recent-dirs-file "$XDG_STATE_HOME/zsh/chpwd-recent-dirs" +zstyle ':completion:*:*:cdr:*:*' menu selection + +# ── OSC 7 — report CWD to terminal (zellij uses this for new pane/tab CWD) ── +_osc7_chpwd() { + printf '\e]7;file://%s%s\e\\' "${HOST}" "${PWD}" +} +add-zsh-hook chpwd _osc7_chpwd +_osc7_chpwd + +# ── Help system ─────────────────────────────────────────────────────────────── +autoload -Uz run-help run-help-git run-help-ip +(( $+aliases[run-help] )) && unalias run-help +alias help=run-help + +# ── Bracketed paste ─────────────────────────────────────────────────────────── +autoload -Uz bracketed-paste-magic +zle -N bracketed-paste bracketed-paste-magic + +# ── Aliases ─────────────────────────────────────────────────────────────────── +# Files +alias l='lsd -l' +alias la='lsd -lA' +alias lt='lsd --tree' +alias mkdir='mkdir -p' +alias du='du -h' +alias df='df -h' +alias free='free -h' + +# Grep / diff with color +alias grep='grep --color=auto' +alias fgrep='grep -F --color=auto' +alias egrep='grep -E --color=auto' +alias diff='diff --color=auto' +alias dmesg='dmesg --color=auto' +alias dm='dmesg --color=always | less -r' + +# Networking +alias ip="ip -color=auto" +alias lsip="ip -human -color=auto --brief address show" +alias ipa="ip -stats -details -human -color=auto address show" +alias ipecho='curl ipecho.net/plain' +alias ss='doas ss -tupnl' + +# Privilege escalation +alias sudo='doas' +alias sudoedit='doasedit' +alias gimme='doas chown $USER:$(id -gn $USER)' +alias pacdiff='doas pacdiff' + +# Pacman +alias pacopt='comm -13 <(pacman -Qqdt | sort) <(pacman -Qqdtt | sort)' + +# Git +alias g='git' + +# Systemd +alias sys='systemctl' +alias ssys='doas systemctl' +alias sysu='systemctl --user' + +# Navigation +alias c='clear' + +# Yazi: cd-on-exit wrapper +y() { + local tmp="$(mktemp -t "yazi-cwd.XXXXXX")" + command yazi "$@" --cwd-file="$tmp" + IFS= read -r -d '' cwd < "$tmp" + [[ "$cwd" != "$PWD" ]] && [[ -d "$cwd" ]] && builtin cd -- "$cwd" + rm -f -- "$tmp" +} + +# Tools +alias stow='stow -R --no-folding --adopt' +alias curl='curlie' +alias cpr='rsync --archive -hh --partial --info=stats1,progress2 --modify-window=1' +alias mvr='rsync --archive -hh --partial --info=stats1,progress2 --modify-window=1 --remove-source-files' +alias sub='subliminal download -l en' + +# Neovim +alias n='nvim' +alias ndiff='nvim -d' +alias nd='nvim -d' +alias nview='nvim -R' +alias nv='nvim -R' +alias ng='nvim +Neogit' + +# Zellij: smart attach — 0 sessions: create, 1: attach, many: welcome picker +za() { + if [[ -n $ZELLIJ ]]; then + echo "Already inside zellij" >&2 + return 1 + fi + local -a sessions=("${(@f)$(zellij list-sessions -ns 2>/dev/null)}") + sessions=(${sessions:#}) + case ${#sessions} in + 0) zellij ;; + 1) zellij attach "${sessions[1]}" ;; + *) zellij -l welcome ;; + esac +} + +# Just +alias j='just' + +# LLVM / Clang tooling +alias ncmake='cmake -G Ninja -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache -DCMAKE_C_FLAGS="$DEV_CFLAGS" -DCMAKE_CXX_FLAGS="$DEV_CFLAGS" -DCMAKE_INSTALL_PREFIX=build/install -DCMAKE_BUILD_TYPE=Debug -DBUILD_SHARED_LIBS=ON -DCMAKE_EXPORT_COMPILE_COMMANDS=ON -B build' +alias ircc='clang -S -emit-llvm -fno-discard-value-names -O0 -Xclang -disable-O0-optnone -o -' +alias irfc='flang -S -emit-llvm -O0 -o -' +alias astcc='clang -Xclang -ast-dump -fsyntax-only' +alias astfc='flang -fc1 -fdebug-dump-parse-tree' +alias symfc='flang -fc1 -fdebug-dump-symbols' +alias gdbr='gdb -ex start --args' + +# GitHub Copilot CLI +alias copilot='gh copilot --autopilot --enable-all-github-mcp-tools --yolo --resume' + +# ── Alias completions ───────────────────────────────────────────────────────── +compdef g=git +compdef j=just +compdef n=nvim ndiff=nvim nd=nvim nview=nvim nv=nvim +compdef sys=systemctl ssys=systemctl sysu=systemctl +compdef l=lsd la=lsd lt=lsd + +# ── GPG agent ───────────────────────────────────────────────────────────────── +# Set GPG_TTY to this shell's actual TTY (not the login console) and tell +# the agent so pinentry prompts appear in the right terminal +export GPG_TTY=$TTY +gpg-connect-agent updatestartuptty /bye &>/dev/null + +# ── Zoxide (smart directory jumping) ────────────────────────────────────────── +# z foo → jump to frecency-ranked dir matching "foo" +# zi → interactive picker with fzf +eval "$(zoxide init zsh)" + +# ── FZF ─────────────────────────────────────────────────────────────────────── +source <(fzf --zsh) + +# Ctrl-X Ctrl-R: search history with fzf and immediately execute +fzf-history-widget-accept() { + fzf-history-widget + zle accept-line +} +zle -N fzf-history-widget-accept +bindkey '^X^R' fzf-history-widget-accept + +_fzf_compgen_path() { fd --hidden --follow --exclude ".git" . "$1" } +_fzf_compgen_dir() { fd --type d --hidden --follow --exclude ".git" . "$1" } + +# ── Plugins (must be sourced last) ──────────────────────────────────────────── +# Highlight config must be set BEFORE sourcing the plugin +ZSH_HIGHLIGHT_HIGHLIGHTERS=(main brackets pattern) +typeset -A ZSH_HIGHLIGHT_STYLES +ZSH_HIGHLIGHT_STYLES[comment]='fg=yellow' +source /usr/share/zsh/plugins/zsh-syntax-highlighting/zsh-syntax-highlighting.zsh + +source /usr/share/zsh/plugins/zsh-autosuggestions/zsh-autosuggestions.zsh +bindkey '^[[Z' autosuggest-accept # Shift-Tab to accept suggestion + +source /usr/share/zsh/plugins/zsh-history-substring-search/zsh-history-substring-search.zsh +[[ -n "${key[Up]}" ]] && bindkey -- "${key[Up]}" history-substring-search-up +[[ -n "${key[Down]}" ]] && bindkey -- "${key[Down]}" history-substring-search-down |
