Giter Club home page Giter Club logo

monaco-vim's Introduction

monaco-vim

Vim keybindings for monaco-editor demo

npm version

Install

Webpack/browserify

npm install monaco-vim
As global

This package will only work when bundled using webpack/browserify or using AMD. Including globally is not possible due to the use of an internal dependency of monaco-editor which is not exposed in the API. Loading 'monaco' globally is also not possible as you'll have to use its loader.js file. If you are using that, then there will be no problem. See AMD.

Usage

import { initVimMode } from 'monaco-vim';

const vimMode = initVimMode(editor, document.getElementById('my-statusbar'))

Here, editor is initialized instance of monaco editor and the 2nd argument should be the node where you would like to place/show the VIM status info.

To remove the attached VIM bindings, call

vimMode.dispose();

Handling key presses

If you would like a particular keypress to not be handled by this extension, add your onKeyDown handler before initializing monaco-vim and call preventDefault() on it. monaco-vim will ignore such events and won't do anything. This can be useful if you want to handle events like running code on CTRL/CMD+Enter which otherwise would have been eaten up by monaco-vim. (Available from v0.0.14 onwards).

AMD

If you are following the official guide and integrating the AMD version of monaco-editor, you can follow this -

<!DOCTYPE html>
<html>
<head>
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta http-equiv="Content-Type" content="text/html;charset=utf-8" >
</head>
<body>

<div id="container" style="width:800px;height:600px;border:1px solid grey"></div>
<div id="status"></div>

<script src="https://unpkg.com/monaco-editor/min/vs/loader.js"></script>
<script>
  require.config({
    paths: {
      'vs': 'https://unpkg.com/monaco-editor/min/vs',
      'monaco-vim': 'https://unpkg.com/monaco-vim/dist/monaco-vim',
    }
  });
  require(['vs/editor/editor.main', 'monaco-vim'], function(a, MonacoVim) {
    var editor = monaco.editor.create(document.getElementById('container'), {
      value: [
        'function x() {',
        '\tconsole.log("Hello world!");',
        '}'
      ].join('\n'),
      language: 'javascript'
    });
    var statusNode = document.getElementById('status');
    var vimMode = MonacoVim.initVimMode(editor, statusNode);

    // remove vim mode by calling
    // vimMode.dispose();
  });
</script>
</body>
</html>

See demo.js for full usage.

If you would like to customize the statusbar or provide your own implementation, see initVimMode's implementation in src/index.js.

Adding custom key bindings

Actual vim implementation can be imported as:

import { VimMode } from 'monaco-vim';

Defining ex mode command

// VimMode.Vim.defineEx(name, shorthand, callback);
VimMode.Vim.defineEx('write', 'w', function() {
  // your own implementation on what you want to do when :w is pressed
  localStorage.setItem('editorvalue', editor.getValue());
});

For advanced usage, refer codemirror. CodeMirror.Vim is available as VimMode.Vim;

This implementaion of VIM is a layer between Codemirror's VIM keybindings and monaco. There may be issues in some of the keybindings, especially those that expect extra input like the Ex commands or search/replace. If you encounter such bugs, create a new issue. PRs to resolve those are welcome too.

monaco-vim's People

Contributors

animeshz avatar berniexie avatar brijeshb42 avatar cgnonofr avatar corrieann avatar dependabot[bot] avatar drakulix avatar exaphis avatar gorbit99 avatar jserme avatar katlyn-edwards avatar masad-frost avatar partouf avatar rynorris avatar terryzfeng avatar thien-do avatar tjk avatar valeras avatar wujun51227 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

monaco-vim's Issues

Support newer monacos

We love this plugin; would be great if it supported 0.22.x monaco versions. It seems like it probably works, perhaps just the package.json peer dependencies need updating?

di( sometimes deletes {} blocks

Copying from compiler-explorer/compiler-explorer#1618

Describe the bug
di( is supposed to remove everything inside the innermost matching (), but sometimes (I don't know under what conditions) it deletes a {} block instead.

To Reproduce

 int  main() {
    int( 1 );
}

With the cursor on the 1, type di(. If you remove the space before the 1, this it does the right thing.

Monaco 0.32 won't work with monaco-vim

When trying the new Monaco version, we get

ERROR in ./node_modules/monaco-vim/lib/cm_adapter.js 10:28-105
Module not found: Error: Can't resolve 'monaco-editor/esm/vs/editor/common/controller/cursorTypeOperations' in '/home/ruben/coding/godbolt/ce/node_modules/monaco-vim/lib'
 @ ./node_modules/monaco-vim/lib/cm/keymap_vim.js 8:41-65

Seems like the new path is now found at monaco-editor/esm/vs/editor/common/cursor/cursorTypeOperations which makes the new version work as expected

Editor freezes when using /g on search and replace

Hello,

I've been experiencing a bug where if the text that is being replaced contains content from before the match and /g is used,the editor will freeze.

For example, if the editor content consists of foo bar, :s/bar/foo bar/g will break the editor
:%s/bar/foo bar works fine.

It may be related to a commit this year from src/cm_adapter.js:967, as reverting that specific line fixed the issue.
commit hash: 914b9e1

Inconsistencies with CodeMirror vim

I've been playing around with the demo and it's looking really good, I can't wait to use this in a real project!

I've spotted the following small issues – these all work fine in the CodeMirror demo so hopefully they won't be too hard to fix. Let me know if you need further clarification on any of these.


  • Ctrl+O causes new line to be inserted

Steps to reproduce:

  1. Press } to move to the next block
  2. Press Ctrl+O

Expected result:

  1. The cursor returns to the previous position

Actual result:

  1. The cursor returns to the previous position
  2. A new line is inserted at the cursor position

  • Parenthesis/brace text objects do not work

Steps to reproduce:

  1. Position the cursor inside a pair of parentheses/braces ((...), { ... }, [ ... ] etc)
  2. Press any of the corresponding text objects, e.g. dib, vaB, ci] etc

Expected result:

  1. The edit/selection is applied

Actual result:

  • No effect

N.B. More details on the available text objects can be found here


  • t jump cannot be repeated

Steps to reproduce:

  1. Position the cursor at the start of a line that contains multiple occurrences of a character (e.g. a)
  2. Press e.g. ta to jump to the position immediately before the first occurrence
  3. Press ; to jump to the next occurrence within the current line
  4. Press , to jump back to the previous occurrence

Expected result:

  • The cursor moves between occurrences within the current line

Actual result:

  • The cursor stays at the first occurrence

N.B. This works fine with f, just not with t


  • Put does not cause cursor to change posittion

Steps to reproduce:

  1. Position the cursor within a word
  2. Press ye to yank the remainder of the word
  3. Press p to put the yanked text after the current position

Expected result:

  • The cursor moves to the end of the inserted text

Actual result:

  • The cursor does not move

  • Delete > put > undo skips intermediate history state

Steps to reproduce:

  1. Position the cursor within a word
  2. Press de to delete the rest of the word
  3. Press p to put the deleted text after the current position
  4. Press u to undo the put

Expected result:

  1. The inserted text is removed

Actual result:

  1. The inserted text is removed
  2. The deleted text is restored

  • Ctrl+[ should perform the same function as Esc key

Steps to reproduce:

  1. Press i to enter insert mode
  2. Press Ctrl+[

Expected result:

  • The editor leaves insert mode

Actual result:

  • The editor remains in insert mode

… also one final one that is also present in the CodeMirror version – no worries if this is too much effort to look into!

  • Change > undo creates extra intermediate history state

Steps to reproduce:

  1. Press e.g. s to enter change mode (or ce, ciw, vec etc)
  2. Type some text
  3. Press Esc to leave insert mode
  4. Press u to undo the insertion

Expected result:

  1. The inserted text is removed
  2. The deleted text is restored

Actual result:

  1. The inserted text is removed
  2. The deleted text is not restored unless you press u again

Paste in visual mode does not replace last character

When pasting in visual mode, the last character in the selection (the character under the cursor) is not replaced. To reproduce, enter into visual mode, make a selection, press yank, make the same selection again, and then paste.

I tried to dig into this a bit and noticed that, when yanking, there is a one character offset added to either the head or the anchor (see makeCmSelection, L3116 to L3119). This doesn't happen when pasting. I came up with a naive solution by adding 1 to selectionEnd.ch after L2597:

var selectionEnd = selectedArea[1];

// Added the following two lines
selectionEnd.ch += 1;
cm.setSelection(selectionStart, selectionEnd)

var selectedText = cm.getSelection();

It would be great to get this behavior fixed so that it mimics vim :) Thanks so much!

Unable to integrate via AMD

Monaco Editor: v0.17.1
Monaco Vim: v0.0.14

I've tried an example code show how to integrate monaco-vim with monaco-editor using AMD. But it has problem import some file.

Here is an error.
image

This error comes from this file.

import { TypeOperations } from 'monaco-editor/esm/vs/editor/common/controller/cursorTypeOperations';

Could you help with this problem? I would love to use this ^^

Thank you

Search/Substitute Syntax for limited searches

Vim supports search/substitution with bounded queries:
:.,+2s/something/something_else

Which is supposed to search from the current line, to the current line plus 2, for the string something and replace it with something_else.

It looks like the +2 is ignored.

Add option to start in insert mode

In order to initialize an editor in insert mode, I don't see any way other than simulating keypress events like so:

const vim = initVimMode(editor, statusBar);

const browserEvent = new Event('keydown');
browserEvent.keyCode = 39;
browserEvent.key = "i";

const wrapperEvent = new Event('keydown');
wrapperEvent.keyCode = 39;
wrapperEvent.browserEvent = browserEvent;

vim.handleKeyDown(wrapperEvent);

Could this be made into a higher-level API like a flag passed to initVimMode? I'd also be happy with instead offering an API to interact directly with the internal vim state, which would be powerful.

r does not replaced marked section in visual mode

when one marks a section in visual mode (visual, visual block, visual line) in vim, and hits r␣, then all marked characters get replaced by whitespaces.

on godbolt.org, r␣ just ends visual mode and goes back to normal mode, but does not replace the marked characters.

Visual mode breaks with "enter"

Pressing enter while in visual mode should not actually insert an enter.

Repro steps: press 'v' to enter visual mode
select text using arrow keys.
press enter.
text is removed.

Avoid assigning text to innerHTML

It looks like statusbar.js has some assignments to innerHTML which are somewhat difficult to audit to ensure that they do not contain user-controlled text.

Would it be possible to allow an HTML sanitizer to be provided to validate the content?

I'd imagine something like an additional argument to initVimMode, where if provided:

if (sanitizer) {
  // Clear out previous contents first
  target.textContent = '';
  target.appendChild(sanitizer(htmlContents));
} else {
  target.innerHTML = htmlContents;
}

Again- these may be benign, but as-is, it's non-trivial to audit.

Thanks!

Buggy on Safari.

I am using Safari 10.

I am unable to switch between normal/insert modes using ESC/i keys. To repro, simply load the official demo in Safari, and try to switch between modes.

`r↵` does not insert the newline in the right place

How to reproduce:

starting from a textbox with

if ( b ) { f(); }
// trailing comment

One might want to introduce line breaks by moving the cursor on the whitespace in front of f() and type r↵. The result should then be

if ( b ) {
f(); }
// trailing comment

Contrary to the expectation, the result is

if ( b ) {f(); }

// trailing comment

i.e.

  • a line feed got inserted after (good)
  • the whitespace before the f() got removed (good)
  • everything after that whitespace did not get moved to the new line, after the linefeed (bad)

on linux, tested in firefox and google-chrome.

Indenting with `>` cases error `e.indentLine is not a function`

This can be reproduced in the monaco playground https://editor.bitwiser.in/
Issue the normal mode command >>. The expected result would be that the current line or visual selection is indented by one level. This doesn't happen. Instead there's an error message in the console.

TypeError: e.indentLine is not a function
    at Object.indent (65.525a3f98171e18d877f8.js:1)
    at Object.evalInput (65.525a3f98171e18d877f8.js:1)
    at Object.processOperator (65.525a3f98171e18d877f8.js:1)
    at Object.processCommand (65.525a3f98171e18d877f8.js:1)
    at 65.525a3f98171e18d877f8.js:1
    at e.value (65.525a3f98171e18d877f8.js:1)
    at 65.525a3f98171e18d877f8.js:1
    at C.handleKeyDown (65.525a3f98171e18d877f8.js:1)
    at e.fire (bundle.573d4004e7ef173aa606.js:1)
    at t.o.onKeyDown (bundle.573d4004e7ef173aa606.js:1)
    at Object.indent (65.525a3f98171e18d877f8.js:1)
    at Object.evalInput (65.525a3f98171e18d877f8.js:1)
    at Object.processOperator (65.525a3f98171e18d877f8.js:1)
    at Object.processCommand (65.525a3f98171e18d877f8.js:1)
    at 65.525a3f98171e18d877f8.js:1
    at e.value (65.525a3f98171e18d877f8.js:1)
    at 65.525a3f98171e18d877f8.js:1
    at C.handleKeyDown (65.525a3f98171e18d877f8.js:1)
    at e.fire (bundle.573d4004e7ef173aa606.js:1)
    at t.o.onKeyDown (bundle.573d4004e7ef173aa606.js:1)
    at bundle.573d4004e7ef173aa606.js:1

Type Annotations?

Hey there!

I've been making a few contributions, and think it'd be really helpful to have some form of type annotations.

For example: https://github.com/brijeshb42/monaco-vim/blob/master/src/statusbar.js#L31
options here is actually a pretty complex object:
@param {{

  • bottom: boolean,
  • desc: string,
  • onKeyDown: function,
  • onKeyUp: function(),
  • onClose: function(),
  • prefix: string,
  • selectValueOnOpen: boolean}} options,
  • value: string,
  • }};

Happy to help either add Closure style annotations, or to migrate to TypeScript.

extend demo to show how to hook :w

i'm trying to figure out how to hook the write command right now.
in case i find it, i might submit a pr. otherwise i'd appreciate a code snippet for that task.

Question about peerDependencies

Greetings.

monaco-vim lists a peer dependency of monaco-editor at "^0.14.0 || ^0.15.0", but 0.16 and 0.17 are available. Is monaco-vim incompatible with these newer versions of monaco-editor? If not, can we simply update the peerDependencies listing to include those newer versions? I'm happy to create a PR if so.

Thanks!

feature request: event listener for command execution

we currently use monaco-vim for online code editing, somehow we have a tree view and wanna toggle files by :e command inside the tree view, just like what you did at terminal. so it would be nice if monaco-vim could provide an event listener, the api could be:

const vimMode = MonacoVim.initVimMode(editor, statusNode);
vimMode.on('afterCommandExecuted', (command) => {
  // user do what they want according to the command
});

// or vimMode.addEventListener('event', handler)

so that our users can use :e command to toggle files for free :)

Pressing `c` in visual mode should delete currently selected characters

Amazing job on this! I've spotted one minor inconsistency so far:

Steps to reproduce:

  1. Press v to enter visual mode
  2. [Optional] Use motions to expand the selection
  3. Press c

Expected result:

  1. The currently selected range is deleted
  2. The editor switches to insert mode, with the cursor at the start offset of the visual selection range

Actual result:

  1. [The selection is not deleted]
  2. The editor switches to insert mode, with the cursor at the start offset of the visual selection range

Great work though, it feels really solid otherwise!

AMD load does not work?

Using the exact code from the AMD example in the README, I get the same issue I see when trying to integrate in my own amd-aware app:

Loading "vs/editor/common/controller/cursorTypeOperations" failed

The cursorTypeOperations script only lives in the esm variant of monaco-editor.

I see that cm_adapter.js specifically relies on the esm variant of monaco -- is there any chance that AMD usage can be restored?

Thanks

preventDefault not respected

related to #18

I added a listener for Ctrl+C to prevent sending it to monaco-vim; I added preventDefault, and stopPropagation, yet monaco-vim still handles it.

handleKeyDown = (e) => {

At this point, e should be checked ot see if e.browserEvent.defaultPrevented, and if so, do nothing.

executecommands bug

In cm_adapter.js line 1111 currently is:

editor.executeCommands(

it should be:

this.editor.executeCommands(

Support monaco-editor 0.19.0

Monaco-editor did breaking changes: getConfiguration() is replaced by getRawOptions(), which returns the passed in editor options.

So, monaco-vim doesn't work with 0.19.0 version of the editor.

Copying spans of text with the mouse doesn't work reliably

This can be seen on the playground demo as well: https://editor.bitwiser.in/

Steps to repro:
Select to enable vim on the playground
Attempt to select the entire line of "package kotlin"

Notice that as soon as you go over the "n" with your mouse, selection breaks. Even if you try to then go back to the left, selection weirdly restarts from the right.

Expectation is that this behaves as normal browser native selection.

Bracket Matching

when I put vi(, cursor is at 333

it will match {} first, it's strange.

function test(){
   console.log(333)
}

Monaco commands with overlapping shortcuts get ignored

this.monaco.addCommand(
    monaco.KeyCode.Escape,
    () => {
       alert('hello!')
    }, 'true');

Since escape is also used for leaving input mode in Vim, this alert appears to never be fired.
It'd be cool if monaco-vim let keyboard shortcuts propogate if they were unhandled, whereas currently it seems that propagation is stopped somewhere.

Can't leave insert mode

See #18

ESC is getting default-prevented from Monaco itself, and the library seems to be respecting that.

Maybe we can add a flag/property to the event to disable defaultPrevented from stopping it?

multiple editors causes issues with search

If you happen to have two editors with monaco vim, (think a UI with diffing, or before-after, or merging, or notebooks with multiple editing cells), search always focuses the last status bar, instead of the status bar for the editor you were using.

I tried having one central status bar for all editors, but this also doesn't work, since each registration with that status bar adds a new "status" layer into the bar.

How to map `jk` to <Esc> ?

How to map jk to ?

Answer:

import { VimMode } from "monaco-vim"

VimMode.Vim.map("jk", "<Esc>", "insert")

undo does too much undoing

  1. visit the demo page:
    https://editor.bitwiser.in/

  2. enable vim mode

  3. enter insert mode

  4. type I will delete this WORD after typing this

  5. hit escape

  6. move the cursor to the front of WORD

  7. type dw in command mode to delete the word

  8. press u in command mode to undo deleting the word

  9. notice that the end of the sentence this is also now gone.

Actions on visual selection is off-by-one

When selecting text in visual mode, the cursor position is off by one relative to regular vim.

Steps to reproduce:
(0) Enable vim keybindings on the demo site: https://editor.bitwiser.in/
(1) Enter the string "blah word blah"
(2) Enter visual mode with the cursor over the "w" and move the cursor to be blinking over the "d".
(3) Perform some operation on the selected text (e.g. delete (d), yank (y), toggle case (~))

Expected result:
The operation is performed on the string "word". For example, if you toggled case, the cell should contain "blah WORD blah".

Actual result:
The operation is performed on the string "wor". For example, if you toggled case, the cell contains "blah WORd blah".

This is different from vim's behavior in the terminal.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.