From 3f343d0d983f0e6c67a8515a4dcc6622531a7ae5 Mon Sep 17 00:00:00 2001
From: Kris Maglione
Date: Sat, 18 Dec 2010 09:32:09 -0500
Subject: [PATCH] Replace %format strings with our standard format
strings in 'editor' and the like.
--HG--
extra : rebase_source : b5a658dd9f07e30f7e9cb589bb6efca8fd260a66
---
common/content/buffer.js | 2 +-
common/content/editor.js | 14 +++----
common/locale/en-US/options.xml | 34 ++++++++++++++---
common/modules/util.jsm | 67 +++++++++++++++++++++++++++++++++
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 +", {
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 @@
line: 32 'Lieder eines fahrenden Gesellen.txt'
+
+ Some options may be given format strings containing macro replacements in
+ the form of <name>. These tokens are replaced by
+ the parameter name as specified in the relevant documentation.
+ If the token is in the form <q-name>, the value of the
+ parameter is automatically quoted.
+
+
+ Any substring enclosed by <[
+ and ]> is automatically elided if any of the contained macros
+ characters aren't currently valid. A literal < or >
+ character may be included with the special escape sequences <lt>
+ or <gt> respectively.
+
+
+
+ For example, given the format string
+ <[(cmd: <column>) ]><[line: <line> ]><file>,
+ where line=32 and
+ file=Lieder eines fahrenden Gesellen.txt,
+ the result is formatted as
+ line: 32 'Lieder eines fahrenden Gesellen.txt'
+
Set the external text editor.
@@ -562,16 +586,16 @@
- Accepts a format-string with the following escapes available.
+ Accepts a macro-string 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.
-
%f
The file to edit. Appended as the final argument if missing.
-
%l
The line number at which to position the cursor.
-
%c
The column at which to position the cursor.
+
<file>
The file to edit. Appended as the final argument if missing.
+
<line>
The line number at which to position the cursor.
+
<column>
The column at which to position the cursor.
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( | // 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.
*