init.el 90 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460
  1. ;;; init.el --- Configuration entry point -*- lexical-binding: t -*-
  2. ;;; Commentary:
  3. ;;; Code:
  4. ;; Some other config files
  5. (add-to-list 'load-path "~/.emacs.d/elisp")
  6. ;; Set package dir to follow no-littering conventions
  7. (setq package-user-dir "~/.emacs.d/var/elpa")
  8. ;; Use melpa
  9. (require 'package)
  10. (add-to-list 'package-archives '("melpa" . "https://melpa.org/packages/") t)
  11. (package-initialize)
  12. ;; Ensure use-package is installed
  13. (unless (package-installed-p 'use-package)
  14. (package-refresh-contents)
  15. (package-install 'use-package))
  16. ;; use-package
  17. (eval-when-compile
  18. (require 'use-package)
  19. (setq use-package-always-ensure t
  20. package-user-dir "~/.emacs.d/var/elpa"))
  21. ;; no-littering
  22. (use-package no-littering
  23. :autoload (no-littering-theme-backups
  24. no-littering-expand-etc-file-name)
  25. :init
  26. (no-littering-theme-backups)
  27. (setq custom-file (no-littering-expand-etc-file-name "custom.el")))
  28. ;; diminish
  29. (use-package diminish
  30. :config
  31. (diminish 'visual-line-mode)
  32. (diminish 'abbrev-mode))
  33. ;; Private config loading
  34. (require 'private nil t)
  35. (defun my/get-private (key)
  36. "Get the private config variable KEY from the private configuration file."
  37. (alist-get key my/private-config))
  38. ;; basic stuff
  39. (use-package emacs
  40. :hook (;;(emacs-lisp-mode . my/-emacs-lisp-mode-setup-evil-lookup)
  41. ;;(prog-mode . electric-pair-local-mode)
  42. ((text-mode tex-mode prog-mode) . auto-fill-mode)
  43. ((text-mode tex-mode prog-mode) . my/-enable-show-trailing-whitespace))
  44. :init
  45. (defun my/-enable-show-trailing-whitespace ()
  46. (setq-local show-trailing-whitespace t))
  47. ;; (defun my/-emacs-lisp-mode-setup-evil-lookup ()
  48. ;; (setq-local evil-lookup-func
  49. ;; #'my/describe-symbol-at-point))
  50. (defun my/describe-symbol-at-point ()
  51. "Calls `describe-symbol' on the return value of `symbol-at-point'."
  52. (interactive)
  53. (let ((form (symbol-at-point)))
  54. (if (consp form)
  55. (describe-symbol (cadr form))
  56. (describe-symbol form))))
  57. ;; Increase responsiveness
  58. (setq gc-cons-threshold 80000000
  59. read-process-output-max (* 1024 1024)) ;; 1mb
  60. (global-so-long-mode 1)
  61. ;; Terminal mouse support
  62. (xterm-mouse-mode 1)
  63. ;; Make cursor more visible
  64. (global-hl-line-mode 1)
  65. (blink-cursor-mode -1)
  66. ;; Enable all disabled stuff
  67. (setq disabled-command-function nil)
  68. ;; Stop some annoying stuff
  69. (setq extended-command-suggest-shorter nil
  70. suggest-key-bindings nil)
  71. ;; Better scrolling
  72. (setq mouse-scroll-delay 0
  73. scroll-conservatively 10
  74. scroll-margin 2
  75. scroll-preserve-screen-position t)
  76. ;; Make show paren instant
  77. (setq show-paren-delay 0)
  78. (show-paren-mode 1)
  79. ;; Display line numbers
  80. (global-display-line-numbers-mode 1)
  81. ;; Allow the frame to be any size
  82. (setq frame-resize-pixelwise t)
  83. ;; Don't use a gtk file picker
  84. (setq use-file-dialog nil)
  85. ;; Make yes-or-no-p less verbose (and not use windows)
  86. (setq use-dialog-box nil
  87. use-short-answers t)
  88. ;; Disable startup screen
  89. (setq inhibit-startup-screen t
  90. server-client-instructions nil)
  91. ;; show column numbers
  92. (column-number-mode 1)
  93. ;; Disable the menu and tool bars
  94. (menu-bar-mode -1)
  95. (tool-bar-mode -1)
  96. ;; No scroll bars
  97. (scroll-bar-mode -1)
  98. ;; Visual line mode
  99. (global-visual-line-mode 1)
  100. ;; Make some commands easier to enter multiple times
  101. (repeat-mode 1)
  102. ;; Easier buffer navigation
  103. (keymap-global-set "C-c <" #'previous-buffer)
  104. (keymap-global-set "C-c >" #'next-buffer)
  105. (keymap-global-set "C-c k" #'previous-buffer)
  106. (keymap-global-set "C-c j" #'next-buffer)
  107. ;; Set fonts
  108. (add-to-list 'default-frame-alist '(font . "FiraCode Nerd Font Mono-12"))
  109. (add-hook 'server-after-make-frame-hook
  110. (lambda ()
  111. (set-fontset-font t 'japanese-jisx0208 "IPAGothic")))
  112. ;; Enable color in compilation buffers
  113. (add-hook 'compilation-filter-hook 'ansi-color-compilation-filter)
  114. ;; Some settings for programming
  115. (setq-default indent-tabs-mode nil
  116. tab-width 4
  117. fill-column 80
  118. comment-multi-line t
  119. comment-empty-lines 'eol)
  120. (add-to-list 'auto-mode-alist '("\\.[cC][nN][fF]\\'" . conf-mode))
  121. (keymap-set emacs-lisp-mode-map "C-c C-r" #'eval-region)
  122. (defun my/-fix-emacs-lisp-mode-system-files ()
  123. (when (string-prefix-p lisp-directory buffer-file-name)
  124. ;; system Emacs files use tab characters and look weird without this.
  125. (setq-local tab-width 8)))
  126. (add-hook 'emacs-lisp-mode-hook #'my/-fix-emacs-lisp-mode-system-files)
  127. ;; Tree sitter download locations
  128. (setq treesit-language-source-alist
  129. '((c "https://github.com/tree-sitter/tree-sitter-c")
  130. (cpp "https://github.com/tree-sitter/tree-sitter-cpp")
  131. (java "https://github.com/tree-sitter/tree-sitter-java")
  132. (python "https://github.com/tree-sitter/tree-sitter-python")
  133. (rust "https://github.com/tree-sitter/tree-sitter-rust")
  134. (json "https://github.com/tree-sitter/tree-sitter-json")
  135. (yaml "https://github.com/ikatyang/tree-sitter-yaml")
  136. (css "https://github.com/tree-sitter/tree-sitter-css")
  137. (go "https://github.com/tree-sitter/tree-sitter-go")
  138. (gomod "https://github.com/camdencheek/tree-sitter-go-mod")
  139. (javascript "https://github.com/tree-sitter/tree-sitter-javascript")
  140. (bash "https://github.com/tree-sitter/tree-sitter-bash")
  141. (cmake "https://github.com/uyha/tree-sitter-cmake")
  142. (blueprint "https://github.com/huanie/tree-sitter-blueprint")
  143. (kdl "https://github.com/tree-sitter-grammars/tree-sitter-kdl")))
  144. ;; Tree sitter major mode conversions
  145. (setq major-mode-remap-alist
  146. '((c-mode . c-ts-mode)
  147. (c++-mode . c++-ts-mode)
  148. (c-or-c++-mode . c-or-c++-ts-mode)
  149. (python-mode . python-ts-mode)
  150. (java-mode . java-ts-mode)
  151. (rust-mode . rust-ts-mode)
  152. (json-mode . json-ts-mode)
  153. (yaml-mode . yaml-ts-mode)
  154. (css-mode . css-ts-mode)
  155. (js-mode . js-ts-mode)
  156. (cmake-mode . cmake-ts-mode)))
  157. (defun my/treesit-compile-all (force)
  158. "Compile all the modules defined in `treesit-language-source-alist'.
  159. If FORCE, recompile all modules, even ones that are already compiled.
  160. Interactively, force the recompile if called with a prefix."
  161. (interactive "P")
  162. (let ((did-build nil))
  163. (dolist (lang treesit-language-source-alist)
  164. (when (or force (not (treesit-language-available-p (car lang))))
  165. (treesit-install-language-grammar (car lang))
  166. (setq did-build t)))
  167. (unless did-build
  168. (message "All defined parsers installed!")))))
  169. (use-package midnight
  170. :ensure nil
  171. :config
  172. (add-to-list 'clean-buffer-list-kill-never-buffer-names
  173. "*mu4e-main*")
  174. (add-to-list 'clean-buffer-list-kill-never-buffer-names
  175. "*Async-native-compile-log*")
  176. (add-to-list 'clean-buffer-list-kill-never-buffer-names
  177. "*dashboard*")
  178. (add-to-list 'clean-buffer-list-kill-never-buffer-names
  179. "*elfeed-search*")
  180. (midnight-mode 1))
  181. (defvar my/kill-some-buffers-exclude-names
  182. '("*mu4e-main*" "*Async-native-compile-log*" "*dashboard*" "*elfeed-search*"
  183. "*Messages*" "*scratch*")
  184. "List of literal buffer names that `my/kill-some-buffers' should not kill.")
  185. (defun my/kill-some-buffers-excluded-buffer-p (buffer)
  186. "Return non-nil if BUFFER should be excluded from `my/kill-some-buffers'."
  187. (cl-find (buffer-name buffer) my/kill-some-buffers-exclude-names
  188. :test 'equal))
  189. (defun my/buffer-visible-p (buffer)
  190. "Return non-nil if BUFFER is visible.
  191. BUFFER can be a string or a buffer."
  192. (cond
  193. ((stringp buffer)
  194. (not (string-prefix-p " " buffer)))
  195. ((bufferp buffer)
  196. (and (stringp (buffer-name buffer))
  197. (my/buffer-visible-p (buffer-name buffer))))
  198. (t
  199. (signal 'wrong-type-argument `((or bufferp stringp) ,buffer)))))
  200. (defvar my/kill-some-buffers-default-pred 'my/buffer-visible-p
  201. "Default predicate for `my/kill-some-buffers'.")
  202. (defun my/kill-some-buffers-prompt-for (buffer)
  203. "Generate a prompt for BUFFER."
  204. (let* ((process (get-buffer-process buffer))
  205. (process-p (and (process-live-p process)
  206. (not (process-query-on-exit-flag process))))
  207. (modified-p (and (buffer-file-name buffer)
  208. (buffer-modified-p buffer))))
  209. (format "Buffer \"%s\" %s. Kill? "
  210. (buffer-name buffer)
  211. (cond
  212. ((and process-p modified-p)
  213. "HAS BEEN EDITED AND HAS A LIVE PROCESS")
  214. (modified-p
  215. "HAS BEEN EDITED")
  216. (process-p
  217. "HAS A LIVE PROCESS")
  218. (t "is unmodified")))))
  219. (cl-defun my/kill-some-buffers (&optional auto-unmod pred)
  220. "Improved version of `kill-some-buffers'.
  221. Ask the user weather to kill each visible buffer whose name is not in
  222. `my/kill-some-buffers-exclude-names'.
  223. When AUTO-UNMOD is non-nil, as it is with a prefix argument, automatically kill
  224. unmodified buffers, and then ask about the rest.
  225. When PRED is non-nil, it is a function that will be run in each buffer (not just
  226. visible ones). If it returns t, that buffer will be considered for killing. If
  227. PRED is nil, the value of `my/kill-some-buffers-default-pred' is used."
  228. (interactive "P")
  229. ;; we already ask, no need to do it again
  230. (let ((kill-buffer-query-functions nil)
  231. (all-action (when auto-unmod 'unmod))
  232. (had-valid-buffer)
  233. (ask-again-buffers)
  234. (to-kill))
  235. (cl-flet ((ask-about (buffer allow-unmod)
  236. (unless all-action
  237. (read-answer
  238. (my/kill-some-buffers-prompt-for buffer)
  239. `(("yes" ?y "save and kill this buffer")
  240. ("no" ?n "skip this buffer")
  241. ("all" ?! "save and kill all remaining buffers")
  242. ("nosave" ?l "kill this buffer without saving")
  243. ,@(when allow-unmod
  244. '(("unmod" ?a
  245. "kill unmodified buffers, ask about the rest")))
  246. ("quit" ?q "exit")))))
  247. (act-on (ans buffer allow-unmod)
  248. (when (equal ans "all")
  249. (setq all-action 'all))
  250. (when (and allow-unmod
  251. (equal ans "unmod"))
  252. (setq all-action 'unmod))
  253. (cond
  254. ((and (eq all-action 'unmod)
  255. (buffer-file-name buffer)
  256. (buffer-modified-p buffer))
  257. (push buffer ask-again-buffers))
  258. ((or (eq all-action 'all)
  259. (eq all-action 'unmod)
  260. (equal ans "yes"))
  261. (when (buffer-file-name buffer)
  262. (with-current-buffer buffer
  263. (save-buffer)))
  264. (push buffer to-kill))
  265. ((equal ans "nosave")
  266. (with-current-buffer buffer
  267. (set-buffer-modified-p nil))
  268. (push buffer to-kill))
  269. ;; Skip buffer
  270. ;; ((equal ans "no"))
  271. ((equal ans "quit")
  272. (cl-return-from my/kill-some-buffers)))))
  273. (dolist (buffer (buffer-list))
  274. (when (and (not (my/kill-some-buffers-excluded-buffer-p buffer))
  275. (funcall (or pred my/kill-some-buffers-default-pred) buffer))
  276. (setq had-valid-buffer t)
  277. (act-on (ask-about buffer t) buffer t)))
  278. (unless had-valid-buffer
  279. (message "Nothing to do..."))
  280. (setq all-action nil)
  281. (dolist (buffer ask-again-buffers)
  282. (act-on (ask-about buffer nil) buffer nil))
  283. ;; Do this last so that tty frames don't auto-close half way through
  284. (dolist (buffer to-kill)
  285. (kill-buffer buffer)))))
  286. (keymap-global-set "C-x K" 'my/kill-some-buffers)
  287. (use-package tab-bar
  288. :ensure nil
  289. :init
  290. (setq tab-bar-show 1
  291. tab-bar-tab-hints t
  292. icon-preference '(symbol text image emoji))
  293. (tab-bar-mode 1))
  294. ;; jinx (better flyspell)
  295. (use-package jinx
  296. :hook (emacs-startup . global-jinx-mode)
  297. :config
  298. (evil-define-key 'normal 'global
  299. "z=" #'jinx-correct))
  300. ;; recentf
  301. (use-package recentf
  302. :init
  303. (setq recentf-exclude `("^/tmp/.*"
  304. "^~/.mail/[^/]/Drafts/.*"
  305. ,(format "^%svar/elpa/.*" user-emacs-directory)
  306. ,(format "^%svar/elfeed/.*" user-emacs-directory)
  307. ,(format "^%svar/gnus/.*" user-emacs-directory)
  308. ,(format "^%svar/ellama-sessions/.*" user-emacs-directory)
  309. ,(format "^%setc/gnus/.*" user-emacs-directory)
  310. ,(format "^%svar/bookmark-default.el" user-emacs-directory)))
  311. :bind ("C-c r" . recentf)
  312. :config
  313. (recentf-mode 1))
  314. ;; bookmarks
  315. (use-package bookmark
  316. :ensure nil
  317. :bind ("C-c b" . my/bookmark-find-file)
  318. :config
  319. (defun my/bookmark-find-file (&optional name)
  320. "Run `find-file' in or on bookmark NAME.
  321. If NAME points to a directory, run `find-file' with `default-directory' in that
  322. directory. Otherwise, run `find-file' on that file."
  323. (interactive (list (bookmark-completing-read
  324. "Find file in" bookmark-current-bookmark)))
  325. (unless name
  326. (error "No bookmark specified"))
  327. (bookmark-maybe-historicize-string name)
  328. (when-let ((file (bookmark-get-filename name)))
  329. (if (file-directory-p file)
  330. (let ((default-directory (file-name-as-directory file)))
  331. (call-interactively 'find-file))
  332. (find-file file)))))
  333. ;; kitty keyboard protocol
  334. (use-package kkp
  335. :defer nil
  336. :config
  337. (global-kkp-mode 1)
  338. (defun my/-kkp-after-terminal-setup ()
  339. ;; Make tab and backtab work properly
  340. (define-key input-decode-map [(control ?i)] [tab])
  341. (define-key input-decode-map [(control ?I)] [backtab])
  342. (define-key input-decode-map [(control ?m)] [return]))
  343. (defun my/-kkp-after-terminal-teardown (term)
  344. (with-selected-frame (car (frames-on-display-list term))
  345. (define-key input-decode-map [(control ?i)] nil t)
  346. (define-key input-decode-map [(control ?I)] nil t)
  347. (define-key input-decode-map [(control ?m)] nil t)))
  348. (advice-add 'kkp--terminal-setup :after 'my/-kkp-after-terminal-setup)
  349. (advice-add 'kkp--terminal-teardown :after 'my/-kkp-after-terminal-teardown)
  350. (defun my/quoted-insert (arg)
  351. "Insert the next character using read-key, not read-char."
  352. (interactive "*p")
  353. ;; Source: https://github.com/benjaminor/kkp/issues/11
  354. (let ((char (read-key)))
  355. ;; Ensure char is treated as a character code for insertion
  356. (unless (characterp char)
  357. (user-error "%s is not a valid character"
  358. (key-description (vector char))))
  359. (when (numberp char)
  360. (while (> arg 0)
  361. (insert-and-inherit char)
  362. (setq arg (1- arg))))))
  363. (keymap-global-set "C-q" #'my/quoted-insert)
  364. (defun my/-kkp-fix-map-y-or-n-p (oldfun &rest args)
  365. "Fix `map-y-or-n-p' when used in a terminal with kkp enabled."
  366. (let ((status (kkp--terminal-has-active-kkp-p)))
  367. (condition-case err
  368. (progn
  369. (when status (kkp-disable-in-terminal))
  370. (apply oldfun args))
  371. (quit
  372. ;; We won't die in this case, so just re-enable kkp
  373. (when (and status (not (kkp--terminal-has-active-kkp-p)))
  374. (kkp-enable-in-terminal))
  375. (signal 'quit nil))
  376. (t
  377. (when (and status (not (kkp--terminal-has-active-kkp-p)))
  378. ;; this does async stuff that will make kitty send characters after
  379. ;; Emacs exits. We prevent that by not re-enabling if this frame (or
  380. ;; Emacs) is about to die
  381. (let ((will-die))
  382. (mapbacktrace
  383. (lambda (_evald func _args _flags)
  384. (when (or (eq func 'save-buffers-kill-emacs)
  385. (eq func 'server-save-buffers-kill-terminal))
  386. (setq will-die t))))
  387. (unless will-die
  388. (kkp-enable-in-terminal))))
  389. (when err
  390. (signal (car err) (cdr err)))))))
  391. (advice-add #'map-y-or-n-p :around
  392. #'my/-kkp-fix-map-y-or-n-p))
  393. ;; mozc
  394. (require 'mozc nil t)
  395. (setq default-input-method "japanese-mozc")
  396. ;; undo-tree
  397. (use-package undo-tree
  398. :defer nil
  399. :hook (undo-tree-visualizer-mode . my/-undo-tree-visualizer-mode-setup)
  400. :config
  401. (defun my/-undo-tree-visualizer-mode-setup ()
  402. (visual-line-mode -1)
  403. (setq truncate-lines t))
  404. (global-undo-tree-mode))
  405. ;; evil
  406. (use-package evil
  407. :init
  408. (setq evil-want-integration t
  409. evil-want-C-d-scroll nil
  410. evil-want-keybinding nil
  411. evil-undo-system 'undo-tree
  412. evil-search-module 'isearch
  413. evil-respect-visual-line-mode t)
  414. :config
  415. (evil-mode 1)
  416. (evil-define-key '(normal visual motion) proced-mode-map
  417. "u" #'proced-unmark)
  418. (evil-define-key '(normal visual motion) dired-mode-map
  419. "u" #'dired-unmark)
  420. (evil-define-key '(normal visual motion) profiler-report-mode-map
  421. (kbd "TAB") #'profiler-report-toggle-entry)
  422. (eldoc-add-command 'evil-insert
  423. 'evil-append
  424. 'evil-insert-line
  425. 'evil-append-line))
  426. (use-package evil-collection
  427. :after evil
  428. :diminish evil-collection-unimpaired-mode
  429. :config
  430. (evil-collection-init))
  431. (use-package evil-surround
  432. :after evil
  433. :config
  434. (evil-define-key 'operator evil-surround-mode-map
  435. "z" #'evil-surround-edit
  436. "Z" #'evil-Surround-edit)
  437. (evil-define-key 'visual evil-surround-mode-map
  438. "gz" #'evil-surround-region
  439. "gZ" #'evil-Surround-region)
  440. (global-evil-surround-mode 1))
  441. (use-package evil-terminal-cursor-changer
  442. :after evil
  443. :config
  444. (evil-terminal-cursor-changer-activate))
  445. (use-package evil-numbers
  446. :after evil
  447. :bind (("C-c =" . evil-numbers/inc-at-pt)
  448. ("C-c +" . evil-numbers/inc-at-pt)
  449. ("C-c -" . evil-numbers/dec-at-pt)
  450. ("C-c C-=" . evil-numbers/inc-at-pt-incremental)
  451. ("C-c C-+" . evil-numbers/inc-at-pt-incremental)
  452. ("C-c C--" . evil-numbers/dec-at-pt-incremental)))
  453. (use-package evil-cleverparens
  454. :hook ((prog-mode . my/-enable-evil-cleverparens)
  455. (evil-cleverparens-mode . paredit-mode))
  456. :bind (:map paredit-mode-map
  457. ("C-<return>" . paredit-RET)
  458. ("C-RET" . paredit-RET)
  459. :map evil-cleverparens-mode-map
  460. ("C-c o" . evil-cp-open-below-form))
  461. :custom
  462. (evil-cleverparens-use-s-and-S nil)
  463. :config
  464. (eldoc-add-command 'paredit-RET
  465. 'paredit-open-round
  466. 'paredit-open-angled
  467. 'paredit-open-bracket
  468. 'paredit-open-angled
  469. 'paredit-open-parenthesis
  470. 'delete-indentation
  471. 'evil-cp-insert
  472. 'evil-cp-append
  473. 'evil-cp-insert-at-beginning-of-form
  474. 'evil-cp-insert-at-end-of-form)
  475. (keymap-unset evil-cleverparens-mode-map "<normal-state> M-o" t)
  476. (defun my/-enable-evil-cleverparens ()
  477. (if (member major-mode '(lisp-mode emacs-lisp-mode
  478. lisp-interaction-mode))
  479. (evil-cleverparens-mode 1)
  480. (electric-pair-local-mode 1)))
  481. (cl-defun my/range-inside-thing-p (thing beg end &optional no-edge)
  482. "Return non-nil if BEG and END fall inside the bounds of THING.
  483. With NO-EDGE, return nil if beg or end fall on the edge of the range."
  484. (save-excursion
  485. ;; this fixes that fact that `thing-at-point-bounds-of-string-at-point'
  486. ;; errors if called at the end of the buffer
  487. (condition-case nil
  488. (let ((sb (progn (goto-char beg) (bounds-of-thing-at-point thing)))
  489. (eb (progn (goto-char end) (bounds-of-thing-at-point thing))))
  490. (and sb eb (equal sb eb)
  491. (or (not no-edge)
  492. (and (/= beg (car sb))
  493. (< beg (cdr sb))
  494. (/= end (car sb))
  495. (< end (cdr sb))))))
  496. ;; if the error happens, we aren't in a string
  497. (wrong-type-argument nil))))
  498. (defun my/-evil-cp-region-ok-p-no-string (oldfun beg end)
  499. (or
  500. (and (sp-point-in-comment beg)
  501. (sp-point-in-comment end))
  502. (and (sp-point-in-string beg)
  503. (sp-point-in-string end)
  504. (my/range-inside-thing-p 'string beg end t))
  505. (funcall oldfun beg end)))
  506. (defun my/column-num-at-pos (pos)
  507. "Return the column number at POS."
  508. (save-excursion
  509. (goto-char pos)
  510. (current-column)))
  511. (defun my/-evil-cp-block-ok-p-no-string (oldfun beg end)
  512. (when (> beg end) (cl-rotatef beg end))
  513. (or
  514. (save-excursion
  515. (goto-char beg)
  516. (let ((start-off (current-column))
  517. (end-off (my/column-num-at-pos end)))
  518. (cl-block nil
  519. (dotimes (_ (count-lines beg end) t)
  520. (let ((bol (pos-bol)))
  521. (unless (sp-region-ok-p (+ bol start-off)
  522. (+ bol end-off))
  523. (cl-return))
  524. (forward-line))))))
  525. (funcall oldfun beg end)))
  526. (advice-add 'sp-region-ok-p :around 'my/-evil-cp-region-ok-p-no-string)
  527. (advice-add 'evil-cp--balanced-block-p :around 'my/-evil-cp-block-ok-p-no-string))
  528. ;; better lisp editing
  529. (use-package adjust-parens
  530. :hook (prog-mode . adjust-parens-mode)
  531. :config
  532. (defun my/lisp-indent-adjust-parens ()
  533. "Like `lisp-indent-adjust-parens', but got to first char on line first.
  534. Also, this works even if the region is active (it indents every line in the
  535. region)."
  536. (interactive)
  537. (save-mark-and-excursion
  538. (let ((end (mark t))
  539. (line-count 1)
  540. (indent-cols))
  541. (when (and (region-active-p) end)
  542. (setq mark-active nil
  543. line-count (count-lines (point) end))
  544. (when (> (point) end)
  545. (let ((start (point)))
  546. (goto-char end)
  547. (setq end start))))
  548. ;; find the indentation column of each line
  549. (save-excursion
  550. (dotimes (_ line-count)
  551. (back-to-indentation)
  552. (push (- (point) (pos-bol)) indent-cols)
  553. (forward-line))
  554. (cl-callf nreverse indent-cols))
  555. (cl-loop repeat line-count
  556. for indent-col in indent-cols
  557. for bol = (pos-bol)
  558. do (back-to-indentation)
  559. ;; skip this line if the indentation has changed
  560. when (= (- (point) bol) indent-col) do
  561. (lisp-indent-adjust-parens)
  562. ;; if the indent failed, stop
  563. (when (= (- (point) bol) indent-col)
  564. (cl-return))
  565. do (forward-line)))))
  566. (defun my/lisp-dedent-adjust-parens ()
  567. "Like `lisp-dedent-adjust-parens', but got to first char on line first.
  568. Also, this works even if the region is active (it just jumps to the first line
  569. in the region and indents once)."
  570. (interactive)
  571. (save-mark-and-excursion
  572. (let ((end (mark t)))
  573. (when (and (region-active-p) end)
  574. (setq mark-active nil)
  575. (when (> (point) end)
  576. (goto-char end))))
  577. (back-to-indentation)
  578. (lisp-dedent-adjust-parens)))
  579. (eldoc-add-command 'my/lisp-indent-adjust-parens
  580. 'my/lisp-dedent-adjust-parens
  581. 'lisp-indent-adjust-parens
  582. 'lisp-dedent-adjust-parens)
  583. (evil-define-key '(normal visual) adjust-parens-mode-map
  584. (kbd "<tab>") #'my/lisp-indent-adjust-parens
  585. (kbd "<backtab>") #'my/lisp-dedent-adjust-parens))
  586. ;; for when the files are just too large
  587. (use-package vlf
  588. :demand t
  589. :config
  590. (require 'vlf-setup))
  591. ;; allow copy from terminal
  592. (use-package xclip
  593. :config
  594. (setq xclip-method 'wl-copy
  595. xclip-program (symbol-name xclip-method))
  596. (xclip-mode 1)
  597. (defun my/-xclip-detect-wl-paste-error (oldfun type)
  598. (if (eq xclip-method 'wl-copy)
  599. ;; Direct from `xclip-get-selection'
  600. (when (and (getenv "WAYLAND_DISPLAY")
  601. (memq type '(clipboard CLIPBOARD primary PRIMARY)))
  602. (let* ((exit-code 0)
  603. (output
  604. (with-output-to-string
  605. (setq exit-code
  606. (apply #'call-process (replace-regexp-in-string
  607. "\\(.*\\)copy" "\\1paste"
  608. xclip-program 'fixedcase)
  609. nil standard-output nil
  610. "-n" (if (memq type '(primary PRIMARY))
  611. '("-p")))))))
  612. (if (zerop exit-code)
  613. output
  614. "")))
  615. (funcall oldfun type)))
  616. (advice-add 'xclip-get-selection :around 'my/-xclip-detect-wl-paste-error))
  617. ;; which-key
  618. (use-package which-key
  619. :diminish which-key-mode
  620. :config
  621. (which-key-mode 1))
  622. ;; avy
  623. (use-package avy
  624. :bind (("C-c C-j" . avy-resume)
  625. ("M-s s" . evil-avy-goto-char-2)
  626. ("M-s S" . evil-avy-goto-line))
  627. :init
  628. (define-minor-mode my/evil-avy-mode
  629. "A minor mode for binding avy commands to s and S in evil's normal and
  630. visual states."
  631. :keymap (make-sparse-keymap))
  632. (evil-define-key '(normal visual operator motion) my/evil-avy-mode-map
  633. "s" #'evil-avy-goto-char-2
  634. "S" #'evil-avy-goto-line)
  635. (define-globalized-minor-mode my/evil-avy-global-mode my/evil-avy-mode
  636. (lambda () (my/evil-avy-mode 1))
  637. :predicate '((not magit-mode dired-mode
  638. proced-mode mu4e-main-mode
  639. mu4e-view-mode mu4e-headers-mode
  640. ibuffer-mode calc-mode calc-trail-mode
  641. gnus-group-mode) t))
  642. (my/evil-avy-global-mode 1)
  643. :config
  644. (avy-setup-default))
  645. ;; ace-window
  646. (use-package ace-window
  647. :diminish ace-window-mode
  648. :bind ("M-o" . ace-window)
  649. :init
  650. (setq aw-scope 'frame
  651. aw-minibuffer-flag t))
  652. ;; savehist
  653. (use-package savehist
  654. :config
  655. (savehist-mode 1))
  656. ;; vertico
  657. (use-package vertico
  658. :bind (:map vertico-map
  659. ("C-RET" . vertico-exit-input)
  660. ("C-<return>" . vertico-exit-input)
  661. ("C-S-k" . kill-line)
  662. ("C-k" . vertico-previous)
  663. ("C-j" . vertico-next)
  664. ("RET" . vertico-directory-enter)
  665. ("DEL" . vertico-directory-delete-char)
  666. ("M-DEL" . vertico-directory-delete-word))
  667. :hook (minibuffer-setup . cursor-intangible-mode)
  668. :init
  669. (defun my/crm-indicator (args)
  670. (cons (format "[CRM%s] %s"
  671. (replace-regexp-in-string
  672. "\\`\\[.*?]\\*\\|\\[.*?]\\*\\'" ""
  673. crm-separator)
  674. (car args))
  675. (cdr args)))
  676. (advice-add #'completing-read-multiple :filter-args #'my/crm-indicator)
  677. (setq vertico-cycle t
  678. enable-recursive-minibuffers t
  679. ;; read-extended-command-predicate #'command-completion-default-include-p
  680. read-extended-command-predicate nil
  681. minibuffer-prompt-properties '(read-only t ;; noindent 3
  682. cursor-intangible t
  683. face minibuffer-prompt))
  684. (vertico-mode 1)
  685. ;; for jinx
  686. (require 'vertico-multiform)
  687. (add-to-list 'vertico-multiform-categories
  688. '(jinx grid (vertico-grid-annotate . 20)))
  689. (vertico-multiform-mode 1))
  690. ;; orderless
  691. (use-package orderless
  692. :autoload orderless-define-completion-style
  693. :hook (text-mode . my/-setup-text-mode-completion-styles)
  694. :init
  695. (defun my/-setup-text-mode-completion-styles ()
  696. (setq-local completion-styles '(basic)))
  697. (orderless-define-completion-style my/orderless-with-initialism
  698. (orderless-matching-styles '(orderless-initialism
  699. orderless-regexp)))
  700. (setq orderless-matching-styles '(orderless-regexp)
  701. completion-styles '(orderless basic)
  702. completion-category-defaults nil
  703. completion-category-overrides '((file
  704. (styles basic partial-completion))
  705. (command
  706. (styles my/orderless-with-initialism basic)))))
  707. ;; marginalia
  708. (use-package marginalia
  709. :bind (:map minibuffer-local-map
  710. ("M-a" . marginalia-cycle))
  711. :init
  712. (marginalia-mode 1))
  713. ;; embark
  714. (use-package embark
  715. :bind (("C-," . embark-act)
  716. ("C-;" . embark-dwim)
  717. :map help-map
  718. ("B" . embark-bindings)
  719. :map embark-symbol-map
  720. ("h" . helpful-symbol)
  721. :map embark-become-file+buffer-map
  722. ("b" . consult-buffer)
  723. ("B" . switch-to-buffer))
  724. :init
  725. (setq embark-quit-after-action nil
  726. embark-indicators '(embark-minimal-indicator
  727. embark-isearch-highlight-indicator
  728. embark-highlight-indicator))
  729. :config
  730. (defvar-keymap my/embark-string-map
  731. :doc "Keymap for Embark string actions."
  732. :parent embark-expression-map
  733. "R" 'repunctuate-sentences)
  734. (defun my/embark-target-string ()
  735. "Target the string at point."
  736. (if-let (((not (eobp))) ; prevent next line from causing errors
  737. (bounds (bounds-of-thing-at-point 'string)))
  738. (append (list 'string (buffer-substring-no-properties (car bounds)
  739. (cdr bounds)))
  740. bounds)))
  741. (add-to-list 'embark-around-action-hooks
  742. '(repunctuate-sentences embark--mark-target))
  743. (add-to-list 'embark-keymap-alist
  744. '(string my/embark-string-map))
  745. (add-to-list 'embark-target-finders 'my/embark-target-string)
  746. (add-to-list 'display-buffer-alist
  747. '("\\`\\*Embark Collect \\(Live\\|Completions\\)\\*"
  748. nil
  749. (window-parameters (mode-line-format . none))))
  750. (evil-define-key '(normal motion) org-mode-map
  751. (kbd "C-,") #'embark-act))
  752. ;; consult
  753. (use-package consult
  754. :bind (("C-s" . consult-line)
  755. ("C-x b" . consult-buffer)
  756. ("C-S-s" . consult-ripgrep)
  757. ("C-x C-S-f" . consult-fd)
  758. ("C-x c k" . consult-keep-lines)
  759. ("C-x c f" . consult-focus-lines)
  760. ("C-x c r" . consult-recent-file)
  761. ("C-x c b" . consult-bookmark)
  762. ("C-x c d" . consult-fd)
  763. ("C-x c g" . consult-ripgrep)
  764. ("C-x c y" . consult-yank-from-kill-ring)
  765. ("M-g i" . consult-imenu)
  766. ("M-g I" . consult-imenu-multi)
  767. ("M-g r" . consult-imenu-multi)
  768. :map help-map
  769. ("TAB". consult-info)
  770. ("C-m" . consult-man))
  771. :hook (minibuffer-setup . my/consult-setup-minibuffer-completion)
  772. :init
  773. (defun my/consult-setup-minibuffer-completion ()
  774. (setq-local completion-in-region-function #'consult-completion-in-region))
  775. (evil-declare-motion #'consult-line))
  776. (use-package consult-eglot
  777. :commands consult-eglot-symbols)
  778. ;; wgrep
  779. (use-package wgrep)
  780. ;; integration for embark and consult
  781. (use-package embark-consult
  782. :hook (embark-collect-mode . consult-preview-at-point-mode))
  783. ;; corfu (autocomplete)
  784. (use-package corfu
  785. :bind (("M-<tab>" . completion-at-point)
  786. :map corfu-map
  787. ("C-j" . corfu-next)
  788. ("C-k" . corfu-previous)
  789. ("M-SPC" . corfu-insert-separator)
  790. ("M-m" . my/corfu-move-to-minibuffer))
  791. :init
  792. (defun my/corfu-move-to-minibuffer ()
  793. (interactive)
  794. (when completion-in-region--data
  795. (let ((completion-extra-properties corfu--extra)
  796. (completion-cycle-threshold completion-cycling))
  797. (apply #'consult-completion-in-region completion-in-region--data))))
  798. (setq corfu-cycle t
  799. corfu-auto t
  800. corfu-on-exact-match nil
  801. corfu-popupinfo-delay '(1.0 . 0.5)
  802. completion-cycle-threshold nil
  803. global-corfu-minibuffer
  804. ;; only enable corfu in the minibuffer in graphical frames
  805. (lambda ()
  806. (and (display-graphic-p)
  807. (not (eq (current-local-map)
  808. read-passwd-map)))))
  809. (global-corfu-mode 1)
  810. (corfu-popupinfo-mode 1)
  811. :config
  812. (add-to-list 'corfu-continue-commands #'my/corfu-move-to-minibuffer)
  813. (defun my/help-buffer-exists-p ()
  814. "Return if the buffer that `help-buffer' would, or nil if it doesn't exist."
  815. (or (and help-xref-following (derived-mode-p 'help-mode))
  816. (get-buffer "*Help*")))
  817. (defun my/-corfu-popupinfo-close-help-buffer (oldfun &rest args)
  818. (if (derived-mode-p 'emacs-lisp-mode)
  819. (let ((help-buf (my/help-buffer-exists-p)))
  820. (prog1
  821. (apply oldfun args)
  822. (when-let (((not help-buf))
  823. (buf (help-buffer)))
  824. ;; Ensure that, even if `help-buffer' returns nil in the future, we
  825. ;; don't kill the current buffer
  826. (kill-buffer buf))))
  827. (apply oldfun args)))
  828. (advice-add 'corfu-popupinfo--get-documentation :around
  829. 'my/-corfu-popupinfo-close-help-buffer))
  830. (use-package corfu-terminal
  831. :init
  832. (corfu-terminal-mode 1)
  833. :config
  834. (require 'corfu-terminal-popupinfo)
  835. (corfu-terminal-popupinfo-mode 1))
  836. (use-package dabbrev
  837. :ensure nil
  838. :config
  839. (add-to-list 'dabbrev-ignored-buffer-regexps "\\` ")
  840. (add-to-list 'dabbrev-ignored-buffer-modes 'doc-view-mode)
  841. (add-to-list 'dabbrev-ignored-buffer-modes 'pdf-view-mode)
  842. (add-to-list 'dabbrev-ignored-buffer-modes 'tags-table-mode))
  843. ;; cape (a bunch of capfs!)
  844. (use-package cape
  845. :bind (("C-c p" . cape-dabbrev)
  846. ([remap dabbrev-expand] . cape-dabbrev)
  847. ("C-c P" . cape-line)
  848. ("C-c f" . cape-file))
  849. :hook (text-mode . my/-cape-setup-text-mode)
  850. :init
  851. (defun my/-cape-setup-text-mode ()
  852. ;; Only run this if we are not in `TeX-mode'
  853. (unless (bound-and-true-p TeX-mode-p)
  854. (setq-local completion-at-point-functions
  855. (append completion-at-point-functions (list 'cape-dict
  856. 'cape-dabbrev))
  857. corfu-auto nil))))
  858. ;; xref
  859. (use-package xref
  860. :init
  861. (evil-define-key '(normal motion) 'global
  862. "gr" #'xref-find-references)
  863. (setq xref-show-xrefs-function #'consult-xref
  864. xref-show-definitions-function #'consult-xref))
  865. ;; popup.el
  866. (use-package popup)
  867. ;; posframe
  868. (use-package posframe
  869. :init
  870. (defun my/posframe-tip (name msg)
  871. "Like `popup-tip', but with a posframe.
  872. NAME should be the buffer name to pass to `posframe-show'. MSG is the message to
  873. display."
  874. (unwind-protect
  875. (progn
  876. (posframe-show name
  877. :string msg
  878. :position (point)
  879. :max-width 80
  880. :border-width 2
  881. :border-color "white")
  882. (clear-this-command-keys)
  883. (push (read-event) unread-command-events)
  884. (posframe-hide name))
  885. (posframe-hide name))))
  886. (defun my/floating-tooltip (name msg)
  887. "If `display-graphic-p', call `my/posframe-tip', otherwise `popup-tip'.
  888. MSG is the message to show in the popup. NAME is the name of the buffer to pass
  889. to `posframe-show' if the display is graphical."
  890. (if (display-graphic-p)
  891. (my/posframe-tip name msg)
  892. (popup-tip msg)))
  893. ;; flymake
  894. (use-package flymake
  895. :config
  896. (require 'consult-flymake))
  897. ;; flycheck
  898. (use-package flycheck
  899. :hook ((sh-mode emacs-lisp-mode) . flycheck-mode)
  900. :custom
  901. (flycheck-indication-mode 'left-margin)
  902. :init
  903. (setq flycheck-display-errors-function nil))
  904. (use-package consult-flycheck)
  905. (defun my/sly-notes-at-point (&optional pos buffer)
  906. "Return the sly notes at POS in BUFFER.
  907. If BUFFER is nil, the current buffer is used."
  908. (with-current-buffer (or buffer (current-buffer))
  909. (unless pos
  910. (setq pos (point)))
  911. (cl-loop for overlay in (overlays-at pos)
  912. for note = (overlay-get overlay 'sly-note)
  913. when note
  914. collect note)))
  915. (defun my/diagnostic-at-point ()
  916. "Show the diagnostics under point."
  917. (interactive)
  918. (let ((message))
  919. (when-let (((bound-and-true-p flymake-mode))
  920. (diag (get-char-property (point) 'flymake-diagnostic)))
  921. (cl-callf nconc message (string-split (flymake--diag-text diag) "\n" t)))
  922. (when (bound-and-true-p flycheck-mode)
  923. (cl-callf nconc message
  924. (mapcar 'flycheck-error-message (flycheck-overlay-errors-at (point)))))
  925. ;; sly (lazy-loaded)
  926. (when (featurep 'sly)
  927. (cl-callf nconc message (mapcar (lambda (note)
  928. (plist-get note :message))
  929. (my/sly-notes-at-point))))
  930. ;; jinx
  931. (when-let (((bound-and-true-p jinx-mode))
  932. (jinx-msg (jinx--get-overlays (point) (1+ (point)))))
  933. (push "misspelled word" message))
  934. (when message
  935. (my/floating-tooltip " *my-diagnostic-posframe*"
  936. (mapconcat (lambda (msg)
  937. (concat "•" msg))
  938. message "\n")))))
  939. (defconst my/consult-flymake-flycheck-narrow
  940. '((?e . "Error")
  941. (?w . "Warning")
  942. (?i . "Info")
  943. (?n . "Info")))
  944. (defun my/-consult-replace-flymake-error-level (candidates)
  945. "Return CANDIDATES with the flymake error level note replaced with info."
  946. (cl-loop for cand in candidates
  947. collect
  948. (cl-loop
  949. with start = nil
  950. for i below (length cand)
  951. for props = (text-properties-at i cand)
  952. for face = (plist-get props 'face)
  953. when (eq face 'compilation-info) do
  954. (setq start (or start i))
  955. else when start do
  956. (setf (substring cand start i)
  957. (propertize (string-pad "info" (- i start))
  958. 'face (flycheck-error-level-error-list-face
  959. 'info)))
  960. (cl-return cand)
  961. finally return cand)))
  962. (defun my/consult-flymake-flycheck-candidates (&optional project)
  963. "Return combined candidate list for flymake and flycheck.
  964. With PROJECT, return the candiadeets for that project."
  965. (let ((had-errors))
  966. (prog1
  967. (seq-uniq
  968. (append
  969. (when-let (((bound-and-true-p flymake-mode))
  970. (diags (if project (flymake--project-diagnostics
  971. project)
  972. (flymake-diagnostics))))
  973. (setq had-errors t)
  974. (my/-consult-replace-flymake-error-level
  975. (consult-flymake--candidates diags)))
  976. (when (boundp 'flycheck-mode)
  977. (if project
  978. (cl-loop for buf in (project-buffers project)
  979. append
  980. (with-current-buffer buf
  981. (when (and flycheck-mode flycheck-current-errors)
  982. (setq had-errors t)
  983. (consult-flycheck--candidates))))
  984. (when (and flycheck-mode flycheck-current-errors)
  985. (setq had-errors t)
  986. (consult-flycheck--candidates))))))
  987. (unless had-errors
  988. (user-error "No errors (Flymake: %s | Flycheck: %s)"
  989. (cond
  990. ((not (bound-and-true-p flymake-mode))
  991. "not running")
  992. ((seq-difference (flymake-running-backends)
  993. (flymake-reporting-backends))
  994. "running")
  995. (t "finished"))
  996. (if (boundp 'flycheck-last-status-change)
  997. flycheck-last-status-change
  998. "not running"))))))
  999. (defun my/consult-flymake-flycheck (&optional project)
  1000. "Jump to flymake or flycheck error.
  1001. With PROJECT, give diagnostics for all buffers in the current project."
  1002. (interactive "P")
  1003. (consult--read
  1004. (consult--with-increased-gc
  1005. (my/consult-flymake-flycheck-candidates
  1006. (and project (project-current))))
  1007. :prompt "Error: "
  1008. :category 'flymake-flycheck-error
  1009. :history t
  1010. :require-match t
  1011. :sort nil
  1012. :narrow (consult--type-narrow my/consult-flymake-flycheck-narrow)
  1013. :group (consult--type-group my/consult-flymake-flycheck-narrow)
  1014. :lookup #'consult--lookup-candidate
  1015. :state (consult--jump-state)))
  1016. (with-eval-after-load 'flymake
  1017. (keymap-set flymake-mode-map "C-c e" 'my/diagnostic-at-point)
  1018. (keymap-set flymake-mode-map "C-c E" 'my/consult-flymake-flycheck))
  1019. (with-eval-after-load 'flycheck
  1020. (keymap-set flycheck-mode-map "C-c e" 'my/diagnostic-at-point)
  1021. (keymap-set flycheck-mode-map "C-c E" 'my/consult-flymake-flycheck))
  1022. (with-eval-after-load 'jinx
  1023. (keymap-set jinx-mode-map "C-c e" 'my/diagnostic-at-point))
  1024. ;; eldoc
  1025. (use-package eldoc
  1026. :diminish eldoc-mode
  1027. :init
  1028. (setq-default eldoc-echo-area-use-multiline-p nil))
  1029. ;; eglot
  1030. (use-package eglot
  1031. :demand t
  1032. :pin gnu ;; try to force Elpa version to fix warnings
  1033. :hook ((eglot-managed-mode . my/-eglot-setup))
  1034. :init
  1035. ;; (defun my/eglot-in-text-mode-only ()
  1036. ;; (when (eq major-mode 'text-mode)
  1037. ;; (eglot-ensure)))
  1038. (defvar my/-eglot-documentation-buffer nil
  1039. "Buffer for showing documentation for `my/eglot-documentation-at-point'.")
  1040. (defun my/eglot-documentation-at-point ()
  1041. "Show documentation for a symbol at point."
  1042. (interactive)
  1043. (if-let (server (eglot-current-server))
  1044. (progn
  1045. (if-let* (((not (buffer-live-p my/-eglot-documentation-buffer)))
  1046. (name (generate-new-buffer-name "*eglot documentation*")))
  1047. (setq my/-eglot-documentation-buffer (generate-new-buffer name)))
  1048. (eglot-hover-eldoc-function
  1049. (lambda (info _ _)
  1050. (if-let (((not (seq-empty-p info)))
  1051. (buff (current-buffer)))
  1052. (with-current-buffer my/-eglot-documentation-buffer
  1053. (read-only-mode -1)
  1054. (erase-buffer)
  1055. (insert info)
  1056. (goto-char (point-min))
  1057. (special-mode)
  1058. (read-only-mode 1)
  1059. (when (not (get-buffer-window my/-eglot-documentation-buffer nil))
  1060. (switch-to-buffer-other-window my/-eglot-documentation-buffer t)
  1061. (switch-to-buffer-other-window buff t)))))))))
  1062. (defun my/-eglot-cleanup-doc-buffer (_server &optional _interactive _timeout
  1063. preserve-buffers)
  1064. (when (and (not preserve-buffers)
  1065. (buffer-live-p my/-eglot-documentation-buffer)
  1066. (cl-every (lambda (buffer)
  1067. (with-current-buffer buffer
  1068. (let ((server (eglot-current-server)))
  1069. (or (not (eglot-lsp-server-p server))
  1070. (eglot--shutdown-requested server)))))
  1071. (buffer-list)))
  1072. (kill-buffer my/-eglot-documentation-buffer)))
  1073. (advice-add 'eglot-shutdown :after 'my/-eglot-cleanup-doc-buffer)
  1074. (defun my/-eglot-setup ()
  1075. "Setup eldoc variables for `eglot-managed-mode-hook'."
  1076. (setq-local evil-lookup-func #'my/eglot-documentation-at-point)
  1077. (evil-define-key '(normal motion) 'local
  1078. "K" #'evil-lookup
  1079. "gR" #'eglot-rename
  1080. "gA" #'eglot-code-actions
  1081. "gs" #'consult-eglot-symbols)
  1082. (eglot-inlay-hints-mode -1))
  1083. (setq eglot-autoshutdown t)
  1084. :config
  1085. (add-to-list 'eglot-server-programs
  1086. (cons '(c-mode c-ts-mode c++-mode c++-ts-mode objc-mode)
  1087. '("clangd" "--all-scopes-completion" "--background-index"
  1088. "--clang-tidy" "--completion-style=detailed"
  1089. "--header-insertion=never" "--pch-storage=memory"
  1090. "--function-arg-placeholders"))))
  1091. ;; LTeX (languagetool)
  1092. (require 'ltex-eglot)
  1093. ;; gud
  1094. (use-package gud
  1095. :demand t
  1096. :ensure nil
  1097. :after (project evil)
  1098. :bind (:map project-prefix-map
  1099. ("U" . my/project-gdb))
  1100. :config
  1101. (setq gdb-debuginfod-enable-setting t)
  1102. (defvar my/project-gdb-command nil
  1103. "Command to use in `my/project-gdb'.")
  1104. (put 'my/project-gdb-command 'safe-local-variable (lambda (val)
  1105. (stringp val)))
  1106. (defun my/project-gdb (project command-line)
  1107. "Run gdb in the project root"
  1108. (interactive (let* ((project (project-current t))
  1109. (default-directory (project-root project)))
  1110. (list project (gud-query-cmdline 'gdb))))
  1111. (let ((default-directory (project-root project)))
  1112. (gdb command-line)))
  1113. (evil-set-initial-state 'gdb-locals-mode 'motion)
  1114. (evil-collection-inhibit-insert-state 'gdb-locals-mode-map)
  1115. (evil-define-key '(normal motion visual) gdb-locals-mode-map
  1116. (kbd "TAB") (keymap-lookup gdb-locals-mode-map "TAB")
  1117. (kbd "RET") #'gdb-edit-locals-value
  1118. (kbd "<mouse-1>") #'gdb-edit-locals-value
  1119. "q" #'kill-current-buffer)
  1120. (evil-set-initial-state 'gdb-registers-mode 'motion)
  1121. (evil-collection-inhibit-insert-state 'gdb-registers-mode-map)
  1122. (evil-define-key '(normal motion visual) gdb-registers-mode-map
  1123. (kbd "TAB") (keymap-lookup gdb-registers-mode-map "TAB")
  1124. (kbd "RET") #'gdb-edit-register-value
  1125. (kbd "<mouse-1>") #'gdb-edit-register-value
  1126. "q" #'kill-current-buffer
  1127. (kbd "C-c f") #'gdb-registers-toggle-filter
  1128. (kbd "C-c F") (lambda ()
  1129. "Customize the filter for the registers buffer."
  1130. (interactive)
  1131. (customize-option-other-window
  1132. 'gdb-registers-filter-pattern-list)))
  1133. (evil-set-initial-state 'gdb-frames-mode 'motion)
  1134. (evil-collection-inhibit-insert-state 'gdb-frames-mode-map)
  1135. (evil-define-key '(normal motion visual) gdb-frames-mode-map
  1136. "q" #'kill-current-buffer
  1137. (kbd "RET") #'gdb-select-frame)
  1138. (evil-set-initial-state 'gdb-breakpoints-mode 'motion)
  1139. (evil-collection-inhibit-insert-state 'gdb-breakpoints-mode-map)
  1140. (evil-define-key '(normal motion visual) gdb-breakpoints-mode-map
  1141. (kbd "TAB") (keymap-lookup gdb-breakpoints-mode-map "TAB")
  1142. "q" #'gdb-delete-frame-or-window
  1143. "D" #'gdb-delete-breakpoint
  1144. (kbd "RET") #'gdb-goto-breakpoint
  1145. (kbd "<mouse-1>") #'gdb-goto-breakpoint
  1146. (kbd "SPC") #'gdb-toggle-breakpoint)
  1147. (evil-set-initial-state 'gdb-threads-mode 'motion)
  1148. (evil-collection-inhibit-insert-state 'gdb-threads-mode-map)
  1149. (evil-define-key '(normal motion visual) gdb-threads-mode-map
  1150. (kbd "TAB") (keymap-lookup gdb-threads-mode-map "TAB")
  1151. "q" #'gdb-delete-frame-or-window
  1152. "D" #'gdb-frame-disassembly-for-thread
  1153. (kbd "C-c f") #'gdb-display-stack-for-thread
  1154. (kbd "C-c i") #'gdb-interrupt-thread
  1155. (kbd "C-c l") #'gdb-display-locals-for-thread
  1156. (kbd "C-c r") #'gdb-display-registers-for-thread
  1157. (kbd "C-c c") #'gdb-continue-thread
  1158. (kbd "C-c d") #'gdb-display-disassembly-for-thread
  1159. (kbd "C-c s") #'gdb-step-thread
  1160. (kbd "C-c F") #'gdb-frame-stack-for-thread
  1161. (kbd "C-c L") #'gdb-frame-locals-for-thread
  1162. (kbd "C-c R") #'gdb-frame-registers-for-thread
  1163. (kbd "RET") #'gdb-select-thread
  1164. (kbd "<mouse-2>") #'gdb-select-thread))
  1165. ;; dape
  1166. (use-package dape
  1167. :hook ((after-init . dape-breakpoint-load)
  1168. (kill-emacs . dape-breakpoint-save)
  1169. (dape-start . save-some-buffers)
  1170. (dape-display-source . pulse-momentary-highlight-one-line))
  1171. :bind (:map dape-info-parent-mode-map
  1172. ("<tab>" . dape--info-buffer-tab))
  1173. :init
  1174. (setopt dape-default-breakpoints-file (no-littering-expand-var-file-name
  1175. "dape-breakpoints"))
  1176. :config
  1177. (setopt dape-buffer-window-arrangement 'right)
  1178. (dape-breakpoint-global-mode 1))
  1179. ;; dumb-jump
  1180. (use-package dumb-jump
  1181. :init
  1182. (add-hook 'xref-backend-functions #'dumb-jump-xref-activate))
  1183. ;; yasnippet
  1184. (use-package yasnippet
  1185. :demand t
  1186. :bind ("C-c s" . yas-expand)
  1187. :config
  1188. (yas-global-mode 1))
  1189. ;; project.el
  1190. (use-package project
  1191. :bind (("C-c v" . my/project-eshell-or-default)
  1192. ([remap project-compile] . my/project-compile-or-default)
  1193. :map project-prefix-map
  1194. ("s" . my/project-eshell)
  1195. ("u" . my/project-run))
  1196. :init
  1197. (defvar eshell-buffer-name)
  1198. (defun my/project-eshell (prompt &optional arg)
  1199. "Switch to or create an eshell buffer in the current projects root."
  1200. (interactive (list t current-prefix-arg))
  1201. (if-let ((proj (project-current prompt))
  1202. (default-directory (project-root proj))
  1203. (eshell-buffer-name
  1204. (concat "*eshell for project " default-directory "*")))
  1205. (eshell arg)))
  1206. (defun my/project-eshell-or-default (&optional arg)
  1207. "Open an eshell for the current project, otherwise, open a normal eshell."
  1208. (interactive "P")
  1209. (unless (my/project-eshell nil arg)
  1210. (eshell arg)))
  1211. (defun my/project-compile-or-default ()
  1212. "If in a project, run `project-compile', otherwise run `compile'."
  1213. (interactive)
  1214. (if (project-current)
  1215. (call-interactively 'project-compile)
  1216. (call-interactively 'compile)))
  1217. (defvar my/project-run-command nil
  1218. "Command to run with `my/project-run'.")
  1219. (put 'my/project-run-command 'safe-local-variable (lambda (val)
  1220. (stringp val)))
  1221. (defvar my/project-run-dir nil
  1222. "Directory to run project in with `my/project-run'.")
  1223. (put 'my/project-run-dir 'safe-local-variable (lambda (val)
  1224. (stringp val)))
  1225. (defvar my/-project-run-history '()
  1226. "Commands previously run with `my/project-run'")
  1227. (defvar my/project-root-marker ".project-root"
  1228. "Marker file to look for in non-vc backed projects.")
  1229. (defun my/project-get-root-dir ()
  1230. "Get the root dir for the current project"
  1231. (let* ((proj (project-current nil))
  1232. (default-directory (if proj
  1233. (project-root proj)
  1234. default-directory)))
  1235. (if my/project-run-dir
  1236. (expand-file-name my/project-run-dir)
  1237. default-directory)))
  1238. (defun my/project-run (command comint)
  1239. "Like `project-compile', but for running a project.
  1240. COMMAND and COMINT are like `compile'."
  1241. (interactive
  1242. (list
  1243. (let ((default-directory (my/project-get-root-dir)))
  1244. (read-shell-command "Run Command: "
  1245. (or (car my/-project-run-history)
  1246. my/project-run-command)
  1247. (if (and my/project-run-command
  1248. (equal my/project-run-command
  1249. (car-safe my/-project-run-history)))
  1250. '(my/-project-run-history . 1)
  1251. 'my/-project-run-history)))
  1252. (consp current-prefix-arg)))
  1253. (let* ((default-directory (my/project-get-root-dir))
  1254. (compilation-buffer-name-function (lambda (_)
  1255. (progn "*run project*")))
  1256. (compilation-directory default-directory)
  1257. (compile-history nil)
  1258. (compile-command nil))
  1259. (compile command comint)
  1260. (when (not my/project-run-command)
  1261. (setq my/project-run-command command))))
  1262. :config
  1263. (defun my/project-try-dotfile (dir)
  1264. (if-let (root (locate-dominating-file dir my/project-root-marker))
  1265. (list 'vc nil root)))
  1266. (add-hook 'project-find-functions #'my/project-try-dotfile))
  1267. ;; nxml
  1268. (use-package nxml-mode
  1269. :ensure nil
  1270. :hook (nxml-mode . my/-nxml-setup)
  1271. :init
  1272. (defun my/-nxml-setup ()
  1273. "Setup `nxml-mode'."
  1274. (sgml-electric-tag-pair-mode 1)
  1275. (setq-local completion-at-point-functions
  1276. '(rng-completion-at-point cape-file)))
  1277. (add-to-list 'auto-mode-alist
  1278. `(,(concat
  1279. (regexp-opt '("gschema" "gresource" "ui")) "\\'")
  1280. . nxml-mode)))
  1281. ;; Bibtex (built in)
  1282. (require 'bibtex)
  1283. (defun my/bibtex-in-entry-p (&optional exclude-braces)
  1284. "Return t is point is inside a BibTeX entry.
  1285. When EXCLUDE-BRACES is non-nil, don't count the first and last brace of the
  1286. entry as in the entry. That is, if the point is on the first { or last } of the
  1287. entry, return nil."
  1288. (save-excursion
  1289. (when (and exclude-braces (eq ?\} (char-after)))
  1290. (forward-char))
  1291. ;; go to top level and check if the character at point is {
  1292. (let ((start-pos (point))
  1293. (last-valid (point)))
  1294. (condition-case nil
  1295. (while t
  1296. (backward-up-list 1 t t)
  1297. (setq last-valid (point)))
  1298. (error
  1299. (and
  1300. (eq ?\{ (char-after last-valid))
  1301. (or (not exclude-braces)
  1302. (not (= start-pos last-valid)))))))))
  1303. (defvar my/bibtex-indent-width 4
  1304. "Width to indent for `my/bibtex-calculate-indentation'.")
  1305. (defun my/bibtex-calculate-indentation ()
  1306. "Calculate the column to indent to on the current line."
  1307. (save-excursion
  1308. (back-to-indentation)
  1309. (if (my/bibtex-in-entry-p t)
  1310. my/bibtex-indent-width
  1311. 0)))
  1312. (defun my/bibtex-empty-line-p ()
  1313. "Return t if the current line is only blank characters."
  1314. (save-excursion
  1315. (beginning-of-line)
  1316. (looking-at (rx (* blank) eol))))
  1317. (defun my/bibtex-indent-line ()
  1318. "Indent the current line."
  1319. (interactive)
  1320. (save-excursion
  1321. (beginning-of-line)
  1322. (when (looking-at (rx (+ blank)))
  1323. (delete-region (point) (match-end 0)))
  1324. (indent-to (my/bibtex-calculate-indentation)))
  1325. (when (looking-at (rx (+ blank) eol))
  1326. (end-of-line)))
  1327. (defun my/bibtex-indent-or-find-text ()
  1328. "Either indent the current line or jump to the current fields text.
  1329. If the current line is only whitespace call `my/bibtex-calculate-indentation',
  1330. otherwise, call `bibtex-find-text'."
  1331. (interactive)
  1332. (if (my/bibtex-empty-line-p)
  1333. (my/bibtex-indent-line)
  1334. (bibtex-find-text)))
  1335. (defun my/bibtex-indent-or-find-text-and-insert ()
  1336. "Like `my/bibtex-indent-or-find-text', but enter insert mode after."
  1337. (interactive)
  1338. (my/bibtex-indent-or-find-text)
  1339. (if (my/bibtex-empty-line-p)
  1340. (evil-append 1)
  1341. (evil-insert 1)))
  1342. (defun my/-bibtex-setup-indent ()
  1343. "Set up `bibtex-mode' indentation stuff."
  1344. (setq-local indent-line-function 'my/bibtex-indent-line
  1345. electric-indent-chars '(?\n ?\{ ?\} ?,)))
  1346. (defun my/-bibtex-fix-fill-prefix ()
  1347. "`bivtex-mode' has a bad habbit of messing up `fill-prefix'."
  1348. (when (eq major-mode 'bibtex-mode)
  1349. (setq-local fill-prefix nil)))
  1350. (advice-add 'bibtex-mode :after 'my/-bibtex-fix-fill-prefix)
  1351. (add-hook 'bibtex-mode-hook 'my/-bibtex-setup-indent)
  1352. (keymap-set bibtex-mode-map "RET" 'newline-and-indent)
  1353. (keymap-set bibtex-mode-map "TAB" 'my/bibtex-indent-or-find-text)
  1354. (evil-define-key 'normal bibtex-mode-map
  1355. (kbd "TAB") 'my/bibtex-indent-or-find-text-and-insert)
  1356. ;; Latex help (from elisp file)
  1357. (require 'latex-help)
  1358. ;; AUCTeX
  1359. (use-package auctex
  1360. :hook ((LaTeX-mode . turn-on-reftex)
  1361. (LaTeX-mode . LaTeX-math-mode)
  1362. (LaTeX-mode . my/-setup-LaTeX-mode)
  1363. (LaTeX-mode . flycheck-mode))
  1364. :bind (:map TeX-mode-map
  1365. ("C-c ?" . latex-help))
  1366. :init
  1367. (add-to-list 'major-mode-remap-alist '(plain-tex-mode . plain-TeX-mode))
  1368. (add-to-list 'major-mode-remap-alist '(latex-mode . LaTeX-mode))
  1369. (add-to-list 'major-mode-remap-alist '(ams-tex-mode . AmSTeX-mode))
  1370. (add-to-list 'major-mode-remap-alist '(context-mode . ConTeXt-mode))
  1371. (add-to-list 'major-mode-remap-alist '(texinfo-mode . Texinfo-mode))
  1372. (add-to-list 'major-mode-remap-alist '(doctex-mode . docTeX-mode))
  1373. (add-to-list 'auto-mode-alist '("/\\.latexmkrc\\'" . perl-mode))
  1374. (add-to-list 'auto-mode-alist '("\\.[tT]e[xX]\\'" . LaTeX-mode))
  1375. :config
  1376. (defun my/-auctex-texdoc-setup-env (oldfun &rest args)
  1377. (let ((process-environment process-environment)
  1378. (emacs-cmd (concat "emacsclient" (and (not (display-graphic-p)) " -nw"))))
  1379. (setenv "PDFVIEWER_texdoc" "evince")
  1380. (setenv "MDVIEWER_texdoc" emacs-cmd)
  1381. (setenv "PAGER_texdoc" emacs-cmd)
  1382. (apply oldfun args)))
  1383. (advice-add 'TeX-documentation-texdoc :around 'my/-auctex-texdoc-setup-env)
  1384. (defun my/-setup-LaTeX-mode ()
  1385. (setq evil-lookup-func 'latex-help-at-point))
  1386. (setq TeX-auto-save t
  1387. TeX-parse-self t
  1388. reftex-plug-into-AUCTeX t)
  1389. (evil-define-operator my/evil-LaTeX-fill (beg end)
  1390. "Like `evil-fill', but using auctex."
  1391. ;; The code here came straight from `evil-fill'
  1392. :move-point nil
  1393. :type line
  1394. (save-excursion
  1395. (ignore-errors (LaTeX-fill-region beg end))))
  1396. (evil-define-operator my/evil-LaTeX-fill-and-move (beg end)
  1397. "Like `evil-fill-and-move', but using auctex."
  1398. ;; The code here came straight from `evil-fill-and-move'
  1399. :move-point nil
  1400. :type line
  1401. (let ((marker (make-marker)))
  1402. (move-marker marker (1- end))
  1403. (ignore-errors
  1404. (LaTeX-fill-region beg end)
  1405. (goto-char marker)
  1406. (evil-first-non-blank))))
  1407. (evil-define-key 'normal TeX-mode-map
  1408. "gq" 'my/evil-LaTeX-fill-and-move
  1409. "gw" 'my/evil-LaTeX-fill)
  1410. (setq-default TeX-master nil)
  1411. (require 'tex)
  1412. (TeX-global-PDF-mode 1))
  1413. ;; blueprint
  1414. (use-package blueprint-ts-mode
  1415. :hook (blueprint-ts-mode . eglot-ensure)
  1416. :after eglot)
  1417. ;; python-ts-mode
  1418. (use-package python-ts-mode
  1419. :ensure nil
  1420. :hook (python-ts-mode . eglot-ensure))
  1421. ;; java-ts-mode
  1422. (use-package java-ts-mode
  1423. :hook (java-ts-mode . eglot-ensure))
  1424. ;; c-ts-mode
  1425. (use-package c-ts-mode
  1426. :after evil
  1427. :hook ((c-ts-mode c++-ts-mode) . eglot-ensure)
  1428. :init
  1429. (setq-default c-ts-mode-indent-offset 4)
  1430. :config
  1431. (evil-define-key 'normal 'c-ts-mode-map
  1432. "go" #'ff-find-other-file
  1433. "gO" #'ff-find-other-file-other-window)
  1434. (evil-define-key 'normal 'c++-ts-mode-map
  1435. "go" #'ff-find-other-file
  1436. "gO" #'ff-find-other-file-other-window)
  1437. (evil-define-key 'normal 'objc-mode-map
  1438. "go" #'ff-find-other-file
  1439. "gO" #'ff-find-other-file-other-window))
  1440. ;; php-mode
  1441. (use-package php-mode
  1442. :hook (php-mode . eglot-ensure))
  1443. ;; web-mode
  1444. (use-package web-mode
  1445. :hook (web-mode . eglot-ensure)
  1446. :init
  1447. (add-to-list 'eglot-server-programs
  1448. '(web-mode . ("vscode-html-language-server" "--stdio"))))
  1449. ;; Polymode
  1450. (use-package polymode
  1451. :config
  1452. (define-hostmode my/poly-web-hostmode
  1453. :mode 'web-mode)
  1454. (define-innermode my/poly-php-innermode
  1455. :mode 'php-mode
  1456. :head-matcher "\<\?php"
  1457. :tail-matcher "\?\>"
  1458. :head-mode 'body
  1459. :tail-mode 'body)
  1460. (define-polymode my/poly-web-mode
  1461. :hostmode 'my/poly-web-hostmode
  1462. :innermodes '(my/poly-php-innermode))
  1463. (add-to-list 'auto-mode-alist '("\\.php\\|\\.phtml\\'" . my/poly-web-mode)))
  1464. ;; shell-mode
  1465. (use-package sh-script
  1466. :ensure nil
  1467. :hook (sh-mode . my/-setup-sh-mode)
  1468. :init
  1469. (defun my/-setup-sh-mode ()
  1470. (add-to-list 'completion-at-point-functions #'cape-file)))
  1471. ;; go mode
  1472. (use-package go-mode
  1473. :defer nil
  1474. :hook (go-mode . eglot-ensure))
  1475. (use-package go-ts-mode
  1476. :ensure nil
  1477. :hook (go-ts-mode . eglot-ensure))
  1478. ;; rust
  1479. (use-package rust-mode)
  1480. (use-package rust-ts-mode
  1481. :ensure nil
  1482. :hook (rust-ts-mode . eglot-ensure))
  1483. ;; zig
  1484. (use-package zig-mode
  1485. :hook (zig-mode . eglot-ensure))
  1486. ;; lua
  1487. (use-package lua-mode
  1488. :hook (lua-mode . eglot-ensure))
  1489. ;; markdown
  1490. (use-package markdown-mode
  1491. :hook (markdown-mode . auto-fill-mode))
  1492. ;; groovy
  1493. (use-package groovy-mode)
  1494. ;; cmake
  1495. (require 'cmake-mode)
  1496. (with-eval-after-load 'cmake-mode
  1497. (defun my/setup-cmake-ts-mode ()
  1498. "Setup `cmake-ts-mode' buffers."
  1499. (setq-local indent-line-function #'cmake-indent))
  1500. (add-hook 'cmake-ts-mode-hook #'my/setup-cmake-ts-mode))
  1501. ;; kdl
  1502. (require 'kdl-ts-mode)
  1503. ;; json
  1504. (use-package json-ts-mode
  1505. :hook (json-ts-mode . eglot-ensure))
  1506. (use-package json-mode)
  1507. ;; csv
  1508. (use-package csv-mode)
  1509. ;; firejail
  1510. (require 'firejail-mode)
  1511. ;; yaml
  1512. (use-package yaml-ts-mode
  1513. :hook ((yaml-ts-mode . eglot-ensure)
  1514. (yaml-ts-mode . my/-setup-yaml-ts-mode))
  1515. :init
  1516. (defun my/-setup-yaml-ts-mode ()
  1517. (setq indent-line-function #'yaml-indent-line)))
  1518. (use-package yaml-mode)
  1519. ;; yuck (config language for eww)
  1520. (use-package yuck-mode)
  1521. ;; Some Elisp indentation stuff
  1522. ;; Source: https://github.com/magit/emacsql
  1523. ;; emacsql.el line 394
  1524. (defun my/lisp-inside-plist-p ()
  1525. "Return t if point is inside a plist."
  1526. (save-excursion
  1527. (let ((start (point)))
  1528. (beginning-of-defun)
  1529. (when-let ((sexp (nth 1 (parse-partial-sexp (point) start))))
  1530. (goto-char sexp)
  1531. (looking-at (rx "(" (* (syntax whitespace)) ":"))))))
  1532. (defun my/-calculate-indent-fix-plists (oldfun &rest args)
  1533. "This function is meant to advise `calculate-lisp-indent'.
  1534. It calls OLDFUN with ARGS in such an environment as to prevent the default
  1535. indentation of plists."
  1536. (if (and (eq major-mode 'emacs-lisp-mode)
  1537. (save-excursion
  1538. (beginning-of-line)
  1539. (my/lisp-inside-plist-p)))
  1540. (let ((lisp-indent-offset 1))
  1541. (apply oldfun args))
  1542. (apply oldfun args)))
  1543. (advice-add 'calculate-lisp-indent :around
  1544. 'my/-calculate-indent-fix-plists)
  1545. (defvar my/max-lisp-noindent-comment-search-lines 30
  1546. "Max lines to search for the noindent comment.")
  1547. (defun my/-calculate-lisp-indent-noindent-comment (oldfun &rest args)
  1548. "This function is meant to advise `calculate-lisp-indent'.
  1549. It calls OLDFUN with ARGS, unless the line ends with the comment
  1550. ; noindent [LINES]
  1551. In this case, it just returns the current amount of indentation. LINES is the
  1552. number of lines that this comment affects. This is limited by
  1553. `my/max-lisp-noindent-comment-search-lines'.
  1554. This only works if its on the first or second form in a block. I think this is
  1555. because the indentation code only checks those and then assumes the same
  1556. indentation for every following line in the same block. This is probably OK as
  1557. I can't imagine too many instances where you need to randomly change the indent
  1558. midway through a block, and in those cases you can just stick this on the first
  1559. line in the block and manually deal with indentation."
  1560. (if (and (save-excursion
  1561. (end-of-line)
  1562. (re-search-backward
  1563. (rx (+ ";") (syntax whitespace) "noindent"
  1564. (? (syntax whitespace) (group (+ num)))
  1565. line-end)
  1566. (pos-bol (- my/max-lisp-noindent-comment-search-lines))
  1567. t))
  1568. (save-excursion
  1569. ;; if we are on a blank line, move forward a line
  1570. (when (zerop (length (buffer-substring-no-properties
  1571. (pos-bol) (pos-eol))))
  1572. (beginning-of-line 2))
  1573. (<= (count-lines (match-beginning 0) (pos-eol))
  1574. (if-let ((match (match-string 1)))
  1575. (string-to-number match)
  1576. 1))))
  1577. (save-excursion
  1578. (beginning-of-line)
  1579. (looking-at (rx (* blank)))
  1580. (length (match-string 0)))
  1581. (apply oldfun args)))
  1582. (advice-add 'calculate-lisp-indent :around
  1583. 'my/-calculate-lisp-indent-noindent-comment)
  1584. ;; sly
  1585. (use-package sly
  1586. ;; :hook (lisp-mode . my/-lisp-mode-autoconnect-sly)
  1587. :bind (:map sly-mode-map
  1588. ("C-c e" . my/diagnostic-at-point))
  1589. :autoload sly-connected-p
  1590. :init
  1591. (defun my/-lisp-mode-autoconnect-sly ()
  1592. (unless (sly-connected-p)
  1593. (sly)))
  1594. (setq inferior-lisp-program "/usr/bin/sbcl")
  1595. (defun my/-sly-fix-special-buffers ()
  1596. (when (string-match-p (rx bos "*" (* any) "*" eos) (buffer-name))
  1597. (setq-local show-trailing-whitespace nil)))
  1598. (add-hook 'lisp-mode-hook 'my/-sly-fix-special-buffers)
  1599. :config
  1600. (sly-symbol-completion-mode -1))
  1601. ;; pdf-tools
  1602. (use-package pdf-tools
  1603. :hook (pdf-view-mode . my/setup-pdf-view-mode)
  1604. :init
  1605. (setq pdf-misc-print-program-executable "lp")
  1606. (defun my/setup-pdf-view-mode ()
  1607. (display-line-numbers-mode -1)
  1608. (evil-define-key '(motion normal visual) 'local
  1609. (kbd "C-s") #'isearch-forward
  1610. (kbd "C-r") #'isearch-backward)
  1611. (setq-local cursor-type nil))
  1612. (pdf-tools-install))
  1613. ;; doc view
  1614. (use-package doc-view
  1615. :ensure nil
  1616. :hook (doc-view-mode . my/-setup-doc-view-mode)
  1617. :init
  1618. (defun my/-setup-doc-view-mode ()
  1619. (display-line-numbers-mode -1)
  1620. (evil-define-key '(motion normal visual) 'local
  1621. (kbd "C-s") #'isearch-forward
  1622. (kbd "C-r") #'isearch-backward)))
  1623. ;; calc
  1624. (use-package calc
  1625. :ensure nil
  1626. :bind (("C-c m" . quick-calc)
  1627. :map calc-mode-map
  1628. ("M-<tab>" . calc-roll-up)
  1629. ("M-TAB" . calc-roll-up))
  1630. :hook ((calc-mode calc-trail-mode) . my/setup-calc-calc-trail-mode)
  1631. :init
  1632. (defun my/setup-calc-calc-trail-mode ()
  1633. (setq-local doom-modeline-percent-position '()
  1634. truncate-partial-width-windows nil)
  1635. (visual-line-mode -1)
  1636. (display-line-numbers-mode -1)
  1637. (toggle-truncate-lines 1))
  1638. :config
  1639. (evil-define-key '(normal visual motion) calc-edit-mode-map
  1640. (kbd "RET") 'calc-edit-return
  1641. (kbd "<return>") 'calc-edit-return)
  1642. (defun my/-calc-float-mode-string ()
  1643. (cl-destructuring-bind (mode prec) calc-float-format
  1644. (concat
  1645. (upcase-initials (symbol-name mode))
  1646. (unless (zerop prec)
  1647. (concat ": " (number-to-string prec))))))
  1648. (doom-modeline-def-segment calc
  1649. "Display calculator icons and info."
  1650. (concat
  1651. (doom-modeline-spc)
  1652. (when-let ((icon (doom-modeline-icon 'faicon "nf-fa-calculator" "🖩" "")))
  1653. (concat
  1654. (doom-modeline-display-icon icon)
  1655. (doom-modeline-vspc)))
  1656. (doom-modeline--buffer-simple-name)
  1657. (when (eq major-mode 'calc-mode)
  1658. (concat
  1659. (doom-modeline-spc)
  1660. (number-to-string calc-internal-prec)
  1661. (doom-modeline-spc)
  1662. (upcase-initials (symbol-name calc-angle-mode))
  1663. (doom-modeline-spc)
  1664. (my/-calc-float-mode-string)
  1665. (when calc-prefer-frac
  1666. (concat
  1667. (doom-modeline-spc)
  1668. "Frac"))
  1669. (cond
  1670. (calc-algebraic-mode
  1671. (concat
  1672. (doom-modeline-spc)
  1673. "Alg"))
  1674. (calc-incomplete-algebraic-mode
  1675. (concat
  1676. (doom-modeline-spc)
  1677. "IAlg"))))))))
  1678. ;; sage (for when calc is not enough)
  1679. (use-package sage-shell-mode
  1680. :demand
  1681. :bind ("C-c g" . my/run-sage)
  1682. :hook (sage-shell-mode . my/-setup-sage-shell-mode)
  1683. :init
  1684. (defun my/-setup-sage-shell-mode ()
  1685. (setq-local comint-dynamic-complete-functions
  1686. '(comint-c-a-p-replace-by-expanded-history)))
  1687. :config
  1688. (defun my/run-sage (p)
  1689. "Like `sage-shell:run-sage', but does not ask anything without a prefix
  1690. argument."
  1691. (interactive "P")
  1692. (let ((sage-shell:ask-command-options p))
  1693. (funcall-interactively #'sage-shell:run-sage
  1694. (sage-shell:read-command)))))
  1695. ;; fricas (because I like calculators)
  1696. (add-to-list 'load-path "/usr/lib/fricas/emacs/")
  1697. (use-package fricas
  1698. :ensure nil
  1699. :custom
  1700. (fricas-run-command "fricas -nosman")
  1701. :init
  1702. ;; Fix `fricas-mode' messing up `completion-at-point-functions'
  1703. (advice-add #'fricas-mode :around
  1704. #'(lambda (oldfun &rest r)
  1705. (let ((temp-capfs))
  1706. (let ((completion-at-point-functions '(t)))
  1707. (apply oldfun r)
  1708. (setq temp-capfs completion-at-point-functions))
  1709. (setq-local completion-at-point-functions temp-capfs)))
  1710. '((name . "my/-fricas-fix-capfs")))
  1711. :config
  1712. (face-spec-set 'fricas-type-time '((t (:foreground unspecified
  1713. :background unspecified
  1714. :inherit font-lock-type-face))))
  1715. (face-spec-set 'fricas-message '((t (:foreground unspecified
  1716. :background unspecified
  1717. :inherit error))))
  1718. (face-spec-set 'fricas-undefined '((t (:foreground unspecified
  1719. :background unspecified
  1720. :inherit nerd-icons-lblue))))
  1721. (face-spec-set 'fricas-algebra '((t (:foreground unspecified
  1722. :background unspecified
  1723. :weight bold
  1724. :inherit fricas-prompt))))
  1725. (face-spec-set 'fricas-TeX '((t (:foreground "black"
  1726. :background "white"
  1727. :inherit fricas-prompt)))))
  1728. ;; gnuplot (mostly for org-plot)
  1729. (use-package gnuplot)
  1730. ;; eat
  1731. (use-package eat
  1732. :bind (("C-c V" . my/project-eat-or-default)
  1733. :map eat-mode-map
  1734. ("M-o" . ace-window)
  1735. :map eat-semi-char-mode-map
  1736. ("M-o" . ace-window)
  1737. :map eat-eshell-emacs-mode-map
  1738. ("M-o" . ace-window)
  1739. :map eat-eshell-semi-char-mode-map
  1740. ("M-o" . ace-window))
  1741. :config
  1742. (defvar my/project-eat-hash-table (make-hash-table :test 'equal)
  1743. "Hash table that maps project root dirs to eat buffers.")
  1744. (defun my/project-eat (prompt)
  1745. "Switch to or create a eat buffer in the current projects root."
  1746. (interactive (list t))
  1747. (if-let ((proj (project-current prompt))
  1748. (default-directory (project-root proj)))
  1749. (if-let ((eat-buff (gethash default-directory
  1750. my/project-eat-hash-table))
  1751. ((buffer-live-p eat-buff)))
  1752. (switch-to-buffer eat-buff)
  1753. (let ((eat-buffer-name (concat "*eat for project " default-directory
  1754. "*"))
  1755. (eat-term-name (if (file-remote-p default-directory)
  1756. "xterm-256color"
  1757. eat-term-name)))
  1758. (puthash default-directory
  1759. (eat)
  1760. my/project-eat-hash-table)))))
  1761. (defun my/project-eat-or-default ()
  1762. "Open an eat for the current project, otherwise, open a normal eat."
  1763. (interactive)
  1764. (unless (my/project-eat nil)
  1765. (if-let ((eat-buff (gethash nil my/project-eat-hash-table))
  1766. ((buffer-live-p eat-buff)))
  1767. (switch-to-buffer eat-buff)
  1768. (puthash nil (let ((eat-term-name (if (file-remote-p default-directory)
  1769. "xterm-256color"
  1770. eat-term-name)))
  1771. (eat))
  1772. my/project-eat-hash-table)))))
  1773. ;; eshell stuff
  1774. (use-package eshell
  1775. :ensure nil
  1776. :defer nil
  1777. :hook ((eshell-load . eat-eshell-visual-command-mode)
  1778. (eshell-load . eat-eshell-mode)
  1779. (eshell-mode . my/-eshell-mode-setup))
  1780. :bind (:map eshell-mode-map
  1781. ("TAB" . completion-at-point)
  1782. ("<tab>" . completion-at-point))
  1783. :init
  1784. (defun my/-eshell-mode-setup ()
  1785. "Setup function run from `eshell-mode-hook'"
  1786. (setq-local corfu-auto nil))
  1787. (setq-default eshell-command-aliases-list
  1788. '(("clear" "clear t")
  1789. ("e" "find-file $1")
  1790. ("n" "find-file $1")
  1791. ("emacs" "find-file $1")
  1792. ("nvim" "find-file $1")
  1793. ("ls" "eza --git -F $*")
  1794. ("la" "ls -a $*")
  1795. ("l" "ls -l $*")
  1796. ("ll" "la -l $*")
  1797. ("gt" "git status $*")
  1798. ("gp" "git push $*")
  1799. ("gu" "git pull $*")
  1800. ("gf" "git fetch $*")
  1801. ("ga" "git add $*")
  1802. ("gcm" "git commit -m ${string-join $* \" \"}")
  1803. ("ldg" "ledger -f \"$HOME/docs/finance/finances.ledger\" $*")
  1804. ("tp" "trash-put $*")
  1805. ("trr" "trash-restore $*")
  1806. ("tre" "trash-empty $*")
  1807. ("tre" "trash-empty $*")
  1808. ("trm" "trash-rm $*")
  1809. ("rm" "echo 'rm: I''m unsafe! Don''t use me.'; false")
  1810. ("\\rm" "eshell/rm")))
  1811. (defvar my/eshell-bm-auto-ls t
  1812. "Weather or not to run ls after `eshell/bm'")
  1813. (defun eshell/bm (&optional name)
  1814. "Change to directory of bookmark NAME.
  1815. If no name is given, list all bookmarks instead."
  1816. (if name
  1817. (progn
  1818. (eshell/cd (bookmark-get-filename name))
  1819. (when my/eshell-bm-auto-ls
  1820. (eshell/ls)))
  1821. (eshell-print (string-join (bookmark-all-names) " ")))))
  1822. (use-package esh-help
  1823. :hook (eshell-mode . my/-setup-eshell-help-func)
  1824. :init
  1825. (defun my/-setup-eshell-help-func ()
  1826. (eldoc-mode 1)
  1827. (setq-local evil-lookup-func #'esh-help-run-help))
  1828. (setup-esh-help-eldoc))
  1829. (use-package eshell-syntax-highlighting
  1830. :init
  1831. (eshell-syntax-highlighting-global-mode 1))
  1832. (use-package eshell-starship
  1833. :ensure nil
  1834. :demand t
  1835. :hook (eshell-prompt-mode . eshell-starship-prompt-mode))
  1836. ;; proced
  1837. (use-package proced
  1838. :bind ("C-x j" . proced)
  1839. :init
  1840. (evil-define-key '(motion visual normal) proced-mode-map
  1841. "u" 'proced-unmark)
  1842. (setq proced-auto-update-flag t
  1843. proced-auto-update-interval 1)
  1844. (defun my/-setup-proced-mode ()
  1845. (visual-line-mode -1)
  1846. (setq-local truncate-lines t))
  1847. (add-hook 'proced-mode-hook 'my/-setup-proced-mode))
  1848. ;; dired
  1849. (use-package dired
  1850. :ensure nil
  1851. :init
  1852. (setq-default dired-kill-when-opening-new-dired-buffer t)
  1853. (setq delete-by-moving-to-trash t
  1854. dired-recursive-copies 'always
  1855. dired-recursive-deletes 'always
  1856. dired-dwim-target t
  1857. dired-create-destination-dirs 'ask
  1858. dired-create-destination-dirs-on-trailing-dirsep t
  1859. dired-isearch-filenames 'dwim
  1860. dired-do-revert-buffer (lambda (dir)
  1861. (not (file-remote-p dir)))
  1862. dired-clean-up-buffers-too t
  1863. dired-clean-confirm-killing-deleted-buffers t)
  1864. (evil-define-key '(normal visual motion) dired-mode-map
  1865. "u" #'dired-unmark
  1866. "U" #'dired-unmark-all-marks))
  1867. ;; ibuffer
  1868. (use-package ibuffer
  1869. :bind ("C-x C-b" . ibuffer))
  1870. ;; magit
  1871. (use-package magit
  1872. :init
  1873. (evil-define-key '(normal visual motion) magit-mode-map
  1874. "s" #'magit-stage-file
  1875. "S" #'magit-stage-modified))
  1876. ;; org-mode
  1877. (use-package org
  1878. :pin gnu
  1879. :bind (("C-c c" . org-capture)
  1880. ("C-c a" . org-agenda)
  1881. ("C-c l" . org-store-link)
  1882. :map org-mode-map
  1883. ("C-c t" . org-table-create))
  1884. :hook (org-mode . org-table-header-line-mode)
  1885. :init
  1886. (font-lock-add-keywords 'org-mode
  1887. `((,(rx bol (* " ") (group "-") " ")
  1888. (0 (prog1 nil
  1889. (compose-region (match-beginning 1)
  1890. (match-end 1) "•"))))))
  1891. (setq org-directory "~/org"
  1892. org-agenda-files '("~/org/")
  1893. org-log-into-drawer t
  1894. org-log-done 'time
  1895. org-log-redeadline 'time
  1896. org-log-reschedule 'time
  1897. org-preview-latex-default-process 'dvisvgm
  1898. org-highlight-latex-and-related '(native entities)
  1899. org-startup-with-inline-images t
  1900. org-adapt-indentation t
  1901. org-hide-leading-stars t
  1902. org-html-with-latex 'dvisvgm
  1903. org-preview-latex-process-alist
  1904. '((dvisvgm
  1905. :image-input-type "dvi"
  1906. :image-output-type "svg"
  1907. :image-size-adjust (1.7 . 1.5)
  1908. :latex-compiler ("pdflatex -interaction nonstopmode -output-format=dvi -output-directory=%o %f")
  1909. :image-converter ("dvisvgm %o%b.dvi --no-fonts --exact-bbox --scale=%S --output=%O"))))
  1910. (defun my/-org-allow-in-derived-mode (oldfun &rest r)
  1911. "Allow OLDFUN to run, even if `major-mode' is only derived from `org-mode'.
  1912. R is rest of the arguments to OLDFUN."
  1913. (let ((major-mode (if (derived-mode-p 'org-mode)
  1914. 'org-mode
  1915. major-mode)))
  1916. (apply oldfun r)))
  1917. (advice-add 'org-element-at-point :around 'my/-org-allow-in-derived-mode)
  1918. (advice-add 'org-table-header-line-mode :around 'my/-org-allow-in-derived-mode))
  1919. (use-package evil-org
  1920. :after org
  1921. :hook (org-mode . evil-org-mode)
  1922. :init
  1923. (require 'evil-org-agenda)
  1924. (evil-org-agenda-set-keys))
  1925. ;; ledger
  1926. (use-package ledger-mode)
  1927. (use-package flycheck-ledger
  1928. :hook (ledger-mode . flycheck-mode))
  1929. ;; khard contacts
  1930. (require 'khard)
  1931. ;; This is also in khard (see above), it's just also here so that if I remove
  1932. ;; that file ever, other things will not break.
  1933. (defun my/message-in-header-p (name &optional testfn)
  1934. "If in field NAME, return the start of the header, otherwise, return nil.
  1935. The name is compared with the field name using TESTFN (defaults to `equal')."
  1936. (save-excursion
  1937. (when (and (message-point-in-header-p)
  1938. (message-beginning-of-header t))
  1939. (beginning-of-line)
  1940. (when (and (looking-at (rx bol (group (+? any)) ":" (? " ")))
  1941. (funcall (or testfn 'equal) (match-string 1) name))
  1942. (match-end 0)))))
  1943. ;; mu4e
  1944. (use-package mu4e
  1945. :ensure nil
  1946. :defer nil
  1947. :hook ((mu4e-index-updated . my/-mu4e-enable-index-messages)
  1948. (mu4e-main-mode . my/-mu4e-setup-main-mode)
  1949. (mu4e-view-mode . my/-mu4e-setup-view-mode)
  1950. (mu4e-compose-mode . my/-mu4e-setup-compose-mode))
  1951. :bind (("C-x C-m" . mu4e)
  1952. :map message-mode-map
  1953. ("C-c k" . khard-insert-email-contact)
  1954. :map mu4e-headers-mode-map
  1955. ([remap mu4e-headers-mark-for-trash] .
  1956. my/mu4e-headers-mark-for-trash)
  1957. :map mu4e-view-mode-map
  1958. ([remap mu4e-view-mark-for-trash] .
  1959. my/mu4e-view-mark-for-trash))
  1960. :init
  1961. (require 'mu4e)
  1962. (evil-define-key '(normal motion) mu4e-main-mode-map "q" #'bury-buffer)
  1963. (evil-define-key '(normal motion) mu4e-view-mode-map "gy" #'mu4e-view-save-url)
  1964. (defun my/-mu4e-setup-view-mode ()
  1965. (setq-local global-hl-line-mode nil))
  1966. (defun my/-mu4e-setup-main-mode ()
  1967. (setq-local default-directory "~/"))
  1968. (defun my/-mu4e-enable-index-messages ()
  1969. (setq mu4e-hide-index-messages nil))
  1970. (defun my/mu4e-update-mail-and-index-silent ()
  1971. "Run `mu4e-update-mail-and-index' without any messages in the background."
  1972. (setq mu4e-hide-index-messages t)
  1973. (mu4e-update-mail-and-index t))
  1974. (defun my/mu4e-headers-mark-for-trash ()
  1975. "Move the message a point to the trash without marking it was deleted
  1976. (trashed)."
  1977. (interactive)
  1978. (when (mu4e-thread-message-folded-p)
  1979. (mu4e-warn "Cannot mark folded messages"))
  1980. (mu4e-mark-at-point 'move mu4e-trash-folder)
  1981. (when mu4e-headers-advance-after-mark
  1982. (mu4e-headers-next)))
  1983. (defun my/mu4e-view-mark-for-trash ()
  1984. "Like `my/mu4e-headers-mark-for-trash', but for `mu4e-view-mode'."
  1985. (interactive)
  1986. (mu4e--view-in-headers-context
  1987. (my/mu4e-headers-mark-for-trash)))
  1988. (defun my/-mu4e-enable-autocomplete-in-header ()
  1989. ;; corfu auto must be t (not the integer returned by
  1990. ;; `my/message-in-header-p'
  1991. (setq-local corfu-auto (and (not (window-minibuffer-p))
  1992. (my/message-in-header-p "To")
  1993. t)))
  1994. (defun my/-mu4e-setup-compose-mode ()
  1995. (add-hook 'post-command-hook 'my/-mu4e-enable-autocomplete-in-header
  1996. nil t)
  1997. (add-to-list
  1998. (make-local-variable 'completion-at-point-functions)
  1999. (cape-capf-super #'mu4e-complete-contact #'khard-message-mode-capf)))
  2000. (defun my/-mu4e-fix-cycle-threshold ()
  2001. (setq-local completion-cycle-threshold nil))
  2002. (advice-add 'mu4e--compose-setup-completion :after
  2003. 'my/-mu4e-fix-cycle-threshold)
  2004. (defvar my/mu4e-interesting-mail-query
  2005. (concat "flag:unread AND NOT flag:trashed AND NOT "
  2006. "maildir:/protonmail/Trash AND NOT maildir:/protonmail/Spam")
  2007. "Flag for mail which will appear as \"unread\" and will be notified.")
  2008. (setq message-kill-buffer-on-exit t
  2009. message-confirm-send t
  2010. message-send-mail-function 'sendmail-send-it
  2011. mu4e-change-filenames-when-moving t
  2012. mu4e-context-policy 'pick-first
  2013. mu4e-attachment-dir "~/downloads/"
  2014. mu4e-last-update-buffer " *mu4e-last-update*"
  2015. mu4e-index-update-error-warning nil
  2016. mu4e-get-mail-command "mbsync protonmail"
  2017. mu4e-completing-read-function #'completing-read-default
  2018. mu4e-compose-context-policy 'ask-if-none
  2019. mu4e-contexts
  2020. (list (make-mu4e-context
  2021. :name "Personal"
  2022. :match-func (lambda (msg)
  2023. (when msg
  2024. (string-match-p "^/protonmail/"
  2025. (mu4e-message-field msg
  2026. :maildir))))
  2027. :vars `((user-mail-address . ,(my/get-private 'mu4e-email))
  2028. (user-full-name . ,(my/get-private 'mu4e-name))
  2029. (message-signature . nil)
  2030. (mu4e-refile-folder . "/protonmail/Archive")
  2031. (mu4e-sent-folder . "/protonmail/Sent")
  2032. (mu4e-drafts-folder . "/protonmail/Drafts")
  2033. (mu4e-trash-folder . "/protonmail/Trash")
  2034. (mu4e-bookmarks
  2035. . ((:name "Inbox"
  2036. :query "maildir:/protonmail/Inbox"
  2037. :key ?i)
  2038. (:name "Unread"
  2039. :query ,my/mu4e-interesting-mail-query
  2040. :key ?u))))))))
  2041. (use-package mu4e-alert
  2042. :after mu4e
  2043. :hook (after-init . mu4e-alert-enable-notifications)
  2044. :init
  2045. (setq mu4e-alert-set-window-urgency nil
  2046. mu4e-alert-interesting-mail-query my/mu4e-interesting-mail-query)
  2047. :config
  2048. (mu4e-alert-set-default-style 'libnotify))
  2049. (mu4e t)
  2050. (mu4e-context-switch nil "Personal")
  2051. ;; mu4e compose HTML messages
  2052. (use-package org-mime)
  2053. (require 'org-mu4e-compose)
  2054. (setq mail-user-agent 'org-mu4e-user-agent
  2055. org-mime-org-html-with-latex-default 'dvisvgm
  2056. org-mime-export-options '(:with-latex dvisvgm :with-footnotes t))
  2057. (evil-define-key '(normal visual) org-mu4e-compose-mode-map
  2058. "G" #'mu4e-compose-goto-bottom
  2059. "gg" #'mu4e-compose-goto-top)
  2060. (evil-define-key 'normal org-mu4e-compose-mode-map
  2061. "ZZ" #'message-send-and-exit
  2062. "ZD" #'message-dont-send
  2063. "ZQ" #'message-kill-buffer
  2064. "ZF" #'mml-attach-file)
  2065. (evil-define-key 'normal mu4e-view-mode-map
  2066. "R" 'org-mu4e-compose-reply
  2067. "cr" 'org-mu4e-compose-reply)
  2068. (evil-define-key 'normal mu4e-headers-mode-map
  2069. "R" 'org-mu4e-compose-reply
  2070. "cr" 'org-mu4e-compose-reply)
  2071. (defun my/-setup-org-mu4e-compose-mode ()
  2072. "Setup up stuff in `org-mu4e-compose' buffers."
  2073. (setq-local ltex-eglot-variable-save-method 'file)
  2074. ;; this should come last so it can pick up the above
  2075. ;; (eglot-ensure)
  2076. )
  2077. (add-hook 'org-mu4e-compose-mode-hook #'my/-setup-org-mu4e-compose-mode)
  2078. ;; elfeed
  2079. (use-package elfeed
  2080. :bind (("C-c d" . elfeed))
  2081. :custom
  2082. (elfeed-feeds
  2083. '(("https://archlinux.org/feeds/news/" linux arch)
  2084. ("https://9to5linux.com/feed/atom" linux news)))
  2085. :config
  2086. (setq elfeed-log-buffer-name " *elfeed-log*")
  2087. (evil-define-key '(normal motion) elfeed-search-mode-map
  2088. "r" #'elfeed-search-fetch)
  2089. (elfeed-db-load))
  2090. ;; helpful
  2091. (use-package helpful
  2092. :hook ((emacs-lisp-mode . my/-helpful-setup-emacs-lisp-mode)
  2093. (helpful-mode . my/-setup-helpful-mode))
  2094. :bind (:map help-map
  2095. ("f" . helpful-callable)
  2096. ("v" . helpful-variable)
  2097. ("k" . helpful-key)
  2098. ("o" . helpful-symbol)
  2099. ("x" . helpful-command)
  2100. ("F" . helpful-function)
  2101. :map helpful-mode-map
  2102. ("<mouse-8>" . my/helpful-history-back)
  2103. ("<mouse-9>" . my/helpful-history-forward)
  2104. ("<normal-state><" . my/helpful-history-back)
  2105. ("<normal-state>>" . my/helpful-history-forward))
  2106. :init
  2107. (defun my/-helpful-setup-emacs-lisp-mode ()
  2108. (setq-local evil-lookup-func #'helpful-at-point))
  2109. (defun my/-setup-helpful-mode ()
  2110. (setq-local evil-lookup-func #'helpful-at-point
  2111. tab-width 8))
  2112. (defvar my/helpful-symbol-history-size 50
  2113. "Max size of `my/helpful-symbol-history'.")
  2114. (defvar my/helpful-symbol-history '()
  2115. "History of helpful symbols.")
  2116. (defvar my/-helpful-inhibit-history nil
  2117. "If non-nil, don't add symbols to `my/helpful-symbol-history'.")
  2118. (defvar my/-helpful-last-entry nil
  2119. "Last entry looked up with helpful.")
  2120. (defun my/helpful-history-back (count)
  2121. "Go back COUNT symbols in `my/helpful-symbol-history'. If called
  2122. interactively, COUNT defaults to 1."
  2123. (interactive "p")
  2124. (my/helpful-history-forward (- count)))
  2125. (defun my/helpful-history-forward (count)
  2126. "Move COUNT symbols in `my/helpful-symbol-history'. If COUNT is negative,
  2127. move back. If COUNT is larger than the history, go to the newest entry. Go to
  2128. the oldest entry if -COUNT is larger than the history."
  2129. (interactive "p")
  2130. (when helpful--sym
  2131. (let* ((hist-len (length my/helpful-symbol-history))
  2132. (current-pos (seq-position my/helpful-symbol-history
  2133. (cons helpful--sym
  2134. helpful--callable-p)
  2135. 'equal))
  2136. (new-pos (- current-pos count)))
  2137. (cond
  2138. ;; if already at the newest element, signal an error
  2139. ((and (> count 0) (= current-pos 0))
  2140. (message "%s" "No newer symbol!"))
  2141. ;; if already at the oldest element, signal an error
  2142. ((and (< count 0) (= (1+ current-pos) hist-len))
  2143. (message "%s" "No older symbol!"))
  2144. (t
  2145. (let ((my/-helpful-inhibit-history t)
  2146. (entry (cond
  2147. ((<= new-pos 0)
  2148. (seq-first my/helpful-symbol-history))
  2149. ((>= new-pos hist-len)
  2150. (car (last my/helpful-symbol-history)))
  2151. (t
  2152. (nth new-pos my/helpful-symbol-history)))))
  2153. (if (cdr entry)
  2154. (helpful-callable (car entry))
  2155. (helpful-variable (car entry)))))))))
  2156. (defun my/-helpful-switch-buffer-function (helpful-buf)
  2157. "Like `pop-to-buffer', but kill previous helpful buffers and save the new
  2158. buffers `helpful--sym' to `my/helpful-symbol-history'."
  2159. (cl-loop with window = nil
  2160. for buf in (buffer-list)
  2161. when (and
  2162. (not (eq buf helpful-buf))
  2163. (eq (buffer-local-value 'major-mode buf) 'helpful-mode))
  2164. do
  2165. (when-let (cur-window (get-buffer-window buf nil))
  2166. (setq window cur-window))
  2167. (kill-buffer buf)
  2168. finally
  2169. (let ((entry (cons (buffer-local-value 'helpful--sym helpful-buf)
  2170. (buffer-local-value 'helpful--callable-p
  2171. helpful-buf))))
  2172. (unless my/-helpful-inhibit-history
  2173. (when-let (from-current-hist
  2174. (member my/-helpful-last-entry
  2175. my/helpful-symbol-history))
  2176. (setq my/helpful-symbol-history from-current-hist))
  2177. (cl-pushnew entry my/helpful-symbol-history :test 'equal)
  2178. (setq my/helpful-symbol-history
  2179. (seq-take my/helpful-symbol-history
  2180. my/helpful-symbol-history-size)))
  2181. (setq my/-helpful-last-entry entry))
  2182. (if window
  2183. (window--display-buffer helpful-buf window 'reuse)
  2184. (pop-to-buffer helpful-buf))))
  2185. (setq helpful-switch-buffer-function 'my/-helpful-switch-buffer-function
  2186. helpful-max-buffers 2))
  2187. (defun my/greyify-color (color percent &optional frame)
  2188. "Make COLOR closer to black by PERCENT on FRAME.
  2189. Color can be any color which can be passed to `color-values'."
  2190. (cl-destructuring-bind (&optional r g b)
  2191. (color-name-to-rgb color frame)
  2192. (when (and r g b)
  2193. (let ((scale (- 1.0 (/ percent 100.0))))
  2194. (color-rgb-to-hex (* r scale)
  2195. (* g scale)
  2196. (* b scale))))))
  2197. ;; rainbow-delimiters
  2198. (use-package rainbow-delimiters
  2199. :hook (prog-mode . rainbow-delimiters-mode)
  2200. :config
  2201. ;; generate dark version of the rainbow delimiters faces
  2202. (defun my/-rainbow-delimiters-recalc-dark-faces (&optional frame)
  2203. (unless frame (setq frame (selected-frame)))
  2204. (dotimes (i 9)
  2205. (when-let ((old-face (intern-soft
  2206. (format "rainbow-delimiters-depth-%d-face"
  2207. (1+ i))))
  2208. (new-face
  2209. (intern
  2210. (format "my/rainbow-delimiters-depth-%d-dark-face"
  2211. (1+ i))))
  2212. (old-color (face-attribute old-face :foreground frame))
  2213. (new-color (my/greyify-color old-color 50 frame)))
  2214. (set-face-attribute new-face frame :foreground new-color))))
  2215. (add-hook 'after-make-frame-functions
  2216. #'my/-rainbow-delimiters-recalc-dark-faces)
  2217. (add-hook 'server-after-make-frame-hook
  2218. #'my/-rainbow-delimiters-recalc-dark-faces)
  2219. (defun my/rainbow-delimiters-parinfer-pick-face (depth match loc)
  2220. "Version of `rainbow-delimiters-default-pick-face' that colors closing
  2221. parenthesis darker than opening ones. This function defers to
  2222. `rainbow-delimiters-default-pick-face' and just changes the output if it returns
  2223. one of the normal rainbow-delimiters-depth-N-face faces."
  2224. (save-match-data
  2225. (let* ((base-face (rainbow-delimiters-default-pick-face depth match loc))
  2226. (base-name (symbol-name base-face)))
  2227. (if (and evil-cleverparens-mode
  2228. (eq ?\) (char-syntax
  2229. (elt (buffer-substring-no-properties loc (1+ loc)) 0)))
  2230. (string-match (rx string-start "rainbow-delimiters-depth-"
  2231. (group (+ num))
  2232. "-face" string-end)
  2233. base-name))
  2234. (or (intern-soft (format "my/rainbow-delimiters-depth-%s-dark-face"
  2235. (match-string 1 base-name)))
  2236. base-face)
  2237. base-face))))
  2238. (setopt rainbow-delimiters-pick-face-function
  2239. 'my/rainbow-delimiters-parinfer-pick-face))
  2240. ;; auto-highlight-symbol
  2241. (use-package auto-highlight-symbol
  2242. :hook (lisp-data-mode . auto-highlight-symbol-mode)
  2243. :init
  2244. (setq ahs-face 'bold
  2245. ahs-face-unfocused 'bold
  2246. ahs-definition-face 'bold
  2247. ahs-definition-face-unfocused 'bold
  2248. ahs-plugin-default-face 'bold
  2249. ahs-plugin-default-face-unfocused 'bold))
  2250. ;; Theme (doom-themes)
  2251. (use-package doom-themes
  2252. :config
  2253. (load-theme 'doom-molokai t)
  2254. (doom-themes-org-config))
  2255. ;; solaire-mode
  2256. (use-package solaire-mode
  2257. :config
  2258. (solaire-global-mode 1))
  2259. ;; Highlight todos
  2260. (use-package hl-todo
  2261. :config
  2262. (global-hl-todo-mode 1))
  2263. (use-package magit-todos
  2264. :after (hl-todo magit)
  2265. :config
  2266. (magit-todos-mode 1))
  2267. ;; icons
  2268. (use-package nerd-icons)
  2269. (use-package nerd-icons-completion
  2270. :config
  2271. (nerd-icons-completion-mode))
  2272. (use-package nerd-icons-dired
  2273. :hook (dired-mode . nerd-icons-dired-mode))
  2274. (use-package kind-icon
  2275. :after corfu
  2276. :init
  2277. (setq kind-icon-default-face 'corfu-default
  2278. kind-icon-default-style
  2279. '(:padding -1 :stroke 0 :margin 0 :radius 0 :height 0.5 :scale 1))
  2280. :config
  2281. (add-to-list 'corfu-margin-formatters #'kind-icon-margin-formatter))
  2282. ;; modeline (doom-modeline)
  2283. (use-package doom-modeline
  2284. :init
  2285. (setq doom-modeline-support-imenu t)
  2286. (doom-modeline-mode 1))
  2287. ;; dashboard.el
  2288. (use-package dashboard
  2289. :config
  2290. (dashboard-setup-startup-hook)
  2291. (setq initial-buffer-choice (lambda () (get-buffer-create "*dashboard*"))
  2292. dashboard-force-refresh t
  2293. dashboard-display-icons-p t
  2294. dashboard-icon-type 'nerd-icons
  2295. dashboard-set-file-icons t
  2296. dashboard-projects-backend 'project-el
  2297. dashboard-items '((recents . 5)
  2298. (projects . 5)
  2299. (bookmarks . 5))))
  2300. ;; page break lines
  2301. (use-package page-break-lines
  2302. :config
  2303. (global-page-break-lines-mode 1)
  2304. (add-to-list 'page-break-lines-modes 'prog-mode)
  2305. (add-to-list 'page-break-lines-modes 'text-mode)
  2306. (add-to-list 'page-break-lines-modes 'helpful-mode))
  2307. ;; fun!
  2308. (use-package mines)
  2309. ;;; init.el ends here