1" Vim indent file 2" Language: Meson 3" License: VIM License 4" Maintainer: Nirbheek Chauhan <nirbheek.chauhan@gmail.com> 5" Original Authors: David Bustos <bustos@caltech.edu> 6" Bram Moolenaar <Bram@vim.org> 7" Last Change: 2015 Feb 23 8 9" Only load this indent file when no other was loaded. 10if exists("b:did_indent") 11 finish 12endif 13let b:did_indent = 1 14 15" Some preliminary settings 16setlocal nolisp " Make sure lisp indenting doesn't supersede us 17setlocal autoindent " indentexpr isn't much help otherwise 18 19setlocal indentexpr=GetMesonIndent(v:lnum) 20setlocal indentkeys+==elif,=else,=endforeach,=endif,0) 21 22" Only define the function once. 23if exists("*GetMesonIndent") 24 finish 25endif 26let s:keepcpo= &cpo 27setlocal cpo&vim 28 29" Come here when loading the script the first time. 30 31let s:maxoff = 50 " maximum number of lines to look backwards for () 32 33function GetMesonIndent(lnum) 34 echom getline(line(".")) 35 36 " If this line is explicitly joined: If the previous line was also joined, 37 " line it up with that one, otherwise add two 'shiftwidth' 38 if getline(a:lnum - 1) =~ '\\$' 39 if a:lnum > 1 && getline(a:lnum - 2) =~ '\\$' 40 return indent(a:lnum - 1) 41 endif 42 return indent(a:lnum - 1) + (exists("g:mesonindent_continue") ? eval(g:mesonindent_continue) : (shiftwidth() * 2)) 43 endif 44 45 " If the start of the line is in a string don't change the indent. 46 if has('syntax_items') 47 \ && synIDattr(synID(a:lnum, 1, 1), "name") =~ "String$" 48 return -1 49 endif 50 51 " Search backwards for the previous non-empty line. 52 let plnum = prevnonblank(v:lnum - 1) 53 54 if plnum == 0 55 " This is the first non-empty line, use zero indent. 56 return 0 57 endif 58 59 " If the previous line is inside parenthesis, use the indent of the starting 60 " line. 61 " Trick: use the non-existing "dummy" variable to break out of the loop when 62 " going too far back. 63 call cursor(plnum, 1) 64 let parlnum = searchpair('(\|{\|\[', '', ')\|}\|\]', 'nbW', 65 \ "line('.') < " . (plnum - s:maxoff) . " ? dummy :" 66 \ . " synIDattr(synID(line('.'), col('.'), 1), 'name')" 67 \ . " =~ '\\(Comment\\|Todo\\|String\\)$'") 68 if parlnum > 0 69 let plindent = indent(parlnum) 70 let plnumstart = parlnum 71 else 72 let plindent = indent(plnum) 73 let plnumstart = plnum 74 endif 75 76 77 " When inside parenthesis: If at the first line below the parenthesis add 78 " a 'shiftwidth', otherwise same as previous line. 79 " i = (a 80 " + b 81 " + c) 82 call cursor(a:lnum, 1) 83 let p = searchpair('(\|{\|\[', '', ')\|}\|\]', 'bW', 84 \ "line('.') < " . (a:lnum - s:maxoff) . " ? dummy :" 85 \ . " synIDattr(synID(line('.'), col('.'), 1), 'name')" 86 \ . " =~ '\\(Comment\\|Todo\\|String\\)$'") 87 if p > 0 88 if p == plnum 89 " When the start is inside parenthesis, only indent one 'shiftwidth'. 90 let pp = searchpair('(\|{\|\[', '', ')\|}\|\]', 'bW', 91 \ "line('.') < " . (a:lnum - s:maxoff) . " ? dummy :" 92 \ . " synIDattr(synID(line('.'), col('.'), 1), 'name')" 93 \ . " =~ '\\(Comment\\|Todo\\|String\\)$'") 94 if pp > 0 95 return indent(plnum) + (exists("g:pyindent_nested_paren") ? eval(g:pyindent_nested_paren) : shiftwidth()) 96 endif 97 return indent(plnum) + (exists("g:pyindent_open_paren") ? eval(g:pyindent_open_paren) : shiftwidth()) 98 endif 99 if plnumstart == p 100 return indent(plnum) 101 endif 102 return plindent 103 endif 104 105 106 " Get the line and remove a trailing comment. 107 " Use syntax highlighting attributes when possible. 108 let pline = getline(plnum) 109 let pline_len = strlen(pline) 110 if has('syntax_items') 111 " If the last character in the line is a comment, do a binary search for 112 " the start of the comment. synID() is slow, a linear search would take 113 " too long on a long line. 114 if synIDattr(synID(plnum, pline_len, 1), "name") =~ "\\(Comment\\|Todo\\)$" 115 let min = 1 116 let max = pline_len 117 while min < max 118 let col = (min + max) / 2 119 if synIDattr(synID(plnum, col, 1), "name") =~ "\\(Comment\\|Todo\\)$" 120 let max = col 121 else 122 let min = col + 1 123 endif 124 endwhile 125 let pline = strpart(pline, 0, min - 1) 126 endif 127 else 128 let col = 0 129 while col < pline_len 130 if pline[col] == '#' 131 let pline = strpart(pline, 0, col) 132 break 133 endif 134 let col = col + 1 135 endwhile 136 endif 137 138 " If the previous line ended the conditional/loop 139 if getline(plnum) =~ '^\s*\(endif\|endforeach\)\>\s*' 140 " Maintain indent 141 return -1 142 endif 143 144 " If the previous line ended with a builtin, indent this line 145 if pline =~ '^\s*\(foreach\|if\|else\|elif\)\>\s*' 146 return plindent + shiftwidth() 147 endif 148 149 " If the current line begins with a header keyword, deindent 150 if getline(a:lnum) =~ '^\s*\(else\|elif\|endif\|endforeach\)' 151 152 " Unless the previous line was a one-liner 153 if getline(plnumstart) =~ '^\s*\(foreach\|if\)\>\s*' 154 return plindent 155 endif 156 157 " Or the user has already dedented 158 if indent(a:lnum) <= plindent - shiftwidth() 159 return -1 160 endif 161 162 return plindent - shiftwidth() 163 endif 164 165 " When after a () construct we probably want to go back to the start line. 166 " a = (b 167 " + c) 168 " here 169 if parlnum > 0 170 return plindent 171 endif 172 173 return -1 174 175endfunction 176 177let &cpo = s:keepcpo 178unlet s:keepcpo 179 180" vim:sw=2 181