Merge pull request #4595 from treapster/mru-tabs

Respect MRU order in tab completions and :tab command
This commit is contained in:
Oliver Blanthorn 2023-02-18 13:10:38 +00:00 committed by GitHub
commit f2d3e1b66b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 41 additions and 59 deletions

View file

@ -1,5 +1,5 @@
import * as Perf from "@src/perf"
import { browserBg } from "@src/lib/webext"
import { browserBg, getSortedTabs, prevActiveTab } from "@src/lib/webext"
import { enumerate } from "@src/lib/itertools"
import * as Containers from "@src/lib/containers"
import * as Completions from "@src/completions"
@ -10,7 +10,6 @@ class BufferCompletionOption
extends Completions.CompletionOptionHTML
implements Completions.CompletionOptionFuse {
public fuseKeys = []
public tabIndex: number
public tabId: number
constructor(
@ -18,9 +17,10 @@ class BufferCompletionOption
tab: browser.tabs.Tab,
public isAlternative = false,
container: browser.contextualIdentities.ContextualIdentity,
public tabIndex: number,
) {
super()
this.tabIndex = tab.index
this.tabId = tab.id
// pre contains max four uppercase characters for tab status.
@ -66,7 +66,9 @@ class BufferCompletionOption
<td class="prefixplain" hidden>${preplain}</td>
<td class="container"></td>
<td class="icon"><img loading="lazy" src="${favIconUrl}" /></td>
<td class="title">${tab.index + 1}: ${indicator} ${tab.title}</td>
<td class="title">
${this.tabIndex + 1}: ${indicator} ${tab.title}
</td>
<td class="content">
<a class="url" target="_blank" href=${tab.url}>${tab.url}</a>
</td>
@ -179,35 +181,14 @@ export class BufferCompletionSource extends Completions.CompletionSourceFuse {
}
private async fillOptions() {
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") {
tabs = currentWindowTabs
} else {
tabs = await browserBg.tabs.query({
currentWindow: true,
hidden: false,
})
tabs.sort((a, b) => b.lastAccessed - a.lastAccessed)
}
const altTab = await prevActiveTab()
const tabs = await getSortedTabs()
const options = []
const useMruTabOrder = config.get("tabsort") === "mru"
if (!useMruTabOrder) {
tabs.sort((a, b) => a.index - b.index)
} else {
tabs.push(tabs.shift()) // If using MRU, move the current tab to the bottom (issue #4168)
}
const container_all = await browserBg.contextualIdentities.query({})
const container_map = new Map()
container_all.forEach(elem =>
@ -215,18 +196,18 @@ export class BufferCompletionSource extends Completions.CompletionSourceFuse {
)
// firefox-default is not in contextualIdenetities
container_map.set("firefox-default", Containers.DefaultContainer)
for (const tab of tabs) {
for (const [index, tab] of tabs.entries()) {
let tab_container = container_map.get(tab.cookieStoreId)
if (!tab_container) {
tab_container = Containers.DefaultContainer
}
options.push(
new BufferCompletionOption(
(tab.index + 1).toString(),
(index + 1).toString(),
tab,
tab.index === altTab.index,
tab_container,
index,
),
)
}

View file

@ -74,7 +74,7 @@
// Shared
import * as Messaging from "@src/lib/messaging"
import { ownWinTriIndex, getTriVersion, browserBg, activeTab, activeTabId, activeTabContainerId, openInNewTab, openInNewWindow, openInTab, queryAndURLwrangler, goToTab } from "@src/lib/webext"
import { ownWinTriIndex, getTriVersion, browserBg, activeTab, activeTabId, activeTabContainerId, openInNewTab, openInNewWindow, openInTab, queryAndURLwrangler, goToTab, getSortedTabs, prevActiveTab } from "@src/lib/webext"
import * as Container from "@src/lib/containers"
import state from "@src/state"
import * as State from "@src/state"
@ -2884,26 +2884,13 @@ async function idFromIndex(index?: number | "%" | "#" | string): Promise<number>
async function tabFromIndex(index?: number | "%" | "#" | string): Promise<browser.tabs.Tab> {
if (index === "#") {
// Support magic previous/current tab syntax everywhere
const tabs = await getSortedWinTabs()
if (tabs.length < 2) {
// In vim, '#' is the id of the previous buffer even if said buffer has been wiped
// However, firefox doesn't store tab ids for closed tabs
// Since vim makes '#' default to the current buffer if only one buffer has ever been opened for the current session, it seems reasonable to return the id of the current tab if only one tab is opened in firefox
return activeTab()
}
return tabs[1]
return prevActiveTab()
} else if (index !== undefined && index !== "%") {
// Wrap
const tabs = await getSortedTabs()
index = Number(index)
index = (index - 1).mod((await browser.tabs.query({ currentWindow: true })).length) + 1
index = (index - 1).mod(tabs.length) + 1
// Return id of tab with that index.
return (
await browser.tabs.query({
currentWindow: true,
index: index - 1,
})
)[0]
return tabs[index - 1]
} else {
return activeTab()
}
@ -2941,17 +2928,6 @@ export async function tabdetach(index?: number) {
return browser.windows.create({ tabId: await idFromIndex(index) })
}
/** Get list of tabs sorted by most recent use
@hidden
*/
//#background_helper
async function getSortedWinTabs(): Promise<browser.tabs.Tab[]> {
const tabs = await browser.tabs.query({ currentWindow: true })
tabs.sort((a, b) => (a.lastAccessed < b.lastAccessed ? 1 : -1))
return tabs
}
/** Toggle fullscreen state
*/

View file

@ -5,6 +5,20 @@ import * as UrlUtil from "@src/lib/url_util"
import { sleep } from "@src/lib/patience"
import * as R from "ramda"
export async function getSortedTabs(): Promise<browser.tabs.Tab[]> {
const comp =
config.get("tabsort") === "mru"
? (a, b) => +a.active || -b.active || b.lastAccessed - a.lastAccessed
: (a, b) => a.index - b.index
const hiddenVal = config.get("tabshowhidden") === "true" ? undefined : false
return browserBg.tabs
.query({
currentWindow: true,
hidden: hiddenVal,
})
.then(tabs => tabs.sort(comp))
}
export function inContentScript() {
return getContext() === "content"
}
@ -70,6 +84,17 @@ export async function activeTabId() {
return (await activeTab()).id
}
export async function prevActiveTab() {
const tabs = (
await browserBg.tabs.query({
currentWindow: true,
})
).sort((a, b) => b.lastAccessed - a.lastAccessed)
if (tabs.length > 1) return tabs[1]
return tabs[0]
}
/**
* Return the active window's id.
*