- 桌面应用
【免费下载链接】QOwnNotes
QOwnNotes is a plain-text file notepad and todo-list manager with Markdown support and Nextcloud / ownCloud integration.
QOwnNotes 通过内置的 Harper 支持,在笔记编辑器中提供可选的离线语法与风格检查(offline grammar and style checking),基于harper-ls语言服务器在本地完成检测,无需把笔记内容发送到任何外部服务。本文将带你完成 Harper 的启用、运输方式(Transport)选择、方言与 Linter 配置、连接测试,并从源码层面剖析它的工作机理,帮助你把这套检查能力无缝接入自己的写作流程。
Harper 与现有拼写检查的关系
Harper 并不是用来替代 QOwnNotes 原有拼写检查(spellchecking)的,而是作为其补充:拼写检查负责基础拼写纠错,Harper 更进一步覆盖语法、风格、标点与措辞层面的问题。在 README 中,QOwnNotes 将 Harper 与 LanguageTool、Markdown LSP 并列介绍,三者同属于编辑器可选的语法/风格检查能力。
核心功能
根据 Harper 文档 与源码实现,该功能包含以下能力:
- 彩色下划线标注:语法、风格、标点、措辞问题按类别用不同颜色显示在编辑器内;
- 右键菜单替换建议:右键点击问题文本即可看到候选替换词;
- 忽略机制:支持
Ignore this rule(忽略某条规则)与Ignore word(忽略某个单词)操作; - 快速开关:
Edit(编辑)菜单提供Check grammar with Harper切换项; - 完全本地检查:通过
harper-ls语言服务器以Stdio或TCP方式通信,全程无需联网。
设置步骤
打开 QOwnNotes 的Settings(设置),选择Editor -> Harper,即可看到 harpersettingswidget.ui 中定义的完整配置界面。
1. 启用功能
勾选Enable offline grammar and style checking with Harper(启用 Harper 离线语法与风格检查)。该开关对应设置键harperEnabled,默认值为false,源码中由 harperchecker.cpp 的readSettings()读取。同时,Edit菜单中的Check grammar with Harper动作(见 mainwindow.ui)也会同步该开关状态,具体逻辑位于 mainwindow.cpp。
2. 选择运输方式(Transport)
| 选项 | 说明 | 默认值 |
|---|---|---|
Stdio (recommended) | 由 QOwnNotes 直接启动本地harper-ls进程(对应模式值 0) | 推荐 |
TCP | 连接一个已经运行的harper-ls服务器(对应模式值 1) | — |
运输方式保存在设置键harperTransportMode中。源码层面,harperclient.cpp 的ensureTransport()根据模式分别创建HarperStdioTransport(基于QProcess)或HarperTcpTransport(基于QTcpSocket)两种传输实现。
Stdio 模式参数
Command / binary path(命令/二进制路径):默认命令为harper-ls,对应设置键harperBinaryPath;Auto-detect(自动检测):通过QStandardPaths::findExecutable在系统PATH中查找harper-ls(见 harpersettingswidget.cpp),找到后会把完整路径回填到输入框;Browse(浏览):手动选择 Harper 可执行文件。
启动时,Stdio 传输会以harper-ls --stdio参数拉起子进程,并等待最多 2 秒确认启动成功(harperclient.cpp)。
TCP 模式参数
Server address(服务器地址):默认127.0.0.1,对应设置键harperTcpAddress;Port(端口):默认4000,对应设置键harperTcpPort,UI 中允许的范围为 1~65535。
TCP 连接等待超时同为 2 秒;连接失败时会记录下一次重试时间(当前实现为失败后等待 2 秒再重连,见ensureStarted())。
3. 选择方言(Dialect)
Dialect下拉框提供 5 种英语方言选项:
American(美式,默认)British(英式)Australian(澳式)Canadian(加式)Indian(印式)
方言值保存在harperDialect中,会作为dialect字段写入发送给harper-ls的配置(harperclient.cpp)。
4. 调整检查延迟(Check delay)
Check delay(检查延迟)控制 QOwnNotes 在停止输入后、发起检查请求前等待的毫秒数。UI 中可调范围为500~5000 ms,步长 100 ms,默认 1500 ms(对应设置键harperCheckDelay)。底层通过单次定时器QTimer实现防抖(debounce),并在设置读取时把定时器间隔同步为该值(harperchecker.cpp)。
5. 选择启用的 Linter
以下 12 个 Linter 均可独立勾选(源码中的内部标识见括号):
| UI 名称 | 内部标识 |
|---|---|
| Spell Check(拼写检查) | SpellCheck |
| Sentence Capitalization(句首大写) | SentenceCapitalization |
| Repeated Words(重复单词) | RepeatedWords |
| Long Sentences(长句) | LongSentences |
| An vs A(冠词 a/an 选择) | AnA |
| Unclosed Quotes(未闭合引号) | UnclosedQuotes |
| Correct Number Suffix(数字后缀纠正) | CorrectNumberSuffix |
| Spaces(空格) | Spaces |
| Quote Spacing(引号间距) | QuoteSpacing |
| No French Spaces(无法语空格) | NoFrenchSpaces |
| Wrong Apostrophe(错误撇号) | WrongApostrophe |
| Spelled Numbers(拼写数字) | SpelledNumbers |
默认启用SpellCheck、AnA、SentenceCapitalization、RepeatedWords、LongSentences、Spaces、QuoteSpacing、NoFrenchSpaces、WrongApostrophe、CorrectNumberSuffix、UnclosedQuotes这 11 项(SpelledNumbers默认关闭),完整默认列表见 harperchecker.cpp。勾选结果保存在harperEnabledLinters中,并在发送配置时以布尔开关形式写入 LSP 的linters配置对象。
6. 测试连接
点击Test Connection按钮验证配置是否可用:
- Stdio 模式下会尝试启动
harper-ls; - TCP 模式下会尝试连接配置的服务器;
- 测试时会发送一段固定测试文本
"This are a test sentence."(harpersettingswidget.cpp),收到checkFinished信号则弹窗提示连接成功,并附带服务器版本号;收到checkError则提示连接失败原因。
页面底部还有一个Status状态区:Stdio 模式下会显示找到的harper-ls路径与版本(通过执行harper-ls --version查询),TCP 模式下显示目标地址与端口。
7. 管理忽略项
设置页提供两个重置按钮:
Reset ignored rules(重置忽略的规则):清除所有通过右键菜单Ignore this rule忽略的规则;Reset ignored words(重置忽略的单词):清除所有通过右键菜单Ignore word忽略的单词。
两者点击后均会弹出确认对话框。忽略的规则保存在harperIgnoredRules、忽略的单词保存在harperIgnoredWords中。值得注意的是,忽略单词时不仅会记录到 Harper 自己的集合,还会同步调用QOwnSpellChecker把该词加入系统拼写词典(harperchecker.cpp)。
工作原理
Harper 在 QOwnNotes 中的工作流程由三个核心组件协作完成,全部位于 services 目录:
- HarperChecker(harperchecker.h / harperchecker.cpp):编辑器侧的调度器,负责决定检查哪些内容、何时发起请求、缓存与管理忽略项;
- HarperClient(harperclient.h / harperclient.cpp):LSP 客户端,负责与
harper-ls的协议通信; - HarperMatch(harpertypes.h):表示单个检查结果的数据结构,包含偏移量、长度、消息、规则 ID、规则类别、替换建议与上下文文本。
只检查可见区块
QOwnNotes 不会把整篇文档一次性发给 Harper,而是通过visibleBlocks()计算当前视口(viewport)内可见的文本块(harperchecker.cpp)。滚动编辑器时也会触发重新调度(监听垂直滚动条的valueChanged)。
跳过无关内容
shouldCheckBlock()会跳过以下类型的文本块(harperchecker.cpp):
- 不可见或无效的块;
- 空白行(trim 后为空);
- 标题行(
HeadlineEnd状态); - 代码块(
CodeBlock状态,以及 MarkdownHighlighter 中CodeCpp之后的所有代码状态)。
防抖与缓存
- 防抖:每次文本变化只启动单次定时器,间隔即设置中的
Check delay,避免每敲一个键就发一次请求; - 区块级缓存:每个文本块以其 SHA-1 哈希作为键缓存结果,内容未变化时直接复用;缓存条目默认 TTL 为 300 秒、上限 500 条,过期与超限条目会被清理(
cleanupExpiredCache()与enforceCacheLimit()); - 结果有效性校验:请求返回时会重新计算文档 SHA-1,与提交时记录的哈希比对,若文档在请求期间被修改则丢弃过期结果(
handleRequestFinished())。
LSP 协议通信细节
HarperClient 实现了标准的 Language Server Protocol(LSP)2.0 流程,包括:
- 初始化握手(
initialize/initialized),并声明textDocument/codeAction与workspace/configuration能力; - 通过
workspace/didChangeConfiguration下发方言与 Linter 配置; - 用
textDocument/didOpen打开一个虚拟 Markdown 文档(URI 形如file:///qownnotes-harper-<id>.md,languageId 为markdown); - 接收
textDocument/publishDiagnostics通知,将行/列坐标换算为绝对偏移,构造HarperMatch; - 对每个诊断发起
textDocument/codeAction请求,从返回结果中解析Replace with: "..."形式的替换建议(decodeReplacementTitle())以及 workspace edit 中的newText; - 所有请求带 5 秒超时,超时或服务异常时通过
checkError信号通知上层。
问题高亮与右键菜单
- 着色:
QOwnNotesMarkdownHighlighter的highlightHarper()(qownnotesmarkdownhighlighter.cpp)根据ruleCategory决定下划线颜色:Spelling(拼写)→ 红色;Style(风格)→ 琥珀色#c99500;Punctuation(标点)→ 绿色#1c8f47;Typography(排版)→ 紫色#7a3db8;- 其余(默认 Grammar 语法类)→ 蓝色
#2a6fdb。 高亮采用SpellCheckUnderline波浪下划线样式,并附带问题消息作为 tooltip。
- 右键菜单:
addHarperMenuSection()(qownnotesmarkdowntextedit.cpp)在光标位置命中问题时会弹出菜单,包含:类别与规则名(不可点击的头部)、最多 8 条替换建议、Ignore this rule、Ignore word "..."。选择替换建议后通过applyHarperReplacement()以对应位置范围直接替换文本。
不可用时的降级行为
如果 Harper 无法启动或连接(如harper-ls未安装),QOwnNotes 会在状态栏显示带警告图标的提示消息(持续约 5 秒),并通过connectionError信号通知,随后停止检查直到服务恢复可用(harperchecker.cpp)。
构建前提
Harper 支持是可选的,取决于构建时是否启用该特性:
- CMake 构建:
src/CMakeLists.txt中定义HARPER_ENABLED选项,默认ON(src/CMakeLists.txt),启用后通过target_compile_definitions(... HARPER_ENABLED)传入编译器; - qmake 构建:对应源码文件在 src/QOwnNotes.pro 中登记。
若构建未启用该特性,Settings -> Editor -> Harper页面会显示"Harper support is not available in this build.",且所有选项不可用;Edit菜单中的Check grammar with Harper动作也会被隐藏(mainwindow.cpp)。
与 LanguageTool 的关系
Harper 与 LanguageTool 可以同时启用。两者的定位差异在于:
- LanguageTool:既可连接本地自托管服务,也可连接远程服务(如
http://localhost:8081或https://api.languagetoolplus.com),并支持按 Spelling/Grammar/Style/Punctuation/Typography 类别勾选; - Harper:主打完全本地离线,通过
harper-ls以 Stdio 或 TCP 方式工作,无需配置任何远程 URL。
在实现上二者相互独立(分别由LANGUAGETOOL_ENABLED与HARPER_ENABLED编译开关控制),高亮渲染也走各自的管线,因此可以放心叠加使用。
常见问题
harper-ls没有找到?先确认已安装 Harper 命令行工具并使其位于PATH中,然后点击设置页的Auto-detect;或使用Browse手动指定可执行文件路径。- TCP 连接失败?确认
harper-ls已以 TCP 服务方式启动、地址端口与设置一致(默认127.0.0.1:4000),再用Test Connection验证。 - 修改配置后不生效?HarperChecker 的
scheduleCheck()每次触发前都会调用readSettings()重新读取设置,因此改动保存后会在下一次检查时自动生效。 - 检查结果没有出现?确认已勾选启用开关、对应的 Linter 处于开启状态,并且光标所在文本块不是标题或代码块(这些内容会被有意跳过)。
相关文档
- 拼写检查
- LanguageTool 语法与风格检查
- Markdown LSP
- QOwnNotes 核心概念
- 桌面应用
【免费下载链接】QOwnNotes
QOwnNotes is a plain-text file notepad and todo-list manager with Markdown support and Nextcloud / ownCloud integration.
相关推荐
QOwnNotes 集成 Harper 离线语法与风格检查:完整配置指南与 harper-ls 工作原理
QOwnNotes 集成 Harper 离线语法与风格检查:完整配置指南与 harper ls 工作原理 QOwnNotes 通过可选集成 Harper htt
桌面应用QOwnNotes 集成 Harper:基于 harper-ls 的离线语法与风格检查配置指南
QOwnNotes 集成 Harper:基于 harper ls 的离线语法与风格检查配置指南 QOwnNotes 可在笔记编辑器中集成 Harper http
桌面应用QOwnNotes 集成 Harper:离线语法与风格检查的配置与实现原理
QOwnNotes 集成 Harper:离线语法与风格检查的配置与实现原理 QOwnNotes 通过本地 harper ls 语言服务器提供可选的 离线语法与风
桌面应用
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考