Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added TeXmacs/misc/images/tutorial/stem-image.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
22 changes: 12 additions & 10 deletions TeXmacs/plugins/tutorial/data/first-launch-tutorial.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
"offset-x": 0,
"offset-y": 0,
"media-path": "",
"bottom-text": "这是 Liii STEM 的主工作区。教程会依次介绍几个核心功能,帮助你快速上手。",
"bottom-text": "这是 Liii STEM 的主工作区。教程会依次介绍几个核心功能,帮助您快速上手。",
"target-id": "",
"placement": "bottom",
"highlight-padding": 0,
Expand All @@ -20,7 +20,7 @@
{
"id": "login",
"title": "登录账户",
"top-text": "点击这里登录你的账户,解锁更多高级功能和扩展能力。",
"top-text": "点击这里登录您的账户,解锁更多高级功能和扩展能力。",
"bubble-size": "medium",
"offset-x": -20,
"offset-y": 0,
Expand All @@ -35,31 +35,33 @@
{
"id": "magic-paste",
"title": "魔法粘贴",
"top-text": "在编辑区使用 Ctrl+V 粘贴内容时,粘贴板会根据内容类型自动选择合适的格式,让你的排版更加高效。",
"top-text": "魔法粘贴可以自动识别剪贴板中的内容类型,并尽可能保留网页内容的结构、标题层级、列表样式和公式表达,让外部内容进入文档后依然便于继续编辑与排版。",
"bubble-size": "large",
"offset-x": 500,
"offset-y": 0,
"media-path": "../../../misc/images/tutorial/test.gif",
"bottom-text": "",
"media-path": ":/tutorial/test.gif",
"bottom-text": "<b>系统已经为您打开了一个新的空白文档,并将一段网页内容复制到了剪贴板。</b>请在编辑区中使用 <b>Ctrl+Shift+V</b>(Windows / Linux)或 <b>Command+Shift+V</b>(macOS)进行粘贴,体验魔法粘贴对网页内容结构的自动识别与导入。完成本步操作后,才可以进入下一步。",
"target-id": "editorArea",
"placement": "top",
"highlight-padding": 12,
"on-enter": "",
"require-action": "magic-paste",
"on-enter": "(tutorial-prepare-magic-paste-demo)",
"skip-if-missing": true
},
{
"id": "ocr",
"title": "OCR 文字识别",
"top-text": "如果你的剪贴板中包含图片或PDF内容,编辑区会自动提示是否需要提取其中的文字,让你快速将扫描文档或截图转换为可编辑文本。",
"top-text": "如果您的剪贴板中包含图片内容,软件可以通过快捷键触发 OCR ,提取其中的文字,让您快速将截图转换为可编辑文本;您也可以在插入图片后,通过图片悬浮菜单上的 OCR 按钮发起识别。",
"bubble-size": "large",
"offset-x": 500,
"offset-y": 0,
"media-path": "../../../misc/images/tutorial/test.gif",
"bottom-text": "",
"media-path": ":/tutorial/test.gif",
"bottom-text": "系统已经为您打开了一个包含图片的文档,且将一张图片放入了您的剪贴板,您可以在编辑区中使用 <b>Ctrl+Alt+V</b>(Windows / Linux)或 <b>Command+Option+V</b>(macOS)触发 OCR 识别,也可以用鼠标点击悬浮菜单中的按钮触发 OCR 识别,图片中的文字将被快速提取为文档中的可编辑文本。完成本步操作后,才可以进入下一步。",
"target-id": "editorArea",
"placement": "top",
"highlight-padding": 12,
"on-enter": "",
"require-action": "ocr-paste",
"on-enter": "(tutorial-prepare-ocr-demo)",
"skip-if-missing": true
}
]
Expand Down
14 changes: 14 additions & 0 deletions TeXmacs/plugins/tutorial/data/ocr-demo.tmu

Large diffs are not rendered by default.

29 changes: 29 additions & 0 deletions TeXmacs/plugins/tutorial/data/zhihu-magic-paste-demo.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="utf-8" />
<title>知乎回答示例 - 魔法粘贴体验</title>
</head>
<body>
<main>
<h1>为什么数学公式在排版软件里经常显得难编辑?</h1>
<p>因为大多数编辑器只擅长处理纯文本,而不擅长处理结构化内容。</p>
<p>当一段内容同时包含标题、正文、列表、强调和公式时,编辑器需要理解它的语义结构,而不只是把它当成一串字符。</p>
<blockquote>
<p>真正高效的编辑体验,不是“把格式补回来”,而是“粘贴进来时就尽量保留结构”。</p>
</blockquote>
<h2>一个简单例子</h2>
<p>如果原文里有如下结论:</p>
<p>对于任意实数 <strong>a</strong> 与 <strong>b</strong>,都有</p>
<p>$$ (a+b)^2 = a^2 + 2ab + b^2 $$</p>
<p>那么理想的粘贴结果应该尽量保留:</p>
<ul>
<li>标题层级</li>
<li>段落结构</li>
<li>强调样式</li>
<li>公式表达</li>
</ul>
<p>这也是“魔法粘贴”存在的意义:让来自网页、问答平台和 AI 对话的内容,进入文档后仍然尽量可编辑、可继续排版。</p>
</main>
</body>
</html>
35 changes: 33 additions & 2 deletions TeXmacs/plugins/tutorial/progs/init-tutorial.scm
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,36 @@
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(tm-define (tutorial-open-something)
(display* "tutorial enter editor step\n"))
(define (tutorial-magic-paste-demo-path)
(unix->url "$TEXMACS_PATH/plugins/tutorial/data/zhihu-magic-paste-demo.html"))

(define tutorial-magic-paste-demo-opened? #f)
(define tutorial-ocr-demo-opened? #f)

(define (tutorial-ocr-demo-document-path)
(unix->url "$TEXMACS_PATH/plugins/tutorial/data/ocr-demo.tmu"))

(define (tutorial-ocr-demo-image-path)
(unix->url "$TEXMACS_PATH/misc/images/tutorial/stem-image.png"))

(tm-define (tutorial-notify-action action)
(cpp-set-preference "tutorial:last-action" action))

(tm-define (tutorial-prepare-magic-paste-demo)
(let* ((html-path (tutorial-magic-paste-demo-path))
(html (utf8->cork (string-load html-path)))
(old-export (clipboard-get-export)))
(if (not tutorial-magic-paste-demo-opened?)
(begin
(new-document)
(set! tutorial-magic-paste-demo-opened? #t)))
(clipboard-set-export "verbatim")
(clipboard-set "primary" html)
(clipboard-set-export old-export)))
Comment on lines +28 to +38
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 剪贴板导出模式恢复不能抵御异常

clipboard-set-export "verbatim"clipboard-set-export old-export 之间的 clipboard-set "primary" html 若抛出异常,导出模式将保持 "verbatim" 而无法恢复,影响后续粘贴操作。建议使用 dynamic-wind 保证清理代码必定执行:

(dynamic-wind
  (lambda () (clipboard-set-export "verbatim"))
  (lambda () (clipboard-set "primary" html))
  (lambda () (clipboard-set-export old-export)))


(tm-define (tutorial-prepare-ocr-demo)
(if (not tutorial-ocr-demo-opened?)
(begin
(load-document (tutorial-ocr-demo-document-path))
(set! tutorial-ocr-demo-opened? #t)))
(graphics-file-to-clipboard (tutorial-ocr-demo-image-path)))
13 changes: 10 additions & 3 deletions TeXmacs/progs/generic/generic-edit.scm
Original file line number Diff line number Diff line change
Expand Up @@ -521,7 +521,9 @@ ocr-paste
(with data
(parse-texmacs-snippet (tree->string (tree-ref (clipboard-get "primary") 1)))
(when (tree-is? (tree-ref data 0) 'image)
(ocr-to-latex-by-cursor data))))
(ocr-to-latex-by-cursor data)
(when (defined? 'tutorial-notify-action)
(tutorial-notify-action "ocr-paste")))))

#|
image-and-ocr-paste
Expand All @@ -539,7 +541,9 @@ image-and-ocr-paste
(kbd-return)
(when (not (defined? 'ocr-to-latex-by-cursor))
(use-modules (liii ocr)))
(ocr-to-latex-by-cursor data))))
(ocr-to-latex-by-cursor data)
(when (defined? 'tutorial-notify-action)
(tutorial-notify-action "ocr-paste")))))

(tm-define (paste-as-html)
(with source-format (qt-clipboard-format)
Expand Down Expand Up @@ -626,7 +630,10 @@ TODO: 在文本模式中,可以自动识别剪贴板中的内容,并智能
(clipboard-paste-import "code" "primary"))
((== mode "math")
(clipboard-paste-import "latex" "primary"))
(else (smart-format-paste))))))
(else (smart-format-paste)))))
(when (and (defined? 'tutorial-notify-action)
(not (string-starts? (qt-clipboard-format) "image")))
(tutorial-notify-action "magic-paste")))

(tm-define (any-image-context?)
(tree-innermost
Expand Down
47 changes: 43 additions & 4 deletions devel/222_68.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
+ `media-path`:正文中间图片或 GIF 路径,可为空
+ `bottom-text`:正文下方文字,可为空
+ `on-enter`:进入该步骤时执行一次的 Scheme 命令,可为空
+ `require-action`:要求用户先完成某个动作后才能进入下一步,可为空
+ `target-id`:步骤要高亮的目标区域,可为空;为空时仅显示说明卡片,不绘制高亮区域
+ `placement`:说明卡片相对高亮区域的位置,可选值为 `auto / top / bottom / left / right`
+ `bubble-size`:说明卡片尺寸,可选值为 `small / medium / large`,未设置时默认为 `medium`
Expand All @@ -37,6 +38,7 @@
+ 调整步骤顺序:直接修改 `steps` 数组中的对象顺序
+ 修改步骤文案:修改 `title`、`top-text`、`bottom-text`
+ 进入时执行动作:修改 `on-enter`
+ 控制下一步解锁条件:修改 `require-action`
+ 修改高亮目标:修改 `target-id`
+ 修改卡片位置:修改 `placement`
+ 修改卡片尺寸:修改 `bubble-size`
Expand Down Expand Up @@ -68,6 +70,7 @@
+ 步骤支持配置卡片偏移量 `offset-x` / `offset-y`
+ 首次启动教程第三步、第四步接入了 GIF 演示图
+ 第二步卡片位置从 `left` 调整为 `bottom`,避免默认布局下更容易贴边
+ 第三步、第四步支持“完成操作后才允许下一步”的约束

### Why

Expand All @@ -77,13 +80,14 @@
+ 欢迎页实际上不需要高亮任何区域,却被迫绑定一个大范围目标
+ 某些步骤需要更大的卡片去承载 GIF,而有些步骤只需要较小卡片
+ 仅依赖 `placement` 的四向布局还不够,部分步骤需要做像素级微调
+ 第三步和第四步属于操作体验步骤,如果用户没有真正完成粘贴或 OCR,就不应允许直接跳到后续步骤

这些问题都不应该通过继续硬编码 UI 分支来解决,更合适的方式是把能力下沉到教程配置模型中。

### How

+ `TutorialStepConfig` 中新增 `bubbleSize`、`offsetX`、`offsetY` 字段,默认值分别为 `medium`、`0`、`0`
+ `TutorialConfigLoader::loadFlow()` 读取步骤时,额外解析 `bubble-size`、`offset-x`、`offset-y`
+ `TutorialStepConfig` 中新增 `bubbleSize`、`offsetX`、`offsetY`、`requiredAction` 字段,默认值分别为 `medium`、`0`、`0`、空字符串
+ `TutorialConfigLoader::loadFlow()` 读取步骤时,额外解析 `bubble-size`、`offset-x`、`offset-y`、`require-action`
+ `bubble-size` 当前支持三档:`small / medium / large`
+ `TutorialBubble::setStep()` 根据 `bubble-size` 切换卡片固定宽度和媒体区域尺寸:
`small` 对应 `300` 宽和 `240x144` 媒体区
Expand All @@ -92,11 +96,17 @@
+ `TutorialBubble::setStep()` 在 `media-path` 为空时显式隐藏 `m_mediaLabel`,避免空白占位
+ `TutorialEngine::showStep()` 对 `target-id` 为空的步骤直接走“仅展示卡片、清空高亮”的分支
+ `TutorialOverlay::bubbleRectForPlacement()` 在最终气泡坐标上叠加 `offset-x` / `offset-y`
+ `TutorialEngine` 为声明了 `require-action` 的步骤禁用“下一步”按钮,并轮询临时偏好 `tutorial:last-action`;动作完成后再解锁
+ `TeXmacs/plugins/tutorial/progs/init-tutorial.scm` 中新增 `tutorial-notify-action`
+ `TeXmacs/progs/generic/generic-edit.scm` 中的 `kbd-magic-paste`、`ocr-paste`、`image-and-ocr-paste` 在实际执行后会上报 tutorial action
+ `src/Plugins/Qt/QTMImagePopup.cpp` 中图片悬浮菜单的 OCR 按钮也会上报 `ocr-paste`,因此第四步既支持快捷键,也支持悬浮按钮解锁
+ `TeXmacs/plugins/tutorial/data/first-launch-tutorial.json` 当前已使用这些能力:
第一页 `target-id` 置空,用作无高亮欢迎页
第二页 `placement` 调整为 `bottom`
第三页和第四页的 `bubble-size` 调整为 `large`
第三页和第四页接入 `TeXmacs/misc/images/tutorial/test.gif`
第三页和第四页接入 Qt 资源路径 `:/tutorial/test.gif`
第三页设置 `require-action = "magic-paste"`
第四页设置 `require-action = "ocr-paste"`

## 2026/04/14 首次启动教程当前配置

Expand All @@ -119,7 +129,36 @@

+ `placement + bubble-size + offset-x + offset-y`
+ `target-id=""` 的无高亮欢迎页
+ `media-path` 指向相对路径 GIF 的演示步骤
+ `media-path` 指向 Qt 资源路径 GIF 的演示步骤
+ `on-enter + require-action` 的操作型步骤

## 2026/04/14 首次启动教程操作型步骤

### What

当前第三步与第四步不再只是“展示说明”,而是具备明确的“先操作,后放行”行为:

+ 第三步进入时打开新的无标题文档,并准备一份 mock HTML 到剪贴板
+ 第四步进入时打开 OCR 示例文档,并准备一张示例图片到剪贴板
+ 两步都只有在用户实际完成目标操作后,才允许点击“下一步”

### How

+ 第三步 `on-enter` 调用 `(tutorial-prepare-magic-paste-demo)`:
第一次进入时 `new-document`
读取 `TeXmacs/plugins/tutorial/data/zhihu-magic-paste-demo.html`
经 `utf8->cork` 后放入剪贴板
+ 第四步 `on-enter` 调用 `(tutorial-prepare-ocr-demo)`:
第一次进入时加载 `TeXmacs/plugins/tutorial/data/ocr-demo.tmu`
将 `TeXmacs/misc/images/tutorial/stem-image.png` 放入剪贴板
+ 第三步当前认可的完成入口:
`Ctrl+Shift+V`(Windows / Linux)
`Command+Shift+V`(macOS)
+ 第四步当前认可的完成入口:
`Ctrl+Alt+V`(Windows / Linux)
`Command+Option+V`(macOS)
图片悬浮菜单上的 OCR 按钮
+ 第三步和第四步的文案中已经显式提示“完成本步操作后,才可以进入下一步”

## 2026/04/03 聚光灯教程基础设施

Expand Down
5 changes: 4 additions & 1 deletion src/Plugins/Qt/QTMImagePopup.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,11 @@ QTMImagePopup::QTMImagePopup (QWidget* parent, qt_simple_widget_rep* owner)
call ("set-image-alignment", current_tree, "center");
else if (button == rightBtn)
call ("set-image-alignment", current_tree, "right");
else if (button == ocrBtn)
else if (button == ocrBtn) {
call ("ocr-to-latex-by-image", current_tree);
eval ("(when (defined? 'tutorial-notify-action) "
"(tutorial-notify-action \"ocr-paste\"))");
Comment on lines 73 to +75
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 OCR 教程通知无条件触发

点击浮动菜单中的 OCR 按钮时,无论 ocr-to-latex-by-image 是否真正识别成功,tutorial-notify-action "ocr-paste" 都会被发送,用户因此可以在未完成有效 OCR 的情况下推进教程步骤。而键盘路径(generic-edit.scm 中的 ocr-paste)只有在剪贴板确实包含图片且处理成功时才发送通知,两者行为不一致。

建议让通知仅在 ocr-to-latex-by-image 执行成功后才发送,或在 Scheme 侧的 ocr-to-latex-by-image 内部统一处理通知,与 ocr-to-latex-by-cursor 的模式保持一致。

}
current_align=
as_string (call ("get-image-alignment", current_tree));
});
Expand Down
Loading
Loading