home *** CD-ROM | disk | FTP | other *** search
/ vim.ftp.fu-berlin.de / 2015-02-03.vim.ftp.fu-berlin.de.tar / vim.ftp.fu-berlin.de / unix / vim-6.2.tar.bz2 / vim-6.2.tar / vim62 / runtime / indent / awk.vim < prev    next >
Encoding:
Text File  |  2003-05-11  |  7.5 KB  |  229 lines

  1. "  vim: set sw=3 sts=3:
  2.  
  3. " Awk indent script. It can handle multi-line statements and expressions.
  4. " It works up to the point where the distinction between correct/incorrect
  5. " and personal taste gets fuzzy. Drop me an e-mail for bug reports and
  6. " reasonable style suggestions.
  7. "
  8. " Bugs:
  9. " =====
  10. " - Some syntax errors may cause erratic indentation.
  11. " - Same for very unusual but syntacticly correct use of { }
  12. " - In some cases it's confused by the use of ( and { in strings constants
  13. " - This version likes the closing brace of a multiline pattern-action be on
  14. "   character position 1 before the following pattern-action combination is
  15. "   formatted
  16.  
  17. " Author:
  18. " =======
  19. " Erik Janssen, ejanssen@itmatters.nl
  20. "
  21. " History:
  22. " ========
  23. " 26-04-2002 Got initial version working reasonably well
  24. " 29-04-2002 Fixed problems in function headers and max line width
  25. "         Added support for two-line if's without curly braces
  26.  
  27. " Only load this indent file when no other was loaded.
  28. if exists("b:did_indent")
  29.     finish
  30. endif
  31.  
  32. let b:did_indent = 1
  33.  
  34. setlocal indentexpr=GetAwkIndent()
  35. " Mmm, copied from the tcl indent program. Is this okay?
  36. setlocal indentkeys-=:,0#
  37.  
  38. " Only define the function once.
  39. if exists("*GetAwkIndent")
  40.     finish
  41. endif
  42.  
  43. " This function contains a lot of exit points. It checks for simple cases
  44. " first to get out of the function as soon as possible, thereby reducing the
  45. " number of possibilities later on in the difficult parts
  46.  
  47. function! GetAwkIndent()
  48.  
  49.    " Find previous line and get it's indentation
  50.    let prev_lineno = s:Get_prev_line( v:lnum )
  51.    if prev_lineno == 0
  52.       return 0
  53.    endif
  54.    let prev_data = getline( prev_lineno )
  55.    let ind = indent( prev_lineno )
  56.  
  57.    " Increase indent if the previous line contains an opening brace. Search
  58.    " for this brace the hard way to prevent errors if the previous line is a
  59.    " 'pattern { action }' (simple check match on /{/ increases the indent then)
  60.  
  61.    if s:Get_brace_balance( prev_data, '{', '}' ) > 0
  62.       return ind + &sw
  63.    endif
  64.  
  65.    let brace_balance = s:Get_brace_balance( prev_data, '(', ')' )
  66.  
  67.    " If prev line has positive brace_balance and starts with a word (keyword
  68.    " or function name), align the current line on the first '(' of the prev
  69.    " line
  70.  
  71.    if brace_balance > 0 && s:Starts_with_word( prev_data )
  72.       return s:Safe_indent( ind, s:First_word_len(prev_data), getline(v:lnum))
  73.    endif
  74.  
  75.    " If this line starts with an open brace bail out now before the line
  76.    " continuation checks.
  77.  
  78.    if getline( v:lnum ) =~ '^\s*{'
  79.       return ind
  80.    endif
  81.  
  82.    " If prev line seems to be part of multiline statement:
  83.    " 1. Prev line is first line of a multiline statement
  84.    "    -> attempt to indent on first ' ' or '(' of prev line, just like we
  85.    "       indented the positive brace balance case above
  86.    " 2. Prev line is not first line of a multiline statement
  87.    "    -> copy indent of prev line
  88.  
  89.    let continue_mode = s:Seems_continuing( prev_data )
  90.    if continue_mode > 0
  91.      if s:Seems_continuing( getline(s:Get_prev_line( prev_lineno )) )
  92.        " Case 2
  93.        return ind
  94.      else
  95.        " Case 1
  96.        if continue_mode == 1
  97.       " Need continuation due to comma, backslash, etc
  98.       return s:Safe_indent( ind, s:First_word_len(prev_data), getline(v:lnum))
  99.        else
  100.      " if/for/while without '{'
  101.      return ind + &sw
  102.        endif
  103.      endif
  104.    endif
  105.  
  106.    " If the previous line doesn't need continuation on the current line we are
  107.    " on the start of a new statement.  We have to make sure we align with the
  108.    " previous statement instead of just the previous line. This is a bit
  109.    " complicated because the previous statement might be multi-line.
  110.    "
  111.    " The start of a multiline statement can be found by:
  112.    "
  113.    " 1 If the previous line contains closing braces and has negative brace
  114.    "   balance, search backwards until cumulative brace balance becomes zero,
  115.    "   take indent of that line
  116.    " 2 If the line before the previous needs continuation search backward
  117.    "   until that's not the case anymore. Take indent of one line down.
  118.  
  119.    " Case 1
  120.    if prev_data =~ ')' && brace_balance < 0
  121.       while brace_balance != 0
  122.      let prev_lineno = s:Get_prev_line( prev_lineno )
  123.      let prev_data = getline( prev_lineno )
  124.      let brace_balance=brace_balance+s:Get_brace_balance(prev_data,'(',')' )
  125.       endwhile
  126.       let ind = indent( prev_lineno )
  127.    else
  128.       " Case 2
  129.       if s:Seems_continuing( getline( prev_lineno - 1 ) )
  130.      let prev_lineno = prev_lineno - 2
  131.      let prev_data = getline( prev_lineno )
  132.      while prev_lineno > 0 && (s:Seems_continuing( prev_data ) > 0)
  133.         let prev_lineno = s:Get_prev_line( prev_lineno )
  134.         let prev_data = getline( prev_lineno )
  135.      endwhile
  136.      let ind = indent( prev_lineno + 1 )
  137.       endif
  138.    endif
  139.  
  140.    " Decrease indent if this line contains a '}'.
  141.    if getline(v:lnum) =~ '^\s*}'
  142.       let ind = ind - &sw
  143.    endif
  144.  
  145.    return ind
  146. endfunction
  147.  
  148. " Find the open and close braces in this line and return how many more open-
  149. " than close braces there are. It's also used to determine cumulative balance
  150. " across multiple lines.
  151.  
  152. function! s:Get_brace_balance( line, b_open, b_close )
  153.    let line2 = substitute( a:line, a:b_open, "", "g" )
  154.    let openb = strlen( a:line ) - strlen( line2 )
  155.    let line3 = substitute( line2, a:b_close, "", "g" )
  156.    let closeb = strlen( line2 ) - strlen( line3 )
  157.    return openb - closeb
  158. endfunction
  159.  
  160. " Find out whether the line starts with a word (i.e. keyword or function
  161. " call). Might need enhancements here.
  162.  
  163. function! s:Starts_with_word( line )
  164.   if a:line =~ '^\s*[a-zA-Z_0-9]\+\s*('
  165.      return 1
  166.   endif
  167.   return 0
  168. endfunction
  169.  
  170. " Find the length of the first word in a line. This is used to be able to
  171. " align a line relative to the 'print ' or 'if (' on the previous line in case
  172. " such a statement spans multiple lines.
  173. " Precondition: only to be used on lines where 'Starts_with_word' returns 1.
  174.  
  175. function! s:First_word_len( line )
  176.    let white_end = matchend( a:line, '^\s*' )
  177.    if match( a:line, '^\s*func' ) != -1
  178.      let word_end = matchend( a:line, '[a-z]\+\s\+[a-zA-Z_0-9]\+[ (]*' )
  179.    else
  180.      let word_end = matchend( a:line, '[a-zA-Z_0-9]\+[ (]*' )
  181.    endif
  182.    return word_end - white_end
  183. endfunction
  184.  
  185. " Determine if 'line' completes a statement or is continued on the next line.
  186. " This one is far from complete and accepts illegal code. Not important for
  187. " indenting, however.
  188.  
  189. function! s:Seems_continuing( line )
  190.   " Unfinished lines
  191.   if a:line =~ '[\\,\|\&\+\-\*\%\^]\s*$'
  192.     return 1
  193.   endif
  194.   " if/for/while (cond) eol
  195.   if a:line =~ '^\s*\(if\|while\|for\)\s*(.*)\s*$' || a:line =~ '^\s*else\s*'
  196.       return 2
  197.    endif
  198.   return 0
  199. endfunction
  200.  
  201. " Get previous relevant line. Search back until a line is that is no
  202. " comment or blank and return the line number
  203.  
  204. function! s:Get_prev_line( lineno )
  205.    let lnum = a:lineno - 1
  206.    let data = getline( lnum )
  207.    while lnum > 0 && (data =~ '^\s*#' || data =~ '^\s*$')
  208.       let lnum = lnum - 1
  209.       let data = getline( lnum )
  210.    endwhile
  211.    return lnum
  212. endfunction
  213.  
  214. " This function checks whether an indented line exceeds a maximum linewidth
  215. " (hardcoded 80). If so and it is possible to stay within 80 positions (or
  216. " limit num of characters beyond linewidth) by decreasing the indent (keeping
  217. " it > base_indent), do so.
  218.  
  219. function! s:Safe_indent( base, wordlen, this_line )
  220.    let line_base = matchend( a:this_line, '^\s*' )
  221.    let line_len = strlen( a:this_line ) - line_base
  222.    let indent = a:base
  223.    if (indent + a:wordlen + line_len) > 80
  224.      " Simple implementation good enough for the time being
  225.      let indent = indent + 3
  226.    endif
  227.    return indent + a:wordlen
  228. endfunction
  229.