mirror of
https://github.com/vale981/tridactyl
synced 2025-03-05 09:31:41 -05:00
Merge pull request #4539 from rddunphy/feature/tab-groups
Tab group fixes
This commit is contained in:
commit
640dfb34bf
6 changed files with 240 additions and 59 deletions
|
@ -181,21 +181,25 @@ export class BufferCompletionSource extends Completions.CompletionSourceFuse {
|
||||||
private async fillOptions() {
|
private async fillOptions() {
|
||||||
let tabs: browser.tabs.Tab[]
|
let tabs: browser.tabs.Tab[]
|
||||||
|
|
||||||
|
// Get alternative tab, defined as last accessed tab in any group in
|
||||||
|
// this window.
|
||||||
|
const currentWindowTabs = await browserBg.tabs.query({
|
||||||
|
currentWindow: true,
|
||||||
|
})
|
||||||
|
currentWindowTabs.sort((a, b) => b.lastAccessed - a.lastAccessed)
|
||||||
|
const altTab = currentWindowTabs[1]
|
||||||
|
|
||||||
if (config.get("tabshowhidden") === "true") {
|
if (config.get("tabshowhidden") === "true") {
|
||||||
tabs = await browserBg.tabs.query({
|
tabs = currentWindowTabs
|
||||||
currentWindow: true
|
|
||||||
})
|
|
||||||
} else {
|
} else {
|
||||||
tabs = await browserBg.tabs.query({
|
tabs = await browserBg.tabs.query({
|
||||||
currentWindow: true,
|
currentWindow: true,
|
||||||
hidden: false
|
hidden: false,
|
||||||
})
|
})
|
||||||
|
tabs.sort((a, b) => b.lastAccessed - a.lastAccessed)
|
||||||
}
|
}
|
||||||
|
|
||||||
const options = []
|
const options = []
|
||||||
// Get alternative tab, defined as last accessed tab.
|
|
||||||
tabs.sort((a, b) => b.lastAccessed - a.lastAccessed)
|
|
||||||
const alt = tabs[1]
|
|
||||||
|
|
||||||
const useMruTabOrder = config.get("tabsort") === "mru"
|
const useMruTabOrder = config.get("tabsort") === "mru"
|
||||||
if (!useMruTabOrder) {
|
if (!useMruTabOrder) {
|
||||||
|
@ -221,7 +225,7 @@ export class BufferCompletionSource extends Completions.CompletionSourceFuse {
|
||||||
new BufferCompletionOption(
|
new BufferCompletionOption(
|
||||||
(tab.index + 1).toString(),
|
(tab.index + 1).toString(),
|
||||||
tab,
|
tab,
|
||||||
tab === alt,
|
tab.index === altTab.index,
|
||||||
tab_container,
|
tab_container,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
|
@ -4,6 +4,7 @@ import * as Containers from "@src/lib/containers"
|
||||||
import * as Completions from "@src/completions"
|
import * as Completions from "@src/completions"
|
||||||
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"
|
||||||
|
import { tabTgroup } from "@src/lib/tab_groups"
|
||||||
|
|
||||||
class TabAllCompletionOption
|
class TabAllCompletionOption
|
||||||
extends Completions.CompletionOptionHTML
|
extends Completions.CompletionOptionHTML
|
||||||
|
@ -13,15 +14,54 @@ class TabAllCompletionOption
|
||||||
constructor(
|
constructor(
|
||||||
public value: string,
|
public value: string,
|
||||||
tab: browser.tabs.Tab,
|
tab: browser.tabs.Tab,
|
||||||
|
isAlternative: boolean,
|
||||||
|
isCurrent: boolean,
|
||||||
winindex: number,
|
winindex: number,
|
||||||
container: browser.contextualIdentities.ContextualIdentity,
|
container: browser.contextualIdentities.ContextualIdentity,
|
||||||
incognito: boolean,
|
incognito: boolean,
|
||||||
|
tgroupname: string,
|
||||||
) {
|
) {
|
||||||
super()
|
super()
|
||||||
this.value = `${winindex}.${tab.index + 1}`
|
const valueStr = `${winindex}.${tab.index + 1}`
|
||||||
|
this.value = valueStr
|
||||||
this.fuseKeys.push(this.value, tab.title, tab.url)
|
this.fuseKeys.push(this.value, tab.title, tab.url)
|
||||||
this.tab = tab
|
this.tab = tab
|
||||||
|
|
||||||
|
// pre contains max four uppercase characters for tab status.
|
||||||
|
// If statusstylepretty is set to true replace use unicode characters,
|
||||||
|
// but keep plain letters in hidden column for completion.
|
||||||
|
let preplain = ""
|
||||||
|
if (isCurrent) {
|
||||||
|
preplain += "%"
|
||||||
|
} else if (isAlternative) {
|
||||||
|
preplain += "#"
|
||||||
|
this.value = "#"
|
||||||
|
}
|
||||||
|
let pre = preplain
|
||||||
|
if (tab.pinned) preplain += "P"
|
||||||
|
if (tab.audible) preplain += "A"
|
||||||
|
if (tab.mutedInfo.muted) preplain += "M"
|
||||||
|
if (tab.discarded) preplain += "D"
|
||||||
|
|
||||||
|
if (config.get("completions", "Tab", "statusstylepretty") === "true") {
|
||||||
|
if (tab.pinned) pre += "\uD83D\uDCCC"
|
||||||
|
if (tab.audible) pre += "\uD83D\uDD0A"
|
||||||
|
if (tab.mutedInfo.muted) pre += "\uD83D\uDD07"
|
||||||
|
if (tab.discarded) pre += "\u2296"
|
||||||
|
} else {
|
||||||
|
pre = preplain
|
||||||
|
}
|
||||||
|
|
||||||
|
tgroupname = tgroupname === undefined ? "" : tgroupname
|
||||||
|
|
||||||
|
// Push prefix before padding so we don't match on whitespace
|
||||||
|
this.fuseKeys.push(pre)
|
||||||
|
this.fuseKeys.push(preplain)
|
||||||
|
this.fuseKeys.push(tgroupname)
|
||||||
|
|
||||||
|
// Push properties we want to fuzmatch on
|
||||||
|
this.fuseKeys.push(String(tab.index + 1), tab.title, tab.url)
|
||||||
|
|
||||||
// Create HTMLElement
|
// Create HTMLElement
|
||||||
const favIconUrl = tab.favIconUrl
|
const favIconUrl = tab.favIconUrl
|
||||||
? tab.favIconUrl
|
? tab.favIconUrl
|
||||||
|
@ -31,14 +71,16 @@ class TabAllCompletionOption
|
||||||
? "incognito"
|
? "incognito"
|
||||||
: ""}"
|
: ""}"
|
||||||
>
|
>
|
||||||
<td class="prefix"></td>
|
<td class="prefix">${pre}</td>
|
||||||
|
<td class="prefixplain" hidden>${preplain}</td>
|
||||||
<td class="privatewindow"></td>
|
<td class="privatewindow"></td>
|
||||||
<td class="container"></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="title">${valueStr}: ${tab.title}</td>
|
||||||
<td class="content">
|
<td class="content">
|
||||||
<a class="url" target="_blank" href=${tab.url}>${tab.url}</a>
|
<a class="url" target="_blank" href=${tab.url}>${tab.url}</a>
|
||||||
</td>
|
</td>
|
||||||
|
<td class="tgroup">${tgroupname}</td>
|
||||||
</tr>`
|
</tr>`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -147,6 +189,12 @@ export class TabAllCompletionSource extends Completions.CompletionSourceFuse {
|
||||||
return a.windowId - b.windowId
|
return a.windowId - b.windowId
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const currentWindowTabs = await browserBg.tabs.query({
|
||||||
|
currentWindow: true,
|
||||||
|
})
|
||||||
|
currentWindowTabs.sort((a, b) => b.lastAccessed - a.lastAccessed)
|
||||||
|
const altTab = currentWindowTabs[1]
|
||||||
|
|
||||||
// Check to see if this is a command that needs to exclude the current
|
// Check to see if this is a command that needs to exclude the current
|
||||||
// window
|
// window
|
||||||
const excludeCurrentWindow = ["tabgrab"].includes(prefix.trim())
|
const excludeCurrentWindow = ["tabgrab"].includes(prefix.trim())
|
||||||
|
@ -162,14 +210,20 @@ export class TabAllCompletionSource extends Completions.CompletionSourceFuse {
|
||||||
}
|
}
|
||||||
// if we are excluding the current window and this tab is in the current window
|
// if we are excluding the current window and this tab is in the current window
|
||||||
// then skip it
|
// then skip it
|
||||||
if (excludeCurrentWindow && tab.windowId === currentWindow.id) continue
|
if (excludeCurrentWindow && tab.windowId === currentWindow.id)
|
||||||
|
continue
|
||||||
options.push(
|
options.push(
|
||||||
new TabAllCompletionOption(
|
new TabAllCompletionOption(
|
||||||
tab.id.toString(),
|
tab.id.toString(),
|
||||||
tab,
|
tab,
|
||||||
|
tab.index === altTab.index &&
|
||||||
|
tab.windowId === altTab.windowId,
|
||||||
|
tab.active &&
|
||||||
|
tab.windowId === currentWindowTabs[0].windowId,
|
||||||
winindex,
|
winindex,
|
||||||
await Containers.getFromId(tab.cookieStoreId),
|
await Containers.getFromId(tab.cookieStoreId),
|
||||||
windows[tab.windowId].incognito,
|
windows[tab.windowId].incognito,
|
||||||
|
await tabTgroup(tab.id),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,20 +1,64 @@
|
||||||
import * as Completions from "@src/completions"
|
import * as Completions from "@src/completions"
|
||||||
import { tgroups, windowTgroup, tgroupTabs } from "@src/lib/tab_groups"
|
import * as config from "@src/lib/config"
|
||||||
|
import {
|
||||||
|
tgroups,
|
||||||
|
windowTgroup,
|
||||||
|
windowLastTgroup,
|
||||||
|
tgroupTabs,
|
||||||
|
} from "@src/lib/tab_groups"
|
||||||
|
|
||||||
class TabGroupCompletionOption extends Completions.CompletionOptionHTML
|
class TabGroupCompletionOption
|
||||||
|
extends Completions.CompletionOptionHTML
|
||||||
implements Completions.CompletionOptionFuse {
|
implements Completions.CompletionOptionFuse {
|
||||||
public fuseKeys = []
|
public fuseKeys = []
|
||||||
|
|
||||||
constructor(group: string, tabCount: number) {
|
constructor(
|
||||||
|
group: string,
|
||||||
|
tabCount: number,
|
||||||
|
current: boolean,
|
||||||
|
alternate: boolean,
|
||||||
|
audible: boolean,
|
||||||
|
urls: string[],
|
||||||
|
) {
|
||||||
super()
|
super()
|
||||||
this.value = group
|
this.value = group
|
||||||
|
let preplain = ""
|
||||||
|
if (current) {
|
||||||
|
preplain += "%"
|
||||||
|
}
|
||||||
|
if (alternate) {
|
||||||
|
preplain += "#"
|
||||||
|
}
|
||||||
|
let pre = preplain
|
||||||
|
if (audible) {
|
||||||
|
preplain += "A"
|
||||||
|
}
|
||||||
|
if (config.get("completions", "Tab", "statusstylepretty") === "true") {
|
||||||
|
if (audible) {
|
||||||
|
pre += "\uD83D\uDD0A"
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
pre = preplain
|
||||||
|
}
|
||||||
|
|
||||||
this.fuseKeys.push(group)
|
this.fuseKeys.push(group)
|
||||||
|
this.fuseKeys.push(pre)
|
||||||
|
this.fuseKeys.push(preplain)
|
||||||
|
this.fuseKeys.push(urls)
|
||||||
|
|
||||||
this.html = html`<tr class="TabGroupCompletionOption option">
|
this.html = html`<tr class="TabGroupCompletionOption option">
|
||||||
|
<td class="prefix">${pre}</td>
|
||||||
|
<td class="prefixplain" hidden>${preplain}</td>
|
||||||
<td class="title">${group}</td>
|
<td class="title">${group}</td>
|
||||||
<td class="tabcount">${tabCount} tab${
|
<td class="tabcount">
|
||||||
tabCount !== 1 ? "s" : ""
|
${tabCount} tab${tabCount !== 1 ? "s" : ""}
|
||||||
}</td>
|
</td>
|
||||||
|
<td class="content"></td>
|
||||||
</tr>`
|
</tr>`
|
||||||
|
const urlMarkup = urls.map(
|
||||||
|
u => `<a class="url" target="_blank" href="${u}">${u}</a>`,
|
||||||
|
)
|
||||||
|
this.html.lastElementChild.innerHTML = urlMarkup.join(",")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -23,7 +67,7 @@ export class TabGroupCompletionSource extends Completions.CompletionSourceFuse {
|
||||||
|
|
||||||
constructor(private _parent: any) {
|
constructor(private _parent: any) {
|
||||||
super(
|
super(
|
||||||
["tgroupswitch", "tgroupmove"],
|
["tgroupswitch", "tgroupmove", "tgroupclose"],
|
||||||
"TabGroupCompletionSource",
|
"TabGroupCompletionSource",
|
||||||
"Tab Groups",
|
"Tab Groups",
|
||||||
)
|
)
|
||||||
|
@ -32,7 +76,11 @@ export class TabGroupCompletionSource extends Completions.CompletionSourceFuse {
|
||||||
this._parent.appendChild(this.node)
|
this._parent.appendChild(this.node)
|
||||||
}
|
}
|
||||||
|
|
||||||
async filter(exstr: string) {
|
async onInput(exstr) {
|
||||||
|
return this.updateOptions(exstr)
|
||||||
|
}
|
||||||
|
|
||||||
|
private async updateOptions(exstr = "") {
|
||||||
this.lastExstr = exstr
|
this.lastExstr = exstr
|
||||||
const [prefix] = this.splitOnPrefix(exstr)
|
const [prefix] = this.splitOnPrefix(exstr)
|
||||||
|
|
||||||
|
@ -47,22 +95,28 @@ export class TabGroupCompletionSource extends Completions.CompletionSourceFuse {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.updateDisplay()
|
|
||||||
}
|
|
||||||
|
|
||||||
private async updateOptions() {
|
|
||||||
const currentGroup = await windowTgroup()
|
const currentGroup = await windowTgroup()
|
||||||
const otherGroups = [...(await tgroups())].filter(
|
const alternateGroup = await windowLastTgroup()
|
||||||
group => group !== currentGroup,
|
const groups = [...(await tgroups())]
|
||||||
)
|
|
||||||
this.options = await Promise.all(
|
this.options = await Promise.all(
|
||||||
otherGroups.map(async group => {
|
groups.map(async group => {
|
||||||
const tabCount = (await tgroupTabs(group)).length
|
const tabs = await tgroupTabs(group)
|
||||||
const o = new TabGroupCompletionOption(group, tabCount)
|
const audible = tabs.some(t => t.audible)
|
||||||
|
tabs.sort((a, b) => b.lastAccessed - a.lastAccessed)
|
||||||
|
const urls = tabs.map(t => t.url)
|
||||||
|
const o = new TabGroupCompletionOption(
|
||||||
|
group,
|
||||||
|
tabs.length,
|
||||||
|
group === currentGroup,
|
||||||
|
group === alternateGroup,
|
||||||
|
audible,
|
||||||
|
urls,
|
||||||
|
)
|
||||||
o.state = "normal"
|
o.state = "normal"
|
||||||
return o
|
return o
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
return this.updateDisplay()
|
this.completion = undefined
|
||||||
|
return this.updateChain()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -170,7 +170,7 @@ import * as Updates from "@src/lib/updates"
|
||||||
import * as Extensions from "@src/lib/extension_info"
|
import * as Extensions from "@src/lib/extension_info"
|
||||||
import * as webrequests from "@src/background/webrequests"
|
import * as webrequests from "@src/background/webrequests"
|
||||||
import * as commandsHelper from "@src/background/commands"
|
import * as commandsHelper from "@src/background/commands"
|
||||||
import { tgroups, tgroupActivate, setTabTgroup, setWindowTgroup, setTgroups, windowTgroup, tgroupClearOldInfo, tgroupLastTabId, tgroupTabs, clearAllTgroupInfo, tgroupActivateLast, tgroupHandleTabActivated, tgroupHandleTabCreated, tgroupHandleTabAttached, tgroupHandleTabUpdated, tgroupHandleTabRemoved, tgroupHandleTabDetached } from "./lib/tab_groups"
|
import { tgroups, tgroupActivate, setTabTgroup, setWindowTgroup, setTgroups, windowTgroup, windowLastTgroup, tgroupClearOldInfo, tgroupLastTabId, tgroupTabs, clearAllTgroupInfo, tgroupActivateLast, tgroupHandleTabActivated, tgroupHandleTabCreated, tgroupHandleTabAttached, tgroupHandleTabUpdated, tgroupHandleTabRemoved, tgroupHandleTabDetached } from "./lib/tab_groups"
|
||||||
|
|
||||||
ALL_EXCMDS = {
|
ALL_EXCMDS = {
|
||||||
"": BGSELF,
|
"": BGSELF,
|
||||||
|
@ -3457,7 +3457,7 @@ export async function tgroupcreate(name: string) {
|
||||||
const promises = []
|
const promises = []
|
||||||
const groups = await tgroups()
|
const groups = await tgroups()
|
||||||
|
|
||||||
if (groups.has(name)) {
|
if (groups.has(name) || name === "#") {
|
||||||
throw new Error(`Tab group "${name}" already exists`)
|
throw new Error(`Tab group "${name}" already exists`)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3468,7 +3468,7 @@ export async function tgroupcreate(name: string) {
|
||||||
promises.push(tgroupTabs(name, true).then(tabs => browserBg.tabs.hide(tabs.map(tab => tab.id))))
|
promises.push(tgroupTabs(name, true).then(tabs => browserBg.tabs.hide(tabs.map(tab => tab.id))))
|
||||||
} else {
|
} else {
|
||||||
promises.push(
|
promises.push(
|
||||||
browser.tabs.query({ currentWindow: true }).then(tabs => {
|
browser.tabs.query({ currentWindow: true, pinned: false }).then(tabs => {
|
||||||
setTabTgroup(
|
setTabTgroup(
|
||||||
name,
|
name,
|
||||||
tabs.map(({ id }) => id),
|
tabs.map(({ id }) => id),
|
||||||
|
@ -3488,15 +3488,23 @@ export async function tgroupcreate(name: string) {
|
||||||
/**
|
/**
|
||||||
* Switch to a different tab group, hiding all other tabs.
|
* Switch to a different tab group, hiding all other tabs.
|
||||||
*
|
*
|
||||||
|
* "%" denotes the current tab group and "#" denotes the tab group that was
|
||||||
|
* last active. "A" indates a tab group that contains an audible tab. Use
|
||||||
|
* `:set completions.Tab.statusstylepretty true` to display a unicode character
|
||||||
|
* instead.
|
||||||
|
*
|
||||||
* @param name The name of the tab group to switch to.
|
* @param name The name of the tab group to switch to.
|
||||||
*
|
*
|
||||||
* If the tab group does not exist, act like tgroupcreate.
|
* If the tab group does not exist, act like [[tgroupcreate]].
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
//#background
|
//#background
|
||||||
export async function tgroupswitch(name: string) {
|
export async function tgroupswitch(name: string) {
|
||||||
|
if (name === "#") {
|
||||||
|
return tgrouplast().then(() => name)
|
||||||
|
}
|
||||||
if (name == (await windowTgroup())) {
|
if (name == (await windowTgroup())) {
|
||||||
throw new Error(`Already on tab group "${name}"`)
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
const groups = await tgroups()
|
const groups = await tgroups()
|
||||||
|
@ -3543,22 +3551,39 @@ export async function tgrouprename(name: string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Close the current tab group.
|
* Close all tabs in a tab group and delete the group.
|
||||||
*
|
*
|
||||||
* First switch to the previously active tab group. Do nothing if there is only
|
* @param name The name of the tab group to close. If not specified, close the
|
||||||
* one tab group.
|
* current tab group and switch to the previously active tab group.
|
||||||
|
*
|
||||||
|
* Do nothing if there is only one tab group - to discard all tab group
|
||||||
|
* information, use [[tgroupabort]].
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
//#background
|
//#background
|
||||||
export async function tgroupclose() {
|
export async function tgroupclose(name?: string) {
|
||||||
const groups = await tgroups()
|
const groups = await tgroups()
|
||||||
if (groups.size == 0) {
|
if (groups.size == 0) {
|
||||||
throw new Error("No tab groups exist")
|
throw new Error("No tab groups exist")
|
||||||
} else if (groups.size == 1) {
|
} else if (groups.size == 1) {
|
||||||
throw new Error("This is the only tab group")
|
throw new Error("This is the only tab group")
|
||||||
|
} else if (name !== undefined && name !== "#" && !groups.has(name)) {
|
||||||
|
throw new Error(`No tab group named "${name}"`)
|
||||||
} else if (groups.size > 1) {
|
} else if (groups.size > 1) {
|
||||||
const closeGroup = await windowTgroup()
|
const currentGroup = await windowTgroup()
|
||||||
const newTabGroup = await tgroupActivateLast()
|
let closeGroup = currentGroup
|
||||||
|
if (name === "#") {
|
||||||
|
closeGroup = await windowLastTgroup()
|
||||||
|
if (name === undefined) {
|
||||||
|
throw new Error("No alternate tab group")
|
||||||
|
}
|
||||||
|
} else if (name !== undefined) {
|
||||||
|
closeGroup = name
|
||||||
|
}
|
||||||
|
let newTabGroup = currentGroup
|
||||||
|
if (closeGroup === currentGroup) {
|
||||||
|
newTabGroup = await tgroupActivateLast()
|
||||||
|
}
|
||||||
await tgroupTabs(closeGroup).then(tabs => {
|
await tgroupTabs(closeGroup).then(tabs => {
|
||||||
browser.tabs.remove(tabs.map(tab => tab.id))
|
browser.tabs.remove(tabs.map(tab => tab.id))
|
||||||
})
|
})
|
||||||
|
@ -3567,7 +3592,7 @@ export async function tgroupclose() {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Move the current tab to another tab group.
|
* Move the current tab to another tab group, creating it if it does not exist.
|
||||||
*
|
*
|
||||||
* @param name The name of the tab group to move the tab to.
|
* @param name The name of the tab group to move the tab to.
|
||||||
*
|
*
|
||||||
|
@ -3583,16 +3608,25 @@ export async function tgroupmove(name: string) {
|
||||||
if (groups.size == 0) {
|
if (groups.size == 0) {
|
||||||
throw new Error("No tab groups exist")
|
throw new Error("No tab groups exist")
|
||||||
}
|
}
|
||||||
if (!groups.has(name)) {
|
|
||||||
throw new Error(`Tab group "${name}" does not exist`)
|
|
||||||
}
|
|
||||||
if (name == currentGroup) {
|
if (name == currentGroup) {
|
||||||
throw new Error(`Tab is already on group "${name}"`)
|
throw new Error(`Tab is already on group "${name}"`)
|
||||||
}
|
}
|
||||||
|
if (name === "#") {
|
||||||
|
name = await windowLastTgroup()
|
||||||
|
if (name === undefined) {
|
||||||
|
throw new Error("No alternate tab group")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!groups.has(name)) {
|
||||||
|
// Create new tab group if there isn't one with this name
|
||||||
|
groups.add(name)
|
||||||
|
await setTgroups(groups)
|
||||||
|
}
|
||||||
|
|
||||||
const tabCount = await tgroupTabs(currentGroup).then(tabs => tabs.length)
|
const tabCount = await tgroupTabs(currentGroup).then(tabs => tabs.length)
|
||||||
|
|
||||||
await setTabTgroup(name)
|
await setTabTgroup(name)
|
||||||
|
setContentStateGroup(name)
|
||||||
const currentTabId = await activeTabId()
|
const currentTabId = await activeTabId()
|
||||||
|
|
||||||
// switch to other group if this is the last tab in the current group
|
// switch to other group if this is the last tab in the current group
|
||||||
|
@ -4054,7 +4088,7 @@ export async function yankimage(url: string): Promise<void> {
|
||||||
|
|
||||||
A string following the following format: "[0-9]+.[0-9]+" means the first number being the index of the window that should be selected and the second one being the index of the tab within that window. [[taball]] has completions for this format.
|
A string following the following format: "[0-9]+.[0-9]+" means the first number being the index of the window that should be selected and the second one being the index of the tab within that window. [[taball]] has completions for this format.
|
||||||
|
|
||||||
"%" denotes the current tab and "#" denotes the tab that was last accessed in this window. "P", "A", "M" and "D" indicate tab status (i.e. a pinned, audible, muted or discarded tab. Use `:set completions.Tab.statusstylepretty true` to display unicode characters instead. "P","A","M","D" can be used to filter by tab status in either setting.
|
"%" denotes the current tab and "#" denotes the tab that was last accessed in this window. "P", "A", "M" and "D" indicate tab status (i.e. a pinned, audible, muted or discarded tab). Use `:set completions.Tab.statusstylepretty true` to display unicode characters instead. "P","A","M","D" can be used to filter by tab status in either setting.
|
||||||
|
|
||||||
A non integer string means to search the URL and title for matches, in this window if called from tab, all windows if called from taball. Title matches can contain '*' as a wildcard.
|
A non integer string means to search the URL and title for matches, in this window if called from tab, all windows if called from taball. Title matches can contain '*' as a wildcard.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -49,10 +49,10 @@ export async function windowTgroup(id?: number) {
|
||||||
if (id === undefined) {
|
if (id === undefined) {
|
||||||
id = await activeWindowId()
|
id = await activeWindowId()
|
||||||
}
|
}
|
||||||
return (browserBg.sessions.getWindowValue(
|
return browserBg.sessions.getWindowValue(
|
||||||
id,
|
id,
|
||||||
"tridactyl-active-tgroup",
|
"tridactyl-active-tgroup",
|
||||||
) as unknown) as string
|
) as unknown as string
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -73,6 +73,22 @@ export async function setWindowTgroup(name: string, id?: number) {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Return the last active tab group for a window or undefined.
|
||||||
|
*
|
||||||
|
* @param id The id of the window. Use the current window if not specified.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
export async function windowLastTgroup(id?: number) {
|
||||||
|
const otherGroupsTabs = await tgroupTabs(await windowTgroup(id), true)
|
||||||
|
if (otherGroupsTabs.length === 0) {
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
|
otherGroupsTabs.sort((a, b) => b.lastAccessed - a.lastAccessed)
|
||||||
|
const lastTabId = otherGroupsTabs[0].id
|
||||||
|
return tabTgroup(lastTabId)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Clear the active tab group for the current window.
|
* Clear the active tab group for the current window.
|
||||||
*
|
*
|
||||||
|
@ -91,10 +107,10 @@ export async function tabTgroup(id?: number) {
|
||||||
if (id === undefined) {
|
if (id === undefined) {
|
||||||
id = await activeTabId()
|
id = await activeTabId()
|
||||||
}
|
}
|
||||||
return (browserBg.sessions.getTabValue(
|
return browserBg.sessions.getTabValue(
|
||||||
id,
|
id,
|
||||||
"tridactyl-tgroup",
|
"tridactyl-tgroup",
|
||||||
) as unknown) as string
|
) as unknown as string
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -252,12 +268,8 @@ export async function tgroupActivate(name: string) {
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
export async function tgroupActivateLast() {
|
export async function tgroupActivateLast() {
|
||||||
const otherGroupsTabs = await tgroupTabs(await windowTgroup(), true)
|
const lastTabGroup = await windowLastTgroup()
|
||||||
otherGroupsTabs.sort((a, b) => b.lastAccessed - a.lastAccessed)
|
return tgroupActivate(lastTabGroup).then(() => lastTabGroup)
|
||||||
const lastTabId = otherGroupsTabs[0].id
|
|
||||||
return browserBg.tabs
|
|
||||||
.update(lastTabId, { active: true })
|
|
||||||
.then(() => tabTgroup(lastTabId))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -325,10 +337,14 @@ export async function tgroupHandleTabActivated(activeInfo) {
|
||||||
await setWindowTgroup(tabGroup, activeInfo.windowId)
|
await setWindowTgroup(tabGroup, activeInfo.windowId)
|
||||||
|
|
||||||
promises.push(
|
promises.push(
|
||||||
tgroupTabs(tabGroup, false, activeInfo.windowId).then(tabs => browserBg.tabs.show(tabs.map(tab => tab.id))),
|
tgroupTabs(tabGroup, false, activeInfo.windowId).then(tabs =>
|
||||||
|
browserBg.tabs.show(tabs.map(tab => tab.id)),
|
||||||
|
),
|
||||||
)
|
)
|
||||||
promises.push(
|
promises.push(
|
||||||
tgroupTabs(tabGroup, true, activeInfo.windowId).then(tabs => browserBg.tabs.hide(tabs.map(tab => tab.id))),
|
tgroupTabs(tabGroup, true, activeInfo.windowId).then(tabs =>
|
||||||
|
browserBg.tabs.hide(tabs.map(tab => tab.id)),
|
||||||
|
),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
return Promise.all(promises)
|
return Promise.all(promises)
|
||||||
|
|
|
@ -79,6 +79,17 @@ input:focus {
|
||||||
#completions table tr td.privatewindow {
|
#completions table tr td.privatewindow {
|
||||||
width: 1.5em;
|
width: 1.5em;
|
||||||
}
|
}
|
||||||
|
#completions table tr td.tabcount {
|
||||||
|
width: 6em;
|
||||||
|
}
|
||||||
|
#completions table tr td.tgroup {
|
||||||
|
width: 10em;
|
||||||
|
padding-left: 0.5em;
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
#completions table tr td.tgroup:empty {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
/* #completions table tr td:nth-of-type(3) { width: 5em; } */
|
/* #completions table tr td:nth-of-type(3) { width: 5em; } */
|
||||||
#completions table tr td.content {
|
#completions table tr td.content {
|
||||||
width: 50%;
|
width: 50%;
|
||||||
|
@ -259,6 +270,14 @@ a.url:hover {
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#completions .TabGroupCompletionOption td.title {
|
||||||
|
width: 15%;
|
||||||
|
}
|
||||||
|
|
||||||
|
#completions .TabGroupCompletionOption td.content {
|
||||||
|
width: auto;
|
||||||
|
}
|
||||||
|
|
||||||
.HelpCompletionOption td.name {
|
.HelpCompletionOption td.name {
|
||||||
width: 25%;
|
width: 25%;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue