Skip to content

lua-vr/baremacs

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

baremacs

Package ideas

Bookmarks ranges and display as highlights in the buffer

General package to scroll sync two files

E.g., have a “notes” buffer and a main buffer. In the main buffer, save “snapshots” of the scroll position of the other buffer.

Could also be used for translation, porting, rewriting, etc., any task that demand two files open side by side.

Option to automatically save positions, whenever something is written in the “auxiliary” buffer, attach it to the visible position in the “main” buffer.

Elpaca setup

;;; -*- lexical-binding: t; -*-
(load (expand-file-name "elpaca-init" user-emacs-directory))

Now we make it so that use-package declarations are installed by Elpaca by default.

(setopt use-package-always-ensure t
        use-package-always-defer t)

Strange bugs and their stranger fixes

  • turns out the newline character \n is not in the space category of the org-mode syntax table, or at least it should not be. If this is not the case, you start getting errors with org-edit-src-block. At least one instance of this issue was fixed by deleting the desktop file so that the problematic org file would not be restored from it.

    It seems to also be fixed by (modify-syntax-entry ?\n "-" org-mode-syntax-table), BUT then, smartparens gets horribly slow!!!

    (defun fix-org-syntax-bug ()
      (interactive)
      (modify-syntax-entry ?\n "-" org-mode-syntax-table)
      (org-element-cache-reset))
        
  • In terminal, sometimes buried child frames appear and won’t go away. This command exterminates all of them.
    (defun child-frame-delete-all ()
      (interactive)
      (dolist (frame (frame-list))
        (when (frame-parameter frame 'parent-frame)
          (delete-frame frame))))
        

Useful toolbox

(defmacro cmd! (&rest forms) `(lambda () (interactive) ,@forms))
(defmacro buffer-fp-match! (regex)
  `(lambda (buffer-or-name &rest _)
     (when-let* ((buffer (get-buffer buffer-or-name))
                 (file (buffer-file-name buffer)))
       (string-match-p ,regex file))))

(defmacro buffer-mode-p! (&rest modes)
  `(lambda (buffer-or-name &rest _)
     (with-current-buffer buffer-or-name
       (derived-mode-p ',modes))))
(defun setmap (map &rest defs)
  (while defs
    (keymap-set map (car defs) (cadr defs))
    (setq defs (cddr defs))))
;; borrowed from gptel
(defun api-key-from-auth-source (host &optional user)
  "Lookup api key for HOST, USER in the auth source."
  (if-let* ((secret
             (plist-get
              (car (auth-source-search
                    :host host
                    :user (or user "apikey")
                    :require '(:secret)))
              :secret)))
      (if (functionp secret)
          (encode-coding-string (funcall secret) 'utf-8)
        secret)
    (user-error "No api-key found in the auth source")))

Performance

GCMH

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

Navigation and insertion

Basic

(keymap-global-set "C-s" #'save-buffer)
(keymap-global-set "M-z" #'toggle-frame-tab-bar)

Custom leader

(defvar leader-key (kbd "SPC"))
(defvar leader-alt-key (kbd "M-SPC"))
(defvar map-local-overrides nil)

(defun modal-setmap (active-map map &rest defs)
  (cl-symbol-macrolet ((overrides (alist-get active-map map-local-overrides)))
    (let ((new-map (alist-get map overrides)) new-leader)
      (unless new-map
        (setq new-map (make-sparse-keymap)
              new-leader (make-sparse-keymap))
        (setf (alist-get map overrides) new-map)
        (set-keymap-parent new-map map)
        (set-keymap-parent new-leader leader-map)
        (keymap-substitute new-leader map new-map)
        (require 'evil-core)
        (evil-define-key* 'motion active-map leader-key new-leader)
        (evil-define-key* 'insert active-map leader-alt-key new-leader))
      (apply #'setmap new-map defs))))

Keymaps

(repeat-mode)
(defvar-keymap leader-map
  :doc "Leader key keymap.")

(defvar-keymap file-map
  :doc "File actions keymap.")

(defvar-keymap toggle-map
  :doc "Toggle actions keymap.")

(defvar-keymap open-map
  :doc "Open actions keymap.")

(defvar-keymap buffer-map
  :doc "Buffer actions keymap.")

(defvar-keymap debug-map
  :doc "Debug actions keymap.")

(defvar-keymap code-map
  :doc "Code actions keymap.")

(defvar-keymap window-map
  :doc "Window actions keymap.")

(defvar-keymap project-map
  :doc "Mode actions keymap.")

(defvar-keymap mode-map
  :doc "Mode actions keymap.")

(setmap file-map
        "f" #'find-file
        "c" #'copy-file
        "s" #'save-buffer
        "m" #'rename-visited-file)

(setmap toggle-map
        "l" #'display-line-numbers-mode)

(setmap debug-map
        "e" #'toggle-debug-on-error
        "q" #'toggle-debug-on-quit
        "t" #'trace-function
        "T" #'untrace-function)

(setmap buffer-map
        "d" (defun kill-this-buffer () (interactive) (kill-buffer))
        "i" #'ibuffer
        "r" #'revert-buffer)

(setmap window-map
        "C-w" (defun mru-window ()
                (interactive)
                (when-let* ((window (get-mru-window nil t t t)))
                  (select-window window)))
        "p" #'other-window-prefix
        "P" #'same-window-prefix)

(setmap leader-map
        "w" (cons "Window" window-map)
        "x" (cons "x" ctl-x-map)
        "b" (cons "Buffer" buffer-map)
        "d" (cons "Debug" debug-map)
        "c" (cons "Code" code-map)
        "s" (cons "Search" search-map)
        "p" (cons "Project" project-map)
        "h" (cons "Help" help-map)
        "t" (cons "Toggle" toggle-map)
        "o" (cons "Open" open-map)
        "f" (cons "File" file-map)
        "m" (cons "Mode" mode-map)
        "TAB" (cons "Tabs" tab-prefix-map)
        "." #'find-file
        "x" #'scratch-buffer
        "u" #'universal-argument)

(setmap universal-argument-map
        "C-u" nil
        "SPC u" #'universal-argument-more)

(setmap open-map
        "f" #'make-frame)

TAB hook

This functionality allows binding many keys to TAB via a hook. The command will run all commands in the hook in order and stop at the first function that returns non-nil.

(defvar tab-actions '(indent-for-tab-command)
  "TAB actions hook.")

(defun run-tab-actions ()
  (interactive)
  (cl-dolist (action tab-actions)
    (when-let* ((res (call-interactively action)))
      (cl-return res))))

(global-set-key (kbd "TAB") #'indent-for-tab-command)

Smartparens

(use-package smartparens
  :hook (prog-mode LaTeX-mode)
  :init
  (defun smartparens-tab (&optional this)
    (lambda (&optional arg)
      (interactive "P")
      (if-let* ((e (plist-get
                    (and smartparens-mode
                         (sp--looking-at
                          (sp--get-closing-regexp
                           (sp--get-pair-list-context 'navigate)))
                         (sp-get-enclosing-sexp))
                    :cl)))
          (forward-char (length e))
        (let ((this-command this))
          (indent-for-tab-command arg)))))
  :config
  (global-set-key (kbd "TAB") (smartparens-tab))
  (global-set-key (kbd "<backtab>") #'sp-up-sexp)
  (require 'smartparens-config)
  (dolist (h '(prog-mode-hook LaTeX-mode-hook))
    (add-hook h 'smartparens-mode 99 nil)))

Link-hint

(use-package link-hint
  :bind (:map search-map ("l" . link-hint-open-link)))

Evil 😈 🥰

(use-package evil
  :bind (("C-w" . evil-delete-backward-word))
  :init
  (setopt evil-want-integration t
          evil-ex-substitute-global t
          evil-lookup-func #'helpful-at-point
          evil-shift-round nil
          evil-shift-width 2
          evil-move-beyond-eol t
          evil-cross-lines t
          evil-symbol-word-search t
          evil-want-abbrev-expand-on-insert-exit nil
          evil-undo-system 'undo-redo
          evil-move-cursor-back nil
          evil-want-fine-undo t
          evil-want-keybinding nil)
  (evil-mode)

  (with-eval-after-load 'evil-collection-unimpaired
    (evil-define-key '(normal visual) evil-collection-unimpaired-mode-map
      (kbd "] e") (cmd! () (flymake-goto-next-error current-prefix-arg '(:error)))
      (kbd "[ e") (cmd! () (flymake-goto-prev-error current-prefix-arg '(:error)))))

  :config
  (keymap-global-set "C-j" (cmd! (evil-next-visual-line) (scroll-up 1)))
  (keymap-global-set "C-k" (cmd! (evil-previous-visual-line) (scroll-down 1)))
  
  (set-keymap-parent window-map evil-window-map)
  (keymap-set evil-motion-state-map "C-w" window-map)

  (evil-define-key '(motion visual) 'global
    (kbd "g s s") #'evil-avy-goto-char-timer
    (kbd "g s 2") #'evil-avy-goto-char-2)
  (evil-define-key 'motion 'global
    "j" #'evil-next-visual-line
    "k" #'evil-previous-visual-line)
  (keymap-global-set "M-SPC" leader-map)
  (evil-define-key 'insert 'global
    (kbd "C-v") #'evil-paste-before
    (kbd "M-TAB") #'completion-at-point
    (kbd "C-g") #'evil-normal-state)
  (evil-define-key 'motion 'global
    (kbd "SPC") leader-map
    (kbd "C-u") #'evil-scroll-up
    (kbd "C-t") nil)

  (setmap buffer-map
          "l" #'evil-switch-to-windows-last-buffer
          "D" (defun quit-this-buffer () (interactive) (kill-buffer) (evil-quit))))

Anzu

(use-package evil-anzu
  :after (evil)
  :init
  (global-anzu-mode)
  (require 'evil-anzu))

Exchange

(use-package evil-exchange
  :after evil
  :init
  (evil-exchange-install))

Collection

(use-package evil-collection
  :after evil
  :init
  (evil-collection-init)
  :config
  (evil-define-key 'normal help-mode-map (kbd "SPC") nil))

Multiedit

(use-package evil-multiedit
  :init
  (require 'evil-multiedit)
  (evil-multiedit-default-keybinds))

Surround

(use-package evil-surround
  :after evil
  :init
  (global-evil-surround-mode))

Snipe

(use-package evil-snipe
  :after evil
  :init
  (setopt evil-snipe-spillover-scope 'visible)
  (evil-snipe-mode)
  (evil-snipe-override-mode)
  (add-hook 'magit-mode-hook 'turn-off-evil-snipe-override-mode))

Text objects

Tree-sitter

(use-package evil-textobj-tree-sitter
  :after evil
  :init
  (setmap evil-outer-text-objects-map
          "c" (evil-textobj-tree-sitter-get-textobj "comment.outer"))
  (setmap evil-inner-text-objects-map
          "c" (evil-textobj-tree-sitter-get-textobj "comment.inner")))

Ace

(use-package ace-window
  :custom
  (aw-keys '(?q ?w ?e ?r ?t ?y))
  :bind (:map window-map
         ("w" . ace-window))
  :config
  (when (assoc ?e aw-dispatch-alist)
    (setf (car (assoc ?e aw-dispatch-alist)) ?E))
  (custom-set-faces
   '(aw-leading-char-face ((t (:height 1.0))))))

Completion

Orderless

(use-package orderless
  :init
  (setopt completion-styles '(orderless basic)
          completion-category-defaults nil
          completion-category-overrides '((file (styles partial-completion))))
  :config
  (setopt orderless-component-separator #'orderless-escapable-split-on-space
          orderless-matching-styles '(orderless-initialism
                                      orderless-literal
                                      orderless-regexp)))

Cape

(use-package cape
  :bind (:map mode-specific-map
         ("c p" . completion-at-point) ;; capf
         ("c t" . complete-tag)        ;; etags
         ("c d" . cape-dabbrev)        ;; or dabbrev-completion
         ("c f" . cape-file)
         ("c k" . cape-keyword)
         ("c s" . cape-symbol)
         ("c a" . cape-abbrev)
         ("c l" . cape-line)
         ("c w" . cape-dict)
         ("c \\" . cape-tex)
         ("c &" . cape-sgml)
         ("c r" . cape-rfc1345))
  :config
  (setopt cape-dabbrev-min-length 3
          cape-dict-file
          (mapcar (lambda (s)
                    (expand-file-name (format "dicts/%s" s) user-emacs-directory))
                  '("en-small" "pt-br-small"))
          dabbrev-case-fold-search t
          cape-dabbrev-check-other-buffers t)
  :init
  (advice-add #'comint-completion-at-point :around #'cape-wrap-nonexclusive)
  (advice-add #'eglot-completion-at-point :around #'cape-wrap-nonexclusive)
  (advice-add #'pcomplete-completions-at-point :around #'cape-wrap-nonexclusive)

  (defun +corfu-add-cape-file-h ()
    (add-hook 'completion-at-point-functions #'cape-file -10 t))

  (add-hook 'prog-mode-hook #'+corfu-add-cape-file-h)

  (defun +corfu-add-cape-elisp-block-h ()
    (add-hook 'completion-at-point-functions #'cape-elisp-block 0 t))

  (dolist (h '(org-mode-hook markdown-mode-hook))
    (add-hook h #'+corfu-add-cape-elisp-block-h))

  (with-eval-after-load 'dabbrev
    (setq dabbrev-ignored-buffer-regexps
          '("^ " "\\(TAGS\\|tags\\|ETAGS\\|etags\\|GTAGS\\|GRTAGS\\|GPATH\\)\\(<[0-9]+>\\)?")
          dabbrev-upcase-means-case-search t)
    (add-to-list 'dabbrev-ignored-buffer-modes 'pdf-view-mode))

  (defun +corfu-add-cape-dabbrev-dict-h ()
    (add-hook 'completion-at-point-functions (cape-capf-super #'cape-dabbrev #'cape-dict) 30 t))

  (add-hook 'text-mode-hook #'+corfu-add-cape-dabbrev-dict-h))

The cape-dabbrev backend does not handle casing very well; see my issue here. The following advice makes cape-dabbrev match the case of uppercase words with the case of the completion prefix.

(advice-add #'cape--dabbrev-list :override
  (defun cape--dabbrev-list-ad (input)
    "Find all Dabbrev expansions for INPUT."
    (cape--silent
      (let ((dabbrev-check-other-buffers (not (null cape-dabbrev-check-other-buffers)))
            (dabbrev-check-all-buffers (eq cape-dabbrev-check-other-buffers t)))
        (dabbrev--reset-global-variables))
      (cons
       (apply-partially #'string-prefix-p input)
       (cl-loop with min-len = (+ cape-dabbrev-min-length (length input))
                 with ic = (cape--case-fold-p dabbrev-case-fold-search)
                 for w in (dabbrev--find-all-expansions input ic)
                 if (>= (length w) min-len) collect
                 (let ((dw (if (let (case-fold-search) (not (string-match-p "[[:lower:]]" w)))
                               w (downcase w))))
                  (cape--case-replace (and ic dabbrev-case-replace) input dw)))))))

Consult

(use-package consult
  :ensure (:host github :repo "estradilua/consult" :ref "flymake-better-project")
  :bind (;; C-c bindings in `mode-specific-map'
         ("C-c M-x" . consult-mode-command)
         ("C-c h" . consult-history)
         ("C-c k" . consult-kmacro)
         ("C-c m" . consult-man)
         ("C-c i" . consult-info)
         ([remap Info-search] . consult-info)
         ;; C-x bindings in `ctl-x-map'
         ("C-x M-:" . consult-complex-command)     ;; orig. repeat-complex-command
         ("C-x b" . consult-buffer)                ;; orig. switch-to-buffer
         ("C-x 4 b" . consult-buffer-other-window) ;; orig. switch-to-buffer-other-window
         ("C-x 5 b" . consult-buffer-other-frame)  ;; orig. switch-to-buffer-other-frame
         ("C-x t b" . consult-buffer-other-tab)    ;; orig. switch-to-buffer-other-tab
         ("C-x r b" . consult-bookmark)            ;; orig. bookmark-jump
         ("C-x p b" . consult-project-buffer)      ;; orig. project-switch-to-buffer
         ;; Custom M-# bindings for fast register access
         ("M-#" . consult-register-load)
         ("M-'" . consult-register-store)          ;; orig. abbrev-prefix-mark (unrelated)
         ("C-M-#" . consult-register)
         ;; Other custom bindings
         ("M-y" . consult-yank-pop)                ;; orig. yank-pop
         ;; M-g bindings in `goto-map'
         ("M-g e" . consult-compile-error)
         ("M-g f" . consult-flymake)               ;; Alternative: consult-flycheck
         ("M-g g" . consult-goto-line)             ;; orig. goto-line
         ("M-g M-g" . consult-goto-line)           ;; orig. goto-line
         ("M-g o" . consult-outline)               ;; Alternative: consult-org-heading
         ("M-g m" . consult-mark)
         ("M-g k" . consult-global-mark)
         ;; Isearch integration
         ("M-s e" . consult-isearch-history)
         :map leader-map
         ("," . consult-buffer)
         :map file-map
         ("r" . consult-recent-file)
         :map search-map
         ("d" . consult-find)                  ;; Alternative: consult-fd
         ("c" . consult-locate)
         ("g" . consult-grep)
         ("G" . consult-git-grep)
         ("r" . consult-ripgrep)
         ("s" . consult-line)
         ("S" . consult-line-multi)
         ("k" . consult-keep-lines)
         ("u" . consult-focus-lines)
         ("i" . consult-imenu)
         ("I" . consult-imenu-multi)
         :map code-map
         ("X" . consult-flymake)
         ("x" . (lambda () (interactive) (consult-flymake t)))
         :map isearch-mode-map
         ("M-e" . consult-isearch-history)         ;; orig. isearch-edit-string
         ("M-s e" . consult-isearch-history)       ;; orig. isearch-edit-string
         ("M-s l" . consult-line)                  ;; needed by consult-line to detect isearch
         ("M-s L" . consult-line-multi)            ;; needed by consult-line to detect isearch
         ;; Minibuffer history
         :map minibuffer-local-map
         ("M-s" . consult-history)                 ;; orig. next-matching-history-element
         ("M-r" . consult-history))                ;; orig. previous-matching-history-element

  ;; Enable automatic preview at point in the *Completions* buffer. This is
  ;; relevant when you use the default completion UI.
  :hook (completion-list-mode . consult-preview-at-point-mode)

  ;; The :init configuration is always executed (Not lazy)
  :init
  ;; Optionally configure the register formatting. This improves the register
  ;; preview for `consult-register', `consult-register-load',
  ;; `consult-register-store' and the Emacs built-ins.
  (setq register-preview-delay 0.5
        register-preview-function #'consult-register-format)

  ;; Optionally tweak the register preview window.
  ;; This adds thin lines, sorting and hides the mode line of the window.
  (advice-add #'register-preview :override #'consult-register-window)

  ;; Use Consult to select xref locations with preview
  (setq xref-show-xrefs-function #'consult-xref
        xref-show-definitions-function #'consult-xref)

  ;; Configure other variables and modes in the :config section,
  ;; after lazily loading the package.
  :config

  ;; Optionally configure preview. The default value
  ;; is 'any, such that any key triggers the preview.
  ;; (setq consult-preview-key 'any)
  ;; (setq consult-preview-key "M-.")
  ;; (setq consult-preview-key '("S-<down>" "S-<up>"))
  ;; For some commands and buffer sources it is useful to configure the
  ;; :preview-key on a per-command basis using the `consult-customize' macro.
  (consult-customize
   consult-theme :preview-key '(:debounce 0.2 any)
   consult-ripgrep consult-git-grep consult-grep
   consult-bookmark consult-recent-file consult-xref
   consult--source-bookmark consult--source-file-register
   consult--source-recent-file consult--source-project-recent-file
   ;; :preview-key "M-."
   :preview-key '(:debounce 0.4 any))

  ;; Optionally configure the narrowing key.
  ;; Both < and C-+ work reasonably well.
  (setq consult-narrow-key "<")) ;; "C-+"

  ;; Optionally make narrowing help available in the minibuffer.
  ;; You may want to use `embark-prefix-help-command' or which-key instead.
  ;; (define-key consult-narrow-map (vconcat consult-narrow-key "?") #'consult-narrow-help)

  ;; By default `consult-project-function' uses `project-root' from project.el.
  ;; Optionally configure a different project root function.
  ;;;; 1. project.el (the default)
  ;; (setq consult-project-function #'consult--default-project--function)
  ;;;; 2. vc.el (vc-root-dir)
  ;; (setq consult-project-function (lambda (_) (vc-root-dir)))
  ;;;; 3. locate-dominating-file
  ;; (setq consult-project-function (lambda (_) (locate-dominating-file "." ".git")))
  ;;;; 4. projectile.el (projectile-project-root)
  ;; (autoload 'projectile-project-root "projectile")
  ;; (setq consult-project-function (lambda (_) (projectile-project-root)))
  ;;;; 5. No project support
  ;; (setq consult-project-function nil)

Recoll

(use-package consult-recoll)

File templates

Auto-insert

(use-package autoinsert
  :ensure nil
  :init
  (auto-insert-mode)
  :config
  (setopt auto-insert-directory
          (expand-file-name "auto-insert/" user-emacs-directory)))

Gitignore

(use-package gitignore-templates)

Licenses

(use-package license-templates)

AI

GPTel

(use-package gptel
  :config
  (setopt gptel-api-key #'gptel-api-key-from-auth-source)

  (gptel-make-anthropic "Claude"
    :stream t
    :key #'gptel-api-key-from-auth-source)
  (gptel-make-deepseek "DeepSeek"
    :stream t
    :key #'gptel-api-key-from-auth-source))
(use-package gptel-quick
  :ensure (:host github :repo "karthink/gptel-quick"))

Minuet

(use-package minuet
  :config
  (setopt minuet-provider 'openai-fim-compatible)
  (plist-put minuet-openai-fim-compatible-options :api-key
             (lambda () (api-key-from-auth-source "api.deepseek.com")))
  (plist-put minuet-claude-options :api-key
             (lambda () (api-key-from-auth-source "api.anthropic.com"))))

Copilot

(use-package copilot
  :bind (:map copilot-completion-map
              ("<tab>" . copilot-accept-completion-by-word)
              ("TAB" . copilot-accept-completion-by-word)
              ("<backtab>" . copilot-accept-completion)))

Whisper (speech-to-text)

(use-package whisper
  :ensure (:host github :repo "natrys/whisper.el")
  :custom
  (whisper-install-directory "~/dados/Applications/")
  (whisper-model "small")
  (whisper-language "auto")
  :bind (:map text-mode-map
              ("M-s" . whisper-run)))

Marginalia

(use-package marginalia
  :bind (:map minibuffer-mode-map
            ("M-A" . marginalia-cycle))
  :init
  (marginalia-mode))

Nerd-icons

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

Templates

Tempel

(use-package tempel
  :ensure (:repo "git@github.com:lucasvreis/tempel.git")
  :bind (("M-+" . tempel-complete) ;; Alternative tempel-expand
         ("M-*" . tempel-insert))
  :init
  (advice-add #'tempel-next :after
    (defun tempel-next-ad (arg)
      "Move ARG fields forward and REALLY quit at the end."
      (unless (tempel--find arg)
        (tempel-done))))
  
  ;; Setup completion at point
  (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 you
    ;; should also configure `tempel-trigger-prefix', such that Tempel
    ;; does not 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.
    (add-hook 'completion-at-point-functions #'tempel-expand 20 t))

  (add-hook 'conf-mode-hook 'tempel-setup-capf)
  (add-hook 'prog-mode-hook 'tempel-setup-capf)
  (add-hook 'text-mode-hook 'tempel-setup-capf)
  :config
  (setmap tempel-map
          "TAB" #'tempel-next
          "<backtab>" #'tempel-previous
          "M-d" (cmd! (tempel-kill) (tempel-next 1))))

AAS

(use-package aas)

Some monkey patching to keep the order of hooks reasonable. Otherwise there is a huge mess with smartparens.

(with-eval-after-load 'aas
  (define-minor-mode aas-mode
    "Minor mode for dynamically auto-expanding snippets.

This does not set any default keymaps. For that use
`aas-activate-for-major-mode' and `aas-activate-keymap'."
    :init-value nil
    :group 'aas
    (if aas-mode
        (add-hook 'post-self-insert-hook #'aas-post-self-insert-hook 90 t)
      (remove-hook 'post-self-insert-hook #'aas-post-self-insert-hook t))))

UIs

Vertico

Config

(use-package vertico
  :init
  (vertico-mode)
  :config
  (setopt vertico-resize nil
          vertico-count 8)
  (vertico-mouse-mode)
  (vertico-multiform-mode)
  (add-to-list 'vertico-multiform-categories '(embark-keybinding grid)))

(add-hook 'minibuffer-setup-hook #'cursor-intangible-mode)
(setopt minibuffer-prompt-properties
        '(read-only t cursor-intangible t face minibuffer-prompt)
        enable-recursive-minibuffers t
        read-extended-command-predicate #'command-completion-default-include-p)

Extensions

Directory
(use-package vertico-directory
  :after vertico
  :ensure nil
  ;; More convenient directory navigation commands
  :bind (:map vertico-map
              ("RET" . vertico-directory-enter)
              ("DEL" . vertico-directory-delete-char)
              ("M-DEL" . vertico-directory-delete-word))
  ;; Tidy shadowed file names
  :hook (rfn-eshadow-update-overlay . vertico-directory-tidy))
Repeat
(use-package vertico-repeat
  :after vertico
  :ensure nil
  :bind (("M-R" . vertico-repeat)
         :map vertico-map
              ("M-P" . vertico-repeat-previous)
              ("M-N" . vertico-repeat-next)
              ("S-<prior>" . vertico-repeat-previous)
              ("S-<next>" . vertico-repeat-next))
  :hook (minibuffer-setup . vertico-repeat-save))

Corfu

(use-package corfu
  :init
  (defun corfu-enable-in-minibuffer ()
    "Enable Corfu in the minibuffer."
    (when (local-variable-p 'completion-at-point-functions)
      ;; (setq-local corfu-auto nil) ;; Enable/disable auto completion
      (setq-local corfu-echo-delay nil ;; Disable automatic echo and popup
                  corfu-popupinfo-delay nil)
      (corfu-mode)))
  (remove-hook 'minibuffer-setup-hook #'corfu-enable-in-minibuffer)
  (global-corfu-mode)
  :custom-face (corfu-default ((t (:inherit fixed-pitch))))
  :bind (:map corfu-map
         ("<remap> <completion-at-point>" . corfu-complete)
         ("TAB" . corfu-next)
         ("<backtab>" . corfu-previous)
         ("C-<tab>" . corfu-expand)
         ("\\" . corfu-quit)
         ("M-s" . corfu-insert-separator)
         :map evil-insert-state-map
         ("C-<tab>" . completion-at-point))
  :config
  (setopt corfu-cycle t
          corfu-preselect 'directory
          corfu-auto nil
          corfu-auto-prefix 3
          corfu-count 16
          corfu-auto-delay 0.4
          corfu-max-width 120
          corfu-on-exact-match 'insert
          corfu-preview-current 'insert
          global-corfu-minibuffer t
          tab-always-indent t)
  (add-hook 'evil-insert-state-exit-hook #'corfu-quit)
  ;; In case you ever get `args-out-of-range 0 0' errors when using
  ;; Corfu with Eglot, try setting this. It is also related to ``:exlusive 'no''.
  (add-to-list 'completion-category-overrides `(eglot-capf (styles ,@completion-styles)))

  ;; Per-mode settings)
  (require 'mode-local)
  (setq-mode-local prog-mode
                   corfu-auto-prefix 2
                   corfu-auto-delay 0))
(advice-add #'corfu--make-buffer :filter-return
  (defun corfu-no-line-spacing-ad (buffer)
    (with-current-buffer buffer
      (setq-local line-spacing 0)
      buffer)))

Extensions

History
(use-package corfu-history
  :ensure nil
  :after (savehist corfu)
  :hook ((corfu-mode . corfu-history-mode))
  :config
  (add-to-list 'savehist-additional-variables 'corfu-history))
Popupinfo
(use-package corfu-popupinfo
  :ensure nil
  :after corfu
  :hook ((corfu-mode . corfu-popupinfo-mode))
  :config
  (setopt corfu-popupinfo-delay '(0 . 1.0)))
Kind-icon
(use-package kind-icon
  :after corfu
  :init
  (add-to-list 'corfu-margin-formatters #'kind-icon-margin-formatter)
  :config
  (setopt kind-icon-default-face 'corfu-default
          kind-icon-blend-background t
          kind-icon-default-style '(:padding 0
                                    :stroke 0
                                    :margin 0
                                    :radius 0
                                    :height 0.8
                                    :scale 1.0))
  (add-hook 'after-enable-theme-hook #'kind-icon-reset-cache))

Embark

(use-package embark
  :bind (("C-;" . embark-act)
         ("C-:" . embark-dwim)
         ([remap describe-bindings] . embark-bindings)
         :map embark-file-map
         ("C" . copy-directory))
  :init
  (setq which-key-use-C-h-commands nil
        prefix-help-command #'embark-prefix-help-command)
  :config

  (defun embark-which-key-indicator ()
   "An embark indicator that displays keymaps using which-key.
The which-key help message will show the type and value of the
current target followed by an ellipsis if there are further
targets."
   (lambda (&optional keymap targets prefix)
     (if (null keymap)
         (which-key--hide-popup-ignore-command)
       (which-key--show-keymap
        (if (eq (plist-get (car targets) :type) 'embark-become)
            "Become"
          (format "Act on %s '%s'%s"
                  (plist-get (car targets) :type)
                  (embark--truncate-target (plist-get (car targets) :target))
                  (if (cdr targets) "" "")))
        (if prefix
            (pcase (lookup-key keymap prefix 'accept-default)
              ((and (pred keymapp) km) km)
              (_ (key-binding prefix 'accept-default)))
          keymap)
        nil nil t (lambda (binding)
                    (not (string-suffix-p "-argument" (cdr binding))))))))

  (setopt embark-indicators '(embark-highlight-indicator
                              embark-isearch-highlight-indicator))
  
  (add-to-list 'display-buffer-alist
             '("\\`\\*Embark Collect \\(Live\\|Completions\\)\\*"
               nil
               (window-parameters (mode-line-format . none)))))

(use-package embark-consult
  :bind (:map embark-consult-search-map
              ("s" . consult-line)
              ("S" . consult-line-multi))
  :hook (embark-collect-mode . consult-preview-at-point-mode))

Which-key indicator

(with-eval-after-load 'embark
  (when (require 'which-key nil t)
    (defun embark-which-key-indicator ()
     "An embark indicator that displays keymaps using which-key.
The which-key help message will show the type and value of the
current target followed by an ellipsis if there are further
targets."
     (lambda (&optional keymap targets prefix)
       (if (null keymap)
           (which-key--hide-popup-ignore-command)
         (which-key--show-keymap
          (if (eq (plist-get (car targets) :type) 'embark-become)
              "Become"
            (format "Act on %s '%s'%s"
                    (plist-get (car targets) :type)
                    (embark--truncate-target (plist-get (car targets) :target))
                    (if (cdr targets) "" "")))
          (if prefix
              (pcase (lookup-key keymap prefix 'accept-default)
                ((and (pred keymapp) km) km)
                (_ (key-binding prefix 'accept-default)))
            keymap)
          nil nil t (lambda (binding)
                      (not (string-suffix-p "-argument" (cdr binding))))))))

   (setq embark-indicators
     '(embark-which-key-indicator
       embark-highlight-indicator
       embark-isearch-highlight-indicator))

   (defun embark-hide-which-key-indicator (fn &rest args)
     "Hide the which-key indicator immediately when using the completing-read prompter."
     (which-key--hide-popup-ignore-command)
     (let ((embark-indicators
            (remq #'embark-which-key-indicator embark-indicators)))
         (apply fn args)))

   (advice-add #'embark-completing-read-prompter
               :around #'embark-hide-which-key-indicator)))

Functionality

Buffer management

IBuffer

Let’s group by projects using a handy package.

(use-package ibuffer-project
  :init
  (add-hook
    'ibuffer-hook
    (lambda ()
      (setq ibuffer-filter-groups (ibuffer-project-generate-filter-groups))
      (unless (eq ibuffer-sorting-mode 'project-file-relative)
        (ibuffer-do-sort-by-project-file-relative)))))

Bufferfile

(use-package bufferfile
  :bind (:map file-map
              ("c" . bufferfile-copy)
              ("d" . bufferfile-delete)))
              ;; NB: bufferfile-rename prompt is bad. `rename-visited-file' does the right thing.
              ;; ("m" . bufferfile-rename)))

Change-case

(use-package change-case
  :ensure (:host github :repo "TakesxiSximada/change-case.el"))

Custom

(setopt custom-file "/dev/null")

Add a hook after theme changes.

(use-package custom
  :ensure nil
  :init
  (defvar after-enable-theme-hook nil)
  (defun run-after-enable-theme-hook (&rest _args)
    (run-hooks 'after-enable-theme-hook))
  (advice-add 'enable-theme :after #'run-after-enable-theme-hook))

Eglot

(use-package eglot
  :ensure (:repo "~/dados/projetos/codigo/emacs/emacs/lisp/progmodes/"
           :files ("eglot.el"))
  :custom-face
  (eglot-diagnostic-tag-unnecessary-face ((t (:inherit shadow))))
  (eglot-inlay-hint-face ((t (:height unspecified :inherit shadow))))
  (eglot-code-action-indicator-face ((t (:weight bold :inherit (font-lock-escape-face default)))))
  :custom
  (eglot-code-action-indicator "")
  (eglot-autoshutdown t)
  (eglot-send-changes-idle-time 0.2)
  (eglot-advertise-cancellation t)
  (eglot-confirm-server-edits '((eglot-rename) (t . maybe-summary)))
  (eglot-events-buffer-config '(:size 0 :format short))
  (eglot-ignored-server-capabilities '(:inlayHintProvider))
  :config
  (add-to-list 'eglot-server-programs
               (cons '(latex-mode plain-tex-mode context-mode bibtex-mode tex-mode)
                     '("texlab")))
  (modal-setmap eglot-mode-map code-map
                "a" #'eglot-code-actions
                "f" #'eglot-format
                "I" #'consult-eglot-symbols
                "r" #'eglot-rename)

  (advice-add 'eglot--format-markup :around
              (defun eglot--format-markup-ad (fn markup &optional mode)
                (let ((markdown-fontify-code-block-default-mode (or mode major-mode)))
                  (apply fn markup mode))))
  (require 'markdown-mode))

Consult integration

(use-package consult-eglot)

(use-package consult-eglot-embark
  :after eglot
  :init
  (consult-eglot-embark-mode))

Booster 🚀

(use-package eglot-booster
  :ensure (:host github :repo "jdtsmith/eglot-booster")
  :after eglot
  :init
  (eglot-booster-mode))

Errors, linting

Flymake

(with-eval-after-load 'flymake
  (setopt flymake-indicator-type 'margins)
  (setopt flymake-margin-indicators-string
          '((error "" compilation-error)
            (warning "!" compilation-warning)
            (note "!" success))
          flymake-diagnostic-format-alist
          '((:help-echo origin code message) (:eol oneliner) (:eldoc origin code message)
            (:eldoc-echo origin code oneliner) (t origin code oneliner)))
  (custom-set-faces
   '(flymake-error-echo ((t (:inherit (error fixed-pitch)))))
   '(flymake-note-echo ((t (:inherit (success fixed-pitch)))))
   '(flymake-warning-echo ((t (:inherit (warning fixed-pitch)))))))

(with-eval-after-load 'flymake-proc
  (remove-hook 'flymake-diagnostic-functions 'flymake-proc-legacy-flymake))

Sideline

(use-package sideline
  :custom-face
  (sideline-default ((t (:inherit fixed-pitch))))
  :config
  (setopt sideline-delay 0.2))
(use-package sideline-flymake
  :hook (flymake-mode . sideline-mode)
  :custom-face
  (sideline-flymake-error ((t (:height 0.85 :inherit (error fixed-pitch)))))
  (sideline-flymake-note ((t (:height 0.85 :inherit (success fixed-pitch)))))
  (sideline-flymake-warning ((t (:height 0.85 :inherit (warning fixed-pitch)))))
  (sideline-flymake-success ((t (:height 0.85 :inherit (success fixed-pitch)))))
  :init
  (setq sideline-flymake-display-mode 'point)
  (setq sideline-backends-right '(sideline-flymake)))

  ;; (advice-add 'elisp-flymake-byte-compile :after #'sideline-render-this))

Eldoc

(use-package eldoc
  :ensure nil
  :config
  (make-variable-buffer-local 'eldoc-last-message)
  (add-hook 'eldoc-mode-hook
            (defun eldoc/fix-hooks ()
              (if eldoc-mode
                  (progn
                    (remove-hook 'pre-command-hook #'eldoc-pre-command-refresh-echo-area t)
                    (add-hook 'post-command-hook #'eldoc-pre-command-refresh-echo-area nil t))
                (remove-hook 'post-command-hook #'eldoc-pre-command-refresh-echo-area t))))
  (setopt eldoc-echo-area-use-multiline-p 'truncate-sym-name-if-fit
          eldoc-help-at-pt t
          eldoc-idle-delay 0.1))

Eldoc-box

(use-package eldoc-box
  :after eldoc
  :custom-face 
  (eldoc-box-body ((t (:height 1.0 :weight normal :inherit (variable-pitch corfu-default)))))
  (eldoc-box-border ((t (:background unspecified :inherit corfu-border))))
  (eldoc-box-markdown-separator
   ((t :height 0.5
       :underline (:color foreground-color :style wave :position nil)
       :strike-through unspecified
       :inherit shadow)))
  :init
  (with-eval-after-load 'eglot
    (evil-define-key 'normal eglot-mode-map
      "K" #'eldoc-box-help-at-point))
  :config
  (setopt eldoc-box-max-pixel-height 400)
  (setcdr (assoc 'internal-border-width eldoc-box-frame-parameters) 1)
  (setcdr (assoc 'left-fringe eldoc-box-frame-parameters)  5)
  (setcdr (assoc 'right-fringe eldoc-box-frame-parameters) 5)

  (defun eldoc-box-better-at-point-position-function (width height)
    "See `eldoc-box--default-at-point-position-function' for WIDTH & HEIGHT docs."
    (let* ((pos (posn-x-y (posn-at-point)))
           (edge (window-inside-pixel-edges))
           ;; calculate point coordinate relative to native frame
           ;; because childframe coordinate is relative to native frame
           (x (+ (car edge) (car pos)))
           (y (+ (cadr edge) (window-tab-line-height) (cdr pos)))
           (em (default-line-height)))
      (cons (if (< (- (frame-inner-width) width) x)
                ;; space on the right of the pos is not enough
                ;; put to left
                (max 0 (- x width))
              ;; normal, just return x
              x)
            (if (< (- (frame-inner-height) height) y)
                ;; space under the pos is not enough
                ;; put above
                (max 0 (- y height))
              ;; normal, just return y + em
              (+ y em)))))
  (setopt eldoc-box-at-point-position-function #'eldoc-box-better-at-point-position-function))

GIF Screencast

(use-package gif-screencast
  :bind (:map gif-screencast-mode-map
              ("C-c C-s" . gif-screencast-stop))
  :config
  (setopt gif-screencast-program "grim"
          gif-screencast-convert-program "magick"
          gif-screencast-convert-args '("-delay" "100" "-loop" "0" "-dither" "None" "-fuzz" "40%")
          gif-screencast-capture-prefer-internal nil
          gif-screencast-args '()))

Helpful

(use-package helpful
  :hook (helpful-mode . (lambda () (setq truncate-lines t)))
  :bind (("C-h f" . #'helpful-callable)
         ("C-h F" . #'helpful-function)
         ("C-h v" . #'helpful-variable)
         ("C-h k" . #'helpful-key)
         ("C-h x" . #'helpful-command)
         ("C-h '" . #'helpful-at-point)
         ("C-h m" . #'helpful-macro)))

(with-eval-after-load 'embark
  (setmap embark-symbol-map "h" #'helpful-symbol))

Idiosyncrasy

(setopt indent-tabs-mode nil
        user-full-name "Lua Viana Reis"
        user-mail-address "me@lua.blog.br"
        trusted-content '("~/dados/projetos/" "~/dados/arquivo/")
        inhibit-startup-screen t
        frame-resize-pixelwise t
        vc-follow-symlinks t
        recenter-redisplay nil
        scroll-conservatively 0
        backup-inhibited t
        switch-to-buffer-obey-display-actions t
        confirm-kill-emacs #'y-or-n-p
        use-dialog-box nil
        standard-indent 2
        ring-bell-function #'ignore
        kill-buffer-quit-windows t
        text-scale-mode-step 1.05
        revert-without-query '(".")
        display-line-numbers-width-start t
        use-short-answers t
        auto-save-file-name-transforms
        `(("\\`/\\([^/]*[/:]\\)*\\([^/]*\\)\\'" ,(concat user-emacs-directory "auto-save-list/\\2") t))
        create-lockfiles nil
        ;; what the fuck, emacs!
        sentence-end-double-space nil
        auth-sources `(,(expand-file-name "authinfo.gpg" user-emacs-directory)))

(column-number-mode)
(undelete-frame-mode)
(defun display-startup-echo-area-message ())

Magit

(use-package magit
  :ensure (:source "NonGNU ELPA")
  :config
  (setopt magit-display-buffer-function #'magit-display-buffer-fullframe-status-v1
          magit-bury-buffer-function #'magit-restore-window-configuration))

(use-package transient
  :ensure (:source "NonGNU ELPA"))

Let’s add some keys to it.

(use-package magit
  :ensure nil
  :init
  (defvar-keymap git-map :doc "Actions related to Git.")
  (keymap-set leader-map "g" (cons "Git" git-map))
  :bind
  (:map git-map
        ("g" . magit)
        ("G" . magit-status-here)
        ("S" . magit-stage)
        ("u" . magit-unstage)
        ("c c" . magit-commit-create)
        ("c a" . magit-commit-amend)
        ("c f" . magit-commit-fixup)
        ("p" . magit-push)
        ("l" . magit-log)))

Todos

(use-package hl-todo
  :ensure (:tag "v3.7.0"))

(use-package magit-todos
  :after magit
  :init
  (magit-todos-mode)
  :config
  (setopt magit-todos-exclude-globs
          '(".git/" "**/elpaca/")))

Forge

(use-package forge)

Gutter (diff-hl)

(use-package diff-hl
  :hook ((prog-mode conf-mode text-mode) . diff-hl-mode)
  :commands (diff-hl-stage-dwim)
  :init
  (setmap git-map
          "s" (cons "Stage hunk" #'diff-hl-stage-dwim)
          "r" (cons "Revert hunk" #'diff-hl-revert-hunk)
          "h" (cons "Show hunk" #'diff-hl-show-hunk))
  :config
  (setopt diff-hl-show-staged-changes nil
          diff-hl-draw-borders nil
          diff-hl-update-async t
          diff-hl-fringe-bmp-function #'diff-hl-fringe-bmp-from-pos
          diff-hl-margin-symbols-alist
            '((insert . " ") (delete . " ") (change . " ")
              (unknown . " ") (ignored . " ")))
  (diff-hl-flydiff-mode))

Persistence

Savehist

(use-package savehist
  :ensure nil
  :hook (after-init . savehist-mode)
  :config
  (add-to-list 'savehist-additional-variables 'custom-enabled-themes)
  (add-to-list 'savehist-additional-variables 'register-alist)
  (add-hook 'elpaca-after-init-hook
            (defun savehist-apply-theme-h ()
              (dolist (theme custom-enabled-themes)
                (load-theme theme :no-confirm)))))

Desktop

(add-hook 'elpaca-after-init-hook
  (defun enable-desktop-save-h ()
    (desktop-read)
    (desktop-save-mode))
  99)

Tab-bookmark

(use-package tab-bookmark
  :ensure (:repo "https://github.com/minad/tab-bookmark.git"))

Save-place

(with-eval-after-load 'emacs
  (save-place-mode))

Projects

(use-package project
  :ensure nil
  :init
  (require 'project)
  :config
  (defun project-remember-and-open (dir &optional dont-open)
    (interactive "DDirectory: \nP")
    (project--ensure-read-project-list)
    (if-let* ((project (project--find-in-directory dir)))
        (progn (project-remember-project project)
               (message "Found %s..." (project-root project))
               (unless dont-open
                 (project-switch-project (project-root project))))
      (message "No projects were found")))
  (setmap project-prefix-map
          "a" #'project-remember-and-open 
          "A" #'project-remember-projects-under
          "d" #'project-forget-project
          "D" #'project-forget-projects-under)
  (set-keymap-parent project-map project-prefix-map)
  (keymap-set leader-map "SPC" #'project-find-file)
  (setopt project-switch-commands #'project-find-file
          project-prompter #'project-prompt-project-dir
          project-vc-extra-root-markers '("latexmkrc" "package.json")))

EPX (shell commands)

(use-package epx
  :after project
  :bind
  (:map project-map
        ("e e" . #'epx-run-command-in-shell)
        ("e c" . #'epx-add-command)
        ("e d" . #'epx-remove-command))
  :init
  (put 'epx-commands 'safe-local-variable (lambda (_) t)))

Workaround to bad VC cache management

(defun clear-vc-obarray-cache ()
  (interactive)
  (setq vc-file-prop-obarray (obarray-make)))

Monkey patch

fixes read function when project directory listing is empty

(with-eval-after-load 'project
  (defun project--read-file-cpd-relative (prompt
                                          all-files &optional predicate
                                          hist mb-default)
    "Read a file name, prompting with PROMPT.
ALL-FILES is a list of possible file name completions.

PREDICATE and HIST have the same meaning as in `completing-read'.

MB-DEFAULT is used as part of \"future history\", to be inserted
by the user at will."
    (let* ((common-parent-directory
            (let ((common-prefix (try-completion "" all-files)))
              (if (> (length common-prefix) 0)
                  (file-name-directory common-prefix))))
           (cpd-length (length common-parent-directory))
           (common-parent-directory (if (and (car all-files)
                                             (file-name-absolute-p (car all-files)))
                                        common-parent-directory
                                      (concat default-directory common-parent-directory)))
           (prompt (if (and (zerop cpd-length)
                            all-files
                            (file-name-absolute-p (car all-files)))
                       prompt
                     (concat prompt (format " in %s" common-parent-directory))))
           (substrings (mapcar (lambda (s) (substring s cpd-length)) all-files))
           (new-collection (project--file-completion-table substrings))
           (relname (project--completing-read-strict prompt
                                                     new-collection
                                                     predicate
                                                     hist mb-default
                                                     (unless (equal common-parent-directory "")
                                                       common-parent-directory)))
           (absname (expand-file-name relname common-parent-directory)))
      absname)))

Recentf

(use-package recentf
  :ensure nil
  :hook (after-init . recentf-mode))

Scrolling

Recenter after a long scroll

Thank you so much, https://emacs.stackexchange.com/a/55478!

(add-hook 'window-scroll-functions
          (defun window-scroll-functions/recenter-after-jump (window new-win-start)
            (with-selected-window window
              (let* ((new-start-line (line-number-at-pos new-win-start))
                     (old-start-line (or (bound-and-true-p last-start-line-memo)
                                         (line-number-at-pos (point))))
                     (distance (abs (- old-start-line new-start-line))))
                (when (and (> distance 5)
                           (not (memq last-command '(next-line
                                                     recenter-top-bottom)))
                           (not (and (symbolp last-command)
                                     (get last-command 'scroll-command))))
                  (recenter))
                (setq-local last-start-line-memo new-start-line)))))

Fast and good scrolling

(setopt pixel-scroll-precision-interpolation-factor 0.1
        pixel-scroll-precision-interpolate-mice t
        pixel-scroll-precision-interpolate-page t
        pixel-scroll-precision-interpolation-total-time 0.15)
(use-package ultra-scroll
  :ensure (:repo "https://github.com/jdtsmith/ultra-scroll")
  :init
  (ultra-scroll-mode)
  :custom
  (auto-window-vscroll nil)            ; Don't adjust window-vscroll for tall lines
  (next-screen-context-lines 4)        ; Preserve this many lines when jumping a screenful
  (scroll-margin 0)                    ; Scroll when cursor is this many lines to screen edge
  (scroll-conservatively 101)          ; Only 'jump' when moving this far off the screen
  (scroll-preserve-screen-position t)) ; Preserve line/column (nicer M-v, C-v, etc.)

Server

(use-package server
  :ensure nil
  :init
  (server-force-delete)
  (server-start nil t))

Spelling (jinx)

(use-package jinx
  :hook (text-mode conf-mode)
  :config
  (setq jinx-languages "pt_BR en_US")
  (cl-pushnew 'font-lock-constant-face (alist-get 'tex-mode jinx-exclude-faces))
  (cl-pushnew 'markdown-math-face (alist-get 'markdown-mode jinx-exclude-faces))
  (cl-pushnew 'markdown-ts-code-block (alist-get 'markdown-ts-mode jinx-exclude-faces))
  (define-key evil-visual-state-map "z=" 'jinx-correct)
  (define-key evil-normal-state-map "z=" 'jinx-correct))

Let’s also add a dir-local saving option.

(with-eval-after-load 'jinx
  (defun jinx--save-dir (save key word)
    "Save WORD in dir-local variable.
If SAVE is non-nil save, otherwise format candidate given action KEY."
    (if save
        (progn
          (jinx--add-local-word 'jinx-dir-local-words word)
          (save-excursion
            (modify-dir-local-variable nil 'jinx-dir-local-words jinx-dir-local-words 'add-or-replace)
            (save-buffer)
            (kill-buffer)))
      (list key word "Directory")))
  (add-to-list 'jinx--save-keys '(?/ . jinx--save-dir)))

Stupidity

Elcord

(use-package elcord
  :config
  (setopt elcord-use-major-mode-as-main-icon t
          elcord-idle-message "cat is sleeping on the keyboard")
  (add-to-list 'elcord-mode-icon-alist '(LaTeX-mode . "latex-mode_icon"))
  (add-to-list 'elcord-mode-icon-alist '(haskell-ts-mode . "haskell-mode_icon")))

Tabs

(use-package nerd-icons
  :config
  (setopt tab-bar-back-button "<"
          tab-bar-forward-button ">"))
          ;; (nerd-icons-octicon "nf-oct-chevron_left")
          ;; (nerd-icons-octicon "nf-oct-chevron_right")))

(use-package tab-bar
  :ensure nil
  :custom-face
  (tab-bar ((t (:height 0.9))))
  (tab-bar-tab-group-inactive ((t (:box nil))))
  (tab-bar-tab-group-current ((t (:slant italic :weight normal :box nil))))
  :bind (:map tab-prefix-map
              ("<left>" . tab-bar-history-back)
              ("h" . tab-bar-history-back)
              ("<right>" . tab-bar-history-forward)
              ("l" . tab-bar-history-forward))
  :init
  (tab-bar-mode)
  (cl-loop for i from 1 to 9 do
           (keymap-global-set (format "M-%s" i) `(lambda () (interactive) (tab-select ,i))))
  (tab-bar-history-mode) 
  :config
  (setopt tab-bar-close-button-show nil
          tab-bar-new-button "+"
          tab-bar-tab-group-format-function
          (lambda (tab i &optional p)
            (propertize
             (concat " " (tab-bar-tab-group-format-default tab i p) " ")
             'face (if p 'tab-bar-tab-group-current 'tab-bar-tab-group-inactive)))
          tab-bar-tab-name-format-function
          (lambda (tab i)
            (propertize
             (concat " " (tab-bar-tab-name-format-default tab i) " ")
             'face (funcall tab-bar-tab-face-function tab)))
          tab-bar-format '(tab-bar-format-history
                           tab-bar-format-tabs-groups
                           tab-bar-separator
                           tab-bar-format-add-tab)
          tab-bar-tab-hints nil
          tab-bar-new-tab-choice #'get-scratch-buffer-create))

(use-package tab-line
  :ensure nil
  :custom-face
  (tab-line ((t (:height 0.9))))
  :custom
  (tab-line-close-tab-function 'kill-buffer))

Terminal (eat)

(use-package eat
  :init
  (setmap open-map
          "T" (cons "Terminal" #'eat-other-window)
          "t" (cons "Terminal (project)" #'eat-project-other-window))
  :config
  (setq eat-kill-buffer-on-exit t
        eat-shell "zsh"))

Guess standard-indent

(use-package dtrt-indent
  :hook (prog-mode . dtrt-indent-mode))

Text wrapping

(use-package adaptive-wrap
  :hook ((text-mode prog-mode) . adaptive-wrap-prefix-mode)
  :config
  (add-hook 'adaptive-wrap-prefix-mode-hook
            (defun adaptive-wrap/disable-on-org-indent ()
              (when (and adaptive-wrap-prefix-mode
                         (bound-and-true-p org-indent-mode))
                (adaptive-wrap-prefix-mode -1)))))

Tramp

(setq tramp-default-method "ssh")
(advice-add #'completion-file-name-table :around
            (defun completion-file-name-table-ad (fn str pred action)
              (let ((pred (if (eq pred 'file-directory-p)
                              (lambda (s)
                                (let ((len (length s)))
                                  (and (> len 0) (memq (aref s (1- len)) '(?/ ?: ?@)))))
                            pred)))
                (funcall fn str pred action))))

Treemacs

(use-package treemacs
  :bind (:map toggle-map
              ("p" . treemacs))
  :custom-face
  (treemacs-window-background-face ((t :inherit corfu-default)))
  (treemacs-file-face ((t :inherit variable-pitch)))
  (treemacs-directory-face ((t :inherit (variable-pitch font-lock-function-name-face))))
  (treemacs-git-untracked-face ((t :inherit (variable-pitch font-lock-string-face))))
  (treemacs-git-added-face ((t :inherit (variable-pitch font-lock-type-face))))
  (treemacs-git-ignored-face ((t :inherit (variable-pitch font-lock-comment-face))))
  (treemacs-git-modified-face ((t :inherit (variable-pitch font-lock-variable-name-face))))
  :config
  (setopt treemacs-position 'left
          treemacs-width 35)
  (treemacs-project-follow-mode))

(use-package treemacs-evil
  :after (treemacs evil)
  :demand t)

(use-package treemacs-nerd-icons
  :after (treemacs)
  :demand t
  :config
  (treemacs-load-theme "nerd-icons"))

(use-package treemacs-tab-bar ;;treemacs-tab-bar if you use tab-bar-mode
  :after (treemacs)
  :demand t
  :config
  (treemacs-set-scope-type 'Tabs))

Tree-sitter

Builtin (treesit)

(use-package treesit
  :ensure nil
  :config
  (setopt treesit-language-source-alist
          '((haskell "https://github.com/tree-sitter/tree-sitter-haskell.git")
            (html "https://github.com/tree-sitter-grammars/tree-sitter-html")
            (kdl "https://github.com/tree-sitter-grammars/tree-sitter-kdl.git")
            (lean "~/dados/projetos/codigo/emacs/tree-sitter-lean/")
            (markdown "https://github.com/tree-sitter-grammars/tree-sitter-markdown" nil "tree-sitter-markdown/src")
            (markdown-inline "https://github.com/tree-sitter-grammars/tree-sitter-markdown" nil "tree-sitter-markdown-inline/src")
            (qmljs "https://github.com/yuja/tree-sitter-qmljs")
            (rust "https://github.com/tree-sitter/tree-sitter-rust.git")
            (toml "https://github.com/tree-sitter-grammars/tree-sitter-toml")
            (tsx "https://github.com/tree-sitter/tree-sitter-typescript.git" nil "tsx/src")
            (typescript "https://github.com/tree-sitter/tree-sitter-typescript.git" nil "typescript/src")
            (typst "https://github.com/uben0/tree-sitter-typst")
            (yaml "https://github.com/tree-sitter-grammars/tree-sitter-yaml"))))

Highlight

(use-package ts-query-highlight
  :ensure (:repo "https://git.sr.ht/~meow_king/ts-query-highlight"))

Expreg

(use-package expreg
  :bind (("M-r" . expreg-expand)
         ("C-M-r" . expreg-contract)))

Windows

Transpose-frame

(use-package transpose-frame
  :init
  (setmap window-map
          "C-r" #'rotate-frame-clockwise
          "C-R" #'rotate-frame-anticlockwise
          "C-t" #'transpose-frame))

Popper

(use-package popper
  :bind (("C-,"   . popper-toggle)
         ("M-,"   . popper-cycle)
         ("C-M-," . popper-toggle-type))
  :init
  (setopt popper-reference-buffers
          `("\\*Messages\\*"
            "\\*Warnings\\*"
            "\\*eldoc\\*"
            "\\*Async Shell Command\\*"
            "\\*eat\\*" eat-mode
            "\\*ChatGPT\\*"
            ;; "\\*scratch\\*"
            help-mode
            helpful-mode
            compilation-mode
            comint-mode
            shell-mode
            ,(buffer-fp-match! "/\\.lake/packages/"))
          popper-mode-line '(:eval (propertize " P " 'face 'mode-line-emphasis))
          popper-group-function nil
          popper-display-control 'user)
  (popper-mode))
  • [ ] Write a proper popper-group-function.
  • [ ] Write a consult backend
(defvar consult-popper-buffer-history nil)

(defun consult-popper--buffers ()
  (let (out)
    (dolist (g popper-buried-popup-alist)
      (dolist (b (cdr g))
        (when (buffer-live-p (cdr b))
          (push (consult--buffer-pair (cdr b)) out))))
    (dolist (b popper-open-popup-alist)
      (push (consult--buffer-pair (cdr b)) out))
    out))

(defvar consult-popper-buffer-source
  `( :name "Popper buffers"
     :narrow ?,
     :hidden t
     :category buffer
     :default t
     :face consult-buffer
     :history consult-popper-buffer-history
     :action ,#'switch-to-buffer
     :items ,#'consult-popper--buffers)
  "Source for `consult-buffer' to list Denote buffers.")

(with-eval-after-load 'consult
  (add-to-list 'consult-buffer-sources 'consult-popper-buffer-source 'append))

Shackle

(use-package shackle
  :init
  (shackle-mode)
  :config
  (setopt shackle-rules `((("^\\*.*shell\\*$" compilation-mode)
                           :regexp t :popup t :align 'below :size 0.4 :select t))))

(defun display-buffer-pred-window (buf alist)
  (let ((win (cl-find-if (cdr (assq 'pred alist))
                         (window-list)
                         :key #'window-buffer)))
    (when (and win (window-live-p win))
      (with-selected-window win
        (display-buffer-same-window buf alist)))))

(defmacro display-grouped (pred actions &rest alist)
  (let ((pfun (eval pred)))
    `'(,pfun ,(push 'display-buffer-pred-window actions)
             ,@(push `(pred . ,pfun) alist))))

(setq display-buffer-alist
      `(("\\`\\*Embark Collect \\(Live\\|Completions\\)\\*" nil
         (window-parameters (mode-line-format . none)))
        ("\\`\\*Warnings\\*"
         (display-buffer-in-side-window))
        ,(display-grouped
          (buffer-fp-match! "/\\.lake/packages/")
          (display-buffer-in-side-window)
          (window-height . 0.6)
          (side . bottom))
        ,(display-grouped
          (buffer-mode-p! messages-buffer-mode)
          (display-buffer-in-side-window)
          (window-height . 0.3)
          (side . bottom))
        ,(display-grouped
          (buffer-mode-p! eat-mode)
          (display-buffer-in-side-window)
          (window-height . 0.3)
          (side . bottom))
        ,(display-grouped
          (buffer-mode-p! helpful-mode Info-mode)
          (display-buffer-in-side-window)
          (window-width . 80)
          (side . right))
        (shackle-display-buffer-condition shackle-display-buffer-action)))

Writing / note taking

Mathematical writing

Abbrev

Language & math predicate

(defcustom abbrev/math-text-lang 'pt
  "docs"
  :safe #'symbolp)

(defun abbrev/set-math-text-lang ()
  (interactive)
  (when-let* ((key (car (org-collect-keywords '("language")))))
    (setq abbrev/math-text-lang (make-symbol (cadr key)))))

(defun abbrev/math-text-pt-p () (and (not (texmathp)) (string= abbrev/math-text-lang 'pt)))
(defun abbrev/math-text-en-p () (and (not (texmathp)) (string= abbrev/math-text-lang 'en)))

Textual abbrevs

(setq abbrev/math-text-abbrevs-pt
  '(("pa" "podemos assumir")
    ("pd" "por definição")
    ("ie" "i.e.")
    ("tq" "tal que")
    ("ssg" "suficientemente grande")
    ("spg" "sem perda de generalidade")
    ("qtp" "q.t.p.")
    ("sss" "se, e somente se,")
    ("mdd" "medida")
    ("cjto" "conjunto")
    ("li" "linearmente independentes")))

(setq abbrev/math-text-abbrevs-en
  '(("wlog" "without loss of generality")
    ("iff" "if, and only if,")
    ("ie" "i.e.")
    ("st" "such that")
    ("ae" "a.e.")
    ("pos" "positive")
    ("neg" "negative")
    ("wrt" "with respect to")
    ("meas" "measure")
    ("bd" "by definition")
    ("li" "linearly independent")))

Variable abbrevs

(setq abbrev/var-abbrevs-pt '(b c d f g h i j k l m n p q r s t u v w x y z))
(setq abbrev/var-abbrevs-en '(b c d e f g h j k l m n o p q r s t u v w x y z))

(defun abbrev/compile-var-abbrevs (abbrevs)
  (mapcar (lambda (s) (list (symbol-name s) (format "\\(%s\\)" s) nil :system t))
          abbrevs))

Tables and mode-local tables

(setq abbrev/tables
  `((abbrev/math-text-pt-table
     ,(append
       abbrev/math-text-abbrevs-pt
       (abbrev/compile-var-abbrevs abbrev/var-abbrevs-pt))
     abbrev/math-text-pt-p)
    (abbrev/math-text-en-table
     ,(append
       abbrev/math-text-abbrevs-en
       (abbrev/compile-var-abbrevs abbrev/var-abbrevs-en))
     abbrev/math-text-en-p)))

(defun abbrev/setup ()
  (require 'abbrev)
  (setq-local local-abbrev-table nil)
  (pcase-dolist (`(,name ,defs ,cond) abbrev/tables)
   (define-abbrev-table name defs :enable-function cond)
   (push (symbol-value name) local-abbrev-table))
  (abbrev-mode))

(add-hook 'LaTeX-mode-hook #'abbrev/setup)

Pretty concealed symbols

Custom predicate for composing only inside LaTeX delimiters.

(defun math-prettify--symbols-compose-p (start end _match)
  (and
   (or
    ;; Allow for math delimiters
    (eq ?\) (char-before end))
    (eq ?\( (char-before end))
    ;; Only compose inside math
    t)
   (or
    ;; If the matched symbol doesn't end in a word character, then we
    ;; simply allow composition.  The symbol is probably something like
    ;; \|, \(, etc.
    (not (eq ?w (char-syntax (char-before end))))
    ;; Else we look at what follows the match in order to decide.
    (let* ((after-char (char-after end))
           (after-syntax (char-syntax after-char)))
      (not (or
            ;; Don't compose \alpha@foo.
            (eq after-char ?@)
            ;; The \alpha in \alpha2 or \alpha-\beta may be composed but
            ;; of course \alphax may not.
            (and (eq after-syntax ?w)
                 (not (memq after-char
                            '(?0 ?1 ?2 ?3 ?4 ?5 ?6 ?7 ?8 ?9 ?+ ?- ?' ?\" ?$ ?_))))
            ;; Don't compose inside verbatim blocks.
            (eq 2 (nth 7 (syntax-ppss)))))))))
(defvar math-prettify--symbols-alist nil)

(with-eval-after-load 'tex-mode
  (setq math-prettify--symbols-alist
          (append
           '(("\\left" . )
             ("\\right" . )
             ("\\middle" . ?ᴍ)
             ("\\tilde" . )
             ("\\implies" . ?⇒)
             ("\\colon" . ?:)
             ("\\impliedby" . ?⇐)
             ("\\sqrt" . ?√)
             ("\\dots" . ?…)
             ("\\not\\subset" . ?⊄))
           (bound-and-true-p tex--prettify-symbols-alist))))

(defun math-prettify-activate ()
  (interactive)
  (setq-local prettify-symbols-alist math-prettify--symbols-alist)
  (setq-local prettify-symbols-unprettify-at-point 'right-edge)
  (setq-local prettify-symbols-compose-predicate
              #'math-prettify--symbols-compose-p)
  (prettify-symbols-mode))

;; (dolist (h '(LaTeX-mode-hook latex-mode-hook org-mode-hook))
;;   (add-hook h #'math-prettify-activate))

Citar

(use-package citar
  :init
  (put 'citar-bibliography 'safe-local-variable #'list-of-strings-p)
  :config
  (setopt citar-file-open-functions '(("pdf" . citar-file-open-external)
                                      (t . citar-file-open-external))
          citar-bibliography '("~/Zotero/bibs/all.bib")
          org-cite-csl-styles-dir "~/Zotero/styles"
          citar-symbol-separator " "))
(use-package citar-embark
  :after embark
  :init
  (citar-embark-mode))

Boox attach

(defun boox/copy-and-process (basename callback)
  (let ((fp "/adb:8A3DF2BF:storage/self/primary/note/export/export.pdf"))
    (when (file-readable-p fp)
        (when-let* ((tmpdir (make-temp-file "boox-export" t))
                   (tmpin (concat tmpdir "/in.pdf"))
                   (tmpout (format "%s/%s.png" tmpdir basename)))
          (copy-file fp tmpin)
          (let ((lastpage (shell-command-to-string (format "pdfinfo %s | awk '/^Pages:/ {print $2}'" tmpin)))
                (marker (point-marker)))
            (async-start-process
             "inkscape-convert"
             "inkscape"
             (lambda (_)
               (message "Inkscape finished.")
               (with-current-buffer (marker-buffer marker)
                 (without-restriction
                   (save-excursion
                     (goto-char (marker-position marker))
                     (condition-case e
                         (funcall callback tmpout)
                       (error (message "Handler threw an error: %s" e)))
                     (delete-directory tmpdir t nil)))))
             "--actions=select-by-selector:svg>g>use;delete;page-fit-to-selection"
             "--pdf-poppler"
             (concat "--pages=" lastpage)
             "-o" tmpout
             tmpin))))))

(defun boox/org-handler (tmpout)
  (require 'org-attach)
  (require 'org-download)
  (let ((org-attach-store-link-p 'attached))
       (org-attach-attach tmpout nil 'cp))
  (org-insert-link nil (caar org-stored-links) ""))

(defun boox/tex-handler (tmpout)
  (let* ((file (read-file-name "Directory or file: " nil ""))
         (out (if (or (string= file "") (file-directory-p file))
                  (concat file (file-name-nondirectory tmpout))
                file)))
    (make-directory (file-name-directory out) 't)
    (copy-file tmpout out t)
    (let ((LaTeX-default-environment "figure")
          (TeX-default-macro "includegraphics")
          (LaTeX-includegraphics-read-file (lambda () (file-relative-name out))))
      (call-interactively #'LaTeX-environment)
      (call-interactively #'TeX-insert-macro))))

(defvar boox/handlers '((org-mode . boox/org-handler)
                        (latex-mode . boox/tex-handler)))

(defun boox/attach-last-figure-adb (basename)
  (interactive "sName: ")
  (if-let* ((handler (alist-get major-mode boox/handlers)))
      (boox/copy-and-process basename handler)
    (message "No handlers available for mode.")))

AAS setup

(use-package aas
  :ensure nil
  :init
  (defun +activate-aas-h ()
    (require 'latex)
    (aas-mode)
    (setq-local TeX-font-list LaTeX-font-list)
    (LaTeX-math-mode)
    (aas-activate-keymap 'aas-math))
  (dolist (h '(LaTeX-mode-hook markdown-mode-hook))
   (add-hook h #'+activate-aas-h))
  
  :config
  (defvar-local aas-math-delimiters (cons "\\(" "\\)"))

  (defvar-mode-local markdown-mode
    aas-math-delimiters (cons "$" "$"))
  
  (defun tex-not-command-p ()
    (and (not (looking-back "\\\\[[:alpha:]]*?" (line-beginning-position)))
         (not (looking-back "\\(^\\|[^\\]\\)\\[[^]]*" (line-beginning-position)))))
  (defun latex-brace-tempel-elt (elt)
    (when (eq (car-safe elt) 'sb)
      (let ((var (or (nth 3 elt) 'sb-str)))
        `(l ,(nth 1 elt)
            (if (length> ,var 1) "{" "")
            (p ,(nth 2 elt) ,var)
            (if (length> ,var 1) "}" "")))))
  (defun i-binop (str)
    (cmd!
     (if (memq (char-before) '(?\( ?\{ ?\[ ?^ ?_))
         (insert str)
       (insert (if (eq (char-before) 32) "" " ") str " "))))

  (with-eval-after-load 'tempel
    (add-to-list 'tempel-user-elements #'latex-brace-tempel-elt))
  
  (aas-set-snippets 'aas-math
    :cond (lambda ()
            (and (memq (char-before) '(32 ?- ?\( ?\n))
                 (not (texmathp))))
    " " '(tempel (car aas-math-delimiters) q (cdr aas-math-delimiters))

    ";cas" '(tempel "\\begin\{cases\}" p "\\end\{cases\}")

    :cond #'texmathp
    ".."   "\\dots"

    "+" (i-binop "+")
    "-" (i-binop "-")
    "=" (i-binop "=")
    "<" (i-binop "<")
    ">" (i-binop ">")
    "**" (i-binop "\\cdot")

    "_" '(tempel (sb "_" "n"))
    "^" '(tempel (sb "^" "n"))

    :cond (lambda () (and (tex-not-command-p) (texmathp)))

    "em" (i-binop "\\in")
    "xx" (i-binop "\\times")
    "ss" (i-binop "\\subseteq")
    "sps" (i-binop "\\supeteq")
    "ne" (i-binop "\\ne")
    "le" (i-binop "\\le")
    "ge" (i-binop "\\ge")
    "com" (i-binop "\\circ")

    "norm" (cmd! (TeX-insert-macro "norm"))
    "abs" (cmd! (TeX-insert-macro "abs"))
    "set" (cmd! (TeX-insert-macro "set"))

    "fun" '(tempel (p "f") " \\colon " (p "A") " \\to " (p "B"))

    ;; Modifiers
    "bb" (cmd! (TeX-font nil 19))
    "cal" (cmd! (TeX-font nil 1))
    "tt" (cmd! (TeX-font nil 20))

    "sr" (cmd! (TeX-insert-macro "sqrt"))
    "fr" '(tempel "\\frac{" p "}{" p "}")

    "to" (i-binop "\\to")
    "mto" (i-binop "\\mapsto")

    "sm" (i-binop "\\setminus")

    "NN" "\\NN"
    "ZZ" "\\ZZ"

    "xto" (cmd! (TeX-insert-macro "xrightarrow"))

    "oo"   "\\infty"
    "c.."  "\\cdots"

    "sq"    "^2"
    "cb"    "^3"
    "inv"   "^{-1}"

    "lim" '(tempel "\\lim" (sb "_" "n \\to \\infty") " ")

    "bcap" '(tempel "\\bigcap" (sb "_" "i = 1") (sb "^" "\\infty" v2) " ")
    "bcup" '(tempel "\\bigcup" (sb "_" "i = 1") (sb "^" "\\infty" v2) " ")
    "prod" '(tempel "\\prod"   (sb "_" "i = 1") (sb "^" "\\infty" v2) " ")
    "sum"  '(tempel "\\sum"    (sb "_" "i = 1") (sb "^" "\\infty" v2) " ")
    "bsum" '(tempel "\\frac{1}{" (p "n" var) "}\\sum_{" (p "i") " = 0}^{" var " - 1} ")
    "int"  '(tempel "\\int" (sb "_" "-\\infty") (sb "^" "\\infty" v2) " " p (when (length> meas 0) "\\;d") (p "\\mu" meas))

    "arccos" "\\arccos"
    "arccot" "\\arccot"
    "arccot" "\\arccot"
    "arccsc" "\\arccsc"
    "arcsec" "\\arcsec"
    "arcsin" "\\arcsin"
    "arctan" "\\arctan"
    "cos"    "\\cos"
    "cot"    "\\cot"
    "csc"    "\\csc"
    "exp"    "\\exp"
    "ln"     "\\ln"
    "log"    "\\log"
    "perp"   "\\perp"
    "sin"    "\\sin"
    "star"   "\\star"
    "gcd"    "\\gcd"
    "min"    "\\min"
    "max"    "\\max"
    "inf"    "\\inf"
    "sup"    "\\sup"))

Evil-tex

(use-package evil-tex
  :hook ((LaTeX-mode org-mode) . evil-tex-mode))

Denote and friends

(use-package denote
  :config
  (setopt denote-file-type 'markdown-yaml))
(use-package denote-explore)
(use-package denote-refs)
(use-package consult-denote
  :after (:and denote consult)
  :init
  (consult-denote-mode))
(use-package denote-menu)

Citar-denote

(use-package citar-denote
  :after denote
  :init
  (citar-denote-mode))

Mixed-pitch

(use-package mixed-pitch
  :hook (LaTeX-mode)
  :init
  (defun add-fixed-face-to-prespace ()
    "Add fixed-pitch face to all spaces at line starts."
    (font-lock-add-keywords nil '(("^\\( +\\)" (1 'fixed-pitch append)))))
  :config
  (add-hook 'mixed-pitch-mode-hook #'add-fixed-face-to-prespace)
  (add-hook 'mixed-pitch-mode-hook
            (defun mixed-pitch-line-spacing-h ()
              (setq line-spacing 6)))
  (add-to-list 'mixed-pitch-fixed-pitch-faces 'rainbow-delimiters-depth-1-face))

(use-package rainbow-delimiters
  :hook (LaTeX-mode))

Org-roam

(use-package org-roam
  :custom
  (org-roam-directory (file-truename "~/dados/notas/"))
  (org-roam-capture-templates
   '(("d" "default" plain "%?"
           :target (file+head "%<%Y%m%d%H%M%S>.org" "#+title: ${title}
#+language: pt
")
           :unnarrowed t
          ("m" "math" plain "%?"
           :target (file+head "math/%<%Y%m%d%H%M%S>.org" "#+title: ${title}
#+language: pt
")
           :unnarrowed t))))
  (org-roam-capture-ref-templates
   '(("m" "math" plain "%?"
        :target (file+head "math/%<%Y%m%d%H%M%S>.org" "#+title: ${title}\n\n${body}")
        :unnarrowed t)
     ("fr" "Add to my future-read list" entry "* ${title}\n%?"
      :target (file+olp "to-read.org" ("${title}"))
      :empty-lines-before 1 nil nil)
     ("r" "ref" plain "%?" :target
      (file+head "${slug}.org" "#+title: ${title}")
      :unnarrowed t)))
  :bind (("C-c n l" . org-roam-buffer-toggle)
         ("C-c n f" . org-roam-node-find)
         ("C-c n g" . org-roam-graph)
         ("C-c n i" . org-roam-node-insert)
         ("C-c n c" . org-roam-capture)
         ;; Dailies
         ("C-c n j" . org-roam-dailies-capture-today))
  :config
  ;; If you're using a vertical completion framework, you might want a more informative completion interface
  (setq org-roam-node-display-template (concat "${title:*} " (propertize "${tags:10}" 'face 'org-tag)))
  (org-roam-db-autosync-mode)
  ;; If using org-roam-protocol
  (require 'org-roam-protocol))

Org-node

(use-package org-mem
  :config
  (setopt org-mem-watch-dirs '("~/dados/notas/")
          org-mem-do-sync-with-org-id t)
  (org-mem-updater-mode))

(use-package org-node
  :config
  (org-node-cache-mode)
  (org-node-roam-accelerator-mode)
  (setopt org-node-creation-fn #'org-node-new-via-roam-capture
          org-node-file-slug-fn #'org-node-slugify-like-roam-default
          org-node-file-timestamp-format "%Y%m%d%H%M%S-"))

(put 'org-attach-id-dir 'safe-local-variable #'stringp)

Looks and UI

Fonts and faces

(set-face-font 'default (font-spec :family "Victor Mono" :size 13 :weight 'medium))
(custom-set-faces
 '(fixed-pitch ((t (:family "Victor Mono"))))
 '(variable-pitch ((t (:weight normal :family "IBM Plex Sans"))))
 '(ef-themes-ui-variable-pitch ((t (:inherit variable-pitch)))))

Ligatures

(use-package ligature
  :init
  (global-ligature-mode t)
  :config
  (ligature-set-ligatures
   'haskell-ts-mode
   '("</" "</>" "/>" "~-" "-~" "~@" "<~" "<~>" "<~~" "~>" "~~"
     "~~>" ">=" "<=" "<!--" "##" "###" "####" "|-" "-|" "|->"
     "<-|" ">-|" "|-<" "|=" "|=>" "<-" "<--" "-->" "->" "-<"
     ">->" ">>-" "<<-" "<->" "->>" "-<<" "<-<" "==>" "=>" "=/="
     "!==" "!=" "<==" ">>=" "=>>" ">=>" "<=>" "<=<" "<<=" "=<<"
     ".-" ".=" "=:=" "=!=" "==" "===" "::" ":=" 
     "<|" "<|>" "|>" "<>" "<$" "<$>" "$>" "<+" "<+>" "+>"
     "?=" "/=" "/==" "/\\" "\\/" "__" "&&" "++" "+++"))
  (ligature-set-ligatures
   'lean-ts-mode
   '("</" "</>" "/>" "~-" "-~" "~@" "<~" "<~>" "<~~" "~>" "~~"
     "~~>" ">=" "<=" "<!--" "##" "###" "####" "|-" "-|" "|->"
     "<-|" ">-|" "|-<" "|=" "|=>" "<-" "<--" "-->" "->" "-<"
     ">->" ">>-" "<<-" "<->" "->>" "-<<" "<-<" "==>" "=>" "=/="
     "!==" "!=" "<==" ">>=" "=>>" ">=>" "<=>" "<=<" "<<=" "=<<"
     ".-" ".=" "=:=" "=!=" "==" "===" "::" ":=" 
     "<|" "<|>" "|>" "<>" "<$" "<$>" "$>" "<+" "<+>" "+>"
     "?=" "/=" "/==" "/\\" "\\/" "__" "&&" "++" "+++")))

Unicode

(setopt use-default-font-for-symbols t
        scalable-fonts-allowed t
        face-font-selection-order '(:height :width :weight :slant)
        face-font-rescale-alist '(("JuliaMono" . 0.99)
                                  ("Symbols Nerd Font Mono" . 0.90)))

(defun adjust-symbolic-fonts ()
  (setup-default-fontset)
  (dolist (script '(symbol mathematical unicode))
    (set-fontset-font t script (font-spec :family "Julia Mono" :weight 'normal))
    (set-fontset-font t script (font-spec :family "Victor Mono") nil 'append))
  (dolist (script '(han kana cjk-misc kanbun bopomofo ideographic-description))
    (set-fontset-font t script (font-spec :family "IBM Plex Sans JP")))
  (set-fontset-font t 'emoji "Twemoji" nil 'prepend))

(adjust-symbolic-fonts)
(add-hook 'after-setting-font-hook #'adjust-symbolic-fonts)

Layout

Built-in

(setopt tool-bar-mode nil
        scroll-bar-mode nil
        menu-bar-mode nil)

Darkroom

(use-package darkroom
  :ensure (:repo "~/dados/projetos/codigo/emacs/darkroom/")
  :hook ((text-mode prog-mode conf-mode) . darkroom-mode)
  :config
  (setopt darkroom-fringes-outside-margins nil
          darkroom-text-scale-increase 0))
  • write split-window-preferred-function (window-parameter window ‘split-window)

Indent bars

(use-package indent-bars
  :custom
  (indent-bars-no-descend-lists t) ; no extra bars in continued func arg lists
  (indent-bars-treesit-support t)
  (indent-bars-width-frac 0.1)
  (indent-bars-pad-frac 0.4)
  (indent-bars-treesit-ignore-blank-lines-types '("module"))
  ;; Add other languages as needed
  (indent-bars-depth-update-delay 0.075)
  (indent-bars-starting-column nil)
  (indent-bars-display-on-blank-lines 'least)
  (indent-bars-treesit-wrap '((rust arguments parameters)))
  (indent-bars-treesit-scope '((rust trait_item impl_item 
                                     macro_definition macro_invocation 
                                     struct_item enum_item mod_item 
                                     const_item let_declaration 
                                     function_item for_expression 
                                     if_expression loop_expression 
                                     while_expression match_expression 
                                     match_arm call_expression 
                                     token_tree token_tree_pattern 
                                     token_repetition)))
  :hook ((prog-mode) . indent-bars-mode))

Fringes

(fringe-mode '(4 . 4))

Theme

EF-themes

(use-package ef-themes
  :bind (:map toggle-map ("t" . ef-themes-toggle))
  :custom-face
  (ef-themes-fixed-pitch ((t (:inherit fixed-pitch))))
  :config
  (setopt ef-themes-to-toggle '(ef-reverie ef-dream)
          ef-themes-mixed-fonts t
          ef-themes-variable-pitch-ui t))

Doric

(use-package doric-themes)

Modus customization

This is a beatiful, extremely readable and highly customizable theme. Protesilaos at its finest. I like it a lot for long writing sessions without worries about getting sick or distracted by a colorful theme.

(use-package modus-themes
  :ensure nil
  :custom-face
  (modus-themes-tab-active ((t (:box nil))))
  (modus-themes-tab-inactive ((t (:box nil))))
  :custom
  (modus-themes-tabs-accented t)
  (modus-themes-variable-pitch-ui t)
  (modus-themes-mixed-fonts t)
  (modus-themes-common-palette-overrides
   '((fringe nil)
     (bg-prose-block-contents bg-yellow-nuanced)
     (bg-prose-block-delimiter bg-ochre)
     (fg-prose-block-delimiter yellow-cooler)))
  (modus-themes-mode-line '(accented borderless)))

Terminal

Let’s change the color of the terminal background to match the theme color.

(defun set-terminal-theme (bg cursor)
  "Set the terminal background BG and CURSOR (in #rrggbb)."
  (when (not (display-graphic-p)) ; only in TTY
    (send-string-to-terminal (format "\e]11;%s\a" bg))
    (send-string-to-terminal (format "\e]12;%s\a" cursor))))

(defun sync-theme-to-terminal ()
  (let ((bg (face-attribute 'default :background))
        (cs (face-attribute 'cursor :background)))
    (set-terminal-theme bg cs)))

(add-hook 'after-enable-theme-hook #'sync-theme-to-terminal)

Modeline

(use-package doom-modeline
  :init
  (doom-modeline-mode)
  :config
  (custom-set-faces
   '(mode-line ((t (:family "Julia Mono" :height 95))))
   '(mode-line-inactive ((t (:family "Julia Mono" :height 95))))
   '(doom-modeline-buffer-read-only-modeoodified ((t (:underline t)))))
  (setopt doom-modeline-irc nil
          doom-modeline-height 18
          doom-modeline-buffer-encoding nil
          doom-modeline-workspace-name nil
          doom-modeline-display-misc-in-all-mode-lines nil
          doom-modeline-bar-width 1
          doom-modeline-icon nil))

Segments

PDF

(with-eval-after-load 'doom-modeline
  (doom-modeline-def-segment buffer-name
   "Display the current buffer's name, without any other information."
   (concat
     (doom-modeline-spc)
     (doom-modeline--buffer-name)))

  (doom-modeline-def-segment pdf-icon
    "PDF icon from all-the-icons."
    (concat
      (doom-modeline-spc)
      (doom-modeline-icon 'octicon "file-pdf" nil nil
                          :face (if (doom-modeline--active)
                                    'all-the-icons-red
                                  'mode-line-inactive)
                          :v-adjust 0.02)))

  (defun doom-modeline-update-pdf-pages ()
    "Update PDF pages."
    (setq doom-modeline--pdf-pages
          (let ((current-page-str (number-to-string (eval `(pdf-view-current-page))))
                (total-page-str (number-to-string (pdf-cache-number-of-pages))))
            (concat
              (propertize
                (concat (make-string (- (length total-page-str) (length current-page-str)) 32)
                      " P" current-page-str)
                'face 'mode-line)
              (propertize (concat "/" total-page-str) 'face 'doom-modeline-buffer-minor-mode)))))

  (doom-modeline-def-segment pdf-pages
    "Display PDF pages."
    (if (doom-modeline--active) doom-modeline--pdf-pages
      (propertize doom-modeline--pdf-pages 'face 'mode-line-inactive)))

  (doom-modeline-def-modeline 'pdf
    '(bar window-number pdf-pages pdf-icon buffer-name)
    '(misc-info matches major-mode process vcs)))

Better Flymake segment

When in a project, display Flymake diagnostics counts for the whole project.

(advice-add
 'doom-modeline--flymake-count-errors :around
 (defun doom-modeline--flymake-count-project-errors (old-fn)
   (if (project-current)
       (let ((warning-level (warning-numeric-level :warning))
             (note-level (warning-numeric-level :debug))
             (note 0) (warning 0) (error 0))
         (dolist (diag (flymake--project-diagnostics))
           (let ((severity (flymake--lookup-type-property
                            (flymake--diag-type diag)
                            'severity
                            (warning-numeric-level :error))))
             (cond ((> severity warning-level) (cl-incf error))
                   ((> severity note-level) (cl-incf warning))
                   (t (cl-incf note)))))
         `((note . ,note) (warning . ,warning) (error . ,error)))
     (funcall old-fn))))

MLScroll

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

Hiding

(use-package hide-mode-line
  :hook helpful-mode)

Terminal screen

Cursor, mouse

(setopt xterm-set-window-title t
        visible-cursor nil)
(add-hook 'tty-setup-hook #'xterm-mouse-mode)
(use-package evil-terminal-cursor-changer
  :hook (tty-setup . evil-terminal-cursor-changer-activate))

Kitty Keyboard Protocol

(use-package kkp
  :hook (tty-setup . global-kkp-mode))
  ;; :config
  ;; (setq kkp--progressive-enhancement-flags '((disambiguate-escape-codes :bit 1)
  ;;                                            (report-alternate-keys :bit 4)
  ;;                                            (report-all-keys-as-escape-codes :bit 8))
  ;;       kkp-active-enhancements '(disambiguate-escape-codes
  ;;                                 report-alternate-keys
  ;;                                 report-all-keys-as-escape-codes)))

Clipboard

(use-package clipetty
  :init
  (global-clipetty-mode))

Dedicated server

(add-hook 'server-after-make-frame-hook #'run-after-enable-theme-hook)

Languages

Prog

(add-hook 'prog-mode-hook #'display-line-numbers-mode)

(setopt fill-column 100)

C mode

(add-to-list 'auto-mode-alist '("\\.c\\'" . c-ts-mode))

Elisp

Parinfer

(use-package parinfer-rust-mode
  :hook emacs-lisp-mode)

Highlighting

(use-package highlight-defined
  :custom-face (highlight-defined-face-name-face ((t (:inherit nil))))
  :hook (emacs-lisp-mode . highlight-defined-mode))
(use-package elisp-mode
  :ensure nil
  :config
  (add-hook 'emacs-lisp-mode-hook #'cursor-sensor-mode)
  (setopt elisp-fontify-semantically t))

Flymake checking

(with-eval-after-load 'elisp-mode
  (add-hook 'emacs-lisp-mode-hook #'flymake-mode)
  (add-variable-watcher 'load-path (defun elpaca-load-path (_ newval op local)
                                     (when (and (eq op 'set) (not local))
                                       (setopt elisp-flymake-byte-compile-load-path
                                               (cons "./" newval))))))
Temporary fix
(with-eval-after-load 'elisp-mode
  (defun elisp-flymake-byte-compile--executable ()
    "Return absolute file name of the Emacs executable for flymake byte-compilation."
    (let ((filename
           (when (stringp elisp-flymake-byte-compile-executable)
             (if (file-name-absolute-p elisp-flymake-byte-compile-executable)
                 elisp-flymake-byte-compile-executable
               (when-let* ((pr (project-current)))
                 (file-name-concat (project-root pr)
                                   elisp-flymake-byte-compile-executable))))))
      (if (and filename (file-executable-p filename))
          filename
        (when elisp-flymake-byte-compile-executable
          (message "No such `elisp-flymake-byte-compile-executable': %s"
                   filename))
        (expand-file-name invocation-name invocation-directory)))))

Haskell

(use-package haskell-ts-mode
  :mode "\\.hs\\'"
  :config
  (setopt haskell-ts-prettify-words t)
  (add-hook 'haskell-ts-mode-hook 'prettify-symbols-mode)
  (add-hook 'haskell-ts-mode-hook 'eglot-ensure)

  (with-eval-after-load 'eglot
    (add-to-list 'eglot-server-programs
                 '(haskell-cabal-mode "haskell-language-server-wrapper" "--lsp"))
  
    (setopt eglot-workspace-configuration
            (plist-put eglot-workspace-configuration
                       :haskell `(:cabalFormattingProvider "cabal-gild"
                                  :formattingProvider "fourmolu"
                                  :plugin (:semanticTokens (:globalOn t)
                                           :fourmolu (:config (:external t))))))))

Autoinsert

(defun haskell-guess-module-name (file)
  "Guess Haskell module name from FILE, capitalizing path components only if needed."
  (let* ((root (project-root (project-current t)))
         (rel (file-relative-name file root))
         (no-ext (file-name-sans-extension rel))
         (parts (split-string no-ext "/")))
    (string-join
     (seq-filter (lambda (p) (char-uppercase-p (string-to-char p))) parts)
     ".")))

(with-eval-after-load 'autoinsert
  (define-auto-insert
    '(haskell-ts-mode . "Haskell module skeleton")
    '(lambda ()
       (let* ((module-name (haskell-guess-module-name buffer-file-name)))
         (insert "module " module-name " where\n\n")))))

Julia

(use-package julia-snail
  :custom
  (julia-snail-terminal-type :eat)
  (julia-indent-offset 2)
  :hook
  (julia-mode . julia-snail-mode))

Lean

(use-package lean-ts-mode
  :ensure (:repo "~/dados/projetos/codigo/emacs/lean-ts-mode/"
           :files ("*.el" "data")))

(with-eval-after-load 'autoinsert
  (add-to-list 'auto-insert-alist
               (cons '(predicate
                       (lambda ()
                         (when-let* ((_ (derived-mode-p 'lean-ts-mode))
                                     (fp (buffer-file-name)))
                           (string-match-p "Mathlib/" fp))))
                     "mathlib.lean")))

Rust

(add-to-list 'auto-mode-alist '("\\.rs\\'" . rust-ts-mode))
(add-hook 'conf-toml-mode-hook 'eglot-ensure)
(with-eval-after-load 'eglot
  (add-to-list 'eglot-server-programs
               '(conf-toml-mode . ("taplo" "lsp" "stdio"))))

(with-eval-after-load 'rust-ts-mode
  (setopt rust-ts-mode-indent-offset 2))

QML

(use-package qml-ts-mode
  :ensure (:host github :repo "xhcoding/qml-ts-mode")
  :config
  (setopt qml-ts-mode-indent-offset 2)
  (add-hook 'qml-ts-mode-hook
            (defun setup-qml-ts-mode ()
              (setq-local electric-indent-chars '(?\n ?\( ?\) ?{ ?} ?\[ ?\] ?\; ?,))
              (eglot-ensure))))

(with-eval-after-load 'eglot
  (add-to-list 'eglot-server-programs '(qml-ts-mode "qmlls")))

Web

HTMl

(use-package web-mode)

CSS

(with-eval-after-load 'css-mode
  (setopt css-indent-offset 2))

Typescript

(use-package typescript-ts-mode
  :ensure nil
  :mode (("\\.ts\\'" . typescript-ts-mode)
         ("\\.tsx\\'" . tsx-ts-mode))
  :config
  (add-hook 'typescript-ts-base-mode-hook #'eglot-ensure))

Javascript

(use-package js
  :ensure nil
  :mode (("\\.js\\'" . js-ts-mode))
  :custom
  (js-indent-level 2)
  :config
  (add-hook 'js-ts-mode-hook #'eglot-ensure))

(with-eval-after-load 'eglot
  (setopt eglot-workspace-configuration
          (plist-put eglot-workspace-configuration
                     :javascript (list :format (list :indentSize 2)))))

Text

(add-hook 'text-mode-hook #'visual-line-mode)
(with-eval-after-load 'text-mode
  (setopt text-mode-ispell-word-completion nil))

LaTeX

(use-package font-latex
  :ensure nil
  :custom-face (font-latex-math-face ((t (:inherit modus-themes-fixed-pitch))))
  :config
  (setopt font-latex-script-display '((raise -0.3) . (raise 0.4))
          font-latex-fontify-script 'multi-level))

AucTeX

(use-package tex
  :ensure (auctex :pre-build (("./autogen.sh")
                              ("./configure"
                               "--with-texmf-dir=$(dirname $(kpsexpand '$TEXMFHOME'))")
                              ("make"))
                  :repo "https://github.com/emacsmirror/auctex.git"
                  :branch "master")
  :hook (LaTeX-mode . (lambda () (require 'latex) (LaTeX-math-mode)))
  :config
  (add-hook 'LaTeX-mode-hook #'LaTeX-math-mode) 
  (add-hook 'LaTeX-mode-hook #'diff-hl-mode)
  (add-hook 'LaTeX-mode-hook #'diff-hl-margin-local-mode)
  (setopt TeX-parse-self t
          TeX-auto-save t))

(use-package latex
  :ensure nil
  :hook (LaTeX-mode . eglot-ensure)
  :bind (:map LaTeX-mode-map ("C-j" . nil))
  :config
  (setopt LaTeX-flymake-chktex-options '("-n1" "-n3"))
  (add-hook 'LaTeX-mode-hook
            (defun eglot-flymake-add-chktex ()
              (add-hook 'eglot-managed-mode-hook
                        (lambda () (add-to-list 'flymake-diagnostic-functions 'LaTeX-flymake))
                        nil t)))
  (modal-setmap LaTeX-mode-map mode-map
                "@" #'citar-insert-citation
                "!" #'citar-open-files))
Preview
(use-package preview-dvisvgm
  :after preview
  :defer nil
  :config
  (setopt preview-image-type 'dvisvgm
          TeX-PDF-mode nil
          preview-dvisvgm-command "dvisvgm --bbox=preview --no-fonts %d --page=- --output=\"%m/prev%%3p.svg\""))

(with-eval-after-load 'preview
  (setopt preview-default-preamble
          '("\\RequirePackage[" ("," . preview-default-option-list)
            "]{preview}[2004/11/05]"
            "\\definecolor{fg}{rgb}{%(fg)}"
            "\\definecolor{bg}{rgb}{%(bg)}"
            "\\color{fg}"
            "\\pagecolor{bg}"))
  
  (setopt TeX-expand-list
          '(("%(fg)" (lambda ()
                       (mapconcat #'preview-gs-color-value
                                  (aref (nth 2 (preview-get-geometry)) 1)
                                  ",")))
            ("%(bg)" (lambda ()
                       (mapconcat #'preview-gs-color-value
                                  (aref (nth 2 (preview-get-geometry)) 0)
                                  ",")))))
  
  (setopt preview-leave-open-previews-visible t
          preview-protect-point t
          preview-scale-function (lambda ()
                                   (let ((f (preview-scale-from-face)))
                                     (lambda () (* 1.25 (funcall f))))))

  (advice-add 'preview-inactive-string :override
              (defun preview-inactive-string/better-newline (ov)
                (concat
                 (preview-make-clickable (overlay-get ov 'preview-map)
                                         (if preview-leave-open-previews-visible
                                             (overlay-get ov 'preview-image)
                                           preview-icon)
                                         "\
%s redisplays preview
%s more options")
                 (with-current-buffer (overlay-buffer ov)
                   (save-excursion
                     (save-restriction
                       (widen)
                       (goto-char (overlay-start ov))
                       (beginning-of-line)
                       (skip-chars-forward "[:space:]")
                       (if (eq (point) (overlay-start ov))
                           (concat "\n" (buffer-substring-no-properties (pos-bol) (point)))
                         "")))))))

  (advice-add 'preview-ascent-from-bb :filter-return
              (defun preview-ascent-from-bb/add-offset (ascent)
                (min 100 (+ ascent 3))))

  (advice-add 'preview-create-icon :filter-return
              (defun preview-create-icon/add-foreground (img)
                (cons `(,@(car img) :foreground ,(face-attribute 'default :foreground))
                      (cdr img)))))
                
                

Reftex

(use-package reftex
  :ensure nil
  :hook (LaTeX-mode . turn-on-reftex)
  :config
  (setopt reftex-label-alist '(("theorem" ?h "thm:" nil nil nil -3)
                               ("lemma" ?l "lem:" nil nil nil -3)
                               ("example" ?g "eg:" nil nil nil -3)
                               ("corollary" ?c "col:" nil nil nil -3)
                               ("proposition" ?p "prop:" nil nil nil -3))
          reftex-ref-style-default-list '("Cleveref" "AMSmath")
          reftex-plug-into-AUCTeX t
          reftex-insert-label-flags '("s" "sfthlgcp")))

Texlab with Eglot

lsp-mode, for some weird reason, is really lagging in LaTeX documents, while Eglot is not. This tends to annoy and distract me. Let’s create a simple interface to Texlab features with Eglot.

(with-eval-after-load 'eglot
  (setopt eglot-workspace-configuration
          (plist-put eglot-workspace-configuration
                     :texlab '(:build
                               (:args ["-interaction=nonstopmode" "-synctex=1" "%f"]
                                :buildParent t)
                               :forwardSearch
                               (:executable "sioyek"
                                            :args ["--forward-search-file" "%f"
                                                   "--forward-search-line" "%l" "%p"])
                               ;; (:executable "zathura"
                               ;;  :args ["--synctex-forward" "%l:1:%f" "%p"])
                               :experimental
                               (:labelReferenceCommands ["nameref"]))))

  (defun eglot-texlab-build ()
    (interactive)
    (save-buffer)
    (jsonrpc-async-request
     (eglot--current-server-or-lose)
     :textDocument/build (eglot--TextDocumentPositionParams)
     :success-fn (lambda (r) (message "Build %s" r))
     :error-fn (lambda (r) (message "Error %s" r))
     :deferred t))

  (defun eglot-texlab-forward-search ()
    (interactive)
    (jsonrpc-async-request
     (eglot--current-server-or-lose)
     :textDocument/forwardSearch (eglot--TextDocumentPositionParams)
     :success-fn (lambda (r) (message "Search %s" r))
     :error-fn (lambda (r) (message "Error %s" r))
     :deferred t))

  (with-eval-after-load 'latex
    (modal-setmap LaTeX-mode-map mode-map
                  "a" #'eglot-texlab-build
                  "f" #'eglot-texlab-forward-search)

    (setmap LaTeX-mode-map
            "C-c C-a" #'eglot-texlab-build
            "C-c C-c" #'eglot-texlab-forward-search
            "C-c @"   #'citar-insert-citation)))

Markdown

(use-package markdown-mode
  :config
  (setmap markdown-mode-map
          "TAB" (smartparens-tab 'markdown-cycle))
  (setopt markdown-fontify-code-blocks-natively t
          markdown-enable-math t)
  (modal-setmap markdown-mode-map mode-map
                "@" #'citar-insert-citation
                "!" #'citar-open-files)
  (add-hook 'markdown-mode-hook #'smartparens-mode)
  (with-eval-after-load 'smartparens
    (sp-local-pair '(markdown-mode) "$" "$"
                    :actions '(wrap insert autoskip navigate))))

(use-package markdown-ts-mode
  :ensure (:repo "~/dados/projetos/codigo/emacs/emacs/lisp/textmodes/"
           :files ("markdown-ts-mode.el")))

Org

(use-package org
  :ensure nil
  :mode ("\\.org\\'" . org-mode)
  :commands (org-mode)
  :config
  (require 'org-mouse)
  (modal-setmap org-mode-map mode-map
                "." #'consult-org-heading
                "i" #'consult-org-heading
                "s p" #'org-paste-subtree
                "s y" #'org-copy-subtree
                "s d" #'org-cut-subtree
                "s a" #'org-archive-subtree
                "l s" #'org-store-link)
  (setmap org-mode-map "C-," nil)
  (evil-define-key 'normal org-mode-map
    "\\" #'org-edit-special
    (kbd "TAB") #'org-cycle)
  (evil-define-minor-mode-key 'normal 'org-src-mode "\\" #'org-edit-src-exit)
  (setopt org-indent-indentation-per-level 1
          org-src-window-setup 'split-window-below
          org-directory "~/dados/org"
          org-startup-indented t
          org-support-shift-select t
          org-insert-heading-respect-content t
          org-hide-leading-stars t
          org-fold-show-context-detail '((agenda . local) (bookmark-jump . lineage) (isearch . local) (default . ancestors))
          org-id-method 'ts
          org-src-lang-modes (cl-pushnew '("latex" . LaTeX) org-src-lang-modes)
          org-highlight-latex-and-related '(native latex script)
          org-src-preserve-indentation t)

  (setq org-attach-auto-tag nil
        org-attach-id-to-path-function-list
        '(org-attach-id-ts-folder-format org-attach-id-uuid-folder-format identity)))

Organon

(define-minor-mode organon-follow-mode
  "Set whether organon should follow your every move in Emacs."
  :lighter " organon"
  :global t
  :group 'organon
  :init-value nil
  (if organon-follow-mode
      (progn
        (add-hook 'post-command-hook #'organon--update-position)
        (message "organon will now follow you around."))
    (remove-hook 'post-command-hook #'organon--update-position)
    (message "organon will now leave you alone.")))

(defvar organon--last-pos nil)
(defvar organon--conn nil)

(defun organon--connect ()
  (require 'websocket)
  (unless organon--conn
    (websocket-open
     "ws://127.0.0.1:9160"
     :on-open (lambda (ws) (message "organon: connected") (setq organon--conn ws))
     :on-close (lambda (ws) (message "organon: disconnected") (setq organon--conn nil)))))

(defun organon--get-info ()
  (list :id (org-entry-get nil "ID" t)
        :file (buffer-file-name)
        :anchor (or (org-entry-get nil "CUSTOM_ID")
                    (condition-case nil
                        (let ((str (or (nth 4 (org-heading-components)) "")))
                          (string-match "[^[:alpha:]]*\\(.*\\)" str)
                          (substring str (match-beginning 1)))
                      (user-error nil)))))

(defun organon--update-position ()
  (when-let* ((_ (eq major-mode 'org-mode))
             (cur-pos (organon--get-info))
             (_ (not (equal cur-pos organon--last-pos))))
    (setq organon--last-pos cur-pos)
    (send-to-organon)))

(defun send-to-organon ()
  (interactive)
  (organon--connect)
  (when organon--conn
    (let ((cur-info (organon--get-info)))
      (websocket-send-text organon--conn (json-encode cur-info)))))

Skip ‘SUBTREE’

(advice-add #'org-cycle-internal-local :around
  (defun org-cycle-internal-local-ad (f)
    (if (eq org-cycle-subtree-status 'children)
        (let ((last-command nil))
          (funcall f))
      (funcall f))))

Appearance

Font-lock patches
Fragment fontification without org-block

Org reuses the org-src-font-lock-fontify-block function to fontify LaTeX fragments natively. But this function adds the very inappropiate face org-block to everything. Let’s remove it when the native block is one of our fragments.

(defvar org--font-locking-latex-fragment nil)

(advice-add #'org-do-latex-and-related :around
            (defun signal-font-locking-latex (orig-fun &rest args)
              (let ((org--font-locking-latex-fragment t))
                (apply orig-fun args))))

(advice-add #'org-src-font-lock-fontify-block :after
            (defun do-not-org-block-my-latex-advice (_ start end)
              (when org--font-locking-latex-fragment
                (alter-text-property start end 'face (lambda (l) (remove 'org-block l))))))
Better alignment for mixed-pitch
(defun org-add-indent-face-to-prespace ()
  (setq
   org-font-lock-extra-keywords
   (append (delete
            '("^ *\\([-+]\\|\\(?:[0-9]+\\|[a-zA-Z]\\)[).]\\)[ \t]" 1 'org-list-dt append)
            org-font-lock-extra-keywords)
           ;; Add org-indent face to all spaces at line starts
           '(("^\\( +\\)"
              (1 'org-indent append))
             ;; Also fontify * bullets
             ("^ +\\(\\*\\)\\([ \t]\\)"
              (1 'org-list-dt append)
              (2 'org-indent append))
             ;; This is modified from user @psii
             ;; https://github.com/doomemacs/themes/pull/716
             ("^ *\\([-+]\\|\\(?:[0-9]+\\|[a-zA-Z]\\)[).]\\)\\([ \t]\\)"
                           (1 'org-list-dt append)
                           (2 'org-indent append))))))

(add-hook 'org-font-lock-set-keywords-hook #'org-add-indent-face-to-prespace)

We can also make list bullets fixed-pitch, so they are even more aligned.

(with-eval-after-load 'mixed-pitch
  (add-to-list 'mixed-pitch-fixed-pitch-faces 'org-list-dt)
  (add-to-list 'mixed-pitch-fixed-pitch-faces 'rainbow-delimiters-depth-1-face))
Fontify counter cookies
(defun org-fontify-counter-cookies ()
  (setq
   org-font-lock-extra-keywords
   (append org-font-lock-extra-keywords
           '(("^[ \t]*\\(?:[-+*]\\|\\(?:[0-9]+\\|[a-zA-Z]\\)[.)]\\)[ \t]+\\(\\[@\\(?:start:\\)?\\(?:[0-9]+\\|[a-zA-Z]\\)\\]\\)"
              (1 'org-property-value prepend))))))

(add-hook 'org-font-lock-set-keywords-hook #'org-fontify-counter-cookies)
Stars
(use-package org-superstar
  :after (org)
  :hook (org-mode . org-superstar-mode)
  :config
  (setq org-superstar-headline-bullets-list '(?◆ ?❉ ?🞱 ?🞽 ?✺)))

Conf

KDL

(use-package kdl-ts-mode
  :mode "\\.kdl\\'"
  :ensure (:repo "https://github.com/dataphract/kdl-ts-mode.git" :main "kdl-ts-mode.el"))

YAML

(use-package yaml-mode)

Systemd

(use-package systemd)

(use-package daemons)

(with-eval-after-load 'autoinsert
  (add-to-list 'auto-insert-alist
               (cons 'systemd-mode
                     (lambda ()
                       (tempel-insert
                        '("[Unit]" n
                          "PartOf="(p "graphical-session" tgt)".target" n
                          "After=" tgt ".target" n
                          "Requisite=" tgt ".target" n n
                          "[Service]" n
                          "ExecStart=" p n
                          "Restart=on-failure"))))))

PDF

(use-package pdf-tools
  :mode  ("\\.pdf\\'" . pdf-view-mode)
  :config
  (setopt pdf-view-display-size 'fit-page)
  (add-hook 'pdf-view-mode-hook
            (defun pdf-evil-disable-cursor ()
              (set (make-local-variable 'evil-normal-state-cursor) (list nil))))
  (advice-add 'pdf-view-enlarge :after (lambda (_) (pdf-view-center-in-window))))

Random apps

Matrix (ement)

(use-package ement)

Smudge

(use-package smudge
  :config
  (setopt smudge-oauth2-client-id "55d2deb3878f4b73912f72a3a131024c"
          smudge-oauth2-client-secret (api-key-from-auth-source "api.spotify.com")))

About

My bare Emacs config. No frameworks :)

Resources

Stars

Watchers

Forks