parsonsmatt/intero-neovim

Vim 8.1 support

parsonsmatt opened this issue ยท 10 comments

Vim 8.1 has async stuff and a terminal, so we can potentially support vanilla vim in addition to neovim. I have no idea what this entails, so this issue will serve as a place to stuff research and notes.

Here's a really terrible first effort at using intero to display the type signature of the identifier under the cursor. I added it to my .vim/plugin directory and it worked so I thought I'd put it up here. Next steps involve more documentation, testing, cleaning up the code and adding more features.

To be able to run it, you need to first install intero using stack build intero in your stack project directory.

" store the buffer's name
autocmd FileType haskell let s:modulePath = bufname("%")
" store the module's name
autocmd FileType haskell let s:moduleName = fnamemodify(s:modulePath, ":t:r")
" activate intero
autocmd FileType haskell term stack exec intero
" switch panes
autocmd FileType haskell call feedkeys("\<C-W>j")
" return a terminal id
autocmd FileType haskell let s:terminalId = term_list()[0]
" load the current module
autocmd FileType haskell call term_sendkeys(s:terminalId, ":load " . s:modulePath . "\<CR>")
" a mapping to return the type of the expression under the cursor
autocmd FileType haskell nnoremap <localleader>qt :call <SID>QueryType()<cr>

function! s:QueryType()
  " get line number
  let line = line(".")
  " move to start of identifier
  normal b
  " get column number
  let startcol = col(".")
  " move to end of identifier
  normal e
  " get column number
  let endcol = col(".")
  " move to terminal window
  call feedkeys("\<C-W>k") 
  " change terminal window to normal mode
  call feedkeys("\<C-W>N")
  " move to last line
  call feedkeys("G")
  " store this line number
  let lastline = term_getcursor(s:terminalId)[0]
  " back to Terminal-Job mode
  call feedkeys("i")
  " move to haskell buffer
  call feedkeys("\<C-W>j")
  " execute type query
  call term_sendkeys(s:terminalId, ":type-at " . s:moduleName . " " . line . " " . startcol . " " . line . " " . endcol . "\<CR>")
  " sleep for 100 milliseconds
  sleep 100m
  " get newest line
  let type = term_getline(s:terminalId, lastline + 1)
  " show the type in the message window
  echom type
endfunction

Very cool! That's a demonstration that this can work :)

We'll need to find every neovim-specific thing here and identify it's counterpart in vim, and then choose which codepath to go on based on which editor we're using. I think that much of the current code will be fine in either editor, and only the async/terminal stuff will need to be modified.

I tried to go through the intero-neovim code to understand which things in my example are vim-specific and I made a table of important(?) counterparts.

vim function neovim function
autocmd same
bufname() same
fnamemodify() same
feedkeys() same
line() same
col() same
sleep same
term terminal
term_list() bufnr("%") when terminal is active buffer
term_sendkeys() jobsend()
term_getcursor() getpos() when terminal is active buffer
term_getline() getline() when terminal is active buffer

Based on the evidence, your observation about most of the code being fine in either editor is on point!

I really like how the intero-neovim code is structured so I think it would be nice to maintain that when porting the plugin.

If I'm interested in getting it to work, you wouldn't mind if I started transplanting the code function-by-function and making tiny changes as necessary, would you?

Go for it! If you implement this then I will likely make you a maintainer and responsible for the non-neovim parts :)

I would suggest writing a "compatibility layer" file with functions like

g:vim_compat:term_list()

that does the same thing in both neovim and vim. Then all things which are different between the editors can just be ported there and used from client code without having to care about the vim/neovim distinction.

Okay I believe I got the plugin to work with Vim 8, and I've put the code up here.

When I say that it "works" I mean that I can use the commands defined in plugin/intero.vim
without errors. Terminal interaction is not giving me problems at all.

The README.md file describes the changes I made and why I had to make them.
I've mostly made small changes here and there in repl.vim and process.vim files and apart from that I've made like one change to util.vim. I have also defined two short 'wrapper functions' in a new file compatibility.vim .

I want to ask you a few questions about adapting the code to the "compatibility layer" style once you have seen exactly what needed to be changed.

This is fantastic work @Fyrbll ๐Ÿ˜„ I'll review it more closely tomorrow.

@parsonsmatt I don't know if you got the chance to look at the code and/or try out the plugin yet.

I understand that you might be quite busy with other things. Given that, I really appreciate the time you've spent responding to the messages on this thread.

I'm certain that people other than myself would like to use intero with vim. What do you think about spreading the word that a vim port of the intero-neovim plugin exists and is available for testing? That way I can handle issues that people report and fix them. How should I go about it?

Thanks!

I apologize, I didn't get the chance to review it. Please feel free to put out a notice that there is a fork for vim and we'll get some beta testers going :)

Hello! I'm sorry about having disappeared for about a month... I was returning to college after a break and needed to adjust. I'm actively making time for Haskell stuff again so I should be more prompt with everything. I'm going to:

  • give my fork a proper readme, etc. deriving from yours (and linking the original project ofc) but with my existing content on additions/deletions included so that readers know what's up
  • make a post on r/haskell notifying people that there's a fork for vim. I'm thinking maybe Discord and haskell-cafe if possible so if I'm missing anything please let me know!