mirror of
https://github.com/gryf/pentadactyl-pm.git
synced 2025-12-21 11:57:59 +01:00
Add 'linenumbers'.
This commit is contained in:
@@ -1841,7 +1841,15 @@ var Buffer = Module("buffer", {
|
||||
|
||||
mappings.add([modes.NORMAL], ["G", "<End>", "<scroll-bottom>"],
|
||||
"Go to the end of the document",
|
||||
function (args) { buffer.scrollToPercent(null, args.count != null ? args.count : 100); },
|
||||
function (args) {
|
||||
if (args.count)
|
||||
var elem = options.get("linenumbers").getLine(buffer.focusedFrame.document,
|
||||
args.count);
|
||||
if (elem)
|
||||
elem.scrollIntoView(true);
|
||||
else
|
||||
buffer.scrollToPercent(null, args.count != null ? args.count : 100);
|
||||
},
|
||||
{ count: true });
|
||||
|
||||
mappings.add([modes.NORMAL], ["%", "<scroll-percent>"],
|
||||
@@ -2132,6 +2140,52 @@ var Buffer = Module("buffer", {
|
||||
&& Object.keys(value).every(function (v) v.length == 1)
|
||||
});
|
||||
|
||||
options.add(["linenumbers", "ln"],
|
||||
"Patterns used to determine line numbers used by G",
|
||||
"sitemap", {
|
||||
"code.google.com": '#nums [id^="nums_table"] a[href^="#"]',
|
||||
"github.com": '.line_numbers>*',
|
||||
"mxr.mozilla.org": 'a.l',
|
||||
"pastebin.com": '#code_frame>div>ol>li'
|
||||
},
|
||||
{
|
||||
getLine: function getLine(doc, line) {
|
||||
let uri = util.newURI(doc.documentURI);
|
||||
for (let filter in values(this.value))
|
||||
if (filter(uri, doc)) {
|
||||
if (/^func:/.test(filter.result))
|
||||
var res = dactyl.userEval("(" + Option.dequote(filter.result.substr(5)) + ")")(doc, line);
|
||||
else
|
||||
res = iter.nth(filter.matcher(doc),
|
||||
function (elem) (elem.nodeValue || elem.textContent).trim() == line && DOM(elem).display != "none",
|
||||
0)
|
||||
|| iter.nth(filter.matcher(doc), util.identity, line - 1);
|
||||
if (res)
|
||||
break;
|
||||
}
|
||||
|
||||
return res;
|
||||
},
|
||||
|
||||
keepQuotes: true,
|
||||
|
||||
setter: function (vals) {
|
||||
for (let value in values(vals))
|
||||
if (!/^func:/.test(value.result))
|
||||
value.matcher = DOM.compileMatcher(Option.splitList(value.result));
|
||||
return vals;
|
||||
},
|
||||
|
||||
validate: function validate(values) {
|
||||
return this.testValues(values, function (value) {
|
||||
if (/^func:/.test(value))
|
||||
return callable(dactyl.userEval("(" + Option.dequote(value.substr(5)) + ")"));
|
||||
else
|
||||
return DOM.testMatcher(value);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
options.add(["nextpattern"],
|
||||
"Patterns to use when guessing the next page in a document sequence",
|
||||
"regexplist", UTF8(/'\bnext\b',^>$,^(>>|»)$,^(>|»),(>|»)$,'\bmore\b'/.source),
|
||||
|
||||
@@ -111,20 +111,7 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), {
|
||||
}
|
||||
},
|
||||
|
||||
/** @property {string} The name of the current user profile. */
|
||||
profileName: Class.Memoize(function () {
|
||||
// NOTE: services.profile.selectedProfile.name doesn't return
|
||||
// what you might expect. It returns the last _actively_ selected
|
||||
// profile (i.e. via the Profile Manager or -P option) rather than the
|
||||
// current profile. These will differ if the current process was run
|
||||
// without explicitly selecting a profile.
|
||||
|
||||
let dir = services.directory.get("ProfD", Ci.nsIFile);
|
||||
for (let prof in iter(services.profile.profiles))
|
||||
if (prof.QueryInterface(Ci.nsIToolkitProfile).rootDir.path === dir.path)
|
||||
return prof.name;
|
||||
return "unknown";
|
||||
}),
|
||||
profileName: deprecated("config.profileName", { get: function profileName() config.profileName }),
|
||||
|
||||
/**
|
||||
* @property {Modes.Mode} The current main mode.
|
||||
|
||||
@@ -134,7 +134,9 @@
|
||||
<description>
|
||||
<p>
|
||||
Go to the end of the document. With <oa>count</oa>,
|
||||
behaves exactly the same as <oa>gg</oa>.
|
||||
go to the <oa>count</oa>th line as determined by <o>linenumbers</o>,
|
||||
or to the <oa>count</oa>th percent of the document if the line number
|
||||
can't be determined.
|
||||
</p>
|
||||
</description>
|
||||
</item>
|
||||
|
||||
@@ -1034,6 +1034,25 @@
|
||||
</description>
|
||||
</item>
|
||||
|
||||
<item>
|
||||
<tags>'ln' 'linenumbers'</tags>
|
||||
<spec>'linenumbers' 'ln'</spec>
|
||||
<type>&option.linenumbers.type;</type>
|
||||
<default>&option.linenumbers.default;</default>
|
||||
<description>
|
||||
<p>
|
||||
Patterns used to determine line numbers used by <k>G</k>. May be
|
||||
either a selector expression as accepted by <o>hinttags</o>, in
|
||||
which case the first matching element whose text content is equal to
|
||||
the desired line number is used or the <oa>count</oa>th element
|
||||
failing that, or the string <str delim="'">func:</str> followed by a
|
||||
function which, given arguments for the document and desired line
|
||||
number must return the target element.
|
||||
</p>
|
||||
</description>
|
||||
</item>
|
||||
|
||||
|
||||
<item>
|
||||
<tags>'lpl' 'loadplugins'</tags>
|
||||
<spec>'loadplugins' 'lpl'</spec>
|
||||
|
||||
@@ -122,7 +122,12 @@ if (!Object.keys)
|
||||
|
||||
let getGlobalForObject = Cu.getGlobalForObject || function (obj) obj.__parent__;
|
||||
|
||||
let jsmodules = {};
|
||||
let jsmodules = {
|
||||
lazyRequire: function lazyRequire(module, names, target) {
|
||||
for each (let name in names)
|
||||
memoize(target || this, name, function (name) require(module)[name]);
|
||||
}
|
||||
};
|
||||
let use = {};
|
||||
let loaded = {};
|
||||
let currentModule;
|
||||
@@ -229,6 +234,8 @@ defineModule("base", {
|
||||
]
|
||||
}, this);
|
||||
|
||||
this.lazyRequire("messages", ["_", "Messages"]);
|
||||
|
||||
/**
|
||||
* Returns a list of all of the top-level properties of an object, by
|
||||
* way of the debugger.
|
||||
@@ -325,7 +332,7 @@ deprecated.warn = function warn(func, name, alternative, frame) {
|
||||
let filename = util.fixURI(frame.filename || "unknown");
|
||||
if (!Set.add(func.seenCaller, filename))
|
||||
util.dactyl(func).warn([util.urlPath(filename), frame.lineNumber, " "].join(":")
|
||||
+ require("messages")._("warn.deprecated", name, alternative));
|
||||
+ _("warn.deprecated", name, alternative));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1242,7 +1249,7 @@ var StructBase = Class("StructBase", Array, {
|
||||
|
||||
localize: function localize(key, defaultValue) {
|
||||
let i = this.prototype.members[key];
|
||||
Object.defineProperty(this.prototype, i, require("messages").Messages.Localized(defaultValue).init(key, this.prototype));
|
||||
Object.defineProperty(this.prototype, i, Messages.Localized(defaultValue).init(key, this.prototype));
|
||||
return this;
|
||||
}
|
||||
});
|
||||
|
||||
@@ -13,6 +13,10 @@ defineModule("config", {
|
||||
require: ["dom", "protocol", "services", "storage", "util", "template"]
|
||||
}, this);
|
||||
|
||||
this.lazyRequire("addons", ["AddonManager"]);
|
||||
this.lazyRequire("highlight", ["highlight"]);
|
||||
this.lazyRequire("messages", ["_"]);
|
||||
|
||||
function AboutHandler() {}
|
||||
AboutHandler.prototype = {
|
||||
get classDescription() "About " + config.appName + " Page",
|
||||
@@ -102,9 +106,6 @@ var ConfigBase = Class("ConfigBase", {
|
||||
},
|
||||
|
||||
loadStyles: function loadStyles(force) {
|
||||
const { highlight } = require("highlight");
|
||||
const { _ } = require("messages");
|
||||
|
||||
highlight.styleableChrome = this.styleableChrome;
|
||||
|
||||
highlight.loadCSS(this.CSS.replace(/__MSG_(.*?)__/g, function (m0, m1) _(m1)));
|
||||
@@ -145,7 +146,7 @@ var ConfigBase = Class("ConfigBase", {
|
||||
|
||||
addon: Class.Memoize(function () {
|
||||
return (JSMLoader.bootstrap || {}).addon ||
|
||||
require("addons").AddonManager.getAddonByID(this.addonID);
|
||||
AddonManager.getAddonByID(this.addonID);
|
||||
}),
|
||||
|
||||
/**
|
||||
@@ -311,6 +312,21 @@ var ConfigBase = Class("ConfigBase", {
|
||||
return (/pre-hg\d+-(\S*)/.exec(this.version) || [])[1];
|
||||
}),
|
||||
|
||||
/** @property {string} The name of the current user profile. */
|
||||
profileName: Class.Memoize(function () {
|
||||
// NOTE: services.profile.selectedProfile.name doesn't return
|
||||
// what you might expect. It returns the last _actively_ selected
|
||||
// profile (i.e. via the Profile Manager or -P option) rather than the
|
||||
// current profile. These will differ if the current process was run
|
||||
// without explicitly selecting a profile.
|
||||
|
||||
let dir = services.directory.get("ProfD", Ci.nsIFile);
|
||||
for (let prof in iter(services.profile.profiles))
|
||||
if (prof.QueryInterface(Ci.nsIToolkitProfile).rootDir.path === dir.path)
|
||||
return prof.name;
|
||||
return "unknown";
|
||||
}),
|
||||
|
||||
/** @property {string} The Dactyl version string. */
|
||||
version: Class.Memoize(function () {
|
||||
if (this.VCSPath)
|
||||
@@ -375,7 +391,6 @@ var ConfigBase = Class("ConfigBase", {
|
||||
helpStyles: /^(Help|StatusLine|REPL)|^(Boolean|Dense|Indicator|MoreMsg|Number|Object|Logo|Key(word)?|String)$/,
|
||||
styleHelp: function styleHelp() {
|
||||
if (!this.helpStyled) {
|
||||
const { highlight } = require("highlight");
|
||||
for (let k in keys(highlight.loaded))
|
||||
if (this.helpStyles.test(k))
|
||||
highlight.loaded[k] = true;
|
||||
@@ -1064,7 +1079,6 @@ config.INIT = update(Object.create(config.INIT), config.INIT, {
|
||||
let img = window.Image();
|
||||
img.src = this.logo || "resource://dactyl-local-content/logo.png";
|
||||
img.onload = util.wrapCallback(function () {
|
||||
const { highlight } = require("highlight");
|
||||
highlight.loadCSS(<>{"!Logo {"}
|
||||
display: inline-block;
|
||||
background: url({img.src});
|
||||
|
||||
@@ -1324,7 +1324,7 @@ var DOM = Class("DOM", {
|
||||
yield elem;
|
||||
|
||||
if (matcher.css)
|
||||
for (let [, elem] in iter(node.querySelectorAll(matcher.css)))
|
||||
for (let [, elem] in iter(util.withProperErrors("querySelectorAll", node, matcher.css)))
|
||||
yield elem;
|
||||
}, {
|
||||
css: css.join(", "),
|
||||
@@ -1343,13 +1343,15 @@ var DOM = Class("DOM", {
|
||||
validateMatcher: function validateMatcher(list) {
|
||||
let evaluator = services.XPathEvaluator();
|
||||
let node = services.XMLDocument();
|
||||
return this.testValues(list, function (value) {
|
||||
if (/^xpath:/.test(value))
|
||||
evaluator.createExpression(value.substr(6), DOM.XPath.resolver);
|
||||
else
|
||||
node.querySelector(value);
|
||||
return true;
|
||||
});
|
||||
return this.testValues(list, this.closure.testMatcher);
|
||||
},
|
||||
|
||||
testMatcher: function testMatcher(value) {
|
||||
if (/^xpath:/.test(value))
|
||||
evaluator.createExpression(value.substr(6), DOM.XPath.resolver);
|
||||
else
|
||||
node.querySelector(value);
|
||||
return true;
|
||||
},
|
||||
|
||||
/**
|
||||
|
||||
@@ -12,8 +12,6 @@ defineModule("finder", {
|
||||
|
||||
function equals(a, b) XPCNativeWrapper(a) == XPCNativeWrapper(b);
|
||||
|
||||
try {
|
||||
|
||||
/** @instance rangefinder */
|
||||
var RangeFinder = Module("rangefinder", {
|
||||
Local: function (dactyl, modules, window) ({
|
||||
@@ -265,7 +263,6 @@ var RangeFinder = Module("rangefinder", {
|
||||
},
|
||||
options: function (dactyl, modules, window) {
|
||||
const { options, rangefinder } = modules;
|
||||
const { prefs } = require("prefs");
|
||||
|
||||
options.add(["hlfind", "hlf"],
|
||||
"Highlight all /find pattern matches on the current page after submission",
|
||||
@@ -844,9 +841,8 @@ var RangeFind = Class("RangeFind", {
|
||||
}
|
||||
});
|
||||
|
||||
} catch(e){ if (typeof e === "string") e = Error(e); dump(e.fileName+":"+e.lineNumber+": "+e+"\n" + e.stack); }
|
||||
// catch(e){ if (typeof e === "string") e = Error(e); dump(e.fileName+":"+e.lineNumber+": "+e+"\n" + e.stack); }
|
||||
|
||||
endModule();
|
||||
|
||||
|
||||
// vim: set fdm=marker sw=4 ts=4 et ft=javascript:
|
||||
|
||||
@@ -7,9 +7,11 @@
|
||||
Components.utils.import("resource://dactyl/bootstrap.jsm");
|
||||
defineModule("storage", {
|
||||
exports: ["File", "Storage", "storage"],
|
||||
require: ["services", "util"]
|
||||
require: ["config", "services", "util"]
|
||||
}, this);
|
||||
|
||||
this.lazyRequire("io", ["IO"]);
|
||||
|
||||
var win32 = /^win(32|nt)$/i.test(services.runtime.OS);
|
||||
var myObject = JSON.parse("{}").constructor;
|
||||
|
||||
@@ -169,6 +171,10 @@ var Storage = Module("Storage", {
|
||||
this.observers = {};
|
||||
},
|
||||
|
||||
infoPath: Class.Memoize(function ()
|
||||
File(IO.runtimePath.replace(/,.*/, ""))
|
||||
.child("info").child(config.profileName)),
|
||||
|
||||
exists: function exists(name) this.infoPath.child(name).exists(),
|
||||
|
||||
newObject: function newObject(key, constructor, params) {
|
||||
@@ -270,12 +276,6 @@ var Storage = Module("Storage", {
|
||||
skipXpcom: function skipXpcom(key, val) val instanceof Ci.nsISupports ? null : val
|
||||
}
|
||||
}, {
|
||||
init: function init(dactyl, modules) {
|
||||
init.superapply(this, arguments);
|
||||
storage.infoPath = File(modules.IO.runtimePath.replace(/,.*/, ""))
|
||||
.child("info").child(dactyl.profileName);
|
||||
},
|
||||
|
||||
cleanup: function (dactyl, modules, window) {
|
||||
overlay.setData(window, "storage-refs", null);
|
||||
this.removeDeadObservers();
|
||||
|
||||
@@ -80,6 +80,7 @@
|
||||
- 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]
|
||||
- n_G now uses 'linenumbers' to determine destination if possible. [b8]
|
||||
- Add n_s and n_S. [b8]
|
||||
- Added Operator mode for motion maps, per Vim. [b8]
|
||||
- Added site-specific mapping groups and related command
|
||||
@@ -211,6 +212,7 @@
|
||||
- 'complete' now defaults to "slf" but file completion only
|
||||
triggers when the URL begins as above. [b1]
|
||||
- Added 'jumptags' option. [b7]
|
||||
- Added 'linenumbers' option. [b8]
|
||||
- Added 's' flag to 'pageinfo' and changed default value. [b7]
|
||||
- Added 'passkeys' option. [b3]
|
||||
- Added 'passunknown' option. [b7]
|
||||
|
||||
Reference in New Issue
Block a user