- Good examples
- General settings
- General appearence
- Minibuffer
- Major modes
- Minor modes
- Buffer
- General configuration
- General buffer actions
- Switch between buffers
- Autocomplete
- Syntax checking
- Spell checking
- Grammar checking
- Paren handling
- Indentation
- Selection
- Code folding
- Context menu
- Cursor actions
- Keystroke visualizer
- Lorem ipsum / Blindtext
- Undo & remove
- Save, kill & yank
- Search & replace
- Narrowing
- Commenting
- Quoting
- Line actions
- Capitalization
- Special characters
- Speech to text
- Thesauri
- Translation
- Printing
- Integers
- Numbered examples
- Zooming
- Files
- Project management
- Windows and frames
- Bookmarks
- General settings
- [[#burly][Burly]]
- Git
- Kill ring
- Shells
- Data security
- System management
- Tags
- Web browsing
- Remote connections
- Help
- Hydras
- hydra: begin
- Hydras for function keys
- hydra-artist
- hydra-bibtex
- hydra-bookmarks
- hydra-cm-mode
- hydra-dired
- hydra-elisp
- hydra-org
- hydra-deft
- hydra-git-gutter
- hydra-helm
- hydra-ibuffer
- hydra-image
- hydra-insert-date
- hydra-insert-file-name
- hydra-jump
- hydra-khardel
- hydra-latex
- hydra-macro
- hydra-markdown
- hydra-mu4e
- hydra-flycheck
- hydra-flyspell
- hydra-compilation-error
- hydra-multiple-cursors
- hydra-highlight-changes
- hydra-highlight-symbol
- hydra-pdftools
- hydra-pomidor
- hydra-position-register
- hydra-load-theme
- hydra-search
- hydra-smerge
- hydra-tags
- hydra-transpose
- hydra-drag-stuff
- hydra: end
- Key bindings
- Debugging
- Private settings
- http://ivanmalison.github.io/dotfiles/
- https://github.com/novoid/dot-emacs/blob/master/config.org
- http://www.coli.uni-saarland.de/~slemaguer/emacs/main.html
- https://github.com/progfolio/.emacs.d
General settings concerning startup, special variables, package management etc. are stored in an extra file. init.el
Don’t show the toolbar:
(tool-bar-mode 0)
https://github.com/emacs-dashboard/emacs-dashboard
An extensible Emacs startup screen.
(use-package dashboard
:ensure t
:diminish dashboard-mode
:config
(setq
dashboard-banner-logo-title (emacs-version)
dashboard-startup-banner 'logo
dashboard-items '((recents . 10)
(bookmarks . 10)
(projects . 5)
)
)
(add-to-list 'dashboard-item-generators '(custom-settings . dashboard-insert-custom-settings))
(add-to-list 'dashboard-items '(custom-settings) t)
(define-key dashboard-mode-map (kbd "<up>") (lambda () (interactive)(widget-forward -1)))
(define-key dashboard-mode-map (kbd "<down>") (lambda () (interactive)(widget-forward 1)))
;; (setq dashboard-set-navigator t)
;; (setq dashboard-navigator-buttons
;; `(;; line1
;; ((,(all-the-icons-octicon "mark-github" :height 1.1 :v-adjust 0.0)
;; "Homepage"
;; "Browse homepage"
;; (lambda (&rest _) (browse-url "homepage")))
;; ("★" "Star" "Show stars" (lambda (&rest _) (show-stars)) warning)
;; ("?" "" "?/h" #'show-help nil "<" ">"))
;; ;; line 2
;; ((,(all-the-icons-faicon "linkedin" :height 1.1 :v-adjust 0.0)
;; "Linkedin"
;; ""
;; (lambda (&rest _) (browse-url "homepage")))
;; ("⚑" nil "Show flags" (lambda (&rest _) (message "flag")) error))))
(dashboard-setup-startup-hook)
)
Custom settings (https://www.gnu.org/software/emacs/manual/html_mono/widget.html):
(defun dashboard-insert-custom-settings (&rest ignore)
(interactive)
(widget-insert "Custom settings:\n\t\t")
(widget-create
'checkbox
:notify (lambda (&rest ignore)
(if (bound-and-true-p cua-mode)
(progn (cua-mode nil)
(customize-save-variable 'cua-mode nil))
(cua-mode t)
(customize-save-variable 'cua-mode t)
))
(bound-and-true-p cua-mode))
(widget-insert " Use CUA-mode?"))
Show dashboard when also starting a client:
(setq initial-buffer-choice (lambda () (get-buffer "*dashboard*")))
No beeping:
(setq visible-bell nil)
Show matching brackets:
(show-paren-mode 1)
(setq show-paren-delay 0)
Apply syntax highlighting to all buffers:
(global-font-lock-mode t)
https://github.com/nschum/highlight-symbol.el
Quickly highlight a symbol – most likely the word under point – throughout the buffer and cycle through its locations. There is a hydra attached to it: hydra-highlight-symbol
(use-package highlight-symbol
:ensure t
:config
(setq highlight-symbol-idle-delay 0.2)
(add-hook 'highlight-symbol-mode-hook
(function
(lambda () (highlight-symbol-nav-mode +1)))))
Highlight line of cursor:
(global-hl-line-mode t)
Soft-wrap lines:
(global-visual-line-mode t)
Display line numbers in the modeline:
(line-number-mode t)
Before Emacs v26, the (sometimes slow) linum package was used for displaying the line numbers in the margin of the window:
;; ;; before Emacs 26
;; (global-linum-mode t)
;; (setq linum-format " %3d ")
With Emcas v26, the display of line numbers is built-in and much faster:
;; ;; with Emacs 26
;; (global-display-line-numbers-mode)
Line numbering can be turned on/off with M-x display-line-numbers-mode.
Relative line numbers will be displayed after setting display-line-numbers
as follows:
(setq display-line-numbers 'relative)
Let the cursor blink forever:
(blink-cursor-mode 1) ; blink
(setq blink-cursor-blinks 0) ; blink forever
Stretch cursor:
(setq x-stretch-cursor t)
A face is a collection of graphical attributes for displaying text: font, foreground color, background color, optional underlining, etc.
https://www.gnu.org/software/emacs/manual/html_node/emacs/Faces.html
A theme is a specified collection of faces, so that different types of text is displayed in a different way.
Add local themes directory to search space (just in case):
(setq themes-dir
(expand-file-name "themes" user-emacs-directory))
(add-to-list 'custom-theme-load-path themes-dir)
https://github.com/oneKelvinSmith/monokai-emacs
The monokai theme is one of my favourites.
(use-package monokai-theme
:ensure t
:config
(load-theme 'monokai t)
;; font size of org-mode headers
(setq monokai-height-minus-1 1.0
monokai-height-plus-1 1.0
monokai-height-plus-2 1.1
monokai-height-plus-3 1.25
monokai-height-plus-4 1.5)
)
Yet I don’t like how regions are highlighted:
(custom-theme-set-faces
'monokai
`(region ((t (:inherit highlight :background "#FFB269" :foreground ,monokai-background))))
)
(enable-theme 'monokai) ; needed since v27
Toggle proportional mode when appropriate. Inspired by https://ogbe.net/blog/toggle-serif.html
(defvar font-preserve-default-list nil
"A list holding the faces that preserve the default family and
height when TOGGLE-SERIF is used.")
(setq font-preserve-default-list
'(;; LaTeX markup
font-latex-math-face
font-latex-sedate-face
font-latex-warning-face
;; org markup
org-latex-and-related
org-meta-line
org-verbatim
org-block-begin-line
;; syntax highlighting using font-lock
font-lock-builtin-face
font-lock-comment-delimiter-face
font-lock-comment-face
font-lock-constant-face
font-lock-doc-face
font-lock-function-name-face
font-lock-keyword-face
font-lock-negation-char-face
font-lock-preprocessor-face
font-lock-regexp-grouping-backslash
font-lock-regexp-grouping-construct
font-lock-string-face
font-lock-type-face
font-lock-variable-name-face
font-lock-warning-face))
(defun toggle-proportional ()
"Change the default face of the current buffer to use a proportional family."
(interactive)
(when (display-graphic-p) ;; this is only for graphical emacs
;; the serif font familiy and height, save the default attributes
(let ((proportional-fam "Segoe UI")
(proportional-height 125)
(default-fam (face-attribute 'default :family))
(default-height (face-attribute 'default :height)))
(if (not (bound-and-true-p default-cookie))
(progn (make-local-variable 'default-cookie)
(make-local-variable 'preserve-default-cookies-list)
(setq preserve-default-cookies-list nil)
;; remap default face to serif
(setq default-cookie
(face-remap-add-relative
'default :family proportional-fam :height proportional-height))
;; keep previously defined monospace fonts the same
(dolist (face font-preserve-default-list)
(add-to-list 'preserve-default-cookies-list
(face-remap-add-relative
face :family default-fam :height default-height)))
(message "Turned on proportional font."))
;; undo changes
(progn (face-remap-remove-relative default-cookie)
(dolist (cookie preserve-default-cookies-list)
(face-remap-remove-relative cookie))
(setq default-cookie nil)
(setq preserve-default-cookies-list nil)
(message "Restored default fonts."))))))
Replace LaTeX commands by UTF8 symbols:
;; (use-package latex-pretty-symbols
;; :ensure t)
As of Emacs v29, displaying and selecting emojis is now built-in via input methods.
(global-set-key (kbd "C-c i e") 'emoji-search)
Show file path in window title:
(setq frame-title-format
'(buffer-file-name "%b - %f" ; File buffer
(dired-directory dired-directory ; Dired buffer
(revert-buffer-function "%b" ; Buffer Menu
("%b - Dir: " default-directory))))) ; Plain buffer
Show date and time:
(setq display-time-24hr-format t)
(display-time-mode +1)
Fringe style:
;; (set-face-attribute 'fringe nil :background "#3F3F3F" :foreground "#3F3F3F")
https://github.com/Malabarba/smart-mode-line/
Make the mode line nicer and better readable.
(use-package smart-mode-line
:ensure t
:init
;; (setq sml/theme 'dark)
(setq sml/no-confirm-load-theme t)
:config
(sml/setup))
https://github.com/joostkremers/writeroom-mode
A minor mode for Emacs that implements a distraction-free writing mode similar to the famous Writeroom editor for OS X.
(use-package writeroom-mode
:ensure t
:bind
(:map writeroom-mode-map
("C-M-<" . writeroom-decrease-width)
("C-M->" . writeroom-increase-width)
("C-M-=" . writeroom-adjust-width)
("C-<f10>" . writeroom-toggle-mode-line)
)
)
(global-set-key (kbd "<f10>") 'writeroom-mode)
https://github.com/emacsorphanage/ov
Package for manipulating overlays. However, it does not affect font-lock or text-properties.
(use-package ov
:ensure t)
https://github.com/domtronn/all-the-icons.el
all-the-icons
makes popular icons available in Emacs.
(use-package all-the-icons
:ensure t
:if (display-graphic-p))
Missing fonts can be installed with M-x all-the-icons-install-fonts
.
https://github.com/Lindydancer/font-lock-studio
Interactive debugger for font-lock keywords.
(use-package font-lock-studio
:ensure t)
https://www.gnu.org/software/emacs/manual/html_node/elisp/The-Echo-Area.html
The echo area is used for displaying error messages, messages created with the message
function, and for echoing keystrokes. It is not to be confused with the minibuffer, although it is shown in the same place of an Emacs window,
Messages from the echo area are also recorded in the *Messages*
buffer.
The following code adds timestamps to messages in the *Messages*
buffer. It is a modified version of https://emacs.stackexchange.com/a/64551/12336.
(defvar last-message-with-timestamp nil
"Last message with timestamp appended to it.")
(defun add-timestamp-to-message (format-string &rest args)
"Prepend timestamp to each message in message buffer.
FORMAT-STRING and ARGS are used by `message' to print a formatted string.
Enable with (advice-add 'message :before 'add-timestamp-to-message)"
(when (and message-log-max
(not (string-equal format-string "%s%s")))
(let ((formatted-message-string (if args
(apply 'format `(,format-string ,@args))
format-string)))
(unless (string= formatted-message-string last-message-with-timestamp)
(setq last-message-with-timestamp formatted-message-string)
(let ((deactivate-mark nil)
(inhibit-read-only t))
(with-current-buffer "*Messages*"
(goto-char (point-max))
(when (not (bolp))
(newline))
(insert (format-time-string "[%F %T] "))))))))
(advice-add 'message :before 'add-timestamp-to-message)
Shorten yes/no answers to y/n:
(fset 'yes-or-no-p 'y-or-n-p)
Currently, I’m using neither of the two.
https://www.gnu.org/software/emacs/manual/html_node/emacs/Imenu.html
Imenu is built into Emacs and helps to navigate between “definitions”, e.g. defun statements in lisp code, within a buffer.
https://github.com/vspinu/imenu-anywhere
Imenu navigation across buffers of the same type (major mode, project).
(use-package imenu-anywhere
:ensure t)
https://github.com/emacs-helm/helm https://tuhdo.github.io/helm-intro.html
Emacs framework for incremental completions and narrowing selections.
(use-package helm
:diminish helm-mode
:init
(progn
;; (require 'helm-config) ; Obsolete since v3.9.1: https://github.com/emacs-helm/helm/commit/e81fbbc687705595ab65ae5cd3bdf93c17a90743
(setq helm-candidate-number-limit 100)
(setq helm-idle-delay 0.0 ; update sources immediately
helm-input-idle-delay 0.01 ; update input quickly
helm-yas-display-key-on-candidate t
helm-M-x-requires-pattern nil
helm-ff-skip-boring-files t
helm-mode-fuzzy-match t ; global fuzzy match
helm-buffers-fuzzy-matching t
helm-recentf-fuzzy-match t
helm-M-x-fuzzy-match t
helm-follow-mode-persistent t ; follow candidate in buffer (with C-up/C-down)
helm-imenu-fuzzy-match t
helm-completion-in-region-fuzzy-match t
helm-apropos-fuzzy-match t
helm-autoresize-mode 1 ; re-size the completion window based on number of candidates
helm-adaptive-mode t ; show commonly used commands first
helm-move-to-line-cycle-in-source nil ; if non-nil, cycle only within a source
)
(setq bibtex-completion-bibliography user-bibliography-file
bibtex-completion-library-path user-bibliography-pdf-dir ; directory of PDFs
bibtex-completion-notes-path user-bibliography-notes-dir ; directory of notes
)
;; helm-mini
(setq helm-mini-default-sources
'(helm-source-buffers-list
helm-source-bookmarks
helm-source-recentf
helm-source-buffer-not-found))
(helm-mode)
;; ;; http://emacs.stackexchange.com/a/7896/12336
;; ;; <return> opens directory in helm-find-files, not dired
;; (defun fu/helm-find-files-navigate-forward (orig-fun &rest args)
;; (if (file-directory-p (helm-get-selection))
;; (apply orig-fun args)
;; (helm-maybe-exit-minibuffer)))
;; (advice-add 'helm-execute-persistent-action :around #'fu/helm-find-files-navigate-forward)
;; (define-key helm-find-files-map (kbd "<return>") 'helm-execute-persistent-action)
;; http://emacs.stackexchange.com/a/7896/12336
;; <backspace> before backslash lets helm-find-files move one directory up
(defun fu/helm-find-files-navigate-back (orig-fun &rest args)
(if (= (length helm-pattern) (length (helm-find-files-initial-input)))
(helm-find-files-up-one-level 1)
(apply orig-fun args)))
(advice-add 'helm-ff-delete-char-backward :around #'fu/helm-find-files-navigate-back)
;; ;; https://redd.it/3f55nm
;; ;; Remove . and .. from helm-find-files
;; (advice-add 'helm-ff-filter-candidate-one-by-one
;; :around (lambda (fcn file)
;; (unless (string-match "\\(?:/\\|\\`\\)\\.\\{1,2\\}\\'" file)
;; (funcall fcn file))))
)
:bind (("M-y" . helm-mini)
("C-x C-r" . helm-recentf)
("C-h a" . helm-apropos)
("C-x C-b" . helm-buffers-list)
("C-x b" . helm-buffers-list)
("C-x C-f" . helm-find-files)
("C-x C-y" . helm-show-kill-ring)
("C-x y" . helm-show-kill-ring)
("C-x t" . helm-etags-select)
("C-x C-t" . helm-etags-select)
("C-x SPC" . helm-all-mark-rings)
("C-x C-SPC" . helm-all-mark-rings)
("M-x" . helm-M-x)
("C-s" . helm-occur)
;; ("C-x c s" . helm-swoop)
("C-x c y" . helm-yas-complete)
("C-x c Y" . helm-yas-create-snippet-on-region)
("C-x c SPC" . helm-all-mark-rings)
("C-ß" . helm-imenu)
("C-S-?" . helm-imenu-anywhere)
)
)
(ido-mode -1) ; turn off ido mode, just in case
https://github.com/emacs-helm/helm-descbinds
List active key bindings.
(use-package helm-descbinds
:ensure t
:bind ("C-h b" . helm-descbinds))
https://github.com/emacs-helm/helm-org
Complete tags with helm
when using org-set-tags
:
(use-package helm-org
:ensure t
:pin MELPA
:config
(add-to-list 'helm-completing-read-handlers-alist '(org-capture . helm-org-completing-read-tags))
(add-to-list 'helm-completing-read-handlers-alist '(org-set-tags . helm-org-completing-read-tags))
)
https://github.com/emacsorphanage/helm-swoop
Search buffer while showing matches in a separate buffer.
(use-package helm-swoop
:ensure t
:pin MELPA
:config
;; Move up and down like isearch
(define-key helm-swoop-map (kbd "C-r") 'helm-previous-line)
(define-key helm-swoop-map (kbd "C-s") 'helm-next-line)
(define-key helm-multi-swoop-map (kbd "C-r") 'helm-previous-line)
(define-key helm-multi-swoop-map (kbd "C-s") 'helm-next-line)
;; From helm-swoop to helm-multi-swoop-all
(define-key helm-swoop-map (kbd "M-i") 'helm-multi-swoop-all-from-helm-swoop)
;; Instead of helm-multi-swoop-all, you can also use helm-multi-swoop-current-mode
(define-key helm-swoop-map (kbd "M-m") 'helm-multi-swoop-current-mode-from-helm-swoop)
;; If nil, you can slightly boost invoke speed in exchange for text color
(setq helm-swoop-speed-or-color t)
;; Optional face for line numbers
;; Face name is `helm-swoop-line-number-face`
(setq helm-swoop-use-line-number-face t)
;; If you prefer fuzzy matching (seems to be already activated)
;; (setq helm-swoop-use-fuzzy-match t)
;; Do not call helm-swoop with symbol or word at point
(setq helm-swoop-pre-input-function
(lambda () nil))
:bind ("C-c /" . helm-swoop))
https://github.com/abo-abo/swiper-helm
Swiper with Helm backend.
Issues:
- [ ] Error: “swiper-helm: Cannot open load file: No such file or directory, helm-match-plugin”
(use-package swiper-helm
:ensure t
:bind ("C-s" . swiper-helm))
https://github.com/dash-docs-el/helm-dash
Browse Dash docsets with helm.
helm-dash
depends on sqlite3
which you probably have to install manually:
http://sqlite.org/download.html
(use-package helm-dash
:ensure t
:init
(setq helm-dash-common-docsets ; active in all buffers
'())
(setq helm-dash-browser-func 'eww) ; use internal web browser
(setq helm-dash-docsets-path docsets-dir) ; FIXME: under windows, helm-dash does not install docsets here but in ~/AppData/... Because of missing tar command?
(add-hook 'latex-mode-hook (lambda () (interactive)(setq-local helm-dash-docsets '("LaTeX"))))
(add-hook 'TeX-mode-hook (lambda () (interactive)(setq-local helm-dash-docsets '("LaTeX"))))
(add-hook 'emacs-lisp-mode-hook (lambda () (interactive)(setq-local helm-dash-docsets '("Emacs Lisp"))))
;; (add-hook 'js2-mode-hook (lambda () (interactive)(setq-local helm-dash-docsets '("JavaScript"))))
(add-hook 'org-mode-hook (lambda () (interactive)(setq-local helm-dash-docsets '("Org_Mode"))))
(add-hook 'plantuml-mode-hook (lambda () (interactive)(setq-local helm-dash-docsets '("PlantUML"))))
(add-hook 'sh-mode-hook (lambda () (interactive)(setq-local helm-dash-docsets '("Bash"))))
;; (add-hook 'perl-mode-hook (lambda () (interactive)(setq-local helm-dash-docsets '("Perl"))))
(add-hook 'python-mode-hook (lambda () (interactive)(setq-local helm-dash-docsets '("Python 3" "SciPy" "NumPy"))))
:bind
(("C-h d" . helm-dash))
)
https://github.com/emacs-helm/helm-mu
Helm frontend for Mu and mu4e.
Issues:
- [X] Does not find emails when using a non-standard mu folder.
(use-package helm-mu
:ensure t
:after helm mu4e
:config
(setq helm-mu-append-implicit-wildcard t
helm-mu-default-search-string "(maildir:/INBOX OR maildir:/Sent)"
helm-mu-contacts-personal t ; Only show contacts who sent you emails directly
helm-mu-command-arguments (concat "--muhome=" mu4e-mu-home) ; Search in `mu4e-mu-home' when calling `mu'
;; helm-mu-gnu-sed-program "gsed"
)
(define-key mu4e-main-mode-map "f" 'helm-mu)
(define-key mu4e-headers-mode-map "f" 'helm-mu))
https://github.com/alphapapa/org-rifle
Quick, comprehensive search on org-mode files.
(use-package helm-org-rifle
:ensure t
:pin MELPA
:config
(define-key helm-org-rifle-map (kbd "<left>") 'backward-char) ; instead of helm-previous-source
(define-key helm-org-rifle-map (kbd "<right>") 'forward-char) ; instead of helm-next-source
(define-key helm-org-rifle-map (kbd "C-n") 'helm-next-source)
(define-key helm-org-rifle-map (kbd "C-p") 'helm-previous-source)
(setq helm-org-rifle-show-path t)
)
https://github.com/emacsorphanage/helm-ag
Helm interface to The Silver Searcher.
(use-package helm-ag
:ensure t
;; :config
;; (setq helm-ag-base-command "rg --vimgrep --no-heading --smart-case") ; use ripgrep instead of ag
)
https://github.com/clojure-emacs/helm-cider
Helm interface to CIDER.
(use-package helm-cider
:ensure t
:hook ((cider-mode . helm-cider-mode)
(clojure-mode . helm-cider-mode)))
https://github.com/emacs-helm/helm-recoll
Helm interface to recoll.
(use-package helm-recoll
:ensure t
:commands helm-recoll
:init (setq helm-recoll-directories
'(("all" . "~/.recoll"))))
;; M-x in minibuffer quits the minibuffer
(add-hook 'minibuffer-setup-hook
(lambda ()
(local-set-key (kbd "M-x") 'abort-recursive-edit)))
;; M-y in minibuffer quits the minibuffer
(add-hook 'minibuffer-setup-hook
(lambda ()
(local-set-key (kbd "M-y") 'abort-recursive-edit)))
;; C-ß in minibuffer quits the minibuffer
(add-hook 'minibuffer-setup-hook
(lambda ()
(local-set-key (kbd "C-ß") 'abort-recursive-edit)))
;; C-s in minibuffer quits the minibuffer
(add-hook 'minibuffer-setup-hook
(lambda ()
(local-set-key (kbd "C-s") 'abort-recursive-edit)))
;; (global-set-key (kbd "C-x C-b") 'switch-to-buffer) ; instead of 'list-buffers (see helm)
;; (global-set-key (kbd "C-x b") 'ibuffer)
(global-set-key (kbd "C-x C-k") 'kill-buffer)
https://github.com/justbur/emacs-which-key
Show possible completions of entered key sequences.
(use-package which-key
:ensure t
:config
(which-key-mode))
Major mode for writing notes and much much more.
Must appear before LaTeX stuff!
Documentation and examples:
Historical remark on taking notes:
- Blumenbach system: https://web.archive.org/web/20191208033603/http://takingnotenow.blogspot.com/2008/07/note-keeping-in-1786-blumenbachs-system.html
Other good examples:
~/org/attachements/
~/org/calendar/
~/org/captures.org
~/org/contacts.org
~/org/elfeed.org
~/org/home/home.org
~/org/journal.org
~/org/work/work.org
~/org/zettel/
Heading type | Properties | Body | Purpose | End of life | Title format |
---|---|---|---|---|---|
area | non-intersecting with other areas | topics, projects, … | group topics, keep overview | ||
topic | :topic: | topics, projects, … | group content, keeping overview | ||
project | SCHEDULED, DEADLINE, outcome, :project:, DIR | todos, notes, events that lead to some common outcome | track progress | :ARCHIVE: | $outcome: $topic |
todo | SCHEDULED, DEADLINE | text, todo, event | track progress, take action | :ARCHIVE: | |
event | timestamp, location, participants, :event: | minutes/notes | store observations, ideas, action items | :ARCHIVE: | $topic/$participants $timestamp |
note | CREATED, LAST_CHANGED, :media:, … | text | store ideas, concepts, references, … |
Areas (e.g. administration, research, teaching) are usually implemented as separate org-mode
files with the following general structure:
- Clocking (for general clocking)
- Inbox
- Events
- Projects
- Notes
- Topics
- Events
- Projects
- Notes
- Archive
- Topics
Information flow:
- Inbox
Events|Projects Topics - Karl Voit’s setup
The area file for teaching is organized similar to the format shown above:
- Clocking (for general clocking)
- Inbox
- Courses & course ideas
- Courses are treated as projects – see below
- Notes about teaching methods and goals
- Typsetting
- How to give talks
- etc.
- Supervised theses
- Administration
- Accreditation
- etc.
- Archive
Courses have the following specific headings:
Heading type | Properties | Title format | Body |
---|---|---|---|
course | semester, :project:, DIR | (Semester) Title of course | list of sessions |
session | timestamp, :event: | Nth session Shorttitle of course <timestamp> | list of teaching units |
teaching unit | presenter, literature, material, attachments | Title of teaching unit | notes |
Here is an example of how they might be structured:
* (Semester) Course name with abbreviation XYZ
:PROPERTIES:
:DIR: ~/path/to/course/folder
:END:
** Sessions
*** 1. session XYZ <active timestamp>
**** Topic of teaching unit
** Term papers / projects
** Homework / exercises
** Course description
** Topics & notes
Every course is linked with a directory (via DIR property) including the following subdirectories depending on the type of event:
- slides (by me)
- presentations (by students)
- term papers (by students)
- literature
- exercises (instructions & submissions)
Notes regarding texts, videos etc. are handled in the following way:
- one heading per piece
- tags: media > text, video, audio, live
- properties: ID
- body: URL or org-ref citation link
- When available, an electronic copy (usually as PDF) is stored as regular attachment based on the heading’s ID. As far as PDFs are concerned, notes can be left there with pdf-tools.
- eternal
I use org-roam to look through my notes on literature.
- Projects have a defined start and end, similar to events, but in contrast to notes and topics.
- Projects have a defined goal, which is achieved via todo items (either a list of checkboxes or headings), in contrast to events (which usually serve a goal but don’t reach the goal unfortunately).
How to deal with and define projects within org-mode
:
Set indentation of list items:
(setq-default org-list-indent-offset 4)
Show bullet instead of - or *.
(font-lock-add-keywords
'org-mode
'(("^[[:space:]]*\\(-\\) "
(0 (prog1 () (compose-region (match-beginning 1) (match-end 1) "•"))))))
;; ;; The following tries to estimate the embedding level via the number of preceding spaces.
;;
;; (font-lock-add-keywords
;; 'org-mode
;; '(("^\\(-\\) "
;; (0 (prog1 () (compose-region (match-beginning 1) (match-end 1) "•"))))))
;;
;; (font-lock-add-keywords
;; 'org-mode
;; `((,(concat "^[[:space:]]\\{" (number-to-string (+ 2 org-list-indent-offset)) "\\}\\(-\\) ")
;; (0 (prog1 () (compose-region (match-beginning 1) (match-end 1) "◦"))))))
;;
;; (font-lock-add-keywords
;; 'org-mode
;; `((,(concat "^[[:space:]]\\{" (number-to-string
;; (* 2 (+ 2 org-list-indent-offset))) "\\}\\(-\\) ")
;; (0 (prog1 () (compose-region (match-beginning 1) (match-end 1) "▸"))))))
;;
;; (font-lock-add-keywords
;; 'org-mode
;; `((,(concat "^[[:space:]]\\{" (number-to-string
;; (* 3 (+ 2 org-list-indent-offset))) "\\}\\(-\\) ")
;; (0 (prog1 () (compose-region (match-beginning 1) (match-end 1) "▹"))))))
;; ;; Trying to make bullet face aware of embedding depth:
;;
;; (font-lock-add-keywords
;; 'org-mode
;; '(("^[[:space:]]*\\(-\\) "
;; (0 (prog1 () (let ((bullet "-")
;; (depth (org-list--depth (org-element-at-point))))
;; (cond ((= depth 2) (setq bullet "•"))
;; ((= depth 3) (setq bullet "▸"))
;; ((= depth 4) (setq bullet "-"))
;; ((= depth 5) (setq bullet "▪"))
;; )
;; (compose-region (match-beginning 1) (match-end 1) bullet)))))))
Allow for alphabetical list item labels:
(setq org-list-allow-alphabetical t)
Text can be colored using the link syntax, e.g. this is red. Taken from https://github.com/jkitchin/jmax/blob/master/org-colored-text.el See also http://kitchingroup.cheme.cmu.edu/blog/2016/01/16/Colored-text-in-org-mode-with-export-to-HTML/ Depends on ov.
(use-package org-colored-text
:after ov)
Add support for export to LaTeX:
;; Taken and adapted from org-colored-text
(org-add-link-type
"color"
(lambda (path)
"No follow action.")
(lambda (color description backend)
(cond
((eq backend 'latex) ; added by TL
(format "{\\color{%s}%s}" color description)) ; added by TL
((eq backend 'html)
(let ((rgb (assoc color color-name-rgb-alist))
r g b)
(if rgb
(progn
(setq r (* 255 (/ (nth 1 rgb) 65535.0))
g (* 255 (/ (nth 2 rgb) 65535.0))
b (* 255 (/ (nth 3 rgb) 65535.0)))
(format "<span style=\"color: rgb(%s,%s,%s)\">%s</span>"
(truncate r) (truncate g) (truncate b)
(or description color)))
(format "No Color RGB for %s" color)))))))
Link type for typesetting linguistic examples:
(org-link-set-parameters
"bsp"
:follow (lambda (path) (message "You clicked me."))
:export (lambda (path desc backend)
(cond
((eq backend 'latex)
(format "\\bsp{%s}" (or desc path)))
((eq 'html backend)
(format "<font color=\"blue\">%s</font>"
(or desc path)))))
:face '(:foreground "CornflowerBlue" :slant italic :weight bold )
:help-echo "This will be exported as example.")
(org-link-set-parameters
"bspcolor"
:follow (lambda (path) (message "You clicked me."))
:export (lambda (path desc backend)
(cond
((eq backend 'latex)
(format "\\bspcolor{%s}" (or desc path)))
((eq 'html backend)
(format "<font color=\"blue\">%s</font>"
(or desc path)))))
:face '(:foreground "CornflowerBlue")
:help-echo "This will be exported in the color of examples.")
Link type for typesetting terminology:
(org-link-set-parameters
"term"
:follow (lambda (path) (message "You clicked me."))
:export (lambda (path desc backend)
(cond
((eq backend 'latex)
(format "\\term{%s}" (or desc path)))
((eq 'html backend)
(format "<span style=\"font-variant:small-caps;\">%s</span>"
(or desc path)))))
:face '(:box t :slant normal)
:help-echo "This will be exported as term."
)
Link type for typesetting emphasized text:
(org-link-set-parameters
"emph"
:follow (lambda (path) (message "You clicked me."))
:export (lambda (path desc backend)
(cond
((eq backend 'latex)
(format "\\emph{%s}" (or desc path)))
((eq 'html backend)
(format "<em>%s</em>"
(or desc path)))))
:face '(:overline t :underline t :slant italic)
:help-echo "This will be exported as emphasized text."
)
Link type for typesetting small caps:
(org-link-set-parameters
"textsc"
:follow (lambda (path) (message "You clicked me."))
:export (lambda (path desc backend)
(cond
((eq backend 'latex)
(if (not (string= path ""))
(format "{\\color{%s}\\textsc{%s}}" path desc)
(format "\\textsc{%s}" desc)))
((eq 'html backend)
(format "<span style=\"font-variant:small-caps;\">%s</span>"
(or desc path)))))
:face (lambda (path)
`(:box t :slant normal
:foreground ,(if (not (string= "" path)) "CornflowerBlue")))
:help-echo "This will be exported in small caps.")
Link type for typesetting with typewriter font:
(org-link-set-parameters
"texttt"
:follow (lambda (path) (message "You clicked me."))
:export (lambda (path desc backend)
(cond
((eq backend 'latex)
(if (not (string= path ""))
(format "{\\color{%s}\\texttt{%s}}" path desc)
(format "\\texttt{%s}" desc)))
((eq 'html backend)
(format "<span style=\"font-family:monospace;\">%s</span>"
(or desc path)))))
:face (lambda (path)
`(:box t :slant normal :family ,custom-fixed-pitch-font
:foreground ,(if (not (string= "" path)) "CornflowerBlue")))
:help-echo "This will be exported with typewriter font.")
Link type for typesetting with alert font:
(org-link-set-parameters
"alert"
:follow (lambda (path) (message "You clicked me."))
:export (lambda (path desc backend)
(cond
((eq backend 'latex)
(if (not (string= path ""))
(format "\\alert<%s>{%s}" path desc)
(format "\\alert<.>{%s}" desc)))
((eq 'html backend)
(format "<span style=\"color: red;\">%s</span>"
(or desc path)))))
:face (lambda (path)
'(:box t :slant normal
:foreground "red"))
:help-echo "This will be exported as alerted text.")
(add-hook 'org-mode-hook (lambda ()
(variable-pitch-mode t)
;; (text-scale-increase 0.5)
))
(with-eval-after-load 'org
(set-face-attribute 'org-table nil :inherit 'fixed-pitch)
(set-face-attribute 'org-verbatim nil :inherit 'fixed-pitch)
;; Use the same color for LaTeX code as is used for math code in LaTeX mode.
(set-face-attribute 'org-latex-and-related nil :foreground "#AE81FF" :inherit 'fixed-pitch)
;; ;; The following reuses the color of font-latex-math-face directly.
;; ;; Unfortunately, font-latex-math-face may not yet be available when setting the face.
;; (with-eval-after-load 'auctex
;; (set-face-attribute 'org-latex-and-related nil :foreground (face-attribute 'font-latex-math-face :foreground) :inherit 'fixed-pitch))
(set-face-attribute 'org-link nil :inherit 'fixed-pitch)
(set-face-attribute 'org-date nil :inherit 'fixed-pitch)
(set-face-attribute 'org-tag nil :inherit 'fixed-pitch)
)
(custom-set-faces
'(org-block ((t (:inherit fixed-pitch )))) ; org-mode >9
'(org-block-background ((t (:inherit fixed-pitch))))
'(org-block-begin-line ((t (:underline t))))
'(org-block-end-line ((t (:overline t))))
)
(custom-set-faces
'(org-level-1 ((t (:inherit outline-1 :overline t :weight semi-bold ))))
'(org-level-2 ((t (:inherit outline-2 :overline t :weight semi-bold ))))
'(org-level-3 ((t (:inherit outline-3 :weight semi-bold ))))
'(org-level-4 ((t (:inherit outline-4 :weight semi-bold ))))
'(org-level-5 ((t (:inherit outline-5 :weight semi-bold ))))
)
https://orgmode.org/manual/Emphasis-and-Monospace.html
Hide markers:
(setq org-hide-emphasis-markers t)
See also org-appear for automatically toggling visibility.
Modify some faces:
(face-spec-set 'org-todo '((t (:overline t))))
(face-spec-set 'org-done '((t (:overline t))))
Do not change the face of a headline if it is marked DONE.
(setq org-fontify-done-headline nil)
Nicer bullets:
;; (use-package org-bullets
;; :ensure t
;; :init
;; (setq org-bullets-bullet-list
;; '("◉" "◎" "○" "●" "►" "♦" "◇"))
;; (setq inhibit-compacting-font-caches t) ; effects an acceleration under Windows
;; :config
;; (add-hook 'org-mode-hook (lambda () (org-bullets-mode 1)))
;; )
Folding symbol:
(setq org-ellipsis " ▼")
Replace HTML/LaTeX code by UTF-8 characters (see org-pretty-entities for an enumeration):
(setq org-pretty-entities t)
Do not edit in invisible areas of the buffer:
(setq-default org-catch-invisible-edits 'show-and-error)
Org offers a way to include code inline with src_<language>[<header arguments>]{<body>}
, for example src_latex[:tangle no]{\section{Title}}.
See https://orgmode.org/manual/Structure-of-Code-Blocks.html.
For better visibility (and more probably due to my ignorance), I once defined my own poor-man’s version of it, namely @@latex:\section{Title}@@.
(font-lock-add-keywords
'org-mode
'(("\\(@@latex:\\)\\(.*?\\)\\(@@\\)"
(1 font-lock-comment-face)
(2 '(org-latex-and-related))
(3 font-lock-comment-face))
))
(font-lock-add-keywords
'org-mode
'(("\\(@@beamer:\\)\\(.*?\\)\\(@@\\)"
(1 font-lock-comment-face)
(2 '(org-latex-and-related))
(3 font-lock-comment-face))
))
(font-lock-add-keywords
'org-mode
'(("\\(@@html:\\)\\(.*?\\)\\(@@\\)"
(1 font-lock-comment-face)
(2 '(org-latex-and-related)) ; FIXME?
(3 font-lock-comment-face))
))
;; Does not work
(font-lock-add-keywords
'org-mode
'(("\\(#\\+BEAMER_HEADER:\\)\\(.*\\)$"
(1 font-lock-comment-face)
(2 '(org-latex-and-related)))
))
Fontify checkbox items. (inspired by https://fuco1.github.io/2017-05-25-Fontify-done-checkbox-items-in-org-mode.html)
(defface org-checkbox-todo-text
'((t (;;:inherit org-todo
:overline nil
:foreground "red"
:weight bold)))
"Face for the text part of an unchecked org-mode checkbox.")
(font-lock-add-keywords
'org-mode
`(("^[ \t]*\\(?:[-+*]\\|[0-9]+[).]\\)[ \t]+\\(\\(?:\\[@\\(?:start:\\)?[0-9]+\\][ \t]+\\)?\\[\\(?: \\|-\\|\\([0-9]+\\)/\\2\\)\\][ \t]+[^\n]*\\)" 1 'org-checkbox-todo-text prepend))
'append)
(defface org-checkbox-done-text
'((t (;;:inherit org-done
:overline nil
:foreground "forest green"
:weight unspecified)))
"Face for the text part of a checked org-mode checkbox.")
(font-lock-add-keywords
'org-mode
`(("^[ \t]*\\(?:[-+*]\\|[0-9]+[).]\\)[ \t]+\\(\\(?:\\[@\\(?:start:\\)?[0-9]+\\][ \t]+\\)?\\[\\(?:X\\|\\([0-9]+\\)/\\2\\)\\][ \t]+[^\n]*\\)" 1 'org-checkbox-done-text prepend))
'append)
https://github.com/alphapapa/org-sticky-header
Show current header in first line of buffer.
(use-package org-sticky-header
:ensure t
:config
(setq org-sticky-header-always-show-header t
org-sticky-header-prefix nil ; don't indent sticky header
org-sticky-header-full-path 'full) ; values: nil, 'full, 'reversed
(add-hook 'org-mode-hook 'org-sticky-header-mode))
Function to only unfold current heading and its content:
;; Taken from https://stackoverflow.com/a/28031539/6452961
;; and slightly modified.
(defun org-show-current-heading-tidily ()
"Show entry under point, keeping other entries closed."
(interactive)
(save-excursion
(if (save-excursion (end-of-line) (outline-invisible-p))
(progn (org-show-entry) (show-children))
(outline-back-to-heading)
(unless (and (bolp) (org-on-heading-p))
(org-up-heading-safe)
(hide-subtree)
(error "Boundary reached"))
(org-overview)
(org-reveal t)
(org-show-entry)
(show-children))))
(global-set-key (kbd "C-c a") 'org-agenda)
(global-set-key (kbd "C-c l") 'org-store-link)
(with-eval-after-load 'org
(define-key org-mode-map (kbd "C-<tab>") nil )
(define-key org-mode-map (kbd "S-<up>") nil )
(define-key org-mode-map (kbd "S-<down>") nil )
(define-key org-mode-map (kbd "S-<left>") nil )
(define-key org-mode-map (kbd "S-<right>") nil )
(define-key org-mode-map (kbd "C-n") 'org-next-visible-heading )
(define-key org-mode-map (kbd "C-p") 'org-previous-visible-heading )
(define-key org-mode-map (kbd "C-S-p") 'org-backward-heading-same-level)
(define-key org-mode-map (kbd "C-S-n") #'(lambda () (interactive) (org-backward-heading-same-level -1)))
(define-key org-mode-map (kbd "C-c C-f") 'org-footnote-action )
(define-key org-mode-map (kbd "C-c C-t") 'org-todo )
(define-key org-mode-map (kbd "C-c C-x C-b") 'org-tree-to-indirect-buffer )
(define-key org-mode-map (kbd "C-c C-t") 'org-todo )
(define-key org-mode-map (kbd "C-c C-<return>") 'org-ctrl-c-ret )
;; With Org-mode v9.2, the explicit mapping of C-a and C-e becomes necessary.
;; See http://lists.gnu.org/archive/html/emacs-orgmode/2019-01/msg00253.html
(define-key org-mode-map (kbd "C-a") 'org-beginning-of-line )
(define-key org-mode-map (kbd "C-e") 'org-end-of-line )
)
;; (with-eval-after-load 'org-agenda
;; (bind-key "i" 'org-agenda-clock-in org-agenda-mode-map))
Selection
(setq org-support-shift-select t)
Fold headings at startup
(setq org-startup-folded 'show2levels)
Hide blocks at startup
(setq org-hide-block-startup t)
Indent automatically
(add-hook 'org-mode-hook 'org-indent-mode)
Support for inline tasks
(define-key org-mode-map (kbd "C-c C-x C-t") 'org-inlinetask-insert-task)
C-a and C-e behave org-sensitive
(setq org-special-ctrl-a/e t)
Footnotes
(setq org-footnote-define-inline t
org-footnote-auto-adjust t)
Jump
(setq org-goto-interface 'outline-path-completion
org-goto-max-level 10)
IDs
(setq org-id-ts-format (concat "%y%m%dT%H%M%S.%N-" user-acronym)
org-id-method 'ts)
https://orgmode.org/manual/Agenda-Views.html
Show all headers with clocks, timestamps and todos in one overview buffer.
(require 'org-agenda)
- State “TODO” from [2024-07-25 Thu 11:28]
Don’t split window when opening agenda:
(setq org-agenda-window-setup "current-window")
Show notifications of agenda events (NOT USED):
(use-package org-alert
:ensure t)
Sort agenda TODOs with org-agenda-sorting-strategy
.
Skip scheduled items and items with deadline when they are DONE:
(setq org-agenda-skip-scheduled-if-done t
org-agenda-skip-deadline-if-done t)
Change the face of deadline items in agenda:
(setq org-agenda-deadline-faces
'((1.0 . org-imminent-deadline)
(0.5 . org-upcoming-deadline)
(0.0 . org-upcoming-deadline)
;; (0.0 . org-upcoming-distant-deadline) ; default
))
Do not make the block agenda more compact:
(setq org-agenda-compact-blocks nil)
Change the separator between blocks in agenda:
(setq org-agenda-block-separator ?\-)
Set the start day of the weekly agenda:
(setq org-agenda-start-on-weekday 1) ; nil --> today, 0 --> Sunday, 1 --> Monday
Agenda remains open in background. No need to recompile it every time you call it:
(setq org-agenda-sticky t)
Do not show tags in agenda, because it takes too much space:
(setq org-agenda-remove-tags t)
Truncate lines:
(add-hook 'org-agenda-finalize-hook
#'(lambda () (toggle-truncate-lines t)))
Show tags at the right edge of the screen (DEPRECATED):
;; (setq org-agenda-tags-column (- (- (window-total-width) 3)))
;; taken from https://lists.gnu.org/archive/html/emacs-orgmode/2010-12/msg00410.html
(add-hook 'org-finalize-agenda-hook #'place-agenda-tags)
(defun place-agenda-tags ()
"Put the agenda tags by the right border of the agenda window."
(setq org-agenda-tags-column (- 4 (window-width)))
(org-agenda-align-tags))
Add the Emacs diary (which also stores holidays) to org-agenda
:
(setq org-agenda-include-diary t)
Recenter buffer when coming from the agenda:
(add-hook 'org-agenda-after-show-hook 'recenter-top-bottom)
Enable log mode in order to display done and clocked items:
(setq org-agenda-start-with-log-mode t)
(setq org-agenda-log-mode-items '(closed clock))
Change font faces:
- [ ]
org-agenda-date
andorg-agenda-date-weekend
should depend onorg-agenda-date-today
. Hard coding of colors should be avoided.
(defun tl/org-agenda-style ()
(set-face-attribute 'org-agenda-clocking nil :inherit 'unspecified)
;; Make scheduled items more visible
;; Note that using `eval-after-load' with org instead does not work.
(set-face-attribute 'org-scheduled-today nil :foreground
(face-attribute 'org-scheduled :foreground))
(set-face-attribute 'org-scheduled-previously nil :foreground
(face-attribute 'org-scheduled :foreground))
;;;; Does not work, because `org-agenda-date-today' does not seem to be available when org-agenda-mode-hook is executed:
;; (set-face-attribute 'org-agenda-date nil :foreground
;; (face-attribute 'org-agenda-date-today :foreground))
;; (set-face-attribute 'org-agenda-date-weekend nil :foreground
;; (face-attribute 'org-agenda-date-today :foreground))
;; (set-face-attribute 'org-agenda-clocking nil :inherit unspecified)
(set-face-attribute 'org-agenda-date nil :foreground "#66d9ef")
(set-face-attribute 'org-agenda-date-weekend nil :foreground "#66d9ef")
)
(add-hook 'org-agenda-mode-hook #'tl/org-agenda-style)
Do not dim blocked headings (headings with TODO subheadings):
(setq org-agenda-dim-blocked-tasks nil)
Specifying the timespan of org-agenda views:
(defvar tl/org-agenda-timespan
'((org-agenda-start-on-weekday nil)
(org-agenda-span 7)
(org-agenda-start-day "-3d")))
Specifying the sections of org-agenda views:
(defvar tl/org-agenda-structure
`((agenda "" ,tl/org-agenda-timespan)
(tags "PRIORITY=\"A\""
((org-agenda-skip-function '(org-agenda-skip-entry-if 'todo 'done))
(org-agenda-overriding-header "HIGH-PRIORITY TASKS")))
;; (todo "INPROGRESS"
;; ((org-agenda-overriding-header "ONGOING PROJECTS")))
(tags "project+TODO=\"INPROGRESS\""
((org-agenda-overriding-header "ONGOING PROJECTS")))
(tags "project+TODO=\"WAITING\""
((org-agenda-overriding-header "")
(org-agenda-block-separator nil)))
(todo "NEXT" ((org-agenda-overriding-header "NORMAL-PRIORITY TASKS")))
(todo "TODO" ((org-agenda-overriding-header "")
(org-agenda-block-separator nil)))
(todo "WAITING" ((org-agenda-overriding-header "")
(org-agenda-block-separator nil)))
(todo "HOLD" ((org-agenda-overriding-header "")
(org-agenda-block-separator nil)))
(todo "SOMEDAY" ((org-agenda-overriding-header "")
(org-agenda-block-separator nil)))
))
Customize the content of views:
(setq org-agenda-custom-commands
`(("E" "Events with timestamp"
((tags "event"
((org-agenda-overriding-header "Events without date")
(org-agenda-prefix-format '((tags . " %i %-12:c %?-12t")))
(org-agenda-skip-function
;; Skip if non-nil and proceed search at returned position.
;; This mimics org-agenda-skip-entry-if for headings with a simple timestamp
'(lambda ()
(org-back-to-heading t)
(let* (;; (beg (point))
(end (save-excursion (org-end-of-subtree t)(point))
;; Alternative: (org-entry-end-position)
))
(and (org-entry-get nil "TIMESTAMP")
end))))
;; The following does it the usual way, but this would exclude also
;; headings which are scheduled or with a deadline.
;; '(org-agenda-skip-entry-if 'timestamp)
))
(tags "event+TIMESTAMP>=\"<now>\""
((org-agenda-overriding-header "Future events")
(org-agenda-sorting-strategy '((tags ts-down)))
(org-agenda-prefix-format '((tags . " %i %-12:c %?-12t")))
))
(tags "event+TIMESTAMP<=\"<now>\""
((org-agenda-overriding-header "Past events")
(org-agenda-sorting-strategy '((tags ts-down)))
(org-agenda-prefix-format '((tags . " %i %-12:c %?-12t")))
))))
("C" "Clocked Headings"
((tags "*"
((org-agenda-overriding-header "Clocked Headings")
(org-agenda-prefix-format '((tags . " %i %-12:c %?-12t")))
(org-agenda-skip-function
;; Skip if non-nil and proceed search at returned position.
;; This mimics org-agenda-skip-entry-if for headings with a clock
'(lambda ()
(org-back-to-heading t)
(let* ((end (or (save-excursion (outline-next-heading) (point))
(save-excursion (org-end-of-subtree t) (point)))
;; Alternative: (org-entry-end-position)
))
(and (not (re-search-forward org-clock-line-re end t))
end))))
(org-agenda-sorting-strategy '((tags user-defined-down)))
))))
("W" "Work-related agenda and tasks"
,tl/org-agenda-structure
((org-agenda-tag-filter-preset '("+@work"))))
("H" "Home-related agenda and tasks"
,tl/org-agenda-structure
((org-agenda-tag-filter-preset '("+@home"))))
("A" "Complete list of agenda and tasks"
,tl/org-agenda-structure
;; ((org-agenda-tag-filter-preset '("+@home")))
)
))
Sorting function for clocked headings:
(defun tl/org-agenda-sort-clocks-function (a b)
"Custom sorting function for agenda items."
;; With (get-text-property 1 'org-marker a), one can access the underlying heading of the org-ageanda line.
(let* ((last-clock-a (org-with-point-at (get-text-property 1 'org-marker a)
(org-clock-get-last-clock-out-time)))
(last-clock-b (org-with-point-at (get-text-property 1 'org-marker b)
(org-clock-get-last-clock-out-time))))
(if (and last-clock-a last-clock-b)
(cond ((time-less-p last-clock-a last-clock-b) -1)
((time-less-p last-clock-b last-clock-a) 1)
(t nil))
nil
;; (if last-clock-a t (not last-clock-b))
)))
(setq org-agenda-cmp-user-defined 'tl/org-agenda-sort-clocks-function)
Function to check if a heading has CLOCK lines:
(defun tl/org-heading-with-clock-p ()
"If non-nil, heading und point has a CLOCK line."
(when (org-log-beginning)
(org-with-point-at (org-log-beginning)
(let ((log-end (save-excursion (re-search-forward org-clock-drawer-end-re))))
(re-search-forward org-clock-line-re log-end t)))))
Set up key bindings for each view:
(defun org-agenda-list-work ()
(interactive)
(org-agenda nil "W"))
(defun org-agenda-list-home ()
(interactive)
(org-agenda nil "H"))
(defun org-agenda-list-complete ()
(interactive)
(org-agenda nil "A"))
(defun org-agenda-list-events ()
(interactive)
(org-agenda nil "E"))
(defun org-agenda-list-clocks ()
(interactive)
(org-agenda nil "C"))
(define-key org-agenda-mode-map (kbd "W") 'org-agenda-list-work)
(define-key org-agenda-mode-map (kbd "H") 'org-agenda-list-home)
(define-key org-agenda-mode-map (kbd "A") 'org-agenda-list-complete)
(define-key org-agenda-mode-map (kbd "E") 'org-agenda-list-events)
(define-key org-agenda-mode-map (kbd "C") 'org-agenda-list-clocks)
Gantt charts illustrate project time schedules.
https://github.com/legalnonsense/elgantt
Creates a Gantt calendar from your org(-agenda) files.
Heavily inspired by https://emacs.stackexchange.com/questions/21380/show-sum-of-efforts-for-a-day-in-org-agenda-day-title
The following code works directly with the agenda buffer. For each day, the clocked times are collected and then added to the day headers.
(defun tl/org-agenda-collect-clocked-minutes (limit)
"Sum the clocked time of entries up to LIMIT in the agenda buffer."
(let ((total '(0)))
(save-excursion
(while (and limit
(< (point) limit))
;; Just read off the clocked times from the agenda table
(when (member (org-get-at-bol 'type) '("clock"))
(push
;; (org-get-at-bol 'duration) ; Strangely, some durations are negative (Bug?).
(org-hh:mm-string-to-minutes
(if (re-search-forward "Clocked:[[:blank:]]*(\\([0-9]+\\:[0-9]+\\))" (line-end-position) t)
(match-string 1)
""))
total)
)
(forward-line)))
(apply '+ total)))
(defun tl/org-agenda-insert-clocked-time-per-day ()
"Insert the clocked time for each day inside the agenda buffer."
(save-excursion
(let ((col (save-excursion
(text-property-search-forward 'type "clock")
(re-search-forward "Clocked:[[:blank:]]*?(" nil t)
(- (current-column) 2) ; --> -2, if re-search was unsuccessful
))
(pos)
(total '(0)))
;; For each day ...
(while
(and (text-property-search-forward 'org-agenda-date-header t)
(org-get-at-bol 'org-agenda-date-header)) ; double check
(end-of-line)
(or (< col (current-column))
(move-to-column col t))
(let ((day-clocked-minutes (tl/org-agenda-collect-clocked-minutes
(next-single-property-change (point) 'day))))
(insert-and-inherit (concat " ("
(org-duration-from-minutes day-clocked-minutes)
")"))
(push day-clocked-minutes total)))
;; Go back to week and insert total
(beginning-of-buffer)
(when (and (text-property-search-forward 'org-agenda-date-header t)
(> (forward-line -1) -1))
(or (< col (current-column))
(move-to-column col t))
(insert-and-inherit (concat " ("
(org-duration-from-minutes (apply '+ total))
")")))
)))
(add-hook 'org-agenda-finalize-hook 'tl/org-agenda-insert-clocked-time-per-day)
The function describe-text-properties
turned out very helpful to find out the specific (hidden) properties of lines of the org agenda.
While timestamps in headers are automatically removed when they trigger the appearance of the header in the agenda, this is not the case for clocked items. The following removes the timestamp also in clocked items.
(defun tl/org-agenda-view-remove-timestamps ()
"Remove timestamps from the agenda view."
(save-excursion
(when (org-agenda-check-type nil 'agenda)
(goto-char (point-min))
(while (re-search-forward (concat org-ts-regexp-both " ") nil t)
(replace-match "")))))
(add-hook 'org-agenda-finalize-hook 'tl/org-agenda-view-remove-timestamps)
org-conflict
helps to detect and resolve scheduling conflicts.
https://www.mail-archive.com/emacs-orgmode@gnu.org/msg123154.html
https://github.com/dfeich/org-clock-convenience
Convenience functions for clocking workflow.
(use-package org-clock-convenience
:ensure t
:bind (:map org-agenda-mode-map
("<M-S-up>" . org-clock-convenience-timestamp-up)
("<M-S-down>" . org-clock-convenience-timestamp-down)
("ö" . org-clock-convenience-fill-gap)
("é" . org-clock-convenience-fill-gap-both)))
Open heading with double-click:
(define-key org-agenda-mode-map [double-mouse-1] 'org-agenda-switch-to)
https://orgmode.org/manual/Archiving.html
Archiving helps to “to keep your working files compact and global searches like the construction of agenda views fast.”
There are two standard ways of archiving headings in Org:
- Moving a tree to an archive file
- Internal archiving using the
ARCHIVE
tag
Preserves the first heading of the org-mode file (found in https://orgmode.org/worg/org-hacks.html#org58038ec):
(defadvice org-archive-subtree (around my-org-archive-subtree activate)
(let ((org-archive-location
(if (save-excursion (org-back-to-heading)
(> (org-outline-level) 1))
(concat (car (split-string org-archive-location "::"))
"::* "
(car (org-get-outline-path)))
org-archive-location)))
ad-do-it))
Add the outline path to the heading text:
(defadvice org-archive-subtree (around prepend-path-to-heading activate)
"Prepend the outline path to the heading text before archiving."
(let* ((heading (org-get-heading 'no-tags 'no-todo))
(path (org-get-outline-path))
(full-path (concat (mapconcat 'identity path " ❯ ") " ❯ " heading)))
(org-edit-headline full-path)
ad-do-it))
Keep inherited tags of archived headings (found in https://orgmode.org/worg/org-hacks.html#org4449edf): Deactivated for now.
(defadvice org-archive-subtree
(before add-inherited-tags-before-org-archive-subtree activate)
"add inherited tags before org-archive-subtree"
(org-set-tags-to (org-get-tags-at)))
Preserves the first heading of the org-mode file and the inherited tags (found in https://orgmode.org/worg/org-hacks.html#org58038ec):
Deactivated because org-extract-archive-file
is not found.
(defun my-org-inherited-no-file-tags ()
(let ((tags (org-entry-get nil "ALLTAGS" 'selective))
(ltags (org-entry-get nil "TAGS")))
(mapc (lambda (tag)
(setq tags
(replace-regexp-in-string (concat tag ":") "" tags)))
(append org-file-tags (when ltags (split-string ltags ":" t))))
(if (string= ":" tags) nil tags)))
(defadvice org-archive-subtree (around my-org-archive-subtree-low-level activate)
(let ((tags (my-org-inherited-no-file-tags))
(org-archive-location
(if (save-excursion (org-back-to-heading)
(> (org-outline-level) 1))
(concat (car (split-string org-archive-location "::"))
"::* "
(car (org-get-outline-path)))
org-archive-location)))
ad-do-it
(with-current-buffer (find-file-noselect (org-extract-archive-file))
(save-excursion
(while (org-up-heading-safe))
(org-set-tags tags)))))
https://orgmode.org/org.html#Attachments
Org headings and files can be associated with directories which contain their “attachments”.
org-attach
might not be autoloaded by org-mode.
(require 'org-attach)
There are two ways to decide the attachment directory:
- the ID property, from which the relative path is derived
- the DIR property which explicitely contains the path
I prefer using general inheritance – child nodes inherit the attachment directory of their parent node – and relative paths in the DIR property.
(setq
org-attach-use-inheritance t ; enable inheritance
org-attach-dir-relative t ; enable relative paths in DIR property
org-attach-preferred-new-method 'dir ; prefered method for attachments (id, dir, ask, nil)
)
Note that ID and DIR are inherited asymmetrically, since DIR always takes precedence over ID.
- If a node has both ID and DIR properties, only the DIR property counts.
- If a node has an ID property, but its parent has a DIR property, then the DIR property of the parent counts.
Handling attachments of xournalpp
files:
(defun tl/org-add-or-open-xournal-attachment ()
"Start `xournalpp' in attachment directory and open notes file, if available.
If no attachment directory can be found, the user is asked to create one."
(interactive)
(if (derived-mode-p 'org-mode)
(progn (when (and (not (org-attach-dir))
(y-or-n-p "No attachment directory found. Create one? "))
(org-attach-dir t))
(if (org-attach-dir)
(start-process "" nil
"xournalpp" (expand-file-name "hand-notes.xopp" (org-attach-dir)))
(start-process "" nil "xournalpp")))
(message "Not in org-mode")))
Note that one can specify the name of attachment directories per file with
# -*- org-attach-id-dir: "my-fancy-dir-name" -*-
or with a property drawer at the very beginning of the file:
:PROPERTIES:
:DIR: my-fancy-dir-name
:END:
Function to jump from attachment directory in dired to heading (https://fuco1.github.io/2023-02-08-Visit-the-org-headline-from-the-attach-dired-buffer.html):
(defun my-org-attach-visit-headline-from-dired ()
"Go to the headline corresponding to this org-attach directory."
(interactive)
(let* ((id-parts (last (split-string default-directory "/" t) 2))
(id (apply #'concat id-parts)))
(let ((m (org-id-find id 'marker)))
(unless m (user-error "Cannot find entry with ID \"%s\"" id))
(pop-to-buffer (marker-buffer m))
(goto-char m)
(move-marker m nil)
(org-fold-show-context))))
Add some link types (deprecated since v9.3):
;; (add-to-list 'org-link-abbrev-alist '("attachment" . org-attach-expand-link)) ; included in `org-attach` since v9.3
;; (add-to-list 'org-link-abbrev-alist '("att" . org-attach-expand-link)) ; only for downward compatibility and not supported any longer since v9.4
Function to rename ATTACH_DIR
(deprecated since v9.3) to DIR
, and to remove ATTACH_DIR_INHERIT
(deprecated since v9.3):
(defun org-update-attach-properties ()
"Change properties for Org-Attach."
(interactive)
(org-with-point-at 1
(while (outline-next-heading)
(let ((DIR (org--property-local-values "ATTACH_DIR" nil)))
(when DIR
(org-set-property "DIR" (car DIR))
(org-delete-property "ATTACH_DIR"))))
(org-delete-property-globally "ATTACH_DIR_INHERIT")))
https://github.com/andras-simonyi/citeproc-org
Renders org-mode
citations and bibliographies during export in Citation Style Language (CSL) styles using the citeproc-el
library.
citeproc-org
is used by helm-bibtex.
(use-package citeproc-org
:ensure t
;; :config
;; (citeproc-org-setup)
)
- Template expansions: http://orgmode.org/manual/Template-expansion.html
(setq org-capture-templates
`(
;; uses appointment tag
("a" "Appointment"
entry (file+headline
(lambda () (expand-file-name "captures.org" org-directory))
"Appointments")
"* %^T %?\t:appointment:\n\n"
:prepend t
:jump-to-captured t
;; :before-finalize org-id-get-create ; Not always needed
)
;; ;; used for org-gcal
;; ("a" "Appointment" entry (file (concat org-directory "/gcal.org"))
;; "* %?\n\n%^T\n\n:PROPERTIES:\n\n:END:\n\n")
("t" "Todo" entry (file+headline
(lambda () (expand-file-name "captures.org" org-directory))
"Todos")
"* TODO %?\t%^G\n :LOGBOOK:\n - CREATED: %U\n :END:\n\n About region:%i\n %a" :prepend t)
("j" "Journal" entry (file+datetree (lambda ()(expand-file-name "journal.org" org-directory)))
"* %?\t%^G\n CREATED: %U\n About region:%i\n %a")
("c" "Code" entry (file+headline
(lambda () (expand-file-name "captures.org" org-directory ))
"Code")
"* %?\t%^G\n#+BEGIN_SRC %^{language}\n\n#+END_SRC\n CREATED: %U\n About region:%i\n %a" :prepend t)
;; The following two templates are used by the org-capture extension in your web browser
("p" "Protocol" entry (file+headline
(lambda () (expand-file-name "captures.org" org-directory ))
"Bookmarks from the web browser")
"* [[%:link][%:description]]\nCREATED: %U\n\n #+BEGIN_QUOTE\n%i\n#+END_QUOTE\n\n%?" :prepend t)
("L" "Protocol Link" entry (file+headline
(lambda () (expand-file-name "captures.org" org-directory ))
"Bookmarks from the web browser")
"* [[%:link][%:description]] \nCREATED: %U\n\n%?" :prepend t)
))
Collect log entries in drawer:
(setq org-log-into-drawer t)
Clock out when quitting emacs:
;; Taken from https://emacs.stackexchange.com/a/38487/12336
(defun my/org-clock-query-out ()
"Ask the user before clocking out.
This is a useful function for adding to `kill-emacs-query-functions'."
(if (and
(featurep 'org-clock)
(funcall 'org-clocking-p)
(y-or-n-p "You are currently clocking time, clock out? "))
(org-clock-out)
t)) ;; only fails on keyboard quit or error
;; timeclock.el puts this on the wrong hook!
(add-hook 'kill-emacs-query-functions 'my/org-clock-query-out)
Only use hours and minutes as duration format in clocktables:
(setq org-duration-format (quote h:mm))
Configure mode line:
(setq org-clock-mode-line-total 'today)
Helper function to collect today’s clocked times:
(defun tl/org-agenda-files-clock-sum-today ()
(apply '+ (mapcar
#'(lambda (file)
(save-window-excursion
(find-file file)
(org-clock-sum-today)))
(org-agenda-files))))
https://github.com/unhammer/org-mru-clock
Pre-fill your clock history with clocks from your agenda files.
(use-package org-mru-clock
:ensure t)
- State “TODO” from [2021-04-08 Thu 15:13]
https://github.com/abo-abo/org-download
- [ ] Issue with rename-at-point: abo-abo/org-download#164
(use-package org-download
:ensure t
:pin MELPA
:config
(setq org-download-image-org-width 400 ; will also add #+ATTR_ORG keyword
org-download-method 'attach
org-download-screenshot-method "scrot -s %s")
(add-hook 'dired-mode-hook 'org-download-enable))
Use a less intrusive export interface:
(setq org-export-dispatch-use-expert-ui t)
Note that the last export command on the current buffer can be reused with C-u C-c C-e
.
Usually, when copying parts of an Org file to the system clipboard (i.e. with kill-ring-save
) and inserting it in another application, the formatting (bold face, links, lists, code blocks, …) is not preserved, but the bare Org markup is shown. To preserve the formatting, the Org markup has to be exported to HTML first, and then copied to the clipboard.
For this, I’m adapting the solution proposed by John Kitchin for macOS. See also his short presentation on Youtube: https://www.youtube.com/watch?v=irkmQnggVpE
(defun org-copy-formatted-text-to-clipboard ()
"Export region to HTML, and copy it to the clipboard."
(interactive)
(save-window-excursion
(let* ((buf (org-export-to-buffer 'html "*Formatted Copy*" nil nil t t))
(html (with-current-buffer buf (buffer-string))))
(with-current-buffer buf
(shell-command-on-region
(point-min)
(point-max)
;; Command on macOS
;; "textutil -stdin -format html -convert rtf -stdout | pbcopy"
;; Command on Linux
"xclip -verbose -selection clipboard -t text/html"
))
(kill-buffer buf))))
(define-key org-mode-map (kbd "s-w") 'org-copy-formatted-text-to-clipboard)
Note that xclip
will wait (and Emacs will be stuck) until the copied content is pasted! I’m therefore using ox-clip instead, which is a little heavier.
https://github.com/jkitchin/ox-clip
Copy selected regions in Org buffers as formatted text to the clipboard. With ox-clip-image-to-clipboard
, this also includes attached image files or LaTeX formulas which are first converted to images.
(use-package ox-clip
:ensure t)
(define-key org-mode-map (kbd "s-w") 'tl/ox-clip-formatted-copy)
I add some custom filters for list items:
(defun tl/ox-clip-formatted-copy ()
"Export the selected region to HTML to the clipboard using
`ox-clip-formatted-copy', but with custom filters."
(interactive)
(let ((org-export-filter-plain-list-functions
'(org-fm-export-list-item-to-html))
(org-export-filter-final-output-functions
'(org-fm-export-whole-list-to-html)))
(call-interactively 'ox-clip-formatted-copy)))
(define-key org-mode-map (kbd "s-w") 'tl/ox-clip-formatted-copy)
https://www.gnu.org/software/emacs/manual/html_node/org/iCalendar-Export.html
(setq org-icalendar-timezone "Europe/Berlin"
org-icalendar-include-todo nil ; Non-nil means create VTODO components from TODO items.
org-icalendar-use-deadline '(event-if-todo ; Deadlines in TODO entries become calendar events.
event-if-not-todo ; Deadlines in non-TODO entries become calendar events.
todo-due ; Use deadlines in TODO entries as due-dates.
)
org-icalendar-use-scheduled '(;; todo-start ; Scheduling time stamps in TODO entries become start date.
;; event-if-todo ; Scheduling time stamps in TODO entries become an event.
;; event-if-not-todo ; Scheduling time stamps in non-TODO entries become an event.
)
org-icalendar-include-body nil) ; Amount of text below headline to be included in iCalendar export.
Helper function for removing timestamps from headers:
(defun tl/remove-org-timestamps (&optional file)
"Remove all (exported) Org timestamps and surrounding blanks from buffer or FILE."
(save-window-excursion
(when file (find-file file))
(beginning-of-buffer)
(while (re-search-forward
(concat "\\([[:blank:]]\\)*"
"\\(" org-element--timestamp-regexp "\\)"
"\\(–\\|[[:blank:]]\\)*"
) nil t)
(replace-match ""))
(when file
(save-buffer)
(kill-buffer))
))
Helper function for removing old dates in an icalender file:
(defun tl/icalendar-remove-dates-older-than (&optional date-string-Ymd)
"Remove all events older than DATE-STRING-YMD in an icalendar/ics buffer.
The argument DATE-STRING-YMD is optional. If not specified, it is set 90 days
before current time."
(beginning-of-buffer)
(let ((date-string-Ymd (or date-string-Ymd
(format-time-string "%Y%m%d"
(let ((time (decode-time (current-time)))
(delta (make-decoded-time :day -90)))
(encode-time (decoded-time-add time delta)))
)
;; (format-time-string "%Y%m%d"
;; (time-subtract
;; (current-time)
;; (seconds-to-time (* 60 60 24 90))))
)
))
(while (re-search-forward "DTSTART\\(?:;VALUE=DATE\\)?:[[:blank:]]*\\(.\\{8\\}\\)" nil t)
(when (< (string-to-number (match-string 1))
(string-to-number date-string-Ymd))
(delete-region
(re-search-backward "BEGIN:VEVENT")
(re-search-forward "END:VEVENT"))
;; Remove empty line
(if (save-excursion
(beginning-of-line)
(looking-at-p "[[:blank:]]*$"))
(delete-line)
())
))))
I now and then export the dates of my org-agenda and push them to a CalDAV server with vdirsyncer.
See blog post Integrating Org mode Agenda into other calendar apps.
The org-mode agenda can be exported with two commands:
org-icalendar-export-agenda-files
: export to separate files.org-icalendar-combine-agenda-files
: combine all exported entries in one file, which is specified inorg-icalendar-combined-agenda-file
(~/org.ics
by default).
The idea is to export the agenda to an icalendar file (when saving an agenda file) that is regularly imported to the calendar.
(defun tl/org-export-agenda-to-ics ()
(interactive)
(if (org-agenda-files)
(let* (
(org-export-with-broken-links t) ; Ignore broken links
(org-agenda-start-day "-2w") ; Unfortunately, this does not limit the export to recent dates
)
(org-icalendar-combine-agenda-files) ; Non-nil argument for asynchronuous processing
(message (concat "org-agenda exported to " org-icalendar-combined-agenda-file))
(save-window-excursion
(find-file org-icalendar-combined-agenda-file)
(tl/remove-org-timestamps)
(tl/icalendar-remove-dates-older-than)
(save-buffer)
(kill-buffer))
(message (concat "org-agenda calendar file cleaned and saved: " org-icalendar-combined-agenda-file)))
(message "tl/org-export-agenda-to-ics: org-agenda-files not specified, export aborted.")
)
)
The export can be narrowed to specific org-agenda files in the following way:
(let ((org-agenda-files (list
"/path/to/my/org-file.org"))
(org-icalendar-combined-agenda-file "/path/to/my/ics-file.ics"))
(org-icalendar-combine-agenda-files))
Lets create a helper function that can exports an org-mode buffer to an ics file with the same path:
(defun tl/org-export-buffer-to-ics ()
(interactive)
(if (buffer-file-name (current-buffer))
(let* ((file-name (buffer-file-name (current-buffer)))
(org-agenda-files (list file-name))
(org-icalendar-combined-agenda-file
(concat
(file-name-sans-extension file-name)
".ics")))
(tl/org-export-agenda-to-ics))
(message "tl/org-export-buffer-to-ics: buffer has no file, export aborted.")
))
Finally, wrap a function around the export of the org-agenda and syncing it with a CalDAV server using vdirsyncer.
(defun tl/org-export-agenda-to-caldav ()
"Export `org-agenda' to icalendar/ics file and upload it to CalDAV server."
(interactive)
(message "Exporting org-agenda to ics file...")
(tl/org-export-agenda-to-ics)
(message "Exporting org-agenda to ics file finished.")
(message "Syncing org-agenda and CalDav server...")
(shell-command "vdirsyncer sync org_agenda_calendar")
(while (yes-or-no-p "Sync with vdirsyncer once more? ")
(shell-command "vdirsyncer sync org_agenda_calendar"))
(message "Syncing org-agenda and CalDav server finished.")
)
There is a function org-icalendar-export-to-ics
, which exports a buffer or region to a single iCalendar file.
Let’s define a robuster function that exports just the heading under point and removes Org timestamps:
(defun tl/org-icalendar-export-heading-to-ics ()
"Export heading under point to ics file."
(interactive)
(let* ((org-export-with-broken-links t)
(org-icalendar-after-save-hook 'tl/remove-org-timestamps)
(org-icalendar-store-UID t)
(org-icalendar-categories nil)
(org-icalendar-include-body t))
;; (org-icalendar-export-to-ics nil t) ; Only works for regions
(save-restriction
(widen)
(org-narrow-to-subtree)
;; Add property EXPORT_FILE_NAME, which org-icalendar-export-to-ics will read when
;; SUBTREEP is t.
(unless (org-entry-get nil "EXPORT_FILE_NAME")
(org-set-property "EXPORT_FILE_NAME"
(concat
(read-directory-name "Select directory to safe ics file: "
(expand-file-name "~/Downloads/"))
(org-id-get-create)
".ics")))
;; Mark subtree if there is no active region. If SUBTREEP is t, only marked regions are exported.
(beginning-of-buffer)
(unless (region-active-p) (save-excursion (org-mark-subtree)))
(org-icalendar-export-to-ics nil t) ; If SUBTREEP is t.
(deactivate-mark)
(widen))))
Work in progress:
(defun org-icalendar--add-status (entry)
"Return the iCalendar STATUS field based on the :STATUS: property."
(let ((status (org-entry-get (point) "STATUS")))
(cond
((equal status "TENTATIVE") "STATUS:TENTATIVE\n")
((equal status "CONFIRMED") "STATUS:CONFIRMED\n")
((equal status "CANCELLED") "STATUS:CANCELLED\n")
(t nil))))
(advice-add 'org-icalendar--vevent :around
(lambda (orig-fn &rest args)
"Include STATUS in iCalendar export within VEVENT."
(let* ((event (apply orig-fn args))
(status (org-icalendar--add-status (car args))))
(if status
;; Insert the STATUS line after the SUMMARY line
(replace-regexp-in-string
"\\(SUMMARY:.*\\)"
(concat "\\1\n" status)
event)
event))))
Export to Hugo-compatible markdown.
(use-package ox-hugo
:pin MELPA
:ensure t
:after ox)
https://github.com/yjwen/org-reveal/ https://github.com/hexmode/ox-reveal
Turn org-mode buffers into Reveal slides. Requires htmlize.
(use-package ox-reveal
:ensure t
:config
(setq org-reveal-root "https://cdn.jsdelivr.net/npm/reveal.js@4.6.1/dist/reveal.min.js"
org-reveal-mathjax t)
)
- Apply custom styles
- https://orgmode.org/manual/Applying-custom-styles.html
#+ODT_STYLES_FILE: "/path/to/example.ott"
Only use actual width of image when not specified with #+ATTR* :width
(requires imagemagick)
(setq org-image-actual-width nil)
Set background color of images to white. Taken from https://emacs.stackexchange.com/a/37927/12336
(defcustom org-inline-image-background nil
"The color used as the default background for inline images.
When nil, use the default face background."
:group 'org
:type '(choice color (const nil)))
(defun create-image-with-background-color (args)
"Specify background color of Org-mode inline image through modify `ARGS'."
(let* ((file (car args))
(type (cadr args))
(data-p (caddr args))
(props (cdddr args)))
;; Get this return result style from `create-image'.
(append (list file type data-p)
(list :background (or org-inline-image-background (face-background 'default)))
props)))
(advice-add 'create-image :filter-args
#'create-image-with-background-color)
(require 'mode-local)
(setq-mode-local org-mode org-inline-image-background "white")
When inserting formatted content from the clipboard, this is first converted to appropriate Org markup:
(defun org-insert-formatted-text-from-clipboard ()
"Insert formatted clipboard content with Org markup."
(interactive)
(shell-command "xclip -o -t text/html | pandoc -f html -t org -" '(4)))
(define-key org-mode-map (kbd "s-y") 'org-insert-formatted-text-from-clipboard)
When receiving an ics file by mail, this is handled by mu4e.
Load export module for LaTeX:
(require 'ox-latex)
Headlines with :ignore:
tag are ignored during export, but not their body:
(require 'ox-extra)
(ox-extras-activate '(ignore-headlines))
Support from org-babel:
;; (org-babel-do-load-languages 'org-babel-load-languages '((latex . t)))
(setq org-highlight-latex-and-related '(latex script entities)) ; inline sytax highlighting
;; (add-to-list 'org-latex-packages-alist '("" "tikz" t)) ; unfortunately this breaks the color of fonts in inline previews
;; (add-to-list 'org-latex-packages-alist '("" "forest" t))
LaTeX source blocks should be executed with the following header arguments:
#+PROPERTY: header-args:latex+ :dir graphics :packages '(("" "../text-template/packages/tikz-settings")("" "times")) :headers '("\\input{../text-template/myMacros}") ... ...
Style of LaTeX previews:
(let ((default-scale 1.8))
;; static
(plist-put org-format-latex-options :scale default-scale) ; scale inline PNGs
(plist-put org-format-latex-options :background 'default) ; background of inline PNGs
;; dynamic (http://emacs.stackexchange.com/a/13032/12336)
(defun update-org-latex-fragment-scale ()
(let ((text-scale-factor (expt text-scale-mode-step text-scale-mode-amount)))
(plist-put org-format-latex-options :scale (* 2.3 default-scale text-scale-factor)))
)
(add-hook 'text-scale-mode-hook 'update-org-latex-fragment-scale)
)
Use LaTeXmk:
(setq org-latex-pdf-process (list "latexmk -f -pdf %f -outdir=%o"))
;; The option "-cd %o" is needed when executing babel source blocks,
;; during which the auxiliary files are moved to some temporary directory.
;; Instead of "-cd %o", one could also use "-outdir=%o".
;; See the discussion here:
;; https://github.com/fniessen/refcard-org-beamer/commit/9f75e013127940e793e0a925fc4ee222bae0e45c
Extra function to delete auxiliary files:
(defun delete-org-latex-aux-files ()
"This function deletes auxiliary files that are not deleted by `latexmk` or `TeX-clean`."
(interactive)
(shell-command "rm -rfv *.fls *.prv preview.fmt .aux .fdb_latexmk frag-master.tex"))
Adjust org-format-latex-header
:
(let ((default org-format-latex-header))
(setq org-format-latex-header (concat default "
\\DeclareMathOperator*{\\argmax}{arg\\,max}
\\DeclareMathOperator*{\\argmin}{arg\\,min}
")))
Add some classes to the set of known classes:
(add-to-list 'org-latex-classes
'("tl-abstract"
"\\documentclass{article}
[NO-DEFAULT-PACKAGES]"
("\\paragraph{%s}" . "\\paragraph*{%s}")
("\\subparagraph{%s}" . "\\subparagraph*{%s}")))
(add-to-list 'org-latex-classes
'("tl-article"
"\\documentclass{scrartcl}
[NO-DEFAULT-PACKAGES]"
("\\section{%s}" . "\\section*{%s}")
("\\subsection{%s}" . "\\subsection*{%s}")
("\\subsubsection{%s}" . "\\subsubsection*{%s}")
("\\paragraph{%s}" . "\\paragraph*{%s}")))
Add the class langscibook to the set of known classes:
(add-to-list 'org-latex-classes
'("langscibook"
"\\documentclass{langscibook}
[NO-DEFAULT-PACKAGES]"
("\\part{%s}" . "\\part*{%s}")
("\\chapter{%s}" . "\\chapter*{%s}")
("\\section{%s}" . "\\section*{%s}")
("\\subsection{%s}" . "\\subsection*{%s}")
("\\subsubsection{%s}" . "\\subsubsection*{%s}")
("\\paragraph{%s}" . "\\paragraph*{%s}")
))
(add-to-list 'org-latex-classes
'("langscibook-paper"
"\\documentclass[output=paper]{langscibook}
[NO-DEFAULT-PACKAGES]"
("\\section{%s}" . "\\section*{%s}")
("\\subsection{%s}" . "\\subsection*{%s}")
("\\subsubsection{%s}" . "\\subsubsection*{%s}")
("\\paragraph{%s}" . "\\paragraph*{%s}")
))
Add the class jlm to the set of known classes:
(add-to-list 'org-latex-classes
'("jlm"
"\\documentclass{jlm}
[NO-DEFAULT-PACKAGES]"
("\\section{%s}" . "\\section*{%s}")
("\\subsection{%s}" . "\\subsection*{%s}")
("\\subsubsection{%s}" . "\\subsubsection*{%s}")
("\\paragraph{%s}" . "\\paragraph*{%s}")
))
Use #+NAME:
field as argument of \label
during export:
(setq org-latex-prefer-user-labels t)
Put \label
outside and after \caption
(see https://emacs.stackexchange.com/a/51397/12336):
(defun org-latex--caption/label-string (element info)
"Return caption and label LaTeX string for ELEMENT.
INFO is a plist holding contextual information. If there's no
caption nor label, return the empty string.
For non-floats, see `org-latex--wrap-label'."
(let* ((label (org-latex--label element info nil t))
(main (org-export-get-caption element))
(attr (org-export-read-attribute :attr_latex element))
(type (org-element-type element))
(nonfloat (or (and (plist-member attr :float)
(not (plist-get attr :float))
main)
(and (eq type 'src-block)
(not (plist-get attr :float))
(null (plist-get info :latex-listings)))))
(short (org-export-get-caption element t))
(caption-from-attr-latex (plist-get attr :caption)))
(cond
((org-string-nw-p caption-from-attr-latex)
(concat caption-from-attr-latex "\n"))
((and (not main) (equal label "")) "")
((not main) label)
;; Option caption format with short name.
(t
(format (if nonfloat "\\captionof{%s}%s{%s}\n%s"
"\\caption%s%s{%s}\n%s")
(let ((type* (if (eq type 'latex-environment)
(org-latex--environment-type element)
type)))
(if nonfloat
(cl-case type*
(paragraph "figure")
(image "figure")
(special-block "figure")
(src-block (if (plist-get info :latex-listings)
"listing"
"figure"))
(t (symbol-name type*)))
""))
(if short (format "[%s]" (org-export-data short info)) "")
(org-export-data main info)
label)))))
Documentation:
- https://github.com/fniessen/refcard-org-beamer
- http://orgmode.org/tmp/worg/org-tutorials/org-latex-export.html
Load support for exporting LaTeX beamer presentations:
(require 'ox-beamer)
Add virtual beamer class (tl-beamer
) to the known LaTeX classes:
(add-to-list 'org-latex-classes
'("tl-beamer"
"\\documentclass{beamer}
[NO-DEFAULT-PACKAGES]"
("\\section{%s}" . "\\section*{%s}")
("\\subsection{%s}" . "\\subsection*{%s}")
("\\subsubsection{%s}" . "\\subsubsection*{%s}")
("\\paragraph{%s}" . "\\paragraph*{%s}")
("\\subparagraph{%s}" . "\\subparagraph*{%s}")))
Change export of bold font:
(defun my-beamer-bold (contents backend info)
(when (eq backend 'beamer)
(replace-regexp-in-string "\\`\\\\[A-Za-z0-9]+" "\\\\textbf" contents)))
(add-to-list 'org-export-filter-bold-functions 'my-beamer-bold)
Change export of italic font:
(defun my-beamer-italic (contents backend info)
(when (eq backend 'beamer)
(replace-regexp-in-string "\\`\\\\[A-Za-z0-9]+" "\\\\textit" contents)))
(add-to-list 'org-export-filter-italic-functions 'my-beamer-italic)
https://github.com/io12/org-fragtog
Automatically toggle LaTeX fragment previews under point.
(use-package org-fragtog
:ensure t
;; :config
;; (add-hook 'org-mode-hook 'org-fragtog-mode)
)
Follow links when pressing <return>
:
(setq org-return-follows-link t)
Links to files are opened in the same window, i.e. the window does not get split:
(setq org-link-frame-setup '((file . find-file)))
Show whether links to files are valid:
;; taken from https://emacs.stackexchange.com/a/33078/12336
(org-link-set-parameters
"file"
:face (lambda (path) (when (not (file-remote-p path))(if (file-exists-p path) 'org-link 'org-warning))))
(org-link-set-parameters
"attachment"
:face (lambda (path) (when (not (file-remote-p path))(if (file-exists-p (expand-file-name path (org-attach-dir))) 'org-link 'org-warning))))
Use IDs rather than headline names:
(setq org-id-link-to-org-use-id 'create-if-interactive)
create-if-interactive
is chosen, because, with t,
unwanted ID properties would be inserted when tangling org-babel source blocks. From the description:
create-if-interactive If ‘org-store-link’ is called directly (interactively, as a user command), do create an ID to support the link. But when doing the job for capture, only use the ID if it already exists. The purpose of this setting is to avoid proliferation of unwanted IDs, just because you happen to be in an Org file when you call ‘org-capture’ that automatically and preemptively creates a link. If you do want to get an ID link in a capture template to an entry not having an ID, create it first by explicitly creating a link to it, using ‘C-c l’ first.
Use ID completion when generating ID links:
;; taken from https://emacs.stackexchange.com/a/12434/12336
(defun org-id-complete-link (&optional arg)
"Create an id: link using completion"
(concat "id:"
(org-id-get-with-outline-path-completion)))
(org-link-set-parameters "id"
:complete 'org-id-complete-link)
Function to remove all ID properties from buffer:
(defun tl/org-id-remove-from-buffer ()
"Remove/delete all ID entries from current buffer and update the databases."
(interactive)
(save-excursion
(beginning-of-buffer)
(let ((id-removed-p nil))
(when (not (org-at-heading-p))
(org-next-visible-heading 1))
;; org-next-visible-heading moves point to end of buffer after last heading
(while (not (eobp))
(when (org-entry-delete (point) "ID")
(setq id-removed-p t))
(org-next-visible-heading 1))
(when (symbol-value 'id-removed-p)
(org-id-update-id-locations)))))
Function to replace a link with its description, inspired by https://emacs.stackexchange.com/a/10712/12336:
(defun tl/org-replace-link-with-description ()
"Replace an Org link of the format [[LINK][DESCRIPTION]] with DESCRIPTION.
If the link is of the format [[LINK]], delete the whole org link.
In both the cases, save the LINK to the kill-ring.
Execute this command when point is at an Org link."
(interactive)
(when (and (derived-mode-p 'org-mode)
(org-in-regexp org-link-bracket-re))
(save-excursion
(let* ((link-range (org-in-regexp org-link-bracket-re 1))
(link-start-pos (car link-range))
(link-end-pos (cdr link-range))
(link (match-string 0))
(target (match-string 1))
(description (match-string 2))
;; (description-start-pos (match-beginning 2))
;; (description-end-pos (match-end 2))
)
(kill-new (substring-no-properties target)) ; Save the link target to kill-ring
(delete-region link-start-pos link-end-pos)
(insert description)))))
;; (defun my/org-delete-link ()
;; "Replace an org link of the format [[LINK][DESCRIPTION]] with DESCRIPTION.
;; If the link is of the format [[LINK]], delete the whole org link.
;; In both the cases, save the LINK to the kill-ring.
;; Execute this command while the point is on or after the hyper-linked org link."
;; (interactive)
;; (when (derived-mode-p 'org-mode)
;; (let ((search-invisible t) start end)
;; (save-excursion
;; (when (re-search-backward "\\[\\[" nil :noerror)
;; (when (re-search-forward "\\[\\[\\(.*?\\)\\(\\]\\[.*?\\)*\\]\\]" nil :noerror)
;; (setq start (match-beginning 0))
;; (setq end (match-end 0))
;; (kill-new (match-string-no-properties 1)) ; Save the link to kill-ring
;; (replace-regexp "\\[\\[.*?\\(\\]\\[\\(.*?\\)\\)*\\]\\]" "\\2" nil start end)))))))
Open file types with specific programs:
(add-to-list 'org-file-apps '("\\.xopp\\'" . "xournalpp %s"))
Function to open links in new frame:
(defun tl/org-open-in-new-frame ()
"Open thing at point in new frame."
(interactive)
(let ((new-frame (make-frame)))
(select-frame-set-input-focus new-frame)
(org-open-at-point)
(recenter)))
Added to hydra-org.
- [ ] Also add it to the mouse context menu!
Deactivate timestamps in link description by replacing angular brackets. The following approach advices org-insert-link
:
(defun tl/org-link-deactivate-timestamp ()
"Deactivate timestamp in Org link description by replacing angular brackets with curly braces."
(interactive)
(when (and (derived-mode-p 'org-mode)
(org-in-regexp org-link-bracket-re))
(save-excursion
(let* ((link-range (org-in-regexp org-link-bracket-re 1))
(link-start-pos (car link-range))
(link-end-pos (cdr link-range))
(link (match-string 0))
(target (match-string 1))
(description (match-string 2))
(description-start-pos (match-beginning 2))
(description-end-pos (match-end 2)))
(goto-char description-start-pos)
(while (re-search-forward org-element--timestamp-regexp description-end-pos t)
(let* ((timestamp-start-pos (match-beginning 0))
(timestamp-end-pos (match-end 0)))
(replace-regexp "<" "{" nil timestamp-start-pos timestamp-end-pos t)
(replace-regexp ">" "}" nil timestamp-start-pos timestamp-end-pos t)
))))))
(advice-add 'org-insert-link :after #'tl/org-link-deactivate-timestamp)
Alternatively, one could change the heading before generating the link with org-store-link. However, this is more complicated and creates other problems, for example, when using the capture mechanism:
(defun tl/org-store-link-advice (orig-fun &rest args)
"Modify Org heading before creating an Org link.
Timestamps are deactivated by replacing angular brackets with curly braces."
(interactive)
;; (when (derived-mode-p 'org-mode)
(if (and (eq major-mode 'org-mode)
(org-current-level) ; t if below heading
;; Heading has a timestamp?
(save-excursion
(org-back-to-heading t)
(re-search-forward org-element--timestamp-regexp (line-end-position) t)))
(progn
(org-id-get nil t) ; Create ID if missing
(org-copy-subtree)
(save-window-excursion
(let ((temp-file (make-temp-file "-temp-buffer-")))
(find-file temp-file)
(yank)
(org-mode)
(goto-char (point-min))
(while (re-search-forward org-element--timestamp-regexp (line-end-position) t)
(let* ((timestamp-start-pos (match-beginning 0))
(timestamp-end-pos (match-end 0)))
(replace-regexp "<" "{" nil timestamp-start-pos timestamp-end-pos t)
(replace-regexp ">" "}" nil timestamp-start-pos timestamp-end-pos t)
))
(save-buffer)
;; (org-run-like-in-org-mode orig-fun)
(call-interactively orig-fun) ; FIXME: issue with non-interactive calls
(let ((buffer-offer-save nil))
(kill-buffer)))))
;; (org-run-like-in-org-mode orig-fun)
(call-interactively orig-fun) ; FIXME: issue with non-interactive calls
))
(advice-add 'org-store-link :around #'tl/org-store-link-advice)
Function to update link syntax that got changed in org-mode
v9.3 (taken from https://orgmode.org/Changes.html):
(defun org-update-link-syntax (&optional no-query)
"Update syntax for links in current buffer.
Query before replacing a link, unless optional argument NO-QUERY
is non-nil."
(interactive "P")
(org-with-point-at 1
(let ((case-fold-search t))
(while (re-search-forward "\\[\\[[^]]*?%\\(?:2[05]\\|5[BD]\\)" nil t)
(let ((object (save-match-data (org-element-context))))
(when (and (eq 'link (org-element-type object))
(= (match-beginning 0)
(org-element-property :begin object)))
(goto-char (org-element-property :end object))
(let* ((uri-start (+ 2 (match-beginning 0)))
(uri-end (save-excursion
(goto-char uri-start)
(re-search-forward "\\][][]" nil t)
(match-beginning 0)))
(uri (buffer-substring-no-properties uri-start uri-end)))
(when (or no-query
(y-or-n-p
(format "Possibly obsolete URI syntax: %S. Fix? "
uri)))
(setf (buffer-substring uri-start uri-end)
(org-link-escape (org-link-decode uri)))))))))))
Use the listings
package:
(setq org-latex-listings 'listings)
Map scr-block languages to listings
environments:
;; (setq org-latex-custom-lang-environments
;; '((org-babel-language "listings-environment")))
;; (org-babel-do-load-languages 'org-babel-load-languages '((makefile . t)))
https://github.com/novoid/Memacs https://arxiv.org/pdf/1304.1332.pdf
Blog posts:
https://github.com/timmli/org-fm-dev
Fast minutes with org-fm
.
;; (add-to-list 'load-path (expand-file-name "org-fm-dev" lisp-dir))
(use-package org-fm
:load-path "lisp/org-fm-dev"
:config
(org-fm-minor-mode))
HTML export of org-fm
is used in ox-clip.
See http://orgmode.org/worg/org-contrib/
;; (setq org-modules '( ;; org-bbdb
;; ;; org-gnus
;; ;; org-drill
;; ;; org-info
;; ;; org-jsinfo
;; ;; org-habit
;; ;; org-irc
;; ;; org-mouse
;; ;; org-protocol
;; ;; org-annotate-file
;; ;; org-eval
;; ;; org-expiry
;; ;; org-interactive-query
;; ;; org-man
;; ;; org-collector
;; ;; org-panel
;; ;; org-screen
;; ;; org-toc
;; ))
;; (eval-after-load 'org
;; '(org-load-modules-maybe t))
;; (setq org-expiry-inactive-timestamps t)
Split the line with M-<return>
. Disables org-table-wrap-region
when set to nil
.
(setq org-M-RET-may-split-line '((default . t)))
The following is taken from http://github.com/jkitchin/scimax/blob/master/scimax-org.el . See also http://kitchingroup.cheme.cmu.edu/blog/2017/04/09/A-better-return-in-org-mode/ .
(require 'org-inlinetask)
(defun scimax/org-return (&optional ignore)
"Add new list item, heading or table row with RET.
A double return on an empty element deletes it.
Use a prefix arg to get regular RET. "
(interactive "P")
(if ignore
(org-return)
(cond
((eq 'line-break (car (org-element-context)))
(org-return t))
;; Open links like usual, unless point is at the end of a line.
;; and if at beginning of line, just press enter.
((or (and (eq 'link (car (org-element-context))) (not (eolp)))
(bolp))
(org-return))
;; It doesn't make sense to add headings in inline tasks. Thanks Anders
;; Johansson!
((org-inlinetask-in-task-p)
(org-return))
;; checkboxes - add new or delete empty
((org-at-item-checkbox-p)
(cond
;; at the end of a line.
((and (eolp)
(not (eq 'item (car (org-element-context)))))
(org-insert-todo-heading nil))
;; no content, delete
((and (eolp) (eq 'item (car (org-element-context))))
(setf (buffer-substring (line-beginning-position) (point)) ""))
((eq 'paragraph (car (org-element-context)))
(goto-char (org-element-property :end (org-element-context)))
(org-insert-todo-heading nil))
(t
(org-return))))
;; lists end with two blank lines, so we need to make sure we are also not
;; at the beginning of a line to avoid a loop where a new entry gets
;; created with only one blank line.
((org-in-item-p)
(cond
;; empty definition list
((and (looking-at " ::")
(looking-back "- " 3))
(beginning-of-line)
(delete-region (line-beginning-position) (line-end-position)))
;; empty item
((and (looking-at "$")
(looking-back "- " 3))
(beginning-of-line)
(delete-region (line-beginning-position) (line-end-position)))
;; ;; numbered list (original)
;; ((and (looking-at "$")
;; (looking-back "[0-9]+. " (line-beginning-position)))
;; (beginning-of-line)
;; (delete-region (line-beginning-position) (line-end-position)))
;; numbered or alphabetical list (changed by TL)
((save-excursion
(beginning-of-line)
(or (looking-at " *[0-9]+. *$")
(looking-at " *[a-zA-Z]. *$")))
(beginning-of-line)
(delete-region (line-beginning-position) (line-end-position)))
;; insert new item
(t
(end-of-line)
(org-insert-item))))
;; org-heading
((org-at-heading-p)
(if (not (string= "" (org-element-property :title (org-element-context))))
(progn
;; Go to end of subtree suggested by Pablo GG on Disqus post.
(org-end-of-subtree)
(org-insert-heading-respect-content)
(outline-show-entry))
;; The heading was empty, so we delete it
(beginning-of-line)
(setf (buffer-substring
(line-beginning-position) (line-end-position)) "")))
;; tables
((org-at-table-p)
(if (-any?
(lambda (x) (not (string= "" x)))
(nth
(- (org-table-current-dline) 1)
(remove 'hline (org-table-to-lisp))))
(org-return)
;; empty row
(beginning-of-line)
(setf (buffer-substring
(line-beginning-position) (line-end-position)) "")
(org-return)))
;; fall-through case
(t
(org-return)))))
Set keys:
(with-eval-after-load 'org
(define-key org-mode-map (kbd "<return>") 'scimax/org-return)) ; not org-table-next-row
(defun tl/org-shift-return ()
(interactive)
(cond
;; in org-table
((org-table-p)
(org-table-copy-down 1))
;; else
(t (smart-open-line))
)
)
Set keys:
(with-eval-after-load 'org
(define-key org-mode-map (kbd "S-<return>") 'tl/org-shift-return )) ; not org-table-copy-down
- State “TODO” from [2023-10-28 Sat 11:33]
https://github.com/awth13/org-appear
Automatically toggle visibility of emphasis markers and links under point.
Issues
- [ ] Links not shown with Org v9.6.1: awth13/org-appear#46
- Seems to be connected to
org-fold-core-style
being set to'overlays
: awth13/org-appear#53
- Seems to be connected to
(use-package org-appear
:ensure t
:pin MELPA
:after org
:config
(add-hook 'org-mode-hook 'org-appear-mode)
(setq org-appear-autoemphasis t
org-appear-autolinks t
org-appear-autosubmarkers t))
Preserve indentation in source blocks:
(setq org-src-preserve-indentation t)
Don’t ask for confirmation when evaluating source blocks:
(setq org-confirm-babel-evaluate nil)
Fontify source blocks as defined for the enclosed language:
(setq org-src-fontify-natively t)
Use tab key as defined for the enclosed language:
(setq org-src-tab-acts-natively t)
The following fixes a problem with gnuplot-mode under windows. Alternatively, one could add `:session none` to every source block. See https://www.mail-archive.com/emacs-orgmode@gnu.org/msg30416.html
(when (eq system-type 'windows-nt)
(setq org-babel-default-header-args:gnuplot
'((:results . "file")
(:exports . "results"))))
Add org-mode to the list of supported languages:
;; (org-babel-do-load-languages 'org-babel-load-languages '((org . t)))
https://orgmode.org/worg/org-contrib/babel/languages/ob-doc-gnuplot.html
;; (org-babel-do-load-languages 'org-babel-load-languages '((gnuplot . t)))
Gnuplot example:
reset
set title "a simple graph"
set xrange [0:1]
set autoscale y
set xlabel "frequency of A"
plot x * x title 'AA', (1-x) * (1-x) title 'aa', 2 * x * (1-x) title 'Aa'
(add-to-list 'org-src-lang-modes '("dot" . graphviz-dot))
;; (org-babel-do-load-languages 'org-babel-load-languages '((dot . t)))
The LaTeX compiler is specified in org-latex-compiler
or buffer-locally in #+LATEX_COMPILER
.
https://orgmode.org/worg/org-contrib/babel/languages/ob-doc-plantuml.html
;; (org-babel-do-load-languages 'org-babel-load-languages '((plantuml . t)))
PlantUML example:
Bob -> Alice : Hello World!
https://github.com/nnicandro/emacs-jupyter
Provides an API for creating Jupyter kernel frontends in Emacs and also provides REPL and org-mode source block based frontends.
(use-package jupyter
:ensure t
:defer t
:config ; Do not use :init here, because this will throw "Error (use-package): jupyter/:init"
(setq org-babel-default-header-args:jupyter-python
'((:async . "yes")
(:session . "py")
(:kernel . "python3")))
;; (org-babel-do-load-languages 'org-babel-load-languages
;; '((emacs-lisp . t)
;; (python . t)
;; (jupyter . t)))
)
https://orgmode.org/worg/org-contrib/babel/languages/ob-doc-R.html
Requires ess.
;; (org-babel-do-load-languages 'org-babel-load-languages '((R . t)))
;; (setq org-babel-R-command "R --slave --no-save") ; needed on Windows
R example (from https://r-lang.com/plot-function-in-r-with-example/):
x <- seq(-pi, pi, 0.1)
plot(x, cos(x), type = "l",
main = "Overlaying Charts",
ylab = "",
col = "red")
lines(x, sin(x), col = "blue")
legend("topleft", c("sin(x)", "cos(x)"), fill = c("blue", "red"))
Org-babel source blocks containting the conf format.
Just export them to a file using :results file
keyword.
(defvar org-babel-default-header-args:conf '())
(defun org-babel-execute:conf (body _params)
"Execute a block of conf code.
This function is called by `org-babel-execute-src-block'."
body)
(defun org-babel-prep-session:conf (_session _params)
"Signal error; conf does not support sessions."
(error "Conf file sessions are nonsensical"))
Load languages that can be evaluated in org-babel source blocks.
- https://orgmode.org/manual/Languages.html
- https://orgmode.org/worg/org-contrib/babel/languages/index.html
(org-babel-do-load-languages
'org-babel-load-languages
'((emacs-lisp . t)
(dot . t)
(gnuplot . t)
(latex . t)
(makefile . t)
(org . t)
(python . t)
(jupyter . t) ; load jupyter after python
(plantuml . t)
(R . t)
(shell . t)))
https://gitlab.com/phillord/org-drill/ https://orgmode.org/worg/org-contrib/org-drill.html
Drill yourself in everything you want to learn – inspired by Anki.
(use-package org-drill
:ensure t)
https://github.com/chrisbarrett/org-drill-table
Easily generate org-drill cards using org-mode tables.
(use-package org-drill-table
:ensure t)
- State “TODO” from [2021-01-06 Wed 09:38]
https://github.com/lepisma/org-krita
https://orgmode.org/worg/org-contrib/org-protocol.html
(require 'org-protocol)
In order to make it available to, e.g., web browsers as an application, execute the following:
cat > "${HOME}/.local/share/applications/org-protocol.desktop" << EOF
[Desktop Entry]
Name=org-protocol
Exec=emacsclient %u
Type=Application
Terminal=false
Categories=System;
MimeType=x-scheme-handler/org-protocol;
EOF
update-desktop-database ~/.local/share/applications/
xdg-mime default org-protocol.desktop x-scheme-handler/org-protocol
https://github.com/jkitchin/org-ref
Add all kinds of reference types (citations, text references, indexes, …) to Org.
(use-package org-ref
:ensure t
:pin MELPA ; v2.0.0 is not compatible with helm v3.9.1
:after (org helm)
:init
(require 'org-ref) ; don't know why I need this
(setq org-ref-default-bibliography (list user-bibliography-file)
;; org-ref-bibliography-notes "~/bibliography/notes.org"
org-ref-pdf-directory user-bibliography-pdf-dir
org-ref-prefer-bracket-links t
org-ref-default-ref-type "autoref"
)
:config
(define-key org-mode-map (kbd "C-c ]") org-ref-insert-cite-function)
(define-key org-mode-map (kbd "C-c )") org-ref-insert-ref-function)
(define-key org-mode-map (kbd "C-c (") org-ref-insert-label-function)
;; :bind (:map org-mode-map
;; ("C-c ]" . org-ref-helm-insert-cite-link) ; Obsolete since > v2.0.0
;; ("C-c )" . org-ref-helm-insert-ref-link) ; Obsolete since > v2.0.0
;; ("C-c (" . org-ref-helm-insert-label-link) ; Obsolete since > v2.0.0
;; )
)
Add \citeauthoryear and \citealtauthoryear to org-ref:
;; Obsolete since > v2.0.0
;; (org-ref-define-citation-link "citeauthoryear")
;; (add-to-list 'org-ref-cite-types "citeauthoryear")
;; (org-ref-define-citation-link "citealtauthoryear")
;; (add-to-list 'org-ref-cite-types "citealtauthoryear")
Set colors:
(custom-set-variables
'(org-ref-label-color "magenta")
'(org-ref-ref-color "LimeGreen")
'(org-ref-cite-color "ForestGreen")
)
TODO: Change format entry string with org-ref-formatted-citation-formats
.
https://github.com/org-roam/org-roam
Knowledge management system similar to Roam and Zettelkästen. This configuration works with v2 of org-roam.
Example of how it works: https://blog.jethro.dev/posts/how_to_take_smart_notes_org/
Issues
- [ ] The face specified with propertize is not shown in org-roam-find-file.
(use-package org-roam
:ensure t
:pin MELPA
:init
(setq org-roam-v2-ack t)
:custom
(org-roam-directory my-org-roam-directory)
(org-roam-file-extensions '("org" "org_archive"))
(org-roam-db-location (expand-file-name "org-roam.db" my-org-roam-directory))
:bind (:map org-roam-mode-map
(("C-c n l" . org-roam)
("C-c n f" . org-roam-find-file)
("C-c n g" . org-roam-graph))
:map org-mode-map
(("C-c n i" . org-roam-insert))
(("C-c n I" . org-roam-insert-immediate)))
:config
(require 'org-roam-protocol)
(setq org-roam-tag-sources '(prop vanilla)
org-roam-index-file (expand-file-name "index.org" org-roam-directory))
;; The following adds a hierarchy view to org-roam-node-display-template
;; Taken from: https://github.com/org-roam/org-roam/wiki/User-contributed-Tricks#showing-node-hierarchy
(cl-defmethod org-roam-node-hierarchy ((node org-roam-node))
(let ((level (org-roam-node-level node)))
(concat
(when (> level 0) (concat (org-roam-node-file-title node) " > "))
(when (> level 1) (concat (string-join (org-roam-node-olp node) " > ") " > "))
(org-roam-node-title node))))
;; Setting the display of org-roam-node-find
(setq org-roam-node-template-prefixes '(("tags" . "#")("todo" . ""))
org-roam-node-display-template
(concat
"${todo:10} "
;; "${title:*} "
"${hierarchy:*} " ; provided by org-roam-node-hierarchy
(propertize "${tags:40}" 'face 'org-tag)) ; add tags to org-roam-node-find
)
;; ;; Make completion case-insensitive (https://emacs.stackexchange.com/a/77296/12336)
;;(defun case-insensitive-org-roam-node-read (orig-fn &rest args)
;; (let ((completion-ignore-case t))
;; (apply orig-fn args)))
;; (advice-add 'org-roam-node-read :around #'case-insensitive-org-roam-node-read)
)
Different org-roam databases (“Zettelkästen”) can be maintained using directory-local settings. See the advice here: https://www.orgroam.com/manual.html#How-do-I-have-more-than-one-Org_002droam-directory_003f
((nil . ((org-roam-directory . "/path/to/alt/org-roam-dir")
(org-roam-db-location . "/path/to/alt/org-roam-dir/org-roam.db"))))
Note that the function eval
has to be used in order to evaluate elisp code:
((nil . ((eval . (setq-local
org-roam-directory (expand-file-name "zettel" (locate-dominating-file
default-directory ".dir-locals.el") )))
(eval . (setq-local
org-roam-db-location (expand-file-name "org-roam.db"
org-roam-directory))))))
The org-roam manual recommends to use Deft to perform full-text search: https://www.orgroam.com/manual.html#Full_002dtext-search-with-Deft
Although I clearly prefer helm-org-rifle using the following function, it becomes quite slow with many files:
(defun tl/search-in-org-roam-files ()
(interactive)
(helm-org-rifle-files (org-roam-list-files)))
Eventually, I use ripgrep for the sake of speed. This is added to hydra-org-roam.
- State “TODO” from [2023-03-24 Fri 22:49]
In org-roam, you most probably end up either with a large number of small files, or with a small number of large files. Maintaining large files in org-roam is disadvantageous, because DB update takes longer and the long tail of unchanged headings with an ID will litter org-roam-find-file.
Since internal archiving (by adding the tag ARCHIVE) is not recognized in org-roam, I decided using external archiving to keep working files lean.
Plan
- [ ] Optionally add archive files to search tools like helm-rifle
https://www.orgroam.com/manual.html#Org_002droam-Protocol
org-roam-protocol
requires few extra steps in order to properly work:
cat > "${HOME}/.local/share/applications/org-protocol.desktop" << EOF
[Desktop Entry]
Name=org-protocol
Exec=emacsclient %u
Type=Application
Terminal=false
Categories=System;
MimeType=x-scheme-handler/org-protocol;
EOF
update-desktop-database ~/.local/share/applications/
xdg-mime default org-protocol.desktop x-scheme-handler/org-protocol
https://www.orgroam.com/manual.html#The-Templating-System
(setq org-roam-capture-templates
'(("d" "default" plain "%?"
:target (file+head "%<%Y%m%d%H%M%S>-${slug}.org"
":PROPERTIES:\n:ROAM_ALIASES: %^{Aliases| }\n:END:\n#+TITLE: ${title}\n#+FILETAGS: %^{Tags|:topic:}\n#+CREATED: %U\n#+LAST_MODIFIED: \n\n- links :: \n\n")
:unnarrowed t)
("t" "text" plain "%?"
:target (file+head "%<%Y%m%d%H%M%S>-${slug}.org"
":PROPERTIES:\n:ROAM_ALIASES: %^{Aliases| }\n:END:#+TITLE: ${title}\n#+FILETAGS: :text:\n#+ROAM_ALIASES: \n#+CREATED: %U\n#+LAST_MODIFIED: \n\n- links :: \n- PDF :: \n\n")
:unnarrowed t)))
https://www.orgroam.com/manual.html#Daily_002dnotes
Org-roam provides journaling capabilities akin to org-journal
with org-roam-dailies
.
Issues
- [ ] I actually prefer to put all days into one file, but this does not seem to allow for modifying the body of an entry, unlike the one-file-per-day approach.
- [ ] %? (After completing the template, position cursor here.) does not work inside the template.
(setq org-roam-dailies-directory "daily/")
(setq org-roam-dailies-capture-templates
`(
("f" "file" entry
"* %?"
:target (file+head "day_%<%Y-%m-%d>.org"
"#+title: Day %<%Y-%m-%d %A>
#+filetags: :day:
%u
Plan & Todos
Ideas & thoughts
Observations & encounters
"))
;; ("n" "node" entry
;; "* %?"
;; :target (file+olp "dailies.org"
;; (,(format-time-string "%Y")
;; ,(format-time-string "%Y-%m %B")
;; ,(format-time-string "%Y-%m-%d %A"))
;; ))
;; ;; :empty-lines 1 ; throws "peculiar error"
;; ;; :prepend t ; throws "peculiar error"
))
https://github.com/org-roam/org-roam-ui
Graphical interface to org-roam v2 notes in the web browser. Successor of org-roam-server.
(use-package org-roam-ui
:ensure t
:after org-roam
;; normally we'd recommend hooking orui after org-roam, but since org-roam does not have
;; a hookable mode anymore, you're advised to pick something yourself
;; if you don't care about startup time, use
;; :hook (after-init . org-roam-ui-mode)
:config
(setq org-roam-ui-sync-theme t
org-roam-ui-follow t
org-roam-ui-update-on-save t
org-roam-ui-open-on-start t ; Whether to open your default browser when ‘org-roam-ui’ launces.
))
https://github.com/org-roam/org-roam-bibtex
Enables a tight integration of org-roam
with helm-bibtex
and org-ref
.
(use-package org-roam-bibtex
:ensure t
:pin MELPA
:after (org-roam org-ref)
;; :hook (org-roam-mode . org-roam-bibtex-mode) ; will start org-roam-bibtex too late
:config
(require 'org-ref) ; optional: if using Org-ref v2 or v3 citation links
(setq orb-roam-ref-format 'org-ref-v2)
(org-roam-bibtex-mode t) ; enable org-roam-bibtex-mode
:custom
(orb-insert-interface 'helm-bibtex))
Templates for org-roam-bibtex
:
(add-to-list 'org-roam-capture-templates
'("r" "bibliography reference" plain "%?"
:target
(file+head "${citekey}.org"
"#+TITLE: ${citekey}: ${title}\n#+FILETAGS: %^{Tags|:text:}\n#+CREATED: %U\n#+LAST_MODIFIED: \n\n- links :: \n- PDF ::\n\n")
:unnarrowed t))
;; (setq orb-templates
;; '(("r" "ref" plain (function org-roam-capture--get-point) ""
;; :file-name "${citekey}"
;; :head "#+TITLE: ${citekey}: ${title}\n#+CREATED: %U\n#+ROAM_KEY: ${ref}\n#+ROAM_TAGS: %^{Tags} \n#+ROAM_ALIAS: \n#+LAST_MODIFIED: \n\n- links :: \n\n%?"
;; :unnarrowed t)))
Simple interactive presentations from within Emacs. See https://github.com/jkitchin/jmax/blob/master/org/org-show.org for more information.
(require 'org-show)
https://github.com/ichernyshovvv/org-timeblock
Show events in the agenda as timeblocks.
(use-package org-timeblock
:ensure t)
https://github.com/nobiot/org-transclusion
Manual: https://nobiot.github.io/org-transclusion/
Include content from one file into another by reference.
(use-package org-transclusion
:after org
:ensure t
:pin "GNU ELPA")
https://gitlab.com/vherrmann/org-xournalpp
Xournal++ is a versatile software to create hand-written notes and drawings, also allowing for the annotation of PDFs.
org-xournalpp
creates a new org link type called xournalpp
that:
- when clicked on, opens
xournalpp
for editing the file linked, and - shows the updated image preview inline if
org-xournalpp-mode
is enabled.
Note that the installation requires quelpa
.
(use-package org-xournalpp
:ensure t
:quelpa (org-xournalpp :fetcher gitlab :repo "vherrmann/org-xournalpp" :files ("*.el" "resources"))
:config
(add-hook 'org-mode-hook 'org-xournalpp-mode))
https://github.com/rudolfochrist/interleave
Following this excellent blog post: https://blog.aaronbieber.com/2017/03/19/organizing-notes-with-refile.html
(setq org-refile-targets '((org-agenda-files :maxlevel . 3))
org-refile-use-outline-path 'file
org-outline-path-complete-in-steps nil
org-refile-allow-creating-parent-nodes 'confirm)
https://github.com/alphapapa/org-ql
Search Org files with a powerful query language.
(use-package org-ql
:quelpa (org-ql :fetcher github :repo "alphapapa/org-ql"
:files (:defaults (:exclude "helm-org-ql.el"))))
Helm support is available separately.
(use-package helm-org-ql
:quelpa (helm-org-ql :fetcher github :repo "alphapapa/org-ql"
:files ("helm-org-ql.el")))
The most important use case for me is performing garbage collection on my agenda files. This is how DONE headings with clocks older than 60 days are searched for:
(org-ql-search (org-agenda-files) "todo:DONE and clocked:to=-60") ; Non-sexp syntax
(org-ql-search (org-agenda-files) '(and (todo "DONE") (clocked :to -60))) ; Sexp syntax
Here is more complex example for searching headings with an old clock that are DONE or events not in projects:
(org-ql-search (org-agenda-files)
'(and (and (or (todo "DONE")
;; tag hierarchies are not yet supported: https://github.com/alphapapa/org-ql/issues/145
(tags "event" "appointment")
)
(not (ancestors (tags "project"))))
(not (clocked :from -60))))
;; ispell
(add-to-list 'ispell-skip-region-alist '(":\\(PROPERTIES\\|LOGBOOK\\|SETTINGS\\):" . ":END:"))
(add-to-list 'ispell-skip-region-alist '("#\\+BEGIN_SRC" . "#\\+END_SRC"))
(add-to-list 'ispell-skip-region-alist '("#\\+BEGIN_EXPORT" . "#\\+END_EXPORT"))
;; flyspell
;; http://emacs.stackexchange.com/a/9347/12336
;; NO spell check for embedded snippets
(defadvice org-mode-flyspell-verify (after org-mode-flyspell-verify-hack activate)
(let ((rlt ad-return-value)
(begin-regexp "^[ \t]*#\\+begin_\\(src\\|html\\|latex\\|export\\)")
(end-regexp "^[ \t]*#\\+end_\\(src\\|html\\|latex\\|export\\)")
old-flag
b e)
(when ad-return-value
(save-excursion
(setq old-flag case-fold-search)
(setq case-fold-search t)
(setq b (re-search-backward begin-regexp nil t))
(if b (setq e (re-search-forward end-regexp nil t)))
(setq case-fold-search old-flag))
(if (and b e (< (point) e)) (setq rlt nil)))
(setq ad-return-value rlt)))
bjm/org-headline-to-top
is a function that moves the current heading to the top of a section; taken from http://pragmaticemacs.com/emacs/reorder-todo-items-in-your-org-mode-agenda/.
(defun bjm/org-headline-to-top ()
"Move the current org headline to the top of its section"
(interactive)
;; check if we are at the top level
(let ((lvl (org-current-level)))
(cond
;; above all headlines so nothing to do
((not lvl)
(message "No headline to move"))
((= lvl 1)
;; if at top level move current tree to go above first headline
(org-cut-subtree)
(beginning-of-buffer)
;; test if point is now at the first headline and if not then
;; move to the first headline
(unless (looking-at-p "*")
(org-next-visible-heading 1))
(org-paste-subtree))
((> lvl 1)
;; if not at top level then get position of headline level above
;; current section and refile to that position. Inspired by
;; https://gist.github.com/alphapapa/2cd1f1fc6accff01fec06946844ef5a5
(let* ((org-reverse-note-order t)
(pos (save-excursion
(outline-up-heading 1)
(point)))
(filename (buffer-file-name))
(rfloc (list nil filename nil pos)))
(org-refile nil nil rfloc))))))
Activate org-table-header-line-mode
by default:
(setq org-table-header-line-p t)
Some functions to select and copy columns (http://emacs.stackexchange.com/a/28298/12336)
(defun org-table-goto-col-beginning ()
"Go to beginning of current column and return `point'."
(interactive)
(assert (org-table-p) "Not in org-table.")
(org-table-align)
(let ((col (org-table-current-column)))
(goto-char (org-table-begin))
(org-table-goto-column col))
(point))
(defun org-table-col-beginning ()
"Return beginning position of current column."
(save-excursion
(org-table-goto-col-beginning)))
(defun org-table-goto-col-end ()
"Goto end of current column and return `point'."
(interactive)
(assert (org-table-p) "Not in org-table.")
(org-table-align)
(let ((col (org-table-current-column)))
(goto-char (1- (org-table-end)))
(org-table-goto-column col)
(skip-chars-forward "^|"))
(point))
(defun org-table-col-end ()
"Return end position of current column."
(save-excursion
(org-table-goto-col-end)))
(defun org-table-select-col ()
"Select current column."
(interactive)
(set-mark (org-table-col-beginning))
(org-table-goto-col-end))
(defun org-table-copy-col ()
"Copy current column."
(interactive)
(save-excursion
(org-table-copy-region (org-table-goto-col-beginning)
(org-table-goto-col-end))))
A function for copying the content of a cell:
(defun tl/org-table-copy-cell-content ()
(interactive)
(require 's)
(if (org-table-p)
(let ((cell-content (s-trim (substring-no-properties (org-table-get-field)))))
(kill-new cell-content)
(message "Copied cell content to kill ring."))
(message "Not inside org-mode table.")))
A function for killing the content of a cell:
(defun tl/org-table-kill-cell-content ()
(interactive)
(tl/org-table-copy-cell-content)
(org-table-blank-field))
A function to automatically number rows:
(defun tl/org-table-number-rows ()
"Number rows in an org-mode table by replacing the cells of the first column with consecutive numbers."
(interactive)
(when (org-table-p)
(save-excursion
(org-edit-special)
(beginning-of-buffer)
(when (not
(or (search-forward "$1=@#-1" nil t)
(search-forward "$1 = @#-1" nil t)))
(move-end-of-line nil)
(newline)
(insert "$1=@#-1"))
(org-table-fedit-finish)
(org-table-recalculate 'iterate))))
https://github.com/casouri/valign
Pixel-perfect visual alignment for Org and Markdown tables.
(use-package valign
:ensure t
;; :config
;; (add-hook 'org-mode-hook #'valign-mode)
)
Tags can be set globally as default using the variable org-tag-alist
.
Tags can be set globally and permantly using the variable org-tag-persistent-alist
.
(setq org-tag-persistent-alist
'(
;; ontology
(:startgroup . nil)
("topic" . ?t) ; for headings that denote topics
(:endgroup . nil)
(:startgroup . nil)
("project" . ?p)
(:grouptags . nil) ; kinds of projects
("task" . nil)
(:endgroup . nil)
(:startgroup . nil)
("event" . nil)
(:grouptags . nil) ; kinds of events
("appointment" . ?a)
("conference" . nil)
("talk" . nil)
("workshop" . nil)
("session" . nil)
(:endgroup . nil)
(:startgroup . nil)
("media" . ?m)
(:grouptags . nil) ; kinds of content
("text" . ?x)
("video" . nil)
("talk" . nil)
("poster" . nil)
(:endgroup . nil)
(:startgroup . nil)
("ressource" . ?r)
(:grouptags . nil) ; kinds of content
("data" . ?d)
("corpus" . nil)
("software" . ?s)
(:endgroup . nil)
;; topics
(:startgroup . nil)
("@work" . ?w)
(:grouptags . nil)
("administration" . ?v)
("research" . ?r)
("teaching" . ?e)
(:endgroup . nil)
))
Tags that should not be inherited by children:
(setq org-tags-exclude-from-inheritance '("topic" "event" "appointment" "conference" "talk" "workshop" "project" "text" "media" "video" "poster"))
Key bindings:
(define-key org-mode-map (kbd "C-c :") 'org-set-tags-command)
- State “TODO” from [2021-09-09 Thu 22:28]
- State “TODO” from [2021-09-09 Thu 22:28]
Insert timestamp or change type depending on region or point:
(defun tl/org-timestamp-dwim ()
(interactive)
(cond
((use-region-p)
(tl/org-read-date-and-insert-timestamp))
((eq (org-at-timestamp-p 'inactive) 'bracket)
(org-toggle-timestamp-type))
(t
(org-time-stamp nil))))
(define-key org-mode-map (kbd "C-c .") 'tl/org-timestamp-dwim)
(defun tl/org-read-date-and-insert-timestamp ()
"Replace date in region with active timestamp"
(interactive)
(if (use-region-p)
(let ((date (org-read-date nil nil (buffer-substring-no-properties (region-beginning) (region-end)))))
(save-excursion
(delete-region (region-beginning) (region-end))
(goto-char (region-beginning))
(insert "<" date ">")
(org-ctrl-c-ctrl-c)))
(message "No region selected")))
Set timestamp language to English:
(setq system-time-locale "C")
Use Alt-Shift+cursor key chords to quickly change timestamps:
- [ ] reorganize with cond
- [ ] fix: does not work with inactive time stamps
(defun tl/org-alt-shift-up ()
(interactive)
(if (org-at-timestamp-p)
(org-timestamp-up)
(org-shiftmetaup)
))
(defun tl/org-alt-shift-down ()
(interactive)
(if (org-at-timestamp-p)
(org-timestamp-down)
(org-shiftmetadown)
))
(defun tl/org-alt-shift-left ()
(interactive)
(if (org-at-timestamp-p)
(org-timestamp-down-day)
(org-shiftmetaleft)
))
(defun tl/org-alt-shift-right ()
(interactive)
(if (org-at-timestamp-p)
(org-timestamp-up-day)
(org-shiftmetaright)
))
(defun tl/org-agenda-alt-shift-up ()
(interactive)
(unless (ignore-errors
(funcall-interactively 'org-agenda-date-earlier-hours 1))
(org-clock-convenience-timestamp-up)
))
(defun tl/org-agenda-alt-shift-down ()
(interactive)
(unless (ignore-errors
(funcall-interactively 'org-agenda-date-later-hours 1))
(org-clock-convenience-timestamp-down)
))
(with-eval-after-load 'org
(define-key org-mode-map (kbd "M-S-<up>") 'tl/org-alt-shift-up)
(define-key org-mode-map (kbd "M-S-<down>") 'tl/org-alt-shift-down)
(define-key org-mode-map (kbd "M-S-<left>") 'tl/org-alt-shift-left)
(define-key org-mode-map (kbd "M-S-<right>") 'tl/org-alt-shift-right)
(define-key org-agenda-mode-map (kbd "M-S-<up>") 'tl/org-agenda-alt-shift-up)
(define-key org-agenda-mode-map (kbd "M-S-<down>") 'tl/org-agenda-alt-shift-down)
(define-key org-agenda-mode-map (kbd "M-S-<left>") 'org-agenda-date-earlier)
(define-key org-agenda-mode-map (kbd "M-S-<right>") 'org-agenda-date-later)
)
See https://emacs.stackexchange.com/a/21302/12336
(defvar org-created-property-name "CREATED"
"The name of the org-mode property that stores the creation date of the entry")
(defun org-set-created-property (&optional active NAME)
"Set a property on the entry giving the creation time.
By default the property is called CREATED. If given the `NAME'
argument will be used instead. If the property already exists, it
will not be modified."
(interactive)
(let* ((created (or NAME org-created-property-name))
(fmt (if active "<%s>" "[%s]"))
(now (format fmt (format-time-string "%Y-%m-%d %a %H:%M"))))
(unless (org-entry-get (point) created nil)
(org-set-property created now))))
http://karl-voit.at/2017/01/15/org-clone-subtree-with-time-shift/
https://github.com/snosov1/toc-org
Insert or update a Github-compatible table of contents under a heading with tag :TOC:
.
:TOC_2:
sets the max depth of the headlines in the table of contents to 2 (the default):TOC_2_gh:
sets the max depth as in above and also uses GitHub-style hrefs in the table of contents (this style is default). The other supported href style is ‘org’, which is the default org style.
(use-package toc-org
:ensure t
;; :config
;; (if (require 'toc-org nil t)
;; (add-hook 'org-mode-hook 'toc-org-mode)
;; (warn "toc-org not found"))
)
(Must appear before org-agenda
settings. Otherwise org-todo-keywords
may not get updated buffer locally.)
https://orgmode.org/manual/TODO-Items.html
TODO keywords appear in headlines right after the initial stars. They can be used to keep track of the states of projects and tasks.
State keywords for tasks and projects:
- TODO: something that needs to be done, maybe now, maybe later.
- NEXT: something that can be done now. There’s everything you need to start doing it.
- INPROGRESS: something that is being done right now.
- WAITING: something that cannot be done now, because some prerequisites are not yet met.
- HOLD: something that cannot be done now, and the prerequisites are unlikely to be fullfilled in the future.
- SOMEDAY: you are not yet sure whether this needs to be done.
- DELEGATED: something that has been delegated and is not tracked any more.
State keywords for events and appointments:
- TENTATIVE: not yet confirmed that something will take place.
- CONFIRMED: confirmed that something will take place. This is the default.
- CANCELLED: something will not take place though it was planned.
From the org-mode documentation (http://orgmode.org/worg/doc.html#org-todo-keywords):
“WAIT(w@/!)”. “@” means to add a note (with time), “!” means to record only the time of the state change. With X and Y being either “@” or “!”, “X/Y” means use X when entering the state, and use Y when leaving the state if and only if the target state does not define X. You may omit any of the fast-selection key or X or /Y, so WAIT(w@), WAIT(w/@) and WAIT(@/@) are all valid.
(setq org-todo-keywords
(quote ((sequence "TODO(t!)" "NEXT(n!)" "INPROGRESS(p!)" "|" "DONE(d)")
(sequence "WAITING(w@/!)" "HOLD(h@/!)" "SOMEDAY(s)" "|" "DELEGATED(l@/!)" "CANCELLED(c@/!)")
(sequence "TENTATIVE(T!)" "|" "CONFIRMED(C!)" "CANCELLED(c@/!)" ))))
(setq org-todo-keyword-faces
(quote (("TODO" :foreground "red" :weight bold)
("NEXT" :foreground "blue" :weight bold)
("INPROGRESS" :foreground "gold" :weight bold)
("DONE" :foreground "forest green" :weight bold)
("WAITING" :foreground "cyan" :weight bold)
("HOLD" :foreground "magenta" :weight bold)
("CANCELLED" :foreground "forest green" :weight bold)
("DELEGATED" :foreground "forest green" :weight bold)
("SOMEDAY" :foreground "goldenrod" :weight bold)
("CONFIRMED" :foreground "forest green" :weight bold)
("TENTATIVE" :foreground "cyan" :weight bold)
)))
Fast TODO selection:
(setq org-use-fast-todo-selection t)
Insert timestamp when task is marked as DONE:
(setq org-log-done 'time)
Insert timestamp when changing deadline:
(setq org-log-redeadline 'time)
Do not insert timestamp or note when changing schedule:
(setq org-log-reschedule nil)
As I frequently change SCHEDULED and (mis)use it for planning when to work next on a project, this is to prevent the LOGBOOK from being cluttered.
Observe dependencies between TODOs:
(setq org-enforce-todo-dependencies t)
If the file keyword #+LAST_MODIFIED
is present within the first 20 lines, the following timestamp gets updated when saving the file:
(add-hook 'org-mode-hook (lambda ()
(set (make-local-variable 'time-stamp-pattern)
"20/^#\\+LAST_MODIFIED:[ \t]+%:y-%02m-%02d %3a %02H:%02M:%02S$")))
(add-hook 'before-save-hook 'time-stamp)
https://github.com/ledger/ledger-mode
Ledger is a powerful, double-entry accounting system.
(use-package ledger-mode
:ensure t
:mode ("\\.ledger\\'" "\\.dat\\'")
:config
(define-key ledger-mode-map (kbd "C-c c") 'ledger-mode-clean-buffer)
(define-key ledger-mode-map (kbd "C-<tab>") nil)
(setq ledger-post-amount-alignment-at :decimal
ledger-post-amount-alignment-column 49
ledger-default-date-format "%Y-%m-%d"
ledger-use-iso-dates t
ledger-reconcile-default-commodity "€"
ledger-clear-whole-transactions t)
(use-package flycheck-ledger
:ensure t))
https://github.com/DamienCassou/vdirel/
vidirel reads and manipulates contacts in the vdir format.
Issues:
- [ ] Import of contacts crashes with error: “Wrong number of arguments: #<subr org-vcard-import-parse>, 2”
(use-package vdirel
:ensure t
:pin MELPA
:config
(setq vdirel-repositories (file-expand-wildcards "~/PATH/TO/VDIRs")))
https://github.com/DamienCassou/khardel
Uses khard and vdirsyncer to edit and sync local copies of CarDAV address books. Also supports org-mode links to khard entries.
(use-package khardel
:ensure t
:config
(require 'khardel-org) ; org links to khard contact edit buffers
)
Function to sync contacts using vdirsyncer:
(defun tl/vdirsyncer-sync-contacts ()
"Start vdirsyncer in a subprocess in order to sync contacts."
(interactive)
(let* ((command "vdirsyncer-sync-contacts.sh")
(name "*vdirsyncer-sync*")
(buffer (progn (when (get-buffer name)
(kill-buffer name))
(get-buffer-create name))))
(with-current-buffer buffer
(call-process "vdirsyncer-sync-contacts.sh" nil t nil)
(setq buffer-read-only t)
(local-set-key (kbd "q") 'kill-this-buffer)
(switch-to-buffer buffer)
(goto-char (point-min)))
;; (start-process-shell-command name buffer command)
(message "tl/vdirsyncer-sync-contacts: Syncing in progress, see buffer %s" name)
))
http://savannah.nongnu.org/projects/bbdb/
Built-in address book in Emacs.
Unfortunately, the current version of BBDB is lacking a decent manual. For an outdated manual, see: https://bbdb.sourceforge.net/bbdb.html
BBDB seems to only allow for one database (file). Therefore (and for other reasons), I switched to EBDB.
(use-package bbdb
:ensure t
:config
(progn
(bbdb-initialize '(gnus message mu4e))
;; (add-hook 'gnus-startup-hook 'bbdb-insinuate-gnus)
;; (add-hook 'gnus-startup-hook 'bbdb-insinuate-message)
;; (add-hook 'message-setup-hook 'bbdb-define-all-aliases)
(setq bbdb-file my-bbdb-file ; Addresses are stored in one file
bbdb-auto-revert t ; Revert DB when changing the bbdb-
bbdb-check-auto-save-file t ; Auto-save to bbdb-file
bbdb-phone-style nil ; nanp = North American Numbering Plan
bbdb-complete-mail-allow-cycling t ; Cycle mail addresses when calling ‘bbdb-complete-mail’.
;; Pop-up window
bbdb-pop-up-window-size 0.5 ; Default split is 0.5
bbdb-pop-up-target-lines 1 ; The window should be as small as possible
bbdb-use-pop-up nil ; Down't show pup-up
;; bbdb-complete-name-allow-cycling t ; Not documented
;; bbdb-complete-name-full-completion t ; Not documented
;; bbdb-completion-type 'primary-or-name ; Not documented
;; bbdb-offer-save 1 ; Not documented
;; bbdb-electric-p t ; Not documented
;; bbdb-expand-mail-aliases t ; Not documented
)
))
https://github.com/tohojo/bbdb-vcard
Import and export vCards to/from BBDB.
(use-package bbdb-vcard
:pin MELPA
:ensure t)
https://github.com/emacs-helm/helm-bbdb
A Helm Interface to BBDB.
(use-package helm-bbdb
:ensure t)
(global-set-key (kbd "<f7> a") 'helm-bbdb)
https://github.com/girzel/ebdb
An object-orientied port of bbdb.
Issues
- [ ] Unfortunately, vcard/vcf files cannot be imported: girzel/ebdb#60
(use-package ebdb
:ensure t
:config
(require 'ebdb-gnus)
(require 'ebdb-message))
!!! WORK IN PROGRESS !!!
https://github.com/timmli/helm-khard
A Helm interface for khard.
(use-package uuidgen
:ensure t
:pin MELPA)
(use-package helm-khard
:after mu4e
:load-path "lisp/helm-khard/"
:config
(setq helm-khard-vdirsyncer-command "vdirsyncer-sync-contacts.sh"
helm-khard-sync-after-editing t
helm-khard-sync-during-initialization t)
(advice-add 'mu4e--update-contacts :after #'helm-khard--inject-contacts-into-mu4e))
https://www.gnu.org/software/emacs/manual/html_node/emacs/Calendar_002fDiary.html
(setq calendar-week-start-day 1) ; weeks start on Mondays
(setq calendar-intermonth-text
'(propertize
(format "%2d"
(car
(calendar-iso-from-absolute
(calendar-absolute-from-gregorian (list month day year)))))
'font-lock-face 'font-lock-warning-face))
(setq calendar-intermonth-header
(propertize "W" ; or e.g. "KW" in Germany
'font-lock-face 'font-lock-keyword-face))
https://github.com/rudolfochrist/german-holidays
Adds German holidays to the calendar.
(use-package german-holidays
:ensure t
:config
(setq calendar-holidays holiday-german-holidays)
;; (setq calendar-holidays holiday-german-BW-holidays)
)
iCalendar files can be imported
- via calfw
- via the Emacs diary:
icalendar-import-file
imports ics-files from caldav servers into the diary file. This will eventually be shown in org-agenda based on the variableorg-agenda-include-diary
- via org-mode and mu4e
https://github.com/kiwanami/emacs-calfw/
Powerful calendar view for Emacs.
Issues:
- [ ] Week numbers are not shown: kiwanami/emacs-calfw#137
- [ ] Recurring events in imported ics files are not shown.
(use-package calfw :ensure t :init (use-package calfw-org ; for org-agenda :ensure t) (use-package calfw-ical ; for ics files :ensure t) (use-package calfw-cal ; for diaries :ensure t) (setq cfw:render-line-breaker 'cfw:render-line-breaker-simple) )
Define a key to update calendars from within calfw:
(define-key cfw:calendar-mode-map (kbd "u")
#'(lambda () (interactive)
(when (fboundp 'tl/update-my-calendars) ; tl/update-my-calendars can be redefined in private-emacs-settings-after.el
(tl/update-my-calendars))
(my-open-calfw)
))
Calendars are defined in my-private-calendars
:
(defvar my-private-calendars
'((:name "NAME"
:url "URL"
:color "Orange"
:description ""))
"This variable stores the remote calendars as a list of plists.
A calendar consists of a list of KEY VALUE pairs (plist) with keys :name, :url, :color, and :description.
It is recommended to populate this variable in `private-emacs-settings-after.el`.")
Helper functions:
(require 'dash)
(defun tl/update-my-calendars ()
(let ((newpcal
(-zip-with
(lambda (s1 s2) (append s1 s2))
(mapcar
(lambda (cal)
(let* ((name (plist-get cal ':name))
(url (plist-get cal ':url))
(color (plist-get cal ':color))
(file (if (plist-get cal ':file)
(plist-get cal ':file)
(concat trimmed-private-emacs-settings-dir name ".ics"))))
(tl/check-url-and-download-file url file)
`(:file ,file)))
my-private-calendars)
my-private-calendars)
))
(setq my-private-calendars newpcal)))
(defun my-open-calfw ()
(interactive)
(cfw:open-calendar-buffer
:contents-sources
(append
(list
(cfw:org-create-source "Orange") ; orgmode source
;; (cfw:cal-create-source) ; diary source
)
(mapcar
(lambda (cal)
(let* ((name (plist-get cal ':name))
(url (plist-get cal ':url))
(color (plist-get cal ':color))
(file (if (plist-get cal ':file)
(plist-get cal ':file)
(concat trimmed-private-emacs-settings-dir name ".ics"))))
(cfw:ical-create-source name file color)))
my-private-calendars))
))
(defun tl/check-url-and-download-file (url filename)
(if (url-https-file-exists-p url)
(url-copy-file url filename t nil nil)
(display-warning 'calendar (concat "Could not download " filename))))
https://gitlab.com/hperrey/khalel
Uses khal and vdirsyncer to sync local copies of CalDAV calendars with calendar entries in org-mode files. As for address books, please have a look at khard and khardel.
Important limitations:
- Only for importing calendars as org-mode files. Hence, changes to calendars must be made upstream with a client such as khal.
+-------+ +----------+ +-------+ +-------+ +---------+
| |--->| |--->| |--->| |--->| |
| remote| |vdirsyncer| | khal | |khalel | | org mode|
| |<===| |<===| |===>| |===>| |
+-------+ +----------+ +-------+ +-------+ +---------+
^
:
:
+----------+ +--------+
| | | | --> existing events
| org mode |===>| khalel |
| | | | ==> new events
+----------+ +--------+
!!! WORK IN PROGRESS !!!
https://codeberg.org/timmli/org-ical-sync
Sync Org headings with iCal database.
(use-package org-ical-sync
:after org
:load-path "lisp/org-ical-sync/"
:config
(org-ical-sync-setup)
(setq org-ical-sync-vdirsyncer-command "vdirsyncer-sync-calendars.sh"
org-ical-sync-after-save t)
(org-ical-sync-call-vdirsyncer-now))
http://www.lysator.liu.se/~tab/artist/ http://dinasis.com/oliver/Learning_GNU_Emacs/gnu3-CHP-7-SECT-6.html
Artist mode is a built-in minor mode for picture mode in Emacs with which simple geometric forms (lines, rectangles, circles, ellipses, …) can be drawn using just text characters. This can be handy when wanting to create, e.g., simple diagrams to be included in your code.
Here is an example:
-------
--/ \--
+---------+ / \
| | / \
| Hello | <---------> | World! |
| | \ /
+---------+ \ /
--\ /--
-------
I have made a Hydra for artist-mode.
Note that the function set of artist-mode is very basic. For example, one cannot resize a rectangular directly.
https://github.com/clojure-emacs/clojure-mode/
Font-lock (syntax highlighting), indentation, navigation and refactoring support for Clojure(Script).
(use-package clojure-mode
:ensure t
:mode (("\\.clj\\'" . clojure-mode)
("\\.edn\\'" . clojure-mode))
:init
(add-hook 'clojure-mode-hook #'subword-mode))
https://github.com/clojure-emacs/clj-refactor.el
Powerful refactoring functionality for Clojure projects which complements clojure-mode and CIDER.
(use-package clj-refactor
:defer t
:ensure t
:diminish clj-refactor-mode
:config (cljr-add-keybindings-with-prefix "C-c C-m"))
https://github.com/clojure-emacs/cider
CIDER is the Clojure(Script) Interactive Development Environment that Rocks! AKA REPL. A basic configuration of Cider is shown here: http://ccann.github.io/2015/10/18/cider.html
(use-package cider
:ensure t
:defer t
:init (add-hook 'cider-mode-hook #'clj-refactor-mode)
:diminish subword-mode
:bind (:map cider-repl-mode-map
("C-h a" . cider-apropos)
:map clojure-mode-map
("C-h a" . cider-apropos))
:config
(setq nrepl-log-messages t ; useful for debugging
cider-repl-display-in-current-window t ; switch to REPL in this window
cider-repl-use-clojure-font-lock t ; syntax highlighting in REPL
cider-prompt-save-file-on-load 'always-save ; just always save when loading buffer
cider-font-lock-dynamically '(macro core function var) ; syntax highlight all namespaces
nrepl-hide-special-buffers t ; hide nrepl buffers from menu
cider-overlays-use-font-lock t) ; syntax highlight evaluation overlays
(cider-repl-toggle-pretty-printing)) ; REPL always pretty-prints results
https://github.com/clojure-emacs/cider-eval-sexp-fu
From the README: ”eval-sexp-fu
provides tiny improvements to expression evaluation - e.g. the expression you’ve just evaluated would briefly flash and so on.”
(use-package cider-eval-sexp-fu
:ensure t
:defer t)
EditorConfig helps specifying and sharing coding styles for consistent coding.
Coding styles are stored in a file named .editorconfig
that is located in the directory of the opened file or in some parent directory.
Here is an example from the website:
# EditorConfig is awesome: https://EditorConfig.org
# top-most EditorConfig file
root = true
# Unix-style newlines with a newline ending every file
[*]
end_of_line = lf
insert_final_newline = true
# Matches multiple files with brace expansion notation
# Set default charset
[*.{js,py}]
charset = utf-8
# 4 space indentation
[*.py]
indent_style = space
indent_size = 4
# Tab indentation (no size specified)
[Makefile]
indent_style = tab
# Indentation override for all JS under lib directory
[lib/**.js]
indent_style = space
indent_size = 2
# Matches the exact files either package.json or .travis.yml
[{package.json,.travis.yml}]
indent_style = space
indent_size = 2
https://github.com/editorconfig/editorconfig-emacs
EditorConfig plugin for Emacs.
(use-package editorconfig
:ensure t
:config
(editorconfig-mode 1))
Guides
- https://github.com/bbatsov/emacs-lisp-style-guide
- https://spin.atomicobject.com/2016/05/27/write-emacs-package/
- https://github.com/alphapapa/emacs-package-dev-handbook?tab=readme-ov-file#binding
Makefiles
https://elpa.gnu.org/packages/elisp-benchmarks.html
See http://xahlee.info/emacs/emacs/elisp_benchmark.html for examples.
Usage:
(benchmark-run REPETITIONS FORMS)
(benchmark-run-compiled REPETITIONS FORMS)
: Use the ad-hoc byte-compiled version of FORMS.
https://www.gnu.org/software/emacs/manual/html_node/elisp/Profiling.html
Interactive profiler that records the CPU time consumed by function calls.
Usage:
(profiler-start MODE)
: start profiler(profiler-stop)
: end profiler(profiler-report)
: show profiler report
https://github.com/emacs-eldev/eldev
Elisp development tool similar to Cask, but fully written in Elisp.
If the file keyword ;; Last modified:
is present within the first 20 lines, the following timestamp gets updated when saving the file:
(add-hook 'emacs-lisp-mode-hook (lambda ()
(set (make-local-variable 'time-stamp-pattern)
"20/^;; Last modified:[ \t]+%:y-%02m-%02d %3a %02H:%02M:%02S$")))
(add-hook 'before-save-hook 'time-stamp)
https://github.com/emacsorphanage/gnuplot
Major mode for gnuplot files.
(use-package gnuplot
:ensure t
:mode "\\.\\(gp\\|gnuplot|plt\\)$"
)
Example:
f(x) = x**2
plot f(x)
https://github.com/ppareit/graphviz-dot-mode
Major mode for graphiz/dot code.
(use-package graphviz-dot-mode
:ensure t
:mode "\\.dot\\'")
https://github.com/hniksic/emacs-htmlize
Convert buffers and files to HTML while preserving text and formatting.
(use-package htmlize
:ensure t)
https://github.com/mooz/js2-mode
Major mode for JavaScript files.
(use-package js2-mode
:ensure t
:mode
("\\.js\\'" . js2-mode)
:config
;; Better imenu
(add-hook 'js2-mode-hook #'js2-imenu-extras-mode)
)
https://github.com/js-emacs/js2-refactor.el
(use-package js2-refactor
:ensure t
:after js2-mode
:config
(add-hook 'js2-mode-hook #'js2-refactor-mode)
(js2r-add-keybindings-with-prefix "C-c C-r")
(define-key js2-mode-map (kbd "C-k") #'js2r-kill))
If the file keyword // Last modified:
is present within the first 20 lines, the following timestamp gets updated when saving the file:
(add-hook 'js-mode-hook (lambda ()
(set (make-local-variable 'time-stamp-pattern)
"20/^// Last modified:[ \t]+%:y-%02m-%02d %3a %02H:%02M:%02S$")))
(add-hook 'before-save-hook 'time-stamp)
JSDoc is a commeting style of JavaScript source code. Other than docstrings in languages like Lisp, however, these comments are not part of the program, and are usually stripped off during parsing.
https://github.com/isamert/jsdoc.el
Provides simple JSDoc support for the prize of requiring Tree-Sitter.
(use-package jsdoc
:ensure t)
https://github.com/NicolasPetton/Indium
JavaScript development environment for Emacs
for better autocompletion
- [ ] How to do completion of custom macros?
(use-package tex
:ensure auctex ; because auctex overwrites tex
:mode ("\\.bbx\\'" . latex-mode)("\\.cbx\\'" . latex-mode)
:init
;; to activate auctex
(setq TeX-auto-save t)
(setq TeX-auto-local
(expand-file-name "temp" user-emacs-directory))
(setq TeX-parse-self t)
(setq-default TeX-master nil)
(setq TeX-save-query nil) ; autosave before compiling
;; Show compilation log
(setq TeX-show-compilation nil) ; always show and follow TeX output
;; FIXME: Make C-c C-l behave like this
(setq compilation-scroll-output t)
;; don't indent
(setq LaTeX-indent-level 0)
(setq LaTeX-item-indent 0)
;; viewer
(setq TeX-PDF-mode t)
(setq TeX-source-correlate-mode t)
(setq TeX-source-correlate-method 'synctex)
(when (eq system-type 'windows-nt)
(setq TeX-view-program-list
'(("Sumatra PDF" ("\"SumatraPDF.exe\" -reuse-instance"
(mode-io-correlate " -forward-search %b %n ") " %o"))))
(eval-after-load 'tex
'(progn
(assq-delete-all 'output-pdf TeX-view-program-selection)
(add-to-list 'TeX-view-program-selection '(output-pdf "Sumatra PDF"))))
)
(when (not (eq system-type 'windows-nt))
;; Use pdf-tools to open PDF files
(setq TeX-view-program-selection '((output-pdf "PDF Tools"))
TeX-source-correlate-start-server t)
;; Update PDF buffers after successful LaTeX runs
(add-hook 'TeX-after-compilation-finished-functions
#'TeX-revert-document-buffer)
)
;; set up engines
(setq TeX-engine-alist
'(
(xetex "XeTeX"
"xetex --file-line-error"
"xelatex --file-line-error"
"xetex")
(xetex_sh "XeTeX shell escape"
"xetex --file-line-error --shell-escape"
"xelatex --file-line-error --shell-escape"
"xetex")))
;; make LaTeXmk default
(use-package auctex-latexmk
:ensure t
:config
(auctex-latexmk-setup)
(setq auctex-latexmk-inherit-TeX-PDF-mode t)
(setq TeX-command-force "LatexMk") ; remember to set path variable accordingly!
)
:config
;; font keys
(defun TeX-italic()
(interactive)
(TeX-font nil ?\C-i))
(defun TeX-bold()
(interactive)
(TeX-font nil ?\C-b))
(defun TeX-typewriter()
(interactive)
(TeX-font nil ?\C-t))
(defun TeX-emphasis()
(interactive)
(TeX-font nil ?\C-e))
(defun TeX-smallcaps()
(interactive)
(TeX-font nil ?\C-c))
(defun TeX-italic-replace()
(interactive)
(TeX-font t ?\C-i))
(defun TeX-bold-replace()
(interactive)
(TeX-font t ?\C-b))
(defun TeX-typewriter-replace()
(interactive)
(TeX-font t ?\C-t))
(defun TeX-emphasis-replace()
(interactive)
(TeX-font t ?\C-e))
(defun TeX-smallcaps-replace()
(interactive)
(TeX-font t ?\C-c))
(defun TeX-deletefont()
(interactive)
(TeX-font nil ?\C-d))
(define-key LaTeX-mode-map (kbd "C-c C-f i") 'TeX-italic)
(define-key LaTeX-mode-map (kbd "C-c C-f b") 'TeX-bold)
(define-key LaTeX-mode-map (kbd "C-c C-f t") 'TeX-typewriter)
(define-key LaTeX-mode-map (kbd "C-c C-f e") 'TeX-emphasis)
(define-key LaTeX-mode-map (kbd "C-c C-f s") 'TeX-smallcaps)
(define-key LaTeX-mode-map (kbd "C-c C-f c") 'TeX-smallcaps)
(define-key LaTeX-mode-map (kbd "C-c C-f d") 'TeX-deletefont)
(define-key LaTeX-mode-map (kbd "C-c C-f DEL") 'TeX-deletefont)
(define-key LaTeX-mode-map (kbd "C-c f i") 'TeX-italic)
(define-key LaTeX-mode-map (kbd "C-c f b") 'TeX-bold)
(define-key LaTeX-mode-map (kbd "C-c f t") 'TeX-typewriter)
(define-key LaTeX-mode-map (kbd "C-c f e") 'TeX-emphasis)
(define-key LaTeX-mode-map (kbd "C-c f s") 'TeX-smallcaps)
(define-key LaTeX-mode-map (kbd "C-c f c") 'TeX-smallcaps)
(define-key LaTeX-mode-map (kbd "C-c f d") 'TeX-deletefont)
(define-key LaTeX-mode-map (kbd "C-c f DEL") 'TeX-deletefont)
(define-key LaTeX-mode-map (kbd "C-c C-f ! i") 'TeX-italic-replace)
(define-key LaTeX-mode-map (kbd "C-c C-f ! b") 'TeX-bold-replace)
(define-key LaTeX-mode-map (kbd "C-c C-f ! t") 'TeX-typewriter-replace)
(define-key LaTeX-mode-map (kbd "C-c C-f ! e") 'TeX-emphasis-replace)
(define-key LaTeX-mode-map (kbd "C-c C-f ! s") 'TeX-smallcaps-replace)
(define-key LaTeX-mode-map (kbd "C-c C-f ! c") 'TeX-smallcaps-replace)
(define-key LaTeX-mode-map (kbd "C-c f ! i") 'TeX-italic-replace)
(define-key LaTeX-mode-map (kbd "C-c f ! b") 'TeX-bold-replace)
(define-key LaTeX-mode-map (kbd "C-c f ! t") 'TeX-typewriter-replace)
(define-key LaTeX-mode-map (kbd "C-c f ! e") 'TeX-emphasis-replace)
(define-key LaTeX-mode-map (kbd "C-c f ! s") 'TeX-smallcaps-replace)
(define-key LaTeX-mode-map (kbd "C-c f ! c") 'TeX-smallcaps-replace)
;; activate folding
(add-hook 'LaTeX-mode-hook (lambda ()
(TeX-fold-mode 1)
;; (TeX-fold-buffer)
))
;; folding behavior for environments
(custom-set-variables '(TeX-fold-env-spec-list
'(("[comment]" ("comment"))
("[figure]" ("figure"))
("[tikz]" ("tikzpicture")))))
:bind (:map LaTeX-mode-map
;; ("C-l C-q" . align-current) ; useful command to align arrays
;; ("C-l H-i" . align-current) ; useful command to align arrays
;; keys for error browsing (disabled; see hydra settings)
;; ("<f4>" . TeX-next-error)
;; ("S-<f4>" . TeX-previous-error)
;; ("C-<f4>" . TeX-error-overview)
;; miscellaneous keys
("C-c <backspace>" . TeX-clean)
("C-<return>" . LaTeX-close-environment)
;; goto keys
("C-c {" . LaTeX-find-matching-begin)
("C-c }" . LaTeX-find-matching-end)
;; ("C-c C-l" . (lambda () (interactive) ())) ;FIXME
)
)
Autocompletion: see company.
https://www.gnu.org/software/auctex/reftex.html
- [ ] Issue:
\section
,\frametitle
etc. are not shown in TOC when not being line-inital or preceded by whitespaces. - [ ] Issue:
\begin{frame}
ist not recognized.
(use-package reftex
:diminish reftex-mode
:init
(add-hook 'latex-mode-hook 'turn-on-reftex)
(add-hook 'LaTeX-mode-hook 'turn-on-reftex)
(setq reftex-plug-into-AUCTeX t
;; reftex-ref-style-default-list '("Cleveref" "Hyperref" "Fancyref")
;; reftex-toc-split-windows-horizontally t
reftex-ref-macro-prompt nil ; go straight to the labels when referencing
reftex-bibliography-commands '("bibliography" "nobibliography" "addbibresource")
reftex-default-bibliography (list user-bibliography-file)
)
;; add frametitle to TOC
(setq reftex-section-levels '(("part" . 0)
("chapter" . 1)
("section" . 2)
("subsection" . 3)
("subsubsection" . 4)
("frametitle" . -3)
("paragraph" . 5)
("subparagraph" . 6)
("addchap" . -1)
("addsec" . -2)))
;; connect reftex to imenu
;; (add-hook 'reftex-load-hook 'imenu-add-menubar-index) ; Error: imenu unavailable: "The mode ‘Fundamental’ does not support Imenu"
(add-hook 'reftex-mode-hook 'imenu-add-menubar-index)
;; isearch across files
(add-hook 'reftex-mode-hook (lambda () (reftex-isearch-minor-mode)))
:config
;; jumping around like in org-mode
(define-key LaTeX-mode-map (kbd "C-c C-j") 'tl/reftex-in-follow-mode)
(define-key LaTeX-mode-map (kbd "C-n") 'tl/reftex-next)
(define-key LaTeX-mode-map (kbd "C-p") 'tl/reftex-previous)
(defun tl/reftex-in-follow-mode()
(interactive)
(setq reftex-toc-follow-mode t)
(reftex-toc))
(defun tl/reftex-next ()
(interactive)
(next-line) ; no clue why this is necessary
(tl/reftex-in-follow-mode)
(reftex-toc-next)
(reftex-toc-goto-line-and-hide)
(recenter))
(defun tl/reftex-previous ()
(interactive)
(next-line) ; no clue why this is necessary
(tl/reftex-in-follow-mode)
(reftex-toc-previous)
(reftex-toc-goto-line-and-hide)
(recenter))
:bind (:map LaTeX-mode-map
("C-c ]" . reftex-citation); same as in org-mode
)
)
Autocompletion: see *company.
http://www.jonathanleroux.org/bibtex-mode.html
(setq bibtex-dialect 'biblatex)
Align at equal sign instead of field text:
(setq bibtex-align-at-equal-sign t)
Formatting:
(setq bibtex-field-indentation 2
bibtex-text-indentation 14
bibtex-contline-indentation 15)
(add-hook 'bibtex-mode-hook (lambda () (set-fill-column 999))) ; don't fill column
Cleaning actions:
(setq bibtex-entry-format
'(opts-or-alts ; delete empty optional and alternative fields
;; required-fields ; signal an error if a required field is missing.
numerical-fields ; delete delimiters around numeral fields
inherit-booktitle ; insert booktitle if it is in the crossref
realign ; realign entries
last-comma ; add or delete last comma
delimiters ; change delimiters
unify-case ; change case of entry types and field names
sort-fields
))
Key generation:
(setq
;; name part
bibtex-autokey-names 1 ; maximal number of names used
bibtex-autokey-names-stretch 1 ; additionally used names, if then all names are used
bibtex-autokey-preserve-case t ; probably deprecatedd; instead use bibtex-autokey-name-case-convert
bibtex-autokey-name-case-convert 'identity
bibtex-autokey-name-separator ":"
bibtex-autokey-additional-names ":etal"
;; year part
bibtex-autokey-year-length 2 ; size of year part (from the right)
bibtex-autokey-name-year-separator ":"
bibtex-autokey-year-use-crossref-entry t ; use year from crossref (depends on bibtex-maintain-sorted-entries)
;; title part
bibtex-autokey-year-title-separator "-"
bibtex-autokey-titleword-length 20 ; max. number of used characters from title words
bibtex-autokey-titlewords 5 ; max. number of used title words
bibtex-autokey-titleword-case-convert-function 'downcase
)
Sorting entries:
(setq bibtex-maintain-sorted-entries t)
Taken from http://www.anghyflawn.net/blog/2014/emacs-give-a-doi-get-a-bibtex-entry/:
(defun get-bibtex-from-doi (doi)
"Get a BibTeX entry from the DOI"
(interactive "MDOI: ")
(let ((url-mime-accept-string "text/bibliography;style=bibtex"))
(with-current-buffer
(url-retrieve-synchronously
(format "http://dx.doi.org/%s"
(replace-regexp-in-string "http://dx.doi.org/" "" doi)))
(switch-to-buffer (current-buffer))
(goto-char (point-max))
(setq bibtex-entry
(buffer-substring
(string-match "@" (buffer-string))
(point)))
(kill-buffer (current-buffer))))
(insert (decode-coding-string bibtex-entry 'utf-8))
(bibtex-fill-entry))
Function to add timestamp:
(defun tl/bibtex-add-timestamp ()
(interactive)
(bibtex-set-field "timestamp" (format-time-string "%Y-%m-%d" (current-time)))
)
Use bibtex-entry
when inserting entry templates:
(define-key bibtex-mode-map (kbd "C-c C-e") 'bibtex-entry)
Documentation of bibtex-entry-field-alist
:
Alist of BibTeX entry types and their associated fields. Elements are lists (ENTRY-TYPE DOC REQUIRED CROSSREF OPTIONAL). ENTRY-TYPE is the type of a BibTeX entry. DOC is a brief doc string used for menus. If nil ENTRY-TYPE is used. REQUIRED is a list of required fields. CROSSREF is a list of fields that are optional if a crossref field is present; but these fields are required otherwise. OPTIONAL is a list of optional fields.
Each element of these lists is a list of the form (FIELD COMMENT INIT ALTERNATIVE). COMMENT, INIT, and ALTERNATIVE are optional.
FIELD is the name of the field. COMMENT is the comment string that appears in the echo area. If COMMENT is nil use ‘bibtex-BibTeX-field-alist’ if possible. INIT is either the initial content of the field or a function, which is called to determine the initial content of the field. ALTERNATIVE if non-nil is an integer that numbers sets of alternatives, starting from zero.
See https://github.com/timmli/biblatex-muss
(defvar bibtex-muss-entry-alist
`(("Article" "Article in a journal"
;; required
(("author")
("title" "Title of the article (BibTeX converts it to lowercase)"))
;; required without crossref
(("journal")
("year"))
;; optional
(("volume" "Volume of the journal")
("number" "Number of the journal (only allowed if entry contains volume)")
("pages" "Pages in the journal")
("url")
("doi")
("timestamp" nil ,(format-time-string "%Y-%m-%d" (current-time)))
("note")))
("Book" "A book with one or more authors where the authors share credit for the work as a whole"
;; required
(("author")
("title")
("year")
("doi" nil nil 1)
("url" nil nil 1)
("publisher" nil nil 1)
)
;; required without crossref
nil
;; optional
(("volume" "Volume of the book in the series")
("number" "Number of the book in a small series (overwritten by volume)")
("series" "Series in which the book appeared")
("edition" "Edition of the book as a capitalized English word")
("timestamp" nil ,(format-time-string "%Y-%m-%d" (current-time)))
("note")))
("Collection" "A collection with multiple, self-contained contributions by distinct authors which have their own title"
;; required
(("editor")
("booktitle")
("year")
("doi" nil nil 1)
("url" nil nil 1)
("publisher" nil nil 1))
;; required without crossref
nil
;; optional
(("volume" "Volume of the book in the series")
("number" "Number of the book in a small series (overwritten by volume)")
("series" "Series in which the book appeared")
("edition" "Edition of the book as a capitalized English word")
("timestamp" nil ,(format-time-string "%Y-%m-%d" (current-time)))
("note")))
("Proceedings" "Conference Proceedings"
;; required
(("booktitle")
("year")
("doi" nil nil 1)
("url" nil nil 1)
("publisher" nil nil 1))
;; required without crossref
nil
;; optional
(("editor")
("volume" "Volume of the conference proceedings in the series")
("number" "Number of the conference proceedings in a small series (overwritten by volume)")
("series" "Series in which the conference proceedings appeared")
("timestamp" nil ,(format-time-string "%Y-%m-%d" (current-time)))
("note")))
("InProceedings" "Paper in conference proceedings"
;; required
(("author")
("title" "Title of the paper")
("pages" "Pages in the conference proceedings")
)
;; required without crossref
(("booktitle" "Name of the paper")
("year")
("doi" nil nil 1)
("url" nil nil 1)
("publisher" nil nil 1))
;; optional
(("volume" "Volume of the conference proceedings in the series")
("number" "Number of the conference proceedings in a small series (overwritten by volume)")
("series" "Series in which the conference proceedings appeared")
("timestamp" nil ,(format-time-string "%Y-%m-%d" (current-time)))
("note")))
("InCollection" "Contribution in a collection"
;; required
(("author")
("title" "Title of the contribution")
("pages" "Pages in the collection"))
;; required without crossref
(("booktitle" "Title of the collection")
("editor")
("doi" nil nil 1)
("url" nil nil 1)
("publisher" nil nil 1)
("year"))
;; optional
(("volume" "Volume of the collection in the series")
("number" "Number of the collection in a small series (overwritten by volume)")
("series" "Series in which the collection appeared")
("timestamp" nil ,(format-time-string "%Y-%m-%d" (current-time)))
("note")))
("Thesis" "Thesis"
;; required
(("author")
("title" "Title of the thesis")
("type" "Type of the thesis")
("school" "School where the thesis was written" nil 1)
("institution" "Institution where the thesis was written" nil 1)
("year"))
;; required without crossref
nil
;; optional
(("url")
("doi")
("timestamp" nil ,(format-time-string "%Y-%m-%d" (current-time)))
("note")))
("PhDThesis" "PhD Thesis"
;; required
(("author")
("title" "Title of the thesis")
("type" "Type of the thesis")
("school" "School where the thesis was written" nil 1)
("institution" "Institution where the thesis was written" nil 1)
("year"))
;; required without crossref
nil
;; optional
(("url")
("doi")
("timestamp" nil ,(format-time-string "%Y-%m-%d" (current-time)))
("note")))
("Report" "Technical Report"
;; required
(("author")
("title" "Title of the technical report")
("year")
("type")
("institution"))
;; required without crossref
nil
;; optional
(("url")
("doi")
("timestamp" nil ,(format-time-string "%Y-%m-%d" (current-time)))
("note")))
("TechReport" "Technical Report"
;; required
(("author")
("title" "Title of the technical report")
("year")
("type")
("institution"))
;; required without crossref
nil
;; optional
(("url")
("doi")
("timestamp" nil ,(format-time-string "%Y-%m-%d" (current-time)))
("note")))
("Manual" "Manual"
;; required
(("title" "Title of the manual")
("author")
("year")
("url")
("urldate"))
;; required without crossref
nil
;; optional
(("doi")
("timestamp" nil ,(format-time-string "%Y-%m-%d" (current-time)))
("note")))
("Online" "Online resource"
;; required
(("title" "Title of the online resource")
("author")
("year")
("url")
("urldate"))
;; required without crossref
nil
;; optional
(("doi")
("timestamp" nil ,(format-time-string "%Y-%m-%d" (current-time)))
("note")))
)
"Entry types following the formatting rules of MUSS (https://github.com/timmli/biblatex-muss)."
)
Activate MUSS dialect:
(defvar bibtex-muss-field-alist bibtex-biblatex-field-alist)
(add-to-list 'bibtex-muss-field-alist '("timestamp" "Date of creation or modification of the entry."))
(add-to-list 'bibtex-dialect-list 'muss)
(setq bibtex-dialect 'muss)
https://github.com/tmalsburg/helm-bibtex
Search through your BibTeX bibliography with helm.
(use-package helm-bibtex
:ensure t
;; :after (org-citeproc org-ref) ; do not uncomment this
:pin MELPA
:config
;; Make sure that the most recent version of `bibtex-completion' is installed.
(use-package bibtex-completion
:ensure t
:pin MELPA)
(setq bibtex-completion-bibliography (list user-bibliography-file))
(setq bibtex-completion-additional-search-fields '(bibtexkey))
;; The standard function with modified default action
;; :bind (:map LaTeX-mode-map ("C-l C-r" . helm-bibtex-with-local-bibliography))
;; See https://github.com/tmalsburg/helm-bibtex#reverse-order-of-entries
(advice-add 'bibtex-completion-candidates :filter-return 'reverse)
(setq bibtex-completion-display-formats
'((t . "${author:36} ${title:*} ${year:4} ${=has-pdf=:1}${=has-note=:1} ${=type=:7}")))
<<helm-bibtex-csl>>
)
One can influence the order of actions in helm like this:
;; (helm-delete-action-from-source "Open PDF, URL or DOI" helm-source-bibtex)
;; (helm-delete-action-from-source "Open PDF file (if present)" helm-source-bibtex)
;; (helm-delete-action-from-source "Open URL or DOI in browser" helm-source-bibtex)
;; (helm-delete-action-from-source "Show entry" helm-source-bibtex)
;; (helm-add-action-to-source "Show entry"
;; 'bibtex-completion-show-entry
;; helm-source-bibtex 5)
;; (helm-add-action-to-source "Open PDF, URL or DOI"
;; 'bibtex-completion-open-any
;; helm-source-bibtex 6)
;; (helm-add-action-to-source "Open PDF file (if present)"
;; 'bibtex-completion-open-pdf
;; helm-source-bibtex 7)
;; (helm-add-action-to-source "Open URL or DOI in browser"
;; 'bibtex-completion-open-url-or-doi
;; helm-source-bibtex 8)
;; ;; Temporarily move "Show entry" to the first position of the action list when in bibtex-mode
;; (defun tl/promote_show_entry (&optional arg local-bib)
;; (helm-delete-action-from-source "Show entry" helm-source-bibtex)
;; (helm-add-action-to-source "Show entry"
;; 'bibtex-completion-show-entry
;; helm-source-bibtex 0))
;; (defun tl/demote_show_entry (&optional arg local-bib)
;; (helm-delete-action-from-source "Show entry" helm-source-bibtex)
;; (helm-add-action-to-source "Show entry"
;; 'bibtex-completion-show-entry
;; helm-source-bibtex 5))
;; (defun tl/helm-bibtex-in-bibtex-mode ()
;; (interactive)
;; (tl/promote_show_entry)
;; (helm-bibtex)
;; (tl/demote_show_entry))
;; (define-key bibtex-mode-map (kbd "C-c h") 'tl/helm-bibtex-in-bibtex-mode)
;; (define-key bibtex-mode-map (kbd "C-c C-h") 'tl/helm-bibtex-in-bibtex-mode)
Support for CSL, see tmalsburg/helm-bibtex#235 (comment).
(defvar helm-bibtex-csl-style "~/.emacs.d/csl/minimal-unified-style-sheet-for-computational-linguistics.csl")
(defvar helm-bibtex-csl-locale-dir "~/.emacs.d/csl")
(defun helm-bibtex-insert-citeproc-reference (_candidate)
(let* ((locale-getter (citeproc-locale-getter-from-dir helm-bibtex-csl-locale-dir))
(item-getter (citeproc-itemgetter-from-bibtex helm-bibtex-bibliography))
(proc (citeproc-create helm-bibtex-csl-style item-getter locale-getter))
(cites (mapcar (lambda (x) (citeproc-citation-create :cites `(((id . ,x)))))
(helm-marked-candidates))))
(citeproc-append-citations cites proc)
(insert (car (citeproc-render-bib proc 'plain)))))
(helm-add-action-to-source "Insert citeproc-formatted reference" 'helm-bibtex-insert-citeproc-reference helm-source-bibtex)
- Note taken on [2017-11-13 Mo 10:07]
Add\begin{frame}
to outline (and imenu):(add-to-list 'TeX-outline-extra '("\\\\begin{frame}\\(\\[.*\\]\\)?" 4))
FIXME: Does not show the title.
Add \frametitle
to outline (and imenu):
(add-to-list 'TeX-outline-extra '("\\\\frametitle\\b" 4))
Make square brackets indent correctly (testing):
;; (modify-syntax-entry ?\[ "(]" LaTeX-mode-syntax-table)
;; (modify-syntax-entry ?\] ")[" LaTeX-mode-syntax-table)
;; Proposed by https://emacs.stackexchange.com/a/35507/12336
;; Overwrites TeX-brace-count-line from tex.el
(defun TeX-brace-count-line ()
"Count number of open/closed braces."
(save-excursion
(let ((count 0) (limit (line-end-position)) char)
(while (progn
(skip-chars-forward "^{}[]\\\\" limit)
(when (and (< (point) limit) (not (TeX-in-comment)))
(setq char (char-after))
(forward-char)
(cond ((eq char ?\{)
(setq count (+ count TeX-brace-indent-level)))
((eq char ?\})
(setq count (- count TeX-brace-indent-level)))
((eq char ?\[)
(setq count (+ count TeX-brace-indent-level)))
((eq char ?\])
(setq count (- count TeX-brace-indent-level)))
((eq char ?\\)
(when (< (point) limit)
(forward-char)
t))))))
count)))
Delete macro at point (http://emacs.stackexchange.com/a/7997/12336):
(defun TeX-delete-macro ()
"Remove current macro and return `t'. If no macro at point,
return `nil'."
(interactive)
(when (TeX-current-macro)
(let ((bounds (TeX-find-macro-boundaries))
(brace (save-excursion
(goto-char (1- (TeX-find-macro-end)))
(TeX-find-opening-brace))))
(delete-region (1- (cdr bounds)) (cdr bounds))
(delete-region (car bounds) (1+ brace)))
t))
Delete environment at point (https://www.reddit.com/r/emacs/comments/5f99nv/help_with_auctex_how_to_delete_an_environment/dailbtu/):
(defun TeX-delete-environment ()
(interactive)
(when (LaTeX-current-environment)
(save-excursion
(let* ((begin-start (save-excursion
(LaTeX-find-matching-begin)
(point)))
(begin-end (save-excursion
(goto-char begin-start)
(search-forward-regexp "begin{.*?}")))
(end-end (save-excursion
(LaTeX-find-matching-end)
(point)))
(end-start (save-excursion
(goto-char end-end)
(1- (search-backward-regexp "\\end")))))
;; delete end first since if we delete begin first it shifts the
;; location of end
(delete-region end-start end-end)
(delete-region begin-start begin-end)))))
<tab> should always insert a tab (instead of indentation):
;; (add-hook 'LaTeX-mode-hook #'(lambda () (setq-local tab-always-indent nil)))
Usefull extras, e.g., org-mode-like folding:
(use-package latex-extra
:ensure t
:defer t
:config (add-hook 'LaTeX-mode-hook #'latex-extra-mode))
See *company.
https://jblevins.org/projects/markdown-mode/
Major mode for editing Markdown-formatted text.
(use-package markdown-mode
:ensure t
:commands (markdown-mode gfm-mode)
:mode (("README\\.md\\'" . gfm-mode)
("\\.md\\'" . markdown-mode)
("\\.markdown\\'" . markdown-mode))
:init (setq markdown-command "multimarkdown")
:config (setq markdown-enable-math t))
https://github.com/ardumont/markdown-toc
Insert TOC in a markdown file.
(use-package markdown-toc
:ensure t)
Depends on PlantUML and Gaphviz.
(use-package plantuml-mode
:ensure t
:mode ("\\.plu\\'" "\\.puml\\'")
:init
(setq org-plantuml-exec-mode 'plantuml
org-plantuml-jar-path "/usr/share/plantuml/plantuml.jar")
(when (eq system-type 'windows-nt)
(setq org-plantuml-jar-path
(expand-file-name "C:/ProgramData/chocolatey/lib/plantuml/tools/plantuml.jar"))
(setq plantuml-jar-path
(expand-file-name "C:/ProgramData/chocolatey/lib/plantuml/tools/plantuml.jar"))))
https://github.com/jorgenschaefer/elpy
Powerful environment for Python coding.
Prerequisites as for Python:
sudo pip install jedi flake8 importmagic autopep8 # Elpy's recommendation
sudo pip install pylint virtualenv epc # Zamansky's recommendation
(use-package elpy
:ensure t
:defer 2
:init
(elpy-enable)
:config
;; Use Flycheck instead of Flymake
(when (load "flycheck" t t)
(setq elpy-modules (delq 'elpy-module-flymake elpy-modules))
(add-hook 'elpy-mode-hook 'flycheck-mode))
;;;; Maybe outdated
;; (when (require 'flycheck nil t)
;; (remove-hook 'elpy-modules 'elpy-module-flymake)
;; (remove-hook 'elpy-modules 'elpy-module-yasnippet)
;; (remove-hook 'elpy-mode-hook 'elpy-module-highlight-indentation)
;; (add-hook 'elpy-mode-hook 'flycheck-mode))
(define-key python-mode-map (kbd "C-h f") 'python-eldoc-at-point)
;; highlight-indentation is ugly
(add-hook 'elpy-mode-hook #'(lambda () (highlight-indentation-mode -1)))
;; jedi is great
(setq elpy-rpc-backend "jedi")
;; tell elpy to use python3 (or install python-is-python3 under GNU/Linux)
(setq elpy-rpc-python-command "python3")
)
https://github.com/emacsorphanage/company-jedi
company-mode
completion back-end for Python JEDI.
Prerequisites as for Python:
sudo pip install jedi
;; Use Company for auto-completion interface.
(defun my/python-mode-hook ()
(add-to-list 'company-backends 'company-jedi))
(use-package company-jedi
:ensure t
:init
(add-hook 'python-mode-hook 'my/python-mode-hook))
Procedure to open a notebook:
- externally start Jupyter server
ein:notebooklist-login
and insert the token of the Jupyter session (see terminal)ein:notebooklist-open
and select the notebook
(use-package ein
:ensure t
:config
(setq ein:completion-backend 'ein:use-ac-jedi-backend))
The associated major modes is sh-mode
, for which shell-script-mode
is an alias.
Make script files (e.g. Bash scripts) with the hash-bang notation exectuable when saving them:
(add-hook 'after-save-hook
'executable-make-buffer-file-executable-if-script-p)
Fast incremental parsing of source code.
More general information:
Installation & configuration in Emacs:
List of available grammars, which can be installed with treesit-install-language-grammar
:
(setq treesit-language-source-alist
'((bash "https://github.com/tree-sitter/tree-sitter-bash")
(cmake "https://github.com/uyha/tree-sitter-cmake")
(css "https://github.com/tree-sitter/tree-sitter-css")
(elisp "https://github.com/Wilfred/tree-sitter-elisp")
(go "https://github.com/tree-sitter/tree-sitter-go")
(html "https://github.com/tree-sitter/tree-sitter-html")
(javascript "https://github.com/tree-sitter/tree-sitter-javascript" "master" "src")
(json "https://github.com/tree-sitter/tree-sitter-json")
(make "https://github.com/alemuller/tree-sitter-make")
(markdown "https://github.com/ikatyang/tree-sitter-markdown")
(python "https://github.com/tree-sitter/tree-sitter-python")
(toml "https://github.com/tree-sitter/tree-sitter-toml")
(tsx "https://github.com/tree-sitter/tree-sitter-typescript" "master" "tsx/src")
(typescript "https://github.com/tree-sitter/tree-sitter-typescript" "master" "typescript/src")
(yaml "https://github.com/ikatyang/tree-sitter-yaml")))
By convention, major modes that use Tree-Sitter have the infix -ts-
added to their name. Thankfully, Emacs 29 provides major-mode-remap-alist
to replace old major modes with new “major-ts-modes” under the hood:
(setq major-mode-remap-alist
'((yaml-mode . yaml-ts-mode)
(bash-mode . bash-ts-mode)
(js2-mode . js-ts-mode)
(typescript-mode . typescript-ts-mode)
(json-mode . json-ts-mode)
(css-mode . css-ts-mode)
(python-mode . python-ts-mode)))
However, as described in https://www.masteringemacs.org/article/how-to-get-started-tree-sitter, this still has some rough edges and seems to need more time to integrate properly into Emacs.
https://web-mode.org/ https://github.com/fxbois/web-mode
(use-package web-mode ; for improved html support
:ensure t
:mode
("\\.phtml\\'" . web-mode)
("\\.tpl\\'" . web-mode)
("\\.php\\'" . web-mode)
("\\.[agj]sp\\'" . web-mode)
("\\.as[cp]x\\'" . web-mode)
("\\.erb\\'" . web-mode)
("\\.mustache\\'" . web-mode)
("\\.djhtml\\'" . web-mode)
("\\.html?\\'" . web-mode)
("\\.xml\\'" . web-mode)
("\\.css\\'" . web-mode)
("\\.svg\\'" . web-mode)
:config
;; highlight enclosing tags of the element under cursor
(setq web-mode-enable-current-element-highlight t)
;; colorize CSS
(setq web-mode-enable-css-colorization t)
)
https://github.com/skeeto/impatient-mode
See the effect of your HTML as you type it.
(use-package impatient-mode
:ensure t)
Usage: when in a HTML buffer,
- call httpd-start & impatient-mode
- open your browser at http://localhost:8080/imp/
(require 'xmg-mode)
https://jblevins.org/projects/deft/
Quickly browsing, filtering, and editing directories of plain text notes.
(use-package deft ; for displaying list of note files
:ensure t
:bind
("<f9> o" . deft)
("<f9> d" . deft)
:commands (deft)
:config (setq deft-directory my-deft-dir
deft-extensions '("md" "org")
deft-recursive t
deft-use-filename-as-title t
deft-use-filter-string-for-filename t))
Dired is a powerful file browser in Emacs. Needless to say, with some tweaking, it has become my favourite file browser by far.
The following prevents Emacs from throwing Symbol's value as variable is void: dired-mode-map
:
(require 'dired)
Tips: http://ergoemacs.org/emacs/emacs_dired_tips.html
Open new buffer when opening a file/directory, if necessary:
;; (define-key dired-mode-map (kbd "<return>") 'dired-find-alternate-file) ; was dired-advertised-find-file
;; (define-key dired-mode-map (kbd "<backspace>") (lambda () (interactive) (find-alternate-file ".."))) ; find-alternate-file forgets the cursor position of the left dired buffer
;; (define-key dired-mode-map (kbd "<left>") (lambda () (interactive) (find-alternate-file "..")))
(define-key dired-mode-map (kbd "<left>") (lambda () (interactive) (diredp-up-directory)))
(define-key dired-mode-map (kbd "<backspace>") (lambda () (interactive) (diredp-up-directory)))
View file and return to dired with q:
(define-key dired-mode-map (kbd "<tab>") 'dired-view-file)
(define-key dired-mode-map (kbd "<right>") 'dired-view-file)
(add-hook 'view-mode-hook
(lambda ()
(define-key view-mode-map (kbd "<left>") 'View-quit)
(define-key view-mode-map (kbd "<right>") 'View-exit-and-edit)
))
Copy/move into other dired buffer:
(setq dired-dwim-target t)
Show details of files and directories:
(add-hook 'dired-mode-hook
(lambda () (dired-hide-details-mode -1)))
Don’t break lines:
(add-hook 'dired-initial-position-hook #'(lambda () (setq truncate-lines t)))
;; (add-hook 'dired-mode-hook (lambda () (setq truncate-lines t)))
Order directories first (only windows?):
(setq ls-lisp-dirs-first t)
Ignore case when sorting:
(setq ls-lisp-ignore-case t)
Other settings: http://oremacs.com/2015/01/13/dired-options/
(setq dired-listing-switches "-laGh1v --group-directories-first") ; --group-directories-first is only supported by recent versions of ls.
Specify ls program: https://www.gnu.org/software/emacs/manual/html_node/efaq-w32/Dired-ls.html
(setq ls-lisp-use-insert-directory-program t) ; use external ls
;; (setq insert-directory-program "c:/tools/cygwin/bin/ls") ; path to ls program
Chose Windows drives:
(when (eq system-type 'windows-nt)
(define-key dired-mode-map (kbd "\\") 'diredp-w32-drives))
Move to trash can (recycle bin under windows) when deleting:
(setq delete-by-moving-to-trash t)
<mouse-1> opens file/directory in the same window:
(define-key dired-mode-map (kbd "<mouse-2>") 'dired-mouse-find-file)
Use shift-up and shift-down in the usual way. See http://emacs.stackexchange.com/a/30890/12336
(defun my-dired-toggle (arg)
(save-restriction
(narrow-to-region (point-at-bol) (point-at-eol))
(dired-toggle-marks))
(dired-previous-line arg))
(defun my-dired-mark-up ()
(interactive)
(my-dired-toggle 1))
(defun my-dired-mark-down ()
(interactive)
(my-dired-toggle -1))
(define-key dired-mode-map (kbd "<S-up>") 'my-dired-mark-up)
(define-key dired-mode-map (kbd "<S-down>") 'my-dired-mark-down)
https://github.com/FrostyX/dired-open-with
Select external program to open a file.
(use-package dired-open-with
:load-path "lisp/"
;; :ensure t
)
(define-key dired-mode-map (kbd "C-<return>") 'dired-open-with)
(defun xah-open-in-external-app (&optional @fname)
"Open the current file or dired marked files in external app.
The app is chosen from your OS's preference.
When called in emacs lisp, if @fname is given, open that.
URL `http://ergoemacs.org/emacs/emacs_dired_open_file_in_ext_apps.html'
Version 2019-11-04"
(interactive)
(let* (
($file-list
(if @fname
(progn (list @fname))
(if (string-equal major-mode "dired-mode")
(dired-get-marked-files)
(list (buffer-file-name)))))
($do-it-p (if (<= (length $file-list) 5)
t
(y-or-n-p "Open more than 5 files? "))))
(when $do-it-p
(cond
((string-equal system-type "windows-nt")
(mapc
(lambda ($fpath)
(w32-shell-execute "open" $fpath)) $file-list))
((string-equal system-type "darwin")
(mapc
(lambda ($fpath)
(shell-command
(concat "open " (shell-quote-argument $fpath)))) $file-list))
((string-equal system-type "gnu/linux")
(mapc
(lambda ($fpath) (let ((process-connection-type nil))
(start-process "" nil "xdg-open" $fpath))) $file-list))))))
;; (define-key dired-mode-map (kbd "C-<return>") 'xah-open-in-external-app)
Duplicate file at point while changing the file name.
(defun tl/dired-duplicate-this-file ()
"Duplicate file on this line.
Taken from https://emacs.stackexchange.com/a/60663/12336."
(interactive)
(let* ((this (dired-get-filename t))
(ctr 1)
(new (format "%s[%d]" this ctr)))
(while (file-exists-p new)
(setq ctr (1+ ctr)
new (format "%s[%d]" this ctr)))
(dired-copy-file this new nil))
(revert-buffer))
Sometimes its useful to copy the path of a file or directory under cursor:
(defun tl/dired-copy-path-at-point ()
(interactive)
(dired-copy-filename-as-kill 0)
)
(define-key dired-mode-map (kbd "W") 'tl/dired-copy-path-at-point)
Delete with <delete> key.
(define-key dired-mode-map (kbd "<delete>") 'dired-do-delete)
(use-package dired-imenu
:ensure t
:init
(require 'dired-imenu)
)
https://github.com/emacsorphanage/dired-k
Enrich dired buffer with git information.
(use-package dired-k
:ensure t
:bind (:map dired-mode-map ("K" . dired-k))
:config
(progn
;; FIXME: Tramp prompts for the password in every new dired buffer!
;; (add-hook 'dired-initial-position-hook 'dired-k)
;; (add-hook 'dired-after-readin-hook #'dired-k-no-revert)
))
https://github.com/10sr/git-ps1-mode-el
Show git branch in modeline.
(use-package git-ps1-mode
:ensure t
:pin MELPA
:config
(git-ps1-mode t))
https://gitlab.com/xuhdev/dired-quick-sort
Depends on ls
, the version of which should support --group-directories-first
.
Activated in dired
with <S-s>.
(use-package dired-quick-sort
:ensure t
:init
(require 'dired-quick-sort)
(dired-quick-sort-setup)
)
https://www.emacswiki.org/emacs/DiredPlus
Downloaded from here: https://github.com/emacsmirror/emacswiki.org/blob/master/dired%2b.el
(use-package dired+
:config
(require 'dired+)
(setq diredp-hide-details-initially-flag nil)
(set-face-foreground 'diredp-file-name nil)
;; Keep dired buffers updated when the file system changes.
(setq global-auto-revert-non-file-buffers t)
(setq auto-revert-verbose nil)
(define-key dired-mode-map (kbd "<mouse-2>") 'dired-mouse-find-file) ; Just a reminder for dired+ ;-)
)
Several helper packages for dired. See documentation here: https://github.com/Fuco1/dired-hacks
Filter dired list on the fly:
(use-package dired-narrow
:ensure t
:bind (:map dired-mode-map
("/" . dired-narrow)
:map dired-narrow-map
("<tab>" . dired-narrow-enter-directory)
("<right>" . dired-view-file)
("<return>" . exit-minibuffer))
:config
(setq dired-narrow-exit-action 'dired-narrow-find-file)
)
More customizable highlightning in dired listings. Settings inspired by
- https://github.com/Fuco1/.emacs.d/blob/master/files/dired-defs.el
- https://github.com/Fuco1/dired-hacks#dired-rainbow
(defconst my-dired-media-files-extensions '("mp3" "mp4" "MP3" "MP4" "avi" "mpg" "flv" "ogg" "wmv" "mkv" "mov" "wma")
"Media file extensions that should launch in VLC.
Also used for highlighting.")
(use-package dired-rainbow
:ensure t
:config
(progn
(dired-rainbow-define html "#4e9a06" ("htm" "html" "xhtml"))
(dired-rainbow-define xml "#b4fa70" ("xml" "xsd" "xsl" "xslt" "wsdl"))
(dired-rainbow-define document "#fce94f" ("doc" "docx" "odt" "pdb" "pdf" "ps" "rtf" "djvu" "epub"))
(dired-rainbow-define excel "#3465a4" ("xlsx"))
(dired-rainbow-define media "#ce5c00" my-dired-media-files-extensions)
(dired-rainbow-define image "#ff4b4b" ("jpg" "png" "jpeg" "gif"))
(dired-rainbow-define log "#c17d11" ("log"))
(dired-rainbow-define sourcefile "#fcaf3e" ("py" "c" "cc" "h" "java" "pl" "rb" "R" "php"))
(dired-rainbow-define executable "#8cc4ff" ("exe" "msi"))
(dired-rainbow-define compressed "#ad7fa8" ("zip" "bz2" "tgz" "txz" "gz" "xz" "z" "Z" "jar" "war" "ear" "rar" "sar" "xpi" "apk" "xz" "tar"))
(dired-rainbow-define packaged "#e6a8df" ("deb" "rpm"))
(dired-rainbow-define encrypted "LightBlue" ("gpg" "pgp"))
(dired-rainbow-define-chmod executable-unix "Green" "-.*x.*")
))
https://github.com/Fuco1/dired-hacks#dired-ranger
Adds conventional copy & paste behaviour to dired
.
See blog post at http://pragmaticemacs.com/emacs/copy-and-paste-files-with-dired-ranger/.
(use-package dired-ranger
:ensure t
:config
(setq dired-ranger-copy-ring-size 1)
(define-key dired-mode-map (kbd "C-w")
(lambda ()
(interactive)
(dired-ranger-copy nil) ; t adds item to dired-ranger-copy-ring
(define-key dired-mode-map (kbd "C-y") 'dired-ranger-move)))
(define-key dired-mode-map (kbd "M-w")
(lambda ()
(interactive)
(dired-ranger-copy nil)
(define-key dired-mode-map (kbd "C-y") 'dired-ranger-paste)))
)
Show whole path to contained file or directory if there is only one.
See https://github.com/Fuco1/dired-hacks#dired-collapse.
(use-package dired-collapse
:ensure t
:init
(add-hook 'dired-mode-hook #'dired-collapse-mode))
Rename file name at point.
(use-package dired-efap
:ensure t
:config
(setq dired-efap-initial-filename-selection nil)
(define-key dired-mode-map (kbd "r") 'dired-efap)
)
Quick ediff on marked files. Copied from https://oremacs.com/2017/03/18/dired-ediff/:
(defun ora-ediff-files ()
(interactive)
(let ((files (dired-get-marked-files))
(wnd (current-window-configuration)))
(if (<= (length files) 2)
(let ((file1 (car files))
(file2 (if (cdr files)
(cadr files)
(read-file-name
"file: "
(dired-dwim-target-directory)))))
(if (file-newer-than-file-p file1 file2)
(ediff-files file2 file1)
(ediff-files file1 file2))
(add-hook 'ediff-after-quit-hook-internal
(lambda ()
(setq ediff-after-quit-hook-internal nil)
(set-window-configuration wnd))))
(error "no more than 2 files should be marked"))))
(define-key dired-mode-map "e" 'ora-ediff-files)
https://github.com/ShuguangSun/diffpdf.el
Use diffpdf
in dired
.
(use-package diffpdf
:ensure t)
https://github.com/justbur/emacs-vdiff
Vimdiff for Emacs.
(use-package vdiff
:ensure t
:pin MELPA
:config
(setq vdiff-auto-refine t) ; If non-nil, automatically refine all hunks.
)
Integrate imenu into dired. Copied from https://fuco1.github.io/2017-05-01-Support-for-imenu-in-dired.html
(defun my-dired-imenu-prev-index-position (&optional arg)
"Go to the header line of previous directory."
(interactive "p")
(unless (= (line-number-at-pos) 1)
(call-interactively 'dired-prev-subdir)
t))
(defun my-dired-extract-index-name ()
"Extract name of the current item for imenu."
(save-excursion
(back-to-indentation)
(buffer-substring-no-properties
(point)
(1- (re-search-forward ":$")))))
(defun my-dired-imenu-create-index ()
"Create `imenu' index for dired."
(let* ((alist (imenu-default-create-index-function))
(uniquified (f-uniquify-alist (-map 'car alist))))
(--remove
(= 0 (length (car it)))
(--map (cons (cdr (assoc (car it) uniquified)) (cdr it))
alist))))
(defun my-dired-imenu-init ()
"Initialize `imenu' variables in current buffer."
(setq-local imenu-prev-index-position-function
'my-dired-imenu-prev-index-position)
(setq-local imenu-extract-index-name-function
'my-dired-extract-index-name)
(setq-local imenu-create-index-function
'my-dired-imenu-create-index))
(add-hook 'dired-mode-hook 'my-dired-imenu-init)
- [ ] I would like to be able to browse the dired history.
helm-dired-history
could be useful for this, but I don’t know how to use it to this end.
Calculates the size of marked directories using du
.
Copied from https://oremacs.com/2015/01/12/dired-file-size/ and slightly adapted.
(defun dired-get-size ()
"Print size of marked files or directories using shell command `du'."
(interactive)
(let ((files (dired-get-marked-files)))
(with-temp-buffer
(apply 'call-process "du" nil t nil "-sch" files)
(message
"Size of all marked files: %s"
(progn
(re-search-backward "\\(^[ 0-9.,]+\\([A-Za-z]+\\)?\\).*total$")
(match-string 1))))))
(define-key dired-mode-map (kbd "z") 'dired-get-size)
https://gitlab.com/ambrevar/emacs-disk-usage
A file system analyzer similar to ncdu. However, I prefer using the latter.
(use-package disk-usage
:load-path "lisp/disk-usage/")
https://codeberg.org/fourier/ztree
Show folder structure as foldable tree, also allowing for diffs on folders with ztree-diff
.
(use-package ztree
:ensure t)
https://github.com/TatriX/pomidor/
Pomidor brings the Pomodoro technique to Emacs.
(use-package pomidor
:ensure t
:init
(setq pomidor-sound-tick nil
pomidor-sound-tack nil
pomidor-sound-overwork t)
)
GNU Typist: An interactive typing tutor https://www.gnu.org/software/gtypist/doc/gtypist.html
There seems to be a mode for Emacs: https://www.gnu.org/software/gtypist/doc/gtypist.html#Emacs-mode
Functions to extract email addresses from strings and buffers:
(defun tl/extract-email-addresses-in-buffer (&optional separator)
"Extract email addresses from current buffer and return them as string mit SEPARATOR."
(or (stringp separator)
(setq separator ", "))
(save-excursion
(goto-char (point-min))
(let ((email-list '()))
(while (search-forward "@" nil t)
(let ((email (thing-at-point 'email)))
(when email
(setq email-list (cons email email-list)))))
(setq email-list (sort email-list 'string<))
(mapconcat 'identity email-list separator))))
(defun tl/extract-email-addresses-from-string (string &optional separator)
"Extract email addresses from STRING and return them as string mit SEPARATOR."
(with-temp-buffer
(insert string)
(goto-char (point-min))
(tl/extract-email-addresses-in-buffer separator)))
(defun tl/insert-string-to-new-buffer (string)
"Insert STRING into new buffer and go to this buffer."
(let ((new-buffer (generate-new-buffer "*temp*")))
(switch-to-buffer new-buffer)
(insert string)
(goto-char (point-min))))
;; Usage:
;; (tl/insert-string-to-new-buffer (tl/extract-email-addresses-in-buffer "\n"))
The Exteditor plugin can be used in Thunderbird in order to open and edit an email in Emacs.
Open eml-files with org-mode
turned on:
(add-to-list 'auto-mode-alist '("\\.eml\\'" . org-mode))
https://www.djcbsoftware.nl/code/mu/mu4e/index.html https://github.com/djcb/mu
Mu4e is an email client for Emacs that uses mu, which constructs a Xapian database for emails in the Maildir format for faster search.
Note that it is recommended to use the version of mu4e that is shipped together with the installed mu. Currently supported version: 1.12.x
Mu4e and Mu do not synchronize local and remote mailboxes. Below I’m assuming that mbsync is used for this purpose. (A popular alternative might be offlineimap.) The following tutorial gives an idea how to set up mbsync:
Good examples of elaborate mu4e configurations:
- https://config.daviwil.com/mail
- https://github.com/munen/emacs.d/#mu4e
- https://github.com/rougier/dotemacs/blob/master/dotemacs.org#mail
Email workflow with org-capture:
(add-to-list 'load-path (expand-file-name "lisp/mu4e" user-emacs-directory))
(require 'mu4e)
;; Home of the Xapian index
;; Note that mu does not like to expand ~, as explained here:
;; https://github.com/djcb/mu/blob/release/1.10/NEWS.org#110-releases-on-march-26-2023
(setq mu4e-mu-home "/home/USER/.cache/mu")
;; Refresh rate of emails
(setq mu4e-update-interval (* 5 60))
;; Close mu4e without asking.
(setq mu4e-confirm-quit nil)
;; Set a sane ISO 8601 date format.
(setq mu4e-headers-date-format "%+4Y-%m-%d")
;; This allows for using 'helm' to select mailboxes
(setq mu4e-completing-read-function 'completing-read)
;; Mute index messages
(setq mu4e-hide-index-messages t)
;; Keybindings
(define-key mu4e-headers-mode-map (kbd "M") #'mu4e)
(define-key mu4e-view-mode-map (kbd "M") #'mu4e)
;; Default account on startup
(setq
mu4e-mu-home "~/.cache/mu" ; as of v1.4
;; mu4e-maildir "~/Maildir" ; deprecated in v1.4
mu4e-sent-folder "/Sent"
mu4e-drafts-folder "/Drafts"
mu4e-trash-folder "/Trash")
(setq mu4e-get-mail-command "mbsync -c ~/SOME_PATH/.mbsyncrc work"
mu4e-attachment-dir "~/Downloads" ; where to store attachments
)
;; Update mails every 5 minutes and in the background
(setq mu4e-update-interval (* 5 60))
(setq mu4e-index-update-in-background t)
;; Always sign outgoing emails
;; (setq mu4e-compose-crypto-reply-plain-policy 'sign)
Note that each mail account must be indexed by mu before it can be accessed with mu4e:
mu init --maildir=~/SOME_PATH/mbsyncmail/
mu index
Contexts are bundles of settings that can, for example, represent different mail accounts. Contexts are defined in mu4e-context
, see the manual for details: https://www.djcbsoftware.nl/code/mu/mu4e/What-are-contexts.html
The context can be chosen automatically or manually. This is controlled by the variables mu4e-context-policy
and compose-context-policy
. See the manual for more details: https://www.djcbsoftware.nl/code/mu/mu4e/Context-policies.html
(setq mu4e-context-policy 'ask
mu4e-compose-context-policy 'ask)
Here is an example (taken from https://www.djcbsoftware.nl/code/mu/mu4e/Contexts-example.html) for how contexts are specified:
(setq mu4e-contexts
`( ,(make-mu4e-context
:name "Private"
:enter-func (lambda () (mu4e-message "Entering Private context"))
:leave-func (lambda () (mu4e-message "Leaving Private context"))
;; we match based on the contact-fields of the message
:match-func (lambda (msg)
(when msg
(mu4e-message-contact-field-matches msg
:to "aliced@home.example.com")))
:vars '( ( user-mail-address . "aliced@home.example.com" )
( user-full-name . "Alice Derleth" )
( message-user-organization . "Homebase" )
( mu4e-compose-signature .
(concat
"Alice Derleth\n"
"Lauttasaari, Finland\n"))))
,(make-mu4e-context
:name "Work"
:enter-func (lambda () (mu4e-message "Switch to the Work context"))
;; no leave-func
;; we match based on the maildir of the message
;; this matches maildir /Arkham and its sub-directories
:match-func (lambda (msg)
(when msg
(string-match-p "^/Arkham" (mu4e-message-field msg :maildir))))
:vars '( ( user-mail-address . "aderleth@miskatonic.example.com" )
( user-full-name . "Alice Derleth" )
( message-user-organization . "Miskatonic University" )
( mu4e-compose-signature .
(concat
"Prof. Alice Derleth\n"
"Miskatonic University, Dept. of Occult Sciences\n"))))
,(make-mu4e-context
:name "Cycling"
:enter-func (lambda () (mu4e-message "Switch to the Cycling context"))
;; no leave-func
;; we match based on the maildir of the message; assume all
;; cycling-related messages go into the /cycling maildir
:match-func (lambda (msg)
(when msg
(string= (mu4e-message-field msg :maildir) "/cycling")))
:vars '( ( user-mail-address . "aderleth@example.com" )
( user-full-name . "AliceD" )
( mu4e-compose-signature . nil)))))
;; set `mu4e-context-policy` and `mu4e-compose-policy` to tweak when mu4e should
;; guess or ask the correct context, e.g.
;; start with the first (default) context;
;; default is to ask-if-none (ask when there's no context yet, and none match)
;; (setq mu4e-context-policy 'pick-first)
;; compose with the current context is no context matches;
;; default is to ask
;; (setq mu4e-compose-context-policy nil)
;; How to show messages / headers.
;; A symbol which is either:
;; * ‘horizontal’: split horizontally (headers on top)
;; * ‘vertical’: split vertically (headers on the left).
;; * ‘single-window’: view and headers in one window (mu4e will try not to
;; touch your window layout), main view in minibuffer
;; * anything else: don’t split (show either headers or messages,
;; not both)
(setq mu4e-split-view 'vertical)
(setq mu4e-headers-visible-lines 10)
(setq mu4e-headers-visible-columns 100)
;; Look of mail headers
;; The following is an attempt to truncate lines in mu4e-headers-mode.
(add-hook 'mu4e-headers-mode-hook
#'(lambda ()
(with-current-buffer "*mu4e-headers*"
(toggle-truncate-lines t))))
(add-hook 'mu4e-headers-found-hook
#'(lambda ()
(with-current-buffer "*mu4e-headers*"
(toggle-truncate-lines t))))
;; Change some text faces
(set-face-attribute 'mu4e-replied-face nil :inherit 'font-lock-function-name-face)
(set-face-attribute 'mu4e-forwarded-face nil :inherit 'mu4e-header-value-face)
(set-face-attribute 'mu4e-related-face nil :inherit 'font-lock-comment-face)
;; Columns shown
(setq mu4e-headers-fields '(
(:human-date . 12)
(:flags . 6)
;; (:mailing-list . 10)
(:from . 22)
(:to . 22)
(:subject . nil)))
Visible flags are listed in mu4e-headers-visible-flags
. Only a small subset of flags is needed since the other ones are redundant:
(setq mu4e-headers-visible-flags '(flagged attach encrypted list calendar))
Flag symbols can be easily changed. Let’s try something fancier, as proposed in mu4e-headers.el
:
(setq mu4e-headers-draft-mark '("D" . "💈")
mu4e-headers-flagged-mark '("F" . "📍")
mu4e-headers-new-mark '("N" . "🔥")
mu4e-headers-passed-mark '("P" . "❯")
mu4e-headers-replied-mark '("R" . "❮")
mu4e-headers-seen-mark '("S" . "☑")
mu4e-headers-trashed-mark '("T" . "💀")
mu4e-headers-attach-mark '("a" . "📎")
mu4e-headers-encrypted-mark '("x" . "🔒")
mu4e-headers-signed-mark '("s" . "🔑")
mu4e-headers-unread-mark '("u" . "⎕")
mu4e-headers-list-mark '("l" . "🔈")
mu4e-headers-personal-mark '("p" . "👨")
mu4e-headers-calendar-mark '("c" . "📅"))
Actions:
(setq mu4e-headers-actions
'(("capture message" . mu4e-action-capture-message)
("narrow to thread" . mu4e-action-show-thread)
("save email as file" . tl/mu4e-action-copy-message-file)))
Keys:
;; v1.12 standardly uses C-<tab> for folding threads.
(define-key mu4e-thread-mode-map (kbd "C-<tab>") nil)
;; Message viewer settings
;; (setq mu4e-view-use-old t) ; use Gnus; since v1.6
;; (setq mu4e-view-use-gnus t) ; deprecated in v1.6
;; show full addresses in view message (instead of just names)
;; toggle per name with M-RET
(setq mu4e-view-show-addresses t)
;; Customize header fields to show in mu4e-view. This only adds :bcc and :size.
(setq mu4e-view-fields '(:from :to :cc :bcc :subject :flags :date :maildir :mailing-list :tags :attachments :size :signature :decryption))
;; Show images inline
(setq mu4e-view-show-images t)
;; Allow fancy (Unicode) characters for marks/threads
(setq mu4e-use-fancy-chars t)
;; to view selected message in the browser, no signin, just html mail
;; (add-to-list 'mu4e-view-actions
;; '("ViewInBrowser" . mu4e-action-view-in-browser) t)
;; Automatic line breaks when reading mail.
;; Disabled for now, because visual-line-mode may be invoked by w, if needed.
;; (add-hook 'mu4e-view-mode-hook #'visual-line-mode)
Since v1.10, messages can be detached in mu4e-view-mode
. The following functions detaches a displayed message and opens it in new frame:
(defun tl/mu4e-detach-and-view-message-in-new-frame ()
(interactive)
(when (mu4e--view-mode-p)
(mu4e-view-detach)
(make-frame)
(view-buffer "*mu4e-headers*") ; Interestingly does not work with with-current-buffer
(keyboard-escape-quit)))
(define-key mu4e-view-mode-map "z" 'tl/mu4e-detach-and-view-message-in-new-frame)
Actions:
(setq mu4e-view-actions
'(("capture message" . mu4e-action-capture-message)
("view in browser" . mu4e-action-view-in-browser)
("xview in xwidget" . mu4e-action-view-in-xwidget)
("narrow to thread" . mu4e-action-show-thread)
("save email as file" . tl/mu4e-action-copy-message-file)))
The following code is taken from djcb/mu#2247 (comment). It depends on alterMIME.
(defun bjm/mime-part-filename (num)
"Filename of MIME part numbered num in gnus-article-mode."
;; Check whether the specified part exists.
(when (> num (length gnus-article-mime-handle-alist))
(error "No such part"))
;; Move point to MIME part
(when (gnus-article-goto-part num)
;; Get handle for MIME part at point
(let ((handle (get-text-property (point) 'gnus-data)))
(when handle
;; Return file name of handle
(mm-handle-filename handle)))))
(defun bjm/mu4e-delete-attachment (num)
"Remove email attachment from mu4e using altermime."
(let* ((path (mu4e-message-field (mu4e-message-at-point) :path))
(filename (bjm/mime-part-filename num))
(cmd (format "altermime --input='%s' --remove='%s' --xheader='X-Attachment-Removed: %s'" path filename filename)))
(when (and filename
(yes-or-no-p
(format "Remove '%s'?" filename)))
(shell-command cmd)
(mu4e-message cmd))))
;; get custom header field
(defun bjm/mu4e-fetch-field (msg hdr)
"Find the value for an arbitrary header field HDR from MSG."
(with-temp-buffer
(insert-file-contents (plist-get msg :path))
(message-fetch-field hdr)))
;; display attachmment removed field
(add-to-list 'mu4e-header-info-custom
'(:xremoved . (:name "X-Attachment-Removed"
:shortname "XAR"
:help "Name of attachment removed"
:function (lambda (msg) (or (bjm/mu4e-fetch-field msg "X-Attachment-Removed") "")))))
;; display this header field in message view
(add-to-list 'mu4e-view-fields :xremoved t)
(add-to-list 'mu4e-view-mime-part-actions
'(:name "delete-attachment"
:handler bjm/mu4e-delete-attachment
:receives index))
- State “TODO” from [2024-05-27 Mon 11:49]
- [ ] Adapt the Org heading generated for the event
- See function gnus-icalendar-event->org-entry (not yet customizable)
With the help of Gnus, iCalendar invitations can be viewed and replied to. Documentation: https://www.djcbsoftware.nl/code/mu/mu4e/iCalendar.html
(require 'mu4e-icalendar)
;; (mu4e-icalendar-setup) ; obsolete since around v1.12
(gnus-icalendar-setup)
Furthermore, with Gnus, one can convert iCalendar invitations to Org headings using the Org capture mechanism.
(setq gnus-icalendar-org-capture-file (expand-file-name "captures.org" org-directory))
(setq gnus-icalendar-org-capture-headline "Calendar")
Since the default template for Gnus captures does not work, I’m using the following one:
(add-to-list 'org-capture-templates
`("#" "used by gnus-icalendar-org" entry
(file+headline ,gnus-icalendar-org-capture-file
,gnus-icalendar-org-capture-headline)
"%i" :jump-to-captured t :prepend t)
)
Here is the one that Gnus would use otherwise:
("#" "used by gnus-icalendar-org" entry
(file+olp ,gnus-icalendar-org-capture-file
,gnus-icalendar-org-capture-headline)
"%i" :immediate-finish t)
Finally, activate the iCalendar-to-Org export:
(gnus-icalendar-org-setup)
- State “TODO” from [2024-05-02 Thu 23:12]
The variable gnus-mime-button-line-format
controls the text of Gnus buttons for attachments.
Valid specifiers include: %t The MIME type %T MIME type, along with additional info %n The ‘name’ parameter %d The description, if any %l The length of the encoded part %p The part identifier number %e Dots if the part isn’t displayed
The following changes the default look of buttons.
(setq gnus-mime-button-line-format "%{%([%p. \"%n\" – %t]%)%}%e
")
Since Gnus removes line breaks (which I want) with skip-chars-backward
when “buttonizing” attachments, the following disables skip-chars-backward
locally. Not optimal, but it works for now. See the discussion here: djcb/mu#1983
(defun tl/advice-gnus-mime-buttonize-attachments-in-header (orig-fun &rest args)
"Advice for `gnus-mime-buttonize-attachments-in-header` that locally disables `skip-chars-backward`."
(cl-letf (((symbol-function 'skip-chars-backward)
(lambda (&rest args) nil)))
(apply orig-fun args)))
(advice-add 'gnus-mime-buttonize-attachments-in-header
:around #'tl/advice-gnus-mime-buttonize-attachments-in-header)
(add-hook 'mu4e-compose-mode-hook
(defun my-mu4e-compose-settings ()
"My settings for message composition."
(company-mode) ; Complete addresses with company
(save-excursion (message-goto-bcc)
(when (not (looking-at "[[:blank:]]*$"))
(kill-line)) ; Avoid double insertions
(insert user-mail-address))
(save-excursion (message-goto-cc))
;; Remove the first date field (but not the one in forwarded messages).
;; Otherwise, the date of the composing start is used!
;; https://github.com/djcb/mu/issues/2096
(message-remove-header "Date" nil t)
;; Replace citation line place keeper.
(save-excursion
(beginning-of-buffer)
(when (re-search-forward message-citation-line-format nil t)
(replace-match (tl/message-citation-line-string) t)))
;; General fill settings
(turn-off-auto-fill)
(set-fill-column 79)
;; Activate spell checking
(flyspell-mode)
;; Do not autosafe drafts
(auto-save-mode -1)
;; FIXME: Does not work!
(when (re-search-forward "<#part sign=smime>" nil t)
(end-of-line)
(open-line 1)
(forward-line))
))
;; Only complete with mail addresses that have been used recently and with personal contact
(setq mu4e-compose-complete-only-personal t
mu4e-compose-complete-only-after (format-time-string
"%Y-%m-%d"
(time-subtract (current-time) (days-to-time 300))))
;; Compose email in separate frame
(setq mu4e-compose-in-new-frame t)
;; Close buffer (unfortunately not the frame) after sending the email
(setq message-kill-buffer-on-exit t)
;; Automatically include a message-signature in new messages (if it is set).
(setq mu4e-compose-signature-auto-include t)
;; Don't reply to yourself
;; Presupposes: mu init --my-address=your.email@address
(setq mu4e-compose-dont-reply-to-self t)
Edit-as-new feature: since v1.12, this feature is supported to some extend with the function mu4e-compose-supersede
. Let’s bind it to [N]:
(define-key mu4e-compose-minor-mode-map (kbd "N")
#'mu4e-compose-supersede)
Switch between “Reply” and “Wide Reply”. As of v1.12, the key [R] will start a compose buffer replying only to the sender of the message under point. To get the old behaviour back, the following code can be used:
;; Adapted code from https://github.com/djcb/mu/issues/2665#issuecomment-2004909314
(defun compose-reply-wide-or-not-please-ask ()
"Ask whether to reply-to-all or not."
(interactive)
;; (mu4e-compose-reply (yes-or-no-p "Reply to all?"))
(let* ((from-myself (mu4e-message-sent-by-me (mu4e-message-at-point)))
(addressees (append (mu4e-field-at-point ':to)
(mu4e-field-at-point ':cc))))
(mu4e-compose-reply ; non-nil creates a wide reply
(cond ((> (length addressees) 1)
(string-equal "a"
(char-to-string
(read-char "Reply to [a]ll or only to [s]ender? "))))
(from-myself t)
(t nil)
))))
(define-key mu4e-compose-minor-mode-map (kbd "R")
#'compose-reply-wide-or-not-please-ask)
Alternatively, one could bind [R] to “wide” replies:
(define-key mu4e-compose-minor-mode-map (kbd "R")
#'mu4e-compose-wide-reply)
Configure the body of forwarded messages:
(setq message-forward-as-mime nil
message-forward-before-signature t)
In general, files should be attached at the end of a message except for inline attachments. Since mml-attach-file-at-the-end
does not differentiate between inline and other attachments, it should not be used:
(setq mml-attach-file-at-the-end nil)
Attachments can be included directly from dired with the help of gnus
.
Taken from https://www.djcbsoftware.nl/code/mu/mu4e/Dired.html#Dired.
(require 'gnus-dired)
;; make the `gnus-dired-mail-buffers' function also work on
;; message-mode derived modes, such as mu4e-compose-mode
(defun gnus-dired-mail-buffers ()
"Return a list of active message buffers."
(let (buffers)
(save-current-buffer
(dolist (buffer (buffer-list t))
(set-buffer buffer)
(when (and (derived-mode-p 'message-mode)
(null message-sent-message-via))
(push (buffer-name buffer) buffers))))
(nreverse buffers)))
(setq gnus-dired-mail-mode 'mu4e-user-agent)
(add-hook 'dired-mode-hook 'turn-on-gnus-dired-mode)
Paste images from clipboard:
;; Taken from https://emacs.stackexchange.com/a/73068 and slightly modified
(defun my/clip-to-PNG ()
(interactive)
(when (string-match-p (regexp-quote "image/png") (shell-command-to-string "xclip -selection clipboard -o -t TARGETS"))
(let
((image-file (concat "/tmp/" (format-time-string "tmp_%Y%m%d_%H%M%S.png"))))
(shell-command-to-string (concat "xclip -o -selection clipboard -t image/png > " image-file))
image-file)))
(defun my/mu4e-attach-image-from-clipboard ()
(interactive)
(let ((image-file (my/clip-to-PNG)) ;; paste clipboard to temp file
(pos (point-marker)))
(when image-file
;; Add image as an external attachment
;; (goto-char (point-max))
;; (mail-add-attachment image-file)
;; Add image as an internal attachment
(mml-attach-file image-file "image/png" nil "inline")
)))
When inserting formatted content from the clipboard, this is first converted to appropriate Markdown markup:
(defun message-insert-formatted-text-from-clipboard ()
"Insert formatted clipboard content with Org markup."
(interactive)
(shell-command "xclip -o -t text/html | pandoc -f html -t gfm-raw_html -" '(4)))
(define-key mu4e-compose-mode-map (kbd "s-y") 'message-insert-formatted-text-from-clipboard)
Copy as formatted text to the clipboard:
(defun markdown-copy-formatted-text-to-clipboard ()
"Export region to HTML, and copy it to the clipboard."
(interactive)
(if (use-region-p)
(shell-command-on-region
(region-beginning)
(region-end)
"pandoc -t html -f gfm-raw_html - | xclip -verbose -selection clipboard -t text/html"
)))
(define-key mu4e-compose-mode-map (kbd "s-w") 'markdown-copy-formatted-text-to-clipboard)
Note that xclip
will wait (and Emacs will be stuck) until the copied content is pasted!
Check whether the message has an attachment if it mentions one:
(defun tl/mu4e-message-has-attachment-p ()
"Check whether the message has an attachment."
(save-excursion
(message-goto-body-1)
(search-forward-regexp "<#part .* disposition=attachment" nil t)))
(require 'subr-x)
(defun tl/mu4e-message-mentions-attachment-p ()
"Check whether the message mentions an attachment."
(save-excursion
(message-goto-body-1)
(let ((case-fold-search nil)
(keywords '("attached"
"attachment"
"angehängt"
"Anhang"
"anbei"
"häng.*an")))
(search-forward-regexp
(concat "^\\("
"[^>]\\{2\\}.*" ; do not search in quoted messages (yes, [^>] has to appear twice here)
"\\(" (string-join keywords "\\|") "\\)"
"\\|"
"\\(" (string-join keywords "\\|") "\\)"
"\\)")
nil t))))
(defun tl/mu4e-check-attachment ()
"Check whether the message has an attachment if it mentions one."
(when (and (tl/mu4e-message-mentions-attachment-p)
(not (tl/mu4e-message-has-attachment-p)))
(when (yes-or-no-p "Warning: Attachement is mentioned, but not yet added! Do you want to add an attachment?")
(error "Please add an attachment before sending the email!")
)))
(add-hook 'message-send-hook
'tl/mu4e-check-attachment)
Check whether the message has a subject:
(defun tl/mu4e-check-empty-subject ()
"Check whether the message has a subject."
(let ((subject (message-field-value "Subject")))
(when (or (not subject)
(string-empty-p subject))
(message "Warning: Subject is missing! Please provide a subject before sending.")
(sit-for 2) ; Display the warning for 2 seconds
(message-goto-subject)
(error "Cannot send the email without a subject"))))
(add-hook 'message-send-hook
'tl/mu4e-check-empty-subject)
For re-using predefined text snippets, tempel can be used. See templates/tempel/templates for an example.
yasnippet is not recommended when the snippet directly changes the buffer using functions (which is what I want).
A simpler method might be abbrevs, which is built-in in Emacs,
For specifying templates of whole emails, there is no straightforward solution as far as I know.
format=flowed is a general technique to give mail clients the flexibility to reformat parts of a message, particularly by inserting soft line breaks when paragraphs are filled. With this, the receiving email client will later be able to distinguish “deliberate”/hard from “automatic”/soft line breaks. The motivation ist that using hard line breaks when filling paragraphs will likely mess up the display of quoted text in downstream email clients.
Mu4e has built-in support of format=flowed, see https://www.djcbsoftware.nl/code/mu/mu4e/Writing-messages.html#How-can-I-apply-format_003dflowed-to-my-outgoing-messages_003f.
;; Activate format=flowed (i.e. the automatic insertion of soft line breaks).
(setq mu4e-compose-format-flowed t)
Notice that the Emacs MIME library also knows format=flowed, see https://www.gnu.org/software//emacs/manual/html_node/emacs-mime/Flowed-text.html.
;; Column beyond which format=flowed lines are wrapped, in outgoing messages.
;; The variable controls how the text will look in a client that does not support flowed text, the default is to wrap after 66 characters.
(setq fill-flowed-encode-column 66)
There is one nasty detail though: Mu4e will only apply format=flowed, if use-hard-newlines
is enabled, in which case a hard line break will be inserted whenever return is pressed (using the function newline
or open-line
). This is fine when writing text directly in the compose buffer. However, if one yanks text (or expands a template), the visible line breaks will be underspecified, and therefore interpreted as soft line breaks if there are any hard line breaks inserted with return. This can result in a great mess, because empty lines are potentially not interpreted as separators between paragraphs and the visible structure will be lost.
My solution is to harden all manually inserted or pasted line breaks at the very end when sending the message. Quoted messages do not get hard line breaks (this obviously would make format=flowed useless) with two exceptions:
- the header of quoted messages, which start with box symbols (┌│└)
- lines in quotes which start with two consecutive spaces after the quote symbols
This will, for example, avoid breaking Org tables, if they are preceded by at least two consecutive spaces.
(add-hook 'message-send-hook
(defun format-message-before-sending ()
(save-excursion
(message-goto-body)
(delete-trailing-whitespace)
;; Harden line breaks except most quoted ones
(while (search-forward-regexp "^\\([^>]\\|>+[ ][ ┌│└]\\).*\n" nil t)
(put-text-property (1- (point)) (point) 'hard t))
;; Harden further line breaks and activate use-hard-newlines
(use-hard-newlines 1 t))))
Perhaps obsolete: In mu4e, line breaks are handled in a way that is very unusual when coming from, e.g., Thunderbird. Namely, (hard) line breaks are ignored if they are preceded by trailing whitespace, which may lead to an unexpected paragraph structure in the sent message. (This is probably an effect of using format=flowed above.) In order to preserve the line breaks that one intentionally makes when writing the message, the following code therefore adds delete-trailing-whitespace
to message-send-hook
:
(add-hook 'message-send-hook
'delete-trailing-whitespace)
- State “TODO” from [2023-12-15 Fri 09:31]
Citation lines precede cited contents of replied or forwarded messages. Out of the box, Mu4e only includes the sender, which can be adjusted with message-citation-line-format
:
;; Alternatively, see https://www.djcbsoftware.nl/code/mu/mu4e/Writing-messages.html
(setq message-citation-line-format "On %Y-%m-%d at %H:%M:%S, %f wrote:"
message-citation-line-function 'message-insert-formatted-citation-line)
For adding further fields of a message to the citation line, I replace a special citation line with the output of the function tl/message-citation-line-string
using mu4e-compose-mode-hook
(see above) :
(setq message-citation-line-format "MU4E: REPLACE THIS CITATION LINE!")
(defun tl/mail-address-plist-to-string (address)
"Convert the plist ADDRESS with keys :name and :email into a string."
(let ((email (plist-get address ':email))
(name (plist-get address ':name)))
(concat
(or name email)
" "
"<" email ">")))
(defun tl/message-citation-line-string ()
"Generate citation text for current message with mu4e functions."
(let* ((msg mu4e-compose-parent-message)
(from (mu4e-message-field msg :from))
(to (mu4e-message-field msg :to))
(cc (mu4e-message-field msg :cc))
(subject (mu4e-message-field msg :subject))
(date (mu4e-message-field msg :date)))
(concat
"\n"
"> ┌ \n"
"> │ From: " (mapconcat 'tl/mail-address-plist-to-string from ", ") "\n"
"> │ Subject: " (save-match-data
(string-replace "\n" "\n> │ "
(string-fill subject (- message-fill-column 15)))) "\n"
"> │ To: " (mapconcat 'tl/mail-address-plist-to-string to ",\n> │ ") "\n"
(when cc (concat "> │ Cc: " (mapconcat 'tl/mail-address-plist-to-string cc ",\n> │ ") "\n"))
"> │ Date: " (format-time-string "%A, %Y-%m-%d, at %H:%M" date) "\n"
"> └ \n"
">"
)))
Since v1.12, citation lines of forwarded messages should be changed using Gnus’ message-forward:
(setq message-forward-included-headers '("^From:" "^Subject:" "^To:" "^Cc:" "^Date:"))
By default, mu4e removes the signature from cited messages by using message-cite-original-without-signature
as value of mu4e-compose-cite-function
. To include the signature, uncomment the following:
;; (setq mu4e-compose-cite-function 'message-cite-original)
Taken from djcb/mu#1843, but should be fixed in upcomping versions of mu4e.
Remove buttons like [[S/MIME ...
from text bodies of cited messages:
(defun tv/mu4e-remove-buttons-in-reply (original-fn &rest args)
(if current-prefix-arg
(delete-region (point) (point-max))
(save-excursion
(message-goto-body)
(while (re-search-forward "^[[]\\{2\\}.*[]]\\{2\\}" nil t)
(replace-match "")))
(apply original-fn args)))
(add-function :around mu4e-compose-cite-function #'tv/mu4e-remove-buttons-in-reply)
I use helm-khard for this. The steps are:
- Make sure that categories are shown in helm-khard.
- The contacts of the mailing list are assign a specific category.
- When writing an email, contacts are selected by filtering for this category.
Signing and encryption (vice versa verification and decryption) is done using emacs-mime, and can therefore be selected in the attachment menu.
Documentation:
- https://www.djcbsoftware.nl/code/mu/mu4e/Signing-and-encrypting.html
- https://www.gnu.org/software/emacs/manual/html_node/message/Using-S_002fMIME.html
Global settings:
(setq mml-smime-use 'epg ; Use EasyPG (epg), i.e. GnuPG, when handling S/MIME.
mm-sign-option nil ; With 'guided, the key can be chosen in a menu.
mm-verify-option 'always ; Alwyays verify digital signatures.
gnus-buttonized-mime-types '("multipart/signed") ; Required by 'mm-verify-option' being set to 'always.
)
Account-local settings:
(setq mml-secure-smime-sign-with-sender t ; If t, use message sender to find an S/MIME key to sign with.
mml-default-sign-method "smime" ; "smime" or "pgpmime"
epg-user-id "123456789" ; GnuPG ID of your default identity when using PGP.
smime-keys nil ; Map mail addresses to a PEM file containing Certificate (and private key).
smime-CA-directory nil ; Directory containing certificates (in PEM format) for CAs you trust.
smime-CA-file nil ; The same as `smime-CA-directory', but in one PEM file.
)
Caveats:
- Don’t use inline PGP, but PGP/MIME: https://josefsson.org/inline-openpgp-considered-harmful.html
Support of DKIM
- Show status as header field using
opendkim
(pretty slow): djcb/mu#2348
(setq send-mail-function 'smtpmail-send-it
smtpmail-debug-info t)
Normally, smtpmail will try first to send emails via SMTP without user/password credentials, and then retry using credentials if
the server says that it requires it. Some mail servers do not like this and will therefore reject these requests. This can be changed by setting smtpmail-servers-requiring-authorization
to the address of the SMTP server. As a default, the following enforces authentification for all SMTP servers.
(setq smtpmail-servers-requiring-authorization ".*")
There is a built-in search, but I prefer helm-mu, which allows for incremental search of mails and contacts.
Queries can be stored as bookmarks: https://www.djcbsoftware.nl/code/mu/mu4e/Bookmarks.html
My bookmarks are narrowed to helm-mu-default-search-string
, which makes it necessary to set the bookmarks every time mu4e-main-mode-hook
is called (and helm-mu-default-search-string
is possibly changed).
(setq mu4e-bookmarks nil) ; Remove any default bookmarks
(add-hook 'mu4e-main-mode-hook
(lambda ()
(setq mu4e-bookmarks
`((:name "With attachment"
:key ?a
:query ,(concat helm-mu-default-search-string " flag:attach"))
(:name "With calendar invitation"
:key ?c
:query ,(concat helm-mu-default-search-string " flag:calendar"))
(:name "With images"
:query ,(concat helm-mu-default-search-string " mime:image/*")
:key ?i)
(:name "Flagged"
:key ?f
:query ,(concat helm-mu-default-search-string " flag:flagged"))
(:name "Unread messages"
:query ,(concat helm-mu-default-search-string " flag:unread AND NOT flag:trashed")
:key ?u)
(:name "Today's messages"
:query ,(concat helm-mu-default-search-string " date:today..now")
:key ?t)
(:name "Last 7 days"
:query ,(concat helm-mu-default-search-string " date:7d..now")
:hide-unread t
:key ?w)
(:name "[Global] With attachment"
:key ?A
:query "flag:attach")
(:name "[Global] With calendar invitation"
:key ?C
:query "flag:calendar")
(:name "[Global] Messages with images"
:query "mime:image/*"
:key ?I)
(:name "[Global] Flagged"
:key ?F
:query "flag:flagged")
(:name "[Global] Unread messages"
:query "flag:unread AND NOT flag:trashed"
:key ?U)
(:name "[Global] Today's messages"
:query "date:today..now"
:key ?T)
(:name "[Global] Last 7 days"
:query "date:7d..now"
:hide-unread t
:key ?W)
)
)))
Note: As of v1.12.6, mu4e comes with a function mu4e-save-message
.
The following function (written by Dirk-Jan Binnema, copied from https://notes.baty.net/notes/saving-a-maildir-email-as-.eml-using-mu4e/) exports an email at point to an eml file.
(defun djcb-mu4e-copy-message-at-point (&optional dir)
"Copy message at point to somewhere else as <date>_<subject>.eml."
(interactive)
(let* ((msg (mu4e-message-at-point))
(target (format "%s_%s.eml"
(format-time-string "%F" (mu4e-message-field msg :date))
(or (mu4e-message-field msg :subject) "No subject"))))
(copy-file
(mu4e-message-field msg :path)
(format "%s/%s" (or dir (read-directory-name "Copy message to: ")) target) 1)))
Let’s write a proper mu4e action based on this:
(defun tl/mu4e-action-copy-message-file (msg)
"Copy message to <date>_<subject>.eml in some user-specified
directory."
(interactive)
(let ((target
(string-replace "/" "-"
(format "%s_%s.eml"
(format-time-string "%F" (mu4e-message-field msg :date))
(or (mu4e-message-field msg :subject) "No subject")))))
(copy-file
(mu4e-message-field msg :path)
(format "%s/%s" (read-directory-name "Copy message to: " (expand-file-name "~/")) target) 1)))
Documentation: https://www.djcbsoftware.nl/code/mu/mu4e/Org_002dmode-links.html
Load org-mode integration (FIXME: necessary?):
(require 'mu4e-org)
Store link to message if in header view, not to header query:
(setq org-mu4e-link-query-in-headers-mode nil)
Adapt description of links:
(defun tl/mu4e-org-link-descr (msg)
(let ((subject (or (plist-get msg :subject)
"No subject"))
(date (or (format-time-string mu4e-headers-date-format
(mu4e-msg-field msg :date))
"No date"))
(sender (or (plist-get (car (plist-get msg :from)) :name)
"No Sender")))
(concat date " | " sender " | " subject)))
(setq mu4e-org-link-desc-func 'tl/mu4e-org-link-descr)
Open links to messages in the mu4e frame:
See the discussion here: https://groups.google.com/g/mu-discuss/c/EME00itASYM/m/hu0faSFSBwAJ
I choose a different approach, namely modifying the function mu4e-org-open
.
(defun mu4e-org-open (link)
"Open the org LINK.
Open the mu4e message (for links starting with \"msgid:\") or run
the query (for links starting with \"query:\")."
(require 'mu4e)
;; BEGIN: added by TL
;; Swich to frame with buffer "*mu4e-headers*"
(let* ((buffer-name mu4e-headers-buffer-name)
(buffer (get-buffer buffer-name)))
(if buffer
(let ((frames (frame-list)))
(dolist (frame frames)
(when (get-buffer-window buffer frame)
(select-frame-set-input-focus frame))))
(progn
(message (format "No buffer named %s; creating new frame to open link" buffer-name))
(make-frame))))
;; END: added by TL
(cond
((string-match "^msgid:\\(.+\\)" link)
(mu4e-view-message-with-message-id (match-string 1 link)))
((string-match "^query:\\(.+\\)" link)
(mu4e-search (match-string 1 link) current-prefix-arg))
(t (mu4e-error "Unrecognized link type '%s'" link))))
To open mailto URLs in mu4e, do the following (taken from https://emacs.stackexchange.com/questions/52281/handling-mailto-links-with-mu4e):
- Set
mail-user-agent
to#'mu4e-user-agent
.
(setq mail-user-agent #'mu4e-user-agent
message-mail-user-agent t ; when t, use MUA specified in mail-user-agent
)
- Create a desktop file which executes
emacsclient --alternate-editor= --eval "(message-mailto \"%u\")"
. Emacs provides a specific desktop file for opening mailto URLs (https://git.savannah.gnu.org/cgit/emacs.git/tree/etc/emacsclient-mail.desktop), but unfortunately it does not work for me as is. The following is the content of my adapted desktop file:
[Desktop Entry]
Name=Emacs client for mailto URLs
Comment=Open mailto URL in Emacs
MimeType=x-scheme-handler/mailto;
## From the original Emacs desktop file (https://git.savannah.gnu.org/cgit/emacs.git/tree/etc/emacsclient-mail.desktop)
# Exec=emacsclient --alternate-editor= --eval "(message-mailto (pop server-eval-args-left))" %u
## My adaptation of the above
## For some unkown reason, there can be a trailing apostrophe.
Exec=emacsclient --alternate-editor= --eval "(message-mailto (string-trim-right \"%u\" \"'\"))"
Icon=emacs
Type=Application
Terminal=false
Categories=Development;TextEditor;
StartupWMClass=Emacs
- Select this as default programm to open mailto URLs in your browser.
- Optionally add the desktop file to
~/.config/mimeapps.list
.
[Default Applications]
x-scheme-handler/mailto=emacsclient-mailto.desktop
One can store messages using Org’s capture mechanism. See also the dedicated page in the documentation of mu4e: https://www.djcbsoftware.nl/code/mu/mu4e/Org_002dmode-links.html
I mainly use this for scheduling when to work on messages. For this, I add a suitable template to org-capture-templates
, which will create a header with a link in my capture file:
(add-to-list 'org-capture-templates
'("s" "Scheduled emails" entry
(file+headline (lambda nil
(expand-file-name "captures.org" org-directory))
"Scheduled emails")
"* %?%a\nSCHEDULED: %^T" :prepend t))
Let’s also add keybindings for capturing messages:
(define-key mu4e-headers-mode-map (kbd "C-c c") 'mu4e-org-store-and-capture)
(define-key mu4e-view-mode-map (kbd "C-c c") 'mu4e-org-store-and-capture)
- State “TODO” from [2024-10-23 Wed 08:40]
https://codeberg.org/martianh/mastodon.el
A Mastodon client for Emacs.
(use-package mastodon
:ensure t
:config
;; (mastodon-discover)
;;; Account settings should be put elsewhere
(setq mastodon-instance-url "https://social.instance.org"
mastodon-active-user "example_user")
(setq mastodon-tl--show-avatars t
mastodon-tl--horiz-bar (make-string 70 ?═)
mastodon-media--avatar-height 40
mastodon-media--preview-max-height 500
mastodon-tl--highlight-current-toot nil)
;;; Recentering the view like this will throw "apply: Wrong number of arguments: (0 . 1), 2"
;; (advice-add 'mastodon-tl--goto-prev-item
;; :after #'recenter)
;; (advice-add 'mastodon-tl--goto-next-item
;; :after #'recenter)
)
A nice alternative design by Nicolas Rougier: https://github.com/rougier/mastodon-alt
- [ ] Crashes
(use-package mastodon-alt
:load-path "./lisp/mastodon-alt.el"
:after mastodon
:config
(mastodon-alt-tl-activate)
;; (advice-add 'mastodon-tl--goto-prev-item
;; :after #'recenter)
;; (advice-add 'mastodon-tl--goto-next-item
;; :after #'recenter)
)
A fitting hydra from https://holgerschurig.github.io/en/emacs-mastodon-hydra/
(defhydra hydra-mastodon (:color blue :hint nil)
"
Timelines^^ Toots^^^^ Own Toots^^ Profiles^^ Users/Follows^^ Misc^^
^^-----------------^^^^--------------------^^----------^^-------------------^^------^^-----
_H_ome _n_ext _p_rev _r_eply _A_uthors follo_W_ _X_ lists
_L_ocal _T_hread of toot^^ wri_t_e user _P_rofile _N_otifications f_I_lter
_F_ederated (un) _b_oost^^ _e_dit ^^ _R_equests _C_opy URL
fa_V_orites (un) _f_avorite^^ _d_elete _O_wn su_G_estions _s_earch
_#_ tagged (un) p_i_n^^ ^^ _U_pdate own _M_ute user _h_elp
_@_ mentions (un) boo_k_mark^^ show _E_dits ^^ _B_lock user
boo_K_marks _v_ote^^
trendin_g_
_u_pdate
"
("H" mastodon-tl--get-home-timeline)
("L" mastodon-tl--get-local-timeline)
("F" mastodon-tl--get-federated-timeline)
("V" mastodon-profile--view-favourites)
("#" mastodon-tl--get-tag-timeline)
("@" mastodon-notifications--get-mentions)
("K" mastodon-profile--view-bookmarks)
("g" mastodon-search--trending-tags)
("u" mastodon-tl--update :exit nil)
("n" mastodon-tl--goto-next-toot)
("p" mastodon-tl--goto-prev-toot)
("T" mastodon-tl--thread)
("b" mastodon-toot--toggle-boost :exit nil)
("f" mastodon-toot--toggle-favourite :exit nil)
("i" mastodon-toot--pin-toot-toggle :exit nil)
("k" mastodon-toot--bookmark-toot-toggle :exit nil)
("c" mastodon-tl--toggle-spoiler-text-in-toot)
("v" mastodon-tl--poll-vote)
("A" mastodon-profile--get-toot-author)
("P" mastodon-profile--show-user)
("O" mastodon-profile--my-profile)
("U" mastodon-profile--update-user-profile-note)
("W" mastodon-tl--follow-user)
("N" mastodon-notifications-get)
("R" mastodon-profile--view-follow-requests)
("G" mastodon-tl--get-follow-suggestions)
("M" mastodon-tl--mute-user)
("B" mastodon-tl--block-user)
("r" mastodon-toot--reply)
("t" mastodon-toot)
("e" mastodon-toot--edit-toot-at-point)
("d" mastodon-toot--delete-toot)
("E" mastodon-toot--view-toot-edits)
("I" mastodon-tl--view-filters)
("X" mastodon-tl--view-lists)
("C" mastodon-toot--copy-toot-url)
("s" mastodon-search--search)
("h" describe-mode)
("q" doom/escape))
- State “TODO” from [2024-11-10 Sun 20:06]
https://github.com/skeeto/elfeed
Web feed reader for Emacs.
Issues:
- [ ] Rework hydra
(use-package elfeed
:ensure t
:bind (:map elfeed-search-mode-map
("m" . elfeed-toggle-star)
("M" . tl/elfeed-show-starred)
("R" . elfeed-mark-all-as-read)
("U" . tl/elfeed-show-unread)
("s" . tl/elfeed-search-live-filter-space)
("f" . tl/elfeed-search-live-filter-space)
("*" . tl/elfeed-show-starred)
;; ;; ("/" . mz/make-and-run-elfeed-hydra)
("A" . tl/elfeed-show-all)
)
:config
(when (boundp 'my-elfeed-db-directory)
(setq elfeed-db-directory my-elfeed-db-directory))
(defalias 'elfeed-toggle-star
(elfeed-expose #'elfeed-search-toggle-all 'star))
(defface star-elfeed-entry
'((t :foreground "#FD5FF0" :weight bold))
"Face of a starred Elfeed entry.")
(push '(star star-elfeed-entry)
elfeed-search-face-alist)
(defface unread-elfeed-entry
'((t :inherit font-lock-keyword-face))
"Face of an unread Elfeed entry.")
(push '(unread unread-elfeed-entry)
elfeed-search-face-alist)
;; TODO: Unfortunately, it does not work like this.
;; (set-face-attribute 'elfeed-search-feed-face nil :inherit font-lock-number-face)
;; (set-face-attribute 'elfeed-search-tag-face nil :inherit 'font-lock-comment-face)
(defun elfeed-mark-all-as-read ()
(interactive)
(mark-whole-buffer)
(elfeed-search-untag-all-unread))
(defun tl/elfeed-show-starred ()
(interactive)
(elfeed-search-set-filter "@6-months-ago +star"))
(defun tl/elfeed-show-all ()
(interactive)
(elfeed-search-set-filter "@6-months-ago"))
(defun tl/elfeed-show-unread ()
(interactive)
(elfeed-search-set-filter "@6-months-ago +unread"))
(defun tl/elfeed-search-live-filter-space ()
"Insert trailing space when running elfeed filter"
(interactive)
(let ((elfeed-search-filter (concat elfeed-search-filter " ")))
(elfeed-search-live-filter)))
(advice-add 'elfeed :after
;; (add-hook 'elfeed-search-mode-hook
#'(lambda ()
(with-current-buffer "*elfeed-search*"
(toggle-truncate-lines t))))
;; Generate filter hydra for a given set of tags (using code macros).
;; Taken from http://cestlaz.github.io/posts/using-emacs-31-elfeed-3/.
(defun z/hasCap (s)
""
(let ((case-fold-search nil))
(string-match-p "[[:upper:]]" s)
))
(defun z/get-hydra-option-key (s)
"returns single upper case letter (converted to lower) or first"
(interactive)
(let ( (loc (z/hasCap s)))
(if loc
(downcase (substring s loc (+ loc 1)))
(substring s 0 1)
)))
(defun mz/make-elfeed-cats (tags)
"Returns a list of lists. Each one is line for the hydra configuratio in the form
(c function hint)"
(interactive)
(mapcar (lambda (tag)
(let* (
(tagstring (symbol-name tag))
(c (z/get-hydra-option-key tagstring))
)
(list c (append '(elfeed-search-set-filter) (list (format "@6-months-ago +%s" tagstring) ))tagstring )))
tags))
(defmacro mz/make-elfeed-hydra ()
`(defhydra mz/hydra-elfeed ()
"filter"
,@(mz/make-elfeed-cats (elfeed-db-get-all-tags))
("*" (elfeed-search-set-filter "@6-months-ago +star") "Starred")
;; ("M" elfeed-toggle-star "Mark")
("A" (elfeed-search-set-filter "@6-months-ago") "All")
("T" (elfeed-search-set-filter "@1-day-ago") "Today")
("Q" bjm/elfeed-save-db-and-bury "Quit Elfeed" :color blue)
("q" nil "quit" :color blue)
))
(defun mz/make-and-run-elfeed-hydra ()
""
(interactive)
(mz/make-elfeed-hydra)
(mz/hydra-elfeed/body))
;; Write to disk when quiting
;; TODO: Still needed?
(defun bjm/elfeed-save-db-and-bury ()
"Wrapper to save the elfeed db to disk before burying buffer"
(interactive)
(elfeed-db-save)
(quit-window))
)
Change the columns (and some faces) of the elfeed-search buffer:
(defun tl/elfeed-search-print-entry (entry)
"Print ENTRY to the buffer."
(let* ((date (elfeed-search-format-date (elfeed-entry-date entry)))
(title (or (elfeed-meta entry :title) (elfeed-entry-title entry) ""))
(title-faces (elfeed-search--faces (elfeed-entry-tags entry)))
(feed (elfeed-entry-feed entry))
(feed-title
(when feed
(or (elfeed-meta feed :title) (elfeed-feed-title feed))))
(feed-title-max-width 20)
(feed-short-title
(if (> (length feed-title) (- feed-title-max-width 1))
(concat (truncate-string-to-width feed-title
(- feed-title-max-width 1))
"… ")
feed-title))
(feed-title-column (elfeed-format-column
feed-short-title (elfeed-clamp
feed-title-max-width
feed-title-max-width
feed-title-max-width)
:left))
(elfeed-search-trailing-width (+ 11 feed-title-max-width 20))
(title-width (- (window-width) 10 elfeed-search-trailing-width))
(elfeed-search-title-max-width
(or (and (> title-width elfeed-search-title-max-width)
title-width)
elfeed-search-title-max-width))
(title-column (elfeed-format-column
title (elfeed-clamp
elfeed-search-title-min-width
title-width
elfeed-search-title-max-width)
:left))
(tags (mapcar #'symbol-name (elfeed-entry-tags entry)))
(tags-str (mapconcat
(lambda (s) (propertize s 'face 'elfeed-search-tag-face))
tags ","))
)
(insert (propertize date 'face 'elfeed-search-date-face) " ")
(insert (propertize feed-title-column 'face 'font-lock-number-face) " ") ; Only hard-coding the face seems to work.
;; (when feed-title
;; (insert (propertize feed-title 'face 'elfeed-search-feed-face) " "))
(insert (propertize title-column 'face title-faces 'kbd-help title) " ")
(when tags
(insert (propertize (concat "(" tags-str ")") 'face 'font-lock-comment-face))) ; Only hard-coding the face seems to work.
;; (when tags
;; (insert "(" tags-str ")"))
))
(setq elfeed-search-print-entry-function #'tl/elfeed-search-print-entry)
Wrapper function for elfeed (used in hydra-f7):
(defun tl/elfeed ()
(interactive)
(elfeed)
(visual-line-mode -1))
Split-pane view for Elfeed, taken from https://karthinks.com/software/lazy-elfeed/.
Issues:
- [ ] Killing the elfeed-show buffer replaces it with a new elfeed-search window. Intended behavior: Return to original elfeed-search window and “unsplit” it.
(setq elfeed-show-entry-switch #'elfeed-display-buffer)
(defun elfeed-display-buffer (buf &optional act)
(pop-to-buffer buf)
(set-window-text-height (get-buffer-window) (round (* 0.7 (frame-height)))))
(defun elfeed-search-show-entry-pre (&optional lines)
"Returns a function to scroll forward or back in the Elfeed
search results, displaying entries without switching to them."
(lambda (times)
(interactive "p")
(forward-line (* times (or lines 0)))
(recenter)
(call-interactively #'elfeed-search-show-entry)
(select-window (previous-window))
(unless elfeed-search-remain-on-entry (forward-line -1))))
(with-eval-after-load 'elfeed
(define-key elfeed-search-mode-map (kbd "n") (elfeed-search-show-entry-pre +1))
(define-key elfeed-search-mode-map (kbd "p") (elfeed-search-show-entry-pre -1))
(define-key elfeed-search-mode-map (kbd "M-RET") (elfeed-search-show-entry-pre)))
The following code allows one to watch YouTube videos with mpv. Taken from https://joshrollinswrites.com/help-desk-head-desk/20200611/.
(require 'elfeed)
(defun elfeed-v-mpv (url)
"Watch a video from URL in MPV"
(async-shell-command (format "mpv %s" url)))
(defun elfeed-view-mpv (&optional use-generic-p)
"Youtube-feed link"
(interactive "P")
(let ((entries (elfeed-search-selected)))
(cl-loop for entry in entries
do (elfeed-untag entry 'unread)
when (elfeed-entry-link entry)
do (elfeed-v-mpv it))
(mapc #'elfeed-search-update-entry entries)
(unless (use-region-p) (forward-line))))
(define-key elfeed-search-mode-map (kbd "v") 'elfeed-view-mpv)
!!! WORK IN PROGRESS !!!
https://codeberg.org/timmli/helm-elfeed
A Helm interface for Elfeed.
(use-package helm-elfeed
:after elfeed
:load-path "lisp/helm-elfeed/"
:config
(define-key elfeed-search-mode-map (kbd "C-i") 'helm-elfeed)
)
https://github.com/jeetelongname/elfeed-goodies
From the documentation:
- An adaptive, powerline-based header for the elfeed-search and elfeed-entry buffers, with a matching entry format.
- Split pane setup.
- A function to toggle the elfeed-log buffer in a popup window.
- Easy customisation.
Issues (therefore disabled right now)
- [ ] No date column: jeetelongname/elfeed-goodies#39
(use-package elfeed-goodies
:ensure t
:after elfeed
:config
(elfeed-goodies/setup)
(setq elfeed-goodies/entry-pane-size 0.75
elfeed-goodies/entry-pane-position 'bottom))
https://github.com/remyhonig/elfeed-org
Configure the Elfeed RSS reader with an Org file, the path of which is specified in my-elfeed-org-file
.
Feed collections can be converted to the format of elfeed-org
with the function elfeed-org-import-opml
.
(use-package elfeed-org
:ensure t
:after elfeed
:config
(elfeed-org)
(when (boundp 'my-elfeed-org-file)
(setq rmh-elfeed-org-files (list my-elfeed-org-file)))
(setq rmh-elfeed-org-auto-ignore-invalid-feeds nil)) ; handle with care
- State “TODO” from [2022-05-15 Sun 10:53]
https://github.com/SqrtMinusOne/elfeed-summary
A tree-based feed summary interface for elfeed. Superseded (in my view) by helm-elfeed.
Issues & TODOs:
- [ ] Add hydra
- [ ] Fold all groups in the beginning
- [ ] Change group face if it contains unread entities
(use-package elfeed-summary
:ensure t
:pin MELPA
:config
:init
(setq elfeed-summary-settings
(append
'(
;; (group
;; (:title . "All feeds")
;; (:elements
;; (query . :all)))
(group (:title . "Searches")
(:elements
(search
(:filter . "+star")
(:title . "Starred/marked entries"))
(search
(:filter . "@14-days-ago +unread")
(:title . "Unread entries this and last week"))))
(auto-tags (:max-level . 2)
(:original-order . t))
;; (tag-groups (:repeat-feeds . t))
;; (mapcar #'(lambda (tag)
;; `(group
;; (:title . ,(upcase-initials (symbol-name tag)))
;; (:elements (query . (,tag)))))
;; (elfeed-db-get-all-tags))
)))
:bind (:map elfeed-summary-mode-map
("<C-tab>" . iflipb-next-buffer)
("<C-iso-lefttab>" . iflipb-previous-buffer)
("C-c C-u" . elfeed-summary-update)
("U" . elfeed-summary-update)
("R" . elfeed-summary--action-mark-read))
:custom-face
(elfeed-summary-count-face-unread ((t (:inherit unread-elfeed-entry))))
)
Wrapper function for starting elfeed-summary with hydra-f7.
(defun tl/elfeed-summary ()
(interactive)
(elfeed) ; This is necessary for truncating lines.
(elfeed-summary)
(with-current-buffer "*elfeed-summary*"
(forward-line +1)
(magit-section-forward)
(forward-line +1)))
https://github.com/karthink/elfeed-tube
Elfeed interface to Youtube subscriptions.
(use-package elfeed-tube
:straight (:host github :repo "karthink/elfeed-tube")
:after elfeed
:demand t
:config
;; (setq elfeed-tube-auto-save-p nil) ;; t is auto-save (not default)
;; (setq elfeed-tube-auto-fetch-p t) ;; t is auto-fetch (default)
(elfeed-tube-setup)
:bind (:map elfeed-show-mode-map
("F" . elfeed-tube-fetch)
([remap save-buffer] . elfeed-tube-save)
:map elfeed-search-mode-map
("F" . elfeed-tube-fetch)
([remap save-buffer] . elfeed-tube-save)))
https://github.com/odanoburu/conllu-mode
Major mode for CoNLL-U files.
(use-package conllu-mode
:ensure t
:config
(add-to-list 'auto-mode-alist '("\\.conllu\\'" . conllu-mode))
)
https://elpa.gnu.org/packages/csv-mode.html
Major mode for editing files in a generalized CSV (character-separated values) format.
(use-package csv-mode
:ensure t)
https://github.com/wasamasa/nov.el
(when (eq system-type 'windows-nt)
(setq doc-view-ghostscript-program "gswin64c.exe"))
The hard part is to generate epdfinfo.exe
under Windows, which is why I’m not using it there.
New: https://github.com/vedang/pdf-tools Old: https://github.com/politza/pdf-tools
Issues
- [ ] Add a cursor for marking: vedang/pdf-tools#39
- [ ] Add multi-page view: vedang/pdf-tools#224
(use-package pdf-tools
:ensure t
:pin MELPA
;; :if (executable-find "epdfinfo")
:mode (("\\.pdf\\'" . pdf-view-mode))
:bind ("M-w" . pdf-view-kill-ring-save) ; does not work
:config
(setq-default pdf-view-display-size 'fit-page) ; fit page by default
(setq pdf-view-resize-factor 1.10
pdf-view-selection-style 'glyph)
(pdf-tools-install)
;; Manually set path to epdfinfo binary
;; (setq pdf-info-epdfinfo-program (expand-file-name "epdinfo.exe" (concat wemacs-dir "pdftools")))
(define-key pdf-view-mode-map (kbd "M-w") 'pdf-view-kill-ring-save)
(define-key pdf-view-mode-map (kbd "C-w") 'pdf-view-kill-ring-save)
(define-key pdf-view-mode-map (kbd "M-<left>") 'pdf-history-backward)
(define-key pdf-view-mode-map (kbd "M-<right>") 'pdf-history-forward)
(add-hook 'pdf-occur-buffer-mode-hook 'next-error-follow-minor-mode) ; activate follow mode in `pdf-occur'
)
- State “TODO” from [2020-03-30 Mo 11:07]
org-pdftools provides =org-links
with prefix pdf:
to single pages of PDFs using pdf-tools
.
URL: https://github.com/fuxialexander/org-pdftools
- [ ] Links relative to attachment directory?
(use-package org-pdftools
:ensure t
;; :hook (org-load . org-pdftools-setup-link) ; recommended but does not work
:hook (org-mode . org-pdftools-setup-link)
;; :config
;; (with-eval-after-load 'org ; Instead of: :hook (org-mode . org-pdftools-setup-link)
;; (org-pdftools-setup-link))
;; (setq org-pdftools-root-dir user-bibliography-pdf-dir) ; not supported anymore?
)
The following function checks the signature of a PDF that is opened in a buffer or under point in dired (taken from ChatGPT). It uses the command line tool pdfsig
of the Poppler library:
(defun check-pdf-signature-dwim ()
"Check the digital signature of a PDF file.
If in Dired, check the PDF file at point. If in a `pdf-view-mode` buffer,
check the currently opened PDF file. Otherwise, prompt for a file."
(interactive)
(let* ((file (cond
;; If in Dired, use the file at point.
((derived-mode-p 'dired-mode) (dired-get-file-for-visit))
;; If in a `pdf-view-mode` buffer, use the current file.
((eq major-mode 'pdf-view-mode) (buffer-file-name))
;; Otherwise, prompt the user for a file.
(t (read-file-name "Select PDF file: "))))
(output-buffer "*PDF Signature*"))
(if (and file (string-match "\\.pdf\\'" file))
(with-output-to-temp-buffer output-buffer
(call-process "pdfsig" nil output-buffer nil file)
(display-buffer output-buffer))
(message "Not a valid PDF file"))))
I will add this to hydra-f4.
Starting from GNU Emacs 26, doc-view
supports DjVu documents. Both doc-view
and djvu-view
depend on the package djvulibre
, which includes djvused
.
Open DjVu files with doc-view
or djvu
.
(add-to-list 'auto-mode-alist '("\\.djvu\\'" . doc-view-mode))
;; (add-to-list 'auto-mode-alist '("\\.djvu\\'" . djvu-dummy-mode))
Issues with doc-view
:
- [ ] Copying text from within DocView is not possible.
- [ ] Searching within DocView ist not possible
https://elpa.gnu.org/packages/djvu.html
Package for reading an editing DjVu files.
(use-package djvu
:ensure t)
https://github.com/mhayashi1120/Emacs-imagex
Show and modify images within emacs. Used in hydra-image.
(use-package image+
:ensure t
:init
(eval-after-load 'image '(require 'image+))
:config
(if (eq system-type 'windows-nt)
(setq imagex-convert-command "magick") ; "convert" does not work on Windows machines
(setq imagex-convert-command "convert"))
)
https://github.com/minad/osm
OpenStreetMap viewer for Emacs.
(use-package osm
:ensure t
:pin MELPA
;; :bind (("C-c m h" . osm-home)
;; ("C-c m s" . osm-search)
;; ("C-c m v" . osm-server)
;; ("C-c m t" . osm-goto)
;; ("C-c m j" . osm-bookmark-jump))
:custom
;; Take a look at the customization group `osm' for more options.
(osm-server 'default) ;; Configure the tile server
(osm-copyright t) ;; Display the copyright information
:config
(add-hook 'osm-mode-hook #'(lambda () (visual-line-mode -1)))
)
https://gitlab.com/ambrevar/emacs-gif-screencast
Slim GIF screencasts for Emacs. This package uses scrot, convert and Gifsicle.
(use-package gif-screencast
:ensure t)
pandoc-mode allows one to use pandoc
from within Emacs. pandoc
is a very rich transducer for text formats. Note that pandoc
needs to be installed separately.
(use-package pandoc-mode
:ensure t
:config
;; (add-hook 'markdown-mode-hook 'pandoc-mode)
;; (add-hook 'org-mode-hook 'pandoc-mode)
(add-hook 'pandoc-mode-hook 'pandoc-load-default-settings))
https://www.emacswiki.org/emacs/SoLong
so-long.el
optimizes the performance on files with long lines. Built into Emacs since v27.
(when (require 'so-long nil :noerror)
(global-so-long-mode 1))
Automatically update buffers when files change:
(global-auto-revert-mode t)
Visible bell:
(setq visible-bell t)
(setq ring-bell-function (lambda ()
(invert-face 'mode-line)
(run-with-timer 0.05 nil 'invert-face 'mode-line)))
Delete marked text on typing:
(delete-selection-mode t)
Use tabs for indent:
(setq-default tab-width 2)
(setq-default indent-tabs-mode t)
Scrolling:
(setq scroll-step 1
scroll-conservatively 10000)
;; autoscroll compilation output
(setq compilation-scroll-output t)
;; scroll to the first/last line
(setq scroll-error-top-bottom t)
Open untitled new buffer:
(defun xah-new-empty-buffer ()
"Open a new empty buffer.
URL `http://ergoemacs.org/emacs/emacs_new_empty_buffer.html'
Version 2015-06-12"
(interactive)
(let ((buf (generate-new-buffer "untitled")))
(switch-to-buffer buf)
(funcall (and initial-major-mode))
(setq buffer-offer-save t)))
(global-set-key (kbd "<f7> <f7>") 'xah-new-empty-buffer)
Kill buffer:
(global-set-key (kbd "M-<f3>") 'kill-this-buffer) ; M-<f4> is bound to killing the application under xfce.
Revert buffer:
(global-set-key (kbd "<f5>") 'revert-buffer)
https://github.com/jrosdahl/iflipb
Switching between buffers with C-tab:
(use-package iflipb
:ensure t
:config
(setq iflipb-wrap-around t)
(setq iflipb-ignore-buffers "^ ") ; include all buffers
:bind
("<C-tab>" . iflipb-next-buffer)
("<C-iso-lefttab>" . iflipb-previous-buffer))
https://github.com/killdash9/buffer-flip.el
Flip through Emacs buffers Alt-Tab style.
https://github.com/alphapapa/bufler.el
Show open buffers in a more structured way.
(use-package bufler
:ensure t
:pin MELPA)
Fuzzy search in helm.
(use-package helm-bufler
:ensure t
:pin MELPA
:config
(defun helm-bufler-go ()
(interactive)
(helm :sources '(helm-bufler-source))))
https://github.com/joaotavora/yasnippet
Yet Another Snippet system for Emacs.
(use-package yasnippet
:ensure t
:pin MELPA
:config
(yas-global-mode 1)
(add-to-list 'warning-suppress-types '(yasnippet backquote-change)))
Helper functions for yasnippet:
(defun yas/org-insert-time-stamp (&rest args)
"Return the string that `org-insert-time-stamp' would insert.
Taken from https://emacs.stackexchange.com/questions/24060/yasnippet-truncates-clipboard-contents"
(with-temp-buffer
(apply #'org-insert-time-stamp args)
(buffer-string)))
(defun yas/org-time-stamp (&rest args)
"Return the string that `org-time-stamp' would insert.
Similar to `yas/org-insert-time-stamp`"
(with-temp-buffer
(apply #'org-time-stamp args)
(buffer-string)))
- [ ] completion of LaTeX code in AUCTex
- [ ] completion in org-mode of LaTeX code
http://company-mode.github.io/
(use-package company
:ensure t
:config
;; some general variables
(setq company-idle-delay 0.2
company-minimum-prefix-length 1
company-selection-wrap-around t ; If enabled, selecting item before first or after last wraps around.
company-tooltip-flip-when-above t
;; company-show-numbers t
company-dabbrev-downcase nil
company-auto-complete nil
company-tooltip-align-annotations nil ; When non-nil, align annotations to the right tooltip border.
company-transformers '(company-sort-by-occurrence))
;; face
(set-face-attribute 'company-tooltip nil :inherit 'fixed-pitch) ; Use monospaced font in tooltips.
;; keys
(eval-after-load 'company
'(progn
(define-key company-active-map (kbd "<tab>") 'company-complete-selection)
(define-key company-active-map (kbd "<return>") nil)
(define-key company-active-map (kbd "RET") nil)
;; (define-key company-active-map (kbd "<tab>") 'company-complete-common) ; Insert the common part of all candidates.
;; (define-key company-active-map (kbd "<tab>") 'company-select-next))
(define-key company-active-map (kbd "<up>") 'company-select-previous)
(define-key company-active-map (kbd "<down>") 'company-select-next)
))
;; activate global-company-mode
(add-hook 'after-init-hook 'global-company-mode)
)
When company
is actively used by browsing completion candidates, <return>
should execute the selected completion.
;; Taken from https://github.com/company-mode/company-mode/issues/530.
(defun my-company-active-return ()
(interactive)
(if (company-explicit-action-p)
(company-complete)
(call-interactively
(or (key-binding (this-command-keys))
(key-binding (kbd "RET")))
)))
(define-key company-active-map (kbd "<return>") #'my-company-active-return)
(define-key company-active-map (kbd "RET") #'my-company-active-return)
https://github.com/dunn/company-emoji
company backend for emojis. Recommended to be used with emacs-emojify.
(use-package company-emoji
:ensure t
:config
(add-to-list 'company-backends 'company-emoji))
https://github.com/PythonNut/company-flx
Add fuzzy matching capabilities with flx
:
(use-package company-flx
:ensure t
:config
(with-eval-after-load 'company
(company-flx-mode +1)))
https://github.com/vspinu/company-math
Add company completions for LaTeX and unicode math symbols.
(use-package company-math
:ensure t
:config
;; (add-to-list 'company-backends 'company-math-symbols-unicode) ; insert unicode symbol
(add-to-list 'company-backends 'company-math-symbols-latex) ; insert LaTeX code
)
https://github.com/alexeyr/company-auctex/
Add company completions for AUCTeX.
(use-package company-auctex
:ensure t
:config (company-auctex-init))
https://github.com/TheBB/company-reftex
Add company completions for citations and label references in LaTeX based on RefTeX.
(use-package company-reftex
:ensure t
:config
(add-to-list 'company-backends 'company-reftex-labels)
(add-to-list 'company-backends 'company-reftex-citations)
)
Execute when all backends added to company-backends
.
;; Code from https://emacs.stackexchange.com/a/10520/12336
(defvar company-mode/enable-yas t
"Enable yasnippet for all backends.")
(defun company-mode/backend-with-yas (backend)
(if (or (not company-mode/enable-yas)
(and (listp backend) (member 'company-yasnippet backend)))
backend
(append (if (consp backend) backend (list backend))
'(:with company-yasnippet))))
(setq company-backends (mapcar #'company-mode/backend-with-yas company-backends))
https://github.com/nashamri/academic-phrases
Choose from a collection of academic phrases.
(use-package academic-phrases
:ensure t)
https://github.com/minad/tempel
Another package for writing text templates, which is a little simpler than yasnippet. Templates are stored in templates/tempel/templates
(use-package tempel
:ensure t
;; :bind (("M-+" . tempel-complete) ;; Alternative tempel-expand
;; ("M-*" . tempel-insert))
:init
;; Setup completion at point
(defun tempel-setup-capf ()
;; Add the Tempel Capf to `completion-at-point-functions'.
;; `tempel-expand' only triggers on exact matches. Alternatively use
;; `tempel-complete' if you want to see all matches, but then you
;; should also configure `tempel-trigger-prefix', such that Tempel
;; does not trigger too often when you don't expect it. NOTE: We add
;; `tempel-expand' *before* the main programming mode Capf, such
;; that it will be tried first.
(setq-local completion-at-point-functions
(cons #'tempel-complete
completion-at-point-functions)))
(add-hook 'conf-mode-hook 'tempel-setup-capf)
(add-hook 'prog-mode-hook 'tempel-setup-capf)
(add-hook 'text-mode-hook 'tempel-setup-capf)
;; Optionally make the Tempel templates available to Abbrev,
;; either locally or globally. `expand-abbrev' is bound to C-x '.
;; (add-hook 'prog-mode-hook #'tempel-abbrev-mode)
;; (global-tempel-abbrev-mode)
:config
(setq tempel-path (expand-file-name "templates/tempel/*" user-emacs-directory))
;; Require trigger prefix before template name when completing.
(setq tempel-trigger-prefix nil)
)
;; Optional: Add tempel-collection.
;; The package is young and doesn't have comprehensive coverage.
;; (use-package tempel-collection)
;; Optional: Use the Corfu completion UI
;; (use-package corfu
;; :init
;; (global-corfu-mode))
https://www.gnu.org/software/emacs/manual/html_node/emacs/Flymake.html
Flymake is a built-in syntax checker for many programming languages. I’m currently using flycheck.
https://www.flycheck.org/en/latest/
Syntax checking extension for Emacs, intended as a replacement of Flymake. Additional syntax checking programs for the supported programming languages are required for Flycheck to work.
(use-package flycheck
:ensure t
:config
(global-flycheck-mode t)
(add-hook 'text-mode-hook #'(lambda ()(flycheck-mode 0))) ; See flycheck-vale
)
https://github.com/alexmurray/flycheck-plantuml
Flycheck support of PlantUML code.
(use-package flycheck-plantuml
:ensure t
:after (flycheck plantuml)
:config (flycheck-plantuml-setup))
https://www.gnu.org/software/emacs/manual/html_node/emacs/Spelling.html
- Using multiple dictionaries:
https://www.gnu.org/software/emacs/manual/html_node/emacs/Spelling.html
ispell
is the built-in spell checking routine.
Tell ispell
which back-end to use:
(setq ispell-program-name "aspell")
Comparisons of spell checkers:
- http://aspell.net/test/cur/
- https://battlepenguin.com/tech/aspell-and-hunspell-a-tale-of-two-spell-checkers/
Note on aspell
:
- Unfortunately,
ispell-program-name
does not allow for also specifyingaspell
options. This would be desirable for changing, e.g.,home-dir
. - Newer versions of aspell do not have the CL option
home-dir
any more. Instead, a configuration file.aspell.conf
in the home directory should be used.
The following sets the home-dir
option via .aspell.conf
:
(if (and (file-exists-p "~/.aspell.conf")
personal-dictionary-dir)
(with-temp-buffer
(insert (concat "home-dir " personal-dictionary-dir))
(write-region (point-min) (point-max) "~/.aspell.conf")))
https://www.gnu.org/software/emacs/manual/html_node/emacs/Spelling.html
Built-in on-the-fly spell checking.
;; remove keybindings for autocorrect
(eval-after-load "flyspell"
'(define-key flyspell-mode-map (kbd "C-;") nil))
(eval-after-load "flyspell"
'(define-key flyspell-mode-map (kbd "C-.") nil))
;; ;; activate for text
;; (dolist (hook '(text-mode-hook LaTeX-mode-hook))
;; (add-hook hook (lambda () (flyspell-mode 1))))
(defun flyspell-toggle (arg)
(interactive "p")
(if (bound-and-true-p flyspell-mode)
(progn
(flyspell-mode -1)
)
(progn
(flyspell-buffer)
(flyspell-mode)
)))
;; move point to previous error
;; http://emacs.stackexchange.com/a/14912/2017
(defun flyspell-goto-previous-error (arg)
"Go to arg previous spelling error."
(interactive "p")
(while (not (= 0 arg))
(let ((pos (point))
(min (point-min)))
(if (and (eq (current-buffer) flyspell-old-buffer-error)
(eq pos flyspell-old-pos-error))
(progn
(if (= flyspell-old-pos-error min)
;; goto beginning of buffer
(progn
(message "Restarting from end of buffer")
(goto-char (point-max)))
(backward-word 1))
(setq pos (point))))
;; seek the next error
(while (and (> pos min)
(let ((ovs (overlays-at pos))
(r '()))
(while (and (not r) (consp ovs))
(if (flyspell-overlay-p (car ovs))
(setq r t)
(setq ovs (cdr ovs))))
(not r)))
(backward-word 1)
(setq pos (point)))
;; save the current location for next invocation
(setq arg (1- arg))
(setq flyspell-old-pos-error pos)
(setq flyspell-old-buffer-error (current-buffer))
(goto-char pos)
(if (= pos min)
(progn
(message "No more miss-spelled word!")
(setq arg 0))))))
(defun flyspell-next-and-ispell-word (args)
""
(interactive "P")
(progn
(flyspell-goto-next-error)
(ispell-word)))
(defun flyspell-previous-and-ispell-word (args)
""
(interactive "P")
(progn
(flyspell-goto-previous-error)
(ispell-word)))
(defun flyspell-goto-next-and-correct (args)
""
(interactive "P")
(progn
(flyspell-goto-next-error)
(flyspell-correct-word-generic)
(right-char)))
(defun flyspell-goto-previous-and-correct (args)
""
(interactive "P")
(progn
(flyspell-goto-previous-error 1)
(flyspell-correct-word-generic)
(left-word)))
Flyspell face:
(face-spec-set 'flyspell-incorrect '((t (:inherit error))))
https://github.com/d12frosted/flyspell-correct
Correcting misspelled words with flyspell using your favourite interface. Mine is helm.
(use-package flyspell-correct
:ensure t
:after flyspell
:config
(use-package flyspell-correct-helm
:ensure t)
;; (add-hook 'flyspell-mode-hook #'flyspell-correct-auto-mode)
;; (setq flyspell-correct-auto-delay 0.8)
:bind ("M-$" . flyspell-correct-at-point)
)
https://github.com/tmalsburg/guess-language.el
Minor mode for robust automatic language detection that automatically switches the spell checker accordingly.
This mode assumes that flyspell is activated and configured for all relevant languages, i.e., those listed in guess-language-languages
.
(use-package guess-language
:ensure t
:pin MELPA
:init (add-hook 'text-mode-hook #'guess-language-mode)
:config
(setq guess-language-languages '(en de))
(setq guess-language-min-paragraph-length 35)
:diminish guess-language-mode)
To see what dictionaries are installed, call
(mapcar 'car ispell-dictionary-alist)
https://codeberg.org/ideasman42/emacs-spell-fu
Fast spell checking without external programs.
- State “TODO” from [2024-11-02 Sat 21:40]
- [ ] Compilation throws an error
https://github.com/minad/jinx
An alternative to flyspell that uses Enchant. Only the visible part of the buffer is checked.
Requirements:
- libenchant-2-dev (>v2.3.1)
- pkgconf
(use-package jinx
:ensure t
;; :hook (emacs-startup . global-jinx-mode)
;; :bind (("M-$" . jinx-correct)
;; ("C-M-$" . jinx-languages))
)
Grammar checking with LanguageTool. It requires to download resources from here: https://languagetool.org/download/
(use-package langtool
:ensure t
:config
(setq langtool-language-tool-jar
(expand-file-name (concat langtool-dir "/languagetool-commandline.jar"))))
https://github.com/Fuco1/smartparens
Dealing with pairs of symbols (e.g. parens) in Emacs. Similar to embrace.
(use-package smartparens
:ensure t
:init
(--each '(LaTeX-mode-hook
R-mode-hook
TeX-mode-hook
bibtex-mode-hook
css-mode-hook
emacs-lisp-mode-hook
java-mode-hook
js-mode-hook
markdown-mode-hook
mu4e-compose-mode-hook
org-mode-hook
perl-mode-hook
plantuml-mode-hook
python-mode-hook
sh-mode-hook
shell-mode-hook
xmg-mode-hook
web-mode-hook)
(add-hook it #'smartparens-mode))
(require 'smartparens-config) ; loads configurations for several modes, e.g. latex-mode
:config
(setq sp-autoescape-string-quote nil)
(setq sp-show-pair-from-inside nil)
(setq smartparens-strict-mode t) ; skip over delimiters when deleting
;; for all modes
(sp-pair "(" nil :unless '(sp-point-before-word-p))
(sp-pair "[" nil :unless '(sp-point-before-word-p))
(sp-pair "{" nil :unless '(sp-point-before-word-p))
(sp-pair "\"" nil :unless '(sp-point-before-word-p
sp-point-after-word-p
tl/sp-point-next-to-non-space-p))
;; org-mode
(sp-with-modes '(org-mode mu4e-compose-mode)
(sp-local-pair "*" "*"
;; :actions '(insert wrap) ; Don't know what this is good for.
:unless '(sp-point-before-word-p
sp-point-after-word-p
sp-point-at-bol-p
sp-in-math-p
tl/sp-point-next-to-non-space-p) )
(sp-local-pair "_" "_" :unless '(sp-point-before-word-p
sp-point-after-word-p
sp-in-math-p
tl/sp-point-next-to-non-space-p) )
(sp-local-pair "/" "/" :unless '(sp-point-before-word-p
sp-point-after-word-p
sp-in-math-p
tl/sp-point-next-to-non-space-p) )
(sp-local-pair "~" "~" :unless '(sp-point-before-word-p
sp-point-after-word-p
sp-in-math-p
tl/sp-point-next-to-non-space-p) )
(sp-local-pair "=" "=" :unless '(sp-point-before-word-p
sp-point-after-word-p
sp-in-math-p
tl/sp-point-next-to-non-space-p) )
(sp-local-pair "+" "+" :unless '(sp-point-before-word-p
sp-point-after-word-p
sp-in-math-p
tl/sp-point-next-to-non-space-p) )
(sp-local-pair "$" "$" :unless '(sp-point-before-word-p
sp-point-after-word-p
tl/sp-point-next-to-non-space-p) )
(sp-local-pair "«" "»"))
;; latex-mode
(sp-local-pair 'LaTeX-mode "$" nil :unless '(sp-point-before-word-p sp-point-after-word-p))
)
(defun tl/sp-point-after-hash-p (id action context)
"Return t if point is after a hash, nil otherwise.
This predicate is only tested on \"insert\" action.
Its definition follows the one of sp-point-after-word-p."
(when (eq action 'insert)
(sp--looking-back-p (concat "\\(#\\)" (regexp-quote id)))))
(defun tl/sp-point-next-to-non-space-p (id action context)
"Return t if the character before or after point is a non-space
character. This predicate is only tested on \"insert\" action. Its
definition follows the one of sp-point-after-word-p."
(and (eq action 'insert)
(or (sp--looking-back-p "[^ \t\n]")
(sp--looking-at-p "[^ \t\n]"))))
;; jump to matching paren
(defun goto-match-paren (arg)
"Go to the matching if on (){}[], similar to vi style of % "
(interactive "p")
;; first, check for "outside of bracket" positions expected by forward-sexp, etc.
(cond ((looking-at "[\[\(\{]") (forward-sexp))
((looking-back "[\]\)\}]" 1) (backward-sexp))
;; now, try to succeed from inside of a bracket
((looking-at "[\]\)\}]") (forward-char) (backward-sexp))
((looking-back "[\[\(\{]" 1) (backward-char) (forward-sexp))
(t nil)))
(global-set-key (kbd "C-M-m") 'goto-match-paren)
(global-set-key (kbd "M-(") 'sp-backward-sexp)
(global-set-key (kbd "M-)") 'sp-forward-sexp)
(global-set-key (kbd "M-m") 'goto-match-paren)
(global-set-key (kbd "M-[") 'sp-beginning-of-sexp)
(global-set-key (kbd "M-]") 'sp-end-of-sexp)
(global-set-key (kbd "M-DEL") nil)
(global-set-key (kbd "M-DEL M-[") 'sp-unwrap-sexp)
;; https://ebzzry.github.io/emacs-pairs.html
;; (defmacro def-pairs (pairs)
;; `(progn
;; ,@(loop for (key . val) in pairs
;; collect
;; `(defun ,(read (concat
;; "wrap-with-"
;; (prin1-to-string key)
;; "s"))
;; (&optional arg)
;; (interactive "p")
;; (sp-wrap-with-pair ,val)))))
;; (def-pairs ((paren . "(")
;; (bracket . "[")
;; (brace . "{")
;; (single-quote . "'")
;; (double-quote . "\"")
;; (back-quote . "`")))
;; (global-set-key (kbd "C-[") 'wrap-with-brackets) ; TODO: find nice key bindings
;; (global-set-key (kbd "C-(") 'wrap-with-parens)
;; (global-set-key (kbd "C-{") 'wrap-with-braces)
- State “TODO” from [2018-09-03 Mo 23:13]
https://github.com/cute-jumper/embrace.el
Add/Change/Delete pairs based on expand-region
, similar to evil-surround
and smartparens.
Issues:
- [ ] Still does not load correctly in
org-mode
.
(use-package embrace
:ensure t
;; :hook (org-mode . embrace-org-mode-hook)
:bind
(("C-( a" . embrace-add)
("C-( d" . embrace-delete)
("C-( c" . embrace-change))
:config
(defun tl/embrace-delete-* ()
(interactive)
(embrace--delete ?*))
(defun tl/embrace-delete-/ ()
(interactive)
(embrace--delete ?/))
(defun tl/embrace-delete-_ ()
(interactive)
(embrace--delete ?_))
(defun tl/embrace-delete-+ ()
(interactive)
(embrace--delete ?+))
(defun tl/embrace-delete-= ()
(interactive)
(embrace--delete ?=))
(defun tl/embrace-delete-~ ()
(interactive)
(embrace--delete ?~))
(defun tl/embrace-org-mode-hook ()
"Mostly taken from embrace-org-mode-hook which is defined in embrace.el."
(dolist (lst '((?= "=" . "=")
(?~ "~" . "~")
(?/ "/" . "/")
(?* "*" . "*")
(?_ "_" . "_")
(?+ "+" . "+")
(?k "@@html:<kbd>@@" . "@@html:</kbd>@@")
(?l "@@latex:" . "@@")))
(embrace-add-pair (car lst) (cadr lst) (cddr lst)))
(embrace-add-pair-regexp ?b "#\\+BEGIN_.*" "#\\+END_.*" 'embrace-with-org-block
(embrace-build-help "#+BEGIN_*" "#+END") t))
;; (add-hook 'LaTeX-mode-hook 'embrace-LaTeX-mode-hook)
;; (add-hook 'org-mode-hook 'embrace-org-mode-hook)
(add-hook 'org-mode-hook 'tl/embrace-org-mode-hook))
Auto-indent when yanking https://www.emacswiki.org/emacs/AutoIndentation
(dolist (command '(yank yank-pop))
(eval `(defadvice ,command (after indent-region activate)
(and (not current-prefix-arg)
(member major-mode '(emacs-lisp-mode lisp-mode
clojure-mode scheme-mode
haskell-mode ruby-mode
rspec-mode python-mode
c-mode c++-mode
objc-mode latex-mode
plain-tex-mode))
(let ((mark-even-if-inactive transient-mark-mode))
(indent-region (region-beginning) (region-end) nil))))))
Shift/delete indentation at cursor position or region:
;; shift-region is taken from http://stackoverflow.com/a/6918574/6452961
(defun shift-region (distance)
"Shift the selected region right if distance is positive, left if negative"
(let ((mark (mark)))
(save-excursion
(indent-rigidly (region-beginning) (region-end) distance)
(push-mark mark t t)
;; Tell the command loop not to deactivate the mark
;; for transient mark mode
(setq deactivate-mark nil))))
(defun tl/delete-indentation ()
(interactive)
(if (use-region-p)
(shift-region -999)
(indent-rigidly (line-beginning-position) (line-end-position) -999)
))
https://github.com/Malabarba/aggressive-indent-mode
aggressive-indent-mode
is a minor mode that keeps your code always indented.
Not sure whether I want to auto-indent whole files …
(use-package aggressive-indent
:ensure t
:config
;; (add-hook 'prog-mode-hook #'aggressive-indent-mode) ; Bad: Will also be active in Makefiles
;; (dolist (hook '(emacs-lisp-mode-hook
;; css-mode-hook
;; clojure-mode))
;; (add-hook hook #'aggressive-indent-mode))
(global-aggressive-indent-mode)
(add-to-list 'aggressive-indent-excluded-modes 'html-mode)
(add-to-list 'aggressive-indent-excluded-modes 'sql-mode)
(add-to-list 'aggressive-indent-excluded-modes 'web-mode)
(add-to-list 'aggressive-indent-excluded-modes 'makefile-mode)
)
- State “TODO” from [2025-01-10 Fri 08:30]
https://github.com/DarthFennec/highlight-indent-guides
Show vertical line per indentation level.
Issues:
- [ ] Vertical lines sometimes do not have the right color (white or barely visible). This is independent of
highlight-indent-guides-method
.
(use-package highlight-indent-guides
:ensure t
:config
(add-hook 'prog-mode-hook 'highlight-indent-guides-mode)
(setq highlight-indent-guides-method 'bitmap)
)
- State “TODO” from [2024-09-26 Thu 14:45]
https://github.com/jdtsmith/indent-bars
Indentation guide supporting tree-sitter. Maybe an alternative to highlight-indent-guides?
https://github.com/magnars/expand-region.el
Expand region increases the selected region by semantic units. I’ve bound it to C-+
.
(use-package expand-region
:ensure t
:bind ("C-+" . er/expand-region)
)
https://github.com/casouri/expreg
Similar to expand-region, but uses tree-sitter.
- State “TODO” from [2021-02-11 Thu 09:22]
Copy mouse selection to kill-ring:
;; (setq mouse-drag-copy-region t)
Drag’n drop of text with the mouse:
(setq mouse-drag-and-drop-region t)
- [ ] Does not work in org-mode
https://github.com/rejeep/drag-stuff.el
Drag around marked stuff (words, region, lines) with the keyboard.
There is a irreconcilable conflict in the key bindings of drag-stuff
and org-mode
, see here. I have therefore added hydra-drag-stuff and will use it in hydra-transpose.
(use-package drag-stuff
:ensure t
:config
(drag-stuff-global-mode 1)
;; (drag-stuff-define-keys) ; Use <M-up>, <M-down>, <M-left> and <M-right>
)
https://github.com/victorhge/iedit
Edit regions with identical content in the same way simultaneously. Cool!
(use-package iedit
:ensure t)
(use-package hideshow
:ensure t
:diminish hs-minor-mode
:config
(add-hook 'prog-mode-hook 'hs-minor-mode))
hideshow-org
adds org-mode like folding experience to hideshow.
(use-package hideshow-org
:ensure t
:config
(add-hook 'prog-mode-hook 'hs-org/minor-mode))
(global-set-key (kbd "<mouse-3>") 'mouse-major-mode-menu)
(global-set-key (kbd "<C-down-mouse-3>") 'mouse-popup-menubar)
Org-mode has its own context menu:
(require 'org-mouse)
https://www.emacswiki.org/emacs/download/lacarte.el
Menu completion at the keyboard
(use-package lacarte
:bind ("C-<f6>" . lacarte-execute-menu-command))
This is supposed to accelerate cursor movement (https://emacs.stackexchange.com/a/28746/12336):
(setq auto-window-vscroll nil)
https://github.com/winterTTr/ace-jump-mode
Fasting moving of the cursor to any position in the buffer. Just type the first character of the word or line, and then type the shown jump code.
(use-package ace-jump-mode
:ensure t
:bind
("C-c SPC" . ace-jump-mode))
https://github.com/jacktasia/dumb-jump
Jump to definition without using tags. Requires external programs (ag
, rg
).
This packages uses the xref interface of Emacs.
(use-package dumb-jump
:ensure t
:bind (("M-g o" . dumb-jump-go-other-window)
("M-g j" . dumb-jump-go)
("M-g x" . dumb-jump-go-prefer-external)
("M-g z" . dumb-jump-go-prefer-external-other-window))
:config
(add-hook 'xref-backend-functions #'dumb-jump-xref-activate)
(setq dumb-jump-selector 'helm
dumb-jump-max-find-time 10)
)
https://github.com/magnars/multiple-cursors.el
Multiple cursors for Emacs. Super cool!
(use-package multiple-cursors
:ensure t
;; :bind
;; ("C-S-c C-S-c" . mc/edit-lines)
;; ("C->" . mc/mark-next-like-this)
;; ("C-<" . mc/mark-previous-like-this)
;; ("C-c C-<" . mc/mark-all-like-this)
)
Cursor position history (LOCAL)
(require 'point-undo)
(global-set-key [M-left] 'point-undo)
(global-set-key [M-right] 'point-redo)
(global-set-key (kbd "M-j") 'point-undo)
(global-set-key (kbd "M-k") 'point-redo)
;; focus on line-based jumps
;; http://emacs.stackexchange.com/a/28078/12336
(defvar point-undo-ring-length 100)
(defvar point-undo-ring (make-ring point-undo-ring-length))
(make-variable-buffer-local 'point-undo-ring)
(defvar point-redo-ring (make-ring point-undo-ring-length))
(make-variable-buffer-local 'point-redo-ring)
(defun point-undo-pre-command-hook ()
"Save positions before command."
(unless (or (eq this-command 'point-undo)
(eq this-command 'point-redo))
(let ((line (line-number-at-pos)))
(when (eq line (cdr (nth 0 (ring-elements point-undo-ring))))
(ring-remove point-undo-ring 0))
(ring-insert point-undo-ring (cons (point) line))
(setq point-redo-ring (make-ring point-undo-ring-length)))))
(add-hook 'pre-command-hook 'point-undo-pre-command-hook)
(defun point-undo-doit (ring1 ring2)
"ring1, ring2 = {point-undo-ring, point-redo-ring}"
(condition-case nil
(progn
(goto-char (car (nth 0 (ring-elements ring1))))
(ring-insert ring2 (ring-remove ring1 0)))
(error nil)))
(defun point-undo ()
"Undo position."
(interactive)
(point-undo-doit point-undo-ring point-redo-ring))
(defun point-redo ()
"Redo position."
(interactive)
(when (or (eq last-command 'point-undo)
(eq last-command 'point-redo))
(point-undo-doit point-redo-ring point-undo-ring)))
https://elpa.gnu.org/packages/cursor-undo.html
https://github.com/camdez/goto-last-change.el
Move cursor position back in undo history.
(use-package goto-last-change
:ensure t
:bind
("M-_" . goto-last-change))
Copied from http://emacsredux.com/blog/2013/05/22/smarter-navigation-to-the-beginning-of-a-line/
(defun my/smarter-move-beginning-of-line (arg)
"Move point back to indentation of beginning of line.
Move point to the first non-whitespace character on this line.
If point is already there, move to the beginning of the line.
Effectively toggle between the first non-whitespace character and
the beginning of the line.
If ARG is not nil or 1, move forward ARG - 1 lines first. If
point reaches the beginning or end of the buffer, stop there."
(interactive "^p")
(setq arg (or arg 1))
;; Move lines first
(when (/= arg 1)
(let ((line-move-visual nil))
(forward-line (1- arg))))
(let ((orig-point (point)))
(back-to-indentation)
(when (= orig-point (point))
(move-beginning-of-line 1))))
;; remap C-a to `smarter-move-beginning-of-line'
(global-set-key [remap move-beginning-of-line]
'my/smarter-move-beginning-of-line)
https://github.com/atykhonov/iregister.el
Helper functions to use the Emacs register (to save positions, text and more) interactively. They are primarily used in hydra-position-register.
(use-package iregister
:ensure t)
https://github.com/chuntaro/emacs-keypression
https://github.com/jschaf/emacs-lorem-ipsum
Nam euismod tellus id erat.
(use-package lorem-ipsum
:ensure t
:config
(global-set-key (kbd "C-c i l") 'lorem-ipsum-insert-paragraphs)
)
https://www.dr-qubit.org/undo-tree.html https://gitlab.com/tsc25/undo-tree
Visualize the undo history.
Issues:
- [X] waiting for v0.8 to appear on elpa
- In retrospect, I don’t remember the exact reason. Maybe a broken undo history in v0.7?
(use-package undo-tree
:ensure t
:diminish undo-tree-mode
:config
(global-undo-tree-mode)
(setq undo-tree-visualizer-timestamps t
undo-tree-visualizer-diff t)
(global-unset-key (kbd "C-z"))
(global-set-key (kbd "C-z") 'undo-tree-undo)
(global-set-key (kbd "C-S-z") 'undo-tree-redo)
:custom
(undo-tree-auto-save-history nil)
)
https://github.com/casouri/vundo
Visual helper for the regular undo. See blog post: https://archive.casouri.cat/note/2021/visual-undo-tree/index.html Requires Emacs 28.
- alternative: shrink-whitespace
http://stackoverflow.com/a/5194503
(defun remove-newlines-in-region ()
"Removes all newlines in the region."
(interactive)
(save-restriction
(narrow-to-region (point) (mark))
(goto-char (point-min))
(while (search-forward "\n" nil t) (replace-match " " nil t))))
(defun remove-newline ()
(save-excursion
(search-forward "\n")
(replace-match " ")))
(defun remove-newlines-or-blank-lines-dwim ()
(interactive)
(progn (if (use-region-p)
(remove-newlines-in-region)
(if (this-line-empty-p)
(delete-blank-lines)
(remove-newline)
))))
(defun next-line-empty-p ()
(save-excursion
(next-line)
(beginning-of-line)
(looking-at "[[:space:]]*$")))
(defun this-line-empty-p ()
(save-excursion
(beginning-of-line)
(looking-at "[[:space:]]*$")))
- alternative: shrink-whitespace
Remove extra spaces from line or region (TODO):
(defun tl/remove-extra-spaces-dwim ()
"Remove extra spaces in line or in region."
(interactive)
(if (region-active-p)
(save-restriction
(narrow-to-region (point) (mark))
(save-excursion
(goto-char (point-min))
(while (re-search-forward "[ ]+" nil t) (replace-match " " nil t))))
(save-excursion
(move-beginning-of-line nil) ; FIXME: undo doesn't see save-excursion
(while (re-search-forward "[ ]+" (line-end-position) t)
(replace-match " "))))
)
https://github.com/nflath/hungry-delete
Delete consecutive white space characters in one go.
(use-package hungry-delete
:ensure t
;; :config
;; (global-hungry-delete-mode)
)
- State “TODO” from [2018-11-09 Fri 19:00]
https://github.com/leoliu/easy-kill https://emacsredux.com/blog/2018/11/09/an-easy-kill/
https://github.com/benma/visual-regexp.el
Like replace-regexp
, but with live visual feedback directly in the buffer.
(use-package visual-regexp
:ensure t
:config
(define-key global-map (kbd "C-c r") 'vr/replace)
(define-key global-map (kbd "C-c q") 'vr/query-replace))
https://github.com/benma/visual-regexp-steroids.el/
This is an extension to visual-regexp for using more standard (i.e. Python) regular expressions. There is also an interface to multiple-cursors.
(use-package visual-regexp-steroids
:ensure t)
https://github.com/szermatt/visual-replace
Visual helper for standard query-replace in Emacs similar to visual-regexp, but with a prompt that lets one modify the search and the replacement at the same time.
I’m not using it right now.
Taken from http://endlessparentheses.com/emacs-narrow-or-widen-dwim.html:
(defun narrow-or-widen-dwim (p)
"Widen if buffer is narrowed, narrow-dwim otherwise.
Dwim means: region, org-src-block, org-subtree, or
defun, whichever applies first. Narrowing to
org-src-block actually calls `org-edit-src-code'.
With prefix P, don't widen, just narrow even if buffer
is already narrowed."
(interactive "P")
(declare (interactive-only))
(cond ((and (buffer-narrowed-p) (not p)) (widen))
((region-active-p)
(narrow-to-region (region-beginning)
(region-end)))
((derived-mode-p 'org-mode)
;; `org-edit-src-code' is not a real narrowing
;; command. Remove this first conditional if
;; you don't want it.
(cond ((ignore-errors (org-edit-src-code) t)
(delete-other-windows))
((ignore-errors (org-narrow-to-block) t))
(t (org-narrow-to-subtree))))
((derived-mode-p 'latex-mode)
(LaTeX-narrow-to-environment))
(t (narrow-to-defun))))
;; This line actually replaces Emacs' entire narrowing
;; keymap, that's how much I like this command. Only
;; copy it if that's what you want.
(define-key ctl-x-map "n" #'narrow-or-widen-dwim)
(add-hook 'LaTeX-mode-hook
(lambda ()
(define-key LaTeX-mode-map "\C-xn"
nil)))
The keymap in org-mode
seems to require a special treatment:
(add-hook 'org-mode-hook
(lambda ()
(define-key org-mode-map "\C-xn"
nil)))
Taken from https://emacs.stackexchange.com/a/21356/12336:
(defun org-narrow-to-here ()
"Exclude the current heading while narrowing."
(interactive)
(save-excursion
(narrow-to-region
(progn (unless (org-at-heading-p) (org-next-visible-heading -1))
(forward-line)
(point))
(progn (org-next-visible-heading 1)
(point)))))
C-;
is used to insert inline comments across major modes.
(global-set-key (kbd "C-;") 'comment-or-uncomment-region-or-line)
(eval-after-load "LaTeX-mode"
'(define-key LaTeX-mode-map (kbd "C-;") 'comment-or-uncomment-region-or-line))
(eval-after-load "markdown-mode"
'(define-key LaTeX-mode-map (kbd "C-;") 'comment-or-uncomment-region-or-line))
(defun comment-or-uncomment-region-or-line ()
"Comments or uncomments the region or the current line if there's no active region."
(interactive)
(let (beg end)
(if (region-active-p)
(setq beg (region-beginning) end (region-end))
(setq beg (line-beginning-position) end (line-end-position)))
(comment-or-uncomment-region beg end)
(next-line)))
(defun insert-comment-box ()
"Insert a comment box around the region."
(interactive)
(comment-box (region-beginning) (region-end)))
https://github.com/QBobWatson/poporg
Poporg lets one edit comments in a separate buffer.
(use-package poporg
:ensure t
:bind (("C-c '" . poporg-dwim))
:init
(setq-default poporg-edit-hook 'org-mode)
(add-hook 'TeX-mode-hook
#'(lambda ()
"poporg configuration"
(define-key TeX-mode-map (kbd "C-c '") 'poporg-dwim)
(setq poporg-edit-hook 'TeX-mode)))
(add-hook 'LaTeX-mode-hook
#'(lambda ()
"poporg configuration"
(define-key LaTeX-mode-map (kbd "C-c '") 'poporg-dwim)
(setq poporg-edit-hook 'LaTeX-mode)))
:config
(define-key poporg-mode-map (kbd "C-c '") 'poporg-dwim))
https://github.com/joostkremers/criticmarkup-emacs
Support of CriticMarkup in Emacs.
(use-package cm-mode
:ensure t
:config
(setq-default cm-author user-acronym))
http://kitchingroup.cheme.cmu.edu/blog/2015/04/24/Commenting-in-org-files/
- State “TODO” from [2023-12-23 Sat 12:19]
https://github.com/davep/boxquote.el
Mark quotes with brackets on the left side.
,----[ Title ] | Example quote `----
Issues
- [ ] Create hydra for boxquotes
(use-package boxquote
:ensure t
:pin MELPA)
Additional DWIM function to use boxquote:
(defun boxquote-dwim ()
"Do what I mean when using boxquote."
(interactive)
(if (region-active-p)
(if (boxquote-quoted-p)
(call-interactively 'boxquote-unbox-region)
(call-interactively 'boxquote-region))
(if (boxquote-quoted-p)
(call-interactively 'boxquote-unbox)
(call-interactively 'boxquote-text))))
Some general keys (I barely use):
;; (global-set-key (kbd "C-d C-o") 'delete-blank-lines) ; not allowed here, see underi-mode.el
;; (global-set-key (kbd "C-d C-m") 'delete-blank-lines)
(global-set-key (kbd "C-S-k") 'kill-whole-line)
;; (global-set-key (kbd "C-k") 'kill-sentence) ; too greedy
(global-set-key (kbd "C-S-d") 'kill-whole-line)
Copy/cut whole line or region (I mostly use):
(global-set-key (kbd "C-w") 'xah-cut-line-or-region) ; cut
(global-set-key (kbd "M-w") 'xah-copy-line-or-region) ; copy
(defun xah-cut-line-or-region ()
"Cut current line, or text selection.
When `universal-argument' is called first, cut whole buffer (respects `narrow-to-region').
URL `http://ergoemacs.org/emacs/emacs_copy_cut_current_line.html'
Version 2015-06-10"
(interactive)
(if current-prefix-arg
(progn ; not using kill-region because we don't want to include previous kill
(kill-new (buffer-string))
(delete-region (point-min) (point-max)))
(progn (if (use-region-p)
(kill-region (region-beginning) (region-end) t)
(kill-region (line-beginning-position) (line-beginning-position 2))))))
(defun xah-copy-line-or-region ()
"Copy current line, or text selection.
When called repeatedly, append copy subsequent lines.
When `universal-argument' is called first, copy whole buffer (respects `narrow-to-region').
URL `http://ergoemacs.org/emacs/emacs_copy_cut_current_line.html'
Version 2016-06-18"
(interactive)
(let (-p1 -p2)
(if current-prefix-arg
(setq -p1 (point-min) -p2 (point-max))
(if (use-region-p)
(setq -p1 (region-beginning) -p2 (region-end))
(setq -p1 (line-beginning-position) -p2 (line-end-position))))
(if (eq last-command this-command)
(progn
(progn ; hack. exit if there's no more next line
(end-of-line)
(forward-char)
(backward-char))
;; (push-mark (point) "NOMSG" "ACTIVATE")
(kill-append "\n" nil)
(kill-append (buffer-substring-no-properties (line-beginning-position) (line-end-position)) nil)
(message "Line copy appended"))
(progn
(kill-ring-save -p1 -p2)
(if current-prefix-arg
(message "Buffer text copied")
(message "Text copied"))))
;; TL: commented out the following two lines. Cursor remains at region.
;; (end-of-line)
;; (forward-char)
))
(global-set-key (kbd "S-<return>") 'smart-open-line)
(global-set-key (kbd "C-x C-<return>") 'smart-open-line)
(global-set-key (kbd "C-S-<return>") 'smart-open-line-above)
(global-set-key (kbd "C-o") 'smart-open-line)
(global-set-key (kbd "C-S-o") 'smart-open-line-above)
;; http://emacsredux.com/blog/2013/03/26/smarter-open-line/
(defun smart-open-line ()
"Insert an empty line after the current line.
Position the cursor at its beginning, according to the current mode."
(interactive)
(move-end-of-line nil)
(newline-and-indent))
;; http://emacsredux.com/blog/2013/06/15/open-line-above/
(defun smart-open-line-above ()
"Insert an empty line above the current line.
Position the cursor at it's beginning, according to the current mode."
(interactive)
(move-beginning-of-line nil)
(newline-and-indent)
(forward-line -1)
(indent-according-to-mode))
This comes from vanilla Emacs:
(global-set-key (kbd "C-l") 'recenter-top-bottom)
https://github.com/emacsfodder/move-text
Move line or region up and down in a buffer using M-<up>
and M-<down>
.
(use-package move-text
:ensure t
:init
(move-text-default-bindings)
)
http://xahlee.info/emacs/emacs/modernization_upcase-word.html
Cycle through different kinds of capitalization. Requires titlecase.
(global-set-key (kbd "C-7") 'xah-toggle-letter-case)
(defun xah-toggle-letter-case ()
"Toggle the letter case of current word or text selection.
Always cycle in this order: Init Caps, ALL CAPS, all lower.
URL `http://xahlee.info/emacs/emacs/modernization_upcase-word.html'
Version 2020-06-26"
(interactive)
(let (
(deactivate-mark nil)
$p1 $p2)
(if (use-region-p)
(setq $p1 (region-beginning) $p2 (region-end))
(save-excursion
(skip-chars-backward "[:alpha:]")
(setq $p1 (point))
(skip-chars-forward "[:alpha:]")
(setq $p2 (point))))
(when (not (eq last-command this-command))
(put this-command 'state 0))
(cond
((equal 0 (get this-command 'state))
(upcase-initials-region $p1 $p2)
(put this-command 'state 1))
((equal 1 (get this-command 'state))
(upcase-region $p1 $p2)
(put this-command 'state 2))
((equal 2 (get this-command 'state))
(downcase-region $p1 $p2)
(put this-command 'state 3))
((equal 3 (get this-command 'state))
(titlecase-dwim)
(put this-command 'state 0)))))
https://github.com/duckwork/titlecase.el
Convert text to title case in Emacs
(use-package titlecase
:ensure t)
Insert special characters with helm based on org-entities-help
.
Copied from https://github.com/jkitchin/scimax/blob/master/scimax-org.el.
(defun helm-insert-org-entity ()
"Helm interface to insert an entity from `org-entities'.
F1 inserts utf-8 character
F2 inserts entity code
F3 inserts LaTeX code (does not wrap in math-mode)
F4 inserts HTML code
F5 inserts the entity code."
(interactive)
(helm :sources
(reverse
(let ((sources '())
toplevel
secondlevel)
(dolist (element (append
'("* User" "** User entities")
org-entities-user org-entities))
(when (and (stringp element)
(s-starts-with? "* " element))
(setq toplevel element))
(when (and (stringp element)
(s-starts-with? "** " element))
(setq secondlevel element)
(add-to-list
'sources
`((name . ,(concat
toplevel
(replace-regexp-in-string
"\\*\\*" " - " secondlevel)))
(candidates . nil)
(action . (("insert utf-8 char" . (lambda (x)
(mapc (lambda (candidate)
(insert (nth 6 candidate)))
(helm-marked-candidates))))
("insert org entity" . (lambda (x)
(mapc (lambda (candidate)
(insert
(concat "\\" (car candidate))))
(helm-marked-candidates))))
("insert latex" . (lambda (x)
(mapc (lambda (candidate)
(insert (nth 1 candidate)))
(helm-marked-candidates))))
("insert html" . (lambda (x)
(mapc (lambda (candidate)
(insert (nth 3 candidate)))
(helm-marked-candidates))))
("insert code" . (lambda (x)
(mapc (lambda (candidate)
(insert (format "%S" candidate)))
(helm-marked-candidates)))))))))
(when (and element (listp element))
(setf (cdr (assoc 'candidates (car sources)))
(append
(cdr (assoc 'candidates (car sources)))
(list (cons
(format "%10s %s" (nth 6 element) element)
element))))))
sources))))
(global-set-key (kbd "C-c i E") 'helm-insert-org-entity)
https://github.com/astoff/unicode-math-input.el
Insert mathematical symbols as Unicode characters.
(use-package unicode-math-input
:ensure t
:bind ("C-c i m" . unicode-math-input)
:init
(setq unicode-math-input-insert-tex t))
https://github.com/natrys/whisper.el
Speech-to-Text interface for Emacs using OpenAI’s whisper speech recognition model.
This will download and compile whisper.ccp the first time whisper-run
is executed.
Note that whisper.el
inserts text in bigger chunks, not in a word-by-word fashion: calling whisper-run
the first time starts the recording; calling whisper-run
a second time then initiates the transcription of the recording.
(use-package whisper
:load-path "lisp/whisper.el"
:bind ("C-c i w" . whisper-run)
:config
(setq whisper-install-directory share-dir
whisper-model "base"
whisper-language "auto"
whisper-translate nil))
https://github.com/hpdeifel/synosaurus
Thesaurus frontend for Emacs with pluggable backends:
- OpenThesaurus for German (online)
- WordNet for English (http://wordnet.princeton.edu/wordnet/download/current-version)
(use-package synosaurus
:ensure t
:config
(setq-default synosaurus-choose-method "default"
synosaurus-backend 'synosaurus-backend-openthesaurus)
)
https://github.com/SavchenkoValeriy/emacs-powerthesaurus
Uses powerthesaurus.org for English.
(use-package powerthesaurus
:ensure t)
https://github.com/martenlienen/dictcc.el
Look up translations in the translation dictionaries of dict.cc.
(use-package dictcc
:ensure t
:bind
(("C-0" . dictcc))
)
Call dictcc with word under cursor or marked region:
(defun tl/dictcc-at-point ()
(interactive)
(if (use-region-p)
(dictcc (concat "\"" (filter-buffer-substring (region-beginning) (region-end)) "\""))
(if (word-at-point)
(dictcc (word-at-point))
(call-interactively 'dictcc))
))
(global-set-key (kbd "C-0") 'tl/dictcc-at-point)
https://github.com/lorniu/go-translate
Translation framework for Emacs.
(use-package go-translate
:ensure t
:config
(setq gt-langs '("de" "en"))
;;;; Example from Github
;; (setq gt-default-translator
;; (gt-translator
;; :taker (gt-taker :text 'buffer :pick 'paragraph) ; config the Taker
;; :engines (list (gt-bing-engine) (gt-google-engine)) ; specify the Engines
;; :render (gt-buffer-render))) ; config the Render
(setq gt-default-translator
(gt-translator
:taker (gt-taker :text 'word :pick 'paragraph)
:engines (list
;; (gt-bing-engine)
(gt-deepl-engine :key user-deepl-key)
(gt-google-engine)
;; (gt-google-rpc-engine)
)
:render (gt-buffer-render)))
)
DEPRECATED:
(use-package go-translate
:ensure t
:config
(setq gts-translate-list '(("de" "en")))
;; (setq gts-default-translator (gts-translator :engines (gts-bing-engine)))
(setq gts-default-translator
(gts-translator
:picker (gts-prompt-picker)
:engines (list
;; (gts-bing-engine)
(gts-deepl-engine :auth-key user-deepl-key :pro nil)
(gts-google-engine)
;; (gts-google-rpc-engine)
)
:render (gts-buffer-render)))
)
This solution reuses code from here:
(require 'ps-print)
;; In order to avoid printing from buffers with dark theme
;; (use-package load-theme-buffer-local
;; :ensure t)
(defun tl/harden-visual-line-breaks-in-buffer ()
"Insert real newlines at visual line breaks."
(interactive)
(save-excursion
(goto-char (point-min))
(while (= 0 (save-excursion (forward-line)))
(unless (this-line-empty-p)
(end-of-visual-line)
(newline)
;; Kill empty line if it was just inserted
(when (this-line-empty-p)
(kill-line)))
(forward-line))))
;; Print line numbers when in prog-mode
(add-hook 'prog-mode-hook
(lambda () (setq ps-line-number t)))
(defun tl/print-buffer-to-pdf ()
"Print the current buffer or region to print_buffertitle_timestamp.pdf.
This command depends on the shell command `ps2pdf'."
(interactive)
(let* ((buf (current-buffer))
(path (read-directory-name "Save PDF to: " (expand-file-name "~/Downloads")))
(filename (concat path
"print_"
(replace-regexp-in-string "\\ \\|\\[\\|\\]\\|\\*" "" (buffer-name buf))
"_"
(format-time-string "%Y-%m-%d")))
(region-start-pos (when (region-active-p) (region-beginning)))
(region-end-pos (when (region-active-p) (region-end))))
(with-temp-buffer
(insert-buffer buf)
(visual-line-mode t)
(tl/harden-visual-line-breaks-in-buffer)
(let ((start-pos (or region-start-pos (point-min)))
(end-pos (or region-end-pos (point-max))))
(if (y-or-n-p "Print with faces? ")
(progn
;; (load-theme-buffer-local 'leuven tempbuf) ; FIXME: doesn't seem to take effect
(ps-print-with-faces start-pos end-pos (concat filename ".ps")))
(progn (ps-print-without-faces start-pos end-pos (concat filename ".ps"))))))
(shell-command (concat "ps2pdf " filename ".ps " filename ".pdf" ))
(delete-file (concat filename ".ps"))
(message (concat "PDF saved to " filename ".pdf"))))
Increase or decrease number at point, and when inside an org-mode timestamp, do the appropriate thing. But do not go below 0!
Inspired by andy/increment-number-at-point
from https://gist.github.com/argherna/6392696.
(defun tl/change-number-at-point (step)
(interactive)
(save-excursion
(skip-chars-backward "0123456789")
(or (looking-at "[0123456789]+")
(error "No number at point"))
(replace-match
(let ((number (string-to-number (match-string 0))))
(number-to-string
(if (> (+ number step) 0)
(+ number step)
0))))
))
(defun tl/change-number-dwim (step)
(interactive)
(cond
((and (org-at-clock-log-p) (> step 0)) (let ((org-clock-adjust-closest t))
(call-interactively 'org-timestamp-up)))
((and (org-at-clock-log-p) (< step 0)) (let ((org-clock-adjust-closest t))
(call-interactively 'org-timestamp-down)))
;; with `(org-at-timestamp-p 'lax)', the function matches any part of the document looking like a timestamp
((and (org-at-timestamp-p 'lax) (> step 0))
(org-timestamp-up))
((and (org-at-timestamp-p 'lax) (< step 0))
(org-timestamp-down))
(t (tl/change-number-at-point step))
))
(global-set-key (kbd "C-8") (lambda () (interactive) (tl/change-number-dwim -1)))
(global-set-key (kbd "C-9") (lambda () (interactive) (tl/change-number-dwim +1)))
https://github.com/enricoflor/numbex
- State “TODO” from [2022-08-10 Wed 12:14]
Built into Emacs: https://www.gnu.org/software/emacs/manual/html_node/emacs/Text-Scale.html
Issues:
- [ ] Only changes the default font.
Should be loaded after Buffer settings in order to take effect.
Org-mode files are usually bundled within a single directory stored in the variable org-directory
. But if there are links to org-mode files outside org-directory
, they should be included to org-agenda-files
, too.
Since there can be a vast amount of org-mode files in org-directory
, especially when using org-roam, only org-files
with org-agenda-file-tag
as filetag are used as org-agenda-files
.
(defcustom org-files nil
"List of org-mode files, which is a super set of org-agenda-files")
(defun tl/update-org-agenda-files ()
(interactive)
(require 'org-attach) ; in order not get disturbed by org-attach links
(setq org-files
(find-org-files-recursively (expand-file-name (concat org-directory "/")))) ; trailing slash required
;; search for linked org-mode files within org-files and add them
(dolist (file org-files)
(setq org-files (append org-files (find-links-to-org-files file))))
;; remove duplicates from org-files
(setq org-files (delete-duplicates org-files :test #'string-equal))
;; org-agenda-files are org-files with a certain filetag
(setq org-agenda-files ())
(if org-agenda-file-tag ; include all files if org-agenda-file-tag is nil
(dolist (file org-files)
(if (tl/org-agenda-file-tag-p file)
(setq org-agenda-files (cons file org-agenda-files)))))
(customize-save-variable 'org-agenda-files org-agenda-files)
(customize-save-variable 'org-files org-files)
(message "org-agenda-files and org-files updated")
(org-id-update-id-locations)
(message "org-id-files updated")
)
Search for org-mode files recursively:
;; Modified http://stackoverflow.com/a/26548971/6452961
(require 'dash)
(defun find-org-files-recursively (dir) "Find all org-files in DIR."
(let ((output ()))
(unless (file-directory-p dir) (error "Not a directory `%s'" dir))
(unless (equal (directory-files dir nil org-agenda-file-regexp t) nil)
(setq output
(append output
(-filter ; filter files with org-extension
(lambda (x) (not (string-match "#" x))) ; does not contain #-symbol
(file-expand-wildcards (concat dir "*.org*")))))) ; also include files with extension .org_archive
(dolist (file (directory-files dir nil nil t))
(unless (member file '("." ".."))
(let ((file (concat dir file "/")))
(when (file-directory-p file)
(setq output (append output (find-org-files-recursively file)))))))
output)
)
;; ;; The following code does not search the org directory recursively:
;; (setq org-agenda-files
;; (append
;; (list org-directory)
;; (file-expand-wildcards (concat org-directory "/*/*.org"))))
Return list of linked org-mode files:
(defun find-links-to-org-files (file)
"Return list of linked org-mode files.
Inspired by: http://stackoverflow.com/questions/38061773/add-linked-org-files-to-org-agenda-files"
(interactive)
(let ((output ()))
(save-current-buffer
(find-file file)
(org-element-map
(org-element-parse-buffer)
'link
(lambda (x)
(let ((org-link-path (org-element-property :path x))
(org-link-type (org-element-property :type x)))
(when (and (equal org-link-type "file") ; only links to files
(string-match-p "\\(^[a-z]:\\)\\|\\(~/\\)" "~/") ; relative paths are bad
(equal "org" (file-name-extension org-link-path)) ;only org-mode files
(file-exists-p org-link-path) ; only existing files
)
(princ (concat " " org-link-path))
(add-to-list 'output (expand-file-name org-link-path))
)))))
(switch-to-buffer (current-buffer)) ; return to first buffer
output))
Only keep org-agenda-files
with a certain filetag:
(defcustom org-agenda-file-tag "orgagendafile"
"This variabel saves the filetag that identifies files that are relevant for org-agenda.
When set to nil, all org-files are added to org-agenda-files.
When set to \"\", no org -files are added to org-agenda-files." )
(defun tl/org-agenda-file-tag-p (file)
(let ((found nil)
(oafiletag org-agenda-file-tag))
(save-current-buffer
(find-file file)
(dolist (tag org-file-tags)
(if (string-equal tag oafiletag)
(setq found t))))
(switch-to-buffer (current-buffer))
found))
Update org-agenda-files
once a day during start-up:
(defcustom org-agenda-files-last-update nil
"This variable saves the date of the last update of org-agenda-files.")
(when (not (string-equal org-agenda-files-last-update (format-time-string "%Y-%m-%d")))
(tl/update-org-agenda-files)
(customize-save-variable 'org-agenda-files-last-update (format-time-string "%Y-%m-%d"))
(message "org-agenda-files-last-update updated"))
Set refile targets to move entries inside org-files:
(setq org-refile-targets '(
(nil :maxlevel . 2) ; refile to headings in the current buffer
(org-files :maxlevel . 2) ; refile to any of these files
))
Helper function to export org-agenda-files to one icalendar file:
(defun tl/org-agenda-export-icalendar-file (&optional target)
(let ((org-icalendar-combined-agenda-file (or target org-icalendar-combined-agenda-file)))
(org-icalendar-combine-agenda-files)
;; Remove org-mode timestamps from date titles
(with-current-buffer (find-file-noselect org-icalendar-combined-agenda-file)
(goto-char (point-min))
(while (re-search-forward "<.*?>\\(\\(-\\|–\\)?<.*?>\\)?" nil t)
(replace-match ""))
(save-buffer))
))
https://github.com/dajva/rg.el
Use ripgrep in Emacs.
(use-package rg
:ensure t
;; :config
;; (rg-enable-default-bindings)
;; (rg-enable-menu) ; Magit-like interface (not working in v1.8.1)
)
Helper function to call rg in a specific directory:
(defun tl/call-rg-in-directory (dir)
"Call rg (from rg.el) in DIR."
(let ((default-directory dir))
(call-interactively 'rg)))
pdfgrep
enables one to grep through PDFs.
URL: https://github.com/jeremy-compostella/pdfgrep
(use-package pdfgrep
:ensure t
:config
(pdfgrep-mode))
Emacs copies the old contents of a file before actually saving it, called the “backup”.
https://www.emacswiki.org/emacs/BackupFiles http://pragmaticemacs.com/emacs/auto-save-and-backup-every-save/
(setq
backup-by-copying t ; don't clobber symlinks
kept-new-versions 10 ; keep 10 latest versions
kept-old-versions 0 ; don't bother with old versions
delete-old-versions t ; don't ask about deleting old versions
version-control t ; number backups
vc-make-backup-files t) ; backup version controlled files
The target directory is to determined by the variable backup-directory-alist
.
;; write backup files to own directory
(setq backup-directory-alist
`(("." . ,backup-dir)))
Show difference between current file buffer and auto-save file (taken from https://www.emacswiki.org/emacs/AutoSave):
(defun tl/diff-auto-save-file ()
"Get auto-save #file# difference with current buffer."
(interactive)
(diff (make-auto-save-file-name) (current-buffer) nil 'noasync))
https://www.gnu.org/software/emacs/manual/html_node/emacs/Auto-Save.html https://www.emacswiki.org/emacs/AutoSave
https://www.gnu.org/software/emacs/manual/html_node/elisp/File-Locks.html https://www.emacswiki.org/emacs/LockFiles
By default, Emacs will store a symbolic link with prefix .#
for every file that is currently being edited in order to “lock” them and prevent collisions.
However, within Cryptomator volumes under Linux, these symbolic links are not properly handled and ls
will throw an “Input/output error” when trying to read them. I’m therefore turning off the creation of lock files for the time being:
(setq create-lockfiles nil)
- State “TODO” from [2020-04-16 Do 23:20]
- [ ] plug it into hydra-dired
Living in both OS worlds, different line endings may be encountered in files that need to be unified. Here is a function to do that for several files which also works in dired
.
(defun xah-change-file-line-ending-style (@files @style)
"Change current file or dired marked file's newline convention.
When called non-interactively, *style is one of 'unix 'dos 'mac or any of accepted emacs coding system. See `list-coding-systems'.
URL `http://ergoemacs.org/emacs/elisp_convert_line_ending.html'
Version 2016-10-16"
(interactive
(list
(if (eq major-mode 'dired-mode )
(dired-get-marked-files)
(list (buffer-file-name)))
(ido-completing-read "Line ending:" '("Linux/MacOSX/Unix" "MacOS9" "Windows") "PREDICATE" "REQUIRE-MATCH")))
(let* (
($codingSystem
(cond
((equal @style "Linux/MacOSX/Unix") 'unix)
((equal @style "MacOS9") 'mac)
((equal @style "Windows") 'dos)
(t (error "code logic error 65327. Expect one of it." )))))
(mapc
(lambda (x) (xah-convert-file-coding-system x $codingSystem))
@files)))
(defun xah-convert-file-coding-system (@fpath @coding-system)
"Convert file's encoding.
*fpath is full path to file.
*coding-system is one of 'unix 'dos 'mac or any of accepted emacs coding system. See `list-coding-systems'.
If the file is already opened, it will be saved after this command.
URL `http://ergoemacs.org/emacs/elisp_convert_line_ending.html'
Version 2015-07-24"
(let ($buffer
($bufferOpened-p (get-file-buffer @fpath)))
(if $bufferOpened-p
(with-current-buffer $bufferOpened-p
(set-buffer-file-coding-system @coding-system)
(save-buffer))
(progn
(setq $buffer (find-file @fpath))
(set-buffer-file-coding-system @coding-system)
(save-buffer)
(kill-buffer $buffer)))))
Project management based on Git repositories.
(use-package projectile
:ensure t
:commands (projectile-find-file
projectile-switch-project)
:diminish projectile-mode
:config
(setq projectile-remember-window-configs t
projectile-enable-caching t ; speed up projectile by caching index
projectile-indexing-method 'alien ; use external commands like find, git etc. Maybe not supported in Windows.
projectile-require-project-root t ; only use projectile in git projects
;; projectile-keymap-prefix (kbd "C-x p") ; change keymap prefix (obsolete sind v2.0.0)
projectile-switch-project-action 'projectile-dired ; use dired when switching projects
)
(define-key projectile-mode-map (kbd "C-x p") 'projectile-command-map)
(projectile-global-mode)
)
Use helm for completions.
(use-package helm-projectile
:ensure t
:bind (("C-x p o" . helm-projectile-find-file)
("C-x p p" . helm-projectile-switch-project)
("C-x p h" . helm-projectile)
("C-x p g" . helm-projectile-grep)
("C-x p s" . helm-projectile-grep))
)
Better keys for closing and switching between windows. The rest is done in hydra-f2.
(global-set-key (kbd "M-s-<left>") 'windmove-left)
(global-set-key (kbd "M-s-<right>") 'windmove-right)
(global-set-key (kbd "M-s-<up>") 'windmove-up)
(global-set-key (kbd "M-s-<down>") 'windmove-down)
;; close window
(global-set-key (kbd "M-<f2>") 'delete-window)
winner-mode
allows you to undo (and redo) changes in the window configuration.
(winner-mode 1)
Goto other window:
(define-key dired-mode-map (kbd "M-s") nil)
(global-set-key (kbd "M-s") 'other-window)
https://www.emacswiki.org/emacs/TransposeFrame
Interactive functions which allow users to transpose windows arrangement in currently selected frame.
(use-package transpose-frame
:ensure t
;; :bind ("H-t" . transpose-frame)
)
- State “TODO” from [2024-07-29 Mon 10:47]
https://github.com/gonewest818/dimmer.el
Visually highlight the selected buffer.
Issues
- [ ] dimmer-face-color: Wrong type argument: stringp, reset
(use-package dimmer
:ensure t
:pin MELPA
:config
(dimmer-configure-which-key) ; which-key popups are not dimmed
(dimmer-configure-helm) ; helm buffers are not dimmed
(dimmer-configure-hydra) ; hydra buffers are not dimmed
(dimmer-configure-magit) ; magit trancient buffers are not dimmed
;; (dimmer-configure-org) ; org buffers are not dimmed
(setq dimmer-adjustment-mode ':foreground) ; possible values are `:foreground', `:background', `:both'
(setq dimmer-fraction 0.3) ; between 0 and 1; larger means more dimmed
(dimmer-mode t))
https://github.com/alphapapa/burly.el
From the project decription: This package provides tools to save and restore frame and window configurations in Emacs, including buffers that may not be live anymore.
(use-package burly
:ensure t
:pin MELPA)
https://github.com/tecosaur/emacs-everywhere https://emacstil.com/til/2021/10/04/edit-text-everywhere-with-emacs/
Open and edit everything in an Emacs frame.
(use-package emacs-everywhere
:ensure t)
One can evoke emacs-everywhere
from everywhere with:
emacsclient --eval "(emacs-everywhere)"
I have bound this to Super-e
.
Under Linux, make sure that the dependencies are satisfied:
sudo apt install xclip xdotool
Bookmarks are built into Emacs and similar to registers: they store positions one can jump back to. “Unlike registers, they have long names, and they persist automatically from one Emacs session to the next.”
(setq bookmark-default-file my-bookmarks-file) ; default bookmark file
(setq bookmark-save-flag 1) ; everytime bookmark is changed, automatically save it
(global-set-key (kbd "C-x C-r") 'helm-bookmarks)
https://github.com/magit/magit
A Git porcelain inside Emacs.
(use-package magit
:ensure t
:pin MELPA
:bind
("C-x g" . magit-status)
;; ("C-x C-g" . magit-status)
:init
;; make sure the latest version of magit-section is installed
(use-package magit-section
:ensure t
:pin MELPA)
:config
;; show magit full screen
(setq magit-display-buffer-function #'magit-display-buffer-fullframe-status-v1)
)
https://github.com/magit/forge
Work with Git forges from the comfort of Magit.
- use extra functions of Git forges: issues, pull requests
- very similar to magithub
- supports Github and Gitlab out of the box. Further Git forges can be installed with ghub.
Usage:
Issues:
(use-package forge
:ensure t
:pin MELPA
:after magit)
https://github.com/emacsorphanage/git-gutter
An Emacs port of the Sublime Text plugin GitGutter.
(use-package git-gutter
:ensure t
:config
(global-git-gutter-mode +1)
;; (git-gutter:linum-setup) ; git-gutter is struggling with linum-mode (DEPRECATED)
(custom-set-variables
'(git-gutter:update-interval 2))
:bind
("C-x C-g" . nil)
("C-x C-g TAB" . git-gutter:popup-hunk)
("C-x C-g _" . git-gutter:revert-hunk)
("C-x C-g z" . git-gutter:revert-hunk)
("C-x C-g C-g" . git-gutter-mode)
("C-x C-g g" . git-gutter-mode)
("C-x C-g n" . git-gutter:next-hunk)
("C-x C-g p" . git-gutter:previous-hunk)
)
https://github.com/sshaw/git-link
Create URLs for files and commits in GitHub/Bitbucket/GitLab/… repositories.
(use-package git-link
:ensure t
:bind (("C-c g l" . git-link))
)
(defun xah-show-kill-ring ()
"Insert all `kill-ring' content in a new buffer.
URL `http://ergoemacs.org/emacs/emacs_show_kill_ring.html'
Version 2017-06-19"
(interactive)
(let (($buf (generate-new-buffer "untitled")))
(progn
(switch-to-buffer $buf)
(funcall 'fundamental-mode)
(setq buffer-offer-save t)
(dolist (x kill-ring )
(insert x "\n--------------------------------------------------\n\n"))
(goto-char (point-min)))))
https://github.com/killdash9/better-shell
Better-shell simplifies shell management and sudo access.
(use-package better-shell
:ensure t
;; :bind (("C-'" . better-shell-shell)
;; ("C-;" . better-shell-remote-open))
)
https://www.gnu.org/software/emacs/manual/html_mono/eshell.html
Some tweaks of the built-in Eshell.
(add-hook 'eshell-mode-hook
#'(lambda () (define-key eshell-mode-map (kbd "<tab>") 'completion-at-point)))
(setq eshell-cmpl-dir-ignore "\`\\(CVS\\)/\\'") ; in order to complete `..` to `../`
(defun tl/eshell () ; http://emacs.stackexchange.com/a/28603/12336
(interactive)
(eshell t))
(global-set-key (kbd "<f7> e") 'tl/eshell)
Function to open external terminal at point. See discussion here.
(defun open-external-terminal-here ()
(interactive "@")
(let ((terminal-path (file-name-directory
(if (string-equal (buffer-mode) "dired-mode")
(dired-current-directory)
(or load-file-name
buffer-file-name
""))))
(terminal-command-prefix (first (open-external-terminal-here--terminal-command)))
(terminal-command-postfix (second (open-external-terminal-here--terminal-command))))
(shell-command (concat terminal-command-prefix
terminal-path
terminal-command-postfix) nil nil)))
(defun open-external-terminal-here--desktop-environment ()
"Return the desktop environment as string.
Taken from: https://emacs.stackexchange.com/a/52585/12336"
(interactive)
(let (
;; Create new variable with DE name
(de_env (getenv "XDG_CURRENT_DESKTOP"))
;; Make sure search is case insensitiveopen-external-terminal-here
(case-fold-search t))
(cond ((eq system-type 'darwin)
"darwin")
((memq system-type '(windows-nt ms-dos cygwin))
"windows")
((string-match ".*kde.*" de_env)
"kde")
((string-match ".*gnome.*" de_env)
"gnome")
((string-match ".*unity.*" de_env)
"unity")
((string-match ".*xfce.*" de_env)
"xfce")
((string-match ".*lxde.*" de_env)
"lxde")
((string-match ".*mate.*" de_env)
"mate")
((string-match ".*cinnamon.*" de_env)
"cinnamon")
(t "unknown"))))
(defun open-external-terminal-here--terminal-command ()
"Return the prefix and postfix of the terminal command depending on the desktop environment as pair of strings."
(alist-get (open-external-terminal-here--desktop-environment)
'(("darwin" . ("open -a Terminal.app" ""))
("windows" . ("cmd.exe /C start cmd.exe" ""))
("kde" . ("konsole --workdir " " > /dev/null 2>&1 & disown"))
("gnome" . ("gnome-terminal --working-directory=" " > /dev/null 2>&1 & disown"))
("xfce" . ("xfce4-terminal --working-directory=" " > /dev/null 2>&1 & disown")))
'("x-terminal-emulator --working-directory=" " > /dev/null 2>&1 & disown") nil 'equal))
https://github.com/akermu/emacs-libvterm
A native linux shell inside Emacs.
(use-package vterm
:ensure t
:config
(add-hook 'vterm-mode-hook (lambda () (setq-local winkeys-mode nil)))
(setq vterm-buffer-name-string "vterm %s") ; set to a string including %s for multiple vterms
:bind
(:map vterm-mode-map
("M-s" . nil)))
During installation, vterm-module
is compiled, which depends on
- cmake
- libtool
- libtool-bin
Note that, in order to use all the features of vterm
, also the underlying linux shell needs to be configured. See https://github.com/akermu/emacs-libvterm#shell-side-configuration-files for more information.
echo '# vterm settings
if [[ "$INSIDE_EMACS" = 'vterm' ]] \
&& [[ -n ${EMACS_VTERM_PATH} ]] \
&& [[ -f ${EMACS_VTERM_PATH}/etc/emacs-vterm-bash.sh ]]; then
source ${EMACS_VTERM_PATH}/etc/emacs-vterm-bash.sh
fi' >> ~/.bashrc
https://www.masteringemacs.org/article/keeping-secrets-in-emacs-gnupg-auth-sources
EasyPG Assistant (epa) is the Emacs assistant for interacting with GnuPG (i.e. OpenPGP, not S/MIME) that provides the following features:
- Key management.
- Cryptographic operations on regions.
- Cryptographic operations on files.
- Dired integration.
- Mail-mode integration. (Not recommended!)
- Automatic encryption/decryption of *.gpg files.
GnuPG keyrings can be used for encrypting a file by adding
-*- epa-file-encrypt-to: ("your@email.address") -*-
to the top.
Caveat: EasyPG (epg) itself does also handle S/MIME!
Variables:
(setq epg-user-id "123456789" ; GnuPG ID of your default identity.
)
Authinfo is basically a list of (hopefully encrypted) files that store user names and passwords.
Documentation
- https://www.gnu.org/software/emacs/manual/html_node/smtpmail/Authentication.html
- https://www.emacswiki.org/emacs/GnusAuthinfo
- https://www.gnu.org/software/emacs/manual/html_mono/auth.html
Look for authinfo file in authinfo-directory
:
(setq auth-sources
(list (expand-file-name ".authinfo.gpg" authinfo-directory)))
Function to look up password:
;; Taken from https://github.com/jwiegley/dot-emacs/blob/master/init.el
(defun lookup-password (host user port)
(require 'auth-source)
(funcall (plist-get (car (auth-source-search :host host :user user
:type 'netrc :port port))
:secret)))
The built-in top-like process viewer in Emacs.
See https://www.masteringemacs.org/article/displaying-interacting-processes-proced or http://emacsredux.com/blog/2013/05/02/manage-processes-with-proced/
(require 'proced)
(setq proced-auto-update-interval 1)
(defun proced-settings ()
(call-interactively 'proced-toggle-auto-update))
(add-hook 'proced-mode-hook 'proced-settings)
(global-set-key (kbd "C-x P") 'proced)
https://github.com/emacs-helm/helm-system-packages
A Helm interface to the package manager of your operating system.
(use-package helm-system-packages
:ensure t
:pin MELPA)
https://github.com/alezost/guix.el
Emacs front-end for the Guix package manager.
(use-package guix
:ensure t
:pin MELPA)
guix
requires geiser-guile
which oddly enough is not automatically installed as a dependency:
(use-package geiser-guile
:ensure t)
Also make sure that evironment variables are properly set (maybe restart required):
export GUIX_PROFILE=$HOME/.guix-profile
source $GUIX_PROFILE/etc/profile
https://www.gnu.org/software/emacs/manual/html_node/emacs/Tags-Tables.html
etags
is part of Emacs.
https://github.com/alpha22jp/atomic-chrome
Edit text areas of the browser in Emacs. A similar tool ist emacs-everywhere.
(use-package atomic-chrome
:ensure t
:config (atomic-chrome-start-server))
On the side of the browser, you need to install an extension such as GhostText.
- State “TODO” from [2020-04-01 Mi 10:51]
- [ ] change keybindings
- [ ] add German Wikipedia
http://ergoemacs.org/emacs/xah-lookup.html http://xahlee.info/emacs/emacs/xah-lookup.html
Look up information about words and phrases in online databases such as Wikpedia, Google Search etc.
(use-package xah-lookup
:load-path "lisp/xah-lookup.el")
https://www.gnu.org/software/tramp/
Built-in package for editing remote files.
(require 'tramp)
(if (eq system-type 'windows-nt)
(progn
(setq ange-ftp-ftp-program-name "ftp.exe")
(setq tramp-default-method "plink"))
(setq tramp-default-method "ssh"))
;; (setq tramp-default-user "")
There is a strange interaction with org-roam: Archive files (odt, zip, …) in my org-roam directory are mounted by Tramp when starting Emacs. Disabling tramp-archive.el
as suggested in https://emacs.stackexchange.com/a/56345/12336 does not help.
(with-eval-after-load 'tramp-archive
(setq tramp-archive-enabled nil)
;; Remove Libreoffice file extensions
(dolist (ext '("odb" "odf" "odg" "odp" "ods" "odt"))
(setq tramp-archive-suffixes (delete ext tramp-archive-suffixes))))
;; Another try ...
(setq tramp-ignored-file-name-regexp "\\(^.\\.odt.\\)")
Last straw: disable Tramp alltogether. Only works when disabling Tramp already in init.el
!
(with-eval-after-load 'tramp
(setq tramp-mode nil))
Deploy local files and directories to remote hosts.
https://github.com/cjohansson/emacs-ssh-deploy
https://github.com/Wilfred/helpful
A better help buffer.
(use-package helpful
:ensure t
:bind
(("C-h f" . helpful-callable)
("C-h v" . helpful-variable)
("C-h k" . helpful-key)
("C-c C-d" . helpful-at-point)
("C-h F" . helpful-function)
("C-h C" . helpful-command)))
https://github.com/mickeynp/discover.el
Discover more of emacs with the help of context menus. Similar to Hydras.
Currently I’m not using it because it binds M-s
, which I use for switching between windows.
(use-package discover
:ensure t)
https://github.com/abo-abo/hydra
Hydras are contextual keybindings that are displayed in the minibuffer. Both the keybindings and the minibuffer display can be flexibly set.
Nice examples:
Comparison of Transient and Hydra (by the author of Transient): https://magit.vc/manual/transient/Comparison-With-Other-Packages.html#Hydra
Lets start by activating the hydra package.
(use-package hydra
:ensure t
:config
The function keys are assigned to general hydras.
Hydra in case you need help/documentation.
(defhydra hydra-f1 (:exit t :hint nil)
"
╭────┐
│<f1>│ _<f2>_ _<f3>_ _<f4>_ _<f5>_ _<f6>_ _<f7>_ _<f8>_ _<f9>_
│Help│ Window^^ Config^^ Check^^ Refresh^^ Mode^^ Open^^ Mark^^ Org^^
╭╯ └──^^─────────^^─────────^^────────^^──────────^^───────^^───────^^───────^^────╯
Describe ^^Keys ^^Elisp ^^Documentation ^^Processes
--------------^^-------------------------^^---------------^^------------------^^-----------
_m_ode single _k_eybinding _a_propros _i_nfo _S_ystem
_p_ackage available _b_indings _f_unction _d_ocsets _E_macs
_c_ursor _w_here is key _v_ariable _n_: man
^^ _y_asnippets _L_ibrary
"
;; Boring help commands...
("e" view-echo-area-messages "messages")
("l" view-lossage "lossage")
("C" describe-coding-system "coding system")
("I" describe-input-method "input method")
;; Documentation
("i" info nil)
("n" helm-man-woman nil)
("d" helm-dash nil)
;; Keybinds
("b" describe-bindings nil)
("c" describe-key-briefly nil)
("k" describe-key nil)
("w" where-is nil)
("y" yas-describe-tables nil)
;; Elisp
("a" apropos-command nil)
("s" info-lookup-symbol nil)
("v" describe-variable nil)
("f" describe-function nil)
;; ("S" describe-syntax nil)
("L" finder-commentary nil)
;; Describe
("p" describe-package nil)
("m" describe-mode nil)
("c" (what-cursor-position t) nil)
;; ^Processes
("S" proced nil)
("E" list-processes nil)
("<f2>" hydra-f2/body :exit t)
("<f3>" hydra-f3/body :exit t)
("<f4>" hydra-f4/body :exit t)
("<f5>" revert-buffer :exit t)
("<f6>" hydra-f6/body :exit t)
("<f7>" hydra-f7/body :exit t)
("<f8>" hydra-f8/body :exit t)
("<f9>" hydra-f9/body :exit t)
;; quit
("q" help-quit "quit"))
(global-set-key (kbd "<f1>") #'hydra-f1/body)
Hydra for everything about windows and frames.
(require 'hydra-examples) ; provides hydra-move-splitter-left etc.
(defhydra hydra-f2
(:hint nil
:idle 0.2)
"
^^ ╭──────┐
_<f1>_ │<f2> │ _<f3>_ _<f4>_ _<f5>_ _<f6>_ _<f7>_ _<f8>_ _<f9>_
Help^^ │Window│ Config^^ Check^^ Refresh^^ Mode^^ Open^^ Mark^^ Org^^
╭─────^^──╯ └────────^^────────^^──────────^^───^^───────^^───────^^───────^^────╯
^^ _<up>_ │→ _M-<right>_ [_z_] window undo [_t_] transpose frame
^^ ↑ ^^ │split [_h_]oriz. [_Z_] window redo [_H_] swap horizontally
_<left>_ ← → _<right>_ │← _M-<left>_ [_f_] clone frame [_V_] swap vertically
^^ ↓ ^^ ────────^^──────── [_b_] clone buffer [_C-L_] scroll
^^ _<down>_ ↑ _M-<up>_ [_p_] print buffer to PDF
^^ ^^ split [_v_]ert. [_=_] balance windows [_q_]uit
^^ ^^ ↓ _M-<down>_
"
("<down>" windmove-down :exit t)
("<up>" windmove-up :exit t)
("<right>" windmove-right :exit t)
("<left>" windmove-left :exit t)
("f" make-frame :exit t)
("b" clone-indirect-buffer :exit t)
("v" split-window-vertically :exit t)
("h" split-window-horizontally :exit t)
("M-<right>" hydra-move-splitter-right :exit nil)
("M-<left>" hydra-move-splitter-left :exit nil)
("M-<up>" hydra-move-splitter-up :exit nil)
("M-<down>" hydra-move-splitter-down :exit nil)
("=" balance-windows :exit t)
("t" transpose-frame :exit t)
("H" flop-frame :exit t)
("C-L" hydra-scroll :exit t)
("V" flip-frame :exit t)
("z" winner-undo)
("Z" winner-redo)
("p" tl/print-buffer-to-pdf :exit t)
("q" nil :color blue)
("<f1>" hydra-f1/body :exit t)
("<f3>" hydra-f3/body :exit t)
("<f4>" hydra-f4/body :exit t)
("<f5>" revert-buffer :exit t)
("<f6>" hydra-f6/body :exit t)
("<f7>" hydra-f7/body :exit t)
("<f8>" hydra-f8/body :exit t)
("<f9>" hydra-f9/body :exit t))
(global-set-key (kbd "<f2>") 'hydra-f2/body)
(defhydra hydra-scroll (:hint nil)
"Scroll buffer"
("n" (lambda nil (interactive) (scroll-up 3)) :exit nil)
("p" (lambda nil (interactive) (scroll-down 3)) :exit nil)
("<down>" (lambda nil (interactive) (scroll-up 3)) "scroll down" :exit nil)
("<up>" (lambda nil (interactive) (scroll-down 3)) "scroll up" :exit nil)
("q" nil :color blue))
(global-set-key (kbd "C-S-l") 'hydra-scroll/body)
Hydra for everything about configurating Emacs.
(defhydra hydra-f3
(:hint nil
:idle 0.2)
"
^^ ^^ ╭──────┐
_<f1>_ _<f2>_ │<f3> │ _<f4>_ _<f5>_ _<f6>_ _<f7>_ _<f8>_ _<f9>_
Help^^ Window^^ │Config│ Check^^ Refresh^^ Mode^^ Open^^ Mark^^ Org^^
╭─────^^─────────^^───╯ └───────^^──────────^^───^^───────^^───────^^───────^^────╯
[_i_] init file [_p_] package manager [_m_] macros
[_d_] .emacs.d [_u_] upgrade packages [_fp_] proportional font
[_c_] customize emacs [_t_] load theme [_s_] system packages
[_lv_] visual line mode [_ln_] line numbers [_P_] private settings
[_lt_] truncate lines [_lr_] relative line numbers [_q_]uit
"
("i" (find-file (expand-file-name org-init-file user-emacs-directory)) :exit t)
("d" (find-file user-emacs-directory) :exit t)
("fp" toggle-proportional :exit t)
("c" customize :exit t)
("p" paradox-list-packages :exit t)
("P" (find-file private-emacs-settings-dir) :exit t)
("s" helm-system-packages :exit t)
("u" paradox-upgrade-packages :exit t)
("m" hydra-macro/body :exit t)
("t" hydra-load-theme/body :exit t)
("ln" tl/choose-line-numbering :exit t)
("lr" tl/toggle-relative-line-numbering :exit t)
("lv" visual-line-mode :exit t)
("lt" toggle-truncate-lines :exit t)
("q" nil :color blue)
("<f1>" hydra-f1/body :exit t)
("<f2>" hydra-f2/body :exit t)
("<f4>" hydra-f4/body :exit t)
("<f5>" revert-buffer :exit t)
("<f6>" hydra-f6/body :exit t)
("<f7>" hydra-f7/body :exit t)
("<f8>" hydra-f8/body :exit t)
("<f9>" hydra-f9/body :exit t))
(global-set-key (kbd "<f3>") 'hydra-f3/body)
(defun tl/choose-line-numbering ()
(interactive)
(if (version<= "26.0.50" emacs-version )
(display-line-numbers-mode 'toggle)
(linum-mode)))
(defun tl/toggle-relative-line-numbering ()
(interactive)
(if (not (eq display-line-numbers 'relative))
(setq display-line-numbers 'relative)
(setq display-line-numbers t)))
Hydra for everything about checking buffer contents.
(defhydra hydra-f4
(:hint nil
:idle 0.2)
"
^^ ^^ ^^ ╭─────┐
_<f1>_ _<f2>_ _<f3>_ │<f4> │ _<f5>_ _<f6>_ _<f7>_ _<f8>_ _<f9>_
Help^^ Window^^ Config^^ │Check│ Refresh^^ Mode^^ Open^^ Mark^^ Org^^
╭─────^^─────────^^─────────^^──╯ └─────────^^───^^───────^^───────^^───────^^─────╯
[_e_] compilation errors [_c_] code checking [_s_] spell checking
[_#m_] count matches [_r_] recover file [_=_] inline calculator
[_#w_] count words/lines/chars [_t_] translate [_L_] lookup in online resource [_q_]uit
[_p_] PDF signature
"
("e" hydra-compilation-error/body :exit t)
("c" hydra-flycheck/body :exit t)
("p" check-pdf-signature-dwim :exit t)
("r" recover-this-file :exit t)
("s" hydra-flyspell/body :exit t)
("t" gt-do-translate :exit t)
("=" literate-calc-minor-mode :exit t)
("L" hydra-lookup/body :exit t)
("#w" count-words :exit t)
("#m" count-matches :exit t)
("q" nil :color blue)
("<f1>" hydra-f1/body :exit t)
("<f2>" hydra-f2/body :exit t)
("<f3>" hydra-f3/body :exit t)
("<f5>" revert-buffer :exit t)
("<f6>" hydra-f6/body :exit t)
("<f7>" hydra-f7/body :exit t)
("<f8>" hydra-f8/body :exit t)
("<f9>" hydra-f9/body :exit t))
(global-set-key (kbd "<f4>") 'hydra-f4/body)
(defhydra hydra-lookup (:hint nil)
"Lookup in online resources"
("d" tl/dictcc-at-point "translation dictionary")
("p" powerthesaurus-hydra/body "powerthesaurus" :exit t)
("g" xah-lookup-google "google" :exit t)
("t" gts-do-translate :exit t)
("w" xah-lookup-wikipedia "wikipedia" :exit t)
("q" nil :exit t))
Hydra for functions specific to the buffer major mode.
(global-set-key (kbd "<f6>") 'hydra-f6/body)
(global-set-key (kbd "C-S-c") 'hydra-f6/body)
(defun hydra-f6/body () ;hydra-for-major-mode ()
(interactive)
(cond
((string-equal (buffer-mode) "deft-mode")
(hydra-deft/body))
((string-equal (buffer-mode) "dired-mode")
(hydra-dired-main/body))
((string-equal (buffer-mode) "elfeed-search-mode")
(mz/make-and-run-elfeed-hydra))
((string-equal (buffer-mode) "image-mode")
(hydra-image/body))
((string-equal (buffer-mode) "latex-mode")
(hydra-latex-main/body))
((string-equal (buffer-mode) "bibtex-mode")
(hydra-bibtex/body))
;; Must appear before entry for org-mode
((string-equal (car (org-babel-get-src-block-info)) "jupyter-python")
(jupyter-org-hydra/body))
((string-equal (buffer-mode) "org-mode")
(hydra-org-main/body))
((string-equal (buffer-mode) "org-agenda-mode")
(hydra-org-agenda/body))
((string-equal (buffer-mode) "pomidor-mode")
(hydra-pomidor/body))
((or (string-equal (buffer-mode) "markdown-mode")
(string-equal (buffer-mode) "gfm-mode"))
(hydra-markdown/body))
((string-equal (buffer-mode) "smerge-mode")
(unpackaged/smerge-hydra/body))
((string-equal (buffer-mode) "emacs-lisp-mode")
(hydra-elisp/body))
((string-equal (buffer-mode) "pdf-view-mode")
(hydra-pdftools/body))
((string-equal (buffer-mode) "mu4e-headers-mode")
(hydra-mu4e-headers/body))
((string-equal (buffer-mode) "mu4e-view-mode")
(hydra-mu4e-view/body))
((string-equal (buffer-mode) "mu4e-compose-mode")
(hydra-mu4e-compose/body))
((string-equal (buffer-mode) "mastodon-mode")
(hydra-mastodon/body))
((string-equal (buffer-mode) "picture-mode")
(hydra-artist/body))
((or t) (message (concat "no hydra defined for major mode"))))
)
Function to look up the major mode of a buffer:
(defun buffer-mode (&optional buffer-or-name)
"Returns the major mode associated with a buffer.
If buffer-or-name is nil return current buffer's mode."
(buffer-local-value 'major-mode
(if buffer-or-name (get-buffer buffer-or-name) (current-buffer))))
For using a hydra within helm
:
(define-key helm-map (kbd "<f6>") 'hydra-helm/body)
Hydra for opening a new buffer.
(defhydra hydra-f7
(:hint nil
:idle 0.2)
"
^^ ^^ ^^ ^^ ^^ ^^ ╭────┐
_<f1>_ _<f2>_ _<f3>_ _<f4>_ _<f5>_ _<f6>_ │<f7>│ _<f8>_ _<f9>_
Help^^ Window^^ Config^^ Check^^ Refresh^^ Mode^^ │Open│ Mark^^ Org^^
╭─────^^─────────^^─────────^^────────^^──────────^^───────^^──╯ └──────^^────────╯
[_a_] address book [_d_] dired/file browser [_t_] pomodoro timer [_m_] mail
[_b_] new buffer [_e_] emacs shell [_l_] dictionary [_M_] mastodon
[_i_] buffer overview [_s_] system shell [_B_] bookmarks [_v_] vterm
[_c_] calendar [_S_] external shell [_gl_] magit buffer log
[_p_] projectile [_f_] search files [_hb_] bibliography
[_P_] pandoc [_r_] elfeed [_j_] Jupyter notebook
[_o_] open externally [_R_] R repl [_gs_] magit status [_q_]uit
[_G_] guix
"
("a" helm-khard :exit t)
;; ("a" hydra-khardel/body :exit t)
;; ("a" helm-bbdb :exit t)
("c" (lambda ()
(interactive)
(if (get-buffer "*cfw-calendar*")
(switch-to-buffer "*cfw-calendar*")
(my-open-calfw))) :exit t)
("d" dired-jump :exit t)
("f" hydra-search/body :exit t)
("s" shell :exit t)
("S" open-external-terminal-here :exit t)
("b" xah-new-empty-buffer :exit t)
("hb" helm-bibtex :exit t)
("i" ibuffer :exit t)
("j" tl/open-jupyter-notebook :exit t)
("l" dictcc :exit t)
("m" mu4e :exit t)
("M" mastodon :exit t)
("G" guix :exit t)
("gs" magit-status :exit t)
("gl" magit-log-buffer-file :exit t)
("e" tl/eshell :exit t)
("B" bookmark-bmenu-list :exit t)
("o" xah-open-in-external-app :exit t)
("p" helm-projectile :exit t)
("P" pandoc-main-hydra/body :exit t)
;; ("r" tl/elfeed-summary :exit t)
("r" tl/elfeed :exit t)
("R" R :exit t)
("t" pomidor :exit t)
("v" vterm :exit t)
("q" nil :color blue)
("<f1>" hydra-f1/body :exit t)
("<f2>" hydra-f2/body :exit t)
("<f3>" hydra-f3/body :exit t)
("<f4>" hydra-f4/body :exit t)
("<f5>" revert-buffer :exit t)
("<f6>" hydra-f6/body :exit t)
("<f8>" hydra-f8/body :exit t)
("<f9>" hydra-f9/body :exit t))
(global-set-key (kbd "<f7>") 'hydra-f7/body)
(defun tl/open-jupyter-notebook ()
"Open iPython/Jupyter notebook within emacs.
This presupposes a running Jupyter server on localhost."
(interactive)
(call-interactively 'ein:notebooklist-login)
(ein:notebooklist-open))
Hydra for marking contents of a buffer.
(defhydra hydra-f8
(:hint nil
:idle 0.2)
"
^^ ^^ ^^ ^^ ^^ ^^ ^^ ╭─────┐
_<f1>_ _<f2>_ _<f3>_ _<f4>_ _<f5>_ _<f6>_ _<f7>_ │<f8> │ _<f9>_
Help^^ Window^^ Config^^ Check^^ Refresh^^ Mode^^ Open^^ │Mark │ Org^^
╭─────^^─────────^^─────────^^────────^^──────────^^───────^^───────^^──╯ └─────^^─╯
Mark & Edit ^^Highlight ^^Bookmark
------------------------------^^-------------------------------^^-----------------------
[_a_] mark all [_c_] highlight changes [_b_] add bookmark
[_r_] mark rectangular [_s_] highlight same symbols [_p_] position register
[_e_] edit same symbol [_gg_] git gutter [_gl_] git link
[_*_] critic markup [_w_] show/hide whitespaces
[_(_] key macro [_o_] highlight with overlays
[_>_] box-quote ^^ [_q_]uit
"
("a" mark-whole-buffer :exit t)
("gg" hydra-git-gutter/body :exit t)
("gl" git-link :exit t)
("c" hydra-highlight-changes/body :exit t)
("r" rectangle-mark-mode :exit t)
("b" hydra-add-bookmark/body :exit t)
("e" iedit-mode :exit t)
("o" ov-highlight/body :exit t)
("p" hydra-position-register/body :exit t)
("s" hydra-highlight-symbol/body :exit t)
;; ("t" hydra-tags/body :exit t)
("w" whitespace-mode :exit t)
("(" hydra-macro/body :exit t)
(">" boxquote-dwim :exit t)
("m" hydra-macro/body :exit t)
("*" hydra-cm-mode/body :exit t )
("q" nil :color blue)
("<f1>" hydra-f1/body :exit t)
("<f2>" hydra-f2/body :exit t)
("<f3>" hydra-f3/body :exit t)
("<f4>" hydra-f4/body :exit t)
("<f5>" revert-buffer :exit t)
("<f6>" hydra-f6/body :exit t)
("<f7>" hydra-f7/body :exit t)
("<f9>" hydra-f9/body :exit t)
)
(global-set-key (kbd "<f8>") 'hydra-f8/body)
Hydra for global org-mode keys:
(defhydra hydra-f9
(:hint nil
:idle 0.2)
"
^^ ^^ ^^ ^^ ^^ ^^ ^^ ^^ ╭────┐
_<f1>_ _<f2>_ _<f3>_ _<f4>_ _<f5>_ _<f6>_ _<f7>_ _<f8>_ │<f9>│
Help^^ Window^^ Config^^ Check^^ Refresh^^ Mode^^ Open^^ Mark^^ │Org │
╭─────^^─────────^^─────────^^────────^^──────────^^───────^^───────^^───────^^──╯ ╵
^^ [_a_] agenda ^^ [_j_] show journal ^^ ^^ ^^ ^^ ^^ [_r_] reload org
^^ [_d_] deft ^^ [_t_] show todos ^^ ^^ ^^ ^^ ^^ [_u_] update agenda files
^^ [_c_] capture ^^ [_:_] filter by tags ^^ ^^ ^^ ^^ ^^ [_C_] clocking...
^^ [_f_] search ^^ [_e_] export agenda files [_n_] show notes
^^ ^^ ^^ ^^ ^^ ^^ ^^ ^^ ^^ [_q_]uit
"
("a" org-agenda-list-complete :exit t)
("d" deft :exit t)
("e" (lambda nil (interactive)
(tl/org-agenda-export-icalendar-file)) :exit t)
("j" (lambda nil (interactive)
(find-file (concat org-directory "/journal.org"))) :exit t)
("n" hydra-org-roam/body :exit t)
("o" deft :exit t)
("c" org-capture :exit t)
("C" hydra-org-clock/body :exit t)
("t" org-todo-list :exit t)
("w" (lambda nil (interactive)
(find-file (concat org-directory "/work/work.org"))) :exit t)
("h" (lambda nil (interactive)
(find-file (concat org-directory "/home/home.org"))) :exit t)
(":" org-tags-view :exit t)
("r" org-reload :exit t)
;; ("f" helm-org-rifle-agenda-files :exit t)
("f" hydra-org-search/body :exit t)
;; ("f" org-search-view :exit t)
("s" org-search-view :exit t)
("u" tl/update-org-agenda-files :exit t)
("q" nil :color blue)
("<f1>" hydra-f1/body :exit t)
("<f2>" hydra-f2/body :exit t)
("<f3>" hydra-f3/body :exit t)
("<f4>" hydra-f4/body :exit t)
("<f5>" revert-buffer :exit t)
("<f6>" hydra-f6/body :exit t)
("<f7>" hydra-f7/body :exit t)
("<f8>" hydra-f8/body :exit t)
)
(global-set-key (kbd "<f9>") 'hydra-f9/body)
Hydra for artist-mode.
(defhydra hydra-artist (:color teal :hint nil)
"
^^ ^^ ^^ ^^ ╭────────┐
^Draw^ ^^ ^Modify^ ^Operations^ │ artist │
╭─^^──────────────^^───^^────────────────────────────^^─────────────────────────────┴────────╯
_l_ line _<_--_>_ add|remove arrow head _E_ erase Prefix: C-c C-a
^^ ^^ _v_ delete whole line _RET_ start|end drawing
_p_ poly line ^ ^
_r_ rectangle ┐ ^^ ^ ^ _M-w_ copy with rectangular
_s_ square │ ^^ _f_ fill _C-k_ cut with rectangular
_c_ circle │ ^^_C-f_ choose fill _C-y_ paste
_e_ ellipsis ╯ ^ ^ ^ ^
_S_ spray can ^ ^ ^ ^
_x_ pen line ^^ ^ ^ _C-o_ choose operation _q_ Quit
"
("l" artist-select-op-line)
("<" artist-toggle-first-arrow)
(">" artist-toggle-second-arrow)
("p" artist-select-op-poly-line)
("r" artist-select-op-rectangle)
("M-w" artist-select-op-copy-rectangle)
("C-k" artist-select-op-cut-rectangle)
("C-y" artist-select-op-paste)
("E" artist-select-op-erase-rectangle)
("s" artist-select-op-square)
("c" artist-select-op-circle)
("e" artist-select-op-ellipse)
("f" artist-select-op-flood-fill)
("C-f" artist-select-fill-char)
("S" artist-select-op-spray-can)
("v" artist-select-op-vaporize-line)
("x" artist-select-op-pen-line)
("RET" artist-key-set-point)
("C-o" artist-select-operation)
("q" nil)
)
(defhydra hydra-bibtex (:color teal :hint nil)
"
^^ ^^ ^^ ╭────────┐
^Field^ ^Entry^ ^File^ │ bibtex │
╭─^^──────────────────────^^───────────────────────────^^──────────────────────────┴────────╯
_f_ New _+_ New... _s_ Sort entries
_k_ Kill _c_ Clean _h_ Open helm-bibtex
_o_ Remove OPT/ALT _C_ Clean & generate key _O_ org-ref hydra...
_t_ Add timestamp _w_ Kill _F_ File actions...
_y_ Yank _x_ Goto crossref ^ ^
_?_ Help _i_ Import from DOI ^ ^
^ ^ _u_ Update ^ ^ _q_ Quit
"
("o" bibtex-remove-OPT-or-ALT)
("c" bibtex-clean-entry)
("C" (bibtex-clean-entry '(4)))
("f" bibtex-make-field)
("C-k" bibtex-kill-field)
("k" bibtex-kill-field)
("C-w" bibtex-kill-entry)
("w" bibtex-kill-entry)
("u" bibtex-entry-update)
("y" bibtex-yank)
("s" bibtex-sort-buffer)
("t" tl/bibtex-add-timestamp)
("x" bibtex-search-crossref)
;; ("+" org-ref-bibtex-new-entry/body "new entry..." :exit t)
;; ("+" hydra-bibtex-langsci-new-entry/body "new entry..." :exit t)
("+" bibtex-entry)
("i" get-bibtex-from-doi)
("h" helm-bibtex)
("F" org-ref-bibtex-file/body)
("O" org-ref-bibtex-hydra/body)
("?" bibtex-print-help-message)
("q" nil)
)
(defhydra hydra-add-bookmark (:hint nil)
"Add bookmark"
("b" bookmark-set "buffer" :exit t)
("f" burly-bookmark-frames "frames" :exit t)
("w" burly-bookmark-windows "windows" :exit t)
("q" nil :exit t))
(defhydra hydra-cm-mode
(:body-pre (when (not (string-equal cm-mode "t"))
(font-lock-mode -1)
(font-lock-mode 1)
(cm-mode 1))
:hint nil)
"
CriticMarkup
╭──────────────╯
[_<up>_] previous [_a_] addition [_i_] accept/reject
[_<down>_] next [_d_] deletion [_I_] accept/reject all
^^ [_s_] substitution
[_F_] follow changes [_c_] comment [_q_]uit
^^ ^^ [_Q_]uit and deactivate cm-mode
"
("<up>" #'cm-backward-change)
("<down>" #'cm-forward-change)
("a" #'cm-addition :color blue)
("d" #'cm-deletion :color blue)
("s" #'cm-substitution :color blue)
("c"#'cm-comment :color blue)
("i" #'cm-accept/reject-change-at-point)
("I" #'cm-accept/reject-all-changes)
("t" #'cm-set-author)
("F" #'cm-follow-changes :color blue)
("q" nil :color blue)
("Q" (cm-mode -1) :color blue))
(global-set-key (kbd "C-*") 'hydra-cm-mode/body)
(defhydra hydra-dired-main (:hint nil)
"
^Navigation^ ^^ ^Mark^ ^Actions^ ^View^
-^----------^------------^^------------^----^--------------^-------^-------------^----^----------------------
_<up>_ ^^ _m_: mark _+_: new _g_: refresh
^^ ʌ ^^ _u_: unmark _C_: copy to _/_: filter
^^ ^^ _U_: unmark all _D_: delete _s_: sort
_<left>_ .. view _<right>_ _t_: toggle mark _R_: move to _(_: details
^^ enter _RET_ _*_: specific _r_: rename _)_: collapse
^^ ^^ ^^ _S_: symlink _z_: size
^^ v ^^ _w_: copy file name _P_: change property _ow_: open in other window
_<down>_ ^^ _W_: copy path _c_/_Z_: compress _of_: open in other frame
^^ ^^ ^^ _=_: diff
_._: home _j_: jump _f_: find _$_: wdired _am_: attach to mail ^^
^^ ^^ ^^ ^^ _af_: goto attached heading
^^ ^^ ^^ ^^ _&_: clone file _q_: quit hydra
-^----------^------------------------^----^---------------^-------^-------------^----^---------------------
"
("<left>" (lambda () (interactive) (find-alternate-file "..")))
("<up>" diredp-previous-line)
("<down>" diredp-next-line)
("RET" dired-find-file)
("<right>" dired-view-file)
("+" hydra-dired-new/body :color blue)
("*" hydra-dired-mark/body :color blue)
("P" hydra-dired-properties/body :color blue)
("am" gnus-dired-attach :color blue)
("af" my-org-attach-visit-headline-from-dired :color blue)
("O" dired-do-chown)
("M" dired-do-chmod)
("G" dired-do-chgrp)
("C" dired-do-copy)
("D" dired-do-delete)
("<delete>" dired-do-delete)
("R" dired-do-rename)
("S" dired-do-symlink)
("Z" dired-do-compress)
("c" dired-do-compress-to)
("/" dired-narrow)
("(" dired-hide-details-mode)
(")" dired-collapse-mode)
("$" wdired-change-to-wdired-mode :color blue)
("&" tl/dired-duplicate-this-file :color blue)
("f" helm-find)
("." (find-file home-directory))
("=" hydra-dired-diff/body :color blue)
;; ("=" dired-diff)
("g" revert-buffer)
("j" dired-goto-file)
("ow" dired-find-file-other-window :color blue)
("of" diredp-find-file-other-frame :color blue)
("r" dired-efap)
;; ("s" dired-sort-toggle-or-edit)
("s" hydra-dired-quick-sort/lambda-S :color blue)
("m" dired-mark)
("u" dired-unmark)
("U" dired-unmark-all-marks)
("t" dired-toggle-marks)
("v" dired-view-file)
("w" dired-copy-filename-as-kill)
("W" tl/dired-copy-path-at-point)
("z" dired-get-size)
;; ("q" quit-window :color blue)
("q" nil :color blue)
)
(defhydra hydra-dired-new (:hint nil )
"New"
("d" dired-create-directory "directory" :exit t :after-exit (hydra-dired-main/body))
("f" find-file "file" :exit t)
("s" dired-do-symlink "symbolic link" :exit t :after-exit (hydra-dired-main/body))
("h" dired-do-hardlink "hard link" :exit t :after-exit (hydra-dired-main/body))
("q" hydra-dired-main/body "quit" :color blue)
)
(defhydra hydra-dired-mark (:hint nil :after-exit (hydra-dired-main/body))
"Mark"
("a" (dired-mark-files-regexp ".*") "all" :exit t)
("d" dired-mark-directories "directories" :exit t)
("." diredp-mark/unmark-extension "by extension" :exit t)
("s" dired-mark-symlinks "symbolic links" :exit t)
("r" dired-mark-files-regexp "by regexp" :exit t)
("/" dired-mark-sexp "by search term" :exit t)
("q" hydra-dired-main/body "quit" :exit t)
)
(defhydra hydra-dired-properties (:hint nil :after-exit (hydra-dired-main/body))
"Change"
("o" dired-do-chown "owner")
("r" dired-do-chmod "rights")
("g" dired-do-chgrp "group")
("q" hydra-dired-main/body "quit" :color blue)
)
(defhydra hydra-dired-diff (:hint nil :after-exit (hydra-dired-main/body))
"Diff"
("=" diredp-ediff "ediff")
("e" ora-ediff-files "ediff on marked")
("d" ztree-diff "diff on directories")
("p" diffpdf-dired--command "diffpdf")
("q" hydra-dired-main/body "quit" :color blue)
)
Don’t ask for the path when searching for files:
(defun my-find-name-dired (pattern)
"My version of find-name-dired that always starts in my chosen folder"
(interactive "sFind Name (file name wildcard): ")
(dired-hide-details-mode)
(find-name-dired "." pattern))
(defhydra hydra-elisp (:hint nil :color blue :columns 3)
"Elisp mode"
("df" edebug-defun "debug function" :color blue)
("da" edebug-all-defs "debug all" :color blue)
("dd" checkdoc "debug documentation" :color blue)
("C-M-x" eval-defun nil :color blue)
("ef" eval-defun "evaluate function" :color blue)
("eb" eval-buffer "evaluate buffer" :color blue)
("q" nil "quit" :color blue)
)
(defhydra hydra-org-main (:hint nil :color blue)
"
^^ ^^ ^^ ^^ ╭──────────┐
^Heading^ ^Text^ ^Filter^ ^Navigation^ │ org-mode │
╭──^^───────────────────────────^^──────────────────────────^^────────────────────────^^──────────────┴──────────╯
_a_ attachment... _l_ preview LaTeX _C_ columns... _<down>_ next visible heading
_A_ archive... _$_ preview LaTeX _/_ filter _<up>_ previous visible heading
_b_ open in new buffer _m_ markup... _<tab>_ tidily unfold _C-c C-u_ embedding heading
_c_ clocking... _r_ org-ref _<left>_ hide subtree _C-<down>_ next heading same level
_i_ add ID _._ timestamp _<right>_ show subtree _C-<up>_ previous heading same level
_n_ notes... _*_ cycle list type _C-<left>_ hide sublevels _o_ open link/timestamp/...
_p_ add property _#_ table... _C-<right>_ show sublevels _O_ open link/timestamp/... in new frame
_P_ add property-value pair _v_ toggle images ^<f9>:^ filter tags globally _j_ jump to heading
_s_/\^ sort \\ toggle overlays ^^ _B_ jump to named block
_t_ set todo keyword _dl_ delete link
_:_ set tags _dt_ delete aux files ^^ ^^ _q_ quit
_+_/_-_ priority up/down _e_ editmarks...
_1_ move to top _D_ download
_N_ number headings
_x_ add/open hand notes
"
("a" org-attach)
("A" hydra-org-archive/body)
("b" org-tree-to-indirect-buffer)
("B" org-babel-goto-named-src-block :color pink)
("C" hydra-org-columns/body)
("D" hydra-org-download/body)
("c" hydra-org-clock/body)
("E" my-sem-hydra-start)
("e" my-sem-hydra-start)
("i" org-id-get-create)
("j" org-goto :color pink)
("l" org-toggle-latex-fragment)
("dl" tl/org-replace-link-with-description)
("dt" delete-org-latex-aux-files)
("$" org-fragtog-mode)
("m" hydra-org-markup/body)
("n" hydra-org-roam/body)
("N" org-num-mode)
("o" org-open-at-point)
("O" tl/org-open-in-new-frame)
("p" org-set-property)
("P" org-set-property-and-value)
("r" org-ref)
("s" org-sort)
("x" tl/org-add-or-open-xournal-attachment)
("/" org-sparse-tree)
("." tl/org-timestamp-dwim)
("<tab>" org-show-current-heading-tidily)
("<left>" tl/org-hide-subtree-or-up-dwim :color pink)
("C-<left>" outline-hide-sublevels :color pink)
("C-<right>" tl/org-show-sublevels :color pink)
("<right>" org-cycle :color pink)
("t" org-todo)
(":" org-set-tags-command)
("+" org-priority-up :color pink)
("-" org-priority-down :color pink)
("1" bjm/org-headline-to-top :color pink)
("*" org-cycle-list-bullet :color pink)
("#" hydra-org-table/body)
("v" org-toggle-inline-images)
("\\" tl/org-toggle-overlays)
("^" org-sort)
("C-n" org-next-visible-heading :color pink)
("<down>" org-next-visible-heading :color pink)
("C-p" org-previous-visible-heading :color pink)
("<up>" org-previous-visible-heading :color pink)
("C-N" org-forward-heading-same-level :color pink)
("C-P" org-backward-heading-same-level :color pink)
("C-<down>" org-forward-heading-same-level :color pink)
("C-<up>" org-backward-heading-same-level :color pink)
("C-f" org-forward-heading-same-level :color pink)
("C-b" org-backward-heading-same-level :color pink)
("C-c C-u" outline-up-heading :color pink)
("q" nil :color blue)
)
(defun tl/org-toggle-overlays ()
"Toggle the use of overlays that are used with links, emphasis markers, special symbols in the buffer."
(interactive)
(org-toggle-pretty-entities)
(org-toggle-link-display)
(if org-hide-emphasis-markers
(setq org-hide-emphasis-markers nil)
(setq org-hide-emphasis-markers t)))
Taken from https://emacs.stackexchange.com/a/26840/12336 and modified:
(defun tl/org-folded-p ()
"Returns non-nil if point is on a folded headline or plain item."
(and (or (org-at-heading-p)
(org-at-item-p))
(invisible-p (point-at-eol))))
(defun tl/org-hide-subtree-or-up-dwim ()
(interactive)
(if (tl/org-folded-p)
(outline-up-heading 1)
(outline-hide-subtree))
)
(defun tl/org-show-sublevels ()
(interactive)
(outline-hide-sublevels (+ (org-current-level) 1))
(recenter-top-bottom)
)
(defhydra hydra-org-archive (:hint nil)
"Org-mode archive"
("t" org-toggle-archive-tag "set archive tag" :exit t)
("a" org-archive-to-archive-sibling "archive below" :exit t)
("A" org-archive-subtree-default "archive outside" :exit t)
("<tab>" org-force-cycle-archived "expand archive" :exit t)
("q" nil :color blue)
)
A hydra for org-columns.
(defhydra hydra-org-columns (:hint nil :color pink :columns 3 :body-pre (progn (beginning-of-line) (org-columns)))
"Org-mode columns"
(">" org-columns-widen "widen")
("<" org-columns-narrow "narrow")
("a" org-columns-edit-allowed "allowed values" :exit t)
("c" org-columns-content "content" :exit t)
("e" org-columns-edit-value "edit" :exit t)
("n" org-columns-next-allowed-value "next allowed value")
("p" org-columns-previous-allowed-value "previous allowed value")
("r" org-columns-redo "refresh")
("s" org-columns-edit-attributes "select attribute")
("t" org-columns-todo "todo")
("2" (org-show-children 2) "Show up to 2 sublevels")
("M-S-<left>" org-columns-delete "delete")
("M-S-<right>" org-columns-new "new")
("M-<right>" org-columns-move-right "move right")
("M-<left>" org-columns-move-left "move left")
("<delete>" org-columns-delete)
("v" org-columns-show-value "show value")
("q" org-columns-quit :color blue)
)
Hydra for clocking activities in org-mode (taken from https://github.com/abo-abo/hydra/wiki/Org-clock-and-timers):
(bind-key "C-c c" 'hydra-org-clock/body)
(defhydra hydra-org-clock (:color blue :hint nil)
"
^Clock:^ ^In/out^ ^Edit^ ^Summary^ | ^Timers:^ ^Run^ ^Insert
-^-^-----^-^----------^-^------^-^----------|--^-^------^-^-------------^------
(_?_) _i_n _e_dit _g_oto entry | (_h_) _b_egin ti_m_e
^ ^ _c_ontinue _Q_uit _d_isplay | ^ ^ cou_n_tdown i_t_em
^ ^ _o_ut ^ ^ _r_eport | ^ ^ _p_ause toggle
^ ^ h_I_istory ^ ^ ^ ^ | ^ ^ _s_top
"
("i" org-clock-in)
("c" org-clock-in-last)
("o" org-clock-out)
("I" org-mru-clock-in)
("e" org-clock-modify-effort-estimate)
("Q" org-clock-cancel)
("g" org-clock-goto)
("d" org-clock-display)
("r" org-clock-report)
("?" (org-info "Clocking commands"))
("b" org-timer-start)
("n" org-timer-set-timer)
("p" org-timer-pause-or-continue)
("s" org-timer-stop)
("m" org-timer)
("t" org-timer-item)
("h" (org-info "Timers")))
Download with org-download.
(defhydra hydra-org-download (:hint nil)
"Org-mode download"
("c" org-download-clipboard "clipboard" :exit t)
("d" org-download-delete "delete" :exit t)
("r" org-download-rename-at-point "rename " :exit t)
("s" org-download-screenshot "screenshot" :exit t)
("u" org-download-image "url" :exit t)
("y" org-download-yank "yank" :exit t)
("q" nil :color blue)
)
(defhydra hydra-org-agenda (:hint nil :color red)
"
^^ ^^ ^^ ^^ ╭────────────┐
^Calendar^ ^Heading^ ^Clocking^ ^Filter^ │ org-agenda │
╭─^^─────────────────────^^─────────────────^^───────────────────────^^────────────────────────┴────────────╯
_b_ backward d/w/y _+_ priority up _I_ clock in _/_ by tag _S_ync with CalDAV
_._ today _-_ priority down _O_ clock out _<_ by category
_f_ forward d/w/y _t_ set todo _J_ jump to clocked-in \^ siblings
_j_ goto date _:_ set tags _R_ clocking report _|_ remove all
_d_ day view _>_ set date ^^ _l_ show done (log mode)
_w_ week view _C-c C-d_ set deadline ^^
_vm_ month view _C-c C-s_ set schedule ^^ _C_ complete agenda
_vy_ year view _C-k_ kill ^^ _H_ home agenda ^^ _r_efresh
^^ _M-S-<up>_ earlier hour _M-S-<up>_ earlier time _W_ work agenda ^^ _q_uit hydra
^^ _M-S-<down>_ later hour _M-S-<down>_ later time _E_ events ^^ e_x_it agenda
^^ _M-S-<right>_ earlier day ^^
^^ _M-S-<down>_ later day ^^ _m_ mark
_h_ show holidays ^^ ^^ _u_ unmark
_]_ show inactive timestamps ^^ ^^ _B_ action on marked
_k_ capture with timestamp ^^ ^^ ^^
"
("+" org-agenda-priority-up)
("-" org-agenda-priority-down)
("d" org-agenda-day-view)
("w" org-agenda-week-view)
("vm" org-agenda-month-view)
("vy" org-agenda-year-view)
("h" org-agenda-holidays)
("H" org-agenda-list-home)
("W" org-agenda-list-work)
("C" org-agenda-list-complete)
("E" org-agenda-list-events)
("I" org-agenda-clock-in)
("O" org-agenda-clockreport-mode)
("R" org-agenda-clock-in)
("S" tl/org-export-agenda-to-caldav :color blue)
("f" org-agenda-later)
("b" org-agenda-earlier)
("F" org-agenda-follow-mode)
("j" org-agenda-goto-date)
("J" org-agenda-clock-goto)
("." org-agenda-goto-today)
("C-k" org-agenda-kill)
("C-c C-s" org-agenda-schedule)
("C-c C-d" org-agenda-deadline)
("M-S-<left>" org-agenda-date-earlier)
("M-S-<right>" org-agenda-date-later)
("M-S-<up>" tl/org-agenda-alt-shift-up)
("M-S-<down>" tl/org-agenda-alt-shift-down)
("m" org-agenda-bulk-mark)
("u" org-agenda-bulk-unmark)
("B" org-agenda-bulk-action)
("k" org-agenda-capture)
("t" org-agenda-todo)
("/" org-agenda-filter-by-tag)
("|" org-agenda-filter-remove-all)
("^" org-agenda-filter-by-top-headline)
("l" org-agenda-log-mode)
("]" org-agenda-manipulate-query-subtract)
(":" org-agenda-set-tags)
(">" org-agenda-date-prompt)
("<" org-agenda-filter-by-category)
("r" org-agenda-redo)
("x" org-agenda-exit :color blue)
("q" nil :color blue)
)
(defhydra hydra-org-search (:color blue :hint nil)
"Org-mode search"
("a"
(lambda nil (interactive)
(helm-org-rifle-files org-agenda-files))
"agenda files")
("e"
;; (let ((org-super-agenda-date-format "(W%V) %d %B %Y, %A"))
(org-ql-search
(org-agenda-files)
'(tags "event" "appointment")
:sort '(date)
;; :super-groups '((:auto-ts reverse))
)
;; )
"events")
("f" (lambda nil (interactive)
(helm-org-ql org-files) ; FIXME: way too slow!
)
"free search")
("g" (org-ql-search
(org-agenda-files)
'(and
;; Heading is DONE or an event not in a (potentially ongoing) project
(and (or (todo "DONE")
;; Event must be in the past
(and
;; Tag hierarchies are not yet supported:
;; https://github.com/alphapapa/org-ql/issues/145
(tags "event" "appointment")
(not (ts-active :from -60)))
)
(not (ancestors (tags "project"))))
;; Heading has no recent clocks
(not (clocked :from -60))
;; Descendents have no recent clocks
(not (descendants (clocked :from -60)))))
"garbage collection")
("q" nil :color blue)
)
Taken from https://gist.github.com/dfeich/1df4e174d45f05fb5798ca514d28c68a and modified:
(defhydra hydra-org-table (:color red :hint nil)
"
^^ ^^ ^^ ^^ ╭───────────┐
^Cell^ ^Table^ ^Formula^ ^Navigation^ │ org-table │
╭──────^^───────────────────^^──────────────────────────^^────────────────────────^^──────────────┴───────────╯
_'_ edit cell _s_ sort lines _e_ eval formula _<up>_ above cell
_?_ cell info _t_ transpose _r_ recalculate _<down>_ below cell
_<return>_ wrap region _E_ export table _D_ toggle debugger _<left>_ left cell
_<SPC>_ empty cell _c_ toggle coordinates _i_ iterate table _<right>_ right cell
_m_ move cell... _-_ collapse/expand column _B_ iterate buffer
_M-w_ copy cell _<_ collapse all columns _+_ sum column
_C-w_ kill cell _>_ expand all columns _N_ number rows
_C-y_ yank & align _|_ convert from region
_S-<return>_ copy cell down _v_ vertical align ^^ _q_ quit
"
("E" org-table-export :color blue)
("s" org-table-sort-lines)
("'" org-table-edit-field nil :color blue)
("e" org-table-eval-formula)
("r" org-table-recalculate)
("i" org-table-iterate)
("m" hydra-org-table-move-cell/body :color blue)
("N" tl/org-table-number-rows)
("B" org-table-iterate-buffer-tables)
("D" org-table-toggle-formula-debugger)
("t" org-table-transpose-table-at-point)
("v" valign-mode)
("?" org-table-field-info)
("M-w" tl/org-table-copy-cell-content)
("C-w" tl/org-table-kill-cell-content)
("C-y" (progn
(org-yank)
(org-table-align)))
("<return>" org-table-wrap-region)
("S-<return>" org-table-copy-down)
("<SPC>" org-table-blank-field)
("<tab>" org-cycle)
("S-<tab>" org-shifttab)
("-" org-table-toggle-column-width)
("+" org-table-sum)
("<" (org-table-toggle-column-width '(4)))
(">" (org-table-toggle-column-width '(16)))
("|" org-table-convert-region)
("<up>" previous-line)
("<down>" org-table-next-row)
("<left>" org-table-previous-field)
("<right>" org-table-next-field)
;; ("n" dfeich/org-table-remove-num-sep :color blue) ; _n_ remove number separators
("c" org-table-toggle-coordinate-overlays :color blue)
("q" nil :color blue))
As of v9.3, moving cells is built into org-mode
. Before that I used org-table-move-single-cell
.
(defhydra hydra-org-table-move-cell (:hint nil
:idle 0.5)
"
Move org-table cell
╭─────────────────────╯
_<up>_: move up _<left>_: move left
_<down>_: move down _<right>_: move left _q_uit
"
("<up>" org-table-move-cell-up)
("<down>" org-table-move-cell-down)
("<right>" org-table-move-cell-right)
("<left>" org-table-move-cell-left)
("q" hydra-org-table/body :color blue))
(defhydra hydra-org-markup (:hint nil)
"Org-mode markup"
("a" tl/insert-org-link-alert "alert" :exit t)
("b" (org-emphasize ?*) "bold" :exit t)
("c" tl/insert-org-link-color "color" :exit t)
("e" tl/insert-org-link-emph "emphasized" :exit t)
("E" my-sem-hydra-start "editmarks" :exit t)
("i" (org-emphasize ?/) "italic" :exit t)
("m" tl/insert-org-link-mono "monospaced" :exit t)
("s" tl/insert-org-link-smallcaps "small caps" :exit t)
("t" tl/insert-org-link-term "term" :exit t)
("u" (org-emphasize ?_) "underlined" :exit t)
("x" tl/insert-org-link-example "example" :exit t)
("d" tl/org-replace-link-with-description "delete markup" :exit t)
("q" nil :color blue))
(global-set-key (kbd "C-c m") 'hydra-org-markup/body)
(defun tl/insert-org-link (type)
(if (use-region-p)
(let ((marked (buffer-substring (region-beginning) (region-end))))
(progn
(delete-region(region-beginning) (region-end))
(insert (concat "[[" type "][" marked "]]"))))
(insert (concat "[[" type "][]]"))
(backward-char 2)))
(defun tl/insert-org-link-alert ()
(interactive)
(tl/insert-org-link "alert:"))
(defun tl/insert-org-link-term ()
(interactive)
(tl/insert-org-link "term:"))
(defun tl/insert-org-link-smallcaps ()
(interactive)
(tl/insert-org-link "textsc:"))
(defun tl/insert-org-link-mono ()
(interactive)
(tl/insert-org-link "texttt:"))
(defun tl/insert-org-link-emph ()
(interactive)
(tl/insert-org-link "emph:"))
(defun tl/insert-org-link-example ()
(interactive)
(tl/insert-org-link "bsp:"))
(defun tl/insert-org-link-color ()
(interactive)
(tl/insert-org-link
(concat "color:"
(replace-regexp-in-string "[[:space:]]+" "" (helm-colors)))))
(defhydra hydra-org-roam (:color teal :hint nil)
"
^^ ^^ ^^ ╭──────────┐
^Navigation between notes^ ^Actions inside note^ ^General actions^ │ org-roam │
╭─^^───────────────────────────────^^─────────────────────────────^^──────────────────────────┴──────────╯
_b_ Backlinks _a+_ Add alias _g_ Show graph
_c_ Capture _a-_ Remove alias _s_ Start UI server
_d_ Dailies _i_ Insert link _u_ Update db
_<_ Previous day _li_ Insert citation link
_>_ Next day _t+_ Add tag ^^ _q_:uit
_f_ Find note _t-_ Remove tag
_F_ Full-text search _P_ Promote heading to file
^^ _D_ Demote file to heading
"
("q" nil)
("a+" org-roam-alias-add)
("a-" org-roam-alias-remove)
("b" org-roam-buffer-toggle)
("c" org-roam-capture)
("d" org-roam-dailies-goto-today)
("<" org-roam-dailies-goto-previous-note :color red)
(">" org-roam-dailies-goto-next-note :color red)
("f" org-roam-node-find)
;; ("F" tl/search-in-org-roam-files) ; Way too slow!
("F" (lambda () (interactive) (tl/call-rg-in-directory my-org-roam-directory)))
("g" org-roam-graph)
("i" org-roam-node-insert)
("li" orb-insert-link)
("s" org-roam-ui-mode)
("t+" org-roam-alias-add)
("t-" org-roam-alias-remove)
("P" org-roam-extract-subtree)
("D" org-roam-demote-entire-buffer)
("u" org-roam-db-sync)
)
(defhydra hydra-deft (:hint nil :columns 3)
"Deft"
("a" deft-archive-file "archive" :exit t)
("d" deft-delete-file "delete" :exit t)
("k" deft-delete-file nil :exit t)
("f" deft-find-file "find" :exit t)
("g" deft-refresh "refresh" :exit t)
("n" deft-new-file "new" :exit t)
("r" deft-rename-file "rename" :exit t)
("l" deft-filter "filter" :exit t)
("/" deft-filter nil :exit t)
("Q" quit-window "quit" :exit t)
("q" nil :color blue)
)
;; inspired by https://github.com/abo-abo/hydra/wiki/Git-gutter
(defhydra hydra-git-gutter (:body-pre (git-gutter-mode 1)
:hint nil)
"
Git gutter
╭────────────╯
[_j_] next hunk [_s_]tage hunk [_q_]uit
[_k_] previous hunk [_r_]evert hunk [_Q_]uit and deactivate git-gutter
^ ^ [_p_]opup hunk
[_h_] first hunk
[_l_] last hunk set start [_R_]evision
"
("j" git-gutter:next-hunk)
("k" git-gutter:previous-hunk)
("h" (progn (goto-char (point-min))
(git-gutter:next-hunk 1)))
("l" (progn (goto-char (point-min))
(git-gutter:previous-hunk 1)))
("s" git-gutter:stage-hunk)
("r" git-gutter:revert-hunk)
("p" git-gutter:popup-hunk)
("R" git-gutter:set-start-revision)
("q" nil :color blue)
("Q" (progn (git-gutter-mode -1)
;; git-gutter-fringe doesn't seem to
;; clear the markup right away
(sit-for 0.1)
(git-gutter:clear))
:color blue))
- State “TODO” from [2018-11-21 Wed 22:06]
- [ ] needs revision
- [ ] define hydra for helm-ag
- [ ] unfold org-mode headings in follow mode
Inspired by https://github.com/abo-abo/hydra/wiki/Helm-2.
(defhydra hydra-helm (:hint nil
:color pink)
"
╭──────┐
Navigation Other Sources Mark Do Help │ Helm │
╭───────────────────────────────────────────────────────────────────────┴──────╯
^_k_^ _K_ _p_ [_m_] mark [_v_] view [_H_] helm help
^^↑^^ ^↑^ ^↑^ [_t_] toggle all [_d_] delete [_s_] source help
_h_ ← → _l_ _c_ ^ ^ [_u_] unmark all [_f_] follow: %(helm-attr 'follow)
^^↓^^ ^↓^ ^↓^ ^ ^ [_y_] yank selection
^_j_^ _J_ _n_ ^ ^ [_w_] toggle windows
--------------------------------------------------------------------------------
"
("<tab>" helm-keyboard-quit "back" :exit t)
("<escape>" nil "quit")
("\\" (insert "\\") "\\" :color blue)
("h" helm-beginning-of-buffer)
("j" helm-next-line)
("k" helm-previous-line)
("l" helm-end-of-buffer)
("g" helm-beginning-of-buffer)
("G" helm-end-of-buffer)
("n" helm-next-source)
("p" helm-previous-source)
("K" helm-scroll-other-window-down)
("J" helm-scroll-other-window)
("c" helm-recenter-top-bottom-other-window)
("m" helm-toggle-visible-mark)
("t" helm-toggle-all-marks)
("u" helm-unmark-all)
("H" helm-help)
("s" helm-buffer-help)
("v" helm-execute-persistent-action)
("d" helm-persistent-delete-marked)
("y" helm-yank-selection)
("w" helm-toggle-resplit-and-swap-windows)
("f" helm-follow-mode)
)
Adapted hydra from https://github.com/abo-abo/hydra/wiki/Ibuffer:
(defhydra hydra-ibuffer-main (:color pink :hint nil)
"
^Navigation^ ^Mark^ ^Actions^ ^View^
-^----------^------^----^----------^-------^----------^----^-------
_<up>_: ʌ _m_: mark _D_: delete _g_: refresh
_RET_: visit _u_: unmark _S_: save _s_: sort
_<down>_: v _*_: specific _a_: all actions _/_: filter
-^----------^---^----^----------^-------^----------^----^----------
"
("j" ibuffer-forward-line)
("<down>" ibuffer-forward-line)
("RET" ibuffer-visit-buffer :color blue)
("<up>" ibuffer-backward-line)
("k" ibuffer-backward-line)
("m" ibuffer-mark-forward)
("u" ibuffer-unmark-forward)
("*" hydra-ibuffer-mark/body :color blue)
("D" ibuffer-do-delete)
("S" ibuffer-do-save)
("a" hydra-ibuffer-action/body :color blue)
("g" ibuffer-update)
("s" hydra-ibuffer-sort/body :color blue)
("/" hydra-ibuffer-filter/body :color blue)
("o" ibuffer-visit-buffer-other-window "other window" :color blue)
("q" ibuffer-quit "quit ibuffer" :color blue)
("." nil "toggle hydra" :color blue))
(defhydra hydra-ibuffer-mark (:color teal :columns 5
:after-exit (hydra-ibuffer-main/body))
"Mark"
("*" ibuffer-unmark-all "unmark all")
("M" ibuffer-mark-by-mode "mode")
("m" ibuffer-mark-modified-buffers "modified")
("u" ibuffer-mark-unsaved-buffers "unsaved")
("s" ibuffer-mark-special-buffers "special")
("r" ibuffer-mark-read-only-buffers "read-only")
("/" ibuffer-mark-dired-buffers "dired")
("e" ibuffer-mark-dissociated-buffers "dissociated")
("h" ibuffer-mark-help-buffers "help")
("z" ibuffer-mark-compressed-file-buffers "compressed")
("b" hydra-ibuffer-main/body "back" :color blue))
(defhydra hydra-ibuffer-action (:color teal :columns 4
:after-exit
(if (eq major-mode 'ibuffer-mode)
(hydra-ibuffer-main/body)))
"Action"
("A" ibuffer-do-view "view")
("E" ibuffer-do-eval "eval")
("F" ibuffer-do-shell-command-file "shell-command-file")
("I" ibuffer-do-query-replace-regexp "query-replace-regexp")
("H" ibuffer-do-view-other-frame "view-other-frame")
("N" ibuffer-do-shell-command-pipe-replace "shell-cmd-pipe-replace")
("M" ibuffer-do-toggle-modified "toggle-modified")
("O" ibuffer-do-occur "occur")
("P" ibuffer-do-print "print")
("Q" ibuffer-do-query-replace "query-replace")
("R" ibuffer-do-rename-uniquely "rename-uniquely")
("T" ibuffer-do-toggle-read-only "toggle-read-only")
("U" ibuffer-do-replace-regexp "replace-regexp")
("V" ibuffer-do-revert "revert")
("W" ibuffer-do-view-and-eval "view-and-eval")
("X" ibuffer-do-shell-command-pipe "shell-command-pipe")
("b" nil "back"))
(defhydra hydra-ibuffer-sort (:color amaranth :columns 3)
"Sort"
("i" ibuffer-invert-sorting "invert")
("a" ibuffer-do-sort-by-alphabetic "alphabetic")
("v" ibuffer-do-sort-by-recency "recently used")
("s" ibuffer-do-sort-by-size "size")
("f" ibuffer-do-sort-by-filename/process "filename")
("m" ibuffer-do-sort-by-major-mode "mode")
("b" hydra-ibuffer-main/body "back" :color blue))
(defhydra hydra-ibuffer-filter (:color amaranth :columns 4)
"Filter"
("m" ibuffer-filter-by-used-mode "mode")
("M" ibuffer-filter-by-derived-mode "derived mode")
("n" ibuffer-filter-by-name "name")
("c" ibuffer-filter-by-content "content")
("e" ibuffer-filter-by-predicate "predicate")
("f" ibuffer-filter-by-filename "filename")
(">" ibuffer-filter-by-size-gt "size")
("<" ibuffer-filter-by-size-lt "size")
("/" ibuffer-filter-disable "disable")
("b" hydra-ibuffer-main/body "back" :color blue))
Automatically open the hydra with ibuffer:
(add-hook 'ibuffer-hook #'hydra-ibuffer-main/body)
;; (global-set-key (kbd "C-x b") 'ibuffer)
(defhydra hydra-image ()
"Manipulate image"
("+" imagex-sticky-zoom-in "zoom in")
("-" imagex-sticky-zoom-out "zoom out")
("m" imagex-sticky-maximize "maximize")
("o" imagex-sticky-restore-original "original")
;; ("S" imagex-sticky-save-image "save")
("r" imagex-sticky-rotate-right "rotate right")
("l" imagex-sticky-rotate-left "rotate left")
("n" image-next-file "next image")
("p" image-previous-file "previous image"))
Copied from https://github.com/cmcmahan/elisp/blob/master/emacs-hydra.el:
(global-set-key
(kbd "C-c d")
(defhydra hydra-insert-date (:exit t :hint none)
"
Insert Date
╭─────────────╯
[_1_] ?1? [_o_] ?o?
[_2_] ?2? [_O_] ?O?
[_3_] ?3?
[_4_] ?4? [_._] ?.?
[_5_] ?5? [_/_] ?/?
[_6_] ?6?
[_7_] ?7? [_q_] quit
"
("1" (insert-date "%y%m%d") (format-time-string "%y%m%d"))
("2" (insert-date "%Y-%m-%d") (format-time-string "%Y-%m-%d"))
("3" (insert-date) (format-time-string "%Y-%m-%d %a"))
("4" (insert-date "%Y-%m-%d %a %H:%M") (format-time-string "%Y-%m-%d %a %H:%M"))
("5" (insert-date "%Y-%m-%dT%T%z") (format-time-string "%Y-%m-%dT%T%z"))
("6" (insert-date "%B %d, %Y") (format-time-string "%B %d, %Y"))
("7" (insert-date "%A, %B %d, %Y") (format-time-string "%A, %B %d, %Y"))
;; ;; inspired from http://ergoemacs.org/emacs/elisp_insert-date-time.html
;; ("4" (progn
;; (when (use-region-p) (delete-region (region-beginning) (region-end)))
;; (insert (concat
;; (format-time-string "%Y-%m-%dT%T")
;; (funcall (lambda ($x) (format "%s:%s" (substring $x 0 3) (substring $x 3 5))) (format-time-string "%z"))))))
("o" (insert-date "[%Y-%m-%d %a %k:%M]") (format-time-string "[%Y-%m-%d %a %k:%M]"))
("O" (insert-date "<%Y-%m-%d %a %k:%M>") (format-time-string "<%Y-%m-%d %a %k:%M>"))
("/" (insert-date "%d/%m/%Y") (format-time-string "%d/%m/%Y"))
("." (insert-date "%d.%m.%Y") (format-time-string "%d.%m.%Y"))
("q" nil)))
(global-set-key (kbd "C-c i d") 'hydra-insert-date/body)
Copied from https://github.com/cmcmahan/elisp/blob/master/emacs-misc.el:
(defvar insert-time-format "%k:%M"
"*Format for \\[insert-time]. See `format-time-string' for info on how to format.")
(setq insert-time-format "%k:%M") ;; 08:09
(defvar insert-date-format "%Y-%m-%d"
"*Format for \\[insert-date]. See `format-time-string' for info on how to format.")
(setq insert-date-format "%Y-%m-%d %a") ;; 2015-03-26 Thu
(defun insert-time (&optional time-format)
"Insert the current time. Optional time format defaults to `insert-time-format'."
(interactive "*")
(let ((tformat (or time-format insert-time-format)))
(when (use-region-p)
(delete-region (region-beginning) (region-end)))
(insert (concat (format-time-string tformat (current-time)) ; " " ; removed by TL
))))
(defun insert-date (&optional date-format)
"Insert the current date. Option format defaults to `insert-date-format'."
(interactive "*")
(insert-time (or date-format insert-date-format)))
(defun insert-date-time ()
"Insert the current date formatted with `insert-date-format',
then a space, then the current time formatted with
`insert-time-format'."
(interactive "*")
(insert-time
(concat insert-date-format " " insert-time-format)))
(defun idt ()
"Shortcut to `insert-date-time'"
(interactive)
(insert-date-time))
(defun mp-insert-date ()
(interactive)
(insert (format-time-string "%x")))
(defun mp-insert-time ()
(interactive)
(insert (format-time-string "%X")))
;; (global-set-key (kbd "C-c i d") 'mp-insert-date)
;; (global-set-key (kbd "C-c i t") 'mp-insert-time)
(defun insert-current-file-name ()
(interactive)
(insert (buffer-file-name (current-buffer))))
(defhydra hydra-insert-file-name (:exit t :hint nil)
"
Insert File Name
╭──────────────────╯
[_._] ../relative/path [_w_] file name
[_/_] /absolute/path
^^ [_q_] quit
"
("/" (insert (read-file-name "")))
("." (insert (file-relative-name (read-file-name "")
(file-name-directory (buffer-file-name)))))
("w" (insert (file-name-nondirectory (read-file-name ""))))
("q" nil))
(global-set-key (kbd "C-c i f") 'hydra-insert-file-name/body)
(defhydra hydra-jump (:color blue :columns 3)
"Jump to"
("l" goto-line "line number")
("g" goto-line)
("TAB" move-to-column "column number")
("L" ace-jump-line-mode "visible line")
("c" ace-jump-mode "visible char")
("d" dumb-jump-go "definition")
("D" dumb-jump-go-prompt "definition(prompt)")
("f" dumb-jump-quick-look "definition (quick look)")
("b" dumb-jump-back "definition (back)"))
Hydra for khardel.
(defhydra hydra-khardel (:hint nil :columns 3)
"Khardel – Frontend for Khard"
("i" khardel-insert-email "insert email address" :exit t)
("e" khardel-edit-contact "edit contact" :exit t)
("n" khardel-new-contact "new contact" :exit t)
("s" tl/vdirsyncer-sync-contacts "sync contacts" :exit t)
("q" nil :color blue)
)
(defhydra hydra-latex-main (:hint nil :pre (outline-minor-mode 1))
"
^^ ^^ ^^ ^^ ╭────────┐
^Navigation^ ^Text^ ^Outline^ ^Compile^ │ LaTeX │
╭─^^──────────────────────────^^─────────────────────────^^──────────────────────^^──────────┴────────╯
_<up>_ previous heading _m_ insert macro _S-<tab>_ cycle all _c_ compile
_<down>_ next heading _s_ insert section _<tab>_ cycle at point _l_ show log
_=_ table of contents _e_ insert environment _M-<up>_ move up _r_ compile region
^^ _!e_ change environment _M-<down>_ move down _v_ view output
^^ _d_ delete... _M-<left>_ promote ___ set master file
^^ _f_ font... _M-<right>_ demote _b_ generate bib-file
^^ _#a_ align _o_ folding...
"
("<up>" tl/reftex-previous :exit nil)
("<down>" tl/reftex-next :exit nil)
("p" tl/reftex-previous :exit nil)
("n" tl/reftex-next :exit nil)
("=" reftex-toc :exit t)
("S-<tab>" (lambda () (interactive)
(save-excursion
(beginning-of-buffer)
(search-forward "\\begin{document}")
(outline-cycle)
(recenter-top-bottom))) :exit nil)
("<tab>" outline-cycle :exit nil)
("M-<up>" outline-move-subtree-up :exit nil)
("M-<down>" outline-move-subtree-down :exit nil)
("M-<left>" outline-promote :exit nil)
("M-<right>" outline-demote :exit nil)
("d" hydra-latex-delete/body :exit t)
("e" LaTeX-environment :exit t)
("!e" (lambda () (interactive) (LaTeX-environment '4)) :exit t)
("m" TeX-insert-macro :exit t)
("f" hydra-latex-fonts/body :exit t)
("#a" align-current :exit t)
("b" reftex-create-bibtex-file :exit t)
("c" TeX-command-master :exit t)
("l" TeX-recenter-output-buffer :exit t)
("r" TeX-command-region :exit t)
("s" LaTeX-section :exit t)
("o" hydra-latex-folding/body :exit t)
("v" TeX-view :exit t)
("_" TeX-master-file-ask :exit t)
("q" nil :color blue)
)
A hydra for code folding with AUCTeX:
(defhydra hydra-latex-folding (:hint nil :body-pre (TeX-fold-mode 1))
"LaTeX folding"
("b" TeX-fold-clearout-buffer "remove folding in buffer" :exit t)
("B" TeX-fold-buffer "activate folding in buffer" :exit t)
("o" TeX-fold-dwim "fold dwim" :exit t)
("Q" TeX-fold-mode "quit TeX-fold-mode" :exit t)
("q" nil :color blue)
)
A hydra for code deletion with AUCTeX:
(defhydra hydra-latex-delete (:hint nil)
"LaTeX deletion"
("f" TeX-deletefont "font" :exit t)
("e" TeX-delete-environment "environment" :exit t)
("m" TeX-delete-macro "macro" :exit t)
("t" TeX-clean "temporary files" :exit t)
("q" nil :color blue)
)
A hydra for font selection with AUCTeX:
(defhydra hydra-latex-fonts (:hint nil :columns 3)
"LaTeX fonts"
("b" TeX-bold "bold" :exit t)
("i" TeX-italic "italic" :exit t)
("t" TeX-typewriter "typewriter" :exit t)
("s" TeX-smallcaps "smallcaps" :exit t)
("e" TeX-emphasis "emphasis" :exit t)
("d" TeX-deletefont "delete" :exit t)
("!b" TeX-bold-replace "replace with bold" :exit t)
("!i" TeX-italic-replace "replace with italic" :exit t)
("!t" TeX-typewriter-replace "replace with typewriter" :exit t)
("!s" TeX-smallcaps-replace "replace with smallcaps" :exit t)
("!e" TeX-emphasis-replace "replace with emphasis" :exit t)
("q" nil :color blue)
)
Inspired by: https://github.com/abo-abo/hydra/wiki/Macro
(defhydra hydra-macro (:hint nil :color pink :pre
(when defining-kbd-macro
(kmacro-end-macro 1)))
"
^Create-Cycle^ ^Basic^ ^Counter^ ^Save^ ^Edit^
╭────────────────────────────────────────────────────────────────────────────╯
^_C-n_^ [_e_] execute [_ci_] insert [_N_] name [_'_] previous
^^↑^^ [_r_] on region [_cs_] set [_K_] key [_,_] last
_(_ ← → _)_ [_o_] edit [_ca_] add [_R_] register
^^↓^^ [_d_] delete [_cf_] format [_D_] defun
^_C-p_^ [_m_] step
^^ ^^ [_t_] swap on ring
"
("j" kmacro-start-macro :color blue)
("(" kmacro-start-macro :color blue)
("l" kmacro-end-or-call-macro-repeat)
(")" kmacro-end-or-call-macro-repeat)
("i" kmacro-cycle-ring-previous)
("C-p" kmacro-cycle-ring-previous)
("k" kmacro-cycle-ring-next)
("C-n" kmacro-cycle-ring-next)
("r" apply-macro-to-region-lines)
("d" kmacro-delete-ring-head)
("e" kmacro-end-or-call-macro-repeat)
("o" kmacro-edit-macro-repeat)
("m" kmacro-step-edit-macro)
("t" kmacro-swap-ring)
("ci" kmacro-insert-counter)
("cs" kmacro-set-counter)
("ca" kmacro-add-counter)
("cf" kmacro-set-format)
("N" kmacro-name-last-macro)
("K" kmacro-bind-to-key)
("D" insert-kbd-macro)
("R" kmacro-to-register)
("'" kmacro-edit-macro)
("," edit-kbd-macro)
("q" nil :color blue))
(defhydra hydra-markdown (:hint nil :color blue)
"
^^ ^^ ^^ ╭───────────────┐
^Heading^ ^Text^ ^Navigation^ │ markdown-mode │
╭──^^───────────────────────────^^────────────────────^^──────────────┴───────────────╯
_M-<right>_ demote _b_ bold
_M-<left>_ promote _i_ italic
_M-<up>_ move up _s_ strike through
_M-<down>_ move down _l_ link
_T_ generate TOC _>_ blockquote
^^ _`_ code
^^ _c_ code block
^^ _#_ table
"
("b" markdown-insert-bold)
("i" markdown-insert-italic)
("s" markdown-insert-strike-through)
("l" markdown-insert-link)
(">" markdown-insert-blockquote)
("`" markdown-insert-code)
("c" markdown-insert-gfm-code-block)
("#" hydra-markdown-table/body)
("M-<right>" markdown-demote :color pink)
("M-<left>" markdown-promote :color pink)
("M-<up>" markdown-move-up :color pink)
("M-<down>" markdown-move-down :color pink)
("T" markdown-toc-generate-toc)
("q" nil :color blue)
)
(defhydra hydra-markdown-table (:hint nil :color blue)
"
^^ ^^ ^^ ╭─────────────────────┐
^Navigation^ ^Insert & Delete^ ^Create & Convert │ markdown-mode table │
╭──^^──────────────────────────^^───────────────────────────^^───────────────────────┴─────────────────────╯
_<up>_ previous row _i_ insert table
_<down>_ next row _M-S-<up>_ delete row _t_ transpose table
_<left>_ left column _M-S-<down>_ insert row _|_ convert region
_<right>_ right column _M-S-<left>_ delete column _a_ align table
^^ _M-S-<right>_ insert column
"
("<up>" previous-line :color pink)
("<down>" markdown-table-next-row :color pink)
("<left>" markdown-table-backward-cell :color pink)
("<right>" markdown-table-forward-cell :color pink)
("M-<right>" markdown-demote :color pink)
("M-<left>" markdown-promote :color pink)
("M-<up>" markdown-move-up :color pink)
("M-<down>" markdown-move-down :color pink)
("M-S-<down>" markdown-table-insert-row :color pink)
("M-S-<up>" markdown-table-delete-row :color pink)
("M-S-<left>" markdown-table-delete-column :color pink)
("M-S-<right>" markdown-table-insert-column :color pink)
("i" markdown-insert-table)
("t" markdown-table-transpose)
("|" markdown-table-convert-region)
("a" markdown-table-align)
("q" nil :color blue)
)
(defhydra hydra-mu4e-headers (:hint none :color blue)
"
^^ ^^ ^^ ╭─────────────┐
^Header^ ^Navigation^ ^Filter^ │ mu4e-header │
╭──^^───────────────────────────^^──────────────────────────^^─────────────────────────────┴─────────────╯
_C_ Compose _p_ Previous _[_ unread _g_ Refresh _H_ Help
_R_ Reply _n_ Next _]_ unread _s_ Search _q_ quit
_F_ Forward _j_ Jump to mailbox _b_ Search with bookmarks
_N_ Edit as new _;_ Switch context _M-<left>_ Previous search
^Mark for^ ^^ _M-<right>_ Next search
_d_/_=_ Trash/Untrash _f_ Search with helm-mu
_!_/_?_ Read/Unread _Sv_ ?Sv? Split vertic. _c_ Contacts
_+_/_-_ Flag/Unflag _Sh_ ?Sh? Split horiz. _Pt_ Toggle threading
_u_ Unmark ^^ _Pr_ Toggle show related
_U_ Unmark all ^^ _O_ Change Sorting
_T_ Mark whole thread _._ View raw message
_a_ Action
_x_ Execute marks
"
("p" mu4e-headers-prev :color pink)
("n" mu4e-headers-next :color pink)
("s" mu4e-search)
("f" helm-mu)
("g" mu4e-search-rerun)
("j" mu4e~headers-jump-to-maildir)
("b" mu4e-search-bookmark)
("c" helm-mu-contacts)
("C" mu4e-compose-new)
("R" mu4e-compose-reply)
("F" mu4e-compose-forward)
("N" mu4e-compose-supersede)
("Pt" mu4e-headers-toggle-threading)
("Pr" mu4e-headers-toggle-include-related)
("O" mu4e-search-change-sorting)
("Sv" (setq mu4e-split-view 'vertical) (if (eq 'vertical mu4e-split-view) "[x]" "[ ]"))
("Sh" (setq mu4e-split-view 'horizontal) (if (eq 'horizontal mu4e-split-view) "[x]" "[ ]"))
("H" mu4e-display-manual)
("+" mu4e-headers-mark-for-flag)
("-" mu4e-headers-mark-for-unflag)
("d" mu4e-headers-mark-for-trash)
("=" mu4e-headers-mark-for-untrash)
("u" mu4e-headers-mark-for-unmark)
("U" mu4e-headers-unmark-all)
("T" mu4e-headers-mark-thread)
("x" mu4e-mark-execute-all)
("!" mu4e-headers-mark-for-read)
("?" mu4e-headers-mark-for-unread)
(";" mu4e-context-switch)
("." mu4e-view-raw-message)
("[" mu4e-headers-prev-unread :color pink)
("]" mu4e-headers-next-unread :color pink)
("M-<left>" mu4e-search-prev :color pink)
("M-<right>" mu4e-search-next :color pink)
("a" mu4e-headers-mark-for-action)
("q" nil :color blue)
)
(defhydra hydra-mu4e-view (:hint nil :color blue)
"
^^ ^^ ^^ ╭───────────┐
^Message^ ^Navigation^ ^Filter^ │ mu4e-view │
╭──^^───────────────────────────^^──────────────────────────^^─────────────────────────────┴───────────╯
_C_ Compose _p_ Previous _[_ unread _g_ Refresh _H_ Help
_R_ Reply _n_ Next _]_ unread _s_ Search _q_ quit
_F_ Forward _j_ Jump to mailbox _b_ Search with bookmarks
_N_ Edit as new _;_ Switch context _c_ Contacts
^Mark for^ ^^
_d_/_=_ Trash/Untrash _z_ Detach view _Pt_ Toggle threading
_!_/_?_ Read/Unread _._ View raw _Pr_ Toggle show related
_+_/_-_ Flag/Unflag ^^ _O_ Change Sorting
_u_ Unmark _e_ Save attachment
_U_ Unmark all _o_ Save inline image
_T_ Mark whole thread
_a_ Action
_A_ Action on attachment
_x_ Execute marks
"
("p" mu4e-view-headers-prev :color pink)
("n" mu4e-view-headers-next :color pink)
("s" mu4e-search)
("g" mu4e-search-rerun)
("j" mu4e~headers-jump-to-maildir)
("b" mu4e-search-bookmark)
("c" helm-mu-contacts)
("C" mu4e-compose-new)
("e" mu4e-view-save-attachments)
("o" image-save)
("R" mu4e-compose-reply)
("F" mu4e-compose-forward)
("N" mu4e-compose-supersede)
("O" mu4e-search-change-sorting)
("Pt" mu4e-headers-toggle-threading)
("Pr" mu4e-headers-toggle-include-related)
("+" mu4e-view-mark-for-flag)
("-" mu4e-view-mark-for-unflag)
("d" mu4e-view-mark-for-trash)
("=" mu4e-view-mark-for-untrash)
("u" mu4e-view-unmark)
("U" mu4e-view-unmark-all)
("T" mu4e-view-mark-thread)
("x" mu4e-view-marked-execute)
("z" tl/mu4e-detach-and-view-message-in-new-frame)
("!" mu4e-view-mark-for-read)
("?" mu4e-view-mark-for-unread)
(";" mu4e-context-switch)
("." mu4e-view-raw-message)
("[" mu4e-view-headers-prev-unread :color pink)
("]" mu4e-view-headers-next-unread :color pink)
("a" mu4e-view-action)
("A" mu4e-view-mime-part-action)
("H" mu4e-display-manual)
("q" nil :color blue)
)
- State “TODO” from [2024-04-02 Tue 16:04]
- [ ] Add keys for all address fields and more
(defhydra hydra-mu4e-compose (:hint nil :color blue)
"
^^ ^^ ^^ ╭───────────┐
^Actions^ ^Attach^ ^Contents^ │ mu4e-view │
╭──^^────────────────────────^^──────────────────────────^^──────────────────────┴───────────╯
_C-c C-c_ Send _af_ File _S_ Sign _H_ Help
_C-c C-d_ Pospone _ab_ Buffer _C_ Encrypt _q_ quit
_C-c C-j_ Delay _ac_ Clipoard _E_ Sign & encrypt
_C-c C-k_ Kill _aC_ Captured message _is_ Insert screenshot
^^ ^^ _ic_ Insert text with CAESAR13
"
("C-c C-c" message-send-and-exit)
("C-c C-d" message-dont-send)
("C-c C-j" gnus-delay-article)
("C-c C-k" mu4e-message-kill-buffer)
("af" mml-attach-file)
("ab" mml-attach-buffer)
("ac" my/mu4e-attach-image-from-clipboard)
("aC" mu4e-compose-attach-captured-message)
("S" mml-secure-sign)
("C" mml-secure-encrypt)
("E" mml-secure-message-sign-encrypt)
("is" message-insert-screenshot)
("ic" message-caesar-buffer-body)
("H" mu4e-display-manual)
("q" nil :color blue)
)
;; inspired by https://github.com/abo-abo/hydra/wiki/Flycheck
(defhydra hydra-flycheck
(:pre (flycheck-list-errors)
:post (quit-windows-on "*Flycheck errors*")
:hint nil)
"
Errors
╭────────╯
"
("f" flycheck-error-list-set-filter "Filter")
("j" flycheck-next-error nil)
("<down>" flycheck-next-error "Next")
("k" flycheck-previous-error nil)
("<up>" flycheck-previous-error "Previous")
("[" flycheck-first-error "First")
("]" (progn (goto-char (point-max)) (flycheck-previous-error)) "Last")
("Q" (flycheck-mode -1) "Quit flycheck-mode")
("q" nil))
(defhydra hydra-flyspell (:pre (when (not flyspell-mode)
(flyspell-mode +1)
(flyspell-buffer))
:color blue
:hint nil
:idle 0.2)
"
^^ ^^ ╭──────────┐
^^Flyspell ^^Ispell │ Flyspell │
╭──^^────────────────────────────^^─────────────────────────────┴──────────╯
[_<up>_] previous error [_b_] check buffer
[_c_] correct word [_w_] check word
[_<down>_] next error [_d_] change dictionary
[_f_] toggle flyspell [_q_] quit window
[_p_] toggle prog mode [_Q_] quit flyspell
"
("w" ispell-word :color red)
("i" ispell)
("b" ispell-buffer)
("d" ispell-change-dictionary)
("f" flyspell-mode)
("p" flyspell-prog-mode)
;; ("c" flyspell-auto-correct-word)
("c" flyspell-correct-word-generic)
;; ("<up>" flyspell-previous-and-ispell-word :color red)
;; ("<down>" flyspell-next-and-ispell-word :color red)
;; ("k" flyspell-previous-and-ispell-word :color red)
;; ("j" flyspell-next-and-ispell-word :color red)
("<up>" flyspell-goto-previous-and-correct :color red)
("<down>" flyspell-goto-next-and-correct :color red)
("k" flyspell-goto-previous-and-correct :color red)
("j" flyspell-goto-next-and-correct :color red)
("q" nil)
("Q" (flyspell-mode -1)))
;; inspired by https://github.com/abo-abo/hydra/wiki/Compilation
(defhydra hydra-compilation-error (:hint nil :body-pre (hydra-compilation-error-body-pre))
"
Compilation errors
╭────────────────────╯
[_<up>_] previous error [_l_] list errors [_q_]uit
[_<down>_] next error
"
("`" hydra-compilation-error-next)
("j" hydra-compilation-error-next)
("<down>" hydra-compilation-error-next)
("k" hydra-compilation-error-previous)
("<up>" hydra-compilation-error-previous)
("l" hydra-compilation-error-list :exit t)
("o" hydra-compilation-error-list :exit t)
("q" hydra-compilation-error-quit nil :color blue))
(defun hydra-compilation-error-next ()
(interactive)
(when (string-equal (buffer-mode) "latex-mode")
(TeX-next-error 1)))
(defun hydra-compilation-error-previous ()
(interactive)
(when (string-equal (buffer-mode) "latex-mode")
(TeX-previous-error 1)))
(defun hydra-compilation-error-list ()
(interactive)
(when (string-equal (buffer-mode) "latex-mode")
(TeX-error-overview)))
(defun hydra-compilation-error-quit ()
(interactive)
(when (string-equal (buffer-mode) "latex-mode")
(delete-other-windows)))
(defun hydra-compilation-error-body-pre ()
(interactive)
(when (string-equal (buffer-mode) "latex-mode")
(TeX-next-error 1)))
;; inspired by https://github.com/abo-abo/hydra/wiki/multiple-cursors
(defhydra hydra-multiple-cursors (:hint nil :idle 0.2)
"
^Up^ ^Down^ ^Other^
╭───^^───────────────────────────────^^──────────────^^───────────────────╯
[_S-<up>_] Next [_S-<down>_] Next [_l_] Edit lines
[_<up>_] Skip [_<down>_] Skip [_a_] Mark all
[_M-<up>_] Unmark [_M-<down>_] Unmark [_r_] Mark by regexp
[_SPC_] Mark region ^^ ^^[C-S-<mouse1>] Mark with mouse
^ ^ ^^ [_q_] Quit hydra [_Q_] Quit mc-mode
"
("l" mc/edit-lines :exit t)
("a" mc/mark-all-like-this :exit t)
("n" mc/mark-next-like-this)
("N" mc/skip-to-next-like-this)
("M-n" mc/unmark-next-like-this)
("S-<down>" mc/mark-next-like-this)
("<down>" mc/skip-to-next-like-this)
("M-<down>" mc/unmark-next-like-this)
("C-S-<mouse-1>" 'mc/add-cursor-on-click)
("p" mc/mark-previous-like-this)
("P" mc/skip-to-previous-like-this)
("M-p" mc/unmark-previous-like-this)
("SPC" set-rectangular-region-anchor :exit t)
("S-<up>" mc/mark-previous-like-this)
("<up>" mc/skip-to-previous-like-this)
("M-<up>" mc/unmark-previous-like-this)
("r" mc/mark-all-in-region-regexp :exit t)
("Q" (multiple-cursors-mode -1) :exit t)
("q" nil))
(global-set-key (kbd "C-<") 'hydra-multiple-cursors/body)
(global-set-key (kbd "M-+") 'hydra-multiple-cursors/body)
(global-set-key (kbd "C-S-<mouse-1>") 'mc/add-cursor-on-click)
(defhydra hydra-highlight-changes
(:body-pre (highlight-changes-mode +1)
:hint nil
:idle 0.5)
"
Highlight changes
╭───────────────────╯
_<up>_: next change _q_uit
_<down>_: previous change _Q_uit and turn off highlighting
"
("<down>" highlight-changes-next-change)
("<up>" highlight-changes-previous-change)
("<right>" highlight-changes-next-change)
("<left>" highlight-changes-previous-change)
("j" highlight-changes-next-change)
("k" highlight-changes-previous-change)
("n" highlight-changes-next-change)
("p" highlight-changes-previous-change)
("Q" (highlight-changes-mode -1) :color blue)
("q" nil :color blue))
(defhydra hydra-highlight-symbol
(:pre (highlight-symbol-at-point)
:hint nil
:idle 0.5)
"
Highlight symbol
╭──────────────────╯
_<up>_: previous occurrence _r_: replace occurrences _q_uit
_<down>_: next occurrence
"
("<down>" highlight-symbol-next)
("<up>" highlight-symbol-prev)
("<right>" highlight-symbol-next)
("<left>" highlight-symbol-prev)
("j" highlight-symbol-next)
("k" highlight-symbol-prev)
("n" highlight-symbol-next)
("p" highlight-symbol-prev)
("c" highlight-symbol-count)
("r" highlight-symbol-query-replace)
("l" highlight-symbol-list-all)
("q" highlight-symbol-remove-all :color blue))
Hydra taken from https://github.com/abo-abo/hydra/wiki/PDF-Tools#my-hydra-for-pdf-tools:
(defhydra hydra-pdftools (:color blue :hint nil)
"
╭───────────┐
Move History Scale/Fit Annotations Search/Link Do │ PDF Tools │
╭─────────────────────────────────────────────────────────────────────────────────────┴───────────╯
^^_g_^^ _B_/_M-<left>_ ^↧^ _+_ ^ ^ [_C-c C-a l_] list [_f_] search [_u_] revert buffer
^^^↑^^^ ^↑^^^ _H_ ^↑^ ↦ _W_ ↤ [_C-c C-a m_] markup... [_o_] outline [_i_] info
^^_p_^^ ^ ^^^ ^↥^ _0_ ^ ^ [_C-c C-a t_] text [_F_] link [_d_] dark mode
^^^↑^^^ ^↓^^^ ╭─^─^─┐ ^↓^ ╭─^ ^─┐ [_C-c C-a D_] delete [_f_] search link
_h_ ←pag_e_→ _l_ _N_/_M-<right>_ │ _P_ │ _-_ _b_ [_C-c C-a a_] attacments
^^^↓^^^ ^ ^^^ ╰─^─^─╯ ^ ^ ╰─^ ^─╯ [_C-w_] copy
^^_n_^^ ^ ^^^ _r_eset slice box
^^^↓^^^
^^_G_^^
--------------------------------------------------------------------------------
"
("\\" hydra-master/body "back")
("<ESC>" nil "quit")
("q" nil nil)
("C-c C-a l" pdf-annot-list-annotations)
("C-c C-a D" pdf-annot-delete)
("C-c C-a a" pdf-annot-attachment-dired)
("C-c C-a m" hydra-pdftools-markup/body)
("C-c C-a t" pdf-annot-add-text-annotation)
("C-w" pdf-view-kill-ring-save)
("+" pdf-view-enlarge :color red)
("-" pdf-view-shrink :color red)
("0" pdf-view-scale-reset)
("H" pdf-view-fit-height-to-window)
("W" pdf-view-fit-width-to-window)
("P" pdf-view-fit-page-to-window)
("n" pdf-view-next-page-command :color red)
("p" pdf-view-previous-page-command :color red)
("d" pdf-view-dark-minor-mode)
("b" pdf-view-set-slice-from-bounding-box)
("r" pdf-view-reset-slice)
("g" pdf-view-first-page)
("G" pdf-view-last-page)
("e" pdf-view-goto-page)
("o" pdf-outline)
("f" pdf-occur)
("s" isearch-forward)
("i" pdf-misc-display-metadata)
("u" pdf-view-revert-buffer)
("F" pdf-links-action-perfom)
;; ("f" pdf-links-isearch-link)
("B" pdf-history-backward :color red)
("M-<left>" pdf-history-backward :color red)
("N" pdf-history-forward :color red)
("M-<right>" pdf-history-forward :color red)
("l" image-forward-hscroll :color red)
("h" image-backward-hscroll :color red))
(with-eval-after-load 'pdf-tools
(define-key pdf-view-mode-map (kbd "C-f") 'pdf-occur))
(defhydra hydra-pdftools-markup (:color blue)
"PDFTools Markup"
("h" pdf-annot-add-highlight-markup-annotation "highlight")
("s" pdf-annot-add-squiggly-markup-annotation "squiggly")
("u" pdf-annot-add-underline-markup-annotation "underline")
("o" pdf-annot-add-strikeout-markup-annotation "strikeout")
("*" pdf-annot-add-markup-annotation "free choice")
)
(defhydra hydra-pomidor (:color blue)
"Pomidor"
("<return>" pomidor-stop "next")
("<space>" pomidor-break "pause")
("R" pomidor-reset "reset")
("q" quit-window "quit window")
("Q" pomidor-quit "quit pomidor")
)
(defhydra hydra-position-register (:hint nil :columns 4)
"Position register"
("i" iregister-point-to-register "insert position" :exit t)
("j" helm-register "jump to position" :exit t)
("n" iregister-jump-to-next-marker "next position" :exit t)
("p" iregister-jump-to-previous-marker "previous position" :exit t)
("d" (lambda () (interactive)
(setq register-alist '())
(message "Register is empty now.")) "clean register" :exit t)
("q" nil :color blue))
Switch between installed themes.
Copied from http://www.superloopy.io/articles/2017/hydra-theme-switcher.html:
(defun sb/disable-all-themes ()
(interactive)
(mapc #'disable-theme custom-enabled-themes))
(defun sb/load-theme (theme)
"Enhance `load-theme' by first disabling enabled themes."
(sb/disable-all-themes)
(load-theme theme))
(setq sb/hydra-selectors
"abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ")
(defun sb/sort-themes (themes)
(sort themes (lambda (a b) (string< (symbol-name a) (symbol-name b)))))
(defun sb/hydra-load-theme-heads (themes)
(mapcar* (lambda (a b)
(list (char-to-string a) `(sb/load-theme ',b) (symbol-name b)))
sb/hydra-selectors themes))
(bind-keys ("C-c w t" .
(lambda ()
(interactive)
(call-interactively
(eval `(defhydra sb/hydra-select-themes (:hint nil :color pink)
"Select Theme"
,@(sb/hydra-load-theme-heads (sb/sort-themes (custom-available-themes)))
("DEL" (sb/disable-all-themes))
("RET" nil "done" :color blue)))))))
I’ve added this to make it fit into hydra-f3:
(defun hydra-load-theme/body ()
(interactive)
(call-interactively
(eval `(defhydra sb/hydra-select-themes (:hint nil :color pink)
"Select Theme"
,@(sb/hydra-load-theme-heads (sb/sort-themes (custom-available-themes)))
("DEL" (sb/disable-all-themes))
("q" nil "quit" :color blue))))
)
(defhydra hydra-search (:color blue :hint nil)
"
^^ ^^ ^^ ^^ ╭────────┐
^in buffer^ ^across buffers^ ^grep-like^ ^file^ │ Search │
╭─^^─────────────────────^^──────────────────────^^───────────────────^^──────────┴────────╯
_b_ helm-swoop _B_ all buffers _a_ helm-ag _f_ helm-find
_s_ isearch forward _M_ all buffers _g_ git grep _c_ helm-recoll
_r_ isearch backward ^^ with current mode _p_ projectile grep
_o_ occur _O_ all buffers _R_ ripgrep
^^ ^^ _P_ pdfgrep
"
("a" helm-ag)
("b" helm-swoop)
("B" helm-multi-swoop-all)
("c" helm-recoll-all)
("M" helm-multi-swoop-current-mode)
("f" helm-find)
("g" helm-grep-do-git-grep)
("O" multi-occur)
("o" occur)
("p" projectile-grep)
("P" pdfgrep)
("r" isearch-backward)
("R" rg)
("s" isearch-forward)
)
(global-set-key (kbd "C-S-f") 'hydra-search/body)
From https://github.com/alphapapa/unpackaged.el#hydra.
(defhydra unpackaged/smerge-hydra
(:color pink :hint nil :post (smerge-auto-leave))
"
^Move^ ^Keep^ ^Diff^ ^Other^
^^-----------^^-------------------^^---------------------^^-------
_n_ext _b_ase _<_: upper/base _C_ombine
_p_rev _u_pper _=_: upper/lower _r_esolve
^^ _l_ower _>_: base/lower _k_ill current
^^ _a_ll _R_efine
^^ _RET_: current _E_diff
"
("n" smerge-next)
("p" smerge-prev)
("b" smerge-keep-base)
("u" smerge-keep-upper)
("l" smerge-keep-lower)
("a" smerge-keep-all)
("RET" smerge-keep-current)
("\C-m" smerge-keep-current)
("<" smerge-diff-base-upper)
("=" smerge-diff-upper-lower)
(">" smerge-diff-base-lower)
("R" smerge-refine)
("E" smerge-ediff)
("C" smerge-combine-with-next)
("r" smerge-resolve)
("k" smerge-kill-current)
("ZZ" (lambda ()
(interactive)
(save-buffer)
(bury-buffer))
"Save and bury buffer" :color blue)
("q" nil "cancel" :color blue))
(defhydra hydra-tags (:color red)
"Tags"
("." helm-etags-select "goto definition" :color blue)
("q" nil "cancel" :color blue))
Taken from https://github.com/abo-abo/hydra/wiki/Emacs
(defhydra hydra-transpose (:color red)
"Transpose"
("d" hydra-drag-stuff/body "drag stuff" :color blue)
("D" xah-fix-datetime "date")
("c" transpose-chars "characters")
("w" transpose-words "words")
("x" transpose-sexps "expressions")
("l" transpose-lines "lines")
("s" transpose-sentences "sentences")
("p" transpose-paragraphs "paragraphs")
("f" transpose-frame "frame")
("o" org-transpose-words "Org-words")
("e" org-transpose-element "Org-elements")
("tp" org-table-transpose-table-at-point "Org-table at point")
("tc" hydra-org-table-move-cell/body "Org-table cell")
("C-t" nil nil :color blue)
("q" nil "cancel" :color blue))
(global-set-key (kbd "C-t") 'hydra-transpose/body)
Helper function to transform date to yyyy-mm-dd format:
(defun xah-fix-datetime (@begin @end)
"Change timestamp under cursor into a yyyy-mm-dd format.
If there's a text selection, use that as input, else use current line.
Replace the text in selection or current line.
Any “day of week”, or “time” info, or any other parts of the string, are discarded.
For example:
TUESDAY, FEB 15, 2011 05:16 ET → 2011-02-15
November 28, 1994 → 1994-11-28
Nov. 28, 1994 → 1994-11-28
11/28/1994 → 1994-11-28
1994/11/28 → 1994-11-28
URL `http://ergoemacs.org/emacs/elisp_datetime_parser.html'
Version 2020-09-08"
(interactive
(list
(if (region-active-p) (region-beginning))
(if (region-active-p) (region-end))))
(require 'parse-time)
(let ($p1 $p2 $in)
(if @begin
(setq $p1 @begin $p2 @end)
(setq $p1 (line-beginning-position) $p2 (line-end-position)))
(setq $in (replace-regexp-in-string "^ *\\(.+\\) *$" "\\1" (buffer-substring-no-properties $p1 $p2)))
; remove white spaces
(setq $in
(cond
;; yyyy/mm/dd
((string-match "\\([0-9][0-9][0-9][0-9]\\)/\\([0-9][0-9]\\)/\\([0-9][0-9]\\)" $in)
(concat (match-string 1 $in) "-" (match-string 2 $in) "-" (match-string 3 $in)))
;; mm/dd/yyyy
((string-match "\\([0-9][0-9]\\)/\\([0-9][0-9]\\)/\\([0-9][0-9][0-9][0-9]\\)" $in)
(concat (match-string 3 $in) "-" (match-string 1 $in) "-" (match-string 2 $in)))
;; m/dd/yyyy
((string-match "\\([0-9]\\)/\\([0-9][0-9]\\)/\\([0-9][0-9][0-9][0-9]\\)" $in)
(concat (match-string 3 $in) "-0" (match-string 1 $in) "-" (match-string 2 $in)))
;; USA convention of mm/dd/yy
((string-match "\\([0-9][0-9]\\)/\\([0-9][0-9]\\)/\\([0-9][0-9]\\)" $in)
(concat (format-time-string "%C") (match-string 3 $in) "-" (match-string 1 $in) "-" (match-string 2 $in)))
;; USA convention of m/dd/yy
((string-match "\\([0-9]\\)/\\([0-9][0-9]\\)/\\([0-9][0-9]\\)" $in)
(concat (format-time-string "%C") (match-string 3 $in) "-0" (match-string 1 $in) "-" (match-string 2 $in)))
;; Inserted by Timm Lichte -->
;; dd.mm.yyyy
((string-match "\\([0-9][0-9]\\).\\([0-9][0-9]\\).\\([0-9][0-9][0-9][0-9]\\)" $in)
(concat (match-string 3 $in) "-" (match-string 2 $in) "-" (match-string 1 $in)))
;; d.mm.yyyy
((string-match "\\([0-9]\\).\\([0-9][0-9]\\).\\([0-9][0-9][0-9][0-9]\\)" $in)
(concat (match-string 3 $in) "-" (match-string 2 $in) "-0" (match-string 1 $in)))
;; d.m.yyyy
((string-match "\\([0-9]\\).\\([0-9]\\).\\([0-9][0-9][0-9][0-9]\\)" $in)
(concat (match-string 3 $in) "-0" (match-string 2 $in) "-0" (match-string 1 $in)))
;; dd.m.yyyy
((string-match "\\([0-9][0-9]\\).\\([0-9]\\).\\([0-9][0-9][0-9][0-9]\\)" $in)
(concat (match-string 3 $in) "-0" (match-string 2 $in) "-" (match-string 1 $in)))
;; dd.mm.yy
((string-match "\\([0-9][0-9]\\).\\([0-9][0-9]\\).\\([0-9][0-9]\\)" $in)
(concat (format-time-string "%C") (match-string 3 $in) "-" (match-string 2 $in) "-" (match-string 1 $in)))
;; d.mm.yy
((string-match "\\([0-9]\\).\\([0-9][0-9]\\).\\([0-9][0-9]\\)" $in)
(concat (format-time-string "%C") (match-string 3 $in) "-" (match-string 2 $in) "-0" (match-string 1 $in)))
;; dd.m.yy
((string-match "\\([0-9][0-9]\\).\\([0-9]\\).\\([0-9][0-9]\\)" $in)
(concat (format-time-string "%C") (match-string 3 $in) "-0" (match-string 2 $in) "-" (match-string 1 $in)))
;; d.m.yy
((string-match "\\([0-9]\\).\\([0-9]\\).\\([0-9][0-9]\\)" $in)
(concat (format-time-string "%C") (match-string 3 $in) "-0" (match-string 2 $in) "-0" (match-string 1 $in)))
;; Inserted by Timm Lichte <--
;; some ISO 8601. yyyy-mm-ddThh:mm
((string-match "\\([0-9][0-9][0-9][0-9]\\)-\\([0-9][0-9]\\)-\\([0-9][0-9]\\)T[0-9][0-9]:[0-9][0-9]" $in)
(concat (match-string 1 $in) "-" (match-string 2 $in) "-" (match-string 3 $in)))
;; some ISO 8601. yyyy-mm-dd
((string-match "\\([0-9][0-9][0-9][0-9]\\)-\\([0-9][0-9]\\)-\\([0-9][0-9]\\)" $in)
(concat (match-string 1 $in) "-" (match-string 2 $in) "-" (match-string 3 $in)))
;; some ISO 8601. yyyy-mm
((string-match "\\([0-9][0-9][0-9][0-9]\\)-\\([0-9][0-9]\\)" $in)
(concat (match-string 1 $in) "-" (match-string 2 $in)))
;; else
(t
(progn
(setq $in (replace-regexp-in-string "January " "Jan. " $in))
(setq $in (replace-regexp-in-string "February " "Feb. " $in))
(setq $in (replace-regexp-in-string "March " "Mar. " $in))
(setq $in (replace-regexp-in-string "April " "Apr. " $in))
(setq $in (replace-regexp-in-string "May " "May. " $in))
(setq $in (replace-regexp-in-string "June " "Jun. " $in))
(setq $in (replace-regexp-in-string "July " "Jul. " $in))
(setq $in (replace-regexp-in-string "August " "Aug. " $in))
(setq $in (replace-regexp-in-string "September " "Sep. " $in))
(setq $in (replace-regexp-in-string "October " "Oct. " $in))
(setq $in (replace-regexp-in-string "November " "Nov. " $in))
(setq $in (replace-regexp-in-string "December " "Dec. " $in))
(setq $in (replace-regexp-in-string "\\([0-9]+\\)st" "\\1" $in))
(setq $in (replace-regexp-in-string "\\([0-9]+\\)nd" "\\1" $in))
(setq $in (replace-regexp-in-string "\\([0-9]+\\)rd" "\\1" $in))
(setq $in (replace-regexp-in-string "\\([0-9]\\)th" "\\1" $in))
(let ($dateList $year $month $date $yyyy $mm $dd )
(setq $dateList (parse-time-string $in))
(setq $year (nth 5 $dateList))
(setq $month (nth 4 $dateList))
(setq $date (nth 3 $dateList))
(setq $yyyy (number-to-string $year))
(setq $mm (if $month (format "%02d" $month) "" ))
(setq $dd (if $date (format "%02d" $date) "" ))
(concat $yyyy "-" $mm "-" $dd))))))
(delete-region $p1 $p2 )
(insert $in)))
For package drag-stuff.
(defhydra hydra-drag-stuff (:color red)
"Drag stuff"
("<left>" drag-stuff-left "left")
("<right>" drag-stuff-right "right")
("<up>" drag-stuff-up "up")
("<down>" drag-stuff-down "down")
("q" nil "cancel" :color blue))
)
- State “TODO” from [2023-10-02 Mon 22:43]
- [ ] Overhaul and systematize key bindings.
Opinionated Emacs key bindings just for this init file.
(define-minor-mode tlkeys-mode
"Opinionated Emacs key bindings just for this init file."
:lighter nil
:global t
:init-value t
:keymap (let ((map (make-keymap)))
(define-key input-decode-map (kbd "C-i") (kbd "H-i")) ; to disentangle <tab> and C-i
;; disentangle keys when using Emacs server
;; local-function-key-map or input-decode-map are terminal-local
(defun my-disentangled-keys (&optional frame)
(with-selected-frame frame
(define-key input-decode-map (kbd "C-i") (kbd "H-i")) ; to disentangle <tab> and C-i
))
(add-hook 'after-make-frame-functions #'my-disentangled-keys)
;; delete
(define-key map (kbd "C-d") nil)
(define-key map (kbd "C-d C-k") 'kill-line)
(define-key map (kbd "C-d <up>") #'(lambda () (interactive) (tl/kill-forward-line -1)))
(define-key map (kbd "C-d <left>") 'delete-backward-char)
(define-key map (kbd "C-d <right>") 'delete-forward-char)
(define-key map (kbd "C-d <down>") #'(lambda () (interactive) (tl/kill-forward-line 1)))
(define-key map (kbd "C-d C-<up>") #'(lambda () (interactive) (tl/kill-forward-line -1)))
(define-key map (kbd "C-d C-<left>") 'delete-backward-char)
(define-key map (kbd "C-d C-<right>") 'delete-forward-char)
(define-key map (kbd "C-d C-<down>") #'(lambda () (interactive) (tl/kill-forward-line 1)))
(define-key map (kbd "C-d C-o") 'delete-blank-lines)
(define-key map (kbd "C-d C-m") 'remove-newlines-or-blank-lines-dwim)
(define-key map (kbd "C-d C-<return>") 'remove-newlines-or-blank-lines-dwim)
(define-key map (kbd "C-d C-a") #'(lambda () (interactive) (kill-line 0)))
(define-key map (kbd "C-d C-e") 'kill-line)
(define-key map (kbd "C-S-d") 'kill-whole-line)
(define-key map (kbd "C-d SPC") 'tl/remove-extra-spaces-dwim)
(define-key map (kbd "C-d C-SPC") 'tl/remove-extra-spaces-dwim)
(define-key map (kbd "C-d TAB") 'tl/delete-indentation)
(define-key map (kbd "C-d C-TAB") 'tl/delete-indentation)
(define-key map (kbd "C-d [") 'sp-unwrap-sexp)
(define-key map (kbd "C-d ]") 'sp-unwrap-sexp)
(define-key map (kbd "C-d {") 'sp-unwrap-sexp)
(define-key map (kbd "C-d }") 'sp-unwrap-sexp)
(define-key map (kbd "C-d (") 'sp-unwrap-sexp)
(define-key map (kbd "C-d )") 'sp-unwrap-sexp)
(define-key map (kbd "C-d DEL") 'hungry-delete-backward)
(define-key map (kbd "C-d <deletechar>") 'hungry-delete-forward)
;; LaTeX
(define-key LaTeX-mode-map (kbd "C-d m") 'TeX-delete-macro)
(define-key LaTeX-mode-map (kbd "C-d e") 'TeX-delete-environment)
(define-key LaTeX-mode-map (kbd "C-d t") 'TeX-clean)
;; return
(define-key input-decode-map (kbd "C-m") (kbd "H-o")) ; to disentangle <return> and C-m
(define-key key-translation-map (kbd "H-o") (kbd "RET"))
(define-key map (kbd "C-S-m") 'smart-open-line)
;; org-mode
(define-key org-mode-map (kbd "C-d r") 'org-babel-remove-result)
(define-key org-mode-map (kbd "C-d f") 'embrace-delete) ; delete emphasis/font
(define-key org-mode-map (kbd "C-d (") 'embrace-delete)
(define-key org-mode-map (kbd "C-d *") 'tl/embrace-delete-*)
(define-key org-mode-map (kbd "C-d /") 'tl/embrace-delete-/)
(define-key org-mode-map (kbd "C-d +") 'tl/embrace-delete-+)
(define-key org-mode-map (kbd "C-d _") 'tl/embrace-delete-_)
(define-key org-mode-map (kbd "C-d =") 'tl/embrace-delete-=)
(define-key org-mode-map (kbd "C-d ~") 'tl/embrace-delete-~)
(define-key org-mode-map (kbd "C-c f") 'embrace-add)
(define-key org-mode-map (kbd "C-d c") 'org-table-delete-column)
(define-key org-mode-map (kbd "C-d C-c") 'org-table-delete-column)
;; navigation
(define-key map (kbd "C-j") 'hydra-jump/body)
(define-key map (kbd "C-S-j") 'ace-jump-line-mode)
(define-key map (kbd "H-i") #'(lambda ()
(interactive)
(if (string= (buffer-mode) "org-mode")
(progn
(org-goto)
(recenter-top-bottom))
(helm-imenu))))
(define-key helm-map (kbd "H-i") 'helm-select-action) ; show actions (default is <tab>)
; (define-key map (kbd "C-S-i") 'imenu-list) ; disabled because it will break org-edit-special
;; buffers
(when (require 'bufler nil t)
(define-key map (kbd "C-x b") 'bufler))
(when (require 'helm-bufler nil t)
(define-key map (kbd "C-x C-b") 'helm-bufler-go))
(define-key map (kbd "C-x C-s") 'save-some-buffers)
;; helm
(define-key helm-map (kbd "C-n") 'helm-next-source)
(define-key helm-map (kbd "C-p") 'helm-previous-source)
(define-key helm-map (kbd "<tab>") 'helm-execute-persistent-action) ; complete with <tab> (default is <ret>)
(define-key helm-map (kbd "C-z") 'helm-select-action) ; show actions (default is <tab>)
(define-key helm-map (kbd "<left>") 'backward-char) ; instead of C-f
(define-key helm-map (kbd "<right>") 'forward-char) ; instead of C-b
(define-key helm-map (kbd "M-<left>") 'previous-history-element)
(define-key helm-map (kbd "M-<right>") 'next-history-element)
map)
;; body
(add-hook 'minibuffer-setup-hook 'tlkeys-minibuffer)
)
Key bindings in the minibuffer:
(defun tlkeys-minibuffer ()
"Keymap for the minibuffer."
(let ((map minibuffer-local-map))
;; delete
(define-key map (kbd "C-d") nil)
(define-key map (kbd "C-d C-k") 'kill-line)
(define-key map (kbd "C-d <up>") #'(lambda () (interactive) (tl/kill-forward-line -1)))
(define-key map (kbd "C-d <left>") 'delete-backward-char)
(define-key map (kbd "C-d <right>") 'delete-forward-char)
(define-key map (kbd "C-d <down>") #'(lambda () (interactive) (tl/kill-forward-line 1)))
(define-key map (kbd "C-d C-<up>") #'(lambda () (interactive) (tl/kill-forward-line -1)))
(define-key map (kbd "C-d C-<left>") 'delete-backward-char)
(define-key map (kbd "C-d C-<right>") 'delete-forward-char)
(define-key map (kbd "C-d C-<down>") #'(lambda () (interactive) (tl/kill-forward-line 1)))
(define-key map (kbd "C-d C-a") #'(lambda () (interactive) (kill-line 0)))
(define-key map (kbd "C-S-d") 'kill-whole-line)
(define-key map (kbd "C-d [") 'sp-unwrap-sexp)
(define-key map (kbd "C-d ]") 'sp-unwrap-sexp)
(define-key map (kbd "C-d {") 'sp-unwrap-sexp)
(define-key map (kbd "C-d }") 'sp-unwrap-sexp)
(define-key map (kbd "C-d (") 'sp-unwrap-sexp)
(define-key map (kbd "C-d )") 'sp-unwrap-sexp)
))
Start mode:
;; (add-hook 'text-mode-hook 'tlkeys-mode) ; superseded by :init-value t
;; (add-hook 'prog-mode-hook 'tlkeys-mode) ; superseded by :init-value t
Helper functions:
(defun tl/kill-forward-line (N)
(interactive)
(save-excursion
(when (= (forward-line N) 0)
(kill-whole-line))))
Key bindings for more ergonomic cursor movement: the cursor movement keys are under the <i> key and get activated with the Meta/Alt key.
Inspired by: http://ergoemacs.org/emacs/emacs_useful_user_keybinding.html
(define-minor-mode underi-mode
"Key bindings for more ergonomic cursor movement: the cursor movement keys are under the <i> key and get activated with the Meta/Alt key.
Inspired by: http://ergoemacs.org/emacs/emacs_useful_user_keybinding.html"
:lighter " ui"
:global t
:init-value t
:keymap (let ((map (make-keymap)))
;; cursor keys
(define-key key-translation-map (kbd "M-i") (kbd "<up>"))
(define-key key-translation-map (kbd "M-k") (kbd "<down>"))
(define-key key-translation-map (kbd "M-j") (kbd "<left>"))
(define-key key-translation-map (kbd "M-l") (kbd "<right>"))
(define-key key-translation-map (kbd "M-I") (kbd "S-<up>"))
(define-key key-translation-map (kbd "M-K") (kbd "S-<down>"))
(define-key key-translation-map (kbd "M-J") (kbd "S-<left>"))
(define-key key-translation-map (kbd "M-L") (kbd "S-<right>"))
;; more cursor keys
(define-key map (kbd "M-n") 'scroll-up-command)
(define-key map (kbd "M-p") 'scroll-down-command)
(define-key map (kbd "C-M-n") #'(lambda () (interactive) (scroll-up 3)))
(define-key map (kbd "C-M-p") #'(lambda () (interactive) (scroll-down 3)))
(define-key map (kbd "M-o") 'point-redo)
(define-key map (kbd "M-u") 'point-undo)
(define-key map (kbd "M-z") 'goto-last-change)
(define-key map (kbd "C-M-i") 'backward-paragraph)
(define-key map (kbd "C-M-k") 'forward-paragraph)
(define-key map (kbd "C-M-j") 'left-word)
(define-key map (kbd "C-M-l") 'right-word)
(define-key map (kbd "M-s-j") 'windmove-left)
(define-key map (kbd "M-s-l") 'windmove-right)
(define-key map (kbd "M-s-i") 'windmove-up)
(define-key map (kbd "M-s-k") 'windmove-down)
map)
;; body
(add-hook 'minibuffer-setup-hook 'underi-minibuffer)
)
Key bindings in the minibuffer:
(defun underi-minibuffer ()
"Keymap for the minibuffer."
(let ((map minibuffer-local-map))
;; move cursor
(define-key map (kbd "M-n") 'scroll-up-command)
(define-key map (kbd "M-p") 'scroll-down-command)
(define-key map (kbd "M-o") 'point-redo)
(define-key map (kbd "M-u") 'point-undo)
(define-key map (kbd "M-z") 'goto-last-change)
(define-key map (kbd "C-M-i") 'backward-paragraph)
(define-key map (kbd "C-M-k") 'forward-paragraph)
(define-key map (kbd "C-M-j") 'left-word)
(define-key map (kbd "C-M-l") 'right-word)
))
Start mode:
;; (add-hook 'text-mode-hook 'underi-mode) ; superseded by :init-value t
;; (add-hook 'prog-mode-hook 'underi-mode) ; superseded by :init-value t
Key bindings roughly following the conventions of the Windows habitat.
(define-minor-mode winkeys-mode
"Key bindings roughly following the conventions of the Windows habitat."
:init-value t
:global t
:lighter " wk"
:keymap (let ((map (make-keymap)))
;; save
(define-key map (kbd "C-s") 'save-buffer)
(define-key map (kbd "C-S-s") 'write-file)
;; search and replace
(define-key map (kbd "C-f") #'(lambda ()
(interactive)
(if (string= (buffer-mode) "pdf-view-mode")
;; helm-swoop does not work here
(call-interactively 'pdf-occur) ; `call-interactively' is needed by occur
(helm-swoop))))
;; (define-key map (kbd "C-S-f a") 'helm-multi-swoop-all)
;; (define-key map (kbd "C-S-f m") 'helm-multi-swoop-current-mode)
;; (define-key map (kbd "C-f") 'swiper-helm)
;; (define-key map (kbd "C-f") 'swiper)
;; (define-key map (kbd "C-f") 'isearch-search)
;; (define-key map (kbd "C-S-f s") 'isearch-forward)
;; (define-key map (kbd "C-S-f C-s") 'isearch-forward)
;; (define-key map (kbd "C-S-f r") 'isearch-backward)
;; (define-key map (kbd "C-S-f C-r") 'isearch-backward)
(define-key map (kbd "C-r") 'vr/replace)
(define-key map (kbd "C-S-r") 'vr/query-replace)
(define-key map (kbd "C-o") 'helm-find-files)
;; mark all
(define-key map (kbd "C-x C-a") 'mark-whole-buffer)
;; quit
(define-key key-translation-map (kbd "M-q") (kbd "C-g"))
;; undo/redo
;; (define-key map (kbd "C-z") 'undo-tree-undo)
;; (define-key map (kbd "C-S-z") 'undo-tree-redo)
;; yank
(define-key map (kbd "C-v") 'yank)
;; press ESC only once
(define-key map (kbd "<escape>") 'keyboard-escape-quit)
map
)
;; body
(add-hook 'minibuffer-setup-hook 'winkeys-minibuffer)
(with-eval-after-load 'helm-swoop
(define-key helm-swoop-map (kbd "C-r") 'helm-previous-line)
(define-key helm-swoop-map (kbd "C-f") 'tl/helm-swoop-C-s)
(define-key helm-multi-swoop-map (kbd "C-r") 'helm-previous-line)
(define-key helm-multi-swoop-map (kbd "C-f") 'helm-next-line)
(define-key helm-swoop-map (kbd "C-S-f a") 'helm-multi-swoop-all-from-helm-swoop)
(define-key helm-swoop-map (kbd "C-S-f m") 'helm-multi-swoop-current-mode-from-helm-swoop)
(define-key helm-swoop-map (kbd "M-a") 'helm-multi-swoop-all-from-helm-swoop))
(with-eval-after-load 'swiper-helm
(define-key swiper-helm-keymap (kbd "C-r") 'helm-previous-line)
(define-key swiper-helm-keymap (kbd "C-f") 'tl/swiper-helm-C-s))
(with-eval-after-load 'company
(define-key company-active-map (kbd "C-s") 'save-buffer))
;; (define-key key-translation-map (kbd "C-v") (kbd "C-y")) ; unfortunately this interferes with key chords using C-v
)
Key bindings in the minibuffer:
(defun winkeys-minibuffer ()
"Keymap for the minibuffer."
(let ((map minibuffer-local-map))
;; undo/redo
(define-key map (kbd "C-z") 'undo-tree-undo)
(define-key map (kbd "C-S-z") 'undo-tree-redo)
))
Let helm-swoop
behave more like isearch:
;; FIXME: does not follow search hits; helm-action-follow-forward does not work here
(defun tl/helm-swoop-C-s ()
(interactive)
(if (boundp 'helm-swoop-pattern)
(if (equal helm-swoop-pattern "")
(previous-history-element 1)
(helm-next-line))
(helm-next-line)
))
TESTING: Let swiper-helm
behave more like isearch:
(defun tl/swiper-helm-C-s ()
(interactive)
(if (boundp 'helm-pattern)
(if (equal helm-pattern "")
(previous-history-element 1)
(helm-next-line))
(helm-next-line)
))
https://github.com/publicus/emacs-org-mode-for-the-laity
emacs --debug-init
It has proven surprisingly useful to debug problems within Emacs from outside, namely by invoking pkill
from a shell like this:
pkill -SIGUSR2 emacs
I learned about this way of debugging Emacs from a question on StackOverflow: https://stackoverflow.com/q/65815662/6452961
If you experience strange crashes when starting emacs, it has proven effective to delete the content of the folder ~/.cache/org-persist.
Don’t ask me why.
org-persist
is used to store cached data across Emacs sessions.
https://www.gnu.org/software/emacs/manual/html_node/eintr/debug_002don_002dentry.html
(debug-on-entry FUNCTION)
Request FUNCTION to invoke debugger each time it is called.
Use M-x cancel-debug-on-entry
to cancel the effect of this command.
- https://www.gnu.org/software/emacs/manual/html_node/elisp/Error-Debugging.html
- https://emacsredux.com/blog/2025/03/01/debugging-errors-in-emacs/
Toggle whether to enter Lisp debugger when an error is signaled.
https://orgmode.org/manual/Feedback.html#Feedback
Load file with private settings after generic settings.
(let ((private-settings-file (expand-file-name "private-emacs-settings-after.el" private-emacs-settings-dir)))
(when (file-exists-p private-settings-file)
(load-file private-settings-file)))