diff --git a/content/commands.js b/content/commands.js index f739447c..1dabbd34 100644 --- a/content/commands.js +++ b/content/commands.js @@ -1293,6 +1293,62 @@ vimperator.Commands = function () //{{{ function (args) { vimperator.editor.removeAllAbbreviations("i"); }, { shortHelp: "Remove all abbreviations for Insert mode" } )); + commandManager.add(new vimperator.Command(["au[tocmd]"], + function (args, special) + { + if (!args) + { + if (special) // :au! + vimperator.autocommands.remove(null, null); + else // :au + vimperator.autocommands.list(null, null); + } + else + { + // (?: ) means don't store; (....)? <-> exclamation marks makes the group optional + var [all, asterix, auEvent, regex, cmds] = args.match(/^(\*)?(?:\s+)?(\S+)(?:\s+)?(\S+)?(?:\s+)?(.+)?$/); + + if (cmds) + { + vimperator.autocommands.add(auEvent, regex, cmds); + } + else if (regex) // e.g. no cmds provided + { + if (special) + vimperator.autocommands.remove(auEvent, regex); + else + vimperator.autocommands.list(auEvent, regex); + } + else if (auEvent) + { + if (asterix) + if (special) + vimperator.autocommands.remove(null, auEvent); // ':au! * auEvent' + else + vimperator.autocommands.list(null, auEvent); + else + if (special) + vimperator.autocommands.remove(auEvent, null); + else + vimperator.autocommands.list(auEvent, null); + } + } + }, + { + shortHelp: "Execute commands automatically on events", + help: ":au[tocmd] {event} {pat} {cmd}
" + + "Add {cmd} to the list of commands Vimperator will execute on {event}

" + + ":autocmd[!] {events} {pat}
" + + "list/remove autocommands filtered be {events} and {pat}
" + + ":autocmd[!] {events}
" + + "list/remove autocommands matching {events}
" + + ":autocmd[!] * {pat}
" + + "list/remove autocommands matching {pat}
" + + ":autocmd[!]
" + + "list/remove all autocommands", + completer: function (filter) { return vimperator.completion.autocommands(filter); } //TODO: improve + } + )); // 0 args -> list all maps // 1 arg -> list the maps starting with args // 2 args -> map arg1 to arg* @@ -1494,6 +1550,10 @@ vimperator.Commands = function () //{{{ } } + line += "\n\" Auto-Commands\n"; + for (var item in vimperator.autocommands) + line += "autocmd " + item + "\n"; + line += "\n\" Abbreviations\n"; for (var abbrCmd in vimperator.editor.abbreviations) line += abbrCmd; diff --git a/content/completion.js b/content/completion.js index 35ffae25..b9322875 100644 --- a/content/completion.js +++ b/content/completion.js @@ -129,7 +129,22 @@ vimperator.Completion = function () //{{{ } return longest; }, + autocommands: function (filter) + { + substrings = []; + var nodes = [ + ["onPageLoad", "when a page gets (re)loaded/opened"] + ]; + if (!filter) + return [0, nodes]; + + var mapped = nodes.map(function (node) { + return [[node[0]], node[1]]; + }); + + return [0, buildLongestCommonSubstring(mapped, filter)]; + }, dialog: function (filter) { substrings = []; diff --git a/content/events.js b/content/events.js index 78b7c886..a8b6436c 100644 --- a/content/events.js +++ b/content/events.js @@ -26,6 +26,149 @@ the provisions above, a recipient may use your version of this file under the terms of any one of the MPL, the GPL or the LGPL. }}} ***** END LICENSE BLOCK *****/ +vimperator.AutoCommands = function()//{{{ +{ + //////////////////////////////////////////////////////////////////////////////// + ////////////////////// PRIVATE SECTION ///////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////////{{{ + + var autoCommands = {}; + + function autoCommandsIterator() + { + for (var item in autoCommands) + for (var i = 0; i < autoCommands[item].length; i++) + yield item + " " + autoCommands[item][i][0] + " " + autoCommands[item][i][1]; + throw StopIteration; + } + + /////////////////////////////////////////////////////////////////////////////}}} + ////////////////////// PUBLIC SECTION ////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////////{{{ + + //TODO: maybe this.function rather than v.autocommands.function... + + return { + + __iterator__: function () + { + return autoCommandsIterator(); + }, + + remove: function (auEvent, regex) // arguments are filters (NULL = all) + { + if (!auEvent && !regex) + { + autoCommands = {}; // delete all TODO: rather delete.. or something? + } + else if (!regex) // remove all on this auEvent + { + for (var item in autoCommands) + { + if (item == auEvent) + delete autoCommands[item]; + } + } + else if (!auEvent) // delete all match's to this regex + { + for (var item in autoCommands) + { + var i = 0; + while (i < autoCommands[item].length) + { + if (regex == autoCommands[item][i][0]) + { + autoCommands[item].splice(i, 1); // remove array + // keep `i' since this is removed, so a possible next one is at this place now) + } + else + i++; + } + } + } + else // delete matching `auEvent && regex' items + { + for (var item in autoCommands) + { + if (item == auEvent) + { + for (var i = 0; i < autoCommands[item].length; i++) + { + if (regex == autoCommands[item][i][0]) + autoCommands[item].splice(i, 1); // remove array + } + } + } + } + }, + + list: function (auEvent, regex) // arguments are filters (NULL = all) + { + var flag; + var list = ""; + for (var item in autoCommands) + { + flag = true; + if (!auEvent || item == auEvent) // filter event + { + for (var i = 0; i < autoCommands[item].length; i++) + { + if (!regex || regex == autoCommands[item][i][0]) // filter regex + { + if (flag == true) + { + list += ""; + flag = false; + } + + list += ""; + list += ""; + list += ""; + list += ""; + } + } + } + } + + list += "
---- Auto-Commands ----
" + + vimperator.util.escapeHTML(item) + "
  " + vimperator.util.escapeHTML(autoCommands[item][i][0]) + "" + vimperator.util.escapeHTML(autoCommands[item][i][1]) + "
"; + vimperator.commandline.echo(list, vimperator.commandline.HL_NORMAL, vimperator.commandline.FORCE_MULTILINE); + }, + + add: function (auEvent, regex, cmds) + { + var eventsIter = auEvent.split(","); + for (var i = 0; i < eventsIter.length; i++) + { + if (!autoCommands[eventsIter[i]]) + autoCommands[eventsIter[i]] = []; + + var flag = true; + for (var y = 0; y < autoCommands[eventsIter[i]].length; y++) + { + if (autoCommands[eventsIter[i]][y][0] == regex && autoCommands[eventsIter[i]][y][1] == cmds) + flag = false; + } + if (flag) + autoCommands[eventsIter[i]].push([regex, cmds]); + } + }, + + trigger: function (auEvent, url) + { + if (autoCommands[auEvent]) + { + for (var i = 0; i < autoCommands[auEvent].length; i++) + { + var regex = new RegExp(autoCommands[auEvent][i][0]); + if (regex.test(url)) + vimperator.execute(autoCommands[auEvent][i][1]); + } + } + } + }; +}//}}} + vimperator.Events = function () //{{{ { //////////////////////////////////////////////////////////////////////////////// @@ -229,13 +372,16 @@ vimperator.Events = function () //{{{ } // code which should happen for all (also background) newly loaded tabs goes here: - vimperator.buffer.updateBufferList(); - //update history var url = vimperator.buffer.URL; var title = vimperator.buffer.title; + + //update history vimperator.history.add(url, title); + vimperator.buffer.updateBufferList(); + vimperator.autocommands.trigger("onPageLoad", url); + // mark the buffer as loaded, we can't use vimperator.buffer.loaded // since that always refers to the current buffer, while doc can be // any buffer, even in a background tab diff --git a/content/vimperator.js b/content/vimperator.js index 627def26..ccd6ec9d 100644 --- a/content/vimperator.js +++ b/content/vimperator.js @@ -615,6 +615,8 @@ const vimperator = (function () //{{{ vimperator.quickmarks = vimperator.QuickMarks(); vimperator.log("Loading module hints...", 3); vimperator.hints = vimperator.Hints(); + vimperator.log("Loading module autocommands...", 3); //XXX: what the 3 there, I didn't check + vimperator.autocommands = vimperator.AutoCommands(); vimperator.log("Loading module io...", 3); vimperator.io = vimperator.IO(); vimperator.log("Loading module completion...", 3);