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

167 lines
5.9 KiB
Org Mode
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#+title: Emacs — Custom Elisp
#+setupfile: ../headers
#+property: header-args:emacs-lisp :mkdirp yes :lexical t :exports code
#+property: header-args:emacs-lisp+ :tangle ~/.config/emacs/lisp/custom-elisp.el
#+property: header-args:emacs-lisp+ :mkdirp yes :noweb no-export
* 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.
#+begin_src emacs-lisp
(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))))
#+end_src
** 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.
#+begin_src emacs-lisp
(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*"))
#+end_src
** 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 [[file:./packages/applications.md#screenshot][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 [[https://www.reddit.com/r/emacs/comments/idz35e/emacs_27_can_take_svg_screenshots_of_itself/g2c2c6y/][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.
#+begin_src emacs-lisp
(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)))
#+end_src
I used this function to take the screenshots you can see in this
document.
** 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.
#+begin_src emacs-lisp
(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)))
#+end_src
** Resize windows
#+begin_src emacs-lisp
(with-eval-after-load 'hydra
(defhydra windows-adjust-size ()
"
_s_: enlarge
_c_: enlarge _r_: right
_t_: shrink
"
("c" enlarge-window-horizontally)
("t" shrink-window)
("s" enlarge-window)
("r" shrink-window-horizontally)))
#+end_src
** 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:
#+begin_src emacs-lisp
(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)))))
#+end_src
** Generate and insert random passwords
#+begin_src emacs-lisp
(defun my/generate-password (nb-chars)
"Generate an alphanumeric password of NB-CHARS."
(shell-command-to-string
(concat "tr -dc 'A-Za-z0-9!@#$%^&*' < /dev/urandom | head -c "
(number-to-string nb-chars))))
#+end_src
#+begin_src emacs-lisp
(defun my/copy-generated-password (&optional prefix)
(interactive "P")
(kill-new
(my/generate-password (if prefix
(string-to-number
(completing-read "Amount of characters: " nil))
32))))
#+end_src
#+begin_src emacs-lisp
(defun my/insert-generated-password (&optional prefix)
(interactive "P")
(insert
(my/generate-password (if prefix
(string-to-number
(completing-read "Amount of characters: "
nil))
32))))
#+end_src