#+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

** 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~.
That’s not very clean. Let’s 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 isn’t 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
These functions got replaced by my custom package, see [[file:packages/misc.md#password-generator][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.
#+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))
#+end_src

** Resize windows
#+begin_src emacs-lisp
(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)))
#+end_src

** Screenshots
Since Emacs27, it is possible for Emacs to take screenshots of itself
in various formats. I’m mainly interested in the SVG and PNG format,
so I’ll only write functions for these. It isn’t 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.

** 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

** Tangle all Emacs config files
#+begin_src emacs-lisp :results none
(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))))
#+end_src
