Add 8 real Emacs feature implementations: electric quotes, aggressive indent, volatile highlights, highlight changes, dtrt-indent, rainbow mode, hl-todo, glasses mode
ober
e25e0168e97b9c5583576eacc4a37dabc7a5e4d8
--- a/src/jerboa-emacs/app.ss +++ b/src/jerboa-emacs/app.ss @@ -562,6 +562,9 @@ ;; Tick pulse highlight countdown (pulse-tick!) + ;; Tick volatile highlights countdown + (volatile-highlight-tick!) + ;; Tick which-key delayed display (which-key-tui-tick! app) --- a/src/jerboa-emacs/editor-core.ss +++ b/src/jerboa-emacs/editor-core.ss @@ -35,6 +35,7 @@ ;;;============================================================================ (def *auto-pair-mode* #t) (def *auto-revert-mode* #f) +(def *aggressive-indent-mode* #f) ;;;============================================================================ ;;; Pulse/flash highlight on jump (beacon-like) @@ -80,6 +81,45 @@ (set! *pulse-countdown* 0))) ;;;============================================================================ +;;; Volatile highlights — flash changed regions (yank, undo) +;;;============================================================================ +(def *volatile-highlight-indicator* 2) +(def *volatile-highlight-countdown* 0) +(def *volatile-highlight-editor* #f) + +(def (volatile-highlight! ed start len) + "Flash-highlight region [START, START+LEN) briefly when volatile-highlights is on." + (when (and *volatile-highlights* (> len 0)) + ;; Clear any previous volatile highlight + (volatile-highlight-clear!) + ;; Set up indicator: green-tinted box + (send-message ed SCI_INDICSETSTYLE *volatile-highlight-indicator* INDIC_ROUNDBOX) + (send-message ed SCI_INDICSETFORE *volatile-highlight-indicator* #x80FF80) ; light green + (send-message ed SCI_INDICSETALPHA *volatile-highlight-indicator* 60) + (send-message ed SCI_INDICSETUNDER *volatile-highlight-indicator* 1) + (send-message ed SCI_SETINDICATORCURRENT *volatile-highlight-indicator* 0) + (send-message ed SCI_INDICATORFILLRANGE start len) + (set! *volatile-highlight-editor* ed) + (set! *volatile-highlight-countdown* 8))) ; 8 * 50ms = 400ms + +(def (volatile-highlight-tick!) + "Called each main loop iteration. Decrements volatile highlight countdown." + (when (> *volatile-highlight-countdown* 0) + (set! *volatile-highlight-countdown* (- *volatile-highlight-countdown* 1)) + (when (= *volatile-highlight-countdown* 0) + (volatile-highlight-clear!)))) + +(def (volatile-highlight-clear!) + "Remove volatile highlight indicator." + (when *volatile-highlight-editor* + (let ((len (editor-get-text-length *volatile-highlight-editor*))) + (send-message *volatile-highlight-editor* SCI_SETINDICATORCURRENT + *volatile-highlight-indicator* 0) + (send-message *volatile-highlight-editor* SCI_INDICATORCLEARRANGE 0 len)) + (set! *volatile-highlight-editor* #f) + (set! *volatile-highlight-countdown* 0))) + +;;;============================================================================ ;;; System clipboard integration (xclip/xsel/wl-copy) ;;;============================================================================ @@ -440,6 +480,19 @@ (auto-pair-char ch)))) (n (get-prefix-arg app))) ; Get prefix arg (cond + ;; Electric quote mode: convert " and ' to curly quotes + ((and *electric-quote-mode* (= n 1) + (or (= ch 34) (= ch 39))) ; " or ' + (let* ((pos (editor-get-current-pos ed)) + (replacement (electric-quote-char ch ed))) + (if replacement + (let ((rlen (string-length replacement))) + (editor-insert-text ed pos replacement) + (editor-goto-pos ed (+ pos rlen))) + ;; Fallback: insert raw char + (begin + (editor-insert-text ed pos (string (integer->char ch))) + (editor-goto-pos ed (+ pos 1)))))) ;; Auto/electric-pair skip-over: typing a closing delimiter when next char matches ((and pair-active (= n 1) (if *electric-pair-mode* @@ -468,11 +521,66 @@ (str (make-string n (integer->char ch)))) (editor-insert-text ed pos str) (editor-goto-pos ed (+ pos n))))) + ;; Aggressive indent: reindent current line after each insertion + (when (and *aggressive-indent-mode* + (not (dired-buffer? buf)) + (not (shell-buffer? buf)) + (not (terminal-buffer? buf))) + (tui-aggressive-indent-line! ed)) ;; Auto-fill: break line if past fill-column (tui-auto-fill-after-insert! app ed)))))) ;;;============================================================================ +;;; Aggressive indent — reindent current line based on paren depth +;;;============================================================================ + +(def (tui-aggressive-indent-line! ed) + "Reindent the current line based on paren/bracket depth of preceding text." + (let* ((text (editor-get-text ed)) + (len (string-length text)) + (pos (min (editor-get-current-pos ed) len))) + (when (> len 0) + (let* ((line-start (let loop ((i (- pos 1))) + (cond ((< i 0) 0) + ((char=? (string-ref text i) #\newline) (+ i 1)) + (else (loop (- i 1)))))) + (depth (let loop ((i 0) (d 0)) + (if (>= i line-start) d + (case (string-ref text i) + ((#\( #\[ #\{) (loop (+ i 1) (+ d 1))) + ((#\) #\] #\}) (loop (+ i 1) (max 0 (- d 1)))) + (else (loop (+ i 1) d)))))) + (line-end (let loop ((i line-start)) + (cond ((>= i len) i) + ((char=? (string-ref text i) #\newline) i) + (else (loop (+ i 1)))))) + (line-text (substring text line-start line-end)) + (trimmed (string-trim line-text)) + (close-first (let loop ((i 0) (d 0)) + (if (>= i (string-length trimmed)) d + (case (string-ref trimmed i) + ((#\) #\] #\}) (loop (+ i 1) (+ d 1))) + (else d))))) + (target-depth (max 0 (- depth close-first))) + (target-indent (make-string (* target-depth 2) #\space)) + (current-indent (let loop ((i 0)) + (if (>= i (string-length line-text)) "" + (if (char-whitespace? (string-ref line-text i)) + (loop (+ i 1)) + (substring line-text 0 i)))))) + (unless (string=? current-indent target-indent) + (let ((new-line (string-append target-indent trimmed))) + (send-message ed SCI_SETTARGETSTART line-start 0) + (send-message ed SCI_SETTARGETEND line-end 0) + (editor-replace-target ed new-line) + (let ((new-pos (+ line-start (string-length target-indent) + (max 0 (- pos line-start + (string-length current-indent)))))) + (editor-goto-pos ed (min new-pos + (+ line-start (string-length new-line))))))))))) + +;;;============================================================================ ;;; Auto-fill check for TUI self-insert ;;;============================================================================ @@ -865,7 +973,9 @@ (let ((new-pos (editor-get-current-pos ed))) (set! (app-state-last-yank-pos app) pos) (set! (app-state-last-yank-len app) (- new-pos pos)) - (set! (app-state-kill-ring-idx app) 0)))) + (set! (app-state-kill-ring-idx app) 0) + ;; Volatile highlight: flash the yanked region + (volatile-highlight! ed pos (- new-pos pos))))) ;;;============================================================================ ;;; Mark and region --- a/src/jerboa-emacs/editor-extra-modes.ss +++ b/src/jerboa-emacs/editor-extra-modes.ss @@ -2043,10 +2043,54 @@ "Correct word with jinx — delegates to flyspell-correct." (cmd-flyspell-correct-word app)) -;; Hl-todo — highlight TODO/FIXME/HACK keywords +;; Hl-todo — highlight TODO/FIXME/HACK keywords with colored indicators +(def *hl-todo-indicator* 5) +(def *hl-todo-keywords* + '(("TODO" . #x00CCFF) ; orange + ("FIXME" . #x0000FF) ; red + ("HACK" . #x00BBFF) ; dark orange + ("BUG" . #x0000CC) ; dark red + ("XXX" . #x0088FF) ; amber + ("NOTE" . #x00CC00))) ; green + +(def (hl-todo-refresh! ed) + "Scan the buffer and highlight all TODO-like keywords with colored indicators." + (let* ((text (editor-get-text ed)) + (len (string-length text))) + ;; Clear existing hl-todo indicators + (send-message ed SCI_SETINDICATORCURRENT *hl-todo-indicator* 0) + (send-message ed SCI_INDICATORCLEARRANGE 0 (max 1 len)) + ;; Set up indicator style + (send-message ed SCI_INDICSETSTYLE *hl-todo-indicator* INDIC_TEXTFORE) + (send-message ed SCI_INDICSETUNDER *hl-todo-indicator* 1) + ;; Find and highlight each keyword + (for-each + (lambda (kw-pair) + (let ((kw (car kw-pair)) + (color (cdr kw-pair)) + (kw-len (string-length (car kw-pair)))) + (send-message ed SCI_INDICSETFORE *hl-todo-indicator* color) + (send-message ed SCI_SETINDICATORCURRENT *hl-todo-indicator* 0) + (let loop ((start 0)) + (let ((found (string-contains text kw start))) + (when found + (send-message ed SCI_INDICATORFILLRANGE found kw-len) + (loop (+ found kw-len))))))) + *hl-todo-keywords*))) + +(def (hl-todo-clear! ed) + "Remove all hl-todo indicators." + (let ((len (editor-get-text-length ed))) + (send-message ed SCI_SETINDICATORCURRENT *hl-todo-indicator* 0) + (send-message ed SCI_INDICATORCLEARRANGE 0 (max 1 len)))) + (def (cmd-hl-todo-mode app) - "Toggle hl-todo mode — highlights TODO keywords." - (let ((on (toggle-mode! 'hl-todo))) + "Toggle hl-todo mode — highlights TODO/FIXME/HACK keywords with colors." + (let ((on (toggle-mode! 'hl-todo)) + (ed (current-editor app))) + (if on + (hl-todo-refresh! ed) + (hl-todo-clear! ed)) (echo-message! (app-state-echo app) (if on "HL-todo: on" "HL-todo: off")))) (def (cmd-hl-todo-next app) @@ -2324,10 +2368,72 @@ (echo-message! echo (if *global-editorconfig* "Global editorconfig ON" "Global editorconfig OFF")))) +(def (dtrt-detect-indent text) + "Analyze TEXT to detect indentation style. Returns (values use-tabs? indent-size) + by sampling the first 200 lines. Counts leading-tab vs leading-space lines, + and for spaces, finds the most common indent width (2, 3, 4, or 8)." + (let* ((lines (let loop ((i 0) (start 0) (acc '()) (count 0)) + (cond + ((or (>= i (string-length text)) (>= count 200)) + (reverse acc)) + ((char=? (string-ref text i) #\newline) + (loop (+ i 1) (+ i 1) + (cons (substring text start i) acc) + (+ count 1))) + (else (loop (+ i 1) start acc count))))) + (tab-lines 0) + (space-lines 0) + (widths (make-vector 9 0))) ; index 0-8, count occurrences of each width + (for-each + (lambda (line) + (when (> (string-length line) 0) + (cond + ((char=? (string-ref line 0) #\tab) + (set! tab-lines (+ tab-lines 1))) + ((char=? (string-ref line 0) #\space) + (let ((n (let loop ((i 0)) + (if (and (< i (string-length line)) + (char=? (string-ref line i) #\space)) + (loop (+ i 1)) + i)))) + (when (and (> n 0) (<= n 8)) + (set! space-lines (+ space-lines 1)) + (vector-set! widths n (+ (vector-ref widths n) 1)))))))) + lines) + (if (> tab-lines space-lines) + (values #t 8) ; tabs with 8-wide tab stops + ;; Find the most common space width among 2, 3, 4, 8 + (let ((best-width 4) + (best-count 0)) + (for-each + (lambda (w) + (when (> (vector-ref widths w) best-count) + (set! best-width w) + (set! best-count (vector-ref widths w)))) + '(2 3 4 8)) + (values #f best-width))))) + +(def (dtrt-apply-indent! ed use-tabs? indent-size) + "Apply detected indentation settings to a Scintilla editor." + (send-message ed SCI_SETUSETABS (if use-tabs? 1 0) 0) + (send-message ed SCI_SETTABWIDTH indent-size 0) + (send-message ed SCI_SETINDENT indent-size 0)) + +(def (dtrt-indent-buffer! app) + "Auto-detect and apply indentation for the current buffer." + (when *global-dtrt-indent* + (let* ((ed (current-editor app)) + (text (editor-get-text ed))) + (when (> (string-length text) 0) + (let-values (((use-tabs? indent-size) (dtrt-detect-indent text))) + (dtrt-apply-indent! ed use-tabs? indent-size)))))) + (def (cmd-toggle-global-dtrt-indent app) "Toggle global dtrt-indent-mode (auto-detect indentation)." (let ((echo (app-state-echo app))) (set! *global-dtrt-indent* (not *global-dtrt-indent*)) + (when *global-dtrt-indent* + (dtrt-indent-buffer! app)) (echo-message! echo (if *global-dtrt-indent* "Global dtrt-indent ON" "Global dtrt-indent OFF")))) --- a/src/jerboa-emacs/editor-extra-tools.ss +++ b/src/jerboa-emacs/editor-extra-tools.ss @@ -1355,18 +1355,66 @@ "Indent guides on" "Indent guides off")))) -;;; --- Toggle rainbow delimiters mode --- +;;; --- Rainbow mode: colorize hex color codes inline --- (def *rainbow-mode* #f) +(def *rainbow-indicator* 4) + +(def (hex-char-value c) + "Return 0-15 for hex char, or #f." + (cond ((and (char>=? c #\0) (char<=? c #\9)) (- (char->integer c) 48)) + ((and (char>=? c #\a) (char<=? c #\f)) (+ 10 (- (char->integer c) 97))) + ((and (char>=? c #\A) (char<=? c #\F)) (+ 10 (- (char->integer c) 65))) + (else #f))) + +(def (rainbow-refresh! ed) + "Scan the buffer for #rrggbb hex color codes and highlight each with its color." + (let* ((text (editor-get-text ed)) + (len (string-length text))) + ;; Clear all rainbow indicators + (send-message ed SCI_SETINDICATORCURRENT *rainbow-indicator* 0) + (send-message ed SCI_INDICATORCLEARRANGE 0 (max 1 len)) + (send-message ed SCI_INDICSETSTYLE *rainbow-indicator* INDIC_STRAIGHTBOX) + (send-message ed SCI_INDICSETUNDER *rainbow-indicator* 1) + (send-message ed SCI_INDICSETALPHA *rainbow-indicator* 100) + ;; Scan for #rrggbb patterns + (let loop ((i 0)) + (when (< (+ i 6) len) + (if (and (char=? (string-ref text i) #\#) + (hex-char-value (string-ref text (+ i 1))) + (hex-char-value (string-ref text (+ i 2))) + (hex-char-value (string-ref text (+ i 3))) + (hex-char-value (string-ref text (+ i 4))) + (hex-char-value (string-ref text (+ i 5))) + (hex-char-value (string-ref text (+ i 6)))) + (let* ((r (+ (* 16 (hex-char-value (string-ref text (+ i 1)))) + (hex-char-value (string-ref text (+ i 2))))) + (g (+ (* 16 (hex-char-value (string-ref text (+ i 3)))) + (hex-char-value (string-ref text (+ i 4))))) + (b (+ (* 16 (hex-char-value (string-ref text (+ i 5)))) + (hex-char-value (string-ref text (+ i 6))))) + ;; Scintilla uses BGR format + (color (+ b (* 256 g) (* 65536 r)))) + (send-message ed SCI_INDICSETFORE *rainbow-indicator* color) + (send-message ed SCI_SETINDICATORCURRENT *rainbow-indicator* 0) + (send-message ed SCI_INDICATORFILLRANGE i 7) + (loop (+ i 7))) + (loop (+ i 1))))))) (def (cmd-toggle-rainbow-mode app) - "Toggle rainbow delimiter/bracket coloring mode." - (let ((echo (app-state-echo app))) + "Toggle rainbow mode — colorize #rrggbb hex color codes inline." + (let* ((echo (app-state-echo app)) + (ed (current-editor app))) (set! *rainbow-mode* (not *rainbow-mode*)) - (echo-message! echo - (if *rainbow-mode* - "Rainbow delimiters on" - "Rainbow delimiters off")))) + (if *rainbow-mode* + (begin + (rainbow-refresh! ed) + (echo-message! echo "Rainbow mode on (hex colors highlighted)")) + (begin + (let ((len (editor-get-text-length ed))) + (send-message ed SCI_SETINDICATORCURRENT *rainbow-indicator* 0) + (send-message ed SCI_INDICATORCLEARRANGE 0 (max 1 len))) + (echo-message! echo "Rainbow mode off"))))) ;;; --- Quick switch to scratch buffer --- @@ -1433,6 +1481,35 @@ (def *electric-quote-mode* #f) +(def (electric-quote-char ch ed) + "Return a curly-quote replacement string for CH at the current position in ED, + or #f if no replacement should be made. Uses the character before point to + decide opening vs closing: after whitespace/BOL → opening, otherwise → closing." + (let* ((pos (editor-get-current-pos ed)) + (prev-ch (if (> pos 0) + (send-message ed SCI_GETCHARAT (- pos 1) 0) + 0)) + (at-word-boundary? (or (= pos 0) + (= prev-ch 32) ; space + (= prev-ch 10) ; newline + (= prev-ch 13) ; CR + (= prev-ch 9) ; tab + (= prev-ch 40) ; ( + (= prev-ch 91) ; [ + (= prev-ch 123)))) ; { + (cond + ;; Double quote → curly double quotes + ((= ch 34) ; " + (if at-word-boundary? + "\x201C;" ; left double quotation mark " + "\x201D;")) ; right double quotation mark " + ;; Single quote / apostrophe → curly single quotes + ((= ch 39) ; ' + (if at-word-boundary? + "\x2018;" ; left single quotation mark ' + "\x2019;")) ; right single quotation mark ' + (else #f)))) + (def (cmd-toggle-electric-quote app) "Toggle electric quote mode (auto-convert straight quotes to smart quotes)." (let ((echo (app-state-echo app))) --- a/src/jerboa-emacs/editor-extra-tools2.ss +++ b/src/jerboa-emacs/editor-extra-tools2.ss @@ -676,9 +676,43 @@ (echo-message! (app-state-echo app) (if on "Superword mode: symbol-aware" "Superword mode off")))) +(def *glasses-indicator* 6) + +(def (glasses-refresh! ed) + "Scan buffer and mark CamelCase boundaries with a subtle underscore indicator." + (let* ((text (editor-get-text ed)) + (len (string-length text))) + ;; Clear existing indicators + (send-message ed SCI_SETINDICATORCURRENT *glasses-indicator* 0) + (send-message ed SCI_INDICATORCLEARRANGE 0 (max 1 len)) + ;; Set up indicator: thin underline at CamelCase boundaries + (send-message ed SCI_INDICSETSTYLE *glasses-indicator* INDIC_COMPOSITIONTHICK) + (send-message ed SCI_INDICSETFORE *glasses-indicator* #x888888) ; grey + (send-message ed SCI_INDICSETUNDER *glasses-indicator* 1) + (send-message ed SCI_SETINDICATORCURRENT *glasses-indicator* 0) + ;; Find CamelCase boundaries: lowercase followed by uppercase + (let loop ((i 1)) + (when (< i len) + (let ((prev (string-ref text (- i 1))) + (cur (string-ref text i))) + (when (and (char-lower-case? prev) (char-upper-case? cur)) + ;; Mark the boundary with a 1-char indicator on the uppercase char + (send-message ed SCI_INDICATORFILLRANGE i 1))) + (loop (+ i 1)))))) + +(def (glasses-clear! ed) + "Remove all glasses indicators." + (let ((len (editor-get-text-length ed))) + (send-message ed SCI_SETINDICATORCURRENT *glasses-indicator* 0) + (send-message ed SCI_INDICATORCLEARRANGE 0 (max 1 len)))) + (def (cmd-glasses-mode app) - "Toggle glasses mode (visual CamelCase separation)." - (let ((on (toggle-mode! 'glasses))) + "Toggle glasses mode (visual CamelCase separation with indicators)." + (let ((on (toggle-mode! 'glasses)) + (ed (current-editor app))) + (if on + (glasses-refresh! ed) + (glasses-clear! ed)) (echo-message! (app-state-echo app) (if on "Glasses mode enabled" "Glasses mode disabled")))) @@ -1521,17 +1555,75 @@ (number->string (string-length text)) " chars)"))))))))) ;;; --- Highlight changes tracking --- +;;; Uses Scintilla indicator #3 to mark lines modified since last save. +;;; Tracks modified line ranges and highlights them with a margin marker. (def *highlight-changes-mode* #f) +(def *highlight-changes-indicator* 3) +(def *highlight-changes-saved-text* (make-hash-table)) ; buffer-name -> text at last save + +(def (highlight-changes-snapshot! app) + "Snapshot current buffer text as the 'clean' baseline for change tracking." + (when *highlight-changes-mode* + (let* ((buf (current-buffer-from-app app)) + (ed (current-editor app)) + (text (editor-get-text ed))) + (when buf + (hash-put! *highlight-changes-saved-text* (buffer-name buf) text))))) + +(def (highlight-changes-refresh! app) + "Refresh change indicators by comparing current text against saved snapshot. + Highlights lines that differ from the baseline." + (when *highlight-changes-mode* + (let* ((ed (current-editor app)) + (buf (current-buffer-from-app app))) + (when (and ed buf) + (let* ((name (buffer-name buf)) + (saved (hash-get *highlight-changes-saved-text* name)) + (current (editor-get-text ed)) + (total-len (string-length current))) + ;; Clear existing change indicators + (send-message ed SCI_SETINDICATORCURRENT *highlight-changes-indicator* 0) + (send-message ed SCI_INDICATORCLEARRANGE 0 (max 1 total-len)) + (when (and saved (not (string=? saved current))) + ;; Set up indicator style: yellow left-edge bar + (send-message ed SCI_INDICSETSTYLE *highlight-changes-indicator* INDIC_FULLBOX) + (send-message ed SCI_INDICSETFORE *highlight-changes-indicator* #x60D0FF) ; orange + (send-message ed SCI_INDICSETALPHA *highlight-changes-indicator* 40) + (send-message ed SCI_INDICSETUNDER *highlight-changes-indicator* 1) + (send-message ed SCI_SETINDICATORCURRENT *highlight-changes-indicator* 0) + ;; Compare line by line + (let* ((saved-lines (string-split saved #\newline)) + (cur-lines (string-split current #\newline)) + (n-cur (length cur-lines))) + (let loop ((i 0) (pos 0) (sl saved-lines) (cl cur-lines)) + (when (pair? cl) + (let* ((cur-line (car cl)) + (line-len (string-length cur-line)) + (saved-line (if (pair? sl) (car sl) "")) + (changed? (not (string=? cur-line saved-line)))) + (when (and changed? (> line-len 0)) + (send-message ed SCI_INDICATORFILLRANGE pos line-len)) + ;; +1 for the newline separator + (loop (+ i 1) (+ pos line-len 1) + (if (pair? sl) (cdr sl) '()) + (cdr cl)))))))))))) (def (cmd-toggle-highlight-changes app) "Toggle tracking of modified regions." (let ((echo (app-state-echo app))) (set! *highlight-changes-mode* (not *highlight-changes-mode*)) - (echo-message! echo - (if *highlight-changes-mode* - "Highlight-changes mode enabled" - "Highlight-changes mode disabled")))) + (if *highlight-changes-mode* + (begin + (highlight-changes-snapshot! app) + (echo-message! echo "Highlight-changes mode enabled")) + (begin + ;; Clear indicators when turning off + (let* ((ed (current-editor app)) + (len (editor-get-text-length ed))) + (send-message ed SCI_SETINDICATORCURRENT *highlight-changes-indicator* 0) + (send-message ed SCI_INDICATORCLEARRANGE 0 (max 1 len))) + (echo-message! echo "Highlight-changes mode disabled"))))) ;;; --- Window layout save/restore --- --- a/src/jerboa-emacs/editor-extra-web.ss +++ b/src/jerboa-emacs/editor-extra-web.ss @@ -1118,8 +1118,8 @@ (echo-message! echo "Timer list displayed"))) ;;; --- Aggressive indent mode --- - -(def *aggressive-indent-mode* #f) +;;; *aggressive-indent-mode* and tui-aggressive-indent-line! are defined in +;;; editor-core.ss so the self-insert path can use them without circular imports. (def (cmd-toggle-aggressive-indent app) "Toggle aggressive auto-indent mode." --- a/src/jerboa-emacs/qt/app.ss +++ b/src/jerboa-emacs/qt/app.ss @@ -84,7 +84,7 @@ :jerboa-emacs/qt/menubar :jerboa-emacs/ipc :jerboa-emacs/vtscreen - (only-in :jerboa-emacs/editor-extra-web *aggressive-indent-mode*) + (only-in :jerboa-emacs/editor-core *aggressive-indent-mode*) (only-in :jerboa-emacs/debug-repl start-debug-repl! stop-debug-repl! debug-repl-bind!) :jerboa-emacs/qt/automation)