Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
128 changes: 125 additions & 3 deletions dev/cm5/index.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,128 @@
import { initVim as initVimInternal } from "../../src/vim.js";

export function initVim(CodeMirror5) {
CodeMirror5.Vim = initVimInternal(CodeMirror5);
return CodeMirror5.Vim;
export function initVim(CodeMirror) {
var Vim = CodeMirror.Vim = initVimInternal(CodeMirror);
var Pos = CodeMirror.Pos;

function transformCursor(cm, range) {
var vim = cm.state.vim;
if (!vim || vim.insertMode) return range.head;
var head = vim.sel.head;
if (!head) return range.head;

if (vim.visualBlock) {
if (range.head.line != head.line) {
return;
}
}
if (range.from() == range.anchor && !range.empty()) {
if (range.head.line == head.line && range.head.ch != head.ch)
return new Pos(range.head.line, range.head.ch - 1);
}

return range.head;
}

CodeMirror.keyMap['vim-insert'] = {
// TODO: override navigation keys so that Esc will cancel automatic
// indentation from o, O, i_<CR>
fallthrough: ['default'],
attach: attachVimMap,
detach: detachVimMap,
call: cmKey
};

CodeMirror.keyMap['vim-replace'] = {
'Backspace': 'goCharLeft',
fallthrough: ['vim-insert'],
attach: attachVimMap,
detach: detachVimMap
};


CodeMirror.keyMap.vim = {
attach: attachVimMap,
detach: detachVimMap,
call: cmKey
};

// Deprecated, simply setting the keymap works again.
CodeMirror.defineOption('vimMode', false, function(cm, val, prev) {
if (val && cm.getOption("keyMap") != "vim")
cm.setOption("keyMap", "vim");
else if (!val && prev != CodeMirror.Init && /^vim/.test(cm.getOption("keyMap")))
cm.setOption("keyMap", "default");
});

function cmKey(key, cm) {
if (!cm) { return undefined; }
if (this[key]) { return this[key]; }
var vimKey = cmKeyToVimKey(key);
if (!vimKey) {
return false;
}
var cmd = Vim.findKey(cm, vimKey);
if (typeof cmd == 'function') {
CodeMirror.signal(cm, 'vim-keypress', vimKey);
}
return cmd;
}

var modifiers = {Shift:'S',Ctrl:'C',Alt:'A',Cmd:'D',Mod:'A',CapsLock:''};
var specialKeys = {Enter:'CR',Backspace:'BS',Delete:'Del',Insert:'Ins'};

function cmKeyToVimKey(key) {
if (key.charAt(0) == '\'') {
// Keypress character binding of format "'a'"
return key.charAt(1);
}
var pieces = key.split(/-(?!$)/);
var lastPiece = pieces[pieces.length - 1];
if (pieces.length == 1 && pieces[0].length == 1) {
// No-modifier bindings use literal character bindings above. Skip.
return false;
} else if (pieces.length == 2 && pieces[0] == 'Shift' && lastPiece.length == 1) {
// Ignore Shift+char bindings as they should be handled by literal character.
return false;
}
var hasCharacter = false;
for (var i = 0; i < pieces.length; i++) {
var piece = pieces[i];
if (piece in modifiers) { pieces[i] = modifiers[piece]; }
else { hasCharacter = true; }
if (piece in specialKeys) { pieces[i] = specialKeys[piece]; }
}
if (!hasCharacter) {
// Vim does not support modifier only keys.
return false;
}
// TODO: Current bindings expect the character to be lower case, but
// it looks like vim key notation uses upper case.
if (/^[A-Z]$/.test(lastPiece))
pieces[pieces.length - 1] = lastPiece.toLowerCase();

return '<' + pieces.join('-') + '>';
}

function detachVimMap(cm, next) {
if (this == CodeMirror.keyMap.vim) {
cm.options.$customCursor = null;
CodeMirror.rmClass(cm.getWrapperElement(), "cm-fat-cursor");
}

if (!next || next.attach != attachVimMap)
Vim.leaveVimMode(cm);
}
function attachVimMap(cm, prev) {
if (this == CodeMirror.keyMap.vim) {
if (cm.curOp) cm.curOp.selectionChanged = true;
cm.options.$customCursor = transformCursor;
CodeMirror.addClass(cm.getWrapperElement(), "cm-fat-cursor");
}

if (!prev || prev.attach != attachVimMap)
Vim.enterVimMode(cm);
}

return CodeMirror.Vim;
}
48 changes: 0 additions & 48 deletions src/cm_adapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,15 +66,6 @@ function signalTo(handlers: any, ...args: any[]) {
for (var i = 0; i < handlers.length; ++i) { handlers[i](...args); }
}

var specialKey: any = {
Return: 'CR', Backspace: 'BS', 'Delete': 'Del', Escape: 'Esc', Insert: 'Ins',
ArrowLeft: 'Left', ArrowRight: 'Right', ArrowUp: 'Up', ArrowDown: 'Down',
Enter: 'CR', ' ': 'Space'
};
var ignoredKeys: any = { Shift: 1, Alt: 1, Command: 1, Control: 1,
CapsLock: 1, AltGraph: 1, Dead: 1, Unidentified: 1 };


let wordChar: RegExp
try {
wordChar = new RegExp("[\\w\\p{Alphabetic}\\p{Number}_]", "u")
Expand Down Expand Up @@ -170,45 +161,6 @@ export class CodeMirror {
e?.stopPropagation?.()
e?.preventDefault?.()
};
static keyName = function (e: KeyboardEvent) {
var key = e.key;
if (ignoredKeys[key]) return;
if (key == "Escape") key = "Esc";
if (key == " ") key = "Space";
if (key.length > 1) {
key = key.replace(/Numpad|Arrow/, "");
}
if (key.length == 1) key = key.toUpperCase();
var name = '';
if (e.ctrlKey) { name += 'Ctrl-'; }
if (e.altKey) { name += 'Alt-'; }
if ((name || key.length > 1) && e.shiftKey) { name += 'Shift-'; }
name += key;
return name;
};
static vimKey = function vimKey(e: KeyboardEvent) {
var key = e.key;
if (ignoredKeys[key]) return;
if (key.length > 1 && key[0] == "n") {
key = key.replace("Numpad", "");
}
key = specialKey[key] || key;
var name = '';
if (e.ctrlKey) { name += 'C-'; }
if (e.altKey) { name += 'A-'; }
if (e.metaKey) { name += 'M-'; }
// on mac many characters are entered as option- combos
// (e.g. on swiss keyboard { is option-8)
// so we ignore lonely A- modifier for keypress event on mac
if (CodeMirror.isMac && e.altKey && !e.metaKey && !e.ctrlKey) {
name = name.slice(2);
}
if ((name || key.length > 1) && e.shiftKey) { name += 'S-'; }

name += key;
if (name.length > 1) { name = '<' + name + '>'; }
return name;
};

static lookupKey = function lookupKey(key: string, map: string, handle: Function) {
var result = CodeMirror.keys[key];
Expand Down
21 changes: 17 additions & 4 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -197,14 +197,12 @@ const vimPlugin = ViewPlugin.fromClass(
decorations = Decoration.none;
waitForCopy = false;
handleKey(e: KeyboardEvent, view: EditorView) {
const rawKey = CodeMirror.vimKey(e);
if (!rawKey) return;

const cm = this.cm;
let vim = cm.state.vim;
if (!vim) return;

const key = vim.expectLiteralNext ? rawKey : Vim.langmapRemapKey(rawKey);
const key = Vim.vimKeyFromEvent(e, vim);
if (!key) return;

// clear search highlight
if (
Expand Down Expand Up @@ -253,6 +251,7 @@ const vimPlugin = ViewPlugin.fromClass(
}
lastKeydown = ''
useNextTextInput = false
compositionText = ''
},
{
eventHandlers: {
Expand Down Expand Up @@ -307,6 +306,20 @@ const vimPlugin = ViewPlugin.fromClass(
return true;
}
if (text.length == 1 && vimPlugin.useNextTextInput) {
if (vim.expectLiteralNext && view.composing) {
vimPlugin.compositionText = text;
return false
}
if (vimPlugin.compositionText) {
var toRemove = vimPlugin.compositionText;
vimPlugin.compositionText = '';
var head = view.state.selection.main.head
var textInDoc = view.state.sliceDoc(head - toRemove.length, head);
if (toRemove === textInDoc) {
var pos = cm.getCursor();
cm.replaceRange('', cm.posFromIndex(head - toRemove.length), pos);
}
}
vimPlugin.handleKey({
key: text,
preventDefault: ()=>{},
Expand Down
Loading