⚛️

TextMateを使うメモ

2023/06/04に公開

経緯

VSCode が最近重いなと思い始めたので、何か軽量なエディタを探している中、Rails の作者 DHH がいまでも TextMate を愛用しているというのを知って、2023年のいまさらながら TextMate を初めて触りました。
戸惑いながらも次第に愛着が湧いてきて、軽快に動いて自分仕様にできる楽しいエディタだと思いました。
本記事は、諸々の設定をどのように行なうか備忘を兼ねたメモになります。

TextMateについて

https://macromates.com

https://github.com/textmate/textmate

TextMate は Mac専用のネイティブエディタです。最終更新は2021年10月(2023/6/3時点)

2000年代後半から2010年頃に流行ったエディタらしいですが、その後 SublimeText, Atom, VSCode と出てきてかつて TextMate を使っていた人はほぼ全員そっちに行ったらしいです。
なので、Web上で何か調べようと思っても情報が少ないのが現状です。
公式サイトのマニュアル等を見ながら試したことを以下に書きます。

シンタックスの追加

TextMate を単にインストールしただけでは対応していない言語があったり、標準の定義だと不満があるのですが、VSCode用に定義された設定を TextMate に移行(かつては逆が行なわれた)することができます。

どういうことかと言うと、VSCode では各言語の文法は xxx.tmLanguage.json というファイルで定義されていますが、tm は TextMate の略であり、TextMate で使われていたシンタックス定義がそのまま VSCode で採用されています。ファイル形式が違うだけなので json ファイルを plist(XML) に変換すれば TextMate で動きます。

例) VSCode用に書かれたAsciidocのtmLanguage.jsonを持ってくる

Markdownの代わりにAsciiDocをよく使うのですが、TextMate 標準の言語には含まれておらず、 https://github.com/mattneub/AsciiDoc-TextMate-2.tmbundle を追加したのですが埋め込みコードのハイライトが効かないことに不満があり、これをVSCode用に定義されたものに入れ替えようと思います。

変更前シンタックス
標準シンタックスの見た目

Grammarの追加

まず、TextMate側で新しいGrammarを追加します。
メニューの [Bundles] から [Edit Bundles...] を選びます。
Bundleの編集画面が表示されるので追加したいBundleを選択(ここでは [AsciiDoc] に移動)し、cmd + N を押します。
するとキャプチャのようにダイアログが出るので、[Grammar] を選びます。
New Grammar
Bundleの編集画面が [Grammar] を追加

[AsciiDoc] 配下に新しいファイルができました。
できたファイルを選択して cmd + S で保存し、右クリック の [Show xxx in Finder] で保存場所を開きます。

新規 Grammar の保存場所を Finder で開く


Finder から xxx.tmLanguage を何かしらのエディタで開く

そのファイルを何かしらのエディタで開き、ファイル最下部のuuidの部分をコピーして控えます。

xxx.tmLanguage
	<key>scopeName</key>
	<string>text.asciidoc</string>
	<key>uuid</key>
	<string>A2AE6D21-3F08-4978-ADF3-55B5AD580921</string>
</dict>

JSONをplist(XML)に変換する。

参考

今回使用する VSCode 用のシンタックスは asciidoctor が出しているものにします。
https://github.com/asciidoctor/asciidoctor-vscode/blob/master/syntaxes/Asciidoctor.json

$ wget https://raw.githubusercontent.com/asciidoctor/asciidoctor-vscode/master/syntaxes/Asciidoctor.json
$ plutil -convert xml1 Asciidoctor.json -o Asciidoctor.plist
$ cat Asciidoctor.plist | pbcopy

json ファイルを plutil コマンドで変換してできた中身を
先ほどエディタで開いた xxx.tmLanguage に貼り付けます。
その後、控えていたuuid

<key>uuid</key>
<string>A2AE6D21-3F08-4978-ADF3-55B5AD580921</string>

の部分を </dict> の直前に差し込んで保存します。

するとBundle編集画面にも変更が反映されています。
(※表示名もXML内で定義されていた内容に変わるので、別名にしたかったら画面から修正します)

tmLanguageを編集後のBundle編集画面

元々あった方とAsciiDocのシンタックスが競合するので、元の方は右側の編集フォームで [Enable this item] のチェックをOFFにします。

エディタを確認すると、無事埋め込みコードもハイライトされるシンタックスになりました。


Asciidoctor シンタックス追加後の見た目

テーマの追加

githubでそれなりの数のテーマが公開されているので、気に入ったものがあればまずはそこから追加したらよいと思います。
https://github.com/filmgirl/TextMate-Themes
各テーマの見た目はここから確認

上記から xxx.tmTheme ファイルをダウンロードし、TextMate に追加します。

追加する手順は、
メニューの [Bundles] から [Edit Bundles...] を選び、Bundleの編集画面がで [Themes] に移動します。
何か適当なテーマを選択して 右クリック の [Show xxx in Finder] でテーマの保存場所を開いて、先ほどダウンロードした xxx.tmTheme ファイルを追加すればよいです。


Finder で Themes.tmbundle を開き、xxx.tmTheme ファイルを Themes フォルダに追加する

Theme の自作

自分で一からテーマを作成するには、
Bundleの編集画面で cmd + N を押下 [Theme] を選択します。

おおまかに下記の項目について色を設定できます。

  • comment
  • constant
  • entity
  • invalid
  • keyword
  • markup
  • meta
  • storage
  • string
  • support
  • variable

scope に設定したい対象を書くことでスタイルを適用できます。
. をつなげることでより詳細に設定できます。

Custom.tmTheme
{ name = 'Entity';
  scope = 'entity';
  settings = {
    fontStyle = '';
    foreground = '#FDFF9A';
  };
},
{ name = 'Type name';
  scope = 'entity.name.type';
  settings = {
    fontStyle = 'underline bold';
    foreground = '#FFB3E9';
  };
},

詳細は公式を参照
(https://macromates.com/manual/en/language_grammars#naming_conventions)

例) テーマを編集してHTMLのdata-x属性だけ色を変える

特定のキーワードのみ色を変えたいとします。
例えば、HTMLのマークアップでdata-x属性だけ特殊な意味があるので色を変えたいなど。


標準テーマの見た目

元の設定のままだとclass属性などと同じ見た目で埋没しているので目立たせたいです。
目立たせたいキーワードにスタイルを適用できるかどうかはその言語のGrammarでキャプチャしているか次第ですが、幸いHTMLのGrammarでは下記のようにキャプチャしていました。

HTML.plist
{ name = 'meta.attribute.data-x.$1.html';
  comment = 'HTML5 attributes, data-*';
  begin = '(data-[a-z\-]+)(?![\w:-])';
  end = '(?=\s*+[^=\s])';
  beginCaptures = { 0 = { name = 'entity.other.attribute-name.html'; }; };
  patterns = ( { include = '#attribute-interior'; } );
},

なので、下記のような設定をテーマに追記することでHTMLのdata-x属性だけ色を変えることができました。

Custom.tmTheme
{ name = 'HTML data-xxx attributes key';
  scope = 'text.html meta.attribute.data-x > entity.other.attribute-name.html';
  settings = { foreground = '#DCF710'; };
},


設定追記後のテーマの見た目

スニペットの自作

スニペットを作成するには、
Bundleの編集画面で cmd + N を押下 [Snippet] を選択し作成します。
作成したら、[Scope Selctor] に設定したい言語の対象を記述。
[Tab Trigger] に tab キーで展開する際のキーワードを書きます。
カーソル位置は $0, $1, $2 のように書くと $1 から順にカーソル位置が決まり。tab キーで次の数字のカーソル位置に移動できます。最後は $0 になります。
簡単です。

参考 https://macromates.com/manual/ja/snippets


スニペット(attr_accessor)

ファイル名でスニペットの出力結果を変える

もう少し手の込んだスニペットを登録したいとします。
例えば、自分は仕事で Rails を使うので、RSpec で以下のような形のテストコードを書くことが多いです。

app/models/user_spec.rb
describe '#inactive?' do
  subject { user.inactive? }
  let(:user) { create :user, active: false }
  it { is_expected.to eq true }
end
  • describe の後に #method_name
  • ブロックの先頭に subject { model_name.method_name }
  • let(:model_name) { create :model_name } でレコードの生成

という決まったルーチンがあります。
これをスニペットで #method_name の部分を $1model_name の部分をファイル名から初期値を取得して $2 としたいとします。

以下のようにスニペットを登録します。

describe '#${1:some_method}' do
  subject { ${2:${TM_FILENAME/([A-Za-z0-9]+)(?:(?:_spec)?\.[a-z]+)*/(?2::$1)/g}}.$1 }
  let(:$2) { create :$2$3 }
  $0
end
  • ${1:some_method} のようにコロン : をつけると後続の文字列が初期値として出力されます。
  • 同じ内容を反映させたい $1$2 はそれぞれ2箇所に書くことで入力をミラーリングします。
  • TM_FILENAME という変数でファイル名を取得できます。抜き出した文字は / で続けることでフォーマットできます。
    (参考 https://macromates.com/manual/ja/snippets)

そうすると、以下のように動きます。

スニペットにプルダウンの選択肢を表示する

似たような形だけど、一部分だけ違うものを出力したいとします。
例えば、リクエストスペックの describe 'GET /users' と書いたら subject { get users_path, params: params } としたいけど、POST なら post users_path に一緒に変わって欲しいなど。

app/models/user_spec.rb
describe 'GET /users' do
  subject { get users_path, params: params }
  let(:params) { {} }
  it '...'
end

describe 'POST /users' do
  subject { post users_path, params: params }
  let(:params) { {} }
  it '...'
end

以下のようにスニペットを登録します。

describe '${1|GET,POST,PUT,DELETE|} /${2:${TM_FILENAME/([A-Za-z0-9]+)(?:(?:_spec)?\.[a-z]+)*/(?2::$1)/g}}' do
  subject { ${1/(.+)/\L$1/g} ${3:${TM_FILENAME/([A-Za-z0-9]+)(?:(?:_spec)?\.[a-z]+)*/(?2::$1)/g}_path}, params: params }
  let(:params) { {$4} }
  $0
end

${1|GET,POST,PUT,DELETE|} のようにパイプ | でつなぐことで、スニペットを起動時にプルダウンが表示されてそこから選べるようにできます。

コマンドの自作

TextMate では shellscript もしくは Ruby でコマンド(マクロ)を書けます。
Ruby が使えるのでいろいろできそうな気がしますね。

追加するには、
Bundleの編集画面で cmd + N を押下 [Snippet] を選択し作成します。
作成したら、[Scope Selctor] に設定したい言語の対象を記述。
[Key Equivalent] にショートカットキーを登録
[Input] と [Output] で、何を入力としてどこに出力させるかを設定します。

例) 選択行の git のコミットメッセージを表示して、SHAをクリップボードにコピーする。

  • [Key Equivalent] に ^B
  • [Input] に Selection 、[Format] に Text
  • [Output] に Show in Tool Tip 、[Format] に Text
    して、下記のコードをスニペットとして設定します。
#!/usr/bin/env ruby18 -wKU

line = ENV['TM_LINE_NUMBER'].to_i
command = "git blame -w -L #{line},#{line} #{ENV['TM_FILEPATH']}"
# puts command
# puts `#{command}`
sha = `#{command}`[/(\w+)/, 1]
# puts "[#{sha}]\n" + `git show -s --format=medium #{sha}`
puts `git show -s --format="[%h] %ar[LINEBREAK]  %an <%aE>  [LINEBREAK]---[LINEBREAK]  %s    [LINEBREAK]---" #{sha}`.gsub('[LINEBREAK]', "\n")

if sha && !sha.empty? && sha != '00000000'
  system("echo #{sha} | tr -d '\n' | pbcopy")
  puts "SHA copied to clipboard!"
end

git blame したい行で ctrl + B を押すとツールチップが表示されて、裏ではコミットSHAがクリップボードにコピーされました。(その後 git show したいときなどに使用する想定)

おわり

以上で TextMate のだいたいのカスタマイズはできるようになります。

ここでは触れませんでしたが、VSCode に慣れていたのでショートカットキーの違い(※ファイルを開くのは⌘Pではなく⌘T、インデントはtabではなく⌘]であるなど)に戸惑いました。
設定で変更できそうな気がしたんですが、よくわかりませんでした。結果、これはこれで慣れてしまったのでまあいいかと思ってます。

TextMate はいいぞ。

Discussion