サポンテ 勉強ノート

サポンテの勉強ノート・読書メモなどを晒します。

CotEditor で開いている書類の diff を取得する【CotEditor】

はじめに

 二つのテキストの差分を調べる diff コマンドですが、いちいちファイルに保存せず手軽に比較したいことがしばしばあります。

 CotEditor で開いている Window から、二つを選択して比較するスクリプトを作ってみました。書類は保存する必要はありません。

 出来上がったものは、正直なところあまり実用的ではないと感じるのですが、まあ役に立つこともあるかもしれないので置いておきます。

使い方

 CotEditor で二つのウィンドウを開きます。

f:id:saponte:20210910203704p:plain

f:id:saponte:20210910203721p:plain

 比較元のウィンドウをアクティブにして、スクリプトを起動します。

 最初に起動した時には、アクセス権の許可確認ダイアログが表示されます。「OK」をクリックしてスクリプトから SystemUIServer.app へのアクセスを許可してください。1

f:id:saponte:20210910203741p:plain

 CotEditor で編集中のウィンドウが一覧されます。そこから比較先のウィンドウを選択してください。

f:id:saponte:20210910203803p:plain

 ウィンドウを選択すると、以下のような diff 結果が新しい書類として開きます。

f:id:saponte:20210910203818p:plain

スクリプト

 CotEditor のスクリプトです。拡張子は .js で、お好みのファイル名でスクリプトフォルダに保存してください。実行権も付与しておいてくださいね。

 二つのウィンドウの内容を標準入力として diff コマンドを実行しているだけです。diff コマンドのオプションを追加したい場合は、ソースコードの中の diff コマンドを実行しているところを探して追記してください。

#!/usr/bin/osascript -l JavaScript

var app = Application.currentApplication();
app.includeStandardAdditions = true;

var cotDocs = Application('CotEditor').documents;

function getDocNameList() {
    var docs = [];
    for (let i = 1; i < cotDocs.length; i++) {
        docs.push(cotDocs[i].name());
    }
    return docs;
}

function getDocIndex(name) {
    for (let i = 1; i < cotDocs.length; i++) {
        if (cotDocs[i].name() == name) {return i;}
    }
}

function chooseDoc() {
    let su = Application("SystemUIServer");
    su.includeStandardAdditions = true;
    su.activate();
    return su.chooseFromList(getDocNameList(), {
        withPrompt: "Which documents do you compare with \n    '" + cotDocs[0].name() + "' ?"
    });
}

// ----- main -----

(() => {
    'use strict';
    
    // check document
    if (cotDocs.length <= 1) {return;}
    
    // choose document
    let doc = chooseDoc();
    if (doc == false) {
        // cancel
        return;
    }

    let cmd1 = "osascript -l JavaScript -e \\\"Application('CotEditor').documents[0].contents();\\\"";
    let cmd2 = "osascript -l JavaScript -e \\\"Application('CotEditor').documents[" + getDocIndex(doc) + "].contents();\\\"";
    let cmd = "/bin/zsh -c \"/usr/bin/diff <(" + cmd1 + ") <(" + cmd2 + ")\"";
    
    let result = "";
    try
    {
        result = app.doShellScript(cmd);
    }
    catch(e)
    {
        // exists diff
        result = e.message;
    }
    
    // new document
    let newDoc = Application('CotEditor').Document().make();
    newDoc.text = result;
    newDoc.selection.range = [0, 0];
    newDoc.coloringStyle = "Diff";
})();

終わりに

 もちろんできれば opendiff コマンド(つまり FileMerge.app)が使えればという思いはありますが、残念ながら同じ方法は使えませんでした。

参考

Google先生も知らないJXAのプライベートメソッド - Qiita

標準入力同士の diff - Qiita


  1. Window 選択ダイアログをアクティブにする処理で使用しています。