对照着看
两个编辑器初始内容相同:四行裸文本。试着在两个编辑器里都框选这四行, 然后点工具栏上的 无序列表 按钮。
- 左边(main):旧实现只动第一行, 剩下三行不动,结果是「一行列表 + 三行散落段落」。
- 右边(feat):新实现把选区当成一个整体, 四行要么全加
-,要么全去;再点一次就整段消失。
也可以试试混合态:手动把其中一行改成1. ,再点无序列表。旧版会留下1. 行,新版会把它剥掉、统一成- 。
思路:把整段当成一个动作
新版把选区里的所有行(包含跨行的范围)作为整体来 toggle, 方向遵循「全有则去,否则加」:
- 选区里非空的行已经全都有同种 marker(比如全是
-),就整段去掉。 - 只要有一行没有、或者 marker 类型不一致,就把整段统一加上。
- 有序模式从 1 开始重编;选区里夹的空白行直接跳过、保留为空。
- 类型相反的 marker 现场转换,不堆叠。
伪代码
const lines = getSelectedLines(doc, from, to)
const nonEmpty = lines.filter((l) => l.line.trim().length > 0)
const ownMarker = mode === "ordered" ? /^\d+\.\s/ : /^[-*+]\s/
// 全有则去,否则加
const allMarked = nonEmpty.length > 0 &&
nonEmpty.every((l) => ownMarker.test(l.line))
const shouldRemove = allMarked
let counter = 1
const transformed = lines.map((l) => {
if (l.line.trim().length === 0) return l.line
if (shouldRemove) return l.line.replace(ownMarker, "")
const stripped = l.line
.replace(ownMarker, "")
.replace(/^[-*+]\s/, "")
.replace(/^\d+\.\s/, "")
return mode === "ordered"
? `${counter++}. ${stripped}`
: `- ${stripped}`
})