Renaming extensions subdirectory for GNOME 48.
Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
parent
8ed6608e27
commit
d13dfd08e5
189 changed files with 1 additions and 1 deletions
|
@ -1,478 +0,0 @@
|
|||
/**
|
||||
* V-Shell (Vertical Workspaces)
|
||||
* search.js
|
||||
*
|
||||
* @author GdH <G-dH@github.com>
|
||||
* @copyright 2022 - 2024
|
||||
* @license GPL-3.0
|
||||
*
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
import GLib from 'gi://GLib';
|
||||
import Clutter from 'gi://Clutter';
|
||||
import St from 'gi://St';
|
||||
import Shell from 'gi://Shell';
|
||||
import GObject from 'gi://GObject';
|
||||
|
||||
import * as Main from 'resource:///org/gnome/shell/ui/main.js';
|
||||
import * as Search from 'resource:///org/gnome/shell/ui/search.js';
|
||||
import * as AppDisplay from 'resource:///org/gnome/shell/ui/appDisplay.js';
|
||||
|
||||
import * as SystemActions from 'resource:///org/gnome/shell/misc/systemActions.js';
|
||||
import { Highlighter } from 'resource:///org/gnome/shell/misc/util.js';
|
||||
|
||||
let Me;
|
||||
// gettext
|
||||
let _;
|
||||
let opt;
|
||||
|
||||
const SEARCH_MAX_WIDTH = 1092;
|
||||
|
||||
export const SearchModule = class {
|
||||
constructor(me) {
|
||||
Me = me;
|
||||
opt = Me.opt;
|
||||
_ = Me.gettext;
|
||||
|
||||
this._firstActivation = true;
|
||||
this.moduleEnabled = false;
|
||||
this._overrides = null;
|
||||
}
|
||||
|
||||
cleanGlobals() {
|
||||
Me = null;
|
||||
opt = null;
|
||||
_ = null;
|
||||
}
|
||||
|
||||
update(reset) {
|
||||
this.moduleEnabled = opt.get('searchModule');
|
||||
const conflict = false;
|
||||
|
||||
reset = reset || !this.moduleEnabled || conflict;
|
||||
|
||||
// don't touch the original code if module disabled
|
||||
if (reset && !this._firstActivation) {
|
||||
this._disableModule();
|
||||
} else if (!reset) {
|
||||
this._firstActivation = false;
|
||||
this._activateModule();
|
||||
}
|
||||
if (reset && this._firstActivation)
|
||||
console.debug(' SearchModule - Keeping untouched');
|
||||
}
|
||||
|
||||
_activateModule() {
|
||||
this._updateSearchViewWidth();
|
||||
|
||||
if (!this._overrides)
|
||||
this._overrides = new Me.Util.Overrides();
|
||||
|
||||
this._overrides.addOverride('AppSearchProvider', AppDisplay.AppSearchProvider.prototype, AppSearchProvider);
|
||||
this._overrides.addOverride('SearchResult', Search.SearchResult.prototype, SearchResult);
|
||||
this._overrides.addOverride('SearchResultsView', Search.SearchResultsView.prototype, SearchResultsView);
|
||||
this._overrides.addOverride('ListSearchResults', Search.ListSearchResults.prototype, ListSearchResults);
|
||||
this._overrides.addOverride('ListSearchResult', Search.ListSearchResult.prototype, ListSearchResultOverride);
|
||||
this._overrides.addOverride('Highlighter', Highlighter.prototype, HighlighterOverride);
|
||||
|
||||
// Don't expand the search view vertically and align it to the top
|
||||
// this is important in the static workspace mode when the search view bg is not transparent
|
||||
// also the "Searching..." and "No Results" notifications will be closer to the search entry, with the distance given by margin-top in the stylesheet
|
||||
Main.overview.searchController.y_align = Clutter.ActorAlign.START;
|
||||
// Increase the maxResults for app search so that it can show more results in case the user decreases the size of the result icon
|
||||
const appSearchDisplay = Main.overview.searchController._searchResults._providers.filter(p => p.id === 'applications')[0]?.display;
|
||||
if (appSearchDisplay)
|
||||
appSearchDisplay._maxResults = 12;
|
||||
console.debug(' SearchModule - Activated');
|
||||
}
|
||||
|
||||
_disableModule() {
|
||||
const reset = true;
|
||||
|
||||
const searchResults = Main.overview.searchController._searchResults;
|
||||
if (searchResults?._searchTimeoutId) {
|
||||
GLib.source_remove(searchResults._searchTimeoutId);
|
||||
searchResults._searchTimeoutId = 0;
|
||||
}
|
||||
|
||||
this._updateSearchViewWidth(reset);
|
||||
|
||||
if (this._overrides)
|
||||
this._overrides.removeAll();
|
||||
this._overrides = null;
|
||||
|
||||
Main.overview.searchController.y_align = Clutter.ActorAlign.FILL;
|
||||
|
||||
console.debug(' WorkspaceSwitcherPopupModule - Disabled');
|
||||
}
|
||||
|
||||
_updateSearchViewWidth(reset = false) {
|
||||
const searchContent = Main.overview.searchController._searchResults._content;
|
||||
|
||||
if (reset) {
|
||||
searchContent.set_style('');
|
||||
} else {
|
||||
let width = SEARCH_MAX_WIDTH;
|
||||
if (Me.Util.monitorHasLowResolution())
|
||||
width = Math.round(width * 0.8);
|
||||
width = Math.round(width * opt.SEARCH_VIEW_SCALE);
|
||||
searchContent.set_style(`max-width: ${width}px;`);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const ListSearchResults = {
|
||||
_getMaxDisplayedResults() {
|
||||
return opt.SEARCH_MAX_ROWS;
|
||||
},
|
||||
};
|
||||
|
||||
// AppDisplay.AppSearchProvider
|
||||
const AppSearchProvider = {
|
||||
getInitialResultSet(terms, cancellable) {
|
||||
// Defer until the parental controls manager is initialized, so the
|
||||
// results can be filtered correctly.
|
||||
if (!this._parentalControlsManager.initialized) {
|
||||
return new Promise(resolve => {
|
||||
let initializedId = this._parentalControlsManager.connect('app-filter-changed', async () => {
|
||||
if (this._parentalControlsManager.initialized) {
|
||||
this._parentalControlsManager.disconnect(initializedId);
|
||||
resolve(await this.getInitialResultSet(terms, cancellable));
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
const pattern = terms.join(' ');
|
||||
|
||||
let appInfoList = Shell.AppSystem.get_default().get_installed();
|
||||
|
||||
let weightList = {};
|
||||
appInfoList = appInfoList.filter(appInfo => {
|
||||
try {
|
||||
appInfo.get_id(); // catch invalid file encodings
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let string = '';
|
||||
let name;
|
||||
let shouldShow = false;
|
||||
if (appInfo.get_display_name) {
|
||||
// show only launchers that should be visible in this DE
|
||||
shouldShow = appInfo.should_show() && this._parentalControlsManager.shouldShowApp(appInfo);
|
||||
|
||||
if (shouldShow) {
|
||||
let id = appInfo.get_id().split('.');
|
||||
id = id[id.length - 2] || '';
|
||||
let baseName = appInfo.get_string('Name') || '';
|
||||
let dispName = appInfo.get_display_name() || '';
|
||||
let gName = appInfo.get_generic_name() || '';
|
||||
let description = appInfo.get_description() || '';
|
||||
let categories = appInfo.get_string('Categories')?.replace(/;/g, ' ') || '';
|
||||
let keywords = appInfo.get_string('Keywords')?.replace(/;/g, ' ') || '';
|
||||
name = `${dispName} ${id}`;
|
||||
string = `${dispName} ${gName} ${baseName} ${description} ${categories} ${keywords} ${id}`;
|
||||
}
|
||||
}
|
||||
|
||||
let m = -1;
|
||||
if (shouldShow && opt.SEARCH_FUZZY) {
|
||||
m = Me.Util.fuzzyMatch(pattern, name);
|
||||
m = (m + Me.Util.strictMatch(pattern, string)) / 2;
|
||||
} else if (shouldShow) {
|
||||
m = Me.Util.strictMatch(pattern, string);
|
||||
}
|
||||
|
||||
if (m !== -1)
|
||||
weightList[appInfo.get_id()] = m;
|
||||
|
||||
return shouldShow && (m !== -1);
|
||||
});
|
||||
|
||||
appInfoList.sort((a, b) => weightList[a.get_id()] > weightList[b.get_id()]);
|
||||
|
||||
const usage = Shell.AppUsage.get_default();
|
||||
// sort apps by usage list
|
||||
appInfoList.sort((a, b) => usage.compare(a.get_id(), b.get_id()));
|
||||
// prefer apps where any word in their name starts with the pattern
|
||||
appInfoList.sort((a, b) => Me.Util.isMoreRelevant(a.get_display_name(), b.get_display_name(), pattern));
|
||||
|
||||
let results = appInfoList.map(app => app.get_id());
|
||||
|
||||
if (opt.SEARCH_APP_GRID_MODE && Main.overview.dash.showAppsButton.checked)
|
||||
this._filterAppGrid(results);
|
||||
|
||||
results = results.concat(this._systemActions.getMatchingActions(terms));
|
||||
|
||||
return new Promise(resolve => resolve(results));
|
||||
},
|
||||
|
||||
_filterAppGrid(results) {
|
||||
const appDisplay = Main.overview._overview.controls._appDisplay;
|
||||
let icons = appDisplay._orderedItems;
|
||||
icons.forEach(icon => {
|
||||
icon.visible = true;
|
||||
});
|
||||
appDisplay._redisplay(results);
|
||||
icons = appDisplay._orderedItems;
|
||||
icons.forEach(icon => {
|
||||
icon.visible = results.includes(icon.id);
|
||||
});
|
||||
},
|
||||
|
||||
// App search result size
|
||||
createResultObject(resultMeta) {
|
||||
let iconSize = opt.SEARCH_ICON_SIZE;
|
||||
if (!iconSize) {
|
||||
iconSize = Me.Util.monitorHasLowResolution()
|
||||
? 64
|
||||
: 96;
|
||||
}
|
||||
|
||||
if (resultMeta.id.endsWith('.desktop')) {
|
||||
const icon = new AppDisplay.AppIcon(this._appSys.lookup_app(resultMeta['id']), {
|
||||
expandTitleOnHover: false,
|
||||
});
|
||||
icon.icon.setIconSize(iconSize);
|
||||
return icon;
|
||||
} else {
|
||||
this._iconSize = iconSize;
|
||||
return new SystemActionIcon(this, resultMeta);
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
const SystemActionIcon = GObject.registerClass({
|
||||
// Registered name should be unique
|
||||
GTypeName: `SystemAction${Math.floor(Math.random() * 1000)}`,
|
||||
}, class SystemActionIcon extends Search.GridSearchResult {
|
||||
_init(provider, metaInfo, resultsView) {
|
||||
super._init(provider, metaInfo, resultsView);
|
||||
this.icon._setSizeManually = true;
|
||||
this.icon.setIconSize(provider._iconSize);
|
||||
}
|
||||
|
||||
activate() {
|
||||
SystemActions.getDefault().activateAction(this.metaInfo['id']);
|
||||
Main.overview.hide();
|
||||
}
|
||||
});
|
||||
|
||||
const SearchResult = {
|
||||
activate() {
|
||||
this.provider.activateResult(this.metaInfo.id, this._resultsView.terms);
|
||||
|
||||
if (this.metaInfo.clipboardText) {
|
||||
St.Clipboard.get_default().set_text(
|
||||
St.ClipboardType.CLIPBOARD, this.metaInfo.clipboardText);
|
||||
}
|
||||
// don't close overview if Shift key is pressed - Shift moves windows to the workspace
|
||||
if (!Me.Util.isShiftPressed())
|
||||
Main.overview.toggle();
|
||||
},
|
||||
};
|
||||
|
||||
const SearchResultsView = {
|
||||
setTerms(terms) {
|
||||
// Check for the case of making a duplicate previous search before
|
||||
// setting state of the current search or cancelling the search.
|
||||
// This will prevent incorrect state being as a result of a duplicate
|
||||
// search while the previous search is still active.
|
||||
let searchString = terms.join(' ');
|
||||
let previousSearchString = this._terms.join(' ');
|
||||
if (searchString === previousSearchString)
|
||||
return;
|
||||
|
||||
this._startingSearch = true;
|
||||
|
||||
this._cancellable.cancel();
|
||||
this._cancellable.reset();
|
||||
|
||||
if (terms.length === 0) {
|
||||
this._reset();
|
||||
return;
|
||||
}
|
||||
|
||||
let isSubSearch = false;
|
||||
if (this._terms.length > 0)
|
||||
isSubSearch = searchString.indexOf(previousSearchString) === 0;
|
||||
|
||||
this._terms = terms;
|
||||
this._isSubSearch = isSubSearch;
|
||||
this._updateSearchProgress();
|
||||
|
||||
if (!this._searchTimeoutId)
|
||||
this._searchTimeoutId = GLib.timeout_add(GLib.PRIORITY_DEFAULT, opt.SEARCH_DELAY, this._onSearchTimeout.bind(this));
|
||||
|
||||
this._highlighter = new Highlighter(this._terms);
|
||||
|
||||
this.emit('terms-changed');
|
||||
},
|
||||
|
||||
_doSearch() {
|
||||
this._startingSearch = false;
|
||||
|
||||
let previousResults = this._results;
|
||||
this._results = {};
|
||||
|
||||
const term0 = this._terms[0];
|
||||
const onlySupportedProviders = term0.startsWith(Me.WSP_PREFIX) || term0.startsWith(Me.ESP_PREFIX) || term0.startsWith(Me.RFSP_PREFIX);
|
||||
|
||||
this._providers.forEach(provider => {
|
||||
const supportedProvider = ['open-windows', 'extensions', 'recent-files'].includes(provider.id);
|
||||
if (!onlySupportedProviders || (onlySupportedProviders && supportedProvider)) {
|
||||
let previousProviderResults = previousResults[provider.id];
|
||||
this._doProviderSearch(provider, previousProviderResults);
|
||||
} else {
|
||||
// hide unwanted providers, they will show() automatically when needed
|
||||
provider.display.visible = false;
|
||||
}
|
||||
});
|
||||
|
||||
this._updateSearchProgress();
|
||||
this._clearSearchTimeout();
|
||||
},
|
||||
|
||||
_updateSearchProgress() {
|
||||
let haveResults = this._providers.some(provider => {
|
||||
let display = provider.display;
|
||||
return display.getFirstResult() !== null;
|
||||
});
|
||||
|
||||
this._scrollView.visible = haveResults;
|
||||
this._statusBin.visible = !haveResults;
|
||||
|
||||
if (!haveResults) {
|
||||
if (this.searchInProgress)
|
||||
this._statusText.set_text(_('Searching…'));
|
||||
else
|
||||
this._statusText.set_text(_('No results.'));
|
||||
}
|
||||
},
|
||||
|
||||
_highlightFirstVisibleAppGridIcon() {
|
||||
const appDisplay = Main.overview._overview.controls._appDisplay;
|
||||
// appDisplay.grab_key_focus();
|
||||
for (const icon of appDisplay._orderedItems) {
|
||||
if (icon.visible) {
|
||||
appDisplay.selectApp(icon.id);
|
||||
break;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
_maybeSetInitialSelection() {
|
||||
if (opt.SEARCH_APP_GRID_MODE && Main.overview.dash.showAppsButton.checked) {
|
||||
this._highlightFirstVisibleAppGridIcon();
|
||||
return;
|
||||
}
|
||||
|
||||
let newDefaultResult = null;
|
||||
|
||||
let providers = this._providers;
|
||||
for (let i = 0; i < providers.length; i++) {
|
||||
let provider = providers[i];
|
||||
let display = provider.display;
|
||||
|
||||
if (!display.visible)
|
||||
continue;
|
||||
|
||||
let firstResult = display.getFirstResult();
|
||||
if (firstResult) {
|
||||
newDefaultResult = firstResult;
|
||||
break; // select this one!
|
||||
}
|
||||
}
|
||||
|
||||
if (newDefaultResult !== this._defaultResult) {
|
||||
this._setSelected(this._defaultResult, false);
|
||||
this._setSelected(newDefaultResult, this._highlightDefault);
|
||||
|
||||
this._defaultResult = newDefaultResult;
|
||||
}
|
||||
},
|
||||
|
||||
highlightDefault(highlight) {
|
||||
if (opt.SEARCH_APP_GRID_MODE && Main.overview.dash.showAppsButton.checked) {
|
||||
if (highlight)
|
||||
this._highlightFirstVisibleAppGridIcon();
|
||||
} else {
|
||||
this._highlightDefault = highlight;
|
||||
this._setSelected(this._defaultResult, highlight);
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
// Add highlighting of the "name" part of the result for all providers
|
||||
const ListSearchResultOverride = {
|
||||
_highlightTerms() {
|
||||
let markup = this._resultsView.highlightTerms(this.metaInfo['name']);
|
||||
this.label_actor.clutter_text.set_markup(markup);
|
||||
markup = this._resultsView.highlightTerms(this.metaInfo['description'].split('\n')[0]);
|
||||
this._descriptionLabel.clutter_text.set_markup(markup);
|
||||
},
|
||||
};
|
||||
|
||||
const HighlighterOverride = {
|
||||
/**
|
||||
* @param {?string[]} terms - list of terms to highlight
|
||||
*/
|
||||
/* constructor(terms) {
|
||||
if (!terms)
|
||||
return;
|
||||
|
||||
const escapedTerms = terms
|
||||
.map(term => Shell.util_regex_escape(term))
|
||||
.filter(term => term.length > 0);
|
||||
|
||||
if (escapedTerms.length === 0)
|
||||
return;
|
||||
|
||||
this._highlightRegex = new RegExp(
|
||||
`(${escapedTerms.join('|')})`, 'gi');
|
||||
},*/
|
||||
|
||||
/**
|
||||
* Highlight all occurences of the terms defined for this
|
||||
* highlighter in the provided text using markup.
|
||||
*
|
||||
* @param {string} text - text to highlight the defined terms in
|
||||
* @returns {string}
|
||||
*/
|
||||
highlight(text, options) {
|
||||
if (!this._highlightRegex)
|
||||
return GLib.markup_escape_text(text, -1);
|
||||
|
||||
// force use local settings if the class is overridden by another extension (WSP, ESP)
|
||||
const o = options || opt;
|
||||
let escaped = [];
|
||||
let lastMatchEnd = 0;
|
||||
let match;
|
||||
let style = ['', ''];
|
||||
if (o.HIGHLIGHT_DEFAULT)
|
||||
style = ['<b>', '</b>'];
|
||||
// The default highlighting by the bold style causes text to be "randomly" ellipsized in cases where it's not necessary
|
||||
// and also blurry
|
||||
// Underscore doesn't affect label size and all looks better
|
||||
else if (o.HIGHLIGHT_UNDERLINE)
|
||||
style = ['<u>', '</u>'];
|
||||
|
||||
while ((match = this._highlightRegex.exec(text))) {
|
||||
if (match.index > lastMatchEnd) {
|
||||
let unmatched = GLib.markup_escape_text(
|
||||
text.slice(lastMatchEnd, match.index), -1);
|
||||
escaped.push(unmatched);
|
||||
}
|
||||
let matched = GLib.markup_escape_text(match[0], -1);
|
||||
escaped.push(`${style[0]}${matched}${style[1]}`);
|
||||
lastMatchEnd = match.index + match[0].length;
|
||||
}
|
||||
let unmatched = GLib.markup_escape_text(
|
||||
text.slice(lastMatchEnd), -1);
|
||||
escaped.push(unmatched);
|
||||
return escaped.join('');
|
||||
},
|
||||
};
|
Loading…
Add table
Add a link
Reference in a new issue