view runtime/indent/fortran.vim @ 33947:f4d88db48a63 v9.0.2168

patch 9.0.2168: Moving tabpages on :drop may cause an endless loop Commit: https://github.com/vim/vim/commit/df12e39b8b9dd39056e22b452276622cb7b617fd Author: Christian Brabandt <cb@256bit.org> Date: Sat Dec 16 13:55:32 2023 +0100 patch 9.0.2168: Moving tabpages on :drop may cause an endless loop Problem: Moving tabpages on :drop may cause an endless loop Solution: Disallow moving tabpages on :drop when cleaning up the arglist first Moving tabpages during drop command may cause an endless loop When executing a :tab drop command, Vim will close all windows not in the argument list. This triggers various autocommands. If a user has created an 'au Tabenter * :tabmove -' autocommand, this can cause Vim to end up in an endless loop, when trying to iterate over all tabs (which would trigger the tabmove autocommand, which will change the tpnext pointer, etc). So instead of blocking all autocommands before we actually try to edit the given file, lets simply disallow to move tabpages around. Otherwise, we may change the expected number of events triggered during a :drop command, which users may rely on (there is actually a test, that expects various TabLeave/TabEnter autocommands) and would therefore be a backwards incompatible change. Don't make this an error, as this could trigger several times during the drop command, but silently ignore the :tabmove command in this case (and it should in fact finally trigger successfully when loading the given file in a new tab). So let's just be quiet here instead. fixes: #13676 closes: #13686 Signed-off-by: Christian Brabandt <cb@256bit.org>
author Christian Brabandt <cb@256bit.org>
date Sat, 16 Dec 2023 14:00:05 +0100
parents cf2ae76cbbf7
children 7bbae0fa2d7d
line wrap: on
line source

" Vim indent file
" Language:	Fortran 2008 (and Fortran 2003, 95, 90, and 77)
" Version:	(v49) 2023 December 1
" Maintainers:	Ajit J. Thakkar <ajit@unb.ca>; <https://ajit.ext.unb.ca/>
" 	        Joshua Hollett <j.hollett@uwinnipeg.ca>
" Usage:	For instructions, do :help fortran-indent from Vim
" Credits:
"  Version 0.1 was created in September 2000 by Ajit Thakkar.
"  Since then, useful suggestions and contributions have been made, in order, by:
"  Albert Oliver Serra, Takuya Fujiwara, Philipp Edelmann, Eisuke Kawashima,
"  Louis Cochen, and Doug Kearns.

" Only load this indent file when no other was loaded.
if exists("b:did_indent")
  finish
endif
let b:did_indent = 1

let s:cposet=&cpoptions
set cpoptions&vim
let b:undo_indent = "setl inde< indk<"

setlocal indentkeys+==~end,=~case,=~if,=~else,=~do,=~where,=~elsewhere,=~select
setlocal indentkeys+==~endif,=~enddo,=~endwhere,=~endselect,=~elseif
setlocal indentkeys+==~type,=~interface,=~forall,=~associate,=~block,=~enum
setlocal indentkeys+==~endforall,=~endassociate,=~endblock,=~endenum
if exists("b:fortran_indent_more") || exists("g:fortran_indent_more")
  setlocal indentkeys+==~function,=~subroutine,=~module,=~contains,=~program
  setlocal indentkeys+==~endfunction,=~endsubroutine,=~endmodule
  setlocal indentkeys+==~endprogram
endif

" Determine whether this is a fixed or free format source file
" if this hasn't been done yet using the priority:
" buffer-local value
" > global value
" > file extension as in Intel ifort, gcc (gfortran), NAG, Pathscale, and Cray compilers
if !exists("b:fortran_fixed_source")
  if exists("fortran_free_source")
    " User guarantees free source form
    let b:fortran_fixed_source = 0
  elseif exists("fortran_fixed_source")
    " User guarantees fixed source form
    let b:fortran_fixed_source = 1
  elseif expand("%:e") =~? '^f\%(90\|95\|03\|08\)$'
    " Free-form file extension defaults as in Intel ifort, gcc(gfortran), NAG, Pathscale, and Cray compilers
    let b:fortran_fixed_source = 0
  elseif expand("%:e") =~? '^\%(f\|f77\|for\)$'
    " Fixed-form file extension defaults
    let b:fortran_fixed_source = 1
  else
    " Modern fortran still allows both fixed and free source form
    " Assume fixed source form unless signs of free source form
    " are detected in the first five columns of the first s:lmax lines.
    " Detection becomes more accurate and time-consuming if more lines
    " are checked. Increase the limit below if you keep lots of comments at
    " the very top of each file and you have a fast computer.
    let s:lmax = 500
    if ( s:lmax > line("$") )
      let s:lmax = line("$")
    endif
    let b:fortran_fixed_source = 1
    let s:ln=1
    while s:ln <= s:lmax
      let s:test = strpart(getline(s:ln),0,5)
      if s:test !~ '^[Cc*]' && s:test !~ '^ *[!#]' && s:test =~ '[^ 0-9\t]' && s:test !~ '^[ 0-9]*\t'
	let b:fortran_fixed_source = 0
	break
      endif
      let s:ln = s:ln + 1
    endwhile
  endif
endif

" Define the appropriate indent function but only once
if (b:fortran_fixed_source == 1)
  setlocal indentexpr=FortranGetFixedIndent()
  if exists("*FortranGetFixedIndent")
    let &cpoptions = s:cposet
    unlet s:cposet
    finish
  endif
else
  setlocal indentexpr=FortranGetFreeIndent()
  if exists("*FortranGetFreeIndent")
    let &cpoptions = s:cposet
    unlet s:cposet
    finish
  endif
endif

function FortranGetIndent(lnum)
  let ind = indent(a:lnum)
  let prevline=getline(a:lnum)
  " Strip tail comment
  let prevstat=substitute(prevline, '!.*$', '', '')
  let prev2line=getline(a:lnum-1)
  let prev2stat=substitute(prev2line, '!.*$', '', '')

  "Indent do loops only if they are all guaranteed to be of do/end do type
  if exists("b:fortran_do_enddo") || exists("g:fortran_do_enddo")
    if prevstat =~? '^\s*\(\d\+\s\)\=\s*\(\a\w*\s*:\)\=\s*do\>'
      let ind = ind + shiftwidth()
    endif
    if getline(v:lnum) =~? '^\s*\(\d\+\s\)\=\s*end\s*do\>'
      let ind = ind - shiftwidth()
    endif
  endif

  "Add a shiftwidth to statements following if, else, else if, case, class,
  "where, else where, forall, type, interface and associate statements
  if prevstat =~? '^\s*\(case\|class\|else\|else\s*if\|else\s*where\)\>'
	\ ||prevstat=~? '^\s*\(type\|interface\|associate\|enum\)\>'
	\ ||prevstat=~?'^\s*\(\d\+\s\)\=\s*\(\a\w*\s*:\)\=\s*\(forall\|where\|block\)\>'
	\ ||prevstat=~? '^\s*\(\d\+\s\)\=\s*\(\a\w*\s*:\)\=\s*if\>'
     let ind = ind + shiftwidth()
    " Remove unwanted indent after logical and arithmetic ifs
    if prevstat =~? '\<if\>' && prevstat !~? '\<then\>'
      let ind = ind - shiftwidth()
    endif
    " Remove unwanted indent after type( statements
    if prevstat =~? '^\s*type\s*('
      let ind = ind - shiftwidth()
    endif
  endif

  "Indent program units unless instructed otherwise
  if !exists("b:fortran_indent_less") && !exists("g:fortran_indent_less")
    let prefix='\(\(pure\|impure\|elemental\|recursive\)\s\+\)\{,2}'
    let type='\(\(integer\|real\|double\s\+precision\|complex\|logical'
          \.'\|character\|type\|class\)\s*\S*\s\+\)\='
    if prevstat =~? '^\s*\(contains\|submodule\|program\)\>'
            \ ||prevstat =~? '^\s*'.'module\>\(\s*\procedure\)\@!'
            \ ||prevstat =~? '^\s*'.prefix.'subroutine\>'
            \ ||prevstat =~? '^\s*'.prefix.type.'function\>'
            \ ||prevstat =~? '^\s*'.type.prefix.'function\>'
      let ind = ind + shiftwidth()
    endif
    if getline(v:lnum) =~? '^\s*contains\>'
          \ ||getline(v:lnum)=~? '^\s*end\s*'
          \ .'\(function\|subroutine\|module\|submodule\|program\)\>'
      let ind = ind - shiftwidth()
    endif
  endif

  "Subtract a shiftwidth from else, else if, elsewhere, case, class, end if,
  " end where, end select, end forall, end interface, end associate,
  " end enum, end type, end block and end type statements
  if getline(v:lnum) =~? '^\s*\(\d\+\s\)\=\s*'
        \. '\(else\|else\s*if\|else\s*where\|case\|class\|'
        \. 'end\s*\(if\|where\|select\|interface\|'
        \. 'type\|forall\|associate\|enum\|block\)\)\>'
    let ind = ind - shiftwidth()
    " Fix indent for case statement immediately after select
    if prevstat =~? '\<select\s*\(case\|type\)\>'
      let ind = ind + shiftwidth()
    endif
  endif

  "First continuation line
  if prevstat =~ '&\s*$' && prev2stat !~ '&\s*$'
    let ind = ind + shiftwidth()
  endif
  "Line after last continuation line
  if prevstat !~ '&\s*$' && prev2stat =~ '&\s*$' && prevstat !~? '\<then\>'
    let ind = ind - shiftwidth()
  endif

  return ind
endfunction

function FortranGetFreeIndent()
  "Find the previous non-blank line
  let lnum = prevnonblank(v:lnum - 1)

  "Use zero indent at the top of the file
  if lnum == 0
    return 0
  endif

  let ind=FortranGetIndent(lnum)
  return ind
endfunction

function FortranGetFixedIndent()
  let currline=getline(v:lnum)
  "Don't indent comments, continuation lines and labelled lines
  if strpart(currline,0,6) =~ '[^ \t]'
    let ind = indent(v:lnum)
    return ind
  endif

  "Find the previous line which is not blank, not a comment,
  "not a continuation line, and does not have a label
  let lnum = v:lnum - 1
  while lnum > 0
    let prevline=getline(lnum)
    if (prevline =~ "^[C*!]") || (prevline =~ "^\s*$")
	\ || (strpart(prevline,5,1) !~ "[ 0]")
      " Skip comments, blank lines and continuation lines
      let lnum = lnum - 1
    else
      let test=strpart(prevline,0,5)
      if test =~ "[0-9]"
	" Skip lines with statement numbers
	let lnum = lnum - 1
      else
	break
      endif
    endif
  endwhile

  "First line must begin at column 7
  if lnum == 0
    return 6
  endif

  let ind=FortranGetIndent(lnum)
  return ind
endfunction

let &cpoptions = s:cposet
unlet s:cposet

" vim:sw=2 tw=130