15 Commits

Author SHA1 Message Date
Joe Frikker 5f96f98158 wip 2026-07-15 15:21:15 -04:00
Joe Frikker a1abf5b4a1 wip 2026-07-10 00:11:54 -04:00
Joe Frikker ba8ef4f585 wip 2026-07-09 23:36:36 -04:00
Joe Frikker eb057a2c3a perspective 2026-07-07 23:10:02 -04:00
Joe Frikker 8effe5f401 popper 2026-07-07 22:48:21 -04:00
Joe Frikker 8fae2a5338 wip 2026-07-07 15:01:03 -04:00
Joe Frikker 1c379cc4a3 wip 2026-07-02 15:19:56 -04:00
Joe Frikker 69f3fa445b Fewer sbcl packages 2026-06-30 16:19:08 -04:00
Joe Frikker 6c1b0faea4 format-all 2026-06-30 16:16:57 -04:00
Joe Frikker c68e79ca4f Bufferlo, and re-add God mode 2026-06-30 15:42:28 -04:00
Joe Frikker af8a00ab5b Flake update, and fixing side window sizes 2026-06-27 16:16:41 -04:00
Joe Frikker 50d27458af no evil 2026-06-23 22:54:08 -04:00
Joe Frikker d0d340e04f shibumi -> redbook 2026-06-19 18:39:46 -04:00
Joe Frikker b7912eef52 Redbook 2026-06-19 18:38:22 -04:00
Joe Frikker ed88afe698 wip 2026-06-19 18:33:43 -04:00
3 changed files with 518 additions and 288 deletions
Generated
+56 -54
View File
@@ -1,20 +1,41 @@
{
"nodes": {
"flake-parts": {
"claude-code": {
"inputs": {
"nixpkgs-lib": "nixpkgs-lib"
"flake-utils": "flake-utils",
"nixpkgs": [
"nixpkgs"
]
},
"locked": {
"lastModified": 1765835352,
"narHash": "sha256-XswHlK/Qtjasvhd1nOa1e8MgZ8GS//jBoTqWtrS1Giw=",
"owner": "hercules-ci",
"repo": "flake-parts",
"rev": "a34fae9c08a15ad73f295041fec82323541400a9",
"lastModified": 1783380155,
"narHash": "sha256-SwUwKaLrZ+c5y4GoZHKBf1nUsDHVsIUtn2CFloZrV2A=",
"owner": "sadjow",
"repo": "claude-code-nix",
"rev": "25d979d1a39d0acdbcb1b8d0b9d83ffdd10b5f43",
"type": "github"
},
"original": {
"owner": "hercules-ci",
"repo": "flake-parts",
"owner": "sadjow",
"repo": "claude-code-nix",
"type": "github"
}
},
"flake-utils": {
"inputs": {
"systems": "systems"
},
"locked": {
"lastModified": 1731533236,
"narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
@@ -25,11 +46,11 @@
]
},
"locked": {
"lastModified": 1779969295,
"narHash": "sha256-HwIJ3tOcwSMiV75L7KqJXciXR9UfT+d7rwOZMX7cTnA=",
"lastModified": 1783436070,
"narHash": "sha256-F80z1JoiJgZyTT5D+3siLOVzqmCEphLR7t0Ym/I2CLI=",
"owner": "nix-community",
"repo": "home-manager",
"rev": "61e2c9659324181e0f0ed911958c536333b1d4f6",
"rev": "f09af49406ffad37acb6538d3207189a1a1e0b7e",
"type": "github"
},
"original": {
@@ -39,25 +60,6 @@
"type": "github"
}
},
"kube": {
"inputs": {
"flake-parts": "flake-parts",
"nixpkgs": [
"nixpkgs"
]
},
"locked": {
"lastModified": 1767247330,
"narHash": "sha256-CxXwzmvAOO07719jzE0Zw14C9r3fQcXfPllLtt5cIzo=",
"rev": "4a4d79a290c92de630e503f395fc8fd709904c1b",
"type": "tarball",
"url": "https://gitea.home-frikker.dedyn.io/api/v1/repos/jfrikker/kube/archive/4a4d79a290c92de630e503f395fc8fd709904c1b.tar.gz"
},
"original": {
"type": "tarball",
"url": "https://gitea.home-frikker.dedyn.io/jfrikker/kube/archive/1.0.1.tar.gz"
}
},
"nix-index-database": {
"inputs": {
"nixpkgs": [
@@ -65,11 +67,11 @@
]
},
"locked": {
"lastModified": 1779604987,
"narHash": "sha256-ZQ5z+fVhxYKtIFwtqGp5O0PD84BM1riASvqDaN5Xs+s=",
"lastModified": 1783414108,
"narHash": "sha256-RY8e+gR2/DhXsYDxGDL6Hhe9+POD9u4+llwxMBqMQDs=",
"owner": "nix-community",
"repo": "nix-index-database",
"rev": "8fba98c80b48fa013820e0163c5096922fea4ddd",
"rev": "96d6de10eb281b98f5cfcd1841394c03da5df77c",
"type": "github"
},
"original": {
@@ -80,42 +82,42 @@
},
"nixpkgs": {
"locked": {
"lastModified": 1779560665,
"narHash": "sha256-tpyBcxPpcQb8ukyNF7DoCwfSY3VPsxHoYwj00Cayv5o=",
"lastModified": 1783148766,
"narHash": "sha256-uslt2pqShTIXDdAHRHv2QkYLsVdY8Oqwz0EA48/RSM8=",
"owner": "nixos",
"repo": "nixpkgs",
"rev": "64c08a7ca051951c8eae34e3e3cb1e202fe36786",
"rev": "a50de1b7d8a586adc18d2395c19de7d6058e6030",
"type": "github"
},
"original": {
"owner": "nixos",
"ref": "nixos-unstable",
"ref": "nixos-26.05",
"repo": "nixpkgs",
"type": "github"
}
},
"nixpkgs-lib": {
"locked": {
"lastModified": 1765674936,
"narHash": "sha256-k00uTP4JNfmejrCLJOwdObYC9jHRrr/5M/a/8L2EIdo=",
"owner": "nix-community",
"repo": "nixpkgs.lib",
"rev": "2075416fcb47225d9b68ac469a5c4801a9c4dd85",
"type": "github"
},
"original": {
"owner": "nix-community",
"repo": "nixpkgs.lib",
"type": "github"
}
},
"root": {
"inputs": {
"claude-code": "claude-code",
"home-manager": "home-manager",
"kube": "kube",
"nix-index-database": "nix-index-database",
"nixpkgs": "nixpkgs"
}
},
"systems": {
"locked": {
"lastModified": 1681028828,
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
"owner": "nix-systems",
"repo": "default",
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
"type": "github"
},
"original": {
"owner": "nix-systems",
"repo": "default",
"type": "github"
}
}
},
"root": "root",
+18 -11
View File
@@ -3,15 +3,20 @@
inputs = {
# Specify the source of Home Manager and Nixpkgs.
nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
nixpkgs.url = "github:nixos/nixpkgs/nixos-26.05";
claude-code = {
url = "github:sadjow/claude-code-nix";
inputs.nixpkgs.follows = "nixpkgs";
};
home-manager = {
url = "github:nix-community/home-manager/master";
inputs.nixpkgs.follows = "nixpkgs";
};
kube = {
url = "https://gitea.home-frikker.dedyn.io/jfrikker/kube/archive/1.0.1.tar.gz";
inputs.nixpkgs.follows = "nixpkgs";
};
# kube = {
# url = "https://gitea.home-frikker.dedyn.io/jfrikker/kube/archive/1.0.1.tar.gz";
# inputs.nixpkgs.follows = "nixpkgs";
# };
nix-index-database = {
url = "github:nix-community/nix-index-database";
@@ -19,7 +24,7 @@
};
};
outputs = { nixpkgs, home-manager, kube, nix-index-database, ... }:
outputs = { nixpkgs, home-manager, claude-code, nix-index-database, ... }:
let modules-for-system = pkgs: pkgs.stdenv.mkDerivation {
name = "home-manager-modules";
src = pkgs.lib.fileset.toSource {
@@ -41,7 +46,7 @@
'';
};
in {
homeConfigurations.shibumi =
homeConfigurations.redbook =
let pkgs = import nixpkgs { system = "aarch64-darwin"; config.allowUnfree = true; };
modules = modules-for-system pkgs;
in home-manager.lib.homeManagerConfiguration {
@@ -50,17 +55,19 @@
modules =
[
nix-index-database.homeModules.default
"${modules}"
"${modules}/base.nix"
"${modules}/desktop.nix"
"${modules}/redbook.nix"
"${modules}/redbook-desktop.nix"
] ++
[{
home.stateVersion = "22.05";
home.username = "jfrikker";
home.homeDirectory = "/Users/jfrikker";
home.packages = [ pkgs.pinentry_mac ];
jfrikker.desktop.enable = true;
}];
extraSpecialArgs = { kube = kube.packages.aarch64-darwin.default; };
extraSpecialArgs = { claude-code = claude-code.packages.aarch64-darwin.default; };
};
homeConfigurations.home =
let pkgs = nixpkgs.legacyPackages.x86_64-linux;
@@ -80,7 +87,7 @@
home.homeDirectory = "/home/jfrikker";
}];
extraSpecialArgs = { kube = kube.packages.x86_64-linux.default; };
extraSpecialArgs = { claude-code = claude-code.packages.x86_64-linux.default; };
};
packages.aarch64-darwin.default = modules-for-system nixpkgs.legacyPackages.aarch64-darwin;
};
+360 -139
View File
@@ -1,32 +1,36 @@
#+PROPERTY: header-args :mkdirp yes
#+PROPERTY: header-args:elisp :lexical t
* Base
* Categories
#+BEGIN_SRC nix :tangle target/default.nix
{
imports = [
./base_options.nix
./sbcl.nix
./crypto.nix
./rust-reimpls.nix
./ledger.nix
./nil.nix
./magic-wormhole.nix
./desktop-packages.nix
./shibumi.nix
./slack.nix
];
#+BEGIN_SRC nix :tangle target/base.nix
{lib, ...}: {
imports = lib.filter
(n: lib.strings.hasSuffix ".nix" n)
(lib.filesystem.listFilesRecursive ./base);
}
#+END_SRC
#+BEGIN_SRC nix :tangle target/base_options.nix
{lib, ...}:
with lib;
{
options = {
jfrikker.desktop.enable = mkEnableOption "desktop tools";
jfrikker.shibumi.enable = mkEnableOption "shibumi-specific tools";
};
#+BEGIN_SRC nix :tangle target/desktop.nix
{lib, ...}: {
imports = lib.filter
(n: lib.strings.hasSuffix ".nix" n)
(lib.filesystem.listFilesRecursive ./desktop);
}
#+END_SRC
#+BEGIN_SRC nix :tangle target/redbook.nix
{lib, ...}: {
imports = lib.filter
(n: lib.strings.hasSuffix ".nix" n)
(lib.filesystem.listFilesRecursive ./redbook);
}
#+END_SRC
#+BEGIN_SRC nix :tangle target/redbook-desktop.nix
{lib, ...}: {
imports = lib.filter
(n: lib.strings.hasSuffix ".nix" n)
(lib.filesystem.listFilesRecursive ./redbook-desktop);
}
#+END_SRC
@@ -41,7 +45,7 @@ in a ~nix~ devshell I think I'd also like to use it for scripting / exploratory
so I'm installing it globally with a useful set of libraries. I should curate this somewhat
carefully so it doesn't get carried away...
#+BEGIN_SRC nix :tangle target/sbcl.nix
#+BEGIN_SRC nix :tangle target/base/sbcl.nix
{pkgs, ...}:
{
home.packages = with pkgs; [
@@ -50,10 +54,8 @@ carefully so it doesn't get carried away...
alexandria
cl-markup
cl-mock
cl-rdkafka
clack
clack-handler-woo
dbd-mysql
dbi
defstar
dexador
@@ -92,7 +94,7 @@ the name implies, allows generating and storing ~age~ keys on a Yubikey. ~rage~
~age~ when using ~age.el~, because it supports ~pinentry~. That allows it to prompt for yubikey pins
using a dialog, rather than a command line prompt.
#+BEGIN_SRC nix :tangle target/crypto.nix
#+BEGIN_SRC nix :tangle target/base/crypto.nix
{pkgs, ...}:
{
home.packages = with pkgs; [
@@ -112,7 +114,7 @@ tools. They boost better speed, or simply more streamlined features.
| ~ripgrep~ | ~grep~ |
| ~xh~ | ~curl~ |
#+BEGIN_SRC nix :tangle target/rust-reimpls.nix
#+BEGIN_SRC nix :tangle target/base/rust-reimpls.nix
{pkgs, ...}:
{
home.packages = with pkgs; [
@@ -127,7 +129,7 @@ tools. They boost better speed, or simply more streamlined features.
[[https://ledger-cli.org/][~ledger~]] is how I manage my budget. It's a plain-text accounting tool that's really awesome.
#+BEGIN_SRC nix :tangle target/ledger.nix
#+BEGIN_SRC nix :tangle target/base/ledger.nix
{pkgs, ...}:
{
home.packages = with pkgs; [
@@ -138,7 +140,7 @@ tools. They boost better speed, or simply more streamlined features.
~nil~ is an LSP server for nix files.
#+BEGIN_SRC nix :tangle target/nil.nix
#+BEGIN_SRC nix :tangle target/base/nil.nix
{pkgs, ...}:
{
home.packages = with pkgs; [
@@ -151,7 +153,7 @@ tools. They boost better speed, or simply more streamlined features.
computers in the world, assuming that you have an out-of-band way to communicate a passphrase
between them. Once installed, the actual command is ~wormhole~.
#+begin_src nix :tangle target/magic-wormhole.nix
#+begin_src nix :tangle target/base/magic-wormhole.nix
{pkgs, ...}:
{
home.packages = with pkgs; [
@@ -161,33 +163,29 @@ between them. Once installed, the actual command is ~wormhole~.
#+end_src
These are the other programs I have installed globally. A few (like ~awscli~, ~mysql-client~, etc.)
are still Shibumi-specific; ideally I'd find another way to install them.
are still Redbook-specific; ideally I'd find another way to install them.
#+BEGIN_SRC nix :tangle target/shibumi.nix
{lib, pkgs, kube, config, ...}:
#+BEGIN_SRC nix :tangle target/redbook/other-packages.nix
{pkgs, ...}:
{
config = lib.mkIf config.jfrikker.shibumi.enable {
home.packages = with pkgs; [
aws-iam-authenticator
awscli2
kube
kubectl
mariadb.client
postgresql
openssh
];
};
fonts.fontconfig.enable = true;
}
#+END_SRC
These programs require a full desktop environment:
#+BEGIN_SRC nix :tangle target/desktop-packages.nix
{lib, pkgs, config, ...}:
#+BEGIN_SRC nix :tangle target/desktop/desktop-packages.nix
{pkgs, ...}:
{
config = lib.mkIf config.jfrikker.desktop.enable {
home.packages = with pkgs; [
google-chrome
nerd-fonts.jetbrains-mono
nerd-fonts.symbols-only
(iosevka-bin.override { variant = "Aile"; })
(iosevka-bin.override { variant = "Etoile"; })
(iosevka-bin.override { variant = "SGr-IosevkaTerm"; })
@@ -195,20 +193,23 @@ These programs require a full desktop environment:
proton-pass
wireshark
];
fonts.fontconfig.enable = true;
};
}
#+END_SRC
#+BEGIN_SRC nix :tangle target/slack.nix
{lib, pkgs, config, ...}:
#+BEGIN_SRC nix :tangle target/redbook-desktop/desktop-packages.nix
{pkgs, ...}:
{
config = lib.mkIf (config.jfrikker.shibumi.enable && config.jfrikker.desktop.enable) {
home.packages = with pkgs; [
slack
];
linear
(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
];
}
#+END_SRC
@@ -315,7 +316,8 @@ We all know what ~git~ does.
programs.git = {
enable = true;
settings.user.name = "Joe Frikker";
settings.user.email = "joe.frikker@shibumi.com";
settings.user.email = "joe@redbookcattle.com";
settings.github.user = "joe@redbookcattle.com";
};
programs.delta = {
@@ -660,7 +662,7 @@ Now we'll set up some keybindings:
key = "g",
mods = "CMD",
action = wezterm.action.SpawnCommandInNewTab {
args = { wezterm.home_dir .. "/.nix-profile/bin/zsh", "-l", "-c", "lazygit" }
args = { wezterm.home_dir .. "/.nix-profile/bin/zsh", "-l", "-i", "-c", "lazygit" }
}
},
{
@@ -690,6 +692,17 @@ Now we'll set up some keybindings:
end
#+END_SRC
** Ghostty
#+BEGIN_SRC nix :tangle target/desktop/ghostty.nix
{pkgs, ...}: {
programs.ghostty = {
enable = true;
package = pkgs.ghostty-bin;
};
}
#+END_SRC
** Zsh
This is my default shell for now. Unfortunately, nix requires a posix-compliant shell, so bash or
@@ -732,9 +745,10 @@ Actually, nix *really* requires ~bash~. This is a plugin that allows using zsh f
** Claude Code
#+BEGIN_SRC nix :tangle target/base/claude-code.nix
{
{claude-code, ...}: {
programs.claude-code = {
enable = true;
package = claude-code;
};
}
#+END_SRC
@@ -782,10 +796,13 @@ These are just some general settings that apply everywhere. First, a few package
programs.emacs = {
enable = true;
extraPackages = epkgs: with epkgs; [
ace-window
doom-modeline
free-keys
ligature
mixed-pitch
ace-window
perspective
popper
];
extraConfig = builtins.readFile ./emacs-global.el;
};
@@ -797,6 +814,7 @@ Turn off some default settings that I don't find useful.
#+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)
@@ -808,6 +826,15 @@ Turn off some default settings that I don't find useful.
display-buffer-in-previous-window
display-buffer-use-some-window)))
(setopt view-read-only t)
(setopt save-interprogram-paste-before-kill t)
(setopt kill-whole-line t)
(delete-selection-mode t)
(column-number-mode t)
(setopt auto-save-default nil)
(setopt create-lockfiles nil)
(setopt mouse-wheel-tilt-scroll t)
(setq-default truncate-lines t)
#+END_SRC
Make sure which-key mode is always on. The on-the-fly keymap help it gives is indespensable.
@@ -915,6 +942,7 @@ Use variable-width fonts in text buffers. ~mixed-pitch-mode~ keeps most code blo
(add-hook 'yaml-ts-mode-hook 'no-mixed-pitch)
(add-hook 'mhtml-mode 'no-mixed-pitch)
(add-hook 'nxml-mode 'no-mixed-pitch)
#+END_SRC
A basic ace-window setup. Allows switching between windows quickly (although avy can do the same...).
@@ -931,11 +959,12 @@ Set up a few project- / workspace-related key bindings.
#+BEGIN_SRC elisp
(bind-keys ("s-f" . project-find-file)
("s-F" . project-switch-project))
("s-F" . project-switch-project)
("s-s" . persp-switch))
(with-eval-after-load 'tab-bar
(bind-keys :map tab-bar-mode-map
("s-s" . tab-bar-switch-to-tab)))
;; (with-eval-after-load 'tab-bar
;; (bind-keys :map tab-bar-mode-map
;; ("s-s" . tab-bar-switch-to-tab)))
#+END_SRC
Don't run a server. I'm not using this, I can always turn it back on if I need to.
@@ -986,19 +1015,99 @@ windows. I place windows in the bottom or on the right mostly depending on how w
content to be.
#+BEGIN_SRC elisp
(setq display-buffer-alist
'(((or "\\*Flymake diagnostics .*"
(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))))))))
(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.
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\\*")
".*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)
(popper-mode)
(popper-echo-mode)
(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)
@@ -1008,25 +1117,30 @@ content to be.
((or "magit: *"
"magit-revision: .*"
"magit-log*"
"\\*eldoc\\*"
"\\*Help\\*"
"\\*rustfmt\\*"
"\\*slack: .*"
"\\*forge: .*"
"new-pullreq"
"\\*claude:.*"
"\\*Man .*")
(display-buffer-reuse-window display-buffer-in-side-window)
"\\*Man .*"
"\\*List .*")
(display-buffer-in-side-window)
(side . right)
(slot . 0)
(window-width . 0.5)
(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)))
("\\*Embark Actions\\*"
((or "\\*Embark Actions\\*"
"\\*eldoc\\*")
(display-buffer-in-side-window)
(side . right)
(slot . -1)
(window-width . 0.5)
(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)))))
@@ -1052,9 +1166,11 @@ This configuration affects general text editing, across all modes. First, some p
avy
edit-indirect
embark
evil
evil-collection
evil-org
format-all
god-mode
# evil
# evil-collection
# evil-org
string-inflection
];
extraConfig = builtins.readFile ./emacs-editing.el;
@@ -1074,17 +1190,32 @@ cancel them more frequently). In the end, I opted for Devil mode. It avoids modi
its own devil-mode-only repeat maps that don't interfere when using normal modifier key sequences.
#+BEGIN_SRC elisp
(setopt evil-want-keybinding nil)
(require 'evil)
(evil-mode 1)
(require 'evil-collection)
(evil-collection-init)
;; (setopt evil-want-keybinding nil)
;; (require 'evil)
;; (evil-mode 1)
;; (require 'evil-collection)
;; (evil-collection-init)
(require 'evil-org)
(add-hook 'org-mode-hook 'evil-org-mode)
(evil-org-set-key-theme '(navigation insert textobjects additional calendar))
(require 'evil-org-agenda)
(evil-org-agenda-set-keys)
;; (require 'evil-org)
;; (add-hook 'org-mode-hook 'evil-org-mode)
;; (evil-org-set-key-theme '(navigation insert textobjects additional calendar))
;; (require 'evil-org-agenda)
;; (evil-org-agenda-set-keys)
(require 'god-mode)
(require 'which-key)
(bind-keys :map god-local-mode-map
("i" . (lambda () (interactive) (god-mode-all -1)))
("z" . repeat))
(bind-keys ("<escape>" . (lambda () (interactive) (god-mode-all 1))))
(defun my-god-mode-update-cursor-type ()
(setq cursor-type (cond
((and (featurep 'org-present) org-present-mode) nil)
((or (and (featurep 'god-mode) god-local-mode) buffer-read-only) 'box)
(t 'bar))))
(add-hook 'post-command-hook 'my-god-mode-update-cursor-type)
(which-key-enable-god-mode-support)
#+END_SRC
Avy allows jumping to any place on the screen with just a few keystrokes. I've stolen most of these
@@ -1106,10 +1237,17 @@ his article.
(avy-goto-char-timer)))
(bind-keys
("M-j" . avy-goto-char-timer)
("C-c j" . avy-goto-char-timer)
("M-J" . avy-goto-char-timer-embark)
("C-j" . avy-goto-char-timer)
("M-j" . avy-goto-char-timer-embark)
("C-." . embark-act))
(with-eval-after-load 'lispy
(bind-keys :map lispy-mode-map
("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
Just "silently" wrap when searching at the bottom of a document.
@@ -1142,6 +1280,44 @@ Just "silently" wrap when searching at the bottom of a document.
(bind-keys ("C-x 4 n" . edit-indirect-region))
#+END_SRC
** Workflow
:PROPERTIES:
:header-args:elisp: :tangle target/desktop/emacs-workflow.el
:END:
#+BEGIN_SRC nix :tangle target/desktop/emacs-workflow.nix
{
programs.emacs = {
enable = true;
extraPackages = epkgs: with epkgs; [
# bufferlo
];
extraConfig = builtins.readFile ./emacs-workflow.el;
};
}
#+END_SRC
#+BEGIN_SRC elisp
;; (bufferlo-mode)
;; (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
("s-b" . consult-buffer)
;; ("C-x t 0" . bufferlo-tab-close-kill-buffers)
;; ("C-x k" . my/bury-or-kill-buffer)
)
#+END_SRC
** Language Support
:PROPERTIES:
:header-args:elisp: :tangle target/desktop/emacs-languages.el
@@ -1153,18 +1329,21 @@ Just "silently" wrap when searching at the bottom of a document.
enable = true;
extraPackages = epkgs: with epkgs; [
consult-eglot
graphql-ts-mode
haskell-ts-mode
jenkinsfile-mode
jq-mode
(lispy.overrideAttrs {
packageRequires = [
ace-window iedit swiper zoutline
ace-window iedit swiper zoutline hydra
];
ignoreCompilationError = true;
})
lispyville
# lispyville
lua-mode
nix-mode
pnpm-mode
prisma-ts-mode
rust-mode
sly
sly-macrostep
@@ -1195,6 +1374,7 @@ Just "silently" wrap when searching at the bottom of a document.
g.tree-sitter-nix
g.tree-sitter-org
g.tree-sitter-php
g.tree-sitter-prisma
g.tree-sitter-python
g.tree-sitter-rust
g.tree-sitter-rust-format-args
@@ -1232,7 +1412,7 @@ Show a vertical bar 100 characters out; ideally I don't want lines longer than t
is about the max you can have and still fit two files side-by-side on the screen.
#+begin_src elisp
(setq-default fill-column 100)
(setq-default fill-column 120)
(defun jf-init-fill-column ()
(display-fill-column-indicator-mode 1))
@@ -1272,6 +1452,10 @@ available? It seems to work for now anyway...
(advice-add 'prog-fill-reindent-defun :override #'my-prog-fill-reindent-defun))
#+end_src
#+BEGIN_SRC elisp
(add-hook 'compilation-filter-hook 'ansi-color-compilation-filter)
#+END_SRC
*** Flymake
#+begin_src elisp
(autoload 'flymake-show-project-diagnostics "flymake")
@@ -1343,9 +1527,10 @@ for completion. That makes it really annoying to use; don't use yasnippet with e
(setopt lispy-compat '(god-mode edebug))
(add-hook 'emacs-lisp-mode-hook (lambda () (lispy-mode 1)))
(add-hook 'lisp-mode-hook (lambda () (lispy-mode 1)))
(add-hook 'lisp-data-mode-hook (lambda () (lispy-mode 1)))
(with-eval-after-load 'lispy
(require 'lispyville)
(add-hook 'lispy-mode-hook #'lispyville-mode)
;; (require 'lispyville)
;; (add-hook 'lispy-mode-hook #'lispyville-mode)
(bind-keys :map lispy-mode-map
("i" . (lambda ()
(interactive)
@@ -1356,11 +1541,11 @@ for completion. That makes it really annoying to use; don't use yasnippet with e
*** Typescript
#+BEGIN_SRC elisp
(push '("\\.ts\\'" . typescript-mode) auto-mode-alist)
(push '(typescript-mode . typescript-ts-mode) major-mode-remap-alist)
(push '("\\.tsx\\'" . tsx-mode) auto-mode-alist)
(push '(tsx-mode . tsx-ts-mode) major-mode-remap-alist)
(setopt typescript-ts-mode-indent-offset 4)
(add-to-list 'auto-mode-alist '("\\.ts\\'" . typescript-mode))
(add-to-list 'major-mode-remap-alist '(typescript-mode . typescript-ts-mode))
(add-to-list 'auto-mode-alist '("\\.tsx\\'" . tsx-mode))
(add-to-list 'major-mode-remap-alist '(tsx-mode . tsx-ts-mode))
(setopt typescript-ts-mode-indent-offset 2)
(with-eval-after-load 'typescript-ts-mode
(defun my-tsx-ts-mode--indent-compatibility-b893426 ()
"Indent rules helper, to handle different releases of tree-sitter-tsx.
@@ -1374,6 +1559,52 @@ for completion. That makes it really annoying to use; don't use yasnippet with e
`(((match "<" "jsx_text") parent 0)
((parent-is "jsx_text") grand-parent typescript-ts-mode-indent-offset)))))
(advice-add 'tsx-ts-mode--indent-compatibility-b893426 :override #'my-tsx-ts-mode--indent-compatibility-b893426))
(defvar my/edit-indirect-tag-modes
'(("graphql" . graphql-ts-mode)
("gql" . graphql-ts-mode)
("sql" . sql-mode)
("css" . css-mode))
"Map of tagged-template tag names to major modes.")
(defun my/edit-indirect--node-bounds (node)
"Return (BEG . END) for NODE's contents, excluding delimiters."
(cons (1+ (treesit-node-start node))
(1- (treesit-node-end node))))
(defun my/edit-indirect-tagged-template-at-point ()
(interactive)
(let* ((node (treesit-node-at (point)))
(tmpl-node (treesit-parent-until
node
(lambda (n) (equal (treesit-node-type n) "template_string"))))
(str-node (unless tmpl-node
(treesit-parent-until
node
(lambda (n) (equal (treesit-node-type n) "string")))))
(target-node (or tmpl-node str-node)))
(unless target-node
(user-error "Point is not inside a string or template literal"))
(let* ((tagged-node (and tmpl-node (treesit-node-parent tmpl-node)))
(tag-node (and tagged-node
(equal (treesit-node-type tagged-node) "call_expression")
(treesit-node-child-by-field-name tagged-node "function")))
(tag-name (and tag-node (treesit-node-text tag-node t)))
(mode (cond
(tag-name (or (cdr (assoc tag-name my/edit-indirect-tag-modes))
major-mode))
(t 'text-mode)))
(bounds (my/edit-indirect--node-bounds target-node))
(buf (edit-indirect-region (car bounds) (cdr bounds) t)))
(with-current-buffer buf
(funcall 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 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
*** Java
@@ -1520,11 +1751,10 @@ for completion. That makes it really annoying to use; don't use yasnippet with e
;; ("C-x M-:" . consult-complex-command)
("C-x b" . consult-buffer)
("s-b" . consult-project-buffer)
("s-B" . consult-buffer)
("C-x 4 b" . consult-buffer-other-window)
("C-x 5 b" . consult-buffer-other-frame)
("C-x t b" . consult-buffer-other-tab)
;; ("C-x t b" . consult-buffer-other-tab)
("C-x r b" . consult-bookmark)
("C-x p b" . consult-project-buffer)
@@ -1563,15 +1793,20 @@ for completion. That makes it really annoying to use; don't use yasnippet with e
(eval-when-compile
(require 'consult))
(require 'perspective)
(with-eval-after-load 'consult
(consult-customize
consult-theme :preview-key '(:debounce 0.2 any)
consult-ripgrep consult-git-grep consult-grep consult-man
consult-bookmark consult-recent-file consult-xref
consult-source-bookmark consult-source-file-register
consult-source-recent-file consult-source-project-recent-file
consult-source-recent-file
consult-source-buffer
;; :preview-key "M-."
:preview-key '(:debounce 0.4 any)))
consult-source-project-recent-file
: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-+"
@@ -1655,11 +1890,11 @@ 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-8 nil :font "Iosevka Aile")
(require 'org-present)
(defvar-local my/org-present-face-remapping-cookies nil)
(with-eval-after-load 'org-present
(require 'face-remap)
(require 'visual-fill-column)
(defvar-local my/org-present-face-remapping-cookies nil)
(defun my/org-present-start ()
(setq-local my/org-present-face-remapping-cookies nil)
;; Tweak font sizes
@@ -1711,17 +1946,17 @@ for completion. That makes it really annoying to use; don't use yasnippet with e
)
(add-hook 'org-present-mode-hook 'my/org-present-start)
(add-hook 'org-present-mode-quit-hook 'my/org-present-end)
(add-hook 'org-present-mode-quit-hook 'my/org-present-end))
(require 'org-roam)
(bind-keys ("C-c n l" . org-roam-buffer-toggle)
("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))
;; (require 'org-roam)
;; (bind-keys ("C-c n l" . org-roam-buffer-toggle)
;; ("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)))
(org-roam-db-autosync-mode)
;; (org-roam-db-autosync-mode)
(add-hook 'org-mode-hook 'org-modern-mode)
@@ -1767,32 +2002,16 @@ for completion. That makes it really annoying to use; don't use yasnippet with e
#+END_SRC
#+BEGIN_SRC elisp
(setopt lui-time-stamp-format "[%Y-%m-%d %H:%M]")
(setopt slack-render-profile-images-p nil)
(setopt slack-buffer-function #'switch-to-buffer)
#+END_SRC
(use-package lui
:defer t
:custom
(lui-time-stamp-format "[%Y-%m-%d %H:%M]"))
** Kubernetes
:PROPERTIES:
:header-args:elisp: :tangle target/desktop/emacs-kubernetes.el
:END:
#+BEGIN_SRC nix :tangle target/desktop/emacs-kubernetes.nix
{
programs.emacs = {
enable = true;
extraPackages = epkgs: with epkgs; [
kubed
];
extraConfig = builtins.readFile ./emacs-kubernetes.el;
};
}
#+END_SRC
#+BEGIN_SRC elisp
(use-package kubed
:bind-keymap
("s-k" . kubed-prefix-map))
(use-package slack
:commands slack-start
:custom
(slack-render-profile-images-p nil)
(slack-buffer-function #'switch-to-buffer))
#+END_SRC
** Ledger
@@ -1844,12 +2063,13 @@ for completion. That makes it really annoying to use; don't use yasnippet with e
enable = true;
extraPackages = epkgs: with epkgs; [
(epkgs.trivialBuild {
name = "claude-code";
pname = "claude-code";
version = "0.4.5";
src = pkgs.fetchFromGitHub {
owner = "stevemolitor";
repo = "claude-code.el";
rev = "4a9914bd4161eb43f489820f9174c62390e5adc8";
sha256 = "sha256-ISlD6q1hceckry1Jd19BX1MfobHJxng5ulX2gq9f644=";
rev = "03199df8b3a1e9cd4857f0851f7a912ba524aff3";
sha256 = "sha256-5QJrWIu4EgnHcOqMwlrs2JBBx7aI9OaSJswesr6Apfk=";
};
packageRequires = [ epkgs.inheritenv ];
})
@@ -1860,8 +2080,9 @@ for completion. That makes it really annoying to use; don't use yasnippet with e
#+END_SRC
#+BEGIN_SRC elisp
(require 'claude-code)
(keymap-global-set "C-c c" claude-code-command-map)
(use-package claude-code
:bind-keymap ("C-c c" . claude-code-command-map)
:custom (claude-code-optimize-window-resize nil))
#+END_SRC
* Theme
I like Catppuccin Frappe as my theme. Let's use it in as many places as we can.