gdscript.vim 4.3 KB

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