OCamlPro / ocp-indent

Indentation tool for OCaml, to be used from editors like Emacs and Vim.
http://www.typerex.org/ocp-indent.html
Other
200 stars 63 forks source link

Vim script seems a bit too minimal #54

Closed dbaelde closed 11 years ago

dbaelde commented 11 years ago

The current vim script does not use ocp-indent in a way that is really useful: it only filters one or several lines through the tool. As a result, indenting a single line usually does not result in the desired indentation, since the context is ignored.

Also, it seems that the --numeric option would be more lightweight than replacing parts of the buffer by ocp-indent's output.

AltGr commented 11 years ago

Acknowledged. I'll try and find vim-using contributors for this :)

dbaelde commented 11 years ago

I spent a while trying to remember the vim scripting I know... I did not remember anything. Best solution I have so far is this setlocal indentexpr=GetOCPIndent(v:lnum)

function GetOCPIndent(l) silent execute "1,".a:l."w !ocp-indent --numeric | tail -n 2 | head -n 1 > .ocpindentlevel" return system("cat .ocpindentlevel") endfunction

It sucks to go through a file, and it makes the screen flicker. The good solution seems to be :redir but I couldn't make it to work.

Note that I don't know the use of the former vim script you provided, for me the above is enough, although it is probably sub-optimal when indenting a region.

let-def commented 11 years ago

I started working on better integration of ocp-indent in vim. I submitted a pull request a few days ago to use ocp-indent interactively instead of spawning a new process each time, though I am not sure it is the way to go.

Here is the python helper I use in vim: ocpindent.py ocpindent.vim

Results are encouraging so far, but integration is far from perfect.

AltGr commented 11 years ago

@dbaelde I don't know much about vim scripting, but if you could find a way to specify the --lines option to ocp-indent, you could save the pipe through tail/head (and maybe the silent+redirect+cat ?) ; incidentally, that would get the indentation of the current line to adapt relatively to the lines above if they don't follow the expected indentation.

Maybe this is not well documented, but --lines + --numeric only gives output for the concerned lines. So maybe something like:

function GetOCPIndent(l)
  execute "w !ocp-indent --numeric --lines ".a:l
endfunction

could be enough ?

dbaelde commented 11 years ago

Louis, you're right, I should really have used lines. However this doesn't save the redirect dance: the problem is that execute seems to be the only way to get the file into a process' stdin, and system is the only way to get a process' stdout...

The future of vim scripting might be to use interfaces such as python (or lua, perl..). I haven't tested def-lkb's scripts but I'm hopeful that he has the right answer and is getting close.

On Tue, Apr 2, 2013 at 10:56 AM, Louis Gesbert notifications@github.comwrote:

@dbaelde https://github.com/dbaelde I don't know much about vim scripting, but if you could find a way to specify the --lines option to ocp-indent, you could save the pipe through tail/head (and maybe the silent+redirect+cat ?) ; incidentally, that would get the indentation of the current line to adapt relatively to the lines above if they don't follow the expected indentation.

Maybe this is not well documented, but --lines + --numeric only gives output for the concerned lines. So maybe something like:

function GetOCPIndent(l) execute "w !ocp-indent --numeric --lines ".a:l endfunction

could be enough ?

— Reply to this email directly or view it on GitHubhttps://github.com/OCamlPro/ocp-indent/issues/54#issuecomment-15763818 .

David

Karmaki commented 11 years ago

Just a message to tell you that I would be very interested if you make '==' work to indent a line in vim since the result of the indentation with 'ocp-indent' seems very nice. Unfortunately, I have no time at the moment to find a solution myself... sorry.

let-def commented 11 years ago

Two options:

Either set equalprg to '':

:set equalprg=

This way, vim will invoke ocp-indent for every line. This will be quite slow, especially considering "quadratic behavior" (ocp-indent will reparse everyline already indented for each new line…). I have an experimental vim plugin making use of the state checkpointing introduced in ocp-indent master that partially solve this problem.

Otherwise, you will have to workaround vim handling of "=". For instance using this snippet (put it in your .vimrc):

python <<END
import vim
def ocpindent_equal():
  r = vim.current.range
  w = vim.current.window
  pos = w.cursor
  vim.command("0,'>!%s --lines %d-" % ("ocp-indent", r.start+1))
  w.cursor = pos
END

function! OcpIndentEqual()
  py ocpindent_equal()
endfunction!

Then

call OcpIndentEqual()

instead of using "=" (for instance, mapping "=" to this statemant in normal and visual mode).

Karmaki commented 11 years ago

Thank you. I'll try that as soon as possible, but I don't understand the first suggestion. Do you really mean setting equalprg to nothing ? or do you meant to ocp-indent ? (I already have setlocal equalprg=ocp-indent in my .vimrc)

let-def commented 11 years ago

By setting equalprg to nothing, vim will fallback to indentexpr to compute line indentation. indentexpr is what is used to indent during edition (and ocp-indent.vim essentially plug ocp-indent binary to the indentexpr "api").

The pros is that you will get exactly the same behavior as reindenting line-by-line manually, the cons is that it will do an enormous amount of useless work (on big file, it will feel really slow).

Karmaki commented 11 years ago

The solution with an empty equalprg is working great : thanks ! I don't like having big files anyway, and on the files that I tried, it doesn't feel slow at all. Many thanks again.

jonathanderque commented 11 years ago

I agree the current mode is not as featureful as the emacs plugin.

For the record, here is an updated version which:

The plugin filters the whole document and only indents the selected text with the --lines ocp-indent option. This is not an issue, even with large files (I've a 15k+ loc file which get indented almost instantly by this plugin).

One of the issue is that vim tends to jump to the beginning of the file when you undo the indendation, but this version is still better that the one shipped with ocp-indent.

" Assumes that ocp-indent is in PATH.
" This can be overriden by setting g:ocp_indent_binary in your .vimrc. Eg.
"
" let g:ocp_indent_binary = "/home/jo/bin/ocp-indent.exe"
"

function! PreserveExec(expr)
  let l:pos = getpos(".")
  let l:winview = winsaveview()
  try
    execute(a:expr)
  finally
    call setpos(".", l:pos)
    call winrestview(l:winview)
  endtry
endfunction

function! OcpIndentRange() range
  let l:ocp_indent_binary = exists("g:ocp_indent_binary") ? g:ocp_indent_binary : "ocp-indent"
  call PreserveExec(':%!' . l:ocp_indent_binary . ' -l ' . a:firstline . '-' . a:lastline)
endfunction

function! OcpIndentBuffer()
  let l:ocp_indent_binary = exists("g:ocp_indent_binary") ? g:ocp_indent_binary : "ocp-indent"
  call PreserveExec(':%!' . l:ocp_indent_binary)
endfunction

vnoremap <LocalLeader>i :call OcpIndentRange()<CR>
nnoremap <LocalLeader>i :call OcpIndentBuffer()<CR>
map == :call OcpIndentRange()<CR>
vnoremap = :call OcpIndentRange()<CR>
Karmaki commented 11 years ago

Sorry, I didn't have time to test it before... I have just copied that in my vim files, and it seems to work fine. Many thanks !

AltGr commented 11 years ago

I'm closing this issue, hopeful that Jonathan's new script does the trick. Feel free to reopen, or open new issues for remaining vim-related limitations.