search: Make the internal search interface callback-based
Long ago, the search system worked in a synchronous manner: providers were given a query, and results were collected in a single array of [provider, results] pairs, and then the search display was updated from that. We introduced an asynchronous search system when we wanted to potentially add a Zeitgeist search provider to the Shell in 3.2. For a while, search providers were either async or sync, which worked by storing a dummy array in the results, and adding a method for search providers to add results later. Later, we removed the search system entirely and ported the remaining search providers to simply use the API to modify the empty array, but the remains of the synchronous search system with its silly array still lingered. Finally, it's time to modernize. Promises^WCallbacks are the future. Port the one remaining in-shell search engine (app search) to the new callback based system, and simplify the remote search system in the process.
This commit is contained in:
parent
dc2468b27b
commit
9cd7ea9371
@ -890,12 +890,12 @@ const AppSearchProvider = new Lang.Class({
|
|||||||
return results.slice(0, maxNumber);
|
return results.slice(0, maxNumber);
|
||||||
},
|
},
|
||||||
|
|
||||||
getInitialResultSet: function(terms) {
|
getInitialResultSet: function(terms, callback, cancellable) {
|
||||||
this.searchSystem.setResults(this, this._appSys.initial_search(terms));
|
callback(this._appSys.initial_search(terms));
|
||||||
},
|
},
|
||||||
|
|
||||||
getSubsearchResultSet: function(previousResults, terms) {
|
getSubsearchResultSet: function(terms, callback, cancellable) {
|
||||||
this.searchSystem.setResults(this, this._appSys.subsearch(previousResults, terms));
|
callbacl(this._appSys.subsearch(previousResults, terms));
|
||||||
},
|
},
|
||||||
|
|
||||||
activateResult: function(result) {
|
activateResult: function(result) {
|
||||||
|
@ -203,8 +203,6 @@ const RemoteSearchProvider = new Lang.Class({
|
|||||||
this.appInfo = appInfo;
|
this.appInfo = appInfo;
|
||||||
this.id = appInfo.get_id();
|
this.id = appInfo.get_id();
|
||||||
this.isRemoteProvider = true;
|
this.isRemoteProvider = true;
|
||||||
|
|
||||||
this._cancellable = new Gio.Cancellable();
|
|
||||||
},
|
},
|
||||||
|
|
||||||
createIcon: function(size, meta) {
|
createIcon: function(size, meta) {
|
||||||
@ -234,29 +232,27 @@ const RemoteSearchProvider = new Lang.Class({
|
|||||||
return regularResults.slice(0, maxNumber).concat(specialResults.slice(0, maxNumber));
|
return regularResults.slice(0, maxNumber).concat(specialResults.slice(0, maxNumber));
|
||||||
},
|
},
|
||||||
|
|
||||||
_getResultsFinished: function(results, error) {
|
_getResultsFinished: function(results, error, callback) {
|
||||||
if (error) {
|
if (error) {
|
||||||
if (!error.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED))
|
if (!error.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED))
|
||||||
log('Received error from DBus search provider %s: %s'.format(this.id, String(error)));
|
log('Received error from DBus search provider %s: %s'.format(this.id, String(error)));
|
||||||
} else {
|
callback([]);
|
||||||
this.searchSystem.setResults(this, results[0]);
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
callback(results[0]);
|
||||||
},
|
},
|
||||||
|
|
||||||
getInitialResultSet: function(terms) {
|
getInitialResultSet: function(terms, callback, cancellable) {
|
||||||
this._cancellable.cancel();
|
|
||||||
this._cancellable.reset();
|
|
||||||
this.proxy.GetInitialResultSetRemote(terms,
|
this.proxy.GetInitialResultSetRemote(terms,
|
||||||
Lang.bind(this, this._getResultsFinished),
|
Lang.bind(this, this._getResultsFinished, callback),
|
||||||
this._cancellable);
|
cancellable);
|
||||||
},
|
},
|
||||||
|
|
||||||
getSubsearchResultSet: function(previousResults, newTerms) {
|
getSubsearchResultSet: function(previousResults, newTerms, cancellable) {
|
||||||
this._cancellable.cancel();
|
|
||||||
this._cancellable.reset();
|
|
||||||
this.proxy.GetSubsearchResultSetRemote(previousResults, newTerms,
|
this.proxy.GetSubsearchResultSetRemote(previousResults, newTerms,
|
||||||
Lang.bind(this, this._getResultsFinished),
|
Lang.bind(this, this._getResultsFinished, callback),
|
||||||
this._cancellable);
|
cancellable);
|
||||||
},
|
},
|
||||||
|
|
||||||
_getResultMetasFinished: function(results, error, callback) {
|
_getResultMetasFinished: function(results, error, callback) {
|
||||||
@ -284,12 +280,10 @@ const RemoteSearchProvider = new Lang.Class({
|
|||||||
callback(resultMetas);
|
callback(resultMetas);
|
||||||
},
|
},
|
||||||
|
|
||||||
getResultMetas: function(ids, callback) {
|
getResultMetas: function(ids, callback, cancellable) {
|
||||||
this._cancellable.cancel();
|
|
||||||
this._cancellable.reset();
|
|
||||||
this.proxy.GetResultMetasRemote(ids,
|
this.proxy.GetResultMetasRemote(ids,
|
||||||
Lang.bind(this, this._getResultMetasFinished, callback),
|
Lang.bind(this, this._getResultMetasFinished, callback),
|
||||||
this._cancellable);
|
cancellable);
|
||||||
},
|
},
|
||||||
|
|
||||||
activateResult: function(id) {
|
activateResult: function(id) {
|
||||||
|
@ -37,6 +37,8 @@ const SearchSystem = new Lang.Class({
|
|||||||
this._searchSettings.connect('changed::sort-order', Lang.bind(this, this._reloadRemoteProviders));
|
this._searchSettings.connect('changed::sort-order', Lang.bind(this, this._reloadRemoteProviders));
|
||||||
|
|
||||||
this._reloadRemoteProviders();
|
this._reloadRemoteProviders();
|
||||||
|
|
||||||
|
this._cancellable = new Gio.Cancellable();
|
||||||
},
|
},
|
||||||
|
|
||||||
addProvider: function(provider) {
|
addProvider: function(provider) {
|
||||||
@ -60,14 +62,12 @@ const SearchSystem = new Lang.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
_registerProvider: function (provider) {
|
_registerProvider: function (provider) {
|
||||||
provider.searchSystem = this;
|
|
||||||
this._providers.push(provider);
|
this._providers.push(provider);
|
||||||
},
|
},
|
||||||
|
|
||||||
_unregisterProvider: function (provider) {
|
_unregisterProvider: function (provider) {
|
||||||
let index = this._providers.indexOf(provider);
|
let index = this._providers.indexOf(provider);
|
||||||
this._providers.splice(index, 1);
|
this._providers.splice(index, 1);
|
||||||
provider.searchSystem = null;
|
|
||||||
},
|
},
|
||||||
|
|
||||||
getProviders: function() {
|
getProviders: function() {
|
||||||
@ -75,54 +75,50 @@ const SearchSystem = new Lang.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
getTerms: function() {
|
getTerms: function() {
|
||||||
return this._previousTerms;
|
return this._terms;
|
||||||
},
|
},
|
||||||
|
|
||||||
reset: function() {
|
reset: function() {
|
||||||
this._previousTerms = [];
|
this._terms = [];
|
||||||
this._previousResults = [];
|
this._results = {};
|
||||||
},
|
},
|
||||||
|
|
||||||
setResults: function(provider, results) {
|
_gotResults: function(results, provider) {
|
||||||
let i = this._providers.indexOf(provider);
|
this._results[provider.id] = results;
|
||||||
if (i == -1)
|
this.emit('search-updated', provider, results);
|
||||||
return;
|
|
||||||
|
|
||||||
this._previousResults[i] = [provider, results];
|
|
||||||
this.emit('search-updated', this._previousResults[i]);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
setTerms: function(terms) {
|
setTerms: function(terms) {
|
||||||
|
this._cancellable.cancel();
|
||||||
|
this._cancellable.reset();
|
||||||
|
|
||||||
|
let previousResults = this._results;
|
||||||
|
let previousTerms = this._terms;
|
||||||
|
this.reset();
|
||||||
|
|
||||||
if (!terms)
|
if (!terms)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
let searchString = terms.join(' ');
|
let searchString = terms.join(' ');
|
||||||
let previousSearchString = this._previousTerms.join(' ');
|
let previousSearchString = previousTerms.join(' ');
|
||||||
if (searchString == previousSearchString)
|
if (searchString == previousSearchString)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
let isSubSearch = false;
|
let isSubSearch = false;
|
||||||
if (this._previousTerms.length > 0)
|
if (previousTerms.length > 0)
|
||||||
isSubSearch = searchString.indexOf(previousSearchString) == 0;
|
isSubSearch = searchString.indexOf(previousSearchString) == 0;
|
||||||
|
|
||||||
let previousResultsArr = this._previousResults;
|
this._terms = terms;
|
||||||
|
|
||||||
let results = [];
|
|
||||||
this._previousTerms = terms;
|
|
||||||
this._previousResults = results;
|
|
||||||
|
|
||||||
if (isSubSearch) {
|
if (isSubSearch) {
|
||||||
for (let i = 0; i < this._providers.length; i++) {
|
this._providers.forEach(Lang.bind(this, function(provider) {
|
||||||
let [provider, previousResults] = previousResultsArr[i];
|
let previousResults = previousResults[provider.id];
|
||||||
results.push([provider, []]);
|
provider.getSubsearchResultSet(previousResults, terms, Lang.bind(this, this._gotResults, provider), this._cancellable);
|
||||||
provider.getSubsearchResultSet(previousResults, terms);
|
}));
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
for (let i = 0; i < this._providers.length; i++) {
|
this._providers.forEach(Lang.bind(this, function(provider) {
|
||||||
let provider = this._providers[i];
|
provider.getInitialResultSet(terms, Lang.bind(this, this._gotResults, provider), this._cancellable);
|
||||||
results.push([provider, []]);
|
}));
|
||||||
provider.getInitialResultSet(terms);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -309,6 +305,8 @@ const SearchResultsBase = new Lang.Class({
|
|||||||
this.actor.add(separator.actor);
|
this.actor.add(separator.actor);
|
||||||
|
|
||||||
this._resultDisplays = {};
|
this._resultDisplays = {};
|
||||||
|
|
||||||
|
this._cancellable = new Gio.Cancellable();
|
||||||
},
|
},
|
||||||
|
|
||||||
destroy: function() {
|
destroy: function() {
|
||||||
@ -345,6 +343,9 @@ const SearchResultsBase = new Lang.Class({
|
|||||||
if (metasNeeded.length === 0) {
|
if (metasNeeded.length === 0) {
|
||||||
callback();
|
callback();
|
||||||
} else {
|
} else {
|
||||||
|
this._cancellable.cancel();
|
||||||
|
this._cancellable.reset();
|
||||||
|
|
||||||
this.provider.getResultMetas(metasNeeded, Lang.bind(this, function(metas) {
|
this.provider.getResultMetas(metasNeeded, Lang.bind(this, function(metas) {
|
||||||
metasNeeded.forEach(Lang.bind(this, function(resultId, i) {
|
metasNeeded.forEach(Lang.bind(this, function(resultId, i) {
|
||||||
let meta = metas[i];
|
let meta = metas[i];
|
||||||
@ -354,7 +355,7 @@ const SearchResultsBase = new Lang.Class({
|
|||||||
this._resultDisplays[resultId] = display;
|
this._resultDisplays[resultId] = display;
|
||||||
}));
|
}));
|
||||||
callback();
|
callback();
|
||||||
}));
|
}), this._cancellable);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -638,12 +639,11 @@ const SearchResults = new Lang.Class({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
_updateResults: function(searchSystem, results) {
|
_updateResults: function(searchSystem, provider, results) {
|
||||||
let terms = searchSystem.getTerms();
|
let terms = searchSystem.getTerms();
|
||||||
let [provider, providerResults] = results;
|
|
||||||
let display = provider.display;
|
let display = provider.display;
|
||||||
|
|
||||||
display.updateSearch(providerResults, terms, Lang.bind(this, function() {
|
display.updateSearch(results, terms, Lang.bind(this, function() {
|
||||||
this._maybeSetInitialSelection();
|
this._maybeSetInitialSelection();
|
||||||
this._updateStatusText();
|
this._updateStatusText();
|
||||||
}));
|
}));
|
||||||
|
Loading…
Reference in New Issue
Block a user