Wtswkz
Wtswkz

Reputation: 333

The indent of “if-else-end if;” work weirdly in vim

When I edit a vhdl file using vim or neovim, the “if-else-end if;” statement never autoindent properly. When I typed “if xxx then” and Enter, it looks like as follows:

if xxx then
    |

which is fine. Then I keep typing “end” and a Space, the it looks like:

if xxx then

end |

After I finish the statement by typing “if;”, then it looks like follows:

if xxx then

    end if;

So, how can I fix this?

The filetype is vhdl, the vim version is 8.2, and the script loaded by vim that implements vhdl indention is /usr/share/vim/vim82/indent/vhdl.vim.

Upvotes: 2

Views: 424

Answers (1)

Chris Heithoff
Chris Heithoff

Reputation: 1863

I was able to reproduce this with a vhdl filetype, using filetype indentation.

:set filetype?    --> vhdl
:filetype         --> filetype detection:ON plugin:ON indent:ON

I noticed that the error described is only happening when there were no non-comment, non-empty lines between the if and end if; lines:

if xxx then
    SOMETHING <= '1';
end if;

if xxx then
    end if;

The error is caused by this part of the $VIMRUNTIME/indent/vhdl.vim file. If the current string contains end if and the previous line's string contains if, then return the number ind.

  " indent:   -sw
  " keywords: "else", "elsif", "end" + "block", "for", "function", "generate", "if", "loop", "procedure", "process", "record", "units"
  " where:    start of current line
  let s5 = 'block\|for\|function\|generate\|if\|loop\|procedure\|process\|record\|units'
  if curs =~? '^\s*\%(else\|elsif\|end\s\+\%('.s5.'\)\)\>'
    if prevs =~? '^\s*\%(elsif\|'.s5.'\)'
      return ind
    else
      return ind - shiftwidth()
    endif
  endif

Earlier in the script, the value of ind is increased by a shiftwidth() if the previous line contains then. Later in the script, the value of ind is decreased by a shiftwidth() is end matches the current line. This is the intended behavior, but the above return ind prevents that from happening.

Solution Comment out the return ind line.

  " indent:   -sw
  " keywords: "else", "elsif", "end" + "block", "for", "function", "generate", "if", "loop", "procedure", "process", "record", "units"
  " where:    start of current line
  let s5 = 'block\|for\|function\|generate\|if\|loop\|procedure\|process\|record\|units'
  if curs =~? '^\s*\%(else\|elsif\|end\s\+\%('.s5.'\)\)\>'
    if prevs =~? '^\s*\%(elsif\|'.s5.'\)'
      " DO NOTHING.  COMMENT OUT LINE BELOW
      " return ind
    else
      return ind - shiftwidth()
    endif
  endif

If you can't edit your $VIMRUNTIME/indent/vhdl.vim file, you'll need to copy it to ~/.vim/indent/vhdl.vim first. When you restart Vim with a vhdl file, it will use your local override.

Please also report this as an issue at https://github.com/vim/vim

Upvotes: 3

Related Questions