{"id":13483313,"url":"https://github.com/lambdalisue/jupyter-vim-binding","last_synced_at":"2025-09-28T19:31:30.682Z","repository":{"id":36868699,"uuid":"41175671","full_name":"lambdalisue/jupyter-vim-binding","owner":"lambdalisue","description":"Jupyter meets Vim. Vimmer will fall in love.","archived":true,"fork":false,"pushed_at":"2023-08-22T18:34:16.000Z","size":1718,"stargazers_count":2102,"open_issues_count":47,"forks_count":136,"subscribers_count":45,"default_branch":"master","last_synced_at":"2024-09-27T02:41:01.050Z","etag":null,"topics":["codemirror-vim","jupyter-notebook","jupyter-vim-binding","vim-mode"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/lambdalisue.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":".github/CONTRIBUTING.md","funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2015-08-21T20:18:33.000Z","updated_at":"2024-09-24T02:18:20.000Z","dependencies_parsed_at":"2024-01-13T18:34:02.617Z","dependency_job_id":null,"html_url":"https://github.com/lambdalisue/jupyter-vim-binding","commit_stats":null,"previous_names":[],"tags_count":7,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lambdalisue%2Fjupyter-vim-binding","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lambdalisue%2Fjupyter-vim-binding/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lambdalisue%2Fjupyter-vim-binding/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lambdalisue%2Fjupyter-vim-binding/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/lambdalisue","download_url":"https://codeload.github.com/lambdalisue/jupyter-vim-binding/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":234555785,"owners_count":18851845,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["codemirror-vim","jupyter-notebook","jupyter-vim-binding","vim-mode"],"created_at":"2024-07-31T17:01:09.975Z","updated_at":"2025-09-28T19:31:25.348Z","avatar_url":"https://github.com/lambdalisue.png","language":"JavaScript","funding_links":[],"categories":["JavaScript"],"sub_categories":[],"readme":"jupyter-vim-binding\n===============================================================================\n![Version 2.1.0](https://img.shields.io/badge/version-2.1.0-yellow.svg?style=flat-square) ![Support Jupyter 4.1 or above](https://img.shields.io/badge/support-Jupyter%204.1%20or%20above-yellowgreen.svg?style=flat-square) [![MIT License](https://img.shields.io/badge/license-MIT-blue.svg?style=flat-square)](LICENSE) ![Doc](https://img.shields.io/badge/doc-%3Ah%20Press%20F1%20on%20Jupyter-orange.svg?style=flat-square)\n\n---\n\n**See https://github.com/jupyterlab-contrib/jupyterlab-vim for an alternative of this plugin.**\n\n---\n\nDo you use Vim? And you need to use [Jupyter Notebook]?\nThis is a [Jupyter Notebook][] (formerly known as [IPython Notebook][]) extension to enable Vim like environment powered by [CodeMirror's Vim][].\nI'm sure that this plugin helps to improve your QOL.\n\n[Jupyter Notebook]: https://jupyter.org/\n[IPython Notebook]: http://ipython.org/notebook.html\n[CodeMirror's Vim]: https://codemirror.net/demo/vim.html\n[IPython-notebook-extensions]: https://github.com/ipython-contrib/IPython-notebook-extensions\n\n\u003cdiv align=\"center\"\u003e\n  \u003cimg src=\"resource/screencast.gif\" alt=\"Screencast\"\u003e\n\u003c/div\u003e\n\nThis extension stands for providing a Vim like environment, so it would drastically overwrite the default mappings and introduce new behaviors.\nFor example\n\n- Jupyter has two modes, *Command mode* and *Edit mode* but this extension has three modes, *Jupyter mode*, *Vim command mode*, and *Insert mode*\n- Jupyter provides `C` (`Shift-c`) and `V` (`Shift-v`) to perform copy and paste cells, but this extension provides `yy` and `p` to perform copy and paste cells\n- Jupyter provides `\u003cC-s\u003e` (`Ctrl-s`) to save a checkpoint, but this extension eliminates that mapping while `:w` works same\n- A lot more.\n\n\nNeed contributors\n-------------------------------------------------------------------------------\n\nWhile I changed my job, I don't use jupyter notebook, and I can't make enough time to maintain this plugin.\n\n**So if you like this plugin, please consider being a contributor.**\n\nhttps://github.com/lambdalisue/jupyter-vim-binding/issues/89\n\n\nInstallation\n-------------------------------------------------------------------------------\n\nThere are several ways to install the extension, see [Installation](https://github.com/lambdalisue/jupyter-vim-binding/wiki/Installation) for detail.\nThe procedure below is the most simple one for quick use (**A recommended way is different from this. See the link above if you are a beginner.**)\n\n```bash\n# Create required directory in case (optional)\nmkdir -p $(jupyter --data-dir)/nbextensions\n# Clone the repository\ncd $(jupyter --data-dir)/nbextensions\ngit clone https://github.com/lambdalisue/jupyter-vim-binding vim_binding\n# Activate the extension\njupyter nbextension enable vim_binding/vim_binding\n```\n\n\nUsage\n-------------------------------------------------------------------------------\n\nThis extension provides *Jupyter mode* (For manipulating Jupyter) and *Vim mode* (For manipulating text).\nIn *Vim mode*, there is *Command mode* and *Insert mode* like native Vim.\nUsers can distinguish these modes by the background color of the cell.\n\nKey mappings are designed for Vimmer so probably you don't need to know much about the mapping but remember the followings to survive:\n\n- All mappings are shown by hitting `\u003cF1\u003e`\n- Enter *Vim mode*; a super mode of *Vim command mode* and *Insert mode*; by 1) Double clicking a cell, 2) Hit `\u003cEnter\u003e` on a cell, or 3) Hit `i` on a cell\n- Leave *Vim mode* and re-enter *Jupyter mode* by `:q` or `\u003cS-Esc\u003e` (`Shift-Escape`)\n- Enter *Insert mode* or leave *Insert mode* as like Vim (`i`, `a`, etc.)\n\nYou can find detailed information about the mappings or concept in [Concept](https://github.com/lambdalisue/jupyter-vim-binding/wiki/Concept) page.\n\n\nCompletion and Tooltip\n-------------------------------------------------------------------------------\n\njupyter-vim-binding supports `\u003cC-n\u003e`/`\u003cC-p\u003e` completion and `\u003cC-g\u003e` tooltip in a code cell (not in markdown / raw cell).\nThese mappings are not listed in a help panel, due to a technical limitation.\n\nWhen the user hits `\u003cC-n\u003e` or `\u003cC-p\u003e`, a completion panel like below will be shown.\nOnce the completion panel is shown, users can select a candidate by `\u003cC-n\u003e`/`\u003cC-p\u003e` and apply by `\u003cEnter\u003e` or cancel by `\u003cEsc\u003e`.\n\n![Completion](resource/completion.png)\n\nWhen user hit `\u003cC-g\u003e`, a tooltip panel like below will be shown.\nThe tooltip will disappear when users perform some actions like hitting a key.\n\n![Tooltip](resource/tooltip.png)\n\nNote that you can repeat `\u003cC-g\u003e` to make the tooltip larger (more information).\n\n\nPlug mappings\n-------------------------------------------------------------------------------\n\njupyter-vim-binding provides the following `\u003cPlug\u003e` mappings for CodeMirror.\n\n- `\u003cPlug\u003e(vim-binding-j)` : `j` which move to the next cell at the cell side\n- `\u003cPlug\u003e(vim-binding-k)` : `k` which move to the previous cell at the cell side\n- `\u003cPlug\u003e(vim-binding-gj)` : `gj` which move to the next cell at the cell side\n- `\u003cPlug\u003e(vim-binding-gk)` : `gk` which move to the previous cell at the cell side\n- `\u003cPlug\u003e(vim-binding-+)` : `+` which move to the next cell at the cell side\n- `\u003cPlug\u003e(vim-binding--)` : `-` which move to the previous cell at the cell side\n- `\u003cPlug\u003e(vim-binding-_)` : `_` which move to the next cell at the cell side\n\nWhile CodeMirror's Vim does not provide `noremap` type of mappings.\nYou need to use these `\u003cPlug\u003e` mappings to prevent an infinite loop (See samples in Customization section).\n\n\nCustomization\n-------------------------------------------------------------------------------\n\nTo customize key mappings in *Vim mode*, you need to understand that there are two kinds of mappings in this extension:\n\n1. Mappings provided by [Jupyter Notebook][], users can customize this type of mappings with [Keyboard shortcut editor][] provided in [IPython-notebook-extensions][]\n2. Mappings provided by [CodeMirror's Vim][], users can customize this type of mappings with [`custom.js`][] as described below\n\nTo customize mappings provided by [CodeMirror's Vim][], create a [`custom.js`][] at `~/.jupyter/custom/custom.js` (at least in Linux) and use [CodeMirror's Vim API][] to manipulate like:\n\n```javascript\n// Configure CodeMirror Keymap\nrequire([\n  'nbextensions/vim_binding/vim_binding',   // depends your installation\n], function() {\n  // Map jj to \u003cEsc\u003e\n  CodeMirror.Vim.map(\"jj\", \"\u003cEsc\u003e\", \"insert\");\n  // Swap j/k and gj/gk (Note that \u003cPlug\u003e mappings)\n  CodeMirror.Vim.map(\"j\", \"\u003cPlug\u003e(vim-binding-gj)\", \"normal\");\n  CodeMirror.Vim.map(\"k\", \"\u003cPlug\u003e(vim-binding-gk)\", \"normal\");\n  CodeMirror.Vim.map(\"gj\", \"\u003cPlug\u003e(vim-binding-j)\", \"normal\");\n  CodeMirror.Vim.map(\"gk\", \"\u003cPlug\u003e(vim-binding-k)\", \"normal\");\n});\n\n// Configure Jupyter Keymap\nrequire([\n  'nbextensions/vim_binding/vim_binding',\n  'base/js/namespace',\n], function(vim_binding, ns) {\n  // Add post callback\n  vim_binding.on_ready_callbacks.push(function(){\n    var km = ns.keyboard_manager;\n    // Allow Ctrl-2 to change the cell mode into Markdown in Vim normal mode\n    km.edit_shortcuts.add_shortcut('ctrl-2', 'vim-binding:change-cell-to-markdown', true);\n    // Update Help\n    km.edit_shortcuts.events.trigger('rebuild.QuickHelp');\n  });\n});\n```\n\nIf you would like to customize the design, create a your `custom.css` at `~/.jupyter/custom/custom.css` (at least in Linux) like:\n\n```css\n/* Jupyter cell is in normal mode when code mirror */\n.edit_mode .cell.selected .CodeMirror-focused.cm-fat-cursor {\n  background-color: #F5F6EB !important;\n}\n/* Jupyter cell is in insert mode when code mirror */\n.edit_mode .cell.selected .CodeMirror-focused:not(.cm-fat-cursor) {\n  background-color: #F6EBF1 !important;\n}\n```\n\nSee [Customization](https://github.com/lambdalisue/jupyter-vim-binding/wiki/Customization) to find useful snippets. Don't be afraid to share your snippets at that page ;-)\n\n[Keyboard shortcut editor]: https://github.com/ipython-contrib/IPython-notebook-extensions/tree/master/nbextensions/usability/keyboard_shortcut_editor\n[`custom.js`]: http://jdfreder-notebook.readthedocs.org/en/docs/examples/Notebook/JavaScript%20Notebook%20Extensions.html\n[CodeMirror's Vim API]: https://codemirror.net/doc/manual.html#vimapi\n\n\nLimitation\n-------------------------------------------------------------------------------\n\njupyter-vim-binding has the following technical limitation.\nIf anybody knows about a confirmed workaround for these limitations, let me know.\n\n### Google Chrome\n\nGoogle Chrome prohibits javascript from overriding several key mappings such as `Ctrl-N`, `Ctrl-T`, etc.\nBecause of this policy, users have no chance to use default key mappings of jupyter-vim-binding, such as `\u003cC-n\u003e` completion.\n\n- https://code.google.com/p/chromium/issues/detail?id=33056\n- http://stackoverflow.com/questions/15911785/overriding-shortcut-keys-in-firefox-and-chrome\n- https://github.com/liftoff/GateOne/issues/290\n\n### Vivaldi\n\nThe chromium-based [Vivaldi][vivaldi] browser provides more flexibility in key mapping customizations and might be a viable alternative to Google Chrome for power users.\nIn contrast to Google Chrome or Chromium, (almost) all keyboard shortcuts in Vivaldi can be [changed or disabled][vivaldi-keyboard], including (but not limited to) `Ctrl-N`, `Ctrl-T`, `Ctrl-J`, etc.\n\nFurthermore, Vivaldi allows assigning a keyboard shortcut to temporarily [disable all other browser keyboard shortcuts][vivaldi-disable], making all key mappings available for other uses.\nNote that this temporary change applies globally to *all* tabs and windows of the browser instance (or \"Profile\") under consideration. To confine it to a subset of tabs, use a separate profile via [the `--user-data-dir=...` option][user-data-dir].\n\n[vivaldi]: https://vivaldi.com/\n[vivaldi-keyboard]: https://vivalditips.com/customization/shortcuts/en\n[vivaldi-disable]: https://www.ghacks.net/2017/02/07/vivaldi-tip-block-all-keyboard-shortcuts/\n[user-data-dir]: https://chromium.googlesource.com/chromium/src/+/master/docs/user_data_dir.md\n\n### Clipboard\n\nMost modern browsers prohibit javascript from accessing a system clipboard without user action, such as clicking a button.\nBecause of this, there is no chance to enable copy and paste through `yy`, `dd`, or `p` while HTML5 clipboard object cannot be retrieved in a `keydown` event.\nSo Users need to use browser default mappings such as `Ctrl-C`, `Ctrl-V` if they want to copy and paste through a system clipboard.\n\nThe followings are clipboard library for javascript, but all of them require `click` event or no paste support.\n\n- https://github.com/zeroclipboard/zeroclipboard\n- https://clipboardjs.com/\n\nWhat we need is a `clipboard` object which can be used for copy and paste in a `keydown` event rather than `click` event.\nHowever, I don't know any workaround for this, so it is impossible to perform copy and paste in `yy` or `p` for now.\n\n\nLicense\n-------------------------------------------------------------------------------\n\nThe MIT License (MIT)\n\nCopyright (c) 2015-2016 Alisue, hashnote.net\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flambdalisue%2Fjupyter-vim-binding","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flambdalisue%2Fjupyter-vim-binding","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flambdalisue%2Fjupyter-vim-binding/lists"}