home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 5 Edit / 05-Edit.zip / vim60.zip / vim60rt2.zip / vim / vim60 / indent / ada.vim next >
Text File  |  2001-09-26  |  6KB  |  178 lines

  1. " Vim indent file
  2. " Language:    Ada
  3. " Maintainer:    Neil Bird <neil@fnxweb.com>
  4. " Last Change:    2001 Sep 02
  5. " Version:    $Id: ada.vim,v 1.10 2001/06/21 12:14:59 nabird Exp $
  6. "
  7. " ToDo:
  8. "  Verify handling of multi-line exprs. and recovery upon the final ';'.
  9. "  Correctly find comments given '"' and "" ==> " syntax.
  10.  
  11. " Only load this indent file when no other was loaded.
  12. if exists("b:did_indent")
  13.    finish
  14. endif
  15. let b:did_indent = 1
  16.  
  17. setlocal indentexpr=GetAdaIndent()
  18. setlocal indentkeys-=0{,0}
  19. setlocal indentkeys+=0=~then,0=~end,0=~elsif,0=~when,0=~exception,0=~begin,0=~is,0=~record
  20.  
  21. " Only define the functions once.
  22. if exists("*GetAdaIndent")
  23.    finish
  24. endif
  25.  
  26. let s:AdaBlockStart = '^\s*\(if\|while\|else\|elsif\|loop\|for\>.*\<loop\|declare\|begin\|record\|procedure\|function\|accept\|do\|task\|package\|then\|when\|is\)\>'
  27. let s:AdaComment = "\v^(\"[^\"]*\"|'.'|[^\"']){-}\zs\s*--.*"
  28.  
  29.  
  30. " Try to find indent of the block we're in (and about to complete)
  31. " prev_indent = the previous line's indent
  32. " prev_lnum   = previous line (to start looking on)
  33. " blockstart  = expr. that indicates a possible start of this block
  34. " No recursive previous block analysis: simply look for a valid line
  35. " with a lesser or equal indent than we currently (on prev_lnum) have.
  36. " This shouldn't work as well as it appears to with lines that are currently
  37. " nowhere near the correct indent (e.g., start of line)!
  38. " Seems to work OK as it 'starts' with the indent of the /previous/ line.
  39. function s:MainBlockIndent( prev_indent, prev_lnum, blockstart )
  40.    let lnum = a:prev_lnum
  41.    let line = getline(lnum)
  42.    while lnum > 1
  43.       if getline(lnum) =~ '^\s*' . a:blockstart
  44.      let ind = indent(lnum)
  45.      if ind <= a:prev_indent
  46.         return ind
  47.      endif
  48.       endif
  49.       let lnum = prevnonblank(lnum - 1)
  50.       " Get previous non-blank/non-comment-only line
  51.       while 1
  52.      let line = getline(lnum)
  53.      let line = substitute( line, s:AdaComment, '', '' )
  54.      if line !~ '^\s*$'
  55.         break
  56.      endif
  57.      let lnum = prevnonblank(lnum - 1)
  58.      if lnum <= 0
  59.         return a:prev_indent
  60.      endif
  61.       endwhile
  62.    endwhile
  63.    " Fallback - just move back one
  64.    return a:prev_indent - &sw
  65. endfunction
  66.  
  67.  
  68. " As per MainBlockIndent, but return indent of previous startement-start
  69. " (after we've indented due to multi-line statements).
  70. " This time, we start searching on the line *before* the one given (which is
  71. " the end of a statement - we want the previous beginning).
  72. function s:StatementIndent( current_indent, prev_lnum )
  73.    let lnum  = a:prev_lnum
  74.    while lnum > 0
  75.       let prev_lnum = lnum
  76.       let lnum = prevnonblank(lnum - 1)
  77.       " Get previous non-blank/non-comment-only line
  78.       while 1
  79.      let line = getline(lnum)
  80.      let line = substitute( line, s:AdaComment, '', '' )
  81.      if line !~ '^\s*$'
  82.         break
  83.      endif
  84.      let lnum = prevnonblank(lnum - 1)
  85.      if lnum <= 0
  86.         return a:current_indent
  87.      endif
  88.       endwhile
  89.       " Leave indent alone if our ';' line is part of a ';'-delineated
  90.       " aggregate (e.g., procedure args.) or first line after a block start.
  91.       if line =~ s:AdaBlockStart
  92.      return a:current_indent
  93.       endif
  94.       if line !~ '[.=(]\s*$'
  95.      let ind = indent(prev_lnum)
  96.      if ind < a:current_indent
  97.         return ind
  98.      endif
  99.       endif
  100.    endwhile
  101.    " Fallback - just use current one
  102.    return a:current_indent
  103. endfunction
  104.  
  105.  
  106. " Find correct indent of a new line based upon what went before
  107. function GetAdaIndent()
  108.    " Find a non-blank line above the current line.
  109.    let lnum = prevnonblank(v:lnum - 1)
  110.    let ind = indent(lnum)
  111.  
  112.    " Get previous non-blank/non-comment-only line
  113.    while 1
  114.       let line = getline(lnum)
  115.       let line = substitute( line, s:AdaComment, '', '' )
  116.       if line !~ '^\s*$'
  117.      break
  118.       endif
  119.       let lnum = prevnonblank(lnum - 1)
  120.       if lnum <= 0
  121.      return ind
  122.       endif
  123.    endwhile
  124.  
  125.    " Get default indent (from prev. line)
  126.    let ind = indent(lnum)
  127.  
  128.    " Now check what's on the previous line
  129.    if line =~ s:AdaBlockStart  ||  line =~ '(\s*$'
  130.       " Move indent in
  131.       let ind = ind + &sw
  132.    elseif line =~ '^\s*\(case\|exception\)\>'
  133.       " Move indent in twice (next 'when' will move back)
  134.       let ind = ind + 2 * &sw
  135.    elseif line =~ '^\s*end\s*record\>'
  136.       " Move indent back to tallying 'type' preceeding the 'record'.
  137.       let ind = s:MainBlockIndent( ind, lnum, 'type\>' )
  138.    elseif line =~ ')\s*[;,]\s*$'
  139.       " Revert to indent of line that started this parenthesis pair
  140.       let b:jobby = 'normal! ' . lnum . 'G$F)%'
  141.       exe 'normal! ' . lnum . 'G$F)%'
  142.       if getline('.') =~ '^\s*('
  143.      " Dire layout - use previous indent (could check for AdaComment here)
  144.      let ind = indent( prevnonblank( line('.')-1 ) )
  145.       else
  146.      let ind = indent('.')
  147.       endif
  148.       exe 'normal! ' . v:lnum . 'G'
  149.    elseif line =~ '[.=(]\s*$'
  150.       " A statement continuation - move in one
  151.       let ind = ind + &sw
  152.    elseif line =~ ';\s*$'
  153.       " Statement end - try to find current statement-start indent
  154.       let ind = s:StatementIndent( ind, lnum )
  155.    endif
  156.  
  157.    " Check current line; search for simplistic matching start-of-block
  158.    let line = getline(v:lnum)
  159.    if line =~ '^\s*\(begin\|is\)\>'
  160.       let ind = s:MainBlockIndent( ind, lnum, '\(procedure\|function\|declare\|package\|task\)\>' )
  161.    elseif line =~ '^\s*record\>'
  162.       let ind = s:MainBlockIndent( ind, lnum, 'type\>' ) + &sw
  163.    elseif line =~ '^\s*\(else\|elsif\)\>'
  164.       let ind = s:MainBlockIndent( ind, lnum, 'if\>' )
  165.    elseif line =~ '^\s*when\>'
  166.       " Align 'when' one /in/ from matching block start
  167.       let ind = s:MainBlockIndent( ind, lnum, '\(case\|exception\)\>' ) + &sw
  168.    elseif line =~ '^\s*end\>'
  169.       let ind = s:MainBlockIndent( ind, lnum, '\(if\|while\|loop\|accept\|begin\|record\)\>' )
  170.    elseif line =~ '^\s*exception\>'
  171.       let ind = s:MainBlockIndent( ind, lnum, 'begin\>' )
  172.    elseif line =~ '^\s*then\>'
  173.       let ind = s:MainBlockIndent( ind, lnum, 'if\>' )
  174.    endif
  175.  
  176.    return ind
  177. endfunction
  178.