summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--common/content/buffer.js16
-rw-r--r--common/content/history.js19
-rw-r--r--common/content/marks.js116
-rw-r--r--common/content/tabs.js16
-rw-r--r--common/locale/en-US/browsing.xml26
-rw-r--r--common/modules/base.jsm3
-rw-r--r--pentadactyl/NEWS1
7 files changed, 135 insertions, 62 deletions
diff --git a/common/content/buffer.js b/common/content/buffer.js
index 279b3c94..f4828eec 100644
--- a/common/content/buffer.js
+++ b/common/content/buffer.js
@@ -270,11 +270,18 @@ var Buffer = Module("buffer", {
* tab.
*/
get localStore() {
- if (!content.document.dactylStore)
- content.document.dactylStore = {};
- return content.document.dactylStore;
+ let doc = content.document;
+ if (!doc.dactylStore || !buffer.localStorePrototype.isPrototypeOf(doc.dactylStore))
+ doc.dactylStore = Object.create(buffer.localStorePrototype);
+ return doc.dactylStore.instance = doc.dactylStore;
},
+ localStorePrototype: memoize({
+ instance: {},
+ get jumps() [],
+ jumpsIndex: 0
+ }),
+
/**
* @property {Node} The last focused input field in the buffer. Used
* by the "gi" key binding.
@@ -1263,9 +1270,8 @@ var Buffer = Module("buffer", {
* null, to not alter the vertical scroll offset.
*/
scrollTo: function scrollTo(elem, left, top) {
- // Temporary hack. Should be done better.
if (elem.ownerDocument == buffer.focusedFrame.document)
- marks.add("'");
+ marks.push();
if (left != null)
elem.scrollLeft = left;
diff --git a/common/content/history.js b/common/content/history.js
index a4bb2838..36d052f9 100644
--- a/common/content/history.js
+++ b/common/content/history.js
@@ -63,7 +63,20 @@ var History = Module("history", {
return obj;
},
- stepTo: function stepTo(steps) {
+ /**
+ * Step to the given offset in the history stack.
+ *
+ * @param {number} steps The possibly negative number of steps to
+ * step.
+ * @param {boolean} jumps If true, take into account jumps in the
+ * marks stack. @optional
+ */
+ stepTo: function stepTo(steps, jumps) {
+ if (jumps)
+ steps -= marks.jump(steps);
+ if (steps == 0)
+ return;
+
let start = 0;
let end = window.getWebNavigation().sessionHistory.count - 1;
let current = window.getWebNavigation().sessionHistory.index;
@@ -274,12 +287,12 @@ var History = Module("history", {
mappings.add(myModes,
["<C-o>"], "Go to an older position in the jump list",
- function (args) { history.stepTo(-Math.max(args.count, 1)); },
+ function (args) { history.stepTo(-Math.max(args.count, 1), true); },
{ count: true });
mappings.add(myModes,
["<C-i>"], "Go to a newer position in the jump list",
- function (args) { history.stepTo(Math.max(args.count, 1)); },
+ function (args) { history.stepTo(Math.max(args.count, 1), true); },
{ count: true });
mappings.add(myModes,
diff --git a/common/content/marks.js b/common/content/marks.js
index d0c7c252..c15cbef4 100644
--- a/common/content/marks.js
+++ b/common/content/marks.js
@@ -34,6 +34,19 @@ var Marks = Module("marks", {
get localURI() buffer.focusedFrame.document.documentURI,
+ Mark: function Mark(params) {
+ let win = buffer.focusedFrame;
+ let doc = win.document;
+
+ params = params || {};
+
+ params.location = doc.documentURI,
+ params.offset = buffer.scrollPosition;
+ params.path = util.generateXPath(buffer.findScrollable(0, params.offset.x));
+ params.timestamp = Date.now() * 1000;
+ return params;
+ },
+
/**
* Add a named mark for the current buffer, at its current position.
* If mark matches [A-Z], it's considered a URL mark, and will jump to
@@ -41,39 +54,58 @@ var Marks = Module("marks", {
* selected from. If it matches [a-z], it's a local mark, and can
* only be recalled from a buffer with a matching URL.
*
- * @param {string} mark The mark name.
+ * @param {string} name The mark name.
* @param {boolean} silent Whether to output error messages.
*/
- add: function (mark, silent) {
- let win = buffer.focusedFrame;
- let doc = win.document;
+ add: function (name, silent) {
+ let mark = this.Mark();
- let position = buffer.scrollPosition;
- let path = util.generateXPath(buffer.findScrollable(0, position.x));
-
- if (Marks.isURLMark(mark)) {
- let res = this._urlMarks.set(mark, {
- location: doc.documentURI,
- offset: position,
- xpath: path,
- tab: Cu.getWeakReference(tabs.getTab()),
- timestamp: Date.now()*1000
- });
- if (!silent)
- dactyl.log(_("mark.addURL", Marks.markToString(mark, res)), 5);
+ if (Marks.isURLMark(name)) {
+ mark.tab = Cu.getWeakReference(tabs.getTab());
+ this._urlMarks.set(name, mark);
+ var message = "mark.addURL";
}
- else if (Marks.isLocalMark(mark)) {
- let marks = this._localMarks.get(doc.documentURI, {});
- marks[mark] = {
- location: doc.documentURI,
- offset: position,
- xpath: path,
- timestamp: Date.now()*1000
- };
+ else if (Marks.isLocalMark(name)) {
+ this._localMarks.get(mark.location, {})[name] = mark;
this._localMarks.changed();
- if (!silent)
- dactyl.log(_("mark.addLocal", Marks.markToString(mark, marks[mark])), 5);
+ message = "mark.addLocal";
}
+
+ if (!silent)
+ dactyl.log(_(message, Marks.markToString(name, mark)), 5);
+ return mark;
+ },
+
+ /**
+ * Push the current buffer position onto the jump stack.
+ */
+ push: function push() {
+ if (!this.jumping) {
+ let mark = this.add("'");
+ let store = buffer.localStore;
+ store.jumps[store.jumpsIndex++] = mark;
+ store.jumps.length = store.jumpsIndex;
+ }
+ },
+
+ /**
+ * Jump to the given offset in the jump stack.
+ *
+ * @param {number} offset The offset from the current position in
+ * the jump stack to jump to.
+ * @returns {number} The actual change in offset.
+ */
+ jump: function jump(offset) {
+ return this.withSavedValues(["jumping"], function _jump() {
+ this.jumping = true;
+ let store = buffer.localStore;
+ let idx = Math.constrain(store.jumpsIndex + offset, 0, store.jumps.length - 1);
+ let orig = store.jumpsIndex;
+
+ if (idx in store.jumps && !dactyl.trapErrors("_scrollTo", this, store.jumps[idx]))
+ store.jumpsIndex = idx;
+ return store.jumpsIndex - orig;
+ });
},
/**
@@ -176,10 +208,10 @@ var Marks = Module("marks", {
util.assert(node);
util.scrollIntoView(node);
- if (mark.position)
- Buffer.scrollToPercent(node, mark.position.x * 100, mark.position.y * 100);
- else if (mark.offset)
+ if (mark.offset)
Buffer.scrollToPosition(node, mark.offset.x, mark.offset.y);
+ else if (mark.position)
+ Buffer.scrollToPercent(node, mark.position.x * 100, mark.position.y * 100);
},
/**
@@ -203,10 +235,10 @@ var Marks = Module("marks", {
["Mark", "HPos", "VPos", "File"],
["", "text-align: right", "text-align: right", "color: green"],
([name,
- mark.position ? Math.round(mark.position.x * 100) + "%"
- : Math.round(mark.offset.x),
- mark.position ? Math.round(mark.position.y * 100) + "%"
- : Math.round(mark.offset.y),
+ mark.offset ? Math.round(mark.offset.x)
+ : Math.round(mark.position.x * 100) + "%",
+ mark.offset ? Math.round(mark.offset.y)
+ : Math.round(mark.position.y * 100) + "%",
mark.location]
for ([, [name, mark]] in Iterator(marks)))));
},
@@ -224,6 +256,13 @@ var Marks = Module("marks", {
}, {
markToString: function markToString(name, mark) {
let tab = mark.tab && mark.tab.get();
+ if (mark.offset)
+ return [name, mark.location,
+ "(" + Math.round(mark.offset.x * 100),
+ Math.round(mark.offset.y * 100) + ")",
+ (tab && "tab: " + tabs.index(tab))
+ ].filter(util.identity).join(", ");
+
if (mark.position)
return [name, mark.location,
"(" + Math.round(mark.position.x * 100) + "%",
@@ -231,11 +270,6 @@ var Marks = Module("marks", {
(tab && "tab: " + tabs.index(tab))
].filter(util.identity).join(", ");
- return [name, mark.location,
- "(" + Math.round(mark.offset.x * 100),
- Math.round(mark.offset.y * 100) + ")",
- (tab && "tab: " + tabs.index(tab))
- ].filter(util.identity).join(", ");
},
isLocalMark: function isLocalMark(mark) /^[a-z`']$/.test(mark),
@@ -309,7 +343,9 @@ var Marks = Module("marks", {
function percent(i) Math.round(i * 100);
context.title = ["Mark", "HPos VPos File"];
- context.keys.description = function ([, m]) percent(m.position.x) + "% " + percent(m.position.y) + "% " + m.location;
+ context.keys.description = function ([, m]) (m.offset ? Math.round(m.offset.x) + " " + Math.round(m.offset.y)
+ : percent(m.position.x) + "% " + percent(m.position.y) + "%"
+ ) + " " + m.location;
context.completions = marks.all;
};
},
diff --git a/common/content/tabs.js b/common/content/tabs.js
index 2aeae8b7..395cabcd 100644
--- a/common/content/tabs.js
+++ b/common/content/tabs.js
@@ -127,12 +127,7 @@ var Tabs = Module("tabs", {
/**
* @property {Object} The local options store for the current tab.
*/
- get options() {
- let store = this.localStore;
- if (!("options" in store))
- store.options = {};
- return store.options;
- },
+ get options() this.localStore.options,
get visibleTabs() config.tabbrowser.visibleTabs || this.allTabs.filter(function (tab) !tab.hidden),
@@ -151,8 +146,8 @@ var Tabs = Module("tabs", {
getLocalStore: function getLocalStore(tabIndex) {
let tab = this.getTab(tabIndex);
if (!tab.dactylStore)
- tab.dactylStore = {};
- return tab.dactylStore;
+ tab.dactylStore = Object.create(this.localStorePrototype);
+ return tab.dactylStore.instance = tab.dactylStore;
},
/**
@@ -161,6 +156,11 @@ var Tabs = Module("tabs", {
*/
get localStore() this.getLocalStore(),
+ localStorePrototype: memoize({
+ instance: {},
+ get options() ({})
+ }),
+
/**
* @property {[Object]} The array of closed tabs for the current
* session.
diff --git a/common/locale/en-US/browsing.xml b/common/locale/en-US/browsing.xml
index 0e0c4075..4b249c57 100644
--- a/common/locale/en-US/browsing.xml
+++ b/common/locale/en-US/browsing.xml
@@ -264,10 +264,9 @@ want to bypass &dactyl.appName;'s key handling and pass keys directly to
<h2 tag="navigating">Navigating</h2>
<item>
- <tags><![CDATA[H <C-o> CTRL-O :ba :back]]></tags>
+ <tags><![CDATA[H CTRL-O :ba :back]]></tags>
<spec>:<oa>count</oa>ba<oa>ck</oa> <oa>url</oa></spec>
<spec>:ba<oa>ck</oa>!</spec>
- <spec><oa>count</oa>&lt;C-o></spec>
<description>
<p>
Go <oa>count</oa> pages back in the browser history. If
@@ -279,10 +278,9 @@ want to bypass &dactyl.appName;'s key handling and pass keys directly to
</item>
<item>
- <tags><![CDATA[L <C-i> CTRL-I :fo :fw :forward]]></tags>
+ <tags><![CDATA[L CTRL-I :fo :fw :forward]]></tags>
<spec>:<oa>count</oa>fo<oa>rward</oa> <oa>url</oa></spec>
<spec>:fo<oa>rward</oa>!</spec>
- <spec><oa>count</oa>&lt;C-i></spec>
<description>
<p>
Go <oa>count</oa> pages forward in the browser history.
@@ -294,6 +292,26 @@ want to bypass &dactyl.appName;'s key handling and pass keys directly to
</item>
<item>
+ <tags><![CDATA[<C-o>]]></tags>
+ <spec><oa>count</oa>&lt;C-o></spec>
+ <description>
+ <p>
+ Go <oa>count</oa> steps back in the jumps stack.
+ </p>
+ </description>
+</item>
+
+<item>
+ <tags><![CDATA[<C-i>]]></tags>
+ <spec><oa>count</oa>&lt;C-i></spec>
+ <description>
+ <p>
+ Go <oa>count</oa> steps forward in the jumps stack.
+ </p>
+ </description>
+</item>
+
+<item>
<tags>:ju :jumps</tags>
<spec>:ju<oa>mps</oa></spec>
<description>
diff --git a/common/modules/base.jsm b/common/modules/base.jsm
index db6342e2..d92c8d4b 100644
--- a/common/modules/base.jsm
+++ b/common/modules/base.jsm
@@ -611,8 +611,7 @@ function call(fn) {
*/
function memoize(obj, key, getter) {
if (arguments.length == 1) {
- obj = update({ __proto__: obj.__proto__ }, obj);
- for (let prop in Object.getOwnPropertyNames(obj)) {
+ for each (let prop in Object.getOwnPropertyNames(obj)) {
let get = __lookupGetter__.call(obj, prop);
if (get)
memoize(obj, prop, get);
diff --git a/pentadactyl/NEWS b/pentadactyl/NEWS
index 1be83db6..b9f8f311 100644
--- a/pentadactyl/NEWS
+++ b/pentadactyl/NEWS
@@ -77,6 +77,7 @@
• Mapping changes:
- It's now possible to map keys in many more modes, including
Hint, Multi-line Output, and Menu. [b4]
+ - <C-o> and <C-i> now behave more like Vim. [b8]
- Added Operator mode for motion maps, per Vim. [b8]
- Added site-specific mapping groups and related command
changes. [b6]