diff --git a/configs/console/index.html b/configs/console/index.html index 92d095c..78c173c 100644 --- a/configs/console/index.html +++ b/configs/console/index.html @@ -76,8 +76,7 @@
-+No matter from which side you approach penguins, more always come from behind
-
No matter from which side you approach penguins, more always come from behind
(let ((val (if (ct-light-p (my/color-value name))
- (my/color-value 'black)
- (my/color-value 'white))))
+ (my/color-value 'black)
+ (my/color-value 'white))))
(if (eq quote 1)
(concat "\"" val "\"")
val))
@@ -137,31 +136,38 @@
I’m paranoid so I encrypt my SSH keys.
Got the idea for below from ArchWiki:
-if ! pgrep -u "$USER" ssh-agent > /dev/null; then
- ssh-agent -t 1h > "$XDG_RUNTIME_DIR/ssh-agent.env"
+SSH_AGENT_DIR="/tmp"
+
+if [ "$IS_ANDROID" == "true" ]; then
+ SSH_AGENT_DIR="/data/data/com.termux/files/tmp"
+ mkdir -p $SSH_AGENT_DIR
+fi
+
+if ! pgrep -u "$USER" ssh-agent > /dev/null; then
+ ssh-agent -t 1h > "$SSH_AGENT_DIR/ssh-agent.env"
fi
if [[ ! -f "$SSH_AUTH_SOCK" ]]; then
- source "$XDG_RUNTIME_DIR/ssh-agent.env" >/dev/null
+ source "$SSH_AGENT_DIR/ssh-agent.env" >/dev/null
fi
Guix settings
Enable extra profiles
if [ -z "$IS_ANDROID" ] && [ -z "$NO_GUIX" ] ; then
GUIX_EXTRA_PROFILES=$HOME/.guix-extra-profiles
for i in $GUIX_EXTRA_PROFILES/*; do
- profile=$i/$(basename "$i")
- if [ -f "$profile"/etc/profile ]; then
- GUIX_PROFILE="$profile"
- . "$GUIX_PROFILE"/etc/profile
- fi
- if [ -d "$profile"/share/man ]; then
- if command -v manpath; then
- export MANPATH="${MANPATH:-$(manpath)}:$profile/share/man"
- else
- export MANPATH="${MANPATH}:$profile/share/man"
- fi
- fi
- export XDG_DATA_DIRS="$XDG_DATA_DIRS:$profile/share"
- unset profile
+ profile=$i/$(basename "$i")
+ if [ -f "$profile"/etc/profile ]; then
+ GUIX_PROFILE="$profile"
+ . "$GUIX_PROFILE"/etc/profile
+ fi
+ if [ -d "$profile"/share/man ]; then
+ if command -v manpath >/dev/null 2>/dev/null; then
+ export MANPATH="${MANPATH:-$(manpath)}:$profile/share/man"
+ else
+ export MANPATH="${MANPATH}:$profile/share/man"
+ fi
+ fi
+ export XDG_DATA_DIRS="$XDG_DATA_DIRS:$profile/share"
+ unset profile
done
fi
Set Jupyter config PATH. It defaults to readonly directory somewhere in Guix profile.
@@ -276,7 +282,7 @@
If termux-setup-storage is available, then we’re running inside termux. It is necessary to source ~/.profile manually.
if command -v termux-setup-storage > /dev/null; then
if [[ -z "$IS_ANDROID" ]]; then
- source ~/.profile
+ source ~/.profile
fi
fi
Source the system-wide file
@@ -298,7 +304,7 @@Allow other users to access X server. Necessary for stuff like aw-watcher-window.
xhost +local:root > /dev/null 2>&1
Set manpager to bat
-export MANPAGER="sh -c 'sed -e s/.\\\\x08//g | bat -l man -p'"
+# export MANPAGER="sh -c 'sed -e s/.\\\\x08//g | bat -l man -p'"
eat integration
[ -n "$EAT_SHELL_INTEGRATION_DIR" ] && source "$EAT_SHELL_INTEGRATION_DIR/bash"
Launch fish
@@ -331,17 +337,17 @@
if ${use_color} ; then
# Enable colors for ls, etc. Prefer ~/.dir_colors #64489
if type -P dircolors >/dev/null ; then
- if [[ -f ~/.dir_colors ]] ; then
- eval $(dircolors -b ~/.dir_colors)
- elif [[ -f /etc/DIR_COLORS ]] ; then
- eval $(dircolors -b /etc/DIR_COLORS)
- fi
+ if [[ -f ~/.dir_colors ]] ; then
+ eval $(dircolors -b ~/.dir_colors)
+ elif [[ -f /etc/DIR_COLORS ]] ; then
+ eval $(dircolors -b /etc/DIR_COLORS)
+ fi
fi
if [[ ${EUID} == 0 ]] ; then
- PS1='\[\033[01;31m\][\h\[\033[01;36m\] \W\[\033[01;31m\]]\$\[\033[00m\] '
+ PS1='\[\033[01;31m\][\h\[\033[01;36m\] \W\[\033[01;31m\]]\$\[\033[00m\] '
else
- PS1='\[\033[01;32m\][\u@\h\[\033[01;37m\] \W\[\033[01;32m\]]\$\[\033[00m\] '
+ PS1='\[\033[01;32m\][\u@\h\[\033[01;37m\] \W\[\033[01;32m\]]\$\[\033[00m\] '
fi
alias ls='ls --color=auto'
@@ -350,10 +356,10 @@
alias fgrep='fgrep --colour=auto'
else
if [[ ${EUID} == 0 ]] ; then
- # show root@ when we don't have colors
- PS1='\u@\h \W \$ '
+ # show root@ when we don't have colors
+ PS1='\u@\h \W \$ '
else
- PS1='\u@\h \w \$ '
+ PS1='\u@\h \w \$ '
fi
fi
@@ -401,21 +407,20 @@
I’ve moved from conda to micromamba because it’s faster.
-+managed by ‘mamba init’ !!!
-
managed by ‘mamba init’ !!!
Yeah, tell this to yourself
init_mamba () {
export MAMBA_EXE="/home/pavel/.guix-extra-profiles/dev/dev/bin/micromamba";
export MAMBA_ROOT_PREFIX="/home/pavel/micromamba";
__mamba_setup="$("$MAMBA_EXE" shell hook --shell bash --prefix "$MAMBA_ROOT_PREFIX" 2> /dev/null)"
if [ $? -eq 0 ]; then
- eval "$__mamba_setup"
+ eval "$__mamba_setup"
else
- if [ -f "/home/pavel/micromamba/etc/profile.d/micromamba.sh" ]; then
- . "/home/pavel/micromamba/etc/profile.d/micromamba.sh"
- else
- export PATH="/home/pavel/micromamba/bin:$PATH" # extra space after export prevents interference from conda init
- fi
+ if [ -f "/home/pavel/micromamba/etc/profile.d/micromamba.sh" ]; then
+ . "/home/pavel/micromamba/etc/profile.d/micromamba.sh"
+ else
+ export PATH="/home/pavel/micromamba/bin:$PATH" # extra space after export prevents interference from conda init
+ fi
fi
unset __mamba_setup
}
@@ -456,8 +461,8 @@
starship init fish | source
else
function fish_prompt -d "Write out the prompt"
- printf '%s@%s %s%s%s > ' $USER $hostname \
- (set_color $fish_color_cwd) (basename (pwd)) (set_color normal)
+ printf '%s@%s %s%s%s > ' $USER $hostname \
+ (set_color $fish_color_cwd) (basename (pwd)) (set_color normal)
end
end
Enable vi keybindings & aliases. The alias syntax is the same as in bash, so it’s just a noweb reference to .bashrc.
Also, get a foreground for the current color:
(let ((val (if (ct-light-p (my/color-value name))
- (my/color-value 'black)
- (my/color-value 'white))))
+ (my/color-value 'black)
+ (my/color-value 'white))))
(if (eq quote 1)
(concat "\"" val "\"")
val))
@@ -203,7 +203,7 @@
(concat "*" (nth 1 elem) ": " (my/color-value (nth 0 elem))))
(seq-filter
(lambda (elem) (and (nth 1 elem)
- (not (string-empty-p (nth 1 elem)))))
+ (not (string-empty-p (nth 1 elem)))))
table)
"\n")
<<get-xresources()>>
@@ -216,10 +216,10 @@
(let ((hostname (system-name)))
(cond ((string-equal hostname "azure") 120)
- ((string-equal hostname "eminence") 120)
- ((string-equal hostname "violet") 120)
- ((string-equal hostname "iris") 120)
- (t 96)))
+ ((string-equal hostname "eminence") 120)
+ ((string-equal hostname "violet") 120)
+ ((string-equal hostname "iris") 120)
+ (t 96)))
Xft.dpi: <<get-dpi()>>
Themes
A few programs I use to customize the apperance are listed below.
@@ -446,21 +446,21 @@
Does not take the minibuffer into account."
(cl-some (lambda (dir)
- (let ((win (windmove-find-other-window dir)))
- (and win (not (window-minibuffer-p win)))))
- (pcase dir
- ('width '(left right))
- ('height '(up down)))))
+ (let ((win (windmove-find-other-window dir)))
+ (and win (not (window-minibuffer-p win)))))
+ (pcase dir
+ ('width '(left right))
+ ('height '(up down)))))
And a function to implement that:
(defun my/exwm-move-window (dir)
"Move the current window in the direction DIR."
(let ((other-window (windmove-find-other-window dir))
- (other-direction (my/exwm-direction-exists-p
- (pcase dir
- ('up 'width)
- ('down 'width)
- ('left 'height)
- ('right 'height)))))
+ (other-direction (my/exwm-direction-exists-p
+ (pcase dir
+ ('up 'width)
+ ('down 'width)
+ ('left 'height)
+ ('right 'height)))))
(cond
((and other-window (not (window-minibuffer-p other-window)))
(window-swap-states (selected-window) other-window))
@@ -483,20 +483,20 @@
(unless value
(setq value my/exwm-resize-value))
(let* ((is-exwm-floating
- (and (derived-mode-p 'exwm-mode)
- exwm--floating-frame))
- (func (if is-exwm-floating
- (intern
- (concat
- "exwm-layout-"
- (pcase kind ('shrink "shrink") ('grow "enlarge"))
- "-window"
- (pcase dir ('height "") ('width "-horizontally"))))
- (intern
- (concat
- "evil-window"
- (pcase kind ('shrink "-decrease-") ('grow "-increase-"))
- (symbol-name dir))))))
+ (and (derived-mode-p 'exwm-mode)
+ exwm--floating-frame))
+ (func (if is-exwm-floating
+ (intern
+ (concat
+ "exwm-layout-"
+ (pcase kind ('shrink "shrink") ('grow "enlarge"))
+ "-window"
+ (pcase dir ('height "") ('width "-horizontally"))))
+ (intern
+ (concat
+ "evil-window"
+ (pcase kind ('shrink "-decrease-") ('grow "-increase-"))
+ (symbol-name dir))))))
(when is-exwm-floating
(setq value (* 5 value)))
(funcall func value)))
@@ -524,17 +524,17 @@
(interactive)
(when (and (eq major-mode 'exwm-mode) (not (eq (next-window) (get-buffer-window))))
(let ((other-exwm-buffer
- (cl-loop with other-buffer = (persp-other-buffer)
- for buf in (sort (persp-current-buffers) (lambda (a _) (eq a other-buffer)))
- with current-buffer = (current-buffer)
- when (and (not (eq current-buffer buf))
- (buffer-live-p buf)
- (not (string-match-p (persp--make-ignore-buffer-rx) (buffer-name buf)))
- (not (get-buffer-window buf)))
- return buf)))
+ (cl-loop with other-buffer = (persp-other-buffer)
+ for buf in (sort (persp-current-buffers) (lambda (a _) (eq a other-buffer)))
+ with current-buffer = (current-buffer)
+ when (and (not (eq current-buffer buf))
+ (buffer-live-p buf)
+ (not (string-match-p (persp--make-ignore-buffer-rx) (buffer-name buf)))
+ (not (get-buffer-window buf)))
+ return buf)))
(when other-exwm-buffer
- (with-selected-window (next-window)
- (switch-to-buffer other-exwm-buffer))))))
+ (with-selected-window (next-window)
+ (switch-to-buffer other-exwm-buffer))))))
This is meant to be called after doing an either vertical or horizontal split, so it’s advised like that:
(advice-add 'evil-window-split :after #'my/exwm-fill-other-window)
(advice-add 'evil-window-vsplit :after #'my/exwm-fill-other-window)
@@ -557,11 +557,11 @@
:straight t
:config
(setq perspective-exwm-override-initial-name
- '((0 . "misc")
- (1 . "core")
- (2 . "browser")
- (3 . "comms")
- (4 . "dev")))
+ '((0 . "misc")
+ (1 . "core")
+ (2 . "browser")
+ (3 . "comms")
+ (4 . "dev")))
(setq perspective-exwm-cycle-max-message-length 180)
(general-define-key
:keymaps 'perspective-map
@@ -575,23 +575,23 @@
(pcase exwm-class-name
((or "Firefox" "Nightly")
(perspective-exwm-assign-window
- :workspace-index 2
- :persp-name "browser"))
+ :workspace-index 2
+ :persp-name "browser"))
("Nyxt"
(perspective-exwm-assign-window
- :workspace-index 2
- :persp-name "browser"))
+ :workspace-index 2
+ :persp-name "browser"))
("Alacritty"
(perspective-exwm-assign-window
- :persp-name "term"))
+ :persp-name "term"))
((or "VK" "Slack" "discord" "TelegramDesktop" "Rocket.Chat")
(perspective-exwm-assign-window
- :workspace-index 3
- :persp-name "comms"))
+ :workspace-index 3
+ :persp-name "comms"))
((or "Chromium-browser" "jetbrains-datagrip")
(perspective-exwm-assign-window
- :workspace-index 4
- :persp-name "dev")))))
+ :workspace-index 4
+ :persp-name "dev")))))
(add-hook 'exwm-manage-finish-hook #'my/exwm-configure-window)
The variable my/exwm-last-workspaces stores the workspace indices; the first item is the index of the current workspace, the second item is the index of the previous workspace, and so on.
One note here is that workspaces may also disappear (e.g. after M-x exwm-workspace-delete), so we also need a function to clean the list:
(defun my/exwm-last-workspaces-clear ()
"Clean `my/exwm-last-workspaces' from deleted workspaces."
(setq my/exwm-last-workspaces
- (seq-filter
- (lambda (i) (nth i exwm-workspace--list))
- my/exwm-last-workspaces)))
+ (seq-filter
+ (lambda (i) (nth i exwm-workspace--list))
+ my/exwm-last-workspaces)))
The second piece of the puzzle is getting the monitor list in the right order.
While it is possible to retrieve the monitor list from exwm-randr-workspace-monitor-plist, this won’t scale well beyond two monitors, mainly because changing this variable may screw up the order.
So the easiest way is to just define the variable like that:
(setq my/exwm-monitor-list
(pcase (system-name)
- ("indigo" '(nil "DVI-D-0"))
- ("violet" '(nil "DP-1"))
- (_ '(nil))))
+ ("indigo" '(nil "DVI-D-0"))
+ ("violet" '(nil "DP-1"))
+ (_ '(nil))))
If you are changing the RandR configuration on the fly, this variable will also need to be changed, but for now, I don’t have such a necessity.
A function to get the current monitor:
(defun my/exwm-get-current-monitor ()
"Return the current monitor name or nil."
(plist-get exwm-randr-workspace-monitor-plist
- (cl-position (selected-frame)
- exwm-workspace--list)))
+ (cl-position (selected-frame)
+ exwm-workspace--list)))
And a function to cycle the monitor list in either direction:
(defun my/exwm-get-other-monitor (dir)
"Cycle the monitor list in the direction DIR.
@@ -647,13 +647,13 @@
DIR is either 'left or 'right."
(nth
(% (+ (cl-position
- (my/exwm-get-current-monitor)
- my/exwm-monitor-list
- :test #'string-equal)
- (length my/exwm-monitor-list)
- (pcase dir
- ('right 1)
- ('left -1)))
+ (my/exwm-get-current-monitor)
+ my/exwm-monitor-list
+ :test #'string-equal)
+ (length my/exwm-monitor-list)
+ (pcase dir
+ ('right 1)
+ ('left -1)))
(length my/exwm-monitor-list))
my/exwm-monitor-list))
I bind this function to s-q, as I’m used from i3.
Now, moving the workspace to another monitor.
@@ -683,20 +683,20 @@ "Move the current workspace to another monitor." (interactive) (let ((new-monitor (my/exwm-get-other-monitor 'right)) - (current-monitor (my/exwm-get-current-monitor))) + (current-monitor (my/exwm-get-current-monitor))) (when (and current-monitor - (>= 1 - (cl-loop for (key value) on exwm-randr-workspace-monitor-plist - by 'cddr - if (string-equal value current-monitor) sum 1))) + (>= 1 + (cl-loop for (key value) on exwm-randr-workspace-monitor-plist + by 'cddr + if (string-equal value current-monitor) sum 1))) (error "Can't remove the last workspace on the monitor!")) (setq exwm-randr-workspace-monitor-plist - (map-delete exwm-randr-workspace-monitor-plist exwm-workspace-current-index)) + (map-delete exwm-randr-workspace-monitor-plist exwm-workspace-current-index)) (when new-monitor (setq exwm-randr-workspace-monitor-plist - (plist-put exwm-randr-workspace-monitor-plist - exwm-workspace-current-index - new-monitor)))) + (plist-put exwm-randr-workspace-monitor-plist + exwm-workspace-current-index + new-monitor)))) (exwm-randr-refresh))In my configuration this is bound to s-<tab>.
Setting up some completion interfaces that fit particularly well to use with EXWM. While rofi also works, I want to use Emacs functionality wherever possible to have one completion interface everywhere.
SOURCE: https://github.com/ch11ng/exwm/issues/550#issuecomment-744784838
(defun my/advise-fn-suspend-follow-mouse (fn &rest args)
(let ((focus-follows-mouse nil)
- (mouse-autoselect-window nil)
- (pos (x-mouse-absolute-pixel-position)))
+ (mouse-autoselect-window nil)
+ (pos (x-mouse-absolute-pixel-position)))
(unwind-protect
- (apply fn args)
+ (apply fn args)
(x-set-mouse-absolute-pixel-position (car pos)
- (cdr pos)))))
+ (cdr pos)))))
(with-eval-after-load 'ivy-posframe
(advice-add #'ivy-posframe--read :around #'my/advise-fn-suspend-follow-mouse))
First, some prefixes for keybindings that are always passed to EXWM instead of the X application in line-mode:
(setq exwm-input-prefix-keys
`(?\C-x
- ?\C-w
- ?\M-x
- ?\M-u))
+ ?\C-w
+ ?\M-x
+ ?\M-u))
Also other local keybindings, that are also available only in line-mode:
(defmacro my/app-command (command)
`(lambda () (interactive) (my/run-in-background ,command)))
@@ -833,106 +833,106 @@
"M-SPC" (general-key "SPC"))
Simulation keys.
(setopt exwm-input-simulation-keys `(
- ;; (,(kbd "M-w") . ,(kbd "C-w"))
- (,(kbd "M-c") . ,(kbd "C-c"))))
+ ;; (,(kbd "M-w") . ,(kbd "C-w"))
+ (,(kbd "M-c") . ,(kbd "C-c"))))
A quit function with a confirmation.
(defun my/exwm-quit ()
(interactive)
(when (or (not (eq (selected-window) (next-window)))
- (y-or-n-p "This is the last window. Are you sure?"))
+ (y-or-n-p "This is the last window. Are you sure?"))
(evil-quit)))
And keybindings that are available in both char-mode and line-mode:
(setq exwm-input-global-keys
`(
- ;; Reset to line-mode
- (,(kbd "s-R") . exwm-reset)
+ ;; Reset to line-mode
+ (,(kbd "s-R") . exwm-reset)
- ;; Switch windows
- (,(kbd "s-<left>") . (lambda () (interactive) (my/exwm-windmove 'left)))
- (,(kbd "s-<right>") . (lambda () (interactive) (my/exwm-windmove 'right)))
- (,(kbd "s-<up>") . (lambda () (interactive) (my/exwm-windmove 'up)))
- (,(kbd "s-<down>") . (lambda () (interactive) (my/exwm-windmove 'down)))
+ ;; Switch windows
+ (,(kbd "s-<left>") . (lambda () (interactive) (my/exwm-windmove 'left)))
+ (,(kbd "s-<right>") . (lambda () (interactive) (my/exwm-windmove 'right)))
+ (,(kbd "s-<up>") . (lambda () (interactive) (my/exwm-windmove 'up)))
+ (,(kbd "s-<down>") . (lambda () (interactive) (my/exwm-windmove 'down)))
- (,(kbd "s-h"). (lambda () (interactive) (my/exwm-windmove 'left)))
- (,(kbd "s-l") . (lambda () (interactive) (my/exwm-windmove 'right)))
- (,(kbd "s-k") . (lambda () (interactive) (my/exwm-windmove 'up)))
- (,(kbd "s-j") . (lambda () (interactive) (my/exwm-windmove 'down)))
+ (,(kbd "s-h"). (lambda () (interactive) (my/exwm-windmove 'left)))
+ (,(kbd "s-l") . (lambda () (interactive) (my/exwm-windmove 'right)))
+ (,(kbd "s-k") . (lambda () (interactive) (my/exwm-windmove 'up)))
+ (,(kbd "s-j") . (lambda () (interactive) (my/exwm-windmove 'down)))
- ;; Moving windows
- (,(kbd "s-H") . (lambda () (interactive) (my/exwm-move-window 'left)))
- (,(kbd "s-L") . (lambda () (interactive) (my/exwm-move-window 'right)))
- (,(kbd "s-K") . (lambda () (interactive) (my/exwm-move-window 'up)))
- (,(kbd "s-J") . (lambda () (interactive) (my/exwm-move-window 'down)))
+ ;; Moving windows
+ (,(kbd "s-H") . (lambda () (interactive) (my/exwm-move-window 'left)))
+ (,(kbd "s-L") . (lambda () (interactive) (my/exwm-move-window 'right)))
+ (,(kbd "s-K") . (lambda () (interactive) (my/exwm-move-window 'up)))
+ (,(kbd "s-J") . (lambda () (interactive) (my/exwm-move-window 'down)))
- ;; Fullscreen
- (,(kbd "s-f") . exwm-layout-toggle-fullscreen)
- (,(kbd "s-F") . exwm-floating-toggle-floating)
+ ;; Fullscreen
+ (,(kbd "s-f") . exwm-layout-toggle-fullscreen)
+ (,(kbd "s-F") . exwm-floating-toggle-floating)
- ;; Quit
- (,(kbd "s-Q") . my/exwm-quit)
+ ;; Quit
+ (,(kbd "s-Q") . my/exwm-quit)
- ;; Split windows
- (,(kbd "s-s") . evil-window-vsplit)
- (,(kbd "s-v") . evil-window-hsplit)
+ ;; Split windows
+ (,(kbd "s-s") . evil-window-vsplit)
+ (,(kbd "s-v") . evil-window-hsplit)
- ;; Switch perspectives
- (,(kbd "s-,") . persp-prev)
- (,(kbd "s-.") . persp-next)
+ ;; Switch perspectives
+ (,(kbd "s-,") . persp-prev)
+ (,(kbd "s-.") . persp-next)
- ;; Switch buffers
- (,(kbd "s-e") . persp-switch-to-buffer*)
- ;; (,(kbd "s-E") . my/persp-ivy-switch-buffer-other-window)
+ ;; Switch buffers
+ (,(kbd "s-e") . persp-switch-to-buffer*)
+ ;; (,(kbd "s-E") . my/persp-ivy-switch-buffer-other-window)
- ;; Resize windows
- (,(kbd "s-r") . my/exwm-resize-hydra/body)
+ ;; Resize windows
+ (,(kbd "s-r") . my/exwm-resize-hydra/body)
- ;; Apps & stuff
- (,(kbd "s-p") . app-launcher-run-app)
- (,(kbd "s-P") . async-shell-command)
- (,(kbd "s-;") . my/exwm-apps-hydra/body)
- (,(kbd "s--") . password-store-completion)
- (,(kbd "s-=") . emoji-insert)
- (,(kbd "s-i") . ,(my/app-command "copyq menu"))
+ ;; Apps & stuff
+ (,(kbd "s-p") . app-launcher-run-app)
+ (,(kbd "s-P") . async-shell-command)
+ (,(kbd "s-;") . my/exwm-apps-hydra/body)
+ (,(kbd "s--") . password-store-completion)
+ (,(kbd "s-=") . emoji-insert)
+ (,(kbd "s-i") . ,(my/app-command "copyq menu"))
- ;; Basic controls
- (,(kbd "<XF86AudioRaiseVolume>") . ,(my/app-command "ponymix increase 5 --max-volume 150"))
- (,(kbd "<XF86AudioLowerVolume>") . ,(my/app-command "ponymix decrease 5 --max-volume 150"))
- (,(kbd "<XF86MonBrightnessUp>") . ,(my/app-command "light -A 5"))
- (,(kbd "<XF86MonBrightnessDown>") . ,(my/app-command "light -U 5"))
- (,(kbd "<XF86AudioMute>") . ,(my/app-command "ponymix toggle"))
+ ;; Basic controls
+ (,(kbd "<XF86AudioRaiseVolume>") . ,(my/app-command "ponymix increase 5 --max-volume 150"))
+ (,(kbd "<XF86AudioLowerVolume>") . ,(my/app-command "ponymix decrease 5 --max-volume 150"))
+ (,(kbd "<XF86MonBrightnessUp>") . ,(my/app-command "light -A 5"))
+ (,(kbd "<XF86MonBrightnessDown>") . ,(my/app-command "light -U 5"))
+ (,(kbd "<XF86AudioMute>") . ,(my/app-command "ponymix toggle"))
- (,(kbd "<XF86AudioPlay>") . ,(my/app-command "mpc toggle"))
- (,(kbd "<XF86AudioPause>") . ,(my/app-command "mpc pause"))
- (,(kbd "<print>") . ,(my/app-command "flameshot gui"))
+ (,(kbd "<XF86AudioPlay>") . ,(my/app-command "mpc toggle"))
+ (,(kbd "<XF86AudioPause>") . ,(my/app-command "mpc pause"))
+ (,(kbd "<print>") . ,(my/app-command "flameshot gui"))
- ;; Input method
- (,(kbd "M-\\") . my/toggle-input-method)
+ ;; Input method
+ (,(kbd "M-\\") . my/toggle-input-method)
- ;; Switch workspace
- (,(kbd "s-q") . my/exwm-switch-to-other-monitor)
- (,(kbd "s-w") . exwm-workspace-switch)
- (,(kbd "s-W") . exwm-workspace-move-window)
- (,(kbd "s-<tab>") . my/exwm-workspace-switch-monitor)
+ ;; Switch workspace
+ (,(kbd "s-q") . my/exwm-switch-to-other-monitor)
+ (,(kbd "s-w") . exwm-workspace-switch)
+ (,(kbd "s-W") . exwm-workspace-move-window)
+ (,(kbd "s-<tab>") . my/exwm-workspace-switch-monitor)
- ;; Perspectives
- (,(kbd "s-{") . perspective-exwm-cycle-all-buffers-backward)
- (,(kbd "s-}") . perspective-exwm-cycle-all-buffers-forward)
- (,(kbd "s-[") . perspective-exwm-cycle-exwm-buffers-backward)
- (,(kbd "s-]") . perspective-exwm-cycle-exwm-buffers-forward)
- (,(kbd "s-<mouse-4>") . perspective-exwm-cycle-exwm-buffers-backward)
- (,(kbd "s-<mouse-5>") . perspective-exwm-cycle-exwm-buffers-forward)
- (,(kbd "s-`") . perspective-exwm-switch-perspective)
- (,(kbd "s-o") . ,(my/app-command "rofi -show window"))
+ ;; Perspectives
+ (,(kbd "s-{") . perspective-exwm-cycle-all-buffers-backward)
+ (,(kbd "s-}") . perspective-exwm-cycle-all-buffers-forward)
+ (,(kbd "s-[") . perspective-exwm-cycle-exwm-buffers-backward)
+ (,(kbd "s-]") . perspective-exwm-cycle-exwm-buffers-forward)
+ (,(kbd "s-<mouse-4>") . perspective-exwm-cycle-exwm-buffers-backward)
+ (,(kbd "s-<mouse-5>") . perspective-exwm-cycle-exwm-buffers-forward)
+ (,(kbd "s-`") . perspective-exwm-switch-perspective)
+ (,(kbd "s-o") . ,(my/app-command "rofi -show window"))
- ;; 's-N': Switch to certain workspace with Super (Win) plus a number key (0 - 9)
- ,@(mapcar (lambda (i)
- `(,(kbd (format "s-%d" i)) .
- (lambda ()
- (interactive)
- (when (or (< ,i (exwm-workspace--count))
- (y-or-n-p (format "Create workspace %d" ,i)))
- (exwm-workspace-switch-create ,i) ))))
- (number-sequence 0 9))))
+ ;; 's-N': Switch to certain workspace with Super (Win) plus a number key (0 - 9)
+ ,@(mapcar (lambda (i)
+ `(,(kbd (format "s-%d" i)) .
+ (lambda ()
+ (interactive)
+ (when (or (< ,i (exwm-workspace--count))
+ (y-or-n-p (format "Create workspace %d" ,i)))
+ (exwm-workspace-switch-create ,i) ))))
+ (number-sequence 0 9))))
A function to apply changes to exwm-input-global-keys.
(defun my/exwm-update-global-keys ()
(interactive)
@@ -973,15 +973,15 @@
(setq last-command #'exwm-input--noop)
(condition-case hook-error
(progn
- (run-hooks 'pre-command-hook)
- (run-hooks 'post-command-hook))
+ (run-hooks 'pre-command-hook)
+ (run-hooks 'post-command-hook))
((error)
(exwm--log "Error occurred while running command hooks: %s\n\nBacktrace:\n\n%s"
- hook-error
- (with-temp-buffer
- (setq-local standard-output (current-buffer))
- (backtrace)
- (buffer-string))))))
+ hook-error
+ (with-temp-buffer
+ (setq-local standard-output (current-buffer))
+ (backtrace)
+ (buffer-string))))))
These 3 settings seem to cause particular trouble with floating windows. Setting them to nil improves the stability greatly.
(defun my/fix-exwm-floating-windows ()
@@ -995,183 +995,183 @@
(defun exwm--on-ClientMessage-old (raw-data _synthetic)
"Handle ClientMessage event."
(let ((obj (make-instance 'xcb:ClientMessage))
- type id data)
+ type id data)
(xcb:unmarshal obj raw-data)
(setq type (slot-value obj 'type)
- id (slot-value obj 'window)
- data (slot-value (slot-value obj 'data) 'data32))
+ id (slot-value obj 'window)
+ data (slot-value (slot-value obj 'data) 'data32))
(exwm--log "atom=%s(%s)" (x-get-atom-name type exwm-workspace--current)
- type)
+ type)
(cond
;; _NET_NUMBER_OF_DESKTOPS.
((= type xcb:Atom:_NET_NUMBER_OF_DESKTOPS)
(let ((current (exwm-workspace--count))
- (requested (elt data 0)))
- ;; Only allow increasing/decreasing the workspace number by 1.
- (cond
- ((< current requested)
- (make-frame))
- ((and (> current requested)
- (> current 1))
- (let ((frame (car (last exwm-workspace--list))))
- (exwm-workspace--get-remove-frame-next-workspace frame)
- (delete-frame frame))))))
+ (requested (elt data 0)))
+ ;; Only allow increasing/decreasing the workspace number by 1.
+ (cond
+ ((< current requested)
+ (make-frame))
+ ((and (> current requested)
+ (> current 1))
+ (let ((frame (car (last exwm-workspace--list))))
+ (exwm-workspace--get-remove-frame-next-workspace frame)
+ (delete-frame frame))))))
;; _NET_CURRENT_DESKTOP.
((= type xcb:Atom:_NET_CURRENT_DESKTOP)
(exwm-workspace-switch (elt data 0)))
;; _NET_ACTIVE_WINDOW.
((= type xcb:Atom:_NET_ACTIVE_WINDOW)
(let ((buffer (exwm--id->buffer id))
- iconic window)
- (when (buffer-live-p buffer)
- (with-current-buffer buffer
- (when (eq exwm--frame exwm-workspace--current)
- (if exwm--floating-frame
- (select-frame exwm--floating-frame)
- (setq iconic (exwm-layout--iconic-state-p))
- (when iconic
- ;; State change: iconic => normal.
- (set-window-buffer (frame-selected-window exwm--frame)
- (current-buffer)))
- ;; Focus transfer.
- (setq window (get-buffer-window nil t))
- (when (or iconic
- (not (eq window (selected-window))))
- (select-window window))))))))
+ iconic window)
+ (when (buffer-live-p buffer)
+ (with-current-buffer buffer
+ (when (eq exwm--frame exwm-workspace--current)
+ (if exwm--floating-frame
+ (select-frame exwm--floating-frame)
+ (setq iconic (exwm-layout--iconic-state-p))
+ (when iconic
+ ;; State change: iconic => normal.
+ (set-window-buffer (frame-selected-window exwm--frame)
+ (current-buffer)))
+ ;; Focus transfer.
+ (setq window (get-buffer-window nil t))
+ (when (or iconic
+ (not (eq window (selected-window))))
+ (select-window window))))))))
;; _NET_CLOSE_WINDOW.
((= type xcb:Atom:_NET_CLOSE_WINDOW)
(let ((buffer (exwm--id->buffer id)))
- (when (buffer-live-p buffer)
- (exwm--defer 0 #'kill-buffer buffer))))
+ (when (buffer-live-p buffer)
+ (exwm--defer 0 #'kill-buffer buffer))))
;; _NET_WM_MOVERESIZE
((= type xcb:Atom:_NET_WM_MOVERESIZE)
(let ((direction (elt data 2))
- (buffer (exwm--id->buffer id)))
- (unless (and buffer
- (not (buffer-local-value 'exwm--floating-frame buffer)))
- (cond ((= direction
- xcb:ewmh:_NET_WM_MOVERESIZE_SIZE_KEYBOARD)
- ;; FIXME
- )
- ((= direction
- xcb:ewmh:_NET_WM_MOVERESIZE_MOVE_KEYBOARD)
- ;; FIXME
- )
- ((= direction xcb:ewmh:_NET_WM_MOVERESIZE_CANCEL)
- (exwm-floating--stop-moveresize))
- ;; In case it's a workspace frame.
- ((and (not buffer)
- (catch 'break
- (dolist (f exwm-workspace--list)
- (when (or (eq id (frame-parameter f 'exwm-outer-id))
- (eq id (frame-parameter f 'exwm-id)))
- (throw 'break t)))
- nil)))
- (t
- ;; In case it's a floating frame,
- ;; move the corresponding X window instead.
- (unless buffer
- (catch 'break
- (dolist (pair exwm--id-buffer-alist)
- (with-current-buffer (cdr pair)
- (when
- (and exwm--floating-frame
- (or (eq id
- (frame-parameter exwm--floating-frame
- 'exwm-outer-id))
- (eq id
- (frame-parameter exwm--floating-frame
- 'exwm-id))))
- (setq id exwm--id)
- (throw 'break nil))))))
- ;; Start to move it.
- (exwm-floating--start-moveresize id direction))))))
+ (buffer (exwm--id->buffer id)))
+ (unless (and buffer
+ (not (buffer-local-value 'exwm--floating-frame buffer)))
+ (cond ((= direction
+ xcb:ewmh:_NET_WM_MOVERESIZE_SIZE_KEYBOARD)
+ ;; FIXME
+ )
+ ((= direction
+ xcb:ewmh:_NET_WM_MOVERESIZE_MOVE_KEYBOARD)
+ ;; FIXME
+ )
+ ((= direction xcb:ewmh:_NET_WM_MOVERESIZE_CANCEL)
+ (exwm-floating--stop-moveresize))
+ ;; In case it's a workspace frame.
+ ((and (not buffer)
+ (catch 'break
+ (dolist (f exwm-workspace--list)
+ (when (or (eq id (frame-parameter f 'exwm-outer-id))
+ (eq id (frame-parameter f 'exwm-id)))
+ (throw 'break t)))
+ nil)))
+ (t
+ ;; In case it's a floating frame,
+ ;; move the corresponding X window instead.
+ (unless buffer
+ (catch 'break
+ (dolist (pair exwm--id-buffer-alist)
+ (with-current-buffer (cdr pair)
+ (when
+ (and exwm--floating-frame
+ (or (eq id
+ (frame-parameter exwm--floating-frame
+ 'exwm-outer-id))
+ (eq id
+ (frame-parameter exwm--floating-frame
+ 'exwm-id))))
+ (setq id exwm--id)
+ (throw 'break nil))))))
+ ;; Start to move it.
+ (exwm-floating--start-moveresize id direction))))))
;; _NET_REQUEST_FRAME_EXTENTS
((= type xcb:Atom:_NET_REQUEST_FRAME_EXTENTS)
(let ((buffer (exwm--id->buffer id))
- top btm)
- (if (or (not buffer)
- (not (buffer-local-value 'exwm--floating-frame buffer)))
- (setq top 0
- btm 0)
- (setq top (window-header-line-height)
- btm (window-mode-line-height)))
- (xcb:+request exwm--connection
- (make-instance 'xcb:ewmh:set-_NET_FRAME_EXTENTS
- :window id
- :left 0
- :right 0
- :top top
- :bottom btm)))
+ top btm)
+ (if (or (not buffer)
+ (not (buffer-local-value 'exwm--floating-frame buffer)))
+ (setq top 0
+ btm 0)
+ (setq top (window-header-line-height)
+ btm (window-mode-line-height)))
+ (xcb:+request exwm--connection
+ (make-instance 'xcb:ewmh:set-_NET_FRAME_EXTENTS
+ :window id
+ :left 0
+ :right 0
+ :top top
+ :bottom btm)))
(xcb:flush exwm--connection))
;; _NET_WM_DESKTOP.
((= type xcb:Atom:_NET_WM_DESKTOP)
(let ((buffer (exwm--id->buffer id)))
- (when (buffer-live-p buffer)
- (exwm-workspace-move-window (elt data 0) id))))
+ (when (buffer-live-p buffer)
+ (exwm-workspace-move-window (elt data 0) id))))
;; _NET_WM_STATE
((= type xcb:Atom:_NET_WM_STATE)
(let ((action (elt data 0))
- (props (list (elt data 1) (elt data 2)))
- (buffer (exwm--id->buffer id))
- props-new)
- ;; only support _NET_WM_STATE_FULLSCREEN / _NET_WM_STATE_ADD for frames
- (when (and (not buffer)
- (memq xcb:Atom:_NET_WM_STATE_FULLSCREEN props)
- (= action xcb:ewmh:_NET_WM_STATE_ADD))
- (xcb:+request
- exwm--connection
- (make-instance 'xcb:ewmh:set-_NET_WM_STATE
- :window id
- :data (vector xcb:Atom:_NET_WM_STATE_FULLSCREEN)))
- (xcb:flush exwm--connection))
- (when buffer ;ensure it's managed
- (with-current-buffer buffer
- ;; _NET_WM_STATE_FULLSCREEN
- (when (or (memq xcb:Atom:_NET_WM_STATE_FULLSCREEN props)
- (memq xcb:Atom:_NET_WM_STATE_ABOVE props))
- (cond ((= action xcb:ewmh:_NET_WM_STATE_ADD)
- (unless (exwm-layout--fullscreen-p)
- (exwm-layout-set-fullscreen id))
- (push xcb:Atom:_NET_WM_STATE_FULLSCREEN props-new))
- ((= action xcb:ewmh:_NET_WM_STATE_REMOVE)
- (when (exwm-layout--fullscreen-p)
- (exwm-layout-unset-fullscreen id)))
- ((= action xcb:ewmh:_NET_WM_STATE_TOGGLE)
- (if (exwm-layout--fullscreen-p)
- (exwm-layout-unset-fullscreen id)
- (exwm-layout-set-fullscreen id)
- (push xcb:Atom:_NET_WM_STATE_FULLSCREEN props-new)))))
- ;; _NET_WM_STATE_DEMANDS_ATTENTION
- ;; FIXME: check (may require other properties set)
- (when (memq xcb:Atom:_NET_WM_STATE_DEMANDS_ATTENTION props)
- (when (= action xcb:ewmh:_NET_WM_STATE_ADD)
- (unless (eq exwm--frame exwm-workspace--current)
- (set-frame-parameter exwm--frame 'exwm-urgency t)
- (setq exwm-workspace--switch-history-outdated t)))
- ;; xcb:ewmh:_NET_WM_STATE_REMOVE?
- ;; xcb:ewmh:_NET_WM_STATE_TOGGLE?
- )
- (xcb:+request exwm--connection
- (make-instance 'xcb:ewmh:set-_NET_WM_STATE
- :window id :data (vconcat props-new)))
- (xcb:flush exwm--connection)))))
+ (props (list (elt data 1) (elt data 2)))
+ (buffer (exwm--id->buffer id))
+ props-new)
+ ;; only support _NET_WM_STATE_FULLSCREEN / _NET_WM_STATE_ADD for frames
+ (when (and (not buffer)
+ (memq xcb:Atom:_NET_WM_STATE_FULLSCREEN props)
+ (= action xcb:ewmh:_NET_WM_STATE_ADD))
+ (xcb:+request
+ exwm--connection
+ (make-instance 'xcb:ewmh:set-_NET_WM_STATE
+ :window id
+ :data (vector xcb:Atom:_NET_WM_STATE_FULLSCREEN)))
+ (xcb:flush exwm--connection))
+ (when buffer ;ensure it's managed
+ (with-current-buffer buffer
+ ;; _NET_WM_STATE_FULLSCREEN
+ (when (or (memq xcb:Atom:_NET_WM_STATE_FULLSCREEN props)
+ (memq xcb:Atom:_NET_WM_STATE_ABOVE props))
+ (cond ((= action xcb:ewmh:_NET_WM_STATE_ADD)
+ (unless (exwm-layout--fullscreen-p)
+ (exwm-layout-set-fullscreen id))
+ (push xcb:Atom:_NET_WM_STATE_FULLSCREEN props-new))
+ ((= action xcb:ewmh:_NET_WM_STATE_REMOVE)
+ (when (exwm-layout--fullscreen-p)
+ (exwm-layout-unset-fullscreen id)))
+ ((= action xcb:ewmh:_NET_WM_STATE_TOGGLE)
+ (if (exwm-layout--fullscreen-p)
+ (exwm-layout-unset-fullscreen id)
+ (exwm-layout-set-fullscreen id)
+ (push xcb:Atom:_NET_WM_STATE_FULLSCREEN props-new)))))
+ ;; _NET_WM_STATE_DEMANDS_ATTENTION
+ ;; FIXME: check (may require other properties set)
+ (when (memq xcb:Atom:_NET_WM_STATE_DEMANDS_ATTENTION props)
+ (when (= action xcb:ewmh:_NET_WM_STATE_ADD)
+ (unless (eq exwm--frame exwm-workspace--current)
+ (set-frame-parameter exwm--frame 'exwm-urgency t)
+ (setq exwm-workspace--switch-history-outdated t)))
+ ;; xcb:ewmh:_NET_WM_STATE_REMOVE?
+ ;; xcb:ewmh:_NET_WM_STATE_TOGGLE?
+ )
+ (xcb:+request exwm--connection
+ (make-instance 'xcb:ewmh:set-_NET_WM_STATE
+ :window id :data (vconcat props-new)))
+ (xcb:flush exwm--connection)))))
((= type xcb:Atom:WM_PROTOCOLS)
(let ((type (elt data 0)))
- (cond ((= type xcb:Atom:_NET_WM_PING)
- (setq exwm-manage--ping-lock nil))
- (t (exwm--log "Unhandled WM_PROTOCOLS of type: %d" type)))))
+ (cond ((= type xcb:Atom:_NET_WM_PING)
+ (setq exwm-manage--ping-lock nil))
+ (t (exwm--log "Unhandled WM_PROTOCOLS of type: %d" type)))))
((= type xcb:Atom:WM_CHANGE_STATE)
(let ((buffer (exwm--id->buffer id)))
- (when (and (buffer-live-p buffer)
- (= (elt data 0) xcb:icccm:WM_STATE:IconicState))
- (with-current-buffer buffer
- (if exwm--floating-frame
- (call-interactively #'exwm-floating-hide)
- (bury-buffer))))))
+ (when (and (buffer-live-p buffer)
+ (= (elt data 0) xcb:icccm:WM_STATE:IconicState))
+ (with-current-buffer buffer
+ (if exwm--floating-frame
+ (call-interactively #'exwm-floating-hide)
+ (bury-buffer))))))
(t
(exwm--log "Unhandled: %s(%d)"
- (x-get-atom-name type exwm-workspace--current) type)))))
+ (x-get-atom-name type exwm-workspace--current) type)))))
(with-eval-after-load 'exwm
(advice-add 'exwm--on-ClientMessage :override #'exwm--on-ClientMessage-old))
@@ -1179,7 +1179,7 @@
Start Nyxt in char-mode.
(setq exwm-manage-configurations
'(((member exwm-class-name '("Nyxt"))
- char-mode t)))
+ char-mode t)))
EXWM config
And the EXWM config itself.
(defun my/exwm-init ()
@@ -1197,9 +1197,9 @@
(defun my/exwm-set-alpha (alpha)
(setf (alist-get 'alpha default-frame-alist)
- `(,alpha . ,alpha))
+ `(,alpha . ,alpha))
(cl-loop for frame being the frames
- do (set-frame-parameter frame 'alpha `(,alpha . ,alpha))))
+ do (set-frame-parameter frame 'alpha `(,alpha . ,alpha))))
(use-package exwm
:straight t
@@ -1666,12 +1666,12 @@
output HDMI-A-0
tray_output none
colors {
- background $bg-color
- separator #757575
- # border background text
- focused_workspace $bg-color $bg-color $text-color
- inactive_workspace $inactive-bg-color $inactive-bg-color $inactive-text-color
- urgent_workspace $urgent-bg-color $urgent-bg-color $urgent-text-color
+ background $bg-color
+ separator #757575
+ # border background text
+ focused_workspace $bg-color $bg-color $text-color
+ inactive_workspace $inactive-bg-color $inactive-bg-color $inactive-text-color
+ urgent_workspace $urgent-bg-color $urgent-bg-color $urgent-text-color
}
}
@@ -1681,12 +1681,12 @@
font pango:monospace 10
output DVI-D-0
colors {
- background $bg-color
- separator #757575
- # border background text
- focused_workspace $bg-color $bg-color $text-color
- inactive_workspace $inactive-bg-color $inactive-bg-color $inactive-text-color
- urgent_workspace $urgent-bg-color $urgent-bg-color $urgent-text-color
+ background $bg-color
+ separator #757575
+ # border background text
+ focused_workspace $bg-color $bg-color $text-color
+ inactive_workspace $inactive-bg-color $inactive-bg-color $inactive-text-color
+ urgent_workspace $urgent-bg-color $urgent-bg-color $urgent-text-color
}
}
Keyboard Layout
@@ -1771,28 +1771,28 @@
(cl-reduce
(lambda (acc name)
(let* ((color (my/color-value name)))
- (unless (member name '("black"))
- (setq color (ct-iterate
- color
- (lambda (c) (ct-edit-hsl-l-inc c 2))
- (lambda (c)
- (ct-light-p c 65)))))
- (push (cons name color) acc)
- (push (cons (format "light-%s" name)
- (ct-edit-lab-l-inc
- color
- my/alpha-for-light))
- acc)
- (push (cons (format "dark-%s" name)
- (ct-edit-lab-l-dec
- color
- my/alpha-for-light))
- acc) )
+ (unless (member name '("black"))
+ (setq color (ct-iterate
+ color
+ (lambda (c) (ct-edit-hsl-l-inc c 2))
+ (lambda (c)
+ (ct-light-p c 65)))))
+ (push (cons name color) acc)
+ (push (cons (format "light-%s" name)
+ (ct-edit-lab-l-inc
+ color
+ my/alpha-for-light))
+ acc)
+ (push (cons (format "dark-%s" name)
+ (ct-edit-lab-l-dec
+ color
+ my/alpha-for-light))
+ acc) )
acc)
'("black" "red" "green" "yellow" "blue" "magenta" "cyan" "white")
:initial-value nil))
`(("background" . ,(or (my/color-value 'bg-active)
- (my/color-value 'bg)))
+ (my/color-value 'bg)))
("foreground" . "#000000")))
"\n")
[colors]
@@ -2021,33 +2021,33 @@
(let* ((monitors
- (thread-last
- exclude-table
- (seq-map (lambda (el) (nth 0 el)))
- (seq-uniq)))
+ (thread-last
+ exclude-table
+ (seq-map (lambda (el) (nth 0 el)))
+ (seq-uniq)))
(exclude-combinations
- (seq-map
- (lambda (monitor)
- (seq-map
- (lambda (el) (nth 1 el))
- (seq-filter
- (lambda (el) (and (string-equal (nth 0 el) monitor)
- (nth 1 el)))
- exclude-table)))
- `(,@monitors "")))
+ (seq-map
+ (lambda (monitor)
+ (seq-map
+ (lambda (el) (nth 1 el))
+ (seq-filter
+ (lambda (el) (and (string-equal (nth 0 el) monitor)
+ (nth 1 el)))
+ exclude-table)))
+ `(,@monitors "")))
(module-glyph-combinations
- (thread-last
- exclude-combinations
- (seq-map
- (lambda (exclude)
- (thread-last
- table
- (seq-filter
- (lambda (elt)
- (not (or
- (member (nth 1 elt) exclude)
- (not (string-equal (nth 3 elt) "+")))))))))
- (seq-uniq)))
+ (thread-last
+ exclude-combinations
+ (seq-map
+ (lambda (exclude)
+ (thread-last
+ table
+ (seq-filter
+ (lambda (elt)
+ (not (or
+ (member (nth 1 elt) exclude)
+ (not (string-equal (nth 3 elt) "+")))))))))
+ (seq-uniq)))
(color-changes nil))
(dolist (e extra)
(add-to-list
@@ -2058,8 +2058,8 @@
(add-to-list
'color-changes
(concat (nth 2 (nth i comb))
- "--"
- (nth 2 (nth (1+ i) comb))))))
+ "--"
+ (nth 2 (nth (1+ i) comb))))))
(mapconcat
(lambda (el)
(let ((colors (split-string el "--")))
@@ -2070,10 +2070,10 @@
content-foreground = ${colors.%s}
content = ${glyph.gright}
content-font = 5"
- (nth 0 colors)
- (nth 1 colors)
- (nth 0 colors)
- (nth 1 colors))))
+ (nth 0 colors)
+ (nth 1 colors)
+ (nth 0 colors)
+ (nth 1 colors))))
color-changes
"\n"))
Here’s a rough outline of how the code works:
@@ -2104,14 +2104,14 @@
(let* ((exclude-modules
- (thread-last
- exclude-table
- (seq-filter (lambda (el) (string-equal (nth 0 el) monitor)))
- (seq-map (lambda (el) (nth 1 el)))))
+ (thread-last
+ exclude-table
+ (seq-filter (lambda (el) (string-equal (nth 0 el) monitor)))
+ (seq-map (lambda (el) (nth 1 el)))))
(modules
- (thread-last
- table
- (seq-filter (lambda (el) (not (member (nth 1 el) exclude-modules))))))
+ (thread-last
+ table
+ (seq-filter (lambda (el) (not (member (nth 1 el) exclude-modules))))))
(prev-color first-color)
(ret nil))
(concat
@@ -2120,11 +2120,11 @@
(apply
#'concat
(list
- (when (string-equal (nth 3 el) "+")
- (setq ret (format "glyph-%s--%s " prev-color (nth 2 el)))
- (setq prev-color (nth 2 el))
- ret)
- (nth 1 el))))
+ (when (string-equal (nth 3 el) "+")
+ (setq ret (format "glyph-%s--%s " prev-color (nth 2 el)))
+ (setq prev-color (nth 2 el))
+ ret)
+ (nth 1 el))))
modules
" ")
(unless (string-empty-p last-color) (format " glyph-%s--%s " prev-color last-color))))
@@ -2212,9 +2212,9 @@
TRAY_MONITOR="eDP-1"
elif [ "$hostname" = "eminence" ]; then
if xrandr --query | grep " connected" | cut -d" " -f1 | grep -q "HDMI-A-0"; then
- TRAY_MONITOR="HDMI-A-0"
+ TRAY_MONITOR="HDMI-A-0"
else
- TRAY_MONITOR="eDP"
+ TRAY_MONITOR="eDP"
fi
elif [ "$hostname" = "iris" ]; then
TRAY_MONITOR="HDMI-1"
@@ -2275,15 +2275,15 @@
for m in $(xrandr --query | grep " connected" | cut -d" " -f1); do
export MONITOR=$m
if [ "$MONITOR" = "$TRAY_MONITOR" ]; then
- export TRAY="right"
+ export TRAY="right"
else
- export TRAY="none"
+ export TRAY="none"
fi
SIZE=${FONT_SIZES[$MONITOR]}
SCALE=${EMOJI_SCALE[$MONITOR]}
TEMP=${TEMP_HWMON_PATHS[$(hostname)]}
if [[ -z "$SCALE" ]]; then
- continue
+ continue
fi
# export FONT0="pango:monospace:size=$SIZE;1"
# export FONT1="NotoEmoji:scale=$SCALE:antialias=false;1"
@@ -2478,8 +2478,8 @@
function check_proc_net_dev {
if [ ! -f "/proc/net/dev" ]; then
- echo "/proc/net/dev not found"
- exit 1
+ echo "/proc/net/dev not found"
+ exit 1
fi
}
@@ -2491,12 +2491,12 @@
while getopts i:t:u:p:lh opt; do
case "$opt" in
- i) iface="$OPTARG" ;;
- t) dt="$OPTARG" ;;
- u) unit="$OPTARG" ;;
- p) printf_command="$OPTARG" ;;
- l) list_interfaces && exit 0 ;;
- h) printf \
+ i) iface="$OPTARG" ;;
+ t) dt="$OPTARG" ;;
+ u) unit="$OPTARG" ;;
+ p) printf_command="$OPTARG" ;;
+ l) list_interfaces && exit 0 ;;
+ h) printf \
"Usage: bandwidth3 [-i interface] [-t time] [-u unit] [-p printf_command] [-l] [-h]
Options:
-i\tNetwork interface to measure. Default determined using \`ip route\`.
@@ -2557,8 +2557,8 @@
old_received=received;
old_sent=sent;
if(rx >= 0 && wx >= 0){
- '"$printf_command"';
- fflush(stdout);
+ '"$printf_command"';
+ fflush(stdout);
}
}
'
@@ -2817,16 +2817,16 @@
CMDLINE=$(ps -p "$PID" -o args=)
if [[ "$CMDLINE" == *"$EXCLUDE_PATTERN"* ]]; then
- continue
+ continue
fi
kill -SIGUSR2 "$PID" 2>/dev/null
if [ $? -eq 0 ]; then
- echo "Sent SIGUSR2 to Emacs (PID: $PID)"
- SIGNAL_SENT=true
+ echo "Sent SIGUSR2 to Emacs (PID: $PID)"
+ SIGNAL_SENT=true
else
- echo "Failed to send SIGUSR2 to Emacs (PID: $PID)"
+ echo "Failed to send SIGUSR2 to Emacs (PID: $PID)"
fi
done
@@ -3514,34 +3514,34 @@
(with-output-to-string
(with-current-buffer standard-output
(call-process "node" nil t nil
- (expand-file-name "~/bin/firefox-theme/main.js")
- string))))
+ (expand-file-name "~/bin/firefox-theme/main.js")
+ string))))
(defun my/color-value-rgb (color)
(let ((color (if (stringp color)
- color
- (my/color-value color))))
+ color
+ (my/color-value color))))
`((r . ,(* 2.55 (ct-get-rgb-r color)))
(g . ,(* 2.55 (ct-get-rgb-g color)))
(b . ,(* 2.55 (ct-get-rgb-b color))))))
(defun my/firefox-get-json ()
(let ((toolbar-color
- (my/color-value-rgb
- 'modeline))
- (text-color
- (my/color-value-rgb
- (if (my/light-p) 'fg 'yellow))))
+ (my/color-value-rgb
+ 'modeline))
+ (text-color
+ (my/color-value-rgb
+ (if (my/light-p) 'fg 'yellow))))
`((colors . ((toolbar . ,toolbar-color)
- (toolbar_text . ,text-color)
- (frame . ,(my/color-value-rgb 'bg))
- (tab_background_text . ,(my/color-value-rgb 'fg))
- (toolbar_field . ,(my/color-value-rgb 'bg))
- (toolbar_field_text . ,(my/color-value-rgb 'blue))
- (tab_line . ,text-color)
- (popup . ,(my/color-value-rgb 'bg-alt))
- (popup_text . ,(my/color-value-rgb 'fg))
- (tab_loading . ,text-color))))))
+ (toolbar_text . ,text-color)
+ (frame . ,(my/color-value-rgb 'bg))
+ (tab_background_text . ,(my/color-value-rgb 'fg))
+ (toolbar_field . ,(my/color-value-rgb 'bg))
+ (toolbar_field_text . ,(my/color-value-rgb 'blue))
+ (tab_line . ,text-color)
+ (popup . ,(my/color-value-rgb 'bg-alt))
+ (popup_text . ,(my/color-value-rgb 'fg))
+ (tab_loading . ,text-color))))))
(defun my/firefox-get-color-url ()
(concat
@@ -3826,8 +3826,8 @@
c.url.start_pages = ['https://licht.sqrtminusone.xyz']
c.zoom.levels = ['25%', '33%', '50%', '67%', '75%', '90%', '100%', '110%',
- '125%', '133%', '150%', '175%', '200%', '250%', '300%',
- '400%', '500%']
+ '125%', '133%', '150%', '175%', '200%', '250%', '300%',
+ '400%', '500%']
Theme
Taken from the dracula theme from qutebrowser.
palette = {
@@ -4575,8 +4575,8 @@
#:provides '(deterred-mpd)
#:respawn? #t
#:start (make-forkexec-constructor
- '("python" "/home/pavel/10-19 Code/13 Other Projects/13.02 sqrt-data/13.02.R Repos/13.02.R.05 deterred/watchers/deterred-mpd.py"
- "--db" "/home/pavel/.deterred/database.db"))
+ '("python" "/home/pavel/10-19 Code/13 Other Projects/13.02 sqrt-data/13.02.R Repos/13.02.R.05 deterred/watchers/deterred-mpd.py"
+ "--db" "/home/pavel/.deterred/database.db"))
#:stop (make-kill-destructor)
#:requires '(mpd)))
GNU Mcron
@@ -4747,23 +4747,23 @@
(action 'shepherd 'daemonize)
Run services
(for-each start '(mpd
- sqrt-data-agent-mpd
- deterred-mpd
- mcron
- aw-server
- aw-watcher-afk
- aw-watcher-window
- pulseeffects
- xsettingsd
- ;; discord-rich-presence
- ;; polkit-gnome
- davmail
- ;; ; xmodmap
- ;; nm-applet
- vnstatd
- ;; opensnitchd
- ;; opensnitch-ui
- ))
+ sqrt-data-agent-mpd
+ deterred-mpd
+ mcron
+ aw-server
+ aw-watcher-afk
+ aw-watcher-window
+ pulseeffects
+ xsettingsd
+ ;; discord-rich-presence
+ ;; polkit-gnome
+ davmail
+ ;; ; xmodmap
+ ;; nm-applet
+ vnstatd
+ ;; opensnitchd
+ ;; opensnitch-ui
+ ))
Guix settings
Other desktop programs I use are listed below.
diff --git a/configs/emacs/index.html b/configs/emacs/index.html
index 17981c9..0c028fd 100644
--- a/configs/emacs/index.html
+++ b/configs/emacs/index.html
@@ -76,8 +76,7 @@
-One day we won’t hate one another, no young boy will march to war and I will clean up my Emacs config. But that day isn’t today.
-
+One day we won’t hate one another, no young boy will march to war and I will clean up my Emacs config. But that day isn’t today.
- Me, in commit 93a0573. Adapted from The Dark Element - “The Pallbearer Walks Alone”. T_T
@@ -244,9 +243,9 @@ Emacs is also particularly great at writing Lisp code, e.g. Clojure, Common Lisp
(bootstrap-version 5))
(unless (file-exists-p bootstrap-file)
(with-current-buffer
- (url-retrieve-synchronously
- "https://raw.githubusercontent.com/raxod502/straight.el/develop/install.el"
- 'silent 'inhibit-cookies)
+ (url-retrieve-synchronously
+ "https://raw.githubusercontent.com/raxod502/straight.el/develop/install.el"
+ 'silent 'inhibit-cookies)
(goto-char (point-max))
(eval-print-last-sexp)))
(load bootstrap-file nil 'nomessage))
@@ -265,8 +264,8 @@ Emacs is also particularly great at writing Lisp code, e.g. Clojure, Common Lisp
The following is true is Emacs is run on a remote server where I don’t need stuff like my org workflow
(setq my/remote-server
(or (string= (getenv "IS_REMOTE") "true")
- (string= (system-name) "dev-digital")
- (string= (system-name) "viridian")))
+ (string= (system-name) "dev-digital")
+ (string= (system-name) "viridian")))
And the following is true if Emacs is run from termux on Android.
(setq my/is-termux (string-match-p (rx (* nonl) "com.termux" (* nonl)) (getenv "HOME")))
Custom system name logic because on termux it’s always “localhost”.
@@ -286,13 +285,13 @@ Emacs is also particularly great at writing Lisp code, e.g. Clojure, Common Lisp
(setq my/emacs-started nil)
(add-hook 'emacs-startup-hook
- (lambda ()
- (message "*** Emacs loaded in %s with %d garbage collections."
- (format "%.2f seconds"
- (float-time
- (time-subtract after-init-time before-init-time)))
- gcs-done)
- (setq my/emacs-started t)))
+ (lambda ()
+ (message "*** Emacs loaded in %s with %d garbage collections."
+ (format "%.2f seconds"
+ (float-time
+ (time-subtract after-init-time before-init-time)))
+ gcs-done)
+ (setq my/emacs-started t)))
Set the following to t to print debug information during the startup. This will include package loading order and time.
(setq use-package-verbose nil)
(setq use-package-compute-statistics t)
@@ -304,30 +303,30 @@ Emacs is also particularly great at writing Lisp code, e.g. Clojure, Common Lisp
Run GC when Emacs loses focus. Time will tell if that’s a good idea.
I still don’t know if there is any quantifiable advantage to this, but it doesn’t hurt.
(add-hook 'emacs-startup-hook
- (lambda ()
- (if (boundp 'after-focus-change-function)
- (add-function :after after-focus-change-function
- (lambda ()
- (unless (frame-focus-state)
- (garbage-collect))))
- (add-hook 'after-focus-change-function 'garbage-collect))))
+ (lambda ()
+ (if (boundp 'after-focus-change-function)
+ (add-function :after after-focus-change-function
+ (lambda ()
+ (unless (frame-focus-state)
+ (garbage-collect))))
+ (add-hook 'after-focus-change-function 'garbage-collect))))
Measure RAM usage
I’ve noticed that Emacs occasionally eats a lot of RAM, especially when used with EXWM. This is my attempt to measure RAM usage.
I have some concerns that ps -o rss may be unrepresentative because of shared memory, but I guess this shouldn’t be a problem here because there’s only one process of Emacs.
(defun my/get-ram-usage-async (callback)
(let* ((temp-buffer (generate-new-buffer "*ps*"))
- (proc (start-process "ps" temp-buffer "ps"
- "-p" (number-to-string (emacs-pid)) "-o" "rss")))
+ (proc (start-process "ps" temp-buffer "ps"
+ "-p" (number-to-string (emacs-pid)) "-o" "rss")))
(set-process-sentinel
proc
(lambda (process _msg)
(when (eq (process-status process) 'exit)
- (let* ((output (with-current-buffer temp-buffer
- (buffer-string)))
- (usage (string-to-number (nth 1 (split-string output "\n")))))
- (ignore-errors
- (funcall callback usage)))
- (kill-buffer temp-buffer))))))
+ (let* ((output (with-current-buffer temp-buffer
+ (buffer-string)))
+ (usage (string-to-number (nth 1 (split-string output "\n")))))
+ (ignore-errors
+ (funcall callback usage)))
+ (kill-buffer temp-buffer))))))
(defun my/ram-usage ()
(interactive)
@@ -405,7 +404,7 @@ Emacs is also particularly great at writing Lisp code, e.g. Clojure, Common Lisp
(which-key-mode)
(which-key-setup-side-window-bottom)
(set-face-attribute 'which-key-local-map-description-face nil
- :weight 'bold)
+ :weight 'bold)
:straight t)
dump keybindings
A function to dump keybindings starting with a prefix to a buffer in a tree-like form.
@@ -413,11 +412,11 @@ Emacs is also particularly great at writing Lisp code, e.g. Clojure, Common Lisp
(dolist (key (which-key--get-bindings (kbd prefix)))
(with-current-buffer buffer
(when level
- (insert (make-string level ? )))
+ (insert (make-string level ? )))
(insert (apply #'format "%s%s%s\n" key)))
(when (string-match-p
- (rx bos "+" (* nonl))
- (substring-no-properties (elt key 2)))
+ (rx bos "+" (* nonl))
+ (substring-no-properties (elt key 2)))
(my/dump-bindings-recursive
(concat prefix " " (substring-no-properties (car key)))
(+ 2 (or level 0))
@@ -482,8 +481,8 @@ Emacs is also particularly great at writing Lisp code, e.g. Clojure, Common Lisp
:after evil
:config
:hook ((prog-mode . turn-on-evil-quickscope-mode)
- (LaTeX-mode . turn-on-evil-quickscope-mode)
- (org-mode . turn-on-evil-quickscope-mode)))
+ (LaTeX-mode . turn-on-evil-quickscope-mode)
+ (org-mode . turn-on-evil-quickscope-mode)))
evil-numbers allows incrementing and decrementing numbers at point.
(use-package evil-numbers
:straight t
@@ -509,7 +508,7 @@ Emacs is also particularly great at writing Lisp code, e.g. Clojure, Common Lisp
Do ex search in other buffer. Like *, but switch to other buffer and search there.
(defun my/evil-ex-search-word-forward-other-window (count &optional symbol)
(interactive (list (prefix-numeric-value current-prefix-arg)
- evil-symbol-word-search))
+ evil-symbol-word-search))
(save-excursion
(evil-ex-start-word-search nil 'forward count symbol))
(other-window 1)
@@ -526,10 +525,10 @@ Emacs is also particularly great at writing Lisp code, e.g. Clojure, Common Lisp
:config
(evil-collection-init
'(eww devdocs proced emms pass calendar dired debug guix calc
- docker ibuffer geiser pdf info elfeed edebug bookmark company
- vterm flycheck profiler cider explain-pause-mode notmuch custom
- xref eshell helpful compile comint git-timemachine magit prodigy
- slime forge deadgrep vc-annonate telega doc-view gnus outline)))
+ docker ibuffer geiser pdf info elfeed edebug bookmark company
+ vterm flycheck profiler cider explain-pause-mode notmuch custom
+ xref eshell helpful compile comint git-timemachine magit prodigy
+ slime forge deadgrep vc-annonate telega doc-view gnus outline)))
My keybindings
Various keybinding settings that I can’t put anywhere else.
Escape key
@@ -556,10 +555,10 @@ Emacs is also particularly great at writing Lisp code, e.g. Clojure, Common Lisp
(general-define-key
:keymaps '(minibuffer-local-map
- minibuffer-local-ns-map
- minibuffer-local-completion-map
- minibuffer-local-must-match-map
- minibuffer-local-isearch-map)
+ minibuffer-local-ns-map
+ minibuffer-local-completion-map
+ minibuffer-local-must-match-map
+ minibuffer-local-isearch-map)
[escape] 'minibuffer-keyboard-quit)
Home & end
(general-def :states '(normal insert visual)
@@ -643,9 +642,9 @@ Emacs is also particularly great at writing Lisp code, e.g. Clojure, Common Lisp
:infix "b"
"" '(:which-key "buffers")
"s" '(my/lisp-interaction-buffer
- :which-key "*lisp-interaction*")
+ :which-key "*lisp-interaction*")
"m" '((lambda () (interactive) (persp-switch-to-buffer "*Messages*"))
- :which-key "*Messages*")
+ :which-key "*Messages*")
"l" 'next-buffer
"h" 'previous-buffer
"k" 'kill-buffer
@@ -678,15 +677,15 @@ Emacs is also particularly great at writing Lisp code, e.g. Clojure, Common Lisp
"Increase font size by 10 points"
(interactive)
(set-face-attribute 'default nil
- :height
- (+ (face-attribute 'default :height) 10)))
+ :height
+ (+ (face-attribute 'default :height) 10)))
(defun my/zoom-out ()
"Decrease font size by 10 points"
(interactive)
(set-face-attribute 'default nil
- :height
- (- (face-attribute 'default :height) 10)))
+ :height
+ (- (face-attribute 'default :height) 10)))
;; change font size, interactively
(global-set-key (kbd "C-+") 'my/zoom-in)
@@ -728,7 +727,7 @@ Emacs is also particularly great at writing Lisp code, e.g. Clojure, Common Lisp
(defun my/emacs-i3-windmove (dir)
(let ((other-window (windmove-find-other-window dir)))
(if (or (null other-window) (window-minibuffer-p other-window))
- (i3-msg "focus" (symbol-name dir))
+ (i3-msg "focus" (symbol-name dir))
(windmove-do-window-select dir))))
For the move I want the following behavior:
@@ -741,20 +740,20 @@ Emacs is also particularly great at writing Lisp code, e.g. Clojure, Common Lisp
So here is a simple predicate which checks whether there is space in the given direction.
(defun my/emacs-i3-direction-exists-p (dir)
(cl-some (lambda (dir)
- (let ((win (windmove-find-other-window dir)))
- (and win (not (window-minibuffer-p win)))))
- (pcase dir
- ('width '(left right))
- ('height '(up down)))))
+ (let ((win (windmove-find-other-window dir)))
+ (and win (not (window-minibuffer-p win)))))
+ (pcase dir
+ ('width '(left right))
+ ('height '(up down)))))
And the implementation of the move command.
(defun my/emacs-i3-move-window (dir)
(let ((other-window (windmove-find-other-window dir))
- (other-direction (my/emacs-i3-direction-exists-p
- (pcase dir
- ('up 'width)
- ('down 'width)
- ('left 'height)
- ('right 'height)))))
+ (other-direction (my/emacs-i3-direction-exists-p
+ (pcase dir
+ ('up 'width)
+ ('down 'width)
+ ('left 'height)
+ ('right 'height)))))
(cond
((and other-window (not (window-minibuffer-p other-window)))
(window-swap-states (selected-window) other-window))
@@ -765,23 +764,23 @@ Emacs is also particularly great at writing Lisp code, e.g. Clojure, Common Lisp
This function also checks whether there is space to resize in the given direction with the help of the predicate defined above. The command is forwarded back to i3 if there is not.
(defun my/emacs-i3-resize-window (dir kind value)
(if (or (one-window-p)
- (not (my/emacs-i3-direction-exists-p dir)))
+ (not (my/emacs-i3-direction-exists-p dir)))
(i3-msg "resize" (symbol-name kind) (symbol-name dir)
- (format "%s px or %s ppt" value value))
+ (format "%s px or %s ppt" value value))
(setq value (/ value 2))
(pcase kind
('shrink
(pcase dir
- ('width
- (evil-window-decrease-width value))
- ('height
- (evil-window-decrease-height value))))
+ ('width
+ (evil-window-decrease-width value))
+ ('height
+ (evil-window-decrease-height value))))
('grow
(pcase dir
- ('width
- (evil-window-increase-width value))
- ('height
- (evil-window-increase-height value)))))))
+ ('width
+ (evil-window-increase-width value))
+ ('height
+ (evil-window-increase-height value)))))))
transpose-frame is a package to “transpose” the current frame layout, which behaves someone similar to the layout toggle split command in i3, so I’ll use it as well.
(use-package transpose-frame
:straight t
@@ -826,9 +825,9 @@ Emacs is also particularly great at writing Lisp code, e.g. Clojure, Common Lisp
(require 'cl-extra)
(add-hook 'before-save-hook
- (lambda ()
- (unless (cl-some #'derived-mode-p my/trailing-whitespace-modes)
- (delete-trailing-whitespace))))
+ (lambda ()
+ (unless (cl-some #'derived-mode-p my/trailing-whitespace-modes)
+ (delete-trailing-whitespace))))
Tabs
Some default settings to manage tabs.
(setq tab-always-indent nil)
@@ -890,9 +889,9 @@ Emacs is also particularly great at writing Lisp code, e.g. Clojure, Common Lisp
:straight t
:config
(setq yas-snippet-dirs
- `(,(concat (expand-file-name user-emacs-directory) "snippets")
- ;; yasnippet-snippets-dir
- ))
+ `(,(concat (expand-file-name user-emacs-directory) "snippets")
+ ;; yasnippet-snippets-dir
+ ))
(setq yas-triggers-in-field t)
(yas-global-mode 1)
(my-leader-def
@@ -906,8 +905,7 @@ Emacs is also particularly great at writing Lisp code, e.g. Clojure, Common Lisp
(general-imap "M-TAB" 'company-yasnippet)
Input Method
-I have to switch layouts all the time, especially in LaTeX documents, because for some reason the Bolsheviks abandoned the idea of replacing Russian Cyrillic letters with Latin ones.
-
+I have to switch layouts all the time, especially in LaTeX documents, because for some reason the Bolsheviks abandoned the idea of replacing Russian Cyrillic letters with Latin ones.
- Me, , in a commit to SystemCrafters/crafter-configs.
@@ -936,11 +934,11 @@ Emacs is also particularly great at writing Lisp code, e.g. Clojure, Common Lisp
(if (derived-mode-p 'exwm-mode)
(my/run-in-background "xkb-switch -n")
(if (or
- (not (executable-find "xkb-switch"))
- (equal (string-trim
- (shell-command-to-string "xkb-switch -p"))
- "us"))
- (toggle-input-method)
+ (not (executable-find "xkb-switch"))
+ (equal (string-trim
+ (shell-command-to-string "xkb-switch -p"))
+ "us"))
+ (toggle-input-method)
(my/run-in-background "xkb-switch -s us"))))
M-x delete-horizontal-space doesn’t feel that useful to me.
(general-define-key
@@ -982,13 +980,13 @@ Emacs is also particularly great at writing Lisp code, e.g. Clojure, Common Lisp
(require 'accent)
(message "%s" arg)
(let* ((after? (eq accent-position 'after))
- (char (if after? (char-after) (char-before)))
- (curr (intern (string char)))
- (default-diac (cdr (assoc curr my/default-accents))))
+ (char (if after? (char-after) (char-before)))
+ (curr (intern (string char)))
+ (default-diac (cdr (assoc curr my/default-accents))))
(if (and default-diac (not arg))
- (progn
- (delete-char (if after? 1 -1))
- (insert (format "%c" default-diac)))
+ (progn
+ (delete-char (if after? 1 -1))
+ (insert (format "%c" default-diac)))
(call-interactively #'accent-company))))
(use-package accent
@@ -1009,7 +1007,27 @@ Emacs is also particularly great at writing Lisp code, e.g. Clojure, Common Lisp
"M-j" #'popup-next
"M-k" #'popup-previous)
(setq accent-custom '((a (ā))
- (A (Ā)))))
+ (A (Ā)))))
+
Random editing tricks
+Round number at point
+(defun my/round-number-at-point (word signs)
+ (interactive
+ (list (or (when (region-active-p)
+ (buffer-substring-no-properties
+ (region-beginning)
+ (region-end)))
+ (thing-at-point 'number 'no-properties))
+ (read-number "Decimal signs: " 2)))
+ (when (stringp word)
+ (setq word (string-to-number word)))
+ (let ((number (/ (float (round (* (expt 10 signs) word)))
+ (expt 10 signs))))
+ (save-excursion
+ (replace-string-in-region
+ (number-to-string word)
+ (number-to-string number)
+ (line-beginning-position)
+ (line-end-position)))))
Working with projects
Packages related to managing projects.
I used to have Treemacs here, but in the end decided that dired with dired-sidebar does a better job. Dired has its separate section in “Applications”.
@@ -1046,13 +1064,13 @@ Emacs is also particularly great at writing Lisp code, e.g. Clojure, Common Lisp
:config
(require 'forge)
(setq magit-blame-styles
- '((headings
- (heading-format . "%-20a %C %s\n"))
- (highlight
- (highlight-face . magit-blame-highlight))
- (lines
- (show-lines . t)
- (show-message . t)))))
+ '((headings
+ (heading-format . "%-20a %C %s\n"))
+ (highlight
+ (highlight-face . magit-blame-highlight))
+ (lines
+ (show-lines . t)
+ (show-message . t)))))
git-gutter is shows git changes for each line (added/changed/deleted lines).
(use-package git-gutter
:straight t
@@ -1078,9 +1096,9 @@ Emacs is also particularly great at writing Lisp code, e.g. Clojure, Common Lisp
(use-package difftastic
:straight t
:commands (difftastic-magit-diff
- difftastic-magit-show
- difftastic-files
- difftastic-buffers)
+ difftastic-magit-show
+ difftastic-files
+ difftastic-buffers)
:init
(with-eval-after-load 'magit-diff
(transient-append-suffix 'magit-diff '(-1 -1)
@@ -1116,9 +1134,9 @@ Emacs is also particularly great at writing Lisp code, e.g. Clojure, Common Lisp
:straight t
:config
(add-to-list 'forge-alist '("gitlab.etu.ru"
- "gitlab.etu.ru/api/v4"
- "gitlab.etu.ru"
- forge-gitlab-repository)))
+ "gitlab.etu.ru/api/v4"
+ "gitlab.etu.ru"
+ forge-gitlab-repository)))
forge depends on a package called ghub. I don’t like that it uses auth-source to store the token so I’ll advise it to use password-store.
(defun my/password-store-get-field (entry field)
(if-let (field (password-store-get-field entry field))
@@ -1127,12 +1145,12 @@ Emacs is also particularly great at writing Lisp code, e.g. Clojure, Common Lisp
(defun my/ghub--token (host username package &optional nocreate forge)
(cond ((and (or (equal host "gitlab.etu.ru/api/v4")
- (equal host "gitlab.etu.ru/api"))
- (equal username "pvkorytov"))
- (my/password-store-get-field
- "Job/Digital/Infrastructure/gitlab.etu.ru"
- (format "%s-token" package)))
- (t (error "Don't know token: %s %s %s" host username package))))
+ (equal host "gitlab.etu.ru/api"))
+ (equal username "pvkorytov"))
+ (my/password-store-get-field
+ "Job/Digital/Infrastructure/gitlab.etu.ru"
+ (format "%s-token" package)))
+ (t (error "Don't know token: %s %s %s" host username package))))
(with-eval-after-load 'ghub
(advice-add #'ghub--token :override #'my/ghub--token))
@@ -1180,7 +1198,7 @@ Emacs is also particularly great at writing Lisp code, e.g. Clojure, Common Lisp
:straight t
:config
(add-to-list 'editorconfig-indentation-alist
- '(emmet-mode emmet-indentation))
+ '(emmet-mode emmet-indentation))
(editorconfig-mode))
Editing files
A minor mode to remember recently edited files.
@@ -1264,7 +1282,7 @@ Emacs is also particularly great at writing Lisp code, e.g. Clojure, Common Lisp
:config
(setq avy-timeout-seconds 0.5)
(setq avy-ignored-modes
- '(image-mode doc-view-mode pdf-view-mode exwm-mode))
+ '(image-mode doc-view-mode pdf-view-mode exwm-mode))
(general-define-key
:states '(normal motion)
"-" #'avy-goto-char-timer))
@@ -1272,8 +1290,8 @@ Emacs is also particularly great at writing Lisp code, e.g. Clojure, Common Lisp
(defun avy-action-embark (pt)
(unwind-protect
(save-excursion
- (goto-char pt)
- (embark-act))
+ (goto-char pt)
+ (embark-act))
(select-window
(cdr (ring-ref avy-ring 0))))
t)
@@ -1300,11 +1318,11 @@ Emacs is also particularly great at writing Lisp code, e.g. Clojure, Common Lisp
Add prompt indicator to completing-read-multiple:
(defun crm-indicator (args)
(cons (format "[CRM%s] %s"
- (replace-regexp-in-string
- "\\`\\[.*?]\\*\\|\\[.*?]\\*\\'" ""
- crm-separator)
- (car args))
- (cdr args)))
+ (replace-regexp-in-string
+ "\\`\\[.*?]\\*\\|\\[.*?]\\*\\'" ""
+ crm-separator)
+ (car args))
+ (cdr args)))
(with-eval-after-load 'crm
(advice-add #'completing-read-multiple :filter-args #'crm-indicator))
Persist history over Emacs restarts.
@@ -1329,7 +1347,7 @@ Emacs is also particularly great at writing Lisp code, e.g. Clojure, Common Lisp
(defun my/sort-directories-first (files)
(setq files (vertico-sort-alpha files))
(nconc (seq-filter (lambda (x) (string-suffix-p "/" x)) files)
- (seq-remove (lambda (x) (string-suffix-p "/" x)) files)))
+ (seq-remove (lambda (x) (string-suffix-p "/" x)) files)))
(use-package vertico-multiform
:after vertico
@@ -1340,14 +1358,14 @@ Emacs is also particularly great at writing Lisp code, e.g. Clojure, Common Lisp
"M-b" #'vertico-multiform-buffer
"M-g" #'vertico-multiform-grid)
(setq vertico-multiform-categories
- '((file (vertico-sort-function . my/sort-directories-first))
- (password-store-pass grid)))
+ '((file (vertico-sort-function . my/sort-directories-first))
+ (password-store-pass grid)))
(setq vertico-multiform-commands
- '((eshell-atuin-history (vertico-sort-function . nil))
- (my/index-nav (vertico-sort-function . nil))
- (org-ql-view (vertico-sort-function . nil))
- (my/consult-line (vertico-sort-function . nil))
- (telega-msg-add-reaction grid))))
+ '((eshell-atuin-history (vertico-sort-function . nil))
+ (my/index-nav (vertico-sort-function . nil))
+ (org-ql-view (vertico-sort-function . nil))
+ (my/consult-line (vertico-sort-function . nil))
+ (telega-msg-add-reaction grid))))
vertico-quick enables ivy-like bindings to choose candidates.
(use-package vertico-quick
:after vertico
@@ -1365,9 +1383,9 @@ Emacs is also particularly great at writing Lisp code, e.g. Clojure, Common Lisp
(setq completion-styles '(orderless basic))
(setq completion-category-defaults nil)
(setq completion-category-overrides
- '((file (styles partial-completion))))
+ '((file (styles partial-completion))))
(setq orderless-matching-styles
- '(orderless-literal orderless-initialism orderless-regexp)))
+ '(orderless-literal orderless-initialism orderless-regexp)))
Disable orderless for company:
(defun company-completion-styles (capf-fn &rest args)
(let ((completion-styles '(basic partial-completion)))
@@ -1381,8 +1399,8 @@ Emacs is also particularly great at writing Lisp code, e.g. Clojure, Common Lisp
:straight t
:config
(setq consult-preview-excluded-files
- `("\\`/[^/|:]+:"
- ,(rx "html" eos))))
+ `("\\`/[^/|:]+:"
+ ,(rx "html" eos))))
marginalia
marginalia provides annotations in the completion interface.
(use-package marginalia
@@ -1390,7 +1408,7 @@ Emacs is also particularly great at writing Lisp code, e.g. Clojure, Common Lisp
:config
(marginalia-mode)
(push '(projectile-find-file . file)
- marginalia-command-categories))
+ marginalia-command-categories))
embark
embark provides minibuffer actions.
(use-package embark
@@ -1413,32 +1431,32 @@ Emacs is also particularly great at writing Lisp code, e.g. Clojure, Common Lisp
targets."
(lambda (&optional keymap targets prefix)
(if (null keymap)
- (which-key--hide-popup-ignore-command)
+ (which-key--hide-popup-ignore-command)
(which-key--show-keymap
(if (eq (plist-get (car targets) :type) 'embark-become)
- "Become"
- (format "Act on %s '%s'%s"
- (plist-get (car targets) :type)
- (embark--truncate-target (plist-get (car targets) :target))
- (if (cdr targets) "…" "")))
+ "Become"
+ (format "Act on %s '%s'%s"
+ (plist-get (car targets) :type)
+ (embark--truncate-target (plist-get (car targets) :target))
+ (if (cdr targets) "…" "")))
(if prefix
- (pcase (lookup-key keymap prefix 'accept-default)
- ((and (pred keymapp) km) km)
- (_ (key-binding prefix 'accept-default)))
- keymap)
+ (pcase (lookup-key keymap prefix 'accept-default)
+ ((and (pred keymapp) km) km)
+ (_ (key-binding prefix 'accept-default)))
+ keymap)
nil nil t (lambda (binding)
- (not (string-suffix-p "-argument" (cdr binding))))))))
+ (not (string-suffix-p "-argument" (cdr binding))))))))
(defun embark-hide-which-key-indicator (fn &rest args)
"Hide the which-key indicator immediately when using the completing-read prompter."
(which-key--hide-popup-ignore-command)
(let ((embark-indicators
- (remq #'embark-which-key-indicator embark-indicators)))
+ (remq #'embark-which-key-indicator embark-indicators)))
(apply fn args)))
(with-eval-after-load 'embark
(advice-add #'embark-completing-read-prompter
- :around #'embark-hide-which-key-indicator)
+ :around #'embark-hide-which-key-indicator)
(setq embark-indicators (delq #'embark-mixed-indicator embark-indicators))
(push #'embark-which-key-indicator embark-indicators))
keybindings
@@ -1497,11 +1515,11 @@ Emacs is also particularly great at writing Lisp code, e.g. Clojure, Common Lisp
(use-package helpful
:straight t
:commands (helpful-callable
- helpful-variable
- helpful-key
- helpful-macro
- helpful-function
- helpful-command))
+ helpful-variable
+ helpful-key
+ helpful-macro
+ helpful-function
+ helpful-command))
As I use C-h to switch buffers, I moved the help to SPC-h with the code below.
(my-leader-def
"h" '(:keymap help-map :which-key "help"))
@@ -1543,14 +1561,14 @@ Emacs is also particularly great at writing Lisp code, e.g. Clojure, Common Lisp
:config
(setq wakatime-ignore-exit-codes '(0 1 102 112))
(advice-add 'wakatime-init :after
- (lambda ()
- (setq wakatime-cli-path (or
- (executable-find "wakatime-cli")
- (expand-file-name "~/bin/wakatime-cli")))))
+ (lambda ()
+ (setq wakatime-cli-path (or
+ (executable-find "wakatime-cli")
+ (expand-file-name "~/bin/wakatime-cli")))))
(when (file-exists-p "~/.wakatime.cfg")
(setq wakatime-api-key
- (string-trim
- (shell-command-to-string "awk '/api-key/{print $NF}' ~/.wakatime.cfg"))))
+ (string-trim
+ (shell-command-to-string "awk '/api-key/{print $NF}' ~/.wakatime.cfg"))))
;; (setq wakatime-cli-path (executable-find "wakatime"))
(global-wakatime-mode))
ActivityWatch
@@ -1618,14 +1636,14 @@ Emacs is also particularly great at writing Lisp code, e.g. Clojure, Common Lisp
Custom frame format
Title format, which used to look something like emacs:project@hostname. Now it’s just emacs.
(setq-default frame-title-format
- '(""
- "emacs"
- ;; (:eval
- ;; (let ((project-name (projectile-project-name)))
- ;; (if (not (string= "-" project-name))
- ;; (format ":%s@%s" project-name (system-name))
- ;; (format "@%s" (system-name)))))
- ))
+ '(""
+ "emacs"
+ ;; (:eval
+ ;; (let ((project-name (projectile-project-name)))
+ ;; (if (not (string= "-" project-name))
+ ;; (format ":%s@%s" project-name (system-name))
+ ;; (format "@%s" (system-name)))))
+ ))
Olivetti
Olivetti is a package that limits the current text body width. It’s pretty nice to use when writing texts.
(use-package olivetti
@@ -1643,9 +1661,9 @@ Emacs is also particularly great at writing Lisp code, e.g. Clojure, Common Lisp
"Keycast mode"
:global t
(if keycast-mode
- (progn
- (add-to-list 'global-mode-string '("" keycast-mode-line " "))
- (add-hook 'pre-command-hook 'keycast--update t) )
+ (progn
+ (add-to-list 'global-mode-string '("" keycast-mode-line " "))
+ (add-hook 'pre-command-hook 'keycast--update t) )
(remove-hook 'pre-command-hook 'keycast--update)
(setq global-mode-string (delete '("" keycast-mode-line " ") global-mode-string))))
:commands (keycast--update))
@@ -1657,7 +1675,7 @@ Emacs is also particularly great at writing Lisp code, e.g. Clojure, Common Lisp
;; Not deferring becuase I want `doom-themes-visual-bell-config'
:config
(setq doom-themes-enable-bold t
- doom-themes-enable-italic t)
+ doom-themes-enable-italic t)
;; (if my/remote-server
;; (load-theme 'doom-gruvbox t)
;; (load-theme 'doom-palenight t))
@@ -1671,7 +1689,7 @@ Emacs is also particularly great at writing Lisp code, e.g. Clojure, Common Lisp
:straight t
:config
(setq ef-duo-light-palette-overrides
- '((constant green))))
+ '((constant green))))
Custom theme
Here I define a few things on the top of Emacs theme, because:
@@ -1686,15 +1704,15 @@ Emacs is also particularly great at writing Lisp code, e.g. Clojure, Common Lisp
As of now I want this to support doom-themes and modus-themes. So, let’s get which one is enabled:
(defun my/doom-p ()
(seq-find (lambda (x) (string-match-p (rx bos "doom") (symbol-name x)))
- custom-enabled-themes))
+ custom-enabled-themes))
(defun my/modus-p ()
(seq-find (lambda (x) (string-match-p (rx bos "modus") (symbol-name x)))
- custom-enabled-themes))
+ custom-enabled-themes))
(defun my/ef-p ()
(seq-find (lambda (x) (string-match-p (rx bos "ef") (symbol-name x)))
- custom-enabled-themes))
+ custom-enabled-themes))
I also want to know if the current theme is light or not:
(defun my/light-p ()
(ct-light-p (my/color-value 'bg)))
@@ -1716,30 +1734,30 @@ Emacs is also particularly great at writing Lisp code, e.g. Clojure, Common Lisp
(defun my/doom-color (color)
(when (doom-color 'bg)
(let ((override (alist-get (my/doom-p) my/theme-override))
- (color-name (symbol-name color))
- (is-light (ct-light-p (doom-color 'bg))))
+ (color-name (symbol-name color))
+ (is-light (ct-light-p (doom-color 'bg))))
(or
(alist-get color override)
(cond
- ((eq 'black color)
- (if is-light (doom-color 'fg) (doom-color 'bg)))
- ((eq 'white color)
- (if is-light (doom-color 'bg) (doom-color 'fg)))
- ((eq 'border color)
- (if is-light (doom-color 'base0) (doom-color 'base8)))
- ((string-match-p (rx bos "light-") color-name)
- (ct-edit-hsl-l-inc (my/doom-color (intern (substring color-name 6)))
- my/alpha-for-light))
- ((string-match-p (rx bos "dark-") color-name)
- (or (doom-color color)
- (ct-edit-hsl-l-dec (my/doom-color (intern (substring color-name 5)))
- my/alpha-for-light)))
- (t (doom-color color)))))))
+ ((eq 'black color)
+ (if is-light (doom-color 'fg) (doom-color 'bg)))
+ ((eq 'white color)
+ (if is-light (doom-color 'bg) (doom-color 'fg)))
+ ((eq 'border color)
+ (if is-light (doom-color 'base0) (doom-color 'base8)))
+ ((string-match-p (rx bos "light-") color-name)
+ (ct-edit-hsl-l-inc (my/doom-color (intern (substring color-name 6)))
+ my/alpha-for-light))
+ ((string-match-p (rx bos "dark-") color-name)
+ (or (doom-color color)
+ (ct-edit-hsl-l-dec (my/doom-color (intern (substring color-name 5)))
+ my/alpha-for-light)))
+ (t (doom-color color)))))))
And the same for modus-themes. my/modus-color has to accept the same arguments as I use for my/doom-color for backward compatibility, which requires a bit more tuning.
(defun my/modus-get-base (color)
(let ((base-value (string-to-number (substring (symbol-name color) 4 5)))
- (base-start (cadr (assoc 'bg-main (modus-themes--current-theme-palette))))
- (base-end (cadr (assoc 'fg-dim (modus-themes--current-theme-palette)))))
+ (base-start (cadr (assoc 'bg-main (modus-themes--current-theme-palette))))
+ (base-end (cadr (assoc 'fg-dim (modus-themes--current-theme-palette)))))
(nth base-value (ct-gradient 9 base-start base-end t))))
(defun my/prot-color (color palette)
@@ -1747,16 +1765,16 @@ Emacs is also particularly great at writing Lisp code, e.g. Clojure, Common Lisp
(cond
((member color '(black white light-black light-white))
(let ((bg-main (cadr (assoc 'bg-main palette)))
- (fg-main (cadr (assoc 'fg-main palette))))
- (pcase color
- ('black (if is-light fg-main bg-main))
- ('white (if is-light bg-main fg-main))
- ('light-black (ct-edit-hsl-l-inc
- (if is-light fg-main bg-main)
- 15))
- ('light-white (ct-edit-hsl-l-inc
- (if is-light bg-main fg-main)
- 15)))))
+ (fg-main (cadr (assoc 'fg-main palette))))
+ (pcase color
+ ('black (if is-light fg-main bg-main))
+ ('white (if is-light bg-main fg-main))
+ ('light-black (ct-edit-hsl-l-inc
+ (if is-light fg-main bg-main)
+ 15))
+ ('light-white (ct-edit-hsl-l-inc
+ (if is-light bg-main fg-main)
+ 15)))))
((or (eq color 'bg))
(cadr (assoc 'bg-main palette)))
((or (eq color 'fg))
@@ -1769,7 +1787,7 @@ Emacs is also particularly great at writing Lisp code, e.g. Clojure, Common Lisp
(my/modus-get-base color))
((string-match-p (rx bos "dark-") (symbol-name color))
(cadr (assoc (intern (format "%s-cooler" (substring (symbol-name color) 5)))
- palette)))
+ palette)))
((eq color 'grey)
(my/modus-get-base 'base5))
((string-match-p (rx bos "light-") (symbol-name color))
@@ -1786,10 +1804,10 @@ Emacs is also particularly great at writing Lisp code, e.g. Clojure, Common Lisp
Test the three functions.
(defconst my/test-colors-list
'(black red green yellow blue magenta cyan white light-black
- dark-red dark-green dark-yellow dark-blue dark-magenta dark-cyan
- light-red light-green light-yellow light-blue light-magenta
- light-cyan light-white bg bg-alt fg fg-alt violet grey base0 base1
- base2 base3 base4 base5 base6 base7 base8 border))
+ dark-red dark-green dark-yellow dark-blue dark-magenta dark-cyan
+ light-red light-green light-yellow light-blue light-magenta
+ light-cyan light-white bg bg-alt fg fg-alt violet grey base0 base1
+ base2 base3 base4 base5 base6 base7 base8 border))
(defun my/test-colors ()
(interactive)
@@ -1797,12 +1815,12 @@ Emacs is also particularly great at writing Lisp code, e.g. Clojure, Common Lisp
(with-current-buffer buf
(insert (format "%-20s %-10s %-10s %-10s" "Color" "Doom" "Modus" "Ef") "\n")
(cl-loop for color in my/test-colors-list
- do (insert
- (format "%-20s %-10s %-10s %-10s\n"
- (prin1-to-string color)
- (my/doom-color color)
- (my/modus-color color)
- (my/ef-color color))))
+ do (insert
+ (format "%-20s %-10s %-10s %-10s\n"
+ (prin1-to-string color)
+ (my/doom-color color)
+ (my/modus-color color)
+ (my/ef-color color))))
(special-mode)
(rainbow-mode))
(switch-to-buffer buf)))
@@ -1812,16 +1830,16 @@ Emacs is also particularly great at writing Lisp code, e.g. Clojure, Common Lisp
((stringp color) (my/color-value (intern color)))
((eq color 'bg-other)
(or (my/color-value 'bg-dim)
- (let ((color (my/color-value 'bg)))
- (if (ct-light-p color)
- (ct-edit-hsl-l-dec color 2)
- (ct-edit-hsl-l-dec color 3)))))
+ (let ((color (my/color-value 'bg)))
+ (if (ct-light-p color)
+ (ct-edit-hsl-l-dec color 2)
+ (ct-edit-hsl-l-dec color 3)))))
((eq color 'modeline)
(or
(my/color-value 'bg-mode-line-active)
(my/color-value 'bg-mode-line)
(if (my/light-p)
- (ct-edit-hsl-l-dec (my/color-value 'bg-alt) 10)
+ (ct-edit-hsl-l-dec (my/color-value 'bg-alt) 10)
(ct-edit-hsl-l-inc (my/color-value 'bg-alt) 15))))
((my/doom-p) (my/doom-color color))
((my/modus-p) (my/modus-color color))
@@ -1836,20 +1854,20 @@ Emacs is also particularly great at writing Lisp code, e.g. Clojure, Common Lisp
(defmacro my/use-colors (&rest data)
`(progn
,@(cl-loop for i in data collect
- `(setf (alist-get ',(car i) my/my-theme-update-color-params)
- (list ,@(cl-loop for (key value) on (cdr i) by #'cddr
- append `(,key ',value)))))
+ `(setf (alist-get ',(car i) my/my-theme-update-color-params)
+ (list ,@(cl-loop for (key value) on (cdr i) by #'cddr
+ append `(,key ',value)))))
(when (and (or (my/doom-p) (my/modus-p)) my/emacs-started)
(my/update-my-theme))))
This macro puts lambdas to my/my-theme-update-colors-hook that updates faces in my-theme-1. Now I have to call this hook:
(defun my/update-my-theme (&rest _)
(interactive)
(cl-loop for (face . values) in my/my-theme-update-color-params
- do (custom-theme-set-faces
- 'my-theme-1
- `(,face ((t ,@(cl-loop for (key value) on values by #'cddr
- collect key
- collect (eval value)))))))
+ do (custom-theme-set-faces
+ 'my-theme-1
+ `(,face ((t ,@(cl-loop for (key value) on values by #'cddr
+ collect key
+ collect (eval value)))))))
(enable-theme 'my-theme-1))
(unless my/is-termux
@@ -1858,22 +1876,22 @@ Emacs is also particularly great at writing Lisp code, e.g. Clojure, Common Lisp
Defining colors for tab-bar.el:
(my/use-colors
(tab-bar-tab :background (my/color-value 'bg)
- :foreground (my/color-value 'yellow)
- :underline (my/color-value 'yellow))
+ :foreground (my/color-value 'yellow)
+ :underline (my/color-value 'yellow))
(tab-bar :background 'unspecified :foreground 'unspecified)
(magit-section-secondary-heading :foreground (my/color-value 'blue)
- :weight 'bold))
+ :weight 'bold))
Switch theme
The built-in load-theme does not deactivate the previous theme, so here’s a function that does that:
(defun my/switch-theme (theme)
(interactive
(list (intern (completing-read "Load custom theme: "
- (mapcar #'symbol-name
- (custom-available-themes))))))
+ (mapcar #'symbol-name
+ (custom-available-themes))))))
(cl-loop for enabled-theme in custom-enabled-themes
- if (not (or (eq enabled-theme 'my-theme-1)
- (eq enabled-theme theme)))
- do (disable-theme enabled-theme))
+ if (not (or (eq enabled-theme 'my-theme-1)
+ (eq enabled-theme theme)))
+ do (disable-theme enabled-theme))
(load-theme theme t)
(when current-prefix-arg
(my/regenerate-desktop)))
@@ -1948,8 +1966,8 @@ Emacs is also particularly great at writing Lisp code, e.g. Clojure, Common Lisp
(when (display-graphic-p)
(if (x-list-fonts "JetBrainsMono Nerd Font")
(let ((font "-JB -JetBrainsMono Nerd Font-medium-normal-normal-*-17-*-*-*-m-0-iso10646-1"))
- (set-frame-font font nil t)
- (add-to-list 'default-frame-alist `(font . ,font)))
+ (set-frame-font font nil t)
+ (add-to-list 'default-frame-alist `(font . ,font)))
(message "Install JetBrainsMono Nerd Font!")))
To make the icons work (e.g. in the Doom Modeline), run M-x all-the-icons-install-fonts. The package definition is somewhere later in the config.
Other fonts
@@ -2006,17 +2024,17 @@ Emacs is also particularly great at writing Lisp code, e.g. Clojure, Common Lisp
(use-package nerd-icons
:straight t)
Text highlight
-Highlight indent guides. I used highlight-indent-guides before but indent-bars seems to work better, and also doesn’t break with treesit-fold.
+Highlight indent guides. I used highlight-indent-guides before but indent-bars seems to work better, and it doesn’t break with treesit-fold.
(use-package indent-bars
:straight (:host github :repo "jdtsmith/indent-bars")
:if (not (or my/remote-server))
:hook ((prog-mode . indent-bars-mode)
- (LaTeX-mode . indent-bars-mode))
+ (LaTeX-mode . indent-bars-mode))
:config
(require 'indent-bars-ts)
(setopt indent-bars-no-descend-lists t
- indent-bars-treesit-support t
- indent-bars-width-frac 0.3))
+ indent-bars-treesit-support t
+ indent-bars-width-frac 0.3))
Rainbow parentheses.
(use-package rainbow-delimiters
:straight t
@@ -2059,58 +2077,58 @@ Emacs is also particularly great at writing Lisp code, e.g. Clojure, Common Lisp
(defun my/tab-bar-mode-line--format ()
(unless (derived-mode-p 'company-box-mode)
(cl-letf (((symbol-function 'window-pixel-width)
- 'frame-pixel-width)
- ((symbol-function 'window-margins)
- (lambda (&rest _)
- (list nil))))
+ 'frame-pixel-width)
+ ((symbol-function 'window-margins)
+ (lambda (&rest _)
+ (list nil))))
(let ((doom-modeline-window-width-limit nil)
- (doom-modeline--limited-width-p nil))
- (format-mode-line
- '("%e"
- (:eval
- (doom-modeline-format--main))))))))
+ (doom-modeline--limited-width-p nil))
+ (format-mode-line
+ '("%e"
+ (:eval
+ (doom-modeline-format--main))))))))
(defun my/hide-mode-line-if-only-window ()
(let* ((windows (window-list))
- (hide-mode-line-p (length= windows 1)))
+ (hide-mode-line-p (length= windows 1)))
(dolist (win windows)
(with-current-buffer (window-buffer win)
- (unless (eq hide-mode-line-p hide-mode-line-mode)
- (hide-mode-line-mode
- (if hide-mode-line-p +1 -1)))))))
+ (unless (eq hide-mode-line-p hide-mode-line-mode)
+ (hide-mode-line-mode
+ (if hide-mode-line-p +1 -1)))))))
(define-minor-mode my/tab-bar-mode-line-mode
"Use tab-bar as mode line mode."
:global t
(if my/tab-bar-mode-line-mode
(progn
- (tab-bar-mode +1)
- (setq tab-bar-format '(my/tab-bar-mode-line--format))
- (set-face-attribute 'tab-bar nil :inherit 'mode-line)
- (add-hook 'window-configuration-change-hook #'my/hide-mode-line-if-only-window)
+ (tab-bar-mode +1)
+ (setq tab-bar-format '(my/tab-bar-mode-line--format))
+ (set-face-attribute 'tab-bar nil :inherit 'mode-line)
+ (add-hook 'window-configuration-change-hook #'my/hide-mode-line-if-only-window)
- (dolist (buf (buffer-list))
- (with-current-buffer buf
- (doom-modeline-set-modeline 'minimal)))
- (doom-modeline-set-modeline 'minimal 'default)
+ (dolist (buf (buffer-list))
+ (with-current-buffer buf
+ (doom-modeline-set-modeline 'minimal)))
+ (doom-modeline-set-modeline 'minimal 'default)
- (dolist (frame (frame-list))
- (with-selected-frame frame
- (my/hide-mode-line-if-only-window))
- (when-let (cb-frame (company-box--get-frame frame))
- (set-frame-parameter cb-frame 'tab-bar-lines 0)))
- (setenv "POLYBAR_BOTTOM" "false")
- (when (fboundp #'my/exwm-run-polybar)
- (my/exwm-run-polybar)))
+ (dolist (frame (frame-list))
+ (with-selected-frame frame
+ (my/hide-mode-line-if-only-window))
+ (when-let (cb-frame (company-box--get-frame frame))
+ (set-frame-parameter cb-frame 'tab-bar-lines 0)))
+ (setenv "POLYBAR_BOTTOM" "false")
+ (when (fboundp #'my/exwm-run-polybar)
+ (my/exwm-run-polybar)))
(tab-bar-mode -1)
(setq tab-bar-format
- '(tab-bar-format-history tab-bar-format-tabs tab-bar-separator tab-bar-format-add-tab))
+ '(tab-bar-format-history tab-bar-format-tabs tab-bar-separator tab-bar-format-add-tab))
(set-face-attribute 'tab-bar nil :inherit 'default)
(remove-hook 'window-configuration-change-hook #'my/hide-mode-line-if-only-window)
(global-hide-mode-line-mode -1)
(dolist (buf (buffer-list))
(with-current-buffer buf
- (doom-modeline-set-modeline 'main)))
+ (doom-modeline-set-modeline 'main)))
(doom-modeline-set-modeline 'main 'default)
(setenv "POLYBAR_BOTTOM" "true")
(when (fboundp #'my/exwm-run-polybar)
@@ -2173,22 +2191,22 @@ Emacs is also particularly great at writing Lisp code, e.g. Clojure, Common Lisp
(defun my/perspective-assign ()
(when-let* ((_ (not my/perspective-assign-ignore))
- (rule (alist-get major-mode my/perspective-assign-alist)))
+ (rule (alist-get major-mode my/perspective-assign-alist)))
(let ((workspace-index (car rule))
- (persp-name (cadr rule))
- (buffer (current-buffer)))
+ (persp-name (cadr rule))
+ (buffer (current-buffer)))
(if (fboundp #'perspective-exwm-assign-window)
- (progn
- (perspective-exwm-assign-window
- :workspace-index workspace-index
- :persp-name persp-name)
- (when workspace-index
- (exwm-workspace-switch workspace-index))
- (when persp-name
- (persp-switch persp-name)))
- (with-perspective persp-name
- (persp-set-buffer buffer))
- (persp-switch-to-buffer buffer)))))
+ (progn
+ (perspective-exwm-assign-window
+ :workspace-index workspace-index
+ :persp-name persp-name)
+ (when workspace-index
+ (exwm-workspace-switch workspace-index))
+ (when persp-name
+ (persp-switch persp-name)))
+ (with-perspective persp-name
+ (persp-set-buffer buffer))
+ (persp-switch-to-buffer buffer)))))
Also advise to ignore the assignment:
(defun my/perspective-assign-ignore-advice (fun &rest args)
(let ((my/perspective-assign-ignore t))
@@ -2204,12 +2222,12 @@ Emacs is also particularly great at writing Lisp code, e.g. Clojure, Common Lisp
(let (result)
(while body
(let ((major-mode (pop body))
- (workspace-index (pop body))
- (persp-name (pop body)))
- (push
- `(add-to-list 'my/perspective-assign-alist
- '(,major-mode . (,workspace-index ,persp-name)))
- result)))
+ (workspace-index (pop body))
+ (persp-name (pop body)))
+ (push
+ `(add-to-list 'my/perspective-assign-alist
+ '(,major-mode . (,workspace-index ,persp-name)))
+ result)))
`(progn
,@result)))
Also, the logic above works only for cases when the buffer is created. Occasionally, packages run switch-to-buffer, which screws both EXWM workspaces and perspectives; to work around that, I define a macro that runs a command in the context of a given perspective and workspace.
@@ -2217,7 +2235,7 @@ Emacs is also particularly great at writing Lisp code, e.g. Clojure, Common Lisp
`'((lambda ()
(interactive)
(when (and ,workspace-index (fboundp #'exwm-workspace-switch-create))
- (exwm-workspace-switch-create ,workspace-index))
+ (exwm-workspace-switch-create ,workspace-index))
(persp-switch ,persp-name)
(delete-other-windows)
,@args)
@@ -2261,18 +2279,18 @@ Emacs is also particularly great at writing Lisp code, e.g. Clojure, Common Lisp
:straight t
:if (not (or my/is-termux my/remote-server))
:hook (
- (typescript-mode . lsp)
- (js-mode . lsp)
- (vue-mode . lsp)
- (go-mode . lsp)
- (svelte-mode . lsp)
- ;; (python-mode . lsp)
- (json-mode . lsp)
- (haskell-mode . lsp)
- (haskell-literate-mode . lsp)
- (java-mode . lsp)
- ;; (csharp-mode . lsp)
- )
+ (typescript-mode . lsp)
+ (js-mode . lsp)
+ (vue-mode . lsp)
+ (go-mode . lsp)
+ (svelte-mode . lsp)
+ ;; (python-mode . lsp)
+ (json-mode . lsp)
+ (haskell-mode . lsp)
+ (haskell-literate-mode . lsp)
+ (java-mode . lsp)
+ ;; (csharp-mode . lsp)
+ )
:commands lsp
:init
(setq lsp-keymap-prefix nil)
@@ -2312,30 +2330,53 @@ Emacs is also particularly great at writing Lisp code, e.g. Clojure, Common Lisp
(defun my/lsp--progress-status ()
"Returns the status of the progress for the current workspaces."
(-let ((progress-status
- (s-join
- "|"
- (-keep
- (lambda (workspace)
- (let ((tokens (lsp--workspace-work-done-tokens workspace)))
- (unless (ht-empty? tokens)
- (mapconcat
- (-lambda ((&WorkDoneProgressBegin :message? :title :percentage?))
- (concat (if percentage?
- (if (numberp percentage?)
- (format "%.0f%%%% " percentage?)
- (format "%s%%%% " percentage?))
- "")
- (let ((msg (url-unhex-string (or message\? title))))
- (if (string-match-p "\\`file:///" msg)
- (file-name-nondirectory msg)))))
- (ht-values tokens)
- "|"))))
- (lsp-workspaces)))))
+ (s-join
+ "|"
+ (-keep
+ (lambda (workspace)
+ (let ((tokens (lsp--workspace-work-done-tokens workspace)))
+ (unless (ht-empty? tokens)
+ (mapconcat
+ (-lambda ((&WorkDoneProgressBegin :message? :title :percentage?))
+ (concat (if percentage?
+ (if (numberp percentage?)
+ (format "%.0f%%%% " percentage?)
+ (format "%s%%%% " percentage?))
+ "")
+ (let ((msg (url-unhex-string (or message\? title))))
+ (if (string-match-p "\\`file:///" msg)
+ (file-name-nondirectory msg)))))
+ (ht-values tokens)
+ "|"))))
+ (lsp-workspaces)))))
(unless (s-blank? progress-status)
(concat lsp-progress-prefix progress-status))))
(with-eval-after-load 'lsp-mode
(advice-add 'lsp--progress-status :override #'my/lsp--progress-status))
+
Fix vue-semantic-server
+Somehow, for me vue-semantic-server sends an empty textDocument/publishDiagnostics message a second or two after the real one, causing the diagnostics to disappear.
+For now, I’ve advised this away by ignoring empty messages unless they show up more than 5 seconds after a non-empty message.
+(setq my/lsp--vue-diagnostics-last-update (make-hash-table :test #'equal))
+
+(defun my/lsp--on-diagnostics (fn workspace params)
+ (if (equal (gethash 'vue-semantic-server lsp-clients)
+ (lsp--workspace-client workspace))
+ (progn
+ (let* ((is-empty (seq-empty-p (gethash "diagnostics" params)))
+ (uri (gethash "uri" params))
+ (last-update (gethash uri my/lsp--vue-diagnostics-last-update))
+ (current-update (time-convert nil #'integer)))
+ (unless is-empty
+ (puthash uri current-update my/lsp--vue-diagnostics-last-update))
+ (when (or (not is-empty)
+ (not last-update)
+ (> (- current-update (or last-update 0)) 5))
+ (funcall fn workspace params))))
+ (funcall fn workspace params)))
+
+(with-eval-after-load 'lsp
+ (advice-add #'lsp--on-diagnostics :around #'my/lsp--on-diagnostics))
Flycheck
A syntax checking extension for Emacs. Integrates with LSP-mode, but can also use various standalone checkers.
References:
@@ -2355,12 +2396,12 @@ Emacs is also particularly great at writing Lisp code, e.g. Clojure, Common Lisp
;; ))
(advice-add 'flycheck-eslint-config-exists-p :override (lambda() t))
(add-to-list 'display-buffer-alist
- `(,(rx bos "*Flycheck errors*" eos)
- (display-buffer-reuse-window
- display-buffer-in-side-window)
- (side . bottom)
- (reusable-frames . visible)
- (window-height . 0.33))))
+ `(,(rx bos "*Flycheck errors*" eos)
+ (display-buffer-reuse-window
+ display-buffer-in-side-window)
+ (side . bottom)
+ (reusable-frames . visible)
+ (window-height . 0.33))))
General additional config
Have to put this before tree-sitter because I need my/set-smartparens-indent there.
Make smartparens behave the way I like for C-like languages.
@@ -2391,42 +2432,42 @@ Emacs is also particularly great at writing Lisp code, e.g. Clojure, Common Lisp
:if (featurep 'treesit)
:config
(setq treesit-language-source-alist
- (mapcar
- (lambda (item)
- (let ((lang (nth 0 item))
- (url (nth 1 item))
- (rev (nth 2 item))
- (source-dir (nth 3 item)))
- `(,lang ,url ,rev ,source-dir
- ,(executable-find "gcc") ,(executable-find "c++"))))
- '((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"))))
+ (mapcar
+ (lambda (item)
+ (let ((lang (nth 0 item))
+ (url (nth 1 item))
+ (rev (nth 2 item))
+ (source-dir (nth 3 item)))
+ `(,lang ,url ,rev ,source-dir
+ ,(executable-find "gcc") ,(executable-find "c++"))))
+ '((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"))))
(setq treesit-font-lock-level 4)
(setq major-mode-remap-alist
- '((typescript-mode . typescript-ts-mode)
- (js-mode . javascript-ts-mode)
- (python-mode . python-ts-mode)
- (json-mode . json-ts-mode)))
+ '((typescript-mode . typescript-ts-mode)
+ (js-mode . javascript-ts-mode)
+ (python-mode . python-ts-mode)
+ (json-mode . json-ts-mode)))
(cl-loop for (old-mode . new-mode) in major-mode-remap-alist
- do (my/set-smartparens-indent new-mode)
- do (set (intern (concat (symbol-name new-mode) "-hook"))
- (list
- (eval `(lambda ()
- (run-hooks
- ',(intern (concat (symbol-name old-mode) "-hook")))))))))
+ do (my/set-smartparens-indent new-mode)
+ do (set (intern (concat (symbol-name new-mode) "-hook"))
+ (list
+ (eval `(lambda ()
+ (run-hooks
+ ',(intern (concat (symbol-name old-mode) "-hook")))))))))
treesit-fold
treesit-fold uses treesit.el for folding.
(use-package treesit-fold
@@ -2439,32 +2480,32 @@ Emacs is also particularly great at writing Lisp code, e.g. Clojure, Common Lisp
(when-let*
((node (ignore-errors (treesit-buffer-root-node)))
(patterns (seq-mapcat (lambda (fold-range) `((,(car fold-range)) @name))
- (alist-get major-mode treesit-fold-range-alist)))
+ (alist-get major-mode treesit-fold-range-alist)))
(query (ignore-errors
- (treesit-query-compile (treesit-node-language node)
- patterns)))
+ (treesit-query-compile (treesit-node-language node)
+ patterns)))
(nodes-to-fold (treesit-query-capture node query))
(mode-ranges (alist-get major-mode treesit-fold-range-alist))
(nodes-to-fold
- (cl-remove-if (lambda (node)
- (treesit-fold--non-foldable-node-p (cdr node) mode-ranges))
- nodes-to-fold)))
+ (cl-remove-if (lambda (node)
+ (treesit-fold--non-foldable-node-p (cdr node) mode-ranges))
+ nodes-to-fold)))
nodes-to-fold))
Then filter children of the current foldable node and fold them:
(defun my/treesit-fold-hide-children ()
(interactive)
(let* ((current-node (treesit-fold--foldable-node-at-pos))
- (all-nodes-to-fold (my/treesit-fold--get-nodes-to-fold))
- ;; Find foldable children of `current-node'
- (target-nodes-to-fold
- (seq-filter
- (lambda (n)
- (cl-block tree-iter
- (while n
- (setq n (treesit-node-parent n))
- (when (equal n current-node)
- (cl-return-from tree-iter t)))))
- (mapcar #'cdr all-nodes-to-fold))))
+ (all-nodes-to-fold (my/treesit-fold--get-nodes-to-fold))
+ ;; Find foldable children of `current-node'
+ (target-nodes-to-fold
+ (seq-filter
+ (lambda (n)
+ (cl-block tree-iter
+ (while n
+ (setq n (treesit-node-parent n))
+ (when (equal n current-node)
+ (cl-return-from tree-iter t)))))
+ (mapcar #'cdr all-nodes-to-fold))))
(dolist (node target-nodes-to-fold)
(treesit-fold-close node))))
(defun my/evil-fold-hide-level ()
@@ -2523,8 +2564,8 @@ Emacs is also particularly great at writing Lisp code, e.g. Clojure, Common Lisp
,(concat "Toggle DAP " name "buffer")
(interactive)
(if-let (window (get-buffer-window ,(intern (concat "dap-ui--" name "-buffer"))))
- (quit-window nil window)
- (,(intern (concat "dap-ui-" name))))))
+ (quit-window nil window)
+ (,(intern (concat "dap-ui-" name))))))
(my/define-dap-ui-window-toggler "locals")
(my/define-dap-ui-window-toggler "expressions")
@@ -2541,8 +2582,8 @@ Emacs is also particularly great at writing Lisp code, e.g. Clojure, Common Lisp
_o_: Step out _ul_: Locals _sf_: Stack frame _ba_: Add _dl_: Debug last _es_: Eval thing at point
_c_: Continue _ur_: REPL _su_: Up stack frame _bc_: Set condition _de_: Edit debug template _ea_: Add expression
_r_: Restart frame _uo_: Output _sd_: Down stack frame _bh_: Set hit count _Q_: Disconnect _ed_: Remove expression
- _us_: Sessions _sF_: Stack frame filtered _bl_: Set log message _eu_: Refresh expressions
- _ub_: Breakpoints "
+ _us_: Sessions _sF_: Stack frame filtered _bl_: Set log message _eu_: Refresh expressions
+ _ub_: Breakpoints "
("n" dap-next)
("i" dap-step-in)
@@ -2593,10 +2634,10 @@ Emacs is also particularly great at writing Lisp code, e.g. Clojure, Common Lisp
(defmacro my/define-dap-tree-buffer-fixer (buffer-var buffer-name)
`(defun ,(intern (concat "my/fix-dap-ui-" buffer-name "-buffer")) (&rest _)
(with-current-buffer ,buffer-var
- (unless my/dap-mode-buffer-fixed
- (toggle-truncate-lines 1)
- (doom-modeline-set-modeline 'info)
- (setq-local my/dap-mode-buffer-fixed t)))))
+ (unless my/dap-mode-buffer-fixed
+ (toggle-truncate-lines 1)
+ (doom-modeline-set-modeline 'info)
+ (setq-local my/dap-mode-buffer-fixed t)))))
(my/define-dap-tree-buffer-fixer dap-ui--locals-buffer "locals")
(my/define-dap-tree-buffer-fixer dap-ui--expressions-buffer "expressions")
@@ -2625,27 +2666,27 @@ Emacs is also particularly great at writing Lisp code, e.g. Clojure, Common Lisp
(let ((value (plist-get (button-get node :item) :value)))
(when value
(let ((buffer (generate-new-buffer "dap-value")))
- (with-current-buffer buffer
- (insert value))
- (select-window (display-buffer buffer))))))
+ (with-current-buffer buffer
+ (insert value))
+ (select-window (display-buffer buffer))))))
Switch to stack frame with filter
One significant improvement over Chrome Inspector for my particular stack is an ability to filter the stack frame list, for instance, to see only frames that relate to my current project.
So, here are functions that customize the filters:
(with-eval-after-load 'dap-mode
(setq my/dap-stack-frame-filters
- `(("node_modules,node:internal" . ,(rx (or "node_modules" "node:internal")))
- ("node_modules" . ,(rx (or "node_modules")))
- ("node:internal" . ,(rx (or "node:internal")))))
+ `(("node_modules,node:internal" . ,(rx (or "node_modules" "node:internal")))
+ ("node_modules" . ,(rx (or "node_modules")))
+ ("node:internal" . ,(rx (or "node:internal")))))
(setq my/dap-stack-frame-current-filter (cdar my/dap-stack-frame-filters))
(defun my/dap-stack-frame-filter-set ()
(interactive)
(setq my/dap-stack-frame-current-filter
- (cdr
- (assoc
- (completing-read "Filter: " my/dap-stack-frame-filters)
- my/dap-stack-frame-filters))))
+ (cdr
+ (assoc
+ (completing-read "Filter: " my/dap-stack-frame-filters)
+ my/dap-stack-frame-filters))))
(defun my/dap-stack-frame-filter (frame)
(when-let (path (dap--get-path-for-frame frame))
@@ -2659,30 +2700,30 @@ Emacs is also particularly great at writing Lisp code, e.g. Clojure, Common Lisp
(-if-let (thread-id (dap--debug-session-thread-id (dap--cur-session)))
(-if-let (stack-frames
- (gethash
- thread-id
- (dap--debug-session-thread-stack-frames (dap--cur-session))))
- (let* ((index 0)
- (stack-framces-filtered
- (-filter
- #'my/dap-stack-frame-filter
- stack-frames))
- (new-stack-frame
- (dap--completing-read
- "Select active frame: "
- stack-framces-filtered
- (-lambda ((frame &as &hash "name"))
- (if-let (frame-path (dap--get-path-for-frame frame))
- (format "%s: %s (in %s)"
- (cl-incf index) name frame-path)
- (format "%s: %s" (cl-incf index) name)))
- nil
- t)))
- (dap--go-to-stack-frame (dap--cur-session) new-stack-frame))
- (->> (dap--cur-session)
- dap--debug-session-name
- (format "Current session %s is not stopped")
- error))
+ (gethash
+ thread-id
+ (dap--debug-session-thread-stack-frames (dap--cur-session))))
+ (let* ((index 0)
+ (stack-framces-filtered
+ (-filter
+ #'my/dap-stack-frame-filter
+ stack-frames))
+ (new-stack-frame
+ (dap--completing-read
+ "Select active frame: "
+ stack-framces-filtered
+ (-lambda ((frame &as &hash "name"))
+ (if-let (frame-path (dap--get-path-for-frame frame))
+ (format "%s: %s (in %s)"
+ (cl-incf index) name frame-path)
+ (format "%s: %s" (cl-incf index) name)))
+ nil
+ t)))
+ (dap--go-to-stack-frame (dap--cur-session) new-stack-frame))
+ (->> (dap--cur-session)
+ dap--debug-session-name
+ (format "Current session %s is not stopped")
+ error))
(error "No thread is currently active %s" (dap--debug-session-name (dap--cur-session)))))
Smarter switch to stack frame
@@ -2695,18 +2736,18 @@ Emacs is also particularly great at writing Lisp code, e.g. Clojure, Common Lisp
Returns (<buffer> . <workspace-index>) or nil."
(let* ((buf (cl-loop for buf being buffers
- if (and (buffer-file-name buf)
- (f-equal-p (buffer-file-name buf) path))
- return buf))
- (target-workspace
- (and buf
- (cl-loop for frame in exwm-workspace--list
- if (with-selected-frame frame
- (cl-loop for persp-name being the hash-keys of (perspectives-hash)
- if (member buf (persp-buffers
- (gethash persp-name (perspectives-hash))))
- return persp-name))
- return (cl-position frame exwm-workspace--list)))))
+ if (and (buffer-file-name buf)
+ (f-equal-p (buffer-file-name buf) path))
+ return buf))
+ (target-workspace
+ (and buf
+ (cl-loop for frame in exwm-workspace--list
+ if (with-selected-frame frame
+ (cl-loop for persp-name being the hash-keys of (perspectives-hash)
+ if (member buf (persp-buffers
+ (gethash persp-name (perspectives-hash))))
+ return persp-name))
+ return (cl-position frame exwm-workspace--list)))))
(when target-workspace (cons buf target-workspace))))
And override dap--go-to-stack-frame to take that into account. For some reason, evaluating this before dap-mode doesn’t work.
(defun my/dap--go-to-stack-frame-override (debug-session stack-frame)
@@ -2714,25 +2755,25 @@ Emacs is also particularly great at writing Lisp code, e.g. Clojure, Common Lisp
(with-lsp-workspace (dap--debug-session-workspace debug-session)
(when stack-frame
(-let* (((&hash "line" line "column" column "name" name) stack-frame)
- (path (dap--get-path-for-frame stack-frame)))
- (setf (dap--debug-session-active-frame debug-session) stack-frame)
- ;; If we have a source file with path attached, open it and
- ;; position the point in the line/column referenced in the
- ;; stack trace.
- (if (and path (file-exists-p path))
- (progn
- (let ((exwm-target (my/exwm-perspective-find-buffer path)))
- (if exwm-target
- (progn
- (unless (= (cdr exwm-target) exwm-workspace-current-index)
- (exwm-workspace-switch (cdr exwm-target)))
- (persp-switch-to-buffer (car exwm-target)))
- (select-window (get-mru-window (selected-frame) nil))
- (find-file path)))
- (goto-char (point-min))
- (forward-line (1- line))
- (forward-char column))
- (message "No source code for %s. Cursor at %s:%s." name line column))))
+ (path (dap--get-path-for-frame stack-frame)))
+ (setf (dap--debug-session-active-frame debug-session) stack-frame)
+ ;; If we have a source file with path attached, open it and
+ ;; position the point in the line/column referenced in the
+ ;; stack trace.
+ (if (and path (file-exists-p path))
+ (progn
+ (let ((exwm-target (my/exwm-perspective-find-buffer path)))
+ (if exwm-target
+ (progn
+ (unless (= (cdr exwm-target) exwm-workspace-current-index)
+ (exwm-workspace-switch (cdr exwm-target)))
+ (persp-switch-to-buffer (car exwm-target)))
+ (select-window (get-mru-window (selected-frame) nil))
+ (find-file path)))
+ (goto-char (point-min))
+ (forward-line (1- line))
+ (forward-char column))
+ (message "No source code for %s. Cursor at %s:%s." name line column))))
(run-hook-with-args 'dap-stack-frame-changed-hook debug-session)))
(with-eval-after-load 'exwm
@@ -2746,19 +2787,19 @@ Emacs is also particularly great at writing Lisp code, e.g. Clojure, Common Lisp
(dap-register-debug-template
"Node::Nest.js"
(list :type "node"
- :request "attach"
- :name "Node::Attach"
- :port 9229
- :outFiles ["${workspaceFolder}/dist/**/*.js"]
- :sourceMaps t
- :program "${workspaceFolder}/src/app.ts"))
+ :request "attach"
+ :name "Node::Attach"
+ :port 9229
+ :outFiles ["${workspaceFolder}/dist/**/*.js"]
+ :sourceMaps t
+ :program "${workspaceFolder}/src/app.ts"))
(dap-register-debug-template
"Node::Babel"
(list :type "node"
- :request "attach"
- :name "Node::Attach"
- :port 9229
- :program "${workspaceFolder}/dist/bin/www.js")))
+ :request "attach"
+ :name "Node::Attach"
+ :port 9229
+ :program "${workspaceFolder}/dist/bin/www.js")))
Reformatter
A general-purpose package to run formatters on files. While the most popular formatters are already packaged for Emacs, those that aren’t can be invoked with this package.
(use-package reformatter
@@ -2770,9 +2811,9 @@ Emacs is also particularly great at writing Lisp code, e.g. Clojure, Common Lisp
(or (copilot-accept-completion)
(when (my/should-run-emmet-p) (my/emmet-or-tab))
(when (and (eq evil-state 'normal)
- (or hs-minor-mode treesit-fold-mode outline-minor-mode))
- (evil-toggle-fold)
- t)
+ (or hs-minor-mode treesit-fold-mode outline-minor-mode))
+ (evil-toggle-fold)
+ t)
(indent-for-tab-command)))
(use-package copilot
@@ -2781,8 +2822,8 @@ Emacs is also particularly great at writing Lisp code, e.g. Clojure, Common Lisp
:disabled t
:init
(add-hook 'emacs-startup-hook
- (lambda ()
- (add-hook 'prog-mode-hook #'copilot-mode)))
+ (lambda ()
+ (add-hook 'prog-mode-hook #'copilot-mode)))
:config
(push '(copilot) warning-suppress-types)
(setq copilot-node-executable "/home/pavel/.guix-extra-profiles/dev/dev/bin/node")
@@ -2797,7 +2838,7 @@ Emacs is also particularly great at writing Lisp code, e.g. Clojure, Common Lisp
Web development
Configs for various web development technologies I’m using.
Emmet
-Emmet is a toolkit which greatly speeds up typing HTML & CSS.
+Emmet is a toolkit which greatly speeds up typing HTML & CSS.
@@ -2820,24 +2861,24 @@ Emacs is also particularly great at writing Lisp code, e.g. Clojure, Common Lisp
(defun my/should-run-emmet-p ()
(and (bound-and-true-p emmet-mode)
(or (and (derived-mode-p 'web-mode)
- (member (web-mode-language-at-pos) '("html" "css")))
- (not (derived-mode-p 'web-mode)))))
+ (member (web-mode-language-at-pos) '("html" "css")))
+ (not (derived-mode-p 'web-mode)))))
(use-package emmet-mode
:straight t
:hook ((vue-html-mode . emmet-mode)
- (svelte-mode . emmet-mode)
- (web-mode . emmet-mode)
- (html-mode . emmet-mode)
- (css-mode . emmet-mode)
- (scss-mode . emmet-mode))
+ (svelte-mode . emmet-mode)
+ (web-mode . emmet-mode)
+ (html-mode . emmet-mode)
+ (css-mode . emmet-mode)
+ (scss-mode . emmet-mode))
:config
(defun my/emmet-or-tab (&optional arg)
(interactive)
(if (my/should-run-emmet-p)
- (or (emmet-expand-line arg)
- (emmet-go-to-edit-point 1)
- (indent-for-tab-command arg))
+ (or (emmet-expand-line arg)
+ (emmet-go-to-edit-point 1)
+ (indent-for-tab-command arg))
(indent-for-tab-command arg)))
(general-imap :keymaps 'emmet-mode-keymap
"TAB" 'my/emmet-or-tab
@@ -2849,11 +2890,11 @@ Emacs is also particularly great at writing Lisp code, e.g. Clojure, Common Lisp
:init
(my-leader-def
:keymaps '(js-mode-map
- web-mode-map
- typescript-mode-map
- typescript-ts-mode-map
- vue-mode-map
- svelte-mode-map)
+ web-mode-map
+ typescript-mode-map
+ typescript-ts-mode-map
+ vue-mode-map
+ svelte-mode-map)
"rr" #'prettier-prettify))
TypeScript
(use-package typescript-mode
@@ -2873,7 +2914,7 @@ Emacs is also particularly great at writing Lisp code, e.g. Clojure, Common Lisp
(use-package jest-test-mode
:straight t
:hook ((typescript-mode . jest-test-mode)
- (js-mode . jest-test-mode))
+ (js-mode . jest-test-mode))
:config
(my-leader-def
:keymaps 'jest-test-mode-map
@@ -2886,7 +2927,7 @@ Emacs is also particularly great at writing Lisp code, e.g. Clojure, Common Lisp
"Execute FORM with debugger flags set."
(declare (indent 0))
`(let ((jest-test-options (seq-concatenate 'list jest-test-options (list "--runInBand") ))
- (jest-test-npx-options (seq-concatenate 'list jest-test-npx-options (list "--node-options" "--inspect-brk"))))
+ (jest-test-npx-options (seq-concatenate 'list jest-test-npx-options (list "--node-options" "--inspect-brk"))))
,form))
(defun my/jest-test-debug ()
"Run the test with an inline debugger attached."
@@ -2906,16 +2947,16 @@ Emacs is also particularly great at writing Lisp code, e.g. Clojure, Common Lisp
(advice-add #'jest-test-debug :override #'my/jest-test-debug)
(advice-add #'jest-test-debug-rerun-test :override #'my/jest-test-debug-rerun-test)
(advice-add #'jest-test-debug-run-at-point
- :override #'my/jest-test-debug-run-at-point))
+ :override #'my/jest-test-debug-run-at-point))
(defun my/jest-test-run-at-point-copy ()
"Run the top level describe block of the current buffer's point."
(interactive)
(let ((filename (jest-test-find-file))
- (example (jest-test-unit-at-point)))
+ (example (jest-test-unit-at-point)))
(if (and filename example)
- (jest-test-from-project-directory filename
- (let ((jest-test-options (seq-concatenate 'list jest-test-options (list "-t" example))))
- (kill-new (jest-test-command filename))))
+ (jest-test-from-project-directory filename
+ (let ((jest-test-options (seq-concatenate 'list jest-test-options (list "-t" example))))
+ (kill-new (jest-test-command filename))))
(message jest-test-not-found-message))))
web-mode
web-mode.el is a major mode to edit various web templates.
@@ -2931,16 +2972,20 @@ Emacs is also particularly great at writing Lisp code, e.g. Clojure, Common Lisp
(add-hook 'web-mode-hook 'smartparens-mode)
(add-hook 'web-mode-hook 'hs-minor-mode)
(my/set-smartparens-indent 'web-mode)
+ (with-eval-after-load 'editorconfig
+ (push
+ 'standard-indent
+ (alist-get 'web-mode editorconfig-indentation-alist)))
(setq web-mode-auto-pairs nil))
Hooking this up with lsp.
(setq my/web-mode-lsp-extensions
`(,(rx ".svelte" eos)
- ,(rx ".vue" eos)))
+ ,(rx ".vue" eos)))
(defun my/web-mode-lsp ()
(when (seq-some
- (lambda (regex) (string-match-p regex (buffer-file-name)))
- my/web-mode-lsp-extensions)
+ (lambda (regex) (string-match-p regex (buffer-file-name)))
+ my/web-mode-lsp-extensions)
(lsp-deferred)))
(add-hook 'web-mode-hook #'my/web-mode-lsp)
@@ -2948,7 +2993,7 @@ Emacs is also particularly great at writing Lisp code, e.g. Clojure, Common Lisp
(defun my/web-mode-vue-setup (&rest _)
(let ((filename (buffer-file-name)))
(when (and (stringp filename)
- (string-match-p (rx ".vue" eos) filename))
+ (string-match-p (rx ".vue" eos) filename))
(setq-local web-mode-script-padding 0)
(setq-local web-mode-style-padding 0)
(setq-local create-lockfiles nil)
@@ -3000,20 +3045,20 @@ Emacs is also particularly great at writing Lisp code, e.g. Clojure, Common Lisp
(assoc-delete-all "---" tex--prettify-symbols-alist))
(add-hook 'LaTeX-mode-hook
- (lambda ()
- (TeX-fold-mode 1)
- (outline-minor-mode)))
+ (lambda ()
+ (TeX-fold-mode 1)
+ (outline-minor-mode)))
(add-to-list 'TeX-view-program-selection
- '(output-pdf "Zathura"))
+ '(output-pdf "Zathura"))
;; Do not run lsp within templated TeX files
(add-hook 'LaTeX-mode-hook
- (lambda ()
- (unless (string-match "\.hogan\.tex$" (buffer-name))
- (lsp))
- (setq-local lsp-diagnostic-package :none)
- (setq-local flycheck-checker 'tex-chktex)))
+ (lambda ()
+ (unless (string-match "\.hogan\.tex$" (buffer-name))
+ (lsp))
+ (setq-local lsp-diagnostic-package :none)
+ (setq-local flycheck-checker 'tex-chktex)))
(add-hook 'LaTeX-mode-hook #'rainbow-delimiters-mode)
(add-hook 'LaTeX-mode-hook #'smartparens-mode)
@@ -3041,37 +3086,37 @@ Emacs is also particularly great at writing Lisp code, e.g. Clojure, Common Lisp
(directory-files
(seq-some
(lambda (dir)
- (if (and
- (f-directory-p dir)
- (seq-some
- (lambda (file) (string-match ".*\.sty$" file))
- (directory-files dir))
- ) dir nil))
+ (if (and
+ (f-directory-p dir)
+ (seq-some
+ (lambda (file) (string-match ".*\.sty$" file))
+ (directory-files dir))
+ ) dir nil))
(list "./styles" "../styles/" "." "..")) :full))
(lambda (f1 f2)
(let ((f1b (file-name-base f1))
- (f1b (file-name-base f2)))
- (cond
- ((string-match-p ".*BibTex" f1) t)
- ((and (string-match-p ".*Locale" f1) (not (string-match-p ".*BibTex" f2))) t)
- ((string-match-p ".*Preamble" f2) t)
- (t (string-lessp f1 f2))))))))
+ (f1b (file-name-base f2)))
+ (cond
+ ((string-match-p ".*BibTex" f1) t)
+ ((and (string-match-p ".*Locale" f1) (not (string-match-p ".*BibTex" f2))) t)
+ ((string-match-p ".*Preamble" f2) t)
+ (t (string-lessp f1 f2))))))))
(defun my/import-sty ()
(interactive)
(insert
(apply #'concat
- (cl-mapcar
- (lambda (file) (concat "\\usepackage{" (file-name-sans-extension (file-relative-name file default-directory)) "}\n"))
- (my/list-sty)))))
+ (cl-mapcar
+ (lambda (file) (concat "\\usepackage{" (file-name-sans-extension (file-relative-name file default-directory)) "}\n"))
+ (my/list-sty)))))
(defun my/import-sty-org ()
(interactive)
(insert
(apply #'concat
- (cl-mapcar
- (lambda (file) (concat "#+LATEX_HEADER: \\usepackage{" (file-name-sans-extension (file-relative-name file default-directory)) "}\n"))
- (my/list-sty)))))
+ (cl-mapcar
+ (lambda (file) (concat "#+LATEX_HEADER: \\usepackage{" (file-name-sans-extension (file-relative-name file default-directory)) "}\n"))
+ (my/list-sty)))))
Snippets
@@ -3092,43 +3137,43 @@ Emacs is also particularly great at writing Lisp code, e.g. Clojure, Common Lisp
Noweb points to the AUCTeX config block.
(setq my/greek-alphabet
'(("a" . "\\alpha")
- ("b" . "\\beta" )
- ("g" . "\\gamma")
- ("d" . "\\delta")
- ("e" . "\\epsilon")
- ("z" . "\\zeta")
- ("h" . "\\eta")
- ("o" . "\\theta")
- ("i" . "\\iota")
- ("k" . "\\kappa")
- ("l" . "\\lambda")
- ("m" . "\\mu")
- ("n" . "\\nu")
- ("x" . "\\xi")
- ("p" . "\\pi")
- ("r" . "\\rho")
- ("s" . "\\sigma")
- ("t" . "\\tau")
- ("u" . "\\upsilon")
- ("f" . "\\phi")
- ("c" . "\\chi")
- ("v" . "\\psi")
- ("g" . "\\omega")))
+ ("b" . "\\beta" )
+ ("g" . "\\gamma")
+ ("d" . "\\delta")
+ ("e" . "\\epsilon")
+ ("z" . "\\zeta")
+ ("h" . "\\eta")
+ ("o" . "\\theta")
+ ("i" . "\\iota")
+ ("k" . "\\kappa")
+ ("l" . "\\lambda")
+ ("m" . "\\mu")
+ ("n" . "\\nu")
+ ("x" . "\\xi")
+ ("p" . "\\pi")
+ ("r" . "\\rho")
+ ("s" . "\\sigma")
+ ("t" . "\\tau")
+ ("u" . "\\upsilon")
+ ("f" . "\\phi")
+ ("c" . "\\chi")
+ ("v" . "\\psi")
+ ("g" . "\\omega")))
(setq my/latex-greek-prefix "'")
;; The same for capitalized letters
(dolist (elem my/greek-alphabet)
(let ((key (car elem))
- (value (cdr elem)))
+ (value (cdr elem)))
(when (string-equal key (downcase key))
(add-to-list 'my/greek-alphabet
- (cons
- (capitalize (car elem))
- (concat
- (substring value 0 1)
- (capitalize (substring value 1 2))
- (substring value 2)))))))
+ (cons
+ (capitalize (car elem))
+ (concat
+ (substring value 0 1)
+ (capitalize (substring value 1 2))
+ (substring value 2)))))))
(yas-define-snippets
'latex-mode
@@ -3155,21 +3200,21 @@ Emacs is also particularly great at writing Lisp code, e.g. Clojure, Common Lisp
Math symbols
(setq my/latex-math-symbols
'(("x" . "\\times")
- ("." . "\\cdot")
- ("v" . "\\forall")
- ("s" . "\\sum_{$1}^{$2}$0")
- ("p" . "\\prod_{$1}^{$2}$0")
- ("d" . "\\partial")
- ("e" . "\\exists")
- ("i" . "\\int_{$1}^{$2}$0")
- ("c" . "\\cap")
- ("u" . "\\cup")
- ("0" . "\\emptyset")
- ("^" . "\\widehat{$1}$0")
- ("_" . "\\overline{$1}$0")
- ("~" . "\\sim")
- ("|" . "\\mid")
- ("_|" . "\\perp")))
+ ("." . "\\cdot")
+ ("v" . "\\forall")
+ ("s" . "\\sum_{$1}^{$2}$0")
+ ("p" . "\\prod_{$1}^{$2}$0")
+ ("d" . "\\partial")
+ ("e" . "\\exists")
+ ("i" . "\\int_{$1}^{$2}$0")
+ ("c" . "\\cap")
+ ("u" . "\\cup")
+ ("0" . "\\emptyset")
+ ("^" . "\\widehat{$1}$0")
+ ("_" . "\\overline{$1}$0")
+ ("~" . "\\sim")
+ ("|" . "\\mid")
+ ("_|" . "\\perp")))
(setq my/latex-math-prefix ";")
@@ -3178,44 +3223,44 @@ Emacs is also particularly great at writing Lisp code, e.g. Clojure, Common Lisp
(mapcar
(lambda (elem)
(let ((key (car elem))
- (value (cdr elem)))
+ (value (cdr elem)))
(list (concat my/latex-math-prefix key) value (concat "Math symbol " value))))
my/latex-math-symbols))
Section snippets
Section snippets. The code turned out to be more complicated than just writing the snippets by hand.
(setq my/latex-section-snippets
'(("ch" . "\\chapter{$1}")
- ("sec" . "\\section{$1}")
- ("ssec" . "\\subsection{$1}")
- ("sssec" . "\\subsubsection{$1}")
- ("par" . "\\paragraph{$1}}")))
+ ("sec" . "\\section{$1}")
+ ("ssec" . "\\subsection{$1}")
+ ("sssec" . "\\subsubsection{$1}")
+ ("par" . "\\paragraph{$1}}")))
(setq my/latex-section-snippets
(mapcar
(lambda (elem)
- `(,(car elem)
- ,(cdr elem)
- ,(progn
- (string-match "[a-z]+" (cdr elem))
- (match-string 0 (cdr elem)))))
+ `(,(car elem)
+ ,(cdr elem)
+ ,(progn
+ (string-match "[a-z]+" (cdr elem))
+ (match-string 0 (cdr elem)))))
my/latex-section-snippets))
(dolist (elem my/latex-section-snippets)
(let* ((key (nth 0 elem))
- (value (nth 1 elem))
- (desc (nth 2 elem))
- (star-index (string-match "\{\$1\}" value)))
+ (value (nth 1 elem))
+ (desc (nth 2 elem))
+ (star-index (string-match "\{\$1\}" value)))
(add-to-list 'my/latex-section-snippets
- `(,(concat key "*")
- ,(concat
- (substring value 0 star-index)
- "*"
- (substring value star-index))
- ,(concat desc " with *")))
+ `(,(concat key "*")
+ ,(concat
+ (substring value 0 star-index)
+ "*"
+ (substring value star-index))
+ ,(concat desc " with *")))
(add-to-list 'my/latex-section-snippets
- `(,(concat key "l")
- ,(concat value "%\n\\label{sec:$2}")
- ,(concat desc " with label")))))
+ `(,(concat key "l")
+ ,(concat value "%\n\\label{sec:$2}")
+ ,(concat desc " with label")))))
(dolist (elem my/latex-section-snippets)
(setf (nth 1 elem) (concat (nth 1 elem) "\n$0")))
@@ -3230,13 +3275,13 @@ Emacs is also particularly great at writing Lisp code, e.g. Clojure, Common Lisp
:mode "\\.md\\'"
:config
(setq markdown-command
- (concat
- "pandoc"
- " --from=markdown --to=html"
- " --standalone --mathjax --highlight-style=pygments"
- " --css=pandoc.css"
- " --quiet"
- ))
+ (concat
+ "pandoc"
+ " --from=markdown --to=html"
+ " --standalone --mathjax --highlight-style=pygments"
+ " --css=pandoc.css"
+ " --quiet"
+ ))
(setq markdown-live-preview-delete-export 'delete-on-export)
(setq markdown-asymmetric-header t)
(setq markdown-open-command "/home/pavel/bin/scripts/chromium-sep")
@@ -3290,7 +3335,7 @@ Emacs is also particularly great at writing Lisp code, e.g. Clojure, Common Lisp
A major mode to work with subtitles.
(use-package subed
:straight (:host github :repo "rndusr/subed" :files ("subed/*.el")
- :build (:not native-compile))
+ :build (:not native-compile))
;; (cons (rx (| "srt" "vtt" "ass") eos) #'subed-mode)
:mode ("\\(?:ass\\|\\(?:sr\\|vt\\)t\\)\\'" . subed-mode)
:config
@@ -3312,8 +3357,8 @@ Emacs is also particularly great at writing Lisp code, e.g. Clojure, Common Lisp
(defun my/ltex-lang ()
(interactive)
(setq lsp-ltex-language (completing-read
- "Language: "
- '("en-GB" "ru-RU" "de-DE")))
+ "Language: "
+ '("en-GB" "ru-RU" "de-DE")))
(lsp-workspace-restart (lsp--read-workspace)))
Check whether it’s necessary to run LTeX:
(defun my/ltex-need-p ()
@@ -3479,25 +3524,25 @@ Emacs is also particularly great at writing Lisp code, e.g. Clojure, Common Lisp
(defun my/get-pipenv-python ()
(let ((default-directory (projectile-project-root)))
(if (file-exists-p "Pipfile")
- (let ((asc (assoc default-directory my/pipenv-python-alist)))
- (if asc
- (cdr asc)
- (let ((python-executable
- (string-trim (shell-command-to-string "PIPENV_IGNORE_VIRTUALENVS=1 pipenv run which python 2>/dev/null"))))
- (if (string-match-p ".*not found.*" python-executable)
- (message "Pipfile found, but not pipenv executable!")
- (message (format "Found pipenv python: %s" python-executable))
- (add-to-list 'my/pipenv-python-alist (cons default-directory python-executable))
- python-executable))))
+ (let ((asc (assoc default-directory my/pipenv-python-alist)))
+ (if asc
+ (cdr asc)
+ (let ((python-executable
+ (string-trim (shell-command-to-string "PIPENV_IGNORE_VIRTUALENVS=1 pipenv run which python 2>/dev/null"))))
+ (if (string-match-p ".*not found.*" python-executable)
+ (message "Pipfile found, but not pipenv executable!")
+ (message (format "Found pipenv python: %s" python-executable))
+ (add-to-list 'my/pipenv-python-alist (cons default-directory python-executable))
+ python-executable))))
"python")))
(use-package lsp-pyright
:straight t
:defer t
:hook (python-mode . (lambda ()
- (require 'lsp-pyright)
- (setq-local lsp-pyright-python-executable-cmd (my/get-pipenv-python))
- (lsp))))
+ (require 'lsp-pyright)
+ (setq-local lsp-pyright-python-executable-cmd (my/get-pipenv-python))
+ (lsp))))
(add-hook 'python-mode-hook #'smartparens-mode)
(add-hook 'python-mode-hook #'treesit-fold-mode)
@@ -3535,9 +3580,9 @@ Emacs is also particularly great at writing Lisp code, e.g. Clojure, Common Lisp
:straight (:repo "JorisE/yapfify" :host github)
:disabled
:commands (yapfify-region
- yapfify-buffer
- yapfify-region-or-buffer
- yapf-mode))
+ yapfify-buffer
+ yapfify-region-or-buffer
+ yapf-mode))
Global config:
[style]
based_on_style = facebook
@@ -3588,10 +3633,10 @@ Emacs is also particularly great at writing Lisp code, e.g. Clojure, Common Lisp
(my-leader-def
:keymaps '(python-mode-map python-ts-mode-map)
"rr" (lambda ()
- (interactive)
- (unless (and (fboundp #'org-src-edit-buffer-p) (org-src-edit-buffer-p))
- (py-isort-buffer))
- (python-black-buffer)))
+ (interactive)
+ (unless (and (fboundp #'org-src-edit-buffer-p) (org-src-edit-buffer-p))
+ (py-isort-buffer))
+ (python-black-buffer)))
OFF sphinx-doc
A package to generate sphinx-compatible docstrings.
(use-package sphinx-doc
@@ -3646,30 +3691,30 @@ Emacs is also particularly great at writing Lisp code, e.g. Clojure, Common Lisp
(cl-defun python-pytest--run-as-comint (&key command)
"Run a pytest comint session for COMMAND."
(let* ((buffer (python-pytest--get-buffer))
- (process (get-buffer-process buffer)))
+ (process (get-buffer-process buffer)))
(with-current-buffer buffer
(when (comint-check-proc buffer)
- (unless (or compilation-always-kill
- (yes-or-no-p "Kill running pytest process?"))
- (user-error "Aborting; pytest still running")))
+ (unless (or compilation-always-kill
+ (yes-or-no-p "Kill running pytest process?"))
+ (user-error "Aborting; pytest still running")))
(when process
- (delete-process process))
+ (delete-process process))
(let ((inhibit-read-only t))
- (erase-buffer))
+ (erase-buffer))
(unless (eq major-mode 'python-pytest-mode)
- (python-pytest-mode))
+ (python-pytest-mode))
(compilation-forget-errors)
(display-buffer buffer)
(setq command (format "export COLUMNS=%s; %s"
- (- (window-width (get-buffer-window buffer)) 5)
- command))
+ (- (window-width (get-buffer-window buffer)) 5)
+ command))
(insert (format "cwd: %s\ncmd: %s\n\n" default-directory command))
(setq python-pytest--current-command command)
(when python-pytest-pdb-track
- (add-hook
- 'comint-output-filter-functions
- 'python-pdbtrack-comint-output-filter-function
- nil t))
+ (add-hook
+ 'comint-output-filter-functions
+ 'python-pdbtrack-comint-output-filter-function
+ nil t))
(run-hooks 'python-pytest-setup-hook)
(make-comint-in-buffer "pytest" buffer "bash" nil "-c" command)
(run-hooks 'python-pytest-started-hook)
@@ -3740,7 +3785,7 @@ Emacs is also particularly great at writing Lisp code, e.g. Clojure, Common Lisp
(use-package gitignore-templates
:straight t
:commands (gitignore-templates-insert
- gitignore-templates-new-file))
+ gitignore-templates-new-file))
Docker
(use-package dockerfile-mode
:mode "Dockerfile\\'"
@@ -3790,7 +3835,7 @@ Emacs is also particularly great at writing Lisp code, e.g. Clojure, Common Lisp
"Set dialect for sql-formatter"
(interactive)
(setq my/sqlformatter-dialect
- (completing-read "Dialect: " my/sqlformatter-dialect-choice)))
+ (completing-read "Dialect: " my/sqlformatter-dialect-choice)))
(reformatter-define sqlformat
:program (executable-find "sql-formatter")
@@ -3845,7 +3890,7 @@ Emacs is also particularly great at writing Lisp code, e.g. Clojure, Common Lisp
(use-package x509-mode
:commands (x509-dwim)
:straight (:host github :repo "jobbflykt/x509-mode"
- :build (:not native-compile)))
+ :build (:not native-compile)))
Java
(use-package lsp-java
:straight t
@@ -3947,13 +3992,13 @@ Emacs is also particularly great at writing Lisp code, e.g. Clojure, Common Lisp
(setq org-src-tab-acts-natively nil)
(add-hook 'org-mode-hook 'smartparens-mode)
(add-hook 'org-agenda-mode-hook
- (lambda ()
- (visual-line-mode -1)
- (toggle-truncate-lines 1)
- (display-line-numbers-mode 0)))
+ (lambda ()
+ (visual-line-mode -1)
+ (toggle-truncate-lines 1)
+ (display-line-numbers-mode 0)))
(add-hook 'org-mode-hook
- (lambda ()
- (rainbow-delimiters-mode -1))))
+ (lambda ()
+ (rainbow-delimiters-mode -1))))
Encryption
Setting up org-crypt to encrypt parts of file.
(with-eval-after-load 'org
@@ -3964,14 +4009,14 @@ Emacs is also particularly great at writing Lisp code, e.g. Clojure, Common Lisp
(with-eval-after-load 'epg
(setq epg-gpg-program "gpg")
(setq epg-config--program-alist
- `((OpenPGP
- epg-gpg-program
- ;; ("gpg2" . ,epg-gpg2-minimum-version)
- ("gpg" . ((,epg-gpg-minimum-version . "2.0")
- ,epg-gpg2-minimum-version)))
- (CMS
- epg-gpgsm-program
- ("gpgsm" . "2.0.4")))))
+ `((OpenPGP
+ epg-gpg-program
+ ;; ("gpg2" . ,epg-gpg2-minimum-version)
+ ("gpg" . ((,epg-gpg-minimum-version . "2.0")
+ ,epg-gpg2-minimum-version)))
+ (CMS
+ epg-gpgsm-program
+ ("gpgsm" . "2.0.4")))))
This enables encryption for Org segments tagged :crypt:.
Another way to encrypt Org files is to save them with the extension .org.gpg. However, by default EPA always prompts for the key, which is not what I want when there is only one key to select. Hence the following advice:
(defun my/epa--select-keys-around (fun prompt keys)
@@ -3992,9 +4037,9 @@ Emacs is also particularly great at writing Lisp code, e.g. Clojure, Common Lisp
This used to have org-contacts and ol-notmuch at some point, but they have since been migrated to separate repos.
(use-package org-contrib
:straight (org-contrib
- :type git
- :repo "https://git.sr.ht/~bzg/org-contrib"
- :build t)
+ :type git
+ :repo "https://git.sr.ht/~bzg/org-contrib"
+ :build t)
:after (org)
:if (not my/remote-server)
:config
@@ -4020,8 +4065,8 @@ Emacs is also particularly great at writing Lisp code, e.g. Clojure, Common Lisp
:hook (org-mode . evil-org-mode)
:config
(add-hook 'evil-org-mode-hook
- (lambda ()
- (evil-org-set-key-theme '(navigation insert textobjects additional calendar todo))))
+ (lambda ()
+ (evil-org-set-key-theme '(navigation insert textobjects additional calendar todo))))
(add-to-list 'evil-emacs-state-modes 'org-agenda-mode)
(require 'evil-org-agenda)
(evil-org-agenda-set-keys))
@@ -4038,7 +4083,13 @@ Emacs is also particularly great at writing Lisp code, e.g. Clojure, Common Lisp
Keybindings & stuff
I’ve moved this block above because the my-leader-def expression in the next block seems to override the previous ones. So it has to be on the top.
General keybindings
-(with-eval-after-load 'org
+(defun my/outline-prev-or-up-heading ()
+ (interactive)
+ (if (outline-on-heading-p)
+ (outline-up-heading 1)
+ (outline-previous-visible-heading 1)))
+
+(with-eval-after-load 'org
(general-define-key
:keymaps 'org-mode-map
"C-c d" #'org-decrypt-entry
@@ -4057,6 +4108,7 @@ Emacs is also particularly great at writing Lisp code, e.g. Clojure, Common Lisp
"M-9" #'org-previous-visible-heading
"C-0" #'org-forward-heading-same-level
"C-9" #'org-backward-heading-same-level
+ "(" #'my/outline-prev-or-up-heading
"M-]" #'org-babel-next-src-block
"M-[" #'org-babel-previous-src-block)
@@ -4071,9 +4123,9 @@ Emacs is also particularly great at writing Lisp code, e.g. Clojure, Common Lisp
"Extract URL from org-mode link and add it to kill ring."
(interactive "P")
(let* ((link (org-element-lineage (org-element-context) '(link) t))
- (type (org-element-property :type link))
- (url (org-element-property :path link))
- (url (concat type ":" url)))
+ (type (org-element-property :type link))
+ (url (org-element-property :path link))
+ (url (concat type ":" url)))
(kill-new url)
(message (concat "Copied URL: " url))))
@@ -4090,22 +4142,22 @@ Emacs is also particularly great at writing Lisp code, e.g. Clojure, Common Lisp
(interactive "p")
(let ((regexp org-babel-src-block-regexp))
(if (< arg 0)
- (beginning-of-line)
+ (beginning-of-line)
(end-of-line))
(while (and (< arg 0) (re-search-backward regexp nil :move))
(unless (bobp)
- (while (pcase (get-char-property-and-overlay (point) 'invisible)
- (`(outline . ,o)
- (goto-char (overlay-start o))
- (re-search-backward regexp nil :move))
- (_ nil))))
+ (while (pcase (get-char-property-and-overlay (point) 'invisible)
+ (`(outline . ,o)
+ (goto-char (overlay-start o))
+ (re-search-backward regexp nil :move))
+ (_ nil))))
(cl-incf arg))
(while (and (> arg 0) (re-search-forward regexp nil t))
(while (pcase (get-char-property-and-overlay (point) 'invisible)
- (`(outline . ,o)
- (goto-char (overlay-end o))
- (re-search-forward regexp nil :move))
- (_ (end-of-line) nil)))
+ (`(outline . ,o)
+ (goto-char (overlay-end o))
+ (re-search-forward regexp nil :move))
+ (_ (end-of-line) nil)))
(re-search-backward regexp nil :move)
(cl-decf arg))
(if (> arg 0) (goto-char (point-max)) (beginning-of-line))))
@@ -4128,18 +4180,18 @@ Emacs is also particularly great at writing Lisp code, e.g. Clojure, Common Lisp
(defun my/org-file-open ()
(interactive)
(let* ((files
- (thread-last
- '("projects" "misc" "learning")
- (mapcar (lambda (f)
- (directory-files (concat org-directory "/" f) t (rx ".org" eos))))
- (apply #'append)
- (mapcar (lambda (file)
- (string-replace (concat org-directory "/") "" file)))
- (append
- '("inbox.org" "contacts.org")))))
+ (thread-last
+ '("projects" "misc" "learning")
+ (mapcar (lambda (f)
+ (directory-files (concat org-directory "/" f) t (rx ".org" eos))))
+ (apply #'append)
+ (mapcar (lambda (file)
+ (string-replace (concat org-directory "/") "" file)))
+ (append
+ '("inbox.org" "contacts.org" "recurring.org")))))
(find-file
(concat org-directory "/"
- (completing-read "Org file: " files)))))
+ (completing-read "Org file: " files)))))
UI
LaTeX fragments
A function to enable LaTeX native highlighting. Not setting this as default, because it loads LaTeX stuff.
@@ -4172,12 +4224,12 @@ Emacs is also particularly great at writing Lisp code, e.g. Clojure, Common Lisp
\\pagestyle{empty}")
(setq org-preview-latex-process-alist
- (mapcar
- (lambda (item)
- (cons
- (car item)
- (plist-put (cdr item) :latex-header my/latex-preview-header)))
- org-preview-latex-process-alist)))
+ (mapcar
+ (lambda (item)
+ (cons
+ (car item)
+ (plist-put (cdr item) :latex-header my/latex-preview-header)))
+ org-preview-latex-process-alist)))
Better headers
org-superstar-mode is a package that makes Org heading lines look a bit prettier.
Disabled it for now because of overlapping functionality with org-bars.
@@ -4206,7 +4258,7 @@ Emacs is also particularly great at writing Lisp code, e.g. Clojure, Common Lisp
(my/use-colors
(org-block :background (my/color-value 'bg-other))
(org-block-begin-line :background (my/color-value 'bg-other)
- :foreground (my/color-value 'grey)))
+ :foreground (my/color-value 'grey)))
Hide stuff in buffer
org-appear is a package that toggles visibility of hidden elements upon entering and leaving them.
(use-package org-appear
@@ -4263,16 +4315,16 @@ Emacs is also particularly great at writing Lisp code, e.g. Clojure, Common Lisp
(defun my/org-view-html ()
(interactive)
(let ((elem (org-element-at-point))
- (temp-file-path (concat my/org-view-html-tmp-dir (number-to-string (random (expt 2 32))) ".html")))
+ (temp-file-path (concat my/org-view-html-tmp-dir (number-to-string (random (expt 2 32))) ".html")))
(cond
((not (eq 'export-block (car elem)))
(message "Not in an export block!"))
((not (string-equal (plist-get (car (cdr elem)) :type) "HTML"))
(message "Export block is not HTML!"))
(t (progn
- (f-mkdir my/org-view-html-tmp-dir)
- (f-write (plist-get (car (cdr elem)) :value) 'utf-8 temp-file-path)
- (start-process "org-html-preview" nil "xdg-open" temp-file-path))))))
+ (f-mkdir my/org-view-html-tmp-dir)
+ (f-write (plist-get (car (cdr elem)) :value) 'utf-8 temp-file-path)
+ (start-process "org-html-preview" nil "xdg-open" temp-file-path))))))
PlantUML
(with-eval-after-load 'org
(setq org-plantuml-executable-path "/home/pavel/.guix-extra-profiles/emacs/emacs/bin/plantuml")
@@ -4330,12 +4382,12 @@ Emacs is also particularly great at writing Lisp code, e.g. Clojure, Common Lisp
(org-babel-jupyter-override-src-block "hy"))
Turn of some minor modes in source blocks.
(add-hook 'org-src-mode-hook
- (lambda ()
- ;; (hs-minor-mode -1)
- ;; (electric-indent-local-mode -1)
- ;; (rainbow-delimiters-mode -1)
- ;; (highlight-indent-guides-mode -1)
- ))
+ (lambda ()
+ ;; (hs-minor-mode -1)
+ ;; (electric-indent-local-mode -1)
+ ;; (rainbow-delimiters-mode -1)
+ ;; (highlight-indent-guides-mode -1)
+ ))
Async code blocks evaluations. Jupyter blocks have a built-in async, so they are set as ignored.
(use-package ob-async
:straight t
@@ -4364,12 +4416,12 @@ Emacs is also particularly great at writing Lisp code, e.g. Clojure, Common Lisp
(defun my/select-jupyter-kernel ()
(let ((ports (my/get-open-ports))
- (files (my/list-jupyter-kernel-files)))
+ (files (my/list-jupyter-kernel-files)))
(completing-read
"Jupyter kernels: "
(seq-filter
(lambda (file)
- (member (cdr file) ports))
+ (member (cdr file) ports))
files))))
(defun my/insert-jupyter-kernel ()
@@ -4386,20 +4438,20 @@ Emacs is also particularly great at writing Lisp code, e.g. Clojure, Common Lisp
"Open Jupyter QtConsole, connected to a Jupyter kernel"
(interactive)
(start-process "jupyter-qtconsole" nil "setsid" "jupyter" "qtconsole" "--existing"
- (file-name-nondirectory (my/select-jupyter-kernel))))
+ (file-name-nondirectory (my/select-jupyter-kernel))))
I’ve also noticed that there are JSON files left in the runtime folder whenever the kernel isn’t stopped correctly. So here is a cleanup function.
(defun my/jupyter-cleanup-kernels ()
(interactive)
(let* ((ports (my/get-open-ports))
- (files (my/list-jupyter-kernel-files))
- (to-delete (seq-filter
- (lambda (file)
- (not (member (cdr file) ports)))
- files)))
+ (files (my/list-jupyter-kernel-files))
+ (to-delete (seq-filter
+ (lambda (file)
+ (not (member (cdr file) ports)))
+ files)))
(when (and (length> to-delete 0)
- (y-or-n-p (format "Delete %d files?" (length to-delete))))
+ (y-or-n-p (format "Delete %d files?" (length to-delete))))
(dolist (file to-delete)
- (delete-file (car file))))))
+ (delete-file (car file))))))
Output post-processing
Do not wrap the output in emacs-jupyter
Emacs-jupyter has its own insertion mechanisms, which always prepends output statements with :. That is not desirable in cases where a kernel supports only plain output, e.g. calysto_hy kernel.
@@ -4432,19 +4484,19 @@ Emacs is also particularly great at writing Lisp code, e.g. Clojure, Common Lisp
As for now, it looks sufficient to format source code outputs to get a tolerable LaTeX.
(defun my/org-caption-wrap (data &optional name caption attrs strip-drawer src-wrap)
(let* ((data-s (if (and strip-drawer (not (string-empty-p strip-drawer)))
- (my/org-strip-results data)
- data))
- (drawer-start (if (string-match-p "^:RESULTS:.*" data-s) 10 0)))
+ (my/org-strip-results data)
+ data))
+ (drawer-start (if (string-match-p "^:RESULTS:.*" data-s) 10 0)))
(concat
(substring data-s 0 drawer-start)
(and name (not (string-empty-p name)) (concat "#+NAME:" name "\n"))
(and caption (not (string-empty-p caption)) (concat "#+CAPTION:" caption "\n"))
(and attrs (not (string-empty-p attrs)) (concat "#+ATTR_LATEX:" attrs "\n"))
(if (and src-wrap (not (string-empty-p src-wrap)))
- (concat "#+begin_src " src-wrap "\n"
- (substring data-s drawer-start)
- (when (not (string-match-p ".*\n" data-s)) "\n")
- "#+end_src")
+ (concat "#+begin_src " src-wrap "\n"
+ (substring data-s drawer-start)
+ (when (not (string-match-p ".*\n" data-s)) "\n")
+ "#+end_src")
(substring data-s drawer-start)))))
To use, add the following snippet to the org file:
#+NAME: out_wrap
@@ -4461,9 +4513,9 @@ Emacs is also particularly great at writing Lisp code, e.g. Clojure, Common Lisp
(save-excursion
(goto-char beg)
(when (looking-at org-babel-result-regexp)
- (let ((end (org-babel-result-end))
- (ansi-color-context-region nil))
- (ansi-color-apply-on-region beg end))))))
+ (let ((end (org-babel-result-end))
+ (ansi-color-context-region nil))
+ (ansi-color-apply-on-region beg end))))))
(define-minor-mode org-babel-ansi-colors-mode
"Apply ANSI color codes to Org Babel results."
@@ -4481,11 +4533,11 @@ Emacs is also particularly great at writing Lisp code, e.g. Clojure, Common Lisp
(let ((point (point)))
(org-save-outline-visibility t
(org-babel-map-executables nil
- (when (>= (point) point)
- (if (memq (org-element-type (org-element-context))
- '(babel-call inline-babel-call))
- (org-babel-lob-execute-maybe)
- (org-babel-execute-src-block arg)))))))
+ (when (>= (point) point)
+ (if (memq (org-element-type (org-element-context))
+ '(babel-call inline-babel-call))
+ (org-babel-lob-execute-maybe)
+ (org-babel-execute-src-block arg)))))))
(defun my/org-babel-execute-buffer-above (&optional arg)
(interactive "P")
@@ -4493,34 +4545,34 @@ Emacs is also particularly great at writing Lisp code, e.g. Clojure, Common Lisp
(let ((point (point)))
(org-save-outline-visibility t
(org-babel-map-executables nil
- (when (<= (point) point)
- (if (memq (org-element-type (org-element-context))
- '(babel-call inline-babel-call))
- (org-babel-lob-execute-maybe)
- (org-babel-execute-src-block arg)))))))
+ (when (<= (point) point)
+ (if (memq (org-element-type (org-element-context))
+ '(babel-call inline-babel-call))
+ (org-babel-lob-execute-maybe)
+ (org-babel-execute-src-block arg)))))))
Execute all code blocks marked with :startup t:
(defun my/org-babel-execute-marked (&optional arg)
(interactive "P")
(let (markers)
(org-element-map (org-element-parse-buffer) 'src-block
(lambda (elem)
- (let ((params (org-element-property :parameters elem)))
- (when (and params
- (string-match-p (rx "startup t") params))
- (let ((m (make-marker)))
- (set-marker m (org-element-property :begin elem))
- (set-marker-insertion-type m t)
- (push m markers))))))
+ (let ((params (org-element-property :parameters elem)))
+ (when (and params
+ (string-match-p (rx "startup t") params))
+ (let ((m (make-marker)))
+ (set-marker m (org-element-property :begin elem))
+ (set-marker-insertion-type m t)
+ (push m markers))))))
(setq markers (nreverse markers))
(when arg
(setq markers
- (seq-filter
- (lambda (m) (> (marker-position m) (point)))
- markers)))
+ (seq-filter
+ (lambda (m) (> (marker-position m) (point)))
+ markers)))
(dolist (m markers)
(goto-char m)
(ignore-errors
- (org-babel-execute-src-block)))))
+ (org-babel-execute-src-block)))))
Some keybindings:
(with-eval-after-load 'org
(general-define-key
@@ -4570,36 +4622,36 @@ Emacs is also particularly great at writing Lisp code, e.g. Clojure, Common Lisp
"<next>" 'my/present-next-with-latex
"<prior>" 'my/present-prev-with-latex)
(setq org-present-mode-hook
- (list (lambda ()
- (blink-cursor-mode 0)
- (org-present-big)
- (org-bars-mode -1)
- ;; (org-display-inline-images)
- (org-present-hide-cursor)
- (org-present-read-only)
- (display-line-numbers-mode 0)
- (hide-mode-line-mode +1)
- (setq-local org-format-latex-options
- (plist-put org-format-latex-options
- :scale (* org-present-text-scale my/org-latex-scale 0.5)))
- ;; (org-latex-preview '(16))
- ;; TODO ^somehow this stucks at running LaTeX^
- (setq-local olivetti-body-width 60)
- (olivetti-mode 1))))
+ (list (lambda ()
+ (blink-cursor-mode 0)
+ (org-present-big)
+ (org-bars-mode -1)
+ ;; (org-display-inline-images)
+ (org-present-hide-cursor)
+ (org-present-read-only)
+ (display-line-numbers-mode 0)
+ (hide-mode-line-mode +1)
+ (setq-local org-format-latex-options
+ (plist-put org-format-latex-options
+ :scale (* org-present-text-scale my/org-latex-scale 0.5)))
+ ;; (org-latex-preview '(16))
+ ;; TODO ^somehow this stucks at running LaTeX^
+ (setq-local olivetti-body-width 60)
+ (olivetti-mode 1))))
(setq org-present-mode-quit-hook
- (list (lambda ()
- (blink-cursor-mode 1)
- (org-present-small)
- (org-bars-mode 1)
- ;; (org-remove-inline-images)
- (org-present-show-cursor)
- (org-present-read-write)
- (display-line-numbers-mode 1)
- (hide-mode-line-mode 0)
- (setq-local org-format-latex-options (plist-put org-format-latex-options :scale my/org-latex-scale))
- (org-latex-preview '(64))
- (olivetti-mode -1)
- (setq-local olivetti-body-width (default-value 'olivetti-body-width))))))
+ (list (lambda ()
+ (blink-cursor-mode 1)
+ (org-present-small)
+ (org-bars-mode 1)
+ ;; (org-remove-inline-images)
+ (org-present-show-cursor)
+ (org-present-read-write)
+ (display-line-numbers-mode 1)
+ (hide-mode-line-mode 0)
+ (setq-local org-format-latex-options (plist-put org-format-latex-options :scale my/org-latex-scale))
+ (org-latex-preview '(64))
+ (olivetti-mode -1)
+ (setq-local olivetti-body-width (default-value 'olivetti-body-width))))))
TOC
Make a TOC inside the org file.
References:
@@ -4620,7 +4672,9 @@ Emacs is also particularly great at writing Lisp code, e.g. Clojure, Common Lisp
A nice package to make screenshots and insert them to the Org document.
(use-package org-attach-screenshot
:commands (org-attach-screenshot)
- :straight t)
+ :straight t
+ :config
+ (setq org-attach-screenshot-auto-refresh 'never))
Transclusion
A package that implements transclusions in Org Mode, i.e. rendering part of one file inside another file.
(use-package org-transclusion
@@ -4655,14 +4709,14 @@ Emacs is also particularly great at writing Lisp code, e.g. Clojure, Common Lisp
(org-table-map-tables
(lambda ()
(when-let
- (name
- (plist-get (cadr (org-element-at-point)) :name))
+ (name
+ (plist-get (cadr (org-element-at-point)) :name))
(org-table-export
- (concat
- (file-name-directory
- (buffer-file-name))
- name ".csv")
- "orgtbl-to-csv")))))
+ (concat
+ (file-name-directory
+ (buffer-file-name))
+ name ".csv")
+ "orgtbl-to-csv")))))
Partial scrolling
(use-package phscroll
:straight (:host github :repo "misohena/phscroll")
@@ -4694,31 +4748,31 @@ Emacs is also particularly great at writing Lisp code, e.g. Clojure, Common Lisp
(defun my/update-org-agenda ()
(interactive)
(let ((project-files
- (when (file-directory-p (concat org-directory "/projects"))
- (thread-last "/projects"
- (concat org-directory)
- (directory-files)
- (mapcar (lambda (f)
- (concat
- org-directory "/projects/" f)))
- (seq-filter (lambda (f)
- (not (file-directory-p f))))))))
+ (when (file-directory-p (concat org-directory "/projects"))
+ (thread-last "/projects"
+ (concat org-directory)
+ (directory-files)
+ (mapcar (lambda (f)
+ (concat
+ org-directory "/projects/" f)))
+ (seq-filter (lambda (f)
+ (not (file-directory-p f))))))))
(setq org-agenda-files
- (seq-filter #'file-exists-p
- (append
- project-files
- (mapcar (lambda (f)
- (concat org-directory "/" f))
- '("inbox.org"
- "misc/habit.org"
- "contacts.org")))))
+ (seq-filter #'file-exists-p
+ (append
+ project-files
+ (mapcar (lambda (f)
+ (concat org-directory "/" f))
+ '("inbox.org"
+ "misc/habit.org"
+ "contacts.org")))))
(setq org-refile-targets
- `(,@(mapcar
- (lambda (f) `(,f . (:tag . "refile")))
- project-files)
- ,@(mapcar
- (lambda (f) `(,f . (:regexp . "Tasks")))
- project-files)))
+ `(,@(mapcar
+ (lambda (f) `(,f . (:tag . "refile")))
+ project-files)
+ ,@(mapcar
+ (lambda (f) `(,f . (:regexp . "Tasks")))
+ project-files)))
(when (file-exists-p (concat org-directory "/scripts/refile.el"))
(load-file (concat org-directory "/scripts/refile.el"))
(run-hooks 'my/org-refile-hooks))))
@@ -4741,27 +4795,27 @@ Emacs is also particularly great at writing Lisp code, e.g. Clojure, Common Lisp
(format-time-string "%Y%m%d%H%M%S")
(let ((note-name (read-string "Note name: ")))
(if (not (string-empty-p note-name))
- (string-replace " " "-" (concat "-" (downcase note-name)))
+ (string-replace " " "-" (concat "-" (downcase note-name)))
""))))
(setq org-capture-templates
`(("i" "Inbox" entry (file "inbox.org")
- ,(concat "* TODO %?\n"
- "/Entered on/ %U"))
- ("e" "email" entry (file "inbox.org")
- ,(concat "* TODO %:from %:subject \n"
- "/Entered on/ %U\n"
- "/Received on/ %:date-timestamp-inactive\n"
- "%a\n"))
- ("f" "elfeed" entry (file "inbox.org")
- ,(concat "* TODO %:elfeed-entry-title\n"
- "/Entered on/ %U\n"
- "%a\n"))
- ("n" "note" plain (file my/generate-inbox-note-name)
- ,(concat "#+TODO: PROCESSED(p)\n"
- "\n"
- "* %?\n"
- "/Entered on/ %U"))))
+ ,(concat "* TODO %?\n"
+ "/Entered on/ %U"))
+ ("e" "email" entry (file "inbox.org")
+ ,(concat "* TODO %:from %:subject \n"
+ "/Entered on/ %U\n"
+ "/Received on/ %:date-timestamp-inactive\n"
+ "%a\n"))
+ ("f" "elfeed" entry (file "inbox.org")
+ ,(concat "* TODO %:elfeed-entry-title\n"
+ "/Entered on/ %U\n"
+ "%a\n"))
+ ("n" "note" plain (file my/generate-inbox-note-name)
+ ,(concat "#+TODO: PROCESSED(p)\n"
+ "\n"
+ "* %?\n"
+ "/Entered on/ %U"))))
org-clock & org-clock-agg
org-clock allows for tracking time spent in Org entries. org-clock-agg is my package for creating reports from org-clock records.
It’s been somewhat complicated to integrate into my workflow, but I think it’s been worth it because I can now create reports for:
@@ -4784,16 +4838,16 @@ Emacs is also particularly great at writing Lisp code, e.g. Clojure, Common Lisp
(setq org-clock-agg-node-title-width-delta 47)
(push
(cons "Agenda+Archive"
- (append
- (org-agenda-files)
- (thread-last "/projects/archive"
- (concat org-directory)
- (directory-files)
- (mapcar (lambda (f)
- (concat
- org-directory "/projects/archive/" f)))
- (seq-filter (lambda (f)
- (not (file-directory-p f)))))))
+ (append
+ (org-agenda-files)
+ (thread-last "/projects/archive"
+ (concat org-directory)
+ (directory-files)
+ (mapcar (lambda (f)
+ (concat
+ org-directory "/projects/archive/" f)))
+ (seq-filter (lambda (f)
+ (not (file-directory-p f)))))))
org-clock-agg-files-preset))
The following enables org-clock persistence between Emacs sessions.
(with-eval-after-load 'org
@@ -4811,24 +4865,24 @@ Emacs is also particularly great at writing Lisp code, e.g. Clojure, Common Lisp
(defun my/org-clock-in--fix-mode-line ()
(when (memq 'org-mode-line-string global-mode-string)
(let (new-global-mode-string
- appended
- (is-first t))
+ appended
+ (is-first t))
(dolist (item global-mode-string)
- (cond
- ((or (equal item '(:eval (exwm-modeline-segment)))
- (equal item '(:eval (persp-mode-line))))
- (unless appended
- (when is-first
- (push "" new-global-mode-string))
- (push 'org-mode-line-string new-global-mode-string)
- (setq appended t))
- (push item new-global-mode-string))
- ((equal item 'org-mode-line-string))
- (t
- (push item new-global-mode-string)))
- (setq is-first nil))
+ (cond
+ ((or (equal item '(:eval (exwm-modeline-segment)))
+ (equal item '(:eval (persp-mode-line))))
+ (unless appended
+ (when is-first
+ (push "" new-global-mode-string))
+ (push 'org-mode-line-string new-global-mode-string)
+ (setq appended t))
+ (push item new-global-mode-string))
+ ((equal item 'org-mode-line-string))
+ (t
+ (push item new-global-mode-string)))
+ (setq is-first nil))
(unless appended
- (push 'org-mode-line-string new-global-mode-string))
+ (push 'org-mode-line-string new-global-mode-string))
(setq global-mode-string (nreverse new-global-mode-string)))))
(add-hook 'org-clock-in-hook #'my/org-clock-in--fix-mode-line)
@@ -4854,9 +4908,9 @@ Emacs is also particularly great at writing Lisp code, e.g. Clojure, Common Lisp
(defun my/org-clock-get-total-minutes-at-point ()
"Get total clocked time for heading at point."
(let* ((element (org-element-at-point-no-context))
- (s (buffer-substring-no-properties
- (org-element-property :begin element)
- (org-element-property :end element))))
+ (s (buffer-substring-no-properties
+ (org-element-property :begin element)
+ (org-element-property :end element))))
(with-temp-buffer
(insert s)
(org-clock-sum)
@@ -4883,18 +4937,18 @@ Emacs is also particularly great at writing Lisp code, e.g. Clojure, Common Lisp
(defun my/org-clock-recent ()
(interactive)
(let* ((entries (org-ql-query
- :select #'element-with-markers
- :from (org-agenda-files)
- :where '(clocked :from -1)))
- (entries-data (mapcar (lambda (e)
- (cons (org-element-property :raw-value e) e))
- entries)))
+ :select #'element-with-markers
+ :from (org-agenda-files)
+ :where '(clocked :from -1)))
+ (entries-data (mapcar (lambda (e)
+ (cons (org-element-property :raw-value e) e))
+ entries)))
(unless entries
(user-error "No recently clocked entries!"))
entries-data
(let* ((entry (alist-get (completing-read "Entry: " entries-data)
- entries-data nil nil #'equal))
- (marker (org-element-property :org-marker entry)))
+ entries-data nil nil #'equal))
+ (marker (org-element-property :org-marker entry)))
(pop-to-buffer-same-window (marker-buffer marker))
(goto-char marker))))
@@ -4907,17 +4961,17 @@ Emacs is also particularly great at writing Lisp code, e.g. Clojure, Common Lisp
(defun my/org-fix-task-kind ()
(interactive)
(let ((entries (org-ql-query
- :select #'element-with-markers
- :from (current-buffer)
- :where '(and (olp "Tasks")
- (not (property "TASK_KIND"))
- (clocked)))))
+ :select #'element-with-markers
+ :from (current-buffer)
+ :where '(and (olp "Tasks")
+ (not (property "TASK_KIND"))
+ (clocked)))))
(org-fold-show-all)
(dolist (entry entries)
(let ((marker (org-element-property :org-marker entry)))
- (org-with-point-at marker
- (let ((value (org-read-property-value "TASK_KIND")))
- (org-set-property "TASK_KIND" value)))))))
+ (org-with-point-at marker
+ (let ((value (org-read-property-value "TASK_KIND")))
+ (org-set-property "TASK_KIND" value)))))))
org-super-agenda
org-super-agenda is alphapapa’s extension to group items in org-agenda. I don’t use it instead of the standard agenda, but org-ql uses it for some of its views.
(use-package org-super-agenda
@@ -4936,8 +4990,8 @@ Emacs is also particularly great at writing Lisp code, e.g. Clojure, Common Lisp
(org-super-agenda--when-with-marker-buffer (org-super-agenda--get-marker item)
;; org-ql depends on f and s anyway
(s-join "/" (cons
- (f-filename (buffer-file-name))
- (org-get-outline-path))))))
+ (f-filename (buffer-file-name))
+ (org-get-outline-path))))))
It doesn’t look great with org-bars mode, so…
(defun my/org-super-agenda--make-agenda-header-around (fun name)
(remove-text-properties 0 (length name) '(line-prefix nil) name)
@@ -4957,8 +5011,8 @@ Emacs is also particularly great at writing Lisp code, e.g. Clojure, Common Lisp
:init
;; See https://github.com/alphapapa/org-ql/pull/237
(setq org-ql-regexp-part-ts-time
- (rx " " (repeat 1 2 digit) ":" (repeat 2 digit)
- (optional "-" (repeat 1 2 digit) ":" (repeat 2 digit))))
+ (rx " " (repeat 1 2 digit) ":" (repeat 2 digit)
+ (optional "-" (repeat 1 2 digit) ":" (repeat 2 digit))))
(my-leader-def
:infix "o"
"v" #'org-ql-view
@@ -4967,23 +5021,23 @@ Emacs is also particularly great at writing Lisp code, e.g. Clojure, Common Lisp
I just want to change the default grouping in org-ql-view-recent-items…
(cl-defun my/org-ql-view-recent-items
(&key num-days (type 'ts)
- (files (org-agenda-files))
- (groups '((:auto-outline-path-file t)
- (:auto-todo t))))
+ (files (org-agenda-files))
+ (groups '((:auto-outline-path-file t)
+ (:auto-todo t))))
"Show items in FILES from last NUM-DAYS days with timestamps of TYPE.
TYPE may be `ts', `ts-active', `ts-inactive', `clocked', or
`closed'."
(interactive (list :num-days (read-number "Days: ")
- :type (->> '(ts ts-active ts-inactive clocked closed)
- (completing-read "Timestamp type: ")
- intern)))
+ :type (->> '(ts ts-active ts-inactive clocked closed)
+ (completing-read "Timestamp type: ")
+ intern)))
;; It doesn't make much sense to use other date-based selectors to
;; look into the past, so to prevent confusion, we won't allow them.
(-let* ((query (pcase-exhaustive type
- ((or 'ts 'ts-active 'ts-inactive)
- `(,type :from ,(- num-days) :to 0))
- ((or 'clocked 'closed)
- `(,type :from ,(- num-days) :to 0)))))
+ ((or 'ts 'ts-active 'ts-inactive)
+ `(,type :from ,(- num-days) :to 0))
+ ((or 'clocked 'closed)
+ `(,type :from ,(- num-days) :to 0)))))
(org-ql-search files query
:title "Recent items"
:sort '(todo priority date)
@@ -4994,19 +5048,19 @@ Emacs is also particularly great at writing Lisp code, e.g. Clojure, Common Lisp
(interactive)
;; The hack I borrowed from notmuch to make " " a separator
(let* ((crm-separator " ")
- (crm-local-completion-map
- (let ((map (make-sparse-keymap)))
- (set-keymap-parent map crm-local-completion-map)
- (define-key map " " 'self-insert-command)
- map))
- (vertico-sort-function nil)
- (categories (completing-read-multiple
- "Categories: "
- '("TEACH" "EDU" "JOB" "LIFE" "COMP"))))
+ (crm-local-completion-map
+ (let ((map (make-sparse-keymap)))
+ (set-keymap-parent map crm-local-completion-map)
+ (define-key map " " 'self-insert-command)
+ map))
+ (vertico-sort-function nil)
+ (categories (completing-read-multiple
+ "Categories: "
+ '("TEACH" "EDU" "JOB" "LIFE" "COMP"))))
(org-ql-search (org-agenda-files)
`(and (todo)
- ,@(unless (seq-empty-p categories)
- `((category ,@categories))))
+ ,@(unless (seq-empty-p categories)
+ `((category ,@categories))))
:sort '(priority todo deadline)
:super-groups '((:auto-outline-path-file t)))))
Items clocked or closed today
@@ -5014,58 +5068,58 @@ Emacs is also particularly great at writing Lisp code, e.g. Clojure, Common Lisp
(defun my/org-ql-clocked-today ()
(interactive)
(let ((today (format-time-string
- "%Y-%m-%d"
- (days-to-time
- (- (org-today) (time-to-days 0))))))
+ "%Y-%m-%d"
+ (days-to-time
+ (- (org-today) (time-to-days 0))))))
(org-ql-search (org-agenda-files) `(clocked :from ,today)
:title "Clocked today"
:sort '(todo priority date)
:super-groups '((:auto-outline-path-file t)
- (:auto-todo t)))))
+ (:auto-todo t)))))
(defun my/org-ql-closed-today ()
(interactive)
(let ((today (format-time-string
- "%Y-%m-%d"
- (days-to-time
- (- (org-today) (time-to-days 0))))))
+ "%Y-%m-%d"
+ (days-to-time
+ (- (org-today) (time-to-days 0))))))
(org-ql-search (org-agenda-files) `(closed :from ,today)
:title "Closed today"
:sort '(todo priority date)
:super-groups '((:auto-outline-path-file t)
- (:auto-todo t)))))
+ (:auto-todo t)))))
Configuring views
Putting all the above in org-ql-views.
(setq org-ql-views
(list
(cons "Overview: All TODO" #'my/org-ql-all-todo)
(cons "Review: Stale tasks"
- (list :buffers-files #'org-agenda-files
- :query '(and (todo)
- (not (tags "nots"))
- (not (ts :from -14)))
- :title "Review: Stale tasks"
- :sort '(todo priority date)
- :super-groups '((:auto-outline-path-file t))))
+ (list :buffers-files #'org-agenda-files
+ :query '(and (todo)
+ (not (tags "nots"))
+ (not (ts :from -14)))
+ :title "Review: Stale tasks"
+ :sort '(todo priority date)
+ :super-groups '((:auto-outline-path-file t))))
(cons "Review: Unclocked tasks"
- (list :buffers-files #'org-agenda-files
- :query '(and (done)
- (ts :from -14)
- (not (clocked))
- (not (tags "nots")))
- :title "Review: Unclocked tasks"
- :sort '(todo priority date)
- :super-groups '((:auto-outline-path-file t))))
+ (list :buffers-files #'org-agenda-files
+ :query '(and (done)
+ (ts :from -14)
+ (not (clocked))
+ (not (tags "nots")))
+ :title "Review: Unclocked tasks"
+ :sort '(todo priority date)
+ :super-groups '((:auto-outline-path-file t))))
(cons "Review: Recently timestamped" #'my/org-ql-view-recent-items)
(cons "Review: Clocked today" #'my/org-ql-clocked-today)
(cons "Review: Closed today" #'my/org-ql-closed-today)
(cons "Fix: tasks without TASK_KIND"
- (lambda ()
- (interactive)
- (org-ql-search (current-buffer)
- '(and (olp "Tasks")
- (not (property "TASK_KIND"))
- (clocked))
- :super-groups '((:auto-outline-path-file t)))))))
+ (lambda ()
+ (interactive)
+ (org-ql-search (current-buffer)
+ '(and (olp "Tasks")
+ (not (property "TASK_KIND"))
+ (clocked))
+ :super-groups '((:auto-outline-path-file t)))))))
Custom format element
Changing the default org-ql-view--format-element to include effort estimation and the clocked time. I wish it were more configurable out-of-the-box.
(defun my/org-ql-view--format-element-override (element)
@@ -5077,60 +5131,60 @@ Emacs is also particularly great at writing Lisp code, e.g. Clojure, Common Lisp
""
(setf element (org-ql-view--resolve-element-properties element))
(let* ((properties (cadr element))
- (properties (cl-loop for (key val) on properties by #'cddr
- for symbol = (intern (cl-subseq (symbol-name key) 1))
- unless (member symbol '(parent))
- append (list symbol val)))
- (title (--> (org-ql-view--add-faces element)
- (org-element-property :raw-value it)
- (org-link-display-format it)))
- (todo-keyword (-some--> (org-element-property :todo-keyword element)
- (org-ql-view--add-todo-face it)))
- (tag-list (if org-use-tag-inheritance
- (if-let ((marker (or (org-element-property :org-hd-marker element)
- (org-element-property :org-marker element))))
- (with-current-buffer (marker-buffer marker)
- (org-with-wide-buffer
- (goto-char marker)
- (cl-loop for type in (org-ql--tags-at marker)
- unless (or (eq 'org-ql-nil type)
- (not type))
- append type)))
- (display-warning 'org-ql (format "No marker found for item: %s" title))
- (org-element-property :tags element))
- (org-element-property :tags element)))
- (tag-string (when tag-list
- (--> tag-list
- (s-join ":" it)
- (s-wrap it ":")
- (org-add-props it nil 'face 'org-tag))))
- ;; (category (org-element-property :category element))
- (priority-string (-some->> (org-element-property :priority element)
- (char-to-string)
- (format "[#%s]")
- (org-ql-view--add-priority-face)))
- (clock-string (let ((effort (org-element-property :EFFORT element))
- (clocked (org-element-property my/org-clock-total-prop element)))
- (cond
- ((and clocked effort) (format "[%s/%s]" clocked effort))
- ((and clocked (not effort) (format "[%s]" clocked)))
- ((and (not clocked) effort) (format "[EST: %s]" effort)))))
- (habit-property (org-with-point-at (or (org-element-property :org-hd-marker element)
- (org-element-property :org-marker element))
- (when (org-is-habit-p)
- (org-habit-parse-todo))))
- (due-string (pcase (org-element-property :relative-due-date element)
- ('nil "")
- (string (format " %s " (org-add-props string nil 'face 'org-ql-view-due-date)))))
- (string (s-join " " (-non-nil (list todo-keyword priority-string title due-string clock-string tag-string)))))
+ (properties (cl-loop for (key val) on properties by #'cddr
+ for symbol = (intern (cl-subseq (symbol-name key) 1))
+ unless (member symbol '(parent))
+ append (list symbol val)))
+ (title (--> (org-ql-view--add-faces element)
+ (org-element-property :raw-value it)
+ (org-link-display-format it)))
+ (todo-keyword (-some--> (org-element-property :todo-keyword element)
+ (org-ql-view--add-todo-face it)))
+ (tag-list (if org-use-tag-inheritance
+ (if-let ((marker (or (org-element-property :org-hd-marker element)
+ (org-element-property :org-marker element))))
+ (with-current-buffer (marker-buffer marker)
+ (org-with-wide-buffer
+ (goto-char marker)
+ (cl-loop for type in (org-ql--tags-at marker)
+ unless (or (eq 'org-ql-nil type)
+ (not type))
+ append type)))
+ (display-warning 'org-ql (format "No marker found for item: %s" title))
+ (org-element-property :tags element))
+ (org-element-property :tags element)))
+ (tag-string (when tag-list
+ (--> tag-list
+ (s-join ":" it)
+ (s-wrap it ":")
+ (org-add-props it nil 'face 'org-tag))))
+ ;; (category (org-element-property :category element))
+ (priority-string (-some->> (org-element-property :priority element)
+ (char-to-string)
+ (format "[#%s]")
+ (org-ql-view--add-priority-face)))
+ (clock-string (let ((effort (org-element-property :EFFORT element))
+ (clocked (org-element-property my/org-clock-total-prop element)))
+ (cond
+ ((and clocked effort) (format "[%s/%s]" clocked effort))
+ ((and clocked (not effort) (format "[%s]" clocked)))
+ ((and (not clocked) effort) (format "[EST: %s]" effort)))))
+ (habit-property (org-with-point-at (or (org-element-property :org-hd-marker element)
+ (org-element-property :org-marker element))
+ (when (org-is-habit-p)
+ (org-habit-parse-todo))))
+ (due-string (pcase (org-element-property :relative-due-date element)
+ ('nil "")
+ (string (format " %s " (org-add-props string nil 'face 'org-ql-view-due-date)))))
+ (string (s-join " " (-non-nil (list todo-keyword priority-string title due-string clock-string tag-string)))))
(remove-list-of-text-properties 0 (length string) '(line-prefix) string)
(--> string
- (concat " " it)
- (org-add-props it properties
- 'org-agenda-type 'search
- 'todo-state todo-keyword
- 'tags tag-list
- 'org-habit-p habit-property)))))
+ (concat " " it)
+ (org-add-props it properties
+ 'org-agenda-type 'search
+ 'todo-state todo-keyword
+ 'tags tag-list
+ 'org-habit-p habit-property)))))
(with-eval-after-load 'org-ql
(advice-add #'org-ql-view--format-element :override #'my/org-ql-view--format-element-override))
@@ -5166,9 +5220,9 @@ Emacs is also particularly great at writing Lisp code, e.g. Clojure, Common Lisp
Here MATCH is a match string of the same format used by
`org-tags-view'."
(funcall (cdr (org-make-tags-matcher match))
- (org-get-todo-state)
- (org-get-tags-at)
- (org-reduced-level (org-current-level))))
+ (org-get-todo-state)
+ (org-get-tags-at)
+ (org-reduced-level (org-current-level))))
(defun my/org-agenda-skip-without-match (match)
"Skip current headline unless it matches MATCH.
@@ -5183,32 +5237,32 @@ Emacs is also particularly great at writing Lisp code, e.g. Clojure, Common Lisp
(save-excursion
(unless (org-at-heading-p) (org-back-to-heading))
(let ((next-headline (save-excursion
- (or (outline-next-heading) (point-max)))))
+ (or (outline-next-heading) (point-max)))))
(if (my/org-match-at-point-p match) nil next-headline))))
And the agendas themselves:
(defun my/org-scheduled-get-time ()
(let ((scheduled (org-get-scheduled-time (point))))
(if scheduled
- (format-time-string "%Y-%m-%d" scheduled)
+ (format-time-string "%Y-%m-%d" scheduled)
"")))
(setq org-agenda-hide-tags-regexp (rx (or "org" "refile" "proj" "habit")))
(setq org-agenda-custom-commands
`(("p" "My outline"
- ((agenda "" ((org-agenda-skip-function '(my/org-agenda-skip-without-match "-habit"))))
- (tags-todo "inbox"
- ((org-agenda-overriding-header "Inbox")
- (org-agenda-prefix-format " %i %-12:c")
- (org-agenda-hide-tags-regexp ".")))
- (tags-todo "+waitlist+SCHEDULED<=\"<+14d>\""
- ((org-agenda-overriding-header "Waitlist")
- (org-agenda-hide-tags-regexp "waitlist")
- (org-agenda-prefix-format " %i %-12:c %-12(my/org-scheduled-get-time)")))
- (tags-todo "habit+SCHEDULED<=\"<+0d>\""
- ((org-agenda-overriding-header "Habits")
- (org-agenda-prefix-format " %i %-12:c")
- (org-agenda-hide-tags-regexp ".")))))))
+ ((agenda "" ((org-agenda-skip-function '(my/org-agenda-skip-without-match "-habit"))))
+ (tags-todo "inbox"
+ ((org-agenda-overriding-header "Inbox")
+ (org-agenda-prefix-format " %i %-12:c")
+ (org-agenda-hide-tags-regexp ".")))
+ (tags-todo "+waitlist+SCHEDULED<=\"<+14d>\""
+ ((org-agenda-overriding-header "Waitlist")
+ (org-agenda-hide-tags-regexp "waitlist")
+ (org-agenda-prefix-format " %i %-12:c %-12(my/org-scheduled-get-time)")))
+ (tags-todo "habit+SCHEDULED<=\"<+0d>\""
+ ((org-agenda-overriding-header "Habits")
+ (org-agenda-prefix-format " %i %-12:c")
+ (org-agenda-hide-tags-regexp ".")))))))
Alerts
- Me at 10:00: Open Org Agenga oh, there’s a meeting at 15:00
@@ -5237,18 +5291,18 @@ Emacs is also particularly great at writing Lisp code, e.g. Clojure, Common Lisp
(defun my/org-alert--is-scheduled (label time)
"Check if LABEL is scheduled to be shown an TIME."
(gethash (cons label time)
- my/org-alert--alerts nil))
+ my/org-alert--alerts nil))
(defun my/org-alert--schedule (label time)
"Schedule LABEL to be shown at TIME, unless it's already scheduled."
(unless (my/org-alert--is-scheduled label time)
(puthash (cons label time)
- (run-at-time time
- nil
- (lambda ()
- (alert label
- :title "PROXIMITY ALERT")))
- my/org-alert--alerts)))
+ (run-at-time time
+ nil
+ (lambda ()
+ (alert label
+ :title "PROXIMITY ALERT")))
+ my/org-alert--alerts)))
And unschedule items that need to be unscheduled:
(defun my/org-alert-cleanup (&optional keys)
"Unschedule items that do not appear in KEYS.
@@ -5256,44 +5310,44 @@ Emacs is also particularly great at writing Lisp code, e.g. Clojure, Common Lisp
KEYS is a list of cons cells like (<label> . <time>)."
(let ((existing-hash (make-hash-table :test #'equal)))
(cl-loop for key in keys
- do (puthash key t existing-hash))
+ do (puthash key t existing-hash))
(cl-loop for key being the hash-keys of my/org-alert--alerts
- unless (gethash key existing-hash)
- do (progn
- (cancel-timer (gethash key my/org-alert--alerts))
- (remhash key my/org-alert--alerts)))))
+ unless (gethash key existing-hash)
+ do (progn
+ (cancel-timer (gethash key my/org-alert--alerts))
+ (remhash key my/org-alert--alerts)))))
And a function to extract the required items with org-ql-query and schedule them:
(defun my/org-alert--update-today-alerts ()
(when-let* ((files (org-agenda-files))
- (items
- (org-ql-query
- :select 'element
- :from files
- :where `(and
- (todo "FUTURE")
- (ts-active :from ,(format-time-string "%Y-%m-%d %H:%M")
- :to ,(format-time-string
- "%Y-%m-%d"
- (time-add
- (current-time)
- (* 60 60 24)))
- :with-time t))
- :order-by 'date)))
+ (items
+ (org-ql-query
+ :select 'element
+ :from files
+ :where `(and
+ (todo "FUTURE")
+ (ts-active :from ,(format-time-string "%Y-%m-%d %H:%M")
+ :to ,(format-time-string
+ "%Y-%m-%d"
+ (time-add
+ (current-time)
+ (* 60 60 24)))
+ :with-time t))
+ :order-by 'date)))
(let (scheduled-keys)
(cl-loop
for item in items
for scheduled = (org-timestamp-to-time (org-element-property :scheduled item))
do (cl-loop
- for before-time in my/org-alert-notify-times
- for label = (format "%s at %s [%s min. remaining]"
- (org-element-property :raw-value item)
- (format-time-string "%H:%M" scheduled)
- (number-to-string (/ before-time 60)))
- for time = (time-convert
- (+ (time-convert scheduled 'integer) (- before-time)))
- do (progn
- (my/org-alert--schedule label time)
- (push (cons label time) scheduled-keys))))
+ for before-time in my/org-alert-notify-times
+ for label = (format "%s at %s [%s min. remaining]"
+ (org-element-property :raw-value item)
+ (format-time-string "%H:%M" scheduled)
+ (number-to-string (/ before-time 60)))
+ for time = (time-convert
+ (+ (time-convert scheduled 'integer) (- before-time)))
+ do (progn
+ (my/org-alert--schedule label time)
+ (push (cons label time) scheduled-keys))))
(my/org-alert-cleanup scheduled-keys))))
Let’s wrap it into a minor mode:
(setq my/org-alert--timer nil)
@@ -5303,11 +5357,11 @@ Emacs is also particularly great at writing Lisp code, e.g. Clojure, Common Lisp
:after-hook
(if my/org-alert-mode
(progn
- (my/org-alert--update-today-alerts)
- (when (timerp my/org-alert--timer)
- (cancel-timer my/org-alert--timer))
- (setq my/org-alert--timer
- (run-at-time 600 t #'my/org-alert--update-today-alerts)))
+ (my/org-alert--update-today-alerts)
+ (when (timerp my/org-alert--timer)
+ (cancel-timer my/org-alert--timer))
+ (setq my/org-alert--timer
+ (run-at-time 600 t #'my/org-alert--update-today-alerts)))
(when (timerp my/org-alert--timer)
(cancel-timer my/org-alert--timer))
(my/org-alert-cleanup)))
@@ -5331,82 +5385,82 @@ Emacs is also particularly great at writing Lisp code, e.g. Clojure, Common Lisp
(unless (wholenump n) (user-error "Invalid number of replications %s" n))
(when (org-before-first-heading-p) (user-error "No subtree to clone"))
(let* ((beg (save-excursion (org-back-to-heading t) (point)))
- (end-of-tree (save-excursion (org-end-of-subtree t t) (point)))
- (shift
- (or shift
- (if (and (not (equal current-prefix-arg '(4)))
- (save-excursion
- (goto-char beg)
- (re-search-forward org-ts-regexp-both end-of-tree t)))
- (read-from-minibuffer
- "Date shift per clone (e.g. +1w, empty to copy unchanged): ")
- ""))) ;No time shift
- (doshift
- (and (org-string-nw-p shift)
- (or (string-match "\\`[ \t]*\\([+-]?[0-9]+\\)\\([hdwmy]\\)[ \t]*\\'"
- shift)
- (user-error "Invalid shift specification %s" shift)))))
+ (end-of-tree (save-excursion (org-end-of-subtree t t) (point)))
+ (shift
+ (or shift
+ (if (and (not (equal current-prefix-arg '(4)))
+ (save-excursion
+ (goto-char beg)
+ (re-search-forward org-ts-regexp-both end-of-tree t)))
+ (read-from-minibuffer
+ "Date shift per clone (e.g. +1w, empty to copy unchanged): ")
+ ""))) ;No time shift
+ (doshift
+ (and (org-string-nw-p shift)
+ (or (string-match "\\`[ \t]*\\([+-]?[0-9]+\\)\\([hdwmy]\\)[ \t]*\\'"
+ shift)
+ (user-error "Invalid shift specification %s" shift)))))
(goto-char end-of-tree)
(unless (bolp) (insert "\n"))
(let* ((end (point))
- (template (buffer-substring beg end))
- (shift-n (and doshift (string-to-number (match-string 1 shift))))
- (shift-what (pcase (and doshift (match-string 2 shift))
- (`nil nil)
- ("h" 'hour)
- ("d" 'day)
- ("w" (setq shift-n (* 7 shift-n)) 'day)
- ("m" 'month)
- ("y" 'year)
- (_ (error "Unsupported time unit"))))
- (nmin 1)
- (nmax n)
- (n-no-remove -1)
- (org-id-overriding-file-name (buffer-file-name (buffer-base-buffer)))
- (idprop (org-entry-get beg "ID")))
+ (template (buffer-substring beg end))
+ (shift-n (and doshift (string-to-number (match-string 1 shift))))
+ (shift-what (pcase (and doshift (match-string 2 shift))
+ (`nil nil)
+ ("h" 'hour)
+ ("d" 'day)
+ ("w" (setq shift-n (* 7 shift-n)) 'day)
+ ("m" 'month)
+ ("y" 'year)
+ (_ (error "Unsupported time unit"))))
+ (nmin 1)
+ (nmax n)
+ (n-no-remove -1)
+ (org-id-overriding-file-name (buffer-file-name (buffer-base-buffer)))
+ (idprop (org-entry-get beg "ID")))
(when (and doshift
- (string-match-p "<[^<>\n]+ [.+]?\\+[0-9]+[hdwmy][^<>\n]*>"
- template))
- (delete-region beg end)
- (setq end beg)
- (setq nmin 0)
- (setq nmax (1+ nmax))
- (setq n-no-remove nmax))
+ (string-match-p "<[^<>\n]+ [.+]?\\+[0-9]+[hdwmy][^<>\n]*>"
+ template))
+ (delete-region beg end)
+ (setq end beg)
+ (setq nmin 0)
+ (setq nmax (1+ nmax))
+ (setq n-no-remove nmax))
(goto-char end)
(cl-loop for n from nmin to nmax do
- (insert
- ;; Prepare clone.
- (with-temp-buffer
- (insert template)
- (org-mode)
- (goto-char (point-min))
- (org-show-subtree)
- (and idprop (if org-clone-delete-id
- (org-entry-delete nil "ID")
- (org-id-get-create t)))
- (unless (= n 0)
- (while (re-search-forward org-clock-line-re nil t)
- (delete-region (line-beginning-position)
- (line-beginning-position 2)))
- (goto-char (point-min))
- (while (re-search-forward org-drawer-regexp nil t)
- (org-remove-empty-drawer-at (point))))
- (goto-char (point-min))
+ (insert
+ ;; Prepare clone.
+ (with-temp-buffer
+ (insert template)
+ (org-mode)
+ (goto-char (point-min))
+ (org-show-subtree)
+ (and idprop (if org-clone-delete-id
+ (org-entry-delete nil "ID")
+ (org-id-get-create t)))
+ (unless (= n 0)
+ (while (re-search-forward org-clock-line-re nil t)
+ (delete-region (line-beginning-position)
+ (line-beginning-position 2)))
+ (goto-char (point-min))
+ (while (re-search-forward org-drawer-regexp nil t)
+ (org-remove-empty-drawer-at (point))))
+ (goto-char (point-min))
- (when doshift
- (while (re-search-forward org-ts-regexp-both nil t)
- (org-timestamp-change (* n shift-n) shift-what))
- (save-excursion
- (goto-char (point-min))
- (evil-numbers/inc-at-pt n (point-min)))
- (unless (= n n-no-remove)
- (goto-char (point-min))
- (while (re-search-forward org-ts-regexp nil t)
- (save-excursion
- (goto-char (match-beginning 0))
- (when (looking-at "<[^<>\n]+\\( +[.+]?\\+[0-9]+[hdwmy]\\)")
- (delete-region (match-beginning 1) (match-end 1)))))))
- (buffer-string)))))
+ (when doshift
+ (while (re-search-forward org-ts-regexp-both nil t)
+ (org-timestamp-change (* n shift-n) shift-what))
+ (save-excursion
+ (goto-char (point-min))
+ (evil-numbers/inc-at-pt n (point-min)))
+ (unless (= n n-no-remove)
+ (goto-char (point-min))
+ (while (re-search-forward org-ts-regexp nil t)
+ (save-excursion
+ (goto-char (match-beginning 0))
+ (when (looking-at "<[^<>\n]+\\( +[.+]?\\+[0-9]+[hdwmy]\\)")
+ (delete-region (match-beginning 1) (match-end 1)))))))
+ (buffer-string)))))
(goto-char beg)))
My addition to that is the form with evil-numbers/inc-at-pt.
Keeping consistency among sequential records
@@ -5415,18 +5469,18 @@ Emacs is also particularly great at writing Lisp code, e.g. Clojure, Common Lisp
(defun my/org--headings-in-outline ()
(org-ql-query
:select (lambda () (propertize
- (substring-no-properties (org-get-heading t t t))
- 'marker (copy-marker (point))))
+ (substring-no-properties (org-get-heading t t t))
+ 'marker (copy-marker (point))))
:from (append
- (list (buffer-file-name))
- (let ((archive
- (concat (file-name-directory (buffer-file-name))
- "archive/"
- (file-name-nondirectory (buffer-file-name)))))
- (when (file-exists-p archive)
- (list archive))))
+ (list (buffer-file-name))
+ (let ((archive
+ (concat (file-name-directory (buffer-file-name))
+ "archive/"
+ (file-name-nondirectory (buffer-file-name)))))
+ (when (file-exists-p archive)
+ (list archive))))
:where `(and (outline-path ,@(org-get-outline-path))
- (level ,(org-current-level)))))
+ (level ,(org-current-level)))))
(defun my/org--heading-strip (heading)
(thread-last
@@ -5443,38 +5497,38 @@ Emacs is also particularly great at writing Lisp code, e.g. Clojure, Common Lisp
(seq-group-by #'my/org--heading-strip)
(seq-sort-by #'car #'string-lessp)
(mapcar (lambda (group)
- (cons (car group)
- (seq-sort-by
- (lambda (heading)
- (save-match-data
- (or
- (and (string-match (rx (group (+ digit)))
- heading)
- (string-to-number (match-string 1 heading)))
- -1)))
- #'<
- (cdr group)))))))
+ (cons (car group)
+ (seq-sort-by
+ (lambda (heading)
+ (save-match-data
+ (or
+ (and (string-match (rx (group (+ digit)))
+ heading)
+ (string-to-number (match-string 1 heading)))
+ -1)))
+ #'<
+ (cdr group)))))))
Then, display all such headings a buffer:
(defun my/org-headings-seq ()
(interactive)
(let* ((headings (my/org--headings-in-outline))
- (headings-seq (my/org--headings-group-seq headings))
- (buffer (generate-new-buffer "*Sequential Headings in Outline*")))
+ (headings-seq (my/org--headings-group-seq headings))
+ (buffer (generate-new-buffer "*Sequential Headings in Outline*")))
(with-current-buffer buffer
(outline-mode)
(setq-local widget-push-button-prefix "")
(setq-local widget-push-button-suffix "")
(dolist (group headings-seq)
- (insert (format "* %s\n" (car group)))
- (dolist (heading (cdr group))
- (widget-create 'push-button
- :marker (get-text-property 0 'marker heading)
- :notify (lambda (widget &rest ignore)
- (let ((marker (widget-get widget :marker)))
- (pop-to-buffer (marker-buffer marker))
- (goto-char marker)))
- (concat "** " (substring-no-properties heading)))
- (insert "\n")))
+ (insert (format "* %s\n" (car group)))
+ (dolist (heading (cdr group))
+ (widget-create 'push-button
+ :marker (get-text-property 0 'marker heading)
+ :notify (lambda (widget &rest ignore)
+ (let ((marker (widget-get widget :marker)))
+ (pop-to-buffer (marker-buffer marker))
+ (goto-char marker)))
+ (concat "** " (substring-no-properties heading)))
+ (insert "\n")))
(widget-setup)
(setq buffer-read-only t)
(goto-char (point-min)))
@@ -5483,21 +5537,21 @@ Emacs is also particularly great at writing Lisp code, e.g. Clojure, Common Lisp
(defun my/org-heading-seq-insert ()
(interactive)
(let* ((headings (my/org--headings-in-outline))
- (headings-seq (my/org--headings-group-seq headings))
- (heading (completing-read "Headings: " headings-seq))
- (last-number
- (thread-last headings-seq
- (assoc heading)
- (cdr)
- (mapcar (lambda (x)
- (save-match-data
- (or
- (when (string-match (rx (group (+ digit)))
- x)
- (string-to-number (match-string 1 x)))
- 1))))
- (seq-max)
- (1+))))
+ (headings-seq (my/org--headings-group-seq headings))
+ (heading (completing-read "Headings: " headings-seq))
+ (last-number
+ (thread-last headings-seq
+ (assoc heading)
+ (cdr)
+ (mapcar (lambda (x)
+ (save-match-data
+ (or
+ (when (string-match (rx (group (+ digit)))
+ x)
+ (string-to-number (match-string 1 x)))
+ 1))))
+ (seq-max)
+ (1+))))
(org-insert-heading '(4))
(insert (format "FUTURE %s %s" heading last-number))))
Archiving records
@@ -5510,9 +5564,9 @@ Emacs is also particularly great at writing Lisp code, e.g. Clojure, Common Lisp
(defun my/org-archive--get-file ()
"Get an archive version of the file."
(let ((archive-file
- (concat
- (file-name-directory (buffer-file-name))
- "archive/" (file-name-nondirectory (buffer-file-name)))))
+ (concat
+ (file-name-directory (buffer-file-name))
+ "archive/" (file-name-nondirectory (buffer-file-name)))))
(unless (file-exists-p archive-file)
(make-empty-file archive-file))
archive-file))
@@ -5521,53 +5575,53 @@ Emacs is also particularly great at writing Lisp code, e.g. Clojure, Common Lisp
(defun my/org-refile--assert-path-exists (refile-path)
(cl-assert (equal org-refile-use-outline-path 'file))
(let* ((parts (string-split refile-path "/"))
- (tbl (mapcar
- (lambda (x)
- (cons (concat (car x) "/") (cdr x)))
- org-refile-target-table)))
+ (tbl (mapcar
+ (lambda (x)
+ (cons (concat (car x) "/") (cdr x)))
+ org-refile-target-table)))
(cl-loop for i from 1
- for part in (cdr parts)
- for target = (org-refile--get-location
- (string-join (seq-take parts (1+ i)) "/")
- tbl)
- unless target
- do (let ((parent-target
- (org-refile--get-location
- (string-join (seq-take parts i) "/")
- tbl)))
- (push (org-refile-new-child parent-target part) tbl)))))
+ for part in (cdr parts)
+ for target = (org-refile--get-location
+ (string-join (seq-take parts (1+ i)) "/")
+ tbl)
+ unless target
+ do (let ((parent-target
+ (org-refile--get-location
+ (string-join (seq-take parts i) "/")
+ tbl)))
+ (push (org-refile-new-child parent-target part) tbl)))))
Now we can make a function to archive one record interactively.
(defun my/org-archive-refile ()
(interactive)
(let* ((org-refile-targets `((,(my/org-archive--get-file) . (:maxlevel . 6))))
- (org-refile-target-table (org-refile-get-targets))
- (org-refile-history nil)
- (org-refile-use-outline-path 'file)
- (org-refile-allow-creating-parent-nodes t)
- (org-outline-path-complete-in-steps nil)
- (refile-path (string-join
- (append
- (list (file-name-nondirectory
- (buffer-file-name)))
- (org-get-outline-path nil t))
- "/")))
+ (org-refile-target-table (org-refile-get-targets))
+ (org-refile-history nil)
+ (org-refile-use-outline-path 'file)
+ (org-refile-allow-creating-parent-nodes t)
+ (org-outline-path-complete-in-steps nil)
+ (refile-path (string-join
+ (append
+ (list (file-name-nondirectory
+ (buffer-file-name)))
+ (org-get-outline-path nil t))
+ "/")))
;; The path is already known
(cl-letf (((symbol-function 'completing-read)
- (lambda (&rest _) refile-path)))
+ (lambda (&rest _) refile-path)))
(my/org-refile--assert-path-exists refile-path)
(org-refile))))
And a function to archive all records older than the given number of days. I’ll use org-ql to find these records.
(defun my/org-archive-refile-all (days)
(interactive (list (read-number "Days: " 60)))
(let ((records (org-ql-query
- :select #'element-with-markers
- :from (current-buffer)
- :where `(and (ts :to ,(- days)) (done)))))
+ :select #'element-with-markers
+ :from (current-buffer)
+ :where `(and (ts :to ,(- days)) (done)))))
(when (y-or-n-p (format "Archive %d records? " (length records)))
(dolist (record records)
- (let ((marker (org-element-property :org-marker record)))
- (org-with-point-at marker
- (my/org-archive-refile)))))))
+ (let ((marker (org-element-property :org-marker record)))
+ (org-with-point-at marker
+ (my/org-archive-refile)))))))
Keybindings
Global keybindings:
(my-leader-def
@@ -5636,29 +5690,29 @@ Emacs is also particularly great at writing Lisp code, e.g. Clojure, Common Lisp
(defun my/weather-get ()
(when (> (- (time-convert nil 'integer) my/weather-last-time)
- (* 60 5))
+ (* 60 5))
(request (format "https://wttr.in/%s" my/location)
:params '(("format" . "%l:%20%C%20%t%20%w%20%p"))
:sync t
:parser (lambda () (url-unhex-string (buffer-string)))
:timeout 10
:success (cl-function
- (lambda (&key data &allow-other-keys)
- (setq my/weather-value data)
- (setq my/weather-last-time (time-convert nil 'integer))))
+ (lambda (&key data &allow-other-keys)
+ (setq my/weather-value data)
+ (setq my/weather-last-time (time-convert nil 'integer))))
:error
(cl-function (lambda (&rest args &key error-thrown &allow-other-keys)
- (message "Got error: %S" error-thrown)))))
+ (message "Got error: %S" error-thrown)))))
my/weather-value)
Let’s also try to log the current mood:
(defun my/get-mood ()
(let* ((crm-separator " ")
- (crm-local-completion-map
- (let ((map (make-sparse-keymap)))
- (set-keymap-parent map crm-local-completion-map)
- (define-key map " " 'self-insert-command)
- map))
- (vertico-sort-function nil))
+ (crm-local-completion-map
+ (let ((map (make-sparse-keymap)))
+ (set-keymap-parent map crm-local-completion-map)
+ (define-key map " " 'self-insert-command)
+ map))
+ (vertico-sort-function nil))
(mapconcat
#'identity
(completing-read-multiple
@@ -5688,24 +5742,24 @@ Emacs is also particularly great at writing Lisp code, e.g. Clojure, Common Lisp
(when (fboundp 'emms-playlist-current-selected-track)
(let ((track (emms-playlist-current-selected-track)))
(when track
- (let ((album (cdr (assoc 'info-album track)))
- (artist (or (cdr (assoc 'info-albumartist track))
- (cdr (assoc 'info-album track))))
- (title (cdr (assoc 'info-title track)))
- (string ""))
- (when artist
- (setq string (concat string "[" artist "] ")))
- (when album
- (setq string (concat string album " - ")))
- (when title
- (setq string (concat string title)))
- (when (> (length string) 0)
- (org-set-property "EMMS_Track" string))))))
+ (let ((album (cdr (assoc 'info-album track)))
+ (artist (or (cdr (assoc 'info-albumartist track))
+ (cdr (assoc 'info-album track))))
+ (title (cdr (assoc 'info-title track)))
+ (string ""))
+ (when artist
+ (setq string (concat string "[" artist "] ")))
+ (when album
+ (setq string (concat string album " - ")))
+ (when title
+ (setq string (concat string title)))
+ (when (> (length string) 0)
+ (org-set-property "EMMS_Track" string))))))
(when-let (mood (my/get-mood))
(org-set-property "Mood" mood)))
(add-hook 'org-journal-after-entry-create-hook
- #'my/set-journal-header)
+ #'my/set-journal-header)
Also, a function to decrypt the current file:
(defun my/org-journal-decrypt ()
"Decrypt the current org journal file."
@@ -5733,9 +5787,9 @@ Emacs is also particularly great at writing Lisp code, e.g. Clojure, Common Lisp
org-cite-activate-processor 'citar
citar-bibliography org-cite-global-bibliography)
(setq org-cite-export-processors
- '((latex bibtex "numeric")))
+ '((latex bibtex "numeric")))
(setq citar-library-paths
- '("~/30-39 Life/33 Library/33.01 Documents/"))
+ '("~/30-39 Life/33 Library/33.01 Documents/"))
(add-hook 'latex-mode #'citar-capf-setup)
(add-hook 'org-mode #'citar-capf-setup))
@@ -5752,7 +5806,7 @@ Emacs is also particularly great at writing Lisp code, e.g. Clojure, Common Lisp
:straight (:files (:defaults "citeproc" (:exclude "*helm*")))
:if (not my/remote-server)
:commands (org-ref-insert-link-hydra/body
- org-ref-bibtex-hydra/body)
+ org-ref-bibtex-hydra/body)
:init
(setq bibtex-dialect 'biblatex)
(add-hook 'bibtex-mode 'smartparens-mode)
@@ -5765,8 +5819,8 @@ Emacs is also particularly great at writing Lisp code, e.g. Clojure, Common Lisp
:keymaps 'bibtex-mode-map
"M-RET" 'org-ref-bibtex-hydra/body)
(setq org-ref-insert-cite-function
- (lambda ()
- (call-interactively #'citar-insert-citation))))
+ (lambda ()
+ (call-interactively #'citar-insert-citation))))
Org Roam
org-roam is a plain-text knowledge database.
Things I tried with Org Roam:
@@ -5804,8 +5858,7 @@ Didn’t work out as I expected, so I’ve made org-journal-tags
About installing the package on Guix (CREDIT: thanks @Ashraz on the SystemCrafters discord)
So, for all those interested: unfortunately, org-roam (or rather emacsql-sqlite) cannot compile the sqlite.c and emacsql.c due to missing headers (linux/falloc.h) on Guix. You would have to properly set all the include paths on Guix, and also adjust the PATH to have gcc actually find as later on in the compilation process.
-Instead, you should remove all Org-Roam related packages from your Emacs installation (via M-x package-delete org-roam RET and M-x package-autoremove RET y RET) and then use the Guix package called emacs-org-roam.
-
+Instead, you should remove all Org-Roam related packages from your Emacs installation (via M-x package-delete org-roam RET and M-x package-autoremove RET y RET) and then use the Guix package called emacs-org-roam.
References:
- Hitchhiker’s Rough Guide to Org roam V2
@@ -5818,7 +5871,7 @@ Didn’t work out as I expected, so I’ve made org-journal-tags
(use-package org-roam
:straight (:host github :repo "org-roam/org-roam"
- :files (:defaults "extensions/*.el"))
+ :files (:defaults "extensions/*.el"))
:if (and
(not my/remote-server)
(file-directory-p org-roam-directory))
@@ -5834,14 +5887,14 @@ Didn’t work out as I expected, so I’ve made org-journal-tags
Capture templates for org-roam-capture. As for now, nothing too complicated here.
(setq org-roam-capture-templates
`(("d" "default" plain "%?"
- :target (file+head "%<%Y%m%d%H%M%S>-${slug}.org" "#+title: ${title}\n")
- :unnarrowed t)
- ("f" "fleeting" plain "%?"
- :target (file+head "%<%Y%m%d%H%M%S>-${slug}.org" "#+title: ${title}\n#+filetags: :fleeting:\n")
- :unnarrowed t)
- ("e" "encrypted" plain "%?"
- :target (file+head "%<%Y%m%d%H%M%S>-${slug}.org.gpg" "#+title: ${title}\n")
- :unnarrowed t)))
+ :target (file+head "%<%Y%m%d%H%M%S>-${slug}.org" "#+title: ${title}\n")
+ :unnarrowed t)
+ ("f" "fleeting" plain "%?"
+ :target (file+head "%<%Y%m%d%H%M%S>-${slug}.org" "#+title: ${title}\n#+filetags: :fleeting:\n")
+ :unnarrowed t)
+ ("e" "encrypted" plain "%?"
+ :target (file+head "%<%Y%m%d%H%M%S>-${slug}.org.gpg" "#+title: ${title}\n")
+ :unnarrowed t)))
org-roam-ql
org-roam-ql is a package to query org-roam files like org-ql.
(use-package org-roam-ql
@@ -5937,12 +5990,12 @@ Didn’t work out as I expected, so I’ve made org-journal-tags
(defun my/org-roam--count-overlay-make (pos count)
(let* ((overlay-value (concat
- " "
- (propertize
- (format "%d" count)
- 'face 'my/org-roam-count-overlay-face)
- " "))
- (ov (make-overlay pos pos (current-buffer) nil t)))
+ " "
+ (propertize
+ (format "%d" count)
+ 'face 'my/org-roam-count-overlay-face)
+ " "))
+ (ov (make-overlay pos pos (current-buffer) nil t)))
(overlay-put ov 'roam-backlinks-count count)
(overlay-put ov 'priority 1)
(overlay-put ov 'after-string overlay-value)))
@@ -5957,48 +6010,48 @@ Didn’t work out as I expected, so I’ve made org-journal-tags
(org-element-map (org-element-parse-buffer) 'link
(lambda (elem)
(when (string-equal (org-element-property :type elem) "id")
- (let* ((id (org-element-property :path elem))
- (count (caar
- (org-roam-db-query
- [:select (funcall count source)
- :from links
- :where (= dest $s1)
- :and (= type "id")]
- id))))
- (when (< 0 count)
- (my/org-roam--count-overlay-make
- (org-element-property :end elem)
- count)))))))
+ (let* ((id (org-element-property :path elem))
+ (count (caar
+ (org-roam-db-query
+ [:select (funcall count source)
+ :from links
+ :where (= dest $s1)
+ :and (= type "id")]
+ id))))
+ (when (< 0 count)
+ (my/org-roam--count-overlay-make
+ (org-element-property :end elem)
+ count)))))))
And a minor mode to toggle the display in a particular org-roam buffer.
(define-minor-mode my/org-roam-count-overlay-mode
"Display backlink count for org-roam links."
:after-hook
(if my/org-roam-count-overlay-mode
(progn
- (my/org-roam--count-overlay-make-all)
- (add-hook 'after-save-hook #'my/org-roam--count-overlay-make-all nil t))
+ (my/org-roam--count-overlay-make-all)
+ (add-hook 'after-save-hook #'my/org-roam--count-overlay-make-all nil t))
(my/org-roam--count-overlay-remove-all)
(remove-hook 'after-save-hook #'my/org-roam--count-overlay-remove-all t)))
Extract all links from page
(defun my/org-roam-extract-links ()
(interactive)
(let ((buffer (generate-new-buffer "*roam-links*"))
- elems)
+ elems)
(org-element-map (org-element-parse-buffer) 'link
(lambda (elem)
- (when (string-equal (org-element-property :type elem) "id")
- (push elem elems))))
+ (when (string-equal (org-element-property :type elem) "id")
+ (push elem elems))))
(with-current-buffer buffer
(cl-loop for elem in elems
- for file-name =
- (file-name-nondirectory
- (caar
- (org-roam-db-query
- [:select [file]
- :from nodes
- :where (= id $s1)]
- (org-element-property :path elem))))
- do (insert file-name "\n")))
+ for file-name =
+ (file-name-nondirectory
+ (caar
+ (org-roam-db-query
+ [:select [file]
+ :from nodes
+ :where (= id $s1)]
+ (org-element-property :path elem))))
+ do (insert file-name "\n")))
(switch-to-buffer buffer)))
Org Roam UI
A browser frontend to visualize the Roam database as a graph.
@@ -6024,7 +6077,7 @@ Didn’t work out as I expected, so I’ve made org-journal-tags
(setq deft-recursive t)
(setq deft-use-filter-string-for-filename t)
(add-hook 'deft-mode-hook
- (lambda () (display-line-numbers-mode -1)))
+ (lambda () (display-line-numbers-mode -1)))
(general-define-key
:keymaps 'deft-mode-map
:states '(normal motion)
@@ -6038,9 +6091,9 @@ Didn’t work out as I expected, so I’ve made org-journal-tags
The default deft view does not look that great because of various Roam metadata. To improve that, we can tweak deft-strip-summary-regexp:
(setq deft-strip-summary-regexp
(rx (or
- (: ":PROPERTIES:" (* anything) ":END:")
- (: "#+" (+ alnum) ":" (* nonl))
- (regexp "[\n\t]"))))
+ (: ":PROPERTIES:" (* anything) ":END:")
+ (: "#+" (+ alnum) ":" (* nonl))
+ (regexp "[\n\t]"))))
And advise deft-parse-summary to filter out Org links:
(defun my/deft-parse-summary-around (fun contents title)
(funcall fun (org-link-display-format contents) title))
@@ -6053,7 +6106,7 @@ Didn’t work out as I expected, so I’ve made org-journal-tags
(insert contents)
(goto-char (point-min))
(if (search-forward-regexp (rx (| "#+title:" "#+TITLE:")) nil t)
- (string-trim (buffer-substring-no-properties (point) (line-end-position)))
+ (string-trim (buffer-substring-no-properties (point) (line-end-position)))
file)))
(defun my/deft-parse-title-around (fun file contents)
@@ -6091,22 +6144,22 @@ Didn’t work out as I expected, so I’ve made org-journal-tags
First, as I have autocommit set up in my org directory, here is a function to get an alist of changed files in a form (status . path). The rev parameter can be a commit, tag, etc. but here I’m interested in the date form (e.g. @{2021-08-30}).
(setq my/git-diff-status
'(("A" . added)
- ("C" . copied)
- ("D" . deleted)
- ("M" . modified)
- ("R" . renamed)
- ("R100" . moved)
- ("T" . type-changed)
- ("U" . unmerged)))
+ ("C" . copied)
+ ("D" . deleted)
+ ("M" . modified)
+ ("R" . renamed)
+ ("R100" . moved)
+ ("T" . type-changed)
+ ("U" . unmerged)))
(defun my/get-files-status (rev)
(let ((files (shell-command-to-string (concat "git diff --name-status " rev))))
(mapcar
(lambda (file)
(let ((elems (split-string file "\t")))
- (cons
- (cdr (assoc (car elems) my/git-diff-status))
- (car (last elems)))))
+ (cons
+ (cdr (assoc (car elems) my/git-diff-status))
+ (car (last elems)))))
(split-string files "\n" t))))
I’ll use it to get a list of added and changed files in the Org directory since the last review. The date should be in a format YYYY-MM-DD.
(defun my/org-changed-files-since-date (date)
@@ -6114,68 +6167,108 @@ Didn’t work out as I expected, so I’ve made org-journal-tags
(my/get-files-status (format "@{%s}" date))))
Data from org-roam
I’ll use data from git to get the list of what I’ve been working on. The directories include org-roam itself and inbox-notes, where my in-process notes live.
-(defun my/org-review-format-org-roam (date)
+(defun my/org-review--org-roam-get-changes (date)
(let ((changes (my/org-changed-files-since-date date))
- (nodes (org-roam-node-list))
- (nodes-by-file (make-hash-table :test #'equal)))
+ (nodes (org-roam-node-list))
+ (nodes-by-file (make-hash-table :test #'equal)))
(cl-loop for node in nodes
- for file = (org-roam-node-file node)
- do (puthash file node nodes-by-file))
+ for file = (org-roam-node-file node)
+ do (puthash file node nodes-by-file))
+ (let* ((changed-nodes
+ (thread-last
+ changes
+ (mapcar (lambda (c)
+ (cons (car c)
+ (gethash
+ (concat org-directory "/" (cdr c))
+ nodes-by-file))))
+ (seq-filter #'cdr)))
+ (changed-inbox
+ (thread-last
+ changes
+ (seq-filter
+ (lambda (file) (string-match-p (rx bos "inbox-notes") (cdr file))))))
+ (changed-fleeting
+ (thread-last
+ changed-nodes
+ (seq-filter (lambda (c)
+ (seq-contains-p (org-roam-node-tags (cdr c))
+ "fleeting")))
+ (seq-sort-by (lambda (c) (concat (symbol-name (car c))
+ (org-roam-node-title (cdr c))))
+ #'string-lessp)))
+ (changed-permanent
+ (thread-last
+ changed-nodes
+ (seq-filter (lambda (c)
+ (not (seq-contains-p (org-roam-node-tags (cdr c))
+ "fleeting"))))
+ (seq-sort-by (lambda (c) (concat (symbol-name (car c))
+ (org-roam-node-title (cdr c))))
+ #'string-lessp))))
+ (list
+ changed-inbox
+ changed-fleeting
+ changed-permanent))))
+
+(defun my/org-review-org-roam-format (date)
+ (let* ((data (my/org-review--org-roam-get-changes date))
+ (changed-inbox (nth 0 data))
+ (changed-fleeting (nth 1 data))
+ (changed-permanent (nth 2 data)))
(concat
- "*** Zettelkasten Updates\n"
- "TODO Sort the updates by topics\n\n"
"Changes in inbox:\n"
(thread-last
- changes
- (seq-filter
- (lambda (file) (string-match-p (rx bos "inbox-notes") (cdr file))))
- (seq-sort-by (lambda (s) (symbol-name (car s)))
- #'string-lessp)
+ changed-inbox
(mapcar (lambda (change)
- (format "- %s :: %s\n"
- (cond
- ((or (member (car change) '(deleted moved))
- (string-match-p "figured-out" (cdr change)))
- "Processed")
- (t (capitalize (symbol-name (car change)))))
- (cdr change))))
+ (format "- %s :: %s\n"
+ (cond
+ ((or (member (car change) '(deleted moved))
+ (string-match-p "figured-out" (cdr change)))
+ "Processed")
+ (t (capitalize (symbol-name (car change)))))
+ (cdr change))))
(apply #'concat))
- "\nChanges in notes:\n"
+ "\nChanges in fleeting notes:\n"
(thread-last
- changes
+ changed-fleeting
(mapcar (lambda (c)
- (cons (car c)
- (gethash
- (concat org-directory "/" (cdr c))
- nodes-by-file))))
- (seq-filter #'cdr)
- (seq-sort-by (lambda (c) (concat (symbol-name (car c))
- (org-roam-node-title (cdr c))))
- #'string-lessp)
+ (format "- %s :: [[id:%s][%s]]\n"
+ (capitalize (symbol-name (car c)))
+ (org-roam-node-id (cdr c))
+ (org-roam-node-title (cdr c)))))
+ (apply #'concat))
+ "\nChanges in permanent notes:\n"
+ (thread-last
+ changed-permanent
(mapcar (lambda (c)
- (format "- %s :: [[id:%s][%s]]\n"
- (capitalize (symbol-name (car c)))
- (org-roam-node-id (cdr c))
- (org-roam-node-title (cdr c)))))
+ (format "- %s :: [[id:%s][%s]]\n"
+ (capitalize (symbol-name (car c)))
+ (org-roam-node-id (cdr c))
+ (org-roam-node-title (cdr c)))))
(apply #'concat)))))
General review logic
(defun my/org-review-get-last-review-date (kind)
(let* ((start-of-day (- (time-convert nil #'integer)
- (% (time-convert nil #'integer)
- (* 24 60 60))))
- (query-res (org-journal-tags-query
- :tag-names (list (format "review.%s" kind))
- :start-date (pcase kind
- ('weekly
- (- start-of-day
- (* 21 24 60 60)))
- (_ (error "Unsupported kind: %s" kind)))
- :location 'section
- :order 'descending)))
+ (% (time-convert nil #'integer)
+ (* 24 60 60))))
+ (query-res (org-journal-tags-query
+ :tag-names (list (format "review.%s" kind))
+ :start-date (pcase kind
+ ('weekly
+ (- start-of-day
+ (* 21 24 60 60)))
+ ('zk
+ (- start-of-day
+ (* 45 24 60 60)))
+ (_ (error "Unsupported kind: %s" kind)))
+ :location 'section
+ :order 'descending)))
(if query-res
- (org-journal-tag-reference-date (car query-res))
+ (org-journal-tag-reference-date (car query-res))
(pcase kind
- ('weekly (- start-of-day (* 7 24 60 60)))))))
+ ('weekly (- start-of-day (* 7 24 60 60)))
+ ('zk (- start-of-day (* 45 24 60 60)))))))
Weekly review
(defun my/org-review-set-weekly-record ()
(save-excursion
@@ -6185,12 +6278,12 @@ Didn’t work out as I expected, so I’ve made org-journal-tags
(goto-char (point-max))
(insert "Last review date: "
- (format-time-string
- "[%Y-%m-%d]"
- (seconds-to-time last-review-date)))
+ (format-time-string
+ "[%Y-%m-%d]"
+ (seconds-to-time last-review-date)))
(insert "
-Review checklist:
+Review checklist (/delete this/):
- [ ] Clear email inbox
- [ ] Reconcile ledger
- [ ] Clear [[file:~/Downloads][downloads]] and [[file:~/00-Scratch][scratch]] folders
@@ -6207,8 +6300,6 @@ Didn’t work out as I expected, so I’ve made org-journal-tags
- [ ] Review journal records
")
- (insert (my/org-review-format-org-roam
- (format-time-string "%Y-%m-%d" (seconds-to-time last-review-date))))
(insert "
*** Summary
TODO Write something, maybe? "))))
@@ -6216,8 +6307,8 @@ Didn’t work out as I expected, so I’ve made org-journal-tags
(defun my/org-review-weekly ()
(interactive)
(let ((org-journal-after-entry-create-hook
- `(,@org-journal-after-entry-create-hook
- my/org-review-set-weekly-record)))
+ `(,@org-journal-after-entry-create-hook
+ my/org-review-set-weekly-record)))
(org-journal-new-entry nil)
(org-fold-show-subtree)))
(with-eval-after-load 'org-journal
@@ -6233,12 +6324,17 @@ Didn’t work out as I expected, so I’ve made org-journal-tags
(call-process-shell-command "pkill -f 'bwrap --args 36 element'")
(call-process-shell-command "pkill -f element-desktop"))
(defun my/org-review-set-daily-record ()
- (save-excursion
- (org-journal-tags-prop-apply-delta :add '("review.daily"))
- (insert "Daily Review")
- (goto-char (point-max))
+ (let* ((today (format-time-string
+ "%Y-%m-%d"
+ (days-to-time
+ (- (org-today) (time-to-days 0)))))
+ (roam-changes (my/org-review--org-roam-get-changes today)))
+ (save-excursion
+ (org-journal-tags-prop-apply-delta :add '("review.daily"))
+ (insert "Daily Review")
+ (goto-char (point-max))
- (insert "
+ (insert "
Maintenance checklist (/delete this/):
- [ ] [[elisp:(my/kill-messengers)][Close all messengers]]
- [ ] Process [[file:../inbox.org][inbox]]
@@ -6257,22 +6353,117 @@ Didn’t work out as I expected, so I’ve made org-journal-tags
*** New ideas
/Write them down in org-roam with the \"fleeting\" tag; leave links here. Perhaps note what sparked that idea?/
-
+"
+ (thread-last
+ (nth 1 roam-changes)
+ (seq-filter (lambda (c) (eq 'added (car c))))
+ (mapcar (lambda (c)
+ (format "- [[id:%s][%s]]\n"
+ (org-roam-node-id (cdr c))
+ (org-roam-node-title (cdr c)))))
+ (apply #'concat))
+ "
*** Interactions today
/Any meaninginful interactions, conflicts or tensions?/
*** Emotions today
/How did I feel?/
-")))
+"))))
(defun my/org-review-daily ()
(interactive)
(let ((org-journal-after-entry-create-hook
- `(,@org-journal-after-entry-create-hook
- my/org-review-set-daily-record)))
+ `(,@org-journal-after-entry-create-hook
+ my/org-review-set-daily-record)))
(org-journal-new-entry nil)
(org-fold-show-subtree)))
(with-eval-after-load 'org-journal
(my-leader-def "ojd" #'my/org-review-daily))
+
ZK review
+Mostly incorporating or discarding my fleeting notes here.
+This function formats the list of notes to review:
+(defun my/org-review-org-roam-format-zk-before (date)
+ (let* ((data (my/org-review--org-roam-get-changes date))
+ (changed-inbox (nth 0 data))
+ (changed-fleeting (nth 1 data))
+ (changed-permanent (nth 2 data)))
+ (concat
+ (when changed-inbox
+ (concat
+ "Process these changes in inbox:\n"
+ (thread-last
+ changed-inbox
+ (mapcar (lambda (change)
+ (format "- [ ] %s :: %s\n"
+ (cond
+ ((or (member (car change) '(deleted moved))
+ (string-match-p "figured-out" (cdr change)))
+ "Processed")
+ (t (capitalize (symbol-name (car change)))))
+ (cdr change))))
+ (apply #'concat))
+ "\n"))
+ (when changed-fleeting
+ (concat
+ "Process these fleeting notes:\n"
+ (thread-last
+ changed-fleeting
+ (mapcar (lambda (c)
+ (format "- [ ] %s :: [[id:%s][%s]]\n"
+ (capitalize (symbol-name (car c)))
+ (org-roam-node-id (cdr c))
+ (org-roam-node-title (cdr c)))))
+ (apply #'concat))
+ "\n"))
+ (when changed-permanent
+ (concat
+ "Check these changes in permanent notes:\n"
+ (thread-last
+ changed-permanent
+ (mapcar (lambda (c)
+ (format "- [ ] %s :: [[id:%s][%s]]\n"
+ (capitalize (symbol-name (car c)))
+ (org-roam-node-id (cdr c))
+ (org-roam-node-title (cdr c)))))
+ (apply #'concat)))))))
+
(defun my/org-review-org-roam-finish (date)
+ (org-roam-db-sync)
+ (save-excursion
+ (org-back-to-heading)
+ (replace-regexp
+ (rx
+ ":BEGIN_REVIEW:" (* anything) ":END_REVIEW:")
+ (string-trim
+ (my/org-review-org-roam-format date)))))
+
(defun my/org-review-set-zk-record ()
+ (save-excursion
+ (let ((last-review-date (my/org-review-get-last-review-date 'zk)))
+ (org-journal-tags-prop-apply-delta :add '("review.zk"))
+ (insert "Zettelkasten Review")
+ (goto-char (point-max))
+
+ (insert "Last review date: "
+ (format-time-string
+ "[%Y-%m-%d]"
+ (seconds-to-time last-review-date)))
+
+ (insert "\n\n:BEGIN_REVIEW:\n"
+ "Process all the required categories in this block, then execute \"Finish review\".\n\n"
+ (string-trim
+ (my/org-review-org-roam-format-zk-before last-review-date))
+ "\n\n[[elisp:(my/org-review-org-roam-finish \""
+ (format-time-string "%Y-%m-%d" last-review-date)
+ "\")][Finish review]]"
+ "\n:END_REVIEW:\n"))))
+
(defun my/org-review-zk ()
+ (interactive)
+ (let ((org-journal-after-entry-create-hook
+ `(,@org-journal-after-entry-create-hook
+ my/org-review-set-zk-record)))
+ (org-journal-new-entry nil)
+ (org-fold-show-subtree)))
+
+(with-eval-after-load 'org-journal
+ (my-leader-def "ojz" #'my/org-review-zk))
Contacts
org-contacts is a package to store contacts in an org file.
It seems the package has been somewhat revived in the recent months. It used things like lexical-let when I first found it.
@@ -6282,7 +6473,7 @@ Didn’t work out as I expected, so I’ve made org-journal-tags
:after (org)
:config
(setq org-contacts-files (list
- (concat org-directory "/contacts.org"))))
+ (concat org-directory "/contacts.org"))))
An example contact entry can look like this:
* Pavel Korytov
:PROPERTIES:
@@ -6366,8 +6557,8 @@ Didn’t work out as I expected, so I’ve made org-journal-tags
(with-eval-after-load 'org-ref
(setq org-ref-csl-default-locale "ru-RU")
(setq org-ref-csl-default-style (expand-file-name
- (concat user-emacs-directory
- "gost-r-7-0-5-2008-numeric.csl"))))
+ (concat user-emacs-directory
+ "gost-r-7-0-5-2008-numeric.csl"))))
LaTeX
Add a custom LaTeX template without default packages. Packages are indented to be imported with function from Import *.sty.
(defun my/setup-org-latex ()
@@ -6376,47 +6567,47 @@ Didn’t work out as I expected, so I’ve made org-journal-tags
(setq org-latex-pdf-process '("latexmk -outdir=%o %f")) ;; Use latexmk
(setq org-latex-listings 'minted) ;; Use minted to highlight source code
(setq org-latex-minted-options ;; Some minted options I like
- '(("breaklines" "true")
- ("tabsize" "4")
- ("autogobble")
- ("linenos")
- ("numbersep" "0.5cm")
- ("xleftmargin" "1cm")
- ("frame" "single")))
+ '(("breaklines" "true")
+ ("tabsize" "4")
+ ("autogobble")
+ ("linenos")
+ ("numbersep" "0.5cm")
+ ("xleftmargin" "1cm")
+ ("frame" "single")))
;; Use extarticle without the default packages
(add-to-list 'org-latex-classes
- '("org-plain-extarticle"
- "\\documentclass{extarticle}
+ '("org-plain-extarticle"
+ "\\documentclass{extarticle}
[NO-DEFAULT-PACKAGES]
[PACKAGES]
[EXTRA]"
- ("\\section{%s}" . "\\section*{%s}")
- ("\\subsection{%s}" . "\\subsection*{%s}")
- ("\\subsubsection{%s}" . "\\subsubsection*{%s}")
- ("\\paragraph{%s}" . "\\paragraph*{%s}")
- ("\\subparagraph{%s}" . "\\subparagraph*{%s}")))
+ ("\\section{%s}" . "\\section*{%s}")
+ ("\\subsection{%s}" . "\\subsection*{%s}")
+ ("\\subsubsection{%s}" . "\\subsubsection*{%s}")
+ ("\\paragraph{%s}" . "\\paragraph*{%s}")
+ ("\\subparagraph{%s}" . "\\subparagraph*{%s}")))
(add-to-list 'org-latex-classes
- '("org-plain-extreport"
- "\\documentclass{extreport}
+ '("org-plain-extreport"
+ "\\documentclass{extreport}
[NO-DEFAULT-PACKAGES]
[PACKAGES]
[EXTRA]"
- ("\\chapter{%s}" . "\\chapter*{%s}")
- ("\\section{%s}" . "\\section*{%s}")
- ("\\subsection{%s}" . "\\subsection*{%s}")
- ("\\subsubsection{%s}" . "\\subsubsection*{%s}")
- ("\\paragraph{%s}" . "\\paragraph*{%s}")))
+ ("\\chapter{%s}" . "\\chapter*{%s}")
+ ("\\section{%s}" . "\\section*{%s}")
+ ("\\subsection{%s}" . "\\subsection*{%s}")
+ ("\\subsubsection{%s}" . "\\subsubsection*{%s}")
+ ("\\paragraph{%s}" . "\\paragraph*{%s}")))
;; Use beamer without the default packages
(add-to-list 'org-latex-classes
- '("org-latex-beamer"
- "\\documentclass{beamer}
+ '("org-latex-beamer"
+ "\\documentclass{beamer}
[NO-DEFAULT-PACKAGES]
[PACKAGES]
[EXTRA]"
- ("beamer" "\\documentclass[presentation]{beamer}"
- ("\\section{%s}" . "\\section*{%s}")
- ("\\subsection{%s}" . "\\subsection*{%s}")
- ("\\subsubsection{%s}" . "\\subsubsection*{%s}")))))
+ ("beamer" "\\documentclass[presentation]{beamer}"
+ ("\\section{%s}" . "\\section*{%s}")
+ ("\\subsection{%s}" . "\\subsection*{%s}")
+ ("\\subsubsection{%s}" . "\\subsubsection*{%s}")))))
;; Make sure to eval the function when org-latex-classes list already exists
(with-eval-after-load 'ox-latex
@@ -6425,14 +6616,14 @@ Didn’t work out as I expected, so I’ve made org-journal-tags
No idea why, but somehow the exported file uses english words if there isn’t :default key in the dictionary.
(with-eval-after-load 'ox
(setq org-export-dictionary
- (cl-loop for item in org-export-dictionary collect
- (cons
- (car item)
- (cl-loop for entry in (cdr item)
- if (and (equal (car entry) "ru")
- (plist-get (cdr entry) :utf-8))
- collect (list "ru" :default (plist-get (cdr entry) :utf-8))
- else collect entry)))))
+ (cl-loop for item in org-export-dictionary collect
+ (cons
+ (car item)
+ (cl-loop for entry in (cdr item)
+ if (and (equal (car entry) "ru")
+ (plist-get (cdr entry) :utf-8))
+ collect (list "ru" :default (plist-get (cdr entry) :utf-8))
+ else collect entry)))))
System configuration
Functions related to literate configuration.
Tables for Guix Dependencies
@@ -6478,49 +6669,49 @@ Didn’t work out as I expected, so I’ve made org-journal-tags
(org-table-map-tables
(lambda ()
(let* ((table
- (seq-filter
- (lambda (q) (not (eq q 'hline)))
- (org-table-to-lisp)))
- (dep-name-index
- (cl-position
- nil
- (mapcar #'substring-no-properties (nth 0 table))
- :test (lambda (_ elem)
- (string-match-p "[G|g]uix.*dep" elem))))
- (category-name-index
- (cl-position
- nil
- (mapcar #'substring-no-properties (nth 0 table))
- :test (lambda (_ elem)
- (string-match-p ".*[C|c]ategory.*" elem))))
- (disabled-name-index
- (cl-position
- nil
- (mapcar #'substring-no-properties (nth 0 table))
- :test (lambda (_ elem)
- (string-match-p ".*[D|d]isabled.*" elem)))))
- (when dep-name-index
- (dolist (elem (cdr table))
- (when
- (and
- ;; Category
- (or
- ;; Category not set and not present in the table
- (and
- (or (not category) (string-empty-p category))
- (not category-name-index))
- ;; Category is set and present in the table
- (and
- category-name-index
- (not (string-empty-p category))
- (string-match-p category (nth category-name-index elem))))
- ;; Not disabled
- (or
- (not disabled-name-index)
- (string-empty-p (nth disabled-name-index elem))))
- (add-to-list
- 'dependencies
- (substring-no-properties (nth dep-name-index elem)))))))))
+ (seq-filter
+ (lambda (q) (not (eq q 'hline)))
+ (org-table-to-lisp)))
+ (dep-name-index
+ (cl-position
+ nil
+ (mapcar #'substring-no-properties (nth 0 table))
+ :test (lambda (_ elem)
+ (string-match-p "[G|g]uix.*dep" elem))))
+ (category-name-index
+ (cl-position
+ nil
+ (mapcar #'substring-no-properties (nth 0 table))
+ :test (lambda (_ elem)
+ (string-match-p ".*[C|c]ategory.*" elem))))
+ (disabled-name-index
+ (cl-position
+ nil
+ (mapcar #'substring-no-properties (nth 0 table))
+ :test (lambda (_ elem)
+ (string-match-p ".*[D|d]isabled.*" elem)))))
+ (when dep-name-index
+ (dolist (elem (cdr table))
+ (when
+ (and
+ ;; Category
+ (or
+ ;; Category not set and not present in the table
+ (and
+ (or (not category) (string-empty-p category))
+ (not category-name-index))
+ ;; Category is set and present in the table
+ (and
+ category-name-index
+ (not (string-empty-p category))
+ (string-match-p category (nth category-name-index elem))))
+ ;; Not disabled
+ (or
+ (not disabled-name-index)
+ (string-empty-p (nth disabled-name-index elem))))
+ (add-to-list
+ 'dependencies
+ (substring-no-properties (nth dep-name-index elem)))))))))
dependencies))
To make it work in the configuration, it is necessary to format the list so that Scheme could read it:
(defun my/format-guix-dependencies (&optional category)
@@ -6550,15 +6741,15 @@ Didn’t work out as I expected, so I’ve made org-journal-tags
(mapcar
#'expand-file-name
'("~/Emacs.org"
- "~/Desktop.org"
- "~/Console.org"
- "~/Guix.org"
- "~/Mail.org")))
+ "~/Desktop.org"
+ "~/Console.org"
+ "~/Guix.org"
+ "~/Mail.org")))
(add-hook 'org-mode-hook
- (lambda ()
- (when (member (buffer-file-name) my/org-config-files)
- (setq-local org-confirm-babel-evaluate nil))))
+ (lambda ()
+ (when (member (buffer-file-name) my/org-config-files)
+ (setq-local org-confirm-babel-evaluate nil))))
yadm hook
A script to run tangle from CLI.
(require 'org)
@@ -6583,11 +6774,11 @@ Didn’t work out as I expected, so I’ve made org-journal-tags
(setq-local comment-start-skip "#+ *"))
(mapcar #'org-babel-tangle-file
- '("/home/pavel/Emacs.org"
- "/home/pavel/Desktop.org"
- "/home/pavel/Console.org"
- "/home/pavel/Guix.org"
- "/home/pavel/Mail.org"))
+ '("/home/pavel/Emacs.org"
+ "/home/pavel/Desktop.org"
+ "/home/pavel/Console.org"
+ "/home/pavel/Guix.org"
+ "/home/pavel/Mail.org"))
To launch from CLI, run:
emacs -Q --batch -l run-tangle.el
I have added this line to yadm’s post_alt hook, so to run tangle after yadm alt
@@ -6603,7 +6794,7 @@ Didn’t work out as I expected, so I’ve made org-journal-tags
(call-process "herd" nil nil nil "restart" "xsettingsd")
(when (fboundp #'my/exwm-set-alpha)
(if (my/light-p)
- (my/exwm-set-alpha 100)
+ (my/exwm-set-alpha 100)
(my/exwm-set-alpha 90))))
Applications
Dired
@@ -6623,9 +6814,9 @@ Didn’t work out as I expected, so I’ve made org-journal-tags
(setq dired-recursive-deletes 'always)
(setq dired-kill-when-opening-new-dired-buffer t)
(add-hook 'dired-mode-hook
- (lambda ()
- (setq truncate-lines t)
- (visual-line-mode nil)))
+ (lambda ()
+ (setq truncate-lines t)
+ (visual-line-mode nil)))
(when my/is-termux
(add-hook 'dired-mode-hook #'dired-hide-details-mode))
@@ -6673,8 +6864,8 @@ Didn’t work out as I expected, so I’ve made org-journal-tags
(if (not current-prefix-arg)
(dired-sidebar-toggle-sidebar)
(let ((dired-sidebar-follow-file-at-point-on-toggle-open
- current-prefix-arg)
- (current-prefix-arg nil))
+ current-prefix-arg)
+ (current-prefix-arg nil))
(dired-sidebar-toggle-sidebar))))
(use-package dired-sidebar
@@ -6686,7 +6877,7 @@ Didn’t work out as I expected, so I’ve made org-journal-tags
(general-define-key
:keymaps '(normal override global)
"C-n" `(my/dired-sidebar-toggle
- :wk "dired-sidebar"))
+ :wk "dired-sidebar"))
:config
(setq dired-sidebar-width 45)
(defun my/dired-sidebar-setup ()
@@ -6732,15 +6923,15 @@ Didn’t work out as I expected, so I’ve made org-journal-tags
:after (dired)
:if (display-graphic-p)
:hook (dired-mode . (lambda ()
- (unless (string-match-p "/gnu/store" default-directory)
- (all-the-icons-dired-mode)))))
+ (unless (string-match-p "/gnu/store" default-directory)
+ (all-the-icons-dired-mode)))))
(use-package nerd-icons-dired
:straight t
:after (dired)
:hook (dired-mode . (lambda ()
- (unless (or (file-remote-p default-directory)
- (string-match-p "/gnu/store" default-directory))
- (nerd-icons-dired-mode))))
+ (unless (or (file-remote-p default-directory)
+ (string-match-p "/gnu/store" default-directory))
+ (nerd-icons-dired-mode))))
:config
(advice-add #'dired-create-empty-file :around #'nerd-icons-dired--refresh-advice))
Provides stuff like dired-open-xdg
@@ -6780,9 +6971,9 @@ Didn’t work out as I expected, so I’ve made org-journal-tags
dired-rsync allows using rsync instead of the default synchronous copy operation. The only trouble is that it doesn’t replace dired-do-copy completely, so…
(defun my/dired-rsync--refresh ()
(cl-loop for window being the windows
- do (with-current-buffer (window-buffer window)
- (when (derived-mode-p 'dired-mode)
- (revert-buffer)))))
+ do (with-current-buffer (window-buffer window)
+ (when (derived-mode-p 'dired-mode)
+ (revert-buffer)))))
(use-package dired-rsync
:straight t
@@ -6844,7 +7035,25 @@ Didn’t work out as I expected, so I’ve made org-journal-tags
(when (executable-find "xdg-open")
(let ((file (ignore-errors (dired-get-file-for-visit))))
(start-process "dired-open" nil
- "xdg-open" (file-truename file)))))
+ "xdg-open" (file-truename file)))))
+
Run a command on the marked files. Unlike dired-do-async-shell-command, this uses start-process instead of shell-command, which prevents the output buffer from popping up.
+(defun my/dired-do-async-shell-command (command &optional arg file-list)
+ (interactive
+ (let ((files (dired-get-marked-files t current-prefix-arg nil nil t)))
+ (list
+ ;; Want to give feedback whether this file or marked files are used:
+ (dired-read-shell-command "& on %s: " current-prefix-arg files)
+ current-prefix-arg
+ files)))
+ (start-process-shell-command
+ "*Dired Command*" nil
+ (dired-shell-stuff-it command file-list arg)))
+
+(with-eval-after-load 'dired
+ (general-define-key
+ :states '(normal insert)
+ :keymaps '(dired-mode-map)
+ "&" #'my/dired-do-async-shell-command))
Bookmarks
A simple bookmark list for Dired, mainly to use with TRAMP. I may look into a proper bookmarking system later.
Bookmarks are listed in the private.el file, which has an expression like this:
@@ -6855,9 +7064,9 @@ Didn’t work out as I expected, so I’ve made org-journal-tags
(defun my/dired-bookmark-open ()
(interactive)
(let ((bookmarks
- (mapcar
- (lambda (el) (cons (format "%-30s %s" (car el) (cdr el)) (cdr el)))
- my/dired-bookmarks)))
+ (mapcar
+ (lambda (el) (cons (format "%-30s %s" (car el) (cdr el)) (cdr el)))
+ my/dired-bookmarks)))
(dired
(cdr
(assoc
@@ -6873,25 +7082,25 @@ Didn’t work out as I expected, so I’ve made org-journal-tags
if (eq (buffer-local-value 'major-mode buf) buffer-major-mode)
collect buf into all-buffers
if (and (eq (buffer-local-value 'major-mode buf) buffer-major-mode)
- (get-buffer-window buf t))
+ (get-buffer-window buf t))
collect buf into visible-buffers
finally return (if (= (length visible-buffers) 1)
- (car visible-buffers)
- (if (= (length all-buffers) 1)
- (car all-buffers)
- (when-let ((buffers-by-name (mapcar (lambda (b)
- (cons (buffer-name b) b))
- all-buffers)))
- (cdr
- (assoc
- (completing-read prompt buffers-by-name nil t)
- buffers-by-name))))))
+ (car visible-buffers)
+ (if (= (length all-buffers) 1)
+ (car all-buffers)
+ (when-let ((buffers-by-name (mapcar (lambda (b)
+ (cons (buffer-name b) b))
+ all-buffers)))
+ (cdr
+ (assoc
+ (completing-read prompt buffers-by-name nil t)
+ buffers-by-name))))))
(user-error "No buffer found!")))
Attach file to telega.
(defun my/dired-attach-to-telega (files telega-buffer)
(interactive
(list (dired-get-marked-files nil nil #'dired-nondirectory-p)
- (my/get-good-buffer 'telega-chat-mode "Telega buffer: ")))
+ (my/get-good-buffer 'telega-chat-mode "Telega buffer: ")))
(unless files
(user-error "No (non-directory) files selected"))
(with-current-buffer telega-buffer
@@ -6901,13 +7110,13 @@ Didn’t work out as I expected, so I’ve made org-journal-tags
(defun my/telega-save-to-dired (msg arg)
(interactive
(list (telega-msg-for-interactive)
- (prefix-numeric-value current-prefix-arg)))
+ (prefix-numeric-value current-prefix-arg)))
(if (eq arg 4)
(progn
- (setq telega-msg-save-dir
- (with-current-buffer (my/get-good-buffer 'dired-mode "Dired buffer: ")
- (dired-current-directory)))
- (telega-msg-save msg))
+ (setq telega-msg-save-dir
+ (with-current-buffer (my/get-good-buffer 'dired-mode "Dired buffer: ")
+ (dired-current-directory)))
+ (telega-msg-save msg))
(setq default-directory (expand-file-name "~"))
(setq telega-msg-save-dir nil)
(telega-msg-save msg)))
@@ -6915,58 +7124,58 @@ Didn’t work out as I expected, so I’ve made org-journal-tags
(defun my/dired-attach-to-notmuch (files notmuch-buffer)
(interactive
(list (dired-get-marked-files nil nil #'dired-nondirectory-p)
- (my/get-good-buffer 'notmuch-message-mode "Notmuch message buffer: ")))
+ (my/get-good-buffer 'notmuch-message-mode "Notmuch message buffer: ")))
(unless files
(user-error "No (non-directory) files selected"))
(with-current-buffer notmuch-buffer
(goto-char (point-max))
(dolist (file files)
(let ((type
- (or (mm-default-file-type file)
- "application/octet-stream")))
- (mml-attach-file
- file
- type
- (mml-minibuffer-read-description)
- (mml-minibuffer-read-disposition type nil file))))))
+ (or (mm-default-file-type file)
+ "application/octet-stream")))
+ (mml-attach-file
+ file
+ type
+ (mml-minibuffer-read-description)
+ (mml-minibuffer-read-disposition type nil file))))))
Save a notmuch file to a dired buffer.
(defun my/notmuch-save-to-dired (arg)
(interactive
(list (prefix-numeric-value current-prefix-arg)))
(if (eq arg 4)
(let ((default-directory
- (with-current-buffer (my/get-good-buffer 'dired-mode "Dired buffer: ")
- (dired-current-directory))))
- (notmuch-show-save-part))
+ (with-current-buffer (my/get-good-buffer 'dired-mode "Dired buffer: ")
+ (dired-current-directory))))
+ (notmuch-show-save-part))
(notmuch-show-save-part)))
Attach files to ement.
(defun my/dired-attach-to-ement (files ement-buffer)
(interactive
(list (dired-get-marked-files nil nil #'dired-nondirectory-p)
- (my/get-good-buffer 'ement-room-mode "Ement room buffer: ")))
+ (my/get-good-buffer 'ement-room-mode "Ement room buffer: ")))
(unless files
(user-error "No (non-directory) files selected"))
(with-current-buffer ement-buffer
(ement-with-room-and-session
(dolist (file files)
- (ement-room-send-file
- file
- (read-from-minibuffer (format "Message body for %s: " file))
- ement-room
- ement-session)))))
+ (ement-room-send-file
+ file
+ (read-from-minibuffer (format "Message body for %s: " file))
+ ement-room
+ ement-session)))))
Attach files to mastodon.
(defun my/dired-attach-to-mastodon (files mastodon-buffer)
(interactive
(list (dired-get-marked-files nil nil #'dired-nondirectory-p)
- (or (cl-loop for buf being the buffers
- if (eq (buffer-local-value 'mastodon-toot-mode buf) t)
- return buf)
- (user-error "No buffer found!"))))
+ (or (cl-loop for buf being the buffers
+ if (eq (buffer-local-value 'mastodon-toot-mode buf) t)
+ return buf)
+ (user-error "No buffer found!"))))
(unless files
(user-error "No (non-directory) files selected"))
(with-current-buffer mastodon-buffer
(dolist (file files)
- (mastodon-toot--attach-media
+ (mastodon-toot-attach-media
file
(read-from-minibuffer (format "Description for %s: " file))))))
And the keybindings:
@@ -6995,13 +7204,13 @@ Didn’t work out as I expected, so I’ve made org-journal-tags
(setq remote-file-name-inhibit-cache nil)
(setq vc-ignore-dir-regexp
(format "\\(%s\\)\\|\\(%s\\)"
- vc-ignore-dir-regexp
- tramp-file-name-regexp))
+ vc-ignore-dir-regexp
+ tramp-file-name-regexp))
Also, a hack to make TRAMP find ls on Guix:
(with-eval-after-load 'tramp
(setq tramp-remote-path
- (append tramp-remote-path
- '(tramp-own-remote-path))))
+ (append tramp-remote-path
+ '(tramp-own-remote-path))))
Set the default shell to bin/bash for TRAMP or on a remote server.
(when (or my/remote-server)
(setq explicit-shell-file-name "/bin/bash"))
@@ -7030,9 +7239,9 @@ Didn’t work out as I expected, so I’ve made org-journal-tags
(with-eval-after-load 'editorconfig
(advice-add #'editorconfig-apply :around #'my/tramp-void-if-tramp)
(advice-add #'editorconfig--disabled-for-filename
- :around #'my/tramp-void-if-file-is-tramp)
+ :around #'my/tramp-void-if-file-is-tramp)
(advice-add #'editorconfig--advice-find-file-noselect :around
- #'my/editorconfig--advice-find-file-noselect-around))
+ #'my/editorconfig--advice-find-file-noselect-around))
all-the-icons-dired runs test on every file in the directory.
(with-eval-after-load 'all-the-icons-dired
(advice-add #'all-the-icons-dired-mode :around #'my/tramp-void-if-tramp))
@@ -7074,7 +7283,7 @@ Didn’t work out as I expected, so I’ve made org-journal-tags
(defun my/vterm-setup ()
(display-line-numbers-mode 0)
(setq-local term-prompt-regexp
- (rx bol (| ">" "✕") " ")))
+ (rx bol (| ">" "✕") " ")))
(use-package vterm
:commands (vterm vterm-other-window)
@@ -7129,27 +7338,27 @@ Didn’t work out as I expected, so I’ve made org-journal-tags
Open a terminal in the lower third of the frame with the ` key.
I guess that’s the first Emacs function I wrote!
(add-to-list 'display-buffer-alist
- `(,"vterm-subterminal.*"
- (display-buffer-reuse-window
- display-buffer-in-side-window)
- (side . bottom)
- (reusable-frames . visible)
- (window-height . 0.33)))
+ `(,"vterm-subterminal.*"
+ (display-buffer-reuse-window
+ display-buffer-in-side-window)
+ (side . bottom)
+ (reusable-frames . visible)
+ (window-height . 0.33)))
(defun my/toggle-vterm-subteminal ()
"Toogle subteminal."
(interactive)
(let ((vterm-window
- (seq-find
- (lambda (window)
- (string-match
- "vterm-subterminal.*"
- (buffer-name (window-buffer window))))
- (window-list))))
+ (seq-find
+ (lambda (window)
+ (string-match
+ "vterm-subterminal.*"
+ (buffer-name (window-buffer window))))
+ (window-list))))
(if vterm-window
- (if (eq (get-buffer-window (current-buffer)) vterm-window)
- (kill-buffer (current-buffer))
- (select-window vterm-window))
+ (if (eq (get-buffer-window (current-buffer)) vterm-window)
+ (kill-buffer (current-buffer))
+ (select-window vterm-window))
(vterm-other-window "vterm-subterminal"))))
;; (unless my/slow-ssh
@@ -7238,10 +7447,10 @@ Didn’t work out as I expected, so I’ve made org-journal-tags
;; XXX 90 to override `evil-collection'
(add-hook 'eshell-first-time-mode-hook 'my/configure-eshell 90)
(setq eshell-command-aliases-list
- '(("q" "exit")
- ("c" "clear")
- ("ll" "ls -la")
- ("e" "find-file")))
+ '(("q" "exit")
+ ("c" "clear")
+ ("ll" "ls -la")
+ ("e" "find-file")))
(setq eshell-banner-message "")
;; (setq eshell-visual-commands
;; `(,@eshell-visual-commands "jless"))
@@ -7253,25 +7462,25 @@ Didn’t work out as I expected, so I’ve made org-journal-tags
(defun my/get-starship-prompt ()
(let ((cmd (format "TERM=xterm starship prompt --status=%d --cmd-duration=%d --logical-path=%s"
- eshell-last-command-status
- (if my/eshell-last-command-start-time
- (let ((delta (float-time
- (time-subtract
- (current-time)
- my/eshell-last-command-start-time))))
- (setq my/eshell-last-command-start-time nil)
- (round (* delta 1000)))
- 0)
- (shell-quote-argument default-directory))))
+ eshell-last-command-status
+ (if my/eshell-last-command-start-time
+ (let ((delta (float-time
+ (time-subtract
+ (current-time)
+ my/eshell-last-command-start-time))))
+ (setq my/eshell-last-command-start-time nil)
+ (round (* delta 1000)))
+ 0)
+ (shell-quote-argument default-directory))))
(with-temp-buffer
(call-process "bash" nil t nil "-c" cmd)
(when my/is-termux
- (let ((inhibit-message t))
- (replace-string "\\[" "" nil (point-min) (point-max))
- (replace-string "\\]" "" nil (point-min) (point-max))))
+ (let ((inhibit-message t))
+ (replace-string "\\[" "" nil (point-min) (point-max))
+ (replace-string "\\]" "" nil (point-min) (point-max))))
(thread-first "\n"
- (concat (string-trim (buffer-string)))
- (ansi-color-apply)))))
+ (concat (string-trim (buffer-string)))
+ (ansi-color-apply)))))
(defun my/eshell-set-start-time (&rest _args)
(setq-local my/eshell-last-command-start-time (current-time)))
@@ -7341,20 +7550,20 @@ Didn’t work out as I expected, so I’ve made org-journal-tags
(defun my/shell-unquote-argument-without-process (string)
(save-match-data
(let ((idx 0) next inside
- (quote-chars (rx (| "'" "`" "\"" "\\"))))
+ (quote-chars (rx (| "'" "`" "\"" "\\"))))
(while (and (< idx (length string))
- (setq next (string-match quote-chars string next)))
- (cond ((= (aref string next) ?\\)
- (setq string (replace-match "" nil nil string))
- (setq next (1+ next)))
- ((and inside (= (aref string next) inside))
- (setq string (replace-match "" nil nil string))
- (setq inside nil))
- (inside
- (setq next (1+ next)))
- (t
- (setq inside (aref string next))
- (setq string (replace-match "" nil nil string)))))
+ (setq next (string-match quote-chars string next)))
+ (cond ((= (aref string next) ?\\)
+ (setq string (replace-match "" nil nil string))
+ (setq next (1+ next)))
+ ((and inside (= (aref string next) inside))
+ (setq string (replace-match "" nil nil string))
+ (setq inside nil))
+ (inside
+ (setq next (1+ next)))
+ (t
+ (setq inside (aref string next))
+ (setq string (replace-match "" nil nil string)))))
string)))
Now, verify one suggestion against the current input. At the moment, outside of checking the prefix, it does the following:
@@ -7365,18 +7574,18 @@ Didn’t work out as I expected, so I’ve made org-journal-tags
(defun my/eshell-history-is-good-suggestion (input suggestion)
(and (string-prefix-p input suggestion)
(if (string-prefix-p "cd " input)
- (let ((suggested-dir
- (my/shell-unquote-argument-without-process
- (substring suggestion 3))))
- (if (or (string-prefix-p "/" suggested-dir)
- (string-prefix-p "~" suggested-dir))
- (file-directory-p suggested-dir)
- (file-directory-p (concat (eshell/pwd) "/" suggested-dir))))
- t)
+ (let ((suggested-dir
+ (my/shell-unquote-argument-without-process
+ (substring suggestion 3))))
+ (if (or (string-prefix-p "/" suggested-dir)
+ (string-prefix-p "~" suggested-dir))
+ (file-directory-p suggested-dir)
+ (file-directory-p (concat (eshell/pwd) "/" suggested-dir))))
+ t)
(if (string-prefix-p "git" suggestion)
- ;; How is this faster than 'magit-toplevel'?
- (vc-git-root)
- t)))
+ ;; How is this faster than 'magit-toplevel'?
+ (vc-git-root)
+ t)))
And propose one suggestion for the current input, because I don’t need more. It users two sources:
eshell-history-ring
@@ -7387,34 +7596,34 @@ Didn’t work out as I expected, so I’ve made org-journal-tags
(unless (seq-empty-p input)
(or
(when-let (s (cl-loop for elem in (ring-elements eshell-history-ring)
- for proc-elem = (string-trim (substring-no-properties elem))
- when (my/eshell-history-is-good-suggestion input proc-elem)
- return proc-elem))
+ for proc-elem = (string-trim (substring-no-properties elem))
+ when (my/eshell-history-is-good-suggestion input proc-elem)
+ return proc-elem))
(substring s (length input)))
(ignore-errors
(when-let* ((pcomplete-stub input)
- (completions (pcomplete-completions))
- (one-completion (car (all-completions pcomplete-stub completions)))
- (bound (car (completion-boundaries pcomplete-stub completions nil ""))))
- (unless (zerop bound)
- (setq one-completion (concat (substring pcomplete-stub 0 bound) one-completion)))
- ;; (message "%s %s" pcomplete-stub one-completion)
- (comint-quote-filename
- (substring one-completion (min
- (length pcomplete-stub)
- (length one-completion)))))))))
+ (completions (pcomplete-completions))
+ (one-completion (car (all-completions pcomplete-stub completions)))
+ (bound (car (completion-boundaries pcomplete-stub completions nil ""))))
+ (unless (zerop bound)
+ (setq one-completion (concat (substring pcomplete-stub 0 bound) one-completion)))
+ ;; (message "%s %s" pcomplete-stub one-completion)
+ (comint-quote-filename
+ (substring one-completion (min
+ (length pcomplete-stub)
+ (length one-completion)))))))))
As I said, I want to use an overlay to display the suggestion. I tried to store the current overlay in a buffer-local variable, but somehow it was getting lost at times… And there aren’t many overlays anyway, so this doesn’t seem to slow down Emacs that much.
(defun my/eshell-overlay-get ()
(seq-find (lambda (ov)
- (overlay-get ov 'my/eshell-completion-overlay))
- (overlays-in (point-min) (point-max))))
+ (overlay-get ov 'my/eshell-completion-overlay))
+ (overlays-in (point-min) (point-max))))
Thanks this answer on StackExchange for pointing out the cursor text property.
(defun my/eshell-overlay-update (pos value)
(let ((overlay-value (propertize value 'face 'shadow
- 'cursor t))
- (overlay (my/eshell-overlay-get)))
+ 'cursor t))
+ (overlay (my/eshell-overlay-get)))
(if overlay
- (move-overlay overlay pos pos)
+ (move-overlay overlay pos pos)
(setq overlay (make-overlay pos pos (current-buffer) nil t))
(overlay-put overlay 'my/eshell-completion-overlay t))
(overlay-put overlay 'after-string overlay-value)))
@@ -7427,8 +7636,8 @@ Didn’t work out as I expected, so I’ve made org-journal-tags
This also hides the overlay if company completion is active because company sometimes creates its own overlays that intersect with mine… I don’t yet understand when it happens because sometimes company just creates the completion dialog with no overlay, and I couldn’t find a way to check if the overlay is created or not.
(defun my/eshell-overlay-suggest (&rest _args)
(if-let* ((input (my/eshell-get-input))
- (suggestion (my/eshell-history-suggest-one input))
- (_ (not company-prefix)))
+ (suggestion (my/eshell-history-suggest-one input))
+ (_ (not company-prefix)))
(my/eshell-overlay-update (line-end-position) suggestion)
(my/eshell-overlay-remove)))
The function can be added in after-change-functions, which is executed on every text modification. This shouldn’t slow eshell down because eshell-send-input sets inhibit-modification-hooks to t.
@@ -7437,9 +7646,9 @@ Didn’t work out as I expected, so I’ve made org-journal-tags
:after-hook
(if my/eshell-overlay-suggest-mode
(progn
- (add-hook 'after-change-functions #'my/eshell-overlay-suggest nil t)
- (add-hook 'company-completion-started-hook #'my/eshell-overlay-suggest nil t)
- (add-hook 'company-after-completion-hook #'my/eshell-overlay-suggest nil t))
+ (add-hook 'after-change-functions #'my/eshell-overlay-suggest nil t)
+ (add-hook 'company-completion-started-hook #'my/eshell-overlay-suggest nil t)
+ (add-hook 'company-after-completion-hook #'my/eshell-overlay-suggest nil t))
(remove-hook 'after-change-functions #'my/eshell-overlay-suggest t)
(add-hook 'company-completion-started-hook #'my/eshell-overlay-suggest t)
(add-hook 'company-after-completion-hook #'my/eshell-overlay-suggest t)
@@ -7451,10 +7660,10 @@ Didn’t work out as I expected, so I’ve made org-journal-tags
(interactive)
(if (and (= (point) (line-end-position)))
(if-let ((overlay (my/eshell-overlay-get)))
- (progn
- (delete-overlay overlay)
- (insert (overlay-get overlay 'after-string)))
- (company-complete))
+ (progn
+ (delete-overlay overlay)
+ (insert (overlay-get overlay 'after-string)))
+ (company-complete))
(company-complete)))
Atuin integration
eshell-atuin is my package that integrates eshell with atuin.
@@ -7472,12 +7681,12 @@ Didn’t work out as I expected, so I’ve made org-journal-tags
Dedicated buffer
Make a dedicated buffer for eshell in the bottom of the screen.
(add-to-list 'display-buffer-alist
- '("eshell-dedicated.*"
- (display-buffer-reuse-window
- display-buffer-in-side-window)
- (side . bottom)
- (reusable-frames . visible)
- (window-height . 0.33)))
+ '("eshell-dedicated.*"
+ (display-buffer-reuse-window
+ display-buffer-in-side-window)
+ (side . bottom)
+ (reusable-frames . visible)
+ (window-height . 0.33)))
(defun my/eshell-dedicated ()
(interactive)
@@ -7486,13 +7695,13 @@ Didn’t work out as I expected, so I’ve made org-journal-tags
;; How?
(require 'eshell)
(let* ((eshell-buffer-name "eshell-dedicated")
- (dedicated-buffer (get-buffer eshell-buffer-name)))
+ (dedicated-buffer (get-buffer eshell-buffer-name)))
(if (not dedicated-buffer)
- (eshell)
+ (eshell)
(let ((window (get-buffer-window dedicated-buffer)))
- (if (eq (selected-window) window)
- (kill-buffer-and-window)
- (select-window window))))))
+ (if (eq (selected-window) window)
+ (kill-buffer-and-window)
+ (select-window window))))))
Custom commands
(defun eshell/prt ()
(if-let ((root (projectile-project-root)))
@@ -7509,10 +7718,10 @@ Didn’t work out as I expected, so I’ve made org-journal-tags
Still, I’ll probably switch to eat if eshell doesn’t work for me.
(use-package eat
:straight (:files ("*.el" ("term" "term/*.el") "*.texi"
- "*.ti" ("terminfo/e" "terminfo/e/*")
- ("terminfo/65" "terminfo/65/*")
- ("integration" "integration/*")
- (:exclude ".dir-locals.el" "*-tests.el")))
+ "*.ti" ("terminfo/e" "terminfo/e/*")
+ ("terminfo/65" "terminfo/65/*")
+ ("integration" "integration/*")
+ (:exclude ".dir-locals.el" "*-tests.el")))
:commands (eat eat-shell-mode)
:config
(setq eat-shell "/bin/bash"))
@@ -7545,12 +7754,12 @@ Didn’t work out as I expected, so I’ve made org-journal-tags
(with-eval-after-load 'tramp
(add-to-list 'tramp-methods
- `("yadm"
- (tramp-login-program "yadm")
- (tramp-login-args (("enter")))
- (tramp-login-env (("SHELL") "/bin/sh"))
- (tramp-remote-shell "/bin/sh")
- (tramp-remote-shell-args ("-c")))))
+ `("yadm"
+ (tramp-login-program "yadm")
+ (tramp-login-args (("enter")))
+ (tramp-login-env (("SHELL") "/bin/sh"))
+ (tramp-remote-shell "/bin/sh")
+ (tramp-remote-shell-args ("-c")))))
(defun my/yadm-magit ()
@@ -7675,14 +7884,14 @@ Didn’t work out as I expected, so I’ve made org-journal-tags
(with-eval-after-load 'elfeed
(setq elfeed-search-face-alist
- '((podcasts elfeed-podcasts-entry)
- (music elfeed-music-entry)
- (gov elfeed-govt-entry)
- (twitter elfeed-twitter-entry)
- (videos elfeed-videos-entry)
- (emacs elfeed-emacs-entry)
- (blogs elfeed-blogs-entry)
- (unread elfeed-search-unread-title-face))))
+ '((podcasts elfeed-podcasts-entry)
+ (music elfeed-music-entry)
+ (gov elfeed-govt-entry)
+ (twitter elfeed-twitter-entry)
+ (videos elfeed-videos-entry)
+ (emacs elfeed-emacs-entry)
+ (blogs elfeed-blogs-entry)
+ (unread elfeed-search-unread-title-face))))
elfeed-summary
elfeed-summary is my package that provides a feed summary interface for elfeed.
The default interface of elfeed is just a list of all entries, so it gets hard to navigate when there are a lot of sources with varying frequencies of posts. This is my attempt to address this issue.
@@ -7708,12 +7917,12 @@ Didn’t work out as I expected, so I’ve made org-journal-tags
There are multiple kinds of entries that I want to be opened by EMMS. First, a function that returns a YouTube URL:
(defun my/get-youtube-url (entry)
(let ((watch-id (cadr
- (assoc "watch?v"
- (url-parse-query-string
- (substring
- (url-filename
- (url-generic-parse-url (elfeed-entry-link entry)))
- 1))))))
+ (assoc "watch?v"
+ (url-parse-query-string
+ (substring
+ (url-filename
+ (url-generic-parse-url (elfeed-entry-link entry)))
+ 1))))))
(when watch-id
(concat "https://www.youtube.com/watch?v=" watch-id))))
Second, a function that returns a URL to an enclosure. This is generally how podcasts are distributed.
@@ -7734,12 +7943,12 @@ Didn’t work out as I expected, so I’ve made org-journal-tags
(with-eval-after-load 'emms
(define-emms-source elfeed (entry)
(let ((url (or (my/get-enclosures-url entry)
- (my/get-youtube-url entry))))
+ (my/get-youtube-url entry))))
(unless url
- (error "URL not found"))
+ (error "URL not found"))
(let ((track (emms-track 'url url)))
- (emms-track-set track 'info-title (elfeed-entry-title entry))
- (emms-playlist-insert-track track)))))
+ (emms-track-set track 'info-title (elfeed-entry-title entry))
+ (emms-playlist-insert-track track)))))
(defun my/elfeed-add-emms ()
(interactive)
@@ -7780,61 +7989,61 @@ Didn’t work out as I expected, so I’ve made org-journal-tags
Call CALLBACK with the output."
(let* ((buffer (generate-new-buffer "rdrview"))
- (proc (start-process "rdrview" buffer "rdrview"
- url "-T" "title,sitename,body"
- "-H")))
+ (proc (start-process "rdrview" buffer "rdrview"
+ url "-T" "title,sitename,body"
+ "-H")))
(set-process-sentinel
proc
(lambda (process _msg)
(let ((status (process-status process))
- (code (process-exit-status process)))
- (cond ((and (eq status 'exit) (= code 0))
- (progn
- (funcall callback
- (with-current-buffer (process-buffer process)
- (buffer-string)))
- (kill-buffer (process-buffer process))) )
- ((or (and (eq status 'exit) (> code 0))
- (eq status 'signal))
- (let ((err (with-current-buffer (process-buffer process)
- (buffer-string))))
- (kill-buffer (process-buffer process))
- (user-error "Error in rdrview: %s" err)))))))
+ (code (process-exit-status process)))
+ (cond ((and (eq status 'exit) (= code 0))
+ (progn
+ (funcall callback
+ (with-current-buffer (process-buffer process)
+ (buffer-string)))
+ (kill-buffer (process-buffer process))) )
+ ((or (and (eq status 'exit) (> code 0))
+ (eq status 'signal))
+ (let ((err (with-current-buffer (process-buffer process)
+ (buffer-string))))
+ (kill-buffer (process-buffer process))
+ (user-error "Error in rdrview: %s" err)))))))
proc))
The function calls callback with the output of rdrview. This usually doesn’t take long, but it’s still nice to avoid freezing Emacs that way.
Now we have to parse the output. The -T flag puts the title in the <h1> tag, the site name site in the <h2> tag, and the content in a <div>. What’s more, headers of the content are often shifted, e.g. the top-level header may well end up being and <h2> or <h3>, which does not look great in LaTeX.
With that said, here’s a function that does the required changes:
(defun my/rdrview-parse (dom-string)
(let ((dom (with-temp-buffer
- (insert dom-string)
- (libxml-parse-html-region (point-min) (point-max)))))
+ (insert dom-string)
+ (libxml-parse-html-region (point-min) (point-max)))))
(let (title sitename content (i 0))
(dolist (child (dom-children (car (dom-by-id dom "readability-page-1"))))
- (when (listp child)
- (cond
- ((eq (car child) 'h1)
- (setq title (dom-text child)))
- ((eq (car child) 'h2)
- (setq sitename (dom-text child)))
- ((eq (car child) 'div)
- (setq content child)))))
+ (when (listp child)
+ (cond
+ ((eq (car child) 'h1)
+ (setq title (dom-text child)))
+ ((eq (car child) 'h2)
+ (setq sitename (dom-text child)))
+ ((eq (car child) 'div)
+ (setq content child)))))
(while (and
- (not (dom-by-tag content 'h1))
- (dom-search
- content
- (lambda (el)
- (when (listp el)
- (pcase (car el)
- ('h2 (setf (car el) 'h1))
- ('h3 (setf (car el) 'h2))
- ('h4 (setf (car el) 'h3))
- ('h5 (setf (car el) 'h4))
- ('h6 (setf (car el) 'h5))))))))
+ (not (dom-by-tag content 'h1))
+ (dom-search
+ content
+ (lambda (el)
+ (when (listp el)
+ (pcase (car el)
+ ('h2 (setf (car el) 'h1))
+ ('h3 (setf (car el) 'h2))
+ ('h4 (setf (car el) 'h3))
+ ('h5 (setf (car el) 'h4))
+ ('h6 (setf (car el) 'h5))))))))
`((title . ,title)
- (sitename . ,sitename)
- (content . ,(with-temp-buffer
- (dom-print content)
- (buffer-string)))))))
+ (sitename . ,sitename)
+ (content . ,(with-temp-buffer
+ (dom-print content)
+ (buffer-string)))))))
Using rdrview from elfeed
Because I didn’t find a smart way to advise the desired behavior into elfeed, here’s a modification of the elfeed-show-refresh--mail-style function with two changes:
@@ -7852,45 +8061,45 @@ Didn’t work out as I expected, so I’ve made org-journal-tags
(elfeed-entry-link elfeed-show-entry)
(lambda (result)
(let* ((data (my/rdrview-parse result))
- (inhibit-read-only t)
- (title (elfeed-entry-title elfeed-show-entry))
- (date (seconds-to-time (elfeed-entry-date elfeed-show-entry)))
- (authors (elfeed-meta elfeed-show-entry :authors))
- (link (elfeed-entry-link elfeed-show-entry))
- (tags (elfeed-entry-tags elfeed-show-entry))
- (tagsstr (mapconcat #'symbol-name tags ", "))
- (nicedate (format-time-string "%a, %e %b %Y %T %Z" date))
- (content (alist-get 'content data))
- (feed (elfeed-entry-feed elfeed-show-entry))
- (feed-title (elfeed-feed-title feed))
- (base (and feed (elfeed-compute-base (elfeed-feed-url feed)))))
+ (inhibit-read-only t)
+ (title (elfeed-entry-title elfeed-show-entry))
+ (date (seconds-to-time (elfeed-entry-date elfeed-show-entry)))
+ (authors (elfeed-meta elfeed-show-entry :authors))
+ (link (elfeed-entry-link elfeed-show-entry))
+ (tags (elfeed-entry-tags elfeed-show-entry))
+ (tagsstr (mapconcat #'symbol-name tags ", "))
+ (nicedate (format-time-string "%a, %e %b %Y %T %Z" date))
+ (content (alist-get 'content data))
+ (feed (elfeed-entry-feed elfeed-show-entry))
+ (feed-title (elfeed-feed-title feed))
+ (base (and feed (elfeed-compute-base (elfeed-feed-url feed)))))
(erase-buffer)
(insert (format (propertize "Title: %s\n" 'face 'message-header-name)
- (propertize title 'face 'message-header-subject)))
+ (propertize title 'face 'message-header-subject)))
(when elfeed-show-entry-author
- (dolist (author authors)
- (let ((formatted (elfeed--show-format-author author)))
- (insert
- (format (propertize "Author: %s\n" 'face 'message-header-name)
- (propertize formatted 'face 'message-header-to))))))
+ (dolist (author authors)
+ (let ((formatted (elfeed--show-format-author author)))
+ (insert
+ (format (propertize "Author: %s\n" 'face 'message-header-name)
+ (propertize formatted 'face 'message-header-to))))))
(insert (format (propertize "Date: %s\n" 'face 'message-header-name)
- (propertize nicedate 'face 'message-header-other)))
+ (propertize nicedate 'face 'message-header-other)))
(insert (format (propertize "Feed: %s\n" 'face 'message-header-name)
- (propertize feed-title 'face 'message-header-other)))
+ (propertize feed-title 'face 'message-header-other)))
(when tags
- (insert (format (propertize "Tags: %s\n" 'face 'message-header-name)
- (propertize tagsstr 'face 'message-header-other))))
+ (insert (format (propertize "Tags: %s\n" 'face 'message-header-name)
+ (propertize tagsstr 'face 'message-header-other))))
(insert (propertize "Link: " 'face 'message-header-name))
(elfeed-insert-link link link)
(insert "\n")
(cl-loop for enclosure in (elfeed-entry-enclosures elfeed-show-entry)
- do (insert (propertize "Enclosure: " 'face 'message-header-name))
- do (elfeed-insert-link (car enclosure))
- do (insert "\n"))
+ do (insert (propertize "Enclosure: " 'face 'message-header-name))
+ do (elfeed-insert-link (car enclosure))
+ do (insert "\n"))
(insert "\n")
(if content
- (elfeed-insert-html content base)
- (insert (propertize "(empty)\n" 'face 'italic)))
+ (elfeed-insert-html content base)
+ (insert (propertize "(empty)\n" 'face 'italic)))
(setq-local my/elfeed-show-rdrview-html content)
(goto-char (point-min))))))
That way, calling M-x my/rdrview-elfeed-show replaces the original content with one from rdrview.
@@ -7919,7 +8128,7 @@ Didn’t work out as I expected, so I’ve made org-journal-tags
Invoking pandoc
Now that we have the template, let’s save it somewhere and store the path to a variable:
(setq my/rdrview-template (expand-file-name
- (concat user-emacs-directory "rdrview.tex")))
+ (concat user-emacs-directory "rdrview.tex")))
And let’s invoke pandoc. We need to pass the following flags:
--pdf-engine=xelatex, of course
@@ -7930,7 +8139,7 @@ Didn’t work out as I expected, so I’ve made org-journal-tags
In fact, pandoc is a pretty awesome tool in the sense that it allows for feeding custom variables to rich-language templates.
So, the rendering function is as follows:
(cl-defun my/rdrview-render (content type variables callback
- &key file-name overwrite)
+ &key file-name overwrite)
"Render CONTENT with pandoc.
TYPE is a file extension as supported by pandoc, for instance,
@@ -7947,34 +8156,34 @@ Didn’t work out as I expected, so I’ve made org-journal-tags
(unless file-name
(setq file-name (format "/tmp/%d.pdf" (random 100000000))))
(let (params
- (temp-file-name (format "/tmp/%d.%s" (random 100000000) type)))
+ (temp-file-name (format "/tmp/%d.%s" (random 100000000) type)))
(cl-loop for (key . value) in variables
- when value
- do (progn
- (push "--variable" params)
- (push (format "%s=%s" key value) params)))
+ when value
+ do (progn
+ (push "--variable" params)
+ (push (format "%s=%s" key value) params)))
(setq params (nreverse params))
(if (and (file-exists-p file-name) (not overwrite))
- (funcall callback file-name)
+ (funcall callback file-name)
(with-temp-file temp-file-name
- (insert content))
+ (insert content))
(let ((proc (apply #'start-process
- "pandoc" (get-buffer-create "*Pandoc*") "pandoc"
- temp-file-name "-o" file-name
- "--pdf-engine=xelatex" "--template" my/rdrview-template
- params)))
- (set-process-sentinel
- proc
- (lambda (process _msg)
- (let ((status (process-status process))
- (code (process-exit-status process)))
- (cond ((and (eq status 'exit) (= code 0))
- (progn
- (message "Done!")
- (funcall callback file-name)))
- ((or (and (eq status 'exit) (> code 0))
- (eq status 'signal))
- (user-error "Error in pandoc. Check the *Pandoc* buffer"))))))))))
+ "pandoc" (get-buffer-create "*Pandoc*") "pandoc"
+ temp-file-name "-o" file-name
+ "--pdf-engine=xelatex" "--template" my/rdrview-template
+ params)))
+ (set-process-sentinel
+ proc
+ (lambda (process _msg)
+ (let ((status (process-status process))
+ (code (process-exit-status process)))
+ (cond ((and (eq status 'exit) (= code 0))
+ (progn
+ (message "Done!")
+ (funcall callback file-name)))
+ ((or (and (eq status 'exit) (> code 0))
+ (eq status 'signal))
+ (user-error "Error in pandoc. Check the *Pandoc* buffer"))))))))))
Opening elfeed entries
Now we have everything required to open elfeed entries.
Also, in my case elfeed entries come in two languages, so I have to set main-lang and other-lang variables accordingly. Here’s the main function:
@@ -7987,30 +8196,30 @@ Didn’t work out as I expected, so I’ve made org-journal-tags
PDF already exists."
(interactive (list elfeed-show-entry current-prefix-arg))
(let ((authors (mapcar (lambda (m) (plist-get m :name)) (elfeed-meta entry :authors)))
- (feed-title (elfeed-feed-title (elfeed-entry-feed entry)))
- (tags (mapconcat #'symbol-name (elfeed-entry-tags entry) ", "))
- (date (format-time-string "%a, %e %b %Y"
- (seconds-to-time (elfeed-entry-date entry))))
- (content (elfeed-deref (elfeed-entry-content entry)))
- (file-name (concat my/elfeed-pdf-dir
- (elfeed-ref-id (elfeed-entry-content entry))
- ".pdf"))
- (main-language "english")
- (other-language "russian"))
+ (feed-title (elfeed-feed-title (elfeed-entry-feed entry)))
+ (tags (mapconcat #'symbol-name (elfeed-entry-tags entry) ", "))
+ (date (format-time-string "%a, %e %b %Y"
+ (seconds-to-time (elfeed-entry-date entry))))
+ (content (elfeed-deref (elfeed-entry-content entry)))
+ (file-name (concat my/elfeed-pdf-dir
+ (elfeed-ref-id (elfeed-entry-content entry))
+ ".pdf"))
+ (main-language "english")
+ (other-language "russian"))
(unless content
(user-error "No content!"))
(setq subtitle
- (cond
- ((seq-empty-p authors) feed-title)
- ((and (not (seq-empty-p (car authors)))
- (string-match-p (regexp-quote (car authors)) feed-title)) feed-title)
- (t (concat (string-join authors ", ") "\\\\" feed-title))))
+ (cond
+ ((seq-empty-p authors) feed-title)
+ ((and (not (seq-empty-p (car authors)))
+ (string-match-p (regexp-quote (car authors)) feed-title)) feed-title)
+ (t (concat (string-join authors ", ") "\\\\" feed-title))))
(when (member 'ru (elfeed-entry-tags entry))
(setq main-language "russian")
(setq other-language "english"))
(my/rdrview-render
(if (bound-and-true-p my/elfeed-show-rdrview-html)
- my/elfeed-show-rdrview-html
+ my/elfeed-show-rdrview-html
content)
(elfeed-entry-content-type entry)
`((title . ,(elfeed-entry-title entry))
@@ -8034,18 +8243,18 @@ Didn’t work out as I expected, so I’ve made org-journal-tags
As you may have noticed, we also can display arbitrary web pages with this setup, so let’s go ahead and implement that:
(defun my/get-languages (url)
(let ((main-lang "english")
- (other-lang "russian"))
+ (other-lang "russian"))
(when (string-match-p (rx ".ru") url)
(setq main-lang "russian"
- other-lang "english"))
+ other-lang "english"))
(list main-lang other-lang)))
(defun my/rdrview-open (url overwrite)
(interactive
(let ((url (read-from-minibuffer
- "URL: "
- (if (bound-and-true-p elfeed-show-entry)
- (elfeed-entry-link elfeed-show-entry)))))
+ "URL: "
+ (if (bound-and-true-p elfeed-show-entry)
+ (elfeed-entry-link elfeed-show-entry)))))
(when (string-empty-p url)
(user-error "URL is empty"))
(list url current-prefix-arg)))
@@ -8053,16 +8262,16 @@ Didn’t work out as I expected, so I’ve made org-journal-tags
url
(lambda (res)
(let ((data (my/rdrview-parse res))
- (langs (my/get-languages url)))
+ (langs (my/get-languages url)))
(my/rdrview-render
- (alist-get 'content data)
- 'html
- `((title . ,(alist-get 'title data))
- (subtitle . ,(alist-get 'sitename data))
- (main-lang . ,(nth 0 langs))
- (other-lang . ,(nth 1 langs)))
- (lambda (file-name)
- (start-process "xdg-open" nil "xdg-open" file-name)))))))
+ (alist-get 'content data)
+ 'html
+ `((title . ,(alist-get 'title data))
+ (subtitle . ,(alist-get 'sitename data))
+ (main-lang . ,(nth 0 langs))
+ (other-lang . ,(nth 1 langs)))
+ (lambda (file-name)
+ (start-process "xdg-open" nil "xdg-open" file-name)))))))
Unfortunately, this part doesn’t work that well, so we can’t just uninstall Firefox or Chromium and browse the web from a PDF viewer.
The most common problem I’ve encountered is incorrectly formed pictures, such as .png files without the boundary info. I’m sure you’ve also come across this if you ever tried to insert a lot of Internet pictures into a LaTeX document.
However, sans the pictures issue, for certain sites like Wikipedia this is usable.
@@ -8095,37 +8304,37 @@ Didn’t work out as I expected, so I’ve made org-journal-tags
invoke CALLBACK straight away without doing the rendering, unless
OVERWRITE is non-nil."
(interactive (list (read-string "Video ID: ")
- (lambda (file-name)
- (find-file file-name))
- :file-name nil
- :overwrite t))
+ (lambda (file-name)
+ (find-file file-name))
+ :file-name nil
+ :overwrite t))
(unless file-name
(setq file-name (format "/tmp/%d.vtt" (random 100000000))))
(if (and (file-exists-p file-name) (not overwrite))
(funcall callback file-name)
(let* ((buffer (generate-new-buffer "youtube-transcripts"))
- (proc (start-process "youtube_transcript_api" buffer
- "youtube_transcript_api" video-id
- "--languages" "en" "ru" "de"
- "--format" "webvtt")))
+ (proc (start-process "youtube_transcript_api" buffer
+ "youtube_transcript_api" video-id
+ "--languages" "en" "ru" "de"
+ "--format" "webvtt")))
(set-process-sentinel
proc
(lambda (process _msg)
- (let ((status (process-status process))
- (code (process-exit-status process)))
- (cond ((and (eq status 'exit) (= code 0))
- (progn
- (with-current-buffer (process-buffer process)
- (setq buffer-file-name file-name)
- (save-buffer))
- (kill-buffer (process-buffer process))
- (funcall callback file-name)))
- ((or (and (eq status 'exit) (> code 0))
- (eq status 'signal))
- (let ((err (with-current-buffer (process-buffer process)
- (buffer-string))))
- (kill-buffer (process-buffer process))
- (user-error "Error in youtube_transcript_api: %s" err)))))))
+ (let ((status (process-status process))
+ (code (process-exit-status process)))
+ (cond ((and (eq status 'exit) (= code 0))
+ (progn
+ (with-current-buffer (process-buffer process)
+ (setq buffer-file-name file-name)
+ (save-buffer))
+ (kill-buffer (process-buffer process))
+ (funcall callback file-name)))
+ ((or (and (eq status 'exit) (> code 0))
+ (eq status 'signal))
+ (let ((err (with-current-buffer (process-buffer process)
+ (buffer-string))))
+ (kill-buffer (process-buffer process))
+ (user-error "Error in youtube_transcript_api: %s" err)))))))
proc)))
elfeed and subed
Now that we have a standalone function, let’s invoke it with the current elfeed-show-entry:
@@ -8140,23 +8349,23 @@ Didn’t work out as I expected, so I’ve made org-journal-tags
they were fetched before."
(interactive (list elfeed-show-entry current-prefix-arg))
(let ((video-id (cadr
- (assoc "watch?v"
- (url-parse-query-string
- (substring
- (url-filename
- (url-generic-parse-url (elfeed-entry-link entry)))
- 1))))))
+ (assoc "watch?v"
+ (url-parse-query-string
+ (substring
+ (url-filename
+ (url-generic-parse-url (elfeed-entry-link entry)))
+ 1))))))
(unless video-id
(user-error "Can't get video ID from the entry"))
(my/youtube-subtitles-get
video-id
(lambda (file-name)
(with-current-buffer (find-file-other-window file-name)
- (setq-local elfeed-show-entry entry)
- (goto-char (point-min))))
+ (setq-local elfeed-show-entry entry)
+ (goto-char (point-min))))
:file-name (concat my/elfeed-srt-dir
- (elfeed-ref-id (elfeed-entry-content entry))
- ".vtt")
+ (elfeed-ref-id (elfeed-entry-content entry))
+ ".vtt")
:overwrite arg)))
That opens up a .vtt buffer with the subtitles for the current video, which means now we can use the functionality of Sacha Chua’s awesome package called subed.
This package, besides syntax highlighting, allows for controlling the MPV playback, for instance by moving the cursor in the subtitles buffer. Using that requires having the URL of the video in this buffer, which necessitates the line with setq-local in the previous function.
@@ -8172,8 +8381,8 @@ Didn’t work out as I expected, so I’ve made org-journal-tags
(unless (derived-mode-p 'subed-mode)
(user-error "Not subed mode!"))
(setq-local subed-mpv-arguments
- (seq-uniq
- (append subed-mpv-arguments emms-player-mpv-parameters)))
+ (seq-uniq
+ (append subed-mpv-arguments emms-player-mpv-parameters)))
(setq-local subed-mpv-video-file (elfeed-entry-link entry))
(subed-mpv--play subed-mpv-video-file))
Keep in mind that this function has to be launched inside the buffer opened by the my/elfeed-youtube-subtitles function.
@@ -8183,7 +8392,7 @@ Didn’t work out as I expected, so I’ve made org-journal-tags
(unless (or my/remote-server)
(let ((mail-file (expand-file-name "mail.el" user-emacs-directory)))
(if (file-exists-p mail-file)
- (load-file mail-file)
+ (load-file mail-file)
(message "Can't load mail.el"))))
Gnus
Gnus is an Emacs newsreader.
@@ -8222,10 +8431,10 @@ Didn’t work out as I expected, so I’ve made org-journal-tags
(when (gnus-group-topic-p)
(let ((topic (gnus-topic-find-topology (gnus-current-topic))))
(if (eq (cadadr topic) 'visible)
- (progn
- (gnus-topic-goto-topic (gnus-current-topic))
- (gnus-topic-remove-topic nil nil))
- (gnus-topic-remove-topic t nil)))))
+ (progn
+ (gnus-topic-goto-topic (gnus-current-topic))
+ (gnus-topic-remove-topic nil nil))
+ (gnus-topic-remove-topic t nil)))))
Custom keybindings.
(with-eval-after-load 'gnus-group
;; Group
@@ -8261,10 +8470,10 @@ Didn’t work out as I expected, so I’ve made org-journal-tags
:straight t
:if (not (or my/remote-server my/is-termux))
:commands (emms-smart-browse
- emms-browser
- emms-add-url
- emms-add-file
- emms-add-find)
+ emms-browser
+ emms-add-url
+ emms-add-file
+ emms-add-find)
:init
(my-leader-def
:infix "as"
@@ -8319,12 +8528,12 @@ Didn’t work out as I expected, so I’ve made org-journal-tags
(add-hook 'emms-playlist-cleared-hook 'emms-player-mpd-clear)
Set a custom regex for MPD. EMMS sets up the default one from MPD’s diagnostic output so that regex opens basically everything, including videos, https links, etc. That is fine if MPD is the only player in EMMS, but as I want to use MPV as well, I override the regex.
(emms-player-set emms-player-mpd
- 'regex
- (rx (or (: "https://" (* nonl) (or "acast.com") (* nonl))
- (+ (? (or "https://" "http://"))
- (* nonl)
- (regexp (eval (emms-player-simple-regexp
- "m3u" "ogg" "flac" "mp3" "wav" "mod" "au" "aiff" "m4a")))))))
+ 'regex
+ (rx (or (: "https://" (* nonl) (or "acast.com") (* nonl))
+ (+ (? (or "https://" "http://"))
+ (* nonl)
+ (regexp (eval (emms-player-simple-regexp
+ "m3u" "ogg" "flac" "mp3" "wav" "mod" "au" "aiff" "m4a")))))))
After all this is done, run M-x emms-cache-set-from-mpd-all to set cache from MPD. If everything is correct, EMMS browser will be populated with MPD database.
MPV
@@ -8349,17 +8558,17 @@ Didn’t work out as I expected, so I’ve made org-journal-tags
(add-to-list 'emms-player-list 'emms-player-mpv t)
Also a custom regex. My demands for MPV include running yt-dlp, so there is a regex that matches youtube.com or some of the video formats.
(emms-player-set emms-player-mpv
- 'regex
- (rx (or (: "https://" (* nonl) "youtube.com" (* nonl))
- (+ (? (or "https://" "http://"))
- (* nonl)
- (regexp (eval (emms-player-simple-regexp
- "mp4" "mov" "wmv" "webm" "flv" "avi" "mkv")))))))
+ 'regex
+ (rx (or (: "https://" (* nonl) "youtube.com" (* nonl))
+ (+ (? (or "https://" "http://"))
+ (* nonl)
+ (regexp (eval (emms-player-simple-regexp
+ "mp4" "mov" "wmv" "webm" "flv" "avi" "mkv")))))))
By default, MPV plays the video in the best possible quality, which may be pretty high, even too high with limited bandwidth. So here is the logic to choose the quality.
(setq my/youtube-dl-quality-list
'("bestvideo[height<=720]+bestaudio/best[height<=720]"
- "bestvideo[height<=480]+bestaudio/best[height<=480]"
- "bestvideo[height<=1080]+bestaudio/best[height<=1080]"))
+ "bestvideo[height<=480]+bestaudio/best[height<=480]"
+ "bestvideo[height<=1080]+bestaudio/best[height<=1080]"))
(setq my/default-emms-player-mpv-parameters
'("--quiet" "--really-quiet" "--no-audio-display"))
@@ -8369,7 +8578,7 @@ Didn’t work out as I expected, so I’ve made org-journal-tags
(unless quality
(setq quality (completing-read "Quality: " my/youtube-dl-quality-list nil t)))
(setq emms-player-mpv-parameters
- `(,@my/default-emms-player-mpv-parameters ,(format "--ytdl-format=%s" quality))))
+ `(,@my/default-emms-player-mpv-parameters ,(format "--ytdl-format=%s" quality))))
(my/set-emms-mpd-youtube-quality (car my/youtube-dl-quality-list))
Now emms-add-url should work on YouTube URLs just fine. Just keep in mind that it will only add the URL to the playlist, not play it right away.
@@ -8379,9 +8588,9 @@ Didn’t work out as I expected, so I’ve made org-journal-tags
(interactive)
(let ((keys-to-delete '()))
(maphash (lambda (key value)
- (when (eq (cdr (assoc 'type value)) 'url)
- (add-to-list 'keys-to-delete key)))
- emms-cache-db)
+ (when (eq (cdr (assoc 'type value)) 'url)
+ (add-to-list 'keys-to-delete key)))
+ emms-cache-db)
(dolist (key keys-to-delete)
(remhash key emms-cache-db)))
(setq emms-cache-dirty t))
@@ -8398,7 +8607,7 @@ Didn’t work out as I expected, so I’ve made org-journal-tags
"asT" #'lyrics-fetcher-show-lyrics-query)
:config
(setq lyrics-fetcher-genius-access-token
- (my/password-store-get "My_Online/APIs/genius.com"))
+ (my/password-store-get "My_Online/APIs/genius.com"))
(general-define-key
:states '(emacs normal)
:keymaps 'emms-browser-mode-map
@@ -8408,23 +8617,23 @@ Didn’t work out as I expected, so I’ve made org-journal-tags
"go" 'lyrics-fetcher-emms-browser-open-large-cover-at-point)
(advice-add #'emms-lyrics-mode-line
- :override #'my/emms-lyrics-mode-line-override))
+ :override #'my/emms-lyrics-mode-line-override))
Also advice to change the location of the lyrics in the mode line.
(defun my/emms-lyrics-mode-line-override ()
(add-to-list 'global-mode-string
- '(:eval emms-lyrics-mode-line-string)))
+ '(:eval emms-lyrics-mode-line-string)))
(defun my/emms-lyrics-restore-mode-line-override ()
"Restore the mode line."
(setq global-mode-string
- (remove '(:eval emms-lyrics-mode-line-string) global-mode-string))
+ (remove '(:eval emms-lyrics-mode-line-string) global-mode-string))
(force-mode-line-update))
(with-eval-after-load 'emms-lyrics
(advice-add #'emms-lyrics-mode-line
- :override #'my/emms-lyrics-mode-line-override)
+ :override #'my/emms-lyrics-mode-line-override)
(advice-add #'emms-lyrics-restore-mode-line
- :override #'my/emms-lyrics-restore-mode-line-override))
+ :override #'my/emms-lyrics-restore-mode-line-override))
Some keybindings
(with-eval-after-load 'emms-browser
(general-define-key
@@ -8440,9 +8649,9 @@ Didn’t work out as I expected, so I’ve made org-journal-tags
Setting volume
(defun my/set-volume (value)
(start-process "ponymix" nil "ponymix"
- (if (< 0 value) "increase" "decrease")
- (number-to-string (abs value))
- "--max-volume" "150"))
+ (if (< 0 value) "increase" "decrease")
+ (number-to-string (abs value))
+ "--max-volume" "150"))
(setq emms-volume-change-function #'my/set-volume)
(setq emms-volume-change-amount 5)
@@ -8452,23 +8661,23 @@ Didn’t work out as I expected, so I’ve made org-journal-tags
(defun emms-info-mpd-process (track info)
(dolist (data info)
(let ((name (car data))
- (value (cdr data)))
+ (value (cdr data)))
(setq name (cond ((string= name "artist") 'info-artist)
- ((string= name "albumartist") 'info-albumartist)
- ((string= name "composer") 'info-composer)
- ((string= name "performer") 'info-performer)
- ((string= name "title") 'info-title)
- ((string= name "album") 'info-album)
- ((string= name "track") 'info-tracknumber)
- ((string= name "disc") 'info-discnumber)
- ((string= name "date") 'info-year)
- ((string= name "genre") 'info-genre)
- ((string= name "time")
- (setq value (string-to-number value))
- 'info-playing-time)
- (t nil)))
+ ((string= name "albumartist") 'info-albumartist)
+ ((string= name "composer") 'info-composer)
+ ((string= name "performer") 'info-performer)
+ ((string= name "title") 'info-title)
+ ((string= name "album") 'info-album)
+ ((string= name "track") 'info-tracknumber)
+ ((string= name "disc") 'info-discnumber)
+ ((string= name "date") 'info-year)
+ ((string= name "genre") 'info-genre)
+ ((string= name "time")
+ (setq value (string-to-number value))
+ 'info-playing-time)
+ (t nil)))
(when name
- (emms-track-set track name value)))))
+ (emms-track-set track name value)))))
Also, emms-player-mpd-get-alists has an interesting bug. This function parses the response to listallinfo, which looks something like this:
tag1: value1
tag2: value2
@@ -8487,19 +8696,19 @@ Didn’t work out as I expected, so I’ve made org-journal-tags
The list will be in reverse order."
(when (and info
- (null (car info)) ; no error has occurred
- (cdr info)) ; data exists
+ (null (car info)) ; no error has occurred
+ (cdr info)) ; data exists
(let ((alists nil)
- (alist nil)
- cell)
+ (alist nil)
+ cell)
(dolist (line (cdr info))
- (when (setq cell (emms-player-mpd-parse-line line))
- (if (member (car cell) '("file" "directory" "playlist"))
- (setq alists (cons alist alists)
- alist (list cell))
- (setq alist (cons cell alist)))))
+ (when (setq cell (emms-player-mpd-parse-line line))
+ (if (member (car cell) '("file" "directory" "playlist"))
+ (setq alists (cons alist alists)
+ alist (list cell))
+ (setq alist (cons cell alist)))))
(when alist
- (setq alists (cons alist alists)))
+ (setq alists (cons alist alists)))
alists)))
EWW
Emacs built-in web browser. I wonder if anyone actually uses it.
@@ -8529,9 +8738,9 @@ Didn’t work out as I expected, so I’ve made org-journal-tags
'face
(mapcar
(lambda (face)
- (if (eq face 'my/shr-face)
- 'link
- face))
+ (if (eq face 'my/shr-face)
+ 'link
+ face))
(if (sequencep faces) faces (list faces))))))
(with-eval-after-load 'shr
@@ -8561,21 +8770,21 @@ Didn’t work out as I expected, so I’ve made org-journal-tags
(add-to-list 'erc-modules 'log)
(erc-update-modules)
(setq erc-autojoin-channels-alist
- `((,(rx "libera.chat")
- "#systemcrafters" "#systemcrafters-emacs")))
+ `((,(rx "libera.chat")
+ "#systemcrafters" "#systemcrafters-emacs")))
(setq erc-kill-buffer-on-part t)
(setq erc-track-shorten-start 8))
Exclude everything but actual messages from notifications.
(setq erc-track-exclude-types '("NICK" "JOIN" "LEAVE" "QUIT" "PART"
- "301" ; away notice
- "305" ; return from awayness
- "306" ; set awayness
- "324" ; modes
- "329" ; channel creation date
- "332" ; topic notice
- "333" ; who set the topic
- "353" ; Names notice
- ))
+ "301" ; away notice
+ "305" ; return from awayness
+ "306" ; set awayness
+ "324" ; modes
+ "329" ; channel creation date
+ "332" ; topic notice
+ "333" ; who set the topic
+ "353" ; Names notice
+ ))
A plugin to highlight IRC nicknames:
(use-package erc-hl-nicks
:hook (erc-mode . erc-hl-nicks-mode)
@@ -8591,18 +8800,18 @@ Didn’t work out as I expected, so I’ve made org-journal-tags
erc-mode 3 "ERC")
:config
(setq znc-servers
- `(("sqrtminusone.xyz" 6697 t
- ((libera "sqrtminusone"
- ,(my/password-store-get "Selfhosted/ZNC")))))))
+ `(("sqrtminusone.xyz" 6697 t
+ ((libera "sqrtminusone"
+ ,(my/password-store-get "Selfhosted/ZNC")))))))
Send /detach to all servers. Kinda strange that there’s no such function already
(defun my/erc-detach-all ()
(interactive)
(cl-loop for buf being the buffers
- if (eq (buffer-local-value 'major-mode buf) 'erc-mode)
- do (with-current-buffer buf
- (when (erc-server-process-alive)
- (let ((tgt (erc-default-target)))
- (erc-server-send (format "DETACH %s" tgt) nil tgt))))))
+ if (eq (buffer-local-value 'major-mode buf) 'erc-mode)
+ do (with-current-buffer buf
+ (when (erc-server-process-alive)
+ (let ((tgt (erc-default-target)))
+ (erc-server-send (format "DETACH %s" tgt) nil tgt))))))
Mastodon
Mastodon is a decentralized social media network. I use an instance called emacs.ch.
Package configuration
@@ -8623,22 +8832,22 @@ Didn’t work out as I expected, so I’ve made org-journal-tags
(setq mastodon-tl--timeline-posts-count "40")
(setq mastodon-tl--show-avatars t)
(setq mastodon-tl--horiz-bar
- (make-string shr-max-width
- (if (char-displayable-p ?―) ?― ?-)))
+ (make-string shr-max-width
+ (if (char-displayable-p ?―) ?― ?-)))
;; The default emojis take two characters for me
(mapcar (lambda (item)
- (setf (alist-get (car item) mastodon-tl--symbols)
- (cdr item)))
- '((reply "" . "R")
- (boost "" . "B")
- (favourite "" . "F")
- (bookmark "" . "K")
- (media "" . "[media]")
- (verified "" . "V")
- (locked "" . "[locked]")
- (private "" . "[followers]")
- (direct "" . "[direct]")
- (edited "" . "[edited]"))))
+ (setf (alist-get (car item) mastodon-tl--symbols)
+ (cdr item)))
+ '((reply "" . "R")
+ (boost "" . "B")
+ (favourite "" . "F")
+ (bookmark "" . "K")
+ (media "" . "[media]")
+ (verified "" . "V")
+ (locked "" . "[locked]")
+ (private "" . "[followers]")
+ (direct "" . "[direct]")
+ (edited "" . "[edited]"))))
(use-package mastodon-alt
:straight (:host github :repo "rougier/mastodon-alt")
@@ -8664,22 +8873,22 @@ Didn’t work out as I expected, so I’ve made org-journal-tags
(defun my/mastodon-reset ()
(interactive)
(cl-loop for process in (process-list)
- if (string-match-p "emacs.ch" (process-name process))
- do (delete-process process)))
+ if (string-match-p "emacs.ch" (process-name process))
+ do (delete-process process)))
The package also doesn’t have evil bindings. I implement a few basic bindings here:
(with-eval-after-load 'mastodon
(general-define-key
:states '(normal motion)
:keymaps '(mastodon-mode-map)
- "J" #'mastodon-tl--goto-next-item
- "K" #'mastodon-tl--goto-prev-item
- "M-j" #'mastodon-tl--next-tab-item
- "M-k" #'mastodon-tl--prev-tab-item
- "<tab>" #'mastodon-tl--next-tab-item
- "<backtab>" #'mastodon-tl--previous-tab-item
+ "J" #'mastodon-tl-goto-next-item
+ "K" #'mastodon-tl-goto-prev-item
+ "M-j" #'mastodon-tl-next-tab-item
+ "M-k" #'mastodon-tl-prev-tab-item
+ "<tab>" #'mastodon-tl-next-tab-item
+ "<backtab>" #'mastodon-tl-previous-tab-item
"o" #'my/mastodon-toot
- "r" 'mastodon-tl--update
- "c" #'mastodon-tl--toggle-spoiler-text-in-toot
+ "r" 'mastodon-tl-update
+ "c" #'mastodon-tl-toggle-spoiler-text-in-toot
"q" #'kill-current-buffer))
Modeline segment
This is my attempt to make a modeline indicator for new mastodon notifications.
@@ -8699,30 +8908,30 @@ Didn’t work out as I expected, so I’ve made org-journal-tags
(when (file-exists-p my/mastodon-mode-line-file)
(ignore-errors
(with-temp-buffer
- (insert-file-contents my/mastodon-mode-line-file)
- (setq my/mastodon-mode-line-saved-ids
- (read (current-buffer)))))))
+ (insert-file-contents my/mastodon-mode-line-file)
+ (setq my/mastodon-mode-line-saved-ids
+ (read (current-buffer)))))))
(defun my/mastodon-mode-line-persist-meta ()
(mkdir (file-name-directory my/mastodon-mode-line-file) t)
(let ((coding-system-for-write 'utf-8))
(ignore-errors
(with-temp-file my/mastodon-mode-line-file
- (let ((standard-output (current-buffer))
- (print-level nil)
- (print-length nil)
- (print-circle nil))
- (princ ";;; Mastodon Saved Notifications\n\n")
- (prin1 my/mastodon-mode-line-saved-ids))))))
+ (let ((standard-output (current-buffer))
+ (print-level nil)
+ (print-length nil)
+ (print-circle nil))
+ (princ ";;; Mastodon Saved Notifications\n\n")
+ (prin1 my/mastodon-mode-line-saved-ids))))))
(defun my/mastodon-mode-line-update ()
(if my/mastodon-mode-line-unread-ids
(setq my/mastodon-mode-string
- (concat "["
- (propertize (number-to-string
- (length my/mastodon-mode-line-unread-ids))
- 'face 'success)
- "]"))
+ (concat "["
+ (propertize (number-to-string
+ (length my/mastodon-mode-line-unread-ids))
+ 'face 'success)
+ "]"))
(setq my/mastodon-mode-string "")))
(defun my/mastodon-mode-line-update-fetch ()
@@ -8730,21 +8939,21 @@ Didn’t work out as I expected, so I’ve made org-journal-tags
(mastodon-http--api "notifications") nil
(lambda (data)
(let ((fetched-ids
- (cl-loop for datum in data collect (alist-get 'id datum))))
+ (cl-loop for datum in data collect (alist-get 'id datum))))
(setq my/mastodon-mode-line-unread-ids
- (seq-difference fetched-ids my/mastodon-mode-line-saved-ids))
+ (seq-difference fetched-ids my/mastodon-mode-line-saved-ids))
(setq my/mastodon-mode-line-saved-ids
- (seq-intersection my/mastodon-mode-line-saved-ids fetched-ids)))
+ (seq-intersection my/mastodon-mode-line-saved-ids fetched-ids)))
(my/mastodon-mode-line-update))))
(defun my/mastodon-notifications--timeline-before (toots)
(let* ((all-ids (seq-uniq
- (append
- my/mastodon-mode-line-saved-ids
- (cl-loop for datum in toots
- collect (alist-get 'id datum))))))
+ (append
+ my/mastodon-mode-line-saved-ids
+ (cl-loop for datum in toots
+ collect (alist-get 'id datum))))))
(setq my/mastodon-mode-line-unread-ids
- (seq-difference my/mastodon-mode-line-unread-ids all-ids))
+ (seq-difference my/mastodon-mode-line-unread-ids all-ids))
(setq my/mastodon-mode-line-saved-ids all-ids))
(my/mastodon-mode-line-update))
@@ -8757,43 +8966,43 @@ Didn’t work out as I expected, so I’ve made org-journal-tags
:after-hook
(progn
(when (timerp my/mastodon-mode-line-timer)
- (cancel-timer my/mastodon-mode-line-timer))
+ (cancel-timer my/mastodon-mode-line-timer))
(if my/mastodon-mode-line
- (progn
- (add-to-list 'mode-line-misc-info '(:eval my/mastodon-mode-string) t)
- (my/mastodon-mode-line-load-meta)
- (setq my/mastodon-mode-line-timer
- (run-with-timer 0 150 #'my/mastodon-mode-line-update-fetch))
- (advice-add #'mastodon-notifications--timeline :before
- #'my/mastodon-notifications--timeline-before)
- (add-hook 'kill-emacs-hook #'my/mastodon-mode-line-persist-meta))
- (setq mode-line-misc-info (delete '(:eval my/mastodon-mode-string)
- mode-line-misc-info))
- (advice-remove #'mastodon-notifications--timeline
- #'my/mastodon-notifications--timeline-before)
- (remove-hook 'kill-emacs-hook #'my/mastodon-mode-line-persist-meta)
- (my/mastodon-mode-line-persist-meta)))))
+ (progn
+ (add-to-list 'mode-line-misc-info '(:eval my/mastodon-mode-string) t)
+ (my/mastodon-mode-line-load-meta)
+ (setq my/mastodon-mode-line-timer
+ (run-with-timer 0 150 #'my/mastodon-mode-line-update-fetch))
+ (advice-add #'mastodon-notifications--timeline :before
+ #'my/mastodon-notifications--timeline-before)
+ (add-hook 'kill-emacs-hook #'my/mastodon-mode-line-persist-meta))
+ (setq mode-line-misc-info (delete '(:eval my/mastodon-mode-string)
+ mode-line-misc-info))
+ (advice-remove #'mastodon-notifications--timeline
+ #'my/mastodon-notifications--timeline-before)
+ (remove-hook 'kill-emacs-hook #'my/mastodon-mode-line-persist-meta)
+ (my/mastodon-mode-line-persist-meta)))))
Timeline Transient
The default mastodon-tl--get-home-timeline allows only to hide replies, and not boosted posts.
So here’s a custom update function:
(defun my/mastodon-get-update-funciton (hide-replies hide-boosts)
(lambda (toots)
(let* ((is-profile (eq (mastodon-tl--get-buffer-type) 'profile-statuses))
- (hide-replies (and (not is-profile) hide-replies))
- (hide-boosts (and (not is-profile) hide-boosts))
- (toots (seq-filter
- (lambda (toot)
- (and
- (or (not hide-replies)
- (not (mastodon-tl--is-reply toot)))
- (or (not hide-boosts)
- (not (alist-get 'reblog toot)))))
- toots))
- (start-pos (point)))
+ (hide-replies (and (not is-profile) hide-replies))
+ (hide-boosts (and (not is-profile) hide-boosts))
+ (toots (seq-filter
+ (lambda (toot)
+ (and
+ (or (not hide-replies)
+ (not (mastodon-tl--is-reply toot)))
+ (or (not hide-boosts)
+ (not (alist-get 'reblog toot)))))
+ toots))
+ (start-pos (point)))
(mapc #'mastodon-tl--toot toots)
(when mastodon-tl--display-media-p
- (save-excursion
- (mastodon-media--inline-images start-pos (point)))))))
+ (save-excursion
+ (mastodon-media--inline-images start-pos (point)))))))
In order to use it, the function has to be passed to mastodon-tl--init:
(defun my/mastodon-tl--get-home (hide-replies hide-boosts)
(mastodon-tl--init
@@ -8815,15 +9024,15 @@ Didn’t work out as I expected, so I’ve made org-journal-tags
["Timelines"
:class transient-row
("t" "Home" (lambda (args)
- (interactive (list (transient-args transient-current-command)))
- (my/mastodon-tl--get-home
- (seq-contains-p args "--hide-replies")
- (seq-contains-p args "--hide-boosts"))))
- ("l" "Local" mastodon-tl--get-local-timeline)
- ("f" "Federated" mastodon-tl--get-federated-timeline)
- ("g" "One tag" mastodon-tl--get-tag-timeline)
- ("a" "Followed tags" mastodon-tl--followed-tags-timeline)
- ("s" "Some followed tags" mastodon-tl--some-followed-tags-timeline)]
+ (interactive (list (transient-args transient-current-command)))
+ (my/mastodon-tl--get-home
+ (seq-contains-p args "--hide-replies")
+ (seq-contains-p args "--hide-boosts"))))
+ ("l" "Local" mastodon-tl-get-local-timeline)
+ ("f" "Federated" mastodon-tl-get-federated-timeline)
+ ("g" "One tag" mastodon-tl-get-tag-timeline)
+ ("a" "Followed tags" mastodon-tl-followed-tags-timeline)
+ ("s" "Some followed tags" mastodon-tl-some-followed-tags-timeline)]
["Misc"
:class transient-row
("q" "Quit" transient-quit-one)]))
@@ -8839,26 +9048,26 @@ Didn’t work out as I expected, so I’ve made org-journal-tags
("m" "Mastodon" mastodon)
("t" "Timelines" my/mastodon-tl)
("n" "Notifications" mastodon-notifications-get)
- ("s" "Search query" mastodon-search--query)]
+ ("s" "Search query" mastodon-search-query)]
["Tags"
:class transient-row
- ("aa" "Followed tags" mastodon-tl--list-followed-tags)
- ("af" "Follow tag" mastodon-tl--follow-tag)
- ("aF" "Unfollow tag" mastodon-tl--unfollow-tag)]
+ ("aa" "Followed tags" mastodon-tl-list-followed-tags)
+ ("af" "Follow tag" mastodon-tl-follow-tag)
+ ("aF" "Unfollow tag" mastodon-tl-unfollow-tag)]
["Own profile"
:class transient-row
("c" "Toot" mastodon-toot)
- ("o" "My profile" mastodon-profile--my-profile)
- ("u" "Update profile note" mastodon-profile--update-user-profile-note)
- ("f" "Favourites" mastodon-profile--view-favourites)
- ("b" "Bookmarks" mastodon-profile--view-bookmarks)]
+ ("o" "My profile" mastodon-profile-my-profile)
+ ("u" "Update profile note" mastodon-profile-update-user-profile-note)
+ ("f" "Favourites" mastodon-profile-view-favourites)
+ ("b" "Bookmarks" mastodon-profile-view-bookmarks)]
["Minor views"
:class transient-row
- ("F" "Follow requests" mastodon-views--view-follow-requests)
- ("S" "Scheduled toots" mastodon-views--view-scheduled-toots)
- ("I" "Filters" mastodon-views--view-filters)
- ("G" "Follow suggestions" mastodon-views--view-follow-suggestions)
- ("L" "Lists" mastodon-views--view-lists)]
+ ("F" "Follow requests" mastodon-views-view-follow-requests)
+ ("S" "Scheduled toots" mastodon-views-view-scheduled-toots)
+ ("I" "Filters" mastodon-views-view-filters)
+ ("G" "Follow suggestions" mastodon-views-view-follow-suggestions)
+ ("L" "Lists" mastodon-views-view-lists)]
["Misc"
:class transient-row
("/" "Switch to buffer" mastodon-switch-to-buffer)
@@ -8879,60 +9088,60 @@ Didn’t work out as I expected, so I’ve made org-journal-tags
base toot."
(interactive)
(let* ((toot (or (mastodon-tl--property 'base-toot)
- (mastodon-tl--property 'toot-json)))
- (url (if (mastodon-tl--field 'reblog toot)
- (alist-get 'url (alist-get 'reblog toot))
- (alist-get 'url toot))))
+ (mastodon-tl--property 'toot-json)))
+ (url (if (mastodon-tl--field 'reblog toot)
+ (alist-get 'url (alist-get 'reblog toot))
+ (alist-get 'url toot))))
(browse-url url)))
And the prefix itself:
(with-eval-after-load 'mastodon
- (my/def-confirmer mastodon-toot--toggle-boost "Toggle boost for this post? ")
- (my/def-confirmer mastodon-toot--toggle-favourite "Toggle favourite this post? ")
- (my/def-confirmer mastodon-toot--toggle-bookmark "Toggle bookmark this post? ")
- (my/def-confirmer mastodon-tl--follow-user "Follow this user? ")
- (my/def-confirmer mastodon-tl--unfollow-user "Unfollow this user? ")
- (my/def-confirmer mastodon-tl--block-user "Block this user? ")
- (my/def-confirmer mastodon-tl--unblock-user "Unblock this user? ")
- (my/def-confirmer mastodon-tl--mute-user "Mute this user? ")
- (my/def-confirmer mastodon-tl--unmute-user "Unmute this user? ")
- (my/def-confirmer mastodon-tl--unmute-user "Unmute this user? ")
+ (my/def-confirmer mastodon-toot-toggle-boost "Toggle boost for this post? ")
+ (my/def-confirmer mastodon-toot-toggle-favourite "Toggle favourite this post? ")
+ (my/def-confirmer mastodon-toot-toggle-bookmark "Toggle bookmark this post? ")
+ (my/def-confirmer mastodon-tl-follow-user "Follow this user? ")
+ (my/def-confirmer mastodon-tl-unfollow-user "Unfollow this user? ")
+ (my/def-confirmer mastodon-tl-block-user "Block this user? ")
+ (my/def-confirmer mastodon-tl-unblock-user "Unblock this user? ")
+ (my/def-confirmer mastodon-tl-mute-user "Mute this user? ")
+ (my/def-confirmer mastodon-tl-unmute-user "Unmute this user? ")
+ (my/def-confirmer mastodon-tl-unmute-user "Unmute this user? ")
(transient-define-prefix my/mastodon-toot ()
"Mastodon toot actions."
["View"
:class transient-row
- ("o" "Thread" mastodon-tl--thread)
+ ("o" "Thread" mastodon-tl-thread)
("w" "Browser" my/mastodon-toot--browse)
- ("le" "List edits" mastodon-toot--view-toot-edits)
- ("lf" "List favouriters" mastodon-toot--list-favouriters)
- ("lb" "List boosters" mastodon-toot--list-boosters)]
+ ("le" "List edits" mastodon-toot-view-toot-edits)
+ ("lf" "List favouriters" mastodon-toot-list-favouriters)
+ ("lb" "List boosters" mastodon-toot-list-boosters)]
["Toot Actions"
:class transient-row
- ("r" "Reply" mastodon-toot--reply)
- ("v" "Vote" mastodon-tl--poll-vote)
+ ("r" "Reply" mastodon-toot-reply)
+ ("v" "Vote" mastodon-tl-poll-vote)
("b" "Boost" my/mastodon-toot--toggle-boost-confirm)
("f" "Favourite" my/mastodon-toot--toggle-favourite-confirm)
("k" "Bookmark" my/mastodon-toot--toggle-bookmark-confirm)]
["My Toot Actions"
:class transient-row
- ("md" "Delete" mastodon-toot--delete-toot)
- ("mD" "Delete and redraft" mastodon-toot--delete-and-redraft-toot)
- ("mp" "Pin" mastodon-toot--pin-toot-toggle)
- ("me" "Edit" mastodon-toot--edit-toot-at-point)]
+ ("md" "Delete" mastodon-toot-delete-toot)
+ ("mD" "Delete and redraft" mastodon-toot-delete-and-redraft-toot)
+ ("mp" "Pin" mastodon-toot-pin-toot-toggle)
+ ("me" "Edit" mastodon-toot-edit-toot-at-point)]
["Profile Actions"
:class transient-row
- ("pp" "Profile" mastodon-profile--show-user)
- ("pf" "List followers" mastodon-profile--open-followers)
- ("pF" "List following" mastodon-profile--open-following)
- ("ps" "List statues (no reblogs)" mastodon-profile--open-statuses-no-reblogs)]
+ ("pp" "Profile" mastodon-profile-show-user)
+ ("pf" "List followers" mastodon-profile-open-followers)
+ ("pF" "List following" mastodon-profile-open-following)
+ ("ps" "List statues (no reblogs)" mastodon-profile-open-statuses-no-reblogs)]
["User Actions"
:class transient-row
- ("uf" "Follow user" my/mastodon-tl--follow-user-confirm)
- ("uF" "Unfollow user" my/mastodon-tl--unfollow-user-confirm)
- ("ub" "Block user" my/mastodon-tl--block-user-confirm)
- ("uB" "Unblock user" my/mastodon-tl--unblock-user-confirm)
- ("um" "Mute user" my/mastodon-tl--mute-user-confirm)
- ("uB" "Unmute user" my/mastodon-tl--unmute-user-confirm)]
+ ("uf" "Follow user" my/mastodon-tl-follow-user-confirm)
+ ("uF" "Unfollow user" my/mastodon-tl-unfollow-user-confirm)
+ ("ub" "Block user" my/mastodon-tl-block-user-confirm)
+ ("uB" "Unblock user" my/mastodon-tl-unblock-user-confirm)
+ ("um" "Mute user" my/mastodon-tl-mute-user-confirm)
+ ("uB" "Unmute user" my/mastodon-tl-unmute-user-confirm)]
["Misc"
:class transient-row
("q" "Quit" transient-quit-one)]))
@@ -8940,8 +9149,7 @@ Didn’t work out as I expected, so I’ve made org-journal-tags
wallabag is a self-hosted “read it later” app.
This might be the best online reading advice I’ve heard:
-I have a different approach: waiting periods. Every time I come across something I may want to read/watch, I’m totally allowed to. No limits! The only requirement is I have to save it to Pocket, and then choose to consume it at a later time.
-
+I have a different approach: waiting periods. Every time I come across something I may want to read/watch, I’m totally allowed to. No limits! The only requirement is I have to save it to Pocket, and then choose to consume it at a later time.
Source: Tiago Forte - The Secret Power of ‘Read It Later’ Apps
(use-package wallabag
:straight (:host github :repo "chenyanming/wallabag.el" :files (:defaults "default.css" "emojis.alist"))
@@ -8993,18 +9201,18 @@ Didn’t work out as I expected, so I’ve made org-journal-tags
(set-face-attribute 'ement-room-reactions-key nil :height 'unspecified)
(set-face-attribute 'ement-room-timestamp nil :inherit 'font-lock-function-name-face)
(set-face-attribute 'ement-room-membership nil :height 0.9
- :inherit 'font-lock-warning-face)
+ :inherit 'font-lock-warning-face)
(set-face-attribute 'ement-room-wrap-prefix nil :inherit 'unspecified)
(set-face-attribute 'ement-room-timestamp-header nil :height 'unspecified)
(set-face-attribute 'ement-room-wrap-prefix nil :inherit 'unspecified)
;; Notify only on mentions
(setq ement-notify-notification-predicates
- '(ement-notify--event-mentions-session-user-p
- ement-notify--event-mentions-room-p
- ement-notify--room-unread-p))
+ '(ement-notify--event-mentions-session-user-p
+ ement-notify--event-mentions-room-p
+ ement-notify--room-unread-p))
;; Fix the anti-synergy with major mode re-activation in `ement-room-list-revert'
(advice-add #'ement-room-list-revert
- :around #'my/perspective-assign-ignore-advice))
+ :around #'my/perspective-assign-ignore-advice))
Keybindings
Some custom keymaps for room lists:
(with-eval-after-load 'ement-room-list
@@ -9025,14 +9233,14 @@ Didn’t work out as I expected, so I’ve made org-journal-tags
"q" #'quit-window))
(defun my/ement-room-send-reaction (key position)
(interactive (list
- (completing-read "Add reaction: " (append telega-emoji-reaction-list '("👋")))
- (point)))
+ (completing-read "Add reaction: " (append telega-emoji-reaction-list '("👋")))
+ (point)))
(ement-room-send-reaction key position))
(defun my/ement-room-compose-quit ()
(interactive)
(when (or (string-empty-p (buffer-string))
- (y-or-n-p "Quit compose? "))
+ (y-or-n-p "Quit compose? "))
(quit-window t)))
(defun my/ement-room-compose-setup ()
@@ -9086,16 +9294,15 @@ Didn’t work out as I expected, so I’ve made org-journal-tags
Scroll to the previous mention.
alphapapa 🐃> And, yes, that is a currently unsolved problem. As I said, in the future we can try using a different API endpoint to access those notifications similarly to Element. In the meantime, you can load old messages (e.g. “C-u 1000 M-v” to load 1000 old ones at a time), until you find it, maybe using “C-s sqrtm” to search for messages mentioning you.
-Or you can load up Element for a moment to see what the mention was, if that’s easier.
-
+Or you can load up Element for a moment to see what the mention was, if that’s easier.
(defun my/ement-about-me-p (event)
(let ((me (ement-user-id (ement-session-user ement-session))))
(or
(equal (ement-user-id (ement-event-sender event)) me)
(when-let ((formatted-body
- (alist-get
- 'formatted_body
- (ement-event-content event))))
+ (alist-get
+ 'formatted_body
+ (ement-event-content event))))
(string-match-p me formatted-body)))))
(defun my/ement-scroll-to-previous-about-me ()
@@ -9104,20 +9311,20 @@ Didn’t work out as I expected, so I’ve made org-journal-tags
(when (< (line-number-at-pos) 20)
(forward-line 20))
(if ement-room-retro-loading
- (run-with-timer 0.5 nil #'my/ement-scroll-to-previous-about-me)
+ (run-with-timer 0.5 nil #'my/ement-scroll-to-previous-about-me)
(while (let ((event (ewoc-data (ewoc-locate ement-ewoc))))
- (and
- (not ement-room-retro-loading)
- (or
- (not (ement-event-p event))
- (not (my/ement-about-me-p event)))))
- (condition-case _err
- (scroll-down 1)
- (beginning-of-buffer
- (call-interactively #'ement-room-retro)
- (run-with-timer 0.5 nil #'my/ement-scroll-to-previous-about-me)))
- (cl-incf scrolled)
- (message "Scrolled %s" scrolled)))))
+ (and
+ (not ement-room-retro-loading)
+ (or
+ (not (ement-event-p event))
+ (not (my/ement-about-me-p event)))))
+ (condition-case _err
+ (scroll-down 1)
+ (beginning-of-buffer
+ (call-interactively #'ement-room-retro)
+ (run-with-timer 0.5 nil #'my/ement-scroll-to-previous-about-me)))
+ (cl-incf scrolled)
+ (message "Scrolled %s" scrolled)))))
Telega
telega.el is a Telegam client for Emacs.
@@ -9148,17 +9355,19 @@ Didn’t work out as I expected, so I’ve made org-journal-tags
(my-leader-def "a l" (my/command-in-persp "telega" "telega" 3 (telega)))
(my/use-colors
(telega-button-active :foreground (my/color-value 'base0)
- :background (my/color-value 'cyan))
+ :background (my/color-value 'cyan))
(telega-webpage-chat-link :foreground (my/color-value 'base0)
- :background (my/color-value 'fg)))
+ :background (my/color-value 'fg))
+ (telega-entity-type-spoiler :background (my/color-value 'base8)))
:config
- (when (file-directory-p "~/.guix-extra-profiles/emacs/")
+ (when (file-exists-p "~/.guix-extra-profiles/emacs/emacs/bin/telega-server")
(setq telega-server-command
- (expand-file-name
- "~/.guix-extra-profiles/emacs/emacs/bin/telega-server")))
+ (expand-file-name
+ "~/.guix-extra-profiles/emacs/emacs/bin/telega-server")))
(setq telega-emoji-use-images nil)
(setq telega-chat-fill-column 80)
(setq telega-completing-read-function #'completing-read)
+ (setq telega-sticker-size '(12 . 24))
(add-to-list 'savehist-additional-variables 'telega-msg-add-reaction)
(remove-hook 'telega-chat-mode-hook #'telega-chat-auto-fill-mode)
(general-define-key
@@ -9180,72 +9389,72 @@ Didn’t work out as I expected, so I’ve made org-journal-tags
(defun my/telega-server-build ()
(interactive)
(setq telega-server-libs-prefix
- (if (executable-find "guix")
- (string-trim
- (shell-command-to-string "guix build tdlib"))
- (expand-file-name "~/bin/td/build/res/usr/local")))
+ (if (executable-find "guix")
+ (string-trim
+ (shell-command-to-string "guix build tdlib"))
+ (expand-file-name "~/bin/td/build/res/usr/local")))
(telega-server-build "CC=gcc"))
Setting up the modeline. The default mode string doesn’t look great with my other modeline modules, so I override that.
(add-hook 'telega-load-hook #'telega-mode-line-mode)
(setq telega-mode-line-string-format
'("["
- (:eval
- (telega-mode-line-online-status))
- (:eval
- (when telega-use-tracking-for
- (telega-mode-line-tracking)))
- (:eval
- (telega-mode-line-unread-unmuted))
- (:eval
- (telega-mode-line-mentions 'messages))
- "]"))
+ (:eval
+ (telega-mode-line-online-status))
+ (:eval
+ (when telega-use-tracking-for
+ (telega-mode-line-tracking)))
+ (:eval
+ (telega-mode-line-unread-unmuted))
+ (:eval
+ (telega-mode-line-mentions 'messages))
+ "]"))
Configuring company backends for the chat buffer, as recommended in the manual:
(defun my/telega-chat-setup ()
(interactive)
(set (make-local-variable 'company-backends)
(append (list 'telega-company-emoji
- 'telega-company-username
- 'telega-company-hashtag
- 'telega-company-markdown-precode)
- (when (telega-chat-bot-p telega-chatbuf--chat)
- '(telega-company-botcmd))))
+ 'telega-company-username
+ 'telega-company-hashtag
+ 'telega-company-markdown-precode)
+ (when (telega-chat-bot-p telega-chatbuf--chat)
+ '(telega-company-botcmd))))
(company-mode 1)
(setopt visual-fill-column-width
- (+ telega-chat-fill-column
- (if (display-graphic-p) 5 6)))
+ (+ telega-chat-fill-column
+ (if (display-graphic-p) 5 6)))
(setq-local split-width-threshold 1))
(add-hook 'telega-chat-mode-hook #'my/telega-chat-setup)
And custom online status. By default it marks you online when the Emacs frame is active, but I use EXWM, so I change that to when telega.el buffer is active. Otherwise, I’m online all the time.
(defun my/telega-online-status ()
(derived-mode-p 'telega-root-mode 'telega-chat-mode
- 'telega-image-mode 'telega-webpage-mode))
+ 'telega-image-mode 'telega-webpage-mode))
(setq telega-online-status-function #'my/telega-online-status)
Switch to topic in forum chats.
(defun my/telega-switch-to-topic ()
(interactive)
(let* ((topics-data (gethash
- (plist-get telega-chatbuf--chat :id)
- telega--chat-topics))
- (topics-string
- (mapcar
- (lambda (topic)
- (let* ((name (plist-get (plist-get topic :info) :name))
- (unread-count (plist-get topic :unread_count))
- (name-string (with-temp-buffer
- (telega-ins--topic-title topic 'with-icon)
- (buffer-string))))
- (if (zerop unread-count)
- name-string
- (format "%-40s (%s)"
- name-string
- (propertize (format "%d" unread-count)
- 'face 'telega-unread-unmuted-modeline)))))
- topics-data))
- (topics-collection (cl-loop for datum in topics-data
- for string in topics-string
- collect (cons string datum)))
- (topic (completing-read "Topic: " topics-collection nil t)))
+ (plist-get telega-chatbuf--chat :id)
+ telega--chat-topics))
+ (topics-string
+ (mapcar
+ (lambda (topic)
+ (let* ((name (plist-get (plist-get topic :info) :name))
+ (unread-count (plist-get topic :unread_count))
+ (name-string (with-temp-buffer
+ (telega-ins--topic-title topic 'with-icon)
+ (buffer-string))))
+ (if (zerop unread-count)
+ name-string
+ (format "%-40s (%s)"
+ name-string
+ (propertize (format "%d" unread-count)
+ 'face 'telega-unread-unmuted-modeline)))))
+ topics-data))
+ (topics-collection (cl-loop for datum in topics-data
+ for string in topics-string
+ collect (cons string datum)))
+ (topic (completing-read "Topic: " topics-collection nil t)))
(telega-chat--goto-thread
telega-chatbuf--chat
(plist-get
@@ -9273,10 +9482,10 @@ Didn’t work out as I expected, so I’ve made org-journal-tags
:if (not my/remote-server)
:functions (my-google-translate-at-point google-translate--search-tkk)
:commands (google-translate-at-point
- google-translate-at-point-reverse
- google-translate-query-translate
- google-translate-query-translate-reverse
- google-translate-smooth-translate)
+ google-translate-at-point-reverse
+ google-translate-query-translate
+ google-translate-query-translate-reverse
+ google-translate-smooth-translate)
:custom
(google-translate-backend-method 'curl)
:config
@@ -9288,13 +9497,13 @@ Didn’t work out as I expected, so I’ve made org-journal-tags
"reverse translate if prefix"
(interactive)
(if current-prefix-arg
- (google-translate-at-point)
+ (google-translate-at-point)
(google-translate-at-point-reverse)))
(setq google-translate-translation-directions-alist
- '(("en" . "ru")
- ("ru" . "en")
- ("de" . "en")
- ("en" . "de"))))
+ '(("en" . "ru")
+ ("ru" . "en")
+ ("de" . "en")
+ ("en" . "de"))))
(my-leader-def
:infix "at"
@@ -9316,9 +9525,9 @@ Didn’t work out as I expected, so I’ve made org-journal-tags
(setq biome-api-try-parse-error-as-response t))
:config
(add-to-list 'biome-query-coords
- '("Saint-Petersburg, Russia" 59.942651 30.229930))
+ '("Saint-Petersburg, Russia" 59.942651 30.229930))
(add-to-list 'biome-query-coords
- '("Tyumen, Russia" 57.15222 65.52722)))
+ '("Tyumen, Russia" 57.15222 65.52722)))
Reading documentation
tldr
tldr is a collaborative project providing cheatsheets for various console commands. For some reason, the built-in download in the package is broken, so I use my own function.
@@ -9364,13 +9573,13 @@ Didn’t work out as I expected, so I’ve made org-journal-tags
(use-package devdocs-browser
:straight t
:commands (devdocs-browser-open
- devdocs-browser-open-in
- devdocs-browser-install-doc
- devdocs-browser-uninstall-doc
- devdocs-browser-download-offline-data
- devdocs-browser-remove-offline-data
- devdocs-browser-upgrade-all-docs
- devdocs-browser-update-docs)
+ devdocs-browser-open-in
+ devdocs-browser-install-doc
+ devdocs-browser-uninstall-doc
+ devdocs-browser-download-offline-data
+ devdocs-browser-remove-offline-data
+ devdocs-browser-upgrade-all-docs
+ devdocs-browser-update-docs)
:init
(my-leader-def
:infix "hd"
@@ -9434,7 +9643,7 @@ Didn’t work out as I expected, so I’ve made org-journal-tags
"hS" #'sx-tab-frontpage)
(my/use-colors
(sx-question-mode-accepted :foreground (my/color-value 'green)
- :weight 'bold)
+ :weight 'bold)
(sx-question-mode-content :background nil))
(add-hook 'sx-question-mode-hook #'doom-modeline-mode)
(add-hook 'sx-question-list-mode-hook #'doom-modeline-mode))
@@ -9456,28 +9665,34 @@ Didn’t work out as I expected, so I’ve made org-journal-tags
:commands (gptel gptel-send gptel-menu)
:config
(setq gptel-mode "llama3:latest")
- (setq gptel-backend (gptel-make-ollama "Ollama"
- :host "localhost:11434"
- :stream t
- :models '("llama3.1:8b" "deepseek-r1:32b"
- "qwen2.5:32b" "qwen2.5-coder:32b"
- "eva-qwen2.5-q4_k_l-32b:latest"
- "t-pro-1.0-q4_k_m:latest")))
+ (setq gptel-track-media t)
+ (setq gptel-backend
+ (gptel-make-ollama "Ollama"
+ :host "localhost:11434"
+ :stream t
+ :models '("llama3.1:8b" "deepseek-r1:32b"
+ "qwen2.5:32b" "qwen2.5-coder:32b"
+ "eva-qwen2.5-q4_k_l-32b:latest"
+ "t-pro-1.0-q4_k_m:latest"
+ "qwq:32b"
+ (gemma3:32b
+ :capabilities (media)
+ :mime-types ("image/jpeg" "image/png")))))
(gptel-make-openai "OpenRouter"
:host "openrouter.ai/api"
:key (lambda () (my/password-store-get-field
- "My_Online/Accounts/openrouter" "api-key"))
+ "My_Online/Accounts/openrouter" "api-key"))
:stream t
:models '("anthropic/claude-3.5-haiku"))
(setq gptel--known-backends
- (seq-filter
- (lambda (cell)
- (not (equal (car cell) "ChatGPT")))
- gptel--known-backends))
+ (seq-filter
+ (lambda (cell)
+ (not (equal (car cell) "ChatGPT")))
+ gptel--known-backends))
(setq gptel-response-prefix-alist
- '((markdown-mode . "[Response] ")
- (org-mode . "*** Response: ")
- (text-mode . "[Response]")))
+ '((markdown-mode . "[Response] ")
+ (org-mode . "*** Response: ")
+ (text-mode . "[Response]")))
(general-define-key
:keymaps '(gptel-mode-map)
@@ -9497,24 +9712,24 @@ Didn’t work out as I expected, so I’ve made org-journal-tags
(setq ellama-long-lines-length 100000)
(setq ellama-provider (make-llm-ollama
- :chat-model "qwen2.5:32b"
- :embedding-model "qwen2.5:32b"))
+ :chat-model "qwen2.5:32b"
+ :embedding-model "qwen2.5:32b"))
(setq ellama-coding-provider (make-llm-ollama
- :chat-model "qwen2.5-coder:32b"
- :embedding-model "qwen2.5-coder:32b"))
+ :chat-model "qwen2.5-coder:32b"
+ :embedding-model "qwen2.5-coder:32b"))
(setq ellama-providers
- `(("llama3.1:8b" . ,(make-llm-ollama
- :chat-model "llama3.1:latest"
- :embedding-model "llama3.1:latest"))
- ("phi4:latest" . ,(make-llm-ollama
- :chat-model "phi4:latest"
- :embedding-model "phi4:latest"))
- ("qwen2.5:32b" . ,(make-llm-ollama
- :chat-model "qwen2.5:32b"
- :embedding-model "qwen2.5:32b"))
- ("qwen2.5-coder:32b" . ,(make-llm-ollama
- :chat-model "qwen2.5-coder:32b"
- :embedding-model "qwen2.5-coder:32b")))))
+ `(("llama3.1:8b" . ,(make-llm-ollama
+ :chat-model "llama3.1:latest"
+ :embedding-model "llama3.1:latest"))
+ ("phi4:latest" . ,(make-llm-ollama
+ :chat-model "phi4:latest"
+ :embedding-model "phi4:latest"))
+ ("qwen2.5:32b" . ,(make-llm-ollama
+ :chat-model "qwen2.5:32b"
+ :embedding-model "qwen2.5:32b"))
+ ("qwen2.5-coder:32b" . ,(make-llm-ollama
+ :chat-model "qwen2.5-coder:32b"
+ :embedding-model "qwen2.5-coder:32b")))))
The keybindings are a bit crazy to use even with which-key, so here goes transient.el.
(with-eval-after-load 'ellama
(transient-define-prefix my/ellama-transient ()
@@ -9568,18 +9783,18 @@ Didn’t work out as I expected, so I’ve made org-journal-tags
So first, I need to diff two strings.
(defun my/diff-strings (str1 str2)
(let ((file1 (make-temp-file "diff1"))
- (file2 (make-temp-file "diff2")))
+ (file2 (make-temp-file "diff2")))
(unwind-protect
- (progn
- (with-temp-file file1
- (insert str1))
- (with-temp-file file2
- (insert str2))
- (with-temp-buffer
- (diff-mode)
- (diff-no-select file1 file2 (diff-switches) t (current-buffer))
- (font-lock-fontify-buffer)
- (buffer-string)))
+ (progn
+ (with-temp-file file1
+ (insert str1))
+ (with-temp-file file2
+ (insert str2))
+ (with-temp-buffer
+ (diff-mode)
+ (diff-no-select file1 file2 (diff-switches) t (current-buffer))
+ (font-lock-fontify-buffer)
+ (buffer-string)))
(delete-file file1)
(delete-file file2))))
And the function to do the prompting iself. Llama tends to output in Markdown, so I use a function from Ellama to convert the output back to Org-mode, if necessary.
@@ -9590,22 +9805,22 @@ Didn’t work out as I expected, so I’ve made org-journal-tags
(format prompt text))
(lambda (response)
(let* ((parts (split-string response "-FIXED TEXT ENDS-"))
- (changed-text (nth 0 parts))
- (comments (nth 1 parts))
- (buffer (generate-new-buffer "*ellama-diff*")))
+ (changed-text (nth 0 parts))
+ (comments (nth 1 parts))
+ (buffer (generate-new-buffer "*ellama-diff*")))
(when is-org-mode
- (setq changed-text (ellama--translate-markdown-to-org-filter changed-text)))
+ (setq changed-text (ellama--translate-markdown-to-org-filter changed-text)))
(with-current-buffer buffer
- (text-mode)
- (insert
- (propertize "Changed text:\n" 'face 'transient-heading)
- (string-trim changed-text)
- "\n\n"
- (propertize "Comments:\n" 'face 'transient-heading)
- (string-trim comments)
- "\n\n"
- (propertize "Diff:\n" 'face 'transient-heading)
- (my/diff-strings text changed-text)))
+ (text-mode)
+ (insert
+ (propertize "Changed text:\n" 'face 'transient-heading)
+ (string-trim changed-text)
+ "\n\n"
+ (propertize "Comments:\n" 'face 'transient-heading)
+ (string-trim comments)
+ "\n\n"
+ (propertize "Diff:\n" 'face 'transient-heading)
+ (my/diff-strings text changed-text)))
(display-buffer buffer)))
(lambda (&rest err)
(message "Error: %s" err))))
@@ -9626,8 +9841,8 @@ Didn’t work out as I expected, so I’ve made org-journal-tags
(defun my/ellama--text ()
(if (region-active-p)
- (buffer-substring-no-properties (region-beginning) (region-end))
- (buffer-substring-no-properties (point-min) (point-max))))
+ (buffer-substring-no-properties (region-beginning) (region-end))
+ (buffer-substring-no-properties (point-min) (point-max))))
(defun my/ellama-proof-read (text is-org-mode)
(interactive (list (my/ellama--text) (derived-mode-p 'org-mode)))
@@ -9672,51 +9887,51 @@ Didn’t work out as I expected, so I’ve made org-journal-tags
(defun my/whisper--format-vtt-seconds (seconds)
(if (numberp seconds)
(let* ((hours (/ (floor seconds) (* 60 60)))
- (minutes (/ (- (floor seconds) (* hours 60 60)) 60))
- (sec (% (floor seconds) 60))
- (ms (floor (* 1000 (- seconds (floor seconds))))))
- (format "%.2d:%.2d:%.2d.%.3d" hours minutes sec ms))
+ (minutes (/ (- (floor seconds) (* hours 60 60)) 60))
+ (sec (% (floor seconds) 60))
+ (ms (floor (* 1000 (- seconds (floor seconds))))))
+ (format "%.2d:%.2d:%.2d.%.3d" hours minutes sec ms))
""))
(defun my/whisper--save-chucks-vtt (path data)
(with-temp-file path
(insert "WEBVTT\n\n")
(cl-loop for chunk across (alist-get 'chunks data)
- for start = (my/whisper--format-vtt-seconds
- (aref (alist-get 'timestamp chunk) 0))
- for end = (my/whisper--format-vtt-seconds
- (aref (alist-get 'timestamp chunk) 1))
- do (insert (format "%s --> %s" start end) "\n")
- do (insert (string-trim (alist-get 'text chunk)) "\n\n"))))
+ for start = (my/whisper--format-vtt-seconds
+ (aref (alist-get 'timestamp chunk) 0))
+ for end = (my/whisper--format-vtt-seconds
+ (aref (alist-get 'timestamp chunk) 1))
+ do (insert (format "%s --> %s" start end) "\n")
+ do (insert (string-trim (alist-get 'text chunk)) "\n\n"))))
(defun my/whisper--save-speakers-vtt (path data)
(with-temp-file path
(insert "WEBVTT\n\n")
(cl-loop for chunk across (alist-get 'speakers data)
- for start = (my/whisper--format-vtt-seconds
- (aref (alist-get 'timestamp chunk) 0))
- for end = (my/whisper--format-vtt-seconds
- (aref (alist-get 'timestamp chunk) 1))
- do (insert (format "%s --> %s" start end) "\n")
- do (insert
- (format "<v %s>" (alist-get 'speaker chunk))
- (string-trim (alist-get 'text chunk)) "\n\n"))))
+ for start = (my/whisper--format-vtt-seconds
+ (aref (alist-get 'timestamp chunk) 0))
+ for end = (my/whisper--format-vtt-seconds
+ (aref (alist-get 'timestamp chunk) 1))
+ do (insert (format "%s --> %s" start end) "\n")
+ do (insert
+ (format "<v %s>" (alist-get 'speaker chunk))
+ (string-trim (alist-get 'text chunk)) "\n\n"))))
(defun my/whisper--save-speakers-txt (path data)
(with-temp-file path
(cl-loop with prev-speaker
- for chunk across (alist-get 'speakers data)
- for speaker = (alist-get 'speaker chunk)
- if (not (equal speaker prev-speaker))
- do (progn
- (when prev-speaker
- (fill-region
- (line-beginning-position)
- (line-end-position))
- (insert "\n\n"))
- (insert (format "[%s]" speaker) "\n")
- (setq prev-speaker speaker))
- do (insert (string-trim (alist-get 'text chunk)) " "))
+ for chunk across (alist-get 'speakers data)
+ for speaker = (alist-get 'speaker chunk)
+ if (not (equal speaker prev-speaker))
+ do (progn
+ (when prev-speaker
+ (fill-region
+ (line-beginning-position)
+ (line-end-position))
+ (insert "\n\n"))
+ (insert (format "[%s]" speaker) "\n")
+ (setq prev-speaker speaker))
+ do (insert (string-trim (alist-get 'text chunk)) " "))
(fill-region
(line-beginning-position)
(line-end-position))))
@@ -9725,10 +9940,10 @@ Didn’t work out as I expected, so I’ve made org-journal-tags
(let ((data (json-read-file transcript-path)))
(when (alist-get 'text data)
(with-temp-file (concat
- (file-name-sans-extension transcript-path)
- ".txt")
- (insert (string-trim (alist-get 'text data)))
- (do-auto-fill)))
+ (file-name-sans-extension transcript-path)
+ ".txt")
+ (insert (string-trim (alist-get 'text data)))
+ (do-auto-fill)))
(unless (seq-empty-p (alist-get 'speakers data))
(my/whisper--save-speakers-vtt
(concat (file-name-sans-extension transcript-path) "-spk.vtt")
@@ -9752,36 +9967,36 @@ Didn’t work out as I expected, so I’ve made org-journal-tags
(if (string-empty-p lang) nil lang))
(let ((num (read-number "Number of speakers (optional): " 0)))
(when (> num 0)
- (number-to-string num)))))
+ (number-to-string num)))))
(let* ((transcript-path (concat
- (expand-file-name (file-name-as-directory output-dir))
- (file-name-base input)
- ".json"))
- (args
- `("--file-name" ,(expand-file-name input)
- "--transcript-path" ,transcript-path
- "--hf-token" ,(my/password-store-get-field "My_Online/Accounts/huggingface.co" "token")
- ,@(when language
- `("--language" ,language))
- ,@(when num-speakers
- `("--num-speakers" ,num-speakers))))
- (buffer (generate-new-buffer "*whisper*"))
- (proc (apply #'start-process "whisper" buffer my/whisper-path args)))
+ (expand-file-name (file-name-as-directory output-dir))
+ (file-name-base input)
+ ".json"))
+ (args
+ `("--file-name" ,(expand-file-name input)
+ "--transcript-path" ,transcript-path
+ "--hf-token" ,(my/password-store-get-field "My_Online/Accounts/huggingface.co" "token")
+ ,@(when language
+ `("--language" ,language))
+ ,@(when num-speakers
+ `("--num-speakers" ,num-speakers))))
+ (buffer (generate-new-buffer "*whisper*"))
+ (proc (apply #'start-process "whisper" buffer my/whisper-path args)))
(set-process-sentinel
proc
(lambda (process _msg)
(let ((status (process-status process))
- (code (process-exit-status process)))
- (cond ((and (eq status 'exit) (= code 0))
- (my/whisper--process-output transcript-path)
- (notifications-notify :body "Audio conversion completed"
- :title "Whisper")
- (kill-buffer (process-buffer process)))
- ((or (and (eq status 'exit) (> code 0))
- (eq status 'signal))
- (let ((err (with-current-buffer (process-buffer process)
- (buffer-string))))
- (user-error "Error in Whisper: %s" err)))))))))
+ (code (process-exit-status process)))
+ (cond ((and (eq status 'exit) (= code 0))
+ (my/whisper--process-output transcript-path)
+ (notifications-notify :body "Audio conversion completed"
+ :title "Whisper")
+ (kill-buffer (process-buffer process)))
+ ((or (and (eq status 'exit) (> code 0))
+ (eq status 'signal))
+ (let ((err (with-current-buffer (process-buffer process)
+ (buffer-string))))
+ (user-error "Error in Whisper: %s" err)))))))))
If run interactively, the defined function prompts for paths to both files.
The process sentinel sends a desktop notification because it’s a bit more noticeable than message, and the process is expected to take some time.
Integrating with elfeed
@@ -9796,14 +10011,14 @@ Didn’t work out as I expected, so I’ve made org-journal-tags
(defun my/elfeed-whisper-get-transcript-new (entry)
(interactive (list elfeed-show-entry))
(let* ((url (caar (elfeed-entry-enclosures entry)))
- (file-name (concat
- (elfeed-ref-id (elfeed-entry-content entry))
- "."
- (file-name-extension url)))
- (file-path (expand-file-name
- (concat
- my/elfeed-whisper-podcast-files-directory
- file-name))))
+ (file-name (concat
+ (elfeed-ref-id (elfeed-entry-content entry))
+ "."
+ (file-name-extension url)))
+ (file-path (expand-file-name
+ (concat
+ my/elfeed-whisper-podcast-files-directory
+ file-name))))
(message "Download started")
(unless (file-exists-p my/elfeed-whisper-podcast-files-directory)
(mkdir my/elfeed-whisper-podcast-files-directory))
@@ -9813,36 +10028,36 @@ Didn’t work out as I expected, so I’ve made org-journal-tags
:complete
(cl-function
(lambda (&key data &allow-other-keys)
- (let ((coding-system-for-write 'binary)
- (write-region-annotate-functions nil)
- (write-region-post-annotation-function nil))
- (write-region data nil file-path nil :silent))
- (message "Conversion started")
- (my/invoke-whisper file-path my/elfeed-srt-dir)))
+ (let ((coding-system-for-write 'binary)
+ (write-region-annotate-functions nil)
+ (write-region-post-annotation-function nil))
+ (write-region data nil file-path nil :silent))
+ (message "Conversion started")
+ (my/invoke-whisper file-path my/elfeed-srt-dir)))
:error
(cl-function
(lambda (&key error-thrown &allow-other-keys)
- (message "Error!: %S" error-thrown))))))
+ (message "Error!: %S" error-thrown))))))
I also experimented with a bunch of options to write binary data in Emacs, of which the way with write-region (as implemented in f.el) seems to be the fastest. This thread on StackExchange suggests that it may screw some bytes towards the end, but whether or not this is the case, mp3 files survive the procedure. The proposed solution with seq-doseq takes at least a few seconds.
As my/invoke-whisper creates multiple files, here’s a function to select related files:
(defun my/elfeed-show-related-files (entry)
(interactive (list elfeed-show-entry))
(let* ((files
- (mapcar
- (lambda (file) (cons (file-name-extension file) file))
- (seq-filter
- (lambda (file)
- (string-match-p
- (rx bos (literal (elfeed-ref-id (elfeed-entry-content entry))) ".")
- file))
- (directory-files my/elfeed-srt-dir))))
- (buffer
- (find-file-other-window
- (concat
- my/elfeed-srt-dir
- (alist-get
- (completing-read "File: " files)
- files nil nil #'equal)))))
+ (mapcar
+ (lambda (file) (cons (file-name-extension file) file))
+ (seq-filter
+ (lambda (file)
+ (string-match-p
+ (rx bos (literal (elfeed-ref-id (elfeed-entry-content entry))) ".")
+ file))
+ (directory-files my/elfeed-srt-dir))))
+ (buffer
+ (find-file-other-window
+ (concat
+ my/elfeed-srt-dir
+ (alist-get
+ (completing-read "File: " files)
+ files nil nil #'equal)))))
(with-current-buffer buffer
(setq-local elfeed-show-entry entry))))
Finally, we need a function to show the transcript if it exists or invoke my/elfeed-whisper-get-transcript-new if it doesn’t. And this is the function that we’ll call from an elfeed-entry buffer.
@@ -9853,13 +10068,13 @@ Didn’t work out as I expected, so I’ve made org-journal-tags
(unless enclosure
(user-error "No enclosure found!"))
(let ((srt-path (concat my/elfeed-srt-dir
- (elfeed-ref-id (elfeed-entry-content entry))
- ".srt")))
+ (elfeed-ref-id (elfeed-entry-content entry))
+ ".srt")))
(if (file-exists-p srt-path)
- (let ((buffer (find-file-other-window srt-path)))
- (with-current-buffer buffer
- (setq-local elfeed-show-entry entry)))
- (my/elfeed-whisper-get-transcript-new entry)))))
+ (let ((buffer (find-file-other-window srt-path)))
+ (with-current-buffer buffer
+ (setq-local elfeed-show-entry entry)))
+ (my/elfeed-whisper-get-transcript-new entry)))))
Integrating with subed
Now that we’ve produced a .srt file, we can use a package called subed to control the playback, as I have done in the YouTube section.
By the way, this wasn’t the most straightforward thing to figure out, because the MPV window doesn’t show up for an audio file, and the player itself starts in the paused state. So I thought nothing was happening until I enabled the debug log.
@@ -9874,10 +10089,10 @@ Didn’t work out as I expected, so I’ve made org-journal-tags
(unless (derived-mode-p 'subed-mode)
(user-error "Not subed mode!"))
(setq-local subed-mpv-video-file
- (expand-file-name
- (concat my/elfeed-whisper-podcast-files-directory
- (my/get-file-name-from-url
- (caar (elfeed-entry-enclosures entry))))))
+ (expand-file-name
+ (concat my/elfeed-whisper-podcast-files-directory
+ (my/get-file-name-from-url
+ (caar (elfeed-entry-enclosures entry))))))
(subed-mpv--play subed-mpv-video-file))
After running M-x my/elfeed-whisper-subed, run M-x subed-toggle-loop-over-current-subtitle (C-c C-l), because somehow it’s turned on by default, and M-x subed-toggle-pause-while-typing (C-c C-p), because sometimes this made my instance of MPV lag.
After that, M-x subed-mpv-toggle-pause should start the playback, which you can control by moving the cursor in the buffer.
@@ -9888,15 +10103,15 @@ Didn’t work out as I expected, so I’ve made org-journal-tags
(defun my/whisper-url (url file-name output-dir &optional language num-speakers)
(interactive
(list (read-from-minibuffer "URL: ")
- (read-from-minibuffer "File name: ")
- (read-directory-name "Output directory: ")
- (let ((lang (read-string "Language (optional): ")))
- (if (string-empty-p lang) nil lang))
- (let ((num (read-number "Number of speakers (optional): " 0)))
- (when (> num 0)
- (number-to-string num)))))
+ (read-from-minibuffer "File name: ")
+ (read-directory-name "Output directory: ")
+ (let ((lang (read-string "Language (optional): ")))
+ (if (string-empty-p lang) nil lang))
+ (let ((num (read-number "Number of speakers (optional): " 0)))
+ (when (> num 0)
+ (number-to-string num)))))
(let ((file-path
- (concat output-dir file-name "." (file-name-extension url))))
+ (concat output-dir file-name "." (file-name-extension url))))
(message "Download started")
(request url
:type "GET"
@@ -9904,16 +10119,16 @@ Didn’t work out as I expected, so I’ve made org-journal-tags
:complete
(cl-function
(lambda (&key data &allow-other-keys)
- (let ((coding-system-for-write 'binary)
- (write-region-annotate-functions nil)
- (write-region-post-annotation-function nil))
- (write-region data nil file-path nil :silent))
- (message "Conversion started")
- (my/invoke-whisper file-path output-dir language num-speakers)))
+ (let ((coding-system-for-write 'binary)
+ (write-region-annotate-functions nil)
+ (write-region-post-annotation-function nil))
+ (write-region data nil file-path nil :silent))
+ (message "Conversion started")
+ (my/invoke-whisper file-path output-dir language num-speakers)))
:error
(cl-function
(lambda (&key error-thrown &allow-other-keys)
- (message "Error!: %S" error-thrown))))))
+ (message "Error!: %S" error-thrown))))))
Some observations
So, the functions above work for my purposes.
Vosk API works much faster than Whisper. The smallest Vosk model requires ~10 times less than the playback time, and even the tiny.en Whisper model on my PC requires maybe 1.2x playback time.
@@ -10051,33 +10266,33 @@ Didn’t work out as I expected, so I’ve made org-journal-tags
The return value is an alist; see `my/index--tree-get' for details."
(when (eq (org-element-type heading) 'headline)
(let (val
- (new-path (concat
- (or path my/index-root)
- (org-element-property :raw-value heading)
- "/")))
+ (new-path (concat
+ (or path my/index-root)
+ (org-element-property :raw-value heading)
+ "/")))
(when-let* ((children (thread-last
- (org-element-contents heading)
- (mapcar (lambda (e)
- (my/index--tree-get-recursive
- e new-path)))
- (seq-filter #'identity))))
- (setf (alist-get :children val) children))
+ (org-element-contents heading)
+ (mapcar (lambda (e)
+ (my/index--tree-get-recursive
+ e new-path)))
+ (seq-filter #'identity))))
+ (setf (alist-get :children val) children))
(when-let ((machine (org-element-property :MACHINE heading)))
- (setf (alist-get :machine val) (split-string machine)))
+ (setf (alist-get :machine val) (split-string machine)))
(when-let ((symlink (org-element-property :SYMLINK heading)))
- (setf (alist-get :symlink val) symlink))
+ (setf (alist-get :symlink val) symlink))
(when (org-element-property :PROJECT heading)
- (setf (alist-get :project val) t))
+ (setf (alist-get :project val) t))
(when-let* ((kind-str (org-element-property :KIND heading))
- (kind (intern kind-str)))
- (setf (alist-get :kind val) kind)
- (when (equal kind 'git)
- (let ((remote (org-element-property :REMOTE heading)))
- (unless remote
- (user-error "No remote for %s" (alist-get :name val)))
- (setf (alist-get :remote val) remote))))
+ (kind (intern kind-str)))
+ (setf (alist-get :kind val) kind)
+ (when (equal kind 'git)
+ (let ((remote (org-element-property :REMOTE heading)))
+ (unless remote
+ (user-error "No remote for %s" (alist-get :name val)))
+ (setf (alist-get :remote val) remote))))
(setf (alist-get :name val) (org-element-property :raw-value heading)
- (alist-get :path val) new-path)
+ (alist-get :path val) new-path)
val)))
(defun my/index--tree-get ()
@@ -10093,15 +10308,15 @@ Didn’t work out as I expected, so I’ve made org-journal-tags
- `:kind' - one of \"git\", \"mega\", or \"dummy\"
- `:remote' - the remote to use for git nodes"
(let* ((tree
- (thread-last
- (org-element-map (org-element-parse-buffer) 'headline #'identity)
- (seq-filter (lambda (el)
- (and
- (= (org-element-property :level el) 1)
- (seq-contains-p
- (mapcar #'substring-no-properties (org-element-property :tags el))
- "folder"))))
- (mapcar #'my/index--tree-get-recursive))))
+ (thread-last
+ (org-element-map (org-element-parse-buffer) 'headline #'identity)
+ (seq-filter (lambda (el)
+ (and
+ (= (org-element-property :level el) 1)
+ (seq-contains-p
+ (mapcar #'substring-no-properties (org-element-property :tags el))
+ "folder"))))
+ (mapcar #'my/index--tree-get-recursive))))
tree))
Verify tree
I also want to make sure that I didn’t mess up the numbers, i.e., didn’t place 10.02 under 11, and so on.
@@ -10122,25 +10337,25 @@ Didn’t work out as I expected, so I’ve made org-journal-tags
CURRENT is the current number or name of the parent element."
(let* ((name (alist-get :name elem))
- (number (my/index--extact-number name)))
+ (number (my/index--extact-number name)))
(unless number
(user-error "Can't find number: %s" name))
(cond
((and (listp current) (not (null current)))
(unless (seq-some (lambda (cand) (string-prefix-p cand name)) current)
- (user-error "Name: %s doesn't match: %s" name current)))
+ (user-error "Name: %s doesn't match: %s" name current)))
((stringp current)
(unless (string-prefix-p current name)
- (user-error "Name: %s doesn't match: %s" name current))))
+ (user-error "Name: %s doesn't match: %s" name current))))
(let ((recur-value
- (if (string-match-p (rx (+ num) "-" (+ num)) number)
- (let* ((borders (split-string number "-"))
- (start (string-to-number (nth 0 borders)))
- (end (string-to-number (nth 1 borders))))
- (cl-loop for i from start to (1- end) collect (number-to-string i)))
- number)))
+ (if (string-match-p (rx (+ num) "-" (+ num)) number)
+ (let* ((borders (split-string number "-"))
+ (start (string-to-number (nth 0 borders)))
+ (end (string-to-number (nth 1 borders))))
+ (cl-loop for i from start to (1- end) collect (number-to-string i)))
+ number)))
(mapcar (lambda (e) (my/tree--verfify-recursive e recur-value))
- (alist-get :children elem))))
+ (alist-get :children elem))))
t)
(defun my/index--tree-verify (tree)
@@ -10155,15 +10370,15 @@ Didn’t work out as I expected, so I’ve made org-journal-tags
(defun my/index--tree-narrow-recursive (elem machine)
"Remove all children of ELEM that are not active on MACHINE."
(unless (when-let ((elem-machines (alist-get :machine elem)))
- (not (seq-some (lambda (elem-machine)
- (string-equal elem-machine machine))
- elem-machines)))
+ (not (seq-some (lambda (elem-machine)
+ (string-equal elem-machine machine))
+ elem-machines)))
(setf (alist-get :children elem)
- (seq-filter
- #'identity
- (mapcar (lambda (e)
- (my/index--tree-narrow-recursive e machine))
- (alist-get :children elem))))
+ (seq-filter
+ #'identity
+ (mapcar (lambda (e)
+ (my/index--tree-narrow-recursive e machine))
+ (alist-get :children elem))))
elem))
(defun my/index--tree-narrow (tree)
@@ -10205,34 +10420,34 @@ Didn’t work out as I expected, so I’ve made org-journal-tags
the folder."
(let ((active-paths (or active-paths (my/index--tree-get-paths tree))))
(cl-loop for elem in full-tree
- for path = (alist-get :path elem)
- for extra-folders = (when (and (alist-get :children elem)
- (file-directory-p path))
- (seq-difference
- (mapcar (lambda (d) (if (file-directory-p d)
- (concat d "/")
- d))
- (directory-files path t (rx (not ".") eos)))
- (cl-loop for child in (alist-get :children elem)
- collect (alist-get :path child))))
- for folder-exists = (file-directory-p path)
- for folder-has-to-exist = (seq-contains-p active-paths path)
- collect `((path . ,path)
- (exists . ,folder-exists)
- (has-to-exist . ,folder-has-to-exist)
- (children . ,(append
- (cl-loop for f in extra-folders
- collect
- `((path . ,f)
- (exists . t)
- (has-to-exist
- . ,(member
- (file-name-nondirectory
- (directory-file-name f))
- my/index-keep-files))
- (extra . t)))
- (my/index--filesystem-tree-mapping
- (alist-get :children elem) tree active-paths)))))))
+ for path = (alist-get :path elem)
+ for extra-folders = (when (and (alist-get :children elem)
+ (file-directory-p path))
+ (seq-difference
+ (mapcar (lambda (d) (if (file-directory-p d)
+ (concat d "/")
+ d))
+ (directory-files path t (rx (not ".") eos)))
+ (cl-loop for child in (alist-get :children elem)
+ collect (alist-get :path child))))
+ for folder-exists = (file-directory-p path)
+ for folder-has-to-exist = (seq-contains-p active-paths path)
+ collect `((path . ,path)
+ (exists . ,folder-exists)
+ (has-to-exist . ,folder-has-to-exist)
+ (children . ,(append
+ (cl-loop for f in extra-folders
+ collect
+ `((path . ,f)
+ (exists . t)
+ (has-to-exist
+ . ,(member
+ (file-name-nondirectory
+ (directory-file-name f))
+ my/index-keep-files))
+ (extra . t)))
+ (my/index--filesystem-tree-mapping
+ (alist-get :children elem) tree active-paths)))))))
And generate commands from the results of the above:
(defun my/index--filesystem-commands (mapping)
"Get commands to sync filesystem with the tree.
@@ -10244,17 +10459,17 @@ Didn’t work out as I expected, so I’ve made org-journal-tags
The return value is a list of commands as defined by
`my/index--commands-display'."
(cl-loop for elem in mapping
- for path = (alist-get 'path elem)
- for exists = (alist-get 'exists elem)
- for has-to-exist = (alist-get 'has-to-exist elem)
- for extra = (alist-get 'extra elem)
- when (and (not exists) has-to-exist)
- collect (list (format "mkdir \"%s\"" path) "Make directories" 1)
- when (and exists (not has-to-exist))
- collect (list (format "rm -rf \"%s\"" path)
- (if extra "Remove extra files" "Remove directories")
- (if extra 20 10))
- append (my/index--filesystem-commands (alist-get 'children elem))))
+ for path = (alist-get 'path elem)
+ for exists = (alist-get 'exists elem)
+ for has-to-exist = (alist-get 'has-to-exist elem)
+ for extra = (alist-get 'extra elem)
+ when (and (not exists) has-to-exist)
+ collect (list (format "mkdir \"%s\"" path) "Make directories" 1)
+ when (and exists (not has-to-exist))
+ collect (list (format "rm -rf \"%s\"" path)
+ (if extra "Remove extra files" "Remove directories")
+ (if extra 20 10))
+ append (my/index--filesystem-commands (alist-get 'children elem))))
MEGA
As I said above, MEGA provides MEGAcmd, which is a convenient way to access MEGA via CLI.
To initialize the session, run
@@ -10276,25 +10491,25 @@ Didn’t work out as I expected, so I’ve made org-journal-tags
The functions also skips lines in [square brackets] and ones that
start with more than 3 spaces."
(when-let* ((lines (seq-filter
- (lambda (s) (not (or (string-empty-p s)
- (string-match-p (rx bos "[" (* nonl) "]") s)
- (string-match-p (rx bos (>= 3 " ")) s))))
- (split-string string "\n")))
- (first-line (car lines))
- (headers (split-string first-line))
- (header-indices (mapcar
- (lambda (header)
- (cl-search header first-line))
- headers)))
+ (lambda (s) (not (or (string-empty-p s)
+ (string-match-p (rx bos "[" (* nonl) "]") s)
+ (string-match-p (rx bos (>= 3 " ")) s))))
+ (split-string string "\n")))
+ (first-line (car lines))
+ (headers (split-string first-line))
+ (header-indices (mapcar
+ (lambda (header)
+ (cl-search header first-line))
+ headers)))
(cl-loop for line in (cdr lines)
- collect (cl-loop for header in headers
- for start in header-indices
- for end in (append (cdr header-indices)
- (list (length line)))
- collect (cons
- (intern header)
- (string-trim
- (substring line start end)))))))
+ collect (cl-loop for header in headers
+ for start in header-indices
+ for end in (append (cdr header-indices)
+ (list (length line)))
+ collect (cons
+ (intern header)
+ (string-trim
+ (substring line start end)))))))
Now we can invoke mega-sync to get the current sync status. --path-display-size=10000 disables truncation of long paths.
(defun my/index--mega-data-from-sync ()
"Get the current MEGA sync status.
@@ -10303,14 +10518,15 @@ Didn’t work out as I expected, so I’ve made org-journal-tags
- path - path to file or directory
- enabled - whether the file or directory is enabled for sync"
(let ((mega-result (my/parse-table-str
- (shell-command-to-string "mega-sync --path-display-size=10000"))))
+ (shell-command-to-string "mega-sync --path-display-size=10000"))))
(cl-loop for value in mega-result
- for localpath = (alist-get 'LOCALPATH value)
- collect `((path . ,(if (file-directory-p localpath)
- (concat localpath "/")
- localpath))
- (enabled . ,(string-equal (alist-get 'ACTIVE value)
- "Enabled"))))))
+ for localpath = (alist-get 'LOCALPATH value)
+ collect `((path . ,(if (file-directory-p localpath)
+ (concat localpath "/")
+ localpath))
+ (enabled . ,(seq-contains-p
+ '("Pending" "Loading" "Running")
+ (alist-get 'RUN_STATE value)))))))
And get the same data from the tree.
(defun my/index--tree-get-paths (tree &optional kind)
"Get paths from TREE.
@@ -10321,10 +10537,10 @@ Didn’t work out as I expected, so I’ve made org-journal-tags
The return value is a list of strings."
(cl-loop for elem in tree
- when (or (null kind) (eq (alist-get :kind elem) kind))
- collect (alist-get :path elem)
- append (my/index--tree-get-paths
- (alist-get :children elem) kind)))
+ when (or (null kind) (eq (alist-get :kind elem) kind))
+ collect (alist-get :path elem)
+ append (my/index--tree-get-paths
+ (alist-get :children elem) kind)))
With that information, we can generate commands to synchronize the required and actual sync paths.
(defun my/index--mega-local-path (path)
"Get path in the MEGA cloud by the local path PATH."
@@ -10339,34 +10555,34 @@ Didn’t work out as I expected, so I’ve made org-journal-tags
The return value is a list of commands as defined by
`my/index--commands-display'."
(let* ((paths-all (my/index--tree-get-paths full-tree))
- (mega-paths-to-enable (my/index--tree-get-paths tree 'mega))
- (mega-info (my/index--mega-data-from-sync))
- (mega-paths-enabled (seq-map
- (lambda (e) (alist-get 'path e))
- (seq-filter (lambda (e) (alist-get 'enabled e))
- mega-info)))
- (mega-paths-disabled (seq-map
- (lambda (e) (alist-get 'path e))
- (seq-filter (lambda (e) (not (alist-get 'enabled e)))
- mega-info))))
+ (mega-paths-to-enable (my/index--tree-get-paths tree 'mega))
+ (mega-info (my/index--mega-data-from-sync))
+ (mega-paths-enabled (seq-map
+ (lambda (e) (alist-get 'path e))
+ (seq-filter (lambda (e) (alist-get 'enabled e))
+ mega-info)))
+ (mega-paths-disabled (seq-map
+ (lambda (e) (alist-get 'path e))
+ (seq-filter (lambda (e) (not (alist-get 'enabled e)))
+ mega-info))))
(append
(cl-loop for path in (seq-difference mega-paths-to-enable mega-paths-enabled)
- if (seq-contains-p mega-paths-disabled path)
- collect (list (format "mega-sync -e \"%s\"" path) "Mega enable sync" 5)
- else append (list
- (list (format "mega-mkdir -p \"%s\""
- (my/index--mega-local-path path))
- "Mega mkdirs" 4)
- (list (format "mega-sync \"%s\" \"%s\""
- path (my/index--mega-local-path path))
- "Mega add sync" 5)))
+ if (seq-contains-p mega-paths-disabled path)
+ collect (list (format "mega-sync -r \"%s\"" path) "Mega enable sync" 5)
+ else append (list
+ (list (format "mega-mkdir -p \"%s\""
+ (my/index--mega-local-path path))
+ "Mega mkdirs" 4)
+ (list (format "mega-sync \"%s\" \"%s\""
+ path (my/index--mega-local-path path))
+ "Mega add sync" 5)))
(cl-loop for path in (seq-difference
- (seq-intersection mega-paths-enabled paths-all)
- mega-paths-to-enable)
- collect (list
- (format "mega-sync -d \"%s\""
- (substring path 0 (1- (length path))))
- "Mega remove sync" 4)))))
+ (seq-intersection mega-paths-enabled paths-all)
+ mega-paths-to-enable)
+ collect (list
+ (format "mega-sync -d \"%s\""
+ (substring path 0 (1- (length path))))
+ "Mega remove sync" 4)))))
my/index--mega-commands
Git repos
To sync git, we just need to clone the required git repos. Removing the repos is handled by the folder sync commands.
@@ -10379,15 +10595,15 @@ Didn’t work out as I expected, so I’ve made org-journal-tags
The return value is a list of commands as defined by
`my/index--commands-display'."
(cl-loop for elem in tree
- for path = (alist-get :path elem)
- when (and (eq (alist-get :kind elem) 'git)
- (or (not (file-directory-p path))
- (directory-empty-p path)))
- collect (list (format "git clone \"%s\" \"%s\""
- (alist-get :remote elem)
- path)
- "Init git repos" 2)
- append (my/index--git-commands (alist-get :children elem))))
+ for path = (alist-get :path elem)
+ when (and (eq (alist-get :kind elem) 'git)
+ (or (not (file-directory-p path))
+ (directory-empty-p path)))
+ collect (list (format "git clone \"%s\" \"%s\""
+ (alist-get :remote elem)
+ path)
+ "Init git repos" 2)
+ append (my/index--git-commands (alist-get :children elem))))
Wakatime
So, that’s it for synchronization. A few other things are needed here.
I use WakaTime to track my coding activity, and I don’t like the alphanumeric prefixes in my coding stats. Fortunately, wakatime-cli provides an option called projectmap to rename projects, so we just have to generate its contents.
@@ -10413,23 +10629,23 @@ Didn’t work out as I expected, so I’ve made org-journal-tags
\"bare-project-name\" is project name without the alphanumeric
prefix."
(cl-loop for elem in tree
- for name = (alist-get :name elem)
- if (eq (alist-get :kind elem) 'git)
- collect (cons (my/index--wakatime-escape name)
- (my/index--wakatime-escape
- (my/index--bare-project-name name)))
- if (and (eq (alist-get :kind elem) 'git)
- (alist-get :symlink elem))
- collect (cons (my/index--wakatime-escape
- ;; lmao
- ;; /a/b/c/ -> c
- ;; /a/b/c -> b
- (file-name-nondirectory
- (directory-file-name
- (file-name-directory (alist-get :symlink elem)))))
- (my/index--wakatime-escape
- (my/index--bare-project-name name)))
- append (my/index--wakatime-get-map-tree (alist-get :children elem))))
+ for name = (alist-get :name elem)
+ if (eq (alist-get :kind elem) 'git)
+ collect (cons (my/index--wakatime-escape name)
+ (my/index--wakatime-escape
+ (my/index--bare-project-name name)))
+ if (and (eq (alist-get :kind elem) 'git)
+ (alist-get :symlink elem))
+ collect (cons (my/index--wakatime-escape
+ ;; lmao
+ ;; /a/b/c/ -> c
+ ;; /a/b/c -> b
+ (file-name-nondirectory
+ (directory-file-name
+ (file-name-directory (alist-get :symlink elem)))))
+ (my/index--wakatime-escape
+ (my/index--bare-project-name name)))
+ append (my/index--wakatime-get-map-tree (alist-get :children elem))))
And insert that in wakatime.cfg if necessary.
(defun my/index--wakatime-commands (tree)
"Get commands to update WakaTime config from TREE.
@@ -10438,18 +10654,18 @@ Didn’t work out as I expected, so I’ve made org-journal-tags
a list of commands as defined by `my/index--commands-display'."
(require 'ini)
(let* ((map-tree (my/index--wakatime-get-map-tree tree))
- (map-tree-encoding (ini-encode `(("projectmap" . ,map-tree))))
- (map-tree-saved (with-temp-buffer
- (insert-file-contents (expand-file-name "~/.wakatime.cfg"))
- (string-match-p (regexp-quote map-tree-encoding)
- (buffer-string)))))
+ (map-tree-encoding (ini-encode `(("projectmap" . ,map-tree))))
+ (map-tree-saved (with-temp-buffer
+ (insert-file-contents (expand-file-name "~/.wakatime.cfg"))
+ (string-match-p (regexp-quote map-tree-encoding)
+ (buffer-string)))))
(unless map-tree-saved
(let ((insert-command (list (format "echo \"\n\n%s\" >> ~/.wakatime.cfg"
- map-tree-encoding)
- "Update WakaTime config" 9)))
- (list (list (format "sed -i -z 's/\\[projectmap\\]\\n[^[]*//g' ~/.wakatime.cfg")
- "Update WakaTime config" 9)
- insert-command)))))
+ map-tree-encoding)
+ "Update WakaTime config" 9)))
+ (list (list (format "sed -i -z 's/\\[projectmap\\]\\n[^[]*//g' ~/.wakatime.cfg")
+ "Update WakaTime config" 9)
+ insert-command)))))
Symlinks
The last part here is creating symbolic links.
(defun my/index-get-symlink-commands (tree)
@@ -10458,22 +10674,22 @@ Didn’t work out as I expected, so I’ve made org-journal-tags
TREE is a form a defined by `my/index--tree-get'. The return value is
a list of commands as defined by `my/index--commands-display'."
(cl-loop for elem in tree
- for path = (alist-get :path elem)
- for symlink = (alist-get :symlink elem)
- when (and symlink (not (string-match-p (rx "/" eos) symlink)))
- do (user-error "Wrong symlink: %s (should be a directory)" symlink)
- when (and path symlink
- (or (file-exists-p symlink)
- (file-exists-p (substring symlink 0 -1)))
- (not (file-symlink-p (substring symlink 0 -1))))
- collect (list (format "rm -rf %s" (substring symlink 0 -1))
- "Remove files to make symlinks" 6)
- when (and path symlink
- (not (file-symlink-p (substring symlink 0 -1))))
- collect (list (format "ln -s '%s' '%s'" path
- (substring symlink 0 -1))
- "Make symlinks" 7)
- append (my/index-get-symlink-commands (alist-get :children elem))))
+ for path = (alist-get :path elem)
+ for symlink = (alist-get :symlink elem)
+ when (and symlink (not (string-match-p (rx "/" eos) symlink)))
+ do (user-error "Wrong symlink: %s (should be a directory)" symlink)
+ when (and path symlink
+ (or (file-exists-p symlink)
+ (file-exists-p (substring symlink 0 -1)))
+ (not (file-symlink-p (substring symlink 0 -1))))
+ collect (list (format "rm -rf %s" (substring symlink 0 -1))
+ "Remove files to make symlinks" 6)
+ when (and path symlink
+ (not (file-symlink-p (substring symlink 0 -1))))
+ collect (list (format "ln -s '%s' '%s'" path
+ (substring symlink 0 -1))
+ "Make symlinks" 7)
+ append (my/index-get-symlink-commands (alist-get :children elem))))
my/index-get-symlink-commands
Run all commands
And put that all together.
@@ -10485,7 +10701,7 @@ Didn’t work out as I expected, so I’ve made org-journal-tags
(define-key keymap (kbd "q") #'my/quit-window-and-buffer)
(when (fboundp 'evil-define-key*)
(evil-define-key* 'normal keymap
- "q" #'my/quit-window-and-buffer))
+ "q" #'my/quit-window-and-buffer))
keymap)
"Keymap for `biome-api-error-mode'.")
@@ -10501,25 +10717,25 @@ Didn’t work out as I expected, so I’ve made org-journal-tags
(unless commands
(user-error "No commands to display"))
(let ((buffer (get-buffer-create "*index commands*"))
- (groups (seq-sort-by
- (lambda (g) (nth 2 (nth 1 g)))
- #'<
- (seq-group-by (lambda (c) (nth 1 c))
- commands))))
+ (groups (seq-sort-by
+ (lambda (g) (nth 2 (nth 1 g)))
+ #'<
+ (seq-group-by (lambda (c) (nth 1 c))
+ commands))))
(with-current-buffer buffer
(my/index-commands-mode)
(let ((inhibit-read-only t)
- commands-sequence)
- (erase-buffer)
- (setq-local my/index-commands nil)
- (cl-loop for g in groups
- for group-name = (car g)
- for elems = (cdr g)
- do (insert "# " group-name "\n")
- do (cl-loop for elem in elems
- do (push (nth 0 elem) my/index-commands)
- do (insert (nth 0 elem) "\n")))
- (setq-local buffer-read-only t)))
+ commands-sequence)
+ (erase-buffer)
+ (setq-local my/index-commands nil)
+ (cl-loop for g in groups
+ for group-name = (car g)
+ for elems = (cdr g)
+ do (insert "# " group-name "\n")
+ do (cl-loop for elem in elems
+ do (push (nth 0 elem) my/index-commands)
+ do (insert (nth 0 elem) "\n")))
+ (setq-local buffer-read-only t)))
(switch-to-buffer buffer)))
In order to execute these commands, compile with bash -x on a temporary file is quite sufficient.
(defun my/index-commands-exec ()
@@ -10541,14 +10757,14 @@ Didn’t work out as I expected, so I’ve made org-journal-tags
(setq
my/index--tree
(cond ((string-equal (buffer-file-name) my/index-file)
- (my/index--tree-get))
- ((or (null my/index--tree)
- (file-has-changed-p my/index-file 'index))
- (with-temp-buffer
- (insert-file-contents my/index-file)
- (let ((buffer-file-name my/index-file))
- (my/index--tree-get))))
- (t my/index--tree))))
+ (my/index--tree-get))
+ ((or (null my/index--tree)
+ (file-has-changed-p my/index-file 'index))
+ (with-temp-buffer
+ (insert-file-contents my/index-file)
+ (let ((buffer-file-name my/index-file))
+ (my/index--tree-get))))
+ (t my/index--tree))))
With that, we can make the main entrypoint.
(defun my/index-commands-sync ()
"Sync the filesystem with the index."
@@ -10556,14 +10772,14 @@ Didn’t work out as I expected, so I’ve made org-journal-tags
(let* ((full-tree (my/index--tree-retrive)))
(my/index--tree-verify full-tree)
(let* ((tree (my/index--tree-narrow full-tree))
- (mega-commands (my/index--mega-commands full-tree tree))
- (mapping (my/index--filesystem-tree-mapping full-tree tree))
- (folder-commands (my/index--filesystem-commands mapping))
- (git-commands (my/index--git-commands tree))
- (waka-commands (my/index--wakatime-commands tree))
- (symlink-commands (my/index-get-symlink-commands tree)))
+ (mega-commands (my/index--mega-commands full-tree tree))
+ (mapping (my/index--filesystem-tree-mapping full-tree tree))
+ (folder-commands (my/index--filesystem-commands mapping))
+ (git-commands (my/index--git-commands tree))
+ (waka-commands (my/index--wakatime-commands tree))
+ (symlink-commands (my/index-get-symlink-commands tree)))
(my/index--commands-display (append mega-commands folder-commands git-commands
- waka-commands symlink-commands)))))
+ waka-commands symlink-commands)))))
Navigation
The last piece is the navigation interface.
Of course, plain dired does the job fine, thanks to the relatively low-depth filesystem structure. But I still want a navigation interface like M-x projectile-switch-project.
@@ -10582,27 +10798,27 @@ Didn’t work out as I expected, so I’ve made org-journal-tags
The return value is a form as defined by `my/index--nav-get'."
(when (file-directory-p path)
(let* ((number (my/index--extact-number name))
- (files (mapcar
- (lambda (f) (cons f (concat path f)))
- (seq-filter (lambda (f) (not (string-prefix-p "." f)))
- (directory-files path))))
- (matching-files
- (seq-filter
- (lambda (f) (and (file-directory-p (cdr f))
- (string-prefix-p number (car f))))
- files)))
+ (files (mapcar
+ (lambda (f) (cons f (concat path f)))
+ (seq-filter (lambda (f) (not (string-prefix-p "." f)))
+ (directory-files path))))
+ (matching-files
+ (seq-filter
+ (lambda (f) (and (file-directory-p (cdr f))
+ (string-prefix-p number (car f))))
+ files)))
(when (and (length> matching-files 0)
- (length< matching-files (length files)))
- (user-error "Extraneuous files in %s" path))
+ (length< matching-files (length files)))
+ (user-error "Extraneuous files in %s" path))
(cl-loop for (name-1 . path-1) in matching-files
- append (if-let ((child-files (my/index--nav-extend name-1 (concat path-1 "/"))))
- (mapcar
- (lambda (child-datum)
- (push name-1 (alist-get :names child-datum))
- child-datum)
- child-files)
- `(((:names . (,name-1))
- (:path . ,(concat path-1 "/")))))))))
+ append (if-let ((child-files (my/index--nav-extend name-1 (concat path-1 "/"))))
+ (mapcar
+ (lambda (child-datum)
+ (push name-1 (alist-get :names child-datum))
+ child-datum)
+ child-files)
+ `(((:names . (,name-1))
+ (:path . ,(concat path-1 "/")))))))))
And one to get the navigation data structure.
(defun my/index--nav-get (tree &optional names)
"Get the navigation structure from TREE.
@@ -10623,31 +10839,31 @@ Didn’t work out as I expected, so I’ve made org-journal-tags
(cl-reduce
(lambda (acc elem)
(let* ((name (alist-get :name elem))
- (path (alist-get :path elem)))
- (cond ((alist-get :project elem)
- (let ((current-nav `((:names . (,@names ,name))
- (:path . ,path))))
- (when-let (child-navs
- (and (alist-get :children elem)
- (my/index--nav-get (alist-get :children elem))))
- (setf (alist-get :child-navs current-nav) child-navs))
- (push current-nav acc)))
- ((alist-get :children elem)
- (when-let (child-navs (my/index--nav-get
- (alist-get :children elem)
- `(,@names ,name)))
- (cl-loop for child-nav in child-navs
- do (push child-nav acc))))
- (t (if-let ((extended-nav (my/index--nav-extend name path)))
- (cl-loop for child-nav in extended-nav
- do (setf (alist-get :names child-nav)
- (append names (list name)
- (alist-get :names child-nav)))
- do (push child-nav acc))
- (push `((:names . (,@names ,name))
- (:path . ,path))
- acc))))
- acc))
+ (path (alist-get :path elem)))
+ (cond ((alist-get :project elem)
+ (let ((current-nav `((:names . (,@names ,name))
+ (:path . ,path))))
+ (when-let (child-navs
+ (and (alist-get :children elem)
+ (my/index--nav-get (alist-get :children elem))))
+ (setf (alist-get :child-navs current-nav) child-navs))
+ (push current-nav acc)))
+ ((alist-get :children elem)
+ (when-let (child-navs (my/index--nav-get
+ (alist-get :children elem)
+ `(,@names ,name)))
+ (cl-loop for child-nav in child-navs
+ do (push child-nav acc))))
+ (t (if-let ((extended-nav (my/index--nav-extend name path)))
+ (cl-loop for child-nav in extended-nav
+ do (setf (alist-get :names child-nav)
+ (append names (list name)
+ (alist-get :names child-nav)))
+ do (push child-nav acc))
+ (push `((:names . (,@names ,name))
+ (:path . ,path))
+ acc))))
+ acc))
tree
:initial-value nil)))
It also makes sense to cache results of the above.
@@ -10659,10 +10875,10 @@ Didn’t work out as I expected, so I’ve made org-journal-tags
The return value is a form as defined by `my/index--nav-get'."
(if (or (null my/index--nav)
- (file-has-changed-p my/index-file 'nav))
+ (file-has-changed-p my/index-file 'nav))
(let ((tree (my/index--tree-retrive)))
- (setq my/index--nav (my/index--nav-get
- (my/index--tree-narrow tree))))
+ (setq my/index--nav (my/index--nav-get
+ (my/index--tree-narrow tree))))
my/index--nav))
Emacs interface
As for Emacs interface, completing-read is sufficient, except that I don’t want prescient.el to interfere with the default ordering of elements.
@@ -10671,11 +10887,11 @@ Didn’t work out as I expected, so I’ve made org-journal-tags
NAV is a structure as defined by `my/index--nav-get'."
(let* ((collection
- (mapcar (lambda (item)
- (cons (car (last (alist-get :names item)))
- (alist-get :path item)))
- nav))
- (vertico-sort-function nil))
+ (mapcar (lambda (item)
+ (cons (car (last (alist-get :names item)))
+ (alist-get :path item)))
+ nav))
+ (vertico-sort-function nil))
(cdr
(assoc
(completing-read "Index: " collection nil t)
@@ -10701,20 +10917,20 @@ Didn’t work out as I expected, so I’ve made org-journal-tags
to `dired' if used interactively."
(interactive (list current-prefix-arg #'dired))
(let* ((nav (my/index--nav-retrive))
- (current-nav (my/index--nav-find-path
- nav (expand-file-name default-directory)))
- (current-child-navs (alist-get :child-navs current-nav)))
+ (current-nav (my/index--nav-find-path
+ nav (expand-file-name default-directory)))
+ (current-child-navs (alist-get :child-navs current-nav)))
(cond ((null arg)
- (let ((selected (my/index--nav-find-path
- nav
- (my/index--nav-prompt nav))))
- (if-let (child-navs (alist-get :child-navs selected))
- (funcall func (my/index--nav-prompt child-navs))
- (funcall func (alist-get :path selected)))))
- ((and (equal arg '(4)) current-child-navs)
- (funcall func (my/index--nav-prompt current-child-navs)))
- ((and (equal arg '(4)) (null current-child-navs))
- (funcall func (my/index--nav-prompt nav))))))
+ (let ((selected (my/index--nav-find-path
+ nav
+ (my/index--nav-prompt nav))))
+ (if-let (child-navs (alist-get :child-navs selected))
+ (funcall func (my/index--nav-prompt child-navs))
+ (funcall func (alist-get :path selected)))))
+ ((and (equal arg '(4)) current-child-navs)
+ (funcall func (my/index--nav-prompt current-child-navs)))
+ ((and (equal arg '(4)) (null current-child-navs))
+ (funcall func (my/index--nav-prompt nav))))))
Finally, something that I can bind to a key.
(defun my/index-nav-with-select-file (arg)
(interactive (list current-prefix-arg))
@@ -10785,8 +11001,8 @@ Didn’t work out as I expected, so I’ve made org-journal-tags
(use-package screenshot
:straight (:repo "tecosaur/screenshot"
- :host github
- :build (:not compile))
+ :host github
+ :build (:not compile))
:if (display-graphic-p)
:commands (screenshot)
:init
@@ -10796,9 +11012,9 @@ Didn’t work out as I expected, so I’ve made org-journal-tags
(my-leader-def "ah" 'proced)
(setq proced-auto-update-interval 1)
(add-hook 'proced-mode-hook (lambda ()
- (visual-line-mode -1)
- (setq-local truncate-lines t)
- (proced-toggle-auto-update 1)))
+ (visual-line-mode -1)
+ (setq-local truncate-lines t)
+ (proced-toggle-auto-update 1)))
Guix
An Emacs package to help managing GNU Guix.
(use-package guix
@@ -10849,7 +11065,7 @@ Didn’t work out as I expected, so I’ve made org-journal-tags
(pomm-mode-line-mode)
(add-hook 'pomm-on-status-changed-hook #'pomm--sync-org-clock)
(add-hook 'pomm-third-time-on-status-changed-hook
- #'pomm-third-time--sync-org-clock))
+ #'pomm-third-time--sync-org-clock))
hledger
is a plain-text double-entry accounting software. I use it for managing my personal finances, and thus far it’s great.
@@ -10870,9 +11086,9 @@ Didn’t work out as I expected, so I’ve made org-journal-tags
:config
(setq hledger-jfile (concat org-directory "/ledger/ledger.journal"))
(add-hook 'hledger-mode-hook
- (lambda ()
- (make-local-variable 'company-backends)
- (add-to-list 'company-backends 'hledger-company))))
+ (lambda ()
+ (make-local-variable 'company-backends)
+ (add-to-list 'company-backends 'hledger-company))))
(use-package flycheck-hledger
:straight t
@@ -10955,11 +11171,11 @@ Didn’t work out as I expected, so I’ve made org-journal-tags
(defun org-babel-execute:pgn (body params)
(let ((out-file (or (alist-get :file params)
- (org-babel-temp-file "pgn-" ".png"))))
+ (org-babel-temp-file "pgn-" ".png"))))
(org-babel-eval
(format "%s %s '%s' '%s'" my/chess-python
- "~/bin/python-scripts/render_pgn.py"
- body out-file)
+ "~/bin/python-scripts/render_pgn.py"
+ body out-file)
"")
nil))
@@ -10969,11 +11185,11 @@ Didn’t work out as I expected, so I’ve made org-journal-tags
(defun org-babel-execute:fen (body params)
(let ((out-file (or (alist-get :file params)
- (org-babel-temp-file "fen-" ".png"))))
+ (org-babel-temp-file "fen-" ".png"))))
(org-babel-eval
(format "%s %s '%s' '%s' true" my/chess-python
- "~/bin/python-scripts/render_pgn.py"
- body out-file)
+ "~/bin/python-scripts/render_pgn.py"
+ body out-file)
"")
nil))
@@ -11014,11 +11230,11 @@ Didn’t work out as I expected, so I’ve made org-journal-tags
(use-package elcord
:straight t
:if (and (or
- (string= (system-name) "violet")
- (string= (system-name) "eminence")
- (string= (system-name) "iris"))
- (not my/remote-server)
- (not my/nested-emacs))
+ (string= (system-name) "violet")
+ (string= (system-name) "eminence")
+ (string= (system-name) "iris"))
+ (not my/remote-server)
+ (not my/nested-emacs))
:config
(setq elcord-buffer-details-format-function #'my/elcord-buffer-details-format-functions)
(advice-add 'elcord--try-update-presence :filter-args #'my/elcord-update-presence-mask-advice)
@@ -11051,11 +11267,11 @@ Didn’t work out as I expected, so I’ve made org-journal-tags
(defun my/zone-with-select ()
(interactive)
(let ((zone-programs
- (vector
- (intern
- (completing-read
- "Zone programs"
- (cl-mapcar 'symbol-name original-zone-programs))))))
+ (vector
+ (intern
+ (completing-read
+ "Zone programs"
+ (cl-mapcar 'symbol-name original-zone-programs))))))
(zone)))
Gource
Gource is a program that draws an animated graph of users changing the repository over time.
@@ -11073,10 +11289,10 @@ It may happen when people use forges like GitLab
(defun my/gravatar-retrieve-sync (email file-name)
"Get gravatar for EMAIL and save it to FILE-NAME."
(let ((gravatar-default-image "identicon")
- (gravatar-size nil)
- (coding-system-for-write 'binary)
- (write-region-annotate-functions nil)
- (write-region-post-annotation-function nil))
+ (gravatar-size nil)
+ (coding-system-for-write 'binary)
+ (write-region-annotate-functions nil)
+ (write-region-post-annotation-function nil))
(write-region
(image-property (gravatar-retrieve-synchronously email) :data)
nil file-name nil :silent)))
@@ -11119,70 +11335,70 @@ It may happen when people use forges like GitLab
- author: the most popular username
I.e. one alist is all emails and usernames of one author."
(let* ((default-directory repo)
- (data (shell-command-to-string
- "git log --pretty=format:\"%ae|%an\" | sort | uniq -c | sed \"s/^[ \t]*//;s/ /|/\""))
- (authors
- (cl-loop for string in (split-string data "\n")
- if (= (length (split-string string "|")) 3)
- collect (let ((datum (split-string string "|")))
- `((count . ,(string-to-number (nth 0 datum)))
- (email . ,(downcase (nth 1 datum)))
- (author . ,(nth 2 datum)))))))
+ (data (shell-command-to-string
+ "git log --pretty=format:\"%ae|%an\" | sort | uniq -c | sed \"s/^[ \t]*//;s/ /|/\""))
+ (authors
+ (cl-loop for string in (split-string data "\n")
+ if (= (length (split-string string "|")) 3)
+ collect (let ((datum (split-string string "|")))
+ `((count . ,(string-to-number (nth 0 datum)))
+ (email . ,(downcase (nth 1 datum)))
+ (author . ,(nth 2 datum)))))))
(mapcar
(lambda (datum)
(setf (alist-get 'author datum)
- (car (cl-reduce
- (lambda (acc author)
- (if (> (cdr author) (cdr acc))
- author
- acc))
- (alist-get 'authors datum)
- :initial-value '(nil . -1))))
+ (car (cl-reduce
+ (lambda (acc author)
+ (if (> (cdr author) (cdr acc))
+ author
+ acc))
+ (alist-get 'authors datum)
+ :initial-value '(nil . -1))))
(setf (alist-get 'email datum)
- (car (cl-reduce
- (lambda (acc email)
- (if (> (cdr email) (cdr acc))
- email
- acc))
- (alist-get 'emails datum)
- :initial-value '(nil . -1))))
+ (car (cl-reduce
+ (lambda (acc email)
+ (if (> (cdr email) (cdr acc))
+ email
+ acc))
+ (alist-get 'emails datum)
+ :initial-value '(nil . -1))))
datum)
(cl-reduce
(lambda (acc val)
- (let* ((author (alist-get 'author val))
- (email (alist-get 'email val))
- (count (alist-get 'count val))
- (saved-value
- (seq-find
- (lambda (cand)
- (or (alist-get email (alist-get 'emails cand)
- nil nil #'string-equal)
- (alist-get author (alist-get 'authors cand)
- nil nil #'string-equal)
- (alist-get email (alist-get 'authors cand)
- nil nil #'string-equal)
- (alist-get author (alist-get 'emails cand)
- nil nil #'string-equal)))
- acc)))
- (if saved-value
- (progn
- (if (alist-get email (alist-get 'emails saved-value)
- nil nil #'string-equal)
- (cl-incf (alist-get email (alist-get 'emails saved-value)
- nil nil #'string-equal)
- count)
- (push (cons email count) (alist-get 'emails saved-value)))
- (if (alist-get author (alist-get 'authors saved-value)
- nil nil #'string-equal)
- (cl-incf (alist-get author (alist-get 'authors saved-value)
- nil nil #'string-equal)
- count)
- (push (cons author count) (alist-get 'authors saved-value))))
- (setq saved-value
- (push `((emails . ((,email . ,count)))
- (authors . ((,author . ,count))))
- acc)))
- acc))
+ (let* ((author (alist-get 'author val))
+ (email (alist-get 'email val))
+ (count (alist-get 'count val))
+ (saved-value
+ (seq-find
+ (lambda (cand)
+ (or (alist-get email (alist-get 'emails cand)
+ nil nil #'string-equal)
+ (alist-get author (alist-get 'authors cand)
+ nil nil #'string-equal)
+ (alist-get email (alist-get 'authors cand)
+ nil nil #'string-equal)
+ (alist-get author (alist-get 'emails cand)
+ nil nil #'string-equal)))
+ acc)))
+ (if saved-value
+ (progn
+ (if (alist-get email (alist-get 'emails saved-value)
+ nil nil #'string-equal)
+ (cl-incf (alist-get email (alist-get 'emails saved-value)
+ nil nil #'string-equal)
+ count)
+ (push (cons email count) (alist-get 'emails saved-value)))
+ (if (alist-get author (alist-get 'authors saved-value)
+ nil nil #'string-equal)
+ (cl-incf (alist-get author (alist-get 'authors saved-value)
+ nil nil #'string-equal)
+ count)
+ (push (cons author count) (alist-get 'authors saved-value))))
+ (setq saved-value
+ (push `((emails . ((,email . ,count)))
+ (authors . ((,author . ,count))))
+ acc)))
+ acc))
authors
:initial-value authors-init))))
Despite the probable we-enjoy-typing-ness of the implementation, it’s actually pretty simple:
@@ -11221,28 +11437,28 @@ I’ve seen a couple of cases where people would swap their username and ema
AUTHORS is the output of `my/git-get-authors'."
(let ((log (shell-command-to-string
- (concat
- "gource --output-custom-log - "
- repo)))
- (authors-mapping (make-hash-table :test #'equal))
- (prefix (file-name-base repo)))
+ (concat
+ "gource --output-custom-log - "
+ repo)))
+ (authors-mapping (make-hash-table :test #'equal))
+ (prefix (file-name-base repo)))
(cl-loop for author-datum in authors
- for author = (alist-get 'author author-datum)
- do (my/gravatar-save (alist-get 'email author-datum) author)
- do (cl-loop for other-author in (alist-get 'authors author-datum)
- unless (string-equal (car other-author) author)
- do (puthash (car other-author) author
- authors-mapping)))
+ for author = (alist-get 'author author-datum)
+ do (my/gravatar-save (alist-get 'email author-datum) author)
+ do (cl-loop for other-author in (alist-get 'authors author-datum)
+ unless (string-equal (car other-author) author)
+ do (puthash (car other-author) author
+ authors-mapping)))
(cl-loop for line in (split-string log "\n")
- concat (let ((fragments (split-string line "|")))
- (when (> (length fragments) 3)
- (when-let (mapped-author (gethash (nth 1 fragments)
- authors-mapping))
- (setf (nth 1 fragments) mapped-author))
- (setf (nth 3 fragments)
- (concat "/" prefix (nth 3 fragments))))
- (string-join fragments "|"))
- concat "\n")))
+ concat (let ((fragments (split-string line "|")))
+ (when (> (length fragments) 3)
+ (when-let (mapped-author (gethash (nth 1 fragments)
+ authors-mapping))
+ (setf (nth 1 fragments) mapped-author))
+ (setf (nth 3 fragments)
+ (concat "/" prefix (nth 3 fragments))))
+ (string-join fragments "|"))
+ concat "\n")))
This function:
- Downloads a gravatar for each author
@@ -11260,33 +11476,33 @@ I’ve seen a couple of cases where people would swap their username and ema
This function is meant to be invoked from `dired', where the required
repositories are marked."
(interactive (list (or (dired-get-marked-files nil nil #'file-directory-p)
- (user-error "Select at least one directory"))
- (read-file-name "Log file name: " nil "combined.log")))
+ (user-error "Select at least one directory"))
+ (read-file-name "Log file name: " nil "combined.log")))
(let ((authors
- (cl-reduce
- (lambda (acc repo)
- (my/git-get-authors repo acc))
- repos
- :initial-value nil)))
+ (cl-reduce
+ (lambda (acc repo)
+ (my/git-get-authors repo acc))
+ repos
+ :initial-value nil)))
(with-temp-file log-name
(insert
(string-join
- (seq-filter
- (lambda (line)
- (not (string-empty-p line)))
- (seq-sort-by
- (lambda (line)
- (if-let (time (car (split-string line "|")))
- (string-to-number time)
- 0))
- #'<
- (split-string
- (mapconcat
- (lambda (repo)
- (my/gource-prepare-log repo authors))
- repos "\n")
- "\n")))
- "\n")))))
+ (seq-filter
+ (lambda (line)
+ (not (string-empty-p line)))
+ (seq-sort-by
+ (lambda (line)
+ (if-let (time (car (split-string line "|")))
+ (string-to-number time)
+ 0))
+ #'<
+ (split-string
+ (mapconcat
+ (lambda (repo)
+ (my/gource-prepare-log repo authors))
+ repos "\n")
+ "\n")))
+ "\n")))))
This function extracts authors from each repository and merges the logs as required by gource, that is sorting the result by time in ascending order.
Using the function
To use the function above, mark the required repos in a dired buffer and run M-x my/gource-dired-create-logs. This also works nicely with dired-subtree, in case your repos are located in different folders.
@@ -11406,6 +11622,7 @@ I’ve seen a couple of cases where people would swap their username and ema
- Snippets
- Input Method
- Other small packages
+ - Random editing tricks
- Working with projects
diff --git a/configs/guix/index.html b/configs/guix/index.html
index e0268b2..b628650 100644
--- a/configs/guix/index.html
+++ b/configs/guix/index.html
@@ -122,9 +122,9 @@
# Source the new profile
GUIX_PROFILE="$profilePath/$profileName"
if [ -f $GUIX_PROFILE/etc/profile ]; then
- . "$GUIX_PROFILE"/etc/profile
+ . "$GUIX_PROFILE"/etc/profile
else
- echo -e "${RED}Couldn't find profile:" $GUIX_PROFILE/etc/profile "${NC}"
+ echo -e "${RED}Couldn't find profile:" $GUIX_PROFILE/etc/profile "${NC}"
fi
else
echo "No profile found at path" $profilePath
@@ -246,16 +246,16 @@
(kernel
(let*
((channels
- (list (channel
- (name 'nonguix)
- (url "https://gitlab.com/nonguix/nonguix")
- (commit "213be7ee6676fc4a3db0e3ac9ce5cd79e2ed209e"))
- (channel
- (name 'guix)
- (url "https://git.savannah.gnu.org/git/guix.git")
- (commit "6311493d7a6271bfbc51f4693857f9a12fe9965d"))))
+ (list (channel
+ (name 'nonguix)
+ (url "https://gitlab.com/nonguix/nonguix")
+ (commit "213be7ee6676fc4a3db0e3ac9ce5cd79e2ed209e"))
+ (channel
+ (name 'guix)
+ (url "https://git.savannah.gnu.org/git/guix.git")
+ (commit "6311493d7a6271bfbc51f4693857f9a12fe9965d"))))
(inferior
- (inferior-for-channels channels)))
+ (inferior-for-channels channels)))
(first (lookup-inferior-packages inferior "linux" "6.2.9"))))
;; (kernel linux)
(initrd microcode-initrd)
@@ -266,32 +266,32 @@
(keyboard-layout (keyboard-layout "us,ru" #:options '("grp:alt_shift_toggle")))
User accounts.
(users (cons* (user-account
- (name "pavel")
- (comment "Pavel")
- (group "users")
- (home-directory "/home/pavel")
- (supplementary-groups
- '("wheel" ;; sudo
- "netdev" ;; network devices
- "audio"
- "video"
- "input"
- "tty"
- "docker"
- "scanner"
- "libvirt"
- "lp")))
- %base-user-accounts))
+ (name "pavel")
+ (comment "Pavel")
+ (group "users")
+ (home-directory "/home/pavel")
+ (supplementary-groups
+ '("wheel" ;; sudo
+ "netdev" ;; network devices
+ "audio"
+ "video"
+ "input"
+ "tty"
+ "docker"
+ "scanner"
+ "libvirt"
+ "lp")))
+ %base-user-accounts))
Base packages, necessary right after the installation.
(packages
(append
(list nss-certs
- git
- i3-gaps
- i3lock
- openbox
- xterm
- vim)
+ git
+ i3-gaps
+ i3lock
+ openbox
+ xterm
+ vim)
%base-packages))
Default services for each machine:
@@ -310,31 +310,31 @@
(extra-special-file "/lib64/ld-linux-x86-64.so.2" (file-append glibc "/lib/ld-linux-x86-64.so.2"))
(service nix-service-type)
(service cups-service-type
- (cups-configuration
- (web-interface? #t)))
+ (cups-configuration
+ (web-interface? #t)))
(service docker-service-type)
(service libvirt-service-type
- (libvirt-configuration
- (unix-sock-group "libvirt")
- (tls-port "16555")))
+ (libvirt-configuration
+ (unix-sock-group "libvirt")
+ (tls-port "16555")))
(service virtlog-service-type)
(bluetooth-service #:auto-enable? #f)
(modify-services %desktop-services
- (network-manager-service-type
- config =>
- (network-manager-configuration
- (inherit config)
- (vpn-plugins (list network-manager-openvpn))))
- (guix-service-type
- config =>
- (guix-configuration
- (inherit config)
- (substitute-urls
- (append (list "https://substitutes.nonguix.org")
- %default-substitute-urls))
- (authorized-keys
- (append (list (local-file "./signing-key.pub"))
- %default-authorized-guix-keys)))))))
+ (network-manager-service-type
+ config =>
+ (network-manager-configuration
+ (inherit config)
+ (vpn-plugins (list network-manager-openvpn))))
+ (guix-service-type
+ config =>
+ (guix-configuration
+ (inherit config)
+ (substitute-urls
+ (append (list "https://substitutes.nonguix.org")
+ %default-substitute-urls))
+ (authorized-keys
+ (append (list (local-file "./signing-key.pub"))
+ %default-authorized-guix-keys)))))))
indigo
indigo is my desktop PC.
<<system-common>>
@@ -344,10 +344,10 @@
(host-name "indigo")
(services (cons*
- (set-xorg-configuration
- (xorg-configuration
- (keyboard-layout keyboard-layout)))
- %my-base-services))
+ (set-xorg-configuration
+ (xorg-configuration
+ (keyboard-layout keyboard-layout)))
+ %my-base-services))
(bootloader
(bootloader-configuration
@@ -360,14 +360,14 @@
(file-systems
(cons* (file-system
- (mount-point "/")
- (device (file-system-label "my-root"))
- (type "ext4"))
- (file-system
- (mount-point "/boot/efi")
- (device "/dev/sda1")
- (type "vfat"))
- %base-file-systems)))
+ (mount-point "/")
+ (device (file-system-label "my-root"))
+ (type "ext4"))
+ (file-system
+ (mount-point "/boot/efi")
+ (device "/dev/sda1")
+ (type "vfat"))
+ %base-file-systems)))
eminence
eminence is a HP 15s laptop.
%backlight-udev-rule should enable members of video group change the display backlight. See the relevant page at Arch Wiki.
@@ -377,31 +377,31 @@
(udev-rule
"90-backlight.rules"
(string-append "ACTION==\"add\", SUBSYSTEM==\"backlight\", "
- "RUN+=\"/run/current-system/profile/bin/chgrp video /sys/class/backlight/%k/brightness\""
- "\n"
- "ACTION==\"add\", SUBSYSTEM==\"backlight\", "
- "RUN+=\"/run/current-system/profile/bin/chmod g+w /sys/class/backlight/%k/brightness\"")))
+ "RUN+=\"/run/current-system/profile/bin/chgrp video /sys/class/backlight/%k/brightness\""
+ "\n"
+ "ACTION==\"add\", SUBSYSTEM==\"backlight\", "
+ "RUN+=\"/run/current-system/profile/bin/chmod g+w /sys/class/backlight/%k/brightness\"")))
(operating-system
<<system-base>>
(host-name "eminence")
(services (cons*
- (set-xorg-configuration
- (xorg-configuration
- (keyboard-layout keyboard-layout)))
- (modify-services %my-base-services
- (elogind-service-type
- config =>
- (elogind-configuration
- (inherit config)
- (handle-lid-switch-external-power 'suspend)))
- (udev-service-type
- config =>
- (udev-configuration
- (inherit config)
- (rules (cons %backlight-udev-rule
- (udev-configuration-rules config))))))))
+ (set-xorg-configuration
+ (xorg-configuration
+ (keyboard-layout keyboard-layout)))
+ (modify-services %my-base-services
+ (elogind-service-type
+ config =>
+ (elogind-configuration
+ (inherit config)
+ (handle-lid-switch-external-power 'suspend)))
+ (udev-service-type
+ config =>
+ (udev-configuration
+ (inherit config)
+ (rules (cons %backlight-udev-rule
+ (udev-configuration-rules config))))))))
(bootloader
(bootloader-configuration
@@ -414,16 +414,16 @@
(file-systems
(cons* (file-system
- (mount-point "/")
- (device
- (uuid "1d937704-bbeb-43b5-bc63-453886c426af"
- 'ext4))
- (type "ext4"))
- (file-system
- (mount-point "/boot/efi")
- (device (uuid "0031-3784" 'fat32))
- (type "vfat"))
- %base-file-systems)))
+ (mount-point "/")
+ (device
+ (uuid "1d937704-bbeb-43b5-bc63-453886c426af"
+ 'ext4))
+ (type "ext4"))
+ (file-system
+ (mount-point "/boot/efi")
+ (device (uuid "0031-3784" 'fat32))
+ (type "vfat"))
+ %base-file-systems)))
azure
azure is a Lenovo Ideapad 330 laptop.
%backlight-udev-rule should enable members of video group change the display backlight. See the relevant page at Arch Wiki.
@@ -433,27 +433,27 @@
(udev-rule
"90-backlight.rules"
(string-append "ACTION==\"add\", SUBSYSTEM==\"backlight\", "
- "RUN+=\"/run/current-system/profile/bin/chgrp video /sys/class/backlight/%k/brightness\""
- "\n"
- "ACTION==\"add\", SUBSYSTEM==\"backlight\", "
- "RUN+=\"/run/current-system/profile/bin/chmod g+w /sys/class/backlight/%k/brightness\"")))
+ "RUN+=\"/run/current-system/profile/bin/chgrp video /sys/class/backlight/%k/brightness\""
+ "\n"
+ "ACTION==\"add\", SUBSYSTEM==\"backlight\", "
+ "RUN+=\"/run/current-system/profile/bin/chmod g+w /sys/class/backlight/%k/brightness\"")))
(operating-system
<<system-base>>
(host-name "azure")
(services (cons*
- (set-xorg-configuration
- (xorg-configuration
- (keyboard-layout keyboard-layout)))
- (modify-services %my-base-services
- (elogind-service-type config =>
- (elogind-configuration (inherit config)
- (handle-lid-switch-external-power 'suspend)))
- (udev-service-type config =>
- (udev-configuration (inherit config)
- (rules (cons %backlight-udev-rule
- (udev-configuration-rules config))))))))
+ (set-xorg-configuration
+ (xorg-configuration
+ (keyboard-layout keyboard-layout)))
+ (modify-services %my-base-services
+ (elogind-service-type config =>
+ (elogind-configuration (inherit config)
+ (handle-lid-switch-external-power 'suspend)))
+ (udev-service-type config =>
+ (udev-configuration (inherit config)
+ (rules (cons %backlight-udev-rule
+ (udev-configuration-rules config))))))))
(bootloader
(bootloader-configuration
@@ -466,14 +466,14 @@
(file-systems
(cons* (file-system
- (mount-point "/")
- (device (file-system-label "my-root"))
- (type "ext4"))
- (file-system
- (mount-point "/boot/efi")
- (device "/dev/sda1")
- (type "vfat"))
- %base-file-systems)))
+ (mount-point "/")
+ (device (file-system-label "my-root"))
+ (type "ext4"))
+ (file-system
+ (mount-point "/boot/efi")
+ (device "/dev/sda1")
+ (type "vfat"))
+ %base-file-systems)))
iris
iris is my work machine.
<<system-common>>
@@ -483,34 +483,34 @@
(host-name "iris")
(services (cons*
- (set-xorg-configuration
- (xorg-configuration
- (keyboard-layout keyboard-layout)))
- %my-base-services))
+ (set-xorg-configuration
+ (xorg-configuration
+ (keyboard-layout keyboard-layout)))
+ %my-base-services))
(bootloader (bootloader-configuration
- (bootloader grub-bootloader)
- (targets (list "/dev/sdb"))
- (keyboard-layout keyboard-layout)))
+ (bootloader grub-bootloader)
+ (targets (list "/dev/sdb"))
+ (keyboard-layout keyboard-layout)))
(swap-devices (list (swap-space
- (target (uuid
- "bc284384-ff00-4fbc-abda-1c46f69c0505")))))
+ (target (uuid
+ "bc284384-ff00-4fbc-abda-1c46f69c0505")))))
(mapped-devices (list (mapped-device
- (source (uuid
- "21876acb-e05a-4731-8df0-ba5761910ca8"))
- (target "cryptroot")
- (type luks-device-mapping))))
+ (source (uuid
+ "21876acb-e05a-4731-8df0-ba5761910ca8"))
+ (target "cryptroot")
+ (type luks-device-mapping))))
(file-systems (cons* (file-system
- (mount-point "/")
- (device "/dev/mapper/cryptroot")
- (type "ext4")
- (dependencies mapped-devices))
- (file-system
- (mount-point "/boot/efi")
- (device (uuid "782E-F6D3"
- 'fat32))
- (type "vfat")) %base-file-systems)))
+ (mount-point "/")
+ (device "/dev/mapper/cryptroot")
+ (type "ext4")
+ (dependencies mapped-devices))
+ (file-system
+ (mount-point "/boot/efi")
+ (device (uuid "782E-F6D3"
+ 'fat32))
+ (type "vfat")) %base-file-systems)))
System installation
Preparation
In my case, the provided ISO doesn’t work because of the Libre kernel.
@@ -735,11 +735,11 @@ Also not necessary now. Just herd stop vpn and sudo pkill vpn
for env in "${CONDA_ENVS_ALL[@]}"; do
env="${env:1:${#env}-2}"
if [ -w "$env" ]; then
- if [ -f "$env/bin/npm" ]; then
- CONDA_ENVS_NPM+=($env)
- else
- CONDA_ENVS_NO_NPM+=($env)
- fi
+ if [ -f "$env/bin/npm" ]; then
+ CONDA_ENVS_NPM+=($env)
+ else
+ CONDA_ENVS_NO_NPM+=($env)
+ fi
fi
done
diff --git a/configs/index.xml b/configs/index.xml
index 49e268f..c5f7d46 100644
--- a/configs/index.xml
+++ b/configs/index.xml
@@ -12,7 +12,7 @@
https://sqrtminusone.xyz/configs/console/
Mon, 01 Jan 0001 00:00:00 +0000
https://sqrtminusone.xyz/configs/console/
- <blockquote>
<p>No matter from which side you approach penguins, more always come from behind</p>
</blockquote>
<ul>
<li>A friend of mine</li>
</ul>
<h2 id="colors">Colors</h2>
<p>Noweb function to get colors.</p>
<p><a id="code-snippet--get-color"></a></p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">let</span> ((<span style="color:#19177c">color</span> (<span style="color:#008000">or</span> (<span style="color:#19177c">my/color-value</span> <span style="color:#19177c">name</span>))))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">if</span> (<span style="color:#00f">></span> <span style="color:#008000">quote</span> <span style="color:#666">0</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">concat</span> <span style="color:#ba2121">"\""</span> <span style="color:#19177c">color</span> <span style="color:#ba2121">"\""</span>)
</span></span><span style="display:flex;"><span> <span style="color:#19177c">color</span>))
</span></span></code></pre></div><p><a id="code-snippet--get-fg-for-color"></a></p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">let</span> ((<span style="color:#19177c">val</span> (<span style="color:#008000">if</span> (<span style="color:#19177c">ct-light-p</span> (<span style="color:#19177c">my/color-value</span> <span style="color:#19177c">name</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my/color-value</span> <span style="color:#19177c">'black</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my/color-value</span> <span style="color:#19177c">'white</span>))))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">if</span> (<span style="color:#00f">eq</span> <span style="color:#008000">quote</span> <span style="color:#666">1</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">concat</span> <span style="color:#ba2121">"\""</span> <span style="color:#19177c">val</span> <span style="color:#ba2121">"\""</span>)
</span></span><span style="display:flex;"><span> <span style="color:#19177c">val</span>))
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">setq-local</span> <span style="color:#19177c">org-confirm-babel-evaluate</span> <span style="color:#800">nil</span>)
</span></span></code></pre></div><h2 id="dot-profile"><code>.profile</code></h2>
<h3 id="environment">Environment</h3>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span><span style="color:#008000">export</span> <span style="color:#19177c">QT_QPA_PLATFORMTHEME</span><span style="color:#666">=</span><span style="color:#ba2121">"qt5ct"</span>
</span></span><span style="display:flex;"><span><span style="color:#008000">export</span> <span style="color:#19177c">QT_AUTO_SCREEN_SCALE_FACTOR</span><span style="color:#666">=</span><span style="color:#666">0</span>
</span></span></code></pre></div><p>Set ripgrep config path</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span><span style="color:#008000">export</span> <span style="color:#19177c">RIPGREP_CONFIG_PATH</span><span style="color:#666">=</span><span style="color:#19177c">$HOME</span>/.config/ripgrep/ripgreprc
</span></span></code></pre></div><p>hledger path</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span><span style="color:#008000">export</span> <span style="color:#19177c">LEDGER_FILE</span><span style="color:#666">=</span><span style="color:#ba2121">"</span><span style="color:#19177c">$HOME</span><span style="color:#ba2121">/30-39 Life/32 org-mode/ledger/ledger.journal"</span>
</span></span></code></pre></div><p>Checking if running inside termux</p>
+ <blockquote>
<p>No matter from which side you approach penguins, more always come from behind</p></blockquote>
<ul>
<li>A friend of mine</li>
</ul>
<h2 id="colors">Colors</h2>
<p>Noweb function to get colors.</p>
<p><a id="code-snippet--get-color"></a></p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">let</span> ((<span style="color:#19177c">color</span> (<span style="color:#008000">or</span> (<span style="color:#19177c">my/color-value</span> <span style="color:#19177c">name</span>))))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">if</span> (<span style="color:#00f">></span> <span style="color:#008000">quote</span> <span style="color:#666">0</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">concat</span> <span style="color:#ba2121">"\""</span> <span style="color:#19177c">color</span> <span style="color:#ba2121">"\""</span>)
</span></span><span style="display:flex;"><span> <span style="color:#19177c">color</span>))
</span></span></code></pre></div><p><a id="code-snippet--get-fg-for-color"></a></p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">let</span> ((<span style="color:#19177c">val</span> (<span style="color:#008000">if</span> (<span style="color:#19177c">ct-light-p</span> (<span style="color:#19177c">my/color-value</span> <span style="color:#19177c">name</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my/color-value</span> <span style="color:#19177c">'black</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my/color-value</span> <span style="color:#19177c">'white</span>))))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">if</span> (<span style="color:#00f">eq</span> <span style="color:#008000">quote</span> <span style="color:#666">1</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">concat</span> <span style="color:#ba2121">"\""</span> <span style="color:#19177c">val</span> <span style="color:#ba2121">"\""</span>)
</span></span><span style="display:flex;"><span> <span style="color:#19177c">val</span>))
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">setq-local</span> <span style="color:#19177c">org-confirm-babel-evaluate</span> <span style="color:#800">nil</span>)
</span></span></code></pre></div><h2 id="dot-profile"><code>.profile</code></h2>
<h3 id="environment">Environment</h3>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span><span style="color:#008000">export</span> <span style="color:#19177c">QT_QPA_PLATFORMTHEME</span><span style="color:#666">=</span><span style="color:#ba2121">"qt5ct"</span>
</span></span><span style="display:flex;"><span><span style="color:#008000">export</span> <span style="color:#19177c">QT_AUTO_SCREEN_SCALE_FACTOR</span><span style="color:#666">=</span><span style="color:#666">0</span>
</span></span></code></pre></div><p>Set ripgrep config path</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span><span style="color:#008000">export</span> <span style="color:#19177c">RIPGREP_CONFIG_PATH</span><span style="color:#666">=</span><span style="color:#19177c">$HOME</span>/.config/ripgrep/ripgreprc
</span></span></code></pre></div><p>hledger path</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span><span style="color:#008000">export</span> <span style="color:#19177c">LEDGER_FILE</span><span style="color:#666">=</span><span style="color:#ba2121">"</span><span style="color:#19177c">$HOME</span><span style="color:#ba2121">/30-39 Life/32 org-mode/ledger/ledger.journal"</span>
</span></span></code></pre></div><p>Checking if running inside termux</p>
-
Desktop
@@ -26,7 +26,7 @@
https://sqrtminusone.xyz/configs/emacs/
Mon, 01 Jan 0001 00:00:00 +0000
https://sqrtminusone.xyz/configs/emacs/
- <blockquote>
<p>One day we won’t hate one another, no young boy will march to war and I will clean up my Emacs config. But that day isn’t today.</p>
</blockquote>
<ul>
<li>Me, <span class="timestamp-wrapper"><span class="timestamp"><2021-05-27 Thu 17:35> </span></span> in commit 93a0573. Adapted from <a href="https://www.youtube.com/watch?v=pIdBinlW40E">The Dark Element - “The Pallbearer Walks Alone”</a>. T_T</li>
</ul>
<h2 id="introduction">Introduction</h2>
<p>My configuration of <a href="https://www.gnu.org/software/emacs/">GNU Emacs</a>, an awesome <del>text editor</del> piece of software that can do almost anything.</p>
<p>At the moment of writing this, that “almost anything” includes:</p>
+ <blockquote>
<p>One day we won’t hate one another, no young boy will march to war and I will clean up my Emacs config. But that day isn’t today.</p></blockquote>
<ul>
<li>Me, <span class="timestamp-wrapper"><span class="timestamp"><2021-05-27 Thu 17:35> </span></span> in commit 93a0573. Adapted from <a href="https://www.youtube.com/watch?v=pIdBinlW40E">The Dark Element - “The Pallbearer Walks Alone”</a>. T_T</li>
</ul>
<h2 id="introduction">Introduction</h2>
<p>My configuration of <a href="https://www.gnu.org/software/emacs/">GNU Emacs</a>, an awesome <del>text editor</del> piece of software that can do almost anything.</p>
<p>At the moment of writing this, that “almost anything” includes:</p>
-
Guix
@@ -40,7 +40,7 @@
https://sqrtminusone.xyz/configs/mail/
Mon, 01 Jan 0001 00:00:00 +0000
https://sqrtminusone.xyz/configs/mail/
- <p>:TOC: :include all :depth 3</p>
<p>My email configration. Currently I use <a href="https://github.com/gauteh/lieer">lieer</a> to fetch emails from Gmail, <a href="http://davmail.sourceforge.net/">davmail</a> & <a href="http://www.offlineimap.org/">offlineimap</a> to fetch emails from MS Exchange, <a href="https://notmuchmail.org/">notmuch</a> to index, <a href="https://marlam.de/msmtp/">msmtp</a> to send emails. Also using notmuch frontend from Emacs.</p>
<p>My problem with any particular mail setup was that I use Gmail labels quite extensively, and handling these over IMAP is rather awkward. Notmuch seems to be the only software that provides the same first-class support for labels.</p>
+ <p>My email configration. Currently I use <a href="https://github.com/gauteh/lieer">lieer</a> to fetch emails from Gmail, <a href="http://davmail.sourceforge.net/">davmail</a> & <a href="http://www.offlineimap.org/">offlineimap</a> to fetch emails from MS Exchange, <a href="https://notmuchmail.org/">notmuch</a> to index, <a href="https://marlam.de/msmtp/">msmtp</a> to send emails. Also using notmuch frontend from Emacs.</p>
<p>My problem with any particular mail setup was that I use Gmail labels quite extensively, and handling these over IMAP is rather awkward. Notmuch seems to be the only software that provides the same first-class support for labels.</p>
<p>But I also have an Exchange account, with which I communicate via IMAP/SMTP adapter, and in this case, I synchronize notmuch tags and IMAP folders.</p>
-
My dotfiles
diff --git a/configs/mail/index.html b/configs/mail/index.html
index 0e6961e..c4d6f7e 100644
--- a/configs/mail/index.html
+++ b/configs/mail/index.html
@@ -75,8 +75,7 @@
Mail
- :TOC: :include all :depth 3
-My email configration. Currently I use lieer to fetch emails from Gmail, davmail & offlineimap to fetch emails from MS Exchange, notmuch to index, msmtp to send emails. Also using notmuch frontend from Emacs.
+ My email configration. Currently I use lieer to fetch emails from Gmail, davmail & offlineimap to fetch emails from MS Exchange, notmuch to index, msmtp to send emails. Also using notmuch frontend from Emacs.
My problem with any particular mail setup was that I use Gmail labels quite extensively, and handling these over IMAP is rather awkward. Notmuch seems to be the only software that provides the same first-class support for labels.
But I also have an Exchange account, with which I communicate via IMAP/SMTP adapter, and in this case, I synchronize notmuch tags and IMAP folders.
References:
@@ -147,12 +146,16 @@
pass show Job/Digital/Email/pvkorytov@etu.ru | head -n 1
[general]
-accounts = pvkorytov
+accounts = pvkorytov,pvkorytov-mbox
[Account pvkorytov]
localrepository = pvkorytov-local
remoterepository = pvkorytov-remote
+[Account pvkorytov-mbox]
+localrepository = pvkorytov-mbox-local
+remoterepository = pvkorytov-mbox-remote
+
[Repository pvkorytov-local]
type = Maildir
localfolders = ~/Mail/pvkorytov_etu/
@@ -166,6 +169,18 @@
starttls = no
ssl = no
sslcacertfile = /etc/ssl/certs/ca-certificates.crt
+
+[Repository pvkorytov-mbox-local]
+type = Maildir
+localfolders = ~/Mail/pvkorytov_etu_mbox/
+
+[Repository pvkorytov-mbox-remote]
+type = IMAP
+remotehost = mbox.etu.ru
+remoteuser = <<mail-username()>>
+remotepass = <<mail-password()>>
+remoteport = 993
+cert_fingerprint = 07bdfab4eaa79f5fc8ab93cd9ad0ba025ea0b4e5
Notmuch
@@ -278,6 +293,7 @@
+&BCMENAQwBDsENQQ9BD0ESwQ1-
And below is a noweb function, which generates the following commands for notmuch to execute:
- before sync:
@@ -304,39 +320,40 @@ Remove
TAG from emails which are outside the matching PATH(let ((rules '()))
(dolist (row tags)
(let ((tag (nth 0 row))
- (folder (nth 1 row)))
+ (folder (nth 1 row)))
(unless (string-empty-p make_tag)
- (add-to-list
- 'rules
- (format "notmuch tag +%s \"path:%s/%s/cur/** AND NOT tag:%s\""
- tag root folder tag)
- t))
+ (add-to-list
+ 'rules
+ (format "notmuch tag +%s \"path:%s/%s/cur/** AND NOT tag:%s\""
+ tag root folder tag)
+ t))
(unless (string-empty-p remove)
- (add-to-list
- 'rules
- (format "notmuch tag -%s \"NOT path:%s/%s/cur/** AND tag:%s AND tag:%s\""
- tag root folder tag root_tag)
- t))
+ (add-to-list
+ 'rules
+ (format
+ "notmuch tag -%s \"NOT path:%s/%s/cur/** AND path:%s/** AND tag:%s AND tag:%s\""
+ tag root folder root tag root_tag)
+ t))
(unless (string-empty-p move)
- (add-to-list
- 'rules
- (concat
- (format "notmuch search --output=files \"NOT path:%s/%s/cur/** AND tag:%s AND tag:%s\""
- root folder tag root_tag)
- (format " | xargs -I ! mv ! %s/%s/%s/cur/" my/maildir-root root folder))
- t))))
+ (add-to-list
+ 'rules
+ (concat
+ (format "notmuch search --output=files \"NOT path:%s/%s/cur/** AND path:%s/** AND tag:%s AND tag:%s\""
+ root folder root tag root_tag)
+ (format " | xargs -I ! mv ! %s/%s/%s/cur/" my/maildir-root root folder))
+ t))))
(unless (string-empty-p archive_root)
(add-to-list
'rules
(concat
- (format "notmuch search --output=files \"NOT path:%s/%s/cur/** AND %s AND tag:%s\""
- root archive_root
- (mapconcat
- (lambda (row)
- (format "NOT tag:%s" (car row)))
- tags
- " AND ")
- root_tag)
+ (format "notmuch search --output=files \"NOT path:%s/%s/cur/** AND path:%s/** AND %s AND tag:%s\""
+ root archive_root root
+ (mapconcat
+ (lambda (row)
+ (format "NOT tag:%s" (car row)))
+ tags
+ " AND ")
+ root_tag)
(format " | xargs -I ! mv ! %s/%s/%s/cur/" my/maildir-root root archive_root))
t))
(string-join rules "\n"))
@@ -345,24 +362,31 @@ Remove TAG from emails which are outside the matching PATHIt isn’t necessary to run cd for offlineimap, but it’s easier to write that way.
(my/mail-format-tags-rules tags "pvkorytov_etu" "pvkorytov" nil nil t "Archive")
-
# GMI="/home/pavel/Programs/miniconda3/envs/mail/bin/gmi"
+
GMI="/home/pavel/Programs/miniconda3/envs/mail/bin/gmi"
GMI="gmi"
echo "Running pre-new filters"
<<mail-tags(move="t",archive_root="Archive")>>
-echo "Pre-new filters done"
-parallel --link -j0 "(cd /home/pavel/Mail/{1}/ && {2} {3})" ::: thexcloud progin6304 pvkorytov_etu ::: "$GMI" "$GMI" "offlineimap" ::: sync sync ""
-
post_new
+<<mail-tags(move="t",archive_root="Archive",root="pvkorytov_etu_mbox")>>
+echo "Pre-new filters done"
+
+parallel --link -j0 "(cd /home/pavel/Mail/{1}/ && {2} {3})" ::: thexcloud progin6304 pvkorytov_etu ::: "$GMI" "$GMI" "offlineimap" ::: sync sync ""
+post_new
And this hook tags different mailboxes with different tags.
(my/mail-format-tags-rules tags "pvkorytov_etu" "pvkorytov" t t)
notmuch tag +main "path:thexcloud/** AND tag:new"
notmuch tag +progin "path:progin6304/** AND tag:new"
notmuch tag +pvkorytov "path:pvkorytov_etu/** AND tag:new"
+notmuch tag +pvkorytov "path:pvkorytov_etu_mbox/** AND tag:new"
+notmuch tag +mbox "path:pvkorytov_etu_mbox/** AND tag:new"
echo "Running post-new filters"
-<<mail-tags(make_tag="t",remove="t")>>
+<<mail-tags(make_tag="t",remove="t")>>
+
+<<mail-tags(make_tag="t",remove="t",root="pvkorytov_etu_mbox")>>
+
echo "Post-new filters done"
notmuch tag -new "tag:new"
Sync script
@@ -432,10 +456,11 @@ Remove TAG from emails which are outside the matching PATHpasswordeval "pass show My_Online/ETU/progin6304@gmail.com | head -n 1"
account pvkorytov
-tls off
-auth plain
-host localhost
-port 1025
+host mbox.etu.ru
+port 465
+tls on
+tls_starttls off
+tls_fingerprint 87:1F:17:1C:12:A4:DE:82:6F:CF:E5:E6:9C:EE:F8:0B:D1:7D:B2:00:F9:7B:2C:96:21:65:FA:0A:F5:24:8E:0E
from pvkorytov@etu.ru
user pvkorytov
passwordeval "pass show Job/Digital/Email/pvkorytov@etu.ru | head -n 1"
@@ -482,6 +507,9 @@ Remove TAG from emails which are outside the matching PATH (my/use-colors
(notmuch-wash-cited-text :foreground (doom-color 'yellow)))
:config
+ (setq notmuch-fcc-dirs
+ '(("pvkorytov@etu.ru" . "pvkorytov_etu_mbox/Sent")
+ (".*" . "sent")))
(setq mail-specify-envelope-from t)
(setq message-sendmail-envelope-from 'header)
(setq mail-envelope-from 'header)
@@ -501,7 +529,7 @@ Remove TAG from emails which are outside the matching PATH (require 'org-contacts)
(setq notmuch-address-command 'as-is)
(add-hook 'notmuch-hello-mode-hook
- (lambda () (display-line-numbers-mode 0))))
+ (lambda () (display-line-numbers-mode 0))))
The file is read in init.el.
Keybindings
I used to have a more complicated keybinding system here, but that seemed to go against the Dao.
@@ -512,7 +540,8 @@ Remove TAG from emails which are outside the matching PATH notmuch-hello-mode 0 "mail"
notmuch-search-mode 0 "mail"
notmuch-tree-mode 0 "mail"
- notmuch-message-mode 0 "mail")
+ notmuch-message-mode 0 "mail"
+ notmuch-show-mode 0 "mail")
@@ -580,18 +609,18 @@ Remove TAG from emails which are outside the matching PATH (add-to-list
'searches
(format "(:name \"%s\" :query \"%s\" :key \"%s\")"
- (format "%s (%s)"
- (nth 0 root_tag)
- (nth 2 tag))
- (concat "tag:" (nth 0 root_tag)
- (unless (string-empty-p (nth 0 tag))
- (concat " AND tag:" (nth 0 tag))))
- (concat (nth 1 root_tag) (nth 1 tag)))
+ (format "%s (%s)"
+ (nth 0 root_tag)
+ (nth 2 tag))
+ (concat "tag:" (nth 0 root_tag)
+ (unless (string-empty-p (nth 0 tag))
+ (concat " AND tag:" (nth 0 tag))))
+ (concat (nth 1 root_tag) (nth 1 tag)))
t)))
(string-join searches "\n"))
(setq notmuch-saved-searches
'((:name "drafts" :query "tag:draft" :key "d")
- <<format-notmuch-saved-searches()>>))
+ <<format-notmuch-saved-searches()>>))
(setq notmuch-show-empty-saved-searches nil)
(general-define-key
:states '(normal visual)
@@ -603,12 +632,12 @@ Remove TAG from emails which are outside the matching PATH
(setq mml-secure-key-preferences
'((OpenPGP
- (sign
- ("thexcloud@gmail.com" "914472A1FD6775C166F96EBEED739ADF81C78160"))
- (encrypt))
- (CMS
- (sign)
- (encrypt))))
+ (sign
+ ("thexcloud@gmail.com" "914472A1FD6775C166F96EBEED739ADF81C78160"))
+ (encrypt))
+ (CMS
+ (sign)
+ (encrypt))))
Tuning signature
Edit : Apparently this was a feature, not a bug. Disabling this.
By default, message.el inserts the signature at the bottom of the message, like this:
@@ -643,11 +672,11 @@ Remove TAG from emails which are outside the matching PATH (save-excursion
(goto-char (point-min))
(when (re-search-forward message-signature-separator nil t)
- (move-beginning-of-line 0)
- (kill-region (point) (point-max)))
+ (move-beginning-of-line 0)
+ (kill-region (point) (point-max)))
(message-goto-body)
(when (re-search-forward (rx "sign=pgpmime") nil t)
- (forward-line))
+ (forward-line))
(insert (current-kill 0))
(insert "\n\n")
(set-buffer-modified-p nil))))
@@ -657,7 +686,7 @@ Remove TAG from emails which are outside the matching PATHWarn if no subject
(defun my/message-ensure-subject ()
(unless (or (message-field-value "Subject")
- (y-or-n-p "No subject. Send? "))
+ (y-or-n-p "No subject. Send? "))
(user-error "Aborting.")))
(add-hook 'notmuch-mua-send-hook #'my/message-ensure-subject)
@@ -676,20 +705,20 @@ Remove TAG from emails which are outside the matching PATH (message-goto-body)
(cl-block nil
(let ((case-fold-search nil)
- confirmed)
- (while (re-search-forward my/ru-formal-pronous-regex nil t)
- (let* ((match (match-string 0))
- (capitalized (capitalize match))
- (beg (match-beginning 0))
- (end (match-end 0)))
- (if (or confirmed
- (y-or-n-p (format "Replace %s with %s? "
- match capitalized)))
- (progn
- (delete-region beg end)
- (insert capitalized)
- (setq confirmed t))
- (cl-return))))))))
+ confirmed)
+ (while (re-search-forward my/ru-formal-pronous-regex nil t)
+ (let* ((match (match-string 0))
+ (capitalized (capitalize match))
+ (beg (match-beginning 0))
+ (end (match-end 0)))
+ (if (or confirmed
+ (y-or-n-p (format "Replace %s with %s? "
+ match capitalized)))
+ (progn
+ (delete-region beg end)
+ (insert capitalized)
+ (setq confirmed t))
+ (cl-return))))))))
(add-hook 'notmuch-mua-send-hook #'my/message-ensure-capitalized-formal-pronouns)
Ensure password is loaded
diff --git a/index.html b/index.html
index 3567601..e690e67 100644
--- a/index.html
+++ b/index.html
@@ -1,6 +1,6 @@
-
+
diff --git a/index.xml b/index.xml
index 5a44a65..d91e9d7 100644
--- a/index.xml
+++ b/index.xml
@@ -90,6 +90,8 @@
<p>See <a href="https://www.gnu.org/software/emacs/manual/html_node/elisp/Custom-Format-Strings.html">(emacs) Custom Format Strings</a> for information on the general <code>format-spec</code> syntax.</p>
<p>I suspect the package might be slow if your history has a lot of records (I haven’t checked yet). In this case, it might be worth setting a limit:</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">setq</span> <span style="color:#19177c">eshell-atuin-search-options</span> <span style="color:#666">'</span>(<span style="color:#ba2121">"--exit"</span> <span style="color:#ba2121">"0"</span> <span style="color:#ba2121">"--limit"</span> <span style="color:#ba2121">"10000"</span>))
+</span></span></code></pre></div><p>If the package ignores imported history, remove <code>--exit 0</code> from the options (see <a href="https://github.com/SqrtMinusOne/eshell-atuin/issues/9">#9</a>).</p>
+<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">setq</span> <span style="color:#19177c">eshell-atuin-search-options</span> <span style="color:#800">nil</span>)
</span></span></code></pre></div><h2 id="usage">Usage</h2>
<p>Enable <code>eshell-atuin-mode</code> to turn on storing eshell commands in <code>atuin</code>.</p>
<p>Run <code>eshell-atuin-history</code> inside an <code>eshell</code> buffer to browse the saved history. Accepting the completion will insert the command.</p>
@@ -147,11 +149,11 @@
<p>By default, the package selects <code>org-clock</code> records from <code>(org-agenda-files)</code>. Additional options can be included by customizing the <code>org-clock-agg-files-preset</code> variable. For instance:</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">setq</span> <span style="color:#19177c">org-clock-agg-files-preset</span>
</span></span><span style="display:flex;"><span> <span style="color:#666">`</span>((<span style="color:#ba2121">"Org Agenda + Archive"</span>
-</span></span><span style="display:flex;"><span> <span style="color:#666">.</span>
-</span></span><span style="display:flex;"><span> <span style="color:#666">,</span>(<span style="color:#00f">append</span> (<span style="color:#19177c">org-agenda-files</span>)
-</span></span><span style="display:flex;"><span> (<span style="color:#19177c">cl-remove-if</span>
-</span></span><span style="display:flex;"><span> (<span style="color:#008000">lambda</span> (<span style="color:#19177c">f</span>) (<span style="color:#19177c">string-match-p</span> (<span style="color:#008000">rx</span> <span style="color:#ba2121">"."</span> <span style="color:#19177c">eos</span>) <span style="color:#19177c">f</span>))
-</span></span><span style="display:flex;"><span> (<span style="color:#00f">directory-files</span> (<span style="color:#00f">concat</span> <span style="color:#19177c">org-directory</span> <span style="color:#ba2121">"/archive/"</span>) <span style="color:#800">t</span>))))))
+</span></span><span style="display:flex;"><span> <span style="color:#666">.</span>
+</span></span><span style="display:flex;"><span> <span style="color:#666">,</span>(<span style="color:#00f">append</span> (<span style="color:#19177c">org-agenda-files</span>)
+</span></span><span style="display:flex;"><span> (<span style="color:#19177c">cl-remove-if</span>
+</span></span><span style="display:flex;"><span> (<span style="color:#008000">lambda</span> (<span style="color:#19177c">f</span>) (<span style="color:#19177c">string-match-p</span> (<span style="color:#008000">rx</span> <span style="color:#ba2121">"."</span> <span style="color:#19177c">eos</span>) <span style="color:#19177c">f</span>))
+</span></span><span style="display:flex;"><span> (<span style="color:#00f">directory-files</span> (<span style="color:#00f">concat</span> <span style="color:#19177c">org-directory</span> <span style="color:#ba2121">"/archive/"</span>) <span style="color:#800">t</span>))))))
</span></span></code></pre></div><p>Note that after updating any of these variables, you’ll need to reopen the <code>*org-clock-agg*</code> buffer to view the changes.</p>
<p>Alternatively, you can directly specify the list of files within the buffer by selecting “Custom list” in the “Files” control.</p>
<h3 id="date-range">Date Range</h3>
@@ -328,22 +330,22 @@ Customize the formatting of these records through <code>org-clock-agg-elem
</span></span><span style="display:flex;"><span> <span style="color:#008000">:readable-name</span> <span style="color:#ba2121">"Event"</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:default-sort</span> <span style="color:#19177c">total</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let*</span> ((<span style="color:#19177c">title</span> (<span style="color:#19177c">org-element-property</span> <span style="color:#008000">:raw-value</span> (<span style="color:#19177c">alist-get</span> <span style="color:#008000">:headline</span> <span style="color:#19177c">elem</span>)))
-</span></span><span style="display:flex;"><span> (<span style="color:#19177c">is-meeting</span> (<span style="color:#008000">or</span> (<span style="color:#19177c">string-match-p</span> <span style="color:#ba2121">"meeting"</span> (<span style="color:#00f">downcase</span> <span style="color:#19177c">title</span>))
-</span></span><span style="display:flex;"><span> (<span style="color:#19177c">seq-contains-p</span> (<span style="color:#19177c">alist-get</span> <span style="color:#008000">:tags</span> <span style="color:#19177c">elem</span>) <span style="color:#ba2121">"mt"</span>)))
-</span></span><span style="display:flex;"><span> (<span style="color:#19177c">is-offline</span> (<span style="color:#008000">or</span> (<span style="color:#19177c">string-match-p</span> <span style="color:#ba2121">"offline"</span> (<span style="color:#00f">downcase</span> <span style="color:#19177c">title</span>))
-</span></span><span style="display:flex;"><span> (<span style="color:#19177c">seq-contains-p</span> (<span style="color:#19177c">alist-get</span> <span style="color:#008000">:tags</span> <span style="color:#19177c">elem</span>) <span style="color:#ba2121">"offline"</span>)))
-</span></span><span style="display:flex;"><span> (<span style="color:#19177c">title-without-stuff</span> (<span style="color:#19177c">string-trim</span>
-</span></span><span style="display:flex;"><span> (<span style="color:#19177c">replace-regexp-in-string</span>
-</span></span><span style="display:flex;"><span> (<span style="color:#008000">rx</span> (<span style="color:#008000">or</span>
-</span></span><span style="display:flex;"><span> (<span style="color:#19177c">group</span> (<span style="color:#00f">+</span> (<span style="color:#008000">or</span> <span style="color:#19177c">digit</span> <span style="color:#ba2121">"."</span>)))
-</span></span><span style="display:flex;"><span> <span style="color:#ba2121">"(offline)"</span>
-</span></span><span style="display:flex;"><span> (<span style="color:#19177c">seq</span> <span style="color:#ba2121">"["</span> (<span style="color:#00f">+</span> <span style="color:#19177c">alnum</span>) <span style="color:#ba2121">"]"</span>) ))
-</span></span><span style="display:flex;"><span> <span style="color:#ba2121">""</span> <span style="color:#19177c">title</span>))))
+</span></span><span style="display:flex;"><span> (<span style="color:#19177c">is-meeting</span> (<span style="color:#008000">or</span> (<span style="color:#19177c">string-match-p</span> <span style="color:#ba2121">"meeting"</span> (<span style="color:#00f">downcase</span> <span style="color:#19177c">title</span>))
+</span></span><span style="display:flex;"><span> (<span style="color:#19177c">seq-contains-p</span> (<span style="color:#19177c">alist-get</span> <span style="color:#008000">:tags</span> <span style="color:#19177c">elem</span>) <span style="color:#ba2121">"mt"</span>)))
+</span></span><span style="display:flex;"><span> (<span style="color:#19177c">is-offline</span> (<span style="color:#008000">or</span> (<span style="color:#19177c">string-match-p</span> <span style="color:#ba2121">"offline"</span> (<span style="color:#00f">downcase</span> <span style="color:#19177c">title</span>))
+</span></span><span style="display:flex;"><span> (<span style="color:#19177c">seq-contains-p</span> (<span style="color:#19177c">alist-get</span> <span style="color:#008000">:tags</span> <span style="color:#19177c">elem</span>) <span style="color:#ba2121">"offline"</span>)))
+</span></span><span style="display:flex;"><span> (<span style="color:#19177c">title-without-stuff</span> (<span style="color:#19177c">string-trim</span>
+</span></span><span style="display:flex;"><span> (<span style="color:#19177c">replace-regexp-in-string</span>
+</span></span><span style="display:flex;"><span> (<span style="color:#008000">rx</span> (<span style="color:#008000">or</span>
+</span></span><span style="display:flex;"><span> (<span style="color:#19177c">group</span> (<span style="color:#00f">+</span> (<span style="color:#008000">or</span> <span style="color:#19177c">digit</span> <span style="color:#ba2121">"."</span>)))
+</span></span><span style="display:flex;"><span> <span style="color:#ba2121">"(offline)"</span>
+</span></span><span style="display:flex;"><span> (<span style="color:#19177c">seq</span> <span style="color:#ba2121">"["</span> (<span style="color:#00f">+</span> <span style="color:#19177c">alnum</span>) <span style="color:#ba2121">"]"</span>) ))
+</span></span><span style="display:flex;"><span> <span style="color:#ba2121">""</span> <span style="color:#19177c">title</span>))))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">when</span> <span style="color:#19177c">is-meeting</span>
</span></span><span style="display:flex;"><span> <span style="color:#666">`</span>(<span style="color:#ba2121">"Meeting"</span>
-</span></span><span style="display:flex;"><span> <span style="color:#666">,@</span>(<span style="color:#008000">when</span> (<span style="color:#19177c">alist-get</span> <span style="color:#008000">:events-online</span> <span style="color:#19177c">extra-params</span>)
-</span></span><span style="display:flex;"><span> (<span style="color:#008000">if</span> <span style="color:#19177c">is-offline</span> <span style="color:#666">'</span>(<span style="color:#ba2121">"Offline"</span>) <span style="color:#666">'</span>(<span style="color:#ba2121">"Online"</span>)))
-</span></span><span style="display:flex;"><span> <span style="color:#666">,</span><span style="color:#19177c">title-without-stuff</span>))))
+</span></span><span style="display:flex;"><span> <span style="color:#666">,@</span>(<span style="color:#008000">when</span> (<span style="color:#19177c">alist-get</span> <span style="color:#008000">:events-online</span> <span style="color:#19177c">extra-params</span>)
+</span></span><span style="display:flex;"><span> (<span style="color:#008000">if</span> <span style="color:#19177c">is-offline</span> <span style="color:#666">'</span>(<span style="color:#ba2121">"Offline"</span>) <span style="color:#666">'</span>(<span style="color:#ba2121">"Online"</span>)))
+</span></span><span style="display:flex;"><span> <span style="color:#666">,</span><span style="color:#19177c">title-without-stuff</span>))))
</span></span></code></pre></div><p>For the following result:</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>* Results
</span></span><span style="display:flex;"><span>** Meetings
@@ -1212,8 +1214,8 @@ Customize the formatting of these records through <code>org-clock-agg-elem
<p>Global variables must always include a location (section “Select Coordinates or City”). To enter a location, you can either enter latitude and longitude (Open Meteo has an <a href="https://open-meteo.com/en/docs/geocoding-api">API for those</a> as well) or select a location from <code>biome-query-coords</code>. Example configuration:</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">setq</span> <span style="color:#19177c">biome-query-coords</span>
</span></span><span style="display:flex;"><span> <span style="color:#666">'</span>((<span style="color:#ba2121">"Helsinki, Finland"</span> <span style="color:#666">60.16952</span> <span style="color:#666">24.93545</span>)
-</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">"Berlin, Germany"</span> <span style="color:#666">52.52437</span> <span style="color:#666">13.41053</span>)
-</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">"Dubai, UAE"</span> <span style="color:#666">25.0657</span> <span style="color:#666">55.17128</span>)))
+</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">"Berlin, Germany"</span> <span style="color:#666">52.52437</span> <span style="color:#666">13.41053</span>)
+</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">"Dubai, UAE"</span> <span style="color:#666">25.0657</span> <span style="color:#666">55.17128</span>)))
</span></span></code></pre></div><p>A timezone (“Settings” > “Timezone”) may not be required, but be sure to set it because <strong>the default one is UTC+0</strong>.</p>
<p>The current group is switched with <code><tab></code>. Each group’s section has a set of variables that can be toggled on and off, such as temperature, precipitation, etc. Check out the <a href="https://open-meteo.com/en/docs">API docs</a> if you’re interested in the meaning of more esoteric ones.</p>
<p>Press <code>RET</code> after you’ve configured the query to call the API. If something goes wrong, it will output an error, such as:</p>
@@ -1239,8 +1241,8 @@ Customize the formatting of these records through <code>org-clock-agg-elem
<p>Alternatively, use the <code>add-to-list</code> form (generated below the <code>biome-def-preset</code> form). Presets added that way will show up in <code>M-x biome-presets</code> or “Presets” in <code>M-x biome</code>.</p>
<p>Table formatting can be configured with <code>biome-grid-format</code>; check the docstring for more information. For instance, if you want to disable all gradients:</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">setq</span> <span style="color:#19177c">biome-grid-format</span> (<span style="color:#19177c">seq-filter</span> (<span style="color:#008000">lambda</span> (<span style="color:#19177c">f</span>) (<span style="color:#19177c">not</span> (<span style="color:#00f">eq</span> (<span style="color:#00f">car-safe</span> (<span style="color:#00f">nth</span> <span style="color:#666">2</span> <span style="color:#19177c">f</span>))
-</span></span><span style="display:flex;"><span> <span style="color:#19177c">'gradient</span>)))
-</span></span><span style="display:flex;"><span> <span style="color:#19177c">biome-grid-format</span>))
+</span></span><span style="display:flex;"><span> <span style="color:#19177c">'gradient</span>)))
+</span></span><span style="display:flex;"><span> <span style="color:#19177c">biome-grid-format</span>))
</span></span></code></pre></div><p>Turn off highlighting of the current hour or day as follows:</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">setq</span> <span style="color:#19177c">biome-grid-highlight-current</span> <span style="color:#800">nil</span>)
</span></span></code></pre></div><h2 id="composite-queries">Composite queries</h2>
@@ -1329,8 +1331,7 @@ Customize the formatting of these records through <code>org-clock-agg-elem
}
</style>
<blockquote>
-<p>Poof I made my free-time disappear</p>
-</blockquote>
+<p>Poof I made my free-time disappear</p></blockquote>
<p class="quote-title">- <a href="https://elken.dev">Ellis Kenyő</a>, on being called an "elisp mage"
<p>Little did I know on the fateful day of <strong><span class="timestamp-wrapper"><span class="timestamp">[2020-10-09 Fri]</span></span></strong>, when I had installed <a href="https://www.gnu.org/software/emacs/">GNU Emacs</a>. I wasn’t thinking about the <a href="https://www.gnu.org/philosophy/philosophy.html">ethical aspects</a> of free software, the <a href="https://www.webofstories.com/play/marvin.minsky/44">aesthetics of Lisp</a>, or these other things with which an occasional layperson might explain how an almost <a href="https://www.jwz.org/doc/emacs-timeline.html">half a century old</a> program can still be in <a href="https://emacsconf.org/2022/talks/survey/">active use</a>.</p>
<p>In fact, when considering using software X for anything, the most important question to me was: can X provide a better user experience? For Emacs, the answer to most of these questions turned out to be yes.</p>
@@ -2914,55 +2915,55 @@ assigned to group with the least amount of members.</li>
<p>Here is an excerpt from my configuration that was used to produce this screenshot:</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">setq</span> <span style="color:#19177c">elfeed-summary-settings</span>
</span></span><span style="display:flex;"><span> <span style="color:#666">'</span>((<span style="color:#19177c">group</span> (<span style="color:#008000">:title</span> <span style="color:#666">.</span> <span style="color:#ba2121">"GitHub"</span>)
-</span></span><span style="display:flex;"><span> (<span style="color:#008000">:elements</span>
-</span></span><span style="display:flex;"><span> (<span style="color:#19177c">query</span> <span style="color:#666">.</span> (<span style="color:#19177c">url</span> <span style="color:#666">.</span> <span style="color:#ba2121">"SqrtMinusOne.private.atom"</span>))
-</span></span><span style="display:flex;"><span> (<span style="color:#19177c">group</span> <span style="color:#666">.</span> ((<span style="color:#008000">:title</span> <span style="color:#666">.</span> <span style="color:#ba2121">"Guix packages"</span>)
-</span></span><span style="display:flex;"><span> (<span style="color:#008000">:elements</span>
-</span></span><span style="display:flex;"><span> (<span style="color:#19177c">query</span> <span style="color:#666">.</span> (<span style="color:#008000">and</span> <span style="color:#19177c">github</span> <span style="color:#19177c">guix_packages</span>)))
-</span></span><span style="display:flex;"><span> (<span style="color:#008000">:hide</span> <span style="color:#800">t</span>)))))
-</span></span><span style="display:flex;"><span> (<span style="color:#19177c">group</span> (<span style="color:#008000">:title</span> <span style="color:#666">.</span> <span style="color:#ba2121">"Blogs [Software]"</span>)
-</span></span><span style="display:flex;"><span> (<span style="color:#008000">:elements</span>
-</span></span><span style="display:flex;"><span> (<span style="color:#19177c">query</span> <span style="color:#666">.</span> <span style="color:#19177c">software_blogs</span>)))
-</span></span><span style="display:flex;"><span> (<span style="color:#19177c">group</span> (<span style="color:#008000">:title</span> <span style="color:#666">.</span> <span style="color:#ba2121">"Blogs [People]"</span>)
-</span></span><span style="display:flex;"><span> (<span style="color:#008000">:elements</span>
-</span></span><span style="display:flex;"><span> (<span style="color:#19177c">query</span> <span style="color:#666">.</span> (<span style="color:#008000">and</span> <span style="color:#19177c">blogs</span> <span style="color:#19177c">people</span> (<span style="color:#19177c">not</span> <span style="color:#19177c">emacs</span>)))
-</span></span><span style="display:flex;"><span> (<span style="color:#19177c">group</span> (<span style="color:#008000">:title</span> <span style="color:#666">.</span> <span style="color:#ba2121">"Emacs"</span>)
-</span></span><span style="display:flex;"><span> (<span style="color:#008000">:elements</span>
-</span></span><span style="display:flex;"><span> (<span style="color:#19177c">query</span> <span style="color:#666">.</span> (<span style="color:#008000">and</span> <span style="color:#19177c">blogs</span> <span style="color:#19177c">people</span> <span style="color:#19177c">emacs</span>))))))
-</span></span><span style="display:flex;"><span> (<span style="color:#19177c">group</span> (<span style="color:#008000">:title</span> <span style="color:#666">.</span> <span style="color:#ba2121">"Podcasts"</span>)
-</span></span><span style="display:flex;"><span> (<span style="color:#008000">:elements</span>
-</span></span><span style="display:flex;"><span> (<span style="color:#19177c">query</span> <span style="color:#666">.</span> <span style="color:#19177c">podcasts</span>)))
-</span></span><span style="display:flex;"><span> (<span style="color:#19177c">group</span> (<span style="color:#008000">:title</span> <span style="color:#666">.</span> <span style="color:#ba2121">"Videos"</span>)
-</span></span><span style="display:flex;"><span> (<span style="color:#008000">:elements</span>
-</span></span><span style="display:flex;"><span> (<span style="color:#19177c">group</span>
-</span></span><span style="display:flex;"><span> (<span style="color:#008000">:title</span> <span style="color:#666">.</span> <span style="color:#ba2121">"Music"</span>)
-</span></span><span style="display:flex;"><span> (<span style="color:#008000">:elements</span>
-</span></span><span style="display:flex;"><span> (<span style="color:#19177c">query</span> <span style="color:#666">.</span> (<span style="color:#008000">and</span> <span style="color:#19177c">videos</span> <span style="color:#19177c">music</span>))))
-</span></span><span style="display:flex;"><span> (<span style="color:#19177c">group</span>
-</span></span><span style="display:flex;"><span> (<span style="color:#008000">:title</span> <span style="color:#666">.</span> <span style="color:#ba2121">"Tech"</span>)
-</span></span><span style="display:flex;"><span> (<span style="color:#008000">:elements</span>
-</span></span><span style="display:flex;"><span> (<span style="color:#19177c">query</span> <span style="color:#666">.</span> (<span style="color:#008000">and</span> <span style="color:#19177c">videos</span> <span style="color:#19177c">tech</span>))))
-</span></span><span style="display:flex;"><span> (<span style="color:#19177c">group</span>
-</span></span><span style="display:flex;"><span> (<span style="color:#008000">:title</span> <span style="color:#666">.</span> <span style="color:#ba2121">"History"</span>)
-</span></span><span style="display:flex;"><span> (<span style="color:#008000">:elements</span>
-</span></span><span style="display:flex;"><span> (<span style="color:#19177c">query</span> <span style="color:#666">.</span> (<span style="color:#008000">and</span> <span style="color:#19177c">videos</span> <span style="color:#19177c">history</span>))))
-</span></span><span style="display:flex;"><span> <span style="color:#408080;font-style:italic">;; ...</span>
-</span></span><span style="display:flex;"><span> ))
-</span></span><span style="display:flex;"><span> <span style="color:#408080;font-style:italic">;; ...</span>
-</span></span><span style="display:flex;"><span> (<span style="color:#19177c">group</span> (<span style="color:#008000">:title</span> <span style="color:#666">.</span> <span style="color:#ba2121">"Miscellaneous"</span>)
-</span></span><span style="display:flex;"><span> (<span style="color:#008000">:elements</span>
-</span></span><span style="display:flex;"><span> (<span style="color:#19177c">group</span>
-</span></span><span style="display:flex;"><span> (<span style="color:#008000">:title</span> <span style="color:#666">.</span> <span style="color:#ba2121">"Searches"</span>)
-</span></span><span style="display:flex;"><span> (<span style="color:#008000">:elements</span>
-</span></span><span style="display:flex;"><span> (<span style="color:#19177c">search</span>
-</span></span><span style="display:flex;"><span> (<span style="color:#008000">:filter</span> <span style="color:#666">.</span> <span style="color:#ba2121">"@6-months-ago sqrtminusone"</span>)
-</span></span><span style="display:flex;"><span> (<span style="color:#008000">:title</span> <span style="color:#666">.</span> <span style="color:#ba2121">"About me"</span>))
-</span></span><span style="display:flex;"><span> (<span style="color:#19177c">search</span>
-</span></span><span style="display:flex;"><span> (<span style="color:#008000">:filter</span> <span style="color:#666">.</span> <span style="color:#ba2121">"+later"</span>)
-</span></span><span style="display:flex;"><span> (<span style="color:#008000">:title</span> <span style="color:#666">.</span> <span style="color:#ba2121">"Check later"</span>))))
-</span></span><span style="display:flex;"><span> (<span style="color:#19177c">group</span>
-</span></span><span style="display:flex;"><span> (<span style="color:#008000">:title</span> <span style="color:#666">.</span> <span style="color:#ba2121">"Ungrouped"</span>)
-</span></span><span style="display:flex;"><span> (<span style="color:#008000">:elements</span> <span style="color:#008000">:misc</span>))))))
+</span></span><span style="display:flex;"><span> (<span style="color:#008000">:elements</span>
+</span></span><span style="display:flex;"><span> (<span style="color:#19177c">query</span> <span style="color:#666">.</span> (<span style="color:#19177c">url</span> <span style="color:#666">.</span> <span style="color:#ba2121">"SqrtMinusOne.private.atom"</span>))
+</span></span><span style="display:flex;"><span> (<span style="color:#19177c">group</span> <span style="color:#666">.</span> ((<span style="color:#008000">:title</span> <span style="color:#666">.</span> <span style="color:#ba2121">"Guix packages"</span>)
+</span></span><span style="display:flex;"><span> (<span style="color:#008000">:elements</span>
+</span></span><span style="display:flex;"><span> (<span style="color:#19177c">query</span> <span style="color:#666">.</span> (<span style="color:#008000">and</span> <span style="color:#19177c">github</span> <span style="color:#19177c">guix_packages</span>)))
+</span></span><span style="display:flex;"><span> (<span style="color:#008000">:hide</span> <span style="color:#800">t</span>)))))
+</span></span><span style="display:flex;"><span> (<span style="color:#19177c">group</span> (<span style="color:#008000">:title</span> <span style="color:#666">.</span> <span style="color:#ba2121">"Blogs [Software]"</span>)
+</span></span><span style="display:flex;"><span> (<span style="color:#008000">:elements</span>
+</span></span><span style="display:flex;"><span> (<span style="color:#19177c">query</span> <span style="color:#666">.</span> <span style="color:#19177c">software_blogs</span>)))
+</span></span><span style="display:flex;"><span> (<span style="color:#19177c">group</span> (<span style="color:#008000">:title</span> <span style="color:#666">.</span> <span style="color:#ba2121">"Blogs [People]"</span>)
+</span></span><span style="display:flex;"><span> (<span style="color:#008000">:elements</span>
+</span></span><span style="display:flex;"><span> (<span style="color:#19177c">query</span> <span style="color:#666">.</span> (<span style="color:#008000">and</span> <span style="color:#19177c">blogs</span> <span style="color:#19177c">people</span> (<span style="color:#19177c">not</span> <span style="color:#19177c">emacs</span>)))
+</span></span><span style="display:flex;"><span> (<span style="color:#19177c">group</span> (<span style="color:#008000">:title</span> <span style="color:#666">.</span> <span style="color:#ba2121">"Emacs"</span>)
+</span></span><span style="display:flex;"><span> (<span style="color:#008000">:elements</span>
+</span></span><span style="display:flex;"><span> (<span style="color:#19177c">query</span> <span style="color:#666">.</span> (<span style="color:#008000">and</span> <span style="color:#19177c">blogs</span> <span style="color:#19177c">people</span> <span style="color:#19177c">emacs</span>))))))
+</span></span><span style="display:flex;"><span> (<span style="color:#19177c">group</span> (<span style="color:#008000">:title</span> <span style="color:#666">.</span> <span style="color:#ba2121">"Podcasts"</span>)
+</span></span><span style="display:flex;"><span> (<span style="color:#008000">:elements</span>
+</span></span><span style="display:flex;"><span> (<span style="color:#19177c">query</span> <span style="color:#666">.</span> <span style="color:#19177c">podcasts</span>)))
+</span></span><span style="display:flex;"><span> (<span style="color:#19177c">group</span> (<span style="color:#008000">:title</span> <span style="color:#666">.</span> <span style="color:#ba2121">"Videos"</span>)
+</span></span><span style="display:flex;"><span> (<span style="color:#008000">:elements</span>
+</span></span><span style="display:flex;"><span> (<span style="color:#19177c">group</span>
+</span></span><span style="display:flex;"><span> (<span style="color:#008000">:title</span> <span style="color:#666">.</span> <span style="color:#ba2121">"Music"</span>)
+</span></span><span style="display:flex;"><span> (<span style="color:#008000">:elements</span>
+</span></span><span style="display:flex;"><span> (<span style="color:#19177c">query</span> <span style="color:#666">.</span> (<span style="color:#008000">and</span> <span style="color:#19177c">videos</span> <span style="color:#19177c">music</span>))))
+</span></span><span style="display:flex;"><span> (<span style="color:#19177c">group</span>
+</span></span><span style="display:flex;"><span> (<span style="color:#008000">:title</span> <span style="color:#666">.</span> <span style="color:#ba2121">"Tech"</span>)
+</span></span><span style="display:flex;"><span> (<span style="color:#008000">:elements</span>
+</span></span><span style="display:flex;"><span> (<span style="color:#19177c">query</span> <span style="color:#666">.</span> (<span style="color:#008000">and</span> <span style="color:#19177c">videos</span> <span style="color:#19177c">tech</span>))))
+</span></span><span style="display:flex;"><span> (<span style="color:#19177c">group</span>
+</span></span><span style="display:flex;"><span> (<span style="color:#008000">:title</span> <span style="color:#666">.</span> <span style="color:#ba2121">"History"</span>)
+</span></span><span style="display:flex;"><span> (<span style="color:#008000">:elements</span>
+</span></span><span style="display:flex;"><span> (<span style="color:#19177c">query</span> <span style="color:#666">.</span> (<span style="color:#008000">and</span> <span style="color:#19177c">videos</span> <span style="color:#19177c">history</span>))))
+</span></span><span style="display:flex;"><span> <span style="color:#408080;font-style:italic">;; ...</span>
+</span></span><span style="display:flex;"><span> ))
+</span></span><span style="display:flex;"><span> <span style="color:#408080;font-style:italic">;; ...</span>
+</span></span><span style="display:flex;"><span> (<span style="color:#19177c">group</span> (<span style="color:#008000">:title</span> <span style="color:#666">.</span> <span style="color:#ba2121">"Miscellaneous"</span>)
+</span></span><span style="display:flex;"><span> (<span style="color:#008000">:elements</span>
+</span></span><span style="display:flex;"><span> (<span style="color:#19177c">group</span>
+</span></span><span style="display:flex;"><span> (<span style="color:#008000">:title</span> <span style="color:#666">.</span> <span style="color:#ba2121">"Searches"</span>)
+</span></span><span style="display:flex;"><span> (<span style="color:#008000">:elements</span>
+</span></span><span style="display:flex;"><span> (<span style="color:#19177c">search</span>
+</span></span><span style="display:flex;"><span> (<span style="color:#008000">:filter</span> <span style="color:#666">.</span> <span style="color:#ba2121">"@6-months-ago sqrtminusone"</span>)
+</span></span><span style="display:flex;"><span> (<span style="color:#008000">:title</span> <span style="color:#666">.</span> <span style="color:#ba2121">"About me"</span>))
+</span></span><span style="display:flex;"><span> (<span style="color:#19177c">search</span>
+</span></span><span style="display:flex;"><span> (<span style="color:#008000">:filter</span> <span style="color:#666">.</span> <span style="color:#ba2121">"+later"</span>)
+</span></span><span style="display:flex;"><span> (<span style="color:#008000">:title</span> <span style="color:#666">.</span> <span style="color:#ba2121">"Check later"</span>))))
+</span></span><span style="display:flex;"><span> (<span style="color:#19177c">group</span>
+</span></span><span style="display:flex;"><span> (<span style="color:#008000">:title</span> <span style="color:#666">.</span> <span style="color:#ba2121">"Ungrouped"</span>)
+</span></span><span style="display:flex;"><span> (<span style="color:#008000">:elements</span> <span style="color:#008000">:misc</span>))))))
</span></span></code></pre></div><h3 id="automatic-generation-of-groups">Automatic generation of groups</h3>
<h4 id="auto-tags"><code>auto-tags</code></h4>
<p>As described in the <a href="#tree-configuration-1">tree configuration</a> section, there are two ways to avoid defining all the relevant groups manually, <code>auto-tags</code> and <code>tag-groups</code>. Both use tags that are defined in <code>elfeed-feeds</code>.</p>
@@ -3198,10 +3199,10 @@ assigned to group with the least amount of members.</li>
</ul>
<p>The default value is as follows:</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span><span style="color:#666">'</span>((<span style="color:#19177c">autotype</span> <span style="color:#666">.</span> (<span style="color:#19177c">wait</span>
-</span></span><span style="display:flex;"><span> (<span style="color:#19177c">field</span> <span style="color:#666">.</span> <span style="color:#ba2121">"username"</span>)
-</span></span><span style="display:flex;"><span> (<span style="color:#19177c">key</span> <span style="color:#666">.</span> <span style="color:#ba2121">"Tab"</span>)
-</span></span><span style="display:flex;"><span> (<span style="color:#19177c">field</span> <span style="color:#666">.</span> <span style="color:#19177c">secret</span>)
-</span></span><span style="display:flex;"><span> (<span style="color:#19177c">key</span> <span style="color:#666">.</span> <span style="color:#ba2121">"Return"</span>)))
+</span></span><span style="display:flex;"><span> (<span style="color:#19177c">field</span> <span style="color:#666">.</span> <span style="color:#ba2121">"username"</span>)
+</span></span><span style="display:flex;"><span> (<span style="color:#19177c">key</span> <span style="color:#666">.</span> <span style="color:#ba2121">"Tab"</span>)
+</span></span><span style="display:flex;"><span> (<span style="color:#19177c">field</span> <span style="color:#666">.</span> <span style="color:#19177c">secret</span>)
+</span></span><span style="display:flex;"><span> (<span style="color:#19177c">key</span> <span style="color:#666">.</span> <span style="color:#ba2121">"Return"</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">password</span> <span style="color:#666">.</span> (<span style="color:#19177c">wait</span> (<span style="color:#19177c">field</span> <span style="color:#666">.</span> <span style="color:#19177c">secret</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">username</span> <span style="color:#666">.</span> (<span style="color:#19177c">wait</span> (<span style="color:#19177c">field</span> <span style="color:#666">.</span> <span style="color:#ba2121">"username"</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">url</span> <span style="color:#666">.</span> (<span style="color:#19177c">wait</span> (<span style="color:#19177c">field</span> <span style="color:#666">.</span> <span style="color:#ba2121">"url"</span>))))
@@ -3870,7 +3871,7 @@ timestamps by their date.</li>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">org-journal-tags-prop-apply-delta</span> <span style="color:#008000">:add</span> (<span style="color:#00f">list</span> <span style="color:#19177c">my/loc-tag</span>))))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#19177c">add-hook</span> <span style="color:#19177c">'org-journal-after-entry-create-hook</span>
-</span></span><span style="display:flex;"><span> <span style="color:#00f">#'</span><span style="color:#19177c">my/set-journal-header</span>)
+</span></span><span style="display:flex;"><span> <span style="color:#00f">#'</span><span style="color:#19177c">my/set-journal-header</span>)
</span></span></code></pre></div><h3 id="encryption">Encryption</h3>
<p>There are two ways how org-journal can be encrypted:</p>
<ul>
@@ -4542,7 +4543,7 @@ interval = 1
<p>The package can be used with <a href="https://orgmode.org/manual/Clocking-commands.html">org-clock</a> in the following way. Set up these two hooks:</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#19177c">add-hook</span> <span style="color:#19177c">'pomm-on-status-changed-hook</span> <span style="color:#00f">#'</span><span style="color:#19177c">pomm--sync-org-clock</span>)
</span></span><span style="display:flex;"><span>(<span style="color:#19177c">add-hook</span> <span style="color:#19177c">'pomm-third-time-on-status-changed-hook</span>
-</span></span><span style="display:flex;"><span> <span style="color:#00f">#'</span><span style="color:#19177c">pomm-third-time--sync-org-clock</span>
+</span></span><span style="display:flex;"><span> <span style="color:#00f">#'</span><span style="color:#19177c">pomm-third-time--sync-org-clock</span>
</span></span></code></pre></div><p>Then, start the timer (either <code>pomm</code> or <code>pomm-third-time</code>) and <code>org-clock-in</code>, in whichever order. The package will call <code>org-clock-out</code> when a break starts and <code>org-clock-in-last</code> when it ends.</p>
<p>Setting <code>pomm-org-clock-in-immediately</code> to <code>nil</code> “defers” calling <code>org-clock-in-last</code> until after any command from the user (via <code>post-command-hook</code>). I’ve added this because I occasionally return to my PC a few minutes after the break ends, so I don’t want these minutes to show up in <code>org-clock</code>.</p>
<p>Also see <a href="https://github.com/SqrtMinusOne/pomm.el/issues/13#issuecomment-2216868331">this comment</a> (<a href="https://github.com/SqrtMinusOne/pomm.el/issues/13">#13</a>) for an alternative approach.</p>
diff --git a/packages/biome/index.html b/packages/biome/index.html
index 98285d7..e1d7c3d 100644
--- a/packages/biome/index.html
+++ b/packages/biome/index.html
@@ -111,8 +111,8 @@
Global variables must always include a location (section “Select Coordinates or City”). To enter a location, you can either enter latitude and longitude (Open Meteo has an API for those as well) or select a location from biome-query-coords. Example configuration:
(setq biome-query-coords
'(("Helsinki, Finland" 60.16952 24.93545)
- ("Berlin, Germany" 52.52437 13.41053)
- ("Dubai, UAE" 25.0657 55.17128)))
+ ("Berlin, Germany" 52.52437 13.41053)
+ ("Dubai, UAE" 25.0657 55.17128)))
A timezone (“Settings” > “Timezone”) may not be required, but be sure to set it because the default one is UTC+0.
The current group is switched with <tab>. Each group’s section has a set of variables that can be toggled on and off, such as temperature, precipitation, etc. Check out the API docs if you’re interested in the meaning of more esoteric ones.
Press RET after you’ve configured the query to call the API. If something goes wrong, it will output an error, such as:
@@ -138,8 +138,8 @@
Alternatively, use the add-to-list form (generated below the biome-def-preset form). Presets added that way will show up in M-x biome-presets or “Presets” in M-x biome.
Table formatting can be configured with biome-grid-format; check the docstring for more information. For instance, if you want to disable all gradients:
(setq biome-grid-format (seq-filter (lambda (f) (not (eq (car-safe (nth 2 f))
- 'gradient)))
- biome-grid-format))
+ 'gradient)))
+ biome-grid-format))
Turn off highlighting of the current hour or day as follows:
(setq biome-grid-highlight-current nil)
Composite queries
diff --git a/packages/elfeed-summary/index.html b/packages/elfeed-summary/index.html
index 2adde81..f093ca2 100644
--- a/packages/elfeed-summary/index.html
+++ b/packages/elfeed-summary/index.html
@@ -234,55 +234,55 @@ assigned to group with the least amount of members.
Here is an excerpt from my configuration that was used to produce this screenshot:
(setq elfeed-summary-settings
'((group (:title . "GitHub")
- (:elements
- (query . (url . "SqrtMinusOne.private.atom"))
- (group . ((:title . "Guix packages")
- (:elements
- (query . (and github guix_packages)))
- (:hide t)))))
- (group (:title . "Blogs [Software]")
- (:elements
- (query . software_blogs)))
- (group (:title . "Blogs [People]")
- (:elements
- (query . (and blogs people (not emacs)))
- (group (:title . "Emacs")
- (:elements
- (query . (and blogs people emacs))))))
- (group (:title . "Podcasts")
- (:elements
- (query . podcasts)))
- (group (:title . "Videos")
- (:elements
- (group
- (:title . "Music")
- (:elements
- (query . (and videos music))))
- (group
- (:title . "Tech")
- (:elements
- (query . (and videos tech))))
- (group
- (:title . "History")
- (:elements
- (query . (and videos history))))
- ;; ...
- ))
- ;; ...
- (group (:title . "Miscellaneous")
- (:elements
- (group
- (:title . "Searches")
- (:elements
- (search
- (:filter . "@6-months-ago sqrtminusone")
- (:title . "About me"))
- (search
- (:filter . "+later")
- (:title . "Check later"))))
- (group
- (:title . "Ungrouped")
- (:elements :misc))))))
+ (:elements
+ (query . (url . "SqrtMinusOne.private.atom"))
+ (group . ((:title . "Guix packages")
+ (:elements
+ (query . (and github guix_packages)))
+ (:hide t)))))
+ (group (:title . "Blogs [Software]")
+ (:elements
+ (query . software_blogs)))
+ (group (:title . "Blogs [People]")
+ (:elements
+ (query . (and blogs people (not emacs)))
+ (group (:title . "Emacs")
+ (:elements
+ (query . (and blogs people emacs))))))
+ (group (:title . "Podcasts")
+ (:elements
+ (query . podcasts)))
+ (group (:title . "Videos")
+ (:elements
+ (group
+ (:title . "Music")
+ (:elements
+ (query . (and videos music))))
+ (group
+ (:title . "Tech")
+ (:elements
+ (query . (and videos tech))))
+ (group
+ (:title . "History")
+ (:elements
+ (query . (and videos history))))
+ ;; ...
+ ))
+ ;; ...
+ (group (:title . "Miscellaneous")
+ (:elements
+ (group
+ (:title . "Searches")
+ (:elements
+ (search
+ (:filter . "@6-months-ago sqrtminusone")
+ (:title . "About me"))
+ (search
+ (:filter . "+later")
+ (:title . "Check later"))))
+ (group
+ (:title . "Ungrouped")
+ (:elements :misc))))))
Automatic generation of groups
auto-tags
As described in the tree configuration section, there are two ways to avoid defining all the relevant groups manually, auto-tags and tag-groups. Both use tags that are defined in elfeed-feeds.
diff --git a/packages/eshell-atuin/index.html b/packages/eshell-atuin/index.html
index be9bd65..2bc8aa4 100644
--- a/packages/eshell-atuin/index.html
+++ b/packages/eshell-atuin/index.html
@@ -155,6 +155,8 @@
See (emacs) Custom Format Strings for information on the general format-spec syntax.
I suspect the package might be slow if your history has a lot of records (I haven’t checked yet). In this case, it might be worth setting a limit:
(setq eshell-atuin-search-options '("--exit" "0" "--limit" "10000"))
+
If the package ignores imported history, remove --exit 0 from the options (see #9).
+(setq eshell-atuin-search-options nil)
Usage
Enable eshell-atuin-mode to turn on storing eshell commands in atuin.
Run eshell-atuin-history inside an eshell buffer to browse the saved history. Accepting the completion will insert the command.
diff --git a/packages/index.xml b/packages/index.xml
index 4a2e115..941d546 100644
--- a/packages/index.xml
+++ b/packages/index.xml
@@ -90,6 +90,8 @@
<p>See <a href="https://www.gnu.org/software/emacs/manual/html_node/elisp/Custom-Format-Strings.html">(emacs) Custom Format Strings</a> for information on the general <code>format-spec</code> syntax.</p>
<p>I suspect the package might be slow if your history has a lot of records (I haven’t checked yet). In this case, it might be worth setting a limit:</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">setq</span> <span style="color:#19177c">eshell-atuin-search-options</span> <span style="color:#666">'</span>(<span style="color:#ba2121">"--exit"</span> <span style="color:#ba2121">"0"</span> <span style="color:#ba2121">"--limit"</span> <span style="color:#ba2121">"10000"</span>))
+</span></span></code></pre></div><p>If the package ignores imported history, remove <code>--exit 0</code> from the options (see <a href="https://github.com/SqrtMinusOne/eshell-atuin/issues/9">#9</a>).</p>
+<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">setq</span> <span style="color:#19177c">eshell-atuin-search-options</span> <span style="color:#800">nil</span>)
</span></span></code></pre></div><h2 id="usage">Usage</h2>
<p>Enable <code>eshell-atuin-mode</code> to turn on storing eshell commands in <code>atuin</code>.</p>
<p>Run <code>eshell-atuin-history</code> inside an <code>eshell</code> buffer to browse the saved history. Accepting the completion will insert the command.</p>
@@ -147,11 +149,11 @@
<p>By default, the package selects <code>org-clock</code> records from <code>(org-agenda-files)</code>. Additional options can be included by customizing the <code>org-clock-agg-files-preset</code> variable. For instance:</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">setq</span> <span style="color:#19177c">org-clock-agg-files-preset</span>
</span></span><span style="display:flex;"><span> <span style="color:#666">`</span>((<span style="color:#ba2121">"Org Agenda + Archive"</span>
-</span></span><span style="display:flex;"><span> <span style="color:#666">.</span>
-</span></span><span style="display:flex;"><span> <span style="color:#666">,</span>(<span style="color:#00f">append</span> (<span style="color:#19177c">org-agenda-files</span>)
-</span></span><span style="display:flex;"><span> (<span style="color:#19177c">cl-remove-if</span>
-</span></span><span style="display:flex;"><span> (<span style="color:#008000">lambda</span> (<span style="color:#19177c">f</span>) (<span style="color:#19177c">string-match-p</span> (<span style="color:#008000">rx</span> <span style="color:#ba2121">"."</span> <span style="color:#19177c">eos</span>) <span style="color:#19177c">f</span>))
-</span></span><span style="display:flex;"><span> (<span style="color:#00f">directory-files</span> (<span style="color:#00f">concat</span> <span style="color:#19177c">org-directory</span> <span style="color:#ba2121">"/archive/"</span>) <span style="color:#800">t</span>))))))
+</span></span><span style="display:flex;"><span> <span style="color:#666">.</span>
+</span></span><span style="display:flex;"><span> <span style="color:#666">,</span>(<span style="color:#00f">append</span> (<span style="color:#19177c">org-agenda-files</span>)
+</span></span><span style="display:flex;"><span> (<span style="color:#19177c">cl-remove-if</span>
+</span></span><span style="display:flex;"><span> (<span style="color:#008000">lambda</span> (<span style="color:#19177c">f</span>) (<span style="color:#19177c">string-match-p</span> (<span style="color:#008000">rx</span> <span style="color:#ba2121">"."</span> <span style="color:#19177c">eos</span>) <span style="color:#19177c">f</span>))
+</span></span><span style="display:flex;"><span> (<span style="color:#00f">directory-files</span> (<span style="color:#00f">concat</span> <span style="color:#19177c">org-directory</span> <span style="color:#ba2121">"/archive/"</span>) <span style="color:#800">t</span>))))))
</span></span></code></pre></div><p>Note that after updating any of these variables, you’ll need to reopen the <code>*org-clock-agg*</code> buffer to view the changes.</p>
<p>Alternatively, you can directly specify the list of files within the buffer by selecting “Custom list” in the “Files” control.</p>
<h3 id="date-range">Date Range</h3>
@@ -328,22 +330,22 @@ Customize the formatting of these records through <code>org-clock-agg-elem
</span></span><span style="display:flex;"><span> <span style="color:#008000">:readable-name</span> <span style="color:#ba2121">"Event"</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:default-sort</span> <span style="color:#19177c">total</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let*</span> ((<span style="color:#19177c">title</span> (<span style="color:#19177c">org-element-property</span> <span style="color:#008000">:raw-value</span> (<span style="color:#19177c">alist-get</span> <span style="color:#008000">:headline</span> <span style="color:#19177c">elem</span>)))
-</span></span><span style="display:flex;"><span> (<span style="color:#19177c">is-meeting</span> (<span style="color:#008000">or</span> (<span style="color:#19177c">string-match-p</span> <span style="color:#ba2121">"meeting"</span> (<span style="color:#00f">downcase</span> <span style="color:#19177c">title</span>))
-</span></span><span style="display:flex;"><span> (<span style="color:#19177c">seq-contains-p</span> (<span style="color:#19177c">alist-get</span> <span style="color:#008000">:tags</span> <span style="color:#19177c">elem</span>) <span style="color:#ba2121">"mt"</span>)))
-</span></span><span style="display:flex;"><span> (<span style="color:#19177c">is-offline</span> (<span style="color:#008000">or</span> (<span style="color:#19177c">string-match-p</span> <span style="color:#ba2121">"offline"</span> (<span style="color:#00f">downcase</span> <span style="color:#19177c">title</span>))
-</span></span><span style="display:flex;"><span> (<span style="color:#19177c">seq-contains-p</span> (<span style="color:#19177c">alist-get</span> <span style="color:#008000">:tags</span> <span style="color:#19177c">elem</span>) <span style="color:#ba2121">"offline"</span>)))
-</span></span><span style="display:flex;"><span> (<span style="color:#19177c">title-without-stuff</span> (<span style="color:#19177c">string-trim</span>
-</span></span><span style="display:flex;"><span> (<span style="color:#19177c">replace-regexp-in-string</span>
-</span></span><span style="display:flex;"><span> (<span style="color:#008000">rx</span> (<span style="color:#008000">or</span>
-</span></span><span style="display:flex;"><span> (<span style="color:#19177c">group</span> (<span style="color:#00f">+</span> (<span style="color:#008000">or</span> <span style="color:#19177c">digit</span> <span style="color:#ba2121">"."</span>)))
-</span></span><span style="display:flex;"><span> <span style="color:#ba2121">"(offline)"</span>
-</span></span><span style="display:flex;"><span> (<span style="color:#19177c">seq</span> <span style="color:#ba2121">"["</span> (<span style="color:#00f">+</span> <span style="color:#19177c">alnum</span>) <span style="color:#ba2121">"]"</span>) ))
-</span></span><span style="display:flex;"><span> <span style="color:#ba2121">""</span> <span style="color:#19177c">title</span>))))
+</span></span><span style="display:flex;"><span> (<span style="color:#19177c">is-meeting</span> (<span style="color:#008000">or</span> (<span style="color:#19177c">string-match-p</span> <span style="color:#ba2121">"meeting"</span> (<span style="color:#00f">downcase</span> <span style="color:#19177c">title</span>))
+</span></span><span style="display:flex;"><span> (<span style="color:#19177c">seq-contains-p</span> (<span style="color:#19177c">alist-get</span> <span style="color:#008000">:tags</span> <span style="color:#19177c">elem</span>) <span style="color:#ba2121">"mt"</span>)))
+</span></span><span style="display:flex;"><span> (<span style="color:#19177c">is-offline</span> (<span style="color:#008000">or</span> (<span style="color:#19177c">string-match-p</span> <span style="color:#ba2121">"offline"</span> (<span style="color:#00f">downcase</span> <span style="color:#19177c">title</span>))
+</span></span><span style="display:flex;"><span> (<span style="color:#19177c">seq-contains-p</span> (<span style="color:#19177c">alist-get</span> <span style="color:#008000">:tags</span> <span style="color:#19177c">elem</span>) <span style="color:#ba2121">"offline"</span>)))
+</span></span><span style="display:flex;"><span> (<span style="color:#19177c">title-without-stuff</span> (<span style="color:#19177c">string-trim</span>
+</span></span><span style="display:flex;"><span> (<span style="color:#19177c">replace-regexp-in-string</span>
+</span></span><span style="display:flex;"><span> (<span style="color:#008000">rx</span> (<span style="color:#008000">or</span>
+</span></span><span style="display:flex;"><span> (<span style="color:#19177c">group</span> (<span style="color:#00f">+</span> (<span style="color:#008000">or</span> <span style="color:#19177c">digit</span> <span style="color:#ba2121">"."</span>)))
+</span></span><span style="display:flex;"><span> <span style="color:#ba2121">"(offline)"</span>
+</span></span><span style="display:flex;"><span> (<span style="color:#19177c">seq</span> <span style="color:#ba2121">"["</span> (<span style="color:#00f">+</span> <span style="color:#19177c">alnum</span>) <span style="color:#ba2121">"]"</span>) ))
+</span></span><span style="display:flex;"><span> <span style="color:#ba2121">""</span> <span style="color:#19177c">title</span>))))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">when</span> <span style="color:#19177c">is-meeting</span>
</span></span><span style="display:flex;"><span> <span style="color:#666">`</span>(<span style="color:#ba2121">"Meeting"</span>
-</span></span><span style="display:flex;"><span> <span style="color:#666">,@</span>(<span style="color:#008000">when</span> (<span style="color:#19177c">alist-get</span> <span style="color:#008000">:events-online</span> <span style="color:#19177c">extra-params</span>)
-</span></span><span style="display:flex;"><span> (<span style="color:#008000">if</span> <span style="color:#19177c">is-offline</span> <span style="color:#666">'</span>(<span style="color:#ba2121">"Offline"</span>) <span style="color:#666">'</span>(<span style="color:#ba2121">"Online"</span>)))
-</span></span><span style="display:flex;"><span> <span style="color:#666">,</span><span style="color:#19177c">title-without-stuff</span>))))
+</span></span><span style="display:flex;"><span> <span style="color:#666">,@</span>(<span style="color:#008000">when</span> (<span style="color:#19177c">alist-get</span> <span style="color:#008000">:events-online</span> <span style="color:#19177c">extra-params</span>)
+</span></span><span style="display:flex;"><span> (<span style="color:#008000">if</span> <span style="color:#19177c">is-offline</span> <span style="color:#666">'</span>(<span style="color:#ba2121">"Offline"</span>) <span style="color:#666">'</span>(<span style="color:#ba2121">"Online"</span>)))
+</span></span><span style="display:flex;"><span> <span style="color:#666">,</span><span style="color:#19177c">title-without-stuff</span>))))
</span></span></code></pre></div><p>For the following result:</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>* Results
</span></span><span style="display:flex;"><span>** Meetings
@@ -394,8 +396,8 @@ Customize the formatting of these records through <code>org-clock-agg-elem
<p>Global variables must always include a location (section “Select Coordinates or City”). To enter a location, you can either enter latitude and longitude (Open Meteo has an <a href="https://open-meteo.com/en/docs/geocoding-api">API for those</a> as well) or select a location from <code>biome-query-coords</code>. Example configuration:</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">setq</span> <span style="color:#19177c">biome-query-coords</span>
</span></span><span style="display:flex;"><span> <span style="color:#666">'</span>((<span style="color:#ba2121">"Helsinki, Finland"</span> <span style="color:#666">60.16952</span> <span style="color:#666">24.93545</span>)
-</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">"Berlin, Germany"</span> <span style="color:#666">52.52437</span> <span style="color:#666">13.41053</span>)
-</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">"Dubai, UAE"</span> <span style="color:#666">25.0657</span> <span style="color:#666">55.17128</span>)))
+</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">"Berlin, Germany"</span> <span style="color:#666">52.52437</span> <span style="color:#666">13.41053</span>)
+</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">"Dubai, UAE"</span> <span style="color:#666">25.0657</span> <span style="color:#666">55.17128</span>)))
</span></span></code></pre></div><p>A timezone (“Settings” > “Timezone”) may not be required, but be sure to set it because <strong>the default one is UTC+0</strong>.</p>
<p>The current group is switched with <code><tab></code>. Each group’s section has a set of variables that can be toggled on and off, such as temperature, precipitation, etc. Check out the <a href="https://open-meteo.com/en/docs">API docs</a> if you’re interested in the meaning of more esoteric ones.</p>
<p>Press <code>RET</code> after you’ve configured the query to call the API. If something goes wrong, it will output an error, such as:</p>
@@ -421,8 +423,8 @@ Customize the formatting of these records through <code>org-clock-agg-elem
<p>Alternatively, use the <code>add-to-list</code> form (generated below the <code>biome-def-preset</code> form). Presets added that way will show up in <code>M-x biome-presets</code> or “Presets” in <code>M-x biome</code>.</p>
<p>Table formatting can be configured with <code>biome-grid-format</code>; check the docstring for more information. For instance, if you want to disable all gradients:</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">setq</span> <span style="color:#19177c">biome-grid-format</span> (<span style="color:#19177c">seq-filter</span> (<span style="color:#008000">lambda</span> (<span style="color:#19177c">f</span>) (<span style="color:#19177c">not</span> (<span style="color:#00f">eq</span> (<span style="color:#00f">car-safe</span> (<span style="color:#00f">nth</span> <span style="color:#666">2</span> <span style="color:#19177c">f</span>))
-</span></span><span style="display:flex;"><span> <span style="color:#19177c">'gradient</span>)))
-</span></span><span style="display:flex;"><span> <span style="color:#19177c">biome-grid-format</span>))
+</span></span><span style="display:flex;"><span> <span style="color:#19177c">'gradient</span>)))
+</span></span><span style="display:flex;"><span> <span style="color:#19177c">biome-grid-format</span>))
</span></span></code></pre></div><p>Turn off highlighting of the current hour or day as follows:</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">setq</span> <span style="color:#19177c">biome-grid-highlight-current</span> <span style="color:#800">nil</span>)
</span></span></code></pre></div><h2 id="composite-queries">Composite queries</h2>
@@ -926,55 +928,55 @@ assigned to group with the least amount of members.</li>
<p>Here is an excerpt from my configuration that was used to produce this screenshot:</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">setq</span> <span style="color:#19177c">elfeed-summary-settings</span>
</span></span><span style="display:flex;"><span> <span style="color:#666">'</span>((<span style="color:#19177c">group</span> (<span style="color:#008000">:title</span> <span style="color:#666">.</span> <span style="color:#ba2121">"GitHub"</span>)
-</span></span><span style="display:flex;"><span> (<span style="color:#008000">:elements</span>
-</span></span><span style="display:flex;"><span> (<span style="color:#19177c">query</span> <span style="color:#666">.</span> (<span style="color:#19177c">url</span> <span style="color:#666">.</span> <span style="color:#ba2121">"SqrtMinusOne.private.atom"</span>))
-</span></span><span style="display:flex;"><span> (<span style="color:#19177c">group</span> <span style="color:#666">.</span> ((<span style="color:#008000">:title</span> <span style="color:#666">.</span> <span style="color:#ba2121">"Guix packages"</span>)
-</span></span><span style="display:flex;"><span> (<span style="color:#008000">:elements</span>
-</span></span><span style="display:flex;"><span> (<span style="color:#19177c">query</span> <span style="color:#666">.</span> (<span style="color:#008000">and</span> <span style="color:#19177c">github</span> <span style="color:#19177c">guix_packages</span>)))
-</span></span><span style="display:flex;"><span> (<span style="color:#008000">:hide</span> <span style="color:#800">t</span>)))))
-</span></span><span style="display:flex;"><span> (<span style="color:#19177c">group</span> (<span style="color:#008000">:title</span> <span style="color:#666">.</span> <span style="color:#ba2121">"Blogs [Software]"</span>)
-</span></span><span style="display:flex;"><span> (<span style="color:#008000">:elements</span>
-</span></span><span style="display:flex;"><span> (<span style="color:#19177c">query</span> <span style="color:#666">.</span> <span style="color:#19177c">software_blogs</span>)))
-</span></span><span style="display:flex;"><span> (<span style="color:#19177c">group</span> (<span style="color:#008000">:title</span> <span style="color:#666">.</span> <span style="color:#ba2121">"Blogs [People]"</span>)
-</span></span><span style="display:flex;"><span> (<span style="color:#008000">:elements</span>
-</span></span><span style="display:flex;"><span> (<span style="color:#19177c">query</span> <span style="color:#666">.</span> (<span style="color:#008000">and</span> <span style="color:#19177c">blogs</span> <span style="color:#19177c">people</span> (<span style="color:#19177c">not</span> <span style="color:#19177c">emacs</span>)))
-</span></span><span style="display:flex;"><span> (<span style="color:#19177c">group</span> (<span style="color:#008000">:title</span> <span style="color:#666">.</span> <span style="color:#ba2121">"Emacs"</span>)
-</span></span><span style="display:flex;"><span> (<span style="color:#008000">:elements</span>
-</span></span><span style="display:flex;"><span> (<span style="color:#19177c">query</span> <span style="color:#666">.</span> (<span style="color:#008000">and</span> <span style="color:#19177c">blogs</span> <span style="color:#19177c">people</span> <span style="color:#19177c">emacs</span>))))))
-</span></span><span style="display:flex;"><span> (<span style="color:#19177c">group</span> (<span style="color:#008000">:title</span> <span style="color:#666">.</span> <span style="color:#ba2121">"Podcasts"</span>)
-</span></span><span style="display:flex;"><span> (<span style="color:#008000">:elements</span>
-</span></span><span style="display:flex;"><span> (<span style="color:#19177c">query</span> <span style="color:#666">.</span> <span style="color:#19177c">podcasts</span>)))
-</span></span><span style="display:flex;"><span> (<span style="color:#19177c">group</span> (<span style="color:#008000">:title</span> <span style="color:#666">.</span> <span style="color:#ba2121">"Videos"</span>)
-</span></span><span style="display:flex;"><span> (<span style="color:#008000">:elements</span>
-</span></span><span style="display:flex;"><span> (<span style="color:#19177c">group</span>
-</span></span><span style="display:flex;"><span> (<span style="color:#008000">:title</span> <span style="color:#666">.</span> <span style="color:#ba2121">"Music"</span>)
-</span></span><span style="display:flex;"><span> (<span style="color:#008000">:elements</span>
-</span></span><span style="display:flex;"><span> (<span style="color:#19177c">query</span> <span style="color:#666">.</span> (<span style="color:#008000">and</span> <span style="color:#19177c">videos</span> <span style="color:#19177c">music</span>))))
-</span></span><span style="display:flex;"><span> (<span style="color:#19177c">group</span>
-</span></span><span style="display:flex;"><span> (<span style="color:#008000">:title</span> <span style="color:#666">.</span> <span style="color:#ba2121">"Tech"</span>)
-</span></span><span style="display:flex;"><span> (<span style="color:#008000">:elements</span>
-</span></span><span style="display:flex;"><span> (<span style="color:#19177c">query</span> <span style="color:#666">.</span> (<span style="color:#008000">and</span> <span style="color:#19177c">videos</span> <span style="color:#19177c">tech</span>))))
-</span></span><span style="display:flex;"><span> (<span style="color:#19177c">group</span>
-</span></span><span style="display:flex;"><span> (<span style="color:#008000">:title</span> <span style="color:#666">.</span> <span style="color:#ba2121">"History"</span>)
-</span></span><span style="display:flex;"><span> (<span style="color:#008000">:elements</span>
-</span></span><span style="display:flex;"><span> (<span style="color:#19177c">query</span> <span style="color:#666">.</span> (<span style="color:#008000">and</span> <span style="color:#19177c">videos</span> <span style="color:#19177c">history</span>))))
-</span></span><span style="display:flex;"><span> <span style="color:#408080;font-style:italic">;; ...</span>
-</span></span><span style="display:flex;"><span> ))
-</span></span><span style="display:flex;"><span> <span style="color:#408080;font-style:italic">;; ...</span>
-</span></span><span style="display:flex;"><span> (<span style="color:#19177c">group</span> (<span style="color:#008000">:title</span> <span style="color:#666">.</span> <span style="color:#ba2121">"Miscellaneous"</span>)
-</span></span><span style="display:flex;"><span> (<span style="color:#008000">:elements</span>
-</span></span><span style="display:flex;"><span> (<span style="color:#19177c">group</span>
-</span></span><span style="display:flex;"><span> (<span style="color:#008000">:title</span> <span style="color:#666">.</span> <span style="color:#ba2121">"Searches"</span>)
-</span></span><span style="display:flex;"><span> (<span style="color:#008000">:elements</span>
-</span></span><span style="display:flex;"><span> (<span style="color:#19177c">search</span>
-</span></span><span style="display:flex;"><span> (<span style="color:#008000">:filter</span> <span style="color:#666">.</span> <span style="color:#ba2121">"@6-months-ago sqrtminusone"</span>)
-</span></span><span style="display:flex;"><span> (<span style="color:#008000">:title</span> <span style="color:#666">.</span> <span style="color:#ba2121">"About me"</span>))
-</span></span><span style="display:flex;"><span> (<span style="color:#19177c">search</span>
-</span></span><span style="display:flex;"><span> (<span style="color:#008000">:filter</span> <span style="color:#666">.</span> <span style="color:#ba2121">"+later"</span>)
-</span></span><span style="display:flex;"><span> (<span style="color:#008000">:title</span> <span style="color:#666">.</span> <span style="color:#ba2121">"Check later"</span>))))
-</span></span><span style="display:flex;"><span> (<span style="color:#19177c">group</span>
-</span></span><span style="display:flex;"><span> (<span style="color:#008000">:title</span> <span style="color:#666">.</span> <span style="color:#ba2121">"Ungrouped"</span>)
-</span></span><span style="display:flex;"><span> (<span style="color:#008000">:elements</span> <span style="color:#008000">:misc</span>))))))
+</span></span><span style="display:flex;"><span> (<span style="color:#008000">:elements</span>
+</span></span><span style="display:flex;"><span> (<span style="color:#19177c">query</span> <span style="color:#666">.</span> (<span style="color:#19177c">url</span> <span style="color:#666">.</span> <span style="color:#ba2121">"SqrtMinusOne.private.atom"</span>))
+</span></span><span style="display:flex;"><span> (<span style="color:#19177c">group</span> <span style="color:#666">.</span> ((<span style="color:#008000">:title</span> <span style="color:#666">.</span> <span style="color:#ba2121">"Guix packages"</span>)
+</span></span><span style="display:flex;"><span> (<span style="color:#008000">:elements</span>
+</span></span><span style="display:flex;"><span> (<span style="color:#19177c">query</span> <span style="color:#666">.</span> (<span style="color:#008000">and</span> <span style="color:#19177c">github</span> <span style="color:#19177c">guix_packages</span>)))
+</span></span><span style="display:flex;"><span> (<span style="color:#008000">:hide</span> <span style="color:#800">t</span>)))))
+</span></span><span style="display:flex;"><span> (<span style="color:#19177c">group</span> (<span style="color:#008000">:title</span> <span style="color:#666">.</span> <span style="color:#ba2121">"Blogs [Software]"</span>)
+</span></span><span style="display:flex;"><span> (<span style="color:#008000">:elements</span>
+</span></span><span style="display:flex;"><span> (<span style="color:#19177c">query</span> <span style="color:#666">.</span> <span style="color:#19177c">software_blogs</span>)))
+</span></span><span style="display:flex;"><span> (<span style="color:#19177c">group</span> (<span style="color:#008000">:title</span> <span style="color:#666">.</span> <span style="color:#ba2121">"Blogs [People]"</span>)
+</span></span><span style="display:flex;"><span> (<span style="color:#008000">:elements</span>
+</span></span><span style="display:flex;"><span> (<span style="color:#19177c">query</span> <span style="color:#666">.</span> (<span style="color:#008000">and</span> <span style="color:#19177c">blogs</span> <span style="color:#19177c">people</span> (<span style="color:#19177c">not</span> <span style="color:#19177c">emacs</span>)))
+</span></span><span style="display:flex;"><span> (<span style="color:#19177c">group</span> (<span style="color:#008000">:title</span> <span style="color:#666">.</span> <span style="color:#ba2121">"Emacs"</span>)
+</span></span><span style="display:flex;"><span> (<span style="color:#008000">:elements</span>
+</span></span><span style="display:flex;"><span> (<span style="color:#19177c">query</span> <span style="color:#666">.</span> (<span style="color:#008000">and</span> <span style="color:#19177c">blogs</span> <span style="color:#19177c">people</span> <span style="color:#19177c">emacs</span>))))))
+</span></span><span style="display:flex;"><span> (<span style="color:#19177c">group</span> (<span style="color:#008000">:title</span> <span style="color:#666">.</span> <span style="color:#ba2121">"Podcasts"</span>)
+</span></span><span style="display:flex;"><span> (<span style="color:#008000">:elements</span>
+</span></span><span style="display:flex;"><span> (<span style="color:#19177c">query</span> <span style="color:#666">.</span> <span style="color:#19177c">podcasts</span>)))
+</span></span><span style="display:flex;"><span> (<span style="color:#19177c">group</span> (<span style="color:#008000">:title</span> <span style="color:#666">.</span> <span style="color:#ba2121">"Videos"</span>)
+</span></span><span style="display:flex;"><span> (<span style="color:#008000">:elements</span>
+</span></span><span style="display:flex;"><span> (<span style="color:#19177c">group</span>
+</span></span><span style="display:flex;"><span> (<span style="color:#008000">:title</span> <span style="color:#666">.</span> <span style="color:#ba2121">"Music"</span>)
+</span></span><span style="display:flex;"><span> (<span style="color:#008000">:elements</span>
+</span></span><span style="display:flex;"><span> (<span style="color:#19177c">query</span> <span style="color:#666">.</span> (<span style="color:#008000">and</span> <span style="color:#19177c">videos</span> <span style="color:#19177c">music</span>))))
+</span></span><span style="display:flex;"><span> (<span style="color:#19177c">group</span>
+</span></span><span style="display:flex;"><span> (<span style="color:#008000">:title</span> <span style="color:#666">.</span> <span style="color:#ba2121">"Tech"</span>)
+</span></span><span style="display:flex;"><span> (<span style="color:#008000">:elements</span>
+</span></span><span style="display:flex;"><span> (<span style="color:#19177c">query</span> <span style="color:#666">.</span> (<span style="color:#008000">and</span> <span style="color:#19177c">videos</span> <span style="color:#19177c">tech</span>))))
+</span></span><span style="display:flex;"><span> (<span style="color:#19177c">group</span>
+</span></span><span style="display:flex;"><span> (<span style="color:#008000">:title</span> <span style="color:#666">.</span> <span style="color:#ba2121">"History"</span>)
+</span></span><span style="display:flex;"><span> (<span style="color:#008000">:elements</span>
+</span></span><span style="display:flex;"><span> (<span style="color:#19177c">query</span> <span style="color:#666">.</span> (<span style="color:#008000">and</span> <span style="color:#19177c">videos</span> <span style="color:#19177c">history</span>))))
+</span></span><span style="display:flex;"><span> <span style="color:#408080;font-style:italic">;; ...</span>
+</span></span><span style="display:flex;"><span> ))
+</span></span><span style="display:flex;"><span> <span style="color:#408080;font-style:italic">;; ...</span>
+</span></span><span style="display:flex;"><span> (<span style="color:#19177c">group</span> (<span style="color:#008000">:title</span> <span style="color:#666">.</span> <span style="color:#ba2121">"Miscellaneous"</span>)
+</span></span><span style="display:flex;"><span> (<span style="color:#008000">:elements</span>
+</span></span><span style="display:flex;"><span> (<span style="color:#19177c">group</span>
+</span></span><span style="display:flex;"><span> (<span style="color:#008000">:title</span> <span style="color:#666">.</span> <span style="color:#ba2121">"Searches"</span>)
+</span></span><span style="display:flex;"><span> (<span style="color:#008000">:elements</span>
+</span></span><span style="display:flex;"><span> (<span style="color:#19177c">search</span>
+</span></span><span style="display:flex;"><span> (<span style="color:#008000">:filter</span> <span style="color:#666">.</span> <span style="color:#ba2121">"@6-months-ago sqrtminusone"</span>)
+</span></span><span style="display:flex;"><span> (<span style="color:#008000">:title</span> <span style="color:#666">.</span> <span style="color:#ba2121">"About me"</span>))
+</span></span><span style="display:flex;"><span> (<span style="color:#19177c">search</span>
+</span></span><span style="display:flex;"><span> (<span style="color:#008000">:filter</span> <span style="color:#666">.</span> <span style="color:#ba2121">"+later"</span>)
+</span></span><span style="display:flex;"><span> (<span style="color:#008000">:title</span> <span style="color:#666">.</span> <span style="color:#ba2121">"Check later"</span>))))
+</span></span><span style="display:flex;"><span> (<span style="color:#19177c">group</span>
+</span></span><span style="display:flex;"><span> (<span style="color:#008000">:title</span> <span style="color:#666">.</span> <span style="color:#ba2121">"Ungrouped"</span>)
+</span></span><span style="display:flex;"><span> (<span style="color:#008000">:elements</span> <span style="color:#008000">:misc</span>))))))
</span></span></code></pre></div><h3 id="automatic-generation-of-groups">Automatic generation of groups</h3>
<h4 id="auto-tags"><code>auto-tags</code></h4>
<p>As described in the <a href="#tree-configuration-1">tree configuration</a> section, there are two ways to avoid defining all the relevant groups manually, <code>auto-tags</code> and <code>tag-groups</code>. Both use tags that are defined in <code>elfeed-feeds</code>.</p>
@@ -1210,10 +1212,10 @@ assigned to group with the least amount of members.</li>
</ul>
<p>The default value is as follows:</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span><span style="color:#666">'</span>((<span style="color:#19177c">autotype</span> <span style="color:#666">.</span> (<span style="color:#19177c">wait</span>
-</span></span><span style="display:flex;"><span> (<span style="color:#19177c">field</span> <span style="color:#666">.</span> <span style="color:#ba2121">"username"</span>)
-</span></span><span style="display:flex;"><span> (<span style="color:#19177c">key</span> <span style="color:#666">.</span> <span style="color:#ba2121">"Tab"</span>)
-</span></span><span style="display:flex;"><span> (<span style="color:#19177c">field</span> <span style="color:#666">.</span> <span style="color:#19177c">secret</span>)
-</span></span><span style="display:flex;"><span> (<span style="color:#19177c">key</span> <span style="color:#666">.</span> <span style="color:#ba2121">"Return"</span>)))
+</span></span><span style="display:flex;"><span> (<span style="color:#19177c">field</span> <span style="color:#666">.</span> <span style="color:#ba2121">"username"</span>)
+</span></span><span style="display:flex;"><span> (<span style="color:#19177c">key</span> <span style="color:#666">.</span> <span style="color:#ba2121">"Tab"</span>)
+</span></span><span style="display:flex;"><span> (<span style="color:#19177c">field</span> <span style="color:#666">.</span> <span style="color:#19177c">secret</span>)
+</span></span><span style="display:flex;"><span> (<span style="color:#19177c">key</span> <span style="color:#666">.</span> <span style="color:#ba2121">"Return"</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">password</span> <span style="color:#666">.</span> (<span style="color:#19177c">wait</span> (<span style="color:#19177c">field</span> <span style="color:#666">.</span> <span style="color:#19177c">secret</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">username</span> <span style="color:#666">.</span> (<span style="color:#19177c">wait</span> (<span style="color:#19177c">field</span> <span style="color:#666">.</span> <span style="color:#ba2121">"username"</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">url</span> <span style="color:#666">.</span> (<span style="color:#19177c">wait</span> (<span style="color:#19177c">field</span> <span style="color:#666">.</span> <span style="color:#ba2121">"url"</span>))))
@@ -1371,7 +1373,7 @@ timestamps by their date.</li>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">org-journal-tags-prop-apply-delta</span> <span style="color:#008000">:add</span> (<span style="color:#00f">list</span> <span style="color:#19177c">my/loc-tag</span>))))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#19177c">add-hook</span> <span style="color:#19177c">'org-journal-after-entry-create-hook</span>
-</span></span><span style="display:flex;"><span> <span style="color:#00f">#'</span><span style="color:#19177c">my/set-journal-header</span>)
+</span></span><span style="display:flex;"><span> <span style="color:#00f">#'</span><span style="color:#19177c">my/set-journal-header</span>)
</span></span></code></pre></div><h3 id="encryption">Encryption</h3>
<p>There are two ways how org-journal can be encrypted:</p>
<ul>
@@ -1656,7 +1658,7 @@ interval = 1
<p>The package can be used with <a href="https://orgmode.org/manual/Clocking-commands.html">org-clock</a> in the following way. Set up these two hooks:</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#19177c">add-hook</span> <span style="color:#19177c">'pomm-on-status-changed-hook</span> <span style="color:#00f">#'</span><span style="color:#19177c">pomm--sync-org-clock</span>)
</span></span><span style="display:flex;"><span>(<span style="color:#19177c">add-hook</span> <span style="color:#19177c">'pomm-third-time-on-status-changed-hook</span>
-</span></span><span style="display:flex;"><span> <span style="color:#00f">#'</span><span style="color:#19177c">pomm-third-time--sync-org-clock</span>
+</span></span><span style="display:flex;"><span> <span style="color:#00f">#'</span><span style="color:#19177c">pomm-third-time--sync-org-clock</span>
</span></span></code></pre></div><p>Then, start the timer (either <code>pomm</code> or <code>pomm-third-time</code>) and <code>org-clock-in</code>, in whichever order. The package will call <code>org-clock-out</code> when a break starts and <code>org-clock-in-last</code> when it ends.</p>
<p>Setting <code>pomm-org-clock-in-immediately</code> to <code>nil</code> “defers” calling <code>org-clock-in-last</code> until after any command from the user (via <code>post-command-hook</code>). I’ve added this because I occasionally return to my PC a few minutes after the break ends, so I don’t want these minutes to show up in <code>org-clock</code>.</p>
<p>Also see <a href="https://github.com/SqrtMinusOne/pomm.el/issues/13#issuecomment-2216868331">this comment</a> (<a href="https://github.com/SqrtMinusOne/pomm.el/issues/13">#13</a>) for an alternative approach.</p>
diff --git a/packages/org-clock-agg/index.html b/packages/org-clock-agg/index.html
index fcdfdc3..78a76e3 100644
--- a/packages/org-clock-agg/index.html
+++ b/packages/org-clock-agg/index.html
@@ -104,11 +104,11 @@
By default, the package selects org-clock records from (org-agenda-files). Additional options can be included by customizing the org-clock-agg-files-preset variable. For instance:
(setq org-clock-agg-files-preset
`(("Org Agenda + Archive"
- .
- ,(append (org-agenda-files)
- (cl-remove-if
- (lambda (f) (string-match-p (rx "." eos) f))
- (directory-files (concat org-directory "/archive/") t))))))
+ .
+ ,(append (org-agenda-files)
+ (cl-remove-if
+ (lambda (f) (string-match-p (rx "." eos) f))
+ (directory-files (concat org-directory "/archive/") t))))))
Note that after updating any of these variables, you’ll need to reopen the *org-clock-agg* buffer to view the changes.
Alternatively, you can directly specify the list of files within the buffer by selecting “Custom list” in the “Files” control.
Date Range
@@ -285,22 +285,22 @@ Customize the formatting of these records through org-clock-agg-elem-forma
:readable-name "Event"
:default-sort total
(let* ((title (org-element-property :raw-value (alist-get :headline elem)))
- (is-meeting (or (string-match-p "meeting" (downcase title))
- (seq-contains-p (alist-get :tags elem) "mt")))
- (is-offline (or (string-match-p "offline" (downcase title))
- (seq-contains-p (alist-get :tags elem) "offline")))
- (title-without-stuff (string-trim
- (replace-regexp-in-string
- (rx (or
- (group (+ (or digit ".")))
- "(offline)"
- (seq "[" (+ alnum) "]") ))
- "" title))))
+ (is-meeting (or (string-match-p "meeting" (downcase title))
+ (seq-contains-p (alist-get :tags elem) "mt")))
+ (is-offline (or (string-match-p "offline" (downcase title))
+ (seq-contains-p (alist-get :tags elem) "offline")))
+ (title-without-stuff (string-trim
+ (replace-regexp-in-string
+ (rx (or
+ (group (+ (or digit ".")))
+ "(offline)"
+ (seq "[" (+ alnum) "]") ))
+ "" title))))
(when is-meeting
`("Meeting"
- ,@(when (alist-get :events-online extra-params)
- (if is-offline '("Offline") '("Online")))
- ,title-without-stuff))))
+ ,@(when (alist-get :events-online extra-params)
+ (if is-offline '("Offline") '("Online")))
+ ,title-without-stuff))))
For the following result:
* Results
** Meetings
diff --git a/packages/org-journal-tags/index.html b/packages/org-journal-tags/index.html
index 8b4f79a..d950a2f 100644
--- a/packages/org-journal-tags/index.html
+++ b/packages/org-journal-tags/index.html
@@ -210,7 +210,7 @@ timestamps by their date.
(org-journal-tags-prop-apply-delta :add (list my/loc-tag))))
(add-hook 'org-journal-after-entry-create-hook
- #'my/set-journal-header)
+ #'my/set-journal-header)
Encryption
There are two ways how org-journal can be encrypted:
diff --git a/packages/password-store-completion/index.html b/packages/password-store-completion/index.html
index 53f8cc2..713c610 100644
--- a/packages/password-store-completion/index.html
+++ b/packages/password-store-completion/index.html
@@ -126,10 +126,10 @@
The default value is as follows:
'((autotype . (wait
- (field . "username")
- (key . "Tab")
- (field . secret)
- (key . "Return")))
+ (field . "username")
+ (key . "Tab")
+ (field . secret)
+ (key . "Return")))
(password . (wait (field . secret)))
(username . (wait (field . "username")))
(url . (wait (field . "url"))))
diff --git a/packages/pomm/index.html b/packages/pomm/index.html
index 7b82cad..218879e 100644
--- a/packages/pomm/index.html
+++ b/packages/pomm/index.html
@@ -181,7 +181,7 @@ interval = 1
The package can be used with org-clock in the following way. Set up these two hooks:
(add-hook 'pomm-on-status-changed-hook #'pomm--sync-org-clock)
(add-hook 'pomm-third-time-on-status-changed-hook
- #'pomm-third-time--sync-org-clock
+ #'pomm-third-time--sync-org-clock
Then, start the timer (either pomm or pomm-third-time) and org-clock-in, in whichever order. The package will call org-clock-out when a break starts and org-clock-in-last when it ends.
Setting pomm-org-clock-in-immediately to nil “defers” calling org-clock-in-last until after any command from the user (via post-command-hook). I’ve added this because I occasionally return to my PC a few minutes after the break ends, so I don’t want these minutes to show up in org-clock.
Also see this comment (#13) for an alternative approach.
diff --git a/posts/2023-04-13-emacs/index.html b/posts/2023-04-13-emacs/index.html
index f4fd16f..979dd14 100644
--- a/posts/2023-04-13-emacs/index.html
+++ b/posts/2023-04-13-emacs/index.html
@@ -84,8 +84,7 @@
}
-Poof I made my free-time disappear
-
+Poof I made my free-time disappear
- Ellis Kenyő, on being called an "elisp mage"
Little did I know on the fateful day of , when I had installed GNU Emacs. I wasn’t thinking about the ethical aspects of free software, the aesthetics of Lisp, or these other things with which an occasional layperson might explain how an almost half a century old program can still be in active use.
In fact, when considering using software X for anything, the most important question to me was: can X provide a better user experience? For Emacs, the answer to most of these questions turned out to be yes.
diff --git a/posts/index.xml b/posts/index.xml
index 29e0268..f4c4a2c 100644
--- a/posts/index.xml
+++ b/posts/index.xml
@@ -838,8 +838,7 @@
}
</style>
<blockquote>
-<p>Poof I made my free-time disappear</p>
-</blockquote>
+<p>Poof I made my free-time disappear</p></blockquote>
<p class="quote-title">- <a href="https://elken.dev">Ellis Kenyő</a>, on being called an "elisp mage"
<p>Little did I know on the fateful day of <strong><span class="timestamp-wrapper"><span class="timestamp">[2020-10-09 Fri]</span></span></strong>, when I had installed <a href="https://www.gnu.org/software/emacs/">GNU Emacs</a>. I wasn’t thinking about the <a href="https://www.gnu.org/philosophy/philosophy.html">ethical aspects</a> of free software, the <a href="https://www.webofstories.com/play/marvin.minsky/44">aesthetics of Lisp</a>, or these other things with which an occasional layperson might explain how an almost <a href="https://www.jwz.org/doc/emacs-timeline.html">half a century old</a> program can still be in <a href="https://emacsconf.org/2022/talks/survey/">active use</a>.</p>
<p>In fact, when considering using software X for anything, the most important question to me was: can X provide a better user experience? For Emacs, the answer to most of these questions turned out to be yes.</p>
diff --git a/stats/all.png b/stats/all.png
index a46f62b..70bf7c3 100644
Binary files a/stats/all.png and b/stats/all.png differ
diff --git a/stats/emacs-vim.png b/stats/emacs-vim.png
index 94d15e9..42ea94f 100644
Binary files a/stats/emacs-vim.png and b/stats/emacs-vim.png differ
diff --git a/stats/literate-config.png b/stats/literate-config.png
index a1cd669..5413498 100644
Binary files a/stats/literate-config.png and b/stats/literate-config.png differ
diff --git a/tags/emacs/index.xml b/tags/emacs/index.xml
index 0f21130..5cf09c0 100644
--- a/tags/emacs/index.xml
+++ b/tags/emacs/index.xml
@@ -20,7 +20,7 @@
https://sqrtminusone.xyz/posts/2023-04-13-emacs/
Thu, 13 Apr 2023 00:00:00 +0000
https://sqrtminusone.xyz/posts/2023-04-13-emacs/
- <style>
.quote-title {
margin-left: 24px;
}
</style>
<blockquote>
<p>Poof I made my free-time disappear</p>
</blockquote>
<p class="quote-title">- <a href="https://elken.dev">Ellis Kenyő</a>, on being called an "elisp mage"
<p>Little did I know on the fateful day of <strong><span class="timestamp-wrapper"><span class="timestamp">[2020-10-09 Fri]</span></span></strong>, when I had installed <a href="https://www.gnu.org/software/emacs/">GNU Emacs</a>. I wasn’t thinking about the <a href="https://www.gnu.org/philosophy/philosophy.html">ethical aspects</a> of free software, the <a href="https://www.webofstories.com/play/marvin.minsky/44">aesthetics of Lisp</a>, or these other things with which an occasional layperson might explain how an almost <a href="https://www.jwz.org/doc/emacs-timeline.html">half a century old</a> program can still be in <a href="https://emacsconf.org/2022/talks/survey/">active use</a>.</p>
<p>In fact, when considering using software X for anything, the most important question to me was: can X provide a better user experience? For Emacs, the answer to most of these questions turned out to be yes.</p>
+ <style>
.quote-title {
margin-left: 24px;
}
</style>
<blockquote>
<p>Poof I made my free-time disappear</p></blockquote>
<p class="quote-title">- <a href="https://elken.dev">Ellis Kenyő</a>, on being called an "elisp mage"
<p>Little did I know on the fateful day of <strong><span class="timestamp-wrapper"><span class="timestamp">[2020-10-09 Fri]</span></span></strong>, when I had installed <a href="https://www.gnu.org/software/emacs/">GNU Emacs</a>. I wasn’t thinking about the <a href="https://www.gnu.org/philosophy/philosophy.html">ethical aspects</a> of free software, the <a href="https://www.webofstories.com/play/marvin.minsky/44">aesthetics of Lisp</a>, or these other things with which an occasional layperson might explain how an almost <a href="https://www.jwz.org/doc/emacs-timeline.html">half a century old</a> program can still be in <a href="https://emacsconf.org/2022/talks/survey/">active use</a>.</p>
-
Running Gource with Emacs