diff --git a/TeXmacs/progs/generic/generic-kbd.scm b/TeXmacs/progs/generic/generic-kbd.scm index 907ad63f95..c1da345ad2 100644 --- a/TeXmacs/progs/generic/generic-kbd.scm +++ b/TeXmacs/progs/generic/generic-kbd.scm @@ -301,6 +301,17 @@ ("std 5" (switch-to-view-index 4)) ("std 6" (switch-to-view-index 5)) + ;; 切换标签页:Ctrl+Shift+[ / ](macOS:Cmd+Shift+[ / ]),见 #4685。 + ;; Qt 对 Shift+[ 上报的 key 随平台/版本而异,C++ 侧(qt_utilities.cpp + ;; from_key_press_event)归一结果有三种:Windows/Linux 为 "C-{";macOS 为 + ;; "M-S-[" 或 "M-S-{"。三种写法都绑,保证各平台一致。 + ("std {" (switch-to-previous-view)) + ("std }" (switch-to-next-view)) + ("std S-[" (switch-to-previous-view)) + ("std S-]" (switch-to-next-view)) + ("std S-{" (switch-to-previous-view)) + ("std S-}" (switch-to-next-view)) + ;; not yet implemented ;; ("std t" (add-tab)) ;; ("std tab" (next-tab)) diff --git a/TeXmacs/progs/texmacs/texmacs/tm-files-test.scm b/TeXmacs/progs/texmacs/texmacs/tm-files-test.scm index 58899b7654..42d61d4cb2 100644 --- a/TeXmacs/progs/texmacs/texmacs/tm-files-test.scm +++ b/TeXmacs/progs/texmacs/texmacs/tm-files-test.scm @@ -142,6 +142,33 @@ ) ;let* ) ;define +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Tests for tab cycling (4685): Ctrl/Cmd+Shift+[ / ] +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(define (test-cyclic-view-index) + ;; 向前、向后、两端回绕 + (check (cyclic-view-index 0 1 3) => 1) + (check (cyclic-view-index 2 1 3) => 0) + (check (cyclic-view-index 1 -1 3) => 0) + (check (cyclic-view-index 0 -1 3) => 2) + ;; 只有一个 tab:原地不动 + (check (cyclic-view-index 0 1 1) => 0) + (check (cyclic-view-index 0 -1 1) => 0) + ;; 空列表:无效 + (check (cyclic-view-index 0 1 0) => #f) +) ;define + +(define (test-switch-view-round-trip) + ;; headless 下 tab 数不定(可能只有 1 个)。不依赖具体数量: + ;; 向后再向前必须回到原 view,且两次调用都不得抛错。 + (let ((v (current-view))) + (switch-to-next-view) + (switch-to-previous-view) + (check (== (current-view) v) => #t) + ) ;let +) ;define + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Test entry point ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; @@ -154,5 +181,7 @@ (test-scratch-buffer-title-stem) (test-scratch-buffer-title-old-and-new-stamp) (test-scratch-buffer-title-legacy-one-underscore-this-week) + (test-cyclic-view-index) + (test-switch-view-round-trip) (check-report) ) ;tm-define diff --git a/TeXmacs/progs/texmacs/texmacs/tm-files.scm b/TeXmacs/progs/texmacs/texmacs/tm-files.scm index fa8270dc4c..a77a8e689b 100644 --- a/TeXmacs/progs/texmacs/texmacs/tm-files.scm +++ b/TeXmacs/progs/texmacs/texmacs/tm-files.scm @@ -32,7 +32,7 @@ ) ;only ) ;import (import (only (srfi srfi-1) find)) -(import (only (srfi srfi-1) remove take)) +(import (only (srfi srfi-1) remove take list-index)) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Remember last save/open directory @@ -368,6 +368,36 @@ ) ;let* ) ;tm-define +;; 环形下标:从 idx 偏移 delta,在 [0, len) 内回绕;len <= 0 时返回 #f。 +;; 抽成纯函数便于 headless 单测(见 tm-files-test.scm)。 + +(tm-define (cyclic-view-index idx delta len) + (and (> len 0) (modulo (+ idx delta) len)) +) ;tm-define + +(tm-define (switch-to-view-offset delta) + (:synopsis "Switch to the tab @delta positions away from the current one, wrapping around") + (let* ((lst (tabpage-list #t)) + (len (length lst)) + (idx (list-index (lambda (v) (== v (current-view))) lst)) + ) ; + ;; 当前 view 不在本窗口 tab 列表(如独立弹出的辅助 view)或只有一个 tab 时不动。 + (when (and idx (> len 1)) + (switch-to-view-index (cyclic-view-index idx delta len)) + ) ;when + ) ;let* +) ;tm-define + +(tm-define (switch-to-next-view) + (:synopsis "Switch to the next tab, wrapping around to the first one") + (switch-to-view-offset 1) +) ;tm-define + +(tm-define (switch-to-previous-view) + (:synopsis "Switch to the previous tab, wrapping around to the last one") + (switch-to-view-offset -1) +) ;tm-define + (tm-define (ensure-default-view) (:synopsis "Switch to parent window if not in default view") (if (not (is-view-type? (current-view) "default")) (switch-to-parent-window))