;; -------- Speed up load time ------- ;; I don't use emacs-server, so startup times are very important to me. ;; Garbage collection is triggered very often during start up, and it ;; slows the whole thing down. It is safe to increase threshold ;; temporarily to prevent aggressive GC, and then re-enable it at the ;; end. (setq gc-cons-threshold 402653184 gc-cons-percentage 0.6) ;; There are special ways to handle files (via SSH or in archives), ;; but this is not necessary during startup, and it also slows down ;; the load significantly, as emacs is going through lots of files. (defvar saved--file-name-handler-alist file-name-handler-alist) (setq file-name-handler-alist nil) ;; Restore defaults after initialization has completed (add-hook 'after-init-hook #'(lambda () (setq gc-cons-threshold 16777216 gc-cons-percentage 0.1) (setq file-name-handler-alist saved--file-name-handler-alist))) ;; -------- Default directories -------- (setq default-directory "~/") (setq command-line-default-directory "~/") ;; -------- State files -------- ;; By default emacs leaves lots of trash around your filesystem while ;; you are editing. This section cleans up the basics. ;; Don't leave =yourfile~= temporary files nearby, and put them to a ;; separate directory instead. (setq backup-directory-alist '(("." . "~/.emacs.d/backups"))) (setq auto-save-file-name-transforms '((".*" "~/.emacs.d/backups" t))) ;; -------- Command history -------- ;; Save command history so that when emacs is restarted, the history ;; is preserved. (setq savehist-file "~/.emacs.d/savehist") (savehist-mode +1) (setq savehist-save-minibuffer-history +1) (setq savehist-additional-variables '(kill-ring search-ring regexp-search-ring)) ;; -------- Recent files -------- ;; Recent files are convenient to record because you can use them to ;; quickly jump to what you've been editing recently. (setq recentf-save-file "~/.emacs.d/recentf" recentf-max-menu-items 0 recentf-max-saved-items 300 recentf-filename-handlers '(file-truename) recentf-exclude (list "^/tmp/" "^/ssh:" "\\.?ido\\.last$" "\\.revive$" "/TAGS$" "^/var/folders/.+$" )) (recentf-mode 1) ;; -------- De-clutter -------- ;; Toolbar and scrollbars are only useful to novices. The same for ;; startup screen and menu bar. (tool-bar-mode -1) (scroll-bar-mode -1) (setq inhibit-startup-screen t) (if (not (eq window-system 'mac)) (menu-bar-mode -1)) ;; More reliable inter-window border ;; The native border "consumes" a pixel of the fringe on righter-most splits, ;; ~window-divider~ does not. Available since Emacs 25.1. (setq-default window-divider-default-places t window-divider-default-bottom-width 0 window-divider-default-right-width 1) (window-divider-mode +1) ;; Remove continuation arrow on right fringe (setq fringe-indicator-alist (delq (assq 'continuation fringe-indicator-alist) fringe-indicator-alist)) ;; No more typing the whole yes or no. Just y or n will do. (fset 'yes-or-no-p 'y-or-n-p) ;; Makes *scratch* empty. (setq initial-scratch-message "") ;; Hide modeline in the vterm mode (use-package hide-mode-line) (add-hook 'vterm-mode-hook #'hide-mode-line-mode) ;; -------- Cursor and movement -------- ;; On emacs mac port use Alt as meta key (if (eq window-system 'mac) (progn (setq mac-option-modifier 'meta) (setq mac-command-modifier nil) (setq mac-pass-command-to-system 't))) ;; Blinking cursor is inconvenient (blink-cursor-mode -1) ;; Disable bell ring when moving outside of available area (setq ring-bell-function 'ignore) ;; Disable annoying blink-matching-paren (setq blink-matching-paren nil) ;; -------- Window decoration -------- ;; This makes the header transparent on Emacs 26.1+ under OS X (add-to-list 'default-frame-alist '(ns-transparent-titlebar . t)) (add-to-list 'default-frame-alist '(ns-appearance . dark)) (setq ns-use-proxy-icon nil) ;; -------- Minor modes -------- ;; Hide some miror modes from sight to not clutter the modeline (use-package diminish) (require 'diminish) (diminish 'company-mode) (diminish 'projectile-mode) (diminish 'editorconfig-mode) (diminish 'eldoc-mode) (diminish 'flycheck-mode) (diminish 'which-key-mode) ;; -------- Theme -------- ;; - I don't like that fringes are visible, so I set them to regular ;; background color ;; - Panels look better without outset/inset shadows (use-package modus-themes) (load-theme 'modus-operandi t) (set-face-attribute 'fringe nil :foreground (face-foreground 'default) :background (face-background 'default)) ;; On many OSs the modeline has an outset border (lighter on top and ;; darker on the bottom). This doesn't look pretty on a flat theme. (set-face-attribute 'mode-line nil :box nil) (set-face-attribute 'mode-line-inactive nil :box nil) ;; -------- Font -------- ;; Some time ago I've purchased a great font called Pragmata Pro, ;; which is easy on the eyes and tailored for programmers. It may ;; not be available everywhere though, hence conditional load. (when window-system (if (not (null (x-list-fonts "PragmataPro"))) (add-to-list 'default-frame-alist '(font . "PragmataPro-15")) (add-to-list 'default-frame-alist '(font . "Source Code Pro-11")) )) ;; -------- Packages -------- (diminish 'company-mode) (diminish 'projectile-mode) (diminish 'editorconfig-mode) (diminish 'eldoc-mode) (diminish 'flycheck-mode) (diminish 'which-key-mode) ;; -------- Navigation -------- ;; Quickly find my way around emacs ;; Default scheme for uniquifying buffer names is not convenient. ;; It's better to have a regular path-like structure. ;;(require 'uniquify) (setq uniquify-buffer-name-style 'forward) (setq uniquify-separator "/") (setq uniquify-after-kill-buffer-p t) ; rename after killing uniquified (setq uniquify-ignore-buffers-re "^\\*") ; don't muck with special buffers ;; If you stop after typing a part of keybinding, shows available ;; options in minibuffer. (use-package which-key) (add-hook 'after-init-hook 'which-key-mode) (with-eval-after-load 'which-key (which-key-setup-side-window-bottom)) ;; persp-mode allows you to have tagged workspaces akin to ;; Linux tiled-window managers. (use-package persp-mode) ;; persp-mode clashes with corfu (setq persp-auto-resume-time 0) (add-hook 'after-init-hook 'persp-mode) (global-set-key (kbd "C-x x s") 'persp-switch) ;; vertico-mode allows for easy navigation between buffers and files (use-package vertico) (add-hook 'after-init-hook 'vertico-mode) (setq completion-ignore-case t) (setq completion-styles '(basic substring partial-completion flex)) (use-package marginalia) (add-hook 'after-init-hook 'marginalia-mode) ;; ripgrep search with consult (use-package consult) (global-set-key (kbd "M-s r") 'consult-ripgrep) (setq completion-in-region-function 'consult-completion-in-region) ;; Navigation when in russian layout (cl-loop for from across "йцукенгшщзхъфывапролджэячсмитьбюЙЦУКЕНГШЩЗХЪФЫВАПРОЛДЖ\ЭЯЧСМИТЬБЮ№" for to across "qwertyuiop[]asdfghjkl;'zxcvbnm,.QWERTYUIOP{}ASDFGHJKL:\"ZXCVBNM<>#" do (eval `(define-key key-translation-map (kbd ,(concat "C-" (string from))) (kbd ,(concat "C-" (string to))))) (eval `(define-key key-translation-map (kbd ,(concat "M-" (string from))) (kbd ,(concat "M-" (string to)))))) ;; -------- Editor basics -------- ;; Use 4 spaces to indent by default (setq-default indent-tabs-mode nil) (setq-default tab-width 4) ;; Clean up trailing whitespace on file save (add-hook 'before-save-hook 'whitespace-cleanup) ;; But use editorconfig to guess proper project-wide indentation rules (use-package editorconfig) (add-hook 'prog-mode-hook #'editorconfig-mode) ;; Speed up comint buffers by disabling bidirectional language support (setq-default bidi-display-reordering nil) ;; -------- Evil mode -------- ;; Evil mode is a vi/vim compatibility layer for Emacs that provides roughly ;; equivalent keybindings for editing. (setq evil-want-keybinding nil) (setq evil-want-C-u-scroll t) (use-package evil) (use-package evil-collection) (add-hook 'after-init-hook #'(lambda () (evil-mode 1) (evil-set-undo-system 'undo-redo) (evil-collection-init))) (evil-set-leader 'normal " ") (evil-define-key 'normal 'global (kbd "f") 'find-file) (evil-define-key 'normal 'global (kbd "b") 'switch-to-buffer) ;; -------- Tools and environment -------- ;; By default, Emacs doesn't add system path to its search places (use-package exec-path-from-shell) (require 'exec-path-from-shell) (setenv "PATH" (concat "/usr/local/bin:" (getenv "PATH"))) ;; On a mac, this will set up PATH and MANPATH from your environment (when (memq window-system '(mac ns x pgtk)) (exec-path-from-shell-initialize)) ;; -------- Org roam -------- (use-package org) (use-package org-contrib) (use-package org-roam) (use-package consult-org-roam) (setq org-roam-completion-everywhere t) (setq org-roam-directory "~/notes") (setq org-roam-node-default-sort 'file-mtime) (setq consult-org-roam-grep-func #'consult-ripgrep) (global-set-key (kbd "C-c n l") 'org-roam-buffer-toggle) (global-set-key (kbd "C-c n i") 'org-roam-node-insert) (global-set-key (kbd "C-c n f") 'org-roam-node-find) (global-set-key (kbd "C-c n r") 'consult-org-roam-search) (autoload 'org-roam-buffer-toggle "org-roam" "\ Enable org-roam " t nil) (autoload 'org-roam-setup "org-roam" "\ Enable org-roam " t nil) (setq org-roam-capture-templates `( ("d" "default" plain "%?" :target (file+head "%<%Y%m%d%H%M%S>-${slug}.org" "#+title: ${title}\n") :unnarrowed t) ("p" "post" plain "%?" :target (file+head "%<%Y%m%d%H%M%S>-${slug}.org" ,(concat "#+date: %<%Y-%m-%dT%H:%M:%S>Z\n" "#+slug: ${slug}\n" "#+title: ${title}\n" "#+filetags: Post\n" "\n")) :unnarrowed t) ("i" "interview" plain "%?" :target (file+head "%<%Y%m%d%H%M%S>-${slug}.org" ,(concat "#+title: ${title}\n" "#+filetags: Interview\n" "\n")) :unnarrowed t) )) (setq org-roam-node-display-template (concat "${title:80} " (propertize "${tags:20}" 'face 'org-tag)) org-roam-node-annotation-function (lambda (node) (marginalia--time (org-roam-node-file-mtime node)))) (add-hook 'after-init-hook 'org-roam-setup) (defun roam-extra:get-filetags () (split-string (or (org-roam-get-keyword "filetags") ""))) (defun roam-extra:add-filetag (tag) (let* ((new-tags (cons tag (roam-extra:get-filetags))) (new-tags-str (combine-and-quote-strings new-tags))) (org-roam-set-keyword "filetags" new-tags-str))) (defun roam-extra:del-filetag (tag) (let* ((new-tags (seq-difference (roam-extra:get-filetags) `(,tag))) (new-tags-str (combine-and-quote-strings new-tags))) (org-roam-set-keyword "filetags" new-tags-str))) (defun roam-extra:todo-p () "Return non-nil if current buffer has any TODO entry. TODO entries marked as done are ignored, meaning the this function returns nil if current buffer contains only completed tasks." (org-element-map (org-element-parse-buffer 'headline) 'headline (lambda (h) (eq (org-element-property :todo-type h) 'todo)) nil 'first-match)) (defun roam-extra:update-todo-tag () "Update TODO tag in the current buffer." (when (and (not (active-minibuffer-window)) (org-roam-file-p)) (org-with-point-at 1 (let* ((tags (roam-extra:get-filetags)) (is-todo (roam-extra:todo-p))) (cond ((and is-todo (not (seq-contains-p tags "todo"))) (roam-extra:add-filetag "todo")) ((and (not is-todo) (seq-contains-p tags "todo")) (roam-extra:del-filetag "todo"))))))) (defun roam-extra:todo-files () "Return a list of roam files containing todo tag." (org-roam-db-sync) (let ((todo-nodes (seq-filter (lambda (n) (seq-contains-p (org-roam-node-tags n) "todo")) (org-roam-node-list)))) (seq-uniq (seq-map #'org-roam-node-file todo-nodes)))) (defun roam-extra:update-todo-files (&rest _) "Update the value of `org-agenda-files'." (setq org-agenda-files (roam-extra:todo-files))) (add-hook 'find-file-hook #'roam-extra:update-todo-tag) (add-hook 'before-save-hook #'roam-extra:update-todo-tag) (advice-add 'org-agenda :before #'roam-extra:update-todo-files) (defun org-roam-week (&optional other-window) "Opens or creates a weekly note." (interactive) (let* ((title (format-time-string "Week %U %Y")) (nodes (org-roam-node-list)) (node (seq-find (lambda (n) (string-equal (org-roam-node-title n) title)) nodes))) (if (and node (org-roam-node-file node)) (org-roam-node-visit node other-window) (org-roam-capture- :node (org-roam-node-create :title title) :templates `(("w" "week" plain "* Goals\n\n%?\n\n* Tasks\n\n" :if-new (file+head "%<%Y%m%d%H%M%S>-${slug}.org" "#+title: ${title}\n#+category: ${title}\n#+filetags: Week") :unnarrowed t)) :props '(:finalize find-file)) ) ) ) (global-set-key (kbd "C-c n w") 'org-roam-week) ;; -------- Org mode --------- (use-package org-modern) (with-eval-after-load 'org (global-org-modern-mode)) (setq org-modules '(org-w3m org-bbdb org-bibtex org-docview org-gnus org-info org-irc org-mhe org-rmail org-checklist org-mu4e)) ;; Sometimes I sit at night until 4 AM, and I still want org to treat it ;; as "today" (setq org-extend-today-until 4) ;; navigate with (org-goto) by offering the full list of targets in ido-mode (setq org-goto-interface 'outline-path-completion) ;; don't search incrementally (setq org-outline-path-complete-in-steps nil) ;; see whole path at once ;; avoid inadvertently editing hidden text (setq org-catch-invisible-edits 'show-and-error) ;; hide empty spaces between folded subtrees (setq org-cycle-separator-lines 0) ;; use hours in clocktable instead of days and hours (setq org-time-clocksum-format "%d:%02d") ;; After a recurring task is marked as done, reset it to TODO. This ;; is important because I have the "INBOX" state first in the sequence ;; of states. (setq org-todo-repeat-to-state "TODO") ;; Default format for column view (setq org-columns-default-format "%38ITEM(Details) %TAGS(Context) %7TODO(To Do) %5Effort(Time){:} %6CLOCKSUM(Total){:}") ;; Better source code editing (setq org-src-fontify-natively t org-src-window-setup 'current-window org-src-strip-leading-and-trailing-blank-lines t org-src-preserve-indentation t org-src-tab-acts-natively t) ;; Default tags (setq org-tag-alist '((:startgroup . nil) ("WORK" . ?w) ("HOME" . ?h) (:endgroup . nil) ("PROJECT" . ?p) ("PHONE" . ?n) ("MEETING" . ?m) ("DOC" . ?d) ("GOOGLE" . ?g) ("QUICK" . ?q))) ;; Default todo sequence (setq org-todo-keywords '((sequence "INBOX(i)" "TODO(t)" "ERRAND(k)" "SOMEDAY(s)" "WAITING(w@/!)" "APPT(a)" "|" "DONE(d!)" "CANCELLED(c!)"))) ;; Babel and code block embedding (setq org-confirm-babel-evaluate nil) (org-babel-do-load-languages 'org-babel-load-languages '((emacs-lisp . t) (python . t))) ;; Log TODO state changes and clock-ins into the LOGBOOK drawer (setq org-clock-into-drawer t) (setq org-log-into-drawer t) ;; Quickly creating new tasks (global-set-key (kbd "\C-c r") 'org-capture) (setq org-capture-templates `(("t" "Todo" entry (file+headline "~/org/gtd.org" "Tasks") "* TODO %?\n %U\n %a") ("i" "Inbox" entry (file+headline "~/org/gtd.org" "Tasks") "* INBOX %?\n %U") ("f" "Follow-up" entry (file+headline "~/org/gtd.org" "Tasks") ,(concat "* TODO %? :EMAIL:\n" " %U\n" " %a")) ("c" "Contacts" entry (file "~/org/contacts.org") (concat "* %(org-contacts-template-name)\n" ":PROPERTIES:\n" ":EMAIL: %(org-contacts-template-email)\n" ":END:")) ("q" "Org capture template" entry (file+headline "~/org/capture.org" "Notes") "* %:description\n\n Source: %u, %:link\n\n %i" :empty-lines 1) ) ) ;; org-protocol allows you to capture stuff into your system from web ;; browsers (require 'org-protocol) ;; Refiling allows you to quickly move an element with its children to ;; another location. ;; By default, refile works up to 2-level sections, which is not very ;; convenient if you have project-based organization ;; (/Projects/ProjectName). (setq org-refile-targets '((org-agenda-files :maxlevel . 3))) ;; Then, it's nice to have a full path to the target element appear in ;; completion (setq org-refile-use-outline-path 'file) ;; But, when using helm, we also need to tell org mode to present the ;; whole list of possible completions right away, and not use ;; incremental search: (setq org-outline-path-complete-in-steps nil) ;; It may also be useful to be able to create elements, if the refile ;; target doesn't already exist. (setq org-refile-allow-creating-parent-nodes 'confirm) ;; Agenda (global-set-key "\C-ca" 'org-agenda) (setq org-agenda-files '("~/org/gtd.org" "~/org/weeklyreview.org" )) (setq org-agenda-custom-commands nil) (add-to-list 'org-agenda-custom-commands '("h" "Work todos" tags-todo "-personal-doat={.+}-dowith={.+}/!-ERRAND" ((org-agenda-todo-ignore-scheduled t)))) (add-to-list 'org-agenda-custom-commands '("H" "All work todos" tags-todo "-personal/!-ERRAND-MAYBE" ((org-agenda-todo-ignore-scheduled nil)))) (add-to-list 'org-agenda-custom-commands '("A" "Work todos with doat or dowith" tags-todo "-personal+doat={.+}|dowith={.+}/!-ERRAND" ((org-agenda-todo-ignore-scheduled nil)))) (add-to-list 'org-agenda-custom-commands '("P" "Projects" tags "+PROJECT-TODO=\"SOMEDAY\"")) (add-to-list 'org-agenda-custom-commands '("i" "Inbox" todo "INBOX")) (add-to-list 'org-agenda-custom-commands '("o" "Someday" todo "SOMEDAY")) (add-to-list 'org-agenda-custom-commands '("c" "Simple agenda view" ( (agenda "" ) (todo "" ( (org-agenda-overriding-header "\nUnscheduled TODO") (org-agenda-skip-function '(org-agenda-skip-entry-if 'timestamp 'todo '("SOMEDAY" "ERRAND"))) (org-agenda-sorting-strategy (quote ((agenda time-up priority-down tag-up)))) )) ) ((org-agenda-overriding-columns-format "%38ITEM(Details) %TAGS(Context) %7TODO(To Do) %5Effort(Time){:} %6CLOCKSUM_T(Total){:}") (org-agenda-view-columns-initially t)) ) ) (setq org-todo-keyword-faces '(("ERRAND" . (:foreground "light sea green" :weight bold)) ("INBOX" . (:foreground "DarkGoldenrod" :weight bold)))) ;;(set-face-foreground 'org-scheduled-previously "DarkGoldenrod") (setq org-tags-exclude-from-inheritance '("PROJECT") org-stuck-projects '("+PROJECT/-MAYBE-DONE-SOMEDAY" ("TODO" "ERRAND" "WAITING") () ())) ;; -------- Email -------- ;;(use-package mu4e) ;;(add-to-list 'load-path "/usr/share/emacs/site-lisp/mu4e") (setq sendmail-program (executable-find "msmtp")) (autoload 'mu4e "mu4e" "\ If mu4e is not running yet, start it. Then, show the main window, unless BACKGROUND (prefix-argument) is non-nil. " t nil) (setq mu4e-update-interval 600) ;; refresh every X seconds (setq message-citation-line-format "On %d %b %Y at %R, %f wrote:\n") (setq message-citation-line-function 'message-insert-formatted-citation-line) (setq mu4e-attachment-dir "~/Downloads") (setq mu4e-html2text-command 'mu4e-shr2text) (setq mu4e-user-mail-address-list '("mail@knazarov.com" "k.nazarov@corp.mail.ru")) ;; exlude myself from the email replies (setq mu4e-compose-dont-reply-to-self t) ;; set mu4e as a default mail agent (setq mail-user-agent 'mu4e-user-agent) (setq mu4e-maildir "/home/knazarov/Maildir") (setq mu4e-view-show-images t mu4e-image-max-width 800 mu4e-view-prefer-html t mu4e-change-filenames-when-moving t ;; prevent duplicate UIDs mu4e-get-mail-command "mbsync -a -q" mu4e-headers-include-related nil) (setq mu4e-sent-folder "/personal/Sent" mu4e-drafts-folder "/personal/Drafts" mu4e-trash-folder "/personal/Trash" mu4e-refile-folder "/personal/Archive" user-full-name "Konstantin Nazarov" user-mail-address "mail@knazarov.com" smtpmail-default-smtp-server "smtp.fastmail.com" smtpmail-local-domain "knazarov.com" smtpmail-smtp-server "smtp.fastmail.com" smtpmail-stream-type 'starttls smtpmail-smtp-service 587 message-send-mail-function 'message-send-mail-with-sendmail ;;message-sendmail-extra-arguments '("--read-envelope-from") ) (setq mu4e-compose-signature "<#part type=text/html>

Hello ! I am the html signature which can contains anything in html !

<#/part>" ) (defvar my-mu4e-account-alist `(("personal" (mu4e-sent-folder "/personal/Sent") (mu4e-drafts-folder "/personal/Drafts") (mu4e-trash-folder "/personal/Trash") (mu4e-refile-folder "/personal/Archive") (user-mail-address "mail@knazarov.com") (message-sendmail-envelope-from "mail@knazarov.com") ;;(mu4e-compose-signature-auto-include nil) (mu4e-compose-signature ,(if (file-exists-p "~/.mail-sig.txt") (with-temp-buffer (insert-file-contents "~/.mail-sig.txt") (buffer-string)) "")) (message-signature-file "~/.mail-sig.txt") (message-cite-reply-position above) (message-cite-style message-cite-style-outlook)) ("work" (mu4e-sent-folder "/work/Sent") (mu4e-drafts-folder "/work/Drafts") (mu4e-trash-folder "/work/Trash") (mu4e-refile-folder "/work/Archive") (user-mail-address "k.nazarov@corp.mail.ru") (message-sendmail-envelope-from "k.nazarov@corp.mail.ru") (mu4e-compose-signature-auto-include nil) (message-signature-file "~/.mail-sig.txt") (mu4e-compose-signature ,(if (file-exists-p "~/.mail-sig.txt") (with-temp-buffer (insert-file-contents "~/.mail-sig.txt") (buffer-string)) "")) (message-cite-reply-position above) (message-cite-style message-cite-style-outlook)) )) (defun my-mu4e-set-account () "Set the account for composing a message." (let* ((account (if mu4e-compose-parent-message (let ((maildir (mu4e-message-field mu4e-compose-parent-message :maildir))) (string-match "/\\(.*?\\)/" maildir) (match-string 1 maildir)) (completing-read (format "Compose with account: (%s) " (mapconcat #'(lambda (var) (car var)) my-mu4e-account-alist "/")) (mapcar #'(lambda (var) (car var)) my-mu4e-account-alist) nil t nil nil (caar my-mu4e-account-alist)))) (account-vars (cdr (assoc account my-mu4e-account-alist)))) (if account-vars (mapc #'(lambda (var) (set (car var) (cadr var))) account-vars) (error "No email account found")))) (defun my-mu4e-refile-folder-function (msg) (let ((mu4e-accounts my-mu4e-account-alist) (current-message msg) (account)) (setq account (catch 'found (dolist (candidate mu4e-accounts) (if (string-match (car candidate) (mu4e-message-field current-message :maildir)) (throw 'found candidate) )))) (if account (cadr (assoc 'mu4e-refile-folder account)) (throw 'account_not_found (mu4e-message-field current-message :maildir)) ) ) ) (setq mu4e-refile-folder 'my-mu4e-refile-folder-function) (add-hook 'mu4e-compose-pre-hook 'my-mu4e-set-account) ;; Be smart about inserting signature for either cite-reply-position used (defun insert-signature () "Insert signature where you are replying" ;; Do not insert if already done - needed when switching modes back/forth (unless (save-excursion (message-goto-signature)) (save-excursion (if (eq message-cite-reply-position 'below) (goto-char (point-max)) (message-goto-body)) (insert-file-contents message-signature-file) (save-excursion (insert "\n-- \n"))))) (add-hook 'mu4e-compose-mode-hook 'insert-signature) ;;(add-to-list 'mu4e-bookmarks ;; '("maildir:/work/INBOX" "work inbox" ?w)) ;;(add-to-list 'mu4e-bookmarks ;; '("maildir:/knazarov/INBOX" "personal inbox" ?p)) (setq mu4e-bookmarks '(("maildir:/personal/INBOX OR maildir:/work/INBOX" "inbox" ?i))) ;; -------- Programming -------- ;; Enable direnv-mode to automatically load Nix flake dependencies for projects (use-package direnv :config (direnv-mode)) ;; Rainbow delimeters highlight matching pairs of braces in different colors (use-package rainbow-delimiters) (add-hook 'prog-mode-hook #'rainbow-delimiters-mode) ;; Flycheck is an on-the-fly syntax checker for emacs with pluggable backengs. (use-package flycheck) ;; Not usable for every single mode, so need to be selective ;;(add-hook 'prog-mode-hook #'flycheck-mode) ;; Scroll compilation buffer with the output (setq compilation-scroll-output t) ;; Projectile auto-detects projects and allows to run project-wide commands (use-package projectile) (setq projectile-cache-file "~/.emacs.d/projectile.cache") (projectile-mode +1) (define-key projectile-mode-map (kbd "C-c p") 'projectile-command-map) ;; Corfu mode is a simple auto completion framework with ;; pluggable backends ;;(setq company-backends '(company-capf (company-dabbrev-code) company-dabbrev)) ;;(add-hook 'prog-mode-hook #'company-mode) ;;(add-hook 'mu4e-compose-mode-hook #'company-mode) (use-package corfu) (add-hook 'after-init-hook 'global-corfu-mode) (add-hook 'after-init-hook 'corfu-popupinfo-mode) (setq corfu-auto t) (setq tab-always-indent 'complete) (setq corfu-quit-no-match 'separator) (use-package cape) (add-to-list 'completion-at-point-functions #'cape-dabbrev) (add-to-list 'completion-at-point-functions #'cape-file) ;; Can't live without magit. It makes working with git sooo much easie (use-package magit) (global-set-key (kbd "C-x g") 'magit-status) ;;(setq magit-completing-read-function 'magit-ido-completing-read) ;; LSP ;; Maybe switch to EGLOT, which is shipped in Emacs 29 (add-hook 'lua-mode-hook #'lsp) ;; Tree-sitter (setq major-mode-remap-alist '((yaml-mode . yaml-ts-mode) (bash-mode . bash-ts-mode) (js2-mode . js-ts-mode) (typescript-mode . typescript-ts-mode) (json-mode . json-ts-mode) (css-mode . css-ts-mode) (python-mode . python-ts-mode) (cpp-mode . cpp-ts-mode) (c-mode . c-ts-mode) )) (setq treesit-font-lock-level 4) ;; vterm ;; Vterm is a fully featured terminal emulator, that works inside ;; emacs buffers. It is miles ahead of "term" and "eshell" both in ;; speed and features. (setq vterm-always-compile-module t) (use-package vterm) ;;(add-to-list 'load-path (expand-file-name "~/dev/emacs-libvterm/")) (defun vterm-less (content) (let ((less-buffer (get-buffer-create (make-temp-name "vterm-less-")))) (with-current-buffer less-buffer (switch-to-buffer less-buffer) (special-mode) (insert (base64-decode-string content))) ) ) (use-package with-editor) (defun my-vterm-mode-hook () (add-to-list 'vterm-eval-cmds (list "less" #'vterm-less)) (with-editor-export-editor) ) (add-hook 'vterm-mode-hook #'my-vterm-mode-hook) (put 'upcase-region 'disabled nil) (autoload 'vterm "vterm" "\ If vterm is not running yet, start it. Then, show the main window, unless BACKGROUND (prefix-argument) is non-nil. " t nil) ;; lua (use-package lua-mode) (setq lua-indent-level 4) ;; common lisp (use-package sly) (use-package sly-asdf) (use-package aggressive-indent) (add-to-list 'sly-contribs 'sly-asdf 'append) (autoload 'sly "sly" "Start an inferior^_superior Lisp and connect to its Swank server." t nil) (define-key lisp-mode-map (kbd "C-c v") 'sly-asdf-test-system) ;autoload 'sly-lisp-mode-hook "sly" ; "Set up sly for a lisp buffer." ; t nil) (add-hook 'lisp-mode-hook #'aggressive-indent-mode) ;(add-hook 'lisp-mode-hook 'sly-lisp-mode-hook) ;(setq slime-contribs '(slime-fancy slime-company)) (setq inferior-lisp-program "sbcl") ;; Markdown (use-package markdown-mode) ;; Dockerfiles (use-package dockerfile-mode) ;; Yaml (use-package yaml-mode) ;; CMake (use-package cmake-mode) ;; C/C++ (with-eval-after-load 'eglot (add-to-list 'eglot-server-programs `(c++-mode . ("clangd"))) (add-to-list 'eglot-server-programs `(c++-ts-mode . ("clangd"))) (add-to-list 'eglot-server-programs `(c-ts-mode . ("clangd")) )) (add-hook 'c++-mode-hook 'eglot-ensure) (add-hook 'c++-ts-mode-hook 'eglot-ensure) (add-hook 'c-ts-mode-hook 'eglot-ensure) (use-package clang-format) (use-package clang-format+) (add-hook 'c-mode-hook 'clang-format+-mode) (add-hook 'c-ts-mode-hook 'clang-format+-mode) (add-hook 'c++-mode-hook 'clang-format+-mode) (setq clang-format+-context 'buffer) ;; Zig (use-package zig-mode) ;; Terraform (use-package terraform-mode) ;; Nix (use-package nix-mode) (use-package sudo-edit) (global-set-key (kbd "C-c C-r") 'sudo-edit) (provide 'init) ;;; init.el ends here