Impletment sessions completion

Sessions completion let us provide completions for the `:undo` ex
command, which can be useful if you need to restore an older tab.

Closes https://github.com/tridactyl/tridactyl/issues/1127.
This commit is contained in:
glacambre 2019-01-19 18:06:05 +01:00
parent e62eae4d15
commit a353c51354
No known key found for this signature in database
GPG key ID: B9625DB1767553AC
4 changed files with 106 additions and 1 deletions

View file

@ -30,6 +30,7 @@ import { HelpCompletionSource } from "@src/completions/Help"
import { HistoryCompletionSource } from "@src/completions/History" import { HistoryCompletionSource } from "@src/completions/History"
import { PreferenceCompletionSource } from "@src/completions/Preferences" import { PreferenceCompletionSource } from "@src/completions/Preferences"
import { RssCompletionSource } from "@src/completions/Rss" import { RssCompletionSource } from "@src/completions/Rss"
import { SessionsCompletionSource } from "@src/completions/Sessions"
import { SettingsCompletionSource } from "@src/completions/Settings" import { SettingsCompletionSource } from "@src/completions/Settings"
import * as Messaging from "@src/lib/messaging" import * as Messaging from "@src/lib/messaging"
import * as Config from "@src/lib/config" import * as Config from "@src/lib/config"
@ -101,8 +102,9 @@ export function enableCompletions() {
HelpCompletionSource, HelpCompletionSource,
HistoryCompletionSource, HistoryCompletionSource,
PreferenceCompletionSource, PreferenceCompletionSource,
SettingsCompletionSource,
RssCompletionSource, RssCompletionSource,
SessionsCompletionSource,
SettingsCompletionSource,
] ]
.map(constructorr => { .map(constructorr => {
try { try {

View file

@ -0,0 +1,85 @@
import { browserBg } from "@src/lib/webext.ts"
import * as Completions from "@src/completions"
function computeDate(session) {
let howLong = Math.round(
((new Date() as any) - session.lastModified) / 1000,
)
let qualifier = "s"
if (howLong > 60) {
qualifier = "m"
howLong = Math.round(howLong / 60)
if (howLong > 60) {
qualifier = "h"
howLong = Math.round(howLong / 60)
if (howLong > 24) {
qualifier = "d"
howLong = Math.round(howLong / 24)
}
}
}
return [howLong, qualifier]
}
function getTabInfo(session) {
let tab
let extraInfo
if (session.tab) {
tab = session.tab
extraInfo = tab.url
} else {
tab = session.window.tabs.sort(
(a, b) => b.lastAccessed - a.lastAccessed,
)[0]
const tabCount = session.window.tabs.length
if (tabCount < 2) {
extraInfo = tab.url
} else {
extraInfo = `${tabCount - 1} more tab${tabCount > 2 ? "s" : ""}.`
}
}
return [tab, extraInfo]
}
class SessionCompletionOption extends Completions.CompletionOptionHTML
implements Completions.CompletionOptionFuse {
public fuseKeys = []
constructor(public session) {
super()
this.value = (session.tab || session.window).sessionId
const [howLong, qualifier] = computeDate(session)
const [tab, extraInfo] = getTabInfo(session)
this.fuseKeys.push(tab.title)
this.html = html`<tr class="SessionCompletionOption option">
<td class="type">${session.tab ? "T" : "W"}</td>
<td class="time">${howLong}${qualifier}</td>
<td class="icon"><img src="${tab.favIconUrl ||
Completions.DEFAULT_FAVICON}"/></td>
<td class="title">${tab.title}</td>
<td class="extraInfo">${extraInfo}</td>
</tr>`
}
}
export class SessionsCompletionSource extends Completions.CompletionSourceFuse {
public options: SessionCompletionOption[]
private shouldSetStateFromScore = true
constructor(private _parent) {
super(["undo"], "SessionCompletionSource", "sessions")
this.updateOptions()
this._parent.appendChild(this.node)
}
private async updateOptions(exstr = "") {
const [prefix, query] = this.splitOnPrefix(exstr)
const sessions = await browserBg.sessions.getRecentlyClosed()
this.options = sessions.map(s => new SessionCompletionOption(s))
}
async onInput(exstr) {
return this.updateOptions(exstr)
}
}

View file

@ -2064,6 +2064,13 @@ export async function undo(item = "recent"): Promise<Number> {
return lastSession.window.id return lastSession.window.id
} }
} }
} else if (!isNaN(parseInt(item))) {
const sessionId = item
const session = sessions.find(s => (s.tab || s.window).sessionId == sessionId)
if (session) {
browser.sessions.restore(sessionId)
return (session.tab || session.window).id
}
} else { } else {
throw new Error(`[undo] Invalid argument: ${item}. Must be one of "tab", "window", "recent"`) throw new Error(`[undo] Invalid argument: ${item}. Must be one of "tab", "window", "recent"`)
} }

View file

@ -240,3 +240,14 @@ a.url:hover {
.HelpCompletionOption td.name { .HelpCompletionOption td.name {
max-width: 25%; max-width: 25%;
} }
#completions .SessionCompletionOption td.type {
width: 1ch !important;
padding: 0px 3pt;
}
#completions .SessionCompletionOption td.time {
width: 5ch !important;
padding: 0px 3pt;
text-align: right;
}