Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/soficshift/baremacs
My bare Emacs config. No frameworks.
https://github.com/soficshift/baremacs
Last synced: 20 days ago
JSON representation
My bare Emacs config. No frameworks.
- Host: GitHub
- URL: https://github.com/soficshift/baremacs
- Owner: soficshift
- Created: 2024-06-06T03:15:01.000Z (7 months ago)
- Default Branch: main
- Last Pushed: 2024-12-15T18:13:18.000Z (27 days ago)
- Last Synced: 2024-12-15T18:20:08.684Z (27 days ago)
- Language: Emacs Lisp
- Homepage:
- Size: 4.4 MB
- Stars: 0
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: .github/readme.org
Awesome Lists containing this project
README
#+property: header-args :lexical t :results none
#+startup: content
#+todo: ORGANIZE(o) TODO(t) | DONE (d)This Emacs config attempts to use the bundled libraries as much as possible, but only when it makes sense to do so. For about three years I used [[https://github.com/doomemacs/doomemacs][Doom Emacs]], which was great to introduce me to how Emacs works and its ecosystem, but after having a go at this vanilla configuration, I can assure you that you can build a config that works much better for you and is more stable. Of couse, this requires work, but for me this was very much worth it.
Here is an overview of features:
- Persistence across sessions via built-in ~savehist~ and ~desktop~ packages;
- Project management via built-in ~project~, enhanced via ~project-tab-groups~ and ~tab-bar-echo-area~ to make it very much like ~perspective~ but way more stable and integrated;
- ~evil~! The muscle memory is way too strong to give up on this one!
- Everything Minad has gifted us puny humans:
- ~vertico~ completion interface, with ~marginalia~ annotations and ~nerd-icons~;
- ~corfu~ completion-at-point interface, along with ~cape~ goodies;
- ~tempel~, great template (snippets) system;
- ~jinx~ spell correction;
- ~embark~ for "transient" actions --- very much like a mouse right-click;
- LSP via ~eglot~, with additional features such as semantic tokens;* Elpaca setup
#+begin_src emacs-lisp
;;; -*- lexical-binding: t; -*-
#+end_src#+begin_src emacs-lisp
(load (expand-file-name "elpaca-init" user-emacs-directory))
#+end_srcNow we make it so that =use-package= declarations are installed by Elpaca by default.
#+begin_src emacs-lisp
(setopt use-package-always-ensure t
use-package-always-defer t)
#+end_src* Useful toolbox
#+begin_src emacs-lisp
(defmacro cmd! (&rest forms) `(lambda () (interactive) ,@forms))
#+end_src#+begin_src emacs-lisp
(defun setmap (map &rest defs)
(while defs
(keymap-set map (car defs) (cadr defs))
(setq defs (cddr defs))))
#+end_src* Performance
** GCMH
#+begin_src emacs-lisp
(use-package gcmh
:init
(gcmh-mode 1))
#+end_src* Navigation and insertion
** Basic
#+begin_src emacs-lisp
(keymap-set global-map "C-s" #'save-buffer)
#+end_src** Custom leader
This is pretty much a hack but it is short and it works.#+begin_src emacs-lisp
(defvar leader-key (kbd "SPC"))
(defvar leader-alt-key (kbd "M-SPC"))
#+end_src#+begin_src emacs-lisp
(defun modal-setmap (active-map map &rest defs)
(let ((new-map (make-sparse-keymap))
(new-leader (make-sparse-keymap)))
(set-keymap-parent new-map map)
(set-keymap-parent new-leader leader-map)
(apply #'setmap new-map defs)
(keymap-substitute new-leader map new-map)
(evil-define-key* 'normal active-map leader-key new-leader)
(evil-define-key* 'insert active-map leader-alt-key new-leader)))
#+end_src** Keymaps
#+begin_src emacs-lisp
(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 buffer-map
:doc "Buffer 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-file)(setmap toggle-map
"l" #'display-line-numbers-mode)(setmap buffer-map
"d" #'kill-buffer
"r" #'revert-buffer)(setmap leader-map
"w" (cons "Window" window-map)
"x" (cons "x" ctl-x-map)
"b" (cons "Buffer" buffer-map)
"c" (cons "Code" code-map)
"s" (cons "Search" search-map)
"p" (cons "Project" project-map)
"t" (cons "Toggle" toggle-map)
"f" (cons "File" file-map)
"m" (cons "Mode" mode-map)
"." #'find-file)
#+end_src** Utility
#+begin_src emacs-lisp
(defun delete-file-and-buffer ()
"Kill the current buffer and deletes the file it is visiting."
(interactive)
(let ((filename (buffer-file-name)))
(if filename
(if (y-or-n-p (concat "Do you really want to delete file " filename " ?"))
(progn
(delete-file filename)
(message "Deleted file %s." filename)
(kill-buffer)))
(message "Not a file visiting buffer!"))))(setmap file-map "d" #'delete-file-and-buffer)
#+end_src** 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.#+begin_src emacs-lisp
(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") #'run-tab-actions)
#+end_src** Smartparens
#+begin_src emacs-lisp
(use-package smartparens
:hook ((prog-mode text-mode) . smartparens-mode)
:config
(add-hook 'tab-actions 'sp-up-sexp 10)
(require 'smartparens-config)
(dolist (h '(prog-mode-hook LaTeX-mode-hook))
(add-hook h 'smartparens-mode 99 nil)))
#+end_src** Link-hint
#+begin_src emacs-lisp
(use-package link-hint
:bind (:map search-map ("l" . link-hint-open-link)))
#+end_src** Evil π π₯°
#+begin_src emacs-lisp
(use-package evil
:bind (("C-w" . evil-delete-backward-word)
:map buffer-map
("l" . evil-switch-to-windows-last-buffer))
:init
(setq evil-want-integration t
evil-ex-substitute-global t
evil-lookup-func #'helpful-at-point
evil-shift-round nil
evil-cross-lines 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 1)
:config
(set-keymap-parent window-map evil-window-map)
(evil-define-key 'motion text-mode-map
"j" #'evil-next-visual-line
"k" #'evil-previous-visual-line)
(evil-define-key 'insert 'global
(kbd "C-v") #'evil-paste-before
(kbd "M-SPC") leader-map
(kbd "M-TAB") #'completion-at-point
(kbd "C-g") #'evil-normal-state)
(evil-define-key '(normal emacs) 'global
(kbd "SPC") leader-map
(kbd "C-t") nil))
#+end_src*** COMMENT Embrace
#+begin_src emacs-lisp
(use-package embrace)
#+end_src#+begin_src emacs-lisp
(use-package evil-embrace
:after evil
:init
(evil-embrace-enable-evil-surround-integration))
#+end_src*** COMMENT Escape
#+begin_src emacs-lisp
(use-package evil-escape
:after evil
:init
(setopt evil-escape-key-sequence "jk")
(evil-escape-mode))
#+end_src*** Collection
#+begin_src emacs-lisp
(use-package evil-collection
:after evil
:init
(evil-collection-init))
#+end_src*** Multiedit
#+begin_src emacs-lisp
(use-package evil-multiedit
:init
(require 'evil-multiedit)
(evil-multiedit-default-keybinds))
#+end_src*** Surround
#+begin_src emacs-lisp
(use-package evil-surround
:after evil
:init
(global-evil-surround-mode 1))
#+end_src*** Snipe
#+begin_src emacs-lisp
(use-package evil-snipe
:after evil
:init
(setopt evil-snipe-spillover-scope 'visible)
(evil-snipe-mode 1)
(evil-snipe-override-mode 1)
(add-hook 'magit-mode-hook 'turn-off-evil-snipe-override-mode))
#+end_src
*** Text objects
**** Tree-sitter
#+begin_src emacs-lisp
(use-package evil-textobj-tree-sitter
:after evil)
#+end_src* Completion
** Orderless
#+begin_src emacs-lisp
(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)))
#+end_src** Cape
#+begin_src emacs-lisp
(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 nil)
:init
(advice-add #'lsp-completion-at-point :around #'cape-wrap-noninterruptible)
(advice-add #'lsp-completion-at-point :around #'cape-wrap-nonexclusive)
(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-h ()
(add-hook 'completion-at-point-functions #'cape-dabbrev 20 t))(dolist (h '(prog-mode-hook conf-mode-hook))
(add-hook h #'+corfu-add-cape-dabbrev-h))(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))
#+end_srcThe ~cape-dabbrev~ backend does not handle casing very well; see my issue [[https://github.com/minad/cape/issues/116][here]]. The following advice makes ~cape-dabbrev~ match the case of uppercase words with the case of the completion prefix.
#+begin_src emacs-lisp
(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)))))))
#+end_src** Consult
#+begin_src emacs-lisp
(use-package consult
: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-project-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)
: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-" "S-"))
;; 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)
#+end_src** Marginalia
#+begin_src emacs-lisp
(use-package marginalia
:bind (:map minibuffer-local-map
("M-A" . marginalia-cycle))
:init
(marginalia-mode))
#+end_src** Nerd-icons
#+begin_src emacs-lisp
(use-package nerd-icons-completion
:after marginalia
:init
(nerd-icons-completion-mode)
(add-hook 'marginalia-mode-hook #'nerd-icons-completion-marginalia-setup))
#+end_src** Templates
*** Tempel
#+begin_src emacs-lisp
(use-package tempel
:ensure (:repo "[email protected]: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
"" #'tempel-previous
"M-d" (cmd! (tempel-kill) (tempel-next 1))))
#+end_src*** AAS
#+begin_src emacs-lisp
(use-package aas)
#+end_srcSome monkey patching to keep the order of hooks reasonable. Otherwise there is a huge mess with smartparens.
#+begin_src emacs-lisp
(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))))
#+end_src** UIs
*** Vertico
**** Config
#+begin_src emacs-lisp
(use-package vertico
:init
(vertico-mode)
:config
(setopt vertico-resize nil
vertico-count 8))(add-hook 'minibuffer-setup-hook #'cursor-intangible-mode)
(setopt minibuffer-prompt-properties '(read-only t cursor-intangible t face minibuffer-prompt))
(setopt enable-recursive-minibuffers t)
(setopt read-extended-command-predicate #'command-completion-default-include-p)
#+end_src**** Extensions
***** Directory
#+begin_src emacs-lisp
(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))
#+end_src***** Repeat
#+begin_src emacs-lisp
(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-" . vertico-repeat-previous)
("S-" . vertico-repeat-next))
:hook (minibuffer-setup . vertico-repeat-save))
#+end_src**** Posframe
#+begin_src emacs-lisp
(use-package vertico-posframe
:init
(vertico-posframe-mode 1)
:config
(setopt vertico-posframe-border-width 1
;; without this, the horizontal state gets messed up
;; permanently if the minibuffer input is too long.
vertico-posframe-truncate-lines nil)
;; setopt is complaining
(setq vertico-posframe-parameters '((left-fringe . 8) (right-fringe . 8))))
#+end_src*** Corfu
#+begin_src emacs-lisp
(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 1)))
(remove-hook 'minibuffer-setup-hook #'corfu-enable-in-minibuffer)
(global-corfu-mode)
:custom-face (corfu-default ((t (:inherit fixed-pitch))))
:bind
(:map corfu-map
("\\" . corfu-quit)
("M-s" . corfu-insert-separator))
:config
(setopt corfu-cycle t
corfu-auto t
corfu-auto-prefix 4
corfu-count 16
corfu-auto-delay 0.1
corfu-preselect 'valid
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)
(add-to-list 'completion-category-overrides `(lsp-capf (styles ,@completion-styles))))
#+end_src#+begin_src emacs-lisp
(advice-add #'corfu--make-buffer :filter-return
(defun corfu-no-line-spacing-ad (buffer)
(with-current-buffer buffer
(setq-local line-spacing 0)
buffer)))
#+end_src**** Extensions
***** Terminal
#+begin_src emacs-lisp
(use-package corfu-terminal
:when (not (display-graphic-p))
:hook ((corfu-mode . corfu-terminal-mode)))
#+end_src***** History
#+begin_src emacs-lisp
(use-package corfu-history
:ensure nil
:after (savehist corfu)
:hook ((corfu-mode . corfu-history-mode))
:config
(add-to-list 'savehist-additional-variables 'corfu-history))
#+end_src***** Popupinfo
#+begin_src emacs-lisp
(use-package corfu-popupinfo
:ensure nil
:after corfu
:hook ((corfu-mode . corfu-popupinfo-mode))
:config
(setopt corfu-popupinfo-delay '(0.5 . 1.0)))
#+end_src***** Kind-icon
#+begin_src emacs-lisp
(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))
#+end_src*** Embark
#+begin_src emacs-lisp
(use-package embark
:bind (("C-;" . embark-act)
("C-," . embark-dwim)
([remap describe-bindings] . embark-bindings))
: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-which-key-indicator
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
:hook (embark-collect-mode . consult-preview-at-point-mode))
#+end_src**** Which-key indicator
#+begin_src emacs-lisp
(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)))
#+end_src*** Which-key
#+begin_src emacs-lisp
(use-package which-key
:init
(which-key-mode))
#+end_src* Functionality
** Custom
#+begin_src emacs-lisp
(setopt custom-file "/dev/null")
#+end_srcAdd a hook after theme changes.
#+begin_src emacs-lisp
(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))
#+end_src
** Buffer management
*** IBuffer
Let's group by projects using a handy package.#+begin_src emacs-lisp
(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)))))
#+end_src** Eglot
#+begin_src emacs-lisp
(use-package jsonrpc
:ensure nil)(use-package eglot
:ensure nil
:custom-face
(eglot-diagnostic-tag-unnecessary-face ((t (:inherit shadow))))
:config
(setcdr (assoc '(latex-mode plain-tex-mode context-mode texinfo-mode bibtex-mode tex-mode)
eglot-server-programs)
'("texlab"))
(modal-setmap eglot-mode-map code-map
"a" #'eglot-code-actions
"f" #'eglot-format
"I" #'consult-eglot-symbols))
#+end_src*** Semtok
#+begin_src emacs-lisp
(use-package eglot-semantic-tokens
:ensure (:repo "https://codeberg.org/eownerdead/eglot-semantic-tokens.git"))
#+end_src*** Consult integration
#+begin_src emacs-lisp
(use-package consult-eglot)(use-package consult-eglot-embark
:after eglot
:init
(consult-eglot-embark-mode 1))
#+end_src*** Booster π
#+begin_src emacs-lisp
(use-package eglot-booster
:ensure (:host github :repo "jdtsmith/eglot-booster")
:after eglot
:init
(eglot-booster-mode 1))
#+end_src** Errors, linting
*** Flymake
**** Popon
#+begin_src emacs-lisp
(use-package flymake-popon
:after flymake
:custom-face (flymake-popon ((t (:inherit corfu-popupinfo))))
:init
(global-flymake-popon-mode)
:config
(setopt flymake-popon-delay 0.8
flymake-popon-posframe-border-width 0
flymake-popon-method 'posframe
flymake-popon-diagnostic-formatter #'flymake-diagnostic-text))
#+end_src
*** Eldoc
#+begin_src emacs-lisp
(use-package eldoc
:ensure nil
:config
(setopt eldoc-echo-area-use-multiline-p nil))
#+end_src*** Eldoc-box
#+begin_src emacs-lisp
(use-package eldoc-box
:after eldoc
:custom-face
(eldoc-box-body ((t (:height 1.0 :weight normal :inherit (variable-pitch)))))
(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) 10)
(setcdr (assoc 'right-fringe eldoc-box-frame-parameters) 10)(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))
#+end_src** File templates
*** Auto-insert
#+begin_src emacs-lisp
(use-package auto-insert-mode
:ensure nil)
#+end_src*** Gitignore
#+begin_src emacs-lisp
(use-package gitignore-templates)
#+end_src** Good scrolling
#+begin_src emacs-lisp
(pixel-scroll-precision-mode 1)
(setopt pixel-scroll-precision-interpolation-factor 1.5)
#+end_src** Helpful
#+begin_src emacs-lisp
(use-package helpful
: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)))
#+end_src** Idiosyncrasy
#+begin_src emacs-lisp
(setopt indent-tabs-mode nil
inhibit-startup-screen t
frame-resize-pixelwise t
scroll-conservatively 20
backup-inhibited t
ring-bell-function #'ignore
revert-without-query '(".")
display-line-numbers-width-start t
use-short-answers t
;; what the fuck, emacs!
sentence-end-double-space nil
auth-sources `(,(expand-file-name "authinfo.gpg" user-emacs-directory)))(defun display-startup-echo-area-message ())
#+end_src** Ligatures
#+begin_src emacs-lisp
(use-package ligature
:init
(global-ligature-mode t)
:config
(ligature-set-ligatures
'haskell-mode '("" ">" "/>" "~-" "-~" "~@" "<~" "<~>" "<~~" "~>" "~~"
"~~>" ">=" "<=" "" "->" "-<"
">->" ">>-" "<<-" "<->" "->>" "-<<" "<-<" "==>" "=>" "=/="
"!==" "!=" "<==" ">>=" "=>>" ">=>" "<=>" "<=<" "<<=" "=<<"
".-" ".=" "=:=" "=!=" "==" "===" "::" ":="
"<|" "<|>" "|>" "<>" "<$" "<$>" "$>" "<+" "<+>" "+>"
"?=" "/=" "/==" "/\\" "\\/" "__" "&&" "++" "+++")))
#+end_src** Magit
#+begin_src emacs-lisp
(use-package magit
:ensure (:source "NonGNU ELPA")
:config
(setopt magit-display-buffer-function #'magit-display-buffer-fullframe-status-v1))(use-package transient
:ensure (:source "NonGNU ELPA"))
#+end_srcLet's add some keys to it.
#+begin_src emacs-lisp
(use-package magit
:ensure nil
:init
(defvar-keymap git-map :doc "Actions related to Git.")
(keymap-set leader-map "g" (cons "Git" git-map))
(setmap git-map
"g" #'magit
"s" #'magit-stage
"u" #'magit-unstage
"c c" #'magit-commit-create
"c a" #'magit-commit-amend
"c f" #'magit-commit-fixup))
#+end_src*** Todos
#+begin_src emacs-lisp
(use-package hl-todo
:ensure (:tag "v3.7.0"))(use-package magit-todos
:after magit
:init
(magit-todos-mode 1)
:config
(setopt magit-todos-exclude-globs
'(".git/" "**/elpaca/")))
#+end_src*** Forge
#+begin_src emacs-lisp
(use-package forge)
#+end_src** Persistence
*** Savehist
#+begin_src emacs-lisp
(use-package savehist
:ensure nil
:hook (after-init . savehist-mode))
#+end_src*** Desktop
#+begin_src emacs-lisp
(with-eval-after-load 'desktop
(add-to-list 'desktop-globals-to-save 'custom-enabled-themes))
(add-hook 'desktop-after-read-hook
(defun desktop-apply-theme-h ()
(dolist (theme custom-enabled-themes)
(load-theme theme :no-confirm))))(add-hook 'elpaca-after-init-hook
(defun enable-desktop-save-h ()
(desktop-read)
(desktop-save-mode 1))
99)
#+end_src** Projects
#+begin_src emacs-lisp
(use-package project
:ensure nil
:config
(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")))
#+end_src** Recentf
#+begin_src emacs-lisp
(use-package recentf
:ensure nil
:hook (after-init . recentf-mode))
#+end_src** Screen cast
#+begin_src emacs-lisp
(use-package gif-screencast
:config
(setopt gif-screencast-program "grim"
gif-screencast-args '()))
#+end_src** Spelling (jinx)
#+begin_src emacs-lisp
(use-package jinx
:hook (text-mode conf-mode)
:config
(setq jinx-languages "pt_BR en_US")
(cl-pushnew 'font-lock-constant-face (cdr (assq 'tex-mode jinx-exclude-faces)))
(define-key evil-visual-state-map "z=" 'jinx-correct)
(define-key evil-normal-state-map "z=" 'jinx-correct))
#+end_srcLet's also add a dir-local saving option.
#+begin_src emacs-lisp
(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
(add-to-list 'jinx--session-words word)
(setq jinx-local-words
(string-join
(sort (delete-dups
(cons word (split-string jinx-local-words)))
#'string<)
" "))
(modify-dir-local-variable major-mode 'jinx-local-words jinx-local-words 'add-or-replace)
(save-buffer)
(kill-buffer))
(list key word "Directory")))
(setopt jinx--save-keys (map-insert jinx--save-keys ?, #'jinx--save-dir)))
#+end_src** Server
#+begin_src emacs-lisp
(use-package server
:ensure nil
:init
(server-force-delete)
(server-start t t))
#+end_src** Tab groups
#+begin_src emacs-lisp
(use-package nerd-icons
:config
(setopt tab-bar-back-button
(nerd-icons-octicon "nf-oct-chevron_left")
tab-bar-forward-button
(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))))
:init
(tab-bar-mode 1)
(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 1)
: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 "*scratch*"))(use-package project-tab-groups
:init
(project-tab-groups-mode 1))
#+end_src**** COMMENT Echo area tab bar
#+begin_src emacs-lisp
(use-package tab-bar-echo-area
:init
(tab-bar-echo-area-mode 1)
:config
(push #'project-switch-project tab-bar-echo-area-trigger-display-functions)
(push #'desktop-read tab-bar-echo-area-trigger-display-functions)
(tab-bar-echo-area-apply-display-tab-names-advice))
#+end_src**** COMMENT Consult source
#+begin_src emacs-lisp
(defun tabspaces-buffer-names ()
(let ((exclude-re (consult--regexp-filter consult-buffer-filter))
(buffers (consult--buffer-sort-visibility
(seq-copy (frame-parameter nil 'buffer-list)))))
(consult--keep! buffers
(unless (or (string-match-p exclude-re (buffer-name it))
(eq (current-buffer) it))
(consult--buffer-pair it)))
buffers))(setq consult--source-tab-local
`(:name "Tab Buffer"
:narrow (?l . "Tab")
:category buffer
:face consult-buffer
:history buffer-name-history
:state ,#'consult--buffer-state
:action ,#'consult--buffer-action
:items ,#'tabspaces-buffer-names
,(lambda () (consult--buffer-query :sort 'visibility
:as #'consult--buffer-pair))))(add-to-list 'consult-buffer-sources 'consult--source-tab-local)
(add-to-list 'consult-project-buffer-sources 'consult--source-tab-local)
#+end_src** Tramp
#+begin_src emacs-lisp
(setq tramp-default-method "ssh")
#+end_src** Terminal
#+begin_src emacs-lisp
(use-package eat)
#+end_src** Text wrapping
#+begin_src emacs-lisp
(use-package adaptive-wrap
:hook ((LaTeX-mode prog-mode) . adaptive-wrap-prefix-mode))
#+end_src** Tree-sitter
*** Builtin
#+begin_src emacs-lisp
(use-package treesit
:ensure nil
:config
(setopt treesit-language-source-alist
'((kdl "https://github.com/tree-sitter-grammars/tree-sitter-kdl.git")
(typescript "https://github.com/tree-sitter/tree-sitter-typescript.git" nil "typescript/src")
(tsx "https://github.com/tree-sitter/tree-sitter-typescript.git" nil "tsx/src"))))
#+end_src
*** External
#+begin_src emacs-lisp
(use-package tree-sitter)
(use-package tree-sitter-langs)
#+end_src* Writing
** Mathematical writing
*** Abbrev
**** Language & math predicate
#+begin_src emacs-lisp
(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)))
#+end_src**** Textual abbrevs
#+begin_src emacs-lisp
(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")))
#+end_src**** Variable abbrevs
#+begin_src emacs-lisp
(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))
#+end_src**** Tables and mode-local tables
#+begin_src emacs-lisp
(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)
(abbrev/set-math-text-lang)
(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 +1))(add-hook 'LaTeX-mode-hook #'abbrev/setup)
#+end_src*** Pretty concealed symbols
Custom predicate for composing only inside LaTeX delimiters.
#+begin_src emacs-lisp
(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)))))))))
#+end_src#+begin_src emacs-lisp
(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 +1))(dolist (h '(LaTeX-mode-hook latex-mode-hook org-mode-hook))
(add-hook h #'math-prettify-activate))
#+end_src*** Citar
#+begin_src emacs-lisp
(use-package citar
:bind (:map LaTeX-mode-map ("C-c @" . citar-insert-citation))
:config
(setopt citar-file-open-functions '(("pdf" . citar-file-open-external)
(t . citar-file-open-external))
citar-bibliography '("/home/lucas/Zotero/bibs/all.bib")
org-cite-csl-styles-dir "/home/lucas/Zotero/styles"
citar-symbol-separator " "))
#+end_src#+begin_src emacs-lisp
(use-package citar-embark
:after (citar embark)
:init
(citar-embark-mode +1))
#+end_src*** Boox attach
#+begin_src emacs-lisp
(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.")))
#+end_src*** AAS setup
#+begin_src emacs-lisp
(use-package aas
:ensure nil
:init
(add-hook 'LaTeX-mode-hook
(defun +activate-aas-h ()
(aas-mode +1)
(aas-activate-keymap 'aas-math)))
:config
(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 "\\(" q "\\)")";cas" '(tempel "\\begin\{cases\}" p "\\end\{cases\}")
:cond #'texmathp
".." "\\dots""+" (i-binop "+")
"-" (i-binop "-")
"=" (i-binop "=")
"<" (i-binop "<")
">" (i-binop ">")"_" '(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")"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"))
#+end_src*** Evil-tex
#+begin_src emacs-lisp
(use-package evil-tex
:hook ((LaTeX-mode org-mode) . evil-tex-mode))
#+end_src
** Denote and friends
#+begin_src emacs-lisp
(use-package denote)
(use-package denote-explore)
(use-package denote-refs)
(use-package consult-denote
:after (:and denote consult)
:init
(consult-denote-mode 1))
(use-package denote-menu)
#+end_src**** Citar-denote
#+begin_src emacs-lisp
(use-package citar-denote
:after denote
:init
(citar-denote-mode 1))
#+end_src** Mixed-pitch
#+begin_src emacs-lisp
(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 5)))
(add-to-list 'mixed-pitch-fixed-pitch-faces 'rainbow-delimiters-depth-1-face))(use-package rainbow-delimiters
:hook (LaTeX-mode))
#+end_src* Looks and UI
** Fonts and faces
#+begin_src emacs-lisp
(custom-set-faces
'(default ((t (:weight medium :height 155 :family "Victor Mono"))))
'(fixed-pitch ((t (:family "Victor Mono"))))
'(variable-pitch ((t (:weight normal :family "IBM Plex Sans"))))
'(ef-themes-ui-variable-pitch ((t (:inherit variable-pitch)))))
#+end_src*** Unicode
#+begin_src emacs-lisp
(setopt use-default-font-for-symbols t)(defun adjust-symbolic-fonts ()
(dolist (script '(symbol mathematical unicode))
(set-fontset-font t script (font-spec :family "Julia Mono") nil 'prepend))
(set-fontset-font t 'emoji "Twemoji" nil 'prepend))(adjust-symbolic-fonts)
(add-hook 'after-setting-font-hook #'adjust-symbolic-fonts)
#+end_src** Layout
*** Built-in
#+begin_src emacs-lisp
(setopt tool-bar-mode nil
scroll-bar-mode nil
menu-bar-mode nil)
#+end_src*** Olivetti
#+begin_src emacs-lisp
(use-package olivetti
:hook ((text-mode prog-mode) . olivetti-mode)
:commands olivetti-mode
:bind (:map toggle-map ("e" . olivetti-mode))
:config
(setopt olivetti-body-width 100))
#+end_src** Theme
*** EF themes
#+begin_src emacs-lisp
(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-arbutus ef-dream)
ef-themes-mixed-fonts t
ef-themes-variable-pitch-ui t))
#+end_src*** 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.#+begin_src emacs-lisp
(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)))
#+end_src** Modeline
#+begin_src emacs-lisp
(use-package doom-modeline
:init
(doom-modeline-mode 1)
:custom-face
(mode-line ((t (:family "Julia Mono" :height 108))))
(mode-line-inactive ((t (:family "Julia Mono" :height 108))))
(doom-modeline-buffer-modified ((t (:underline t))))
:config
(setopt doom-modeline-irc nil
doom-modeline-height 22
doom-modeline-buffer-encoding nil
doom-modeline-workspace-name nil
doom-modeline-bar-width 1
doom-modeline-icon nil)(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)))#+end_src
*** MLScroll
#+begin_src emacs-lisp
(use-package mlscroll
:init
(mlscroll-mode +1))
#+end_src** Treemacs
#+begin_src emacs-lisp
(use-package treemacs
:bind (:map toggle-map
("p" . treemacs)))(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))
#+end_src* Terminal screen
** Cursor, mouse
#+begin_src emacs-lisp
(setopt xterm-set-window-title t
visible-cursor nil)
(add-hook 'tty-setup-hook #'xterm-mouse-mode)
#+end_src#+begin_src emacs-lisp
(use-package evil-terminal-cursor-changer
:hook (tty-setup . evil-terminal-cursor-changer-activate))
#+end_src** Kitty Keyboard Protocol
#+begin_src emacs-lisp
(use-package kkp
:hook (tty-setup . global-kkp-mode))
#+end_src* Languages
** Elisp
*** Parinfer
#+begin_src emacs-lisp
(use-package parinfer-rust-mode
:hook emacs-lisp-mode)
#+end_src*** Highlighting
#+begin_src emacs-lisp
(use-package highlight-defined
:custom-face (highlight-defined-face-name-face ((t (:inherit nil))))
:hook (emacs-lisp-mode . highlight-defined-mode))
#+end_src** Haskell
#+begin_src emacs-lisp
(use-package haskell-mode)
#+end_src*** Eglot
#+begin_src emacs-lisp
(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))))))
#+end_src*** COMMENT Lsp-mode
#+begin_src emacs-lisp
(use-package lsp-haskell
:after '(lsp-mode haskell-mode)
:config
(setopt lsp-haskell-server-path "haskell-language-server-wrapper"
lsp-haskell-formatting-provider "fourmolu"
lsp-haskell-plugin-eval-global-on t
lsp-haskell-plugin-class-global-on nil
lsp-haskell-plugin-ghcide-type-lenses-global-on t
lsp-haskell-plugin-ghcide-completions-config-auto-extend-on t
lsp-haskell-plugin-import-lens-code-lens-on nil
lsp-haskell-plugin-import-lens-code-actions-on t)
(lsp-defcustom lsp-haskell-plugin-semantic-tokens t
"Enables semtok"
:type 'boolean
:group 'lsp-haskell-plugins
:package-version '(lsp-mode . "8.0.1")
:lsp-path "haskell.plugin.semanticTokens.globalOn"))
#+end_src** Julia
#+begin_src emacs-lisp
(use-package julia-snail
:custom
(julia-snail-terminal-type :eat)
(julia-indent-offset 2)
:hook
(julia-mode . julia-snail-mode))
#+end_src** KDL
#+begin_src emacs-lisp
(use-package kdl-ts-mode
:ensure (:repo "https://github.com/dataphract/kdl-ts-mode.git" :main "kdl-ts-mode.el"))
#+end_src** Textual modes
#+begin_src emacs-lisp
(with-eval-after-load 'text-mode
(setopt text-mode-ispell-word-completion nil))
#+end_src** HTMl
#+begin_src emacs-lisp
(use-package web-mode)
#+end_src** LaTeX
#+begin_src emacs-lisp
(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))
#+end_src*** AucTeX
#+begin_src emacs-lisp
(use-package tex
:ensure (auctex :pre-build (("./autogen.sh")
("./configure"
"--with-texmf-dir=$(dirname $(kpsexpand '$TEXMFHOME'))")
("make")))
:hook ((LaTeX-mode org-mode) . (lambda () (require 'latex) (LaTeX-math-mode))))(with-eval-after-load 'tex
(setopt TeX-parse-self t
TeX-auto-save t))
#+end_src*** Reftex
#+begin_src emacs-lisp
(use-package reftex
:ensure nil
:hook (LaTeX-mode . turn-on-reftex)
:config
(setopt reftex-label-alist '(("theorem" 104 "thm:" nil nil nil -3)
("lemma" 108 "lem:" nil nil nil -3))
reftex-ref-style-default-list '("Cleveref" "AMSmath")
reftex-plug-into-AUCTeX t
reftex-insert-label-flags '("s" "sfthl")))
#+end_src*** 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.#+begin_src emacs-lisp
(use-package latex
:ensure nil
:hook (LaTeX-mode . eglot-ensure)
: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))))(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 "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)))
#+end_src** Lean
#+begin_src emacs-lisp
(use-package lean4-mode
:ensure (lean4-mode :repo "~/dados/projetos/codigo/emacs/lean4-eglot-mode/"
:files ("*.el" "data")))
#+end_src** Markdown
#+begin_src emacs-lisp
(use-package markdown-mode)
#+end_src** Org
#+begin_src emacs-lisp
(use-package org
:mode ("\\.org\\'" . org-mode)
:commands (org-mode)
:config
(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)
(evil-define-key 'normal org-mode-map "\\" #'org-edit-special)
(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-fold-core-style 'text-properties
org-startup-indented t
org-support-shift-select t
org-insert-heading-respect-content t
org-hide-leading-stars t
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)))
#+end_src*** Organon
#+begin_src emacs-lisp
(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)))))
#+end_src*** Skip 'SUBTREE'
#+begin_src emacs-lisp
(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))))
#+end_src*** Appearance
#+begin_src emacs-lisp
(use-package org-superstar
:after (org)
:hook (org-mode . org-superstar-mode)
:config
(setq org-superstar-headline-bullets-list '(?β ?β ?π± ?π½ ?βΊ)))
#+end_src*** Roam
#+begin_src emacs-lisp
(use-package org-roam
:custom
(org-roam-directory (file-truename "/home/lucas/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))
#+end_src
#+begin_src emacs-lisp
(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))))
#+end_src** YAML
#+begin_src emacs-lisp
(use-package yaml-mode)
#+end_src