From 3ddfb11add952be84f5e184d3baab8c4e7d522a3 Mon Sep 17 00:00:00 2001 From: Viktor Kojouharov Date: Sun, 22 Apr 2007 14:17:28 +0000 Subject: [PATCH] ex parser for use with .vimperatorrc, the command line and other sourced files. sourced files are no longer javascript code, but can use the new :javascript ex command to execute javascript. :javascript also supports multiline with heredocs (:js <eval().
"+ - ":exec alert('Hello world') would show a dialog box with the text \"Hello world\".
"+ - "The special version :execute! will open the javascript console of Firefox.", - function(args, special) { - if (special) // open javascript console - openURLsInNewTab("chrome://global/content/console.xul", true); - else - eval(args); - }, + "Executes a string as an Ex command", + "Usage: :execute {expr1} [ ... ]
" + + "Executes the string that results from the evaluation of {expr1} as an Ex command.
"+ + ":execute "echo test" would show a message with the text "test".
", + execute, null ], [ @@ -174,6 +169,21 @@ var g_commands = [/*{{{*/ hsshow, function(filter) { return get_history_completions(filter); } ], + [ + ["javascript", "js"], + "Run any javascript command through eval()", + "Acts as a javascript interpreter by passing the argument to eval().
" + + ":javascript alert('Hello world') would show a dialog box with the text \"Hello world\".
" + + ":javascript <<EOF would read all the lines until a line starting with 'EOF' is found, and will eval() them.
" + + "The special version :javascript! will open the javascript console of Firefox.", + function(args, special) { + if (special) // open javascript console + openURLsInNewTab("chrome://global/content/console.xul", true); + else + eval(args); + }, + null + ], [ ["mark"], "Mark current location within the webpage", @@ -286,7 +296,7 @@ var g_commands = [/*{{{*/ "The .vimperatorrc file in your home directory is always sourced at start up.
"+ "~ is supported as a shortcut for the $HOME directory.", source, - null + function (filter) { return get_file_completions(filter); } ], [ ["tabnext", "tn", "tnext"], @@ -910,6 +920,7 @@ function get_command(cmd) // {{{ function execute_command(count, cmd, special, args) // {{{ { + if (!cmd) return; var command = get_command(cmd); if (command == null) { @@ -929,6 +940,86 @@ function execute_command(count, cmd, special, args) // {{{ } // }}} +function tokenize_ex(string, tag) +{ + // removing commends + string.replace(/\s*".*$/, ''); + if (tag) + { + if (string == tag) + return [null, null, null, null, false]; + else + return [null, null, null, string, tag]; + } + + // 0 - count, 1 - cmd, 2 - special, 3 - args, 4 - heredoc tag + var matches = string.match(/^:*(\d+)?([a-zA-Z]+)(!)?(?:\s+(.*?))?$/); + if (!matches) return [null, null, null, null, null]; + matches.shift(); + + if (matches[0]) + { + matches[0] = parseInt(matches[0]); + if (isNaN(matches[0])) matches[0] = 0; + } + else matches[0] = 0; + matches[2] = !!matches[2]; + matches.push(null); + if (matches[3]) + { + tag = matches[3].match(/<<\s*(\w+)/); + if (tag && tag[1]) + matches[4] = tag[1]; + } + else matches[3] = ''; + + return matches; +} + +function multiliner(line, prev_match, heredoc) +{ + var end = true; + var match = tokenize_ex(line, prev_match[4]); + if (prev_match[3] === undefined) prev_match[3] = ''; + if (match[4] === null) + { + focusContent(false, true); // also sets comp_tab_index to -1 + execute_command.apply(this, match); + } + else + { + if (match[4] === false) + { + prev_match[3] = prev_match[3].replace(new RegExp('<<\s*' + prev_match[4]), heredoc.replace(/\n$/, '')); + execute_command.apply(this, prev_match); + prev_match = new Array(5); + prev_match[3] = ''; + heredoc = ''; + } + else + { + end = false; + if (!prev_match[3]) + { + prev_match[0] = match[0]; + prev_match[1] = match[1]; + prev_match[2] = match[2]; + prev_match[3] = match[3]; + prev_match[4] = match[4]; + } + else + { + heredoc += match[3] + '\n'; + } + } + } + return [prev_match, heredoc, end]; +} + +function execute(string) +{ + return execute_command.apply(this, tokenize_ex(string.replace(/^'(.*)'$/, '$1'))); +} //////////////////////////////////////////////////////////////////////// // statusbar/commandbar handling ////////////////////////////////// {{{1 //////////////////////////////////////////////////////////////////////// @@ -1628,7 +1719,12 @@ function source(filename, silent) var s = fd.read(); fd.close(); - eval(s); + var prev_match = new Array(5); + var heredoc = ''; + var end = false; + s.split('\n').forEach(function (line) { + [prev_match, heredoc, end] = multiliner(line, prev_match, heredoc); + }); } catch(e) { @@ -1637,7 +1733,6 @@ function source(filename, silent) } } - function help(section, easter) { if (easter) diff --git a/chrome/content/vimperator/completion.js b/chrome/content/vimperator/completion.js index 3f85585f..101af0ec 100644 --- a/chrome/content/vimperator/completion.js +++ b/chrome/content/vimperator/completion.js @@ -180,6 +180,27 @@ function completion_select_previous_item()/*{{{*/ }/*}}}*/ +function get_file_completions(filter)/*{{{*/ +{ + g_completions = []; + + var match = filter.match(/^(.*[\/\\])(.*?)$/); + var dir; + if (!match || !(dir = match[1])) return []; + var compl = match[2] || ''; + var fd = fopen(dir, "<"); + if (!fd) return []; + var entries = fd.read(); + var delim = (fd.path.search(/\\/) != -1) ? "\\" : "/"; + var reg = new RegExp("^" + fd.path + delim + compl); + entries.forEach(function(file) { + if (file.path.search(reg) != -1) + g_completions.push([file.path]); + }); + + return g_completions; +}/*}}}*/ + /* * filter a list of urls diff --git a/chrome/content/vimperator/file.js b/chrome/content/vimperator/file.js index 2f404614..df96f35e 100644 --- a/chrome/content/vimperator/file.js +++ b/chrome/content/vimperator/file.js @@ -129,6 +129,19 @@ function fo_write(buf) LocalFile.prototype.read = function fo_read(max) { + if (this.localFile.isDirectory()) + { + var entries = this.localFile.directoryEntries; + var array = []; + while(entries.hasMoreElements()) + { + var entry = entries.getNext(); + entry.QueryInterface(Components.interfaces.nsIFile); + array.push(entry); + } + return array; + } + if (!("inputStream" in this)) throw "file not open for reading."; diff --git a/chrome/content/vimperator/settings.js b/chrome/content/vimperator/settings.js index 5af96cb2..62e69043 100644 --- a/chrome/content/vimperator/settings.js +++ b/chrome/content/vimperator/settings.js @@ -63,17 +63,6 @@ var g_settings = [/*{{{*/ null, null ], - [ - ["completeopt", "cot"], - "Define how command line completion works", - "Not implemented yet.", - function(value) { set_pref("completeopt", value); }, - function() { return get_pref("completeopt"); }, - "stringlist", - "menu", - null, - null - ], [ ["extendedhinttags", "eht"], "XPath string of hintable elements activated by ';'", @@ -221,6 +210,17 @@ var g_settings = [/*{{{*/ false, null, null + ], + [ + ["wildmode", "wim"], + "Define how command line completion works", + "Not implemented yet.", + function(value) { set_pref("wildmode", value); }, + function() { return get_pref("wildmode"); }, + "stringlist", + "menu", + null, + null ] ]/*}}}*/ diff --git a/chrome/content/vimperator/vimperator.js b/chrome/content/vimperator/vimperator.js index fefb31c6..fb545868 100644 --- a/chrome/content/vimperator/vimperator.js +++ b/chrome/content/vimperator/vimperator.js @@ -45,6 +45,10 @@ var g_inputbuffer = ""; // here we store partial commands (e.g. 'g' if you want var g_count = -1; // the parsed integer of g_inputbuffer, or -1 if no count was given var g_bufshow = false; // keeps track if the preview window shows current buffers ('B') +// handles multi-line commands +var prev_match = new Array(5); +var heredoc = ''; + // handles to our gui elements var preview_window = null; var status_line = null; @@ -83,7 +87,7 @@ nsBrowserStatusHandler.prototype = setOverLink : function(link, b) { - echo(link); + updateStatusbar(link); if (link == "") showMode(); @@ -518,45 +522,24 @@ function onVimperatorKeypress(event)/*{{{*/ updateStatusbar(); return false; }/*}}}*/ + function onCommandBarKeypress(evt)/*{{{*/ { + var end = false; try { /* parse our command string into tokens */ var command = command_line.value; - var matches1 = command.match(/^:(\d+)/); - var matches2 = command.match(/^:(\d+)?([a-zA-Z!]+)/); - var matches3 = command.match(/^:(\d+)?([a-zA-Z!]+)\s*(.*?)\s*$/); - var count = 0; - var cmd = ""; - var args= ""; - var special = false; - - if (matches1 != null && matches1.length == 2) - count = parseInt(matches1[1], 10); - if (matches2 != null && matches2.length >= 3) - cmd = matches2[2]; - if (matches3 != null && matches3.length >= 4) - args = matches3[3]; - - /* if the user executes a command with ! at the end */ - if (cmd.length - 1 == cmd.lastIndexOf("!")) - { - special = true; - cmd = cmd.replace(/!$/, ""); - } - else - special = false; - /* user pressed ENTER to carry out a command */ if (evt.keyCode == KeyEvent.DOM_VK_RETURN) { // unfocus command line first - focusContent(false, true); // also sets comp_tab_index to -1 add_to_command_history(command); - execute_command(count, cmd, special, args); + [prev_match, heredoc, end] = multiliner(command, prev_match, heredoc); + if (!end) + command_line.value = ""; } else if ((evt.keyCode == KeyEvent.DOM_VK_ESCAPE) || @@ -606,6 +589,8 @@ function onCommandBarKeypress(evt)/*{{{*/ /* user pressed TAB to get completions of a command */ else if (evt.keyCode == KeyEvent.DOM_VK_TAB) { + var match = tokenize_ex(command); + var [count, cmd, special, args] = match; //always reset our completion history so up/down keys will start with new values comp_history_index = -1; @@ -714,6 +699,17 @@ function onCommandBarInput(event) command_line.value = ":"; } +function onCommandBarMouseDown(event) +{ + if (command_line.value.indexOf(':') != 0) + { + command_line.blur(); + event.preventDefault(); + event.stopPropagation(); + return false; + } +} + //////////////////////////////////////////////////////////////////////// // focus and mode handling //////////////////////////////////////// {{{1 //////////////////////////////////////////////////////////////////////// @@ -802,12 +798,12 @@ function setStatusbarColor(color) bar.setAttribute("style", "background-color: " + color); } -function updateStatusbar() +function updateStatusbar(message) { var buffers = "[" + (gBrowser.tabContainer.selectedIndex + 1).toString() + "/" + gBrowser.tabContainer.childNodes.length.toString() + "]"; - showStatusbarMessage(getCurrentLocation(), STATUSFIELD_URL); + showStatusbarMessage(message || getCurrentLocation(), STATUSFIELD_URL); showStatusbarMessage(" " + g_inputbuffer + " ", STATUSFIELD_INPUTBUFFER); showStatusbarMessage("", STATUSFIELD_PROGRESS); showStatusbarMessage(buffers, STATUSFIELD_BUFFERS); diff --git a/chrome/content/vimperator/vimperator.xul b/chrome/content/vimperator/vimperator.xul index d2dec2f9..d8822729 100644 --- a/chrome/content/vimperator/vimperator.xul +++ b/chrome/content/vimperator/vimperator.xul @@ -79,7 +79,7 @@ the terms of any one of the MPL, the GPL or the LGPL.