catarinacps / .emacs.d

My Emacs configuration!

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

My Emacs configuration file

These configurations represent my preferred version of Emacs, one that tries to be as minimalist as I want possible. Beware that this configuration uses a cutting-edge version of Emacs, so YMMV.

emacs-version

Cool Emacs configs from cool people:

Table of contents

Introduction

First of all, welcome to my configuration file for Emacs. I built it from almost the ground up, picking up configs from several sources, some of which I’ve cited in the beginning of this file.

As I’d like that this file be used as a source of inspiration for others, I wrote it in an .org file, using all of org-mode’s black magic powers of tangling source blocks to intertwine both source .el and prose.

Also, I’ve used in almost all sections of this document a package called use-package in order to organize all the additional packages that I use to get a better Emacs experience. So, I’ll teach you to read a use-package statement! That way you can understand what’s happening beneath all sugar syntax.

What packages you can find here

You can find the following packages in this configuration file:

- ace-window
- aggressive-indent
- ansi-color
- anzu
- auctex
- auctex-latexmk
- autoinsert
- auto-virtualenv
- avy
- bash-completion
- beacon
- bison
- cape
- cargo
- cc-mode
- cider
- clang-format
- clj-refactor
- clojure-mode
- clojure-mode-extra-font-locking
- cmake-font-lock
- cmake-mode
- comint
- compile
- conf-mode
- consult
- corfu
- corfu-doc
- cperl-mode
- crux
- cuda-mode
- dashboard
- deadgrep
- delight
- diff-hl
- dired
- dockerfile-mode
- eglot
- elec-pair
- electric
- elisp-mode
- elisp-slime-nav
- embark
- embark-consult
- ess
- ess-r-mode
- exec-path-from-shell
- expand-region
- files
- flymake
- flymake-diagnostic-at-point
- forge
- gcmh
- gdb-mi
- general
- ggo-mode
- git-modes
- git-timemachine
- gmpl-mode
- go-mode
- graphviz-dot-mode
- gruvbox-theme
- gud
- hcl-mode
- helpful
- hide-mode-line
- highlight-doxygen
- highlight-escape-sequences
- highlight-indent-guides
- highlight-numbers
- hl-todo
- htmlize
- hydra
- ibuffer
- inf-clojure
- info-colors
- js
- julia-mode
- jupyter
- ligature
- link-hint
- lisp-extra-font-lock
- lisp-mode
- lispy
- lua-mode
- magit
- make-mode
- marginalia
- markdown-mode
- meson-mode
- midnight
- mixed-pitch
- mode-local
- modern-cpp-font-lock
- no-littering
- notmuch
- ob
- ob-R
- openwith
- orderless
- org
- org-agenda
- org-appear
- org-attach
- org-bars
- org-capture
- org-contrib
- org-id
- org-inline-pdf
- org-journal
- org-ref
- org-refile
- ox
- ox-beamer
- ox-dnd
- ox-extra
- ox-hugo
- ox-latex
- ox-twbs
- page-break-lines
- paren
- plantuml-mode
- preproc-font-lock
- prog-mode
- project
- puni
- pyenv
- python
- racket-mode
- rainbow-delimiters
- recentf
- reftex
- rust-mode
- sendmail
- sh-script
- smart-mode-line
- smartparens
- smerge-mode
- ssh
- subword
- super-save
- sxhkd-mode
- tempel
- terraform-mode
- tex
- text-mode
- toc-org
- tramp
- treemacs
- tree-sitter
- tree-sitter-langs
- typescript-mode
- undo-tree
- uniquify
- use-package
- vertico
- vertico-directory
- view
- vimish-fold
- vimrc-mode
- visual-fill-column
- websocket
- which-key
- whitespace
- windmove
- writeroom-mode
- wucuo
- xref
- yaml-mode
- yasnippet
- zmq

use-package

Briefly, this package wraps your configuration for a given package in a neat little statement, which can include several useful categorizations and sub-tools.

Here are all little keywords you can use to organize your configs:

:after

The :after keyword sets a relation of dependency between the loading of two packages. In other words, you can tell use-package that a given package should only be loaded if that other package is already loaded.

(use-package foo)

(use-package bar
  :after foo)

(use-package moo
  :after (foo bar))    ; Supports mmultiple dependencies!

:defer

The :defer keyword tells use-package that it can defer the loading of your package until its absolutely needed. Its behaviour is the opposite of the keyword :demand.

(use-package foo
  :defer t)

:demand

The :demand keyword says to use-package that this package must not be lazy-loaded, and should be loaded right away as Emacs loads.

(use-package foo
  :demand)

:init

The :init keyword can tell use-package to execute said commands BEFORE the package is loaded. In reality, said execution will happen as soon as the use-package statement is processed on the Emacs loading process.

(use-package foo
  :init
  (setq bar t))

:config

The :config keyword, much like the :init keyword, tells use-package to execute commands. The difference is that commands defined with this keyword will only execute AFTER the package is loaded. There is an important difference here, as use-package uses what’s called lazy loading, i.e. only load the package when you actually need it.

(use-package foo
  :config
  (foo-init))

Personal

Stuff that isn’t either a package nor a language nor downloadable: stuff you coded yourself.

To-do:

  • [X] Increase/decrease font size
  • [ ] Input date on command (and as a new heading in org-mode)

Information

Some basic info about me.

(setq user-full-name "Henrique Silva"
      user-mail-address "hcpsilva@inf.ufrgs.br")

Functions and Macros

Some very useful functions I got from other people or that I coded myself.

Fetching text

To get the current selected text without newlines.

(defun hcps/get-selected-text (start end)
  (interactive "r")
  (when (use-region-p)
    (kill-new
     (replace-regexp-in-string
      "\n" " "
      (buffer-substring start end)))))

Date

Insert the current date.

(defun hcps/date-iso ()
  "Insert the current date, ISO format, eg. 2016-12-09."
  (interactive)
  (insert (format-time-string "%F")))

(defun hcps/date-iso-with-time ()
  "Insert the current date, ISO format with time, eg. 2016-12-09T14:34:54+0100."
  (interactive)
  (insert (format-time-string "%FT%T%z")))

(defun hcps/date-long ()
  "Insert the current date, long format, eg. December 09, 2016."
  (interactive)
  (insert (format-time-string "%B %d, %Y")))

(defun hcps/date-long-with-time ()
  "Insert the current date, long format, eg. December 09, 2016 - 14:34."
  (interactive)
  (insert (capitalize (format-time-string "%B %d, %Y - %H:%M"))))

(defun hcps/date-short ()
  "Insert the current date, short format, eg. 2016.12.09."
  (interactive)
  (insert (format-time-string "%Y.%m.%d")))

(defun hcps/date-short-with-time ()
  "Insert the current date, short format with time, eg. 2016.12.09 14:34"
  (interactive)
  (insert (format-time-string "%Y.%m.%d %H:%M")))

One-time advice

‘Cause that is kinda cool to have. Got it from this place.

(defun advise-once (symbol where function &optional props)
  (advice-add symbol :after `(lambda (&rest _) (advice-remove ',symbol #',function)))
  (advice-add symbol where function props))

Automatic byte-compile

To use with this configuration file.

(defconst config-file-name (expand-file-name "config.org" user-emacs-directory)
  "The path to the configuration")

(defun hcps/async-byte-compile-org-config ()
  "To add as a hook when saving the config file."
  (when (yes-or-no-p "Recompile config?")
    (let ((default-directory user-emacs-directory)
          (compile-script (concat "compile-" (file-name-base config-file-name) ".el")))
      (start-process
       "Emacs : Config compilation" (concat "*" (file-name-sans-extension compile-script) "*")
       "emacs" "--batch" "-l" compile-script))))

Auto-removing hook

Sometimes it’s cool to have a single-use hook.

(eval-and-compile
  (defmacro hcps/hook-require-once (hook package)
    "Add a hook to `pre-command-hook' which requires the given package once."
    (let ((func (intern (concat "hcps/" (symbol-name hook) "-require-" (symbol-name package)))))
      `(progn
         (defun ,func ()
           (remove-hook ',hook #',func)
           (require ',package))
         (add-hook ',hook #',func)))))

Do-list with a macro

Probably the dumbest way to do this

(defmacro hcps/macro-dolist (macro list-name)
  "Kinda like an macro map, but more specific."
  (let ((list (symbol-value list-name)))
    (macroexp-progn
     (mapcar (lambda (item) `(,macro ,item)) list))))

Trim functions

Directly from Magnar Sveen’s s.el

(defun hcps/s-trim-left (s)
  "Remove whitespace at the beginning of S."
  (declare (pure t) (side-effect-free t))
  (if (string-match "\\`[ \t\n\r]+" s)
      (replace-match "" t t s)
    s))

(defun hcps/s-trim-right (s)
  "Remove whitespace at the end of S."
  (declare (pure t) (side-effect-free t))
  (if (string-match "[ \t\n\r]+\\'" s)
      (replace-match "" t t s)
    s))

(defun hcps/s-trim (s)
  "Remove whitespace at the beginning and end of S."
  (declare (pure t) (side-effect-free t))
  (s-trim-left (s-trim-right s)))

Fontification of sub-blocks

Inside other languages or strings, like in shell-scripts and such.

  • [ ] org-src-font-lock-fontify-block
    • org-fontify-meta-lines-and-blocks
(defun hcps/externally-fontify-sub-block (lang start end)
  "Shamelessly stolen from `org-mode' implementation (sort-of).
Many languages include code sections in a different language.
This way we don't need to reimplement the font-lock rules and we
still get the pretty colors."
  (when (fboundp lang)
    (let ((string (buffer-substring-no-properties start end))
          (modified (buffer-modified-p))
          (this-buffer (current-buffer)))
      (remove-text-properties start end '(face nil))
      (with-current-buffer
          (get-buffer-create (format " *block-fontification:%s*" (symbol-name lang)))
        (let ((inhibit-modification-hooks nil))
          (erase-buffer)
          ;; Add string and a final space to ensure property change.
          (insert string " "))
        (unless (eq major-mode lang) (funcall lang))
        (font-lock-ensure)
        (let ((pos (point-min))
              next)
          (while (setq next (next-property-change pos))
            ;; Handle additional properties from font-lock, so as to
            ;; preserve, e.g., composition.
            (dolist (prop (cons 'face font-lock-extra-managed-props))
              (let ((new-prop (get-text-property pos prop)))
                (put-text-property
                 (+ start (1- pos)) (1- (+ start next)) prop new-prop
                 this-buffer)))
            (setq pos next))))
      (add-text-properties
       start end
       '(font-lock-fontified t fontified t font-lock-multiline t))
      (set-buffer-modified-p modified))))

(defun hcps/fontify-region-as-lang (lang rx-start rx-end)
  (lambda (limit)
    (let ((case-fold-search t))
      (when (re-search-forward rx-start limit t)
        (let ((block-start (match-end 0))
              (block-end nil))
          (when (re-search-forward rx-end nil t)
            (setq block-end (match-beginning 0))
            (hcps/externally-fontify-sub-block lang block-start block-end)))))))

Modeline

A clear modeline is prettier sometimes

(defun hcps/clean-mode-line ()
  "Clean mode-line format."
  (setq-local mode-line-format ""))

also goddamnit can we please not have variable pitch?

(custom-set-faces '(mode-line-active ((t (:inherit mode-line)))))

Move lines

Using the transpose-lines function.

(defmacro ew/save-column (&rest body)
  `(let ((column (current-column)))
     (unwind-protect
     (progn ,@body)
       (move-to-column column))))

(defun hcps/move-line-up ()
  "Move up the current line."
  (interactive)
  (ew/save-column
   (transpose-lines 1)
   (forward-line -2)))

(defun hcps/move-line-down ()
  "Move down the current line."
  (interactive)
  (ew/save-column
   (forward-line 1)
   (transpose-lines 1)
   (forward-line -1)))

Fixes

Stuff changed in trunk and I’m way too eager to return to stable.

(defun define-obsolete-fix (func obsolete current &optional when &rest args)
  (apply func obsolete current (or when "now") args))

(advice-add #'define-obsolete-function-alias :around #'define-obsolete-fix)
(advice-add #'define-obsolete-variable-alias :around #'define-obsolete-fix)

(defun disable-scroll-margin (fun &rest args)
  "Disable margin from active line in modes where it is detrimental."
  (let ((temp-scroll-margin scroll-margin))
    (setq-local scroll-margin 0)
    (apply fun args)
    (setq-local scroll-margin temp-scroll-margin)))

(defun turn-off-cursor (&rest _)
  "It is kinda unnecessary while inside some modes."
  (internal-show-cursor nil nil))

Definitions and preferences

Defaults that are better if defined other way.

Paths and defconst

Silly names for easier path usage.

(eval-and-compile
  (defconst current-user (getenv "USER") "The current user.")
  (defconst home-dir (getenv "HOME") "The user home dir.")

  (defconst lisp-user-dir (expand-file-name "lisp" user-emacs-directory) "The extra emacs-lisp directory.")
  (defconst var-user-dir (expand-file-name "var" user-emacs-directory) "The temporaries directory.")
  (defconst straight-user-dir (expand-file-name "straight/repos") "The default straight repos directory.")
  (defconst vendor-user-dir (expand-file-name "vendor" lisp-user-dir) "The externally .el directory.")
  (defconst documents-user-dir (expand-file-name "Documents" home-dir) "The (usually) default documents directory.")
  (defconst proj-user-dir (expand-file-name "Repositories" home-dir) "Default projects directory.")
  (defconst onedrive-user-dir (expand-file-name "OneDrive" home-dir) "Default OneDrive path."))

GUI elements

Almost every GUI element of Emacs is useless and a waste of screen space. Most of those are turned off in my early-init.el config.

And then there’s the title question. I for one like Emacs capitalized, so…

(setq-default frame-title-format
          '((capitalize invocation-name)
        (:eval (if (buffer-file-name)
               (abbreviate-file-name (buffer-file-name))
             "%b"))))

Text

Here’s every other setting relating to text editing I can’t categorize any further.

(setq-default fill-column 80
              ;; posssible values: (left right center full nil)
              default-justification 'left
              indent-tabs-mode nil
              tab-always-indent 'complete
              tab-first-completion nil
              bidi-paragraph-direction 'left-to-right
              sentence-end-double-space nil
              tab-width 4
              truncate-lines t
              truncate-partial-width-windows nil
              require-final-newline t
              x-stretch-cursor t
              cursor-in-non-selected-windows nil)

Mode line

Here’s everything related to the mode-line.

(setq-default display-time-format "%H:%M "
              display-time-default-load-average nil)

;; (add-to-list 'mode-line-misc-info '("@" system-name) t)

(display-time-mode 1)
(line-number-mode 1)
(column-number-mode 1)
(size-indication-mode 1)

Line numbering and scrolling

I like the vim style of relative numbering of lines. Never mind, I grew tired of it.

(setq-default display-line-numbers-type t
              display-line-numbers-width-start t)

;; I used to do this globally, but now let's only do selectively
;; (add-hook 'prog-mode-hook #'display-line-numbers-mode)

And I also like the vim style of scrolling better.

(setq-default auto-window-vscroll t
              ;; line-move-visual nil
              scroll-conservatively 101
              scroll-margin 10)

Small fix for scroll-margin

(defun get-lines-from-top ()
  (save-excursion
    (beginning-of-line)
    (count-screen-lines (point) (window-start))))

(defun scroll-margin-fix (func &rest args)
  (apply func args)
  (if (> scroll-margin 0)
      (let ((diff (- (min scroll-margin (floor (* maximum-scroll-margin (window-screen-lines))))
                     (get-lines-from-top))))
        (when (> diff 0)
          (scroll-down 1)))))

(advice-add #'previous-line :around #'scroll-margin-fix)

;; (add-hook 'prog-mode-hook #'visual-line-mode)

Highlighting the current line is also very useful.

(global-hl-line-mode 1)

and let’s enable pixel-scroll-precision-mode

(pixel-scroll-precision-mode 1)

Randoms

Random configs and definitions that don’t have a clear category.

(setq ad-redefinition-action 'accept   ; Silence warnings for redefinition
      confirm-kill-emacs #'yes-or-no-p ; Confirm before exiting Emacs
      select-enable-clipboard t        ; Merge system's and Emacs' clipboard
      blink-matching-paren nil         ; Disable annoying blink-matching-paren
      window-combination-resize t      ; Resize windows proportionally
      use-dialog-box nil               ; dont use graphical dialog boxes
      resize-mini-windows t
      read-process-output-max (* 1024 1024)
      ring-bell-function 'ignore)      ; No bell ring

(add-hook 'after-save-hook
          #'executable-make-buffer-file-executable-if-script-p)

;; (setq initial-major-mode 'text-mode)
;; (setq initial-scratch-message "\
;; This buffer is for notes you don't want to save.
;; If you want to create a file, visit that file with \\[find-file],
;; then enter the text in that file's own buffer.")

;; Replace yes/no prompts with y/n
(fset #'yes-or-no-p #'y-or-n-p)

;; Set Emacs to call the garbage collector on focus-out
;; (add-hook 'focus-out-hook #'garbage-collect)

;; use GPG-agent instead of the default
(setenv "SSH_AUTH_SOCK"
    (expand-file-name "gnupg/S.gpg-agent.ssh" (getenv "XDG_RUNTIME_DIR")))
(setq epg-pinentry-mode 'loopback)

(global-auto-revert-mode t)

;; (setq hippie-expand-try-functions-list '(try-expand-dabbrev
;;                                          try-expand-dabbrev-all-buffers
;;                                          try-expand-dabbrev-from-kill
;;                                          try-complete-file-name-partially
;;                                          try-complete-file-name
;;                                          try-expand-all-abbrevs
;;                                          try-expand-list
;;                                          try-expand-line
;;                                          try-complete-lisp-symbol-partially
;;                                          try-complete-lisp-symbol))

;; (require 'ediff)
;; (setq ediff-window-setup-function 'ediff-setup-windows-plain)

;; (require 'eshell)
;; (setq eshell-directory-name (expand-file-name "eshell" var-user-dir))

;; (global-diff-hl-mode 1)
;; (add-hook 'dired-mode-hook 'diff-hl-dired-mode)

;; ;; use hippie-expand instead of dabbrev
;; (global-set-key (kbd "M-/") 'hippie-expand)

Custom variables

Finally, let’s load our custom variables

(setq custom-file (expand-file-name "custom.el" var-user-dir))

(when (file-exists-p custom-file)
  (load-file custom-file))

Package configuration

Everything that isn’t an specific file-mode .el.

Setting-up

Some setting up before we start configuring the packages themselves.

(eval-and-compile
  (setq straight-check-for-modifications '(check-on-save find-when-checking))

  (defvar bootstrap-version)
  (let ((bootstrap-file (expand-file-name "straight/repos/straight.el/bootstrap.el" user-emacs-directory))
        (bootstrap-version 5))
    (unless (file-exists-p bootstrap-file)
      (with-current-buffer
          (url-retrieve-synchronously
           "https://raw.githubusercontent.com/raxod502/straight.el/develop/install.el"
           'silent 'inhibit-cookies)
        (goto-char (point-max))
        (eval-print-last-sexp)))
    (load bootstrap-file nil 'nomessage))

  (setq package-user-dir (expand-file-name "straight" user-emacs-directory))

  (unless (file-directory-p package-user-dir)
    (make-directory package-user-dir t)))

I use use-package to load my packages and to organize them neatly in this org file.

(eval-when-compile
  (straight-use-package 'use-package)

  (setq use-package-verbose t
        use-package-always-defer t
        use-package-hook-name-suffix nil
        straight-use-package-by-default t
        byte-compile-warnings '(not free-vars unresolved noruntime lexical make-local)))

;; general requires this bit otherwise everything blows up when native
;; compiling
(eval-and-compile
  (straight-use-package 'general)
  (require 'general))

also lets add a (require 'cl-lib) for good measure

(eval-when-compile
  (require 'cl-lib))

Support

All these packages just help on the configuration of the rest of the other packages.

delight

And we’ll use delight to hide minor-modes names and such.

(use-package delight
  :demand t
  :commands delight
  :delight
  (auto-fill-function " af")
  (eldoc-mode " ed")
  (editorconfig-mode)
  (visual-line-mode " vl")
  (abbrev-mode))

gcmh

Automatic hacks to the garbage collector settings

(use-package gcmh
  :demand t
  :straight (:type built-in)
  :load-path (lambda () (expand-file-name "gcmh" vendor-user-dir))
  :delight (gcmh-mode)
  :config
  (gcmh-mode 1))

no-littering

no-littering will help us by setting sane paths to all cache and history files the packages might set.

(use-package no-littering
  :demand t
  :commands (no-littering-expand-var-file-name no-littering-expand-etc-file-name)
  :config
  (require 'no-littering)
  (setq custom-file (no-littering-expand-var-file-name "custom.el")))

general

To facilitate my keybinding issues, I also use general.el. It adds some very welcome keywords to use-package, in which I’ll use extensively throughout this file.

(use-package general
  :demand t
  :commands (general-define-key general-def)
  :preface
  (defconst hcps/leader-key "C-c"
    "Leader key for some personal commands.")
  (defvar hcps/leader-map (make-sparse-keymap)
    "Keymap for all my leader bindings.")
  :init
  (general-def
    :keymaps 'override
    hcps/leader-key '(:keymap hcps/leader-map :package general)
    ;; "C-c x" #'hcps/date-iso
    "<f9>" #'hcps/get-selected-text
    "M--" #'text-scale-decrease
    "M-+" #'text-scale-increase
    "M-K" #'hcps/move-line-up
    "M-J" #'hcps/move-line-down
    "<f12>" #'menu-bar-mode)
  :config
  ;; leader-map keybindings
  (general-def 'hcps/leader-map
    "\\" #'indent-region
    "e a" #'align-current
    "e e" #'eval-region
    ;; cute names for the prefixes (some will only be defined further
    ;; along)
    "g" '(:ignore t :wk "magit")
    "f" '(:ignore t :wk "file")
    "w" '(:ignore t :wk "window")
    "n" '(:ignore t :wk "navigate")
    "o" '(:ignore t :wk "org")
    "m" '(:ignore t :wk "mode")
    "v" '(:ignore t :wk "view")
    "e" '(:ignore t :wk "edit")
    "p" '(:ignore t :wk "project")
    "l" '(:ignore t :wk "mail")
    "m e" '(:ignore t :wk "eglot")))

hide-mode-line

Made by the doom-emacs guy. Yeah I know I could just write a function for this, but eh.

(use-package hide-mode-line
  :commands hide-mode-line-mode)

mode-local

Pretty little package that hides unnecessary hooks to set local variables

(use-package mode-local
  :demand t
  :straight (:type built-in))

crux

Which stands for…

A Collection of Ridiculously Useful eXtensions for Emacs.

… yeah.

(use-package crux
  :hook
  (find-file-hook . crux-reopen-as-root)
  :general
  (:keymaps 'hcps/leader-map
   ;; file stuff
   :prefix "f"
   "s" #'crux-sudo-edit
   "m" #'crux-rename-file-and-buffer ;; as in `move'
   "d" #'crux-delete-file-and-buffer
   "c" #'crux-find-user-custom-file
   "n" #'crux-create-scratch-buffer
   "i" #'crux-find-user-init-file
   "o" #'crux-open-with)
  (:keymaps 'hcps/leader-map
   ;; edit stuff
   :prefix "e"
   "E" #'crux-eval-and-replace))

hydra

hydra is a package that allows keybindings to be activated under the pressing of a specific combination of keys. These will then be active as long as only them are being pressed, as on the moment a key which isn’t part of the hydra is pressed the hydra is killed and the keybindings deactivated.

(use-package hydra
  :commands defhydra
  :custom
  (hydra-default-hint nil))

Eyebrowse

(with-eval-after-load 'hydra
  (defhydra hydra-eyebrowse (:color blue)
    "
^Eyebrowse^         ^Do^                ^Switch^
^---------^---------^--^----------------^------^------------
_q_ quit            _c_ create          _<_ previous
^^                  _k_ kill            _>_ next
^^                  _r_ rename          _e_ last
^^                  ^^                  _s_ switch
^^                  ^^                  ^^
"
    ("q" nil)
    ("<" eyebrowse-prev-window-config :color red)
    (">" eyebrowse-next-window-config :color red)
    ("c" eyebrowse-create-window-config)
    ("e" eyebrowse-last-window-config)
    ("k" eyebrowse-close-window-config :color red)
    ("r" eyebrowse-rename-window-config)
    ("s" eyebrowse-switch-to-window-config))

  (with-eval-after-load 'general
    (general-def '(global-map special-mode-map)
      "C-c e" 'hydra-eyebrowse/body)))

Flycheck

(with-eval-after-load 'hydra
  (defhydra hydra-flycheck (:color pink)
    "
^
^Flycheck^          ^Errors^            ^Checker^
^────────^──────────^──────^────────────^───────^───────────
_q_ quit            _<_ previous        _?_ describe
_m_ manual          _>_ next            _d_ disable
_v_ verify setup    _f_ check           _s_ select
^^                  _l_ list            ^^
^^                  ^^                  ^^
"
    ("q" nil)
    ("<" flycheck-previous-error)
    (">" flycheck-next-error)
    ("?" flycheck-describe-checker :color blue)
    ("d" flycheck-disable-checker :color blue)
    ("f" flycheck-buffer)
    ("l" flycheck-list-errors :color blue)
    ("m" flycheck-manual :color blue)
    ("s" flycheck-select-checker :color blue)
    ("v" flycheck-verify-setup :color blue))

  (with-eval-after-load 'general
    (general-def '(global-map special-mode-map)
      "C-c f" 'hydra-flycheck/body)))

use-package

The one and only, for runtime use only!

(use-package use-package
  :commands (use-package-core use-package))

Built-in

The ones that really don’t require use-package :straight t.

  • [ ] bookmark
  • [ ] dired
  • [ ] hippie-expand
  • [ ] eshell
  • [ ] save-place
  • [X] ibuffer
  • [-] autoinsert
    • [ ] org
    • [X] shellscript
    • [ ] elisp
    • [X] c
    • [X] makefile
  • [X] electric-pairs
  • [X] project
  • [X] flymake
  • [X] xref

whitespace

Let’s monitor ourselves with whitespace.

(use-package whitespace
  :straight (:type built-in)
  :commands (whitespace-mode whitespace-cleanup delete-trailing-whitespace)
  :hook
  (before-save-hook . whitespace-cleanup)
  :custom
  (whitespace-line-column nil)
  (whitespace-style
   '(face tabs indentation trailing lines-tail space-after-tab space-before-tab)))

view

I didn’t know this existed before like 5 seconds ago.

(use-package view
  :demand t
  :straight (:type built-in)
  :custom
  (view-read-only t)
  :general
  (:keymaps 'view-mode-map
   "/" #'search-forward
   "?" #'search-backward
   "k" #'scroll-up
   "j" #'scroll-down)
  ("C-v" #'View-scroll-half-page-forward
   "M-v" #'View-scroll-half-page-backward))

compile

This compilation helper mode facilitates the navigation of error outputs on compilations.

(use-package compile
  :straight (:type built-in)
  :commands compile-mode
  :custom
  (compilation-ask-about-save nil)
  (compilation-always-kill t)
  (compilation-scroll-output 'first-error)
  (compilation-auto-jump-to-first-error t))

tramp

tramp is very useful when it comes to editing remote files and to editing as super-user.

(use-package tramp
  :straight (:type built-in)
  :custom
  (tramp-default-method "ssh")
  (tramp-terminal-type "xterm-mono"))

ansi-color

To have pretty colors on ansi output.

(use-package ansi-color
  :straight (:type built-in)
  :commands
  (ansi-color-for-comint-mode-on ansi-color-filter-apply ansi-color-process-output)
  :hook
  ((shell-mode-hook                   . ansi-color-for-comint-mode-on)
   (eshell-preoutput-filter-functions . ansi-color-filter-apply)
   (comint-output-filter-functions    . ansi-color-process-output)))

windmove

A package that creates commands to move around windows.

(use-package windmove
  :straight (:type built-in)
  :general
  (:keymaps 'override
   "C-M-h" #'windmove-left
   "C-M-l" #'windmove-right
   "C-M-k" #'windmove-up
   "C-M-j" #'windmove-down))

midnight

Originally, midnight is used to run something at midnight. I use its feature that kills old buffers.

(use-package midnight
  :disabled
  :defer 60
  :straight (:type built-in)
  :custom
  (clean-buffer-list-delay-general (/ 1 12))
  (clean-buffer-list-delay-special (* 1 3600))
  (clean-buffer-list-kill-buffer-names
   '("*Help*" "*Apropos*" "*Buffer List*" "*Compile-Log*" "*info*" "*vc*"
     "*vc-diff*" "*diff*" "*IBuffer*" "*Finder*")))

uniquify

uniquify creates automatic meaningful names for buffers with the same name:

(use-package uniquify
  :demand t
  :straight (:type built-in)
  :custom
  (uniquify-buffer-name-style 'post-forward)
  (uniquify-separator ":")
  (uniquify-after-kill-buffer-p t)
  (uniquify-ignore-buffers-re "^[*[:space:]]"))

recentf

Keep a list of recent files with recentf

(use-package recentf
  :straight (:type built-in)
  :commands recentf-open-files
  :hook
  (kill-emacs-hook . recentf-cleanup)
  :custom
  (recentf-save-file (expand-file-name "recentf-save.el" var-user-dir))
  (recentf-max-menu-items 0)
  (recentf-max-saved-items 300)
  (recentf-exclude
   (list
    'file-remote-p
    "\\.\\(?:gz\\|gif\\|svg\\|png\\|jpe?g\\)$"
    "^/tmp/"
    "^/ssh:"
    "\\.?ido\\.last$"
    "\\.revive$"
    "/TAGS$"
    var-user-dir
    package-user-dir
    no-littering-var-directory
    no-littering-etc-directory
    (expand-file-name "savefile" user-emacs-directory)))
  (recentf-auto-cleanup 'never)
  :config
  (recentf-mode 1))

ibuffer

Way better than the default one (and is built-in!)

(use-package ibuffer
  :straight (:type built-in)
  :general
  (:keymaps 'ibuffer-mode-map
   "q" #'kill-this-buffer)
  (:keymaps 'hcps/leader-map
   "B" #'ibuffer)
  ("C-x C-b" #'ibuffer))

autoinsert

To easily insert boilerplate text into files that need it, e.g. an org-mode beamer file, org-mode latex-file or a shell-script.

(use-package autoinsert
  :straight (:type built-in)
  :hook
  (find-file-hook . auto-insert)
  :custom
  (auto-insert t)
  (auto-insert-query nil)
  (auto-insert-directory (expand-file-name "templates/" user-emacs-directory))
  :config
  (auto-insert-mode 1))

comint

If this works, I’ll be very much pleasantly surprised.

(use-package comint
  :straight (:type built-in)
  :preface
  (defun comint-fix-window-size ()
    "Change process window size."
    (when (derived-mode-p 'comint-mode)
      (let ((process (get-buffer-process (current-buffer))))
        (when process
          (set-process-window-size process (window-height) 72)))))
  :hook
  ((comint-exec-hook . comint-fix-window-size)
   (comint-mode-hook . rainbow-delimiters-mode)))

paren

Minor mode to highlight matching parenthesis after point.

(use-package paren
  :demand t
  :straight (:type built-in)
  :commands show-paren-mode
  :custom
  (show-paren-delay 0)
  (show-paren-style 'parenthesis)
  :custom-face
  (show-paren-match ((t (:inherit hl-line :foreground unspecified :background "#504945" :extend nil)))))

elec-pair

For pretty much every programming language it’s interesting to have automatic pair close insert.

(use-package elec-pair
  :demand t
  :straight (:type built-in)
  :config
  (electric-pair-mode 1))

electric

Like the previous one but for indentation.

(use-package electric
  :demand t
  :straight (:type built-in)
  :custom
  (electric-indent-chars '(?\n ?}))
  :config
  (electric-indent-mode 1)
  (electric-layout-mode 1))

xref

(use-package xref
  :straight (:type built-in)
  :custom
  (xref-search-program 'ripgrep)
  (xref-show-xrefs-function #'consult-xref)
  :general
  (:keymaps 'hcps/leader-map
   :prefix "m"
   "d" #'xref-find-definitions
   "r" #'xref-find-references
   "a" #'xref-find-apropos))

gdb

Basic GUD configuration as setup to gdb-mi

(use-package gud
  :straight (:type built-in)
  :custom
  (gud-chdir-before-run nil))

An upgrade from GUD, has more shiny stuff

(use-package gdb-mi
  :straight (:type built-in)
  :commands gdb
  :custom
  (gdb-many-windows t))

project

Built-in replacement for projectile???

(use-package project
  :straight (:type built-in)
  :commands project-root
  :custom
  (project-vc-ignores '(".DS_Store"))
  :general
  (:keymaps 'hcps/leader-map
   "p" '(:keymap project-prefix-map)))

files

No better place to put these, honestly

(use-package files
  :demand t
  :straight (:type built-in)
  :hook
  ((focus-out-hook . do-auto-save)
   (mouse-leave-buffer-hook . do-auto-save))
  :custom
  (auto-save-timeout 5)
  (auto-save-file-name-transforms `((".*" ,(no-littering-expand-var-file-name "auto-save/") t))))

smerge-mode

For dealing with merges in VCSs

(use-package smerge-mode
  :straight (:type built-in)
  :delight
  (smerge-mode " sm")
  :init
  (with-eval-after-load 'hydra
    (defhydra hydra-smerge (:color pink
                            :pre (smerge-mode 1))
      "
^Movement^       ^Merge Action^          ^Other
^^^^^^------------------------------------------------
_n_: next hunk   _b_: keep base          _M_: makeup
_p_: prev hunk   _m_: keep mine          _r_: resolve
^ ^              _a_: keep all           _R_: refine
^ ^              _o_: keep other         _s_: swap
^ ^              _c_: keep current       _q_: quit
^ ^              _C_: combine with next
^ ^              _e_: ediff
"
      ("n" smerge-next)
      ("p" smerge-prev)
      ("a" smerge-keep-all)
      ("b" smerge-keep-base)
      ("m" smerge-keep-upper)
      ("o" smerge-keep-lower)
      ("c" smerge-keep-current)
      ("C" smerge-combine-with-next)
      ("e" smerge-ediff :color blue)
      ("M" smerge-makeup-conflict)
      ("r" smerge-resolve)
      ("R" smerge-refine)
      ("s" smerge-swap)
      ("q" nil :color blue)))
  :general
  (:keymaps 'hcps/leader-map
   :prefix "f e"
   nil '(:ignore t :wk "smerge")
   "h" #'hydra-smerge/body
   "n" #'smerge-next
   "p" #'smerge-prev
   "r" #'smerge-resolve
   "a" #'smerge-keep-all
   "b" #'smerge-keep-base
   "o" #'smerge-keep-lower           ; for the obsolete keep-other
   "l" #'smerge-keep-lower
   "m" #'smerge-keep-upper           ; for the obsolete keep-mine
   "u" #'smerge-keep-upper
   "E" #'smerge-ediff
   "C" #'smerge-combine-with-next
   "R" #'smerge-refine)
  :config
  (require 'hydra))

sendmail

Default package for sending email, originally uses the homonymous Perl script, now setup to use msmtp

(use-package sendmail
  :straight (:type built-in)
  :commands sendmail-send-it
  :custom
  (sendmail-program "/usr/bin/msmtp")
  (send-mail-function #'sendmail-send-it)
  (mail-specify-envelope-from t)
  (message-sendmail-envelope-from 'header)
  (mail-envelope-from 'header))

flymake

Built-in error checking and linting package.

(use-package flymake
  :straight (:type built-in)
  :commands (flymake-mode flymake-goto-next-error flymake-goto-prev-error)
  :delight
  (flymake-mode " fm" flymake)
  :general
  (:keymaps 'flymake-mode-map
   "M-n" #'flymake-goto-next-error
   "M-p" #'flymake-goto-prev-error))

Also lets add posframe support to it

(use-package flymake-diagnostic-at-point
  :after flymake
  :commands (flymake-diagnostic-at-point-mode)
  :straight
  (flymake-diagnostic-at-point
   :type git
   :host github
   :repo "waymondo/flymake-diagnostic-at-point")
  :hook
  (flymake-mode-hook . flymake-diagnostic-at-point-mode)
  :custom
  (flymake-diagnostic-at-point-display-diagnostic-function 'flymake-diagnostic-at-point-display-posframe)
  (flymake-diagnostic-at-point-error-prefix "* ")
  (flymake-diagnostic-at-point-timer-delay 1.5)
  :custom-face
  (flymake-diagnostic-at-point-posframe-background-face ((t (:inherit corfu-background :background unspecified))))
  (flymake-diagnostic-at-point-posframe-border-face ((t (:inherit corfu-border :background unspecified)))))

subword

Do things considering case in names

(use-package subword
  :straight (:type built-in)
  :commands (subword-mode global-subword-mode))

dired

Some basic configuration for the Emacs file manager

(use-package dired
  :demand t
  :straight (:type built-in)
  :custom
  (dired-dwim-target t)
  (dired-recursive-copies 'always))

Extensions

The ones from MELPA and ELPA and whatever.

  • [X] vterm

smart-mode-line

I use smart-mode-line as it is very minimalist and informative (and it looks very pretty on gruvbox).

(use-package smart-mode-line
  :disabled
  :demand t
  :init
  (setq sml/use-projectile-p nil
        sml/projectile-loaded-p nil
        sml/projectile-replacement-format "")
  :custom
  (sml/size-indication-format " %I ")
  (sml/line-number-format "%4l")
  (sml/shorten-directory nil)
  (sml/shorten-modes t)
  (sml/mode-width 'full)
  (sml/name-width 40)
  (sml/theme 'respectful)
  (sml/no-confirm-load-theme t)
  (sml/replacer-regexp-list
   `((,straight-user-dir ":STRAIGHT:")
     (,user-emacs-directory ":ED:")
     ("^/sudo:.*:" ":SU:")
     (,documents-user-dir ":DOC:")
     (,proj-user-dir ":VCS:")
     (,onedrive-user-dir ":OD:")))
  :config
  (sml/setup))

orderless

(use-package orderless
  :demand t
  :commands (orderless-filter orderless-highlight-matches)
  :init
  (setq-default completion-ignore-case t)
  (setq-default completion-category-defaults nil)
  :custom
  (completion-styles '(orderless))
  (completion-category-overrides '((eglot (styles . (orderless)))))
  (orderless-matching-styles '(orderless-initialism orderless-regexp orderless-prefixes))
  :custom-face
  (orderless-match-face-0 ((t (:weight bold :foreground "#d75f5f"))))
  (orderless-match-face-1 ((t (:weight bold :foreground "#ffaf00"))))
  (orderless-match-face-2 ((t (:weight bold :foreground "#87afaf"))))
  (orderless-match-face-3 ((t (:weight bold :foreground "#d787af"))))
  :config
  (savehist-mode 1))

cape

Complete at point function wrappers for stuff that doesn’t have them. Useful in many senses.

(use-package cape
  :demand t
  :config
  (add-to-list 'completion-at-point-functions #'cape-file)
  (add-to-list 'completion-at-point-functions #'cape-tex)
  (add-to-list 'completion-at-point-functions #'cape-dabbrev t)
  (add-to-list 'completion-at-point-functions #'cape-keyword))

vertico

Setting up vertico, which is a completing-read system 100% based on Emacs internals.

(use-package vertico
  :after orderless
  :demand t
  :straight
  (:files (:defaults "extensions/*")
   :includes (vertico-buffer
              vertico-directory
              vertico-flat
              vertico-indexed
              vertico-mouse
              vertico-quick
              vertico-repeat
              vertico-reverse))
  :custom
  (vertico-count 8)
  (read-file-name-completion-ignore-case t)
  (read-buffer-completion-ignore-case t)
  :custom-face
  (vertico-current ((t (:inherit hl-line :extend t))))
  :general
  (:keymaps 'vertico-map
   "M-k" #'vertico-previous
   "M-j" #'vertico-next
   "C-f" #'vertico-exit-input
   "C-u" #'vertico-scroll-down
   "C-d" #'vertico-scroll-up)
  :config
  (vertico-mode 1))

vertico-directory

Easier editing when dealing with filenames.

(use-package vertico-directory
  :after vertico
  :straight nil
  :hook
  (rfn-eshadow-update-overlay . vertico-directory-tidy)
  :general
  (:keymaps 'vertico-map
   "TAB" #'vertico-directory-enter
   "DEL" #'vertico-directory-delete-char
   "M-DEL" #'vertico-directory-delete-word))

corfu

corfu.el (Complete Overlay Region FUnction) is a pretty way to get in-buffer completion and narrowing within a popup. Issue is, it doesn’t play along well with LSP servers in general (at least with both lsp-mode and eglot). Really hope that eventually changes in the future, ‘cause I like Corfu more than I like company.

(use-package corfu
  :after orderless
  :demand t
  :commands (corfu-mode corfu-global-mode)
  :preface
  (defun corfu-enable-always-in-minibuffer ()
    "Enable Corfu in the minibuffer if Vertico/Mct are not active."
    (unless (or (bound-and-true-p mct--active)
                (bound-and-true-p vertico--input))
      (setq-local corfu-auto nil) ;; Enable/disable auto completion
      (corfu-mode 1)))
  :hook
  (minibuffer-setup-hook . corfu-enable-always-in-minibuffer)
  :custom
  (corfu-auto nil)
  (corfu-cycle t)
  (corfu-quit-at-boundary nil)
  (corfu-quit-no-match t)
  (corfu-max-width 60)
  (corfu-scroll-margin 5)
  (corfu-echo-documentation nil)
  :custom-face
  (corfu-current ((t (:inherit hl-line :extend t))))
  :general
  (:keymaps 'corfu-map
   "M-k" #'corfu-previous
   "M-j" #'corfu-next
   "SPC" #'corfu-insert-separator
   [remap newline] #'corfu-insert)
  :config
  (global-corfu-mode 1))

Let’s also add corfu-doc to display documentation in a meaningful way

(use-package corfu-doc
  :after corfu
  :straight
  (corfu-doc
   :type git
   :host github
   :repo "galeo/corfu-doc")
  :hook
  (corfu-mode-hook . corfu-doc-mode)
  :custom
  (corfu-doc-hide-threshold 1.0)
  (corfu-doc-max-height 15)
  (corfu-doc-delay 0.0)
  :general
  (:keymaps 'corfu-map
   "M-d" #'corfu-doc-toggle))

consult

Think of it as counsel but without needing ivy to work.

(use-package consult
  :commands consult-xref
  :custom
  (consult-narrow-key "<")
  (consult-project-root-function
   (lambda ()
     (when-let (project (project-current))
       (car (project-roots project)))))
  :general
  (:keymaps 'hcps/leader-map
   "f b" #'consult-bookmark
   "f r" #'consult-recent-file
   "e p" #'consult-yank-pop
   "n l" #'consult-line
   "n m" #'consult-mark
   "n o" #'consult-outline
   "n g" #'consult-ripgrep
   "n G" #'consult-git-grep
   "n e" #'consult-compile-error
   "n f" #'consult-flycheck
   "n j" #'consult-goto-line
   "m f" #'consult-flymake)
  ("C-x b" #'consult-buffer
   "C-h a" #'consult-apropos))

marginalia

Adds information on some selection functions such as find-file and others. Feels good to use Emacs built-in function in a prettier way.

(use-package marginalia
  :after vertico
  :demand t
  :custom
  (marginalia-annotators
   '(marginalia-annotators-heavy
     marginalia-annotators-light
     nil))
  :general
  (:keymaps 'minibuffer-local-map
   "M-A" #'marginalia-cycle)
  :config
  (marginalia-mode 1))

undo-tree

Undo and redo and kools with undo-tree!

(use-package undo-tree
  :delight
  :preface
  (defconst hcps/undo-tree-visualizer-diff t
    "My value for the `undo-tree-visualizer-diff' variable.")
  (defun reset-visualizer-diff (&rest _)
    "Because undo-tree-visualize sets the value of this variable to nil on quit."
    (setq undo-tree-visualizer-diff hcps/undo-tree-visualizer-diff))
  (defun wolfgang/clean-undo-tree ()
    "Clear current buffer's undo-tree."
    (interactive)
    (let ((buff (current-buffer)))
      (if (local-variable-p 'buffer-undo-tree)
          (if (y-or-n-p "Clear buffer-undo-tree? ")
              (progn
                (setq buffer-undo-tree nil)
                (message "Cleared undo-tree of buffer: %s" (buffer-name buff)))
            (message "Cancelled clearing undo-tree of buffer: %s" (buffer-name buff)))
        (error "Buffer %s has no local binding of `buffer-undo-tree'" (buffer-name buff)))))
  :hook
  ((after-init-hook . global-undo-tree-mode)
   (undo-tree-visualizer-mode-hook . hide-mode-line-mode))
  :init
  (advice-add #'undo-tree-visualize :before #'reset-visualizer-diff)
  :custom
  (undo-tree-visualizer-timestamps t)
  (undo-tree-enable-undo-in-region t)
  (undo-tree-auto-save-history nil)
  (undo-tree-history-directory-alist `((".*" . ,temporary-file-directory)))
  (undo-tree-visualizer-diff hcps/undo-tree-visualizer-diff)
  :general
  (:keymaps 'hcps/leader-map
   "u" #'undo-tree-visualize
   "U" #'wolfgang/clean-undo-tree))

dashboard

There’s some utility in having a cool initial screen actually. And there’s a cool extension that provides such functionality.

(use-package dashboard
  :functions dashboard-mode
  :commands (dashboard-mode dashboard-insert-startupify-lists dashboard-refresh-buffer)
  :init
  (defun hcps/open-dashboard ()
    (let ((buffer (switch-to-buffer "*dashboard*")))
      (dashboard-mode)
      buffer))
  (setq-default initial-buffer-choice #'hcps/open-dashboard)
  :custom
  (dashboard-banner-logo-title (format "Welcome to Emacs, %s!" current-user))
  (dashboard-set-heading-icons nil)
  (dashboard-set-file-icons nil)
  (dashboard-center-content t)
  (dashboard-page-separator "\n\n\n")
  (dashboard-startup-banner 'logo)
  (dashboard-items '((recents  . 10)
                     (bookmarks . 5)))
  :general
  (:keymaps 'dashboard-mode-map
   "n" #'widget-forward
   "p" #'widget-backward
   "m" #'dashboard-jump-to-bookmarks
   "r" #'dashboard-jump-to-recent-files)
  :config
  (setq-mode-local dashboard-mode scroll-margin 0)
  (dashboard-setup-startup-hook))

treemacs

While I’ve somewhat used neotree.el, I believe that treemacs is turning out to be a better option, as it offers a bunch of extra integrating packages and is overall more popular than the former.

(use-package treemacs
  :commands treemacs-mode
  :init
  (advice-add #'treemacs-mode :around #'disable-scroll-margin)
  :hook
  (treemacs-mode-hook . hide-mode-line-mode)
  :custom
  (treemacs-persist-file (expand-file-name "treemacs/persist.org" var-user-dir))
  (treemacs-display-in-side-window t)
  (treemacs-follow-after-init t)
  (treemacs-show-cursor nil)
  (treemacs-no-png-images t)
  (treemacs-project-follow-cleanup t)
  (treemacs-sorting 'alphabetic-desc)
  (treemacs-width 22)
  :general
  ("M-0" #'treemacs-select-window
   "M-t" #'treemacs)
  :config
  (treemacs-follow-mode 1)
  (treemacs-filewatch-mode 1)
  (treemacs-fringe-indicator-mode -1))

exec-path-from-shell

To ensure that Emacs uses the same path and environment as shell uses, I use exec-path-from-shell. That way commands that work on the shell will certainly work on Emacs!

(use-package exec-path-from-shell
  :straight
  (exec-path-from-shell
   :type git
   :host github
   :repo "purcell/exec-path-from-shell")
  :init
  (setenv "SHELL" "/bin/bash")
  (setq-default shell-file-name "/bin/bash")
  :custom
  (exec-path-from-shell-shell-name "/bin/bash")
  (exec-path-from-shell-arguments '("-l"))
  (exec-path-from-shell-variables '("PATH" "MANPATH"))
  :config
  (exec-path-from-shell-initialize))

anzu

Besides the ISearch from Emacs itself or the search function from evil, I also like to use anzu.

(use-package anzu
  :delight
  (isearch-mode)
  (anzu-mode)
  :preface
  (defun hcps/anzu-update-func (here total)
    (when anzu--state
      (let ((status (cl-case anzu--state
                      (search (format "(%d/%d) " here total))
                      (replace-query (format "(%d replaces) " total))
                      (replace (format "(%d/%d) " here total)))))
        (propertize status 'face 'anzu-mode-line))))
  :custom
  (anzu-cons-mode-line-p t)
  (anzu-mode-line-update-function #'hcps/anzu-update-func)
  :general
  (:keymaps 'hcps/leader-map
   :prefix "e"
   "r" #'anzu-query-replace-at-cursor-thing
   "q" #'anzu-query-replace-regexp)
  :config
  (global-anzu-mode 1))

I use only the anzu-replace-at-cursor-thing, which is a very useful to replace multiple occurrences of a word fast.

deadgrep

I enjoy using ripgrep to search for stuff using grep syntax without the slowness of it. So, I use deadgrep!

(use-package deadgrep
  :general
  (:keymaps 'hcps/leader-map
   :prefix "f"
   "g" #'deadgrep))

link-hint

link-hint replicates the hinting mechanic from trydactil and such.

(use-package link-hint
  :custom
  (browse-url-browser-function 'browse-url-firefox)
  :general
  (:keymaps 'hcps/leader-map
   "h" #'link-hint-open-link))

avy

As I love some overkill, here’s avy.

(use-package avy
  :custom
  (avy-styles-alist
   '((avy-goto-char-2 . post)
     (avy-goto-line   . at-full)))
  (avy-background t)
  :general
  ("M-g f" #'avy-goto-line))

which-key

The package called which-key shows you possible completions to the command you’re typing in the mode-line.

(use-package which-key
  :delight
  :init
  (hcps/hook-require-once pre-command-hook which-key)
  :custom
  (which-key-allow-evil-operators t)
  :config
  (which-key-mode 1))

eglot

Non-bloated lsp-mode alternative. Always strive for leaner, simpler alternatives (and try to contribute to them when possible).

(use-package eglot
  :commands eglot-ensure
  :hook
  (eglot-managed-mode-hook . turn-on-eldoc-mode)
  :init
  (setq-default eglot-workspace-configuration
                '((:diagnostics . ((:onChange . 5)))
                  (:completion . ((:filterAndSort . :json-false)))))
  :custom
  (eglot-autoreconnect t)
  (eglot-autoshutdown t)
  (eglot-extend-to-xref t)
  (eglot-connect-timeout 60)
  (eglot-send-changes-idle-time 0.10)
  :general
  (:keymaps 'hcps/leader-map
   :prefix "m e"
   "f" #'eglot-format
   "r" #'eglot-rename
   "a" #'eglot-code-actions
   "d" #'eglot-find-declaration
   "i" #'eglot-find-implementation
   "C-r" #'eglot-reconnect
   "C-s" #'eglot-shutdown
   "C-a" #'eglot-shutdown-all)
  :config
  (add-to-list 'eglot-server-programs
               '((perl-mode cperl-mode) . ("perl" "-MPerl::LanguageServer" "-e" "Perl::LanguageServer::run()")))
  (push :documentHighlightProvider eglot-ignored-server-capabilities)
  (require 'xref))

highlight-numbers

This highlights numbers in prog-mode:

(use-package highlight-numbers
  :commands highlight-numbers-mode)

highlight-escape-sequences

And this is to highlight escape sequences in some common modes:

(use-package highlight-escape-sequences
  :commands turn-on-hes-mode
  :preface
  (defconst hes-shell-escape-sequence-re "\\(\\\\\\([\"'?\\abfnrtv]\\)\\)"
    "Simple regex to match any common escaped character in sh-mode")
  :config
  (add-to-list 'hes-mode-alist `(ggo-mode . ,hes-shell-escape-sequence-re))
  (add-to-list 'hes-mode-alist `(shell-script-mode . ,hes-shell-escape-sequence-re)))

flyspell

Of course, flyspell corrects your writing!

(use-package wucuo
  :commands (wucuo-start)
  :delight
  (wucuo-mode " fs")
  (flyspell-mode " fs")
  (flyspell-prog-mode " fs")
  :custom
  (ispell-program-name "aspell")
  (ispell-extra-args '("--sug-mode=ultra" "--run-together" "--run-together-limit=16"))
  (flyspell-issue-message-flag nil)
  (flyspell-issue-welcome-flag nil)
  :general
  (:keymaps 'hcps/leader-map
   "e d" #'ispell-change-dictionary)
  :config
  (add-to-list 'ispell-skip-region-alist '("^#+begin_src" . "^#+end_src")))

diff-hl

diff-hl to highlight any diffs!

(use-package diff-hl
  :commands (diff-hl-mode turn-on-diff-hl-mode diff-hl-magit-post-refresh))

ace-window

ace-window creates labels so we can jump windows with precision:

(use-package ace-window
  :custom
  (aw-keys '(?a ?s ?d ?f ?g ?h ?j ?k ?l))
  :general
  (:keymaps 'hcps/leader-map
   "w o" #'ace-window))

super-save

super-save auto-saves buffers when you switch or close buffers or when Emacs loses focus, etc.

(use-package super-save
  :disabled
  :delight
  :init
  (hcps/hook-require-once before-save-hook super-save)
  :custom
  (super-save-auto-save-when-idle t)
  (super-save-remote-files nil)
  (super-save-idle-duration 60)
  :config
  (add-to-list 'super-save-triggers #'ace-window)
  (super-save-mode 1))

yasnippet

I use yasnippet to handle my snippet needs.

(use-package yasnippet
  :disabled
  :delight
  (yas-minor-mode " ys")
  :commands (yas-minor-mode yas-expand-snippet yas-lookup-snippet)
  :preface
  (defun hcps/get-pretty-source-path (path)
    (replace-regexp-in-string
     ".*\\(?:src\\|source\\|include\\|inc\\)/\\(.+\\)$" "\\1"
     path))
  (defun hcps/get-pretty-include-guard (path)
    (concat
     "_"
     (upcase (replace-regexp-in-string "[/.]" "_" (hcps/get-pretty-source-path path)))
     "_"))
  :init
  (add-to-list 'hippie-expand-try-functions-list #'yas-hippie-try-expand)
  :hook
  (html-mode-hook . yas-minor-mode)
  :custom
  (yas-snippet-dirs `(,(expand-file-name "snippets" user-emacs-directory)))
  :config
  (general-def 'insert 'yas-minor-mode-map
    "<tab>" yas-maybe-expand)
  (yas-reload-all)
  (yas-load-directory auto-insert-directory))

vimish-fold

Enables vim-like folding of regions.

(use-package vimish-fold
  :custom
  (vimish-fold-header-width 79)
  :general
  (:keymaps 'vimish-fold-folded-keymap
   "C-<tab>" #'vimish-fold-unfold)
  (:keymaps 'vimish-fold-unfolded-keymap
   "C-<tab>" #'vimish-fold-refold)
  :config
  (vimish-fold-global-mode 1))

magit

Obviously, any configuration file that says it deserves any respect should feature magit, as it is, hands down, the best git front-end in the visible universe, nay, in the whole multiverse.

(use-package magit
  :hook
  ((after-save-hook         . magit-after-save-refresh-status)
   (magit-file-mode-hook    . diff-hl-mode)
   (magit-post-refresh-hook . diff-hl-magit-post-refresh))
  :preface
  ;; easy on-off for the following function
  (defcustom magit-push-protected-branch nil
    "When set, ask for confirmation before pushing to this branch (e.g. master)."
    :type 'string
    :safe #'stringp
    :group 'magit)
  ;; are you sure you wanna push to master?
  (defun magit-push--protected-branch (magit-push-fun &rest args)
    "Ask for confirmation before pushing a protected branch."
    (if (equal magit-push-protected-branch (magit-get-current-branch))
        ;; Arglist is (BRANCH TARGET ARGS)
        (if (yes-or-no-p (format "Push branch %s? " (magit-get-current-branch)))
            (apply magit-push-fun args)
          (error "Push aborted by user"))
      (apply magit-push-fun args)))
  :init
  (advice-add #'magit-push-current-to-pushremote
              :around #'magit-push--protected-branch)
  (advice-add #'magit-push-current-to-upstream
              :around #'magit-push--protected-branch)
  :custom
  (git-commit-major-mode 'text-mode)
  (magit-push-protected-branch "master")
  (magit-save-repository-buffers 'dontask)
  (magit-refs-show-commit-count 'all)
  (magit-log-buffer-file-locked t)
  (magit-revision-show-gravatars nil)
  (magit-bury-buffer-function 'magit-mode-quit-window)
  :general
  (:keymaps 'hcps/leader-map
   :prefix "g"
   "p" #'magit-list-repositories
   "g" #'magit-status
   "d" #'magit-dispatch
   "f" #'magit-file-dispatch
   "l" #'magit-log
   "b" #'magit-blame)
  (:keymaps '(magit-log-mode-map magit-diff-mode-map magit-status-mode-map magit-mode-map magit-diff-section-base-map)
   "j" #'magit-next-line
   "k" #'magit-previous-line
   "C-j" #'magit-section-forward
   "C-k" #'magit-section-backward
   "M-j" #'magit-section-forward-sibling
   "M-k" #'magit-section-backward-sibling)
  (:keymaps 'magit-status-mode-map
   "h" #'magit-diff-toggle-refine-hunk
   "l" #'magit-log
   "J" #'magit-status-jump
   "K" #'magit-discard)
  :config
  (transient-replace-suffix 'magit-dispatch #'magit-discard '("K" "Discard" magit-discard)))

git-timemachine

Also, git-timemachine is a beautiful way to walk through git history:

(use-package git-timemachine
  :after magit
  :hook
  (git-timemachine-mode-hook . read-only-mode)
  :general
  (:keymaps 'git-timemachine-mode-map
   "q" #'git-timemachine-quit
   "w" #'git-timemachine-kill-abbreviated-revision
   "g" #'git-timemachine-show-nth-revision
   "c" #'git-timemachine-show-commit
   "C-j" #'git-timemachine-show-next-revision
   "C-k" #'git-timemachine-show-previous-revision)
  (:keymaps 'hcps/leader-map
   "g t" #'git-timemachine)
  :config
  (require 'magit))

expand-region

Increase region by semantic units. It tries to be smart about it and adapt to the structure of the current major mode.

(use-package expand-region
  :general
  ("C-+" #'er/contract-region
   "C-=" #'er/expand-region))

smartparens

When in need of smart pairing, look no further than smartparens!

(use-package smartparens
  :disabled
  :delight (smartparens-mode " sp")
  :commands (smartparens-mode smartparens-strict-mode)
  :hook
  (prog-mode-hook . smartparens-mode)
  :custom
  (sp-base-key-bindings 'paredit)
  (sp-autoskip-closing-pair 'always)
  (sp-hybrid-kill-entire-symbol nil)
  :config
  (require 'smartparens-config)
  (sp-use-paredit-bindings)
  (show-smartparens-global-mode 1))

rainbow-delimiters

With that, rainbow-delimiters is a great match:

(use-package rainbow-delimiters
  :commands rainbow-delimiters-mode)

beacon

This little add-on will highlight big cursor movements.

(use-package beacon
  :init
  (hcps/hook-require-once pre-command-hook beacon)
  :delight
  :config
  (beacon-mode 1))

aggressive-indent

I use aggressive-indent to keep my code indented as I type.

(use-package aggressive-indent
  :commands aggressive-indent-mode
  :custom
  (aggressive-indent-comments-too t)
  (aggressive-indent-sit-for-time 0.05)
  :config
  (add-to-list 'aggressive-indent-protected-commands 'undo-tree-visualize-undo)
  (add-to-list 'aggressive-indent-protected-commands 'undo-tree-visualize-redo)
  (add-to-list 'aggressive-indent-protected-commands 'comment-dwim))

highligh-indent-guides

Also highligh-indent-guides is very useful, as Emacs doesn’t come with it out of the box.

(use-package highlight-indent-guides
  :delight
  (highlight-indent-guides-mode)
  :commands
  (highlight-indent-guides-auto-set-faces highlight-indent-guides-mode)
  :preface
  (defun highlight-indent-guides-auto-set-faces-with-frame (frame)
    (with-selected-frame frame
      (highlight-indent-guides-auto-set-faces)))
  :hook
  (highlight-indent-guides-mode-hook . highlight-indent-guides-auto-set-faces)
  :custom
  (highlight-indent-guides-method 'character)
  (highlight-indent-guides-responsive 'stack)
  (highlight-indent-guides-character ?|)
  (highlight-indent-guides-delay 0.05)
  (highlight-indent-guides-auto-odd-face-perc 5)
  (highlight-indent-guides-auto-even-face-perc 5)
  (highlight-indent-guides-auto-character-face-perc 10))

helpful

helpful is a package that is overall an improvement over the default help windows.

(use-package helpful
  :general
  (:keymaps 'override
   :prefix "C-h"
   "F" #'helpful-function
   "C" #'helpful-command
   "M" #'helpful-macro)
  (:keymaps 'override
   [remap describe-key] #'helpful-key
   [remap describe-variable] #'helpful-variable
   [remap describe-function] #'helpful-callable))

openwith

openwith is a small and useful tool to set how you want to open your files with Emacs. I use it to set the opener of pdfs in my Emacs, as well to other diverse media files.

(use-package openwith
  :init
  (hcps/hook-require-once pre-command-hook openwith)
  :custom
  (openwith-associations
   '(("\\.pdf\\'" "xdg-open" (file))
     ;; ("\\.jpe?g\\'" "sxiv" (file))
     ;; ("\\.png\\'" "sxiv" (file))
     ;; ("\\.svg\\'" "sxiv" (file))
     ;; ("\\.jpeg\\'" "sxiv" (file))
     ;; ("\\.bmp\\'" "sxiv" (file))
     ("\\.flac\\'" "mpv" (file))
     ("\\.mkv\\'" "mpv" (file))
     ("\\.mp3\\'" "mpv" (file))
     ("\\.mp4\\'" "mpv" (file))))
  (openwith-confirm-invocation t)
  :config
  (openwith-mode 1))

page-break-lines

To make pretty page breaks in your Emacs buffers:

(use-package page-break-lines
  :commands (page-break-lines-mode)
  :delight
  :custom
  (page-break-lines-max-width (floor (/ fill-column 2)))
  (page-break-lines-char ?-)
  :custom-face
  (page-break-lines ((t :inherit font-lock-comment-face :bold nil :italic nil))))

writeroom-mode

A nice writing environment for Emacs in a minor-mode.

(use-package writeroom-mode
  :straight t
  :straight visual-fill-column
  :custom
  (writeroom-fullscreen-effect 'maximized)
  (writeroom-width (+ 3 fill-column))
  :general
  (:keymaps 'hcps/leader-map
   "v w" #'writeroom-mode))

ssh

Here’s a small package that allows remotely opening sessions.

(use-package ssh
  :after shell
  :preface
  (defcustom ssh-remote-user-server nil
    "Dummy variable that holds a server name."
    :type 'string
    :safe #'stringp
    :group 'ssh)
  (defun hcps/get-user-server ()
    "Call to set and print the user server."
    (interactive)
    (if (equal ssh-remote-user-server nil)
    (setq ssh-remote-user-server
          (read-from-minibuffer "What server to store: ")))
    (concat "/ssh:" ssh-remote-user-server ":"))
  (defun hcps/store-user-remote ()
    "Store a server name to the desired target."
    (interactive)
    (let* ((read-server (read-from-minibuffer
             (format "What server to store (current: %s): " ssh-remote-user-server)))
       (server-to-connect (if (equal read-server "") ssh-remote-user-server read-server)))
      (setq ssh-remote-user-server server-to-connect)))
  :custom
  (shell-command-dont-erase-buffer t)
  (ssh-directory-tracking-mode t)
  :config
  (shell-dirtrack-mode t))

ligature.el

Obscure but nice way to enable ligature fonts.

(use-package ligature
  :disabled
  :demand t
  :straight
  (ligature
   :type git
   :host github
   :repo "mickeynp/ligature.el")
  :config
  (ligature-set-ligatures 't '("www"))
  ;; enable Iosevka ligatures in programming modes
  (ligature-set-ligatures
   'prog-mode
   '("<---" "<--"  "<<-" "<-" "->" "-->" "--->" "<->" "<-->"
     "<--->" "<---->" "<!--" "<==" "<===" "<=" "=>" "=>>" "==>"
     "===>" ">=" "<=>" "<==>" "<===>" "<====>" "<!---" "<~~"
     "<~" "~>" "~~>" "::" ":::" "==" "!=" "===" "!==" ":=" ":-"
     ":+" "<*" "<*>" "*>" "<|" "<|>" "|>" "+:" "-:" "=:"
     "<******>" "++" "+++"))
  (global-ligature-mode 1))

mixed-pitch-mode

So we don’t trouble ourselves with setting which fonts should be fixed and which should be variable.

(use-package mixed-pitch
  :disabled
  :commands (mixed-pitch-mode)
  :delight
  (mixed-pitch-mode " mp")
  :custom-face
  (variable-pitch ((t (:font "Iosevka Aile" :weight light)))))

hl-todo

Pretty TODO highlighting :)

(use-package hl-todo
  :commands (hl-todo-mode))

emacs-tree-sitter

Trying out and hopefully will switch to in in a few languages.

(use-package tree-sitter
  :straight t
  :straight tree-sitter-langs
  :commands (tree-sitter-mode global-tree-sitter-mode)
  :delight (tree-sitter-mode " ts")
  :hook
  (tree-sitter-mode-hook . tree-sitter-hl-mode)
  :custom-face
  (tree-sitter-hl-face:function.call ((t (:foreground "#8ec07c"))))
  (tree-sitter-hl-face:method.call ((t (:foreground "#8ec07c"))))
  (tree-sitter-hl-face:label ((t (:inherit font-lock-builtin-face :slant italic))))
  :config
  (require 'tree-sitter-langs))

lispy

Supposedly this works better than smartparens when using Evil keybindings. Hopefully this is the case, ‘cause I don’t really use smartparens keybindings the way (nor the frequency) I should be.

(use-package lispy
  :commands (lispy-mode)
  :delight (lispy-mode " lp"))

embark

Finally, adding this amazing package

(use-package embark
  :general
  (:keymaps 'override
   "M-SPC" #'embark-act
   "M-S-SPC" #'embark-dwim))

embark-consult

To provide live preview of embark actions.

(use-package embark-consult
  :after (embark consult)
  :demand t
  :hook
  (embark-collect-mode-hook . consult-preview-at-point-mode))

notmuch

notmuch interface for Emacs!

(use-package notmuch
  :commands (notmuch-hello notmuch-show notmuch-tree notmuch-search)
  :custom
  (notmuch-search-oldest-first nil)
  (notmuch-saved-searches
   '((:name "inbox" :query "tag:inbox" :key "i")
     (:name "unread" :query "tag:unread" :key "u")
     (:name "graduacao" :query "tag:graduacao" :key "g")
     (:name "cadeiras" :query "tag:cadeira" :key "c")
     (:name "sent" :query "tag:sent" :key "t")
     (:name "all mail" :query "*" :key "a")))
  :general
  (:keymaps 'hcps/leader-map
   :prefix "l"
   "h" #'notmuch-hello
   "s" #'notmuch-search
   "t" #'notmuch-tree
   "w" #'notmuch-show
   "n" #'notmuch-poll))

tempel

A tiny package that modernizes the tempo built-in template package!

(use-package tempel
  :commands (tempel-expand tempel-complete tempel-insert)
  :preface
  (defconst hcps/tempel-snippets-dir (expand-file-name "snippets" user-emacs-directory))
  (defun tempel-setup-capf ()
    ;; Add the Tempel Capf to `completion-at-point-functions'. `tempel-expand'
    ;; only triggers on exact matches. Alternatively use `tempel-complete' if
    ;; you want to see all matches, but then Tempel will probably trigger too
    ;; often when you don't expect it.
    ;; NOTE: We add `tempel-expand' *before* the main programming mode Capf,
    ;; such that it will be tried first.
    (setq-local completion-at-point-functions
                (cons #'tempel-expand
                      completion-at-point-functions)))
  :custom
  (tempel-path (mapcar (lambda (f) (expand-file-name f hcps/tempel-snippets-dir))
                       '("prog-mode" "lisp-mode" "text-mode" "org-mode")))
  (tempel-trigger-prefix "<")
  :general
  (:keymaps 'tempel-map
   "M-n" #'tempel-next
   "M-p" #'tempel-previous
   [remap keyboard-quit] #'tempel-abort))

forge

Add commands to magit that interact with git forges!

(use-package forge
  :disabled
  :after magit)

puni

Soft parenthesis handling!

(use-package puni
  :demand
  :commands (puni-disable-puni-mode puni-mode)
  :hook
  (eval-expression-minibuffer-setup-hook . puni-mode))

info-colors

info-colors makes the info node buffers a little bit more readable.

(use-package info-colors
  :straight
  (info-colors
   :type git
   :host github
   :repo "ubolonton/info-colors")
  :hook
  (Info-selection-hook . info-colors-fontify-node))

Theme

Here I define the theme that I use, which is gruvbox, as it provides nice support for a lot of packages and is very pleasant for the eyes.

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

File modes

Here I’ll store any package load and configurations related to languages and file types.

I still need to add packages relating to these languages:

  • [ ] Scala
  • [X] Dot (using Graphviz)
  • [ ] English (as in literal english)
  • [ ] Coq (yes, I’m slowly turning into what I most hate (check the hrs config!))
  • [X] PKGBUILD
  • [X] Markdown
  • [X] Clojure
  • [X] prog-mode
  • [X] text-mode
  • [X] bison-mode
  • [X] Typescript
  • [ ] Scheme and Geiser

prog-mode

This mode gets derived by all programming modes.

(use-package prog-mode
  :straight (:type built-in)
  :preface
  (defun setup-hyphen-word-component ()
    (modify-category-entry ?- ?u))
  :hook
  ((prog-mode-hook . rainbow-delimiters-mode)
   (prog-mode-hook . subword-mode)
   (prog-mode-hook . eldoc-mode)
   (prog-mode-hook . puni-mode)
   (prog-mode-hook . hl-todo-mode)
   (prog-mode-hook . page-break-lines-mode)
   (prog-mode-hook . highlight-indent-guides-mode)
   (prog-mode-hook . tempel-setup-capf)
   (prog-mode-hook . turn-on-hes-mode)
   (prog-mode-hook . flymake-mode)
   (prog-mode-hook . highlight-numbers-mode)
   (prog-mode-hook . show-paren-mode)
   (prog-mode-hook . whitespace-mode)
   (prog-mode-hook . display-line-numbers-mode)))

text-mode

Sane basic configurations to text-mode.

(use-package text-mode
  :straight (:type built-in)
  :hook
  ((text-mode-hook . whitespace-mode)
   (text-mode-hook . page-break-lines-mode)
   (text-mode-hook . auto-fill-mode)
   (text-mode-hook . wucuo-start)
   (text-mode-hook . tempel-setup-capf)
   (text-mode-hook . (lambda () (ansi-color-apply-on-region (point-min) (point-max) t)))))

Org

org-mode is probably the killer mode and one of the main reasons as to why anyone should try Emacs.

Important links:

(use-package org
  :mode ("\\.org\\'" . org-mode)
  :straight t
  :straight org-contrib
  :delight
  (org-indent-mode nil org-indent)
  :preface
  (defconst org-electric-pairs '((?/ . ?/) (?= . ?=) (?~ . ?~)))
  (defun org-mode-insert-zero-width-space ()
    (interactive)
    (insert "\u200B"))
  :hook
  ((org-mode-hook . hes-mode)
   (org-mode-hook . eldoc-mode)
   (org-mode-hook . (lambda () (whitespace-toggle-options 'lines-tail))))
  :custom
  (org-return-follows-link t)
  ;; the following used to be '(latex script entities)
  (org-highlight-latex-and-related nil)
  (org-hide-leading-stars t)
  (org-hide-emphasis-markers t)
  (org-support-shift-select nil)
  (org-link-descriptive t)
  (org-log-done 'note)
  (org-directory (if (file-directory-p onedrive-user-dir)
                     (expand-file-name "org" onedrive-user-dir)
                   documents-user-dir))
  (org-cycle-emulate-tab t)
  (org-use-property-inheritance nil)
  (org-startup-indented t)
  (org-startup-folded t)
  (org-use-speed-commands t)
  (org-outline-path-complete-in-steps nil)
  (org-fontify-done-headline t)
  (org-fontify-todo-headline t)
  (org-catch-invisible-edits 'smart)
  ;; 10 pixels because default-font-width doesn't work with daemon mode
  (org-image-actual-width (round (* 10 fill-column 0.85)))
  (org-display-remote-inline-images 'download)
  (org-modules
   '(ol-w3m ;; this comment is here for identation purposes
     ol-bbdb ol-bibtex ol-docview ol-gnus ol-info ol-irc ol-mhe
     ol-rmail ol-eww org-tempo org-inlinetask org-indent))
  ;; logging stuff
  (org-tag-alist
   '(("noexport"   . ?e)
     ("ignore"     . ?i)
     ("TOC"        . ?t)
     ("DEPRECATED" . ?d)
     ("NOTE"       . ?n)
     ("WIP"        . ?g)
     ("PERSONAL"   . ?p)
     ("MEETING"    . ?m)
     ("REFILE"     . ?f)
     ("REPEAT"     . ?r)
     ("UNI"        . ?u)
     ("WORK"       . ?w)
     ("URGENT"     . ?a)))
  (org-todo-keywords '((sequence "TODO(t)" "STARTED(s!)" "|" "DONE(d!)")
                       (sequence "WAITING(w@/!)" "HOLD(h@/!)" "|" "CANCELLED(c@/!)")))
  (org-log-into-drawer t)
  ;; (org-effort-property "EFFORT")
  (org-global-properties
   '(("EFFORT_ALL" . "0 1 2 3 4 5 6 7 8 9 10")))
  :general
  (:keymaps 'org-mode-map
   :prefix hcps/leader-key
   "v n s" #'org-narrow-to-subtree
   "v n b" #'org-narrow-to-block
   "m i" '(:ignore t :wk "insert")
   "m i d" #'org-insert-drawer
   "m i t" #'org-insert-time-stamp
   "m i l" #'org-insert-link
   "m t" #'org-set-tags-command
   "m f" #'org-set-effort
   "m d" #'org-deadline
   "m h" #'org-schedule
   "m o" #'org-priority
   "m p" #'org-set-property
   "m s" #'org-match-sparse-tree
   "m t" #'org-todo                     ; mark a TODO item as DONE
   "m h" #'org-do-promote
   "m l" #'org-do-demote
   "m <tab>" #'outline-toggle-children)
  (:keymaps 'org-mode-map
   "H-n" #'outline-next-visible-heading
   "H-p" #'outline-previous-visible-heading
   "H-u" #'outline-up-heading
   "H-i" #'org-toggle-inline-images
   "H-<" #'org-promote-subtree
   "H->" #'org-demote-subtree
   "H-SPC" #'org-mode-insert-zero-width-space
   "H-TAB" #'outline-toggle-children)
  (:keymaps 'hcps/leader-map
   "o b" #'org-switchb)
  :config
  (setq org-effort-property "EFFORT")
  (setq-mode-local org-mode electric-pair-inhibit-predicate (lambda (c) (if (char-equal c ?<) t (electric-pair-default-inhibit c))))
  (setq-mode-local org-mode electric-pair-pairs (append electric-pair-pairs org-electric-pairs)))

Add-ons

Stuff that increases the capabilities of org-mode

toc-org

With it I also use toc-org, which is an useful way to automatically maintain an updated table of contents of your .org file. Check it out!

(use-package toc-org
  :hook
  (org-mode-hook . toc-org-mode)
  :custom
  (toc-org-max-depth 3)
  (toc-org-hrefify-default "org"))

org-appear

Makes the emphasis markers magically show up when you hover those words!

(use-package org-appear
  :hook
  (org-mode-hook . org-appear-mode))

org-ref

org-ref is the de-facto way to cite inside Emacs, as it supports multiple export backends and such

(use-package org-ref
  :disabled
  :preface
  (defconst hcps/user-org-ref-path
    (expand-file-name "Documentos/Papers" onedrive-user-dir))
  :custom
  (org-ref-bibliography-notes (expand-file-name "notes.org" hcps/user-org-ref-path))
  (org-ref-default-bibliography `(,(expand-file-name "references.bib" hcps/user-org-ref-path)))
  (reftex-default-bibliography `(,(expand-file-name "references.bib" hcps/user-org-ref-path)))
  (org-ref-pdf-directory hcps/user-org-ref-path)
  (org-ref-completion-library 'org-ref-ivy-cite)
  (org-ref-insert-cite-function 'org-ref-ivy-insert-cite-link)
  (org-ref-insert-label-function 'org-ref-ivy-insert-label-link)
  (org-ref-insert-ref-function 'org-ref-ivy-insert-ref-link)
  (org-ref-show-broken-links nil)
  :general
  (:keymaps 'org-mode-map
   :prefix hcps/leader-key
   :non-normal-prefix hcps/alt-leader-key
   "m c" #'org-ref-cite-hydra/body)
  :config
  (require 'doi-utils))

org-agenda

The ultimate journaling tool of the ultimate note-taking tool.

(use-package org-agenda
  :straight (:type built-in)
  :preface
  (defun hcps/open-agenda ()
    "Opens my custom org-agenda command."
    (interactive)
    (org-agenda nil " "))
  (defun hcps/goto-inbox ()
    "Open the organizer file."
    (interactive)
    (find-file (expand-file-name "organizer.org" org-directory)))
  :custom
  (org-columns-default-format
   "%20CATEGORY(FILE) %35ITEM(TASK) %PRIORITY(P) %EFFORT(E) %DEADLINE(D) %TAGS(T)")
  (org-agenda-files
   (append (directory-files-recursively (expand-file-name "org" onedrive-user-dir) "\\.org\\'")
       (directory-files-recursively proj-user-dir "^hcps[[:alnum:]-]*\\.org\\'")))
  (org-agenda-start-with-log-mode t)
  (org-agenda-use-tag-inheritance t)
  (org-agenda-block-separator nil)
  (org-agenda-view-columns-initially t)
  (org-agenda-skip-deadline-if-done t)
  (org-agenda-skip-scheduled-if-done t)
  (org-agenda-log-mode-items '(clock closed))
  (org-agenda-custom-commands
   `((" " "Agenda"
      ((agenda ""
           ((org-agenda-span 'week)
        (org-deadline-warning-days 0)))
       (todo "STARTED"
         ((org-agenda-overriding-header "IN PROGRESS")
          (org-agenda-block-separator ?-)))
       (tags "URGENT"
         ((org-agenda-overriding-header "URGENT TASKS")))
       (tags "UNI"
         ((org-agenda-overriding-header "UNI STUFF")))
       (todo "TODO"
         ((org-agenda-overriding-header "PROJECTS")
          (org-agenda-files ',(directory-files-recursively proj-user-dir "^hcps[[:alnum:]-]*\\.org\\'"))))
       (tags "REFILE"
         ((org-agenda-overriding-header "TO REFILE")
          (org-agenda-files '(,(expand-file-name "org/organizer.org" onedrive-user-dir)))))))))
  :general
  (:keymaps 'hcps/leader-map
   "o a" #'hcps/open-agenda
   "o i" #'hcps/goto-inbox))

org-journal

org-journal is a powerful tool to journal your day.

(use-package org-journal
  :custom
  (org-journal-dir (format-time-string (expand-file-name "org/journal/%Y" onedrive-user-dir)))
  (org-journal-file-type 'monthly)
  (org-journal-file-format "%Y%m")
  (org-journal-date-format "%e %b %Y (%A)")
  (org-journal-time-format "")
  :general
  (:keymaps 'hcps/leader-map
   "o j" #'org-journal-new-entry))

org-capture

It is built-in and it is beautiful.

(use-package org-capture
  :straight (:type built-in)
  :commands (org-capture-mode org-capture-upgrade-templates)
  :preface
  (defconst org-main-notes-file (expand-file-name "org/organizer.org" onedrive-user-dir)
    "File that I use to store notes before reviewing them.")
  :custom
  (org-default-notes-file org-main-notes-file)
  (org-capture-templates
   `(("t" "todo" entry (file+headline ,org-main-notes-file "Inbox")
      "* TODO %? :REFILE:\nDEADLINE: %^T\n%U\n"
      :empty-lines 1 :kill-buffer t)
     ("n" "note" entry (file+headline ,org-main-notes-file "Inbox")
      "* %? :NOTE:REFILE:\n%U\n"
      :empty-lines 1 :kill-buffer t)
     ("m" "meeting" entry (file+headline ,org-main-notes-file "Inbox")
      "* %? :MEETING:REFILE:\nSCHEDULED: %^{Meeting date?}T\n%U\n"
      :empty-lines 1 :kill-buffer t)))
  :general
  (:keymaps 'hcps/leader-map
   "o c" #'org-capture))

org-id

Apparently this doesn’t get loaded with org by default?

(use-package org-id
  :after org
  :straight (:type built-in)
  :custom
  (org-id-link-to-org-use-id 'create-if-interactive-and-no-custom-id)
  (org-id-locations-file-relative t))

org-attach

Configurations related to this feature in specific

(use-package org-attach
  :after org
  :straight (:type built-in)
  :custom
  (org-attach-use-inheritance 'selective)
  (org-attach-dir-relative t)
  (org-attach-id-dir "attach/")
  (org-attach-id-to-path-function-list
   '(org-attach-id-ts-folder-format org-attach-id-uuid-folder-format))
  (org-attach-preferred-new-method 'id)
  :general
  (:keymaps 'org-mode-map
   :prefix hcps/leader-key
   "m a" #'org-attach))

org-refile

As of Org 9.4, there is a org-refile.el!

(use-package org-refile
  :after org
  :straight (:type built-in)
  :custom
  (org-refile-use-outline-path 'file)
  (org-refile-allow-creating-parent-nodes 'confirm)
  (org-refile-targets '((org-agenda-files :maxlevel . 1)))
  :general
  (:keymaps 'org-mode-map
   :prefix hcps/leader-key
   "m r" #'org-refile))

org-inline-pdf

To see inline pdf images! Amazing right?

(use-package org-inline-pdf
  :after org
  :hook
  (org-mode-hook . org-inline-pdf-mode))

org-bars

Adds bars to visualize the indentation provided by the built-in org-indent

(use-package org-bars
  :straight
  (org-bars
   :type git
   :host github
   :repo "tonyaldon/org-bars")
  :hook
  (org-mode-hook . org-bars-mode)
  :config
  (setq org-bars-stars '(:empty "*" :invisible "*" :visible "*")
        org-bars-color-options '(:desaturate-level-faces 15
                                 :darken-level-faces 30)
        org-bars-extra-pixels-height 0))

Export

Configurations relating all the numerous org exporters.

(use-package ox
  :after org
  :straight (:type built-in)
  :straight htmlize
  :preface
  (defconst org-export-default-output-folder "build"
    "Defines the default export folder for `ox' and friends.")
  (defun org-export-output-file-name-modified (orig-fun extension &optional subtreep pub-dir)
    "Collect all generated files from an export in a neat folder."
    (unless pub-dir
      (setq pub-dir org-export-default-output-folder)
      (unless (file-directory-p pub-dir)
        (make-directory pub-dir)))
    (apply orig-fun extension subtreep pub-dir nil))
  (defun org-export-remove-zero-width-space (text &rest _)
    (unless (org-export-derived-backend-p 'org)
      (replace-regexp-in-string "\u200B" "" text)))
  :init
  (advice-add #'org-export-output-file-name
              :around #'org-export-output-file-name-modified)
  (advice-add #'org-export-dispatch
              :around #'disable-scroll-margin)
  :custom
  (org-export-backends '(latex html ascii))
  (org-export-exclude-tags '("noexport" "NOEXPORT"))
  (org-export-allow-bind-keywords t)
  (org-export-headline-levels 5)
  (org-export-creator-string
   (format "Emacs %s (Org mode %s%s)" emacs-version (org-release) (org-git-version)))
  (org-export-with-sub-superscripts '{})
  (org-export-with-latex t)
  (org-export-babel-evaluate t)
  (org-export-in-background t)
  (org-export-snippet-translation-alist
   '(("b" . "beamer")
     ("l" . "latex")
     ("h" . "html")
     ("o" . "odt")))
  :general
  (:keymaps 'org-mode-map
   :prefix hcps/leader-key
   "m e" #'org-export-dispatch)
  :config
  (add-to-list 'org-export-filter-final-output-functions
               #'org-export-remove-zero-width-space t))

ox-extra

ox-extra defines a couple of cool extras, like ignore-headlines!

(use-package ox-extra
  :after (ox org-contrib)
  :straight (:type built-in)
  :hook
  ((org-export-filter-parse-tree-functions . org-export-ignore-headlines)
   (org-export-before-parsing-hook . org-latex-header-blocks-filter)))

ox-latex

Configurations to the LaTeX org exporter.

(use-package ox-latex
  :after ox
  :straight (:type built-in)
  :custom
  (org-latex-image-default-width "1\\linewidth")
  (org-latex-packages-alist
   `((,(concat "cache=false,outputdir=" org-export-default-output-folder) "minted")
     ("T1" "fontenc")
     ("" "placeins")))
  (org-latex-listings 'minted)
  (org-latex-minted-options
   '(("breaklines")
     ("breakafter" "d")
     ("linenos" "true")
     ("xleftmargin" "\\parindent")))
  (org-latex-pdf-process
   '("latexmk -pdfxelatex='xelatex -shell-escape -interaction=nonstopmode' -f -xelatex -outdir=%o %f"))
  :config
  (add-to-list 'org-latex-classes
               '("iiufrgs"
                 "\\documentclass{iiufrgs}"
                 ("\\chapter{%s}"       . "\\chapter*{%s}")
                 ("\\section{%s}"       . "\\section*{%s}")
                 ("\\subsection{%s}"    . "\\subsection*{%s}")
                 ("\\subsubsection{%s}" . "\\subsubsection*{%s}")
                 ("\\paragraph{%s}"     . "\\paragraph*{%s}")))
  (add-to-list 'org-latex-classes
               '("newlfm"
                 "\\documentclass{newlfm}"
                 ("\\chapter{%s}"       . "\\chapter*{%s}")
                 ("\\section{%s}"       . "\\section*{%s}")
                 ("\\subsection{%s}"    . "\\subsection*{%s}")
                 ("\\subsubsection{%s}" . "\\subsubsection*{%s}")))
  (add-to-list 'org-latex-classes
               '("IEEEtran"
                 "\\documentclass{IEEEtran}"
                 ("\\section{%s}"       . "\\section*{%s}")
                 ("\\subsection{%s}"    . "\\subsection*{%s}")
                 ("\\subsubsection{%s}" . "\\subsubsection*{%s}")
                 ("\\paragraph{%s}"     . "\\paragraph*{%s}")
                 ("\\subparagraph{%s}"  . "\\subparagraph*{%s}"))))

ox-hugo

To the oh-so-pretty Hugo markdown format!

(use-package ox-hugo
  :after ox
  :demand t)

ox-twbs

Twitter bootstrap htmls!

(use-package ox-twbs
  :after ox
  :demand t)

ox-dnd

Yeah. That’s right.

I mean, it’s basically a tool to interface with the D&D LaTeX class. Not that nerdy, is it?

(use-package ox-dnd
  :after ox
  :straight (:type built-in)
  :load-path (lambda () (expand-file-name "emacs-org-dnd" vendor-user-dir)))

ox-beamer

To export pretty slide presentations

(use-package ox-beamer
  :after ox
  :straight (:type built-in)
  :delight
  (org-beamer-mode nil)
  :custom
  (org-beamer-environments-extra
   '(("onlyenv" "O" "\\begin{onlyenv}%a" "\\end{onlyenv}")
     ("minipage" "m" "\\begin{minipage}[%R]{%O}" "\\end{minipage}%")))
  :general
  (:keymaps 'org-beamer-mode-map
   :prefix hcps/leader-key
   "m b" '(:ignore t :wk "beamer")
   "m b e" #'org-beamer-select-environment
   "m b p" #'org-beamer-export-to-pdf))

Babel

Now, some configurations relating org-babel and its magic source blocks.

(use-package ob
  :after org
  :straight (:type built-in)
  :delight
  (org-src-mode)
  :preface
  (defun org-babel-tangle-block ()
    (interactive)
    (let ((current-prefix-arg '(4)))
      (call-interactively #'org-babel-tangle)))
  (defun org-babel-strip-ansi-codes (func &rest args)
    (let ((result (apply func args)))
      (unless (null result)
        (replace-regexp-in-string ansi-color-control-seq-regexp "" result))))
  (defun org-babel-region-strip-ansi-codes (func beg &rest args)
    "Remove all ansi-color codes from point (the end of the region) to `beg'."
    (while (re-search-forward ansi-color-control-seq-regexp beg t -1)
      (replace-match "" nil nil))
    (apply func beg args))
  :hook
  (org-babel-after-execute-hook . org-remove-inline-images)
  :init
  (advice-add #'org-trim :around #'org-babel-strip-ansi-codes)
  (advice-add #'org-no-properties :around #'org-babel-strip-ansi-codes)
  (advice-add #'org-element-normalize-string  :around #'org-babel-strip-ansi-codes)
  (advice-add #'org-babel-examplify-region :around #'org-babel-region-strip-ansi-codes)
  (advice-add #'org-string-nw-p :around #'org-babel-strip-ansi-codes)
  (advice-add #'org-element-interpret-data :around #'org-babel-strip-ansi-codes)
  :custom
  (org-edit-src-content-indentation 0)
  (org-edit-src-persistent-message nil)
  (org-src-preserve-indentation t)
  (org-src-fontify-natively t)
  (org-src-tab-acts-natively t)
  (org-src-window-setup 'other-window)
  (org-babel-default-header-args
   '((:session . "none")
     (:results . "value replace")
     (:exports . "code")
     (:cache   . "none")
     (:noweb   . "no")
     (:async   . "yes")
     (:eval    . "never-export")
     (:hlines  . "no")
     (:tangle  . "no")))
  (org-babel-load-languages
   '((emacs-lisp . t)
     (shell . t)
     (python . t)
     (julia . t)
     (makefile . t)
     (R . t)
     (C . t)
     (ruby . t)
     (ditaa . t)
     (dot . t)
     (octave . t)
     (sqlite . t)
     (perl . t)
     (screen . t)
     (plantuml . t)
     (lilypond . t)
     (latex . t)))
  :general
  (:keymaps 'org-mode-map
   :prefix hcps/leader-key
   "m x" #'org-babel-execute-buffer
   "m z" #'org-babel-tangle-block
   "m Z" #'org-babel-tangle)
  (:keymaps 'org-mode-map
   "C-c SPC" #'org-edit-special)
  (:keymaps 'org-src-mode-map
   "C-c SPC" #'org-edit-src-exit)
  :config
  ;; set correct modes for some languages
  (setf (alist-get "dot" org-src-lang-modes) 'graphviz-dot
        (alist-get "latex" org-src-lang-modes) 'TeX-latex))

ob-jupyter

As a great way to run Python and Julia source blocks inside org-mode

(use-package jupyter
  :after ob
  :straight t
  :straight zmq
  :straight websocket
  :commands jupyter-org-interaction-mode
  :custom
  (org-babel-default-header-args:jupyter-julia
   '((:eval . "no-export")
     (:async . "yes")
     (:session . "*Julia*")
     (:results . "value")
     (:exports . "both")
     (:kernel . "julia-1.4")))
  (org-babel-default-header-args:jupyter-python
   '((:eval . "no-export")
     (:async . "yes")
     (:session . "*Python*")
     (:results . "value")
     (:exports . "both")
     (:kernel . "python3"))))

ob-R

Basic configuration about org-babel for R

(use-package ob-R
  :after ob
  :straight (:type built-in)
  :custom
  (org-babel-default-header-args:R
   '((:exports . "both"))))

cc-mode languages

Here I set some defaults I appreciate for cc-mode (the builtin mode for all c-like languages):

(use-package cc-mode
  :straight (:type built-in)
  :commands (c-mode awk-mode java-mode c++-mode)
  :mode
  (("\\.c\\'"       . c-mode)
   ("\\.h\\'"       . c-mode)
   ("\\.C\\'"       . c++-mode)
   ("\\.H\\'"       . c++-mode)
   ("\\.c\\+\\+\\'" . c++-mode)
   ("\\.h\\+\\+\\'" . c++-mode)
   ("\\.cpp\\'"     . c++-mode)
   ("\\.hpp\\'"     . c++-mode)
   ("\\.awk\\'"     . awk-mode)
   ("\\.java\\'"    . java-mode))
  :preface
  (defun c-indent-for-tab-command ()
    (interactive)
    (let ((p (point)))
      (c-indent-line-or-region)
      (when (= p (point))
        (call-interactively #'complete-symbol))))
  :hook
  (((c-mode-hook c++-mode-hook java-mode-hook) . eglot-ensure)
   ((c-mode-hook c++-mode-hook java-mode-hook) . tree-sitter-mode))
  :custom
  (c-default-style
   '((java-mode . "java")
     (awk-mode  . "awk")
     (other     . "linux")))
  (c-doc-comment-style
   '((java-mode . javadoc)
     (pike-mode . autodoc)
     (c-mode    . doxygen)
     (c++-mode  . doxygen)))
  (c-basic-offset 4)
  :general
  (:keymaps 'c-mode-base-map
   "TAB" #'c-indent-for-tab-command))

As languages that are part of cc-mode are known to using a lot of doxygen, here’s a package that highlights it!

(use-package highlight-doxygen
  :disabled
  :hook
  (c-mode-common-hook . highlight-doxygen-mode)
  :custom-face
  (highlight-doxygen-comment ((t :inherit font-lock-doc-face :background "#363230" :extend t)))
  (highlight-doxygen-code-block ((t :background "#363230" :extend t))))

C/C++

Better C++ font lock

(use-package modern-cpp-font-lock
  :delight
  (modern-c++-font-lock-mode)
  :hook
  (c++-mode-hook . modern-c++-font-lock-mode))

And better pre-processor highlighting

(use-package preproc-font-lock
  :commands (preproc-font-lock-mode preproc-font-lock-global-mode)
  :hook
  ((c-mode-hook c++-mode-hook) . preproc-font-lock-mode)
  :custom-face
  (preproc-font-lock-preprocessor-background ((t :background "#302c2b"))))

In the department of code formatting, clang-format is a lovely tool that can really be of great use while editing C and C++ code.

(use-package clang-format
  :preface
  (defun cc-format-on-save-hook ()
    (when c-buffer-is-cc-mode
      (clang-format-buffer)))
  :custom
  (clang-format-fallback-style "webkit")
  :general
  (:keymaps 'c-mode-base-map
   :prefix hcps/leader-key
   "m f" #'clang-format-region))

CUDA

Suporting CUDA syntax per-se is kinda easy, as it’s a subset of C after all. The thing is I want proper syntax highlighting for all those special keywords and types that CUDA introduces. So, let’s install cuda-mode:

(use-package cuda-mode
  :straight
  (cuda-mode
   :type git
   :host github
   :repo "hcpsilva/cuda-mode")
  :mode "\\.cu\\'"
  :custom
  (cuda-font-lock-keywords 'cuda-font-lock-keywords-3))

It falls back on c++-mode by default, so we are safe here.

R

For R you pretty much need the ess package, i.e. Emacs Speaks Statistics. It provides you with everything you need from R.

(use-package ess-r-mode
  :straight ess
  :commands (R R-mode r-mode ess-r-mode ess-r-transcript-mode)
  :preface
  (defun hcps/insert-r-pipe ()
    "Lets us insert the magrittr piping operator in R"
    (interactive)
    (just-one-space 1)
    (insert "%>%")
    (reindent-then-newline-and-indent))
  :hook
  ((ess-r-mode-hook . aggressive-indent-mode)
   ;; (ess-r-mode-hook . tree-sitter-mode)
   (inferior-ess-mode-hook . comint-fix-window-size))
  :custom
  (ido-enable-flex-matching t)
  (ess-gen-proc-buffer-name-function #'ess-gen-proc-buffer-name:simple)
  (ess-auto-width fill-column)
  (ess-style 'RStudio)
  :general
  (:keymaps 'ess-r-mode-map
   "M-RET" #'hcps/insert-r-pipe
   "<tab>" #'ess-indent-or-complete)
  (:keymaps 'ess-r-mode-map
   :prefix hcps/leader-key
   "m c" #'ess-eval-region-or-function-or-paragraph-and-step
   "m r" #'ess-eval-region
   "m e" #'Rd-mode-insert-skeleton
   "m f" #'Rd-font
   "m j" #'Rd-mode-insert-item
   "m n" #'ess-eval-line-visibly-and-step
   "m p" #'Rd-preview-help
   "m s" #'Rd-mode-insert-section
   "m v" #'ess-display-help-on-object
   "m w" #'ess-switch-process
   "m y" #'ess-switch-to-ESS
   "m z" #'ess-switch-to-end-of-ESS))

Shell script

As for shell-scripting:

(use-package sh-script
  :straight (:type built-in)
  :commands (shell-script-mode sh-mode)
  :mode
  (("\\.zsh\\'" . shell-script-mode)
   ("PKGBUILD\\'" . shell-script-mode))
  :preface
  (defconst prezto-files
    '(".zlogin" ".zlogin" ".zlogout" ".zpreztorc" ".zprofile" ".zshenv" ".zshrc")
    "Files that are too zsh-style files.")
  (defun zsh-prezto-files ()
    "Function to ease switching to zsh when dealing with a zsh file."
    (if (and buffer-file-name
             (member (file-name-nondirectory buffer-file-name) prezto-files))
        (sh-set-shell "zsh")))
  :hook
  ((sh-mode-hook . zsh-prezto-files)
   (sh-mode-hook . tree-sitter-mode)
   (sh-mode-hook . sh-electric-here-document-mode))
  :general
  (:keymaps 'sh-mode-map
   :prefix hcps/leader-key
   "m s" #'sh-set-shell
   "m i c" #'sh-case
   "m i f" #'sh-for
   "m i i" #'sh-if
   "m i s" #'sh-select
   "m i w" #'sh-while
   "m i o" #'sh-while-getopts
   "m i u" #'sh-until
   "m i F" #'sh-function
   "m i I" #'sh-indexed-loop))

For shell completion I use bash-complete, which auto completes several bash functions.

(use-package bash-completion
  :hook
  (shell-dynamic-complete-functions . bash-completion-dynamic-complete)
  :custom
  (bash-completion-use-separate-processes t))

Makefile

In Makefile files we have a special case: it needs tabulators to work. So, we’ll set that up.

(use-package make-mode
  :straight (:type built-in)
  :commands makefile-mode
  :mode ("^[Mm]akefile\\'" . makefile-mode)
  :config
  (setq-mode-local makefile-mode indent-tabs-mode t))

PlantUML

PlantUML is a graph language that describes loads of different diagram types, mainly focusing on UML, of course.

(use-package plantuml-mode
  :mode "\\.plantuml\\'"
  :interpreter "plantuml")

Lisp

Fix for the annoying keyword default indentation:

(defun fuco1/lisp-indent-function (indent-point state)
  "This function is the normal value of the variable `lisp-indent-function'.
The function `calculate-lisp-indent' calls this to determine if
the arguments of a Lisp function call should be indented
specially. INDENT-POINT is the position at which the line being
indented begins. Point is located at the point to indent
under (for default indentation); STATE is the
`parse-partial-sexp' state for that position. If the current line
is in a call to a Lisp function that has a non-nil property
`lisp-indent-function' (or the deprecated `lisp-indent-hook'), it
specifies how to indent. The property value can be:
* `defun', meaning indent `defun'-style
  (this is also the case if there is no property and the function
  has a name that begins with \"def\", and three or more arguments);
* an integer N, meaning indent the first N arguments specially
  (like ordinary function arguments), and then indent any further
  arguments like a body;
* a function to call that returns the indentation (or nil).
  `lisp-indent-function' calls this function with the same two arguments
  that it itself received.
This function returns either the indentation to use, or nil if the
Lisp function does not specify a special indentation."
  (let ((normal-indent (current-column))
        (orig-point (point)))
    (goto-char (1+ (elt state 1)))
    (parse-partial-sexp (point) calculate-lisp-indent-last-sexp 0 t)
    (cond
     ;; car of form doesn't seem to be a symbol, or is a keyword
     ((and (elt state 2)
           (or (not (looking-at "\\sw\\|\\s_"))
               (looking-at ":")))
      (if (not (> (save-excursion (forward-line 1) (point))
                  calculate-lisp-indent-last-sexp))
          (progn (goto-char calculate-lisp-indent-last-sexp)
                 (beginning-of-line)
                 (parse-partial-sexp (point)
                                     calculate-lisp-indent-last-sexp 0 t)))
      ;; Indent under the list or under the first sexp on the same
      ;; line as calculate-lisp-indent-last-sexp.  Note that first
      ;; thing on that line has to be complete sexp since we are
      ;; inside the innermost containing sexp.
      (backward-prefix-chars)
      (current-column))
     ((and (save-excursion
             (goto-char indent-point)
             (skip-syntax-forward " ")
             (not (looking-at ":")))
           (save-excursion
             (goto-char orig-point)
             (looking-at ":")))
      (save-excursion
        (goto-char (+ 2 (elt state 1)))
        (current-column)))
     (t
      (let ((function (buffer-substring (point)
                                        (progn (forward-sexp 1) (point))))
            method)
        (setq method (or (function-get (intern-soft function)
                                       'lisp-indent-function)
                         (get (intern-soft function) 'lisp-indent-hook)))
        (cond ((or (eq method 'defun)
                   (and (null method)
                        (> (length function) 3)
                        (string-match "\\`def" function)))
               (lisp-indent-defform state indent-point))
              ((integerp method)
               (lisp-indent-specform method state
                                     indent-point normal-indent))
              (method
               (funcall method indent-point state))))))))

also extra magic font lock for Lisp and Scheme

(use-package lisp-extra-font-lock
  :commands (lisp-extra-font-lock-mode lisp-extra-font-lock-global-mode))

Finally, the mode’s final configuration

(use-package lisp-mode
  :straight (:type built-in)
  :mode
  (("\\.lsp\\'"  . lisp-mode)
   ("\\.lisp\\'" . lisp-mode)
   ("\\.cl\\'"   . lisp-mode))
  :hook
  ((lisp-mode-hook . aggressive-indent-mode)
   (lisp-mode-hook . puni-disable-puni-mode)
   (lisp-mode-hook . lispy-mode)
   (lisp-mode-hook . lisp-extra-font-lock-mode))
  :custom
  (lisp-indent-function #'fuco1/lisp-indent-function))

Elisp

Emacs version!

(use-package elisp-mode
  :straight (:type built-in)
  :straight elisp-slime-nav
  :commands emacs-lisp-mode
  :mode ("\\.el\\'" . emacs-lisp-mode)
  :preface
  (defun recompile-elc-on-save ()
    "Recompile your elc when saving an elisp file."
    (when (and (string-prefix-p user-emacs-directory (file-truename buffer-file-name))
               (file-exists-p (byte-compile-dest-file buffer-file-name)))
      (emacs-lisp-byte-compile)))
  :hook
  ((after-save-hook      . recompile-elc-on-save)
   (emacs-lisp-mode-hook . (lambda () (run-hooks 'lisp-mode-hook))))
  :config
  (require 'use-package))

Python

Start by adding pyenv.el to deal with virtual environments

(use-package pyenv
  :commands (pyenv-activate pyenv-workon))

and auto-virtualenv

(use-package auto-virtualenv
  :after pyenv
  :commands auto-virtualenv-set-virtualenv)

Finally, a simple yet effective Python configuration.

(use-package python
  :straight (:type built-in)
  :commands python-mode
  :hook
  ((python-mode-hook . tree-sitter-mode)
   (python-mode-hook . eglot-ensure)
   (python-mode-hook . auto-virtualenv-set-virtualenv))
  :custom
  (python-flymake-command '("flake8" "-")))

CMake

As CMake is very simple, each word carries a load of meaning and importance. This little mode colors them accordingly.

(use-package cmake-mode
  :mode
  (("^CMakeLists\\.txt\\'" . cmake-mode)
   ("\\.cmake\\'"          . cmake-mode)))

Also add extra colors

(use-package cmake-font-lock
  :after cmake-mode
  :demand t
  :hook
  (cmake-mode-hook . cmake-font-lock-activate))

Dockerfile

dockerfile-mode adds support to syntax highlighting and to build the image directly from the buffer using C-c C-b.

(use-package dockerfile-mode
  :mode "[Dd]ockerfile\\'"
  :hook
  (dockerfile-mode-hook . puni-mode))

GMPL

So I have syntax highlighting while editing GLPK files.

(use-package gmpl-mode
  :mode "\\.mod\\'"
  :hook
  (gmpl-mode-hook . puni-mode))

Julia

Packages to write Julia source code in Emacs.

(use-package julia-mode
  :mode "\\.jl\\'"
  :preface
  (defun hcps/insert-julia-pipe ()
    "Lets us insert the piping operator |> in Julia"
    (interactive)
    (just-one-space 1)
    (insert "|>")
    (reindent-then-newline-and-indent))
  :init
  (setq inferior-julia-program (hcps/s-trim-right (shell-command-to-string "which julia")))
  (defvaralias 'inferior-julia-program-name 'inferior-julia-program
    "Because jupyter still uses this symbol.")
  (advice-add #'julia :around (lambda (func &rest args) (set-buffer (apply func args))))
  :hook
  ((julia-mode-hook . tree-sitter-mode)
   (julia-mode-hook . aggressive-indent-mode))
  :general
  (:keymaps 'julia-mode-map
   "M-RET" #'hcps/insert-julia-pipe))

LaTeX

Let’s start with some basic AUCTeX configuration

(use-package tex
  :straight auctex
  :commands (tex-mode plain-tex-mode texinfo-mode latex-mode doctex-mode TeX-tex-mode)
  :mode ("\\.tex\\'" . TeX-latex-mode)
  :hook
  (((LaTeX-mode-hook TeX-mode-hook) . auto-fill-mode)
   ((LaTeX-mode-hook TeX-mode-hook) . puni-mode)
   ((LaTeX-mode-hook TeX-mode-hook) . rainbow-delimiters-mode))
  :init
  (setq reftex-plug-into-AUCTeX t)
  :custom
  (TeX-auto-save t)
  (TeX-master nil)
  (TeX-engine 'xetex)
  (TeX-parse-self t)
  (TeX-save-query nil)
  (TeX-source-correlate-method 'synctex)
  (TeX-output-dir "build")
  (TeX-view-program-selection
   '(((output-dvi has-no-display-manager) "dvi2tty")
     ((output-dvi style-pstricks) "dvips and gv")
     (output-dvi "xdvi")
     (output-pdf "xdg-open")
     (output-html "xdg-open")))
  :general
  (:keymaps 'LaTeX-mode-map
   :prefix hcps/leader-key
   "m e" #'LaTeX-environment
   "m s" #'LaTeX-section
   "m m" #'TeX-insert-macro))

And RefTeX to follow it

(use-package reftex
  :straight (:type built-in)
  :delight (reftex-mode " ref")
  :commands (reftex-mode turn-on-reftex)
  :hook
  (LaTeX-mode-hook . turn-on-reftex)
  :custom
  (reftex-bibliography-commands '("bibliography" "nobibliography" "addbibresource"))
  :general
  (:keymaps 'LaTeX-mode-map
   :prefix hcps/leader-key
   "m b" #'reftex-label
   "m r" #'reftex-reference
   "m c" #'reftex-citation
   "m t" #'reftex-toc
   "m i" #'reftex-index))

So, for my LaTeX config I’ll mainly use latexmk as it’s way simpler to use.

(use-package auctex-latexmk
  :straight
  (auctex-latexmk
   :type git
   :host github
   :repo "wang1zhen/auctex-latexmk")
  :after tex
  :demand t
  :config
  (auctex-latexmk-setup))

With latexmk I do also use its configuration file in ~/.latexmkrc, so some important stuff may be defined there.

Meson

Syntax support for the Meson build system DSL (which is based from Python).

(use-package meson-mode
  :commands meson
  :mode "^meson\\.build\\'")

sxhkdrc

Mode recently made by a cool person online. Replaces the old and strange configuration I had before.

(use-package sxhkd-mode
  :straight
  (sxhkd-mode
   :type git
   :host github
   :repo "xFA25E/sxhkd-mode")
  :mode "sxhkdrc\\'"
  :hook
  (sxhkd-mode-hook . (lambda () (run-hooks 'conf-mode-hook))))

Configuration files

Just a little hook to start the desired conf-mode when we open these files.

(use-package conf-mode
  :straight (:type built-in)
  :mode
  (("\\.service\\'" . conf-mode)
   ("\\.conf\\'" . conf-mode))
  :hook
  (conf-mode-hook . (lambda () (run-hooks 'prog-mode-hook))))

Rust

The newest greatest compiled language!

(use-package rust-mode
  :straight t
  :straight cargo
  :hook
  ((rust-mode-hook . eglot-ensure)
   (rust-mode-hook . cargo-minor-mode)))

Perl

Old language, still great for doing admin stuff in few lines.

(use-package cperl-mode
  :straight (:type built-in)
  :mode "\\.p[lm]\\'"
  :interpreter "perl"
  :commands cperl-mode
  :preface
  (defalias #'perl-mode #'cperl-mode "CPerl has better handling and utilities.")
  :hook
  (cperl-mode-hook . eglot-ensure)
  :custom
  (cperl-font-lock t)
  (cperl-info-on-command-no-prompt t)
  (cperl-clobber-lisp-bindings nil)
  (cperl-indent-level 4)
  :custom-face
  (cperl-nonoverridable-face ((t (:inherit font-lock-builtin-face :foreground unspecified))))
  ;; (cperl-array-face ((t nil)))
  ;; (cperl-hash-face ((t nil)))
  :general
  (:keymaps 'cperl-mode-map
   :prefix hcps/leader-key
   "i" #'cperl-indent-region)
  :config
  (font-lock-add-keywords
   'cperl-mode
   '(("^#!\\/\\(?:\\w+\\/\\)*\\(\\w+\\)"
      (1 'font-lock-keyword-face prepend))
     ("\\(\\\\\\)\\(&\\)\\([[:alnum:]_:]+\\)"
      (1 'font-lock-builtin-face)
      (2 'font-lock-type-face)
      (3 'font-lock-function-name-face))
     ("\\(\\$\\)\\([[:digit:]_`]\\)[^[:alnum:]_:]"
      (1 'font-lock-type-face prepend)
      (2 'font-lock-builtin-face prepend))
     ("\\(?:^\\|[^[:alnum:]_:\\\\]\\)\\([&$*@%]+\\)\\([[:alnum:]_:]+\\)"
      (1 'font-lock-type-face append)
      (2 'font-lock-variable-name-face append))))
  ;; (font-lock-remove-keywords
  ;;  'cperl-mode
  ;;  '(("\\(\\([$@%]+\\)[a-zA-Z_:][a-zA-Z0-9_:]*\\)[ \t]*\\([[{]\\)" 1
  ;;     (if (= (- (match-end 2) (match-beginning 2)) 1)
  ;;         (if (eq (char-after (match-beginning 3)) ?{)
  ;;             'cperl-hash-face
  ;;           'cperl-array-face)
  ;;       font-lock-variable-name-face)
  ;;     t)
  ;;    ("\\(\\([@%]\\|\\$#\\)[a-zA-Z_:][a-zA-Z0-9_:]*\\)" 1
  ;;     (if (eq (char-after (match-beginning 2)) ?%)
  ;;         'cperl-hash-face
  ;;       'cperl-array-face)
  ;;     nil)
  ;;    ("\\(@\\|\\$#\\)\\(\\$+\\([a-zA-Z_:][a-zA-Z0-9_:]*\\|[^ \t\n]\\)\\)"
  ;;     (1 'cperl-array-face)
  ;;     (2 font-lock-variable-name-face))
  ;;    ("\\(%\\)\\(\\$+\\([a-zA-Z_:][a-zA-Z0-9_:]*\\|[^ \t\n]\\)\\)"
  ;;     (1 'cperl-hash-face)
  ;;     (2 font-lock-variable-name-face))
  ;;    ("\\([$*]{?\\(?:\\sw+\\|::\\)+\\)" 1
  ;;     font-lock-variable-name-face)))
  )

Dot (Graphviz)

Diagrams are cool

(use-package graphviz-dot-mode
  :mode
  (("\\.gv\\'"  . graphviz-dot-mode)
   ("\\.dot\\'" . graphviz-dot-mode))
  :commands (graphviz-dot-mode)
  :hook
  ((graphviz-dot-mode-hook . aggressive-indent-mode)
   (graphviz-dot-mode-hook . puni-mode))
  :custom
  (graphviz-dot-indent-width 4)
  :general
  (:keymaps 'graphviz-dot-mode-map
   :prefix hcps/leader-key
   "m f" #'graphviz-dot-indent-graph
   "m p" #'graphviz-dot-preview))

Bison/Flex/Yacc

For lexer shenanigans

(use-package bison
  :straight (:type built-in)
  :commands bison-mode
  :load-path (lambda () (expand-file-name "bison-mode" vendor-user-dir))
  :mode
  (("\\.y\\'" . bison-mode)
   ;; ("\\.l\\'" . flex-mode)
   ;; ("\\.jison\\'" . jison-mode)
   )
  ;; :custom
  ;; (bison-all-electricity-off t)
  ;; (bison-rule-separator-column 0)
  ;; (bison-rule-enumeration-column 0)
  ;; (bison-decl-type-column 0)
  ;; (bison-decl-token-column 0)
  )

Markdown

Ugh another mode that insists in putting bigger fonts everywhere…

(use-package markdown-mode
  :mode "\\.md\\'"
  :commands (markdown-mode gfm-mode)
  :preface
  (defconst markdown-electric-pairs '((?_ . ?_) (?* . ?*) (?` . ?`)))
  :hook
  ((markdown-mode-hook . auto-fill-mode)
   (markdown-mode-hook . puni-mode)
   (markdown-mode-hook . hes-mode)
   (markdown-mode-hook . eldoc-mode)
   (markdown-mode-hook . (lambda () (whitespace-toggle-options 'lines-tail))))
  :custom
  (markdown-hr-display-char ?-)
  (markdown-hide-markup nil)
  :custom-face
  (markdown-line-break-face ((t (:inherit unspecified :underline unspecified))))
  (markdown-header-face ((t (:height 1.0))))
  :config
  (setq-mode-local markdown-mode electric-pair-pairs (append electric-pair-pairs
                                                             markdown-electric-pairs))
  (dolist (num (number-sequence 1 6))
    (custom-set-faces `(,(intern (format "markdown-header-face-%d" num)) ((t (:height 1.0))))))
  (font-lock-remove-keywords
   'markdown-mode
   `((,markdown-regex-line-break
      1 'markdown-line-break-face prepend))))

JavaScript

So I can write a decent Tree Sitter grammar.

(use-package js
  :mode "\\.jsx?\\'"
  :straight (:type built-in)
  :commands (js-mode)
  :hook
  ((js-mode-hook . tree-sitter-mode)
   (js-mode-hook . aggressive-indent-mode)))

Typescript

Here we’ll not be using js-mode! Instead, we’ll be using typescript-mode with Tree Sitter atop it!

(use-package typescript-mode
  :mode "\\.tsx?\\'"
  :hook
  (typescript-mode-hook . (lambda () (run-hooks 'js-mode-hook))))

Clojure

Fucking finally

(use-package clojure-mode
  :mode
  (("\\.\\(clj\\|dtm\\|edn\\)\\'" . clojure-mode)
   ("\\.cljc\\'" . clojurec-mode)
   ("\\.cljs\\'" . clojurescript-mode))
  :hook
  ((clojure-mode-hook . aggressive-indent-mode)
   (clojure-mode-hook . puni-disable-puni-mode)
   (clojure-mode-hook . eglot-ensure)
   (clojure-mode-hook . lispy-mode))
  :config
  (define-clojure-indent
    (defroutes 'defun)
    (GET 2)
    (POST 2)
    (PUT 2)
    (DELETE 2)
    (HEAD 2)
    (ANY 2)
    (OPTIONS 2)
    (PATCH 2)
    (rfn 2)
    (let-routes 1)
    (context 2)))

also add extra font-locking to the mode

(use-package clojure-mode-extra-font-locking
  :demand t
  :after clojure-mode)

also configure CIDER

(use-package cider
  :after clojure-mode
  :custom
  (cider-allow-jack-in-without-project t)
  :general
  (:keymaps 'clojure-mode-map
   :prefix hcps/leader-key
   "m i" #'cider-jack-in))

and clj-refactor

(use-package clj-refactor
  :after clojure-mode
  :hook
  (clojure-mode-hook . clj-refactor-mode))

and inf-clojure (inferior repl buffer for Clojure)

(use-package inf-clojure
  :after clojure-mode
  :general
  (:keymaps 'clojure-mode-map
   :prefix hcps/leader-key
   "m R" #'inf-clojure)
  :config
  (setf (alist-get 'joker inf-clojure-startup-forms) "joker --no-readline"))

Racket

Yes! I’ve came full circle and now I love Lisp/Scheme, what the heck.

(use-package racket-mode
  :mode "\\.rkt?\\'"
  :hook
  ((racket-mode-hook . (lambda () (run-hooks 'lisp-mode-hook)))
   (racket-mode-hook . racket-xp-mode)
   (racket-repl-mode-hook . (lambda () (run-hooks 'lisp-mode-hook))))
  :custom
  (racket-memory-limit 4096)
  (racket-show-functions '(racket-show-echo-area))
  :custom-face
  (racket-selfeval-face ((t (:inherit font-lock-constant-face :foreground unspecified))))
  :general
  (:keymaps 'racket-mode-map
   :prefix hcps/leader-key
   "m x" #'racket-run-and-switch-to-repl
   "m l" #'racket-insert-lambda))

YAML

Yet Another Markup Language

(use-package yaml-mode
  :mode
  (("\\.yaml\\'" . yaml-mode)
   ("\\.yml\\'"  . yaml-mode))
  :hook
  (yaml-mode-hook . puni-mode))

GGO

gengetopt files!

(use-package ggo-mode
  :straight
  (ggo-mode
   :type git
   :host github
   :repo "mkjunker/ggo-mode")
  :mode "\\.ggo\\'"
  :hook
  (ggo-mode-hook . (lambda () (run-hooks 'prog-mode-hook))))

Git-related files

Like configuration files, only, I don’t know, different?

(use-package git-modes
  :mode
  (("\\.gitconfig\\'"      . gitconfig-mode)
   ("\\.git/config\\'"     . gitconfig-mode)
   ("modules/.*/config\\'" . gitconfig-mode)
   ("git/config\\'"        . gitconfig-mode)
   ("\\.gitmodules\\'"     . gitconfig-mode)
   ("/etc/gitconfig\\'"    . gitconfig-mode)
   ("\\.gitignore\\'"      . gitignore-mode)
   ("info/exclude\\'"      . gitignore-mode)
   ("git/ignore\\'"        . gitignore-mode)
   ("\\.gitattributes\\'"  . gitattributes-mode)
   ("info/attributes\\'"   . gitattributes-mode)
   ("git/attributes\\'"    . gitattributes-mode)))

Go Language

The Go programming language!

(use-package go-mode
  :mode "\\.go\\'"
  :hook
  ((go-mode-hook . eglot-ensure)
   (go-mode-hook . tree-sitter-mode)))

Terraform

And its weird HCL markup language

(use-package hcl-mode
  :mode "\\.hcl\\'")
(use-package terraform-mode
  :after hcl-mode
  :mode "\\.tf\\(vars\\)?\\'")

Vimscript

Yeah I have no comments for this one

(use-package vimrc-mode
  :mode "\\.vim\\(rc\\)?\\'")

Lua

Brazilian export!

(use-package lua-mode
  :mode "\\.lua\\'"
  :interpreter "lua")

Local variables

About

My Emacs configuration!

License:MIT License


Languages

Language:Emacs Lisp 95.2%Language:YASnippet 2.7%Language:Common Lisp 1.5%Language:Shell 0.6%