neovim

Neovim text editor
git clone https://git.dasho.dev/neovim.git
Log | Files | Refs | README

perl.vim (6083B)


      1 " Vim indent file
      2 " Language:      Perl
      3 " Maintainer:    vim-perl <vim-perl@googlegroups.com> (need to be subscribed to post)
      4 " Homepage:      https://github.com/vim-perl/vim-perl
      5 " Bugs/requests: https://github.com/vim-perl/vim-perl/issues
      6 " License:       Vim License (see :help license)
      7 " Last Change:   2022 Jun 14
      8 
      9 " Suggestions and improvements by :
     10 "   Aaron J. Sherman (use syntax for hints)
     11 "   Artem Chuprina (play nice with folding)
     12 
     13 " TODO things that are not or not properly indented (yet) :
     14 " - Continued statements
     15 "     print "foo",
     16 "       "bar";
     17 "     print "foo"
     18 "       if bar();
     19 " - Multiline regular expressions (m//x)
     20 " (The following probably needs modifying the perl syntax file)
     21 " - qw() lists
     22 " - Heredocs with terminators that don't match \I\i*
     23 
     24 " Only load this indent file when no other was loaded.
     25 if exists("b:did_indent")
     26    finish
     27 endif
     28 let b:did_indent = 1
     29 
     30 " Is syntax highlighting active ?
     31 let b:indent_use_syntax = has("syntax")
     32 
     33 setlocal indentexpr=GetPerlIndent()
     34 setlocal indentkeys+=0=,0),0],0=or,0=and
     35 if !b:indent_use_syntax
     36    setlocal indentkeys+=0=EO
     37 endif
     38 
     39 let b:undo_indent = "setl inde< indk<"
     40 
     41 let s:cpo_save = &cpo
     42 set cpo-=C
     43 
     44 function! GetPerlIndent()
     45 
     46    " Get the line to be indented
     47    let cline = getline(v:lnum)
     48 
     49    " Indent POD markers to column 0
     50    if cline =~ '^\s*=\L\@!'
     51        return 0
     52    endif
     53 
     54    " Get current syntax item at the line's first char
     55    let csynid = ''
     56    if b:indent_use_syntax
     57        let csynid = synIDattr(synID(v:lnum,1,0),"name")
     58    endif
     59 
     60    " Don't reindent POD and heredocs
     61    if csynid == "perlPOD" || csynid == "perlHereDoc" || csynid =~ "^pod"
     62        return indent(v:lnum)
     63    endif
     64 
     65    " Indent end-of-heredocs markers to column 0
     66    if b:indent_use_syntax
     67        " Assumes that an end-of-heredoc marker matches \I\i* to avoid
     68        " confusion with other types of strings
     69        if csynid == "perlStringStartEnd" && cline =~ '^\I\i*$'
     70            return 0
     71        endif
     72    else
     73        " Without syntax hints, assume that end-of-heredocs markers begin with EO
     74        if cline =~ '^\s*EO'
     75            return 0
     76        endif
     77    endif
     78 
     79    " Now get the indent of the previous perl line.
     80 
     81    " Find a non-blank line above the current line.
     82    let lnum = prevnonblank(v:lnum - 1)
     83    " Hit the start of the file, use zero indent.
     84    if lnum == 0
     85        return 0
     86    endif
     87    let line = getline(lnum)
     88    let ind = indent(lnum)
     89    " Skip heredocs, POD, and comments on 1st column
     90    if b:indent_use_syntax
     91        let skippin = 2
     92        while skippin
     93            let synid = synIDattr(synID(lnum,1,0),"name")
     94            if (synid == "perlStringStartEnd" && line =~ '^\I\i*$')
     95                        \ || (skippin != 2 && synid == "perlPOD")
     96                        \ || (skippin != 2 && synid == "perlHereDoc")
     97                        \ || synid == "perlComment"
     98                        \ || synid =~ "^pod"
     99                let lnum = prevnonblank(lnum - 1)
    100                if lnum == 0
    101                    return 0
    102                endif
    103                let line = getline(lnum)
    104                let ind = indent(lnum)
    105                let skippin = 1
    106            else
    107                let skippin = 0
    108            endif
    109        endwhile
    110    else
    111        if line =~ "^EO"
    112            let lnum = search("<<[\"']\\=EO", "bW")
    113            let line = getline(lnum)
    114            let ind = indent(lnum)
    115        endif
    116    endif
    117 
    118    " Indent blocks enclosed by {}, (), or []
    119    if b:indent_use_syntax
    120        " Find a real opening brace
    121        " NOTE: Unlike Perl character classes, we do NOT need to escape the
    122        " closing brackets with a backslash.  Doing so just puts a backslash
    123        " in the character class and causes sorrow.  Instead, put the closing
    124        " bracket as the first character in the class.
    125        let braceclass = '[][(){}]'
    126        let bracepos = match(line, braceclass, matchend(line, '^\s*[])}]'))
    127        while bracepos != -1
    128            let synid = synIDattr(synID(lnum, bracepos + 1, 0), "name")
    129            " If the brace is highlighted in one of those groups, indent it.
    130            " 'perlHereDoc' is here only to handle the case '&foo(<<EOF)'.
    131            if synid == ""
    132                        \ || synid == "perlMatchStartEnd"
    133                        \ || synid == "perlHereDoc"
    134                        \ || synid == "perlBraces"
    135                        \ || synid == "perlStatementIndirObj"
    136                        \ || synid == "perlSubDeclaration"
    137                        \ || synid =~ "^perlFiledescStatement"
    138                        \ || synid =~ '^perl\(Sub\|Block\|Package\)Fold'
    139                let brace = strpart(line, bracepos, 1)
    140                if brace == '(' || brace == '{' || brace == '['
    141                    let ind = ind + shiftwidth()
    142                else
    143                    let ind = ind - shiftwidth()
    144                endif
    145            endif
    146            let bracepos = match(line, braceclass, bracepos + 1)
    147        endwhile
    148        let bracepos = matchend(cline, '^\s*[])}]')
    149        if bracepos != -1
    150            let synid = synIDattr(synID(v:lnum, bracepos, 0), "name")
    151            if synid == ""
    152                        \ || synid == "perlMatchStartEnd"
    153                        \ || synid == "perlBraces"
    154                        \ || synid == "perlStatementIndirObj"
    155                        \ || synid =~ '^perl\(Sub\|Block\|Package\)Fold'
    156                let ind = ind - shiftwidth()
    157            endif
    158        endif
    159    else
    160        if line =~ '[{[(]\s*\(#[^])}]*\)\=$'
    161            let ind = ind + shiftwidth()
    162        endif
    163        if cline =~ '^\s*[])}]'
    164            let ind = ind - shiftwidth()
    165        endif
    166    endif
    167 
    168    " Indent lines that begin with 'or' or 'and'
    169    if cline =~ '^\s*\(or\|and\)\>'
    170        if line !~ '^\s*\(or\|and\)\>'
    171            let ind = ind + shiftwidth()
    172        endif
    173    elseif line =~ '^\s*\(or\|and\)\>'
    174        let ind = ind - shiftwidth()
    175    endif
    176 
    177    return ind
    178 
    179 endfunction
    180 
    181 let &cpo = s:cpo_save
    182 unlet s:cpo_save
    183 
    184 " vim:ts=8:sts=4:sw=4:expandtab:ft=vim