jim@bilpin.UUCP (JimG) (06/20/89)
#{ v_unix.3 } [ Long - about 280 lines ] IN ARTICLE <19890@adm.BRL.MIL>, thoyt@ddn-wms.arpa (Thomas Hoyt) WRITES: > Can vi reformat a paragraph, justifying it properly(left, right, or > centered)? IN ARTICLE <13816@dartvax.Dartmouth.EDU>, andyb@coat.com (Andy Behrens) WRITES: > If you put the following line in your .exrc file, you can type "V" when > the cursor is anywhere in a paragraph, and the entire paragraph will be > rejustified by being piped through "fmt". > map V 0}!{fmt^M} For those, like me, who don't have fmt on their system, here are three Bourne shell scripts which use awk to effect the required reformatting. Use the usual vi ! operator to execute them, preceded by an optional count, and succeeded by a context marker, ) for sentences, } for paragraphs, and G for lines ( remember that vi requires two spaces after a full stop to delimit a sentence ). The reformat scripts preserve blank lines, so multiple paragraphs can be altered at once; lines can also be protected by appending a CTRL M character, so a chunk of text can be reformatted while leaving certain lines within it unchanged; optional line width and left margin size can be specified, otherwise defaults are taken from specified system variables, or assumed. See the detailed comments at the start of each script for more information. The following scripts are delimited by lines of +'s. #+ START OF centre + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #{ centre 1.2 } Last update: 20-Apr-89 11:44 # Author: Jim Grimwood, Hatfield, England # CENTRE TEXT TO SPECIFIED MARGIN # Syntax : centre [arg1] [arg2] # Optional arguments are : # arg1 line size ( range 10 - 136 ) # arg2 margin size ( range 0 - 40 ) # Line/margin arguments on the command line are given priority; if not # defined, shell environment variables PSIZE/PMARG are used; if not defined, # defaults of 80/0 are used. Errors in any arguments supplied are trapped # silently and defaults substituted. # NOTE: Assumes tabstep to be 8. # WARNING!: Avoid embedded apostrophes in awk comments! PSIZE=${1:-$PSIZE} PMARG=${2:-$PMARG} if [ "$PSIZE" -lt 10 -o "$PSIZE" -gt 136 ] then PSIZE=80 fi # The next line *shouldn't* be -lt 0 ( rather than -lt 1 ), because then # invalid alphanumeric arguments wouldn't be trapped if [ "$PMARG" -lt 1 -o "$PMARG" -gt 40 ] then PMARG=0 fi # Convert embedded tabs to spaces first, to get 'length' char count correct pr -e -t | \ awk ' BEGIN { SPACES = " " # 40 spaces TABS = " " # 5 tabs } { TEXT = substr( $0, index( $0, $1 ) ) # Omit leading white space OFFSET = PMARG + int( ( PSIZE - length( TEXT ) ) / 2 ) CT = int( OFFSET / 8 ) CB = OFFSET - 8 * CT print substr( TABS, 1, CT ) substr( SPACES, 1, CB ) TEXT } ' PSIZE=$PSIZE PMARG=$PMARG #+ END OF centre + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #+ START OF reform + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #{ reform 1.2 } Last update: 20-Apr-89 11:55 # Author: Jim Grimwood, Hatfield, England # REFORMAT TEXT TO SPECIFIED LINE LENGTH / MARGIN - RAGGED RIGHT # Syntax : reform [arg1] [arg2] # Optional arguments are : # arg1 line size ( range 10 - 136 ) # arg2 margin size ( range 0 - 40 ) # Line/margin arguments on the command line are given priority; if not # defined, shell environment variables PSIZE/PMARG are used; if not defined, # defaults of 80/0 are used. Errors in any arguments supplied are trapped # silently and defaults substituted. # Multiple paragraphs in the context area are re-formatted individually and # kept separate; if you always want the context area to be merged into a # single paragraph, then remove the clause 'NF == 0 ||' on the line marked # '# <<<<' in the main awk program below. # Lines marked with a CTRL M as the last character will print unchanged # (useful for headings, embedded tables, and so on). # NOTE: Assumes tabstep to be 8. # WARNING!: Avoid embedded apostrophes in awk comments! PSIZE=${1:-$PSIZE} PMARG=${2:-$PMARG} if [ "$PSIZE" -lt 10 -o "$PSIZE" -gt 136 ] then PSIZE=80 fi # The next line *shouldn't* be -lt 0 ( rather than -lt 1 ), because then # invalid alphanumeric arguments wouldn't be trapped if [ "$PMARG" -lt 1 -o "$PMARG" -gt 40 ] then PMARG=0 fi awk ' BEGIN { SPACES = " " # 40 spaces TABS = " " # 5 tabs } # I`d like to be able to do the next bit in the BEGIN, but awk pretends not # to know about the command line arguments at that time NR == 1 { PSIZE = int( PSIZE ) # coerce to type int CT = int( PMARG / 8 ) CB = PMARG - 8 * CT MARGIN = substr( TABS,1,CT ) substr( SPACES,1,CB ) # set left margin } # The next un-commented line may display partially overprinted on # your terminal, except in vi; the line should read (minus the #): # { if( NF == 0 || substr( $0, length ) == "^M" ) # where the character in quotes is a single-byte CTRL M { if( NF == 0 || substr( $0, length ) == " { if( TEXT > "" ) { print MARGIN TEXT TEXT = "" } print next } $1 = $1 # compress white space # discard leading white space and append to previous text, if any if( length( TEXT ) == 0 ) TEXT = substr( $0, index( $0, $1 ) ) else TEXT = TEXT " " substr( $0, index( $0, $1 ) ) while( length( TEXT ) > PSIZE ) { for( L = PSIZE+1; L > 0; L-- ) # find last word which fits if( substr( TEXT, L, 1 ) == " " ) break print MARGIN substr( TEXT, 1, L-1 ) TEXT = substr( TEXT, L+1 ) } } END { print MARGIN TEXT } ' PSIZE=$PSIZE PMARG=$PMARG #+ END OF reform + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #+ START OF rjust + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #{ rjust 1.2 } Last update: 20-Apr-89 11:55 # Author: Jim Grimwood, Hatfield, England # REFORMAT TEXT TO SPECIFIED LINE LENGTH / MARGIN - ALIGNED TO BOTH MARGINS # Syntax : rjust [arg1] [arg2] # Optional arguments are : # arg1 line size ( range 10 - 136 ) # arg2 margin size ( range 0 - 40 ) # Line/margin arguments on the command line are given priority; if not # defined, shell environment variables PSIZE/PMARG are used; if not defined, # defaults of 80/0 are used. Errors in any arguments supplied are trapped # silently and defaults substituted. # Multiple paragraphs in the context area are re-formatted individually and # kept separate; if you always want the context area to be merged into a # single paragraph, then remove the clause 'NF == 0 ||' on the line marked # '# <<<<' in the main awk program below. # Lines marked with a CTRL M as the last character will print unchanged # (useful for headings, embedded tables, and so on). # NOTE: Assumes tabstep to be 8. # WARNING!: Avoid embedded apostrophes in awk comments! PSIZE=${1:-$PSIZE} PMARG=${2:-$PMARG} if [ "$PSIZE" -lt 10 -o "$PSIZE" -gt 136 ] then PSIZE=80 fi # The next line *shouldn't* be -lt 0 ( rather than -lt 1 ), because then # invalid alphanumeric arguments wouldn't be trapped if [ "$PMARG" -lt 1 -o "$PMARG" -gt 40 ] then PMARG=0 fi awk ' BEGIN { SPACES = " " # 40 spaces TABS = " " # 5 tabs } # I`d like to be able to do the next bit in the BEGIN, but awk pretends not # to know about the command line arguments at that time NR == 1 { PSIZE = int( PSIZE ) # coerce to type int CT = int( PMARG / 8 ) CB = PMARG - 8 * CT MARGIN = substr( TABS,1,CT ) substr( SPACES,1,CB ) # set left margin } # The next un-commented line may display partially overprinted on # your terminal, except in vi; the line should read (minus the #): # { if( NF == 0 || substr( $0, length ) == "^M" ) # where the character in quotes is a single-byte CTRL M { if( NF == 0 || substr( $0, length ) == " { if( TEXT > "" ) { print MARGIN TEXT TEXT = "" } print next } $1 = $1 # compress white space # discard leading white space and append to previous text, if any if( length( TEXT ) == 0 ) TEXT = substr( $0, index( $0, $1 ) ) else TEXT = TEXT " " substr( $0, index( $0, $1 ) ) while( length( TEXT ) > PSIZE ) { for( L = PSIZE+1; L > 0; L-- ) # find last word which fits if( substr( TEXT, L, 1 ) == " " ) break if( L-1 < PSIZE ) # if it`s a short line, spread it out { SPACE = 0 for( I = 1; I <= L-1; I++ ) # count spaces if( substr( TEXT, I, 1 ) == " " ) SPACE++ CHARS = L - 1 - SPACE # no of non-space chars WSEP = int( ( PSIZE - CHARS ) / SPACE ) # avg separation requ`d WSEPC = substr( SPACES, 1, WSEP ) # avg separation spaces LSEP = PSIZE - CHARS - WSEP * ( SPACE - 1 ) # remainder sep`tion WTEXT = ""; WORDL=0; LASTW=0 for( I = 1; I <= L-1; I++ ) { TCHAR = substr( TEXT, I, 1 ) if( TCHAR == " " ) { if( LSEP > 2 ) # even out the separation { WTEXT = WTEXT WSEPC " " LASTW += WORDL + WSEP + 1 LSEP-- } else { WTEXT = WTEXT WSEPC LASTW += WORDL + WSEP } WORDL = 0 } else { WTEXT = WTEXT TCHAR WORDL++ # length of current word } } print MARGIN substr( WTEXT,1,LASTW-WSEP ) \ substr( SPACES,1,LSEP ) \ substr( WTEXT,LASTW+1 ) # phew! finally done it! } else print MARGIN substr( TEXT, 1, L-1 ) TEXT = substr( TEXT, L+1 ) } } END { print MARGIN TEXT } ' PSIZE=$PSIZE PMARG=$PMARG #+ END OF rjust + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -- <Path: mcvax!ukc!icdoc!bilpin!jim> <UUCP: jim@bilpin.uucp> {JimG : Hatfield, England} This line has been intentionally left blank.