diff --git a/chrome/content/vimperator/editor.js b/chrome/content/vimperator/editor.js index 845b6284..cbd3c220 100644 --- a/chrome/content/vimperator/editor.js +++ b/chrome/content/vimperator/editor.js @@ -19,6 +19,10 @@ function Editor() //{{{ { + // store our last search with f,F,t or T + var last_findChar = null; + var last_findChar_func = null; + function editor() { return window.document.commandDispatcher.focusedElement; @@ -33,6 +37,29 @@ function Editor() //{{{ return el.controllers.getControllerAt(0); } + this.line = function() + { + var line = 1; + var text = editor().value; + for (var i = 0; i < editor().selectionStart; i++) + if (text[i] == "\n") + line++; + return line; + } + + this.col = function() + { + var col = 1; + var text = editor().value; + for (var i = 0; i < editor().selectionStart; i++) + { + col++; + if (text[i] == "\n") + col = 1; + } + return col; + } + this.unselectText = function() { var elt = window.document.commandDispatcher.focusedElement; @@ -40,6 +67,12 @@ function Editor() //{{{ return true; } + this.selectedText = function() + { + var text = editor().value; + return text.substring(editor().selectionStart, editor().selectionEnd); + } + this.pasteClipboard = function() { var elt = window.document.commandDispatcher.focusedElement; @@ -86,9 +119,6 @@ function Editor() //{{{ { controller.doCommand(cmd); did_command = true; - - if (vimperator.hasMode(vimperator.modes.TEXTAREA)) - this.moveCaret(); } catch(e) { @@ -101,47 +131,195 @@ function Editor() //{{{ return true; } + // cmd = y, d, c + // motion = b, 0, gg, G, etc. + this.executeCommandWithMotion = function(cmd, motion, count) + { + if (!typeof count == "number" || count < 1) + count = 1; + + if (cmd == motion) + { + motion = "j"; + count--; + } + + switch (motion) + { + case "j": + this.executeCommand("cmd_beginLine", 1); + this.executeCommand("cmd_selectLineNext", count+1); + break; + case "k": + this.executeCommand("cmd_beginLine", 1); + this.executeCommand("cmd_lineNext", 1); + this.executeCommand("cmd_selectLinePrevious", count+1); + break; + case "h": + this.executeCommand("cmd_selectCharPrevious", count); + break; + case "l": + this.executeCommand("cmd_selectCharNext", count); + break; + case "e": + case "w": + this.executeCommand("cmd_selectWordNext", count); + break; + case "b": + this.executeCommand("cmd_selectWordPrevious", count); + break; + case "0": + case "^": + this.executeCommand("cmd_selectBeginLine", 1); + break; + case "$": + this.executeCommand("cmd_selectEndLine", 1); + break; + case "gg": + this.executeCommand("cmd_endLine", 1); + this.executeCommand("cmd_selectTop", 1); + this.executeCommand("cmd_selectBeginLine", 1); + break; + case "G": + this.executeCommand("cmd_beginLine", 1); + this.executeCommand("cmd_selectBottom", 1); + this.executeCommand("cmd_selectEndLine", 1); + break; + + default: + vimperator.beep(); + return false; + } + + switch (cmd) + { + case "d": + this.executeCommand("cmd_delete", 1); + // need to reset the mode as the visual selection changes it + vimperator.setMode(vimperator.modes.TEXTAREA); + break; + case "c": + this.executeCommand("cmd_delete", 1); + this.startInsert(); + break; + case "y": + this.executeCommand("cmd_copy", 1); + this.unselectText(); + break; + + default: + vimperator.beep(); + return false; + } + return true; + } this.startNormal = function() { vimperator.setMode(vimperator.modes.TEXTAREA); - this.moveCaret(); - } - this.startVisual = function() - { - vimperator.setMode(vimperator.modes.VISUAL, vimperator.modes.TEXTAREA); + //var self = this; + //editor().addEventListener("mouseclick", function() { + // setTimeout(function() { + // pos = editor().selectionStart; + // self.moveCaret(pos); + // }, 10); + //}, false); } this.startInsert = function() { vimperator.setMode(vimperator.modes.INSERT, vimperator.modes.TEXTAREA); - this.moveCaret(); } - this.stopInsert = function() + // This function will move/select up to given "pos" + // Simple setSelectionRange() would be better, but we want to maintain the correct + // order of selectionStart/End (a firefox bug always makes selectionStart <= selectionEnd) + // Use only for small movements! + this.moveToPosition = function(pos, forward, select) { - vimperator.setMode(vimperator.modes.TEXTAREA); - this.moveCaret(); + if (!select) + { + editor().setSelectionRange(pos, pos); + return; + } + + if (forward) + { + if (pos <= editor().selectionEnd || pos > editor().value.length) + return false; + + do // TODO: test code for endless loops + { + this.executeCommand("cmd_selectCharNext", 1); + } + while ( editor().selectionEnd != pos ); + } + else + { + if (pos >= editor().selectionStart || pos < 0) + return false; + + do // TODO: test code for endless loops + { + this.executeCommand("cmd_selectCharPrevious", 1); + } + while ( editor().selectionStart != pos ); + } } - // very rudimentary testing code - this.moveCaret = function(pos) + // returns the position of char + this.findCharForward = function(char, count) { - if (!pos) - pos = editor().selectionStart - 1; + if (!editor()) + return -1; - if (!vimperator.hasMode(vimperator.modes.INSERT)) - editor().setSelectionRange(pos, pos+1); - else if (!vimperator.hasMode(vimperator.modes.VISUAL)) - editor().setSelectionRange(pos, pos); + last_findChar = char; + last_findChar_func = this.findCharForward; + + var text = editor().value; + if (!typeof count == "number" || count < 1) + count = 1; + + for (var i = editor().selectionEnd + 1; i < text.length; i++) + { + if (text[i] == "\n") + break; + if (text[i] == char) + count--; + if (count == 0) + return i + 1; // always position the cursor after the char + } + + vimperator.beep(); + return -1; + } + // returns the position of char + this.findCharBackward = function(char, count) + { + if (!editor()) + return -1; + + last_findChar = char; + last_findChar_func = this.findCharBackward; + + var text = editor().value; + if (!typeof count == "number" || count < 1) + count = 1; + + for (var i = editor().selectionStart - 1; i >= 0; i--) + { + if (text[i] == "\n") + break; + if (text[i] == char) + count--; + if (count == 0) + return i; + } + + vimperator.beep(); + return -1; } - // cmd = y, d, c - // motion = b, 0, gg, G, etc. - this.executeCommandWithMotion = function(cmd, motion) - { - - } } //}}} // vim: set fdm=marker sw=4 ts=4 et: diff --git a/chrome/content/vimperator/events.js b/chrome/content/vimperator/events.js index 19dd2f9a..0d9e67dc 100644 --- a/chrome/content/vimperator/events.js +++ b/chrome/content/vimperator/events.js @@ -64,9 +64,6 @@ function Events() //{{{ // this adds an event which is is called on each page load, even if the // page is loaded in a background tab getBrowser().addEventListener("load", onPageLoad, true); - // to keep track if we are in a text field - //getBrowser().addEventListener("focus", onFocus, true); - //getBrowser().addEventListener("focus", onFocus, true); // called when the active document is scrolled getBrowser().addEventListener("scroll", function (event) @@ -75,12 +72,10 @@ function Events() //{{{ vimperator.setMode(); // trick to reshow the mode in the command line }, null); - // + + ///////////////////////////////////////////////////////// // track if a popup is open or the menubar is active - // - var active_menubar = false; - function enterPopupMode(event) { if (event.originalTarget.localName == "tooltip" || event.originalTarget.id == "vimperator-visualbell") @@ -88,35 +83,31 @@ function Events() //{{{ vimperator.addMode(null, vimperator.modes.MENU); } - function exitPopupMode() { // gContextMenu is set to NULL by firefox, when a context menu is closed if (!gContextMenu && !active_menubar) vimperator.removeMode(null, vimperator.modes.MENU); } - function enterMenuMode() { active_menubar = true; vimperator.addMode(null, vimperator.modes.MENU) } - function exitMenuMode() { active_menubar = false; vimperator.removeMode(null, vimperator.modes.MENU); } - window.addEventListener("popupshown", enterPopupMode, true); window.addEventListener("popuphidden", exitPopupMode, true); window.addEventListener("DOMMenuBarActive", enterMenuMode, true); window.addEventListener("DOMMenuBarInactive", exitMenuMode, true); - window.document.addEventListener("DOMTitleChanged", function(event) - { - //alert("titlechanged"); - }, null); + // window.document.addEventListener("DOMTitleChanged", function(event) + // { + // vimperator.log("titlechanged"); + // }, null); // NOTE: the order of ["Esc", "Escape"] or ["Escape", "Esc"] // matters, so use that string as the first item, that you @@ -381,7 +372,8 @@ function Events() //{{{ return (key == "" || key == "" || key == ""); } - // event is delibarately not used, as i don't seem to have access to the really focus target + // argument "event" is delibarately not used, as i don't seem to have + // access to the real focus target this.onFocusChange = function(event) { if (vimperator.hasMode(vimperator.modes.COMMAND_LINE)) @@ -397,16 +389,43 @@ function Events() //{{{ else if (elem && elem instanceof HTMLTextAreaElement) { if (elem.selectionEnd - elem.selectionStart > 0) - vimperator.editor.startVisual(); + vimperator.setMode(vimperator.modes.VISUAL, vimperator.modes.TEXTAREA); else vimperator.editor.startNormal(); vimperator.buffer.lastInputField = elem; } - else - { - if (vimperator.hasMode(vimperator.modes.INSERT) || + else if //(vimperator.hasMode(vimperator.modes.VISUAL) || + (vimperator.hasMode(vimperator.modes.INSERT) || vimperator.hasMode(vimperator.modes.TEXTAREA)) - vimperator.setMode(vimperator.modes.NORMAL); // FIXME: remember previous mode + vimperator.setMode(vimperator.modes.NORMAL); + } + + this.onSelectionChange = function(event) + { + vimperator.log("onselection"); + var could_copy = false; + var controller = document.commandDispatcher.getControllerForCommand("cmd_copy"); + if (controller && controller.isCommandEnabled("cmd_copy")) + could_copy = true; + + var extended = vimperator.modes.NONE; + if (vimperator.hasMode(vimperator.modes.TEXTAREA)) + extended = vimperator.modes.TEXTAREA; + else if (vimperator.hasMode(vimperator.modes.CARET)) + extended = vimperator.modes.CARET; + + if (could_copy && !vimperator.hasMode(vimperator.modes.VISUAL) && + (vimperator.hasMode(vimperator.modes.NORMAL) || + vimperator.hasMode(vimperator.modes.TEXTAREA) || + vimperator.hasMode(vimperator.modes.CARET))) + { + vimperator.setMode(vimperator.modes.VISUAL, extended); + } + else if (vimperator.hasMode(vimperator.modes.VISUAL)) + { + if (!could_copy && !vimperator.hasMode(vimperator.modes.CARET) && + !vimperator.hasMode(vimperator.modes.TEXTAREA)) + vimperator.setMode(extended || vimperator.modes.NORMAL); } } @@ -416,16 +435,23 @@ function Events() //{{{ { if (!vimperator.hasMode(vimperator.modes.ESCAPE_ONE_KEY)) { - // clear any selection made - // FIXME: need to make more general to allow caret/visual mode also for text fields - var selection = window.content.getSelection(); - selection.collapseToStart(); - if (vimperator.hasMode(vimperator.modes.VISUAL)) { if (vimperator.hasMode(vimperator.modes.TEXTAREA)) + { vimperator.editor.unselectText(); - vimperator.setMode(vimperator.getMode()[1], vimperator.modes.NONE); + vimperator.setMode(vimperator.modes.TEXTAREA, vimperator.modes.NONE); + } + else + { + // clear any selection made + var selection = window.content.getSelection(); + selection.collapseToStart(); + if (vimperator.hasMode(vimperator.modes.CARET)) // set as an extended mode + vimperator.setMode(vimperator.modes.CARET); + else + vimperator.setMode(vimperator.modes.NORMAL); + } } else if (vimperator.hasMode(vimperator.modes.CARET)) { @@ -436,7 +462,7 @@ function Events() //{{{ else if (vimperator.hasMode(vimperator.modes.INSERT)) { if(vimperator.hasMode(vimperator.modes.TEXTAREA)) - vimperator.editor.stopInsert(); + vimperator.setMode(vimperator.modes.TEXTAREA); else { vimperator.editor.unselectText(); @@ -452,8 +478,6 @@ function Events() //{{{ vimperator.statusline.updateUrl(); vimperator.focusContent(); } - - } } @@ -491,7 +515,8 @@ function Events() //{{{ // FIXME: proper way is to have a better onFocus handler which also handles events for the XUL if (!vimperator.hasMode(vimperator.modes.TEXTAREA) && !vimperator.hasMode(vimperator.modes.INSERT) && - isFormElemFocused()) // non insert mode, but e.g. the location bar has focus + !vimperator.hasMode(vimperator.modes.COMMAND_LINE) && + isFormElemFocused()) // non insert mode, but e.g. the location bar has focus return false; // XXX: ugly hack for now pass certain keys to firefox as they are without beeping @@ -607,16 +632,20 @@ function Events() //{{{ // counts must be at the start of a complete mapping (10j -> go 10 lines down) if ((vimperator.input.buffer + key).match(/^[1-9][0-9]*$/)) { - vimperator.input.buffer += key; + // no count for insert mode mappings + if (vimperator.hasMode(vimperator.modes.INSERT)) + stop = false; + else + vimperator.input.buffer += key; } - else if (vimperator.input.pendingMap) + else if (vimperator.input.pendingArgMap) { vimperator.input.buffer = ""; if (key != "" && key != "") - vimperator.input.pendingMap.execute(null, vimperator.input.count, key); + vimperator.input.pendingArgMap.execute(null, vimperator.input.count, key); - vimperator.input.pendingMap = null; + vimperator.input.pendingArgMap = null; } else if (map = vimperator.mappings.get(mode, candidate_command)) { @@ -625,9 +654,24 @@ function Events() //{{{ vimperator.input.count = -1; if (map.flags & Mappings.flags.ARGUMENT) { - vimperator.input.pendingMap = map; + vimperator.input.pendingArgMap = map; vimperator.input.buffer += key; } + else if (vimperator.input.pendingMotionMap) + { + if (key != "" && key != "") + { + vimperator.input.pendingMotionMap.execute(candidate_command, vimperator.input.count, null); + } + vimperator.input.pendingMotionMap = null; + vimperator.input.buffer = ""; + } + // no count support for these commands yet + else if (map.flags & Mappings.flags.MOTION) + { + vimperator.input.pendingMotionMap = map; + vimperator.input.buffer = ""; + } else { vimperator.input.buffer = ""; @@ -642,7 +686,8 @@ function Events() //{{{ else { vimperator.input.buffer = ""; - vimperator.input.pendingMap = null; + vimperator.input.pendingArgMap = null; + vimperator.input.pendingMotionMap = null; if (vimperator.hasMode(vimperator.modes.INSERT) || vimperator.hasMode(vimperator.modes.COMMAND_LINE)) @@ -657,7 +702,8 @@ function Events() //{{{ event.stopPropagation(); } - vimperator.statusline.updateInputBuffer(vimperator.input.buffer); + var motion_map = (vimperator.input.pendingMotionMap && vimperator.input.pendingMotionMap.names[0]) || ""; + vimperator.statusline.updateInputBuffer(motion_map + vimperator.input.buffer); return false; } window.addEventListener("keypress", this.onKeyPress, true); diff --git a/chrome/content/vimperator/mappings.js b/chrome/content/vimperator/mappings.js index a4f353a7..55b00d35 100644 --- a/chrome/content/vimperator/mappings.js +++ b/chrome/content/vimperator/mappings.js @@ -1333,7 +1333,7 @@ function Mappings() //{{{ }, { flags: Mappings.flags.COUNT } )); - addDefaultMap(new Map([vimperator.modes.CARET], ["w", "W", ""], + addDefaultMap(new Map([vimperator.modes.CARET], ["w", "W", "e", ""], function(count) { if (count < 1) count = 1; @@ -1406,10 +1406,14 @@ function Mappings() //{{{ if (count < 1) count = 1; while(count--) { - if (vimperator.hasMode(vimperator.modes.CARET)) - getSelectionController().lineMove(true, true); - else + if (vimperator.hasMode(vimperator.modes.TEXTAREA)) + { vimperator.editor.executeCommand("cmd_selectLineNext"); + if (vimperator.hasMode(vimperator.modes.LINE) && !vimperator.editor.selectedText()) + vimperator.editor.executeCommand("cmd_selectLineNext"); + } + else + getSelectionController().lineMove(true, true); } }, { flags: Mappings.flags.COUNT } @@ -1420,10 +1424,14 @@ function Mappings() //{{{ if (count < 1) count = 1; while(count--) { - if (vimperator.hasMode(vimperator.modes.CARET)) - getSelectionController().lineMove(false, true); - else + if (vimperator.hasMode(vimperator.modes.TEXTAREA)) + { vimperator.editor.executeCommand("cmd_selectLinePrevious"); + if (vimperator.hasMode(vimperator.modes.LINE) && !vimperator.editor.selectedText()) + vimperator.editor.executeCommand("cmd_selectLinePrevious"); + } + else + getSelectionController().lineMove(false, true); } }, { flags: Mappings.flags.COUNT } @@ -1434,10 +1442,10 @@ function Mappings() //{{{ if (count < 1) count = 1; while(count--) { - if (vimperator.hasMode(vimperator.modes.CARET)) - getSelectionController().characterMove(false, true); - else + if (vimperator.hasMode(vimperator.modes.TEXTAREA)) vimperator.editor.executeCommand("cmd_selectCharPrevious"); + else + getSelectionController().characterMove(false, true); } }, { flags: Mappings.flags.COUNT } @@ -1448,10 +1456,10 @@ function Mappings() //{{{ if (count < 1) count = 1; while(count--) { - if (vimperator.hasMode(vimperator.modes.CARET)) - getSelectionController().characterMove(true, true); - else + if (vimperator.hasMode(vimperator.modes.TEXTAREA)) vimperator.editor.executeCommand("cmd_selectCharNext"); + else + getSelectionController().characterMove(true, true); } }, { flags: Mappings.flags.COUNT } @@ -1462,24 +1470,24 @@ function Mappings() //{{{ if (count < 1) count = 1; while(count--) { - if (vimperator.hasMode(vimperator.modes.CARET)) - getSelectionController().wordMove(false, true); - else + if (vimperator.hasMode(vimperator.modes.TEXTAREA)) vimperator.editor.executeCommand("cmd_selectWordPrevious"); + else + getSelectionController().wordMove(false, true); } }, { flags: Mappings.flags.COUNT } )); - addDefaultMap(new Map([vimperator.modes.VISUAL], ["w", "W"], + addDefaultMap(new Map([vimperator.modes.VISUAL], ["w", "W", "e"], function(count) { if (count < 1) count = 1; while(count--) { - if (vimperator.hasMode(vimperator.modes.CARET)) - getSelectionController().wordMove(true, true); - else + if (vimperator.hasMode(vimperator.modes.TEXTAREA)) vimperator.editor.executeCommand("cmd_selectWordNext"); + else + getSelectionController().wordMove(true, true); } }, { flags: Mappings.flags.COUNT } @@ -1490,10 +1498,10 @@ function Mappings() //{{{ if (count < 1) count = 1; while(count--) { - if (vimperator.hasMode(vimperator.modes.CARET)) - getSelectionController().pageMove(true, true); + if (vimperator.hasMode(vimperator.modes.TEXTAREA)) + ;//vimperator.editor.executeCommand("cmd_selectPageNext"); else - ;//vimperator.editor.executeCommand("cmd_selectWordNext"); + getSelectionController().pageMove(true, true); } }, { flags: Mappings.flags.COUNT } @@ -1504,10 +1512,10 @@ function Mappings() //{{{ if (count < 1) count = 1; while(count--) { - if (vimperator.hasMode(vimperator.modes.CARET)) - getSelectionController().pageMove(false, true); - else + if (vimperator.hasMode(vimperator.modes.TEXTAREA)) ;//vimperator.editor.executeCommand("cmd_selectWordNext"); + else + getSelectionController().pageMove(false, true); } }, { flags: Mappings.flags.COUNT } @@ -1515,93 +1523,95 @@ function Mappings() //{{{ addDefaultMap(new Map([vimperator.modes.VISUAL], ["gg", ""], function(count) { - if (vimperator.hasMode(vimperator.modes.CARET)) - getSelectionController().completeMove(false, true); - else + if (vimperator.hasMode(vimperator.modes.TEXTAREA)) vimperator.editor.executeCommand("cmd_selectTop"); + else + getSelectionController().completeMove(false, true); }, { } )); addDefaultMap(new Map([vimperator.modes.VISUAL], ["G", ""], function(count) { - if (vimperator.hasMode(vimperator.modes.CARET)) - getSelectionController().completeMove(true, true); - else + if (vimperator.hasMode(vimperator.modes.TEXTAREA)) vimperator.editor.executeCommand("cmd_selectBottom"); + else + getSelectionController().completeMove(true, true); }, { } )); addDefaultMap(new Map([vimperator.modes.VISUAL], ["0", "^", ""], function(count) { - if (vimperator.hasMode(vimperator.modes.CARET)) - getSelectionController().intraLineMove(false, true); - else + if (vimperator.hasMode(vimperator.modes.TEXTAREA)) vimperator.editor.executeCommand("cmd_selectBeginLine"); + else + getSelectionController().intraLineMove(false, true); }, { } )); addDefaultMap(new Map([vimperator.modes.VISUAL], ["$", ""], function(count) { - if (vimperator.hasMode(vimperator.modes.CARET)) - getSelectionController().intraLineMove(true, true); - else + if (vimperator.hasMode(vimperator.modes.TEXTAREA)) vimperator.editor.executeCommand("cmd_selectEndLine"); + else + getSelectionController().intraLineMove(true, true); }, { } )); addDefaultMap(new Map([vimperator.modes.VISUAL], ["c", "s"], function(count) { - if (vimperator.hasMode(vimperator.modes.CARET)) - vimperator.beep(); - else + if (vimperator.hasMode(vimperator.modes.TEXTAREA)) { vimperator.editor.executeCommand("cmd_cut"); vimperator.setMode(vimperator.modes.INSERT, vimperator.modes.TEXTAREA); } + else + vimperator.beep(); }, { } )); addDefaultMap(new Map([vimperator.modes.VISUAL], ["d"], function(count) { - if (vimperator.hasMode(vimperator.modes.CARET)) - vimperator.beep(); - else + if (vimperator.hasMode(vimperator.modes.TEXTAREA)) { vimperator.editor.executeCommand("cmd_cut"); vimperator.setMode(vimperator.modes.TEXTAREA); } + else + vimperator.beep(); }, { } )); addDefaultMap(new Map([vimperator.modes.VISUAL], ["y"], function(count) { - if (vimperator.hasMode(vimperator.modes.CARET)) - vimperator.beep(); // TODO: yanking is possible for caret mode - else + if (vimperator.hasMode(vimperator.modes.TEXTAREA)) { vimperator.editor.executeCommand("cmd_copy"); - vimperator.editor.unselectText(); + // vimperator.editor.unselectText(); vimperator.setMode(vimperator.modes.TEXTAREA); } + else + vimperator.beep(); // TODO: yanking is possible for caret mode }, { } )); addDefaultMap(new Map([vimperator.modes.VISUAL, vimperator.modes.TEXTAREA], ["p"], function(count) { - if (vimperator.hasMode(vimperator.modes.CARET)) - vimperator.beep(); // TODO: yanking is possible for caret mode - else + if (vimperator.hasMode(vimperator.modes.TEXTAREA)) { - vimperator.editor.executeCommand("cmd_paste"); + if (!count) count = 1; + while (count--) + vimperator.editor.executeCommand("cmd_paste"); vimperator.setMode(vimperator.modes.TEXTAREA); } + else + vimperator.beep(); }, { } )); @@ -1668,12 +1678,21 @@ function Mappings() //{{{ function(count) { vimperator.setMode(vimperator.modes.VISUAL, vimperator.modes.TEXTAREA); }, { } )); + addDefaultMap(new Map([vimperator.modes.TEXTAREA], ["V"], + function(count) + { + vimperator.editor.executeCommand("cmd_beginLine", 1); + vimperator.editor.executeCommand("cmd_selectLineNext", 1); + vimperator.setMode(vimperator.modes.VISUAL, vimperator.modes.TEXTAREA | vimperator.modes.LINE); + }, + { } + )); addDefaultMap(new Map([vimperator.modes.TEXTAREA], ["u"], - function(count) { vimperator.editor.executeCommand("cmd_undo", count); }, + function(count) { vimperator.editor.executeCommand("cmd_undo", count); vimperator.setMode(vimperator.modes.TEXTAREA); }, { flags: Mappings.flags.COUNT } )); addDefaultMap(new Map([vimperator.modes.TEXTAREA], [""], - function(count) { vimperator.editor.executeCommand("cmd_redo", count); }, + function(count) { vimperator.editor.executeCommand("cmd_redo", count); vimperator.setMode(vimperator.modes.TEXTAREA); }, { flags: Mappings.flags.COUNT } )); addDefaultMap(new Map([vimperator.modes.TEXTAREA], ["j", "", ""], @@ -1692,7 +1711,7 @@ function Mappings() //{{{ function(count) { vimperator.editor.executeCommand("cmd_charNext", count); }, { flags: Mappings.flags.COUNT } )); - addDefaultMap(new Map([vimperator.modes.TEXTAREA], ["w", "W", ""], + addDefaultMap(new Map([vimperator.modes.TEXTAREA], ["w", "W", "e", ""], function(count) { vimperator.editor.executeCommand("cmd_wordNext", count); }, { flags: Mappings.flags.COUNT } )); @@ -1724,6 +1743,86 @@ function Mappings() //{{{ function(count) { vimperator.editor.executeCommand("cmd_movePageUp", count); }, { flags: Mappings.flags.COUNT } )); + addDefaultMap(new Map([vimperator.modes.TEXTAREA], ["o"], + function(count) + { + vimperator.editor.executeCommand("cmd_endLine", 1); + vimperator.editor.startInsert(); + vimperator.events.feedkeys(""); + }, + { } + )); + addDefaultMap(new Map([vimperator.modes.TEXTAREA], ["O"], + function(count) + { + vimperator.editor.executeCommand("cmd_beginLine", 1); + vimperator.editor.startInsert(); + vimperator.events.feedkeys(""); + vimperator.editor.executeCommand("cmd_linePrevious", 1); + }, + { } + )); + + // no need to check if we are really in TEXTAREA mode, as findCharForward/Backward will return -1 otherwise + addDefaultMap(new Map([vimperator.modes.TEXTAREA, vimperator.modes.VISUAL], ["f"], + function(count, arg) + { + var pos = vimperator.editor.findCharForward(arg, count); + if (pos >= 0) + vimperator.editor.moveToPosition(pos, true, vimperator.hasMode(vimperator.modes.VISUAL)); + }, + { flags: Mappings.flags.ARGUMENT | Mappings.flags.COUNT} + )); + addDefaultMap(new Map([vimperator.modes.TEXTAREA, vimperator.modes.VISUAL], ["F"], + function(count, arg) + { + var pos = vimperator.editor.findCharBackward(arg, count); + if (pos >= 0) + vimperator.editor.moveToPosition(pos, false, vimperator.hasMode(vimperator.modes.VISUAL)); + }, + { flags: Mappings.flags.ARGUMENT | Mappings.flags.COUNT} + )); + addDefaultMap(new Map([vimperator.modes.TEXTAREA, vimperator.modes.VISUAL], ["t"], + function(count, arg) + { + var pos = vimperator.editor.findCharForward(arg, count); + if (pos >= 0) + vimperator.editor.moveToPosition(pos - 1, true, vimperator.hasMode(vimperator.modes.VISUAL)); + }, + { flags: Mappings.flags.ARGUMENT | Mappings.flags.COUNT} + )); + addDefaultMap(new Map([vimperator.modes.TEXTAREA, vimperator.modes.VISUAL], ["T"], + function(count, arg) + { + var pos = vimperator.editor.findCharBackward(arg, count); + if (pos >= 0) + vimperator.editor.moveToPosition(pos + 1, false, vimperator.hasMode(vimperator.modes.VISUAL)); + }, + { flags: Mappings.flags.ARGUMENT | Mappings.flags.COUNT} + )); + // addDefaultMap(new Map([vimperator.modes.TEXTAREA, vimperator.modes.VISUAL], [";"], + // function(count, arg) + // { + // var pos = vimperator.editor.findCharBackward(null, count); + // if (pos >= 0) + // vimperator.editor.moveToPosition(pos + 1, false, vimperator.hasMode(vimperator.modes.VISUAL)); + // }, + // { flags: Mappings.flags.ARGUMENT | Mappings.flags.COUNT} + // )); + + // commands which require a motion + addDefaultMap(new Map([vimperator.modes.TEXTAREA], ["d"], + function(motion, count) { vimperator.editor.executeCommandWithMotion("d", motion, count); }, + { flags: Mappings.flags.MOTION | Mappings.flags.COUNT } + )); + addDefaultMap(new Map([vimperator.modes.TEXTAREA], ["c"], + function(motion, count) { vimperator.editor.executeCommandWithMotion("c", motion, count); }, + { flags: Mappings.flags.MOTION | Mappings.flags.COUNT } + )); + addDefaultMap(new Map([vimperator.modes.TEXTAREA], ["y"], + function(motion, count) { vimperator.editor.executeCommandWithMotion("y", motion, count); }, + { flags: Mappings.flags.MOTION | Mappings.flags.COUNT } + )); // }}} // INSERT mode diff --git a/chrome/content/vimperator/vimperator.js b/chrome/content/vimperator/vimperator.js index ed0ba5c5..0f85f5b2 100644 --- a/chrome/content/vimperator/vimperator.js +++ b/chrome/content/vimperator/vimperator.js @@ -52,7 +52,8 @@ const vimperator = (function() //{{{ QUICK_HINT: 1 << 16, EXTENDED_HINT: 1 << 17, ALWAYS_HINT: 1 << 18, - MENU: 1 << 19 // a popupmenu is active + MENU: 1 << 19, // a popupmenu is active + LINE: 1 << 20 // linewise visual mode } var mode_messages = {}; @@ -60,8 +61,9 @@ const vimperator = (function() //{{{ mode_messages[modes.INSERT] = "INSERT"; mode_messages[modes.VISUAL] = "VISUAL"; mode_messages[modes.HINTS] = "HINTS"; - mode_messages[modes.CARET] = "CARET"; // XXX: not a perfect name - mode_messages[modes.TEXTAREA] = "TEXTAREA"; // XXX: not a perfect name + mode_messages[modes.CARET] = "CARET"; + mode_messages[modes.TEXTAREA] = "TEXTAREA"; + mode_messages[modes.TEXTAREA | modes.LINE] = "line"; // used in visual mode mode_messages[modes.ESCAPE_ONE_KEY] = "escape one key"; mode_messages[modes.ESCAPE_ALL_KEYS] = "escape all keys"; mode_messages[modes.ESCAPE_ONE_KEY | modes.ESCAPE_ALL_KEYS] = "pass one key"; @@ -202,7 +204,8 @@ const vimperator = (function() //{{{ input: { buffer: "", // partial command storage - pendingMap: null, // pending map storage + pendingMotionMap: null, // e.g. "d{motion}" if we wait for a motion of the "d" command + pendingArgMap: null, // pending map storage for commands like m{a-z} count: -1 // parsed count from the input buffer }, @@ -244,6 +247,14 @@ const vimperator = (function() //{{{ { mode = main; extended_mode = vimperator.modes.NONE; + + // TODO: also fix the other modes!! + switch (main) + { + case vimperator.modes.TEXTAREA: + vimperator.editor.unselectText(); + break; + } } if (typeof extended === "number") extended_mode = extended; diff --git a/chrome/content/vimperator/vimperator.xul b/chrome/content/vimperator/vimperator.xul index 8d9b959a..b057bc7c 100644 --- a/chrome/content/vimperator/vimperator.xul +++ b/chrome/content/vimperator/vimperator.xul @@ -127,10 +127,14 @@ the terms of any one of the MPL, the GPL or the LGPL. - +