#+PROPERTY: header-args:emacs-lisp :tangle ./.emacs.d/init.el :mkdirp yes #+TODO: CHECK(s) | OFF(o) #+begin_quote One day we won't hate one another, no young boy will march to war and I will clean up my Emacs config. But that day isn't today. #+end_quote My [[https://www.gnu.org/software/emacs/][Emacs]] configuration. As with other files in the repo, parts prefixed with (OFF) are not used but kept for historic purposes. | Note | Type | |------+------------------------------------| | TODO | Find a way to specify dependencies | * Primary setup ** Measure startup speed A small function to print out the loading time and number of GCs during the loading. Can be useful as a point of data for optimizing Emacs startup time. #+begin_src emacs-lisp (add-hook 'emacs-startup-hook (lambda () (message "*** Emacs loaded in %s with %d garbage collections." (format "%.2f seconds" (float-time (time-subtract after-init-time before-init-time))) gcs-done))) #+end_src ** straight.el Straight.el is my Emacs package manager of choice. Its advantages & disadvantages over other options are listed pretty thoroughly in the README file in the repo. The following is a straight.el bootstrap script. References: - [[https://github.com/raxod502/straight.el][straight.el repo]] #+begin_src emacs-lisp (defvar bootstrap-version) (let ((bootstrap-file (expand-file-name "straight/repos/straight.el/bootstrap.el" user-emacs-directory)) (bootstrap-version 5)) (unless (file-exists-p bootstrap-file) (with-current-buffer (url-retrieve-synchronously "https://raw.githubusercontent.com/raxod502/straight.el/develop/install.el" 'silent 'inhibit-cookies) (goto-char (point-max)) (eval-print-last-sexp))) (load bootstrap-file nil 'nomessage)) #+end_src ** use-package A macro to simplify package specification & configuration. Integrates with straight.el. Set ~use-package-verbose~ to ~t~ to print out individual package loading time. References: - [[https://github.com/jwiegley/use-package][use-package repo]] #+begin_src emacs-lisp (straight-use-package 'use-package) (eval-when-compile (require 'use-package)) ;; (setq use-package-verbose t) #+end_src ** Performance *** Garbage collection Just setting ~gc-cons-treshold~ to a larger value. | Note | Type | |-------+---------------------------------------------------| | CHECK | The value may be too large for an interactive use | #+begin_src emacs-lisp (setq gc-cons-threshold 80000000) (setq read-process-output-max (* 1024 1024)) #+end_src *** Run garbage collection when Emacs is unfocused Run GC when Emacs loses focus. Time will tell if that's a good idea. #+begin_src emacs-lisp (add-hook 'emacs-startup-hook (lambda () (if (boundp 'after-focus-change-function) (add-function :after after-focus-change-function (lambda () (unless (frame-focus-state) (garbage-collect)))) (add-hook 'after-focus-change-function 'garbage-collect)))) #+end_src *** Misc The following variable is true when my machine is not powerful enough for some resource-heavy packages. #+begin_src emacs-lisp (setq my/lowpower (string= (system-name) "pntk")) #+end_src ** Anaconda & environment [[https://www.anaconda.com/][Anaconda]] is a free package and environment manager. I currently use it to manage multiple versions of Python and Node.js The following code uses the conda package to activate the base environment on startup if Emacs is launched outside the environment. References: - [[https://docs.anaconda.com/][Anaconda docs]] - [[https://github.com/necaris/conda.el][conda.el repo]] #+begin_src emacs-lisp (use-package conda :straight t :config (setq conda-anaconda-home (expand-file-name "~/Programs/miniconda3/")) (setq conda-env-home-directory (expand-file-name "~/Programs/miniconda3/")) (setq conda-env-subdirectory "envs")) (if (not (getenv "CONDA_DEFAULT_ENV")) (conda-env-activate "base")) #+end_src Also, I sometimes need to know if a program is running inside Emacs (say, inside a terminal emulator). To do that, I set the following environment variable: #+begin_src emacs-lisp (setenv "IS_EMACS" "true") #+end_src ** Custom file location By default, custom writes stuff to =init.el=, which is somewhat annoying. The following makes a separate file =custom.el= #+begin_src emacs-lisp (setq custom-file (concat user-emacs-directory "custom.el")) (load custom-file 'noerror) #+end_src * Global editing configuration ** General keybindings stuff *** general.el general.el provides a convenient interface to manage Emacs keybindings. References: - [[https://github.com/noctuid/general.el][general.el repo]] #+begin_src emacs-lisp (use-package general :straight t :config (general-evil-setup)) #+end_src *** which-key A package that displays the available keybindings in a popup. Pretty useful, as Emacs seems to have more keybindings than I can remember at any given point. References: - [[https://github.com/justbur/emacs-which-key][which-key repo]] #+begin_src emacs-lisp (use-package which-key :config (setq which-key-idle-delay (if my/lowpower 1 0.3)) (setq which-key-popup-type 'frame) (which-key-mode) (which-key-setup-side-window-bottom) (set-face-attribute 'which-key-local-map-description-face nil :weight 'bold) :straight t) #+end_src ** Evil mode A whole ecosystem of packages that emulates the main features of Vim. Probably the best vim emulator out there. The only problem is that the package name makes it hard to google anything by just typing "evil". References: - [[https://github.com/emacs-evil/evil][evil repo]] - [[https://www.youtube.com/watch?v=JWD1Fpdd4Pc][(YouTube) Evil Mode: Or, How I Learned to Stop Worrying and Love Emacs]] *** evil Basic evil configuration. #+begin_src emacs-lisp (use-package evil :straight t :init (setq evil-want-integration t) (setq evil-want-C-u-scroll t) (setq evil-want-keybinding nil) :config (evil-mode 1) (setq evil-search-module 'evil-search) (setq evil-split-window-below t) (setq evil-vsplit-window-right t) ;; (setq evil-respect-visual-line-mode t) (evil-set-undo-system 'undo-tree) ;; (add-to-list 'evil-emacs-state-modes 'dired-mode) ) #+end_src *** Addons [[https://github.com/emacs-evil/evil-surround][evil-surround]] emulates one of my favorite vim plugins, surround.vim. Adds a lot of parentheses management options. #+begin_src emacs-lisp (use-package evil-surround :straight t :after evil :config (global-evil-surround-mode 1)) #+end_src [[https://github.com/linktohack/evil-commentary][evil-commentary]] emulates commentary.vim. #+begin_src emacs-lisp (use-package evil-commentary :straight t :after evil :config (evil-commentary-mode)) #+end_src [[https://github.com/blorbx/evil-quickscope][evil-quickscope]] emulates quickscope.vim. It highlights the important target characters for f, F, t, T keys. #+begin_src emacs-lisp (use-package evil-quickscope :straight t :after evil :config :hook ((prog-mode . turn-on-evil-quickscope-mode) (LaTeX-mode . turn-on-evil-quickscope-mode))) #+end_src *** evil-collection [[https://github.com/emacs-evil/evil-collection][evil-collection]] is a package that provides evil bindings for a lot of different packages. One can see the whole list in the [[https://github.com/emacs-evil/evil-collection/tree/master/modes][modes]] folder. I don't enable the entire package, just the modes I need. #+begin_src emacs-lisp (use-package evil-collection :straight t :after evil :config (evil-collection-init '(eww dired company vterm flycheck profiler cider explain-pause-mode notmuch custom xref eshell helpful compile comint magit))) #+end_src ** More keybindigs The main keybindigs setup is positioned after evil mode to take the latter into account. *** Escape key Use escape key instead of =C-g= whenever possible. I must have copied it from somewhere, but as I googled to find out the original source, I discovered quite a number of variations of the following code over time. I wonder if Richard Dawkins was inspired by something like this a few decades ago. #+begin_src emacs-lisp (defun minibuffer-keyboard-quit () "Abort recursive edit. In Delete Selection mode, if the mark is active, just deactivate it; then it takes a second \\[keyboard-quit] to abort the minibuffer." (interactive) (if (and delete-selection-mode transient-mark-mode mark-active) (setq deactivate-mark t) (when (get-buffer "*Completions*") (delete-windows-on "*Completions*")) (abort-recursive-edit))) (general-define-key :keymaps '(normal visual global) [escape] 'keyboard-quit) (general-define-key :keymaps '(minibuffer-local-map minibuffer-local-ns-map minibuffer-local-completion-map minibuffer-local-must-match-map minibuffer-local-isearch-map) [escape] 'minibuffer-keyboard-quit) #+end_src *** Home & end #+begin_src emacs-lisp (general-def :states '(normal insert visual) "" 'beginning-of-line "" 'end-of-line) #+end_src *** My leader Using the =SPC= key as a sort of a leader key. #+begin_src emacs-lisp (general-create-definer my-leader-def :keymaps 'override :prefix "SPC" :states '(normal motion emacs)) (general-def :keymaps 'override :states '(normal motion emacs insert visual) "M-u" 'universal-argument) (general-def :states '(normal motion emacs) "SPC" nil) (my-leader-def "?" 'which-key-show-top-level) (my-leader-def "E" 'eval-expression) #+end_src *** Profiler The built-in profiler is a magnificent tool to troubleshoot performance issues. #+begin_src emacs-lisp (my-leader-def "Ps" 'profiler-start) (my-leader-def "Pe" 'profiler-stop) (my-leader-def "Pp" 'profiler-report) #+end_src *** Buffer switching Some keybindings I used in vim to switch buffer and can't let go of. #+begin_src emacs-lisp (general-define-key :keymaps 'override "C-" 'evil-window-right "C-" 'evil-window-left "C-" 'evil-window-up "C-" 'evil-window-down "C-h" 'evil-window-left "C-l" 'evil-window-right "C-k" 'evil-window-up "C-j" 'evil-window-down "C-x h" 'previous-buffer "C-x l" 'next-buffer) #+end_src And winner-mode to keep a history of window states. #+begin_src emacs-lisp (winner-mode 1) (define-key evil-window-map (kbd "u") 'winner-undo) (define-key evil-window-map (kbd "U") 'winner-redo) #+end_src *** xref Some keybindings for xref, Emacs' built-in systems for managing identifiers. #+begin_src emacs-lisp (general-nmap "gD" 'xref-find-definitions-other-window "gr" 'xref-find-references) (my-leader-def "fx" 'xref-find-apropos) #+end_src *** Folding #+begin_src emacs-lisp (general-nmap "TAB" 'evil-toggle-fold) (general-nmap :keymaps 'hs-minor-mode-map "ze" 'hs-hide-level) #+end_src *** Zoom #+begin_src emacs-lisp (defun my/zoom-in () "Increase font size by 10 points" (interactive) (set-face-attribute 'default nil :height (+ (face-attribute 'default :height) 10))) (defun my/zoom-out () "Decrease font size by 10 points" (interactive) (set-face-attribute 'default nil :height (- (face-attribute 'default :height) 10))) ;; change font size, interactively (global-set-key (kbd "C-+") 'my/zoom-in) (global-set-key (kbd "C-=") 'my/zoom-out) #+end_src ** Editing helpers & config *** Visual fill column mode #+begin_src emacs-lisp (use-package visual-fill-column :straight t :config (add-hook 'visual-fill-column-mode-hook (lambda () (setq visual-fill-column-center-text t)))) #+end_src *** smartparens A minor mode to deal with pairs. Its functionality overlaps with evil-surround, but smartparens provides the most comfortable way to do stuff like automatically insert pairs. References: - [[https://github.com/Fuco1/smartparens][smartparens repo]] #+begin_src emacs-lisp (use-package smartparens :straight t) #+end_src *** Aggressive Indent A package to keep the code intended. Doesn't work too well with js ecosystem, because the lsp-based indentation is rather slow, but nice for Lisps. References: - [[https://github.com/Malabarba/aggressive-indent-mode][aggressive-indent-mode repo]] #+begin_src emacs-lisp (use-package aggressive-indent :straight t) #+end_src *** Tabs Some default settings to manage tabs. #+begin_src emacs-lisp (setq tab-always-indent nil) (setq default-tab-width 4) (setq tab-width 4) (setq evil-indent-convert-tabs nil) (setq indent-tabs-mode nil) (setq tab-width 4) (setq evil-shift-round nil) #+end_src *** Scrolling config #+begin_src emacs-lisp (setq scroll-conservatively scroll-margin) (setq scroll-step 1) (setq scroll-preserve-screen-position t) (setq scroll-error-top-bottom t) (setq mouse-wheel-progressive-speed nil) (setq mouse-wheel-inhibit-click-time nil) #+end_src *** Clipboard config #+begin_src emacs-lisp (setq select-enable-clipboard t) (setq mouse-yank-at-point t) #+end_src *** Backups #+begin_src emacs-lisp (setq backup-inhibited t) (setq auto-save-default nil) #+end_src ** Undo Tree Replaces Emacs build-in sequential undo system with a tree-based one. Probably one of the greatest features of Emacs as a text editor. References: - [[https://www.emacswiki.org/emacs/UndoTree][UndoTree on EmacsWiki]] #+begin_src emacs-lisp (use-package undo-tree :straight t :config (global-undo-tree-mode) (setq undo-tree-visualizer-diff t) (setq undo-tree-visualizer-timestamps t) (my-leader-def "u" 'undo-tree-visualize) (fset 'undo-auto-amalgamate 'ignore) (setq undo-limit 6710886400) (setq undo-strong-limit 100663296) (setq undo-outer-limit 1006632960)) #+end_src ** Help [[https://github.com/Wilfred/helpful][helpful]] package improves the =*help*= buffer. #+begin_src emacs-lisp (use-package helpful :straight t :commands (helpful-callable helpful-variable helpful-key helpful-macro helpful-function helpful-command)) #+end_src As I use =C-h= to switch buffers, I moved the help to =SPC-h= with the code below. Of course, I didn't type it all by hand. #+begin_src emacs-lisp (my-leader-def :infix "h" "RET" 'view-order-manuals "." 'display-local-help "?" 'help-for-help "C" 'describe-coding-system "F" 'Info-goto-emacs-command-node "I" 'describe-input-method "K" 'Info-goto-emacs-key-command-node "L" 'describe-language-environment "P" 'describe-package "S" 'info-lookup-symbol "a" 'helm-apropos "b" 'describe-bindings "c" 'describe-key-briefly "d" 'apropos-documentation "e" 'view-echo-area-messages "f" 'helpful-function "g" 'describe-gnu-project "h" 'view-hello-file "i" 'info "k" 'helpful-key "l" 'view-lossage "m" 'describe-mode "n" 'view-emacs-news "o" 'describe-symbol "p" 'finder-by-keyword "q" 'help-quit "r" 'info-emacs-manual "s" 'describe-syntax "t" 'help-with-tutorial "v" 'helpful-variable "w" 'where-is "" 'help-for-help "C-\\" 'describe-input-method "C-a" 'about-emacs "C-c" 'describe-copying "C-d" 'view-emacs-debugging "C-e" 'view-external-packages "C-f" 'view-emacs-FAQ "C-h" 'help-for-help "C-n" 'view-emacs-news "C-o" 'describe-distribution "C-p" 'view-emacs-problems "C-s" 'search-forward-help-for-help "C-t" 'view-emacs-todo "C-w" 'describe-no-warranty) #+end_src ** Ivy, counsel, swiper Minibuffer completion tools for Emacs. References: - [[https://oremacs.com/swiper/][repo]] - [[https://oremacs.com/swiper/][User Manual]] #+begin_src emacs-lisp (use-package ivy :straight t :config (setq ivy-use-virtual-buffers t) (ivy-mode)) (use-package counsel :straight t :after ivy :config (counsel-mode)) (use-package swiper :defer t :straight t) #+end_src *** ivy-rich [[https://github.com/Yevgnen/ivy-rich][ivy-rich]] provides more informative interface for ivy. #+begin_src emacs-lisp (use-package ivy-rich :straight t :after ivy :config (ivy-rich-mode 1) (setcdr (assq t ivy-format-functions-alist) #'ivy-format-function-line)) #+end_src *** Keybindings #+begin_src emacs-lisp (my-leader-def :infix "f" "b" 'ivy-switch-buffer "e" 'conda-env-activate "f" 'project-find-file "c" 'counsel-yank-pop "a" 'counsel-rg "A" 'counsel-ag) (general-imap "C-y" 'counsel-yank-pop) (my-leader-def "SPC" 'ivy-resume) (my-leader-def "s" 'swiper-isearch "S" 'swiper-all) (general-define-key :keymaps '(ivy-minibuffer-map swiper-map) "M-j" 'ivy-next-line "M-k" 'ivy-previous-line "" 'ivy-call "M-RET" 'ivy-immediate-done [escape] 'minibuffer-keyboard-quit) #+end_src ** OFF (OFF) Helm Config for the Helm incremental completion framework. I switched to Ivy some time ago, but keep the configuration just in case. #+begin_src emacs-lisp :tangle no (use-package helm :init (require 'helm-config) (setq helm-split-window-in-side-p t) (setq helm-move-to-line-cycle-in-source t) :straight t :config (helm-mode 1) (helm-autoresize-mode 1)) (use-package helm-ag :straight t) (use-package helm-rg :straight t) (general-nmap :keymaps 'helm-ag-mode-map "RET" 'helm-ag-mode-jump "M-RET" 'helm-ag-mode-jump-other-window) (general-nmap :keymaps 'helm-occur-mode-map "RET" 'helm-occur-mode-goto-line "M-RET" 'helm-occur-mode-goto-line-ow) (general-define-key "M-x" 'helm-M-x) (my-leader-def "fb" 'helm-buffers-list "fs" 'helm-lsp-workspace-symbol "fw" 'helm-lsp-global-workspace-symbol "fc" 'helm-show-kill-ring ;; "fa" 'helm-do-ag-project-root "fm" 'helm-bookmarks "ff" 'project-find-file "fe" 'conda-env-activate) (my-leader-def "s" 'helm-occur) (my-leader-def "SPC" 'helm-resume) (general-define-key :keymaps 'helm-map "C-j" 'helm-next-line "C-k" 'helm-previous-line) (general-define-key :keymaps '(helm-find-files-map helm-locate-map) "C-h" 'helm-find-files-up-one-level "C-l" 'helm-execute-persistent-action) (general-imap "C-y" 'helm-show-kill-ring) ;; (general-nmap "C-p" 'project-find-file) #+end_src ** Treemacs [[https://github.com/Alexander-Miller/treemacs][Treemacs]] calls itself a tree layout file explorer, but looks more like a project and workspace management system. Integrates with evil, magit and projectile. #+begin_src emacs-lisp (use-package treemacs :straight t :commands (treemacs treemacs-switch-workspace treemacs-edit-workspace) :config (setq treemacs-follow-mode nil) (setq treemacs-follow-after-init nil) (setq treemacs-space-between-root-nodes nil) (treemacs-git-mode 'extended) (with-eval-after-load 'treemacs (add-to-list 'treemacs-pre-file-insert-predicates #'treemacs-is-file-git-ignored?))) (use-package treemacs-evil :after (treemacs evil) :straight t) (use-package treemacs-magit :after (treemacs magit) :straight t) (general-define-key :keymaps '(normal override global) "C-n" 'treemacs) (general-define-key :keymaps '(treemacs-mode-map) [mouse-1] #'treemacs-single-click-expand-action) (my-leader-def "tw" 'treemacs-switch-workspace "te" 'treemacs-edit-workspaces) #+end_src ** Projectile [[https://github.com/bbatsov/projectile][Projectile]] gives a bunch of useful functions for managing projects, like finding files within a project, fuzzy-find, replace, etc. #+begin_src emacs-lisp (use-package projectile :straight t :config (projectile-mode +1) (setq projectile-project-search-path '("~/Code" "~/Documents"))) (use-package counsel-projectile :after (counsel projectile) :straight t) (use-package treemacs-projectile :after (treemacs projectile) :straight t) (my-leader-def "p" 'projectile-command-map) (general-nmap "C-p" 'counsel-projectile-find-file) #+end_src ** Company A completion framework for Emacs. References: - [[http://company-mode.github.io/][company homepage]] - [[https://github.com/sebastiencs/company-box][company-box homepage]] #+begin_src emacs-lisp (use-package company :straight t :config (global-company-mode) (setq company-idle-delay (if my/lowpower 0.5 0.125)) (setq company-dabbrev-downcase nil) (setq company-show-numbers t)) (general-imap "C-SPC" 'company-complete) #+end_src A company frontend with nice icons. #+begin_src emacs-lisp (use-package company-box :straight t :if (not my/lowpower) :after (company) :hook (company-mode . company-box-mode)) #+end_src ** Git & Magit [[https://magit.vc/][Magic]] is a git interface for Emacs. The closest non-Emacs alternative (sans actual clones) I know is [[https://github.com/jesseduffield/lazygit][lazygit]], which I used before Emacs. Also, [[https://github.com/emacsorphanage/git-gutter][git-gutter]] is plugin which shows git changes for each line (added/changed/deleted lines). #+begin_src emacs-lisp (use-package magit :straight t :commands (magit-status magit-file-dispatch) :config (setq magit-blame-styles '((margin (margin-format . ("%a %A %s")) (margin-width . 42) (margin-face . magit-blame-margin) (margin-body-face . (magit-blame-dimmed))) (headings (heading-format . "%-20a %C %s\n")) (highlight (highlight-face . magit-blame-highlight)) (lines (show-lines . t) (show-message . t))) )) (use-package git-gutter :straight t :config (global-git-gutter-mode +1)) (my-leader-def "m" 'magit "M" 'magit-file-dispatch) #+end_src ** Editorconfig Editorconfig support for Emacs. References: - [[https://editorconfig.org/][Editorconfig reference]] #+begin_src emacs-lisp (use-package editorconfig :straight t :config (editorconfig-mode 1)) #+end_src ** OFF (OFF) Avy #+begin_src emacs-lisp :tangle no (use-package avy :straight t) (general-nmap "\\w" 'avy-goto-word-0-below) (general-nmap "\\b" 'avy-goto-word-0-above) #+end_src ** Snippets A snippet system for Emacs and a collection of pre-built snippets. References: - [[http://joaotavora.github.io/yasnippet/][yasnippet documentation]] #+begin_src emacs-lisp (use-package yasnippet :straight t :config (yas-global-mode 1)) (use-package yasnippet-snippets :straight t) (general-imap "M-TAB" 'company-yasnippet) #+end_src ** Time trackers A bunch of timetrackers I use. References: - [[https://wakatime.com][WakaTime]] - [[https://activitywatch.net/][ActivityWatch]] *** WakaTime #+begin_src emacs-lisp (use-package wakatime-mode :straight t :config (global-wakatime-mode)) #+end_src *** ActivityWatch #+begin_src emacs-lisp (use-package request :straight t) (use-package activity-watch-mode :straight t :config (global-activity-watch-mode)) #+end_src * Dired Dired is a built-in file manager. I use it as my primary file manager, hence the top level of config. ** Basic config & keybindings My config mostly follows ranger's and vifm's keybindings which I'm used to. #+begin_src emacs-lisp (use-package dired :ensure nil :custom ((dired-listing-switches "-alh --group-directories-first")) :commands (dired) :config (setq dired-dwim-target t) (setq wdired-allow-to-change-permissions t) (setq wdired-create-parent-directories t) (setq dired-recursive-copies 'always) (setq dired-recursive-deletes 'always) (add-hook 'dired-mode-hook (lambda () (setq truncate-lines t) (visual-line-mode nil))) (evil-collection-define-key 'normal 'dired-mode-map "h" 'dired-single-up-directory "l" 'dired-single-buffer "h" 'dired-single-up-directory "l" 'dired-single-buffer "=" 'dired-narrow "-" 'dired-create-empty-file (kbd "") 'dired-single-up-directory (kbd "") 'dired-single-buffer) (general-define-key :keymaps 'dired-mode-map [remap dired-find-file] 'dired-single-buffer [remap dired-mouse-find-file-other-window] 'dired-single-buffer-mouse [remap dired-up-directory] 'dired-single-up-directory "M-" 'dired-open-xdg)) (my-leader-def "ad" 'dired) #+end_src ** Addons [[https://www.emacswiki.org/emacs/DiredPlus][Dired+]] provides a lot of extensions for dired functionality. #+begin_src emacs-lisp (use-package dired+ :straight t :after dired :init (setq diredp-hide-details-initially-flag nil)) #+end_src Reuse the current dired buffer instead of spamming new ones. #+begin_src emacs-lisp (use-package dired-single :after dired :straight t) #+end_src Display icons for files. | Note | Type | |-----------+-----------------------------------------| | *ACHTUNG* | This plugin is slow as hell with TRAMP | #+begin_src emacs-lisp (use-package all-the-icons-dired :straight t :if (not my/lowpower) :after dired :config (add-hook 'dired-mode-hook 'all-the-icons-dired-mode) (advice-add 'dired-add-entry :around #'all-the-icons-dired--refresh-advice) (advice-add 'dired-remove-entry :around #'all-the-icons-dired--refresh-advice)) #+end_src Provides stuff like =dired-open-xdg= #+begin_src emacs-lisp (use-package dired-open :after dired :straight t) #+end_src vifm-like filter #+begin_src emacs-lisp (use-package dired-narrow :after dired :straight t :config (general-define-key :keymaps 'dired-narrow-map [escape] 'keyboard-quit)) #+end_src * Shells ** vterm My terminal emulator of choice. References: - [[https://github.com/akermu/emacs-libvterm][emacs-libvterm repo]] *** Configuration #+begin_src emacs-lisp (use-package vterm :straight t :commands (vterm vterm-other-window) :config (setq vterm-kill-buffer-on-exit t) (add-hook 'vterm-mode-hook (lambda () (setq-local global-display-line-numbers-mode nil) (display-line-numbers-mode 0))) (general-define-key :keymaps 'vterm-mode-map "M-q" 'vterm-send-escape "C-h" 'evil-window-left "C-l" 'evil-window-right "C-k" 'evil-window-up "C-j" 'evil-window-down "C-" 'evil-window-right "C-" 'evil-window-left "C-" 'evil-window-up "C-" 'evil-window-down "M-" 'vterm-send-left "M-" 'vterm-send-right "M-" 'vterm-send-up "M-" 'vterm-send-down) (general-imap :keymaps 'vterm-mode-map "C-r" 'vterm-send-C-r "C-k" 'vterm-send-C-k "C-j" 'vterm-send-C-j "M-l" 'vterm-send-right "M-h" 'vterm-send-left)) (general-nmap "~" 'vterm) #+end_src *** Subterminal Open a terminal in the lower third of the frame with the =`= key. That's mostly how I use vterm. #+begin_src emacs-lisp (add-to-list 'display-buffer-alist `(,"vterm-subterminal.*" (display-buffer-reuse-window display-buffer-in-side-window) (side . bottom) (reusable-frames . visible) (window-height . 0.33))) (defun my/toggle-vterm-subteminal () "Toogle subteminal." (interactive) (let ((vterm-window (seq-find (lambda (window) (string-match "vterm-subterminal.*" (buffer-name (window-buffer window)))) (window-list)))) (if vterm-window (if (eq (get-buffer-window (current-buffer)) vterm-window) (kill-buffer (current-buffer)) (select-window vterm-window)) (vterm-other-window "vterm-subterminal")))) (general-nmap "`" 'my/toggle-vterm-subteminal) #+end_src ** Eshell A shell written in Emacs lisp. I don't use it as of now, but keep the config just in case. #+begin_src emacs-lisp (defun my/configure-eshell () (add-hook 'eshell-pre-command-hook 'eshell-save-some-history) (add-to-list 'eshell-output-filter-functions 'eshell-truncate-buffer) (setq eshell-history-size 10000) (setq eshell-hist-ingnoredups t) (setq eshell-buffer-maximum-lines 10000) (evil-define-key '(normal insert visual) eshell-mode-map (kbd "") 'eshell-bol) (evil-define-key '(normal insert visual) eshell-mode-map (kbd "C-r") 'counsel-esh-history) (evil-collection-define-key 'normal 'eshell-mode-map (kbd "C-h") 'evil-window-left (kbd "C-l") 'evil-window-right (kbd "C-k") 'evil-window-up (kbd "C-j") 'evil-window-down)) (use-package eshell :ensure nil :after evil-collection :commands (eshell) :config (add-hook 'eshell-first-time-mode-hook 'my/configure-eshell 90) (setq eshell-banner-message "")) (use-package aweshell :straight (:repo "manateelazycat/aweshell" :host github) :after eshell :config (setq eshell-highlight-prompt nil) (setq eshell-prompt-function 'epe-theme-pipeline)) ;; (general-nmap "`" 'aweshell-dedicated-toggle) ;; (general-nmap "~" 'eshell) #+end_src * Org Mode The best feature of Emacs. Just after every other best feature of Emacs, probably. References: - [[https://orgmode.org/][Org Mode homepage]] - [[https://orgmode.org/manual/][Manual]] ** Installation & basic settings Use the built-in org mode. #+begin_src emacs-lisp (use-package org :straight (:type built-in)) (setq org-directory (expand-file-name "~/Documents/org-mode")) (setq org-default-notes-file (concat org-directory "/notes.org")) (setq org-startup-indented t) (setq org-return-follows-link t) (add-hook 'org-mode-hook (lambda () (rainbow-delimiters-mode 0))) #+end_src *** Encryption #+begin_src emacs-lisp (require 'org-crypt) (org-crypt-use-before-save-magic) (setq org-tags-exclude-from-inheritance (quote ("crypt"))) (setq org-crypt-key nil) #+end_src ** Integration with evil #+begin_src emacs-lisp (use-package evil-org :straight t :after (org evil-collection) :config (add-hook 'org-mode-hook 'evil-org-mode) (add-hook 'org-mode-hook #'smartparens-mode) (add-hook 'evil-org-mode-hook (lambda () (evil-org-set-key-theme '(navigation insert textobjects additional calendar todo)))) (add-to-list 'evil-emacs-state-modes 'org-agenda-mode) (require 'evil-org-agenda) (add-hook 'org-agenda-mode-hook (lambda () (visual-line-mode -1) (toggle-truncate-lines 1) (display-line-numbers-mode 0))) (evil-org-agenda-set-keys)) #+end_src ** Literate programing *** Python Use jupyter kernels for Org Mode. | Note | Type | |------+---------------------------| | TODO | Connect to remote kernels | | TODO | View HTML? | References: - [[https://github.com/nnicandro/emacs-jupyter][emacs-jupyter repo]] - [[https://github.com/jkitchin/scimax/blob/master/scimax.org][SCIMAX manual]] #+begin_src emacs-lisp (use-package jupyter :straight t) (my-leader-def "ar" 'jupyter-run-repl) #+end_src *** Setup Enable languages #+begin_src emacs-lisp (org-babel-do-load-languages 'org-babel-load-languages '((emacs-lisp . t) (python . t) ;; (typescript .t) (shell . t) (jupyter . t))) (add-hook 'org-babel-after-execute-hook 'org-redisplay-inline-images) #+end_src Use Jupyter block instead of built-in Python. #+begin_src emacs-lisp (org-babel-jupyter-override-src-block "python") #+end_src Turn of some minor modes in source blocks. #+begin_src emacs-lisp (add-hook 'org-src-mode-hook (lambda () (hs-minor-mode 0) (highlight-indent-guides-mode 0))) #+end_src Async code blocks evaluations. Jupyter blocks have a built-in async. #+begin_src emacs-lisp (use-package ob-async :straight t :after (org) :config (setq ob-async-no-async-languages-alist '("python" "jupyter-python"))) #+end_src ** UI *** Equations preview Instant math previews for org mode. References: - [[https://github.com/yangsheng6810/org-latex-impatient][org-latex-impatient repo]] #+begin_src emacs-lisp (use-package org-latex-impatient :straight (:repo "yangsheng6810/org-latex-impatient" :branch "master" :host github) :hook (org-mode . org-latex-impatient-mode) :init (setq org-latex-impatient-tex2svg-bin "/home/pavel/Programs/miniconda3/lib/node_modules/mathjax-node-cli/bin/tex2svg") (setq org-latex-impatient-scale 2) (setq org-latex-impatient-delay 1) (setq org-latex-impatient-border-color "#ffffff")) #+end_src *** Better headers #+begin_src emacs-lisp (use-package org-superstar :straight t :after (org) :config (add-hook 'org-mode-hook (lambda () (org-superstar-mode 1)))) #+end_src *** Org Agenda Icons #+begin_src emacs-lisp (if (not my/lowpower) (setq org-agenda-category-icon-alist `( ("work" ,(list (all-the-icons-faicon "cog")) nil nil :ascent center) ("lesson" ,(list (all-the-icons-faicon "book")) nil nil :ascent center) ("education" ,(list (all-the-icons-material "build")) nil nil :ascent center) ("meeting" ,(list (all-the-icons-material "chat")) nil nil :ascent center) ("music" ,(list (all-the-icons-faicon "music")) nil nil :ascent center) ("misc" ,(list (all-the-icons-material "archive")) nil nil :ascent center) ("event" ,(list (all-the-icons-octicon "clock")) nil nil :ascent center)))) #+end_src ** Export *** Hugo #+begin_src emacs-lisp (use-package ox-hugo :straight t :after ox) #+end_src *** OFF (OFF) LaTeX | Type | Note | |------+------------------------| | TODO | Make LaTeX export work | #+begin_src emacs-lisp :tangle no ;; (use-package htmlize ;; :straight t) (defun my/setup-org-latex () (setq org-latex-compiler "xelatex") (add-to-list 'org-latex-classes '("extarticle" "\\documentclass[a4paper, 14pt]{extarticle}" ("\\section{%s}" . "\\section*{%s}") ("\\subsection{%s}" . "\\subsection*{%s}") ("\\subsubsection{%s}" . "\\subsubsection*{%s}") ("\\paragraph{%s}" . "\\paragraph*{%s}") ("\\subparagraph{%s}" . "\\subparagraph*{%s}")) ) ) (with-eval-after-load 'ox-latex (my/setup-org-latex)) #+end_src ** Keybindings & stuff #+begin_src emacs-lisp (general-define-key :keymaps 'org-mode-map "C-c d" 'org-decrypt-entry "C-c e" 'org-encrypt-entry "M-p" 'org-latex-preview) (general-define-key :keymaps 'org-mode-map :states '(normal emacs) "L" 'org-shiftright "H" 'org-shiftleft "S-" 'org-babel-next-src-block "S-" 'org-babel-previous-src-block) (general-define-key :keymaps 'org-agenda-mode-map "M-]" 'org-agenda-later "M-[" 'org-agenda-earlier) ;; (general-imap :keymaps 'org-mode-map "RET" 'evil-org-return) (general-nmap :keymaps 'org-mode-map "RET" 'org-ctrl-c-ctrl-c) (my-leader-def "aa" 'org-agenda "ao" 'org-switchb) #+end_src *** Copy a link #+begin_src emacs-lisp (defun my/org-link-copy (&optional arg) "Extract URL from org-mode link and add it to kill ring." (interactive "P") (let* ((link (org-element-lineage (org-element-context) '(link) t)) (type (org-element-property :type link)) (url (org-element-property :path link)) (url (concat type ":" url))) (kill-new url) (message (concat "Copied URL: " url)))) (general-nmap :keymaps 'org-mode-map "C-x C-l" 'my/org-link-copy) #+end_src ** Presentations Doing presentations with [[https://github.com/rlister/org-present][org-present]]. #+begin_src emacs-lisp (use-package hide-mode-line :straight t) (use-package org-present :straight (:host github :repo "rlister/org-present") :commands (org-present) :config (general-define-key :keymaps 'org-present-mode-keymap "" 'org-present-next "" 'org-present-prev) (add-hook 'org-present-mode-hook (lambda () (org-present-big) (org-display-inline-images) (org-present-hide-cursor) (org-present-read-only) (display-line-numbers-mode 0) (hide-mode-line-mode +1) (tab-bar-mode 0))) (add-hook 'org-present-mode-quit-hook (lambda () (org-present-small) (org-remove-inline-images) (org-present-show-cursor) (org-present-read-write) (display-line-numbers-mode 1) (hide-mode-line-mode 0) (tab-bar-mode 1)))) #+end_src ** TOC Make a TOC inside the org file. References: - [[https://github.com/alphapapa/org-make-toc][alphapapa/org-make-toc]] #+begin_src emacs-lisp (use-package org-make-toc :after (org) :straight t) #+end_src * UI ** General UI & GUI Settings Disable GUI elements #+begin_src emacs-lisp (tool-bar-mode -1) (menu-bar-mode -1) (scroll-bar-mode -1) #+end_src Transparency #+begin_src emacs-lisp ;; (set-frame-parameter (selected-frame) 'alpha '(90 . 90)) ;; (add-to-list 'default-frame-alist '(alpha . (90 . 90))) #+end_src Prettify symbols #+begin_src emacs-lisp ;; (global-prettify-symbols-mode) #+end_src No start screen #+begin_src emacs-lisp (setq inhibit-startup-screen t) #+end_src Visual bell #+begin_src emacs-lisp (setq visible-bell 0) #+end_src y or n instead of yes or no #+begin_src emacs-lisp (defalias 'yes-or-no-p 'y-or-n-p) #+end_src Hide mouse cursor while typing #+begin_src emacs-lisp (setq make-pointer-invisible t) #+end_src Font #+begin_src emacs-lisp (set-frame-font "JetBrainsMono Nerd Font 10" nil t) #+end_src Line numbers #+begin_src emacs-lisp (global-display-line-numbers-mode 1) (line-number-mode nil) (setq display-line-numbers-type 'visual) (column-number-mode) #+end_src Show pairs #+begin_src emacs-lisp (show-paren-mode 1) #+end_src Word wrap #+begin_src emacs-lisp (setq word-wrap 1) (global-visual-line-mode t) #+end_src Hightlight line #+begin_src emacs-lisp (global-hl-line-mode 1) #+end_src ** Custom frame title #+begin_src emacs-lisp (setq frame-title-format '("" "emacs" (:eval (let ((project-name (projectile-project-name))) (if (not (string= "-" project-name)) (format ":%s@%s" project-name (system-name)) (format "@%s" (system-name))))))) #+end_src ** Tab bar I rely rather heavily on tab-bar in my workflow. I have a suspicion I'm not using it the intended way, but that works for me. *** Setup #+begin_src emacs-lisp (general-define-key :keymaps 'override :states '(normal emacs) "gt" 'tab-bar-switch-to-next-tab "gT" 'tab-bar-switch-to-prev-tab "gn" 'tab-bar-new-tab) (setq tab-bar-show 1) (setq tab-bar-tab-hints t) (setq tab-bar-tab-name-function 'tab-bar-tab-name-current-with-count) ;; Tabs (general-nmap "gn" 'tab-new) (general-nmap "gN" 'tab-close) #+end_src *** My title Prepend tab name with the shortened projectile project title #+begin_src emacs-lisp (setq my/project-title-separators "[-_ ]") (defun my/shorten-project-name-elem (elem crop) (if (string-match "^\\[.*\\]$" elem) (concat "[" (my/shorten-project-name-elem (substring elem 1 (- (length elem) 1)) crop) "]") (let ((prefix (car (s-match my/project-title-separators elem)))) (let ((rest (substring (if prefix (substring elem (length prefix)) elem) 0 (if crop 1 nil)))) (concat prefix rest))))) (defun my/shorten-project-name (project-name) (let ((elems (s-slice-at my/project-title-separators project-name))) (concat (apply #'concat (cl-mapcar (lambda (elem) (my/shorten-project-name-elem elem t)) (butlast elems))) (my/shorten-project-name-elem (car (last elems)) nil)))) (defun my/tab-bar-name-function () (let ((project-name (projectile-project-name))) (if (string= "-" project-name) (tab-bar-tab-name-current-with-count) (concat "[" (my/shorten-project-name project-name) "] " (tab-bar-tab-name-current-with-count))))) (setq tab-bar-tab-name-function #'my/tab-bar-name-function) #+end_src ** Modeline A modeline from Doom Emacs. References: - [[https://github.com/seagle0128/doom-modeline][Doom Modeline]] #+begin_src emacs-lisp (use-package doom-modeline :straight t :init (setq doom-modeline-env-enable-python nil) (setq doom-modeline-env-enable-go nil) :config (doom-modeline-mode 1) (setq doom-modeline-minor-modes nil) (setq doom-modeline-buffer-state-icon nil)) #+end_src ** Font stuff *** Emojis | Note | Type | |------+-----------------------------------------------------------| | TODO | Figure out how to display emojis without prettify symbols | #+begin_src emacs-lisp (use-package emojify :straight t :if (not my/lowpower) :hook (after-init . global-emojify-mode)) #+end_src *** Ligatures Ligature setup for the JetBrainsMono font. #+begin_src emacs-lisp (use-package ligature :straight (:host github :repo "mickeynp/ligature.el") :config (ligature-set-ligatures '( typescript-mode js2-mode vue-mode svelte-mode scss-mode php-mode python-mode js-mode markdown-mode clojure-mode go-mode sh-mode haskell-mode) '("--" "---" "==" "===" "!=" "!==" "=!=" "=:=" "=/=" "<=" ">=" "&&" "&&&" "&=" "++" "+++" "***" ";;" "!!" "??" "?:" "?." "?=" "<:" ":<" ":>" ">:" "<>" "<<<" ">>>" "<<" ">>" "||" "-|" "_|_" "|-" "||-" "|=" "||=" "##" "###" "####" "#{" "#[" "]#" "#(" "#?" "#_" "#_(" "#:" "#!" "#=" "^=" "<$>" "<$" "$>" "<+>" "<+" "+>" "<*>" "<*" "*>" "" "/>" "" "->" "->>" "<<-" "<-" "<=<" "=<<" "<<=" "<==" "<=>" "<==>" "==>" "=>" "=>>" ">=>" ">>=" ">>-" ">-" ">--" "-<" "-<<" ">->" "<-<" "<-|" "<=|" "|=>" "|->" "<->" "<~~" "<~" "<~>" "~~" "~~>" "~>" "~-" "-~" "~@" "[||]" "|]" "[|" "|}" "{|" "[<" ">]" "|>" "<|" "||>" "<||" "|||>" "<|||" "<|>" "..." ".." ".=" ".-" "..<" ".?" "::" ":::" ":=" "::=" ":?" ":?>" "//" "///" "/*" "*/" "/=" "//=" "/==" "@_" "__")) (global-ligature-mode t)) #+end_src *** Icons #+begin_src emacs-lisp (use-package all-the-icons :straight t) #+end_src ** Theme & global stuff Dim inactive buffers. #+begin_src emacs-lisp (use-package auto-dim-other-buffers :straight t :if (display-graphic-p) :config (set-face-attribute 'auto-dim-other-buffers-face nil :background "#212533") (auto-dim-other-buffers-mode t)) #+end_src My colorscheme of choice. #+begin_src emacs-lisp (use-package doom-themes :straight t :config (setq doom-themes-enable-bold t doom-themes-enable-italic t) (load-theme 'doom-palenight t) (doom-themes-visual-bell-config) (setq doom-themes-treemacs-theme "doom-colors") (doom-themes-treemacs-config)) #+end_src ** Text highlight improvements Hightlight indent guides. #+begin_src emacs-lisp (use-package highlight-indent-guides :straight t :if (not my/lowpower) :hook ( (prog-mode . highlight-indent-guides-mode) (vue-mode . highlight-indent-guides-mode) (LaTeX-mode . highlight-indent-guides-mode)) :config (setq highlight-indent-guides-method 'bitmap) (setq highlight-indent-guides-bitmap-function 'highlight-indent-guides--bitmap-line)) #+end_src Rainbow parentheses. #+begin_src emacs-lisp (use-package rainbow-delimiters :straight t :if (not my/lowpower) :hook ( (prog-mode . rainbow-delimiters-mode))) #+end_src * OFF (OFF) EAF [[https://github.com/manateelazycat/emacs-application-framework][Emacs Application Framework]] provides a way to integrate PyQt applications with Emacs. I've made it work, but don't find any uses cases for me at the moment ** Installation Requirements: Node >= 14 #+begin_src bash :tangle no pip install qtconsole markdown qrcode[pil] PyQt5 PyQtWebEngine #+end_src ** Config #+begin_src emacs-lisp :tangle no (use-package eaf :straight (:host github :repo "manateelazycat/emacs-application-framework" :files ("*")) :init (use-package epc :defer t :straight t) (use-package ctable :defer t :straight t) (use-package deferred :defer t :straight t) :config (require 'eaf-evil) (setq eaf-evil-leader-key "SPC")) #+end_src * Programming ** General setup *** LSP LSP-mode provides an IDE-like experience for Emacs - real-time diagnostic, code actions, intelligent autocompletion, etc. References: - [[https://emacs-lsp.github.io/lsp-mode/][lsp-mode homepage]] **** Setup #+begin_src emacs-lisp (use-package lsp-mode :straight t :hook ( (typescript-mode . lsp) (vue-mode . lsp) (go-mode . lsp) (svelte-mode . lsp) (python-mode . lsp) (json-mode . lsp) (haskell-mode . lsp) (haskell-literate-mode . lsp) (java-mode . lsp)) :commands lsp :config (setq lsp-idle-delay 1) (setq lsp-eslint-server-command '("node" "/home/pavel/.emacs.d/.cache/lsp/eslint/unzipped/extension/server/out/eslintServer.js" "--stdio")) (setq lsp-eslint-run "onSave") (setq lsp-signature-render-documentation nil) ; (lsp-headerline-breadcrumb-mode nil) (setq lsp-headerline-breadcrumb-enable nil) (add-to-list 'lsp-language-id-configuration '(svelte-mode . "svelte"))) (use-package lsp-ui :straight t :commands lsp-ui-mode :config (setq lsp-ui-doc-delay 2) (setq lsp-ui-sideline-show-hover nil)) #+end_src **** Integrations The only integration left now is treemacs. Origami should've leveraged LSP folding, but it was too unstable at the moment I tried it. #+begin_src emacs-lisp ;; (use-package helm-lsp ;; :straight t ;; :commands helm-lsp-workspace-symbol) ;; (use-package origami ;; :straight t ;; :hook (prog-mode . origami-mode)) ;; (use-package lsp-origami ;; :straight t ;; :config ;; (add-hook 'lsp-after-open-hook #'lsp-origami-try-enable)) (use-package lsp-treemacs :straight t :commands lsp-treemacs-errors-list) #+end_src **** Keybindings #+begin_src emacs-lisp (my-leader-def "ld" 'lsp-ui-peek-find-definitions "lr" 'lsp-rename "lu" 'lsp-ui-peek-find-references "ls" 'lsp-ui-find-workspace-symbol ;; "la" 'helm-lsp-code-actions "le" 'list-flycheck-errors) #+end_src *** Flycheck A syntax checking extension for Emacs. Integrates with LSP-mode, but can also use various standalone checkers. References: - [[https://www.flycheck.org/en/latest/][Flycheck homepage]] #+begin_src emacs-lisp (use-package flycheck :straight t :config (global-flycheck-mode) (setq flycheck-check-syntax-automatically '(save idle-buffer-switch mode-enabled)) (add-hook 'evil-insert-state-exit-hook '(lambda () (if flycheck-checker (flycheck-buffer)) )) (advice-add 'flycheck-eslint-config-exists-p :override (lambda() t)) (add-to-list 'display-buffer-alist `(,(rx bos "*Flycheck errors*" eos) (display-buffer-reuse-window display-buffer-in-side-window) (side . bottom) (reusable-frames . visible) (window-height . 0.33)))) #+end_src *** OFF (OFF) DAP An Emacs client for Debugger Adapter Protocol. I don't use it now, because there are debuggers I like more for the technologies I'm currently using. References: - [[https://emacs-lsp.github.io/dap-mode/][dap-mode homepage]] #+begin_src emacs-lisp :tangle no (use-package dap-mode :straight t :defer t :init (setq lsp-enable-dap-auto-configure nil) :config (setq dap-ui-variable-length 100) (require 'dap-node) (dap-node-setup) (require 'dap-chrome) (dap-chrome-setup) (require 'dap-python) (dap-mode 1) (dap-ui-mode 1) (dap-tooltip-mode 1) (tooltip-mode 1) (dap-ui-controls-mode 1)) (my-leader-def :infix "d" "d" 'dap-debug "b" 'dap-breakpoint-toggle "c" 'dap-breakpoint-condition "wl" 'dap-ui-locals "wb" 'dap-ui-breakpoints "wr" 'dap-ui-repl "ws" 'dap-ui-sessions "we" 'dap-ui-expressions) (my-leader-def :infix "d" :keymaps 'dap-mode-map "h" 'dap-hydra) (defun my/dap-yank-value-at-point (node) (interactive (list (treemacs-node-at-point))) (kill-new (message (plist-get (button-get node :item) :value)))) #+end_src *** OFF (OFF) TabNine A ML-based autocompletion system. More often than not gives really good results, but slow as hell & consumes a lot of RAM. Also, LSP-provided completions were more useful in my experience. References: - [[https://www.tabnine.com/][TabNine Homepage]] #+begin_src emacs-lisp :tangle no (use-package company-tabnine :straight t :if (not my/lowpower) :after company :config (add-to-list 'company-backends #'company-tabnine)) #+end_src *** OFF (OFF) Code Compass A set of code analysing tools. References: - [[https://github.com/ag91/code-compass][code-compass repo]] **** Dependencies #+begin_src emacs-lisp :tangle no (use-package async :straight t) (use-package dash :straight t) (use-package f :straight t) (use-package s :straight t) (use-package simple-httpd :straight t) #+end_src **** Plugin #+begin_src emacs-lisp :tangle no (use-package code-compass :straight ( :repo "ag91/code-compass" :files ("code-compass.el") :branch "main" )) #+end_src *** General additional config Make smartparens behave the way I like for C-like languages. #+begin_src emacs-lisp (defun my/set-smartparens-indent (mode) (sp-local-pair mode "{" nil :post-handlers '(("|| " "SPC") ("||\n[i]" "RET"))) (sp-local-pair mode "[" nil :post-handlers '(("|| " "SPC") ("||\n[i]" "RET"))) (sp-local-pair mode "(" nil :post-handlers '(("|| " "SPC") ("||\n[i]" "RET")))) #+end_src Override flycheck checker with eslint. #+begin_src emacs-lisp (defun set-flycheck-eslint() "Override flycheck checker with eslint." (setq-local lsp-diagnostic-package :none) (setq-local flycheck-checker 'javascript-eslint)) #+end_src ** Web development Configs for various web development technologies I'm using. *** OFF (OFF) Emmet | Note | Type | |------+----------------------------------------------------| | TODO | I really want Emmet :( find a way to make it work | #+begin_src emacs-lisp :tangle no (use-package emmet-mode :straight t) (general-imap :keymaps 'emmet-mode-keymap "TAB" 'emmet-expand-line) (add-hook 'web-mode 'emmet-mode) #+end_src *** TypeScript #+begin_src emacs-lisp (use-package typescript-mode :straight t :mode "\\.ts\\'" :config (add-hook 'typescript-mode-hook #'smartparens-mode) (add-hook 'typescript-mode-hook #'rainbow-delimiters-mode) (add-hook 'typescript-mode-hook #'hs-minor-mode) (my/set-smartparens-indent 'typescript-mode)) #+end_src *** JavaScript #+begin_src emacs-lisp (add-hook 'js-mode-hook #'smartparens-mode) (add-hook 'js-mode-hook #'hs-minor-mode) (my/set-smartparens-indent 'js-mode) #+end_src *** Jest #+begin_src emacs-lisp (use-package jest-test-mode :straight t :hook ((typescript-mode . jest-test-mode) (js-mode . jest-test-mode)) :config (my-leader-def :keymaps 'jest-test-mode-map :infix "t" "t" 'jest-test-run-at-point "r" 'jest-test-run "a" 'jest-test-run-all-tests)) #+end_src *** Vue.js #+begin_src emacs-lisp (use-package vue-mode :straight t :mode "\\.vue\\'" :config (add-hook 'vue-mode-hook #'hs-minor-mode) (add-hook 'vue-mode-hook #'smartparens-mode) (my/set-smartparens-indent 'vue-mode) (add-hook 'vue-mode-hook (lambda () (set-face-background 'mmm-default-submode-face nil)))) (with-eval-after-load 'editorconfig (add-to-list 'editorconfig-indentation-alist '(vue-mode css-indent-offset js-indent-level sgml-basic-offset ssass-tab-width typescript-indent-level ))) #+end_src **** mmm-mode fix References: - [[https://github.com/purcell/mmm-mode/issues/112][mmm-mode issue]] #+begin_src diff :tangle no --- a/mmm-region.el +++ b/mmm-region.el @@ -868,9 +868,10 @@ calls each respective submode's `syntax-propertize-function'." (mmm-set-current-pair mode ovl) (mmm-set-local-variables mode mmm-current-overlay) (save-restriction - (when mmm-current-overlay + (if mmm-current-overlay (narrow-to-region (overlay-start mmm-current-overlay) - (overlay-end mmm-current-overlay))) + (overlay-end mmm-current-overlay)) + (narrow-to-region beg end)) (cond (func (funcall func beg end)) #+end_src *** Svelte #+begin_src emacs-lisp (use-package svelte-mode :straight t :mode "\\.svelte\\'" :config (add-hook 'svelte-mode-hook 'set-flycheck-eslint) (add-hook 'svelte-mode-hook #'smartparens-mode) (my/set-smartparens-indent 'svelte-mode)) #+end_src *** SCSS #+begin_src emacs-lisp (add-hook 'scss-mode-hook #'smartparens-mode) (add-hook 'scss-mode-hook #'hs-minor-mode) (my/set-smartparens-indent 'scss-mode) #+end_src *** PHP #+begin_src emacs-lisp (use-package php-mode :straight t :mode "\\.php\\'") #+end_src ** Documents & markup languages *** LaTeX **** AUCTeX The best LaTeX editing environment I've found so far. References: - [[https://www.gnu.org/software/auctex/][AUCTeX homepage]] #+begin_src emacs-lisp (use-package tex :straight auctex ;; :mode "\\.tex\\'" :config (setq-default TeX-auto-save t) (setq-default TeX-parse-self t) (TeX-PDF-mode) ;; Use XeLaTeX & stuff (setq-default TeX-engine 'xetex) (setq-default TeX-command-extra-options "-shell-escape") (setq-default TeX-source-correlate-method 'synctex) (TeX-source-correlate-mode) (setq-default TeX-source-correlate-start-server t) (setq-default LaTeX-math-menu-unicode t) (setq-default font-latex-fontify-sectioning 1.3) ;; Scale preview for my DPI (setq-default preview-scale-function 1.4) ;; (assoc-delete-all "--" tex--prettify-symbols-alist) ;; (assoc-delete-all "---" tex--prettify-symbols-alist) (add-hook 'LaTeX-mode-hook (lambda () (TeX-fold-mode 1) (outline-minor-mode))) (add-to-list 'TeX-view-program-selection '(output-pdf "Zathura")) ;; Do not run lsp within templated TeX files (add-hook 'LaTeX-mode-hook #'(lambda () (unless (string-match "\.hogan\.tex$" (buffer-name)) (lsp)) (setq-local lsp-diagnostic-package :none) (setq-local flycheck-checker 'tex-chktex))) (add-hook 'LaTeX-mode-hook #'rainbow-delimiters-mode) (add-hook 'LaTeX-mode-hook #'smartparens-mode) (add-hook 'LaTeX-mode-hook #'prettify-symbols-mode) (my/set-smartparens-indent 'LaTeX-mode) (require 'smartparens-latex) (general-nmap :keymaps '(LaTeX-mode-map latex-mode-map) "RET" 'TeX-command-run-all "C-c t" 'orgtbl-mode)) #+end_src **** Import *.sty A function to import =.sty= files to the LaTeX document. #+begin_src emacs-lisp (defun my/import-sty () (interactive) (insert (apply #'concat (cl-mapcar (lambda (file) (concat "\\usepackage{" (file-name-sans-extension (file-relative-name file default-directory)) "}\n")) (sort (seq-filter (lambda (file) (if (string-match ".*\.sty$" file) 1 nil)) (directory-files (seq-some (lambda (dir) (if (and (f-directory-p dir) (seq-some (lambda (file) (string-match ".*\.sty$" file)) (directory-files dir)) ) dir nil)) (list "./styles" "../styles/" "." "..")) :full)) (lambda (f1 f2) (pcase f1 ("gostBibTex.sty" 2) ("russianlocale.sty" 1) (_ nil)))))))) #+end_src *** Markdown #+begin_src emacs-lisp (use-package markdown-mode :straight t :mode "\\.md\\'" :config (setq markdown-command (concat "pandoc" " --from=markdown --to=html" " --standalone --mathjax --highlight-style=pygments" " --css=pandoc.css" " --quiet" )) (setq markdown-live-preview-delete-export 'delete-on-export) (setq markdown-asymmetric-header t) (setq markdown-open-command "/home/pavel/bin/scripts/chromium-sep") (add-hook 'markdown-mode-hook #'smartparens-mode)) ;; (use-package livedown ;; :straight (:host github :repo "shime/emacs-livedown") ;; :commands livedown-preview ;; :config ;; (setq livedown-browser "qutebrowser")) (general-define-key :keymaps 'markdown-mode-map "M-" 'markdown-promote "M-" 'markdown-demote) #+end_src *** PlantUML #+begin_src emacs-lisp (use-package plantuml-mode :straight t :mode "(\\.\\(plantuml?\\|uml\\|puml\\)\\'" :config (setq plantuml-executable-path "/usr/bin/plantuml") (setq plantuml-default-exec-mode 'executable) (add-to-list 'auto-mode-alist '("\\.plantuml\\'" . plantuml-mode)) (add-to-list 'auto-mode-alist '("\\.uml\\'" . plantuml-mode)) (add-hook 'plantuml-mode-hook #'smartparens-mode)) (general-nmap :keymaps 'plantuml-mode-map "RET" 'plantuml-preview) #+end_src *** Natural languages #+begin_src emacs-lisp (use-package langtool :straight t :commands (langtool-check) :config (setq langtool-language-tool-server-jar "/home/pavel/Programs/LanguageTool-5.1/languagetool-server.jar") (setq langtool-mother-tongue "ru")) (my-leader-def :infix "L" "c" 'langtool-check "s" 'langtool-server-stop "d" 'langtool-check-done "n" 'langtool-goto-next-error "p" 'langtool-goto-previous-error) #+end_src ** Emacs Lisp #+begin_src emacs-lisp (add-hook 'lisp-interaction-mode-hook #'smartparens-mode) (add-hook 'emacs-lisp-mode-hook #'smartparens-strict-mode) (add-hook 'emacs-lisp-mode-hook #'aggressive-indent-mode) (sp-with-modes sp-lisp-modes (sp-local-pair "'" nil :actions nil)) #+end_src ** Python #+begin_src emacs-lisp (add-hook 'python-mode-hook #'smartparens-mode) (add-hook 'python-mode-hook #'hs-minor-mode) #+end_src ** Java #+begin_src emacs-lisp (use-package lsp-java :straight t :after (lsp) :config (setq lsp-java-jdt-download-url "https://download.eclipse.org/jdtls/milestones/0.57.0/jdt-language-server-0.57.0-202006172108.tar.gz")) (add-hook 'java-mode-hook #'smartparens-mode) (add-hook 'java-mode-hook #'hs-minor-mode) (my/set-smartparens-indent 'java-mode) #+end_src ** Clojure #+begin_src emacs-lisp (use-package clojure-mode :straight t :mode "\\.clj[sc]?\\'" :config (add-hook 'clojure-mode-hook #'smartparens-strict-mode) (add-hook 'clojure-mode-hook #'aggressive-indent-mode)) (use-package cider :mode "\\.clj[sc]?\\'" :straight t) #+end_src ** Go ** fish #+begin_src emacs-lisp (use-package fish-mode :straight t :mode "\\.fish\\'" :config (add-hook 'fish-mode-hook #'smartparens-mode)) #+end_src ** sh #+begin_src emacs-lisp (add-hook 'sh-mode-hook #'smartparens-mode) #+end_src ** CLIPS #+begin_src emacs-lisp (use-package clips-mode :straight t :mode "\\.cl\\'") #+end_src ** Haskell #+begin_src emacs-lisp (use-package haskell-mode :straight t :mode "\\.hs\\'") (use-package lsp-haskell :straight t :after (lsp haskell-mode)) #+end_src ** JSON #+begin_src emacs-lisp (use-package json-mode :straight t :mode "\\.json\\'" :config (add-hook 'json-mode #'smartparens-mode) (add-hook 'json-mode #'hs-minor-mode) (my/set-smartparens-indent 'json-mode)) #+end_src ** YAML #+begin_src emacs-lisp (use-package yaml-mode :straight t :mode "\\.yml\\'" :config (add-to-list 'auto-mode-alist '("\\.yml\\'" . yaml-mode))) #+end_src ** CSV #+begin_src emacs-lisp (use-package csv-mode :straight t :mode "\\.csv\\'") #+end_src ** Docker #+begin_src emacs-lisp (use-package dockerfile-mode :mode "Dockerfile\\'" :straight t) #+end_src * Apps & Misc ** Managing dotfiles *** Open Emacs config #+begin_src emacs-lisp (defun my/edit-configuration () "Open the init file." (interactive) (find-file "~/Emacs.org")) ;; (defun my/edit-exwm-configuration () ;; "Open the exwm config file." ;; (interactive) ;; (find-file "~/.emacs.d/exwm.org")) (general-define-key "C-c c" 'my/edit-configuration) ;; (general-define-key "C-c C" 'my/edit-exwm-configuration) #+end_src *** Open dotfile Open a file managed by yadm. #+begin_src emacs-lisp (defun my/open-yadm-file () "Open a file managed by yadm" (interactive) (find-file (concat (file-name-as-directory (getenv "HOME")) (completing-read "yadm files: " (split-string (shell-command-to-string "yadm ls-files $HOME --full-name") "\n"))))) (general-define-key "C-c f" 'my/open-yadm-file) #+end_src ** Notmuch My notmuch config. References: - [[https://sqrtminusone.xyz/posts/2021-02-27-gmail/][My post about notmuch configuration]] #+begin_src emacs-lisp (use-package notmuch :ensure nil :commands (notmuch) :config (setq mail-specify-envelope-from t) (setq message-sendmail-envelope-from 'header) (setq mail-envelope-from 'header) (setq notmuch-always-prompt-for-sender t) (setq sendmail-program "/usr/bin/msmtp") (setq send-mail-function #'sendmail-send-it) (add-hook 'notmuch-hello-mode-hook (lambda () (display-line-numbers-mode 0)))) (my-leader-def "am" 'notmuch) #+end_src ** EWW Emacs built-in web browser. I wonder if anyone actually uses it. #+begin_src emacs-lisp (my-leader-def "aw" 'eww) (general-define-key :keymaps 'eww-mode-map "+" 'text-scale-increase "-" 'text-scale-decrease) #+end_src ** Snow #+begin_src emacs-lisp (use-package snow :straight (:repo "alphapapa/snow.el" :host github) :commands (snow)) #+end_src ** Zone #+begin_src emacs-lisp (use-package zone :ensure nil :config (setq original-zone-programs (copy-sequence zone-programs))) (defun my/zone-with-select () (interactive) (ivy-read "Zone programs" (cl-pairlis (cl-mapcar 'symbol-name original-zone-programs) original-zone-programs) :action (lambda (elem) (setq zone-programs (vector (cdr elem))) (zone)))) #+end_src