11 Commits

Author SHA1 Message Date
Joe Frikker c9394673db A little more prose 2026-09-09 09:48:50 -04:00
Joe Frikker 48ed1287d7 A little prose 2026-09-04 17:07:17 -04:00
Joe Frikker 9713bb6ae2 Removing perspective 2026-09-04 16:53:46 -04:00
Joe Frikker afdbf7cfa2 buffer-terminator 2026-09-04 16:41:54 -04:00
Joe Frikker 9e9d2bbfcc No more right side window 2026-09-04 14:36:52 -04:00
Joe Frikker 3682c1ad10 flake update 2026-08-19 21:32:09 -04:00
Joe Frikker 5f639e747d kitty? 2026-08-19 17:39:50 -04:00
Joe Frikker 3159d20e6d wip 2026-08-06 16:22:57 -04:00
Joe Frikker e6240591c9 font etc 2026-07-24 17:08:51 -04:00
Joe Frikker 5f96f98158 wip 2026-07-15 15:21:15 -04:00
Joe Frikker a1abf5b4a1 wip 2026-07-10 00:11:54 -04:00
2 changed files with 464 additions and 281 deletions
Generated
+17 -35
View File
@@ -2,40 +2,22 @@
"nodes": { "nodes": {
"claude-code": { "claude-code": {
"inputs": { "inputs": {
"flake-utils": "flake-utils",
"nixpkgs": [ "nixpkgs": [
"nixpkgs" "nixpkgs"
] ],
},
"locked": {
"lastModified": 1783380155,
"narHash": "sha256-SwUwKaLrZ+c5y4GoZHKBf1nUsDHVsIUtn2CFloZrV2A=",
"owner": "sadjow",
"repo": "claude-code-nix",
"rev": "25d979d1a39d0acdbcb1b8d0b9d83ffdd10b5f43",
"type": "github"
},
"original": {
"owner": "sadjow",
"repo": "claude-code-nix",
"type": "github"
}
},
"flake-utils": {
"inputs": {
"systems": "systems" "systems": "systems"
}, },
"locked": { "locked": {
"lastModified": 1731533236, "lastModified": 1787169825,
"narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=", "narHash": "sha256-3MmWHAzeoFHfwjUCQC01olBN+MC4xoSuR7D0bpPr+EE=",
"owner": "numtide", "owner": "sadjow",
"repo": "flake-utils", "repo": "claude-code-nix",
"rev": "11707dc2f618dd54ca8739b309ec4fc024de578b", "rev": "f575914388682670df73e80c9caf82063b659699",
"type": "github" "type": "github"
}, },
"original": { "original": {
"owner": "numtide", "owner": "sadjow",
"repo": "flake-utils", "repo": "claude-code-nix",
"type": "github" "type": "github"
} }
}, },
@@ -46,11 +28,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1783436070, "lastModified": 1787176219,
"narHash": "sha256-F80z1JoiJgZyTT5D+3siLOVzqmCEphLR7t0Ym/I2CLI=", "narHash": "sha256-djoRr6jBpe35q/0JwAvXpFXg1Ktf+X54NU2RLR7wnHw=",
"owner": "nix-community", "owner": "nix-community",
"repo": "home-manager", "repo": "home-manager",
"rev": "f09af49406ffad37acb6538d3207189a1a1e0b7e", "rev": "c53d643b3737e2fcd04e6cb3b3580ef50b2087a0",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -67,11 +49,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1783414108, "lastModified": 1786852476,
"narHash": "sha256-RY8e+gR2/DhXsYDxGDL6Hhe9+POD9u4+llwxMBqMQDs=", "narHash": "sha256-IM5CYtf86W4w8eUPpKcY/LpdHElmVBtJhaKnoTKxZEA=",
"owner": "nix-community", "owner": "nix-community",
"repo": "nix-index-database", "repo": "nix-index-database",
"rev": "96d6de10eb281b98f5cfcd1841394c03da5df77c", "rev": "c7962dc97b45129df8d751bedaf37beb5a17706e",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -82,11 +64,11 @@
}, },
"nixpkgs": { "nixpkgs": {
"locked": { "locked": {
"lastModified": 1783148766, "lastModified": 1787101114,
"narHash": "sha256-uslt2pqShTIXDdAHRHv2QkYLsVdY8Oqwz0EA48/RSM8=", "narHash": "sha256-gwrPcFf/rDjHPaVflbDZ040ZDmBTRj/7+s8ZmE2SaIM=",
"owner": "nixos", "owner": "nixos",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "a50de1b7d8a586adc18d2395c19de7d6058e6030", "rev": "b18a4b905f8d028dc4476412e6d6891728695379",
"type": "github" "type": "github"
}, },
"original": { "original": {
+447 -246
View File
@@ -188,7 +188,7 @@ These programs require a full desktop environment:
nerd-fonts.symbols-only nerd-fonts.symbols-only
(iosevka-bin.override { variant = "Aile"; }) (iosevka-bin.override { variant = "Aile"; })
(iosevka-bin.override { variant = "Etoile"; }) (iosevka-bin.override { variant = "Etoile"; })
(iosevka-bin.override { variant = "SGr-IosevkaTerm"; }) (iosevka-bin.override { variant = "SGr-IosevkaTermSS14"; })
keymapp keymapp
proton-pass proton-pass
wireshark wireshark
@@ -201,7 +201,13 @@ These programs require a full desktop environment:
{ {
home.packages = with pkgs; [ home.packages = with pkgs; [
linear linear
slack (slack.overrideAttrs {
version = "4.50.143";
src = pkgs.fetchurl {
url = "https://downloads.slack-edge.com/desktop-releases/mac/arm64/4.50.143/Slack-4.50.143-macOS.dmg";
hash = "sha256-f5oYi8NPKXWpDcowFYMUjptbQs4V9hK2bm1TuaQeJn0=";
};
})
teams teams
]; ];
} }
@@ -312,6 +318,7 @@ We all know what ~git~ does.
settings.user.name = "Joe Frikker"; settings.user.name = "Joe Frikker";
settings.user.email = "joe@redbookcattle.com"; settings.user.email = "joe@redbookcattle.com";
settings.github.user = "joe@redbookcattle.com"; settings.github.user = "joe@redbookcattle.com";
settings.merge.conflictstyle = "zdiff3";
}; };
programs.delta = { programs.delta = {
@@ -338,7 +345,7 @@ The best text editor ever? Heresy!
auto-save.after-delay.timeout = 1000; auto-save.after-delay.timeout = 1000;
cursorline = true; cursorline = true;
idle-timeout = 0; idle-timeout = 0;
rulers = [100]; rulers = [120];
text-width = 100; text-width = 100;
lsp.goto-reference-include-declaration = false; lsp.goto-reference-include-declaration = false;
cursor-shape.insert = "bar"; cursor-shape.insert = "bar";
@@ -499,6 +506,7 @@ Then the real lua config:
#+BEGIN_SRC lua #+BEGIN_SRC lua
local config = {} local config = {}
config.default_prog = { '/Users/jfrikker/.nix-profile/bin/zsh', '-l' } config.default_prog = { '/Users/jfrikker/.nix-profile/bin/zsh', '-l' }
config.font = wezterm.font 'Iosevka Term SS14'
config.font_size = 13.0 config.font_size = 13.0
-- config.font = wezterm.font("JetBrains Mono") -- config.font = wezterm.font("JetBrains Mono")
config.inactive_pane_hsb = { config.inactive_pane_hsb = {
@@ -686,6 +694,32 @@ Now we'll set up some keybindings:
end end
#+END_SRC #+END_SRC
** Kitty
#+BEGIN_SRC nix :tangle target/desktop/kitty.nix
{pkgs, ...}: {
programs.kitty = {
enable = true;
font = {
name = "Iosevka Term SS14";
package = pkgs.iosevka-bin.override { variant = "SGr-IosevkaTermSS14"; };
size = 13;
};
themeFile = "Catppuccin-Frappe";
keybindings = {
"ctrl+1" = "goto_tab 1";
"ctrl+2" = "goto_tab 2";
"ctrl+3" = "goto_tab 3";
"ctrl+4" = "goto_tab 4";
"ctrl+5" = "goto_tab 5";
"ctrl+6" = "goto_tab 6";
"ctrl+7" = "goto_tab 7";
"ctrl+8" = "goto_tab 8";
"ctrl+9" = "goto_tab 9";
};
};
}
#+END_SRC
** Ghostty ** Ghostty
#+BEGIN_SRC nix :tangle target/desktop/ghostty.nix #+BEGIN_SRC nix :tangle target/desktop/ghostty.nix
@@ -693,6 +727,11 @@ Now we'll set up some keybindings:
programs.ghostty = { programs.ghostty = {
enable = true; enable = true;
package = pkgs.ghostty-bin; package = pkgs.ghostty-bin;
settings = {
adjust-cell-height = "15%";
font-family = "Iosevka Term SS14";
font-size = 13;
};
}; };
} }
#+END_SRC #+END_SRC
@@ -795,7 +834,6 @@ These are just some general settings that apply everywhere. First, a few package
free-keys free-keys
ligature ligature
mixed-pitch mixed-pitch
perspective
popper popper
]; ];
extraConfig = builtins.readFile ./emacs-global.el; extraConfig = builtins.readFile ./emacs-global.el;
@@ -806,31 +844,77 @@ These are just some general settings that apply everywhere. First, a few package
Turn off some default settings that I don't find useful. Turn off some default settings that I don't find useful.
#+BEGIN_SRC elisp #+BEGIN_SRC elisp
(setopt inhibit-startup-screen t)
(setopt initial-scratch-message nil)
(setopt sentence-end-double-space nil)
(menu-bar-mode -1)
(scroll-bar-mode -1)
(tool-bar-mode -1)
(setopt make-backup-files nil)
(setopt split-width-threshold 200)
(setopt split-height-threshold nil)
(setopt display-buffer-base-action
'((display-buffer-reuse-window display-buffer-same-window
display-buffer-in-previous-window
display-buffer-use-some-window)))
(setopt view-read-only t)
(setopt save-interprogram-paste-before-kill t) (setopt save-interprogram-paste-before-kill t)
(setopt kill-whole-line t) (setopt enable-recursive-minibuffers t)
(delete-selection-mode t) (setopt line-spacing 0.15)
(column-number-mode t)
(setopt auto-save-default nil)
(setopt create-lockfiles nil)
(setopt mouse-wheel-tilt-scroll t) (setopt mouse-wheel-tilt-scroll t)
(setq-default truncate-lines t) (setq-default truncate-lines t)
(setopt tab-bar-show nil)
(tab-bar-mode)
#+END_SRC #+END_SRC
Don't show the welcome screen, and keep the scratch buffer empty by default. These are not useful
after you've started emacs more than a few times.
#+begin_src elisp
(setopt inhibit-startup-screen t)
(setopt initial-scratch-message nil)
#+end_src
Turn off all the ugly graphical crap.
#+begin_src elisp
(menu-bar-mode -1)
(scroll-bar-mode -1)
(tool-bar-mode -1)
#+end_src
I don't find emacs's backup files useful, and they seem to litter my directories. I could maybe see
a use if I wasn't using git. But, git is so easy to use, that I pretty much use it everywhere. I
don't need a poor man's local history.
Also, why do I have to set so many variables just to get emacs to stop putting extra files
everywhere?
#+begin_src elisp
(setopt make-backup-files nil)
(setopt create-lockfiles nil)
(setopt auto-save-default nil)
#+end_src
Turn on ~view-mode~ automatically when the buffer is read-only. This just helps out with navigation
a bit. I almost want to open files read-only by default, just so I can use ~view-mode~ (maybe with
some other keybindings) all the time. But, I think one more invisible flag to manage is a bit much.
#+begin_src elisp
(setopt view-read-only t)
#+end_src
I don't really do anything with sentences. But, I also never put two spaces after a period. So, at
least this setting is correct.
#+begin_src elisp
(setopt sentence-end-double-space nil)
#+end_src
I kill whole lines *way* more than partial lines. If the cursor is at the front of a line, this will
just kill the whole line instead of requiring two ~C-k C-k~ presses to make it happen. I'm not sure
when I'd ever want it to kill the line *without* the trailing newline, but I guess the one time ever
that I do, I'll have to press two more keys :(
#+begin_src elisp
(setopt kill-whole-line t)
#+end_src
Show column numbers in the modeline. Now that I think about it, I'm not sure why I want this. I
guess I could try turning it off someday?
#+begin_src elisp
(column-number-mode t)
#+end_src
Make sure which-key mode is always on. The on-the-fly keymap help it gives is indespensable. Make sure which-key mode is always on. The on-the-fly keymap help it gives is indespensable.
#+BEGIN_SRC elisp #+BEGIN_SRC elisp
@@ -859,23 +943,13 @@ already indented, then try to complete the thing at point." Recommended by [[htt
#+END_SRC #+END_SRC
Set the cursor to be a bar. I'm not sure what the benefit would be of a block cursor, since the Set the cursor to be a bar. I'm not sure what the benefit would be of a block cursor, since the
current character isn't really "selected" like it would be in Helix. When I had God mode set up, I current character isn't really "selected" like it would be in Helix. I switch this to a box when in
switched to a block cursor during normal mode, just because I was so used to it from Helix and god mode / read-only buffers, like vim would.
Vim. Now, I don't think there's really a need to ever switch.
#+BEGIN_SRC elisp #+BEGIN_SRC elisp
(setq-default cursor-type 'bar) (setq-default cursor-type 'bar)
#+END_SRC #+END_SRC
Emacs is supposed to be all about automation (maybe?). There's basically never a case where I don't
want changes I've made to be immediately saved to disk. So let's have Emacs do that. There's still a
fairly long (~5 sec) delay before changes are saved, which is kind of annoying. Maybe I'll look into
that at some point?
#+BEGIN_SRC elisp
; (auto-save-visited-mode)
#+END_SRC
Repeat-mode takes care of eliminating some annoying duplicate keypresses. I mostly use repeat-mode Repeat-mode takes care of eliminating some annoying duplicate keypresses. I mostly use repeat-mode
for two-character commands that need to be repeated; ~devil~ also has some single-key-with-modifier for two-character commands that need to be repeated; ~devil~ also has some single-key-with-modifier
repeats set up that only apply in that mode. repeats set up that only apply in that mode.
@@ -954,13 +1028,17 @@ Set up a few project- / workspace-related key bindings.
#+BEGIN_SRC elisp #+BEGIN_SRC elisp
(bind-keys ("s-f" . project-find-file) (bind-keys ("s-f" . project-find-file)
("s-F" . project-switch-project) ("s-F" . project-switch-project)
("s-s" . persp-switch)) ;; ("s-s" . persp-switch)
)
;; (with-eval-after-load 'tab-bar (with-eval-after-load 'tab-bar
;; (bind-keys :map tab-bar-mode-map (bind-keys :map tab-bar-mode-map
;; ("s-s" . tab-bar-switch-to-tab))) ("s-s" . tab-bar-switch-to-tab)))
#+END_SRC #+END_SRC
#+RESULTS:
: tab-bar-switch-to-tab
Don't run a server. I'm not using this, I can always turn it back on if I need to. Don't run a server. I'm not using this, I can always turn it back on if I need to.
#+BEGIN_SRC elisp #+BEGIN_SRC elisp
@@ -977,7 +1055,7 @@ less so?
I'm trying this out. This disables visual selections. It's bold, which is why I like it :) I'm trying this out. This disables visual selections. It's bold, which is why I like it :)
#+BEGIN_SRC elisp #+BEGIN_SRC elisp
;; (transient-mark-mode -1) (transient-mark-mode -1)
#+END_SRC #+END_SRC
I use tabs to manage multiple "workspaces". I don't tie a project to a tab or anything; often fixing I use tabs to manage multiple "workspaces". I don't tie a project to a tab or anything; often fixing
@@ -1009,120 +1087,227 @@ windows. I place windows in the bottom or on the right mostly depending on how w
content to be. content to be.
#+BEGIN_SRC elisp #+BEGIN_SRC elisp
(defun jf/window-children (window) (defun jf/window-children (window)
(let ((result nil) (let ((result nil)
(child (window-child window))) (child (window-child window)))
(while child (while child
(push child result) (push child result)
(setq child (window-next-sibling child))) (setq child (window-next-sibling child)))
(reverse result))) (reverse result)))
(defun jf/enforce-right-side-heights (win) (defun jf/window-main-root (&optional frame)
(let ((slot-heights '((-1 . 20))) "Return FRAME's main (non-side) window or window subtree."
(parent (window-parent win))) (let* ((root (frame-root-window (or frame (selected-frame))))
(when parent (children (jf/window-children root)))
(let ((children (jf/window-children parent))) (if (seq-some (lambda (w) (window-parameter w 'window-side)) children)
(when (> (length children) 1) (seq-find (lambda (w) (not (window-parameter w 'window-side))) children)
(cl-loop for child in children root)))
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))))))))
(require 'perspective) (defun jf/window-leaves (window)
(setopt persp-mode-prefix-key (kbd "C-x t")) "Return the live leaf windows in WINDOW's subtree."
(setopt persp-show-modestring nil) (if (window-live-p window)
(persp-mode) (list window)
(mapcan #'jf/window-leaves (jf/window-children window))))
(setopt popper-reference-buffers (defun jf/topright-window (windows)
'("\\*Flymake diagnostics .*" "Return whichever of WINDOWS sits furthest up, then furthest right."
"\\*Embark Export: .*" (car (sort (copy-sequence windows)
"\\*Embark Collect .*" (lambda (a b)
"\\*xref\\*" (let ((top-a (nth 1 (window-edges a)))
"\\*compilation\\*" (top-b (nth 1 (window-edges b))))
"\\*sly-mrepl *" (if (= top-a top-b)
"\\*Messages\\*" (> (nth 0 (window-edges a)) (nth 0 (window-edges b)))
"\\*lispy-message\\*" (< top-a top-b)))))))
"\\*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 'popper-group-by-perspective)
(popper-mode) (defun jf/display-buffer-right (buffer alist)
(popper-echo-mode) "Display BUFFER on the right of the main editing area.
(bind-keys ("C-q" . popper-toggle) Applies three rules, based on the shape of the frame's non-side windows:
("C-;" . popper-cycle)) 1. One window -> split it and show BUFFER in the new right window.
2. Two windows side-by-side -> show BUFFER in the right one. If the
right window is selected, swap the two windows first (keeping
focus on the buffer that was active) so BUFFER doesn't evict it.
3. Any other layout -> show BUFFER in the upper-rightmost window."
(let ((main (jf/window-main-root)))
(cond
((window-live-p main)
(let* ((new (split-window main nil 'right))
(width (max 1 (- (frame-width) 120)))
(delta (window-resizable new (- width (window-width new)) t)))
(window-resize new delta t)
(window--display-buffer buffer new 'window alist)))
((and (window-left-child main)
(= (length (jf/window-children main)) 2)
(seq-every-p #'window-live-p (jf/window-children main)))
(let* ((left (window-left-child main))
(right (window-next-sibling left)))
(when (eq (selected-window) right)
(window-swap-states left right)
(select-window left))
(window--display-buffer buffer right 'reuse alist)))
(t
(window--display-buffer buffer (jf/topright-window (jf/window-leaves main)) 'reuse alist)))))
(setq display-buffer-alist
'(((or "\\*Flymake diagnostics .*"
"\\*Embark Export: .*"
"\\*Embark Collect .*"
"\\*xref\\*"
"\\*compilation\\*"
"\\*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 . 93)
(window-height . jf/enforce-right-side-heights)
(preserve-size . (t . 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 . 93)
(window-height . jf/enforce-right-side-heights)
(preserve-size . (t . t))
(window-parameters (no-delete-other-windows . t)
(no-other-window . t)))))
(setopt window-persistent-parameters (setopt popper-reference-buffers
(cl-list* '(no-delete-other-windows . writable) '("\\*Flymake diagnostics .*"
'(no-other-window . writable) "\\*Embark Export: .*"
window-persistent-parameters)) "\\*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)
(popper-mode)
(popper-echo-mode)
(bind-keys ("C-q" . popper-toggle)
("C-;" . popper-cycle))
(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'.")
(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)
(setopt split-width-threshold 200)
(setopt split-height-threshold nil)
(setopt display-buffer-base-action
'((display-buffer-reuse-window display-buffer-same-window
display-buffer-in-previous-window
display-buffer-use-some-window)))
(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 .*"
"\\*Embark Actions\\*"
"\\*eldoc\\*")
(jf/display-buffer-right))))
(setopt window-persistent-parameters
(cl-list* '(no-delete-other-windows . writable)
'(no-other-window . writable)
window-persistent-parameters))
#+END_SRC #+END_SRC
@@ -1185,7 +1370,7 @@ its own devil-mode-only repeat maps that don't interfere when using normal modif
(bind-keys ("<escape>" . (lambda () (interactive) (god-mode-all 1)))) (bind-keys ("<escape>" . (lambda () (interactive) (god-mode-all 1))))
(defun my-god-mode-update-cursor-type () (defun my-god-mode-update-cursor-type ()
(setq cursor-type (cond (setq cursor-type (cond
(org-present-mode nil) ((and (featurep 'org-present) org-present-mode) nil)
((or (and (featurep 'god-mode) god-local-mode) buffer-read-only) 'box) ((or (and (featurep 'god-mode) god-local-mode) buffer-read-only) 'box)
(t 'bar)))) (t 'bar))))
@@ -1214,11 +1399,15 @@ his article.
(bind-keys (bind-keys
("C-j" . avy-goto-char-timer) ("C-j" . avy-goto-char-timer)
("M-j" . avy-goto-char-timer-embark) ("M-j" . avy-goto-char-timer-embark)
("C-." . embark-act) ("C-." . embark-act))
:map lispy-mode-map
("C-j" . avy-goto-char-timer) (with-eval-after-load 'lispy
:map org-mode-map (bind-keys :map lispy-mode-map
("C-j" . avy-goto-char-timer)) ("C-j" . avy-goto-char-timer)))
(with-eval-after-load 'org
(bind-keys :map org-mode-map
("C-j" . avy-goto-char-timer)))
#+END_SRC #+END_SRC
Just "silently" wrap when searching at the bottom of a document. Just "silently" wrap when searching at the bottom of a document.
@@ -1261,7 +1450,7 @@ Just "silently" wrap when searching at the bottom of a document.
programs.emacs = { programs.emacs = {
enable = true; enable = true;
extraPackages = epkgs: with epkgs; [ extraPackages = epkgs: with epkgs; [
# bufferlo buffer-terminator
]; ];
extraConfig = builtins.readFile ./emacs-workflow.el; extraConfig = builtins.readFile ./emacs-workflow.el;
}; };
@@ -1269,24 +1458,10 @@ Just "silently" wrap when searching at the bottom of a document.
#+END_SRC #+END_SRC
#+BEGIN_SRC elisp #+BEGIN_SRC elisp
;; (bufferlo-mode) (buffer-terminator-mode 1)
;; (setopt bufferlo-include-buried-buffers nil)
;; (with-eval-after-load 'bufferlo
;; (setq mode-line-misc-info
;; (assq-delete-all 'bufferlo-mode mode-line-misc-info)))
;; (defun my/bury-or-kill-buffer ()
;; (interactive)
;; (bury-buffer)
;; (bufferlo-kill-orphan-buffers))
(bind-keys (bind-keys
("s-b" . consult-buffer) ("s-b" . consult-project-buffer))
;; ("C-x t 0" . bufferlo-tab-close-kill-buffers)
;; ("C-x k" . my/bury-or-kill-buffer)
)
#+END_SRC #+END_SRC
** Language Support ** Language Support
@@ -1313,6 +1488,7 @@ Just "silently" wrap when searching at the bottom of a document.
# lispyville # lispyville
lua-mode lua-mode
nix-mode nix-mode
pnpm-mode
prisma-ts-mode prisma-ts-mode
rust-mode rust-mode
sly sly
@@ -1450,6 +1626,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)) (setopt eglot-ignored-server-capabilities '(:inlayHintProvider :semanticTokensProvider))
(add-hook 'eglot-managed-mode-hook (lambda () (eglot-inlay-hints-mode -1)) nil t) (add-hook 'eglot-managed-mode-hook (lambda () (eglot-inlay-hints-mode -1)) nil t)
(setopt eglot-code-action-indications nil) (setopt eglot-code-action-indications nil)
(setopt eglot-events-buffer-config '(:size 300000 :format full))
#+END_SRC #+END_SRC
Set up a few useful eglot keys. Set up a few useful eglot keys.
@@ -1572,6 +1749,9 @@ for completion. That makes it really annoying to use; don't use yasnippet with e
(with-eval-after-load 'typescript-ts-mode (with-eval-after-load 'typescript-ts-mode
(define-key typescript-ts-mode-map (kbd "C-c '") #'my/edit-indirect-tagged-template-at-point) (define-key typescript-ts-mode-map (kbd "C-c '") #'my/edit-indirect-tagged-template-at-point)
(define-key tsx-ts-mode-map (kbd "C-c '") #'my/edit-indirect-tagged-template-at-point)) (define-key tsx-ts-mode-map (kbd "C-c '") #'my/edit-indirect-tagged-template-at-point))
(with-eval-after-load 'eglot
(add-to-list 'eglot-server-programs '((prisma-ts-mode) "prisma-language-server" "--stdio")))
#+END_SRC #+END_SRC
*** Java *** Java
@@ -1760,7 +1940,6 @@ for completion. That makes it really annoying to use; don't use yasnippet with e
(eval-when-compile (eval-when-compile
(require 'consult)) (require 'consult))
(require 'perspective)
(with-eval-after-load 'consult (with-eval-after-load 'consult
(consult-customize (consult-customize
consult-theme :preview-key '(:debounce 0.2 any) consult-theme :preview-key '(:debounce 0.2 any)
@@ -1771,9 +1950,7 @@ for completion. That makes it really annoying to use; don't use yasnippet with e
consult-source-buffer consult-source-buffer
;; :preview-key "M-." ;; :preview-key "M-."
consult-source-project-recent-file consult-source-project-recent-file
:preview-key '(:debounce 0.4 any)) :preview-key '(:debounce 0.4 any)))
(consult-customize consult-source-buffer :hidden t :default nil)
(add-to-list 'consult-buffer-sources persp-consult-source))
(setopt consult-narrow-key "<") ;; "C-+" (setopt consult-narrow-key "<") ;; "C-+"
@@ -1823,6 +2000,8 @@ for completion. That makes it really annoying to use; don't use yasnippet with e
("C-c C" . org-capture) ("C-c C" . org-capture)
("C-c l" . org-id-store-link)) ("C-c l" . org-id-store-link))
(setopt org-babel-load-languages '((emacs-lisp . t) (sql . t)))
(setopt org-confirm-babel-evaluate nil)
(add-hook 'org-mode-hook 'visual-line-mode) (add-hook 'org-mode-hook 'visual-line-mode)
(setopt org-link-keep-stored-after-insertion t (setopt org-link-keep-stored-after-insertion t
org-capture-templates org-capture-templates
@@ -1857,77 +2036,78 @@ for completion. That makes it really annoying to use; don't use yasnippet with e
(set-face-attribute 'org-level-7 nil :font "Iosevka Aile") (set-face-attribute 'org-level-7 nil :font "Iosevka Aile")
(set-face-attribute 'org-level-8 nil :font "Iosevka Aile") (set-face-attribute 'org-level-8 nil :font "Iosevka Aile")
(require 'org-present)
(require 'face-remap)
(require 'visual-fill-column)
(defvar-local my/org-present-face-remapping-cookies nil) (defvar-local my/org-present-face-remapping-cookies nil)
(defun my/org-present-start () (with-eval-after-load 'org-present
(setq-local my/org-present-face-remapping-cookies nil) (require 'face-remap)
;; Tweak font sizes (require 'visual-fill-column)
(dolist (face '((default :height 2.0)
(header-line :height 4.0 :background "#303446")
(org-document-title :height 1.75)
(org-code :height 2.0)
(org-verbatim :height 2.0)
(org-block :height 1.25)
(org-block-begin-line :height 0.7)
(org-level-1 :height 3.0)
(org-level-2 :height 3.0)
(org-level-3 :height 3.0)
(org-level-4 :height 3.0)
(org-level-5 :height 3.0)
(org-level-6 :height 3.0)
(org-level-7 :height 3.0)
(org-level-8 :height 3.0)))
(push (apply #'face-remap-add-relative face) my/org-present-face-remapping-cookies))
;; Set a blank header line string to create blank space at the top (defun my/org-present-start ()
(setq header-line-format " ") (setq-local my/org-present-face-remapping-cookies nil)
;; Tweak font sizes
(dolist (face '((default :height 2.0)
(header-line :height 4.0 :background "#303446")
(org-document-title :height 1.75)
(org-code :height 2.0)
(org-verbatim :height 2.0)
(org-block :height 1.25)
(org-block-begin-line :height 0.7)
(org-level-1 :height 3.0)
(org-level-2 :height 3.0)
(org-level-3 :height 3.0)
(org-level-4 :height 3.0)
(org-level-5 :height 3.0)
(org-level-6 :height 3.0)
(org-level-7 :height 3.0)
(org-level-8 :height 3.0)))
(push (apply #'face-remap-add-relative face) my/org-present-face-remapping-cookies))
;; Display inline images automatically ;; Set a blank header line string to create blank space at the top
(org-display-inline-images) (setq header-line-format " ")
(org-present-hide-cursor)
;; Center the presentation and wrap lines ;; Display inline images automatically
(visual-fill-column-mode 1) (org-display-inline-images)
(setq visual-fill-column-center-text t) (org-present-hide-cursor)
;; (visual-line-mode 1)
)
(defun my/org-present-end () ;; Center the presentation and wrap lines
;; Reset font customizations (visual-fill-column-mode 1)
(dolist (cookie my/org-present-face-remapping-cookies) (setq visual-fill-column-center-text t)
(face-remap-remove-relative cookie)) ;; (visual-line-mode 1)
)
;; Clear the header line string so that it isn't displayed (defun my/org-present-end ()
(setq header-line-format nil) ;; Reset font customizations
(dolist (cookie my/org-present-face-remapping-cookies)
(face-remap-remove-relative cookie))
;; Stop displaying inline images ;; Clear the header line string so that it isn't displayed
(org-remove-inline-images) (setq header-line-format nil)
(org-present-show-cursor)
;; Stop centering the document ;; Stop displaying inline images
(visual-fill-column-mode 0) (org-remove-inline-images)
;; (visual-line-mode 0) (org-present-show-cursor)
)
(add-hook 'org-present-mode-hook 'my/org-present-start) ;; Stop centering the document
(add-hook 'org-present-mode-quit-hook 'my/org-present-end) (visual-fill-column-mode 0)
;; (visual-line-mode 0)
)
(require 'org-roam) (add-hook 'org-present-mode-hook 'my/org-present-start)
(bind-keys ("C-c n l" . org-roam-buffer-toggle) (add-hook 'org-present-mode-quit-hook 'my/org-present-end))
("C-c n f" . org-roam-node-find)
("C-c n g" . org-roam-graph) ;; (require 'org-roam)
("C-c n i" . org-roam-node-insert) ;; (bind-keys ("C-c n l" . org-roam-buffer-toggle)
("C-c n c" . org-roam-capture)) ;; ("C-c n f" . org-roam-node-find)
;; ("C-c n g" . org-roam-graph)
;; ("C-c n i" . org-roam-node-insert)
;; ("C-c n c" . org-roam-capture))
;; (setq org-roam-node-display-template (concat "${title:*} " (propertize "${tags:10}" 'face 'org-tag))) ;; (setq org-roam-node-display-template (concat "${title:*} " (propertize "${tags:10}" 'face 'org-tag)))
(org-roam-db-autosync-mode) ;; (org-roam-db-autosync-mode)
(add-hook 'org-mode-hook 'org-modern-mode) (use-package org-modern
:hook org-mode-hook)
(define-key org-mode-map (kbd "C-c C-r") verb-command-map) ;; (define-key org-mode-map (kbd "C-c C-r") verb-command-map)
#+END_SRC #+END_SRC
** Terminal ** Terminal
@@ -1948,7 +2128,9 @@ for completion. That makes it really annoying to use; don't use yasnippet with e
#+END_SRC #+END_SRC
#+BEGIN_SRC elisp #+BEGIN_SRC elisp
(eat-eshell-mode) (use-package eat
:commands (eat)
:hook (eshell-load-hook . eat-eshell-mode))
#+END_SRC #+END_SRC
** Slack ** Slack
@@ -1969,9 +2151,16 @@ for completion. That makes it really annoying to use; don't use yasnippet with e
#+END_SRC #+END_SRC
#+BEGIN_SRC elisp #+BEGIN_SRC elisp
(setopt lui-time-stamp-format "[%Y-%m-%d %H:%M]") (use-package lui
(setopt slack-render-profile-images-p nil) :defer t
(setopt slack-buffer-function #'switch-to-buffer) :custom
(lui-time-stamp-format "[%Y-%m-%d %H:%M]"))
(use-package slack
:commands slack-start
:custom
(slack-render-profile-images-p nil)
(slack-buffer-function #'switch-to-buffer))
#+END_SRC #+END_SRC
** Ledger ** Ledger
@@ -2005,10 +2194,13 @@ for completion. That makes it really annoying to use; don't use yasnippet with e
#+END_SRC #+END_SRC
#+BEGIN_SRC elisp #+BEGIN_SRC elisp
(setopt age-default-identity "~/source/dotfiles/keys/yubi1age.txt") (use-package age
(setopt age-default-recipient "~/source/dotfiles/keys/myself.txt") :custom
(setenv "PINENTRY_PROGRAM" "pinentry-mac") (setopt age-default-identity "~/source/dotfiles/keys/yubi1age.txt")
(age-file-enable) (age-default-recipient "~/source/dotfiles/keys/myself.txt")
:config
(setenv "PINENTRY_PROGRAM" "pinentry-mac")
(age-file-enable))
#+END_SRC #+END_SRC
** Claude Code ** Claude Code
@@ -2023,12 +2215,13 @@ for completion. That makes it really annoying to use; don't use yasnippet with e
enable = true; enable = true;
extraPackages = epkgs: with epkgs; [ extraPackages = epkgs: with epkgs; [
(epkgs.trivialBuild { (epkgs.trivialBuild {
name = "claude-code"; pname = "claude-code";
version = "0.4.5";
src = pkgs.fetchFromGitHub { src = pkgs.fetchFromGitHub {
owner = "stevemolitor"; owner = "stevemolitor";
repo = "claude-code.el"; repo = "claude-code.el";
rev = "4a9914bd4161eb43f489820f9174c62390e5adc8"; rev = "03199df8b3a1e9cd4857f0851f7a912ba524aff3";
sha256 = "sha256-ISlD6q1hceckry1Jd19BX1MfobHJxng5ulX2gq9f644="; sha256 = "sha256-5QJrWIu4EgnHcOqMwlrs2JBBx7aI9OaSJswesr6Apfk=";
}; };
packageRequires = [ epkgs.inheritenv ]; packageRequires = [ epkgs.inheritenv ];
}) })
@@ -2039,8 +2232,9 @@ for completion. That makes it really annoying to use; don't use yasnippet with e
#+END_SRC #+END_SRC
#+BEGIN_SRC elisp #+BEGIN_SRC elisp
(require 'claude-code) (use-package claude-code
(keymap-global-set "C-c c" claude-code-command-map) :bind-keymap ("C-c c" . claude-code-command-map)
:custom (claude-code-optimize-window-resize nil))
#+END_SRC #+END_SRC
* Theme * Theme
I like Catppuccin Frappe as my theme. Let's use it in as many places as we can. I like Catppuccin Frappe as my theme. Let's use it in as many places as we can.
@@ -2131,6 +2325,13 @@ I like Catppuccin Frappe as my theme. Let's use it in as many places as we can.
return config return config
#+END_SRC #+END_SRC
** Ghostty
#+BEGIN_SRC nix :tangle target/desktop/ghostty-theme.nix
{
programs.ghostty.settings.theme = "Catppuccin Frappe";
}
#+END_SRC
** Emacs ** Emacs
:PROPERTIES: :PROPERTIES:
:header-args:elisp: :tangle target/desktop/emacs-theme.el :header-args:elisp: :tangle target/desktop/emacs-theme.el
@@ -2155,7 +2356,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 'default nil :font "JetBrainsMono Nerd Font" :height 130)
;; (set-face-attribute 'fixed-pitch 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" :height 130 :width 'expanded) (set-face-attribute 'default nil :font "Iosevka Term SS14" :height 130)
(set-face-attribute 'fixed-pitch nil :font "Iosevka Term" :height 130 :width 'expanded) (set-face-attribute 'fixed-pitch nil :font "Iosevka Term SS14" :height 130)
(set-face-attribute 'variable-pitch nil :font "Iosevka Etoile" :height 130) (set-face-attribute 'variable-pitch nil :font "Iosevka Etoile" :height 130)
#+END_SRC #+END_SRC