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