codemirror 3.18 with enabled the fullscreen addon

This commit is contained in:
Paolo
2013-09-26 21:52:53 +02:00
parent 633acffd28
commit ddf1998d49
166 changed files with 3820 additions and 2321 deletions
+138 -101
View File
@@ -40,6 +40,10 @@
* TODO: Implement the remaining special marks. They have more complex
* behavior.
*
* Events:
* 'vim-mode-change' - raised on the editor anytime the current mode changes,
* Event object: {mode: "visual", subMode: "linewise"}
*
* Code structure:
* 1. Default keymap
* 2. Variable declarations and short basic helpers
@@ -206,8 +210,7 @@
// Operators
{ keys: ['d'], type: 'operator', operator: 'delete' },
{ keys: ['y'], type: 'operator', operator: 'yank' },
{ keys: ['c'], type: 'operator', operator: 'change',
operatorArgs: { enterInsertMode: true } },
{ keys: ['c'], type: 'operator', operator: 'change' },
{ keys: ['>'], type: 'operator', operator: 'indent',
operatorArgs: { indentRight: true }},
{ keys: ['<'], type: 'operator', operator: 'indent',
@@ -231,10 +234,11 @@
motion: 'moveToEol', motionArgs: { inclusive: true },
operatorMotionArgs: { visualLine: true }},
{ keys: ['C'], type: 'operatorMotion',
operator: 'change', operatorArgs: { enterInsertMode: true },
operator: 'change',
motion: 'moveToEol', motionArgs: { inclusive: true },
operatorMotionArgs: { visualLine: true }},
{ keys: ['~'], type: 'operatorMotion', operator: 'swapcase',
{ keys: ['~'], type: 'operatorMotion',
operator: 'swapcase', operatorArgs: { shouldMoveCursor: true },
motion: 'moveByCharacters', motionArgs: { forward: true }},
// Actions
{ keys: ['<C-i>'], type: 'action', action: 'jumpListWalk',
@@ -315,6 +319,28 @@
];
var Vim = function() {
CodeMirror.defineOption('vimMode', false, function(cm, val) {
if (val) {
cm.setOption('keyMap', 'vim');
CodeMirror.signal(cm, "vim-mode-change", {mode: "normal"});
cm.on('beforeSelectionChange', beforeSelectionChange);
maybeInitVimState(cm);
} else if (cm.state.vim) {
cm.setOption('keyMap', 'default');
cm.off('beforeSelectionChange', beforeSelectionChange);
cm.state.vim = null;
}
});
function beforeSelectionChange(cm, cur) {
var vim = cm.state.vim;
if (vim.insertMode || vim.exMode) return;
var head = cur.head;
if (head.ch && head.ch == cm.doc.getLine(head.line).length) {
head.ch--;
}
}
var numberRegex = /[\d]/;
var wordRegexp = [(/\w/), (/[^\w\s]/)], bigWordRegexp = [(/\S/)];
function makeKeyRange(start, size) {
@@ -450,28 +476,11 @@
};
};
// Global Vim state. Call getVimGlobalState to get and initialize.
var vimGlobalState;
function getVimGlobalState() {
if (!vimGlobalState) {
vimGlobalState = {
// The current search query.
searchQuery: null,
// Whether we are searching backwards.
searchIsReversed: false,
jumpList: createCircularJumpList(),
macroModeState: createMacroState(),
// Recording latest f, t, F or T motion command.
lastChararacterSearch: {increment:0, forward:true, selectedCharacter:''},
registerController: new RegisterController({})
};
}
return vimGlobalState;
}
function getVimState(cm) {
if (!cm.vimState) {
function maybeInitVimState(cm) {
if (!cm.state.vim) {
// Store instance state in the CodeMirror object.
cm.vimState = {
cm.state.vim = {
inputState: new InputState(),
// Vim's input state that triggered the last edit, used to repeat
// motions and operators with '.'.
@@ -500,7 +509,21 @@
visualLine: false
};
}
return cm.vimState;
return cm.state.vim;
}
var vimGlobalState;
function resetVimGlobalState() {
vimGlobalState = {
// The current search query.
searchQuery: null,
// Whether we are searching backwards.
searchIsReversed: false,
jumpList: createCircularJumpList(),
macroModeState: createMacroState(),
// Recording latest f, t, F or T motion command.
lastChararacterSearch: {increment:0, forward:true, selectedCharacter:''},
registerController: new RegisterController({})
};
}
var vimApi= {
@@ -510,16 +533,19 @@
// Testing hook, though it might be useful to expose the register
// controller anyways.
getRegisterController: function() {
return getVimGlobalState().registerController;
return vimGlobalState.registerController;
},
// Testing hook.
clearVimGlobalState_: function() {
vimGlobalState = null;
},
resetVimGlobalState_: resetVimGlobalState,
// Testing hook.
getVimGlobalState_: function() {
return vimGlobalState;
},
// Testing hook.
maybeInitVimState_: maybeInitVimState,
InsertModeKey: InsertModeKey,
map: function(lhs, rhs) {
// Add user defined key bindings.
@@ -532,17 +558,12 @@
exCommands[name]=func;
exCommandDispatcher.commandMap_[prefix]={name:name, shortName:prefix, type:'api'};
},
// Initializes vim state variable on the CodeMirror object. Should only be
// called lazily by handleKey or for testing.
maybeInitState: function(cm) {
getVimState(cm);
},
// This is the outermost function called by CodeMirror, after keys have
// been mapped to their Vim equivalents.
handleKey: function(cm, key) {
var command;
var vim = getVimState(cm);
var macroModeState = getVimGlobalState().macroModeState;
var vim = maybeInitVimState(cm);
var macroModeState = vimGlobalState.macroModeState;
if (macroModeState.enteredMacroMode) {
if (key == 'q') {
actions.exitMacroRecordMode();
@@ -554,19 +575,17 @@
// Clear input state and get back to normal mode.
vim.inputState = new InputState();
if (vim.visualMode) {
exitVisualMode(cm, vim);
exitVisualMode(cm);
}
return;
}
if (vim.visualMode &&
cursorEqual(cm.getCursor('head'), cm.getCursor('anchor'))) {
// The selection was cleared. Exit visual mode.
exitVisualMode(cm, vim);
}
// Enter visual mode when the mouse selects text.
if (!vim.visualMode &&
!cursorEqual(cm.getCursor('head'), cm.getCursor('anchor'))) {
vim.visualMode = true;
vim.visualLine = false;
CodeMirror.signal(cm, "vim-mode-change", {mode: "visual"});
cm.on('mousedown', exitVisualMode);
}
if (key != '0' || (key == '0' && vim.inputState.getRepeat() === 0)) {
// Have to special case 0 since it's both a motion and a number.
@@ -970,7 +989,7 @@
// cachedCursor is used to save the old position of the cursor
// when * or # causes vim to seek for the nearest word and shift
// the cursor before entering the motion.
getVimGlobalState().jumpList.cachedCursor = cm.getCursor();
vimGlobalState.jumpList.cachedCursor = cm.getCursor();
cm.setCursor(word.start);
handleQuery(query, true /** ignoreCase */, false /** smartCase */);
@@ -1052,7 +1071,7 @@
return;
}
if (motionArgs.toJumplist) {
var jumpList = getVimGlobalState().jumpList;
var jumpList = vimGlobalState.jumpList;
// if the current motion is # or *, use cachedCursor
var cachedCursor = jumpList.cachedCursor;
if (cachedCursor) {
@@ -1091,6 +1110,11 @@
if (vim.visualLine) {
if (cursorIsBefore(selectionStart, selectionEnd)) {
selectionStart.ch = 0;
var lastLine = cm.lastLine();
if (selectionEnd.line > lastLine) {
selectionEnd.line = lastLine;
}
selectionEnd.ch = lineLength(cm, selectionEnd.line);
} else {
selectionEnd.ch = 0;
@@ -1146,15 +1170,12 @@
operators[operator](cm, operatorArgs, vim, curStart,
curEnd, curOriginal);
if (vim.visualMode) {
exitVisualMode(cm, vim);
}
if (operatorArgs.enterInsertMode) {
actions.enterInsertMode(cm, {}, vim);
exitVisualMode(cm);
}
}
},
recordLastEdit: function(vim, inputState, actionCommand) {
var macroModeState = getVimGlobalState().macroModeState;
var macroModeState = vimGlobalState.macroModeState;
if (macroModeState.inReplay) { return; }
vim.lastEditInputState = inputState;
vim.lastEditActionCommand = actionCommand;
@@ -1272,8 +1293,13 @@
}
var repeat = motionArgs.repeat+(motionArgs.repeatOffset||0);
var line = motionArgs.forward ? cur.line + repeat : cur.line - repeat;
if (line < cm.firstLine() || line > cm.lastLine() ) {
return null;
var first = cm.firstLine();
var last = cm.lastLine();
// Vim cancels linewise motions that start on an edge and move beyond
// that edge. It does not cancel motions that do not start on an edge.
if ((line < first && cur.line == first) ||
(line > last && cur.line == last)) {
return;
}
if(motionArgs.toFirstChar){
endCh=findFirstNonWhiteSpaceCharacter(cm.getLine(line));
@@ -1456,7 +1482,7 @@
return [start, end];
},
repeatLastCharacterSearch: function(cm, motionArgs) {
var lastSearch = getVimGlobalState().lastChararacterSearch;
var lastSearch = vimGlobalState.lastChararacterSearch;
var repeat = motionArgs.repeat;
var forward = motionArgs.forward === lastSearch.forward;
var increment = (lastSearch.increment ? 1 : 0) * (forward ? -1 : 1);
@@ -1474,22 +1500,16 @@
var operators = {
change: function(cm, operatorArgs, _vim, curStart, curEnd) {
getVimGlobalState().registerController.pushText(
vimGlobalState.registerController.pushText(
operatorArgs.registerName, 'change', cm.getRange(curStart, curEnd),
operatorArgs.linewise);
if (operatorArgs.linewise) {
// Delete starting at the first nonwhitespace character of the first
// line, instead of from the start of the first line. This way we get
// an indent when we get into insert mode. This behavior isn't quite
// correct because we should treat this as a completely new line, and
// indent should be whatever codemirror thinks is the right indent.
// But cm.indentLine doesn't seem work on empty lines.
// TODO: Fix the above.
curStart.ch =
findFirstNonWhiteSpaceCharacter(cm.getLine(curStart.line));
// Insert an additional newline so that insert mode can start there.
// curEnd should be on the first character of the new line.
cm.replaceRange('\n', curStart, curEnd);
// Push the next line back down, if there is a next line.
var replacement = curEnd.line > cm.lastLine() ? '' : '\n';
cm.replaceRange(replacement, curStart, curEnd);
cm.indentLine(curStart.line, 'smart');
// null ch so setCursor moves to end of line.
curStart.ch = null;
} else {
// Exclude trailing whitespace if the range is not all whitespace.
var text = cm.getRange(curStart, curEnd);
@@ -1501,6 +1521,7 @@
}
cm.replaceRange('', curStart, curEnd);
}
actions.enterInsertMode(cm, {}, cm.state.vim);
cm.setCursor(curStart);
},
// delete is a javascript keyword.
@@ -1512,7 +1533,7 @@
curStart.line--;
curStart.ch = lineLength(cm, curStart.line);
}
getVimGlobalState().registerController.pushText(
vimGlobalState.registerController.pushText(
operatorArgs.registerName, 'delete', cm.getRange(curStart, curEnd),
operatorArgs.linewise);
cm.replaceRange('', curStart, curEnd);
@@ -1542,7 +1563,7 @@
cm.setCursor(curStart);
cm.setCursor(motions.moveToFirstNonWhiteSpaceCharacter(cm));
},
swapcase: function(cm, _operatorArgs, _vim, curStart, curEnd, curOriginal) {
swapcase: function(cm, operatorArgs, _vim, curStart, curEnd, curOriginal) {
var toSwap = cm.getRange(curStart, curEnd);
var swapped = '';
for (var i = 0; i < toSwap.length; i++) {
@@ -1551,10 +1572,12 @@
character.toUpperCase();
}
cm.replaceRange(swapped, curStart, curEnd);
cm.setCursor(curOriginal);
if (!operatorArgs.shouldMoveCursor) {
cm.setCursor(curOriginal);
}
},
yank: function(cm, operatorArgs, _vim, curStart, curEnd, curOriginal) {
getVimGlobalState().registerController.pushText(
vimGlobalState.registerController.pushText(
operatorArgs.registerName, 'yank',
cm.getRange(curStart, curEnd), operatorArgs.linewise);
cm.setCursor(curOriginal);
@@ -1568,7 +1591,7 @@
}
var repeat = actionArgs.repeat;
var forward = actionArgs.forward;
var jumpList = getVimGlobalState().jumpList;
var jumpList = vimGlobalState.jumpList;
var mark = jumpList.move(cm, forward ? repeat : -repeat);
var markPos = mark ? mark.find() : undefined;
@@ -1594,7 +1617,7 @@
replayMacro: function(cm, actionArgs) {
var registerName = actionArgs.selectedCharacter;
var repeat = actionArgs.repeat;
var macroModeState = getVimGlobalState().macroModeState;
var macroModeState = vimGlobalState.macroModeState;
if (registerName == '@') {
registerName = macroModeState.latestRegister;
}
@@ -1604,18 +1627,19 @@
}
},
exitMacroRecordMode: function() {
var macroModeState = getVimGlobalState().macroModeState;
var macroModeState = vimGlobalState.macroModeState;
macroModeState.toggle();
parseKeyBufferToRegister(macroModeState.latestRegister,
macroModeState.macroKeyBuffer);
},
enterMacroRecordMode: function(cm, actionArgs) {
var macroModeState = getVimGlobalState().macroModeState;
var macroModeState = vimGlobalState.macroModeState;
var registerName = actionArgs.selectedCharacter;
macroModeState.toggle(cm, registerName);
emptyMacroKeyBuffer(macroModeState);
},
enterInsertMode: function(cm, actionArgs, vim) {
if (cm.getOption('readOnly')) { return; }
vim.insertMode = true;
vim.insertModeRepeat = actionArgs && actionArgs.repeat || 1;
var insertAt = (actionArgs) ? actionArgs.insertAt : null;
@@ -1633,10 +1657,12 @@
// Handle Replace-mode as a special case of insert mode.
cm.toggleOverwrite(true);
cm.setOption('keyMap', 'vim-replace');
CodeMirror.signal(cm, "vim-mode-change", {mode: "replace"});
} else {
cm.setOption('keyMap', 'vim-insert');
CodeMirror.signal(cm, "vim-mode-change", {mode: "insert"});
}
if (!getVimGlobalState().macroModeState.inReplay) {
if (!vimGlobalState.macroModeState.inReplay) {
// Only record if not replaying.
cm.on('change', onChange);
cm.on('cursorActivity', onCursorActivity);
@@ -1651,6 +1677,7 @@
// equal to the repeat times the size of the previous visual
// operation.
if (!vim.visualMode) {
cm.on('mousedown', exitVisualMode);
vim.visualMode = true;
vim.visualLine = !!actionArgs.linewise;
if (vim.visualLine) {
@@ -1675,6 +1702,7 @@
} else {
cm.setSelection(curStart, curEnd);
}
CodeMirror.signal(cm, "vim-mode-change", {mode: "visual", subMode: vim.visualLine ? "linewise" : ""});
} else {
curStart = cm.getCursor('anchor');
curEnd = cm.getCursor('head');
@@ -1687,12 +1715,14 @@
curEnd.ch = cursorIsBefore(curStart, curEnd) ?
lineLength(cm, curEnd.line) : 0;
cm.setSelection(curStart, curEnd);
CodeMirror.signal(cm, "vim-mode-change", {mode: "visual", subMode: "linewise"});
} else if (vim.visualLine && !actionArgs.linewise) {
// v pressed in linewise visual mode. Switch to characterwise visual
// mode instead of exiting visual mode.
vim.visualLine = false;
CodeMirror.signal(cm, "vim-mode-change", {mode: "visual"});
} else {
exitVisualMode(cm, vim);
exitVisualMode(cm);
}
}
updateMark(cm, vim, '<', cursorIsBefore(curStart, curEnd) ? curStart
@@ -1728,6 +1758,7 @@
});
},
newLineAndEnterInsertMode: function(cm, actionArgs, vim) {
vim.insertMode = true;
var insertAt = cm.getCursor();
if (insertAt.line === cm.firstLine() && !actionArgs.after) {
// Special case for inserting newline before start of document.
@@ -1746,7 +1777,7 @@
},
paste: function(cm, actionArgs) {
var cur = cm.getCursor();
var register = getVimGlobalState().registerController.getRegister(
var register = vimGlobalState.registerController.getRegister(
actionArgs.registerName);
if (!register.text) {
return;
@@ -1832,7 +1863,7 @@
cm.replaceRange(replaceWithStr, curStart, curEnd);
if(vim.visualMode){
cm.setCursor(curStart);
exitVisualMode(cm,vim);
exitVisualMode(cm);
}else{
cm.setCursor(offsetCursor(curEnd, 0, -1));
}
@@ -1989,7 +2020,9 @@
return s.replace(/([.?*+$\[\]\/\\(){}|\-])/g, '\\$1');
}
function exitVisualMode(cm, vim) {
function exitVisualMode(cm) {
cm.off('mousedown', exitVisualMode);
var vim = cm.state.vim;
vim.visualMode = false;
vim.visualLine = false;
var selectionStart = cm.getCursor('anchor');
@@ -2000,6 +2033,7 @@
// it's not supposed to be.
cm.setCursor(clipCursorToContent(cm, selectionEnd));
}
CodeMirror.signal(cm, "vim-mode-change", {mode: "normal"});
}
// Remove any trailing newlines from the selection. For
@@ -2113,12 +2147,11 @@
function recordJumpPosition(cm, oldCur, newCur) {
if(!cursorEqual(oldCur, newCur)) {
getVimGlobalState().jumpList.add(cm, oldCur, newCur);
vimGlobalState.jumpList.add(cm, oldCur, newCur);
}
}
function recordLastCharacterSearch(increment, args) {
var vimGlobalState = getVimGlobalState();
vimGlobalState.lastChararacterSearch.increment = increment;
vimGlobalState.lastChararacterSearch.forward = args.forward;
vimGlobalState.lastChararacterSearch.selectedCharacter = args.selectedCharacter;
@@ -2572,10 +2605,10 @@
function SearchState() {}
SearchState.prototype = {
getQuery: function() {
return getVimGlobalState().query;
return vimGlobalState.query;
},
setQuery: function(query) {
getVimGlobalState().query = query;
vimGlobalState.query = query;
},
getOverlay: function() {
return this.searchOverlay;
@@ -2584,14 +2617,14 @@
this.searchOverlay = overlay;
},
isReversed: function() {
return getVimGlobalState().isReversed;
return vimGlobalState.isReversed;
},
setReversed: function(reversed) {
getVimGlobalState().isReversed = reversed;
vimGlobalState.isReversed = reversed;
}
};
function getSearchState(cm) {
var vim = getVimState(cm);
var vim = cm.state.vim;
return vim.searchState_ || (vim.searchState_ = new SearchState());
}
function dialog(cm, template, shortText, onClose, options) {
@@ -2840,9 +2873,9 @@
};
Vim.ExCommandDispatcher.prototype = {
processCommand: function(cm, input) {
var vim = getVimState(cm);
var vim = cm.state.vim;
if (vim.visualMode) {
exitVisualMode(cm, vim);
exitVisualMode(cm);
}
var inputStream = new CodeMirror.StringStream(input);
var params = {};
@@ -2921,7 +2954,7 @@
case '$':
return cm.lastLine();
case '\'':
var mark = getVimState(cm).marks[inputStream.next()];
var mark = cm.state.vim.marks[inputStream.next()];
if (mark && mark.find()) {
return mark.find().line;
}
@@ -3031,7 +3064,7 @@
exCommandDispatcher.map(mapArgs[0], mapArgs[1], cm);
},
move: function(cm, params) {
commandDispatcher.processCommand(cm, getVimState(cm), {
commandDispatcher.processCommand(cm, cm.state.vim, {
type: 'motion',
motion: 'moveToLineOrEdgeOfDocument',
motionArgs: { forward: false, explicitRepeat: true,
@@ -3186,7 +3219,7 @@
return;
}
var state = getVimState(cm);
var state = cm.state.vim;
var stream = new CodeMirror.StringStream(params.argString.trim());
while (!stream.eol()) {
stream.eatSpace();
@@ -3257,6 +3290,7 @@
function doReplace(cm, confirm, lineStart, lineEnd, searchCursor, query,
replaceWith) {
// Set up all the functions.
cm.state.vim.exMode = true;
var done = false;
var lastPos = searchCursor.from();
function replaceAll() {
@@ -3291,7 +3325,8 @@
cm.focus();
if (lastPos) {
cm.setCursor(lastPos);
var vim = getVimState(cm);
var vim = cm.state.vim;
vim.exMode = false;
vim.lastHPos = vim.lastHSPos = lastPos.ch;
}
}
@@ -3403,9 +3438,8 @@
CodeMirror.keyMap.vim = buildVimKeyMap();
function exitInsertMode(cm) {
var vim = getVimState(cm);
vim.insertMode = false;
var inReplay = getVimGlobalState().macroModeState.inReplay;
var vim = cm.state.vim;
var inReplay = vimGlobalState.macroModeState.inReplay;
if (!inReplay) {
cm.off('change', onChange);
cm.off('cursorActivity', onCursorActivity);
@@ -3419,8 +3453,10 @@
}
delete vim.insertModeRepeat;
cm.setCursor(cm.getCursor().line, cm.getCursor().ch-1, true);
vim.insertMode = false;
cm.setOption('keyMap', 'vim');
cm.toggleOverwrite(false); // exit replace mode if we were in it.
CodeMirror.signal(cm, "vim-mode-change", {mode: "normal"});
}
CodeMirror.keyMap['vim-insert'] = {
@@ -3446,7 +3482,7 @@
function parseRegisterToKeyBuffer(macroModeState, registerName) {
var match, key;
var register = getVimGlobalState().registerController.getRegister(registerName);
var register = vimGlobalState.registerController.getRegister(registerName);
var text = register.toString();
var macroKeyBuffer = macroModeState.macroKeyBuffer;
emptyMacroKeyBuffer(macroModeState);
@@ -3462,7 +3498,7 @@
function parseKeyBufferToRegister(registerName, keyBuffer) {
var text = keyBuffer.join('');
getVimGlobalState().registerController.setRegisterText(registerName, text);
vimGlobalState.registerController.setRegisterText(registerName, text);
}
function emptyMacroKeyBuffer(macroModeState) {
@@ -3490,7 +3526,7 @@
* Should only be active in insert mode.
*/
function onChange(_cm, changeObj) {
var macroModeState = getVimGlobalState().macroModeState;
var macroModeState = vimGlobalState.macroModeState;
var lastChange = macroModeState.lastInsertModeChanges;
while (changeObj) {
lastChange.expectCursorActivityForChange = true;
@@ -3510,7 +3546,7 @@
* - Should only be active in insert mode.
*/
function onCursorActivity() {
var macroModeState = getVimGlobalState().macroModeState;
var macroModeState = vimGlobalState.macroModeState;
var lastChange = macroModeState.lastInsertModeChanges;
if (lastChange.expectCursorActivityForChange) {
lastChange.expectCursorActivityForChange = false;
@@ -3531,7 +3567,7 @@
* - For recording deletes in insert mode.
*/
function onKeyEventTargetKeyDown(e) {
var macroModeState = getVimGlobalState().macroModeState;
var macroModeState = vimGlobalState.macroModeState;
var lastChange = macroModeState.lastInsertModeChanges;
var keyName = CodeMirror.keyName(e);
function onKeyFound() {
@@ -3553,7 +3589,7 @@
* corresponding enterInsertMode call was made with a count.
*/
function repeatLastEdit(cm, vim, repeat, repeatForInsert) {
var macroModeState = getVimGlobalState().macroModeState;
var macroModeState = vimGlobalState.macroModeState;
macroModeState.inReplay = true;
var isAction = !!vim.lastEditActionCommand;
var cachedInputState = vim.inputState;
@@ -3621,6 +3657,7 @@
}
}
resetVimGlobalState();
return vimApi;
};
// Initialize Vim and make it available as an API.