dotfiles/.emacs.d/config.org

47 KiB

EMACS konfiguracija

Tukaj se nahaja celotna konfiguracija za emacs urejevalnik, ki jo uporabljam, v ORG obliki. Na ta - "literate programming" oz. pismeni način - podana konfiguracija daje v ospredje opis posameznih sekcij in s tem poveča preglednost, olajša pa tudi navigacijo po konfiguraciji.

Razdeljena je na poglavja ohlapno glede na vlogo oz področje. Področja so nekoliko raznosvrstna (evil način - tipkovnične bližnjice v slogu VIM so ena sekcija, programiranje druga…), bi pa moralo biti iz naslovov precej jasno, za kaj gre.

V primeru napak pri nalaganju ne pozabimo na uporaben ukaz emacs --debug-init.

Bližnjice do drugih konfiguracij

Zagon

debug-on-error uresničimo, če bi radi sprožili razhroščevalnik, kadar pride do napake (zelo priročno pri reševanju težav).

  (setq debug-on-error t)

Pospešimo zagon z zmanjšanjem frekvence zbiranja smeti (garbage collection).

  (setq gc-cons-threshold (* 50 1024 1024))

Vedno sledi simboličnim linkom. To potrebujem, ker se konfiguracijski fajli ponavadi nahajajo v ločenem direktoriju zbirke konfiguracij in je tečno vsakič potrjevati sledenje v dialogu.

  (setq vc-follow-symlinks t)

Po zagunu izpiši čas nalaganja.

  (add-to-list 'after-init-hook
     (lambda ()
       (message (concat "emacs (" (number-to-string (emacs-pid)) ") started in "
                        (emacs-init-time)))))

Nalaganje paketov

Vklopi prikazovanje statistik naloženih paketov (prikažemo jih z M-x use-package-report).

  (setq use-package-compute-statistics t)

Nastavimo vire nalaganja paketov in pa vklopimo privzeto nalaganje use-package paketov iz spletnih zbirališč.

  (require 'package)
  (setq use-package-always-ensure t)
  (add-to-list 'package-archives '("melpa" . "https://melpa.org/packages/") t)
  (add-to-list 'package-archives '("org" . "https://orgmode.org/elpa/") t)
  (add-to-list 'package-archives '("elpa" . "https://elpa.gnu.org/packages/") t)
  (package-initialize)
  ;(require 'use-package)

Vklop merjenja časa nalaganja posameznih paketov. Rezultate merjenja lahko pogledamo z M-x benchmark-init/show-durations-tabulated ali M-x benchmark-init/show-durations-tree

  (use-package benchmark-init
    :config
    ;; To disable collection of benchmark data after init is done.
    (add-hook 'after-init-hook 'benchmark-init/deactivate))

Vezane tipke

S paketom general je definiranih več kategorij tipkovničnih bližnjic, ki so združene po svoji funkciji, podobno kot poglavja tega dokumenta. Če v ukaznem načinu kliknemo SPC (ali pa v tekstovnem načinu C-SPC), se nam prikažejo tipke kategorij, po kliku na posamezno pa ukazi, ki jih sprožimo (ali pa podkategorije).

V sledečim podpoglavjih so navedene kategorije posameznih bližnjic. Imajo dokaj samoopisna imena. Paket which key sproti izpisuje, kaj kateri gumb počne oz. kam nas pelje dalje.

  (use-package general
    :config
    (general-evil-setup t)

    ;; Leader key nastavitev (za prozenje ukazov)
    (general-create-definer start/leader-keys
      :states '(normal insert visual emacs rcirc)
      :keymaps 'override
      :prefix "SPC"
      :global-prefix "C-SPC")

Splošne bližnice

Tukaj se nahajate samo bližnjici za preklop med bufferji (kako bi to lepo prevedli?). In pa ukaz za ponovno naložit konfiguracijo emacsa.

  (defun ponovno-nalozi-config ()
    "Ponovno naloži emacs konfiguracijo"
    (interactive)
    (load-file "~/.emacs.d/init.el"))
  
  (start/leader-keys
    ;; Osnovne bliznjice
    "[" 'previous-buffer
    "]" 'next-buffer
    "r" 'ponovno-nalozi-config
    "u" 'font-lock-update
  )

Upravljanje z okni

Navigacijo med okni izvajamo s klasičnimi HJKL UNIX smernimi tipkami, recimo okno pod trenutnim izberemo s SPC w j. Posamezno okno pa lahko razdvojimo vertikalno ali horizontalno s SPC w v oz. SPC w s. SPC w d "ubije" trenutni buffer in okno.

  (start/leader-keys
     "w" '(:ignore t :wk "window")
     "w j" 'windmove-down
     "w k" 'windmove-up
     "w h" 'windmove-left
     "w l" 'windmove-right
     "w s" 'split-window-below
     "w v" 'split-window-right
     "w d" 'kill-buffer-and-window)

Upravljanje z bufferji

Bližnjice za delo z bufferji se začnejo z b. Ne pozabimo na splošni bližnjici ([ in ] za prejšnji / naslednji buffer).

  (start/leader-keys
     "b" '(:ignore t :wk "buffer")
     "b b" 'switch-to-buffer
     "b p" 'previous-buffer
     "b n" 'next-buffer
     "b s" (defun scratch-buffer () "Show scratch buffer" (interactive) (switch-to-buffer "*scratch*"))
     "b d" 'kill-current-buffer
     "b k" 'kill-buffer)

Evalviranje

Sledeči ukazi so za evalviranje ELISP kode TODO napiši navodila

  (start/leader-keys
    :keymaps 'emacs-lisp-mode-map
    ;; EVAL ukazi
    "e" '(:ignore t :wk "eval")
    "e b" 'eval-buffer
    "e e" 'eval-expression
    "e r" 'eval-region
    "b e" 'eval-buffer)

Datoteke

Bližnjice za delo z datotekami se začnejo s f.

  (defun odpri-konfiguracijo () (interactive) (find-file "~/.emacs.d/config.org"))
  (defun odpri-init () (interactive) (find-file "~/.emacs.d/init.el"))
  (defun odpri-todo () (interactive) (find-file "~/org/TODO.org"))
  
  (start/leader-keys
     "f" '(:ignore t :wk "file")
     "f f" 'counsel-find-file
     "f c" 'odpri-konfiguracijo :wk "odpri konfiguracijo (config.org)"
     "f i" 'odpri-init :wk "odpri init.el"
     "f r" 'recentf :wk "nedavno odprto"
     "f z" 'odpri-zapiske
     "f t" 'odpri-todo)

Vplogled / introspekcija

Emacs nudi kup uporabnih funkcij, ki so nepogrešljive na poti učenja o funkcionalnosti. Zaenkrat sem definiral bližnjice do štirih od njih; opis funkcije, tipke, simbola (to so recimo rezervirana imena spremenljivk), načina (mode).

  (start/leader-keys
    "d" '(:ignore :t :wk "describe")
    "d f" 'describe-function
    "d k" 'describe-key
    "d s" 'describe-symbol
    "d m" 'describe-mode)

Info

Branje navodil, SICP, še kaj.

  (start/leader-keys
    "i" 'info)

Konec

Dodamo manjkajoči zaklepaj. :) To pa je malo grdo pri pismenem programiranju.

  )

EVIL

Ta sekcija vsebuje razne konfiguracije povezane z evil-mode - modalnim načino editiranja, podobnim vi/vim urejevalnikom.

Vklopi evil mode!

evil-shift-width nastavi širino tabulacije ko pritisnemo >

  (setq evil-want-integration t
        evil-want-keybinding nil
        evil-shift-width 2)
        ;org-return-follows-link t
  (require 'evil)
  (evil-mode 1)

Paket evil-collection pa vsebuje še dodatne evil bližnjice (recimo za help-mode, eshell in tako dalje).

  (use-package evil-collection
    :after evil
    :config
    (evil-collection-init))

Evil v orgmode načinu (pa tudi v org-agenda).

(use-package evil-org
  :after org
  :hook ((org-mode . evil-org-mode))
  :config
  (require 'evil-org-agenda)
  (evil-org-set-key-theme '(navigation insert textobjects additional calendar))
  (evil-org-agenda-set-keys)

V evil mode lahko linke znotraj ORG dokumentov odpiramo kar z RET.

  (defun odpri-org-link ()
    "Odpri link v ORG fajlu pod kurzorjem"
    (interactive)
    (if (org-in-regexp org-link-any-re nil t)
        (org-open-at-point)
        nil))

  (general-evil-define-key
      'normal
      org-mode-map
      "RET" 'odpri-org-link))

Evil v treemacs drevesu datotečnega sistema.

  ;(use-package treemacs-evil :after treemacs)

Emacs splošno

Dashboard

Prvi zaslon ob zagonu (homescreen), prikaže uporabne stvari.

  (use-package dashboard
    :general
    (start/leader-keys
      "b h" 'dashboard-open)
    :after nerd-icons
    :init
    (dashboard-setup-startup-hook)
    (setq initial-buffer-choice (lambda () (get-buffer-create "*dashboard*")))
    (setq dashboard-banner-logo-title "EMA☭S")
    (setq dashboard-startup-banner 3)
    (setq dashboard-center-content t)
    (setq dashboard-items '((agenda . 5)
                            (bookmarks . 3)
                            (recents  . 5)))
    ;(setq dashboard-display-icons-p t) ;; display icons on both GUI and terminal
    ;(setq dashboard-icon-type 'nerd-icons) ;; use `nerd-icons' package
    (setq dashboard-set-heading-icons t)
    (setq dashboard-set-file-icons t)
    (setq dashboard-set-navigator t)
    (setq dashboard-set-init-info t))

Vertico dopolnjevanje

Paket za dopolnjevanje, nadomestek ivy. Nudi nekoliko lepšo iskušnjo priporočil pri izvajanju emacs ukazov.

(use-package vertico
  :config
  (setq vertico-cycle t)
  (setq vertico-resize nil)
  (vertico-mode 1))

savehist sortira priporočila glede na preteklo rabo.

(use-package savehist
  :init
  (savehist-mode))

marginalia prikaze v minibufferju dopolni z uporabnimi informacijami, odvisno od konteksta.

(use-package marginalia
  :config
  (marginalia-mode 1))

orderless poskrbi, da minibuffer dopolnjevanje deluje tudi kadar v kakšnem drugem vrstnem redu napišemo besede. Recimo: inst pac ponudi package-install.

(use-package orderless
  :config
  (setq completion-styles '(orderless basic)))

nerd-icons-completion nam dired in ostalo dopolnjevanje pojača z ikonami.

  (use-package nerd-icons-completion
    :after marginalia
    :config
    (nerd-icons-completion-mode)
    :hook (marginalia-mode-hook . #'nerd-icons-completion-marginalia-setup))

Iskanje

swiper je ivy-jev iskalnik po bufferjih, ki nudi lep vmesnik s predogledom rezultatov, nastavimo ga na C-S.

  (use-package swiper
    :config
    (global-set-key "\C-s" 'swiper))

counsel pa nudi kup zamenjav privzetih emacs ukazov/operacij za prijetnejša opravila. Nastavimo nekaj bližnjic za njih. Recimo M-x menjava ki kaže predoglede v minibuferju, SPC RET za shranjevanje in menjavo med zaznamki, SPC / za ripgrep rekurzivno iskanje po vsebini datotek (potrebuje nameščen ripgrep!).

@TODO zamenjamo raje s consult?

  (use-package counsel
    :config
    ;(global-set-key (kbd "M-x") 'counsel-M-x)
    (global-set-key (kbd "C-x C-f") 'counsel-find-file)
    (global-set-key (kbd "<f1> f") 'counsel-describe-function)
    (global-set-key (kbd "<f1> v") 'counsel-describe-variable)
    (global-set-key (kbd "<f1> o") 'counsel-describe-symbol)
    (global-set-key (kbd "<f1> l") 'counsel-find-library)
    (global-set-key (kbd "<f2> i") 'counsel-info-lookup-symbol)
    (global-set-key (kbd "<f2> u") 'counsel-unicode-char)
    (global-set-key (kbd "C-c g") 'counsel-git)
    (global-set-key (kbd "C-c j") 'counsel-git-grep)
    (global-set-key (kbd "C-c k") 'counsel-ag)
    (global-set-key (kbd "C-x l") 'counsel-locate)
    (define-key minibuffer-local-map (kbd "C-r") 'counsel-minibuffer-history)
    (start/leader-keys
     "RET" 'counsel-bookmark
     "/" 'counsel-projectile-rg)

counsel-M-x poganjalnik ukazov doplnimo s paketom smex za prikazovanje nedavno uporabljenih ukazov pri vrhu.

  (use-package smex)

Šum pri iskalnih rezultatih ripgrep-a zmanjšamo z ignoriranjem node_modules direktorija javascript odvisnih paketov.

    (defvar my-rg-excludes '("node_modules")
      "List of directories to exclude from `counsel-rg' results.")
    (define-advice counsel-rg
        (:around (fn &optional in dir opts &rest args) my-glob)
      "Exclude `my-rg-excludes' from `counsel-rg' results."
      (let ((dir (or dir default-directory)))
        (dolist (x my-rg-excludes)
          (let ((glob (and (file-in-directory-p x dir)
                           (file-relative-name (expand-file-name "**" x) dir))))
            (when glob (setq opts (concat "-g !" glob (and opts " ") opts))))))
      (apply fn in dir opts args)))

Pomoč / introspekcija

Paket helpful obarva strani za pomoč ter doda več kontekstualnih informacij in pa nekaj funkcij za lažje razumevanje kaj je kje, recimo helpful-at-point, helpful-callable, helpful-command

  (use-package helpful :defer t)

which-key prikazuje minibuffer z razlago, katere tipkovnične bližnjice so na voljo.

  (use-package which-key
    :config
    ;; Allow C-h to trigger which-key before it is done automatically
    (setq which-key-show-early-on-C-h t)
    ;; make sure which-key doesn't show normally but refreshes quickly after it is
    ;; triggered.
    (setq which-key-idle-delay 0.2)
    (setq which-key-idle-secondary-delay 0.05)
    (which-key-mode))

Kolaborativno urejanje - CRDT

Paket crdt omogoča istočasno urejanje bufferjev, kar je superuporabno :) Paziti pa moramo na verzije emacsa; zaznali smo težave pri mešanju emacs 30/29 s starejšimi (28, 27) - znaki se lahko med odjemalci pomešajo. Emacs 29 in 30 bi morala vredu sodelovati.

  (use-package crdt
    :defer t
    :after general
    :general
    (start/leader-keys
      "c" '(:ignore t :wk "crdt")
      "c c" 'crdt-connect
    ;  "c c" 'crdt-connect)
    ;:general-config
    ;(start/leader-keys
      "c" '(:ignore t :wk "crdt")
      "c u" 'crdt-list-users
      "c s" 'crdt-share-buffer
      "c b" 'crdt-list-buffers))

Varnostne kopije

Privzeto emacs dodaja varnostne kopije fajlov v iste direktorije kot so originali, kar zna malo nasmetiti. Zato nastavimo direktorij, kam naj jih shranjuje ter nastavimo nekaj drugih priročnih stvari, naj kopira fajle namesto preimenovanja, brisanje starih (z nastavljenimi omejitvami ter verzioniranje varnostnih kopij.

  (setq
     backup-directory-alist
      `(("." . ,(concat user-emacs-directory "saves")))
     backup-by-copying t
     delete-old-versions t
     kept-new-versions 6
     kept-old-versions 2
     version-control t)

Za vsak odprt fajl emacs ustvari lockfile, kar tudi zna smetiti (so pa zato, da obvestijo če več ljudi istočasno odpre fajl). To izklopimo.

  (setq create-lockfiles nil)

Ne odpiraj pdf datotek

PDF dokumenti so včasih zelo veliki, raje jih odpirajmo s sistemskim preglejevalnikom.

  (use-package openwith
    :config
    (setq openwith-associations '(("\\.pdf\\'" "xdg-open" (file))))
    (openwith-mode t))

Lepši REPL (ielm)

Nekoliko bolj prijazen elisp REPL, ki ima med drugim zgodovino.

  (defun g-ielm-init-history ()
    "Obstojna ielm zgodovina."
    (let ((path (expand-file-name "ielm/history" user-emacs-directory)))
      (make-directory (file-name-directory path) t)
      (setq-local comint-input-ring-file-name path))
    (setq-local comint-input-ring-size 10000)
    (setq-local comint-input-ignoredups t)
    (comint-read-input-ring))
  (defun g-ielm-write-history (&rest _args)
    "Tole je povezano z obstojno ielm zgodovino."
    (with-file-modes #o600
      (comint-write-input-ring)))
  (use-package ielm
    :defer t
    :hook (ielm-mode-hook . (lambda ()
                              (eldoc-mode)
                              ;(paredit-mode)
                              (g-ielm-init-history)))
    :general
    (start/leader-keys
      ";" 'ielm)
    :config
    (advice-add 'ielm-send-input :after 'g-ielm-write-history)
    (define-key inferior-emacs-lisp-mode-map (kbd "C-l")
                'comint-clear-buffer)
    (define-key inferior-emacs-lisp-mode-map (kbd "C-r")
                'helm-comint-input-ring))

ORG

Orgmode je način, v katerem je spisan tale dokument. Orgmode je marsikaj, lahko bi ga pa strnili v razširitev navadnega (plain) teksta.

  (add-to-list 'auto-mode-alist '("\\.org$" . org-mode))
  (use-package org

Dodamo tudi bližnjice za org-capture ter org-agenda. TODO dodaj več!

    :after general
    :general
    (start/leader-keys
      "o" '(:ignore t :wk "orgmode")
      "o c" 'org-capture
      "o a" 'org-agenda)
    :general-config
    (start/leader-keys
      :keymaps 'org-mode-map
      "o i" 'org-toggle-inline-images
      "o t" 'org-time-stamp
      "o r" 'org-refile)

V org dokumente lahko vnašamo bloke vsebin, kot so programska koda, citati in podobno. Privzeto to dosežemo s C-c C-, in izbiro vrste željenega bloka, s sledečo konfiguracijo pa vklopimo bližnjico; na prazni vrstici samo "<s" TAB vstavi blok izvorne kode.

    :config
    (require 'org-tempo)
    (setq org-src-tab-acts-natively nil)

Za lepšo preglednost skrijemo znake za krepitev črk, podčrtovanje in podobno.

    (setq org-hide-emphasis-markers t)

Nastavimo lokacije org-agenda dokumentov in pa privzeto datoteko za zapiske

  (setq org-agenda-files (list "~/org/TODO.org" "~/org/projekti.org"))
  (setq org-default-notes-file "~/org/TODO.org")

Koledarski teden naj se začne s ponedeljkom, kot je pri nas konvencija.

  (setq calendar-week-start-day 1)

Slike naj bodo omejene širine.

  (setq org-image-actual-width (list 600))

Diagrami

Razširitev orgmode z diagramiranje preko DOT ter ditaa.

    (org-babel-do-load-languages
      'org-babel-load-languages
      '((dot   . t)
        (ditaa . t)
        (clojure . t)))

Z ob-mermaid paketom pa dodamo še podporo za prikazovanje mermaid diagramov! Delovanje tega paketa je odvisno od globalne namestitve javascript paketa z npm: sudo npm i -g @mermaid-js/mermaid-cli.

  (use-package ob-mermaid
    :after org
    :config
    ;; sudo npm install -g @mermaid-js/mermaid-cli
    (setq ob-mermaid-cli-path "/usr/local/bin/mmdc")
    (org-babel-do-load-languages
     'org-babel-load-languages
     '((mermaid . t)
       (scheme . t))))

Stanja opravil

Stanja opravil. Stanja (v naslovih) menjamo s S-<levo> in S-<desno>.

    (setq org-todo-keywords
      '((sequence "TODO" "NEXT" "V DELU" "TESTIRANJE" "DOKUMENTIRANJE" "DONE"))))

Nemoteno pisanje

Način writeroom-mode omogoča nemoteno pisanje; trenutni buffer raztegne čez cel zaslon in v sredino centrira širinsko-omejen tekst. Tako buffer izgleda bolj kot popisan list papirja.

  (use-package writeroom-mode
    :defer t
    :general
    (start/leader-keys
      "w w" 'writeroom-mode)
    :config
    :hook ((org-mode . (lambda () (display-line-numbers-mode -1)))))

Sinhronizacija koledarjev

Paket org-caldav omogoča sinhronizacijo koledarskih dogodkov v org dokumente. TODO popravi/preveri delovanje?

  (use-package org-caldav
    :defer t
    :init
    (setq org-caldav-url "https://goba.rhiz0.me/remote.php/dav/calendars/g1smo"
          org-caldav-files '("~/org/TODO.org")
          org-icalendar-timezone "Europe/Ljubljana"
          org-caldav-calendars '((:calendar-id "org"
                                  ;:files '("~/org/todo.org")
                                  :inbox "~/org/koledarji/org-in.org")
                                 (:calendar-id "personal"
                                  :inbox "~/org/koledarji/osebno-in.org")
                                 (:calendar-id "megla"
                                  :inbox "~/org/koledarji/megla-in.org"))))

Izgled

Za šminko olepšamo predpone (pod)poglavij v simbole namesto vrst zvezdic.

  (use-package org-bullets
    :after org
    :hook ((org-mode . (lambda () (org-bullets-mode 1)))))

Pri seznamih prikaži pike namesto vezajev.

  (font-lock-add-keywords
    'org-mode
    '(("^ *\\([-]\\) "
      (0 (prog1 () (compose-region (match-beginning 1) (match-end 1) "•"))))))

Za lepšo preglednost osvetlimo ozadje org blokov (recimo primere izvorne kode).

  (require 'color)
  (set-face-attribute 'org-block nil :background
    (color-darken-name
      (face-attribute 'default :background) 3))

Lepše pisave v blokih izvorne kode.

    (setq org-src-fontify-natively t)

Naslov dokumenta ter naslove in podnaslove prikaži z drugimi pisavami in velikostmi.

    ;; Drugačne pisave za naslove, svoje velikosti
    ;; Vir: https://zzamboni.org/post/beautifying-org-mode-in-emacs/
    (let* ((variable-tuple
            (cond ((x-list-fonts "ETBembo")         '(:font "ETBembo"))
                  ((x-list-fonts "Lucida Grande")   '(:font "Lucida Grande"))
                  ; tale pa ni free
                  ;((x-list-fonts "Verdana")         '(:font "Verdana"))
                  ((x-family-fonts "Sans Serif")    '(:family "Sans Serif"))
                  (nil (warn "Cannot find a Sans Serif Font.  Install Source Sans Pro."))))
             (headline           `(:inherit default :weight bold)))

        (custom-theme-set-faces
          'user
          `(org-level-4 ((t (,@headline ,@variable-tuple :height 1.1))))
          `(org-level-3 ((t (,@headline ,@variable-tuple :height 1.25))))
          `(org-level-2 ((t (,@headline ,@variable-tuple :height 1.45))))
          `(org-level-1 ((t (,@headline ,@variable-tuple :height 1.75))))
          `(org-document-title ((t (,@headline ,@variable-tuple :height 2.0 :underline nil))))))

(lepši) zamiki naslovov. Potrebuje svg-lib.

  ;(use-package svg-lib :defer t)
  ;(use-package org-margin
  ;  :after org svg-lib
  ;  :vc "https://github.com/rougier/org-margin"
  ;  :init (org-margin-mode 1))

Izvoz

V HTML org izvozu obarvaj bloke kode.

  (use-package htmlize :after org-mode :defer t)

Predstavitve

Bližnjice:

  • left/right for movement
  • C-c C-= for large txt
  • C-c C-- for small text
  • C-c C-q for quit (which will return you back to vanilla org-mode)
  • C-c < and C-c > to jump to first/last slide
  • C-c C-r for buffer read-only
  • C-c C-w for buffer read/write
  • C-c C-1 for one big page showing all slides
  (use-package org-present :after org-mode :defer t)
  (use-package htmlize :after org-mode :defer t)

Grafični vmesnik

Barvna tema je gruvbox, v varjanti gruvbox-dark-soft, s pisavo Iosevka.

  (use-package gruvbox-theme
    :config
    (load-theme 'gruvbox-dark-medium t))

  (set-frame-font "Iosevka Medium 11" nil t)

Modeline vrstica (v bufferjih spodaj) je iz doom emacsa.

  (use-package doom-modeline
    :init (doom-modeline-mode 1))

Uporabimo nerd ikone. POZOR pisavo naložimo z ukazom M-x nerd-icons-install-fonts.

  (use-package nerd-icons)

Drsenje (skrolanje)

Omogočimo gladko piksel skrolanje, v emacsu od verzije 29 dalje in nastavimo dve opciji, ki sta skopirani od drugje in za njih nevem kaj počneta. Mislim da vpivata na to, kako je, ko pridrsaš do dna okna.

  (pixel-scroll-precision-mode)
  ;; Nevem kaj to dela
  (setq scroll-conservatively 10)
  (setq scroll-margin 8)

Prihranimo prostor

Nekaj prostora prihranimo z umikom menija in orodne vrstice, iz katere tudi umaknemo ikone.

  (menu-bar-mode -1)
  (tool-bar-mode -1)
  (setq ns-use-proxy-icon nil)

Onemogočimo grafične dialoge. Namesto tega tekstovno odgovorimo y/n (skrajšana oblika).

  (setq use-dialog-box nil)
  (fset 'yes-or-no-p 'y-or-n-p)

Umaknemo tudi naslove okvirjev.

  (setq frame-title-format nil)

Ob strani piksle pridobimo s skrivanjem drsnega traka.

  (scroll-bar-mode -1)

Zmanjšamo razmike med okni.

  (setq window-divider-default-bottom-width 3)
  (window-divider-mode t)

Transparentno ozadje

  (set-frame-parameter nil 'alpha-background 90)
  (add-to-list 'default-frame-alist '(alpha-background . 90))

Tekst

V široko paleto funkcionalnosti emacsa spada tudi urejanje navadnega teksta.

Tekst naj se prelamlja ob robu okna! Skrolanje na stran je naporno…

  (global-visual-line-mode)

Ponavadi nas tudi zanimajo številke vrstic. Predvsem zaradi urejanje kode, morda bi to bolj pasalo v odsek programiranja TODO.

  (global-display-line-numbers-mode)

Namesto navadnega undo/redo lahko uporabimo drevesne razveljavitve. Teh dreves nisem zares nikoli neposredno uporabljal, je pa praktično shranjevanje zgodovine undoja v emacsov nastavitveni direktorij.

  (use-package undo-tree
    :config
    (global-undo-tree-mode)
    (evil-set-undo-system 'undo-tree)
    ;; Drevo razveljavitev shrani v emacsov folder
    (setq undo-tree-history-directory-alist '(("." . "~/.emacs.d/undo"))))

In pa nenazadnje, čeravno je ORGMODE superioren, naložimo še podporo za markdown.

  (use-package markdown-mode :mode "\\.(md|markdown)\\'")

GNU/Guix

  (use-package guix :ensure f :defer t)

Pretty SHA path

Minor mode, ki SHA hashe v bufferju skrajša in tako poveča preglednost.

  (use-package pretty-sha-path
    :ensure t
    :config
    (pretty-sha-path-global-mode))

Delo s projekti

Knjižnica za projektne interakcije. Vsak projekt je svoja git zbirka. Lajša menjavo med projekti, iskanje datotek v posameznem projektu in tako dalje.

  (use-package projectile

Vlopimo projectile način, prezrimo direktorij z javascript paketi in priklopimo na ivy mehanizem za avtomatsko dopolnjevanje. SPC p odpre preddefinirano drevo bližnjic za delo s projectile.

    :config
    (projectile-mode 1)
    (start/leader-keys "p" 'projectile-command-map)
    (setq projectile-globally-ignored-directories '("node_modules"))

Zaradi težav pri uporabi projectile preko SSH povezav spremenimo način indeksiranja datotečnega drevesa. Dodajanje večjega projekta zato traja nekoliko dlje

    (setq projectile-indexing-method 'hybrid)
    (setq projectile-enable-caching t)
    ;(add-to-list 'tramp-remote-path 'tramp-own-remote-path)
    ;(setq-default projectile-indexing-method 'alien)

Datoteke sortiraj glede na nedavno uporabljene bufferje in nato nedavno odprte.

    (setq projectile-sort-order 'recently-active))

counsel-projectile nudi dodatne integracije z ivy sistemom dopolnjevanja.

  (use-package counsel-projectile :after projectile)

org-projectile omogoča vzdrževanje ORG TODO list na posameznih projektih.

  (use-package org-projectile :after projectile)

Oblikovanje teksta

Editorconfig omogoča nastavljanje oblikovanje tekstovnih fajlov na ravni posameznega projekta.

  (use-package editorconfig
    :config
    (editorconfig-mode 1))

Datotečno drevo

treemacs nudi vizualni drevesni pregled nad datotekami in direktoriji za posamezni projekt. Vklop je nastavljen na SPC t. Številke vrstic nas v drevesnem bufferju ne zanima. Pridodamo še paket za projectile podporo.

  (use-package treemacs
    :defer t
    :general
    (start/leader-keys
      "t" 'treemacs)
    :hook ((treemacs-mode . (lambda () ;; Brez stevilk vrstic v file drevesu!
                              (display-line-numbers-mode -1)))))
  (use-package treemacs-projectile :after treemacs)

Programiranje

Splošno

Za začetek nastavimo uporabo dveh navadnih presledkov za tab zamik.

  (setq-default tab-width 2) 
  (setq-default indent-tabs-mode nil)
  (setq indent-line-function 'insert-tab)

Vklopimo avtomatsko zapiranje oklepajev ter emacsovo avtomatsko zamikanje.

  (electric-indent-mode 1)
;  (electric-pair-mode 1)

Samodejno zapiranje oklepajev. Tega ne rabimo ker imamo electric-pair-mode, ki je vgrajen v emacs in lepše obravnava zamik teksta ob vstopu v novo vrstico.

  (use-package smartparens-mode
    :ensure smartparens
    :hook (prog-mode text-mode markdown-mode)
    :config
    (require 'smartparens-config)
    (sp-pair "'" "'" :actions nil))

Avtomatsko dopolnjevanje izrazov.

  (use-package company
    :config
    (setq lsp-completion-provider :capf)
    :init (global-company-mode))

flycheck sproti preverja sintakso kode in opozarja na morebitne nečednosti.

  (use-package flycheck
    :defer t
    :init (global-flycheck-mode))

Avtomatsko oblikovanje kode za razne programske jezike. Kličemo ga ročno. TODO dodamo kakšno bližnjico?

  (use-package format-all :defer t)

direnv integracija omogoča uporabo definiranih okoljskih spremenljivk na posameznih projektih (recimo vključitev drush v PATH za drupal).

  (use-package direnv :config (direnv-mode))

GIT

magit paket je super za delo z git sistemom za deljeno verzioniranje kode ali drugih podatkov.

  (use-package magit
    :defer t
    :general
    (start/leader-keys
      "g" '(:ignore t :wk "magit")
      "g s" 'magit-status)
    :config

Sledeča konfiguracija prepreči zamrznitev ko stage-amo spremembe preko TRAMP povezave.

    (defun my--tramp-send-command--workaround-stty-icanon-bug (conn-vec orig-command &rest args)
      "See: https://github.com/magit/magit/issues/4720"
      (let ((command
             (if (string= "stty -icrnl -icanon min 1 time 0" orig-command)
               "stty -icrnl"
               orig-command)))
           (append (list conn-vec command) args)))

    (defun my--tramp-send-command--workaround-stty-icanon-bug--filter-args (args)
      (apply #'my--tramp-send-command--workaround-stty-icanon-bug args))

    (advice-add 'tramp-send-command :filter-args
      #'my--tramp-send-command--workaround-stty-icanon-bug--filter-args))

Z magit-todos si malo olajšamo spremlajnje TODO-jev v drevesu kode. Zaenkrat onemogočeno, zaradi težavo preko TRAMP povezav.

;(use-package magit-todos 
;  :after magit
;  :config (magit-todos-mode 1))

Tree-sitter

Tree-sitter je knjižnica za inkrementalno razčlenjevanje (parsing) programske kode. Na podlagi definicij slovnic za različne programske jezike (namestimo jih z M-x treesit-install-language-grammar) omogoča obarvanja kode, priporočila in podobno. To počne nekoliko hitreje kot klasični načini. Tukaj so definicije nadomestnih treesit načinov za določene programske jezike.

S treesit-auto paketom se avtomatsko naredijo asociacije za treesit načine, vedno ko odpremo fajl s podporo ze treesitter pa nas obvesti o tem, da ga lahko namestimo. Tako ni treba ročno nastavljat za vsak programski jezik posebej.

  (use-package treesit-auto
    :custom
    (treesit-auto-install 'prompt)
    :config
    (treesit-auto-add-to-auto-mode-alist 'all)
    (global-treesit-auto-mode))

Spodaj pa je primer nastavitev ročnih asociacij s fajli, za menjavo z klasičnimi major načini.

;  (dolist
;    (item (list '("\\.css\\'"  . css-ts-mode)
;                '("\\.json\\'" . json-ts-mode)
;                '("\\.php\\'"  . php-ts-mode)
;                '("\\.py\\'"   . python-ts-mode)
;                '("\\.js\\'"   . js-ts-mode)))
;    (add-to-list 'auto-mode-alist item))

LISP

To poglavje zajema nastavitve raznih LISP dialektov.

Vsi LISPi, tudi vgrajeni emacs-lisp, so bolj berljivi z mavričnim obarvanjem oklepajev.

  (use-package rainbow-delimiters
    :hook ((prog-mode . rainbow-delimiters-mode)))

Geiser lajša delo s scheme jeziki, nastavljeno za GNU Guile. Omogoča recimo povezovanje v REPL (read-eval-print-loope).

  (use-package scheme-mode
    :ensure f
    :mode "\\.scm\\'")
    
  (use-package geiser-guile
    :defer t
    :general-config
    (start/leader-keys
      :keymaps 'geiser-mode-map
      "s" '(:ignore t :wk "geiser")
      "s b" 'geiser-eval-buffer
      "s e" 'geiser-eval-expression
      "s s" (defun geiser-start-and-eval-buffer ()
              (interactive)
              (geiser-guile)
              (previous-buffer)
              (geiser-eval-buffer))
      "s s" 'geiser-start-and-eval-buffer
      "s g" 'geiser
      "s c" 'geiser-connect
      "s k" 'geiser-exit-repl
      "s r" (defun geiser-restart ()
              ;(interactive)
              (geiser-exit-repl)
              (geiser-start-and-eval-buffer))
      "e" '(:ignore t :wk "eval (geiser)")
      "e b" 'geiser-eval-buffer
      "e e" 'geiser-eval-expression
      "e r" 'geiser-eval-region
      "b e" 'geiser-eval-buffer)
    :init
    (setq geiser-mode-auto-p nil))

Kdaj delam tudi z racket.

  (use-package racket-mode :mode "\\.rkt\\'")

Poskusimo še common lisp - SLIME!

  (use-package slime
    :defer t
    :config (setq inferior-lisp-program "/usr/bin/sbcl"))

Spletno

Način za obarvanje html, twig in podobne kode (jinja?) se imenuje web-mode. Dodamo še pripadajoč paket za olepševanje kode (avtomatsko prilagoditev zamikov kode).

  (use-package web-mode
    :mode "\\.(html|twig)\\'"
    :custom
    (web-mode-markup-indent-offset 2)
    (web-mode-css-indent-offset 2)
    (web-mode-code-indent-offset 2))
    
  (use-package web-beautify :after web-mode)

Ozadja pri vue-mode se z gruvbox temo rada grdo pomešajo, kar lahko rešimo s sledečim hookom:

  (add-hook 'mmm-mode-hook
            (lambda ()
              (set-face-background 'mmm-default-submode-face nil)))

CSS zamike nastavimo na 2 presledka, kot je drugje.

  (setq css-indent-level 2)
  (setq css-indent-offset 2)

Pri spletnem programiranju zelo prav pride tudi restclient odjemalec za pošiljanje HTTP poizvedb in pregled odzivov.

  (use-package restclient :defer t)

PHP

Podpora za programiranje s PHP domačo spletno stranjo oz. hipertekstualnim predprocesorjem.

  (use-package php-mode
    :mode "\\.(php|module)\\'"

Bližnjica za cache rebuild na drupalu (dela tudi preko SSH!).

    :general-config
    ;:general
    (start/leader-keys
      :keymaps 'php-mode-map
      "d d" (defun drupal-cache-rebuild ()
              (interactive)
              ;(shell-command "drush cr")
              (projectile-run-shell-command-in-root "./vendor/bin/drush cr")
              )))

Sicer obstaja tudi način ki lajša delanje z drupalom.

  (use-package drupal-mode :after php-mode)

Geben je za php debugiranje.

  (use-package geben
    :after php-mode
    :config
    (setq geben-pause-at-entry-line nil)
    (setq geben-dbgp-default-port 9003))

Javascript

Najprej nastavimo zamike.

  (setq js2-strict-missing-semi-warning nil
        js2-missing-semi-one-line-override nil
        js2-basic-offset 2
        js-indent-level 2
        indent-tabs-mode nil
        tab-width 2)

js2 je en fajn način za javascriptanje.

  (use-package js2-mode
    :mode "\\.js\\'")

Vue način lajša razvoj z vue javascript ogrodjem. Integriran je z LSP, moramo pa za integracijo globalno namestiti npm paket: sudo npm i -g vue-language-server

(use-package vue-mode
  :mode "\\.vue\\'"
  :config (add-hook 'vue-mode-hook #'lsp))

rjsx pride prav pri recimo ogrodju react.

  (use-package rjsx-mode :after js2-mode)

Python

Zamik na 2 presledka.

  (setq python-indent-offset 2)

Podpora za delo z venv okolji.

  (use-package pyvenv
    :mode "\\.py\\'"
    :init
    (pyvenv-mode t)

Nastavljen naj bo na python3.

  (setq pyvenv-post-activate-hooks
        (list (lambda ()
                (setq python-shell-interpreter (concat pyvenv-virtual-env "bin/python3")))))
  (setq pyvenv-post-deactivate-hooks
        (list (lambda ()
                (setq python-shell-interpreter "python3")))))

Živo kodiranje

supercollider je platforma za zvočno sintezo in algoritmično kompozicijo. Uporabna tudi za živo kodiranje. Vključuje svoje integrirano razvijalsko okolje, integrira se pa tudi z emacsom.

Najprej moramo vključit direktorij, v katerem se nahajajo emacs paketi zanj (pridejo iz v supercolliderju nameščenega quarka), lahko bi pra prišel iz paketnega upravljalnika linux distribucije ali pa MELPE:

  (add-to-list 'load-path "~/.local/share/SuperCollider/scel/el")
;  (add-to-list 'load-path "~/.guix-profile/share/emacs/site-lisp/scel-20170629-1.aeea3ad")

Nato vključimo emacs modul ter sclang-helper za lažjo evalvacijo kode in nastavimo bližnjice; C-RET za evalviranje "trenutne regije" (med zunanjimi oklepaji), C-c C-c za evalvacijo vrstice ali izbrane regije ter C-. za utišanje (kot v IDE-ju).

  (require 'sclang)
  
  ;; Za branje dokumentacije
  (use-package sclang-extensions
    :config
    (load "~/.emacs.d/sclang-helper.el")
    (add-hook 'sclang-mode-hook 'sclang-extensions-mode)
    (add-hook 'sclang-mode-hook (lambda () (local-set-key (kbd "C-<return>") 'sclang-helper-eval-paren-region))))

Za branje supercollider dokumentacije potrebujemo še w3m paket.

  (use-package w3m :defer t)

Povozimo drug keybinding.

  (use-package bind-key
    :defer t
    :init
    (bind-key "C-c C-c" 'sclang-helper-eval-region-or-line sclang-extensions-mode-map)
    (bind-key* "C-." 'sclang-server-free-all sclang-extensions-mode-map))

fluxus je programsko okolje za hitro prototipiranje ter igranje z oz. učenje 3d grafike. Pisam je v schemu.

  (use-package fluxus-mode :defer t)

Extempore je programski jezik za kiberfizično programiranje.

  (use-package extempore-mode :mode "\\.xtm\\'")

Tidal cycles omogoča kodiranje glasbe z algoritmičnimi vzorci. Pred uporabo moramo namestiti še supercollider.

  (use-package tidal
    :defer t

Nastaviti mu moramo lokacijo BootTidal.hs datoteke, ki jo lahko namestimo s cabal-om ali kako drugače.

    :init
    ;; Tidal cycles lokacija
    (setq tidal-boot-script-path "~/.cabal/store/ghc-9.0.2/tidal-1.9.2-8e9cf9a217d87a6950880512f51893a6434970cd0690e831c563fc64ebd5de8f/share/BootTidal.hs"))

sardine je glasbeni inštrument v pythonu. Gre za pythonovski vmesnik v supercollider, namenjen živemu kodiranju. Supercollider in sardine najprej namestimo, pri uporabi pa nam pomagajo sledeče emacs funkcije.

  (setq python-shell-interpreter "python3"
          python-shell-interpreter-args "")
  
  (defun sardine/start-sardine ()
    "Start a new interactive Sardine Session"
    (interactive)
    (run-python))

  (defun sardine/eval-block ()
    "Evaluate a sardine code block"
    (interactive)
    (mark-paragraph)
    (if (and transient-mark-mode mark-active)
        (python-shell-send-region (point) (mark))
      (python-shell-send-region (point-at-bol) (point-at-eol)))
    (forward-paragraph))

  (defun sardine/stop-code ()
    "Stop all the Sardine code currently running"
    (interactive)
    (python-shell-send-string "panic()"))

  ; Unmapping keys from the Python mode
  ;(add-hook 'python-mode-hook
  ;          (lambda() (local-unset-key (kbd "C-c C-c"))))
  ;(add-hook 'python-mode-hook
  ;          (lambda() (local-unset-key (kbd "C-c C-s"))))

  ; Remapping keys
  (global-set-key (kbd "C-M-x") #'sardine/eval-block)
  (global-set-key (kbd "C-M-.") #'sardine/stop-code)

Konfiguracijski jeziki

YAML in TOML sta dva primera konfiguracijskih jezikov, s katerima kdaj delam.

  (use-package yaml-mode :mode "\\.yaml\\'")
  (use-package toml-mode :mode "\\.toml\\'")

Arduino

  (use-package arduino-mode :mode "\\.ino\\'")

Jezikovni strežnik

Podpora za protokol jezikovnega strežnika (LSP - Language Server Protocol) precej izboljša izkušnjo programiranja s priporočevanjem in dopolnjevanjem. Emacs spremeni v IDE (integrirano razvojno okolje).

(use-package lsp-mode
  :defer t

S sledečimi nastavitvami pospešimo delovanje.

  :config
  ;; Make gc pauses faster by decreasing the threshold.
  (setq gc-cons-threshold (* 100 1000 1000))
  ;; Increase the amount of data which Emacs reads from the process
  (setq read-process-output-max (* 1024 1024))) ;; 1mb

Clojure

clojure-mode za obarvanje in podobno

(use-package clojure-mode)

CIDER integrira clojure repl.

(use-package cider
  :after clojure-mode
  :general-config
  (start/leader-keys
    :keymaps 'clojure-mode-map
    ;; EVAL ukazi
    "e" '(:ignore t :wk "eval")
    "e b" 'cider-eval-buffer
    "e c" 'cider-connect
    "e e" 'cider-eval-dwim
    "e j" 'cider-jack-in
    "e r" 'cider-eval-region
    "b e" 'cider-eval-buffer)
  (cider-mode-map "C-<return>" 'cider-eval-last-sexp))

E-pošta

Emacs že vključuje mu4e (mu za emacs), modul ki omogoča brskanje po prejeti e-pošti. Pred uporabo je treba konfigurirati nekaj več stvari, potrebujemo recimo isync za pridobivanje pošte (tudi starejši mbsync je vredu), program mu za indeksiranje prejetih mejlov, oba pa tudi primerno nastavljena.

Prejemanje

isync

Namestitev

Najprej namestimo isync. Primer za guix ter debian.

  guix install isync
  sudo apt install  isync
Konfiguracija

Konfiguriramo ga v ~/.mbsyncrc. Primer je za dva poštna nabiralnika, ki bosta shranjena znotraj ~/.mail.


Create Both
Expunge Both
SyncState *

MaildirStore local
Path ~/.mail/
Trash Trash

IMAPAccount acc1
Host host1.org
User u1
PassCmd "gpg -q --for-your-eyes-only --no-tty -d ~/.mailpass.acc1.gpg"
SSLType IMAPS

IMAPAccount acc2
Host mail.kompot.si
User u2
PassCmd "gpg -q --for-your-eyes-only --no-tty -d ~/.mailpass.acc2.gpg"
SSLType IMAPS

IMAPStore acc1-remote
Account acc1

IMAPStore acc2-remote
Account acc2

MaildirStore acc2-local
Subfolders Verbatim
Path ~/.mail/acc2
Inbox ~/.mail/acc2/inbox

MaildirStore acc1-local
Subfolders Verbatim
Path ~/.mail/acc1
Inbox ~/.mail/acc1/inbox

Channel acc1-default
Far :acc1-remote:
Near :acc1-local:

Channel acc2-default
Far :acc2-remote:
Near :acc2-local:
Create Both
SyncState *
Sync All

Group user
Channel acc1-default
Channel acc2-default
Kriptiranje gesel

Ker sta gesli za mejle shranjeni kriptirani z gpg, ju najprej kar v navadnem tekstu shranimo v ~/.mailpass.acc1 ter ~/.mailpass.acc2, nato pa poženemo:

  gpg -c ~/.mailpass.rs.gpg
  gpg -c ~/.mailpass.kompot.gpg

mu

Najprej namestimo (guix oz. debian):

  guix install mu
  sudo apt install mu

Nato inicializiramo.

  mu init --maildir=~/.mail --my-address=u1@host1.org --my-address=u2@kompot.si

Indeksiramo s sledečim ukazom ali pa kar iz dashboarda mu4e:

  mu index

mu4e

Vključimo paket in nastavimo ukaz za pridobivanje mejlov, ki ga sproži mu4e.

  (use-package mu4e
    :ensure f
    :defer t
    :config
    (setq mu4e-get-mail-command "mbsync -a"))

Preglednost lahko izboljšamo s paketom za ikone.

  (use-package mu4e-marker-icons
    :after mu4e
    :config
    (mu4e-marker-icons-mode 1))
Dodatki

mu4e-dashboard omogoča pripravo "nadzorne plošče", torej domačega zaslona pregleda mejlov, ki je pravzaprav ORG dokument z mu4e poizvedbami. Recimo, da prikaže koliko imamo skupno neprebranih sporočil in pa da skočimo na skupek vseh z zastavico označenih sporočil.

  (use-package mu4e-dashboard   
    :after mu4e)
;    :vc "https://github.com/rougier/mu4e-dashboard")

mu4e-thread-folding nam skrči niti v posamezne vrstice, ki jih lahko razširimo.

  (use-package svg-icon)
;    :vc (svg-icon :url "https://github.com/rougier/emacs-svg-icon"))
    
  ;(use-package mu4e-thread-folding
   ; :after mu4e
   ; :vc (mu4e-thread-folding :url "https://github.com/rougier/mu4e-thread-folding"))

TODO spisat dodatne konfiguracije, tega še ne uporabljam res.

Pošiljanje

(require 'smtpmail)
(setq send-mail-function        'smtpmail-send-it
      smtpmail-smtp-server      "kompot.si"
      smtpmail-stream-type      'ssl
      smtpmail-auth-credentials "~/.mailpass.kompot.gpg"
      smtpmail-stream-type      'starttls
      smtpmail-smtp-service     587)

Razno

Zone nyancat!

  (use-package zone-nyan :defer t)