rodjek / vim-puppet

Puppet niceties for your Vim setup
Apache License 2.0
500 stars 137 forks source link

Brackets and hash in string breaks indentation #117

Closed jonjhallettuob closed 3 years ago

jonjhallettuob commented 4 years ago

It appears that a hash following a bracket in a string breaks indentation. For example, gg=G on the following mis-indents the second line:

$baz = '[#'
  $qux = 0

I'm using the current master branch, commit fc6e9efef797c505b2e67631ad2517d7d6e8f00d.

For comparison, a bracket and a hash on their own indent correctly:

$baz = '['
$bar = '#'
$qux = 0
jonjhallettuob commented 4 years ago

The issue is line 104 in indent/puppet.vim:

    if pline =~ '\({\|\[\|(\|:\)\s*\(#.*\)\?$'

which is mistakenly treating a hash in a string as a comment.

lelutin commented 4 years ago

I can confirm this issue, and that the # doesn't match when not placed after an open square bracket.

@jonjhallettuob thanks for also tracking down the source of the issue! removing \(#.*\)\? from the regexp does remove the problem -- mind you this is not a solution at all, just a way to identify the part of the regexp that's causing the trouble :)

by looking very quickly at the regexp, the part matching the sharp sign is there to permit trailing comments on the line. the problem is that the match does not disqualify litteral # in a string. in fact in a similar manner, even matching the open brace/bracket/parens matches even though we're inside a string. the following example causes indentation even though it shouldn't:

$bar = '{
  #text indented here even though we're still inside the string

I'm not sure off the top of my head how we could identify this situation with the regexp.

maybe we can check the syntax group of the matched open brace/brackent/parens to ensure that it's not in a string?

I'll have to let this idea ferment in my head for a while... if you come up with a better idea let me know

jonjhallettuob commented 4 years ago

@lelutin How about something like this?

    let l:bracketAtEndOfLinePattern = '\({\|\[\|(\|:\)\s*\(#.*\)\?$'
    if pline =~ l:bracketAtEndOfLinePattern
        let l:i = match(pline, l:bracketAtEndOfLinePattern)
        let l:syntaxType = synIDattr(synID(pnum, l:i + 1, 0), 'name')
        if l:syntaxType !~ '\(Comment\|String\)$'
            let ind += &sw
        endif

It only works if syntax is on, but it seems to be idiomatic in Vim indent files.

A pull request is linked below.