dot-emacs/init.el
2025-09-03 01:00:45 +02:00

1265 lines
36 KiB
EmacsLisp

;;; -*- lexical-binding: t -*-
(defun tangle-init ()
"If the current buffer is init.org the code-blocks are
tangled, and the tangled file is compiled."
(when (equal (buffer-file-name)
(expand-file-name (concat user-emacs-directory "init.org")))
;; Avoid running hooks when tangling.
(let ((prog-mode-hook nil))
(org-babel-tangle)
;; (byte-compile-file (concat user-emacs-directory "init.el"))
)))
(add-hook 'after-save-hook 'tangle-init)
(setq gc-cons-percentage 0.6)
(setq read-process-output-max (* 1024 1024)) ;; 1mb
(setq idle-update-delay 1.0)
(dolist (mode
'(tool-bar-mode
scroll-bar-mode
menu-bar-mode
blink-cursor-mode))
(funcall mode 0))
(setq ring-bell-function 'ignore
initial-scratch-message nil
inhibit-startup-message t
use-dialog-box nil)
(defvar emacs-autosave-directory
(concat user-emacs-directory "autosaves/")
"This variable dictates where to put auto saves. It is set to a
directory called autosaves located wherever your .emacs.d/ is
located.")
;; Sets all files to be backed up and auto saved in a single directory.
(setq backup-directory-alist
`((".*" . ,emacs-autosave-directory))
auto-save-file-name-transforms
`((".*" ,emacs-autosave-directory t)))
(defvar bootstrap-version)
(let ((bootstrap-file
(expand-file-name
"straight/repos/straight.el/bootstrap.el"
(or (bound-and-true-p straight-base-dir)
user-emacs-directory)))
(bootstrap-version 7))
(unless (file-exists-p bootstrap-file)
(with-current-buffer
(url-retrieve-synchronously
"https://raw.githubusercontent.com/radian-software/straight.el/develop/install.el"
'silent 'inhibit-cookies)
(goto-char (point-max))
(eval-print-last-sexp)))
(load bootstrap-file nil 'nomessage))
(straight-use-package 'use-package)
(setq straight-use-package-by-default t)
(use-package org
:straight (:type built-in))
(defvar local-lisp (concat user-emacs-directory "local-lisp/"))
(add-to-list 'load-path local-lisp)
(let ((default-directory local-lisp))
(normal-top-level-add-subdirs-to-load-path))
(set-language-environment "UTF-8")
(delete-selection-mode t) ;; Replace selected text when yanking
(dirtrack-mode t) ;; Directory tracking in shell
(global-so-long-mode t) ;; Mitigate performance for long lines
(global-visual-line-mode t) ;; Break lines instead of truncating them
(global-auto-revert-mode t) ;; Revert buffers automatically when they change
(recentf-mode t) ;; Remember recently opened files
(savehist-mode t) ;; Remember minibuffer prompt history
(save-place-mode t) ;; Remember last cursor location in file
(show-paren-mode t) ;; Highlight matching parentheses
(setq-default tab-width 4
fill-column 80
indent-tabs-mode nil)
(setq use-short-answers t)
(setq initial-major-mode 'org-mode)
(use-package exec-path-from-shell
:straight t
:config
(when (daemonp)
(exec-path-from-shell-initialize)))
(use-package keychain-environment
:straight t
:init
(keychain-refresh-environment))
(use-package keychain-environment
:straight t
:defer t
:config
(keychain-refresh-environment))
(defvar custom-bindings-map (make-keymap)
"A keymap for custom keybindings.")
(define-minor-mode custom-bindings-mode
"A mode that activates custom keybindings."
:init-value t
:keymap custom-bindings-map)
(add-to-list 'default-frame-alist '(internal-border-width . 8 ))
(set-fringe-mode 4)
(setq-default fringes-outside-margins 0)
(setq-default indicate-buffer-boundaries nil)
(setq-default indicate-empty-lines nil)
(set-face-attribute 'header-line t :inherit 'default)
(use-package gruvbox-theme
:straight t)
;; doom needs this somehow
(use-package all-the-icons
:straight t)
(use-package doom-themes
:straight t
:config
(setq doom-themes-enable-bold t
doom-themes-enable-italic t)
(doom-themes-org-config))
(defvar nemo/dark-theme 'gruvbox-dark-medium)
(defvar nemo/light-theme 'gruvbox-light-medium)
(add-hook 'after-init-hook (lambda () (load-theme nemo/dark-theme t)))
(defadvice load-theme
(before disable-before-load (theme &optional no-confirm no-enable) activate)
(mapc 'disable-theme custom-enabled-themes))
(defun nemo/set-light-theme ()
"load the light theme."
(interactive)
(load-theme nemo/light-theme t))
(defun nemo/set-dark-theme ()
"load the dark theme."
(interactive)
(load-theme nemo/dark-theme t))
(setq help-window-select t
help-window-keep-selected t)
(defvar nemo/font-height-mono 110)
(defvar nemo/font-height-sans 120)
(defun apply-if-gui (&rest action)
"apply ACTION if emacs is run in GUI context, regardless of daemonp or display-graphic-p"
(if (daemonp)
(add-hook 'after-make-frame-functions
(lambda (frame)
(select-frame frame)
(if (display-graphic-p frame)
(apply action))))
(if (display-graphic-p)
(apply action))))
(set-face-attribute 'default nil :font "monospace" :height nemo/font-height-mono)
(set-face-attribute 'fixed-pitch nil :font "monospace" :height nemo/font-height-mono)
(set-face-attribute 'variable-pitch nil :font "sans-serif" :height nemo/font-height-sans)
;; (when (member "SF Mono" (font-family-list))
;; (set-face-attribute 'default nil :font "SF Mono" :height nemo/font-height-mono)
;; (set-face-attribute 'fixed-pitch nil :family "SF Mono" :height nemo/font-height-mono))
(when (member "SF Pro Text" (font-family-list))
(set-face-attribute 'variable-pitch nil :family "SF Pro Text" :height nemo/font-height-sans))
(defvar nemo/nerd-fonts-font "Symbols Nerd Font")
(defun nemo/set-fallback-fonts ()
"Set fallback fonts for icons/symbols."
(set-fontset-font t nil (font-spec :height nemo/font-height-mono :font nemo/nerd-fonts-font))
)
(apply-if-gui #'nemo/set-fallback-fonts)
(use-package nerd-icons
:straight t)
(use-package emojify
:straight t
:config
(when (member "Apple Color Emoji" (font-family-list))
(set-fontset-font t 'symbol (font-spec :family "Apple Color Emoji") nil 'prepend)))
(use-package mixed-pitch
:straight t
:hook ((org-mode . mixed-pitch-mode)
(LaTeX-mode . mixed-pitch-mode)))
;; Mode line setup
(column-number-mode t) ;; Show current column number in mode line
(setq-default
mode-line-format
'((:propertize "λ" face mode-line-emphasis)
" "
mode-line-buffer-identification
" "
; read-only or modified status
(:eval
(cond (buffer-read-only
(propertize "" 'face 'mode-line-read-only-face))
((buffer-modified-p)
(propertize " 󰳻 " 'face 'mode-line-modified-face))
(t "" 'face 'mode-line)))
; directory and buffer/file name
(:propertize (:eval (shorten-directory default-directory 30))
face mode-line-folder-face)
(:propertize "%b"
face mode-line-filename-face)
;; Version control info
(:eval (when-let (vc vc-mode)
;; Use a pretty branch symbol in front of the branch name
(list (propertize "" 'face 'font-lock-keyword-face)
(propertize (substring vc 5)
'face 'font-lock-doc-face))))
" "
(:propertize mode-name)
(:propertize (length local-minor-modes))
; (global-mode-string global-mode-string)
(:eval (propertize
" " 'display
`((space :align-to
(- (+ right right-fringe right-margin)
,(+ 1 (string-width "%p %4l:%c")))))))
;; Line and column numbers
mode-line-percent-position
" "
(:propertize "%4l:" face mode-line-position-face)
(:eval (propertize "%c" 'face
(if (>= (current-column) 80)
'mode-line-80col-face
'mode-line-position-face)))
))
;; Helper function
(defun shorten-directory (dir max-length)
"Show up to `max-length' characters of a directory name `dir'."
(let ((path (reverse (split-string (abbreviate-file-name dir) "/")))
(output ""))
(when (and path (equal "" (car path)))
(setq path (cdr path)))
(while (and path (< (length output) (- max-length 4)))
(setq output (concat (car path) "/" output))
(setq path (cdr path)))
(when path
(setq output (concat ".../" output)))
output))
;; Extra mode line faces
(make-face 'mode-line-read-only-face)
(make-face 'mode-line-modified-face)
(make-face 'mode-line-folder-face)
(make-face 'mode-line-filename-face)
(make-face 'mode-line-position-face)
(make-face 'mode-line-mode-face)
(make-face 'mode-line-80col-face)
(set-face-attribute 'mode-line-read-only-face nil
:inherit 'mode-line-face
:foreground "#4271ae"
:box '(:line-width 2 :color "#4271ae"))
(set-face-attribute 'mode-line-modified-face nil
:inherit 'mode-line-face
:foreground "#c82829"
:background "#ffffff"
:box '(:line-width 2 :color "#c82829"))
(set-face-attribute 'mode-line-folder-face nil
:inherit 'mode-line-face
:foreground "gray60")
(set-face-attribute 'mode-line-filename-face nil
:inherit 'mode-line-face
:foreground "#eab700"
:weight 'bold)
(set-face-attribute 'mode-line-position-face nil
:inherit 'mode-line-face)
(set-face-attribute 'mode-line-mode-face nil
:inherit 'mode-line-face
:foreground "gray80")
(set-face-attribute 'mode-line-80col-face nil
:inherit 'mode-line-position-face
:foreground "black" :background "#eab700")
(defconst nemo/leader-evil "SPC")
(defconst nemo/leader-global "C-c")
(defconst nemo/major-key "m")
(defconst nemo/leader-major-evil (concat nemo/leader-evil " " nemo/major-key))
(defconst nemo/leader-major-global (concat nemo/leader-global " " nemo/major-key))
(use-package general
:straight t
:config
(general-define-key
:states '(emacs normal)
:prefix-map 'nemo/leader-prefix-map
:prefix-command 'nemo/leader-prefix-command
:global-prefix nemo/leader-global
:prefix nemo/leader-evil)
(general-create-definer leader-def
:prefix-command 'nemo/leader-prefix-command
:prefix-map 'nemo/leader-prefix-map)
(general-create-definer leader-other-def
:states '(emacs normal)
:prefix-map 'nemo/leader-prefix-map
:prefix-command 'nemo/leader-prefix-command
:global-prefix nemo/leader-global
:prefix nemo/leader-evil
)
(general-create-definer leader-major-def
:states '(emacs normal)
:global-prefix nemo/leader-global
:prefix nemo/leader-evil
)
;; magit uses with-editor-mode to spawn the git process
;; in with the emacs client as the $EDITOR
(general-def '(emacs normal) 'with-editor-mode-map ",," 'with-editor-finish)
(leader-def
"<TAB>" #'nemo/switch-to-last-buffer
"<SPC>" #'completion-at-point
"d" #'duplicate-line
"gb" #'xref-go-back
"gf" #'xref-go-forward
"bk" #'switch-to-prev-buffer
"bp" #'switch-to-prev-buffer
"bj" #'switch-to-next-buffer
"bn" #'switch-to-next-buffer
"bb" #'consult-buffer
"bd" #'kill-current-buffer
"bs" #'scratch-buffer
"wd" #'delete-window
"wo" #'delete-other-windows
"ff" #'find-file
"fi" '("Edit init.org" . nemo/edit-init-org)
"fs" '("Save" . save-buffer)
"fr" '("rg" . consult-ripgrep)
"fR" '("rg in dir" . nemo/consult-ripgrep-dir)
)
)
(use-package engine-mode
:straight t
:defer t
:config
(defengine duckduckgo
"https://duckduckgo.com/?q=%s"
:keybinding "g")
(defengine twitter
"https://twitter.com/search?q=%s"
:keybinding "x")
(defengine wikipedia
"https://www.wikipedia.org/search-redirect.php?language=en&go=Go&search=%s"
:keybinding "w"
:docstring "Searchin' the wikis.")
(defengine wiktionary
"https://www.wikipedia.org/search-redirect.php?family=wiktionary&language=en&go=Go&search=%s"
:keybinding "d")
(defengine wolfram-alpha
"https://www.wolframalpha.com/input/?i=%s")
(defengine youtube
"https://www.youtube.com/results?aq=f&oq=&search_query=%s"
:keybinding "y")
(engine-mode t)
)
(use-package diff-hl
:straight t
:config
(global-diff-hl-mode))
(use-package magit
:straight t
:defer t
:general
(leader-def
"gSh" 'magit-status-here
"gs" #'magit-status
"gSb" 'magit-blame)
:config
(setq magit-mode-quit-window 'magit-restore-window-configuration
ediff-window-setup-function #'ediff-setup-windows-plain
ediff-merge-split-window-function #'split-window-horizontally
;;magit-auto-revert-mode t
))
(use-package forge
:straight t
:after magit)
(use-package which-key
:straight t
:config
(which-key-mode))
(use-package rainbow-delimiters
:straight t
:hook (prog-mode . rainbow-delimiters-mode))
(use-package evil
:straight t
:init
(setq evil-want-C-u-scroll t)
(setq evil-want-keybinding nil)
(setq evil-want-integration t)
(setq evil-undo-system 'undo-fu)
:config
(evil-mode 1)
(leader-def
"wj" 'evil-window-down
"wk" 'evil-window-up
"wh" 'evil-window-left
"wl" 'evil-window-right
)
(defun nemo/evil-search-forward--push-xref
(&optional _regex-p _no-recursive-edit)
"push current marker to xref stack when forward searching."
(xref-push-marker-stack))
(advice-add #'evil-search-forward
:before #'nemo/evil-search-forward--push-xref
'((name . "evil-search-push-xref")))
)
(use-package evil-surround
:straight t
:defer t
:config
(global-evil-surround-mode 1))
(use-package evil-collection
:after evil
:straight t
:init (setq evil-collection-key-blacklist '("C-c <tab>" "<SPC>"))
:config
(evil-collection-init))
(use-package undo-fu
:straight t
:defer t)
(use-package projectile
:straight t
:defer t
:general
(leader-def
"p" '(:keymap project-prefix-map :wk "Projectile")
)
:config
(setq projectile-project-search-path '("~/code/"))
(projectile-mode))
(use-package ripgrep
:straight t
:defer t)
(use-package rg
:straight t
:defer t)
(use-package wgrep
:straight t
:defer t)
(use-package vterm
:straight t)
(defun nemo/abort-minibuffer-if-active ()
"Abort the minibuffer if it is active."
(interactive)
(when (active-minibuffer-window)
(abort-recursive-edit)))
(global-set-key (kbd "<escape>") 'nemo/abort-minibuffer-if-active)
(use-package olivetti
:straight t
:defer t
;; :bind (:map custom-bindings-map ("C-c o" . olivetti-mode))
:hook (org-mode . olivetti-mode)
:hook (olivetti-mode-on . (lambda () (olivetti-set-width 88)))
:config
(setq olivetti-style t))
(use-package jinx
:straight t
:hook (emacs-startup . global-jinx-mode)
:bind (("M-$" . jinx-correct)
("C-M-$" . jinx-languages))
:config
(leader-def "Ss" 'jinx-correct)
(setq jinx-languages "en_GB dk_DK de_DE"))
(use-package ispell
:straight t
:defer t
:config
(setq ispell-dictionary "en_GB"))
(use-package auctex
:straight t
:hook
(LaTeX-mode . turn-on-prettify-symbols-mode)
(LaTeX-mode . reftex-mode)
;; (LaTeX-mode . (lambda () (corfu-mode -1)))
;; (LaTeX-mode . outline-minor-mode)
(LaTeX-mode . olivetti-mode)
:config
(setq TeX-view-program-selection '((output-pdf "PDF Tools"))
TeX-view-program-list '(("PDF Tools" TeX-pdf-tools-sync-view))
TeX-source-correlate-start-server t))
(use-package pdf-tools
:straight t
:defer t
:mode ("\\.pdf\\'" . pdf-view-mode)
:config
(pdf-loader-install)
(setq-default pdf-view-display-size 'fit-height)
(setq pdf-view-continuous t)
(setq +latex-viewers '(pdf-tools))
(leader-major-def
:keymaps 'pdf-view-mode-map
"g b" #'pdf-history-backward
"g f" #'pdf-history-forward)
(general-def :keymaps 'pdf-view-mode-map
"j" (lambda() (interactive) (pdf-view-scroll-up-or-next-page 20))
"k" (lambda() (interactive) (pdf-view-scroll-down-or-previous-page 20)))
)
(use-package org
:straight (:type built-in)
:defer t
:hook (org-mode . variable-pitch-mode)
;; I basically always want to be running =visual-line-mode= anyway, but certainly in org-mode.
:hook (org-mode . visual-line-mode)
:hook (org-mode . nemo/prettify-symbols-setup)
:general-config
(general-define-key
:prefix-map 'nemo/org-map
"i" '(:ignore t :which-key "Insert..")
"ih" '("Heading" . org-insert-heading)
"is" '("Subheading" . org-insert-subheading)
"ii" '("Item" . org-insert-item)
"ib" '("Block..". org-insert-structure-template)
"il" '("Link" . org-insert-link)
)
(leader-major-def
:keymaps 'org-mode-map
"m" '(:keymap nemo/org-map :wk "Org")
)
(general-def 'normal 'org-src-mode-map ",," 'org-edit-src-exit)
(general-def 'normal 'org-mode-map
"TAB" 'org-cycle
"RET" 'org-open-at-point)
:config
(custom-set-faces
'(org-document-title ((t (:height 1.8))))
'(outline-1 ((t (:height 1.35))))
'(outline-2 ((t (:height 1.3))))
'(outline-3 ((t (:height 1.2))))
'(outline-4 ((t (:height 1.1))))
'(outline-5 ((t (:height 1.1))))
'(outline-6 ((t (:height 1.1))))
'(outline-8 ((t (:height 1.1))))
'(outline-9 ((t (:height 1.1)))))
(setq org-startup-folded 'content)
(setq org-startup-with-latex-preview t)
(setq org-startup-with-inline-images t)
(plist-put org-format-latex-options :scale 1.35)
(setq org-adapt-indentation t
org-hide-leading-stars t
org-pretty-entities-include-sub-superscripts t
org-pretty-entities t)
(setq org-src-fontify-natively t
org-src-tab-acts-natively t
org-edit-src-content-indentation 0)
)
(use-package ox-epub
:straight t)
(use-package org-fragtog
:straight t
:hook (org-mode . org-fragtog-mode))
(use-package org-appear
:straight t
:commands (org-appear-mode)
:hook (org-mode . org-appear-mode)
:config
(setq org-hide-emphasis-markers t)
(setq org-appear-autoemphasis t ;; show /../ *..* =..= ~..~ tokens
org-appear-autolinks t ;; show link hyperlinks when editing
org-appear-autosubmarkers t)) ;; show _.._ and superscript markers
(use-package org-modern
:straight t
:defer t
:after org
:hook (org-mode . org-modern-mode))
(defun nemo/prettify-symbols-setup ()
;; org-babel
(push '("#+BEGIN_SRC" . ?≫) prettify-symbols-alist)
(push '("#+END_SRC" . ?≫) prettify-symbols-alist)
(push '("#+begin_src" . ?≫) prettify-symbols-alist)
(push '("#+end_src" . ?≫) prettify-symbols-alist)
(push '("#+BEGIN_QUOTE" . ?❝) prettify-symbols-alist)
(push '("#+END_QUOTE" . ?❞) prettify-symbols-alist)
(prettify-symbols-mode))
(use-package svg-tag-mode
:straight t
:config
(setq svg-tag-tags
'((":TODO:" . ((lambda (tag) (svg-tag-make "TODO"))))))
)
(require 'org)
(setq org-agenda-start-on-weekday nil
org-agenda-block-separator nil
org-agenda-remove-tags t)
(use-package org-super-agenda
:straight t
:after org
:config
(org-super-agenda-mode))
(setq org-agenda-files (list "~/Shared/agenda.org"
"~/notes.org"
"~/projects.org"))
(add-hook 'emacs-startup-hook
(lambda () (progn (org-agenda nil "a")
(delete-other-windows)
(olivetti-mode))))
(use-package move-text
:straight t
:defer t
:bind (("M-j" . move-text-down)
("M-k" . move-text-up)))
(use-package treemacs
:straight t
;; hijack projectile prefix because they fit together
:general
(general-define-key
:prefix-map 'project-prefix-map
"t" '("Treemacs" . treemacs-select-window)
)
:config
(setq treemacs-width 25)
)
(use-package treemacs-evil
:after (treemacs evil)
:straight t)
(use-package treemacs-projectile
:after (treemacs projectile)
:straight t)
(use-package treemacs-icons-dired
:hook (dired-mode . treemacs-icons-dired-enable-once)
:straight t)
(use-package treemacs-magit
:after (treemacs magit)
:straight t)
(use-package vertico
:straight t
:bind (:map minibuffer-local-map
("C-h" . backward-kill-sexp))
:config
(vertico-mode 1)
(setq vertico-count 25
completion-ignore-case t
read-buffer-completion-ignore-case t
read-file-name-completion-ignore-case t)
(vertico-multiform-mode)
)
(use-package vertico-posframe
:straight t
;; Ensure posframe is always restored when exiting a minibuffer
:hook (minibuffer-exit . (lambda () (vertico-posframe-mode 1)))
:config
(vertico-posframe-mode 1)
(setq vertico-posframe-height vertico-count
vertico-multiform-commands
'((consult-line (:not posframe))
(consult-ripgrep (:not posframe))
(nemo/consult-ripgrep (:not posframe))
(nemo/consult-ripgrep-dir (:not posframe))
(lsp-find-references (:not posframe))
(embark-act (:not posframe))
(t posframe))
))
(use-package savehist
:straight t
:init (savehist-mode))
(use-package consult
:straight t
:bind (:map custom-bindings-map
("C-x b" . consult-buffer)
("M-g g" . consult-goto-line))
:init
(setq xref-show-xrefs-function #'consult-xref
xref-show-definitions-function #'consult-xref)
:config
())
(defun nemo/exec-without-posframe (fn &rest args)
"Execute FN with ARGS while temporarily disabling vertico-posframe-mode."
(vertico-posframe-mode -1)
(unwind-protect
(apply fn args)
(vertico-posframe-mode 1)))
(defun nemo/consult-line ()
(interactive)
(nemo/exec-without-posframe #'consult-line))
(defun nemo/consult-ripgrep (&rest args)
(interactive)
(apply #'consult-ripgrep args))
(defun nemo/consult-ripgrep-dir ()
"Call consult-ripgrep in a user-specified directory."
(interactive)
(let ((dir (read-directory-name "Ripgrep directory: ")))
(consult-ripgrep dir))
)
(bind-key "C-s" 'consult-line custom-bindings-map)
(bind-key "C-M-s" 'consult-ripgrep custom-bindings-map)
(use-package marginalia
:straight t
:init
(marginalia-mode 1))
(use-package corfu
:straight t
:hook ((prog-mode text-mode) . completion-preview-mode)
:custom
;; Enable auto completion
(corfu-auto t)
;; Enable cycling for `corfu-next/previous'
(corfu-cycle t)
;; No delay
(corfu-auto-delay 0)
;; Start when this many characters have been typed
(corfu-auto-prefix 1)
;; Short delay
(corfu-popupinfo-delay 0.5)
;; Preselect the first suggestion
(corfu-preselect nil)
(corfu-on-exact-match nil)
;; Don't automatically fill in the selected candidate
(corfu-preview-current nil)
:custom
(lsp-completion-provider :none)
:init
(defun nemo/orderless-dispatch-flex-first (_pattern index _total)
(and (eq index 0) 'orderless-flex))
(defun nemo/lsp-mode-setup-completion ()
(setf (alist-get 'styles (alist-get 'lsp-capf completion-category-defaults)) '(orderless))
(add-hook 'orderless-style-dispatchers #'nemo/orderless-dispatch-flex-first nil 'local))
:hook (lsp-completion-mode . nemo/lsp-mode-setup-completion)
:config
(global-corfu-mode))
(use-package corfu-terminal
:straight t
:defer t
:hook (before-make-frame .
(lambda ()
(corfu-terminal-mode
(if (display-graphic-p) -1 +1))))
)
;; (use-package emacs
;; ;; :custom
;; ;; TODO
;; :init
;; ;; TAB cycle if there are only few candidates
;; ;; (setq completion-cycle-threshold 3)
;; (setq enable-recursive-minibuffers t)
;; ;; Hide commands in M-x which do not apply to the current mode. Corfu
;; ;; commands are hidden, since they are not supposed to be used via M-x.
;; (setq read-extended-command-predicate
;; #'command-completion-default-include-p)
;; (setq text-mode-ispell-word-completion nil)
;; ;; Enable indentation+completion using the TAB key.
;; ;; `completion-at-point' is often bound to M-TAB.
;; (setq tab-always-indent 'complete)
;; )
(use-package kind-icon
:straight t
:after corfu
:config
(add-to-list 'corfu-margin-formatters #'kind-icon-margin-formatter))
(use-package cape
:straight t
;; Bind dedicated completion commands
;; Alternative prefix keys: C-c p, M-p, M-+, ...
;; :bind (("C-c p p" . completion-at-point) ;; capf
;; ("C-c p t" . complete-tag) ;; etags
;; ("C-c p d" . cape-dabbrev) ;; or dabbrev-completion
;; ("C-c p h" . cape-history)
;; ("C-c p f" . cape-file)
;; ("C-c p k" . cape-keyword)
;; ("C-c p s" . cape-symbol)
;; ("C-c p a" . cape-abbrev)
;; ("C-c p l" . cape-line)
;; ("C-c p w" . cape-dict)
;; ("C-c p \\" . cape-tex)
;; ("C-c p _" . cape-tex)
;; ("C-c p ^" . cape-tex)
;; ("C-c p &" . cape-sgml)
;; ("C-c p r" . cape-rfc1345))
:init
;; Add `completion-at-point-functions', used by `completion-at-point'.
;; NOTE: The order matters!
;; (add-to-list 'completion-at-point-functions #'cape-capf-buster)
;; (add-to-list 'completion-at-point-functions #'cape-dabbrev)
;; (add-to-list 'completion-at-point-functions #'cape-file)
;; (add-to-list 'completion-at-point-functions #'cape-elisp-block)
;; (add-to-list 'completion-at-point-functions #'cape-history)
;; (add-to-list 'completion-at-point-functions #'cape-keyword)
;; (add-to-list 'completion-at-point-functions #'cape-tex)
;; (add-to-list 'completion-at-point-functions #'cape-dict)
;; (add-to-list 'completion-at-point-functions #'cape-sgml)
;; (add-to-list 'completion-at-point-functions #'cape-rfc1345)
;; (add-to-list 'completion-at-point-functions #'cape-abbrev)
;; (add-to-list 'completion-at-point-functions #'cape-symbol)
;; (add-to-list 'completion-at-point-functions #'cape-line)
)
(use-package prescient
:straight t
:config
(add-to-list 'completion-styles 'prescient)
(add-to-list 'prescient-filter-method 'fuzzy))
(use-package orderless
:straight t
:config
(add-to-list 'completion-styles 'orderless)
(setq orderless-matching-styles '(orderless-flex)
completion-category-overrides '((file (styles basic partial-completion)))
orderless-component-separator "[ |]")
)
(add-hook 'prog-mode-hook 'hs-minor-mode)
(use-package inheritenv
:straight t)
(use-package envrc
:straight t
:hook (after-init . envrc-global-mode))
(use-package hl-todo
:straight t
:hook ((prog-mode) . hl-todo-mode)
:config
(setq hl-todo-keyword-faces
'(("TODO" . "#e78a4e")))
)
(use-package copilot
:straight (:host github :repo "copilot-emacs/copilot.el" :files ("*.el"))
:ensure t
:hook ((prog-mode markdown-mode conf-toml-mode) . copilot-mode)
:bind (
("TAB" . 'copilot-accept-completion)
("C-<tab>" . 'copilot-accept-completion)
("M-<tab>" . 'copilot-accept-completion-by-word)
("C-S-<tab>" . 'copilot-accept-completion-by-line)
)
)
(use-package copilot-chat
:straight (:host github :repo "chep/copilot-chat.el" :files ("*.el"))
:after (org markdown-mode)
:general
(leader-def
"cg" '("Generate commit message" . copilot-chat-insert-commit-message)
"cG" '("Regenerate commit message" . copilot-chat-regenerate-commit-message)
"cC" '("Open Copilot Chat" . copilot-chat-display)
"cba" '("Add Buffer to Copilot" . copilot-chat-add-current-buffer)
"cbd" '("Remove Buffer from Copilot" . copilot-chat-del-current-buffer)
"cbw" '("Add Workspace to Copilot" . copilot-chat-add-workspace)
"cbf" #'copilot-chat-add-file
"cbb" '("List Buffers visible to Copilot" . copilot-chat-list)
"cch" #'copilot-chat-hide
"ccx" #'copilot-chat-reset
"ccb" #'copilot-chat-switch-to-buffer
"ccd" #'copilot-chat-doc
"ccr" #'copilot-chat-review
"ccm" #'copilot-chat-set-model
"cy" '("Past latest code block" . copilot-chat-yank)
)
)
(use-package smartparens
:straight t
:hook ((prog-mode text-mode markdown-mode) . smartparens-mode)
:config
(require 'smartparens-config))
(use-package flycheck
:straight t
:defer t
:hook (after-init. global-flycheck-mode)
:config)
(use-package yasnippet
:straight t
:defer t
:hook ((prog-mode text-mode) . yas-minor-mode))
(use-package yasnippet-snippets
:straight t)
(use-package lsp-mode
:straight t
:defer t
:hook (prog-mode . lsp-deferred)
:hook (lsp-mode . lsp-enable-which-key-integration)
:hook (lsp-mode . lsp-inlay-hints-mode)
:init
(setq lsp-keymap-prefix "C-l")
(add-to-list 'completion-at-point-functions #'lsp-completion-at-point)
;; (advice-add 'lsp :before #'envrc-reload)
:commands lsp
:general-config
(leader-def
"l" '(:keymap lsp-command-map :wk "LSP")
)
:config
(setq
lsp-idle-delay 0.5
lsp-inlay-hint-enable t
lsp-modeline-code-actions-enable t
lsp-modeline-code-actions-segments '(name count)
lsp-modeline-diagnostics-enable t
lsp-completion-enable-additional-text-edit t
lsp-completion-provider :capf
lsp-enable-snippet t
lsp-rust-server 'rust-analyzer
lsp-rust-analyzer-server-display-inlay-hints t
lsp-rust-analyzer-proc-macro-enable t
lsp-rust-analyzer-completion-auto-import-enable t
lsp-rust-analyzer-proc-macro-enable t
lsp-rust-analyzer-binding-mode-hints t
lsp-rust-analyzer-display-closure-return-type-hints t
lsp-rust-analyzer-server-format-inlay-hints t
lsp-rust-analyzer-cargo-extra-env ["RUSTFLAGS", "-Clinker=clang -Clink-arg=-fuse-ld=mold"]
lsp-enable-suggest-server-download nil)
(setq lsp-glsl-executable '("glsl_analyzer"))
(add-to-list 'lsp-language-id-configuration '("CMakeLists.txt" . "cmake"))
)
(use-package consult-lsp
:straight t
:general
(with-eval-after-load 'lsp-mode
(general-define-key
:keymaps 'lsp-command-map
"c s" '("Symbols" . consult-lsp-symbols)
"c f" '("Symbols" . consult-lsp-file-symbols)
"c d" '("Diagnostics" . consult-lsp-diagnostics)
)
)
)
(use-package lsp-treemacs
:straight t
:commands lsp-treemacs-errors-list)
(use-package lsp-ui
:config
(setq
;; lsp-modeline-code-actions-enable nil
;; lsp-rust-analyzer-cargo-all-targets nil
;; lsp-rust-analyzer-server-command "xwin-env rust-analyzer"
lsp-ui-sideline-show-code-actions t
lsp-ui-doc-enable t
lsp-ui-doc-delay 0.5
lsp-ui-doc-show-with-cursor t
; lsp-ui-doc-use-childframe t
; lsp-ui-doc-use-webkit t
)
:commands lsp-ui-mode)
(defvar-local nemo/lsp-format-on-save t)
(define-minor-mode nemo/lsp-format-on-save-mode
"Run lsp-format-buffer on save."
:lighter " fmt"
(if nemo/lsp-format-on-save-mode
(add-hook 'before-save-hook #'lsp-format-buffer nil t)
(remove-hook 'before-save-hook #'lsp-format-buffer nil t)
))
(defun nemo/do-lsp-format-on-save ()
"Format on save using LSP server."
(if nemo/lsp-format-on-save
(lsp-format-buffer)))
(use-package wgsl-mode
:straight t
:ensure lsp-mode
:mode "\\.wesl\\'"
:hook (wgsl-mode . lsp-deferred)
:init
(add-to-list 'lsp-language-id-configuration '(wgsl-mode . "wgsl"))
(lsp-register-client (make-lsp-client
:new-connection (lsp-stdio-connection "wgsl-analyzer")
:activation-fn (lsp-activate-on "wgsl")
:server-id 'wgsl-analyzer))
)
(use-package glsl-mode
:straight t
:defer t
:init
(add-to-list 'auto-mode-alist '("\\.vert\\'" . glsl-mode))
(add-to-list 'auto-mode-alist '("\\.glsl\\'" . glsl-mode))
(add-to-list 'auto-mode-alist '("\\.frag\\'" . glsl-mode))
)
(require 'hlsl-mode)
(with-eval-after-load 'hlsl-mode
(add-to-list 'auto-mode-alist '("\\.hlsl\\'" . hlsl-mode))
(add-to-list 'auto-mode-alist '("\\.frag\\'" . hlsl-mode))
)
(require 'slang-ts-mode)
(add-hook 'slang-ts-mode-hook (lambda () (hs-minor-mode -1)))
;; (use-package rust-mode
;; :straight t
;; ;; :hook (rust-mode . lsp-mode)
;; :init
;; (setq rust-mode-treesitter-derive t
;; ))
(use-package rustic
:straight t
:defer t
:after (inheritenv envrc)
;; :after (rust-mode)
:hook(rustic-mode . nemo/lsp-format-on-save-mode)
:general-config
(general-define-key
:prefix-map 'nemo/rust-map
"c v" '("Check" . rustic-cargo-check)
"c c" '("Compile" . rustic-compile)
"c b" '("Build" . rustic-cargo-build)
;;"c B" '("Build" . rust-cargo-relea)
"c c" '("Clean" . rustic-cargo-clean)
"c x" '("Run" . rustic-cargo-run)
"c f" '("Format Buffer" . rustic-format-buffer)
"t t" '("Current Test" . rustic-cargo-current-test)
"t a" '("Test" . rustic-cargo-test)
"c a" '("cargo-add" . rustic-cargo-add)
"c r" '("cargo-rm" . rustic-cargo-remove)
"c l" '("lint" . rustic-cargo-clippy)
"c L" '("lint" . rustic-cargo-clippy-fix)
"c n" '("new" . rustic-cargo-new)
"c i" '("init" . rustic-cargo-init)
"c d" '("Docs" . rustic-cargo-doc)
)
(leader-major-def
:keymaps 'rustic-mode-map
"m" '(:keymap nemo/rust-map :wk "Cargo")
)
:config
(setq rust-mode-treesitter-derive t
rustic-format-on-save nil
;; rustic-format-trigger 'on-save
;; rustic-format-on-save-method #'rustic-format-buffer
;; rustic-analyzer-command '("/usr/bin/rust-analyzer")
)
;; (setq nemo/lsp-format-on-save t)
)
(use-package rust-playground
:straight t
:defer t)
(use-package dap-mode
:straight t
:after (lsp-mode)
:config
;; (require 'dap-cpptools)
;; (dap-cpptools-setup)
(require 'dap-gdb-lldb)
(dap-register-debug-template "Rust::GDB Run Configuration"
(list :type "gdb"
:request "launch"
:name "GDB::Run"
:gdbpath "rust-gdb"
:target nil
:cwd nil))
(dap-auto-configure-mode))
(use-package web-mode
:straight t
:defer t
:mode
(("\\.phtml\\'" . web-mode)
("\\.tpl\\.php\\'" . web-mode)
("\\.twig\\'" . web-mode)
("\\.xml\\'" . web-mode)
("\\.html\\'" . web-mode)
("\\.htm\\'" . web-mode)
("\\.[gj]sp\\'" . web-mode)
("\\.as[cp]x?\\'" . web-mode)
("\\.eex\\'" . web-mode)
("\\.erb\\'" . web-mode)
("\\.mustache\\'" . web-mode)
("\\.handlebars\\'" . web-mode)
("\\.hbs\\'" . web-mode)
("\\.eco\\'" . web-mode)
("\\.ejs\\'" . web-mode)
("\\.svelte\\'" . web-mode)
("\\.ctp\\'" . web-mode)
("\\.djhtml\\'" . web-mode))
:config
(setq
web-mode-css-indent-offset 2
web-mode-code-indent-offset 2
web-mode-attr-indent-offset 2
web-mode-markup-indent-offset 2))
(use-package clang-format
:straight t
:defer t)
(use-package cmake-mode
:straight t)
(use-package zig-mode
:straight t
:config
(add-to-list 'auto-mode-alist '("\\.zig\\'" . zig-mode))
(setq lsp-zig-enable-build-on-save t
lsp-zig-enable-inlay-hints nil
lsp-zig-build-on-save-step "check"))
(use-package nix-mode
:ensure t
:mode ("\\.nix\\'" "\\.nix.in\\'")
)
(defun snake-case ()
"convert region from PascalCase into snake_case"
(interactive)
(save-excursion
(let ((bounds (bounds-of-thing-at-point 'symbol)))
(replace-regexp "\\([A-Z]\\)" "_\\1" nil (1+ (car bounds)) (cdr bounds))
(downcase-region (car bounds) (cdr (bounds-of-thing-at-point 'word)))))
)
(defun nemo/edit-init-org ()
"Open the init.org file."
(interactive)
(find-file (concat user-emacs-directory "/init.org"))
)
(defun nemo/magit-dotfiles ()
"View Dotfiles repository with magit"
(interactive)
(require 'magit)
(let ((magit-git-global-arguments
`(,(substitute-env-vars "--git-dir=$HOME/.cfg")
,(substitute-env-vars "--work-tree=$HOME")
,@magit-git-global-arguments)))
(magit-status "~")
(recursive-edit)))
(set-default 'tramp-default-proxies-alist (quote ((".*" "\\`root\\'" "/ssh:%h:"))))
(require 'tramp)
(defun sudo-edit-current-file ()
(interactive)
(let ((position (point)))
(find-alternate-file
(if (file-remote-p (buffer-file-name))
(let ((vec (tramp-dissect-file-name (buffer-file-name))))
(tramp-make-tramp-file-name
"sudo"
(tramp-file-name-user vec)
(tramp-file-name-host vec)
(tramp-file-name-localname vec)))
(concat "/sudo:root@localhost:" (buffer-file-name))))
(goto-char position)))
(leader-def "fe" 'sudo-edit-current-file)
(defun nemo/switch-to-last-buffer ()
(interactive)
(switch-to-buffer nil)
)
(define-key custom-bindings-map (kbd "C-c l") 'org-store-link)
(define-key custom-bindings-map (kbd "C-c a") 'org-agenda)
(define-key custom-bindings-map (kbd "C-c c") 'org-capture)
(define-key custom-bindings-map (kbd "C-c t") 'org-todo)
(define-key custom-bindings-map (kbd "M-h") 'org-todo)