Factor out autocompleter

This commit is contained in:
Alan Bernstein 2017-05-18 18:30:25 -05:00
parent db256c91cc
commit 39e46e2c48

View file

@ -1,8 +1,9 @@
class REPL {
constructor(input, output, button) {
constructor(input, output, button, completer) {
this.input = input
this.output = output
this.button = button
this.completer = completer
this.history = []
this.history_index = 0
this.history_buffer = ''
@ -16,21 +17,6 @@ class REPL {
UP_ARROW: 38,
DOWN_ARROW: 40
}
var keywords = {
// keyword: length of substring that comes after cursor
"SetBit()": 1,
"ClearBit()": 1,
"SetRowAttrs()": 1,
"SetColumnAttrs()": 1,
"Bitmap()": 1,
"Union()": 1,
"Intersect()": 1,
"Difference()": 1,
"Count()": 1,
"Range()": 1,
"TopN()": 1,
"frame=": 0,
}
this.input.addEventListener("keydown", function(e) {
if (e.keyCode == keys.UP_ARROW) {
@ -70,42 +56,7 @@ class REPL {
}
if (e.keyCode == keys.TAB) {
e.preventDefault()
// extract word fragment ending at cursor. a word fragment:
// - starts with last nonalpha character before cursor (or beginning of string)
// - ends at cursor
var word_start = repl.input.selectionEnd-1
while(word_start>0) {
var c = repl.input.value.charCodeAt(word_start)
if(!((c>64 && c<91) || (c>96 && c<123))) {
word_start++
break
}
word_start--
}
var input_word = repl.input.value.substring(word_start, repl.input.selectionEnd)
// check for keyword match and insert if exactly one match
var matches = []
for(var keyword in keywords) {
if(keyword.startsWith(input_word)){
matches.push(keyword)
}
}
if(matches.length > 1) {
// display in some dynamic element
}
if(matches.length == 1) {
var cursor_pos = repl.input.selectionEnd
var completion = matches[0].substring(input_word.length)
var before = repl.input.value.substring(0, cursor_pos)
var after = repl.input.value.substring(cursor_pos)
repl.input.value = before + completion + after
var new_pos = cursor_pos + completion.length - keywords[matches[0]]
repl.input.setSelectionRange(new_pos, new_pos)
}
repl.completer.complete()
}
})
repl.button.onclick = function() {
@ -451,11 +402,73 @@ Date.prototype.timeNow = function () {
populate_version()
class Autocompleter {
constructor(input) {
this.input = input
this.keyword_map = this.static_keywords
}
get static_keywords() {
return {
// keyword: length of substring that comes after cursor
"SetBit()": 1,
"ClearBit()": 1,
"SetRowAttrs()": 1,
"SetColumnAttrs()": 1,
"Bitmap()": 1,
"Union()": 1,
"Intersect()": 1,
"Difference()": 1,
"Count()": 1,
"Range()": 1,
"TopN()": 1,
"frame=": 0,
}
}
complete() {
var completer = this
// extract word fragment ending at cursor. a word fragment:
// - starts with last nonalpha character before cursor (or beginning of string)
// - ends at cursor
var word_start = completer.input.selectionEnd-1
while(word_start>0) {
var c = completer.input.value.charCodeAt(word_start)
if(!((c>64 && c<91) || (c>96 && c<123))) {
word_start++
break
}
word_start--
}
var input_word = completer.input.value.substring(word_start, completer.input.selectionEnd)
// check for keyword match and insert if exactly one match
var matches = []
for(var keyword in this.keyword_map) {
if(keyword.startsWith(input_word)){
matches.push(keyword)
}
}
if(matches.length == 1) {
var cursor_pos = completer.input.selectionEnd
var completion = matches[0].substring(input_word.length)
var before = completer.input.value.substring(0, cursor_pos)
var after = completer.input.value.substring(cursor_pos)
completer.input.value = before + completion + after
var new_pos = cursor_pos + completion.length - this.keyword_map[matches[0]]
completer.input.setSelectionRange(new_pos, new_pos)
}
}
}
var input = document.getElementById('query')
var output = document.getElementById('outputs')
var button = document.getElementById('query-btn')
repl = new REPL(input, output, button)
autocompleter = new Autocompleter(input)
repl = new REPL(input, output, button, autocompleter)
repl.populate_index_dropdown()
repl.bind_events()