// Copyright (c) 2006-2008 by Martin Stubenschrott <stubenschrott@vimperator.org>
-// Copyright (c) 2007-2011 by Doug Kearns <dougkearns@gmail.com>
-// Copyright (c) 2008-2011 by Kris Maglione <maglione.k@gmail.com>
-// Some code based on Venkman
+// Copyright (c) 2007-2012 by Doug Kearns <dougkearns@gmail.com>
+// Copyright (c) 2008-2014 Kris Maglione <maglione.k@gmail.com>
//
// This work is licensed for reuse under an MIT license. Details are
// given in the LICENSE.txt file included with this file.
-/* use strict */
+"use strict";
try {
-Components.utils.import("resource://dactyl/bootstrap.jsm");
defineModule("io", {
exports: ["IO", "io"],
require: ["services"]
-}, this);
+});
-this.lazyRequire("config", ["config"]);
-this.lazyRequire("contexts", ["Contexts", "contexts"]);
+lazyRequire("config", ["config"]);
+lazyRequire("contexts", ["Contexts", "contexts"]);
+lazyRequire("promises", ["Promise"]);
+lazyRequire("storage", ["File", "storage"]);
+lazyRequire("styles", ["styles"]);
+lazyRequire("template", ["template"]);
// TODO: why are we passing around strings rather than file objects?
/**
this._oldcwd = null;
this._lastRunCommand = ""; // updated whenever the users runs a command with :!
- this._scriptNames = [];
+ this._scriptNames = RealSet();
},
CommandFileMode: Class("CommandFileMode", modules.CommandMode, {
*/
getRuntimeDirectories: function getRuntimeDirectories(name) {
return modules.options.get("runtimepath").files
- .map(function (dir) dir.child(name))
- .filter(function (dir) dir.exists() && dir.isDirectory() && dir.isReadable());
+ .map(dir => dir.child(name))
+ .filter(dir => (dir.exists() && dir.isDirectory() && dir.isReadable()));
},
// FIXME: multiple paths?
let sourceJSM = function sourceJSM() {
context = contexts.Module(uri);
dactyl.triggerObserver("io.source", context, file, file.lastModifiedTime);
- }
+ };
- if (/\.js,$/.test(filename))
+ if (/\.jsm$/.test(filename))
sourceJSM();
else if (/\.js$/.test(filename)) {
try {
var context = contexts.Script(file, params.group);
- if (Set.has(this._scriptNames, file.path))
+ if (this._scriptNames.has(file.path))
util.flushCache();
dactyl.loadScript(uri.spec, context);
sourceJSM();
}
else {
+ if (e instanceof Finished)
+ return;
if (e.fileName && !(e instanceof FailedAssertion))
try {
e.fileName = util.fixURI(e.fileName);
if (e.fileName == uri.spec)
e.fileName = filename;
- e.echoerr = <>{e.fileName}:{e.lineNumber}: {e}</>;
+ e.echoerr = [e.fileName, ":", e.lineNumber, ": ", e].join("");
}
catch (e) {}
throw e;
dactyl.triggerObserver("io.source", context, file, file.lastModifiedTime);
}
- Set.add(this._scriptNames, file.path);
+ this._scriptNames.add(file.path);
dactyl.echomsg(_("io.sourcingEnd", filename.quote()), 2);
dactyl.log(_("dactyl.sourced", filename), 3);
/**
* Sets the current working directory.
*
- * @param {string} newDir The new CWD. This may be a relative or
+ * @param {File|string} newDir The new CWD. This may be a relative or
* absolute path and is expanded by {@link #expandPath}.
+ * @optional
+ * @default = "~"
*/
- set cwd(newDir) {
- newDir = newDir && newDir.path || newDir || "~";
+ set cwd(newDir = "~") {
+ newDir = newDir.path || newDir;
if (newDir == "-") {
util.assert(this._oldcwd != null, _("io.noPrevDir"));
*/
File: Class.Memoize(function () let (io = this)
Class("File", File, {
- init: function init(path, checkCWD)
- init.supercall(this, path, (arguments.length < 2 || checkCWD) && io.cwd)
+ init: function init(path, checkCWD=true)
+ init.supercall(this, path, checkCWD && io.cwd)
})),
/**
},
/**
- * Creates a temporary file.
+ * Returns a temporary file.
*
+ * @param {string} ext The filename extension.
+ * @default "txt"
+ * @param {string} label A metadata string appended to the filename. Useful
+ * for identifying the file, beyond its extension, to external
+ * applications.
+ * @default ""
* @returns {File}
*/
- createTempFile: function createTempFile(name, type) {
- if (name instanceof Ci.nsIFile) {
- var file = name.clone();
- if (!type || type == "file")
- file.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, octal(666));
- else
- file.createUnique(Ci.nsIFile.DIRECTORY_TYPE, octal(777));
- }
- else {
- file = services.directory.get("TmpD", Ci.nsIFile);
- file.append(this.config.tempFile + (name ? "." + name : ""));
- file.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, octal(666));
- }
+ createTempFile: function createTempFile(ext="txt", label="") {
+ let file = services.directory.get("TmpD", Ci.nsIFile);
+ file.append(config.name + label + "." + ext);
+ file.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, octal(666));
services.externalApp.deleteTemporaryFileOnExit(file);
file = util.getFile(file);
if (file && file.exists() && file.isFile() && file.isReadable()) {
// let jar = services.zipReader.getZip(file); Crashes.
- let jar = services.ZipReader(file);
+ let jar = services.ZipReader(file.file);
try {
let filter = RegExp("^" + util.regexp.escape(decodeURI(path))
+ "[^/]*/?$");
return -1;
}
- let process = services.Process(file);
+ let process = services.Process(file.file);
process.run(false, args.map(String), args.length);
- try {
- if (callable(blocking))
- var timer = services.Timer(
- function () {
- if (!process.isRunning) {
- timer.cancel();
- util.trapErrors(blocking, self, process.exitValue);
- }
- },
- 100, services.Timer.TYPE_REPEATING_SLACK);
- else if (blocking)
- while (process.isRunning)
- util.threadYield(false, true);
- }
- catch (e) {
- process.kill();
- throw e;
+
+ let deferred = Promise.defer();
+
+ if (callable(blocking))
+ // Deprecated.
+ deferred.promise.then(blocking);
+ else if (blocking) {
+ // Deprecated?
+ while (process.isRunning)
+ util.threadYield(false, true);
+ return process.exitValue;
}
- return process.exitValue;
+ let timer = services.Timer(
+ function () {
+ if (!process.isRunning) {
+ timer.cancel();
+ deferred.resolve(process.exitValue);
+ }
+ },
+ 100, services.Timer.TYPE_REPEATING_SLACK);
+
+ return deferred.promise;
},
// TODO: when https://bugzilla.mozilla.org/show_bug.cgi?id=68702 is
system: function system(command, input, callback) {
util.dactyl.echomsg(_("io.callingShell", command), 4);
- let { shellEscape } = util.closure;
+ let { shellEscape } = util.bound;
return this.withTempFiles(function (stdin, stdout, cmd) {
if (input instanceof File)
function async(status) {
let output = stdout.read();
- [stdin, stdout, cmd].forEach(function (f) f.exists() && f.remove(false));
+ for (let f of [stdin, stdout, cmd])
+ if (f.exists())
+ f.remove(false);
callback(result(status, output));
}
* @returns {boolean} false if temp files couldn't be created,
* otherwise, the return value of *func*.
*/
- withTempFiles: function withTempFiles(func, self, checked, ext) {
+ withTempFiles: function withTempFiles(func, self, checked, ext, label) {
let args = array(util.range(0, func.length))
- .map(bind("createTempFile", this, ext)).array;
+ .map(bind("createTempFile", this, ext, label)).array;
try {
if (!args.every(util.identity))
return false;
}
finally {
if (!checked || res !== true)
- args.forEach(function (f) f.remove(false));
+ args.forEach(f => { f.remove(false); });
}
return res;
}
*/
PATH_SEP: deprecated("File.PATH_SEP", { get: function PATH_SEP() File.PATH_SEP })
}, {
- commands: function init_commands(dactyl, modules, window) {
+ commands: function initCommands(dactyl, modules, window) {
const { commands, completion, io } = modules;
commands.add(["cd", "chd[ir]"],
lines.push("\n\" vim: set ft=" + config.name + ":");
try {
- file.write(lines.join("\n"));
+ file.write(lines.join("\n").concat("\n"));
+ dactyl.echomsg(_("io.writing", file.path.quote()), 2);
}
catch (e) {
dactyl.echoerr(_("io.notWriteable", file.path.quote()));
completer: function (context) completion.file(context, true)
});
- commands.add(["mks[yntax]"],
- "Generate a Vim syntax file",
+ commands.add(["mkv[imruntime]"],
+ "Create and install Vim runtime files for " + config.appName,
function (args) {
- let runtime = config.OS.isWindows ? "~/vimfiles/" : "~/.vim/";
- let file = io.File(runtime + "syntax/" + config.name + ".vim");
- if (args.length)
- file = io.File(args[0]);
+ dactyl.assert(args.length <= 1, _("io.oneFileAllowed"));
+
+ if (args.length) {
+ var rtDir = io.File(args[0]);
+ dactyl.assert(rtDir.exists(), _("io.noSuchDir", rtDir.path.quote()));
+ }
+ else
+ rtDir = io.File(config.OS.isWindows ? "~/vimfiles/" : "~/.vim/");
+
+ dactyl.assert(!rtDir.exists() || rtDir.isDirectory(), _("io.eNotDir", rtDir.path.quote()));
+
+ let rtItems = { ftdetect: {}, ftplugin: {}, syntax: {} };
+
+ // require bang if any of the paths exist
+ for (let [type, item] in iter(rtItems)) {
+ let file = io.File(rtDir).child(type, config.name + ".vim");
+ dactyl.assert(!file.exists() || args.bang, _("io.exists", file.path.quote()));
+ item.file = file;
+ }
+
+ rtItems.ftdetect.template = //{{{
+literal(/*" Vim filetype detection file
+<header>
+
+au BufNewFile,BufRead *<name>rc*,*.<fileext> set filetype=<name>
+*/);//}}}
+ rtItems.ftplugin.template = //{{{
+literal(/*" Vim filetype plugin file
+<header>
+
+if exists("b:did_ftplugin")
+ finish
+endif
+let b:did_ftplugin = 1
- if (file.exists() && file.isDirectory() || args[0] && /\/$/.test(args[0]))
- file.append(config.name + ".vim");
- dactyl.assert(!file.exists() || args.bang, _("io.exists"));
+let s:cpo_save = &cpo
+set cpo&vim
+
+let b:undo_ftplugin = "setl com< cms< fo< ofu< | unlet! b:browsefilter"
- let template = util.compileMacro(<![CDATA[
-" Vim syntax file
-" Language: Pentadactyl configuration file
-" Maintainer: Doug Kearns <dougkearns@gmail.com>
+setlocal comments=:\"
+setlocal commentstring=\"%s
+setlocal formatoptions-=t formatoptions+=croql
+setlocal omnifunc=syntaxcomplete#Complete
-" TODO: make this <name> specific - shared dactyl config?
+if has("gui_win32") && !exists("b:browsefilter")
+ let b:browsefilter = "<appname> Config Files (*.<fileext>)\t*.<fileext>\n" .
+ \ "All Files (*.*)\t*.*\n"
+endif
+
+let &cpo = s:cpo_save
+unlet s:cpo_save
+*/);//}}}
+ rtItems.syntax.template = //{{{
+literal(/*" Vim syntax file
+<header>
if exists("b:current_syntax")
finish
let &cpo = s:cpo_save
unlet s:cpo_save
-" vim: tw=130 et ts=4 sw=4:
-]]>, true);
+" vim: tw=130 et ts=8 sts=4 sw=4:
+*/);//}}}
+
+ const { options } = modules;
const WIDTH = 80;
- function wrap(prefix, items, sep) {
+ function wrap(prefix, items, sep) {//{{{
sep = sep || " ";
let width = 0;
let lines = [];
lines.last.push(item, sep);
}
lines.last.pop();
- return lines.map(function (l) l.join("")).join("\n").replace(/\s+\n/gm, "\n");
- }
-
- const { commands, options } = modules;
- file.write(template({
+ return lines.map(l => l.join(""))
+ .join("\n")
+ .replace(/\s+\n/gm, "\n");
+ }//}}}
+
+ let params = { //{{{
+ header: ['" Language: ' + config.appName + ' configuration file',
+ '" Maintainer: Doug Kearns <dougkearns@gmail.com>',
+ '" Version: ' + config.version].join("\n"),
name: config.name,
+ appname: config.appName,
+ fileext: config.fileExtension,
+ maintainer: "Doug Kearns <dougkearns@gmail.com>",
autocommands: wrap("syn keyword " + config.name + "AutoEvent ",
keys(config.autocommands)),
commands: wrap("syn keyword " + config.name + "Command ",
array(o.realNames for (o in options) if (o.type == "boolean"))
.flatten().map(String.quote),
", ") + "]"
- }));
+ }; //}}}
+
+ for (let { file, template } in values(rtItems)) {
+ try {
+ file.write(util.compileMacro(template, true)(params));
+ dactyl.echomsg(_("io.writing", file.path.quote()), 2);
+ }
+ catch (e) {
+ dactyl.echoerr(_("io.notWriteable", file.path.quote()));
+ dactyl.log(_("error.notWriteable", file.path, e.message));
+ }
+ }
}, {
argCount: "?",
bang: true,
- completer: function (context) completion.file(context, true),
+ completer: function (context) completion.directory(context, true),
literal: 1
});
commands.add(["scrip[tnames]"],
"List all sourced script names",
function () {
- let names = Object.keys(io._scriptNames);
+ let names = [k for (k of io._scriptNames)];
if (!names.length)
dactyl.echomsg(_("command.scriptnames.none"));
else
_("command.run.noPrevious"));
arg = arg.replace(/(\\)*!/g,
- function (m) /^\\(\\\\)*!$/.test(m) ? m.replace("\\!", "!") : m.replace("!", io._lastRunCommand)
- );
+ m => (/^\\(\\\\)*!$/.test(m) ? m.replace("\\!", "!")
+ : m.replace("!", io._lastRunCommand)));
}
io._lastRunCommand = arg;
result.output += "\n" + _("io.shellReturn", result.returnValue);
modules.commandline.command = args.commandName.replace("run", "$& ") + arg;
- modules.commandline.commandOutput(<span highlight="CmdOutput">{result.output}</span>);
+ modules.commandline.commandOutput(["span", { highlight: "CmdOutput" }, result.output]);
modules.autocommands.trigger("ShellCmdPost", {});
}, {
literal: 0
});
},
- completion: function init_completion(dactyl, modules, window) {
+ completion: function initCompletion(dactyl, modules, window) {
const { completion, io } = modules;
completion.charset = function (context) {
}
}
};
- context.generate = function () iter(services.charset.getDecoderList());
+ context.generate = () => iter(services.charset.getDecoderList());
};
completion.directory = function directory(context, full) {
this.file(context, full);
- context.filters.push(function (item) item.isdir);
+ context.filters.push(item => item.isdir);
};
completion.environment = function environment(context) {
context.title = ["Environment Variable", "Value"];
- context.generate = function ()
+ context.generate = () =>
io.system(config.OS.isWindows ? "set" : "env")
.output.split("\n")
- .filter(function (line) line.indexOf("=") > 0)
- .map(function (line) line.match(/([^=]+)=(.*)/).slice(1));
+ .filter(line => line.indexOf("=") > 0)
+ .map(line => line.match(/([^=]+)=(.*)/).slice(1));
};
completion.file = function file(context, full, dir) {
icon: function (f) this.isdir ? "resource://gre/res/html/folder.png"
: "moz-icon://" + f.leafName
};
- context.compare = function (a, b) b.isdir - a.isdir || String.localeCompare(a.text, b.text);
+ context.compare = (a, b) => b.isdir - a.isdir || String.localeCompare(a.text, b.text);
if (modules.options["wildignore"])
- context.filters.push(function (item) !modules.options.get("wildignore").getKey(item.path));
+ context.filters.push(item => !modules.options.get("wildignore").getKey(item.path));
// context.background = true;
context.key = dir;
};
completion.addUrlCompleter("file", "Local files", function (context, full) {
- let match = util.regexp(<![CDATA[
+ let match = util.regexp(literal(/*
^
(?P<prefix>
(?P<proto>
)
(?P<path> \/[^\/]* )?
$
- ]]>, "x").exec(context.filter);
+ */), "x").exec(context.filter);
if (match) {
if (!match.path) {
context.key = match.proto;
context.advance(match.proto.length);
- context.generate = function () config.chromePackages.map(function (p) [p, match.proto + p + "/"]);
+ context.generate = () => config.chromePackages.map(p => [p, match.proto + p + "/"]);
}
else if (match.scheme === "chrome") {
context.key = match.prefix;
completion.file(context, full);
});
},
- javascript: function init_javascript(dactyl, modules, window) {
+ javascript: function initJavascript(dactyl, modules, window) {
modules.JavaScript.setCompleter([File, File.expandPath],
[function (context, obj, args) {
context.quote[2] = "";
input: true
});
},
- options: function init_options(dactyl, modules, window) {
+ options: function initOptions(dactyl, modules, window) {
const { completion, options } = modules;
var shell, shellcmdflag;
"List of directories searched when executing :cd",
"stringlist", ["."].concat(services.environment.get("CDPATH").split(/[:;]/).filter(util.identity)).join(","),
{
- get files() this.value.map(function (path) File(path, modules.io.cwd))
- .filter(function (dir) dir.exists()),
+ get files() this.value.map(path => File(path, modules.io.cwd))
+ .filter(dir => dir.exists()),
setter: function (value) File.expandPathList(value)
});
"List of directories searched for runtime files",
"stringlist", IO.runtimePath,
{
- get files() this.value.map(function (path) File(path, modules.io.cwd))
- .filter(function (dir) dir.exists())
+ get files() this.value.map(path => File(path, modules.io.cwd))
+ .filter(dir => dir.exists())
});
options.add(["shell", "sh"],
} catch(e){ if (isString(e)) e = Error(e); dump(e.fileName+":"+e.lineNumber+": "+e+"\n" + e.stack); }
-// vim: set fdm=marker sw=4 ts=4 et ft=javascript:
+// vim: set fdm=marker sw=4 sts=4 ts=8 et ft=javascript: