编写插件

教程
作者:Jan Gerner
en zh

1 八月 2022 发布日期: 11 一月 2016

Plug-ins offer additional features to software applications, usually provided by third parties. This overview covers plug-in development for Glyphs 2.3 or later. Don’t be shy, grab a cup of great coffee, and relax: Others have done it before you.

插件会为软件提供额外功能,通常是由第三方提供的。本教程供你概览如何进行插件开发。你可以在我们 GlyphsSDK 库中的 Readme.md 里找到详细的描述。

别害羞,拿一杯上好的咖啡,放松:前人已经做过不少了。

1. 获取插件模板

我们在 GitHub 页面上提供多种用途的插件骨架(例如文件导出、自定义轮廓滤镜等)。如果你对 Git 已经熟悉,你可以在你最喜欢的版本管理软件中查看文件结构(Git 自己的,或者很多其他可用软件中的某一款。虽然 Versions.app 是一个 SVN 客户端,但本教程作者依然推荐使用它)。

如果你不熟悉代码版本管理的概念,或者只是其他人代码的用户而已,你也可以直接从 Glyphs SDK 主页下载包含整个 Glyphs SDK(软件开发套件)的 ZIP 压缩包。

专业提示:请让自己适应代码版本系统。你以后在工作中的各个领域都会有所受益的。

所以,我们的 SDK 页面在这里:https://github.com/schriftgestalt/GlyphsSDK,插件模板在 Python Templates 子文件夹中。在这里,你会找到一系列插件骨架,等你去赋予生命。每个插件模板都包含全功能的示例代码,以便于理解。

  • File format:文件格式。导出你自己的字体格式。
  • Filter without dialog:不带对话框的滤镜。通过 “滤镜” 菜单,或在字体导出时修改字体。
  • Filter with dialog:带对话框的滤镜。和前一条相同,但带有用户界面对话框。
  • General plug-in:通用插件。没有特别的目的,我们看看能发生什么。
  • Palette:右边栏面板。向右侧边栏中添加一个面板显示。
  • Reporter:汇报器。在 “编辑视图” 和 “预览” 区域中绘图,用于可视化字符形的特征。
  • Select Tool:选择工具。使用自己的功能来增强 “选择工具”。

对于 Glyphs.app,插件以 Mac 系统的所谓 “包” 的形式存在,它们需要被放在 Glyphs 的 “Plugins” 文件夹中,位于 ~/Library/Application Support/Glyphs/Plugins 路径下(~ 代表用户账户的个人文件夹)。如果你将插件文件拖动到 Glyphs 软件图标上,或者通过双击来打开,Glyphs 会自动将其放到上述文件夹中。这些 “包” 的外观和行为和 “访达” 中的单个文件一致,但它们实际上是文件夹,你可以通过在 “访达” 中右键单击这样的文件,选择 “显示包内容” 来访问其中的文件。

下图为这样一个插件文件夹看上去的结构。你的主要代码在 Contents/Resources/plugins.py 文件中。其他值得注意的文件有,包含插件各种相关信息的 Info.plist,以及对于带对话框的插件,还有两个包含用户界面对话框视图的 .nib/.xib 文件。

当今的很多文本编辑器会同时打开整个文件夹,让你能够在同一个面板中以看到文件的树状结构。所以你可以在你的文本编辑中一次打开整个 .glyphsFilter 文件包:

目前,用于这种用途的、最流行的文本编辑器是 TextMateSublimeTextAtom

2. 重命名几个 ____Names____

我们 GitHub 库中的 Python 模板 页面里,包括了如何设置插件文件结构的详尽信息。你需要在这最多三个文件中重命名所有带 “四重下划线” 的内容(比如 ____PluginClassName____)。

对于插件名称,我们要处理两个不同的名称变体:

  • ____PluginName____ 是出现在软件中某些位置的、人类可读的名称,比如在 Glyphs “偏好设置” 窗口的 “插件” 选项卡中。这一名称可以带有空格和 Unicode 字符。
  • ____PluginClassName____ 是你代码中机器可读的 Python 类名称,会出现在几个地方。它需要是独一无二的,你不能同时安装两个类名称相同的插件。尽管我说是 “机器可读”,但用户在一个特定的交互中也会看到插件的这个名称:通过自定义参数在导出时调用滤镜。所以请为其取一个友好而独特的名字。这里只允许出现 ASCII 字符,不能有空格。我们建议使用驼峰式大小写(形如 camelCaseNames)。

Info.plist 中的一节会告诉 Glyphs 在哪里查找你插件的更新,以便在更新可用时通知用户。要实现这一功能,你需要插入一个指向在线 Info.plist 文件的 URL 链接, 其中包含当前版本号。这可以是一个手动编辑的文件,也可以是自动生成的,比如来自在线商店,或着也可以是和下载版插件中的 Info.plist 完全一样的文件。

如果使用 GitHub 分发,你的 Info.plist 文件链接会是:https://raw.githubusercontent.com/*user*/*plugin*/master/*filename*/Contents/Info.plist。用你的 GitHub 用户名替换 *user*,用 GitHub 库名称替换 *plugin*,用插件名称带上后缀来替换 *filename*,比如 MyPlugin.glyphsFilter

现在,是时候读一下 Python 模板页面的详细内容了。

3. 使用 Interface Builder 创建对话框

某些类型的插件可以在 Glyphs.app 中打开对话框:

和 Glyphs 中的所有应用一样,我们使用 Apple 自家的 Cocoa 来创建对话框,特别是 Interface Builder。为此你需要安装 Apple 的 Xcode,可以从 AppStore 免费下载。如果你还没有拥有它,请寻找一处网速够快的地方开始下载。它有 4 GB 大。

如果你想使用 Tal Leming 的 Vanilla 库,你会在所有带对话框插件的 Readme 文件中找到有用的信息。

你的 Python 代码和 Cocoa 用户界面通过 IBOutlets(代码到界面)和 IBActions(界面到代码)互相交流。

它们在 Python 代码中的定义如下所示。IBOutlets 被定义为像这样的类变量:

class CSVFileExport (FileFormatPlugin):
    textField = objc.IBOutlet() # 界面中的一个文本框

IBActions 为类方法,带有 @objc.IBAction 前缀:

    @objc.IBAction
    def buttonClicked_(self, sender):
        # 按钮点击时执行

这是你在 Xcode 的 Interface Builder 中创建对话框时的样子:

所有必要细节都在 Python 模板页面中详述。请通读逐步指南,船到桥头自然直。

4. 分步指南

应对每种插件的方法,都在相应插件的 GitHub 页面中详细描述:

5. 插件管理器

完成后,你就可以让插件通过 “窗口 > 插件管理器” 中简便安装(Glyphs 2.3 或更新的版本)。为此只需给 glyphs-packages 库中的 packages.plist 文件提交拉取请求(pull request)即可。你需要做的,只有在那个文件中添加这样几行:

{
    name = "PluginNameWithExtension.glyphsPlugin";
    url = "https://github.com/userName/repositoryName";
    description = "Single-line description. Careful: WITHOUT LINEBREAKS! Use \n instead.";
}

条目间必须由逗号分隔。所以,如果这段代码之后还有一个条目,别忘了在花括号 } 后添加逗号。(如果这段代码之前还有,就在前面一行加上逗号。)条目间的顺序没有关系,插件管理器会按首字母顺序排列所有注册的插件。

还有一些选项可供你的条目使用,比如指定一张截图,或是最低/最高版本。请确保读过 glyphs-packages readme 文档以便了解全部细节。

祝贺你

就是这样了!这应该可以帮你开始你的 Glyphs 插件。如果你在哪里卡住了,请尽管在我们的论坛中询问。


Jan Gerner (Yanone) 撰写,Rainer Erich Scheichelbauer 编辑。


2018-11-18 更新:修正少量录入错误。

Chinese translation by Willie Liu (刘育黎) and Stone Zeng (曾祥东) from 3type (三言).