emacs/init.el

399 lines
12 KiB
EmacsLisp
Executable File

;;;; Appearance
(defun apply-appearance-first-frame ()
(message "Set first frame appearance")
;; Set theme
(load-theme 'my-theme +1))
(defun apply-appearance-per-frame ()
(message "Set per frame appearance")
;; Hide scroll bar
(toggle-scroll-bar -1)
;; Use JBMono
(set-frame-font "-JB-JetBrainsMonoNL Nerd Font-normal-normal-normal-*-18-*-*-*-m-0-iso10646-1" nil t))
(apply-appearance-first-frame)
(apply-appearance-per-frame)
(setq seen-first-frame nil)
(add-hook 'after-make-frame-functions
(lambda (frame)
(with-selected-frame frame
(apply-appearance-per-frame)
(if (not seen-first-frame)
(progn
(setq seen-first-frame 1)
(apply-appearance-first-frame))))))
;; Hide ribbon, menu bar
(menu-bar-mode -1)
(tool-bar-mode -1)
;; Show colum number in status bar
(column-number-mode +1)
;; Relative line numbers
(setq-default display-line-numbers 'visual)
;; Highlight current line
(global-hl-line-mode +1)
;; Replace yes/no prompts with y/n prompts
(fset #'yes-or-no-p #'y-or-n-p)
;; Fix jumpy scrolling
(setq mouse-wheel-scroll-amount '(3 ((shift) . 1))
mouse-wheel-progressive-speed nil
mouse-wheel-follow-mouse +1
scroll-step 1) ;; C-n C-p scroll step
;; Disable annoying bell sound
(setq ring-bell-function 'ignore)
;; Highlight matching parens faster
(setq show-paren-delay 0)
(setq tab-width 2)
(defun disable-tabs ()
(setq tab-width 2)
(indent-tabs-mode -1))
(defun enable-tabs ()
(setq tab-width 2)
(indent-tabs-mode +1))
(add-hook 'prog-mode-hook 'enable-tabs)
(add-hook 'lisp-mode-hook 'disable-tabs)
(add-hook 'emacs-lisp-mode-hook 'disable-tabs)
(let ((savedir (concat (file-name-as-directory (getenv "XDG_DATA_HOME")) "emacs/autosave/")))
(make-directory savedir t)
(setq backup-directory-alist `(("." . ,savedir)))
(setq auto-save-list-file-prefix (concat savedir ".saves-"))
(setq auto-save-file-name-transforms `((".*" ,savedir t)))
(setq tramp-auto-save-directory savedir))
(setq backup-by-copying t
delete-old-versions t
version-control t
kept-new-versions 2
kept-old-versions 2)
;; Packages
(require 'use-package)
;; Evil (Vim Emulation)
(use-package evil
:init
(setq evil-want-C-u-scroll t
evil-mode-beyond-eol t
evil-mode-fine-undo t
evil-undo-system 'undo-redo
evil-want-keybinding nil)
:config
(add-hook 'evil-local-mode-hook (lambda ()
(setq-local interprogram-cut-function nil)
(setq-local interprogram-paste-function nil)))
(evil-mode +1))
(use-package better-jumper
:after evil
:config
(setq better-jumper-context 'window
better-jumper-new-window-behavior 'copy
better-jumper-max-length 1000
better-jumper-use-evil-jump-advice t)
(define-key evil-motion-state-map (kbd "C-o") #'better-jumper-jump-backward)
(define-key evil-motion-state-map (kbd "C-i") #'better-jumper-jump-forward)
(define-key evil-normal-state-map (kbd "SPC j") #'better-jumper-set-jump)
(better-jumper-mode))
(use-package evil-collection
:after evil
:config
(evil-collection-init '(magit ibuffer)))
(use-package crux)
;; Avy (jump to char)
(use-package avy
:bind (("C-;" . avy-goto-char)
("C-:" . avy-goto-word-1)
("M-g g" . avy-goto-line)))
(use-package undo-tree
:after evil
:config
(setq undo-tree-auto-save-history nil)
(advice-add #'evil-undo :override #'undo-tree-undo)
(advice-add #'evil-redo :override #'undo-tree-redo)
(define-key evil-normal-state-map (kbd "SPC u v") #'undo-tree-visualize)
(global-undo-tree-mode))
;; Magit (git frontend)
(use-package magit)
;; Rainbow-Mode (show hex strings in color)
(use-package rainbow-mode)
;; Vertico (completion helper)
(use-package vertico
:config
(keymap-set vertico-map "M-j" #'vertico-next)
(keymap-set vertico-map "M-k" #'vertico-previous)
(keymap-set vertico-map "M-`" #'vertico-exit)
(vertico-mode))
(use-package vertico-indexed
:after vertico
:init
(setq vertico-indexed-start 1)
:config
(dotimes (i 9)
(keymap-set vertico-map (format "M-%d" (+ i 1))
`(lambda () (interactive)
(setq vertico--index ,i)
(vertico-exit))))
(vertico-indexed-mode))
;; Editorconfig support
(use-package editorconfig
:config
(editorconfig-mode 1))
;; Direnv support (nix shell, gitconfig, etc...)
(use-package direnv
:config
(direnv-mode))
;; Remove trailing whitespace
(use-package ws-butler
:config
(add-hook 'prog-mode-hook #'ws-butler-mode))
;; Markdown
(use-package markdown-mode
:init
(setq markdown-fontify-code-blocks-natively t))
;; Justfile
(use-package just-mode)
;; String casing functions
(use-package string-inflection)
;; Treesitter
(use-package treesit
:config
(customize-set-variable 'treesit-font-lock-level 4)
(setq major-mode-remap-alist
'((c-mode . c-ts-mode)
(csharp-mode . csharp-ts-mode)
(cmake-mode . cmake-ts-mode)
(c++-mode . c++-ts-mode)
(css-mode . css-ts-mode)
(java-mode . java-ts-mode)
(json-mode . json-ts-mode)
(python-mode . python-ts-mode))))
;; Highlight operations
(use-package evil-goggles
:after evil
:init
(setq evil-goggles-duration 0.15)
:config
(evil-goggles-mode +1))
;; Project
(use-package projectile
:config
(define-key prog-mode-map (kbd "C-c p") 'projectile-command-map)
(define-key projectile-mode-map (kbd "C-c p") 'projectile-command-map)
(projectile-mode +1))
;; File tree (+ related integrations)
(use-package treemacs
:init
(setq treemacs-tag-follow-delay 0.5)
:config
(treemacs-resize-icons 15)
(treemacs-follow-mode +1)
(treemacs-tag-follow-mode +1)
(treemacs-project-follow-mode +1))
(use-package treemacs-evil
:after (treemacs evil))
(use-package treemacs-projectile
:after (treemacs projectile))
(use-package treemacs-magit
:after (treemacs magit))
;; Explanations for keybindings
(use-package which-key
:config
(which-key-mode +1))
;; On the fly syntax checking
(use-package flycheck
:after evil
:config
(define-key evil-normal-state-map (kbd "SPC e") #'flycheck-list-errors))
;; Completions
(use-package company
:init
(setq company-minimum-prefix-length 1
company-idle-delay 0
company-selection-wrap-around t
company-tooltip-align-annotations t
company-tooltip-flip-when-above t
company-tooltip-margin 0
company-show-quick-access 'left
;; fix lowercase completions in raw text
company-dabbrev-downcase nil)
:config
(setq company-transformers '(delete-consecutive-dups
company-sort-prefer-same-case-prefix
company-sort-by-backend-importance
company-sort-by-occurrence))
(define-key company-active-map (kbd "<return>") nil)
(define-key company-active-map (kbd "RET") nil)
(define-key company-active-map (kbd "M-`") #'company-complete-selection)
(define-key company-active-map (kbd "M-n") #'company-select-next)
(define-key company-active-map (kbd "M-p") #'company-select-previous)
(define-key company-active-map (kbd "M-j") #'company-select-next)
(define-key company-active-map (kbd "M-k") #'company-select-previous)
(global-company-mode +1))
;; Fuzzy forawrd search in completions
(use-package fussy
:config
(setq completion-styles '(fussy basic)))
;; Lsp
(use-package lsp-mode
:init
(setq lsp-headerline-breadcrumb-enable nil
lsp-signature-auto-activate nil
lsp-signature-doc-lines 0)
:config
(add-hook 'lsp-mode-hook #'lsp-enable-which-key-integration)
(add-hook 'evil-insert-state-entry-hook #'lsp-signature-activate)
(add-hook 'evil-insert-state-exit-hook #'lsp-signature-stop)
(define-key evil-normal-state-map (kbd "SPC l r") #'lsp-rename)
(define-key evil-normal-state-map (kbd "SPC l a") #'lsp-execute-code-action)
(define-key evil-normal-state-map (kbd "SPC l = =") #'lsp-format-buffer)
(define-key evil-normal-state-map (kbd "SPC l = r") #'lsp-format-region)
(define-key evil-normal-state-map (kbd "SPC l s q") #'lsp-workspace-shutdown)
(define-key evil-normal-state-map (kbd "SPC l s r") #'lsp-workspace-restart)
(define-key evil-normal-state-map (kbd "SPC l i") #'lsp-describe-thing-at-point))
(use-package lsp-ui
:after lsp-mode
:init
(setq lsp-ui-doc-enable nil
lsp-ui-sideline-enable nil)
:config
(define-key lsp-ui-mode-map [remap xref-find-definitions] #'lsp-ui-peek-find-definitions)
(define-key lsp-ui-mode-map [remap xref-find-references] #'lsp-ui-peek-find-references)
(define-key evil-normal-state-map (kbd "SPC l d") #'lsp-ui-peek-find-definitions)
(define-key evil-normal-state-map (kbd "SPC l u") #'lsp-ui-peek-find-references)
;; Controls inside references popup
(define-key lsp-ui-peek-mode-map (kbd "j") #'lsp-ui-peek--select-next)
(define-key lsp-ui-peek-mode-map (kbd "k") #'lsp-ui-peek--select-prev)
(define-key lsp-ui-peek-mode-map (kbd "J") #'lsp-ui-peek--select-next-file)
(define-key lsp-ui-peek-mode-map (kbd "K") #'lsp-ui-peek--select-prev-file)
(define-key lsp-ui-peek-mode-map (kbd "o") #'lsp-ui-peek--goto-xref))
(use-package lsp-treemacs
:after (lsp-mode treemacs))
;; Java lsp
(use-package lsp-java
:after lsp-mode
:hook (java-ts-mode . lsp-deferred)
:config
(setq lsp-java-server-install-dir (getenv "JDTLS_PATH"))
(defun lsp-java--ls-command ()
(list "jdt-language-server"
;; this is called "configuration" for come reasn, its acually a cache
"-configuration" (concat (file-name-as-directory (getenv "XDG_CACHE_HOME")) "jdtls")
"-data" "../.jdtls")))
;; Nix support
(use-package nix-mode
:mode "\\.nix\\'"
:hook (nix-mode . disable-tabs))
;; QML Support
(setq qml-ts-mode-indent-offset 2)
(use-package qml-ts-mode
:config
(add-hook 'qml-ts-mode-hook
(lambda () (setq-local electric-indent-chars '(?\n ?\( ?\) ?{ ?} ?\[ ?\] ?\; ?,)))))
(add-to-list 'auto-mode-alist '("\\.rs\\'" . rust-ts-mode))
(add-to-list 'auto-mode-alist '("\\.ts\\'" . typescript-ts-mode))
(add-to-list 'auto-mode-alist '("\\.tsx\\'" . typescript-ts-mode))
(add-to-list 'auto-mode-alist '("\\.toml\\'" . toml-ts-mode))
(add-to-list 'auto-mode-alist '("\\.yaml\\'" . yaml-ts-mode))
(add-hook 'rust-ts-mode-hook #'lsp-deferred)
(add-hook 'c++-ts-mode-hook #'lsp-deferred)
(add-hook 'typescript-ts-mode-hook #'lsp-deferred)
;; Fix indent
(add-hook 'rust-ts-mode-hook
(lambda () (setq-local electric-indent-chars '(?\n ?\( ?\) ?{ ?} ?\[ ?\] ?\; ?,))))
(setq gc-cons-threshold (* 1024 1024 100)
read-process-output-max (* 1024 1024))
;; Misc keybinds
;; hy3 retardation
(use-package frames-only-mode
:config
(frames-only-mode))
(defun hyprctl (&rest args)
(apply #'start-process (append '("hyprctl" "hyprctl-buf" "hyprctl" "dispatch") args)))
(advice-add #'evil-window-split :override
(lambda (&optional count file)
(hyprctl "hy3:makegroup" "v, ephemeral")
(make-frame-command)))
(advice-add #'evil-window-vsplit :override
(lambda (&optional count file)
(hyprctl "hy3:makegroup" "h, ephemeral")
(make-frame-command)))
(define-key evil-normal-state-map (kbd "C-w a")
(lambda () (interactive)
(hyprctl "hy3:makegroup" "tab, ephemeral")
(make-frame-command)))
(define-key evil-normal-state-map (kbd "C-w r") #'make-frame-command)
(advice-add #'evil-window-left :override
(lambda (&optional count file) (hyprctl "hy3:movefocus" "l")))
(advice-add #'evil-window-right :override
(lambda (&optional count file) (hyprctl "hy3:movefocus" "r")))
(advice-add #'evil-window-up :override
(lambda (&optional count file) (hyprctl "hy3:movefocus" "u")))
(advice-add #'evil-window-down :override
(lambda (&optional count file) (hyprctl "hy3:movefocus" "d")))
;;; Overrides
;; stop lsp-mode from yoloing code actions when only one is present
(defun lsp--select-action (actions)
"Select an action to execute from ACTIONS."
(cond
((seq-empty-p actions) (signal 'lsp-no-code-actions nil))
;;((and (eq (seq-length actions) 1) lsp-auto-execute-action)
;;(lsp-seq-first actions))
(t (let ((completion-ignore-case t))
(lsp--completing-read "Select code action: "
(seq-into actions 'list)
(-compose (lsp--create-unique-string-fn)
#'lsp:code-action-title)
nil t)))))