summaryrefslogtreecommitdiff
path: root/config.el
diff options
context:
space:
mode:
Diffstat (limited to 'config.el')
-rw-r--r--config.el412
1 files changed, 203 insertions, 209 deletions
diff --git a/config.el b/config.el
index e19fee3..f3fafc4 100644
--- a/config.el
+++ b/config.el
@@ -1,8 +1,4 @@
;;; config.el --- Emacs-Kick --- A feature rich Emacs config for (neo)vi(m)mers -*- lexical-binding: t; -*-
-(setenv "LSP_USE_PLISTS" "true")
-;; (setq debug-on-error t)
-;; (setenv "LSP_USE_PLISTS" "true")
-;; (setq lsp-use-plists t)
(setq pgtk-wait-for-event-timeout 0.001)
(setq package-enable-at-startup nil)
;; (setq-default mode-line-format t) ;; disabled: boolean t is not valid for mode-line-format
@@ -1115,23 +1111,6 @@ TITLE names the new denote-style file in ~/org."
-(use-package kitty-graphics
- :ensure (:host github :repo "cashmeredev/kitty-graphics.el")
- :demand t
- :custom
- (kitty-graphics-enable-video t)
- (kitty-graphics-shr-scale 'fit)
- (kitty-graphics-shr-fit-width 0.4)
- (kitty-graphics-shr-fit-height 20)
- (kitty-graphics-doc-view-resolution-scale 2.0)
- :hook (dired-mode . kitty-graphics-dired-auto-preview-mode)
- :config
- (setq kitty-graphics-enable-browser t
- kitty-graphics-casty-program "~/projects/casty/bin/casty.js"
- kitty-graphics-casty-chrome "helium-browser")
-
- (kitty-graphics-setup))
-
(with-eval-after-load 'org
(setq org-confirm-babel-evaluate nil)
(org-babel-do-load-languages
@@ -1492,10 +1471,6 @@ Skips capture tasks and projects."
(defun my/org-capture-meeting-to-journal ()
(my/org-capture-to-journal "\n* Meeting: "))
-(with-eval-after-load 'eglot
- (add-to-list 'eglot-server-programs
- '(org-mode . ("harper-ls" "--stdio"))))
-
(defun my/org-capture-task-to-journal ()
(let* ((context (read-string "Task: "))
(todo-state (completing-read "TODO state: "
@@ -2239,16 +2214,22 @@ Timers that expired while Emacs was closed fire immediately."
(use-package company
:ensure t
+ :demand t
:hook (after-init . global-company-mode)
:custom
- (company-idle-delay 0)
- (company-tooltip-idle-delay 0)
- (company-minimum-prefix-length 2)
+ (company-idle-delay nil)
+ ;; (company-minimum-prefix-length 2)
(company-require-match nil)
- (company-frontends
- '(company-pseudo-tooltip-unless-just-one-frontend
- company-echo-metadata-frontend))
- (company-backends '(company-capf)))
+ (company-transformers '(my/company-limit-candidates))
+ (company-backends '(company-capf))
+ :config
+ (defun my/company-limit-candidates (candidates)
+ (seq-take candidates 4))
+
+ (define-key company-mode-map [remap indent-for-tab-command]
+ #'company-manual-begin)
+ (define-key company-mode-map [remap c-indent-line-or-region]
+ #'company-manual-begin))
(use-package which-key
:ensure t
@@ -2273,13 +2254,7 @@ Timers that expired while Emacs was closed fire immediately."
;; used by `completion-at-point'. The order of the functions matters, the
;; first function returning a result wins. Note that the list of buffer-local
;; completion functions takes precedence over the global list.
- (add-hook 'completion-at-point-functions #'cape-file)
- ;; (add-hook 'completion-at-point-functions #'cape-history)
- ;; ...
- :config
- (with-eval-after-load 'eglot
- (advice-add 'eglot-completion-at-point :around #'cape-wrap-noninterruptible)
- (advice-add 'eglot-completion-at-point :around #'cape-wrap-buster)))
+ (add-hook 'completion-at-point-functions #'cape-file))
(use-package embark
:ensure (:wait t)
@@ -2319,7 +2294,6 @@ Timers that expired while Emacs was closed fire immediately."
"\\`\\*scratch\\*\\'"
"\\`\\*Completions\\*\\'"
"\\`\\*Flymake"
- "\\`\\*lsp-help\\*\\'"
"\\`\\*eldoc"
"\\`\\*elpaca-log\\*\\'"
"\\`\\*Native-compile-Log\\*\\'"
@@ -2336,47 +2310,191 @@ Timers that expired while Emacs was closed fire immediately."
(use-package citre
:ensure t
- :defer t
+ :demand t
:init
(require 'citre-config)
:custom
(citre-default-create-tags-file-location 'in-dir)
(citre-edit-ctags-options-manually nil)
(citre-auto-enable-citre-mode-modes '(prog-mode))
- :bind (("C-c e" . citre-jump)
- ("C-c u" . citre-update-this-tags-file)))
-
-(use-package eglot
- :ensure nil
:config
- ;; nil: LSP server stays alive when last managed buffer closes.
- ;; Verhindert churn bei org src edit buffers (C-c ' macht buffer auf/zu
- ;; → mit t neuer pyrefly process jedes Mal).
- (setq eglot-autoshutdown nil)
- (setq eglot-send-changes-idle-time 0.1)
- (setq eglot-sync-connect nil)
- (setq eglot-connect-timeout 30)
- (setq eglot-events-buffer-size 0)
- (setq eglot-report-progress nil)
- (setq jsonrpc-default-request-timeout 10))
-
- ;; (add-hook 'eglot-managed-mode-hook
- ;; (lambda ()
- ;; (eglot-inlay-hints-mode -1)))
+ (defconst my/project-ctags-nix-options
+ '("--langdef=nix"
+ "--map-nix=+.nix"
+ "--kinddef-nix=a,attribute,attributes"
+ "--regex-nix=/^[[:space:]]*([A-Za-z_][A-Za-z0-9_'-]*(\\.[A-Za-z_][A-Za-z0-9_'-]+)+)[[:space:]]*=[^=]/\\1/a/"
+ "--regex-nix=/^[[:space:]]*([A-Za-z_][A-Za-z0-9_'-]*)[[:space:]]*=[^=]/\\1/a/"))
+
+ (defun my/project-ctags-root ()
+ (or (projectile-project-root)
+ (user-error "Not in a Projectile project")))
+
+ (defun my/project-ctags-nixpkgs (root)
+ (when (and (file-directory-p (expand-file-name "npins" root))
+ (executable-find "npins"))
+ (let ((default-directory root)
+ (output (generate-new-buffer " *npins*")))
+ (unwind-protect
+ (when (zerop (process-file "npins" nil output nil
+ "get-path" "nixpkgs"))
+ (with-current-buffer output
+ (string-trim (buffer-string))))
+ (kill-buffer output)))))
+
+ (defun my/project-ctags-nixos-options (nixpkgs output)
+ (let ((expression
+ (format
+ "let
+ nixpkgs = %S;
+ evaluated = import (nixpkgs + \"/nixos/lib/eval-config.nix\") {
+ system = builtins.currentSystem;
+ modules = [ ];
+ };
+ collect = prefix: attrs:
+ builtins.concatLists (builtins.map
+ (name:
+ let value = attrs.${name}; in
+ if builtins.isAttrs value && (value._type or null) == \"option\"
+ then
+ if value.declarations == [ ] then [ ] else [
+ [
+ (builtins.concatStringsSep \".\" (prefix ++ [ name ]))
+ (builtins.toString (builtins.head value.declarations))
+ ]
+ ]
+ else if builtins.isAttrs value then collect (prefix ++ [ name ]) value
+ else [ ])
+ (builtins.attrNames attrs));
+in
+ builtins.concatStringsSep \"\\n\" (builtins.map builtins.toJSON (collect [ ] evaluated.options))"
+ nixpkgs)))
+ (with-current-buffer output
+ (erase-buffer))
+ (if (zerop (process-file "nix-instantiate" nil output nil
+ "--eval" "--raw" "--strict"
+ "--expr" expression))
+ (mapcar (lambda (line)
+ (json-parse-string line :array-type 'list))
+ (split-string (with-current-buffer output
+ (buffer-string))
+ "\n" t))
+ (user-error "Could not evaluate NixOS options"))))
- ;; (setq eglot-code-action-indications '(eldoc-hint))
+ (defun my/project-ctags-add-nixos-options (tags-file root output)
+ (when-let* ((nixpkgs (my/project-ctags-nixpkgs root)))
+ (condition-case err
+ (let (headers tags)
+ (dolist (line (with-temp-buffer
+ (insert-file-contents tags-file)
+ (split-string (buffer-string) "\n" t)))
+ (if (string-prefix-p "!" line)
+ (push line headers)
+ (push line tags)))
+ (dolist (option (my/project-ctags-nixos-options nixpkgs output))
+ (pcase-let ((`(,name ,file) option))
+ (push (format "%s\t%s\t1;\"\tkind:attribute\tlanguage:nix\troles:def"
+ name file)
+ tags)))
+ (with-temp-file tags-file
+ (dolist (line (nreverse headers))
+ (insert line "\n"))
+ (dolist (line (sort (delete-dups tags) #'string<))
+ (insert line "\n"))))
+ (error
+ (message "NixOS option tags unavailable: %s"
+ (error-message-string err))))))
- ;; (setq eglot-ignored-server-capabilities
- ;; '(:inlayHintProvider :documentHighlightProvider)))
+ (defun my/project-ctags-files (root)
+ (let ((default-directory root)
+ files)
+ (dolist (file (projectile-current-project-files))
+ (unless (string= file ".tags")
+ (when (file-regular-p (expand-file-name file root))
+ (push (expand-file-name file root) files))))
+ (nreverse files)))
+
+
+ (defun my/project-ctags-enable-citre (root)
+ (dolist (buffer (buffer-list))
+ (with-current-buffer buffer
+ (when (and buffer-file-name
+ (file-in-directory-p buffer-file-name root))
+ (citre-mode 1)))))
+ (defun my/project-ctags-start (root)
+ (let* ((ctags (executable-find "ctags"))
+ (tags-file (expand-file-name ".tags" root))
+ (list-file (make-temp-file "citre-files-"))
+ (temporary-tags-file (make-temp-file "citre-tags-"))
+ (output (get-buffer-create "*citre-ctags*"))
+ (files (my/project-ctags-files root)))
+ (unless ctags
+ (user-error "Universal Ctags is not available"))
+ (unless files
+ (user-error "No project files to tag"))
+ (with-temp-file list-file
+ (dolist (file files)
+ (insert file "\n")))
+ (with-current-buffer output
+ (erase-buffer))
+ (make-process
+ :name (format "ctags:%s" (file-name-nondirectory (directory-file-name root)))
+ :buffer output
+ :command (append
+ (list ctags
+ "--options=NONE"
+ "--output-format=e-ctags")
+ my/project-ctags-nix-options
+ (list "--languages=all"
+ "--kinds-all=*"
+ "--fields=*"
+ "--extras=*"
+ "-f"
+ temporary-tags-file
+ "-L"
+ list-file))
+ :connection-type 'pipe
+ :sentinel
+ (lambda (process _event)
+ (when (memq (process-status process) '(exit signal))
+ (unwind-protect
+ (if (and (eq (process-status process) 'exit)
+ (zerop (process-exit-status process)))
+ (progn
+ (my/project-ctags-add-nixos-options
+ temporary-tags-file root output)
+ (rename-file temporary-tags-file tags-file t)
+ (citre-clear-tags-file-cache)
+ (my/project-ctags-enable-citre root)
+ (message "Ctags ready for %s" root))
+ (message "Ctags failed for %s; see %s"
+ root
+ (buffer-name output)))
+ (when (file-exists-p list-file)
+ (delete-file list-file))
+ (when (file-exists-p temporary-tags-file)
+ (delete-file temporary-tags-file))))))
+ (message "Generating Ctags for %s..." root)))
+
+ (defun my/project-ctags-setup ()
+ (interactive)
+ (let* ((root (my/project-ctags-root))
+ (tags-file (expand-file-name ".tags" root)))
+ (if (file-exists-p tags-file)
+ (my/project-ctags-start root)
+ (when (y-or-n-p (format "Set up Ctags for %s? " root))
+ (my/project-ctags-start root)))))
+
+ (with-eval-after-load 'evil
+ (evil-define-key '(normal motion) 'global
+ (kbd "g d") #'citre-jump
+ (kbd "g D") #'citre-query-jump
+ (kbd "g p") #'citre-peek
+ (kbd "g r") #'citre-jump-to-reference
+ (kbd "g b") #'citre-jump-back)))
(use-package typst-ts-mode
:ensure t
- :mode "\\.typ\\'"
- :hook (typst-ts-mode . eglot-ensure)
- :config
- (with-eval-after-load 'eglot
- (add-to-list 'eglot-server-programs
- `(typst-ts-mode . ,(eglot-alternatives '("tinymist" "lsp"))))))
+ :mode "\\.typ\\'")
(use-package yasnippet
:ensure t
@@ -2391,12 +2509,7 @@ Timers that expired while Emacs was closed fire immediately."
:ensure t
:mode "\\.nix\\'"
:config
- (modify-syntax-entry ?. "_" nix-ts-mode--syntax-table)
- (with-eval-after-load 'eglot
- (add-to-list 'eglot-server-programs
- '(nix-ts-mode . ("nixd")))))
-
-(put 'eglot-workspace-configuration 'safe-local-variable #'listp)
+ (modify-syntax-entry ?. "_" nix-ts-mode--syntax-table))
(with-eval-after-load 'compile
(dolist (rule '((nix-def "^\\s-*- In [`']\\(/[^'\n]+\\)'" 1)
@@ -2428,25 +2541,15 @@ Timers that expired while Emacs was closed fire immediately."
:ensure nil
:mode (("\\.c\\'" . c-ts-mode)
("\\.h\\'" . c-ts-mode))
- :hook (c-ts-mode . eglot-ensure)
:custom
(c-ts-mode-indent-offset 2)
- (c-ts-mode-indent-style 'k&r)
- :config
- (with-eval-after-load 'eglot
- (add-to-list 'eglot-server-programs
- '((c-ts-mode c-mode) .
- ("clangd"
- "--background-index"
- "--clang-tidy"
- "--header-insertion=never")))))
+ (c-ts-mode-indent-style 'k&r))
(use-package c3-ts-mode
:ensure (:host github :repo "c3lang/c3-ts-mode")
:mode (("\\.c3\\'" . c3-ts-mode)
("\\.c3i\\'" . c3-ts-mode)
("\\.c3t\\'" . c3-ts-mode))
- :hook (c3-ts-mode . eglot-ensure)
:custom
(c3-ts-mode-indent-offset 2)
(setq treesit-font-lock-level 4)
@@ -2455,24 +2558,7 @@ Timers that expired while Emacs was closed fire immediately."
'(c3 "https://github.com/c3lang/tree-sitter-c3"))
:config
(unless (treesit-language-available-p 'c3)
- (treesit-install-language-grammar 'c3))
- (with-eval-after-load 'eglot
- (add-to-list 'eglot-server-programs
- '(c3-ts-mode . ("c3-lsp")))))
-
-(use-package python
- :ensure nil
- :mode ("\\.py\\'" . python-ts-mode)
- :hook (python-ts-mode . eglot-ensure)
- :custom
- (python-indent-offset 4)
- (python-indent-guess-indent-offset-verbose nil)
- (python-shell-interpreter "python3")
- (python-shell-completion-native-enable nil)
- :config
- (with-eval-after-load 'eglot
- (add-to-list 'eglot-server-programs
- '((python-ts-mode python-mode) . ("rass" "--" "pyrefly" "lsp" "--" "ruff" "server")))))
+ (treesit-install-language-grammar 'c3)))
(use-package pyvenv
:ensure t
@@ -2483,37 +2569,11 @@ Timers that expired while Emacs was closed fire immediately."
(lambda ()
(pyvenv-mode 1))))
-(use-package rust-ts-mode
- :ensure nil
- :mode "\\.rs\\'"
- :hook (rust-ts-mode . eglot-ensure)
- :config
- (with-eval-after-load 'eglot
- (add-to-list 'eglot-server-programs
- '(rust-ts-mode .
- ("rust-analyzer" :initializationOptions
- (:check (:command "clippy")))))))
-
(use-package js
:ensure nil
:mode ("\\.js\\'" . js-ts-mode)
- :hook (js-ts-mode . eglot-ensure)
- :config
- (setq js-indent-level 2)
- (with-eval-after-load 'eglot
- (add-to-list 'eglot-server-programs
- '(js-ts-mode . ("rass" "--" "typescript-language-server" "--stdio" "--" "vscode-eslint-language-server" "--stdio")))))
-
-(use-package typescript-ts-mode
- :ensure nil
- :mode (("\\.ts\\'" . typescript-ts-mode)
- ("\\.tsx\\'" . tsx-ts-mode))
- :hook ((typescript-ts-mode . eglot-ensure)
- (tsx-ts-mode . eglot-ensure))
:config
- (with-eval-after-load 'eglot
- (add-to-list 'eglot-server-programs
- '((typescript-ts-mode tsx-ts-mode) . ("rass" "--" "typescript-language-server" "--stdio" "--" "vscode-eslint-language-server" "--stdio")))))
+ (setq js-indent-level 2))
(use-package xonsh-mode
:ensure (:host github :repo "seanfarley/xonsh-mode")
@@ -2530,38 +2590,6 @@ Xonsh is a python superset; reuse python tree-sitter parser."
(add-to-list 'auto-mode-alist '("\\.xsh\\'" . xonsh-ts-mode))
(add-to-list 'auto-mode-alist '("\\.xonshrc\\'" . xonsh-ts-mode))))
-(defun my/org-src-eglot-python ()
- "Give org src edit buffers a stable temp file name so eglot can attach.
-Name derived from owning org file path → identical across re-opens of
-the same src block file, so eglot reuses the existing connection
-instead of churning."
- (when (and (derived-mode-p 'python-ts-mode 'python-mode)
- (not buffer-file-name)
- (bound-and-true-p org-src-mode))
- (let* ((parent (or (buffer-file-name (org-src-source-buffer))
- (buffer-name (org-src-source-buffer))
- "scratch"))
- (root (or (and (project-current)
- (project-root (project-current)))
- temporary-file-directory))
- (name (format "ob-src-%s.py"
- (substring (md5 parent) 0 8))))
- (setq-local buffer-file-name (expand-file-name name root))
- (set-buffer-modified-p nil)
- (eglot-ensure))))
-
-(add-hook 'org-src-mode-hook #'my/org-src-eglot-python)
-
-(with-eval-after-load 'eglot
- (add-to-list 'eglot-server-programs
- '((xonsh-mode xonsh-ts-mode)
- . ("rass" "--" "pyrefly" "lsp" "--" "ruff" "server"))))
-
-;; kein auto-eglot fuer xonsh — pyrefly.toml waere noetig. Manuell via
-;; M-x my/pyrefly-here-xonsh (legt temp pyrefly.toml an + startet eglot).
-;; (add-hook 'xonsh-mode-hook #'eglot-ensure)
-;; (add-hook 'xonsh-ts-mode-hook #'eglot-ensure)
-
(defvar my/ob-xonsh-installer
(lambda ()
(defun org-babel-execute:xonsh (body params)
@@ -2590,38 +2618,18 @@ BODY is the xonsh script. PARAMS may include :dir and :cmdline."
(use-package yaml-ts-mode
:ensure nil
- :mode "\\.ya?ml\\'"
- :hook (yaml-ts-mode . eglot-ensure))
+ :mode "\\.ya?ml\\'")
(use-package bash-ts-mode
:ensure nil
:mode (("\\.sh\\'" . bash-ts-mode)
("\\.bash\\'" . bash-ts-mode)
("\\.bashrc\\'" . bash-ts-mode)
- ("\\.bash_profile\\'" . bash-ts-mode))
- :hook (bash-ts-mode . eglot-ensure)
- :config
- (with-eval-after-load 'eglot
- (add-to-list 'eglot-server-programs
- '(bash-ts-mode . ("bash-language-server" "start"))))
-
- (defun sh-mode-setup ()
- (add-hook 'before-save-hook #'eglot-format-buffer -10 t))
-
- (add-hook 'bash-ts-mode-hook #'sh-mode-setup))
+ ("\\.bash_profile\\'" . bash-ts-mode)))
(use-package just-mode
:ensure t
- :mode ("[Jj]ustfile\\'" "\\.just\\'")
- :hook (just-mode . eglot-ensure)
- :config
- (with-eval-after-load 'eglot
- (add-to-list 'eglot-server-programs
- '(just-mode . ("just-lsp")))))
-
-;; (use-package justl
-;; :ensure t
-;; :after just-mode)
+ :mode ("[Jj]ustfile\\'" "\\.just\\'"))
(use-package olivetti
:ensure t
@@ -3144,14 +3152,7 @@ still require a restart since elpaca queues run at init time."
"^\\*Help\\*$"
"^\\*Apropos\\*$"
"^\\*info\\*$"
- "^\\*Async-native-compile-log\\*$"
-
- ;; LSP Buffers
- "^\\*lsp-log\\*$"
- "^\\*clojure-lsp\\*$"
- "^\\*clojure-lsp::stderr\\*$"
- "^\\*ts-ls\\*$"
- "^\\*ts-ls::stderr\\*$"))
+ "^\\*Async-native-compile-log\\*$"))
(use-package projectile
:ensure (:wait t)
@@ -3171,7 +3172,7 @@ still require a restart since elpaca queues run at init time."
:after (helm projectile)
:commands (helm-projectile-find-file helm-projectile-switch-project)
:custom
- (helm-projectile-fuzzy-match t))
+ (helm-projectile-fuzzy-match nil))
(use-package wgrep
:ensure t
@@ -3568,12 +3569,7 @@ place. `C-c C-c' commits, `C-c C-k' aborts."
(defun my/format-buffer ()
(interactive)
- (cond
- ((eq major-mode 'rust-ts-mode) (eglot-format-buffer))
- ((eq major-mode 'python-ts-mode) (eglot-format-buffer))
- ((eq major-mode 'c-mode) (eglot-format-buffer))
- ((bound-and-true-p eglot--managed-mode) (eglot-format-buffer))
- (t (message "No formatter for %s" major-mode))))
+ (user-error "No formatter configured for %s" major-mode))
(defun my/find-file-or-switch-project ()
"Find a file in the current project; outside one, pick a project first.
@@ -3640,6 +3636,7 @@ workspace (e.g. *scratch*)."
"pa" '(projectile-add-known-project :wk "add project")
"pi" '(projectile-invalidate-cache :wk "invalidate cache")
"pt" '(projectile-run-task :wk "tasks")
+ "pc" '(my/project-ctags-setup :wk "setup/update ctags")
"g" '(:ignore t :wk "git")
"gc" '(magit-clone :wk "clone")
@@ -3651,11 +3648,8 @@ workspace (e.g. *scratch*)."
(let ((current-prefix-arg 4))
(call-interactively #'xref-find-definitions)))
:wk "definition other window")
- "gI" '((lambda () (interactive)
- (let ((current-prefix-arg 4))
- (call-interactively #'eglot-find-implementation)))
- :wk "implementation other window")
- "gt" '(eglot-find-typeDefinition :wk "go to type definition")
+ "gI" '(citre-query-jump :wk "find definition")
+ "gt" '(citre-peek :wk "peek definition")
"gr" '(xref-find-references :wk "find references")
"gs" '(magit-file-stage :wk "stage file")
"gu" '(my/magit-uncommit :wk "uncommit (keep & unstage)")
@@ -3699,9 +3693,9 @@ workspace (e.g. *scratch*)."
"c" '(:ignore t :wk "code")
"cc" '(my/compile-or-recompile :wk "compile")
"cC" '(ghostel-compile :wk "recompile")
- "ca" '(eglot-code-actions :wk "code actions")
- "cr" '(eglot-rename :wk "lsp rename")
- "cf" '(eglot-format :wk "format buffer")
+ "ca" '(citre-query-jump :wk "find definition")
+ "cr" '(query-replace :wk "replace")
+ "cf" '(my/format-buffer :wk "format buffer")
"cs" '(yas-insert-snippet :wk "snippets")
"cl" '(flycheck-list-errors :wk "list errors")