1
0
mirror of https://github.com/gryf/pentadactyl-pm.git synced 2025-12-30 13:02:26 +01:00

Fix some crufty old mode-change related bugginess.

This commit is contained in:
Kris Maglione
2010-10-04 14:17:13 -04:00
parent f141d3921b
commit af64937d55
7 changed files with 165 additions and 163 deletions

View File

@@ -224,15 +224,6 @@ const CommandLine = Module("commandline", {
////////////////////// TIMERS ////////////////////////////////////////////////// ////////////////////// TIMERS //////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////{{{ /////////////////////////////////////////////////////////////////////////////{{{
this._statusTimer = Timer(5, 100, function statusTell() {
if (self._completions == null)
return;
if (self._completions.selected == null)
statusline.updateProgress("");
else
statusline.updateProgress("match " + (self._completions.selected + 1) + " of " + self._completions.items.length);
});
this._autocompleteTimer = Timer(200, 500, function autocompleteTell(tabPressed) { this._autocompleteTimer = Timer(200, 500, function autocompleteTell(tabPressed) {
dactyl.trapErrors(function () { dactyl.trapErrors(function () {
if (!events.feedingKeys && self._completions && options["autocomplete"].length) { if (!events.feedingKeys && self._completions && options["autocomplete"].length) {
@@ -243,6 +234,15 @@ const CommandLine = Module("commandline", {
}); });
}); });
this._statusTimer = Timer(5, 100, function statusTell() {
if (self._completions == null)
return;
if (self._completions.selected == null)
statusline.progess = "";
else
statusline.progress = "match " + (self._completions.selected + 1) + " of " + self._completions.items.length;
});
// This timer just prevents <Tab>s from queueing up when the // This timer just prevents <Tab>s from queueing up when the
// system is under load (and, thus, giving us several minutes of // system is under load (and, thus, giving us several minutes of
// the completion list scrolling). Multiple <Tab> presses are // the completion list scrolling). Multiple <Tab> presses are
@@ -254,6 +254,8 @@ const CommandLine = Module("commandline", {
}); });
}); });
this._timers = [this._autocompleteTimer, this._statusTimer, this._tabTimer];
/////////////////////////////////////////////////////////////////////////////}}} /////////////////////////////////////////////////////////////////////////////}}}
////////////////////// VARIABLES /////////////////////////////////////////////// ////////////////////// VARIABLES ///////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////{{{ /////////////////////////////////////////////////////////////////////////////{{{
@@ -273,8 +275,7 @@ const CommandLine = Module("commandline", {
// we need to save the mode which were in before opening the command line // we need to save the mode which were in before opening the command line
// this is then used if we focus the command line again without the "official" // this is then used if we focus the command line again without the "official"
// way of calling "open" // way of calling "open"
this._currentExtendedMode = null; // the extended mode which we last openend the command line for this.currentExtendedMode = null; // the extended mode which we last openend the command line for
this._currentCommand = null;
// save the arguments for the inputMultiline method which are needed in the event handler // save the arguments for the inputMultiline method which are needed in the event handler
this._multilineEnd = null; this._multilineEnd = null;
@@ -374,6 +375,10 @@ const CommandLine = Module("commandline", {
dactyl.triggerObserver("echoMultiline", str, highlightGroup); dactyl.triggerObserver("echoMultiline", str, highlightGroup);
this._startHints = false;
if (!(modes.extended & modes.OUTPUT_MULTILINE))
modes.push(modes.COMMAND_LINE, modes.OUTPUT_MULTILINE);
// If it's already XML, assume it knows what it's doing. // If it's already XML, assume it knows what it's doing.
// Otherwise, white space is significant. // Otherwise, white space is significant.
// The problem elsewhere is that E4X tends to insert new lines // The problem elsewhere is that E4X tends to insert new lines
@@ -403,9 +408,6 @@ const CommandLine = Module("commandline", {
win.focus(); win.focus();
this._startHints = false;
if (!(modes.extended & modes.OUTPUT_MULTILINE))
modes.set(modes.COMMAND_LINE, modes.OUTPUT_MULTILINE);
commandline.updateMorePrompt(); commandline.updateMorePrompt();
}, },
@@ -483,12 +485,26 @@ const CommandLine = Module("commandline", {
} }
}, },
hideCompletions: function hideCompletions() { hideCompletions: function () {
for (let nodeSet in values([this.widgets.statusbar, this.widgets.commandbar])) for (let nodeSet in values([this.widgets.statusbar, this.widgets.commandbar]))
if (nodeSet.commandline._completionList) if (nodeSet.commandline._completionList)
nodeSet.commandline._completionList.hide(); nodeSet.commandline._completionList.hide();
}, },
currentExtendedMode: Modes.boundProperty(),
_keepCommand: Modes.boundProperty(),
multilineInputVisible: Modes.boundProperty({
set: function (value) {
this.widgets.multilineInput.collapsed = !value;
}
}),
multilineOutputVisible: Modes.boundProperty({
set: function (value) {
this.widgets.mowContainer.collapsed = !value;
}
}),
/** /**
* Open the command line. The main mode is set to * Open the command line. The main mode is set to
* COMMAND_LINE, the extended mode to <b>extendedMode</b>. * COMMAND_LINE, the extended mode to <b>extendedMode</b>.
@@ -500,13 +516,14 @@ const CommandLine = Module("commandline", {
* @param {number} extendedMode * @param {number} extendedMode
*/ */
open: function open(prompt, cmd, extendedMode) { open: function open(prompt, cmd, extendedMode) {
// save the current prompts, we need it later if the command widget modes.push(modes.COMMAND_LINE, this.currentExtendedMode, {
// receives focus without calling the this.open() method leave: function (newMode) {
this._currentCommand = cmd || ""; commandline.leave(newMode);
this._currentExtendedMode = extendedMode || null; }
this._keepCommand = false; });
modes.set(modes.COMMAND_LINE, this._currentExtendedMode); this.currentExtendedMode = extendedMode || null;
this._keepCommand = false;
this.widgets.active.commandline.collapsed = false; this.widgets.active.commandline.collapsed = false;
this.widgets.prompt = prompt; this.widgets.prompt = prompt;
@@ -517,44 +534,27 @@ const CommandLine = Module("commandline", {
// open the completion list automatically if wanted // open the completion list automatically if wanted
if (cmd.length) if (cmd.length)
commandline.triggerCallback("change", this._currentExtendedMode, cmd); commandline.triggerCallback("change", this.currentExtendedMode, cmd);
}, },
/** /**
* Closes the command line. This is ordinarily triggered automatically * Called when leaving a command-line mode.
* by a mode change. Will not hide the command line immediately if
* called directly after a successful command, otherwise it will.
*/ */
close: function close() { leave: function leave() {
let mode = this._currentExtendedMode; commandline.triggerCallback("cancel", this.currentExtendedMode);
this._currentExtendedMode = null;
commandline.triggerCallback("cancel", mode);
this._timers.forEach(function (timer) timer.reset());
if (this._completions) if (this._completions)
this._completions.previewClear(); this._completions.previewClear();
if (this._history) if (this._history)
this._history.save(); this._history.save();
this.resetCompletions(); // cancels any asynchronous completion still going on, must be before we set completions = null this.resetCompletions(); // cancels any asynchronous completion still going on, must be before we set completions = null
this._completions = null;
this._history = null;
statusline.updateProgress(""); // we may have a "match x of y" visible
dactyl.focusContent(false);
this.widgets.multilineInput.collapsed = true;
this.hideCompletions(); this.hideCompletions();
if (!this._keepCommand || this._silent || this._quiet) { if (!this._keepCommand || this._silent || this._quiet) {
this.widgets.mowContainer.collapsed = true;
commandline.updateMorePrompt(); commandline.updateMorePrompt();
this.hide(); this.hide();
} }
if (!this.widgets.mowContainer.collapsed) {
modes.set(modes.COMMAND_LINE, modes.OUTPUT_MULTILINE);
commandline.updateMorePrompt();
}
this._keepCommand = false;
}, },
get command() { get command() {
@@ -573,6 +573,8 @@ const CommandLine = Module("commandline", {
this.widgets.message = null; this.widgets.message = null;
if (modes.main != modes.COMMAND_LINE) if (modes.main != modes.COMMAND_LINE)
this.widgets.command = null; this.widgets.command = null;
if (modes.extended != modes.OUTPUT_MULTILINE)
this.multilineOutputVisible = false;
}, },
/** /**
@@ -689,8 +691,16 @@ const CommandLine = Module("commandline", {
cancel: extra.onCancel cancel: extra.onCancel
}; };
modes.push(modes.COMMAND_LINE, modes.PROMPT); modes.push(modes.COMMAND_LINE, modes.PROMPT | extra.extended, {
this._currentExtendedMode = modes.PROMPT; leave: function (newMode) {
commandline.leave(newMode);
if (extra.leave)
extra.leave(newMode);
},
restore: function (newMode) { extra.restore && extra.restore(newMode) },
save: function (newMode) { extra.save && extra.save(newMode) }
});
this.currentExtendedMode = modes.PROMPT;
this.widgets.prompt = !prompt ? null : [extra.promptHighlight || "Question", prompt]; this.widgets.prompt = !prompt ? null : [extra.promptHighlight || "Question", prompt];
this.widgets.command = extra.default || ""; this.widgets.command = extra.default || "";
@@ -728,7 +738,7 @@ const CommandLine = Module("commandline", {
this._multilineEnd = "\n" + end + "\n"; this._multilineEnd = "\n" + end + "\n";
this._multilineCallback = callbackFunc; this._multilineCallback = callbackFunc;
this.widgets.multilineInput.collapsed = false; this.multilineInputVisible = true;
this.widgets.multilineInput.value = ""; this.widgets.multilineInput.value = "";
this._autosizeMultilineInputWidget(); this._autosizeMultilineInputWidget();
@@ -762,22 +772,22 @@ const CommandLine = Module("commandline", {
} }
else if (event.type == "input") { else if (event.type == "input") {
this.resetCompletions(); this.resetCompletions();
commandline.triggerCallback("change", this._currentExtendedMode, command); commandline.triggerCallback("change", this.currentExtendedMode, command);
} }
else if (event.type == "keypress") { else if (event.type == "keypress") {
let key = events.toString(event); let key = events.toString(event);
if (this._completions) if (this._completions)
this._completions.previewClear(); this._completions.previewClear();
if (!this._currentExtendedMode) if (!this.currentExtendedMode)
return; return;
// user pressed <Enter> to carry out a command // user pressed <Enter> to carry out a command
// user pressing <Esc> is handled in the global onEscape // user pressing <Esc> is handled in the global onEscape
// FIXME: <Esc> should trigger "cancel" event // FIXME: <Esc> should trigger "cancel" event
if (events.isAcceptKey(key)) { if (events.isAcceptKey(key)) {
let mode = this._currentExtendedMode; // save it here, as modes.pop() resets it
this._keepCommand = userContext.hidden_option_command_afterimage; this._keepCommand = userContext.hidden_option_command_afterimage;
this._currentExtendedMode = null; // Don't let modes.pop trigger "cancel" let mode = this.currentExtendedMode;
this.currentExtendedMode = null; // Don't let modes.pop trigger "cancel"
modes.pop(); modes.pop();
commandline.triggerCallback("submit", mode, command); commandline.triggerCallback("submit", mode, command);
} }
@@ -804,7 +814,7 @@ const CommandLine = Module("commandline", {
// and blur the command line if there is no text left // and blur the command line if there is no text left
if (command.length == 0) { if (command.length == 0) {
commandline.triggerCallback("cancel", this._currentExtendedMode); commandline.triggerCallback("cancel", this.currentExtendedMode);
modes.pop(); modes.pop();
} }
} }
@@ -838,14 +848,13 @@ const CommandLine = Module("commandline", {
let index = text.indexOf(this._multilineEnd); let index = text.indexOf(this._multilineEnd);
if (index >= 0) { if (index >= 0) {
text = text.substring(1, index); text = text.substring(1, index);
let callback = this._multilineCallback;
modes.pop(); modes.pop();
this.widgets.multilineInput.collapsed = true; callback.call(this, text);
this._multilineCallback.call(this, text);
} }
} }
else if (events.isCancelKey(key)) { else if (events.isCancelKey(key)) {
modes.pop(); modes.pop();
this.widgets.multilineInput.collapsed = true;
} }
} }
else if (event.type == "blur") { else if (event.type == "blur") {
@@ -1117,7 +1126,7 @@ const CommandLine = Module("commandline", {
0); 0);
doc.body.style.minWidth = ""; doc.body.style.minWidth = "";
this.widgets.mowContainer.collapsed = false; this.multilineOutputVisible = true;
}, },
resetCompletions: function resetCompletions() { resetCompletions: function resetCompletions() {
@@ -1185,7 +1194,7 @@ const CommandLine = Module("commandline", {
*/ */
replace: function (val) { replace: function (val) {
this.input.value = val; this.input.value = val;
commandline.triggerCallback("change", commandline._currentExtendedMode, val, "history"); commandline.triggerCallback("change", commandline.currentExtendedMode, val, "history");
}, },
/** /**
@@ -1299,7 +1308,7 @@ const CommandLine = Module("commandline", {
complete: function complete(show, tabPressed) { complete: function complete(show, tabPressed) {
this.context.reset(); this.context.reset();
this.context.tabPressed = tabPressed; this.context.tabPressed = tabPressed;
commandline.triggerCallback("complete", commandline._currentExtendedMode, this.context); commandline.triggerCallback("complete", commandline.currentExtendedMode, this.context);
this.context.updateAsync = true; this.context.updateAsync = true;
this.reset(show, tabPressed); this.reset(show, tabPressed);
this.wildIndex = 0; this.wildIndex = 0;

View File

@@ -46,6 +46,7 @@
"modules", "modules",
"storage", "storage",
"util", "util",
"modes",
"abbreviations", "abbreviations",
"autocommands", "autocommands",
"buffer", "buffer",
@@ -64,7 +65,6 @@
"javascript", "javascript",
"mappings", "mappings",
"marks", "marks",
"modes",
"options", "options",
"statusline", "statusline",
"styles", "styles",

View File

@@ -16,6 +16,28 @@ const Editor = Module("editor", {
// //
this._lastFindChar = null; this._lastFindChar = null;
this._lastFindCharFunc = null; this._lastFindCharFunc = null;
// Hack?
dactyl.registerObserver("modeChange", function (oldMode, newMode, stack) {
switch (oldMode[0]) {
case modes.TEXTAREA:
case modes.INSERT:
editor.unselectText();
break;
case modes.VISUAL:
if (newMode[0] == modes.CARET) {
try { // clear any selection made; a simple if (selection) does not work
let selection = window.content.getSelection();
selection.collapseToStart();
}
catch (e) {}
}
else
editor.unselectText();
break;
}
});
}, },
line: function () { line: function () {

View File

@@ -753,7 +753,11 @@ const Hints = Module("hints", {
this._hintMode = this._hintModes[minor]; this._hintMode = this._hintModes[minor];
dactyl.assert(this._hintMode); dactyl.assert(this._hintMode);
commandline.input(this._hintMode.prompt + ": ", null, { onChange: this.closure._onInput }); commandline.input(this._hintMode.prompt + ": ", null, {
extended: modes.HINTS,
leave: function () { hints.hide(); },
onChange: this.closure._onInput
});
modes.extended = modes.HINTS; modes.extended = modes.HINTS;
this.hintKeys = events.fromString(options["hintkeys"]).map(events.closure.toString); this.hintKeys = events.fromString(options["hintkeys"]).map(events.closure.toString);

View File

@@ -50,6 +50,17 @@ const Modes = Module("modes", {
this.addMode("MENU", true); // a popupmenu is active this.addMode("MENU", true); // a popupmenu is active
this.addMode("LINE", true); // linewise visual mode this.addMode("LINE", true); // linewise visual mode
this.addMode("PROMPT", true); this.addMode("PROMPT", true);
this.push(this.NORMAL, 0, {
restore: function (prev) {
// disable caret mode when we want to switch to normal mode
if (options.getPref("accessibility.browsewithcaret"))
options.setPref("accessibility.browsewithcaret", false);
statusline.updateUrl();
dactyl.focusContent(true);
}
});
}, },
_getModeMessage: function () { _getModeMessage: function () {
@@ -75,52 +86,6 @@ const Modes = Module("modes", {
return macromode; return macromode;
}, },
// NOTE: Pay attention that you don't run into endless loops
// Usually you should only indicate to leave a special mode like HINTS
// by calling modes.reset() and adding the stuff which is needed
// for its cleanup here
_handleModeChange: function (oldMode, newMode, oldExtended) {
switch (oldMode) {
case modes.TEXTAREA:
case modes.INSERT:
editor.unselectText();
break;
case modes.VISUAL:
if (newMode == modes.CARET) {
try { // clear any selection made; a simple if (selection) does not work
let selection = window.content.getSelection();
selection.collapseToStart();
}
catch (e) {}
}
else
editor.unselectText();
break;
case modes.CUSTOM:
plugins.stop();
break;
case modes.COMMAND_LINE:
// clean up for HINT mode
if (oldExtended & modes.HINTS)
hints.hide();
commandline.close();
break;
}
if (newMode == modes.NORMAL) {
// disable caret mode when we want to switch to normal mode
if (options.getPref("accessibility.browsewithcaret"))
options.setPref("accessibility.browsewithcaret", false);
statusline.updateUrl();
dactyl.focusContent(true);
}
},
NONE: 0, NONE: 0,
__iterator__: function () array.iterValues(this.all), __iterator__: function () array.iterValues(this.all),
@@ -188,21 +153,27 @@ const Modes = Module("modes", {
// helper function to set both modes in one go // helper function to set both modes in one go
// if silent == true, you also need to take care of the mode handling changes yourself // if silent == true, you also need to take care of the mode handling changes yourself
set: function (mainMode, extendedMode, silent, stack) { set: function (mainMode, extendedMode, params, stack) {
params = params || {};
if (!stack && mainMode != null) if (!stack && mainMode != null)
this._modeStack = []; this.reset();
let push = mainMode != null && !(stack && stack.pop) &&
Modes.StackElem(mainMode, extendedMode || this.NONE, params, {});
if (push && this.topOfStack) {
if (this.topOfStack.params.save)
this.topOfStack.params.save(push);
let push = mainMode != null && !(stack && stack.pop);
if (push && this.topOfStack)
for (let [id, { obj, prop }] in Iterator(this.boundProperties)) { for (let [id, { obj, prop }] in Iterator(this.boundProperties)) {
if (!obj.get()) if (!obj.get())
delete this.boundProperties(id); delete this.boundProperties(id);
else else
this.topOfStack[2][id] = { obj: obj.get(), prop: prop, value: obj.get()[prop] }; this.topOfStack.saved[id] = { obj: obj.get(), prop: prop, value: obj.get()[prop] };
} }
}
silent = (silent || this._main == mainMode && this._extended == extendedMode); let silent = this._main === mainMode && this._extended === extendedMode;
// if a this._main mode is set, the this._extended is always cleared // if a this._main mode is set, the this._extended is always cleared
let oldMain = this._main, oldExtended = this._extended; let oldMain = this._main, oldExtended = this._extended;
@@ -211,50 +182,38 @@ const Modes = Module("modes", {
if (typeof mainMode === "number") { if (typeof mainMode === "number") {
this._main = mainMode; this._main = mainMode;
if (!extendedMode) if (!extendedMode)
this._extended = modes.NONE; this._extended = this.NONE;
if (this._main != oldMain)
this._handleModeChange(oldMain, mainMode, oldExtended);
} }
if (mainMode != null && !(stack && stack.pop))
this._modeStack.push([this._main, this._extended, {}]); if (push)
this._modeStack.push(push);
dactyl.triggerObserver("modeChange", [oldMain, oldExtended], [this._main, this._extended], stack); dactyl.triggerObserver("modeChange", [oldMain, oldExtended], [this._main, this._extended], stack);
if (!silent) if (!silent)
this.show(); this.show();
}, },
push: function (mainMode, extendedMode, silent) { push: function (mainMode, extendedMode, params) {
this.set(mainMode, extendedMode, silent, { push: this.topOfStack }); this.set(mainMode, extendedMode, params, { push: this.topOfStack });
}, },
pop: function (silent) { pop: function () {
let a = this._modeStack.pop(); let a = this._modeStack.pop();
if (!this.topOfStack) if (a.params.leave)
this.reset(silent); a.params.leave(this.topOfStack);
else {
this.set(this.topOfStack[0], this.topOfStack[1], silent, { pop: a }); this.set(this.topOfStack.main, this.topOfStack.extended, this.topOfStack.params, { pop: a });
for (let [k, { obj, prop, value }] in Iterator(this.topOfStack[2])) if (this.topOfStack.params.restore)
obj[prop] = value; this.topOfStack.params.restore(a);
}
for (let [k, { obj, prop, value }] in Iterator(this.topOfStack.saved))
obj[prop] = value;
}, },
// TODO: Deprecate this in favor of addMode? --Kris reset: function () {
// Ya --djk while (this._modeStack.length > 1)
setCustomMode: function (modestr, oneventfunc, stopfunc) { this.pop();
// TODO this.plugin[id]... ('id' maybe submode or what..)
plugins.mode = modestr;
plugins.onEvent = oneventfunc;
plugins.stop = stopfunc;
},
// keeps recording state
reset: function (silent) {
this._modeStack = [];
if (config.isComposeWindow)
this.set(modes.COMPOSE, modes.NONE, silent);
else
this.set(modes.NORMAL, modes.NONE, silent);
}, },
remove: function (mode) { remove: function (mode) {
@@ -282,8 +241,10 @@ const Modes = Module("modes", {
get extended() this._extended, get extended() this._extended,
set extended(value) { this.set(null, value); } set extended(value) { this.set(null, value); }
}, { }, {
StackElem: Struct("main", "extended", "params", "saved"),
cacheId: 0, cacheId: 0,
boundProperty: function boundProperty(desc) { boundProperty: function boundProperty(desc) {
desc = desc || {};
let id = this.cacheId++, value; let id = this.cacheId++, value;
return Class.Property(update({ return Class.Property(update({
enumerable: true, enumerable: true,
@@ -295,8 +256,9 @@ const Modes = Module("modes", {
return val === undefined ? value : val; return val === undefined ? value : val;
}, },
set: function (val) { set: function (val) {
value = desc.set.call(this, val); if (desc.set)
value = value === undefined ? val : value; value = desc.set.call(this, val);
value = !desc.set || value === undefined ? val : value;
modes.save(id, this, prop) modes.save(id, this, prop)
} }
}) })

View File

@@ -169,26 +169,31 @@ const StatusLine = Module("statusline", {
* A number n <= 0 - Displayed as a "Loading" message. * A number n <= 0 - Displayed as a "Loading" message.
* Any other number - The progress is cleared. * Any other number - The progress is cleared.
*/ */
updateProgress: function updateProgress(progress) { progress: Modes.boundProperty({
if (!progress) set: function setProgress(progress) {
progress = ""; if (!progress)
progress = "";
if (typeof progress == "string") if (typeof progress == "string")
this.widgets.progress.value = progress; this.widgets.progress.value = progress;
else if (typeof progress == "number") { else if (typeof progress == "number") {
let progressStr = ""; let progressStr = "";
if (progress <= 0) if (progress <= 0)
progressStr = "[ Loading... ]"; progressStr = "[ Loading... ]";
else if (progress < 1) { else if (progress < 1) {
progress = Math.floor(progress * 20); progress = Math.floor(progress * 20);
progressStr = "[" progressStr = "["
+ "====================".substr(0, progress) + "====================".substr(0, progress)
+ ">" + ">"
+ " ".substr(0, 19 - progress) + " ".substr(0, 19 - progress)
+ "]"; + "]";
}
this.widgets.progress.value = progressStr;
} }
this.widgets.progress.value = progressStr;
} }
}),
updateProgress: function updateProgress(progress) {
this.progress = progress;
}, },
/** /**

View File

@@ -779,7 +779,7 @@ Class.prototype = {
const self = this; const self = this;
let notify = { notify: function notify(timer) { callback.call(self) } }; let notify = { notify: function notify(timer) { callback.call(self) } };
let timer = services.create("timer"); let timer = services.create("timer");
timer.initWithCallback(notify, timeout, timer.TYPE_ONE_SHOT); timer.initWithCallback(notify, timeout || 0, timer.TYPE_ONE_SHOT);
return timer; return timer;
} }
}; };