config.phundrak.com/docs/emacs/custom-elisp.org

5.6 KiB
Raw Blame History

Emacs — Custom Elisp

Custom Elisp

Dired functions

phundrak/open-marked-files

This function allows the user to open all marked files from a dired buffer in new Emacs buffers.

(defun phundrak/open-marked-files (&optional files)
  "Open all marked FILES in Dired buffer as new Emacs buffers."
  (interactive)
  (let* ((file-list (if files
                        (list files)
                      (if (equal major-mode "dired-mode")
                          (dired-get-marked-files)
                        (list (buffer-file-name))))))
   (mapc (lambda (file-path)
           (find-file file-path))
         (file-list))))

Extend add-to-list

One function I find missing regarding add-to-list is add-all-to-list which enables the user to add multiple elements to a list at once. Instead, with vanilla Emacs, I have to repeatedly call add-to-list. Thats not very clean. Lets declare this missing function:

(defun add-all-to-list (list-var elements &optional append compare-fn)
  "Add ELEMENTS to the value of LIST-VAR if it isnt there yet.

ELEMENTS is a list of values. For documentation on the variables
APPEND and COMPARE-FN, see `add-to-list'."
  (let (return)
    (dolist (elt elements return)
      (setq return (add-to-list list-var elt append compare-fn)))))

Generate and insert random passwords

These functions got replaced by my custom package, see Password generator.

Handle new windows

The two functions below allow the user to not only create a new window to the right or below the current window (respectively), but also to focus the new window immediately.

(defun split-window-right-and-focus ()
  "Spawn a new window right of the current one and focus it."
  (interactive)
  (split-window-right)
  (windmove-right))

(defun split-window-below-and-focus ()
  "Spawn a new window below the current one and focus it."
  (interactive)
  (split-window-below)
  (windmove-down))

(defun kill-buffer-and-delete-window ()
  "Kill the current buffer and delete its window."
  (interactive)
  (progn
    (kill-this-buffer)
    (delete-window)))

Resize windows

(with-eval-after-load 'hydra
  (defhydra windows-adjust-size ()
    "
             _t_: shrink
_c_: enlarge              _r_: right
             _s_: enlarge
"
    ("c" enlarge-window-horizontally)
    ("t" shrink-window)
    ("s" enlarge-window)
    ("r" shrink-window-horizontally)))

Screenshots

Since Emacs27, it is possible for Emacs to take screenshots of itself in various formats. Im mainly interested in the SVG and PNG format, so Ill only write functions for these. It isnt really redundant with the screenshot.el package used here since these functions take a screenshot of Emacs as a whole rather than of a code snippet.

First, we have a general function which is a slight modification of the function shared by Alphapapa in this Reddit comment. I modified it to make it possible to pass as an argument the format the screenshot will be taken as or ask the user which format they would like to save it as.

(defun self-screenshot (&optional type)
  "Save a screenshot of type TYPE of the current Emacs frame.
As shown by the function `', type can wield the value `svg',
`png', `pdf'.

This function will output in /tmp a file beginning with \"Emacs\"
and ending with the extension of the requested TYPE."
  (interactive (list
                (intern (completing-read "Screenshot type: "
                                         '(png svg pdf postscript)))))
  (let* ((extension (pcase type
                      ('png        ".png")
                      ('svg        ".svg")
                      ('pdf        ".pdf")
                      ('postscript ".ps")
                      (otherwise (error "Cannot export screenshot of type %s" otherwise))))
         (filename (make-temp-file "Emacs-" nil extension))
         (data     (x-export-frames nil type)))
    (with-temp-file filename
      (insert data))
    (kill-new filename)
    (message filename)))

I used this function to take the screenshots you can see in this document.

Switch between buffers

Two default shortcuts I really like from Spacemacs are SPC b m and SPC b s, which bring the user directly to the *Messages* buffer and the *scratch* buffer respectively. These functions do exactly this.

(defun switch-to-messages-buffer ()
  "Switch to Messages buffer."
  (interactive)
  (switch-to-buffer (messages-buffer)))

(defun switch-to-scratch-buffer ()
  "Switch to Messages buffer."
  (interactive)
  (switch-to-buffer "*scratch*"))

Tangle all Emacs config files

(defvar my/emacs-org-config-directory
  (expand-file-name "org/config/docs/emacs" (getenv "HOME"))
  "Location of my config as org files.")

(defun my/tangle-emacs-config ()
  "Tangle all my Emacs config files from org files."
  (interactive)
  (let ((files (f-files my/emacs-org-config-directory
                (lambda (file) (f-ext-p file "org"))
                t))
        (org-confirm-babel-evaluate nil))
    (dolist (file files)
      (message "Tangling %s" file)
      (org-babel-tangle-file file))))