diff --git a/home.org b/home.org index 4b4c1aa..d158aac 100644 --- a/home.org +++ b/home.org @@ -564,7 +564,32 @@ Emacs is a huge portion of this configuration, so although it's a home-manager " ''; #+END_SRC +** Keybindings +These keybindings are scattered throughout this file, I'm collecting them all here to make it easier to track them. + + | Key | Normal Key | Action | Mode | + | s-b | | [[id:6D1A8B35-3093-4DA6-A5AA-2A0D45112BAB][Switch project buffer]] | | + | s-B | | [[id:6D1A8B35-3093-4DA6-A5AA-2A0D45112BAB][Switch buffer]] | | + | s-f | C-x p f | [[id:A2F7FF5C-AFCC-44D4-9AA5-3498F6D6D5E0::workspace_keybinds][Open file in current project]] | | + | s-F | C-x p p | [[id:A2F7FF5C-AFCC-44D4-9AA5-3498F6D6D5E0::workspace_keybinds][Switch project]] | | + | S-s | C-x t RET | [[id:A2F7FF5C-AFCC-44D4-9AA5-3498F6D6D5E0::workspace_keybinds][Switch tab]] | | + | C-c a | | [[id:3B0BFCDC-DFD5-42A0-97D8-3B032B128AF7][Org agenda]] | | + | C-c A | | [[id:5CCB676B-9FF0-47B4-8AF2-10FD3899A646][Eglot code actions]] | prog | + | C-c c | | [[id:3B0BFCDC-DFD5-42A0-97D8-3B032B128AF7][Org capture]] | | + | C-c D | | [[id:5CCB676B-9FF0-47B4-8AF2-10FD3899A646][Show flymake diagnostics]] | prog | + | C-c h | | [[id:6D1A8B35-3093-4DA6-A5AA-2A0D45112BAB][Consult shell history]] | | + | C-c I | | [[id:5CCB676B-9FF0-47B4-8AF2-10FD3899A646][Eglot find implementation]] | prog | + | C-c l | | [[id:3B0BFCDC-DFD5-42A0-97D8-3B032B128AF7][Org store link]] | | + | C-c n | | [[id:3B0BFCDC-DFD5-42A0-97D8-3B032B128AF7][Org Roam prefix]] | | + | C-c R | | [[id:5CCB676B-9FF0-47B4-8AF2-10FD3899A646][Eglot rename]] | prog | + | C-c u | | [[id:5CCB676B-9FF0-47B4-8AF2-10FD3899A646][Cycle string inflection]] | various | + | C-c M-g | | [[id:4F426E77-CE03-4BF8-8D1B-7791C7C02B28][Magit file dispatch]] | | + + ** Global Settings +:PROPERTIES: +:ID: A2F7FF5C-AFCC-44D4-9AA5-3498F6D6D5E0 +:END: These are just some general settings that apply everywhere. First, a few packages: @@ -692,11 +717,7 @@ Use variable-width fonts in text buffers. ~mixed-pitch-mode~ keeps most code blo Set up a few project- / workspace-related key bindings. - | Key | Action | - | s-f | Open file in current project (C-x p f) | - | s-F | Switch project (C-x p p) | - | S-s | Switch tab (C-x t RET) | - +#+name: workspace_keybinds #+BEGIN_SRC elisp :noweb no :noweb-ref emacs_config (bind-keys ("s-f" . project-find-file) ("s-F" . project-switch-project)) @@ -722,6 +743,16 @@ I'm trying this out. This disables visual selections. It's bold, which is why I (transient-mark-mode -1) #+END_SRC +#+BEGIN_SRC elisp :noweb no :noweb-ref emacs_config + (use-package tab-bar + :config + (tab-bar-history-mode) + (defvar-keymap tab-bar-repeat-map + :repeat t + "" #'tab-bar-history-back + "" #'tab-bar-history-forward)) +#+END_SRC + ** Editing This configuration affects general text editing, across all modes. First, some packages: @@ -819,6 +850,9 @@ I find Emacs to be almost unusable on a normal keyboard unless there's some way #+END_SRC ** Language Support +:PROPERTIES: +:ID: 5CCB676B-9FF0-47B4-8AF2-10FD3899A646 +:END: #+BEGIN_SRC nix :noweb-ref emacs_packages consult-eglot @@ -837,192 +871,222 @@ I find Emacs to be almost unusable on a normal keyboard unless there's some way yaml-pro #+END_SRC +I had some weird problems with jsx code where the default M-q would just do a text fill rather than a re-indent. The solution seems to be to only do the ~syntax-ppss~ stuff if tree-sitter isn't available? It seems to work for now anyway... + #+BEGIN_SRC elisp :noweb-ref emacs_config - (use-package nix-mode - :mode "\\.nix\\'") - - (use-package nix-flake - :bind ("C-x p n" . project-nix-flake) + (use-package prog-mode :config - (defun project-nix-flake () + (defun prog-fill-reindent-defun (&optional argument) + "Refill or reindent the paragraph or defun that contains point. + + If the point is in a string or a comment, fill the paragraph that + contains point or follows point. + + Otherwise, reindent the function definition that contains point + or follows point." + (interactive "P") + (save-excursion + (let ((treesit-text-node + (and (treesit-available-p) + (treesit-parser-list) + (treesit-node-match-p + (treesit-node-at (point)) 'text t)))) + (if (or treesit-text-node + (and (not (and (treesit-available-p) (treesit-parser-list))) (nth 8 (syntax-ppss))) + (re-search-forward "\\s-*\\s<" (line-end-position) t)) + (fill-paragraph argument (region-active-p)) + (beginning-of-defun) + (let ((start (point))) + (end-of-defun) + (indent-region start (point) nil))))))) +#+END_SRC + +#+BEGIN_SRC elisp :noweb-ref emacs_config + (use-package nix-mode + :mode "\\.nix\\'") + + (use-package nix-flake + :bind ("C-x p n" . project-nix-flake) + :config + (defun project-nix-flake () + (interactive) + (nix-flake (project-root (project-current t))))) + + (use-package lua-mode + :mode "\\.lua\\'") + + (use-package jenkinsfile-mode + :mode "\\.jenkinsfile\\'") + + (setq major-mode-remap-alist '((rust-mode . rust-mode))) + + (use-package rust-mode + :init (setq rust-mode-treesitter-derive t)) + + (defun yaml-validate () (interactive) - (nix-flake (project-root (project-current t))))) + (compile (concat "yamllint -d '{extends: default, rules: {indentation: {indent-sequences: false}, braces: {max-spaces-inside: 1}}}' " (buffer-file-name)) t)) - (use-package lua-mode - :mode "\\.lua\\'") + (use-package yaml-ts-mode + :mode "\\.yaml\\'") - (use-package jenkinsfile-mode - :mode "\\.jenkinsfile\\'") + (use-package yaml-pro + :hook (yaml-ts-mode . yaml-pro-ts-mode)) - (setq major-mode-remap-alist '((rust-mode . rust-mode))) + (use-package sly + :hook lisp-mode-hook + :custom + (inferior-lisp-program "sbcl")) - (use-package rust-mode - :init (setq rust-mode-treesitter-derive t)) + (use-package sly-macrostep + :defer t + :after sly + :init + (add-to-list 'sly-contribs 'sly-macrostep)) - (defun yaml-validate () - (interactive) - (compile (concat "yamllint -d '{extends: default, rules: {indentation: {indent-sequences: false}, braces: {max-spaces-inside: 1}}}' " (buffer-file-name)) t)) + (use-package consult-eglot + :commands + consult-eglot-symbols) - (use-package yaml-ts-mode - :mode "\\.yaml\\'") + (use-package typescript-ts-mode + :mode "\\.ts\\'" ("\\.tsx\\'" . tsx-ts-mode) + :custom + (typescript-ts-mode-indent-offset 4) + (defun tsx-ts-mode--indent-compatibility-b893426 () + "Indent rules helper, to handle different releases of tree-sitter-tsx. + Check if a node type is available, then return the right indent rules." + ;; handle https://github.com/tree-sitter/tree-sitter-typescript/commit/b893426b82492e59388a326b824a346d829487e8 + (condition-case nil + (progn (treesit-query-capture 'tsx '((jsx_fragment) @capture)) + `(((match "<" "jsx_fragment") parent 0) + ((parent-is "jsx_fragment") parent typescript-ts-mode-indent-offset))) + (treesit-query-error + `(((match "<" "jsx_text") parent 0) + ((parent-is "jsx_text") grand-parent typescript-ts-mode-indent-offset)))))) - (use-package yaml-pro - :hook (yaml-ts-mode . yaml-pro-ts-mode)) + (use-package rust-ts-mode + :mode "\\.rs\\'" + :config + (bind-keys :map rust-ts-mode-map + ("C-c u" . string-inflection-rust-style-cycle))) - (use-package sly - :hook lisp-mode-hook - :custom - (inferior-lisp-program "sbcl")) + (use-package java-ts-mode + :mode "\\.java\\'" + :config + (bind-keys :map java-ts-mode-map + ("C-c u" . string-inflection-java-style-cycle))) - (use-package sly-macrostep - :defer t - :after sly - :init - (add-to-list 'sly-contribs 'sly-macrostep)) + (use-package sql-indent + :hook (sql-mode-hook . sqlind-minor-mode)) - (use-package consult-eglot - :commands - consult-eglot-symbols) + (use-package haskell-ts-mode + :mode "\\.hs\\'" + :custom (haskell-ts-use-indent tc)) - (use-package typescript-ts-mode - :mode "\\.ts\\'" ("\\.tsx\\'" . tsx-ts-mode) - :custom - (typescript-ts-mode-indent-offset 4) - (defun tsx-ts-mode--indent-compatibility-b893426 () - "Indent rules helper, to handle different releases of tree-sitter-tsx. - Check if a node type is available, then return the right indent rules." - ;; handle https://github.com/tree-sitter/tree-sitter-typescript/commit/b893426b82492e59388a326b824a346d829487e8 - (condition-case nil - (progn (treesit-query-capture 'tsx '((jsx_fragment) @capture)) - `(((match "<" "jsx_fragment") parent 0) - ((parent-is "jsx_fragment") parent typescript-ts-mode-indent-offset))) - (treesit-query-error - `(((match "<" "jsx_text") parent 0) - ((parent-is "jsx_text") grand-parent typescript-ts-mode-indent-offset)))))) + (use-package flymake + :bind + (:map prog-mode-map + ("C-c D" . flymake-show-project-diagnostics) + ("M-n" . flymake-goto-next-error) + ("M-p" . flymake-goto-prev-error))) - (use-package rust-ts-mode - :mode "\\.rs\\'" - :config - (bind-keys :map rust-ts-mode-map - ("C-c u" . string-inflection-rust-style-cycle))) + (use-package eglot + :commands eglot + :custom + (eglot-ignored-server-capabilities '(:inlayHintProvider)) + :config + (bind-keys :map eglot-mode-map + ("C-c A" . eglot-code-actions) + ("C-c R" . eglot-rename) + ("C-c I" . eglot-find-implementation)) + + (add-hook 'eglot-managed-mode-hook (lambda () (eglot-inlay-hints-mode -1)) nil t)) - (use-package java-ts-mode - :mode "\\.java\\'" - :config - (bind-keys :map java-ts-mode-map - ("C-c u" . string-inflection-java-style-cycle))) + (use-package lispy + :hook (emacs-lisp-mode lisp-mode) + :init (setq lispy-compat '(god-mode edebug)) + :config + (bind-keys :map lispy-mode-map + ("i" . (lambda () + (interactive) + (if god-global-mode + (god-mode-all -1) + (special-lispy-tab)))))) - (use-package sql-indent - :hook (sql-mode-hook . sqlind-minor-mode)) + (use-package smartparens + :hook + emacs-lisp-mode + common-lisp-mode + :config + (add-to-list 'sp-lisp-modes 'sly-mrepl-mode) + (require 'smartparens-config) + (setq sp-highlight-pair-overlay nil + sp-highlight-wrap-overlay nil + sp-highlight-wrap-tag-overlay nil)) - (use-package haskell-ts-mode - :mode "\\.hs\\'" - :custom (haskell-ts-use-indent tc)) + (setq-default indent-tabs-mode nil) + (setq-default tab-width 4) + (global-tree-sitter-mode 1) + (setq-default fill-column 100) + (defun jf-init-fill-column () + (display-fill-column-indicator-mode 1)) - (use-package flymake - :bind - (:map prog-mode-map - ("C-c D" . flymake-show-project-diagnostics) - ("M-n" . flymake-goto-next-error) - ("M-p" . flymake-goto-prev-error))) + (defvar jf/class-name-to-file-search-path (list "src/main/java" "src/test/java")) - (use-package eglot - :commands eglot - :custom - (eglot-ignored-server-capabilities '(:inlayHintProvider)) - :config - (bind-keys :map eglot-mode-map - ("C-c A" . eglot-code-actions) - ("C-c R" . eglot-rename) - ("C-c I" . eglot-find-implementation)) - - (add-hook 'eglot-managed-mode-hook (lambda () (eglot-inlay-hints-mode -1)) nil t)) + (defun jf/class-name-to-file (class-name) + (let ((root (project-root (project-current t))) + (fragment (format "%s.java" (replace-regexp-in-string "\\." "/" class-name))) + (result)) + (dolist (p jf/class-name-to-file-search-path result) + (unless result + (let ((path (format "%s/%s" p fragment))) + (when (file-exists-p (concat root path)) + (setq result path))))))) - (use-package lispy - :hook (emacs-lisp-mode lisp-mode) - :init (setq lispy-compat '(god-mode edebug)) - :config - (bind-keys :map lispy-mode-map - ("i" . (lambda () - (interactive) - (if god-global-mode - (god-mode-all -1) - (special-lispy-tab)))))) + (defun jf/compile-class-to-file () + (jf/class-name-to-file (concat (match-string 1) (match-string 2)))) - (use-package smartparens - :hook - emacs-lisp-mode - common-lisp-mode - :config - (add-to-list 'sp-lisp-modes 'sly-mrepl-mode) - (require 'smartparens-config) - (setq sp-highlight-pair-overlay nil - sp-highlight-wrap-overlay nil - sp-highlight-wrap-tag-overlay nil)) + ;(add-to-list 'compilation-error-regexp-alist-alist + ; '(java-stack-trace . + ; ("^[[:space:]]*at \\(\\(?:[[:lower:]]+\\.\\)+\\)[^(]+(\\([[:alnum:]]+\\)\\.java:\\([[:digit:]]+\\))" + ; jf/compile-class-to-file 3))) + ;(add-to-list 'compilation-error-regexp-alist 'java-stack-trace) - (setq-default indent-tabs-mode nil) - (setq-default tab-width 4) - (global-tree-sitter-mode 1) - (setq-default fill-column 100) - (defun jf-init-fill-column () - (display-fill-column-indicator-mode 1)) + (add-hook 'prog-mode-hook 'jf-init-fill-column) + (add-hook 'java-mode-hook (lambda () (c-set-offset 'arglist-intro '+))) - (defvar jf/class-name-to-file-search-path (list "src/main/java" "src/test/java")) + (dolist (hook + (list 'grep-mode-hook + 'flymake-project-diagnostics-mode-hook + 'xref--xref-buffer-mode-hook + 'embark-collect-mode-hook + 'compilation-mode-hook + 'sly-mrepl-mode-hook + 'eglot-list-connections-mode-hook)) + (add-hook hook 'tab-line-mode)) - (defun jf/class-name-to-file (class-name) - (let ((root (project-root (project-current t))) - (fragment (format "%s.java" (replace-regexp-in-string "\\." "/" class-name))) - (result)) - (dolist (p jf/class-name-to-file-search-path result) - (unless result - (let ((path (format "%s/%s" p fragment))) - (when (file-exists-p (concat root path)) - (setq result path))))))) + (let ((bottom-window-params '((side . bottom) + (slot . 1) + (window-height . 0.33) + (window-parameters (no-delete-other-windows . t)))) + (right-window-params '((side . right) + (window-width . 0.5) + (window-parameters (no-delete-other-windows . t))))) + (setopt display-buffer-alist + (mapcar (lambda (buffer) `(,buffer + (display-buffer-reuse-window display-buffer-in-side-window) + ,@bottom-window-params)) + (list + "\\*Flymake diagnostics *" + "\\*Embark Export *" + "\\*Embark Collect *" + "\\*xref*" + "\\*compilation\\*" + "\\*sly-mrepl *" + "\\*Messages\\*" + "\\*EGLOT connections\\*")))) - (defun jf/compile-class-to-file () - (jf/class-name-to-file (concat (match-string 1) (match-string 2)))) - - ;(add-to-list 'compilation-error-regexp-alist-alist - ; '(java-stack-trace . - ; ("^[[:space:]]*at \\(\\(?:[[:lower:]]+\\.\\)+\\)[^(]+(\\([[:alnum:]]+\\)\\.java:\\([[:digit:]]+\\))" - ; jf/compile-class-to-file 3))) - ;(add-to-list 'compilation-error-regexp-alist 'java-stack-trace) - - (add-hook 'prog-mode-hook 'jf-init-fill-column) - (add-hook 'java-mode-hook (lambda () (c-set-offset 'arglist-intro '+))) - - (dolist (hook - (list 'grep-mode-hook - 'flymake-project-diagnostics-mode-hook - 'xref--xref-buffer-mode-hook - 'embark-collect-mode-hook - 'compilation-mode-hook - 'sly-mrepl-mode-hook - 'eglot-list-connections-mode-hook)) - (add-hook hook 'tab-line-mode)) - - (let ((bottom-window-params '((side . bottom) - (slot . 1) - (window-height . 0.33) - (window-parameters (no-delete-other-windows . t)))) - (right-window-params '((side . right) - (window-width . 0.5) - (window-parameters (no-delete-other-windows . t))))) - (setopt display-buffer-alist - (mapcar (lambda (buffer) `(,buffer - (display-buffer-reuse-window display-buffer-in-side-window) - ,@bottom-window-params)) - (list - "\\*Flymake diagnostics *" - "\\*Embark Export *" - "\\*Embark Collect *" - "\\*xref*" - "\\*compilation\\*" - "\\*sly-mrepl *" - "\\*Messages\\*" - "\\*EGLOT connections\\*")))) - - (setq ediff-split-window-function 'split-window-horizontally) + (setq ediff-split-window-function 'split-window-horizontally) #+END_SRC ** Envrc @@ -1039,6 +1103,9 @@ I find Emacs to be almost unusable on a normal keyboard unless there's some way #+END_SRC ** Magit +:PROPERTIES: +:ID: 4F426E77-CE03-4BF8-8D1B-7791C7C02B28 +:END: #+BEGIN_SRC nix :noweb-ref emacs_packages consult-gh @@ -1073,6 +1140,9 @@ I find Emacs to be almost unusable on a normal keyboard unless there's some way #+END_SRC ** Vertico +:PROPERTIES: +:ID: 6D1A8B35-3093-4DA6-A5AA-2A0D45112BAB +:END: #+BEGIN_SRC nix :noweb-ref emacs_packages cape @@ -1088,15 +1158,16 @@ I find Emacs to be almost unusable on a normal keyboard unless there's some way #+BEGIN_SRC elisp :noweb-ref emacs_config (use-package consult :bind ( - ("C-c M-x" . consult-mode-command) + ;; ("C-c M-x" . consult-mode-command) ("C-c h" . consult-history) - ("C-c k" . consult-kmacro) - ("C-c m" . consult-man) - ([remap Info-search] . consult-info) + ;; ("C-c k" . consult-kmacro) + ;; ("C-c m" . consult-man) + ;; ([remap Info-search] . consult-info) - ("C-x M-:" . consult-complex-command) + ;; ("C-x M-:" . consult-complex-command) ("C-x b" . consult-buffer) - ("s-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) @@ -1193,9 +1264,13 @@ I find Emacs to be almost unusable on a normal keyboard unless there's some way #+END_SRC ** Org +:PROPERTIES: +:ID: 3B0BFCDC-DFD5-42A0-97D8-3B032B128AF7 +:END: #+BEGIN_SRC nix :noweb-ref emacs_packages org-bullets + org-roam verb #+END_SRC @@ -1207,7 +1282,8 @@ I find Emacs to be almost unusable on a normal keyboard unless there's some way ("C-c l" . org-store-link)) :config (add-hook 'org-mode-hook 'visual-line-mode) - (setq org-todo-keywords + (setq org-link-keep-stored-after-insertion t + org-todo-keywords '((sequence "TODO(o)" "IN_PROGRESS(p!)" @@ -1242,7 +1318,18 @@ I find Emacs to be almost unusable on a normal keyboard unless there's some way org-agenda-files '("~/org/todo.org") org-agenda-todo-ignore-scheduled 'future org-agenda-todo-ignore-with-date t - org-agenda-tags-todo-honor-ignore-options t)) + org-agenda-tags-todo-honor-ignore-options t + org-id-link-to-org-use-id t)) + + (use-package org-roam + :bind (("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)) + :config + (setq org-roam-node-display-template (concat "${title:*} " (propertize "${tags:10}" 'face 'org-tag))) + (org-roam-db-autosync-mode)) (use-package org-bullets :hook org-mode-hook)