使用 Xcode Source Editor Extension开发Xcode 8 插件
前言
Xcode是一个每天都有成千上万开发者使用的IDE( 集成开发环境),它是一个非棒棒的工具,但是有时候为了提高开发效率你可能想自定义一些它的特性和行为。
在Xcode 7的时候,开发者可以在Xccode运行的时候通过注入代码去实现插件的功能。插件可以在一个Alcatraz这个优秀的APP上面提交和分发。不过这一切在在Xcode 8上已经不再可能。
Xcode 8验证每个库和包以防止恶意代码未经您的许可运行。当Xcode启动的时候,先前通过Alcatraz安装的插件不会再被加载。不是一切都没有了,苹果公司在今年的WWDC上宣布了可以通过开发Xcode source editor extensions使得每个人都可以扩展现有的源代码编辑功能。让我们一起来看看通过这些扩展我们能做什么。
1. 好的开端
Xcode 8 source editor extensions 是一个好的开始。如果你使用Xcode工作了一段时间,你可能会迫切地希望一些具体的工作可以在Xcode里面自动完成。Source editor extensions允许第三方应用程序去修改源文件,这可以帮助你提高工作效率。
现阶段,extensions只能和源代码交互。这就意味着不是每一个Alcatraz的插件都可以被source editor extension取代。但是谁知道未来会带来什么?(译者注:作者的意思苹果会不断完善这个功能的)。
每个extension都必须要要包含在一个macOS app里面。比如,你可以给你的extensions添加偏好设置和关于它可以用来做什么的解释说明,然后你可以把它提交到Mac App Store。还要注意的是,每个extension运行在独立的进程里面,如果extension崩溃了,Xcode不会崩溃,不过它会提示一个信息表明extension不能完成它的工作了。
此外,extensions还没有UI交互,它们仅仅能够直接的修改代码当开发者调用相关命令的时候。比如它们不能在后台运行。
我建议观看 WWDC 2016 session about source editor extensions,它不仅仅解释了如何开发 Xcode source editor extensions,同时也展示了一些技巧和快捷方式去加速开发。
2. 概述
在这个教程中,我们将开发一个extension用于清楚Swift语言中的闭包语法。Xcode自动使用括号完成了一个闭包语法。不过为了简单起见,我们可以省略它们。这个任务是很容易自动完成的如果把它封装到source editor extension里面。
我们到底要开发什么呢?简单的解释就是实现一个可以把闭包转化为更简单更清洁语法的extension。下面来看一个具体的例子。
|
|
3. 安装工程
首先,需要安装Xcode 8,可以从Apple’s developer website下载。Xcode 8在OS X 10.11和macOS 10.12都可以运行。
创建一个新的类型为 Cocoa Application 的OS X项目,项目命名为 CleanClosureSyntax 。确保你是选择的语言是 swift,因为在这个教程中将会使用 Swift 3 。
创建好项目之后,我们把注意力集中到创建 Xcode source editor extension上面来。打开File菜单,选择New->Target,在左边的面板上,选择OS X然后从列表中选择 Xcode Source Editor Extension
点击Next然后设置Product Name为Cleaner,如果Xcode提示你新创建的Scheme是否需要激活,点击Activate激活Scheme。
4.项目结构
我们一起来分析一下Xcode给我们创建了什么。打开Cleaner去看它包含些什么。
该教程中,我们不会修改 SourceEditorExtension.swift ,但是如果以后你要更进一步的自定义extension的话,可能会使用到它。extensionDidFinishLaunching()
在extension启动的时候会被调用,如果需要的话开发者可以在此方法里面做一些初始化的东西。commandDefinitions
属性的getter方法可以在动态的展示或是隐藏特定的指令的时候使用。
SourceEditorCommand.swift是整个extension的核心。在这个文件里面可以实现extension的相关逻辑。perform(with:completionHandler:)
方法在用户启动你的extension的时候被调用。XCSourceEditorCommandInvocation
对象包含了一个buffer
属性,这个属性主要是用来访问当前选中文件的源代码。如果一切顺利的话,completion handler
将会以参数为nil
进行调用,否则将会给它传递一个NSError
实例。
5. 实现extension
现在工程里面已经包含了所有需要的targets,我们将要开始开发extension。概况的说,我们将要移除Swift文件中所有闭包里面的括号。主要分以下三步:
- 找到包含闭包的行
- 从特定的行里面移除两个括号
重置被修改的行(译者注:原文是substitute back the modified line ,结合代码感觉重置比较恰当)
我们可以使用正则表达式去遍历每一行代码是否含有闭包。如果你想进一步学习正则表达式可以参考Akiel的教程Swift and regular expressions 。开发者可以使用RegExr 去测试正则表达式。看下面的截图看看我是怎么测试正则表达式的。
打开SourceEditorCommand.swift 文件修改` perform(with:completionHandler:) 方法为如下
|
|
找到使用闭包的行
首先创建了一个Int
类型的数组用于存储我们修改过的行。这样我们就不需要更新所有的行,我们只需要替换掉被修改过的行。
枚举invocation.buffer
对象中所有的行,找出和RegularExpression
匹配的对象的。移除掉正则表达式中的转义字符,正则表达式如下:
|
|
正则将会匹配当字符串包含如下特性的时候
- 有一个花括号(
{
),后面跟着若干个字符但是不包括换行符(\n
)。 - 需要有一个开括号(
(
),后面跟着若干字符,该部分包含的是闭包的参数。 - 然后需要有一个闭括号(
)
),后面跟着若干字符,这部分字符是可选返回类型 - 最后关键字
in
需要找到
如果RegularExpression
对象匹配失败,则在调用completionHandler
时把error作为参数。如果某一行字符串匹配所有的条件,那就说明闭包已经找到。
移除闭包里面括号
当满足条件的闭包被找到后,调用NSString
里面的工具方法去移除括号。在调用的时候需要传入闭包的范围(译者注:就是NSRange)从而避免移除闭包之外的其他括号。
更新行
最后一步代码检查是否至少有一行被找到。如果条件成立,调用setArray()
在正确的位置重置新的代码。此时,传入nil
作为参数调用completionHandler
,这样Xcode便知道extension完成了正确的工作。
最后,实现NSString
的remove(characters:range:)
方法。添加NSString
的extension
(译者注:此处的extension不同于本文一直讲解的extension,此处是Swift的一种基本语法,是类的扩展)到文件里面。
|
|
6. 测试
Xcode 8 带来了一个非常优秀方法用来测试extensions。首先,如果如果你的Xcode是运行在 OS X 10.11 El Capitan的话,打开Terminal,执行下面的命令,然后重启Mac。
|
|
做完以上工作后,选择正确的scheme后编译运行extensions。当询问你去运行哪一个App的时候,查找Xcode并且确保选择了Xcode 8 Beta版本(译者注:作者写此文章时候正式版还没有发布),一个新的灰色图标Xcode被打开,这样可以便于开发者区分哪一个Xcode是用来测试extension的。
在新的Xcode实例中,创建一个新的工程或是打开一个存在的工程。然后执行Editor > Clean Closure > Source Editor Command,需要确保在当前的文件里面含有一个闭包。这样就可以看到如下的效果,刚才开发的extension工作了!
Source Editor Command是命令默认的名字。开发者可以在extension的Info.plist文件里面修改。打开之后修改为 Clean Syntax。
当然,同样可以设置设置快捷键去自动调用Clean Syntax命令。打开Xcode的Preferences,选择Key Bindings 。搜索Clean Syntax,可以看到命令出现了,点击它的右边然后输入你想使用的快捷键,例如:Command-Alt-Shift-+。现在,回到源文件,然后使用快捷键就可以直接调用它了。
7. 技巧和窍门
Xcode 8和source editor extensions 依然在测试阶段。下面的一些方法可能会帮助你调试一些你遇到的问题。
如果你的extension在Xcode的测试实例中变得不可选择,杀掉com.apple.dt.Xcode.AttachToXPCService进程然后再次运行extension
仅重置缓存区里面修改过的行,这使得extension运行得更快而且不容易被Xcode杀掉进程。如果Xcode检测到你的extension花费太长时间的话有可能会杀掉它。
如果想集成多个命令,那就必须分配给每个指令不同的标识,然后使用XCSourceEditorCommandInvocation
对象的commandIdentifier
属性来识别用户触发的是哪一个。
总结
创建 Xcode source editor extension 是非常容易的。可以通过创建source editor extension去提高开发的效率,开始吧,动手去做。苹果公司引入了新的方式,广大开发者可以分享签名过的插件通过Mac App Store,这样一方面减轻了自己的工作,另一方面也可以让其他开发者从中受益。
该教程的代码地址: GitHub
原文地址
译者补充说明:目前Xcode8很不稳定,我自己在测试的时候Editor下面的命令选项时有时没有。还需要继续跟进和研究,
作者: joyseedog
链接: http://www.iseedog.com/2016/09/21/xcode-source-editor/
本文采用知识共享署名-非商业性使用 4.0 国际许可协议进行许可