「タグファイルから補完」の版間の差分

提供: MeryWiki
ナビゲーションに移動 検索に移動
MSY-07 (トーク | 投稿記録)
箇条書きの順番を変更
MSY-07 (トーク | 投稿記録)
変数にvarの宣言を追加
 
(同じ利用者による、間の5版が非表示)
8行目: 8行目:


== インストール ==
== インストール ==
#下のスクリプトをコピーして、MeryのMy Macroフォルダなどに保存
#下のスクリプトをコピーして、MeryのMacrosフォルダなどに保存
#Mery.exeのあるフォルダに[https://hp.vector.co.jp/authors/VA025040/ctags/ ctags.exe]を置く
#Mery.exeのあるフォルダに[https://web.archive.org/web/20241217153248/https://hp.vector.co.jp/authors/VA025040/ctags/ ctags.exe]を置く
#マクロを登録し、Ctrl+→やCtrl+Shift+SpaceやCtrl+Qキーなどにお好みで設定する
#マクロを登録し、Ctrl+→やCtrl+Shift+SpaceやCtrl+Qキーなどにお好みで設定する


67行目: 67行目:


== 変更履歴 ==
== 変更履歴 ==
* r7: 補完候補の単語が1つだけのときうまく補完されないのを修正
* r7 (2012-10-14)
* r6: 確認せずにctagsを起動するオプション
** 補完候補の単語が1つだけのときうまく補完されないのを修正
* r5: C言語の関数で引数を表示、今開いてるファイル中の単語からも補完、文字の大小を区別しないオプション
* r6 (2012-08-23)
* r4: ホットキー
** 確認せずにctagsを起動するオプション
* r3: 単独でctags呼び出し
* r5 (2012-08-01)
* r1~r2: 失念
** C言語の関数で引数を表示、今開いてるファイル中の単語からも補完、文字の大小を区別しないオプション
* r4 (2012-06-22)
** ホットキー
* r3
** 単独でctags呼び出し
* r2
** 失念
* r1
** 失念


== ソースコード ==
== ソースコード ==
<syntaxhighlight lang="javascript">
<syntaxhighlight lang="javascript" copy>
// タグファイルから補完.js r7 2012-10-24
// タグファイルから補完.js r7 2012-10-24
// https://www.haijin-boys.com/wiki/%E3%82%BF%E3%82%B0%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%81%8B%E3%82%89%E8%A3%9C%E5%AE%8C
// https://www.haijin-boys.com/wiki/%E3%82%BF%E3%82%B0%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%81%8B%E3%82%89%E8%A3%9C%E5%AE%8C
84行目: 92行目:


// タグファイルの名前
// タグファイルの名前
TAGS = ".merytags"
var TAGS = ".merytags";


// ctags.exeの名前
// ctags.exeの名前
// 相対パスの場合はmery本体のあるディレクトリのものを使います
// 相対パスの場合はmery本体のあるディレクトリのものを使います
// "c:\\bin\\ctags.exe" のように絶対パスも指定できます
// "c:\\bin\\ctags.exe" のように絶対パスも指定できます
CTAGS = "ctags.exe"
var CTAGS = "ctags.exe";


// ctagsに与える引数 (初期設定:位置を行番号で記憶(必須)、フォルダを再帰的に処理、関数の引数を記憶)
// ctagsに与える引数 (初期設定:位置を行番号で記憶(必須)、フォルダを再帰的に処理、関数の引数を記憶)
CTAGS_FLAGS = "--excmd=number --recurse --fields=+S"
var CTAGS_FLAGS = "--excmd=number --recurse --fields=+S";


// 単語の途中で補完する際の挙動
// 単語の途中で補完する際の挙動
// trueにするとカーソルの置かれた単語全体から補完
// trueにするとカーソルの置かれた単語全体から補完
// falseにするとカーソルより左から補完します
// falseにするとカーソルより左から補完します
WHOLE_WORD = true
var WHOLE_WORD = true;


// 単語の検索の挙動
// 単語の検索の挙動
// trueにすると検索時大文字と小文字を区別しません
// trueにすると検索時大文字と小文字を区別しません
// falseにすると区別します
// falseにすると区別します
CASE_INSENSITIVE = true
var CASE_INSENSITIVE = true;


// タグを作るフォルダ
// タグを作るフォルダ
// "." にすると、編集中のファイルのあるフォルダでタグを作ります
// "." にすると、編集中のファイルのあるフォルダでタグを作ります
// ".." などにすると、編集中のファイルの一つ上のフォルダからタグを作ります
// ".." などにすると、編集中のファイルの一つ上のフォルダからタグを作ります
DEFAULT_TAGS_DIR = "."
var DEFAULT_TAGS_DIR = ".";


// タグファイルがない場合の挙動
// タグファイルがない場合の挙動
// trueにするとタグを作成するフォルダを尋ねます
// trueにするとタグを作成するフォルダを尋ねます
// falseにするとフォルダを尋ねずに無言で作成を始めます
// falseにするとフォルダを尋ねずに無言で作成を始めます
CONFIRM_CREATE_TAGS = false
var CONFIRM_CREATE_TAGS = false;


/** 本体 **/
/** 本体 **/


var FileSystem = new ActiveXObject("Scripting.FileSystemObject")
var FileSystem = new ActiveXObject("Scripting.FileSystemObject");
var Shell = new ActiveXObject("WScript.Shell")
var Shell = new ActiveXObject("WScript.Shell");


main()
main();


function main()
function main() {
{
var ctags = makeCtags();
  var ctags = makeCtags()
var tags = makeTags(ctags);
  var tags = makeTags(ctags)
var query = getQueryWord();
  var query = getQueryWord()
var result = tags.lookup(query);
  var result = tags.lookup(query)
var word = chooseWord(result);
  var word = chooseWord(result)
 
 
if ("string" === typeof word) {
  if ("string" === typeof word)
writeWord(word);
  {
} else if (word === false) {
    writeWord(word)
tags.update();
  }
} else {
  else if (word === false)
jumpToDefinition(word);
  {
}
    tags.update()
  }
  else
  {
    jumpToDefinition(word)
  }
}
}


function makeCtags()
function makeCtags() {
{
return {
  return { run: run }
run: run
};
 
function run(dir) {
var ctags = findCtags();
 
try {
Shell.CurrentDirectory = dir;
window.Status = 'タグファイルを作成しています お待ちください';
Shell.Run('"' + ctags + '" -o ' + TAGS + " " + CTAGS_FLAGS, 0, true);
} catch (e) {}
 
window.Status = 'タグファイルを作成しました';
return FileSystem.BuildPath(dir, TAGS);
}
 
function findCtags() {
if (FileSystem.FileExists(CTAGS)) {
return CTAGS;
}
 
var dir = FileSystem.GetParentFolderName(editor.FullName);
var ctags = FileSystem.BuildPath(dir, CTAGS);
 
if (FileSystem.FileExists(ctags)) {
return ctags;
}


  function run(dir)
throw new Error("ctags.exeが見つかりませんでした\nMery本体のディレクトリに置くか、絶対パスを設定してください");
  {
}
    var ctags = findCtags()
   
    try
    {
      Shell.CurrentDirectory = dir
      window.Status = 'タグファイルを作成しています お待ちください'
      Shell.Run('"' + ctags + '" -o ' + TAGS + " " + CTAGS_FLAGS, 0, true)
    }
    catch (e)
    {
    }
   
    window.Status = 'タグファイルを作成しました'
    return FileSystem.BuildPath(dir, TAGS)
  }
 
  function findCtags()
  {
    if (FileSystem.FileExists(CTAGS))
    {
      return CTAGS
    }
   
    var dir = FileSystem.GetParentFolderName(editor.FullName)
    var ctags = FileSystem.BuildPath(dir, CTAGS)
   
    if (FileSystem.FileExists(ctags))
    {
      return ctags
    }
   
    throw new Error("ctags.exeが見つかりませんでした\nMery本体のディレクトリに置くか、絶対パスを設定してください")
  }
}
}


function makeTags(ctags)
function makeTags(ctags) {
{
var fullname = findTagfile();
  var fullname = findTagfile()
var text = loadTagfile();
  var text = loadTagfile()
 
 
return {
  return { lookup: lookup, update: update }
lookup: lookup,
 
update: update
  function getPath()
};
  {
 
    return FileSystem.GetParentFolderName(fullname)
function getPath() {
  }
return FileSystem.GetParentFolderName(fullname);
 
}
  function lookup(word)
 
  {
function lookup(word) {
    if (/^\s*$/.test(word)) { return }
if (/^\s*$/.test(word)) {
   
return;
    word = reEscape(word)
}
   
 
    var opts = CASE_INSENSITIVE ? "igm" : "gm"
word = reEscape(word);
    var re = new RegExp("^" + word + ".*$", opts)
 
    var lines = text.match(re)
var opts = CASE_INSENSITIVE ? "igm" : "gm";
   
var re = new RegExp("^" + word + ".*$", opts);
    if (!lines) { return [] }
var lines = text.match(re);
   
 
    return calcWords().concat(calcDefinitions(word))
if (!lines) {
   
return [];
    function calcWords()
}
    {
 
      var words = new Array(lines.length)
return calcWords().concat(calcDefinitions(word));
     
 
      words[0] = lines[0].substring(0, lines[0].indexOf("\t"))
function calcWords() {
var words = new Array(lines.length);
 
words[0] = lines[0].substring(0, lines[0].indexOf("\t"));
 
if (words.length === 1) {
return words[0] === word ? [] : words;
}
 
var n = 0;
for (var i = 1; i < lines.length; i++) {
var w = lines[i].substring(0, lines[i].indexOf("\t"));
 
if (words[n] !== w) {
n++;
words[n] = w;
}
}
 
words.length = n + 1;
 
words.sort(function(a, b) {
return a.localeCompare(b);
});
 
return words;
}
 
function calcDefinitions(word) {
var defs = new Array(lines.length);
var n = 0;
 
for (var i = 0; i < lines.length; i++) {
var line = lines[i];
var tab1 = line.indexOf("\t");
 
if (tab1 !== word.length) {
continue;
}
 
var tab2 = line.indexOf("\t", tab1 + 1);
var endnum = line.indexOf(";", tab2 + 1);
var sig = line.indexOf("signature:", endnum + 1);
 
var name = line.substring(0, tab1);
var filename = line.substring(tab1 + 1, tab2);
var linenum = line.substring(tab2 + 1, endnum);
var signature = sig < 0 ? "" : line.substring(sig + "signature:".length);
 
var fullname = FileSystem.BuildPath(getPath(), filename);
 
defs[n] = [fullname, linenum, filename, name + signature];
defs[n].toString = joinme;
n++;
}
 
defs.length = n;
 
return defs;
}
 
function joinme() {
return this[3] + " (" + this[2] + " : " + this[1] + ")";
}
}
 
function reEscape(w) {
return w.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&");
}
 
function loadTagfile() {
if (!fullname) {
fullname = makeTagfile();
}
 
return slurp(fullname);
}
 
function findTagfile() {
var dir = document.Path;
 
while (FileSystem.FolderExists(dir)) {
var file = FileSystem.BuildPath(dir, TAGS);
if (FileSystem.FileExists(file)) {
return file;
}
dir = FileSystem.GetParentFolderName(dir);
}
}


      if (words.length === 1)
function makeTagfile() {
      {
var dir = FileSystem.BuildPath(document.Path, DEFAULT_TAGS_DIR);
        return words[0] === word ? [] : words
      }
     
      var n = 0
      for (var i = 1; i < lines.length; i++)
      {
        var w = lines[i].substring(0, lines[i].indexOf("\t"))
       
        if (words[n] !== w)
        {
          n++
          words[n] = w
        }
      }
     
      words.length = n + 1


      words.sort(function(a, b)
if (CONFIRM_CREATE_TAGS) {
      {
dir = window.Prompt("タグファイル作成フォルダ", dir);
        return a.localeCompare(b)
}
      })
 
     
if (!dir) {
      return words
window.Quit();
    }
}
   
 
    function calcDefinitions(word)
return ctags.run(dir);
    {
}
      var defs = new Array(lines.length)
 
      var n = 0
function update() {
     
return ctags.run(getPath());
      for (var i = 0; i < lines.length; i++)
}
      {
 
        var line = lines[i]
function slurp(filename) {
        var tab1 = line.indexOf("\t")
var f = FileSystem.OpenTextFile(filename);
       
var text = f.ReadAll();
        if (tab1 !== word.length) { continue }
f.Close();
       
return text;
        var tab2 = line.indexOf("\t", tab1 + 1)
}
        var endnum = line.indexOf(";", tab2 + 1)
        var sig = line.indexOf("signature:", endnum + 1)
       
        var name = line.substring(0, tab1)
        var filename = line.substring(tab1 + 1, tab2)
        var linenum = line.substring(tab2 + 1, endnum)
        var signature = sig < 0 ? "" : line.substring(sig + "signature:".length)
       
        var fullname = FileSystem.BuildPath(getPath(), filename)
       
        defs[n] = [fullname, linenum, filename, name + signature]
        defs[n].toString = joinme
        n++
      }
     
      defs.length = n
     
      return defs
    }
   
    function joinme()
    {
      return this[3] + " (" + this[2] + " : " + this[1] + ")"
    }
  }
 
  function reEscape(w)
  {
    return w.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&")
  }
 
  function loadTagfile()
  {
    if (!fullname)
    {
      fullname = makeTagfile()
    }
   
    return slurp(fullname)
  }
 
  function findTagfile()
  {
    var dir = document.Path
   
    while (FileSystem.FolderExists(dir))
    {
      var file = FileSystem.BuildPath(dir, TAGS)
      if (FileSystem.FileExists(file)) { return file }
      dir = FileSystem.GetParentFolderName(dir)
    }
  }
 
  function makeTagfile()
  {
    var dir = FileSystem.BuildPath(document.Path, DEFAULT_TAGS_DIR)
   
    if (CONFIRM_CREATE_TAGS)
    {
      dir = window.Prompt("タグファイル作成フォルダ", dir)
    }
   
    if (!dir)
    {
      window.Quit()
    }
   
    return ctags.run(dir)
  }
 
  function update()
  {
    return ctags.run(getPath())
  }
 
  function slurp(filename)
  {
    var f = FileSystem.OpenTextFile(filename)
    var text = f.ReadAll()
    f.Close()
    return text
  }
}
}


function getQueryWord()
function getQueryWord() {
{
var s = document.selection;
  var s = document.selection
 
 
if (!s.IsEmpty) {
  if (!s.IsEmpty) { return s.Text }
return s.Text;
 
}
  if (WHOLE_WORD)
 
  {
if (WHOLE_WORD) {
    s.SelectWord()
s.SelectWord();
   
 
    // hoge|(); → hogeFuga|(); のように補完  
// hoge|(); → hogeFuga|(); のように補完  
    if (s.Text.length == 1 && !/\w/.test(s.Text))
if (s.Text.length == 1 && !/\w/.test(s.Text)) {
    {
s.Collapse(meCollapseStart);
      s.Collapse(meCollapseStart)
s.WordLeft(true);
      s.WordLeft(true)
}
    }
} else {
  }
s.WordLeft(true);
  else
}
  {
 
    s.WordLeft(true)
if (/\A\s+\z/.test(s.Text)) {
  }
s.Collapse(meCollapseEnd);
 
}
  if (/\A\s+\z/.test(s.Text))
 
  {
return s.Text;
    s.Collapse(meCollapseEnd)
  }
 
  return s.Text
}
}


function chooseWord(words)
function chooseWord(words) {
{
if (words && words.length === 1 && typeof words[0] === "string") {
  if (words && words.length === 1 && typeof words[0] === "string")
return words[0];
  {
}
    return words[0]
  }


  var menu = makeMenu()
var menu = makeMenu();
  var i = menu.Track(0)
var i = menu.Track(0);
 
 
  return i === -1 ? false : words && words[i - 1]
return i === -1 ? false : words && words[i - 1];
 
 
  function makeMenu()
function makeMenu() {
  {
var menu = window.CreatePopupMenu();
    var menu = window.CreatePopupMenu()
initMenu(menu);
    initMenu(menu)
menu.Add("タグファイルを更新する", -1);
    menu.Add("タグファイルを更新する", -1)
return menu;
    return menu
}
  }
 
 
function initMenu(menu) {
  function initMenu(menu)
if (!words || words.length == 0) {
  {
return;
    if (!words || words.length == 0) { return }
}
   
 
    var n = 0
var n = 0;
    function addHotkey(word)
 
    {
function addHotkey(word) {
      if (n > 34) { return word }
if (n > 34) {
      n++
return word;
      return "&" + n.toString(36) + ". " + word
}
    }
n++;
   
return "&" + n.toString(36) + ". " + word;
    for (var i = 0; i < words.length; i++)
}
    {
 
      menu.Add(addHotkey(words[i]), i + 1)
for (var i = 0; i < words.length; i++) {
    }
menu.Add(addHotkey(words[i]), i + 1);
   
}
    menu.Add(undefined, 0, meMenuSeparator)
 
  }
menu.Add(undefined, 0, meMenuSeparator);
}
}
}


function jumpToDefinition(def)
function jumpToDefinition(def) {
{
if (!def) {
  if (!def) { return }
return;
  window.Status = def + "にジャンプします"
}
  var file = def[0]
window.Status = def + "にジャンプします";
  var line = def[1]
var file = def[0];
 
var line = def[1];
  editor.OpenFile(file, 0, meOpenAllowNewWindow)
 
  editor.ActiveDocument.selection.SetActivePoint(mePosLogical, 1, line, false)
editor.OpenFile(file, 0, meOpenAllowNewWindow);
  editor.ActiveDocument.Activate()
editor.ActiveDocument.selection.SetActivePoint(mePosLogical, 1, line, false);
editor.ActiveDocument.Activate();
}
}


function writeWord(word)
function writeWord(word) {
{
if (word) {
  if (word)
document.selection.Text = word;
  {
}
    document.selection.Text = word
  }
}
}
</syntaxhighlight>
</syntaxhighlight>

2025年11月25日 (火) 10:27時点における最新版

ctagsの生成したtagsファイルから検索して単語のメニューを出します。

項目を選ぶとその単語が挿入されます。

単語が完全な形の場合、タグジャンプを行います。

kazyさんのctags.exeでtagsファイルを生成、タグジャンプを行うマクロとあわせてお使いください(単独で使ってもタグジャンプ機能はあります)。

インストール[編集]

  1. 下のスクリプトをコピーして、MeryのMacrosフォルダなどに保存
  2. Mery.exeのあるフォルダにctags.exeを置く
  3. マクロを登録し、Ctrl+→やCtrl+Shift+SpaceやCtrl+Qキーなどにお好みで設定する

使い方[編集]

  1. 補完したい単語にカーソルを置き、マクロを起動する
  2. 初回起動の場合、タグファイルの作成を待つ
  3. すでに単語が完全な場合、メニューを選ぶとその定義にジャンプする
  4. メニューの項目を選ぶと、その単語が挿入される
  5. メニューの最後の「タグファイルを更新する」を選ぶと、タグファイルを作り直すことができる

カスタマイズ[編集]

変数を変えることで、挙動がいくらかカスタマイズできます。

名前 初期設定 効果
TAGS ".merytags" タグファイルの名前。
CTAGS "ctags.exe" ctags.exeの名前。

相対パスの場合はmery本体のあるディレクトリのものを使います。

"c:\\bin\\ctags.exe" のように絶対パスも指定できます。

CTAGS_FLAGS "--excmd=number --recurse --fields=+S" ctagsに与える引数。

初期設定の意味は左から

  • 位置を行番号で記憶 (タグジャンプに必要)
  • フォルダを再帰的に処理
  • 関数の引数を記憶
WHOLE_WORD true 単語の途中で補完する際の挙動。

trueにするとカーソルの置かれた単語全体から補完。

falseにするとカーソルより左から補完します。

CASE_INSENSITIVE true 単語の検索の挙動。

trueにすると検索時大文字と小文字を区別しません。

falseにすると区別します。

DEFAULT_TAGS_DIR "." タグを作るフォルダ。

"." にすると、編集中のファイルのあるフォルダでタグを作ります。

".." などにすると、編集中のファイルの一つ上のフォルダからタグを作ります。

CONFIRM_CREATE_TAGS true タグファイルがない場合の挙動。

trueにするとタグを作成するフォルダを尋ねます。

falseにするとフォルダを尋ねずに無言で作成を始めます。

変更履歴[編集]

  • r7 (2012-10-14)
    • 補完候補の単語が1つだけのときうまく補完されないのを修正
  • r6 (2012-08-23)
    • 確認せずにctagsを起動するオプション
  • r5 (2012-08-01)
    • C言語の関数で引数を表示、今開いてるファイル中の単語からも補完、文字の大小を区別しないオプション
  • r4 (2012-06-22)
    • ホットキー
  • r3
    • 単独でctags呼び出し
  • r2
    • 失念
  • r1
    • 失念

ソースコード[編集]

// タグファイルから補完.js r7 2012-10-24
// https://www.haijin-boys.com/wiki/%E3%82%BF%E3%82%B0%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%81%8B%E3%82%89%E8%A3%9C%E5%AE%8C

// https://hp.vector.co.jp/authors/VA025040/ctags/ の 日本語版ctags 5.8J2 で動作確認しています

/** 設定 **/

// タグファイルの名前
var TAGS = ".merytags";

// ctags.exeの名前
// 相対パスの場合はmery本体のあるディレクトリのものを使います
// "c:\\bin\\ctags.exe" のように絶対パスも指定できます
var CTAGS = "ctags.exe";

// ctagsに与える引数 (初期設定:位置を行番号で記憶(必須)、フォルダを再帰的に処理、関数の引数を記憶)
var CTAGS_FLAGS = "--excmd=number --recurse --fields=+S";

// 単語の途中で補完する際の挙動
// trueにするとカーソルの置かれた単語全体から補完
// falseにするとカーソルより左から補完します
var WHOLE_WORD = true;

// 単語の検索の挙動
// trueにすると検索時大文字と小文字を区別しません
// falseにすると区別します
var CASE_INSENSITIVE = true;

// タグを作るフォルダ
// "." にすると、編集中のファイルのあるフォルダでタグを作ります
// ".." などにすると、編集中のファイルの一つ上のフォルダからタグを作ります
var DEFAULT_TAGS_DIR = ".";

// タグファイルがない場合の挙動
// trueにするとタグを作成するフォルダを尋ねます
// falseにするとフォルダを尋ねずに無言で作成を始めます
var CONFIRM_CREATE_TAGS = false;

/** 本体 **/

var FileSystem = new ActiveXObject("Scripting.FileSystemObject");
var Shell = new ActiveXObject("WScript.Shell");

main();

function main() {
	var ctags = makeCtags();
	var tags = makeTags(ctags);
	var query = getQueryWord();
	var result = tags.lookup(query);
	var word = chooseWord(result);

	if ("string" === typeof word) {
		writeWord(word);
	} else if (word === false) {
		tags.update();
	} else {
		jumpToDefinition(word);
	}
}

function makeCtags() {
	return {
		run: run
	};

	function run(dir) {
		var ctags = findCtags();

		try {
			Shell.CurrentDirectory = dir;
			window.Status = 'タグファイルを作成しています お待ちください';
			Shell.Run('"' + ctags + '" -o ' + TAGS + " " + CTAGS_FLAGS, 0, true);
		} catch (e) {}

		window.Status = 'タグファイルを作成しました';
		return FileSystem.BuildPath(dir, TAGS);
	}

	function findCtags() {
		if (FileSystem.FileExists(CTAGS)) {
			return CTAGS;
		}

		var dir = FileSystem.GetParentFolderName(editor.FullName);
		var ctags = FileSystem.BuildPath(dir, CTAGS);

		if (FileSystem.FileExists(ctags)) {
			return ctags;
		}

		throw new Error("ctags.exeが見つかりませんでした\nMery本体のディレクトリに置くか、絶対パスを設定してください");
	}
}

function makeTags(ctags) {
	var fullname = findTagfile();
	var text = loadTagfile();

	return {
		lookup: lookup,
		update: update
	};

	function getPath() {
		return FileSystem.GetParentFolderName(fullname);
	}

	function lookup(word) {
		if (/^\s*$/.test(word)) {
			return;
		}

		word = reEscape(word);

		var opts = CASE_INSENSITIVE ? "igm" : "gm";
		var re = new RegExp("^" + word + ".*$", opts);
		var lines = text.match(re);

		if (!lines) {
			return [];
		}

		return calcWords().concat(calcDefinitions(word));

		function calcWords() {
			var words = new Array(lines.length);

			words[0] = lines[0].substring(0, lines[0].indexOf("\t"));

			if (words.length === 1) {
				return words[0] === word ? [] : words;
			}

			var n = 0;
			for (var i = 1; i < lines.length; i++) {
				var w = lines[i].substring(0, lines[i].indexOf("\t"));

				if (words[n] !== w) {
					n++;
					words[n] = w;
				}
			}

			words.length = n + 1;

			words.sort(function(a, b) {
				return a.localeCompare(b);
			});

			return words;
		}

		function calcDefinitions(word) {
			var defs = new Array(lines.length);
			var n = 0;

			for (var i = 0; i < lines.length; i++) {
				var line = lines[i];
				var tab1 = line.indexOf("\t");

				if (tab1 !== word.length) {
					continue;
				}

				var tab2 = line.indexOf("\t", tab1 + 1);
				var endnum = line.indexOf(";", tab2 + 1);
				var sig = line.indexOf("signature:", endnum + 1);

				var name = line.substring(0, tab1);
				var filename = line.substring(tab1 + 1, tab2);
				var linenum = line.substring(tab2 + 1, endnum);
				var signature = sig < 0 ? "" : line.substring(sig + "signature:".length);

				var fullname = FileSystem.BuildPath(getPath(), filename);

				defs[n] = [fullname, linenum, filename, name + signature];
				defs[n].toString = joinme;
				n++;
			}

			defs.length = n;

			return defs;
		}

		function joinme() {
			return this[3] + " (" + this[2] + " : " + this[1] + ")";
		}
	}

	function reEscape(w) {
		return w.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&");
	}

	function loadTagfile() {
		if (!fullname) {
			fullname = makeTagfile();
		}

		return slurp(fullname);
	}

	function findTagfile() {
		var dir = document.Path;

		while (FileSystem.FolderExists(dir)) {
			var file = FileSystem.BuildPath(dir, TAGS);
			if (FileSystem.FileExists(file)) {
				return file;
			}
			dir = FileSystem.GetParentFolderName(dir);
		}
	}

	function makeTagfile() {
		var dir = FileSystem.BuildPath(document.Path, DEFAULT_TAGS_DIR);

		if (CONFIRM_CREATE_TAGS) {
			dir = window.Prompt("タグファイル作成フォルダ", dir);
		}

		if (!dir) {
			window.Quit();
		}

		return ctags.run(dir);
	}

	function update() {
		return ctags.run(getPath());
	}

	function slurp(filename) {
		var f = FileSystem.OpenTextFile(filename);
		var text = f.ReadAll();
		f.Close();
		return text;
	}
}

function getQueryWord() {
	var s = document.selection;

	if (!s.IsEmpty) {
		return s.Text;
	}

	if (WHOLE_WORD) {
		s.SelectWord();

		// hoge|(); → hogeFuga|(); のように補完 
		if (s.Text.length == 1 && !/\w/.test(s.Text)) {
			s.Collapse(meCollapseStart);
			s.WordLeft(true);
		}
	} else {
		s.WordLeft(true);
	}

	if (/\A\s+\z/.test(s.Text)) {
		s.Collapse(meCollapseEnd);
	}

	return s.Text;
}

function chooseWord(words) {
	if (words && words.length === 1 && typeof words[0] === "string") {
		return words[0];
	}

	var menu = makeMenu();
	var i = menu.Track(0);

	return i === -1 ? false : words && words[i - 1];

	function makeMenu() {
		var menu = window.CreatePopupMenu();
		initMenu(menu);
		menu.Add("タグファイルを更新する", -1);
		return menu;
	}

	function initMenu(menu) {
		if (!words || words.length == 0) {
			return;
		}

		var n = 0;

		function addHotkey(word) {
			if (n > 34) {
				return word;
			}
			n++;
			return "&" + n.toString(36) + ". " + word;
		}

		for (var i = 0; i < words.length; i++) {
			menu.Add(addHotkey(words[i]), i + 1);
		}

		menu.Add(undefined, 0, meMenuSeparator);
	}
}

function jumpToDefinition(def) {
	if (!def) {
		return;
	}
	window.Status = def + "にジャンプします";
	var file = def[0];
	var line = def[1];

	editor.OpenFile(file, 0, meOpenAllowNewWindow);
	editor.ActiveDocument.selection.SetActivePoint(mePosLogical, 1, line, false);
	editor.ActiveDocument.Activate();
}

function writeWord(word) {
	if (word) {
		document.selection.Text = word;
	}
}
スポンサーリンク