60 KiB
Emacs configuration file
- TODOS
- Header
- First start
- Default settings
- use-package keywords general / diminish
- sane defaults
- Performance Optimization
- Appearance
- Bookmarks
- recentf
- savehist
- undo
- COMMENT ace-window (now avy)
- which-key
- abbrev
- imenu-list
- COMMENT Evil
- Eldoc
- COMMENT Eldoc Box
- Meow
- avy
- Vertico
- Corfu
- Cape
- kind-icon
- Orderless
- Consult
- Marginalia
- Embark
- Org-ql
- COMMENT Xeft (needs xapian, not really windows compatible)
- COMMENT Helm
- COMMENT ivy / counsel / swiper
- outlook
- misc
- COMMENT company (now corfu)
- orgmode
- Programming
- beancount
- Stuff after everything else
TODOS
-
early-init.el? What to outsource here?
-
Paket exec-path-from-shell, um PATH aus Linux auch in emacs zu haben
-
Smart mode line?
-
Theme
-
flymake instead of flycheck?
-
Hydra
-
General
-
(defalias 'list-buffers 'ibuffer) ;; change default to ibuffer
-
ido?
-
treemacs (for linux) windmove?
-
tramp (in linux)
-
visual-regexp
-
org configuration: paths
-
org custom agenda
-
org-ql (related to org agendas)
-
org configuration: everything else
-
beancount configuration from config.org
-
CONTINUE TODO from config.org at Programming
-
all-the-icons?
Header
Emacs variables are dynamically scoped. That's unusual for most languages, so disable it here, too
;;; init.el --- -*- lexical-binding: t -*-
First start
These functions updates config.el whenever changes in config.org are made. The update will be active after saving.
(defun my/tangle-config () "Export code blocks from the literate config file." (interactive) ;; prevent emacs from killing until tangle-process has finished (add-to-list 'kill-emacs-query-functions (lambda () (or (not (process-live-p (get-process "tangle-process"))) (y-or-n-p "\"my/tangle-config\" is running; kill it? ")))) (org-babel-tangle-file config-org init-el) (message "reloading user-init-file") (load-file init-el)) (add-hook 'org-mode-hook (lambda () (if (equal (buffer-file-name) config-org) (my--add-local-hook 'after-save-hook 'my/tangle-config)))) (defun my--add-local-hook (hook function) "Add buffer-local hook." (add-hook hook function :local t))
A small function to measure start up time. Compare that to emacs -q –eval='(message "%s" (emacs-init-time))' (roughly 0.27s) https://blog.d46.us/advanced-emacs-startup/
(add-hook 'emacs-startup-hook (lambda () (message "Emacs ready in %s with %d garbage collections." (format "%.2f seconds" (float-time (time-subtract after-init-time before-init-time))) gcs-done))) ;(setq gc-cons-threshold (* 50 1000 1000))
Default settings
paths
(defconst *sys/gui* (display-graphic-p) "Is emacs running in a gui?") (defconst *sys/linux* (string-equal system-type 'gnu/linux) "Is the system running Linux?") (defconst *sys/windows* (string-equal system-type 'windows-nt) "Is the system running Windows?") (defconst *home_desktop* (string-equal (system-name) "marc") "Is emacs running on my desktop?") (defconst *home_laptop* (string-equal (system-name) "laptop") "Is emacs running on my laptop?") (defconst *work_local* (string-equal (system-name) "PMPCNEU08") "Is emacs running at work on the local system?") (defconst *work_remote* (or (string-equal (system-name) "PMTS01") (string-equal (system-name) "PMTSNEU01")) "Is emacs running at work on the remote system?")
(defvar MY--PATH_USER_LOCAL (concat user-emacs-directory "user-local/")) (defvar MY--PATH_USER_GLOBAL (concat user-emacs-directory "user-global/")) (add-to-list 'custom-theme-load-path (concat MY--PATH_USER_GLOBAL "themes")) (when *sys/linux* (defconst MY--PATH_ORG_FILES (expand-file-name "~/Archiv/Organisieren/")) (defconst MY--PATH_ORG_FILES_MOBILE (expand-file-name "~/Archiv/Organisieren/mobile/")) (defconst MY--PATH_ORG_JOURNAl (expand-file-name "~/Archiv/Organisieren/Journal/")) (defconst MY--PATH_ORG_ROAM (file-truename "~/Archiv/Organisieren/"))) (when *work_remote* (defconst MY--PATH_ORG_FILES "p:/Eigene Dateien/Notizen/") (defconst MY--PATH_ORG_FILES_MOBILE nil) ;; hacky way to prevent "free variable" compiler error (defconst MY--PATH_ORG_JOURNAL nil) ;; hacky way to prevent "free variable" compiler error (defconst MY--PATH_START "p:/Eigene Dateien/Notizen/") (defconst MY--PATH_ORG_ROAM (expand-file-name "p:/Eigene Dateien/Notizen/"))) (setq custom-file (concat MY--PATH_USER_LOCAL "custom.el")) ;; don't spam init.e with saved customization settings (setq backup-directory-alist `((".*" . ,temporary-file-directory))) (setq auto-save-file-name-transforms `((".*" ,temporary-file-directory))) (customize-set-variable 'auth-sources (list (concat MY--PATH_USER_LOCAL "authinfo") (concat MY--PATH_USER_LOCAL "authinfo.gpg") (concat MY--PATH_USER_LOCAL "netrc")))
Browser
(setq browse-url-function 'browse-url-generic browse-url-generic-program "firefox")
Elpaca
Boilerplate for Elpaca
(defvar elpaca-installer-version 0.6) (defvar elpaca-directory (expand-file-name "elpaca/" user-emacs-directory)) (defvar elpaca-builds-directory (expand-file-name "builds/" elpaca-directory)) (defvar elpaca-repos-directory (expand-file-name "repos/" elpaca-directory)) (defvar elpaca-order '(elpaca :repo "https://github.com/progfolio/elpaca.git" :ref nil :files (:defaults "elpaca-test.el" (:exclude "extensions")) :build (:not elpaca--activate-package))) (let* ((repo (expand-file-name "elpaca/" elpaca-repos-directory)) (build (expand-file-name "elpaca/" elpaca-builds-directory)) (order (cdr elpaca-order)) (default-directory repo)) (add-to-list 'load-path (if (file-exists-p build) build repo)) (unless (file-exists-p repo) (make-directory repo t) (when (< emacs-major-version 28) (require 'subr-x)) (condition-case-unless-debug err (if-let ((buffer (pop-to-buffer-same-window "*elpaca-bootstrap*")) ((zerop (call-process "git" nil buffer t "clone" (plist-get order :repo) repo))) ((zerop (call-process "git" nil buffer t "checkout" (or (plist-get order :ref) "--")))) (emacs (concat invocation-directory invocation-name)) ((zerop (call-process emacs nil buffer nil "-Q" "-L" "." "--batch" "--eval" "(byte-recompile-directory \".\" 0 'force)"))) ((require 'elpaca)) ((elpaca-generate-autoloads "elpaca" repo))) (progn (message "%s" (buffer-string)) (kill-buffer buffer)) (error "%s" (with-current-buffer buffer (buffer-string)))) ((error) (warn "%s" err) (delete-directory repo 'recursive)))) (unless (require 'elpaca-autoloads nil t) (require 'elpaca) (elpaca-generate-autoloads "elpaca" repo) (load "./elpaca-autoloads"))) (add-hook 'after-init-hook #'elpaca-process-queues) (elpaca `(,@elpaca-order))
For Windows it might be necessary to disable symlink creations
(when *work_remote* (elpaca-no-symlink-mode))
use-package integration
(elpaca elpaca-use-package ;; enable :elpaca use-package keyword (elpaca-use-package-mode) ;; assume :elpaca t unless otherwise specified (setq elpaca-use-package-by-default t)) ;; block until current queue processed. (elpaca-wait)
(defun +elpaca-unload-seq (e) (and (featurep 'seq) (unload-feature 'seq t)) (elpaca--continue-build e)) ;; You could embed this code directly in the reicpe, I just abstracted it into a function. (defun +elpaca-seq-build-steps () (append (butlast (if (file-exists-p (expand-file-name "seq" elpaca-builds-directory)) elpaca--pre-built-steps elpaca-build-steps)) (list '+elpaca-unload-seq 'elpaca--activate-package))) ;;(elpaca `(seq :build ,(+elpaca-seq-build-steps))) (use-package seq :elpaca `(seq :build ,(+elpaca-seq-build-steps)))
COMMENT Rest of the stuff
(require 'package) (add-to-list 'package-archives '("elpa" . "https://elpa.gnu.org/packages/") t) (add-to-list 'package-archives '("melpa" . "https://melpa.org/packages/") t) (add-to-list 'package-archives '("melpa-stable" . "https://stable.melpa.org/packages/") t) (add-to-list 'package-archives '("nongnu" . "https://elpa.nongnu.org/nongnu/") t) ; fix for bug 34341 (setq gnutls-algorithm-priority "NORMAL:-VERS-TLS1.3") (when (< emacs-major-version 27) (package-initialize))
(unless (package-installed-p 'use-package) (package-refresh-contents) (package-install 'use-package)) (eval-when-compile (setq use-package-enable-imenu-support t) (require 'use-package)) (require 'bind-key) (setq use-package-verbose t) (use-package diminish :ensure t)
cl is deprecated in favor for cl-lib, some packages like emmet still depend on cl. Shut off the compiler warning about it. Maybe turn it on again at some point before the next major emacs upgrade
(setq byte-compile-warnings '(cl-functions))
use-package keywords general / diminish
Needs to be loaded before any other package which uses the :general keyword
(use-package general :ensure t :demand t) (use-package diminish :ensure t :demand t) (elpaca-wait)
sane defaults
(setq-default create-lockfiles nil) ;; disable lock files, can cause trouble in e.g. lsp-mode (defalias 'yes-or-no-p 'y-or-n-p) ;; answer with y and n (setq custom-safe-themes t) ;; don't ask me if I want to load a theme (setq sentence-end-double-space nil) ;; don't coun two spaces after a period as the end of a sentence. (delete-selection-mode t) ;; delete selected region when typing (use-package saveplace :elpaca nil :config (save-place-mode 1) ;; saves position in file when it's closed :custom (save-place-file (concat MY--PATH_USER_LOCAL "places"))) (setq save-place-forget-unreadable-files nil) ;; checks if file is readable before saving position (global-set-key (kbd "RET") 'newline-and-indent) ;; indent after newline (setq save-interprogram-paste-before-kill t) ;; put replaced text into killring ;; https://emacs.stackexchange.com/questions/3673/how-to-make-vc-and-magit-treat-a-symbolic-link-to-a-real-file-in-git-repo-just (setq find-file-visit-truename t) ;; some programs like lsp have trouble following symlinks, maybe vc-follow-symlinks would be enough
Performance Optimization
Garbage Collection
Make startup faster by reducing the frequency of garbage collection. Set gc-cons-threshold (default is 800kb) to maximum value available, to prevent any garbage collection from happening during load time.
(setq gc-cons-threshold most-positive-fixnum)
Restore it to reasonable value after init. Also stop garbage collection during minibuffer interaction (helm etc.)
(defconst 1mb 1048576) (defconst 20mb 20971520) (defconst 30mb 31457280) (defconst 50mb 52428800) (defun my--defer-garbage-collection () (setq gc-cons-threshold most-positive-fixnum)) (defun my--restore-garbage-collection () (run-at-time 1 nil (lambda () (setq gc-cons-threshold 30mb)))) (add-hook 'emacs-startup-hook 'my--restore-garbage-collection 100) (add-hook 'minibuffer-setup-hook 'my--defer-garbage-collection) (add-hook 'minibuffer-exit-hook 'my--restore-garbage-collection) (setq read-process-output-max 1mb) ;; lsp-mode's performance suggest
File Handler
(defvar default-file-name-handler-alist file-name-handler-alist) (setq file-name-handler-alist nil) (add-hook 'emacs-startup-hook (lambda () (setq file-name-handler-alist default-file-name-handler-alist)) 100)
Others
;; Resizing the emacs frame can be a terriblu expensive part of changing the font. ;; By inhibiting this, we easily hale startup times with fonts that are larger ;; than the system default. (setq frame-inhibit-implied-resize t)
Appearance
Defaults
(set-charset-priority 'unicode) (setq-default locale-coding-system 'utf-8 default-process-coding-system '(utf-8-unix . utf-8-unix)) (set-terminal-coding-system 'utf-8) (set-keyboard-coding-system 'utf-8) (set-selection-coding-system 'utf-8) (if *sys/windows* (prefer-coding-system 'utf-8-dos) (prefer-coding-system 'utf-8)) (setq-default bidi-paragraph-direction 'left-to-right bidi-inhibit-bpa t ;; both settings reduce line rescans uniquify-buffer-name-style 'forward indent-tabs-mode nil ;; avoid tabs in place of multiple spaces (they look bad in tex) indicate-empty-lines t ;; show empty lines scroll-margin 5 ;; smooth scrolling scroll-conservatively 10000 scroll-preserve-screen-position 1 scroll-step 1 ring-bell-function 'ignore ;; disable pc speaker bell visible-bell t) (global-hl-line-mode t) ;; highlight current line (blink-cursor-mode -1) ;; turn off blinking cursor (column-number-mode t)
Remove redundant UI
(menu-bar-mode -1) ;; disable menu bar (tool-bar-mode -1) ;; disable tool bar (scroll-bar-mode -1) ;; disable scroll bar
Font
(when *sys/linux* (set-face-font 'default "Hack-10")) (when *work_remote* (set-face-font 'default "Lucida Sans Typewriter-11"))
Themes
(defun my/toggle-theme () (interactive) (when (or *sys/windows* *sys/linux*) (if (eq (car custom-enabled-themes) 'tango-dark) (progn (disable-theme 'tango-dark) (load-theme 'tango)) (progn (disable-theme 'tango) (load-theme 'tango-dark))))) (bind-key "C-c t" 'my/toggle-theme)
Windows Theme:
(when *sys/windows* (load-theme 'tango)) (when *sys/linux* (load-theme 'plastic))
line wrappings
(global-visual-line-mode) ;(diminish 'visual-line-mode) (use-package adaptive-wrap :ensure t :hook (visual-line-mode . adaptive-wrap-prefix-mode)) ; :init ; (when (fboundp 'adaptive-wrap-prefix-mode) ; (defun me/activate-adaptive-wrap-prefix-mode () ; "Toggle `visual-line-mode' and `adaptive-wrap-prefix-mode' simultaneously." ; (adaptive-wrap-prefix-mode (if visual-line-mode 1 -1))) ; (add-hook 'visual-line-mode-hook 'me/activate-adaptive-wrap-prefix-mode)))
line numbers
(use-package display-line-numbers :elpaca nil :init :hook ((prog-mode org-src-mode) . display-line-numbers-mode) :config (setq-default display-line-numbers-type 'visual display-line-numbers-current-absolute t display-line-numbers-with 4 display-line-numbers-widen t))
misc
Delight can replace mode names with custom names , e.g. python-mode with just "π ".
(use-package rainbow-mode :ensure t :diminish :hook ((org-mode emacs-lisp-mode) . rainbow-mode)) (use-package delight :if *sys/linux* :ensure t) (show-paren-mode t) ;; show other part of brackets (setq blink-matching-paren nil) ;; not necessary with show-paren-mode, bugs out on C-s counsel-line (use-package rainbow-delimiters :ensure t :hook (prog-mode . rainbow-delimiters-mode))
Bookmarks
Usage:
-
C-x r m (bookmark-set): add bookmark
-
C-x r l (list-bookmark): list bookmarks
-
C-x r b (bookmark-jump): open bookmark
Edit bookmarks (while in bookmark file):
-
d: mark current item
-
x: delete marked items
-
r: rename current item
-
s: save changes
(use-package bookmark :elpaca nil :custom (bookmark-default-file (concat MY--PATH_USER_LOCAL "bookmarks")))
Some windows specific stuff
(when *sys/windows* (remove-hook 'find-file-hook 'vc-refresh-state) ; (progn ; (setq gc-cons-threshold (* 511 1024 1024) ; gc-cons-percentage 0.5 ; garbage-collection-messages t ; (run-with-idle-timer 5 t #'garbage-collect)) (when (boundp 'w32-pipe-read-delay) (setq w32-pipe-read-delay 0)) (when (boundp 'w32-get-true-file-attributes) (setq w32-get-true-file-attributes nil)))
recentf
Exclude some dirs from spamming recentf
(use-package recentf :elpaca nil ; :defer 1 :config (recentf-mode) :custom (recentf-exclude '(".*-autoloads\\.el\\'" "[/\\]\\elpa/" "COMMIT_EDITMSG\\'")) (recentf-save-file (concat MY--PATH_USER_LOCAL "recentf")) (recentf-max-menu-items 600) (recentf-max-saved-items 600))
savehist
(use-package savehist :elpaca nil :config (savehist-mode) :custom (savehist-file (concat MY--PATH_USER_LOCAL "history")))
undo
(use-package undo-tree :ensure t :diminish undo-tree-mode :init (global-undo-tree-mode 1) :custom (undo-tree-auto-save-history nil))
COMMENT ace-window (now avy)
(use-package ace-window :ensure t :bind (:map global-map ("C-x o" . ace-window)))
which-key
(use-package which-key :ensure t :diminish which-key-mode :defer t :hook (after-init . which-key-mode) :custom (which-key-idle-delay 0.5) (which-key-sort-order 'which-key-description-order) :config (which-key-setup-side-window-bottom))
abbrev
(use-package abbrev :elpaca nil :diminish abbrev-mode :hook ((text-mode org-mode) . abbrev-mode) :init (setq abbrev-file-name (concat MY--PATH_USER_GLOBAL "abbrev_tables.el")) :config (if (file-exists-p abbrev-file-name) (quietly-read-abbrev-file)) (setq save-abbrevs 'silently)) ;; don't bother me with asking for abbrev saving
imenu-list
A minor mode to show imenu in a sidebar. Call imenu-list-smart-toggle. Source
(use-package imenu-list :ensure t :demand t ; otherwise mode loads too late and won't work on first file it's being activated on :config (setq imenu-list-focus-after-activation t imenu-list-auto-resize t imenu-list-position 'right) :general ([f9] 'imenu-list-smart-toggle) (:states '(normal insert) :keymaps 'imenu-list-major-mode-map "RET" '(imenu-list-goto-entry :which-key "goto") "TAB" '(hs-toggle-hiding :which-key "collapse") "v" '(imenu-list-display-entry :which-key "show") ; also prevents visual mode "q" '(imenu-list-quit-window :which-key "quit")) :custom (org-imenu-depth 4))
COMMENT Evil
See also https://github.com/noctuid/evil-guide
Use C-z (evil-toggle-key) to switch between evil and emacs keybindings, in case evil is messing something up.
(use-package evil :ensure t :defer .1 :custom (evil-want-C-i-jump nil) ;; prevent evil from blocking TAB in org tree expanding (evil-want-integration t) (evil-want-keybinding nil) :config ;; example for using emacs default key map in a certain mode ;; (evil-set-initial-state 'dired-mode 'emacs) (evil-mode 1))
Eldoc
use builtin version
(use-package eldoc :elpaca nil :diminish eldoc-mode :defer t)
COMMENT Eldoc Box
Currently corfu-popupinfo displays eldoc in highlighted completion candidate. Maybe that's good enough.
(use-package eldoc-box :ensure t)
Meow
(use-package meow :ensure t :config (setq meow-cheatsheet-layout meow-cheatsheet-layout-qwerty) (meow-motion-overwrite-define-key '("j" . meow-next) '("k" . meow-prev) '("<escape>" . ignore)) (meow-leader-define-key ;; SPC j/k will run the original command in MOTION state. '("j" . "H-j") '("k" . "H-k") ;; Use SPC (0-9) for digit arguments. '("1" . meow-digit-argument) '("2" . meow-digit-argument) '("3" . meow-digit-argument) '("4" . meow-digit-argument) '("5" . meow-digit-argument) '("6" . meow-digit-argument) '("7" . meow-digit-argument) '("8" . meow-digit-argument) '("9" . meow-digit-argument) '("0" . meow-digit-argument) '("/" . meow-keypad-describe-key) '("?" . meow-cheatsheet)) (meow-normal-define-key '("0" . meow-expand-0) '("9" . meow-expand-9) '("8" . meow-expand-8) '("7" . meow-expand-7) '("6" . meow-expand-6) '("5" . meow-expand-5) '("4" . meow-expand-4) '("3" . meow-expand-3) '("2" . meow-expand-2) '("1" . meow-expand-1) '("-" . negative-argument) '(";" . meow-reverse) '("," . meow-inner-of-thing) '("." . meow-bounds-of-thing) '("[" . meow-beginning-of-thing) '("]" . meow-end-of-thing) '("a" . meow-append) '("A" . meow-open-below) '("b" . meow-back-word) '("B" . meow-back-symbol) '("c" . meow-change) '("d" . meow-delete) '("D" . meow-backward-delete) '("e" . meow-next-word) '("E" . meow-next-symbol) '("f" . meow-find) '("g" . meow-cancel-selection) '("G" . meow-grab) '("h" . meow-left) '("H" . meow-left-expand) '("i" . meow-insert) '("I" . meow-open-above) '("j" . meow-next) '("J" . meow-next-expand) '("k" . meow-prev) '("K" . meow-prev-expand) '("l" . meow-right) '("L" . meow-right-expand) '("m" . meow-join) '("n" . meow-search) '("o" . meow-block) '("O" . meow-to-block) '("p" . meow-yank) '("q" . meow-quit) '("Q" . meow-goto-line) '("r" . meow-replace) '("R" . meow-swap-grab) '("s" . meow-kill) '("t" . meow-till) '("u" . meow-undo) '("U" . meow-undo-in-selection) '("v" . meow-visit) '("w" . meow-mark-word) '("W" . meow-mark-symbol) '("x" . meow-line) '("X" . meow-goto-line) '("y" . meow-save) '("Y" . meow-sync-grab) '("z" . meow-pop-selection) '("'" . repeat) '("<escape>" . ignore)) ; :config (meow-global-mode t))
avy
Search, move, copy, delete text within all visible buffers. Also replaces ace-window for buffer switching. https://github.com/abo-abo/avy
(use-package avy :ensure t :general (:prefix "M-s" "" '(:ignore t :which-key "avy") "w" '(avy-goto-char-2 :which-key "avy-jump") "c" '(:ignore t :which-key "avy copy") "c l" '(avy-copy-line :which-key "avy copy line") "c r" '(avy-copy-region :which-key "avy copy region") "m" '(:ignore t :which-key "avy move") "m l" '(avy-move-line :which-key "avy move line") "m r" '(avy-move-region :which-key "avy move region")))
Vertico
Vertico is a completion ui for the minibuffer and replaced selectrum. Vertico Github
;; completion ui (use-package vertico :ensure t :init (vertico-mode))
Corfu
Completion ui, replaces company. Corfu Github
(use-package corfu :ensure t :after savehist :custom (corfu-popupinfo-delay t) (corfu-auto t) (corfu-cycle t) (corfu-auto-delay 0.3) (corfu-preselect-first nil) (corfu-popupinfo-delay '(1.0 . 0.0)) ;1s for first popup, instant for subsequent popups (corfu-popupinfo-max-width 70) (corfu-popupinfo-max-height 20) :init (global-corfu-mode) ; (corfu-popupinfo-mode) ; causes corfu window to stay (corfu-history-mode) ;; belongs to emacs (add-to-list 'savehist-additional-variables 'corfu-history) :hook (corfu-mode . corfu-popupinfo-mode)) ; :bind ; (:map corfu-map ; ("TAB" . corfu-next) ; ("<C-return>" . corfu-insert) ; ("C-TAB" . corfu-popupinfo-toggle))) ;; (general-define-key ;; :states 'insert ;; :definer 'minor-mode ;; :keymaps 'completion-in-region-mode ;; :predicate 'corfu-mode ;; "C-d" 'corfu-info-documentation) (use-package emacs :elpaca nil :init ;; hide commands in M-x which do not apply to current mode (setq read-extended-command-predicate #'command-completion-default-include-p) ;; enable indentation + completion using TAB (setq tab-always-indent 'complete))
Cape
Adds completions for corfu Cape Github
Available functions: dabbrev, file, history, keyword, tex, sgml, rfc1345, abbrev, ispell, dict, symbol, line
(use-package cape :ensure t :bind (("C-c p p" . completion-at-point) ;; capf ("C-c p t" . complete-tag) ;; etags ("C-c p d" . cape-dabbrev) ("C-c p h" . cape-history) ("C-c p f" . cape-file)) :init (advice-add #'lsp-completion-at-point :around #'cape-wrap-noninterruptible) ;; for performance issues with lsp (add-to-list 'completion-at-point-functions #'cape-dabbrev) (add-to-list 'completion-at-point-functions #'cape-file) (add-to-list 'completion-at-point-functions #'cape-history))
kind-icon
Make corfu pretty kind-icon Github
(use-package kind-icon :ensure t :after corfu :custom (kind-icon-default-face 'corfu-default) ;; to compute blended backgrounds correctly :config (add-to-list 'corfu-margin-formatters #'kind-icon-margin-formatter))
Orderless
Orderless Github Orderless orders the suggestions by recency. The package prescient orders by frequency.
(use-package orderless :ensure t :init (setq completion-styles '(orderless partial-completion basic) completion-category-defaults nil completion-category-overrides nil)) ; completion-category-overrides '((file (styles partial-completion)))))
Consult
(use-package consult :ensure t :bind (("C-x C-r" . consult-recent-file) ("C-x b" . consult-buffer) ("C-s" . consult-line)) :config ;; disable preview for some commands and buffers ;; and enable it by M-. ;; see https://github.com/minad/consult#use-package-example (consult-customize consult-theme :preview-key '(debounce 0.2 any) consult-ripgrep consult-git-grep consult-grep consult-bookmark consult-recent-file consult-xref consult--source-bookmark consult--source-file-register consult--source-recent-file consult--source-project-recent-file :preview-key "M-."))
Marginalia
Github Adds additional information to the minibuffer
(use-package marginalia :ensure t :init (marginalia-mode) :bind (:map minibuffer-local-map ("M-A" . marginalia-cycle)) :custom ;; switch by 'marginalia-cycle (marginalia-annotators '(marginalia-annotators-heavy marginalia-annotators-light nil)))
Embark
Does stuff in the minibuffer results
(use-package embark :ensure t :bind (("C-S-a" . embark-act) ("C-h B" . embark-bindings)) :init (setq prefix-help-command #'embark-prefix-help-command) :config ;; hide modeline of the embark live/completions buffers (add-to-list 'display-buffer-alist '("\\`\\*Embark Collect \\(Live\\|Completions\\)\\*" nil (window-parameters (mode-line-format . none))))) (use-package embark-consult :ensure t :after (embark consult) :demand t :hook (embark-collect-mode . embark-consult-preview-minor-mode))
Org-ql
org-ql Run queries on org files
(use-package org-ql :ensure t )
COMMENT Xeft (needs xapian, not really windows compatible)
Fast full text search for stuff org-ql cannot cover
(use-package xeft :ensure t :custom (xeft-recursive 'follow-symlinks))
COMMENT Helm
As an alternative if I'm not happy with selectrum & co
(use-package helm :ensure t :hook (helm-mode . helm-autoresize-mode) ;; :bind ;; (("M-x" . helm-M-x) ;; ("C-s" . helm-occur) ;; ("C-x C-f" . helm-find-files) ;; ("C-x C-b" . helm-buffers-list) ;; ("C-x b" . helm-buffers-list) ;; ("C-x C-r" . helm-recentf) ;; ("C-x C-i" . helm-imenu)) :config (helm-mode) :custom (helm-split-window-inside-p t) ;; open helm buffer inside current window (helm-move-to-line-cycle-in-source t) (helm-echo-input-in-header-line t) (helm-autoresize-max-height 20) (helm-autoresize-min-height 5) )
COMMENT ivy / counsel / swiper
; (require 'ivy) (use-package ivy :ensure t :diminish (ivy-mode . "") :defer t :init (ivy-mode 1) :bind ("C-r" . ivy-resume) ;; overrides isearch-backwards binding :config (setq ivy-use-virtual-buffers t ;; recent files and bookmarks in ivy-switch-buffer ivy-height 20 ;; height of ivy window ivy-count-format "%d/%d" ;; current and total number ivy-re-builders-alist ;; regex replaces spaces with * '((t . ivy--regex-plus)))) ; make counsel-M-x more descriptive (use-package ivy-rich :ensure t :defer t :init (ivy-rich-mode 1)) (use-package counsel :ensure t :defer t :bind (("M-x" . counsel-M-x) ("C-x C-f" . counsel-find-file) ("C-x C-r" . counsel-recentf) ("C-x b" . counsel-switch-buffer) ("C-c C-f" . counsel-git) ("C-c h f" . counsel-describe-function) ("C-c h v" . counsel-describe-variable) ("M-i" . counsel-imenu))) ; :map minibuffer-local-map ;;currently mapped to evil-redo ; ("C-r" . 'counsel-minibuffer-history))) (use-package swiper :ensure t :bind ("C-s" . swiper)) (use-package ivy-hydra :ensure t)
outlook
In outlook a macro is necessary, also a reference to FM20.DLL (Microsoft Forms 2.0 Object Library, in c:\windows\syswow64\fm20.dll) The macro copies the GUID of the email to the clipboard Attention: the GUID changes when the email is moved to another folder!
The macro:
Sub AddLinkToMessageInClipboard() 'Adds a link to the currently selected message to the clipboard Dim objMail As Outlook.MailItem Dim doClipboard As New DataObject 'One and ONLY one message muse be selected If Application.ActiveExplorer.Selection.Count <> 1 Then MsgBox ("Select one and ONLY one message.") Exit Sub End If Set objMail = Application.ActiveExplorer.Selection.Item(1) doClipboard.SetText "[[outlook:" + objMail.EntryID + "][MESSAGE: " + objMail.Subject + " (" + objMail.SenderName + ")]]" doClipboard.PutInClipboard End Sub
;(org-add-link-type "outlook" 'my--org-outlook-open) (defun my--org-outlook-open (id) (w32-shell-execute "open" "outlook" (concat " /select outlook:" id))) (defun my/org-outlook-open-test () (interactive) (w32-shell-execute "open" "outlook" " /select outlook:000000008A209C397CEF2C4FBA9E54AEB5B1F97F0700846D043B407C5B43A0C05AFC46DC5C630587BE5E020900006E48FF8F6027694BA6593777F542C19E0002A6434D000000"))'
misc
(use-package autorevert :diminish auto-revert-mode)
COMMENT company (now corfu)
(use-package company :defer 1 :diminish :defer t :bind (("C-<tab>" . company-complete) :map company-active-map ("RET" . nil) ([return] . nil) ("TAB" . company-complete-selection) ([tab] . company-complete-selection) ("<right>" . company-complete-common) ("<escape>" . company-abort)) :hook (after-init . global-company-mode) (emacs-lisp-mode . my--company-elisp) (org-mode . my--company-org) :config (defun my--company-elisp () (message "set up company for elisp") (set (make-local-variable 'company-backends) '(company-capf ;; capf needs to be before yasnippet, or lsp fucks up completion for elisp company-yasnippet company-dabbrev-code company-files))) (defun my--company-org () (set (make-local-variable 'company-backends) '(company-capf company-files)) ;; (add-hook 'completion-at-point-functions 'pcomplete-completions-at-point nil t) (message "setup company for org")) (setq company-idle-delay .2 company-minimum-prefix-length 1 company-require-match nil company-show-numbers t company-tooltip-align-annotations t)) (use-package company-statistics :ensure t :after company :defer t :init (setq company-statistics-file (concat MY--PATH_USER_LOCAL "company-statistics-cache.el"));~/.emacs.d/user-dir/company-statistics-cache.el") :config (company-statistics-mode 1)) (use-package company-dabbrev :ensure nil :after company :defer t :config (setq-default company-dabbrev-downcase nil)) ;; adds a info box right of the cursor with doc of the function (use-package company-box :ensure t :diminish :defer t :hook (company-mode . company-box-mode)) ; :init ; (add-hook 'company-mode-hook 'company-box-mode))
orgmode
some notes
copy file path within emacs
Enter dired-other-window place cursor on the file M-0 w (copy absolute path) C-u w (copy relative path)
Archiving
C-c C-x C-a
To keep the subheading structure when archiving, set the properties of the superheading.
* FOO :PROPERTIES: :ARCHIVE: %s_archive::* FOO ** DONE BAR ** TODO BAZ
When moving BAR to archive, it will go to FILENAME.org_archive below the heading FOO. Other examples
org
This seems necessary to prevent 'org is already installed' error https://github.com/jwiegley/use-package/issues/319
;(assq-delete-all 'org package--builtins)' ;(assq-delete-all 'org package--builtin-versions)
(defun my--buffer-prop-set (name value) "Set a file property called NAME to VALUE in buffer file. If the property is already set, replace its value." (setq name (downcase name)) (org-with-point-at 1 (let ((case-fold-search t)) (if (re-search-forward (concat "^#\\+" name ":\\(.*\\)") (point-max) t) (replace-match (concat "#+" name ": " value) 'fixedcase) (while (and (not (eobp)) (looking-at "^[#:]")) (if (save-excursion (end-of-line) (eobp)) (progn (end-of-line) (insert "\n")) (forward-line) (beginning-of-line))) (insert "#+" name ": " value "\n"))))) (defun my--buffer-prop-remove (name) "Remove a buffer property called NAME." (org-with-point-at 1 (when (re-search-forward (concat "\\(^#\\+" name ":.*\n?\\)") (point-max) t) (replace-match "")))) (use-package org :ensure t :pin gnu :mode (("\.org$" . org-mode)) :diminish org-indent-mode :defer 1 :hook (org-mode . org-indent-mode) (org-source-mode . smartparens-mode) :bind (("C-c l" . org-store-link) ("C-c c" . org-capture) ("C-c a" . org-agenda) :map org-mode-map ("S-<right>" . org-shiftright) ("S-<left>" . org-shiftleft)) :init (defun my--org-agenda-files-set () "Sets default agenda files. Necessary when updating roam agenda todos." (setq org-agenda-files (list (concat MY--PATH_ORG_FILES "notes.org") (concat MY--PATH_ORG_FILES "projects.org") (concat MY--PATH_ORG_FILES "tasks.org"))) (when *sys/linux* (nconc org-agenda-files (directory-files-recursively MY--PATH_ORG_FILES_MOBILE "\\.org$")))) (my--org-agenda-files-set) (defun my--org-skip-subtree-if-priority (priority) "Skip an agenda subtree if it has a priority of PRIORITY. PRIORITY may be one of the characters ?A, ?B, or ?C." (let ((subtree-end (save-excursion (org-end-of-subtree t))) (pri-value (* 1000 (- org-lowest-priority priority))) (pri-current (org-get-priority (thing-at-point 'line t)))) (if (= pri-value pri-current) subtree-end nil))) :config (when *work_remote* (org-add-link-type "outlook" 'my--org-outlook-open) (setq org-todo-keywords '((sequence "OPEN" "TODO" "UNCLEAR" "|" "DONE" "IMPOSSIBLE" "CANCELLED"))) (setq org-capture-templates '(("t" "telephone call" entry ; (file+olp+datetree (concat MY--PATH_ORG_FILES "phone_calls.org")) (file+datetree "p:/Eigene Dateien/Notizen/phone_calls.org") "* [%<%Y-%m-%d %H:%M>] %?" :empty-lines 0 :jump-to-captured t)))) (when *sys/linux* (org-pretty-entities t)) :custom (org-startup-truncated t) (org-startup-align-all-tables t) (org-src-fontify-natively t) ;; use syntax highlighting in code blocks (org-src-preserve-indentation t) ;; no extra indentation (org-src-window-setup 'current-window) ;; C-c ' opens in current window (org-modules (quote (org-id org-habit org-tempo))) ;; easy templates (org-default-notes-file (concat MY--PATH_ORG_FILES "notes.org")) (org-id-locations-file (concat MY--PATH_USER_LOCAL ".org-id-locations")) (org-log-into-drawer "LOGBOOK") (org-log-done 'time) ;; create timestamp when task is done (org-blank-before-new-entry '((heading) (plain-list-item))) ;; prevent new line before new item (org-src-tab-acts-natively t) ;;Sort agenda by deadline and priority (org-agenda-sorting-strategy (quote ((agenda deadline-up priority-down) (todo priority-down category-keep) (tags priority-down category-keep) (search category-keep)))) (org-agenda-custom-commands '(("c" "Simple agenda view" ((tags "PRIORITY=\"A\"" ((org-agenda-skip-function '(org-agenda-skip-entry-if 'todo 'done)) (org-agenda-overriding-header "Hohe Priorität:"))) (agenda "" ((org-agenda-skip-function '(org-agenda-skip-entry-if 'todo 'done)) (org-agenda-span 7) (org-agenda-start-on-weekday nil) (org-agenda-overriding-header "Nächste 7 Tage:"))) (alltodo "" ((org-agenda-skip-function '(or (my--org-skip-subtree-if-priority ?A) (org-agenda-skip-if nil '(scheduled deadline)))) (org-agenda-overriding-header "Sonstige Aufgaben:"))))))))
COMMENT languages
Set some languages and disable confirmation for evaluating code blocks C-c C-c
Elpaca cant find it, though it's built in org
(use-package ob-python ; :elpaca nil :defer t :after org ; :ensure org-contrib :commands (org-babel-execute:python))
COMMENT habits
(require 'org-habit) ;;TODO Lösung ohne require finden, scheint mir nicht ideal zu sein, nur um ein org-modul zu aktivieren ;; (add-to-list 'org-modules "org-habit") (setq org-habit-graph-column 80 org-habit-preceding-days 30 org-habit-following-days 7 org-habit-show-habits-only-for-today nil)
TODO
COMMENT journal
Ggf. durch org-roam-journal ersetzen
(use-package org-journal :if *sys/linux* :ensure t :defer t :config ;; feels hacky, but this way compiler error "assignment to free variable" disappears (when (and (boundp 'org-journal-dir) (boundp 'org-journal-enable-agenda-integration)) (setq org-journal-dir MY--PATH_ORG_JOURNAl org-journal-enable-agenda-integration t)))
org-roam
Github Um Headings innerhalb einer Datei zu verlinken:
-
org-id-get-create im Heading,
-
org-roam-node-insert in der verweisenden Datei
Bei Problemen wie unique constraint org-roam-db-clear-all org-roam-db-sync
(use-package emacsql-sqlite-builtin :ensure t) (use-package org-roam :requires emacsql-sqlite-builtin :ensure t :defer 2 :after org :init (setq org-roam-v2-ack t) (defun my--roamtodo-p () "Return non-nil if current buffer has any todo entry. TODO entries marked as done are ignored, meaning this function returns nil if current buffer contains only completed tasks." (seq-find (lambda (type) (eq type 'todo)) (org-element-map (org-element-parse-buffer 'headline) 'headline (lambda (h) (org-element-property :todo-type h))))) (defun my--roamtodo-update-tag () "Update ROAMTODO tag in the current buffer." (when (and (not (active-minibuffer-window)) (my--buffer-roam-note-p)) (save-excursion (goto-char (point-min)) (let* ((tags (my--buffer-tags-get)) (original-tags tags)) (if (my--roamtodo-p) (setq tags (cons "roamtodo" tags)) (setq tags (remove "roamtodo" tags))) ;;cleanup duplicates (when (or (seq-difference tags original-tags) (seq-difference original-tags tags)) (apply #'my--buffer-tags-set tags)))))) (defun my--buffer-tags-get () "Return filetags value in current buffer." (my--buffer-prop-get-list "filetags" "[ :]")) (defun my--buffer-tags-set (&rest tags) "Set TAGS in current buffer. If filetags value is already set, replace it." (if tags (my--buffer-prop-set "filetags" (concat ":" (string-join tags ":") ":")) (my--buffer-prop-remove "filetags"))) (defun my--buffer-tags-add (tag) "Add a TAG to filetags in current buffer." (let* ((tags (my--buffer-tags-get)) (tags (append tags (list tag)))) (apply #'my--buffer-tags-set tags))) (defun my--buffer-tags-remove (tag) "Remove a TAG from filetags in current buffer." (let* ((tags (my--buffer-tags-get)) (tags (delete tag tags))) (apply #'my--buffer-tags-set tags))) (defun my--buffer-prop-set (name value) "Set a file property called NAME to VALUE in buffer file. If the property is already set, replace its value." (setq name (downcase name)) (org-with-point-at 1 (let ((case-fold-search t)) (if (re-search-forward (concat "^#\\+" name ":\\(.*\\)") (point-max) t) (replace-match (concat "#+" name ": " value) 'fixedcase) (while (and (not (eobp)) (looking-at "^[#:]")) (if (save-excursion (end-of-line) (eobp)) (progn (end-of-line) (insert "\n")) (forward-line) (beginning-of-line))) (insert "#+" name ": " value "\n"))))) (defun my--buffer-prop-set-list (name values &optional separators) "Set a file property called NAME to VALUES in current buffer. VALUES are quoted and combined into single string using `combine-and-quote-strings'. If SEPARATORS is non-nil, it should be a regular expression matching text that separates, but is not part of, the substrings. If nil it defaults to `split-string-and-unquote', normally \"[ \f\t\n\r\v]+\", and OMIT-NULLS is forced to t. If the property is already set, replace its value." (my--buffer-prop-set name (combine-and-quote-strings values separators))) (defun my--buffer-prop-get (name) "Get a buffer property called NAME as a string." (org-with-point-at 1 (when (re-search-forward (concat "^#\\+" name ": \\(.*\\)") (point-max) t) (buffer-substring-no-properties (match-beginning 1) (match-end 1))))) (defun my--buffer-prop-get-list (name &optional separators) "Get a buffer property NAME as a list using SEPARATORS. If SEPARATORS is non-nil, it should be a regular expression matching text that separates, but is not part of, the substrings. If nil it defaults to `split-string-default-separators', normally \"[ \f\t\n\r\v]+\", and OMIT-NULLS is forced to t." (let ((value (my--buffer-prop-get name))) (when (and value (not (string-empty-p value))) (split-string-and-unquote value separators)))) (defun my--buffer-prop-remove (name) "Remove a buffer property called NAME." (org-with-point-at 1 (when (re-search-forward (concat "\\(^#\\+" name ":.*\n?\\)") (point-max) t) (replace-match "")))) (defun my--buffer-roam-note-p () "Return non-nil if the currently visited buffer is a note." (and buffer-file-name (string-prefix-p (expand-file-name (file-name-as-directory MY--PATH_ORG_ROAM)) (file-name-directory buffer-file-name)))) (defun my--org-roam-filter-by-tag (tag-name) (lambda (node) (member tag-name (org-roam-node-tags node)))) (defun my--org-roam-list-notes-by-tag (tag-name) (mapcar #'org-roam-node-file (seq-filter (my--org-roam-filter-by-tag tag-name) (org-roam-node-list)))) (defun my/org-roam-refresh-agenda-list () "Add all org roam files with #+filetags: roamtodo" (interactive) (my--org-agenda-files-set) (nconc org-agenda-files (my--org-roam-list-notes-by-tag "roamtodo")) (setq org-agenda-files (delete-dups org-agenda-files))) (add-hook 'find-file-hook #'my--roamtodo-update-tag) (add-hook 'before-save-hook #'my--roamtodo-update-tag) (advice-add 'org-agenda :before #'my/org-roam-refresh-agenda-list) (advice-add 'org-todo-list :before #'my/org-roam-refresh-agenda-list) (add-to-list 'org-tags-exclude-from-inheritance "roamtodo") :config (require 'org-roam-dailies) ;; ensure the keymap is available (org-roam-db-autosync-mode) ;; build the agenda list the first ime for the session (my/org-roam-refresh-agenda-list) (when *work_remote* (setq org-roam-capture-templates '(("n" "note" plain "%?" :if-new (file+head "notes/%<%Y%m%d%H%M%S>-${slug}.org" "#+title: ${title}\n") :unnarrowed t) ("i" "idea" plain "%?" :if-new (file+head "ideas/%<%Y%m%d%H%M%S>-${slug}.org" "#+title: ${title}\n") :unnarrowed t) ("p" "project" plain "%?" :target (file+head "projects/${slug}.org" "#+title: ${title}\n#+filetags: :project:\n") :unnarrowed t) ("s" "Sicherheitenmeldung" plain "*** TODO [#A] Sicherheitenmeldung ${title}\n :PROPERTIES:\n :ID: %(org-id-uuid)\n:END:\n%u\n" :target (file+olp "tasks.org" ("Todos" "Sicherheitenmeldungen"))) ("m" "Monatsbericht" plain "*** TODO [#A] Monatsbericht ${title}\n :PROPERTIES:\n :ID: %(org-id-uuid)\n:END:\n%u\n" :target (file+olp "tasks.org" ("Todos" "Monatsberichte")))))) :custom (org-roam-database-connector 'sqlite-builtin) (org-roam-directory MY--PATH_ORG_ROAM) (org-roam-completion-everywhere t) (org-roam-capture-templates '(("n" "note" plain "%?" :if-new (file+head "notes/%<%Y%m%d%H%M%S>-${slug}.org" "#+title: ${title}\n") :unnarrowed t) ("i" "idea" plain "%?" :if-new (file+head "ideas/%<%Y%m%d%H%M%S>-${slug}.org" "#+title: ${title}\n") :unnarrowed t) )) :bind (("C-c n l" . org-roam-buffer-toggle) ("C-c n f" . org-roam-node-find) ("C-c n i" . org-roam-node-insert) :map org-mode-map ("C-M-i" . completion-at-point) :map org-roam-dailies-map ("Y" . org-roam-dailies-capture-yesterday) ("T" . org-roam-dailies-capture-tomorrow)) :bind-keymap ("C-c n d" . org-roam-dailies-map))
TODO Verzeichnis außerhalb roam zum Archivieren (u.a. für erledigte Monatsmeldungen etc.)
Programming
Magit / Git
Little crash course in magit:
-
magit-init to init a git project
-
magit-status (C-x g) to call the status window
In status buffer:
-
s stage files
-
u unstage files
-
U unstage all files
-
a apply changes to staging
-
c c commit (type commit message, then C-c C-c to commit)
-
b b switch to another branch
-
P u git push
-
F u git pull
(use-package magit :ensure t ; :pin melpa-stable :defer t :init ; set git-path in work environment (if (string-equal user-login-name "POH") (setq magit-git-executable "P:/Tools/Git/bin/git.exe") ) :bind (("C-x g" . magit-status)))
COMMENT Eglot (can't do dap-mode, maybe dape?)
for python pyls (in env: pip install python-language-server) seems to work better than pyright (npm install -g pyright), at least pandas couldnt be resolved in pyright
(use-package eglot :ensure t :init (setq completion-category-overrides '((eglot (styles orderless)))) :config (add-to-list 'eglot-server-programs '(python-mode . ("pyright-langserver" "--stdio"))) (with-eval-after-load 'eglot (load-library "project")) :hook (python-mode . eglot-ensure) :custom (eglot-ignored-server-capabilities '(:documentHighlightProvider)) (eglot-autoshutdown t) (eglot-events-buffer-size 0) ) ;; performance stuff if necessary ;(fset #'jsonrpc--log-event #'ignore)
LSP-Mode
(defun corfu-lsp-setup () (setf (alist-get 'styles (alist-get 'lsp-capf completion-category-defaults)) '(orderless))) (use-package lsp-mode :ensure t ; :hook ; ((python-mode . lsp)) :custom (lsp-completion-provider :none) (lsp-enable-suggest-server-download nil) :hook (lsp-completion-mode #'corfu-lsp-setup)) ;(use-package lsp-ui ; :ensure t ; :commands lsp-ui-mode) (use-package lsp-pyright :ensure t :after (python lsp-mode) :custom (lsp-pyright-multi-root nil) :hook (python-mode-hook . (lambda () (require 'lsp-pyright) (lsp))))
flymake
python in venv: pip install pyflake (or ruff?) TODO: if ruff active, sideline stops working
(setq python-flymake-command '("ruff" "--quiet" "--stdin-filename=stdin" "-"))
sideline
show flymake errors on the right of code window
(use-package sideline :ensure t) (use-package sideline-flymake :ensure t :requires sideline :hook (flymake-mode . sideline-mode) :init (setq sideline-flymake-display-mode 'line ; 'point or 'line ; sideline-backends-left '(sideline-lsp) sideline-backends-right '(sideline-flymake)))
yasnippet
For useful snippet either install yasnippet-snippets or get them from here Github
(use-package yasnippet :ensure t :defer t :diminish yas-minor-mode :config (setq yas-snippet-dirs (list (concat MY--PATH_USER_GLOBAL "snippets"))) (yas-global-mode t) (yas-reload-all) (unbind-key "TAB" yas-minor-mode-map) (unbind-key "<tab>" yas-minor-mode-map))
hippie expand
With hippie expand I am able to use yasnippet and emmet at the same time with the same key.
(use-package hippie-exp :elpaca nil :defer t :bind ("C-<return>" . hippie-expand) :config (setq hippie-expand-try-functions-list '(yas-hippie-try-expand emmet-expand-line)))
COMMENT flycheck (now flymake)
(use-package flycheck :ensure t :hook ((css-mode . flycheck-mode) (emacs-lisp-mode . flycheck-mode) (python-mode . flycheck-mode)) :defer 1.0 :init (setq flycheck-emacs-lisp-load-path 'inherit) :config (setq-default flycheck-check-synta-automatically '(save mode-enabled) flycheck-disable-checkers '(emacs-lisp-checkdoc) eldoc-idle-delay .1 ;; let eldoc echo faster than flycheck flycheck-display-errors-delay .3)) ;; this way any errors will override eldoc messages
smartparens
(use-package smartparens :ensure t :diminish smartparens-mode :bind (:map smartparens-mode-map ("C-M-f" . sp-forward-sexp) ("C-M-b" . sp-backward-sexp) ("C-M-a" . sp-backward-down-sexp) ("C-M-e" . sp-up-sexp) ("C-M-w" . sp-copy-sexp) ("M-k" . sp-kill-sexp) ("C-M-<backspace>" . sp-slice-sexp-killing-backward) ("C-S-<backspace>" . sp-slice-sexp-killing-around) ("C-]" . sp-select-next-thing-exchange)) :config (setq sp-show-pair-from-inside nil sp-escape-quotes-after-insert nil) (require 'smartparens-config))
lisp
(use-package elisp-mode :elpaca nil :defer t)
web
apt install npm sudo npm install -g vscode-html-languageserver-bin evtl alternativ typescript-language-server?
Unter Windows: Hier runterladen: https://nodejs.org/dist/latest/ und in ein Verzeichnis entpacken. Optional: PATH erweitern unter Windows (so kann exec-path-from-shell den Pfad ermitteln): PATH=P:\path→\node;%path%
web-mode
(use-package web-mode :ensure t :defer t :mode ("\\.phtml\\'" "\\.tpl\\.php\\'" "\\.djhtml\\'" "\\.[t]?html?\\'") :hook (web-mode . smartparens-mode) :init (if *work_remote* (setq exec-path (append exec-path '("P:/Tools/node")))) :config (setq web-mode-enable-auto-closing t web-mode-enable-auto-pairing t))
Emmet offers snippets, similar to yasnippet. Default completion is C-j Github
(use-package emmet-mode :ensure t :defer t :hook ((web-mode . emmet-mode) (css-mode . emmet-mode)) :config (unbind-key "C-<return>" emmet-mode-keymap))
JavaScript
npm install -g typescript-language-server typescript maybe only typescript? npm install -g prettier
(use-package rjsx-mode :ensure t :mode ("\\.js\\'" "\\.jsx'")) ; :config ; (setq js2-mode-show-parse-errors nil ; js2-mode-show-strict-warnings nil ; js2-basic-offset 2 ; js-indent-level 2) ; (setq-local flycheck-disabled-checkers (cl-union flycheck-disable-checkers ; '(javascript-jshint)))) ; jshint doesn"t work for JSX (use-package tide :ensure t :after (rjsx-mode company flycheck) ; :hook (rjsx-mode . setup-tide-mode) :config (defun setup-tide-mode () "Setup function for tide." (interactive) (tide-setup) (flycheck-mode t) (setq flycheck-check-synta-automatically '(save mode-enabled)) (tide-hl-identifier-mode t))) ;; needs npm install -g prettier (use-package prettier-js :ensure t :after (rjsx-mode) :defer t :diminish prettier-js-mode :hook ((js2-mode rsjx-mode) . prettier-js-mode))
YAML
(use-package yaml-mode :if *sys/linux* :ensure t :defer t :mode ("\\.yml$" . yaml-mode))
R
(use-package ess :ensure t :defer t :init (if *work_remote* (setq exec-path (append exec-path '("P:/Tools/R/bin/x64")) org-babel-R-command "P:/Tools/R/bin/x64/R --slave --no-save")))
project.el
(use-package project :custom (project-vc-extra-root-markers '(".project.el" ".project" )))
Python
Preparations:
-
Install language server in each projects venv source ./bin/activate pip install pyright
-
in project root: touch .project.el echo "((nil . (pyvenv-activate . "path/to/project.env")))" >> .dir-locals.el
für andere language servers https://github.com/emacs-lsp/lsp-mode#install-language-server
TODO if in a project, set venv automatically (when-let ((project (project-current))) (project-root project)) returns project path from project.el to recognize a project, either have git or place a .project.el file in project root and (setq project-vc-extra-root-markers '(".project.el" "…" ))
(use-package python :if *sys/linux* :delight "π " :defer t :bind (("M-[" . python-nav-backward-block) ("M-]" . python-nav-forward-block)) :mode (("\\.py\\'" . python-mode))) (use-package pyvenv ; :if *sys/linux* :ensure t :defer t :after python :hook (python-mode . pyvenv-mode) :custom (pyvenv-default-virtual-env-name ".env") (pyvenv-mode-line-indicator '(pyvenv-virtual-env-name ("[venv:" pyvenv-virtual-env-name "]")))) ;; formatting to pep8 ;; requires pip install black ;(use-package blacken ; :ensure t)
TODO python mode hook:
-
activate venv
-
activate eglot with proper ls
-
activate tree-sitter?
-
have some fallback if activations fail
beancount
Installation
sudo su cd /opt python3 -m venv beancount source ./beancount/bin/activate pip3 install wheel pip3 install beancount sleep 100 echo "shell running!" deactivate
(use-package beancount :elpaca nil :if *sys/linux* :load-path "user-global/elisp/" ; :ensure t :defer t :mode ("\\.beancount$" . beancount-mode) :hook (beancount-mode . my/beancount-company) :config (defun my/beancount-company () (setq-local completion-at-point-functions #'beancount-completion-at-point)) (setq beancount-filename-main "/home/marc/Archiv/Finanzen/Transaktionen/transactions.beancount"))
+BEGIN_SRC emacs-lisp (use-package beancount :if sys/linux :load-path "user-global/elisp" ; :ensure t :defer t :mode ("\\.beancount$" . beancount-mode) ; :hook ; (beancount-mode . my/beancount-company) ; :init ; (add-hook 'beancount-mode-hook 'company/beancount-mode-hook) :config (defun my/beancount-company () (setq-local completion-at-point-functions #'beancount-complete-at-point nil t)) ; (mapcar #'cape-company-to-capf ; (list #'company-beancount #'company-dabbrev)))) (defun my–beancount-companyALT () (set (make-local-variable 'company-backends) '(company-beancount))) (setq beancount-filename-main "/home/marc/Archiv/Finanzen/Transaktionen/transactions.beancount")) +END_SRC
To support org-babel, check if it can find the symlink to ob-beancount.el
orgpath=`find /home/marc/.emacs.d/elpa/ -type d -name "org-plus*" -print` beansym="$orgpath/ob-beancount.el bean="/home/marc/Archiv/Programmierprojekte/Lisp/beancount-mode/ob-beancount.el" if [ -h "$beansym" ] then echo "$beansym found" elif [ -e "$bean" ] then echo "creating symlink" ln -s "$bean" "$beansym" else echo "$bean not found, symlink creation aborted" fi
Fava is strongly recommended.
cd /opt python3 -m venv fava source ./fava/bin/activate pip3 install wheel pip3 install fava deactivate
Start fava with fava my_file.beancount
It is accessable on this URL: Fava Beancount-mode can start fava and open the URL right away.
Stuff after everything else
Set garbage collector to a smaller value to let it kick in faster. Maybe a problem on Windows?
;(setq gc-cons-threshold (* 2 1000 1000))
Rest of early-init.el
(defconst config-org (expand-file-name "config.org" user-emacs-directory)) (defconst init-el (expand-file-name "init.el" user-emacs-directory)) (unless (file-exists-p init-el) (require 'org) (org-babel-tangle-file config-org init-el))