この記事は 2016年 Livesense Advent Calendar 17日目の記事です。
まえがき
こんにちは 新卒エンジニアのroana0229 です。
みなさん、iOS開発していますか?
私は、 Xcodeにもどかしい気持ちを抱きながら 楽しく開発しています。
ところで、今年のWWDC2016で「Xcode Source Editor」という
Xcode8から利用できるExtensionが発表されましたね。
Using and Extending the Xcode Source Editor
今までXcodeの拡張といえば、AlcatrazというXcodeのパッケージマネージャでのプラグイン管理が定番でした。
が、Xcode8になり Xcode.appをごにょごにょしない限り 使用できなくなりました。
というのも、今までのプラグインは非公式で開発・公開されていたものであって
安全性が確保されている訳ではありませんでした。
Xcodeの拡張機能をApple公式にサポートしてくれたのは、とても嬉しいことです。
というわけで、Xcode Source Editorを3分クッキング形式で作ってみようと思います。
基本的な開発の仕方についてはググって頂けると、色々記事が見つかるかと思います。
Xcode Source Editor Extensionを作ってみる
作るものをご紹介します
Androidも開発していて、Intellijの操作感が好きなので、その中で簡単そうなものを2つピックアップしてみました。
値を変数に代入する
alt + enter
でコード補完のサジェストを出し、Introduce Local variable
を選択すると
値を変数に代入するようコードに変更がかかります。
またその時、値の型を考慮して補完してくれます、賢いですね。
選択している行を移動する
cmd + shift
で選択している行を上下に動かすことができます。
当然複数行も対応しています。
出来上がったものがこちら
値を変数に代入する
var
,let
を切り替えられるようにしてみました。
変数名もサジェスト機能がほしいところですね。
class LocalVariableCommand: NSObject, XCSourceEditorCommand {
func perform(with invocation: XCSourceEditorCommandInvocation, completionHandler: @escaping (Error?) -> Void ) -> Void {
guard let selection = invocation.buffer.selections.firstObject as? XCSourceTextRange else {
completionHandler(NSError(domain: "IntellijShortcuts-Local-Variable", code: 0, userInfo: [NSLocalizedDescriptionKey: "Invalid Selection"]))
return
}
// ファイルの行全体を取得
let lines = invocation.buffer.lines
// 選択している行を取得
if var line = lines[selection.start.line] as? String {
// 行頭のスペースを変数へ格納
var space = ""
while line.characters.first == " " {
line = String(line.characters.dropFirst())
space += " "
}
if line.hasPrefix("var ") {
// var だったら let に切り替え
let code = line.replacingOccurrences(of: "var", with: "let")
lines.replaceObject(at: selection.start.line, with: "\(space)\(code)")
} else if line.hasPrefix("let ") {
// let だったら var に切り替え
let code = line.replacingOccurrences(of: "let", with: "var")
lines.replaceObject(at: selection.start.line, with: "\(space)\(code)")
} else {
// var <##> = value のフォーマットを挿入する
let code = "var <##> = \(line)"
lines.replaceObject(at: selection.start.line, with: "\(space)\(code)")
}
}
completionHandler(nil)
}
}
選択している行を移動する
当然 まだ複数行選択には対応していません。
が、少しはもどかしさが解消されました。
class LineMoveNextCommand: NSObject, XCSourceEditorCommand {
func perform(with invocation: XCSourceEditorCommandInvocation, completionHandler: @escaping (Error?) -> Void ) -> Void {
guard let selection = invocation.buffer.selections.firstObject as? XCSourceTextRange else {
completionHandler(NSError(domain: "IntellijShortcuts-Line-Move-Next", code: 0, userInfo: [NSLocalizedDescriptionKey: "Invalid Selection"]))
return
}
// ファイルの行全体を取得
let lines = invocation.buffer.lines
// 選択している次の行を取得
if let nextLine = lines[selection.start.line+1] as? String {
// 次の行を削除し、選択している行へ挿入することで下にずらす
lines.removeObject(at: selection.start.line+1)
lines.insert(nextLine, at: selection.start.line)
}
completionHandler(nil)
}
}
class LineMovePreviousCommand: NSObject, XCSourceEditorCommand {
func perform(with invocation: XCSourceEditorCommandInvocation, completionHandler: @escaping (Error?) -> Void ) -> Void {
guard let selection = invocation.buffer.selections.firstObject as? XCSourceTextRange else {
completionHandler(NSError(domain: "IntellijShortcuts-Line-Move-Previous", code: 0, userInfo: [NSLocalizedDescriptionKey: "Invalid Selection"]))
return
}
// ファイルの行全体を取得
let lines = invocation.buffer.lines
// 選択している前の行を取得
if let beforeLine = lines[selection.start.line-1] as? String {
// 前の行を削除し、選択している次の行へ挿入することで下にずらす
lines.removeObject(at: selection.start.line-1)
lines.insert(beforeLine, at: selection.start.line+1)
}
completionHandler(nil)
}
}
できたらみんなに使ってもらおう
実際にApplicationをStoreに公開する手順と代わりありません。
今回は.app
ファイルをexportして、githubにアップする形にしようと思います。
Xcodeメニュー > Product > Archive とするとこんな感じで出来上がります。
画面右の「Export」を押すと、この画面が出ますので「Export as a macOS App」を押す。
あっという間に、IntellijShortcutsApp.app
ができました。
あとはそれを/Applications
に入れて一度だけ起動するとあら簡単、Xcodeで利用できるようになりました。
※他にもいくつか公開の方法はあるようですが、簡単で手間が少ない手順にしました。
最後に
ね、簡単でしょう?
簡単にこういうものが作れるんだよ。と伝われば本望です。
GUI上でカラーコードをまとめられたCrayonsというプラグインが以前あり、
それを作ってみようと思って調べてみたことがこの記事のきっかけでした。
過去にもIntellijのプラグイン(android-xml-sorter)を作ったことがあるのですが、Xcodeも簡単に作れました。IntellijShortcutsApp
残念ながら、Xcode Source Editor Extensionはまだできることも少ないため、開拓されている感じはありません。
(ソースコードエディタ上でしかプラグインを実行できず、GUIに手を出せないのが厳しい…)
もっと、できることが増えてIntellijで使えるショートカットを使えるようになったら嬉しいなあ。
欲を言えば、IntellijでiOS開発できたらもっと嬉しい。
まとめられているものですと、ここに良さげなものがawesome-xcode-extensionsに載っています。
SwiftLintなどはかなり実用的な感じですね。
このExtensionも載るといいなあ。