6

将 VS Code 打造成跨平台 Markdown「草稿本」

 9 months ago
source link: https://type.cyhsu.xyz/2023/09/vscode-as-scratchpad/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

将 VS Code 打造成跨平台 Markdown「草稿本」

2023-09-13

A version of this article appears on Sep. 13, 2023 on SSPAI as a member-only post. Learn more or subscribe

The article is permitted to be self-archived in the version as originally submitted for publication on the author’s personal website under CC BY-NC 4.0 pursuant to § 5.2(b) of the SSPAI Fellowship Contributor Agreement.

在电脑上工作时,经常会需要一个暂存文本的空间,用来放置一闪而过的想法、起草相对重要的消息回复,或者汇总来自多处的摘录——相当于案头备着的草稿纸所起的功能。

诚然,可选解决方案不可谓不多,既有 nvALTTotDrafts 等将此作为主要功能的软件,也可以用各类笔记软件、甚至剪贴板管理工具兼任。

ec416305ddb262059d0a07dada30bbd4.png

Tot (MacWorld)

但是,我对这些方案一直不很满意。打草稿追求的是快进快出、随身携带,但上述工具中很少见到能兼顾收集快捷、导出方便和跨平台(特别是跨 macOS 和 Windows)同步的。将「草稿」和普通笔记混同在一起,也不便于管理。

更重要的是,越是草稿和临时性质的内容,越意味着需要大量编辑,包括调整顺序、提取信息、整理格式等等;笔记软件通常不会对此做特别优化,导致操作起来颇为麻烦。

经过多番尝试和比较后,我开始意识到,文本编辑器其实就是一种特别适合做「草稿本」的工具:由于基于朴素的目录和文本文件,很容易通过终端命令实现自动化,搭车通用的云盘实现跨平台同步;编辑器的定位使然,查找替换、快捷键操作、自动补全和高亮等功能也是必然内置的。

不过,要让文本编辑器真正成为方便好用的「草稿本」,还需要具有以下功能:

  • 支持自动保存。这是「草稿本」让人能放心使用的信任基础,又可以具体细分为自动保存更改和自动保存会话:前者是指自动保存对现有文件的编辑,后者是指在关闭窗口或退出软件时,即使没有保存到文件的临时内容也会被暂存下来,并在下次启动时重现。
  • 支持新文件名模板。没有人会想在打草稿的时候费脑筋起文件名。「草稿本」最好能为每个新建的文件按一定规则拟一个不会重复的文件名,例如通过时间戳或 UUID。
  • 支持 Markdown 语法。对于文本笔记,Markdown 支持几乎是必须的。理想的「草稿本」应该支持 Markdown 语法高亮、常见格式的快捷键,以及同步预览。
  • 支持区隔不同场景下的设置。「草稿本」的上述功能需求与一般的文件查看和代码编辑是非常不同的;如果编辑器只支持一套配置,按此设置也就意味着它几乎不能再用于别的任务了,显得有些小题大做。

调研下来,如果以「出厂状态」为标准,只有 BBEdit 最接近这样的要求。事实上,它的 Notebook 功能完全就是为了这个需求开发的。

6dc337b574e5dca8af564442ba2bf491.png

BBEdit 的 Notebook 功能(Bare Bones Software)

遗憾的是,BBEdit 只支持 macOS 平台;作为三十年历史的经典软件,有些设计和操作在今天看来略显古旧,对 Markdown 和中文的支持都不完美;Notebook 也不属于其免费功能范围,50 美元的门票有些昂贵了。

于是,我又打起了自己另一个常用软件 VS Code 的主意。经过一番尝试,竟然完全符合需求:

  • VS Code 本身是跨平台、开源的代码编辑器,基础的编辑功能自然不在话下,而且具有特别丰富的插件生态。这使得 VS Code 可能是代码编辑器里最擅长写 Markdown 的,Markdown 工具里编辑功能最强的。
  • 支持多套配置的灵活切换。特别是一月更新的 1.75 版加入了一个非常实用的「配置文件」(profile)功能,可以为各个使用场景选择不同的设置、插件、界面布局和快捷键等,比以往基于工作区(workspace)的方式更灵活,而且支持云端同步。
  • 自动化方便,可以将任何终端命令保存为「任务」;还有完善的命令行界面,方便对接其他自动化工具。

下面,本文将具体介绍怎样将 VS Code 打造成一个跨平台的 Markdown「草稿本」,同时不影响它发挥代码编辑器的本职功能。如果有类似需求,你可以依样操作,也可以挑选适合自己的部分变通采纳。

搭建基本框架

首先,确定一个「草稿本」的存放目录。具体位置按个人习惯即可,但如果有同步需求,可以选择一个云盘中的位置;如果本来就用纯文本方式做笔记,还可以取现有路径的下级目录,方便统一管理。

例如,我的「草稿本」位于 ~/flashes(取「闪念」之意)。这个目录实际上是指向我 Obsidian 笔记库同名子目录的符号链接,本身 (1) 位于 iCloud 云盘中,(2) 通过 Syncthing 与非苹果设备同步,并且 (3) 自动定期提交到一个私人 GitHub 仓库。

这样,无论在 Mac、Android 手机还是 VPS 服务器上,我都可以随时访问到这些「草稿」;在 Obsidian 中整理笔记时,还可以直接引用或链接到「草稿本」中的内容。

创建完成后,在 VS Code 中通过命令面板(Command/Ctrl+Shift+P)运行 File: Open Folder,将这个笔记目录作为工作区打开。(由于 VS Code 的中文本地化翻译质量不高,本文中提及的命令和操作名称以英文版为准。)

接着,创建一个「草稿本」专用配置文件。 为此,通过命令面板运行 Profiles: Create Profile。

3f7aa8ac542a1eb83201d3fca36cf9b7.png

在显示的选项中:

  • 配置文件名称:按喜好填写即可,尽量简洁,方便后面自动化。例如我这里起了一个 flashes,意指「闪念」。
  • 是否复制现有配置或模板的内容:这可以根据你之前的使用情况决定——
    • 如果你从事开发工作,已经对 VS Code 做了开发环境的重度配置,那么显然不适合照搬到「草稿本」中,最好选择「无」,从头开始。
    • 相反,如果你像我一样,主要用 VS Code 码字,配置比较轻量,那么不妨选择「默认」来沿用熟悉的环境。
    • 还有一种选择是 Doc Writer,这是 VS Code 提供的模板之一,内置了一系列为码字优化的设置项和流行插件;如果想偷懒或者没什么思路,它是一个比较好的起点。
260b26899570b3a2e2360763fa9f9f96.png
  • 配置文件范围:这里列举了配置文件可以独立容纳的内容,如果取消勾选,新的配置文件会直接沿用默认配置的相应部分。如后文将会表明,这几项对于配置「草稿本」都是有用的,保持全选的默认状态即可。

做好设置后,点击 Create 即可完成创建。你可以从 Acticity Bar 上设置按钮的角标判断当前生效的配置文件。此外,工作区会记住上一次切换到的配置文件,因此以后打开「草稿本」文件夹时,都会自动使用刚才新创建的配置文件。

aadb8e35840d73580d195c26cd2c8bd5.png

优化「草稿本」的内部环境

如开头提到,配置文件功能的一大优点就是实现了设置、插件的相互隔离。因此,我们可以随意将这个「草稿本」专用的新配置向着最适合 Markdown 随手记的环境改造,而不用担心干扰更适合编辑代码的默认配置,或者因为插件装得太多影响启动速度和性能。

至于具体怎么改造,则是萝卜青菜的问题,读者可以自由发挥。官方帮助中的「Markdown 编辑」一节是很好的起点(读完你很可能会意识到很多功能现在已经不需要装插件)。我之前还介绍过 AutoCorrect(自动添加中英文间的空格)和 markdownlint(自动检测和修复 Markdown 格式)两个实用 Markdown 写作插件,有兴趣的朋友可以回顾

下面只重点介绍一些我认为特别适合本文场景、需要一些注解的配置方式。

精简界面布局

VS Code 默认布局显得比较聒噪,很多功能对于 Markdown 笔记场景也并不适用。因为配置文件也会隔离界面布局,可以放心做些「大刀阔斧」的精简。例如:

  • 将侧边栏的 Explorer、Search 等高频使用的面板放到底栏中(通过拖拽,或者在标题上点击右键,选择 Panel Position > Bottom),然后隐藏 Source Control、Problems 等无关面板(在标题上点击右键选择 Hide Panel)。这样,就可以隐藏左右边栏节约空间了。
  • 点击窗口右上角的「自定义布局」按钮,打开 Zen Mode(但同时关闭 Centered Layout),隐藏无关的界面元素。

这样,界面看起来就清爽多了。

f18c00c06d8c2e6cd74cf3b21bf58653.png

设置自动保存

好的「草稿本」应该尽量让人忘掉「保存」这回事,自己默默保存更改就好,不要用「是否保存」的弹窗来骚扰用户。为此,相关的设置是:

  • files.autoSave: 设为 afterDelay,即每隔一段时间自动保存,具体间隔通过 files.autoSaveDelay 指定(单位为毫秒),例如 5000 即为每 5 秒保存一次。
  • files.hotExit: 设为 onExitAndWindowClose,即在关闭窗口或退出应用时均不额外提醒,下次打开时自动恢复未保存内容。

一键插入格式模版

很多第三方笔记工具会提供快速插入 Markdown 模板的菜单项和快捷键,而这在 VS Code 中也很好实现,并且用自带的「代码片段」(snippet)和快捷键映射功能即可,不需要任何插件。

下面以自制插入 Markdown 任务列表(- [ ])的模板并绑定快捷键为例演示,配置好的效果如下图所示。

05cd38847c295796f44fc27d84815137.gif

首先,将任务列表的语法创建为一个代码片段。 为此,用命令面板运行 Snippets: Configure User Snippets,然后选择 markdown。将打开的 markdown.json 文件修改如下:

{
    // omitted
    "Insert task list": {
        "prefix": "task",
        "body": [
            "- [${1| ,x|}] $2",
            "$0"
        ],
        "description": "Insert task list"
    },
    // omitted
}

由此,我们创建了一个名为 Insert task list,简称为 task 的代码片段,其格式定义位于 body 键。其中:

  • $1$2……$n 称为 tabstop,是模板中待填写的「空档」,在插入后可以按 Tab 键快速跳到下一个。
  • ${1| ,x|} 是指在光标位于这个空档时,用列表提供空格和 x 两个选项供用户选择,对应任务列表的两种状态。
  • $0 是填完所有空档后,光标最后停在的位置,这里设置为下一行的行首。
845d0d5e9522a5c6e9274b3d1fc5e9de.png

这时,就可以用命令面板运行 Snippets: Insert Snippet,然后选择 task 来调用这个模板了。

接着,我们为它指定一个快捷键,以便更快调用。 用命令面板运行 Preferences: Open Keyboard Shortcuts (JSON),将打开的 keybindings.json 文件修改如下:

[
    // omitted
    {
        "when": "editorTextFocus && isMac",
        "key": "cmd+k t",
        "command": "editor.action.insertSnippet",
        "args": {
            "name": "Insert task list",
            "langId": "markdown"
        }
    },
    {
        "when": "editorTextFocus && !isMac",
        "key": "ctrl+k t",
        "command": "editor.action.insertSnippet",
        "args": {
            "name": "Insert task list",
            "langId": "markdown"
        }
    },
    // omitted
]
  • key 键用于指定快捷键,可以是组合式、两段式或其混合(完整语法见官方帮助)。例如 cmd+k t 指先按 Command + K,然后再按 T
  • when 键用于指定启用快捷键的环境,可用条件包括操作状态、操作系统等,且支持逻辑运算(完整列举见官方帮助)。例如 editorTextFocus && !isMac 表示仅在输入焦点位于编辑区域,且当前系统不是 macOS 时才启用。由于 VS Code 是一个跨平台编辑器,这特别适合针对 macOS 和 Windows 设置不同的修饰键。
  • commandargs 键用于指定快捷键要执行的命令。对于代码片段而言,命令总是 editor.action.insertSnippetargs.nameargs.langId 则分别是之前在创建代码片段时设置的名称和适用语言。

通过同样的方法,你可以创建其他自己常用的 Markdown 格式模板并绑定快捷键。和配置文件中的其他设置一样,这都不会和默认配置相冲突,并且可以通过设置同步功能跨端同步。

这里再附一个「插入 Markdown 表格模板」的代码片段供参考:

{
    // omitted
    "Insert 3x2 table": {
        "prefix": "table",
        "body": [
            "| ${1:Column1}  | ${2:Column2}   | ${3:Column3}   |",
            "|-------------- | -------------- | -------------- |",
            "| ${4:Item1}    | ${5:Item1}     | ${6:Item1}     |",
            "${0}"
        ],
        "description": "Insert table with 2 rows and 3 columns."
    },
    // omitted
}

让新建文件名附带时间戳

默认设置下,VS Code 的 Command+N(或 Windows 上的 Ctrl+N)快捷键会新建一个名字毫无新意的 Untitled-1.txt,并且在手动保存之前都是临时文件。对于「草稿本」的场景而言,这既不直观也不方便。

联想到很多采用「卡片笔记」方法的软件都支持自动在文件名中加入时间戳(例如 Obsidian 的「ZK 卡片」按钮),既不会重复,又方便事后检索。这能否在 VS Code 中实现呢?

当然可以,方法是挪用 VS Code 的「任务」(task)功能。任务原本是针对开发场景的自动化功能,每项任务其实就是一条预先定义的命令,可以通过命令面板或快捷键调用,实现代码检查、编译等功能。

这样,问题就转化为「如何用一行命令按模板名称新建文件并打开」。如果有一定终端操作经验,答案想必是很直接的(没有经验也不用担心,今年是 2023 年,有个东西叫 GPT)。

例如,对于 macOS 和 Linux,可以这样写:

note="/path/to/note_$(date +%Y%m%d_%H%M%S).md"; \
    touch "$note" && \
    code --reuse-window "$note"

其中,--reuse-window (-r) 选项告诉 VS Code 尽量「复用」现有的窗口,从而避免每新建一条「草稿」就新开一个窗口。$(date +%Y%m%d_%H%M%S) 使用 date 命令创建一个时间戳,得到的结果形如 20230102_123456,可以按需修改。

而在 Windows 上,等效的 PowerShell 版本则可以写成:

$note='X:\path\to\note_' + $(Get-Date -Format yyyyMMdd_HHmmss) + '.md'; `
    New-Item "$note" && `
    code --reuse-window "$note"

下面我们把这些命令做成 VS Code 任务。用命令面板运行 Tasks: Open User Tasks,然后选择 Others。将打开的 tasks.json 文件编辑为如下内容:

{
    "version": "2.0.0",
    "tasks": [
        // omitted
        {
            "label": "New note",
            "type": "shell",
            "command": "note=\"${workspaceFolder}/note_$(date +%Y%m%d_%H%M%S).md\"; touch \"$note\" && code --reuse-window \"$note\"",
            "windows": {
                "command": "$note='${workspaceFolder}\\note_' + $(Get-Date -Format yyyyMMdd_HHmmss) + '.md'; New-Item \"$note\" && code --reuse-window \"$note\""
            },
            "presentation": {
                "reveal": "silent"
            },
            "problemMatcher": []
        },
        // omitted
    ]
}
  • type 键用于设定该任务的类型,此处的 shell 即指运行终端命令。具体的终端环境在 macOS 和 Linux 上默认为当前用户的登录 shell($SHELL),在 Windows 上默认为 PowerShell,但也可以自行设置
  • command 键用于设定任务要执行的终端命令。如果同时存在 windows.command 键(如本例),则前者只会在 macOS 和 Linux 上执行任务时调用,Windows 上则会调用后者中的命令。注意由于 JSON 语法,命令中的 "\ 都需要用前缀 \ 转义。
  • 命令路径中的 ${workspaceFolder} 是 VS Code 内置变量之一,会在运行时被替换为当前目录的实际路径,这就实现了定向在「草稿本」目录中创建文件。
  • presentation.revealproblemMatcher 键分别用于设置执行任务时是否显示终端输出,以及是否扫描输出检测问题。这都是针对开发环境有用的功能,而我们只需要「默默」新建文件即可,故分别设置为 silent 和空来禁用。

这样,就可以用命令面板执行 Tasks: Run Task,然后选择 New note 来获得文件名带时间戳的新「草稿」了。

但这显然还不够方便,我们可以在上面介绍过的 keybindings.json 中追加一个快捷键定义,把默认的新建文件快捷键 Command/Ctrl+N「绑架」到我们的自定义任务上:

[
    // omitted
    {
        "key": "ctrl+n",
        "command": "workbench.action.tasks.runTask",
        "args": "New note",
        "when": "!isMac"
    },
    {
        "key": "cmd+n",
        "command": "workbench.action.tasks.runTask",
        "args": "New note",
        "when": "isMac"
    },
    // omitted
]

这样,以后直接按最符合直觉的 Command/Ctrl+N,就能执行 New note 任务,新建并打开时间戳命名的文件了。

66aff2bf1f749570813b46fa0f7be5c8.gif

这里再附一个「删除正在编辑的文件」的任务定义供参考:

{
    "label": "Delete current",
    "type": "shell",
    "command": "rm -f '${file}'",
    "presentation": {
        "reveal": "silent"
    },
    "problemMatcher": []
}

快速启动和抓取文本

到目前为止,我们已经为「草稿本」打造了一个比较便捷的「内部环境」。接下来,还可以从外部着手,让「草稿本」的启动和内容录入更加流畅。这就是 VS Code 的命令行界面发挥用处的时候了。

在接着往下看之前,请了解:

  • 作为准备步骤,先确保 VS Code 的主程序 code 位于终端环境的搜索路径中。这在 Windows 和 Linux 上一般会在安装时自动配置,在 macOS 上则需要手动通过命令面板运行一次 Shell Command: Install 'code' command in PATH 命令。(具体可参阅官方帮助的初始设置一节。)
  • 由于自动化方案五花八门,下面示例的方法都只是「最大公分母」,优先说明如何使用 macOS 和 Windows 系统的自带功能实现需求。显然,读者可以根据原理改用到自己习惯的工具中。主力用 Linux 的朋友……可能轮不到我教你用什么工具 :)

快速启动「草稿本」

既然花了一番功夫打造出这个独立的「草稿本」环境,自然会期望为它设置一个专用的启动方式。为此,VS Code 提供了下面的命令:

code /path/to/workspace --profile PROFILE_NAME

因此,只需将这个命令打包成一个快捷方式即可:

在 macOS 上,最简单的方法是用快捷指令 app 创建一个只包含一步「执行终端脚本」的快捷指令,在其中按上述格式填好命令。(注意要使用 VS Code 命令行的完整路径 /usr/local/bin/code。)

f1855e0f171ed7550f4219c005b6bf26.png

然后,选择「文件」>「添加到程序坞」菜单项,即可在 Dock 中添加一键打开「草稿本」的图标。

2b2c4fca69257c13912fa73ff0117c2a.png

在 Windows 上,直接用快捷方式即可。在桌面空白处单击右键,选择「新建」>「快捷方式」,然后填写其目标为 "%LOCALAPPDATA%\Programs\Microsoft VS Code\Code.exe" "X:\path\to\workspace" --profile PROFILE_NAME(按实际情况更换其中的路径和配置文件名),即可在桌面添加一键打开「草稿本」的图标。

快速捕获别处内容

很多第三方笔记工具都支持不同形式的「快速捕获」功能,可以一键将当前选中的内容添加创建为笔记。这在我们的 VS Code「草稿本」中也很容易实现。

在 macOS 上, 仍然可以用快捷指令为载体,制作一条内容如下图所示的快捷指令(下载,注意按实际情况替换其中的路径和配置文件名)。

d099cf433e778a6bafcffe397454f7ab.png

然后,在侧边栏中点击「快捷指令详细信息」,勾选「作为快速操作使用」下的「服务菜单」,并点击「添加键盘快捷键」按钮,为其分配一个快捷键。

这样,以后就可以在其他应用中选择文本,再从右键菜单的「服务」中选择这个快捷指令(或者按下设置的快捷键),就可以将其 Markdown 版本新建为一条「草稿」了。(你也可以根据自己的习惯调整是否转为 Markdown、文件名模板等具体步骤。)

a3992d6440aa8bad0d72c279ab4d4874.gif

根据相同的原理,还可以再制作一条「将剪贴板内容保存为草稿」的快捷指令(下载)。

381438023620831d817f45379d661449.png

运行效果如下图所示:

ef7c4ea682c7e86c15067048e9c9ceec.gif

在 Windows 上,没有像 macOS 那样可以直接跨应用选中内容的内置机制,但捕获剪贴板还是可以通过 PowerShell 实现的。为此,将下列脚本(注意按实际情况替换其中的路径和配置文件名)保存到一个固定位置:

$note = "X:\path\to\workspace" + $(Get-Date -Format "yyyyMMdd_HHmmss") + ".md"
Get-Clipboard | Out-File -FilePath "$note"
code -r "$note" --profile PROFILE_NAME

例如,我按通例放在用户主目录下的 bin 目录,命名为 clipboard2scratchpad.ps1

然后,在桌面上新建一个快捷方式,填写其目标为:powershell.exe -ExecutionPolicy Bypass -File "X:\path\to\clipboard2scratchpad.ps1"(路径按实际情况替换)。

beef93853b354a2c0bd0f1ec4143944d.png

之后双击即可将剪贴板内容保存为「草稿」。你还可以在快捷方式的属性中为其分配一个快捷键。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK