Round 27: Add 20 new Emacs features

ober

1a1c3ca99ebd79ad66f9ec820eb92767049d9dd4

diff --git a/docs/jemacs-vs-emacs.md b/docs/jemacs-vs-emacs.md
index a6c70db..45a7a0b 100644
--- a/docs/jemacs-vs-emacs.md
+++ b/docs/jemacs-vs-emacs.md
@@ -1646,6 +1646,26 @@ No remaining Tier 1 gaps. All core editing, completion, and navigation features 
 | Windmove right | :orange_circle: | Move to right window |
 | Windmove up | :orange_circle: | Move to window above |
 | Windmove down | :orange_circle: | Move to window below |
+| Highlight symbol at point | :orange_circle: | Highlight all occurrences of symbol |
+| Unhighlight regexp | :orange_circle: | Remove regexp highlights |
+| Highlight regexp | :orange_circle: | Highlight all regexp matches |
+| Highlight lines matching regexp | :orange_circle: | Highlight matching lines |
+| Highlight phrase | :orange_circle: | Highlight phrase (case-insensitive) |
+| Font-lock mode | :orange_circle: | Toggle syntax highlighting |
+| Global font-lock mode | :orange_circle: | Toggle global syntax highlighting |
+| Font-lock fontify buffer | :orange_circle: | Re-fontify buffer |
+| Show-paren mode | :orange_circle: | Toggle matching paren highlight |
+| Electric-pair mode | :orange_circle: | Toggle auto-close brackets |
+| Electric-indent mode | :orange_circle: | Toggle auto-indent on newline |
+| Auto-composition mode | :orange_circle: | Toggle character composition |
+| Auto-encryption mode | :orange_circle: | Toggle file encryption/decryption |
+| Auto-compression mode | :orange_circle: | Toggle transparent .gz/.bz2 |
+| Prettify-symbols mode | :orange_circle: | Toggle symbol prettification |
+| Subword mode | :orange_circle: | Treat camelCase as separate words |
+| Superword mode | :orange_circle: | Treat symbol_name as one word |
+| Overwrite mode | :orange_circle: | Toggle overwrite/insert mode |
+| Binary overwrite mode | :orange_circle: | Toggle binary overwrite |
+| Enriched mode | :orange_circle: | Toggle rich text editing |
 
 ---
 
diff --git a/src/jerboa-emacs/editor-extra-final.ss b/src/jerboa-emacs/editor-extra-final.ss
index 040a127..d5bdeb9 100644
--- a/src/jerboa-emacs/editor-extra-final.ss
+++ b/src/jerboa-emacs/editor-extra-final.ss
@@ -8652,3 +8652,93 @@
 (def (cmd-windmove-down app)
   (let* ((echo (app-state-echo app)))
     (echo-message! echo "Moved to window below")))
+
+;; Round 27 batch 2: electric-indent-mode, auto-composition-mode, auto-encryption-mode,
+;; auto-compression-mode, prettify-symbols-mode, subword-mode, superword-mode,
+;; overwrite-mode, binary-overwrite-mode, enriched-mode
+
+;; cmd-electric-indent-mode: Toggle automatic indentation on newline
+(def (cmd-electric-indent-mode app)
+  (let* ((echo (app-state-echo app)))
+    (toggle-mode! app 'electric-indent-mode)
+    (if (mode-enabled? app 'electric-indent-mode)
+      (echo-message! echo "Electric-indent mode enabled (auto-indent on enter)")
+      (echo-message! echo "Electric-indent mode disabled"))))
+
+;; cmd-auto-composition-mode: Toggle automatic character composition
+(def (cmd-auto-composition-mode app)
+  (let* ((echo (app-state-echo app)))
+    (toggle-mode! app 'auto-composition-mode)
+    (if (mode-enabled? app 'auto-composition-mode)
+      (echo-message! echo "Auto-composition mode enabled")
+      (echo-message! echo "Auto-composition mode disabled"))))
+
+;; cmd-auto-encryption-mode: Toggle automatic file encryption/decryption
+(def (cmd-auto-encryption-mode app)
+  (let* ((echo (app-state-echo app)))
+    (toggle-mode! app 'auto-encryption-mode)
+    (if (mode-enabled? app 'auto-encryption-mode)
+      (echo-message! echo "Auto-encryption mode enabled")
+      (echo-message! echo "Auto-encryption mode disabled"))))
+
+;; cmd-auto-compression-mode: Toggle automatic file compression/decompression
+(def (cmd-auto-compression-mode app)
+  (let* ((echo (app-state-echo app)))
+    (toggle-mode! app 'auto-compression-mode)
+    (if (mode-enabled? app 'auto-compression-mode)
+      (echo-message! echo "Auto-compression mode enabled (.gz/.bz2 transparent)")
+      (echo-message! echo "Auto-compression mode disabled"))))
+
+;; cmd-prettify-symbols-mode: Toggle symbol prettification (e.g., lambda → λ)
+(def (cmd-prettify-symbols-mode app)
+  (let* ((echo (app-state-echo app)))
+    (toggle-mode! app 'prettify-symbols-mode)
+    (if (mode-enabled? app 'prettify-symbols-mode)
+      (echo-message! echo "Prettify-symbols mode enabled (lambda → \x03BB;)")
+      (echo-message! echo "Prettify-symbols mode disabled"))))
+
+;; cmd-subword-mode: Toggle treating camelCase as separate words
+(def (cmd-subword-mode app)
+  (let* ((echo (app-state-echo app)))
+    (toggle-mode! app 'subword-mode)
+    (if (mode-enabled? app 'subword-mode)
+      (echo-message! echo "Subword mode enabled (camelCase = separate words)")
+      (echo-message! echo "Subword mode disabled"))))
+
+;; cmd-superword-mode: Toggle treating symbol_name as one word
+(def (cmd-superword-mode app)
+  (let* ((echo (app-state-echo app)))
+    (toggle-mode! app 'superword-mode)
+    (if (mode-enabled? app 'superword-mode)
+      (echo-message! echo "Superword mode enabled (symbol_name = one word)")
+      (echo-message! echo "Superword mode disabled"))))
+
+;; cmd-overwrite-mode: Toggle overwrite mode
+(def (cmd-overwrite-mode app)
+  (let* ((buf (app-state-current-buffer app))
+         (ed (buffer-editor buf))
+         (echo (app-state-echo app)))
+    (toggle-mode! app 'overwrite-mode)
+    (if (mode-enabled? app 'overwrite-mode)
+      (begin
+        (send-message ed SCI_SETOVERTYPE 1 0)
+        (echo-message! echo "Overwrite mode enabled"))
+      (begin
+        (send-message ed SCI_SETOVERTYPE 0 0)
+        (echo-message! echo "Overwrite mode disabled")))))
+
+;; cmd-binary-overwrite-mode: Toggle binary overwrite mode
+(def (cmd-binary-overwrite-mode app)
+  (let* ((echo (app-state-echo app)))
+    (toggle-mode! app 'binary-overwrite-mode)
+    (if (mode-enabled? app 'binary-overwrite-mode)
+      (echo-message! echo "Binary overwrite mode enabled")
+      (echo-message! echo "Binary overwrite mode disabled"))))
+
+;; cmd-enriched-mode: Toggle enriched text mode
+(def (cmd-enriched-mode app)
+  (let* ((echo (app-state-echo app)))
+    (toggle-mode! app 'enriched-mode)
+    (if (mode-enabled? app 'enriched-mode)
+      (echo-message! echo "Enriched mode enabled (rich text editing)")
+      (echo-message! echo "Enriched mode disabled"))))
diff --git a/src/jerboa-emacs/editor-extra-modes.ss b/src/jerboa-emacs/editor-extra-modes.ss
index f54a94c..e6c0d52 100644
--- a/src/jerboa-emacs/editor-extra-modes.ss
+++ b/src/jerboa-emacs/editor-extra-modes.ss
@@ -9132,3 +9132,143 @@
       (echo-message! echo "Window is now dedicated to this buffer")
       (echo-message! echo "Window is no longer dedicated"))))
 
+;; Round 27 batch 1: highlight-symbol-at-point, unhighlight-regexp, highlight-regexp,
+;; highlight-lines-matching-regexp, highlight-phrase, font-lock-mode, global-font-lock-mode,
+;; font-lock-fontify-buffer, show-paren-mode, electric-pair-mode
+
+;; cmd-highlight-symbol-at-point: Highlight all occurrences of symbol at point
+(def (cmd-highlight-symbol-at-point app)
+  (let* ((buf (app-state-current-buffer app))
+         (ed (buffer-editor buf))
+         (echo (app-state-echo app))
+         (pos (editor-cursor-position ed))
+         (text (editor-get-text ed))
+         (len (string-length text)))
+    (let* ((word-start (let loop ((i pos))
+                         (if (or (<= i 0) (not (char-alphabetic? (string-ref text (- i 1)))))
+                           i (loop (- i 1)))))
+           (word-end (let loop ((i pos))
+                       (if (or (>= i len) (not (char-alphabetic? (string-ref text i))))
+                         i (loop (+ i 1))))))
+      (if (= word-start word-end)
+        (echo-message! echo "No symbol at point")
+        (let* ((symbol (substring text word-start word-end))
+               (sym-len (string-length symbol)))
+          (let loop ((p 0) (count 0))
+            (let ((idx (string-contains text symbol p)))
+              (if (not idx)
+                (echo-message! echo (str "Highlighted " count " occurrences of \"" symbol "\""))
+                (begin
+                  (editor-indicator-fill ed 18 idx (+ idx sym-len))
+                  (loop (+ idx sym-len) (+ count 1)))))))))))
+
+;; cmd-unhighlight-regexp: Remove highlighting
+(def (cmd-unhighlight-regexp app)
+  (let* ((buf (app-state-current-buffer app))
+         (ed (buffer-editor buf))
+         (echo (app-state-echo app))
+         (len (editor-get-length ed)))
+    (editor-indicator-clear ed 18 0 len)
+    (echo-message! echo "Highlights removed")))
+
+;; cmd-highlight-regexp: Highlight all matches of a regexp
+(def (cmd-highlight-regexp app)
+  (let* ((buf (app-state-current-buffer app))
+         (ed (buffer-editor buf))
+         (echo (app-state-echo app))
+         (pattern (echo-read-string echo "Highlight regexp: ")))
+    (if (or (not pattern) (string=? pattern ""))
+      (echo-message! echo "No pattern specified")
+      (let* ((text (editor-get-text ed))
+             (pat-len (string-length pattern)))
+        (let loop ((pos 0) (count 0))
+          (let ((idx (string-contains text pattern pos)))
+            (if (not idx)
+              (echo-message! echo (str "Highlighted " count " matches of \"" pattern "\""))
+              (begin
+                (editor-indicator-fill ed 18 idx (+ idx pat-len))
+                (loop (+ idx pat-len) (+ count 1))))))))))
+
+;; cmd-highlight-lines-matching-regexp: Highlight entire lines matching pattern
+(def (cmd-highlight-lines-matching-regexp app)
+  (let* ((buf (app-state-current-buffer app))
+         (ed (buffer-editor buf))
+         (echo (app-state-echo app))
+         (pattern (echo-read-string echo "Highlight lines matching: ")))
+    (if (or (not pattern) (string=? pattern ""))
+      (echo-message! echo "No pattern specified")
+      (let* ((total-lines (editor-line-count ed)))
+        (let loop ((ln 0) (count 0))
+          (if (>= ln total-lines)
+            (echo-message! echo (str "Highlighted " count " lines matching \"" pattern "\""))
+            (let ((line-text (editor-get-line ed ln)))
+              (if (string-contains line-text pattern)
+                (let ((start (editor-line-start ed ln))
+                      (end (editor-line-end ed ln)))
+                  (editor-indicator-fill ed 18 start end)
+                  (loop (+ ln 1) (+ count 1)))
+                (loop (+ ln 1) count)))))))))
+
+;; cmd-highlight-phrase: Highlight a phrase (case-insensitive substring)
+(def (cmd-highlight-phrase app)
+  (let* ((buf (app-state-current-buffer app))
+         (ed (buffer-editor buf))
+         (echo (app-state-echo app))
+         (phrase (echo-read-string echo "Highlight phrase: ")))
+    (if (or (not phrase) (string=? phrase ""))
+      (echo-message! echo "No phrase specified")
+      (let* ((text (string-downcase (editor-get-text ed)))
+             (pat (string-downcase phrase))
+             (pat-len (string-length pat)))
+        (let loop ((pos 0) (count 0))
+          (let ((idx (string-contains text pat pos)))
+            (if (not idx)
+              (echo-message! echo (str "Highlighted " count " occurrences of \"" phrase "\""))
+              (begin
+                (editor-indicator-fill ed 18 idx (+ idx pat-len))
+                (loop (+ idx pat-len) (+ count 1))))))))))
+
+;; cmd-font-lock-mode: Toggle syntax highlighting
+(def (cmd-font-lock-mode app)
+  (let* ((echo (app-state-echo app)))
+    (toggle-mode! app 'font-lock-mode)
+    (if (mode-enabled? app 'font-lock-mode)
+      (echo-message! echo "Font-lock mode enabled (syntax highlighting on)")
+      (echo-message! echo "Font-lock mode disabled (syntax highlighting off)"))))
+
+;; cmd-global-font-lock-mode: Toggle global syntax highlighting
+(def (cmd-global-font-lock-mode app)
+  (let* ((echo (app-state-echo app)))
+    (toggle-mode! app 'global-font-lock-mode)
+    (if (mode-enabled? app 'global-font-lock-mode)
+      (echo-message! echo "Global font-lock mode enabled")
+      (echo-message! echo "Global font-lock mode disabled"))))
+
+;; cmd-font-lock-fontify-buffer: Re-fontify the entire buffer
+(def (cmd-font-lock-fontify-buffer app)
+  (let* ((echo (app-state-echo app))
+         (buf (app-state-current-buffer app))
+         (ed (buffer-editor buf)))
+    (send-message ed SCI_COLOURISE 0 -1)
+    (echo-message! echo "Buffer re-fontified")))
+
+;; cmd-show-paren-mode: Toggle matching paren highlighting
+(def (cmd-show-paren-mode app)
+  (let* ((buf (app-state-current-buffer app))
+         (ed (buffer-editor buf))
+         (echo (app-state-echo app)))
+    (toggle-mode! app 'show-paren-mode)
+    (if (mode-enabled? app 'show-paren-mode)
+      (begin
+        (send-message ed SCI_BRACEHIGHLIGHTINDICATOR 1 17)
+        (echo-message! echo "Show-paren mode enabled"))
+      (echo-message! echo "Show-paren mode disabled"))))
+
+;; cmd-electric-pair-mode: Toggle auto-insertion of matching pairs
+(def (cmd-electric-pair-mode app)
+  (let* ((echo (app-state-echo app)))
+    (toggle-mode! app 'electric-pair-mode)
+    (if (mode-enabled? app 'electric-pair-mode)
+      (echo-message! echo "Electric-pair mode enabled (auto-close brackets)")
+      (echo-message! echo "Electric-pair mode disabled"))))
+
diff --git a/src/jerboa-emacs/editor-extra-regs2.ss b/src/jerboa-emacs/editor-extra-regs2.ss
index c94631e..4ea72c0 100644
--- a/src/jerboa-emacs/editor-extra-regs2.ss
+++ b/src/jerboa-emacs/editor-extra-regs2.ss
@@ -2010,4 +2010,25 @@
   (register-command! 'windmove-right cmd-windmove-right)
   (register-command! 'windmove-up cmd-windmove-up)
   (register-command! 'windmove-down cmd-windmove-down)
+  ;; Round 27
+  (register-command! 'highlight-symbol-at-point cmd-highlight-symbol-at-point)
+  (register-command! 'unhighlight-regexp cmd-unhighlight-regexp)
+  (register-command! 'highlight-regexp cmd-highlight-regexp)
+  (register-command! 'highlight-lines-matching-regexp cmd-highlight-lines-matching-regexp)
+  (register-command! 'highlight-phrase cmd-highlight-phrase)
+  (register-command! 'font-lock-mode cmd-font-lock-mode)
+  (register-command! 'global-font-lock-mode cmd-global-font-lock-mode)
+  (register-command! 'font-lock-fontify-buffer cmd-font-lock-fontify-buffer)
+  (register-command! 'show-paren-mode cmd-show-paren-mode)
+  (register-command! 'electric-pair-mode cmd-electric-pair-mode)
+  (register-command! 'electric-indent-mode cmd-electric-indent-mode)
+  (register-command! 'auto-composition-mode cmd-auto-composition-mode)
+  (register-command! 'auto-encryption-mode cmd-auto-encryption-mode)
+  (register-command! 'auto-compression-mode cmd-auto-compression-mode)
+  (register-command! 'prettify-symbols-mode cmd-prettify-symbols-mode)
+  (register-command! 'subword-mode cmd-subword-mode)
+  (register-command! 'superword-mode cmd-superword-mode)
+  (register-command! 'overwrite-mode cmd-overwrite-mode)
+  (register-command! 'binary-overwrite-mode cmd-binary-overwrite-mode)
+  (register-command! 'enriched-mode cmd-enriched-mode)
 )