New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Allow to pass lua closures to vim script functions from lua #6246
Conversation
@brammool This is now ready for review and merge. I have added tests but not sure why all tests are passing for all builds except This now allows us to seamlessly pass lua callback which will be converted to vim script lambda. Writing lua plugins should be lot easier now. lua <<EOF
vim.fn.timer_start(1000, function (timer)
print(timer)
end)
EOF
char_u *register_cfunc(cfunc_T cb, cfunc_free_T free_cb, void *state);
Test includes all the scenarios i.e. passing return value of lua function to vimscript, calling lua function from vimscript function. |
Issue seems to be here. Any thought on how to fix this?
|
290bb2f
to
d2774ff
Compare
Memory leak is fixed so the PR is ready for review and merge. There is one test that seems to be failing which also is failing in master and is not related to this PR.
Also might be worth moving the CI to use github actions instead of travis and appveyor. For vim-lsp we migrated to github actions and it was way faster then travis. This last PR tooks travis almost 15-20mins to even just start. |
I would like to hear from users who know Lua and would use this functionality. Comments? |
My current use case was to rewrite asyncomplete v3 in both vimscript (for older version and backwards compatibility) and lua (for performance). I need to use I have tried several times in the past few years to write lua plugins but always landed up with vimscript because the integration was ugly since there is no good bindings. It felt that lua was more there just for the sake of it rather than creating real plugins. Given that I had so hard time creating lua plugins I definitely understand why there are very few to almost none lua plugins for vim. Next version of neovim 0.5 is going to ship with LSP protocol by default which is written in lua and as part of that work they have already gone and added these apis so an entire full fledged powerful plugin can be created in lua. In the past few months I have also seen rise of neovim plugins written in pure lua and I expect this to continue to rise once v0.5 ships.
|
So this works exactly the same as in Neovim? |
I just tried in neovim latest nightly and doesn't seem to work but seems like it is just a matter of time since there is a PR by @tjdevries. neovim/neovim#12138. This PR seems to be implemented purely in lua but creates a temporary global function in lua starting with @justinmk @tjdevries It will be good if both of you can have a look at this PR and the existing neovim PR and see if we can lock to one of the solution so both vim and neovim uses same code. |
@prabirshrestha I was actually following this PR already to see what you ended up with here, and was considering porting (or similiar feature) once I saw how you do it. When I first was writing My original PR was mainly just a starter idea for how we could at least let people write the code (just use @prabirshrestha What exactly are you looking for from me? I can review the code here and figure out if this makes the most sense. I'd have to investigate some of the differences between vim's @brammool As an aside, this is a commonly requested feature when people have been writing all Lua plugins in neovim (which is a common occurence these days, especially after the LSP support was merged into master). |
@tjdevries Your explanation now makes more sense. I wasn't aware of your PR in neovim side. Was curious if you preferred I do agree that while the implementation can be different the behavior should be the same. Which means the same code should be valid in both vim and neovim. |
@prabirshrestha Yeah, I think your proposal is basically: "Wherever you could pass a (where "wherever" means going through If that's your proposal, that is a good thing for me. What I can do, assuming we agree on the semantics of what should happen there, is whatever tests you write for this PR, I can try porting to our testing infrastructure so that we can try and maintain as few differences as possible -- assuming I'm actually able to implement the feature in nvim 😉 |
Other places besides function VimFunc(factory)
let f = a:factory()
return f()
endf function LuaFactory()
return function ()
return 'hi'
end
end Basically To sum up any time lua function passes boundries it needs to be auto converted to vim functions. |
Will you handle passing this and calling this from vimL? local callable_table = setmetatable({}, {__call = function(...) return 5 end}) |
I only check for Line 612 in d2774ff
|
OK, I would vote for supporting it (in the interest of completion). We do not have the file |
I made good progress on a branch for this today. I'll ping you (on this PR if still opened) when I get this far. I have to implement a few more things to bring the interface a little closer together (like funcrefs from vim -> lua) and a few other items. |
@tjdevries That would be great. Feel free to share the PR. Also added support for |
35f996c
to
7b1a509
Compare
Codecov Report
@@ Coverage Diff @@
## master #6246 +/- ##
=======================================
Coverage 87.78% 87.78%
=======================================
Files 143 143
Lines 158812 158898 +86
=======================================
+ Hits 139411 139488 +77
- Misses 19401 19410 +9
Continue to review full report at Codecov.
|
@puremourning seems like I missed your message because you posted directly in google groups instead of github.
I haven't looked at YCM source code due to GPL but Vimspector seems to be apache and is using python's subprocess command. Unlike python lua doesn't come with lot of standard libraries which means there is no official way to start a timer or start a process. On the other hand python will never ship with vim functions such as accessing windows/quickfix and so on. And trying to update language interop for every vim feature added is a nightmare on its own. Hence it was very important for me to use expose all the functions of vimscript to lua and vice versa. I also wanted to do it in a generic way so that next time someone adds a new feature to vimscript I don't need to go and update the lua interop. And this PR and vim.fn*` PR allows to achieve this goal. This was done by neovim and I ported it to vim. It is merged in both.
local job_start = vim.fn.job_start
local jobid = job_start('whoami', {
'out_cb' = function (id, msg)
print(msg)
end
})
char_u *register_cfunc(cfunc_T cb, cfunc_free_T free_cb, void *state);
If you would want this for python there is still a bit work for that needs to be done but this PR and the
I'm not worried about neovim and vim compatibility because There are few incompaitiblities with neovim api as they don't support |
@brammool Any thoughts on merging this given the PR has been open for almost 2 weeks and no comment from lua plug-in others? |
I suppose this looks OK. The help change is tiny though. Could do with some more "advertising" for how this works and how easy it is to pass a callback. |
fd3c89a
to
23a5929
Compare
Updated doc in |
23a5929
to
05e9d26
Compare
05e9d26
to
90b2053
Compare
@prabirshrestha i am curious, what else is necessary to port a lua plugin like neovim's lsp implementation to vim? |
This is work in progress but lays the foundation to pass lua closures to a vim function in pure lua. Over the next couple of days will be working on the remaining tasks but please feel free to review and provide feedback.
Here is a working demo:
This introduces
register_cfunc
api in c which takes a c callback and state and converts it to a vimscript lambda which can then be called by any vimscript.Here are remaining work:
register_cfunc
to take a dectructor c callback so when the lambda gets freed it can go ahead and do cleanup such as callinglua_unref()
and callingfree(state)
.FCERR_NONE
instead of void.Based on looking at neovim source code it seems to treat lua functions as first class so
register_cfunc
doesn't exist in neovim.