mirror of
https://github.com/tridactyl/tridactyl.git
synced 2026-09-10 07:16:33 -04:00
Most of the changed lines in this are from random breaking changes in typedoc meaning that lots of docstrings needed to be rewritten
133 lines
4.6 KiB
TypeScript
133 lines
4.6 KiB
TypeScript
import * as Completions from "@src/completions"
|
|
import { excmdsFunctions, getDoc } from "@src/.metadata.generated"
|
|
import * as config from "@src/lib/config"
|
|
import * as aliases from "@src/lib/aliases"
|
|
|
|
export class ExcmdCompletionOption extends Completions.CompletionOptionHTML implements Completions.CompletionOptionFuse {
|
|
public fuseKeys = []
|
|
constructor(
|
|
public value: string,
|
|
public documentation = "",
|
|
) {
|
|
super()
|
|
this.fuseKeys.push(this.value)
|
|
|
|
// Create HTMLElement
|
|
this.html = html`<tr class="ExcmdCompletionOption option">
|
|
<td class="excmd">${value}</td>
|
|
<td class="documentation">${documentation}</td>
|
|
</tr>`
|
|
}
|
|
}
|
|
|
|
export class ExcmdCompletionSource extends Completions.CompletionSourceFuse {
|
|
public options: ExcmdCompletionOption[]
|
|
|
|
constructor(private _parent) {
|
|
super([], "ExcmdCompletionSource", "ex commands")
|
|
|
|
this.updateOptions()
|
|
this._parent.appendChild(this.node)
|
|
}
|
|
|
|
async filter(exstr) {
|
|
this.lastExstr = exstr
|
|
return this.onInput(exstr)
|
|
}
|
|
|
|
async onInput(exstr) {
|
|
return this.updateOptions(exstr)
|
|
}
|
|
|
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
updateChain(exstr = this.lastExstr, options = this.options) {
|
|
if (this.options.length > 0) this.state = "normal"
|
|
else this.state = "hidden"
|
|
|
|
this.updateDisplay()
|
|
}
|
|
|
|
select(option: ExcmdCompletionOption) {
|
|
this.completion = option.value
|
|
option.state = "focused"
|
|
this.lastFocused = option
|
|
}
|
|
|
|
setStateFromScore(scoredOpts: Completions.ScoredOption[]) {
|
|
super.setStateFromScore(scoredOpts, false)
|
|
}
|
|
|
|
private async updateOptions(exstr = "") {
|
|
this.lastExstr = exstr
|
|
|
|
// Add all excmds that start with exstr and that tridactyl has metadata about to completions
|
|
this.options = this.scoreOptions(
|
|
Object.entries(excmdsFunctions)
|
|
.filter(([name]) => name.startsWith(exstr))
|
|
.map(
|
|
([name, fn]) => new ExcmdCompletionOption(name, getDoc(fn)),
|
|
),
|
|
)
|
|
|
|
// Also narrow down aliases map to possible completions
|
|
const exaliasesConfig = config.get("exaliases")
|
|
const exaliases = Object.keys(exaliasesConfig)
|
|
.filter(a => a.startsWith(exstr))
|
|
.reduce((obj, key) => {
|
|
obj[key] = exaliasesConfig[key]
|
|
return obj
|
|
}, {})
|
|
|
|
for (const alias of Object.keys(exaliases)) {
|
|
const cmd = aliases.expandExstr(alias, exaliases)
|
|
const fn = excmdsFunctions[cmd]
|
|
|
|
if (fn) {
|
|
this.options.push(
|
|
new ExcmdCompletionOption(
|
|
alias,
|
|
`Alias for \`${cmd}\`. ${getDoc(fn)}`,
|
|
),
|
|
)
|
|
} else {
|
|
// This can happen when the alias is a composite command or a command with arguments. We can't display doc because we don't know what parameter the alias takes or what it does.
|
|
this.options.push(
|
|
new ExcmdCompletionOption(alias, `Alias for \`${cmd}\`.`),
|
|
)
|
|
}
|
|
}
|
|
|
|
// Add partial matched funcs like: 'conf' ~= 'viewconfig'
|
|
const seen = new Set(this.options.map(o => o.value))
|
|
const partial_options = this.scoreOptions(
|
|
Object.entries(excmdsFunctions)
|
|
.filter(([name]) => name.includes(exstr) && !seen.has(name))
|
|
.map(
|
|
([name, fn]) => new ExcmdCompletionOption(name, getDoc(fn)),
|
|
),
|
|
)
|
|
this.options = this.options.concat(partial_options)
|
|
|
|
this.options.forEach(o => (o.state = "normal"))
|
|
return this.updateChain()
|
|
}
|
|
|
|
private scoreOptions(options: ExcmdCompletionOption[]) {
|
|
return options.sort((o1, o2) => o1.value.localeCompare(o2.value))
|
|
|
|
// Too slow with large profiles
|
|
// let histpos = state.cmdHistory.map(s => s.split(" ")[0]).reverse()
|
|
// return exstrs.sort((a, b) => {
|
|
// let posa = histpos.findIndex(x => x == a)
|
|
// let posb = histpos.findIndex(x => x == b)
|
|
// // If two ex commands have the same position, sort lexically
|
|
// if (posa == posb) return a < b ? -1 : 1
|
|
// // If they aren't found in the list they get lower priority
|
|
// if (posa == -1) return 1
|
|
// if (posb == -1) return -1
|
|
// // Finally, sort by history position
|
|
// return posa < posb ? -1 : 1
|
|
// })
|
|
}
|
|
}
|