いわゆる、ひとつの答え

風邪です。風邪。もう、しんどーい。

さて、以前に掲載した問題ですが、掲示板の方でお答えをいただきました。どうも、ありがとうございました。返答が長くなるのでこちらで答えさせていただきます。

『エディタごとに Wrapper となるスクリプトオブジェクトを用意する』(注、意訳。原典は、掲示板の方を)、というのが頂いた答えでした。書いてくださった方も常套手段と書かれているように、おそらく基本的な解答なのだと思います。

では、問題を作ったときに私が作ったスクリプトを掲載しておきます。

script QuoEdit
    on selectedText()
        tell application "QuoEdit"
            text of selection
        end tell
    end selectedText
end script

script CotEditor
    on selectedText()
        tell application "CotEditor"
            contents of selection
        end tell
    end selectedText
end script

script KEdit
    on selectedText()
        tell application "KEdit"
            selected text of front document
        end tell
    end selectedText
end script

script EnhanceEditor

    on currentEditor()
        tell application "System Events"
            return ((name of processes whose frontmost is true) as Unicode text)
        end tell
    end currentEditor

    on selectedText()
        set apps to currentEditor()
        if apps is "QuoEdit" then
            selectedText() of QuoEdit
        else if apps is "CotEditor" then
            selectedText() of CotEditor
        else if apps is "KEdit" then
            selectedText() of KEdit
        else
            return ""
        end if
    end selectedText
end script

display dialog (EnhanceEditor's selectedText())

ラッパーとなるスクリプトオブジェクトを用意して...というのはこういう感じでしょうか?

おそらく、こういう形が基本的かと思います。ただ、もっと簡潔に簡要に簡便に書けないものなのかと思うのです。例えば、このスクリプトの EnhanceEditor オブジェクトの selectedText() は、if 文が続きます。対象とするエディタが増えるとそれだけ if 文が増えます。どう考えても、不細工です。問題として提起したのは、この if 文が引っかかったからなのでした。もっとスマートな書き方があるはずだ、と。

引き続き、この問題に対する答えは受け付けています。iTMS カードは、やっぱりないですが(笑

「仕方ないな...このサイトの管理人はこんなことも分からないのか。手間がかかるが教えてやろう」という気骨のある方、どうかよろしく。

問題

まずは、前振り。うちの環境には CotEditorQuoEditKEdit と、3 種類のテキストエディタが入っています。もちろん、どのエディタも利用していますし、Mac OS X に標準で入っている TextEdit も(ホンットに、時々)利用しています。

全部で 4 種類ですね。どれも AppleScript に対応しています。当然、機能の拡張は AppleScript で行っています。

どれも AppleScript に対応している...のですが、それぞれ個性があります。例えば、選択文字列の取得。まずは、QuoEdit。

tell application "QuoEdit"
    set curSelection to selection of front document
    -- every text of document 1 of application "QuoEdit"
    text of curSelection
    -- "選択文字列"
end tell

次に kEdit。

tell application "KEdit"
    selected text of front document
    -- "選択文字列"
end tell

そして、CotEditor。

tell application "CotEditor"
    contents of selection
    -- "選択文字列"
end tell

いずれも、選択している文字列(参照ではない)を取得するスクリプトですが、微妙に異なっています。QuoEdit の selection は、application、document クラスなどで利用できます。なので、たんに selection とすると状況により結果が異なる場合があります。kEdit は、選択している文字列は書類のもの、ということで document クラスの属性になっています。CotEditor は、application クラスの属性として用意されています。application クラスだから、例えば、検索パネルを表示して検索文字を入力してから selection とすると、その入力した検索文字が返ってくるかと思ったのですが、そうではないようです(意地悪で言っているのではありません)。

どのクラスでどの属性が定義されているか、この辺りに作者それぞれの考えが反映されていてなかなか面白いものがあります。が、ここではその考えを追うことはしません。

ここからが問題です。

現在作業中のエディタをスクリプトで判断し、それぞれのエディタに応じた方法で選択した文字列を取得するにはどうすればいいか?

例えば、CotEditor で作業をしているなら contents of selection とし、その結果を返せばいいのです。他も同様。もちろん、上記のそれぞれのスクリプトを用意し、各アプリケーションで使い分ければいいだけの話です。しかし、そうではなく、selectedText() というような名前のハンドラ(インターフェース)を 1 つ用意し、どのエディタであってもこのハンドラ経由で選択文字列を取得するにはどうしたらいいのか?という問題です。

いろんなエディタが AppleScript に対応しているのは確かに便利です。が、エディタを変更すると、それまで利用していたエディタ用のスクリプトは使えません(エディタを作業によってころころと変える人ってそんなにいないと思いますが...)。これを解決するために 1 つハンドラを用意し、全ての操作はそのハンドラ経由で。selectedText() ハンドラの内部でいかに小難しいことをしているかは知らなくても、selectedText() を呼び出せば CotEditor でも QuoEdit でも kEdit でも(あるいは、その他のエディタでも)選択している文字列が取得できる。

一人で考えていても、分からない。で、問題としてここに掲載。解答を募集します。優秀な解答には、iTMS カード(5,000 円)をお一人様に。努力賞として iTMS カード(2,500 円)をお二人様に。ふるってご応募ください。

...というようなことをすると AppleScript のサイトとして盛り上がるかなぁ。。。

追記。iTMS カードは、冗談です。