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 / mac / vim54rt.sit / runtime / macros / justify.vim < prev    next >
Encoding:
Text File  |  1999-08-14  |  8.4 KB  |  306 lines  |  [TEXT/ALFA]

  1. " Function to left and rigt align text.
  2. "
  3. " Written by: Preben "Peppe" Guldberg <c928400@student.dtu.dk>
  4. " Last change:  980806 14:13:22
  5. "
  6. "
  7. " function Justify( [ textwidth [, maxspaces [, indent] ] ] )
  8. "
  9. " Justify()  will  left  and  right  align  a  line  by  filling  in  an
  10. " appropriate amount of spaces.  Extra  spaces  are  added  to  existing
  11. " spaces starting from the right side of the line. As  an  example,  the
  12. " following documentation has been justified.
  13. "
  14. " The function takes the following arguments:
  15. "
  16. " textwidth argument
  17. " ------------------
  18. " If not specified, the value of the  'textwidth'  option  is  used.  If
  19. " 'textwidth' is zero a value of 80 is used.
  20. "
  21. " Additionally the arguments 'tw' and ''  are  accepted.  The  value  of
  22. " 'textwidth' will be used. These are handy, if you just want to specify
  23. " the maxspaces argument.
  24. "
  25. " maxspaces argument
  26. " ------------------
  27. " If specified, alignment will only be done, if the  longest  space  run
  28. " after alignment is no longer than maxspaces.
  29. "
  30. " An argument of '' is accepted, should the user  like  to  specify  all
  31. " arguments.
  32. "
  33. " To aid user defined commands, negative  values  are  accepted  aswell.
  34. " Using a negative value specifies the default behaviour: any length  of
  35. " space runs will be used to justify the text.
  36. "
  37. " indent argument
  38. " ---------------
  39. " This argument specifies how a line should be indented. The default  is
  40. " to keep the current indentation.
  41. "
  42. " Negative values: Keep current amount of leading whitespace.
  43. " Positive values: Indent all lines with leading whitespace  using  this
  44. " amount of whitespace.
  45. "
  46. " Note that the value 0, needs to be quoted  as  a  string.  This  value
  47. " leads to a left flushed text.
  48. "
  49. " Additionally units of  'shiftwidth'/'sw'  and  'tabstop'/'ts'  may  be
  50. " added. In this case, if the value of indent is positive, the amount of
  51. " whitespace to be  added  will  be  multiplied  by  the  value  of  the
  52. " 'shiftwidth' and 'tabstop' settings. If  these  units  are  used,  the
  53. "  argument  must  be  given  as  a  string,  eg.  Justify('','','2sw').
  54. "
  55. " If the values of 'sw' or 'tw' are negative, they  are  treated  as  if
  56. " they were 0, which means that the text is flushed left.  There  is  no
  57. " check if a negative number prefix is used  to  change  the  sign  of a
  58. " negative 'sw' or 'ts' value.
  59. "
  60. " As with the other arguments,  ''  may  be  used  to  get  the  default
  61. " behaviour.
  62. "
  63. "
  64. " Notes:
  65. "
  66. " If the line, adjusted for space runs and leading/trailing  whitespace,
  67. " is wider than the used textwidth, the line will be left untouched  (no
  68. " whitespace removed). This should be equivalent  to  the  behaviour  of
  69. " :left, :right and :center.
  70. "
  71. " If the resulting line is shorter than the used textwidth  it  is  left
  72. " untouched.
  73. "
  74. " All space runs in the line  are  truncated  before  the  alignment  is
  75. " carried out.
  76. "
  77. " If you have set 'noexpandtab', :retab! is used to replace  space  runs
  78. "  with  whitespace  using  the  value  of  'tabstop'.  This  should  be
  79. " conformant with :left, :right and :center.
  80. "
  81. " If joinspaces is set, an extra space is added after '.', '?' and  '!'.
  82. " If 'cpooptions' include 'j', extra space  is  only  added  after  '.'.
  83. " (This may on occasion conflict with maxspaces.)
  84. "
  85. "
  86. " Related mappings:
  87. "
  88. " Mappings that will align text using the current text width,  using  at
  89. " most four spaces in a  space  run  and  keeping  current  indentation.
  90. nmap _j :%call Justify('tw',4)<CR>
  91. vmap _j :call Justify('tw',4)<CR>
  92. "
  93. " Mappings that will remove space runs and format lines (might be useful
  94. " prior to aligning the text).
  95. nmap ,gq :%s/\s\+/ /g<CR>gq1G
  96. vmap ,gq :s/\s\+/ /g<CR>gvgq
  97. "
  98. "
  99. " User defined command:
  100. "
  101. " The following is an ex command that works as a shortcut to the Justify
  102. " function. Arguments to Justify()  can  be  added  after  the  command.
  103. com -range -nargs=* Justify <line1>,<line2>call Justify(<f-args>)
  104. "
  105. " The following commands are all equivalent:
  106. "
  107. " 1. Simplest use of Justify():
  108. "       :call Justify()
  109. "       :Justify
  110. "
  111. " 2. The _j mapping above via the ex command:
  112. "       :%Justify tw 4
  113. "
  114. " 3.  Justify  visualised  text  at  72nd  column  while  indenting  all
  115. " previously indented text two shiftwidths
  116. "       :'<,'>call Justify(72,'','2sw')
  117. "       :'<,'>Justify 72 -1 2sw
  118. "
  119. " This documentation has been justified  using  the  following  command:
  120. "       :se et|0;/^" function Justify(/+;/^$/2-g/^"/Justify 72 2
  121.  
  122. " Error function
  123. function Justify_error(message)
  124.     echohl Error
  125.     echo "Justify( [tw , [maxspaces [, indent] ] ): " . a:message
  126.     echohl None
  127. endfunction
  128.  
  129.  
  130. " Now for the real thing
  131. function Justify(...) range
  132.  
  133.     if a:0 > 3
  134.     call Justify_error("Too many arguments (max 3)")
  135.     return 1
  136.     endif
  137.  
  138.     " Set textwidth (accept 'tw' and '' as arguments)
  139.     if a:0 >= 1
  140.     if a:1 =~ '^\(tw\)\=$'
  141.         let tw = &tw
  142.     elseif a:1 =~ '^\d\+$'
  143.         let tw = a:1
  144.     else
  145.         call Justify_error("tw must be a number (>0), '' or 'tw'")
  146.         return 2
  147.     endif
  148.     else
  149.     let tw = &tw
  150.     endif
  151.     if tw == 0
  152.     let tw = 80
  153.     endif
  154.  
  155.     " Set maximum number of spaces between WORDs
  156.     if a:0 >= 2
  157.     if a:2 == ''
  158.         let maxspaces = tw
  159.     elseif a:2 =~ '^-\d\+$'
  160.         let maxspaces = tw
  161.     elseif a:2 =~ '^\d\+$'
  162.         let maxspaces = a:2
  163.     else
  164.         call Justify_error("maxspaces must be a number or ''")
  165.         return 3
  166.     endif
  167.     else
  168.     let maxspaces = tw
  169.     endif
  170.     if maxspaces <= 1
  171.     call Justify_error("maxspaces should be larger than 1")
  172.     return 4
  173.     endif
  174.  
  175.     " Set the indentation style (accept sw and ts units)
  176.     if a:0 >= 3
  177.     if (a:3 == '') || a:3 =~ '^-[1-9]\d*\(sw\|ts\)\=$'
  178.         let indent = -1
  179.     elseif a:3 =~ '^-\=0\(shiftwidth\|sw\|tabstop\|ts\)\=$'
  180.         let indent = 0
  181.     elseif a:3 =~ '^\d\+\(shiftwidth\|sw\|tabstop\|ts\)\=$'
  182.         let indent = substitute( a:3, '\D', '', 'g')
  183.     elseif a:3 =~ '^\(shiftwidth\|sw\|tabstop\|ts\)$'
  184.         let indent = 1
  185.     else
  186.         call Justify_error("indent: a number with 'sw'/'ts' unit")
  187.         return 5
  188.     endif
  189.     if indent >= 0
  190.         let indent_str = ''
  191.         while indent > 0
  192.         let indent_str = indent_str . ' '
  193.         let indent = indent - 1
  194.         endwhile
  195.         if a:3 =~ '\(shiftwidth\|sw\)'
  196.         let indent_sw = &sw
  197.         elseif a:3 =~ '\(tabstop\|ts\)'
  198.         let indent_sw = &ts
  199.         endif
  200.         if exists("indent_sw")
  201.         let indent_str2 = ''
  202.         while indent_sw > 0
  203.             let indent_str2 = indent_str2 . indent_str
  204.             let indent_sw = indent_sw - 1
  205.         endwhile
  206.         let indent_str = indent_str2
  207.         endif
  208.     endif
  209.     else
  210.     let indent = -1
  211.     endif
  212.  
  213.     " Avoid substitution reports
  214.     let save_report = &report
  215.     set report=1000000
  216.  
  217.     " Check 'joinspaces' and 'cpo'
  218.     if &js == 1
  219.     if &cpo =~ 'j'
  220.         let join_str = '\(\. \)'
  221.     else
  222.         let join_str = '\([.!?!] \)'
  223.     endif
  224.     endif
  225.  
  226.     let cur = a:firstline
  227.     while cur <= a:lastline
  228.  
  229.     let str = getline(cur)
  230.  
  231.     " Remember the current indentation
  232.     let indent_orig = matchstr( str, '^\s*')
  233.     if strlen(indent_orig) > 0
  234.         if indent < 0
  235.         let indent_str = indent_orig
  236.         endif
  237.         let indent_n = strlen(indent_str)
  238.     else
  239.         let indent_n = 0
  240.     endif
  241.  
  242.     " Trim trailing, leading and running whitespace
  243.     let str = substitute( str, '\s\+$', '', '')
  244.     let str = substitute( str, '^\s\+', '', 'g')
  245.     let str = substitute( str, '\(\S\)\s\+', '\1 ', 'g')
  246.  
  247.     " Possible addition of space after punctuation
  248.     if exists("join_str")
  249.         let str = substitute( str, join_str, '\1 ', 'g')
  250.     endif
  251.  
  252.     let str_n = strlen(str)
  253.  
  254.     if str_n < tw - indent_n    " Extra spaces can be added
  255.         " How many spaces should be added
  256.         let s_add = tw - str_n - indent_n
  257.         let s_nr  = strlen( substitute( str, '\S', '', 'g') )
  258.         let s_dup = s_add / s_nr
  259.         let s_mod = s_add % s_nr
  260.  
  261.         " Test if the changed line fits with tw
  262.         if 0 <= (str_n + (maxspaces - 1)*s_nr + indent_n) - tw
  263.  
  264.         " Duplicate spaces
  265.         while s_dup > 0
  266.         let str = substitute( str, '\( \+\)', ' \1', 'g')
  267.         let s_dup = s_dup - 1
  268.         endwhile
  269.  
  270.         " Indent the line
  271.         if indent_n > 0
  272.         let str = substitute( str, '^', indent_str, '' )
  273.         endif
  274.  
  275.         " Replace the line (brings the cursor to the line)
  276.         let str = substitute( str, '\\', '\\\\', 'g')
  277.         let str = substitute( str, '/', '\\/', 'g')
  278.         let str = substitute( str, '\~', '\\\~', 'g')
  279.         exec cur . 's/.*/' . str . '/'
  280.  
  281.         " Add extra spaces from the end
  282.         norm $
  283.         while s_mod > 0
  284.         norm ByhP
  285.         let s_mod = s_mod - 1
  286.         endwhile
  287.  
  288.         " Convert to whitespace
  289.         if &et == 0
  290.         :.retab!
  291.         endif
  292.  
  293.         endif   " Change of line
  294.     endif    " Possible change
  295.  
  296.     let cur = cur + 1
  297.     endwhile
  298.  
  299.     norm ^
  300.  
  301.     let &report = save_report
  302.  
  303. endfunction
  304.  
  305. " EOF    vim: tw=78 ts=8 sw=4 sts=4 noet ai
  306.