mirror of
https://github.com/gryf/pentadactyl-pm.git
synced 2026-01-06 21:24:48 +01:00
Recfactoring:
* Standard module format. All modules are explicitly declared as modules, they're created via a constructor and instantiated automatically. They're dependency aware. They stringify properly. * Classes are declared the same way (rather like Structs already were). They also stringify properly. Plus, each instance has a rather nifty closure member that closes all of its methods around 'this', so you can pass them to map, forEach, setTimeout, etc. Modules are themselves classes, with a special metaclass, as it were. * Doug Crockford is dead, metaphorically speaking. Closure-based classes just don't fit into any of the common JavaScript frameworks, and they're inefficient and confusing. Now, all class and module members are accessed explicitly via 'this', which makes it very clear that they're class members and not (e.g.) local variables, without anything nasty like Hungarian notation. * Strictly one module per file. Classes that belong to a module live in the same file. * For the moment, there are quite a few utility functions sitting in base.c, because my class implementation used them, and I haven't had the time or inclination to sort them out. I plan to reconcile them with the current mess that is the util namespace. * Changed bracing style.
This commit is contained in:
@@ -5,29 +5,55 @@
|
||||
|
||||
/** @scope modules */
|
||||
|
||||
const modes = (function () //{{{
|
||||
{
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
////////////////////// PRIVATE SECTION /////////////////////////////////////////
|
||||
/////////////////////////////////////////////////////////////////////////////{{{
|
||||
const Modes = Module("modes", {
|
||||
requires: ["util"],
|
||||
|
||||
var main = 1; // NORMAL
|
||||
var extended = 0; // NONE
|
||||
init: function () {
|
||||
this._main = 1; // NORMAL
|
||||
this._extended = 0; // NONE
|
||||
|
||||
var lastShown = null;
|
||||
this._lastShown = null;
|
||||
|
||||
var passNextKey = false;
|
||||
var passAllKeys = false;
|
||||
var isRecording = false;
|
||||
var isReplaying = false; // playing a macro
|
||||
this._passNextKey = false;
|
||||
this._passAllKeys = false;
|
||||
this._isRecording = false;
|
||||
this._isReplaying = false; // playing a macro
|
||||
|
||||
var modeStack = [];
|
||||
this._modeStack = [];
|
||||
|
||||
function getModeMessage()
|
||||
{
|
||||
if (passNextKey && !passAllKeys)
|
||||
this._mainModes = [self.NONE];
|
||||
this._lastMode = 0;
|
||||
this._modeMap = {};
|
||||
|
||||
// main modes, only one should ever be active
|
||||
this.addMode("NORMAL", { char: "n", display: -1 });
|
||||
this.addMode("INSERT", { char: "i", input: true });
|
||||
this.addMode("VISUAL", { char: "v", display: function () "VISUAL" + (this._extended & modes.LINE ? " LINE" : "") });
|
||||
this.addMode("COMMAND_LINE", { char: "c", input: true });
|
||||
this.addMode("CARET"); // text cursor is visible
|
||||
this.addMode("TEXTAREA", { char: "i" });
|
||||
this.addMode("EMBED", { input: true });
|
||||
this.addMode("CUSTOM", { display: function () plugins.mode });
|
||||
// this._extended modes, can include multiple modes, and even main modes
|
||||
this.addMode("EX", true);
|
||||
this.addMode("HINTS", true);
|
||||
this.addMode("INPUT_MULTILINE", true);
|
||||
this.addMode("OUTPUT_MULTILINE", true);
|
||||
this.addMode("SEARCH_FORWARD", true);
|
||||
this.addMode("SEARCH_BACKWARD", true);
|
||||
this.addMode("SEARCH_VIEW_FORWARD", true);
|
||||
this.addMode("SEARCH_VIEW_BACKWARD", true);
|
||||
this.addMode("MENU", true); // a popupmenu is active
|
||||
this.addMode("LINE", true); // linewise visual mode
|
||||
this.addMode("PROMPT", true);
|
||||
|
||||
config.modes.forEach(function (mode) { this.addMode.apply(this, mode); }, this);
|
||||
},
|
||||
|
||||
_getModeMessage: function () {
|
||||
if (this._passNextKey && !this._passAllKeys)
|
||||
return "-- PASS THROUGH (next) --";
|
||||
else if (passAllKeys && !passNextKey)
|
||||
else if (this._passAllKeys && !this._passNextKey)
|
||||
return "-- PASS THROUGH --";
|
||||
|
||||
// when recording a macro
|
||||
@@ -38,57 +64,52 @@ const modes = (function () //{{{
|
||||
macromode = "replaying";
|
||||
|
||||
let ext = "";
|
||||
if (extended & modes.MENU) // TODO: desirable?
|
||||
if (this._extended & modes.MENU) // TODO: desirable?
|
||||
ext += " (menu)";
|
||||
ext += " --" + macromode;
|
||||
|
||||
if (main in modeMap && typeof modeMap[main].display == "function")
|
||||
return "-- " + modeMap[main].display() + ext;
|
||||
if (this._main in this._modeMap && typeof this._modeMap[this._main].display == "function")
|
||||
return "-- " + this._modeMap[this._main].display() + ext;
|
||||
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
|
||||
function handleModeChange(oldMode, newMode, oldExtended)
|
||||
{
|
||||
_handleModeChange: function (oldMode, newMode, oldExtended) {
|
||||
|
||||
switch (oldMode)
|
||||
{
|
||||
case modes.TEXTAREA:
|
||||
case modes.INSERT:
|
||||
editor.unselectText();
|
||||
break;
|
||||
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) {}
|
||||
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();
|
||||
}
|
||||
else
|
||||
editor.unselectText();
|
||||
break;
|
||||
catch (e) {}
|
||||
}
|
||||
else
|
||||
editor.unselectText();
|
||||
break;
|
||||
|
||||
case modes.CUSTOM:
|
||||
plugins.stop();
|
||||
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;
|
||||
case modes.COMMAND_LINE:
|
||||
// clean up for HINT mode
|
||||
if (oldExtended & modes.HINTS)
|
||||
hints.hide();
|
||||
commandline.close();
|
||||
break;
|
||||
}
|
||||
|
||||
if (newMode == modes.NORMAL)
|
||||
{
|
||||
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);
|
||||
@@ -96,185 +117,134 @@ const modes = (function () //{{{
|
||||
statusline.updateUrl();
|
||||
liberator.focusContent(true);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////}}}
|
||||
////////////////////// PUBLIC SECTION //////////////////////////////////////////
|
||||
/////////////////////////////////////////////////////////////////////////////{{{
|
||||
NONE: 0,
|
||||
|
||||
const self = {
|
||||
__iterator__: function () util.Array.itervalues(this.all),
|
||||
|
||||
NONE: 0,
|
||||
get all() this._mainModes.slice(),
|
||||
|
||||
__iterator__: function () util.Array.itervalues(this.all),
|
||||
get mainModes() (mode for ([k, mode] in Iterator(modes._modeMap)) if (!mode.extended && mode.name == k)),
|
||||
|
||||
get all() mainModes.slice(),
|
||||
get mainMode() this._modeMap[this._main],
|
||||
|
||||
get mainModes() (mode for ([k, mode] in Iterator(modeMap)) if (!mode.extended && mode.name == k)),
|
||||
addMode: function (name, extended, options) {
|
||||
let disp = name.replace("_", " ", "g");
|
||||
this[name] = 1 << this._lastMode++;
|
||||
if (typeof extended == "object") {
|
||||
options = extended;
|
||||
extended = false;
|
||||
}
|
||||
this._modeMap[name] = this._modeMap[this[name]] = util.extend({
|
||||
extended: extended,
|
||||
count: true,
|
||||
input: false,
|
||||
mask: this[name],
|
||||
name: name,
|
||||
disp: disp
|
||||
}, options);
|
||||
this._modeMap[name].display = this._modeMap[name].display || function () disp;
|
||||
if (!extended)
|
||||
this._mainModes.push(this[name]);
|
||||
if ("mappings" in modules)
|
||||
mappings.addMode(this[name]);
|
||||
},
|
||||
|
||||
get mainMode() modeMap[main],
|
||||
getMode: function (name) this._modeMap[name],
|
||||
|
||||
addMode: function (name, extended, options)
|
||||
{
|
||||
let disp = name.replace("_", " ", "g");
|
||||
this[name] = 1 << lastMode++;
|
||||
if (typeof extended == "object")
|
||||
{
|
||||
options = extended;
|
||||
extended = false;
|
||||
}
|
||||
modeMap[name] = modeMap[this[name]] = util.extend({
|
||||
extended: extended,
|
||||
count: true,
|
||||
input: false,
|
||||
mask: this[name],
|
||||
name: name,
|
||||
disp: disp
|
||||
}, options);
|
||||
modeMap[name].display = modeMap[name].display || function () disp;
|
||||
if (!extended)
|
||||
mainModes.push(this[name]);
|
||||
if ("mappings" in modules)
|
||||
mappings.addMode(this[name]);
|
||||
},
|
||||
// show the current mode string in the command line
|
||||
show: function () {
|
||||
let msg = "";
|
||||
if (options["showmode"])
|
||||
msg = this._getModeMessage();
|
||||
|
||||
getMode: function (name) modeMap[name],
|
||||
commandline.echo(msg, "ModeMsg", commandline.FORCE_SINGLELINE);
|
||||
},
|
||||
|
||||
// show the current mode string in the command line
|
||||
show: function ()
|
||||
{
|
||||
let msg = "";
|
||||
if (options["showmode"])
|
||||
msg = getModeMessage();
|
||||
// add/remove always work on the this._extended mode only
|
||||
add: function (mode) {
|
||||
this._extended |= mode;
|
||||
this.show();
|
||||
},
|
||||
|
||||
commandline.echo(msg, "ModeMsg", commandline.FORCE_SINGLELINE);
|
||||
},
|
||||
// helper function to set both modes in one go
|
||||
// if silent == true, you also need to take care of the mode handling changes yourself
|
||||
set: function (mainMode, extendedMode, silent, stack) {
|
||||
silent = (silent || this._main == mainMode && this._extended == extendedMode);
|
||||
// if a this._main mode is set, the this._extended is always cleared
|
||||
let oldMain = this._main, oldExtended = this._extended;
|
||||
if (typeof extendedMode === "number")
|
||||
this._extended = extendedMode;
|
||||
if (typeof mainMode === "number") {
|
||||
this._main = mainMode;
|
||||
if (!extendedMode)
|
||||
this._extended = modes.NONE;
|
||||
|
||||
// add/remove always work on the extended mode only
|
||||
add: function (mode)
|
||||
{
|
||||
extended |= mode;
|
||||
if (this._main != oldMain)
|
||||
this._handleModeChange(oldMain, mainMode, oldExtended);
|
||||
}
|
||||
liberator.triggerObserver("modeChange", [oldMain, oldExtended], [this._main, this._extended], stack);
|
||||
|
||||
if (!silent)
|
||||
this.show();
|
||||
},
|
||||
},
|
||||
|
||||
// helper function to set both modes in one go
|
||||
// if silent == true, you also need to take care of the mode handling changes yourself
|
||||
set: function (mainMode, extendedMode, silent, stack)
|
||||
{
|
||||
silent = (silent || main == mainMode && extended == extendedMode);
|
||||
// if a main mode is set, the extended is always cleared
|
||||
let oldMain = main, oldExtended = extended;
|
||||
if (typeof extendedMode === "number")
|
||||
extended = extendedMode;
|
||||
if (typeof mainMode === "number")
|
||||
{
|
||||
main = mainMode;
|
||||
if (!extendedMode)
|
||||
extended = modes.NONE;
|
||||
push: function (mainMode, extendedMode, silent) {
|
||||
this._modeStack.push([this._main, this._extended]);
|
||||
this.set(mainMode, extendedMode, silent, { push: this._modeStack[this._modeStack.length - 1] });
|
||||
},
|
||||
|
||||
if (main != oldMain)
|
||||
handleModeChange(oldMain, mainMode, oldExtended);
|
||||
}
|
||||
liberator.triggerObserver("modeChange", [oldMain, oldExtended], [main, extended], stack);
|
||||
pop: function (silent) {
|
||||
let a = this._modeStack.pop();
|
||||
if (a)
|
||||
this.set(a[0], a[1], silent, { pop: a });
|
||||
else
|
||||
this.reset(silent);
|
||||
},
|
||||
|
||||
if (!silent)
|
||||
this.show();
|
||||
},
|
||||
// TODO: Deprecate this in favor of addMode? --Kris
|
||||
// Ya --djk
|
||||
setCustomMode: function (modestr, oneventfunc, stopfunc) {
|
||||
// TODO this.plugin[id]... ('id' maybe submode or what..)
|
||||
plugins.mode = modestr;
|
||||
plugins.onEvent = oneventfunc;
|
||||
plugins.stop = stopfunc;
|
||||
},
|
||||
|
||||
push: function (mainMode, extendedMode, silent)
|
||||
{
|
||||
modeStack.push([main, extended]);
|
||||
this.set(mainMode, extendedMode, silent, { push: modeStack[modeStack.length - 1] });
|
||||
},
|
||||
// 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);
|
||||
},
|
||||
|
||||
pop: function (silent)
|
||||
{
|
||||
let a = modeStack.pop();
|
||||
if (a)
|
||||
this.set(a[0], a[1], silent, { pop: a });
|
||||
else
|
||||
this.reset(silent);
|
||||
},
|
||||
remove: function (mode) {
|
||||
if (this._extended & mode) {
|
||||
this._extended &= ~mode;
|
||||
this.show();
|
||||
}
|
||||
},
|
||||
|
||||
// TODO: Deprecate this in favor of addMode? --Kris
|
||||
// Ya --djk
|
||||
setCustomMode: function (modestr, oneventfunc, stopfunc)
|
||||
{
|
||||
// TODO this.plugin[id]... ('id' maybe submode or what..)
|
||||
plugins.mode = modestr;
|
||||
plugins.onEvent = oneventfunc;
|
||||
plugins.stop = stopfunc;
|
||||
},
|
||||
get passNextKey() this._passNextKey,
|
||||
set passNextKey(value) { this._passNextKey = value; this.show(); },
|
||||
|
||||
// keeps recording state
|
||||
reset: function (silent)
|
||||
{
|
||||
modeStack = [];
|
||||
if (config.isComposeWindow)
|
||||
this.set(modes.COMPOSE, modes.NONE, silent);
|
||||
else
|
||||
this.set(modes.NORMAL, modes.NONE, silent);
|
||||
},
|
||||
get passAllKeys() this._passAllKeys,
|
||||
set passAllKeys(value) { this._passAllKeys = value; this.show(); },
|
||||
|
||||
remove: function (mode)
|
||||
{
|
||||
if (extended & mode)
|
||||
{
|
||||
extended &= ~mode;
|
||||
this.show();
|
||||
}
|
||||
},
|
||||
get isRecording() this._isRecording,
|
||||
set isRecording(value) { this._isRecording = value; this.show(); },
|
||||
|
||||
get passNextKey() passNextKey,
|
||||
set passNextKey(value) { passNextKey = value; this.show(); },
|
||||
get isReplaying() this._isReplaying,
|
||||
set isReplaying(value) { this._isReplaying = value; this.show(); },
|
||||
|
||||
get passAllKeys() passAllKeys,
|
||||
set passAllKeys(value) { passAllKeys = value; this.show(); },
|
||||
get main() this._main,
|
||||
set main(value) { this.set(value); },
|
||||
|
||||
get isRecording() isRecording,
|
||||
set isRecording(value) { isRecording = value; this.show(); },
|
||||
|
||||
get isReplaying() isReplaying,
|
||||
set isReplaying(value) { isReplaying = value; this.show(); },
|
||||
|
||||
get main() main,
|
||||
set main(value) { this.set(value); },
|
||||
|
||||
get extended() extended,
|
||||
set extended(value) { this.set(null, value); }
|
||||
|
||||
};
|
||||
|
||||
var mainModes = [self.NONE];
|
||||
var lastMode = 0;
|
||||
var modeMap = {};
|
||||
|
||||
// main modes, only one should ever be active
|
||||
self.addMode("NORMAL", { char: "n", display: -1 });
|
||||
self.addMode("INSERT", { char: "i", input: true });
|
||||
self.addMode("VISUAL", { char: "v", display: function () "VISUAL" + (extended & modes.LINE ? " LINE" : "") });
|
||||
self.addMode("COMMAND_LINE", { char: "c", input: true });
|
||||
self.addMode("CARET"); // text cursor is visible
|
||||
self.addMode("TEXTAREA", { char: "i" });
|
||||
self.addMode("EMBED", { input: true });
|
||||
self.addMode("CUSTOM", { display: function () plugins.mode });
|
||||
// extended modes, can include multiple modes, and even main modes
|
||||
self.addMode("EX", true);
|
||||
self.addMode("HINTS", true);
|
||||
self.addMode("INPUT_MULTILINE", true);
|
||||
self.addMode("OUTPUT_MULTILINE", true);
|
||||
self.addMode("SEARCH_FORWARD", true);
|
||||
self.addMode("SEARCH_BACKWARD", true);
|
||||
self.addMode("SEARCH_VIEW_FORWARD", true);
|
||||
self.addMode("SEARCH_VIEW_BACKWARD", true);
|
||||
self.addMode("MENU", true); // a popupmenu is active
|
||||
self.addMode("LINE", true); // linewise visual mode
|
||||
self.addMode("PROMPT", true);
|
||||
|
||||
config.modes.forEach(function (mode) { self.addMode.apply(self, mode); });
|
||||
|
||||
return self;
|
||||
//}}}
|
||||
})(); //}}}
|
||||
get extended() this._extended,
|
||||
set extended(value) { this.set(null, value); }
|
||||
});
|
||||
|
||||
// vim: set fdm=marker sw=4 ts=4 et:
|
||||
|
||||
Reference in New Issue
Block a user