This is a literate configuration for Emacs
.
Tangling this file creates two Elisp files, init.el
and early-init.el
.
Start with make tangle
to create the init.el and early-init.el from this org file.
Dependencies you need to fully run all configured features:
- ag
- vterm requirements
- pyright
- shellcheck
- fonts
- hunspell
- git and git-flow
- YAML language server (rnix-lsp)
Idea and basics for tuning startup time from https://github.com/progfolio/.emacs.d
Emacs 27.0 introduced an early-init file. It allows customization before package and UI initialization.
;;; early-init.el --- Emacs pre package.el & GUI configuration -*- lexical-binding: t; no-byte-compile: t -*-
;;; Code:
(when (version< emacs-version "27.2")
(error "Emacs version is to low (minimum 27.2)."))
We want the latest version of Org mode.
Removing the Emacs bundled version from the load-path should prevent loading mixed Org versions. e.g. After updating Org mode.
(when-let (orglib (locate-library "org" nil load-path))
(setq-default load-path (delete (substring (file-name-directory orglib) 0 -1)
load-path)))
Save some time at startup.
(setq package-enable-at-startup nil)
Running this form will launch the debugger after loading a package.
This is useful for finding out when a dependency is requiring a package (perhaps earlier than you want).
Use by tangling this block and launching Emacs with emacs --debug-init
.
(unless (string-empty-p file)
(eval-after-load file
'(debug)))
Similarly, this variable will hit the debugger when a message matches its regexp.
(setq debug-on-message "")
Adding a variable watcher can be a useful way to track down initialization and mutation of a variable.
(add-variable-watcher 'org-capture-after-finalize-hook
(lambda (symbol newval operation where)
(debug)
(message "%s set to %s" symbol newval)))
Prevent the scratch buffer from loading a mode.
(setq initial-major-mode 'fundamental-mode)
Skipping a bunch of regular expression searching in the file-name-handler-alist
should improve start time.
(defvar default-file-name-handler-alist file-name-handler-alist)
(when (< emacs-major-version 29)
(setq file-name-handler-alist nil))
Emacs collects garbage every 800KB. This is overly aggressive on a modern machine during our init. Temporarily turning it off should decrease startup times. Resetting it afterward will ensure that normal operations don’t suffer from a large GC period.
I’m still not sure on the optimal gc-cons-threshold value. The following is a table of values from popular Emacs configurations.
Distribution | gc-cons-threshold |
---|---|
Default | 800000 |
Doom | 16777216 |
Spacemacs | 100000000 |
(setq gc-cons-threshold most-positive-fixnum)
(defun +gc-after-focus-change ()
"Run GC when frame loses focus."
(run-with-idle-timer
5 nil
(lambda () (unless (frame-focus-state) (garbage-collect)))))
(defun +reset-init-values ()
(run-with-idle-timer
5 nil
(lambda ()
(setq file-name-handler-alist default-file-name-handler-alist
gc-cons-threshold 100000000)
(message "gc-cons-threshold & file-name-handler-alist restored")
(when (boundp 'after-focus-change-function)
(add-function :after after-focus-change-function #'+gc-after-focus-change)))))
(add-hook 'emacs-startup-hook '+reset-init-values)
Enlargen the maximum number of bytes to read from subprocess in a single chunk. Good for speeding up language servers.
(setq read-process-output-max (* 1024 1024)) ;; 1mb
Turning off these visual elements before UI initialization should speed up init.
(push '(menu-bar-lines . 0) default-frame-alist)
(push '(tool-bar-lines . 0) default-frame-alist)
(push '(vertical-scroll-bars) default-frame-alist)
Implicitly resizing the Emacs frame adds to init time. Fonts larger than the system default can cause frame resizing, which adds to startup time.
(setq frame-inhibit-implied-resize t)
Ignore X resources.
(advice-add #'x-apply-session-resources :override #'ignore)
Taken from:
https://github.com/vsemyonoff/emacsrc/blob/14649a5bafea99cc7e13e7d048e9d15aed7926ce/early-init.el
This helps with a bug I was hitting when using desktop-save-mode
’s desktop-read
.
(setq desktop-restore-forces-onscreen nil)
(provide 'early-init)
;;; early-init.el ends here
The following line turns on lexical binding for performance reasons.
;;; init.el --- Personal configuration file -*- lexical-binding: t; no-byte-compile: t; -*-
straight.el: next-generation, purely functional package manager for the Emacs hacker.
Straight installs packages directly from there git repository.
Bootstrap straight Troubleshoot:
Sometimes, in a corporate environment, url-retrieve-synchronously may not work and straight.el will be unable to download the installation script mentioned in the bootstrap snippet. In this case, you may simply clone this repository into ~/.emacs.d/straight/repos/straight.el and check out your desired revision/branch.
(setq straight-repository-branch "master")
(setq straight-check-for-modifications '(check-on-save))
(setq straight-use-package-by-default t)
(setq straight-vc-git-default-protocol 'https)
(setq straight-vc-git-force-protocol nil)
(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))
This function displays how long Emacs took to start. It’s a rough way of knowing when/if I need to optimize my init file.
(add-hook 'emacs-startup-hook
(lambda ()
(message "Emacs loaded in %s with %d garbage collecitons."
(format "%.2f seconds"
(float-time
(time-subtract after-init-time before-init-time)))
gcs-done)))
(defmacro use-feature (name &rest args)
"Like `use-package' but with `straight-use-package-by-default' disabled.
NAME and ARGS are in `use-package'."
(declare (indent defun))
`(use-package ,name
:straight nil
:ensure nil
,@args))
(straight-use-package 'use-package)
(eval-when-compile
(require 'use-package))
(setq init-file-debug nil)
(if init-file-debug
(setq use-package-verbose t
use-package-expand-minimally nil
use-package-compute-statistics t
debug-on-error t)
(setq use-package-verbose nil
use-package-expand-minimally t))
(defconst *sys/win32*
(eq system-type 'windows-nt)
"Are we running on a Win system?")
(defconst *sys/linux*
(eq system-type 'gnu/linux)
"Are we running on a GNU/Linux system?")
(defconst *sys/mac*
(eq system-type 'darwin)
"Are we running on a Mac system?")
(defconst *sys/project-home*
"~/Devel")
(defconst sys/leader-key "SPC"
"The default leader key.")
(defconst sys/leader-secondary-key "C-SPC"
"The secondary leader key.")
(defconst sys/major-leader-key "SPC m"
"The default major mode leader key.")
(defconst sys/major-leader-secondary-key "C-SPC m"
"The secondary major mode leader key.")
(defconst *sys/shell-history-file* "~/.bash_history")
(defconst *sys/shell-config-file* "~/.bashrc")
(cond (*sys/mac*
(defconst *sys/font-default-height* 160)
(defconst *sys/font-variable-height* 160)
(defconst *sys/shell-executable* "/usr/local/bin/bash")
(defconst *sys/omnisharp-server-path* (expand-file-name "util/omnisharp-run.sh" user-emacs-directory))
(setenv "LSP_MONO_BASE_DIR" "/usr/local/cellar/mono/6.12.0.122")
(setenv "LSP_OMNISHARP_EXE" "/usr/local/share/omnisharp-osx/omnisharp/omnisharp.exe")
)
(*sys/linux*
(defconst *sys/font-default-height* 110)
(defconst *sys/font-variable-height* 130)
;; get bash path without new line
;; TODO assert that paths exists
;; From POSIX specs (https://pubs.opengroup.org/onlinepubs/009695399/utilities/sh.html)
;; Applications should note that the standard PATH to the shell
;; cannot be assumed to be either /bin/sh or /usr/bin/sh
(defconst *sys/shell-executable* (shell-command-to-string "printf %s $SHELL"))
))
Evil is an extensible vi layer for Emacs. It emulates the main features of Vim, and provides facilities for writing custom extensions. […] evil-collection assumes evil-want-keybinding is set to nil and evil-want-integration is set to t before loading evil and evil-collection.
(use-package evil
:demand t
:init
(setq evil-want-integration t)
(setq evil-undo-system 'undo-redo)
(setq evil-want-keybinding nil)
:hook (after-init . evil-mode))
This is a collection of Evil bindings for the parts of Emacs that Evil does not cover properly by default.
(use-package evil-collection
:after evil
:init
(progn
;;Whether to setup Evil bindings in the minibuffer.
(setq evil-collection-setup-minibuffer t))
:config
(progn
(evil-collection-init)
))
general.el provides a more convenient method for binding keys in emacs (for both evil and non-evil users).
Load general before the remaining packages so they can make use of the :general
keyword in their declarations.
(use-package general
:demand t
:init
(progn
(setq general-override-states '(insert emacs hybrid normal visual motion operator replace)))
:config
(progn
(defun sys/major-mode-name (arg)
"Return major mode name"
(cons
(cadr (split-string (car arg) " "))
(replace-regexp-in-string
"-mode$"
""
(symbol-name major-mode))))
(general-evil-setup)
(general-create-definer
global-leader
:keymaps 'override
:states '(normal insert emacs motion visual)
:prefix sys/leader-key
:non-normal-prefix sys/leader-secondary-key)
(general-create-definer
global-major-leader
:states '(normal insert emacs motion viusal)
:prefix sys/major-leader-key
:non-normal-prefix sys/major-leader-secondary-key
"" '(:ignore t :which-key sys/major-mode-name))
(general-nmap "," (general-simulate-key "SPC m"))
(global-leader
"a" '(:ignore t :wk "applications")
"b" '(:ignore t :wk "buffers")
"bx" 'kill-current-buffer
"bd" 'dired
"bD" 'dired-jump
"bm" '((lambda () (interactive) (switch-to-buffer "*Messages*"))
:which-key "messages-buffer")
"bs" '((lambda () (interactive) (switch-to-buffer "*scratch*"))
:which-key "scratch-buffer")
"f" '(:ignore t :wk "files")
"fe" '(:ignore t :which-key "env")
"fed" '((lambda () (interactive) (find-file (expand-file-name "init.org" user-emacs-directory))) :which-key "init.org")
"feb" '((lambda () (interactive) (find-file *sys/shell-config-file*)) :which-key ".bashrc")
"fey" '((lambda () (interactive) (dired (expand-file-name "snippets" user-emacs-directory))) :which-key "yasnippet folder")
"fep" '(straight-freeze-versions :which-key "freeze packages")
"g" '(:ignore t :wk "git")
"j" '(:ignore t :wk "jump")
"p" '(:ignore t :wk "projects")
"s" '(:ignore t :wk "search")
"S" '(:ignore t :wk "spelling")
"t" '(:ignore t :wk "themes")
"T" '(:ignore t :wk "toggle")
"w" '(:ignore t :wk "windows")
"w?" 'split-window-vertically
"w=" 'balance-windows-area
"w/" 'split-window-horizontally
"wH" 'evil-window-move-far-left
"wJ" 'evil-window-move-very-bottom
"wK" 'evil-window-move-very-top
"wL" 'evil-window-move-far-right
"wd" 'delete-window
"wh" 'windmove-left
"wj" 'windmove-down
"wk" 'windmove-up
"wl" 'windmove-right
"wo" 'other-window
"wO" 'delete-other-windows
"wx" 'kill-buffer-and-window
"wX" '((lambda () (interactive) (call-interactively #'other-window) (kill-buffer-and-window))
:which-key "kill-other-buffer-and-window")
"q" '(:ignore t :wk "quit")
"!" 'shell-command
":" 'eval-expression
"TAB" '((lambda () (interactive) (switch-to-buffer nil))
:which-key "other-buffer")
)))
which-key is a minor mode for Emacs that displays the key bindings following your currently entered incomplete command (a prefix) in a popup.
(use-package which-key
:demand t
:config
(progn
(setq which-key-side-window-location 'bottom)
(setq which-key-popup-type 'side-window)
(setq which-key-sort-order 'which-key-key-order-alpha
which-key-side-window-max-width 0.33
which-key-idle-delay 0.75)
(which-key-mode)
)
:diminish )
Magit is an interface to the version control system Git, implemented as an Emacs package.
(use-package magit
:defer t
:after (general)
:general
(global-leader
"gb" 'magit-blame
"gi" 'magit-init
"gs" 'magit-status
)
:config
(transient-bind-q-to-quit))
Plugin in for git-flow in magit.
https://github.com/jtatarik/magit-gitflow
(use-package magit-gitflow
:defer t
:init (setq magit-gitflow-popup-key "%")
;; TODO add % key to magit-dispatch-popup
;; https://magit.vc/manual/magit-popup.html#Customizing-Existing-Popups
;; :config
;; (progn
;; (magit-define-popup-action 'magit-dispatch-popup
;; "%" "Git Flow" 'magit-gitflow-popup t))
:hook (magit-mode . magit-gitflow-mode)
:general
(general-def magit-mode-map
"%" 'magit-gitflow-popup)
)
Company is a text completion framework for Emacs. The name stands for “complete anything”. It uses pluggable back-ends and front-ends to retrieve and display completion candidates.
(use-package company
:hook ((prog-mode yaml-mode) . company-mode)
:diminish
:general
(general-def company-active-map
"C-k" 'company-select-previous
"C-j" 'company-select-next
"<tab>" 'company-complete-common-or-cycle
"S-<tab>" 'company-select-previous
;;for x11 https://emacs.stackexchange.com/a/53469
"S-<iso-lefttab>" 'company-select-previous)
:config
(progn
(defun add-yasnippet-backend (backend)
"Add company-yasnippet backend to given company backend"
(if (and (listp backend) (member 'company-yasnippet backend))
backend
(append (if (consp backend) backend (list backend))
'(:with company-yasnippet))))
;; add yasnippet-backend to all company backends
(setq company-backends (mapcar #'add-yasnippet-backend company-backends))
(setq company-tooltip-align-annotations t
company-idle-delay 0.1
company-show-numbers t
company-dabbrev-ignore-case nil
company-dabbrev-downcase nil
company-minimum-prefix-length 2
company-require-match nil)
)
)
(use-package company-tabnine
:defer t
:commands company-tabnine-install-binary
:after company
:config
(progn
(setq company-tabnine-max-num-results 9)
(company-tabnine-toggle t)
)
:init
(progn
;; tabnine integration from https://github.com/MatthewZMD/.emacs.d/blob/master/elisp/init-company.el
(defun company//sort-by-tabnine (candidates)
"Integrate company-tabnine with lsp-mode"
(if (or (functionp company-backend)
(not (and (listp company-backend) (memq 'company-tabnine company-backends))))
candidates
(let ((candidates-table (make-hash-table :test #'equal))
candidates-lsp
candidates-tabnine)
(dolist (candidate candidates)
(if (eq (get-text-property 0 'company-backend candidate)
'company-tabnine)
(unless (gethash candidate candidates-table)
(push candidate candidates-tabnine))
(push candidate candidates-lsp)
(puthash candidate t candidates-table)))
(setq candidates-lsp (nreverse candidates-lsp))
(setq candidates-tabnine (nreverse candidates-tabnine))
(nconc (seq-take candidates-tabnine 3)
(seq-take candidates-lsp 6)))))
(defun lsp-after-open-tabnine ()
"Hook to attach to `lsp-after-open'."
(setq-local company-tabnine-max-num-results 3)
(add-to-list 'company-transformers 'company//sort-by-tabnine t)
(add-to-list 'company-backends '(company-capf :with company-tabnine :separate)))
(defun company-tabnine-toggle (&optional enable)
"Enable/Disable TabNine. If ENABLE is non-nil, definitely enable it."
(interactive)
(if (or enable (not (memq 'company-tabnine company-backends)))
(progn
(add-hook 'lsp-after-open-hook #'lsp-after-open-tabnine)
(add-to-list 'company-backends #'company-tabnine)
(when (bound-and-true-p lsp-mode) (lsp-after-open-tabnine))
(message "TabNine enabled."))
(setq company-backends (delete 'company-tabnine company-backends))
(setq company-backends (delete '(company-capf :with company-tabnine :separate) company-backends))
(remove-hook 'lsp-after-open-hook #'lsp-after-open-tabnine)
(company-tabnine-kill-process)
(message "TabNine disabled.")))
)
:general
(global-major-leader :keymaps 'prog-mode-map
"c" '(:ignore t :wk "company")
"ct" '(company-tabnine-toggle :wk "toggle tabnine"))
)
(use-package company-statistics
:defer t
:config
(progn
(setq company-statistics-size 10000))
:init
(progn
(add-hook 'company-mode-hook 'company-statistics-mode)))
A company front-end with icons.
(use-package company-box
:if (display-graphic-p)
:after company
:hook (company-mode . company-box-mode))
Consult provides practical commands based on the Emacs completion function completing-read. Completion allows you to quickly select an item from a list of candidates.
(use-package consult
:hook (completion-list-mode . consult-preview-at-point-mode)
:init
(progn
;; Optionally configure the register formatting. This improves the register
;; preview for `consult-register', `consult-register-load',
;; `consult-register-store' and the Emacs built-ins.
(setq register-preview-delay 0.5
register-preview-function #'consult-register-format)
;; Optionally tweak the register preview window.
;; This adds thin lines, sorting and hides the mode line of the window.
(advice-add #'register-preview :override #'consult-register-window)
;; Use Consult to select xref locations with preview
(setq xref-show-xrefs-function #'consult-xref
xref-show-definitions-function #'consult-xref)
)
:config
(progn
(defun consult--preview-p ()
"Are we in a consult preview buffer?"
(when-let (win (active-minibuffer-window))
(not (eq nil (buffer-local-value
'consult--preview-function
(window-buffer win))))))
;; Optionally configure a function which returns the project root directory.
(setq consult-project-root-function #'projectile-project-root)
)
:general
(general-def :states '(normal)
"P" #'consult-yank-from-kill-ring
)
(global-leader
"SPC" '(execute-extended-command :which-key "M-x")
"/" '(consult-ripgrep :wk "ripgrep")
"ss" '(consult-line :wk "search")
"bb" '(consult-buffer :which-key "buffer list")
"ff" '(find-file :wk "find files")
"fr" '(consult-recent-file :wk "recent files")
"ji" '(consult-imenu :wk "imenu")
)
:defer 1
)
Projectile is a project interaction library for Emacs. Its goal is to provide a nice set of features operating on a project level without introducing external dependencies (when feasible).
(use-package projectile
:after (general)
:commands (projectile-project-root)
:general
(global-leader
"p!" 'projectile-run-shell-command-in-root
"pp" 'projectile-switch-project
"pf" 'projectile-find-file
"pD" 'projectile-dired
"pe" 'projectile-edit-dir-locals
"pR" 'projectile-replace
"pS" 'projectile-discover-projects-in-search-path
"pt" 'projectile-run-vterm)
:config
(progn
(defun sys/switch-project-action ()
"Switch to a workspace with the project name."
(persp-switch (projectile-project-name))
(projectile-find-file))
(setq projectile-project-search-path (list *sys/project-home*))
(setq projectile-switch-project-action #'sys/switch-project-action)
(add-to-list 'projectile-globally-ignored-directories "site-packages")
(projectile-mode t))
)
Emacs-libvterm (vterm) is fully-fledged terminal emulator inside GNU Emacs based on libvterm, a C library.
(use-package vterm
:commands (vterm vterm-other-window)
:general
(global-leader "at" '(:ignore t :which-key "terminal")
"att" 'vterm-other-window
"at." 'vterm
)
;; (general-def vterm-mode-map "C-r" 'helm-vterm-search-history :states '(normal emacs))
(general-def vterm-mode-map "C-l" 'vterm-clear :states '(normal emacs))
;; copied from spacemacs
:config
(setq vterm-shell *sys/shell-executable*)
;; (defun vterm-make-history-candidates ()
;; (with-temp-buffer
;; (insert-file-contents *sys/shell-history-file*)
;; (reverse
;; (delete-dups
;; (split-string (buffer-string) "\n")))))
;; (defun helm-vterm-search-history ()
;; "Narrow down bash history with helm."
;; (interactive)
;; (cl-assert (string-equal mode-name "VTerm") nil "Not in VTerm mode")
;; (helm :sources (helm-build-sync-source "Bash history"
;; :candidates (vterm-make-history-candidates)
;; :action #'vterm-send-string)
;; :buffer "*helm-bash-history*"
;; :candidate-number-limit 10000))
(evil-set-initial-state 'vterm-mode 'emacs)
(add-hook 'vterm-mode-hook #'(lambda ()
(setq-local global-hl-line-mode nil)
(setq buffer-face-mode-face '(:family "MesloLGS NF"))
(buffer-face-mode)
))
)
This package implements hiding or abbreviation of the mode line displays (lighters) of minor-modes.
(use-package diminish
:defer 3)
Expand region increases the selected region by semantic units. Just keep pressing the key until it selects what you want.
https://github.com/magnars/expand-region.el
See also https://github.com/hlissner/doom-emacs/blob/develop/docs/faq.org#why-do-non-evil-users-get-expand-region-but-not-evil-users to learn about the VIM way.
(use-package expand-region
:commands er/expand-region
:config
(setq expand-region-contract-fast-key "V"
expand-region-reset-fast-key "r")
:general
(global-leader
"v" 'er/expand-region)
)
Following packages are used majorly for programming
(use-package highlight-indent-guides
:defer t
:hook (prog-mode . highlight-indent-guides-mode)
:if (display-graphic-p)
:diminish
:config
(setq highlight-indent-guides-method 'character)
(setq highlight-indent-guides-responsive 'top)
(setq highlight-indent-guides-delay 0)
(setq highlight-indent-guides-auto-character-face-perc 7)
)
rainbow-delimiters is a “rainbow parentheses”-like mode which highlights delimiters such as parentheses, brackets or braces according to their depth.
(use-package rainbow-delimiters
:defer t
:hook (prog-mode . rainbow-delimiters-mode))
A Nerd Commenter emulation, help you comment code efficiently.
(use-package evil-nerd-commenter
:commands evilnc-comment-or-uncomment-lines
:general
(global-leader
";" '(evilnc-comment-or-uncomment-lines :which-key "evil-comment"))
)
Client for Language Server Protocol. lsp-mode aims to provide IDE-like experience by providing optional integration with the most popular Emacs packages like company, flycheck and projectile.
(use-package lsp-mode
:defer t
:hook
((lsp-mode . lsp-enable-which-key-integration))
:commands (lsp lsp-deferred)
:config
(progn
;; disable flycheck override with lsp checker in python-mode
(setq lsp-diagnostics-disabled-modes '(python-mode)
lsp-keep-workspace-alive nil
lsp-auto-guess-root t
lsp-ui-doc-enable nil
lsp-ui-doc-position 'at-point
lsp-signature-function 'lsp-signature-posframe
;; disable lsp company completion provider
lsp-completion-provider :none
)
)
:general
(global-major-leader :keymaps '(python-mode-map csharp-mode-map)
"l" '(:keymap lsp-command-map :wk "lsp"))
)
(use-package lsp-ui
:after lsp-mode
:commands lsp-ui-mode
:config
(setq lsp-ui-sideline-ignore-duplicate t)
)
Flycheck is a modern on-the-fly syntax checking extension for GNU Emacs, intended as replacement for the older Flymake extension which is part of GNU Emacs.
(use-package flycheck
:defer t
:init
(add-hook 'emacs-lisp-mode-hook #'flycheck-mode)
(add-hook 'sh-mode-hook #'flycheck-mode)
(add-hook 'yaml-mode-hook #'flycheck-mode)
(add-hook 'python-mode-hook #'(lambda ()
(flycheck-mode)
;; checker setup locally for python-mode
;; explicitly set flake8 checker
;; implicitly set mypy and pylint in checker chain
(setq-local flycheck-checker 'python-flake8)
;; safe time and just determine the line of error
(setq-local flycheck-highlighting-mode 'lines)
;; only apply syntax check on save and mode-enabled
(setq-local flycheck-check-syntax-automatically '(save mode-enabled)
flycheck-relevant-error-other-file-show nil)
;; disable highlight for flycheck infos
(face-remap-add-relative 'flycheck-info :underline nil)
(face-remap-add-relative 'flycheck-warning :underline nil)
))
:custom (flycheck-emacs-lisp-load-path 'inherit "necessary with straight.el")
:general
(global-major-leader :keymaps '(prog-mode-map yaml-mode-map)
"f" '(:ignore t :wk "flycheck")
"fe" '(flycheck-list-errors :wk "list errors"))
)
Lets you auto-format source code in many languages using the same command for all languages, instead of learning a different Emacs package and formatting command for each language.
(use-package format-all
:defer t
:init
(add-hook 'prog-mode-hook 'format-all-mode)
:hook (prog-mode . format-all-ensure-formatter)
:general
(global-major-leader
:keymaps
'emacs-lisp-mode-map
"b"
'(:ignore t :which-key "buffers")
"bf"
'format-all-buffer)
;; :hook ((python-mode) . format-all-mode)
)
(use-feature python
:defer t
:config
(progn
(setq python-prettify-symbols-alist '(("in" . ?∈) ("lambda" . ?λ) ("not in" . ?∉))))
:hook ((python-mode . semantic-mode)
(python-mode . prettify-symbols-mode)
(python-mode . (lambda ()
;; disable project errors on modeline
(setq-local lsp-modeline-diagnostics-enable nil
lsp-headerline-breadcrumb-enable nil))))
:init
(progn
(setq semantic-default-submodes nil)
(defun doq-region ()
"Doc the Python function content using `doq'"
(interactive)
(shell-command-on-region
;; beginning and end of buffer
(region-beginning)
(region-end)
;; command and parameters
"doq --omit self"
;; output buffer
(current-buffer)
;; replace and put no mark
'no-mark
;; name of the error buffer
"*Doq Error Buffer*"
;; show error buffer?
t))
)
:general
(global-major-leader :keymaps 'python-mode-map
"D" '(doq-region :wk "Add docstring to region"))
)
Emacs package which tries to suggest imports for unresolved symbols.
https://github.com/anachronic/importmagic.el
(use-package importmagic
:defer t
:init
(add-hook 'venv-postactivate-hook #'importmagic-mode)
:general
(global-major-leader :keymaps 'python-mode-map
"i" '(:ignore t :wk "importmagic")
"ii" '(importmagic-fix-symbol-at-point :wk "fix import at point")
"ia" '(importmagic-fix-imports :wk "fix all imports")))
(use-package lsp-pyright
:defer t
:init
(progn
(defun sys/lsp-start-pyright ()
;;Do not start lsp-mode when in consult preview
(unless (consult--preview-p)
(require 'lsp-pyright)
(lsp-deferred)))
)
:hook (python-mode . sys/lsp-start-pyright)
)
(use-package blacken :defer t :commands blacken-buffer
;; only format buffer when in python-mode
:init (add-hook 'before-save-hook #'(lambda () (when (derived-mode-p 'python-mode)
(blacken-buffer)
)))
)
https://github.com/ionrock/pytest-el
- FIX Package cl is deprecated
(use-package pytest :defer t
:commands (pytest-one ptytest-module pytest-all)
:config (add-to-list 'pytest-project-root-files "setup.cfg")
:general
(global-major-leader :keymaps 'python-mode-map
"t" '(:ignore t :which-key "testing")
"tt" 'pytest-one
"ta" 'pytest-all
"tb" 'pytest-module
)
)
(use-package py-isort
:commands py-isort-before-save
:init
;;isort checks if in python-mode
(add-hook 'before-save-hook 'py-isort-before-save))
Use lsp-mode and OmniSharp-Roslyn as a language server for C#.
Download OmniSharp-Roslyn from https://github.com/OmniSharp/omnisharp-roslyn/releases.
Because OmniSharp comes with its own embedded Mono with no references to other assemblies, we also need Mono (https://www.mono-project.com) installed.
Then tell the run script (*sys/omnisharp-server-path*
) where to find the OmniSharp executable and the path to Mono
by setting the env variable LSP_MONO_BASE_DIR
and LSP_OMNISHARP_EXE
respectively.
Also, tell lsp-mode where to find the OmniSharp executable by setting lsp-csharp-server-path
.
(Could be necessary to do chmod +x run
.)
(use-package csharp-mode
:if (bound-and-true-p *sys/omnisharp-server-path*)
:init
(progn
(setq lsp-csharp-server-path *sys/omnisharp-server-path*))
:defer t
:hook (csharp-mode . lsp-deferred)
:config
(progn
;; todo ignore unity folder then remove line
(setq lsp-enable-file-watchers nil)
;; (make-variable-buffer-local 'lsp-file-watch-ignored-directories)
;; (add-to-list 'lsp-file-watch-ignored-directories "[/\\\\]\\Library\\'")
(setq-local lsp-auto-guess-root t)
)
)
This package provides some Emacs integration with the Unity game engine. Most notably, it provides the ability to open source files from Unity in Emacs or Emacsclient while still generating the solution and project files for use with lsp-mode.
Generate a code binary ([emacs-user-directory]/var/unity/) with (unity-build-code-shim)
and select it in Unity’s preferences External Script Editor.
To open C# files with Emacs also add emacs +$(Line):$(Column) $(File)
to External Script Editor Args.
(use-package unity
:defer t
:init
(progn
(add-hook 'csharp-mode-hook #'unity-setup))
:straight
(unity
:type git
:host github
:repo "elizagamedev/unity.el"
:files ("*.el" "*.c")))
https://github.com/hlissner/emacs-doom-themes
(use-package doom-themes
:config
;; Global settings (defaults)
(setq doom-themes-enable-bold t ; if nil, bold is universally disabled
doom-themes-enable-italic t ; if nil, italics is universally disabled
doom-themes-treemacs-theme "doom-atom")
;; Enable flashing mode-line on errors
(doom-themes-visual-bell-config)
;; Corrects (and improves) org-mode's native fontification.
(doom-themes-org-config)
(doom-themes-treemacs-config)
:general
(global-leader "tt" '(:ignore t :which-key "choose themes")
"tt1" '((lambda () (interactive)
(load-theme 'doom-one t))
:which-key "doom-one")
"tt2" '((lambda () (interactive)
(load-theme 'doom-one-light t))
:which-key "doom-one-light")
"tt3" '((lambda () (interactive)
(load-theme 'doom-dracula t))
:which-key "doom-dracula")
)
)
A fancy and fast mode-line inspired by minimalism design.
Troubleshoot It could happen that when behind a proxy you have to manually download the fonts for the all-the-icons.el package included in doom-modeline.
(use-package doom-modeline
:defer t
:config
(progn
(setq doom-modeline-icon (display-graphic-p)
doom-modeline-buffer-file-name-style 'truncate-all
doom-modeline-buffer-encoding nil)
(set-face-attribute 'mode-line nil :family "JetBrains Mono" :height 100)
(set-face-attribute 'mode-line-inactive nil :family "JetBrains Mono" :height 100)
)
:hook
(after-init . doom-modeline-mode))
solaire-mode is an aesthetic plugin designed to visually distinguish “real” buffers (i.e. file-visiting code buffers where you do most of your work) from “unreal” buffers (like popups, sidebars, log buffers, terminals, etc) by giving the latter a slightly different – often darker – background
(use-package solaire-mode
:defer t)
Hydra helps to design transient key bindings.
https://github.com/abo-abo/hydra
(use-package hydra
:defer t
:config
(defhydra hydra-text-scale (:timeout 4)
"scale text"
("j" text-scale-increase "in")
("k" text-scale-decrease "out")
("q" nil "finished" :exit t))
:general
(global-leader
"ts" '(hydra-text-scale/body :which-key "scale text"))
)
(use-package ispell
:init
(progn
;; env variable is important for hunspell to find
;; the dictionary
(setenv "DICTIONARY" "en_US")
(add-to-list 'ispell-hunspell-dictionary-alist '("deutsch-hunspell"
"[[:alpha:]]"
"[^[:alpha:]]"
"[']"
t
("-d" "de_DE"); Dictionary file name
nil
iso-8859-1))
(add-to-list 'ispell-hunspell-dictionary-alist '("english-hunspell"
"[[:alpha:]]"
"[^[:alpha:]]"
"[']"
t
("-d" "en_US")
nil
iso-8859-1))
(setq ispell-program-name (executable-find "hunspell")
)))
Flyspell enables on-the-fly spell checking in Emacs by the means of a minor mode.
http://www-sop.inria.fr/members/Manuel.Serrano/flyspell/flyspell.html
- FIX ispell starts also in init major mode which is fundamental mode
- TODO add German dict to ispell
- TODO add cycling hydra menu for spell checking
(use-feature flyspell
:after ispell
:hook ((prog-mode . flyspell-prog-mode)
(text-mode . flyspell-mode))
:config
(progn
;; better performance, see https://www.emacswiki.org/emacs/FlySpell#h5o-3
(setq flyspell-issue-message-flag nil)))
Correcting misspelled words with flyspell using favourite interface. Helm in this case.
(use-package flyspell-correct
:defer t
:after flyspell
:general
(global-leader
"Sc" '(flyspell-correct-wrapper :which-key "check"))
)
Winner Mode is a global minor mode that allows you to “undo” and “redo” changes in WindowConfiguration (Changes in window state).
(use-package winner
:defer 3
:general
(global-leader
"wu" 'winner-undo
"wr" 'winner-redo)
:config
(add-to-list 'winner-boring-buffers "*Help*")
(winner-mode t))
Window numbers for Emacs: Navigate your windows and frames using numbers !
(use-package winum
:defer 1
:config
(setq winum-auto-assign-0-to-minibuffer nil
winum-auto-setup-mode-line nil
winum-ignored-buffers '(" *LV*" " *which-key*"))
(global-leader "0" 'winum-select-window-0
"1" 'winum-select-window-1
"2" 'winum-select-window-2
"3" 'winum-select-window-3
"4" 'winum-select-window-4
"5" 'winum-select-window-5
"6" 'winum-select-window-6
"7" 'winum-select-window-7
"8" 'winum-select-window-8
"9" 'winum-select-window-9)
;; Rename the entry winum 0-9 at SPC root, to 0..9
(push '(("\\(.*\\) 0" . "winum-select-window-0") . ("\\1 0..9" . "window 0..9"))
which-key-replacement-alist)
(push '((nil . "winum-select-window-[1-9]") . t) which-key-replacement-alist)
(winum-mode))
Enforce rules for popup windows
(use-package shackle :defer t
:commands (shackle-mode)
:custom (shackle-rules '(("*Flycheck errors*" :align below :size 0.15)
("*vterm*" :align below :size 0.3)
(magit-status-mode :select t)
))
:hook ((flycheck-mode global-flycheck-mode magit-mode vterm-mode) . shackle-mode))
Smartparens is a minor mode for dealing with pairs in Emacs.
(use-package smartparens
:defer t
:hook ((prog-mode org-mode) . smartparens-mode))
Show matching delimiters highlighted.
(use-feature paren
:defer 1
:config (show-paren-mode t))
(use-feature compile
:config
(setq compilation-scroll-output 'first-error)
(defun +compilation-colorize ()
"Colorize from `compilation-filter-start' to `point'."
(require 'ansi-color)
(let ((inhibit-read-only t))
(ansi-color-apply-on-region (point-min) (point-max))))
(add-hook 'compilation-filter-hook #'+compilation-colorize))
(use-package yaml-mode
:defer t
:mode ("\\.\\(yml\\|yaml\\)\\'" . yaml-mode)
:init
(add-hook 'yaml-mode-hook #'lsp)
)
The Perspective package provides multiple named workspaces (or “perspectives”) in Emacs, similar to multiple desktops in window managers like Awesome and XMonad, and Spaces on the Mac.
Perspective package is essentiell for buffer organisation. Therefore we load it early and before other packages like centaur-tab.
(use-package perspective
:hook (after-init . persp-mode)
:general
(global-leader
"pP" 'persp-switch)
:config
(progn
(setq persp-state-default-file (expand-file-name "persp-save-file.el" user-emacs-directory)
persp-modestring-short t
persp-mode-prefix-key "")
(add-hook 'kill-emacs-hook #'persp-state-save)
(unless (equal persp-mode t)
(persp-mode)))
)
(use-package dashboard
:demand t
:after all-the-icons
;; :if (< emacs-major-version 29)
:init
(progn
(add-hook 'dashboard-mode-hook #'(lambda () (setq-local global-hl-line-mode nil))))
:config
(progn
(defun dashboard-insert-hackernews (list-size)
"Request LIST-SIZE number of top-stories from hackernews."
;; TODO implement time interval check (e.g. update every 15 min)
;; only load one time
(when (equal dashboard-hackernews-init-state dashboard-hackernews-state)
(hackernews-get-topstories
list-size
(lambda (stories)
(when stories
(let* ((formatted-stories (dashboard-hackernews-add-formatted-stories-alist stories)))
(setq dashboard-hackernews-state formatted-stories)
;; update dashboard
(let ((dashboard-force-refresh t)) (dashboard-insert-startupify-lists))
)))))
;; TODO add short-cut
(dashboard-insert-section
"Hackernews:"
dashboard-hackernews-state
list-size
nil
(lambda (&rest ignore)
(let ((url (cdr (assoc 'url el))))
(browse-url url)
(kill-new url)
(message "[dashboard] copied '%s' to clipboard." url)))
(format "%s" (cdr (assoc 'formatted-string el))))
)
;; (add-to-list 'dashboard-item-generators '(hackernews . dashboard-insert-hackernews))
;; (add-to-list 'dashboard-items '(hackernews) t)
(setq dashboard-startup-banner
(expand-file-name "emacs.svg" (expand-file-name "media" user-emacs-directory)))
(setq dashboard-items '((recents . 5)
(projects . 5)
;; (hackernews . 30)
)
dashboard-set-heading-icons t
dashboard-set-file-icons t
dashboard-center-content t)
(dashboard-setup-startup-hook)
(dashboard-refresh-buffer)))
(use-package all-the-icons
:if (display-graphic-p)
:defer t)
Treemacs is a file and project explorer similar to NeoTree or vim’s NerdTree, but largely inspired by the Project Explorer in Eclipse.
Currently treemacs is only supported in projects by toggling the treemacs window. Further todos would be to make it possible to switch projects correctly (e.g. activating projectile-after-switch-project-hook) with treemacs.
(use-package treemacs :defer t
:commands (treemacs-select-window
treemacs-current-visibility)
:init
(progn
;; copied from spacemacs
(defun sys/treemacs-project-toggle ()
"Toggle and add the current project to treemacs if not already added."
(interactive)
(if (eq (treemacs-current-visibility) 'visible)
(delete-window (treemacs-get-local-window))
(let ((path (projectile-ensure-project (projectile-project-root)))
(name (projectile-project-name)))
(unless (treemacs-current-workspace)
(treemacs--find-workspace))
(treemacs-do-add-project-to-workspace path name)
(treemacs-select-window)))))
:config
(progn
(when (display-graphic-p)
(require 'all-the-icons)
(require 'treemacs-all-the-icons)
(treemacs-load-theme 'all-the-icons)))
:general
(global-leader
"pT" 'sys/treemacs-project-toggle))
(use-package treemacs-all-the-icons
:if (display-graphic-p)
:defer t)
avy is a GNU Emacs package for jumping to visible text using a char-based decision tree.
(use-package avy
:defer t
:general
(global-leader
"jj" '(evil-avy-goto-char-timer :wk "jump to char")
"jl" '(evil-avy-goto-line :wk "jump to line")
"jo" 'avy-pop-mark)
)
(use-package restart-emacs
:defer t
:general
(global-leader
"qq" '(save-buffers-kill-terminal :wk "quit Emacs")
"qR" '(restart-emacs :wk "restart Emacs"))
;; "qr" '((restart-emacs (list "--resume-layouts")) :wk "restart Emacs (resume layouts)"))
)
(use-feature emacs
:init
(progn
(defun sys/after-startup ()
(set-face-font 'default "JetBrains Mono")
(set-face-font 'fixed-pitch "JetBrains Mono")
(set-face-font 'variable-pitch "Gentium Book Basic")
(set-face-attribute 'default nil :font "JetBrains Mono" :height *sys/font-default-height*)
(set-face-attribute 'fixed-pitch nil :font "JetBrains Mono")
(set-face-attribute 'variable-pitch nil :font "Gentium Book Basic" :height *sys/font-variable-height*)
;; When buffer is closed, saves the cursor location
(save-place-mode t)
(toggle-frame-maximized)
(global-hl-line-mode t)
(solaire-global-mode t)
(global-auto-revert-mode t)
(load-theme 'doom-one-light t)
)
;; always allow 'y' instead of 'yes'.
(defalias 'yes-or-no-p 'y-or-n-p)
;; write over selected text on input... like all modern editors do
(delete-selection-mode t)
;; Don't persist a custom file, this bites me more than it helps
;; (setq custom-file (make-temp-file "")) ; use a temp file as a placeholder
(setq custom-safe-themes t) ; mark all themes as safe, since we can't persist now
(setq enable-local-variables :all) ; fix =defvar= warnings
;; stop emacs from littering the file system with backup files
(setq make-backup-files nil
;; auto-save-default nil
create-lockfiles nil)
;; follow symlinks
(setq vc-follow-symlinks t)
;; Silence native compilation compiler warnings for as they can be pretty disruptive.
(setq native-comp-async-report-warnings-errors nil)
;; Tramp config (own use-feature tramp package was to slow)
(setq tramp-default-method "ssh")
;; Disable version control on tramp buffers to avoid freezes.
(setq vc-ignore-dir-regexp
(format "\\(%s\\)\\|\\(%s\\)"
vc-ignore-dir-regexp
tramp-file-name-regexp))
;; enable commands in minibuffer
(setq enable-recursive-minibuffers t)
;; Emacs 28: Hide commands in M-x which do not work in the current mode.
;; Vertico commands are hidden in normal buffers.
(setq read-extended-command-predicate
#'command-completion-default-include-p)
(add-hook 'after-init-hook #'sys/after-startup)
(add-hook 'text-mode-hook #'(lambda ()
(setq-local line-spacing 0.1)))
(add-hook 'prog-mode-hook #'(lambda ()
(display-line-numbers-mode)
(setq-local line-spacing 0.1
display-line-numbers-width 2
)))
)
)
(use-package dockerfile-mode
:defer t
:mode "Dockerfile\\'")
Packages for better unicode support.
This package maps ordinary graphemes (characters) to fancy ligatures, if both your version of Emacs and the font supports it.
(use-package ligature
:defer t
:hook (prog-mode . ligature-mode)
:config
(progn
(ligature-set-ligatures '(prog-mode) '("|||>" "<|||" "<==>" "<!--" "####" "~~>" "***" "||=" "||>"
":::" "::=" "=:=" "===" "==>" "=!=" "=>>" "=<<" "=/=" "!=="
"!!." ">=>" ">>=" ">>>" ">>-" ">->" "->>" "-->" "---" "-<<"
"<~~" "<~>" "<*>" "<||" "<|>" "<$>" "<==" "<=>" "<=<" "<->"
"<--" "<-<" "<<=" "<<-" "<<<" "<+>" "</>" "###" "#_(" "..<"
"..." "+++" "/==" "///" "_|_" "www" "&&" "^=" "~~" "~@" "~="
"~>" "~-" "**" "*>" "*/" "||" "|}" "|]" "|=" "|>" "|-" "{|"
"[|" "]#" "::" ":=" ":>" ":<" "$>" "==" "=>" "!=" "!!" ">:"
">=" ">>" ">-" "-~" "-|" "->" "--" "-<" "<~" "<*" "<|" "<:"
"<$" "<=" "<>" "<-" "<<" "<+" "</" "#{" "#[" "#:" "#=" "#!"
"##" "#(" "#?" "#_" "%%" ".=" ".-" ".." ".?" "+>" "++" "?:"
"?=" "?." "??" ";;" "/*" "/=" "/>" "//" "__" "~~" "(*" "*)"
"\\\\" "://")))
:straight
(ligature
:type git
:host github
:repo "mickeynp/ligature.el"
:files (:defaults))
)
YASnippet is a template system for Emacs. It allows you to type an abbreviation and automatically expand it into function templates.
(use-package yasnippet
:defer t
:hook ((prog-mode org-mode) . yas-minor-mode)
:config
(progn
(setq yas-snippet-dirs (list (expand-file-name "snippets" user-emacs-directory)))
(yas-reload-all))
)
(use-package org
:defer t
:init
(progn
(add-hook 'org-mode-hook 'variable-pitch-mode))
:config
(progn
(let* ((variable-tuple '(:font "Gentium Book Basic"))
(headline `(:inherit default :weight bold)))
(custom-theme-set-faces
'user
`(org-level-8 ((t (,@headline ,@variable-tuple))))
`(org-level-7 ((t (,@headline ,@variable-tuple))))
`(org-level-6 ((t (,@headline ,@variable-tuple))))
`(org-level-5 ((t (,@headline ,@variable-tuple))))
`(org-level-4 ((t (,@headline ,@variable-tuple :height 1.1))))
`(org-level-3 ((t (,@headline ,@variable-tuple :height 1.25))))
`(org-level-2 ((t (,@headline ,@variable-tuple :height 1.5))))
`(org-level-1 ((t (,@headline ,@variable-tuple :height 1.75))))
`(org-document-title ((t (,@headline ,@variable-tuple :height 2.0 :underline nil))))))
(custom-theme-set-faces
'user
'(org-block ((t (:inherit fixed-pitch))))
'(org-code ((t (:inherit fixed-pitch))))
'(org-document-info-keyword ((t (:inherit (shadow fixed-pitch)))))
'(org-indent ((t (:inherit (org-hide fixed-pitch)))))
'(org-meta-line ((t (:inherit (font-lock-comment-face fixed-pitch)))))
'(org-property-value ((t (:inherit fixed-pitch))) t)
'(org-table ((t (:inherit fixed-pitch))))
'(org-special-keyword ((t (:inherit (font-lock-comment-face fixed-pitch)))))
'(org-tag ((t (:inherit (shadow fixed-pitch) :weight bold :height 0.8))))
'(org-verbatim ((t (:inherit (shadow fixed-pitch))))))
)
)
;; https://emacs.stackexchange.com/questions/28940/how-to-overwrite-properly-a-face-for-a-particular-theme
(use-package org-bullets
:defer t
:init
(add-hook 'org-mode-hook #'(lambda () (org-bullets-mode t))))
Request.el – Easy HTTP request for Emacs Lisp
(use-package request
:commands request
:defer t)
A modern list library for Emacs
(use-package dash
:defer t)
This projects aims to become an aesthetic, functional and efficient tabs plugin for Emacs with a lot of customization options.
(use-package centaur-tabs
:after perspective
:hook
(dashboard-mode . centaur-tabs-local-mode)
(vterm-mode . centaur-tabs-local-mode)
(helpful-mode . centaur-tabs-local-mode)
(projectile-mode . centaur-tabs-local-mode)
:config
(progn
;; TODO group by perspective and perspective-key
(defun centaur-tabs-buffer-groups ()
"`centaur-tabs-buffer-groups' control buffers' group rules.
Group centaur-tabs with mode if buffer is derived from `eshell-mode'
`emacs-lisp-mode' `dired-mode' `org-mode' `magit-mode'.
All buffer name start with * will group to \"Emacs\".
Other buffer group by `centaur-tabs-get-group-name' with project name."
(list
(cond
((memq major-mode '(magit-process-mode
magit-status-mode
magit-diff-mode
magit-log-mode
magit-file-mode
magit-blob-mode
magit-blame-mode
))
"Magit")
((and (string-equal "*" (substring (buffer-name) 0 1))
(not (string-match-p "*scratch*" (buffer-name))))
"Emacs")
((derived-mode-p 'eshell-mode)
"EShell")
((derived-mode-p 'emacs-lisp-mode)
"Elisp")
((derived-mode-p 'dired-mode)
"Dired")
((memq major-mode '(org-mode org-agenda-mode diary-mode))
"OrgMode")
(t
(centaur-tabs-get-group-name (current-buffer))))))
(setq centaur-tabs-style "bar"
centaur-tabs-set-icons t
;; centaur-tabs-height 15
centaur-tabs-gray-out-icons 'buffer
centaur-tabs-set-bar 'left
centaur-tabs-set-modified-marker t
centaur-tabs-close-button "✕"
centaur-tabs-modified-marker "⚠"
centaur-tabs-cycle-scope 'tabs)
;; (centaur-tabs-headline-match)
;; (centaur-tabs-group-by-projectile-project)
;; (centaur-tabs-buffer-groups)
(centaur-tabs-mode t))
:general
(general-def
"C-<tab>" 'centaur-tabs-forward
"C-S-<tab>" 'centaur-tabs-backward
"C-<iso-lefttab>" 'centaur-tabs-backward
"C-w" 'kill-current-buffer
:states '(normal)))
(use-package vertico
:hook (after-init . vertico-mode)
:config
(progn
;; Grow and shrink the Vertico minibuffer
(setq vertico-resize t)
)
:general
(general-def vertico-map :keymaps 'override
"C-j" #'vertico-next
"C-k" #'vertico-previous
)
)
(use-package mini-frame
;; workaround for strange behavior with wayland
;; https://github.com/muffinmad/emacs-mini-frame/issues/60
:if (not (string= (getenv "XDG_SESSION_TYPE") "wayland"))
:after evil
:hook (after-init . mini-frame-mode)
:init
(progn
;; (setq mini-frame-advice-functions '(read-from-minibuffer
;; read-string
;; yes-or-no-p
;; read-shell-command
;; )
;; )
)
:config
(progn
(setq mini-frame-show-parameters '((top . 0.2)
(width . 0.8)
(left . 0.5))
)
(add-to-list 'mini-frame-ignore-commands 'shell-command)
(add-to-list 'mini-frame-ignore-commands 'evil-ex)
))
(use-package marginalia
:hook (after-init . marginalia-mode))
(use-package orderless
:init
;; Configure a custom style dispatcher (see the Consult wiki)
;; (setq orderless-style-dispatchers '(+orderless-dispatch)
;; orderless-component-separator #'orderless-escapable-split-on-space)
(setq completion-styles '(orderless)
completion-category-overrides '((file (styles partial-completion)))))
;; Persist history over Emacs restarts. Vertico sorts by history position.
(use-package savehist
:hook (after-init . savehist-mode))
A simple Emacs minor mode for a nice writing environment.
(use-package olivetti
:defer t
:init
(progn
(setq olivetti-body-width 0.618))
:general
(global-leader "To" '(olivetti-mode :wk "olivetti mode"))
)
Nix-mode uses nixfmt
for formatting and rnix-lsp
as language server.
(use-package nix-mode
:defer t
:mode "\\.nix\\'"
:init
(add-hook 'nix-mode-hook #'(lambda ()
(setq-local format-all-formatters '(("Nix" alejandra)))
(lsp-deferred)))
:general
(global-major-leader :keymaps 'nix-mode-map
"b"
'(:ignore t :which-key "buffers")
"bf"
'format-all-buffer
)
:config
(electric-indent-mode -1)
)
This package provides direnv integration for emacs.
(use-package direnv
:hook (after-init . direnv-mode)
:config
(setq direnv-use-faces-in-summary nil)
)
Asynchronously download top stories from Hacker News.
(defconst hackernews-api-base "https://hacker-news.firebaseio.com")
(defconst hackernews-api-version "v0")
(defun hackernews-get-topstory-ids (list-size callback)
"Asynchronously request hackernews topstories and clip them to LIST-SIZE if necessary and call CALLBACK when request is done."
(let ((result (request (format "%s/%s/topstories.json" hackernews-api-base hackernews-api-version)
:type "GET"
:parser 'json-read
:error
(cl-function (lambda (&rest args &key error-thrown &allow-other-keys)
(message "hackernews-get-topstory-ids error: %S" error-thrown)))
:success
(cl-function
(lambda (&key data &allow-other-keys)
;; append converts vector into list
(funcall callback (-slice (append data nil) 0 list-size))
)))))))
(defun hackernews-get-items (list-of-ids callback)
"Asynchronously request LIST-OF-IDS from hackernews. After requests are completed call CALLBACK."
(setq hackernews-get-items--completed-items '())
(defun hackernews-get-items--callback (count-of-requests idx data callback)
(add-to-list 'hackernews-get-items--completed-items (list idx data) t)
(when (equal count-of-requests (length hackernews-get-items--completed-items))
(let* ((sorted-items (-sort (-on #'< #'-first-item) hackernews-get-items--completed-items))
(mapped-items (-map #'-last-item sorted-items))
(filtered-items (-non-nil mapped-items)))
(funcall callback filtered-items)
(setq hackernews-get-items--completed-items '()))
))
(dotimes (idx (length list-of-ids))
(let* ((count-of-requests (length list-of-ids))
(request-string (format "%s/%s/item/%s.json" hackernews-api-base hackernews-api-version (elt list-of-ids idx)))
(result (request request-string
:type "GET"
:parser 'json-read
:error
(cl-function (lambda (&rest args &key error-thrown &allow-other-keys)
(message "hackernews-get-items error: %S" error-thrown)
(hackernews-get-items--callback count-of-requests idx nil callback)
))
:success (cl-function
(lambda (&key data &allow-other-keys)
(hackernews-get-items--callback count-of-requests idx (append data nil) callback)))))))))
(defun hackernews-get-topstories (list-size callback)
"Asynchronously request LIST-SIZE topstories from Hackernews and call CALLBACK with stories when finished."
(hackernews-get-topstory-ids list-size
(lambda (list-of-ids)
(hackernews-get-items list-of-ids
(lambda (items)
(funcall callback items))))))
Utility and formatting functions to display downloaded stories from Hacker News.
(defconst dashboard-hackernews-init-state (list '((formatted-string . "Loading...")))
"Initial state of dashboard hackernews items.")
(defvar dashboard-hackernews-state dashboard-hackernews-init-state
"State of dashboard hackernews items.")
(defun dashboard-hackernews-add-formatted-story (max-digit-length item)
"Format hackernews story ITEM to the string '[score] title' by also respecting MAX-DIGIT-LENGTH to align all score strings."
;; format-string: [%MAX_DIGIT-LENGTHd] %s
(let* ((format-string (format "[%%%dd] %%s" max-digit-length))
(formatted-string (format format-string (cdr (assoc 'score item)) (decode-coding-string (cdr (assoc 'title item)) 'utf-8))))
;; Backquoting https://www.gnu.org/software/emacs/manual/html_node/elisp/Backquote.html
(push `(formatted-string . ,formatted-string) item)))
(defun dashboard-hackernews-add-formatted-stories-alist (stories)
"Add formatted-string key and value from story title to all STORIES."
(let* ((max-digit-length (dashboard-hackernews-max-digit-length stories))
(formatted-stories (mapcar (-partial 'dashboard-hackernews-add-formatted-story max-digit-length) stories)))
formatted-stories))
(defun dashboard-hackernews-max-digit-length (stories)
"Return the max digit length of all scores in STORIES."
(-max (-flatten (mapcar (lambda (story) (length (number-to-string (cdr (assoc 'score story))))) stories))))
This Dockerfile builds and sets up Emacs and various dependencies on a Debian system during make tangle
.
FROM debian:bullseye AS builder
ARG DEBIAN_FRONTEND=noninteractive
ARG EMACS_COMMIT=a45aed9
# for --shallow-since to speed up cloning
# example: --shallow-since "2 months" or "yyyy-MM-ddTHH:mm:ss"
ARG DATE=2021-06-01
# no --depth=1 because we want specific EMACS_COMMIT, could take longer
RUN apt-get update
RUN apt-get install -y git autoconf texinfo binutils flex bison \
libmpc-dev libmpfr-dev libgmp-dev coreutils make \
libtinfo5 texinfo libjpeg-dev libtiff-dev libgif-dev libxpm-dev \
libgtk-3-dev libgnutls28-dev libncurses5-dev libxml2-dev libxt-dev \
libjansson4 gcc-multilib g++-8 libcanberra-gtk3-module libjansson-dev \
#not build gcc
librsvg2-dev libpng-dev gcc-10 libgccjit0 libgccjit-10-dev
WORKDIR /
RUN git clone https://git.savannah.gnu.org/git/emacs.git \
-b master emacs-native --shallow-since "$DATE"
WORKDIR /emacs-native/
RUN git checkout "$EMACS_COMMIT"
RUN ./autogen.sh
RUN ./configure --with-native-compilation --with-mailutils --with-gnutls --with-cairo --prefix=/install_dir
RUN make NATIVE_FULL_AOT=1 -j"$(nproc)"
RUN make install-strip
# 2. Stage
FROM debian:bullseye
ARG DEBIAN_FRONTEND=noninteractive
# should be changed
ARG SSH_PASS=test1611312
RUN apt-get update && \
apt-get install -y libmpc3 libmpfr6 libgmp10 coreutils libjpeg62-turbo \
libtiff5 libgif7 libxpm4 libgtk-3-0 libgnutlsxx28 libncurses5 libxml2 \
libxt6 libjansson4 libcanberra-gtk3-module libx11-xcb1 binutils libc6-dev \
librsvg2-2 libpng-dev install-info texinfo gcc-10 libgccjit0 openssh-server xorg \
git vim curl unzip make cmake libtool-bin libvterm-dev \
# tackle bug when emacs freezes because of xserver and clipboard handling
xsel \
silversearcher-ag \
git-flow \
# build python3.7
make build-essential libssl-dev zlib1g-dev libbz2-dev libreadline-dev libsqlite3-dev wget curl llvm libncursesw5-dev xz-utils tk-dev libxml2-dev libxmlsec1-dev libffi-dev liblzma-dev \
&& apt-get clean && rm -rf /var/lib/apt/lists/*
RUN apt install -y npm ispell
RUN npm install -g pyright conventional-changelog-cli
COPY --from=builder /install_dir /install_dir
RUN curl -O https://www.python.org/ftp/python/3.7.3/Python-3.7.3.tar.xz
RUN tar -xf Python-3.7.3.tar.xz
RUN rm Python-3.7.3.tar.xz
WORKDIR /Python-3.7.3
# --enable-optimizations executes test for profiling to create a faster executable
# takes longer
RUN ./configure --enable-optimizations
RUN make -j "$(nproc)"
RUN make install
WORKDIR /
RUN rm -rf/Python-3.7.3
SHELL ["/bin/bash", "-o", "pipefail", "-c"]
RUN echo "root:$SSH_PASS" | chpasswd
RUN echo "PermitRootLogin yes" >> /etc/ssh/sshd_config
WORKDIR /root/
RUN pip3.7 install -U pip virtualenv virtualenvwrapper
#virtualenvwrapper is installed to /usr/local/bin/virtualenvwrapper.sh
# bashrc
RUN touch .bashrc
RUN echo "export PATH=/install_dir/bin/:${PATH}" >> .bashrc
RUN echo "export LD_LIBRARY_PATH=/install_dir/lib" >> .bashrc
RUN echo "export LIBRARY_PATH=/install_dir/lib" >> .bashrc
RUN echo "export VIRTUALENVWRAPPER_PYTHON=/usr/local/bin/python3.7" >> .bashrc
RUN echo "export WORKON_HOME=$HOME/.virtualenvs" >> .bashrc
RUN echo "export PROJECT_HOME=$HOME/Devel" >> .bashrc
RUN echo "source /usr/local/bin/virtualenvwrapper_lazy.sh" >> .bashrc
# Setting this is very important to allow x11 forwarding
RUN echo "X11UseLocalhost No">> /etc/ssh/sshd_config
RUN echo "X11Forwarding yes" >> /etc/ssh/sshd_config
RUN echo "AllowTcpForwarding yes" >> /etc/ssh/sshd_config
#TODO add proxy config
#Install font
RUN curl -o fonts.zip https://fonts.google.com/download?family=Source%20Code%20Pro
RUN unzip fonts.zip -d /usr/local/share/fonts
RUN fc-cache -f -v
RUN rm fonts.zip
EXPOSE 22
RUN service ssh start
#TODO logs nothing
CMD ["journalctl", "-t", "ssh", "-f"]