├── .github ├── CONTRIBUTING.md ├── ISSUE_TEMPLATE.md └── PULL_REQUEST_TEMPLATE.md ├── .gitignore ├── .npmignore ├── .npmrc ├── .travis.yml ├── Guardfile ├── LICENSE.txt ├── README.md ├── bin └── cli.js ├── bower.json ├── docs ├── browser-config.md ├── faq.md ├── make-ui-plugin.md ├── runtime-api.md └── tips.md ├── main ├── browser-config.ts ├── lib.d.ts ├── main.ts ├── menu.ts └── tsconfig.json ├── package.json ├── renderer ├── lib.d.ts ├── main.html ├── main.ts ├── nyaovim-app.ts └── tsconfig.json ├── resources ├── icon │ ├── nyaovim-logo.icns │ ├── nyaovim-logo.ico │ ├── nyaovim-logo.png │ └── nyaovim-logo.svg ├── osx_plist │ └── file_associations.plist └── title-bar.png ├── runtime ├── autoload │ └── nyaovim.vim └── plugin │ └── nyaovim.vim ├── scripts ├── make-release.sh └── travis-before-install.sh ├── test ├── helper │ └── nyaovim.ts ├── lib.d.ts ├── mocha.opts ├── smoke │ └── startup.ts └── tsconfig.json └── tslint.json /.github/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | Thank you for contributing NyaoVim! 2 | ========================================= 3 | 4 | ## Language 5 | 6 | I'm Japanese and not good English user. So Japanese is the best language to communicate, but of course English is also OK. 7 | 8 | ## Templates 9 | 10 | Please use issue/PR templates which are inserted automatically. 11 | 12 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ### Expected Behavior 4 | 5 | {Please write here} 6 | 7 | ### Actual Behavior 8 | 9 | {Please write here} 10 | 11 | ### Steps to Reproduce (including precondition) 12 | 13 | {Please write here} 14 | 15 | ### Screenshot on This Problem (if possible) 16 | 17 | {Please write here} 18 | 19 | ### Your Environment 20 | 21 | - OS: {Please write here} 22 | - NyaoVim version: {Please write here} 23 | - `nvim` version: {Please write here} 24 | - Keyboard layout: {Please write here} 25 | - Linux: Window manager: {Please write here} 26 | 27 | ### Additional Comments (if any) 28 | 29 | {Please write here} 30 | 31 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ### What was a problem? 4 | 5 | {Please write here} 6 | 7 | ### How this PR fixes the problem? 8 | 9 | {Please write here} 10 | 11 | ### Check lists (check `x` in `[ ]` of list items) 12 | 13 | - [ ] Coding style (if any code was modified) 14 | - [ ] Confirmed 15 | - OS: {Please write here} 16 | - `nvim` version: {Please write here} 17 | 18 | ### Additional Comments (if any) 19 | 20 | {Please write here} 21 | 22 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /node_modules 2 | npm-debug.log 3 | /app.asar 4 | /bower_components 5 | /main/**/*.js 6 | /main/**/*.js.map 7 | /renderer/**/*.js 8 | /renderer/**/*.js.map 9 | /test/**/*.js 10 | /app 11 | /dist 12 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | npm-debug.log 2 | /app.asar 3 | /.git 4 | /test 5 | /Guardfile 6 | /tslint.json 7 | /scripts 8 | /app 9 | /dist 10 | /.npmrc 11 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | package-lock=false 2 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: "6" 3 | os: 4 | # - osx 5 | - linux 6 | osx_image: xcode9 7 | dist: trusty 8 | sudo: required 9 | before_install: 10 | - source ./scripts/travis-before-install.sh 11 | install: 12 | - npm run dep 13 | script: 14 | - nvim --version 15 | - npm run build 16 | - npm run lint 17 | - npm run smoke-test 18 | notifications: 19 | email: 20 | on_success: never 21 | on_failure: change 22 | -------------------------------------------------------------------------------- /Guardfile: -------------------------------------------------------------------------------- 1 | ignore /^node_modules/, /^build/, /^typings/ 2 | 3 | def build(kind, path) 4 | suffix = 5 | if kind.empty? 6 | '' 7 | else 8 | "-#{kind}" 9 | end 10 | puts "\033[93m#{Time.now}: #{File.basename path}\033[0m" 11 | success = system "npm run build#{suffix}" 12 | if success 13 | puts "\033[92mOK\033[0m\n\n" 14 | else 15 | puts "\033[91mFAIL\033[0m\n\n" 16 | end 17 | end 18 | 19 | guard :shell do 20 | watch %r[^main/.+\.ts$] do |m| 21 | build(:main, m[0]) 22 | end 23 | 24 | watch %r[^renderer/.+\.ts$] do |m| 25 | build(:renderer, m[0]) 26 | end 27 | 28 | watch %r[^test/.+\.ts$] do |m| 29 | build(:test, m[0]) 30 | end 31 | end 32 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015 rhysd 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 7 | of the Software, and to permit persons to whom the Software is furnished to do so, 8 | subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 14 | INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR 15 | PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 16 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 17 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR 18 | THE USE OR OTHER DEALINGS IN THE SOFTWARE. 19 | 20 | 21 | 22 | 23 | Logo of this app is created based on Neovim logo licensed under CCA 3.0 Unported. 24 | The Neovim logo by Jason Long is licensed under the Creative Commons Attribution 3.0 Unported License. 25 | 26 | https://creativecommons.org/licenses/by/3.0/legalcode 27 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![NyaoVim](resources/title-bar.png) 2 | =================================== 3 | 4 | This is a [Neovim](https://neovim.io/) frontend built on [Electron](https://electronjs.org/). 5 | The Neovim editor is [composed as a Web Component](https://github.com/rhysd/neovim-component) and users 6 | can extend the UI with reusable Web Components, HTML, CSS and JavaScript. 7 | 8 | `:help design-not` says: 9 | 10 | > Use Vim as a component from a shell or in an IDE. 11 | 12 | NyaoVim is built in the same spirit. NyaoVim contains the Neovim editor as a Web Component and extends 13 | its UI with web technology, as in other modern editors and IDEs (e.g. [Atom](http://atom.io/), 14 | [VS Code](https://github.com/Microsoft/vscode), [LightTable](http://lighttable.com/)). 15 | 16 | 17 | ## Goals 18 | 19 | - **NyaoVim bundles no extended UI by default.** It only provides the nice UI plugin architecture. 20 | Users can compose their favorite UI with Web Components, HTML and CSS. It is also easy to make a NyaoVim 21 | distribution where useful components are bundled. 22 | - **Do not introduce another plugin manager.** HTML for Web Components should be bundled with Vim plugins. 23 | Therefore, a Vim plugin manager can handle UI components, letting us bundle JS and Vim script code. 24 | - **Do not lose Vim's comfortability by default.** It should be aware of performance. 25 | - **UI component creators can use powerful APIs, packages and tools**; [Node.js APIs](https://nodejs.org/en/docs/), 26 | [Electron APIs](https://github.com/atom/electron/tree/master/docs/api), [Neovim msgpack-rpc APIs](https://neovim.io/doc/user/msgpack_rpc.html)), 27 | so many [npm packages](https://www.npmjs.com/) and [Chrome DevTools](https://developers.google.com/web/tools/chrome-devtools/). 28 | - **Cross Platform** (Linux, OS X, Windows) 29 | 30 | Memo: 'nyao' is 'meow' in Japanese and its pronounce resembles 'neo'. 31 | It is also an acronym for 'Not Yet Another Original'. 32 | 33 | 34 | ## App Structure 35 | 36 | NyaoVim consists of Web Components on Electron as shown in the following figure. At first there is 37 | only `` and you can add/remove additional components. 38 | 39 | ![structure](https://raw.githubusercontent.com/rhysd/ss/master/NyaoVim/structure.png) 40 | 41 | 42 | ## UI Plugin Examples 43 | 44 | UI plugins are installable as easily as regular plugins. Each of them is written within 100~300 lines. 45 | You can also create reusable Web Components and integrate them into NyaoVim. 46 | 47 | - [nyaovim-markdown-preview](https://github.com/rhysd/nyaovim-markdown-preview) 48 | 49 | ![nyaovim-markdown-preview screenshot](https://raw.githubusercontent.com/rhysd/ss/master/nyaovim-markdown-preview/main.gif) 50 | 51 | - [nyaovim-popup-tooltip](https://github.com/rhysd/nyaovim-popup-tooltip) 52 | 53 | ![nyaovim-popup-tooltip screenshot](https://raw.githubusercontent.com/rhysd/ss/master/nyaovim-popup-tooltip/main.gif) 54 | 55 | - [nyaovim-mini-browser](https://github.com/rhysd/nyaovim-mini-browser) 56 | 57 | ![nyaovim-mini-browser screenshot](https://raw.githubusercontent.com/rhysd/ss/master/nyaovim-mini-browser/main.gif) 58 | 59 | 60 | ## Usage 61 | 62 | ### Getting Started 63 | 64 | You can install NyaoVim as an [npm package](https://www.npmjs.com/package/nyaovim). Currently no packaging 65 | release is available yet. If you use Windows and haven't installed Neovim yet, please read [first tips](docs/tips.md) first. 66 | 67 | ```sh 68 | $ npm install -g nyaovim 69 | ``` 70 | 71 | `npm` may require `sudo` if you installed `node` pacakge via system package manager. 72 | 73 | If you haven't installed Neovim yet, please install it following [Neovim's instructions](https://github.com/neovim/neovim/wiki/Installing-Neovim) 74 | because NyaoVim internally uses the `nvim` command. **Note that `nvim` v0.1.6 or later is needed.** 75 | 76 | You can start NyaoVim with the `nyaovim` command if you install this app with npm. 77 | 78 | ```sh 79 | $ nyaovim [files...] 80 | ``` 81 | 82 | You would see a minimal Neovim GUI editor (like gVim). This is an Electron app and Neovim is drawn 83 | on ``. You can see the DevTools of this app with the 'Developer Tools' menu item. 84 | 85 | On first start up of NyaoVim, it creates `~/.config/nyaovim/nyaovimrc.html` for UI configuration 86 | (`%AppData%` instead of `.config` in Windows). Yes, you can extend and configure UI components with 87 | HTML and CSS! 88 | 89 | ### Configure Editor Options 90 | 91 | I guess you're now thinking 'Hmm, font is not good and too small...'. You can configure some editor 92 | options by properties of [`` properties](https://github.com/rhysd/neovim-component#neovim-editor-properties). 93 | For example, below configures font face and font size by `font` and `font-size` properties. Then set 94 | line-height to 1.5 (for example, Atom adopts 1.5 as line-height). 95 | 96 | ```html 97 | 104 | ``` 105 | 106 | And you can also configure browser window options with `browser-config.json` (e.g. Preserving window 107 | state, Single instance app, and so on). See [tips](docs/tips.md) for more detail. 108 | 109 | ### Install UI Plugin 110 | 111 | For example, let's install [nyaovim-popup-tooltip](https://github.com/rhysd/nyaovim-popup-tooltip). 112 | 113 | As described in the Goals section, a UI plugin is a normal Neovim plugin. You can install it like 114 | any other Neovim plugin. If you use [vim-plug](https://github.com/junegunn/vim-plug), all you need 115 | is adding below line to your `init.vim`. 116 | 117 | ```vim 118 | Plug 'rhysd/nyaovim-popup-tooltip' 119 | ``` 120 | 121 | Then you need to put the popup tooltip UI on your NyaoVim interface. Please open `~/.config/nyaovim/nyaovimrc.html` 122 | (`%AppData%` instead of `.config` in Windows). As described in the Goals section, a user can build 123 | a UI with HTML and CSS with high customization. 124 | 125 | Please add `` tag under `` tag as below 126 | 127 | ```html 128 | 129 | 130 | ``` 131 | 132 | `` is a [Polymer](https://github.com/Polymer/polymer) component. 133 | `editor="[[editor]]"` is a data binding in Polymer framework to pass editor instance to ``. It means 134 | unidirectional data flow from parent to child. 135 | 136 | After installing nyaovim-popup-tooltip as a Neovim plugin and adding UI to HTML, you're all done! 137 | Open NyaoVim, move the cursor to any image path, and enter `gi`. NyaoVim will load the image and show 138 | it in a popup tooltip as below. 139 | 140 | ![nyaovim-popup-tooltip screenshot](https://raw.githubusercontent.com/rhysd/ss/master/nyaovim-popup-tooltip/main.gif) 141 | 142 | 143 | ## Documents 144 | 145 | There is more in documentation in the [docs directory](docs). 146 | 147 | - [How to Make UI Plugin](docs/make-ui-plugin.md) 148 | - [Tips](docs/tips.md) 149 | - [FAQ](docs/faq.md) 150 | - [Runtime API](docs/runtime-api.md) 151 | - [Browser Config](docs/browser-config.md) 152 | 153 | 154 | ## Versioning 155 | 156 | NyaoVim is now under beta phase. Major version is fixed to 0 until it gets stable release. 157 | 158 | Updating minor version means it contains breaking changes. And updating patch version means it contains 159 | no breaking change, so you can update version easily. 160 | 161 | 162 | ## License 163 | 164 | [MIT License](/LICENSE.txt). 165 | 166 | Logo of this app is created based on [Neovim logo](https://neovim.io/) licensed under [CCA 3.0 Unported](https://creativecommons.org/licenses/by/3.0/legalcode). 167 | 168 | > The Neovim logo by Jason Long is licensed under the Creative Commons Attribution 3.0 Unported License. 169 | 170 | -------------------------------------------------------------------------------- /bin/cli.js: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env node 2 | 3 | const spawn = require('child_process').spawn; 4 | const electron = require('electron'); 5 | const join = require('path').join; 6 | 7 | const argv = process.argv.slice(2); 8 | const no_detach_idx = argv.indexOf('--no-detach'); 9 | const detached = 10 | no_detach_idx === -1 && 11 | argv.indexOf('--help') === -1 && 12 | argv.indexOf('--version') === -1; 13 | 14 | if (no_detach_idx !== -1) { 15 | argv.splice(no_detach_idx, 1); 16 | } 17 | argv.unshift(join(__dirname, '..')); 18 | 19 | if (!process.env.NODE_ENV) { 20 | process.env.NODE_ENV = 'production'; 21 | } 22 | 23 | if (detached) { 24 | spawn(electron, argv, { 25 | stdio: 'inherit', 26 | detached: true 27 | }).unref(); 28 | } else { 29 | spawn(electron, argv, { stdio: 'inherit' }); 30 | } 31 | 32 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "nyaovim", 3 | "version": "0.0.0", 4 | "homepage": "https://github.com/rhysd/NyaoVim", 5 | "authors": [ 6 | "rhysd " 7 | ], 8 | "license": "MIT", 9 | "dependencies": { 10 | "polymer": "^2.5.0", 11 | "webcomponentsjs": "^1.1.0" 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /docs/browser-config.md: -------------------------------------------------------------------------------- 1 | Browser Config 2 | ============= 3 | 4 | **Please note that `browser-config.json` may be deprecated after Neovim 0.2 because of the change of Neovim frontend architecture** 5 | 6 | NyaoVim is rendered in browser window using [Electron](https://github.com/atom/electron) framework. You can configure editor options with properties of `` component, but cannot configure the browser window options. This is because the browser window options must be specified before window opened. 7 | 8 | You can configure browser window options using `browser-config.json` in `~/.config/nyaovim/`. It does not exist by default and you need to create it at first. 9 | 10 | ```sh 11 | $ echo "{\n \"window_options\": {}\n}" > ~/.config/nyaovim/browser-config.json 12 | ``` 13 | 14 | `browser-config.json` contains one JSON object. The object optionally contains below key/value entries. 15 | 16 | - **window_options** : Its value is [options of `BrowserWindow` class of Electron](https://github.com/atom/electron/blob/master/docs/api/browser-window.md#new-browserwindowoptions). You can configure many options here; `width`, `height`, `fullscreen`, `webPreferences`, and so on. 17 | - **remember_window_state** : Boolean value. Preserve the window state (position, size, fullscreen?, maximized?) at closing window and restore it at next start-up. The state is written to `~/.config/nyaovim/window-state.json`. 18 | - **single_instance** : Boolean value. If true, NyaoVim becomes 'Single Instance Application'. Only one NyaoVim instance can exist in desktop. If `nyaovim` command is secondly executed, it focuses on NyaoVim window which already exists, opens files specified as arguments in it, and simply quits. 19 | - **show_menubar** : Boolean value. If false, NyaoVim hides menubar. Otherwise, NyaoVim shows menubar because Alt key is hijacked in some environment when menubar is auto-hidden. 20 | 21 | Below is an example: 22 | 23 | ```json 24 | { 25 | "window_options": { 26 | "width": 1200, 27 | "height": 960, 28 | "fullscreen": true, 29 | "alwaysOnTop": true, 30 | "webPreferences": { 31 | "webgl": false, 32 | "plugins": true 33 | } 34 | }, 35 | "remember_window_state": true, 36 | "single_instance": true, 37 | "show_menubar": false 38 | } 39 | ``` 40 | 41 | 42 | -------------------------------------------------------------------------------- /docs/faq.md: -------------------------------------------------------------------------------- 1 | FAQ 2 | === 3 | 4 | ## Trouble 5 | 6 | ### Q. I can't input to NyaoVim (OS X) 7 | 8 | Are you using tmux and started NyaoVim in tmux? In the case, you need to use [reattach-to-user-namespace](https://github.com/ChrisJohnsen/tmux-MacOSX-pasteboard) utility. 9 | 10 | 11 | ### Q. White screen is shown at start up 12 | 13 | After NyaoVim shows white screen, could you please input enter key. I think NyaoVim will restore screen. Then please check `:message`. I think some errors are reported. 14 | This problem occurs because Neovim frontend can't handle error output before showing UI. Neovim 0.2 will resolve this. 15 | 16 | ### Q. Swap file doesn't work 17 | 18 | NyaoVim disables swapfile because Neovim frontend can't handle swap file message on start up. The reason is the same as above question, so Neovim 0.2 will resolve this. 19 | 20 | ### Q. Error alert is shown at starting NyaoVim 21 | 22 | Please ensure that `nvim` command exists in `$PATH` environment variable. If you started NyaoVim via non-npm package (e.g. NyaoVim.app), `$PATH` is not set up as started in shell. Please `$PATH` in NyaoVim directly as below. 23 | 24 | 1. Start NyaoVim 25 | 2. Open Chrome DevTools from menu item 'Open DevTools' 26 | 3. Enter `process.env.PATH` to console 27 | 28 | If you don't want to add `nvim`'s directory path to `$PATH`, please specify the absolute path to `nvim` in `` element as below. 29 | 30 | ```html 31 | 36 | ``` 37 | 38 | ### Q. Where is your `init.vim`? 39 | 40 | [Here!](https://github.com/rhysd/dogfiles/blob/master/nvimrc) (Sorry for Japanese in comments.) 41 | 42 | ### Q. Character picker is shown on macOS when holding some key 43 | 44 | From OS X 10.8, macOS enables the 'Character Picker' feature. If you see a weird popup when holding any key, please see the output of following command: 45 | 46 | ``` 47 | $ defaults read -g ApplePressAndHoldEnabled 48 | ``` 49 | 50 | If it shows `true`, you need to disable the feature. 51 | 52 | To disable it globally, please try following command 53 | 54 | ``` 55 | $ defaults write -g ApplePressAndHoldEnabled -bool true 56 | ``` 57 | 58 | If you install `NyaoVim.app`, you can disable it only in NyaoVim with following command. 59 | Please note that this is not available if you install NyaoVim via npm. 60 | 61 | ``` 62 | $ defaults write -app NyaoVim ApplePressAndHoldEnabled -bool true 63 | ``` 64 | -------------------------------------------------------------------------------- /docs/make-ui-plugin.md: -------------------------------------------------------------------------------- 1 | How to Make UI Plugin 2 | ===================== 3 | 4 | I created [nyaovim-popup-tooltip](https://github.com/rhysd/nyaovim-popup-tooltip) as sample UI plugin. It will help you understand how to make UI plugin. 5 | 6 | - [Directory Structure](#structure) 7 | - [Getting Started](#tutorial) 8 | - [Debug Your Plugin](#debug) 9 | - [Handle Resizing Neovim Window](#window-resize) 10 | 11 | ## Directory Structure 12 | 13 | NyaoVim UI plugin is a normal Neovim plugin except for `nyaovim-plugin` directory as below. 14 | 15 | ``` 16 | plugin-root-dir 17 | ├── README.md 18 | ├── autoload 19 | ├── nyaovim-plugin 20 | └── plugin 21 | ``` 22 | 23 | - `autoload` is the same as normal Neovim plugin's autoload directory. 24 | - `plugin` is the same as normal Neovim plugin's plugin directory. 25 | - `nyaovim-plugin` is a place for HTML file which contains Web Component of UI. NyaoVim searches this directory and loads Web Components in it automatically. 26 | - UI should be created as a custom element of WebComponents v1 in the HTML file. And you can use [Polymer v2](https://www.polymer-project.org/) framework to 27 | utilize data binding from `nyaovimrc.html` (mainly for user configuration). 28 | 29 | 30 | ## Getting Started 31 | 32 | Let's make your `nyaovim-plugin/first-component.html`. 33 | 34 | ```html 35 | 36 | 37 | 47 | 48 | ``` 49 | 50 | And you need to get an editor instance from `nayovim-app` element. It is a custom element and it contains [``](https://github.com/rhysd/neovim-component) in it. You can access powerful [``'s APIs](https://github.com/rhysd/neovim-component#neovim-editor-apis) via `editor` property. 51 | 52 | You can write JavaScript for it. 53 | 54 | ```html 55 | 56 | 62 | ``` 63 | 64 | Let's change the content of `
` from Neovim. You can call [Neovim msgpack-rpc APIs](https://neovim.io/doc/user/msgpack_rpc.html) through [client instance](https://github.com/rhysd/neovim-component#call-neovim-apis). 65 | Subscribe notification from Neovim as following. 66 | 67 | ```html 68 | 69 | 82 | ``` 83 | 84 | If you created your component as [Polymer v2](https://github.com/Polymer/polymer) element, you can receive editor instance as `editor` property of it. 85 | 86 | You've finished creating UI. 87 | Note that you can also use [Electron APIs](https://github.com/atom/electron/tree/master/docs/api) and [Node.js APIs](https://nodejs.org/en/) (e.g. `require()`) here. 88 | 89 | Next, write small Vim script code in `plugin/hello-world.vim`. `rpcnotify()` is available to send Vim script values to component via msgpack-rpc. 90 | 91 | ```vim 92 | " Send notification to your UI 93 | command! -nargs=+ HelloWorld call rpcnotify(0, 'hello-world:content', ) 94 | ``` 95 | 96 | All has been done. 97 | Put `` in your `nyaovimrc.html` and start NyaoVim, then execute the command. 98 | 99 | ```vim 100 | :HelloWorld Hello world from NyaoVim! 101 | ``` 102 | 103 | Congrats! Now you can start to make your UI with HTML, CSS, Polymer, Electron and Node.js! When you want to ask a question, please feel free to make an issue for question. 104 | 105 | ## Debug Your Plugin 106 | 107 | If you want to debug your plugin or NyaoVim, you can start NyaoVim in debug mode with `$NODE_ENV` environment variable. 108 | 109 | ```sh 110 | $ NODE_ENV=debug nyaovim 111 | ``` 112 | 113 | Chrome DevTools will be launched in detached window and you can debug your UI plugin like general web applications; showing console, checking DOM elements, profiling and so on. Even if you start NyaoVim normally, you can also open Chrome DevTools by clicking menu item 'Toggle DevTools'. 114 | 115 | ## Handle Resizing Neovim Window 116 | 117 | As [described in neovim-component document](https://github.com/rhysd/neovim-component#view-apis), when `` **may** need to resize, you **must** call `editor.screen.checkShouldResize()` in order to notify it to ``. Please note that the notification is not needed when window is resized. And it is OK that nothing happens to the size of `` as result. 118 | This is needed because Neovim is rendered on `` and it can't know the timing when itself is resized. 119 | 120 | For example, when your component appears in window, the area of `` may change. 121 | 122 | ```javascript 123 | function showUpSomeElementInNyaoVimWindow() { 124 | const e = document.getElementById('some-elem'); 125 | 126 | // Element appears in window! Screen might be resized by the change. 127 | // 'none' -> 'block' 128 | e.style.display = 'block'; 129 | 130 | // You need to call this to say to that 'You may be resized. Check it out!'. 131 | editor.screen.checkShouldResize(); 132 | } 133 | ``` 134 | 135 | -------------------------------------------------------------------------------- /docs/runtime-api.md: -------------------------------------------------------------------------------- 1 | NyaoVim Runtime API 2 | =================== 3 | 4 | As described in [README](../README.md), many APIs are available in NyaoVim; [ APIs](https://github.com/rhysd/neovim-component), [Node.js APIs](https://nodejs.org/en/docs/), [Electron APIs](https://github.com/atom/electron/tree/master/docs/api), [Neovim msgpack-rpc APIs](https://neovim.io/doc/user/msgpack_rpc.html)), so many [npm packages](https://www.npmjs.com/). 5 | In addition to them, NyaoVim offers some extra APIs. 6 | 7 | - API in Vim script 8 | - Subscriable events 9 | 10 | ## API in Vim script 11 | 12 | Vim script interface is defined [in this directory](../runtime). The directory is added to `runtimepath` at Neovim starting. All are defined in `nyaovim#` namespace. 13 | 14 | ### `nyaovim#load_nyaovim_plugin(runtimepath)` 15 | 16 | Load UI plugin from the `runtimepath` directory. It searches `nyaovim-plugin` directory and HTML files in the directory. Then load HTML files with ``. 17 | 18 | ### `nyaovim#load_nyaovim_plugin_direct(html_path)` 19 | 20 | Directly load HTML from `html_path` HTML file with ``. 21 | 22 | ### `nyaovim#require_javascript_file(script_path)` 23 | 24 | Load `script_path` JavaScript file with Node.js's `require()` function. 25 | 26 | ### `nyaovim#call_javascript_function(func_name, args)` 27 | 28 | Call JavaScript `func_name` global function with `args`. `args` values in Vim script will be converted to JavaScript values. 29 | 30 | ### `nyaovim#open_devtools(mode)` 31 | 32 | [Open DevTools](https://github.com/electron/electron/blob/master/docs/api/web-contents.md#contentsopendevtoolsoptions) for NyaoVim. `mode` determines how to open DevTools window and should be one of `'right'`, `'bottom'`, `'undocked'` or `'detach'`. If omitted, `'detach'` will be set. 33 | 34 | ### `nyaovim#execute_javascript(code)` 35 | 36 | Execute JavaScript code from Vim script with `code` string. With this function, you can run various APIs directly from Vim script. Below is a code to toggle window fullscreen. 37 | 38 | ```vim 39 | call nyaovim#execute_javascript('(function(){ 40 | \ const win = require("electron").remote.getCurrentWindow(); 41 | \ win.setFullScreen(!win.isFullScreen()); 42 | \ })()') 43 | ``` 44 | 45 | TODO: This function currently doesn't return the result of evaluating JavaScript. 46 | 47 | ### `nyaovim#browser_window(method, args)` 48 | 49 | Call [`BrowserWindow` API in Electron](https://github.com/electron/electron/blob/master/docs/api/browser-window.md) for the main window. This function is currently using notification. So Vim script side can't receive the return value. 50 | 51 | ```vim 52 | " Calls `window.setFullScreen(true);` in the main window 53 | call nyaovim#browser_window('setFullScreen', [v:true]) 54 | ``` 55 | 56 | 57 | ## Subscriable events 58 | 59 | With Neovim msgpack API, you can receive rpc nortifications. 60 | 61 | ```javascript 62 | const neovim_element = document.getElementById('neovim'); 63 | const client = neovim_element.editor.getClient(); 64 | client.on('notification', (func_name, args) => { 65 | switch (func_name) { 66 | case 'nyaovim:edit-start': 67 | // Do something 68 | break; 69 | default: 70 | break; 71 | } 72 | }); 73 | ``` 74 | 75 | NyaoVim defines some notifications to use internally and UI plugins can also use them. 76 | 77 | ### `nyaovim:edit-start` 78 | 79 | This notification is sent when Neovim starts to edit some buffer. It passes the file path to 1st argument. 80 | 81 | 82 | -------------------------------------------------------------------------------- /docs/tips.md: -------------------------------------------------------------------------------- 1 | Tips 2 | ==== 3 | 4 | ## Installation on Windows 5 | 6 | At first, you need to install Visual C++ 2015 runtime from [official](https://www.microsoft.com/en-us/download) if you didn't yet. Neovim requires it to run. 7 | Following [Neovim official instruction](https://github.com/neovim/neovim/wiki/Installing-Neovim#windows), download Neovim.zip from AppVeyor build result, unzip it, and add `bin` directory to `$PATH`. After installation, please be sure that `nvim` command works correctly from PowerShell or CMD.exe. 8 | Now you can install NyaoVim with [npm](https://www.npmjs.com/). Please read 'Getting Started' subsection in [README](../README.md). Currently zip-archived app is not released yet because NyaoVim is being developed yet. 9 | 10 | ## Check Running on NyaoVim from Vim script 11 | 12 | Before loading `.config/nvim/init.vim`, `g:nyaovim_version` is set to NyaoVim's version string. You can check if the Vim script code is being executed on NyaoVim or not (in `init.vim` or plugin code). 13 | 14 | ```vim 15 | if exists('g:nyaovim_version') 16 | " Write NyaoVim specific code here 17 | " ... 18 | endif 19 | ``` 20 | 21 | `g:nyaovim_version` is a string which represents the version of NyaoVim (e.g. `"0.0.14"`). You can also use it to check the version of NyaoVim. 22 | 23 | ## Single Instance Application 24 | 25 | NyaoVim can become 'Single Instance Application'. 26 | Only one NyaoVim app instance can exist in desktop. If `nyaovim` command is secondly executed, it focuses on NyaoVim window which already exists, opens files specified with arguments in it, and simply quits. 27 | 28 | ```sh 29 | $ nyaovim foo.c bar.c # Open NyaoVim firstly with foo.c and bar.c 30 | $ cd ~/blah 31 | $ nyaovim aaa.js bbb.js # Focus window which already exists, open aaa.js and bbb.js in it 32 | ``` 33 | 34 | You can make NyaoVim 'Single Instance Application' with `browser-config.json`. Please read [the document](browser-config.md) 35 | 36 | 37 | ## Drag and Drop Files 38 | 39 | If you drag and drop a file to NyaoVim window, NyaoVim will start to edit the file with `:edit!`. 40 | 41 | ## 'Recent Files' on OS X 42 | 43 | When you start NyaoVim, NyaoVim's application icon will appear in your OS X dock. As other general OS X applications, 'Recent Files' item is available in dock menu. (Please right click on an icon in dock.) 44 | When NyaoVim starts to edito some files (e.g. `:edit some-file`), NyaoVim registers them as 'recent file' and enables quick access with 'Recent Files' item. 45 | 46 | ## 'Current File' in title bar on OS X 47 | 48 | When a file icon is shown just left of title in title bar, you can select a file to edit via the icon. Please try clicking the icon with command key (Cmd + LeftClick) then you will see the pull-down menu to select a directory. After selecting directory, you can select a file in the directory to start editing. 49 | 50 | ## Don't detach the process 51 | 52 | NyaoVim's process is detached by default when launched from command line. If you don't want to detach the editor process, please consider to use `--no-detach` option of `nyaovim` command. If you always want to use it. `alias nyaovim='nyaovim --no-detach'` in bashrc or zshrc may help you. 53 | 54 | ## Load JavaScript 55 | 56 | If you want to load some JavaScript code, you can use ` 63 | ``` 64 | 65 | It ensures that the script is loaded after loading ``. 66 | 67 | -------------------------------------------------------------------------------- /main/browser-config.ts: -------------------------------------------------------------------------------- 1 | import {join} from 'path'; 2 | import {readFileSync} from 'fs'; 3 | import {app} from 'electron'; 4 | import extend = require('deep-extend'); 5 | import windowStateKeeper = require('electron-window-state'); 6 | 7 | export interface BrowserConfigJson { 8 | remember_window_state: boolean; 9 | window_options: Electron.BrowserWindowConstructorOptions; 10 | single_instance: boolean; 11 | show_menubar: boolean; 12 | } 13 | 14 | export default class BrowserConfig { 15 | loaded_config: BrowserConfigJson; 16 | window_state: ElectronWindowState.WindowState; 17 | 18 | constructor() { 19 | this.loaded_config = null; 20 | this.window_state = null; 21 | } 22 | 23 | loadFrom(config_dir: string) { 24 | return new Promise(resolve => { 25 | try { 26 | const config_file = join(config_dir, 'browser-config.json'); 27 | const content = readFileSync(config_file, 'utf8'); 28 | this.loaded_config = JSON.parse(content); 29 | } catch (e) { 30 | // Do nothing 31 | } 32 | resolve(); 33 | }); 34 | } 35 | 36 | applyToOptions(opt: Electron.BrowserWindowConstructorOptions): Electron.BrowserWindowConstructorOptions { 37 | if (typeof this.loaded_config !== 'object' || this.loaded_config === null) { 38 | return opt; 39 | } 40 | 41 | if (typeof this.loaded_config.window_options === 'object') { 42 | extend(opt, this.loaded_config.window_options); 43 | } 44 | 45 | if (this.loaded_config.remember_window_state) { 46 | const s = windowStateKeeper({ 47 | defaultWidth: 1000, 48 | defaultHeight: 800, 49 | path: global.config_dir_path, 50 | }); 51 | if (typeof s.x === 'number') { 52 | opt.x = s.x; 53 | } 54 | if (typeof s.y === 'number') { 55 | opt.y = s.y; 56 | } 57 | opt.width = s.width; 58 | opt.height = s.height; 59 | if (typeof s.isFullScreen === 'boolean') { 60 | opt.fullscreen = s.isFullScreen; 61 | } 62 | 63 | this.window_state = s; 64 | } 65 | 66 | return opt; 67 | } 68 | 69 | setupWindowState(win: Electron.BrowserWindow) { 70 | if (this.window_state === null) { 71 | return null; 72 | } 73 | // Note: 74 | // Using 'resize' event instead of 'close' event because of 75 | // 'Object has been destroyed' error. 76 | // See https://github.com/rhysd/NyaoVim/pull/63 77 | win.on('resize', () => { 78 | this.window_state.saveState(win); 79 | }); 80 | 81 | if (this.window_state.isMaximized) { 82 | win.maximize(); 83 | } 84 | return this.window_state; 85 | } 86 | 87 | configSingletonWindow(win: Electron.BrowserWindow) { 88 | if (this.loaded_config === null || !this.loaded_config.single_instance) { 89 | return false; 90 | } 91 | return app.makeSingleInstance((argv, cwd) => { 92 | if (win.isMinimized()) { 93 | win.restore(); 94 | } 95 | win.focus(); 96 | 97 | // Note: Omit Electron binary and NyaoVim directory 98 | const args = argv.slice(2); 99 | if (args.length !== 0) { 100 | win.webContents.send('nyaovim:exec-commands', [ 101 | 'cd ' + cwd, 102 | 'args ' + args.join(' '), 103 | ]); 104 | } 105 | return true; 106 | }); 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /main/lib.d.ts: -------------------------------------------------------------------------------- 1 | declare namespace NodeJS { 2 | interface Global { 3 | config_dir_path: string; 4 | nyaovimrc_path: string; 5 | } 6 | } 7 | 8 | declare namespace ElectronWindowState { 9 | interface WindowState { 10 | x: number; 11 | y: number; 12 | width: number; 13 | height: number; 14 | isMaximized: boolean; 15 | isFullScreen: boolean; 16 | manage(win: Electron.BrowserWindow): void; 17 | saveState(win: Electron.BrowserWindow): void; 18 | } 19 | } 20 | 21 | -------------------------------------------------------------------------------- /main/main.ts: -------------------------------------------------------------------------------- 1 | import {join} from 'path'; 2 | import {stat, writeFileSync} from 'fs'; 3 | import {app, BrowserWindow, shell, nativeImage} from 'electron'; 4 | import {sync as mkdirpSync} from 'mkdirp'; 5 | import setMenu from './menu'; 6 | import BrowserConfig from './browser-config'; 7 | 8 | if (process.argv.indexOf('--help') !== -1) { 9 | console.log(`OVERVIEW: NyaoVim; Web-enhanced Extensible Neovim Frontend 10 | 11 | USAGE: nyaovim [options] [neovim args...] 12 | 13 | OPTIONS: 14 | --no-detach : Don't detach the editor process 15 | --help : Show this help 16 | --version : Show versions of NyaoVim, Electron, Chrome, Node.js, and V8 17 | `); 18 | app.exit(); 19 | } 20 | 21 | if (process.argv.indexOf('--version') !== -1) { 22 | const vs: {[n: string]: string} = process.versions as any; 23 | const versions = ['electron', 'chrome', 'node', 'v8'].map((n: string) => ` ${n} : ${vs[n]}`).join('\n'); 24 | console.log(`${app.getName()} version ${app.getVersion()} 25 | ${versions} 26 | `); 27 | app.exit(); 28 | } 29 | 30 | process.on('unhandledRejection', (reason: string, p: Promise) => { 31 | console.error('Fatal: Unhandled rejection at: Promise', p, 'Reason:', reason); 32 | }); 33 | 34 | const is_run_from_npm_package_on_darwin = 35 | app.getAppPath().indexOf('/NyaoVim.app/') === -1; 36 | 37 | const config_dir_name = 38 | process.platform !== 'darwin' ? 39 | app.getPath('appData') : 40 | process.env.XDG_CONFIG_HOME || join(process.env.HOME, '.config'); 41 | 42 | global.config_dir_path = join(config_dir_name, 'nyaovim'); 43 | global.nyaovimrc_path = join(global.config_dir_path, 'nyaovimrc.html'); 44 | 45 | function exists(path: string) { 46 | return new Promise(resolve => { 47 | stat(path, (err, stats) => { 48 | if (err) { 49 | resolve(false); 50 | return; 51 | } 52 | resolve(stats.isFile() || stats.isDirectory()); 53 | }); 54 | }); 55 | } 56 | 57 | function prepareDefaultNyaovimrc() { 58 | console.log('Generate default nyaovimrc at ' + global.nyaovimrc_path); 59 | 60 | return exists(global.config_dir_path).then(e => { 61 | if (!e) { 62 | mkdirpSync(global.config_dir_path); 63 | } 64 | }).then(() => { 65 | const contents = 66 | ` 67 | 75 | 76 | `; 77 | writeFileSync(global.nyaovimrc_path, contents, 'utf8'); 78 | }); 79 | } 80 | 81 | const ensure_nyaovimrc = exists(global.nyaovimrc_path).then((e: boolean) => { 82 | if (!e) { 83 | return prepareDefaultNyaovimrc(); 84 | } else { 85 | // Note: This line needs because of TS7030 error 86 | return undefined; 87 | } 88 | }).catch(err => console.error(err)); 89 | 90 | const browser_config = new BrowserConfig(); 91 | const prepare_browser_config 92 | = browser_config.loadFrom(global.config_dir_path) 93 | .catch(err => console.error(err)); 94 | 95 | function startMainWindow() { 96 | const index_html = 'file://' + join(__dirname, '..', 'renderer', 'main.html'); 97 | 98 | const default_config = { 99 | width: 800, 100 | height: 600, 101 | useContentSize: true, 102 | webPreferences: { 103 | blinkFeatures: 'KeyboardEventKey,Accelerated2dCanvas,Canvas2dFixedRenderingMode', 104 | }, 105 | icon: nativeImage.createFromPath(join(__dirname, '..', 'resources', 'icon', 'nyaovim-logo.png')), 106 | } as Electron.BrowserWindowConstructorOptions; 107 | 108 | const user_config = browser_config.applyToOptions(default_config); 109 | 110 | let win = new BrowserWindow(user_config); 111 | 112 | const already_exists = browser_config.configSingletonWindow(win); 113 | if (already_exists) { 114 | app.quit(); 115 | return null; 116 | } 117 | 118 | browser_config.setupWindowState(win); 119 | if (browser_config.loaded_config !== null && browser_config.loaded_config.show_menubar === false) { 120 | win.setMenuBarVisibility(false); 121 | } 122 | 123 | win.once('closed', function() { 124 | win = null; 125 | }); 126 | 127 | win.loadURL(index_html); 128 | if (process.env.NODE_ENV !== 'production' && is_run_from_npm_package_on_darwin) { 129 | win.webContents.openDevTools({mode: 'detach'}); 130 | } 131 | 132 | return win; 133 | } 134 | 135 | app.once('window-all-closed', () => app.quit()); 136 | app.on('open-url', (e: Event, u: string) => { 137 | e.preventDefault(); 138 | shell.openExternal(u); 139 | }); 140 | app.once('will-finish-launching', function() { 141 | // we use once here because only the first open-file event might be missed by nyaovim-app 142 | app.once('open-file', (e: Event, p: string) => { 143 | // open-file event might be sent before ready event is emitted 144 | // put it in argv to let nyaovim-app to pick it up later 145 | process.argv.push(p); 146 | e.preventDefault(); 147 | }); 148 | }); 149 | 150 | app.once( 151 | 'ready', 152 | () => { 153 | if (process.platform === 'darwin' && is_run_from_npm_package_on_darwin) { 154 | // XXX: 155 | // app.dock.setIcon() is not defined in github-electron.d.ts yet. 156 | (app.dock as any).setIcon(join(__dirname, '..', 'resources', 'icon', 'nyaovim-logo.png')); 157 | } 158 | 159 | Promise.all([ 160 | ensure_nyaovimrc, 161 | prepare_browser_config, 162 | ]).then(() => { 163 | const w = startMainWindow(); 164 | if (w !== null) { 165 | setMenu(w); 166 | } 167 | }); 168 | }, 169 | ); 170 | -------------------------------------------------------------------------------- /main/menu.ts: -------------------------------------------------------------------------------- 1 | import {Menu, app, webContents} from 'electron'; 2 | import {join} from 'path'; 3 | import openAboutWindow from 'about-window'; 4 | 5 | function startAboutWindow() { 6 | openAboutWindow({ 7 | icon_path: join(__dirname, '..', 'resources', 'icon', 'nyaovim-logo.png'), 8 | copyright: 'Copyright (c) 2015 rhysd', 9 | }); 10 | } 11 | 12 | export default function setMenu(win: Electron.BrowserWindow) { 13 | const template = [ 14 | { 15 | label: 'Edit', 16 | submenu: [ 17 | { 18 | label: 'Undo', 19 | accelerator: 'CmdOrCtrl+Z', 20 | click: () => { 21 | if ((win.webContents as any).isFocused()) { 22 | // send the command to the nyaovim-app 23 | win.webContents.send('nyaovim:exec-commands', ['undo']); 24 | } else { 25 | // execute the default command 26 | webContents.getFocusedWebContents().undo(); 27 | } 28 | }, 29 | }, 30 | { 31 | label: 'Redo', 32 | accelerator: 'Shift+CmdOrCtrl+Z', 33 | click: () => { 34 | if ((win.webContents as any).isFocused()) { 35 | // send the command to the nyaovim-app 36 | win.webContents.send('nyaovim:exec-commands', ['redo']); 37 | } else { 38 | // execute the default command 39 | webContents.getFocusedWebContents().redo(); 40 | } 41 | }, 42 | }, 43 | { 44 | type: 'separator', 45 | }, 46 | { 47 | label: 'Cut', 48 | accelerator: 'CmdOrCtrl+X', 49 | click: () => { 50 | if ((win.webContents as any).isFocused()) { 51 | // send the command to the nyaovim-app 52 | win.webContents.send('nyaovim:cut'); 53 | } else { 54 | // execute the default command 55 | webContents.getFocusedWebContents().cut(); 56 | } 57 | }, 58 | }, 59 | { 60 | label: 'Copy', 61 | accelerator: 'CmdOrCtrl+C', 62 | click: () => { 63 | if ((win.webContents as any).isFocused()) { 64 | // send the command to the nyaovim-app 65 | win.webContents.send('nyaovim:copy'); 66 | } else { 67 | // execute the default command 68 | webContents.getFocusedWebContents().copy(); 69 | } 70 | }, 71 | }, 72 | { 73 | label: 'Paste', 74 | accelerator: 'CmdOrCtrl+V', 75 | click: () => { 76 | if ((win.webContents as any).isFocused()) { 77 | // send the command to the nyaovim-app 78 | win.webContents.send('nyaovim:paste'); 79 | } else { 80 | // execute the default command 81 | webContents.getFocusedWebContents().paste(); 82 | } 83 | }, 84 | }, 85 | { 86 | label: 'Select All', 87 | accelerator: 'CmdOrCtrl+A', 88 | click: () => { 89 | if ((win.webContents as any).isFocused()) { 90 | // send the command to the nyaovim-app 91 | win.webContents.send('nyaovim:select-all'); 92 | } else { 93 | // execute the default command 94 | webContents.getFocusedWebContents().selectAll(); 95 | } 96 | }, 97 | }, 98 | ], 99 | }, 100 | 101 | { 102 | label: 'View', 103 | submenu: [ 104 | { 105 | label: 'Reload', 106 | accelerator: 'CmdOrCtrl+R', 107 | click: () => win.reload(), 108 | }, 109 | { 110 | label: 'Toggle Full Screen', 111 | accelerator: process.platform === 'darwin' ? 'Ctrl+Command+F' : 'F11', 112 | click: () => win.setFullScreen(!win.isFullScreen()), 113 | }, 114 | { 115 | label: 'Open Developer Tools', 116 | accelerator: process.platform === 'darwin' ? 'Alt+Command+I' : 'Ctrl+Shift+I', 117 | click: () => win.webContents.openDevTools({mode: 'detach'}), 118 | }, 119 | ], 120 | }, 121 | 122 | { 123 | label: 'Window', 124 | role: 'window', 125 | submenu: [ 126 | { 127 | label: 'Minimize', 128 | accelerator: 'CmdOrCtrl+M', 129 | role: 'minimize', 130 | }, 131 | { 132 | label: 'Close', 133 | accelerator: 'CmdOrCtrl+W', 134 | role: 'close', 135 | }, 136 | ], 137 | }, 138 | 139 | { 140 | label: 'Help', 141 | role: 'help', 142 | submenu: [ 143 | { 144 | label: 'About NyaoVim', 145 | click: () => startAboutWindow(), 146 | }, 147 | ], 148 | }, 149 | ] as Electron.MenuItemConstructorOptions[]; 150 | 151 | if (process.platform === 'darwin') { 152 | template.unshift({ 153 | label: 'NyaoVim', 154 | submenu: [ 155 | { 156 | label: 'About NyaoVim', 157 | click: () => startAboutWindow(), 158 | }, 159 | { 160 | type: 'separator', 161 | }, 162 | { 163 | label: 'Services', 164 | role: 'services', 165 | }, 166 | { 167 | type: 'separator', 168 | }, 169 | { 170 | label: 'Hide NyaoVim', 171 | accelerator: 'Command+H', 172 | role: 'hide', 173 | }, 174 | { 175 | label: 'Hide Others', 176 | accelerator: 'Command+Shift+H', 177 | role: 'hideothers', 178 | }, 179 | { 180 | label: 'Show All', 181 | role: 'unhide', 182 | }, 183 | { 184 | type: 'separator', 185 | }, 186 | { 187 | label: 'Quit', 188 | accelerator: 'Command+Q', 189 | click: () => { app.quit(); }, 190 | }, 191 | ], 192 | } as Electron.MenuItemConstructorOptions); 193 | 194 | (template[3].submenu as Electron.MenuItemConstructorOptions[]).push( 195 | { 196 | type: 'separator', 197 | }, 198 | { 199 | label: 'Bring All to Front', 200 | role: 'front', 201 | }, 202 | ); 203 | } 204 | 205 | const menu = Menu.buildFromTemplate(template); 206 | Menu.setApplicationMenu(menu); 207 | return menu; 208 | } 209 | -------------------------------------------------------------------------------- /main/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "removeComments": true, 5 | "preserveConstEnums": true, 6 | "outDir": ".", 7 | "noImplicitAny": true, 8 | "noImplicitReturns": true, 9 | "noImplicitThis": true, 10 | "noUnusedLocals": true, 11 | "noUnusedParameters": true, 12 | "noEmitOnError": true, 13 | "target": "es2015", 14 | "sourceMap": true 15 | }, 16 | "files": [ 17 | "browser-config.ts", 18 | "menu.ts", 19 | "main.ts", 20 | "lib.d.ts" 21 | ] 22 | } 23 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "nyaovim", 3 | "productName": "NyaoVim", 4 | "version": "0.2.0", 5 | "description": "Web-enhanced Extensible Neovim Frontend", 6 | "main": "main/main.js", 7 | "bin": "./bin/cli.js", 8 | "scripts": { 9 | "dep": "npm install && bower install", 10 | "build:main": "tsc --pretty -p main", 11 | "build:renderer": "tsc --pretty -p renderer", 12 | "build": "npm-run-all -p build:main build:renderer", 13 | "tslint:renderer": "tslint -p renderer/", 14 | "tslint:main": "tslint -p main/", 15 | "nsp": "nsp check", 16 | "lint": "npm-run-all -p tslint:renderer tslint:main nsp", 17 | "app": "cross-env NODE_ENV=production electron .", 18 | "debug": "cross-env ELECTRON_ENABLE_STACK_DUMPING=true NODE_ENV=debug electron .", 19 | "start": "npm-run-all dep build app", 20 | "build:test": "tsc --pretty -p test/", 21 | "smoke-test": "npm run build:test && mocha --exit test/smoke", 22 | "watch": "guard --watchdir main renderer test", 23 | "clean": "rm -rf build bower_components node_modules", 24 | "release": "./scripts/make-release.sh" 25 | }, 26 | "repository": { 27 | "type": "git", 28 | "url": "git+https://github.com/rhysd/NyaoVim.git" 29 | }, 30 | "keywords": [ 31 | "editor", 32 | "extensible", 33 | "WebComponents", 34 | "Neovim", 35 | "nvim", 36 | "Electron", 37 | "Polymer", 38 | "cat", 39 | "meow" 40 | ], 41 | "author": "rhysd ", 42 | "license": "MIT", 43 | "bugs": { 44 | "url": "https://github.com/rhysd/NyaoVim/issues" 45 | }, 46 | "homepage": "https://github.com/rhysd/NyaoVim#readme", 47 | "dependencies": { 48 | "about-window": "^1.11.0", 49 | "deep-extend": "^0.5.0", 50 | "electron": "^1.8.4", 51 | "electron-window-state": "^4.1.1", 52 | "mkdirp": "^0.5.1", 53 | "neovim-component": "^0.10.1", 54 | "promised-neovim-client": "^2.0.2" 55 | }, 56 | "devDependencies": { 57 | "@types/bluebird": "^3.5.20", 58 | "@types/chai": "^4.1.3", 59 | "@types/deep-extend": "^0.4.31", 60 | "@types/electron-window-state": "^2.0.31", 61 | "@types/fbemitter": "^2.0.32", 62 | "@types/flux": "^3.1.7", 63 | "@types/mkdirp": "^0.5.2", 64 | "@types/mocha": "^5.2.0", 65 | "@types/node": "^9.6.6", 66 | "@types/q": "^1.5.0", 67 | "@types/react": "^16.3.12", 68 | "@types/webdriverio": "^4.10.1", 69 | "bower": "^1.8.4", 70 | "chai": "^4.1.2", 71 | "cross-env": "^5.1.4", 72 | "electron-packager": "^12.0.1", 73 | "mocha": "^5.1.1", 74 | "npm-run-all": "^4.1.2", 75 | "nsp": "^3.2.1", 76 | "spectron": "^3.8.0", 77 | "tslint": "^5.9.1", 78 | "typescript": "^2.8.3" 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /renderer/lib.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | declare namespace NodeJS { 4 | interface Global { 5 | require: NodeRequireFunction; 6 | } 7 | } 8 | 9 | interface String { 10 | endsWith(search: string, position?: number): boolean; 11 | } 12 | -------------------------------------------------------------------------------- /renderer/main.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | NyaoVim 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /renderer/main.ts: -------------------------------------------------------------------------------- 1 | if (process.env.PATH.indexOf('/usr/local/bin') === -1 && process.platform !== 'win32') { 2 | // Note: 3 | // This solves the problem that $PATH is not set up when app is 4 | // started via clicking NyaoVim.app. 5 | // 6 | // XXX: 7 | // This is just a workaround. 8 | // If nvim is installed to other directory, we can't know that. 9 | process.env.PATH += ':/usr/local/bin'; 10 | } 11 | 12 | // Note: 13 | // import {remote} from 'electron'; causes an error because both main.js and nyaovim-app.js are 14 | // loaded with