From 40d9ed535b58daf7d69b5ef5310042a655d3cd01 Mon Sep 17 00:00:00 2001 From: "Jasper St. Pierre" Date: Wed, 6 Mar 2013 21:10:41 -0500 Subject: [PATCH] runDialog: Remove the use of file monitors for file completion Launching the run dialog to open the looking glass or something like that shouldn't install a bunch of file monitors that monitor every IO change to the home and system directories. Instead, simply scan all the paths when trying to complete. https://bugzilla.gnome.org/show_bug.cgi?id=695338 --- js/ui/runDialog.js | 172 ++++++++++----------------------------------- 1 file changed, 37 insertions(+), 135 deletions(-) diff --git a/js/ui/runDialog.js b/js/ui/runDialog.js index f35b557c2..bedea40f8 100644 --- a/js/ui/runDialog.js +++ b/js/ui/runDialog.js @@ -30,138 +30,6 @@ const EXEC_ARG_KEY = 'exec-arg'; const DIALOG_GROW_TIME = 0.1; -const CommandCompleter = new Lang.Class({ - Name: 'CommandCompleter', - - _init : function() { - this._changedCount = 0; - this._paths = GLib.getenv('PATH').split(':'); - this._paths.push(GLib.get_home_dir()); - this._valid = false; - this._updateInProgress = false; - this._childs = new Array(this._paths.length); - this._monitors = new Array(this._paths.length); - for (let i = 0; i < this._paths.length; i++) { - this._childs[i] = []; - let file = Gio.file_new_for_path(this._paths[i]); - let info; - try { - info = file.query_info(Gio.FILE_ATTRIBUTE_STANDARD_TYPE, Gio.FileQueryInfoFlags.NONE, null); - } catch (e) { - // FIXME catchall - this._paths[i] = null; - continue; - } - - if (info.get_attribute_uint32(Gio.FILE_ATTRIBUTE_STANDARD_TYPE) != Gio.FileType.DIRECTORY) - continue; - - this._paths[i] = file.get_path(); - this._monitors[i] = file.monitor_directory(Gio.FileMonitorFlags.NONE, null); - if (this._monitors[i] != null) { - this._monitors[i].connect('changed', Lang.bind(this, this._onChanged)); - } - } - this._paths = this._paths.filter(function(a) { - return a != null; - }); - this._update(0); - }, - - update : function() { - if (this._valid) - return; - this._update(0); - }, - - _update : function(i) { - if (i == 0 && this._updateInProgress) - return; - this._updateInProgress = true; - this._changedCount = 0; - this._i = i; - if (i >= this._paths.length) { - this._valid = true; - this._updateInProgress = false; - return; - } - let file = Gio.file_new_for_path(this._paths[i]); - this._childs[this._i] = []; - FileUtils.listDirAsync(file, Lang.bind(this, function (files) { - for (let i = 0; i < files.length; i++) { - this._childs[this._i].push(files[i].get_name()); - } - this._update(this._i + 1); - })); - }, - - _onChanged : function(m, f, of, type) { - if (!this._valid) - return; - let path = f.get_parent().get_path(); - let k = undefined; - for (let i = 0; i < this._paths.length; i++) { - if (this._paths[i] == path) - k = i; - } - if (k === undefined) { - return; - } - if (type == Gio.FileMonitorEvent.CREATED) { - this._childs[k].push(f.get_basename()); - } - if (type == Gio.FileMonitorEvent.DELETED) { - this._changedCount++; - if (this._changedCount > MAX_FILE_DELETED_BEFORE_INVALID) { - this._valid = false; - } - let name = f.get_basename(); - this._childs[k] = this._childs[k].filter(function(e) { - return e != name; - }); - } - if (type == Gio.FileMonitorEvent.UNMOUNTED) { - this._childs[k] = []; - } - }, - - getCompletion: function(text) { - let common = ''; - let notInit = true; - if (!this._valid) { - this._update(0); - return common; - } - function _getCommon(s1, s2) { - let k = 0; - for (; k < s1.length && k < s2.length; k++) { - if (s1[k] != s2[k]) - break; - } - if (k == 0) - return ''; - return s1.substr(0, k); - } - function _hasPrefix(s1, prefix) { - return s1.indexOf(prefix) == 0; - } - for (let i = 0; i < this._childs.length; i++) { - for (let k = 0; k < this._childs[i].length; k++) { - if (!_hasPrefix(this._childs[i][k], text)) - continue; - if (notInit) { - common = this._childs[i][k]; - notInit = false; - } - common = _getCommon(common, this._childs[i][k]); - } - } - if (common.length) - return common.substr(text.length); - return common; - } -}); - const RunDialog = new Lang.Class({ Name: 'RunDialog', Extends: ModalDialog.ModalDialog, @@ -242,8 +110,6 @@ const RunDialog = new Lang.Class({ key: Clutter.Escape }]); this._pathCompleter = new Gio.FilenameCompleter(); - this._commandCompleter = new CommandCompleter(); - this._group.connect('notify::visible', Lang.bind(this._commandCompleter, this._commandCompleter.update)); this._history = new History.HistoryManager({ gsettingsKey: HISTORY_KEY, entry: this._entryText }); @@ -277,11 +143,47 @@ const RunDialog = new Lang.Class({ })); }, + _getCommandCompletion: function(text) { + function _getCommon(s1, s2) { + if (s1 == null) + return s2; + + let k = 0; + for (; k < s1.length && k < s2.length; k++) { + if (s1[k] != s2[k]) + break; + } + if (k == 0) + return ''; + return s1.substr(0, k); + } + + let paths = GLib.getenv('PATH').split(':'); + paths.push(GLib.get_home_dir()); + let someResults = paths.map(function(path) { + let file = Gio.File.new_for_path(path); + let fileEnum = file.enumerate_children('standard::name', Gio.FileQueryInfoFlags.NONE, null); + let info; + let results = []; + while ((info = fileEnum.next_file(null))) { + let name = info.get_name(); + if (name.slice(0, text.length) == text) + results.push(name); + } + return results; + }); + let results = someResults.reduce(function(a, b) { + return a.concat(b); + }, []); + let common = results.reduce(_getCommon, null); + return common.substr(text.length); + }, + _getCompletion : function(text) { if (text.indexOf('/') != -1) { return this._pathCompleter.get_completion_suffix(text); } else { - return this._commandCompleter.getCompletion(text); + return this._getCommandCompletion(text); } },