1*4882a593Smuzhiyun" Vim indent file 2*4882a593Smuzhiyun" Language: BitBake 3*4882a593Smuzhiyun" Copyright: Copyright (C) 2019 Agilent Technologies, Inc. 4*4882a593Smuzhiyun" Maintainer: Chris Laplante <chris.laplante@agilent.com> 5*4882a593Smuzhiyun" License: You may redistribute this under the same terms as Vim itself 6*4882a593Smuzhiyun 7*4882a593Smuzhiyun 8*4882a593Smuzhiyunif exists("b:did_indent") 9*4882a593Smuzhiyun finish 10*4882a593Smuzhiyunendif 11*4882a593Smuzhiyun 12*4882a593Smuzhiyunif exists("*BitbakeIndent") 13*4882a593Smuzhiyun finish 14*4882a593Smuzhiyunendif 15*4882a593Smuzhiyun 16*4882a593Smuzhiyunruntime! indent/sh.vim 17*4882a593Smuzhiyununlet b:did_indent 18*4882a593Smuzhiyun 19*4882a593Smuzhiyunsetlocal indentexpr=BitbakeIndent(v:lnum) 20*4882a593Smuzhiyunsetlocal autoindent nolisp 21*4882a593Smuzhiyun 22*4882a593Smuzhiyunfunction s:is_bb_python_func_def(lnum) 23*4882a593Smuzhiyun let stack = synstack(a:lnum, 1) 24*4882a593Smuzhiyun if len(stack) == 0 25*4882a593Smuzhiyun return 0 26*4882a593Smuzhiyun endif 27*4882a593Smuzhiyun 28*4882a593Smuzhiyun let top = synIDattr(stack[0], "name") 29*4882a593Smuzhiyun echo top 30*4882a593Smuzhiyun 31*4882a593Smuzhiyun return synIDattr(stack[0], "name") == "bbPyFuncDef" 32*4882a593Smuzhiyunendfunction 33*4882a593Smuzhiyun 34*4882a593Smuzhiyun"""" begin modified from indent/python.vim, upstream commit 7a9bd7c1e0ce1baf5a02daf36eeae3638aa315c7 35*4882a593Smuzhiyun"""" This copied code is licensed the same as Vim itself. 36*4882a593Smuzhiyunsetlocal indentkeys+=<:>,=elif,=except 37*4882a593Smuzhiyun 38*4882a593Smuzhiyunlet s:keepcpo= &cpo 39*4882a593Smuzhiyunset cpo&vim 40*4882a593Smuzhiyun 41*4882a593Smuzhiyunlet s:maxoff = 50 " maximum number of lines to look backwards for () 42*4882a593Smuzhiyun 43*4882a593Smuzhiyunfunction GetPythonIndent(lnum) 44*4882a593Smuzhiyun 45*4882a593Smuzhiyun " If this line is explicitly joined: If the previous line was also joined, 46*4882a593Smuzhiyun " line it up with that one, otherwise add two 'shiftwidth' 47*4882a593Smuzhiyun if getline(a:lnum - 1) =~ '\\$' 48*4882a593Smuzhiyun if a:lnum > 1 && getline(a:lnum - 2) =~ '\\$' 49*4882a593Smuzhiyun return indent(a:lnum - 1) 50*4882a593Smuzhiyun endif 51*4882a593Smuzhiyun return indent(a:lnum - 1) + (exists("g:pyindent_continue") ? eval(g:pyindent_continue) : (shiftwidth() * 2)) 52*4882a593Smuzhiyun endif 53*4882a593Smuzhiyun 54*4882a593Smuzhiyun " If the start of the line is in a string don't change the indent. 55*4882a593Smuzhiyun if has('syntax_items') 56*4882a593Smuzhiyun \ && synIDattr(synID(a:lnum, 1, 1), "name") =~ "String$" 57*4882a593Smuzhiyun return -1 58*4882a593Smuzhiyun endif 59*4882a593Smuzhiyun 60*4882a593Smuzhiyun " Search backwards for the previous non-empty line. 61*4882a593Smuzhiyun let plnum = prevnonblank(v:lnum - 1) 62*4882a593Smuzhiyun 63*4882a593Smuzhiyun if plnum == 0 64*4882a593Smuzhiyun " This is the first non-empty line, use zero indent. 65*4882a593Smuzhiyun return 0 66*4882a593Smuzhiyun endif 67*4882a593Smuzhiyun 68*4882a593Smuzhiyun call cursor(plnum, 1) 69*4882a593Smuzhiyun 70*4882a593Smuzhiyun " Identing inside parentheses can be very slow, regardless of the searchpair() 71*4882a593Smuzhiyun " timeout, so let the user disable this feature if he doesn't need it 72*4882a593Smuzhiyun let disable_parentheses_indenting = get(g:, "pyindent_disable_parentheses_indenting", 0) 73*4882a593Smuzhiyun 74*4882a593Smuzhiyun if disable_parentheses_indenting == 1 75*4882a593Smuzhiyun let plindent = indent(plnum) 76*4882a593Smuzhiyun let plnumstart = plnum 77*4882a593Smuzhiyun else 78*4882a593Smuzhiyun " searchpair() can be slow sometimes, limit the time to 150 msec or what is 79*4882a593Smuzhiyun " put in g:pyindent_searchpair_timeout 80*4882a593Smuzhiyun let searchpair_stopline = 0 81*4882a593Smuzhiyun let searchpair_timeout = get(g:, 'pyindent_searchpair_timeout', 150) 82*4882a593Smuzhiyun 83*4882a593Smuzhiyun " If the previous line is inside parenthesis, use the indent of the starting 84*4882a593Smuzhiyun " line. 85*4882a593Smuzhiyun " Trick: use the non-existing "dummy" variable to break out of the loop when 86*4882a593Smuzhiyun " going too far back. 87*4882a593Smuzhiyun let parlnum = searchpair('(\|{\|\[', '', ')\|}\|\]', 'nbW', 88*4882a593Smuzhiyun \ "line('.') < " . (plnum - s:maxoff) . " ? dummy :" 89*4882a593Smuzhiyun \ . " synIDattr(synID(line('.'), col('.'), 1), 'name')" 90*4882a593Smuzhiyun \ . " =~ '\\(Comment\\|Todo\\|String\\)$'", 91*4882a593Smuzhiyun \ searchpair_stopline, searchpair_timeout) 92*4882a593Smuzhiyun if parlnum > 0 93*4882a593Smuzhiyun " We may have found the opening brace of a BitBake Python task, e.g. 'python do_task {' 94*4882a593Smuzhiyun " If so, ignore it here - it will be handled later. 95*4882a593Smuzhiyun if s:is_bb_python_func_def(parlnum) 96*4882a593Smuzhiyun let parlnum = 0 97*4882a593Smuzhiyun let plindent = indent(plnum) 98*4882a593Smuzhiyun let plnumstart = plnum 99*4882a593Smuzhiyun else 100*4882a593Smuzhiyun let plindent = indent(parlnum) 101*4882a593Smuzhiyun let plnumstart = parlnum 102*4882a593Smuzhiyun endif 103*4882a593Smuzhiyun else 104*4882a593Smuzhiyun let plindent = indent(plnum) 105*4882a593Smuzhiyun let plnumstart = plnum 106*4882a593Smuzhiyun endif 107*4882a593Smuzhiyun 108*4882a593Smuzhiyun " When inside parenthesis: If at the first line below the parenthesis add 109*4882a593Smuzhiyun " two 'shiftwidth', otherwise same as previous line. 110*4882a593Smuzhiyun " i = (a 111*4882a593Smuzhiyun " + b 112*4882a593Smuzhiyun " + c) 113*4882a593Smuzhiyun call cursor(a:lnum, 1) 114*4882a593Smuzhiyun let p = searchpair('(\|{\|\[', '', ')\|}\|\]', 'bW', 115*4882a593Smuzhiyun \ "line('.') < " . (a:lnum - s:maxoff) . " ? dummy :" 116*4882a593Smuzhiyun \ . " synIDattr(synID(line('.'), col('.'), 1), 'name')" 117*4882a593Smuzhiyun \ . " =~ '\\(Comment\\|Todo\\|String\\)$'", 118*4882a593Smuzhiyun \ searchpair_stopline, searchpair_timeout) 119*4882a593Smuzhiyun if p > 0 120*4882a593Smuzhiyun if s:is_bb_python_func_def(p) 121*4882a593Smuzhiyun " Handle first non-empty line inside a BB Python task 122*4882a593Smuzhiyun if p == plnum 123*4882a593Smuzhiyun return shiftwidth() 124*4882a593Smuzhiyun endif 125*4882a593Smuzhiyun 126*4882a593Smuzhiyun " Handle the user actually trying to close a BitBake Python task 127*4882a593Smuzhiyun let line = getline(a:lnum) 128*4882a593Smuzhiyun if line =~ '^\s*}' 129*4882a593Smuzhiyun return -2 130*4882a593Smuzhiyun endif 131*4882a593Smuzhiyun 132*4882a593Smuzhiyun " Otherwise ignore the brace 133*4882a593Smuzhiyun let p = 0 134*4882a593Smuzhiyun else 135*4882a593Smuzhiyun if p == plnum 136*4882a593Smuzhiyun " When the start is inside parenthesis, only indent one 'shiftwidth'. 137*4882a593Smuzhiyun let pp = searchpair('(\|{\|\[', '', ')\|}\|\]', 'bW', 138*4882a593Smuzhiyun \ "line('.') < " . (a:lnum - s:maxoff) . " ? dummy :" 139*4882a593Smuzhiyun \ . " synIDattr(synID(line('.'), col('.'), 1), 'name')" 140*4882a593Smuzhiyun \ . " =~ '\\(Comment\\|Todo\\|String\\)$'", 141*4882a593Smuzhiyun \ searchpair_stopline, searchpair_timeout) 142*4882a593Smuzhiyun if pp > 0 143*4882a593Smuzhiyun return indent(plnum) + (exists("g:pyindent_nested_paren") ? eval(g:pyindent_nested_paren) : shiftwidth()) 144*4882a593Smuzhiyun endif 145*4882a593Smuzhiyun return indent(plnum) + (exists("g:pyindent_open_paren") ? eval(g:pyindent_open_paren) : (shiftwidth() * 2)) 146*4882a593Smuzhiyun endif 147*4882a593Smuzhiyun if plnumstart == p 148*4882a593Smuzhiyun return indent(plnum) 149*4882a593Smuzhiyun endif 150*4882a593Smuzhiyun return plindent 151*4882a593Smuzhiyun endif 152*4882a593Smuzhiyun endif 153*4882a593Smuzhiyun 154*4882a593Smuzhiyun endif 155*4882a593Smuzhiyun 156*4882a593Smuzhiyun 157*4882a593Smuzhiyun " Get the line and remove a trailing comment. 158*4882a593Smuzhiyun " Use syntax highlighting attributes when possible. 159*4882a593Smuzhiyun let pline = getline(plnum) 160*4882a593Smuzhiyun let pline_len = strlen(pline) 161*4882a593Smuzhiyun if has('syntax_items') 162*4882a593Smuzhiyun " If the last character in the line is a comment, do a binary search for 163*4882a593Smuzhiyun " the start of the comment. synID() is slow, a linear search would take 164*4882a593Smuzhiyun " too long on a long line. 165*4882a593Smuzhiyun if synIDattr(synID(plnum, pline_len, 1), "name") =~ "\\(Comment\\|Todo\\)$" 166*4882a593Smuzhiyun let min = 1 167*4882a593Smuzhiyun let max = pline_len 168*4882a593Smuzhiyun while min < max 169*4882a593Smuzhiyun let col = (min + max) / 2 170*4882a593Smuzhiyun if synIDattr(synID(plnum, col, 1), "name") =~ "\\(Comment\\|Todo\\)$" 171*4882a593Smuzhiyun let max = col 172*4882a593Smuzhiyun else 173*4882a593Smuzhiyun let min = col + 1 174*4882a593Smuzhiyun endif 175*4882a593Smuzhiyun endwhile 176*4882a593Smuzhiyun let pline = strpart(pline, 0, min - 1) 177*4882a593Smuzhiyun endif 178*4882a593Smuzhiyun else 179*4882a593Smuzhiyun let col = 0 180*4882a593Smuzhiyun while col < pline_len 181*4882a593Smuzhiyun if pline[col] == '#' 182*4882a593Smuzhiyun let pline = strpart(pline, 0, col) 183*4882a593Smuzhiyun break 184*4882a593Smuzhiyun endif 185*4882a593Smuzhiyun let col = col + 1 186*4882a593Smuzhiyun endwhile 187*4882a593Smuzhiyun endif 188*4882a593Smuzhiyun 189*4882a593Smuzhiyun " If the previous line ended with a colon, indent this line 190*4882a593Smuzhiyun if pline =~ ':\s*$' 191*4882a593Smuzhiyun return plindent + shiftwidth() 192*4882a593Smuzhiyun endif 193*4882a593Smuzhiyun 194*4882a593Smuzhiyun " If the previous line was a stop-execution statement... 195*4882a593Smuzhiyun " TODO: utilize this logic to deindent when ending a bbPyDefRegion 196*4882a593Smuzhiyun if getline(plnum) =~ '^\s*\(break\|continue\|raise\|return\|pass\|bb\.fatal\)\>' 197*4882a593Smuzhiyun " See if the user has already dedented 198*4882a593Smuzhiyun if indent(a:lnum) > indent(plnum) - shiftwidth() 199*4882a593Smuzhiyun " If not, recommend one dedent 200*4882a593Smuzhiyun return indent(plnum) - shiftwidth() 201*4882a593Smuzhiyun endif 202*4882a593Smuzhiyun " Otherwise, trust the user 203*4882a593Smuzhiyun return -1 204*4882a593Smuzhiyun endif 205*4882a593Smuzhiyun 206*4882a593Smuzhiyun " If the current line begins with a keyword that lines up with "try" 207*4882a593Smuzhiyun if getline(a:lnum) =~ '^\s*\(except\|finally\)\>' 208*4882a593Smuzhiyun let lnum = a:lnum - 1 209*4882a593Smuzhiyun while lnum >= 1 210*4882a593Smuzhiyun if getline(lnum) =~ '^\s*\(try\|except\)\>' 211*4882a593Smuzhiyun let ind = indent(lnum) 212*4882a593Smuzhiyun if ind >= indent(a:lnum) 213*4882a593Smuzhiyun return -1 " indent is already less than this 214*4882a593Smuzhiyun endif 215*4882a593Smuzhiyun return ind " line up with previous try or except 216*4882a593Smuzhiyun endif 217*4882a593Smuzhiyun let lnum = lnum - 1 218*4882a593Smuzhiyun endwhile 219*4882a593Smuzhiyun return -1 " no matching "try"! 220*4882a593Smuzhiyun endif 221*4882a593Smuzhiyun 222*4882a593Smuzhiyun " If the current line begins with a header keyword, dedent 223*4882a593Smuzhiyun if getline(a:lnum) =~ '^\s*\(elif\|else\)\>' 224*4882a593Smuzhiyun 225*4882a593Smuzhiyun " Unless the previous line was a one-liner 226*4882a593Smuzhiyun if getline(plnumstart) =~ '^\s*\(for\|if\|try\)\>' 227*4882a593Smuzhiyun return plindent 228*4882a593Smuzhiyun endif 229*4882a593Smuzhiyun 230*4882a593Smuzhiyun " Or the user has already dedented 231*4882a593Smuzhiyun if indent(a:lnum) <= plindent - shiftwidth() 232*4882a593Smuzhiyun return -1 233*4882a593Smuzhiyun endif 234*4882a593Smuzhiyun 235*4882a593Smuzhiyun return plindent - shiftwidth() 236*4882a593Smuzhiyun endif 237*4882a593Smuzhiyun 238*4882a593Smuzhiyun " When after a () construct we probably want to go back to the start line. 239*4882a593Smuzhiyun " a = (b 240*4882a593Smuzhiyun " + c) 241*4882a593Smuzhiyun " here 242*4882a593Smuzhiyun if parlnum > 0 243*4882a593Smuzhiyun return plindent 244*4882a593Smuzhiyun endif 245*4882a593Smuzhiyun 246*4882a593Smuzhiyun return -1 247*4882a593Smuzhiyun 248*4882a593Smuzhiyunendfunction 249*4882a593Smuzhiyun 250*4882a593Smuzhiyunlet &cpo = s:keepcpo 251*4882a593Smuzhiyununlet s:keepcpo 252*4882a593Smuzhiyun 253*4882a593Smuzhiyun""" end of stuff from indent/python.vim 254*4882a593Smuzhiyun 255*4882a593Smuzhiyun 256*4882a593Smuzhiyunlet b:did_indent = 1 257*4882a593Smuzhiyunsetlocal indentkeys+=0\" 258*4882a593Smuzhiyun 259*4882a593Smuzhiyun 260*4882a593Smuzhiyunfunction BitbakeIndent(lnum) 261*4882a593Smuzhiyun if !has('syntax_items') 262*4882a593Smuzhiyun return -1 263*4882a593Smuzhiyun endif 264*4882a593Smuzhiyun 265*4882a593Smuzhiyun let stack = synstack(a:lnum, 1) 266*4882a593Smuzhiyun if len(stack) == 0 267*4882a593Smuzhiyun return -1 268*4882a593Smuzhiyun endif 269*4882a593Smuzhiyun 270*4882a593Smuzhiyun let name = synIDattr(stack[0], "name") 271*4882a593Smuzhiyun 272*4882a593Smuzhiyun " TODO: support different styles of indentation for assignments. For now, 273*4882a593Smuzhiyun " we only support like this: 274*4882a593Smuzhiyun " VAR = " \ 275*4882a593Smuzhiyun " value1 \ 276*4882a593Smuzhiyun " value2 \ 277*4882a593Smuzhiyun " " 278*4882a593Smuzhiyun " 279*4882a593Smuzhiyun " i.e. each value indented by shiftwidth(), with the final quote " completely unindented. 280*4882a593Smuzhiyun if name == "bbVarValue" 281*4882a593Smuzhiyun " Quote handling is tricky. kernel.bbclass has this line for instance: 282*4882a593Smuzhiyun " EXTRA_OEMAKE = " HOSTCC="${BUILD_CC} ${BUILD_CFLAGS} ${BUILD_LDFLAGS}" " HOSTCPP="${BUILD_CPP}"" 283*4882a593Smuzhiyun " Instead of trying to handle crazy cases like that, just assume that a 284*4882a593Smuzhiyun " double-quote on a line by itself (following an assignment) means the 285*4882a593Smuzhiyun " user is closing the assignment, and de-dent. 286*4882a593Smuzhiyun if getline(a:lnum) =~ '^\s*"$' 287*4882a593Smuzhiyun return 0 288*4882a593Smuzhiyun endif 289*4882a593Smuzhiyun 290*4882a593Smuzhiyun let prevstack = synstack(a:lnum - 1, 1) 291*4882a593Smuzhiyun if len(prevstack) == 0 292*4882a593Smuzhiyun return -1 293*4882a593Smuzhiyun endif 294*4882a593Smuzhiyun 295*4882a593Smuzhiyun let prevname = synIDattr(prevstack[0], "name") 296*4882a593Smuzhiyun 297*4882a593Smuzhiyun " Only indent if there was actually a continuation character on 298*4882a593Smuzhiyun " the previous line, to avoid misleading indentation. 299*4882a593Smuzhiyun let prevlinelastchar = synIDattr(synID(a:lnum - 1, col([a:lnum - 1, "$"]) - 1, 1), "name") 300*4882a593Smuzhiyun let prev_continued = prevlinelastchar == "bbContinue" 301*4882a593Smuzhiyun 302*4882a593Smuzhiyun " Did the previous line introduce an assignment? 303*4882a593Smuzhiyun if index(["bbVarDef", "bbVarFlagDef"], prevname) != -1 304*4882a593Smuzhiyun if prev_continued 305*4882a593Smuzhiyun return shiftwidth() 306*4882a593Smuzhiyun endif 307*4882a593Smuzhiyun endif 308*4882a593Smuzhiyun 309*4882a593Smuzhiyun if !prev_continued 310*4882a593Smuzhiyun return 0 311*4882a593Smuzhiyun endif 312*4882a593Smuzhiyun 313*4882a593Smuzhiyun " Autoindent can take it from here 314*4882a593Smuzhiyun return -1 315*4882a593Smuzhiyun endif 316*4882a593Smuzhiyun 317*4882a593Smuzhiyun if index(["bbPyDefRegion", "bbPyFuncRegion"], name) != -1 318*4882a593Smuzhiyun let ret = GetPythonIndent(a:lnum) 319*4882a593Smuzhiyun " Should normally always be indented by at least one shiftwidth; but allow 320*4882a593Smuzhiyun " return of -1 (defer to autoindent) or -2 (force indent to 0) 321*4882a593Smuzhiyun if ret == 0 322*4882a593Smuzhiyun return shiftwidth() 323*4882a593Smuzhiyun elseif ret == -2 324*4882a593Smuzhiyun return 0 325*4882a593Smuzhiyun endif 326*4882a593Smuzhiyun return ret 327*4882a593Smuzhiyun endif 328*4882a593Smuzhiyun 329*4882a593Smuzhiyun " TODO: GetShIndent doesn't detect tasks prepended with 'fakeroot' 330*4882a593Smuzhiyun " Need to submit a patch upstream to Vim to provide an extension point. 331*4882a593Smuzhiyun " Unlike the Python indenter, the Sh indenter is way too large to copy and 332*4882a593Smuzhiyun " modify here. 333*4882a593Smuzhiyun if name == "bbShFuncRegion" 334*4882a593Smuzhiyun return GetShIndent() 335*4882a593Smuzhiyun endif 336*4882a593Smuzhiyun 337*4882a593Smuzhiyun " TODO: 338*4882a593Smuzhiyun " + heuristics for de-denting out of a bbPyDefRegion? e.g. when the user 339*4882a593Smuzhiyun " types an obvious BB keyword like addhandler or addtask, or starts 340*4882a593Smuzhiyun " writing a shell task. Maybe too hard to implement... 341*4882a593Smuzhiyun 342*4882a593Smuzhiyun return -1 343*4882a593Smuzhiyunendfunction 344