123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330 |
- ;; -*- lexical-binding: t; -*-
- ;;; Initialisation
- ;;;; Bootstrap and use package
- (defvar jao-emacs-dir (expand-file-name "~/etc/emacs"))
- (setq package-user-dir
- (expand-file-name (format "~/.emacs.d/elpa.%s" emacs-major-version))
- package-check-signature 'allow-unsigned)
- (require 'package)
- (setq package-archives
- '(("gnu-devel" . "https://elpa.gnu.org/devel/")
- ("nongnu-devel" . "https://elpa.nongnu.org/nongnu-devel/")
- ("melpa" . "https://melpa.org/packages/"))
- package-archive-priorities '(("gnu-devel" . 2)
- ("nongnu-devel" . 1)
- ("melpa" . 0)))
- (package-initialize)
- (unless (package-installed-p 'use-package)
- (package-refresh-contents)
- (package-install 'use-package))
- (require 'use-package)
- (use-package gnu-elpa-keyring-update :ensure t)
- ;;;; .elc vs .el loading
- (setq load-prefer-newer t)
- (setq comp-async-report-warnings-errors nil
- warning-suppress-types '((comp)))
- ;;; Paths
- (defvar jao-local-lisp-dir "~/lib/elisp"
- "Directory for external elisp libraries and repos")
- (defvar jao-data-dir (expand-file-name "data" jao-emacs-dir)
- "Directory containing static data, such as images.")
- (defun jao-data-file (file) (expand-file-name file jao-data-dir))
- (setq jao-org-dir (expand-file-name "~/doc/org"))
- (defvar jao-sink-dir
- (file-name-as-directory (expand-file-name "~/doc/sink"))
- "Directory used for downloads and such.")
- (defvar jao-site-dir (expand-file-name "site" jao-emacs-dir))
- (defun jao-site-el (basename &optional gpg)
- (expand-file-name (concat basename ".el" (when gpg ".gpg")) jao-site-dir))
- (defun jao-load-site-el (basename &optional gpg)
- (let ((lf (jao-site-el basename gpg)))
- (if (file-exists-p lf)
- (load lf)
- (message "Attempted to load non existing %s" lf))))
- (defun jao-exec-path (dir)
- (let ((fn (expand-file-name dir)))
- (add-to-list 'exec-path fn nil)
- (setenv "PATH" (concat fn ":" (getenv "PATH")))))
- (defun jao-load-path (subdir)
- "Add to load path a subdir of `jao-local-lisp-dir'"
- (let ((path (expand-file-name subdir jao-local-lisp-dir)))
- (when (file-directory-p path) (add-to-list 'load-path path))))
- ;;;; load and info path initialisation
- (add-to-list 'load-path jao-site-dir)
- (add-to-list 'load-path jao-local-lisp-dir)
- (add-to-list 'load-path (expand-file-name "custom" jao-emacs-dir))
- (add-to-list 'load-path "/usr/local/share/emacs/site-lisp/")
- (let ((libd (expand-file-name "lib" jao-emacs-dir)))
- (add-to-list 'load-path libd)
- (dolist (f (directory-files libd t "^[^.]+$"))
- (when (file-directory-p f) (add-to-list 'load-path f))))
- (defvar jao-info-dir (expand-file-name "~/doc/info"))
- (require 'info)
- (add-to-list 'Info-directory-list jao-info-dir)
- ;;;; custom location of custom.el and co.
- (setq custom-file (jao-site-el "custom"))
- (load custom-file)
- (setq custom-unlispify-tag-names nil)
- (setq custom-buffer-done-kill t)
- (setq custom-raised-buttons nil)
- ;;; Preamble
- ;;;; preamble (pre.el)
- (jao-load-site-el "pre")
- ;;; System Utilities
- ;;;; persist
- (require 'persist)
- ;;;; (no) backups
- (setq vc-make-backup-files nil
- make-backup-files nil)
- ;;;; history (saveplace, recentf, savehist)
- (require 'saveplace)
- (setq save-place-file (expand-file-name "~/.emacs.d/cache/places"))
- (save-place-mode 1)
- (setq recentf-save-file (expand-file-name "~/.emacs.d/cache/recentf")
- recentf-max-saved-items 2000
- recentf-exclude '("/home/jao/\\.emacs\\.d/elpa.*/.*"
- ".*/.git/COMMIT_EDITMSG"))
- (require 'recentf)
- (recentf-mode 1)
- (setq savehist-file (expand-file-name "~/.emacs.d/cache/history"))
- (require 'savehist)
- (savehist-mode t)
- (defun jao-unpropertize-kill-ring ()
- (setq kill-ring (mapcar #'substring-no-properties kill-ring)))
- (add-hook 'kill-emacs-hook #'jao-unpropertize-kill-ring)
- (setq savehist-additional-variables '(kill-ring search-ring regexp-search-ring)
- savehist-ignored-variables '(ido-file-history))
- ;;;; yes/no, bell, startup message
- (setq use-short-answers t)
- (setq inhibit-startup-message t)
- (setq visible-bell t)
- ;;;; server
- (setenv "EDITOR" "emacsclient")
- (require 'server)
- (unless (or (daemonp) (server-running-p)) (server-start))
- ;;;; timers
- (put 'list-timers 'disabled nil)
- ;;;; tramp
- (inhibit-remote-files)
- ;;;; sleep/awake
- (use-package jao-sleep)
- (jao-sleep-dbus-register)
- ;;;; process runners
- (use-package jao-shell
- :demand t
- :config (jao-shell-def-exec jao-trayer "trayer.sh")
- :bind (("s-r" . jao-shell-exec)))
- ;;;; app launcher
- (jao-load-path "app-launcher")
- (use-package app-launcher
- :bind (("s-R" . app-launcher-run-app)))
- ;;;; brightness control
- (jao-shell-def-exec jao-bright-set-up "brightnessctl" "-q" "s" "5%+")
- (jao-shell-def-exec jao-bright-set-down "brightnessctl" "-q" "s" "5%-")
- (defun jao-brightness ()
- (string-trim (or (cadr (jao-shell-cmd-lines "brightnessctl")) "(Unknown)")))
- (defun jao-bright-show ()
- (interactive)
- (message "%s" (jao-brightness)))
- (defun jao-bright-up ()
- (interactive)
- (jao-shell-exec "brightnessctl -q s 5%%+" t)
- (jao-bright-show))
- (defun jao-bright-down ()
- (interactive)
- (jao-shell-exec "brightnessctl -q s 5%%-" t)
- (jao-bright-show))
- ;;;; keyboard
- (when (> emacs-major-version 27)
- (use-package repeat
- :config (setq repeat-echo-function 'repeat-echo-mode-line
- repeat-exit-key "SHIFT"
- repeat-exit-timeout 2))
- (repeat-mode))
- (defun jao-kb-toggle (&optional lyt)
- (interactive)
- (shell-command-to-string (or lyt
- (if (jao-kb-toggled-p)
- "setxkbmap us"
- "setxkbmap us -variant intl"))))
- (defun jao-kb-toggled-p ()
- (not (string-empty-p
- (shell-command-to-string "setxkbmap -query|grep variant"))))
- (customize-set-variable 'default-input-method "catalan-prefix")
- ;; http://mbork.pl/2022-03-07_Transient_input_method
- (customize-set-variable 'default-transient-input-method "TeX")
- (setq echo-keystrokes 1
- suggest-key-bindings nil)
- ;;;; transient
- (use-package transient
- :init (setq transient-show-popup t) ;; 2.0
- :demand t
- :config
- (transient-bind-q-to-quit))
- (defmacro jao-transient-major-mode (mode &rest suffix)
- (declare (indent defun))
- (let ((mode (intern (format "%s-mode" mode)))
- (mmap (intern (format "%s-mode-map" mode)))
- (name (intern (format "jao-transient-%s" mode))))
- `(progn
- (transient-define-prefix ,name ()
- ,(format "Transient ops for %s" mode)
- [,(format "Operations for %s" mode) :if-derived ',mode ,@suffix])
- (define-key ,mmap (kbd "s-SPC") #',name)
- (define-key ,mmap (kbd "C-c SPC") #',name))))
- (defmacro jao-transient-major-mode+1 (mode suffix)
- (declare (indent defun))
- (let ((name (intern (format "jao-transient-%s" mode))))
- (if (fboundp name)
- `(transient-append-suffix ',name '(0 -1) ,suffix)
- `(jao-transient-major-mode ,mode ,suffix))))
- (defmacro jao-transient-major-mode+ (mode &rest suffixes)
- (declare (indent defun))
- `(progn ,@(mapcar (lambda (s) `(jao-transient-major-mode+1 ,mode ,s))
- suffixes)))
- ;;;; disk monitoring
- (use-package jao-dirmon
- :commands jao-dirmon-report)
- ;;;; mailcap
- (use-package mailcap
- :config
- (add-to-list 'mailcap-mime-extensions '(".JPEG" . "image/jpeg"))
- (add-to-list 'mailcap-mime-extensions '(".JPG" . "image/jpeg"))
- (defun jao-icalendar-import-buffer (&optional no-kill)
- (let ((icalendar-import-format "%s%u%l%d"))
- (icalendar-import-buffer diary-file t nil))
- (unless no-kill (kill-buffer))
- (message "Event imported into diary"))
- (defun jao-icalendar-import-invite (file)
- (with-temp-buffer
- (insert-file-contents file)
- (jao-icalendar-import-buffer t)))
- :custom
- ((mailcap-user-mime-data
- `((jao-icalendar-import-buffer "application/ics")
- ("emacsclient -e '(jao-icalendar-import-invite \"%s\")'" "application/ics")
- (doc-view-mode "application/.*pdf" (display-graphic-p))
- ("zathura \"%s\"" "application/.*pdf")
- (image-mode "image/.*" (display-graphic-p))
- ("firefox %s && riverctl set-focused-tags 2" "text/html" jao-river-enabled)
- ("swayimg \"%s\"" "image/.*" jao-sway-enabled)
- ("imv-wayland \"%s\"" "image/.*" jao-wayland-enabled)
- ("imv-x11 \"%s\"" "image/.*")))))
- ;;; Crypto
- ;;;; PGP, EPG, passwords
- (setq auth-source-debug nil)
- (require 'auth-source)
- (add-to-list 'auth-source-protocols '(local "local"))
- (setq auth-sources '("~/.emacs.d/authinfo.gpg" "~/.netrc"))
- (use-package epa-file
- :init (setq epa-file-cache-passphrase-for-symmetric-encryption t)
- :config (epa-file-enable))
- (require 'epa-file)
- (defun jao--get-user/password (h)
- (let ((item (car (auth-source-search :type 'netrc :host h :max 1))))
- (when item
- (let ((user (plist-get item :user))
- (pwd (plist-get item :secret)))
- (list user (when pwd (funcall pwd)))))))
- (defun jao-call-with-auth (host fun)
- (let ((up (jao--get-user/password host)))
- (funcall fun (car up) (cadr up))))
- (defmacro jao-with-auth (host usr pwd &rest body)
- (declare (indent defun))
- `(jao-call-with-auth ,host (lambda (,usr ,pwd) ,@body)))
- ;;;; pass
- (use-package password-store-menu
- :ensure t
- :config (password-store-menu-enable)
- :custom (password-store-menu-key "C-c p"))
- ;;; Fonts and color themes
- ;;;; widgets
- (setq widget-image-enable nil
- widget-link-prefix ""
- widget-link-suffix ""
- widget-button-prefix " "
- widget-button-suffix " "
- widget-push-button-prefix ""
- widget-push-button-suffix "")
- ;;;; nobreak char display
- (setq nobreak-char-display nil)
- ;;;; vertical separator
- (unless (display-graphic-p)
- (set-display-table-slot standard-display-table
- 'vertical-border
- (make-glyph-code ?│)))
- ;;;; transparency
- (defvar jao-transparent-only-bg (> emacs-major-version 28))
- (defvar jao-frames-default-alpha
- (cond ((eq window-system 'pgtk) 85)
- (jao-transparent-only-bg 88)
- (t 85)))
- (defvar jao-transparent-frame (< jao-frames-default-alpha 100))
- (defun jao-alpha-parameters (&optional level)
- (let ((level (or level jao-frames-default-alpha)))
- (if jao-transparent-only-bg
- `((alpha-background . ,level) (alpha))
- `((alpha . ,(cons level level)) (alpha-background)))))
- (defun jao-set-transparency (&optional level all)
- (interactive "nOpacity (0-100): ")
- (let ((level (or level jao-frames-default-alpha)))
- (setq jao-transparent-frame (< level 100))
- (if all
- (modify-all-frames-parameters (jao-alpha-parameters level))
- (modify-frame-parameters nil (jao-alpha-parameters level)))))
- (defun jao-toggle-transparency (&optional all)
- (interactive "P")
- (let ((level (if jao-transparent-frame 100 jao-frames-default-alpha)))
- (jao-set-transparency level all)))
- (jao-set-transparency)
- ;;;; themes
- (defun jao-colors-scheme-dark-p ()
- (equal "dark" (getenv "JAO_COLOR_SCHEME")))
- (defun jao-colors-scheme ()
- (if (jao-colors-scheme-dark-p) 'dark 'light))
- (customize-set-variable 'frame-background-mode (jao-colors-scheme))
- (setq custom-theme-directory
- (expand-file-name "lib/themes" jao-emacs-dir))
- (require 'jao-themes)
- (defvar jao-theme-dark 'jao-dark)
- (defvar jao-theme-light 'jao-light)
- (defvar jao-theme-term-dark 'modus-vivendi)
- (defvar jao-theme-term-light 'jao-light-term)
- (defun jao-themes-setup ()
- (let* ((dark (jao-colors-scheme-dark-p))
- (theme (cond ((and dark window-system) jao-theme-dark)
- (dark jao-theme-term-dark)
- (window-system jao-theme-light)
- (t jao-theme-term-light))))
- (load-theme theme t)
- (modify-all-frames-parameters `((font . ,jao-themes-default-face)))))
- (jao-themes-setup)
- ;;; Help system
- ;;;; help buffers
- (setq help-window-select t
- help-window-keep-selected nil
- help-link-key-to-documentation t)
- ;;;; find-func/var/lib
- (use-package find-func
- :bind (("C-h C-v" . find-variable)
- ("C-h C-f" . find-function)
- ("C-h C-k" . find-function-on-key)
- ("C-h C-l" . find-library)))
- ;;;; eldoc
- (use-package eldoc
- :init (setq eldoc-minor-mode-string nil
- eldoc-idle-delay 0.1
- eldoc-echo-area-display-truncation-message nil
- eldoc-echo-area-use-multiline-p 5
- eldoc-echo-area-prefer-doc-buffer 'maybe
- eldoc-display-functions '(eldoc-display-in-echo-area))
- :config (global-eldoc-mode 1))
- (defun jao-eldoc-toggle ()
- "Toggle eldoc's documentation buffer."
- (interactive)
- (let ((buffer (eldoc-doc-buffer)))
- (if-let (w (and buffer (get-buffer-window buffer)))
- (delete-window w)
- (eldoc-doc-buffer t))))
- ;;;; bookmarks
- (setq bookmark-default-file "~/.emacs.d/emacs.bmk"
- bookmark-fringe-mark nil)
- ;;;; man pages
- (use-package man
- :config (setq Man-notify-method 'pushy)) ;; pushy - same window
- ;;; Minibuffer
- (use-package jao-minibuffer
- :init
- (if (jao-colors-scheme-dark-p)
- (setq jao-minibuffer-active-buffer-line-color "azure4"
- jao-minibuffer-inactive-buffer-line-color "grey25")
- (setq jao-minibuffer-active-buffer-line-color "burlywood3"
- jao-minibuffer-inactive-buffer-line-color "grey65"))
- (setq jao-minibuffer-adaptive-alignment nil)
- :commands (jao-minibuffer-add-variable
- jao-minibuffer-refresh
- jao-minibuffer-mode))
- (setq enable-recursive-minibuffers t)
- (require 'mb-depth)
- (minibuffer-depth-indicate-mode 1)
- (setq minibuffer-default-prompt-format " (default %s)")
- (minibuffer-electric-default-mode 1)
- (jao-minibuffer-mode 1)
- ;;; Mode line
- ;;;; config
- (setq line-number-display-limit-width 250
- mode-line-position-column-format '(" %c")
- mode-line-position-line-format '(" %c %l")
- mode-line-end-spaces nil
- mode-line-percent-position
- '("%2l" (:eval (format " %d " (line-number-at-pos (point-max)))) "%2c"))
- (line-number-mode -1)
- (column-number-mode -1)
- ;;;; jao-mode-line
- (defvar jao-mode-line-in-minibuffer t)
- (use-package jao-mode-line
- :commands (jao-mode-line-add-to-minibuffer-left
- jao-mode-line-add-to-minibuffer-right
- jao-mode-line-remove-from-minibuffer))
- ;;;; time display
- (setq world-clock-list
- '(("Europe/London" "Edinburgh")
- ("Europe/Paris" "Barcelona")
- ("Asia/Tokyo" "Tokyo")
- ("America/Los_Angeles" "Corvallis")
- ("America/New_York" "New York")))
- (setq display-time-day-and-date nil
- display-time-24hr-format nil
- display-time-default-load-average nil
- display-time-format " %a %e %H:%M")
- (defun jao-time-to-epoch (&optional s)
- "Transform a time string to an epoch integer in milliseconds."
- (interactive)
- (let ((s (or s (read-string "Time string: " (thing-at-point 'string)))))
- (message "%s = %s"
- s
- (round (* 1000 (time-to-seconds (parse-time-string s)))))))
- (defun jao-epoch-to-time (&optional v)
- "Transform an epoch, given in milliseconds, to a time string."
- (interactive)
- (let ((v (or v (read-number "Milliseconds: " (thing-at-point 'number)))))
- (message "%s = %s" v
- (format-time-string "%Y-%m-%d %H:%M:%S"
- (seconds-to-time (/ v 1000.0))))))
- ;;;; mode line toggle
- (use-package jao-mode-line
- :init
- (when (and window-system (not jao-mode-line-in-minibuffer))
- (add-to-list 'after-make-frame-functions #'jao-mode-line-hide-inactive)
- (add-hook 'after-init-hook #'jao-mode-line-toggle-inactive))
- :demand t
- :bind (("<home>" . jao-mode-line-toggle-inactive)
- ("<end>" . jao-mode-line-toggle)
- ("<insert>" . jao-mode-line-echo)))
- ;;;; diminish
- (use-package diminish
- :ensure t
- :demand t
- :diminish ((auto-fill-function . " §")
- (auto-revert-mode . "")))
- (use-package outline
- :diminish ((outline-minor-mode . "")))
- ;;;; battery
- (use-package battery
- :init (setq battery-load-low 15
- battery-load-critical 8
- battery-mode-line-limit 40
- battery-echo-area-format
- "%L %r %B (%p%% load, remaining time %t)"
- battery-mode-line-format " 🔋%b%p% "))
- (with-eval-after-load "jao-minibuffer"
- (if jao-mode-line-in-minibuffer
- (display-battery-mode 1)
- (jao-minibuffer-add-variable 'battery-mode-line-string 80)))
- ;;; Notifications
- ;;;; jao-notify
- (use-package jao-notify
- :demand t
- :init (setq jao-notify-use-messages t))
- ;;;; tracking
- (use-package tracking
- :demand t
- :init (setq tracking-position 'before-modes
- tracking-frame-behavior nil
- tracking-most-recent-first nil
- tracking-max-mode-line-entries 10
- tracking-sort-faces-first t
- tracking-shorten-modes '())
- :config
- (setq erc-track-enable-keybindings nil))
- (use-package jao-tracking
- :demand t
- :init (setq jao-tracking-bkg (if (jao-colors-scheme-dark-p) "grey20" "grey93"))
- :config (jao-tracking-setup t))
- ;;;; ednc
- (use-package ednc
- :ensure t
- :diminish nil)
- (use-package jao-ednc
- :demand t
- :init (setq jao-ednc-use-tracking nil)
- :commands (jao-ednc-setup)
- :after ednc
- :config
- (jao-ednc-ignore-app "Firefox")
- (transient-define-prefix jao-transient-ednc ()
- ["Notifications"
- ("s" "show last" jao-ednc-show)
- ("S" "show all" jao-ednc-pop)
- ("n" "dismiss and show" jao-ednc-dismiss-and-show :transient t)
- ("d" "dismiss last" jao-ednc-dismiss)
- ("D" "dismiss all" jao-ednc-dismiss-all)
- ("i" "invoke last action" jao-ednc-invoke-last-action)])
- (global-set-key (kbd "s-n") #'jao-transient-ednc))
- ;;; Calendar, diary, weather
- ;;;; diary
- (setq diary-file (expand-file-name "diary" jao-org-dir)
- diary-display-function 'diary-fancy-display
- diary-mail-addr "jao@localhost"
- diary-comment-start ";;"
- diary-comment-end "")
- (add-hook 'diary-list-entries-hook 'diary-sort-entries t)
- ;;;; calendar
- (setq appt-display-format nil)
- (appt-activate 1)
- (setq calendar-latitude 55.9533
- calendar-longitude -3.1883
- calendar-left-margin 4
- calendar-location-name "Edinburgh, Scotland"
- calendar-mark-diary-entries-flag t
- calendar-week-start-day 1 ;; 0 sunday
- calendar-date-echo-text '(format "ISO date: %s"
- (calendar-iso-date-string
- (list month day year))))
- (setq calendar-holidays
- '((holiday-fixed 1 1 "New Year's Day")
- (holiday-fixed 4 1 "April Fools' Day")
- (holiday-float 5 0 2 "Mother's Day")
- (holiday-fixed 3 19 "Father's Day")
- (holiday-float 11 4 4 "Thanksgiving")
- (holiday-fixed 12 25 "Christmas")
- (holiday-chinese-new-year)
- (solar-equinoxes-solstices)
- (holiday-sexp calendar-daylight-savings-starts
- (format "Daylight Saving Time Begins %s"
- (solar-time-string
- (/ calendar-daylight-savings-starts-time
- (float 60))
- calendar-standard-time-zone-name)))
- (holiday-sexp calendar-daylight-savings-ends
- (format "Daylight Saving Time Ends %s"
- (solar-time-string
- (/ calendar-daylight-savings-ends-time
- (float 60))
- calendar-daylight-time-zone-name)))))
- (add-to-list 'display-buffer-alist
- `(,(regexp-quote diary-fancy-buffer)
- (display-buffer-at-bottom)
- (window-parameters (mode-line-format . none))
- (window-height . fit-window-to-buffer)))
- (defun jao-diary--select ()
- (switch-to-buffer diary-fancy-buffer))
- (add-hook 'diary-fancy-display-mode-hook #'jao-diary--select)
- (setq org-calendar-insert-diary-entry-key nil
- org-agenda-diary-file 'diary-file)
- ;;;; winttr
- (defun jao-weather (&optional wide)
- (interactive "P")
- (if (not wide)
- (message "%s"
- (jao-shell-string "curl -s"
- "https://wttr.in/?format=%l++%m++%C+%c+%t+%w++%p"))
- (jao-afio-goto-scratch)
- (if-let ((b (get-buffer "*wttr*")))
- (progn (pop-to-buffer b)
- (term-send-string (get-buffer-process nil) "clear;curl wttr.in\n"))
- (jao-exec-in-term "curl wttr.in" "*wttr*"))))
- (global-set-key (kbd "<f5>") #'jao-weather)
- ;;; Files, dired and scratch buffer
- ;;;; so-long
- (setq large-file-warning-threshold (* 200 1024 1024))
- ;; (use-package so-long
- ;; :ensure t
- ;; :diminish)
- ;; (global-so-long-mode 1)
- ;;;; persistent scratch
- (use-package persistent-scratch
- :ensure t
- :config (persistent-scratch-setup-default))
- ;;;; dired
- (use-package dired
- :init
- (setq dired-recursive-deletes 'top
- dired-recursive-copies 'top
- dired-listing-switches "-alhF --group-directories-first"
- ls-lisp-dirs-first t
- dired-dwim-target t
- dired-kill-when-opening-new-dired-buffer t
- dired-mouse-drag-files t
- wdired-create-parent-directories t
- dired-guess-shell-alist-user
- '(;; ("\\.\\(png\\|jpe?g\\|tiff\\)" "feh" "xdg-open")
- ("\\.\\(mp[34]\\|m4a\\|ogg\\|flac\\|webm\\|mkv\\)" "mpv" "xdg-open")
- (".*" "xdg-open")))
- (put 'dired-find-alternate-file 'disabled nil)
- :hook (dired-mode . turn-on-gnus-dired-mode)
- :bind (:map dired-mode-map
- ("C-c C-r" . wdired-change-to-wdired-mode)
- ("C-M-m" . gnus-dired-attach)))
- (use-package dired-x :demand t)
- (use-package find-dired
- :init (setq find-ls-option '("-print0 | xargs -0 ls -ld" . "-ld"))
- :bind ("C-c D" . find-name-dired))
- (use-package dired-duplicates :ensure t)
- ;;; General editing
- ;;;; automatically uncompress
- (require 'jka-compr)
- (auto-compression-mode 1)
- ;;;; wgrep
- (use-package wgrep :ensure t)
- (require 'wgrep)
- ;;;; executable scripts
- (add-hook 'after-save-hook
- 'executable-make-buffer-file-executable-if-script-p)
- ;;;; spaces, tabs, kill
- (setq kill-whole-line t)
- (setq-default indent-tabs-mode nil)
- (setq indent-tabs-width 4)
- (setq-default default-tab-width 8)
- (setq kill-read-only-ok t)
- (setq view-read-only nil)
- ;;;; whitespace and filling column
- (add-hook 'write-file-functions 'delete-trailing-whitespace)
- (setq-default indicate-empty-lines nil)
- (setq-default fill-column 78)
- (setq comment-auto-fill-only-comments nil)
- (use-package whitespace
- :init
- (setq whitespace-style '(face tabs trailing ;; lines-tail
- empty missing-newline-at-eof)
- whitespace-line-column 80)
- :hook (prog-mode . whitespace-mode)
- :diminish nil)
- (use-package display-fill-column-indicator
- :init (setq-default display-fill-column-indicator-column 80)
- :hook (prog-mode . display-fill-column-indicator-mode))
- ;;;; visible mode
- (use-package visible-mode
- :bind (("s-v" . visible-mode)))
- ;;;; changes
- (use-package goto-chg
- :ensure t
- :bind (("C-." . goto-last-change)
- ("C-c ." . goto-last-change)
- ("C-c ," . goto-last-change-reverse)))
- ;;;; eval-and-replace
- (defun fc-eval-and-replace ()
- "Replace the preceding sexp with its value."
- (interactive)
- (backward-kill-sexp)
- (condition-case nil
- (prin1 (eval (read (current-kill 0)))
- (current-buffer))
- (error (message "Invalid expression")
- (insert (current-kill 0)))))
- (global-set-key "\C-ce" 'fc-eval-and-replace)
- ;;;; skeletons and autoinsert
- (use-package autoinsert
- :config
- (setq auto-insert-directory "~/.emacs.d/autoinsert/"
- auto-insert t
- auto-insert-query t)
- (setf (alist-get 'html-mode auto-insert-alist nil t) nil))
- (add-hook 'find-file-hook #'auto-insert)
- (use-package jao-skel
- :demand t
- :config
- (defvar flymake-allowed-file-name-masks nil)
- (require 'jao-skel-geiser)
- (require 'jao-skel-lisp)
- (require 'jao-skel-haskell)
- (require 'jao-skel-latex))
- ;;; Completion and search
- ;;;; completion
- (require 'jao-custom-completion)
- ;;;; recoll
- (jao-load-path "consult-recoll")
- (defun jao-recoll-format (title url _mtype)
- (let* ((u (replace-regexp-in-string "file://" "" url))
- (u (replace-regexp-in-string "/home/jao/" "" u))
- (u (replace-regexp-in-string
- "\\(doc\\|org/doc\\|.emacs.d/gnus/Mail\\|var/mail\\)/" "" u)))
- (format "%s (%s)" ;; "%s (%s, %s)"
- title
- (propertize u 'face 'jao-themes-f01)
- ;; (propertize mtype 'face 'jao-themes-f01)
- )))
- (defun jao-recoll-open-html (file &optional _page)
- (if (string-match-p "\.epub\\'" file)
- (find-file file)
- (jao-afio-goto-www)
- (if jao-afio-use-w3m (w3m-find-file file) (eww-open-file file))))
- (defun jao-recoll-open-pdf (file &optional page)
- (if (string-match-p "/gnus/Mail/" file)
- (funcall (or (cdr (assoc-string "message/rfc822" consult-recoll-open-fns))
- 'find-file)
- file
- page)
- (jao-open-doc file page)))
- (defun jao-recoll-consult-messages ()
- (interactive)
- (consult-recoll "mime:message "))
- (defun jao-recoll-consult-docs ()
- (interactive)
- (consult-recoll (format "dir:%s/doc " jao-org-dir)))
- (defun jao-recoll-consult-notes ()
- "Use consult-recoll to search notes."
- (interactive)
- (consult-recoll (format "dir:%s " jao-org-notes-dir)))
- (use-package consult-recoll
- :commands (consult-recoll consult-recoll-embark-setup)
- :init (setq consult-recoll-open-fns
- '(("application/pdf" . jao-recoll-open-pdf)
- ("text/html" . jao-recoll-open-html))
- consult-recoll-search-flags 'query
- consult-recoll-inline-snippets t
- consult-recoll-format-candidate #'jao-recoll-format)
- :config
- (consult-customize consult-recoll :preview-key 'any)
- (transient-define-prefix jao-transient-recoll ()
- ["Consult recoll queries"
- ("r" "everywhere" consult-recoll)
- ("n" "on notes" jao-recoll-consult-notes)
- ("d" "on docs" jao-recoll-consult-docs)
- ("m" "on messages" jao-recoll-consult-messages)])
- :bind (("s-r" . #'jao-transient-recoll)))
- (with-eval-after-load "embark" (consult-recoll-embark-setup))
- ;;; Buffers
- ;;;; cursor and mark
- (transient-mark-mode -1)
- (blink-cursor-mode -1)
- (setopt cursor-in-non-selected-windows nil
- visible-cursor nil) ;; stop blinking in xterm
- ;;;; uniquifiy
- (require 'uniquify)
- (setq uniquify-buffer-name-style 'forward
- uniquify-trailing-separator-p t)
- ;;;; autosave
- (setq auto-save-list-file-prefix "~/.emacs.d/auto-save-list/.saves-"
- auto-save-no-message t
- kill-buffer-delete-auto-save-files t)
- (setq lock-file-name-transforms
- '(("\\`/.*/\\([^/]+\\)\\'" "/tmp/emacs-lock/\\1" t)))
- ;;;; autorevert
- (setq auto-revert-check-vc-info nil)
- (setq auto-revert-verbose nil)
- (setq auto-revert-avoid-polling t)
- (setq auto-revert-mode-text "")
- (require 'autorevert)
- (global-auto-revert-mode 1)
- ;;;; attached buffers
- (defun jao-display-buffer-below-selected (buffer alist)
- (delete-other-windows-vertically)
- (display-buffer-below-selected buffer alist))
- (defun jao-attached-buffer-entry (name-rx height)
- `(,name-rx (display-buffer-reuse-window
- jao-display-buffer-below-selected)
- (window-height . ,(or height 25))))
- (defmacro jao-with-attached-buffer (name-rx height &rest body)
- (declare (indent defun))
- `(let ((display-buffer-alist '(,(jao-attached-buffer-entry name-rx height))))
- ,@body))
- (defun jao-define-attached-buffer (name-rx &optional height)
- (add-to-list 'display-buffer-alist
- (jao-attached-buffer-entry name-rx height)))
- (jao-define-attached-buffer "\\*eldoc\\( .*\\)?\\*" 0.33)
- ;;;; same mode
- (defun jao-buffer-same-mode (&optional mode pre-fn switch-fn)
- (interactive)
- (let* ((mode (or mode major-mode))
- (modes (if (symbolp mode) (list mode) mode))
- (pred `(lambda (b)
- (let ((b (get-buffer (if (consp b) (car b) b))))
- (member (buffer-local-value 'major-mode b)
- ',modes))))
- (buff (read-buffer "Buffer: " nil t pred)))
- (when pre-fn (funcall pre-fn))
- (if switch-fn (funcall switch-fn buff) (switch-to-buffer buff))))
- (defun jao-buffer-same-mode-cmd (&optional pop)
- (interactive "P")
- (jao-buffer-same-mode nil nil (and pop #'pop-to-buffer)))
- (global-set-key (kbd "C-c C-b") #'jao-buffer-same-mode-cmd)
- ;;;; projects
- (use-package project :demand t)
- (global-set-key "\C-xp" 'jao-prev-window)
- ;;;; buffer quit function (the triple ESC)
- (setq buffer-quit-function (lambda () t))
- ;;;; redisplay escape hatch
- ;; (setq max-redisplay-ticks 2250000)
- ;;;; scrolling
- (if window-system
- (setq scroll-preserve-screen-position 'always
- scroll-conservatively most-positive-fixnum
- scroll-margin 0
- scroll-step 2
- redisplay-skip-fontification-on-input t)
- (setq scroll-preserve-screen-position nil
- scroll-conservatively 0
- scroll-margin 0
- scroll-step 1
- redisplay-skip-fontification-on-input nil))
- ;;; Windows
- ;;;; splitting and switch
- (setq split-height-threshold 80
- split-width-threshold 144
- display-buffer-avoid-small-windows 20)
- (setq switch-to-buffer-preserve-window-point nil
- switch-to-buffer-obey-display-actions t
- switch-to-prev-buffer-skip 'this) ;; don't switch to a
- ;; buffer already visible in
- ;; this frame
- (global-set-key (kbd "C-x _") #'delete-other-windows-vertically)
- ;;;; first window
- (defvar jao-first-window--from nil)
- (defun jao-first-window ()
- "Go to previous windows in frame, remembering where we were."
- (interactive)
- (let ((cb (current-buffer)))
- (if (eq (get-buffer-window cb) (select-window (frame-first-window)))
- (when jao-first-window--from (pop-to-buffer jao-first-window--from))
- (setq jao-first-window--from cb))))
- (global-set-key (kbd "s-a") #'jao-first-window)
- (global-set-key (kbd "M-a") #'jao-first-window)
- ;;;; window navigation (custom)
- (defun jao-nth-window (n)
- (if (zerop n)
- 'jao-first-window
- `(lambda ()
- (interactive)
- (select-window (frame-first-window))
- (dotimes (x ,n) (other-window 1)))))
- (defun jao-prev-window ()
- "Go to previous window."
- (interactive)
- (other-window -1))
- (defvar jao-prev-window-repeat-map
- (let ((map (make-sparse-keymap)))
- (define-key map "p" 'jao-prev-window)
- (define-key map "P" (lambda ()
- (interactive)
- (setq repeat-map 'jao-prev-window-repeat-map)
- (other-window 1)))
- map)
- "Keymap to repeat `prev-window' key sequences. Used in `repeat-mode'.")
- (put 'jao-prev-window 'repeat-map jao-prev-window-repeat-map)
- (mapc (lambda (n)
- (global-set-key (format "\C-c%s" (1+ n)) (jao-nth-window n)))
- '(0 1 2 3 4 5 6 7 8))
- ;; transposing windows
- (defun transpose-windows (arg)
- "Transpose the buffers shown in two windows."
- (interactive "p")
- (let ((selector (if (>= arg 0) 'next-window 'previous-window)))
- (while (/= arg 0)
- (let ((this-win (window-buffer))
- (next-win (window-buffer (funcall selector))))
- (set-window-buffer (selected-window) next-win)
- (set-window-buffer (funcall selector) this-win)
- (select-window (funcall selector)))
- (setq arg (if (> arg 0) (1- arg) (1+ arg))))))
- (define-key ctl-x-4-map (kbd "t") 'transpose-windows)
- ;;;; winner mode
- (winner-mode 1)
- ;;; Frames
- ;;;; frame geometry
- (setq frame-resize-pixelwise t)
- (modify-all-frames-parameters
- `((horizontal-scroll-bars . nil)
- (vertical-scroll-bars . nil)
- (scroll-bar-width . 0)
- (menu-bar . nil)))
- ;;;; frame layout, title, etc
- (setq frame-title-format '("%b - emacs"))
- (use-package fringe)
- (fringe-mode)
- (menu-bar-mode -1)
- ;; (setting it to nil avoids mouse wrapping after other-frame)
- (setq focus-follows-mouse (and window-system t))
- (use-package scroll-bar)
- (set-scroll-bar-mode nil)
- (use-package tool-bar)
- (tool-bar-mode -1)
- (defalias 'jao-trisect 'jao-afio-trisect)
- (defun jao-bisect ()
- (interactive)
- (jao-trisect t)
- (other-window 1)
- (delete-window))
- ;;;; afio
- (use-package jao-afio
- :demand t
- :config (jao-afio-setup (not window-system))
- :bind (("C-c f" . 'jao-afio-goto-main)
- ("C-c g" . 'jao-afio-goto-mail)
- ("C-c w" . 'jao-afio-goto-www)
- ("C-c z" . 'jao-afio-goto-docs)
- ("C-c t" . 'jao-afio-goto-chats)
- ("C-c 0" . 'jao-afio-goto-scratch)
- ("M-o" . 'jao-afio-toggle)))
- (add-hook 'jao-afio-switch-hook 'jao-minibuffer-refresh t)
- (defun jao-current--frame-id ()
- (propertize (cond ((and (fboundp 'jao-exwm-enabled)
- (jao-exwm-enabled-p)
- (not (bound-and-true-p jao-exwm--use-afio))
- (boundp 'exwm-workspace-current-index))
- (format "F%s" exwm-workspace-current-index))
- (t jao-afio-use-frames (or (jao-afio-frame-name) ""))
- (t (format "%s" (or (jao-afio-frame-no) ""))))
- 'face 'font-lock-warning-face))
- (jao-minibuffer-add-variable '(jao-current--frame-id) 100)
- ;;; Writing and writing modes
- ;;;; copyright notices
- (setq copyright-year-ranges t)
- (add-hook 'write-file-functions 'copyright-update)
- ;;;; indent on yank
- (defvar jao-auto-indent-modes
- '(emacs-lisp-mode ;; clojure-mode
- scheme-mode objc-mode
- tuareg-mode c-mode c++-mode
- tcl-mode sql-mode
- perl-mode cperl-mode
- java-mode jde-mode
- LaTeX-mode TeX-mode))
- (defadvice yank (after indent-region activate)
- (if (member major-mode jao-auto-indent-modes)
- (indent-region (region-beginning) (region-end) nil)))
- ;;;; org mode
- (require 'jao-custom-org)
- ;;;; blog
- (require 'jao-custom-blog)
- ;;;; text-ish mode settings
- ;; SENTENCES separated by just one space
- (setq sentence-end "[.?!][]\"')]*\\($\\|\t\\| \\)[ \t\n]*")
- (setq sentence-end-double-space t)
- ;; copy rectangle
- (defun kill-rectangle-save (start end)
- "Save the region-rectangle as the last killed one."
- (interactive "r")
- (require 'rect) ; Make sure killed-rectangle is defvar'ed.
- (setq killed-rectangle (extract-rectangle start end))
- (message "Rectangle saved"))
- ;; text mode, autoinserts and write hooks
- (setq default-major-mode 'text-mode)
- (add-hook 'text-mode-hook 'turn-on-auto-fill)
- ;;;; dictionaries
- (use-package dictionary
- :init (setq dictionary-use-single-buffer t
- dictionary-server "localhost")
- :commands (dictionary-search
- dictionary-match-words
- dictionary-lookup-definition
- dictionary
- dictionary-mouse-popup-matching-words
- dictionary-popup-matching-words
- dictionary-tooltip-mode
- global-dictionary-tooltip-mode)
- :bind (("C-c d" . dictionary-search)))
- (use-package ispell
- :custom ((ispell-personal-dictionary
- (expand-file-name "~/.emacs.d/ispell.dict"))))
- (use-package reverso
- :ensure t
- :init (setq reverso-languages '(english spanish french german)))
- ;; (use-package wordreference
- ;; :ensure t
- ;; :init (setq wordreference-target-lang "es"
- ;; wordreference-source-lang "en")
- ;; :bind (("C-c D" . wordreference-search)))
- ;;;; markdown
- (use-package markdown-mode
- :ensure t
- :init (setq markdown-command '("pandoc" "--from=markdown" "--to=html5")
- markdown-asymmetric-header t
- markdown-enable-wiki-links t
- markdown-wiki-link-fontify-missing t
- markdown-enable-math nil ;; toggle with M-x markdown-toggle-math
- markdown-link-space-sub-char "-"
- markdown-gfm-additional-languages '("whizzml" "flatline")
- markdown-hide-urls t
- markdown-hide-markup nil
- markdown-fontify-code-blocks-natively t
- markdown-fontify-whole-heading-line t
- markdown-unordered-list-item-prefix t)
- :hook (markdown-mode . outline-minor-mode)
- :config
- (dolist (u '("doc" "message" "notmuch"))
- (add-to-list 'markdown-uri-types u))
- (use-package markdown-toc :ensure t))
- ;; used by markdown mode to edit code blocks
- (use-package edit-indirect :ensure t)
- (dolist (ext '("\\.md$" "\\.markdown$"))
- (add-to-list 'auto-mode-alist (cons ext 'markdown-mode)))
- ;;;; TeX and LaTex
- (use-package tex-site
- :ensure auctex
- :init
- (setq TeX-auto-save t)
- (setq TeX-parse-self t)
- (setq TeX-a4-paper t)
- (setq TeX-auto-local ".tex-auto-local")
- ;; Preferred view format: dvi, ps, pdf, pdfs
- (setq TeX-view-format "pdf")
- (setq-default TeX-master "../main") ; nil to ask
- (setq TeX-view-program-selection
- ;; '((output-dvi "open")
- ;; (output-pdf "open")
- ;; (output-html "open"))
- '(((output-dvi has-no-display-manager) "dvi2tty")
- ((output-dvi style-pstricks) "dvips and gv")
- (output-dvi "xdvi")
- (output-pdf "xdg-open")
- (output-html "xdg-open")))
- ;; to make RefTeX faster for large documents, try these:
- (setq reftex-enable-partial-scans t)
- (setq reftex-save-parse-info t)
- (setq reftex-use-multiple-selection-buffers t)
- ;; to integrate with AUCTeX
- (setq reftex-plug-into-AUCTeX t)
- (setq reftex-ref-style-default-list
- '("Hyperref" "Varioref" "Fancyref"))
- (setq LaTeX-command "latex -shell-escape")
- (setq LaTeX-biblatex-use-Biber t)
- (setq bibtex-dialect 'biblatex)
- :config
- (add-hook 'TeX-after-compilation-finished-functions 'TeX-revert-document-buffer)
- (add-hook 'LaTeX-mode-hook 'turn-on-reftex))
- ;;; Browsing
- ;;;; variables
- (defvar jao-browse-doc-use-emacs-p t)
- (defvar jao-browse-url-function nil)
- (defvar jao-browse-url-external-function nil)
- ;;;; url around point
- (defun jao-url-around-point (&optional current-url)
- (or (and (fboundp 'w3m-anchor) (w3m-anchor))
- (shr-url-at-point nil)
- (ffap-url-at-point)
- (thing-at-point 'url)
- (when current-url
- (or (and (fboundp 'w3m-anchor) (w3m-anchor))
- (and (derived-mode-p 'eww-mode) (plist-get eww-data :url))))))
- (defun jao--url-prompt (&optional prefix)
- (let* ((def (jao-url-around-point t))
- (prompt (concat prefix "URL" (if def (format " (%s): " def) ": "))))
- (read-string prompt nil nil def)))
- ;;;; downloads using wget
- (defun jao-wget--get-title (filename)
- (or (and (derived-mode-p 'w3m-mode) (w3m-current-title))
- (plist-get eww-data :title)
- (and (not (string-blank-p (or filename "")))
- (subst-char-in-string ?- ? (capitalize (file-name-base filename))))))
- (defun jao-wget (url &optional user pwd)
- "Download URL using wget and kill a link for an org note."
- (let* ((def (file-name-nondirectory url))
- (pmt (format "Save %s to: " url))
- (read-file-name-function nil)
- (dest (expand-file-name
- (read-file-name pmt jao-sink-dir nil nil def)))
- (title (jao-wget--get-title dest))
- (src-url (or (jao-url-around-point t) (file-name-directory url)))
- (auth (when (and user pwd)
- `(,(format "--http-user=%s" user)
- ,(format "--http-password=%s" pwd))))
- (lnk (concat "doc:" (file-name-nondirectory dest))))
- (switch-to-buffer-other-window (get-buffer-create "*downloads*"))
- (erase-buffer)
- (kill-new (format "%s (from %s)"
- (org-link-make-string lnk title)
- (org-link-make-string src-url "here")))
- (apply 'make-term `("downloads" "wget" nil ,@auth "-O" ,dest ,url))))
- (defun jao-download (url &optional pws)
- "Download URL using wget"
- (interactive (list (jao--url-prompt)))
- (when url
- (let ((usr (and pws (read-string "Login name: ")))
- (pwd (and pws (read-passwd "Password: "))))
- (jao-wget url usr pwd))))
- (with-eval-after-load "embark"
- (define-key embark-url-map (kbd "d") #'jao-download))
- ;;;; video
- (defvar jao-video--url-rx
- (format "^https?://\\(?:www\\.\\)?%s/.+"
- (regexp-opt '("youtu.be"
- "youtube.com"
- "blip.tv"
- "vimeo.com"
- "infoq.com")
- t)))
- (defvar jao-video--ext-rx
- (format "^https?://.+/.+\\.%s" (regexp-opt '("mp3" "webm" "mp4"))))
- (defun jao-video--url-p (url)
- (or (string-match-p jao-video--url-rx url)
- (string-match-p jao-video--ext-rx url)))
- (defun jao--remote-run (url prg)
- (let ((args (format "%s %s" prg (shell-quote-argument url))))
- (start-process-shell-command prg nil args)))
- (defun jao--mpv (url &rest _args) (jao--remote-run url "mpv"))
- (defun jao--vlc (url &rest _args) (jao--remote-run url "vlc"))
- (defvar jao--video-player 'jao--mpv)
- (defun jao-view-video (url)
- "Tries to stream a video from the current or given URL"
- (interactive (list (jao--url-prompt "Video ")))
- (when url (funcall jao--video-player url)))
- (defun jao-maybe-view-video (url &rest _ignored)
- (interactive)
- (if (y-or-n-p "View video (y) or web page (n)? ")
- (jao-view-video url)
- (funcall jao-browse-url-function url)))
- ;;;; web browsers
- (defun jao-www--buffer-p (b)
- (with-current-buffer b
- (or (derived-mode-p 'w3m-mode 'eww-mode)
- (and (boundp 'exwm-class-name)
- (member exwm-class-name '("vlc" "mpv"))))))
- (require 'jao-custom-eww)
- ;; (require 'jao-custom-w3m)
- ;;;; browse-url
- (require 'browse-url)
- (setq browse-url-generic-program "~/bin/firehog")
- (defun jao-browse-with-external-browser (&rest url)
- "Browse with external hogging"
- (interactive "s")
- (let ((url (or (car url) (jao-url-around-point))))
- (if (not url)
- (message "No URL at point")
- (cond ((and (jao-exwm-enabled-p) (fboundp 'jao-exwm-firefox))
- (jao-exwm-firefox))
- (jao-river-enabled (jao-river-to-ws 2))
- (jao-sway-enabled (jao-sway-firefox)))
- (browse-url-generic url))))
- (setq jao-browse-url-external-function 'jao-browse-with-external-browser)
- (defun jao--fln (url)
- (shell-quote-argument
- (if (string-match "^[^:]*:/*?\\(/?[^/].*\\)" url)
- (match-string-no-properties 1 url)
- url)))
- (defun jao--browse-doc (url &rest _ignored)
- (let* ((url (substring-no-properties url))
- (file (jao--fln url)))
- (when file
- (unless (file-exists-p file)
- (error "File %s does not exist" file))
- (jao-open-doc file))))
- (defun jao--make-file-rx (exts)
- (format "file:/?/?.+\\.%s$" (regexp-opt exts)))
- (defvar jao--see-exts (jao--make-file-rx '("jpg" "jpeg" "png")))
- (defvar jao--doc-exts
- (jao--make-file-rx '("ps" "ps.gz" "pdf" "dvi" "djvu" "chm")))
- (defvar jao-browse-url-wget-exts
- '("ps" "pdf" "dvi" "djvu" "zip" "gz" "tgz"))
- (defvar jao-browse-external-domains
- '("github.com" "gitlab.com" "slack.com" "spotify.com" "drive.google.com"
- "meet.google.com" "docs.google.com" "x.com" "twitter.com"
- "t.com" "linkedin.com" "bigml.com" "slack.com" "zoom.us"))
- (defvar jao-browse--external-regexp
- (format "https?://.*%s\\(/.*\\)?"
- (regexp-opt jao-browse-external-domains)))
- (defun jao-wget--regexp ()
- (concat "^http[s]?://.+\\(\\."
- (mapconcat 'identity jao-browse-url-wget-exts "\\|\\.")
- "\\)\\'"))
- (defun jao--see (url &rest _r)
- (start-process-shell-command "see" nil (format "see %s" (jao--fln url))))
- (defun jao--find-file-other-window (url &rest _)
- (find-file-other-window (jao--fln url)))
- (defvar jao-browse--sound-rx
- (format "^https?://.*/.*\\.%s" (regexp-opt '("mp3" "flv"))))
- (defun jao-browse-play-sound-url (url &rest _)
- (jao-mpc-add-or-play-url url))
- (defun jao-browse-url-browse (&rest args)
- (apply jao-browse-url-function args))
- (setq browse-url-handlers
- `((jao-video--url-p . jao-maybe-view-video)
- (,jao--doc-exts . jao--browse-doc)
- (,jao--see-exts . jao--see)
- ("^file://?.+\\.html?$" . ,jao-browse-url-function)
- ("^file://?" . jao--find-file-other-window)
- (,jao-browse--external-regexp . ,jao-browse-url-external-function)
- ("^https?://.*\\.gotomeeting\\.com\\.*" . browse-url-chrome)
- (,jao-browse--sound-rx . jao-browse-play-sound-url)
- (,(jao-wget--regexp) . jao-download)
- ("." . jao-browse-url-browse)))
- (when (< emacs-major-version 28)
- (setf (alist-get 'jao-video--url-p browse-url-handlers nil t) nil)
- (setq browse-url-browser-function browse-url-handlers))
- ;;;; subscribe to rss using r2e
- (autoload 'View-quit "view")
- (defun jao-rss--find-url ()
- (save-excursion
- (when (derived-mode-p 'w3m-mode 'eww-mode)
- (if (fboundp 'w3m-view-source) (w3m-view-source) (eww-view-source)))
- (goto-char (point-min))
- (when (re-search-forward
- "type=\"application/\\(?:atom\\|rss\\)\\+xml\" +" nil t)
- (let ((url (save-excursion
- (when (re-search-forward
- "href=\"\\([^\n\"]+\\)\"" nil t)
- (match-string-no-properties 1))))
- (title (when (re-search-forward
- "\\(?:title=\"\\([^\n\"]+\\)\" +\\)" nil t)
- (match-string-no-properties 1))))
- (cond ((derived-mode-p 'w3m-view-mode) (w3m-view-source))
- ((string-match-p ".*\\*eww-source\\b.*" (buffer-name))
- (View-quit)))
- (when url (cons url (or title "")))))))
- (defun jao-rss2e-append (name url mbox)
- (with-current-buffer (find-file-noselect "~/.config/rss2email.cfg")
- (goto-char (point-max))
- (insert "[feed." name "]\nurl = " url)
- (insert "\nto = " mbox "+" name "@localhost")
- (insert "\nmaildir-mailbox = " mbox "\n\n")
- (save-buffer)))
- (defun jao-rss--feeds-dirs ()
- (mapcar (lambda (d) (cadr (split-string d "\\.")))
- (directory-files "~/.emacs.d/gnus/Mail/" nil "^feeds")))
- (defun jao-rss-subscribe (url)
- "Subscribe to a given RSS URL. If URL not given, look for it."
- (interactive (list (or (jao-url-around-point)
- (jao-rss--find-url)
- (read-string "Feed URL: "))))
- (let* ((url+title (ensure-list url))
- (url (car url+title))
- (title (cdr url+title)))
- (unless url (error "No feeds found"))
- (let ((url (if (string-match "^feed:" url) (substring url 5) url)))
- (when (y-or-n-p (format "Subscribe to <%s>? " url))
- (let* ((name (read-string "Feed name: " title))
- (cats (cons "prog" (jao-notmuch--subtags "feeds")))
- (cat (completing-read "Category: " cats nil t))
- (subs (format "r2e add %s '%s' feeds.%s@localhost"
- name url cat)))
- ;; (jao-rss2e-append name url cat)
- (shell-command-to-string subs)
- (shell-command (format "r2e run %s" name)))))))
- ;;; PDFs and other docs
- ;;;; open pdfs
- (use-package jao-pdf :demand t)
- (use-package saveplace-pdf-view
- :ensure t
- :demand t
- :after doc-view)
- (setq jao-open-doc-fun 'jao-find-or-open)
- (setq jao-org-open-pdf-fun 'jao-find-or-open)
- (defun jao-zathura-open (file page)
- (let ((id (jao-x11-search-window (jao-pdf-zathura-title-rx file))))
- (if (string-blank-p id)
- (progn
- (when jao-xmonad-enabled (jao-x11-goto-ws 2))
- (jao-shell-exec (jao-pdf-zathura-open-cmd file page)))
- (let* ((page (if page (format " && xdotool type %dg" page) ""))
- (cmd (format "xdotool windowactivate %s%s" id page)))
- (jao-shell-exec cmd t)))))
- (defun jao-x11-zathura-goto-org (&optional title no-ask)
- (let ((title (or title (jao-shell-string "xdotool"
- "getactivewindow"
- "getwindowname"))))
- (jao-org-open-from-zathura title no-ask)))
- (defun jao-find-or-open (file &optional page height)
- (cond ((and jao-browse-doc-use-emacs-p window-system)
- (let* ((buffs (buffer-list))
- (b (catch 'done
- (while buffs
- (when (string-equal (buffer-file-name (car buffs)) file)
- (throw 'done (car buffs)))
- (setq buffs (cdr buffs))))))
- (jao-afio-goto-docs)
- (if b (pop-to-buffer b) (find-file file))
- (when page (jao-doc-view-goto-page page height))))
- (jao-river-enabled (jao-river-open-with-zathura file page))
- (jao-sway-enabled (jao-sway-open-with-zathura file page))
- (t (jao-zathura-open file page))))
- (defun jao-open-doc (&optional file page height)
- (interactive)
- (when-let (file (or file
- (read-file-name "Document: "
- (concat jao-org-dir "/doc/"))))
- (funcall jao-open-doc-fun file page height)))
- (defun jao-select-pdf ()
- (interactive)
- (jao-buffer-same-mode '(pdf-view-mode doc-view-mode)
- #'jao-afio-goto-docs))
- (defun jao-open-with-zathura ()
- (interactive)
- (when-let (f buffer-file-name)
- (let ((p (jao-doc-view-current-page)))
- (cond (jao-river-enabled (jao-river-open-with-zathura f p))
- (jao-sway-enabled (jao-sway-open-with-zathura f p))
- (t (jao-zathura-open f p))))))
- ;; doc:// links for browse-url
- (defun jao-open-doc-url (url &rest _)
- (when (string-match "doc://\\([^?]+\\)\\(\\?.*\\)?" url)
- (let ((file (match-string 1 url))
- (page (when-let* ((qs (match-string 2 url))
- (long (> (length qs) 1))
- (ps (url-parse-query-string (substring qs 1)))
- (pn (cadr (assoc "page" ps))))
- (string-to-number pn))))
- (jao-open-doc (expand-file-name (concat "doc/" file) jao-org-dir) page))))
- (add-to-list 'browse-url-handlers (cons "^doc://.+" 'jao-open-doc-url))
- ;;;; doc-view
- (use-package doc-view
- :init
- (setq doc-view-cache-directory "~/.emacs.d/cache/docview"
- doc-view-resolution 110
- doc-view-continuous t
- doc-view-conversion-refresh-interval 1
- doc-view-mupdf-use-svg t)
- :hook ((doc-view-mode . jao-doc-session-mark))
- :bind (:map doc-view-mode-map
- ("j" . doc-view-next-line-or-next-page)
- ("J" . doc-view-scroll-up-or-next-page)
- ("k" . doc-view-previous-line-or-previous-page)
- ("K" . doc-view-scroll-down-or-previous-page)
- ("z" . jao-open-with-zathura)))
- (use-package jao-doc-session :demand t)
- (use-package jao-doc-view
- :demand t
- :bind (:map doc-view-mode-map
- ("b" . jao-doc-view-back)
- ("B" . jao-doc-view-forward)
- ("S" . jao-doc-session-save)
- ("u" . jao-doc-view-visit-url)))
- ;;;; epub
- (use-package nov
- :ensure t
- :after doc-view
- :init (setq nov-variable-pitch t
- nov-text-width nil)
- :config
- (add-to-list 'auto-mode-alist '("\\.epub\\'" . nov-mode))
- (defun jao-nov-register-session ()
- (jao-doc-session-mark nov-file-name))
- (add-hook 'nov-mode-hook #'jao-nov-register-session))
- ;;;; transient
- (defun jao-org-pdf-goto-org-linking ()
- (interactive)
- (jao-org-pdf-goto-org 4))
- (jao-transient-major-mode doc-view
- ["Notes"
- ("o" "notes file" jao-org-pdf-goto-org)
- ("O" "notes file, linking" jao-org-pdf-goto-org-linking)]
- ["Navigation"
- ("b" "back jump" jao-doc-view-back)
- ("B" "forward jump" jao-doc-view-back)
- ("u" "visit URL" jao-doc-view-visit-url)]
- ["Slices"
- ("cb" "bounding box" doc-view-set-slice-from-bounding-box)
- ("cm" "using mouse" doc-view-set-slice-using-mouse)]
- ["Session"
- ("s" "load session" jao-afio-open-pdf-session)
- ("S" "save session" jao-doc-session-save)
- ("d" "visit cache directory" doc-view-dired-cache)]
- ["External viewers"
- ("z" "open with zathura" jao-open-with-zathura)])
- (with-eval-after-load "pdf-view"
- (jao-transient-major-mode pdf-view
- ["Notes"
- ("o" "notes file" jao-org-pdf-goto-org)
- ("O" "notes file, linking" jao-org-pdf-goto-org-linking)]
- ["Navigation"
- ("b" "back jump" pdf-history-backward)
- ("f" "forward jump" pdf-history-forward)]
- ["Session"
- ("s" "load session" jao-afio-open-pdf-session)
- ("S" "save session" jao-doc-session-save)]
- ["External viewers"
- ("z" "open with zathura" jao-open-with-zathura)]))
- ;; (transient-get-suffix 'jao-transient-pdf-view '(0 -1))
- ;;; Email
- (require 'jao-custom-email)
- ;;; Shells and terms
- ;;;; shell modes
- (setq sh-basic-offset 2)
- ;; translates ANSI colors into text-properties, for eshell
- (autoload 'ansi-color-for-comint-mode-on "ansi-color" nil t)
- (add-hook 'shell-mode-hook 'ansi-color-for-comint-mode-on)
- (defvar jao-use-vterm nil)
- (defvar jao-use-eat nil)
- (add-to-list 'display-buffer-alist
- '("\\*Async Shell Command\\*" (display-buffer-no-window)))
- ;;;; eat
- (use-package eat
- :ensure t
- :commands jao-exec-in-term
- :init (setq jao-use-eat t
- eat-kill-buffer-on-exit t
- eat-enable-yank-to-terminal t)
- :hook ((eshell-mode . eat-eshell-mode)
- (eshell-mode . eat-eshell-visual-command-mode))
- :diminish ((eat-eshell-mode . "")))
- ;;;; term
- (defvar-local jao-term--cmd nil)
- (defun jao-term--find (cmd)
- (seq-find (lambda (b)
- (with-current-buffer b
- (and (derived-mode-p 'eat-mode 'term-mode 'vterm-mode)
- (string= (or jao-term--cmd "") cmd))))
- (buffer-list)))
- (defun jao-exec-in-term (cmd &optional name)
- (interactive "SCommand")
- (require 'eat nil t)
- (cond ((and jao-use-vterm (fboundp 'jao-exec-in-vterm))
- (jao-exec-in-vterm cmd name))
- (jao-use-eat (let ((eat-term-name "xterm-256color"))
- (with-current-buffer (eat cmd t)
- (setq-local jao-term--cmd cmd))))
- (t (ansi-term "bash" name)
- (set-process-sentinel (get-buffer-process (current-buffer))
- (lambda (process event)
- (when (string= event "finished\n")
- (kill-buffer (process-buffer process)))))
- (setq-local jao-term--cmd cmd)
- (term-send-string nil (concat cmd " ; exit\n")))))
- (defmacro jao-def-exec-in-term (name cmd &rest prelude)
- `(defun ,(intern (format "jao-term-%s" name)) (&optional term)
- (interactive "P")
- ,@prelude
- (let ((jao-use-vterm (if term (not jao-use-vterm) jao-use-vterm)))
- (if-let ((b (jao-term--find ,cmd)))
- (pop-to-buffer b)
- (jao-exec-in-term ,cmd ,(format "*%s*" name))))))
- ;;;; eshell
- ;;;;; basic custom
- (use-package eshell
- :init
- (setq eshell-directory-name "~/.emacs.d/eshell"
- eshell-hist-ignoredups 'erase
- eshell-history-size 1000000
- eshell-error-if-no-glob nil)
- (defun jao-eshell--outline ()
- (setq-local outline-regexp eshell-prompt-regexp))
- :config (setq eshell-prompt-repeat-map nil)
- :hook (eshell-mode . jao-eshell--outline))
- ;;;;; colors
- (autoload 'ansi-color-apply "ansi-color")
- ;; (add-hook 'eshell-preoutput-filter-functions 'ansi-color-filter-apply)
- (add-hook 'eshell-preoutput-filter-functions 'ansi-color-apply)
- (use-package eshell-syntax-highlighting
- :after esh-mode
- :ensure t
- :config
- ;; Enable in all Eshell buffers.
- (eshell-syntax-highlighting-global-mode +1))
- ;;;;; visual commands
- (require 'em-term)
- (dolist (c '("editor" "more" "wget" "dict" "vim" "links" "w3m" "guile"
- "zmore" "pager" "aptitude" "su" "htop" "top"
- "screen" "whizzml" "iex" "spt"))
- (add-to-list 'eshell-visual-commands c))
- (setq eshell-visual-subcommands '(("git" "log" "diff" "show")
- ("sudo" "vim")
- ("rebar3" "shell"))
- eshell-destroy-buffer-when-process-dies nil
- eshell-escape-control-x t)
- ;;;;; bol
- (defun jao-eshell-maybe-bol ()
- (interactive)
- (let ((p (point)))
- (eshell-bol)
- (if (= p (point))
- (beginning-of-line))))
- ;;;;; prompt
- ;; tracking git repos
- (defun jao-eshell--git-dirty ()
- (shell-command-to-string "git diff-index --quiet HEAD -- || echo -n '*'"))
- (use-package git-ps1-mode
- :ensure t
- :init (setq git-ps1-mode-showupstream "1"
- git-ps1-mode-showdirtystate "1"))
- (defun jao-eshell--git-info ()
- (if (fboundp 'git-ps1-mode-get-current)
- (git-ps1-mode-get-current)
- (let ((desc (shell-command-to-string "git branch --no-color")))
- (when (string-match "^* \\(\\<.+\\>\\)" desc)
- (format "%s%s" (match-string 1 desc) (jao-eshell--git-dirty))))))
- (defun jao-eshell--git-current-branch (suffix)
- (let ((desc (or (jao-eshell--git-info) "")))
- (cond ((and (string-empty-p desc) suffix) (format " (%s)" suffix))
- ((string-empty-p (or suffix "")) (format " (%s)" desc))
- (t (format " (%s %s)" desc suffix)))))
- (defun jao-eshell--virtualenv ()
- (let ((venv (getenv "VIRTUAL_ENV")))
- (when (and venv (string-match ".*/\\([^/]+\\)/$" venv))
- (match-string-no-properties 1 venv))))
- (defun jao-eshell-prompt-function ()
- (let* ((venv (jao-eshell--virtualenv))
- (venv (if venv (format "%s" venv) "")))
- (concat (abbreviate-file-name (eshell/pwd))
- (jao-eshell--git-current-branch venv)
- (if (= (user-uid) 0) " # " " $ "))))
- (setq eshell-prompt-function 'jao-eshell-prompt-function)
- ;;;;; in-term
- (defun eshell/in-term (prog &rest args)
- (switch-to-buffer
- (apply #'make-term (format "in-term %s %s" prog args) prog nil args))
- (term-mode)
- (term-char-mode))
- ;;;;; dir navigation
- (use-package eshell-up
- :ensure t
- :config (setq eshell-up-print-parent-dir t))
- (use-package eshell-autojump :ensure t)
- ;;;;; completion
- (defun jao-eshell-completion-capf ()
- (let* ((b (save-excursion (eshell-bol) (point)))
- (c (bash-completion-dynamic-complete-nocomint b (point) t)))
- (when (and c (listp c))
- (append c '(:exclusive no)))))
- (defun jao-eshell--set-up-completion ()
- (setq-local completion-styles '(basic partial-completion)
- completion-at-point-functions
- '(jao-eshell-completion-capf
- pcomplete-completions-at-point t)))
- (use-package bash-completion
- :ensure t
- :hook (eshell-mode . jao-eshell--set-up-completion))
- ;;;;; toggle
- (use-package jao-eshell-here
- :demand t
- :config (jao-define-attached-buffer "^\\*eshell" 0.5)
- :bind (("<f1>" . jao-eshell-here-toggle)
- ("C-<f1>" . jao-eshell-here-toggle-new)))
- ;;;;; workarounds
- ;; at some point, bash completion started insertig the TAB
- ;; after the commands ends
- (defun jao-eshell--clean-prompt ()
- (eshell-bol)
- (ignore-errors (kill-line)))
- (add-hook 'eshell-after-prompt-hook 'jao-eshell--clean-prompt)
- ;;;;; keybindings
- (defun jao-eshell--kbds ()
- (define-key eshell-mode-map "\C-a" 'jao-eshell-maybe-bol)
- (define-key eshell-mode-map "\C-ci" 'consult-outline))
- (jao-eshell--kbds)
- ;;; Version control and CI
- ;;;; vc options
- (setq vc-follow-symlinks t)
- (setq auto-revert-check-vc-info nil)
- ;;;; diff fringe indicators (diff-hl)
- (use-package diff-hl
- :ensure t
- :custom ((diff-hl-draw-borders nil)
- (diff-hl-side 'right)
- (diff-hl-margin-symbols-alist
- '((insert . "█")
- (delete . "█")
- (change . "█")
- (unknown . "█")
- (ignored . "█"))))
- :config
- (map-keymap (lambda (_k cmd)
- (put cmd 'repeat-map 'diff-hl-command-map))
- diff-hl-command-map)
- (add-hook 'magit-post-refresh-hook 'diff-hl-magit-post-refresh))
- (global-diff-hl-mode 1)
- (unless (display-graphic-p) (diff-hl-margin-mode 1))
- ;;;; magit/forge
- (use-package magit
- :ensure t
- :commands magit-status
- :init
- (setq magit-status-initial-section nil
- magit-define-global-key-bindings nil
- magit-completing-read-function 'magit-builtin-completing-read
- magit-display-buffer-function
- 'magit-display-buffer-fullcolumn-most-v1
- magit-delete-by-moving-to-trash nil
- magit-last-seen-setup-instructions "1.4.0"
- magit-log-edit-confirm-cancellation t
- magit-omit-untracked-dir-contents t
- magit-process-connection-type nil
- magit-push-always-verify nil
- magit-repository-directories
- '(("/home/jao/usr/bigml" . 2)
- ("/home/jao/usr/jao" . 3)
- ("/usr/local/src" . 1))
- magit-save-repository-buffers 'dontask
- magit-section-visibility-indicator '("…" . t)
- magit-status-buffer-switch-function 'switch-to-buffer
- magit-status-show-hashes-in-headers t))
- ;;;; forge
- (use-package forge
- :ensure t
- :after magit
- :init
- (setq forge-topic-list-limit (cons 100 -1)
- forge-pull-notifications nil)
- :config
- (use-package embark-vc :ensure t)
- :bind ((:map forge-topic-mode-map ("M-w" . copy-region-as-kill))))
- ;;;; code reviews
- (use-package code-review
- :disabled t
- :ensure t
- :after forge
- :bind (:map magit-status-mode-map
- ("C-c C-r" . code-review-forge-pr-at-point)))
- ;;;; other git packages
- (use-package git-timemachine :ensure t)
- (use-package consult-git-log-grep
- :ensure t
- :custom (consult-git-log-grep-open-function #'magit-show-commit)
- :bind (("C-c K" . consult-git-grep)))
- ;; git config --local git-link.remote / git-link.branch
- (use-package git-link :ensure t)
- (use-package git-modes :ensure t)
- ;;;; jenkins
- (use-package jenkins
- :ensure t
- :init
- ;; one also needs jenkins-api-token, jenkins-username and jenkins-url
- ;; optionally: jenkins-colwidth-id, jenkins-colwidth-last-status
- (setq jenkins-colwidth-name 35)
- :config
- (defun jao-jenkins-first-job (&rest _)
- (interactive)
- (goto-char (point-min))
- (when (re-search-forward "^- Job" nil t)
- (goto-char (match-beginning 0))))
- (add-hook 'jenkins-job-view-mode-hook #'jao-jenkins-first-job)
- (advice-add 'jenkins-job-render :after #'jao-jenkins-first-job)
- (defun jenkins-refresh-console-output ()
- (interactive)
- (let ((n (buffer-name)))
- (when (string-match "\\*jenkins-console-\\([^-]+\\)-\\(.+\\)\\*$" n)
- (jenkins-get-console-output (match-string 1 n) (match-string 2 n))
- (goto-char (point-max)))))
- :bind (:map jenkins-job-view-mode-map
- (("n" . next-line)
- ("p" . previous-line)
- ("f" . jao-jenkins-first-job)
- ("RET" . jenkins--show-console-output-from-job-screen))
- :map jenkins-console-output-mode-map
- (("n" . next-line)
- ("p" . previous-line)
- ("g" . jenkins-refresh-console-output))))
- ;;; Programming
- ;;;; automatic modes
- (add-to-list 'auto-mode-alist '("\\.mix\\'" . hexl-mode))
- (add-to-list 'auto-mode-alist '("\\.m4\\'" . m4-mode))
- (add-to-list 'auto-mode-alist '("\\.am\\'" . makefile-mode))
- (add-to-list 'auto-mode-alist '("\\.pl\\'\\|\\.pm\\'" . cperl-mode))
- ;;;; symbol overlay
- (use-package symbol-overlay
- :ensure t
- :config
- (defun jao-symbol-reveal (&rest _)
- (when outline-minor-mode (outline-show-entry)))
- (advice-add 'symbol-overlay-basic-jump :after 'jao-symbol-reveal)
- (defun jao-symbol-put-and-next ()
- (interactive)
- (symbol-overlay-put)
- (symbol-overlay-jump-next))
- (defun jao-symbol-put-and-prev ()
- (interactive)
- (symbol-overlay-put)
- (symbol-overlay-jump-prev))
- :bind (:map prog-mode-map (("M-i" . symbol-overlay-put)
- ("M-n" . jao-symbol-put-and-next)
- ("M-p" . jao-symbol-put-and-prev)))
- :hook (prog-mode . symbol-overlay-mode)
- :diminish " ^")
- ;;;; eglot
- (use-package eglot
- :bind (:map eglot-mode-map (("C-h ." . jao-eldoc-toggle))))
- ;;;; paredit and parens
- (require 'paren)
- (show-paren-mode t)
- (setq show-paren-context-when-offscreen t
- show-paren-when-point-inside-paren nil)
- (use-package paredit
- :ensure t
- :commands paredit-mode
- :hook ((pie-mode . paredit-mode)
- (scheme-mode . paredit-mode)
- (clojure-mode . paredit-mode)
- (emacs-lisp-mode . paredit-mode)
- ;; (eval-expression-minibuffer-setup . paredit-mode)
- (lisp-interaction-mode . disable-paredit-mode))
- :diminish ((paredit-mode . " þ")))
- ;;;; diff/ediff
- (setq ediff-split-window-function 'split-window-horizontally)
- (setq ediff-make-buffers-readonly-at-startup nil)
- (setq ediff-window-setup-function 'ediff-setup-windows-plain)
- (setq ediff-keep-variants nil)
- ;;;; compilation
- ;;;;; compilation mode options
- (require 'compile)
- (setq compilation-scroll-output t)
- (setq compilation-error-regexp-alist
- (remove 'omake compilation-error-regexp-alist))
- ;; (add-hook 'compilation-mode-hook #'visual-line-mode)
- ;;;;; mode line (no "Compiling"!)
- (require 'compile)
- (diminish 'compilation-minor-mode " ‡")
- (when (< emacs-major-version 27)
- (setcdr (assq 'compilation-in-progress minor-mode-alist) '(" ‡")))
- (when (> emacs-major-version 26)
- (setcdr (assq 'compilation-in-progress mode-line-modes) '("‡ ")))
- ;;;;; colorizing compilation buffer
- (setq compilation-message-face 'default)
- (require 'ansi-color)
- (defun endless/colorize-compilation ()
- "Colorize from `compilation-filter-start' to `point'."
- (let ((inhibit-read-only t))
- (ansi-color-apply-on-region
- compilation-filter-start (point))))
- (add-hook 'compilation-filter-hook #'endless/colorize-compilation)
- ;;;;; compilation commands
- (use-package jao-compilation
- :commands jao-compilation-setup
- :bind (("C-c C" . compile)
- ("C-c c" . jao-compile)))
- (jao-compilation-setup)
- ;;;;; next error
- (setq next-error-find-buffer-function
- #'next-error-buffer-on-selected-frame
- next-error-verbose t)
- ;;;; flymake
- (use-package flymake
- :ensure t
- :custom ((flymake-mode-line-format '(" " flymake-mode-line-counters)))
- :config
- (jao-define-attached-buffer "^\\*Flymake diagnostics .*\\*\\'")
- (transient-define-prefix jao-transient-flymake ()
- ["Flymake"
- ("d" "show diagnostics" flymake-show-buffer-diagnostics)
- ("i" "show diagnostic" flymake-show-diagnostic)
- ("n" "next error" flymake-goto-next-error)
- ("p" "previous error" flymake-goto-prev-error)
- ("c" "consult flymake" consult-flymake)])
- :bind (:map flymake-mode-map (("M-m" . jao-transient-flymake))))
- ;;;; workarounds
- (setq c-type-finder-time-slot nil)
- ;;;; outline minor mode
- (use-package outline
- :init (setq outline-minor-mode-use-buttons nil
- outline-minor-mode-use-margins nil
- outline-minor-mode-cycle t))
- (defvar-local jao-outline-folded nil)
- (dolist (v '(4 5 outline-show-only-headings))
- (add-to-list 'safe-local-variable-values `(outline-default-state . ,v)))
- (defun jao-outline-minor-mode-hide-all (&optional arg)
- (interactive "P")
- (outline-hide-sublevels (if arg 5 4)))
- (defun jao-outline-minor-expand-all ()
- (when jao-outline-minor-mode (outline-show-all)))
- (defun jao-outline-minor-mode-toogle-fold (&optional arg)
- (interactive "P")
- (if (setq jao-outline-folded (not jao-outline-folded))
- (jao-outline-minor-mode-hide-all arg)
- (jao-outline-minor-expand-all)))
- (use-package outline-minor-faces
- :ensure t
- :after outline)
- (define-minor-mode jao-outline-minor-mode
- "Minor outline mode for programming languages"
- :lighter ""
- :keymap `((,(kbd "C-c C-n") . outline-next-visible-heading)
- (,(kbd "C-c C-p") . outline-previous-visible-heading)
- (,(kbd "C-c o") . consult-outline)
- (,(kbd "<f3>") . jao-outline-minor-mode-toogle-fold))
- (if jao-outline-minor-mode
- (progn (setq-local outline-level #'outline-level
- outline-regexp (format "[%s]\\{3,\\} " comment-start))
- (outline-minor-mode 1)
- (outline-minor-faces-mode 1))
- (outline-minor-mode -1)
- (outline-minor-faces-mode -1)))
- (add-hook 'find-function-after-hook #'jao-outline-minor-expand-all)
- ;;; Programming languages
- ;;;; Elisp
- (add-hook 'emacs-lisp-mode-hook #'jao-outline-minor-mode)
- (use-package edit-list :ensure t)
- (use-package package-lint :ensure t)
- ;; (use-package tree-inspector :ensure t)
- (defun elisp-disassemble (function)
- (interactive (list (function-called-at-point)))
- (disassemble function))
- (defun elisp-pp (sexp)
- (with-output-to-temp-buffer "*Pp Eval Output*"
- (pp sexp)
- (with-current-buffer standard-output
- (emacs-lisp-mode))))
- (defun elisp-macroexpand (form)
- (interactive (list (form-at-point 'sexp)))
- (elisp-pp (macroexpand form)))
- (defun elisp-macroexpand-all (form)
- (interactive (list (form-at-point 'sexp)))
- (elisp-pp (macroexpand-all form)))
- (defun elisp-find-definition (name)
- (interactive (list (thing-at-point 'symbol)))
- (cond (name
- (let ((symbol (intern-soft name))
- (search (lambda (fun sym)
- (let* ((r (save-excursion (funcall fun sym)))
- (buffer (car r))
- (point (cdr r)))
- (cond ((not point)
- (error "Found no definition for %s in %s"
- name buffer))
- (t
- (switch-to-buffer buffer)
- (goto-char point)
- (recenter 1)))))))
- (cond ((fboundp symbol)
- (xref-push-marker-stack)
- (funcall search 'find-function-noselect symbol))
- ((boundp symbol)
- (xref-push-marker-stack)
- (funcall search 'find-variable-noselect symbol))
- (t
- (message "Symbol not bound: %S" symbol)))))
- (t (message "No symbol at point"))))
- (defun elisp-bytecompile-and-load ()
- (interactive)
- (or buffer-file-name
- (error "The buffer must be saved in a file first"))
- (require 'bytecomp)
- ;; Recompile if file or buffer has changed since last compilation.
- (when (and (buffer-modified-p)
- (y-or-n-p (format "save buffer %s first? " (buffer-name))))
- (save-buffer))
- (let ((filename (expand-file-name buffer-file-name)))
- (with-temp-buffer
- (byte-compile-file filename))))
- (use-package elisp-mode
- :bind (:map emacs-lisp-mode-map
- (("C-c C-M" . emacs-lisp-macroexpand)
- ("C-c C-m" . elisp-macroexpand-all)
- ("C-c C-k" . elisp-bytecompile-and-load)
- ;; ("C-c C-p" . pp-eval-last-sexp)
- ("M-." . elisp-find-definition)
- ("M-," . pop-tag-mark)
- ("C-c <" . lc-show-package-summary))))
- ;;;; Clojure
- (use-package clojure-mode
- :ensure t
- :config
- (defun jao-clojure--fix-things ()
- (setq-local completion-styles '(basic partial-completion emacs22))
- (eldoc-mode 1)
- (setq mode-name "λ"))
- :hook (clojure-mode . jao-clojure--fix-things))
- (use-package cider
- :ensure t
- :commands cider-mode
- :init (setq cider-annotate-completion-candidates t
- cider-auto-select-error-buffer nil
- cider-auto-select-test-report-buffer nil
- cider-eldoc-display-for-symbol-at-point t
- cider-eldoc-ns-function #'identity ;; #'cider-last-ns-segment
- cider-enrich-classpath nil
- cider-lein-parameters "repl :headless :host localhost"
- cider-mode-line " ÷"
- cider-prompt-for-symbol nil
- cider-repl-history-file
- (expand-file-name "~/.emacs.d/cache/cider.history")
- cider-repl-pop-to-buffer-on-connect nil
- cider-repl-use-pretty-printing t
- cider-show-error-buffer 'except-in-repl
- cider-test-show-report-on-success nil
- cider-use-fringe-indicators nil
- cider-use-overlays nil
- clojure-docstring-fill-column 72
- nrepl-prompt-to-kill-server-buffer-on-quit nil)
- :bind (("<f3>" . cider-selector)))
- (with-eval-after-load "cider-test"
- (advice-add 'cider-scale-background-color :override
- (lambda () (frame-parameter nil 'background-color)))
- (setq cider-test-items-background-color
- (frame-parameter nil 'background-color)))
- (use-package cider-macroexpansion
- :after cider
- :diminish " µ")
- ;;;; Geiser
- (defun jao-org--set-geiser-impl () (setq-local geiser-repl--impl 'guile))
- (add-hook 'org-mode-hook #'jao-org--set-geiser-impl)
- (jao-load-path "geiser")
- (use-package geiser
- :init
- (setq geiser-repl-history-filename "~/.emacs.d/cache/geiser-history"
- geiser-repl-startup-time 20000
- geiser-debug-auto-display-images t
- geiser-log-verbose t)
- :config
- (dolist (m '(geiser-repl-mode geiser-doc-mode geiser-debug-mode))
- (jao-define-attached-buffer `(major-mode . ,m) 0.4)))
- (jao-load-path "geiser-guile")
- (use-package geiser-guile)
- (jao-load-path "geiser-chez")
- (use-package geiser-chez)
- ;; (jao-load-path "geiser/mit")
- ;; (use-package geiser-mit)
- ;; (jao-load-path "geiser/chicken")
- ;; (use-package geiser-chicken)
- ;; (jao-load-path "geiser/chibi")
- ;; (use-package geiser-chibi)
- ;; (jao-load-path "geiser/gambit")
- ;; (use-package geiser-gambit)
- ;; (jao-load-path "geiser/gauche")
- ;; (use-package geiser-gauche)
- ;;;; Haskell
- ;;;;; packages
- ;; (jao-load-path "haskell-mode")
- (use-package haskell-mode
- :ensure t
- :custom
- ((inferior-haskell-find-project-root t)
- (haskell-check-remember-last-command-p nil)
- (haskell-completing-read-function 'completing-read)
- (haskell-font-lock-symbols nil)
- (haskell-hoogle-command "hoogle")
- (haskell-interactive-popup-errors t)
- (haskell-process-auto-import-loaded-modules t)
- (haskell-process-log t)
- (haskell-process-suggest-remove-import-lines t)
- (haskell-process-suggest-hoogle-imports t)
- (haskell-process-type 'cabal-repl)
- (haskell-process-use-presentation-mode t)
- (haskell-stylish-on-save nil)
- (haskell-tags-on-save t))
- :init
- ;; For use with M-x align
- (require 'align)
- (add-to-list 'align-rules-list
- '(haskell-types
- (regexp . "\\(\\s-+\\)\\(::\\|∷\\)\\s-+")
- (modes quote (haskell-mode haskell-literate-mode))))
- (add-to-list 'align-rules-list
- '(haskell-assignment
- (regexp . "\\(\\s-+\\)=\\s-+")
- (modes quote (haskell-mode haskell-literate-mode))))
- (add-to-list 'align-rules-list
- '(haskell-arrows
- (regexp . "\\(\\s-+\\)\\(->\\|→\\)\\s-+")
- (modes quote (haskell-mode haskell-literate-mode))))
- (add-to-list 'align-rules-list
- '(haskell-left-arrows
- (regexp . "\\(\\s-+\\)\\(<-\\|←\\)\\s-+")
- (modes quote (haskell-mode haskell-literate-mode))))
- :config
- (defun jao-haskell-hoogle (no-info)
- (interactive "P")
- (haskell-hoogle (format "%s" (haskell-ident-at-point)) (not no-info)))
- (put 'haskell-process-args-cabal-repl
- 'safe-local-variable
- (apply-partially #'seq-every-p #'stringp))
- (defun jao-haskell-eldoc (cb)
- (let ((msg (or (haskell-doc-current-info--interaction t)
- (haskell-doc-sym-doc (haskell-ident-at-point))
- "")))
- (funcall cb (replace-regexp-in-string "[\n ]+" " " msg))))
- (setq tags-revert-without-query t)
- (defun jao-haskell-mode ()
- (require 'haskell-doc)
- (setq-local eldoc-documentation-function 'eldoc-documentation-default
- eldoc-documentation-functions '(jao-haskell-eldoc))
- (eldoc-mode))
- (dolist (h '(jao-haskell-mode
- haskell-decl-scan-mode
- haskell-indentation-mode
- interactive-haskell-mode))
- (add-hook 'haskell-mode-hook h))
- (add-hook 'haskell-presentation-mode-hook (lambda () (whitespace-mode -1)))
- :bind (:map haskell-mode-map
- (("C-c C-d" . jao-haskell-hoogle)
- ("C-c C-s" . haskell-session-change-target)
- ("C-c h" . haskell-hoogle)
- ("C-c t" . haskell-doc-show-type)
- ("C-c C-e" . haskell-command-insert-language-pragma)
- ("C-M-n" . flymake-goto-next-error)
- ("C-M-p" . flymake-goto-prev-error)
- ("<f3>" . haskell-session-kill))))
- (use-package hlint-refactor
- :ensure t
- :after haskell-mode
- :hook ((haskell-mode . hlint-refactor-mode))
- :bind (:map haskell-mode-map (("C-M-h" . 'hlint-refactor-refactor-at-point)
- ("C-M-S-h" . 'hlint-refactor-refactor-buffer)))
- :diminish)
- (use-package flymake-hlint
- :ensure t
- :after haskell-mode
- :hook ((haskell-mode . flymake-hlint-load)))
- (use-package consult-hoogle
- :ensure t)
- (require 'haskell)
- (diminish 'interactive-haskell-mode " λ")
- (diminish 'haskell-doc-mode)
- (diminish 'haskell-decl-scan-mode)
- (jao-define-attached-buffer "\\*hoogle\\*.*")
- (jao-define-attached-buffer '(major-mode . haskell-interactive-mode) 0.33)
- (jao-define-attached-buffer '(major-mode . haskell-presentation-mode) 0.25)
- ;;;;; transient
- (jao-transient-major-mode haskell
- ["Imports"
- ("in" "Navigate imports" haskell-navigate-imports)
- ("if" "Format imports" haskell-mode-format-imports)
- ("is" "Sort imports" haskell-sort-imports)
- ("ia" "Align imports" haskell-align-imports)]
- ["Session"
- ("s" "Change the session's target" haskell-session-change-target)]
- ["Code"
- ("e" "insert language pragma" haskell-command-insert-language-pragma)
- ("v" "visit cabal file" haskell-cabal-visit-file)
- ("h" "hoogle" jao-haskell-hoogle)
- ("t" "show type" haskell-doc-show-type)]
- ["Flymake"
- ("n" "next error" flymake-goto-next-error)
- ("p" "previous error" flymake-goto-prev-error)])
- ;;;; Pie
- (jao-load-path "pie")
- (use-package pie
- :demand t
- :commands (pie-mode))
- ;;;; Prolog
- ;; (use-package ediprolog :ensure t)
- (use-package prolog
- :ensure t
- :commands (run-prolog prolog-mode mercury-mode)
- :init (progn
- (setq prolog-system 'swi)
- (add-to-list 'auto-mode-alist '("\\.pl$" . prolog-mode))
- (setq prolog-consult-string '((t "[%f].")))
- (setq prolog-program-name
- '(((getenv "EPROLOG") (eval (getenv "EPROLOG")))
- (eclipse "eclipse")
- (mercury nil)
- (sicstus "sicstus")
- (swi "swipl")
- (t "prolog")))))
- ;;;; Python
- (use-package virtualenvwrapper
- :ensure t
- :config
- (venv-initialize-eshell)
- (jao-compilation-env "VIRTUAL_ENV"))
- ;;; Text/data formats
- ;;;; json
- (use-package json-mode :ensure t)
- ;;;; yaml
- (use-package yaml-mode :disabled t :ensure t)
- ;;; Graphics
- ;;;; images
- (setq image-use-external-converter t
- image-cache-eviction-delay 120)
- (setq widget-image-enable nil)
- ;;;; gnuplot
- (use-package gnuplot
- :disabled t
- :ensure t
- :commands (gnuplot-mode gnuplot-make-buffer)
- :init (add-to-list 'auto-mode-alist '("\\.gp$" . gnuplot-mode)))
- ;;; Network
- ;;;; nm applet
- (jao-shell-def-exec jao-nm-applet "nm-applet")
- (defun jao-toggle-nm-applet ()
- (interactive)
- (or (jao-shell-kill-p "nm-applet") (jao-nm-applet)))
- ;;;; bluetooth
- (use-package bluetooth :ensure t)
- ;;;; vpn
- (use-package jao-mullvad :demand t)
- ;;;; ssh
- (use-package tramp)
- (defun jao-tramp-hosts ()
- (seq-uniq
- (mapcan (lambda (x)
- (remove nil (mapcar 'cadr (apply (car x) (cdr x)))))
- (tramp-get-completion-function "ssh"))
- #'string=))
- (defun jao-ssh (&optional scratch)
- (interactive "P")
- (let ((h (completing-read "Host: " (jao-tramp-hosts))))
- (when scratch (jao-afio-goto-scratch))
- (jao-exec-in-term (format "ssh %s" h) (format "*ssh %s*" h))))
- ;;; Chats
- ;;;; circe
- (defvar jao-libera-channels ())
- (defvar jao-oftc-channels ())
- (defvar jao-bitlbee-channels ())
- (defvar jao-slack-channels ())
- (use-package circe
- :ensure t
- :bind (:map circe-channel-mode-map
- (("C-c C-a" . lui-track-jump-to-indicator)))
- :init
- (setq circe-chat-buffer-name "{target}"
- circe-default-realname "https://jao.io"
- circe-default-part-message ""
- circe-default-quit-message ""
- circe-ignore-list nil
- circe-server-coding-system '(undecided . undecided)
- circe-server-killed-confirmation 'ask-and-kill-all
- circe-server-auto-join-default-type :after-auth
- circe-format-say "({nick}) {body}"
- circe-format-self-say "(jao) {body}"
- circe-new-buffer-behavior 'ignore
- circe-new-buffer-behavior-ignore-auto-joins t
- circe-nickserv-ghost-style 'after-auth
- circe-prompt-string ": "
- circe-completion-suffix ", "
- circe-reduce-lurker-spam t
- circe-lagmon-mode-line-format-string "" ;; "%.0f "
- circe-lagmon-mode-line-unknown-lag-string "" ;; "? "
- circe-lagmon-timer-tick 120
- circe-lagmon-reconnect-interval 180
- lui-max-buffer-size 30000
- lui-fill-column 80
- lui-time-stamp-position 'right
- lui-time-stamp-format "%H:%M"
- lui-flyspell-p nil
- lui-track-indicator (if window-system 'fringe 'bar)
- lui-track-behavior 'before-tracking-next-buffer)
- :config
- (defsubst jao-circe-nick-no () (length (circe-channel-nicks)))
- (define-minor-mode jao-circe-user-number-mode ""
- :lighter (:eval (format " [%s]" (jao-circe-nick-no))))
- (defun jao-circe-channel-hook ()
- (when jao-mode-line-in-minibuffer
- (setq header-line-format
- '(" %b" (:eval (format " - %s nicks" (jao-circe-nick-no))))))
- (jao-circe-user-number-mode 1))
- (add-hook 'circe-channel-mode-hook #'jao-circe-channel-hook)
- (defun circe-command-RECOVER (&rest _ignore)
- "Recover nick"
- (jao-with-auth "freenode" u p
- (circe-command-MSG "nickserv" (format "IDENTIFY %s %s" u p))
- (circe-command-MSG "nickserv" (format "GHOST %s" u))
- (circe-command-MSG "nickserv" (format "RELEASE %s" u))
- (circe-command-NICK u)))
- (defun circe-command-NNICKS (&rest _)
- "Echo number of nicks"
- (circe-display-server-message
- (format "%d nicks in this channel" (jao-circe-nick-no))))
- (defun circe-command-SENDFILE (line)
- "/sendfile for localslackirc"
- (circe-command-QUOTE (format "sendfile %s" line)))
- (advice-add 'circe-command-NAMES :after #'circe-command-NNICKS)
- (setq circe-network-options
- (list (jao-with-auth "libera" u p
- (list "Libera Chat" :nick u :channels jao-libera-channels
- :tls t :sasl-username u :sasl-password p))
- (jao-with-auth "oftc" u p
- (list "OFTC"
- :nick u :channels jao-oftc-channels :nickserv-password p
- :tls t :sasl-username u :sasl-password p))
- (jao-with-auth "bitlbee" u p
- (list "Bitlbee" :host "127.0.0.1" :nick u
- :channels jao-bitlbee-channels :lagmon-disabled t
- :nickserv-password u :user p))
- (list "localslack" :host "127.0.0.1" :nick "jao"
- :channels jao-slack-channels :port 9007
- :lagmon-disabled t)
- (list "recoveryou" :host "127.0.0.1" :nick "jao"
- :port 9008 :lagmon-disabled t)))
- (jao-shorten-modes 'circe-channel-mode
- 'circe-server-mode
- 'circe-query-mode)
- (enable-circe-display-images)
- (enable-lui-track)
- (circe-lagmon-mode))
- ;;;; telegram
- (use-package telega
- :ensure t
- :custom
- (telega-use-tracking-for '(unmuted) ;; '(or unmuted mention)
- telega-rainbow-color-custom-for nil
- telega-msg-rainbow-title nil
- telega-sticker-set-download t
- telega-symbol-checkmark "·"
- telega-symbol-heavy-checkmark "×"
- telega-symbol-verified "*")
- :config
- (define-key global-map (kbd "C-c C-t") telega-prefix-map)
- (setq telega-chat-show-avatars nil
- telega-chat-prompt-insexp '(telega-ins "> ")
- telega-completing-read-function #'completing-read
- telega-root-show-avatars nil
- telega-emoji-use-images nil
- telega-temp-dir "/tmp/telega"
- telega-symbol-horizontal-bar
- (propertize "-" 'face 'jao-themes-f00)
- telega-symbol-vertical-bar
- (propertize "| " 'face 'jao-themes-dimm)
- telega-mode-line-string-format
- '(:eval (telega-mode-line-unread-unmuted))
- telega-use-images (display-graphic-p)
- telega-open-file-function #'jao--see
- telega-open-message-as-file
- (unless (display-graphic-p) '(photo video animation)))
- (with-eval-after-load "tracking"
- (jao-shorten-modes 'telega-chat-mode)
- (jao-tracking-faces 'telega-tracking))
- (telega-mode-line-mode 1))
- (defun jao-telega ()
- (interactive)
- (jao-tracking-go-to-chats)
- (if (get-buffer telega-root-buffer-name)
- (pop-to-buffer telega-root-buffer-name)
- (telega)))
- ;;;; ement
- (use-package ement
- :disabled t
- :ensure t
- :init (setq ement-save-sessions t
- ement-sessions-file (locate-user-emacs-file "cache/ement.el")
- ement-room-avatars nil
- ement-notify-dbus-p nil
- ement-room-left-margin-width 0
- ement-room-right-margin-width 11
- ement-room-timestamp-format "%H:%M"
- ement-room-timestamp-header-format "--------")
- :custom ((ement-room-message-format-spec "(%S) %B%r%R %t"))
- :config
- (defun jao-ement-track (event room session)
- (when (ement-notify--room-unread-p event room session)
- (when-let ((n (ement-room--buffer-name room))
- (b (get-buffer n)))
- (tracking-add-buffer b))))
- (add-hook 'ement-event-hook #'jao-ement-track)
- (jao-shorten-modes 'ement-room-mode)
- (jao-tracking-cleaner "^\\*Ement Room: \\(.+\\)\\*" "@\\1"))
- ;;;; mastodon
- (use-package mastodon
- :ensure t
- :init
- (setq mastodon-instance-url "https://fosstodon.org"
- mastodon-active-user "jao@gnu.org"
- mastodon-tl-position-after-update nil
- mastodon-toot-display-orig-in-reply-buffer t)
- :config
- ;; (defun jao-mastodon--setup ()
- ;; (setq-local scroll-margin 12))
- ;; (add-hook 'mastodon-mode-hook #'jao-mastodon--setup)
- (with-eval-after-load "ewww"
- (define-key eww-mode-map (kbd "T") #'jao-mastodon-toot-url)))
- (defun jao-mastodon-toot-url ()
- (interactive)
- (when-let (url (jao-url-around-point t))
- (jao-tracking-go-to-chats)
- (mastodon-toot--compose-buffer nil nil nil url)))
- (defun jao-mastodon ()
- (interactive)
- (jao-afio-goto-chats)
- (mastodon))
- ;; https://0x0.st/XJ14.txt
- (jao-transient-major-mode mastodon
- ["Timelines"
- ("H" "home" mastodon-tl--get-home-timeline)
- ("L" "local" mastodon-tl--get-local-timeline)
- ("F" "federated" mastodon-tl--get-federated-timeline)
- ("K" "bookmarks" mastodon-profile--view-bookmarks)
- ("V" "favorites" mastodon-profile--view-favourites)
- ("'" "followed tags" mastodon-tl--followed-tags-timeline)
- ("@" "mentions" mastodon-notifications--get-mentions)
- ("N" "notifications" mastodon-notifications-get)
- ("\\" "of remote host" mastodon-tl--get-remote-local-timeline)]
- ;; u mastodon-tl--update
- ["Search"
- ("s" "search" mastodon-search--query)
- ("#" "tagged" mastodon-tl--get-tag-timeline)
- ("\"" "followed tags" mastodon-tl--list-followed-tags)
- ("I" "filter" mastodon-views--view-filters)
- ("X" "lists" mastodon-views--view-lists)]
- ["Toots"
- ("n" "next" mastodon-tl--goto-next-item :transient t)
- ("p" "prev" mastodon-tl--goto-prev-item :transient t)
- ("c" "spoiler" mastodon-tl--toggle-spoiler-text-in-toot :transient t)
- ("T" "thread" mastodon-tl--thread)
- ("b" "(un)boost" mastodon-toot--toggle-boost :transient t)
- ("f" "(un)fav" mastodon-toot--toggle-favourite :transient t)
- ("i" "(un)pin" mastodon-toot--pin-toot-toggle :transient t)
- ("k" "(un)bookmark" mastodon-toot--toggle-bookmark :transient t)
- ("v" "vote" mastodon-tl--poll-vote)]
- ;; Z mastodon-tl--report-to-mods
- ;; o mastodon-toot--open-toot-url
- ["Own Toots"
- ("r" "replay" mastodon-toot--reply)
- ("t" "write" mastodon-toot)
- ("e" "edit" mastodon-toot--edit-toot-at-point)
- ("d" "delete" mastodon-toot--delete-toot)
- ("D" "del & redraft" mastodon-toot--delete-and-redraft-toot)
- ("E" "show edits" mastodon-toot--view-toot-edits)]
- ;; S mastodon-views--view-scheduled-toots
- ["Users"
- ("W" "follow" mastodon-tl--follow-user)
- ("R" "follow req" mastodon-views--view-follow-requests)
- ("G" "suggestions" mastodon-views--view-follow-suggestions)
- ("M" "mute user" mastodon-tl--mute-user)
- ("B" "block user" mastodon-tl--block-user)
- ("m" "message user" mastodon-tl--dm-user)
- ""
- ("," "favouriters" mastodon-toot--list-toot-favouriters)
- ("." "boosters" mastodon-toot--list-toot-boosters)]
- ;; S-RET mastodon-tl--unmute-user
- ;; C-S-b mastodon-tl--unblock-user
- ["Profiles"
- ("A" "author" mastodon-profile--get-toot-author)
- ("P" "any user" mastodon-profile--show-user)
- ("O" "own" mastodon-profile--my-profile)
- ("U" "update own" mastodon-profile--update-user-profile-note)]
- ["Misc"
- ("C" "copy URL" mastodon-toot--copy-toot-url)
- ("?" "help" describe-mode)
- ("q" "quit" transient-quit-one)])
- ;;;; startup
- (defun jao-chats (&optional p)
- (interactive "P")
- (when (or p (y-or-n-p "Connect to telegram? "))
- (telega))
- (when (and (fboundp 'ement-connect) (or p (y-or-n-p "Connect to matrix? ")))
- (unless (get-buffer "*Ement Rooms*")
- (jao-with-auth "matrix.org" u p (ement-connect :user-id u :password p))))
- (when (and (fboundp 'mastodon) (or p (y-or-n-p "Connect to mastodon? ")))
- (mastodon))
- (when (or p (y-or-n-p "Connect to libera? "))
- (unless (get-buffer "irc.libera.chat:6697")
- (circe "Libera Chat")))
- (when (or p (y-or-n-p "Connect to localslack? "))
- (unless (get-buffer "127.0.0.1:9007")
- (circe "localslack")))
- (when (or p (y-or-n-p "Connect to recoveryou? "))
- (unless (get-buffer "127.0.0.1:9008")
- (circe "recoveryou"))))
- (defun jao-all-chats ()
- (interactive)
- (when jao-tracking-use-scratch
- (jao-afio-goto-chats)
- (delete-other-windows))
- (jao-chats t))
- (defun jao-chats-telega ()
- (interactive)
- (jao-buffer-same-mode '(telega-root-mode telega-chat-mode)))
- (defun jao-chats-slack ()
- (interactive)
- (jao-buffer-same-mode 'slack-message-buffer-mode))
- (defun jao-chats-irc ()
- (interactive)
- (jao-buffer-same-mode '(circe-channel-mode circe-query-mode erc-mode)))
- ;;;; consult narrowing
- (defvar jao-chat-buffer-source
- (list :name "chats"
- :category 'buffer
- :action (lambda (b) (jao-afio-pop-to-buffer 0 b))
- :hidden t
- :narrow (cons ?c "chats")
- :items (jao-consult--mode-buffers 'erc-mode
- 'circe-channel-mode
- 'circe-query-mode
- 'signel-chat-mode
- 'slack-message-buffer-mode
- 'slack-thread-message-buffer-mode
- 'telega-root-mode
- 'telega-chat-mode
- 'ement-room-mode
- 'ement-room-list-mode)))
- (with-eval-after-load "consult"
- (jao-consult-add-buffer-source 'jao-chat-buffer-source))
- ;;; Multimedia
- ;;;; video
- (use-package ready-player :ensure t)
- (ready-player-mode 1)
- ;;;; mixer
- (defun jao-mixer-get-level (&optional dev nomsg)
- (interactive)
- (let* ((dev (or dev "Master"))
- (s (shell-command-to-string (format "amixer sget %s" dev)))
- (s (car (last (split-string s "\n" t)))))
- (when (string-match ".*Front .*\\[\\([0-9]+\\)%\\] .*" s)
- (let ((level (match-string 1 s)))
- (unless nomsg (message "%s level: %s%%" dev level))
- (string-to-number level)))))
- (defun jao-mixer-set (dev v)
- (jao-shell-exec* t "amixer" "sset" dev v)
- (jao-mixer-get-level dev))
- (defun jao-mixer-master-toggle ()
- (interactive)
- (jao-mixer-set "Master" "toggle"))
- (defun jao-mixer-master-up ()
- (interactive)
- (jao-mixer-set "Master" "10%+"))
- (defun jao-mixer-master-down ()
- (interactive)
- (jao-mixer-set "Master" "10%-"))
- (defun jao-mixer-capture-up ()
- (interactive)
- (jao-mixer-set "Capture" "10%+"))
- (defun jao-mixer-capture-down ()
- (interactive)
- (jao-mixer-set "Capture" "10%-"))
- (jao-shell-def-exec jao-audio-applet "pasystray")
- (defun jao-toggle-audio-applet ()
- (interactive)
- (or (jao-shell-kill-p "paystray") (jao-audio-applet)))
- (global-set-key (kbd "<f4>") #'jao-toggle-audio-applet)
- ;;;; streaming aliases
- (defalias 'jao-streaming-list #'ignore)
- (defalias 'jao-streaming-like #'ignore)
- (defalias 'jao-streaming-dislike #'ignore)
- (defalias 'jao-streaming-toggle-shuffle #'ignore)
- (defalias 'jao-streaming-lyrics #'ignore)
- (defalias 'jao-streaming-toggle #'ignore)
- (defalias 'jao-streaming-next #'ignore)
- (defalias 'jao-streaming-prev #'ignore)
- (defalias 'jao-streaming-current #'ignore)
- (defalias 'jao-streaming-seek #'ignore)
- (defalias 'jao-streaming-seek-back #'ignore)
- (defalias 'jao-streaming-volume #'ignore)
- (defalias 'jao-streaming-volume-down #'ignore)
- ;;;; mpris
- (defun jao-mpris-lyrics (&optional force)
- (interactive "P")
- (jao-show-lyrics force #'jao-mpris-artist-title))
- (defun jao-mpris-mopidy-p () (string= "mopidy "jao-mpris-player))
- (defun jao-mpc-mopidy-playlist ()
- (interactive)
- (jao-mpc-show-playlist jao-mopidy-port))
- (use-package jao-mpris :demand t)
- (defun jao-mpris-setup-aliases ()
- (setq espotify-play-uri-function #'espotify-play-uri-with-dbus)
- ;; (setq jao-mpris-player "mopidy")
- (defalias 'jao-streaming-list #'jao-mpc-mopidy-playlist)
- (defalias 'jao-streaming-lyrics #'jao-mpris-lyrics)
- (defalias 'jao-streaming-toggle #'jao-mpris-play-pause)
- (defalias 'jao-streaming-next #'jao-mpris-next)
- (defalias 'jao-streaming-prev #'jao-mpris-previous)
- (defalias 'jao-streaming-current #'jao-mpris-show-osd)
- (defalias 'jao-streaming-seek #'jao-mpris-seek)
- (defalias 'jao-streaming-seek-back #'jao-mpris-seek-back)
- (defalias 'jao-streaming-volume #'jao-mpris-vol)
- (defalias 'jao-streaming-volume-down #'jao-mpris-vol-down))
- (jao-mpris-register "playerctld" :session 70)
- ;; (jao-mpris-register "mopidy" :session 70)
- ;;;; mpc
- (use-package jao-mpc
- :demand t
- :commands jao-mpc-setup)
- (defvar jao-mopidy-port 6669)
- (defvar jao-mpc-last-port jao-mpc-port)
- (defun jao-mpc-toggle-port ()
- (interactive)
- (setq jao-mpc-port
- (if (equal jao-mpc-port jao-mopidy-port) 6600 jao-mopidy-port)
- jao-mpc-last-port jao-mpc-port))
- (defsubst jao-mpc-mopidy-p () (equal jao-mpc-last-port jao-mopidy-port))
- (jao-mpc-setup jao-mopidy-port 70)
- (defun jao-mpc-pport (&optional mop)
- (cond ((or mop (jao-mpc-playing-p jao-mopidy-port)) jao-mopidy-port)
- ((jao-mpc-playing-p) 6600)
- (t jao-mpc-last-port)))
- (defmacro jao-defun-play (name &optional mpc-name)
- (let ((arg (gensym)))
- `(defun ,(intern (format "jao-player-%s" name)) (&optional ,arg)
- (interactive "P")
- (,(intern (format "jao-mpc-%s" (or mpc-name name)))
- (setq jao-mpc-last-port (jao-mpc-pport ,arg))))))
- (jao-defun-play toggle)
- (jao-defun-play next)
- (jao-defun-play previous)
- (jao-defun-play stop)
- (jao-defun-play echo echo-current-times)
- (jao-defun-play list show-playlist)
- (jao-defun-play info lyrics-track-data)
- (jao-defun-play browse show-albums)
- (jao-defun-play select-album)
- (defun jao-player-seek (delta) (jao-mpc-seek delta (jao-mpc-pport)))
- (defalias 'jao-player-connect 'jao-mpc-connect)
- (defalias 'jao-player-play 'jao-mpc-play)
- ;;;; spotify
- (jao-load-path "espotify")
- (use-package espotify
- :demand t
- :init (setq espotify-service-name "mopidy"))
- (use-package consult-spotify :demand t)
- (defalias 'jao-streaming-album #'consult-spotify-album)
- (defalias 'jao-streaming-track #'consult-spotify-track)
- (defalias 'jao-streaming-artist #'consult-spotify-artist)
- (defalias 'jao-streaming-playlist #'consult-spotify-playlist)
- (jao-def-exec-in-term "ncmpcpp" "ncmpcpp" (jao-afio-goto-scratch))
- ;;;; spt
- (use-package jao-spt
- :demand t
- :config
- (defun jao-spt-setup-aliases ()
- (setq espotify-play-uri-function #'jao-spt-play-uri)
- (defalias 'jao-streaming-list #'jao-term-spt)
- (defalias 'jao-streaming-lyrics #'jao-spt-show-lyrics)
- (defalias 'jao-streaming-toggle #'jao-spt-toggle)
- (defalias 'jao-streaming-next #'jao-spt-next)
- (defalias 'jao-streaming-prev #'jao-spt-previous)
- (defalias 'jao-streaming-current #'jao-spt-echo-current)
- (defalias 'jao-streaming-seek #'jao-spt-seek)
- (defalias 'jao-streaming-seek-back #'jao-spt-seek-back)
- (defalias 'jao-streaming-volume #'jao-spt-vol)
- (defalias 'jao-streaming-volume-down #'jao-spt-vol-down)
- (defalias 'jao-streaming-like #'jao-spt-like)
- (defalias 'jao-streaming-dislike #'jao-spt-dislike)
- (defalias 'jao-streaming-toggle-shuffle #'jao-spt-toggle-shuffle)))
- (jao-def-exec-in-term "spt" "spt" (jao-afio-goto-scratch))
- (defvar jao-spt-on t)
- (defun jao-streaming-toggle-player ()
- (interactive)
- (if jao-spt-on
- (progn (setq jao-mpris-player "playerctld")
- (require 'jao-mpris)
- (jao-mpris-setup-aliases))
- (jao-spt-setup-aliases)
- (setq jao-mpris-player "spt"))
- (setq jao-spt-on (not jao-spt-on))
- (message "%s activated " jao-mpris-player))
- (jao-streaming-toggle-player)
- ;;;; music transients
- (require 'jao-lyrics)
- (setq jao-lyrics-info-function #'jao-player-info)
- (defun jao-player-seek-10 () (interactive) (jao-player-seek 10))
- (defun jao-player-seek--10 () (interactive) (jao-player-seek -10))
- (defun jao-streaming-clear () (interactive) (jao-mpc-clear jao-mopidy-port))
- (defun jao-streaming-echo-current ()
- (interactive)
- (jao-mpc-echo-current jao-mopidy-port))
- (defun jao-streaming-show-playlist ()
- (interactive)
- (jao-mpc-show-playlist jao-mopidy-port))
- (use-package jao-random-album
- :demand t
- :config
- (defun jao--notify-album (album)
- (jao-notify album "Next album" jao-notify-audio-icon)
- (jao-minibuffer-refresh))
- (setq jao-random-album-notify #'jao--notify-album))
- (defun jao-toggle-pasystray-applet ()
- (interactive)
- (or (jao-shell-kill-p "pasystray") (jao-shell-exec "pasystray")))
- (transient-define-prefix jao-transient-streaming ()
- [:description
- (lambda () (format "Streaming using %s" jao-mpris-player))
- ["Search" :if jao-mpris-mopidy-p
- ("a" "album" jao-streaming-album)
- ("A" "artist" jao-streaming-artist)
- ("t" "track" jao-streaming-track)
- ("P" "playlist" jao-streaming-playlist)]
- ["Play"
- ("s" "toggle" jao-streaming-toggle)
- ("n" "next" jao-streaming-next)
- ("p" "previous" jao-streaming-prev)
- ("T" "toggle player" jao-streaming-toggle-player)]
- ["Seek & shout"
- ("f" "seek fwd" jao-streaming-seek :transient t)
- ("F" "seek bwd" jao-streaming-seek-back :transient t)
- ("u" "up" jao-streaming-volume :transient t)
- ("d" "down" jao-streaming-volume-down :transient t)]
- ["Browse"
- ("l" "playing list" jao-streaming-list :if jao-mpris-mopidy-p)
- ("L" "lyrics" jao-streaming-lyrics)
- ("w" "currently playing" jao-streaming-current)]
- ["Act" :if jao-mpris-mopidy-p
- ("k" "like" jao-streaming-like)
- ("K" "dislike" jao-streaming-dislike)
- ("S" "toggle shuffle" jao-streaming-toggle-shuffle)]])
- (transient-define-prefix jao-transient-media ()
- [["Play"
- ("m" "toggle" jao-player-toggle)
- ("n" "next" jao-player-next)
- ("p" "previous" jao-player-previous)
- ("s" "select album" jao-player-select-album)]
- ["Seek and search"
- ("f" "seek fwd" jao-player-seek-10 :transient t)
- ("F" "seek bwd" jao-player-seek--10 :transient t)
- ("a" "search album" jao-mpc-select-album)
- ("S" "play stream" jao-mpc-play-stream)]
- ["Browse"
- ("b" "browse" jao-player-browse)
- ("l" "show play list" jao-player-list)
- ("L" "show lyrics" jao-show-lyrics)
- ("w" "now playing" jao-player-echo)]
- [:description
- (lambda ()
- (message "%s %s"
- (if (jao-mpc-mopidy-p) "mopidy" "mpd")
- (if (jao-mpc-playing-p)
- (jao-mpc--current-timestr t)
- (jao-mpc--current-str)))
- (format "Master %s%%" (jao-mixer-get-level nil t)))
- ("d" "down" jao-mixer-master-down :transient t)
- ("u" "up" jao-mixer-master-up :transient t)
- ("M" "toggle" jao-mixer-master-toggle)]
- [:description
- (lambda () (format "Capture %s%%" (jao-mixer-get-level "Capture" t)))
- ("D" "down" jao-mixer-capture-down :transient t)
- ("U" "up" jao-mixer-capture-up :transient t)]
- ["Utilities"
- ("c" "reconnect to mpd" jao-player-connect)
- ("N" "next random album" jao-random-album-next)
- ("r" (lambda ()
- (concat (if jao-random-album-active "dis" "en") "able random album"))
- jao-random-album-toggle)
- ;; ("P" (lambda () (concat "Toggle to " (if (jao-mpc-mopidy-p) "mpd" "mopidy")))
- ;; jao-mpc-toggle-port)
- ("P" "pasystray" jao-toggle-pasystray-applet)]])
- (global-set-key (kbd "s-m") #'jao-transient-media)
- ;;; Graphical window system
- ;;;; x11 utils
- (defun jao-xdotool (arg-or-wait &rest args)
- (apply 'jao-shell-exec*
- (if (stringp arg-or-wait) "xdotool" arg-or-wait)
- (if (stringp arg-or-wait) arg-or-wait "xdotool")
- args))
- (defsubst jao-xdotool-string (&rest args)
- (apply 'jao-shell-string "xdotool" args))
- (defsubst jao-x11-focused-id () (jao-xdotool-string "getwindowfocus"))
- (defsubst jao-x11-window-name (&optional wid)
- (jao-xdotool-string "getwindowname" (or wid (jao-x11-focused-id))))
- (defsubst jao-x11-search-window (title)
- (jao-xdotool-string "search" "--name" title))
- (defsubst jao-x11-goto-ws (n) (jao-xdotool t "set_desktop" (format "%s" n)))
- ;;;; exwm
- (defvar jao-exwm-enabled nil)
- (defun jao-exwm-enabled-p () jao-exwm-enabled)
- (defun jao-exwm-enable ()
- (require 'jao-custom-exwm)
- (setq jao-exwm-enabled t)
- (display-time-mode -1)
- (jao-ednc-setup 95)
- (exwm-enable)
- (x-change-window-property "_XMONAD_TRAYPAD" "" nil nil nil nil 0)
- (jao-mode-line-add-to-minibuffer-left 90)
- (jao-xmobar-restart)
- (jao-trisect t))
- ;;;; xmonad
- (defvar jao-xmonad-enabled (string= "xmonad" (or (getenv "wm") "")))
- (defun jao-xmonad-enabled-p () jao-xmonad-enabled)
- (defun jao-xmonad-enable ()
- (setq jao-browse-doc-use-emacs-p (display-graphic-p))
- (setq jao-mode-line-in-minibuffer nil)
- (display-battery-mode -1)
- (jao-trisect)
- (message "Welcome to xmonad"))
- (when jao-xmonad-enabled
- (add-hook 'after-init-hook #'jao-xmonad-enable))
- ;;;; wayland
- (use-package jao-wayland :demand t)
- (defun jao-wayland-enable ()
- (interactive)
- (defalias 'x-change-window-property #'ignore)
- (jao-trisect)
- (message "Welcome to wayland"))
- (defun jao-river-enable ()
- (jao-wayland-enable)
- (when (jao-shell-running-p "i3bar-river")
- (jao-tracking-set-log ""))
- (message "Welcome to river"))
- (when jao-river-enabled
- (add-hook 'after-init-hook #'jao-river-enable t))
- (when jao-sway-enabled
- (add-hook 'after-init-hook #'jao-wayland-enable t))
- ;;;; wallpaper
- (defvar jao-wallpaper-dir "~/.wallpapers/")
- (defvar jao-wallpaper-random-candidates
- '("wallpaper.jpg" "wallpaper2.jpg"))
- (defvar jao-wallpaper-random-candidates-light
- '("wallpaper.jpg" "wallpaper2.jpg"))
- (defvar jao-wallpaper-random-wake t
- "Set to t for getting a new wallpaper on awaking from sleep")
- (defun jao-set-wallpaper (&optional path)
- (interactive)
- (let ((current (format "~/.wallpaper.%s" (jao-colors-scheme))))
- (when-let ((f (or (and path (expand-file-name path))
- (read-file-name "Image: "
- jao-wallpaper-dir
- (file-symlink-p current)
- t))))
- (make-symbolic-link f current t)
- (cond (jao-river-enabled (jao-river-set-wallpaper f))
- (jao-sway-enabled (jao-sway-set-wallpaper f))
- (t (shell-command-to-string (format "xwallpaper --zoom %s" f)))))))
- (defun jao-set-random-wallpaper ()
- (interactive)
- (when (or (called-interactively-p 'interactive)
- jao-wallpaper-random-wake)
- (let* ((ws (if (jao-colors-scheme-dark-p)
- jao-wallpaper-random-candidates
- jao-wallpaper-random-candidates-light))
- (f (seq-random-elt ws)))
- (jao-set-wallpaper (expand-file-name f jao-wallpaper-dir))
- (message "%s" f))))
- (add-to-list 'jao-sleep-awake-functions #'jao-set-random-wallpaper)
- ;;;; screensaver and lock
- (defun jao-screensaver-enabled ()
- (string= (jao-shell-string "xdg-screensaver status") "enabled"))
- (defvar jao-screensaver--wid nil)
- (defun jao-screensaver-toggle ()
- (interactive)
- (if (jao-screensaver-enabled)
- (let ((wid (jao-x11-focused-id)))
- (setq jao-screensaver--wid wid)
- (jao-shell-exec* t "xdg-screensaver" "suspend" wid))
- (jao-shell-exec* t "xdg-screensaver" "resume" jao-screensaver--wid)
- (setq jao-screensaver--wid nil))
- (jao-notify (format "Screensaver %s"
- (jao-shell-string "xdg-screensaver status"))))
- (jao-shell-def-exec jao-xlock-screen "xdg-screensaver" "activate")
- (jao-shell-def-exec jao-suspend "sudo" "systemctl" "suspend")
- (jao-shell-def-exec jao-poweroff "sudo" "systemctl" "poweroff")
- (defun jao-lock-screen ()
- (interactive)
- (if jao-wayland-enabled
- (shell-command "swaylock -i ~/.lockimage")
- (jao-xlock-screen)))
- (transient-define-prefix jao-transient-sleep ()
- ["Sleep"
- ("l" "lock screen" jao-lock-screen)
- ("z" "sleep" jao-suspend)
- ("u" (lambda ()
- (if (jao-screensaver-enabled) "suspend screensaver" "resume screensaver"))
- jao-screensaver-toggle)
- ("poof" "power-off" jao-poweroff)])
- ;;;; X clipboard
- (setq select-enable-clipboard t
- select-enable-primary t
- selection-timeout 100
- xterm-select-active-regions t)
- (use-package xclip
- :ensure t
- :init (setq xclip-method (if jao-wayland-enabled 'wl-copy 'xclip)))
- (unless (display-graphic-p) (xclip-mode 1))
- ;;;; pop-up frames
- (defun jao-open-in-x-frame (&optional width height)
- (interactive)
- (make-frame `((window-system . x)
- (name . "emacs popup")
- (width . ,(or width (window-width)))
- (height . ,(or height (window-height)))))
- (define-key (current-local-map) "q" #'delete-frame))
- ;;;; xmobar
- (defun jao-xmobar-kill ()
- (interactive)
- (shell-command "killall xmobar-single"))
- (defun jao-xmobar-restart ()
- (interactive)
- (jao-xmobar-kill)
- (start-process "" nil "xmobar-single" "-d"))
- (use-package tab-bar
- :init (setq tab-bar-close-button-show nil
- tab-bar-show (> emacs-major-version 28)
- tab-bar-format ()))
- (use-package xmobar
- :init (setq xmobar-tab-bar t
- xmobar-tab-split "*"
- xmobar-tab-bar-format
- (if window-system
- '(xmobar-left-string
- tab-bar-format-align-right
- xmobar-right-string)
- '(xmobar-left-string
- xmobar-elastic-space
- xmobar-right-string))
- xmobar-command
- (if window-system '("xmobar-emacs" "-TAnsi") "xmobar-emacs")))
- ;;; Global transients
- (defun jao-list-packages ()
- (interactive)
- (jao-afio-goto-scratch)
- (package-list-packages))
- (defun jao-window-system-p ()
- (or jao-exwm-enabled jao-xmonad-enabled jao-wayland-enabled))
- (defun jao-x11-p () (or jao-exwm-enabled jao-xmonad-enabled))
- (defun jao-reveal ()
- (interactive)
- (cond ((or outline-minor-mode (derived-mode-p 'outline-mode ))
- (outline-show-entry))
- ((derived-mode-p 'org-mode) (org-reveal))))
- (jao-def-exec-in-term "aptitude" "aptitude" (jao-afio-goto-scratch))
- (jao-def-exec-in-term "htop" "htop" (jao-afio-goto-scratch))
- (transient-define-prefix jao-transient-utils ()
- "Global operations."
- [["Notes"
- ("n" "create new note" jao-org-notes-create)
- ("/" "open note" jao-org-notes-open)
- ("\\" "open note by tags" jao-org-notes-consult-tags)
- ("g" "ripgrep notes" jao-org-notes-consult-ripgrep)]
- ["Documents"
- ("dd" "go to doc" jao-select-pdf :if display-graphic-p)
- ("do" "open doc" jao-open-doc)
- ("dr" "search docs with recoll" jao-recoll-consult-docs)]
- ["Monitors"
- ("p" "htop" jao-term-htop)
- ("P" "pasytray" jao-toggle-pasystray-applet)
- ("x" "restart i3bar" jao-river-restart-i3bar :if jao-river-enabled-p)
- ("x" "restart xmobar" jao-xmobar-restart :if jao-exwm-enabled-p)
- ("x" "kill xmobar" jao-xmobar-kill :if jao-xmonad-enabled-p)]
- ["Network"
- ("s" "ssh" jao-ssh)
- ("b" "bluetooth" bluetooth-list-devices)
- ("c" "connect chats" jao-all-chats)
- ("m" "proton bridge" run-proton-bridge)
- ("v" "view video" jao-view-video)]
- ["Chats"
- ("t" "telegram" jao-chats-telega)
- ("i" "irc" jao-chats-irc)
- ("M" "mastodon" jao-mastodon)
- ("T" "telegram rooster" jao-telega)]
- ["Window system" :if jao-window-system-p
- ("w" "set wallpaper" jao-set-wallpaper)
- ("W" "set radom wallpaper" jao-set-random-wallpaper)
- ("B u" (lambda ()
- (let ((b (jao-brightness)))
- (format "bright up %s" (and (string-match ".*\\((.+)\\).*" b)
- (match-string 1 b)))))
- jao-bright-up :transient t)
- ("B d" "bright down" jao-bright-down :transient t)]
- ["Helpers"
- ("a" "aptitude" jao-term-aptitude)
- ("l" "packages" jao-list-packages)
- ("r" "reveal" jao-reveal)
- ("k" (lambda () (concat "keyboard" (when (jao-kb-toggled-p) "*")))
- jao-kb-toggle :if jao-x11-p)]])
- (global-set-key (kbd "s-w") #'jao-transient-utils)
- ;;; Global key bindings
- (defun jao-global-keybindings ()
- (interactive)
- (global-set-key (kbd "<f2>") #'magit-status)
- (global-set-key (kbd "C-x p") #'jao-prev-window)
- (global-set-key (kbd "C-x o") 'other-window)
- (global-set-key "\C-cj" #'join-line)
- (global-set-key "\C-cn" #'next-error)
- (global-set-key "\C-cq" #'auto-fill-mode)
- (global-set-key "\C-xr\M-w" #'kill-rectangle-save)
- (global-set-key "\C-c\C-z" #'comment-or-uncomment-region)
- (global-set-key "\C-z" #'comment-or-uncomment-region))
- (jao-global-keybindings)
- ;;; Last minute (post.el)
- (jao-load-site-el "post")
|