summaryrefslogtreecommitdiff
path: root/common
diff options
context:
space:
mode:
Diffstat (limited to 'common')
-rw-r--r--common/content/buffer.js2
-rw-r--r--common/content/editor.js14
-rw-r--r--common/locale/en-US/options.xml34
-rw-r--r--common/modules/util.jsm67
4 files changed, 104 insertions, 13 deletions
diff --git a/common/content/buffer.js b/common/content/buffer.js
index ad4ce71b..46fb9988 100644
--- a/common/content/buffer.js
+++ b/common/content/buffer.js
@@ -961,7 +961,7 @@ const Buffer = Module("buffer", {
let doc = buffer.focusedFrame.document;
if (isArray(url)) {
- if (options.get("editor").has("l"))
+ if (options.get("editor").has("line"))
this.viewSourceExternally(url[0] || doc, url[1]);
else
window.openDialog("chrome://global/content/viewSource.xul",
diff --git a/common/content/editor.js b/common/content/editor.js
index 61bcf06e..c79c89c5 100644
--- a/common/content/editor.js
+++ b/common/content/editor.js
@@ -242,7 +242,7 @@ const Editor = Module("editor", {
},
editFileExternally: function (path, line, column) {
- let args = options.get("editor").format({ f: path, l: line, c: column });
+ let args = options.get("editor").format({ file: path, line: line, column: column });
dactyl.assert(args.length >= 1, "No editor specified");
@@ -772,19 +772,19 @@ const Editor = Module("editor", {
options: function () {
options.add(["editor"],
"The external text editor",
- "string", "gvim -f +%l %f", {
+ "string", "gvim -f +<line> <file>", {
format: function (obj, value) {
let args = commands.parseArgs(value || this.value, { argCount: "*", allowUnknownOptions: true })
- .map(util.compileFormat).filter(function (fmt) fmt.valid(obj))
+ .map(util.compileMacro).filter(function (fmt) fmt.valid(obj))
.map(function (fmt) fmt(obj));
- if (obj["f"] && !this.has("f"))
- args.push(obj["f"]);
+ if (obj["file"] && !this.has("file"))
+ args.push(obj["file"]);
return args;
},
- has: function (key) set.has(util.compileFormat(this.value).seen, key),
+ has: function (key) set.has(util.compileMacro(this.value).seen, key),
validator: function (value) {
this.format({}, value);
- return Object.keys(util.compileFormat(value).seen).every(function (k) "cfl".indexOf(k) >= 0)
+ return Object.keys(util.compileMacro(value).seen).every(function (k) ["column", "file", "line"].indexOf(k) >= 0)
}
});
diff --git a/common/locale/en-US/options.xml b/common/locale/en-US/options.xml
index d9d24776..e99d475f 100644
--- a/common/locale/en-US/options.xml
+++ b/common/locale/en-US/options.xml
@@ -88,6 +88,30 @@
<str>line: 32 'Lieder eines fahrenden Gesellen.txt'</str>
</p>
+<p tag="macro-string">
+ Some options may be given format strings containing macro replacements in
+ the form of <em>&lt;<a>name</a>></em>. These tokens are replaced by
+ the parameter <a>name</a> as specified in the relevant documentation.
+ If the token is in the form <em>&lt;q-<a>name</a>></em>, the value of the
+ parameter is automatically <link topic="quoting">quoted</link>.
+</p>
+<p>
+ Any substring enclosed by <em>&lt;[</em>
+ and <em>]></em> is automatically elided if any of the contained macros
+ characters aren't currently valid. A literal <em>&lt;</em> or <em>></em>
+ character may be included with the special escape sequences <em>&lt;lt></em>
+ or <em>&lt;gt></em> respectively.
+</p>
+
+<p>
+ For example, given the format string
+ <str><em>&lt;[</em>(cmd: <em>&lt;column></em>) <em>]>&lt;[</em>line: <em>&lt;line> ]>&lt;file></em></str>,
+ where <em>line</em>=<hl key="Number">32</hl> and
+ <em>file</em>=<str delim="'">Lieder eines fahrenden Gesellen.txt</str>,
+ the result is formatted as
+ <str>line: 32 'Lieder eines fahrenden Gesellen.txt'</str>
+</p>
+
<h2 tag="set-option E764">Setting options</h2>
<item>
@@ -553,7 +577,7 @@
<tags>'editor'</tags>
<spec>'editor'</spec>
<type>string</type>
- <default>gvim -f</default>
+ <default><![CDATA[gvim -f +<line> <file>]]></default>
<description>
<p>
Set the external text editor.
@@ -562,16 +586,16 @@
</p>
<p>
- Accepts a <t>format-string</t> with the following escapes available.
+ Accepts a <t>macro-string</t> with the following escapes available.
Arguments containing escapes which are not relevant to a given call
are automatically elided. All field splitting is done before format
characters are processed.
</p>
<dl>
- <dt>%f</dt> <dd>The file to edit. Appended as the final argument if missing.</dd>
- <dt>%l</dt> <dd>The line number at which to position the cursor.</dd>
- <dt>%c</dt> <dd>The column at which to position the cursor.</dd>
+ <dt>&lt;file></dt> <dd>The file to edit. Appended as the final argument if missing.</dd>
+ <dt>&lt;line></dt> <dd>The line number at which to position the cursor.</dd>
+ <dt>&lt;column></dt> <dd>The column at which to position the cursor.</dd>
</dl>
<warning>
diff --git a/common/modules/util.jsm b/common/modules/util.jsm
index 293ffb37..0e8c7734 100644
--- a/common/modules/util.jsm
+++ b/common/modules/util.jsm
@@ -244,6 +244,73 @@ const Util = Module("Util", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference])
return stack.top;
},
+ compileMacro: function compileFormat(macro) {
+ let stack = [frame()];
+ stack.__defineGetter__("top", function () this[this.length - 1]);
+
+ function frame() update(
+ function _frame(obj)
+ _frame === stack.top || _frame.valid(obj) ?
+ _frame.elements.map(function (e) callable(e) ? e(obj) : e).join("") : "",
+ {
+ elements: [],
+ seen: {},
+ valid: function (obj) this.elements.every(function (e) !e.test || e.test(obj))
+ });
+
+ let defaults = { lt: "<", gt: ">" };
+
+ let match, end = 0;
+ let re = util.regexp(<![CDATA[
+ (.*?) // 1
+ (?:
+ (<\[) | // 2
+ < (.*?) > | // 3
+ (\]>) // 4
+ )
+ ]]>, "gy");
+ while (match = re.exec(macro)) {
+ let [, prefix, open, macro, close] = match;
+ end += match[0].length;
+
+ if (prefix)
+ stack.top.elements.push(prefix);
+ if (open) {
+ let f = frame();
+ stack.top.elements.push(f);
+ stack.push(f);
+ }
+ else if (close) {
+ stack.pop();
+ util.assert(stack.length, "Unmatched %] in macro");
+ }
+ else {
+ let [, flags, name] = /^((?:[a-z]-)*)(.*)/.exec(macro);
+ flags = set(flags);
+
+ let quote = util.identity;
+ if (flags.q)
+ quote = function quote(obj) typeof obj === "number" ? obj : Commands.quote(obj);
+
+ if (set.has(defaults, name))
+ stack.top.elements.push(quote(defaults[name]));
+ else {
+ stack.top.elements.push(update(
+ function (obj) obj[name] != null ? quote(obj[name]) : "",
+ { test: function (obj) obj[name] != null }));
+
+ for (let elem in array.iterValues(stack))
+ elem.seen[name] = true;
+ }
+ }
+ }
+ if (end < macro.length)
+ stack.top.elements.push(macro.substr(end));
+
+ util.assert(stack.length === 1, "Unmatched <[ in macro");
+ return stack.top;
+ },
+
/**
* Returns an object representing a Node's computed CSS style.
*