diff --git a/home.org b/home.org index e8ad7ba..6b45389 100644 --- a/home.org +++ b/home.org @@ -318,6 +318,7 @@ We all know what ~git~ does. settings.user.name = "Joe Frikker"; settings.user.email = "joe@redbookcattle.com"; settings.github.user = "joe@redbookcattle.com"; + settings.merge.conflictstyle = "zdiff3"; }; programs.delta = { @@ -344,7 +345,7 @@ The best text editor ever? Heresy! auto-save.after-delay.timeout = 1000; cursorline = true; idle-timeout = 0; - rulers = [100]; + rulers = [120]; text-width = 100; lsp.goto-reference-include-declaration = false; cursor-shape.insert = "bar"; @@ -505,6 +506,7 @@ Then the real lua config: #+BEGIN_SRC lua local config = {} config.default_prog = { '/Users/jfrikker/.nix-profile/bin/zsh', '-l' } + config.font = wezterm.font 'Iosevka Term SS14' config.font_size = 13.0 -- config.font = wezterm.font("JetBrains Mono") config.inactive_pane_hsb = { @@ -699,6 +701,11 @@ Now we'll set up some keybindings: programs.ghostty = { enable = true; package = pkgs.ghostty-bin; + settings = { + adjust-cell-height = "15%"; + font-family = "Iosevka Term SS14"; + font-size = 13; + }; }; } #+END_SRC @@ -832,6 +839,8 @@ Turn off some default settings that I don't find useful. (column-number-mode t) (setopt auto-save-default nil) (setopt create-lockfiles nil) + (setopt enable-recursive-minibuffers t) + (setopt line-spacing 0.15) (setopt mouse-wheel-tilt-scroll t) (setq-default truncate-lines t) @@ -987,7 +996,7 @@ less so? I'm trying this out. This disables visual selections. It's bold, which is why I like it :) #+BEGIN_SRC elisp - ;; (transient-mark-mode -1) + (transient-mark-mode -1) #+END_SRC I use tabs to manage multiple "workspaces". I don't tie a project to a tab or anything; often fixing @@ -1019,152 +1028,229 @@ windows. I place windows in the bottom or on the right mostly depending on how w content to be. #+BEGIN_SRC elisp - (defun jf/window-children (window) - (let ((result nil) - (child (window-child window))) - (while child - (push child result) - (setq child (window-next-sibling child))) - (reverse result))) + (defun jf/window-children (window) + (let ((result nil) + (child (window-child window))) + (while child + (push child result) + (setq child (window-next-sibling child))) + (reverse result))) - (defun jf/enforce-right-side-heights (win) - (let ((slot-heights '((-1 . 20))) - (parent (window-parent win))) - (when parent - (let ((children (jf/window-children parent))) - (when (> (length children) 1) - (cl-loop for child in children - for slot = (window-parameter child 'window-slot) - for height = (alist-get slot slot-heights) - when height do (progn (window-resize child (- height (window-height child))) - (window-preserve-size child nil t)))))))) + (defun jf/enforce-right-side-heights (win) + (let ((slot-heights '((-1 . 20))) + (parent (window-parent win))) + (when parent + (let ((children (jf/window-children parent))) + (when (> (length children) 1) + (cl-loop for child in children + for slot = (window-parameter child 'window-slot) + for height = (alist-get slot slot-heights) + when height do (progn (window-resize child (- height (window-height child))) + (window-preserve-size child nil t)))))))) - (defun jf/enforce-right-side-width (win) - "Resize side window WIN so its frame keeps 120 columns for the rest of the frame." - (let ((width (max 1 (- (frame-width (window-frame win)) 120)))) - (window-resize win (- width (window-width win)) t))) + (defun jf/enforce-right-side-width (win) + "Resize side window WIN so its frame keeps 120 columns for the rest of the frame." + (let ((width (max 1 (- (frame-width (window-frame win)) 120)))) + (window-resize win (- width (window-width win)) t))) - (defun jf/enforce-right-side-widths (frame) - "Re-apply `jf/enforce-right-side-width' to all of FRAME's right-side windows." - (dolist (win (window-list frame 'nomini)) - (when (eq (window-parameter win 'window-side) 'right) - (jf/enforce-right-side-width win)))) + (defun jf/enforce-right-side-widths (frame) + "Re-apply `jf/enforce-right-side-width' to all of FRAME's right-side windows." + (dolist (win (window-list frame 'nomini)) + (when (eq (window-parameter win 'window-side) 'right) + (jf/enforce-right-side-width win)))) - (add-hook 'window-size-change-functions #'jf/enforce-right-side-widths) + (add-hook 'window-size-change-functions #'jf/enforce-right-side-widths) - ;; (require 'perspective) - ;; (setopt persp-mode-prefix-key (kbd "C-x t")) - ;; (setopt persp-show-modestring nil) - ;; (persp-mode) + ;; (require 'perspective) + ;; (setopt persp-mode-prefix-key (kbd "C-x t")) + ;; (setopt persp-show-modestring nil) + ;; (persp-mode) - ;; (defun jf/popper-group-by-owning-perspective () - ;; "Return the name of the perspective that owns the current buffer. + ;; (defun jf/popper-group-by-owning-perspective () + ;; "Return the name of the perspective that owns the current buffer. - ;; Unlike `popper-group-by-perspective', which just returns whichever - ;; perspective happens to be active on the frame right now, this looks - ;; up which perspective's buffer list the popup buffer actually belongs - ;; to. This matters because popper re-groups popups on - ;; `window-configuration-change-hook', which perspective.el triggers - ;; *after* switching the frame's active perspective -- so - ;; `popper-group-by-perspective' ends up filing a popup under the - ;; perspective you just switched *to* rather than the one it came from." - ;; (let ((buf (current-buffer))) - ;; (or (cl-loop for persp being the hash-values of (perspectives-hash (selected-frame)) - ;; if (memq buf (persp-buffers persp)) - ;; return (persp-name persp)) - ;; (persp-current-name)))) + ;; Unlike `popper-group-by-perspective', which just returns whichever + ;; perspective happens to be active on the frame right now, this looks + ;; up which perspective's buffer list the popup buffer actually belongs + ;; to. This matters because popper re-groups popups on + ;; `window-configuration-change-hook', which perspective.el triggers + ;; *after* switching the frame's active perspective -- so + ;; `popper-group-by-perspective' ends up filing a popup under the + ;; perspective you just switched *to* rather than the one it came from." + ;; (let ((buf (current-buffer))) + ;; (or (cl-loop for persp being the hash-values of (perspectives-hash (selected-frame)) + ;; if (memq buf (persp-buffers persp)) + ;; return (persp-name persp)) + ;; (persp-current-name)))) - (setopt popper-reference-buffers - '("\\*Flymake diagnostics .*" - "\\*Embark Export: .*" - "\\*Embark Collect .*" - "\\*xref\\*" - "\\*compilation\\*" - "\\*pnpm:.*" - "\\*sly-mrepl *" - "\\*Messages\\*" - "\\*lispy-message\\*" - "\\*EGLOT connections\\*" - "\\*trace-output\\*" - "\\*occur\\*" - ".*eshell\\*" - "\\*SQL: .*" - "magit: *" - "magit-revision: .*" - "magit-log*" - "\\*Help\\*" - "\\*rustfmt\\*" - "\\*slack: .*" - "\\*forge: .*" - "new-pullreq" - "\\*claude:.*" - "\\*Man .*" - "\\*List .*" - "\\*eldoc\\*")) - (setopt popper-display-control nil) - ;; (setopt popper-group-function 'jf/popper-group-by-owning-perspective) + (setopt popper-reference-buffers + '("\\*Flymake diagnostics .*" + "\\*Embark Export: .*" + "\\*Embark Collect .*" + "\\*xref\\*" + "\\*compilation\\*" + "\\*pnpm:.*" + "\\*sly-mrepl *" + "\\*lispy-message\\*" + "\\*occur\\*" + ".*eshell\\*" + "\\*SQL: .*" + "magit-revision: .*" + "\\*Help\\*" + "\\*rustfmt\\*" + "\\*slack: .*" + "\\*forge: .*" + "new-pullreq" + "\\*claude:.*" + "\\*Man .*" + "\\*List .*" + "\\*eldoc\\*")) + (setopt popper-display-control nil) + ;; (setopt popper-group-function 'jf/popper-group-by-owning-perspective) - (popper-mode) - (popper-echo-mode) + (popper-mode) + (popper-echo-mode) - (bind-keys ("C-q" . popper-toggle) - ("C-;" . popper-cycle)) + (bind-keys ("C-q" . popper-toggle) + ("C-;" . popper-cycle)) - (setq display-buffer-alist - '(((or "\\*Flymake diagnostics .*" - "\\*Embark Export: .*" - "\\*Embark Collect .*" - "\\*xref\\*" - "\\*compilation\\*" - "\\*pnpm:.*" - "\\*sly-mrepl *" - "\\*Messages\\*" - "\\*lispy-message\\*" - "\\*EGLOT connections\\*" - "\\*trace-output\\*" - "\\*occur\\*" - ".*eshell\\*" - "\\*SQL: .*") - (display-buffer-in-side-window) - (side . bottom) - (slot . 0) - (window-height . 0.33) - (window-parameters (no-delete-other-windows . t) - (no-other-window . t))) - ((or "magit: *" - "magit-revision: .*" - "magit-log*" - "\\*Help\\*" - "\\*rustfmt\\*" - "\\*slack: .*" - "\\*forge: .*" - "new-pullreq" - "\\*claude:.*" - "\\*Man .*" - "\\*List .*") - (display-buffer-in-side-window) - (side . right) - (slot . 0) - (window-width . jf/enforce-right-side-width) - (window-height . jf/enforce-right-side-heights) - (preserve-size . (nil . nil)) - (window-parameters (no-delete-other-windows . t) - (no-other-window . t))) - ((or "\\*Embark Actions\\*" - "\\*eldoc\\*") - (display-buffer-in-side-window) - (side . right) - (slot . -1) - (window-width . jf/enforce-right-side-width) - (window-height . jf/enforce-right-side-heights) - (preserve-size . (nil . t)) - (window-parameters (no-delete-other-windows . t) - (no-other-window . t))))) + (defvar jf/fullscreen-popup--param 'jf/fullscreen-saved-configuration + "Key used to stash the window configuration a fullscreen popup replaced. +Stored per-tab when `tab-bar-mode' is active, otherwise as a plain frame +parameter; see `jf/tab-or-frame-parameter'.") - (setopt window-persistent-parameters - (cl-list* '(no-delete-other-windows . writable) - '(no-other-window . writable) - window-persistent-parameters)) + (defvar-local jf/fullscreen-popup-p nil + "Non-nil in a buffer currently being displayed as a fullscreen popup.") + + (defun jf/current-tab-cell (&optional frame) + "Return FRAME's current tab's raw data cell, or nil without `tab-bar-mode'." + (and (bound-and-true-p tab-bar-mode) + (assq 'current-tab (tab-bar-tabs frame)))) + + (defun jf/tab-or-frame-parameter (parameter &optional frame) + "Like `frame-parameter', but scoped to FRAME's selected tab when tabs are in use. + +A plain frame parameter is shared by every tab on that frame, which is wrong +for state like `jf/fullscreen-popup--param': switching tabs swaps in an +entirely different window layout, so \"the layout to restore\" has to travel +with the tab, not the frame." + (if-let ((tab (jf/current-tab-cell frame))) + (alist-get parameter tab) + (frame-parameter frame parameter))) + + (defun jf/set-tab-or-frame-parameter (parameter value &optional frame) + "Set PARAMETER to VALUE, scoped like `jf/tab-or-frame-parameter'." + (if-let ((tab (jf/current-tab-cell frame))) + (let ((cell (assq parameter tab))) + (if cell + (setcdr cell value) + (setcdr tab (cons (cons parameter value) (cdr tab))))) + (set-frame-parameter frame parameter value))) + + (defun jf/display-buffer-fullscreen (buffer alist) + "Display BUFFER, deleting other windows, saving the prior layout. + +Intended for use in `display-buffer-alist' for popups (e.g. Magit +status/log) that should take over the frame while displayed, but +restore the previous window configuration once closed via either +`q' or `popper-toggle' -- both end up calling `quit-window', which +is where the restore actually happens; see +`jf/quit-window-restore-fullscreen'." + (unless (jf/tab-or-frame-parameter jf/fullscreen-popup--param) + (jf/set-tab-or-frame-parameter jf/fullscreen-popup--param + (current-window-configuration))) + (when-let ((window (or (display-buffer-reuse-window buffer alist) + (display-buffer-same-window buffer alist) + (display-buffer-pop-up-window buffer alist) + (display-buffer-use-some-window buffer alist)))) + (let ((ignore-window-parameters t)) + (delete-other-windows window)) + (with-current-buffer buffer + (setq jf/fullscreen-popup-p t)) + window)) + + (defun jf/quit-window-restore-fullscreen (orig-fn &optional kill window) + "Restore the saved window configuration after quitting a fullscreen popup. + +Advice around `quit-window' so both `q' (which Magit and other +special-mode buffers bind to buffer-quitting commands that call +`quit-window') and Popper's close/toggle commands (which also call +`quit-window' directly) trigger the restore. Only restores once the +last fullscreen popup on the tab (or frame, without `tab-bar-mode') +has closed, so opening one fullscreen popup from within another +falls back to the outer one first." + (let* ((window (or window (selected-window))) + (was-fullscreen (buffer-local-value 'jf/fullscreen-popup-p + (window-buffer window))) + (frame (window-frame window))) + (funcall orig-fn kill window) + (when (and was-fullscreen + (not (and (window-live-p window) + (buffer-local-value 'jf/fullscreen-popup-p + (window-buffer window)))) + (jf/tab-or-frame-parameter jf/fullscreen-popup--param frame)) + (let ((conf (jf/tab-or-frame-parameter jf/fullscreen-popup--param frame))) + (jf/set-tab-or-frame-parameter jf/fullscreen-popup--param nil frame) + (set-window-configuration conf))))) + + (advice-add 'quit-window :around #'jf/quit-window-restore-fullscreen) + + (setq display-buffer-alist + '(((or "magit: *" + "magit-log*" + "\\*Messages\\*" + "\\*trace-output\\*" + "\\*EGLOT connections\\*") + (jf/display-buffer-fullscreen)) + ((or "\\*Flymake diagnostics .*" + "\\*Embark Export: .*" + "\\*Embark Collect .*" + "\\*xref\\*" + "\\*compilation\\*" + "\\*pnpm:.*" + "\\*sly-mrepl *" + "\\*lispy-message\\*" + "\\*occur\\*" + ".*eshell\\*" + "\\*SQL: .*") + (display-buffer-in-side-window) + (side . bottom) + (slot . 0) + (window-height . 0.33) + (window-parameters (no-delete-other-windows . t) + (no-other-window . t))) + ((or "magit-revision: .*" + "\\*Help\\*" + "\\*rustfmt\\*" + "\\*slack: .*" + "\\*forge: .*" + "new-pullreq" + "\\*claude:.*" + "\\*Man .*" + "\\*List .*") + (display-buffer-in-side-window) + (side . right) + (slot . 0) + (window-width . jf/enforce-right-side-width) + (window-height . jf/enforce-right-side-heights) + (preserve-size . (nil . nil)) + (window-parameters (no-delete-other-windows . t) + (no-other-window . t))) + ((or "\\*Embark Actions\\*" + "\\*eldoc\\*") + (display-buffer-in-side-window) + (side . right) + (slot . -1) + (window-width . jf/enforce-right-side-width) + (window-height . jf/enforce-right-side-heights) + (preserve-size . (nil . t)) + (window-parameters (no-delete-other-windows . t) + (no-other-window . t))))) + + (setopt window-persistent-parameters + (cl-list* '(no-delete-other-windows . writable) + '(no-other-window . writable) + window-persistent-parameters)) #+END_SRC @@ -1497,6 +1583,7 @@ I don't like UI elements that insert fake text into the file. They mess up the s (setopt eglot-ignored-server-capabilities '(:inlayHintProvider :semanticTokensProvider)) (add-hook 'eglot-managed-mode-hook (lambda () (eglot-inlay-hints-mode -1)) nil t) (setopt eglot-code-action-indications nil) + (setopt eglot-events-buffer-config '(:size 300000 :format full)) #+END_SRC Set up a few useful eglot keys. @@ -2232,7 +2319,7 @@ I like Catppuccin Frappe as my theme. Let's use it in as many places as we can. ;; (set-face-attribute 'default nil :font "JetBrainsMono Nerd Font" :height 130) ;; (set-face-attribute 'fixed-pitch nil :font "JetBrainsMono Nerd Font" :height 130) - (set-face-attribute 'default nil :font "Iosevka Term SS14" :height 130 :width 'expanded) - (set-face-attribute 'fixed-pitch nil :font "Iosevka Term SS14" :height 130 :width 'expanded) + (set-face-attribute 'default nil :font "Iosevka Term SS14" :height 130) + (set-face-attribute 'fixed-pitch nil :font "Iosevka Term SS14" :height 130) (set-face-attribute 'variable-pitch nil :font "Iosevka Etoile" :height 130) #+END_SRC