Add completions for key bindings

This commit is contained in:
mozbug 2020-02-27 21:31:41 +08:00
parent d66db550c6
commit 37b8b99999
2 changed files with 154 additions and 0 deletions

View file

@ -21,6 +21,7 @@ import * as perf from "@src/perf"
import "@src/lib/number.clamp"
import "@src/lib/html-tagged-template"
import { TabAllCompletionSource } from "@src/completions/TabAll"
import { BindingsCompletionSource } from "@src/completions/Bindings"
import { BufferCompletionSource } from "@src/completions/Tab"
import { BmarkCompletionSource } from "@src/completions/Bmark"
import { ExcmdCompletionSource } from "@src/completions/Excmd"
@ -102,6 +103,7 @@ export function enableCompletions() {
if (!commandline_state.activeCompletions) {
commandline_state.activeCompletions = [
// FindCompletionSource,
BindingsCompletionSource,
BmarkCompletionSource,
TabAllCompletionSource,
BufferCompletionSource,

152
src/completions/Bindings.ts Normal file
View file

@ -0,0 +1,152 @@
import * as Completions from "@src/completions"
import * as config from "@src/lib/config"
class BindingsCompletionOption extends Completions.CompletionOptionHTML
implements Completions.CompletionOptionFuse {
public fuseKeys = []
constructor(
public value: string,
binding: { name: string; value: string; mode: string },
) {
super()
this.html = html`<tr class="BindingsCompletionOption option">
<td class="name">${binding.name}</td>
<td class="content">${binding.value}</td>
<td class="type">${binding.mode}</td>
</tr>`
}
}
export class BindingsCompletionSource extends Completions.CompletionSourceFuse {
public options: BindingsCompletionOption[]
constructor(private _parent) {
super(
["bind", "unbind", "bindurl", "unbindurl", "reset", "reseturl"],
"BindingsCompletionSource",
"Bindings",
)
this._parent.appendChild(this.node)
}
public async filter(exstr: string) {
this.lastExstr = exstr
let options = ""
let [prefix, query] = this.splitOnPrefix(exstr)
const args = query ? query.split(/\s+/) : []
let configName: string = "nmaps"
let modeName = "normal"
let urlPattern: string = null
// Hide self and stop if prefixes don't match
if (prefix) {
// Show self if prefix and currently hidden
if (this.state === "hidden") {
this.state = "normal"
}
} else {
this.state = "hidden"
return
}
// url pattern is mandatory: bindurl, unbindurl, reseturl
if (prefix.trim().endsWith("url")) {
urlPattern = args.length > 0 ? args.shift() : ""
options += urlPattern ? urlPattern + " " : ""
if (args.length === 0) {
const patterns = config.get("subconfigs")
this.options = Object.keys(patterns)
.filter(pattern => pattern.startsWith(urlPattern))
.sort()
.map(pattern => {
return new BindingsCompletionOption(
pattern, {
name: pattern,
value: "",
mode: "URL Pattern",
})
})
return this.updateChain()
}
}
const mode2maps = new Map([
["normal", "nmaps"], ["ignore", "ignoremaps"],
["insert", "imaps"], ["input", "inputmaps"], ["ex", "exmaps"],
["hint", "hintmaps"], ["visual", "vmaps"]])
const maps2mode = new Map(
Array.from(mode2maps.keys()).map(k => [mode2maps.get(k), k]))
// completion maps mode
if (args.length === 1 && args[0].startsWith("--m")) {
const margs = args[0].split("=")
if ("--mode".includes(margs[0])) {
const modeStr = margs.length > 1 ? margs[1] : ""
this.options = Array.from(mode2maps.keys())
.filter(k => k.startsWith(modeStr))
.map(name => {
return new BindingsCompletionOption(
options + "--mode=" + name, {
name,
value: "",
mode: "Mode Name",
})
})
return this.updateChain()
}
}
if (args.length > 0 && args[0].startsWith("--mode=")) {
const modeStr = args.shift()
const mode = modeStr.replace("--mode=", "")
modeName = mode
if (maps2mode.has(mode + "maps")) {
modeName = maps2mode.get(mode + "maps")
}
configName = mode2maps.get(modeName)
options += `--mode=${modeName} `
}
if (!configName) {
this.options = []
return this.updateChain()
}
const bindings = urlPattern ? config.getURL(urlPattern, [configName]) : config.get(configName as any)
if (bindings === undefined) {
this.options = []
return this.updateChain()
}
query = args.join(" ").toLowerCase()
this.options = Object.keys(bindings)
.filter(x => x.toLowerCase().startsWith(query) )
.sort()
.map(keystr => {
return new BindingsCompletionOption(
options + keystr + " " + bindings[keystr], {
name: keystr,
value: JSON.stringify(bindings[keystr]),
mode: `${configName} (${modeName})`,
})
})
return this.updateChain()
}
updateChain() {
// Options are pre-trimmed to the right length.
this.options.forEach(option => (option.state = "normal"))
// Call concrete class
return this.updateDisplay()
}
onInput() {}
}