{"id":14990392,"url":"https://github.com/rhysd/neovim-component","last_synced_at":"2025-04-09T12:04:03.258Z","repository":{"id":44463105,"uuid":"46735546","full_name":"rhysd/neovim-component","owner":"rhysd","description":"\u003cneovim-editor\u003e WebComponent to embed Neovim to your app with great ease","archived":false,"fork":false,"pushed_at":"2020-07-07T01:34:47.000Z","size":376,"stargazers_count":197,"open_issues_count":12,"forks_count":19,"subscribers_count":9,"default_branch":"master","last_synced_at":"2025-04-02T06:48:26.319Z","etag":null,"topics":["electron","neovim","webcomponents"],"latest_commit_sha":null,"homepage":"https://github.com/rhysd/NyaoVim","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/rhysd.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2015-11-23T17:07:39.000Z","updated_at":"2025-02-09T22:37:39.000Z","dependencies_parsed_at":"2022-09-21T23:06:52.443Z","dependency_job_id":null,"html_url":"https://github.com/rhysd/neovim-component","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rhysd%2Fneovim-component","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rhysd%2Fneovim-component/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rhysd%2Fneovim-component/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rhysd%2Fneovim-component/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/rhysd","download_url":"https://codeload.github.com/rhysd/neovim-component/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248036064,"owners_count":21037092,"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":["electron","neovim","webcomponents"],"created_at":"2024-09-24T14:20:02.793Z","updated_at":"2025-04-09T12:04:03.224Z","avatar_url":"https://github.com/rhysd.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"`\u003cneovim-editor\u003e` Web Component\n===============================\n[![Build Status](https://travis-ci.org/rhysd/neovim-component.svg?branch=master)](https://travis-ci.org/rhysd/neovim-component)\n\n\nThis component provides `\u003cneovim-editor\u003e`, an HTML custom element built on [Polymer v2](https://github.com/Polymer/polymer)\nand [flux](https://github.com/facebook/flux).  It provides a frontend for the [Neovim editor](https://github.com/neovim/neovim)\nusing Neovim's MessagePack API. It allows you to easily embed a Neovim-backed editor into your application.\n\n**This component assumes to be used in Node.js environment. (i.e. Electron)**\n\nYou can use this component for modern desktop application frameworks such as [Electron](https://github.com/atom/electron)\nor [NW.js](https://github.com/nwjs/nw.js).  You can even use it in Electron-based editors such as [Atom](http://atom.io/)\nor [VS Code](https://github.com/Microsoft/vscode).\n\nThis component is designed around the [Flux architecture](https://facebook.github.io/flux/docs/overview.html).\nYou can access the UI event notifications and can call Neovim APIs directly via `\u003cneovim-editor\u003e`'s\nAPIs.\n\nYou can install this component as an [npm package](https://www.npmjs.com/package/neovim-component).\n\n```\n$ npm install neovim-component\n```\n\nCurrent supported `nvim` version is v0.1.6 or later.\n\n\n## Examples\n\nEach example only takes 100~300 lines.\n\n### [Minimal Example](/example/minimal)\n\n```html\n\u003c!DOCTYPE html\u003e\n\u003chtml\u003e\n  \u003chead\u003e\n    \u003cmeta charset=\"utf-8\" /\u003e\n    \u003cscript src=\"/path/to/webcomponents-lite.js\"\u003e\u003c/script\u003e\n    \u003clink rel=\"import\" href=\"/path/to/polymer.html\" /\u003e\n    \u003clink rel=\"import\" href=\"/path/to/neovim-editor.html\" /\u003e\n  \u003c/head\u003e\n  \u003cbody\u003e\n    \u003cneovim-editor\u003e\u003c/neovim-editor\u003e\n  \u003c/body\u003e\n\u003c/html\u003e\n```\n\nMinimal [Electron](https://github.com/atom/electron) app can be found in the [example directory](/example/minimal).\nThis is a good start point to use this package and it shows how the component works.\n\n![main screenshot](https://raw.githubusercontent.com/rhysd/ss/master/neovim-component/main.gif)\n\nHow to run minimal example is:\n\n```sh\n$ git clone https://github.com/rhysd/neovim-component.git\n$ cd neovim-component\n$ npm start\n```\n\n### [Markdown Editor Example](/example/markdown)\n\nFor a more complicated and realistic example, see the [markdown editor example](/example/markdown).\nThe markdown previewer is integrated with the Neovim GUI using the `\u003cneovim-editor\u003e` component.\n\n![markdown example screenshot](https://raw.githubusercontent.com/rhysd/ss/master/neovim-component/markdown-example.gif)\n\n### [Image Popup Example](/example/image-popup)\n\nThis is an image popup widget example [here](/example/image-popup).  The `gi` mapping is defined\nto show an image under the cursor in a tooltip.\n\n![image popup example screenshot](https://raw.githubusercontent.com/rhysd/ss/master/neovim-component/popup-image-example.gif)\n\n### [Mini Browser Example](/example/mini-browser)\n\nThis example shows how to include a mini web-browser using the\n[`\u003cwebview\u003e` tag from Electron](https://github.com/atom/electron/blob/master/docs/api/web-view-tag.md).\n\n![mini browser example screenshot](https://raw.githubusercontent.com/rhysd/ss/master/neovim-component/mini-browser.gif)\n\n\n## Why Did You Create This?\n\nVim has very powerful editing features, but Vim is an editor (see `:help design-not`) and unfortunately\nlacks support for many graphical tools that writers and programmers like.  NyaoVim adds support for\ngraphical features without losing Vim's powerful text editing abilities.\n[Neovim's msgpack APIs](https://neovim.io/doc/user/msgpack_rpc.html) provide a perfect way to add\na GUI layer using HTML and CSS.  [NyaoVim](https://github.com/rhysd/NyaoVim) is a GUI frontend as\na proof of concept.\n\n\n## Architecture\n\n![data flow](https://raw.githubusercontent.com/rhysd/ss/master/neovim-component/flow.png)\n\n`\u003cneovim-editor\u003e` has an `editor` property to access the internal APIs of the component.\n\n- `editor.screen` is a view of the component (using canvas).  It receives user input and dispatches\n  input actions to the data store.\n- `editor.process` is a process handler to interact with the backing Neovim process via msgpack-rpc\n  APIs.  You can call Neovim's APIs via the Neovim client (`editor.getClient()` helper).\n- `editor.store` is the state of this component.  You can access the current state of the editor through\n  this object.\n\n\n## `\u003cneovim-editor\u003e` Properties\n\nYou can customize `\u003cneovim-editor\u003e` with the following properties:\n\n| Name                | Description                                | Default       |\n| ------------------- | -------------------------------------------| ------------- |\n| `width`             | Width of the editor in pixels.             | `null`        |\n| `height`            | Height of the editor in pixels.            | `null`        |\n| `font`              | Name of the editor's monospace font.       | `\"monospace\"` |\n| `font-size`         | Font-size in pixels.                       | `12`          |\n| `line-height`       | Line height rate relative to font size.    | `1.3`         |\n| `nvim-cmd`          | Command used to start Neovim.              | `\"nvim\"`      |\n| `argv`              | Arguments passed with the Neovim command.  | `[]`          |\n| `on-quit`           | Callback function to run when Neovim quits.| `null`        |\n| `on-error`          | Callback function for Neovim errors.       | `null`        |\n| `disable-alt-key`   | Do not send alt key input to Neovim.       | `false`       |\n| `disable-meta-key`  | Do not send meta key input to Neovim.      | `false`       |\n| `cursor-draw-delay` | Delay in millisec before drawing cursor.   | `10`          |\n| `no-blink-cursor`   | Blink cursor or not.                       | `false`       |\n| `window-title`      | Specify first window title.                | `\"Neovim\"`    |\n\n\n## `\u003cneovim-editor\u003e` APIs\n\n### Receive internal various events\n\nYou can receive various events (including UI redraw notifications) from the **store**.\nThe `store` is a part of flux architecture. It's a global instance of [EventEmitter](https://nodejs.org/api/events.html).\n\nYou can also access the state of editor via the `store`. Note that all values are read only.\nDo not change the values of the `store` directly, it will break the internal state of the component.\n\n```javascript\nconst neovim_element = document.getElementById('neovim');\nconst Store = neovim_element.editor.store;\n\n// Handle cursor movements\nStore.on('cursor', () =\u003e console.log('Cursor is moved to ', Store.cursor));\n\n// Handle mode changes\nStore.on('mode', () =\u003e console.log('Mode is changed to ', Store.mode));\n\n// Handle text redraws\nStore.on('put', () =\u003e console.log('UI was redrawn'));\n\n// Accessing the state of the editor.\nconst bounds = [ Store.size.lines, Store.size.cols ];\nconst cursor_pos = [ Store.cursor.line, Store.cursor.col ];\n```\n\n\n### Call Neovim APIs\n\nYou can call [Neovim APIs](https://neovim.io/doc/user/msgpack_rpc.html#msgpack-rpc-api) via the **client**.\nWhen you call APIs via the client, it sends the call to the underlying Neovim process via MessagePack\nRPC and will return a [Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise)\nwhich resolves to the returned value.\n\n\n`\u003cneovim-component\u003e` uses [promised-neovim-client](https://github.com/rhysd/promised-neovim-client) package.\nYou can see the all API definitions [here](https://github.com/rhysd/promised-neovim-client/blob/promisified/index.d.ts).\nIf you know further about Neovim APIs, [python client implementation](https://github.com/neovim/python-client)\nmay be helpful.\n\n```javascript\nconst neovim_element = document.getElementById('neovim');\nconst client = neovim_element.editor.getClient();\n\n// Send a command\nclient.command('vsplit');\n\n// Send input\nclient.input('\u003cC-w\u003e\u003cC-l\u003e');\n\n// Evaluate a Vim script expression\nclient.eval('\"aaa\" . \"bbb\"').then(result =\u003e console.log(result));\n\n// Get the 'b:foo' variable\nclient.getCurrentBuffer()\n    .then(buf =\u003e buf.getVar('foo'))\n    .then(v =\u003e console.log(v));\n\n// Query something (windows, buffers, etc.)\n// Move to the neighbor window and show its information.\nclient.getWindows()\n    .then(windows =\u003e client.secCurrentWindow(windows[1]))\n    .then(() =\u003e client.getCurrentWindow())\n    .then(win =\u003e console.log(win));\n\n// Receive an RPC request from Neovim\nclient.on('request', (n, args, res) =\u003e console.log(`Name: ${n}, Args: ${JSON.stringify(args)}, Response: ${res}`));\n```\n\n\n### Editor lifecycle\n\nYou can receive notifications related to lifecycle of the editor.\n\n```javascript\nconst neovim_element = document.getElementById('neovim');\n\n// Called when the Neovim background process attaches\nneovim_element.editor.on('process-attached', () =\u003e console.log('Neovim process is ready'));\n\n// Called when the Neovim process is disconnected (usually by :quit)\nneovim_element.editor.on('quit', () =\u003e console.log('Neovim process died'));\n\n// Called when the \u003cneovim-component\u003e detaches\nneovim_element.editor.on('detach', () =\u003e console.log('Element does not exist in DOM.'));\n\n// Called upon experiencing an error in the internal process \nneovim_element.editor.on('error', err =\u003e alert(err.message));\n```\n\n\n### View APIs\n\n- Resize screen\n\n```javascript\nconst editor = document.getElementById('neovim').editor;\neditor.screen.resize(80, 100); // Resize screen to 80 lines and 100 columns\neditor.screen.resizeWithPixels(1920, 1080); // Resize screen to 1920px x 1080px\n```\n\n- Change font size\n\n```javascript\nconst editor = document.getElementById('neovim').editor;\neditor.screen.changeFontSize(18); // Change font size to 18px\n```\n\n- Convert pixels to lines/cols.\n\n```javascript\nconst editor = document.getElementById('neovim').editor;\n\nconst loc = editor.screen.convertPositionToLocation(80, 24);\nconsole.log(loc.x, loc.y);  // Coordinates in pixels of (line, col) = (80, 24)\n\nconst pos = editor.screen.convertLocationToPosition(400, 300);\nconst.log(pos.col, pos.line);  // line/col of location (400px, 300px)\n```\n\n- Notify of screen-size changes:\n\nWhen some process has changed the screen-size **you must notify the `screen`**. The internal `\u003ccanvas\u003e`\nelement has a fixed size and must update itself if there are size changes.  Call `screen.checkShouldResize()`\nif the screen size may have changed.  Note that you don't need to care about `resize` event of `\u003cbody\u003e`\nelement.  `\u003cneovim-editor\u003e` component automatically detects this particular resize event and updates\nautomatically. `screen.checkShouldResize()` will simply be ignored if nothing has actually changed.\n\n```javascript\nconst editor = document.getElementById('neovim').editor;\n\nfunction showUpSomeElementInNeovim() {\n    const e = document.getElementById('some-elem');\n\n    // New element shows up!  The screen may be resized by the change.\n    // 'none' -\u003e 'block'\n    e.style.display = 'block';\n\n    // This call tells to editor to adjust itself in the case that it has been resized\n    editor.screen.checkShouldResize();\n}\n```\n\n### Other APIs\n\n- Setting arguments afterwards:\n\nIf your app doesn't use Polymer you can set arguments afterwards using JavaScript\nNote that it is better to use `argv` property of `\u003cneovim-element\u003e` if possible.\n\n```javascript\nconst editor = document.getElementById('neovim').editor;\neditor.setArgv(['README.md']);\n```\n\n- Focusing the editor\n\n`\u003cneovim-editor\u003e` is just a web-component, so it can be focused just like other elements.  \nIf it loses focus the editor won't receive any input events. \nThe `editor` instance has a method to re-focus the editor in JavaScript.\nThe `store` instance contains the current focus state.\n\n```javascript\nconst editor = document.getElementById('neovim').editor;\nconsole.log(editor.store.focused);\neditor.store.on('focus-changed', () =\u003e {\n    console.log('Focus was changed: ' + editor.store.focused);\n});\n\n// Refocus the editor to ensure it receives user input.\neditor.focus();\n```\n\n### Log Levels\n\n`\u003cneovim-component\u003e` prints logs in the browser console.  The log level is controlled by the `NODE_ENV`\nenvironment variable:\n\n- `NODE_ENV=debug` will log everything.\n- `NODE_ENV=production` ignores all logs except for warnings and errors.\n- Setting `NODE_ENV` to empty string or some other value enables logging for info, warnings, and errors.\n\n\n## TODOs\n\n- [ ] WebGL rendering (using [pixi.js](http://www.pixijs.com/) or [CreateJS](http://www.createjs.com/)).\n  [#2](https://github.com/rhysd/neovim-component/issues/2)\n- [ ] Follow dynamic device pixel ratio change. [#18](https://github.com/rhysd/neovim-component/issues/18)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frhysd%2Fneovim-component","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frhysd%2Fneovim-component","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frhysd%2Fneovim-component/lists"}