diff options
| author | Kévin Le Gouguec <kevin.legouguec@gmail.com> | 2025-01-14 22:48:35 +0100 |
|---|---|---|
| committer | Kévin Le Gouguec <kevin.legouguec@gmail.com> | 2025-01-14 23:26:44 +0100 |
| commit | cf8a3f15ee1c80b874be10cbdd34496b84560f59 (patch) | |
| tree | c7a77d6938c6d8d539a6ae1e72160732d440ccf5 /guides/applications | |
| parent | faf50994d58d2651a2ab1bb1ed94dce1feb246bd (diff) | |
| download | memory-leaks-cf8a3f15ee1c80b874be10cbdd34496b84560f59.tar.xz | |
Sort guides up a bit
Diffstat (limited to 'guides/applications')
| -rw-r--r-- | guides/applications/emacs/AUCTeX.org | 24 | ||||
| -rw-r--r-- | guides/applications/emacs/development.org | 121 | ||||
| -rw-r--r-- | guides/applications/emacs/elisp-demos.org | 28 | ||||
| -rw-r--r-- | guides/applications/emacs/use-package.org | 48 | ||||
| -rw-r--r-- | guides/applications/emacs/windows.org | 25 | ||||
| -rw-r--r-- | guides/applications/ffmpeg.org | 22 | ||||
| -rw-r--r-- | guides/applications/git.org | 40 | ||||
| -rw-r--r-- | guides/applications/imagemagick.org | 81 |
8 files changed, 389 insertions, 0 deletions
diff --git a/guides/applications/emacs/AUCTeX.org b/guides/applications/emacs/AUCTeX.org new file mode 100644 index 0000000..0082759 --- /dev/null +++ b/guides/applications/emacs/AUCTeX.org @@ -0,0 +1,24 @@ +* Completion for cross-references +To integrate AUCTeX with reftex and get completion for ~\cite~ +(bibliography) and ~\ref~ (intra-document labels): +#+begin_src elisp +;; In init file: +(put 'TeX-auto-save 'safe-local-variable 'booleanp) +(put 'TeX-parse-self 'safe-local-variable 'booleanp) +(add-hook 'LaTeX-mode-hook 'turn-on-reftex) +(setq reftex-plug-into-AUCTeX t) +(setq reftex-label-illegal-re "[^-a-zA-Z0-9_+=:;,./]") ; Allow slashes. +(setq TeX-auto-local ".auctex") + +;; Top-level .dir-locals.el: +((latex-mode + . ((TeX-auto-save . t) + (TeX-parse-self . t))) + (bibtex-mode + . ((TeX-auto-save . t) + (TeX-parse-self . t)))) + +;; .dir-locals.el files in subfolders: +((latex-mode + . ((TeX-master . "../path/to/main.tex")))) +#+end_src diff --git a/guides/applications/emacs/development.org b/guides/applications/emacs/development.org new file mode 100644 index 0000000..f1363e1 --- /dev/null +++ b/guides/applications/emacs/development.org @@ -0,0 +1,121 @@ +* Build +** bootstrapping +Libraries that are part of the "bootstrap set" cannot rely on +autoloading. Example: =files.el= must ~(eval-when-compile (require +'pcase))~, even though it only uses autoloaded macros. +* Tests +** Running +Somehow I can never remember how to ask =make= how to run a specific +set of tests. + +tl;dr, running =$testcases_regexp= from =test/$testfile.el=, to test +changes in =lisp/$sourcefile.el=: +#+begin_src sh +make -C test $testfile \ + TEST_LOAD_EL=yes \ + TEST_BACKTRACE_LINE_LENGTH=nil \ + SELECTOR="\"$testcases_regexp\"" \ + EMACS_EXTRAOPT="-l ../lisp/$sourcefile.el" +#+end_src + +Relevant bits from test/Makefile: + +#+begin_src makefile +## filename.log: run tests from filename.el(c) if .log file needs updating +## filename: re-run tests from filename.el(c), with no logging +#+end_src + +#+begin_src makefile +# Whether to run tests from .el files in preference to .elc, we do +# this by default since it gives nicer stacktraces. +# If you just want a pass/fail, setting this to no is much faster. +export TEST_LOAD_EL ?= \ + $(if $(findstring $(MAKECMDGOALS), all check check-maybe),no,yes) +#+end_src + +#+begin_src makefile +TEST_RUN_ERT = --batch --eval '(ert-run-tests-batch-and-exit (quote ${SELECTOR_ACTUAL}))' ${WRITE_LOG} +#+end_src + +#+begin_src makefile +ifdef SELECTOR +SELECTOR_ACTUAL=$(SELECTOR) +#+end_src + +Selector documentation from ~ert-select-tests~: +#+begin_quote +Valid SELECTORs: + +nil -- Selects the empty set. +t -- Selects UNIVERSE. +:new -- Selects all tests that have not been run yet. +:failed, :passed -- Select tests according to their most recent result. +:expected, :unexpected -- Select tests according to their most recent result. +a string -- A regular expression selecting all tests with matching names. +a test -- (i.e., an object of the ert-test data-type) Selects that test. +a symbol -- Selects the test that the symbol names, signals an + ‘ert-test-unbound’ error if none. +(member TESTS...) -- Selects the elements of TESTS, a list of tests + or symbols naming tests. +(eql TEST) -- Selects TEST, a test or a symbol naming a test. +(and SELECTORS...) -- Selects the tests that match all SELECTORS. +(or SELECTORS...) -- Selects the tests that match any of the SELECTORS. +(not SELECTOR) -- Selects all tests that do not match SELECTOR. +(tag TAG) -- Selects all tests that have TAG on their tags list. + A tag is an arbitrary label you can apply when you define a test. +(satisfies PREDICATE) -- Selects all tests that satisfy PREDICATE. + PREDICATE is a function that takes an ert-test object as argument, + and returns non-nil if it is selected. +#+end_quote +** Writing +*** Mocking functions +#+begin_src elisp +(cl-letf (((symbol-function 'read-something) + (lambda (&rest _) "result"))) + (some-command)) +#+end_src + +* Third-party packages +** forge +*** build +Use =config.mk= to set =LOAD_PATH=: +#+begin_src makefile +find-lib = $(dir $(shell emacs -Q -batch \ + -eval "(require 'find-func)" \ + -eval "(package-initialize)" \ + -eval "(require '$(1))" \ + -eval "(princ (find-library-name \"$(1)\"))")) + +sources = ~/src/emacs/magit/lisp + +elpa = \ + closql \ + compat \ + dash \ + emacsql \ + ghub \ + markdown-mode \ + transient \ + treepy \ + with-editor \ + yaml +elpa_dirs = $(foreach d,$(elpa),$(call find-lib,$(d))) + +LOAD_PATH = $(addprefix -L ,$(elpa_dirs) $(sources)) +#+end_src + +*** load sources +~emacs -Q -L ./lisp~ does not seem to work: after running +~(package-initialize)~, =M-x find-library forge= returns the instance +installed under ~package-user-dir~. + +This can be circumvented with ~(setq pacakge-load-list '((forge nil) +all))~. + +Full command line for easy startup: + +#+begin_src sh +emacs -Q -L ./lisp \ + -eval "(setq pacakge-load-list '((forge nil) all))" \ + -f package-initialize \ +#+end_src diff --git a/guides/applications/emacs/elisp-demos.org b/guides/applications/emacs/elisp-demos.org new file mode 100644 index 0000000..029f5be --- /dev/null +++ b/guides/applications/emacs/elisp-demos.org @@ -0,0 +1,28 @@ +Some terse "context-free" Emacs Lisp snippets that hopefully speak for +themselves. + +* The prefix argument +#+begin_src elisp +(defun my/prefix-arg-demo (arg) + (interactive (list current-prefix-arg)) + (insert + (let ((num (prefix-numeric-value arg))) + (format "%s %d %s\n" + arg + num + (cond ((null arg) "N/A") + ((numberp arg) (format "M-%d or C-u %d" arg arg)) + ((equal arg '-) (format "M-- or C-u -")) + ((listp arg) + (if (< num 0) + (format "(M-- or C-u -) C-u × %d" (log (- num) 4)) + (format "C-u × %d" (log num 4))))))))) +#+end_src +#+begin_example +nil 1 N/A +2 2 M-2 or C-u 2 +- -1 M-- or C-u - +(-16) -16 (M-- or C-u -) C-u × 2 +(64) 64 C-u × 3 +#+end_example + diff --git a/guides/applications/emacs/use-package.org b/guides/applications/emacs/use-package.org new file mode 100644 index 0000000..f6cd027 --- /dev/null +++ b/guides/applications/emacs/use-package.org @@ -0,0 +1,48 @@ +* Porting from ~custom-file~ +Some very dumb code to generate ~use-package~ declarations from Custom +settings. Entry point is ~c->us/port~. +#+begin_src elisp +(require 'help-fns) +(require 'radix-tree) + +(defun c->us/get-custom-options () + (seq-map + (pcase-lambda (`(theme-value ,option user ,value)) + (list option value)) + (get 'user 'theme-settings))) + +(defun c->us/get-option-file (option) + ;; Load packages first, otherwise symbol-file can return "loaddefs". + (pcase-dolist + (`(_ . ,files) + (radix-tree-prefixes (help-definition-prefixes) + (symbol-name option))) + (dolist (f files) + (load f 'noerror 'nomessage))) + (when-let ((file (symbol-file option))) + (file-name-base file))) + +(defun c->us/write-declaration (lib pairs) + (insert (format "(use-package %s\n" lib)) + (insert " :custom") + (message "%s -> %s" lib pairs) + (pcase-dolist + (`(,option ,value) pairs) + (insert (format "\n (%s %s)" + option + (prin1-to-string value)))) + (insert ")\n\n")) + +(defun c->us/symbols< (symlist1 symlist2) + (string< (car symlist1) (car symlist2))) + +(defun c->us/port () + (seq-map + (pcase-lambda (`(,lib . ,pairs)) + (c->us/write-declaration lib pairs)) + (sort (seq-group-by + (pcase-lambda (`(,option _)) + (c->us/get-option-file option)) + (sort (c->us/get-custom-options) 'c->us/symbols<)) + 'c->us/symbols<))) +#+end_src diff --git a/guides/applications/emacs/windows.org b/guides/applications/emacs/windows.org new file mode 100644 index 0000000..06cad7e --- /dev/null +++ b/guides/applications/emacs/windows.org @@ -0,0 +1,25 @@ +=nt/INSTALL.w64= provides detailed instructions for compiling Emacs on +recent Windows versions. Here are some additional steps I had to +figure out on my own: +* Mingw-w64 +- Set =$HOME= to =%HOMEPATH%= by changing =db_home= to =windows= in + =c:/msys64/etc/fstab=. +- In addition to =c:\msys64\mingw64\bin=, adding =c:\msys64\usr\bin= + to the system =PATH= allows Emacs to access applications installed + with =pacman=. + - It's not obvious whether the Mingw-w64 =PATH= entries should go + last (in which case Emacs will pick the wrong ~find~ command) or + first (in which case… /everything else/ will pick the wrong ~find~ + command?). At least Emacs has a variable to configure + (~find-program~). +* Compiling +Make sure to specify ~-c core.autocrlf=false~ *when cloning* the Emacs +repository; ~autogen.sh~ gets confused otherwise. +* Configuring +AFAICT one must set the variable ~shell-file-name~ explicitly to +=c:/msys64/usr/bin/bash.exe=, otherwise Emacs's Windows-specific +initialization logic uses a built-in shell ersatz (=nt/cmdproxy.c=). +** TODO =HOME= +Went with the instructions from [[info:emacs#MS-Windows Registry]]; could +maybe use [[info:emacs#Windows HOME]] by setting =HOME= to =%HOMEPATH%=, +to avoid having to spell out my username? diff --git a/guides/applications/ffmpeg.org b/guides/applications/ffmpeg.org new file mode 100644 index 0000000..eded0e9 --- /dev/null +++ b/guides/applications/ffmpeg.org @@ -0,0 +1,22 @@ +ffmpeg recipes I should stuff into config files or scripts, but +haven't yet. +* Extracting parts of videos +~-c copy -map 0~ ensures all streams (audio & subtitles) are kept. +The timestamp syntax is described in the "Time duration" section of +=ffmpeg-utils(1)=; =MM:SS= works fine. + +#+begin_src sh +ffmpeg -i $input -c copy -map 0 \ + -ss $tstart -to $tend \ + $output +#+end_src + +* Reduce file size +** with =-vf=: ~-vf "scale=iw/2:ih/2"~ +** with H.265 +openSUSE Tumbleweed's ffmpeg is not built with H.265 support AFAICT. + +1. Install =libx265-devel= +2. Clone =https://git.ffmpeg.org/ffmpeg.git= +3. ~./configure --enable-libx265 --enable-gpl~ +4. ~ffmpeg -i $input -vcodec libx265 -crf 28~ diff --git a/guides/applications/git.org b/guides/applications/git.org new file mode 100644 index 0000000..bf42130 --- /dev/null +++ b/guides/applications/git.org @@ -0,0 +1,40 @@ +* ~send-email~ with ~.authinfo.gpg~ +** Step 1: Install ~git-credential-netrc~ +AFAICT not all distributions package this script? As far as those I +use are concerned: + +- On Debian, the =git= package brings + =/usr/share/doc/git/contrib/credential/netrc/git-credential-netrc.perl=, + but the file is not executable, so it's not as simple as symlinking + it from =~/.local/bin=: it must be =cp='ed and =chmod='ed. + +- openSUSE does not include anything from =contrib=, I think? So just + grab =contrib/credential/netrc/git-credential-netrc.perl= from the [[https://git.kernel.org/pub/scm/git/git.git/][Git + repository]], stick it in =~/.local/bin= and =chmod= it. + +Now ~git help --all | grep credential-~ should show =credential-netrc=. + +** Step 2: Configure ~git send-email~ +In =~/.gitconfig=, assuming a GMail account for =luser@gmail.com=: + +#+begin_src conf +[sendemail] + smtpencryption = tls + smtpserver = smtp.gmail.com + smtpuser = luser + smtpserverport = 587 +#+end_src + +Most =send-email= guides seem to use the full email address for +=smtpuser=; I'm putting in just the /local-part/, since that's what is in +my =~/.authinfo.gpg=. + +** Step 3: Configure ~git-credential~ +In =~/.gitconfig=: + +#+begin_src conf +[credential] + helper = netrc +#+end_src + +** Step 4: Enjoy 📨 diff --git a/guides/applications/imagemagick.org b/guides/applications/imagemagick.org new file mode 100644 index 0000000..9d56cbf --- /dev/null +++ b/guides/applications/imagemagick.org @@ -0,0 +1,81 @@ +ImageMagick recipes I should stuff into config files or scripts, but +haven't yet. +* Configuration +** Allow conversion from/to PDF +- Open ImageMagick's =policy.xml= configuration file. +- Locate the =<policy>= tag with a =pattern= including "PDF". +- Comment it out. +* Comparing images +~magick compare~ is a thing; ~magick convert~ can also do [[https://stackoverflow.com/a/33673440][neat stuff]]: +#+begin_src sh +convert '(' a.png -flatten -grayscale Rec709Luminance ')' \ + '(' b.png -flatten -grayscale Rec709Luminance ')' \ + '(' -clone 0-1 -compose darken -composite ')' \ + -channel RGB -combine diff.png +#+end_src + +* Adding watermarks +Someday, in the Glorious Future, every thirdparty that insists on +having a copy of my personal documents will be legally obligated to +request it from a trusted government service that steganographizes the +requester's identity in the files they send. + +Until then… +#+begin_src sh +#!/bin/bash + +set -eu + +src=$1 +dst=$2 +label=$3 + +mark () +{ + local marksrc=$1 + local markdst=$2 + + w=$(identify -format '%w\n' "$marksrc" | head -1) + h=$(identify -format '%h\n' "$marksrc" | head -1) + textw=$((w/3)) + texth=$((h/8)) + + pointsize=$((80*w/2500)) + offx=$((100*w/2500)) + offy=$((400*h/3500)) + + convert -size ${textw}x${texth} xc:none \ + -fill '#80808080' -pointsize $pointsize \ + -annotate 340x340+${offx}+${offy} "$label" \ + miff:- | \ + composite -tile - "$marksrc" "$markdst" +} + +if [[ "$src" =~ \.pdf ]] +then + # AFAICT if I feed a multi-page PDF to composite, it outputs only + # the first page. Jump through hoops to split and concatenate the + # PDF; also, roundtrip through JPG because setting -density (to + # preserve a good quality) messes with the size calculations for + # the label. + + tmpd=$(mktemp -d) + bname=$(basename "$src") + qpdf --split-pages "$src" "${tmpd}/$bname" + + shopt -s extglob + + for page in ${tmpd}/${bname/%.pdf/-+([0-9]).pdf} + do + convert -density 300 -flatten "$page" "${page/.pdf/.jpg}" + mark "${page/.pdf/.jpg}" "${page/.pdf/-MARKED.jpg}" + convert -density 300 "${page/.pdf/-MARKED.jpg}" "${page/.pdf/-MARKED.pdf}" + done + + qpdf --empty --pages ${tmpd}/${bname/%.pdf/-+([0-9])-MARKED.pdf} -- "$dst" + + exit +fi + +mark "$src" "$dst" +#+end_src |
