From 6c0cded3719213d09a86c981b38cec538bdd4a60 Mon Sep 17 00:00:00 2001 From: Gerard Vermeulen Date: Wed, 8 May 2024 13:13:09 +0200 Subject: [PATCH] Simplify and clean up the Elisp programming section --- README.org | 300 ++++++----------------------------------------------- 1 file changed, 32 insertions(+), 268 deletions(-) diff --git a/README.org b/README.org index 8faf206..c1f4710 100644 --- a/README.org +++ b/README.org @@ -648,11 +648,6 @@ for technical information. #+caption: Window management variables. #+name: lst:3rd-window-management #+begin_src emacs-lisp -n :results none -;; (info "(emacs) Bug Reference") -(defvar bug-reference-url-format - "https://debbugs.gnu.org/cgi/bugreport.cgi?bug=%s" - "Setting this as a file local variable enables `bug-reference-mode'") - ;; (info "(elisp) Displaying Buffers") ;; (info "(emacs) Window Choice") ;; (describe-function 'display-buffer) @@ -5329,8 +5324,39 @@ Here is a list of links describing how to program and debug [[info:elisp#Top][Em Ref. [cite:@Monnier.ACM-PL.4.1] exposes the evolution of Emacs Lisp and explains important Emacs Lisp idioms. +*** [[info:emacs#Bug Reference][Bug Reference Mode (info)]] +:PROPERTIES: +:CUSTOM_ID: sec:bug-reference-mode +:END: + +Listing [[lst:bug-reference-mode]] configures ~bug-reference-mode~ for use with the +[[https://debbugs.gnu.org/][GNU Bug Tracker]]. + +#+caption[Setup ~bug-reference-mode~]: +#+caption: Setup ~bug-reference-mode~. +#+name: lst:bug-reference-mode +#+begin_src emacs-lisp -n :results silent +;; (info "(emacs) Bug Reference") +(defvar bug-reference-url-format + "https://debbugs.gnu.org/cgi/bugreport.cgi?bug=%s" + "Setting this as a file local variable enables `bug-reference-mode'") +#+end_src + +*** [[info:elisp#Debugging][Debugging Emacs Lisp (info)]] +:PROPERTIES: +:CUSTOM_ID: sec:debugging +:END: + +GAV: I fail to instrument the functions from the [[https://www.emacswiki.org/emacs/SourceLevelDebugger][source level debugger (edebug)]] +wiki entry as in [[info:elisp#Edebug][Edebug (info)]]. + +*** [[https://www.masteringemacs.org/article/evaluating-elisp-emacs][Evaluating Elisp in Emacs]] +:PROPERTIES: +:CUSTOM_ID: sec:elisp-evaluation +:END: + Listing [[lst:setup-ielm][setup ielm]] configures the [[https://wikemacs.org/wiki/IELM][Interactive Emacs Lisp Mode]] for better -interoperability with [[https://smartparens.readthedocs.io/en/latest/][Smartparens]]: get help on the key bindings by means of +interoperability with [[https://smartparens.readthedocs.io/en/latest/][smartparens]]: get help on the key bindings by means of src_emacs-lisp[:results silent]{(describe-function 'ielm)}. #+caption[Setup =ielm=]: @@ -5341,268 +5367,6 @@ src_emacs-lisp[:results silent]{(describe-function 'ielm)}. (setopt ielm-dynamic-return nil)) #+end_src -*** [[https://lists.gnu.org/archive/html/emacs-devel/2023-11/msg00764.html][Benchmarking Emacs Lisp]] :noexport: -:PROPERTIES: -:CUSTOM_ID: sec:benchmarking -:header-args:emacs-lisp: :exports code :tangle no -:END: - -The following snippets present and use a [[https://lists.gnu.org/archive/html/emacs-devel/2023-11/msg00764.html][copy]] of João Távora's code to benchmark -Emacs Lisp forms. - -#+caption[Define macro to benchmark groups of forms]: -#+caption: Define macro to benchmark groups of forms. -#+name: lst:benchmark-group -#+begin_src emacs-lisp -n :results silent -(defvar joaot/bench-group-name nil) -(defvar joaot/setup-form nil) -(defvar joaot/timings-alist nil) -(defvar joaot/repetitions nil) - -(defmacro joaot/with-benchmark-group (bench-name - setup-form - repetitions - &rest body) - (declare (indent 1)) - (let ((f `(alist-get ,bench-name joaot/timings-alist nil nil #'equal))) - `(let ((joaot/bench-group-name ,bench-name) - (joaot/setup-form ',setup-form) - (joaot/repetitions ,repetitions)) - (setf ,f (list)) - ,@body - (cl-loop with sorted = (setf ,f (cl-sort ,f #'< :key #'cadr)) - with fastest = (cadr (car sorted)) - for i from 0 - for res in sorted - for prev-time = time - for (_n time . more) = res - do (setcdr res - (cl-list* (if (eq time fastest) "FASTEST" - (format "%2.1fx %sSLOWER" - (/ time fastest) - (if (= i 1) "" - (format "(rel %2.1fx) " - (/ time prev-time))))) - time - more))) - joaot/timings-alist))) -#+end_src - -#+caption[Define macro to benchmark forms]: -#+caption: Define macro to benchmark forms. -#+name: lst:benchmark-form -#+begin_src emacs-lisp -n :results silent -(defmacro joaot/bench (form) - `(cl-progv - (mapcar #'car joaot/setup-form) - (mapcar #'eval (mapcar #'cdr joaot/setup-form)) - (let ((res - (benchmark-call (prog1 - (,(if (native-comp-available-p) - 'native-compile - 'byte-compile) - '(lambda () ,form)) - (garbage-collect)) - joaot/repetitions)) - (group-name joaot/bench-group-name) - (bench-name ',(car form))) - (push (cons bench-name res) - (alist-get group-name joaot/timings-alist nil nil #'equal))))) -#+end_src - -#+caption[Define benchmark helper functions]: -#+caption: Define benchmark helper functions. -#+name: lst:benchmark-helpers -#+begin_src emacs-lisp -n :results silent -(defun bench-cl-loop-list (l) - (cl-loop for e in l thereis (identity e))) - -(defun bench-cl-loop-vec (v) - (cl-loop for e across v thereis (identity e))) - -(defun bench-cl-some (seq) - (cl-some #'identity seq)) - -(defun bench-seq-some (seq) - (seq-some #'identity seq)) -#+end_src - -#+caption[Benchmark =some= operations on big lists]: -#+caption: Benchmark =some= operations on big lists. -#+name: lst:benchmark-some-big-lists -#+begin_src emacs-lisp -n :eval no-export :results pp silent -(joaot/with-benchmark-group "\"some\" operation, big lists" - ((list1 . (make-list 100000 nil))) - 100 - (joaot/bench (bench-cl-loop-list list1)) - (joaot/bench (cl-some #'identity list1)) - (joaot/bench (seq-some #'identity list1))) -#+end_src - -#+caption[Benchmark =some= operations on small lists]: -#+caption: Benchmark =some= operations on small lists. -#+name: lst:benchmark-some-small-lists -#+begin_src emacs-lisp -n :eval no-export :results pp silent -(joaot/with-benchmark-group "\"some\" operation, small lists" - ((list1 . (make-list 10 nil))) - 100000 - (joaot/bench (bench-cl-loop-list list1)) - (joaot/bench (cl-some #'identity list1)) - (joaot/bench (seq-some #'identity list1))) -#+end_src - -#+caption[Accumulated results of benchmark examples]: -#+caption: Accumulated results of benchmark examples. -#+name: lst:benchmark-example -#+header: :wrap "src emacs-lisp -n" -#+begin_src emacs-lisp -n :eval no-export :exports both :results pp -(joaot/with-benchmark-group "destructuring" - ((list1 . (make-list 3 0))) - 100000 - (joaot/bench (pcase-let ((`(,a ,b ,c) list1)) (+ a b c))) - (joaot/bench (cl-destructuring-bind (a b c) list1 (+ a b c))) - (joaot/bench (seq-let (a b c) list1 (+ a b c)))) -#+end_src - -#+caption[Accumulated results of benchmark examples]: -#+caption: Accumulated results of benchmark examples. -#+name: lst:benchmark-example-results -#+RESULTS: lst:benchmark-example -#+begin_src emacs-lisp -n -(("\"some\" operation, small lists" (cl-some "FASTEST" 0.027944 0 0.0) - (seq-some "2.6x SLOWER" 0.073602 0 0.0) - (bench-cl-loop-list "134.4x (rel 51.0x) SLOWER" 3.7544939999999998 - 12 2.701254000000006)) - ("\"some\" operation, big lists" (cl-some "FASTEST" 0.242062 0 0.0) - (seq-some "2.5x SLOWER" 0.614304 0 0.0) - (bench-cl-loop-list "14.5x (rel 5.7x) SLOWER" 3.505071 0 0.0)) - ("destructuring" - (cl-destructuring-bind "FASTEST" 0.013874999999999998 0 0.0) - (pcase-let "1.2x SLOWER" 0.016648 0 0.0) - (seq-let "2.8x (rel 2.4x) SLOWER" 0.039485 0 0.0))) -#+end_src - -*** [[info:elisp#Debugging][Debugging Emacs Lisp (info)]] -:PROPERTIES: -:CUSTOM_ID: sec:debugging -:header-args:emacs-lisp: :exports code :tangle no -:END: - -Listing [[lst:example-edebug][edebug example]] from the [[https://www.emacswiki.org/emacs/SourceLevelDebugger][source level debugger (edebug)]] wiki entry is a -minimal example of how to use =edebug=: -1. Type {{{kbd(C-c ')}}} to open its =org-src-mode= buffer. -2. Type {{{kbd(C-M-x)}}} with point in =foo=. -3. Type {{{kbd(C-M-x)}}} with point in =bar=. -4. Evaluate =(foo)=. -5. Type {{{kbd(C-u C-M-x)}}} with point in =bar=. -6. Evaluate =(foo)=. -7. Type the space bar to step through =bar=. -Note: I fail to instrument functions as in [[info:elisp#Edebug][Edebug (info)]]. - -#+caption[Example for =edebug=]: -#+caption: Example for =edebug=. -#+name: lst:example-edebug -#+begin_src emacs-lisp -n :exports code :results silent -(defun foo () - (interactive) - (bar)) - -(defun bar () - (let ((a 5) - (b 7)) - (message "%d" (+ a b)))) -#+end_src - -*** [[https://emacs.stackexchange.com/questions/2129/why-is-let-faster-with-lexical-scope][Disassemble dynamical and lexical scope]] :noexport: -:PROPERTIES: -:CUSTOM_ID: sec:disassemble-dynamical-lexical-scope -:header-args:emacs-lisp: :exports code :tangle no -:END: - -Listing [[lst:disassemble-lexical-scope][lexical scope disassembly]] and [[lst:disassemble-dynamical-scope][dynamical scope disassembly]] disassemble -identical code in case of respectively lexical and dynamical scope. Listing -[[lst:disassemble-lexical-scope-results][lexical scope disassembly results]] and [[lst:disassemble-dynamical-scope-results][dynamical scope disassembly results]] show -the respective results. - -The link [[https://emacs.stackexchange.com/questions/61754/how-can-i-enable-lexical-binding-for-elisp-code-in-org-mode][how to enable lexical scope for Emacs Lisp in org-mode source blocks]] -explains all possibilities of disabling or enabling lexical scope. - -#+caption[Disassemble lexical scope]: -#+caption: Disassemble lexical scope. -#+name: lst:disassemble-lexical-scope -#+header: :wrap "src text -n" -#+begin_src emacs-lisp -n :exports both :lexical t :results value -(with-temp-buffer - (disassemble (lambda (n) - "Demonstrate lexical scope." - (let* ((lower most-negative-fixnum) - (upper most-positive-fixnum) - (sum (+ lower upper))) - (expt sum n))) - (current-buffer)) - (buffer-substring-no-properties (point-min) (point-max))) -#+end_src - -#+caption[Disassemble lexical scope results]: -#+caption: Disassemble lexical scope results. -#+name: lst:disassemble-lexical-scope-results -#+RESULTS: lst:disassemble-lexical-scope -#+begin_src text -n -byte code: - doc: Demonstrate lexical scope. ... - args: (arg1) -0 varref most-negative-fixnum -1 varref most-positive-fixnum -2 stack-ref 1 -3 stack-ref 1 -4 plus -5 constant expt -6 stack-ref 1 -7 stack-ref 5 -8 call 2 -9 return -#+end_src - -#+caption[Disassemble dynamical scope]: -#+caption: Disassemble dynamical scope. -#+name: lst:disassemble-dynamical-scope -#+header: :wrap "src text -n" -#+begin_src emacs-lisp -n :exports both :results value -(with-temp-buffer - (disassemble (lambda (n) - "Demonstrate lexical scope." - (let* ((lower most-negative-fixnum) - (upper most-positive-fixnum) - (sum (+ lower upper))) - (expt sum n))) - (current-buffer)) - (buffer-substring-no-properties (point-min) (point-max))) -#+end_src - -#+caption[Disassemble dynamical scope results]: -#+caption: Disassemble dynamical scope results. -#+name: lst:disassemble-dynamical-scope-results -#+RESULTS: lst:disassemble-dynamical-scope -#+begin_src text -n -byte code: - doc: Demonstrate lexical scope. - args: (n) -0 varref most-negative-fixnum -1 varbind lower -2 varref most-positive-fixnum -3 varbind upper -4 varref lower -5 varref upper -6 plus -7 varbind sum -8 constant expt -9 varref sum -10 varref n -11 call 2 -12 unbind 3 -13 return -#+end_src - *** [[http://yummymelon.com/devnull/writing-better-elisp-docstrings.html][Writing Better Elisp Docstrings]] :PROPERTIES: :CUSTOM_ID: sec:describe-function-at-point