Implement Qt blink cursor mode

ober

ffb57610d937d8f26e978e4eda16516afd83225d

diff --git a/src/jerboa-emacs/qt/commands-parity5.ss b/src/jerboa-emacs/qt/commands-parity5.ss
index 93450ea..881c4ef 100644
--- a/src/jerboa-emacs/qt/commands-parity5.ss
+++ b/src/jerboa-emacs/qt/commands-parity5.ss
@@ -1329,6 +1329,20 @@
   (execute-command! app 'add-abbrev))
 (def (cmd-apheleia-format-buffer app)
   (execute-command! app 'format-buffer))
+(def (cmd-blink-cursor-mode app)
+  "Toggle Scintilla cursor blinking for the current Qt editor."
+  (let* ((ed (current-qt-editor app))
+         (echo (app-state-echo app))
+         (period (sci-send ed SCI_GETCARETPERIOD 0))
+         (enabled? (> period 0))
+         (new-period (if enabled? 0 500)))
+    (sci-send ed SCI_SETCARETPERIOD new-period 0)
+    (hash-put! *qt-toggle-states* 'blink-cursor-mode (not enabled?))
+    (hash-put! *qt-toggle-states* 'toggle-blink-cursor-mode (not enabled?))
+    (echo-message! echo
+      (if enabled?
+        "Blink cursor OFF"
+        "Blink cursor ON"))))
 (def *qt-run-with-timer-counter* 0)
 
 (def (next-run-with-timer-name!)
@@ -1432,6 +1446,8 @@
       (cons 'define-global-abbrev cmd-define-global-abbrev)
       (cons 'define-mode-abbrev cmd-define-mode-abbrev)
       (cons 'apheleia-format-buffer cmd-apheleia-format-buffer)
+      (cons 'blink-cursor-mode cmd-blink-cursor-mode)
+      (cons 'toggle-blink-cursor-mode cmd-blink-cursor-mode)
       (cons 'run-with-timer cmd-run-with-timer)
       (cons 'ibuffer-mark cmd-ibuffer-mark)
       (cons 'ibuffer-delete cmd-ibuffer-delete)
diff --git a/tests/test-qt-part2.ss b/tests/test-qt-part2.ss
index 453abd8..2ae5218 100644
--- a/tests/test-qt-part2.ss
+++ b/tests/test-qt-part2.ss
@@ -106,7 +106,7 @@
       (loop (+ i 1)
             (cons (string-append "line " (number->string i) "\n") acc)))))
 
-(display "\n=== Qt Part2 Groups 44-59 ===\n")
+(display "\n=== Qt Part2 Groups 44-60 ===\n")
 
 (test-case "group44 qt key/mouse fidelity"
   (check (qt-key-event->string QT_KEY_RETURN 0 "") => "C-m")
@@ -280,10 +280,19 @@
           (hash-remove! *so-long-buffers* (buffer-name loaded-buf)))
         (with-catch (lambda (e) #f)
           (lambda () (delete-file path)))))))
+(test-case "group60 blink-cursor-mode toggles caret period"
+  (let-values (((ed w app) (make-qt-test-app "part2-60")))
+    (sci-send ed SCI_SETCARETPERIOD 500 0)
+    (execute-command! app 'blink-cursor-mode)
+    (check (sci-send ed SCI_GETCARETPERIOD 0) => 0)
+    (check (echo-state-message (app-state-echo app)) => "Blink cursor OFF")
+    (execute-command! app 'toggle-blink-cursor-mode)
+    (check (sci-send ed SCI_GETCARETPERIOD 0) => 500)
+    (check (echo-state-message (app-state-echo app)) => "Blink cursor ON")))
 
 (newline)
 (let ([total (+ *pass* *fail*)])
-  (printf "Part2 results: ~a/~a tests passed (groups 44-59)~n" *pass* total)
+  (printf "Part2 results: ~a/~a tests passed (groups 44-60)~n" *pass* total)
   (when (> *fail* 0)
     (printf "FAILED: ~a test(s)~n" *fail*))
   (when (= *fail* 0)