Charles.Forsyth20060303a828770d19 years agoHistory
204 lines · 3.9 KB · Brainfuck
RawDownload
implement Fmt; ##	Copyright © 2002 Lucent Technologies Inc.#	based on the Plan 9 command; subject to the Lucent Public License 1.02#	this Vita Nuova variant uses Limbo channels and processes to avoid accumulating words# ##  block up paragraphs, possibly with indentation# include "sys.m";	sys: Sys; include "draw.m"; include "bufio.m";	bufio: Bufio;	Iobuf: import bufio; include "arg.m"; Fmt: module{	init: fn(nil: ref Draw->Context, nil: list of string);}; extraindent := 0;	# how many spaces to indent all linesindent := 0;	# current value of indent, before extra indentlength := 70;	# how many columns per output linejoin := 1;	# can lines be joined?maxtab := 8;bout: ref Iobuf; Word: adt {	text:	string;	indent:	int;	bol:	int;}; init(nil: ref Draw->Context, args: list of string){	sys = load Sys Sys->PATH;	bufio = load Bufio Bufio->PATH;	arg := load Arg Arg->PATH; 	arg->init(args);	arg->setusage("fmt [-j] [-i indent] [-l length] [file...]");	while((c := arg->opt()) != 0) 		case(c){		'i' =>			extraindent = int arg->earg();		'j' =>			join = 0;		'w' or 'l' =>			length = int arg->earg();		* =>			arg->usage();		}	args = arg->argv();	if(length <= extraindent){		sys->fprint(sys->fildes(2), "fmt: line length<=indentation\n");		raise "fail:length";	}	arg = nil; 	err := "";	bout = bufio->fopen(sys->fildes(1), Bufio->OWRITE);	if(args == nil){		bin := bufio->fopen(sys->fildes(0), Bufio->OREAD);		fmt(bin);	}else		for(; args != nil; args = tl args){			bin := bufio->open(hd args, Bufio->OREAD);			if(bin == nil){				sys->fprint(sys->fildes(2), "fmt: can't open %s: %r\n", hd args);				err = "open";			}else{				fmt(bin);				if(tl args != nil)					bout.putc('\n');			}		}	bout.flush();	if(err != nil)		raise "fail:"+err;} fmt(f: ref Iobuf){	words := chan of ref Word;	spawn parser(f, words);	printwords(words);} parser(f: ref Iobuf, words: chan of ref Word){	while((s := f.gets('\n')) != nil){		if(s[len s-1] == '\n')			s = s[0:len s-1];		parseline(s, words);	}	words <-= nil;} parseline(line: string, words: chan of ref Word){	ind: int;	(line, ind) = indentof(line);	indent = ind;	bol := 1;	for(i:=0; i < len line;){		# find next word		if(line[i] == ' ' || line[i] == '\t'){			i++;			continue;		}		# where does this word end?		for(l:=i; l < len line; l++)			if(line[l]==' ' || line[l]=='\t')				break;		words <-= ref Word(line[i:l], indent, bol);		bol = 0;		i = l;	}	if(bol)		words <-= ref Word("", -1, bol);} indentof(line: string): (string, int){	ind := 0;	for(i:=0; i < len line; i++)		case line[i] {		' ' =>			ind++;		'\t' =>			ind += maxtab;			ind -= ind%maxtab;		* =>			return (line, ind);		}	# plain white space doesn't change the indent	return (line, indent);}	printwords(words: chan of ref Word){	# one output line per loop	nw := <-words;	while((w := nw) != nil){		# if it's a blank line, print it		if(w.indent == -1){			bout.putc('\n');			nw = <-words;			continue;		}		# emit leading indent		col := extraindent+w.indent;		printindent(col);		# emit words until overflow; always emit at least one word		for(n:=0;; n++){			bout.puts(w.text);			col += len w.text;			if((nw = <-words) == nil)				break;	# out of words			if(nw.indent != w.indent)				break;	# indent change			nsp := nspaceafter(w.text);			if(col+nsp+len nw.text > extraindent+length)				break;	# fold line			if(!join && nw.bol)				break;			for(j:=0; j<nsp; j++)				bout.putc(' ');	# emit space; another word will follow			col += nsp;			w = nw;		}		bout.putc('\n');	}} printindent(w: int){	while(w >= maxtab){		bout.putc('\t');		w -= maxtab;	}	while(--w >= 0)		bout.putc(' ');} # give extra space if word ends with punctuationnspaceafter(s: string): int{	if(len s < 2)		return 1;	if(len s < 4 && s[0] >= 'A' && s[0] <= 'Z')		return 1;	# assume it's a title, not full stop	if((c := s[len s-1]) == '.' || c == '!' || c == '?')		return 2;	return 1;}