Skip to content

feat: Add keybind for tabs-search #8272

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 26 commits into
base: dev
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
b801685
Attempt to add keybind for tabs-search
rstanuwijaya May 13, 2025
d0c8a86
Replace focus search (alt) with tabs search
rstanuwijaya May 14, 2025
baea2b5
Update keybind to Alt+Q
rstanuwijaya May 14, 2025
59e1d14
Select the first element after envoking keybind
rstanuwijaya May 15, 2025
7a99f0f
Fix selecting unloaded tabs will no longer open new tab
rstanuwijaya May 15, 2025
30541aa
Sort the tabs suggestion by last time tab being opened
rstanuwijaya May 15, 2025
540da7d
Fix schema for url
rstanuwijaya May 15, 2025
cc12958
Enable reverse search as well
rstanuwijaya May 16, 2025
4927e12
Fix typo
rstanuwijaya May 16, 2025
564d2b2
Fix tab search selection logic
rstanuwijaya May 16, 2025
d393385
Update heuristic logic for tab search
rstanuwijaya May 16, 2025
dfec30e
Merge branch 'tabs-search' into dev
rstanuwijaya May 17, 2025
93e72bc
Merge branch 'dev' into tabs-search
rstanuwijaya May 17, 2025
f0672cd
Merge branch 'dev' into tabs-search
rstanuwijaya May 22, 2025
b6b8a79
fix: Update diff into full-index
rstanuwijaya May 22, 2025
0b11190
fix: Changed diff into full-index
rstanuwijaya May 22, 2025
796adb6
Add ZenTabSearch
rstanuwijaya May 22, 2025
bfeb730
style: Format code
rstanuwijaya May 22, 2025
555d847
fix: Change tab result to heuristic
rstanuwijaya May 22, 2025
d4c0571
fix: Change heuristic provider name
rstanuwijaya May 22, 2025
036aab6
feat: Add auto select tab prefs
rstanuwijaya May 22, 2025
628a47f
fix: Try change logic of tab search
rstanuwijaya May 22, 2025
5d3e6d2
feat: Add new prefs to enable tab search
rstanuwijaya May 22, 2025
5874711
fix: Changed logic for tab search
rstanuwijaya May 22, 2025
4e83084
fix: Changed the order of the shortcuts in settings
rstanuwijaya May 22, 2025
9b34394
fix: Avoid error when pref is not enabled
rstanuwijaya May 22, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions src/browser/app/profile/features.inc
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,9 @@ pref('zen.glance.hold-duration', 300); // in ms
pref('zen.glance.open-essential-external-links', true);
pref('zen.glance.activation-method', 'alt'); // ctrl, alt, shift, none, hold

pref('zen.tabsearch.enabled', true);
pref('zen.tabsearch.auto-select-result', false);

pref('zen.view.sidebar-height-throttle', 200); // in ms
pref('zen.view.sidebar-expanded.max-width', 500);

Expand Down
1 change: 1 addition & 0 deletions src/browser/base/content/zen-assets.inc.xhtml
Original file line number Diff line number Diff line change
Expand Up @@ -44,4 +44,5 @@ Services.scriptloader.loadSubScript("chrome://browser/content/zen-components/Zen
Services.scriptloader.loadSubScript("chrome://browser/content/zen-components/ZenGlanceManager.mjs", this);
Services.scriptloader.loadSubScript("chrome://browser/content/zen-components/ZenMediaController.mjs", this);
Services.scriptloader.loadSubScript("chrome://browser/content/zen-components/ZenDownloadAnimation.mjs", this);
Services.scriptloader.loadSubScript("chrome://browser/content/zen-components/ZenTabSearch.mjs", this);
</script>
2 changes: 2 additions & 0 deletions src/browser/base/content/zen-assets.jar.inc.mn
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@
content/browser/zen-components/actors/ZenGlanceChild.sys.mjs (../../zen/glance/actors/ZenGlanceChild.sys.mjs)
content/browser/zen-components/actors/ZenGlanceParent.sys.mjs (../../zen/glance/actors/ZenGlanceParent.sys.mjs)

content/browser/zen-components/ZenTabSearch.mjs (../../zen/tabsearch/ZenTabSearch.mjs)

content/browser/zen-components/ZenFolders.mjs (../../zen/folders/ZenFolders.mjs)
content/browser/zen-styles/zen-folders.css (../../zen/folders/zen-folders.css)

Expand Down
4 changes: 4 additions & 0 deletions src/browser/base/content/zen-keysets.inc.xhtml
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,10 @@
<command id="cmd_zenUnloadTab" />
<command id="cmd_zenPreventUnloadTab" />
<command id="cmd_zenIgnoreUnloadTab" />

<!-- Tab search commands -->
<command id="cmd_zenSearchTabs" />
<command id="cmd_zenBackwardSearchTabs" />
</commandset>

<keyset id="zenKeyset"></keyset>
11 changes: 11 additions & 0 deletions src/browser/components/preferences/zen-settings.js
Original file line number Diff line number Diff line change
Expand Up @@ -777,6 +777,7 @@ var gZenWorkspacesSettings = {
};
Services.prefs.addObserver('zen.tab-unloader.enabled', tabsUnloaderPrefListener);
Services.prefs.addObserver('zen.glance.enabled', tabsUnloaderPrefListener); // We can use the same listener for both prefs
Services.prefs.addObserver('zen.tabsearch.enabled', tabsUnloaderPrefListener); // We can use the same listener for both prefs
Services.prefs.addObserver(
'zen.workspaces.container-specific-essentials-enabled',
tabsUnloaderPrefListener
Expand Down Expand Up @@ -1169,6 +1170,16 @@ Preferences.addAll([
type: 'bool',
default: true,
},
{
id: 'zen.tabsearch.enabled',
type: 'bool',
default: true,
},
{
id: 'zen.tabsearch.auto-select-result',
type: 'bool',
default: false,
},
{
id: 'zen.theme.color-prefs.use-workspace-colors',
type: 'bool',
Expand Down
65 changes: 45 additions & 20 deletions src/browser/components/tabbrowser/content/tabbrowser-js.patch
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,32 @@ diff --git a/browser/components/tabbrowser/content/tabbrowser.js b/browser/compo
index 6dece2b9d0462d90a28e75350ce983d87816ef73..5c49c43714b3914130f8d821d902f9f255c4ebc9 100644
--- a/browser/components/tabbrowser/content/tabbrowser.js
+++ b/browser/components/tabbrowser/content/tabbrowser.js
@@ -415,11 +415,45 @@
@@ -117,6 +117,24 @@
UrlbarProviderOpenTabs:
"resource:///modules/UrlbarProviderOpenTabs.sys.mjs",
});
+ // Add TabSelect event listener to update open tab information
+ this.tabContainer.addEventListener("TabSelect", async event => {
+ let tab = event.target;
+ let browser = tab.linkedBrowser;
+ let url = browser.currentURI.spec;
+ let userContextId = tab.getAttribute("usercontextid") || 0;
+ let isInPrivateWindow = PrivateBrowsingUtils.isWindowPrivate(window);
+
+ try {
+ await this.UrlbarProviderOpenTabs.updateOpenTab(
+ url,
+ parseInt(userContextId),
+ isInPrivateWindow
+ );
+ } catch (error) {
+ console.error("Failed to update open tab:", error);
+ }
+ });
ChromeUtils.defineLazyGetter(this, "tabLocalization", () => {
return new Localization(
["browser/tabbrowser.ftl", "branding/brand.ftl"],
@@ -415,11 +433,45 @@
return this.tabContainer.visibleTabs;
}

Expand Down Expand Up @@ -50,15 +75,15 @@ index 6dece2b9d0462d90a28e75350ce983d87816ef73..5c49c43714b3914130f8d821d902f9f2
}
return i;
}
@@ -571,6 +605,7 @@
@@ -571,6 +623,7 @@
this.tabpanels.appendChild(panel);

let tab = this.tabs[0];
+ gZenWorkspaces.handleInitialTab(tab, (!remoteType || remoteType === E10SUtils.PRIVILEGEDABOUT_REMOTE_TYPE) && !gZenUIManager.testingEnabled);
tab.linkedPanel = uniqueId;
this._selectedTab = tab;
this._selectedBrowser = browser;
@@ -836,11 +871,13 @@
@@ -836,11 +889,13 @@
}

this.showTab(aTab);
Expand All @@ -75,7 +100,7 @@ index 6dece2b9d0462d90a28e75350ce983d87816ef73..5c49c43714b3914130f8d821d902f9f2
this.moveTabTo(aTab, {
tabIndex: this.pinnedTabCount,
forceUngrouped: true,
@@ -857,12 +894,15 @@
@@ -857,12 +912,15 @@
}

if (this.tabContainer.verticalMode) {
Expand All @@ -92,7 +117,7 @@ index 6dece2b9d0462d90a28e75350ce983d87816ef73..5c49c43714b3914130f8d821d902f9f2
});
} else {
this.moveTabTo(aTab, {
@@ -1046,6 +1086,8 @@
@@ -1046,6 +1104,8 @@

let LOCAL_PROTOCOLS = ["chrome:", "about:", "resource:", "data:"];

Expand All @@ -101,7 +126,7 @@ index 6dece2b9d0462d90a28e75350ce983d87816ef73..5c49c43714b3914130f8d821d902f9f2
if (
aIconURL &&
!aLoadingPrincipal &&
@@ -1056,6 +1098,9 @@
@@ -1056,6 +1116,9 @@
);
return;
}
Expand All @@ -111,15 +136,15 @@ index 6dece2b9d0462d90a28e75350ce983d87816ef73..5c49c43714b3914130f8d821d902f9f2

let browser = this.getBrowserForTab(aTab);
browser.mIconURL = aIconURL;
@@ -1305,6 +1350,7 @@
@@ -1305,6 +1368,7 @@
if (!this._previewMode) {
newTab.recordTimeFromUnloadToReload();
newTab.updateLastAccessed();
+ newTab.removeAttribute("unread");
oldTab.updateLastAccessed();
// if this is the foreground window, update the last-seen timestamps.
if (this.ownerGlobal == BrowserWindowTracker.getTopWindow()) {
@@ -1457,6 +1503,9 @@
@@ -1457,6 +1521,9 @@
}

let activeEl = document.activeElement;
Expand All @@ -129,7 +154,7 @@ index 6dece2b9d0462d90a28e75350ce983d87816ef73..5c49c43714b3914130f8d821d902f9f2
// If focus is on the old tab, move it to the new tab.
if (activeEl == oldTab) {
newTab.focus();
@@ -1780,7 +1829,8 @@
@@ -1780,7 +1847,8 @@
}

_setTabLabel(aTab, aLabel, { beforeTabOpen, isContentTitle, isURL } = {}) {
Expand All @@ -139,7 +164,7 @@ index 6dece2b9d0462d90a28e75350ce983d87816ef73..5c49c43714b3914130f8d821d902f9f2
return false;
}

@@ -1888,7 +1938,7 @@
@@ -1888,7 +1956,7 @@
newIndex = this.selectedTab._tPos + 1;
}

Expand All @@ -148,15 +173,15 @@ index 6dece2b9d0462d90a28e75350ce983d87816ef73..5c49c43714b3914130f8d821d902f9f2
if (this.isTabGroupLabel(targetTab)) {
throw new Error(
"Replacing a tab group label with a tab is not supported"
@@ -2152,6 +2202,7 @@
@@ -2152,6 +2220,7 @@
uriIsAboutBlank,
userContextId,
skipLoad,
+ _forZenEmptyTab,
} = {}) {
let b = document.createXULElement("browser");
// Use the JSM global to create the permanentKey, so that if the
@@ -2225,8 +2276,7 @@
@@ -2225,8 +2294,7 @@
// we use a different attribute name for this?
b.setAttribute("name", name);
}
Expand All @@ -166,7 +191,7 @@ index 6dece2b9d0462d90a28e75350ce983d87816ef73..5c49c43714b3914130f8d821d902f9f2
b.setAttribute("transparent", "true");
}

@@ -2391,7 +2441,7 @@
@@ -2391,7 +2459,7 @@

let panel = this.getPanel(browser);
let uniqueId = this._generateUniquePanelID();
Expand All @@ -175,7 +200,7 @@ index 6dece2b9d0462d90a28e75350ce983d87816ef73..5c49c43714b3914130f8d821d902f9f2
aTab.linkedPanel = uniqueId;

// Inject the <browser> into the DOM if necessary.
@@ -2450,8 +2500,8 @@
@@ -2450,8 +2518,8 @@
// If we transitioned from one browser to two browsers, we need to set
// hasSiblings=false on both the existing browser and the new browser.
if (this.tabs.length == 2) {
Expand All @@ -186,15 +211,15 @@ index 6dece2b9d0462d90a28e75350ce983d87816ef73..5c49c43714b3914130f8d821d902f9f2
} else {
aTab.linkedBrowser.browsingContext.hasSiblings = this.tabs.length > 1;
}
@@ -2679,6 +2729,7 @@
@@ -2679,6 +2747,7 @@
schemelessInput,
hasValidUserGestureActivation = false,
textDirectiveUserActivation = false,
+ _forZenEmptyTab,
} = {}
) {
// all callers of addTab that pass a params object need to pass
@@ -2689,6 +2740,12 @@
@@ -2689,6 +2758,12 @@
);
}

Expand All @@ -207,7 +232,7 @@ index 6dece2b9d0462d90a28e75350ce983d87816ef73..5c49c43714b3914130f8d821d902f9f2
if (!UserInteraction.running("browser.tabs.opening", window)) {
UserInteraction.start("browser.tabs.opening", "initting", window);
}
@@ -2752,6 +2809,16 @@
@@ -2752,6 +2827,16 @@
noInitialLabel,
skipBackgroundNotify,
});
Expand All @@ -224,15 +249,15 @@ index 6dece2b9d0462d90a28e75350ce983d87816ef73..5c49c43714b3914130f8d821d902f9f2
if (insertTab) {
if (typeof index == "number") {
elementIndex = this.#tabIndexToElementIndex(index);
@@ -2779,6 +2846,7 @@
@@ -2779,6 +2864,7 @@
openWindowInfo,
skipLoad,
triggeringRemoteType,
+ _forZenEmptyTab,
}));

if (focusUrlBar) {
@@ -2898,6 +2966,12 @@
@@ -2898,6 +2984,12 @@
}
}

Expand All @@ -245,7 +270,7 @@ index 6dece2b9d0462d90a28e75350ce983d87816ef73..5c49c43714b3914130f8d821d902f9f2
// Additionally send pinned tab events
if (pinned) {
this._notifyPinnedStatus(t);
@@ -2945,12 +3019,15 @@
@@ -2945,12 +3037,15 @@
* @param {string} [label=]
* @returns {MozTabbrowserTabGroup}
*/
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,28 @@
diff --git a/browser/components/urlbar/UrlbarMuxerUnifiedComplete.sys.mjs b/browser/components/urlbar/UrlbarMuxerUnifiedComplete.sys.mjs
index dcf1af43d62979d3226d7f704c51a2f0bb935cc0..8879d657b99cb20cd657c2e4841738ffaa09c658 100644
index dcf1af43d62979d3226d7f704c51a2f0bb935cc0..a8271ac083c54947756e6ef35a3b4eac407b03f9 100644
--- a/browser/components/urlbar/UrlbarMuxerUnifiedComplete.sys.mjs
+++ b/browser/components/urlbar/UrlbarMuxerUnifiedComplete.sys.mjs
@@ -794,6 +794,7 @@ class MuxerUnifiedComplete extends UrlbarMuxer {
@@ -117,6 +117,19 @@ class MuxerUnifiedComplete extends UrlbarMuxer {
// When you add state, update _copyState() as necessary.
};

+ let window = Services.wm.getMostRecentWindow("navigator:browser");
+ if (window && typeof window.gZenTabSearch !== "undefined" && window.gURLBar && window.gURLBar.searchMode && window.gURLBar.searchMode.source === 4) {
+ unsortedResults.sort((a, b) => {
+ const lastOpenedA = a.payload?.lastOpened || 0;
+ const lastOpenedB = b.payload?.lastOpened|| 0;
+ return lastOpenedB - lastOpenedA; // Descending order
+ });
+ if (window.gZenTabSearch.shouldInjectHeuristic()) {
+ unsortedResults[0].heuristic = true
+ unsortedResults[0].providerName = "HeuristicFallback"
+ }
+ }
+
// Do the first pass over all results to build some state.
for (let result of unsortedResults) {
// Add each result to the appropriate `resultsByGroup` map.
@@ -794,6 +805,7 @@ class MuxerUnifiedComplete extends UrlbarMuxer {
}

if (result.providerName == lazy.UrlbarProviderTabToSearch.name) {
Expand Down
Loading