Charles.Forsyth20070607-163224a543919 years agoHistory
806 lines · 17.2 KB · Brainfuck
RawDownload
implement Parseman; include "sys.m";	sys: Sys; include "bufio.m";	bufio: Bufio;	Iobuf: import bufio; include "man.m"; FONT_LITERAL: con -1; init(): string{	sys = load Sys Sys->PATH;	bufio = load Bufio Bufio->PATH;	if (bufio == nil)		return sys->sprint("cannot load module: %r");	return nil;} ParseState: adt[T]	for{	T =>		textwidth: fn(t: self T, text: Text): int;	}{	metrics: Metrics;	ql: int;		# quote Literal text	margin: int;	mstack: list of int;	istack: list  of int;	indent: int;	ntlsetindent: int;	#copy prevailindent to indent on n.t.l	prevailindent: int;	curfont: int;	curattr: int;	verbatim: int;	pspace: int;	curline: list of (int, Text);	# most recent first	curwidth: int;	newpara: int;	heading: int;	igto: string;	link: string;	viewer: T;	setline: chan of list of (int, Text); 	# addstring() is simply an addtext() of the current font	addstring: fn(s: self ref ParseState, s: string);	addtext: fn(s: self ref ParseState, t: list of Text);	brk: fn(s: self ref ParseState);	paragraph: fn( s: self ref ParseState);}; parseman[T](fd: ref Sys->FD, metrics: Metrics, ql: int, viewer: T, setline: chan of list of (int, Text))	for{	T =>		textwidth: fn(t: self T, text: Text): int;	}{	iob := bufio->fopen(fd, Sys->OREAD);	state := ref ParseState[T](metrics, ql, 0, nil, nil, 0, 0, metrics.indent, FONT_ROMAN, 0, 0, 1, nil, 0, 1, 0, "", nil, viewer, setline);	while ((l := iob.gets('\n')) != nil) {		if (l[len l -1] == '\n')			l = l[0: len l - 1];		if (state.igto != nil && state.igto != l)			continue;		state.igto = nil;		parseline(state, l);	}	state.pspace = 2;	state.pspace = 1;	state.paragraph();	footer := Text(FONT_ROMAN, 0, "Inferno Manual", 0, nil);	textw := state.viewer.textwidth(footer);#should do 'center' in addtext (state.justify = CENTER)	state.indent = (state.metrics.pagew - textw) / 2;	state.addtext(footer::nil);	state.brk();	setline <- = nil;} parseline[T](state: ref ParseState[T], t: string)	for{	T =>		textwidth: fn(t: self T, text: Text): int;	}{	if (t == nil) {		if (state.verbatim) {			blank := Text(state.curfont, state.curattr, "", 0, "");			state.setline <- = (0, blank)::nil;		} else			state.paragraph();		return;	}	ntlsetindent := state.ntlsetindent;	state.ntlsetindent = 0;	if (t[0] == '.' || t[0] == '\'')		parsemacro(state, t[1:]);	else {		state.addtext(parsetext(state, t));		if (state.verbatim)			state.brk();	}	if (ntlsetindent) {		state.indent = state.prevailindent;		if (state.curwidth + state.metrics.en > state.indent + state.margin)			state.brk();	}} parsemacro[T](state: ref ParseState[T], t: string)	for{	T =>		textwidth: fn(t: self T, text: Text): int;	}{	for (n := 0; n < len t && n < 2; n++)		if (t[n] == ' '  || t[n] == '\t')			break;	macro := t[0:n];	params: list of string;	quote := 0;	param := 0;	esc := 0;	p := "";	for (; n < len t; n++) {		if (esc)			esc = 0;		else {			case t[n] {			' ' or '\t' =>				if (!quote) {					if (param) {						params = p :: params;						p = "";						param = 0;					}				continue;				}			'"' =>				param = 1;				quote = !quote;				continue;			'\\' =>				esc = 1;			}		}		param = 1;		p[len p] = t[n];	}	if (param)		params = p :: params;	plist: list of string;	for (; params != nil; params = tl params)		plist = hd params :: plist;	params = plist; 	case macro {		"ig" =>			igto := "..";			if (params != nil)				igto = "." + hd params;			state.brk();			state.igto = igto;		"sp" =>			sp := "1";			if(params != nil)				sp = hd params;			d := tval(state.metrics, sp, 'v');			gap := d / state.metrics.V;			if (gap < 1)				gap = 1;			while (gap--)				state.paragraph();		"br" =>			state.brk();		"nf" =>			state.verbatim = 1;		"fi" =>			state.verbatim = 0;		"ti" =>			state.brk();			#i := 0;			#if(params != nil)			#	i = tval(state.metrics, hd params, 'n');			#state.ntlsetindent = 1;			#state.prevailindent = i;		"in" =>			state.brk();			#i := 0;			#if(params != nil)			#	i = tval(state.metrics, hd params, 'n');			#state.indent = i;			#state.prevailindent = state.indent;		"1C" =>			state.brk();			# not implemented		"2C" =>			state.brk();			# not implemented		"BI" =>			altattr(state, FONT_BOLD, FONT_ITALIC, params);		"BR" =>			altattr(state, FONT_BOLD, FONT_ROMAN, params);		"IB" =>			altattr(state, FONT_ITALIC, FONT_BOLD, params);		"IR" =>			# need to determine link if params of valid form			state.link = convlink(params);;			altattr(state, FONT_ITALIC, FONT_ROMAN, params);			state.link = nil;		"RB" =>			altattr(state, FONT_ROMAN, FONT_BOLD, params);		"RI" =>			altattr(state, FONT_ROMAN, FONT_ITALIC, params);		"B" =>			state.curfont = FONT_BOLD;			if (params != nil) {				for (; params != nil; params = tl params) {					textl := parsetext(state, hd params);					for (; textl != nil; textl = tl textl)						state.addtext(hd textl::nil);				}				state.curfont = FONT_ROMAN;			}		"I" =>			state.curfont = FONT_ITALIC;			if (params != nil) {				for (; params != nil; params = tl params) {					textl := parsetext(state, hd params);					for (; textl != nil; textl = tl textl)						state.addtext(hd textl::nil);				}				state.curfont = FONT_ROMAN;			} 		"SM"=>			state.curattr |= ATTR_SMALL;			if (params != nil) {				for (; params != nil; params = tl params)					state.addstring(hd params);				state.curattr &= ~ATTR_SMALL;			}		"L" =>			state.curfont = FONT_LITERAL;			if (params != nil) {				str := "`";				for (pl := params; pl != nil;) {					str += hd pl;					if ((pl = tl pl) != nil)						str += " ";					else						break;				}				str += "'";				state.addstring(str);				state.curfont = FONT_ROMAN;			}		"LR" =>			if (params != nil) {				l := Text(FONT_LITERAL, state.curattr, hd params, 0, nil);				t: list of Text;				params = tl params;				if (params == nil)					t = l :: nil;				else {					r := Text(FONT_ROMAN, state.curattr, hd params, 0, nil);					t = l :: r :: nil;				}				state.addtext(t);			}		"RL" =>			if (params != nil) {				r := Text(FONT_ROMAN, state.curattr, hd params, 0, nil);				t: list of Text;				params = tl params;				if (params == nil)					t = r :: nil;				else {					l := Text(FONT_LITERAL, state.curattr, hd params, 0, nil);					t = r :: l :: nil;				}				state.addtext(t);			}		"DT" =>			# not yet supported			;		"EE" =>			state.brk();			state.verbatim = 0;			state.curfont = FONT_ROMAN;		"EX" =>			state.brk();			state.verbatim = 1;			state.curfont = FONT_BOLD;		"HP" =>			state.paragraph();			i := state.metrics.indent;			if (params != nil)				i = tval(state.metrics, hd params, 'n');			state.prevailindent = state.indent + i;		"IP" =>			state.paragraph();			i := state.metrics.indent;			if (params != nil) {				tag := hd params;				params = tl params;				state.addtext(parsetext(state, tag));				if (params != nil)					i = tval(state.metrics, hd params, 'n');			}			state.indent = state.metrics.indent + i;			state.prevailindent = state.indent;		"PD" =>			state.pspace = 1;			if (params != nil) {				v := tval(state.metrics, hd params, 'v') / state.metrics.V;				state.pspace = v;			}		"LP" or "PP" =>			state.paragraph();			state.prevailindent = state.indent;		"RE" =>			state.brk();			if (state.mstack == nil || state.istack == nil)				break;						state.margin = hd state.mstack;			state.mstack = tl state.mstack;			state.prevailindent = hd state.istack;			state.indent = state.prevailindent;			state.istack = tl state.istack;		"RS" =>			state.brk();			i := state.prevailindent - state.metrics.indent;			if (params != nil)				i = tval(state.metrics, hd params, 'n');			state.mstack = state.margin :: state.mstack;			state.istack = state.prevailindent :: state.istack;			state.margin += i;			state.indent = 2 * state.metrics.indent;			state.prevailindent = state.indent;		"SH" =>			state.paragraph();			state.prevailindent = state.indent;			state.curfont = FONT_ROMAN;			state.curattr = 0;			state.indent = 0;			state.heading = 1;			state.verbatim = 0; 			for (pl := params; pl != nil; pl = tl pl)				state.addstring(hd pl); 			state.heading = 0;			state.brk();			state.newpara = 1;			state.pspace = 1;		"SS" =>			state.paragraph();			state.prevailindent = state.indent;			state.curfont = FONT_ROMAN;			state.curattr = 0;			state.indent = state.metrics.ssindent;			state.heading = 2; 			for (pl := params; pl != nil; pl = tl pl)				state.addstring(hd pl); 			state.heading = 0;			state.brk();			state.newpara = 1;			state.pspace = 1; 		"TF" =>			state.brk();			state.pspace = 0;			i := state.metrics.indent;			if (params != nil) {				str := hd params;				text := Text(FONT_BOLD, 0, str, 0, nil);				w := state.viewer.textwidth(text) + 2*state.metrics.em;				if (w > i)					i = w;			}			state.indent = state.metrics.indent;;			state.prevailindent = state.indent + i;		"TH" =>			state.brk();			if (len params < 2)				break;			str := hd params + "(" + hd tl params + ")";			txt := Text(FONT_ROMAN, 0, str, 0, nil);			txtw := state.viewer.textwidth(txt);			state.indent = 0;			state.addtext(txt::nil);			state.indent = state.metrics.pagew - txtw;			state.addtext(txt::nil);			state.indent = 0;			state.brk();		"TP" =>			state.paragraph();			if (state.prevailindent == state.metrics.indent)				state.prevailindent += state.metrics.indent;			state.indent = state.metrics.indent;			state.ntlsetindent = 1;			if (params != nil) {				i := tval(state.metrics, hd params, 'n');				if (i == 0)					i = state.metrics.indent;				state.prevailindent = state.indent + i;			}		* =>			;	}	if (state.verbatim)		state.brk();} parsetext[T](state: ref ParseState[T], t: string): list of Text	for{	T =>		textwidth: fn(t: self T, text: Text): int;	}{	# need to do better here - spot inline font changes etc	# we also currently cannot support troff tab stops	textl: list of Text;	line := "";	curfont := state.curfont;	prevfont := state.curfont;	# should perhaps be in State	step := 1;	for (i := 0; i < len t; i += step) {		step = 1;		ch := t[i];		if (ch == '\\') {			i++;			width := len t - i;			if (width <= 0)				break;			case t[i] {			'-' or '.' or '\\' =>				ch = t[i];			' '  =>				ch = ' ';			'e' =>				ch = '\\';			'|' or '&' =>				continue;			'(' =>				if (width > 3)					width = 3;				step = width;				if (step != 3)					continue;				case t[i+1:i+3] {				"bu" =>					ch = '•';				"em" =>					ch = '—';				"mi" =>					ch = '-';				"mu" =>					ch = '×';				"*m" =>					ch = 'µ';				"*G" =>					ch = 'Γ';				"*p" =>					ch = 'π';				"*b" =>					ch = 'β';				"<=" =>					ch = '≤';				"->" =>					ch = '→';				* =>					continue;				} 			'f' =>				if (width == 1)					continue;				if (t[i+1] == '(') {					if (width > 4)						width = 4;					step = width;					continue;				}				i++;				case t[i] {				'0' or 'R' =>					curfont = FONT_ROMAN;				'1' or 'I' =>					curfont = FONT_ITALIC;				'2' =>					# should be bold but our 'bold' font is constant width					curfont = FONT_ROMAN;

Lines 1–500 of 806.