fortran.vim 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219
  1. " Vim indent file
  2. " Language: Fortran 2008 (and older: Fortran 2003, 95, 90, and 77)
  3. " Version: 47
  4. " Last Change: 2016 Oct. 29
  5. " Maintainer: Ajit J. Thakkar <ajit@unb.ca>; <http://www2.unb.ca/~ajit/>
  6. " Usage: For instructions, do :help fortran-indent from Vim
  7. " Credits:
  8. " Useful suggestions were made, in chronological order, by:
  9. " Albert Oliver Serra, Takuya Fujiwara and Philipp Edelmann.
  10. " Only load this indent file when no other was loaded.
  11. if exists("b:did_indent")
  12. finish
  13. endif
  14. let b:did_indent = 1
  15. let s:cposet=&cpoptions
  16. set cpoptions&vim
  17. setlocal indentkeys+==~end,=~case,=~if,=~else,=~do,=~where,=~elsewhere,=~select
  18. setlocal indentkeys+==~endif,=~enddo,=~endwhere,=~endselect,=~elseif
  19. setlocal indentkeys+==~type,=~interface,=~forall,=~associate,=~block,=~enum
  20. setlocal indentkeys+==~endforall,=~endassociate,=~endblock,=~endenum
  21. if exists("b:fortran_indent_more") || exists("g:fortran_indent_more")
  22. setlocal indentkeys+==~function,=~subroutine,=~module,=~contains,=~program
  23. setlocal indentkeys+==~endfunction,=~endsubroutine,=~endmodule
  24. setlocal indentkeys+==~endprogram
  25. endif
  26. " Determine whether this is a fixed or free format source file
  27. " if this hasn't been done yet using the priority:
  28. " buffer-local value
  29. " > global value
  30. " > file extension as in Intel ifort, gcc (gfortran), NAG, Pathscale, and Cray compilers
  31. if !exists("b:fortran_fixed_source")
  32. if exists("fortran_free_source")
  33. " User guarantees free source form
  34. let b:fortran_fixed_source = 0
  35. elseif exists("fortran_fixed_source")
  36. " User guarantees fixed source form
  37. let b:fortran_fixed_source = 1
  38. elseif expand("%:e") ==? "f\<90\|95\|03\|08\>"
  39. " Free-form file extension defaults as in Intel ifort, gcc(gfortran), NAG, Pathscale, and Cray compilers
  40. let b:fortran_fixed_source = 0
  41. elseif expand("%:e") ==? "f\|f77\|for"
  42. " Fixed-form file extension defaults
  43. let b:fortran_fixed_source = 1
  44. else
  45. " Modern fortran still allows both fixed and free source form
  46. " Assume fixed source form unless signs of free source form
  47. " are detected in the first five columns of the first s:lmax lines.
  48. " Detection becomes more accurate and time-consuming if more lines
  49. " are checked. Increase the limit below if you keep lots of comments at
  50. " the very top of each file and you have a fast computer.
  51. let s:lmax = 500
  52. if ( s:lmax > line("$") )
  53. let s:lmax = line("$")
  54. endif
  55. let b:fortran_fixed_source = 1
  56. let s:ln=1
  57. while s:ln <= s:lmax
  58. let s:test = strpart(getline(s:ln),0,5)
  59. if s:test !~ '^[Cc*]' && s:test !~ '^ *[!#]' && s:test =~ '[^ 0-9\t]' && s:test !~ '^[ 0-9]*\t'
  60. let b:fortran_fixed_source = 0
  61. break
  62. endif
  63. let s:ln = s:ln + 1
  64. endwhile
  65. endif
  66. endif
  67. " Define the appropriate indent function but only once
  68. if (b:fortran_fixed_source == 1)
  69. setlocal indentexpr=FortranGetFixedIndent()
  70. if exists("*FortranGetFixedIndent")
  71. finish
  72. endif
  73. else
  74. setlocal indentexpr=FortranGetFreeIndent()
  75. if exists("*FortranGetFreeIndent")
  76. finish
  77. endif
  78. endif
  79. function FortranGetIndent(lnum)
  80. let ind = indent(a:lnum)
  81. let prevline=getline(a:lnum)
  82. " Strip tail comment
  83. let prevstat=substitute(prevline, '!.*$', '', '')
  84. let prev2line=getline(a:lnum-1)
  85. let prev2stat=substitute(prev2line, '!.*$', '', '')
  86. "Indent do loops only if they are all guaranteed to be of do/end do type
  87. if exists("b:fortran_do_enddo") || exists("g:fortran_do_enddo")
  88. if prevstat =~? '^\s*\(\d\+\s\)\=\s*\(\a\w*\s*:\)\=\s*do\>'
  89. let ind = ind + shiftwidth()
  90. endif
  91. if getline(v:lnum) =~? '^\s*\(\d\+\s\)\=\s*end\s*do\>'
  92. let ind = ind - shiftwidth()
  93. endif
  94. endif
  95. "Add a shiftwidth to statements following if, else, else if, case, class,
  96. "where, else where, forall, type, interface and associate statements
  97. if prevstat =~? '^\s*\(case\|class\|else\|else\s*if\|else\s*where\)\>'
  98. \ ||prevstat=~? '^\s*\(type\|interface\|associate\|enum\)\>'
  99. \ ||prevstat=~?'^\s*\(\d\+\s\)\=\s*\(\a\w*\s*:\)\=\s*\(forall\|where\|block\)\>'
  100. \ ||prevstat=~? '^\s*\(\d\+\s\)\=\s*\(\a\w*\s*:\)\=\s*if\>'
  101. let ind = ind + shiftwidth()
  102. " Remove unwanted indent after logical and arithmetic ifs
  103. if prevstat =~? '\<if\>' && prevstat !~? '\<then\>'
  104. let ind = ind - shiftwidth()
  105. endif
  106. " Remove unwanted indent after type( statements
  107. if prevstat =~? '^\s*type\s*('
  108. let ind = ind - shiftwidth()
  109. endif
  110. endif
  111. "Indent program units unless instructed otherwise
  112. if !exists("b:fortran_indent_less") && !exists("g:fortran_indent_less")
  113. let prefix='\(\(pure\|impure\|elemental\|recursive\)\s\+\)\{,2}'
  114. let type='\(\(integer\|real\|double\s\+precision\|complex\|logical'
  115. \.'\|character\|type\|class\)\s*\S*\s\+\)\='
  116. if prevstat =~? '^\s*\(contains\|submodule\|program\)\>'
  117. \ ||prevstat =~? '^\s*'.'module\>\(\s*\procedure\)\@!'
  118. \ ||prevstat =~? '^\s*'.prefix.'subroutine\>'
  119. \ ||prevstat =~? '^\s*'.prefix.type.'function\>'
  120. \ ||prevstat =~? '^\s*'.type.prefix.'function\>'
  121. let ind = ind + shiftwidth()
  122. endif
  123. if getline(v:lnum) =~? '^\s*contains\>'
  124. \ ||getline(v:lnum)=~? '^\s*end\s*'
  125. \ .'\(function\|subroutine\|module\|submodule\|program\)\>'
  126. let ind = ind - shiftwidth()
  127. endif
  128. endif
  129. "Subtract a shiftwidth from else, else if, elsewhere, case, class, end if,
  130. " end where, end select, end forall, end interface, end associate,
  131. " end enum, end type, end block and end type statements
  132. if getline(v:lnum) =~? '^\s*\(\d\+\s\)\=\s*'
  133. \. '\(else\|else\s*if\|else\s*where\|case\|class\|'
  134. \. 'end\s*\(if\|where\|select\|interface\|'
  135. \. 'type\|forall\|associate\|enum\|block\)\)\>'
  136. let ind = ind - shiftwidth()
  137. " Fix indent for case statement immediately after select
  138. if prevstat =~? '\<select\s\+\(case\|type\)\>'
  139. let ind = ind + shiftwidth()
  140. endif
  141. endif
  142. "First continuation line
  143. if prevstat =~ '&\s*$' && prev2stat !~ '&\s*$'
  144. let ind = ind + shiftwidth()
  145. endif
  146. "Line after last continuation line
  147. if prevstat !~ '&\s*$' && prev2stat =~ '&\s*$' && prevstat !~? '\<then\>'
  148. let ind = ind - shiftwidth()
  149. endif
  150. return ind
  151. endfunction
  152. function FortranGetFreeIndent()
  153. "Find the previous non-blank line
  154. let lnum = prevnonblank(v:lnum - 1)
  155. "Use zero indent at the top of the file
  156. if lnum == 0
  157. return 0
  158. endif
  159. let ind=FortranGetIndent(lnum)
  160. return ind
  161. endfunction
  162. function FortranGetFixedIndent()
  163. let currline=getline(v:lnum)
  164. "Don't indent comments, continuation lines and labelled lines
  165. if strpart(currline,0,6) =~ '[^ \t]'
  166. let ind = indent(v:lnum)
  167. return ind
  168. endif
  169. "Find the previous line which is not blank, not a comment,
  170. "not a continuation line, and does not have a label
  171. let lnum = v:lnum - 1
  172. while lnum > 0
  173. let prevline=getline(lnum)
  174. if (prevline =~ "^[C*!]") || (prevline =~ "^\s*$")
  175. \ || (strpart(prevline,5,1) !~ "[ 0]")
  176. " Skip comments, blank lines and continuation lines
  177. let lnum = lnum - 1
  178. else
  179. let test=strpart(prevline,0,5)
  180. if test =~ "[0-9]"
  181. " Skip lines with statement numbers
  182. let lnum = lnum - 1
  183. else
  184. break
  185. endif
  186. endif
  187. endwhile
  188. "First line must begin at column 7
  189. if lnum == 0
  190. return 6
  191. endif
  192. let ind=FortranGetIndent(lnum)
  193. return ind
  194. endfunction
  195. let &cpoptions=s:cposet
  196. unlet s:cposet
  197. " vim:sw=2 tw=130