处理块级特殊语法

林一二2022年05月22日 18:09

需求分析

基于几个我们的诉求,我们将得到几个需要满足的产品需求。

所见即所得优先,默认所见即所得

我希望有一天编辑太微的默认模式就是所见即所得模式,所以我希望能在编辑模式下使用现在只读模式的所有功能,这些功能里有一些和编辑模式是冲突的,需要用额外操作隔离开:

  • 带链接、按钮的特殊块里的点击
    • 冲突功能1:点击编辑特殊块(低频)
    • 冲突功能2:点击使用特殊块里的按钮等能力(高频)

我们可以让两种点击的区域错开,而特殊块的点击区域可能是整个特殊块,所以有一个点击区域得移出特殊块所占的范围,基于高频功能给低频功能让路的前提,我们需要把触发这个块的编辑模式的点击区域移动到特殊块的外部。

特殊块需要边编辑边预览

用户有两种可能的方式输入特殊块:

  • 逐字输入有一定创新性的块,需要展示编辑框,并希望看到实时渲染结果,预览试错
  • 使用文本片段功能自动黏贴,或者从网页上复制黏贴,不大需要编辑框,需要直接展示渲染结果

它们都要展示渲染结果(而且基于上文,需要在正文区域里展示),而区别在于是否默认展示编辑框。

在已经知道是特殊块的情况下,既然都要展示编辑框,那么编辑框和预览框的位置关系也就只有上下左右前后这几种关系了。或许可以用一个右键/悬浮菜单来让用户选择展示方式。

由于块已经转换为了特殊块,不再是段落块,所以不能在正文里面编辑了,需要在一个脱离正文的弹出窗口里编辑。

需要在特殊语法输入完成后尽快知道它是特殊块

要展示编辑框,意味着我们已经知道当前块是一个特殊块了,但编辑器的默认状态是普通段落块,所以需要根据一些条件来将段落块转换为特殊块。

其它产品只有数学公式这一个特殊块,而且还使用成对的 $$ 这样的语法结构来表示块的始末,在打出第二个$$时就将当前块转换为特殊块。但这样一是没法处理复制黏贴的情况,二是太微支持更复杂的语法,没法用「识别到$$时就转换」这样的方案。

太微所见即所得编辑器上的块,只是一个暂时的状态,因为如果关闭重开富文本编辑模式的时候,一个内容是特殊语法的段落块,就会突然变成特殊块。这和基于 JSON 存储的 Notion 等产品不同,太微是把内容存成文本的,所以是否是特殊块,还要以落到文本文件上的内容为准。所以我们应该在文本保存后,及时解析文本内容,分析当前块是否改变了性质。

  • 无额外操作方案:在保存时(做了去抖,大约2秒一次)刷新解析结果,将段落块转换为特殊块
  • 需要一次额外键盘操作:在底部弹出一个类似 / 菜单的下拉菜单,提示可以转换为显示特殊块
  • 需要一次额外鼠标操作:需要在点击左边的抓手弹出的菜单里点击「解析特殊块」按钮来刷新本块的展示
  • 无开发量但是难为用户的方案:退出重进刷新一下

交互方案

  1. 逐字输入(边输入边预览)
    1. 先通过 / 菜单将当前块转换为特定的特殊块
    2. 这将在文本中创建出一个微件或宏或公式的骨架内容,因为编辑器创建出特殊块后就会在2s后序列化出相应的文本
    3. 这种命令在插入文本后要告诉编辑器进入实时预览模式,在组件边上(默认在下方)展示一个文本输入框
      1. 在预览中实时展示结果,或提供报错信息
      2. 文本输入框里按 ⏎ 可以软换行;按 ⇧+⏎ 没有特殊效果,也还是软换行;按 ⌘+⏎ 真换行,立刻离开当前块,切换到下方的段落,关闭输入框,仅剩预览
  2. 逐字输入(不立即预览)
    1. 直接输入特殊块的维基语法,此时块一直保持为段落块
    2. 通过 ⇧+⏎ 来软换行,保持在同一块里输入多行文本
    3. 最终通过 ⏎ 或 ⌃/⌘+⏎ 真换行,此时尝试解析上一个段落,并转换为相应特殊块
    4. 立即展示相应特殊块的渲染结果,例如展示用户刚输入的微件的渲染效果
  3. 插入文本片段(不预览,直接转换)
    1. 通过 / 菜单插入文本片段,此时块一直保持为段落块
    2. 在创建完成后,对这个段落的文本信息运行语法检测,自动将结果转换成真正的特定的块的 AST 替换上来,例如变成微件块
  4. 通过方向键或菜单打开编辑模式
    1. 在预览块的下方展示文本输入框
    2. 光标放到文本输入框的开头
    3. 未来也会加上拖动低代码编辑器

文本输入框

  • 不需要关闭按钮,点击编辑区域外部,编辑器失去焦点后直接关闭编辑,只保留预览
  • 含有位置调整按钮,可以切换编辑区域到组件上方或左右,甚至变成悬浮框然后用标题来拖动。
  • 从预览模式切换到编辑模式时,取消主编辑器里的选区,在新创建的文本输入框里的开头处创建光标
  • 移动端上,像 Notion 一样在屏幕底部展示预览和输入框;电脑上在编辑器内预览的底部直接悬浮展示输入框

简化编辑模式交互

宏和微件

在编辑宏、微件时,其实其源码包含很多语义噪声,例如微件的 <$ ,宏的 << 都只是为解析器服务的,而人类并不需要编辑、理解、修改它们。所以我们可以提供一个不展示这些无用字符的界面来编辑宏和微件。

可以在打开宏和微件的编辑界面时,在源码编辑框上方标题区域展示显示块类别,在标题区域上可以放置一些表单元素,以便快速修改块中的参数,甚至修改微件名、宏名。

下方依然展示源码,以便用户排查错误情况,或用编辑器快捷键做一些表单不方便做的快速修改。

嵌入

Notion 只提供了基本嵌入功能,允许将其它块拖入嵌入块中,也可以直接编辑嵌入块。但在太微里,嵌入可能是通过列表微件循环批量创建的,也就是嵌入是微件的子元素,编辑时只能打开微件的编辑界面;嵌入也有可能带有模板,使得最终展示的结果不适合编辑。

所以在太微里,可能可以为基本嵌入提供简化交互,但更多高级嵌入只能用源码模式来编辑。

图形化领域特定语言

或许可以用 google/blockly 这种 Sketch 图形化方式来展示源码的 AST,并有来自插槽的可供性和类型限制。

块目录

点击左侧的抓手可以打开块目录,也可以通过快捷键 ⌃/⌘+/ 来打开当前块的目录。

进入编辑模式

在特殊块上打开目录时,默认选中「编辑模式」菜单项,其它块里则是默认选中搜索框。

Code
!! 需求分析

基于几个我们的诉求,我们将得到几个需要满足的产品需求。

!!! 所见即所得优先,默认所见即所得

我希望有一天编辑太微的默认模式就是所见即所得模式,所以我希望能在编辑模式下使用现在只读模式的所有功能,这些功能里有一些和编辑模式是冲突的,需要用额外操作隔离开:

* 带链接、按钮的特殊块里的点击
** 冲突功能1:点击编辑特殊块(低频)
** 冲突功能2:点击使用特殊块里的按钮等能力(高频)


我们可以让两种点击的区域错开,而特殊块的点击区域可能是整个特殊块,所以有一个点击区域得移出特殊块所占的范围,基于高频功能给低频功能让路的前提,我们需要把触发这个块的编辑模式的点击区域移动到特殊块的外部。

!!! 特殊块需要边编辑边预览

用户有两种可能的方式输入特殊块:

* 逐字输入有一定创新性的块,需要展示编辑框,并希望看到实时渲染结果,预览试错
* 使用文本片段功能自动黏贴,或者从网页上复制黏贴,不大需要编辑框,需要直接展示渲染结果

它们都要展示渲染结果(而且基于上文,需要在正文区域里展示),而区别在于是否默认展示编辑框。

在已经知道是特殊块的情况下,既然都要展示编辑框,那么编辑框和预览框的位置关系也就只有上下左右前后这几种关系了。或许可以用一个右键/悬浮菜单来让用户选择展示方式。

由于块已经转换为了特殊块,不再是段落块,所以不能在正文里面编辑了,需要在一个脱离正文的弹出窗口里编辑。

!!! 需要在特殊语法输入完成后尽快知道它是特殊块

要展示编辑框,意味着我们已经知道当前块是一个特殊块了,但编辑器的默认状态是普通段落块,所以需要根据一些条件来将段落块转换为特殊块。

其它产品只有数学公式这一个特殊块,而且还使用成对的 `$$` 这样的语法结构来表示块的始末,在打出第二个`$$`时就将当前块转换为特殊块。但这样一是没法处理复制黏贴的情况,二是太微支持更复杂的语法,没法用「识别到`$$`时就转换」这样的方案。

太微所见即所得编辑器上的块,只是一个暂时的状态,因为如果关闭重开富文本编辑模式的时候,一个内容是特殊语法的段落块,就会突然变成特殊块。这和基于 JSON 存储的 Notion 等产品不同,太微是把内容存成文本的,所以是否是特殊块,还要以落到文本文件上的内容为准。所以我们应该在文本保存后,及时解析文本内容,分析当前块是否改变了性质。

* 无额外操作方案:在保存时(做了去抖,大约2秒一次)刷新解析结果,将段落块转换为特殊块
* 需要一次额外键盘操作:在底部弹出一个类似 `/` 菜单的下拉菜单,提示可以转换为显示特殊块
* 需要一次额外鼠标操作:需要在点击左边的抓手弹出的菜单里点击「解析特殊块」按钮来刷新本块的展示
* 无开发量但是难为用户的方案:退出重进刷新一下

!! 交互方案

# 逐字输入(边输入边预览)
## 先通过 `/` 菜单将当前块转换为特定的特殊块
## 这将在文本中创建出一个微件或宏或公式的骨架内容,因为编辑器创建出特殊块后就会在2s后序列化出相应的文本
## 这种命令在插入文本后要告诉编辑器进入实时预览模式,在组件边上(默认在下方)展示一个文本输入框
### 在预览中实时展示结果,或提供报错信息
### 文本输入框里按 ⏎ 可以软换行;按 ⇧+⏎ 没有特殊效果,也还是软换行;按 ⌘+⏎ 真换行,立刻离开当前块,切换到下方的段落,关闭输入框,仅剩预览
# 逐字输入(不立即预览)
## 直接输入特殊块的维基语法,此时块一直保持为段落块
## 通过 ⇧+⏎ 来软换行,保持在同一块里输入多行文本
## 最终通过 ⏎ 或 ⌃/⌘+⏎ 真换行,此时尝试解析上一个段落,并转换为相应特殊块
## 立即展示相应特殊块的渲染结果,例如展示用户刚输入的微件的渲染效果
# 插入文本片段(不预览,直接转换)
## 通过 `/` 菜单插入文本片段,此时块一直保持为段落块
## 在创建完成后,对这个段落的文本信息运行语法检测,自动将结果转换成真正的特定的块的 AST 替换上来,例如变成微件块
# 通过方向键或菜单打开编辑模式
## 在预览块的下方展示文本输入框
## 光标放到文本输入框的开头
## 未来也会加上拖动低代码编辑器 


!!! 文本输入框

* 不需要关闭按钮,点击编辑区域外部,编辑器失去焦点后直接关闭编辑,只保留预览
* 含有位置调整按钮,可以切换编辑区域到组件上方或左右,甚至变成悬浮框然后用标题来拖动。
* 从预览模式切换到编辑模式时,取消主编辑器里的选区,在新创建的文本输入框里的开头处创建光标
* 移动端上,像 Notion 一样在屏幕底部展示预览和输入框;电脑上在编辑器内预览的底部直接悬浮展示输入框

!!!! 简化编辑模式交互

!!!!! 宏和微件

在编辑宏、微件时,其实其源码包含很多语义噪声,例如微件的 `<$` ,宏的 `<<` 都只是为解析器服务的,而人类并不需要编辑、理解、修改它们。所以我们可以提供一个不展示这些无用字符的界面来编辑宏和微件。

可以在打开宏和微件的编辑界面时,在源码编辑框上方标题区域展示显示块类别,在标题区域上可以放置一些表单元素,以便快速修改块中的参数,甚至修改微件名、宏名。

下方依然展示源码,以便用户排查错误情况,或用编辑器快捷键做一些表单不方便做的快速修改。

!!!!! 嵌入

Notion 只提供了基本嵌入功能,允许将其它块拖入嵌入块中,也可以直接编辑嵌入块。但在太微里,嵌入可能是通过列表微件循环批量创建的,也就是嵌入是微件的子元素,编辑时只能打开微件的编辑界面;<a >嵌入也有可能带有模板</a>,使得最终展示的结果不适合编辑。

所以在太微里,可能可以为基本嵌入提供简化交互,但更多高级嵌入只能用源码模式来编辑。

!!!!! 图形化领域特定语言

或许可以用 <a >google/blockly</a> 这种 Sketch 图形化方式来展示源码的 AST,并有来自插槽的可供性和类型限制。

!!! 块目录

点击左侧的抓手可以打开块目录,也可以通过快捷键 ⌃/⌘+`/` 来打开当前块的目录。

!!!! 进入编辑模式

在特殊块上打开目录时,默认选中「编辑模式」菜单项,其它块里则是默认选中搜索框。