NOTE: swiftformatについてのメモ

インストール方法や設定方法は公式サイトを見るなりググれば大量に出てくるのでそちらを見てください。 私はhomebrewでインストールしました。

車輪の再発明かもしれないけどswiftformatを使いやすくするための小さなスクリプの紹介です。

目的はXCodeから手軽にformatをするために以下の機能を持っています。

  1. XCodeからメニューで選べる

  2. ショートカットキーを設定出来る

  3. ファイルに保存前の編集中のバッファに適応できる

  4. Undo/Redoできる

  5. プロジェクト毎のconfigファイルを自動で読み込んで適応できる

  6. ファイル単位で適応できる

以下の機能は不要と思われるので作らなかった

  1. 選択範囲だけの適応

  2. プロジェクト全体に適応

スクリプト

以下はそのスクリプト

#!/usr/bin/osascript

use framework "Foundation"
use framework "AppKit"
use scripting additions

-- 定数定義したい
property NSString : a reference to current application's NSString
property NSPasteboard : a reference to current application's NSPasteboard
property NSPasteboardTypeString : a reference to current application's NSPasteboardTypeString

tell application "Xcode"

    activate
  -- エラー処理 1個もドキュメントがない
  if (count of documents) is 0 then
    display notification "ファイルが指定されてないです"
    beep
    return
  end if


  -- ドキュメントファイルへのパスを取得したい
  -- 方法は現在XCodeで最も前面に出ているWindowのタイトルを取得し、そのタイトル名から
  -- ドキュメントを特定し、特定したドキュメントからファイルパスを取得する
  -- AppleScriptの文字列とNSStringを行ったり来たりしてるのは単純に私のAppleScriptの技術不足

  -- 最前面のwidnowを取得
  set mainWindow to window 1

  -- 最前面のWindowのタイトルを取得
  set mainWindowTitle to mainWindow's name

  -- Windowのタイトル文字列を区切り文字列で分解する。NSStringに変換して便利なメソッドを使う
  set theWindowTitle to NSString's stringWithString:mainWindowTitle
  set theWordList to theWindowTitle's componentsSeparatedByString:" — "


  -- 末尾がEditedの場合は編集中なので後ろから2番目がドキュメント名と仮定する
  -- それ以外は末尾がドキュメント名と仮定する
  if ((item -1 of theWordList) as string is "Edited") then
    set theDocumentName to (item -2 of theWordList) as string
  else
    set theDocumentName to (item -1 of theWordList) as string
  end if


  -- 名前が一致するdocumentを探し出す
  set theCurrentDocument to document 1 whose name ends with theDocumentName

  -- エラー処理
  if theCurrentDocument is -1 then
    display notification "そんなドキュメントはないです"
    beep
    return
  end if


  -- ファイルパスを取り出す
  set theCurrentDocumentPath to path of theCurrentDocument

  -- エラー処理
  if theCurrentDocumentPath is "" then
    display notification "ファイルに結び付けられていないDocumentです"
    beep
    return
  end if

  -- 拡張子とファイルがあるディレクトリへのパスを取り出す
  set theFilePathString to NSString's stringWithString:theCurrentDocumentPath
  set theExtension to theFilePathString's pathExtension as string
  set theDirectoryPath to theFilePathString's stringByDeletingLastPathComponent as string
  set theFileNameString to theFilePathString's lastPathComponent as string

  -- エラー処理
  if theExtension is not "swift" then
    display notification "拡張子がswiftではないです"
    beep
    return
  end if


  -- 既存のペーストボードデータを破壊しないようにデータの保存
  set savedClipboard to the clipboard

  set thePasteboard to NSPasteboard's generalPasteboard()
  thePasteboard's clearContents()
  thePasteboard's setString:(theCurrentDocument's text) forType:NSPasteboardTypeString

  -- unix shell スクリプトを使うのはcurrent directoryの設定ファイルを使わせるため
  -- 標準入出力を使うだけだと設定ファイルを無視するのでstdinpathでファイル名を渡してます
  set theOutput to do shell script "cd " & theDirectoryPath & "; pbpaste -Prefer txt | /opt/homebrew/bin/swiftformat stdin --stdinpath " & theFileNameString & " | pbcopy"

  -- キーコマンドは送信しているが動作が安定しない
  tell application "System Events"
    tell process "Xcode"
      keystroke "a" using command down -- select all
      keystroke "v" using {command down, option down, shift down} -- cmd opt shift paste スタイルを維持してペースト
      delay 0.5 -- clipbardの内容を同期させるに必要らしい
    end tell
  end tell

  -- 既存のペーストボードデータを破壊しないようにデータの復帰
  set the clipboard to savedClipboard

end tell

上記のスクリプトファイルを適当な場所に置おく。XCodeからアクセスできる場所ならばどこでも良い。 2つの設定ファイル.swiftformatと.swift-versionの設定はググってください。

XCodeから呼び出すための設定

以下はこのスクリプトをXCodeに設定してメニューから呼び出したりショートカットをつけられるようにする方法です。

対象のファイルを編集中にXCodeのBehaviorからスクリプトを呼び出すことでswiftformatを呼び出せます。

Xcode ‣ Behaviors ‣ Edit Behaviors... でBehaviorsの編集Windowを呼び出して以下の画面を出す

../../../_images/250904SS1.png

左下の+ボタンを押して custom behavior を新規に作る

../../../_images/250904SS2.png

右側のゴチャゴチャした部分を下にスクロールして最後の Run Script のチェックを入れる。ファイルを選ぶボタンを押して上記のスクリプトファイルを選ぶ。

ここでAppleScriptのファイルが選べないことがあった。どうやって選択したかは覚えていないので各自工夫してください。

../../../_images/250904SS3.png

最後に項目名の右側をクリックしてキーボードショートカットを決める。

../../../_images/250904SS4.png

あとはAppleScript経由でXcodeを操作するためにXcodeのアクセサビリティを許可する必要があったはず。が、どこで設定したかは忘れた。

使い方は簡単で以下の2ステップ

  1. formatするファイルを開いてEditorにフォーカスを合わせる

  2. behaviors メニューから選ぶかショートカットキーを押す

通常はテキスト編集中に呼び出すのでショートカットを押す1ステップで機能するはず。

感想

私はソースコードの整形ツールはコードを編集しながら使うものだと思っています。 しかしググった結果はそのような使い方をしている人は居ないようでビルド時やコミット時に整形ツールを呼び出すのが標準的な使い方のようでした。

また受託開発のお仕事などでは formatting rule はプロジェクト毎に変わるのが当たり前だと思うのですが、Xcode extension を使う場合は プロジェクト毎に formatting rule を変更するのではなくて最後に読み込んだ設定が有効になるようでした。

上記の2つの事は単純に実装上の問題なのか開発スタイルの問題なのかはわかりませんが私のスタイルには合わないのでこのスクリプトを書きましたが私が何か見落としているのかもしれない。

Comments

comments powered by Disqus