diff --git a/TeXmacs/progs/generic/generic-edit.scm b/TeXmacs/progs/generic/generic-edit.scm index b5eef67813..8111199a25 100644 --- a/TeXmacs/progs/generic/generic-edit.scm +++ b/TeXmacs/progs/generic/generic-edit.scm @@ -166,6 +166,180 @@ (set-message `(concat "Use " ,sh " in order to insert a tab") "tab")))) +;; 辅助函数:定义 enumerate-tag-list +(define (enumerate-tag-list) + '(enumerate enumerate-1 enumerate-2 enumerate-3 enumerate-4)) + +;; 辅助函数:定义 itemize-tag-list +(define (itemize-tag-list) + '(itemize itemize-dot itemize-minus itemize-arrow)) + +;; 辅助函数:定义 description-tag-list +(define (description-tag-list) + '(description description-compact description-aligned description-dash description-long description-paragraphs)) + +;; 辅助函数:检查是否在有序列表环境中 +(define (in-enumerate-context?) + (not (not (tree-search-upwards (focus-tree) (lambda (node) (tree-in? node (enumerate-tag-list))))))) + +;; 辅助函数:检查是否在无序列表环境中 +(define (in-itemize-context?) + (not (not (tree-search-upwards (focus-tree) (lambda (node) (tree-in? node (itemize-tag-list))))))) + +;; 辅助函数:检查是否在描述列表环境中 +(define (in-description-context?) + (not (not (tree-search-upwards (focus-tree) (lambda (node) (tree-in? node (description-tag-list))))))) + +;; 辅助函数:获取当前列表的类型 +;; 辅助函数:获取当前列表的类型 +(define (get-list-type) + (cond + ((in-description-context?) 'description) + ((in-itemize-context?) 'itemize) + ((in-enumerate-context?) 'enumerate) + (else #f) + ) +) + +;; 辅助函数:查找包含 item 的 concat 包装和真正的 item list +(define (find-item-wrapper-and-list item) + (let ((wrapper #f) + (item-list #f)) + (let loop ((current (tree-outer item))) + (if (tree-is? current 'concat) + (begin + (set! wrapper current) + (loop (tree-outer current)) + ) + (set! item-list current) + ) + ) + (values wrapper item-list) + ) +) + +;; 辅助函数:提取 item 内容(处理 concat 包装) +(define (extract-item-content wrapper) + (if (and wrapper (> (tree-arity wrapper) 1)) + (tree-copy (tree-ref wrapper 1)) + #f + ) +) + +;; 辅助函数:在列表中移除 item(处理 concat 包装) +(define (remove-item-from-list item wrapper item-list) + (if wrapper + ;; 如果有 wrapper,移除整个 wrapper + (let ((wrapper-index (tree-index wrapper))) + (tree-remove! item-list wrapper-index 1) + ) + ;; 否则移除单个 item + (let ((item-index (tree-index item))) + (tree-remove! item-list item-index 1) + ) + ) +) + +;; 在有序和无序列表中实现缩进功能 +(tm-define (kbd-variant t forwards?) + (:require + (or + ;; 有序列表或者无序列表 + (and (or in-enumerate-context? in-itemize-context?) (tree-is? (focus-tree) 'item)) + ;; 描述列表 + (and in-description-context? (tree-is? (focus-tree) 'item*)) + ) + ) + + (display "=== kbd-variant 函数调用开始 ===\n") + (display "t: ") (display (tree->stree t)) (display "\n") + (display "forwards?: ") (display forwards?) (display "\n") + (display "focus-tree: ") (display (tree->stree (focus-tree))) (display "\n") + + (let ((item (focus-tree))) + + (display "item: ") (display (tree->stree item)) (display "\n") + + ;; 步骤 1: 查找包装和列表 + (call-with-values (lambda () (find-item-wrapper-and-list item)) + (lambda (wrapper item-list) + + (display "wrapper: ") (display (if wrapper (tree->stree wrapper) #f)) (display "\n") + (display "item-list: ") (display (if item-list (tree->stree item-list) #f)) (display "\n") + + (if (and item item-list) + (let ((item-index (if wrapper (tree-index wrapper) (tree-index item)))) + + (display "item-index: ") (display item-index) (display "\n") + + (if (> item-index 0) + (let ((prev-item (tree-ref item-list (- item-index 1)))) + + (display "prev-item: ") (display (tree->stree prev-item)) (display "\n") + + ;; 步骤 2: 提取内容 + (let ((item-content (extract-item-content wrapper))) + + (display "item-content: ") (display (if item-content (tree->stree item-content) #f)) (display "\n") + + ;; 步骤 3: 创建子列表并移动内容 + (tree-go-to prev-item :end) + (insert-return) + (let ((list-type (get-list-type))) + + (display "list-type: ") (display list-type) (display "\n") + + (if list-type + (make-tmlist list-type) + (make-tmlist 'enumerate) ; 默认使用有序列表 + ) + ) + + ;; 步骤4:拷贝内容 + (if item-content + (let ((new-item (focus-tree)) + (list-type (get-list-type))) + + (display "new-item: ") (display (tree->stree new-item)) (display "\n") + + (let ((content-stree (tree->stree item-content))) + (if (eq? list-type 'description) + (tree-set! new-item `(concat (item*), content-stree)) + (tree-set! new-item `(concat (item), content-stree)) + ) + + (display "new-item after set: ") (display (tree->stree new-item)) (display "\n") + + (tree-go-to new-item) + ) + ) + #f + ) + + ;; 步骤 5: 从原列表中移除 + + (display "Removing item from list...\n") + (remove-item-from-list item wrapper item-list) + (display "Item removed successfully\n") + ) + ) + (begin + (display "item-index is 0, no operation\n") + (noop) + ) + ) + ) + (begin + (display "item or item-list is null, no operation\n") + (noop) + ) + ) + ) + ) + ) + (display "=== kbd-variant 函数调用结束 ===\n") +) + (tm-define (kbd-variant t forwards?) (:require (and (tree-in? t '(label reference pageref eqref smart-ref)) (cursor-inside? t))) diff --git a/devel/201_84.md b/devel/201_84.md new file mode 100644 index 0000000000..3e4ad36715 --- /dev/null +++ b/devel/201_84.md @@ -0,0 +1,49 @@ +# 201_84 有序列表中实现Tab键缩进功能 + +## 如何测试 +- 创建一个有序列表(enumerate环境) +- 在列表中添加多个item +- 将光标放在第二个或后续item上 +- 按Tab键,观察当前item是否缩进成为前一个item的子列表项 +- 测试带concat包装的item是否也能正常缩进 +- 测试第一个item按Tab键是否无反应(因为没有前一个item可以缩进) + +## 2026/02/13 新增有序列表Tab键缩进功能 + +### What +在TeXmacs/progs/generic/generic-edit.scm中新增了有序列表的Tab键缩进功能。当用户在有序列表的item上按Tab键时,该item会缩进成为前一个item的子列表项。 + +### Why +在LaTeX等文档编辑器中,有序列表支持通过Tab键将列表项缩进为子列表,这是常见的编辑功能。TeXmacs此前缺少这一功能,用户体验不够友好。通过添加此功能,用户可以更方便地创建嵌套的有序列表结构。 + +### How +在generic-edit.scm中新增了以下内容: + +1. **辅助函数**: + - `enumerate-tag-list`: 定义有序列表的标签列表(enumerate, enumerate-1, enumerate-2, enumerate-3, enumerate-4) + - `in-enumerate-context?`: 检查当前是否在有序列表环境中 + - `find-item-wrapper-and-list`: 查找包含item的concat包装和真正的item list + - `extract-item-content`: 提取item内容,处理concat包装的情况 + - `remove-item-from-list`: 从列表中移除item,处理concat包装的情况 + +2. **kbd-variant函数重载**: + - 新增了kbd-variant函数的特定版本,专门处理在有序列表中按Tab键的场景 + - 该函数会检查当前是否在有序列表环境中,并且光标是否在item上 + - 当条件满足时,执行以下操作: + a. 查找item的包装和所属列表 + b. 检查是否有前一个item + c. 提取当前item的内容 + d. 在前一个item末尾创建子列表 + e. 将提取的内容移动到新创建的子列表item中 + f. 从原列表中移除当前item + +### 涉及的功能模块 +- 文档编辑功能(generic-edit.scm) +- 列表环境处理(enumerate环境) +- 键盘快捷键处理(kbd-variant) +- 树结构操作(tree操作相关函数) + +### 解决的问题 +- 解决了有序列表中无法通过Tab键创建子列表的问题 +- 提升了用户在编辑有序列表时的效率 +- 使TeXmacs的列表编辑功能更符合主流文档编辑器的使用习惯