From a2a304390700e44141c014c52c47bf2344394dc6 Mon Sep 17 00:00:00 2001 From: nightwing Date: Sun, 22 Apr 2012 14:28:10 +0400 Subject: [PATCH] manual merge of ace++ branch --- lib/ace/keyboard/keybinding.js | 6 +- lib/ace/keyboard/state_handler.js | 2 + lib/ace/keyboard/vim.js | 5 +- lib/ace/keyboard/vim/commands.js | 162 ++++++----- lib/ace/keyboard/vim/keyboard.js | 121 +++----- lib/ace/keyboard/vim/maps/aliases.js | 13 +- lib/ace/keyboard/vim/maps/motions.js | 388 +++++++++++++++++++++---- lib/ace/keyboard/vim/maps/operators.js | 114 ++++---- lib/ace/keyboard/vim/maps/util.js | 110 ++++--- lib/ace/lib/keys.js | 2 +- lib/ace/mode/behaviour/cstyle.js | 2 +- 11 files changed, 599 insertions(+), 326 deletions(-) diff --git a/lib/ace/keyboard/keybinding.js b/lib/ace/keyboard/keybinding.js index d1c9a0cf..1fe10538 100644 --- a/lib/ace/keyboard/keybinding.js +++ b/lib/ace/keyboard/keybinding.js @@ -116,7 +116,7 @@ var KeyBinding = function(editor) { if (toExecute.command != "null") success = commands.exec(toExecute.command, this.$editor, toExecute.args, e); else - success = true; + success = toExecute.stopEvent == true; if (success && e) event.stopEvent(e); @@ -130,9 +130,7 @@ var KeyBinding = function(editor) { }; this.onTextInput = function(text) { - var success = false; - if (text.length == 1) - success = this.$callKeyboardHandlers(0, text); + var success = this.$callKeyboardHandlers(-1, text); if (!success) this.$editor.commands.exec("insertstring", this.$editor, text); }; diff --git a/lib/ace/keyboard/state_handler.js b/lib/ace/keyboard/state_handler.js index 8e93ba30..c7efe552 100644 --- a/lib/ace/keyboard/state_handler.js +++ b/lib/ace/keyboard/state_handler.js @@ -202,6 +202,8 @@ StateHandler.prototype = { * This function is called by keyBinding. */ handleKeyboard: function(data, hashId, key, keyCode, e) { + if (hashId == -1) + hashId = 0 // If we pressed any command key but no other key, then ignore the input. // Otherwise "shift-" is added to the buffer, and later on "shift-g" // which results in "shift-shift-g" which doesn't make sense. diff --git a/lib/ace/keyboard/vim.js b/lib/ace/keyboard/vim.js index 102414e8..0f73e764 100644 --- a/lib/ace/keyboard/vim.js +++ b/lib/ace/keyboard/vim.js @@ -1,5 +1,4 @@ define(function(require, exports, module) { -"use strict"; "never use strict"; @@ -9,7 +8,7 @@ var util = require("./vim/maps/util"); exports.handler = require("./vim/keyboard").handler; exports.onCursorMove = function(e) { - commands.onCursorMove(e.editor); + commands.onCursorMove(e.editor, e); exports.onCursorMove.scheduled = false; }; @@ -21,7 +20,7 @@ exports.handler.attach = function(editor) { exports.handler.detach = function(editor) { editor.removeListener("click", exports.onCursorMove); - commands.coreCommands.start.exec(editor); + util.noMode(editor); util.currentMode = "normal"; }; diff --git a/lib/ace/keyboard/vim/commands.js b/lib/ace/keyboard/vim/commands.js index 3312f4a1..77a30ac6 100644 --- a/lib/ace/keyboard/vim/commands.js +++ b/lib/ace/keyboard/vim/commands.js @@ -35,7 +35,6 @@ exports.searchStore = { }; var repeat = function repeat(fn, count, args) { - count = parseInt(count, 10); while (0 < count--) fn.apply(this, args); }; @@ -48,19 +47,22 @@ var toggleCase = function toggleCase(ch) { }; var ensureScrollMargin = function(editor) { - setTimeout(function() { - var curPos = editor.getCursorPosition().row; - var topRow = editor.renderer.layerConfig.firstRow; - var linesToBottom = editor.renderer.layerConfig.lastRow - curPos; - var linesToTop = curPos - topRow; + var renderer = editor.renderer + var pos = renderer.$cursorLayer.getPixelPosition(); - if (linesToBottom >= 0 && linesToBottom < HMARGIN) { - editor.scrollToRow(topRow + (HMARGIN - linesToBottom)); - } - else if (linesToTop >= 0 && linesToTop < HMARGIN) { - editor.scrollToRow(topRow - (HMARGIN - linesToTop)); - } - }, 20); // Delay introduced to ensure scroll after async find operation. + var top = pos.top; + + var margin = HMARGIN * renderer.layerConfig.lineHeight; + if (2 * margin > renderer.$size.scrollerHeight) + margin = renderer.$size.scrollerHeight / 2 + + if (renderer.scrollTop > top - margin) { + renderer.session.setScrollTop(top - margin); + } + + if (renderer.scrollTop + renderer.$size.scrollerHeight < top + margin + renderer.lineHeight) { + renderer.session.setScrollTop(top + margin + renderer.lineHeight - renderer.$size.scrollerHeight); + } }; var actions = { @@ -69,10 +71,13 @@ var actions = { fn: function(editor, range, count, param) { switch (param) { case "z": - editor.centerSelection(); + editor.alignCursor(null, 0.5); break; case "t": - editor.scrollToRow(editor.getCursorPosition().row); + editor.alignCursor(null, 0); + break; + case "b": + editor.alignCursor(null, 1); break; } } @@ -80,21 +85,30 @@ var actions = { "r": { param: true, fn: function(editor, range, count, param) { - param = util.toRealChar(param); if (param && param.length) { repeat(function() { editor.insert(param); }, count || 1); editor.navigateLeft(); } } }, - // "~" HACK - "shift-`": { + "R": { + fn: function(editor, range, count, param) { + util.insertMode(editor); + editor.setOverwrite(true); + } + }, + "~": { fn: function(editor, range, count) { repeat(function() { - var pos = editor.getCursorPosition(); - var line = editor.session.getLine(pos.row); - var ch = line[pos.column]; - editor.insert(toggleCase(ch)); + var range = editor.selection.getRange(); + if (range.isEmpty()) + range.end.column++ + var text = editor.session.getTextRange(range) + var toggled = text.toUpperCase() + if (toggled == text) + editor.navigateRight() + else + editor.session.replace(range, toggled); }, count || 1); } }, @@ -103,9 +117,8 @@ var actions = { editor.selection.selectWord(); editor.findNext(); ensureScrollMargin(editor); - var cursor = editor.selection.getCursor(); - range = editor.session.getWordRange(cursor.row, cursor.column); - editor.selection.setSelectionRange(range, true); + var r = editor.selection.getRange(); + editor.selection.setSelectionRange(r, true); } }, "#": { @@ -113,9 +126,8 @@ var actions = { editor.selection.selectWord(); editor.findPrevious(); ensureScrollMargin(editor); - var cursor = editor.selection.getCursor(); - range = editor.session.getWordRange(cursor.row, cursor.column); - editor.selection.setSelectionRange(range, true); + var r = editor.selection.getRange(); + editor.selection.setSelectionRange(r, true); } }, "n": { @@ -123,35 +135,39 @@ var actions = { var options = editor.getLastSearchOptions(); options.backwards = false; + editor.selection.moveCursorRight(); + editor.selection.clearSelection(); editor.findNext(options); ensureScrollMargin(editor); - editor.selection.clearSelection(); + var r = editor.selection.getRange(); + r.end.row = r.start.row; + r.end.column = r.start.column + editor.selection.setSelectionRange(r, true); } }, - "shift-n": { + "N": { fn: function(editor, range, count, param) { var options = editor.getLastSearchOptions(); options.backwards = true; - editor.navigateWordLeft(); editor.findPrevious(options); ensureScrollMargin(editor); - editor.selection.clearSelection(); + var r = editor.selection.getRange(); + r.end.row = r.start.row; + r.end.column = r.start.column + editor.selection.setSelectionRange(r, true); } }, "v": { fn: function(editor, range, count, param) { editor.selection.selectRight(); - util.onVisualMode = true; - util.onVisualLineMode = false; - var cursor = document.getElementsByClassName("ace_cursor")[0]; - cursor.style.display = "none"; - } + util.visualMode(editor, false); + }, + acceptsMotion: true }, - "shift-v": { + "V": { fn: function(editor, range, count, param) { - util.onVisualLineMode = true; //editor.selection.selectLine(); //editor.selection.selectLeft(); var row = editor.getCursorPosition().row; @@ -159,9 +175,12 @@ var actions = { editor.selection.moveCursorTo(row, 0); editor.selection.selectLineEnd(); editor.selection.visualLineStart = row; - } + + util.visualMode(editor, true); + }, + acceptsMotion: true }, - "shift-y": { + "Y": { fn: function(editor, range, count, param) { util.copyLine(editor); } @@ -186,7 +205,7 @@ var actions = { editor.selection.clearSelection(); } }, - "shift-p": { + "P": { fn: function(editor, range, count, param) { var defaultReg = registers._default; editor.setOverwrite(false); @@ -204,26 +223,26 @@ var actions = { editor.selection.clearSelection(); } }, - "shift-j": { + "J": { fn: function(editor, range, count, param) { - var pos = editor.getCursorPosition(); + var session = editor.session + range = editor.getSelectionRange(); + var pos = {row: range.start.row, column: range.start.column}; + count = count || range.end.row - range.start.row; + var maxRow = Math.min(pos.row + (count || 1), session.getLength() - 1); - if (editor.session.getLength() === pos.row + 1) - return; + range.start.column = session.getLine(pos.row).length; + range.end.column = session.getLine(maxRow).length; + range.end.row = maxRow; - var nextLine = editor.session.getLine(pos.row + 1); - var cleanLine = /^\s*(.*)$/.exec(nextLine)[1]; + var text = "" + for (var i = pos.row; i < maxRow; i++) { + var nextLine = session.getLine(i + 1); + text += " " + /^\s*(.*)$/.exec(nextLine)[1] || ""; + } - editor.navigateDown(); - editor.removeLines(); - - if (editor.session.getLength() > editor.getCursorPosition().row + 1) - editor.navigateUp(); - - editor.navigateLineEnd(); - editor.insert(" " + (cleanLine || "")); + session.replace(range, text); editor.moveCursorTo(pos.row, pos.column); - } }, "u": { @@ -281,11 +300,6 @@ var inputBuffer = exports.inputBuffer = { lastInsertCommands: [], push: function(editor, char, keyId) { - if (char && char.length > 1) { // There is a modifier key - if (!char[char.length - 1].match(/[A-za-z]/) && keyId) // It is a letter - char = keyId; - } - this.idle = false; var wObj = this.waitingForParam; if (wObj) { @@ -342,6 +356,9 @@ var inputBuffer = exports.inputBuffer = { else { this.exec(editor, actionObj); } + + if (actions[char].acceptsMotion) + this.idle = false; } else if (this.operator) { this.exec(editor, { operator: this.operator }, char); @@ -358,7 +375,7 @@ var inputBuffer = exports.inputBuffer = { getCount: function() { var count = this.currentCount; this.currentCount = ""; - return count; + return count && parseInt(count, 10); }, exec: function(editor, action, param) { @@ -366,6 +383,9 @@ var inputBuffer = exports.inputBuffer = { var o = action.operator; var a = action.action; + if (!param) + param = action.param; + if (o) { this.previous = { action: action, @@ -391,7 +411,7 @@ var inputBuffer = exports.inputBuffer = { else if (m) { var run = function(fn) { if (fn && typeof fn === "function") { // There should always be a motion - if (m.count) + if (m.count && !motionObj.handlesCount) repeat(fn, m.count, [editor, null, m.count, param]); else fn(editor, null, m.count, param); @@ -480,18 +500,15 @@ exports.coreCommands = { util.insertMode(editor); setPreviousCommand(appendEnd); } - }, - builder: { - exec: function builder(editor) {} } }; -var handleCursorMove = exports.onCursorMove = function(editor) { - if(util.currentMode === 'insert' || handleCursorMove.running) +var handleCursorMove = exports.onCursorMove = function(editor, e) { + if (util.currentMode === 'insert' || handleCursorMove.running) return; else if(!editor.selection.isEmpty()) { handleCursorMove.running = true; - if(util.onVisualLineMode) { + if (util.onVisualLineMode) { var originRow = editor.selection.visualLineStart; var cursorRow = editor.getCursorPosition().row; if(originRow <= cursorRow) { @@ -510,6 +527,11 @@ var handleCursorMove = exports.onCursorMove = function(editor) { return; } else { + if (e && (util.onVisualLineMode || util.onVisualMode)) { + editor.selection.clearSelection(); + util.normalMode(editor) + } + handleCursorMove.running = true; var pos = editor.getCursorPosition(); var lineLen = editor.session.getLine(pos.row).length; diff --git a/lib/ace/keyboard/vim/keyboard.js b/lib/ace/keyboard/vim/keyboard.js index 08b02714..fab668d0 100644 --- a/lib/ace/keyboard/vim/keyboard.js +++ b/lib/ace/keyboard/vim/keyboard.js @@ -1,88 +1,61 @@ define(function(require, exports, module) { -"never use strict"; -var StateHandler = require("ace/keyboard/state_handler").StateHandler; +var keyUtil = require("../../lib/keys"); var cmds = require("./commands"); var coreCommands = cmds.coreCommands; -var matchChar = function(buffer, hashId, key, symbolicName, keyId) { - // If no command keys are pressed, then catch the input. - // If only the shift key is pressed and a character key, then - // catch that input as well. - // Otherwise, we let the input got through. - var matched = ((hashId === 0) || (((hashId === 1) || (hashId === 4)) && key.length === 1)); - //console.log("INFO", arguments) - if (matched) { - if (keyId) { - keyId = String.fromCharCode(parseInt(keyId.replace("U+", "0x"), 10)); - } +var startCommands = { + 'i': { + command: coreCommands.start + }, + 'I': { + command: coreCommands.startBeginning, + }, + 'a': { + command: coreCommands.append + }, + 'A': { + command: coreCommands.appendEnd + } +}; - coreCommands.builder.exec = function(editor) { - cmds.inputBuffer.push.call(cmds.inputBuffer, editor, symbolicName, keyId); +exports.handler = { + handleKeyboard: function(data, hashId, key, keyCode, e) { + // ignore command keys (shift, ctrl etc.) + // Otherwise "shift-" is added to the buffer, and later on "shift-g" + // which results in "shift-shift-g" which doesn't make sense. + if (hashId != 0 && (key == "" || key == "\x00")) + return null; + + if (hashId == 1) + key = 'ctrl-' + key; + + if (data.state == 'start') { + if (hashId == -1 || hashId == 1) { + if (cmds.inputBuffer.idle && startCommands[key]) + return startCommands[key]; + + return { command: { + exec: function(editor) {cmds.inputBuffer.push(editor, key);} + } }; + } // wait for input + else if (key.length === 1 && (hashId == 0 || hashId === 4)) { //no modifier || shift + return {command: "null", stopEvent: false} + } else if (key == 'esc') { + return {command: coreCommands.stop}; + } + } else { + if (key == 'esc' || key == 'ctrl-[') { + data.state = 'start' + return {command: coreCommands.stop} + } } } - return matched; -}; +} -var inIdleState = function() { - if (cmds.inputBuffer.idle) { - return true; - } - return false; -}; -var states = exports.states = { - start: [ // normal mode - { - key: "esc", - exec: coreCommands.stop, - then: "start" - }, - { - regex: "^i$", - match: inIdleState, - exec: coreCommands.start, - then: "insertMode" - }, - { - regex: "^shift-i$", - match: inIdleState, - exec: coreCommands.startBeginning, - then: "insertMode" - }, - { - regex: "^a$", - match: inIdleState, - exec: coreCommands.append, - then: "insertMode" - }, - { - regex: "^shift-a$", - match: inIdleState, - exec: coreCommands.appendEnd, - then: "insertMode" - }, - { - // The rest of input will be processed here - match: matchChar, - exec: coreCommands.builder - } - ], - insertMode: [ - { - key: "esc", - exec: coreCommands.stop, - then: "start" - }, - { - key: "backspace", - exec: "backspace" - } - ] -}; -exports.handler = new StateHandler(states); -}); +}); \ No newline at end of file diff --git a/lib/ace/keyboard/vim/maps/aliases.js b/lib/ace/keyboard/vim/maps/aliases.js index 34b6d971..ac495dcd 100644 --- a/lib/ace/keyboard/vim/maps/aliases.js +++ b/lib/ace/keyboard/vim/maps/aliases.js @@ -12,7 +12,7 @@ module.exports = { count: 1 } }, - "shift-x": { + "X": { operator: { char: "d", count: 1 @@ -22,7 +22,7 @@ module.exports = { count: 1 } }, - "shift-d": { + "D": { operator: { char: "d", count: 1 @@ -32,7 +32,7 @@ module.exports = { count: 1 } }, - "shift-c": { + "C": { operator: { char: "c", count: 1 @@ -52,15 +52,12 @@ module.exports = { count: 1 } }, - "shift-s": { + "S": { operator: { char: "c", count: 1 }, - motion: { - char: "l", - count: 1 - } + param: "c" } }; }); diff --git a/lib/ace/keyboard/vim/maps/motions.js b/lib/ace/keyboard/vim/maps/motions.js index 1c9ec02a..42972870 100644 --- a/lib/ace/keyboard/vim/maps/motions.js +++ b/lib/ace/keyboard/vim/maps/motions.js @@ -1,4 +1,4 @@ -"use strict" +"never use strict" define(function(require, exports, module) { @@ -12,23 +12,199 @@ var keepScrollPosition = function(editor, fn) { editor.renderer.scrollToRow(editor.getCursorPosition().row - diff); }; +function Motion(getRange, type){ + if (type == 'extend') + var extend = true + else + var reverse = type + + this.nav = function(editor) { + var r = getRange(editor); + if (!r) + return + if (!r.end) + var a = r + else if (reverse) + var a = r.start + else + var a = r.end + + editor.clearSelection() + editor.moveCursorTo(a.row, a.column); + } + this.sel = function(editor){ + var r = getRange(editor); + if (!r) + return + if (extend) + return editor.selection.setSelectionRange(r); + + if (!r.end) + var a = r + else if (reverse) + var a = r.start + else + var a = r.end + + editor.selection.selectTo(a.row, a.column); + } +} + +var nonWordRe = /[\s.\/\\()\"'-:,.;<>~!@#$%^&*|+=\[\]{}`~?]/; +var wordSeparatorRe = /[.\/\\()\"'-:,.;<>~!@#$%^&*|+=\[\]{}`~?]/; +var whiteRe = /\s/; +var StringStream = function(editor, cursor) { + var sel = editor.selection + this.range = sel.getRange() + cursor = cursor || sel.selectionLead + this.row = cursor.row; + this.col = cursor.column; + var line = editor.session.getLine(this.row); + var maxRow = editor.session.getLength() + this.ch = line[this.col] || '\n' + this.skippedLines = 0 + + this.next = function() { + this.ch = line[++this.col] || this.handleNewLine(1) + //this.debug() + return this.ch + } + this.prev = function() { + this.ch = line[--this.col] || this.handleNewLine(-1) + //this.debug() + return this.ch + } + this.peek = function(dir) { + var ch = line[this.col + dir] + if (ch) + return ch + if (dir == -1) + return '\n' + if (this.col == line.length - 1) + return '\n' + return editor.session.getLine(this.row + 1)[0] || '\n' + } + + this.handleNewLine = function(dir) { + if (dir == 1){ + if (this.col == line.length) + return '\n' + if (this.row == maxRow - 1) + return '' + this.col = 0 + this.row ++ + line = editor.session.getLine(this.row) + this.skippedLines++ + return line[0] || '\n' + } + if (dir == -1) { + if (this.row == 0) + return '' + this.row -- + line = editor.session.getLine(this.row) + this.col = line.length; + this.skippedLines-- + return '\n' + } + } + this.debug = function() { + console.log(line.substring(0, this.col)+'|'+this.ch+'\''+this.col+'\''+line.substr(this.col+1)) + } +} + +var Search = require("ace/search").Search; +var search = new Search(); + +function find(editor, needle, dir) { + search.$options.needle = needle + search.$options.backwards = dir == -1 + return search.find(editor.session) +} +var lang = require("ace/lib/lang"); +var Range = require("ace/range").Range; + module.exports = { - "w": { - nav: function(editor) { - editor.navigateWordRight(); - }, - sel: function(editor) { - editor.selection.selectWordRight(); + "w": new Motion(function(editor) { + var str = new StringStream(editor) + + if (str.ch && wordSeparatorRe.test(str.ch)) { + while (str.ch && wordSeparatorRe.test(str.ch)) + str.next() + } else { + while (str.ch && !nonWordRe.test(str.ch)) + str.next() } - }, - "b": { - nav: function(editor) { - editor.navigateWordLeft(); - }, - sel: function(editor) { - editor.selection.selectWordLeft(); + while (str.ch && whiteRe.test(str.ch) && str.skippedLines < 2) + str.next() + + str.skippedLines == 2 && str.prev() + return {column: str.col, row: str.row} + }), + "W": new Motion(function(editor) { + var str = new StringStream(editor) + while(str.ch && !(whiteRe.test(str.ch) && !whiteRe.test(str.peek(1))) && str.skippedLines < 2) + str.next() + if (str.skippedLines == 2) + str.prev() + else + str.next() + + return {column: str.col, row: str.row} + }), + "b": new Motion(function(editor) { + var str = new StringStream(editor) + + str.prev() + while (str.ch && whiteRe.test(str.ch) && str.skippedLines > -2) + str.prev() + + if (str.ch && wordSeparatorRe.test(str.ch)) { + while (str.ch && wordSeparatorRe.test(str.ch)) + str.prev() + } else { + while (str.ch && !nonWordRe.test(str.ch)) + str.prev() } - }, + str.ch && str.next(); + return {column: str.col, row: str.row} + }), + "B": new Motion(function(editor) { + var str = new StringStream(editor) + str.prev() + while(str.ch && !(!whiteRe.test(str.ch) && whiteRe.test(str.peek(-1))) && str.skippedLines > -2) + str.prev() + + if (str.skippedLines == -2) + str.next() + + return {column: str.col, row: str.row} + }, true), + "e": new Motion(function(editor) { + var str = new StringStream(editor) + + str.next() + while (str.ch && whiteRe.test(str.ch)) + str.next() + + if (str.ch && wordSeparatorRe.test(str.ch)) { + while (str.ch && wordSeparatorRe.test(str.ch)) + str.next() + } else { + while (str.ch && !nonWordRe.test(str.ch)) + str.next() + } + str.ch && str.prev() + return {column: str.col, row: str.row} + }), + "E": new Motion(function(editor) { + var str = new StringStream(editor) + str.next() + while(str.ch && !(!whiteRe.test(str.ch) && whiteRe.test(str.peek(1)))) + str.next() + + return {column: str.col, row: str.row} + }), + "l": { nav: function(editor) { editor.navigateRight(); @@ -72,12 +248,41 @@ module.exports = { editor.selection.selectDown(); } }, + "i": { param: true, sel: function(editor, range, count, param) { switch (param) { case "w": editor.selection.selectWord(); + break; + case "W": + editor.selection.selectAWord(); + break; + case "(": + case "{": + case "[": + var cursor = editor.getCursorPosition() + var end = editor.session.$findClosingBracket(param, cursor, /paren/) + if (!end) + return + var start = editor.session.$findOpeningBracket(editor.session.$brackets[param], cursor, /paren/) + if (!start) + return + start.column ++; + editor.selection.setSelectionRange(Range.fromPoints(start, end)) + break + case "'": + case "\"": + case "/": + var end = find(editor, param, 1) + if (!end) + return + var start = find(editor, param, -1) + if (!start) + return + editor.selection.setSelectionRange(Range.fromPoints(start.end, end.start)) + break } } }, @@ -87,16 +292,46 @@ module.exports = { switch (param) { case "w": editor.selection.selectAWord(); + break; + case "W": + editor.selection.selectAWord(); + break; + case "(": + case "{": + case "[": + var cursor = editor.getCursorPosition() + var end = editor.session.$findClosingBracket(param, cursor, /paren/) + if (!end) + return + var start = editor.session.$findOpeningBracket(editor.session.$brackets[param], cursor, /paren/) + if (!start) + return + end.column ++; + editor.selection.setSelectionRange(Range.fromPoints(start, end)) + break + case "'": + case "\"": + case "/": + var end = find(editor, param, 1) + if (!end) + return + var start = find(editor, param, -1) + if (!start) + return + end.column ++; + editor.selection.setSelectionRange(Range.fromPoints(start.start, end.end)) + break } } }, + "f": { param: true, + handlesCount: true, nav: function(editor, range, count, param) { - count = parseInt(count, 10) || 1; var ed = editor; var cursor = ed.getCursorPosition(); - var column = util.getRightNthChar(editor, cursor, param, count); + var column = util.getRightNthChar(editor, cursor, param, count || 1); if (typeof column === "number") { ed.selection.clearSelection(); // Why does it select in the first place? @@ -104,18 +339,18 @@ module.exports = { } }, sel: function(editor, range, count, param) { - count = parseInt(count, 10) || 1; var ed = editor; var cursor = ed.getCursorPosition(); - var column = util.getRightNthChar(editor, cursor, param, count); + var column = util.getRightNthChar(editor, cursor, param, count || 1); if (typeof column === "number") { ed.moveCursorTo(cursor.row, column + cursor.column + 1); } } }, - "shift-f": { + "F": { param: true, + handlesCount: true, nav: function(editor, range, count, param) { count = parseInt(count, 10) || 1; var ed = editor; @@ -124,27 +359,26 @@ module.exports = { if (typeof column === "number") { ed.selection.clearSelection(); // Why does it select in the first place? - ed.moveCursorTo(cursor.row, cursor.column - column + 1); + ed.moveCursorTo(cursor.row, cursor.column - column - 1); } }, sel: function(editor, range, count, param) { - count = parseInt(count, 10) || 1; var ed = editor; var cursor = ed.getCursorPosition(); - var column = util.getLeftNthChar(editor, cursor, param, count); + var column = util.getLeftNthChar(editor, cursor, param, count || 1); if (typeof column === "number") { - ed.moveCursorTo(cursor.row, cursor.column - column + 1); + ed.moveCursorTo(cursor.row, cursor.column - column - 1); } } }, "t": { param: true, + handlesCount: true, nav: function(editor, range, count, param) { - count = parseInt(count, 10) || 1; var ed = editor; var cursor = ed.getCursorPosition(); - var column = util.getRightNthChar(editor, cursor, param, count); + var column = util.getRightNthChar(editor, cursor, param, count || 1); if (typeof column === "number") { ed.selection.clearSelection(); // Why does it select in the first place? @@ -152,16 +386,39 @@ module.exports = { } }, sel: function(editor, range, count, param) { - count = parseInt(count, 10) || 1; var ed = editor; var cursor = ed.getCursorPosition(); - var column = util.getRightNthChar(editor, cursor, param, count); + var column = util.getRightNthChar(editor, cursor, param, count || 1); if (typeof column === "number") { ed.moveCursorTo(cursor.row, column + cursor.column); } } }, + "T": { + param: true, + handlesCount: true, + nav: function(editor, range, count, param) { + var ed = editor; + var cursor = ed.getCursorPosition(); + var column = util.getLeftNthChar(editor, cursor, param, count || 1); + + if (typeof column === "number") { + ed.selection.clearSelection(); // Why does it select in the first place? + ed.moveCursorTo(cursor.row, -column + cursor.column); + } + }, + sel: function(editor, range, count, param) { + var ed = editor; + var cursor = ed.getCursorPosition(); + var column = util.getLeftNthChar(editor, cursor, param, count || 1); + + if (typeof column === "number") { + ed.moveCursorTo(cursor.row, -column + cursor.column); + } + } + }, + "^": { nav: function(editor) { editor.navigateLineStart(); @@ -188,41 +445,20 @@ module.exports = { ed.selectTo(ed.selection.selectionLead.row, 0); } }, - "shift-g": { + "G": { nav: function(editor, range, count, param) { - count = parseInt(count, 10); if (!count && count !== 0) { // Stupid JS count = editor.session.getLength(); } editor.gotoLine(count); }, sel: function(editor, range, count, param) { - count = parseInt(count, 10); if (!count && count !== 0) { // Stupid JS count = editor.session.getLength(); } editor.selection.selectTo(count, 0); } }, - "ctrl-d": { - nav: function(editor, range, count, param) { - editor.selection.clearSelection(); - keepScrollPosition(editor, editor.gotoPageDown); - }, - sel: function(editor, range, count, param) { - keepScrollPosition(editor, editor.selectPageDown); - } - }, - "ctrl-u": { - nav: function(editor, range, count, param) { - editor.selection.clearSelection(); - keepScrollPosition(editor, editor.gotoPageUp); - - }, - sel: function(editor, range, count, param) { - keepScrollPosition(editor, editor.selectPageUp); - } - }, "g": { param: true, nav: function(editor, range, count, param) { @@ -235,6 +471,10 @@ module.exports = { break; case "g": editor.gotoLine(count || 0); + case "u": + editor.gotoLine(count || 0); + case "U": + editor.gotoLine(count || 0); } }, sel: function(editor, range, count, param) { @@ -264,7 +504,7 @@ module.exports = { } } }, - "shift-o": { + "O": { nav: function(editor, range, count, param) { var row = editor.getCursorPosition().row; count = count || 1; @@ -285,18 +525,42 @@ module.exports = { } } }, - "%": { - nav: function(editor, range, count, param) { - var cursor = editor.getCursorPosition(); - var match = editor.session.findMatchingBracket({ - row: cursor.row, - column: cursor.column + 1 - }); - - if (match) - editor.moveCursorTo(match.row, match.column); + "%": new Motion(function(editor){ + var brRe = /[\[\]{}()]/g; + var cursor = editor.getCursorPosition(); + var ch = editor.session.getLine(cursor.row)[cursor.column] + if (!brRe.test(ch)){ + var range = find(editor, brRe) + if (!range) + return + cursor = range.start } - } + var match = editor.session.findMatchingBracket({ + row: cursor.row, + column: cursor.column + 1 + }); + + return match + }), + "ctrl-d": { + nav: function(editor, range, count, param) { + editor.selection.clearSelection(); + keepScrollPosition(editor, editor.gotoPageDown); + }, + sel: function(editor, range, count, param) { + keepScrollPosition(editor, editor.selectPageDown); + } + }, + "ctrl-u": { + nav: function(editor, range, count, param) { + editor.selection.clearSelection(); + keepScrollPosition(editor, editor.gotoPageUp); + + }, + sel: function(editor, range, count, param) { + keepScrollPosition(editor, editor.selectPageUp); + } + }, }; module.exports.backspace = module.exports.left = module.exports.h; diff --git a/lib/ace/keyboard/vim/maps/operators.js b/lib/ace/keyboard/vim/maps/operators.js index 2b332dce..2dd67ee7 100644 --- a/lib/ace/keyboard/vim/maps/operators.js +++ b/lib/ace/keyboard/vim/maps/operators.js @@ -7,63 +7,65 @@ var registers = require("../registers"); module.exports = { "d": { - selFn: function(editor, range, count, param) { - registers._default.text = editor.getCopyText(); - registers._default.isLine = util.onVisualLineMode; - if(util.onVisualLineMode) - editor.removeLines(); - else - editor.session.remove(range); - util.normalMode(editor); - }, - fn: function(editor, range, count, param) { - count = parseInt(count || 1, 10); - switch (param) { - case "d": - registers._default.text = ""; - registers._default.isLine = true; - for (var i=0; i": { selFn: function(editor, range, count, param) { - count = parseInt(count || 1, 10); + count = count || 1; for (var i = 0; i < count; i++) { editor.indent(); } @@ -126,14 +128,14 @@ module.exports = { }, "<": { selFn: function(editor, range, count, param) { - count = parseInt(count || 1, 10); + count = count || 1; for (var i = 0; i < count; i++) { editor.blockOutdent(); } util.normalMode(editor); }, fn: function(editor, range, count, param) { - count = parseInt(count || 1, 10); + count = count || 1; switch (param) { case "<": var pos = editor.getCursorPosition(); diff --git a/lib/ace/keyboard/vim/maps/util.js b/lib/ace/keyboard/vim/maps/util.js index ae280aac..1956aec3 100644 --- a/lib/ace/keyboard/vim/maps/util.js +++ b/lib/ace/keyboard/vim/maps/util.js @@ -1,78 +1,75 @@ define(function(require, exports, module) { var registers = require("../registers"); +var dom = require("ace/lib/dom"); +dom.importCssString('.insert-mode. ace_cursor{\ + border-left: 2px solid #333333;\ +}\ +.ace_dark.insert-mode .ace_cursor{\ + border-left: 2px solid #eeeeee;\ +}\ +.normal-mode .ace_cursor{\ + border: 0!important;\ + background-color: red;\ + opacity: 0.5;\ +}', 'vimMode'); + module.exports = { onVisualMode: false, onVisualLineMode: false, currentMode: 'normal', + noMode: function(editor) { + editor.unsetStyle('insert-mode'); + editor.unsetStyle('normal-mode'); + if (editor.commands.recording) + editor.commands.toggleRecording(); + }, insertMode: function(editor) { - var _self = this; - var theme = editor && editor.getTheme() || "ace/theme/textmate"; + this.currentMode = 'insert'; + // Switch editor to insert mode + editor.setStyle('insert-mode'); + editor.unsetStyle('normal-mode'); - require(["require", theme], function (require) { - var isDarkTheme = require(theme).isDark; - _self.currentMode = 'insert'; - // Switch editor to insert mode - editor.unsetStyle('insert-mode'); - - var cursor = document.getElementsByClassName("ace_cursor")[0]; - if (cursor) { - cursor.style.display = null; - cursor.style.backgroundColor = null; - cursor.style.opacity = null; - cursor.style.border = null; - cursor.style.borderLeftColor = isDarkTheme? "#eeeeee" : "#333333"; - cursor.style.borderLeftStyle = "solid"; - cursor.style.borderLeftWidth = "2px"; - } - - editor.setOverwrite(false); - editor.keyBinding.$data.buffer = ""; - editor.keyBinding.$data.state = "insertMode"; - _self.onVisualMode = false; - _self.onVisualLineMode = false; - if(_self.onInsertReplaySequence) { - // Ok, we're apparently replaying ("."), so let's do it - editor.commands.macro = _self.onInsertReplaySequence; - editor.commands.replay(editor); - _self.onInsertReplaySequence = null; - _self.normalMode(editor); - } else { - // Record any movements, insertions in insert mode - if(!editor.commands.recording) - editor.commands.toggleRecording(); - } - }); + editor.setOverwrite(false); + editor.keyBinding.$data.buffer = ""; + editor.keyBinding.$data.state = "insertMode"; + this.onVisualMode = false; + this.onVisualLineMode = false; + if(this.onInsertReplaySequence) { + // Ok, we're apparently replaying ("."), so let's do it + editor.commands.macro = this.onInsertReplaySequence; + editor.commands.replay(editor); + this.onInsertReplaySequence = null; + this.normalMode(editor); + } else { + // Record any movements, insertions in insert mode + if(!editor.commands.recording) + editor.commands.toggleRecording(); + } }, normalMode: function(editor) { // Switch editor to normal mode this.currentMode = 'normal'; + editor.unsetStyle('insert-mode'); editor.setStyle('normal-mode'); editor.clearSelection(); - var cursor = document.getElementsByClassName("ace_cursor")[0]; - if (cursor) { - cursor.style.display = null; - cursor.style.backgroundColor = "red"; - cursor.style.opacity = ".5"; - cursor.style.border = "0"; - } - var pos; if (!editor.getOverwrite()) { pos = editor.getCursorPosition(); if (pos.column > 0) editor.navigateLeft(); } + editor.setOverwrite(true); editor.keyBinding.$data.buffer = ""; editor.keyBinding.$data.state = "start"; this.onVisualMode = false; this.onVisualLineMode = false; // Save recorded keystrokes - if(editor.commands.recording) { + if (editor.commands.recording) { editor.commands.toggleRecording(); return editor.commands.macro; } @@ -80,17 +77,36 @@ module.exports = { return []; } }, + visualMode: function(editor, lineMode) { + if ( + (this.onVisualLineMode && lineMode) + || (this.onVisualMode && !lineMode) + ) { + this.normalMode(editor); + return; + } + + editor.setStyle('insert-mode'); + editor.unsetStyle('normal-mode'); + + if (lineMode) { + this.onVisualLineMode = true; + } else { + this.onVisualMode = true; + this.onVisualLineMode = false; + } + }, getRightNthChar: function(editor, cursor, char, n) { var line = editor.getSession().getLine(cursor.row); var matches = line.substr(cursor.column + 1).split(char); - return n < matches.length ? matches.slice(0, n).join(char).length : 0; + return n < matches.length ? matches.slice(0, n).join(char).length : null; }, getLeftNthChar: function(editor, cursor, char, n) { var line = editor.getSession().getLine(cursor.row); var matches = line.substr(0, cursor.column).split(char); - return n < matches.length ? matches.slice(-1 * n).join(char).length + 2 : 0; + return n < matches.length ? matches.slice(-1 * n).join(char).length : null; }, toRealChar: function(char) { if (char.length === 1) diff --git a/lib/ace/lib/keys.js b/lib/ace/lib/keys.js index ef231039..30719ce1 100644 --- a/lib/ace/lib/keys.js +++ b/lib/ace/lib/keys.js @@ -102,7 +102,7 @@ var Keys = (function() { 80: 'p', 81: 'q', 82: 'r', 83: 's', 84: 't', 85: 'u', 86: 'v', 87: 'w', 88: 'x', 89: 'y', 90: 'z', 107: '+', 109: '-', 110: '.', 188: ',', 190: '.', 191: '/', 192: '`', 219: '[', 220: '\\', - 221: ']', 222: '\"' + 221: ']', 222: '\'' } }; diff --git a/lib/ace/mode/behaviour/cstyle.js b/lib/ace/mode/behaviour/cstyle.js index 3db838ad..f180fa39 100644 --- a/lib/ace/mode/behaviour/cstyle.js +++ b/lib/ace/mode/behaviour/cstyle.js @@ -40,7 +40,7 @@ define(function(require, exports, module) { "use strict"; var oop = require("../../lib/oop"); -var Behaviour = require('../behaviour').Behaviour; +var Behaviour = require("../behaviour").Behaviour; var CstyleBehaviour = function () {