diff --git a/.doom.d/config.el b/.doom.d/config.el deleted file mode 100644 index 71c104d..0000000 --- a/.doom.d/config.el +++ /dev/null @@ -1,176 +0,0 @@ -;;; $DOOMDIR/config.el -*- lexical-binding: t; -*- -;; Place your private configuration here! Remember, you do not need to run 'doom -;; sync' after modifying this file! - - -;; Some functionality uses this to identify you, e.g. GPG configuration, email -;; clients, file templates and snippets. -(setq user-full-name "Mike Vanbuskirk" - user-mail-address "mike@mikevanbuskirk.io") - -;; Doom exposes five (optional) variables for controlling fonts in Doom. Here -;; are the three important ones: -;; -;; + `doom-font' -;; + `doom-variable-pitch-font' -;; + `doom-big-font' -- used for `doom-big-font-mode'; use this for -;; presentations or streaming. -;; -;; They all accept either a font-spec, font string ("Input Mono-12"), or xlfd -;; font string. You generally only need these two: -;; (setq doom-font (font-spec :family "monospace" :size 12 :weight 'semi-light) -;; doom-variable-pitch-font (font-spec :family "sans" :size 13)) -(setq doom-font (font-spec :family "Hack Nerd Font Mono" :size 14)) - -;; There are two ways to load a theme. Both assume the theme is installed and -;; available. You can either set `doom-theme' or manually load a theme with the -;; `load-theme' function. This is the default: -(setq doom-theme 'doom-oceanic-next) -(setq doom-themes-treemacs-theme "doom-colors") - -;; If you use `org' and don't want your org files in the default location below, -;; change `org-directory'. It must be set before org loads! -(setq org-local "~/Documents/org/") -(setq org-pkm "~/Dropbox/beorg/org/") -(setq org-projects "~/Dropbox/org/") -(setq org-agenda-files (list org-local (concat org-projects "freelance/") - (concat org-pkm "inbox.org") - (concat org-projects "projects.org"))) -(setq org-refile-targets '((nil :maxlevel . 9) - (org-agenda-files :maxlevel . 9))) - -;; This determines the style of line numbers in effect. If set to `nil', line -;; numbers are disabled. For relative line numbers, set this to `relative'. -(setq display-line-numbers-type 'relative) -(apply #'set-face-attribute '(line-number nil :foreground "#B0BEC5")) - -;; General config -(setq inhibit-splash-screen t) -(transient-mark-mode 1) -(setq shell-file-name "/usr/bin/zsh") -(global-auto-revert-mode t) - -;; Org config -(after! org - (setq org-agenda-skip-deadline-prewarning-if-scheduled t) - (setq org-refile-use-outline-path t) - (setq org-hide-emphasis-markers t) - (setq org-outline-path-complete-in-steps nil) - (setq org-refile-allow-creating-parent-nodes 'confirm) - (setq org-return-follows-link t) - (setq org-clock-into-drawer t) - (setq org-todo-keywords - '((sequence "TODO" "IN-PROGRESS" "WAITING" "DONE"))) - - (setq org-capture-templates - `(("w" "Work Task" entry (file+headline ,(concat org-local "inbox.org") "Tasks") - "* TODO %?") - ("n" "Work Note" entry (file+headline ,(concat org-local "inbox.org") "Notes") - "* %?") - ("t" "Personal Todo" entry (file+headline ,(concat org-pkm "inbox.org") "To-do") - "* TODO %?") - ("c" "Code Task" entry (file+headline ,(concat org-local "inbox.org") "Tasks") - "* TODO %?\n %i\n %a") - ("l" "link" entry (file+headline, (concat org-pkm "inbox.org") "Resources") - "** TODO %(org-cliplink-capture) \n CREATED: %t\n" :immediate-finish t)))) - -;; Org cliplink -(use-package! org-cliplink - :after org) - -;; Org roam -(use-package! org-roam - :after org - :hook - (after-init . org-roam-mode) - :init - (setq org-roam-directory (concat org-pkm "2b/org") - org-roam-completion-everywhere t - org-roam-db-location "~/org-roam.db" - org-roam-graph-executable "/usr/bin/neato" - org-roam-graph-extra-config '(("overlap" . "false") ("splines" . "false")) - org-roam-graph-exclude-matcher '("finished" "blog" "podcast" "article" "video" "to-process" "journal") - org-roam-graph-viewer "/usr/bin/firefox") - :config - (org-roam-mode +1) - (require 'org-roam-protocol) - (setq org-roam-capture-templates - '(("d" "default" plain (function org-roam-capture--get-point) - "\n\n- %?" - :file-name "${slug}" - :head "#+title: ${title} -#+roam_key: ${slug} -#+roam_tags: \"note\" -- tags ::" - :unnarrowed t))) - (setq org-roam-capture-ref-templates - '(("d" "default" plain (function org-roam-capture--get-point) - "\n\n- %?" - :file-name "${slug}" - :head "#+title: ${title} -#+roam_key: ${ref} -#+roam_tags: \"to-process\" -- tags ::" - :unnarrowed t)))) - -;; org-roam-protocol -(use-package! org-roam-protocol - :after org-protocol) - -;; Org journal -(use-package! org-journal - :after org - :bind - ("C-c n j" . org-journal-new-entry) - ("C-c n t" . org-journal-today) - :config - (setq org-journal-date-prefix "#+TITLE: " - org-journal-file-format "journal-%Y-%m-%d.org" - org-journal-dir (concat org-pkm "2b/org") - org-journal-carryover-items nil - org-journal-date-format "%Y-%m-%d")) - -;; Deft -(use-package! deft - :config - (setq deft-extensions '("txt" "tex" "md" "org") - deft-directory org-pkm - deft-recursive t)) - -;; lsp -(use-package! lsp-mode - :commands (lsp)) - -(use-package! company-capf) - -;; Complements `find-defintions' (which is `g d') -(define-key evil-normal-state-map (kbd "g f") 'lsp-ui-peek-find-references) - -(use-package! lsp-ui - :after lsp-mode) - -(after! lsp-ui - (define-key lsp-ui-peek-mode-map (kbd "j") 'lsp-ui-peek--select-next) - (define-key lsp-ui-peek-mode-map (kbd "k") 'lsp-ui-peek--select-prev) - (define-key lsp-ui-peek-mode-map (kbd "C-k") 'lsp-ui-peek--select-prev-file) - (define-key lsp-ui-peek-mode-map (kbd "C-j") 'lsp-ui-peek--select-next-file) - - (setq lsp-ui-peek-fontify 'always - lsp-ui-peek-list-width 50 - lsp-ui-peek-peek-height 40 - - lsp-ui-doc-enable t - ;; Prevents LSP peek to disappear when mouse touches it - lsp-ui-doc-show-with-mouse nil - lsp-ui-doc-include-signature t - lsp-ui-doc-delay 0.5 - lsp-ui-doc-position 'at-point - lsp-ui-doc-max-width 100 - lsp-ui-doc-max-height 40 - - ;; This is just annoying, really - lsp-ui-sideline-enable nil)) - -;; Languages -(use-package! groovy-mode - :mode "\\.groovy\\'") diff --git a/.gitignore b/.gitignore index 3a5ba85..a8e27da 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,7 @@ .DS_Store bin + +# Machine-local overrides (real paths, hosts, secrets). Track *.example instead. +emacs/.config/doom/local.el +emacs/.config/doom/custom.el +hyprland/.config/hypr/local.lua diff --git a/VIM-CHEATSHEET.md b/VIM-CHEATSHEET.md new file mode 100644 index 0000000..40e207a --- /dev/null +++ b/VIM-CHEATSHEET.md @@ -0,0 +1,378 @@ +# Vim/Neovim Cheatsheet + +Quick reference for tmux-heavy DevOps workflow (Python, Terraform, Docker, AWS) + +--- + +## ๐Ÿš€ Installed Plugins + +### Harpoon - File Bookmarking + +| Key | Action | +|-----|--------| +| `a` | Add current file to harpoon | +| `hm` | Toggle harpoon menu | +| `h1` | Jump to harpoon file 1 | +| `h2` | Jump to harpoon file 2 | +| `h3` | Jump to harpoon file 3 | +| `h4` | Jump to harpoon file 4 | +| `hn` | Next harpoon file | +| `hp` | Previous harpoon file | + +### Oil.nvim - Filesystem Editing + +| Key | Action | +|-----|--------| +| `-` | Open parent directory | +| `dd` | Delete file (in Oil buffer) | +| `cw` | Rename file (in Oil buffer) | +| `yy` / `p` | Copy/paste file (in Oil buffer) | +| `:w` | Apply changes (in Oil buffer) | + +### Diffview - Git Diffs + +| Key | Action | +|-----|--------| +| `gd` | Open git diff view | +| `gD` | Close git diff view | +| `gh` | Git history for current file | +| `gH` | Git history for all files | + +### Telescope - Fuzzy Finding + +| Key | Action | +|-----|--------| +| `sf` | Search files (with hidden) | +| `sg` | Live grep | +| `sw` | Search word under cursor | +| `sb` | Search git branches | +| `sc` | Search command history | +| `sm` | Search marks | +| `st` | Search treesitter symbols | +| `sj` | Search jumplist | +| `sh` | Search help tags | +| `sk` | Search keymaps | +| `sd` | Search diagnostics | +| `sr` | Resume last search | +| `s.` | Search recent files | +| `` | Find buffers | +| `gc` | Git commits | +| `gs` | Git status | + +### Fugitive - Git Integration + +| Command | Action | +|---------|--------| +| `:G` | Git status window | +| `:G blame` | Git blame | +| `:G diff` | Git diff | +| `:G log` | Git log | + +### Neo-tree - File Explorer + +| Key | Action | +|-----|--------| +| `` | Toggle Neo-tree | + +### Vim-tmux-navigator + +| Key | Action | +|-----|--------| +| `` | Navigate left (vim/tmux) | +| `` | Navigate down (vim/tmux) | +| `` | Navigate up (vim/tmux) | +| `` | Navigate right (vim/tmux) | + +--- + +## ๐Ÿ“ Marks + +### Local Marks (within file) + +| Key | Action | +|-----|--------| +| `ma` | Set mark 'a' at cursor | +| `'a` | Jump to mark 'a' | +| `` `a `` | Jump to exact position of mark 'a' | +| `]'` | Jump to next line with mark | +| `['` | Jump to previous line with mark | + +### Global Marks (across files) + +| Key | Action | +|-----|--------| +| `mA` | Set global mark 'A' | +| `'A` | Jump to mark 'A' (any file) | +| **Example usage:** | | +| `mT` | Mark terraform main file | +| `mD` | Mark docker-compose file | +| `mP` | Mark python entry point | +| `'T` | Jump to terraform main | + +### Special Marks + +| Key | Action | +|-----|--------| +| `` `. `` | Jump to last change | +| `` `" `` | Jump to last exit position | +| `` `[ `` | Jump to start of last change/yank | +| `` `] `` | Jump to end of last change/yank | + +--- + +## ๐ŸŽฏ Text Objects + +### Motion Commands + +| Key | Action | +|-----|--------| +| `{` / `}` | Jump between paragraphs/blocks | +| `[(` / `])` | Jump to previous/next unmatched `(` | +| `[{` / `]}` | Jump to previous/next unmatched `{` | + +### Text Object Actions + +| Key | Action | +|-----|--------| +| `dap` | Delete around paragraph | +| `=ap` | Auto-indent paragraph | +| `vip` | Visual select inside paragraph | +| `ci"` | Change inside quotes | +| `da(` | Delete around parentheses | +| `vi{` | Visual select inside braces | +| `di{` | Delete inside dict/braces | +| `di[` | Delete inside list/brackets | +| `yiw` | Yank inner word | +| `ciw` | Change inner word | + +--- + +## ๐Ÿ” Navigation + +### Jump List + +| Key | Action | +|-----|--------| +| `` | Jump to older position (back) | +| `` | Jump to newer position (forward) | +| `g;` | Jump to last change position | +| `g,` | Jump to next change position | +| `` | Toggle between current and alternate file | + +### Go-to Commands + +| Key | Action | +|-----|--------| +| `gd` | Go to definition (local scope) | +| `gD` | Go to global definition | +| `gf` | Go to file under cursor | +| `gx` | Open URL under cursor in browser | +| `gg` | Go to first line | +| `G` | Go to last line | +| `10G` | Go to line 10 | + +--- + +## ๐Ÿ“‹ Registers + +### Special Registers + +| Register | Contains | +|----------|----------| +| `"0` | Last yank (not delete!) | +| `"+` | System clipboard | +| `"%` | Current file path | +| `":` | Last command | +| `"/` | Last search | + +### Register Operations + +| Key | Action | +|-----|--------| +| `:reg` | View all registers | +| `"0p` | Paste last yank (safe paste) | +| `"+yy` | Yank line to system clipboard | +| `"+p` | Paste from system clipboard | +| `%` | Insert current file path (insert/command mode) | + +--- + +## ๐ŸŽฌ Macros + +### Recording and Playback + +| Key | Action | +|-----|--------| +| `qa` | Start recording to register 'a' | +| `q` | Stop recording | +| `@a` | Replay macro 'a' | +| `@@` | Replay last macro | +| `100@a` | Run macro 'a' 100 times | + +### Example: Convert print() to logger.info() + +```vim +qa " Record +/print " Find print +ci( " Change inside parentheses +logger.info(0) " Paste what was deleted + " Normal mode +n " Next match +q " Stop +@a " Repeat for next occurrence +``` + +--- + +## ๐Ÿ”ค LSP (Language Server) + +| Key | Action | +|-----|--------| +| `gd` | Go to definition | +| `gD` | Go to declaration | +| `gr` | Go to references | +| `K` | Show hover documentation | +| `rn` | Rename symbol | +| `ca` | Code action | +| `[d` | Go to previous diagnostic | +| `]d` | Go to next diagnostic | + +--- + +## ๐ŸŽจ Visual Mode + +### Visual Selection + +| Key | Action | +|-----|--------| +| `v` | Visual character mode | +| `V` | Visual line mode | +| `` | Visual block mode | +| `gv` | Reselect last visual selection | +| `o` | Toggle cursor to other end of selection | + +### Visual Mode Operations + +| Key | Action | +|-----|--------| +| `>` | Indent | +| `<` | Unindent | +| `=` | Auto-indent | +| `~` | Toggle case | +| `u` | Lowercase | +| `U` | Uppercase | + +--- + +## ๐ŸชŸ Windows & Buffers + +### Window Management + +| Key | Action | +|-----|--------| +| `s` | Split horizontal | +| `v` | Split vertical | +| `q` | Quit window | +| `o` | Close all other windows | +| `=` | Equalize window sizes | +| `_` | Maximize height | +| `\|` | Maximize width | + +### Buffer Navigation + +| Key | Action | +|-----|--------| +| `:bn` | Next buffer | +| `:bp` | Previous buffer | +| `:bd` | Delete buffer | +| `:ls` | List buffers | + +--- + +## ๐Ÿ”ง Editing + +### Indentation + +| Key | Action | +|-----|--------| +| `>>` | Indent line | +| `<<` | Unindent line | +| `=ap` | Auto-indent paragraph | +| `gg=G` | Auto-indent entire file | + +### Case Conversion + +| Key | Action | +|-----|--------| +| `~` | Toggle case of character | +| `gU{motion}` | Uppercase | +| `gu{motion}` | Lowercase | +| `gUU` | Uppercase line | +| `guu` | Lowercase line | + +### Copy/Paste + +| Key | Action | +|-----|--------| +| `yy` | Yank line | +| `Y` | Yank to end of line | +| `p` | Paste after cursor | +| `P` | Paste before cursor | +| `ddp` | Swap current line with next | + +--- + +## ๐Ÿ”Ž Search & Replace + +### Search + +| Key | Action | +|-----|--------| +| `/pattern` | Search forward | +| `?pattern` | Search backward | +| `n` | Next match | +| `N` | Previous match | +| `*` | Search word under cursor (forward) | +| `#` | Search word under cursor (backward) | + +### Replace + +| Command | Action | +|---------|--------| +| `:s/old/new/` | Replace first on line | +| `:s/old/new/g` | Replace all on line | +| `:%s/old/new/g` | Replace all in file | +| `:%s/old/new/gc` | Replace all with confirmation | +| `:5,12s/old/new/g` | Replace in lines 5-12 | + +--- + +## ๐Ÿงฐ DevOps Shell Aliases + +### FZF Functions + +```bash +# Project jumping +p() { cd $(find ~/projects -maxdepth 1 -type d | fzf) } + +# Quick edit with preview +v() { nvim $(fzf --preview 'bat --color=always {}') } + +# Git branch switcher +gb() { git branch -a | grep -v HEAD | sed 's/^..//' | fzf | xargs git checkout } + +# AWS profile switcher +awsp() { export AWS_PROFILE=$(grep -o "\[.*\]" ~/.aws/config | tr -d "[]" | fzf) } +``` + +--- + +## ๐Ÿ’ก Tips + +- **Use Harpoon for your 4-5 core files** - Much faster than telescope +- **Uppercase marks for project navigation** - Mark key files globally +- **Macros for repetitive edits** - Record once, replay many times +- **Text objects for efficient editing** - `dap`, `ci"`, `di{` etc. +- **Visual block mode for columnar edits** - `` then `I` or `A` +- **`` to toggle files** - Quick switch between two files +- **`"0p` for safe paste** - Paste your yank even after deleting diff --git a/X/.xprofile b/X/.xprofile index 8bdce83..73af2c6 100644 --- a/X/.xprofile +++ b/X/.xprofile @@ -1 +1,5 @@ setxkbmap -option "caps:escape" + +# Java/Swing apps (e.g. thinkorswim) render glitched, flashing secondary windows +# and lock up under non-reparenting WMs like i3. Use the JDK's non-reparenting path. +export _JAVA_AWT_WM_NONREPARENTING=1 diff --git a/btop/.config/btop/btop.conf b/btop/.config/btop/btop.conf index 17b4ad5..8a7d449 100644 --- a/btop/.config/btop/btop.conf +++ b/btop/.config/btop/btop.conf @@ -1,18 +1,23 @@ -#? Config file for btop v. 1.4.5 +#? Config file for btop v.1.4.7 #* Name of a btop++/bpytop/bashtop formatted ".theme" file, "Default" and "TTY" for builtin themes. #* Themes should be placed in "../share/btop/themes" relative to binary or "$HOME/.config/btop/themes" -color_theme = "/home/mike/.config/btop/themes/catpuccin_mocha.theme" +color_theme = "catpuccin_mocha" #* If the theme set background should be shown, set to False if you want terminal background transparency. -theme_background = False +theme_background = false #* Sets if 24-bit truecolor should be used, will convert 24-bit colors to 256 color (6x6x6 color cube) if false. -truecolor = True +truecolor = true #* Set to true to force tty mode regardless if a real tty has been detected or not. #* Will force 16-color mode and TTY theme, set all graph symbols to "tty" and swap out other non tty friendly symbols. -force_tty = False +force_tty = false + +#* Option to disable presets. Either the default preset, custom presets, or all presets. +#* "Off" All presets are enabled. +#* "Default" preset is disabled.#* "Custom" presets are disabled.#* "All" presets are disabled. +disable_presets = "Off" #* Define presets for the layout of the boxes. Preset 0 is always all boxes shown with default settings. Max 9 presets. #* Format: "box_name:P:G,box_name:P:G" P=(0 or 1) for alternate positions, G=graph symbol to use for box. @@ -22,10 +27,16 @@ presets = "cpu:1:default,proc:0:default cpu:0:default,mem:0:default,net:0:defaul #* Set to True to enable "h,j,k,l,g,G" keys for directional control in lists. #* Conflicting keys for h:"help" and k:"kill" is accessible while holding shift. -vim_keys = False +vim_keys = false + +#* Disable all mouse events. +disable_mouse = false #* Rounded corners on boxes, is ignored if TTY mode is ON. -rounded_corners = True +rounded_corners = true + +#* Use terminal synchronized output sequences to reduce flickering on supported terminals. +terminal_sync = true #* Default symbols to use for graph creation, "braille", "block" or "tty". #* "braille" offers the highest resolution but might not be included in all fonts. @@ -60,37 +71,43 @@ update_ms = 1000 proc_sorting = "memory" #* Reverse sorting order, True or False. -proc_reversed = False +proc_reversed = false #* Show processes as a tree. -proc_tree = False +proc_tree = false #* Use the cpu graph colors in the process list. -proc_colors = True +proc_colors = true #* Use a darkening gradient in the process list. -proc_gradient = True +proc_gradient = true #* If process cpu usage should be of the core it's running on or usage of the total available cpu power. -proc_per_core = True +proc_per_core = true #* Show process memory as bytes instead of percent. -proc_mem_bytes = True +proc_mem_bytes = true #* Show cpu graph for each process. -proc_cpu_graphs = True +proc_cpu_graphs = true #* Use /proc/[pid]/smaps for memory information in the process info box (very slow but more accurate) -proc_info_smaps = False +proc_info_smaps = false #* Show proc box on left side of screen instead of right. -proc_left = False +proc_left = false #* (Linux) Filter processes tied to the Linux kernel(similar behavior to htop). -proc_filter_kernel = False +proc_filter_kernel = false + +#* Should the process list follow the selected process when detailed view is open. +proc_follow_detailed = true #* In tree-view, always accumulate child process resources in the parent process. -proc_aggregate = False +proc_aggregate = false + +#* Should cpu and memory usage display be preserved for dead processes when paused. +keep_dead_proc_usage = false #* Sets the CPU stat shown in upper half of the CPU graph, "total" is always available. #* Select from a list of detected attributes from the options menu. @@ -104,28 +121,28 @@ cpu_graph_lower = "total" show_gpu_info = "Auto" #* Toggles if the lower CPU graph should be inverted. -cpu_invert_lower = True +cpu_invert_lower = true #* Set to True to completely disable the lower CPU graph. -cpu_single_graph = False +cpu_single_graph = false #* Show cpu box at bottom of screen instead of top. -cpu_bottom = False +cpu_bottom = false #* Shows the system uptime in the CPU box. -show_uptime = True +show_uptime = true #* Shows the CPU package current power consumption in watts. Requires running `make setcap` or `make setuid` or running with sudo. -show_cpu_watts = True +show_cpu_watts = true #* Show cpu temperature. -check_temp = True +check_temp = true #* Which sensor to use for cpu temperature, use options menu to select from list of available sensors. cpu_sensor = "Auto" #* Show temperatures for cpu cores also if check_temp is True and sensors has been found. -show_coretemp = True +show_coretemp = true #* Set a custom mapping between core and coretemp, can be needed on certain cpus to get correct temperature for correct core. #* Use lm-sensors or similar to see which cores are reporting temperatures on your machine. @@ -137,17 +154,20 @@ cpu_core_map = "" temp_scale = "celsius" #* Use base 10 for bits/bytes sizes, KB = 1000 instead of KiB = 1024. -base_10_sizes = False +base_10_sizes = false #* Show CPU frequency. -show_cpu_freq = True +show_cpu_freq = true + +#* How to calculate CPU frequency, available values: "first", "range", "lowest", "highest" and "average". +freq_mode = "first" #* Draw a clock at top of screen, formatting according to strftime, empty string to disable. #* Special formatting: /host = hostname | /user = username | /uptime = system uptime clock_format = "%X" #* Update main ui in background when menus are showing, set this to false if the menus is flickering too much for comfort. -background_update = True +background_update = true #* Custom cpu model name, empty string to disable. custom_cpu_name = "" @@ -157,58 +177,61 @@ custom_cpu_name = "" disks_filter = "" #* Show graphs instead of meters for memory values. -mem_graphs = True +mem_graphs = true #* Show mem box below net box instead of above. -mem_below_net = False +mem_below_net = false #* Count ZFS ARC in cached and available memory. -zfs_arc_cached = True +zfs_arc_cached = true #* If swap memory should be shown in memory box. -show_swap = True +show_swap = true #* Show swap as a disk, ignores show_swap value above, inserts itself after first disk. -swap_disk = True +swap_disk = true #* If mem box should be split to also show disks info. -show_disks = True +show_disks = true #* Filter out non physical disks. Set this to False to include network disks, RAM disks and similar. -only_physical = True +only_physical = true #* Read disks list from /etc/fstab. This also disables only_physical. -use_fstab = True +use_fstab = true #* Setting this to True will hide all datasets, and only show ZFS pools. (IO stats will be calculated per-pool) -zfs_hide_datasets = False +zfs_hide_datasets = false #* Set to true to show available disk space for privileged users. -disk_free_priv = False +disk_free_priv = false #* Toggles if io activity % (disk busy time) should be shown in regular disk usage view. -show_io_stat = True +show_io_stat = true #* Toggles io mode for disks, showing big graphs for disk read/write speeds. -io_mode = False +io_mode = false #* Set to True to show combined read/write io graphs in io mode. -io_graph_combined = False +io_graph_combined = false #* Set the top speed for the io graphs in MiB/s (100 by default), use format "mountpoint:speed" separate disks with whitespace " ". #* Example: "/mnt/media:100 /:20 /boot:1". io_graph_speeds = "" +#* Swap the positions of the upload and download speed graphs. When true, upload will be on top. +swap_upload_download = false + #* Set fixed values for network graphs in Mebibits. Is only used if net_auto is also set to False. net_download = 100 net_upload = 100 #* Use network graphs auto rescaling mode, ignores any values set above and rescales down to 10 Kibibytes at the lowest. -net_auto = True +net_auto = true #* Sync the auto scaling for download and upload to whichever currently has the highest scale. -net_sync = False +net_sync = false #* Starts with the Network Interface specified here. net_iface = "" @@ -217,26 +240,32 @@ net_iface = "" base_10_bitrate = "Auto" #* Show battery stats in top right if battery is present. -show_battery = True +show_battery = true #* Which battery to use if multiple are present. "Auto" for auto detection. selected_battery = "Auto" #* Show power stats of battery next to charge indicator. -show_battery_watts = True +show_battery_watts = true -#* Set loglevel for "~/.config/btop/btop.log" levels are: "ERROR" "WARNING" "INFO" "DEBUG". +#* Set loglevel for "~/.local/state/btop.log" levels are: "ERROR" "WARNING" "INFO" "DEBUG". #* The level set includes all lower levels, i.e. "DEBUG" will show all logging info. log_level = "WARNING" +#* Automatically save current settings to config file on exit. +save_config_on_exit = true + #* Measure PCIe throughput on NVIDIA cards, may impact performance on certain cards. -nvml_measure_pcie_speeds = True +nvml_measure_pcie_speeds = true #* Measure PCIe throughput on AMD cards, may impact performance on certain cards. -rsmi_measure_pcie_speeds = True +rsmi_measure_pcie_speeds = true #* Horizontally mirror the GPU graph. -gpu_mirror_graph = True +gpu_mirror_graph = true + +#* Set which GPU vendors to show. Available values are "nvidia amd intel apple" +shown_gpus = "nvidia amd intel" #* Custom gpu0 model name, empty string to disable. custom_gpu_name0 = "" diff --git a/emacs/.config/doom/config.el b/emacs/.config/doom/config.el index e99a63d..98ad69a 100644 --- a/emacs/.config/doom/config.el +++ b/emacs/.config/doom/config.el @@ -3,6 +3,10 @@ ;; Place your private configuration here! Remember, you do not need to run 'doom ;; sync' after modifying this file! +;; Load machine-local settings (org paths, homelab hosts) from gitignored +;; local.el. Copy local.el.example to local.el on a new machine. +(load! "local" nil t) + ;; Some functionality uses this to identify you, e.g. GPG configuration, email ;; clients, file templates and snippets. It is optional. @@ -39,18 +43,18 @@ ;; numbers are disabled. For relative line numbers, set this to `relative'. (setq display-line-numbers-type 'relative) -;; If you use `org' and don't want your org files in the default location below, + ; If you use `org' and don't want your org files in the default location below, ;; change `org-directory'. It must be set before org loads! -(setq org-local "~/Documents/org/") -(setq org-pkm "~/Dropbox/beorg/org/") -(setq org-projects "~/Dropbox/org/") +;; Fallbacks; real paths set in local.el. defvar won't clobber that. +(defvar org-local "~/org/" "Local org directory.") +(defvar org-pkm "~/org/pkm/" "PKM/notes org root.") +(defvar org-projects "~/org/projects/" "Project org root.") (setq org-agenda-files (list org-local (concat org-projects "freelance/") - (concat org-pkm "inbox.org") - (concat org-pkm "contentsprocket.org") - (concat org-projects "projects.org"))) -(setq org-refile-targets '((nil :maxlevel . 9) - (org-agenda-files :maxlevel . 9))) - + (concat org-pkm "inbox.org") + (concat org-pkm "next.org") + (concat org-pkm "someday.org") + (concat org-projects "projects.org"))) +;; org-refile-targets configured below in `after! org' block ;; General config (setq inhibit-splash-screen t) @@ -61,15 +65,18 @@ ((eq system-type 'darwin) "/bin/zsh") ; macOS ((eq system-type 'gnu/linux) "/usr/bin/zsh") ; Linux (t "/bin/sh"))) ; fallback for other systems -;(setq shell-file-name "/bin/zsh") + ;(setq shell-file-name "/bin/zsh") (global-auto-revert-mode t) -;; Set default transparency mode -(add-to-list 'default-frame-alist '(alpha . 85)) +;; Background transparency. `alpha' sets the X _NET_WM_WINDOW_OPACITY property, +;; which picom honored but Hyprland/Wayland does NOT for XWayland clients -- so it +;; silently does nothing. `alpha-background' (Emacs 29+) uses a real ARGB visual +;; (compositor-agnostic) and only dims the background, keeping text opaque. +(add-to-list 'default-frame-alist '(alpha-background . 85)) (setq doom-theme 'catppuccin) (setq catppuccin-flavor 'mocha) -(setq doom-themes-treemacs-theme "doom-colors") +;;(setq doom-themes-treemacs-theme "doom-colors") ;; Whenever you reconfigure a package, make sure to wrap your config in an ;; `after!' block, otherwise Doom's defaults may override your settings. E.g. @@ -106,59 +113,373 @@ (when (daemonp) (exec-path-from-shell-initialize)) +;;; TRAMP +(after! tramp + (setq tramp-default-method "ssh" + tramp-verbose 1)) + +;; TRAMP host bookmarks for my/homelab-connect; real table set in local.el. +(defvar my/homelab-hosts nil + "Alist of (LABEL . TRAMP-PATH) homelab bookmarks.") + +(defun my/homelab-connect () + "Quick-connect to a homelab host via TRAMP." + (interactive) + (let* ((selection (completing-read "Host: " (mapcar #'car my/homelab-hosts) nil t)) + (path (cdr (assoc selection my/homelab-hosts)))) + (find-file path))) + +(defun my/homelab-find-file () + "Find file on a homelab host via TRAMP." + (interactive) + (let* ((selection (completing-read "Host: " (mapcar #'car my/homelab-hosts) nil t)) + (path (cdr (assoc selection my/homelab-hosts)))) + (let ((default-directory path)) + (call-interactively #'find-file)))) + +;;; Performance tuning +(setq read-process-output-max (* 1024 1024)) ; 1MB for LSP subprocess communication +(setq gcmh-high-cons-threshold (* 64 1024 1024)) ; 64MB during active use + +;; Python +(add-hook! 'python-base-mode-hook 'pet-mode) + +(with-eval-after-load 'eglot + (add-to-list 'eglot-server-programs + '((python-base-mode :language-id "python") . ("ty" "server")))) + +(add-hook 'python-base-mode-hook 'eglot-ensure) + +;; ty handles type checking; ruff handles lint diagnostics. eglot resets +;; `flymake-diagnostic-functions' to its own backend, so add ruff back +;; *after* eglot takes over the buffer. +(after! flymake-ruff + (add-hook 'eglot-managed-mode-hook #'flymake-ruff-load)) + +(after! flycheck + (add-to-list 'flycheck-disabled-checkers 'python-mypy) + (add-to-list 'flycheck-disabled-checkers 'python-pylint) + (add-to-list 'flycheck-disabled-checkers 'python-pyright) + (add-to-list 'flycheck-disabled-checkers 'python-flake8)) + +;; Format on save with ruff (import sort + format), replacing black/isort. +(after! apheleia + (setf (alist-get 'python-mode apheleia-mode-alist) '(ruff-isort ruff) + (alist-get 'python-ts-mode apheleia-mode-alist) '(ruff-isort ruff))) + +;; disable mypy +(add-hook! 'python-base-mode-hook :append + (defun +py/trim-flycheck-checkers () + (make-local-variable 'flycheck-disabled-checkers) + (dolist (c '(python-mypy python-pyright python-pycompile)) + (cl-pushnew c flycheck-disabled-checkers)))) + +;; Manual targeted ruff fix: sort imports + drop unused (I, F401) on the +;; current file only. Uses the venv's ruff resolved via pet's exec-path. +(defun my/ruff-fix-imports () + "Sort and prune imports in the current file with ruff." + (interactive) + (when buffer-file-name + (save-buffer) + (let ((ruff (or (executable-find "ruff") "ruff"))) + (call-process ruff nil nil nil + "check" "--select" "I,F401" "--fix" buffer-file-name)) + (revert-buffer t t t))) +(map! :after python + :localleader :map python-base-mode-map + "i" #'my/ruff-fix-imports) + +(after! company + (setq company-idle-delay 0.3 + company-minimum-prefix-length 2)) + +;;; Projectile / Workspace (sessionizer replacement) +(setq projectile-project-search-path `(("~/projects" . 1) + (,org-local . 0) + (,org-pkm . 1) + ("~/dotfiles" . 0))) +;; Disable auto workspace creation โ€” sessionizer is the single entry point +(setq +workspaces-on-switch-project-behavior nil) +;; Use fd for indexing โ€” faster, respects .gitignore, always fresh (no caching needed) +(setq projectile-indexing-method 'alien + projectile-generic-command "fd . -0 --type f --color=never" + projectile-enable-caching nil + ;; Fall back to default-directory when not in a project (avoids nil errors) + projectile-require-project-root nil + ;; Don't try projectile commands over TRAMP (slow and breaks context) + projectile-mode-line '(:eval (if (file-remote-p default-directory) "" (projectile-project-name)))) + +(after! projectile + ;; Skip Syncthing/system marker dirs during project discovery + (dolist (dir '(".stfolder" ".stversions" ".sync")) + (add-to-list 'projectile-globally-ignored-directories dir)) + ;; Auto-discover projects on startup so the list is pre-loaded + (projectile-discover-projects-in-search-path)) + +;; Terminal opener for a fresh session's pane. Per-machine swap: `+vterm/here' +;; on Linux (vterm), `ghostel' on the Mac ghostty/ghostel setup. Set to nil to +;; skip the terminal pane entirely. +(defvar my/sessionizer-terminal-fn #'+vterm/here + "Function (called with no args) that opens a terminal in the current +window, rooted at `default-directory'.") + +(defvar my/sessionizer-terminal-height 0.35 + "Fraction of the frame height given to the sessionizer terminal pane.") + +(defun my/sessionizer--setup-layout (dir) + "Give a fresh workspace a dired-over-terminal layout, both rooted at DIR." + (let ((default-directory (file-name-as-directory dir))) + (delete-other-windows) + (dired dir) + (when (functionp my/sessionizer-terminal-fn) + (let ((split-window-keep-point t)) + (split-window-below (- (round (* my/sessionizer-terminal-height + (window-total-height)))))) + (other-window 1) + (funcall my/sessionizer-terminal-fn)))) + +(defun my/sessionizer () + "Switch to a project in its own workspace (like tmux sessionizer). +Projects are discovered via projectile; a fresh workspace opens dired over +a terminal. Re-entering an existing workspace switches to it without +rebuilding panes. Single entry point for project switching." + (interactive) + (let* ((projects (projectile-relevant-known-projects)) + (name-to-path (make-hash-table :test 'equal))) + ;; Build lookup โ€” append parent dir for duplicates + (dolist (p projects) + (let ((name (file-name-nondirectory (directory-file-name p)))) + (when (gethash name name-to-path) + (let ((existing (gethash name name-to-path))) + (remhash name name-to-path) + (puthash (format "%s [%s]" (file-name-nondirectory (directory-file-name existing)) + (file-name-nondirectory (directory-file-name (file-name-directory (directory-file-name existing))))) + existing name-to-path) + (setq name (format "%s [%s]" name + (file-name-nondirectory (directory-file-name (file-name-directory (directory-file-name p)))))))) + (puthash name p name-to-path))) + (let* ((selection (completing-read "Session: " (hash-table-keys name-to-path) nil t)) + (project-path (gethash selection name-to-path)) + (existed (member selection (+workspace-list-names)))) + ;; Switch to (or create) the workspace, then tag it with its project + ;; root via the persp parameter Doom itself reads + ;; (`+workspaces-switch-to-project-h', ws-param `+workspace-project'), so + ;; SPC p p / find-file resolve the root with no custom table or advice on + ;; the hot `projectile-project-root'. + (+workspace-switch selection t) + (set-persp-parameter '+workspace-project + (file-truename project-path) + (+workspace-get selection)) + (unless existed + (my/sessionizer--setup-layout project-path))))) + +;;; Terminal (multi-vterm) +(use-package! multi-vterm + :config + (setq multi-vterm-dedicated-window-height-percent 30)) + +(after! vterm + (setq vterm-max-scrollback 10000 + vterm-timer-delay 0.01) + ;; Let window nav keys escape to Emacs instead of being sent to terminal + (dolist (key '("C-h" "C-j" "C-k" "C-l")) + (add-to-list 'vterm-keymap-exceptions key)) + ;; Also bind directly in vterm-mode-map to override any buffer-local bindings + (define-key vterm-mode-map (kbd "C-h") #'evil-window-left) + (define-key vterm-mode-map (kbd "C-j") #'evil-window-down) + (define-key vterm-mode-map (kbd "C-k") #'evil-window-up) + (define-key vterm-mode-map (kbd "C-l") #'evil-window-right)) + +;; ensure GIT_EDITOR is explicitly +;; (picom/glx window bug?) +(setenv "GIT_EDITOR" "emacsclient -c -a ''") + +;;; Keybindings +(setq which-key-idle-delay 0.3) + +;; Use consult-fd instead of locate for SPC s f +(setq consult-locate-args "fd --color=never") + +;; Window navigation with C-h/j/k/l (no prefix needed, vim-tmux-navigator style) +;; Move help from C-h to M-? โ€” SPC h is still available via leader +(global-set-key (kbd "M-?") help-map) +(map! :map 'override + "C-h" #'evil-window-left + "C-j" #'evil-window-down + "C-k" #'evil-window-up + "C-l" #'evil-window-right) + +(map! :leader + ;; Sessionizer + :desc "Sessionizer" "p w" #'my/sessionizer + + ;; Buffer/file quick access + :desc "Switch buffer (workspace)" "," #'persp-switch-to-buffer + :desc "Find file in project" "." #'projectile-find-file + + ;; Insert (extends Doom's SPC i menu) + (:prefix "i" + :desc "Yank as src block" "S" #'my/yank-as-src-block) + + ;; Homelab TRAMP + (:prefix ("r" . "remote") + :desc "Connect to host" "c" #'my/homelab-connect + :desc "Find file on host" "f" #'my/homelab-find-file) + + ;; vterm prefix + (:prefix ("v" . "vterm") + :desc "Toggle vterm popup" "t" #'+vterm/toggle + :desc "New vterm" "n" #'multi-vterm + :desc "Next vterm" "l" #'multi-vterm-next + :desc "Prev vterm" "h" #'multi-vterm-prev + :desc "Dedicated vterm" "d" #'multi-vterm-dedicated-toggle + :desc "Project vterm" "p" #'multi-vterm-project)) + +;;; Format on save โ€” only for specific modes +(setq +format-on-save-enabled-modes '(python-mode go-mode nix-mode terraform-mode)) + +;;; Insert helpers +(defun my/yank-as-src-block (lang) + "Insert the latest kill at point, wrapped in an Org #+begin_src LANG block. +Buffer-agnostic โ€” just inserts text, so it works anywhere, not only Org." + (interactive (list (read-string "src language: " "emacs-lisp"))) + (let ((text (string-trim-right (substring-no-properties (current-kill 0))))) + (insert (format "#+begin_src %s\n%s\n#+end_src\n" lang text)))) + ;;; Org roam (after! org - (setq org-roam-directory (concat org-pkm "2b/org"))); they are implemented. + (setq org-roam-directory (concat org-pkm "2b/org")) + + ;; Keep pasted code's own indentation in src blocks โ€” no org offset/reindent + (setq org-src-preserve-indentation t + org-edit-src-content-indentation 0) -(after! org-roam2 - :ensure t - :init + ;; TODO keywords โ€” Ugmonk-inspired statuses + (setq org-todo-keywords + '((sequence "TODO(t)" "IN-PROGRESS(i)" "WAITING(w)" "DELEGATED(e)" "|" "DONE(d)" "CANCELLED(c)"))) + + ;; Capture templates (beorg-compatible โ€” files in Dropbox) + (setq org-capture-templates + `(("t" "Todo (Inbox)" entry (file+headline ,(concat org-pkm "inbox.org") "To-do") + "* TODO %?\n:PROPERTIES:\n:CREATED: %U\n:END:\n%i") + ("n" "Next" entry (file+headline ,(concat org-pkm "next.org") "Tasks") + "* TODO %?\n:PROPERTIES:\n:CREATED: %U\n:END:\n%i") + ("s" "Someday" entry (file+headline ,(concat org-pkm "someday.org") "Ideas") + "* %?\n:PROPERTIES:\n:CREATED: %U\n:END:\n%i") + ("N" "Note" entry (file+headline ,(concat org-pkm "inbox.org") "Notes") + "* %?\n:PROPERTIES:\n:CREATED: %U\n:END:\n%i") + ("l" "Link/Bookmark" entry (file+headline ,(concat org-pkm "inbox.org") "To-read/To-listen") + "* TODO %?\n:PROPERTIES:\n:CREATED: %U\n:URL: %^{URL}\n:END:\n%i") + ("p" "Project" entry (file+headline ,(concat org-pkm "inbox.org") "Projects") + "* TODO %?\n:PROPERTIES:\n:CREATED: %U\n:END:\n%i") + ("m" "Meeting Notes" entry (file+olp+datetree ,(concat org-pkm "meetings.org")) + "* %? :meeting:\n:PROPERTIES:\n:ATTENDEES:\n:END:\n** Agenda\n** Notes\n** Action Items"))) + + ;; Agenda custom views โ€” Ugmonk dashboard + (setq org-agenda-custom-commands + `(("u" "Ugmonk Dashboard" + ((agenda "" ((org-agenda-span 'day) + (org-agenda-overriding-header "Today"))) + (todo "TODO|IN-PROGRESS" + ((org-agenda-files (list ,(concat org-pkm "next.org"))) + (org-agenda-overriding-header "Next โ€” Pull from here to Today"))) + (todo "TODO" + ((org-agenda-files (list ,(concat org-pkm "someday.org"))) + (org-agenda-overriding-header "Someday โ€” Ideas & Aspirations"))))) + ("d" "Daily Overview" ((agenda "" ((org-agenda-span 'day))) + (tags-todo "+PRIORITY=\"A\"" + ((org-agenda-overriding-header "High Priority"))) + (todo "TODO" + ((org-agenda-overriding-header "All Tasks"))))) + ("i" "Inbox" tags-todo "+inbox" + ((org-agenda-overriding-header "Inbox - Process These"))))) + + ;; Refile โ€” flat outline-path UI (vertico-friendly), creates parents on demand + (setq org-refile-use-outline-path 'file + org-outline-path-complete-in-steps nil + org-refile-allow-creating-parent-nodes 'confirm + org-refile-targets `((,(concat org-pkm "inbox.org") :maxlevel . 3) + (,(concat org-pkm "next.org") :maxlevel . 2) + (,(concat org-pkm "someday.org") :maxlevel . 2) + (,(concat org-projects "projects.org") :maxlevel . 3) + (org-agenda-files :maxlevel . 2)))) + +(after! org-roam (setq org-roam-capture-templates - '( - ("d" "default" plain + '(("d" "default" plain "\n\n- %?" :target (file+head "${slug}.org" "#+TITLE: ${title}\n") - :unnarrowed t)))) + :unnarrowed t) + ("w" "work" plain + "\n\n- %?" + :target (file+head "work/${slug}.org" "#+TITLE: ${title}\n#+FILETAGS: :work:\n") + :unnarrowed t) + ("p" "project" plain + "\n\n- %?" + :target (file+head "projects/${slug}.org" "#+TITLE: ${title}\n#+FILETAGS: :project:\n") + :unnarrowed t))) + + ;; Daily notes (Ugmonk Today card โ€” fresh each day) + (setq org-roam-dailies-directory "daily/") + + (setq org-roam-dailies-capture-templates + '(("d" "Daily Plan" entry + "* TODO %?" + :target (file+head "%<%Y-%m-%d>.org" + "#+title: %<%Y-%m-%d>\n#+filetags: :daily:\n\n* Today\n* Review\n** What got done?\n** What's moving to tomorrow?\n** PKM\n- [ ] Forward rule โ€” literature notes today have a permanent note\n- [ ] Process inbox.org Notes/To-read\n- [ ] One touch on active structure note\n")) + ("t" "Trading Journal" entry + "* %?" + :target (file+head "trading/%<%Y-%m-%d>.org" + "#+title: %<%Y-%m-%d> Trading\n#+filetags: :trading:\n\n* Session Summary\n-\n** VIX\n- High:\n- Low:\n** ES\n** NQ\n* Trades\n"))))) (use-package! websocket - :after org) + :after org) (use-package! org-roam-ui - :after org ;; or :after o - :config - (setq org-roam-ui-sync-theme t - org-roam-ui-follow t - org-roam-ui-update-on-save t)) + :after org ;; or :after o + :config + (setq org-roam-ui-sync-theme t + org-roam-ui-follow t + org-roam-ui-update-on-save t)) (defun my/find-nobacklink-daily-notes() - "Find daily notes with zero connections." + "Find daily notes with zero connections, excluding :trading: journals. +Trading journals are logs, not idea-notes โ€” legitimately isolated, so they +are filtered out to keep this an extraction-candidate list. (Mining journals +for generalizable setups/lessons is a separate, deliberate workflow.)" (interactive) - (let ((results (org-roam-db-query - [:select [nodes:file nodes:title - (as [:select (funcall count links:source) - :from links - :where (and (= links:source nodes:id) - (= links:type "id"))] outgoing) - (as [:select (funcall count links:dest) - :from links - :where (and (= links:dest nodes:id) - (= links:type "id"))] incoming)] - :from nodes - :where (like nodes:file "%/daily/%")]))) + (let* ((trading (mapcar #'car + (org-roam-db-query + [:select tags:node-id :from tags + :where (= tags:tag "trading")]))) + (results (org-roam-db-query + [:select [nodes:id nodes:file nodes:title + (as [:select (funcall count links:source) + :from links + :where (and (= links:source nodes:id) + (= links:type "id"))] outgoing) + (as [:select (funcall count links:dest) + :from links + :where (and (= links:dest nodes:id) + (= links:type "id"))] incoming)] + :from nodes + :where (like nodes:file "%/daily/%")]))) (with-current-buffer (get-buffer-create "*Isolated Daily Notes*") (erase-buffer) - (insert "Truly isolated daily notes (0 in, 0 out):\n\n") + (insert "Truly isolated daily notes (0 in, 0 out), excluding :trading: journals:\n\n") (let ((isolated-count 0)) (dolist (result results) - (let ((file (nth 0 result)) - (title (nth 1 result)) - (outgoing (nth 2 result)) - (incoming (nth 3 result))) - (when (and (= outgoing 0) (= incoming 0)) + (let ((id (nth 0 result)) + (file (nth 1 result)) + (title (nth 2 result)) + (outgoing (nth 3 result)) + (incoming (nth 4 result))) + (when (and (= outgoing 0) (= incoming 0) + (not (member id trading))) (insert-button (file-name-nondirectory file) - 'action (lambda (_) (find-file file)) - 'follow-link t - 'help-echo file) + 'action (lambda (_) (find-file file)) + 'follow-link t + 'help-echo file) (insert (format " - %s\n" title)) (setq isolated-count (1+ isolated-count))))) (goto-char (point-min)) @@ -178,22 +499,211 @@ [:select [nodes:file aliases:alias] :from [nodes aliases] :where (and (= nodes:id aliases:node-id) - (= aliases:alias $s1))] + (= aliases:alias $s1))] search-term))) (with-current-buffer (get-buffer-create "*Duplicate Analysis*") (erase-buffer) (insert (format "Files with title '%s':\n" search-term)) (dolist (match title-matches) (insert-button (file-name-nondirectory (car match)) - 'action (lambda (_) (find-file (car match))) - 'follow-link t - 'help-echo (car match)) + 'action (lambda (_) (find-file (car match))) + 'follow-link t + 'help-echo (car match)) (insert (format " - %s\n" (cadr match)))) (insert (format "\nFiles with alias '%s':\n" search-term)) (dolist (match alias-matches) (insert-button (file-name-nondirectory (car match)) - 'action (lambda (_) (find-file (car match))) - 'follow-link t - 'help-echo (car match)) + 'action (lambda (_) (find-file (car match))) + 'follow-link t + 'help-echo (car match)) (insert (format " - %s\n" (cadr match)))) (pop-to-buffer (current-buffer))))) + +(defun my/org-body-content-lines (file) + "Count meaningful body lines in FILE. +Excludes drawers (:PROPERTIES:, :LOGBOOK:, โ€ฆ), #+keywords, # comments, and +blank lines. A return of 0 means the file is pure scaffolding โ€” a stub." + (if (not (file-readable-p file)) + 0 + (with-temp-buffer + (insert-file-contents file) + (goto-char (point-min)) + (let ((count 0) (in-drawer nil)) + (while (not (eobp)) + (let ((line (string-trim + (buffer-substring-no-properties + (line-beginning-position) (line-end-position))))) + (cond + ;; a bare :WORD: line opens (or, for :END:, closes) a drawer + ((string-match-p "\\`:[A-Za-z0-9_]+:\\'" line) + (setq in-drawer (not (string-equal-ignore-case line ":END:")))) + (in-drawer nil) ; inside a drawer โ€” skip + ((string-empty-p line) nil) ; blank + ((string-prefix-p "#" line) nil) ; #+keywords and # comments + ((string-prefix-p ":" line) nil) ; stray drawer property lines + (t (setq count (1+ count))))) + (forward-line 1)) + count)))) + +(defun my/roam-link-kind (source-file dest-id) + "How does SOURCE-FILE link to DEST-ID? +Return `real' if the id appears on any line that is not a legacy +`- tags ::' line, `tag' if it appears only on tags lines, else nil." + (when (file-readable-p source-file) + (with-temp-buffer + (insert-file-contents source-file) + (goto-char (point-min)) + (let ((needle (concat "[[id:" dest-id)) + (found nil) (real nil)) + (while (search-forward needle nil t) + (setq found t) + (let ((line (string-trim + (buffer-substring-no-properties + (line-beginning-position) (line-end-position))))) + (unless (string-match-p "\\`-?[[:space:]]*tags[[:space:]]*::" line) + (setq real t)))) + (cond (real 'real) (found 'tag) (t nil)))))) + +(defun my/find-stub-notes (&optional max-body-lines) + "List stub notes (empty-bodied file-level nodes), classified by how โ€” and +whether โ€” anything really links to them. Three buckets: + + ORPHAN no inbound id-links at all โ†’ safe to delete + TAG-ONLY linked only by legacy `- tags ::' lines โ†’ promote or retire + REFERENCED a real inline `[[id:]]' link wants it โ†’ promote + +With a prefix arg, count notes with up to that many body lines as stubs +\(default 0 = empty body only). Body is read from disk; link sources come +from the db โ€” run `org-roam-db-sync' first if you have unsynced edits. +Reads source files to classify each link, so it may take a moment." + (interactive "P") + (let* ((threshold (if max-body-lines (prefix-numeric-value max-body-lines) 0)) + (rows (org-roam-db-query + [:select [nodes:id nodes:file nodes:title] + :from nodes :where (= nodes:level 0)])) + (orphan nil) (tag-only nil) (referenced nil)) + (dolist (row rows) + (let ((id (nth 0 row)) (file (nth 1 row)) (title (nth 2 row))) + (when (and (not (string-match-p "/daily/" file)) + (<= (my/org-body-content-lines file) threshold)) + (let ((srcs (delete-dups + (mapcar #'car + (org-roam-db-query + [:select nodes:file + :from [links nodes] + :where (and (= links:source nodes:id) + (= links:dest $s1) + (= links:type "id"))] + id)))) + (real 0) (tag 0)) + (dolist (s srcs) + (pcase (my/roam-link-kind s id) + ('real (setq real (1+ real))) + ('tag (setq tag (1+ tag))))) + (cond ((> real 0) (push (list file title real) referenced)) + ((> tag 0) (push (list file title tag) tag-only)) + (t (push (list file title) orphan))))))) + (cl-flet ((bytitle (l) (sort l (lambda (a b) (string< (cadr a) (cadr b))))) + (section (heading lst note countp) + (insert (format "\nโ”€โ”€ %s (%d) โ”€โ”€\n%s" heading (length lst) + (if note (concat note "\n") ""))) + (dolist (e lst) + (let ((file (car e)) (title (cadr e)) (n (nth 2 e))) + (insert-button (file-name-nondirectory file) + 'action (lambda (_) (find-file file)) + 'follow-link t 'help-echo file) + (insert (if (and countp n) + (format " %s [%d]\n" title n) + (format " %s\n" title))))))) + (setq orphan (bytitle orphan) tag-only (bytitle tag-only) + referenced (bytitle referenced)) + (with-current-buffer (get-buffer-create "*PKM Stubs*") + (erase-buffer) + (insert (format "Stub notes (body โ‰ค %d content line%s)\n" + threshold (if (= threshold 1) "" "s"))) + (insert (format "%d orphan ยท %d tag-only ยท %d referenced\n" + (length orphan) (length tag-only) (length referenced))) + (section "ORPHAN โ€” no inbound links, safe to delete" orphan nil nil) + (section "TAG-ONLY โ€” linked only by legacy `tags ::', promote or retire" + tag-only " [n] = how many tags-lines point here" t) + (section "REFERENCED โ€” a real inline link wants this, promote" + referenced " [n] = inline references" t) + (goto-char (point-min)) + (pop-to-buffer (current-buffer)))))) + +(defun my/find-tags-line-references (node) + "List every legacy `- tags ::' line in other notes that references NODE. +Cleanup checklist for retiring a tag-only stub: visit each line, strip the +link (or delete the line), then delete the stub and `org-roam-db-sync'. +Buttons jump straight to the referencing line." + (interactive (list (org-roam-node-read nil nil nil t))) + (let* ((id (org-roam-node-id node)) + (title (org-roam-node-title node)) + (srcs (delete-dups + (mapcar #'car + (org-roam-db-query + [:select nodes:file + :from [links nodes] + :where (and (= links:source nodes:id) + (= links:dest $s1) + (= links:type "id"))] + id)))) + (needle (concat "[[id:" id)) + (hits nil)) ; (file line text) + (dolist (file srcs) + (when (file-readable-p file) + (with-temp-buffer + (insert-file-contents file) + (goto-char (point-min)) + (while (search-forward needle nil t) + (let ((line (string-trim + (buffer-substring-no-properties + (line-beginning-position) (line-end-position))))) + (when (string-match-p "\\`-?[[:space:]]*tags[[:space:]]*::" line) + (push (list file (line-number-at-pos) line) hits))))))) + (setq hits (nreverse hits)) + (with-current-buffer (get-buffer-create "*Tags-line References*") + (erase-buffer) + (insert (format "tags :: references to: %s\n id:%s\n\n" title id)) + (insert (format "%d tags-line%s across %d file%s\n\n" + (length hits) (if (= (length hits) 1) "" "s") + (length srcs) (if (= (length srcs) 1) "" "s"))) + (if (null hits) + (insert "No tags-line references found โ€” nothing to clean before delete.\n") + (dolist (h hits) + (let ((file (nth 0 h)) (ln (nth 1 h)) (text (nth 2 h))) + (insert-button (format "%s:%d" (file-name-nondirectory file) ln) + 'action (lambda (_) + (find-file file) + (goto-char (point-min)) + (forward-line (1- ln))) + 'follow-link t 'help-echo file) + (insert (format "\n %s\n\n" text))))) + (goto-char (point-min)) + (pop-to-buffer (current-buffer))))) + +;;; LLM / gptel โ€” :tools llm module handles bindings, popup rules, magit hookup. +;; Format authinfo entries as: +;; machine api.anthropic.com login apikey password sk-ant-... +;; machine integrate.api.nvidia.com login apikey password nvapi-... +(setq auth-sources '("~/.authinfo.gpg" "~/.authinfo")) + +(after! gptel + ;; Anthropic as default โ€” prompt caching + tool use + (setq gptel-backend + (gptel-make-anthropic "Claude" + :stream t + :key (lambda () (auth-source-pick-first-password :host "api.anthropic.com")))) + (setq gptel-model 'claude-opus-4-7) + + ;; NVIDIA NIM (OpenAI-compatible) โ€” free open-weight models + (gptel-make-openai "NVIDIA" + :host "integrate.api.nvidia.com" + :endpoint "/v1/chat/completions" + :stream t + :key (lambda () (auth-source-pick-first-password :host "integrate.api.nvidia.com")) + :models '(meta/llama-3.3-70b-instruct + deepseek-ai/deepseek-r1 + nvidia/llama-3.1-nemotron-70b-instruct + qwen/qwen2.5-coder-32b-instruct))) + diff --git a/emacs/.config/doom/init.el b/emacs/.config/doom/init.el index 719cada..6406a72 100644 --- a/emacs/.config/doom/init.el +++ b/emacs/.config/doom/init.el @@ -44,11 +44,11 @@ ophints ; highlight the region an operation acts on (popup +defaults) ; tame sudden yet inevitable temporary windows ;;tabs ; a tab bar for Emacs - treemacs ; a project drawer, like neotree but cooler + ;;treemacs ; a project drawer, like neotree but cooler ;;unicode ; extended unicode support for various languages (vc-gutter +pretty) ; vcs diff in the fringe vi-tilde-fringe ; fringe tildes to mark beyond EOB - ;;window-select ; visually switch windows + window-select ; visually switch windows workspaces ; tab emulation, persistence & separate workspaces ;;zen ; distraction-free coding or writing @@ -56,7 +56,7 @@ (evil +everywhere); come to the dark side, we have cookies file-templates ; auto-snippets for empty files fold ; (nigh) universal code folding - ;;(format +onsave) ; automated prettiness + (format +onsave) ; automated prettiness ;;god ; run Emacs commands without modifier keys ;;lispy ; vim for lisp, for people who don't like vim ;;multiple-cursors ; editing in many places at once @@ -67,14 +67,14 @@ ;;word-wrap ; soft wrapping with language-aware indent :emacs - dired ; making dired pretty [functional] + (dired +dirvish +icons) ; making dired pretty [functional] electric ; smarter, keyword-based electric-indent ;;ibuffer ; interactive buffer management undo ; persistent, smarter undo for your inevitable mistakes vc ; version-control and Emacs, sitting in a tree :term - ;;eshell ; the elisp shell that works everywhere + eshell ; the elisp shell that works everywhere ;;shell ; simple shell REPL for Emacs ;;term ; basic terminal emulator for Emacs vterm ; the best terminal emulation in Emacs @@ -89,13 +89,14 @@ ;;biblio ; Writes a PhD for you (citation needed) ;;collab ; buffers with friends ;;debugger ; FIXME stepping through code, to help you add bugs - ;;direnv + direnv docker ;;editorconfig ; let someone else argue about tabs vs spaces ;;ein ; tame Jupyter notebooks with emacs (eval +overlay) ; run code, run (also, repls) + llm lookup ; navigate your code and its documentation - lsp ; M-x vscode + (lsp +eglot) ; M-x vscode magit ; a git porcelain for Emacs make ; run make tasks from Emacs ;;pass ; password manager for nerds @@ -151,19 +152,19 @@ ;;lua ; one-based indices? one-based indices markdown ; writing docs for people to ignore ;;nim ; python + lisp at the speed of c - ;;nix ; I hereby declare "nix geht mehr!" + (nix + +lsp) ; I hereby declare "nix geht mehr!" ;;ocaml ; an objective camel (org +dragndrop +download - +roam2) ; organize your plain life in plain text + +roam) ; organize your plain life in plain text ;;php ; perl's insecure younger brother ;;plantuml ; diagrams for confusing people more ;;purescript ; javascript, but functional (python +tree-sitter - +poetry - +lsp) ; beautiful is better than ugly + +poetry) ;;qt ; the 'cutest' gui framework ever ;;racket ; a DSL for DSLs ;;raku ; the artist formerly known as perl6 @@ -192,7 +193,7 @@ ;;emms ;;everywhere ; *leave* Emacs!? You must be joking ;;irc ; how neckbeards socialize - ;;(rss +org) ; emacs as an RSS reader + (rss) ; emacs as an RSS reader ;;twitter ; twitter client https://twitter.com/vnought :config diff --git a/emacs/.config/doom/local.el.example b/emacs/.config/doom/local.el.example new file mode 100644 index 0000000..9d2ffbb --- /dev/null +++ b/emacs/.config/doom/local.el.example @@ -0,0 +1,12 @@ +;;; local.el.example -*- lexical-binding: t; -*- +;; Copy to local.el (gitignored) and fill in machine-specific values. + +;; Where your org/PKM trees live on this machine. +(setq org-local "~/org/" + org-pkm "~/org/pkm/" + org-projects "~/org/projects/") + +;; TRAMP bookmarks for my/homelab-connect: (LABEL . PATH) pairs. +(setq my/homelab-hosts + '(("example" . "/ssh:example.lan:") + ("example|root" . "/ssh:example.lan|sudo:example.lan:"))) diff --git a/emacs/.config/doom/packages.el b/emacs/.config/doom/packages.el index 423fb51..4445d3c 100644 --- a/emacs/.config/doom/packages.el +++ b/emacs/.config/doom/packages.el @@ -7,51 +7,59 @@ ;; To install SOME-PACKAGE from MELPA, ELPA or emacsmirror: -;(package! some-package) + ;(package! some-package) ;; To install a package directly from a remote git repo, you must specify a ;; `:recipe'. You'll find documentation on what `:recipe' accepts here: ;; https://github.com/radian-software/straight.el#the-recipe-format -;(package! another-package -; :recipe (:host github :repo "username/repo")) + ;(package! another-package + ; :recipe (:host github :repo "username/repo")) ;; If the package you are trying to install does not contain a PACKAGENAME.el ;; file, or is located in a subdirectory of the repo, you'll need to specify ;; `:files' in the `:recipe': -;(package! this-package -; :recipe (:host github :repo "username/repo" -; :files ("some-file.el" "src/lisp/*.el"))) + ;(package! this-package + ; :recipe (:host github :repo "username/repo" + ; :files ("some-file.el" "src/lisp/*.el"))) ;; If you'd like to disable a package included with Doom, you can do so here ;; with the `:disable' property: -;(package! builtin-package :disable t) + ;(package! builtin-package :disable t) ;; You can override the recipe of a built in package without having to specify ;; all the properties for `:recipe'. These will inherit the rest of its recipe ;; from Doom or MELPA/ELPA/Emacsmirror: -;(package! builtin-package :recipe (:nonrecursive t)) -;(package! builtin-package-2 :recipe (:repo "myfork/package")) + ;(package! builtin-package :recipe (:nonrecursive t)) + ;(package! builtin-package-2 :recipe (:repo "myfork/package")) ;; Specify a `:branch' to install a package from a particular branch or tag. ;; This is required for some packages whose default branch isn't 'master' (which ;; our package manager can't deal with; see radian-software/straight.el#279) -;(package! builtin-package :recipe (:branch "develop")) + ;(package! builtin-package :recipe (:branch "develop")) ;; Use `:pin' to specify a particular commit to install. -;(package! builtin-package :pin "1a2b3c4d5e") + ;(package! builtin-package :pin "1a2b3c4d5e") ;; Doom's packages are pinned to a specific commit and updated from release to ;; release. The `unpin!' macro allows you to unpin single packages... -;(unpin! pinned-package) + ;(unpin! pinned-package) ;; ...or multiple packages -;(unpin! pinned-package another-pinned-package) + ;(unpin! pinned-package another-pinned-package) ;; ...Or *all* packages (NOT RECOMMENDED; will likely break things) -;(unpin! t) + ;(unpin! t) (package! autothemer) -(package! lsp-treemacs) -(package! exec-path-from-shell) +;; These upstreams renamed their default branch master -> main. straight +;; assumes "master" when a recipe omits the branch, so pin it explicitly or +;; sync fails with "couldn't find remote ref master". +(package! exec-path-from-shell :recipe (:branch "main")) +(package! diredfl :recipe (:branch "main")) +(package! flycheck-package :recipe (:branch "main")) +(package! package-lint :recipe (:branch "main")) (unpin! org-roam) (package! org-roam-ui) (package! catppuccin-theme) +(package! multi-vterm) +(package! pet) +(package! flymake-ruff) diff --git a/fuzzel/.config/fuzzel/fuzzel.ini b/fuzzel/.config/fuzzel/fuzzel.ini new file mode 100644 index 0000000..39724e6 --- /dev/null +++ b/fuzzel/.config/fuzzel/fuzzel.ini @@ -0,0 +1,24 @@ +# fuzzel launcher โ€” Catppuccin Mocha. Used by Hyprland (Mod+D) and the +# power menu, and shared with niri. +font=Hack Nerd Font Mono:size=12 +prompt="โฏ " +terminal=kitty +layer=overlay +width=40 +lines=12 +horizontal-pad=20 +vertical-pad=12 +inner-pad=8 + +[colors] +background=1e1e2eee +text=cdd6f4ff +match=f5c2e7ff +selection=45475aff +selection-text=cdd6f4ff +selection-match=f5c2e7ff +border=cba6f7ff + +[border] +width=2 +radius=10 diff --git a/hyprland/.config/hypr/hyprland.lua b/hyprland/.config/hypr/hyprland.lua new file mode 100644 index 0000000..3c47926 --- /dev/null +++ b/hyprland/.config/hypr/hyprland.lua @@ -0,0 +1,393 @@ +-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- +-- AUTOGENERATED HYPRLAND CONFIG. -- +-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- + +-- This is an example Hyprland Lua config file. +-- Refer to the wiki for more information. +-- https://wiki.hypr.land/Configuring/Start/ + +-- Please note not all available settings / options are set here. +-- For a full list, see the wiki + +-- You can (and should!!) split this configuration into multiple files +-- Create your files separately and then require them like this: +-- require("myColors") + +------------------ +---- MONITORS ---- +------------------ + +-- See https://wiki.hypr.land/Configuring/Basics/Monitors/ +-- Per-monitor topology is machine-specific; set it in local.lua (gitignored). +-- Copy local.lua.example to local.lua on a new machine. +local hypr_dir = debug.getinfo(1, "S").source:match("^@(.*/)") or (os.getenv("HOME") .. "/.config/hypr/") +pcall(dofile, hypr_dir .. "local.lua") +-- Fallback for any output not configured in local.lua. +hl.monitor({ output = "", mode = "preferred", position = "auto", scale = "auto" }) + +--------------------- +---- MY PROGRAMS ---- +--------------------- + +-- Set programs that you use +local terminal = "kitty" +local fileManager = "thunar" +local menu = "fuzzel" + +------------------- +---- AUTOSTART ---- +------------------- + +-- See https://wiki.hypr.land/Configuring/Basics/Autostart/ + +-- Autostart necessary processes (like notifications daemons, status bars, etc.) +-- Or execute your favorite apps at launch like this: +-- +hl.on("hyprland.start", function() + hl.exec_cmd("waybar") + hl.exec_cmd("dunst") + if WALLPAPER then hl.exec_cmd("swaybg -i " .. WALLPAPER .. " -m fill") end + hl.exec_cmd("swayidle -w before-sleep 'swaylock -f' lock 'swaylock -f'") +end) + +------------------------------- +---- ENVIRONMENT VARIABLES ---- +------------------------------- + +-- See https://wiki.hypr.land/Configuring/Advanced-and-Cool/Environment-variables/ + +hl.env("XCURSOR_SIZE", "24") +hl.env("HYPRCURSOR_SIZE", "24") +hl.env("LIBVA_DRIVER_NAME", "nvidia") +hl.env("__GLX_VENDOR_LIBRARY_NAME", "nvidia") +hl.env("NVD_BACKEND", "direct") +-- NVIDIA: software cursor avoids hardware-cursor glitches under the open driver. +hl.config({ cursor = { no_hardware_cursors = true } }) + +----------------------- +----- PERMISSIONS ----- +----------------------- + +-- See https://wiki.hypr.land/Configuring/Advanced-and-Cool/Permissions/ +-- Please note permission changes here require a Hyprland restart and are not applied on-the-fly +-- for security reasons + +-- hl.config({ +-- ecosystem = { +-- enforce_permissions = true, +-- }, +-- }) + +-- hl.permission("/usr/(bin|local/bin)/grim", "screencopy", "allow") +-- hl.permission("/usr/(lib|libexec|lib64)/xdg-desktop-portal-hyprland", "screencopy", "allow") +-- hl.permission("/usr/(bin|local/bin)/hyprpm", "plugin", "allow") + +----------------------- +---- LOOK AND FEEL ---- +----------------------- + +-- Refer to https://wiki.hypr.land/Configuring/Basics/Variables/ +hl.config({ + general = { + gaps_in = 5, + gaps_out = 20, + + border_size = 2, + + col = { + active_border = { colors = { "rgba(33ccffee)", "rgba(00ff99ee)" }, angle = 45 }, + inactive_border = "rgba(595959aa)", + }, + + -- Set to true to enable resizing windows by clicking and dragging on borders and gaps + resize_on_border = false, + + -- Please see https://wiki.hypr.land/Configuring/Advanced-and-Cool/Tearing/ before you turn this on + allow_tearing = false, + + layout = "dwindle", + }, + + decoration = { + rounding = 10, + rounding_power = 2, + + -- Change transparency of focused and unfocused windows + active_opacity = 1.0, + inactive_opacity = 1.0, + + shadow = { + enabled = true, + range = 4, + render_power = 3, + color = 0xee1a1a1a, + }, + + blur = { + enabled = true, + size = 3, + passes = 1, + vibrancy = 0.1696, + }, + }, + + animations = { + enabled = true, + }, +}) + +-- Default curves and animations, see https://wiki.hypr.land/Configuring/Advanced-and-Cool/Animations/ +hl.curve("easeOutQuint", { type = "bezier", points = { { 0.23, 1 }, { 0.32, 1 } } }) +hl.curve("easeInOutCubic", { type = "bezier", points = { { 0.65, 0.05 }, { 0.36, 1 } } }) +hl.curve("linear", { type = "bezier", points = { { 0, 0 }, { 1, 1 } } }) +hl.curve("almostLinear", { type = "bezier", points = { { 0.5, 0.5 }, { 0.75, 1 } } }) +hl.curve("quick", { type = "bezier", points = { { 0.15, 0 }, { 0.1, 1 } } }) + +-- Default springs +hl.curve("easy", { type = "spring", mass = 1, stiffness = 71.2633, dampening = 15.8273644 }) + +hl.animation({ leaf = "global", enabled = true, speed = 10, bezier = "default" }) +hl.animation({ leaf = "border", enabled = true, speed = 5.39, bezier = "easeOutQuint" }) +hl.animation({ leaf = "windows", enabled = true, speed = 4.79, spring = "easy" }) +hl.animation({ leaf = "windowsIn", enabled = true, speed = 4.1, spring = "easy", style = "popin 87%" }) +hl.animation({ leaf = "windowsOut", enabled = true, speed = 1.49, bezier = "linear", style = "popin 87%" }) +hl.animation({ leaf = "fadeIn", enabled = true, speed = 1.73, bezier = "almostLinear" }) +hl.animation({ leaf = "fadeOut", enabled = true, speed = 1.46, bezier = "almostLinear" }) +hl.animation({ leaf = "fade", enabled = true, speed = 3.03, bezier = "quick" }) +hl.animation({ leaf = "layers", enabled = true, speed = 3.81, bezier = "easeOutQuint" }) +hl.animation({ leaf = "layersIn", enabled = true, speed = 4, bezier = "easeOutQuint", style = "fade" }) +hl.animation({ leaf = "layersOut", enabled = true, speed = 1.5, bezier = "linear", style = "fade" }) +hl.animation({ leaf = "fadeLayersIn", enabled = true, speed = 1.79, bezier = "almostLinear" }) +hl.animation({ leaf = "fadeLayersOut", enabled = true, speed = 1.39, bezier = "almostLinear" }) +hl.animation({ leaf = "workspaces", enabled = true, speed = 1.94, bezier = "almostLinear", style = "fade" }) +hl.animation({ leaf = "workspacesIn", enabled = true, speed = 1.21, bezier = "almostLinear", style = "fade" }) +hl.animation({ leaf = "workspacesOut", enabled = true, speed = 1.94, bezier = "almostLinear", style = "fade" }) +hl.animation({ leaf = "zoomFactor", enabled = true, speed = 7, bezier = "quick" }) + +-- Ref https://wiki.hypr.land/Configuring/Basics/Workspace-Rules/ +-- "Smart gaps" / "No gaps when only" +-- uncomment all if you wish to use that. +-- hl.workspace_rule({ workspace = "w[tv1]", gaps_out = 0, gaps_in = 0 }) +-- hl.workspace_rule({ workspace = "f[1]", gaps_out = 0, gaps_in = 0 }) +-- hl.window_rule({ +-- name = "no-gaps-wtv1", +-- match = { float = false, workspace = "w[tv1]" }, +-- border_size = 0, +-- rounding = 0, +-- }) +-- hl.window_rule({ +-- name = "no-gaps-f1", +-- match = { float = false, workspace = "f[1]" }, +-- border_size = 0, +-- rounding = 0, +-- }) + +-- See https://wiki.hypr.land/Configuring/Layouts/Dwindle-Layout/ for more +hl.config({ + dwindle = { + preserve_split = true, -- keep a split's orientation instead of auto-flipping + smart_split = false, -- no cursor-quadrant guessing + force_split = 2, -- new windows always open to the right/bottom (predictable, not "clever") + }, +}) + +-- See https://wiki.hypr.land/Configuring/Layouts/Master-Layout/ for more +hl.config({ + master = { + new_status = "master", + }, +}) + +-- See https://wiki.hypr.land/Configuring/Layouts/Scrolling-Layout/ for more +hl.config({ + scrolling = { + fullscreen_on_one_column = true, + }, +}) + +---------------- +---- MISC ---- +---------------- + +hl.config({ + misc = { + force_default_wallpaper = 0, -- no anime mascot wallpaper; we set swaybg ourselves + disable_hyprland_logo = true, + }, +}) + +--------------- +---- INPUT ---- +--------------- + +hl.config({ + input = { + kb_layout = "us", + kb_variant = "", + kb_model = "", + kb_options = "caps:escape", -- Caps Lock = Escape (ported from X setxkbmap; Wayland needs it here) + kb_rules = "", + + follow_mouse = 1, + + sensitivity = 0, -- -1.0 - 1.0, 0 means no modification. + + touchpad = { + natural_scroll = false, + }, + }, +}) + +hl.gesture({ + fingers = 3, + direction = "horizontal", + action = "workspace", +}) + +-- Example per-device config +-- See https://wiki.hypr.land/Configuring/Advanced-and-Cool/Devices/ for more +hl.device({ + name = "epic-mouse-v1", + sensitivity = -0.5, +}) + +--------------------- +---- KEYBINDINGS ---- +--------------------- + +local mainMod = "SUPER" -- Sets "Windows" key as main modifier + +-- Example binds, see https://wiki.hypr.land/Configuring/Basics/Binds/ for more +-- Terminal: kitty + persistent tmux (i3/niri muscle memory: Mod+Return). +hl.bind(mainMod .. " + Return", hl.dsp.exec_cmd("kitty --single-instance tmux new-session -A -s main")) +hl.bind(mainMod .. " + SHIFT + Return", hl.dsp.exec_cmd("kitty --single-instance")) +-- App launcher (fuzzel) and power/session menu, matching niri. +hl.bind(mainMod .. " + D", hl.dsp.exec_cmd("fuzzel")) +hl.bind(mainMod .. " + P", hl.dsp.exec_cmd("~/.config/hypr/scripts/powermenu.sh")) +-- Close focused window (i3: Mod+Shift+q). +hl.bind(mainMod .. " + SHIFT + Q", hl.dsp.window.close()) +hl.bind(mainMod .. " + E", hl.dsp.exec_cmd(fileManager)) +hl.bind(mainMod .. " + V", hl.dsp.window.float({ action = "toggle" })) +hl.bind(mainMod .. " + T", hl.dsp.layout("togglesplit")) -- dwindle only +-- Exit the Hyprland session (deliberate combo to avoid accidents). +hl.bind(mainMod .. " + SHIFT + M", hl.dsp.exec_cmd("uwsm stop 2>/dev/null || hyprctl dispatch 'hl.dsp.exit()'")) + +-- Move focus with mainMod + arrow keys +hl.bind(mainMod .. " + left", hl.dsp.focus({ direction = "left" })) +hl.bind(mainMod .. " + right", hl.dsp.focus({ direction = "right" })) +hl.bind(mainMod .. " + up", hl.dsp.focus({ direction = "up" })) +hl.bind(mainMod .. " + down", hl.dsp.focus({ direction = "down" })) +-- vim-style focus (matches niri/i3 hjkl) +hl.bind(mainMod .. " + H", hl.dsp.focus({ direction = "left" })) +hl.bind(mainMod .. " + J", hl.dsp.focus({ direction = "down" })) +hl.bind(mainMod .. " + K", hl.dsp.focus({ direction = "up" })) +hl.bind(mainMod .. " + L", hl.dsp.focus({ direction = "right" })) +-- Move the focused window with Mod + SHIFT + hjkl +hl.bind(mainMod .. " + SHIFT + H", hl.dsp.window.move({ direction = "left" })) +hl.bind(mainMod .. " + SHIFT + J", hl.dsp.window.move({ direction = "down" })) +hl.bind(mainMod .. " + SHIFT + K", hl.dsp.window.move({ direction = "up" })) +hl.bind(mainMod .. " + SHIFT + L", hl.dsp.window.move({ direction = "right" })) +-- Screenshots (grim + slurp + wl-clipboard): region to clipboard AND file. +hl.bind(mainMod .. " + SHIFT + S", hl.dsp.exec_cmd("grim -g \"$(slurp)\" - | tee \"$HOME/Pictures/Screenshots/$(date +%s).png\" | wl-copy")) +hl.bind("Print", hl.dsp.exec_cmd("grim \"$HOME/Pictures/Screenshots/$(date +%s).png\"")) + +-- Switch workspaces with mainMod + [0-9] +-- Move active window to a workspace with mainMod + SHIFT + [0-9] +for i = 1, 10 do + local key = i % 10 -- 10 maps to key 0 + hl.bind(mainMod .. " + " .. key, hl.dsp.focus({ workspace = i })) + hl.bind(mainMod .. " + SHIFT + " .. key, hl.dsp.window.move({ workspace = i })) +end + +-- Example special workspace (scratchpad) +hl.bind(mainMod .. " + S", hl.dsp.workspace.toggle_special("magic")) +-- (moved off Mod+Shift+S, which is now the screenshot bind) +hl.bind(mainMod .. " + SHIFT + grave", hl.dsp.window.move({ workspace = "special:magic" })) + +-- Scroll through existing workspaces with mainMod + scroll +hl.bind(mainMod .. " + mouse_down", hl.dsp.focus({ workspace = "e+1" })) +hl.bind(mainMod .. " + mouse_up", hl.dsp.focus({ workspace = "e-1" })) + +-- Move/resize windows with mainMod + LMB/RMB and dragging +hl.bind(mainMod .. " + mouse:272", hl.dsp.window.drag(), { mouse = true }) +hl.bind(mainMod .. " + mouse:273", hl.dsp.window.resize(), { mouse = true }) + +-- Laptop multimedia keys for volume and LCD brightness +hl.bind( + "XF86AudioRaiseVolume", + hl.dsp.exec_cmd("wpctl set-volume -l 1 @DEFAULT_AUDIO_SINK@ 5%+"), + { locked = true, repeating = true } +) +hl.bind( + "XF86AudioLowerVolume", + hl.dsp.exec_cmd("wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%-"), + { locked = true, repeating = true } +) +hl.bind( + "XF86AudioMute", + hl.dsp.exec_cmd("wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle"), + { locked = true, repeating = true } +) +hl.bind( + "XF86AudioMicMute", + hl.dsp.exec_cmd("wpctl set-mute @DEFAULT_AUDIO_SOURCE@ toggle"), + { locked = true, repeating = true } +) +hl.bind("XF86MonBrightnessUp", hl.dsp.exec_cmd("brightnessctl -e4 -n2 set 5%+"), { locked = true, repeating = true }) +hl.bind("XF86MonBrightnessDown", hl.dsp.exec_cmd("brightnessctl -e4 -n2 set 5%-"), { locked = true, repeating = true }) + +-- Requires playerctl +hl.bind("XF86AudioNext", hl.dsp.exec_cmd("playerctl next"), { locked = true }) +hl.bind("XF86AudioPause", hl.dsp.exec_cmd("playerctl play-pause"), { locked = true }) +hl.bind("XF86AudioPlay", hl.dsp.exec_cmd("playerctl play-pause"), { locked = true }) +hl.bind("XF86AudioPrev", hl.dsp.exec_cmd("playerctl previous"), { locked = true }) + +-------------------------------- +---- WINDOWS AND WORKSPACES ---- +-------------------------------- + +-- See https://wiki.hypr.land/Configuring/Basics/Window-Rules/ +-- and https://wiki.hypr.land/Configuring/Basics/Workspace-Rules/ + +-- Example window rules that are useful + +local suppressMaximizeRule = hl.window_rule({ + -- Ignore maximize requests from all apps. You'll probably like this. + name = "suppress-maximize-events", + match = { class = ".*" }, + + suppress_event = "maximize", +}) +-- suppressMaximizeRule:set_enabled(false) + +hl.window_rule({ + -- Fix some dragging issues with XWayland + name = "fix-xwayland-drags", + match = { + class = "^$", + title = "^$", + xwayland = true, + float = true, + fullscreen = false, + pin = false, + }, + + no_focus = true, +}) + +-- Layer rules also return a handle. +-- local overlayLayerRule = hl.layer_rule({ +-- name = "no-anim-overlay", +-- match = { namespace = "^my-overlay$" }, +-- no_anim = true, +-- }) +-- overlayLayerRule:set_enabled(false) + +-- Hyprland-run windowrule +hl.window_rule({ + name = "move-hyprland-run", + match = { class = "hyprland-run" }, + + move = "20 monitor_h-120", + float = true, +}) diff --git a/hyprland/.config/hypr/local.lua.example b/hyprland/.config/hypr/local.lua.example new file mode 100644 index 0000000..ec25506 --- /dev/null +++ b/hyprland/.config/hypr/local.lua.example @@ -0,0 +1,7 @@ +-- Copy to local.lua (gitignored) and set machine-specific monitors + wallpaper. + +-- One hl.monitor{} call per output. See https://wiki.hypr.land/Configuring/Basics/Monitors/ +hl.monitor({ output = "DP-1", mode = "preferred", position = "0x0", scale = 1 }) + +-- Absolute path to wallpaper image (swaybg). Unset = no wallpaper. +WALLPAPER = os.getenv("HOME") .. "/Pictures/wallpaper.jpg" diff --git a/hyprland/.config/hypr/scripts/powermenu.sh b/hyprland/.config/hypr/scripts/powermenu.sh new file mode 100755 index 0000000..0613176 --- /dev/null +++ b/hyprland/.config/hypr/scripts/powermenu.sh @@ -0,0 +1,15 @@ +#!/bin/sh +# Wayland power menu via fuzzel. Shared by Hyprland (Mod+P / waybar power button). +# No wlogout dependency โ€” fuzzel is already used as the launcher. +chosen=$(printf '%s\n' ' Lock' ' Logout' ' Suspend' ' Reboot' ' Shutdown' \ + | fuzzel --dmenu --prompt "power: ") + +case "$chosen" in + *Lock) swaylock ;; + *Logout) uwsm stop 2>/dev/null \ + || hyprctl dispatch 'hl.dsp.exit()' 2>/dev/null \ + || loginctl terminate-session "${XDG_SESSION_ID}" ;; + *Suspend) systemctl suspend ;; + *Reboot) systemctl reboot ;; + *Shutdown) systemctl poweroff ;; +esac diff --git a/i3/.config/i3/config b/i3/.config/i3/config index 9e24376..5d069a1 100644 --- a/i3/.config/i3/config +++ b/i3/.config/i3/config @@ -38,12 +38,17 @@ font pango:Hack Nerd Font Mono 12 # The combination of xss-lock, nm-applet and pactl is a popular choice, so # they are included here as an example. Modify as you see fit. +# Spoof the WM name so Java/Swing apps use a working modal/transient +# code path. Under the real name "i3", JDK X11 crashes on modal dialog teardown +# ("Window must not be zero"). LG3D is the long-standing workaround. +exec_always --no-startup-id wmname LG3D + # xss-lock grabs a logind suspend inhibit lock and will use i3lock to lock the # screen before suspend. Use loginctl lock-session to lock your screen. exec --no-startup-id xss-lock --transfer-sleep-lock -- i3lock --nofork # start picom compositor -exec --no-startup-id picom -b +exec_always --no-startup-id sh -c 'pkill -x picom; sleep 0.5; exec picom' # NetworkManager is the most popular way to manage wireless networks on Linux, # and nm-applet is a desktop environment-independent system tray GUI for it. @@ -69,7 +74,6 @@ exec --no-startup-id sh -c '/usr/bin/nvidia-settings --load-config-only' # Set background/wallpaper exec --no-startup-id nitrogen --restore -exec --no-startup-id nitrogen --restore # Start polybar exec_always --no-startup-id $HOME/.config/polybar/launch.sh @@ -135,10 +139,10 @@ bindsym $mod+d exec --no-startup-id ~/.config/rofi/scripts/launcher_t1 bindsym $mod+p exec --no-startup-id ~/.config/rofi/applets/bin/powermenu.sh # Take screenshot to clipboard -bindsym $mod+Shift+s exec maim -s -u | xclip -selection clipboard -t image/png -i +bindsym --release $mod+Shift+s exec maim -s -u | xclip -selection clipboard -t image/png -i # Take screenshot to file -bindsym $mod+Shift+f exec maim -s -u ~/Pictures/screenshots/screenshot-$(date +%s).png +bindsym --release $mod+Shift+f exec maim -s -u ~/Pictures/screenshots/screenshot-$(date +%s).png # set border to none bindsym $mod+u border none diff --git a/nvim/.config/nvim/init.lua b/nvim/.config/nvim/init.lua index bc0a1af..bfabf98 100644 --- a/nvim/.config/nvim/init.lua +++ b/nvim/.config/nvim/init.lua @@ -439,6 +439,16 @@ require('lazy').setup({ vim.keymap.set('n', 's.', builtin.oldfiles, { desc = '[S]earch Recent Files ("." for repeat)' }) vim.keymap.set('n', '', builtin.buffers, { desc = '[ ] Find existing buffers' }) + -- Additional telescope pickers + vim.keymap.set('n', 'sb', builtin.git_branches, { desc = '[S]earch git [B]ranches' }) + vim.keymap.set('n', 'sc', builtin.command_history, { desc = '[S]earch [C]ommand history' }) + vim.keymap.set('n', 'sm', builtin.marks, { desc = '[S]earch [M]arks' }) + vim.keymap.set('n', 'st', builtin.treesitter, { desc = '[S]earch [T]reesitter symbols' }) + + -- Git-specific pickers + vim.keymap.set('n', 'gc', builtin.git_commits, { desc = '[G]it [C]ommits' }) + vim.keymap.set('n', 'gs', builtin.git_status, { desc = '[G]it [S]tatus' }) + -- Slightly advanced example of overriding default behavior and theme vim.keymap.set('n', '/', function() -- You can pass additional configuration to Telescope to change the theme, layout, etc. @@ -758,6 +768,7 @@ require('lazy').setup({ 'shellcheck', -- Bash linter 'hadolint', -- Dockerfile linter 'yamlfmt', -- YAML formatter + 'markdownlint', -- Markdown linter }) require('mason-tool-installer').setup { ensure_installed = ensure_installed } diff --git a/nvim/.config/nvim/lazy-lock.json b/nvim/.config/nvim/lazy-lock.json index 29bec9c..6ced998 100644 --- a/nvim/.config/nvim/lazy-lock.json +++ b/nvim/.config/nvim/lazy-lock.json @@ -1,35 +1,38 @@ { - "LuaSnip": { "branch": "master", "commit": "5a1e39223db9a0498024a77b8441169d260c8c25" }, - "blink.cmp": { "branch": "main", "commit": "327fff91fe6af358e990be7be1ec8b78037d2138" }, - "catppuccin": { "branch": "main", "commit": "cb5665990a797b102715188e73c44c3931b3b42e" }, - "conform.nvim": { "branch": "master", "commit": "cde4da5c1083d3527776fee69536107d98dae6c9" }, - "copilot.vim": { "branch": "release", "commit": "da369d90cfd6c396b1d0ec259836a1c7222fb2ea" }, - "fidget.nvim": { "branch": "main", "commit": "e32b672d8fd343f9d6a76944fedb8c61d7d8111a" }, - "gitsigns.nvim": { "branch": "main", "commit": "20ad4419564d6e22b189f6738116b38871082332" }, + "LuaSnip": { "branch": "master", "commit": "642b0c595e11608b4c18219e93b88d7637af27bc" }, + "blink.cmp": { "branch": "main", "commit": "78336bc89ee5365633bcf754d93df01678b5c08f" }, + "catppuccin": { "branch": "main", "commit": "605b4603797de970e9f3a4238c199c850da03186" }, + "conform.nvim": { "branch": "master", "commit": "619363c30309d29ffa631e67c8183f2a72caa373" }, + "copilot.vim": { "branch": "release", "commit": "a12fd5672110c8aa7e3c8419e28c96943ca179be" }, + "diffview.nvim": { "branch": "main", "commit": "4516612fe98ff56ae0415a259ff6361a89419b0a" }, + "fidget.nvim": { "branch": "main", "commit": "82404b196e73a00b1727a91903beef5ddc319d22" }, + "gitsigns.nvim": { "branch": "main", "commit": "dd3f588bacbeb041be6facf1742e42097f62165d" }, "guess-indent.nvim": { "branch": "main", "commit": "84a4987ff36798c2fc1169cbaff67960aed9776f" }, - "lazy.nvim": { "branch": "main", "commit": "85c7ff3711b730b4030d03144f6db6375044ae82" }, - "lazydev.nvim": { "branch": "main", "commit": "5231c62aa83c2f8dc8e7ba957aa77098cda1257d" }, - "mason-lspconfig.nvim": { "branch": "main", "commit": "b1d9a914b02ba5660f1e272a03314b31d4576fe2" }, + "harpoon": { "branch": "harpoon2", "commit": "87b1a3506211538f460786c23f98ec63ad9af4e5" }, + "lazy.nvim": { "branch": "main", "commit": "306a05526ada86a7b30af95c5cc81ffba93fef97" }, + "lazydev.nvim": { "branch": "main", "commit": "ff2cbcba459b637ec3fd165a2be59b7bbaeedf0d" }, + "mason-lspconfig.nvim": { "branch": "main", "commit": "0a695750d747db1e7e70bcf0267ef8951c95fc83" }, "mason-nvim-dap.nvim": { "branch": "main", "commit": "9a10e096703966335bd5c46c8c875d5b0690dade" }, - "mason-tool-installer.nvim": { "branch": "main", "commit": "517ef5994ef9d6b738322664d5fdd948f0fdeb46" }, - "mason.nvim": { "branch": "main", "commit": "ad7146aa61dcaeb54fa900144d768f040090bff0" }, - "mini.nvim": { "branch": "main", "commit": "f43357be022565d969795cde29b8988d082cc913" }, - "neo-tree.nvim": { "branch": "v3.x", "commit": "f3df514fff2bdd4318127c40470984137f87b62e" }, + "mason-tool-installer.nvim": { "branch": "main", "commit": "443f1ef8b5e6bf47045cb2217b6f748a223cf7dc" }, + "mason.nvim": { "branch": "main", "commit": "16ba83bfc8a25f52bb545134f5bee082b195c460" }, + "mini.nvim": { "branch": "main", "commit": "8b63dc6caf94f6580e371f9b339548848f72e489" }, + "neo-tree.nvim": { "branch": "v3.x", "commit": "ebd66767191714e008ce73b769518a763ff31bdc" }, "nui.nvim": { "branch": "main", "commit": "de740991c12411b663994b2860f1a4fd0937c130" }, - "nvim-dap": { "branch": "master", "commit": "b38f7d30366d9169d0a623c4c85fbcf99d8d58bb" }, + "nvim-dap": { "branch": "master", "commit": "531771530d4f82ad2d21e436e3cc052d68d7aebb" }, "nvim-dap-go": { "branch": "main", "commit": "b4421153ead5d726603b02743ea40cf26a51ed5f" }, - "nvim-dap-ui": { "branch": "master", "commit": "cf91d5e2d07c72903d052f5207511bf7ecdb7122" }, - "nvim-lint": { "branch": "master", "commit": "8b349e822a36e9480aed96c6dd2f757f80524a35" }, - "nvim-lspconfig": { "branch": "master", "commit": "c8503e63c6afab3ed34b49865a4a4edbb1ebf4a8" }, + "nvim-dap-ui": { "branch": "master", "commit": "1a66cabaa4a4da0be107d5eda6d57242f0fe7e49" }, + "nvim-lint": { "branch": "master", "commit": "d48f3a76189d03b2239f6df1b2f7e3fa8353743b" }, + "nvim-lspconfig": { "branch": "master", "commit": "9573948c38bfabeec353ae7dd7d3ffec4c506a6b" }, "nvim-nio": { "branch": "master", "commit": "21f5324bfac14e22ba26553caf69ec76ae8a7662" }, - "nvim-treesitter": { "branch": "master", "commit": "42fc28ba918343ebfd5565147a42a26580579482" }, - "nvim-web-devicons": { "branch": "master", "commit": "8dcb311b0c92d460fac00eac706abd43d94d68af" }, - "plenary.nvim": { "branch": "master", "commit": "b9fd5226c2f76c951fc8ed5923d85e4de065e509" }, - "telescope-fzf-native.nvim": { "branch": "main", "commit": "6fea601bd2b694c6f2ae08a6c6fab14930c60e2c" }, + "nvim-treesitter": { "branch": "master", "commit": "cf12346a3414fa1b06af75c79faebe7f76df080a" }, + "nvim-web-devicons": { "branch": "master", "commit": "dfbfaa967a6f7ec50789bead7ef87e336c1fa63c" }, + "oil.nvim": { "branch": "master", "commit": "b91ee5a77a6a9605d9c1aaf4fda74b66082c8297" }, + "plenary.nvim": { "branch": "master", "commit": "74b06c6c75e4eeb3108ec01852001636d85a932b" }, + "telescope-fzf-native.nvim": { "branch": "main", "commit": "b25b749b9db64d375d782094e2b9dce53ad53a40" }, "telescope-ui-select.nvim": { "branch": "master", "commit": "6e51d7da30bd139a6950adf2a47fda6df9fa06d2" }, - "telescope.nvim": { "branch": "master", "commit": "0294ae3eafe662c438addb8692d9c98ef73a983e" }, + "telescope.nvim": { "branch": "master", "commit": "7d324792b7943e4aa16ad007212e6acc6f9fe335" }, "todo-comments.nvim": { "branch": "main", "commit": "31e3c38ce9b29781e4422fc0322eb0a21f4e8668" }, - "vim-fugitive": { "branch": "master", "commit": "61b51c09b7c9ce04e821f6cf76ea4f6f903e3cf4" }, - "vim-tmux-navigator": { "branch": "master", "commit": "c45243dc1f32ac6bcf6068e5300f3b2b237e576a" }, + "vim-fugitive": { "branch": "master", "commit": "3b753cf8c6a4dcde6edee8827d464ba9b8c4a6f0" }, + "vim-tmux-navigator": { "branch": "master", "commit": "e41c431a0c7b7388ae7ba341f01a0d217eb3a432" }, "which-key.nvim": { "branch": "main", "commit": "3aab2147e74890957785941f0c1ad87d0a44c15a" } } diff --git a/nvim/.config/nvim/lua/custom/plugins/init.lua b/nvim/.config/nvim/lua/custom/plugins/init.lua index bfadafb..4f216ec 100644 --- a/nvim/.config/nvim/lua/custom/plugins/init.lua +++ b/nvim/.config/nvim/lua/custom/plugins/init.lua @@ -42,6 +42,67 @@ return { vim.cmd.colorscheme 'catppuccin' end, }, + { + 'ThePrimeagen/harpoon', + branch = 'harpoon2', + dependencies = { 'nvim-lua/plenary.nvim' }, + config = function() + local harpoon = require 'harpoon' + harpoon:setup() + + vim.keymap.set('n', 'a', function() + harpoon:list():add() + end, { desc = 'Harpoon [A]dd file' }) + vim.keymap.set('n', 'hm', function() + harpoon.ui:toggle_quick_menu(harpoon:list()) + end, { desc = '[H]arpoon [M]enu' }) + + -- Quick jump to positions 1-4 (avoids collision with for tmux-navigator) + vim.keymap.set('n', 'h1', function() + harpoon:list():select(1) + end, { desc = '[H]arpoon file 1' }) + vim.keymap.set('n', 'h2', function() + harpoon:list():select(2) + end, { desc = '[H]arpoon file 2' }) + vim.keymap.set('n', 'h3', function() + harpoon:list():select(3) + end, { desc = '[H]arpoon file 3' }) + vim.keymap.set('n', 'h4', function() + harpoon:list():select(4) + end, { desc = '[H]arpoon file 4' }) + + -- Cycle through harpoon list + vim.keymap.set('n', 'hn', function() + harpoon:list():next() + end, { desc = '[H]arpoon [N]ext' }) + vim.keymap.set('n', 'hp', function() + harpoon:list():prev() + end, { desc = '[H]arpoon [P]rev' }) + end, + }, + { + 'stevearc/oil.nvim', + opts = { + columns = { 'icon' }, + view_options = { + show_hidden = true, + }, + }, + keys = { + { '-', 'Oil', desc = 'Open parent directory' }, + }, + }, + { + 'sindrets/diffview.nvim', + dependencies = { 'nvim-lua/plenary.nvim' }, + cmd = { 'DiffviewOpen', 'DiffviewClose', 'DiffviewFileHistory' }, + keys = { + { 'gd', 'DiffviewOpen', desc = '[G]it [D]iff' }, + { 'gD', 'DiffviewClose', desc = '[G]it [D]iff close' }, + { 'gh', 'DiffviewFileHistory %', desc = '[G]it [H]istory (current file)' }, + { 'gH', 'DiffviewFileHistory', desc = '[G]it [H]istory (all files)' }, + }, + }, { 'github/copilot.vim', }, diff --git a/picom/.config/picom/picom.conf b/picom/.config/picom/picom.conf index 5ec21fa..b0600c0 100644 --- a/picom/.config/picom/picom.conf +++ b/picom/.config/picom/picom.conf @@ -133,16 +133,16 @@ focus-exclude = [ "class_g = 'Cairo-clock'" ]; # example: # opacity-rule = [ "80:class_g = 'URxvt'" ]; # -opacity-rule = [ "100:name *= 'Steam'"] -opacity-rule = [ "100:name *= 'Slack'"] -opacity-rule = [ "100:name *= 'Discord'"] -opacity-rule = [ "100:name *= 'zoom'"] -opacity-rule = [ "100:name *= 'firefox'"] -opacity-rule = [ "100:class_g *= 'Steam'", "100:class_i = 'Steam'"] -opacity-rule = [ "100:class_g *= 'firefox'"] -opacity-rule = [ "100:class_g = 'firefox' && focused", "100:class_g = 'firefox' && !focused" ]; -opacity-rule = [ "100:class_i = 'Navigator' && focused", "100:class_i = 'Navigator' && !focused" ]; -opacity-rule = [ "100:class_i = 'zoom' && focused", "100:class_i = 'zoom' && !focused" ]; +opacity-rule = [ + "100:name *= 'Steam'", + "100:name *= 'Slack'", + "100:name *= 'Discord'", + "100:name *= 'zoom'", + "100:class_g *= 'Steam'", + "100:class_i = 'Steam'", + "100:class_g *= 'firefox'", + "100:class_i = 'Navigator'" +]; ################################# # Corners # @@ -263,7 +263,7 @@ detect-client-opacity = true; # to maximize performance for full-screen windows. Known to cause flickering # when redirecting/unredirecting windows. # - unredir-if-possible = true + unredir-if-possible = false; # Delay before unredirecting the window, in milliseconds. Defaults to 0. # unredir-if-possible-delay = 0 @@ -307,7 +307,7 @@ detect-transient = true; # practically happened) and may not work with blur-background. # My tests show a 15% performance boost. Recommended. # -glx-no-stencil = true; +# glx-no-stencil = true; # deprecated in picom v13 # GLX backend: Avoid rebinding pixmap on window damage. # Probably could improve performance on rapid window content changes, @@ -322,13 +322,13 @@ glx-no-stencil = true; # The opposing option is use-damage # # no-use-damage = false -use-damage = true; +use-damage = false; # Use X Sync fence to sync clients' draw calls, to make sure all draw # calls are finished before picom starts drawing. Needed on nvidia-drivers # with GLX backend for some users. # -# xrender-sync-fence = false +xrender-sync-fence = false; # GLX backend: Use specified GLSL fragment shader for rendering window # contents. Read the man page for a detailed explanation of the interface. diff --git a/polybar/.config/polybar/config b/polybar/.config/polybar/config index bb3ffc3..df7a24b 100644 --- a/polybar/.config/polybar/config +++ b/polybar/.config/polybar/config @@ -190,20 +190,6 @@ label-urgent-padding = 2 ; Separator in between workspaces ; label-separator = | - -[module/mpd] -type = internal/mpd -format-online = - -icon-prev = ๎‚– -icon-stop = ๎‚™ -icon-play = ๎‚š -icon-pause = ๎‚› -icon-next = ๎‚œ - -label-song-maxlen = 25 -label-song-ellipsis = true - [module/xbacklight] type = internal/xbacklight @@ -246,7 +232,7 @@ label-background = ${colors.background-alt} [module/wlan] type = internal/network -interface = wlp59s0 +interface = wlan0 interval = 3.0 format-connected = diff --git a/systemd/.config/environment.d/ssh-agent.conf b/systemd/.config/environment.d/ssh-agent.conf new file mode 100644 index 0000000..cc50f08 --- /dev/null +++ b/systemd/.config/environment.d/ssh-agent.conf @@ -0,0 +1,9 @@ +# SSH agent socket for systemd user services (Emacs daemon, etc.) +# +# Pairs with Arch's shipped `ssh-agent.socket` (ListenStream=%t/ssh-agent.socket +# => $XDG_RUNTIME_DIR/ssh-agent.socket, a stable path). Every user service +# inherits this at manager start, so the Emacs daemon can reach the agent. +# +# NOTE: use ${XDG_RUNTIME_DIR} here, NOT %t โ€” %t is a unit-file specifier and is +# not expanded in environment.d(5). +SSH_AUTH_SOCK="${XDG_RUNTIME_DIR}/ssh-agent.socket" diff --git a/waybar/.config/waybar/config.jsonc b/waybar/.config/waybar/config.jsonc new file mode 100644 index 0000000..3001bb8 --- /dev/null +++ b/waybar/.config/waybar/config.jsonc @@ -0,0 +1,95 @@ +// Waybar config โ€” Hyprland. Mirrors the old polybar layout: +// left = workspaces, center = clock, right = disk/mem/cpu/temp/net/vol/tray/power. +// Icons are Nerd Font (Font Awesome) glyphs written as \u escapes so they survive +// editing reliably; waybar's JSON parser decodes them. +{ + "layer": "top", + "position": "top", + "height": 28, + "spacing": 4, + "margin-top": 5, + "margin-left": 8, + "margin-right": 8, + + "modules-left": ["hyprland/workspaces", "hyprland/window"], + "modules-center": ["clock"], + "modules-right": ["disk", "disk#home", "memory", "cpu", "temperature", "network", "pulseaudio", "tray", "custom/power"], + + "hyprland/workspaces": { + "format": "{id}", + "on-click": "activate", + "sort-by-number": true + }, + + "hyprland/window": { + "max-length": 60, + "separate-outputs": true + }, + + "clock": { + "format": "๏€— {:%Y-%m-%d %a %I:%M %p}", + "tooltip-format": "{calendar}" + }, + + "disk": { + "interval": 30, + "path": "/", + "format": "๏‚  {percentage_used}%", + "tooltip-format": "{used} / {total} on /" + }, + + "disk#home": { + "interval": 30, + "path": "/home", + "format": "๏€• {percentage_used}%", + "tooltip-format": "{used} / {total} on /home" + }, + + "memory": { + "interval": 2, + "format": "๏ˆณ {percentage}%", + "tooltip-format": "{used:0.1f}G / {total:0.1f}G" + }, + + "cpu": { + "interval": 2, + "format": "๏‹› {usage}%" + }, + + // k10temp lives at /sys/class/hwmon/hwmon1 on this box (Ryzen). If the temp + // reads wrong after a kernel update, the hwmon number may have shifted. + "temperature": { + "interval": 5, + "hwmon-path": "/sys/class/hwmon/hwmon1/temp1_input", + "critical-threshold": 80, + "format": "๏‹‰ {temperatureC}ยฐC", + "format-critical": "๏‹‡ {temperatureC}ยฐC" + }, + + "network": { + "interval": 5, + "format-wifi": "๏‡ซ {essid}", + "format-ethernet": "๏ƒจ {ipaddr}", + "format-disconnected": "๏„ง off", + "tooltip-format": "{ifname}: {ipaddr}" + }, + + "pulseaudio": { + "format": "{icon} {volume}%", + "format-muted": "๏€ฆ muted", + "format-icons": { "default": ["๏€ฆ", "๏€ง", "๏€จ"] }, + "on-click": "pavucontrol", + "scroll-step": 5 + }, + + "tray": { + "icon-size": 16, + "spacing": 8 + }, + + "custom/power": { + "format": "๏€‘", + "tooltip": false, + "on-click": "~/.config/hypr/scripts/powermenu.sh" + } +} diff --git a/waybar/.config/waybar/style.css b/waybar/.config/waybar/style.css new file mode 100644 index 0000000..42f6f4b --- /dev/null +++ b/waybar/.config/waybar/style.css @@ -0,0 +1,50 @@ +/* Waybar โ€” Catppuccin Mocha, matching the old polybar look. */ +* { + font-family: "Hack Nerd Font Mono", monospace; + font-size: 13px; + min-height: 0; +} + +window#waybar { + background: rgba(30, 30, 46, 0.85); /* base @ 85% */ + color: #cdd6f4; /* text */ + border-radius: 8px; +} + +#workspaces button { + padding: 0 8px; + margin: 2px 1px; + color: #cdd6f4; + background: transparent; + border-radius: 4px; +} +#workspaces button.active { + color: #1e1e2e; /* base */ + background: #cba6f7; /* mauve */ +} +#workspaces button.urgent { + color: #1e1e2e; + background: #f38ba8; /* red */ +} +#workspaces button:hover { + background: #45475a; /* surface1 */ + color: #cdd6f4; +} + +#window { color: #a6adc8; padding: 0 10px; } /* subtext0 */ + +#clock, +#cpu, #memory, #disk, #temperature, +#network, #pulseaudio, #tray, #custom-power { + padding: 0 10px; +} + +#clock { color: #89b4fa; } /* blue */ +#disk { color: #f9e2af; } /* yellow */ +#memory { color: #fab387; } /* peach */ +#cpu { color: #a6e3a1; } /* green */ +#temperature { color: #94e2d5; } /* teal */ +#temperature.critical { color: #f38ba8; } /* red */ +#network { color: #89dceb; } /* sky */ +#pulseaudio { color: #f5c2e7; } /* pink */ +#custom-power { color: #f38ba8; padding-right: 14px; } /* red */ diff --git a/zsh/.zprofile b/zsh/.zprofile index b38f7d9..1d133de 100644 --- a/zsh/.zprofile +++ b/zsh/.zprofile @@ -2,23 +2,12 @@ # File: ~/.zprofile -SSH_ENV="$HOME/.ssh/environment" - -start_agent() { - echo "Initializing new SSH agent..." - ssh-agent | sed 's/^echo/#echo/' > "${SSH_ENV}" - chmod 600 "${SSH_ENV}" - . "${SSH_ENV}" > /dev/null - ssh-add ~/.ssh/id_rsa - ssh-add ~/.ssh/git_rsa -} - -# Source SSH settings, if applicable -if [ -f "${SSH_ENV}" ]; then - . "${SSH_ENV}" > /dev/null - ps -ef | grep ${SSH_AGENT_PID} | grep ssh-agent > /dev/null || { - start_agent; - } -else - start_agent; -fi +# SSH agent is managed by the systemd user service (ssh-agent.socket), with a +# stable socket at $XDG_RUNTIME_DIR/ssh-agent.socket exported via +# ~/.config/environment.d/ssh-agent.conf (stow pkg `systemd`). All user services +# โ€” including the Emacs daemon โ€” inherit SSH_AUTH_SOCK from there. +# +# Do NOT spawn a shell-local ssh-agent here: setting SSH_AGENT_PID trips the +# shipped unit's `ConditionEnvironment=!SSH_AGENT_PID` and blocks it, which is +# the exact split that left the Emacs daemon unable to reach the agent. +# Load keys via `AddKeysToAgent yes` in ~/.ssh/config, or `ssh-add` on demand. diff --git a/zsh/.zshenv b/zsh/.zshenv index 597153b..12fb77d 100644 --- a/zsh/.zshenv +++ b/zsh/.zshenv @@ -12,5 +12,11 @@ export GOBIN=$GOPATH/bin export XDG_CONFIG_HOME=$HOME/.config export EMACSDIR=$XDG_CONFIG_HOME/emacs +#CUDA +export LD_LIBRARY_PATH=/usr/local/lib/ollama/cuda_v12 + #PATH export PATH=/usr/local/opt/gettext/bin:/usr/local/bin:/usr/local/sbin:/usr/local/go/bin:$HOME/scripts:$HOME/.local/bin:$GOBIN:$HOME/.tfenv/bin:/opt/cuda/lib:$HOME/.local/share/nvim/mason/bin:/opt/cuda/bin/:$XDG_CONFIG_HOME/emacs/bin:$PATH + +#GIT_EDITOR +export GIT_EDITOR="emacsclient -c -a ''" diff --git a/zsh/.zshrc b/zsh/.zshrc index 3407317..6967282 100644 --- a/zsh/.zshrc +++ b/zsh/.zshrc @@ -29,11 +29,9 @@ fi bindkey '^[[A' history-substring-search-up bindkey '^[[B' history-substring-search-down -# source local-specific config +# source local-specific config (machine-specific paths/aliases live here) source "${HOME}/.config/local.zsh" -alias luamake=/home/mike/build/lua-language-server/3rd/luamake/luamake - # hist config # https://www.reddit.com/r/zsh/comments/13jg6ru/nomyzsh_killed_my_history/jkg04xo/ zopts_hist=(