gdscript.vim 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. " Vim indent file
  2. " Language: gdscript (Godot game engine)
  3. " Maintainer: Maxim Kim <habamax@gmail.com>
  4. " Based on python indent file.
  5. "
  6. " This file has been manually translated from Vim9 script.
  7. if exists("b:did_indent")
  8. finish
  9. endif
  10. let b:did_indent = 1
  11. let s:save_cpo = &cpo
  12. set cpo&vim
  13. let s:undo_opts = "setl indentexpr< indentkeys< lisp< autoindent<"
  14. if exists('b:undo_indent')
  15. let b:undo_indent ..= "|" .. s:undo_opts
  16. else
  17. let b:undo_indent = s:undo_opts
  18. endif
  19. setlocal nolisp
  20. setlocal autoindent
  21. setlocal indentexpr=s:GDScriptIndent()
  22. setlocal indentkeys+=<:>,=elif,=except
  23. function s:GDScriptIndent() abort
  24. " If this line is explicitly joined: If the previous line was also joined,
  25. " line it up with that one, otherwise add two 'shiftwidth'
  26. if getline(v:lnum - 1) =~# '\\$'
  27. if v:lnum > 1 && getline(v:lnum - 2) =~# '\\$'
  28. return indent(v:lnum - 1)
  29. endif
  30. return indent(v:lnum - 1) + (shiftwidth() * 2)
  31. endif
  32. " If the start of the line is in a string don't change the indent.
  33. if has('syntax_items') && synIDattr(synID(v:lnum, 1, 1), "name") =~# "String$"
  34. return -1
  35. endif
  36. " Search backwards for the previous non-empty line.
  37. let plnum = prevnonblank(v:lnum - 1)
  38. if plnum == 0
  39. " This is the first non-empty line, use zero indent.
  40. return 0
  41. endif
  42. let plindent = indent(plnum)
  43. let plnumstart = plnum
  44. " Get the line and remove a trailing comment.
  45. " Use syntax highlighting attributes when possible.
  46. let pline = getline(plnum)
  47. let pline_len = strlen(pline)
  48. if has('syntax_items')
  49. " If the last character in the line is a comment, do a binary search for
  50. " the start of the comment. synID() is slow, a linear search would take
  51. " too long on a long line.
  52. if synIDattr(synID(plnum, pline_len, 1), "name") =~# "\\(Comment\\|Todo\\)$"
  53. let min = 1
  54. let max = pline_len
  55. while min < max
  56. let col = (min + max) / 2
  57. if synIDattr(synID(plnum, col, 1), "name") =~# "\\(Comment\\|Todo\\)$"
  58. let max = col
  59. else
  60. let min = col + 1
  61. endif
  62. endwhile
  63. let pline = strpart(pline, 0, min - 1)
  64. endif
  65. else
  66. let col = 0
  67. while col < pline_len
  68. if pline[col] ==# '#'
  69. let pline = strpart(pline, 0, col)
  70. break
  71. endif
  72. let col = col + 1
  73. endwhile
  74. endif
  75. " When "inside" parenthesis: If at the first line below the parenthesis add
  76. " one 'shiftwidth' ("inside" is simplified and not really checked)
  77. " my_var = (
  78. " a
  79. " + b
  80. " + c
  81. " )
  82. if pline =~# '[({\[]\s*$'
  83. return indent(plnum) + shiftwidth()
  84. endif
  85. " If the previous line ended with a colon, indent this line
  86. if pline =~# ':\s*$'
  87. return plindent + shiftwidth()
  88. endif
  89. " If the previous line was a stop-execution statement...
  90. if getline(plnum) =~# '^\s*\(break\|continue\|raise\|return\|pass\)\>'
  91. " See if the user has already dedented
  92. if indent(v:lnum) > indent(plnum) - shiftwidth()
  93. " If not, recommend one dedent
  94. return indent(plnum) - shiftwidth()
  95. endif
  96. " Otherwise, trust the user
  97. return -1
  98. endif
  99. " If the current line begins with a keyword that lines up with "try"
  100. if getline(v:lnum) =~# '^\s*\(except\|finally\)\>'
  101. let lnum = v:lnum - 1
  102. while lnum >= 1
  103. if getline(lnum) =~# '^\s*\(try\|except\)\>'
  104. let ind = indent(lnum)
  105. if ind >= indent(v:lnum)
  106. return -1 " indent is already less than this
  107. endif
  108. return ind " line up with previous try or except
  109. endif
  110. let lnum = lnum - 1
  111. endwhile
  112. return -1 " no matching "try"!
  113. endif
  114. " If the current line begins with a header keyword, dedent
  115. if getline(v:lnum) =~# '^\s*\(elif\|else\)\>'
  116. " Unless the previous line was a one-liner
  117. if getline(plnumstart) =~# '^\s*\(for\|if\|try\)\>'
  118. return plindent
  119. endif
  120. " Or the user has already dedented
  121. if indent(v:lnum) <= plindent - shiftwidth()
  122. return -1
  123. endif
  124. return plindent - shiftwidth()
  125. endif
  126. return -1
  127. endfunction
  128. let &cpo = s:save_cpo
  129. unlet s:save_cpo