「タグファイルから補完」の版間の差分
ナビゲーションに移動
検索に移動
編集の要約なし |
Snipsnipsnip (トーク | 投稿記録) r5に更新 |
||
| 3行目: | 3行目: | ||
項目を選ぶとその単語が挿入されます。 | 項目を選ぶとその単語が挿入されます。 | ||
単語が完全な形の場合、タグジャンプを行います。 | |||
kazyさんの[[ctags.exeでtagsファイルを生成、タグジャンプを行うマクロ]]とあわせてお使いください。(単独で使ってもタグジャンプ機能はあります) | |||
*インストール | *インストール | ||
#下のスクリプトをコピーして、MeryのMy Macroフォルダなどに保存 | #下のスクリプトをコピーして、MeryのMy Macroフォルダなどに保存 | ||
#マクロを登録し、Ctrl+Shift+SpaceやCtrl+ | #マクロを登録し、Ctrl+→やCtrl+Shift+SpaceやCtrl+Qキーなどにお好みで設定する | ||
#Mery.exeのあるフォルダに[[http://hp.vector.co.jp/authors/VA025040/ctags/ ctags.exe]]を置く | #Mery.exeのあるフォルダに[[http://hp.vector.co.jp/authors/VA025040/ctags/ ctags.exe]]を置く | ||
| 26行目: | 27行目: | ||
<source lang="javascript"> | <source lang="javascript"> | ||
// タグファイルから補完.js | // タグファイルから補完.js r5 | ||
// http://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 | |||
/** 設定 **/ | /** 設定 **/ | ||
| 36行目: | 38行目: | ||
// 相対パスの場合は以下のディレクトリから順に探します | // 相対パスの場合は以下のディレクトリから順に探します | ||
// ・mery本体と同じディレクトリ | // ・mery本体と同じディレクトリ | ||
var CTAGS = "ctags.exe" | var CTAGS = "ctags.exe" | ||
// ctagsに与える引数 (初期設定:位置を行番号で記憶( | // ctagsに与える引数 (初期設定:位置を行番号で記憶(必須)、フォルダを再帰的に処理、関数の引数を記憶) | ||
var CTAGS_FLAGS = "--excmd=number --recurse" | var CTAGS_FLAGS = "--excmd=number --recurse --fields=+S" | ||
// 単語の途中で補完する際の挙動 | // 単語の途中で補完する際の挙動 | ||
| 47行目: | 47行目: | ||
// falseにするとカーソルより左から補完します | // falseにするとカーソルより左から補完します | ||
var WHOLE_WORD = false | var WHOLE_WORD = false | ||
// 単語の検索の挙動 | |||
// trueにすると検索時大文字と小文字を区別しません | |||
// falseにすると区別します | |||
var CASE_INSENSITIVE = true | |||
/** 本体 **/ | /** 本体 **/ | ||
| 60行目: | 65行目: | ||
var tags = makeTags(ctags) | var tags = makeTags(ctags) | ||
var query = getQueryWord() | var query = getQueryWord() | ||
var | var result = tags.lookup(query) | ||
var word = chooseWord( | var word = chooseWord(result) | ||
writeWord(word) | if ("string" === typeof word) | ||
{ | |||
writeWord(word) | |||
} | |||
else if (word === false) | |||
{ | |||
tags.update() | |||
} | |||
else | |||
{ | |||
jumpToDefinition(word) | |||
} | |||
} | } | ||
| 74行目: | 90行目: | ||
var ctags = findCtags() | var ctags = findCtags() | ||
try | |||
{ | |||
Shell.CurrentDirectory = dir | |||
window.Status = 'タグファイルを作成しています お待ちください' | |||
Shell.Run(ctags + " -o " + TAGS + " " + CTAGS_FLAGS, 0, true) | |||
} | |||
catch (e) | |||
{ | { | ||
} | } | ||
window.Status = 'タグファイルを作成しました' | window.Status = 'タグファイルを作成しました' | ||
return FileSystem.BuildPath(dir, TAGS) | return FileSystem.BuildPath(dir, TAGS) | ||
| 88行目: | 106行目: | ||
function findCtags() | function findCtags() | ||
{ | { | ||
if (FileSystem.FileExists(CTAGS)) | |||
{ | |||
return '"' + CTAGS + '"' | |||
} | |||
var dir = FileSystem.GetParentFolderName(editor.FullName) | |||
var dir = FileSystem.GetParentFolderName( | |||
var ctags = FileSystem.BuildPath(dir, CTAGS) | var ctags = FileSystem.BuildPath(dir, CTAGS) | ||
if (FileSystem.FileExists(ctags)) | if (FileSystem.FileExists(ctags)) | ||
{ | { | ||
return | return '"' + ctags + '"' | ||
} | } | ||
throw new Error("ctags.exeが見つかりませんでした\nMery本体のディレクトリに置くか、絶対パスを設定してください") | |||
} | } | ||
} | } | ||
| 107行目: | 125行目: | ||
function makeTags(ctags) | function makeTags(ctags) | ||
{ | { | ||
var fullname = findTagfile() | |||
var text = loadTagfile() | var text = loadTagfile() | ||
return { lookup: lookup, update: update } | return { lookup: lookup, update: update } | ||
function getPath() | |||
{ | |||
return FileSystem.GetParentFolderName(fullname) | |||
} | |||
function lookup(word) | function lookup(word) | ||
{ | { | ||
var re = new RegExp("^" + | if (/^\s*$/.test(word)) { return } | ||
return | |||
word = reEscape(word) | |||
var re = new RegExp("^" + word + ".*$", CASE_INSENSITIVE ? "igm" : "gm") | |||
var lines = text.match(re) | |||
if (!lines) { return [] } | |||
return calcWords().concat(calcDefinitions(word)) | |||
function calcWords() | |||
{ | |||
if (lines.length === 1) { return [] } | |||
var words = new Array(lines.length) | |||
words[0] = lines[0].substring(0, lines[0].indexOf("\t")) | |||
var n = 0 | |||
for (var i = 1; i < lines.length; i++) | |||
{ | |||
var word = lines[i].substring(0, lines[i].indexOf("\t")) | |||
if (words[n] !== word) | |||
{ | |||
n++ | |||
words[n] = word | |||
} | |||
} | |||
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 tab1 = lines[i].indexOf("\t") | |||
if (tab1 !== word.length) { continue } | |||
var tab2 = lines[i].indexOf("\t", tab1 + 1) | |||
var endnum = lines[i].indexOf(";", tab2 + 1) | |||
var sig = lines[i].indexOf("signature:", endnum + 1) | |||
var name = lines[i].substring(0, tab1) | |||
var filename = lines[i].substring(tab1 + 1, tab2) | |||
var line = lines[i].substring(tab2 + 1, endnum) | |||
var signature = sig < 0 ? "" : lines[i].substring(sig + "signature:".length) | |||
var fullname = FileSystem.BuildPath(getPath(), filename) | |||
defs[n] = [fullname, line, 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) | function reEscape(w) | ||
{ | { | ||
return | return w.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&") | ||
} | } | ||
function loadTagfile() | function loadTagfile() | ||
{ | { | ||
if (!fullname) | |||
if (! | |||
{ | { | ||
fullname = makeTagfile() | |||
} | } | ||
return slurp( | return slurp(fullname) | ||
} | } | ||
| 160行目: | 257行目: | ||
function update() | function update() | ||
{ | { | ||
return ctags.run(getPath()) | |||
return ctags.run( | |||
} | } | ||
| 205行目: | 299行目: | ||
} | } | ||
function chooseWord(words | function chooseWord(words) | ||
{ | { | ||
if (words && words.length === 1 && typeof words[0] === "string") | |||
{ | |||
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] | |||
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 | ||
} | } | ||
| 230行目: | 322行目: | ||
{ | { | ||
if (!words || words.length == 0) { return } | if (!words || words.length == 0) { return } | ||
var n = 0 | var n = 0 | ||
| 253行目: | 338行目: | ||
menu.Add(undefined, 0, meMenuSeparator) | 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() | |||
} | } | ||
| 261行目: | 358行目: | ||
document.selection.Text = word | document.selection.Text = word | ||
} | } | ||
} | } | ||
</source> | </source> | ||
2012年8月1日 (水) 15:40時点における版
ctagsの生成したtagsファイルから検索して単語のメニューを出します。
項目を選ぶとその単語が挿入されます。
単語が完全な形の場合、タグジャンプを行います。
kazyさんのctags.exeでtagsファイルを生成、タグジャンプを行うマクロとあわせてお使いください。(単独で使ってもタグジャンプ機能はあります)
- インストール
- 下のスクリプトをコピーして、MeryのMy Macroフォルダなどに保存
- マクロを登録し、Ctrl+→やCtrl+Shift+SpaceやCtrl+Qキーなどにお好みで設定する
- Mery.exeのあるフォルダに[ctags.exe]を置く
- 初回起動
- タグファイルが生成されていないので、どこに生成するか尋ねられる
- 指定したディレクトリ以下のソースファイル全てが再帰的にタグファイルに登録される
- 「タグファイルの作成が完了しました」とステータスバーに出るまで待つ
- タグファイルの作成後
- 補完したい単語の右にカーソルを置き、マクロを起動する
- メニューの項目を選ぶと、その単語が挿入される
- メニューの最後の「タグファイルを更新する」を選ぶと、タグファイルを作り直すことができる
// タグファイルから補完.js r5
// http://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
/** 設定 **/
// タグファイルの名前
var TAGS = "tags"
// ctags.exeの名前
// 相対パスの場合は以下のディレクトリから順に探します
// ・mery本体と同じディレクトリ
var CTAGS = "ctags.exe"
// ctagsに与える引数 (初期設定:位置を行番号で記憶(必須)、フォルダを再帰的に処理、関数の引数を記憶)
var CTAGS_FLAGS = "--excmd=number --recurse --fields=+S"
// 単語の途中で補完する際の挙動
// trueにするとカーソルの置かれた単語全体から補完
// falseにするとカーソルより左から補完します
var WHOLE_WORD = false
// 単語の検索の挙動
// trueにすると検索時大文字と小文字を区別しません
// falseにすると区別します
var CASE_INSENSITIVE = true
/** 本体 **/
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 re = new RegExp("^" + word + ".*$", CASE_INSENSITIVE ? "igm" : "gm")
var lines = text.match(re)
if (!lines) { return [] }
return calcWords().concat(calcDefinitions(word))
function calcWords()
{
if (lines.length === 1) { return [] }
var words = new Array(lines.length)
words[0] = lines[0].substring(0, lines[0].indexOf("\t"))
var n = 0
for (var i = 1; i < lines.length; i++)
{
var word = lines[i].substring(0, lines[i].indexOf("\t"))
if (words[n] !== word)
{
n++
words[n] = word
}
}
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 tab1 = lines[i].indexOf("\t")
if (tab1 !== word.length) { continue }
var tab2 = lines[i].indexOf("\t", tab1 + 1)
var endnum = lines[i].indexOf(";", tab2 + 1)
var sig = lines[i].indexOf("signature:", endnum + 1)
var name = lines[i].substring(0, tab1)
var filename = lines[i].substring(tab1 + 1, tab2)
var line = lines[i].substring(tab2 + 1, endnum)
var signature = sig < 0 ? "" : lines[i].substring(sig + "signature:".length)
var fullname = FileSystem.BuildPath(getPath(), filename)
defs[n] = [fullname, line, 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 = window.Prompt("タグファイル作成フォルダ", document.Path)
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
}
}
スポンサーリンク