diff --git a/NEWS b/NEWS index ed756d42..b5b4443a 100644 --- a/NEWS +++ b/NEWS @@ -7,6 +7,8 @@ special versions for the old behavior * IMPORTANT: renamed Startup and Quit autocmd events to VimperatorEnter and VimperatorLeave respectively + * add :doautocmd and :doautoall + * add :style and :delstyle commands * add DOMLoad autocmd event * add :messages and 'messages' * add :runtime @@ -28,8 +30,6 @@ * new ;b extended hint mode (thanks Daniel Schaffrath) * :qa! and :q! quit forcefully, as in vim * stop macro playback on - * allow ; hints to work in the multiline output widget - * add :style and :delstyle commands * many bug fixes 2008-08-16: diff --git a/content/completion.js b/content/completion.js index 31097bd4..a8b4daed 100644 --- a/content/completion.js +++ b/content/completion.js @@ -177,6 +177,12 @@ liberator.Completion = function () //{{{ return buildLongestCommonSubstring(array, filter); }, + autocommand: function (filter) + { + let autoCmds = liberator.config.autocommands; + return [0, this.filter(autoCmds, filter)]; + }, + // FIXME: items shouldn't be [[[a], b]], but [[a, b]] and only mapped if at all for bLCS --mst buffer: function (filter) { diff --git a/content/events.js b/content/events.js index c34221d0..cd9682db 100644 --- a/content/events.js +++ b/content/events.js @@ -32,13 +32,12 @@ liberator.AutoCommands = function () //{{{ ////////////////////// PRIVATE SECTION ///////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////{{{ - var autoCommands = {}; + var store = []; - function autoCommandsIterator() + function matchAutoCmd(autoCmd, event, regex) { - for (let item in autoCommands) - for (let i = 0; i < autoCommands[item].length; i++) - yield item + " " + autoCommands[item][i][0] + " " + autoCommands[item][i][1]; + return (!event || autoCmd.event == event) && + (!regex || autoCmd.pattern.source == regex); } /////////////////////////////////////////////////////////////////////////////}}} @@ -53,7 +52,7 @@ liberator.AutoCommands = function () //{{{ validator: function (value) { let values = value.split(","); - let events = liberator.config.autocommands.map(function (e) e[0]); + let events = liberator.config.autocommands.map(function (event) event[0]); events.push("all"); @@ -75,136 +74,158 @@ liberator.AutoCommands = function () //{{{ { if (!args) { - if (special) // :au! - liberator.autocommands.remove(null, null); - else // :au - liberator.autocommands.list(null, null); + if (special) + liberator.autocommands.remove(null, null); // remove all + else + liberator.autocommands.list(null, null); // list all } else { - // (?: ) means don't store; (....)? <-> exclamation marks makes the group optional - var [all, asterix, auEvent, regex, cmds] = args.match(/^(\*)?(?:\s+)?(\S+)(?:\s+)?(\S+)?(?:\s+)?(.+)?$/); + // TODO: assume the pattern doesn't contain spaces until we have whitespace escaping + let [, event, regex, cmd] = args.match(/^(\S+)?(?:\s+)?(\S+)?(?:\s+)?(.+)?$/); - if (cmds) + // NOTE: event can only be a comma separated list for |:au {event} {pat} {cmd}| + let events = event.split(","); + let validEvents = liberator.config.autocommands.map(function (event) event[0]); + + validEvents.push("*"); + + if (!events.every(function (event) validEvents.indexOf(event) >= 0)) { - liberator.autocommands.add(auEvent, regex, cmds); + liberator.echoerr("E216: No such group or event: " + args); + return; } - else if (regex) // e.g. no cmds provided + + if (cmd) // add new command, possibly removing all others with the same event/pattern { if (special) - liberator.autocommands.remove(auEvent, regex); - else - liberator.autocommands.list(auEvent, regex); + liberator.autocommands.remove(event, regex); + + liberator.autocommands.add(events, regex, cmd); } - else if (auEvent) + else if (regex) { - if (asterix) - if (special) - liberator.autocommands.remove(null, auEvent); // ':au! * auEvent' - else - liberator.autocommands.list(null, auEvent); + if (special) + liberator.autocommands.remove(event == "*" ? null : event, regex); else - if (special) - liberator.autocommands.remove(auEvent, null); - else - liberator.autocommands.list(auEvent, null); + liberator.autocommands.list(event == "*" ? null : event, regex); + } + else if (event) + { + if (special) + { + // TODO: "*" only appears to work in Vim when there is a {group} specified + if (event != "*") + liberator.autocommands.remove(event, null); + } + else + { + liberator.autocommands.list(event == "*" ? null : event, null); + } } } }, { bangAllowed: true, - completer: function (filter) - { - return [0, liberator.completion.filter(liberator.config.autocommands || [], filter)]; - } + completer: function (filter) liberator.completion.autocommand(filter) }); + // TODO: expand target to all buffers + liberator.commands.add(["doauto[all]"], + "Apply the autocommands matching the specified URL pattern to all buffers", + function (args) + { + liberator.commands.get("doautocmd").action.call(this, args); + }, + { + argCount: "+", + completer: function (filter) liberator.completion.autocommand(filter) + } + ); + + // TODO: restrict target to current buffer + liberator.commands.add(["do[autocmd]"], + "Apply the autocommands matching the specified URL pattern to the current buffer", + function (args) + { + args = args.string; + + let [, event, url] = args.match(/^(\S+)(?:\s+(\S+))?$/); + url = url || liberator.buffer.URL; + + let validEvents = liberator.config.autocommands.map(function (e) e[0]); + + if (event == "*") + { + liberator.echoerr("E217: Can't execute autocommands for ALL events"); + } + else if (validEvents.indexOf(event) == -1) + { + liberator.echoerr("E216: No such group or event: " + args); + } + else + { + // TODO: perhaps trigger could return the number of autocmds triggered + if (!liberator.autocommands.get(event).some(function (c) c.pattern.test(url))) + liberator.echo("No matching autocommands"); + else + liberator.autocommands.trigger(event, url); + } + }, + { + // TODO: Vim actually just displays "No matching autocommands" when no arg is specified + argCount: "+", + completer: function (filter) liberator.completion.autocommand(filter) + } + ); + /////////////////////////////////////////////////////////////////////////////}}} ////////////////////// PUBLIC SECTION ////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////{{{ - //TODO: maybe this.function rather than v.autocommands.function... - return { __iterator__: function () { - return autoCommandsIterator(); + for (let i = 0; i < store.length; i++) + yield autoCmd[i]; }, - add: function (auEvent, regex, cmds) + add: function (events, regex, cmd) { - var eventsIter = auEvent.split(","); - for (let i = 0; i < eventsIter.length; i++) + if (typeof events == "string") { - if (!autoCommands[eventsIter[i]]) - autoCommands[eventsIter[i]] = []; - - var flag = true; - for (let j = 0; j < autoCommands[eventsIter[i]].length; j++) - { - if (autoCommands[eventsIter[i]][j][0] == regex && autoCommands[eventsIter[i]][j][1] == cmds) - { - flag = false; - break; - } - } - if (flag) - autoCommands[eventsIter[i]].push([regex, cmds, new RegExp(regex)]); + events = events.split(","); + liberator.log("DEPRECATED: the events list arg to autocommands.add() should be an array of event names"); } + + events.forEach( + function (event) { store.push({event: event, pattern: RegExp(regex), command: cmd}); } + ); }, - remove: function (auEvent, regex) // arguments are filters (NULL = all) + get: function (event, regex) { - if (!auEvent && !regex) - { - autoCommands = {}; // delete all - } - else if (!regex) // remove all on this auEvent - { - for (let item in autoCommands) - { - if (item == auEvent) - delete autoCommands[item]; - } - } - else if (!auEvent) // delete all matches to this regex - { - for (let 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 (let item in autoCommands) - { - if (item == auEvent) - { - for (let i = 0; i < autoCommands[item].length; i++) - { - if (regex == autoCommands[item][i][0]) - autoCommands[item].splice(i, 1); // remove array - } - } - } - } + return store.filter(function (autoCmd) matchAutoCmd(autoCmd, event, regex)); }, - list: function (auEvent, regex) // arguments are filters (NULL = all) + remove: function (event, regex) { - let cmds = (item for (item in Iterator(autoCommands)) - if ((!auEvent || item[0] == auEvent) && item[1].length)); + store = store.filter(function (autoCmd) !matchAutoCmd(autoCmd, event, regex)); + }, + + list: function (event, regex) + { + let cmds = {}; + + // XXX + store.forEach(function (autoCmd) { + if (matchAutoCmd(autoCmd, event, regex)) + { + cmds[autoCmd.event] = cmds[autoCmd.event] || []; + cmds[autoCmd.event].push(autoCmd); + } + }); var list = liberator.template.generic( @@ -219,8 +240,8 @@ liberator.AutoCommands = function () //{{{ + liberator.template.map(items, function (item) - - + + )) }
 {item[0]}{item[1]} {item.pattern.source}{item.command}
); @@ -228,26 +249,30 @@ liberator.AutoCommands = function () //{{{ liberator.commandline.echo(list, liberator.commandline.HL_NORMAL, liberator.commandline.FORCE_MULTILINE); }, - trigger: function (auEvent, url) + trigger: function (event, url) { let events = liberator.options["eventignore"].split(","); - if (events.some(function (event) event == "all" || event == auEvent)) + if (events.some(function (e) e == "all" || e == event)) return; - liberator.echomsg("Executing " + auEvent + " Auto commands for \"*\"", 8); + let autoCmds = store.filter(function (autoCmd) autoCmd.event == event); - if (autoCommands[auEvent]) + liberator.echomsg("Executing " + event + " Auto commands for \"*\"", 8); + + let lastPattern = null; + + for (let [,autoCmd] in Iterator(autoCmds)) { - for (let i = 0; i < autoCommands[auEvent].length; i++) + if (autoCmd.pattern.test(url)) { - if (autoCommands[auEvent][i][2].test(url)) - { - liberator.echomsg("Executing " + auEvent + " Auto commands for \"" - + autoCommands[auEvent][i][2] + "\"", 8); - liberator.echomsg("autocommand " + autoCommands[auEvent][i][1], 9); - liberator.execute(autoCommands[auEvent][i][1]); - } + if (!lastPattern || lastPattern.source != autoCmd.pattern.source) + liberator.echomsg("Executing " + event + " Auto commands for \"" + autoCmd.pattern.source + "\"", 8); + + lastPattern = autoCmd.pattern; + + liberator.echomsg("autocommand " + autoCmd.command, 9); + liberator.execute(autoCmd.command); } } } diff --git a/content/io.js b/content/io.js index 81978f6f..d1976a80 100644 --- a/content/io.js +++ b/content/io.js @@ -244,7 +244,7 @@ liberator.IO = function () //{{{ // :mkvimrc doesn't save autocommands, so we don't either - remove this code at some point // line += "\n\" Auto-Commands\n"; // for (let item in liberator.autocommands) - // line += "autocmd " + item + "\n"; + // line += "autocmd " + item.event + " " + item.pattern.source + " " + item.command + "\n"; line += "\n\" Abbreviations\n"; for (let abbrCmd in liberator.editor.abbreviations) diff --git a/locale/en-US/autocommands.txt b/locale/en-US/autocommands.txt index 4b5b10cc..ac5340cc 100644 --- a/locale/en-US/autocommands.txt +++ b/locale/en-US/autocommands.txt @@ -38,6 +38,22 @@ Warning: Autocommand events are, in general, currently only fired when Vimperator commands are executed. ________________________________________________________________________________ + +|:doautoa| |:doautoall| +||:doautocmda[ll] {event} [url]|| + +________________________________________________________________________________ +Apply the autocommands matching the specified URL to all buffers. If no [url] +is specified use the current URL. +________________________________________________________________________________ + + +|:do| |:doautocmd| +||:do[autocmd] {event} [url]|| + +________________________________________________________________________________ +Apply the autocommands matching the specified URL to the current buffer. If no +[url] is specified use the current URL. +________________________________________________________________________________ + section:Examples[autocmd-examples] Enable _passthrough_ mode on all Google sites: diff --git a/locale/en-US/index.txt b/locale/en-US/index.txt index d89213ea..df57addf 100644 --- a/locale/en-US/index.txt +++ b/locale/en-US/index.txt @@ -159,6 +159,8 @@ section:Ex{nbsp}commands[ex-cmd-index,:index] ||:delmarks|| Delete the specified marks + ||:delqmarks|| Delete the specified QuickMarks + ||:dialog|| Open a undefined dialog + +||:doautoall|| Apply the autocommands matching the specified URL to all buffers + +||:doautocmd|| Apply the autocommands matching the specified URL to the current buffer + ||:downloads|| Show progress of current downloads + ||:echo|| Display a string at the bottom of the window + ||:echoerr|| Display an error string at the bottom of the window + diff --git a/vimperator.vim b/vimperator.vim index 5958288b..b5a1a5c1 100644 --- a/vimperator.vim +++ b/vimperator.vim @@ -1,7 +1,7 @@ " Vim syntax file " Language: VIMperator configuration file " Maintainer: Doug Kearns -" Last Change: 2008 Oct 4 +" Last Change: 2008 Oct 5 if exists("b:current_syntax") finish @@ -17,16 +17,16 @@ syn match vimperatorCommandStart "\%(^\s*:\=\)\@<=" nextgroup=vimperatorCommand, syn keyword vimperatorCommand ab[breviate] ab[clear] addo[ns] b[uffer] ba[ck] bd[elete] beep bf[irst] bl[ast] bma[rk] bmarks \ bn[ext] bN[ext] bp[revious] br[ewind] buffers bun[load] bw[ipeout] ca[bbrev] cabc[lear] cd chd[ir] cuna[bbrev] cm[ap] - \ cmapc[lear] cno[remap] comc[lear] com[mand] cu[nmap] delbm[arks] delc[ommand] delmac[ros] delm[arks] delqm[arks] dels[tyle] - \ dia[log] dl downl[oads] e[dit] ec[ho] echoe[rr] echom[sg] em[enu] exe[cute] exu[sage] fini[sh] files fo[rward] fw h[elp] - \ ha[rdcopy] hist[ory] hs ia[bbrev] iabc[lear] im[ap] imapc[lear] ino[remap] iuna[bbrev] iu[nmap] javas[cript] ju[mps] js let - \ ls macros ma[rk] map mapc[lear] marks mes[sages] mkv[imperatorrc] no[remap] noh[lsearch] norm[al] o[pen] pa[geinfo] - \ pagest[yle] pc[lose] pl[ay] pref[erences] prefs pw[d] q[uit] qa[ll] qma[rk] qmarks quita[ll] re[draw] re[load] reloada[ll] - \ res[tart] run ru[ntime] sty[le] sav[eas] sb[ar] sb[open] sbcl[ose] scrip[tnames] se[t] setg[lobal] setl[ocal] sideb[ar] - \ so[urce] st[op] tN[ext] t[open] tab tabde[tach] tabd[uplicate] tabN[ext] tabc[lose] tabe[dit] tabfir[st] tabl[ast] tabm[ove] - \ tabn[ext] tabnew tabo[nly] tabopen tabp[revious] tabr[ewind] tabs time tn[ext] tp[revious] u[ndo] una[bbreviate] undoa[ll] - \ unl[et] unm[ap] ve[rsion] vie[wsource] viu[sage] w[rite] wc[lose] win[open] winc[lose] wine[dit] wo[pen] wqa[ll] wq xa[ll] - \ zo[om] + \ cmapc[lear] cno[remap] comc[lear] com[mand] cu[nmap] do[autocmd] doautoa[ll] delbm[arks] delc[ommand] delmac[ros] delm[arks] + \ delqm[arks] dels[tyle] dia[log] dl downl[oads] e[dit] ec[ho] echoe[rr] echom[sg] em[enu] exe[cute] exu[sage] fini[sh] files + \ fo[rward] fw h[elp] ha[rdcopy] hist[ory] hs ia[bbrev] iabc[lear] im[ap] imapc[lear] ino[remap] iuna[bbrev] iu[nmap] + \ javas[cript] ju[mps] js let ls macros ma[rk] map mapc[lear] marks mes[sages] mkv[imperatorrc] no[remap] noh[lsearch] + \ norm[al] o[pen] pa[geinfo] pagest[yle] pc[lose] pl[ay] pref[erences] prefs pw[d] q[uit] qa[ll] qma[rk] qmarks quita[ll] + \ re[draw] re[load] reloada[ll] res[tart] run ru[ntime] sty[le] sav[eas] sb[ar] sb[open] sbcl[ose] scrip[tnames] se[t] + \ setg[lobal] setl[ocal] sideb[ar] so[urce] st[op] tN[ext] t[open] tab tabde[tach] tabd[uplicate] tabN[ext] tabc[lose] + \ tabe[dit] tabfir[st] tabl[ast] tabm[ove] tabn[ext] tabnew tabo[nly] tabopen tabp[revious] tabr[ewind] tabs time tn[ext] + \ tp[revious] u[ndo] una[bbreviate] undoa[ll] unl[et] unm[ap] ve[rsion] vie[wsource] viu[sage] w[rite] wc[lose] win[open] + \ winc[lose] wine[dit] wo[pen] wqa[ll] wq xa[ll] zo[om] \ contained syn match vimperatorCommand "!" contained