1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313 |
- ;;; init.el --- Configuration entry point -*- lexical-binding: t -*-
- ;;; Commentary:
- ;;; Code:
- (require 'cl-lib)
- (require 'xdg)
- ;; Some other config files
- (cl-eval-when (compile load eval)
- (add-to-list 'load-path (expand-file-name "elisp" user-emacs-directory))
- (add-to-list 'load-path (expand-file-name "third-party" user-emacs-directory)))
- ;; Set package dir to follow no-littering conventions
- (setq package-user-dir (expand-file-name "var/elpa"
- user-emacs-directory))
- ;; Use melpa
- (require 'package)
- (add-to-list 'package-archives '("melpa" . "https://melpa.org/packages/") t)
- (package-initialize)
- ;; Ensure use-package is installed
- (unless (package-installed-p 'use-package)
- (package-refresh-contents)
- (package-install 'use-package))
- ;; use-package
- (eval-when-compile
- (require 'use-package)
- (setq use-package-always-ensure t
- package-user-dir (expand-file-name "var/elpa"
- user-emacs-directory)))
- ;; no-littering
- (use-package no-littering
- :autoload (no-littering-theme-backups
- no-littering-expand-etc-file-name)
- :init
- (no-littering-theme-backups)
- (setq custom-file (no-littering-expand-etc-file-name "custom.el")))
- ;; load things saved with custom
- (load custom-file t t)
- ;; diminish
- (use-package diminish
- :config
- (diminish 'visual-line-mode)
- (diminish 'abbrev-mode))
- ;; Private config loading
- (require 'private nil t)
- (defun my/get-private (key)
- "Get the private config variable KEY from the private configuration file."
- (alist-get key my/private-config))
- ;; basic stuff
- (use-package emacs
- :hook (;;(emacs-lisp-mode . my/-emacs-lisp-mode-setup-evil-lookup)
- ;;(prog-mode . electric-pair-local-mode)
- ((text-mode tex-mode prog-mode) . auto-fill-mode)
- ((text-mode tex-mode prog-mode) . my/-enable-show-trailing-whitespace))
- :init
- (with-eval-after-load 'find-func
- (when (file-directory-p "~/src/emacs/src/")
- (setq find-function-C-source-directory "~/src/emacs/src/")))
- (defun my/-enable-show-trailing-whitespace ()
- (setq-local show-trailing-whitespace t))
- ;; (defun my/-emacs-lisp-mode-setup-evil-lookup ()
- ;; (setq-local evil-lookup-func
- ;; #'my/describe-symbol-at-point))
- (defun my/describe-symbol-at-point ()
- "Calls `describe-symbol' on the return value of `symbol-at-point'."
- (interactive)
- (let ((form (symbol-at-point)))
- (if (consp form)
- (describe-symbol (cadr form))
- (describe-symbol form))))
- ;; Increase responsiveness
- (setq gc-cons-threshold 80000000
- read-process-output-max (* 1024 1024)) ;; 1mb
- (global-so-long-mode 1)
- ;; Terminal mouse support
- (xterm-mouse-mode 1)
- ;; Make cursor more visible
- (global-hl-line-mode 1)
- (blink-cursor-mode -1)
- ;; Enable all disabled stuff
- (setq disabled-command-function nil)
- ;; Stop some annoying stuff
- (setq extended-command-suggest-shorter nil
- suggest-key-bindings nil)
- ;; Better scrolling
- (setq mouse-scroll-delay 0
- scroll-conservatively 10
- scroll-margin 2
- scroll-preserve-screen-position t)
- ;; Make show paren instant
- (setq show-paren-delay 0)
- (show-paren-mode 1)
- ;; Display line numbers
- (global-display-line-numbers-mode 1)
- ;; Allow the frame to be any size
- (setq frame-resize-pixelwise t)
- ;; Don't use a gtk file picker
- (setq use-file-dialog nil)
- ;; Make yes-or-no-p less verbose (and not use windows)
- (setq use-dialog-box nil
- use-short-answers t)
- ;; Disable startup screen
- (setq inhibit-startup-screen t
- server-client-instructions nil)
- ;; show column numbers
- (column-number-mode 1)
- ;; Disable the menu and tool bars
- (menu-bar-mode -1)
- (tool-bar-mode -1)
- ;; No scroll bars
- (scroll-bar-mode -1)
- ;; Visual line mode
- (global-visual-line-mode 1)
- ;; Make some commands easier to enter multiple times
- (repeat-mode 1)
- ;; Easier buffer navigation
- (keymap-global-set "C-c <" #'previous-buffer)
- (keymap-global-set "C-c >" #'next-buffer)
- (keymap-global-set "C-c k" #'previous-buffer)
- (keymap-global-set "C-c j" #'next-buffer)
- ;; Seems useful...
- (keymap-global-set "C-c u" #'browse-url)
- ;; Set fonts
- (add-to-list 'default-frame-alist '(font . "FiraCode Nerd Font Mono-12"))
- (add-hook 'server-after-make-frame-hook
- (lambda ()
- (set-fontset-font t 'japanese-jisx0208 "IPAGothic")))
- ;; Enable color in compilation buffers
- (add-hook 'compilation-filter-hook 'ansi-color-compilation-filter)
- ;; Some settings for programming
- (setq-default indent-tabs-mode nil
- tab-width 4
- fill-column 80
- comment-multi-line t
- comment-empty-lines 'eol)
- (add-to-list 'auto-mode-alist '("\\.[cC][nN][fF]\\'" . conf-mode))
- (keymap-set emacs-lisp-mode-map "C-c C-r" #'eval-region)
- (defun my/-fix-emacs-lisp-mode-system-files ()
- (when (string-prefix-p lisp-directory buffer-file-name)
- ;; system Emacs files use tab characters and look weird without this.
- (setq-local tab-width 8)))
- (add-hook 'emacs-lisp-mode-hook #'my/-fix-emacs-lisp-mode-system-files)
- ;; Tree sitter download locations
- (setq treesit-language-source-alist
- '((c "https://github.com/tree-sitter/tree-sitter-c")
- (cpp "https://github.com/tree-sitter/tree-sitter-cpp")
- (java "https://github.com/tree-sitter/tree-sitter-java")
- ;; (glsl "https://github.com/tree-sitter-grammars/tree-sitter-glsl")
- (python "https://github.com/tree-sitter/tree-sitter-python")
- (rust "https://github.com/tree-sitter/tree-sitter-rust")
- (json "https://github.com/tree-sitter/tree-sitter-json")
- (yaml "https://github.com/ikatyang/tree-sitter-yaml")
- (css "https://github.com/tree-sitter/tree-sitter-css")
- (go "https://github.com/tree-sitter/tree-sitter-go")
- (gomod "https://github.com/camdencheek/tree-sitter-go-mod")
- (javascript "https://github.com/tree-sitter/tree-sitter-javascript")
- (typescript "https://github.com/tree-sitter/tree-sitter-typescript"
- nil "typescript/src")
- (tsx "https://github.com/tree-sitter/tree-sitter-typescript"
- nil "tsx/src")
- (bash "https://github.com/tree-sitter/tree-sitter-bash")
- (cmake "https://github.com/uyha/tree-sitter-cmake")
- (blueprint "https://github.com/huanie/tree-sitter-blueprint")
- (kdl "https://github.com/tree-sitter-grammars/tree-sitter-kdl")))
- ;; Tree sitter major mode conversions
- (dolist (ent '((c-mode . c-ts-mode)
- (c++-mode . c++-ts-mode)
- (c-or-c++-mode . c-or-c++-ts-mode)
- (python-mode . python-ts-mode)
- (java-mode . java-ts-mode)
- (rust-mode . rust-ts-mode)
- (json-mode . json-ts-mode)
- (yaml-mode . yaml-ts-mode)
- (css-mode . css-ts-mode)
- (javascript-mode . js-ts-mode)
- (cmake-mode . cmake-ts-mode)))
- (add-to-list 'major-mode-remap-alist ent))
- (defun my/treesit-compile-all (force)
- "Compile all the modules defined in `treesit-language-source-alist'.
- If FORCE, recompile all modules, even ones that are already compiled.
- Interactively, force the recompile if called with a prefix."
- (interactive "P")
- (let ((did-build nil))
- (dolist (lang treesit-language-source-alist)
- (when (or force (not (treesit-language-available-p (car lang))))
- (treesit-install-language-grammar (car lang))
- (setq did-build t)))
- (unless did-build
- (message "All defined parsers installed!")))))
- (use-package auth-source
- :ensure nil
- :custom
- (auth-sources '("~/.authinfo.gpg")))
- (use-package tramp
- :ensure nil
- :config
- (connection-local-set-profile-variables
- 'remote-direct-async-process
- '((tramp-direct-async-process . t)))
- (connection-local-set-profiles
- '(:protocol "ssh")
- 'remote-direct-async-process))
- (use-package midnight
- :ensure nil
- :config
- (add-to-list 'clean-buffer-list-kill-never-buffer-names
- "*mu4e-main*")
- (add-to-list 'clean-buffer-list-kill-never-buffer-names
- "*Async-native-compile-log*")
- (add-to-list 'clean-buffer-list-kill-never-buffer-names
- "*dashboard*")
- (add-to-list 'clean-buffer-list-kill-never-buffer-names
- "*elfeed-search*")
- (midnight-mode 1))
- (defvar my/kill-some-buffers-exclude-names
- '("*mu4e-main*" "*Async-native-compile-log*" "*dashboard*" "*elfeed-search*"
- "*Messages*" "*scratch*")
- "List of literal buffer names that `my/kill-some-buffers' should not kill.")
- (defun my/kill-some-buffers-excluded-buffer-p (buffer)
- "Return non-nil if BUFFER should be excluded from `my/kill-some-buffers'."
- (cl-find (buffer-name buffer) my/kill-some-buffers-exclude-names
- :test 'equal))
- (defun my/buffer-visible-p (buffer)
- "Return non-nil if BUFFER is visible.
- BUFFER can be a string or a buffer."
- (cond
- ((stringp buffer)
- (not (string-prefix-p " " buffer)))
- ((bufferp buffer)
- (and (stringp (buffer-name buffer))
- (my/buffer-visible-p (buffer-name buffer))))
- (t
- (signal 'wrong-type-argument `((or bufferp stringp) ,buffer)))))
- (defvar my/kill-some-buffers-default-pred 'my/buffer-visible-p
- "Default predicate for `my/kill-some-buffers'.")
- (defun my/kill-some-buffers-prompt-for (buffer)
- "Generate a prompt for BUFFER."
- (let* ((process (get-buffer-process buffer))
- (process-p (and (process-live-p process)
- (not (process-query-on-exit-flag process))))
- (modified-p (and (buffer-file-name buffer)
- (buffer-modified-p buffer))))
- (format "Buffer \"%s\" %s. Kill? "
- (buffer-name buffer)
- (cond
- ((and process-p modified-p)
- "HAS BEEN EDITED AND HAS A LIVE PROCESS")
- (modified-p
- "HAS BEEN EDITED")
- (process-p
- "HAS A LIVE PROCESS")
- (t "is unmodified")))))
- (cl-defun my/kill-some-buffers (&optional auto-unmod pred)
- "Improved version of `kill-some-buffers'.
- Ask the user weather to kill each visible buffer whose name is not in
- `my/kill-some-buffers-exclude-names'.
- When AUTO-UNMOD is non-nil, as it is with a prefix argument, automatically kill
- unmodified buffers, and then ask about the rest.
- When PRED is non-nil, it is a function that will be run in each buffer (not just
- visible ones). If it returns t, that buffer will be considered for killing. If
- PRED is nil, the value of `my/kill-some-buffers-default-pred' is used."
- (interactive "P")
- ;; we already ask, no need to do it again
- (let ((kill-buffer-query-functions nil)
- (all-action (when auto-unmod 'unmod))
- (had-valid-buffer)
- (ask-again-buffers)
- (to-kill))
- (cl-flet ((ask-about (buffer allow-unmod)
- (unless all-action
- (read-answer
- (my/kill-some-buffers-prompt-for buffer)
- `(("yes" ?y "save and kill this buffer")
- ("no" ?n "skip this buffer")
- ("all" ?! "save and kill all remaining buffers")
- ("nosave" ?l "kill this buffer without saving")
- ,@(when allow-unmod
- '(("unmod" ?a
- "kill unmodified buffers, ask about the rest")))
- ("quit" ?q "exit")))))
- (act-on (ans buffer allow-unmod)
- (when (equal ans "all")
- (setq all-action 'all))
- (when (and allow-unmod
- (equal ans "unmod"))
- (setq all-action 'unmod))
- (cond
- ((and (eq all-action 'unmod)
- (buffer-file-name buffer)
- (buffer-modified-p buffer))
- (push buffer ask-again-buffers))
- ((or (eq all-action 'all)
- (eq all-action 'unmod)
- (equal ans "yes"))
- (when (buffer-file-name buffer)
- (with-current-buffer buffer
- (save-buffer)))
- (push buffer to-kill))
- ((equal ans "nosave")
- (with-current-buffer buffer
- (set-buffer-modified-p nil))
- (push buffer to-kill))
- ;; Skip buffer
- ;; ((equal ans "no"))
- ((equal ans "quit")
- (cl-return-from my/kill-some-buffers)))))
- (dolist (buffer (buffer-list))
- (when (and (not (my/kill-some-buffers-excluded-buffer-p buffer))
- (funcall (or pred my/kill-some-buffers-default-pred) buffer))
- (setq had-valid-buffer t)
- (act-on (ask-about buffer t) buffer t)))
- (unless had-valid-buffer
- (message "Nothing to do..."))
- (setq all-action nil)
- (dolist (buffer ask-again-buffers)
- (act-on (ask-about buffer nil) buffer nil))
- ;; Do this last so that tty frames don't auto-close half way through
- (mapc 'kill-buffer to-kill))))
- (keymap-global-set "C-x K" 'my/kill-some-buffers)
- (use-package tab-bar
- :ensure nil
- :init
- (setq tab-bar-show 1
- tab-bar-tab-hints t
- icon-preference '(symbol text image emoji))
- (tab-bar-mode 1))
- ;; jinx (better flyspell)
- (use-package jinx
- :hook (emacs-startup . global-jinx-mode)
- :config
- (evil-define-key 'normal 'global
- "z=" #'jinx-correct)
- (defun my/jinx-visit-dictionary (language &optional other-window)
- "Visit the dictionary file for LANGUAGE in another window.
- With OTHER-WINDOW, visit the file in another window. Interactively, use the
- current buffer's language, prompting if there is more than one. OTHER-WINDOW is
- t with a prefix argument."
- (interactive (list
- (let ((langs (split-string jinx-languages " ")))
- (if (length= langs 1)
- (car langs)
- (completing-read "Language: " langs nil t)))
- current-prefix-arg))
- (let* ((config-dir (expand-file-name "enchant" (xdg-config-home)))
- (dict-path (expand-file-name (concat language ".dic") config-dir)))
- (if other-window
- (find-file-other-window dict-path)
- (find-file dict-path)))))
- ;; recentf
- (use-package recentf
- :init
- (setq recentf-exclude `("^/tmp/.*"
- "^~/.mail/[^/]/Drafts/.*"
- ,(format "^%svar/dape-breakpoints" user-emacs-directory)
- ,(format "^%svar/elpa/.*" user-emacs-directory)
- ,(format "^%svar/elfeed/.*" user-emacs-directory)
- ,(format "^%svar/gnus/.*" user-emacs-directory)
- ,(format "^%svar/ellama-sessions/.*" user-emacs-directory)
- ,(format "^%setc/gnus/.*" user-emacs-directory)
- ,(format "^%svar/bookmark-default.el" user-emacs-directory)))
- :bind ("C-c r" . recentf)
- :config
- (recentf-mode 1))
- ;; bookmarks
- (use-package bookmark
- :ensure nil
- :bind ("C-c B" . my/bookmark-find-file)
- :config
- (defun my/bookmark-find-file (&optional name)
- "Run `find-file' in or on bookmark NAME.
- If NAME points to a directory, run `find-file' with `default-directory' in that
- directory. Otherwise, run `find-file' on that file."
- (interactive (list (bookmark-completing-read
- "Find file in" bookmark-current-bookmark)))
- (unless name
- (error "No bookmark specified"))
- (bookmark-maybe-historicize-string name)
- (when-let ((file (bookmark-get-filename name)))
- (if (file-directory-p file)
- (let ((default-directory (file-name-as-directory file)))
- (call-interactively 'find-file))
- (find-file file)))))
- ;; kitty keyboard protocol
- (use-package kkp
- :defer nil
- :config
- (global-kkp-mode 1)
- (defun my/quoted-insert (arg)
- "Insert the next character using read-key, not read-char."
- (interactive "*p")
- ;; Source: https://github.com/benjaminor/kkp/issues/11
- (let ((char (read-key)))
- ;; Ensure char is treated as a character code for insertion
- (unless (characterp char)
- (user-error "%s is not a valid character"
- (key-description (vector char))))
- (when (numberp char)
- (while (> arg 0)
- (insert-and-inherit char)
- (setq arg (1- arg))))))
- (keymap-global-set "C-q" #'my/quoted-insert)
- (defun my/kkp-disable-around-advice (oldfun &rest args)
- "Run OLDFUN with ARGS with kkp disabled."
- (let ((status (kkp--this-terminal-has-active-kkp-p)))
- (unwind-protect
- (progn
- (when status (kkp-disable-in-terminal))
- (apply oldfun args))
- (when status (kkp-enable-in-terminal))
- ;; consume the response from the terminal. If this is not here and this
- ;; function is set as advice for `map-y-or-n-p' called from
- ;; `save-buffers-kill-terminal', a bunch of extra characters will be
- ;; printed for the shell after Emacs exits because Emacs will die before
- ;; it can read the terminal's response to `kkp-enable-in-terminal'
- (while-no-input
- (sleep-for 0.1)))))
- (advice-add #'map-y-or-n-p :around #'my/kkp-disable-around-advice))
- ;; some eww (status bar) stuff
- (defun my/cmdline-for-pid (pid)
- "Return the command line arguments passed to PID.
- PID can be a string or a number."
- (butlast (string-split
- (with-temp-buffer
- (insert-file-contents-literally
- (format "/proc/%s/cmdline" pid))
- (buffer-substring-no-properties (point-min)
- (point-max)))
- "\0")))
- (defun my/eww-current-config-dir ()
- "Return the configuration directory for a currently running eww process."
- ;; This probably only works on Linux
- (catch 'found
- (dolist (subdir (directory-files "/proc"))
- (when (string-match-p (rx bos (+ num) eos) subdir)
- (ignore-error permission-denied
- (let* ((attrs (file-attributes (format "/proc/%s/exe" subdir)))
- (type (file-attribute-type attrs)))
- (when (and (stringp type)
- (string-match-p (rx (or bos "/") "eww") type))
- (cl-maplist (lambda (tail)
- (when (equal (car tail) "-c")
- (throw 'found (cl-second tail))))
- (my/cmdline-for-pid subdir)))))))))
- (defun my/eww-update-variables (&rest vars)
- "Update the key value pairs in VARS.
- Each key should be either a symbol or a string. Each value will have its
- printed representation (via `princ') set as the new value for the key."
- (let* ((mappings (map-apply
- #'(lambda (key val)
- (when (symbolp key) (setq key (symbol-name key)))
- (when (cl-find ?= key)
- (error "Key cannot contain an equal sign (=): %s" key))
- (format "%s=%s" key val))
- vars))
- (args (cons "update" mappings))
- (cfg-dir (my/eww-current-config-dir)))
- (when cfg-dir
- (setq args (nconc (list "-c" cfg-dir) args)))
- (apply 'call-process "eww" nil 0 nil args)))
- (defun my/eww-poll-variables (&rest vars)
- "Poll each variable in VARS, which is a lists of strings or symbols."
- (let* ((args (cons "poll" (mapcar #'(lambda (elt) (format "%s" elt)) vars)))
- (cfg-dir (my/eww-current-config-dir)))
- (when cfg-dir
- (setq args (nconc (list "-c" cfg-dir) args)))
- (apply 'call-process "eww" nil 0 nil args)))
- ;; mozc
- (require 'mozc nil t)
- (setq default-input-method "japanese-mozc")
- (defun my/-set-eww-fcitx-state (enabled)
- "Set the fcitx state for eww to ENABLED."
- (my/eww-update-variables "fcitx5-state" (if enabled 2 1)))
- (defun my/global-toggle-mozc (&optional no-eww)
- "Toggle mozc for all buffers.
- With NO-EWW, don't update eww's state."
- (interactive)
- (let ((default-input-method "japanese-mozc"))
- (toggle-input-method nil t)
- (let ((activate (or (bound-and-true-p evil-input-method)
- current-input-method)))
- (dolist (buffer (buffer-list))
- (with-current-buffer buffer
- (if activate
- (activate-input-method activate)
- (deactivate-input-method)
- (mozc-mode -1)
- (when (boundp 'evil-input-method)
- (setq-local evil-input-method nil)))))
- (unless no-eww
- (my/-set-eww-fcitx-state activate)))
- (force-mode-line-update t)))
- (keymap-global-set "C-\\" #'my/global-toggle-mozc)
- (defun my/mozc-active-in-buffer-p (&optional buffer)
- "Return non-nil if mozc is active in BUFFER."
- (unless buffer (setq buffer (current-buffer)))
- (with-current-buffer buffer
- (or (equal (or (bound-and-true-p evil-input-method) current-input-method)
- "japanese-mozc")
- (bound-and-true-p mozc-mode))))
- (defun my/-fcitx-enabled-p ()
- "Return non-nil if fcitx is enabled."
- (ignore-errors
- (= 2 (dbus-call-method :session "org.fcitx.Fcitx5" "/controller"
- "org.fcitx.Fcitx.Controller1" "State"))))
- (defun my/-set-fcitx-enabled (enabled)
- "If ENABLED is non-nil, enabled fcitx, otherwise disabled it."
- (dbus-call-method :session "org.fcitx.Fcitx5" "/controller"
- "org.fcitx.Fcitx.Controller1"
- (if enabled "Activate" "Deactivate")))
- (defun my/-normalize-mozc-state ()
- "Normalize the mozc state between Emacs and fcitx."
- (if (cl-some 'frame-focus-state (frame-list))
- (progn
- (when (my/-fcitx-enabled-p)
- (my/-set-fcitx-enabled nil)
- (when (not (my/mozc-active-in-buffer-p))
- (my/global-toggle-mozc t))))
- (when (cl-some 'my/mozc-active-in-buffer-p (buffer-list))
- (my/global-toggle-mozc t)
- (my/-set-fcitx-enabled t)
- (my/-set-eww-fcitx-state t))))
- (add-function :after after-focus-change-function #'my/-normalize-mozc-state)
- ;; fix the helper process failing if mozc is built with debug flags
- ;; (with-eval-after-load 'mozc
- ;; (defun my/-fixed-mozc-helper-process-filter (proc output-string)
- ;; ;; NOTE this is just a modified version of the origial in mozc.el
- ;; ;; If proc is no longer active, just throw away the data.
- ;; (when (eq proc mozc-helper-process)
- ;; (with-temp-buffer
- ;; (insert (concat mozc-helper-process-string-buf output-string))
- ;; (goto-char (point-min))
- ;; (unwind-protect
- ;; (while-let ((pos (scan-sexps (point) 1)))
- ;; (let* ((msg (buffer-substring-no-properties (point) pos)))
- ;; (push msg mozc-helper-process-message-queue)
- ;; (goto-char pos)))
- ;; (setq mozc-helper-process-string-buf (buffer-substring-no-properties
- ;; (point) (point-max)))))))
- ;; (advice-add 'mozc-helper-process-filter :override
- ;; #'my/-fixed-mozc-helper-process-filter))
- ;; migemo
- (use-package migemo
- :config
- (setq migemo-dictionary "/usr/share/migemo/utf-8/migemo-dict"
- migemo-coding-system 'utf-8-unix
- migemo-regex-dictionary nil
- migemo-user-dictionary nil
- migemo-isearch-enable-p t)
- (keymap-global-set "C-c w" 'isearch-forward)
- (keymap-global-set "C-c W" 'isearch-backward)
- (migemo-init))
- ;; undo-tree
- (use-package undo-tree
- :defer nil
- :hook (undo-tree-visualizer-mode . my/-undo-tree-visualizer-mode-setup)
- :config
- (defun my/-undo-tree-visualizer-mode-setup ()
- (visual-line-mode -1)
- (setq truncate-lines t))
- (global-undo-tree-mode))
- ;; evil
- (use-package evil
- :init
- (setq evil-want-integration t
- evil-want-C-d-scroll nil
- evil-want-keybinding nil
- evil-undo-system 'undo-tree
- evil-search-module 'isearch
- evil-respect-visual-line-mode t)
- :config
- (evil-mode 1)
- (evil-define-key '(normal visual motion) proced-mode-map
- "u" #'proced-unmark)
- (evil-define-key '(normal visual motion) dired-mode-map
- "u" #'dired-unmark)
- (evil-define-key '(normal visual motion) profiler-report-mode-map
- (kbd "TAB") #'profiler-report-toggle-entry)
- (eldoc-add-command 'evil-insert
- 'evil-append
- 'evil-insert-line
- 'evil-append-line))
- (use-package evil-collection
- :after evil
- :diminish evil-collection-unimpaired-mode
- :config
- (evil-collection-init))
- (use-package evil-surround
- :after evil
- :config
- (evil-define-key 'operator evil-surround-mode-map
- "z" #'evil-surround-edit
- "Z" #'evil-Surround-edit)
- (evil-define-key 'visual evil-surround-mode-map
- "gz" #'evil-surround-region
- "gZ" #'evil-Surround-region)
- (global-evil-surround-mode 1))
- (use-package evil-terminal-cursor-changer
- :after evil
- :config
- (evil-terminal-cursor-changer-activate))
- (use-package evil-numbers
- :after evil
- :bind (("C-c =" . evil-numbers/inc-at-pt)
- ("C-c +" . evil-numbers/inc-at-pt)
- ("C-c -" . evil-numbers/dec-at-pt)
- ("C-c C-=" . evil-numbers/inc-at-pt-incremental)
- ("C-c C-+" . evil-numbers/inc-at-pt-incremental)
- ("C-c C--" . evil-numbers/dec-at-pt-incremental)))
- (use-package evil-cleverparens
- :hook ((prog-mode . my/-enable-evil-cleverparens)
- (evil-cleverparens-mode . paredit-mode))
- :bind (:map paredit-mode-map
- ("C-<return>" . paredit-RET)
- ("C-RET" . paredit-RET)
- :map evil-cleverparens-mode-map
- ("C-c o" . evil-cp-open-below-form))
- :custom
- (evil-cleverparens-use-s-and-S nil)
- (evil-cleverparens-complete-parens-in-yanked-region t)
- :config
- (eldoc-add-command 'paredit-RET
- 'paredit-open-round
- 'paredit-open-angled
- 'paredit-open-bracket
- 'paredit-open-angled
- 'paredit-open-parenthesis
- 'delete-indentation
- 'evil-cp-insert
- 'evil-cp-append
- 'evil-cp-insert-at-beginning-of-form
- 'evil-cp-insert-at-end-of-form)
- (keymap-unset evil-cleverparens-mode-map "<normal-state> M-o" t)
- (defun my/-enable-evil-cleverparens ()
- (if (member major-mode '(lisp-mode emacs-lisp-mode
- lisp-interaction-mode))
- (evil-cleverparens-mode 1)
- (electric-pair-local-mode 1)))
- (cl-defun my/range-inside-thing-p (thing beg end &optional no-edge)
- "Return non-nil if BEG and END fall inside the bounds of THING.
- With NO-EDGE, return nil if beg or end fall on the edge of the range."
- (save-excursion
- ;; this fixes that fact that `thing-at-point-bounds-of-string-at-point'
- ;; errors if called at the end of the buffer
- (condition-case nil
- (let ((sb (progn (goto-char beg) (bounds-of-thing-at-point thing)))
- (eb (progn (goto-char end) (bounds-of-thing-at-point thing))))
- (and sb eb (equal sb eb)
- (or (not no-edge)
- (and (/= beg (car sb))
- (< beg (cdr sb))
- (/= end (car sb))
- (< end (cdr sb))))))
- ;; if the error happens, we aren't in a string
- (wrong-type-argument nil))))
- (defun my/-evil-cp-region-ok-p-no-string (oldfun beg end)
- (or
- (and (sp-point-in-comment beg)
- (sp-point-in-comment end))
- (and (sp-point-in-string beg)
- (sp-point-in-string end)
- (my/range-inside-thing-p 'string beg end t))
- (funcall oldfun beg end)))
- (defun my/column-num-at-pos (pos)
- "Return the column number at POS."
- (save-excursion
- (goto-char pos)
- (current-column)))
- (defun my/-evil-cp-block-ok-p-no-string (oldfun beg end)
- (when (> beg end) (cl-rotatef beg end))
- (or
- (save-excursion
- (goto-char beg)
- (let ((start-off (current-column))
- (end-off (my/column-num-at-pos end)))
- (cl-block nil
- (dotimes (_ (count-lines beg end) t)
- (let ((bol (pos-bol)))
- (unless (sp-region-ok-p (+ bol start-off)
- (+ bol end-off))
- (cl-return))
- (forward-line))))))
- (funcall oldfun beg end)))
- (advice-add 'sp-region-ok-p :around 'my/-evil-cp-region-ok-p-no-string)
- (advice-add 'evil-cp--balanced-block-p :around 'my/-evil-cp-block-ok-p-no-string))
- ;; be (hopefully) safer
- (require 'trusted-files)
- (keymap-global-set "C-c t" 'trusted-files-map)
- (trusted-files-modeline-mode)
- ;; better lisp editing
- (use-package adjust-parens
- :hook (prog-mode . adjust-parens-mode)
- :config
- (defun my/lisp-indent-adjust-parens ()
- "Like `lisp-indent-adjust-parens', but got to first char on line first.
- Also, this works even if the region is active (it indents every line in the
- region)."
- (interactive)
- (save-mark-and-excursion
- (let ((end (mark t))
- (line-count 1)
- (indent-cols))
- (when (and (region-active-p) end)
- (setq mark-active nil
- line-count (count-lines (point) end))
- (when (> (point) end)
- (let ((start (point)))
- (goto-char end)
- (setq end start))))
- ;; find the indentation column of each line
- (save-excursion
- (dotimes (_ line-count)
- (back-to-indentation)
- (push (- (point) (pos-bol)) indent-cols)
- (forward-line))
- (cl-callf nreverse indent-cols))
- (cl-loop repeat line-count
- for indent-col in indent-cols
- for bol = (pos-bol)
- do (back-to-indentation)
- ;; skip this line if the indentation has changed
- when (= (- (point) bol) indent-col) do
- (lisp-indent-adjust-parens)
- ;; if the indent failed, stop
- (when (= (- (point) bol) indent-col)
- (cl-return))
- do (forward-line)))))
- (defun my/lisp-dedent-adjust-parens ()
- "Like `lisp-dedent-adjust-parens', but got to first char on line first.
- Also, this works even if the region is active (it just jumps to the first line
- in the region and indents once)."
- (interactive)
- (save-mark-and-excursion
- (let ((end (mark t)))
- (when (and (region-active-p) end)
- (setq mark-active nil)
- (when (> (point) end)
- (goto-char end))))
- (back-to-indentation)
- (lisp-dedent-adjust-parens)))
- (eldoc-add-command 'my/lisp-indent-adjust-parens
- 'my/lisp-dedent-adjust-parens
- 'lisp-indent-adjust-parens
- 'lisp-dedent-adjust-parens)
- (evil-define-key '(normal visual) adjust-parens-mode-map
- (kbd "<tab>") #'my/lisp-indent-adjust-parens
- (kbd "<backtab>") #'my/lisp-dedent-adjust-parens
- (kbd "C-c C-i") #'my/lisp-indent-adjust-parens
- (kbd "C-c S-<tab>") #'my/lisp-dedent-adjust-parens))
- ;; for when the files are just too large
- (use-package vlf
- :demand t
- :config
- (require 'vlf-setup))
- ;; allow copy from terminal
- (use-package xclip
- :config
- (setq xclip-method 'wl-copy
- xclip-program (symbol-name xclip-method))
- (xclip-mode 1)
- (defun my/-xclip-detect-wl-paste-error (oldfun type)
- (if (eq xclip-method 'wl-copy)
- ;; Direct from `xclip-get-selection'
- (when (and (getenv "WAYLAND_DISPLAY")
- (memq type '(clipboard CLIPBOARD primary PRIMARY)))
- (let* ((exit-code 0)
- (output
- (with-output-to-string
- (setq exit-code
- (apply #'call-process (replace-regexp-in-string
- "\\(.*\\)copy" "\\1paste"
- xclip-program 'fixedcase)
- nil standard-output nil
- "-n" (if (memq type '(primary PRIMARY))
- '("-p")))))))
- (if (zerop exit-code)
- output
- "")))
- (funcall oldfun type)))
- (advice-add 'xclip-get-selection :around 'my/-xclip-detect-wl-paste-error))
- ;; Set the WAYLAND_DISPLAY environment variable
- (require 'xdg)
- (defun my/detect-wayland-display ()
- "Try to set the WAYLAND_DISPLAY environment variable.
- This attempts to detect a running Wayland session and set the WAYLAND_DISPLAY
- environment variable accordingly."
- (let ((found '(nil . nil)))
- (dolist (entry (directory-files-and-attributes
- (xdg-runtime-dir) nil nil 'nosort)
- (cdr found))
- (cl-destructuring-bind (name . attrs) entry
- (when-let (((string-match (rx bos "wayland-" (group (+ (any "0-9"))) eos)
- name))
- (id (string-to-number (match-string 1 name)))
- ((or (not (car found)) (< id (car found))))
- ;; socket
- ((string-prefix-p "s" (file-attribute-modes attrs))))
- (setq found (cons id name)))))))
- (unless (getenv "WAYLAND_DISPLAY")
- (setenv "WAYLAND_DISPLAY" (my/detect-wayland-display)))
- ;; which-key
- (use-package which-key
- :diminish which-key-mode
- :config
- (which-key-mode 1))
- ;; avy
- (use-package avy
- :bind (("C-c C-j" . avy-resume)
- ("M-s s" . evil-avy-goto-char-2)
- ("M-s S" . evil-avy-goto-line))
- :init
- (define-minor-mode my/evil-avy-mode
- "A minor mode for binding avy commands to s and S in evil's normal and
- visual states."
- :keymap (make-sparse-keymap))
- (evil-define-key '(normal visual operator motion) my/evil-avy-mode-map
- "s" #'evil-avy-goto-char-2
- "S" #'evil-avy-goto-line)
- (define-globalized-minor-mode my/evil-avy-global-mode my/evil-avy-mode
- (lambda () (my/evil-avy-mode 1))
- :predicate '((not magit-mode dired-mode
- proced-mode mu4e-main-mode
- mu4e-view-mode mu4e-headers-mode
- ibuffer-mode calc-mode calc-trail-mode
- gnus-group-mode) t))
- (my/evil-avy-global-mode 1)
- :config
- (avy-setup-default))
- ;; better `replace-regexp'
- (use-package visual-regexp
- :bind (("C-c q" . vr/replace)
- ("C-M-%" . vr/query-replace)))
- ;; better `align-regexp'
- (use-package ialign
- :defer t
- :custom
- (ialign-initial-repeat t))
- ;; ace-window
- (use-package ace-window
- :diminish ace-window-mode
- :bind ("M-o" . ace-window)
- :init
- (setq aw-scope 'frame
- aw-minibuffer-flag t))
- ;; savehist
- (use-package savehist
- :config
- (savehist-mode 1))
- ;; vertico
- (use-package vertico
- :bind (:map vertico-map
- ("C-RET" . vertico-exit-input)
- ("C-<return>" . vertico-exit-input)
- ("C-S-k" . kill-line)
- ("C-k" . vertico-previous)
- ("C-j" . vertico-next)
- ("RET" . vertico-directory-enter)
- ("DEL" . vertico-directory-delete-char)
- ("M-DEL" . vertico-directory-delete-word))
- :hook (minibuffer-setup . cursor-intangible-mode)
- :init
- (defun my/crm-indicator (args)
- (cons (format "[CRM%s] %s"
- (replace-regexp-in-string
- "\\`\\[.*?]\\*\\|\\[.*?]\\*\\'" ""
- crm-separator)
- (car args))
- (cdr args)))
- (advice-add #'completing-read-multiple :filter-args #'my/crm-indicator)
- (setq vertico-cycle t
- enable-recursive-minibuffers t
- ;; read-extended-command-predicate #'command-completion-default-include-p
- read-extended-command-predicate nil
- minibuffer-prompt-properties '(read-only t ;; noindent 3
- cursor-intangible t
- face minibuffer-prompt))
- (vertico-mode 1)
- ;; for jinx
- (require 'vertico-multiform)
- (add-to-list 'vertico-multiform-categories
- '(jinx grid (vertico-grid-annotate . 20)))
- (vertico-multiform-mode 1))
- ;; orderless
- (use-package orderless
- :autoload orderless-define-completion-style
- :hook (text-mode . my/-setup-text-mode-completion-styles)
- :init
- (defun my/-setup-text-mode-completion-styles ()
- (setq-local completion-styles '(basic)))
- (orderless-define-completion-style my/orderless-with-initialism
- (orderless-matching-styles '(orderless-initialism
- orderless-regexp)))
- (setq orderless-matching-styles '(orderless-regexp)
- completion-styles '(orderless basic)
- completion-category-defaults nil
- completion-category-overrides '((file
- (styles basic partial-completion))
- (command
- (styles my/orderless-with-initialism basic)))))
- ;; marginalia
- (use-package marginalia
- :bind (:map minibuffer-local-map
- ("M-a" . marginalia-cycle))
- :init
- (marginalia-mode 1))
- ;; embark
- (use-package embark
- :bind (("C-," . embark-act)
- ("C-;" . embark-dwim)
- :map help-map
- ("B" . embark-bindings)
- :map embark-symbol-map
- ("h" . helpful-symbol)
- :map embark-become-file+buffer-map
- ("b" . consult-buffer)
- ("B" . switch-to-buffer))
- :init
- (setq embark-quit-after-action nil
- embark-indicators '(embark-minimal-indicator
- embark-isearch-highlight-indicator
- embark-highlight-indicator))
- :config
- (defvar-keymap my/embark-string-map
- :doc "Keymap for Embark string actions."
- :parent embark-expression-map
- "R" 'repunctuate-sentences)
- (defun my/embark-target-string ()
- "Target the string at point."
- (if-let (((not (eobp))) ; prevent next line from causing errors
- (bounds (bounds-of-thing-at-point 'string)))
- (append (list 'string (buffer-substring-no-properties (car bounds)
- (cdr bounds)))
- bounds)))
- (add-to-list 'embark-around-action-hooks
- '(repunctuate-sentences embark--mark-target))
- (add-to-list 'embark-keymap-alist
- '(string my/embark-string-map))
- (add-to-list 'embark-target-finders 'my/embark-target-string)
- (add-to-list 'display-buffer-alist
- '("\\`\\*Embark Collect \\(Live\\|Completions\\)\\*"
- nil
- (window-parameters (mode-line-format . none))))
- (evil-define-key '(normal motion) org-mode-map
- (kbd "C-,") #'embark-act))
- ;; consult
- (use-package consult
- :bind (("C-s" . consult-line)
- ("C-x b" . consult-buffer)
- ("C-S-s" . consult-ripgrep)
- ("C-x C-S-f" . consult-fd)
- ("C-x c k" . consult-keep-lines)
- ("C-x c f" . consult-focus-lines)
- ("C-x c r" . consult-recent-file)
- ("C-x c b" . consult-bookmark)
- ("C-x c d" . consult-fd)
- ("C-c p" . consult-fd)
- ("C-x c g" . consult-ripgrep)
- ("C-c P" . consult-ripgrep)
- ("C-x c y" . consult-yank-from-kill-ring)
- ("M-g i" . consult-imenu)
- ("M-g I" . consult-imenu-multi)
- ("M-g r" . consult-imenu-multi)
- :map help-map
- ("TAB". consult-info)
- ("RET" . consult-man))
- :hook (minibuffer-setup . my/consult-setup-minibuffer-completion)
- :init
- (defun my/consult-setup-minibuffer-completion ()
- (setq-local completion-in-region-function #'consult-completion-in-region))
- (evil-declare-motion #'consult-line))
- (use-package consult-eglot
- :commands consult-eglot-symbols)
- ;; wgrep
- (use-package wgrep)
- ;; integration for embark and consult
- (use-package embark-consult
- :hook (embark-collect-mode . consult-preview-at-point-mode))
- ;; corfu (autocomplete)
- (use-package corfu
- :bind (("M-<tab>" . completion-at-point)
- :map corfu-map
- ("C-j" . corfu-next)
- ("C-k" . corfu-previous)
- ("M-SPC" . corfu-insert-separator)
- ("M-m" . my/corfu-move-to-minibuffer))
- :init
- (defun my/corfu-move-to-minibuffer ()
- (interactive)
- (when completion-in-region--data
- (let ((completion-extra-properties corfu--extra)
- (completion-cycle-threshold completion-cycling))
- (apply #'consult-completion-in-region completion-in-region--data))))
- (setq corfu-cycle t
- corfu-auto t
- corfu-on-exact-match nil
- corfu-popupinfo-delay '(1.0 . 0.5)
- completion-cycle-threshold nil
- global-corfu-minibuffer
- ;; only enable corfu in the minibuffer in graphical frames
- (lambda ()
- (and (display-graphic-p)
- (not (eq (current-local-map)
- read-passwd-map)))))
- (global-corfu-mode 1)
- (corfu-popupinfo-mode 1)
- :config
- (add-to-list 'corfu-continue-commands #'my/corfu-move-to-minibuffer)
- (defun my/help-buffer-exists-p ()
- "Return if the buffer that `help-buffer' would, or nil if it doesn't exist."
- (or (and help-xref-following (derived-mode-p 'help-mode))
- (get-buffer "*Help*")))
- (defun my/-corfu-popupinfo-close-help-buffer (oldfun &rest args)
- (if (derived-mode-p 'emacs-lisp-mode)
- (let ((help-buf (my/help-buffer-exists-p)))
- (prog1
- (apply oldfun args)
- (when-let (((not help-buf))
- (buf (help-buffer)))
- ;; Ensure that, even if `help-buffer' returns nil in the future, we
- ;; don't kill the current buffer
- (kill-buffer buf))))
- (apply oldfun args)))
- (advice-add 'corfu-popupinfo--get-documentation :around
- 'my/-corfu-popupinfo-close-help-buffer))
- (use-package corfu-terminal
- :init
- (corfu-terminal-mode 1)
- :config
- (require 'corfu-terminal-popupinfo)
- (corfu-terminal-popupinfo-mode 1))
- (use-package dabbrev
- :ensure nil
- :config
- (add-to-list 'dabbrev-ignored-buffer-regexps "\\` ")
- (add-to-list 'dabbrev-ignored-buffer-modes 'doc-view-mode)
- (add-to-list 'dabbrev-ignored-buffer-modes 'pdf-view-mode)
- (add-to-list 'dabbrev-ignored-buffer-modes 'tags-table-mode))
- ;; cape (a bunch of capfs!)
- (use-package cape
- :bind (([remap dabbrev-expand] . cape-dabbrev)
- ("C-c P" . cape-line)
- ("C-c f" . cape-file))
- :hook (text-mode . my/-cape-setup-text-mode)
- :init
- (defun my/-cape-setup-text-mode ()
- ;; Only run this if we are not in `TeX-mode'
- (unless (bound-and-true-p TeX-mode-p)
- (setq-local completion-at-point-functions
- (append completion-at-point-functions (list 'cape-dict
- 'cape-dabbrev))
- corfu-auto nil))))
- ;; xref
- (use-package xref
- :init
- (evil-define-key '(normal motion) 'global
- "gr" #'xref-find-references)
- (setq xref-show-xrefs-function #'consult-xref
- xref-show-definitions-function #'consult-xref))
- ;; popup.el
- (use-package popup)
- ;; posframe
- (use-package posframe
- :init
- (defun my/posframe-tip (name msg)
- "Like `popup-tip', but with a posframe.
- NAME should be the buffer name to pass to `posframe-show'. MSG is the message to
- display."
- (unwind-protect
- (progn
- (posframe-show name
- :string msg
- :position (point)
- :max-width 80
- :border-width 2
- :border-color "white")
- (clear-this-command-keys)
- (push (read-event) unread-command-events)
- (posframe-hide name))
- (posframe-hide name))))
- (defun my/floating-tooltip (name msg)
- "If `display-graphic-p', call `my/posframe-tip', otherwise `popup-tip'.
- MSG is the message to show in the popup. NAME is the name of the buffer to pass
- to `posframe-show' if the display is graphical."
- (if (display-graphic-p)
- (my/posframe-tip name msg)
- (popup-tip msg)))
- ;; flymake
- (use-package flymake
- :config
- (require 'consult-flymake))
- ;; flycheck
- (use-package flycheck
- :hook ((sh-mode emacs-lisp-mode) . trusted-files-flycheck-mode-if-safe)
- :custom
- (flycheck-indication-mode 'left-margin)
- :init
- (setq flycheck-display-errors-function nil))
- (use-package consult-flycheck)
- (defun my/sly-notes-at-point (&optional pos buffer)
- "Return the sly notes at POS in BUFFER.
- If BUFFER is nil, the current buffer is used."
- (with-current-buffer (or buffer (current-buffer))
- (unless pos
- (setq pos (point)))
- (cl-loop for overlay in (overlays-at pos)
- for note = (overlay-get overlay 'sly-note)
- when note
- collect note)))
- (defun my/diagnostic-at-point ()
- "Show the diagnostics under point."
- (interactive)
- (let ((message))
- (when-let (((bound-and-true-p flymake-mode))
- (diag (get-char-property (point) 'flymake-diagnostic)))
- (cl-callf nconc message (string-split (flymake--diag-text diag) "\n" t)))
- (when (bound-and-true-p flycheck-mode)
- (cl-callf nconc message
- (mapcar 'flycheck-error-message (flycheck-overlay-errors-at (point)))))
- ;; sly (lazy-loaded)
- (when (featurep 'sly)
- (cl-callf nconc message (mapcar (lambda (note)
- (plist-get note :message))
- (my/sly-notes-at-point))))
- ;; jinx
- (when-let (((bound-and-true-p jinx-mode))
- (jinx-msg (jinx--get-overlays (point) (1+ (point)))))
- (push "misspelled word" message))
- (when message
- (my/floating-tooltip " *my-diagnostic-posframe*"
- (mapconcat (lambda (msg)
- (concat "•" msg))
- message "\n")))))
- (defconst my/consult-flymake-flycheck-narrow
- '((?e . "Error")
- (?w . "Warning")
- (?i . "Info")
- (?n . "Info")))
- (defun my/-consult-replace-flymake-error-level (candidates)
- "Return CANDIDATES with the flymake error level note replaced with info."
- (cl-loop for cand in candidates
- collect
- (cl-loop
- with start = nil
- for i below (length cand)
- for props = (text-properties-at i cand)
- for face = (plist-get props 'face)
- when (eq face 'compilation-info) do
- (setq start (or start i))
- else when start do
- (setf (substring cand start i)
- (propertize (string-pad "info" (- i start))
- 'face (flycheck-error-level-error-list-face
- 'info)))
- (cl-return cand)
- finally return cand)))
- (defun my/consult-flymake-flycheck-candidates (&optional project)
- "Return combined candidate list for flymake and flycheck.
- With PROJECT, return the candiadeets for that project."
- (let ((had-errors))
- (prog1
- (seq-uniq
- (append
- (when-let (((bound-and-true-p flymake-mode))
- (diags (if project (flymake--project-diagnostics
- project)
- (flymake-diagnostics))))
- (setq had-errors t)
- (my/-consult-replace-flymake-error-level
- (consult-flymake--candidates diags)))
- (when (boundp 'flycheck-mode)
- (if project
- (cl-loop for buf in (project-buffers project)
- append
- (with-current-buffer buf
- (when (and flycheck-mode flycheck-current-errors)
- (setq had-errors t)
- (consult-flycheck--candidates))))
- (when (and flycheck-mode flycheck-current-errors)
- (setq had-errors t)
- (consult-flycheck--candidates))))))
- (unless had-errors
- (user-error "No errors (Flymake: %s | Flycheck: %s)"
- (cond
- ((not (bound-and-true-p flymake-mode))
- "not running")
- ((seq-difference (flymake-running-backends)
- (flymake-reporting-backends))
- "running")
- (t "finished"))
- (if (boundp 'flycheck-last-status-change)
- flycheck-last-status-change
- "not running"))))))
- (defun my/consult-flymake-flycheck (&optional project)
- "Jump to flymake or flycheck error.
- With PROJECT, give diagnostics for all buffers in the current project."
- (interactive "P")
- (consult--read
- (consult--with-increased-gc
- (my/consult-flymake-flycheck-candidates
- (and project (project-current))))
- :prompt "Error: "
- :category 'flymake-flycheck-error
- :history t
- :require-match t
- :sort nil
- :narrow (consult--type-narrow my/consult-flymake-flycheck-narrow)
- :group (consult--type-group my/consult-flymake-flycheck-narrow)
- :lookup #'consult--lookup-candidate
- :state (consult--jump-state)))
- (with-eval-after-load 'flymake
- (keymap-set flymake-mode-map "C-c e" 'my/diagnostic-at-point)
- (keymap-set flymake-mode-map "C-c E" 'my/consult-flymake-flycheck))
- (with-eval-after-load 'flycheck
- (keymap-set flycheck-mode-map "C-c e" 'my/diagnostic-at-point)
- (keymap-set flycheck-mode-map "C-c E" 'my/consult-flymake-flycheck))
- (with-eval-after-load 'jinx
- (keymap-set jinx-mode-map "C-c e" 'my/diagnostic-at-point))
- ;; eldoc
- (use-package eldoc
- :diminish eldoc-mode
- :init
- (setq-default eldoc-echo-area-use-multiline-p nil))
- ;; eglot
- (use-package eglot
- :demand t
- :pin gnu ;; try to force Elpa version to fix warnings
- :hook ((eglot-managed-mode . my/-eglot-setup))
- :init
- ;; (defun my/eglot-in-text-mode-only ()
- ;; (when (eq major-mode 'text-mode)
- ;; (trusted-files-eglot-ensure-if-safe)))
- (defvar my/-eglot-documentation-buffer nil
- "Buffer for showing documentation for `my/eglot-documentation-at-point'.")
- (define-derived-mode my/eglot-documentation-mode special-mode "Eglot-Doc"
- "Major mode for eglot documentation buffers."
- :interactive nil
- (face-remap-add-relative 'nobreak-space 'default))
- (defun my/eglot-documentation-at-point ()
- "Show documentation for a symbol at point."
- (interactive)
- (if-let (server (eglot-current-server))
- (progn
- (unless (buffer-live-p my/-eglot-documentation-buffer)
- (setq my/-eglot-documentation-buffer
- (get-buffer-create "*eglot documentation*")))
- (eglot-hover-eldoc-function
- (lambda (info _ _)
- (if-let (((not (seq-empty-p info)))
- (buff (current-buffer)))
- (with-current-buffer my/-eglot-documentation-buffer
- (let ((inhibit-read-only t))
- (unless (derived-mode-p 'my/eglot-documentation-mode)
- (my/eglot-documentation-mode))
- (erase-buffer)
- (insert info)
- (goto-char (point-min)))
- (when (not (get-buffer-window my/-eglot-documentation-buffer nil))
- (switch-to-buffer-other-window my/-eglot-documentation-buffer t)
- (switch-to-buffer-other-window buff t)))))))))
- (defun my/-eglot-cleanup-doc-buffer (_server &optional _interactive _timeout
- preserve-buffers)
- (when (and (not preserve-buffers)
- (buffer-live-p my/-eglot-documentation-buffer)
- (cl-every (lambda (buffer)
- (with-current-buffer buffer
- (let ((server (eglot-current-server)))
- (or (not (eglot-lsp-server-p server))
- (eglot--shutdown-requested server)))))
- (buffer-list)))
- (kill-buffer my/-eglot-documentation-buffer)))
- (advice-add 'eglot-shutdown :after 'my/-eglot-cleanup-doc-buffer)
- (defun my/-eglot-setup ()
- "Setup eldoc variables for `eglot-managed-mode-hook'."
- (setq-local evil-lookup-func #'my/eglot-documentation-at-point)
- (evil-define-key '(normal motion) 'local
- "K" #'evil-lookup
- "gR" #'eglot-rename
- "gA" #'eglot-code-actions
- "gs" #'consult-eglot-symbols)
- (eglot-inlay-hints-mode -1))
- (setq eglot-autoshutdown t
- eglot-ignored-server-capabilities '(:documentOnTypeFormattingProvider))
- :config
- (add-to-list 'eglot-server-programs
- (cons '(c-mode c-ts-mode c++-mode c++-ts-mode objc-mode)
- '("clangd" "--all-scopes-completion" "--background-index"
- "--clang-tidy" "--completion-style=detailed"
- "--header-insertion=never" "--pch-storage=memory"
- "--function-arg-placeholders"
- "--compile-commands-dir=build"))))
- (use-package eglot-inactive-regions
- :custom
- (eglot-inactive-regions-style 'darken-foreground)
- (eglot-inactive-regions-opacity 0.4)
- :config
- (eglot-inactive-regions-mode 1))
- ;; LTeX (languagetool)
- (require 'ltex-eglot)
- ;; apheleia (code formatter)
- (use-package apheleia
- :defer nil
- :bind ("C-c o" . apheleia-format-buffer)
- :init
- (add-to-list 'auto-mode-alist `(,(rx "/.clang-format" eos) . yaml-ts-mode))
- (defun my/apheleia-disable-in-current-buffer ()
- (setq-local apheleia-inhibit t))
- :config
- (with-eval-after-load 'apheleia
- (setf (alist-get 'java-mode apheleia-mode-alist) 'clang-format
- (alist-get 'java-ts-mode apheleia-mode-alist) 'clang-format))
- (apheleia-global-mode +1))
- ;; awk
- (with-eval-after-load 'cc-mode
- (add-hook 'awk-mode-hook #'my/apheleia-disable-in-current-buffer))
- ;; gud
- (use-package gud
- :demand t
- :ensure nil
- :after (project evil)
- :bind (:map project-prefix-map
- ("U" . my/project-gdb))
- :config
- (setq gdb-debuginfod-enable-setting t)
- (defvar my/project-gdb-command nil
- "Command to use in `my/project-gdb'.")
- (put 'my/project-gdb-command 'safe-local-variable (lambda (val)
- (stringp val)))
- (defun my/project-gdb (project command-line)
- "Run gdb in the project root"
- (interactive (let* ((project (project-current t))
- (default-directory (project-root project)))
- (list project (gud-query-cmdline 'gdb))))
- (let ((default-directory (project-root project)))
- (gdb command-line)))
- (evil-set-initial-state 'gdb-locals-mode 'motion)
- (evil-collection-inhibit-insert-state 'gdb-locals-mode-map)
- (evil-define-key '(normal motion visual) gdb-locals-mode-map
- (kbd "TAB") (keymap-lookup gdb-locals-mode-map "TAB")
- (kbd "RET") #'gdb-edit-locals-value
- (kbd "<mouse-1>") #'gdb-edit-locals-value
- "q" #'kill-current-buffer)
- (evil-set-initial-state 'gdb-registers-mode 'motion)
- (evil-collection-inhibit-insert-state 'gdb-registers-mode-map)
- (evil-define-key '(normal motion visual) gdb-registers-mode-map
- (kbd "TAB") (keymap-lookup gdb-registers-mode-map "TAB")
- (kbd "RET") #'gdb-edit-register-value
- (kbd "<mouse-1>") #'gdb-edit-register-value
- "q" #'kill-current-buffer
- (kbd "C-c f") #'gdb-registers-toggle-filter
- (kbd "C-c F") (lambda ()
- "Customize the filter for the registers buffer."
- (interactive)
- (customize-option-other-window
- 'gdb-registers-filter-pattern-list)))
- (evil-set-initial-state 'gdb-frames-mode 'motion)
- (evil-collection-inhibit-insert-state 'gdb-frames-mode-map)
- (evil-define-key '(normal motion visual) gdb-frames-mode-map
- "q" #'kill-current-buffer
- (kbd "RET") #'gdb-select-frame)
- (evil-set-initial-state 'gdb-breakpoints-mode 'motion)
- (evil-collection-inhibit-insert-state 'gdb-breakpoints-mode-map)
- (evil-define-key '(normal motion visual) gdb-breakpoints-mode-map
- (kbd "TAB") (keymap-lookup gdb-breakpoints-mode-map "TAB")
- "q" #'gdb-delete-frame-or-window
- "D" #'gdb-delete-breakpoint
- (kbd "RET") #'gdb-goto-breakpoint
- (kbd "<mouse-1>") #'gdb-goto-breakpoint
- (kbd "SPC") #'gdb-toggle-breakpoint)
- (evil-set-initial-state 'gdb-threads-mode 'motion)
- (evil-collection-inhibit-insert-state 'gdb-threads-mode-map)
- (evil-define-key '(normal motion visual) gdb-threads-mode-map
- (kbd "TAB") (keymap-lookup gdb-threads-mode-map "TAB")
- "q" #'gdb-delete-frame-or-window
- "D" #'gdb-frame-disassembly-for-thread
- (kbd "C-c f") #'gdb-display-stack-for-thread
- (kbd "C-c i") #'gdb-interrupt-thread
- (kbd "C-c l") #'gdb-display-locals-for-thread
- (kbd "C-c r") #'gdb-display-registers-for-thread
- (kbd "C-c c") #'gdb-continue-thread
- (kbd "C-c d") #'gdb-display-disassembly-for-thread
- (kbd "C-c s") #'gdb-step-thread
- (kbd "C-c F") #'gdb-frame-stack-for-thread
- (kbd "C-c L") #'gdb-frame-locals-for-thread
- (kbd "C-c R") #'gdb-frame-registers-for-thread
- (kbd "RET") #'gdb-select-thread
- (kbd "<mouse-2>") #'gdb-select-thread))
- ;; dape
- (use-package dape
- :hook ((after-init . dape-breakpoint-load)
- (kill-emacs . dape-breakpoint-save)
- (dape-start . save-some-buffers)
- (dape-display-source . pulse-momentary-highlight-one-line))
- :bind (:map dape-info-parent-mode-map
- ("<tab>" . dape--info-buffer-tab))
- :init
- (setopt dape-default-breakpoints-file (no-littering-expand-var-file-name
- "dape-breakpoints"))
- :config
- (setopt dape-buffer-window-arrangement 'right)
- (dape-breakpoint-global-mode 1))
- ;; dumb-jump
- (use-package dumb-jump
- :init
- (add-hook 'xref-backend-functions #'dumb-jump-xref-activate))
- ;; yasnippet
- (use-package yasnippet
- :demand t
- :bind ("C-c s" . yas-expand)
- :config
- (yas-global-mode 1))
- ;; project.el
- (use-package project
- :bind (([remap project-compile] . my/project-compile-or-default)
- :map project-prefix-map
- ("s" . my/project-eshell)
- ("u" . my/project-run))
- :init
- (defvar eshell-buffer-name)
- (defun my/project-eshell (prompt &optional arg)
- "Switch to or create an eshell buffer in the current projects root."
- (interactive (list t current-prefix-arg))
- (if-let ((proj (project-current prompt))
- (default-directory (project-root proj))
- (eshell-buffer-name
- (concat "*eshell for project " default-directory "*")))
- (eshell arg)))
- (defun my/project-eshell-or-default (&optional arg)
- "Open an eshell for the current project, otherwise, open a normal eshell."
- (interactive "P")
- (unless (my/project-eshell nil arg)
- (eshell arg)))
- (defun my/project-compile-or-default ()
- "If in a project, run `project-compile', otherwise run `compile'."
- (interactive)
- (if (project-current)
- (call-interactively 'project-compile)
- (call-interactively 'compile)))
- (defvar my/project-run-command nil
- "Command to run with `my/project-run'.")
- (put 'my/project-run-command 'safe-local-variable (lambda (val)
- (stringp val)))
- (defvar my/project-run-dir nil
- "Directory to run project in with `my/project-run'.")
- (put 'my/project-run-dir 'safe-local-variable (lambda (val)
- (stringp val)))
- (defvar my/-project-run-history '()
- "Commands previously run with `my/project-run'")
- (defvar my/project-root-marker ".project-root"
- "Marker file to look for in non-vc backed projects.")
- (defun my/project-get-root-dir ()
- "Get the root dir for the current project"
- (let* ((proj (project-current nil))
- (default-directory (if proj
- (project-root proj)
- default-directory)))
- (if my/project-run-dir
- (expand-file-name my/project-run-dir)
- default-directory)))
- (defvar my/compile-use-comint t
- "Weather or not to use comint by default for compile buffers.")
- (defun my/-compile-use-comint-by-default (args)
- (if my/compile-use-comint
- (list (car args) t)
- args))
- (advice-add 'compile :filter-args 'my/-compile-use-comint-by-default)
- (defun my/project-run (command comint)
- "Like `project-compile', but for running a project.
- COMMAND and COMINT are like `compile'."
- (interactive
- (list
- (let ((default-directory (my/project-get-root-dir)))
- (read-shell-command "Run Command: "
- (or (car my/-project-run-history)
- my/project-run-command)
- (if (and my/project-run-command
- (equal my/project-run-command
- (car-safe my/-project-run-history)))
- '(my/-project-run-history . 1)
- 'my/-project-run-history)))
- (consp current-prefix-arg)))
- (let* ((default-directory (my/project-get-root-dir))
- (compilation-buffer-name-function (lambda (_)
- (progn "*run project*")))
- (compilation-directory default-directory)
- (compile-history nil)
- (compile-command nil))
- (compile command comint)
- (when (not my/project-run-command)
- (setq my/project-run-command command))))
- :config
- (defun my/project-try-dotfile (dir)
- (if-let (root (locate-dominating-file dir my/project-root-marker))
- (list 'vc nil root)))
- (add-hook 'project-find-functions #'my/project-try-dotfile))
- ;; comint
- (use-package comint
- :ensure nil
- :after evil
- :config
- (evil-set-initial-state 'comint-mode 'normal))
- ;; nxml
- (use-package nxml-mode
- :ensure nil
- :hook (nxml-mode . my/-nxml-setup)
- :init
- (defun my/-nxml-setup ()
- "Setup `nxml-mode'."
- (sgml-electric-tag-pair-mode 1)
- (setq-local completion-at-point-functions
- '(rng-completion-at-point cape-file)))
- (add-to-list 'auto-mode-alist
- `(,(concat
- (regexp-opt '("gschema" "gresource" "ui")) "\\'")
- . nxml-mode)))
- ;; devdocs
- (use-package devdocs
- :bind (("C-h D" . devdocs-lookup)))
- ;; Bibtex (built in)
- (require 'bibtex)
- ;; Better URL highlighting and matching
- (dolist (field '("howpublished" "url"))
- (add-to-list 'bibtex-generate-url-list
- `((,field . ,(rx "http" (? "s") "://" (+ (not "}"))))
- "%s"
- (,field
- ,(rx (? (or "\\url{" "{")) (group "http" (? "s") "://"
- (+ (not "}")))
- (? "}"))
- ,(lambda (field)
- (match-string 1 field))))))
- (defun my/bibtex-in-entry-p (&optional exclude-braces)
- "Return t is point is inside a BibTeX entry.
- When EXCLUDE-BRACES is non-nil, don't count the first and last brace of the
- entry as in the entry. That is, if the point is on the first { or last } of the
- entry, return nil."
- (cl-destructuring-bind (depth &rest r) (syntax-ppss)
- (if (zerop depth)
- (and (not exclude-braces) (eql (char-after) ?\{))
- (or (not exclude-braces) (not (eql (char-after) ?\}))))))
- (defvar my/bibtex-indent-width 4
- "Width to indent for `my/bibtex-calculate-indentation'.")
- (defun my/bibtex-calculate-indentation ()
- "Calculate the column to indent to on the current line."
- (save-excursion
- (back-to-indentation)
- (if (my/bibtex-in-entry-p t)
- my/bibtex-indent-width
- 0)))
- (defun my/bibtex-empty-line-p ()
- "Return t if the current line is only blank characters."
- (save-excursion
- (beginning-of-line)
- (looking-at (rx (* blank) eol))))
- (defun my/bibtex-indent-line ()
- "Indent the current line."
- (interactive)
- (save-excursion
- (beginning-of-line)
- (when (looking-at (rx (+ blank)))
- (delete-region (point) (match-end 0)))
- (indent-to (my/bibtex-calculate-indentation)))
- (when (looking-at (rx (+ blank) eol))
- (end-of-line)))
- (defun my/bibtex-indent-or-find-text ()
- "Either indent the current line or jump to the current fields text.
- If the current line is only whitespace call `my/bibtex-calculate-indentation',
- otherwise, call `bibtex-find-text'."
- (interactive)
- (if (my/bibtex-empty-line-p)
- (my/bibtex-indent-line)
- (bibtex-find-text)))
- (defun my/bibtex-indent-or-find-text-and-insert ()
- "Like `my/bibtex-indent-or-find-text', but enter insert mode after."
- (interactive)
- (my/bibtex-indent-or-find-text)
- (if (my/bibtex-empty-line-p)
- (evil-append 1)
- (evil-insert 1)))
- (defun my/-bibtex-setup-indent ()
- "Set up `bibtex-mode' indentation stuff."
- (setq-local indent-line-function 'my/bibtex-indent-line
- electric-indent-chars '(?\n ?\{ ?\} ?,)))
- (defun my/-bibtex-fix-fill-prefix ()
- "`bivtex-mode' has a bad habbit of messing up `fill-prefix'."
- (when (eq major-mode 'bibtex-mode)
- (setq-local fill-prefix nil)))
- (advice-add 'bibtex-mode :after 'my/-bibtex-fix-fill-prefix)
- (add-hook 'bibtex-mode-hook 'my/-bibtex-setup-indent)
- (keymap-set bibtex-mode-map "RET" 'newline-and-indent)
- (keymap-set bibtex-mode-map "TAB" 'my/bibtex-indent-or-find-text)
- (evil-define-key 'normal bibtex-mode-map
- (kbd "TAB") 'my/bibtex-indent-or-find-text-and-insert)
- ;; Latex help (from elisp file)
- (require 'latex-help)
- ;; AUCTeX
- (use-package auctex
- :hook ((LaTeX-mode . turn-on-reftex)
- (LaTeX-mode . LaTeX-math-mode)
- (LaTeX-mode . my/-setup-LaTeX-mode)
- (LaTeX-mode . trusted-files-flycheck-mode-if-safe))
- :bind (:map TeX-mode-map
- ("C-c ?" . latex-help))
- :init
- (add-to-list 'major-mode-remap-alist '(plain-tex-mode . plain-TeX-mode))
- (add-to-list 'major-mode-remap-alist '(latex-mode . LaTeX-mode))
- (add-to-list 'major-mode-remap-alist '(ams-tex-mode . AmSTeX-mode))
- (add-to-list 'major-mode-remap-alist '(context-mode . ConTeXt-mode))
- (add-to-list 'major-mode-remap-alist '(texinfo-mode . Texinfo-mode))
- (add-to-list 'major-mode-remap-alist '(doctex-mode . docTeX-mode))
- (add-to-list 'auto-mode-alist '("/\\.latexmkrc\\'" . perl-mode))
- (add-to-list 'auto-mode-alist '("\\.[tT]e[xX]\\'" . LaTeX-mode))
- :config
- (defun my/-auctex-texdoc-setup-env (oldfun &rest args)
- (let ((process-environment process-environment)
- (emacs-cmd (concat "emacsclient" (and (not (display-graphic-p)) " -nw"))))
- (setenv "PDFVIEWER_texdoc" "evince")
- (setenv "MDVIEWER_texdoc" emacs-cmd)
- (setenv "PAGER_texdoc" emacs-cmd)
- (apply oldfun args)))
- (advice-add 'TeX-documentation-texdoc :around 'my/-auctex-texdoc-setup-env)
- (defun my/-setup-LaTeX-mode ()
- (setq evil-lookup-func 'latex-help-at-point))
- (setq TeX-auto-save t
- TeX-parse-self t
- reftex-plug-into-AUCTeX t)
- (evil-define-operator my/evil-LaTeX-fill (beg end)
- "Like `evil-fill', but using auctex."
- ;; The code here came straight from `evil-fill'
- :move-point nil
- :type line
- (save-excursion
- (ignore-errors (LaTeX-fill-region beg end))))
- (evil-define-operator my/evil-LaTeX-fill-and-move (beg end)
- "Like `evil-fill-and-move', but using auctex."
- ;; The code here came straight from `evil-fill-and-move'
- :move-point nil
- :type line
- (let ((marker (make-marker)))
- (move-marker marker (1- end))
- (ignore-errors
- (LaTeX-fill-region beg end)
- (goto-char marker)
- (evil-first-non-blank))))
- (evil-define-key 'normal TeX-mode-map
- "gq" 'my/evil-LaTeX-fill-and-move
- "gw" 'my/evil-LaTeX-fill)
- (setq-default TeX-master nil)
- (require 'tex)
- (TeX-global-PDF-mode 1))
- ;; blueprint
- (use-package blueprint-ts-mode
- :hook (blueprint-ts-mode . trusted-files-eglot-ensure-if-safe)
- :after eglot)
- ;; python-ts-mode
- (use-package python-ts-mode
- :ensure nil
- :hook (python-ts-mode . trusted-files-eglot-ensure-if-safe))
- ;; python virtual environments
- (use-package pyvenv)
- (use-package pyenv-mode)
- ;; My dev environment for ROS2
- (require 'arch-ros2)
- (require 'inferior-jshell)
- ;; java-ts-mode
- (use-package java-ts-mode
- :hook ((java-ts-mode . trusted-files-eglot-ensure-if-safe)
- (java-ts-mode . my/-setup-java-ts-mode))
- :bind (:map java-ts-mode-map
- ("C-x C-e" . jshell-eval-expression)
- ("C-M-x" . jshell-eval-defun)
- ("C-c C-r" . jshell-eval-region)
- ("C-c C-b" . jshell-eval-buffer))
- :config
- (defun my/-setup-java-ts-mode ()
- (let ((rules (car treesit-simple-indent-rules)))
- (setcdr rules
- (cons '((and (parent-is "array_initializer")
- (node-is "array_initializer"))
- parent-bol java-ts-mode-indent-offset)
- (nthcdr 1 rules))))))
- ;; c-ts-mode
- (use-package c-ts-mode
- :after evil
- :hook ((c-ts-mode c++-ts-mode) . trusted-files-eglot-ensure-if-safe)
- :init
- (setq-default c-ts-mode-indent-offset 4)
- :config
- (evil-define-key 'normal 'c-ts-mode-map
- "go" #'ff-find-other-file
- "gO" #'ff-find-other-file-other-window)
- (evil-define-key 'normal 'c++-ts-mode-map
- "go" #'ff-find-other-file
- "gO" #'ff-find-other-file-other-window)
- (evil-define-key 'normal 'objc-mode-map
- "go" #'ff-find-other-file
- "gO" #'ff-find-other-file-other-window))
- ;; GLSL
- (use-package glsl-mode)
- ;; php-mode
- (use-package php-mode
- :hook (php-mode . trusted-files-eglot-ensure-if-safe))
- ;; web-mode
- (use-package web-mode
- :hook (web-mode . trusted-files-eglot-ensure-if-safe)
- :init
- (add-to-list 'eglot-server-programs
- '(web-mode . ("vscode-html-language-server" "--stdio"))))
- ;; JavaScript
- (use-package js
- :ensure nil
- :hook (js-ts-mode . trusted-files-eglot-ensure-if-safe))
- (use-package js-comint
- :bind (:map js-ts-mode-map
- ("C-x C-e" . js-send-last-sexp)
- ("C-c C-b" . js-send-buffer)
- ("C-c C-r" . js-send-region)
- ("C-M-x" . my/js-send-defun))
- :hook (js-comint-mode . my/-setup-js-comint-mode)
- :config
- (defun my/-setup-js-comint-mode ()
- (setq-local comint-highlight-input nil))
- (defun my/js-send-defun ()
- "Send the defun under point to the inferior JavaScript process."
- (interactive)
- (if-let ((code (thing-at-point 'defun)))
- (js-comint-send-string code)
- (user-error "No defun under point"))))
- ;; TypeScript
- (use-package typescript-ts-mode
- :ensure nil
- :hook (typescript-ts-mode . trusted-files-eglot-ensure-if-safe)
- :init
- (add-to-list 'auto-mode-alist `(,(rx ".ts" eos) . typescript-ts-mode)))
- ;; Polymode
- (use-package polymode
- :config
- (define-hostmode my/poly-web-hostmode
- :mode 'web-mode)
- (define-innermode my/poly-php-innermode
- :mode 'php-mode
- :head-matcher (regexp-quote "<?php")
- :tail-matcher (regexp-quote "?>")
- :head-mode 'body
- :tail-mode 'body)
- (define-polymode my/poly-web-mode
- :hostmode 'my/poly-web-hostmode
- :innermodes '(my/poly-php-innermode))
- (add-to-list 'auto-mode-alist '("\\.php\\|\\.phtml\\'" . my/poly-web-mode)))
- ;; shell-mode
- (use-package sh-script
- :ensure nil
- :hook (sh-mode . my/-setup-sh-mode)
- :init
- (defun my/-setup-sh-mode ()
- (add-hook 'completion-at-point-functions #'cape-file nil t)))
- ;; go mode
- (use-package go-mode
- :defer nil
- :hook (go-mode . trusted-files-eglot-ensure-if-safe))
- (use-package go-ts-mode
- :ensure nil
- :hook (go-ts-mode . trusted-files-eglot-ensure-if-safe))
- ;; rust
- (use-package rust-mode)
- (use-package rust-ts-mode
- :ensure nil
- :hook (rust-ts-mode . trusted-files-eglot-ensure-if-safe))
- ;; zig
- (use-package zig-mode
- :hook (zig-mode . trusted-files-eglot-ensure-if-safe))
- ;; lua
- (use-package lua-mode
- :hook (lua-mode . trusted-files-eglot-ensure-if-safe))
- ;; markdown
- (use-package markdown-mode
- :hook (markdown-mode . auto-fill-mode))
- ;; groovy
- (use-package groovy-mode)
- ;; cmake
- (require 'cmake-mode)
- (require 'cmake-ts-mode)
- (with-eval-after-load 'cmake-mode
- (setq cmake-ts-mode-indent-offset tab-width))
- ;; kdl
- (require 'kdl-ts-mode)
- (with-eval-after-load 'kdl-ts-mode
- (setq kdl-ts-mode-indent-offset 4))
- ;; json
- (use-package json-ts-mode
- :hook (json-ts-mode . trusted-files-eglot-ensure-if-safe)
- :custom
- (json-ts-mode-indent-offset 4)
- :init
- (add-to-list 'auto-mode-alist '("\\.jsonc\\'" . json-ts-mode)))
- (use-package json-mode)
- ;; csv
- (use-package csv-mode)
- ;; firejail
- (require 'firejail-mode)
- ;; yaml
- (use-package yaml-ts-mode
- :hook ((yaml-ts-mode . trusted-files-eglot-ensure-if-safe)
- (yaml-ts-mode . my/-setup-yaml-ts-mode))
- :init
- (defun my/-setup-yaml-ts-mode ()
- (setq indent-line-function #'yaml-indent-line)))
- (use-package yaml-mode)
- ;; yuck (config language for eww)
- (use-package yuck-mode)
- ;; Some Elisp indentation stuff
- ;; Source: https://github.com/magit/emacsql
- ;; emacsql.el line 394
- (defun my/lisp-inside-plist-p ()
- "Return t if point is inside a plist."
- (save-excursion
- (let ((start (point)))
- (beginning-of-defun)
- (when-let ((sexp (nth 1 (parse-partial-sexp (point) start))))
- (goto-char sexp)
- (looking-at (rx "(" (* (syntax whitespace)) ":"))))))
- (defun my/-calculate-indent-fix-plists (oldfun &rest args)
- "This function is meant to advise `calculate-lisp-indent'.
- It calls OLDFUN with ARGS in such an environment as to prevent the default
- indentation of plists."
- (if (and (eq major-mode 'emacs-lisp-mode)
- (save-excursion
- (beginning-of-line)
- (my/lisp-inside-plist-p)))
- (let ((lisp-indent-offset 1))
- (apply oldfun args))
- (apply oldfun args)))
- (advice-add 'calculate-lisp-indent :around
- 'my/-calculate-indent-fix-plists)
- (defvar my/max-lisp-noindent-comment-search-lines 30
- "Max lines to search for the noindent comment.")
- (defun my/-calculate-lisp-indent-noindent-comment (oldfun &rest args)
- "This function is meant to advise `calculate-lisp-indent'.
- It calls OLDFUN with ARGS, unless the line ends with the comment
- ; noindent [LINES]
- In this case, it just returns the current amount of indentation. LINES is the
- number of lines that this comment affects. This is limited by
- `my/max-lisp-noindent-comment-search-lines'.
- This only works if its on the first or second form in a block. I think this is
- because the indentation code only checks those and then assumes the same
- indentation for every following line in the same block. This is probably OK as
- I can't imagine too many instances where you need to randomly change the indent
- midway through a block, and in those cases you can just stick this on the first
- line in the block and manually deal with indentation."
- (if (and (save-excursion
- (end-of-line)
- (re-search-backward
- (rx (+ ";") (syntax whitespace) "noindent"
- (? (syntax whitespace) (group (+ num)))
- line-end)
- (pos-bol (- my/max-lisp-noindent-comment-search-lines))
- t))
- (save-excursion
- ;; if we are on a blank line, move forward a line
- (when (= (pos-bol) (pos-eol))
- (beginning-of-line 2))
- (<= (count-lines (match-beginning 0) (pos-eol))
- (if-let ((match (match-string 1)))
- (string-to-number match)
- 1))))
- (save-excursion
- (beginning-of-line)
- (looking-at (rx (* blank)))
- (length (match-string 0)))
- (apply oldfun args)))
- (advice-add 'calculate-lisp-indent :around
- 'my/-calculate-lisp-indent-noindent-comment)
- ;; sly
- (use-package sly
- ;; :hook (lisp-mode . my/-lisp-mode-autoconnect-sly)
- :bind (:map sly-mode-map
- ("C-c e" . my/diagnostic-at-point))
- :autoload sly-connected-p
- :init
- (defun my/-lisp-mode-autoconnect-sly ()
- (unless (sly-connected-p)
- (trusted-files-sly-if-safe)))
- (setq inferior-lisp-program "/usr/bin/sbcl")
- (defun my/-sly-fix-special-buffers ()
- (when (string-match-p (rx bos "*" (* any) "*" eos) (buffer-name))
- (setq-local show-trailing-whitespace nil)))
- (add-hook 'lisp-mode-hook 'my/-sly-fix-special-buffers)
- :config
- (evil-define-key 'insert sly-mrepl-mode-map
- (kbd ",") 'self-insert-command)
- (evil-define-key nil sly-mrepl-mode-map
- (kbd "C-c ,") 'sly-mrepl-shortcut)
- (sly-symbol-completion-mode -1)
- (setq common-lisp-hyperspec-root
- (concat "file://" (expand-file-name "~/src/clhs/HyperSpec/")))
- (defun my/-hyperspec-loopup-in-eww (oldfun &rest r)
- (let ((browse-url-browser-function #'eww-browse-url))
- (apply oldfun r)))
- (advice-add 'common-lisp-hyperspec :around #'my/-hyperspec-loopup-in-eww)
- (defvar-local my/-sly-fontification-buffer nil
- "The fontification buffer for the current sly buffer.")
- (defun my/-sly-get-fontification-buffer ()
- "Return the sly fontification buffer."
- (if (buffer-live-p my/-sly-fontification-buffer)
- my/-sly-fontification-buffer
- (let ((buffer (generate-new-buffer
- (format " %s-fontification-buffer" (buffer-name)))))
- (with-current-buffer buffer
- (unless (derived-mode-p 'c++-mode)
- (let ((delayed-mode-hooks nil))
- (delay-mode-hooks
- (lisp-mode)
- (rainbow-delimiters-mode 1))))
- (let ((inhibit-message t))
- (indent-tabs-mode -1))
- (unless font-lock-mode
- (font-lock-mode 1)))
- (setq-local my/-sly-fontification-buffer buffer))))
- (defmacro my/-sly-with-font-lock-buffer (&rest body)
- "Execute BODY in the sly indirect buffer.
- Note that this erases the buffer before doing anything."
- `(with-current-buffer (my/-sly-get-fontification-buffer)
- (erase-buffer)
- ,@body))
- (defun my/-sly-fontify-current-input ()
- "Function called from `post-command-hook' to fontify the current input."
- (when-let ((proc (get-buffer-process (current-buffer)))
- (start (process-mark proc))
- (end (point-max))
- (input (buffer-substring-no-properties start end))
- (fontified (my/-sly-with-font-lock-buffer
- (insert input)
- (font-lock-ensure)
- (buffer-string)))
- (len (length fontified))
- (i 0))
- ;; mostly from:
- ;; `python-shell-font-lock-post-command-hook'
- (while (not (= i len))
- (let* ((props (text-properties-at i fontified))
- (change-i (or (next-property-change i fontified)
- len)))
- (when-let ((face (plist-get props 'face)))
- (setf (plist-get props 'face) nil
- (plist-get props 'font-lock-face) face))
- (set-text-properties (+ start i) (+ start change-i) props)
- (setq i change-i)))))
- (defun my/-sly-cleanup-fontification-buffer ()
- (when (buffer-live-p my/-sly-fontification-buffer)
- (kill-buffer my/-sly-fontification-buffer)))
- (defun my/-sly-mrepl-enable-fontification ()
- (setq-local comint-highlight-input nil)
- (add-hook 'post-command-hook #'my/-sly-fontify-current-input
- nil t)
- (add-hook 'kill-buffer-hook #'my/-sly-cleanup-fontification-buffer
- nil t))
- (add-hook 'sly-mrepl-mode-hook #'my/-sly-mrepl-enable-fontification))
- ;; jupyter
- (use-package jupyter
- :hook (jupyter-repl-mode . my/-setup-jupyter-mode)
- :init
- (defun my/-jupyter-dont-use-ts-modes (retval)
- "Prevent `jupyter-kernel-language-mode-properties' from selecting TS modes."
- (cl-destructuring-bind (mode syntax-table) retval
- (if-let (((string-suffix-p "-ts-mode" (symbol-name mode)))
- (non-ts (car (rassq mode major-mode-remap-alist)))
- ((not (string-suffix-p "-ts-mode" (symbol-name non-ts)))))
- (list non-ts
- (if-let ((table-sym (intern-soft (format "%s-syntax-table"
- non-ts))))
- (symbol-value table-sym)
- syntax-table))
- retval)))
- (advice-add 'jupyter-kernel-language-mode-properties
- :filter-return #'my/-jupyter-dont-use-ts-modes)
- :config
- (face-spec-set 'jupyter-repl-traceback
- '((default . (:background unspecified)))
- 'face-override-spec)
- (defun company-doc-buffer (&optional string)
- "Emulate company's `company-doc-buffer'."
- (with-current-buffer (get-buffer-create "*company-documentation*")
- (erase-buffer)
- (fundamental-mode)
- (when string
- (save-excursion
- (insert string)
- (visual-line-mode)))
- (current-buffer)))
- (defun my/-jupyter-kick-use-back-to-cell ()
- "Kick the point out of the invisible read only area at the start of cells."
- (let ((props (text-properties-at (point))))
- (when (and (plist-get props 'invisible)
- (plist-get props 'read-only))
- (forward-char))))
- (defun my/-setup-jupyter-mode ()
- "Setup `jupyter-repl-mode'."
- (display-line-numbers-mode -1)
- (add-hook 'post-command-hook #'my/-jupyter-kick-use-back-to-cell
- nil t))
- (cl-defmethod jupyter-indent-line (&context (jupyter-lang c++))
- (let ((res (syntax-ppss (pos-bol))))
- ;; no paren depth
- (if (zerop (cl-first res))
- (save-excursion
- (back-to-indentation)
- (delete-region (pos-bol) (point)))
- (indent-for-tab-command)))))
- ;; C/C++ and jupyter
- (defvar my/jupyter-extra-language-associations
- '(("c" . "c++")))
- (defun my/-find-jupyter-buffer-for-lang (lang)
- "Find a Jupyter buffer supporint LANG."
- (let ((res (cl-find-if (lambda (buf)
- (with-current-buffer buf
- (and (derived-mode-p 'jupyter-repl-mode)
- jupyter-current-client
- (cl-equalp lang
- (symbol-name
- (jupyter-kernel-language
- jupyter-current-client))))))
- (buffer-list))))
- (when-let (((not res))
- (real (alist-get lang my/jupyter-extra-language-associations nil
- nil #'cl-equalp)))
- (setq res (my/-find-jupyter-buffer-for-lang real)))
- res))
- (defun my/-jupyter-buffer-for-major-mode (&optional mode)
- "Return a Jupyter buffer that can evaluate the code MODE is editing.
- MODE defaults to `major-mode'."
- (when-let ((name (symbol-name (or mode major-mode)))
- ((string-match (rx bos (group (+? any)) (? "-ts") "-mode" eos)
- name)))
- (my/-find-jupyter-buffer-for-lang (match-string 1 name))))
- (defun my/-jupyter-find-proper-buffer ()
- "Find the buffer for `my/jupyter-eval-in-proper-buffer'."
- (if (and (derived-mode-p 'jupyter-repl-mode)
- jupyter-current-client)
- (current-buffer)
- (my/-jupyter-buffer-for-major-mode major-mode)))
- (defun my/jupyter-eval-in-proper-buffer (code &optional no-error)
- "Eval CODE a buffer suitable for `major-mode'.
- If NO-ERROR is non-nil, signal an error if a buffer fails to be found. If the
- current buffer is a Jupyter buffer, just use that."
- (interactive (list (if-let ((buffer (my/-jupyter-find-proper-buffer)))
- (with-current-buffer buffer
- (jupyter-read-expression))
- (user-error "No Jupyter buffer found for mode: %s"
- major-mode))))
- (if-let ((buffer (my/-jupyter-find-proper-buffer)))
- (with-current-buffer buffer
- (let ((jupyter-repl-echo-eval-p t))
- (jupyter-eval-string code)))
- (unless no-error (user-error "No Jupyter buffer found for mode: %s"
- major-mode))))
- (defun my/jupyter-eval-defun ()
- "Eval the defun under point by sending it to a Jupyter repl."
- (interactive)
- (if-let ((code (thing-at-point 'defun)))
- (progn
- (my/jupyter-eval-in-proper-buffer code)
- (message "Evaluated defun"))
- (user-error "Nothing to evaluate under point")))
- (defun my/jupyter-eval-buffer ()
- "Eval the current buffer by sending it to a Jupyter repl."
- (interactive)
- (my/jupyter-eval-in-proper-buffer (buffer-substring-no-properties
- (point-min) (point-max)))
- (message "Evaluated buffer"))
- (defun my/c++-jupyter-eval-region (start end)
- "Send the current buffer between START and END to a Jupyter repl."
- (interactive "r")
- (let ((code (buffer-substring-no-properties start end)))
- (when (string-suffix-p ";" code)
- (setq code (substring code 0 (1- (length code)))))
- (my/jupyter-eval-in-proper-buffer code)
- (message "Evaluated region")))
- (defun my/c++-ts-jupyter-eval-expression ()
- "Eval the expression under point by sending it to a Jupyter repl."
- (interactive nil c-ts-mode c++-ts-mode)
- (save-excursion
- (let ((start (point)))
- (back-to-indentation)
- (unless (> (point) start)
- (goto-char start)))
- (if-let ((thing (treesit-thing-at-point "_" 'nested))
- (code (treesit-node-text thing)))
- (progn
- (when (string-suffix-p ";" code)
- (setq code (substring code 0 (1- (length code)))))
- (my/jupyter-eval-in-proper-buffer code)
- (message "Evaluated: %s" code))
- (user-error "Nothing to evaluate under point"))))
- (defun my/rust-jupyter-eval-region (start end)
- "Send the current buffer between START and END to a Jupyter repl."
- (interactive "r")
- (let ((code (buffer-substring-no-properties start end)))
- (my/jupyter-eval-in-proper-buffer code)
- (message "Evaluated region")))
- (defun my/rust-ts-jupyter-eval-expression ()
- "Eval the expression under point by sending it to a Jupyter repl."
- (interactive nil rust-ts-mode)
- (save-excursion
- (let ((start (point)))
- (back-to-indentation)
- (unless (> (point) start)
- (goto-char start)))
- (if-let ((thing (treesit-thing-at-point "_" 'nested))
- (code (treesit-node-text thing)))
- (progn
- (my/jupyter-eval-in-proper-buffer code)
- (message "Evaluated: %s" code))
- (user-error "Nothing to evaluate under point"))))
- (with-eval-after-load 'c-ts-mode
- (keymap-set c-ts-base-mode-map
- "C-M-x" #'my/jupyter-eval-defun)
- (keymap-set c-ts-base-mode-map
- "C-x C-e" #'my/c++-ts-jupyter-eval-expression)
- (keymap-set c-ts-base-mode-map
- "C-c C-r" #'my/c++-jupyter-eval-region)
- (keymap-set c-ts-base-mode-map
- "C-c C-b" #'my/jupyter-eval-buffer))
- (with-eval-after-load 'rust-ts-mode
- (keymap-set rust-ts-mode-map
- "C-M-x" #'my/jupyter-eval-defun)
- (keymap-set rust-ts-mode-map
- "C-x C-e" #'my/rust-ts-jupyter-eval-expression)
- (keymap-set rust-ts-mode-map
- "C-c C-r" #'my/rust-jupyter-eval-region)
- (keymap-set rust-ts-mode-map
- "C-c C-b" #'my/jupyter-eval-buffer))
- ;; pdf-tools
- (use-package pdf-tools
- :hook (pdf-view-mode . my/setup-pdf-view-mode)
- :init
- (setq pdf-misc-print-program-executable "lp")
- (defun my/setup-pdf-view-mode ()
- (display-line-numbers-mode -1)
- (evil-define-key '(motion normal visual) 'local
- (kbd "C-s") #'isearch-forward
- (kbd "C-r") #'isearch-backward)
- (setq-local cursor-type nil))
- (pdf-tools-install))
- ;; doc view
- (use-package doc-view
- :ensure nil
- :hook (doc-view-mode . my/-setup-doc-view-mode)
- :init
- (defun my/-setup-doc-view-mode ()
- (display-line-numbers-mode -1)
- (evil-define-key '(motion normal visual) 'local
- (kbd "C-s") #'isearch-forward
- (kbd "C-r") #'isearch-backward)))
- ;; calc
- (use-package calc
- :ensure nil
- :bind (("C-c m" . quick-calc)
- :map calc-mode-map
- ("M-<tab>" . calc-roll-up)
- ("M-TAB" . calc-roll-up))
- :hook ((calc-mode calc-trail-mode) . my/setup-calc-calc-trail-mode)
- :init
- (defun my/setup-calc-calc-trail-mode ()
- (setq-local doom-modeline-percent-position '()
- truncate-partial-width-windows nil)
- (visual-line-mode -1)
- (display-line-numbers-mode -1)
- (toggle-truncate-lines 1))
- :config
- (evil-define-key '(normal visual motion) calc-edit-mode-map
- (kbd "RET") 'calc-edit-return
- (kbd "<return>") 'calc-edit-return)
- (defun my/-calc-float-mode-string ()
- (cl-destructuring-bind (mode prec) calc-float-format
- (concat
- (upcase-initials (symbol-name mode))
- (unless (zerop prec)
- (concat ": " (number-to-string prec))))))
- (doom-modeline-def-segment calc
- "Display calculator icons and info."
- (concat
- (doom-modeline-spc)
- (when-let ((icon (doom-modeline-icon 'faicon "nf-fa-calculator" "🖩" "")))
- (concat
- (doom-modeline-display-icon icon)
- (doom-modeline-vspc)))
- (doom-modeline--buffer-simple-name)
- (when (eq major-mode 'calc-mode)
- (concat
- (doom-modeline-spc)
- (number-to-string calc-internal-prec)
- (doom-modeline-spc)
- (upcase-initials (symbol-name calc-angle-mode))
- (doom-modeline-spc)
- (my/-calc-float-mode-string)
- (when calc-prefer-frac
- (concat
- (doom-modeline-spc)
- "Frac"))
- (cond
- (calc-algebraic-mode
- (concat
- (doom-modeline-spc)
- "Alg"))
- (calc-incomplete-algebraic-mode
- (concat
- (doom-modeline-spc)
- "IAlg"))))))))
- ;; sage (for when calc is not enough)
- (use-package sage-shell-mode
- :demand
- :bind ("C-c g" . my/run-sage)
- :hook (sage-shell-mode . my/-setup-sage-shell-mode)
- :init
- (defun my/-setup-sage-shell-mode ()
- (setq-local comint-dynamic-complete-functions
- '(comint-c-a-p-replace-by-expanded-history)))
- :config
- (defun my/run-sage (p)
- "Like `sage-shell:run-sage', but does not ask anything without a prefix
- argument."
- (interactive "P")
- (let ((sage-shell:ask-command-options p))
- (funcall-interactively #'sage-shell:run-sage
- (sage-shell:read-command)))))
- ;; fricas (because I like calculators)
- (add-to-list 'load-path "/usr/lib/fricas/emacs")
- (use-package fricas
- :ensure nil
- :custom
- (fricas-run-command "fricas -nosman")
- :init
- ;; Fix `fricas-mode' messing up `completion-at-point-functions'
- (advice-add #'fricas-mode :around
- #'(lambda (oldfun &rest r)
- (let ((temp-capfs))
- (let ((completion-at-point-functions '(t)))
- (apply oldfun r)
- (setq temp-capfs completion-at-point-functions))
- (setq-local completion-at-point-functions temp-capfs)))
- '((name . "my/-fricas-fix-capfs")))
- :config
- (face-spec-set 'fricas-type-time '((t (:foreground unspecified
- :background unspecified
- :inherit font-lock-type-face))))
- (face-spec-set 'fricas-message '((t (:foreground unspecified
- :background unspecified
- :inherit error))))
- (face-spec-set 'fricas-undefined '((t (:foreground unspecified
- :background unspecified
- :inherit nerd-icons-lblue))))
- (face-spec-set 'fricas-algebra '((t (:foreground unspecified
- :background unspecified
- :weight bold
- :inherit fricas-prompt))))
- (face-spec-set 'fricas-TeX '((t (:foreground "black"
- :background "white"
- :inherit fricas-prompt)))))
- ;; gnuplot (mostly for org-plot)
- (use-package gnuplot)
- ;; eat
- (use-package eat
- :bind (("C-c V" . my/project-eat-or-default)
- :map eat-mode-map
- ("M-o" . ace-window)
- :map eat-semi-char-mode-map
- ("M-o" . ace-window)
- :map eat-eshell-emacs-mode-map
- ("M-o" . ace-window)
- :map eat-eshell-semi-char-mode-map
- ("M-o" . ace-window))
- :init
- (evil-define-key 'insert eat-semi-char-mode-map
- (kbd "<escape>") #'eat-self-input
- (kbd "C-S-n") #'evil-normal-state)
- :config
- ;; The below makes sure that the first time the ESC key is pressed, it does
- ;; what it is supposed to
- (add-hook 'eat--semi-char-mode-hook #'evil-normalize-keymaps)
- (defun my/-evil-disable-cursor-in-eat-buffer (oldfun &rest r)
- "Disable `evil--sw-refresh-cursor' in `eat-mode' buffers."
- (when (or (not (derived-mode-p 'eat-mode))
- (not (eq evil-state 'insert)))
- (apply oldfun r)))
- (advice-add 'evil--sw-refresh-cursor :around
- #'my/-evil-disable-cursor-in-eat-buffer)
- (defun my/-eat-update-cursor-on-tty (&rest r)
- (etcc--evil-set-cursor))
- (advice-add 'eat--set-cursor :after
- #'my/-eat-update-cursor-on-tty)
- (defun my/-eat-disable-evil-in-char-mode ()
- (if eat--char-mode
- (evil-local-mode -1)
- (evil-local-mode 1)))
- (add-hook 'eat--char-mode-hook #'my/-eat-disable-evil-in-char-mode)
- ;; Evil fixes done
- (defvar my/project-eat-hash-table (make-hash-table :test 'equal)
- "Hash table that maps project root dirs to eat buffers.")
- (defun my/-eat-shell-for-cwd ()
- "Return a good shell for CWD, or nil if the default shell should be used."
- (when (file-remote-p default-directory)
- "/bin/sh"))
- (defun my/project-eat (prompt &optional arg)
- "Switch to or create a eat buffer in the current projects root."
- (interactive (list t current-prefix-arg))
- (if-let ((proj (project-current prompt))
- (default-directory (project-root proj)))
- (if-let ((eat-buff (gethash default-directory
- my/project-eat-hash-table))
- ((buffer-live-p eat-buff)))
- (switch-to-buffer eat-buff)
- (let ((eat-buffer-name (concat "*eat for project " default-directory
- "*"))
- (eat-term-name (if (file-remote-p default-directory)
- "xterm-256color"
- eat-term-name)))
- (puthash default-directory
- (eat (my/-eat-shell-for-cwd) arg)
- my/project-eat-hash-table)))))
- (defun my/project-eat-or-default (&optional arg)
- "Open an eat for the current project, otherwise, open a normal eat."
- (interactive "P")
- (unless (my/project-eat nil)
- (if-let ((eat-buff (gethash nil my/project-eat-hash-table))
- ((buffer-live-p eat-buff)))
- (switch-to-buffer eat-buff)
- (puthash nil (let ((eat-term-name (if (file-remote-p default-directory)
- "xterm-256color"
- eat-term-name)))
- (eat (my/-eat-shell-for-cwd) arg))
- my/project-eat-hash-table)))))
- ;; eshell stuff
- (use-package eshell
- :ensure nil
- :defer nil
- :hook ((eshell-load . eat-eshell-visual-command-mode)
- (eshell-mode . eat-eshell-mode)
- (eshell-mode . my/-eshell-mode-setup)
- (eshell-directory-change . my/-eshell-maybe-setup-remote-aliases))
- :bind (:map eshell-mode-map
- ("TAB" . completion-at-point)
- ("<tab>" . completion-at-point))
- :init
- (defun my/-eshell-filter-alias-list ()
- (cl-remove-if-not (lambda (elt)
- (or (string-match-p
- (rx bos
- (or "clear" "find-file"
- "ls" "la" "git"
- (and "eshell/" (+ (not " "))))
- (or " " eos))
- (cl-second elt))))
- eshell-command-aliases-list))
- (defun my/-eshell-maybe-setup-remote-aliases ()
- (if (file-remote-p default-directory)
- (setq-local eshell-command-aliases-list (my/-eshell-filter-alias-list))
- (kill-local-variable 'eshell-command-aliases-list)))
- (defun my/-eshell-mode-setup ()
- "Setup function run from `eshell-mode-hook'"
- (setq-local corfu-auto nil)
- (my/-eshell-maybe-setup-remote-aliases))
- (setq-default eshell-command-aliases-list
- '(("clear" "clear t")
- ("e" "find-file $1")
- ("n" "find-file $1")
- ("emacs" "find-file $1")
- ("nvim" "find-file $1")
- ("ls" "eza --git -F $*")
- ("la" "ls -a $*")
- ("l" "ls -l $*")
- ("ll" "la -l $*")
- ("gt" "git status $*")
- ("gp" "git push $*")
- ("gu" "git pull $*")
- ("gf" "git fetch $*")
- ("ga" "git add $*")
- ("gcm" "git commit -m ${string-join $* \" \"}")
- ("ldg" "ledger -f \"$HOME/docs/finance/finances.ledger\" $*")
- ("tp" "trash-put $*")
- ("trr" "trash-restore $*")
- ("tre" "trash-empty $*")
- ("tre" "trash-empty $*")
- ("trm" "trash-rm $*")
- ("rm" "echo 'rm: I''m unsafe! Don''t use me.'; false")
- ("\\rm" "eshell/rm")))
- (defvar my/eshell-bm-auto-ls t
- "Weather or not to run ls after `eshell/bm'")
- (defun eshell/bm (&optional name)
- "Change to directory of bookmark NAME.
- If no name is given, list all bookmarks instead."
- (if name
- (progn
- (eshell/cd (bookmark-get-filename name))
- (when my/eshell-bm-auto-ls
- (eshell/ls)))
- (eshell-print (string-join (bookmark-all-names) " ")))))
- (use-package esh-help
- :hook (eshell-mode . my/-setup-eshell-help-func)
- :init
- (defun my/-setup-eshell-help-func ()
- (eldoc-mode 1)
- (setq-local evil-lookup-func #'esh-help-run-help))
- (setup-esh-help-eldoc))
- (use-package eshell-syntax-highlighting
- :init
- (eshell-syntax-highlighting-global-mode 1))
- (use-package eshell-starship
- :ensure nil
- :demand t
- :hook (eshell-prompt-mode . eshell-starship-prompt-mode)
- :config
- (eshell-starship-setup-evil-keybindings)
- (set-face-attribute 'eshell-starship-icon-face nil
- :family "FiraCode Nerd Font"))
- (defun my/open-shell-dwim (&optional arg)
- "Open either an Eshell or eat terminal based on `default-directory'.
- If `default-directory' is remote, call `my/project-eat-or-default'. Otherwise,
- call `my/project-eshell-or-default'. ARG is the same as for either of the above
- functions (only eshell uses it at the time of writing)."
- (interactive "P")
- (if (file-remote-p default-directory)
- (my/project-eat-or-default)
- (my/project-eshell-or-default arg)))
- (keymap-global-set "C-c v" #'my/open-shell-dwim)
- ;; proced
- (use-package proced
- :bind ("C-x j" . proced)
- :init
- (evil-define-key '(motion visual normal) proced-mode-map
- "u" 'proced-unmark)
- (setq proced-auto-update-flag t
- proced-auto-update-interval 1)
- (defun my/-setup-proced-mode ()
- (visual-line-mode -1)
- (setq-local truncate-lines t))
- (add-hook 'proced-mode-hook 'my/-setup-proced-mode))
- ;; dired
- (use-package dired
- :ensure nil
- :custom
- (dired-listing-switches
- "-l --almost-all --human-readable --group-directories-first --no-group")
- (dired-hide-details-hide-symlink-targets nil)
- :init
- (setq-default dired-kill-when-opening-new-dired-buffer t)
- (setq delete-by-moving-to-trash t
- dired-recursive-copies 'always
- dired-recursive-deletes 'always
- dired-dwim-target t
- dired-create-destination-dirs 'ask
- dired-create-destination-dirs-on-trailing-dirsep t
- dired-isearch-filenames 'dwim
- dired-do-revert-buffer (lambda (dir)
- (not (file-remote-p dir)))
- dired-clean-up-buffers-too t
- dired-clean-confirm-killing-deleted-buffers t)
- (evil-define-key '(normal visual motion) dired-mode-map
- "u" #'dired-unmark
- "U" #'dired-unmark-all-marks))
- ;; dirvish
- (use-package dirvish
- :defer nil
- :bind (("C-c b" . dirvish-quick-access)
- :map dirvish-mode-map
- ("<mouse-1>" . dirvish-subtree-toggle-or-open)
- ("<mouse-2>" . dired-mouse-find-file-other-window)
- ("<mouse-3>" . dired-mouse-find-file))
- :hook (((dirvish-directory-view-mode dired-mode dirvish-mode) .
- my/-setup-dirvish-lines)
- ;; ((dirvish-directory-view-mode dired-mode dirvish-mode) .
- ;; auto-revert-mode)
- ((dirvish-mode dired-mode) . my/-setup-dirvish-mouse))
- :custom
- (dirvish-subtree-always-show-state t)
- (dirvish-reuse-session t)
- (dirvish-quick-access-function 'dired)
- :init
- (defun my/-setup-dirvish-lines ()
- (setq-local truncate-lines t))
- (defun my/-setup-dirvish-mouse ()
- (setq-local mouse-1-click-follows-link nil
- mouse-1-click-in-non-selected-windows nil))
- (defvar my/-dirvish-base-quick-access-entries
- `(("h" "~/" "Home")
- ("d" "~/downloads/" "Downloads")
- ("e" ,user-emacs-directory "Emacs user directory")
- ("z" "~/.config/zsh/" "Zsh user directory")
- ("o" "~/docs/" "Documents")
- ("w." "~/workspace/" "Workspace")))
- (defun my/-dirvish-build-quick-access-entries (bookmarks)
- ;; NOTE called from a variable watcher for `bookmark-alist' and so must
- ;; never set that variable
- (let (out)
- (dolist (bme bookmarks
- (append my/-dirvish-base-quick-access-entries
- (sort out
- (lambda (elt1 elt2)
- (string< (car elt1) (car elt2))))))
- (let ((name (car bme)))
- (let-alist (cdr bme)
- (when (and (file-directory-p .filename)
- (string-match (rx bos (group (any "a-z" "A-Z")) "ws" eos)
- name))
- (setf (alist-get (concat "w" (match-string 1 name)) out
- nil nil 'equal)
- (list .filename
- (concat
- (capitalize
- (car (last (string-split .filename "/" t))))
- " Workspace")))))))))
- :config
- (require 'dirvish-extras)
- (defun my/-dirvish-bookmark-alist-watcher (_sym newval oper where)
- (when (and (not where) (memq oper '(set makunbound defvaralias)))
- (setopt dirvish-quick-access-entries
- (my/-dirvish-build-quick-access-entries newval))))
- (add-variable-watcher 'bookmark-alist #'my/-dirvish-bookmark-alist-watcher)
- (defvar-local my/-dirvish-uid-name-cache nil
- "Cons of path and a hash table mapping user ids to their names.")
- (dirvish-define-attribute file-owner-mode
- "The file's owner and mode."
- :index 2
- :when (and (dirvish-prop :root) dired-hide-details-mode
- (> win-width 60))
- (let ((root (dirvish-prop :root))
- (uid (file-attribute-user-id f-attrs)))
- (unless (or (dirvish-prop :remote) (stringp uid))
- (unless (and (equal root (car my/-dirvish-uid-name-cache))
- (hash-table-p (cdr my/-dirvish-uid-name-cache)))
- (setq my/-dirvish-uid-name-cache
- (cons root (make-hash-table :test 'equal))))
- (if-let ((name (gethash uid (cdr my/-dirvish-uid-name-cache))))
- (setq uid name)
- (let* ((new-attrs (file-attributes f-name 'string))
- (new-name (file-attribute-user-id new-attrs)))
- (puthash uid new-name
- (cdr my/-dirvish-uid-name-cache))
- (setq uid new-name))))
- (cons 'right (propertize (format " %s %s" uid (file-attribute-modes f-attrs))
- 'face (or hl-face 'dirvish-file-time)))))
- (let ((cur-val dirvish-ui-setup-items))
- (cl-pushnew '("o" file-owner-mode "File owner and mode")
- cur-val :test 'equal)
- (setopt dirvish-ui-setup-items cur-val))
- (add-to-list 'dirvish-libraries '(dirvish file-owner-mode))
- (setopt dirvish-attributes
- '(vc-state subtree-state nerd-icons file-size file-owner-mode))
- (evil-define-key 'normal dirvish-mode-map
- (kbd "q") #'dirvish-quit
- (kbd "a") #'dirvish-quick-access
- (kbd "f") #'dirvish-file-info-menu
- (kbd "y") #'dirvish-yank-menu
- (kbd "N") #'dirvish-narrow
- (kbd "^") #'dirvish-history-last
- (kbd "h") #'dirvish-history-jump
- (kbd "s") #'dirvish-quicksort
- (kbd "o") #'dirvish-quicksort
- (kbd "v") #'dirvish-vc-menu
- (kbd "TAB") #'dirvish-subtree-toggle
- (kbd "M-f") #'dirvish-history-go-forward
- (kbd "M-b") #'dirvish-history-go-backward
- (kbd "M-l") #'dirvish-history-go-forward
- (kbd "M-h") #'dirvish-history-go-backward
- (kbd "M-l") #'dirvish-ls-switches-menu
- (kbd "M-m") #'dirvish-mark-menu
- (kbd "M-t") #'dirvish-layout-toggle
- (kbd "M-s") #'dirvish-setup-menu
- (kbd "M-e") #'dirvish-emerge-menu
- (kbd "M-j") #'dirvish-fd-jump
- (kbd "/") #'dirvish-fd
- (kbd "?") #'dirvish-dispatch)
- (dirvish-override-dired-mode)
- (dirvish-define-preview eza (file)
- "Use `eza' to generate directory preview."
- :require ("eza")
- (when (file-directory-p file)
- `(shell . ("eza" "-la" "--color=always" "--icons"
- "--group-directories-first" ,file))))
- (add-to-list 'dirvish-preview-dispatchers 'eza))
- ;; ibuffer
- (use-package ibuffer
- :bind ("C-x C-b" . ibuffer))
- ;; magit
- (use-package magit
- :init
- (defvar-keymap my/magit-personal-prefix-map
- :doc "Keymap for some useful Magit commands."
- "s" #'magit-stage
- "d" #'magit-diff-dwim
- "D" #'magit-diff
- "b" #'magit-blame)
- (keymap-global-set "C-c i" my/magit-personal-prefix-map)
- (evil-define-key '(normal visual motion) magit-mode-map
- "s" #'magit-stage-file
- "S" #'magit-stage-modified))
- (use-package forge
- :custom
- (forge-add-default-bindings nil)
- :config
- (add-to-list 'forge-alist '("git.zander.im" "git.zander.im/api/v1"
- "git.zander.im" forge-gitea-repository)))
- ;; org-mode
- (use-package org
- :pin gnu
- :bind (("C-c c" . org-capture)
- ("C-c a" . org-agenda)
- ("C-c l" . org-store-link)
- :map org-mode-map
- ("C-c t" . org-table-create))
- :hook (org-mode . org-table-header-line-mode)
- :init
- (font-lock-add-keywords 'org-mode
- `((,(rx bol (* " ") (group "-") " ")
- (0 (prog1 nil
- (compose-region (match-beginning 1)
- (match-end 1) "•"))))))
- (setq org-directory "~/org"
- org-agenda-files '("~/org/")
- org-log-into-drawer t
- org-log-done 'time
- org-log-redeadline 'time
- org-log-reschedule 'time
- org-preview-latex-default-process 'dvisvgm
- org-highlight-latex-and-related '(native entities)
- org-startup-with-inline-images t
- org-adapt-indentation t
- org-hide-leading-stars t
- org-html-with-latex 'dvisvgm
- org-preview-latex-process-alist
- '((dvisvgm
- :image-input-type "dvi"
- :image-output-type "svg"
- :image-size-adjust (1.7 . 1.5)
- :latex-compiler ("pdflatex -interaction nonstopmode -output-format=dvi -output-directory=%o %f")
- :image-converter ("dvisvgm %o%b.dvi --no-fonts --exact-bbox --scale=%S --output=%O"))))
- (defun my/-org-allow-in-derived-mode (oldfun &rest r)
- "Allow OLDFUN to run, even if `major-mode' is only derived from `org-mode'.
- R is rest of the arguments to OLDFUN."
- (let ((major-mode (if (derived-mode-p 'org-mode)
- 'org-mode
- major-mode)))
- (apply oldfun r)))
- (advice-add 'org-element-at-point :around 'my/-org-allow-in-derived-mode)
- (advice-add 'org-table-header-line-mode :around 'my/-org-allow-in-derived-mode))
- (use-package evil-org
- :after org
- :hook (org-mode . evil-org-mode)
- :init
- (require 'evil-org-agenda)
- (evil-org-agenda-set-keys))
- ;; ledger
- (use-package ledger-mode)
- (use-package flycheck-ledger
- :hook (ledger-mode . trusted-files-flycheck-mode-if-safe))
- ;; khard contacts
- (require 'khard)
- ;; This is also in khard (see above), it's just also here so that if I remove
- ;; that file ever, other things will not break.
- (defun my/message-in-header-p (name &optional testfn)
- "If in field NAME, return the start of the header, otherwise, return nil.
- The name is compared with the field name using TESTFN (defaults to `equal')."
- (save-excursion
- (when (and (message-point-in-header-p)
- (message-beginning-of-header t))
- (beginning-of-line)
- (when (and (looking-at (rx bol (group (+? any)) ":" (? " ")))
- (funcall (or testfn 'equal) (match-string 1) name))
- (match-end 0)))))
- ;; mu4e
- (use-package mu4e
- :ensure nil
- :defer nil
- :hook ((mu4e-index-updated . my/-mu4e-enable-index-messages)
- (mu4e-main-mode . my/-mu4e-setup-main-mode)
- (mu4e-view-mode . my/-mu4e-setup-view-mode)
- (mu4e-compose-mode . my/-mu4e-setup-compose-mode))
- :bind (("C-x C-m" . mu4e)
- :map message-mode-map
- ("C-c k" . khard-insert-email-contact)
- :map mu4e-headers-mode-map
- ([remap mu4e-headers-mark-for-trash] .
- my/mu4e-headers-mark-for-trash)
- :map mu4e-view-mode-map
- ([remap mu4e-view-mark-for-trash] .
- my/mu4e-view-mark-for-trash))
- :init
- (require 'mu4e)
- (evil-define-key '(normal motion) mu4e-main-mode-map "q" #'bury-buffer)
- (evil-define-key '(normal motion) mu4e-view-mode-map "gy" #'mu4e-view-save-url)
- (defun my/-mu4e-setup-view-mode ()
- (setq-local global-hl-line-mode nil))
- (defun my/-mu4e-setup-main-mode ()
- (setq-local default-directory "~/"))
- (defun my/-mu4e-enable-index-messages ()
- (setq mu4e-hide-index-messages nil))
- (defun my/mu4e-update-mail-and-index-silent ()
- "Run `mu4e-update-mail-and-index' without any messages in the background."
- (setq mu4e-hide-index-messages t)
- (mu4e-update-mail-and-index t))
- (defun my/mu4e-headers-mark-for-trash ()
- "Move the message a point to the trash without marking it was deleted
- (trashed)."
- (interactive)
- (when (mu4e-thread-message-folded-p)
- (mu4e-warn "Cannot mark folded messages"))
- (mu4e-mark-at-point 'move mu4e-trash-folder)
- (when mu4e-headers-advance-after-mark
- (mu4e-headers-next)))
- (defun my/mu4e-view-mark-for-trash ()
- "Like `my/mu4e-headers-mark-for-trash', but for `mu4e-view-mode'."
- (interactive)
- (mu4e--view-in-headers-context
- (my/mu4e-headers-mark-for-trash)))
- (defun my/-mu4e-enable-autocomplete-in-header ()
- ;; corfu auto must be t (not the integer returned by
- ;; `my/message-in-header-p'
- (setq-local corfu-auto (and (not (window-minibuffer-p))
- (my/message-in-header-p "To")
- t)))
- (defun my/-mu4e-setup-compose-mode ()
- (add-hook 'post-command-hook 'my/-mu4e-enable-autocomplete-in-header
- nil t)
- (add-to-list
- (make-local-variable 'completion-at-point-functions)
- (cape-capf-super #'mu4e-complete-contact #'khard-message-mode-capf)))
- (defun my/-mu4e-fix-cycle-threshold ()
- (setq-local completion-cycle-threshold nil))
- (advice-add 'mu4e--compose-setup-completion :after
- 'my/-mu4e-fix-cycle-threshold)
- (defvar my/mu4e-interesting-mail-query
- (concat "flag:unread AND NOT flag:trashed AND NOT "
- "maildir:/protonmail/Trash AND NOT maildir:/protonmail/Spam")
- "Flag for mail which will appear as \"unread\" and will be notified.")
- (setq message-kill-buffer-on-exit t
- message-confirm-send t
- message-send-mail-function 'sendmail-send-it
- mu4e-change-filenames-when-moving t
- mu4e-context-policy 'pick-first
- mu4e-attachment-dir "~/downloads/"
- mu4e-last-update-buffer " *mu4e-last-update*"
- mu4e-index-update-error-warning nil
- mu4e-get-mail-command "mbsync protonmail"
- mu4e-completing-read-function #'completing-read-default
- mu4e-compose-context-policy 'ask-if-none
- mu4e-contexts
- (list (make-mu4e-context
- :name "Personal"
- :match-func (lambda (msg)
- (when msg
- (string-match-p "^/protonmail/"
- (mu4e-message-field msg
- :maildir))))
- :vars `((user-mail-address . ,(my/get-private 'mu4e-email))
- (user-full-name . ,(my/get-private 'mu4e-name))
- (message-signature . nil)
- (mu4e-refile-folder . "/protonmail/Archive")
- (mu4e-sent-folder . "/protonmail/Sent")
- (mu4e-drafts-folder . "/protonmail/Drafts")
- (mu4e-trash-folder . "/protonmail/Trash")
- (mu4e-bookmarks
- . ((:name "Inbox"
- :query "maildir:/protonmail/Inbox"
- :key ?i)
- (:name "Unread"
- :query ,my/mu4e-interesting-mail-query
- :key ?u))))))))
- (use-package mu4e-alert
- :after mu4e
- :hook (after-init . mu4e-alert-enable-notifications)
- :init
- (setq mu4e-alert-set-window-urgency nil
- mu4e-alert-interesting-mail-query my/mu4e-interesting-mail-query)
- :config
- (mu4e-alert-set-default-style 'libnotify))
- (mu4e t)
- (mu4e-context-switch nil "Personal")
- ;; refresh the eww message count
- (defun my/-mu4e-eww-refresh-unread-count ()
- "Refresh the eww unread message count."
- (my/eww-poll-variables "mu4e"))
- (add-hook 'mu4e-message-changed-hook #'my/-mu4e-eww-refresh-unread-count)
- ;; mu4e compose HTML messages
- (use-package org-mime)
- (require 'org-mu4e-compose)
- (setq ;; mail-user-agent 'org-mu4e-user-agent
- org-mime-org-html-with-latex-default 'dvisvgm
- org-mime-export-options '(:with-latex dvisvgm :with-footnotes t))
- ;; (evil-define-key '(normal visual) org-mu4e-compose-mode-map
- ;; "G" #'mu4e-compose-goto-bottom
- ;; "gg" #'mu4e-compose-goto-top)
- ;; (evil-define-key 'normal org-mu4e-compose-mode-map
- ;; "ZZ" #'message-send-and-exit
- ;; "ZD" #'message-dont-send
- ;; "ZQ" #'message-kill-buffer
- ;; "ZF" #'mml-attach-file)
- ;; (evil-define-key 'normal mu4e-view-mode-map
- ;; "R" 'org-mu4e-compose-reply
- ;; "cr" 'org-mu4e-compose-reply)
- ;; (evil-define-key 'normal mu4e-headers-mode-map
- ;; "R" 'org-mu4e-compose-reply
- ;; "cr" 'org-mu4e-compose-reply)
- ;; (defun my/-setup-org-mu4e-compose-mode ()
- ;; "Setup up stuff in `org-mu4e-compose' buffers."
- ;; (setq-local ltex-eglot-variable-save-method 'file)
- ;; ;; this should come last so it can pick up the above
- ;; ;; (trusted-files-eglot-ensure-if-safe)
- ;; )
- ;; (add-hook 'org-mu4e-compose-mode-hook #'my/-setup-org-mu4e-compose-mode)
- ;; elfeed
- (use-package elfeed
- :bind (("C-c d" . elfeed))
- :custom
- (elfeed-feeds
- '(("https://archlinux.org/feeds/news/" linux arch)
- ("https://9to5linux.com/feed/atom" linux news)))
- :config
- (setq elfeed-log-buffer-name " *elfeed-log*")
- (evil-define-key '(normal motion) elfeed-search-mode-map
- "r" #'elfeed-search-fetch)
- (elfeed-db-load))
- ;; helpful
- (use-package helpful
- :hook ((emacs-lisp-mode . my/-helpful-setup-emacs-lisp-mode)
- (helpful-mode . my/-setup-helpful-mode))
- :bind (:map help-map
- ("f" . helpful-callable)
- ("v" . helpful-variable)
- ("k" . helpful-key)
- ("o" . helpful-symbol)
- ("x" . helpful-command)
- ("F" . helpful-function)
- :map helpful-mode-map
- ("<mouse-8>" . my/helpful-history-back)
- ("<mouse-9>" . my/helpful-history-forward)
- ("<normal-state><" . my/helpful-history-back)
- ("<normal-state>>" . my/helpful-history-forward))
- :init
- (defun my/-helpful-setup-emacs-lisp-mode ()
- (setq-local evil-lookup-func #'helpful-at-point))
- (defun my/-setup-helpful-mode ()
- (setq-local evil-lookup-func #'helpful-at-point
- tab-width 8))
- (defvar my/helpful-symbol-history-size 50
- "Max size of `my/helpful-symbol-history'.")
- (defvar my/helpful-symbol-history '()
- "History of helpful symbols.")
- (defvar my/-helpful-inhibit-history nil
- "If non-nil, don't add symbols to `my/helpful-symbol-history'.")
- (defvar my/-helpful-last-entry nil
- "Last entry looked up with helpful.")
- (defun my/helpful-history-back (count)
- "Go back COUNT symbols in `my/helpful-symbol-history'. If called
- interactively, COUNT defaults to 1."
- (interactive "p")
- (my/helpful-history-forward (- count)))
- (defun my/helpful-history-forward (count)
- "Move COUNT symbols in `my/helpful-symbol-history'. If COUNT is negative,
- move back. If COUNT is larger than the history, go to the newest entry. Go to
- the oldest entry if -COUNT is larger than the history."
- (interactive "p")
- (when helpful--sym
- (let* ((hist-len (length my/helpful-symbol-history))
- (current-pos (seq-position my/helpful-symbol-history
- (cons helpful--sym
- helpful--callable-p)
- 'equal))
- (new-pos (- current-pos count)))
- (cond
- ;; if already at the newest element, signal an error
- ((and (> count 0) (= current-pos 0))
- (message "%s" "No newer symbol!"))
- ;; if already at the oldest element, signal an error
- ((and (< count 0) (= (1+ current-pos) hist-len))
- (message "%s" "No older symbol!"))
- (t
- (let ((my/-helpful-inhibit-history t)
- (entry (cond
- ((<= new-pos 0)
- (seq-first my/helpful-symbol-history))
- ((>= new-pos hist-len)
- (car (last my/helpful-symbol-history)))
- (t
- (nth new-pos my/helpful-symbol-history)))))
- (if (cdr entry)
- (helpful-callable (car entry))
- (helpful-variable (car entry)))))))))
- (defun my/-helpful-switch-buffer-function (helpful-buf)
- "Like `pop-to-buffer', but kill previous helpful buffers and save the new
- buffers `helpful--sym' to `my/helpful-symbol-history'."
- (cl-loop with window = nil
- for buf in (buffer-list)
- when (and
- (not (eq buf helpful-buf))
- (eq (buffer-local-value 'major-mode buf) 'helpful-mode))
- do
- (when-let (cur-window (get-buffer-window buf nil))
- (setq window cur-window))
- (kill-buffer buf)
- finally
- (let ((entry (cons (buffer-local-value 'helpful--sym helpful-buf)
- (buffer-local-value 'helpful--callable-p
- helpful-buf))))
- (unless my/-helpful-inhibit-history
- (when-let (from-current-hist
- (member my/-helpful-last-entry
- my/helpful-symbol-history))
- (setq my/helpful-symbol-history from-current-hist))
- (cl-pushnew entry my/helpful-symbol-history :test 'equal)
- (setq my/helpful-symbol-history
- (seq-take my/helpful-symbol-history
- my/helpful-symbol-history-size)))
- (setq my/-helpful-last-entry entry))
- (if window
- (window--display-buffer helpful-buf window 'reuse)
- (pop-to-buffer helpful-buf))))
- (setq helpful-switch-buffer-function 'my/-helpful-switch-buffer-function
- helpful-max-buffers 2))
- ;; useful for debugging
- (defun my/describe-symbol-plist (symbol)
- "Descrive the plist of SYMBOL in a buffer."
- (interactive (list (intern (completing-read
- "Symbol: "
- (let ((syms))
- (mapatoms (##push (symbol-name %) syms))
- syms)
- nil t))))
- (with-current-buffer (get-buffer-create "*describe-symbol-plist*")
- (unless (derived-mode-p 'special-mode)
- (special-mode))
- (let ((inhibit-read-only t)
- (keys)
- (values))
- (map-do (lambda (k v)
- (push k keys)
- (push v values))
- (symbol-plist symbol))
- (setq keys (nreverse keys)
- values (nreverse values))
- (erase-buffer)
- (insert (propertize "Plist of "
- 'face 'shortdoc-heading))
- (insert (propertize (format "%S" symbol)
- 'face '((:weight normal) shortdoc-heading)))
- (insert "\n\n")
- (with-temp-buffer
- (let ((delayed-mode-hooks nil))
- (delay-mode-hooks
- (lisp-mode))
- (font-lock-mode)
- (show-paren-mode)
- (when (fboundp 'rainbow-delimiters-mode)
- (rainbow-delimiters-mode)))
- (let ((pp-max-width fill-column)
- (pp-use-max-width t))
- (setq values (mapcar (lambda (val)
- (erase-buffer)
- (pp val (current-buffer))
- (font-lock-ensure)
- (buffer-string))
- values))))
- (goto-char (point-max))
- (cl-loop for key in keys
- for value in values
- do
- (insert (propertize (prin1-to-string key)
- 'face 'bold))
- (insert "\n")
- (insert value)
- (insert "\n"))
- (delete-char -1))
- (pop-to-buffer (current-buffer))))
- (defun my/greyify-color (color percent &optional frame)
- "Make COLOR closer to black by PERCENT on FRAME.
- Color can be any color which can be passed to `color-values'."
- (cl-destructuring-bind (&optional r g b)
- (color-name-to-rgb color frame)
- (when (and r g b)
- (let ((scale (- 1.0 (/ percent 100.0))))
- (color-rgb-to-hex (* r scale)
- (* g scale)
- (* b scale))))))
- ;; rainbow-delimiters
- (use-package rainbow-delimiters
- :hook (prog-mode . rainbow-delimiters-mode)
- :config
- ;; generate dark version of the rainbow delimiters faces
- (defun my/-rainbow-delimiters-recalc-dark-faces (&optional frame)
- (unless frame (setq frame (selected-frame)))
- (dotimes (i 9)
- (when-let ((old-face (intern-soft
- (format "rainbow-delimiters-depth-%d-face"
- (1+ i))))
- (new-face
- (intern
- (format "my/rainbow-delimiters-depth-%d-dark-face"
- (1+ i))))
- (old-color (face-attribute old-face :foreground frame))
- (new-color (my/greyify-color old-color 50 frame)))
- (set-face-attribute new-face frame :foreground new-color))))
- (add-hook 'after-make-frame-functions
- #'my/-rainbow-delimiters-recalc-dark-faces)
- (add-hook 'server-after-make-frame-hook
- #'my/-rainbow-delimiters-recalc-dark-faces)
- (defun my/rainbow-delimiters-parinfer-pick-face (depth match loc)
- "Version of `rainbow-delimiters-default-pick-face' that colors closing
- parenthesis darker than opening ones. This function defers to
- `rainbow-delimiters-default-pick-face' and just changes the output if it returns
- one of the normal rainbow-delimiters-depth-N-face faces."
- (save-match-data
- (let* ((base-face (rainbow-delimiters-default-pick-face depth match loc))
- (base-name (symbol-name base-face)))
- (if (and evil-cleverparens-mode
- (eq ?\) (char-syntax
- (elt (buffer-substring-no-properties loc (1+ loc)) 0)))
- (string-match (rx string-start "rainbow-delimiters-depth-"
- (group (+ num))
- "-face" string-end)
- base-name))
- (or (intern-soft (format "my/rainbow-delimiters-depth-%s-dark-face"
- (match-string 1 base-name)))
- base-face)
- base-face))))
- (setopt rainbow-delimiters-pick-face-function
- 'my/rainbow-delimiters-parinfer-pick-face))
- ;; make regexp look nicer
- (use-package easy-escape
- :hook ((emacs-lisp-mode reb-mode) . easy-escape-minor-mode)
- :config
- (face-spec-set 'easy-escape-face
- '((t (:foreground unspecified
- :weight bold
- :inherit 'font-lock-regexp-grouping-backslash)))))
- ;; auto-highlight-symbol
- (use-package auto-highlight-symbol
- :hook (lisp-data-mode . auto-highlight-symbol-mode)
- :init
- (setq ahs-face 'bold
- ahs-face-unfocused 'bold
- ahs-definition-face 'bold
- ahs-definition-face-unfocused 'bold
- ahs-plugin-default-face 'bold
- ahs-plugin-default-face-unfocused 'bold)
- :config
- (keymap-unset auto-highlight-symbol-mode-map "C-x C-a" t))
- ;; Theme (doom-themes)
- (use-package doom-themes
- :config
- (load-theme 'doom-molokai t)
- (doom-themes-org-config))
- ;; solaire-mode
- (use-package solaire-mode
- :config
- (solaire-global-mode 1))
- ;; Highlight todos
- (use-package hl-todo
- :hook (prog-mode . hl-todo-mode))
- (use-package magit-todos
- :after (hl-todo magit)
- :config
- (magit-todos-mode 1))
- ;; icons
- (use-package nerd-icons)
- (use-package nerd-icons-completion
- :config
- (nerd-icons-completion-mode))
- (use-package nerd-icons-dired
- :hook (dired-mode . my/-maybe-enable-nerd-icons-dired)
- :init
- (defun my/-maybe-enable-nerd-icons-dired ()
- (unless (bound-and-true-p dirvish-override-dired-mode)
- (nerd-icons-dired-mode))))
- (use-package kind-icon
- :after corfu
- :init
- (setq kind-icon-default-face 'corfu-default
- kind-icon-default-style
- '(:padding -1 :stroke 0 :margin 0 :radius 0 :height 0.5 :scale 1))
- :config
- (add-to-list 'corfu-margin-formatters #'kind-icon-margin-formatter))
- ;; modeline (doom-modeline)
- (use-package doom-modeline
- :init
- (setq doom-modeline-support-imenu t)
- (doom-modeline-mode 1))
- ;; dashboard.el
- (use-package dashboard
- :config
- (defvar-local my/-dashboard-did-fix-image nil
- "Weather or not the dashboard image has been fixed in this buffer.")
- (defun my/-dashboard-fix-image ()
- (unless my/-dashboard-did-fix-image
- (dashboard-refresh-buffer)
- (setq my/-dashboard-did-fix-image t)))
- (defun my/-dashboard-setup-function ()
- (add-hook 'window-configuration-change-hook 'my/-dashboard-fix-image nil t)
- (setq-local display-line-numbers nil))
- (add-hook 'dashboard-mode-hook 'my/-dashboard-setup-function)
- (set-face-background 'dashboard-banner-logo-title nil)
- (dashboard-setup-startup-hook)
- (setq initial-buffer-choice (lambda () (get-buffer-create "*dashboard*"))
- dashboard-force-refresh t
- dashboard-display-icons-p t
- dashboard-icon-type 'nerd-icons
- dashboard-set-file-icons t
- dashboard-projects-backend 'project-el
- dashboard-items '((recents . 5)
- (projects . 5)
- (bookmarks . 5))))
- ;; world clocks
- (setq zoneinfo-style-world-list
- '(("America/Los_Angeles" "California")
- ("Asia/Tokyo" "Tokyo")
- ("America/New_York" "New York")
- ("Europe/London" "London")
- ("Europe/Paris" "Paris")
- ("Asia/Calcutta" "Bangalore")))
- ;; page break lines
- (use-package page-break-lines
- :config
- (global-page-break-lines-mode 1)
- (add-to-list 'page-break-lines-modes 'prog-mode)
- (add-to-list 'page-break-lines-modes 'text-mode)
- (add-to-list 'page-break-lines-modes 'helpful-mode))
- ;; fun!
- (use-package mines)
- ;;; init.el ends here
|