Shoeisha Technology Media

CodeZine(コードジン)

記事種別から探す

オープンソースのWeb用コードエディター「Brackets」の拡張機能を作成する

原題:初めてのBrackets拡張機能の作成

  • LINEで送る
  • このエントリーをはてなブックマークに追加
2013/01/24 14:00

 新しいオープンソースのWeb用コードエディターであるBracketsでは、拡張性が重視されています。実際、Quick Open(すぐに開く)、Quick Edit(すぐに編集)、HTML Code Hinting(HTMLコードヒント)などの中心的な機能のいくつかは拡張機能として実装されています。

 Bracketsのアーキテクチャは高度にモジュール化されており、Bracketsのメインコードをできる限り的を絞ったものに保ちながら、高いカスタマイズの可能性を提供することによって、問題点の分離を実現しています。これは、現代のWeb開発者のニーズを満たすための絶対的な要件です。

 ただし、既にお気付きかもしれませんが、Bracketsにはデフォルトの拡張機能が付属していますが、そのままではまだ機能が制限されているようです。このような理由から、新しいユーザーが最初にできることは、筆者のブログの記事「Brackets/Edge Code extensions you should install right now」(今すぐインストールすることをお勧めするBrackets/Edge Codeの拡張機能)で説明しているように、追加の拡張機能をインストールすることです。これによって、文字列操作コードスニペットなどの拡張機能を利用できるようになります。

 とはいうものの、ユーザーとしては、おそらくすぐに、「Bracketsであれができればいいのだが、どれくらい難しいのだろうか」と考え始めるでしょう。Bracketsは、Adam Lehman氏の記事「Brackets: The Open Source Code Editor for the Web」(Brackets:オープンソースのWeb用コードエディター)で説明されているように、Web標準を使用して構築されているため、Bracketsを自分でカスタマイズすることは考えているよりもずっと簡単です。また、この体験は得るものが非常に大きいので、すぐにとりこになるかもしれません。

 この記事では、Brackets拡張機能の仕組み、テンプレートを使用して、または一からBrackets拡張機能を作成する方法および開発環境の最適な設定方法について説明します。

注意

 Edge Codeは、Bracketsのディストリビューションの1つであり、潜在的にはEdge Codeを使用して拡張機能も作成できますが、Debug(デバッグ)メニューがないため、拡張機能を作成する作業ではBracketsほど便利ではありません。ただし、Bracketsで作成した拡張機能はすべてEdge Codeで使用できます。この記事の内容は、Brackets Sprint 16に基づいています。

(この記事は、アドビ システムズ 株式会社発行の「Adobe Developer Connection」から許可を得て転載したものです)

拡張機能の保存場所

 技術的に言うと、拡張機能は、Bracketsの起動時に実行されるmain.jsという名前のJavaScriptファイルを格納しているフォルダーにすぎません。

図1.拡張機能の保存場所の設定
図1.拡張機能の保存場所の設定

 Bracketsは、残りのコードの読み込みと実行を完了すると、以下のフォルダーで拡張機能を探します。

  • デフォルト拡張機能フォルダー(src/extensions/default)。このフォルダーには、Bracketsチームが選択したデフォルトの拡張機能が格納されます。ユーザーは、このフォルダーに何も配置しないでください。
  • ユーザー拡張機能フォルダー(OSXでは/Users/<user>/Library/Application Support/Brackets/extensions/user、Windows 7ではC:\Users\<user>\AppData\Roaming\Brackets\extensions\user)。Bracketsユーザーは、Githubからダウンロードしたサードパーティの拡張機能をこのフォルダーに保存します。便宜上、BracketsでHelp(ヘルプ)/Show Extensions Folder(拡張機能フォルダーを表示)を選択すると、自動的にこのフォルダーが開きます。
  • 拡張機能開発フォルダー(src/extensions/dev)。拡張機能開発者は、自分の拡張機能をこのフォルダーに配置します。このフォルダーは、ユーザーシステムに関連付けられるユーザー拡張機能フォルダーよりも便利な場所です。

 Bracketsには、無効になった拡張機能用の場所としてsrc/extensions/disabledが用意されているので、拡張機能を完全に削除することなく、一時的に無効にすることが容易です。

開発用のBracketsの設定

 Brackets内で拡張機能をデバッグするには、以下の手順で行います。

 1. Brackets内で、Debug(デバッグ)/Show Developer Tools(デベロッパーツールを表示)を選択してChromeデベロッパーツールを開きます。現在のバージョン(sprint 16)では、Bracketsは、Chromeブラウザーウィンドウ内でChromeデベロッパーツールを開きます(Chromeが閉じている場合はChromeを開きます)。MacintoshでSpacesを使用している場合は、ChromeウィンドウをBracketsと一緒に開いていることを確認します。

図2.拡張機能のデバッグ
図2.拡張機能のデバッグ

 2. Bracketsから開いたデベロッパーツールのタブではキャッシュを無効にすることを強くお勧めします。キャッシュを無効にしないと、アプリケーションを再読み込みしても、変更内容をテストできません。この設定は、デベロッパーツールのオプションパネルで行うことができます。

図3.変更内容をテストするためのキャッシュの無効化
図3.変更内容をテストするためのキャッシュの無効化

 3. しかし、すぐに、コードの作成と結果のテストを同じエディターウィンドウで行うことは、適切な方法ではないことに気付くでしょう。これが、Debugメニューから新しいBracketsウィンドウを開くことをお勧めする理由です。そのためには、Debug(デバッグ)/New Brackets Window(新しいBracketsウィンドウ)を選択します(図4)。

図4.コードを適切にテストするためにDebug(デバッグ)メニューから新しいBracketsウィンドウを開く。
図4.コードを適切にテストするためにDebug(デバッグ)メニューから新しいBracketsウィンドウを開く。

 また、この2番目のウィンドウからテストすることを強くお勧めします。これを正しく行うには、このウィンドウから、手順1の説明に従って、デベロッパーツールを設定する必要があります。筆者の一般的な設定は次のようになります。

図5.筆者の一般的なデバッグおよび開発用の設定。
図5.筆者の一般的なデバッグおよび開発用の設定。

Bracketsのリポジトリクローンからの作業

 また、Bracketsソースの別のコピーからコードを開発することもお勧めします。メリットとして、アプリケーションコードの最新バージョンを使って作業することができ、拡張機能が最新の状態であることを保証できます。また、オリジナルのアプリケーションソースを編集する必要性を回避することができます。オリジナルのソースを編集すると、好ましくない結果がもたらされる可能性があります。Bracketsリポジトリのクローンから作業するための簡単な方法は、以下の手順に従って、GitHubからBracketsリポジトリのフォークまたはクローンを実行することです。

 1. GitHubのBracketsリポジトリに移動します。

 2. GitHub client for MacまたはGitHub client for Windowsを使用している場合は、このリポジトリのホームページから、プラットフォームに応じて「Clone in Mac(Mac用クローン)」または「Clone in Windows(Windows用クローン)」ボタンをクリックし、ローカルディスク上の保存先を選択します。

図6.Mac用のBracketsリポジトリのクローン作成
図6.Mac用のBracketsリポジトリのクローン作成

 3. Shiftキーを押しながらBracketsを起動することによって、Bracketsでデフォルトのアプリケーションコンテンツではなく、このコードを実行することを指定します。

 この説明を十分に理解するには、Bracketsアプリケーションが実際には2つの部分から構成されていることを理解しておく必要があります。

  • 1つは、Chromium Embedded Frameworkを使って作成されたBracketsシェルで、ネイティブデスクトップアプリケーションシェル内で、ローカルWebコンテンツを実行します。
  • もう1つは、HTML、CSS、JavaScriptファイルなどのローカルWebコンテンツで、Bracketsエディターのソースコードです。

 デフォルトでは、Bracketsシェルは、アプリケーションのインストール時に作成されたアプリケーションコンテンツフォルダー内に格納されているWebファイルを実行します。ただし、このフォルダーから直接コードを編集することはお勧めしません。そのため、ネイティブアプリケーションでは、Shiftキーを押しながらアプリケーションを起動することによって、別のソースフォルダー内から実行できます。または、アプリケーションソースコードのtoolsフォルダーにあるsetup_for_hackingスクリプトを使用することもできます。このスクリプトは、GitHubの記事「How to Hack on Brackets」(Bracketsを改良する方法)から入手できます。

拡張機能テンプレートの使用

 もちろん、拡張機能を一から作成することもできますが、テンプレートを使用する方法をお勧めします。ユーザーが選択できるオプションがいくつかあります。

 拡張機能の開発を始める一般的な方法は、自分が実現しようとする機能に比較的近い既存の拡張機能をコピー&ペーストすることです。これは最初の一歩として有効な方法ですが、すべての拡張機能が最新というわけではないことと、すべての拡張機能が必ずしも最新のベストプラクティスを示しているわけではないことに注意してください。また、拡張機能の中には、特に拡張機能開発の初心者にとって、非常に読みづらいものもあります。

 その代わりとして、Brackets Extension Toolkitを使用することもできます。このツールキットには、専用のテンプレートが用意されており、src/extensions/devフォルダーにドラッグ&ドロップすることができます。また、拡張機能を初めて開発する際のガイドとして使用できる、豊富なコメント付きのコードや、関連するヘルパーツールも用意されています。

 どのオプションを選択した場合でも、比較的快適な環境が整ったら、独自のカスタムテンプレートを、後ですばやくアクセスできるように、src/extensions/disabledフォルダーに格納しておくことをお勧めします。ユーザー拡張機能フォルダーにコピーするだけで使用できます。

Brackets拡張機能APIの概要

 既存の拡張機能を初めて見る場合は、少しとまどうかもしれません。Brackets拡張機能は、RequireJSSimplified CommonJS Wrapperで指定されているようなJavaScriptモジュールです。JavaScriptモジュールの説明はこのチュートリアルの対象範囲外です。詳しくは、Addy Osmani氏の「Modern Modular JavaScript Design Patterns」(最新のモジュール化JavaScriptデザインパターン)を参照してください。デモンストレーション用に最もシンプルな形式の拡張機能を考えると、次のようになります。

define(function (require, exports, module) {
    'use strict';
    // Extension code goes here
    console.log("Extension initialized");
});

 define呼び出し内の匿名関数の本体に含まれるすべてのコードが、アプリケーションの起動時に実行されます。

 当然、多くの場合、作成しようとしているのは、アプリケーションの別の部分で拡張機能を呼び出したときに、何かのコードを実行できるようにする拡張機能です。例えば、ユーザーがメニュー項目を選択したとき、これによってアプリケーションはアクションを実行します。

 このような種類のメカニズムは、コマンドを使用してコーディングすることができます。コマンドIDを関数に登録することによって、アプリケーションがこのIDを呼び出したときに、関数が実行されます。これは、CommandManagerのジョブです。Bracketsのほとんどすべての機能と同様に、CommandManager自体もモジュールです。拡張機能から他のモジュールにアクセスするには、専用のbrackets.getModule()メソッドを呼び出して、srcフォルダーからのモジュールの相対パスをメソッドに渡すだけです。以下のコードでは、JSファイル拡張子を指定していないことに注意してください。

var CommandManager = brackets.getModule("command/CommandManager");

 CommandManagerに対して、どの関数を、いつ実行するかを指定するには、register(name, command_id, function)メソッドを指定します。このメソッドのパラメーターは、次のとおりです。

  • nameパラメーターは、判読可能なユーザーフレンドリな名前で、ユーザーインターフェイスのメニューラベルとしても使用されます。
  • command_idパラメーターは、このコマンドを一意に識別するための文字列です。このパラメーターの形式は、[author].[my_extension].[menu_name].[my_command_name]です。
  • 最後のパラメーターのfunctionは、ユーザーがUIでメニュー項目を選択したときに、メソッドが呼び出す関数です。ユーザーがUIでメニュー項目を選択すると、次のコード例に示されているように、アプリケーションは自動的に、対応するIDを使用してexecute(command_id)メソッドを呼び出します。
var COMMAND_ID = "dderaedt.tutorialExt.logHelloWorld.logHelloWorld";
var COMMAND_NAME = "Log Hello World";

function sayHello() {
   console.log("Hello World");
}
CommandManager.register(COMMAND_NAME, COMMAND_ID, sayHello);

 この段階で、拡張機能は機能しますが、何かがコマンドIDを呼び出す必要があるので、呼び出されません。そのためには、Menusモジュールを通じて対応するコマンドIDを呼び出すメニュー項目を追加し、その結果として関数を実行します。そのために、まず次のように、Menusモジュールにアクセスします。

var Menus = brackets.getModule("command/Menus");

 次に、項目を追加するメニュー(この例では、Fileメニュー)のハンドルを取得します。

var fileMenu = Menus.getMenu(Menus.AppMenuBar.FILE_MENU);

 最後に、次のように、トリガーするコマンドに対応する項目を追加します。

fileMenu.addMenuItem(COMMAND_ID);

 このHello World拡張機能の完成したコードは、次のようになります。

define(function (require, exports, module) {
    'use strict';

    var CommandManager = brackets.getModule("command/CommandManager");
    var Menus          = brackets.getModule("command/Menus");

    var COMMAND_ID = "dderaedt.tutorialExt.LogHelloWorld";
    var COMMAND_NAME = "Log Hello World";

    function sayHello() {
        console.log("Hello World");
    }

    CommandManager.register(COMMAND_NAME, COMMAND_ID, sayHello);

    var fileMenu = Menus.getMenu(Menus.AppMenuBar.FILE_MENU);
    fileMenu.addMenuItem(COMMAND_ID);
});

現在のドキュメントの編集

 ここでは、何かもう少し役に立つ処理をするために、現在のドキュメント内でコードを生成する拡張機能が必要であると仮定しましょう。

 Bracketsでは、ツールで開いたファイルはDocumentクラスのインスタンスとして表されます。現在のドキュメント(つまり、ユーザーが現在開いて、編集しているファイル)への参照を取得するには、DocumentManagerモジュールを使用する必要があります。最初に、このモジュールへの参照を取得する必要があります。このモジュールはdocumentフォルダー内にあります。

var DocumentManager = brackets.getModule("document/DocumentManager");

 ここでは、前のセクションのコードを利用して、sayHello()関数の名前をaddSomeText()に変更します。

 この関数の内部で最初に行う必要がある処理は、現在のドキュメントへの参照を取得することです。

var currentDoc = DocumentManager.getCurrentDocument();

 ここで、テキストコンテンツの操作に役立つDocument APIを使用します。使用可能なメソッドのいくつかを以下に示します。

  • getText()は、テキストコンテンツ全体を返します。
  • setText()は、テキストコンテンツ全体を設定します。
  • getRange(start, end)は、テキストコンテンツの一部を返します。
  • replaceRange(text, start, end)は、指定された位置にあるテキストを置換します。

 テキスト内の位置(前述のstartおよびendパラメーターなど)は位置オブジェクトによって表されます。このオブジェクトには、line(行番号)とch(文字番号)の2つのプロパティがあります。

 次のシナリオでは、現在のカーソル位置に1行のコメントを生成する必要があると仮定します。Editorオブジェクトでコード編集を管理するので、EditorManager.getCurrentFullEditor()メソッドによって返される現在のエディターインスタンスへのアクセスを取得する必要があります。その後、次のように対応するモジュールをインポートします。

var EditorManager = brackets.getModule("editor/EditorManager");

 次のように、現在のドキュメントのエディターにアクセスできます。

var editor = EditorManager.getCurrentFullEditor();

 最後に、このエディターを使用して、次のような、選択したテキストに関連するあらゆる種類の操作を実行できるようになります。

  • getSelectedText()
  • setSelection(start, end)
  • selectWordAt(position)
  • getCursorPos()

 これで、必要なすべてのものにアクセスできるようになったので、addSomeText()関数を次のように作成し直すことができます。

function addSomeText() {        
    var currentDoc = DocumentManager.getCurrentDocument();
    var editor = EditorManager.getCurrentFullEditor();
    var pos = editor.getCursorPos();

    currentDoc.replaceRange("//Black magic. Do not modify EVER", pos);
}

次のステップ

 当然、このようなシンプルな例では、ある程度までしか導いてくれません。すぐに、他のモジュールによって公開されるAPIの詳細を学習することが必要になります。詳しく学習するために役立つリソースのいくつかを以下に示します。

  • Bracketsのソースコード自体は、当然、究極の唯一100%信頼できる情報源です。Brackets Extension Toolkitをインストールしている場合は、Help(ヘルプ)/Open Brackets src(Brackets srcを開く)を選択します。Document、Editor、EditorManager、FileUtilsを始め、デフォルトの拡張機能をすべて参照してください。
  • Brackets wikiには役に立つ情報が豊富にあります。特に、「How to write extensions page」(拡張機能ページを作成する方法)では、知っておく必要がある基本事項が説明されています。Brackets Extension ToolkitのHelpメニューには、このwikiへのショートカットがあります。
  • 現在のドキュメントのコードを編集する拡張機能を作成しようとしている場合、下位のコード編集ロジックを担当するプロジェクトである、CodeMirrorに慣れておくことをお勧めします。
  • より高いレベルでBracketsの仕組みを理解するには、記事「An overview of Brackets code architecture」(Bracketsのコードアーキテクチャの概要)でBracketsの一般的なアーキテクチャの詳細を学習してください。
  • 最後に、拡張機能にUIを含める予定である場合は、Brackets wikiにある「Extension UI Guidelines」(拡張機能のUIガイドライン)のドラフトを参照してください。
  • LINEで送る
  • このエントリーをはてなブックマークに追加

著者プロフィール

  • David Deraedt(David Deraedt)

    David DeraedtはAdobe FlexおよびAdobe AIRを専門に手がけるFlash Platformコンサルタントです。Davidは認定トレーニングセンターのRegart.netにてインストラクターとしても活躍しています。また、これまで、AIR for Flex Developers...

All contents copyright © 2005-2017 Shoeisha Co., Ltd. All rights reserved. ver.1.5