diff options
author | Kris Maglione <maglione.k@gmail.com> | 2011-08-07 18:56:38 -0400 |
---|---|---|
committer | Kris Maglione <maglione.k@gmail.com> | 2011-08-07 18:56:38 -0400 |
commit | 3aa12ba117c1ff818d1ddf9e15b6b347b89d83a5 (patch) | |
tree | d0da6136356a5d9bc04a34745d94f3e87a0e7069 | |
parent | 84a69b920a4ce1d10d1d1a4658abec7e3fcbed6f (diff) | |
download | pentadactyl-3aa12ba117c1ff818d1ddf9e15b6b347b89d83a5.tar.gz |
Initial work towards making <C-o> and <C-i> more Vim-like.
-rw-r--r-- | common/content/buffer.js | 16 | ||||
-rw-r--r-- | common/content/history.js | 19 | ||||
-rw-r--r-- | common/content/marks.js | 116 | ||||
-rw-r--r-- | common/content/tabs.js | 16 | ||||
-rw-r--r-- | common/locale/en-US/browsing.xml | 26 | ||||
-rw-r--r-- | common/modules/base.jsm | 3 | ||||
-rw-r--r-- | pentadactyl/NEWS | 1 |
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><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><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><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><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] |