# 命令与事务

先使用命令，再理解修改如何进入同一份历史记录。

命令是编辑器提供给界面的动作，例如加粗、插入内容和撤销。工具栏、快捷键与业务代码都通过命令修改同一份文档。

## 执行一个命令

安装粗体扩展或 StarterKit 后，可以调用：

```ts [立即切换粗体]
editor.commands.toggleBold()
```

它作用于当前选区。返回的布尔值表示动作是否被处理，不代表内容已经写入存储。

## 把几个动作连起来

点击工具栏后，通常希望先把焦点还给编辑器，再修改格式：

```ts [组合命令]
editor.chain().focus().toggleBold().run()
```

链中的动作使用同一个事务上下文，最后由 `run()` 提交。事务描述这一次修改包含的内容与选区变化，历史记录据此支持撤销和重做。

`run()` 返回所有动作是否都报告处理成功。它不是自动回滚开关：某个动作返回 false，不会撤回其他动作已写入共享事务的步骤。需要先判断可执行性时，使用同样的 `can().chain()`；自定义命令在拒绝时不应先修改 `tr`。

## 先检查能否执行

```ts [不修改内容的检查]
const enabled = editor.isEditable && editor.can().toggleBold()
```

`can()` 在当前状态下检查动作，不提交修改。它不检查应用的写权限，也不保证只读时返回 false。按钮通常组合 `editor.isEditable && editor.can().toggleBold()`；粗体是否“选中”则通过 `isActive('bold')` 查询。

`setEditable(false)` 控制 View 的用户输入，业务命令和协作事务仍可能写入。应用的按钮、AI、异步服务与自动化入口应在最后调用命令前检查自己的写权限、目标和当前可编辑状态，不能仅依靠隐藏按钮。

## 开发自己的命令

在扩展的 `addCommands()` 中注册动作，复用回调提供的 `commands`、`tr` 与 `dispatch`。这样直接调用、命令链和 `can()` 使用相同逻辑。检查模式里不能触发请求、弹窗或修改外部状态。

按步骤接入按钮见[工具栏教程](/build/commands)，定义新动作见[内容扩展](/build/extension)。
