Literate and modular Doom Emacs configuration.
- About
- Tangle
- 30.1 specific
- Predefined
- Input
- Completion
- UI
- Editor
- Emacs
- Term
- Checkers
- Tools
- Lang
- App
- Other packages
- Other configs
The conventions of this org file:
- First level heading respect Doom’s order
- Configured module goes to second level heading
-
- Prerequisite packages tangled into packages.toml (
Arch
only) - Bootstrap scripts tangled to install.d/
- Comment a module with C-c ; at heading
- Prerequisite packages tangled into packages.toml (
- One line config goes into * Tangle
- Often a declare in init.el
(doom!
:input
<<input>>
:completion
<<completion>>
:ui
<<ui>>
hl-todo
indent-guides
(ligatures +extra)
nav-flash
ophints
(smooth-scroll +interpolate)
(vc-gutter +pretty)
(window-select +numbers)
workspaces
;zen
:editor
<<editor>>
(format +onsave)
;file-templates
;multiple-cursors
parinfer
word-wrap
:emacs
<<emacs>>
;electric
;ibuffer
undo
vc
:term
<<term>>
:checkers
<<checkers>>
(syntax +childframe)
:tools
<<tools>>
;biblio
debugger
;editorconfig
(eval +overlay)
tree-sitter
;upload
tree-sitter
:os
;tty
:lang
<<lang>>
;(cc +lsp)
emacs-lisp
json
:email
<<email>>
:app
calendar
<<app>>
:config
literate
(default +bindings +smartparens))
The order of modules in above list make sense
Extra packages from MELPA
Default tangle to config.el
(setq user-full-name "fakeGenius")
Default install all packages in packages.toml
enable_default=true
doomemacs/doomemacs#8287 eldoc error: (invalid-function incf)
(package! eldoc :built-in t)
(package! track-changes :built-in t)
(defun +my/is-utility-daemon ()
"If current session run from daemon called `utility`."
(and (daemonp) (boundp 'server-name) (string= server-name "utility")))
(defun +my/reverse-words (beg end)
"Reverse the order of words in region."
(interactive "*r")
(apply
'insert
(reverse
(split-string
(delete-and-extract-region beg end) "\\b"))))
[chinese]
packages=["base-devel",
"librime" # for +rime
]
(chinese<<chinese-flags()>>)
Default simplified Chinese input
(after! liberime
(liberime-try-select-schema "luna_pinyin_simp")
(setq pyim-default-scheme 'rime-quanpin))
[corfu]
packages=["words"]
(corfu +icons +dabbrev)
(setq corfu-on-exact-match 'show)
(map! :after cape :i "C-c p" cape-prefix-map)
;; dabb_ only match dabbrev not Dabbrev!
(after! dabbrev
(setq dabbrev-case-fold-search nil))
(vertico +icons +childframe)
tumashu/vertico-posframe#16 Disable vertico-posframe when Emacs runs in terminal
(after! vertico-multiform
(add-to-list 'vertico-multiform-commands
'(consult-line
posframe
(vertico-posframe-fallback-mode . vertico-buffer-mode))))
(defun my-posframe-poshandler-frame-top-center-n-lines (info)
(let* ((pos (posframe-poshandler-frame-top-center info))
(y (cdr pos)))
(cons (car pos)
(+ y (* 3 (frame-char-height)))))) ;; 3 lines offset
(after! vertico-posframe
(setq vertico-posframe-poshandler #'my-posframe-poshandler-frame-top-center-n-lines)
(setq vertico-posframe-width 88))
(package! ewal-doom-themes)
(use-package! ewal-doom-themes)
load wal theme from command line
emacs-client -e "(load-theme 'ewal-doom-themes t)"
GitHub - donniebreve/rose-pine-doom-emacs: Soho vibes for DOOM Emacs
doom
restore last selected theme
(defun load-in-doom-dir (file-name &optional dir)
(let* ((dir (or dir doom-user-dir))
(full-name (expand-file-name file-name dir)))
(if (file-exists-p full-name)
(load full-name))))
(load-in-doom-dir "theme.el" doom-cache-dir)
difficult to choose theme? random it
(defun +my/random-theme ()
(interactive)
(let* ((all-themes (custom-available-themes))
(next-theme (nth (random (length all-themes)) all-themes)))
(consult-theme next-theme)
(message (format "switch to theme: %s" next-theme))))
(map! :leader
(:prefix "t"
:desc "Random theme" "t" #'+my/random-theme))
track current theme for later load
(defun +my/save-theme (prev new-theme &rest args)
(let
((theme-config-file (expand-file-name "theme.el" doom-cache-dir)))
(write-region
(format "(setq doom-theme '%s)\n" new-theme) nil theme-config-file)
(message "Switch to theme: %s" new-theme)))
(add-variable-watcher 'doom-theme #'+my/save-theme)
bold italic underline stride
Set default font size, WSL
currently not aware dpi settings in
~/.Xresources while float size makes it work on Linux.
- doomemacs/doomemacs#6131 DPI settings are not respected by “setq doom-font”
- Change my fonts - doom/docs/faq
(setq +my/font-size (* (if (featurep :system 'wsl) 1.5 1) 12.0))
(setq doom-font (font-spec :family "Maple6 NF" :size +my/font-size))
(custom-set-faces
;; quoted text in info
'(fixed-pitch-serif ((t (:slant italic :foreground "tomato"))))
;; prefer italic comment font
'(font-lock-comment-face ((t (:slant italic)))))
doom-dashboard
- How to change your splash screen - Configuration - Doom Emacs Discourse
- elisp - Read from a file into a Emacs lisp list - Stack Overflow
(setq fancy-splash-image (expand-file-name "assets/bitmap_512x.png" doom-user-dir))
splash image not loaded in the first frame of daemon mode
- Splash image not visible initially
- Splash image tinted only on emacs daemon launch - User Support - Doom Emacs D…
- doomemacs/doomemacs#6221 Theme differences in daemon vs standard GUI for the …
- doomemacs/doomemacs#7301 {cosmetic bug} fancy-splash-image not loaded at firs…
;; Refresh the Doom dashboard on the first frame in daemon mode.
(defun +my/load-doom-theme (frame)
(select-frame frame)
(load-theme doom-theme t))
(add-hook 'after-make-frame-functions #'+my/load-doom-theme 90)
;; Remove make frame hook to avoid delays when opening a new frame.
(add-hook! 'doom-first-buffer-hook
(remove-hook 'after-make-frame-functions #'+my/load-doom-theme))
[modeline]
packages=["otf-comicshanns-nerd"]
modeline
custom doom-modeline font, valid on startup and persist after cmd:doom/reload-theme
(defun +my/set-mode-line-font ()
(set-face-font 'mode-line (font-spec :family "ComicShannsMono Nerd Font" :size (+ +my/font-size 1.5)))
(set-face-font 'mode-line-inactive (font-spec :family "ComicShannsMono Nerd Font" :size (+ +my/font-size 1.5))))
(add-hook 'doom-load-theme-hook #'+my/set-mode-line-font 90)
(popup +defaults)
(setq split-width-threshold 120)
Prefer stack at right for following info windows, since they are fill-columned
(set-popup-rules!
'(("^\\*\\([Hh]elp\\|Apropos\\)" ; help messages
:side right :size 80 :slot 2 :vslot -8 :select t)
("^\\*\\(?:Wo\\)?Man "
:side right :size 80 :vslot -6 :select t)
("^\\*info\\*$"
:side right :size 80 :slot 2 :vslot 2 :select t)))
[unicode]
packages=[
"quivira", # org ellipsis ⤵, ℤ
"ttf-dejavu", # org heading ◉ ✸ ∈
"ttf-sarasa-gothic-sc", # ¬
"noto-fonts-emoji", # color emoji
"ttf-nerd-fonts-symbols-mono" # nerd font
]
unicode
To get unicode block name for a character, kbd:SPC h ’ on it to get it’s lexical code, and search in Plane (Unicode) - Wikipedia
Doom’s way of change unicode font, but it will be shadowed by fn:doom-init-fonts-h if var:doom-symbol-font is set.
(after! unicode-fonts
;; ℕ, ⤵, 𝔹
(dolist (unicode-block '("Letterlike Symbols" "Supplemental Arrows-B" "Mathematical Alphanumeric Symbols"))
(push "Quivira" (cadr (assoc unicode-block unicode-fonts-block-font-mapping))))
;; ⨂
(dolist (unicode-block '("Supplemental Mathematical Operators"))
(push "DejaVu Math TeX Gyre" (cadr (assoc unicode-block unicode-fonts-block-font-mapping))))
;; ∈ ∅
(dolist (unicode-block '("Mathematical Operators"))
(push "DejaVu Sans" (cadr (assoc unicode-block unicode-fonts-block-font-mapping))))
;; ¬
(dolist (unicode-block '("Halfwidth and Fullwidth Forms"))
(push "Sarasa Gothic SC" (cadr (assoc unicode-block unicode-fonts-block-font-mapping)))))
Add to var:after-setting-font-hook not work well, font display diffs after cmd:doom/reload-theme
(defun +my/unicode-fonts ()
(dolist (unicode-block '("Letterlike Symbols" "Supplemental Arrows-B"))
(push "Quivira" (cadr (assoc unicode-block unicode-fonts-block-font-mapping)))))
(add-hook 'after-setting-font-hook #'+my/unicode-fonts 60)
Add hook but with fn:set-fontset-font succeed
(defun +my/unicode-fonts ()
; Supplemental Arrows-B, include ⤵
(set-fontset-font t '(#x2900 . #x297f) "Quivira")
; Mathematical symbols, 𝔹
(set-fontset-font t '(#x1d400 . #x1d7ff) "Quivira")
; Mathematical operators, ⨂
(set-fontset-font t '(#x2208 . #x22ff) "DejaVu Math TeX Gyre")
(dolist (chars '("¬")) ; keywords =not= in code ligatures
(set-fontset-font t (string-to-char chars) "Sarasa Gothic SC")))
(add-hook 'after-setting-font-hook #'+my/unicode-fonts 60)
see more in Emacs, fonts and fontsets
Rongcui Dong’s Site - 如何在 Doom Emacs 中设置中文
Check alignment between Chinese and English.
Emacs is the advanced, extensible, customizable, self-documenting editor.
# Emacs is the advanced, extensible, customizable, self-documenting editor.
Emacs 是一款可扩展可自定义且自带文档的高级 editor.
These settings will not work in daemon mode if added instead to
doom-init-ui-hook
, as they might be overridden by unicode-fonts-setup
.
Additionally, consider changing the font for all fontset
instead of just
(frame-parameter nil 'font)
. If the emoji font is not set here, you will need
to use doom/reload-font
later to enable proper color emoji display.
- GitHub - hick/emacs-chinese: Emacs 相关中文问题以及解决方案
- fonts - How do I get colour emoji to display in Emacs - Emacs Stack Exchange
(defun +my/cjk-font ()
(dolist (charset '(kana han cjk-misc bopomofo))
(set-fontset-font t charset
(font-spec :family "Maple6 SC NF")))
;; why not set color emoji font at the same time
(set-fontset-font t 'emoji "Noto Color Emoji"))
(add-hook 'after-setting-font-hook #'+my/cjk-font)
(after! nerd-icons
(setq nerd-icons-scale-factor 0.9))
Transparency
(set-frame-parameter (selected-frame) 'alpha '(85 . 50))
(add-to-list 'default-frame-alist '(alpha . (85 . 50)))
(defun toggle-transparency ()
(interactive)
(let ((alpha (frame-parameter nil 'alpha)))
(set-frame-parameter
nil 'alpha
(if (eql (cond ((numberp alpha) alpha)
((numberp (cdr alpha)) (cdr alpha))
;; Also handle undocumented (<active> <inactive>) form.
((numberp (cadr alpha)) (cadr alpha)))
100)
'(85 . 50) '(100 . 100)))))
(map! :leader
(:prefix "t"
:desc "Toggle transparency" "T" #'toggle-transparency))
Line numbers
(setq display-line-numbers-type nil)
notify initial time
(defun notify-init-time ()
(require 'notifications)
(notifications-notify
:image-path (expand-file-name "assets/notify.jpg" doom-user-dir)
:title "Daemon"
:sound-name "bell"
:body (format "%s initialed in %0.3fs" server-name doom-init-time)))
;; NOTE Why this keep one workspace in `emacsclient -c'?
(add-hook! 'doom-init-ui-hook
(if (and (daemonp) (not (+my/is-utility-daemon)))
(notify-init-time)))
(evil +everywhere)
(after! evil
(setq evil-kill-on-visual-paste nil)
;; Disabling cursor movement when exiting insert mode
(setq evil-move-cursor-back nil)
;; keep previous layout, always!
(setq evil-auto-balance-windows nil))
(after! evil-surround
;; I want surround (..), not ( .. )
(evil--add-to-alist
evil-surround-pairs-alist
?\( '("(" . ")")
?\[ '("[" . "]")
?\{ '("{" . "}")
?\) '("( " . " )")
?\] '("[ " . " ]")
?\} '("{ " . " }")))
Shortcut for evil normal mode
(map! :n "g U" #'browse-url-xdg-open
:n "g u" #'evil-upcase
:n "g d" #'evil-downcase)
snippets
(setq +snippets-dir
(expand-file-name "~/Documents/Templates/snippets"))
fold
work for org-ellipsis
and fold in code mode
(setq +fold-ellipsis "⤵")
(after! org
(setq org-startup-folded 'fold
org-hide-drawer-startup nil))
;; org-hide-block-startup nil
(dired +dirvish +icons)
(after! dired
(setq delete-by-moving-to-trash nil)
(setq dired-listing-switches
"-l --almost-all --sort=time --human-readable --time-style=long-iso --group-directories-first --no-group")
;; Dirvish respects all the keybindings in `dired-mode-map'
(map! :map dired-mode-map
:n "e" #'dired-create-empty-file
:n "." #'dired-omit-mode))
(after! dired-x
;; Make dired-omit-mode hide all "dotfiles"
(setq dired-omit-files
(concat dired-omit-files "\\|^\\..*$")))
[dirvish]
packages=[
"fd",
"libvips",
"imagemagick",
"ffmpegthumbnailer", # may require pipewire-jack
"mediainfo",
# "tar", # include in =base=
"unzip"
]
(after! dirvish
(setq dirvish-quick-access-entries
'(("h" "~/" "Home")
("d" "~/Downloads/" "Downloads")
("c" "~/.config/" "Config")
("D" "~/Documents/" "Documents")
("l" "~/lib/" "Personal Library")
("L" "~/.local/lib/" "Library")
("m" "/mnt/" "Mounts")
("n" "~/.Nextcloud/" "Nextcloud")
("p" "~/Pictures/" "Pictures")
("t" "~/.local/share/Trash/files/" "TrashCan")))
(remove-hook 'dired-mode-hook #'+dired-update-mode-line-height-h))
(after! dirvish
(setq dirvish-side-width 25)
(map!
:map dirvish-mode-map
:gn "S" #'dirvish-cd-into-vterm
;; remap previous =S= to =o=
:gn "o" #'dirvish-quicksort))
(defun dirvish-open-binaries-externally (file fn)
"When FN is not `dired', open binary FILE externally."
(when-let* (((not (eq fn 'dired)))
((file-exists-p file))
((not (file-directory-p file)))
((member (downcase (or (file-name-extension file) ""))
dirvish-binary-exts)))
;; return t to terminate `dirvish--find-entry'.
(prog1 t (dired-do-open))))
(add-hook 'dirvish-find-entry-hook #'dirvish-open-binaries-externally)
(after! dirvish
;; remove pdf
(setq dirvish-binary-exts (remove "pdf" dirvish-binary-exts)))
Replace /home/$user
to ~
(defun +my/home-to-tide (file)
"Replace /home/$user in FILE to ~."
(let ((home (getenv "HOME"))
(file-name (concat file)))
(if (s-starts-with? home file-name)
(s-replace home "~" file-name)
file-name)))
(defun +my/dirvish-copy-file-path (&optional multi-line)
"Copy filepath of marked files.
If MULTI-LINE, make every path occupy a new line."
(interactive "P")
(let* ((files (mapcar #'file-local-name (dired-get-marked-files)))
(related-files (mapcar #'+my/home-to-tide files))
(names (mapconcat #'identity related-files (if multi-line "\n" " "))))
(dirvish--kill-and-echo (if multi-line (concat "\n" names) names))))
(after! dirvish
(advice-add 'dirvish-copy-file-path :override #'+my/dirvish-copy-file-path))
Goto random line, use with fn:dirvish-fd
(defun goto-random-line ()
"Go to a random line in the current buffer."
(interactive)
(let* ((total-lines (count-lines (point-min) (point-max)))
(random-line (1+ (random total-lines))))
(goto-line random-line)))
alexluigit/dirvish#353 When opening m…
(defun dirvish-pre-redisplay-h (window)
"Record root WINDOW and redisplay sessions in selected frame."
(when (eq (frame-selected-window) window)
(setq dirvish--selected-window (frame-selected-window))
(when-let* ((dv (dirvish-curr))) (setf (dv-root-window dv) window))
(dirvish--redisplay)))
[vterm]
packages=[
"libvterm",
"cmake",
"inetutils" # =hostname= command
]
vterm
have a function to disable close confirmation on terms. work on all terms but…
(defun set-no-process-query-on-exit ()
(let ((proc (get-buffer-process (current-buffer))))
(when (processp proc)
(set-process-query-on-exit-flag proc nil))))
(after! vterm
(if (+my/is-utility-daemon)
(add-hook 'vterm-mode-hook #'set-no-process-query-on-exit)))
(defun +my/vterm-switch ()
"Switch to vterm buffer in `Term' workspace.
If `Term' workspace not exist, create it.
If no vterm buffer in `Term' workspace, create it."
(interactive)
(+workspace-switch "Term" t)
(let ((vterm-buffer
;; return first vterm buffer in `Term' workspace
(catch 'foo
(dolist (buffer (+workspace-buffer-list))
(let ((bn (buffer-name buffer)))
(when (and bn
;; https://stackoverflow.com/a/2238589
(with-current-buffer bn
(eq major-mode 'vterm-mode)))
(throw 'foo bn))))))
(display-buffer-alist))
(if vterm-buffer
(switch-to-buffer vterm-buffer)
;; create vterm buffer if not exist
(+vterm/here t))))
(map! :leader
:prefix "TAB"
:desc "Switch to vterm buffer" "v" #'+my/vterm-switch)
(defun +my/vterm-cd-project-root ()
(interactive)
(vterm-send-string "cd $PROOT")
(vterm-send-return))
(after! vterm
(setq vterm-buffer-name-string "%s - vterm"
vterm-ignore-blink-cursor nil)
(map! :leader
(:prefix "o"
;; vterm to current file directory (not project root)
;; use `C-Return' to project root
:desc "Toggle vterm popup" "t" (cmd!! #'+vterm/toggle t)
:desc "Open vterm here" "T" (cmd!! #'+vterm/here t)))
;; TODO fixed-pitch in bpytop like
;; (add-hook 'vterm-mode-hook
;; (lambda ()
;; (set (make-local-variable 'buffer-face-mode-face) 'fixed-pitch
;; (buffer-face-mode t))))
(define-key vterm-mode-map (kbd "M-q") #'vterm-send-escape)
(define-key vterm-mode-map [ (control return) ] #'+my/vterm-cd-project-root)
(dolist (num (number-sequence 0 9))
(define-key vterm-mode-map (kbd (format "M-%d" num)) nil)))
- akermu/emacs-libvterm#666 Integrate with desktop-save-mode
- Desktop-Save Mode
- GitHub - Bad-ptr/persp-mode.el: named perspectives(set of buffers/window conf…
- examples in doom config
No text properties saved.
(after! persp-mode
;; vterm
(persp-def-buffer-save/load
:mode 'vterm-mode :tag-symbol 'def-vterm-buffer
:save-vars '(default-directory)
:save-function (lambda (buf tag vars)
(list tag (buffer-name buf) vars
(string-trim-right (buffer-string))))
;; no face and other text properties saved
;; (string-trim-right (buffer-substring-no-properties (point-min) (point-max)))))
:load-function (lambda (savelist &rest _)
(cl-destructuring-bind (_ buf-name vars buf-string) savelist
(let ((default-directory (alist-get 'default-directory vars)))
(require 'vterm)
(with-current-buffer (get-buffer-create buf-name)
(insert buf-string)
(vterm-mode)))))))
like ranger
(defun dirvish-cd-into-vterm ()
"Switch into recent vterm buffer, and cd into `default-directory` of dirvish buffer."
(interactive)
(let ((cur-dirvish-dir default-directory)
(vterm-buffer (catch 'foo
(dolist (buffer (+workspace-buffer-list))
(let ((bn (buffer-name buffer)))
(when (and bn
;; https://stackoverflow.com/a/2238589
(with-current-buffer bn
(eq major-mode 'vterm-mode)))
(throw 'foo bn)))))))
(dirvish-quit)
(if vterm-buffer
(let ((cur-vterm-dir (with-current-buffer vterm-buffer
default-directory)))
(switch-to-buffer vterm-buffer)
(unless (or (string= cur-vterm-dir cur-dirvish-dir)
(not (vterm--safe-send-p)))
; NOTE only fish shell support directory jump by dir-name
; add space to ignore command from history
(vterm-send-string (concat " " (file-relative-name cur-dirvish-dir cur-vterm-dir)))
(vterm-send-return)))
(with-temp-buffer (setq-local default-directory cur-dirvish-dir)
(+vterm/here t)))))
!!! Just ensure no one type rm -rf
before navigate in dirvish
.
(defun vterm--safe-send-p ()
"Tell if current point safe to send string (no input after prompt)."
(let ((flag (save-excursion
(vterm-reset-cursor-point)
(evil-collection-vterm-append)
(vterm--at-prompt-p))))
(evil-normal-state)
flag))
[spell]
packages=["aspell", "aspell-en"]
(spell +aspell
+everywhere)
(after! ispell
(setq ispell-personal-dictionary
(expand-file-name ".pws" "~/.Nextcloud/ispell/")))
(setf (alist-get 'org-mode +spell-excluded-faces-alist)
(append '(org-level-1 font-lock-function-name-face help-key-binding)
(alist-get 'org-mode +spell-excluded-faces-alist)))
(setf (alist-get 'latex-mode +spell-excluded-faces-alist)
(append '(font-lock-constant-face tex-math font-lock-comment-face)
(alist-get 'latex-mode +spell-excluded-faces-alist)))
[lookup]
packages=["sqlite", "wordnet-common"]
(lookup
+docsets
+dictionary)
(add-to-list '+lookup-provider-url-alist '("Brave" "https://search.brave.com/search?q=%s"))
llm
Should always catch up with newest commit.
(unpin! gptel)
(package! gptel :recipe (:nonrecursive t))
(map! (:leader :prefix "o" :desc "gptel" "g" #'gptel))
(map! "C-c g q" #'gptel-quick
"C-c g m" #'gptel-menu
"C-c g t" #'gptel-org-set-topic)
Who in their right mind would map enter
in org-mode
to gptel-send
?
(after! gptel
(evil-define-key 'normal gptel-mode-map (kbd "RET") nil))
(after! gptel
(setq gptel-default-mode #'org-mode)
(setq gptel-include-reasoning 'ignore)
(setq gptel-expert-commands t)
;; avoid headings as prompt
(setf (alist-get 'org-mode gptel-prompt-prefix-alist) "** "
(alist-get 'org-mode gptel-response-prefix-alist) "*Response:*\n")
(load-in-doom-dir "private/gpt.el"))
;; (add-hook 'gptel-post-stream-hook 'gptel-auto-scroll)
;; (add-hook 'gptel-post-response-functions 'gptel-end-of-response))
After cmd:gptel-org-set-topic, remove the top heading for collect conversation.
(defun +my/gptel-org-rm-upper-heading ()
"Remove upper level heading line."
(while (re-search-backward "\\(?:^\\* .+$\\)[[:space:]]+" nil t)
(delete-region (match-beginning 0) (match-end 0))))
(add-hook 'gptel-prompt-filter-hook #'+my/gptel-org-rm-upper-heading)
Ask standalone question anywhere.
(defun +my/gptel-org-make-standalone ()
"Restrict prompt to system message and things belong previous heading only."
(when (and (org-back-to-heading t)
(member "standalone"
(mapcar #'substring-no-properties (org-get-tags))))
(forward-line)
;; (org-set-tags nil)
(delete-region (point-min) (point))))
(add-hook 'gptel-prompt-filter-hook #'+my/gptel-org-make-standalone)
Chat buffer should be real!
(defun gptel-buffer-p (buf)
(with-current-buffer buf (and (boundp 'gptel-mode) (eq gptel-mode t))))
(add-hook 'doom-real-buffer-functions #'gptel-buffer-p)
gptel-quick
(after! gptel-quick
(setq gptel-quick-model 'qwen3:14b)
(setq gptel-quick-backend (cdr (assoc-string "ollama" gptel--known-backends))))
(defun gptel-shift-response-heading-level (start end)
"Shift all Org headings in region so smallest is level 3 (***).
If the last line at END starts with '** ', exclude it from shifting."
(interactive "r")
(save-excursion
;; Exclude end line if starting with '** '
(let* ((orig-end end))
(goto-char end)
(beginning-of-line)
(when (looking-at "^\\*\\* ")
;; Move END to previous line's end (but not before START)
(forward-line -1)
(end-of-line)
(setq end (max start (point))))
;; STEP 1: Find minimum heading level in adjusted region
(let ((min-level nil)
(heading-re "^\\(\\*+\\) "))
(goto-char start)
(while (re-search-forward heading-re end t)
(let ((level (length (match-string 1))))
(when (or (null min-level) (< level min-level))
(setq min-level level))))
;; STEP 2: Shift all headings, if needed
(when (and min-level (< min-level 3))
(let ((shift (- 3 min-level)))
(goto-char start)
(while (re-search-forward heading-re end t)
(let ((level (length (match-string 1))))
(replace-match
(concat (make-string (+ level shift) ?*) " ")
t t)))))))))
(add-hook 'gptel-post-response-functions #'gptel-shift-response-heading-level)
(after! gptel
(set-popup-rule!
(lambda (bname _action)
(and (null gptel-display-buffer-action)
(buffer-local-value 'gptel-mode (get-buffer bname))))
:select t
:side 'right
:size 88
:quit 'current
:ttl nil))
(lsp +eglot)
magit
(use-package! tramp
:commands yadm-status
:init
(defun yadm-status ()
(interactive)
(magit-status "/yadm::"))
(map! :leader
(:prefix "g"
:desc "yadm-status" "a" #'yadm-status))
:config
;; see `man yadm'
(add-to-list 'tramp-methods
'("yadm"
(tramp-remote-shell "/bin/bash")
(tramp-remote-shell-args ("-c"))
(tramp-login-program "yadm")
(tramp-login-args (("enter"))))))
If you use fish
shell, you may change fish_prompt
. see ~/.config/fish/config.fish
cmd:magit-stage (visually stage hunks) may not work in yadm
, which cause emacs
to hang, use kbd:E s (cmd:magit-ediff-stage) instead.
magit/magit#719 Magit process hangs when trying to stage a hunk
pdf
default pdf viewer in emacs
(after! pdf-tools
(setq-default pdf-view-display-size 'fit-width))
(after! latex (setq +latex-viewers '(pdf-tools evince okular)))
;; to have the buffer refresh after compilation
(add-hook 'TeX-after-compilation-finished-functions
#'TeX-revert-document-buffer)
;; always use midnight view mode
(add-hook! 'pdf-view-mode-hook #'pdf-view-midnight-minor-mode)
Selection in pdf-tools
when evil mode enabled
Correct the file name path if it is a WSL path in Windows or an absolute path
inadvertently synced with a network disk. For pdf-sync-view
, the source file
was correctly identified only after making this adjustment.
(defun +my/synced-true-path (filename)
"Rewrite the FILENAME assuming it from synced netdisk (or WSL).
When from netdisk, ensure they have same directory structure with
respect to your home."
(if (s-starts-with-p "//wsl.localhost" filename)
(setq filename (replace-regexp-in-string "^//wsl.localhost/\\w+" "" filename)))
(unless (s-starts-with-p (getenv "HOME") filename)
(setq filename (replace-regexp-in-string "^/home/\\w+" (getenv "HOME") filename)))
filename)
(defun +my/pdf-sync-backward-search (x y)
"Go to the source corresponding to image coordinates X, Y.
Try to find the exact position, if
`pdf-sync-backward-use-heuristic' is non-nil."
(cl-destructuring-bind (source finder)
(pdf-sync-backward-correlate x y)
(setq source (+my/synced-true-path source))
(pop-to-buffer (or (find-buffer-visiting source)
(find-file-noselect source))
pdf-sync-backward-display-action)
(push-mark)
(funcall finder)
(run-hooks 'pdf-sync-backward-hook)))
(advice-add 'pdf-sync-backward-search :override #'+my/pdf-sync-backward-search)
Auto view .ps
file
(add-hook 'ps-mode-hook 'doc-view-toggle-display)
[latex]
enabled="not is_wsl"
packages=[
"miktex", "texlab",
# for `latexindent.pl` to work, which is called by `+format/buffer`
"perl-yaml-tiny", "perl-file-homedir"
]
(latex
+lsp
+fold
+cdlatex)
Invoke latex.exe
on windows.
(if (featurep :system 'wsl)
(setq LaTeX-command "latex.exe"
TeX-command "latex.exe"))
(after! evil-tex
(setq evil-tex-include-newlines-in-envs nil
evil-tex-select-newlines-with-envs nil))
cdlatex
(map! :map cdlatex-mode-map
:i "TAB" #'cdlatex-tab)
retain .bbl
as it required by APS journals.
synctex.gz
kept to sync tex view.
(after! latex
(setq LaTeX-clean-intermediate-suffixes
(seq-difference LaTeX-clean-intermediate-suffixes
'("\\.bbl" "\\.synctex\\.gz"))))
add XeTeX
mode in TeX/LaTeX
(after! tex
(add-to-list 'TeX-command-list
'("XeLaTeX" "%`xelatex%(mode) %(extraopts) %S%(PDFout)%' %t" TeX-run-TeX nil t)))
fn:latex-indent cmd:LaTeX-fill-buffer
cmd:+format/buffer default installed by miktex
(after! apheleia
(set-formatter! 'latexindent '("latexindent" "-l" "-r" "--logfile=/dev/null")
:modes '(LaTeX-mode)))
formatting - LaTeXTidy in Emacs - TeX - LaTeX Stack Exchange
[lua]
enabled="not is_wsl"
packages=["lua-language-server"]
(lua +lsp)
lsp support
(after! lua-mode
(setq lsp-clients-lua-language-server-bin "/usr/bin/lua-language-server")
(setq lsp-clients-lua-language-server-main-location "/usr/lib/lua-language-server/bin/main.lua")
(setq lsp-clients-lua-language-server-args '("-E" "--logpath" "/tmp/lua-language-server"))
;; (lsp-clients-lua-language-server-command '("lua-language-server" "-E"))
(setq lsp-clients-lua-language-server-command nil))
ligatures
(after! lua-mode
(set-ligatures! 'lua-mode
:def "function"
:return "return"
:and "and"
:or "or"
:not "not"
:true "true"
:false "false"
:for "for"))
[org]
packages=[
"xclip",
"maim",
"graphviz"
]
(org
+hugo
+dragndrop
+jupyter
+noter
+present
+pandoc
+pretty
+roam)
Fix function link recognized as footnote.
(use-package org-modern
:init
(setq org-modern-footnote nil))
(after! org-modern
(setq org-modern-star 'replace))
(setq org-directory "~/Documents/org/"
org-agenda-files '("agenda/todos.org" "agenda/projects.org")
org-agenda-start-with-log-mode t
org-agenda-prefix-format '((agenda . " %i %-12:c%?-12t% s")
(todo . " ")
(tags . " %i %-12:c")
(search . " %i %-12:c"))
org-log-done 'time
org-log-into-drawer t
org-startup-numerated t
org-image-actual-width 400
org-duration-format '((special . h:mm))
org-startup-with-inline-images t
org-refile-targets '(("archive.org" :maxlevel . 1)
("projects.org")))
saving - How do I automatically save org-mode buffers? - Emacs Stack Exchange
(after! org
;;(org-clock-persist 'history)
(org-clock-persistence-insinuate)
(advice-add 'org-refile :after 'org-save-all-org-buffers)
(advice-add 'org-agenda-quit :before 'org-save-all-org-buffers))
custom agenda view from
(setq org-agenda-custom-commands
'(("g" "Get Things Done (GTD)"
((agenda ""
((org-agenda-skip-function
'(org-agenda-skip-entry-if 'deadline))
(org-deadline-warning-days 0)
(org-agenda-start-day "-1d")
(org-agenda-span 4)))
(todo "STRT"
((org-agenda-skip-function
'(org-agenda-skip-entry-if 'deadline))
(org-agenda-prefix-format " %i %-12:c [%e] ")
(org-agenda-overriding-header "\nTasks\n")))
(tags-todo "inbox"
((org-agenda-prefix-format " %?-12t% s")
(org-agenda-overriding-header "\nInbox\n")))
(tags "CLOSED>=\"<today>\""
((org-agenda-overriding-header "\nCompleted today\n")))))))
(after! org-capture
(setq org-capture-templates
`(("i" "Inbox" entry (file "agenda/todos.org")
"* TODO %?\n%U\n%i" :empty-lines 1 :prepend t)
("@" "Inbox [mu4e]" entry (file "agenda/todos.org")
"* TODO Reply to \"%a\"\n%U\n%i" :empty-lines 1 :prepend t)
("n" "Inbox [note]" entry (file "agenda/todos.org")
"* TODO [%a] %? %^G\n%U\n%i" :empty-lines 1 :prepend t))))
- emacs - org-mode capture : dynamic file name - Stack Overflow
- emacs-from-scratch/init.el at c55d0f5e309f7ed8ffa3c00bc35c75937a5184e4 · davi…
Skip executing org source blocks within commented headings. To optimize, consider advising fn:org-babel-map-executables
(defun +my/org-babel-execute-buffer (&optional arg)
"Execute source code blocks in a buffer.
Call `org-babel-execute-src-block' on every source block in
the current buffer."
(interactive "P")
(org-babel-eval-wipe-error-buffer)
(org-save-outline-visibility t
(org-babel-map-executables nil
(unless (org-in-commented-heading-p)
(if (memq (org-element-type (org-element-context))
'(babel-call inline-babel-call))
(org-babel-lob-execute-maybe)
(org-babel-execute-src-block arg))))))
(advice-add 'org-babel-execute-buffer :override #'+my/org-babel-execute-buffer)
Restore window-start after execute subtree. For hook based implement for all fn:narrow-to-region see:
(defun +my/org-babel-execute-subtree (&optional arg)
"Execute source code blocks in a subtree.
Call `org-babel-execute-src-block' on every source block in
the current subtree, passing over the prefix argument ARG."
(interactive "P")
(let ((original-start (window-start)))
(save-restriction
(save-excursion
(org-narrow-to-subtree)
(org-babel-execute-buffer arg)))
(set-window-start (selected-window) original-start)))
(advice-add 'org-babel-execute-subtree :override #'+my/org-babel-execute-subtree)
[jupyter]
packages=["jupyter-notebook"]
(package! jupyter
:pin nil
:recipe (:host github :repo "fakeGenuis/jupyter"))
start session only when exactly execute it.
(after! jupyter
(setq jupyter-org-auto-connect nil))
doomemacs/doomemacs#7354 Jupyter fails to function after upgrade
(with-eval-after-load 'ob-jupyter
(org-babel-jupyter-aliases-from-kernelspecs))
(after! ob-jupyter
;; (push :text/html jupyter-org-mime-types)
(set-popup-rule!
"^\\*jupyter-traceback"
:side 'bottom :size 10 :slot -2 :select t))
To view contents of .ipynb
file, see
Possible issues
- emacs-jupyter/jupyter#584 `jupyter-or…
- doomemacs/doomemacs#3171 if: Need a v…
- emacs-jupyter/jupyter#575 Remote kern…
(package! jupyter-ext
:recipe (:host github
:repo "fakeGenuis/jupyter-ext"))
(use-package! jupyter-ext
:commands jupyter-org-transient
:init
(map! :map jupyter-org-interaction-mode-map
:n ";" #'jupyter-org-transient)
:config
;; A tweaked completion at point function for corfu
(advice-add 'jupyter-completion-at-point :override #'jupyter-ext-completion-at-point))
(after! ob-core
;; with multiple output and =:async yes=, text mass up after `example` block
(setq org-babel-min-lines-for-block-output 256))
Intent mainly with file:::wolfram in jupyter, respect to doom’s org babel lazy load
(defvar +my/jupyter-langs '()
"A list of language that use jupyter override.")
(add-hook '+org-babel-load-functions
(defun +org-babel-load-jupyter-override-h (lang)
;; don't multi run `org-babel-jupyter-override-src-block'
(unless (boundp 'org-babel-header-args:jupyter)
(require 'ob-jupyter))
;; or even org-babel-header-args:%s will be reset
(when-let ((lang-name (symbol-name lang))
(_ (member lang-name +my/jupyter-langs)))
(set (intern (format "org-babel-default-header-args:jupyter-%s" lang-name))
(symbol-value (intern (format "org-babel-default-header-args:%s" lang-name))))
(org-babel-jupyter-override-src-block lang-name)))
-90)
Session async have been include in org mode, see how to implement async using built in method.
- GitHub - jackkamm/ob-session-async: Asynchronous org-mode session evaluation
- emacs/etc/ORG-NEWS at a7cb220523d881449a2dba683e7358b3312fd482 · emacs-mirror…
This branch mainly fix apply: Wrong number of arguments
of advice
cmd:ob-async-org-babel-execute-src-block
(package! ob-async
:pin nil
:recipe (:host github
:repo "stsquad/ob-async"
:branch "update-signature-skip-session"))
(after! org-noter
(org-noter-set-doc-split-fraction '(0.75 . 0.25)))
(setq org-roam-directory (expand-file-name "roam/" org-directory))
(after! org-roam
(setq org-roam-dailies-capture-templates
'(("d" "default" entry "* %?\n[%<%Y-%m-%d %H:%M>]\n"
:if-new (file+head "%<%Y-%m-%d>.org" "#+title: %<%Y-%m-%d>\n")))))
(after! org-roam
(setq org-roam-graph-viewer "librewolf")
(setq org-roam-graph-link-hidden-types
'("file" "http" "https" "attachment" "zotero"
"fuzzy" "doom-module" "kbd" "fn")))
kbd:SPC s b should work as expected
revert native org-cycle
style, see doom-modules:lang/org/README.org
(after! evil-org
(remove-hook 'org-tab-first-hook #'+org-cycle-only-current-subtree-h))
hlissner/doom-emacs#5436 org-src-window-setup not working correctly
(after! org-src
(setq org-src-window-setup 'reorganize-frame)
(set-popup-rule! "^\\*Org Src" :ignore t))
format org-src
(map! :after org :map evil-org-mode-map
:n "g Q" #'+format:region)
org-format
(use-package org-format
:defer 10
;; dawn lazy load
;; :commands (apheleia-format-org-buffer)
:init
(add-to-list 'load-path (expand-file-name "org-format" org-directory)))
(cl-defun apheleia-format-org-buffer
(&key buffer scratch callback &allow-other-keys)
"Copy BUFFER to SCRATCH, then format scratch, then call CALLBACK."
;; ugly implement!
(with-current-buffer scratch
;; FIXME so many local value to copy
(let ((buffer-file-name (buffer-local-value 'buffer-file-name buffer))
(org-format-ignore-link (buffer-local-value 'org-format-ignore-link buffer))
(org-format-keep-empty-below-heading (buffer-local-value 'org-format-keep-empty-below-heading buffer)))
(org-format-buffer))
(funcall callback)))
(after! org
(set-formatter! 'orgfmt #'apheleia-format-org-buffer :modes '(org-mode)))
(after! org
(setq org-archive-location ".bak/%s_archive::")
;; always display _{} and ^{}, please
(setq org-pretty-entities-include-sub-superscripts nil))
Avoid lengthy title
(after! org-cliplink
(setq org-cliplink-max-length 40))
[python]
packages=[
"python-pytest",
"python-nose",
"python-black",
"python-pyflakes",
"python-isort",
"python-pipenv",
"pyright"
]
(python +lsp +pyright +tree-sitter)
doomemacs/doomemacs#3171 if: Need a v…
(with-eval-after-load 'ob-core
(setq org-babel-default-header-args:jupyter-python
'((:kernel . "python3"))))
[sh]
packages=["shellcheck-bin", "bash-language-server", "shfmt"]
(sh +fish +lsp +powershell)
fish shell ligatures
(after! fish-mode
(set-ligatures! 'fish-mode
:def "function"
:return "return"
:and "&&"
:or "||"
:not "not"
:true "true"
:false "false"
:for "for"))
[yaml]
packages=["yaml-language-server"]
(yaml +lsp)
[wolfram]
enabled="not is_wsl"
packages=["mathematica"]
(package! wolfram-mode
:recipe (:local-repo "~/lib/wolfram-mode/"))
(use-package! wolfram-mode
:defer t)
wolfram-format
(after! apheleia
(load "~/lib/wolframFormatter/wolfram-format.el"))
Note that apheleia-formatter
not work well with org-src block, turn
org-indent-mode
off and then run kbd:g Q and then turn on org-indent-mode
.
(after! (wolfram-mode ligature)
(set-ligatures! 'wolfram-mode
:and "&&"
:or "||"
:not "!"
:null "None"
:true "True"
:false "False"))
WLPATH="~/.local/lib/lsp-wl/"
[[ -d "$WLPATH" ]] || git clone https://github.com/kenkangxgwe/lsp-wl.git "$WLPATH"
PacletInstall["CodeParser"]
PacletInstall["CodeInspector"]
PacletInstall["ZeroMQLink"] (* 1.2.6+ *)
eglot
is far faster than LSP
!
(let ((wlserver (expand-file-name "~/.local/lib/lsp-wl/init.wls")))
(when (and (file-exists-p wlserver) (executable-find "wolframscript"))
(with-eval-after-load 'eglot
(add-to-list 'eglot-server-programs
`(wolfram-mode . ("wolframscript" "-f" ,wlserver
"--tcp-server" :autoport))))))
Completion seems not work with 12.3
.
(add-to-list '+my/jupyter-langs "Wolfram-Language")
(after! org-src
(add-to-list 'org-src-lang-modes '("Wolfram-Language" . wolfram))
(setq org-babel-default-header-args:Wolfram-Language
'((:kernel . "wolframforjupyter")
(:async . "yes")
(:results . "scalar"))))
(add-to-list '+org-babel-native-async-langs 'Wolfram-Language)
<>
in Wolfram
org-src break parentheses match.
(defun +my/remove-angle-brackets-from-syntax ()
(modify-syntax-entry ?< "." (syntax-table)) ;; Treat < as punctuation
(modify-syntax-entry ?> "." (syntax-table))) ;; Treat > as punctuation
(add-hook 'org-mode-hook #'+my/remove-angle-brackets-from-syntax)
(after! (wolfram-mode yasnippet)
(let ((key-templates '()))
(dolist (key wolfram-structure-keywords)
(push `(,key ,(format "(* ::%s:: *)\n(*$1*)\n\n" key)) key-templates))
(yas-define-snippets 'wolfram-mode key-templates)))
[markdown]
packages=[
"pandoc-bin"
]
markdown
["typst-mode"]
packages=[
"typst",
"tree-sitter-typst-git", # tree sitter grammar for typst, demand by typst-ts-mode
"tinymist" # language server
# "typst-lsp-bin" # alternative language server
]
(package! typst-ts-mode
:recipe (:host codeberg
:repo "meow_king/typst-ts-mode"
:files (:defaults "*.el")))
(use-package! typst-ts-mode
:mode ("\\.typ\\'")
:custom
(typst-ts-watch-options "--open")
(typst-ts-mode-grammar-location (expand-file-name "tree-sitter/libtree-sitter-typst.so" user-emacs-directory))
(typst-ts-mode-enable-raw-blocks-highlight t)
:config
(setq typst-ts-mode-indent-offset 2)
(keymap-set typst-ts-mode-map "C-c C-c" #'typst-ts-tmenu))
use pdf-tools
to preview
(defun typst-pdf-tools-preview (&optional buffer)
"Use `pdf-tools' to preview compiled pdf."
(interactive)
(find-file-other-window (typst-ts-compile-get-result-pdf-filename buffer)))
(advice-add 'typst-ts-preview :override #'typst-pdf-tools-preview)
language server
(with-eval-after-load 'eglot
(with-eval-after-load 'typst-ts-mode
(add-to-list 'eglot-server-programs
`((typst-ts-mode) .
,(eglot-alternatives `(,typst-ts-lsp-download-path
"tinymist"
"typst-lsp"))))))
more configuration on Tinymist Docs
css
(prependq! auto-mode-alist '(("\\.rasi\\'" . css-mode)))
defer is not work, same to immediate!
(after! parinfer-rust-mode
(setq parinfer-rust-check-before-enable 'defer))
[mu4e]
packages=[
"isync",
"mu",
"pass",
"msmtp"
#"imagemagick"
]
Example for initialing mu
and mbsync
mkdir -p ~/.mail/$mailname
mu init --maildir=~/.mail --my-address=...@...
mu index
mbsync -c ~/.config/isync/$mbsyncrc -V -a
(mu4e +gmail +org)
(set-popup-rule! "^\\*mu4e-\\(main\\|headers\\)\\*" :ignore t)
(setq mu4e-update-interval 300)
(after! mu4e
(setq mu4e-split-view 'vertical
mu4e-change-filenames-when-moving t
mu4e-attachment-dir "~/Downloads"
;; every new email composition gets its own frame!
mu4e-compose-in-new-frame t
mu4e-use-fancy-chars t))
send email by msmtp
, see ~/.config/msmtp/config
(after! mu4e
(setq sendmail-program (executable-find "msmtp")
send-mail-function #'smtpmail-send-it
message-sendmail-f-is-evil t
message-sendmail-extra-arguments '("--read-envelope-from")
message-send-mail-function #'message-send-mail-with-sendmail))
private variables mu4e-get-mail-command
and mu4e-contexts
(after! mu4e
(load-in-doom-dir "private/mu4e.el"))
(rss +org)
Read your RSS feeds in emacs with elfeed | Pragmatic Emacs
(after! elfeed
(add-hook! 'elfeed-search-mode-hook 'elfeed-update)
(setq elfeed-db-directory (concat (getenv "NCDIR") "elfeed/db/")
elfeed-enclosure-default-dir (concat (getenv "NCDIR") "elfeed/enclosures/")
;; elfeed-search-filter "@1-month-ago +unread"
rmh-elfeed-org-files (list (expand-file-name "elfeed.org" org-directory)))
(map! :leader
(:prefix "o"
:desc "elfeed" "e" #'elfeed)))
(after! elfeed-goodies
(setq elfeed-goodies/entry-pane-size 0.5))
everywhere
[everywhere]
packages=[
"xclip",
"xdotool",
"xorg-xprop",
"xorg-xwininfo"
]
(package! gt)
(use-package gt
:bind ("C-c t" . gt-translate)
:config
(setq gt-langs '(en zh))
(setq gt-default-translator
(gt-translator
:engines (list (gt-youdao-dict-engine) (gt-youdao-suggest-engine))
;; :engines (gt-google-engine)
:render (gt-buffer-render)))
(set-popup-rule!
"^\\*gt-result\\*"
:side 'left :size 60 :slot -2 :select t))
(package! keycast)
tarsius/keycast#7 Add support for moody and doom-modeline.
(use-package! keycast
:commands (keycast-mode)
:init
(map! :leader
(:prefix "t"
:desc "Toggle keycast" "k" #'keycast-mode))
:config
(define-minor-mode keycast-mode
"Show current command and its key binding in the mode line (fix for use with doom-mode-line)."
:global t
(if keycast-mode
(progn (add-hook 'pre-command-hook 'keycast--update t)
(setq keycast-mode-line-window-predicate
'keycast-active-frame-bottom-right-p))
(remove-hook 'pre-command-hook 'keycast--update)
(setq keycast-mode-line-window-predicate 'ignore)))
(add-to-list 'global-mode-string '("" keycast-mode-line)))
(package! screenshot
:recipe (:host github :repo "yangsheng6810/screenshot"))
(use-package! screenshot
:commands screenshot
:init
(map! (:leader :prefix "o"
:desc "sreenshot within emacs" "S" #'screenshot)))
Allow attach the screenshot.
(after! screenshot
(screenshot--def-action
"attach"
(set-process-sentinel
;; NOTE feh not transparent well when shadow is included
(start-process "feh" nil "feh"
"--class=attached_window"
screenshot--tmp-file)
(lambda (process event) (delete-file screenshot--tmp-file))))
(transient-append-suffix 'screenshot-transient '(-1 1)
'("a" "Attach" screenshot-attach)))
alias --save convert magick
in fish shell to suppress the warning
WARNING: The convert command is deprecated in IMv7, use “magick” instead of “convert” or “magick convert”
Issues
- Region not correctly selected in
vterm
buffer - When select in visual line mode, newline not stripped
(package! zotxt)
(defun org-zotxt-get-attachment-path ()
"Get attachment file path"
(interactive "P")
(let ((item-id (org-zotxt-extract-link-id-at-point)))
(deferred:$
(zotxt--request-deferred
(format "%s/items" zotxt-url-base)
:params `(("key" . ,item-id) ("format" . "paths"))
:parser 'json-read)
(deferred:nextc it
(lambda (response)
(let ((paths (cdr (assq 'paths (elt (request-response-data response) 0)))))
(org-zotxt-choose-path paths))))
(deferred:error it #'zotxt--deferred-handle-error)
(if zotxt--debug-sync (deferred:sync! it)
(deferred:nextc it
(lambda (path) path))))))
(defun +my/tilde-home-path (path)
"covert path starts with /home/$usr/ to '~'"
(interactive)
(let ((home (getenv "HOME")))
(if (string-prefix-p home path)
(string-join `("~" ,(string-remove-prefix home path)) "")
path)))
(defun org-zotxt-copy-attachment-path ()
"Open attachment of Zotero items linked at point.
Opens with `org-open-file', see for more information about ARG."
(interactive)
(deferred:$
(deferred:next
(lambda ()
(org-zotxt-get-attachment-path)))
(deferred:nextc it
(lambda (path)
(let ((new-path (+my/tilde-home-path path)))
(kill-new new-path)
(message "\"%s\" send to system clipboard!" new-path))))))
A research workflow with Zotero and Org mode | mkbehr.com
(use-package zotxt
:hook (org-mode . org-zotxt-mode)
:config
(setq zotxt-default-bibliography-style "american-physical-society-et-al"))
(map! :map org-zotxt-mode-map
:desc "org-zotxt-insert-selected"
;; use <quote> in in case it pollute balanced brackets
"C-c <quote> <quote>" (cmd!! #'org-zotxt-insert-reference-link '(4))
:desc "org-zotxt-copy-attachment-path"
"C-c <quote> c" #'org-zotxt-copy-attachment-path)
open attachment with point at arxiv link
(defun org-zotxt-open-arxiv-attachment ()
"open attachment from arxiv link, by zotxt"
(interactive)
(let* ((link (org-element-context))
(desc (buffer-substring-no-properties (org-element-property :contents-begin link)
(org-element-property :contents-end link))))
(org-zotxt-insert-reference-link)))
converting comments into ascii arts
[figlet]
packages=["figlet"]
(package! figlet)
(use-package! figlet
:defer t
:config
(setq figlet-options '("-W" "-f" "script")))
(package! tldr)
:config
- EmacsWiki: Unfill Paragraph
- GitHub - purcell/unfill: Functions providing the inverse of Emacs’ fill-parag…
;;; Stefan Monnier <foo at acm.org>. It is the opposite of fill-paragraph
(defun unfill-paragraph (&optional region)
"Takes a multi-line paragraph and makes it into a single line of text."
(interactive (progn (barf-if-buffer-read-only) '(t)))
(let ((fill-column (point-max))
;; This would override `fill-column' if it's an integer.
(emacs-lisp-docstring-fill-column t))
(fill-paragraph nil region)))
;; Handy key definition
(define-key global-map "\M-Q" 'unfill-paragraph)
thank you, fish 4.0😄️
(after! tramp
(add-to-list 'process-environment "SHELL=/bin/bash"))
- akermu/emacs-libvterm#689 Tramp-login-shells custom doesn’t match type
- akermu/emacs-libvterm#706 Allow using the default login shell for remote conn…
- ~/.config/emacs/modules/tools/magit/config.el
- magit/transient#338 Transient window doesn’t come back if display-action is s…
- karthink/gptel#583 Transient issue wh…
(after! (transient magit gptel)
(setq transient-display-buffer-action
'(display-buffer-below-selected
(dedicated . t)
(inhibit-same-window . t)))
(setq transient-show-during-minibuffer-read t))
see also karthink/gptel#583 Transient issue when selecting a model in `gptel-menu`
(after! projectile
(setq projectile-indexing-method 'alien
projectile-sort-order 'recently-active
projectile-file-exists-remote-cache-expire (* 10 60)
projectile-track-known-projects-automatically nil
;; projectile-require-project-root t
projectile-auto-discover t)
;; (projectile-file-exists-local-cache-expire (* 5 60)))
(add-to-list 'projectile-globally-ignored-directories
"*\\.run\\.tmp$")
(pushnew! projectile-globally-ignored-modes
"helpful-mode" "dired-mode")
(add-to-list 'projectile-globally-ignored-buffers "*doom*"))
For non git project, better add following in project root .dir-locals.el
((nil . ((projectile-indexing-method . hybrid))))
and add ignored files in .projectile.
(setq url-proxy-services
`(("no_proxy" . "^\\(localhost\\|10\\..*\\|192\\.168\\..*\\)")
("http" . ,(shell-command-to-string "echo -n $ALL_PROXY"))
("https" . ,(shell-command-to-string "echo -n $ALL_PROXY"))))
Open link with host Librewolf
browser
(if (featurep :system 'wsl)
(setq browse-url-firefox-program "librewolf.exe"))
(defvar rx-arxiv-regexp
(rx (= 4 num) "." (= 5 num))
"Regular expression for arxiv id.")
(defun org-insert-arxiv-link ()
"Insert arxiv link with arxiv id as description."
(interactive)
(let* ((ring (current-kill 0))
(id (if (string-match rx-arxiv-regexp ring)
(match-string 0 ring)
(read-string "Input arxiv id:"))))
(insert " ")
(org-insert-link nil (concat "https://arxiv.org/abs/" id) id)))
(add-to-list '+lookup-provider-url-alist '("Inspire" "https://inspirehep.net/literature?q=%s"))
(map! :leader
:desc "Eval expression" ":" #'pp-eval-expression
:desc "M-x" ";" #'execute-extended-command
:desc "Org agenda" "=" #'org-agenda)