395 lines
12 KiB
EmacsLisp
395 lines
12 KiB
EmacsLisp
;;; config.el -*- lexical-binding: t; -*-
|
|
|
|
;; ============================================================
|
|
;; Custom
|
|
;; ============================================================
|
|
(let ((custom-dir (expand-file-name "custom/" user-emacs-directory)))
|
|
(when (file-directory-p custom-dir)
|
|
(mapc #'load (directory-files custom-dir t "\\.el$"))))
|
|
|
|
(add-to-list 'custom-theme-load-path (expand-file-name "themes/" user-emacs-directory))
|
|
|
|
;; ============================================================
|
|
;; Keybindings
|
|
;; ============================================================
|
|
(use-package general
|
|
:config
|
|
(general-def
|
|
:keymaps 'global
|
|
"C-S-c" #'my/system-copy
|
|
"C-S-x" #'my/system-cut
|
|
"C-S-v" #'my/system-paste
|
|
"C-z" #'undo
|
|
"C-S-z" #'undo-redo
|
|
)
|
|
|
|
(general-def
|
|
:keymaps 'override
|
|
"C-k" #'avy-kill-whole-line
|
|
"C-s C-f" #'avy-goto-char-timer
|
|
"C-s C-s C-f" #'my/avy-char-region
|
|
"C-s C-S-s" #'my/avy-line-region
|
|
"C-s C-l" #'consult-line
|
|
"C-s C-e" #'er/expand-region
|
|
"C-x C-b" #'buffer-table
|
|
"M-g g" #'avy-goto-line
|
|
"C-r" #'recenter-top-bottom
|
|
"C-s w" #'my/vterm-sync-here
|
|
"C-b" #'scroll-down-command
|
|
"C-<backspace>" #'my/delete-word-backward)
|
|
|
|
(general-define-key
|
|
:keymaps 'global
|
|
"C-w" nil)
|
|
;; If you want certain keys to ONLY work in Meow Normal state, use :states.
|
|
)
|
|
|
|
;; ============================================================
|
|
;; Settings, UI
|
|
;; ============================================================
|
|
(setq kill-ring-max 1
|
|
select-enable-clipboard nil
|
|
select-enable-primary nil
|
|
save-interprogram-paste-before-kill nil
|
|
xterm-extra-capabilities '(getSelection setSelection modifyOtherKeys)
|
|
mouse-drag-copy-region nil
|
|
truncate-lines nil
|
|
|
|
display-line-numbers-type t
|
|
cursor-type 'bar
|
|
savehist-additional-variables '(kill-ring search-ring)
|
|
recentf-max-saved-items 75
|
|
)
|
|
|
|
;; Modes
|
|
(global-hl-line-mode t )
|
|
(global-display-line-numbers-mode 1)
|
|
(hl-line-mode 1)
|
|
(savehist-mode 1)
|
|
(global-clipetty-mode)
|
|
|
|
;; Fonts
|
|
(set-face-attribute 'default nil :family "Fira Code" :height 120)
|
|
(set-face-attribute 'variable-pitch nil :family "Noto Sans" :height 140)
|
|
|
|
;; Apply variable pitch to specific modes
|
|
(dolist (hook '(markdown-mode-hook org-mode-hook json-mode-hook))
|
|
(add-hook hook (lambda () (buffer-face-set '(:family "Noto Sans" :height 140)))))
|
|
|
|
(add-to-list 'auto-mode-alist '("\\.qd$" . markdown-mode))
|
|
(add-to-list 'term-file-aliases '("xterm-256" . "xterm"))
|
|
|
|
;; Recentf cleanup
|
|
(with-eval-after-load 'recentf
|
|
(run-at-time nil 600 #'recentf-cleanup)
|
|
(setq recentf-exclude '(".*/$"))) ;; don't include dirs
|
|
|
|
;; ============================================================
|
|
;; packages
|
|
;; ============================================================
|
|
|
|
(use-package emacs
|
|
:ensure nil
|
|
:custom
|
|
(tab-always-indent 'complete)
|
|
(TEXT-mode-ispell-word-completion nil)
|
|
(read-extended-command-predicate #'command-completion-default-include-p)
|
|
)
|
|
|
|
(use-package corfu
|
|
:init
|
|
(global-corfu-mode)
|
|
(corfu-popupinfo-mode)
|
|
:custom
|
|
(corfu-auto t)
|
|
(corfu-auto-delay 0.2)
|
|
(corfu-auto-prefix 2)
|
|
(corfu-popupinfo-delay '(0.5 . 0.3)))
|
|
|
|
(use-package vertico
|
|
:config
|
|
:init
|
|
(vertico-mode))
|
|
|
|
(use-package mason
|
|
:config
|
|
:init
|
|
(mason-ensure))
|
|
|
|
(use-package marginalia
|
|
:config
|
|
:init
|
|
(marginalia-mode))
|
|
|
|
(use-package orderless
|
|
:custom
|
|
(completion-styles '(orderless basic))
|
|
(completion-category-overrides '((file (styles partial-completion))))
|
|
(completion-pcm-leading-wildcard t)) ;; Emacs 31: partial-completion behaves like substring
|
|
|
|
|
|
(use-package meow
|
|
:init (setq meow--kbd-kill-region "C-S-x")
|
|
:config
|
|
(setq meow-use-clipboard nil)
|
|
(meow-setup)
|
|
(meow-global-mode 1)
|
|
(setq meow-use-clipboard t))
|
|
|
|
(use-package avy
|
|
:config
|
|
(setq avy-timeout-seconds 0.25
|
|
avy-style 'at-full
|
|
avy-keys (number-sequence ?a ?z)))
|
|
|
|
(use-package treesit-auto
|
|
:custom
|
|
(treesit-auto-install 'prompt)
|
|
:config
|
|
(treesit-auto-add-to-auto-mode-alist 'all)
|
|
(global-treesit-auto-mode)
|
|
)
|
|
|
|
(use-package treesit-fold
|
|
:commands (treesit-fold-close
|
|
treesit-fold-close-all
|
|
treesit-fold-open
|
|
treesit-fold-toggle
|
|
treesit-fold-open-all
|
|
treesit-fold-mode
|
|
global-treesit-fold-mode
|
|
treesit-fold-open-recursively
|
|
treesit-fold-line-comment-mode)
|
|
|
|
:custom
|
|
(treesit-fold-line-count-show t)
|
|
(treesit-fold-line-count-format " ▼")
|
|
|
|
:config
|
|
(set-face-attribute 'treesit-fold-replacement-face nil
|
|
:foreground "#808080"
|
|
:box nil
|
|
:weight 'bold))
|
|
|
|
;; Systems and General Purpose
|
|
(add-hook 'c-ts-mode-hook #'treesit-fold-mode)
|
|
(add-hook 'c++-ts-mode-hook #'treesit-fold-mode)
|
|
(add-hook 'java-ts-mode-hook #'treesit-fold-mode)
|
|
(add-hook 'rust-ts-mode-hook #'treesit-fold-mode)
|
|
(add-hook 'go-ts-mode-hook #'treesit-fold-mode)
|
|
(add-hook 'ruby-ts-mode-hook #'treesit-fold-mode)
|
|
|
|
;; Web and Frontend
|
|
(add-hook 'js-ts-mode-hook #'treesit-fold-mode)
|
|
(add-hook 'typescript-ts-mode-hook #'treesit-fold-mode)
|
|
(add-hook 'tsx-ts-mode-hook #'treesit-fold-mode)
|
|
(add-hook 'css-ts-mode-hook #'treesit-fold-mode)
|
|
(add-hook 'html-ts-mode-hook #'treesit-fold-mode)
|
|
|
|
;; Scripting and Infrastructure
|
|
(add-hook 'bash-ts-mode-hook #'treesit-fold-mode)
|
|
(add-hook 'cmake-ts-mode-hook #'treesit-fold-mode)
|
|
(add-hook 'dockerfile-ts-mode-hook #'treesit-fold-mode)
|
|
|
|
;; Data and Configuration
|
|
(add-hook 'json-ts-mode-hook #'treesit-fold-mode)
|
|
(add-hook 'toml-ts-mode-hook #'treesit-fold-mode)
|
|
|
|
(add-hook 'emacs-lisp-mode-hook #'outline-minor-mode)
|
|
(add-hook 'lisp-interaction-mode-hook #'hs-minor-mode) ; scratch
|
|
(add-hook 'lisp-mode-hook #'outline-minor-mode)
|
|
(add-hook 'conf-mode-hook #'outline-minor-mode)
|
|
(add-hook 'markdown-mode-hook #'outline-minor-mode)
|
|
(add-hook 'diff-mode-hook #'outline-minor-mode)
|
|
|
|
(use-package highlight-quoted
|
|
:hook (emacs-lisp-mode . highlight-quoted-mode))
|
|
|
|
(use-package highlight-defined
|
|
:hook (emacs-lisp-mode . highlight-defined-mode))
|
|
|
|
(use-package color-identifiers-mode
|
|
:hook (emacs-lisp-mode . color-identifiers-mode))
|
|
|
|
(use-package rainbow-delimiters
|
|
:hook
|
|
(prog-mode . rainbow-delimiters-mode)
|
|
(inferior-ess-mode . rainbow-delimiters-mode))
|
|
|
|
(use-package nerd-icons-completion
|
|
:after marginalia
|
|
:config
|
|
(nerd-icons-completion-mode)
|
|
(add-hook 'marginalia-mode-hook #'nerd-icons-completion-marginalia-setup))
|
|
|
|
(use-package nerd-icons-corfu)
|
|
|
|
(use-package nerd-icons-dired
|
|
:hook
|
|
(dired-mode . nerd-icons-dired-mode))
|
|
|
|
(use-package smartparens
|
|
:init (smartparens-global-mode 1)
|
|
:config
|
|
(sp-pair "\"" "\"" :wrap "C-c \"")
|
|
(sp-pair "'" "'" :wrap "C-c '")
|
|
(sp-pair "<<" ">>" :wrap "C-c <"))
|
|
|
|
(use-package indent-bars
|
|
:config
|
|
(setq indent-bars-prefer-character ?.
|
|
indent-bars-pattern "true"
|
|
indent-bars-width-frac 1
|
|
indent-bars-pad-frac 0.2
|
|
indent-bars-color-by-depth '(:regexp "outline-\\([0-9]+\\)" :blend 0.9)
|
|
indent-bars-highlight-current-depth '(:face default :blend 0.4)
|
|
)
|
|
:init
|
|
(add-hook 'prog-mode-hook #'indent-bars-mode))
|
|
|
|
(use-package kirigami
|
|
:commands (kirigami-open-fold kirigami-open-fold-rec kirigami-close-fold
|
|
kirigami-toggle-fold kirigami-open-folds
|
|
kirigami-close-folds-except-current
|
|
kirigami-close-folds))
|
|
|
|
(use-package clipetty
|
|
:hook (after-init . global-clipetty-mode))
|
|
|
|
(use-package denote
|
|
:config
|
|
(setq denote-directory (list (expand-file-name "~/lyfi/SOR/Notes/"))
|
|
denote-file-type 'markdown-yaml
|
|
denote-prompts '(title subdirectory keywords)))
|
|
|
|
(use-package colorful-mode
|
|
:init (setq colorful-allow-mouse-clicks nil))
|
|
|
|
;; Tree-sitter & LSP tweaks
|
|
(with-eval-after-load 'treesit
|
|
(setq treesit-font-lock-level 4))
|
|
|
|
(with-eval-after-load 'typescript-ts-mode
|
|
(setq typescript-ts-mode-indent-offset 2)
|
|
(defvaralias 'typescript-indent-level 'typescript-ts-mode-indent-offset))
|
|
|
|
(with-eval-after-load 'lsp-mode
|
|
(setq lsp-completion-provider :none))
|
|
|
|
;; ============================================================
|
|
;; Functions
|
|
;; ============================================================
|
|
|
|
(defun my/system-copy (beg end)
|
|
"Copy region directly to system clipboard, bypassing Emacs' kill ring.
|
|
Uses wl-copy on Wayland GUI, and Clipetty (OSC 52) in TUI/SSH."
|
|
(interactive "r")
|
|
(unless (region-active-p)
|
|
(user-error "No active region to copy"))
|
|
(let ((text (buffer-substring-no-properties beg end)))
|
|
(if (display-graphic-p)
|
|
;; GUI: Pipe text directly to Wayland clipboard
|
|
(let ((process-connection-type nil))
|
|
(let ((proc (start-process "wl-copy" nil "wl-copy")))
|
|
(process-send-string proc text)
|
|
(process-send-eof proc)))
|
|
;; TUI/SSH: Use clipetty to send OSC 52 sequence to kitty
|
|
(if (fboundp 'clipetty-set-selection)
|
|
(clipetty-set-selection text)
|
|
(error "Clipetty not loaded. Ensure (global-clipetty-mode) is active")))
|
|
(deactivate-mark)
|
|
(message "Copied to system clipboard")))
|
|
|
|
(defun my/system-cut (beg end)
|
|
"Cut region directly to system clipboard, bypassing the kill ring."
|
|
(interactive "r")
|
|
(my/system-copy beg end)
|
|
;; delete-region deletes without adding to the kill ring
|
|
(delete-region beg end))
|
|
|
|
(defun my/system-paste ()
|
|
"Paste from system clipboard directly to point, bypassing the kill ring."
|
|
(interactive)
|
|
(if (display-graphic-p)
|
|
;; GUI: Read directly from Wayland clipboard and insert
|
|
(let ((text (shell-command-to-string "wl-paste -n")))
|
|
(insert text))
|
|
;; TUI/SSH: Warn the user to use the terminal's native paste
|
|
(message "In a terminal, use your terminal emulator's native paste shortcut (e.g., Ctrl-Shift-V).")))
|
|
|
|
|
|
(defun dired-follow-symlink ()
|
|
"In dired, visit the file or directory at point by its true physical path."
|
|
(interactive)
|
|
(let ((filename (dired-get-file-for-visit)))
|
|
(if filename
|
|
(find-file (file-truename filename))
|
|
(message "No file at point"))))
|
|
|
|
(defun my/vterm-sync-here ()
|
|
"Switch to vterm and instantly 'cd' to the current buffer's directory."
|
|
(interactive)
|
|
(let ((cwd default-directory))
|
|
(vterm-toggle)
|
|
(vterm-send-string (format "cd %s" (shell-quote-argument cwd)))
|
|
(vterm-send-return)))
|
|
|
|
(defun my/delete-word-backward ()
|
|
"Delete the word and any preceding whitespace without affecting the kill ring."
|
|
(interactive)
|
|
(let ((start (point)))
|
|
(skip-chars-backward "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789")
|
|
(skip-chars-backward " \t")
|
|
(delete-region (point) start)))
|
|
|
|
(defun my-modern-delete-word-backward ()
|
|
"Delete a block of similar characters backward without using the kill ring.
|
|
Similar characters are grouped as:
|
|
1. Whitespace (including newlines)
|
|
2. Alphanumerics
|
|
3. Special characters/symbols"
|
|
(interactive)
|
|
(let ((end (point))
|
|
(start (1- (point))))
|
|
(when (>= start 1)
|
|
(let* ((first-char (char-before end))
|
|
(first-type (my-get-char-type first-char)))
|
|
;; Move start point backward as long as the character type matches
|
|
(while (and (>= start 1)
|
|
(string= first-type (my-get-char-type (char-before start))))
|
|
(setq start (1- start)))
|
|
;; Delete the range without adding to the kill ring
|
|
(delete-region start end)))))
|
|
|
|
(defun my-get-char-type (char)
|
|
"Helper to categorize characters into three groups."
|
|
(let ((cat (char-category char)))
|
|
(cond
|
|
((member cat '("space" "newline")) "whitespace")
|
|
((member cat '("letter" "number")) "alphanum")
|
|
(t "special"))))
|
|
|
|
;; Bind it to Ctrl-Backspace
|
|
;; Note: In many terminals, C-Backspace is sent as C-h or C-Delete.
|
|
;; This binding works in GUI Emacs.
|
|
(global-set-key (kbd "C-<backspace>") 'my-modern-delete-word-backward)
|
|
|
|
|
|
;; ============================================================
|
|
;; Theming, ui
|
|
;; ============================================================
|
|
;;
|
|
|
|
(my/apply-theme (selected-frame))
|
|
;; Apply to all future frames (important for emacsclient users)
|
|
(add-hook 'after-make-frame-functions 'my/apply-theme)
|
|
;;fonts
|
|
(setq doom-font "Fira Code 12")
|
|
(setq doom-variable-pitch-font "Noto Sans 14")
|
|
(setq nerd-icons-font-family "Symbols Nerd Font Mono")
|
|
(defun my-set-buffer-font ()
|
|
"Set a specific font for the current buffer only."
|
|
(buffer-face-set '(:family "Noto Sans" :height 140)))
|
|
|
|
(add-hook 'after-make-frame-functions #'my/apply-theme)
|