diff --git a/.emacs.vanilla/early-init.el b/.emacs.vanilla/early-init.el deleted file mode 100644 index e963372..0000000 --- a/.emacs.vanilla/early-init.el +++ /dev/null @@ -1,7 +0,0 @@ -(setq package-enable-at-startup nil) -(setq inhibit-startup-message t) -(scroll-bar-mode -1) ; disable scrollbar -(tool-bar-mode -1) ; disable toolbar -(tooltip-mode -1) ; disable tooltips -(set-fringe-mode 10) ; give some breathing room -(menu-bar-mode -1) ; disable menubar diff --git a/.emacs.vanilla/init.el b/.emacs.vanilla/init.el deleted file mode 100644 index 92942d9..0000000 --- a/.emacs.vanilla/init.el +++ /dev/null @@ -1,962 +0,0 @@ -;;; init.el --- My vanilla Emacs configuration -*- lexical-binding: t -*- - -;; Author: Lucien Cartier-Tilet -;; Maintainer: Lucien Cartier-Tilet -;; Version: 0.1.0 -;; Package-Requires: ((emacs "27.1")) -;; Homepage: https://labs.phundrak.com/phundrak/dotfiles - - -;; This file is not part of GNU Emacs - -;; This program is free software: you can redistribute it and/or modify -;; it under the terms of the GNU General Public License as published by -;; the Free Software Foundation, either version 3 of the License, or -;; (at your option) any later version. - -;; This program is distributed in the hope that it will be useful, -;; but WITHOUT ANY WARRANTY; without even the implied warranty of -;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -;; GNU General Public License for more details. - -;; You should have received a copy of the GNU General Public License -;; along with this program. If not, see . - - -;;; Commentary: - -;; commentary - -;;; Code: - -(setq user-full-name "Lucien Cartier-Tilet" - user-real-login-name "Lucien Cartier-Tilet" - user-login-name "phundrak" - user-mail-address "lucien@phundrak.com") - -(setq indent-tabs-mode nil) - -(defvar phundrak/default-font-size 90 - "Default font size.") - -(setq-default custom-file (expand-file-name ".custom.el" user-emacs-directory)) -(when (file-exists-p custom-file) - (load custom-file)) - -(setq visible-bell t) ; set up visible bell - -(setq display-time-format "%Y-%m-%d %H:%M") -(display-time-mode 1) ; display time in modeline - -;; Display battery in modeline when using a laptop -(unless (equal "Battery status not available" - (battery)) - (display-battery-mode 1)) - -(set-face-attribute 'default nil :font "Cascadia Code" :height phundrak/default-font-size) - - -(setq frame-title-format - '("" - "%b" - (:eval - (let ((project-name (projectile-project-name))) - (unless (string= "-" project-name) - (format (if (buffer-modified-p) " ◉ %s" "  ●  %s") project-name)))))) - -;; Make ESC quit prompts -(global-set-key (kbd "") 'keyboard-escape-quit) - -;; Answer with y or n, not yes or not -(defalias 'yes-or-no-p 'y-or-n-p) - -(column-number-mode) -(global-display-line-numbers-mode t) -;; Disable line numbers for some modes -(dolist (mode '(org-mode-hook - term-mode-hook - shell-mode-hook - eshell-mode-hook - vterm-mode-hook - special-mode-hook - helpful-mode-hook - woman-mode-hook)) - (add-hook mode (lambda () (display-line-numbers-mode 0)))) - -(setq x-stretch-cursor t ; stretch cursor to the glyph’s width - delete-by-moving-to-trash t ; delete files to trash - window-combination-resize t ; take new window space from all other windows - undo-limit 100000000 ; raise undo limit to 100Mb - auto-save-default t - truncate-string-ellipsis "…") - -(global-subword-mode 1) - -(setq-default major-mode 'org-mode) - -(defun modeline-contitional-buffer-encoding () - "Hide \"LF UTF-8\" in modeline. - -It is expected of files to be encoded with LF UTF-8, so only show -the encoding in the modeline if the encoding is worth notifying -the user." - (setq-local doom-modeline-buffer-encoding - (unless (and (memq (plist-get (coding-system-plist buffer-file-coding-system) :category) - '(coding-category-undecided coding-category-utf-8)) - (not (memq (coding-system-eol-type buffer-file-coding-system) '(1 2)))) - t))) - -(add-hook 'after-change-major-mode-hook #'modeline-contitional-buffer-encoding) -(add-hook 'prog-mode-hook #'hs-minor-mode) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - ; Packages ; -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;; Initialize package sources -;; (require 'package) -(setq package-archives '(("melpa" . "https://melpa.org/packages/") - ("org" . "https://orgmode.org/elpa/") - ("elpa" . "https://elpa.gnu.org/packages/"))) - -(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)) - -(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) -(setq use-package-always-ensure t) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Keybinding packages -(use-package spaceleader - :defer t - :after bind-map - :straight (spaceleader :type git - :host github - :repo "mohkale/spaceleader") - :config - (setq leader-key "SPC" - leader-major-mode-prefix ",")) - -(use-package evil - :straight (:build t) - :init - (setq evil-want-integration t) - (setq evil-want-keybinding nil) - (setq evil-want-C-u-scroll t) - (setq evil-want-C-i-jump nil) - :config - (evil-mode 1) - (setq evil-want-fine-undo t) ; more granular undo with evil - - ;; Use visual line motions even outside of visual-line-mode buffers - (evil-global-set-key 'motion "t" 'evil-next-visual-line) - (evil-global-set-key 'motion "s" 'evil-previous-visual-line) - - (define-key evil-normal-state-map "c" nil) - (define-key evil-normal-state-map "C" nil) - (define-key evil-normal-state-map "t" nil) - (define-key evil-normal-state-map "T" nil) - (define-key evil-normal-state-map "s" nil) - (define-key evil-normal-state-map "S" nil) - (define-key evil-normal-state-map "r" nil) - (define-key evil-normal-state-map "R" nil) - (define-key evil-normal-state-map "h" nil) - (define-key evil-normal-state-map "H" nil) - (define-key evil-normal-state-map "j" nil) - (define-key evil-normal-state-map "J" nil) - (define-key evil-normal-state-map "k" nil) - (define-key evil-normal-state-map "K" nil) - (define-key evil-normal-state-map "l" nil) - (define-key evil-normal-state-map "L" nil) - - (define-key evil-motion-state-map "h" 'evil-replace) - (define-key evil-motion-state-map "H" 'evil-replace-state) - (define-key evil-motion-state-map "j" 'evil-find-char-to) - (define-key evil-motion-state-map "J" 'evil-find-char-to-backward) - (define-key evil-motion-state-map "k" 'evil-substitute) - (define-key evil-motion-state-map "K" 'evil-smart-doc-lookup) - (define-key evil-motion-state-map "l" 'evil-change) - (define-key evil-motion-state-map "L" 'evil-change-line) - - (define-key evil-motion-state-map "c" 'evil-backward-char) - (define-key evil-motion-state-map "C" 'evil-window-top) - (define-key evil-motion-state-map "t" 'evil-next-line) - (define-key evil-motion-state-map "T" 'evil-join) - (define-key evil-motion-state-map "s" 'evil-previous-line) - (define-key evil-motion-state-map "S" 'evil-lookup) - (define-key evil-motion-state-map "r" 'evil-forward-char) - (define-key evil-motion-state-map "R" 'evil-window-bottom) - - (evil-set-initial-state 'messages-buffer-mode 'normal) - (evil-set-initial-state 'dashboard-mode 'normal)) - -(use-package evil-collection - :after evil - :straight (:build t) - :config - (evil-collection-init)) - - - - - - -(use-package command-log-mode - :straight (:build t) - :defer t) - -;; NOTE: The first time you load your configuration on a new machine, -;; you’ll need to run the following command interactively o that mode -;; line icons display correctly: -;; -;; M-x all-the-icons-install-fonts - -(use-package all-the-icons - :straight (:build t) - :defer t) - -;;;;;;;;;;;;;;;;;;;;;;; ivy - -(use-package ivy - :straight (:build t) - :defer t - :diminish - :bind (("C-s" . swiper) - :map ivy-minibuffer-map - ("TAB" . ivy-alt-done) - ("C-l" . ivy-alt-done) - ("C-t" . ivy-next-line) - ("C-s" . ivy-previous-line) - :map ivy-switch-buffer-map - ("C-t" . ivy-next-line) - ("C-s" . ivy-previous-line) - ("C-l" . ivy-done) - ("C-d" . ivy-switch-buffer-kill) - :map ivy-reverse-i-search-map - ("C-t" . ivy-next-line) - ("C-s" . ivy-previous-line) - ("C-d" . ivy-reverse-i-search-kill)) - :config - (ivy-mode 1) - (setq ivy-wrap t - ivy-height 17 - ivy-fixed-height-minibuffer t - ivy-read-action-functions #'ivy-hydra-read-action - ivy-read-action-format-function #'ivy-read-action-format-columns - projectile-completion-system 'ivy - ivy-on-del-error-function #'ignore - ivy-use-selectable-prompt t)) - -(use-package ivy-prescient - :after ivy - :straight (:build t)) - -(use-package all-the-icons-ivy - :straight (:build t) - :after (ivy all-the-icons) - :hook (after-init . all-the-icons-ivy-setup)) - -(use-package ivy-posframe - :after ivy - :hook (ivy-mode . ivy-posframe-mode) - :straight (ivy-posframe :type git - :host github - :repo "tumashu/ivy-posframe") - :config - (setq ivy-fixed-height-minibuffer nil - ivy-posframe-border-width 10 - ivy-posframe-parameters - `((min-width . 90) - (min-height . ,ivy-height)))) - -(use-package ivy-rich - :straight (:build t) - :after ivy - :init - (ivy-rich-mode 1)) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Company - -(use-package company - :straight (:build t) - :defer t - :hook (company-mode . evil-normalize-keymaps) - :init (global-company-mode) - :config - (setq company-minimum-prefix-length 2 - company-toolsip-limit 14 - company-tooltip-align-annotations t - company-require-match 'never - company-global-modes '(not erc-mode message-mode help-mode gud-mode) - company-frontends - '(company-pseudo-tooltip-frontend ; always show candidates in overlay tooltip - company-echo-metadata-frontend) ; show selected candidate docs in echo area - - ;; Buffer-local backends will be computed when loading a major - ;; mode, so only specify a global default here. - company-backends '(company-capf) - - ;; These auto-complete the current selection when - ;; `company-auto-complete-chars' is typed. This is too - ;; magical. We already have the much more explicit RET and - ;; TAB. - company-auto-complete nil - company-auto-complete-chars nil - - ;; Only search the current buffer for `company-dabbrev' (a - ;; backend that suggests text you open buffers). This prevents - ;; Company from causing lag once you have a lot of buffers - ;; open. - company-dabbrev-other-buffers nil - - ;; Make `company-dabbrev' fully case-sensitive, to improve UX - ;; with domai-specific words with particular casing. - company-dabbrev-ignore-case nil - company-dabbrev-downcase nil)) - -(use-package company-dict - :after company - :straight (:build t) - :config - (setq company-dict-dir (expand-file-name "dicts" user-emacs-directory))) - -(use-package company-box - :straight (:build t) - :after (company all-the-icons) - :config - (setq company-box-show-single-candidate t - company-box-backends-colors nil - company-box-max-candidates 50 - company-box-icons-alist 'company-box-icons-all-the-icons - company-box-icons-all-the-icons - (let ((all-the-icons-scale-factor 0.8)) - `((Unknown . ,(all-the-icons-material "find_in_page" :face 'all-the-icons-purple)) - (Text . ,(all-the-icons-material "text_fields" :face 'all-the-icons-green)) - (Method . ,(all-the-icons-material "functions" :face 'all-the-icons-red)) - (Function . ,(all-the-icons-material "functions" :face 'all-the-icons-red)) - (Constructor . ,(all-the-icons-material "functions" :face 'all-the-icons-red)) - (Field . ,(all-the-icons-material "functions" :face 'all-the-icons-red)) - (Variable . ,(all-the-icons-material "adjust" :face 'all-the-icons-blue)) - (Class . ,(all-the-icons-material "class" :face 'all-the-icons-red)) - (Interface . ,(all-the-icons-material "settings_input_component" :face 'all-the-icons-red)) - (Module . ,(all-the-icons-material "view_module" :face 'all-the-icons-red)) - (Property . ,(all-the-icons-material "settings" :face 'all-the-icons-red)) - (Unit . ,(all-the-icons-material "straighten" :face 'all-the-icons-red)) - (Value . ,(all-the-icons-material "filter_1" :face 'all-the-icons-red)) - (Enum . ,(all-the-icons-material "plus_one" :face 'all-the-icons-red)) - (Keyword . ,(all-the-icons-material "filter_center_focus" :face 'all-the-icons-red)) - (Snippet . ,(all-the-icons-material "short_text" :face 'all-the-icons-red)) - (Color . ,(all-the-icons-material "color_lens" :face 'all-the-icons-red)) - (File . ,(all-the-icons-material "insert_drive_file" :face 'all-the-icons-red)) - (Reference . ,(all-the-icons-material "collections_bookmark" :face 'all-the-icons-red)) - (Folder . ,(all-the-icons-material "folder" :face 'all-the-icons-red)) - (EnumMember . ,(all-the-icons-material "people" :face 'all-the-icons-red)) - (Constant . ,(all-the-icons-material "pause_circle_filled" :face 'all-the-icons-red)) - (Struct . ,(all-the-icons-material "streetview" :face 'all-the-icons-red)) - (Event . ,(all-the-icons-material "event" :face 'all-the-icons-red)) - (Operator . ,(all-the-icons-material "control_point" :face 'all-the-icons-red)) - (TypeParameter . ,(all-the-icons-material "class" :face 'all-the-icons-red)) - (Template . ,(all-the-icons-material "short_text" :face 'all-the-icons-green)) - (ElispFunction . ,(all-the-icons-material "functions" :face 'all-the-icons-red)) - (ElispVariable . ,(all-the-icons-material "check_circle" :face 'all-the-icons-blue)) - (ElispFeature . ,(all-the-icons-material "stars" :face 'all-the-icons-orange)) - (ElispFace . ,(all-the-icons-material "format_paint" :face 'all-the-icons-pink)))))) - -;; (setq x-gtk-resize-child-frames 'resize-mode) - - - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Emacs-lisp - -(use-package eldoc - :after company - :init - (eldoc-add-command 'company-complete-selection - 'company-complete-common - 'company-capf - 'company-abort)) - -(leader/set-keys-for-major-mode 'emacs-lisp-mode - "e" '("eval" . "evaluate expression") - "ee" #'eval-last-sexp - "ed" #'eval-defun - "er" #'eval-region - - "h" "help" - "hh" #'helpful-at-point) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; themes - -(use-package doom-modeline - :straight (:build t) - :defer t - :init (doom-modeline-mode 1) - :custom ((doom-modeline-height 15))) - -(use-package doom-themes - :straight (:build t) - :defer t - :init (load-theme 'doom-nord t)) - -(use-package rainbow-delimiters - :straight (:build t) - :defer t - :hook (prog-mode . rainbow-delimiters-mode)) - -(use-package which-key - :straight (:build t) - :defer t - :init (which-key-mode) - :diminish which-key-mode - :config - (setq which-key-idle-delay 0.3)) - -(use-package counsel - :straight (:build t) - :defer t - :bind (("M-x" . counsel-M-x) - ("C-x b" . counsel-ibuffer) - ("C-x C-f" . counsel-find-file) - :map minibuffer-local-map - ("C-r" . 'counsel-minibuffer-history))) - -(use-package helpful - :straight (:build t) - :defer t - :custom - (counsel-describe-function-function #'helpfull-callable) - (counsel-describe-variable-function #'helpfull-variable) - :bind - ([remap describe-function] . counsel-describe-function) - ([remap describe-command] . helpful-command) - ([remap describe-variable] . counsel-describe-variable) - ([remap describe-key] . helpful-key)) - -(use-package bind-map - :straight (:build t) - :defer t) - -(use-package hydra - :straight (:build t) - :defer t) - -(defhydra hydra-text-scale (:timeout 4) - "scale text" - ("t" text-scale-increase "in") - ("s" text-scale-decrease "out") - ("q" nil "quit" :exit t)) - -(use-package projectile - :straight (:build t) - :defer t - :diminish projectile-mode - :config (projectile-mode) - :custom ((projectile-completion-system 'ivy)) - :bind-keymap - ("C-c p" . projectile-command-map) - :init - ;; NOTE: Set this to the folder where you keep your Git repos! - (setq projectile-switch-project-action #'projectile-dired)) - -(use-package counsel-projectile - :straight (:build t) - :after (counsel projectile) - :config (counsel-projectile-mode)) - -(use-package magit - :straight (:build t) - :defer t - :custom - (magit-display-buffer-function #'magit-display-buffer-same-window-except-diff-v1)) - -;; (use-package evil-magit -;; :after magit) - -;; NOTE: Make sure to configure a GitHub token before using this package! -;; - https://magit.vc/manual/forge/Token-Creation.html#Token-Creation -;; - https://magit.vc/manual/ghub/Getting-Started.html#Getting-Started -(use-package forge - :after magit - :straight (:build t)) - -(defun phundrak-find-org-files () - "Find all org files in the directories listed in -`phundrak-org-directories', then list them in an ido buffer where -the user can match one and open it." - (interactive) - (find-file - (ivy-completing-read - "Org File: " - (s-split "\n" - (mapconcat (lambda (path) - (shell-command-to-string - (format "fd . %s -e org -c never" path))) - phundrak-org-directories - "\n"))))) - -(use-package mixed-pitch - :defer t - :straight t - :hook - (org-mode . mixed-pitch-mode)) - -(use-package pdf-tools - :defer t - :magic ("%PDF" . pdf-view-mode) - :straight (pdf-tools :build t - :type git - :host github - :repo "vedang/pdf-tools") - :mode (("\\.pdf\\'" . pdf-view-mode)) - :config - (progn - (with-eval-after-load 'pdf-view - (setq pdf-view-midnight-colors '("#d8dee9" . "#2e3440"))) - (leader/set-keys-for-major-mode 'pdf-view-mode - "a" "annotations" - "f" "fit" - "s" "slice/search" - - ;; slicing image - "sm" 'pdf-view-set-slice-using-mouse - "sb" 'pdf-view-set-slice-from-bounding-box - "sr" 'pdf-view-reset-slice - - ;; annotations - "aD" 'pdf-annot-delete - "at" 'pdf-annot-attachment-dired - "ah" 'pdf-annot-add-highlight-markup-annotation - "al" 'pdf-annot-list-annotations - "am" 'pdf-annot-markup-annotation - "ao" 'pdf-annot-add-strikeout-markup-annotation - "as" 'pdf-annot-add-squiggly-markup-annotation - "at" 'pdf-annot-add-text-annotation - "au" 'pdf-annot-add-underline-markup-annotation - - ;; fit image to window - "fw" 'pdf-view-fit-width-to-window - "fh" 'pdf-view-fit-height-to-window - "fp" 'pdf-view-fit-page-to-window - - ;; other - "ss" 'pdf-occur - "o" 'pdf-outline - "m" 'pdf-view-midnight-minor-mode) - - (evil-define-key 'visual pdf-view-mode-map "y" 'pdf-view-kill-ring-save)) - - :hook - (pdf-tools-enabled . pdf-view-midnight-minor-mode)) - -;;;;;;;;;;;;;;;; Docker - -(use-package docker - :defer t - :straight (:build t)) - -(use-package dockerfile-mode - :defer t - :straight (:build t) - :init - (put 'docker-image-name 'safe-local-variable #'stringp) - :mode "Dockerfile\\'") - -;;;;;;;;;;;;;;;; Dashboard - -(use-package dashboard - :straight (:build t) - :ensure t - :after all-the-icons - :config - (setq dashboard-banner-logo-title "Phundrak’s Vanilla Emacs" - dashboard-startup-banner 'logo - dashboard-center-content t - dashboard-show-shortcuts t - dashboard-set-navigator t - dashboard-set-heading-icons t - dashboard-set-file-icons t - initial-buffer-choice (lambda () (get-buffer "*dashboard*")) - dashboard-projects-switch-function 'counsel-projectile-switch-project-by-name) - (setq dashboard-navigator-buttons - `(((,(all-the-icons-faicon "language" :height 1.1 :v-adjust 0.0) - "Linguistics website" - "" - (lambda (&rest _) (browse-url "https://langue.phundrak.com"))) - - (,(all-the-icons-faicon "firefox" :height 1.1 :v-adjust 0.0) - "Config Website" - "" - (lambda (&rest _) (browse-url "https://config.phundrak.com")))) - - ((,(all-the-icons-octicon "git-branch" :height 1.1 :v-adjust 0.0) - "Dotfiles sources" - "" - (lambda (&rest _) (browse-url "https://labs.phundrak.com/phundrak/dotfiles"))) - ("!" "Issues" "Show issues" (lambda (&rest _) - (browse-url "https://labs.phundrak.com/phundrak/dotfiles/issues")) - warning)) - ((,(all-the-icons-faicon "level-up" :height 1.1 :v-adjust 0.0) - "Update packages" - "" - (lambda (&rest _) (progn - (require 'straight) - (straight-pull-all))))))) - - (setq dashboard-items '((recents . 15) - (projects . 10))) - (dashboard-setup-startup-hook) - :init - (add-hook 'after-init-hook 'dashboard-refresh-buffer)) - -(use-package vterm - :defer t - :straight t - :ensure t) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;; Email - -(use-package mu4e - :straight (:build t :location site) - :commands mu4e mu4e-compose-new - :defer t - :init - (provide 'html2text) - (when (or (not (require 'mu4e-meta nil t)) - (version< mu4e-mu-version "1.4")) - (setq mu4e-maidir "~/.mail" - mu4e-trash-folder "/Trash" - mu4e-refile-folder "/Archive" - mu4e-sent-folder "/Sent" - mu4e-drafts-folder "/Drafts" - mu4e-user-mail-address-list nil)) - (setq mu4e-attachment-dir - (lambda (&rest _) - (expand-file-name ".attachments" (mu4e-roo-maildir)))) - :config - (setq mu4e-get-mail-command "mbsync -a" - mu4e-update-interval 60 - mu4e-compose-format-flowed t - mu4e-view-show-addresses t - mu4e-sent-messages-behaviour 'sent - mu4e-hide-index-messages t - ;; try to show images - mu4e-view-show-images t - mu4e-view-image-max-width 600 - ;; configuration for sending mail - message-send-mail-function #'smtpmail-send-it - smtpmail-stream-type 'starttls - message-kill-buffer-on-exit t ; close after sending - ;; start with the first (default) context - mu4e-context-policy 'pick-first - ;; compose with the current context, or ask - mu4e-compose-context-policy 'ask-if-none - ;; use ivy - mu4e-completing-read-function #'ivy-completing-read - ;; no need to ask - mu4e-confirm-quit t - mu4e-header-fields - '((:account . 12) - (:human-date . 12) - (:flags . 4) - (:from . 25) - (:subject))) - - ;; set mail user agent - (setq mail-user-agent 'mu4e-user-agent) - - ;; Use fancy icons - (setq mu4e-use-fancy-chars t - mu4e-headers-draft-mark `("D" . ,(all-the-icons-faicon "pencil":height 0.8)) - mu4e-headers-flagged-mark `("F" . ,(all-the-icons-faicon "flag":height 0.8)) - mu4e-headers-new-mark `("N" . ,(all-the-icons-faicon "rss":height 0.8)) - mu4e-headers-passed-mark `("P" . ,(all-the-icons-faicon "check":height 0.8)) - mu4e-headers-replied-mark `("R" . ,(all-the-icons-faicon "reply":height 0.8)) - mu4e-headers-seen-mark `("S" . ,(all-the-icons-faicon "eye":height 0.8)) - mu4e-headers-unread-mark `("u" . ,(all-the-icons-faicon "eye-slash":height 0.8)) - mu4e-headers-trashed-mark `("T" . ,(all-the-icons-faicon "trash":height 0.8)) - mu4e-headers-attach-mark `("a" . ,(all-the-icons-faicon "paperclip":height 0.8)) - mu4e-headers-encrypted-mark `("x" . ,(all-the-icons-faicon "lock":height 0.8)) - mu4e-headers-signed-mark `("s" . ,(all-the-icons-faicon "certificate":height 0.8))) - - (setq mu4e-bookmarks - `((,(s-join " " - '("NOT flag:trashed" - "AND (maildir:/Inbox OR maildir:/Junk)" - "AND NOT to:CONLANG@LISTSERV.BROWN.EDU" - "AND NOT to:AUXLANG@LISTSERV.BROWN.EDU" - "AND NOT to:ateliers-emacs@framalistes.org" - "AND NOT to:ateliers-paris@emacs-doctor.com" - "AND NOT list:ateliers-emacs.framalistes.org" - "AND NOT list:ateliers-paris.emacs-doctor.com")) - "Inbox" ?i) ;; Inbox without the linguistics mailing lists - (,(s-join " " - '("NOT flag:trashed" - "AND (maildir:/Inbox OR maildir:/Junk)" - "AND (f:/.*up8\.edu|.*univ-paris8.*/" - "OR c:/.*up8\.edu|.*univ-paris8.*/" - "OR t:/.*up8\.edu|.*univ-paris8.*/)")) - "University" ?u) ;; University-related emails - (,(s-join " " - '("to:CONLANG@LISTSERV.BROWN.EDU" - "OR to:AUXLANG@LISTSERV.BROWN.EDU")) - "Linguistics" ?l) ;; linguistics mailing lists - (,(s-join " " - '("list:ateliers-emacs.framalistes.org" - "OR to:ateliers-paris@emacs-doctor.com" - "OR list:ateliers-paris.emacs-doctor.com")) - "Emacs" ?e) ;; Emacs mailing list - ("maildir:/Sent" "Sent messages" ?s) - ("flag:unread AND NOT flag:trashed" "Unread messages" ?U) - ("date:today..now AND NOT flag:trashed" "Today's messages" ?t) - ("date:7d..now AND NOT flag:trashed" "Last 7 days" ?w) - ("date:1m..now AND NOT flag:trashed" "Last month" ?m) - ("date:1y..now AND NOT flag:trashed" "Last year" ?y) - ("flag:trashed AND NOT flag:trashed" "Trash" ?T) - ("mime:image/* AND NOT flag:trashed" "Messages with images" ?p))) - - ;; Add a column to display what email account the email belongs to. - (add-to-list 'mu4e-header-info-custom - '(:account - :name "Account" - :shortname "Account" - :help "Which account this email belongs to" - :function - (lambda (msg) - (let ((maildir (mu4e-message-field msg :maildir))) - (format "%s" (substring maildir 1 (string-match-p "/" maildir 1))))))) - - (add-to-list 'mu4e-view-actions '("View in browser" . mu4e-action-view-in-browser)) - - (when (fboundp 'imagemagick-register-types) - (imagemagick-register-types))) - -(use-package org-msg - :after (org mu4e) - :straight (:build t) - :hook (mu4e-compose-pre . org-msg-mode) - :config - (setq org-msg-startup "inlineimages" - org-msg-greeting-name-limit 3 - org-msg-default-alternatives '(html text))) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;; Org - -(use-package org-appear - :after org - :straight (:build t) - :hook (org-mode . org-appear-mode) - :config - (setq org-appear-autoemphasis t - org-appear-autolinks t - org-appear-autosubmarkers t) - (run-at-time nil nil #'org-appear--set-elements) - :defer t) - -(use-package org-superstar - :after org - :straight (:build t) - :hook (org-mode . org-superstar-mode) - :config - (setq org-superstar-leading-bullet ?\s - org-superstar-leading-fallback ?\s - org-hide-leading-stars nil - org-superstar-todo-bullet-alist - '(("TODO" . 9744) - ("[ ]" . 9744) - ("DONE" . 9745) - ("[X]" . 9745)))) - -(use-package org-fancy-priorities - :after (org all-the-icons) - :straight (:build t) - :hook (org-mode . org-fancy-priorities-mode) - :hook (org-agenda-mode . org-fancy-priorities-mode) - :config - (setq org-fancy-priorities-list `(,(all-the-icons-faicon "flag" :height 1.1 :v-adjust 0.0) - ,(all-the-icons-faicon "arrow-up" :height 1.1 :v-adjust 0.0) - ,(all-the-icons-faicon "square" :height 1.1 :v-adjust 0.0)))) - -(use-package evil-nerd-commenter - :after evil - :straight (:build t)) - -(use-package yaml-mode - :defer t - :straight (:build t) - :mode "\\.yml\\'" - :mode "\\.yaml\\'") - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Snippets - -(use-package yasnippet - :defer t - :straight (:build t) - :init - (yas-global-mode)) - -(use-package yasnippet-snippets - :after yasnippet - :straight (:build t)) - -(use-package yatemplate - :after yasnippet - :straight (:build t)) - -(use-package ivy-yasnippet - :after (ivy yasnippet) - :straight (:build t)) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - ; Keybindings ; -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -(defvar phundrak-org-directories '("~/org" - "~/Documents/university/S8" - "~/Documents/conlanging") - "Directories in which to look for org files with the function -`phundrak-find-org-files'.") - -(defun split-window-right-and-focus () - (interactive) - (split-window-right) - (windmove-right) - (when (and (boundp 'golden-ratio-mode) - (symbol-value golden-ratio-mode)) - (golden-ratio))) - -(defun split-window-below-and-focus () - (interactive) - (split-window-below) - (windmove-down) - (when (and (boundp 'golden-ratio-mode) - (symbol-value golden-ratio-mode)) - (golden-ratio))) - -(defun ibuffer-list-buffers-and-focus () - (interactive) - (ibuffer-list-buffers) - (windmove-down) - (when (and (boundp 'golden-ratio-mode) - (symbol-value golden-ratio-mode)) - (golden-ratio))) - -(defun eshell-new () - "Open a new instance of Eshell." - (interactive) - (eshell 'N)) - -(define-key evil-motion-state-map (kbd ",") nil) - -(leader/set-keys - "SPC" #'counsel-M-x - - "a" "apps" - "ad" #'docker - "as" "shells" - "ase" #'eshell-new - "asv" #'vterm - - "b" "buffers" - "bb" #'counsel-ibuffer - "bi" #'ibuffer-list-buffers-and-focus - "bd" #'kill-this-buffer - "bD" #'kill-buffer - "bh" #'dashboard-refresh-buffer - "bs" (lambda () - (interactive) - (switch-to-buffer "*scratch*")) - - "c" "code" - "cl" #'evilnc-comment-or-uncomment-lines - - "e" "emails" - "em" #'mu4e - "ec" #'mu4e-compose-new - - "f" "files" - "fi" (lambda () - (interactive) - (find-file (expand-file-name "init.el" user-emacs-directory))) - "ff" #'counsel-find-file - "fo" #'phundrak-find-org-files - "fs" #'save-buffer - - "g" "git" - "gs" #'magit-status - - "h" "help" - "hk" #'which-key-show-top-level - "hdf" #'helpful-callable - "hdk" #'helpful-key - "hdv" #'helpful-variable - - "j" "jump" - "jd" #'dired-jump - - "t" "toggles" - "tt" #'counsel-load-theme - - "T" "text" - "Ts" #'hydra-text-scale/body - - "w" "windows" - "w-" #'split-window-below-and-focus - "w/" #'split-window-right-and-focus - "wb" (lambda () - (interactive) - (progn - (kill-this-buffer) - (delete-window))) - "wd" #'delete-window - "wD" #'delete-other-windows - "wo" #'other-window - - "wc" #'evil-window-left - "wt" #'evil-window-down - "ws" #'evil-window-up - "wr" #'evil-window-right - - "q" "quit" - "qf" #'delete-frame - "qq" #'save-buffers-kill-terminal - "qQ" #'kill-emacs) - -(leader/set-keys-for-major-mode 'org-mode - "b" "babel" - "bt" #'org-babel-tangle - - "i" "insert" - "ib" #'org-insert-structure-template - "if" #'org-footnote-new - "ih" #'org-insert-heading - "il" #'org-insert-link - "ip" #'org-set-property - "it" #'org-set-tags-command - "is" #'org-insert-subheading - - "," #'org-ctrl-c-ctrl-c - "'" #'org-edit-special) - -(leader/set-keys-for-major-mode 'org-src-mode - "," #'org-edit-src-exit - "k" #'org-edit-src-abort) - -;; Flycheck won’t shut up if I don’t add this -;; (provide 'init) -;;; init.el ends here diff --git a/org/config/emacs.org b/org/config/emacs.org new file mode 100644 index 0000000..cd5f7e0 --- /dev/null +++ b/org/config/emacs.org @@ -0,0 +1,2540 @@ +# -*- org-confirm-babel-evaluate: nil -*- +#+title: Vanilla Emacs Configuration +#+setupfile: ~/org/config/headers +#+options: auto-id:t +#+html_head: +#+html_head: +#+html_head: +#+property: header-args:emacs-lisp :mkdirp yes :lexical t :exports code +#+property: header-args:emacs-lisp+ :results silent :tangle ~/.emacs.vanilla/init.el +#+property: header-args:emacs-lisp+ :mkdirp yes :noweb yes + +* Introduction +#+begin_center +*STOP* Read this first! + +You just landed on my vanilla Emacs configuration. However, this URL +was used until recently for my Spacemacs configuration. If you want my +complete, working Emacs configuration, I recommend you to head over +there. /*This document is still a work in progress!*/ +#+end_center + +After a couple of years using Spacemacs and a failed attempt at +switching to DoomEmacs, I’m finally switching back to a vanilla +configuration! Be aware though this document is still very much a work +in progress document, lots of comments on existing configuration are +missing, and lots of functionnalities are still not implemented. I’m +still in the process of porting my [[file:spacemacs.org][Spacemacs]] configuration over here. + +* Basic configuration +#+begin_src emacs-lisp + (setq visible-bell t) + + (setq-default initial-major-mode 'emacs-lisp-mode) + + + (setq display-time-format "%Y-%m-%d %H:%M") + (display-time-mode 1) ; display time in modeline + + ;; Display battery in modeline when using a laptop + (unless (equal "Battery status not available" + (battery)) + (display-battery-mode 1)) + + + + (setq frame-title-format + '("" + "%b" + (:eval + (let ((project-name (projectile-project-name))) + (unless (string= "-" project-name) + (format (if (buffer-modified-p) " ◉ %s" "  ●  %s") project-name)))))) + + ;; Make ESC quit prompts + (global-set-key (kbd "") 'keyboard-escape-quit) + + ;; Answer with y or n, not yes or not + (defalias 'yes-or-no-p 'y-or-n-p) + + (column-number-mode) + (global-display-line-numbers-mode t) + ;; Disable line numbers for some modes + (dolist (mode '(org-mode-hook + comint-mode + term-mode-hook + shell-mode-hook + eshell-mode-hook + vterm-mode-hook + special-mode-hook + helpful-mode-hook + woman-mode-hook)) + (add-hook mode (lambda () (display-line-numbers-mode 0)))) + + (setq x-stretch-cursor t ; stretch cursor to the glyph’s width + delete-by-moving-to-trash t ; delete files to trash + window-combination-resize t ; take new window space from all other windows + undo-limit 100000000 ; raise undo limit to 100Mb + auto-save-default t + truncate-string-ellipsis "…") + + (global-subword-mode 1) + ;; (electric-indent-mode -1) + + (setq-default major-mode 'org-mode) + + (defun modeline-contitional-buffer-encoding () + "Hide \"LF UTF-8\" in modeline. + + It is expected of files to be encoded with LF UTF-8, so only show + the encoding in the modeline if the encoding is worth notifying + the user." + (setq-local doom-modeline-buffer-encoding + (unless (and (memq (plist-get (coding-system-plist buffer-file-coding-system) :category) + '(coding-category-undecided coding-category-utf-8)) + (not (memq (coding-system-eol-type buffer-file-coding-system) '(1 2)))) + t))) + + (add-hook 'after-change-major-mode-hook #'modeline-contitional-buffer-encoding) + (add-hook 'prog-mode-hook #'hs-minor-mode) + (with-eval-after-load 'org + (add-hook 'org-mode-hook (lambda () + (interactive) + (electric-indent-local-mode -1)))) +#+end_src + +** Early init +The early init file is the file loaded before anything else in +Emacs. This is where I put some options in order to disable as quickly +as possible some built-in features of Emacs before they can be even +loaded, speeding Emacs up a bit. +#+begin_src emacs-lisp :mkdirp yes :tangle ~/.emacs.vanilla/early-init.el :exports code :results silent :lexical t + (setq package-enable-at-startup nil + inhibit-startup-message t + frame-resize-pixelwise t ; fine resize + package-native-compile t) ; native compile packages + (scroll-bar-mode -1) ; disable scrollbar + (tool-bar-mode -1) ; disable toolbar + (tooltip-mode -1) ; disable tooltips + (set-fringe-mode 10) ; give some breathing room + (menu-bar-mode -1) ; disable menubar +#+end_src + +** Personal information +Emacs needs to know its master! For various reasons by the way, some +packages rely of these variables to know who it is talking to or +dealing with, such as ~mu4e~ which will guess who you are if you haven’t +set it up correctly. +#+begin_src emacs-lisp + (setq user-full-name "Lucien Cartier-Tilet" + user-real-login-name "Lucien Cartier-Tilet" + user-login-name "phundrak" + user-mail-address "lucien@phundrak.com") +#+end_src + +** Stay clean, Emacs! +As nice as Emacs is, it isn’t very polite or clean by default: open a +file, and it will create backup files in the same directory. But then, +when you open your directory with your favorite file manager and see +almost all of your files duplicated with a =~= appended to the filename, +it looks really uncomfortable! This is why I prefer to tell Emacs to +keep its backup files to itself in a directory it only will acces. +#+begin_src emacs-lisp + (setq backup-directory-alist `(("." . ,(expand-file-name ".temp/backups/" user-emacs-directory)))) +#+end_src + +It also loves to litter its ~init.el~ with custom variables here and +there, but the thing is: I regenerate my ~init.el~ each time I tangle +this file! How can I keep Emacs from adding stuff that will be almost +immediately lost? Did someone say /custom file/? +#+begin_src emacs-lisp + (setq-default custom-file (expand-file-name ".custom.el" user-emacs-directory)) + (when (file-exists-p custom-file) ; Don’t forget to load it, we still need it + (load custom-file)) +#+end_src + +Finally, the scatch buffer always has some message at its beginning, I +don’t want it! +#+begin_src emacs-lisp + (setq-default initial-scratch-message nil) +#+end_src + +** Editing text in Emacs +I don’t like tabs. They rarely look good, and if I need it I can +almost always tell Emacs to use them through a ~.dir-locals.el~ file or +through the config file of my code formatter. So by default, let’s +disable them: +#+begin_src emacs-lisp + (setq-default indent-tabs-mode nil) + (add-hook 'prog-mode-hook (lambda () (setq indent-tabs-mode nil))) +#+end_src + +Just to go on a little tangeant here: I don’t exactly /hate/ tabs, but I +find them really annoying when your text editor knows only them. Sure, +for indentation they work great and they allow different people +getting different settings in their text editor depending on their +preferred tastes —some may prefer 2 spaces tabs, some may prefer 4 +spaces tabs, some deranged people prefer 8 spaces tabs, and some +monsters prefer 3! + +But the thing is, once you indented your code and then you need +alignment, tabs don’t work anymore! Or they may on *your* text editor +but not on your coworker’s! (He’s the one using 3 spaces tabs by the +way). + +So, is the answer to use spaces instead of tabs, and screw peoples’ +preferences in terms of tabs width? No, I say the answer is more +moderate than that, and it might frighten or anger some of you at +first: use both spaces and tabs. Now, before you lynch me on the main +avenue in front of everyone, let me tell you absolutely no one should +ever be mixing spaces and tabs for indentation, that would be +absolutely terrible and would bring the worst of both worlds. What’s +the best of both worlds then? +#+begin_center +/Tabs for indentation/ + +/Spaces for alignment/ +#+end_center + +I haven’t found a way to automate that in Emacs yet aside from +formatters’ config file, and tabs look bat in EmacsLisp anyways, so +I’ll stick with spaces by default and change it where needed. + +I *never* want to keep trailing spaces in my files, which is why I’m +doing this: +#+begin_src emacs-lisp + (add-hook 'before-save-hook #'whitespace-cleanup) +#+end_src + +** Fonts +I don’t like the default font I usually have on my machines, I really don’t. + +#+begin_src emacs-lisp + (defvar phundrak/default-font-size 90 + "Default font size.") +#+end_src + +#+begin_src emacs-lisp + (set-face-attribute 'default nil :font "Cascadia Code" :height phundrak/default-font-size) +#+end_src + +** Nice macros from Doom-Emacs +Doom-Emacs has some really nice macros that can come in really handy, +but since I prefer to rely on my own configuration, I’ll instead just +copy their code here. First we get the ~after!~ macro: +#+begin_src emacs-lisp + (defmacro after! (package &rest body) + "Evaluate BODY after PACKAGE have loaded. + + PACKAGE is a symbol or list of them. These are package names, not modes, + functions or variables. It can be: + + - An unquoted package symbol (the name of a package) + (after! helm BODY...) + - An unquoted list of package symbols (i.e. BODY is evaluated once both magit + and git-gutter have loaded) + (after! (magit git-gutter) BODY...) + - An unquoted, nested list of compound package lists, using any combination of + :or/:any and :and/:all + (after! (:or package-a package-b ...) BODY...) + (after! (:and package-a package-b ...) BODY...) + (after! (:and package-a (:or package-b package-c) ...) BODY...) + Without :or/:any/:and/:all, :and/:all are implied. + + This is a wrapper around `eval-after-load' that: + + 1. Suppresses warnings for disabled packages at compile-time + 2. Supports compound package statements (see below) + 3. Prevents eager expansion pulling in autoloaded macros all at once" + (declare (indent defun) (debug t)) + (if (symbolp package) + (list (if (or (not (bound-and-true-p byte-compile-current-file)) + (require package nil 'noerror)) + #'progn + #'with-no-warnings) + ;; We intentionally avoid `with-eval-after-load' to prevent eager + ;; macro expansion from pulling (or failing to pull) in autoloaded + ;; macros/packages. + `(eval-after-load ',package ',(macroexp-progn body))) + (let ((p (car package))) + (cond ((not (keywordp p)) + `(after! (:and ,@package) ,@body)) + ((memq p '(:or :any)) + (macroexp-progn + (cl-loop for next in (cdr package) + collect `(after! ,next ,@body)))) + ((memq p '(:and :all)) + (dolist (next (cdr package)) + (setq body `((after! ,next ,@body)))) + (car body)))))) +#+end_src + +* Custom Elisp +#+begin_src emacs-lisp + (defun split-window-right-and-focus () + (interactive) + (split-window-right) + (windmove-right) + (when (and (boundp 'golden-ratio-mode) + (symbol-value golden-ratio-mode)) + (golden-ratio))) + + (defun split-window-below-and-focus () + (interactive) + (split-window-below) + (windmove-down) + (when (and (boundp 'golden-ratio-mode) + (symbol-value golden-ratio-mode)) + (golden-ratio))) + + (defun ibuffer-list-buffers-and-focus () + (interactive) + (ibuffer-list-buffers) + (windmove-down) + (when (and (boundp 'golden-ratio-mode) + (symbol-value golden-ratio-mode)) + (golden-ratio))) +#+end_src + +#+begin_src emacs-lisp + (defun switch-to-messages-buffer () + "Switch to Messages buffer." + (interactive) + (switch-to-buffer "*Messages*")) + + (defun switch-to-scratch-buffer () + "Switch to Messages buffer." + (interactive) + (switch-to-buffer "*scratch*")) +#+end_src + +| / | | | +| Emphasis | Character | Character code | +|----------+-----------+----------------| +| Bold | ~*~ | 42 | +| Italic | ~/~ | 47 | +| Code | ~~~ | 126 | + +#+begin_src emacs-lisp + (defun org-mode-emphasize-bold () + "Emphasize as bold the current region. + + See also `org-emphasize'." + (interactive) + (org-emphasize 42)) +#+end_src + +#+begin_src emacs-lisp + (defun phundrak/toggle-org-src-window-split () + "This function allows the user to toggle the behavior of + `org-edit-src-code'. If the variable `org-src-window-setup' has + the value `split-window-right', then it will be changed to + `split-window-below'. Otherwise, it will be set back to + `split-window-right'" + (interactive) + (if (equal org-src-window-setup 'split-window-right) + (setq org-src-window-setup 'split-window-below) + (setq org-src-window-setup 'split-window-right)) + (message "Org-src buffers will now split %s" + (if (equal org-src-window-setup 'split-window-right) + "vertically" + "horizontally"))) +#+end_src + +* Package Management +** Repositories +By default, only GNU’s repositories are available to the package +managers of Emacs. I also want to use Melpa and org-mode’s repository, +so let’s add them! Note that the /Elpa/ repository has been renamed to +the /gnu/ repository due to the addition of another Elpa repository, +/nongnu/, which will hosts packages that do not conform to the FSF’s +copyright assignment. Both the /gnu/ and the /nonfree/ repositories are +Elpa repositories now, and they were renamed in order to avoid any +confusion between the two of them. +#+begin_src emacs-lisp + (setq package-archives '(("melpa" . "https://melpa.org/packages/") + ("org" . "https://orgmode.org/elpa/") + ("gnu" . "https://elpa.gnu.org/packages/") + ("nongnu" . "https://elpa.nongnu.org/nongnu/"))) +#+end_src + +** Straight +For my package management, I prefer to use ~straight~ ([[https://github.com/raxod502/straight.el][Github]]). This is +due to its capacity of integrating nicely with ~use-package~, which is +also supported by ~general~ which I use for my keybindings (see below), +but also because with it I can specify where to retrieve packages that +are not on MELPA or ELPA but on Github and other online Git +repositories too. +#+begin_src emacs-lisp + + (defvar bootstrap-version) + (defvar comp-deferred-compilation-deny-list ()) ; workaround, otherwise straight shits itself + (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)) + + (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) + (setq use-package-always-ensure t) +#+end_src + +* Packages Configuration +** Keybinding Management +*** Which-key +#+begin_src emacs-lisp + (use-package which-key + :straight (:build t) + :defer t + :init (which-key-mode) + :diminish which-key-mode + :config + (setq which-key-idle-delay 0.3)) +#+end_src + +*** General +#+begin_src emacs-lisp + (use-package general + :straight (:build t) + :init + (general-auto-unbind-keys)) +#+end_src + +*** Evil +#+begin_src emacs-lisp + (use-package evil + :straight (:build t) + :init + (setq evil-want-integration t) + (setq evil-want-keybinding nil) + (setq evil-want-C-u-scroll t) + (setq evil-want-C-i-jump nil) + :config + (evil-mode 1) + (setq evil-want-fine-undo t) ; more granular undo with evil + (setq evil-undo-system 'undo-tree) + (evil-set-initial-state 'messages-buffer-mode 'normal) + (evil-set-initial-state 'dashboard-mode 'normal) + + ;; Use visual line motions even outside of visual-line-mode buffers + (evil-global-set-key 'motion "t" 'evil-next-visual-line) + (evil-global-set-key 'motion "s" 'evil-previous-visual-line) + + (define-key evil-normal-state-map "c" nil) + (define-key evil-normal-state-map "C" nil) + (define-key evil-normal-state-map "t" nil) + (define-key evil-normal-state-map "T" nil) + (define-key evil-normal-state-map "s" nil) + (define-key evil-normal-state-map "S" nil) + (define-key evil-normal-state-map "r" nil) + (define-key evil-normal-state-map "R" nil) + (define-key evil-normal-state-map "h" nil) + (define-key evil-normal-state-map "H" nil) + (define-key evil-normal-state-map "j" nil) + (define-key evil-normal-state-map "J" nil) + (define-key evil-normal-state-map "k" nil) + (define-key evil-normal-state-map "K" nil) + (define-key evil-normal-state-map "l" nil) + (define-key evil-normal-state-map "L" nil) + + (define-key evil-motion-state-map "h" 'evil-replace) + (define-key evil-motion-state-map "H" 'evil-replace-state) + (define-key evil-motion-state-map "j" 'evil-find-char-to) + (define-key evil-motion-state-map "J" 'evil-find-char-to-backward) + (define-key evil-motion-state-map "k" 'evil-substitute) + (define-key evil-motion-state-map "K" 'evil-smart-doc-lookup) + (define-key evil-motion-state-map "l" 'evil-change) + (define-key evil-motion-state-map "L" 'evil-change-line) + + (define-key evil-motion-state-map "c" 'evil-backward-char) + (define-key evil-motion-state-map "C" 'evil-window-top) + (define-key evil-motion-state-map "t" 'evil-next-line) + (define-key evil-motion-state-map "T" 'evil-join) + (define-key evil-motion-state-map "s" 'evil-previous-line) + (define-key evil-motion-state-map "S" 'evil-lookup) + (define-key evil-motion-state-map "r" 'evil-forward-char) + (define-key evil-motion-state-map "R" 'evil-window-bottom) + ) + + (use-package evil-collection + :after evil + :straight (:build t) + :config + (evil-collection-init)) +#+end_src + +#+begin_src emacs-lisp + (use-package undo-tree + :straight (:build t) + :init + (global-undo-tree-mode)) +#+end_src + +*** Hydra +#+begin_src emacs-lisp + (use-package hydra + :straight (:build t) + :defer t) +#+end_src + +**** Hydras +The following hydra allows me to quickly zoom in and out in the +current buffer. +#+begin_src emacs-lisp + (defhydra hydra-zoom () + "Zoom current buffer." + ("t" text-scale-increase "zoom in") + ("s" text-scale-decrease "zoom out") + ("0" text-scale-adjust "reset") + ("q" nil "finished" :exit t)) +#+end_src + +This one allows me to quickly navigate between code blocks and +interact with them. This code block was inspired by one you can find +in Spacemacs. +#+begin_src emacs-lisp + (defhydra org-babel-transient () + " + ^Navigate^ ^Interact + ^^^^^^^^^^^------------------------------------------ + [_t_/_s_] navigate src blocs [_x_] execute src block + [_g_]^^ goto named block [_'_] edit src block + [_z_]^^ recenter screen [_q_] quit + " + ("q" nil :exit t) + ("t" org-babel-next-src-block) + ("s" org-babel-previous-src-block) + ("g" org-babel-goto-named-src-block) + ("z" recenter-top-bottom) + ("x" org-babel-execute-maybe) + ("'" org-edit-special :exit t)) +#+end_src + +Similarly, this one is also inspired from Spacemacs and allows the +user to interact with the width of the buffer in ~writeroom~. +#+begin_src emacs-lisp + (defhydra writeroom-buffer-width () + "Change the width of a `writeroom-mode' buffer." + ("q" nil :exit t) + ("t" writeroom-increase-width "enlarge") + ("s" writeroom-decrease-width "shrink") + ("r" writeroom-adjust-width "adjust")) +#+end_src + +Another similar one is for ~mu4e-view-mode~ that allows me to shrink or +grow the ~mu4e-headers~ buffer when viewing an email. +#+begin_src emacs-lisp + (defhydra mu4e-headers-split-adjust-width () + "Change the width of a `mu4e-headers' buffer." + ("q" nil :exit t) + ("t" mu4e-headers-split-view-shrink "shrink") + ("s" mu4e-headers-split-view-grow "enlarge")) +#+end_src + +** Helpful +As the name tells, ~helpful~ is a really helpful package which greatly +enhances a couple of built-in functions from Emacs, namely: +| Vanilla Emacs Function | Helpful Function | Comment | +|------------------------+------------------+-----------------------------------------------| +| ~describe-function~ | ~helpful-callable~ | Only interactive functions | +| ~describe-function~ | ~helpful-function~ | Only actual functions (including interactive) | +| ~describe-function~ | ~helpful-macro~ | | +| ~describe-command~ | ~helpful-command~ | | +| ~describe-key~ | ~helpful-key~ | | +| ~describe-variable~ | ~helpful-variable~ | | + +#+begin_src emacs-lisp + (use-package helpful + :straight (:build t) + :after (counsel ivy) + :custom + (counsel-describe-function-function #'helpfull-callable) + (counsel-describe-variable-function #'helpfull-variable) + :bind + ([remap describe-function] . counsel-describe-function) + ([remap describe-command] . helpful-command) + ([remap describe-variable] . counsel-describe-variable) + ([remap describe-key] . helpful-key)) +#+end_src + +** Visual Configuration +*** Dashboard +#+begin_src emacs-lisp + (use-package dashboard + :straight (:build t) + :ensure t + :after all-the-icons + :config + (setq dashboard-banner-logo-title "Phundrak’s Vanilla Emacs" + dashboard-startup-banner 'logo + dashboard-center-content t + dashboard-show-shortcuts t + dashboard-set-navigator t + dashboard-set-heading-icons t + dashboard-set-file-icons t + initial-buffer-choice (lambda () (get-buffer "*dashboard*")) + dashboard-projects-switch-function 'counsel-projectile-switch-project-by-name) + (setq dashboard-navigator-buttons + `(((,(all-the-icons-faicon "language" :height 1.1 :v-adjust 0.0) + "Linguistics website" + "" + (lambda (&rest _) (browse-url "https://langue.phundrak.com"))) + + (,(all-the-icons-faicon "firefox" :height 1.1 :v-adjust 0.0) + "Config Website" + "" + (lambda (&rest _) (browse-url "https://config.phundrak.com")))) + + ((,(all-the-icons-octicon "git-branch" :height 1.1 :v-adjust 0.0) + "Dotfiles sources" + "" + (lambda (&rest _) (browse-url "https://labs.phundrak.com/phundrak/dotfiles"))) + ("!" "Issues" "Show issues" (lambda (&rest _) + (browse-url "https://labs.phundrak.com/phundrak/dotfiles/issues")) + warning)) + ((,(all-the-icons-faicon "level-up" :height 1.1 :v-adjust 0.0) + "Update packages" + "" + (lambda (&rest _) (progn + (require 'straight) + (straight-pull-all))))))) + + (setq dashboard-items '((recents . 15) + (projects . 10))) + (dashboard-setup-startup-hook) + :init + (add-hook 'after-init-hook 'dashboard-refresh-buffer)) +#+end_src + +*** Modeline +#+begin_src emacs-lisp + (use-package doom-modeline + :straight (:build t) + :defer t + :init (doom-modeline-mode 1) + :custom ((doom-modeline-height 15))) +#+end_src + +*** Theme +#+begin_src emacs-lisp + (use-package doom-themes + :straight (:build t) + :defer t + :init (load-theme 'doom-nord t)) +#+end_src + +*** Icons? Did someone say icons? +/*YES! ALL OF THEM!*/ + +Ahem… + +The package ~all-the-icons~ allows us to use a wide variety of icons in +Emacs for various purposes, wherever we want, and /THAT/ is *GREAT*! I’ll +(ab)use this feature in my config, be warned! *NOTE*: The first time a +configuration with ~all-the-icons~ is loaded on a machine, the needed +fonts might not be available, so you’ll need to install them with the +command ~M-x all-the-icons-install-fonts~. +#+begin_src emacs-lisp + (use-package all-the-icons + :defer t) +#+end_src + +~prettify-symbols-mode~ is also a nifty feature of Emacs, and it is +built-in! With that, I can replace strings of my choice by another +character of my choice! +#+begin_src emacs-lisp + (dolist (symbol '(("lambda" . 955) + ("mapc" . 8614))) + (add-to-list 'prettify-symbols-alist symbol)) +#+end_src + +*** Rainbow Delimiters +#+begin_src emacs-lisp + (use-package rainbow-delimiters + :straight (:build t) + :defer t + :hook (prog-mode . rainbow-delimiters-mode)) +#+end_src + +** Autocompletion +*** Code Autocompletion +#+begin_src emacs-lisp + (use-package company + :straight (:build t) + :defer t + :hook (company-mode . evil-normalize-keymaps) + :init (global-company-mode) + :config + (setq company-minimum-prefix-length 2 + company-toolsip-limit 14 + company-tooltip-align-annotations t + company-require-match 'never + company-global-modes '(not erc-mode message-mode help-mode gud-mode) + company-frontends + '(company-pseudo-tooltip-frontend ; always show candidates in overlay tooltip + company-echo-metadata-frontend) ; show selected candidate docs in echo area + + ;; Buffer-local backends will be computed when loading a major + ;; mode, so only specify a global default here. + company-backends '(company-capf) + + ;; These auto-complete the current selection when + ;; `company-auto-complete-chars' is typed. This is too + ;; magical. We already have the much more explicit RET and + ;; TAB. + company-auto-complete nil + company-auto-complete-chars nil + + ;; Only search the current buffer for `company-dabbrev' (a + ;; backend that suggests text you open buffers). This prevents + ;; Company from causing lag once you have a lot of buffers + ;; open. + company-dabbrev-other-buffers nil + + ;; Make `company-dabbrev' fully case-sensitive, to improve UX + ;; with domai-specific words with particular casing. + company-dabbrev-ignore-case nil + company-dabbrev-downcase nil)) + + (use-package company-dict + :after company + :straight (:build t) + :config + (setq company-dict-dir (expand-file-name "dicts" user-emacs-directory))) + + (use-package company-box + :straight (:build t) + :after (company all-the-icons) + :config + (setq company-box-show-single-candidate t + company-box-backends-colors nil + company-box-max-candidates 50 + company-box-icons-alist 'company-box-icons-all-the-icons + company-box-icons-all-the-icons + (let ((all-the-icons-scale-factor 0.8)) + `((Unknown . ,(all-the-icons-material "find_in_page" :face 'all-the-icons-purple)) + (Text . ,(all-the-icons-material "text_fields" :face 'all-the-icons-green)) + (Method . ,(all-the-icons-material "functions" :face 'all-the-icons-red)) + (Function . ,(all-the-icons-material "functions" :face 'all-the-icons-red)) + (Constructor . ,(all-the-icons-material "functions" :face 'all-the-icons-red)) + (Field . ,(all-the-icons-material "functions" :face 'all-the-icons-red)) + (Variable . ,(all-the-icons-material "adjust" :face 'all-the-icons-blue)) + (Class . ,(all-the-icons-material "class" :face 'all-the-icons-red)) + (Interface . ,(all-the-icons-material "settings_input_component" :face 'all-the-icons-red)) + (Module . ,(all-the-icons-material "view_module" :face 'all-the-icons-red)) + (Property . ,(all-the-icons-material "settings" :face 'all-the-icons-red)) + (Unit . ,(all-the-icons-material "straighten" :face 'all-the-icons-red)) + (Value . ,(all-the-icons-material "filter_1" :face 'all-the-icons-red)) + (Enum . ,(all-the-icons-material "plus_one" :face 'all-the-icons-red)) + (Keyword . ,(all-the-icons-material "filter_center_focus" :face 'all-the-icons-red)) + (Snippet . ,(all-the-icons-material "short_text" :face 'all-the-icons-red)) + (Color . ,(all-the-icons-material "color_lens" :face 'all-the-icons-red)) + (File . ,(all-the-icons-material "insert_drive_file" :face 'all-the-icons-red)) + (Reference . ,(all-the-icons-material "collections_bookmark" :face 'all-the-icons-red)) + (Folder . ,(all-the-icons-material "folder" :face 'all-the-icons-red)) + (EnumMember . ,(all-the-icons-material "people" :face 'all-the-icons-red)) + (Constant . ,(all-the-icons-material "pause_circle_filled" :face 'all-the-icons-red)) + (Struct . ,(all-the-icons-material "streetview" :face 'all-the-icons-red)) + (Event . ,(all-the-icons-material "event" :face 'all-the-icons-red)) + (Operator . ,(all-the-icons-material "control_point" :face 'all-the-icons-red)) + (TypeParameter . ,(all-the-icons-material "class" :face 'all-the-icons-red)) + (Template . ,(all-the-icons-material "short_text" :face 'all-the-icons-green)) + (ElispFunction . ,(all-the-icons-material "functions" :face 'all-the-icons-red)) + (ElispVariable . ,(all-the-icons-material "check_circle" :face 'all-the-icons-blue)) + (ElispFeature . ,(all-the-icons-material "stars" :face 'all-the-icons-orange)) + (ElispFace . ,(all-the-icons-material "format_paint" :face 'all-the-icons-pink)))))) +#+end_src + +*** Ivy +My main menu package is ~ivy~ which I use as much as possible –I’ve +noticed ~helm~ can be slow, very slow in comparison to ~ivy~ so I’ll use +the latter as much as possible. Actually, only ~ivy~ is installed for +now. I could have used ~ido~ too, but I find it to be a bit too +restricted in terms of features compared to ~ivy~. +#+begin_src emacs-lisp + (use-package ivy + :straight (:build t) + :defer t + :diminish + :bind (("C-s" . swiper) + :map ivy-minibuffer-map + ("TAB" . ivy-alt-done) + ("C-l" . ivy-alt-done) + ("C-t" . ivy-next-line) + ("C-s" . ivy-previous-line) + :map ivy-switch-buffer-map + ("C-t" . ivy-next-line) + ("C-s" . ivy-previous-line) + ("C-l" . ivy-done) + ("C-d" . ivy-switch-buffer-kill) + :map ivy-reverse-i-search-map + ("C-t" . ivy-next-line) + ("C-s" . ivy-previous-line) + ("C-d" . ivy-reverse-i-search-kill)) + :config + (ivy-mode 1) + (setq ivy-wrap t + ivy-height 17 + ivy-fixed-height-minibuffer t + ivy-read-action-functions #'ivy-hydra-read-action + ivy-read-action-format-function #'ivy-read-action-format-columns + projectile-completion-system 'ivy + ivy-on-del-error-function #'ignore + ivy-use-selectable-prompt t)) +#+end_src + +There is also [[https://github.com/raxod502/prescient.el][~prescient.el~]] that offers some nice features when +coupled with ~ivy~, guess what was born out of it? ~ivy-prescient~, of +course! +#+begin_src emacs-lisp + (use-package ivy-prescient + :after ivy + :straight (:build t)) +#+end_src + +I warned you I’d use too much ~all-the-icons~, I did! +#+begin_src emacs-lisp + (use-package all-the-icons-ivy + :straight (:build t) + :after (ivy all-the-icons) + :hook (after-init . all-the-icons-ivy-setup)) +#+end_src + +A buffer popping at the bottom of the screen is nice and all, but have +you considered a floating buffer in the center of your frame? +#+begin_src emacs-lisp + (use-package ivy-posframe + :defer t + :hook (ivy-mode . ivy-posframe-mode) + :straight (ivy-posframe :build t + :type git + :host github + :repo "tumashu/ivy-posframe") + :config + (setq ivy-fixed-height-minibuffer nil + ivy-posframe-border-width 10 + ivy-posframe-parameters + `((min-width . 90) + (min-height . ,ivy-height)))) +#+end_src + +Finally, let’s make ~ivy~ richer: +#+begin_src emacs-lisp + (use-package ivy-rich + :straight (:build t) + :after ivy + :init + (ivy-rich-mode 1)) +#+end_src + +*** Counsel +#+begin_src emacs-lisp + (use-package counsel + :straight (:build t) + :defer t + :bind (("M-x" . counsel-M-x) + ("C-x b" . counsel-ibuffer) + ("C-x C-f" . counsel-find-file) + :map minibuffer-local-map + ("C-r" . 'counsel-minibuffer-history))) +#+end_src + +*** Yasnippet +#+begin_src emacs-lisp + (use-package yasnippet + :defer t + :straight (:build t) + :init + (yas-global-mode)) +#+end_src + +#+begin_src emacs-lisp + (use-package yasnippet-snippets + :after yasnippet + :straight (:build t)) +#+end_src + +#+begin_src emacs-lisp + (use-package yatemplate + :after yasnippet + :straight (:build t)) +#+end_src + +#+begin_src emacs-lisp + (use-package ivy-yasnippet + :after (ivy yasnippet) + :straight (:build t)) +#+end_src + +** Editing +*** Evil Nerd Commenter +#+begin_src emacs-lisp + (use-package evil-nerd-commenter + :after evil + :straight (:build t)) +#+end_src + +*** string-edit +~string-edit~ is a cool package that allows the user to write naturally +a string and get it automatically escaped for you. No more manually +escaping your strings! +#+begin_src emacs-lisp + (use-package string-edit + :defer t + :straight (:build t)) +#+end_src + +*** Writeroom +On the other hand, ~writeroom~ allows the user to enter a +distraction-free mode of Emacs, and I like that! +#+begin_src emacs-lisp + (use-package writeroom-mode + :defer t + :straight (:build t)) +#+end_src + +** Emacs built-ins +*** Dired +#+begin_src emacs-lisp + (setq dired-dwim-target t) +#+end_src + +*** Eshell +Eshell is a built-in shell available from Emacs which I use almost as +often as fish. Some adjustments are necessary to make it fit my taste +though. +#+begin_src emacs-lisp + (general-define-key + :keymaps 'eshell-mode-map + :states 'insert + "C-a" #'eshell-bol + "C-e" #'end-of-line) +#+end_src + +**** Aliases +First, let’s declare our list of “dumb” aliases we’ll use in +Eshell. You can find them here. +#+begin_src emacs-lisp + (setq eshell-aliases-file (expand-file-name "eshell-aliases" user-emacs-directory)) +#+end_src + +A couple of other aliases will be defined through custom Elisp +functions, but first I’ll need a function for concatenating a shell +command into a single string: +#+begin_src emacs-lisp + (defun phundrak/concatenate-shell-command (&rest command) + "Concatenate an eshell `COMMAND' into a single string. + + All elements of `COMMAND' will be joined in a single + space-separated string." + (string-join command " ")) +#+end_src + +I’ll also declare some aliases here, such as ~open~ and ~openo~ that +respectively allow me to open a file in Emacs, and same but in another +window. +#+begin_src emacs-lisp +(defalias 'open 'find-file) +(defalias 'openo 'find-file-other-window) +#+end_src + +As you see, these were not declared in my dedicated aliases file but +rather were declared programmatically. This is because I like to keep +my aliases file for stuff that could work too with other shells were +the syntax a bit different, and aliases related to Elisp are kept +programmatically. I’ll also declare ~list-buffers~ an alias of ~ibuffer~ +because naming it that way kind of makes more sense to me. +#+begin_src emacs-lisp +(defalias 'list-buffers 'ibuffer) +#+end_src + +I still have some stupid muscle memory telling me to open ~emacs~, ~vim~ +or ~nano~ in Eshell, which is stupid: I’m already inside Emacs and I +have all its power available instantly. So, let’s open each file +passed to these commands. +#+begin_src emacs-lisp + (defun eshell/emacs (&rest file) + "Open each `FILE' and kill eshell. + + Old habits die hard." + (when file + (dolist (f (reverse file)) + (find-file f t)))) +#+end_src + +Finally, I’ll declare ~mkcd~ which allows the simultaneous creation of a +directory and moving into this newly created directory. And of course, +it will also work if the directory also exists or if parent +directories don’t, similarly to the ~-p~ option passed to ~mkdir~. +#+begin_src emacs-lisp + (defun eshell/mkcd (dir) + "Create the directory `DIR' and move there. + + If the directory `DIR' doesn’t exist, create it and its parents + if needed, then move there." + (mkdir dir t) + (cd dir)) +#+end_src + +**** Custom Functions +When I’m in Eshell, sometimes I wish to open multiple files at once in +Emacs. For this, when I have several arguments for ~find-file~, I want +to be able to open them all at once. Let’s modify ~find-file~ like so: +#+BEGIN_SRC emacs-lisp + (defadvice find-file (around find-files activate) + "Also find all files within a list of files. This even works recursively." + (if (listp filename) + (cl-loop for f in filename do (find-file f wildcards)) + ad-do-it)) +#+END_SRC + +I also want to be able to have multiple instances of Eshell opened at +once. For that, I declared the function ~eshell-new~ that does exactly +that. +#+begin_src emacs-lisp + (defun eshell-new () + "Open a new instance of eshell." + (interactive) + (eshell 'N)) +#+end_src + +**** Environment Variables +Some environment variables need to be correctly set so Eshell can correctly +work. The first environment variable to be set is the ~PATH~, as I have a couple +of directories where executables are located. Let’s add them to our +path if they aren’t already. +#+name: table-eshell-env-path +#+caption: Paths to add to ~PATH~ +| Path | Relative to ~HOME~? | +|---------------------+-------------------| +| .pub-cache/bin | yes | +| .local/bin | yes | +| .cargo/bin | yes | +| .gen/ruby/2.6.0/bin | yes | +| go/bin | yes | + +#+name: src-eshell-env-path +#+begin_src emacs-lisp :exports none :tangle no :var paths=table-eshell-env-path :noweb yes + (progn + (setq-local PATH (getenv "PATH")) + (dolist (path paths) + (let ((path (if (equal "yes" (cadr path)) + (concat (getenv "HOME") + "/" + (car path)) + (car path)))) + (unless (string-match-p (regexp-quote path) PATH) + (setq-local PATH (concat path ":" PATH))))) + PATH) +#+end_src + +#+begin_src emacs-lisp + (setenv "PATH" "<>") +#+end_src + +I would also like to set two environment variables related to Dart development: +the ~DART_SDK~ and ~ANDROID_HOME~ variables. +#+BEGIN_SRC emacs-lisp + (setenv "DART_SDK" "/opt/dart-sdk/bin") + (setenv "ANDROID_HOME" (concat (getenv "HOME") "/Android/Sdk/")) +#+END_SRC + +The ~EDITOR~ variable also needs to be set for git commands, especially the +~yadm~ commands. +#+BEGIN_SRC emacs-lisp + (setenv "EDITOR" "emacsclient -c") +#+END_SRC + +Finally, for some specific situations I need ~SHELL~ to be set to +something more standard than fish: +#+begin_src emacs-lisp + (setenv "SHELL" "/bin/sh") +#+end_src + +**** Visual configuration +I like to have at quick glance some information about my machine when +I fire up a terminal. I haven’t found anything that does that the way +I like it, so [[https://github.com/Phundrak/eshell-info-banner.el][I’ve written a package]]! +#+begin_src emacs-lisp + (use-package eshell-info-banner + :defer t + :straight (eshell-info-banner :build t + :type git + :host github + :repo "phundrak/eshell-info-banner.el") + :hook (eshell-banner-load . eshell-info-banner-update-banner) + :config + (setq eshell-info-banner-width 80 + eshell-info-banner-partition-prefixes '("/dev" "zroot" "tank"))) +#+end_src + +*** Org-mode +#+begin_src emacs-lisp :tangle ~/.emacs.vanilla/init.el :noweb tangle + (use-package org + :straight (:build (:not autoloads) :location site) + :after general + :hook (org-mode . visual-line-mode) + :hook (org-mode . org-num-mode) + :init + ;; (add-hook 'org-mode-hook #'visual-line-mode) + (auto-fill-mode -1) + (require 'ox-extra) + (ox-extras-activate '(ignore-headlines)) + + :general + (:states 'normal + :prefix "," + :keymaps 'org-mode-map + "RET" #'org-ctrl-c-ret + "*" #'org-ctrl-c-star + "," #'org-ctrl-c-ctrl-c + "'" #'org-edit-special + "-" #'org-ctrl-c-minus + + "a" #'org-agenda + "c" #'org-capture + "l" #'org-store-link + "p" #'org-priority + + "b" '(:ignore t :wk "babel") + "b." #'org-babel-transient/body + "bb" #'org-babel-execute-buffer + "bc" #'org-babel-check-src-block + "bC" #'org-babel-tangle-clean + "be" #'org-babel-execute-maybe + "bf" #'org-babel-tangle-file + "bn" #'org-babel-next-src-block + "bo" #'org-babel-open-src-block-result + "bp" #'org-babel-previous-src-block + "br" #'org-babel-goto-named-result + "bR" #'org-babel-remove-result-one-or-many + "bt" #'org-babel-tangle + "bi" #'org-babel-view-src-block-info + + "d" '(:ignore t :wk "dates") + "dd" #'org-deadline + "ds" #'org-schedule + "dt" #'org-time-stamp + "dT" #'org-time-stamp-inactive + + "e" '(:ignore t :wk "export") + "ee" #'org-export-dispatch + + "i" '(:ignore t :wk "insert") + "ib" #'org-insert-structure-template + "id" #'org-insert-drawer + "ie" #'org-set-effort + "if" #'org-footnote-new + "ih" #'org-insert-heading + "ii" #'org-insert-item + "il" #'org-insert-link + "in" #'org-add-note + "ip" #'org-set-property + "is" #'org-insert-subheading + "it" #'org-set-tags-command + + "j" '(:ignore t :wk "jump") + "ja" #'counsel-org-goto-all + "jh" #'counsel-org-goto + + "t" '(:ignore t :wk "tables") + "ta" #'org-table-align + "te" #'org-table-eval-formula + "tf" #'org-table-field-info + "th" #'org-table-convert + "tl" #'org-table-recalculate + "ts" #'org-table-sort-lines + "tw" #'org-table-wrap-region + "tN" #'org-table-create-with-table.el + + "tc" #'org-table-previous-field + "tr" #'org-table-next-field + "tC" #'org-table-move-column-left + "tT" #'org-table-move-row-down + "tS" #'org-table-move-row-up + "tR" #'org-table-move-column-right + + "td" '(:ignore t :wk "delete") + "tdc" #'org-table-delete-column + "tdr" #'org-table-kill-row + + "ti" '(:ignore t :wk "insert") + "tic" #'org-table-insert-column + "tih" #'org-table-insert-hline + "tir" #'org-table-insert-row + "tiH" #'org-table-hline-and-move + + "tt" '(:ignore t :wk "toggle") + "ttf" #'org-table-toggle-formula-debugger + "tto" #'org-table-toggle-coordinate-overlays + + "T" '(:ignore t :wk "toggle") + "Tc" #'org-toggle-checkbox + "Ti" #'org-toggle-inline-images + "Tl" #'org-latex-preview + "Tn" #'org-num-mode + "Ts" 'phundrak/toggle-org-src-window-split + "Tt" #'org-show-todo-tree + "TT" #'org-todo) + + (:states 'normal + :keymaps 'org-src-mode-map + :prefix "," + "'" #'org-edit-src-exit + "k" #'org-edit-src-abort) + + :config + (progn + (setq org-hide-leading-stars nil + org-superstar-leading-bullet ?\s + org-hide-macro-markers t + org-ellipsis " ⤵" + org-image-actual-width 550 + org-redisplay-inline-images t + org-display-inline-images t + org-startup-with-inline-images "inlineimages" + org-pretty-entities t + org-fontify-whole-heading-line t + org-fontify-done-headline t + org-fontify-quote-and-verse-blocks t + org-startup-indented t + org-startup-align-all-tables t + org-use-property-inheritance t + org-list-allow-alphabetical t + org-M-RET-may-split-line nil + org-src-window-setup 'split-window-below) + + <> + <> + <> + <> + <> + <> + <> + <> + <> + <> + <> + )) +#+end_src + +#+begin_src emacs-lisp :tangle ~/.emacs.vanilla/init.el + (use-package evil-org + :straight (:build t) + :after org + :hook (org-mode . evil-org-mode) + :config + ;; (dolist (key '("h" "j" "k" "l")) + ;; (define-key org-mode-map (kbd (format "M-%s" key)) 'undefined)) + (setq-default evil-org-movement-bindings + '((up . "s") + (down . "t") + (left . "c") + (right . "r"))) + (evil-org-set-key-theme '(textobjects navigation calendar additional shift operators)) + (require 'evil-org-agenda) + (evil-org-agenda-set-keys)) +#+end_src + +**** Agenda +:PROPERTIES: +:header-args:emacs-lisp: :tangle no :exports code :results silent +:END: +#+name: org-agenda-files +#+begin_src emacs-lisp + (setq-default org-agenda-files (list "~/org/agenda" "~/org/notes.org")) +#+end_src + +**** File export +:PROPERTIES: +:header-args:emacs-lisp: :tangle no :exports code :results silent +:END: +I want to disable by default behavior of ~^~ and ~_~ for only one +character, making it compulsory to use instead ~^{}~ and ~_{}~ +respectively. This is due to my frequent usage of the underscore in my +org files as a regular character and not a markup one, especially when +describing phonetics evolution. So, let’s disable it: +#+NAME: org-use-sub-superscripts +#+BEGIN_SRC emacs-lisp + (setq org-use-sub-superscripts (quote {})) +#+END_SRC + +***** LaTeX +When it comes to exports, I want the LaTeX and PDF exports to be done +with XeLaTeX only. This implies the modification of the following +variable: +#+NAME: org-latex-compiler +#+BEGIN_SRC emacs-lisp + (setq org-latex-compiler "xelatex") +#+END_SRC + +I also want to get by default ~minted~ for LaTeX listings so I can have +syntax highlights: +#+NAME: org-latex-listings +#+BEGIN_SRC emacs-lisp + (setq org-latex-listings 'minted) +#+END_SRC + +The default packages break my LaTeX exports: for some reasons, images +are not loaded and exported in PDFs, so I needed to redifine the +default packages excluding the one that broke my exports. I also added +a default package, ~minted~ for syntax highlighting. +#+NAME: org-latex-default-packages +#+BEGIN_SRC emacs-lisp + (setq org-latex-default-packages-alist '(("" "graphicx" t) + ("T1" "fontspec" t ("pdflatex")) + ("" "longtable" nil) + ("" "wrapfig" nil) + ("" "rotating" nil) + ("normalem" "ulem" t) + ("" "amsmath" t) + ("" "textcomp" t) + ("" "amssymb" t) + ("" "capt-of" nil) + ("" "minted" nil) + ("" "hyperref" nil))) +#+END_SRC + +By the way, reference links in LaTeX should be written in this format: +#+NAME: org-export-latex-hyperref-format +#+BEGIN_SRC emacs-lisp + (setq org-export-latex-hyperref-format "\\ref{%s}") +#+END_SRC + +When it comes to the export itself, the latex file needs to be +processed several times through XeLaTeX in order to get some +references right. Don’t forget to also run bibtex! +#+NAME: org-latex-pdf-process +#+BEGIN_SRC emacs-lisp + (setq org-latex-pdf-process + '("xelatex -8bit -shell-escape -interaction nonstopmode -output-directory %o %f" + "bibtex %b" + "xelatex -8bit -shell-escape -interaction nonstopmode -output-directory %o %f" + "xelatex -8bit -shell-escape -interaction nonstopmode -output-directory %o %f")) +#+END_SRC + +Finally, org-mode is supposed to automatically clean logfiles after it +exports an org file to LaTeX. However, it misses a few, so I need to +add their extension like so: +#+begin_src emacs-lisp + (dolist (ext '("bbl" "lot")) + (add-to-list 'org-latex-logfiles-extensions ext t)) +#+end_src + +***** HTML +For Reveal.JS exports, I need to set where to find the framework by +default: +#+NAME: org-re-reveal-root +#+BEGIN_SRC emacs-lisp + (setq org-re-reveal-root "https://cdn.jsdelivr.net/npm/reveal.js") +#+END_SRC + +On HTML exports, Org-mode tries to include a validation link for the +exported HTML. Let’s disable that since I never use it. +#+NAME: org-html-validation +#+BEGIN_SRC emacs-lisp + (setq org-html-validation-link nil) +#+END_SRC + +**** LaTeX formats +:PROPERTIES: +:header-args:emacs-lisp: :tangle no :exports code :results silent +:END: +I currently have two custom formats for my Org-mode exports: one for general use +(initialy for my conlanging files, hence its ~conlang~ name), and one for beamer +exports. + +Below is the declaration of the ~conlang~ LaTeX class: +#+NAME: org-latex-class-conlang +#+BEGIN_SRC emacs-lisp + '("conlang" + "\\documentclass{book}" + ("\\chapter{%s}" . "\\chapter*{%s}") + ("\\section{%s}" . "\\section*{%s}") + ("\\subsection{%s}" . "\\subsection*{%s}") + ("\\subsubsection{%s}" . "\\subsubsection*{%s}")) +#+END_SRC + +And here is the declaration of the ~beamer~ class: +#+NAME: org-latex-class-beamer +#+BEGIN_SRC emacs-lisp + `("beamer" + ,(concat "\\documentclass[presentation]{beamer}\n" + "[DEFAULT-PACKAGES]" + "[PACKAGES]" + "[EXTRA]\n") + ("\\section{%s}" . "\\section*{%s}") + ("\\subsection{%s}" . "\\subsection*{%s}") + ("\\subsubsection{%s}" . "\\subsubsection*{%s}")) +#+END_SRC + +Both these classes have to be added to ~org-latex-classes~ like so: +#+NAME: org-latex-classes +#+BEGIN_SRC emacs-lisp :noweb yes + (eval-after-load "ox-latex" + '(progn + (add-to-list 'org-latex-classes + <> + ) + (add-to-list 'org-latex-classes + <> + ))) +#+END_SRC + +**** Projects +:PROPERTIES: +:header-args:emacs-lisp: :tangle no :exports code :results silent +:END: +Another great features of Org-mode is the Org projects that allow the user to +easily publish a bunch of org files to a remote location. Here is the current +declaration of my projects, which will be detailed later: +#+NAME: org-publish-projects +#+BEGIN_SRC emacs-lisp :noweb yes + <> + <> + (setq org-publish-project-alist + `( + <> + <> + <> + <> + <> + <> + <>)) +#+END_SRC + +***** Configuration website +This is my configuration for exporting my dotfiles to my website in a web format +only. No PDFs or anything, just HTML. Please note that I do not use that often +anymore, I much prefer the automatic script that I have which deploys through my +Drone instance my website on git pushes. + +And before we get into the actual configuration, I would like to introduce a +couple of variables. This is a bit more verbose than if I declared everything +manually, but now I can change all three values at the same time without a +hasle. +#+NAME: org-proj-config-setup +#+BEGIN_SRC emacs-lisp + (defvar phundrak//projects-config-target + "/rsync:Tilo:~/www/phundrak.com/config" + "Points to where exported files for config.phundrak.com should be put") + (defvar phundrak//projects-config-source + "~/org/config/" + "Points to where the sources for config.phundrak.com are") + (defvar phundrak//projects-config-language + "en" + "Language of config.phundrak.com") + (defvar phundrak//projects-config-recursive + t + "Defines whether subdirectories should be parsed for config.phundrak.com") +#+END_SRC + +Now, here is my configuration. In this snippet, my org files located in my +source directory get exported in the HTML format and published to my target +directory on my remote server through RSYNC via TRAMP. A sitemap is +automatically generated, which comes in handy with the online sitemap that is +available through the navigation bar. +#+NAME: org-proj-config-html +#+BEGIN_SRC emacs-lisp + ("config-website-org" + :base-directory ,phundrak//projects-config-source + :base-extension "org" + :publishing-directory ,phundrak//projects-config-target + :recursive ,phundrak//projects-config-recursive + :language ,phundrak//projects-config-language + :publishing-function org-html-publish-to-html + :headline-levels 5 + :auto-sitemap t + :auto-preamble t) +#+END_SRC + +We also have the component for all the static files needed to run the website +(mostly images tbh). +#+NAME: org-proj-config-static +#+BEGIN_SRC emacs-lisp + ("config-website-static" + :base-directory ,phundrak//projects-config-source + :base-extension "png\\|jpg\\|gif\\|webp\\|svg\\|jpeg\\|ttf\\|woff\\|txt\\|epub\\|md" + :publishing-directory ,phundrak//projects-config-target + :recursive ,phundrak//projects-config-recursive + :language ,phundrak//projects-config-language + :publishing-function org-publish-attachment) +#+END_SRC + +The project is then defined like so: +#+NAME: org-proj-config +#+BEGIN_SRC emacs-lisp + ("config-website" + :components ("config-website-org" + "config-website-static")) +#+END_SRC + +***** Linguistics website +My linguistics website is made out of three projects. As for the previous +project, let’s declare the common values for these. +#+NAME: org-proj-lang-setup +#+BEGIN_SRC emacs-lisp + (defvar phundrak//projects-conlanging-target + "/rsync:Tilo:~/www/phundrak.com/langue/" + "Points to where exported files for langue.phundrak.com should be put") + (defvar phundrak//projects-conlanging-source + "~/Documents/conlanging/content/" + "Points to where the sources for langue.phundrak.com are") + (defvar phundrak//projects-conlanging-language + "fr" + "Language of langue.phundrak.com") + (defvar phundrak//projects-conlanging-recursive + t + "Defines whether subdirectories should be parsed for langue.phundrak.com") +#+END_SRC + +The first component is the one generating the HTML files from the org files. +#+NAME: org-proj-lang-html +#+BEGIN_SRC emacs-lisp + ("langue-phundrak-com-org" + :base-directory ,phundrak//projects-conlanging-source + :base-extension "org" + :exclude "\\./\\(CONTRIB\\|README\\|head\\|temp\\|svg-ink\\).*" + :publishing-directory ,phundrak//projects-conlanging-target + :recursive ,phundrak//projects-conlanging-recursive + :language ,phundrak//projects-conlanging-language + :publishing-function org-html-publish-to-html + :headline-levels 5 + :auto-sitemap t + :auto-preamble t) +#+END_SRC + +We also have the component for the LaTeX and PDF part of the website: +#+NAME: org-proj-lang-pdf +#+BEGIN_SRC emacs-lisp + ("langue-phundrak-com-pdf" + :base-directory ,phundrak//projects-conlanging-source + :base-extension "org" + :exclude "\\./\\(CONTRIB\\|README\\|index\\|head\\|temp\\|svg-ink\\).*" + :publishing-directory ,phundrak//projects-conlanging-target + :recursive ,phundrak//projects-conlanging-recursive + :language ,phundrak//projects-conlanging-language + :publishing-function org-latex-publish-to-pdf + :headline-levels 5 + :auto-preamble t) +#+END_SRC + +And lastly, we have the component for all the static files needed to run the +website: +#+NAME: org-proj-lang-static +#+BEGIN_SRC emacs-lisp + ("langue-phundrak-com-static" + :base-directory ,phundrak//projects-conlanging-source + :base-extension "png\\|jpg\\|gif\\|webp\\|svg\\|jpeg\\|ttf\\|woff\\|txt\\|epub" + :publishing-directory ,phundrak//projects-conlanging-target + :recursive ,phundrak//projects-conlanging-recursive + :language ,phundrak//projects-conlanging-language + :publishing-function org-publish-attachment) +#+END_SRC + +The project is then defined like so: +#+NAME: org-proj-lang +#+BEGIN_SRC emacs-lisp + ("langue-phundrak-com" + :components ("langue-phundrak-com-org" + "langue-phundrak-com-static" + "langue-phundrak-com-pdf")) +#+END_SRC + +**** Visual Configuration +#+begin_src emacs-lisp + (use-package mixed-pitch + :after org + :straight t + :hook + (org-mode . mixed-pitch-mode) + :config + (add-hook 'org-agenda-mode-hook (lambda () (mixed-pitch-mode -1)))) +#+end_src + +#+begin_src emacs-lisp + (use-package org-appear + :after org + :straight (:build t) + :hook (org-mode . org-appear-mode) + :config + (setq org-appear-autoemphasis t + org-hide-emphasis-markers t + org-appear-autolinks t + org-appear-autoentities t + org-appear-autosubmarkers t) + (run-at-time nil nil #'org-appear--set-elements)) +#+end_src + +#+begin_src emacs-lisp + (use-package org-superstar + :after org + :straight (:build t) + :hook (org-mode . org-superstar-mode) + :config + (setq org-superstar-leading-bullet ?\s + org-superstar-leading-fallback ?\s + org-hide-leading-stars nil + org-superstar-todo-bullet-alist + '(("TODO" . 9744) + ("[ ]" . 9744) + ("DONE" . 9745) + ("[X]" . 9745)))) +#+end_src + +#+begin_src emacs-lisp + (use-package org-fancy-priorities + :after (org all-the-icons) + :straight (:build t) + :hook (org-mode . org-fancy-priorities-mode) + :hook (org-agenda-mode . org-fancy-priorities-mode) + :config + (setq org-fancy-priorities-list `(,(all-the-icons-faicon "flag" :height 1.1 :v-adjust 0.0) + ,(all-the-icons-faicon "arrow-up" :height 1.1 :v-adjust 0.0) + ,(all-the-icons-faicon "square" :height 1.1 :v-adjust 0.0)))) +#+end_src + +*** Tramp +Tramp is an Emacs built-in package that allows the user to connect to +various hosts using various protocols, such as ~ssh~ and +~rsync~. However, I have some use-case for Tramp which are not +supported natively. I will describe them here. +#+begin_src emacs-lisp + (require 'tramp) +#+end_src + +**** Yadm +# ~yadm~ is the utility I use for managing my dotfiles, and it is a wrapper In +# order to manage my dotfiles, I use the following shortcut to launch Magit Status +# for ~yadm~: +[[https://yadm.io/][~yadm~]] is a git wrapper made to easily manage your dotfiles. It has +loads of features I don’t use (the main one I like but don’t use is +its [[https://yadm.io/docs/templates][Jinja-like host and OS-aware syntax]]), but unfortunately Magit +doesn’t play nice with it. Tramp to the rescue, and this page explains +how! Let’s just insert in my config this code snippet: +#+begin_src emacs-lisp +(add-to-list 'tramp-methods + '("yadm" + (tramp-login-program "yadm") + (tramp-login-args (("enter"))) + (tramp-login-env (("SHELL") ("/bin/sh"))) + (tramp-remote-shell "/bin/sh") + (tramp-remote-shell-args ("-c")))) +#+end_src + +I’ll also create a fuction for connecting to this new Tramp protocol: +#+begin_src emacs-lisp + (defun my/yadm () + "Manage my dotfiles through TRAMP." + (interactive) + (magit-status "/yadm::")) +#+end_src + +** Project Management +*** Magit +#+begin_src emacs-lisp + (use-package magit + :straight (:build t) + :defer t + :custom + (magit-display-buffer-function #'magit-display-buffer-same-window-except-diff-v1) + :config + (progn + (general-define-key + :keymaps '(git-rebase-mode-map) + "C-t" #'evil-next-line + "C-s" #'evil-previous-line) + (general-define-key + :keymaps 'git-rebase-mode-map + :state 'normal + :prefix "," + "," #'with-editor-finish + "k" #'with-editor-cancel + "a" #'with-editor-cancel))) +#+end_src + +#+begin_src emacs-lisp + (use-package evil-magit + :straight (:build t) + :after magit) +#+end_src + +*** Forge +*NOTE*: Make sure to configure a GitHub token before using this + package! +- [[https://magit.vc/manual/forge/Token-Creation.html#Token-Creation][Token Creation]] +- [[https://magit.vc/manual/ghub/Getting-Started.html#Getting-Started][Getting started]] +#+begin_src emacs-lisp + (use-package forge + :after magit + :straight (:build t)) +#+end_src + +*** Projectile +#+begin_src emacs-lisp + (use-package projectile + :straight (:build t) + :defer t + :diminish projectile-mode + :config (projectile-mode) + :custom ((projectile-completion-system 'ivy)) + :bind-keymap + ("C-c p" . projectile-command-map) + :init + ;; NOTE: Set this to the folder where you keep your Git repos! + (setq projectile-switch-project-action #'projectile-dired)) + + (use-package counsel-projectile + :straight (:build t) + :after (counsel projectile) + :config (counsel-projectile-mode)) +#+end_src + +** Programming languages +*** DSLs +DSLs, or /Domain Specific Languages/, are languages dedicated to some +very tasks, such as configuration languages or non-general programming +such as SQL. +**** Caddy +[[https://caddyserver.com/][Caddy]] (or /Caddyserver/) is a web server akin to Nginx or Apache which I +find much easier to configure that the latter two, plus it has +built-in support for automatically generating SSL certificates with +Letsencrypt! Automatic HTTPS, what more do you want? + +All that is nice and all, but Emacs doesn’t support the syntax of +Caddy files natively, so let’s install ~caddyfile-mode~: +#+begin_src emacs-lisp + (use-package caddyfile-mode + :defer t + :straight (:build t) + :mode (("Caddyfile\\'" . caddyfile-mode) + ("caddy\\.conf\\'" . caddyfile-mode))) +#+end_src + +**** Nginx +Nginx is another webserver, older and more mature than Caddy. A couple +of packages are required in order to be able to properly work with +Nginx configuration files. First, we need the correct mode for editing +Nginx configuration files. +#+begin_src emacs-lisp + (use-package nginx-mode + :straight (:build t) + :defer t) +#+end_src + +We then also have an autocompletion package that adds to ~company~ the +Nginx syntax. +#+begin_src emacs-lisp + (use-package company-nginx + :straight (:build t) + :defer t + :config + (add-hook 'nginx-mode-hook (lambda () + (add-to-list 'company-backends #'company-nginx)))) +#+end_src + +**** Yaml +#+begin_src emacs-lisp + (use-package yaml-mode + :defer t + :straight (:build t) + :mode "\\.yml\\'" + :mode "\\.yaml\\'") +#+end_src + +*** Flycheck +#+begin_src emacs-lisp + (use-package flycheck + :straight (:build t) + :defer t + :init + (global-flycheck-mode) + :config + (setq flycheck-emacs-lisp-load-path 'inherit) + + ;; Rerunning checks on every newline is a mote excessive. + (delq 'new-line flycheck-check-syntax-automatically) + ;; And don’t recheck on idle as often + (setq flycheck-idle-change-delay 2.0) + + ;; For the above functionality, check syntax in a buffer that you + ;; switched to on briefly. This allows “refreshing” the syntax check + ;; state for several buffers quickly after e.g. changing a config + ;; file. + (setq flycheck-buffer-switch-check-intermediate-buffers t) + + ;; Display errors a little quicker (default is 0.9s) + (setq flycheck-display-errors-delay 0.2)) + + (use-package flycheck-popup-tip + :straight (:build t) + :after flycheck + :hook (flycheck-mode . flycheck-popup-tip-mode) + :config + (setq flycheck-popup-tip-error-prefix "X ") + (after! evil + (add-hook 'evil-insert-state-entry-hook + #'flycheck-popup-tip-delete-popup) + (add-hook 'evil-replace-state-entry-hook + #'flycheck-popup-tip-delete-popup))) + + (use-package flycheck-posframe + :straight (:build t) + :hook (flycheck-mode . flycheck-posframe-mode) + :config + (setq flycheck-posframe-warning-prefix "! " + flycheck-posframe-info-prefix "··· " + flycheck-posframe-error-prefix "X ")) +#+end_src + +*** General Programming Languages +**** EmacsLisp +#+begin_src emacs-lisp + (use-package eldoc + :after company + :init + (eldoc-add-command 'company-complete-selection + 'company-complete-common + 'company-capf + 'company-abort)) +#+end_src + +#+begin_src emacs-lisp + (general-define-key + :states 'motion + :keymaps 'emacs-lisp-mode-map + :prefix "," + + "'" #'ielm + + "c" '(emacs-lisp-byte-compile :which-key "Byte compile") + + "e" '(nil :which-key "eval") + "eb" #'eval-buffer + "ed" #'eval-defun + "ee" #'eval-last-sexp + "er" #'eval-region + + "h" '(nil :which-key "help") + "hh" #'helpful-at-point) +#+end_src + +** Applications +*** Docker +#+begin_src emacs-lisp + (use-package docker + :defer t + :straight (:build t)) +#+end_src + +#+begin_src emacs-lisp + (use-package dockerfile-mode + :defer t + :straight (:build t) + :init + (put 'docker-image-name 'safe-local-variable #'stringp) + :mode "Dockerfile\\'") +#+end_src + +*** Elfeed +*** Email - Mu4e +#+begin_src emacs-lisp + (setq message-signature nil + mail-signature nil) +#+end_src + +#+begin_src emacs-lisp + (use-package mu4e + :after all-the-icons + :straight (:build t :location site) + :commands mu4e mu4e-compose-new + :bind (("C-x m" . mu4e-compose-new)) + :init + (progn + (setq mu4e-completing-read-function 'completing-read + mu4e-use-fancy-chars t + mu4e-view-show-images t + message-kill-buffer-on-exit t + mu4e-org-support nil) + (let ((dir "~/Downloads/mu4e")) + (when (file-directory-p dir) + (setq mu4e-attachment-dir dir)))) + + :config + (progn + <> + (setq mu4e-compose-signature nil) + + (when (fboundp 'imagemagick-register-types) + (imagemagick-register-types)) + + (add-to-list 'mu4e-view-actions + '("View in browser" . mu4e-action-view-in-browser) t) + + (require 'gnus-dired) + (setq gnus-dired-mail-mode 'mu4e-user-agent) + + (add-hook 'mu4e-compose-mode-hook + (lambda () (use-hard-newlines t 'guess))) + (add-hook 'dired-mode-hook 'turn-on-gnus-dired-mode) + (add-hook 'mu4e-compose-mode-hook 'mml-secure-message-sign-pgpmime) + + (setq mu4e-get-mail-command "mbsync -a" + mu4e-maildir "~/.mail" + mu4e-trash-folder "/Trash" + mu4e-refile-folder "/Archive" + mu4e-sent-folder "/Sent" + mu4e-drafts-folder "/Drafts" + mu4e-update-interval 60 + mu4e-compose-format-flowed t + mu4e-view-show-addresses t + mu4e-sent-messages-behaviour 'sent + mu4e-hide-index-messages t + ;; try to show images + mu4e-view-show-images t + mu4e-view-image-max-width 600 + ;; configuration for sending mail + message-send-mail-function #'smtpmail-send-it + smtpmail-stream-type 'starttls + message-kill-buffer-on-exit t ; close after sending + ;; start with the first (default) context + mu4e-context-policy 'pick-first + ;; compose with the current context, or ask + mu4e-compose-context-policy 'ask-if-none + ;; use ivy + mu4e-completing-read-function #'ivy-completing-read + ;; no need to ask + mu4e-confirm-quit t + + + mu4e-header-fields + '((:account . 12) + (:human-date . 12) + (:flags . 4) + (:from . 25) + (:subject))) + + ;; set mail user agent + (setq mail-user-agent 'mu4e-user-agent) + + ;; Use fancy icons + (setq mu4e-use-fancy-chars t + mu4e-headers-draft-mark `("D" . ,(all-the-icons-faicon "pencil":height 0.8)) + mu4e-headers-flagged-mark `("F" . ,(all-the-icons-faicon "flag":height 0.8)) + mu4e-headers-new-mark `("N" . ,(all-the-icons-faicon "rss":height 0.8)) + mu4e-headers-passed-mark `("P" . ,(all-the-icons-faicon "check":height 0.8)) + mu4e-headers-replied-mark `("R" . ,(all-the-icons-faicon "reply":height 0.8)) + mu4e-headers-seen-mark `("S" . ,(all-the-icons-faicon "eye":height 0.8)) + mu4e-headers-unread-mark `("u" . ,(all-the-icons-faicon "eye-slash":height 0.8)) + mu4e-headers-trashed-mark `("T" . ,(all-the-icons-faicon "trash":height 0.8)) + mu4e-headers-attach-mark `("a" . ,(all-the-icons-faicon "paperclip":height 0.8)) + mu4e-headers-encrypted-mark `("x" . ,(all-the-icons-faicon "lock":height 0.8)) + mu4e-headers-signed-mark `("s" . ,(all-the-icons-faicon "certificate":height 0.8))) + + (setq mu4e-bookmarks + `((,(s-join " " + '("NOT flag:trashed" + "AND (maildir:/Inbox OR maildir:/Junk)" + "AND NOT to:CONLANG@LISTSERV.BROWN.EDU" + "AND NOT to:AUXLANG@LISTSERV.BROWN.EDU" + "AND NOT to:ateliers-emacs@framalistes.org" + "AND NOT to:ateliers-paris@emacs-doctor.com" + "AND NOT list:ateliers-emacs.framalistes.org" + "AND NOT list:ateliers-paris.emacs-doctor.com")) + "Inbox" ?i) ;; Inbox without the linguistics mailing lists + (,(s-join " " + '("NOT flag:trashed" + "AND (maildir:/Inbox OR maildir:/Junk)" + "AND (f:/.*up8\.edu|.*univ-paris8.*/" + "OR c:/.*up8\.edu|.*univ-paris8.*/" + "OR t:/.*up8\.edu|.*univ-paris8.*/)")) + "University" ?u) ;; University-related emails + (,(s-join " " + '("to:CONLANG@LISTSERV.BROWN.EDU" + "OR to:AUXLANG@LISTSERV.BROWN.EDU")) + "Linguistics" ?l) ;; linguistics mailing lists + (,(s-join " " + '("list:ateliers-emacs.framalistes.org" + "OR to:ateliers-paris@emacs-doctor.com" + "OR list:ateliers-paris.emacs-doctor.com")) + "Emacs" ?e) ;; Emacs mailing list + ("maildir:/Sent" "Sent messages" ?s) + ("flag:unread AND NOT flag:trashed" "Unread messages" ?U) + ("date:today..now AND NOT flag:trashed" "Today's messages" ?t) + ("date:7d..now AND NOT flag:trashed" "Last 7 days" ?w) + ("date:1m..now AND NOT flag:trashed" "Last month" ?m) + ("date:1y..now AND NOT flag:trashed" "Last year" ?y) + ("flag:trashed AND NOT flag:trashed" "Trash" ?T) + ("mime:image/* AND NOT flag:trashed" "Messages with images" ?p))) + + ;; Add a column to display what email account the email belongs to. + (add-to-list 'mu4e-header-info-custom + '(:account + :name "Account" + :shortname "Account" + :help "Which account this email belongs to" + :function + (lambda (msg) + (let ((maildir (mu4e-message-field msg :maildir))) + (format "%s" (substring maildir 1 (string-match-p "/" maildir 1))))))) + + (setq smtpmail-smtp-server "mail.phundrak.com" + smtpmail-smtp-service 587 + smtpmail-stream-type 'starttls + message-send-mail-function 'smtpmail-send-it) + + (defun mu4e-action-open-as-pdf (msg) + "Export and open MSG as pdf." + (let* ((date (mu4e-message-field msg :date)) + (infile (mu4e~write-body-to-html msg)) + (outfile (format-time-string "/tmp/%Y-%m-%d-%H-%M-%S.pdf" date))) + (with-temp-buffer + (shell-command + (format "wkhtmltopdf %s %s" infile outfile) t)) + (find-file outfile))) + + (add-to-list 'mu4e-view-actions '("PDF view" . mu4e-action-open-as-pdf) t))) +#+end_src + +#+name: mu4e-keybindings +#+begin_src emacs-lisp :tangle no + ;; Unbinding some stuff + (general-define-key + :keymaps '(mu4e-headers-mode-map mu4e-view-mode-map) + "s" nil) + (general-define-key + :states 'normal + :keymaps '(mu4e-headers-mode-map mu4e-view-mode-map) + "s" nil) + (general-define-key + :keymaps 'mu4e-view-mode-map + "SPC" nil + "S" nil + "r" nil + "c" nil) + + (general-define-key + :keymaps 'mu4e-view-mode-map + :states 'normal + "SPC" nil + "S" nil + "r" nil + "c" nil + "gu" nil) + + ;; View + (general-define-key + :keymaps 'mu4e-view-mode-map + :states 'normal + ) + + (general-define-key + :states 'motion + :keymaps 'mu4e-view-mode-map + :prefix "," + "|" #'mu4e-view-pipe + "." '(mu4e-headers-split-adjust-width/body :wk "mu4e-headers width") + + "a" '(nil :wk "attachments") + "a|" #'mu4e-view-pipe-attachment + "aa" #'mu4e-view-attachment-action + "ao" #'mu4e-view-open-attachment + "aO" #'mu4e-view-open-attachment-with + + "c" '(nil :wk "compose") + "cc" #'mu4e-compose-new + "ce" #'mu4e-compose-edit + "cf" #'mu4e-compose-forward + "cr" #'mu4e-compose-reply + "cR" #'mu4e-compose-resend + + "g" '(nil :wk "go to") + "gu" #'mu4e-view-go-to-url + "gX" #'mu4e-view-fetch-url + + "l" #'mu4e-show-log + + "m" '(nil :wk "mark") + "md" #'mu4e-view-mark-for-trash + "mD" #'mu4e-view-mark-for-delete + "mm" #'mu4e-view-mark-for-move + "mr" #'mu4e-view-mark-for-refile + "mR" #'mu4e-view-mark-for-read + "mu" #'mu4e-view-mark-for-unread + "mU" #'mu4e-view-mark-for-unmark + + "t" '(nil :wk "thread") + "td" '((lambda () + (interactive) + (mu4e-view-mark-thread '(trash))) + :wk "Mark as trash") + "tD" '((lambda () + (interactive) + (mu4e-view-mark-thread '(delete))) + :wk "Mark as delete") + "tm" '((lambda () + (interactive) + (mu4e-view-mark-thread '(move))) + :wk "Mark as move") + "tr" '((lambda () + (interactive) + (mu4e-view-mark-thread '(refile))) + :wk "Mark as refile") + "tR" '((lambda () + (interactive) + (mu4e-view-mark-thread '(read))) + :wk "Mark as read") + "tu" '((lambda () + (interactive) + (mu4e-view-mark-thread '(unread))) + :wk "Mark as unread") + "tU" '((lambda () + (interactive) + (mu4e-view-mark-thread '(unmark))) + :wk "Mark as unmark") + + "T" '(nil :wk "toggle") + "Tc" #'mu4e-view-toggle-hide-cited + "Th" #'mu4e-view-toggle-html + + + "n" #'mu4e-view-headers-next + "N" #'mu4e-view-headers-next-unread + "p" #'mu4e-view-headers-prev + "P" #'mu4e-view-headers-prev-unread) + + ;; Headers + (general-define-key + :prefix "," + :keymaps 'mu4e-headers-mode-map + :states 'normal + "s" '(nil :wk "search") + "ss" #'swiper) + + (general-define-key + :keymaps 'mu4e-headers-mode-map + :states 'motion + "t" #'evil-next-line + "s" #'evil-previous-line + "T" '((lambda () + (interactive) + (mu4e-headers-mark-thread nil '(read))) + :wk "Mark as read")) + + ;; Message + (general-define-key + :states 'normal + :keymaps 'message-mode-map + :prefix "," + "," #'message-send-and-exit + "c" #'message-send-and-exit + "a" #'message-kill-buffer + "k" #'message-kill-buffer + "s" #'message-dont-send + "f" #'mml-attach-file) +#+end_src + +#+begin_src emacs-lisp + (use-package org-msg + :after (org mu4e) + :straight (:build t) + :hook (mu4e-compose-pre . org-msg-mode) + :general (:keymaps 'org-msg-edit-mode-map + :prefix "," + :states 'normal + "," #'message-send-and-exit + "c" #'message-send-and-exit + "a" #'message-kill-buffer + "k" #'message-kill-buffer + "s" #'message-dont-send + "f" #'org-msg-attach) + + :config + (progn + (defun my/org-msg-signature-convert (orig-fun &rest args) + "Tweak my signature when replying as plain/text only." + (let ((res (apply orig-fun args))) + (when (equal (cadr args) '(text)) + (setf (alist-get 'signature res) + (replace-regexp-in-string "\n+" "\n" org-msg-signature))) + res)) + (advice-add 'org-msg-composition-parameters + :around 'my/org-msg-signature-convert) + + (setq org-msg-startup "inlineimages" + org-msg-default-alternatives '((new . (text html)) + (reply-to-html . (text html)) + (reply-to-text . (text))) + org-msg-convert-citation t + org-msg-greeting-name-limit 3 + org-msg-signature (format "\n--\n#+begin_signature\n%s\n#+end_signature" + (with-temp-buffer + (insert-file-contents mail-signature-file) + (buffer-string)))))) +#+end_src + +#+begin_src emacs-lisp + (use-package mu4e-alert + :straight (:build t) + :after mu4e) +#+end_src + +*** PDF Tools +#+begin_src emacs-lisp + (use-package pdf-tools + :defer t + :magic ("%PDF" . pdf-view-mode) + :straight (:build t) + :mode (("\\.pdf\\'" . pdf-view-mode)) + :config + (progn + (with-eval-after-load 'pdf-view + (setq pdf-view-midnight-colors '("#d8dee9" . "#2e3440"))) + + (general-define-key + :keymaps 'pdf-view-mode-map + "SPC" nil) + (general-define-key + :keymaps 'pdf-view-mode-map + :states 'normal + "SPC" nil) + ;; (define-key 'pdf-view-mode-map (kbd "SPC") nil) + + (general-define-key + :states 'normal + :keymaps 'pdf-view-mode-map + "y" #'pdf-view-kill-ring-save + "t" #'evil-collection-pdf-view-next-line-or-next-page + "s" #'evil-collection-pdf-view-previous-line-or-previous-page)) + + (general-define-key + :states 'motion + :keymaps 'pdf-view-mode-map + :prefix "SPC" + "a" '(nil :which-key "annotations") + "aD" #'pdf-annot-delete + "at" #'pdf-annot-attachment-dired + "ah" #'pdf-annot-add-highlight-markup-annotation + "al" #'pdf-annot-list-annotations + "am" #'pdf-annot-markup-annotation + "ao" #'pdf-annot-add-strikeout-markup-annotation + "as" #'pdf-annot-add-squiggly-markup-annotation + "at" #'pdf-annot-add-text-annotation + "au" #'pdf-annot-add-underline-markup-annotation + + "f" '(nil :which-key "fit") + "fw" #'pdf-view-fit-width-to-window + "fh" #'pdf-view-fit-height-to-window + "fp" #'pdf-view-fit-page-to-window + + "s" '(nil :which-key "slice/search") + "sb" #'pdf-view-set-slice-from-bounding-box + "sm" #'pdf-view-set-slice-using-mouse + "sr" #'pdf-view-reset-slice + "ss" #'pdf-occur + + "o" 'pdf-outline + "m" 'pdf-view-midnight-minor-mode) + + :hook + (pdf-tools-enabled . pdf-view-midnight-minor-mode)) +#+end_src + +*** Screenshot +#+begin_src emacs-lisp + (use-package screenshot + :defer t + :straight (screenshot :build t + :type git + :host github + :repo "tecosaur/screenshot")) +#+end_src + +*** Shells +**** VTerm +#+begin_src emacs-lisp + (use-package vterm + :defer t + :straight t) +#+end_src + +*** Webkit browser +#+begin_src emacs-lisp + (general-define-key + :keymaps 'xwidget-webkit-mode-map + :states 'normal + "c" #'xwidget-webkit-scroll-backward + "t" #'xwidget-webkit-scroll-up + "s" #'xwidget-webkit-scroll-down + "r" #'xwidget-webkit-scroll-forward + "h" #'xwidget-webkit-goto-history + "j" nil + "k" nil + "l" nil + + "H" nil + "L" nil + "T" #'xwidget-webkit-back + "S" #'xwidget-webkit-forward + "R" #'xwidget-webkit-reload) +#+end_src +*** Wttr.in +#+begin_src emacs-lisp + (use-package wttrin + :defer t + :straight (wttrin :build t + :type git + ;; :host github + ;; :repo "Phundrak/emacs-wttrin" + :local-repo "~/fromGIT/emacs-packages/emacs-wttrin" + ) + :config + (setq wttrin-default-cities '("Aubervilliers" "Paris" "Lyon" "Nonières" + "Saint Agrève") + wttrin-use-metric t)) +#+end_src + +**** TODO Derive a major mode for wttrin :noexport: +To handle keybindings correctly, a major mode for wttrin could be +derived from ~fundamental-mode~ and get an associated keymap. + +** Other +*** ~ivy-quick-find-files.el~ +This package is a small utility package I’ve written in order to +quickly find files across my filesystem. +#+begin_src emacs-lisp + (use-package ivy-quick-find-files + :defer t + :straight (ivy-quick-find-files :type git + :host github + :repo "phundrak/ivy-quick-find-files.el" + :build t) + :config + (setq ivy-quick-find-files-program 'fd + ivy-quick-find-files-dirs-and-exts '(("~/org" . "org") + ("~/Documents/conlanging" . "org") + ("~/Documents/university" . "org")))) +#+end_src + +*** Winum +Winum allows Emacs to associate windows with a specific number and +navigate through these windows by directly refering to their +associated number! This allows for faster window configuration than +just going to the frame above, then left, left, and up. +#+begin_src emacs-lisp + (use-package winum + :straight (:build t) + :init (winum-mode) + :general + (:states 'normal + "SPC 0" #'winum-select-window-0-or-10 + "SPC 1" #'winum-select-window-1 + "SPC 2" #'winum-select-window-2 + "SPC 3" #'winum-select-window-3 + "SPC 4" #'winum-select-window-4 + "SPC 5" #'winum-select-window-5 + "SPC 6" #'winum-select-window-6 + "SPC 7" #'winum-select-window-7 + "SPC 8" #'winum-select-window-8 + "SPC 9" #'winum-select-window-9 + "SPC $" #'winum-select-window-by-number)) +#+end_src + +* Keybindings +Undefining some stuff to make keybind prefixes work correctly. +#+begin_src emacs-lisp + (general-define-key + :keymaps '(backtrace-mode-map diff-minor-mode-map magit-mode-map + rmail-mode-map evil-motion-state-map dired-mode-map + epa-key-list-mode-map special-mode-map splash-screen-keymap + undo-tree-visualizer-mode-map magit-blame-read-only-mode-map + org-agenda-keymap org-agenda-mode-map git-rebase-mode-map + Buffer-menu-mode-map custom-mode-map) + "SPC" nil) + + (general-define-key + :keymaps 'evil-motion-state-map + "," nil) + + (general-define-key + :keymaps 'evil-insert-state-map + "C-t" nil) + + (general-define-key + :keymaps '(diff-mode-map help-mode-map image-mode-map + dired-mode-map Man-mode-map eww-mode-map magit-mode-map + debugger-mode-map dired-mode-map custom-mode-map) + :states 'normal + "SPC" nil) + + (general-define-key + :keymaps 'magit-mode-map + :states 'visual + "SPC" nil) + + (general-define-key + :keymaps '(diff-mode-map org-agenda-keymap org-agenda-mode-map) + :states 'motion + "SPC" nil) + + (general-define-key + :keymaps 'eshell-mode-map + :states 'normal + "c" #'evil-backward-char + "t" #'evil-next-line + "s" #'evil-previous-line + "r" #'evil-forward-char) + + (general-define-key + :keymaps 'evil-insert-state-map + "U" nil + "C-a" nil + "C-y" nil + "C-e" nil) + + (general-define-key + :states 'normal + "U" #'evil-redo + "C-a" #'beginning-of-line + "C-e" #'end-of-line + "C-y" #'yank) +#+end_src + +#+begin_src emacs-lisp + (general-define-key + :states 'normal + :prefix "SPC" + "SPC" '(counsel-M-x :wk "M-x") + + "a" '(nil :wk "apps") + "ac" #'calc + "ad" #'docker + "ae" #'eww + "at" #'tetris + "aw" #'wttrin + "aC" #'calendar + + "as" '(nil :wk "shells") + "ase" #'eshell-new + "asv" #'vterm + + "b" '(nil :wk "buffers") + "bb" #'counsel-ibuffer + "bB" #'bury-buffer + "bi" #'ibuffer-list-buffers-and-focus + "bd" #'kill-this-buffer + "bD" #'kill-buffer + "bh" #'dashboard-refresh-buffer + "bm" #'switch-to-messages-buffer + "br" #'counsel-buffer-or-recentf + "bs" #'switch-to-scratch-buffer + + "c" '(nil :wk "code") + "cl" #'evilnc-comment-or-uncomment-lines + + "e" '(nil :wk "email") + "ec" #'mu4e-compose-new + "em" #'mu4e + + "f" '(nil :wk "files") + "fc" '((lambda () + (interactive) + (find-file (concat (getenv "HOME") "/org/config/emacs.org"))) + :wk "Config file") + "ff" #'counsel-find-file + "fF" #'ivy-quick-find-files + "fh" #'hexl-find-file + "fr" #'counsel-recentf + "fs" #'save-buffer + + "g" '(nil :wk "git") + "gc" #'magit-clone + "gd" #'magit-dispatch + "gi" #'magit-init + "gs" #'magit-status + "gy" #'my/yadm + "gS" #'magit-stage-file + "gU" #'magit-unstage-file + + "gf" '(nil :wk "file") + "gfd" #'magit-diff + "gfc" #'magit-file-checkout + "gfl" #'magit-file-dispatch + "gfF" #'magit-find-file + + "h" '(nil :wk "help") + "hk" #'wk-show-top-level + "hd" '(nil :wk "describe") + "hdc" #'describe-char + "hdf" #'helpful-callable + "hdk" #'helpful-key + "hdv" #'helpful-variable + + "i" '(nil :wk "insert") + "iy" #'ivy-yasnippet + + "j" '(nil :wk "jump") + "jd" #'dired-jump + + "t" '(nil :wk "toggles") + "tt" #'counsel-load-theme + "ti" '(nil :wk "input method") + "tit" #'toggle-input-method + "tis" #'set-input-mode + + "u" #'universal-argument + + "w" '(nil :wk "windows") + "w-" #'split-window-below-and-focus + "w/" #'split-window-right-and-focus + "wb" '((lambda () + (interactive) + (progn + (kill-this-buffer) + (delete-window))) + :wk "Kill buffer and window") + "wd" #'delete-window + "wD" #'delete-other-windows + "wo" #'other-window + + "wc" #'evil-window-left + "wt" #'evil-window-down + "ws" #'evil-window-up + "wr" #'evil-window-right + "ww" '(nil :wk "writeroom") + "www" #'writeroom-mode + "wwb" #'writeroom-buffer-width/body + + "T" '(nil :wk "text") + "Tz" #'hydra-zoom/body + "Tu" #'downcase-region + "TU" #'upcase-region + "Te" #'string-edit-at-point + + "q" '(nil :wk "quit") + "qf" #'delete-frame + "qq" #'save-buffers-kill-terminal + "qQ" #'kill-emacs) +#+end_src + +* Various TODOs :noexport: +** TODO advise ~evil-insert~ in eshell +Advise ~evil-insert~ to go to the end of the buffer while in +~eshell-mode~. +** TODO Write macro wrapper around ~general~ +Write a macro wrapper around ~general~ for when an evil state is used in +order to make the keybind available when in ~insert-mode~ through ~M-m~.