[WIP] Add support for ECMAScript (aka JavaScript)#5198
[WIP] Add support for ECMAScript (aka JavaScript)#5198prabirshrestha wants to merge 9 commits intovim:masterfrom
Conversation
example:
__vimcall('eval', ['1+1'])
example:
__vimcmd('echom "Hello world"')
example:
__vimeval('1+1')
Certainly if Vim adds this, Neovim could just dump the whole thing into its tree like we did for But we probably won't. Without NPM/v8, this lacks the chief advantages of Javascript. As an alternative to Vimscript, Lua is the strongest option: small, fast, elegant (3 core concepts used as pervasive building blocks: closures + tables + coroutines). With this change, will Vim be stuck with duktape, or could another JS engine be swapped-in? |
|
This proposal allows anyone to swap duktape with any JS engines. In order to have compatibility with other engines we need to support few functions as possible. In this case I proposed to have Given the JS is dynamic language one can do whatever you want. For example some one could write this which exposes nodejs compatible apis but using pure vim functions. Neovim could go and expose the full node runtime. (function (oldRequire) {
function newRequire(name) {
if (name == 'fs') {
return {
readFileSync: function (path) {
return vim.call('readfile', [path]);
}
};
} else {
return oldRequire(name);
}
}
require = newRequire; // overwrite global require with new require
})(require);Then as a plugin author users can use the following. The best part about this is that the below code can also run in nodejs. var fs = require('fs');
var contents = fs.readFileSync('hello.txt');It is very common in JS world to monkey patch features that doesn't exist - Polyfill. Another api I'm thinking is to only expose var vim = require('vim');
var contents = vim.call('readfile', ['hello.txt']);Basically as a plugin author all I care is about having the stdlib in this case My biggest worry about adding full nodejs api is that it will increase the size and we are back to making ecmascript support optin which means most vim distributions out there won't enable it by default. I would really like this feature to also be available in tiny builds. The same goes for using the npm packages and the entire nodejs ecosystem. If we make the spec for If Neovim does have full support for node I would also be happy with it since then I can use certain features such as watch file. var vim = require('vim');
var fs;
try {
fs = require('fs');
} catch () {}
if (fs) {
fs.watchFile('filetowatch', (cur, prev) => {
// file changed.
});
}
I would be curious to hear @brammool thoughts on always enabling Lua and requiring explicit optout to not include lua. Also might be converting the JS itself is also very small and easy to undertand. It does have generators and async/await similar to lua though all js engines might not support it. It also does have closures (The first example of replacing require js shows an example of closure). The biggest advantage of JS instead of lua is the ability to tap into the entire nodejs and npm ecosystem by getting the The goal of this PR is to start conversations like these so we can get the thoughts and vision from the vim and neovim devs as well as plugin authors. The other option is to completely ignore ECMAScript and Lua as default scripting and go full on with WebAssembly. The only problem with this is that we currently don't have any good runtimes written in pure c now. Biggest advantage of WASM over Ecmascript and JS it that it allows to get the entire ecosystem of almost all languages out there and can also be high performant. Here is the list of wasm runtimes. https://github.com/appcypher/awesome-wasm-runtimes. wac seems to be written in c but I couldn't get to compile it on mac and windows yet but should be simple. It is MPL license. If anyone is interested to work on creating a minimal wasm runtime in c let me know and I would be happy to work on this with others. And of course similar to lua and luajit support we could have a basic unoptimized version of wasm c runtime and interpreter in vim and if people do want a fast one they could use other complicated wasm runtime and interpreters that support JIT. |
|
As for Javascript vs WebAssembly I create a twitter poll that will last for 1 day. Will be curious to see the results. https://twitter.com/PrabirShrestha/status/1193363217763799045 |
But not even Vim's own This would anyways defeat the purpose of the TINY build, which is a vanity exercise for people who insist Vim HEAD is needed on ultra-constrained-resource systems.
Good idea.
Doesn't that conflict with "small and easy to understand"? JS keeps adding language features, workarounds for an incomplete design.
Can do this already in Neovim, with Lua |
What are these? |
Multi line lambdas in vim script with closures. Very important to express for async code. Both Lua and JS shines on this one compared to vimscript. For vim-lsp I use a helper until function to express async workflow. https://github.com/prabirshrestha/vim-lsp/blob/master/autoload/lsp/utils/step.vim |
|
Wasn’t aware of FEAT_EVAL.
This is one of the reason I’m leaning to WASM. Create a simple good wasm vim in c and let the respective language author do the design. |
|
I don't understand why you would wasm at all. You would need a compiler, so you might as well just compile to an .so file and load that - free performance! As for JavaScript - we've already got Python. You say that your goal here is to provide a less bloated feature, so that more distributions ship it by default. In my opinion, the reasonable thing to do here is to reduce the overhead of Python, instead of shipping yet another language, which will increase the size of a full build, and hence increase the pressure to leave some features disabled. Moreover, the design of JavaScript is absolutely terrible. An undefined member variable should clearly be an unrecoverable error, but JavaScript insists on doing something. This is just one example, but this philosophy is applied everywhere. |
Wasm binary is portable so users don't need to compile sources in their environment. If wasm is integrated to Vim, plugin authors can build a plugin with a language which can be compiled into Wasm and can compile it to API to use system interfaces are being defined as WebAssembly System Interface portably. Plugin authors (hopefully) don't need to take care about differences of platforms. Another advantage is security. WebAssembly is run in sandboxed separated environment. BTW I'm not sure what you mean with '.so file', but interfaces between Vim script and |
I feel like this is an easy way to get proprietary vim plugins. I'm not sure if that's desirable.
This would require a creating a permission model. Malicious plugins won't become harmless just because they're being executed by a wasm runtime.
Improving this would certainly be easier and introduce less bloat. |
|
A few comments:
|
|
So I have been playing more with duktype and it not supporting lambdas is very disappointing. Thought typescript is gaining popularity the target language of JS will always be more popular. Browsers have no intention to make TS a first class language. They only have plans to support webassembly. For me the main problem with other languages is that it doesn't come out of the box. So writing a plugin in vimscript is the only way to get 100% coverage. Some OS comes with python but older version and trying to manage is another mess. Though once done it is very easy. If there are ways to make vimscript faster it would be good but I'm not sure it is worth it. I would rather have the investments in making lua the default language or webassembly vm that is always part of vim. Then rather then executing vimscript you compile vimscript to lua or webassembly and let their engine execute. All neovim builds already ship with lua. It would be good if vim does the same. It will almost be impossible to bit the speed of LuaJIIT. Converting all the vimscript in vim to lua would be one way to force people to enable lua in vim for their distributions. At some universities and work we can't install random binaries so having lua/webassembly working with vim by default would be good. |
Agreed, and that hints at a question I've silently had: if a JS dev isn't willing to learn Lua, how in the world will they have the patience to write a plugin for any editor--Vim or otherwise--given that learning the API is the most annoying part. So "JS instead of Lua" isn't compelling in terms of mere syntax.
No. Interface is very important, but "mainly" is an overstatement: at least half of the reason is that Python is optional in Vim. Defaults matter (as Vim admits implicitly, via the defaults.vim half-solution). Not to mention, Vim Python support requires system libs to be upgraded in lockstep.
That's a strong solution if Vimscript is backwards-compatible. But it's not, and I expect it will introduce more breaking changes to achieve such speedups. If "Vimscript version 17" makes backwards-incompatible changes then it's a different language than "Vimscript version 1". And this means there was no reason to keep it instead of using Lua: entire purpose of supporting Vimscript is to support existing plugins. If those plugins don't get the performance improvements because they use an older |
|
Python is the most popular scripting language. Unfortunately, embedding it is problematic. And even then a runtime environment is needed, which is too big to ship together with Vim, thus installing Python (in a version that matches what Vim was build with) is then a requirement, which apparently is too much of a burden for most users. The same is true for all script languages. Lua might be smaller, but I don't think it is feasible to include it with the distribution. And Lua is not popular at all, it dangles near the end of popular language rankings, if it appears at all. Javascript is popular, but that's for use in a browser. It doesn't even have file access in the language itself, requires a runtime like NodeJS, which is big (or perhaps huge, depending on what you expect). Perl appears to have dropped out of the "popular languages" rankings. The same might happen to any less known or less used language. |
Lua 5.1 is 10k LOC. xdiff was pasted-into Vim's source tree without hesitation, adding 5k LOC: e828b76#diff-60e734234eae4792117ac2f0f869eb98 libvterm was also pasted-into Vim's tree.
How is that relevant? Vimscript is even less popular than perl, Lua, Visual Basic, Haskell, and many others. What matters is that Lua is a mature, well-designed language with multiple high-quality implementations. "Vimscript version 1" will never compete in terms of performance nor popularity. "Vimscript version 87" may someday match the performance of Ruby 1.x, yet it will be even less popular than "Vimscript version 1". |
Besides the fact that I personally don't like lua, I don't see how this is relevant. So lua is still twice as big as xdiff (which made a smaller by adding many ifdefs) and it does not fullfill a need. We already have python, perl and tcl that basically serve the same purpose. So that argument doesn't hold at all. If you want to convince me personally, then please come with some arguments why yet another language should be imported and supported. I don't see this here. |
|
Vim is used more often than Lua: https://github.com/oprogramador/github-languages#all |
|
My 2cents, Vim, and more so Neovim, already has integration with many 3rd party languages, most commonly Python. For example, Coc is mostly implemented in TypeScript. The core issue is not that 3rd party languages are excluded, it's that 3rd party integrations are fragile and can sometimes be a pain in the behind when updates occur (system, Homebrew, etc). It is way too easy to break Python plugins as noted here. I avoid Python plugins like the plague for this reason. Fundamentally it should be about what runtimes are available and their capabilities. As much as JavaScript and TypeScript are the new hotness, that can fade, I can not see their runtimes ever being built into Vim. Too big and too much of a moving target. Note that does not preclude JavaScript-based plugins from existing, they already do as noted by Coc. Vim provides Vimscript which has Frankensteined its way into be decent. @justinmk in his recent VimConf provided this VimScript vs Lua micro-performance result: That's a 2000 times speedup.
Plugins implemented in Vimscript will hit problems when dealing with large amounts of items, sorting, filtering, etc. Many, maybe even most, plugins will be fine. However, some do require something faster than Vimscript. If the maintainers of Vim can speed Vimscript up, that would be awesome, it would benefit every Vim user. I am not sure how easy that will be, runtimes and JITs sounds hard. The Neovim crew have incorporated Lua and LuaJIT. Of all the choices available this seems ideal. Very small size, yet comes with a high performance JIT. Lua is a niche language, for sure, but so is Vimscript. Most Vim users aren't writing plugins, hence learning Lua will be limited to the subset of Neovim users who code plugins. In that context it's an ideal choice. And I am very confident that Lua has a bright future since one of the biggest Internet infrastructure companies, Cloudflare, makes use of Lua and LuaJIT. It will be very interesting to see what happens with respect to pure Lua Neovim plugins. Will we see Deoplete-like (completion engine) or CtrlP-like (fuzzy finders) plugins implemented in pure Lua? Maybe we will have a best of both worlds:
Enough ramblings. |
|
QuickJS is tailor-made for this use case:
😕 There is no such language as TypeScript as far as embedding/eval is concerned, any more than there are CoffeeScript, MoonScript, or Riml runtimes/interpreters. Deno (and TypeScript (tsc) itself) transpiles the syntax to JavaScript. |
|
Talking about the scripting language, I think there are two choices in front of us: 1. Adopting a mature language.IMO, lua is the best option which is very fast, very slim and embedable. I am willing to learn it if it can improve the performance, and of course it will cause many people have proved it. And neovim also adopt lua already, if vim adopts too, we'll benefit from neovim's plugin ecosystem. 2. Grow vim-script into a mature one.@brammool and many other developers are doing for this. (Thanks for your working!) We can see patches are uploaded almost everyday. But when can vim-script be ready as a mature language? I don't know. Besides, as vim-script growing, |
|
As an average developer. (Yes we use Vim, and yes we are part of the equation too) If I get to choose between a faster VimScript Implementation vs Lua. I'll choose Lua. Lua is worth learning, is a good investment of my time, it can be used elsewhere to build things other than plugins for a text editor. |
|
This is an interesting discussion, but not a feasible pull request. Therefore closing. |
|
@prabirshrestha @brammool there are too many awesome programming language, can we add all of them? No, of cause, so the best way is add remote API support, just like what neovim did. The all plugins developers can choose their own language! |
This is based on the awesome work by @bobpepin so most of the credit should go to him.
This PR is still work in progress but would like to hear everyones thought on this while I'm working on it.
As a plugin author while vimscript is powerful it is also very difficult to express some of the constructs in vimscript. Since ECMAScript (ES) is one of the most popular languages out there it would be good if we can embed it. Unlike lua and python bindings I would like ECMAScript to be in vim by default even in tiny builds to get maximum coverage.
Here are some of my thoughts on the apis which is very similar to the existing lua api.
has('ecmascript')to detect if ecmascript is enabled or disabled.:ecmascript ...javascript code...lua()function.require()function, similar to node js module system. Do we want to use node module resolution alogrightm or want to use vimscript resolution or combination of both? This would require a deeper discussion.WebWorkerbut instead of using thread use process.__dirnameand__filenamesimilar to nodejs which allows to get the directory and filename of the javascript file.Why functions starting with
__vim?What about rest of the apis? I don't think we need it. Minimal is better and also makes maintenance in vim codebase easier since no one needs to touch javascript ever again. Adding a function in c in vimscript would easily make it available to the javascript world.