JavaScriptで作られたエディタCodeMirrorで、こんな風に補完をしたい。
準備
まず以下のjsとcssを読み込む
- codemirror/lib/codemirror.js
- codemirror/lib/codemirror.css
- codemirror/addon/hint/show-hint.js
- codemirror/addon/hint/show-hint.css
同期的に補完候補を表示する
以下coffeescript
elはなんか適当なDOMTextAreaELement渡してください。
{Pos} = CodeMirror
autocomplete = (cm) ->
CodeMirror.showHint cm, ->
cur = cm.getCursor()
token = cm.getTokenAt(cur)
start = token.start
end = token.end
from = Pos(cur.line, start)
to = Pos(cur.line, end)
list:[
"aaa"
"bbb"
"ccc"
]
from: from
to: to
CodeMirror.fromTextArea el,
extraKeys:
'Tab': autocomplete
TabキーでAutoCompleteを発火させる。showHintで上のような構造体を渡せば補完が走る
非同期的に補完候補を表示する
{Pos} = CodeMirror
autocompleteAsync = (cm) ->
callback = (cm) ->
cur = cm.getCursor()
token = cm.getTokenAt(cur)
start = token.start
end = token.end
from = Pos(cur.line, start)
to = Pos(cur.line, end)
setTimeout ->
CodeMirror.showHint cm, ->
list:[
"aaa"
"bbb"
"ccc"
]
from: from
to: to
, 400
callback.async = true
CodeMirror.showHint cm, callback
CodeMirror.fromTextArea el,
extraKeys:]
'Tab': autocompleteAsync
入力したら常に補完できないか確認する
Tabを押さずにキー入力の度に補完を発火できるかどうか確認する。
{Pos} = CodeMirror
watchChange = (cm) ->
CodeMirror.showHint cm, ->
cur = cm.getCursor()
token = cm.getTokenAt(cur)
start = token.start
end = token.end
from = Pos(cur.line, start)
to = Pos(cur.line, end)
if token.string is '@'
list:[
"@aaa"
"@bbb"
"@ccc"
]
from: from
to: to
cm = CodeMirror.fromTextArea el,
cm.on 'change', -> watchChange(cm)
この例だと @ を入力したら @aaa, @bbb, @ccc を候補に出る。
実践編
バッファ内からすべての単語を探し、入力中の文字列とマッチしたものを表示する。
(ここではunderscoreも使っているので注意)
{Pos} = CodeMirror
collectBufferWords = (cm, word) ->
bufferWords = _.compact(cm.getValue().split(/\n|\s/))
_.uniq _.filter bufferWords, (w) ->
w.indexOf(word) > -1 and w isnt word
autocompleteAnyWords = (cm) ->
CodeMirror.showHint cm, ->
cur = cm.getCursor()
token = cm.getTokenAt(cur)
start = token.start
end = token.end
from = Pos(cur.line, start)
to = Pos(cur.line, end)
currentWord = token.string
ch = cur.ch
line = cur.line
while --ch > -1
t = cm.getTokenAt({ch, line})
if t.string is ' '
break
currentWord= t.string + currentWord
matchedWords = collectBufferWords(cm, currentWord)
list: matchedWords
from: {ch, line}
to: to
CodeMirror.fromTextArea el,
extraKeys:]
'Tab': autocompleteAnyWords
これで冒頭の
ができるってワケ