nix/ext/doom/config.el

516 lines
19 KiB
EmacsLisp

;;; $DOOMDIR/config.el -*- lexical-binding: t; -*-
;; Place your private configuration here! Remember, you do not need to run 'doom
;; sync' after modifying this file!
;; Some functionality uses this to identify you, e.g. GPG configuration, email
;; clients, file templates and snippets. It is optional.
;; (setq user-full-name "John Doe"
;; user-mail-address "john@doe.com")
;; Doom exposes five (optional) variables for controlling fonts in Doom:
;;
;; - `doom-font' -- the primary font to use
;; - `doom-variable-pitch-ont' -- a non-monospace font (where applicable)
;; - `doom-big-font' -- used for `doom-big-font-mode'; use this for
;; presentations or streaming.
;; - `doom-unicode-font' -- for unicode glyphs
;; - `doom-serif-font' -- for the `fixed-pitch-serif' face
;;
;; See 'C-h v doom-font' for documentation and more examples of what they
;; accept. For example:
;;
(setq nerd-icons-font-names '("SymbolsNerdFontMono-Regular.ttf"))
;; NOTE Floats are important for dpi support for some reason
(setq doom-font (font-spec :family "Iosevka Nerd Font Mono" :size 14.0)
doom-variable-pitch-font (font-spec :family "Iosevka Nerd Font Mono" :size 14.0)
;; doom-symbol-font (font-spec :family "all-the-icons" :size 13.0)
doom-big-font (font-spec :family "Iosevka Nerd Font Mono" :size 18.0 :weight 'demibold))
(defun add-back-emoji-fallback-font-families ()
(when (fboundp 'set-fontset-font)
(let ((fn (doom-rpartial #'member (font-family-list))))
(when-let (font (cl-find-if fn doom-emoji-fallback-font-families))
(set-fontset-font t 'unicode font nil 'append)))))
;; (add-hook 'after-setting-font-hook 'add-back-emoji-fallback-font-families)
;;
;; If you or Emacs can't find your font, use 'M-x describe-font' to look them
;; up, `M-x eval-region' to execute elisp code, and 'M-x doom/reload-font' to
;; refresh your font settings. If Emacs still can't find your font, it likely
;; wasn't installed correctly. Font issues are rarely Doom issues!
;; There are two ways to load a theme. Both assume the theme is installed and
;; available. You can either set `doom-theme' or manually load a theme with the
;; `load-theme' function. This is the default:
(setq doom-theme 'doom-gruvbox)
;; This determines the style of line numbers in effect. If set to `nil', line
;; numbers are disabled. For relative line numbers, set this to `relative'.
(setq display-line-numbers-type t)
;; If you use `org' and don't want your org files in the default location below,
;; change `org-directory'. It must be set before org loads!
(setq org-directory "~/org/")
;; Encrypt all roam notes;;;;;;;;;;;;;;;;;
(after! org-roam
;; Org Roam ui is better
(setq +org-roam-open-buffer-on-find-file nil)
(setq org-roam-link-auto-replace t)
(setq-default epa-file-encrypt-to "tristandruyen@vault81.de")
;; (setq org-roam-capture-templates '(("d" "default" plain "%?"
;; :target
;; (file+head "%<%Y%m%d%H%M%S>-${slug}.org.gpg"
;; "#+title: ${title}\n")
;; :unnarrowed t)))
;; (setq org-roam-dailies-capture-templates '(("d" "default" entry "* %?"
;; :target
;; (file+head "%<%Y-%m-%d>.org.gpg"
;; "#+title: %<%Y-%m-%d>\n")
;; :unnarrowed t)))
;;
)
(after! evil-goggles
(setq! evil-goggles-duration 0.15
evil-goggles-pulse 't ; too slow
;; evil-goggles provides a good indicator of what has been affected.
;; delete/change is obvious, so I'd rather disable it for these.
evil-goggles-enable-delete 't
evil-goggles-enable-change 't)
(evil-goggles-use-diff-faces))
;; Whenever you reconfigure a package, make sure to wrap your config in an
;; `after!' block, otherwise Doom's defaults may override your settings. E.g.
;;
;; (after! PACKAGE
;; (setq x y))
;;
;; The exceptions to this rule:
;;
;; - Setting file/directory variables (like `org-directory')
;; - Setting variables which explicitly tell you to set them before their
;; package is loaded (see 'C-h v VARIABLE' to look up their documentation).
;; - Setting doom variables (which start with 'doom-' or '+').
;;
;; Here are some additional functions/macros that will help you configure Doom.
;;
;; - `load!' for loading external *.el files relative to this one
;; - `use-package!' for configuring packages
;; - `after!' for running code after a package has loaded
;; - `add-load-path!' for adding directories to the `load-path', relative to
;; this file. Emacs searches the `load-path' when you load packages with
;; `require' or `use-package'.
;; - `map!' for binding new keys
;;
;; To get information about any of these functions/macros, move the cursor over
;; the highlighted symbol at press 'K' (non-evil users must press 'C-c c k').
;; This will open documentation for it, including demos of how they are used.
;; Alternatively, use `C-h o' to look up a symbol (functions, variables, faces,
;; etc).
;;
;; You can also try 'gd' (or 'C-c c d') to jump to their definition and see how
;; they are implemented.
;; TRAMP
;; (add-to-list 'tramp-connection-properties
;; (list (regexp-quote "/sshx:user@host:")
;; "remote-shell" "/usr/bin/fish"))
;;
;; (eval-after-load 'tramp
;; '((setenv "SHELL" "/run/current-system/sw/bin/fish")
;; (setenv "ESHELL" "/run/current-system/sw/bin/fish")
;; (add-to-list 'tramp-remote-path
;; "/run/current-system/sw/bin")
;; )
;; )
;; (setq! tramp-default-method "ssh")
;; (use-package treesit-auto
;; :custom
;; (treesit-auto-install 'prompt)
;; :config
;; (treesit-auto-langs '(python rust go))
;; ;; (treesit-auto-add-to-auto-mode-alist 'all)
;; (global-treesit-auto-mode))
(use-package ultra-scroll
:init
(setq scroll-conservatively 101 ;; important!
scroll-margin 0)
:config
(ultra-scroll-mode 1))
(use-package! codemetrics)
(use-package! cognitive-complexity) ;; codemetrics for treesit
;; TODO Add fn bound to `SPC t ???` which toggles cog-compl mode for treesit-buffers & codemetrics for normal ones
;; Eat (Native Term Emu)
(use-package! eat
:custom
(eat-shell "fish")
(explicit-shell-file-name "/etc/profiles/per-user/tristand/bin/fish") ;; TODO username dependant
:config
(add-hook 'eshell-first-time-mode-hook
#'eat-eshell-visual-command-mode)
(add-hook 'eshell-first-time-mode-hook #'eat-shell-mode))
;; awatch
(use-package! activity-watch-mode
:config
(global-activity-watch-mode))
;; lsp-booster
(use-package lsp-booster
:after lsp)
(use-package! eglot-booster
:after eglot
:config
(eglot-booster-mode))
(use-package! treesit-fold
:after tree-sitter)
(use-package! eglot-x
:after eglot
:commands (eglot-x-setup))
;; rust
(setq! lsp-inlay-hint-enable t)
(setq! lsp-rust-analyzer-cargo-run-build-scripts t)
(setq! lsp-rust-analyzer-proc-macro-enable t)
(setq! lsp-rust-analyzer-server-display-inlay-hints t)
(setq! lsp-rust-analyzer-completion-auto-import-enable t)
;; Nix
(use-package! nixpkgs-fmt
:hook (nix-mode . nixpkgs-fmt-on-save-mode))
;; Shell stuff;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(setq shell-file-name (executable-find "bash"))
(setq-default vterm-shell (executable-find "fish"))
;; Background Transparency + Toggling
(defun set-frame-bg-opacity (opacity)
;Interactively change the current frames background opacity.
; OPACITY is an integer between 0 to 100, inclusive.
(interactive
(list (read-number "Opacity (0-100): "
(or (frame-parameter nil 'alpha)
100))))
(set-frame-parameter nil 'alpha-background opacity))
(defun toggle-bg-transparency ()
;Toggle between transparent and opaque background.
(interactive)
(let ((alpha-background (frame-parameter nil 'alpha-background)))
(set-frame-bg-opacity
(if (eql (cond
((numberp alpha-background) alpha-background)
(t 100))
100)
90 100)
)))
(map! :leader
(:prefix-map ("t" . "toggle")
(:prefix ("T" . "Transparancy")
:desc "Toggle background transparancy" "b" #'toggle-bg-transparency)))
(defun setup-frame-transparency (frame)
(set-frame-parameter frame 'alpha-background 90))
(add-hook 'after-make-frame-functions #'setup-frame-transparency)
;; TABS;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(setq! uniquify-separator "/")
(setq! uniquify-buffer-name-style 'forward)
(use-package centaur-tabs
:init
(setq centaur-tabs-enable-key-bindings t)
:config
(setq centaur-tabs-style "wave"
centaur-tabs-height 32
centaur-tabs-set-icons t
centaur-tabs-show-new-tab-button t
centaur-tabs-show-navigation-buttons t
centaur-tabs-set-bar 'under
centaur-tabs-show-count t
centaur-tabs-gray-out-icons 'buffer
x-underline-at-descent-line t
centaur-tabs-set-modified-marker t
centaur-tabs-modified-marker ""
centaur-tabs-close-button "x"
centaur-tabs-cycle-scope 'tabs
centaur-tabs-adjust-buffer-order t
centaur-tabs-left-edge-margin nil)
(centaur-tabs-change-fonts (face-attribute 'default :font) 110)
(centaur-tabs-headline-match)
(centaur-tabs-group-by-projectile-project)
;; (centaur-tabs-enable-buffer-alphabetical-reordering)
(centaur-tabs-mode t)
(defvar categories-alist
'(
(:name "org" :modes (org-mode org-agenda-mode) :buffer-name () :type global)
(:name "gptel" :modes nil :buffer-name ("*llama-cpp*" "*llama-cpp-code*" "*llama-cpp-bigchat*" "*llama-cpp-biggerchat*" "*gptel*" "*groq*" "*gptel-context*" "*gptel-query*") :type global)
(:name "terminal" :modes (vterm-mode term-mode) :buffer-name () :type per-project)
(:name "misc" :modes (+doom-dashboard-mode native-comp-limple-mode messages-buffer-mode) :buffer-name () :type global)
(:name "misc" :modes (special-mode fundamental-mode) :buffer-name () :type per-project)
)
"Mapping of categories to modes with their respective type logic.")
(defun get-project-name-or-default (default-name)
"Return the project name if available, or DEFAULT-NAME."
(if-let ((project-root (condition-case _err
(projectile-project-root)
(error nil))))
(concat (projectile-project-name) "::" default-name)
default-name))
(defun get-category-name (buffer)
"Get category name for the given BUFFER."
(let (category-name)
(dolist (category categories-alist category-name)
(let ((buffer-names (plist-get category :buffer-name))
(modes (plist-get category :modes)))
(cond
((and buffer-names (member (buffer-name buffer) buffer-names))
(setq category-name
(if (eq (plist-get category :type) 'per-project)
(get-project-name-or-default (plist-get category :name))
(plist-get category :name))))
((and modes (with-current-buffer buffer (memq major-mode modes)))
(setq category-name
(if (eq (plist-get category :type) 'per-project)
(get-project-name-or-default (plist-get category :name))
(plist-get category :name)))))))))
(defun centaur-tabs-group-name-by-category ()
"Get tab group name based on category."
(let ((mode-category (get-category-name (current-buffer))))
(if mode-category
(list mode-category)
(list (get-project-name-or-default "main")))))
(defun centaur-tabs-projectile-buffer-groups ()
"Return the list of group names BUFFER belongs to."
(if centaur-tabs-projectile-buffer-group-calc
(symbol-value 'centaur-tabs-projectile-buffer-group-calc)
(set (make-local-variable 'centaur-tabs-projectile-buffer-group-calc)
(centaur-tabs-group-name-by-category))))
(add-hook! '(+doom-dashboard-mode-hook +popup-buffer-mode-hook)
(defun +tabs-disable-centaur-tabs-mode-maybe-h ()
"Disable `centaur-tabs-mode' in current buffer."
(when (centaur-tabs-mode-on-p)
(centaur-tabs-local-mode))))
)
;; ruby
(setq! lsp-ruby-lsp-use-bundler t)
;; Copilot
;; accept completion from copilot and fallback to company
;; (use-package! copilot
;; :hook (prog-mode . copilot-mode)
;; :bind (:map copilot-completion-map
;; ("<backtab>" . 'copilot-clear-overlay)
;; ("<left>" . 'copilot-previous-completion)
;; ("<right>" . 'copilot-next-completion)
;; ("<tab>" . 'copilot-accept-completion)
;; ("TAB" . 'copilot-accept-completion)
;; ("C-TAB" . 'copilot-accept-completion-by-word)
;; ("C-<tab>" . 'copilot-accept-completion-by-word)))
;; gptel
;;(require 'gptel)
(use-package! gptel
:init
:config
(defun read-api-secret (secret-file)
(with-temp-buffer
(insert-file-contents (expand-file-name secret-file "~"))
(string-trim (buffer-substring-no-properties (point-min) (point-max)))))
;; Default Model
;; TODO Consider switching to coder
(setq! gptel-backend
(gptel-make-openai "llama-cpp"
:stream t
:protocol "http"
:host "100.64.0.3:18080"
:models '("llama-cpp-code")))
(setq! gptel-model "llama-cpp-code")
;; nicer org mode foo
(setq! gptel-default-mode 'org-mode)
(setq! gptel-org-branching-context t)
(setf (alist-get 'org-mode gptel-prompt-prefix-alist) "@user ")
(setf (alist-get 'org-mode gptel-response-prefix-alist) "@assistant ")
;; Qwen-2.5-Coder-32B / Tabby model
(gptel-make-openai "llama-cpp-biggerchat"
:stream t
:protocol "http"
:host "100.64.0.3:18083"
:models '("llama-cpp-biggerchat"))
;; Groq API
(gptel-make-openai "groq"
:host "api.groq.com"
:endpoint "/openai/v1/chat/completions"
:stream t
:key (read-api-secret ".groq_api_key")
:models '("llama3-70b-8192"
"mixtral-8x7b-32768"
"llama3-8b-8192"))
(setq! gptel-directives '((default
. "You are a large language model living in Emacs and a helpful assistant. Respond concisely.")
(programming
. "You are a large language model and a careful programmer. Provide code and only code as output without any additional text, prompt or note.")
(writing
. "You are a large language model and a writing assistant. Respond concisely.")
(chat
. "You are a large language model and a conversation partner. Respond concisely."))
gptel-expert-commands t
gptel-temperature 0.2)
(add-hook 'gptel-post-response-functions 'gptel-end-of-response)
(add-hook 'gptel-post-stream-hook 'gptel-auto-scroll)
(map! :leader
"<tab>" 'gptel-send
"TAB" 'gptel-send))
(use-package! gptel-extensions
:after gptel)
(use-package! llm)
(use-package! magit-gptcommit
:after magit llm
:demand t
:bind (:map git-commit-mode-map
("C-c C-g" . magit-gptcommit-commit-accept))
:init
(require 'llm-openai)
;; Helper function for writing a prompt for Magit GPTCommit
(defun join-with-newlines (list)
(mapconcat 'identity list "\n"))
:custom
(llm-warn-on-nonfree nil)
(magit-gptcommit-llm-provider (make-llm-openai-compatible :key "OPENAI-KEY" :url "http://100.64.0.3:18080/v1/"))
;; TODO Test different prompts
(magit-gptcommit-prompt
(join-with-newlines
'(
"You are an expert programmer writing a commit message"
"You went over every file diff that was changed in it."
"First Determine the best label for the diffs."
"Here are the labels you can choose from:"
"- build: Changes that affect the build system or external dependencies (example scopes: gulp, broccoli, npm)"
"- chore: Updating libraries, copyrights or other repo setting, includes updating dependencies."
"- ci: Changes to our CI configuration files and scripts (example scopes: Travis, Circle, GitHub Actions)"
"- docs: Non-code changes, such as fixing typos or adding new documentation"
"- feat: a commit of the type feat introduces a new feature to the codebase"
"- fix: A commit of the type fix patches a bug in your codebase"
"- perf: A code change that improves performance"
"- refactor: A code change that neither fixes a bug nor adds a feature"
"- style: Changes that do not affect the meaning of the code (white-space, formatting, missing semi-colons, etc)"
"- test: Adding missing tests or correcting existing tests"
""
"Then summarize the commit into a single specific and cohesive theme."
"Remember to write a one line summary, no more than 50 characters."
"If it is a simple change no need for additional lines."
"If there are multiple unrelated or complicated changes summarize them into bullet points"
"Remember to write an empty line between the summary and bullet points."
""
"Write your response using the imperative tense following the kernel git commit style guide."
"Write a high level title."
""
"# Example 1:"
"refactor: Rework transaction merging logic"
""
"- use functional style instead of nested for loops"
"- cache intermediate results"
"- use refs instead of cloning everywhere"
""
"# Example 2:"
"fix: Fix off-by-one integer in loop"
"# Example 3:"
"style: Add missing semicolon"
"THE FILE DIFFS:"
"```"
"%s"
"```"
"Now write Commit message in follow template: [label]:[one line of summary] :"
)))
;; :init
;; (setq magit-gptcommit-llm-provider (make-llm-openai-compatible :key "OPENAI-KEY" :url "http://100.64.0.3:8080/v1/"))
:config
(magit-gptcommit-mode 1)
(magit-gptcommit-status-buffer-setup))
;; (setq! magit-gptcommit-llm-provider (make-llm-openai-compatible :key "OPENAI-KEY" :url "http://100.64.0.3:8080/v1/")
(defvar my-C-f-funcs '())
(defun my-C-f ()
(interactive)
(unless (call-interactively 'tabby-accept-completion)
(forward-char)))
(use-package! tabby
:hook
(rustic-mode . tabby-mode)
(rust-ts-mode . tabby-mode)
:init
(setq tabby-idle-delay 0.5)
(setq tabby--connection "http://100.64.0.3:8083")
:config
(add-to-list 'my-C-f-funcs 'tabby-accept-completion)
;; (evil-define-key 'insert tabby-mode-map (kbd "C-f") 'tabby-accept-completion)
;; (evil-define-key 'insert tabby-mode-map (kbd "C-f") 'my-C-f)
(evil-define-key 'insert tabby-mode-map (kbd "C-f") 'my-C-f)
(evil-define-key 'insert tabby-mode-map (kbd "C-M-j") 'tabby-dismiss)
(evil-define-key 'insert tabby-mode-map (kbd "C-M-l") 'tabby-accept-completion-by-line))