- 桌面应用
【免费下载链接】QOwnNotes
QOwnNotes is a plain-text file notepad and todo-list manager with Markdown support and Nextcloud / ownCloud integration.
QOwnNotes 在笔记编辑器中集成了Markdown 语言服务器协议(LSP)客户端,使纯文本笔记编辑器获得诊断(lint)、代码动作(quick fix)、补全和文档格式化等"IDE 级"编辑能力。本文以 QOwnNotes 官方文档为主体,结合仓库内 markdownlspclient.cpp、markdownlspdocumenttracker.cpp、markdownlspsettingswidget.cpp 等源码,完整讲解 LSP 服务器的安装、配置、底层协议流程与日常使用,读完后你可以将 Marksman 或 Rumdl 接入编辑器,并用上彩色波浪下划线、右键快速修复、wiki 链接补全和格式化功能。
Markdown LSP 能带来什么
启用 Markdown LSP 后,QOwnNotes 编辑器在保留原有纯文本 Markdown 编辑体验的同时,获得以下增强能力:
- 对检测到的 Markdown 问题与规则违规显示彩色波浪下划线(不同严重级别对应不同颜色)
- 在右键上下文菜单中为诊断提供Code Actions(服务器建议的快速修复)
- 提供忽略规则(Ignore rule)操作,可永久屏蔽某条具体诊断规则
- 提供补全弹窗,支持笔记链接及服务器给出的其他建议(例如与 Marksman 配合的 wiki-link 补全)
- 通过上下文菜单提供Format Document(格式化文档)与Format Selection(格式化选区)操作
- 支持增量文档同步,与服务器通信更高效
- 提供详细日志模式,便于调试服务器通信
这些能力全部发生在QOwnNotesMarkdownTextEdit编辑器组件内部(qownnotesmarkdowntextedit.cpp),笔记内容仍以纯文本形式存储,不引入任何私有格式。
支持的 LSP 服务器
仓库内置了两款开箱即用的 Markdown LSP 服务器,分别覆盖"导航补全"与"lint 规则"两类场景:
| 服务器 | 命令 | 说明 |
|---|---|---|
| Marksman | marksman | 默认服务器;提供 wiki-link 补全和跨笔记导航 |
| Rumdl | rumdl server | 提供类似markdownlint的 Markdown 规则检查 |
从 markdownlspsettingswidget.cpp 中可以看到,自动检测逻辑正是按marksman与rumdl两个可执行文件在PATH中查找的:
const QVector<KnownMarkdownLspServer> kKnownMarkdownLspServers = { {"Marksman", "marksman", {}}, {"Rumdl", "rumdl", {QStringLiteral("server")}}, };除此之外,任何通过stdio通信、兼容 LSP 的 Markdown 服务器,都可以手动配置命令后使用。
安装 LSP 服务器
安装 Marksman
Marksman 提供 wiki-link 补全、跨笔记导航和 Markdown 项目诊断,与 QOwnNotes 的 wiki 风格笔记链接配合效果很好。
- Linux/macOS:从 GitHub Releases 页下载,或通过包管理器安装(macOS 上可用
brew install marksman,NixOS 上可用nix-env -iA nixpkgs.marksman) - Windows:从 GitHub Releases 页下载
.exe,放入PATH中的任意目录
安装完成后,在设置中使用Auto-detect(自动检测)即可自动定位。
安装 Rumdl
Rumdl 是一个快速的 Markdown linter,强制可配置的风格规则,并可作为 LSP 服务器运行。
通过 Cargo(Rust)安装:
cargo install rumdl通过 pip 安装:
pip install rumdl下载预编译二进制:Linux、macOS 和 Windows 的预编译二进制可从 Rumdl 的 GitHub Releases 页面获取。
安装后,在设置中将Command设为rumdl,Arguments设为server。
在 QOwnNotes 中启用与配置
打开设置(Settings),进入Editor -> Markdown LSP页面(对应设置组件 markdownlspsettingswidget.ui):
- 勾选Enable Markdown language server (LSP)启用功能
- 在Command字段填写 LSP 服务器的可执行文件名或完整路径,默认值为
marksman- 点击Auto-detect会在你的
PATH中自动搜索marksman或rumdl并填入命令字段
- 点击Auto-detect会在你的
- 可选:在Arguments中填写传给服务器进程的参数(多个参数以空格分隔),例如 Rumdl 必需的
server - 勾选Show all LSP server log output in debug log开启详细诊断输出
- 点击Test Connection验证 QOwnNotes 能否启动服务器,并针对当前笔记文件夹完成 LSP 初始化握手
- 使用Reset ignored rules清除之前所有被忽略的诊断规则 ID
设置页还提供了状态标签,实时显示解析后的命令路径、参数以及当前是否被禁用(参见updateStatusLabel实现)。
配置项与底层存储键
从 applyMarkdownLspSettings 与 markdownlspsettingswidget.cpp 的读写逻辑可以确认,这些界面选项对应以下 QOwnNotes 设置存储键:
| 界面选项 | 设置键 | 默认值 |
|---|---|---|
| Enable Markdown language server (LSP) | Editor/markdownLspEnabled | false |
| Command | Editor/markdownLspCommand | marksman |
| Arguments | Editor/markdownLspArguments | 空列表 |
| Verbose logging | Editor/markdownLspVerboseLogging | false |
| Ignored rules | Editor/markdownLspIgnoredRules | 空列表 |
当Command或Arguments发生变化时,代码会检测到serverConfigurationChanged,自动关闭并重启已运行的服务器进程,同时重新打开当前文档(保存并恢复 URI 与文本),无需手动重启 QOwnNotes。
工作原理:一次完整的 LSP 会话
从源码层面看,整个集成由三部分组成:
- MarkdownLspClient(markdownlspclient.h):负责通过
QProcess启动服务器进程、编码/解码 LSP 消息、维护请求 ID 与回调分发 - MarkdownLspDocumentTracker(markdownlspdocumenttracker.h):监听
QTextDocument::contentsChange,把每一次编辑转换为didChange负载 - QOwnNotesMarkdownHighlighter(qownnotesmarkdownhighlighter.cpp):把服务器推送的诊断渲染为彩色波浪下划线
生命周期与消息流
- 启动与握手:启用后,QOwnNotes 以当前笔记文件夹(
NoteFolder::currentLocalPath())为工作区根目录启动服务器进程,随后发送initialize请求。请求中携带进程 ID、rootPath、rootUri、客户端信息(名称QOwnNotes、版本号)以及能力声明——例如声明不支持 snippet、格式化和 code action 均不做动态注册(markdownlspclient.cpp)。 - 打开文档:打开笔记时,QOwnNotes 发送
textDocument/didOpen通知(languageId为markdown)。若初始化尚未完成,文档会先缓存在PendingDocument中,握手成功后自动补发。 - 编辑同步:输入过程中,变更通过
textDocument/didChange转发。服务器在initialize响应中通告的textDocumentSync值决定同步方式:2表示增量同步(仅发送变更区间),否则退化为整文档同步。客户端据此设置跟踪器的同步模式。 - 诊断渲染:服务器通过
textDocument/publishDiagnostics推送的诊断,被渲染为编辑器中的彩色波浪下划线。 - 右键交互:在带下划线的区域右键,会显示可用的code actions与忽略该规则选项。
- 补全与格式化:服务器提供补全项时以弹窗展示;文档格式化分别通过
textDocument/formatting或textDocument/rangeFormatting完成。
增量同步的实现细节
MarkdownLspDocumentTracker是性能关键路径的实现核心。它在每次按键触发的contentsChange回调中保持轻量操作:
- 维护一份行长度快照(
_lineLengths),用于把文档位置转换为编辑前的(行、列)坐标,从而精确计算旧区间; - 累积的增量变更先放入待发队列,由防抖定时器(默认 200ms)合并后一次性发送,避免每个按键都触发一次 IPC;
- 对超过 100000 字符的大文档,防抖间隔自动提升到至少 1000ms(见 markdownlspdocumenttracker.cpp 中的
kLargeFullSyncDocumentSize与kLargeFullSyncDebounceIntervalMs常量); - 增量模式下的新增文本直接按字符读取,并把段落分隔符(U+2029)转换为
\n,全程不调用昂贵的toPlainText()。
当服务器返回快速修复的编辑内容时,跟踪器会临时进入setSuppressed(true)状态,避免把程序化编辑当作用户输入重复上报,随后立即执行一次完整同步(flushFullSync),让诊断状态立刻刷新。
通信协议细节
客户端与服务器通过标准stdio管道通信,消息采用 LSP 规范的Content-Length帧格式(sendMessage / parseMessages):
Content-Length: <payload 字节数>\r\n\r\n<JSON-RPC 2.0 负载>对于服务器发来的服务器到客户端请求(如client/registerCapability、window/workDoneProgress/create),客户端会主动回复空结果响应,避免服务器因等待应答而阻塞。服务器stderr中形如ERR/ERROR的行会被提取并作为错误消息反馈给界面。
日常使用指南
诊断下划线的颜色语义
诊断的渲染逻辑位于 qownnotesmarkdownhighlighter.cpp 的setMarkdownLspDiagnostics,颜色由 LSP 严重级别决定:
| 严重级别 | 含义 | 下划线颜色 |
|---|---|---|
| 1 | Error | 红色 |
| 2 | Warning | 橙色 |
| 3 | Information | 蓝色 |
| 4 | Hint | 绿色 |
下划线采用波浪样式(SpellCheckUnderline),与拼写检查、LanguageTool 语法检查的下划线一致,且逐字符合并基础格式,保留原有语法高亮的文字颜色;鼠标悬停时还会显示诊断消息作为 tooltip。多行诊断会自动覆盖其跨越的每一行。
右键菜单:快速修复与忽略规则
在带下划线的区域右键,QOwnNotes 会:
- 定位覆盖光标位置的诊断,以其消息作为子菜单标题;
- 向服务器发起
textDocument/codeAction请求(最多等待 2 秒),把返回的 code action 逐个加入菜单——带编辑内容的动作直接应用到文档,带命令的动作通过workspace/executeCommand执行; - 提供Ignore rule ... globally菜单项,将当前诊断的规则 ID 加入忽略列表。
诊断规则 ID 由source与code组成(如rumdl:MD013形式,见 Diagnostic::ruleId)。被忽略的规则持久化存储在设置键Editor/markdownLspIgnoredRules中(markdownlspignoredrules.cpp),可在设置页用Reset ignored rules一键清空。
补全
输入时若当前没有内置补全候选(wiki 链接、公式结果、单词补全、脚本autocompletion钩子等),QOwnNotes 会向服务器发送textDocument/completion请求,并把返回的补全项展示为带过滤输入框的弹窗(showMarkdownLspCompletions)。选中后以光标所在词起始位置插入补全文本并追加一个空格。若设置中开启了Editor/autocompleteApplySingleResult,当服务器只返回一个补全项时会直接应用而不弹窗。
格式化
编辑器上下文菜单中的Markdown LSP -> Format document / Format selection分别对应textDocument/formatting与textDocument/rangeFormatting。格式化请求固定使用 4 空格缩进(tabSize=4、insertSpaces=true),返回的文本编辑会按从后往前的顺序应用,避免位置偏移。应用编辑后立即触发完整同步与诊断刷新。
故障排查
- 服务器无法启动:QOwnNotes 会在状态区域显示警告。同时
MarkdownLspClient::start()会在命令为空或进程 2 秒内未启动时发出错误消息。 - 查看通信细节:勾选Show all LSP server log output in debug log,服务器全部
stderr输出与同步模式信息都会写入调试日志。 - 验证连接:设置页的Test Connection会独立启动一个客户端、对当前笔记文件夹执行
initialize,等待serverInitialized信号(5 秒超时),成功后显示"Markdown LSP connection successful"。 - 诊断不消失:使用Reset ignored rules清除历史忽略记录;快速修复后会立即执行完整同步,不必等待防抖定时器。
连接成功后,QOwnNotes 会在状态栏短暂显示 "Markdown LSP server connected"(3 秒),表示初始化握手已完成、可以开始使用全部 LSP 能力。
相关阅读
- Spellchecking
- LanguageTool
- Harper
- Concept
- 桌面应用
【免费下载链接】QOwnNotes
QOwnNotes is a plain-text file notepad and todo-list manager with Markdown support and Nextcloud / ownCloud integration.
相关推荐
QOwnNotes Markdown LSP 集成指南:为笔记编辑器接入语言服务器诊断、补全与格式化
QOwnNotes Markdown LSP 集成指南:为笔记编辑器接入语言服务器诊断、补全与格式化 QOwnNotes 内置了一个完整的 Markdown L
桌面应用QOwnNotes 集成 Markdown LSP:为笔记编辑器接入诊断、补全与格式化能力
QOwnNotes 集成 Markdown LSP:为笔记编辑器接入诊断、补全与格式化能力 QOwnNotes 在笔记编辑器中内置了一个基于 Language
桌面应用QOwnNotes 的 Markdown LSP 集成:在笔记编辑器中接入诊断、补全与格式化的完整指南
QOwnNotes 的 Markdown LSP 集成:在笔记编辑器中接入诊断、补全与格式化的完整指南 QOwnNotes 支持接入符合 Markdown La
桌面应用
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考