A literate programming file for helper apps in Emacs.
#+BEGIN_SRC emacs-lisp :exports none
;;; ha-aux-apps.el --- A literate programming file for helper apps in Emacs. -*- lexical-binding: t; -*-
;;
;; Copyright (C) 2021 Howard X. Abrams
;;
;; Author: Howard X. Abrams <http://gitlab.com/howardabrams>
;; Maintainer: Howard X. Abrams
;; Created: November 18, 2021
;;
;; This file is not part of GNU Emacs.
;;
;; *NB:* Do not edit this file. Instead, edit the original literate file at:
;; ~/other/hamacs/ha-aux-apps.org
;; And tangle the file to recreate this one.
;;
;;; Code:
#+END_SRC
* Introduction
The following applications are not really needed. I alternate between trying to /stay in Emacs/ taking advantage of the consistent interface, and simply using a stand-alone app on my Workday computer.
The following section configures my Terminal experience, both inside and outside Emacs.
** Eshell
I used to use [[http://www.howardism.org/Technical/Emacs/eshell.html][Eshell all the time]], but now I've migrated most of /work/ directly into Emacs (rewriting all those shell scripts a Emacs Lisp code). However, a shell is pretty good for my brain at organizing files (old habits, maybe).
#+BEGIN_SRC emacs-lisp
(use-package eshell
:config (ha-leader "a e" '("eshell" . eshell-here)))
#+END_SRC
I usually want a new window running Eshell, that is smaller than the current buffer:
#+BEGIN_SRC emacs-lisp
(defun eshell-here ()
"Opens up a new shell in the directory associated with the
current buffer's file. Rename the eshell buffer name to match
that directory to make multiple eshell windows easier."
(interactive)
(let* ((parent (if (buffer-file-name)
(file-name-directory (buffer-file-name))
default-directory))
(height (/ (window-total-height) 3))
(name (car (last (split-string parent "/" t)))))
(split-window-vertically (- height))
(eshell "new")
(rename-buffer (concat "*eshell: " name "*"))
(insert (concat "ls"))
(eshell-send-input)))
#+END_SRC
And since Emacs supplies Eshell, we can just define these helper functions:
#+BEGIN_SRC emacs-lisp
(defun eshell/e (file)
(find-file file))
(defun eshell/ee (file)
(find-file-other-window file))
(defun eshell/x ()
(insert "exit")
(eshell-send-input)
(delete-window))
#+END_SRC
Add my org-specific predicates, see this [[http://www.howardism.org/Technical/Emacs/eshell-fun.html][this essay]] for the details:
#+BEGIN_SRC emacs-lisp
(defun eshell-org-file-tags ()
"Helps the eshell parse the text the point is currently on,
looking for parameters surrounded in single quotes. Returns a
function that takes a FILE and returns nil if the file given to
it doesn't contain the org-mode #+FILETAGS: entry specified."
;; Step 1. Parse the eshell buffer for our tag between quotes
;; Make sure to move point to the end of the match:
(if (looking-at "'\\([^)']+\\)'")
(let* ((tag (match-string 1))
(reg (rx bol "#+FILETAGS: "
(zero-or-more any)
word-start
(literal tag)
word-end
(zero-or-more any)
eol)))
(goto-char (match-end 0))
;; Step 2. Return the predicate function:
;; Careful when accessing the `reg' variable.
`(lambda (file)
(with-temp-buffer
(insert-file-contents file)
(re-search-forward ,reg nil t 1))))
(error "The `T' predicate takes an org-mode tag value in single quotes.")))
I'm not giving up on Eshell, but I am playing around with [[https://github.com/akermu/emacs-libvterm][vterm]], and it is pretty good, but I use it primarily as a more reliable approach to [[file:ha-remoting.org][a remote shell]].
VTerm has an issue (at least for me) with ~M-Backspace~ not deleting the previous word, and yeah, I want to make sure that both keystrokes do the same thing.
#+BEGIN_SRC emacs-lisp :tangle no
(use-package vterm
:init
(setq vterm-shell "/usr/local/bin/fish")
;; Granted, I seldom pop out to the shell except during code demonstrations,
;; but I like how C-p/C-n jumps up to each prompt entry using this setting
The advantage of running terminals in Emacs is the ability to copy text without a mouse. For that, hit ~C-c C-t~ to enter a special copy-mode. If I go into this mode, I might as well also go into normal mode to move the cursor.
*Note:* To exit the copy-mode (and copy the selected text to the clipboard), hit ~Return~.
Hrm. Seems that I might want a function to copy the output of the last command to a register, or even an org-capture...
Perhaps I should change the reference to this for more local development:
#+begin_example
:straight (:local-repo "~/other/demo-it")
#+end_example
** RPG DM
Been working on a project for getting Emacs helping as a /Dungeon Master's Assistant/, and I must say, it is coming along nicely. In case you are reading this, let me know, and I'll start to share it.