Giter Site home page Giter Site logo

emacs-gnu's Introduction

My literate GNU Emacs config

This is my GNU Emacs configuration. I actually use Doom Emacs, this is mainly for fun and to try some stuff out.

This file is tangled (on save) to ~/.emacs.d/init.el using a buffer local variable (see EOF).

Package management

Setup package.el to work with MELPA, ELPA and ORG

(require 'package)

(setq package-archives '(("melpa" . "https://melpa.org/packages/")
                         ("org" . "https://orgmode.org/elpa/")
                         ("elpa" . "https://elpa.gnu.org/packages/")))

(package-initialize)

(unless package-archive-contents
  (package-refresh-contents))

;; Initialize use-package on non-Linux platforms
(unless (package-installed-p 'use-package)
  (package-install 'use-package))

(require 'use-package)
(require 'use-package-ensure)
(setq use-package-always-ensure t)

use-package auto updates

(use-package auto-package-update
  :custom
  (auto-package-update-interval 7)
  (auto-package-update-prompt-before-update t)
  (auto-package-update-hide-results t)
  :config
  (auto-package-update-maybe)
  (auto-package-update-at-time "09:00"))

Startup

Optimization

Gcmh is the mode used by Doom to garbage collect only on idle time. It is important to do it at the beginning to speed up the startup time.

(use-package gcmh
  :config (gcmh-mode t))

The GC introduces annoying pauses and stuttering into our Emacs experience, so we use `gcmh’ to stave off the GC while we’re using Emacs, and provoke it when it’s idle. However, if the idle delay is too long, we run the risk of runaway memory usage in busy sessions. If it’s too low, then we may as well not be using gcmh at all.

(setq gcmh-idle-delay 'auto  ; default is 15s
      gcmh-auto-idle-delay-factor 10
      gcmh-high-cons-threshold (* 16 1024 1024))  ; 16mb

Emacs “updates” its ui more often than it needs to, so slow it down slightly.

(setq idle-update-delay 1.0)  ; default is 0.5

Remove command line options that aren’t relevant to the current OS; means slightly less to process at startup.

(setq command-line-x-option-alist nil)

Reduce Message noise at startup. An empty scratch buffer (or the dashboard) is more than enough.

(setq inhibit-startup-echo-area-message user-login-name
      ;; Shave seconds off startup time by starting the scratch buffer in
      ;; `fundamental-mode', rather than, say, `org-mode' or `text-mode', which
      ;; pull in a ton of packages.
      initial-major-mode 'fundamental-mode
      initial-scratch-message nil)

Early init

This section is tangled to early-init.el

From Doom: a big contributor to startup times is garbage collection. We up the gc threshold to temporarily prevent it from running, then reset it later by enabling `gcmh-mode’. Not resetting it will cause stuttering/freezes.

(setq gc-cons-threshold most-positive-fixnum)

Make UTF-8 the default coding system.

(set-language-environment "UTF-8")

Set-language-enviornment sets default-input-method, which is unwanted.

(setq default-input-method nil)
(when (featurep 'native-compile)
  (setq native-comp-async-report-warnings-errors nil)
  (setq native-comp-deferred-compilation t))
(push '(menu-bar-lines . 0)   default-frame-alist)
(push '(tool-bar-lines . 0)   default-frame-alist)
(push '(vertical-scroll-bars) default-frame-alist)

Appearance

Icons

(use-package all-the-icons
  :commands (all-the-icons-octicon
             all-the-icons-faicon
             all-the-icons-fileicon
             all-the-icons-wicon
             all-the-icons-material
             all-the-icons-alltheicon))

Windows

(use-package switch-window
  :defer t)
(setq frame-title-format '("Emacs – %b")
      icon-title-format frame-title-format)

Don’t resize the frames in steps; it looks weird, especially in tiling window managers, where it can leave unseemly gaps.

(setq frame-resize-pixelwise t)

But do not resize windows pixelwise, this can cause crashes in some cases when resizing too many windows at once or rapidly.

(setq window-resize-pixelwise nil)

GUIs are inconsistent across systems and themes (and will rarely match the active Emacs theme). They impose inconsistent shortcut key paradigms too. It’s best to avoid them altogether and have Emacs handle the prompting.

(setq use-dialog-box nil)
(when (bound-and-true-p tooltip-mode)
  (tooltip-mode -1))
(setq x-gtk-use-system-tooltips nil) ; Linux only

This is just for consistency inside the session as those are disabled in early-init.

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

Dashboard

(use-package page-break-lines
  :after dashboard)

(setq inhibit-startup-message t)

(use-package dashboard
  :init
  (setq dashboard-set-heading-icons t
        dashboard-set-file-icons t
        dashboard-banner-logo-title "Emacs > All"
        dashboard-startup-banner 'official
        dashboard-items '((recents . 5)
                          (agenda . 5 )
                          (bookmarks . 3)
                          (projects . 3)))
  (add-hook 'after-init-hook 'dashboard-refresh-buffer)
  :config
  (dashboard-setup-startup-hook)

  ;; Ensures that `emacsclient' always opens on dashboard rather than scratch.
  (setq initial-buffer-choice (lambda () (get-buffer "*dashboard*"))))

Theme

(use-package doom-themes
  :config
  (doom-themes-treemacs-config)
  (doom-themes-org-config)
  (setq doom-themes-enable-bold t
        doom-themes-enable-italic t
        doom-themes-treemacs-enable-variable-pitch nil
        doom-themes-treemacs-theme "doom-atom")
  (load-theme 'doom-dracula t)
  )
(use-package solaire-mode
  :after doom-themes
  :config (solaire-global-mode))

Fonts

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

(set-face-attribute 'default nil
                    :font "Source Code Pro" :height 130 :weight 'medium)

(set-face-attribute 'italic nil
                    :family "Victor Mono" :weight 'regular :slant 'italic)

(set-face-attribute 'variable-pitch nil
                    :font "Ubuntu Nerd Font" :height 150 :weight 'light)

(set-face-attribute 'fixed-pitch nil :inherit 'default)

Zooming in and out

;; zoom in/out like we do everywhere else.
(global-set-key (kbd "C-=") 'text-scale-increase)
(global-set-key (kbd "C--") 'text-scale-decrease)
(global-set-key (kbd "<C-wheel-up>") 'text-scale-increase)
(global-set-key (kbd "<C-wheel-down>") 'text-scale-decrease)

Emojis

(use-package emojify
  :hook (after-init . global-emojify-mode))

Line and column numbers

Explicitly define a width to reduce the cost of on-the-fly computation

(setq-default display-line-numbers-width 3)
(column-number-mode)
(add-hook 'prog-mode-hook #'display-line-numbers-mode)
(add-hook 'org-mode-hook #'display-line-numbers-mode)

NOTE: line numbers can also be enabled globally.

Cursor

(setq-default cursor-in-non-selected-windows nil)
(setq highlight-nonselected-windows nil
      ;; Don't stretch the cursor to fit wide characters, it is disorienting,
      ;; especially for tabs.
      x-stretch-cursor nil)
(blink-cursor-mode 0)
(global-hl-line-mode)

Visual effects

(use-package evil-goggles
  :after evil
  :config
  (setq evil-goggles-duration 0.1
        evil-goggles-pulse nil ; too slow
        evil-goggles-enable-delete nil
        evil-goggles-enable-change nil)
  (evil-goggles-mode))
(use-package rainbow-mode
  :commands rainbow-mode)

Bar

(use-package nyan-mode
  :hook (after-init . nyan-mode)
  :config
  (setq nyan-animate-nyancat t))

Tree sitter

(use-package tree-sitter
  :hook
  (c++-mode     . tree-sitter-mode)
  (c-mode       . tree-sitter-mode)
  (python-mode  . tree-sitter-mode)
  (nix-mode     . tree-sitter-mode)
  (rust-mode    . tree-sitter-mode)
  :config
  ;; (global-tree-sitter-mode)
  (add-hook 'tree-sitter-after-on-hook #'tree-sitter-hl-mode))

(use-package tree-sitter-langs
  :after tree-sitter)

Which Key

(use-package which-key
  :defer 0
  :diminish which-key-mode
  :init
  (setq which-key-sort-order #'which-key-key-order-alpha
        which-key-sort-uppercase-first nil
        which-key-add-column-padding 1
        which-key-max-display-columns nil
        which-key-min-display-lines 6
        which-key-side-window-slot -10
        which-key-separator "")

  (which-key-mode))

Misc

Ask “y” or “n” instead of “yes” or “no”

(advice-add #'yes-or-no-p :override #'y-or-n-p)

Refresh buffer if changed on disk

(global-auto-revert-mode 1)

Save cursor position when editing a buffer

(use-package saveplace
  :hook (after-init . save-place-mode))

Enable builtin recentf mode

(add-hook 'after-init-hook #'recentf-mode)
(setq recentf-max-menu-items 25)
(setq recentf-max-saved-items 25)

Disable backup files

(setq make-backup-files nil
      backup-inhibited t
      auto-save-default nil)

Improvments for long files and files with long lines

(setq-default bidi-paragraph-direction 'left-to-right)
(setq-default bidi-inhibit-bpa t)
(global-so-long-mode 1)

Scrolling improvments

(setq hscroll-margin 2
      hscroll-step 1

      scroll-margin 3

      scroll-preserve-screen-position t
      fast-but-imprecise-scrolling t

      ;; Emacs spends too much effort recentering the screen if you scroll the
      ;; cursor more than N lines past window edges (where N is the settings of
      ;; `scroll-conservatively'). This is especially slow in larger files
      ;; during large-scale scrolling commands. If kept over 100, the window is
      ;; never automatically recentered.
      scroll-conservatively 101

      ;; Reduce cursor lag by a tiny bit by not auto-adjusting `window-vscroll'
      ;; for tall lines.
      auto-window-vscroll nil)

;; Remove hscroll-margin in shells, otherwise it causes jumpiness
(add-hook 'eshell-mode-hook (lambda () (setq hscroll-margin 0)))

Dired

(use-package dired
  :ensure nil
  :commands (dired dired-jump)
  :init
  (setq dired-dwim-target t  ; suggest a target for moving/copying intelligently
        dired-hide-details-hide-symlink-targets nil

        ;; Always copy/delete recursively
        dired-recursive-copies  'always
        dired-recursive-deletes 'top
        ;; Ask whether destination dirs should get created when copying/removing files.
        dired-create-destination-dirs 'always))

Icons and colors

(use-package all-the-icons-dired
  :hook (dired-mode . all-the-icons-dired-mode)
  :config
  (setq all-the-icons-dired-monochrome nil))

(use-package diredfl
  :hook (dired-mode . diredfl-mode))
;; TODO add binding for this
(use-package fd-dired
  :defer t
  :init
  (global-set-key [remap find-dired] #'fd-dired)
  )

Vertico and consult

Utilities

Builtins Emacs variables

(setq read-file-name-completion-ignore-case t
      read-buffer-completion-ignore-case t
      completion-ignore-case t)
;; A few more useful configurations...
(use-package emacs
  :init
  ;; Add prompt indicator to `completing-read-multiple'.
  ;; Alternatively try `consult-completing-read-multiple'.
  (defun crm-indicator (args)
    (cons (concat "[CRM] " (car args)) (cdr args)))
  (advice-add #'completing-read-multiple :filter-args #'crm-indicator)

  ;; Do not allow the cursor in the minibuffer prompt
  (setq minibuffer-prompt-properties
        '(read-only t cursor-intangible t face minibuffer-prompt))
  (add-hook 'minibuffer-setup-hook #'cursor-intangible-mode)

  ;; Emacs 28: Hide commands in M-x which do not work in the current mode.
  ;; Vertico commands are hidden in normal buffers.
  ;; (setq read-extended-command-predicate
  ;;       #'command-completion-default-include-p)

  (setq enable-recursive-minibuffers t
        completion-cycle-threshold 4 ; TAB cycle if there are only few candidates
        tab-always-indent 'complete))

Fuzzy search completion

(use-package orderless
  :after vertico
  :init
  (setq completion-styles '(orderless)
        completion-category-defaults nil
        completion-category-overrides '((file (styles . (partial-completion))))))

Builtin package to remember history for commands

(savehist-mode 1)

Vertico

(use-package vertico
  :bind (:map vertico-map
              ("C-j" . vertico-next)
              ("C-k" . vertico-previous)
              :map minibuffer-local-map
              ("<backspace>" . vertico-directory-delete-char))
  :custom
  (vertico-cycle t)
  :init
  (vertico-mode)
  :config
  (add-hook 'minibuffer-setup-hook #'vertico-repeat-save))

Adds information for completions

(use-package marginalia
  :after vertico
  :custom
  (marginalia-annotators '(marginalia-annotators-heavy marginalia-annotators-light nil))
  :init
  (marginalia-mode))

Addon for icons in marginalia mode

(use-package all-the-icons-completion
  :after (marginalia all-the-icons)
  :hook (marginalia-mode . all-the-icons-completion-marginalia-setup)
  :init
  (all-the-icons-completion-mode))

Consult

Front end for vertico

(use-package consult
  :hook (completion-list-mode . consult-preview-at-point-mode)
  :init
  ;; 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)

  ;; Optionally replace `completing-read-multiple' with an enhanced version.
  (advice-add #'completing-read-multiple :override #'consult-completing-read-multiple)

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

  :config
  (consult-customize
   ;; No preview by default for those commands
   consult-buffer consult-recent-file
   :preview-key (kbd "C-SPC"))

  (consult-customize
   consult-theme :preview-key (list (kbd "C-SPC") :debounce 0.5 'any))
  )

(use-package consult-dir
  :after consult
  :bind (([remap list-directory] . consult-dir)
         :map vertico-map
         ("C-x C-d" . consult-dir)
         ("C-x C-j" . consult-dir-jump-file)))

(use-package consult-flycheck
  :after (consult flycheck))

Key bindings

Better escape

Make ESC qui prompts.

(defvar doom-escape-hook nil
  "A hook run when C-g is pressed (or ESC in normal mode, for evil users).
More specifically, when `doom/escape' is pressed. If any hook returns non-nil,
all hooks after it are ignored.")

(defun doom/escape (&optional interactive)
  "Run `doom-escape-hook'."
  (interactive (list 'interactive))
  (cond ((minibuffer-window-active-p (minibuffer-window))
         ;; quit the minibuffer if open.
         (when interactive
           (setq this-command 'abort-recursive-edit))
         (abort-recursive-edit))
        ;; Run all escape hooks. If any returns non-nil, then stop there.
        ((run-hook-with-args-until-success 'doom-escape-hook))
        ;; don't abort macros
        ((or defining-kbd-macro executing-kbd-macro) nil)
        ;; Back to the default
        ((unwind-protect (keyboard-quit)
           (when interactive
             (setq this-command 'keyboard-quit))))))

(global-set-key [remap keyboard-quit] #'doom/escape)

(with-eval-after-load 'eldoc
  (eldoc-add-command 'doom/escape))

Evil mode

(use-package evil
  :init
  (setq evil-want-integration t
        evil-want-keybinding nil
        evil-vsplit-window-right t
        evil-split-window-below t
        evil-want-C-u-scroll t
        evil-want-Y-yank-to-eol t
        evil-undo-system 'undo-redo)
  :config
  (evil-mode 1)

  (define-key evil-insert-state-map (kbd "C-g") 'evil-normal-state)

  ;; Use visual line motions even outside of visual-line-mode buffers
  ;; (evil-global-set-key 'motion "j" 'evil-next-visual-line)
  ;; (evil-global-set-key 'motion "k" 'evil-previous-visual-line)

  (evil-set-initial-state 'messages-buffer-mode 'normal)
  (evil-set-initial-state 'dashboard-mode 'normal)
  )

(use-package evil-collection
  :after evil
  :config
  (evil-collection-init))

General

(use-package general
  :after evil
  :config
  (general-evil-setup t)

  ;; Prevent "X starts with non-prefix key Y" errors except at startup.
  (general-auto-unbind-keys)

  (general-create-definer tf/global-leader-keys
    :states '(normal visual motion emacs)
    :major-modes t
    :keymaps 'override
    :prefix "SPC"
    :global-prefix "C-SPC")

  (general-create-definer tf/leader-key
    :prefix "SPC"))
(general-evil-define-key 'normal 'global
  "g c c" #'evilnc-comment-or-uncomment-lines)
(general-evil-define-key 'visual 'global
  "g c" #'evilnc-comment-or-uncomment-lines
  "g r" #'eval-region)
(tf/global-leader-keys
 "." '(find-file :which-key "Find file")
 "`" '(evil-switch-to-windows-last-buffer :which-key "Switch to last buffer")
 "'" '(vertico-repeat :which-key "Repeat last search")
 "SPC" '(consult-find :which-key "Find file")

 "b" '(:ignore t :which-key "buffers")
 "bk" '(kill-current-buffer :which-key "Kill buffer")
 "bb" '(consult-buffer :which-key "Switch buffer preview")
 "bB" '(switch-to-buffer :which-key "Switch buffer")
 "bi" '(ibuffer :which-key "iBuffer")
 "bs" '(basic-save-buffer :which-key "Save buffer")

 "s" '(:ignore t :which-key "search")
 "ss" '(consult-line :which-key "Search buffer")
 "sb" '(consult-line :which-key "Search buffer")
 "sp" '(consult-ripgrep :which-key "Search project")

 "t" '(:ignore t :which-key "toggle")
 "tw" '(toggle-truncate-lines :which-key "Lines wrapping")

 ;; Bind "SPC w" to "C-w".
 "w" '(evil-window-map :which-key "window")

 ;; Bind "SPC h" to "C-h".
 "h" '(help-command :which-key "help")
 "ht" '(consult-theme :which-key "Load theme")

 "f" '(:ignore t :which-key "file")
 "ff" '(find-file :which-key "Find file")
 "fr" '(consult-recent-file :which-key "Recent files")
 "fC" '(copy-file :which-key "Copy this file")
 "fs" '(save-buffer :which-key "Save file")
 "fD" '(delete-file :which-key "Delete this file")
 "fR" '(rename-file :which-key "Rename/move file")
 ;; "f u" '(sudo-edit-find-file :which-key "Sudo find file")
 ;; "f U" '(sudo-edit :which-key "Sudo this file")
 ;; "f p" TODO
 "o" '(:ignore t :which-key "open")
 "ox" '(consult-file-externally :which-key "Open file externally")

 "q" '(:ignore t :which-key "quit")
 "qq" '(save-buffers-kill-terminal :which-key "Save and quit Emacs")
 "qr" '(:ignore t :which-key "reload")
 "qrR" '(tf/reload-config :which-key "Reload Emacs config")
 )
(general-define-key
 :keymaps 'help-map
 ;; allow keys before bound keys in match
 ;; since binding in a prefix map
 :wk-full-keys nil
 ;; make a prefix-command and add description
 "r" '(:prefix-command tf/reload-prefix-map :which-key "reload")
 "rr" '(tf/reload-config :which-key "Reload Emacs config")
 )
(defconst tf/config-file
  (expand-file-name (concat user-emacs-directory "init.el")))

(defun tf/reload-config ()
    "Loads user init.el file"
    (interactive)
  (load-file tf/config-file))

Hydra

(use-package hydra
  :defer t)

(defhydra hydra-text-scale (:timeout 4)
  "scale text"
  ("j" text-scale-increase "in")
  ("k" text-scale-decrease "out")
  ("q" nil "quit" :exit t))

(tf/global-leader-keys
 "ts" '(hydra-text-scale/body :which-key "Scale text"))

Org mode

Misc

(use-package org
  :ensure nil
  :defer t
  :hook (org-mode . org-indent-mode)
  :custom-face
  ;; (org-block ((t (:inherit fixed-pitch))))
  ;; (org-code ((t (:inherit (shadow fixed-pitch)))))
  :config
  (setq org-ellipsis ""
        org-enforce-todo-dependencies t
        org-eldoc-breadcrumb-separator ""
        org-fontify-done-headline t
        org-fontify-quote-and-verse-blocks t
        org-fontify-whole-heading-line t
        org-hide-leading-stars t
        org-imenu-depth 6

        org-return-follows-link t
        org-mouse-1-follows-link t

        org-edit-src-code-indentation 0
        org-src-fontify-natively t
        org-src-tab-acts-natively t
        org-src-preserve-indentation t
        org-confirm-babel-evaluate nil
        org-link-elisp-confirm-function nil))


;; FIXME

;; (defvar org-src-mode-map
;;   (let ((map (make-sparse-keymap)))
;;     (define-key map "\C-c'" 'org-edit-src-exit)
;;     (define-key map "\C-c\C-k" 'org-edit-src-abort)
;;     (define-key map "\C-x\C-s" 'org-edit-src-save)
;;     map))

;; (add-hook 'org-load-hook
;;           (define-key org-src-mode-map (kbd "C-c C-c") #'org-edit-src-exit))

Workflow

(setq org-directory "~/Documents/orgfiles/")

Most of those come from Doom.

Utils

(with-no-warnings
  (custom-declare-face '+org-todo-active
                       '((t (:inherit (bold font-lock-constant-face org-todo)))) "")
  (custom-declare-face '+org-todo-project
                       '((t (:inherit (bold font-lock-doc-face org-todo)))) "")
  (custom-declare-face '+org-todo-onhold
                       '((t (:inherit (bold warning org-todo)))) "")
  (custom-declare-face '+org-todo-cancel
                       '((t (:inherit (bold error org-todo)))) ""))
(defun +org--capture-local-root (path)
  (let ((filename (file-name-nondirectory path)))
    (expand-file-name
     filename
     (or (locate-dominating-file (file-truename default-directory)
                                 filename)
         (projectile-project-root)
         (user-error "Couldn't detect a project")))))

(defun +org-capture-project-todo-file ()
  "Find the nearest `+org-capture-todo-file' in a parent directory, otherwise,
opens a blank one at the project root. Throws an error if not in a project."
  (+org--capture-local-root "todo.org"))

;;;###autoload
(defun +org-capture-project-notes-file ()
  "Find the nearest `+org-capture-notes-file' in a parent directory, otherwise,
opens a blank one at the project root. Throws an error if not in a project."
  (+org--capture-local-root "project.org"))

;;;###autoload
(defun +org-capture-project-changelog-file ()
  "Find the nearest `+org-capture-changelog-file' in a parent directory,
otherwise, opens a blank one at the project root. Throws an error if not in a
project."
  (+org--capture-local-root "changelog.org"))

(defun +org--capture-ensure-heading (headings &optional initial-level)
  (if (not headings)
      (widen)
    (let ((initial-level (or initial-level 1)))
      (if (and (re-search-forward (format org-complex-heading-regexp-format
                                          (regexp-quote (car headings)))
                                  nil t)
               (= (org-current-level) initial-level))
          (progn
            (beginning-of-line)
            (org-narrow-to-subtree))
        (goto-char (point-max))
        (unless (and (bolp) (eolp)) (insert "\n"))
        (insert (make-string initial-level ?*)
                " " (car headings) "\n")
        (beginning-of-line 0))
      (+org--capture-ensure-heading (cdr headings) (1+ initial-level)))))

(defun +org--capture-central-file (file project)
  (let ((file (expand-file-name file org-directory)))
    (set-buffer (org-capture-target-buffer file))
    (org-capture-put-target-region-and-position)
    (widen)
    (goto-char (point-min))
    ;; Find or create the project headling
    (+org--capture-ensure-heading
     (append (org-capture-get :parents)
             (list project (org-capture-get :heading))))))

(defun +org-capture-central-project-file ()
  "TODO"
  (+org--capture-central-file
   "projects.org" (projectile-project-name)))

Actual

(setq org-todo-keywords
      '((sequence
           "TODO(t)"  ; A task that needs doing & is ready to do
           "PROJ(p)"  ; A project, which usually contains other tasks
           "LOOP(r)"  ; A recurring task
           "STRT(s)"  ; A task that is in progress
           "WAIT(w)"  ; Something external is holding up this task
           "HOLD(h)"  ; This task is paused/on hold because of me
           "IDEA(i)"  ; An unconfirmed and unapproved task or notion
           "|"
           "DONE(d)"  ; Task successfully completed
           "KILL(k)") ; Task was cancelled, aborted or is no longer applicable
          (sequence
           "[ ](T)"   ; A task that needs doing
           "[-](S)"   ; Task is in progress
           "[?](W)"   ; Task is being held up or paused
           "|"
           "[X](D)")  ; Task was completed
          (sequence
           "|"
           "OKAY(o)"
           "YES(y)"
           "NO(n)"))
      org-todo-keyword-faces '(("[-]"  . +org-todo-active)
                               ("STRT" . +org-todo-active)
                               ("[?]"  . +org-todo-onhold)
                               ("WAIT" . +org-todo-onhold)
                               ("HOLD" . +org-todo-onhold)
                               ("PROJ" . +org-todo-project)
                               ("NO"   . +org-todo-cancel)
                               ("KILL" . +org-todo-cancel)))
(setq org-capture-templates
        '(("t" "Personal todo" entry (file+headline "todo.org" "Inbox")
           "* TODO %?\n%i\n%a" :prepend t)
          ("n" "Personal notes" entry (file+headline "notes.org" "Inbox")
           "* %u %?\n%i\n%a" :prepend t)
          ("j" "Journal" entry (file+olp+datetree "journal.org")
           "* %U %?\n%i\n%a" :prepend t)
          ("b" "Book" entry (file+headline "books.org" "Books")
           "* %^{Author} - %^{Title} %^g\n" :prepend t)
          ("l" "Link" entry (file+headline "links.org" "Links")
           "* %x %^g\n" :immediate-finish t :prepend t)

          ;; TODO
          ;; Will use {project-root}/{todo,notes,changelog}.org, unless a
          ;; {todo,notes,changelog}.org file is found in a parent directory.
          ("p" "Templates for projects")
          ("pt" "Project-local todo" entry  ; {project-root}/todo.org
           (file+headline +org-capture-project-todo-file "Inbox")
           "* TODO %?\n%i\n%a" :prepend t)
          ("pn" "Project-local notes" entry  ; {project-root}/notes.org
           (file+headline +org-capture-project-notes-file "Inbox")
           "* %U %?\n%i\n%a" :prepend t)
          ("pc" "Project-local changelog" entry  ; {project-root}/changelog.org
           (file+headline +org-capture-project-changelog-file "Unreleased")
           "* %U %?\n%i\n%a" :prepend t)

          ;; Will use {org-directory}/{+org-capture-projects-file} and store
          ;; these under {ProjectName}/{Tasks,Notes,Changelog} headings. They
          ;; support `:parents' to specify what headings to put them under, e.g.
          ;; :parents ("Projects")
          ("o" "Centralized templates for projects")
          ("ot" "Project todo" entry
           (function +org-capture-central-project-file)
           "* TODO %?\n %i\n %a"
           :heading "Tasks"
           :prepend nil)
          ("on" "Project notes" entry
           (function +org-capture-central-project-file)
           "* %U %?\n %i\n %a"
           :heading "Notes"
           :prepend t)
          ("oc" "Project changelog" entry
           (function +org-capture-central-project-file)
           "* %U %?\n %i\n %a"
           :heading "Changelog"
           :prepend t)))

Packages

(use-package org-bullets
  :hook (org-mode . org-bullets-mode))
Typing the below + TABExpands to
<a#+BEGIN_EXPORT ascii
<c#+BEGIN_CENTER
<C#+BEGIN_COMMENT
<e#+BEGIN_EXAMPLE
<E#+BEGIN_EXPORT
<h#+BEGIN_EXPORT html
<l#+BEGIN_EXPORT latex
<q#+BEGIN_QUOTE
<s#+BEGIN_SRC
<v#+BEGIN_VERSE
(use-package org-tempo
  :ensure nil ; builtin
  :after org)
(use-package toc-org
  :commands toc-org-enable
  :init (add-hook 'org-mode-hook 'toc-org-enable))

org-cycle improvments

Taken from Doom Emacs

  (defun +org-cycle-only-current-subtree-h (&optional arg)
  "Toggle the local fold at the point, and no deeper.
`org-cycle's standard behavior is to cycle between three levels: collapsed,
subtree and whole document. This is slow, especially in larger org buffer. Most
of the time I just want to peek into the current subtree -- at most, expand
*only* the current subtree.

All my (performant) foldings needs are met between this and `org-show-subtree'
(on zO for evil users), and `org-cycle' on shift-TAB if I need it."
  (interactive "P")
  (unless (or (eq this-command 'org-shifttab)
              (and (bound-and-true-p org-cdlatex-mode)
                   (or (org-inside-LaTeX-fragment-p)
                       (org-inside-latex-macro-p))))
    (save-excursion
      (org-beginning-of-line)
      (let (invisible-p)
        (when (and (org-at-heading-p)
                   (or org-cycle-open-archived-trees
                       (not (member org-archive-tag (org-get-tags))))
                   (or (not arg)
                       (setq invisible-p (outline-invisible-p (line-end-position)))))
          (unless invisible-p
            (setq org-cycle-subtree-status 'subtree))
          (org-cycle-internal-local)
          t)))))
(general-evil-define-key 'normal org-mode-map
  "TAB" 'org-cycle)

(add-hook 'org-tab-first-hook #'+org-cycle-only-current-subtree-h)

Prog mode

Programing preferences

Remove trailing whitespaces on save.

(add-hook 'before-save-hook 'whitespace-cleanup)
(add-hook 'before-save-hook (lambda() (delete-trailing-whitespace)))

Spaces instead of tabs

(setq-default indent-tabs-mode nil)

Parens

(use-package rainbow-delimiters
  :hook (prog-mode . rainbow-delimiters-mode))
(use-package smartparens
  :hook
  (add-hook 'prog-mode-hook #'smartparens-mode))

(use-package evil-smartparens
  :hook
  (add-hook 'smartparens-enabled-hook #'evil-smartparens-mode))

Direnv

(use-package direnv
  :init
  (add-hook 'rust-mode-hook #'direnv-update-environment)
  :config
  (direnv-mode))

Compile

(use-package ansi-color
  :config
  (defun my/colorize-compilation-buffer ()
    (when (eq major-mode 'compilation-mode)
      (ansi-color-apply-on-region compilation-filter-start (point-max))))
  :hook (compilation-filter . my/colorize-compilation-buffer))
(with-eval-after-load 'compile
  (setq compilation-scroll-output t))

Flycheck

This is a better checker than the default Emacs Flymake.

(use-package flycheck
  :commands (flycheck-list-errors flycheck-buffer)
  :hook (after-init . global-flycheck-mode)
  :config
  (setq flycheck-emacs-lisp-load-path 'inherit
        flycheck-idle-change-delay 1.0
        ;; For the above functionality, check syntax in a buffer that you switched to
        ;; only briefly. This allows "refreshing" the syntax check state for several
        ;; buffers quickly after e.g. changing a config file.
        flycheck-buffer-switch-check-intermediat-buffers t
        flycheck-display-error-delay 0.25)
  (add-hook 'doom-escape-hook :append
            (defun +syntax-check-buffer-h ()
              "Flycheck buffer on ESC in normal mode."
              (when flycheck-mode
                (ignore-errors (flycheck-buffer))
                nil)))
  )

Treemacs

(use-package treemacs
  :defer t
  :init
  (tf/leader-key
    :states 'normal
    "o" '(:ignore :which-key "open")
    "op" '(treemacs :which-key "Project sidebar"))
  :config
  (setq treemacs-show-cursor t
        treemacs-workspace-switch-cleanup t
        treemacs-project-follow-mode t
        treemacs-project-follow-cleanup t))

(use-package treemacs-evil
  :after (treemacs evil)
  :config
  (general-define-key
   :keymaps 'evil-treemacs-state-map
    [return] #'treemacs-RET-action
    [tab]    #'treemacs-TAB-action
    "TAB"    #'treemacs-TAB-action
    "o v"    #'treemacs-visit-node-horizontal-split
    "o s"    #'treemacs-visit-node-vertical-split)
  (tf/leader-key
    :keymaps 'evil-treemacs-state-map
    "o" '(:ignore :which-key "open")
    "op" '(treemacs-quit :which-key "Project sidebar")))

(use-package treemacs-projectile
  :after (treemacs projectile))

Projects

(use-package projectile
  :commands (projectile-project-root
             projectile-project-name
             projectile-project-p
             projectile-locate-dominating-file
             projectile-relevant-known-projects)
  :init
  (setq projectile-ignored-projects '("~/"))

  (global-set-key [remap evil-jump-to-tag] #'projectile-find-tag)
  (global-set-key [remap find-tag]         #'projectile-find-tag)

  :config (projectile-mode))
(tf/global-leader-keys
  "SPC" '(projectile-find-file :which-key "Find file in project")
  "p" '(:ignore t :which-key "project")
  "p p" '(projectile-switch-project :which-key "Switch project")
  "p a" '(projectile-add-known-project :which-key "Add new project")
  "p s" '(projectile-save-project-buffers :which-key "Save project files")
  "p T" '(projectile-test-project :which-key "Test project")
  "p d" '(projectile-remove-known-project :which-key "Remove known project")
  "p k" '(projectile-kill-buffers :which-key "Kill project buffers")
  "p c" '(projectile-compile-project :which-key "Compile project")
  "p f" '(projectile-find-file :which-key "Find file in project")
  )

Commenting

The keybinding needs to be added.

(use-package evil-nerd-commenter
  :after evil
  :commands evilnc-comment-or-uncomment-lines)

Helpful

(use-package helpful
  :commands (helpful-callable helpful-variable helpful-command helpful-key)
  :custom
  (describe-function #'helpful-callable)
  (describe-variable #'helpful-variable)
  :bind
  ([remap describe-function] . describe-function)
  ([remap describe-command] . helpful-command)
  ([remap describe-variable] . describe-variable)
  ([remap describe-key] . helpful-key))

Git

(use-package magit
  :commands (magit-status magit-init)
  :config
  (setq magit-save-repository-buffers nil)

  ;; start git-commit-mode in insert mode if the commit message is empty
  (add-hook 'git-commit-setup-hook
            (lambda () (when (and (bound-and-true-p evil-mode)
                                  (not (evil-emacs-state-p))
                                  (bobp) (eolp))
                         (evil-insert-state)))))

(use-package magit-todos
  :after magit
  :config
  ;; taken from Doom
  (setq magit-todos-keyword-suffix "\\(?:([^)]+)\\)?:?") ; make colon optional
  (define-key magit-todos-section-map "j" nil))
(tf/global-leader-keys
  "g" '(:ignore t :which-key "git")
  "g g" '(magit-status :which-key "Magit status"))

Code completion

(defun corfu-enable-always-in-minibuffer ()
  "Enable Corfu in the minibuffer if Vertico/Mct are not active."
  (unless (or (bound-and-true-p mct--active)
              (bound-and-true-p vertico--input))
      ;; (setq-local corfu-auto nil) Enable/disable auto completion
      (corfu-mode 1)))

(use-package corfu
  :custom
  (corfu-cycle t)                ;; Enable cycling for `corfu-next/previous'
  (corfu-auto t)                 ;; Enable auto completion
  (corfu-separator ?\s)          ;; Orderless field separator
  ;; (corfu-quit-at-boundary nil)   ;; Never quit at completion boundary
  ;; (corfu-quit-no-match nil)      ;; Never quit, even if there is no match
  (corfu-preview-current nil)    ;; Disable current candidate preview
  ;; (corfu-preselect-first nil)    ;; Disable candidate preselection
  ;; (corfu-on-exact-match nil)     ;; Configure handling of exact matches
  ;; (corfu-echo-documentation nil) ;; Disable documentation in the echo area
  ;; (corfu-scroll-margin 5)        ;; Use scroll margin

  ;; You may want to enable Corfu only for certain modes.
  ;; :hook ((prog-mode . corfu-mode)
  ;;        (shell-mode . corfu-mode)
  ;;        (eshell-mode . corfu-mode))

  :bind (:map corfu-map
              ("ESC" . corfu-reset)
              ("TAB" . corfu-next)
              ([tab] . corfu-next)
              ("C-j" . corfu-next)
              ("S-TAB" . corfu-previous)
              ([backtab] . corfu-previous)
              ("C-k" . corfu-previous))

  ;; Recommended: Enable Corfu globally.
  ;; This is recommended since dabbrev can be used globally (M-/).
  :init
  (global-corfu-mode)
  :config
  (setq corfu-auto-delay 0.0 ; default is 0.2
        corfu-echo-documentation 0.5 ; default is (1.0 . 2.0)
        )
  (add-hook 'minibuffer-setup-hook #'corfu-enable-always-in-minibuffer 1))

Backend for corfu

(use-package cape
  ;; Bind dedicated completion commands
  ;; :bind (("C-c p p" . completion-at-point) ;; capf
  ;;        ("C-c p t" . complete-tag)        ;; etags
  ;;        ("C-c p d" . cape-dabbrev)        ;; or dabbrev-completion
  ;;        ("C-c p f" . cape-file)
  ;;        ("C-c p k" . cape-keyword)
  ;;        ("C-c p s" . cape-symbol)
  ;;        ("C-c p a" . cape-abbrev)
  ;;        ("C-c p i" . cape-ispell)
  ;;        ("C-c p l" . cape-line)
  ;;        ("C-c p w" . cape-dict)
  ;;        ("C-c p \\" . cape-tex)
  ;;        ("C-c p _" . cape-tex)
  ;;        ("C-c p ^" . cape-tex)
  ;;        ("C-c p &" . cape-sgml)
  ;;        ("C-c p r" . cape-rfc1345))
  :init
  ;; Add `completion-at-point-functions', used by `completion-at-point'.
  (add-to-list 'completion-at-point-functions #'cape-file)
  (add-to-list 'completion-at-point-functions #'cape-tex)
  (add-to-list 'completion-at-point-functions #'cape-dabbrev)
  (add-to-list 'completion-at-point-functions #'cape-keyword)
  ;;(add-to-list 'completion-at-point-functions #'cape-sgml)
  ;;(add-to-list 'completion-at-point-functions #'cape-rfc1345)
  (add-to-list 'completion-at-point-functions #'cape-abbrev)
  ;;(add-to-list 'completion-at-point-functions #'cape-ispell)
  ;;(add-to-list 'completion-at-point-functions #'cape-dict)
  ;;(add-to-list 'completion-at-point-functions #'cape-symbol)
  ;;(add-to-list 'completion-at-point-functions #'cape-line)
)

Icons

(use-package kind-icon
  :after corfu
  :custom
  (kind-icon-default-face 'corfu-default) ; to compute blended backgrounds correctly
  :config
  (add-to-list 'corfu-margin-formatters #'kind-icon-margin-formatter))

Snippets

(use-package yasnippet
  :defer t
  ;; TODO configure yas-snippet-dirs
  :init (yas-global-mode 1))

LSP

LSP optimization mode

This was stolen from Doom.

;;
;;; Common

(defvar +lsp--default-read-process-output-max nil)
(defvar +lsp--default-gcmh-high-cons-threshold nil)
(defvar +lsp--optimization-init-p nil)

(define-minor-mode +lsp-optimization-mode
  "Deploys universal GC and IPC optimizations for `lsp-mode' and `eglot'."
  :global t
  :init-value nil
  (if (not +lsp-optimization-mode)
      (setq-default read-process-output-max +lsp--default-read-process-output-max
                    gcmh-high-cons-threshold +lsp--default-gcmh-high-cons-threshold
                    +lsp--optimization-init-p nil)
    ;; Only apply these settings once!
    (unless +lsp--optimization-init-p
      (setq +lsp--default-read-process-output-max
            ;; DEPRECATED Remove check when 26 support is dropped
            (if (boundp 'read-process-output-max)
                (default-value 'read-process-output-max))
            +lsp--default-gcmh-high-cons-threshold
            (default-value 'gcmh-high-cons-threshold))
      ;; `read-process-output-max' is only available on recent development
      ;; builds of Emacs 27 and above.
      (setq-default read-process-output-max (* 1024 1024))
      ;; REVIEW LSP causes a lot of allocations, with or without Emacs 27+'s
      ;;        native JSON library, so we up the GC threshold to stave off
      ;;        GC-induced slowdowns/freezes. Doom uses `gcmh' to enforce its
      ;;        GC strategy, so we modify its variables rather than
      ;;        `gc-cons-threshold' directly.
      (setq-default gcmh-high-cons-threshold (* 2 +lsp--default-gcmh-high-cons-threshold))
      (gcmh-set-high-threshold)
      (setq +lsp--optimization-init-p t))))

LSP mode

(use-package lsp-mode
  :commands lsp
  :custom (lsp-completion-provider :none) ;; use corfu instead
  :hook
  (lsp-mode . lsp-enable-which-key-integration)
  (lsp-completion-mode . my/lsp-mode-setup-completion)
  :init
  (setq lsp-keymap-prefix nil ;; do it later
        read-process-output-max (* 1024 1024) ;; 1mb
        lsp-idle-delay 0
        lsp-enable-on-type-formatting nil
        lsp-headerline-breadcrumb-enable t
        lsp-headerline-breadcrumb-segments '(project file symbols)
        lsp-enable-suggest-server-download nil)

  ;; taken from corfu wiki
  (defun my/orderless-dispatch-flex-first (_pattern index _total)
    (and (eq index 0) 'orderless-flex))

  (defun my/lsp-mode-setup-completion ()
    (setf (alist-get 'styles (alist-get 'lsp-capf completion-category-defaults))
          '(orderless)))
  ;; configure the cape-capf-buster.
  (setq-local completion-at-point-functions (list (cape-capf-buster #'lsp-completion-at-point)))

  :config
  (add-hook 'doom-escape-hook
    (defun +lsp-signature-stop-maybe-h ()
      "Close the displayed `lsp-signature'."
      (when lsp-signature-mode
        (lsp-signature-stop)
        t)))
  (general-define-key
   :keymaps 'lsp-mode-map
   :states 'normal
    "K" #'lsp-describe-thing-at-point)
  )

(use-package consult-lsp
  :defer t ;; HACK can't be loaded after lsp-mode
  :init
  (general-define-key
   :keymaps 'lsp-mode-map
   [remap xref-find-apropos] #'consult-lsp-symbols))
(use-package lsp-treemacs
  :after lsp
  :init (lsp-treemacs-sync-mode 1))

Eglot

This section is not tangled right now. I prefer LSP mode.

(use-package eglot
  :after direnv
  :hook
  (c-mode    . eglot-ensure)
  (c++-mode  . eglot-ensure)
  (rust-mode . eglot-ensure)
  :config
  (setq eglot-autoshutdown t
        eldoc-idle-delay 2.5 ;; long delay to avoid anoying popup
        )
  ;; TODO define this only for eglot keymap
  (tf/global-leader-keys
    "c" '(:ignore t :which-key "code")
    "ca" '(eglot-code-actions :which-key "LSP code actions")
    "cr" '(eglot-rename :which-key "LSP rename"))
  (general-evil-define-key 'normal 'eglot-mode-map
    "g D" #'xref-find-references)
  )

(use-package consult-eglot
  :after eglot
  :init
  (general-define-key
   :keymaps 'eglot-mode-map
   [remap xref-find-apropos] #'consult-eglot-symbols))

Languages

Nix

(use-package nix-mode
  :mode "\\.nix\\'"
  :init
  (tf/leader-key
    :keymaps 'nix-mode-map
    :states 'normal
    "c" '(:ignore :which-key "code")
    "cf" '(nix-format-buffer :which-key "Format buffer")))

VHDL

(use-package vhdl-mode
  :mode "\\.vhdl\\'")

Rasi

(use-package css-mode
  :mode "\\.rasi\\'")

C

(use-package clang-format
  :commands (clang-format-buffer clang-format-region)
  :init
  (tf/leader-key
   :keymaps '(c-mode-map c++-mode-map)
   :states 'normal
   "c" '(:ignore :which-key "code")
   "cf" '(clang-format-buffer :which-key "Clang-format buffer")))
(setq c-default-style "user")

Rust

(use-package rust-mode
  :mode "\\.rs\\'"
  ;; :hook (rust-mode . eglot-ensure)
  :hook (rust-mode . lsp-deferred)
  :config
  (setq indent-tabs-mode nil)
  (tf/leader-key
    :keymaps 'rust-mode-map
    :states 'normal
    "c" '(:ignore :which-key "code")
    "cf" '(rust-format-buffer :which-key "Format buffer")

    "p" '(:ignore :which-key "project")
    "pR" '(rust-run :which-key "Run project")
    "pc" '(rust-compile :which-key "Compile project"))
  (prettify-symbols-mode)
  )

PDFs

(use-package pdf-tools
  :mode "\\.pdf\\'"
  :init (pdf-tools-install))

Literate

Keep a custom file to not pollute this one

(setq custom-file (concat user-emacs-directory "custom.el"))
(load custom-file t)

;; Local Variables: ;; eval: (add-hook ‘after-save-hook ‘org-babel-tangle) ;; End:

emacs-gnu's People

Contributors

tristanfloch avatar

Watchers

 avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.