« テキストエディタのコンテキストメニューID | トップページ | テキストのフォーマット(2.戦略の登録) »

2004.09.18

テキストのフォーマット(1.戦略の作成)

Javaエディタには,インデントや空白の調整を行うフォーマット機能が備わっていて,誰が書いたコードに関しても一定の規律に従ってソースコードを整えることができる。Eclipseでは,さまざまな言語に対応したエディタを自作するための強力なフレームワークが提供されているが,このフォーマット機能もその一つである。今回は自作したエディタに対して,入力された内容を整形するフォーマット機能の作成方法を紹介する。

JFaceが提供しているテキストエディタフレームワークでは,入力されたテキストについて,あるルールに従って複数の区画(パーティション)に分割するのが普通である。例えばJavaエディタでは,Javadocコメントの部分と実際のコードの部分に区画が分けられている。特にプログラム言語を扱う場合,一つのソースコード中でもいくつかの分野(コメント文やマクロ,関数など)が混在しているので,インデントや空白,改行位置などのテキストの整形を行いたい場合,その分野ごとに異なる整形を施したくなる。そこで,テキストエディタフレームワークでは,テキストの区画ごとに異なる整形戦略(Strategy)を割り当てられるようになっている

このフォーマット機能は,具体例を示しながらの方がわかりやすいだろう。ここでは,META_PARTおよびCONTENT_PARTという2つの区画が存在するエディタを題材とする。META_PART区画は{$BEGIN_META}から{$END_META}で囲まれた部分,CONTENT_PART区画は{$BEGIN_CONTENT}から{$END_CONTENT}で囲まれた部分とし,それぞれ異なる背景色を定義してある。入力した状況を下図に示す。

format1.gif

META_PART区画については英小文字をすべて英大文字に変更,CONTENT_PART区画については句読点「。」で改行するようにフォーマット機能を仕上げる。

では,フォーマット処理を行うクラスの作成方法から紹介する。フォーマット処理はIFormattingStrategyインタフェースに規定されている。基本的には,IFormattingStrategyインタフェースの実装クラスでformatメソッドに整形処理を実装すればよい

  public class MetaPartFormattingStrategy implements IFormattingStrategy {
    public void formatterStarts(String initialIndentation) {}
    public String format(String content, boolean isLineStart, String indentation, int[] positions) {
      return content.toUpperCase();
    }
    public void formatterStops() {}
  }

フォーマット処理の直前にformatterStartsメソッドが,フォーマット処理の直後にformatterStopsメソッドがそれぞれ呼び出される。この際,formatterStartsメソッドの引数にフォーマット処理対象の文字列の中で最初の行に使われているインデント文字列(タブあるいは1つ以上の空白)が渡される。

そして実際のフォーマット処理を記述するのがformatメソッドである。基本的に,引数のcontent変数にフォーマット対象の文字列が渡されてくるので,それに対してフォーマット処理を行い,その結果の文字列を返却すればよい。フォーマット処理の呼び出し時点で,もし区画内で文字列が選択されていない場合は区画全体の文字列が,もし区画内で文字列が選択されていた場合は選択文字列がcontent引数に渡されてくる。上記の例では,渡された文字列に対してtoUpperCaseメソッドを使用して英小文字を英大文字に変換し,その結果の文字列をフォーマット処理後の文字列として返却している。

その他の引数として,isLineStart引数は処理対象の文字列の最初の行が0桁目から開始されているかどうかが,indentation引数は処理対象の文字列の最初の行に使用されているインデント文字列が渡される。最後のpositions引数は,Javadocには更新される文字の位置と記述されているが,よくわからず(誰か教えてください)。

上記のコードはMETA_CONTENT区画に対してのフォーマット処理クラスである。CONTENT_PART区画に対してのフォーマット処理クラスについても紹介しておこう。

  public class ContentPartFormattingStrategy implements IFormattingStrategy {
    public void formatterStarts(String initialIndentation) {}
    public String format(String content, boolean isLineStart, String indentation, int[] positions) {
      String temp = "", result = "";
      StringTokenizer st = new StringTokenizer(content, "\r\n");
      while(st.hasMoreTokens())
        temp += st.nextToken();
      BreakIterator iterator = BreakIterator.getSentenceInstance();
      iterator.setText(temp);
      int start = iterator.first();
      for (int end = iterator.next(); end != BreakIterator.DONE; start = end, end = iterator.next())
        result += (start == 0) ? temp.substring(start, end) : "\r\n" + temp.substring(start, end);
      if (result.startsWith("{$BEGIN_CONTENT}"))
        result = result.substring(0, 16) + "\r\n" + result.substring(16);
      return result;
    }
    public void formatterStops() {}
  }

BreakIteratorクラスを使って句読点を区切りとして文字列を分割し,その間に改行を付与することによって整形処理を行っている。

Eclipseでは,大抵のインタフェースに対応して提供されているデフォルト実装クラスを使えば,プラグイン開発者は自分で実装クラスを作成しなくても済んでしまう場面が多い。しかし,IFormattingStrategyインタフェースについては,デフォルト実装クラスは特に用意されていない(JDTにはもちろん実装が存在する)。汎用的なフォーマット処理なんぞ存在しない,ということだろう。しかし,ブロックの開始文字と終了文字を与えることによってインデント整形をやってくれる汎用実装クラスくらいは用意されてても良い気がする。。。

さて,これで各区画に対して行うフォーマット処理を実装することができた。これを使用可能にするためには,あといくつかのステップを踏む必要がある。次回「テキストのフォーマット(2.戦略の登録)」は,IFormattingStrategyオブジェクトをフレームワークに登録する方法を紹介する。

|

« テキストエディタのコンテキストメニューID | トップページ | テキストのフォーマット(2.戦略の登録) »

コメント

コメントを書く



(ウェブ上には掲載しません)




トラックバック

この記事のトラックバックURL:
http://app.cocolog-nifty.com/t/trackback/12631/1466035

この記事へのトラックバック一覧です: テキストのフォーマット(1.戦略の作成):

« テキストエディタのコンテキストメニューID | トップページ | テキストのフォーマット(2.戦略の登録) »