mirror of
https://github.com/vale981/tridactyl
synced 2025-03-06 01:51:40 -05:00
completions: Make sure completion computation has ended before resizeArea
Before this commit, Tridactyl had a bug where resizeArea could be called before completion computation had ended, which resulted in completions pushing the input field out of the viewport (easy way to reproduce this: open a lot of tabs and press `b` to open buffer completions). This happened because for some of the completion sources, `filter` returned before completion computation had actually ended. This is fixed by making sure that filter() (and all underlying calls to updateOptions, onInput, updateChain...) return a promise that will only be resolved once completion computation has actually ended.
This commit is contained in:
parent
5e13b87ebd
commit
5dd1ec3a74
13 changed files with 124 additions and 114 deletions
|
@ -285,7 +285,7 @@ clInput.addEventListener("input", () => {
|
|||
if (exstr != clInput.value) return
|
||||
|
||||
onInputPromise = refresh_completions(exstr)
|
||||
}, 1)
|
||||
}, 100)
|
||||
})
|
||||
|
||||
/** @hidden **/
|
||||
|
|
|
@ -42,9 +42,12 @@ export abstract class CompletionSource {
|
|||
let commands = aliases.getCmdAliasMapping()
|
||||
|
||||
// Now, for each prefix given as argument, add it to the completionsource's prefix list and also add any alias it has
|
||||
prefixes.map(p => p.trim()).forEach(p => {
|
||||
prefixes
|
||||
.map(p => p.trim())
|
||||
.forEach(p => {
|
||||
this.prefixes.push(p)
|
||||
if (commands[p]) this.prefixes = this.prefixes.concat(commands[p])
|
||||
if (commands[p])
|
||||
this.prefixes = this.prefixes.concat(commands[p])
|
||||
})
|
||||
|
||||
// Not sure this is necessary but every completion source has it
|
||||
|
@ -143,7 +146,7 @@ export abstract class CompletionSourceFuse extends CompletionSource {
|
|||
public options: CompletionOptionFuse[]
|
||||
protected lastExstr: string
|
||||
|
||||
protected optionContainer = html`<table class="optionContainer">`
|
||||
protected optionContainer = html`<table class="optionContainer"></table>`
|
||||
|
||||
constructor(prefixes, className: string, title?: string) {
|
||||
super(prefixes)
|
||||
|
@ -162,7 +165,7 @@ export abstract class CompletionSourceFuse extends CompletionSource {
|
|||
public async filter(exstr: string) {
|
||||
this.lastExstr = exstr
|
||||
await this.onInput(exstr)
|
||||
await this.updateChain()
|
||||
return this.updateChain()
|
||||
}
|
||||
|
||||
updateChain(exstr = this.lastExstr, options = this.options) {
|
||||
|
|
|
@ -25,9 +25,11 @@ class BmarkCompletionOption extends Completions.CompletionOptionHTML
|
|||
<td class="prefix">${"".padEnd(2)}</td>
|
||||
<td class="icon"></td>
|
||||
<td class="title">${bmark.title}</td>
|
||||
<td class="content"><a class="url" target="_blank" href=${
|
||||
bmark.url
|
||||
}>${bmark.url}</a></td>
|
||||
<td class="content">
|
||||
<a class="url" target="_blank" href=${bmark.url}
|
||||
>${bmark.url}</a
|
||||
>
|
||||
</td>
|
||||
</tr>`
|
||||
}
|
||||
}
|
||||
|
@ -67,7 +69,7 @@ export class BmarkCompletionSource extends Completions.CompletionSourceFuse {
|
|||
page => new BmarkCompletionOption(option + page.url, page),
|
||||
)
|
||||
|
||||
this.updateChain()
|
||||
return this.updateChain()
|
||||
}
|
||||
|
||||
updateChain() {
|
||||
|
@ -75,7 +77,7 @@ export class BmarkCompletionSource extends Completions.CompletionSourceFuse {
|
|||
this.options.forEach(option => (option.state = "normal"))
|
||||
|
||||
// Call concrete class
|
||||
this.updateDisplay()
|
||||
return this.updateDisplay()
|
||||
}
|
||||
|
||||
onInput() {}
|
||||
|
|
|
@ -35,7 +35,7 @@ export class ExcmdCompletionSource extends Completions.CompletionSourceFuse {
|
|||
}
|
||||
|
||||
async onInput(exstr) {
|
||||
await this.updateOptions(exstr)
|
||||
return this.updateOptions(exstr)
|
||||
}
|
||||
|
||||
updateChain(exstr = this.lastExstr, options = this.options) {
|
||||
|
@ -82,7 +82,7 @@ export class ExcmdCompletionSource extends Completions.CompletionSourceFuse {
|
|||
}
|
||||
|
||||
this.options.forEach(o => (o.state = "normal"))
|
||||
this.updateChain()
|
||||
return this.updateChain()
|
||||
}
|
||||
|
||||
private scoreOptions(options: ExcmdCompletionOption[]) {
|
||||
|
|
|
@ -9,9 +9,11 @@ class FileSystemCompletionOption extends Completions.CompletionOptionHTML
|
|||
constructor(public value: string) {
|
||||
super()
|
||||
this.fuseKeys = [value]
|
||||
this.html = html`<tr class="FileSystemCompletionOption option">
|
||||
this.html = html`
|
||||
<tr class="FileSystemCompletionOption option">
|
||||
<td class="value">${value}</td>
|
||||
</tr>`
|
||||
</tr>
|
||||
`
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -25,7 +27,7 @@ export class FileSystemCompletionSource extends Completions.CompletionSourceFuse
|
|||
}
|
||||
|
||||
public async onInput(exstr) {
|
||||
this.filter(exstr)
|
||||
return this.filter(exstr)
|
||||
}
|
||||
|
||||
public async filter(exstr: string) {
|
||||
|
@ -71,6 +73,6 @@ export class FileSystemCompletionSource extends Completions.CompletionSourceFuse
|
|||
)
|
||||
|
||||
this.state = "normal"
|
||||
this.updateChain()
|
||||
return this.updateChain()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,10 +5,7 @@ class GuisetCompletionOption extends Completions.CompletionOptionHTML
|
|||
implements Completions.CompletionOptionFuse {
|
||||
public fuseKeys = []
|
||||
|
||||
constructor(
|
||||
public value: string,
|
||||
displayValue: string
|
||||
) {
|
||||
constructor(public value: string, displayValue: string) {
|
||||
super()
|
||||
this.fuseKeys.push(value)
|
||||
|
||||
|
@ -56,13 +53,19 @@ export class GuisetCompletionSource extends Completions.CompletionSourceFuse {
|
|||
this.options = this.options.concat(
|
||||
Object.keys(metaRules[ruleName])
|
||||
.filter(s => s.startsWith(subRule))
|
||||
.map(s => new GuisetCompletionOption(`${ruleName} ${s}`, s)))
|
||||
.map(
|
||||
s => new GuisetCompletionOption(`${ruleName} ${s}`, s),
|
||||
),
|
||||
)
|
||||
}
|
||||
if (potentialRules[ruleName]) {
|
||||
this.options = this.options.concat(
|
||||
Object.keys(potentialRules[ruleName].options)
|
||||
.filter(s => s.startsWith(subRule))
|
||||
.map(s => new GuisetCompletionOption(`${ruleName} ${s}`, s)))
|
||||
.map(
|
||||
s => new GuisetCompletionOption(`${ruleName} ${s}`, s),
|
||||
),
|
||||
)
|
||||
}
|
||||
if (this.options.length == 0) {
|
||||
this.options = Object.keys(metaRules)
|
||||
|
@ -71,7 +74,7 @@ export class GuisetCompletionSource extends Completions.CompletionSourceFuse {
|
|||
.map(s => new GuisetCompletionOption(s, s))
|
||||
}
|
||||
|
||||
this.updateChain()
|
||||
return this.updateChain()
|
||||
}
|
||||
|
||||
updateChain() {
|
||||
|
@ -79,10 +82,10 @@ export class GuisetCompletionSource extends Completions.CompletionSourceFuse {
|
|||
this.options.forEach(option => (option.state = "normal"))
|
||||
|
||||
// Call concrete class
|
||||
this.updateDisplay()
|
||||
return this.updateDisplay()
|
||||
}
|
||||
|
||||
onInput(arg) {
|
||||
this.filter(arg)
|
||||
return this.filter(arg)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -136,7 +136,7 @@ export class HelpCompletionSource extends Completions.CompletionSourceFuse {
|
|||
this.options = opts.sort((compopt1, compopt2) =>
|
||||
compopt1.name.localeCompare(compopt2.name),
|
||||
)
|
||||
this.updateChain()
|
||||
return this.updateChain()
|
||||
}
|
||||
|
||||
updateChain() {
|
||||
|
@ -144,7 +144,7 @@ export class HelpCompletionSource extends Completions.CompletionSourceFuse {
|
|||
this.options.forEach(option => (option.state = "normal"))
|
||||
|
||||
// Call concrete class
|
||||
this.updateDisplay()
|
||||
return this.updateDisplay()
|
||||
}
|
||||
|
||||
onInput() {}
|
||||
|
|
|
@ -23,9 +23,11 @@ class HistoryCompletionOption extends Completions.CompletionOptionHTML
|
|||
<td class="prefix">${"".padEnd(2)}</td>
|
||||
<td class="icon"></td>
|
||||
<td class="title">${page.title}</td>
|
||||
<td class="content"><a class="url" target="_blank" href=${
|
||||
page.url
|
||||
}>${page.url}</a></td>
|
||||
<td class="content">
|
||||
<a class="url" target="_blank" href=${page.url}
|
||||
>${page.url}</a
|
||||
>
|
||||
</td>
|
||||
</tr>`
|
||||
}
|
||||
}
|
||||
|
@ -85,7 +87,7 @@ export class HistoryCompletionSource extends Completions.CompletionSourceFuse {
|
|||
page => new HistoryCompletionOption(options + page.url, page),
|
||||
)
|
||||
|
||||
this.updateChain()
|
||||
return this.updateChain()
|
||||
}
|
||||
|
||||
updateChain() {
|
||||
|
@ -93,7 +95,7 @@ export class HistoryCompletionSource extends Completions.CompletionSourceFuse {
|
|||
this.options.forEach(option => (option.state = "normal"))
|
||||
|
||||
// Call concrete class
|
||||
this.updateDisplay()
|
||||
return this.updateDisplay()
|
||||
}
|
||||
|
||||
onInput() {}
|
||||
|
|
|
@ -5,10 +5,7 @@ class PreferenceCompletionOption extends Completions.CompletionOptionHTML
|
|||
implements Completions.CompletionOptionFuse {
|
||||
public fuseKeys = []
|
||||
|
||||
constructor(
|
||||
public value: string,
|
||||
public prefvalue: string
|
||||
) {
|
||||
constructor(public value: string, public prefvalue: string) {
|
||||
super()
|
||||
this.fuseKeys.push(value)
|
||||
this.html = html`<tr class="PreferenceCompletionOption option">
|
||||
|
@ -22,11 +19,7 @@ export class PreferenceCompletionSource extends Completions.CompletionSourceFuse
|
|||
public options: PreferenceCompletionOption[]
|
||||
|
||||
constructor(private _parent) {
|
||||
super(
|
||||
["setpref"],
|
||||
"PreferenceCompletionSource",
|
||||
"Preference",
|
||||
)
|
||||
super(["setpref"], "PreferenceCompletionSource", "Preference")
|
||||
|
||||
this._parent.appendChild(this.node)
|
||||
}
|
||||
|
@ -50,8 +43,7 @@ export class PreferenceCompletionSource extends Completions.CompletionSourceFuse
|
|||
this.options = Object.keys(preferences)
|
||||
.filter(key => key.startsWith(pref))
|
||||
.map(key => new PreferenceCompletionOption(key, preferences[key]))
|
||||
if (this.options.length > 0)
|
||||
this.state = "normal"
|
||||
this.updateChain()
|
||||
if (this.options.length > 0) this.state = "normal"
|
||||
return this.updateChain()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,7 +13,9 @@ class RssCompletionOption extends Completions.CompletionOptionHTML
|
|||
|
||||
this.html = html`<tr class="RssCompletionOption option">
|
||||
<td class="title">${title}</td>
|
||||
<td class="content"><a class="url" target="_blank" href=${url}>${url}</a></td>
|
||||
<td class="content">
|
||||
<a class="url" target="_blank" href=${url}>${url}</a>
|
||||
</td>
|
||||
<td class="type">${type}</td>
|
||||
</tr>`
|
||||
}
|
||||
|
@ -64,6 +66,6 @@ export class RssCompletionSource extends Completions.CompletionSourceFuse {
|
|||
return opt
|
||||
})
|
||||
}
|
||||
this.updateChain()
|
||||
return this.updateChain()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -62,9 +62,11 @@ export class SettingsCompletionSource extends Completions.CompletionSourceFuse {
|
|||
options += options ? " " : ""
|
||||
|
||||
let file, default_config, settings
|
||||
if (!(file = metadata.everything.getFile("src/lib/config.ts"))
|
||||
|| !(default_config = file.getClass("default_config"))
|
||||
|| !(settings = config.get()))
|
||||
if (
|
||||
!(file = metadata.everything.getFile("src/lib/config.ts")) ||
|
||||
!(default_config = file.getClass("default_config")) ||
|
||||
!(settings = config.get())
|
||||
)
|
||||
return
|
||||
|
||||
this.options = Object.keys(settings)
|
||||
|
@ -74,7 +76,7 @@ export class SettingsCompletionSource extends Completions.CompletionSourceFuse {
|
|||
let md = undefined
|
||||
let doc = ""
|
||||
let type = ""
|
||||
if (md = default_config.getMember(setting)) {
|
||||
if ((md = default_config.getMember(setting))) {
|
||||
doc = md.doc
|
||||
type = md.type.toString()
|
||||
}
|
||||
|
@ -86,7 +88,7 @@ export class SettingsCompletionSource extends Completions.CompletionSourceFuse {
|
|||
})
|
||||
})
|
||||
|
||||
this.updateChain()
|
||||
return this.updateChain()
|
||||
}
|
||||
|
||||
updateChain() {
|
||||
|
@ -94,7 +96,7 @@ export class SettingsCompletionSource extends Completions.CompletionSourceFuse {
|
|||
this.options.forEach(option => (option.state = "normal"))
|
||||
|
||||
// Call concrete class
|
||||
this.updateDisplay()
|
||||
return this.updateDisplay()
|
||||
}
|
||||
|
||||
onInput() {}
|
||||
|
|
|
@ -35,16 +35,17 @@ class BufferCompletionOption extends Completions.CompletionOptionHTML
|
|||
const favIconUrl = tab.favIconUrl
|
||||
? tab.favIconUrl
|
||||
: Completions.DEFAULT_FAVICON
|
||||
this.html = html`<tr class="BufferCompletionOption option container_${
|
||||
container.color
|
||||
} container_${container.icon} container_${container.name}">
|
||||
this.html = html`<tr class="BufferCompletionOption option container_${container.color} container_${container.icon} container_${container.name}"
|
||||
>
|
||||
<td class="prefix">${pre.padEnd(2)}</td>
|
||||
<td class="container"></td>
|
||||
<td class="icon"><img src="${favIconUrl}"/></td>
|
||||
<td class="icon"><img src="${favIconUrl}" /></td>
|
||||
<td class="title">${tab.index + 1}: ${tab.title}</td>
|
||||
<td class="content"><a class="url" target="_blank" href=${
|
||||
tab.url
|
||||
}>${tab.url}</a></td>
|
||||
<td class="content">
|
||||
<a class="url" target="_blank" href=${tab.url}
|
||||
>${tab.url}</a
|
||||
>
|
||||
</td>
|
||||
</tr>`
|
||||
}
|
||||
}
|
||||
|
@ -122,18 +123,18 @@ export class BufferCompletionSource extends Completions.CompletionSourceFuse {
|
|||
} else {
|
||||
this.options.forEach(option => (option.state = "normal"))
|
||||
}
|
||||
this.updateDisplay()
|
||||
return this.updateDisplay()
|
||||
}
|
||||
|
||||
async onInput(exstr) {
|
||||
// Schedule an update, if you like. Not very useful for tabs, but
|
||||
// will be for other things.
|
||||
this.updateOptions(exstr)
|
||||
return this.updateOptions(exstr)
|
||||
}
|
||||
|
||||
async filter(exstr) {
|
||||
this.lastExstr = exstr
|
||||
await this.onInput(exstr)
|
||||
return this.onInput(exstr)
|
||||
}
|
||||
|
||||
setStateFromScore(scoredOpts: Completions.ScoredOption[]) {
|
||||
|
|
|
@ -22,19 +22,20 @@ class TabAllCompletionOption extends Completions.CompletionOptionHTML
|
|||
const favIconUrl = tab.favIconUrl
|
||||
? tab.favIconUrl
|
||||
: Completions.DEFAULT_FAVICON
|
||||
this.html = html`<tr class="BufferAllCompletionOption option container_${
|
||||
container.color
|
||||
} container_${container.icon} container_${container.name} ${
|
||||
incognito ? "incognito" : ""
|
||||
}">
|
||||
this.html = html`<tr class="BufferAllCompletionOption option container_${container.color} container_${container.icon} container_${container.name} ${incognito
|
||||
? "incognito"
|
||||
: ""}"
|
||||
>
|
||||
<td class="prefix"></td>
|
||||
<td class="privatewindow"></td>
|
||||
<td class="container"></td>
|
||||
<td class="icon"><img src="${favIconUrl}"/></td>
|
||||
<td class="icon"><img src="${favIconUrl}" /></td>
|
||||
<td class="title">${this.value}: ${tab.title}</td>
|
||||
<td class="content"><a class="url" target="_blank" href=${
|
||||
tab.url
|
||||
}>${tab.url}</a></td>
|
||||
<td class="content">
|
||||
<a class="url" target="_blank" href=${tab.url}
|
||||
>${tab.url}</a
|
||||
>
|
||||
</td>
|
||||
</tr>`
|
||||
}
|
||||
}
|
||||
|
@ -50,7 +51,7 @@ export class TabAllCompletionSource extends Completions.CompletionSourceFuse {
|
|||
}
|
||||
|
||||
async onInput(exstr) {
|
||||
await this.updateOptions(exstr)
|
||||
return this.updateOptions(exstr)
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -112,7 +113,7 @@ export class TabAllCompletionSource extends Completions.CompletionSourceFuse {
|
|||
|
||||
this.completion = undefined
|
||||
this.options = options
|
||||
this.updateChain()
|
||||
return this.updateChain()
|
||||
}
|
||||
|
||||
setStateFromScore(scoredOpts: Completions.ScoredOption[]) {
|
||||
|
|
Loading…
Add table
Reference in a new issue