12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536 |
- ;;; 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
- :defer nil
- :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)
- ;; Load the local system's configuration
- (load (expand-file-name "local-init" user-emacs-directory) 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)
- ((tex-mode prog-mode) . kill-ring-deindent-mode))
- :init
- (with-eval-after-load 'find-func
- (when (and (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))))
- ;; Trusted buffer stuff
- (defun my/temp-trust-buffer ()
- "Set the current buffers local value of `trusted-content' to \\=:all."
- (interactive)
- (setq-local trusted-content :all)
- (cond
- ((and (buffer-modified-p) (y-or-n-p "Save and reload buffer?"))
- (save-buffer)
- (revert-buffer-quick))
- ((y-or-n-p "Revert buffer?")
- (revert-buffer-quick))))
- (put 'trusted-content 'permanent-local t)
- (defun my/-trusted-content-segment ()
- (when (and (derived-mode-p 'prog-mode)
- (not buffer-read-only))
- (cond
- ((and (local-variable-p 'trusted-content)
- (equal trusted-content :all)
- buffer-file-name)
- (propertize "[Temp. Trusted]" 'face 'warning))
- ((not (trusted-content-p))
- (propertize "[Untrusted]" 'face 'error)))))
- (add-to-list 'mode-line-misc-info
- '(:eval (my/-trusted-content-segment)))
- (defun my/-fix-trusted-content-p-for-remote (oldfun &rest args)
- (let ((source (or buffer-file-truename default-directory)))
- (if (not source)
- (apply oldfun args)
- (let* ((method (file-remote-p source 'method))
- (host (file-remote-p source 'host))
- (trusted-content (cl-remove-if-not
- (llama and (equal method (file-remote-p % 'method))
- (equal host (file-remote-p % 'host)))
- trusted-content)))
- (apply oldfun args)))))
- (advice-add 'trusted-content-p :around
- #'my/-fix-trusted-content-p-for-remote)
- ;; Increase responsiveness
- (setq gc-cons-threshold 80000000
- inhibit-compacting-font-caches t
- 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)
- ;; Better line wrapping
- (global-visual-wrap-prefix-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")))
- (setopt remote-file-name-access-timeout 10)
- (use-package tramp
- :ensure nil
- :custom
- (tramp-file-name-with-method "doas")
- :config
- ;; (connection-local-set-profile-variables
- ;; 'direct-async
- ;; '((tramp-direct-async-process . t)))
- (connection-local-set-profile-variables
- 'error-only
- '((tramp-verbose . 1)))
- (connection-local-set-profile-variables
- 'enable-dir-locals
- '((enable-remote-dir-locals . t)))
- (connection-local-set-profile-variables
- 'apheleia-remote-local
- '((apheleia-remote-algorithm . local)))
- (dolist (method '("podman" "docker" "ssh" "sshx" "sudo" "su" "doas"
- "sudoedit" "run0" "kubernetes" "dockercp" "podmancp"
- "distrobox" "toolbox" "flatpak" "apptainer" "nspawn"))
- (let ((inhibit-message t)
- (message-log-max nil))
- (tramp-enable-method (intern method)))
- (connection-local-set-profiles
- `(:method ,method)
- ;; 'direct-async
- 'error-only 'enable-dir-locals
- 'apheleia-remote-local)))
- (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")
- (default-directory "~"))
- (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 (derived-mode-p 'lisp-data-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))
- ;; better lisp editing
- (use-package adjust-parens
- :hook (lisp-data-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))
- :init
- (let ((val minibuffer-regexp-prompts))
- (cl-pushnew "Replace" val :test 'equal)
- (setopt minibuffer-regexp-prompts val)))
- ;; 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))
- (use-package completion-preview
- :ensure nil
- :defer nil
- ;; adjust parens can shadow this if it is not bound to <tab>
- :bind (:map completion-preview-active-mode-map
- ("<tab>" . #'completion-preview-insert))
- :config
- (global-completion-preview-mode 1))
- ;; 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 nil
- 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)
- :custom
- (flymake-indicator-type 'margins))
- ;; flycheck
- (use-package flycheck
- :hook ((sh-mode emacs-lisp-mode) . my/flycheck-if-trusted)
- :custom
- (flycheck-indication-mode 'left-margin)
- :init
- (setq flycheck-display-errors-function nil)
- (defun my/flycheck-if-trusted ()
- (when (trusted-content-p)
- (flycheck-mode))))
- (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)
- ;; (eglot-ensure)))
- (defun my/eglot-if-trusted ()
- (when (trusted-content-p)
- (eglot-ensure)))
- (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
- ;; Fix directory local variables in remote buffers
- (defun my/-eglot-fix-dir-locals-in-remote-dirs (oldfun server &optional path)
- (if (not (file-remote-p (or path default-directory)))
- (funcall oldfun server path)
- (cl-letf (((default-value 'enable-remote-dir-locals)
- (let ((default-directory (if path (if (file-directory-p path)
- (file-name-as-directory path)
- (file-name-directory path))
- default-directory)))
- (connection-local-value enable-remote-dir-locals))))
- (funcall oldfun server path))))
- (advice-add 'eglot--workspace-configuration-plist :around
- #'my/-eglot-fix-dir-locals-in-remote-dirs)
- (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)
- :custom
- (apheleia-formatters-respect-fill-column t)
- :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))
- :custom
- (gud-highlight-current-line t)
- :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
- :defer nil
- :bind (([remap project-compile] . my/project-compile-or-default)
- :map project-prefix-map
- ("s" . my/project-eshell)
- ("u" . my/project-run))
- :init
- (setq uniquify-dirname-transform #'project-uniquify-dirname-transform)
- (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 #'stringp)
- (defvar my/project-run-dir nil
- "Directory to run project in with `my/project-run'.")
- (put 'my/project-run-dir 'safe-local-variable #'stringp)
- (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))
- ;; editorconfig
- (use-package editorconfig
- :demand t
- :ensure nil
- :init
- (editorconfig-mode 1))
- ;; 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 . my/flycheck-if-trusted)
- (TeX-mode . kill-ring-deindent-mode))
- :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 . my/eglot-if-trusted)
- :after eglot)
- ;; python-ts-mode
- (use-package python
- :ensure nil
- :hook ((python-ts-mode . my/eglot-if-trusted)
- (python-ts-mode . my/-setup-python-ts-mode))
- :config
- (defun my/-setup-python-ts-mode ()
- (setq-local fill-column 79)))
- ;; python virtual environments
- (use-package pyvenv)
- (use-package pyenv-mode)
- ;; ros2
- (require 'arch-ros2)
- ;; java-ts-mode
- (use-package java-ts-mode
- :hook ((java-ts-mode . my/eglot-if-trusted)
- (java-ts-mode . my/-setup-java-ts-mode))
- :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) . my/eglot-if-trusted)
- :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-ts-mode
- :ensure nil
- :hook (php-mode . my/eglot-if-trusted))
- ;; web-mode
- (use-package web-mode
- :hook (web-mode . my/eglot-if-trusted)
- :init
- (add-to-list 'eglot-server-programs
- '(web-mode . ("vscode-html-language-server" "--stdio"))))
- ;; JavaScript
- (use-package js
- :ensure nil
- :hook (js-ts-mode . my/eglot-if-trusted))
- (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 . my/eglot-if-trusted)
- :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-ts-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 . my/eglot-if-trusted))
- (use-package go-ts-mode
- :ensure nil
- :hook (go-ts-mode . my/eglot-if-trusted))
- ;; rust
- (use-package rust-mode)
- (use-package rust-ts-mode
- :ensure nil
- :hook (rust-ts-mode . my/eglot-if-trusted))
- ;; zig
- (use-package zig-mode
- :hook (zig-mode . my/eglot-if-trusted))
- ;; lua
- (use-package lua-mode
- :hook (lua-mode . my/eglot-if-trusted))
- ;; 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
- (add-hook 'cmake-ts-mode-hook #'my/eglot-if-trusted)
- (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 . my/eglot-if-trusted)
- :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 . my/eglot-if-trusted)
- (yaml-ts-mode . my/-setup-yaml-ts-mode))
- :init
- (add-to-list 'auto-mode-alist `("\\.clangd\\'" . yaml-ts-mode))
- (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)
- (sly)))
- (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))
- ;; inferior cc
- (require 'inferior-cc)
- (with-eval-after-load 'c-ts-mode
- (keymap-set c-ts-base-mode-map "C-x C-e" #'inferior-cc-eval-expression)
- (keymap-set c-ts-base-mode-map "C-c C-r" #'inferior-cc-eval-region)
- (keymap-set c-ts-base-mode-map "C-c C-b" #'inferior-cc-eval-buffer)
- (keymap-set c-ts-base-mode-map "C-M-x" #'inferior-cc-eval-defun))
- (with-eval-after-load 'java-ts-mode
- (keymap-set java-ts-mode-map "C-x C-e" #'inferior-cc-eval-expression)
- (keymap-set java-ts-mode-map "C-c C-r" #'inferior-cc-eval-region)
- (keymap-set java-ts-mode-map "C-c C-b" #'inferior-cc-eval-buffer)
- (keymap-set java-ts-mode-map "C-M-x" #'inferior-cc-eval-defun))
- ;; 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/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 '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))
- (setq mode-line-right-align-edge 'right-margin)
- :config
- (defun my/-window-dedicated-modeline-segment ()
- (let ((dedicated (window-dedicated-p)))
- (cond
- ((eq dedicated t) "[SD]")
- (dedicated "[D]"))))
- (add-to-list 'mode-line-misc-info
- '(:eval (my/-window-dedicated-modeline-segment)))
- (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)
- (defun my/dir-container-p (&optional dir)
- "Return non-nil if DIR is a remote directory that is a container.
- Actually, return the method name."
- (car (member (file-remote-p default-directory 'method)
- '("docker" "podman" "kubernetes" "dockercp" "podmancp"
- "toolbox" "distrobox" "flatpak" "apptainer" "nspawn"))))
- (defun my/dir-distrobox-p (&optional dir)
- "Return non-nil if DIR is a remote directory that is a distrobox container."
- (let ((method (my/dir-container-p dir)))
- (or (equal method "distrobox")
- (and method
- (let ((default-directory (or dir default-directory)))
- (executable-find "distrobox-host-exec" t))))))
- (defun my/dir-sudo-p (&optional dir)
- "Return non-nil if DIR is a remote directory that is sudo, doas, etc.."
- (member (file-remote-p (or dir default-directory) 'method)
- '("sudo" "doas" "su" "sudoedit")))
- (defun my/dir-really-remote-p (&optional dir)
- "Return non-nil if DIR is a remote directory that is really remote."
- (and (file-remote-p (or dir default-directory))
- (not (my/dir-distrobox-p dir))
- (not (my/dir-sudo-p dir))))
- ;; 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))
- :hook
- (eat-mode . my/-setup-eat-mode)
- :init
- (evil-define-key 'insert eat-semi-char-mode-map
- (kbd "<escape>") #'eat-self-input
- (kbd "C-S-n") #'evil-normal-state
- (kbd "C-y") #'eat-yank
- (kbd "C-u") #'universal-argument
- (kbd "C-w") evil-window-map)
- :config
- (defun my/-setup-eat-mode ()
- (visual-wrap-prefix-mode -1)
- (visual-line-mode -1))
- ;; 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
- (defun my/-eat-choose-good-term ()
- (if (my/dir-really-remote-p)
- "xterm-256color"
- (eat-term-get-suitable-term-name)))
- (setq eat-term-name #'my/-eat-choose-good-term)
- (defun my/-eat-shell-for-cwd ()
- "Return a good shell for CWD, or nil if the default shell should be used."
- (cond
- ((my/dir-container-p) "/bin/sh") ;; idk why zsh dosen't work
- ((my/dir-really-remote-p) "/bin/sh")))
- (defun my/project-eat (&optional arg prompt)
- "Switch to or create a eat buffer in the current projects root."
- (interactive (list current-prefix-arg t))
- (if-let ((proj (project-current prompt))
- (default-directory (project-root proj)))
- (let ((eat-buffer-name (format "*eat for project %s*" default-directory)))
- (eat (my/-eat-shell-for-cwd) arg))))
- (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 arg)
- (eat (my/-eat-shell-for-cwd) arg))))
- ;; 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))
- :bind (:map eshell-mode-map
- ("TAB" . completion-at-point)
- ("<tab>" . completion-at-point))
- :custom
- (eshell-history-append t)
- :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 eshell/-captive-cd (&optional dir &rest _)
- (cond
- ((not dir)
- (eshell/-captive-cd "~"))
- ((or (not (file-remote-p default-directory))
- (file-remote-p dir))
- (eshell/cd dir))
- ((file-name-absolute-p dir)
- (eshell/cd (concat (file-remote-p default-directory) dir)))
- (t
- (eshell/cd dir))))
- (defvar-local my/-eshell-last-remote-system nil)
- (defun my/-eshell-maybe-setup-remote (&optional force)
- (when (or force (not (equal my/-eshell-last-remote-system
- (file-remote-p default-directory))))
- (kill-local-variable 'eshell-syntax-highlighting-highlight-in-remote-dirs)
- (if (my/dir-really-remote-p)
- (setq-local eshell-command-aliases-list (my/-eshell-filter-alias-list))
- (setq-local eshell-command-aliases-list
- (default-toplevel-value 'eshell-command-aliases-list)))
- (setq-local eshell-command-aliases-list
- (copy-tree eshell-command-aliases-list))
- (when (file-remote-p default-directory)
- (add-to-list 'eshell-command-aliases-list '("cd" "-captive-cd $1") t))
- (when (or (my/dir-distrobox-p)
- (my/dir-sudo-p))
- (setq-local eshell-syntax-highlighting-highlight-in-remote-dirs t)
- (setf (alist-get "pwd" eshell-command-aliases-list nil nil 'equal)
- '("(directory-file-name (file-remote-p default-directory 'localname))")))
- (when (my/dir-distrobox-p)
- (unless (executable-find "eza" t)
- (if (executable-find "exa" t)
- (setf (alist-get "ls" eshell-command-aliases-list nil nil 'equal)
- '("exa -F $*"))
- (setf (alist-get "ls" eshell-command-aliases-list nil t 'equal)
- nil)))
- (unless (executable-find "trash-put" t)
- (setf (alist-get "tp" eshell-command-aliases-list nil t 'equal) nil
- (alist-get "trr" eshell-command-aliases-list nil t 'equal) nil
- (alist-get "tre" eshell-command-aliases-list nil t 'equal) nil
- (alist-get "trm" eshell-command-aliases-list nil t 'equal) nil
- (alist-get "rm" eshell-command-aliases-list nil t 'equal) nil))
- (setf (alist-get "ldg" eshell-command-aliases-list nil t 'equal) nil)))
- (setq-local my/-eshell-last-remote-system
- (file-remote-p default-directory)))
- (defun my/-eshell-mode-setup ()
- "Setup function run from `eshell-mode-hook'"
- (setq-local corfu-auto nil)
- (my/-eshell-maybe-setup-remote t))
- (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 $*")
- ("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
- (string-match (rx bos (group (* (not "/"))) (* "/") (group (* any)))
- name)
- (let* ((bm-name (match-string 1 name))
- (after-path (match-string 2 name))
- (bm-path (bookmark-get-filename bm-name))
- (full-path (expand-file-name after-path bm-path)))
- (when (my/dir-distrobox-p)
- (setq full-path (concat (file-remote-p default-directory)
- full-path)))
- (if (not (file-directory-p full-path))
- (progn
- (find-file full-path)
- (goto-char (bookmark-get-position bm-name)))
- (eshell/cd full-path)
- (when my/eshell-bm-auto-ls
- (eshell/ls)))))
- (bookmark-maybe-load-default-file)
- (eshell-print
- (mapconcat (lambda (record)
- (let ((name (bookmark-name-from-full-record record))
- (file (bookmark-get-filename record)))
- (format "%s => %s"
- (propertize name 'face '(:foreground "deep sky blue"
- :weight bold))
- (if (file-directory-p file)
- (file-name-as-directory file)
- (directory-file-name file)))))
- bookmark-alist
- "\n"))))
- (defun pcomplete/bm ()
- "Completions for `bm'."
- (let ((arg (pcomplete-arg)))
- (if (not (cl-find ?/ arg))
- (pcomplete-here (mapcar (##concat % "/") (bookmark-all-names)))
- (when (string-match (rx bos (group (+ (not "/"))) (+ "/") (group (* any)))
- arg)
- (let ((bm-name (match-string 1 arg))
- (after-path (match-string 2 arg)))
- (when-let ((base (ignore-errors (bookmark-get-filename bm-name)))
- ((file-directory-p base))
- (abs-path (expand-file-name after-path base))
- (dir-path (if (string-empty-p after-path)
- abs-path
- (file-name-directory abs-path)))
- (path-end (if (string-empty-p after-path)
- ""
- (file-name-nondirectory abs-path))))
- (pcomplete-here
- (mapcan (lambda (entry)
- (unless (member (car entry) '(".." "."))
- (if (eq t (file-attribute-type (cdr entry)))
- (list (concat (car entry) "/"))
- (list (car entry)))))
- (directory-files-and-attributes dir-path))
- path-end))))))))
- (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"))
- (defvar my/eshell-or-eat-hook nil
- "Hook to determine weather `my/open-shell-dwin' uses `eshell' or `eat'.")
- (defvar my/always-use-eat nil
- "Make `my/open-shell-dwim' always use eat.")
- (put 'my/always-use-eat 'safe-local-variable 'booleanp)
- (defun my/open-shell-dwim (&optional arg)
- "Open either an `eshell' or `eat' terminal based on `my/eshell-or-eat-hook'.
- ARG is the same as for either of the above functions."
- (interactive "P")
- (if (or my/always-use-eat
- (run-hook-with-args-until-success 'my/eshell-or-eat-hook))
- (my/project-eat-or-default arg)
- (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 :key 'car)))
- (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))
- ;; trashed
- (use-package trashed
- :bind ("C-c h" . trashed))
- ;; 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 . my/flycheck-if-trusted))
- ;; 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
- ;; ;; (my/eglot-if-trusted)
- ;; )
- ;; (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")))
- ;; dictionaries
- (use-package dictionary
- :defer t
- :ensure nil
- :custom
- (dictionary-read-word-function . #'dictionary-completing-read-word)
- (dictionary-read-dictionary-function . #'dictionary-completing-read-dictionary))
- ;; 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
|