A collection of my tiny but useful Emacs Lisp code.
I use modern libraries (
ts) heavily, feel free to port them
to Emacs built-ins.
# Kill All buffers
crux-kill-other-buffers for some time. But crux didn’t kill
dired buffers. So I made my own. This will kill ALL buffer including
dired, but special buffers.
(defun aza-kill-other-buffers () "Kill all buffers but current buffer and special buffers. (Buffer that start with '*' and white space ignored)" (interactive) (when (y-or-n-p "Really kill all other buffers ? ") (let ((killed-bufs 0)) (dolist (buffer (delq (current-buffer) (buffer-list))) (let ((name (buffer-name buffer))) (when (and name (not (string-equal name "")) (/= (aref name 0) ?\s) (string-match "^[^\*]" name)) (cl-incf killed-bufs) (funcall 'kill-buffer buffer)))) (message "Killed %d buffer(s)" killed-bufs))))
If you afraid of losing unsaved buffers. You can add the function below and call
(let ((killed-bufs 0)).
(defun save-all-buffers-silently () (save-some-buffers t))
crux-kill-other-buffers: (dired buffer didn’t get killed)
# Insert Today’s Date
I work with huge org files that involve many plain timestamp. It’s easy to get previous/next days using prefix arguments e.g +2 or -4. But it’s painful if you need to get previous/next timestamp based on certain date.
This function will insert today’s date if invoked without arguments and no active region. Prefix arguments specifies how many days to move, arguments can be negative, negative means previous day. If region selected, make fake today’s date according to the date under region.
You need to load ts.el for this
to work. I decide to use ts.el rather than
more readable, beautiful and less code. To duplicate line/region
faster, I use crux-duplicate-current-line-or-region
(require 'ts) (defun aza-today (&optional arg) "Insert today's date. A prefix ARG specifies how many days to move; negative means previous day. If region selected, parse region as today's date pivot." (interactive "P") (let ((date (if (use-region-p) (ts-parse (buffer-substring-no-properties (region-beginning) (region-end))) (ts-now))) (arg (or arg 0))) (if (use-region-p) (delete-region (region-beginning) (region-end))) (insert (ts-format "%A, %B %e, %Y" (ts-adjust 'day arg date)))))
The ‘beautiful’ way to do region is using
(interactive "r") but it
always complain ‘The mark is not set now, so there is no region’ if
you never invoke mark region before (e.g after Emacs start up).
# Insert Current Filename
Most of the time my org first heading name is the same as filename. So I made this function. My habit is to separate word in filename by dash. If you want more robust function, take the second.
(defun insert-filename-as-heading () "Take current filename (word separated by dash) as heading." (interactive) (insert (capitalize (replace-regexp-in-string "-" " " (file-name-sans-extension (buffer-name))))))
This is the more robust function. It can deal with almost separator in filename. You have to load s.el to make this function works. Many packages already use s.el, probably it’s installed in your Emacs.
(defun insert-filename-as-heading () "Take current filename (word separated by dash) as heading." (interactive) (insert (capitalize (s-join " " (s-split-words (file-name-sans-extension (buffer-name)))))))
# Open External Terminal And Tmux From Dired
If no external terminal opened, start one. Else attach to it and open new window in current path
sterm to your favourite terminal.
(defun term-here () (interactive) (start-process "" nil "stterm" "-e" "bash" "-c" "tmux -q has-session && exec tmux new-window || exec tmux new-session -n$USER -s$USER@$HOSTNAME"))
If you prefer to attach to current window (don’t open new window) and change directory path your self. Use:
stterm -e bash -c "tmux -q has-session && exec tmux attach-session -d || exec tmux new-session -n$USER -s$USER@$HOSTNAME"
# Remove Secrets From Region
Most of the time I have to attach the program output / log to bug report. I don’t my all my secrets words there.
Of course you need to put
(list-my-secrets) in your non published files.
(defun list-my-secrets () "The list of my secrets" '(("johndoe" . "user") ("johndoemachine" . "machine") ("email@example.com" . "myemail"))) (defun rm-mysecrets () "Remove all confidential information." (interactive) (dolist (pair (list-my-secrets)) (save-excursion (replace-string (car pair) (cdr pair)))))
# Smart Delete Line
Rather than having separate key to delete line, or having to invoke
prefix-argument. You can use crux-smart-kill-line
which will “kill to the end of the line and kill whole line on the next
call”. But if you prefer
delete instead of
kill, you can use the
For point-to-string operation (kill/delete) I recommend to use zop-to-char
(defun aza-delete-line () "Delete from current position to end of line without pushing to `kill-ring'." (interactive) (delete-region (point) (line-end-position))) (defun aza-delete-whole-line () "Delete whole line without pushing to kill-ring." (interactive) (delete-region (line-beginning-position) (line-end-position))) (defun crux-smart-delete-line () "Kill to the end of the line and kill whole line on the next call." (interactive) (let ((orig-point (point))) (move-end-of-line 1) (if (= orig-point (point)) (aza-delete-whole-line) (goto-char orig-point) (aza-delete-line))))
# Change Selected Region To Snake Case
Most of the time I use this as part of emacs macro to snake-case all attribute response from an API.
(defun to-snake-case (start end) "Change selected text to snake case format" (interactive "r") (if (use-region-p) (let ((camel-case-str (buffer-substring start end))) (delete-region start end) (insert (s-snake-case camel-case-str))) (message "No region selected")))
# Remind Me After Certain Time
I use this function to remind me to switch off the water, check my cookings, other things while I work.
This function uses
mpv to play sound. You replace it with your favourite music player.
(defun play-reminder-sound () (start-process "" nil "mpv" coin-work-medium-sound)) (defun remind-me () "Notify with a sound after certain time" (interactive) (let ((time (read-string "Time (min|sec): " "10 min"))) (message "I will remind you after %s" time) (run-at-time time nil #'play-reminder-sound)))
# Change Screen Brightness
This function uses
light. You replace it with your favourite app.
(defun light-set-value () "Set light value directly inside Emacs" (interactive) (let* ((current-value (s-trim (shell-command-to-string "light -G"))) (light-value (read-string "Set Value: " current-value))) (start-process "" nil "light" "-S" light-value)))
# Get A Day Name From A Date Time
I use this function to know what day some events happen.
(defun what-day () "Show day name from spesific time" (interactive) (let ((date (read-string "Date: ")) (month (read-string "Month: ")) (year (read-string "Year: " (number-to-string (ts-year (ts-now)))))) (message (ts-day-name (ts-parse (s-join " " (list date month year)))))))
# Ask Github If I Have New Notification.
Often times I need fast reply of some issue in Github. Opening github everytime is costly (bandwith and time).
pass to store my credential, so I use
(defun ask-github () "GET Github notification API." (let* ((github-pass (password-store-get-field "code/github" "token")) (archive-response (request "https://api.github.com/notifications?all" :parser 'json-read :headers `(("Authorization" . ,(concat "token" " " github-pass)) ("Content-Type" . "application/json")) :sync t)) (data (request-response-data archive-response)) (status (request-response-status-code archive-response))) (if (eq status 200) data 404))) (defun github-show-notification () "Check if Github notification exist without opening browser Reduce Distraction." (interactive) (let ((result (ask-github))) (if (not (equal result 404)) (if (equal result ') (message "No notification.") (message "Yey, You have notification!")) (message "Request failed"))))
If you don’t use
pass, you can put your secret under encrypted
(require 'keys keys.el.gpg) ; <--- contains `(defvar github-pass 1234)` (defun ask-github () "GET Github notification API." (let* ((archive-response (request "https://api.github.com/notifications?all" :parser 'json-read :headers `(("Authorization" . ,(concat "token" " " github-pass)) ("Content-Type" . "application/json")) :sync t)) ....
# Select Remote Machines and Connect
I work with several remote machine. So selecting them based on name and open dired there is very useful.
Previously I use the same code structure to select and copy my password to
clipboard, but now I use
pass which has nice emacs mode.
(defvar remote-machines `(("machine-api" . ,(list :username "john" :ip "10.10.10.10")) ("machine-foo" . ,(list :username "doe" :ip "22.214.171.124")))) (defun connect-remote () "Open dired buffer in selected remote machine" (interactive) (let* ((remote-source `((name . "") (candidates . ,(mapcar 'car remote-machines)) (action . (lambda (candidate) candidate)))) (selected-machine (helm :sources '(remote-source))) (machine-data (cdr (assoc selected-machine remote-machines))) (username (plist-get machine-data :username)) (ip-address (plist-get machine-data :ip))) (if (string= username "root") (dired (concat "/ssh:" username "@" ip-address ":/")) (dired (concat "/ssh:" username "@" ip-address ":/home/" username "/"))) (message "Connected")))
This code only rely on selection narrowing tool (such
helm) on selecting a key. So
you can replace it with your favourite tool or extract the main part.
# Playing Multimedia/Music Files
Since I browse using dired all the time. It’s more convenient for me to invoke my external application within dired.
I always use
--force-window even for songs, so that I have separate
mpv window that accepts my mpv keybindings
(increase volume, next playlist, etc).
Open dired buffer, place your cursor on the top of media/playlist file, then invoke these interactive functions.
(defun start-mpv (path &optional playlist-p) "Start mpv with specified arguments" (let* ((default-cmd "mpv --force-window") (cmd (if playlist-p (s-append " --loop-playlist --playlist=" default-cmd) (s-append " --loop " default-cmd)))) (call-process-shell-command (s-concat cmd (shell-quote-argument path)) nil 0))) (defun mpv () "Play a file in current line" (interactive) (start-mpv (dired-get-filename))) (defun mpv-dir () "Play all multimedia files in current directory" (interactive) (start-mpv default-directory)) (defun mpv-playlist () "Play a playlist in current line" (interactive) (start-mpv (dired-get-filename) t))