Compare commits
	
		
			4 commits
		
	
	
		
			4a2ed3b87b
			...
			d60de45141
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | d60de45141 | ||
|  | 029a714bd7 | ||
|  | 9101e07990 | ||
|  | 51864edd7c | 
					 5 changed files with 118 additions and 104 deletions
				
			
		
							
								
								
									
										128
									
								
								ha-demos.org
									
									
									
									
									
								
							
							
						
						
									
										128
									
								
								ha-demos.org
									
									
									
									
									
								
							|  | @ -2,7 +2,7 @@ | |||
| #+author: Howard X. Abrams | ||||
| #+date:   2024-10-18 | ||||
| #+filetags: emacs hamacs | ||||
| #+lastmod: [2024-10-30 Wed] | ||||
| #+lastmod: [2024-11-05 Tue] | ||||
| 
 | ||||
| A literate programming file for creating and running demonstrations | ||||
| 
 | ||||
|  | @ -58,6 +58,29 @@ But I feel I should replace it, and this project encapsulates the following goal | |||
| 
 | ||||
| * Presentations with Org | ||||
| A demonstration begins with an Org file where the screen shows a /single heading/ with a larger font. Not much more. I have two projects that I like to use. | ||||
| ** Hiding Blocks | ||||
| When showing a presentation, I never want the =#+business= to lines to completely disappear. First attempt turned the foreground color to the background color, but that still leaves a blank, but occupied line. Using the invisible overlays removes them completely: | ||||
| 
 | ||||
| #+BEGIN_SRC emacs-lisp | ||||
|   (defun ha-org-blocks-hide-headers () | ||||
|     "Make the headers and other block metadata invisible. | ||||
|   See `ha-org-blocks-show-headers' to return their appearance." | ||||
|     (let ((pattern (rx bol (zero-or-more space) | ||||
|                        (or ":" "#") | ||||
|                        (zero-or-more any) eol))) | ||||
|       (save-excursion | ||||
|         (goto-char (point-min)) | ||||
|         (while (re-search-forward pattern nil t) | ||||
|           (let* ((start (match-beginning 0)) (end (1+ (match-end 0))) | ||||
|                  (ovlay (make-overlay start end))) | ||||
|             (overlay-put ovlay 'invisible t)))))) | ||||
| 
 | ||||
|   (defun ha-org-blocks-show-headers () | ||||
|     "Un-invisibilize the headers and other block metadata invisible. | ||||
|   In other words, this undoes what `ha-org-blocks-hide-headers' did." | ||||
|     (delete-all-overlays)) | ||||
| #+END_SRC | ||||
| 
 | ||||
| ** Org Present | ||||
| Converted to use [[https://github.com/rlister/org-present][org-present]]. I love the /hooks/ as that makes it easier to handle. My problem with =org-present= is that it doesn’t always display images. | ||||
| 
 | ||||
|  | @ -67,24 +90,6 @@ Converted to use [[https://github.com/rlister/org-present][org-present]]. I love | |||
|     (defvar ha-org-present-mode-line mode-line-format | ||||
|       "Cache previous mode-line format state") | ||||
| 
 | ||||
|     (defun ha-org-blocks-hide-headers () | ||||
|       "Make the headers and other block metadata invisible. | ||||
|         See `ha-org-blocks-show-headers'." | ||||
|       (let ((pattern (rx bol (zero-or-more space) | ||||
|                          (or ":" "#") | ||||
|                          (zero-or-more any) eol))) | ||||
|         (save-excursion | ||||
|           (goto-char (point-min)) | ||||
|           (while (re-search-forward pattern nil t) | ||||
|             (let* ((start (1+ (match-beginning 0))) (end (1+ (match-end 0))) | ||||
|                    (ovlay (make-overlay start end))) | ||||
|               (overlay-put ovlay 'invisible t)))))) | ||||
| 
 | ||||
|     (defun ha-org-blocks-show-headers () | ||||
|       "Un-invisibilize the headers and other block metadata invisible. | ||||
|     In other words, this undoes what `ha-org-blocks-hide-headers' did." | ||||
|       (delete-all-overlays)) | ||||
| 
 | ||||
|     (defun ha-org-present-start () | ||||
|       "Hook to run when starting a presentation. | ||||
|     This happens _after_ `org-present' has started." | ||||
|  | @ -117,7 +122,7 @@ Converted to use [[https://github.com/rlister/org-present][org-present]]. I love | |||
|       (org-present-show-cursor)) | ||||
| 
 | ||||
|     :bind | ||||
|     (:map org-tree-slide-mode-map | ||||
|     (:map org-present-mode-keymap | ||||
|           ("<f5>" . org-present-next) | ||||
|           ("S-<f5>" . org-present-previous) | ||||
|           ("C-<f5>" . org-present-quit)) | ||||
|  | @ -136,7 +141,7 @@ Converted to use [[https://github.com/rlister/org-present][org-present]]. I love | |||
|              "p" #'org-present-prev | ||||
|              "r" #'org-present-read-only | ||||
|              "w" #'org-present-read-write | ||||
|              "q" #'org-present-quit) | ||||
|              "Q" #'org-present-quit) | ||||
| 
 | ||||
|     :hook | ||||
|     (org-present-mode . ha-org-present-start) | ||||
|  | @ -150,6 +155,7 @@ I’ve used [[https://github.com/takaxp/org-tree-slide][org-tree-slide]] for yea | |||
|     :config | ||||
|     (setq org-tree-slide-heading-emphasis nil | ||||
|           org-tree-slide-activate-message "† This demonstration is running in Emacs" | ||||
|           org-tree-slide-indicator '(:next nil :previous nil :content nil) | ||||
|           org-tree-slide-cursor-init nil) | ||||
|     (org-tree-slide-simple-profile) | ||||
| 
 | ||||
|  | @ -157,33 +163,32 @@ I’ve used [[https://github.com/takaxp/org-tree-slide][org-tree-slide]] for yea | |||
|       "Configure the presentation display. | ||||
|     See `ha-org-tree-slide-stop' that undoes this." | ||||
|       (setq org-hide-emphasis-markers t) | ||||
|       (set-face-attribute 'org-quote nil | ||||
|                           :inherit 'variable-pitch :slant 'italic) | ||||
|       (ha-org-blocks-hide-headers) | ||||
|       (ha-demo-hide-cursor) | ||||
|       (ha-demo-presentation-frame) | ||||
|       (demo-it--presentation-display-set) | ||||
|       (ha-demo-hide-mode-line) | ||||
|       (git-gutter-mode -1) | ||||
|       (ha-demo-presentation-frame) | ||||
|       ;; (demo-it--presentation-display-set) | ||||
|       (text-scale-set 4) | ||||
|       (git-gutter-mode -1) | ||||
|       (flycheck-mode -1) | ||||
|       (jinx-mode -1)) | ||||
| 
 | ||||
|     (defun ha-org-tree-slide-stop () | ||||
|       "Reset the display after a presentation. | ||||
|     See `ha-org-tree-slide-start' for what's set." | ||||
|       (demo-it--presentation-display-restore)  ; Restore previous changes | ||||
|       (setq org-hide-emphasis-markers t) | ||||
|       (ha-org-blocks-show-headers) | ||||
|       (ha-demo-show-cursor) | ||||
|       (ha-demo-show-mode-line) | ||||
|       (ha-demo-normalize-frame) | ||||
|       (ha-demo-show-cursor) | ||||
|       (git-gutter-mode) | ||||
|       ;; (demo-it--presentation-display-restore)  ; Restore previous changes | ||||
|       (text-scale-set 0) | ||||
|       (git-gutter-mode) | ||||
|       (flycheck-mode) | ||||
|       (jinx-mode)) | ||||
| 
 | ||||
|     :bind | ||||
|     (("S-<f6>" . org-tree-slide-skip-done-toggle) | ||||
|      :map org-tree-slide-mode-map | ||||
|     (:map org-tree-slide-mode-map | ||||
|      ("<f5>" . org-tree-slide-move-next-tree) | ||||
|      ("S-<f5>" . org-tree-slide-move-previous-tree) | ||||
|      ("M-<f5>" . org-tree-slide-content) | ||||
|  | @ -191,13 +196,10 @@ I’ve used [[https://github.com/takaxp/org-tree-slide][org-tree-slide]] for yea | |||
| 
 | ||||
|     :general | ||||
|     (:states 'normal :keymaps 'org-tree-slide-mode-map | ||||
|              "c" #'ha-demo-hide-cursor | ||||
|              "C" #'ha-demo-show-cursor | ||||
|              "C" #'ha-demo-toggle-cursor | ||||
|              "n" #'org-tree-slide-move-next-tree | ||||
|              "j" #'org-tree-slide-move-next-tree | ||||
|              "k" #'org-tree-slide-move-previous-tree | ||||
|              "p" #'org-tree-slide-move-previous-tree | ||||
|              "q" (lambda () (interactive) (org-slide-tree-mode -1))) | ||||
|              "N" #'org-tree-slide-move-previous-tree | ||||
|              "Q" (lambda () (interactive) (org-slide-tree-mode -1))) | ||||
| 
 | ||||
|     :hook | ||||
|     ((org-tree-slide-play . ha-org-tree-slide-start) | ||||
|  | @ -219,16 +221,18 @@ To make the contents of the expression easier to write, the =define-ha-demo= as | |||
| 
 | ||||
| #+BEGIN_SRC emacs-lisp | ||||
|   (defmacro define-ha-demo (demo-name &rest forms) | ||||
|     "Create a demonstration sequence as DEMO-NAME function. | ||||
|   Call DEMO-NAME (as an interactive function), executes a function based matching list of states at point. | ||||
|   Where FORMS is an even number of _matcher_ and _function_ to call. | ||||
|     "Create a demonstration sequence from FORMS as DEMO-NAME function. | ||||
| 
 | ||||
|   Call DEMO-NAME (as an interactive function), executes a function | ||||
|   based matching list of states at point. Where FORMS is an even | ||||
|   number of _matcher_ and _function_ to call. | ||||
| 
 | ||||
|   Probably best to explain this in an example: | ||||
| 
 | ||||
|   (define-demo demo1 | ||||
|    (:buffer \"demonstrations.py\") (message \"In a buffer\") | ||||
|    (:mode 'dired-mode)             (message \"In a dired\") | ||||
|    (:heading \"Raven Civilizations\"  (message \"In an org file\"))) | ||||
|     \(define-demo demo1 | ||||
|      \(:buffer \"demonstrations.py\")    \(message \"In a buffer\"\) | ||||
|      \(:mode 'dired-mode\)              \(message \"In a dired\"\) | ||||
|      \(:heading \"Raven Civilizations\"\) \(message \"In an org file\"\)\) | ||||
| 
 | ||||
|   Calling `(demo1)' displays a message based on position of the | ||||
|   point in a particular buffer or place in a heading in an Org file. | ||||
|  | @ -236,9 +240,9 @@ To make the contents of the expression easier to write, the =define-ha-demo= as | |||
|   You can use the `:i' to specify different forms to call when | ||||
|   the trigger matches the first time, versus the second time, etc. | ||||
| 
 | ||||
|   (define-demo demo2 | ||||
|    (:buffer \"demonstrations.org\" :i 0) (message \"First time\") | ||||
|    (:buffer \"demonstrations.org\" :i 1) (message \"Second time\"))" | ||||
|   \(define-demo demo2 | ||||
|    \(:buffer \"demonstrations.org\" :i 0\) \(message \"First time\"\) | ||||
|    \(:buffer \"demonstrations.org\" :i 1\) \(message \"Second time\"\)\)" | ||||
|     `(defun ,demo-name () | ||||
|        (interactive) | ||||
|        (let ((state (list :buffer (buffer-name) | ||||
|  | @ -345,6 +349,7 @@ The typical presentation software has an issue for hiding the cursor when workin | |||
|   (defun ha-demo-hide-cursor () | ||||
|     "Hide the cursor for the current frame." | ||||
|     (interactive) | ||||
|     (unless ha-demo-cursor | ||||
|       (setq ha-demo-cursor | ||||
|             (list cursor-type | ||||
|                   t ; (when (boundp 'evil-default-cursor) evil-default-cursor) | ||||
|  | @ -366,11 +371,12 @@ The typical presentation software has an issue for hiding the cursor when workin | |||
|          evil-normal-state-cursor nil)) | ||||
| 
 | ||||
|       ;; And most importantly, turn off the cursor for the selected frame: | ||||
|     (set-frame-parameter (selected-frame) 'cursor-type nil)) | ||||
|       (set-frame-parameter (selected-frame) 'cursor-type nil))) | ||||
| 
 | ||||
|   (defun ha-demo-show-cursor () | ||||
|     "Restore cursor properties turned off by `ha-demo-hide-cursor'." | ||||
|     (interactive) | ||||
|     (when ha-demo-cursor | ||||
|       (setq cursor-type (car ha-demo-cursor)) | ||||
| 
 | ||||
|       (when (boundp 'evil-default-cursor) | ||||
|  | @ -382,7 +388,15 @@ The typical presentation software has an issue for hiding the cursor when workin | |||
|       (when (nth 4 ha-demo-cursor) (blink-cursor-mode 1)) | ||||
| 
 | ||||
|       (set-frame-parameter (selected-frame) | ||||
|                          'cursor-type (nth 5 ha-demo-cursor))) | ||||
|                            'cursor-type (nth 5 ha-demo-cursor)) | ||||
|       (setq ha-demo-cursor nil))) | ||||
| 
 | ||||
|   (defun ha-demo-toggle-cursor () | ||||
|     "Toggles the display of the cursor." | ||||
|     (interactive) | ||||
|     (if ha-demo-cursor | ||||
|         (ha-demo-show-cursor) | ||||
|       (ha-demo-hide-cursor))) | ||||
|     #+END_SRC | ||||
| 
 | ||||
| ** Hide and Show the Modeline | ||||
|  | @ -444,7 +458,7 @@ Displaying a File with: | |||
| 
 | ||||
| All options? Should I use Common Lisp’s =cl-defun= for the keyword parameters? | ||||
| 
 | ||||
| #+BEGIN_SRC emacs-lisp | ||||
| #+BEGIN_SRC emacs-lisp :tangle no | ||||
|   (cl-defun ha-demo-show-file (filename &key position size modeline | ||||
|                                         line heading shift commands) | ||||
|     "Show a file, FILENAME, in a buffer based on keyed parameters. | ||||
|  | @ -452,6 +466,7 @@ All options? Should I use Common Lisp’s =cl-defun= for the keyword parameters? | |||
|   SIZE is an integer for the font size based on the default size. | ||||
|   MODELINE is shown if non-line, default is to hide it. | ||||
|   LINE is either a line number or a regular expression to match. | ||||
|   HEADING is a headline from the currently display Org file. | ||||
|   SHIFT is the number of lines above the point to show, in case | ||||
|   the LINE shouldn't be at the top of the window. | ||||
| 
 | ||||
|  | @ -462,10 +477,12 @@ All options? Should I use Common Lisp’s =cl-defun= for the keyword parameters? | |||
| 
 | ||||
|     ;; Step 1: Create a window | ||||
|     (pcase position | ||||
|       ('full ) | ||||
|       ('above (progn (split-window-vertically))) | ||||
|       ('up    (progn (split-window-vertically))) | ||||
|       ('left  (progn (split-window-horizontally))) | ||||
|       ('right (progn (split-window-horizontally) (other-window 1))) | ||||
|       ('above (progn (split-window-vertically) (other-window 1))) | ||||
|       ('below (progn (split-window-vertically) (other-window 1)))) | ||||
|     ;; We could do :left and :top by not doing the other window bit... | ||||
| 
 | ||||
|     ;; Step 2: Load the file or switch to the buffer: | ||||
|     (if (file-exists-p filename) | ||||
|  | @ -480,7 +497,7 @@ All options? Should I use Common Lisp’s =cl-defun= for the keyword parameters? | |||
| 
 | ||||
|     (when line | ||||
|       (if (integerp line) | ||||
|           (goto-line line) | ||||
|           (forward-line line) | ||||
|         (re-search-forward line nil t))) | ||||
| 
 | ||||
|     (when heading | ||||
|  | @ -499,10 +516,7 @@ All options? Should I use Common Lisp’s =cl-defun= for the keyword parameters? | |||
|     (unless modeline | ||||
|       (setq-local mode-line-format nil)) | ||||
| 
 | ||||
|     (when commands (funcall commands)) | ||||
|     ) | ||||
| 
 | ||||
|   (funcall (lambda () (message "Hello"))) | ||||
|     (when commands (funcall commands))) | ||||
| #+END_SRC | ||||
| 
 | ||||
| Let try it all together: | ||||
|  |  | |||
|  | @ -9,7 +9,7 @@ A literate programming file for defining leaders with general | |||
|   ;;; ha-leader --- defining leaders with general -*- lexical-binding: t; -*- | ||||
|   ;; | ||||
|   ;; © 2024 Howard X. Abrams | ||||
|   ;;   This work is licensed under a Creative Commons Attribution 4.0 International License. | ||||
|   ;;   Work licensed under a Creative Commons Attribution 4.0 International License. | ||||
|   ;;   See http://creativecommons.org/licenses/by/4.0/ | ||||
|   ;; | ||||
|   ;; Author: Howard X. Abrams <http://gitlab.com/howardabrams> | ||||
|  |  | |||
|  | @ -2,7 +2,7 @@ | |||
| #+author: Howard Abrams | ||||
| #+date:   2024-07-07 | ||||
| #+filetags: emacs hamacs | ||||
| #+lastmod: [2024-10-27 Sun] | ||||
| #+lastmod: [2024-10-29 Tue] | ||||
| 
 | ||||
| A literate programming file for literate programming in Emacs Org Files. | ||||
| 
 | ||||
|  | @ -182,7 +182,7 @@ For instance, the following function can be used to quickly select a source code | |||
|     (avy-jump (rx line-start (zero-or-more blank) "#+begin_src") | ||||
|               :action 'goto-char) | ||||
|     ;; Jump _into_ the block: | ||||
|     (next-line)) | ||||
|     (forward-line)) | ||||
| #+end_src | ||||
| 
 | ||||
| I need to take advantage of this feature more. | ||||
|  | @ -222,7 +222,8 @@ A trick to =org-babel-tangle=, is that it tangles /what Emacs shows/, that is, i | |||
| 
 | ||||
| #+begin_src emacs-lisp :results silent | ||||
|   (defun org-babel-execute-subtree (prefix) | ||||
|     "Execute all Org source blocks in current subtree." | ||||
|     "Execute all Org source blocks in current subtree. | ||||
|   The PREFIX is passed to `org-babel-execute-buffer'." | ||||
|     (interactive "P") | ||||
|     (save-excursion | ||||
|       (org-narrow-to-subtree) | ||||
|  | @ -280,7 +281,7 @@ While the goal is Emacs Lisp (and it mostly works for that), it will probably wo | |||
|   (defun ha-literate-symbol-at-point () | ||||
|     "Return an alphanumeric sequence at point. | ||||
|   Assuming the sequence can be surrounded by typical | ||||
|   punctuation found in org-mode and markdown files." | ||||
|   punctuation found in `org-mode' and markdown files." | ||||
|     (save-excursion | ||||
|       ;; Position point at the first alnum character of the symbol: | ||||
|       (cond ((looking-at (rx (any "=~({<\"'“`") alnum)) | ||||
|  | @ -311,7 +312,7 @@ This helper function does the work of calling =ripgrep=, parsing its output, and | |||
| 
 | ||||
| #+begin_src emacs-lisp | ||||
|   (defun ha-literate--ripgrep-matches (processor regex) | ||||
|     "Return list of running PROCESSOR of `rg' matches from REGEXP. | ||||
|     "Return list of running PROCESSOR of `rg' matches from REGEX. | ||||
|   PROCESSOR is called with an assoc-list of the JSON output from | ||||
|   the call to ripgrep." | ||||
|     (let* ((default-directory (if (project-current) | ||||
|  | @ -345,8 +346,8 @@ The output from =ripgrep= goes through a couple of transformation functions list | |||
|     (string-equal "match" (alist-get 'type json-data))) | ||||
| #+end_src | ||||
| 
 | ||||
| TODO Relative Filenames | ||||
| Since our =ripgrep= searches from the /project root/, but xref wants to make file references relative to the buffer that is calling it, we need to make some changes: | ||||
| 
 | ||||
| #+BEGIN_SRC emacs-lisp | ||||
|   (defun ha-literate-make-xref-file (filepath) | ||||
|     "Return FILEPATH relative to current buffer's file." | ||||
|  | @ -355,7 +356,7 @@ Since our =ripgrep= searches from the /project root/, but xref wants to make fil | |||
|                                          (project-root (project-current)) | ||||
|                                        default-directory))) | ||||
|           (relative-to (file-name-parent-directory (buffer-file-name)))) | ||||
|       (file-relative-name abspath relative-to)))) | ||||
|       (file-relative-name abspath relative-to))) | ||||
| #+END_SRC | ||||
| 
 | ||||
| Let’s test this function: | ||||
|  | @ -484,14 +485,12 @@ And the function to process the output simply attempts to connect the =begin_src | |||
| #+begin_src emacs-lisp | ||||
|   (defvar ha-literate--process-src-refs | ||||
|     (make-hash-table :test 'equal) | ||||
|     "Globabl variable storing results of processing | ||||
|   org-mode's block line numbers. The key in this table is a file | ||||
|   name, and the value is a list of line numbers marking #+begin_src | ||||
|   and #+end_src.") | ||||
|     "Globabl variable storing org-mode's block line numbers. | ||||
|   The key in this table is a file name, and the value is a list of | ||||
|   line numbers marking #+begin_src and #+end_src.") | ||||
| 
 | ||||
|   (defvar ha-literate--process-begin-src nil | ||||
|     "Globabl variable storing the last entry of an | ||||
|   org-mode's `#+begin_src' line number.") | ||||
|     "Global variable last `#+begin_src' line number.") | ||||
| 
 | ||||
|   (defun ha-literate--process-src-blocks (rg-data-line) | ||||
|     "Return nil if RG-DATA-LINE contains a begin_src entry. | ||||
|  | @ -551,7 +550,7 @@ Need the completion table before we can find the references. It actually doesn | |||
|   (defun ha-literate-completion-table ()) | ||||
| #+end_src | ||||
| 
 | ||||
| Now we /hook this up/ to the rest of the system: | ||||
| Now we /hook this up/ to the rest of the system, and the =xref= is now complete: | ||||
| 
 | ||||
| #+begin_src emacs-lisp | ||||
|   (cl-defmethod xref-backend-identifier-completion-table ((_backend (eql org))) | ||||
|  | @ -563,7 +562,7 @@ To finish the connections, we need to create a /hook/ that I only allow to turn | |||
| #+begin_src emacs-lisp | ||||
|   (defun ha-literate-xref-activate () | ||||
|     "Function to activate org-based literate backend. | ||||
|   Add this function to `xref-backend-functions' hook. " | ||||
|   Add this function to `xref-backend-functions' hook." | ||||
|     (when (eq major-mode 'org-mode) | ||||
|       'org)) | ||||
| 
 | ||||
|  | @ -835,8 +834,7 @@ I would like to make the /filename/ more readable, I use the =s-match= again, to | |||
|   (defvar ha-hamacs-edit-file-to-title | ||||
|     (rx (optional (or "README-" "ha-")) | ||||
|         (group (one-or-more any)) ".org") | ||||
|     "Regular expression for extracting the interesting part of a | ||||
|   file to use as a title.") | ||||
|     "Extract the part of a file to use as a title.") | ||||
| #+end_src | ||||
| 
 | ||||
| So the following tests should pass: | ||||
|  |  | |||
							
								
								
									
										
											BIN
										
									
								
								ha-org-mermaid.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								ha-org-mermaid.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 5.6 KiB | 
|  | @ -3,7 +3,7 @@ | |||
| #+date:   2020-09-18 | ||||
| #+tags: emacs org | ||||
| #+startup: inlineimages | ||||
| #+lastmod: [2024-10-25 Fri] | ||||
| #+lastmod: [2024-10-30 Wed] | ||||
| 
 | ||||
| A literate programming file for configuring org-mode and those files. | ||||
| 
 | ||||
|  | @ -882,9 +882,11 @@ And the Emacs interface to that: | |||
| 
 | ||||
| #+begin_src emacs-lisp | ||||
|   (use-package jinx | ||||
|     :straight (:host github :repo "minad/jinx" :files (:defaults "jinx-mod.c" "emacs-module.h")) | ||||
|     :hook (emacs-startup . global-jinx-mode) | ||||
|     :bind (("M-$" . jinx-correct-nearest) | ||||
|            ("s-;" . jinx-correct-nearest)) | ||||
|            ;;   :bind (([remap ispell-word] . #'jinx-correct)) | ||||
|     :general | ||||
|     (:states '(normal insert) :keymaps 'text-mode-map | ||||
|              "M-s M-s" 'jinx-correct) | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue