Questo file mostra come gestire la configurazione di Emacs direttamente all'interno di org-mode. Questo stesso file è anche la mia personale configurazione per Doom Emacs.

Emacs§

Innanzitutto, cos'è Emacs?

Emacs is not a text editor, this is a common misnomer. It is far more apt to describe Emacs as a Lisp machine providing a generic user-centric text manipulation environment. That’s quite a mouthful. In simpler terms one can think of Emacs as a platform for text-related applications. It’s a vague and generic definition because Emacs itself is generic. (@tecosaur)

Se solitamente Emacs è conosciuto come editor di testo, in verità sotto la scocca si tratta di qualcosa di molto più complesso: Emacs è una lisp machine, ovvero un sistema integrato capace di interpretare ed eseguire codice lisp e, con esso, una miriade di programmi pure molto articolati, tipicamente legati alla manipolazione del testo. Considerata la versatilità della piattaforma, mi sarebbe impossibile descriverla senza disseminare avverbi come "solitamente" o "tipicamente".

Io, ad esempio, uso quotidianamente Emacs per:

Per qualche tempo l'ho usato anche come emulatore di terminale, ora capita solo in circostanze particolari, ad esempio per compilare del codice che sto scrivendo nel buffer a fianco.

Distribuzioni Emacs§

La barriera di ingresso, in verità, può essere parzialmente abbattuta per mezzo di distribuzioni Emacs pre-configurate, tra cui ne cito qualcuna, pescando tra le più famose:

  • Spacemacs è stata la mia prima distribuzione: è particolarmente indicata per i neofiti in arrivo da vim, come ero io. Non solo è efficace nell'emulare vim (grazie ad Evil), ma dispone anche di miriadi di funzioni ausiliarie richiamabili con un semplice tocco sulla barra spaziatrice (space-emacs, non a caso).
  • NANO Emacs: dipendenze minime, eccezionalmente elegante, funzionalmente molto vicina a Vanilla Emacs;
  • Doom Emacs è la mia distribuzione attuale, e quindi quella con cui sto scrivendo questo documento; anche questa (come Spacemacs) è molto bene integrata con Evil e si presta bene alle esigenze di ogni ex-vimmer. Inoltre, l'impiego di svariate strategie di lazy-loading e, in generale, una meditata selezione dei pacchetti rendono questa distribuzione estremamente scattante.

La configurazione riportata in questo file può, potenzialmente, essere adattata anche ad altre distribuzioni Emacs, ma presa com'è funziona solo su Doom Emacs.

Emacs Lisp§

Come dicevo, Emacs è un interpreter di lisp, ma per essere più corretti dovremmo fare riferimento ad Emacs Lisp, un dialetto della famiglia di linguaggi di programmazione che rientra sotto la denominazione "Lisp" (LISt Processor).

Come già detto altrove 1, "visto un dialetto di lisp, visti tutti":

if you've seen one lisp, you've seen them all

Non voglio dilungarmi in questa sede nella descrizione del linguaggio. Per un assaggio della sintassi e di qualche funzione base, piuttosto, rimando a questo post che ho scritto sul blog come breve introduzione.

In caso voleste spingervi lievemente oltre, rimando a questi altri post (in ordine di difficoltà):

Avendo iniziato solo da poco tempo a navigare nell'oceano di meraviglie e parentesi lispiane, non sono certo la fonte più autorevole per scendere ancora più nel dettaglio. Per una guida rapida ad Emacs Lisp, consiglio di dare un'occhiata a questa repo. Per una guida meno rapida, ma più approfondita, fate riferimento a Learn elisp the hard way.

Org-mode§

Your life in plain text

Org-mode è una delle più amate major mode esistenti per Emacs ed è anche uno dei migliori pezzi di software che io abbia conosciuto in vita mia. A prima vista sembra "solo l'ennesimo linguaggio di markup", come Markdown o reStructuredText, ma in realtà è molto, molto di più 2.

Proprio come l'abissale versatilità di Emacs riesce a farsi conoscere solo grazie ad ore ed ore di utilizzo, anche Org-mode ha bisogno di tempo per essere addomesticato; in questo caso, in compenso, è più facile annoverare gli utilizzi più comuni:

  • applicazioni di literate programming (un paradigma di programmazione ideato da Donald Knuth, che è alla base anche di questo documento),
  • scrittura di agende
  • scrittura di zettelkasten
  • stesura di documenti scientifici
  • mantenimento di uno o più blog

Literate configuration§

Tradizionalmente, la configurazione di Doom Emacs è raccolta in 3 file fondamentali, a loro volta contenuti in una apposita directory nella home, .doom.d. Questi file sono:

  • config.el;
  • init.el;
  • packages.el.

Altre distribuzioni hanno gerarchie più semplici (Vanilla Emacs prevede sia tutto in .emacs) o più caotiche o più stratificate (es. layer in Spacemacs).

Doom, di suo, mantiene secondo me una piacevole via di mezzo.

Anziché intervenire su questi file direttamente, possiamo scrivere la nostra configurazione su un file .org, da cui generare in seconda battuta i 3 file di configurazione principali.

Let us change our traditional attitude to the construction of programs: Instead of imagining that our main task is to instruct a computer what to do, let us concentrate rather on explaining to human beings what we want a computer to do.

The practitioner of literate programming can be regarded as an essayist, whose main concern is with exposition and excellence of style. Such an author, with thesaurus in hand, chooses the names of variables carefully and explains what each variable means. He or she strives for a program that is comprehensible because its concepts have been introduced in an order that is best for human understanding, using a mixture of formal and informal methods that reinforce each other. — Donald Knuth

Come accennavo in una parentesi sopra, questa prassi si rifa' ai principi della programmazione letteraria (literate programming), un paradigma proposto per la prima volta da Donald Knuth, che ne dimostrò le potenzialità scrivendo così il compilatore di TeX.

Per maggiori dettagli sul literate programming in org-mode vedi la documentazione ufficiale.

Diego Zamboni, nella propria configurazione scrive:

Emacs config is an art, and I have learned a lot by reading through other people’s config files, and from many other resources.

Insomma, l'arte di configurare Emacs (come tante altre) si affina studiando i trucchetti altrui. Tra le configurazioni org più illuminanti, segnalo anche la configurazione di tecosaur. Per entrambe trovate anche i mirrors su Github (che renderizza piacevolmente anche i file org).

Ci sono vari modi per consentire ad Emacs di leggere la configurazione attraverso un org file; come tanti altri, io qui mi limito a generare i file di configurazione a partire dal file org, per mezzo di una pratica che Donald Knuth ha chiamato "tangling" (aggrovigliare).

Frontespizi§

Cominciamo dalla testa dei nostri file di configurazione, cioè da tutti i commenti che troviamo di norma nelle prime 10-20 righe. C'è solo una modifica che è il caso di fare in questo punto: aggiungere un piccolo commento che ricordi all'eventuale lettore che il file in uscita è un file generato e che non va modificato direttamente.

;; DO NOT EDIT THIS FILE DIRECTLY
;; This is a file generated from a literate programing source file located at
;; https://github.com/gicrisf/emacs-config
;; You should make any changes there and regenerate it from Emacs org-mode
;; using org-babel-tangle (C-c C-v t)

Frontespizio di init.el.

;;; init.el -*- lexical-binding: t; -*-

<<do-not-edit>>

;; This file controls what Doom modules are enabled and what order they load
;; in. Remember to run 'doom sync' after modifying it!

;; NOTE Press 'SPC h d h' (or 'C-h d h' for non-vim users) to access Doom's
;;      documentation. There you'll find a "Module Index" link where you'll find
;;      a comprehensive list of Doom's modules and what flags they support.

;; NOTE Move your cursor over a module's name (or its flags) and press 'K' (or
;;      'C-c c k' for non-vim users) to view its documentation. This works on
;;      flags as well (those symbols that start with a plus).
;;
;;      Alternatively, press 'gd' (or 'C-c c d') on a module to browse its
;;      directory (for easy access to its source code).

Frontespizio di packages.el.

;; -*- no-byte-compile: t; -*-
;;; $DOOMDIR/packages.el

<<do-not-edit>>

;; To install a package with Doom you must declare them here and run 'doom sync'
;; on the command line, then restart Emacs for the changes to take effect -- or
;; use 'M-x doom/reload'.


;; To install SOME-PACKAGE from MELPA, ELPA or emacsmirror:
;(package! some-package)

Frontespizio di config.el.

;;; $DOOMDIR/config.el -*- lexical-binding: t; -*-

<<do-not-edit>>

;; Place your private configuration here! Remember, you do not need to run 'doom
;; sync' after modifying this file!


;; Some functionality uses this to identify you, e.g. GPG configuration, email
;; clients, file templates and snippets.

Moduli§

Il codice seguente è impiegato da Doom Emacs per capire quali moduli installare e lanciare tutte le volte che viene avviato.

Input§

;;chinese
;;japanese
;;layout            ; auie,ctsrnm is the superior home row

Completion§

company           ; the ultimate code completion backend
;;helm              ; the *other* search engine for love and life
;;ido               ; the other *other* search engine...
ivy               ; a search engine for love and life

UI§

;;deft              ; notational velocity for Emacs
doom              ; what makes DOOM look the way it does
doom-dashboard    ; a nifty splash screen for Emacs
doom-quit         ; DOOM quit-message prompts when you quit Emacs
(emoji +unicode)  ; 🙂
hl-todo           ; highlight TODO/FIXME/NOTE/DEPRECATED/HACK/REVIEW
;;hydra
;;indent-guides     ; highlighted indent columns
;;ligatures         ; ligatures and symbols to make your code pretty again
;;minimap           ; show a map of the code on the side
modeline          ; snazzy, Atom-inspired modeline, plus API
;;nav-flash         ; blink cursor line after big motions
neotree           ; a project drawer, like NERDTree for vim
ophints           ; highlight the region an operation acts on
(popup +defaults)   ; tame sudden yet inevitable temporary windows
;;tabs              ; a tab bar for Emacs
;;treemacs          ; a project drawer, like neotree but cooler
;;unicode           ; extended unicode support for various languages
vc-gutter         ; vcs diff in the fringe
vi-tilde-fringe   ; fringe tildes to mark beyond EOB
;;window-select     ; visually switch windows
workspaces        ; tab emulation, persistence & separate workspaces
zen               ; distraction-free coding or writing

Editor§

(evil +everywhere); come to the dark side, we have cookies
file-templates    ; auto-snippets for empty files
fold              ; (nigh) universal code folding
;;(format +onsave)  ; automated prettiness
;;god               ; run Emacs commands without modifier keys
;;lispy             ; vim for lisp, for people who don't like vim
multiple-cursors  ; editing in many places at once
;;objed             ; text object editing for the innocent
;;parinfer          ; turn lisp into python, sort of
;;rotate-text       ; cycle region at point between text candidates
snippets          ; my elves. They type so I don't have to
;;word-wrap         ; soft wrapping with language-aware indent

Cursori multipli§

Basta usare g z z come shortcut sequenziale per avviare un altro cursore sul posto.

Emacs§

dired             ; making dired pretty [functional]
electric          ; smarter, keyword-based electric-indent
;;ibuffer         ; interactive buffer management
undo              ; persistent, smarter undo for your inevitable mistakes
vc                ; version-control and Emacs, sitting in a tree

Term§

;;eshell            ; the elisp shell that works everywhere
;;shell             ; simple shell REPL for Emacs
;;term              ; basic terminal emulator for Emacs
vterm               ; the best terminal emulation in Emacs

Checkers§

syntax              ; tasing you for every semicolon you forget
;;(spell +flyspell) ; tasing you for misspelling mispelling
;;grammar           ; tasing grammar mistake every you make

Tools§

;;ansible
;;debugger          ; FIXME stepping through code, to help you add bugs
;;direnv
;;docker
;;editorconfig      ; let someone else argue about tabs vs spaces
;;ein               ; tame Jupyter notebooks with emacs
(eval +overlay)     ; run code, run (also, repls)
;;gist              ; interacting with github gists
lookup              ; navigate your code and its documentation
lsp               ; M-x vscode
magit             ; a git porcelain for Emacs
;;make              ; run make tasks from Emacs
;;pass              ; password manager for nerds
;;pdf               ; pdf enhancements
;;prodigy           ; FIXME managing external services & code builders
;;rgb               ; creating color strings
;;taskrunner        ; taskrunner for all your projects
;;terraform         ; infrastructure as code
;;tmux              ; an API for interacting with tmux
;;upload            ; map local to remote projects via ssh/ftp

OS§

(:if IS-MAC macos)  ; improve compatibility with macOS
;;tty               ; improve the terminal Emacs experience

Lang§

;;agda              ; types of types of types of types...
;;beancount         ; mind the GAAP
;;cc                ; C > C++ == 1
;;clojure           ; java with a lisp
;;common-lisp       ; if you've seen one lisp, you've seen them all
;;coq               ; proofs-as-programs
;;crystal           ; ruby at the speed of c
;;csharp            ; unity, .NET, and mono shenanigans
;;data              ; config/data formats
;;(dart +flutter)   ; paint ui and not much else
;;elixir            ; erlang done right
;;elm               ; care for a cup of TEA?
emacs-lisp        ; drown in parentheses
;;erlang            ; an elegant language for a more civilized age
;;ess               ; emacs speaks statistics
;;factor
;;faust             ; dsp, but you get to keep your soul
;;fsharp            ; ML stands for Microsoft's Language
;;fstar             ; (dependent) types and (monadic) effects and Z3
;;gdscript          ; the language you waited for
;;(go +lsp)         ; the hipster dialect
;;(haskell +dante)  ; a language that's lazier than I am
;;hy                ; readability of scheme w/ speed of python
;;idris             ; a language you can depend on
;;json              ; At least it ain't XML
;;(java +meghanada) ; the poster child for carpal tunnel syndrome
javascript        ; all(hope(abandon(ye(who(enter(here))))))
;;julia             ; a better, faster MATLAB
;;kotlin            ; a better, slicker Java(Script)
latex             ; writing papers in Emacs has never been so fun
;;lean              ; for folks with too much to prove
;;ledger            ; be audit you can be
;;lua               ; one-based indices? one-based indices
markdown          ; writing docs for people to ignore
;;nim               ; python + lisp at the speed of c
;;nix               ; I hereby declare "nix geht mehr!"
;;ocaml             ; an objective camel
org               ; organize your plain life in plain text
;;php               ; perl's insecure younger brother
;;plantuml          ; diagrams for confusing people more
;;purescript        ; javascript, but functional
;;python            ; beautiful is better than ugly
;;qt                ; the 'cutest' gui framework ever
;;racket            ; a DSL for DSLs
;;raku              ; the artist formerly known as perl6
;;rest              ; Emacs as a REST client
;;rst               ; ReST in peace
;;(ruby +rails)     ; 1.step {|i| p "Ruby is #{i.even? ? 'love' : 'life'}"}
(rust + lsp)              ; Fe2O3.unwrap().unwrap().unwrap().unwrap()
;;scala             ; java, but good
;;(scheme +guile)   ; a fully conniving family of lisps
sh                  ; she sells {ba,z,fi}sh shells on the C xor
;;sml
;;solidity          ; do you need a blockchain? No.
;;swift             ; who asked for emoji variables?
;;terra             ; Earth and Moon in alignment for performance.
web               ; the tubes
yaml              ; JSON, but readable
;;zig               ; C, but simpler

Mail§

Per il momento, non uso Emacs per le mie email. Una volta ho provato a gestire tutto da CLI, anche con buoni risultati, ma a causa di problemi di vario genere alla fine ho deciso che era meglio tornare alla web-app. Non tanto perché sia una cattiva idea, quanto piuttosto perché è un inferno con tutto l'HTML pazzo che mettono in mezzo al testo, cosa che si può risolvere leggendo le mail con lynx o altri browser testuali, ma in fin dei conti dà l'impressione di stare sistematicamente forzando il mezzo. Usare il solito browser (coi dovuti accorgimenti) mi sembra la scelta più efficace. Ecco perché non uso mu4e, sebbene l'idea mi tenti di tanto in tanto.

;;(mu4e +gmail)
;;notmuch
;;(wanderlust +gmail)

Ed ecco che la tentazione ritorna: TODO, sincronizzare con protonmail.

App§

Uso Emacs come RSS reader.

;;calendar
;;emms
;;everywhere        ; *leave* Emacs!? You must be joking
;;irc               ; how neckbeards socialize
(rss +org)        ; emacs as an RSS reader
;;twitter           ; twitter client https://twitter.com/vnought

Config§

Questa è una literate configuration, quindi mi pare il caso di abilitare il modulo relativo.

literate
(default +bindings +smartparens)

Package!§

Chiaramente, non tutti i pacchetti disponibili per emacs sono stati integrati in moduli di Doom, quindi alcuni andranno installati per altre vie, ad esempio MELPA o delle repository git.

Manteniamo i commenti originali di packages.el all'interno del file.

Recipe§

;; To install a package directly from a remote git repo, you must specify a
;; `:recipe'. You'll find documentation on what `:recipe' accepts here:
;; https://github.com/raxod502/straight.el#the-recipe-format
;(package! another-package
;  :recipe (:host github :repo "username/repo"))

Files§

;; If the package you are trying to install does not contain a PACKAGENAME.el
;; file, or is located in a subdirectory of the repo, you'll need to specify
;; `:files' in the `:recipe':
;(package! this-package
;  :recipe (:host github :repo "username/repo"
;           :files ("some-file.el" "src/lisp/*.el")))

Disable§

;; If you'd like to disable a package included with Doom, you can do so here
;; with the `:disable' property:
;(package! builtin-package :disable t)

Override§

;; You can override the recipe of a built in package without having to specify
;; all the properties for `:recipe'. These will inherit the rest of its recipe
;; from Doom or MELPA/ELPA/Emacsmirror:
;(package! builtin-package :recipe (:nonrecursive t))
;(package! builtin-package-2 :recipe (:repo "myfork/package"))

Branch§

;; Specify a `:branch' to install a package from a particular branch or tag.
;; This is required for some packages whose default branch isn't 'master' (which
;; our package manager can't deal with; see raxod502/straight.el#279)
;(package! builtin-package :recipe (:branch "develop"))

Pin§

;; Use `:pin' to specify a particular commit to install.
;(package! builtin-package :pin "1a2b3c4d5e")

Unpin§

;; Doom's packages are pinned to a specific commit and updated from release to
;; release. The `unpin!' macro allows you to unpin single packages...
;(unpin! pinned-package)
;; ...or multiple packages
;(unpin! pinned-package another-pinned-package)
;; ...Or *all* packages (NOT RECOMMENDED; will likely break things)
;(unpin! t)

Configurazione§

Infine, veniamo alla configurazione vera e propria.

Chi sono?§

;; Some functionality uses this to identify you, e.g. GPG configuration, email
;; clients, file templates and snippets.
(setq user-full-name "gicrisf"
      user-mail-address "giovanni.crisalfi@protonmail.com")

Font§

TODO: differenziare tra font laptop e desktop e variare la configurazione esportata in base alla situazione.

;; Doom exposes five (optional) variables for controlling fonts in Doom. Here
;; are the three important ones:
;;
;; + `doom-font'
;; + `doom-variable-pitch-font'
;; + `doom-big-font' -- used for `doom-big-font-mode'; use this for
;;   presentations or streaming.
;;
;; They all accept either a font-spec, font string ("Input Mono-12"), or xlfd
;; font string. You generally only need these two:
(setq doom-font (font-spec :family "Noto Sans Mono" :size 16 :weight 'semi-light)
      doom-variable-pitch-font (font-spec :family "sans" :size 16))

Temi§

Default§

Innanzitutto, selezioniamo un tema di default.

;; There are two ways to load a theme. Both assume the theme is installed and
;; available. You can either set `doom-theme' or manually load a theme with the
;; `load-theme' function. This is the default:
(setq doom-theme 'doom-city-lights)

Al momento mi trovo bene con city lights: c'è solo una piccolezza che mi irrita parecchio. Nel momento in cui dichiaro concluso un task (con "DONE") in org-mode, il tema mi grigia non solo la keyword ma anche il titolo.

TODO cambiare questo comportamento.

Alcuni commenti da ricordare:

;; Here are some additional functions/macros that could help you configure Doom:
;;
;; - `load!' for loading external *.el files relative to this one
;; - `use-package!' for configuring packages
;; - `after!' for running code after a package has loaded
;; - `add-load-path!' for adding directories to the `load-path', relative to
;;   this file. Emacs searches the `load-path' when you load packages with
;;   `require' or `use-package'.
;; - `map!' for binding new keys
;;
;; To get information about any of these functions/macros, move the cursor over
;; the highlighted symbol at press 'K' (non-evil users must press 'C-c c k').
;; This will open documentation for it, including demos of how they are used.
;;
;; You can also try 'gd' (or 'C-c c d') to jump to their definition and see how
;; they are implemented.

Spacemacs§

Sono affezionato ai temi di spacemacs. Uso specialmente quello chiaro, se ho bisogno di sovrailluminare lo schermo.

(package! spacemacs-theme)

Mi piacerebbe molto avere a disposizione anche i colori di nano-emacs, ma per il momento sembra sia una cosa più complessa del previsto. Henrik Lissner ha detto un paio di volte che avrebbe intenzione di dedicare un intero modulo a questa integrazione, ma non sembra una priorità.

Ciclatore§

TODO: spiegare questo switcher.

;; Theme switcher functions
(defvar quick-switch-themes
  (let ((themes-list (list 'doom-city-lights
                           'doom-one
                           'spacemacs-light
                           'doom-one-light)))
    (nconc themes-list themes-list))
  "A circular list of themes to keep switching between.
Make sure that the currently enabled theme is at the head of this
list always.

A nil value implies no custom theme should be enabled.")

;; Thanks to narendraj9, user of emacs.stackexchange.com
;; https://emacs.stackexchange.com/questions/24088/make-a-function-to-toggle-themes
;; I just tweaked his code.
(defun toggle-theme ()
  (interactive)
  (if-let* ((next-theme (cadr quick-switch-themes)))
      (progn (when-let* ((current-theme (car quick-switch-themes)))
               (disable-theme (car quick-switch-themes)))
             (load-theme next-theme t)
             (message "Loaded theme: %s" next-theme))
    ;; Always have the dark mode-line theme
    (mapc #'disable-theme (delq 'smart-mode-line-dark custom-enabled-themes)))
  (setq quick-switch-themes (cdr quick-switch-themes)))

(map! :leader
      :desc "Quick toggle theme" "t t" #'toggle-theme)

UI§

;; This determines the style of line numbers in effect. If set to `nil', line
;; numbers are disabled. For relative line numbers, set this to `relative'.
(setq display-line-numbers-type t)

;; Maximize the window upon startup
;; TODO testing this one
(setq initial-frame-alist '((top . 1) (left . 1) (width . 114) (height . 32)))

;; Transparency
(set-frame-parameter (selected-frame)'alpha '(99 . 100))
(add-to-list 'default-frame-alist'(alpha . (99 . 100)))

Org-mode§

Innanzitutto, dichiariamo in quale directory vogliamo che risiedano la maggior parte dei file org (o almeno quelli usati più di frequente), così che Emacs sappia dove cercarli.

;; If you use `org' and don't want your org files in the default location below,
;; change `org-directory'. It must be set before org loads!
(setq org-directory "~/org/")

Downloads§

Adesso possiamo cominciare ad estendere Org-mode. Una prima killer feature, a mio avviso, è data da org-download, che ci consente di appiccicare direttamente degli allegati al file org senza mai abbandonare Emacs, né il documento stesso.

(package! org-download)
(require 'org-download)

org-download-clipboard è legato a SPC m a p dal 25 agosto 2020 in Doom Emacs.

Flashcards§

Una volta usavo Anki, ora mi sono chiesto perché usare una GUI quando posso semplicemente scrivere tutto il necessario.

(package! org-drill)
(require 'org-drill)

Journal§

(package! org-journal)
(require 'org-journal)
;; org journal
;; in ~/.doom.d/+bindings.el
;; From: https://www.rousette.org.uk/archives/doom-emacs-tweaks-org-journal-and-org-super-agenda/
(map! :leader
      (:prefix ("j" . "journal") ;; org-journal bindings
        :desc "Create new journal entry" "j" #'org-journal-new-entry
        :desc "Open previous entry" "p" #'org-journal-open-previous-entry
        :desc "Open next entry" "n" #'org-journal-open-next-entry
        :desc "Search journal" "s" #'org-journal-search-forever))

;; The built-in calendar mode mappings for org-journal
;; conflict with evil bindings
(map!
 (:map calendar-mode-map
   :n "o" #'org-journal-display-entry
   :n "p" #'org-journal-previous-entry
   :n "n" #'org-journal-next-entry
   :n "O" #'org-journal-new-date-entry))

;; Local leader (<SPC m>) bindings for org-journal in calendar-mode
;; I was running out of bindings, and these are used less frequently
;; so it is convenient to have them under the local leader prefix
(map!
 :map (calendar-mode-map)
 :localleader
 "w" #'org-journal-search-calendar-week
 "m" #'org-journal-search-calendar-month
 "y" #'org-journal-search-calendar-year)

(setq org-journal-dir "~/org/amalgam")
(setq org-journal-file-format "%Y-%m.org")
(setq org-journal-file-type 'monthly)

Wikinforg§

Richiama informazioni da Wikipedia direttamente su org.

(package! wikinforg)
(require 'wikinforg)

Spesso mi servono i contenuti in italiano. L'ideale sarebbe scegliere per ogni query.

;; (custom-set-variables '(wikinforg-wikipedia-edition-code "it"))

Purtroppo, i risultati che ottengo da questa versione sono poco accurati. Per il momento la disabiliterò.

Ricerca veloce§

Per il momento ne faccio a meno per lo stesso motivo per cui ho disabilitato deft (vedi più avanti).

;; (package! helm-org-rifle)

Web Tools§

(package! org-web-tools)
(require 'org-web-tools)

Zola§

L'exporter per Zola è un pacchetto che sto mantenendo io, quindi capita spesso che io debba testare delle modifiche in locale. package! gestisce i download, quindi in teoria non dovrebbe essere impiegato per la gestione di file in locale, ma Henrik Lissner consiglia di usare comunque la macro perché è stata adattata anche a questo genere di situazioni.

Aggiunge:

Note: with :no-byte-compile t, you don't have to run doom sync every time you make a change to the package.

Così:

(package! ox-hugo :recipe (:local-repo "lisp/ox-zola"))

Peccato che a me dia "runtime error":

Details: ((:private . packages) "home/cromo.doom.d/packages.el" (wrong-type-argument listp (doom-package-error "ox-hugo" . "Keyword argument :no-byte-compile not one of (:local-repo :files :flavor :build :pre-build :post-build :includes :type :repo :host :branch :protocol :remote :nonrecursive :fork :depth :source :inherit)")))

Non ho ben capito perché (che sia questo il problema? non mi pare...), ma ho risolto più brutalmente. Innanzitutto installo il codice dalla mia repo.

(package! ox-hugo :recipe (:host github :repo "gicrisf/ox-zola"))

In secondo luogo, faccio le modifiche in locale e lancio emacs-lisp-byte-compile-and-load tutte le volte che modifico qualcosa. Finché non riavvio Emacs, è possibile testare quanto si vuole. Forse un po' più scomodo, ma è un approccio che fa il suo sporco lavoro.

Esportare da org a Hugo/Zola Markdown richiede la scrittura di un :PROPERTIES: frontmatter. Ma io sono pigro e non mi va di riscrivere ogni volta lo scaffold del frontmatter, quindi ecco una funzione ausiliaria.

;; Generate ORG/Zola frontmatter
;; TODO Section management
;; MAYBE Add hook to org file IF hugo_base_dir or hugo_section is present at top
(defun org-zola-frontmatter (slug)
  "Insert org-mode properties under a paragraph to setup ox-hugo/zola exports"
  (interactive "sEnter slug: ")
  (insert ":PROPERTIES:\n"
          (concat ":EXPORT_HUGO_SECTION: 2022/" slug "\n")
          ":EXPORT_FILE_NAME: index\n"
          ":END:\n"))

Sempre al fine di automatizzare la produzione dei metadati, meglio automatizzare l'inserimento del timestamp con questa funzione org-mode:

;; add "CLOSED" when an item is set with DONE state
(setq org-log-done 'time)

Org-capture§

Org capture torna comodo per appuntarsi in org-mode frammenti di pagine web.

Come manipolare l'HTML, però, è qualcosa che noi dobbiamo spiegare ad org-capture, fornendo uno o più template.

;; org-capture
(setq org-capture-templates `(
	("p" "Protocol" entry (file+headline ,(concat org-directory "notes.org") "Inbox")
        "* %^{Title}\nSource: %u, %c\n #+BEGIN_QUOTE\n%i\n#+END_QUOTE\n\n\n%?")
	("L" "Protocol Link" entry (file+headline ,(concat org-directory "notes.org") "Inbox")
        "* %? [[%:link][%:description]] \nCaptured On: %U")
))

Al fine di usare Org capture extension (Firefox), dobbiamo anche impostare l'org-protocol.

The gist of it is to make your system recognize emacsclient as the handler of org-protocol:// links. In addition, one needs to set up emacs to load org-protocol and to set up capture templates.

Su linux, bisogna prima registrare questo handler:

[Desktop Entry]
Name=org-protocol
Exec=emacsclient %u
Type=Application
Terminal=false
Categories=System;
MimeType=x-scheme-handler/org-protocol;

A questo punto, su Gnome ed altri GTK-based Desktop Environments, è sufficiente lanciare questo comando:

$ update-desktop-database ~/.local/share/applications/

TODO Bibliography§

Tentativo di literate bibliography con org-mode basato su org-bib-mode, di Nicolas P. Rougier (il creatore di NANO Emacs).

Innanzitutto devo installare le dipendenze dal suo profilo Github.

(package! org-imenu :recipe (:host github :repo "rougier/org-imenu"))
(package! pdf-drop-mode :recipe (:host github :repo "rougier/pdf-drop-mode"))
(package! org-bib-mode :recipe (:host github :repo "rougier/org-bib-mode"))

Purtroppo, quando utilizzo require su org-imenu noto che qualcosa non va. Mi chiedo se il problema sia risolvibile impiegando Nano Emacs, ma non ho tempo per verificare. Anche se fosse, dubito che abbandonerei Doom Emacs, quindi per ora il tentativo mi pare evitabile.

(require 'org-imenu)
(require 'pdf-drop-mode)
(require 'org-bib-mode)

Lo stesso NPR rimanda ad org-ref (di John Kitchin) per chi volesse qualcosa di più elaborato. Anziché aggrovigliare i due blocchi precedenti, aggroviglio i prossimi.

(package! org-ref :recipe (:host github :repo "jkitchin/org-ref"))

Ora configuriamo org-ref.

(setq bibtex-completion-bibliography '("~/org/papers/bibliography.bib"
                                       "~/org/papers/dei.bib"
                                       "~/org/papers/master.bib"
                                       "~/org/papers/archive.bib")
      bibtex-completion-library-path '("~/org/papers/bibtex-pdfs/")
      bibtex-completion-notes-path "~/org/papers/notes/"
      bibtex-completion-notes-template-multiple-files "* ${author-or-editor}, ${title}, ${journal}, (${year}) :${=type=}: \n\nSee [[cite:&${=key=}]]\n"

      bibtex-completion-additional-search-fields '(keywords)
      bibtex-completion-display-formats
      '((article       . "${=has-pdf=:1}${=has-note=:1} ${year:4} ${author:36} ${title:*} ${journal:40}")
        (inbook        . "${=has-pdf=:1}${=has-note=:1} ${year:4} ${author:36} ${title:*} Chapter ${chapter:32}")
        (incollection  . "${=has-pdf=:1}${=has-note=:1} ${year:4} ${author:36} ${title:*} ${booktitle:40}")
        (inproceedings . "${=has-pdf=:1}${=has-note=:1} ${year:4} ${author:36} ${title:*} ${booktitle:40}")
        (t             . "${=has-pdf=:1}${=has-note=:1} ${year:4} ${author:36} ${title:*}"))
      bibtex-completion-pdf-open-function
      (lambda (fpath)
        (call-process "open" nil 0 nil fpath)))

Su consiglio di Kitchin, aggiungo queste impostazioni per semplificarmi il lavoro:

(require 'bibtex)

(setq bibtex-autokey-year-length 4
      bibtex-autokey-name-year-separator "-"
      bibtex-autokey-year-title-separator "-"
      bibtex-autokey-titleword-separator "-"
      bibtex-autokey-titlewords 2
      bibtex-autokey-titlewords-stretch 1
      bibtex-autokey-titleword-length 5)

(define-key bibtex-mode-map (kbd "H-b") 'org-ref-bibtex-hydra/body)

Now require it:

(require 'org-ref)

Vista la complessità della libreria, ho deciso per il momento di non aggrovigliare nulla e aspettare un momento che mi consenta di studiare meglio ogni impostazione.

Backtab§

;; Source: [[https://stackoverflow.com/questions/23692879/emacs24-backtab-is-undefined-how-to-define-this-shortcut-key]]
(global-set-key (kbd "<backtab>") 'un-indent-by-removing-4-spaces)
(defun un-indent-by-removing-4-spaces ()
  "remove 4 spaces from beginning of of line"
  (interactive)
  (save-excursion
    (save-match-data
      (beginning-of-line)
      ;; get rid of tabs at beginning of line
      (when (looking-s "^\\at-+")
        (untabify (match-beginning 0) (match-end 0)))
      (when (looking-at "^    ")
        (replace-match "")))))

Elfeed§

Elfeed is an extensible web feed reader for Emacs, supporting both Atom and RSS.

Di default, basta aggiungere gli URL dei feed desiderati in questa lista per avere già Elfeed operativo.

(setq elfeed-feeds (quote
                    (("https://www.zwitterio.it/rss.xml" stem)
                     ("https://materiaimpersonale.wordpress.com/feed/" lit))))

Io non uso più questo metodo perché trovo più comodo tenere i miei feed in un file org-mode separato.

Per abbellire elfeed, aggiungiamo elfeed-goodies. In particolar modo, cambia il layout (apre in un altro pannello verticale, anziché orizzontale) e si guadagna una powerline.

(package! elfeed-goodies)
(require 'elfeed-goodies)
(elfeed-goodies/setup)
(setq elfeed-goodies/entry-pane-size 0.5)

Ora voglio assicurarmi che elfeed appaia sulla dashboard (vedi sezione dedicata alla dashboard).

Linguaggi§

Typescript/React§

Innanzitutto, bisogna avere aggiunto alcuni moduli: web e javascript, in particolare. Per farlo, basta togliere ;; nel file di configurazione .doom.d/init.el, come fatto nel paragrafo sopra.

A questo punto, è possibile che uno voglia lavorare con file in formato .tsx. Il supporto per questo caso d'uso potrebbe arrivare presto, ma per il momento ci viene in soccorso una semplice riga di lisp nel file di configurazione, secondo il suggerimento di hlissner:

;; Support for Typescript/React
(add-to-list 'auto-mode-alist '("\\.tsx\\'" . typescript-mode))
  • Vanilla Emacs

    In caso foste in cerca di una soluzione per Vanilla Emacs o Spacemacs, quest'altra soluzione potrebbe fare al caso vostro:

    (use-package typescript-mode
      :mode (rx ".ts" string-end)
      :init
      (define-derived-mode typescript-tsx-mode typescript-mode "typescript-tsx")
      (add-to-list 'auto-mode-alist (cons (rx ".tsx" string-end) #'typescript-tsx-mode)))
    

    Praticamente dichiariamo una modalità derivata dalla typescript-mode e le assegniamo anche i file con estensione .tsx. Per maggiori dettagli, fate riferimento a questo issue su Github.

Vala§

Il supporto per Vala è largamente ereditato dalla mode per C#.

(package! vala-mode)
(require 'vala-mode)

Dired§

Drag and drop to dired:

(add-hook 'dired-mode-hook 'org-download-enable)

Markdown§

Funzioni ausiliarie che ho scritto per facilitarmi il lavoro quando scrivevo in Markdown per Zola. Come già spiegato sopra, ora esporto da org-mode, quindi l'utilità di queste funzioni è venuta meno, ma occasionalmente mi capita di impiegarle, quindi le lascio comunque.

TOML frontmatter (Zola)§

Immaginate di voler generare un nuovo file Markdown per il vostro sito web. In base al tipo di generatore, questo potrà avere bisogno di un frontespizio in TOML o in YAML, magari. Si tratta di pochi caratteri, ma scriverli di volta in volta può risultare un po' frustrante, soprattutto se si scrivono molti pezzi.

Allora perché non lasciare che sia Emacs a fare il lavoro per noi? Siccome non sono il primo ad essermi posto questa domanda, ho semplicemente riformulato una soluzione largamente adottata. La forza del programmatore, d'altronde, è la sua pigrizia.

Iniziamo scrivendo una funzione che generi il blocco di testo di cui abbiamo bisogno. Io utilizzo Zola per generare il mio blog, quindi potrei scrivere il frontespizio anche in YAML, ma TOML è il formato di riferimento (ed è anche quello che preferisco, senza alcun dubbio).

Vogliamo quindi ottenere qualcosa del genere:

+++
title=""
date=

[taxonomies]
categories=[""]
tags=[""]

[extra]
+++

Traduciamo in lisp:

;; Generate TOML frontmatter
(defun new-toml-frontmatter ()
  "Insert a TOML frontmatter for Markdown files"
  (interactive)
  (insert "+++\n"
          "title=\"\"\n"
          "date=\n"
          "\n"
          "[taxonomies]\n"
          "categories=[\"\"]\n"
          "tags=[\"\"]\n"
          "\n"
          "[extra]\n"
          "+++"))

Da EmacsWiki:

A Lisp function becomes a command when its body contains, at top level, a form that calls the special form `(interactive...)’. This special form does nothing when executed, but its presence in the function definition indicates that interactive calling is permitted. Its argument controls the reading of the function arguments in an interactive call.

Il resto penso sia fin troppo comprensibile perché meriti spiegazione.

Aggiungiamo questa nuova funzione a .doom.d/config.el (o .emacs in Vanilla Emacs). Poiché le funzioni nel config vengono rese disponibili al lancio di Emacs, è necessario un doom/reload (SPC-h-r).

Già invocare questa funzione nel momento della creazionee del file è ben più comodo della situazione di partenza, in cui dovevamo di volta in volta scrivere l'intero frontespizio. MA non è sufficiente: noi vogliamo che il frontespizio sia automaticamente generato su ogni file markdown nuovo di zecca.

Con la funzione add-hook possiamo agganciare il lancio della nostra funzione ad una modalità. Nel nostro caso, la markdown-mode:

(add-hook 'markdown-mode-hook
          (lambda ()
            (if (= (buffer-size) 0)
            (new-toml-frontmatter))
            (message "markdown hook")))

Da ora in avanti, basterà aprire un file Markdown vuoto perché Emacs inserisca automaticamente il frontespizio.

Shortcode (Zola)§

Con lo stesso approccio, si possono anche ottenere delle funzioni per aggiungere degli shortcode molto usati nel corpo del testo e persino associare delle combinazioni di tasti ad esse!

;; Generate Zola Shortcodes
(defun new-social-shortcode ()
  "Generate new twitter shortcode"
  (interactive)
  (insert "{% social\(\n"
          "social=\"tw\",\n"
          "url=\"\",\n"
          "author=\"\",\n"
          "date=\"\"\n"
          "\) %}"
          "\n"
          "{% end %}"))

Uniamoci, confratelli, nell'amore per Emacs.

Twitter§

Questo piccolo pacchetto (che conto di estendere presto) nasce per assolvere ad una funzione molto semplice: citare i tweet nel mio blog. Ne racconto qui:

(package! eltweet :recipe (:host github :repo "gicrisf/eltweet"))

Musica§

Di questa parte ho già parlato in un post dedicato.

;; Play Lo-Fi
;; Implementation of the knuth shuffle
;; TODO Start amberol or other music player
(defun nshuffle (sequence)
  (cl-loop for i from (length sequence) downto 2
        do (cl-rotatef (elt sequence (random i))
                    (elt sequence (1- i))))
  sequence)

(setq lofi-links '("https://www.youtube.com/watch?v=8nXqcugV2Y4" ;; 3:30 music session
                   "https://www.youtube.com/watch?v=FVue6P2VoTc"
                   "https://www.youtube.com/watch?v=NrJiXKwUjPI" ;; Music to put you in a better mood
                   "https://www.youtube.com/watch?v=kgx4WGK0oNU"
                   "https://www.youtube.com/watch?v=5qap5aO4i9A"))

(setq vaporwave-links '("https://www.youtube.com/watch?v=nVCs83gSYD0"  ;; architecture in tokyo - Summer Paradise
                        ))

(defun play-lofi ()
  "Play random lofi music on your browser"
  (interactive)
  (shell-command (concat "python -mwebbrowser " (car (nshuffle lofi-links)))))

(defun play-vaporwave ()
  "Play random lofi music on your browser"
  (interactive)
  (shell-command (concat "python -mwebbrowser " (car (nshuffle vaporwave-links)))))

Pretty print§

Questa è per la uso per il pretty-printing di HTML, di solito, ma va bene per un qualunque chunk XML:

(defun bf-pretty-print-xml-region (begin end)
  "Pretty format XML markup in region. You need to have nxml-mode
http://www.emacswiki.org/cgi-bin/wiki/NxmlMode installed to do
this.  The function inserts linebreaks to separate tags that have
nothing but whitespace between them.  It then indents the markup
by using nxml's indentation rules."
  (interactive "r")
  (save-excursion
    (nxml-mode)
    (goto-char begin)
    (while (search-forward-regexp "\>[ \\t]*\<" nil t)
      (backward-char) (insert "\n") (setq end (1+ end)))
    (indent-region begin end)
    (normal-mode))
  (message "Ah, much better!"))

Which key§

Let’s make this popup a bit faster

Dalla configurazione di tecosaur:

(setq which-key-idle-delay 0.5) ;; I need the help, I really do

Semantic analysis§

Rust (Racer)§

Come scrive Robert Krahn,

Racer used to be the best option for getting IDE features (code navigation etc) into Emacs. It is a non-LSP solution which is still faster than RLS and rust-analyzer. However, the number of features especially around code completion are not up to par with rust-analyzer anymore.

Il consiglio, quindi, è quello di passare direttamente al paragrafo successivo, ma chi proprio desiderasse Racer (che era piacevole), lascio qui tutte le istruzioni del caso.

Dopo avere abilitato rust in init.el, Doom Emacs lamentava l'introvabilità del binario di Racer:

Please set ‘racer-rust-src-path’ or ‘RUST_SRC_PATH’

Il primo problema derivava non tanto dal fatto che fosse scorretta la variabile racer-rust-src-path, ma che proprio non esistesse alcuna src-path perché bisognava prima che installarla:

rustup component add rust-src

Ma si ottiene un altro errore:

eldoc error: (user-error ....cargo/bin/racer exited with 127. ‘M-x racer-debug’ for more info)

Questo perché manca racer, che va installato a parte. Siccome Racer risiede nella nightly toolchain, installiamo prima quella:

rustup toolchain install nightly

Poi aggiungiamo gli strumenti da sviluppatore rustc-dev:

rustup component add rustc-dev --toolchain=nightly

Assicuriamoci che anche Cargo sia già installato e lanciamo:

cargo +nightly install racer

La compilazione potrebbe fallire, ma bisogna tenere a mente è che Racer non è al momento mantenuto:

Racer is not actively developped now. Please consider using newer software such as rust-analyzer.

Emacs potrebbe non individuare subito Racer, nonostante l'installazione.

"~/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library"

Quick fix per consentire ad Emacs di trovare i binari di Racer:

;; (setq racer-rust-src-path <<racer-path>>)

Io non uso più Racer, ma eldoc si ostina a farlo, dando sempre questo fastidiosissimo errore:

eldoc error: (user-error home/cromo.cargo/bin/racer exited with 127. ‘M-x racer-debug’ for more info)

Spiega @hlissner:

The :lang rust module doesn't use rust-mode, it uses rustic-mode, a fork of rust-mode.

When +lsp is not enabled, the module uses racer to provide code completion, type info in the minibuffer (eldoc) and other features, but the racer package depends on rust-mode, so it must be installed (but doom still doesn't use it directly).

Bisogna perciò evitare che Racer sia avviato tutte le volte che LSP non è attivo. Come ricordato da @subderisorious, per fortuna Doom ci consente di disabilitare un pacchetto della configurazione di default semplicemente richiamando la macro package! in packages.el.

(package! racer :disable t)

Rust (rust-analyzer)§

Circa sei mesi dopo, è tempo di dare un'occhiata a rust-analyzer. Dal manuale:

At its core, rust-analyzer is a library for semantic analysis of Rust code as it changes over time. This manual focuses on a specific usage of the library — running it as part of a server that implements the Language Server Protocol (LSP). The LSP allows various code editors, like VS Code, Emacs or Vim, to implement semantic features like completion or goto definition by talking to an external language server process.

Anche questa volta, possiamo usare rustup:

rustup component add rust-src

Io sto su Arch, quindi installo con pacman:

sudo pacman -S rust-analyzer

È il caso di specificare quale server intendiamo utilizzare, altrimenti Rustic potrebbe fraintendere o optare per Racer:

(setq rustic-lsp-server 'rust-analyzer)

Questo dovrebbe essere sufficiente, ma per essere proprio sicuri:

(after! lsp-rust
  (setq lsp-rust-server 'rust-analyzer))

Lanciamo lsp in un buffer con Rust ed assistiamo al compiersi della magia.

Curriculum Vitae§

Trovandomi costretto, ancora una volta, a scrivere un CV, mi sono detto, ancora una volta, quanto fosse necessario trovare un modo perché fosse l'ultima. Eppure, non importa quanto tempo si passi ad ideare degli automatismi, il CV è qualcosa di intrinsecamente in via di definzione, quindi sempre soggetto a cambiamenti. Non si può fare altro che rimaneggiarlo continuamente. Bisogna quindi focalizzarsi sulla via che garantisca l'attrito minore, così da rendere la pratica degli aggiornamenti non troppo detestabile. Il generato più importante di un CV, ad oggi, è sempre il formato stampabile, cioè un PDF. Ad un buon PDF si può arrivare principalmente per queste vie:

  • LaTeX
  • LibreOffice, Microsoft Office o altre suite d'ufficio WYSIWYG
  • Immagini (SVG e vettoriali in genere)

A me piacerebbe, però, anche avere una pagina web sempre aggiornata, quindi gestire un file esportabile sia in PDF (più o meno direttamente) che in HTML. LaTeX è scomodo per esportare in formati web ed io vorrei mantenere una matrice utile ad esportare da ambo i lati con anche piccole differenze (senza mantenere due file o due branch paralleli su git). C'è chi ottiene questo risultato esportando a partire da un JSON, ma figurarsi se mi metto a scrivere un JSON a mano. Si potrebbe mantenere un YAML/TOML da esportare in JSON che poi esporti nei vari formati, ma comunque mi sembra una strategia poco flessibile.

Sulla base di queste premesse, ho da poco cominciato a mantenere il mio CV in org-mode; poiché l'esportazione avviene attraverso LaTeX (via template AltaCV), torna comoda qualche funzione che tenga in ordine la directory di output ad ogni modifica.

(after! org
  ;; Import ox-latex to get org-latex-classes and other funcitonality
  ;; for exporting to LaTeX from org
  (use-package! ox-latex
    :init
    ;; code here will run immediately
    :config
    ;; code here will run after the package is loaded
    (setq org-latex-pdf-process
          '("pdflatex -interaction nonstopmode -output-directory %o %f"
            "bibtex %b"
            "pdflatex -interaction nonstopmode -output-directory %o %f"
            "pdflatex -interaction nonstopmode -output-directory %o %f"))
    (setq org-latex-with-hyperref nil) ;; stop org adding hypersetup{author..} to latex export
    ;; (setq org-latex-prefer-user-labels t)

    ;; deleted unwanted file extensions after latexMK
    ;; (setq org-latex-logfiles-extensions
    ;;      (quote ("lof" "lot" "tex~" "aux" "idx" "log" "out" "toc" "nav" "snm" "vrb" "dvi" "fdb_latexmk" "blg" "brf" "fls" "entoc" "ps" "spl" "bbl" "xmpi" "run.xml" "bcf" "acn" "acr" "alg" "glg" "gls" "ist")))

    (unless (boundp 'org-latex-classes)
      (setq org-latex-classes nil))))

(after! org
  (use-package! ox-extra
    :config
    (ox-extras-activate '(latex-header-blocks ignore-headlines))))

Manuali§

Le pagine dei manuali su Emacs mancano spesso di colore, cosa che le rende più difficili da leggere delle loro controparti web. Il seguente pacchetto corregge questa mancanza:

(package! info-colors)

Come illustrato nel README, per abilitarlo bisogna aggiungere un hook in config.el.

(add-hook 'Info-selection-hook 'info-colors-fontify-node)

Deft§

Set directory, extension to search for and explicitly say you want to search recursively in the subfolders.

;; Not using deft rn
;;(setq deft-directory "~/org"
;;      deft-extensions '("org" "txt"))
;;(setq deft-recursive t)

La funzione principale per me è troppo lenta, oltre ad essere fin troppo fornita. Per ora disabilito tutto, perché preferisco usare SPC+n+s (notes/search note).

Dashboard§

Open org configuration (SPC o c)§

Al posto di aprire la cartella .doom.d per configurare Emacs, da ora in avanti vogliamo aprire questo file direttamente, quindi la funzione nella dashboard va modificata. Per riuscirci, innanzitutto dobbiamo creare una funzione che apra questo file.

Ci servono due elementi, che possono variare di caso in caso:

  • Il nome del file
  • La directory in cui cercarlo
(setq config-org-file-name "config.org"
      config-org-directory "~/emacs-config")

Scriviamo una funzione dedicata all'apertura del file preselezionato.

(defun open-config-org ()
  "Open your private config.org file."
  (interactive)
  (find-file (expand-file-name config-org-file-name config-org-directory)))

Assegniamo una scorciatoia da tastiera dedicata, sulle orme di SPC+f+P (file > Private).

Come si fa?

In your config.el file add a map declaration using the :leader attribute and whatever prefix key you would like to use. Then after you have added the necessary prefix keys add a :desc "Description of the command" "key" #'elisp-command-to-execute for each shortcut you wish to add.

Con map!:

(map! :leader
      (:prefix-map ("o" . "open")
       :desc "Open your private config.org file." "c" #'open-config-org))

Per intervenire sul menù, prima diamo un'occhiata alle sezioni della dashboard.

(cl-subseq +doom-dashboard-menu-sections 0)

Otteniamo una lista, da cui estrapoliamo la funzione che vogliamo sostituire (questa):

("Open private configuration" :icon (all-the-icons-octicon "tools" :face 'doom-dashboard-menu-title) :when (file-directory-p doom-private-dir) :action doom/open-private-config)

Come intendiamo modificarla? Così:

("Open org configuration" :icon (all-the-icons-octicon "tools" :face 'doom-dashboard-menu-title) :action open-config-org)

Ora sostituiamola al menù con la funzione setf.

(setf (nth 5 +doom-dashboard-menu-sections) '("Open org configuration" :icon (all-the-icons-octicon "tools" :face 'doom-dashboard-menu-title) :action open-config-org))

Enter Elfeed (SPC e e)§

Ripercorro i passi fatti prima, ma stavolta senza dilungarmi in chiacchiere.

Prima assegno una scorciatoia da tastiera:

(map! :leader
      (:prefix-map ("e" . "elfeed")
       :desc "Enter elfeed." "e" #'elfeed))

Voglio questo elemento sulla dashboard:

("Open elfeed" :icon (all-the-icons-octicon "rss" :face 'doom-dashboard-menu-title) :action elfeed)

Stavolta vado a sostituire il terzo elemento, che raramente uso (Recently opened files).

(setf (nth 2 +doom-dashboard-menu-sections) '("Open elfeed" :icon (all-the-icons-octicon "rss" :face 'doom-dashboard-menu-title) :action elfeed))

Già che ci siamo, aggiungiamo una shortcut per aggiornare elfeed:

(map! :leader
      (:prefix-map ("e" . "elfeed")
       :desc "Update all the feeds in elfeed." "u" #'elfeed-update))

Quit and go Home (SPC q h)§

Una semplice scorciatoia da tastiera per tornare alla dashboard:

(map! :leader
      (:prefix-map ("q" . "quit/session")
       :desc "Switch to the dashboard in the current window, of the current FRAME." "h" #'+doom-dashboard/open))

Org Manual (SPC o i)§

Move "Open project" section of the dashboard and make space for the documentation.

Anche stavolta andiamo spediti.

Voglio questo elemento sulla dashboard:

("Open info" :icon (all-the-icons-octicon "info" :face 'doom-dashboard-menu-title) :action info)

Stavolta vado a sostituire il terzo elemento, che raramente uso (Recently opened files).

(setf (nth 3 +doom-dashboard-menu-sections) '("Open info" :icon (all-the-icons-octicon "info" :face 'doom-dashboard-menu-title) :action info))

Riprendiamo l'elemento rimosso...

("Open project" :icon (all-the-icons-octicon "briefcase" :face 'doom-dashboard-menu-title) :action projectile-switch-project)

... e sistemiamolo in prima posizione:

(setf (nth 0 +doom-dashboard-menu-sections) '<<switch-project-menu-section>>)

Aggiungiamo una scorciatoia per org-mode, che è una delle documentazioni più consultate dal sottoscritto.

(map! :leader
      (:prefix-map ("o" . "open")
       :desc "Open org manual." "i" #'org-info))

Doom documentation (SPC h d h)§

Just changing the name.

("Doom documentation" :icon (all-the-icons-octicon "book" :face 'doom-dashboard-menu-title) :action doom/help)

Lasciamo che resti in sesta posizione:

(setf (nth 6 +doom-dashboard-menu-sections) '<<open-doom-docs-menu-section>>)

Experimental. Just trying stuff out, but I stick with the regular banner for the moment.

See this discourse post.

A weebish example (not tangled code):

(defun my-weebery-is-always-greater ()
  (let* ((banner '("⢸⣿⣿⣿⣿⠃⠄⢀⣴⡾⠃⠄⠄⠄⠄⠄⠈⠺⠟⠛⠛⠛⠛⠻⢿⣿⣿⣿⣿⣶⣤⡀⠄"
                   "⢸⣿⣿⣿⡟⢀⣴⣿⡿⠁⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⣸⣿⣿⣿⣿⣿⣿⣿⣷"
                   "⢸⣿⣿⠟⣴⣿⡿⡟⡼⢹⣷⢲⡶⣖⣾⣶⢄⠄⠄⠄⠄⠄⢀⣼⣿⢿⣿⣿⣿⣿⣿⣿⣿"
                   "⢸⣿⢫⣾⣿⡟⣾⡸⢠⡿⢳⡿⠍⣼⣿⢏⣿⣷⢄⡀⠄⢠⣾⢻⣿⣸⣿⣿⣿⣿⣿⣿⣿"
                   "⡿⣡⣿⣿⡟⡼⡁⠁⣰⠂⡾⠉⢨⣿⠃⣿⡿⠍⣾⣟⢤⣿⢇⣿⢇⣿⣿⢿⣿⣿⣿⣿⣿"
                   "⣱⣿⣿⡟⡐⣰⣧⡷⣿⣴⣧⣤⣼⣯⢸⡿⠁⣰⠟⢀⣼⠏⣲⠏⢸⣿⡟⣿⣿⣿⣿⣿⣿"
                   "⣿⣿⡟⠁⠄⠟⣁⠄⢡⣿⣿⣿⣿⣿⣿⣦⣼⢟⢀⡼⠃⡹⠃⡀⢸⡿⢸⣿⣿⣿⣿⣿⡟"
                   "⣿⣿⠃⠄⢀⣾⠋⠓⢰⣿⣿⣿⣿⣿⣿⠿⣿⣿⣾⣅⢔⣕⡇⡇⡼⢁⣿⣿⣿⣿⣿⣿⢣"
                   "⣿⡟⠄⠄⣾⣇⠷⣢⣿⣿⣿⣿⣿⣿⣿⣭⣀⡈⠙⢿⣿⣿⡇⡧⢁⣾⣿⣿⣿⣿⣿⢏⣾"
                   "⣿⡇⠄⣼⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠟⢻⠇⠄⠄⢿⣿⡇⢡⣾⣿⣿⣿⣿⣿⣏⣼⣿"
                   "⣿⣷⢰⣿⣿⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⢰⣧⣀⡄⢀⠘⡿⣰⣿⣿⣿⣿⣿⣿⠟⣼⣿⣿"
                   "⢹⣿⢸⣿⣿⠟⠻⢿⣿⣿⣿⣿⣿⣿⣿⣶⣭⣉⣤⣿⢈⣼⣿⣿⣿⣿⣿⣿⠏⣾⣹⣿⣿"
                   "⢸⠇⡜⣿⡟⠄⠄⠄⠈⠙⣿⣿⣿⣿⣿⣿⣿⣿⠟⣱⣻⣿⣿⣿⣿⣿⠟⠁⢳⠃⣿⣿⣿"
                   "⠄⣰⡗⠹⣿⣄⠄⠄⠄⢀⣿⣿⣿⣿⣿⣿⠟⣅⣥⣿⣿⣿⣿⠿⠋⠄⠄⣾⡌⢠⣿⡿⠃"
                   "⠜⠋⢠⣷⢻⣿⣿⣶⣾⣿⣿⣿⣿⠿⣛⣥⣾⣿⠿⠟⠛⠉⠄⠄          "))
         (longest-line (apply #'max (mapcar #'length banner))))
    (put-text-property
     (point)
     (dolist (line banner (point))
       (insert (+doom-dashboard--center
                +doom-dashboard--width
                (concat line (make-string (max 0 (- longest-line (length line))) 32)))
               "\n"))
     'face 'doom-dashboard-banner)))

(setq +doom-dashboard-ascii-banner-fn #'my-weebery-is-always-greater)

Meteo (wttrin)§

Esiste già un frontend per Emacs, ma è da almeno cinque anni che non dà segni di manutenzione. Quindi lavorerò sul mio fork (tanto avevo comunque intenzione di aggiungere funzioni supplementari, avrei probabilmente forkato a prescindere).

Innanzitutto aggiungiamo questo pacchetto:

(package! wttrin :recipe (:host github :repo "gicrisf/emacs-wttrin"))

Qui lo configuro secondo le mie necessità:

(setq wttrin-default-cities '("Caltagirone" "Bologna" "Ferrara" "Catania"))
(setq wttrin-default-accept-language '("Accept-Language" . "it-IT"))

Mail (disabilitato)§

Quando Protonmail ha rilasciato ProtonBridge mi sono chiesto se non valesse la pena di ritentare un approccio locale alle email. Le alternative apprezzabili per il momento mi sembrano due:

  • Mozilla Thunderbird
  • Emacs

Thunderbird ha di recente ricevuto un importante aggiornamento che ha fatto fare all'app un apparente salto di qualità, anche in termini di design, cosa che sicuramente torna utile in un client email del 2022 in competizione con delle web app sempre più piacevoli da vedere.

Emacs, d'altra parte, mi consentirebbe di scrivere le email in org-mode ed all'interno di un sistema integrato con il mio flusso di lavoro abituale; posso persino scrivere in un buffer separato mentre mi occupo di qualcos'altro nel buffer principale ecc. La comodità di avere tutto a portata di shortcut è irresistibile, soprattutto se non c'è troppo da smanettare con strani script arrangiati in casa. Per una volta, mi trovo dinnanzi un servizio che supporta i client locali, anziché antagonizzarli (sì gmail, guardo proprio te). Per fortuna, c'è già che chi si è portato avanti su questa strada:

Il primo post, in particolar modo, torna utile per la sua brevità. Cosa bisogna fare?

ATTENZIONE!

Prima di continuare, tieni a mente che Proton Bridge è un servizio fornito solo ai possessori di un account premium. Io l'ho scoperto troppo tardi, motivo per cui lascerò tutto nel mio file di configurazione (potrebbe tornare utile in futuro), ma per ora non aggroviglierò nulla.

Installare ProtonBridge§

Da AUR:

yay protonmail-bridge

Si tratta di un'applicazione open source che rimane aperta in background e genera tutti i file necessari per autenticarsi in sicurezza mediante un client esterno. Apprezzo il fatto che non sia un'app di Electron, ma che il frontend sia in Qt. Ciononostante, comunque temo un po' per il consumo sul mio laptop.

Installare mbsync§

Innanzitutto, è necessario installare e configurare mbsync. Sarebbe materia per i miei literate dotfiles, ma al fine di tenere tutto in un posto preferisco gestire da qui anche questo.

sudo pacman -S isync

Configurazione di mbsync§

La configurazione di mbsync è l'ennesimo dotfile sulla home, ~/.mbsyncrc:

IMAPAccount proton
Host 127.0.0.1
User giovanni.crisalfi@protonmail.com
PassCmd "cat ~/.protonBridgePass"
SSLType NONE
CertificateFile /etc/ssl/certs/ca-certificates.crt

IMAPStore proton-remote
Account proton

MaildirStore proton-local
Subfolders Verbatim
Path ~/mail/proton
Inbox ~/mail/proton/inbox

Channel proton
Far :proton-remote:
Near :proton-local:
Patterns *
Create Both
SyncState *

Configurazione di mu4e§

Su Doom Emacs, è possibile abilitare il modulo mu4e onde avere quasi tutto l'occorrente.

Passiamo alla configurazione di mu4e.

  • Ricerca delle mail ogni mezzora;
  • Recupero delle mail attraverso mbsync;
  • Tutte le mail finiscono nella home, sotto la cartella mail.
  • Le shortcut per il momento seguono la notazione inglese.
(setq mu4e-change-filenames-when-moving t ; avoid sync conflicts
      mu4e-update-interval (* 30 60) ; check mail 30 minutes
      mu4e-compose-format-flowed t ; re-flow mail so it's not hard wrapped
      mu4e-get-mail-command "mbsync -a"
      mu4e-maildir "~/mail/proton")

(setq mu4e-drafts-folder "/proton/Drafts"
      mu4e-sent-folder   "/proton/Sent"
      mu4e-refile-folder "/proton/All Mail"
      mu4e-trash-folder  "/proton/Trash")

(setq mu4e-maildir-shortcuts
      '(("/proton/inbox"     . ?i)
    ("/proton/Sent"      . ?s)
    ("/proton/Trash"     . ?t)
    ("/proton/Drafts"    . ?d)
    ("/proton/All Mail"  . ?a)))

Configurazione SMTP§

Il supporto SMTP è integrato nativamente in Emacs con smtpmail. Non c'è bisogno di installare nulla qui. Il server SMTP potrebbe interferire con altri server locali? Esempio quello di Zola?

(setq message-send-mail-function 'smtpmail-send-it
      auth-sources '("~/.authinfo") ;need to use gpg version but only local smtp stored for now
      smtpmail-smtp-server "127.0.0.1"
      smtpmail-smtp-service 1025
      smtpmail-stream-type  'ssl)

Componi le email con org-mode§

Installiamo org-msg per scrivere le mail in org mode ed esportarle in HTML.

OrgMsg is a GNU Emacs global minor mode mixing up Org mode and your Mail User Agent Mode (Message mode, mu4e mode, or notmuch mode) to compose and reply to emails in a Outlook HTML friendly style.

Senza questa accortezza, invieremmo delle mail in puro testo, che sarebbe una cosa pure profondamente amabile, ma qualche tempo fa ho constatato che molti client email tendono ad inserire tra lo spam qualunque cosa non sia formattata in HTML. Lo so, questa idea malsana di introdurre la formattazione HTML per le mail ha rovinato le mail stesse, ma ormai è troppo tardi per opporsi.

(package! org-msg)

Concludiamo con la configurazione minima di org-msg.

(setq mail-user-agent 'mu4e-user-agent)
(require 'org-msg)

(setq org-msg-options "html-postamble:nil H:5 num:nil ^:{} toc:nil author:nil email:nil \\n:t"
      org-msg-startup "hidestars indent inlineimages"
      org-msg-default-alternatives '((new . (text html))
                                     (reply-to-html . (text html))
                                     (reply-to-text . (text)))
      org-msg-convert-citation t)

(org-msg-mode)

Daemon§

Si tratta di una possibilità introdotta con Emacs 23.1 per ridurre i (già bassi) tempi di avvio di ogni finestra. Ottimo se, come me, utilizzate Emacs anche per modificare piccoli file di testo per cui andrebbe benissimo vim o nano.

Per lanciare il daemon da terminale, basta scrivere:

emacs --daemon

Facile, no? Per lanciarlo all'avvio, si può aggiungere il comando qui sopra nella sezione opportuna fornita dal DE o, meglio ancora, perdere mezzo minuto per impostare systemd (utile soprattutto per chi usa un tiling manager anziché un DE "fatto e finito").

[Unit]
Description=Emacs text editor
Documentation=info:emacs man:emacs(1) https://gnu.org/software/emacs/

[Service]
Type=forking
ExecStart=/usr/bin/emacs --daemon
ExecStop=/usr/bin/emacsclient --eval "(kill-emacs)"
Environment=SSH_AUTH_SOCK=%t/keyring/ssh
Restart=on-failure

[Install]
WantedBy=default.target

Per abilitare, lanciare due comandi:

systemctl enable --user emacs
systemctl start --user emacs

Ovviamente non mi sono inventato nulla, sto solo riprendendo la documentazione. L'approccio qui sopra non funziona se usate CentOS o, chiaramente, se non usate systemd. Ma, solitamente, chi non usa systemd non ha bisogno che glielo dica io, perché se l'è andata a cercare.

Fatto ciò, non è sufficiente avviare Emacs con il consueto comando emacs, perché quello continuerebbe ad avviare un'istanza per ogni finestra. È necessario specificare che vogliamo solo lanciare un client.

Al posto di emacs, scriveremo:

emacsclient --create-frame --alternate-editor=""

Chiaramente, scrivere di volta in volta questo comando è a dir poco noioso, quindi ci conviene aggiungere degli alias su .bashrc o lanciarlo con una scorciatoia da tastiera, a seconda del nostro ambiente.

Intendo pubblicare a breve i miei bash dots, stay tuned.

In conclusione§

Questo file è in continua trasformazione.

TODOs:

  • Riportare sotto org tutte le funzioni relative (per ora mantenuto quanto più vicino possibile all'originale per evitare casini)
  • Scrivi una conclusione decente
  • Tradurre l'intero post in inglese ed esportare la traduzione
1

da init file di Doom Emacs 2: anche se, bisogna dirlo, se pure fosse un semplice linguaggio di markup ci sarebbe da tenerne in conto, vista la piacevole sintassi