(require 'use-package-ensure)
(setq use-package-verbose t)
(setq use-package-always-ensure t)
use auto-package-update to keep your packages updated automatically
(use-package auto-package-update
:config
(setq auto-package-update-delete-old-versions t)
(setq auto-package-update-hide-results t)
(auto-package-update-maybe))
Always compile packages, and use the newest version available.
(use-package auto-compile
:config (auto-compile-on-load-mode)
(setq load-prefer-newer t))
use-package supports git repository
(use-package quelpa-use-package
:disabled t
:config
(setq use-package-ensure-function 'quelpa))
(setq comp-deferred-compilation t)
Use sensible-defaults.el for some basic settings.
(load-file "~/.emacs.d/sensible-defaults.el")
(sensible-defaults/use-all-settings)
(sensible-defaults/use-all-keybindings)
(sensible-defaults/backup-to-temp-directory)
(add-to-list 'load-path "~/.emacs.d/resources/")
Define a big ol’ bunch of handy utility functions.
(defun my/view-buffer-name ()
"Display the filename of the current buffer."
(interactive)
(message (buffer-file-name)))
(defun my/rename-file (new-name)
(interactive "FNew name: ")
(let ((filename (buffer-file-name)))
(if filename
(progn
(when (buffer-modified-p)
(save-buffer))
(rename-file filename new-name t)
(kill-buffer (current-buffer))
(find-file new-name)
(message "Renamed '%s' -> '%s'" filename new-name))
(message "Buffer '%s' isn't backed by a file!" (buffer-name)))))
(defun my/generate-scratch-buffer ()
"Create and switch to a temporary scratch buffer with a random
name."
(interactive)
(switch-to-buffer (make-temp-name "scratch-")))
(defun my/unfill-paragraph ()
"Takes a multi-line paragraph and makes it into a single line of text."
(interactive)
(let ((fill-column (point-max)))
(fill-paragraph nil)))
(defun my/visit-last-dired-file ()
"Open the last file in an open dired buffer."
(end-of-buffer)
(previous-line)
(dired-find-file))
(defun my/add-auto-mode (mode &rest patterns)
"Add entries to `auto-mode-alist' to use `MODE' for all given file `PATTERNS'."
(dolist (pattern patterns)
(add-to-list 'auto-mode-alist (cons pattern mode))))
(defun my/find-file-as-sudo ()
(interactive)
(let ((file-name (buffer-file-name)))
(when file-name
(find-alternate-file (concat "/sudo::" file-name)))))
(defun my/region-or-word ()
(if mark-active
(buffer-substring-no-properties (region-beginning)
(region-end))
(thing-at-point 'word)))
(defun my/insert-random-string (len)
"Insert a random alphanumeric string of length len."
(interactive)
(let ((mycharset "1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstyvwxyz"))
(dotimes (i len)
(insert (elt mycharset (random (length mycharset)))))))
(defun my/generate-password ()
"Insert a good alphanumeric password of length 30."
(interactive)
(my/insert-random-string 30))
(defun my/append-to-path (path)
"Add a path both to the $PATH variable and to Emacs' exec-path."
(setenv "PATH" (concat (getenv "PATH") ":" path))
(add-to-list 'exec-path path))
proxy settings
;; https://github.com/happyo/emacs.d/blob/main/lisp/init-proxy.el
(setq my/socks-proxy "127.0.0.1:7891") ; SOCKS proxy
(setq my/remote-host-name "mac")
(setq my/socks5 nil)
(defun my/new-socks5-proxy ()
(apply #'start-process "socks5-proxy"
(format "*socks5-proxy-%s*" my/remote-host-name)
"ssh" (list "-ND" my/socks-proxy my/remote-host-name)))
(defun proxy-socks-show ()
"Show SOCKS proxy."
(interactive)
(if (process-live-p my/socks5)
(message "Current SOCKS%d proxy is %s:%s"
(cadddr socks-server) (cadr socks-server) (caddr socks-server))
(message "No SOCKS proxy")))
(defun proxy-socks-enable ()
"Enable SOCKS proxy."
(interactive)
(unless (process-live-p my/socks5)
(setq my/socks5 (my/new-socks5-proxy)))
(require 'socks)
(setq url-gateway-method 'socks
socks-noproxy '("localhost"))
(let* ((proxy (split-string my/socks-proxy ":"))
(host (car proxy))
(port (string-to-number (cadr proxy))))
(setq socks-server `("Default server" ,host ,port 5)))
;; (setenv "all_proxy" (concat "socks5://" my/socks-proxy))
(proxy-socks-show))
(defun proxy-socks-disable ()
"Disable SOCKS proxy."
(interactive)
(when my/socks5
(kill-process my/socks5)
(setq my/socks5 nil))
(setq url-gateway-method 'native
socks-noproxy nil
socks-server nil)
;; (setenv "all_proxy" "")
(proxy-socks-show))
(defun proxy-socks-toggle ()
"Toggle SOCKS proxy."
(interactive)
(if (process-live-p my/socks5)
(proxy-socks-disable)
(proxy-socks-enable)))
I don’t usually use the menu or scroll bar, and they take up useful space.
(tool-bar-mode -1)
(if (display-graphic-p)
(progn (scroll-bar-mode -1))
(menu-bar-mode -1))
Why not?
(global-prettify-symbols-mode t)
better vertical border and region color
;; Set symbol for the border │ or ┃
(set-display-table-slot standard-display-table
'vertical-border
(make-glyph-code ?┃))
(defun transparency (value)
"Sets the transparency of the frame window. 0=transparent/100=opaque."
(interactive "Transparency Value 0 - 100 opaque:")
(set-frame-parameter (selected-frame) 'alpha value))
Those themes are what I like most.
(use-package modus-themes
:no-require t
:custom
(modus-themes-italic-constructs t)
(modus-themes-bold-constructs nil))
(use-package ef-themes
:no-require t)
Theme loading symbols.
(defvar theme-pool
'(modus-vivendi
;; modus-operandi
;; modus-operandi-tinted
;; modus-vivendi-tinted
;; modus-operandi-deuteranopia
;; modus-vivendi-deuteranopia
;; modus-operandi-tritanopia
;; modus-vivendi-tritanopia
ef-melissa-light
;; ef-dark
;; ef-day
;; ef-night
))
(defvar my/choosing-theme 'ef-melissa-light)
(defun my/ef-themes-custom-faces ()
(ef-themes-with-colors
(if (equal "ef-melissa-light" (symbol-name (car custom-enabled-themes)))
(custom-set-faces
`(font-lock-comment-face ((,c :inherit italic :foreground "grey"))))
(custom-set-faces
`(font-lock-comment-face ((,c :inherit italic :foreground ,fg-dim)))))
))
;; Using the hook lets our changes persist when we use the commands
;; `ef-themes-toggle', `ef-themes-select', and `ef-themes-load-random'.
(add-hook 'ef-themes-post-load-hook #'my/ef-themes-custom-faces)
(defun my/load-theme (theme)
(face-remap-add-relative 'vertical-border '(:inherit default))
(load-theme theme t)
(my/ef-themes-custom-faces))
(defun my/themes-toggle ()
"Toggle between themes defined in theme-pool."
(interactive)
(let* ((current-theme (car custom-enabled-themes))
(index (cl-position current-theme theme-pool)))
(if index
(setq my/choosing-theme
(nth (% (+ 1 index) (length theme-pool)) theme-pool))
(setq my/choosing-theme (car theme-pool)))
(disable-theme current-theme)
(my/load-theme my/choosing-theme)
(message "change theme to `%s'" my/choosing-theme)))
Using light theme on MacOS.
(defun my/apply-light-theme ()
(transparency 98)
(load-theme 'ef-day t))
(if (display-graphic-p)
(my/apply-light-theme)
(my/load-theme my/choosing-theme))
(if (daemonp)
(add-hook 'after-make-frame-functions
(lambda (frame)
(with-selected-frame frame
(my/load-theme my/choosing-theme)))))
Custom face when running in 256-color terminal
(defun my/load-custom-face-el ()
(if (and (eq my/choosing-theme 'nord)
(eq 256 (display-color-cells)))
(load-file "~/.emacs.d/custom-face.el")))
(if (daemonp)
(add-hook 'after-make-frame-functions
(lambda (frame)
(with-selected-frame
frame (my/load-custom-face-el))))
(my/load-custom-face-el))
(use-package minions
:custom
(minions-mode-line-delimiters (cons "" ""))
(minions-prominent-modes '(flymake-mode))
:config
(defun +set-minions-mode-line-lighter ()
(setq minions-mode-line-lighter
(if (display-graphic-p) "⚙" "#")))
(add-hook 'server-after-make-frame-hook #'+set-minions-mode-line-lighter)
(minions-mode 1))
(use-package time
:config
(display-time)
:custom
(display-time-default-load-average nil))
(size-indication-mode)
(column-number-mode)
(setq mode-line-frame-identification " ")
(setq mode-line-end-spaces "")
I’m partial to Inconsolata.
The standard text-scale-
functions just resize the text in the current buffer;
I’d generally like to resize the text in every buffer, and I usually want to
change the size of the modeline, too (this is especially helpful when
presenting). These functions and bindings let me resize everything all together!
Note that this overrides the default font-related keybindings from
sensible-defaults
.
(if (eq system-type 'gnu/linux)
(setq my/default-font "Ubuntu Mono")
(setq my/default-font "Iosevka SS09"))
(setq my/default-font-size 15)
(setq my/current-font-size my/default-font-size)
(setq my/font-change-increment 1.1)
(defun my/font-code ()
"Return a string representing the current font (like \"Inconsolata-14\")."
(concat my/default-font "-" (number-to-string my/current-font-size)))
(defun my/set-font-size ()
"Set the font to `my/default-font' at `my/current-font-size'.
Set that for the current frame, and also make it the default for
other, future frames."
(let ((font-code (my/font-code)))
(add-to-list 'default-frame-alist (cons 'font font-code))
(set-frame-font font-code)))
(defun my/reset-font-size ()
"Change font size back to `my/default-font-size'."
(interactive)
(setq my/current-font-size my/default-font-size)
(my/set-font-size))
(defun my/increase-font-size ()
"Increase current font size by a factor of `my/font-change-increment'."
(interactive)
(setq my/current-font-size
(ceiling (* my/current-font-size my/font-change-increment)))
(my/set-font-size))
(defun my/decrease-font-size ()
"Decrease current font size by a factor of `my/font-change-increment', down to a minimum size of 1."
(interactive)
(setq my/current-font-size
(max 1
(floor (/ my/current-font-size my/font-change-increment))))
(my/set-font-size))
(when (member my/default-font
(font-family-list))
(my/reset-font-size))
global-hl-line-mode
softly highlights the background color of the line
containing point. It makes it a bit easier to find point, and it’s useful when
pairing or presenting code.
(global-hl-line-mode)
Use the git-gutter
package to highlight changed-and-uncommitted lines when
programming.
(use-package git-gutter
:custom
;; │┃▕▐
(git-gutter:window-width 1)
(git-gutter:update-interval 2)
(git-gutter:always-show-separator t)
(git-gutter:added-sign "▐")
(git-gutter:deleted-sign "▐")
(git-gutter:modified-sign "▐")
:custom-face
(git-gutter:added ((t (:foreground "#438340" :background nil))))
(git-gutter:deleted ((t (:foreground "#815EDD" :background nil))))
(git-gutter:modified ((t (:foreground "#3471E3" :background nil))))
;; :hook
;; (git-gutter-mode
;; . (lambda ()
;; (git-gutter:set-window-margin (git-gutter:window-margin))))
:init
(global-git-gutter-mode t)
:bind
("C-x C-g" . git-gutter))
(setq-default display-line-numbers-width 4)
(setq display-line-numbers-grow-only t)
(add-hook 'text-mode-hook (lambda () (display-line-numbers-mode t)))
(add-hook 'prog-mode-hook (lambda () (display-line-numbers-mode t)))
(add-hook 'conf-mode-hook (lambda () (display-line-numbers-mode t)))
(defun symon--display-update-modify (orig-fun &rest args)
"symon step aside other message"
(if (current-message)
(when (string-match-p "\\(MEM:+.*CPU:+.*RX:+.*TX:+.*\\|Quit\\|Reverting\\ buffer\\|Mark\\ set\\)"
(current-message))
(apply orig-fun args))
(apply orig-fun args)))
(use-package symon
:load-path "~/.emacs.d/third_party/symon/"
:config
(symon-mode)
(advice-add 'symon--display-update
:around 'symon--display-update-modify))
(use-package hydra)
I use a few packages in virtually every programming or writing environment to manage the project, handle auto-completion, search for terms, and deal with version control. That’s all in here.
A GNU Emacs library to ensure environment variables inside Emacs look the same as in the user’s shell.
(use-package exec-path-from-shell
:if (eq system-type 'darwin)
:init
(exec-path-from-shell-initialize))
The package project-cmake incorporates the required logic to understand that a project is to be configured, built and tested using CMake and CTest.
(use-package project-cmake
:load-path "~/.emacs.d/third_party/project-cmake/"
:custom
(project-vc-merge-submodules nil)
(project-vc-extra-root-markers '(".dir-locals.el"))
(project-cmake-build-directory-name "build")
:config
;; Rebind C-x C-p to `project-prefix` to prevent mistyping and improve project navigation
(define-key global-map (kbd "C-x C-p") project-prefix-map)
(put 'compilation-environment 'safe-local-variable #'listp)
(put 'project-cmake-configuration-arguments 'safe-local-variable #'listp)
(put 'project-cmake-build-type 'safe-local-variable #'stringp)
(put 'project-cmake-kit 'safe-local-variable #'symbolp)
(put 'project-cmake-generator 'safe-local-variable #'stringp)
(put 'project-cmake-source-directory-name 'safe-local-variable #'stringp)
(project-cmake-scan-kits))
Install and configure deadgrep as an interface to ripgrep
.
(use-package deadgrep
:bind
("C-c s" . deadgrep)
("C-x s" . deadgrep))
(use-package wgrep-deadgrep)
Find file/directory and review Diff/Patch/Commit quickly everywhere.
(use-package find-file-in-project
:custom
(ffip-use-rust-fd t)
:bind
("C-x f" . find-file-in-project)
:config
(push "*/.cache" ffip-prune-patterns))
The dumb-jump
package works well enough in a ton of environments, and it
doesn’t require any additional setup. bounding as official recommendation.
(use-package dumb-jump
:commands (dumb-jump-xref-activate)
:custom
(dumb-jump-quiet t)
(dumb-jump-selector 'completing-read)
(dumb-jump-force-searcher 'rg)
:init
(add-hook 'xref-backend-functions #'dumb-jump-xref-activate))
(use-package flymake
:pin gnu
:init
(package-install 'flymake t) ;; install the latest gnu-flymake
:custom
(flymake-mode-line-lighter "Φ")
(flymake-margin-indicator-position 'right-margin)
(flymake-autoresize-margins t))
I use magit
to handle version control. It’s lovely, but I tweak a few things:
- I bring up the status menu with
C-x g
. - The default behavior of
magit
is to ask before pushing. I haven’t had any problems with accidentally pushing, so I’d rather not confirm that every time. - Per tpope’s suggestions, highlight commit text in the summary line that goes beyond 50 characters.
- I’d like to start in the insert state when writing a commit message.
(use-package magit
:bind
("C-x g" . magit-status)
:config
(use-package with-editor)
(setq magit-bind-magit-project-status nil)
:hook
(git-commit-mode . (lambda ()
"Set up the Git commit message buffer."
(setq fill-column 72)))
:custom
(magit-push-always-verify nil)
(git-commit-summary-max-length 50)
(magit-blame-goto-chunk-hook '(magit-blame-maybe-show-message)))
I’m also partial to git-timemachine
, which lets you quickly page through the
history of a file.
(use-package git-timemachine)
Some project is managed by git-lfs, we need to extent magit
(use-package magit-lfs
:after (magit))
I like tree-based undo management. I only rarely need it, but when I do, oh boy.
(use-package undo-tree
:custom
(global-undo-tree-mode t)
(undo-tree-auto-save-history nil)
(undo-tree-visualizer-relative-timestamps t)
(undo-tree-visualizer-timestamps t))
Indent with 2 spaces.
(add-hook 'sh-mode-hook
(lambda ()
(setq sh-basic-offset 2
sh-indentation 2)))
Force open shell in the current buffer
(push (cons "\\*shell\\*" display-buffer--same-window-action) display-buffer-alist)
(when (fboundp 'winner-mode)
(winner-mode 1))
Bazel is a build system created by Google:
(use-package bazel
:defer t)
show function and variable tree in side buffer
(use-package imenu-list
:init
(use-package nav-flash)
:bind ("C-c i" . imenu-list-smart-toggle)
:config
(setq imenu-list-focus-after-activation t)
(setq imenu-list-auto-update nil)
:hook
(imenu-after-jump . nav-flash-show))
read elf symbols
(use-package elf-mode
:demand
:config
(elf-setup-default))
(use-package demangle-mode
:config
(advice-add 'elf-mode :after 'demangle-mode)
(add-to-list 'demangle-languages
'("LLVM-IR"
"\\(?:_Z\\|\\(?:_GLOBAL_[._$][DI]_\\)\\)[_$[:alnum:]]+"
("llvm-cxxfilt" "--no-strip-underscore")))
:hook
(llvm-mode . demangle-mode))
(use-package plantuml-mode
:mode "\\.plantuml$"
:config
;; not promote to `utxt`.
(defun plantuml-jar-output-type-opt (output-type)
"Create the flag to pass to PlantUML according to OUTPUT-TYPE."
(concat "-t" output-type))
(setq plantuml-jar-path "~/.emacs.d/plantuml.jar")
(when (file-exists-p plantuml-jar-path)
(setq plantuml-default-exec-mode 'jar))
(add-to-list
'org-src-lang-modes '("plantuml" . plantuml)))
(let ((my/shell (if (eq system-type 'darwin)
"/bin/zsh"
"/bin/bash")))
(setq tramp-remote-shell my/shell)
(setq explicit-shell-file-name my/shell) ;; using bash by default.
(setq shell-file-name my/shell)) ;; using bash by default.
(use-package gerrit
:custom
(gerrit-use-ssl nil)
(gerrit-host "gerrit.houmo.ai") ;; is needed for REST API calls
:config
(put 'gerrit-project-to-local-workspace-alist 'safe-local-variable #'listp)
(setq gerrit-dashboard-query-alist
'(("Has draft comments" . "has:draft")
("Work in progress" . "is:open owner:self is:wip")
("Outgoing reviews" . "is:open owner:self -is:wip -is:ignored")
("Incoming reviews" . "is:open -owner:self -is:wip -is:ignored (reviewer:self OR assignee:self)")
("CCed on" . "is:open -is:ignored cc:self")
("toolchain/hmcc" . "project:toolchain/hmcc is:open limit:15")
("Recently closed" . "is:closed -is:ignored (-is:wip OR owner:self) (owner:self OR reviewer:self OR assignee:self OR cc:self) limit:15")))
(progn
(global-set-key (kbd "C-x i") 'gerrit-upload-transient)
(global-set-key (kbd "C-x o") 'gerrit-download)))
Add system path to emacs.
(if (eq system-type 'darwin)
(mapcar #'my/append-to-path
'("/usr/local/bin"
"/Library/TeX/texbin"
"/usr/local/opt/llvm/bin/")))
I like shallow indentation, but tabs are displayed as 8 characters by default. This reduces that.
(setq-default tab-width 4)
Treating terms in CamelCase symbols as separate words makes editing a little
easier for me, so I like to use subword-mode
everywhere.
(use-package subword
:config (global-subword-mode 1))
Compilation output goes to the *compilation*
buffer. I rarely have that window
selected, so the compilation output disappears past the bottom of the window.
This automatically scrolls the compilation window so I can always see the
output.
(setq compilation-scroll-output t)
Use smartparens
(use-package smartparens
:config
(smartparens-global-mode 1))
Emacs Polyglot: an Emacs LSP client that stays out of your way.
(defun my/test-then-add-eglot (mode-list program &optional command)
(when (executable-find program)
(if command
(add-to-list 'eglot-server-programs
(list mode-list program command))
(add-to-list 'eglot-server-programs
(list mode-list program)))
(mapcar
#'(lambda (sym)
(eval `(add-hook
(quote ,(intern (concat (symbol-name sym) "-hook")))
'eglot-ensure)))
mode-list)))
(use-package eglot
:pin gnu
:init
(package-install 'eglot t) ;; install the latest gnu-eglot
(use-package consult-eglot)
:commands
(eglot eglot-ensure)
;; :hook
;; (eglot-managed-mode . (lambda () (eglot-inlay-hints-mode -1)))
:bind (:map eglot-mode-map
("C-M-\\" . eglot-format)
("C-c e r" . eglot-rename)
("C-c e a" . eglot-code-actions)
("C-c e c" . eglot-reconnect)
("C-c e k" . eglot-shutdown)
("C-c e s" . consult-eglot-symbols)
("C-c e i" . eglot-inlay-hints-mode))
:custom
;; (eglot-autoshutdown t)
(eglot-events-buffer-size 0)
(eglot-extend-to-xref t)
(eglot-sync-connect nil)
:config
(add-to-list 'eglot-stay-out-of 'eldoc)
(my/test-then-add-eglot '(c-or-c++-mode c-mode c++-mode c++-ts-mode c-ts-mode) "clangd")
(my/test-then-add-eglot '(python-mode python-ts-mode) "pyright-langserver" "--stdio")
(my/test-then-add-eglot '(LaTeX-mode tex-mode context-mode texinfo-mode bibtex-mode) "texlab")
(my/test-then-add-eglot '(javascript-mode js-ts-mode) "typescript-language-server" "--stdio")
(my/test-then-add-eglot '(sh-mode bash-ts-mode) "bash-language-server" "start")
(my/test-then-add-eglot '(rust-ts-mode) "rust-analyzer")
(my/test-then-add-eglot '(yaml-ts-mode) "yaml-language-server" "--stdio")
(my/test-then-add-eglot '(dockerfile-ts-mode) "docker-langserver" "--stdio")
;; (my/test-then-add-eglot '(json-ts-mode) "vscode-json-language-server" "--stdio")
(my/test-then-add-eglot '(mlir-mode) "mlir-lsp-server")
(defun eglot-tblgen-command-args (interactive-p)
(let* ((build-directory (project-cmake-build-directory))
(database (expand-file-name "tablegen_compile_commands.yml"
build-directory)))
(list "tblgen-lsp-server"
(format "--tablegen-compilation-database=%s" database))))
(when (executable-find "tblgen-lsp-server")
(add-to-list 'eglot-server-programs
'((tablegen-mode) . eglot-tblgen-command-args))
(add-hook 'tablegen-mode-hook 'eglot-ensure))
(setq completion-category-defaults nil))
Dape is a debug adapter client for Emacs.
(use-package dape ;; should use gnu-dev:version
:custom
(dape-buffer-window-arrangement 'right) ;; Info buffers to the right
(dape-breakpoint-margin-string "●") ;; ◯
:config
;; (setq dape-debug t)
(put 'dape-command 'safe-local-variable #'listp)
(put 'dape-adapter-dir 'safe-local-variable #'stringp)
(put 'dape--overlay-arrow-position
'overlay-arrow-string ;; ▶ →
(propertize "▶" 'face 'dape-stack-trace-face)))
Use minibuffer as the interface to select from xref candidates.
(use-package xref)
Emacs-libvterm (vterm) is fully-fledged terminal emulator inside GNU Emacs based on libvterm, a C library. As a result of using compiled code (instead of elisp), emacs-libvterm is fully capable, fast, and it can seamlessly handle large outputs.
(defun my/vterm-env ()
(interactive)
(setq vterm-environment (cdr (assq 'vterm-env dir-local-variables-alist))) ;; FixMe
(vterm))
(define-derived-mode my/vterm-mode fundamental-mode "my/VTerm"
"Major mode for vterm buffer."
(hack-dir-local-variables)
(let ((vterm-env (cdr (assq 'vterm-environment dir-local-variables-alist))))
(when vterm-env
(make-local-variable 'vterm-environment)
(setq vterm-environment vterm-env)))
)
(use-package vterm
:init
(put 'vterm-environment 'safe-local-variable #'listp)
:bind ("C-c v" . vterm) ;; terminal
:custom
(vterm-max-scrollback 10000)
(vterm-kill-buffer-on-exit nil)
(vterm-always-compile-module t)
(term-copy-exclude-prompt t)
(vterm-buffer-name-string "*vterm %s*"))
Eat: Emulate A Terminal
(use-package eat
:bind (("C-c t" . eat-new-term)
(:map eat-line-mode-map ("C-x C-f" . find-file-at-point)))
:config
(define-key eat-line-mode-map [xterm-paste] #'xterm-paste)
(defun eat-new-term ()
"Create a new Eat terminal buffer."
(interactive)
(eat-other-window nil '(4)))
(defun my/eat-add-compilation-environment ()
(hack-dir-local-variables-non-file-buffer)
(setq-local font-lock-defaults '(nil t))
(setq-local process-environment
(append compilation-environment process-environment)))
:hook
;; https://codeberg.org/akib/emacs-eat/issues/129
(eat-exec . (lambda (&rest _) (eat-line-mode)))
(eat-mode . my/eat-add-compilation-environment)
:custom
(xterm-store-paste-on-kill-ring nil)
(eat-enable-auto-line-mode t)
(eat-shell-prompt-annotation-failure-margin-indicator "✘ ")
(eat-shell-prompt-annotation-running-margin-indicator "⧗ ")
(eat-shell-prompt-annotation-success-margin-indicator "✔ "))
configure comint-mode
(setq comint-buffer-maximum-size 8192)
(setq comint-prompt-read-only nil) ;; If non-nil, the comint prompt is read only.
(setq read-process-output-max (* 1024 1024))
(add-hook 'comint-output-filter-functions #'comint-osc-process-output)
(setq process-adaptive-read-buffering nil)
(use-package term
:config
(defun my/term ()
(interactive)
(let* ((title (generate-new-buffer-name "*terminal*"))
(buffer (get-buffer-create title)))
(cond ((not (term-check-proc buffer))
(with-current-buffer buffer
(term-mode)) ; Install local vars, mode, keymap, ...
(term-exec buffer title explicit-shell-file-name nil nil)))
(set-buffer buffer)
(term-line-mode)
(pop-to-buffer-same-window buffer)))
(defun my/add-compilation-environment ()
(hack-dir-local-variables-non-file-buffer)
(hl-line-mode -1)
(setq-local global-hl-line-mode nil)
(setq-local process-environment
(append compilation-environment process-environment)))
:bind (;; ("C-c t" . my/term)
(:map term-mode-map
("C-x C-f" . find-file-at-point)
("TAB" . completion-at-point)
("M-s". nil)))
:hook
(term-mode . my/add-compilation-environment))
Hydra short-keys
(defhydra hydra-hs (:idle 1.0)
"
Hide^^ ^Show^ ^Toggle^ ^Navigation^
----------------------------------------------------------------
_h_ hide all _s_ show all _t_oggle _n_ext line
_d_ hide block _a_ show block _p_revious line
_l_ hide level
_SPC_ cancel _q_ cancel
"
("s" hs-show-all)
("h" hs-hide-all)
("a" hs-show-block)
("d" hs-hide-block)
("t" hs-toggle-hiding)
("l" hs-hide-level)
("n" forward-line)
("p" (forward-line -1))
("SPC" nil)
("q" nil))
Emacs has a minor mode called hs-minor-mode that allows users to fold and hide blocks of text
(defun my/display-code-line-counts (ov)
(when (eq 'code (overlay-get ov 'hs))
(overlay-put ov 'display
(propertize
(format " … <%d>"
(count-lines (overlay-start ov)
(overlay-end ov)))
'face '(:background "#ff0066" :foreground "#000000")))))
(use-package hideshow
:hook (prog-mode . hs-minor-mode)
:bind (:map hs-minor-mode-map
("C-c @" . hydra-hs/body))
:config
(setq hs-set-up-overlay 'my/display-code-line-counts))
(use-package symbol-overlay
:bind (("M-i" . symbol-overlay-put)
("M-n" . symbol-overlay-jump-next)
("M-p" . symbol-overlay-jump-prev)
("M-N" . symbol-overlay-switch-forward)
("M-P" . symbol-overlay-switch-backward)
("M-C" . symbol-overlay-remove-all))
:custom
(symbol-overlay-priority 100))
using tree-sitter to manage Parser
(use-package treesit
:ensure nil
:if (and (fboundp 'treesit-available-p) (treesit-available-p))
:custom
;; (treesit-extra-load-path `(,treesit-langs-folder))
(treesit-max-buffer-size (* 100 1024 1024))
;; disable checking the ‘-*-’ line, this will disable loading .dir-locals.el
;; (enable-local-variables nil)
:config
(setq major-mode-remap-alist
(append major-mode-remap-alist
'((sh-mode . bash-ts-mode)
(javascript-mode . js-ts-mode)
(js-json-mode . json-ts-mode)
(python-mode . python-ts-mode)
(c-or-c++-mode . c++-ts-mode)
(c-mode . c-ts-mode)
(c++-mode . c++-ts-mode))))
(mapcar #'require '(cmake-ts-mode
dockerfile-ts-mode
rust-ts-mode
yaml-ts-mode))
:mode
("\\.h\\.inc\\'" . c++-ts-mode)
("\\.cpp\\.inc\\'" . c++-ts-mode)
("\\.hu$" . c++-ts-mode))
(use-package indent-bars
:config
(require 'indent-bars-ts)
:custom
(indent-bars-treesit-support t)
(indent-bars-no-descend-string t)
(indent-bars-treesit-scope '((python function_definition class_definition for_statement
if_statement with_statement while_statement)))
(indent-bars-treesit-ignore-blank-lines-types '("module"))
:config
(defun my/set-indent-bars-bg-fg ()
(setq
indent-bars-unspecified-fg-color (face-attribute 'default :foreground)
indent-bars-unspecified-bg-color (face-attribute 'default :background)
indent-bars-color '(highlight :face-bg t :blend 0.15)
indent-bars-highlight-current-depth '(:blend 0.5) ;; pump up the BG blend on current
;; blend=1: blend with BG only
indent-bars-color-by-depth '(:regexp "outline-\\([0-9]+\\)" :blend 1))
(indent-bars-reset))
(my/set-indent-bars-bg-fg)
:hook ((python-base-mode c-ts-base-mode) . indent-bars-mode))
(use-package visual-regexp
:bind
("C-c r" . vr/replace)
("C-c q" . vr/query-replace)
;; if you use multiple-cursors, this is for you:
("C-c m" . vr/mc-mark))
Pip can install binary file.
(defun my/get-first-valid-path (path-list)
;; get build path
;; this dirctiry should contain the excutable server and config file.
;; check path validation and return list.
(let ((path (cl-remove-if-not
(lambda (x)
(file-directory-p (eval x)))
path-list)))
(if path
(eval (car path))
nil)))
(use-package virtualenvwrapper
:config
(venv-initialize-interactive-shells) ;; if you want interactive shell support
(venv-initialize-eshell) ;; if you want eshell support
(setq venv-location '("~/py3/"
"~/py3.10/"))
(let ((venv-py (my/get-first-valid-path venv-location)))
(when venv-py
(venv-workon (car (last (split-string venv-py "\/") 2)))))
(my/test-then-add-eglot '(cmake-ts-mode) "cmake-language-server")
;; (my/test-then-add-eglot '(python-mode python-ts-mode) "pylsp")
)
Set ipython as interpreter
(use-package python
:config
(put 'python-shell-process-environment 'safe-local-variable #'listp)
:custom
(python-shell-completion-native-enable nil)
(python-shell-interpreter "ipython")
(python-shell-interpreter-args "--simple-prompt -i")
(python-indent-offset 4)
:hook
(python-mode . (lambda ()
(setq indent-tabs-mode nil)
(setq python-indent 4)
(setq tab-width 4))))
(use-package cython-mode)
(defun my/python-format ()
(interactive)
(if (region-active-p)
(python-black-partial-dwim)
(python-black-buffer)))
(defun my/python-format-key ()
(define-key (current-local-map) [remap eglot-format] 'my/python-format)
(local-set-key (kbd "C-M-\\") 'my/python-format))
(use-package python-black
:if (executable-find "black")
:init
(put 'python-black-extra-args 'safe-local-variable #'listp)
:after python
:hook
(python-mode . my/python-format-key)
(python-ts-mode . my/python-format-key))
LLVM-format-style
(defun llvm-lineup-statement (langelem)
(let ((in-assign (c-lineup-assignments langelem)))
(if (not in-assign)
'++
(aset in-assign 0
(+ (aref in-assign 0)
(* 2 c-basic-offset)))
in-assign)))
;; Add a cc-mode style for editing LLVM C and C++ code
(c-add-style "llvm.org"
'("gnu"
(fill-column . 80)
(c++-indent-level . 2)
(c-basic-offset . 2)
(indent-tabs-mode . nil)
(c-offsets-alist . ((arglist-intro . ++)
(innamespace . 0)
(member-init-intro . ++)
(statement-cont . llvm-lineup-statement)))))
clang-format OVERVIEW: A tool to format C/C++/Java/JavaScript/Objective-C/Protobuf/C# code.
(defun my/clang-format (&optional beg end)
(interactive
(and (region-active-p) (list (region-beginning) (region-end))))
(if (and beg end)
(clang-format beg end)
(clang-format-buffer)))
(defun my/clang-format-key ()
(when (current-local-map)
(define-key (current-local-map) [remap eglot-format] 'my/clang-format))
(local-set-key (kbd "C-M-\\") 'my/clang-format))
(use-package clang-format
:if (executable-find "clang-format")
:custom
(clang-format-fallback-style "llvm")
:hook ((c-mode c++-mode java-mode js-mode tablegen-mode c++-ts-mode c-ts-mode) .
my/clang-format-key))
Google Test For running Google Tests from a given buffer
(use-package gtest-mode
:load-path "~/.emacs.d/third_party/danielmartin-gtest"
:after cc-mode)
(use-package rust-playground
:bind
("C-x r p" . rust-playground)
:config
(add-to-list 'project-vc-extra-root-markers "Cargo.toml")
(defun rust-playground ()
"Run playground for Rust language in a new buffer."
(interactive)
;; get the dir name
(let* ((snippet-dir (rust-playground-dir-name))
(snippet-file-name (rust-playground-snippet-main-file-name snippet-dir))
(snippet-cargo-toml (rust-playground-toml-file-name snippet-dir)))
;; create a buffer for Cargo.toml and switch to it
(make-directory snippet-dir t)
(set-buffer (create-file-buffer snippet-cargo-toml))
(set-visited-file-name snippet-cargo-toml t)
(rust-playground-mode)
(rust-playground-insert-template-head "snippet of code" snippet-dir)
(insert rust-playground-cargo-toml-template)
(save-buffer)
;;now do src/main.rs
(make-directory (concat snippet-dir "src"))
(let ((new-buffer (create-file-buffer snippet-file-name)))
(set-buffer new-buffer)
(set-visited-file-name snippet-file-name t)
(rust-playground-insert-template-head "snippet of code" snippet-dir)
(insert rust-playground-main-rs-template)
(save-buffer)
(switch-to-buffer new-buffer)
;; back up to a good place to edit from
(backward-char 27)
(insert-tab))
(rust-playground-mode))))
Indent everything by 2 spaces.
(setq js-indent-level 2)
(add-hook 'coffee-mode-hook
(lambda ()
(yas-minor-mode 1)
(setq coffee-tab-width 2)))
rainbow-delimiters
is convenient for coloring matching parentheses.
(use-package rainbow-delimiters
:hook ((emacs-lisp-mode lisp-mode racket-mode) . rainbow-delimiters-mode))
If I’m writing in Emacs lisp I’d like to use eldoc-mode
to display
documentation.
(use-package eldoc
:config
(add-hook 'emacs-lisp-mode-hook 'eldoc-mode))
(use-package geiser
:config
(setq geiser-active-implementations '(mit chicken guile racket chez)))
If I’m in web-mode
, I’d like to:
- Color color-related words with
rainbow-mode
. - Still be able to run RSpec tests from
web-mode
buffers. - Indent everything with 2 spaces.
(use-package web-mode
:init
(use-package rainbow-mode)
(use-package rspec-mode)
:config
(add-hook 'web-mode-hook 'rainbow-mode)
(add-hook 'web-mode-hook 'rspec-mode)
(setq web-mode-markup-indent-offset 2)
:mode "\\.erb$"
"\\.html$"
"\\.php$"
"\\.rhtml$")
Use web-mode
with embedded Ruby files, regular HTML, and PHP.
(use-package flatbuffers-mode)
add Google protocol buffer support
(defun my/prototxt-mode-hook ()
(when (and (stringp buffer-file-name)
(string-match "\\.prototxt\\'" buffer-file-name))
(setq-local comment-start "# ")
(setq-local comment-start-skip "#+\\s-*")
(font-lock-add-keywords nil
'(("#.+" . font-lock-comment-face)))))
(use-package protobuf-mode
:mode "\\.prototxt$"
:hook
(protobuf-mode . my/prototxt-mode-hook))
(use-package rst)
These are syntax highlighting files for the Emacs and XEmacs editors.
(use-package llvm-mode
:mode "\\.ll$"
:load-path "~/.emacs.d/third_party/llvm-mode+")
(use-package tablegen-mode
:mode "\\.td$"
:hook
(tablegen-mode . turn-on-font-lock)
(tablegen-mode . git-gutter--turn-on)
(tablegen-mode . display-line-numbers--turn-on)
:load-path "~/.emacs.d/third_party/llvm-mode+")
(use-package llvm-mir-mode
:mode "\\.mir$"
:load-path "~/.emacs.d/third_party/llvm-mode+")
(use-package mlir-mode
:mode "\\.pdll$" "\\.mlir$"
:load-path "~/.emacs.d/third_party/llvm-mode+")
(use-package groovy-mode
:config
(let ((groovy-lsp "/usr/local/lib/groovy-language-server-all.jar"))
(when (file-exists-p groovy-lsp)
(add-to-list 'eglot-server-programs
`(groovy-mode . ("java" "-jar" ,groovy-lsp)))
(add-hook 'groovy-mode-hook 'eglot-ensure))))
(use-package lua-mode)
jq is a lightweight and flexible command-line JSON processor akin to sed,awk,grep, and friends for JSON data.
(use-package jq-mode
:bind ("C-c j" . jq-interactively)
:mode
("\\.jq$" . jq-mode))
(use-package nov
:mode
("\\.epub\\'" . nov-mode))
(defun my/internet-up-p (&optional host)
(= 0 (call-process "ping" nil nil nil "-c" "1" "-W" "1"
(if host host "www.wikipedia.org"))))
(use-package gptel
:defer nil
:bind (("C-c RET" . gptel-send)
("C-c g" . (lambda () (interactive) (gptel "*GPT*" nil nil t)))
("C-c <return>" . gptel-send)
("C-c C-<return>" . gptel-menu)
:map gptel-mode-map
("C-c C-x t" . gptel-set-topic))
:config
;; (setq gptel--debug t)
(setq gptel-default-mode 'org-mode)
(unless (my/internet-up-p)
(setq-default gptel-proxy
(format "socks5h://%s" my/socks-proxy)))
(setq gptel--openai
(gptel-make-openai "ChatGPT"
:key 'gptel-api-key
:stream t
:models '("o1-mini" "chatgpt-4o-latest" "gpt-4o")))
(defvar gptel--gemini
(gptel-make-gemini "Gemini"
:key 'gptel-api-key
:stream t
:models '("gemini-exp-1206" "gemini-1.5-pro-latest")))
(defvar gptel--anthropic
(gptel-make-anthropic "Claude"
:key 'gptel-api-key
:stream t
:models '("claude-3-5-sonnet-latest")))
(defvar gptel--deepseek
(gptel-make-openai "DeepSeek"
:stream t
:key 'gptel-api-key
:host "api.deepseek.com"
:endpoint "/chat/completions"
:models '("deepseek-coder" "deepseek-chat")))
(setq-default gptel-backend gptel--gemini)
(defun my/ediff-cleanup ()
(ediff-kill-buffer-carefully "*Ediff Control Panel*")
(ediff-kill-buffer-carefully "*ediff-errors*")
(ediff-kill-buffer-carefully "*ediff-diff*")
(ediff-kill-buffer-carefully "*Ediff Registry*")
(ediff-kill-buffer-carefully "*ediff-fine-diff*"))
(add-hook 'ediff-quit-hook #'my/ediff-cleanup)
:custom
(gptel-curl-file-size-threshold 2000000)
(gptel-model 'gpt-4o-mini)
(gptel-use-curl t)
(gptel-playback t))
This defines a code refactor function for Embark. The default gptel Ediff is incompatible with Eglot due to bugs in Eglot’s track-changes feature. We need to use the original buffer as the source of the diff, not the cloned one.
(defvar my/gptel--ediff-restore nil
"Function to restore window configuration after ediff.")
(defvar my/gptel--ediff-restore-cwc nil
"Variable to record window configuration before ediff.")
(defun my/get-full-line-region (buffer)
;; enlarge the region to hold full lines
(with-current-buffer buffer
(save-excursion
(let* ((reg-beg (region-beginning))
(reg-end (region-end))
(full-beg (progn (goto-char reg-beg)
(line-beginning-position)))
(full-end (if (eq (char-before reg-end) ?\n)
reg-end
(goto-char reg-end)
(line-beginning-position 2)))) ; include the newline char
(cons full-beg full-end)))))
(defun my/gpt-refacotr (gpt-backend rewrite-message prompt)
(let ((gptel-backend gpt-backend)
(gptel-model (car (gptel-backend-models gpt-backend))))
(setq my/gptel--ediff-restore-cwc (current-window-configuration))
(setq my/gptel--ediff-restore
(lambda ()
(when (window-configuration-p my/gptel--ediff-restore-cwc)
(set-window-configuration my/gptel--ediff-restore-cwc))
(ediff-kill-buffer-carefully "*gptel-rewrite-Region.B-*")
(remove-hook 'ediff-quit-hook my/gptel--ediff-restore)))
(message "Waiting for %s response..." gptel-model)
(gptel-request
;; o1 model does not support system message, but we can embeded it into the prompt.
(format "%s\n%s" rewrite-message prompt)
:system rewrite-message
:context (my/get-full-line-region (current-buffer))
:callback
(lambda (response info)
(if (not response)
(message "ChatGPT response error: %s" (plist-get info :status))
(let* ((gptel-buffer (plist-get info :buffer))
(gptel-bounds (plist-get info :context))
(buffer-mode
(buffer-local-value 'major-mode gptel-buffer)))
(pcase-let ((`(,new-buf ,new-beg ,new-end)
(with-current-buffer (get-buffer-create "*gptel-rewrite-Region.B-*")
(let ((inhibit-read-only t))
(erase-buffer)
(funcall buffer-mode)
(insert response)
(goto-char (point-min))
(list (current-buffer) (point-min) (point-max))))))
(require 'ediff)
(add-hook 'ediff-quit-hook my/gptel--ediff-restore)
(apply
#'ediff-regions-internal
gptel-buffer
(car gptel-bounds) (cdr gptel-bounds)
new-buf new-beg new-end
nil
;; (list 'ediff-regions-wordwise 'word-wise nil)
(list 'ediff-regions-wordwise nil nil)
))))))))
(use-package buildbot)
(use-package graphviz-dot-mode
:config
(setq graphviz-dot-indent-width 4))
There are numerous plugins available that function similarly to Godbolt, each with its own unique features and differences. You can explore Godbolt itself at the following link: [https://godbolt.org](https://godbolt.org).
(use-package compiler-explorer)
A supercharged implementation of the godbolt compiler-explorer for Emacs.
(use-package rmsbolt)
Beardbolt shows assembly output for given source code file, making it easy to see what the compiler is doing.
(use-package beardbolt
:if (eq system-type 'gnu/linux)
:load-path "~/.emacs.d/third_party/beardbolt/"
:config
(add-to-list 'beardbolt-languages '(c++-ts-mode beardbolt--c/c++-setup :base-cmd "g++" :language "c++")))
Including org-tempo restores the <s-style easy-templates that were deprecated in Org 9.2.
(use-package org
:ensure org-contrib
:config
(put 'narrow-to-region 'disabled nil)
(setq org-modules (cl-remove-duplicates
(append org-modules
'(org-tempo
ox-md
ox-beamer
org-capture
ox-latex
ox-odt
org-gnus))))
(define-key org-mode-map (kbd "C-j") nil)
(define-key org-mode-map (kbd "C-c C-j") nil)
(bind-keys*
("C-c l" . org-store-link)
("C-c C-l" . org-insert-link)))
I’d like the initial scratch buffer to be in Org:
(setq initial-major-mode 'org-mode)
I like to see an outline of pretty bullets instead of a list of asterisks.
(defun my/change-cdr-value (in-list key value)
(when (consp in-list)
(if (eq (car in-list) key)
(setcdr in-list value)
(progn
(my/change-cdr-value (car in-list) key value)
(my/change-cdr-value (cdr in-list) key value))
)))
(use-package org-bullets
:config
(add-hook 'org-mode-hook 'org-bullets-mode))
I like seeing a little downward-pointing arrow instead of the usual ellipsis
(...
) that org displays when there’s stuff under a header.
(setq org-ellipsis "…")
Use syntax highlighting in source blocks while editing.
(setq org-src-fontify-natively t)
Make TAB act as if it were issued in a buffer of the language’s major mode.
(setq org-src-tab-acts-natively t)
When editing a code snippet, use the current window rather than popping open a new one (which shows the same information).
(setq org-src-window-setup 'current-window)
Using build-in hide leading starts
(setq org-hide-leading-stars t)
(setq org-pretty-entities t)
(setq org-allow-promoting-top-level-subtree t)
(setq org-email-link-description-format "%c: %.50s")
Wrap long text lines.
(add-hook 'org-mode-hook 'visual-line-mode)
Bind a few handy keys.
(define-key global-map "\C-ca" 'org-agenda)
(define-key global-map "\C-cc" 'org-capture)
(define-key global-map "\C-cL" 'org-occur-link-in-agenda-files)
(define-key global-map "\C-c+" 'org-increase-number-at-point)
(define-key global-map "\C-c-" 'org-decrease-number-at-point)
Hit C-c g
to quickly open up my todo list.
(defun open-gtd-file ()
"Open the master org TODO list."
(interactive)
;; (my/copy-tasks-from-inbox)
(find-file org-gtd-file)
(end-of-buffer))
;; (global-set-key (kbd "C-c g") 'open-gtd-file)
Hit M-n
to quickly open up a capture template for a new todo.
(defun org-capture-todo ()
(interactive)
(org-capture :keys "t"))
(setq org-special-ctrl-a/e 'reversed)
(setq org-special-ctrl-k t)
(setq org-support-shift-select t)
Store my org files in ~/org
, maintain an inbox in Dropbox, define the location
of an index file (my main todo list), and archive finished tasks in
~/org/archive.org
.
(use-package org-pomodoro)
(setq org-directory "~/.Org")
(defun org-file-path (filename)
"Return the absolute address of an org file, given its relative name."
(let ((fun (lambda (x)
(concat (file-name-as-directory org-directory) x))))
(if (listp filename)
(mapcar fun filename)
(eval (list fun filename)))))
(setq org-gtd-file (org-file-path "gtd.org"))
(setq org-default-notes-file (org-file-path "note.org"))
(setq org-scheduled-past-days 100)
(setq org-stuck-projects '("+LEVEL=1" ("NEXT" "TODO" "DONE")))
(setq org-tag-persistent-alist '(("Write" . ?w) ("Read" . ?r)))
(setq org-tag-alist
'((:startgroup)
("Handson" . ?o)
(:grouptags)
("Write" . ?w) ("Code" . ?c) ("Tel" . ?t)
(:endgroup)
(:startgroup)
("Handsoff" . ?f)
(:grouptags)
("Read" . ?r) ("View" . ?v) ("Listen" . ?l)
(:endgroup)
("Mail" . ?@) ("Search" . ?s) ("Buy" . ?b)))
(setq org-tags-column -74)
(setq org-todo-keywords '((type "TODO" "STRT" "NEXT" "WAIT" "|" "DONE" "DELEGATED" "CANCELED")))
(setq org-todo-repeat-to-state t)
(setq org-use-property-inheritance t)
(setq org-use-sub-superscripts nil)
(setq org-todo-keyword-faces
'(("STRT" . (:foreground "white" :inverse-video t))
("NEXT" . (:foreground "brightcyan" :weight bold))
("WAIT" . (:foreground "#889699" :inverse-video t))
("CANCELED" . (:foreground "#889699"))))
(setq org-enforce-todo-dependencies t)
(setq org-enforce-todo-checkbox-dependencies t)
(setq org-deadline-warning-days 7)
Define a few common tasks as capture templates. Specifically
(setq org-capture-templates
'(("C" "Misc [inbox]" entry (file "~/.Org/inbox.org")
"* TODO %a\n :PROPERTIES:\n :CAPTURED: %U\n :END:\n"
:prepend t :immediate-finish t)
("c" "Misc [inbox] (edit)" entry (file "~/.Org/inbox.org")
"* TODO %?\n :PROPERTIES:\n :CAPTURED: %U\n :END:\n\n- %a" :prepend t)
("r" "RDV Perso" entry (file+headline "~/.Org/rdv.org" "RDV Perso")
"* RDV avec %:fromname %?\n :PROPERTIES:\n :CAPTURED: %U\n :END:\n\n- %a" :prepend t)
("R" "RDV Etalab" entry (file+headline "~/.Org/rdv-etalab.org" "RDV Etalab")
"* RDV avec %:fromname %?\n :PROPERTIES:\n :CAPTURED: %U\n :END:\n\n- %a" :prepend t)
("t" "Tickler" entry (file+headline "~/.Org/tickler.org" "Tickler")
"* %i%? \n :PROPERTIES:\n :CAPTURED: %U\n :END:\n\n- %a\n\n%i" :prepend t)))
(setq org-capture-templates-contexts
'(("r" ((in-mode . "gnus-summary-mode")
(in-mode . "gnus-article-mode")
(in-mode . "message-mode")))
("R" ((in-mode . "gnus-summary-mode")
(in-mode . "gnus-article-mode")
(in-mode . "message-mode")))))
set org-refile level deep to max 3
(setq org-refile-targets '((("~/.Org/gtd.org") . (:maxlevel . 3))
(("~/.Org/someday.org") . (:maxlevel . 1))
(("~/.Org/tickler.org") . (:maxlevel . 2))))
(setq org-refile-use-outline-path 'file)
(setq org-refile-allow-creating-parent-nodes 'confirm)
(setq org-refile-use-cache nil)
(setq org-reverse-note-order t)
(setq org-outline-path-complete-in-steps nil)
;; (setq org-archive-default-command 'org-archive-to-archive-sibling)
Hitting C-c C-x C-s
will mark a todo as done and move it to an appropriate
place in the archive.
(setq org-archive-location
(concat (org-file-path "archive.org") "::datetree/"))
(defun my/mark-done-and-archive ()
"Mark the state of an org-mode item as DONE and archive it."
(interactive)
(let ((ts (org-get-todo-state)))
(when (not (or (equal ts "DONE")
(equal ts "DELEGATED")
(equal ts "CANCELLED")))
(org-todo 'done)))
(org-archive-subtree))
(define-key org-mode-map (kbd "C-c C-x C-s") 'my/mark-done-and-archive)
Record the time that a todo was archived.
(setq org-log-done 'time)
auto save org file
(advice-add 'org-archive-subtree :after 'org-save-all-org-buffers)
(advice-add 'org-agenda-quit :before 'org-save-all-org-buffers)
(use-package org-super-agenda)
;; Set headlines to STRT when clocking in
(add-hook 'org-clock-in-hook (lambda () (org-todo "STRT")))
;; (setq org-agenda-diary-file "/home/guerry/org/rdv.org")
(setq org-agenda-dim-blocked-tasks nil)
(setq org-log-into-drawer "LOGBOOK")
(setq org-agenda-entry-text-maxlines 10)
(setq org-timer-default-timer 25)
(setq org-agenda-diary-file (org-file-path '("rdv.org" "gtd.org" "inbox.org")))
(setq org-agenda-files (org-file-path '("inbox.org" "gtd.org" "tickler.org" "someday.org")))
(setq org-agenda-prefix-format
'((agenda . " %i %-12:c%?-14t%s")
(timeline . " % s")
(todo . " %i %-14:c")
(tags . " %i %-14:c")
(search . " %i %-14:c")))
(setq org-agenda-restore-windows-after-quit t)
(setq org-agenda-show-inherited-tags nil)
(setq org-agenda-skip-deadline-if-done t)
(setq org-agenda-skip-deadline-prewarning-if-scheduled t)
(setq org-agenda-skip-scheduled-if-done t)
(setq org-agenda-skip-timestamp-if-done t)
(setq org-agenda-sorting-strategy
'((agenda time-up) (todo time-up) (tags time-up) (search time-up)))
(setq org-agenda-tags-todo-honor-ignore-options t)
(setq org-agenda-use-tag-inheritance nil)
(setq org-agenda-window-frame-fractions '(0.0 . 0.5))
(setq org-agenda-deadline-faces
'((1.0001 . org-warning) ; due yesterday or before
(0.0 . org-upcoming-deadline))) ; due today or later
list stuck projects
(setq org-stuck-projects
'("TODO={.+}/-DONE" nil nil "SCHEDULED:\\|DEADLINE:"))
using priority to organize my life
(setq org-agenda-custom-commands
`(
;; Week agenda for rendez-vous and tasks
("%" "Rendez-vous" agenda* "Week planning"
((org-agenda-span 'week)
(org-agenda-files (org-file-path '("rdv.org")))
;; (org-deadline-warning-days 3)
(org-agenda-sorting-strategy
'(todo-state-up time-up priority-down))))
("!" tags-todo "+DEADLINE<=\"<+7d>\"")
("=" tags-todo "+SCHEDULED<=\"<now>\"")
("?" "WAIT (gtd)" tags-todo "TODO={WAIT}"
((org-agenda-files (org-file-path '("gtd.org")))
(org-agenda-sorting-strategy
'(todo-state-up priority-down time-up))))
("@" tags-todo "+Mail+TODO={NEXT\\|STRT\\|WAIT}")
("w" "Report DONE/CANCELED/DELEGATED"
agenda ""
((org-agenda-span 'week)
(org-agenda-start-on-weekday 0)
(org-agenda-start-with-log-mode '(closed state clock))
(org-agenda-files (org-file-path '("gtd.org" "archive.org")))
(org-agenda-skip-function
'(org-agenda-skip-entry-if 'nottodo 'done))
(org-agenda-sorting-strategy '(timestamp-up))))
("
" . "Task and rendez-vous for today")
("
" "Travail (tout)" agenda "Tasks and rdv for today"
((org-agenda-span 1)
(org-agenda-files (org-file-path '("gtd.org" "my.org")))
(org-deadline-warning-days 3)
(org-agenda-sorting-strategy
'(todo-state-up time-up priority-down))))
("
" "Libre (tout)" agenda "Tasks and rdv for today"
((org-agenda-span 1)
(org-agenda-files (org-file-path '("libre.org")))
(org-deadline-warning-days 3)
(org-agenda-sorting-strategy
'(todo-state-up priority-down time-up))))
("e" "Etalab TODO" tags-todo "TODO={STRT\\|NEXT\\|TODO}"
((org-agenda-files (org-file-path '("libre.org")))
(org-agenda-category-filter-preset '("+ETL"))
(org-agenda-sorting-strategy
'(todo-state-up time-up priority-down))))
("n" "NEXT action" tags-todo "TODO={NEXT\\|STRT}"
((org-agenda-files (org-file-path '("gtd.org")))
(org-agenda-sorting-strategy
'(todo-state-down time-up priority-down))))
("x" . "Scheduled for today")
("xx" "Agenda work" agenda "Work scheduled for today"
((org-agenda-span 1)
(org-deadline-warning-days 3)
(org-agenda-entry-types '(:timestamp :scheduled))
(org-agenda-sorting-strategy
'(todo-state-up priority-down time-up))))
("xX" "Agenda libre" agenda "Libre scheduled for today"
((org-agenda-span 1)
(org-deadline-warning-days 3)
(org-agenda-files (org-file-path '("libre.org")))
(org-agenda-entry-types '(:timestamp :scheduled))
(org-agenda-sorting-strategy
'(todo-state-up priority-down time-up))))
("z" . "Deadlines for today")
("zz" "Work deadlines" agenda "Past/upcoming work deadlines"
((org-agenda-span 1)
(org-deadline-warning-days 15)
(org-agenda-entry-types '(:deadline))
(org-agenda-sorting-strategy
'(todo-state-up priority-down time-up))))
("zZ" "Libre deadlines" agenda "Past/upcoming leisure deadlines"
((org-agenda-span 1)
(org-deadline-warning-days 15)
(org-agenda-files (org-file-path '("libre.org")))
(org-agenda-entry-types '(:deadline))
(org-agenda-sorting-strategy
'(todo-state-up priority-down time-up))))
("r" . "Read")
("rr" tags-todo "+Read+TODO={NEXT\\|STRT}")
("rR" tags-todo "+Read+TODO={NEXT\\|STRT}"
((org-agenda-files '("~/org/libre.org"))))
("v" . "View")
("vv" tags-todo "+View+TODO={NEXT\\|STRT}")
("vV" tags-todo "+View+TODO={NEXT\\|STRT}"
((org-agenda-files (org-file-path '("libre.org")))))
("l" . "Listen")
("ll" tags-todo "+Listen+TODO={NEXT\\|STRT}")
("lL" tags-todo "+Listen+TODO={NEXT\\|STRT}"
((org-agenda-files (org-file-path '("libre.org")))))
("w" . "Write")
("ww" tags-todo "+Write+TODO={NEXT\\|STRT}")
("wW" tags-todo "+Write+TODO={NEXT\\|STRT}"
((org-agenda-files (org-file-path '("libre.org")))))
("c" . "Code")
("cc" tags-todo "+Code+TODO={NEXT\\|STRT}")
("cC" tags-todo "+Code+TODO={NEXT\\|STRT}"
((org-agenda-files (org-file-path '("libre.org")))))
))
ob-async enables asynchronous execution of org-babel src blocks, using :async
(use-package ob-async
:config
(require 'org))
Programming languages support
(org-babel-do-load-languages
'org-babel-load-languages
'((emacs-lisp . t)
(shell . t)
(org . t)
(scheme . t)
(python . t)
(dot . t)
(gnuplot . t)
(C . t)))
(setq org-babel-default-header-args
'((:session . "none")
(:results . "replace")
(:exports . "code")
(:cache . "no")
(:noweb . "yes")
(:hlines . "no")
(:tangle . "no")
(:padnewline . "yes")))
Don’t ask before evaluating code blocks.
(setq org-confirm-babel-evaluate nil)
Associate the “dot” language with the graphviz-dot
major mode.
(add-to-list 'org-src-lang-modes '("dot" . graphviz-dot))
Quickly insert a block of elisp:
(add-to-list 'org-structure-template-alist
'("el" . "src emacs-lisp"))
Hook to update all blocks before saving
(add-hook 'org-mode-hook
(lambda() (add-hook 'before-save-hook
'org-update-all-dblocks t t)))
(setq org-insert-heading-respect-content t)
(setq org-id-method 'uuidgen)
(setq org-id-uuid-program "uuidgen")
(setq org-use-speed-commands
(lambda nil
(and (looking-at org-outline-regexp-bol)
(not (org-in-src-block-p t)))))
(setq org-src-fontify-natively t)
(setq org-src-tab-acts-natively t)
(setq org-link-display-descriptive nil)
(setq org-loop-over-headlines-in-active-region t)
;; (setq org-create-formula-image-program 'dvipng) ;; imagemagick
(setq org-blank-before-new-entry '((heading . t) (plain-list-item . auto)))
(setq org-fontify-whole-heading-line t)
(setq org-global-properties '(("Effort_ALL" . "0:10 0:30 1:00 2:00 3:30 7:00")))
(setq org-confirm-elisp-link-function nil)
(setq org-confirm-shell-link-function nil)
Automatically parse the file after loading it.
(setq TeX-parse-self t)
Always use pdflatex
when compiling LaTeX documents. I don’t really have any
use for DVIs.
(setq TeX-PDF-mode t)
Open compiled PDFs in evince
instead of in the editor.
(add-hook 'org-mode-hook
'(lambda ()
(delete '("\\.pdf\\'" . default) org-file-apps)
(add-to-list 'org-file-apps '("\\.pdf\\'" . "evince %s"))))
Enable a minor mode for dealing with math (it adds a few useful keybindings), and always treat the current file as the “main” file. That’s intentional, since I’m usually actually in an org document.
(add-hook 'LaTeX-mode-hook
(lambda ()
(LaTeX-math-mode)
(setq TeX-master t)))
Translate regular ol’ straight quotes to typographically-correct curly quotes when exporting.
(setq org-export-with-smart-quotes t)
(setq org-export-default-language "en")
(setq org-export-backends '(latex odt icalendar html ascii))
(setq org-export-with-archived-trees nil)
(setq org-export-with-drawers '("HIDE"))
(setq org-export-with-sub-superscripts nil)
(setq org-export-with-tags 'not-in-toc)
(setq org-export-with-timestamps t)
(setq org-export-with-toc nil)
(setq org-export-with-priority t)
(setq org-export-dispatch-use-expert-ui t)
(setq org-export-babel-evaluate t)
(setq org-export-allow-bind-keywords t)
(setq org-publish-list-skipped-files nil)
(setq org-fast-tag-selection-single-key 'expert)
(setq org-fontify-done-headline t)
(setq org-footnote-auto-label 'confirm)
(setq org-footnote-auto-adjust t)
(setq org-hide-emphasis-markers t)
(setq org-hide-macro-markers t)
(setq org-icalendar-include-todo 'all)
(setq org-link-frame-setup '((gnus . gnus) (file . find-file-other-window)))
(setq org-log-note-headings
'((done . "CLOSING NOTE %t") (state . "State %-12s %t") (clock-out . "")))
(setq org-footnote-section "Notes")
(setq org-attach-directory "~/.Org/data/")
(setq org-link-display-descriptive nil)
(setq org-export-filter-planning-functions
'(my/org-html-export-planning))
(setq org-export-with-broken-links t)
Don’t include a footer with my contact and publishing information at the bottom of every exported HTML document.
(setq org-html-head "")
(setq org-html-head-include-default-style nil)
(setq org-html-postamble nil)
(setq org-html-table-row-tags
(cons '(cond (top-row-p "<tr class=\"tr-top\">")
(bottom-row-p "<tr class=\"tr-bottom\">")
(t (if (= (mod row-number 2) 1)
"<tr class=\"tr-odd\">"
"<tr class=\"tr-even\">")))
"</tr>"))
(setq org-gnus-prefer-web-links nil)
(setq org-html-head-include-default-style nil)
(setq org-html-head-include-scripts nil)
(defun my/org-html-export-planning (planning-string backend info)
(when (string-match "<p>.+><\\([0-9]+-[0-9]+-[0-9]+\\)[^>]+><.+</p>" planning-string)
(concat "<span class=\"planning\">" (match-string 1 planning-string) "</span>")))
Exporting to HTML and opening the results triggers /usr/bin/sensible-browser
,
which checks the $BROWSER
environment variable to choose the right browser.
I’d like to always use Firefox, so:
(setenv "BROWSER" "safari")
I want to produce PDFs with syntax highlighting in the code. The best way to do
that seems to be with the minted
package, but that package shells out to
pygments
to do the actual work. pdflatex
usually disallows shell commands;
this enables that.
(setq org-latex-listings t)
(add-to-list 'org-latex-classes
'("my-letter"
"\\documentclass\{scrlttr2\}
\\usepackage[english,frenchb]{babel}
\[NO-DEFAULT-PACKAGES]
\[NO-PACKAGES]
\[EXTRA]"))
(setq org-latex-pdf-process
'("xelatex -shell-escape -interaction nonstopmode -output-directory %o %f"
"xelatex -shell-escape -interaction nonstopmode -output-directory %o %f"
"xelatex -shell-escape -interaction nonstopmode -output-directory %o %f"))
Include the minted
package in all of my LaTeX exports.
(add-to-list 'org-latex-packages-alist '("" "minted"))
(setq org-latex-listings 'minted)
Write raw LaTex document using auctex
(use-package tex
:ensure auctex
:custom
(TeX-engine 'xetex)
:config
(setq TeX-auto-save t)
(setq TeX-parse-self t)
(setq-default TeX-master nil)
(add-hook 'LaTeX-mode-hook 'visual-line-mode)
(add-hook 'LaTeX-mode-hook 'LaTeX-math-mode)
(add-hook 'LaTeX-mode-hook 'turn-on-reftex)
(setq reftex-plug-into-AUCTeX t))
(setq TeX-source-correlate-method (quote synctex))
(setq TeX-source-correlate-mode t)
(setq TeX-source-correlate-start-server t)
(setq TeX-view-program-selection '((output-pdf "PDF Viewer")))
(setq TeX-view-program-list
'(("PDF Viewer" "/Applications/Skim.app/Contents/SharedSupport/displayline -b -g %n %o %b")))
Set reftex References, labels, citations
;; (use-package org-ref)
(add-hook 'LaTeX-mode-hook 'turn-on-reftex) ; with Auctex Latex mode
(add-hook 'latex-mode-hook 'turn-on-reftex) ; with Emacs latex mode
(setq reftex-plug-into-AUCTeX t)
I write prose in several modes: I might be editing an Org document, or a commit message, or an email. These are the main ones, with sub-items being derived from their parents:
git-commit-mode
text-mode
markdown-mode
gfm-mode
message-mode
mu4e-compose-mode
org-mode
Recall that derived modes “inherit” their parent’s hooks, so a hook added onto
e.g. text-mode
will also be executed by mu4e-compose-mode
.
There are some exceptions, but I can usually associate a hook with every prose-related mode, so I store those in a list:
(defvar prose-modes
'(gfm-mode
git-commit-mode
org-mode
markdown-mode
message-mode
text-mode))
(defvar prose-mode-hooks
(mapcar (lambda (mode) (intern (format "%s-hook" mode)))
prose-modes))
I want to make sure that I’ve enabled spell-checking if I’m editing text, composing an email, or authoring a Git commit.
(use-package flyspell
:if (eq system-type 'darwin)
:config
;; (use-package flyspell-lazy)
;; (flyspell-lazy-mode 1)
:config
(setq ispell-dictionary "en_US"
ispell-program-name "aspell"
ispell-extra-args '("--camel-case" "--sug-mode=ultra")
flyspell-issue-message-flag nil
flyspell-mode-line-string nil
flyspell-duplicate-distance 0)
(add-to-list 'flyspell-delayed-commands 'scroll-down-command)
(add-to-list 'flyspell-delayed-commands 'scroll-up-command)
(add-to-list 'flyspell-delayed-commands 'previous-line)
(add-to-list 'flyspell-delayed-commands 'next-line)
(add-to-list 'flyspell-delayed-commands 'line-move)
(add-to-list 'flyspell-delayed-commands 'compilation-read-command)
(add-to-list 'flyspell-delayed-commands 'completion-at-point-functions)
:hook
(prog-mode . (lambda ()
(unless (derived-mode-p 'json-ts-mode)
(flyspell-prog-mode))))
(text-mode . flyspell-mode))
Jinx is a fast just-in-time spell-checker for Emacs. Jinx highlights misspelled words in the text of the visible portion of the buffer.
(use-package jinx
:if (eq system-type 'gnu/linux)
:hook (emacs-startup . global-jinx-mode)
:config
;; (length (jinx--get-overlays (point-min) (point-max) nil))
;; (length (jinx--get-overlays (point-min) (point-max) t))
;; (length (jinx--force-overlays (point-min) (point-max) :check t))
(setq jinx-camel-modes
(append jinx-camel-modes
'(cc-ts-mode c-mode c-or-c++-mode c++-mode c++-ts-mode c-ts-mode)))
(defun jinx--mode-line-format ()
"updata the spelling check error informatin."
(format "J{%d}" (length (jinx--get-overlays (window-start) (window-end) nil))))
(add-to-list 'mode-line-misc-info
'(jinx-mode
(:eval (jinx--mode-line-format))) t)
:bind (:map jinx-mode-map
("M-$" . jinx-correct)
("M-p" . nil)
("M-n" . nil)
("C-M-c" . jinx-correct)
("C-M-p" . jinx-previous)
("C-M-n" . jinx-next)))
A minimalists’ Emacs extension to search http://www.bing.com/dict. Support English to Chinese and Chinese to English.
(use-package bing-dict
:config
;; from fanyi.el
(defun bing-dict-dwim ()
"A more dwim version of `bing-dict'.
No prompt if the region is active or `thing-at-point' returns
non-nil."
(interactive)
(if-let* ((word (if (use-region-p)
(buffer-substring-no-properties (region-beginning) (region-end))
(thing-at-point 'word t))))
(progn
(bing-dict-brief word))
(call-interactively #'bing-dict-brief)))
:bind ("C-c d" . 'bing-dict-dwim))
fanyi.el is a simple yet powerful multi-dictionaries interface for Emacs, currently it includes: 海词 有道同义词, Unofficial API etymonline Longman.
(use-package fanyi
:config
:bind ("C-c D" . 'fanyi-dwim2))
AutoFillMode
automatically wraps paragraphs, kinda like hitting M-q
. I wrap
a lot of paragraphs, so this automatically wraps ‘em when I’m writing text,
Markdown, or Org.
(dolist (hook prose-mode-hooks)
(add-hook hook 'turn-on-auto-fill))
Enable Org-style tables.
(add-hook 'git-commit-mode-hook 'orgtbl-mode)
(add-hook 'markdown-mode-hook 'orgtbl-mode)
(add-hook 'message-mode-hook 'orgtbl-mode)
Use the =orgalist= package for more convenient list manipulation.
(use-package orgalist
:config
(add-hook 'git-commit-mode-hook 'orgalist-mode)
(add-hook 'markdown-mode-hook 'orgalist-mode)
(add-hook 'message-mode-hook 'orgalist-mode))
Because I can’t always use org
.
- Associate
.md
files with GitHub-flavored Markdown. - Use
pandoc
to render the results. - Leave the code block font unchanged.
(use-package markdown-mode
:commands gfm-mode
:mode (("\\.md$" . gfm-mode))
:config
(setq markdown-command "pandoc --standalone --mathjax --from=markdown"
markdown-fontify-code-blocks-natively t))
Successive calls to cycle-spacing
rotate between changing the whitespace
around point to:
- A single space,
- No spaces, or
- The original spacing.
Binding this to M-SPC
is strictly better than the original binding of
just-one-space
.
(global-set-key (kbd "M-SPC") 'cycle-spacing)
(put 'downcase-region 'disabled nil)
(put 'upcase-region 'disabled nil)
(use-package deft
:bind ("C-c n" . deft)
:commands (deft)
:config
(setq deft-directory "~/.notes"
deft-recursive t
deft-use-filename-as-title t))
Scroll preserve screen position or not.
(setq scroll-preserve-screen-position t)
(defhydra hydra-scroll ()
"move"
;; scroll preserve t
("n" scroll-up-line)
("p" scroll-down-line)
;; scroll preserve always
("N" (progn
(next-line)
(scroll-up-line)))
("P" (progn
(previous-line)
(scroll-down-line)))
("v" scroll-up-command)
("V" scroll-down-command)
("q" nil "quit"))
(global-set-key (kbd "C-c b") #'hydra-scroll/body)
configuration
I futz around with my dotfiles a lot. This binds C-c f
to quickly open my
Emacs configuration file.
(defun my/visit-emacs-config ()
(interactive)
(find-file "~/.emacs.d/configuration.org"))
(global-set-key (kbd "C-c f") 'my/visit-emacs-config)
Assume that I always want to kill the current buffer when hitting C-x k
.
(defun my/kill-current-buffer ()
"Kill the current buffer without prompting."
(interactive)
(kill-buffer (current-buffer)))
(global-set-key (kbd "C-x k") 'my/kill-current-buffer)
The helpful
package provides, among other things, more context in Help
buffers.
(use-package helpful
:bind
(("C-h f" . helpful-callable)
("C-h v" . helpful-variable)
("C-h k" . helpful-key)))
Never use tabs. Tabs are the devil’s whitespace.
(setq-default indent-tabs-mode nil)
which-key displays the possible completions for a long keybinding. That’s really helpful for some modes (like project, for example).
(use-package which-key
:config (which-key-mode))
;; A few more useful configurations...
(use-package emacs
:init
(fido-vertical-mode t)
;; set completion case insensitive
(setq completion-auto-help nil)
(setq completion-ignore-case t)
(setq read-file-name-completion-ignore-case t)
(setq read-buffer-completion-ignore-case t)
;; Do not allow the cursor in the minibuffer prompt
(setq minibuffer-prompt-properties
'(read-only t cursor-intangible t face minibuffer-prompt))
(add-hook 'minibuffer-setup-hook #'cursor-intangible-mode)
;; Emacs 28: Hide commands in M-x which do not work in the current mode.
(setq read-extended-command-predicate
#'command-completion-default-include-p))
(use-package icomplete
:config
(defun fussy-fido-setup ()
"Use `fussy' with `fido-mode'."
(setq-local completion-styles '(fussy)))
(advice-add 'icomplete--fido-mode-setup :after 'fussy-fido-setup)
(add-to-list 'completion-ignored-extensions "../")
;; :bind
;; (:map icomplete-minibuffer-map
;; ("TAB" . icomplete-force-complete)
;; ([tab] . icomplete-force-complete))
:custom
(icomplete-tidy-shadowed-file-names t)
(icomplete-show-matches-on-no-input t)
(icomplete-compute-delay 0)
(icomplete-delay-completions-threshold 50))
(defun my/quit-all ()
(interactive)
(if (eq last-command 'my/quit-all)
(cond ((region-active-p)
(deactivate-mark))
((> (minibuffer-depth) 0)
(abort-recursive-edit))
(current-prefix-arg
nil)
((> (recursion-depth) 0)
(exit-recursive-edit))
(buffer-quit-function
(funcall buffer-quit-function)))
(keyboard-quit)))
(setq enable-recursive-minibuffers t)
(global-set-key (kbd "C-g") 'my/quit-all)
(if (eq system-type 'darwin)
(setq fuz-core-bin "/usr/local/lib/libfuz_core.dylib")
(setq fuz-core-bin "/usr/local/lib/libfuz_core.so"))
(use-package fussy
:config
(when (file-exists-p fuz-core-bin)
(use-package fuz
:config
(load fuz-core-bin nil t))
(setq fussy-score-fn 'fussy-fuz-score))
(add-hook 'minibuffer-setup-hook
(lambda ()
(setq-local fussy-use-cache nil)))
:custom
(fussy-use-cache t)
(fussy-compare-same-score-fn 'fussy-histlen->strlen<)
(fussy-filter-fn 'fussy-filter-default)
(fussy-default-regex-fn 'fussy-pattern-flex-1)
(completion-styles '(fussy))
(completion-category-defaults nil)
(completion-category-overrides nil))
;; For cache functionality.
(advice-add 'corfu--capf-wrapper :before 'fussy-wipe-cache)
(add-hook 'corfu-mode-hook
(lambda ()
(setq-local fussy-max-candidate-limit 5000
fussy-default-regex-fn 'fussy-pattern-first-letter
fussy-prefer-prefix nil)))
Marginalia are marks or annotations placed at the margin of the page of a book or in this case helpful colorful annotations placed at the margin of the minibuffer for your completion candidates.
(use-package marginalia
:custom
(marginalia-field-width 120)
:init
;; Must be in the :init section of use-package such that the mode gets
;; enabled right away. Note that this forces loading the package.
(marginalia-mode))
This package provides various commands based on the Emacs completion function completing-read, in particular a more advanced buffer switching command consult-buffer and a Swiper-like search command consult-line.
(use-package consult
;; Replace bindings. Lazily loaded due by `use-package'.
:bind (;; C-c bindings (mode-specific-map)
("C-c k" . consult-kmacro)
;; C-x bindings (ctl-x-map)
("C-x M-:" . consult-complex-command) ;; orig. repeat-complex-command
("C-x b" . consult-buffer) ;; orig. switch-to-buffer
("C-x r b" . consult-bookmark) ;; orig. bookmark-jump
;; Custom M-# bindings for fast register access
("M-#" . consult-register-load)
("M-'" . consult-register-store) ;; orig. abbrev-prefix-mark (unrelated)
("C-M-#" . consult-register)
;; Other custom bindings
("M-y" . consult-yank-pop) ;; orig. yank-pop
("<help> a" . consult-apropos) ;; orig. apropos-command
;; M-g bindings (goto-map)
("M-g e" . consult-compile-error)
("M-g f" . consult-flymake) ;; Alternative: consult-flycheck
("M-g g" . consult-goto-line) ;; orig. goto-line
("M-g M-g" . consult-goto-line) ;; orig. goto-line
("M-g o" . consult-outline) ;; Alternative: consult-org-heading
("M-g m" . consult-mark)
("M-g k" . consult-global-mark)
("M-g i" . consult-imenu)
("M-g I" . consult-imenu-multi)
;; M-s bindings (search-map)
("M-s d" . consult-find)
("M-s D" . consult-locate)
("M-s G" . consult-git-grep)
("M-s r" . consult-ripgrep)
("M-s l" . consult-line)
("M-s L" . consult-line-multi)
("M-s m" . consult-multi-occur)
("M-s k" . consult-keep-lines)
("M-s u" . consult-focus-lines)
;; Isearch integration
("M-s e" . consult-isearch-history)
:map isearch-mode-map
("M-e" . consult-isearch-history) ;; orig. isearch-edit-string
("M-s e" . consult-isearch-history) ;; orig. isearch-edit-string
("M-s l" . consult-line) ;; needed by consult-line to detect isearch
("M-s L" . consult-line-multi)) ;; needed by consult-line to detect isearch
;; Enable automatic preview at point in the *Completions* buffer. This is
;; relevant when you use the default completion UI. You may want to also
;; enable `consult-preview-at-point-mode` in Embark Collect buffers.
:hook (completion-list-mode . consult-preview-at-point-mode)
;; The :init configuration is always executed (Not lazy)
:init
;; 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)
;; Optionally replace `completing-read-multiple' with an enhanced version.
(advice-add #'completing-read-multiple :override #'consult-completing-read-multiple)
;; Use Consult to select xref locations with preview
(setq xref-show-xrefs-function #'consult-xref
xref-show-definitions-function #'consult-xref)
:config
(consult-customize
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-recent-file
consult--source-project-recent-file
:preview-key '(:debounce 0.4 any))
(setq consult-narrow-key "<") ;; (kbd "C-+")
)
(defun my/scp-file (arg input1)
;; Copy files to My local device.
(interactive "P\nsInput 1:")
(let* ((device (completing-read "Select: " '("Mac" "EVB")))
(cmd (format "rsync -rlt %s %s:~/man.lu.huawei/" input1 device))
(cmd-out (shell-command-to-string cmd)))
(if (equal cmd-out "")
(message "Success: %s" cmd)
(message "Failed: %s\n%s"cmd cmd-out))))
embark with ace-windows https://karthinks.com/software/fifteen-ways-to-use-embark/
(eval-when-compile
(defmacro my/embark-ace-action (fn)
`(defun ,(intern (concat "my/embark-ace-" (symbol-name fn))) ()
(interactive)
(with-demoted-errors "%s"
(require 'ace-window)
(let ((aw-dispatch-always t))
(aw-switch-to-window (aw-select nil))
(call-interactively (symbol-function ',fn)))))))
(defun embark-which-key-indicator ()
"An embark indicator that displays keymaps using which-key.
The which-key help message will show the type and value of the
current target followed by an ellipsis if there are further
targets."
(lambda (&optional keymap targets prefix)
(if (null keymap)
(which-key--hide-popup-ignore-command)
(which-key--show-keymap
(if (eq (plist-get (car targets) :type) 'embark-become)
"Become"
(format "Act on %s '%s'%s"
(plist-get (car targets) :type)
(embark--truncate-target (plist-get (car targets) :target))
(if (cdr targets) "…" "")))
(if prefix
(pcase (lookup-key keymap prefix 'accept-default)
((and (pred keymapp) km) km)
(_ (key-binding prefix 'accept-default)))
keymap)
nil nil t (lambda (binding)
(not (string-suffix-p "-argument" (cdr binding))))))))
(defun embark-hide-which-key-indicator (fn &rest args)
"Hide the which-key indicator immediately when using the completing-read prompter."
(which-key--hide-popup-ignore-command)
(let ((embark-indicators
(remq #'embark-which-key-indicator embark-indicators)))
(apply fn args)))
Emacs Mini-Buffer Actions Rooted in Keymaps
(use-package embark
:config
(defmacro my/embark-gpt-refacotr (gpt-backend rewrite-message)
`(defun ,(intern (format "%s-Refactor" (eval `(gptel-backend-name ,gpt-backend)))) (prompt)
(my/gpt-refacotr ,gpt-backend ,rewrite-message prompt)))
(define-key embark-file-map (kbd "o") (my/embark-ace-action find-file))
(define-key embark-buffer-map (kbd "o") (my/embark-ace-action switch-to-buffer))
(define-key embark-bookmark-map (kbd "o") (my/embark-ace-action bookmark-jump))
(setq my/gpt-refacotr-prompt "You are Chris Lattner. Refactor the following code. Generate only code, no explanation, no code fences. Additionally, revise the comment and consider renaming variables if appropriate.")
(keymap-set embark-region-map "g" (my/embark-gpt-refacotr gptel--gemini my/gpt-refacotr-prompt))
(keymap-set embark-region-map "o" (my/embark-gpt-refacotr gptel--openai my/gpt-refacotr-prompt))
(keymap-set embark-region-map "a" (my/embark-gpt-refacotr gptel--anthropic my/gpt-refacotr-prompt))
(keymap-set embark-region-map "d" (my/embark-gpt-refacotr gptel--deepseek my/gpt-refacotr-prompt))
(define-key embark-file-map (kbd "s") 'my/scp-file)
:bind
("C-h B" . embark-bindings) ;; alternative for `describe-bindings'
:init
;; Optionally replace the key help with a completing-read interface
(setq prefix-help-command #'embark-prefix-help-command)
(bind-keys* ("C-;" . embark-act))
:config
(setq embark-indicators
'(embark-which-key-indicator
embark-highlight-indicator
embark-isearch-highlight-indicator))
(advice-add #'embark-completing-read-prompter
:around #'embark-hide-which-key-indicator))
;; Consult users will also want the embark-consult package.
(use-package embark-consult
:after (embark consult)
:demand t ; only necessary if you have the hook below
;; if you want to have consult previews as you move around an
;; auto-updating embark collect buffer
:hook
(embark-collect-mode . consult-preview-at-point-mode))
(use-package corfu
:custom
(corfu-auto-delay 0.1)
(corfu-cycle t) ;; Enable cycling for `corfu-next/previous'
(corfu-auto t) ;; Enable auto completion
;; (global-corfu-modes '((not shell-mode) t))
(global-corfu-modes t)
(corfu-preview-current nil)
;; https://github.com/minad/corfu/discussions/457
(text-mode-ispell-word-completion nil) ;; disable ispell
:config
(when (featurep 'tty-child-frames)
(setq corfu--frame-parameters
'((no-accept-focus . t)
(no-focus-on-map . t)
(min-width . t)
(min-height . t)
(border-width . 0)
(outer-border-width . 0)
(internal-border-width . 0)
(child-frame-border-width . 1)
(vertical-scroll-bars . nil)
(horizontal-scroll-bars . nil)
(menu-bar-lines . 0)
(tool-bar-lines . 0)
(tab-bar-lines . 0)
(no-other-frame . t)
(unsplittable . t)
(undecorated . t)
(cursor-type . nil)
(no-special-glyphs . t)
(desktop-dont-save . t))))
;; https://github.com/minad/corfu/issues/330
(advice-add 'python-shell-completion-at-point :around
(lambda (fun &optional arg)
(cape-wrap-noninterruptible (lambda () (funcall fun arg)))))
:bind
(:map corfu-map
("TAB" . corfu-next)
([tab] . corfu-next)
("S-TAB" . corfu-previous)
([backtab] . corfu-previous))
:init
(global-corfu-mode))
;; Add extensions
(use-package cape
:init
;; Add `completion-at-point-functions', used by `completion-at-point'.
(add-to-list 'completion-at-point-functions #'cape-file)
(add-to-list 'completion-at-point-functions #'cape-dabbrev)
;; (add-to-list 'completion-at-point-functions #'cape-history)
(add-to-list 'completion-at-point-functions #'cape-keyword)
:config
(advice-add 'eglot-completion-at-point :around #'cape-wrap-buster)
:custom
(dabbrev-check-all-buffers nil))
;; A few more useful configurations...
(use-package emacs
:custom
;; TAB cycle if there are only few candidates
(completion-cycle-threshold 3)
(warning-minimum-level :error)
;; Emacs 28: Hide commands in M-x which do not apply to the current mode.
;; Corfu commands are hidden, since they are not supposed to be used via M-x.
(read-extended-command-predicate #'command-completion-default-include-p)
;; Enable indentation+completion using the TAB key.
;; `completion-at-point' is often bound to M-TAB.
(tab-always-indent 'complete))
(use-package corfu-terminal
:init
(unless (corfu--popup-support-p)
(corfu-terminal-mode +1))
:custom
(corfu-terminal-position-right-margin 1))
A Collection of Ridiculously Useful eXtensions for Emacs. crux bundles many useful interactive commands to enhance your overall Emacs experience.
(use-package crux
:after xterm ;; xterm will redefine input-decode-map
:bind
(("C-x d" . crux-duplicate-current-line-or-region)
("C-x x r" . crux-rename-file-and-buffer)
("C-k" . crux-kill-and-join-forward)
("C-S-k" . crux-kill-whole-line)
("C-<S-k>" . crux-kill-whole-line)
("C-x M-c" . crux-capitalize-region))
:init
;; 75 is the ASCII code for 'K', and 6 indicates Ctrl+Shift modifier.
(define-key input-decode-map "\e[75;6~" [C-S-k]))
When splitting a window, I invariably want to switch to the new window. This makes that automatic.
(defun my/split-window-below-and-switch ()
"Split the window horizontally, then switch to the new pane."
(interactive)
(split-window-below)
(balance-windows)
(other-window 1))
(defun my/split-window-right-and-switch ()
"Split the window vertically, then switch to the new pane."
(interactive)
(split-window-right)
(balance-windows)
;; (let ((total-width (window-total-width)))
;; (split-window-right (floor (* 0.6 total-width))))
(other-window 1))
(global-set-key (kbd "C-x 2") 'my/split-window-below-and-switch)
(global-set-key (kbd "C-x 3") 'my/split-window-right-and-switch)
I like the idea of mass editing grep
results the same way I can edit filenames
in dired
. These keybindings allow me to use C-x C-q
to start editing grep
results and C-c C-c
to stop, just like in dired
.
(eval-after-load 'grep
'(define-key grep-mode-map
(kbd "C-x C-q") 'wgrep-change-to-wgrep-mode))
(eval-after-load 'wgrep
'(define-key grep-mode-map
(kbd "C-c C-c") 'wgrep-finish-edit))
(setq wgrep-auto-save-buffer t)
warp selected region with punctuate.
(use-package wrap-region
:config
(wrap-region-global-mode t)
(wrap-region-add-wrappers
'(("$" "$")
("/" "/" nil ruby-mode)
("/* " " */" "#" (java-mode javascript-mode css-mode))
("`" "`" nil (markdown-mode ruby-mode)))))
Set multiple cursors for better marker words
(use-package multiple-cursors
:bind
("C->" . mc/mark-next-like-this)
("C-<" . mc/mark-previous-like-this)
("C-M-m" . mc/mark-all-like-this)
:init
(multiple-cursors-mode))
Expand region increases the selected region by semantic units. Just keep pressing the key until it selects what you want.
(use-package expand-region
:config
;; Replace the original org-mode excursion function to avoid performance overhead
(defun er/save-org-mode-excursion (action)
(funcall action))
:bind
("C-c q" . er/expand-region))
(use-package expreg
:bind
("C-=" . expreg-expand)
("C--" . expreg-contract))
Use ace-jump-mode to quick jump to words or char
(use-package avy
:bind
("C-j" . avy-goto-char-timer)
("C-c C-j" . avy-resume)
:custom
(avy-single-candidate-jump nil)
(avy-background nil)
(avy-timeout-seconds 0.3))
(global-set-key (kbd "C-S-n") "\C-u1\C-v")
(global-set-key (kbd "C-S-p") "\C-u1\M-v")
(use-package goto-chg
:config
(bind-keys* ("C-." . goto-last-change))
(bind-keys* ("C-," . goto-last-change-reverse)))
hydra-frame-window is designed from ace-window (C-x f) and matches aw-dispatch-alist with a few extra
(defhydra hydra-frame-window (:color red :hint nil)
"
^Delete^ ^Frame resize^ ^Window^ Window Size^^^^^^ ^TEXT^ ^Text^ (__)
_0_: delete-frame _g_: resize-frame-right _t_: toggle ^ ^ _k_ ^ ^ _-_ _K_ (oo)
_1_: delete-other-frames _H_: resize-frame-left _e_: ace-swap-win _h_ ^+^ _l_ _=_ _L_ /------\\/
_2_: make-frame _F_: fullscreen ^ ^ ^ ^ _j_ ^ ^ _+_ _J_ / | ||
_d_: kill-and-delete-frame _n_: new-frame-right _w_: ace-delete-window _b_alance^^^^ ^ ^ ^ ^ * /\\---/\\ ~~ C-x w ;
"
("0" delete-frame :exit t)
("1" delete-other-frames :exit t)
("2" make-frame :exit t)
("b" balance-windows :exit t)
("d" kill-and-delete-frame :exit t)
("e" ace-swap-window)
("F" toggle-frame-fullscreen) ;; is <f11>
("g" resize-frame-right :exit t)
("H" resize-frame-left :exit t) ;; aw-dispatch-alist uses h, I rebind here so hjkl can be used for size
("n" new-frame-right :exit t)
;; ("r" reverse-windows)
("t" toggle-window-spilt)
("w" ace-delete-window :exit t)
("x" delete-frame :exit t)
("K" text-scale-decrease)
("J" text-scale-increase)
("L" sensible-defaults/reset-text-size)
("+" my/increase-font-size)
("-" my/decrease-font-size)
("=" my/reset-font-size)
("h" shrink-window-horizontally)
("k" shrink-window)
("j" enlarge-window)
("l" enlarge-window-horizontally)
("q" nil :exit t))
(use-package ace-window
:bind
("M-o" . 'ace-window)
("C-x w" . hydra-frame-window/body)
:config
(setq aw-scope 'frame) ; only the windows of the current frame
(setq aw-background t)
(setq aw-keys '(?a ?s ?d ?f ?g ?h ?j ?k ?l)))
Popper is a minor-mode to tame the flood of ephemeral windows Emacs produces, while still keeping them within arm’s reach.
(use-package popper
:bind (("C-<tab>" . popper-toggle)
("C-M-<tab>" . popper-cycle)
("C-M-<return>" . popper-toggle-type)
("C-M-k" . popper-kill-latest-popup))
:custom
(popper-mode-line nil)
:config
(bind-keys* ("C-<tab>" . popper-toggle))
(setq popper-group-function #'popper-group-by-project)
(defun popper--fit-window-height (win)
"Determine the height of popup window WIN by fitting it to the buffer's content."
(fit-window-to-buffer
win
(floor (frame-height) 3)
(floor (frame-height) 4)))
:init
(setq popper-reference-buffers
'(;;("Output\\*$" . hide)
(completion-list-mode . hide)
occur-mode
"^\\*socks5-proxy-.*\\*$"
"\\*Async Shell Command\\*"
"^\\*vterm.*\\*$" vterm-mode ;vterm as a popup
"^\\*eat*.*$" eat-mode
"^\\*TeX Help.*\\*$" tex-mode
"^\\*tex-shell.*\\*$" tex-mode
compilation-mode))
(popper-mode +1)
(popper-echo-mode +1)) ; For echo area hints
(setq fast-but-imprecise-scrolling t)
(use-package too-long-lines-mode
;; using use-package PATH
:load-path "~/.emacs.d/third_party/too-long-lines-mode"
;; using quelpa URL
;; :quelpa
;; ((too-long-lines-mode
;; :fetcher github
;; :repo "rakete/too-long-lines-mode")
;; :upgrade t)
:config
(setq too-long-lines-threshold 5000)
(set 'too-long-lines-special-buffer-modes
'(shell-mode ag-mode inferior-python-mode comint-mode compilation-mode))
(too-long-lines-mode))
Hydra short-keys
(defhydra hydra-back-and-forth ()
"back-and-forth"
("<right>" back-button-local-forward "→")
("<left>" back-button-local-backward "←")
("<up>" back-button-global-backward "↑")
("<down>" back-button-global-forward "↓")
("q" nil "exit" :exit t))
back-button offers local and global jumping
(use-package back-button
:bind (:map back-button-mode-map
("C-x <C-right>" . hydra-back-and-forth/back-button-local-forward)
("C-x <C-left>" . hydra-back-and-forth/back-button-local-backward)
("C-x <up>" . hydra-back-and-forth/back-button-global-backward)
("C-x <down>" . hydra-back-and-forth/back-button-global-forward))
:init
(back-button-mode 1)
(define-key back-button-mode-map (kbd "C-x <C-left>") nil)
(define-key back-button-mode-map (kbd "C-x <C-right>") nil)
(define-key back-button-mode-map (kbd "C-x <left>") nil)
(define-key back-button-mode-map (kbd "C-x <right>") nil)
(define-key back-button-mode-map (kbd "C-x C-SPC") nil)
(define-key back-button-mode-map (kbd "C-x SPC") nil))
Pcache required by persistent-soft required by back-botton, but it freeze emacs when quit.
(remove-hook 'kill-emacs-hook 'pcache-kill-emacs-hook)
I like Ediff’s control panel to show in the same frame, even on graphical environments.
(setq ediff-window-setup-function 'ediff-setup-windows-plain)
(setq ediff-split-window-function 'split-window-horizontally)
Hydra ediff, more function with less key bindings
(defhydra hydra-ediff (:color blue :hint nil)
"
^Buffers Files VC Ediff regions
----------------------------------------------------------------------
_b_uffers _f_iles (_=_) _r_evisions _l_inewise
_B_uffers (3-way) _F_iles (3-way) _w_ordwise
_c_urrent file
"
("b" ediff-buffers)
("B" ediff-buffers3)
("=" ediff-files)
("f" ediff-files)
("F" ediff-files3)
("c" ediff-current-file)
("r" ediff-revision)
("l" ediff-regions-linewise)
("w" ediff-regions-wordwise)
("q" nil :exit t))
(global-set-key (kbd "C-c w") #'hydra-ediff/body)
Use c-x c-j
to enter current folder.
These are the switches that get passed to ls
when dired
gets a list of
files. We’re using:
l
: Use the long listing format.h
: Use human-readable sizes.v
: Sort numbers naturally.A
: Almost all. Doesn’t include ”.
” or ”..
”.
(setq-default dired-listing-switches "-lhvA")
Hydra Dired till a work in progress but this has helped me navigate and use dired.
(defhydra hydra-dired (:hint nil :color pink)
"
_+_ mkdir _v_iew _m_ark _(_ details _i_nsert-subdir wdired
_C_opy _O_ view other _U_nmark all _)_ omit-mode _$_ hide-subdir C-x C-q : edit
_D_elete _o_pen other _u_nmark _l_ redisplay _w_ kill-subdir C-c C-c : commit
_R_ename _M_ chmod _t_oggle _g_ revert buf _e_ ediff C-c ESC : abort
_Y_ rel symlink _G_ chgrp _E_xtension mark _s_ort _=_ pdiff
_S_ymlink ^ ^ _F_ind marked _._ toggle hydra \\ flyspell
_r_sync ^ ^ ^ ^ ^ ^ _?_ summary
_z_ compress-file _A_ find regexp
_Z_ compress _Q_ repl regexp
T - tag prefix
"
("\\" dired-do-ispell)
("(" dired-hide-details-mode)
(")" dired-omit-mode)
("+" dired-create-directory)
("=" diredp-ediff) ;; smart diff
("?" dired-summary)
("$" diredp-hide-subdir-nomove)
("A" dired-do-find-regexp)
("C" dired-do-copy) ;; Copy all marked files
("D" dired-do-delete)
("E" dired-mark-extension)
("e" dired-ediff-files)
("F" dired-do-find-marked-files)
("G" dired-do-chgrp)
("g" revert-buffer) ;; read all directories again (refresh)
("i" dired-maybe-insert-subdir)
("l" dired-do-redisplay) ;; relist the marked or singel directory
("M" dired-do-chmod)
("m" dired-mark)
("O" dired-display-file)
("o" dired-find-file-other-window)
("Q" dired-do-find-regexp-and-replace)
("R" dired-do-rename)
("r" dired-do-rsynch)
("S" dired-do-symlink)
("s" dired-sort-toggle-or-edit)
("t" dired-toggle-marks)
("U" dired-unmark-all-marks)
("u" dired-unmark)
("v" dired-view-file) ;; q to exit, s to search, = gets line #
("w" dired-kill-subdir)
("Y" dired-do-relsymlink)
("z" diredp-compress-this-file)
("Z" dired-do-compress)
("q" nil)
("C-g" nil :color blue)
("." nil :color blue))
Use “[” and “]” to jump out and in dired.
(eval-after-load "dired"
'(progn
(define-key dired-mode-map (kbd "[") 'dired-up-directory)
(define-key dired-mode-map (kbd "]") 'dired-view-file)
(define-key dired-mode-map (kbd "K") 'dired-kill-subdir)
(define-key dired-mode-map "." 'hydra-dired/body)))
(eval-after-load "view"
'(define-key view-mode-map (kbd "[") 'View-quit))
fast copy and past
(setq dired-dwim-target t)
Kill buffers of files/directories that are deleted in dired
.
(setq dired-clean-up-buffers-too t)
Always copy directories recursively instead of asking every time.
(setq dired-recursive-copies 'always)
Ask before recursively deleting a directory, though.
(setq dired-recursive-deletes 'top)
Files are normally moved and copied synchronously. This is fine for small or local files, but copying a large file or moving a file across a mounted network drive blocks Emacs until the process is completed. Unacceptable!
reuse dired buffer
(put 'dired-find-alternate-file 'disabled nil)
narrow dired to match filter
(use-package dired-narrow
:bind (:map dired-mode-map
("/" . dired-narrow)))
dired-rsync – asynchronous rsync from dired
(use-package dired-rsync
:config
(bind-key "C-c C-r" 'dired-rsync dired-mode-map))
Provide commands easy-kill and easy-mark to let users kill or mark things easily.
(use-package easy-kill
:init
(global-set-key [remap kill-ring-save] 'easy-kill)
;; :bind
;; ("C-=" . easy-mark)
;; (:map easy-kill-base-map
;; ("=" . easy-kill-expand)
;; ("C-=" . easy-kill-expand)
;; ("q" . easy-kill-expand))
)
(recentf-mode 1)
(setq history-length 25)
(savehist-mode 1)
(save-place-mode 1)
(setq-default
;; Match count next to the minibuffer prompt
isearch-lazy-count t
;; Don't be stingy with history; default is to keep just 16 entries
search-ring-max 100
regexp-search-ring-max 100)
(use-package monkeytype
:bind (:map monkeytype-mode-map
("C-c C-c k" .
(lambda ()
(interactive)
(kill-matching-buffers "\\*fortune\\*" nil t)
(kill-matching-buffers "^\\*Monkeytype\\*\\(<[0-9]*>\\)?$" nil t))))
:custom
(monkeytype-directory "~/.emacs.d/.monkeytype")
(fortune-program "/usr/games/fortune")
(fortune-dir "/usr/share/games/fortunes")
(fortune-file "/usr/share/games/fortunes/fortunes")
(monkeytype-auto-fill t)
(monkeytype-colored-mode-line nil)
(monkeytype-downcase nil)
(monkeytype-mode-line-interval-update 50)
(monkeytype-most-mistyped-amount 10))
(setq gc-cons-threshold 100000000)
(setq read-process-output-max (* 8 1024 1024)) ;; 8mb
https://karthinks.com/software/persistent-prefix-keymaps-in-emacs/
(use-package repeat-help
:hook (repeat-mode . repeat-help-mode))
(use-package ts-movement
:load-path "~/.emacs.d/third_party/ts-movement"
:ensure multiple-cursors
:ensure hydra
:config
(defhydra tsm/hydra ()
"TS Movement"
("d" #'tsm/delete-overlay-at-point)
("D" #'tsm/clear-overlays-of-type)
("C-b" #'tsm/backward-overlay)
("C-f" #'tsm/forward-overlay)
("b" #'tsm/node-prev)
("f" #'tsm/node-next)
("u" #'tsm/node-parent)
("d" #'tsm/node-child)
("N" #'tsm/node-children)
("s" #'tsm/node-children-of-type)
("a" #'tsm/node-start)
("e" #'tsm/node-end)
("m" #'tsm/node-mark)
("c" #'tsm/mc/mark-all-overlays))
(push 'tsm/hydra/tsm/mc/mark-all-overlays mc--default-cmds-to-run-once)
(advice-add 'symbol-overlay-remove-all :after (lambda () (tsm/clear-overlays (point))))
(defun my/treesit-backward-up-list ()
(interactive)
(let* ((start-point (point))
(node (treesit-node-on start-point start-point)))
(while (and node
(= (point) start-point))
(setq node (treesit-node-parent node))
(when node
(goto-char (treesit-node-start node))))
(when (= (point) start-point)
(message "No parent node found or already at root"))))
(defun my/down-list ()
(interactive)
(let* ((start-point (point))
(next-sibling (treesit-node-on start-point start-point))
found-node)
(while (and next-sibling (not found-node))
(if (> (treesit-node-child-count next-sibling) 0)
(setq found-node next-sibling)
(setq next-sibling (treesit-node-next-sibling next-sibling))))
(if found-node
(progn
(goto-char (treesit-node-start found-node))
(message "Moved to next non-leaf sibling"))
(message "No next non-leaf sibling found"))))
(defun my/backward-node ()
"Move backward to the previous node in the tree, following a pre-order traversal."
(interactive)
;; (message "node at: %s" (treesit-node-string (treesit-node-at (point))))
(when-let* ((node (treesit-node-at (point))))
(let ((target-node nil))
(while (and node (not target-node))
(if-let* ((prev-sibling (treesit-node-prev-sibling node)))
(progn
(setq node prev-sibling)
(while (treesit-node-child node -1)
(setq node (treesit-node-child node -1)))
(unless (treesit-node-check node 'missing) ; Skip invalid node, continue loop
(setq target-node node)))
(setq node (treesit-node-parent node))))
(when target-node
;; (message "target-node: %s" (treesit-node-string target-node))
(goto-char (treesit-node-start target-node))))))
(defun my/forward-node ()
(interactive)
(let ((node (treesit-node-at (point))))
(while node
(if-let* ((next-sibling (treesit-node-next-sibling node)))
(if (treesit-node-check next-sibling 'missing)
(setq node next-sibling) ; Skip invalid node, continue loop
(goto-char (treesit-node-start next-sibling))
(setq node nil)) ; Exit the loop after moving
(setq node (treesit-node-parent node)))))) ; Move to parent if no next sibling
:bind (:map ts-movement-map
("C-M-u" . my/treesit-backward-up-list)
("C-M-d" . my/down-list)
("M-f" . my/forward-node)
("M-b" . my/backward-node)
("C-c ." . tsm/hydra/body))
:hook
((bash-ts-mode c++-ts-mode c-ts-mode cmake-ts-mode dockerfile-ts-mode json-ts-mode
python-ts-mode rust-ts-mode toml-ts-mode typescript-ts-mode yaml-ts-mode)
. ts-movement-mode))
Just a few handy functions.
(global-set-key (kbd "M-/") 'hippie-expand)
(setq ns-right-option-modifier 'super)
(global-unset-key (kbd "C-x 5 1"))
(local-unset-key (kbd "C-x 5 1"))
get current buffer’s name
(global-set-key (kbd "C-c o")
(lambda () (interactive)
(message buffer-file-name)
(kill-new buffer-file-name)))