Charles.Forsyth20060303a828770d19 years agoHistory
730 lines · 17.1 KB · Brainfuck
RawDownload
## Copyright © 1996-1999 Lucent Technologies Inc.  All rights reserved.#	Modified version of edit#	D.B.Knudsen# Revisions Copyright © 2000-2002 Vita Nuova Holdings Limited.  All rights reserved.#implement WmEdit; include "sys.m";	sys: Sys; include "draw.m";	draw: Draw;	Rect, Screen: import draw; include "tk.m";	tk: Tk; include "tkclient.m";	tkclient: Tkclient; include "dialog.m";	dialog: Dialog; include "selectfile.m";	selectfile: Selectfile; WmEdit: module{	init:	fn(ctxt: ref Draw->Context, argv: list of string);}; ErrIco: con "error -fg red"; ed: ref Tk->Toplevel;dirty := 0; BLUE : con "#0000ff";GREEN : con "#008800"; SEARCH,SEARCHFOR,REPLACE,REPLACEWITH,REPLACEALL,NOSEE : con iota; ed_config := array[] of {	"frame .m -relief raised -bd 2",	"frame .b",	"menubutton .m.file -text File -menu .m.file.menu",	"menubutton .m.edit -text Edit -menu .m.edit.menu",	"menubutton .m.search -text Search -menu .m.search.menu",	"menubutton .m.options -text Options -menu .m.options.menu",#	"label .m.filename",	"pack .m.file .m.edit .m.search .m.options -side left",#	"pack .m.filename -padx 10 -side left",	"menu .m.file.menu",	".m.file.menu add command -label New -command {send c new}",	".m.file.menu add command -label Open... -command {send c open}",	".m.file.menu add separator",	".m.file.menu add command -label Save -command {send c save}",	".m.file.menu add command -label {Save As...} -command {send c saveas}",	".m.file.menu add separator",	".m.file.menu add command -label {Exit} -command {send c exit}",	"menu .m.edit.menu",	".m.edit.menu add command -label Cut -command {send c cut}",	".m.edit.menu add command -label Copy -command {send c copy}",	".m.edit.menu add command -label Paste -command {send c paste}",	"menu .m.search.menu",	".m.search.menu add command -label {Find ...} " +					"-command {send c searchf}",	".m.search.menu add command -label {Replace with...} " +					"-command {send c replacew}",	".m.search.menu add command -label {Find Again} -command {send c search}",	".m.search.menu add command -label {Find and Replace} " +					"-command {send c replace}",	".m.search.menu add command -label {Find and Replace All} " +					"-command {send c replaceall}",	"menu .m.options.menu",	".m.options.menu add checkbutton -text Limbo -command {send c limbo}",	".m.options.menu add command -label Indent -command {send c indent}",	"text .b.t  -yscrollcommand {.b.s set} -bg white",	"bind .b.t <Button-2> {.m.edit.menu post %X %Y}",	"bind .b.t <Key> +{send c dirtied {%A}}",	"bind .b.t <ButtonRelease-1> +{send c reindent}",	"scrollbar .b.s -command {.b.t yview}",	"pack .m -fill x",	"pack .b.s -fill y -side left",	"pack .b.t -fill both -expand 1",	"pack .b -fill both -expand 1",	"focus .b.t",	"pack propagate . 0",	".b.t tag configure keyword -fg " + BLUE,	".b.t tag configure comment -fg " + GREEN,	"update",}; context : ref Draw->Context;curfile := "(New)";snarf := "";searchfor := "";replacewith := "";path := "."; init(ctxt: ref Draw->Context, argv: list of string){	wmctl: chan of string; 	sys = load Sys Sys->PATH;	draw = load Draw Draw->PATH;	tk = load Tk Tk->PATH;	tkclient = load Tkclient Tkclient->PATH;	selectfile = load Selectfile Selectfile->PATH;	dialog = load Dialog Dialog->PATH; 	sys->pctl(Sys->NEWPGRP, nil);	tkclient->init();	selectfile->init();	dialog->init(); 	context = ctxt; 	(ed, wmctl) = tkclient->toplevel(context, "", "Edit", Tkclient->Appl); 	argv = tl argv; 	c := chan of string;	tk->namechan(ed, c, "c");	for (i := 0; i < len ed_config; i++)		cmd(ed, ed_config[i]); 	if (argv != nil) {		e := loadtfile(hd argv);		if(e != nil)			dialog->prompt(ctxt, ed.image, ErrIco, "Open file", e, 0, "Ok"::nil);	} 	tkclient->settitle(ed, "Edit " + curfile);	tkclient->onscreen(ed, nil);	tkclient->startinput(ed, "ptr" :: "kbd" :: nil);	cmd(ed, "update"); 	e := cmd(ed, "variable lasterror");	if(e != "") {		sys->print("edit error: %s\n", e);		return;	} 	cmdloop: for(;;) {		alt {		key := <-ed.ctxt.kbd =>			tk->keyboard(ed, key);		m := <-ed.ctxt.ptr =>			tk->pointer(ed, *m);		s := <-ed.ctxt.ctl or		s = <-ed.wreq or		s = <-wmctl =>			if(s == "exit") {				if (check_dirty())					break cmdloop;				else					break;			}			task_title: string;			if (s == "task") {				if (curfile == "(New)")					task_title = tkclient->settitle(ed, "Edit");				else					task_title = tkclient->settitle(ed, "Edit " + curfile);				cmd(ed, "update");			}			tkclient->wmctl(ed, s);			if (s == "task")				tkclient->settitle(ed, task_title);		s := <-c =>			if ( len s > 7 && s[:7] == "dirtied" ) {				set_dirty(); do_limbo_check(s);			}			else			case s {			"exit" =>	if ( check_dirty() ){ set_clean(); break cmdloop; }			"dirtied" =>	set_dirty(); do_limbo_check(s);			"new" =>	if ( check_dirty()) {set_clean(); do_new();}			"open" =>	if ( check_dirty() && do_open()) set_clean();			"save" =>	do_save(0);			"saveas" =>	do_save(1);			"cut" =>	do_snarf(1); set_dirty();			"copy" =>	do_snarf(0);			"paste" =>	do_paste(); set_dirty();			"search" =>	do_search(SEARCH);			"searchf" =>	do_search(SEARCHFOR);			"replace" =>	do_replace(REPLACE);			"replacew" =>	do_replace(REPLACEWITH);			"replaceall" =>	do_replaceall();			"limbo" =>	do_limbo();			"indent" =>	do_indent();			"reindent" =>	re_indent();			}			cmd(ed, "focus .b.t");		}		cmd(ed, "update");		e = cmd(ed, "variable lasterror");		if(e != "") {			sys->print("edit error: %s\n", e);			break cmdloop;		}	}} check_dirty() : int{	if ( dirty == 0 )		return 1;	if (dialog->prompt(context, ed.image, ErrIco, "Confirm",					"File was changed.\nDiscard changes?",					0, "Yes" :: "No" :: nil) == 0 ) {		return 1;	}	return 0;} set_dirty(){	if(!dirty){		dirty = 1;		tkclient->settitle(ed, "Edit " + curfile + " (dirty)");		cmd(ed, "update");	}#	We want to just remove the binding, but Inferno's tk does not#	recognize the - in front of the command.  To make it do so would#	require changes to utils.c and ebind.c in /tk#	cmd(ed, "bind .b.t <Key> -{send c dirtied}");} set_clean(){	if(dirty){		dirty = 0;		tkclient->settitle(ed, "Edit " + curfile);		cmd(ed, "update");		#cmd(ed, "bind .b.t <Key> +{send c dirtied}");	}} BLOCK, TEMP : con iota;is_limbo	:= 0;		# initially not limbothis_word := "";last_keyword := "";in_comment	:= 0;first_char	:= 1;indent		: list of int;last_kw_is_block := 0;tab		:= "\t";tabs		:= array[] of {	"", "\t", "\t\t", "\t\t\t", "\t\t\t\t", "\t\t\t\t\t",	"\t\t\t\t\t\t", "\t\t\t\t\t\t\t", "\t\t\t\t\t\t\t\t"}; keywords := array[] of {	"adt", "alt", "array", "big", "break",	"byte", "case", "chan", "con", "continue",	"cyclic", "do", "else", "exit", "fn",	"for", "hd", "if", "implement", "import",	"include", "int", "len", "list", "load",	"module", "nil", "of", "or", "pick",	"real", "ref", "return", "self", "spawn",	"string", "tagof", "tl", "to", "type",	"while"};block_keyword := (big 1 << 40 ) | big (1 << 17) | big (1 << 15) |					big (1 << 12) | big (1 << 11); do_limbo(){	is_limbo = !is_limbo;	if ( is_limbo )		mark_keyw_comm();	else {		cmd(ed, ".b.t tag remove comment 1.0 end");		cmd(ed, ".b.t tag remove keyword 1.0 end");	}} do_limbo_check(s : string){	if ( ! is_limbo )		return;	if ( len s < 11 )		return;##   Maybe we should actually remember where the insert point is.#   In general we can get it via .b.t index insert, but for most#   characters, we could maintain the position with simple arithmetic.##   Also, we need to insert code in cut and paste operations to keep#   track of various things when in limbo mode.  Also need to catch#   text deletions via typeover of selection.#	char := s[9];	if ( char == '\\' && len s > 10 )		char = s[10];	case char {	    ' ' or '\t' =>		if ( ! in_comment )			look_keyword(this_word);		this_word = "" ;	    '\n' =>		if ( in_comment ) {			# terminate current tag			cmd(ed, ".b.t tag remove comment insert-1chars");			in_comment = 0;		}		else			look_keyword(this_word);		this_word = "" ;		if ( last_kw_is_block )			indent = TEMP :: indent;		else while ( indent != nil && hd indent == TEMP )			indent = tl indent;		last_kw_is_block = 0;		add_indent();		first_char = 1;		return;	    '{' =>		indent = BLOCK :: indent;		last_kw_is_block = 0;	    '}' =>		if ( indent != nil )			indent = tl indent;		last_kw_is_block = 0;	# If the line is just indentation plus '}', rewrite it	# to have one less indent.		if ( first_char ) {			current := int cmd(ed, ".b.t index insert");			cmd(ed, ".b.t delete " +						string current + ".0 insert");			add_indent();			cmd(ed, ".b.t insert insert '}");		}#	    ';' =>#		last_kw_is_block = 0;#	    '\b' =>	# By the time we see this, the character has#			# already been wiped out, probably.#			# To know what it was we'd need a lastchar,#			# reset for each mouse button up and \b#	    '\u007f' =>	# Here, we have to know what used to be ahead of the#			# insert point.	    '#' =>		# if ( ! in_quote ) {		#	cmd(ed, ".b.t tag add comment insert-1chars");			in_comment = 1;		# }	    'A' to 'Z' or 'a' to 'z' or '0' to '9' or '_' =>		if ( ! in_comment )			this_word[len this_word] = char;	    * =>		if ( ! in_comment )			look_keyword(this_word);		this_word = "";	}	if ( in_comment )		cmd(ed, ".b.t tag add comment insert-1chars");	first_char = 0;} look_keyword(word : string){	# compare this_word to all keywords	if ( is_keyword(word) ) {		cmd(ed, ".b.t tag add keyword insert-" +			string (len this_word + 1) + "chars insert-1chars");	}} is_keyword(word : string) : int{	l := len keywords;	for ( i := 0; i < l; i++ )		if ( word == keywords[i] ) {			if ( i != 26 )	# don't set for 'nil'				last_kw_is_block = int (block_keyword >> i) & 1;			return 1;		}	return 0;} do_new(){	cmd(ed, ".b.t delete 1.0 end");	curfile = "(New)";	tkclient->settitle(ed, "Edit " + curfile);} do_open(): int{	for(;;) {		fname := selectfile->filename(context, ed.image, "", nil, path);		if(fname == "")			break;		cmd(ed, ".b.t delete 1.0 end");		e := loadtfile(fname);		if(e == nil) {			basepath(fname);			return 1;		} 		options := list of {			"Cancel",			"Open another file"		}; 		if(dialog->prompt(context, ed.image, ErrIco, "Open file", e, 0,  options) == 0)			break;	}	return 0;} basepath(file: string){	for(i := len file-1; i >= 0; i--)		if(file[i] == '/') {			path = file[0:i];			break;		}} do_save(prompt: int){	fname := curfile; 	contents := tk->cmd(ed, ".b.t get 1.0 end");	for(;;) {		if(prompt || curfile == "(New)") {			fname = dialog->getstring(context, ed.image, "File");			if ( len fname > 0 && fname[0] != '/' && path != "" )				fname = path + "/" + fname;		} 		if(savetfile(fname, contents)) {			set_clean();			break;		} 		options := list of {			"Cancel",			"Try another file"		}; 		msg := sys->sprint("Trying to write file \"%s\"\n%r", fname);		if(dialog->prompt(context, ed.image, ErrIco, "Save file", msg, 0, options) == 0)			break; 		prompt = 1;	}} do_snarf(del: int){	range := cmd(ed, ".b.t tag nextrange sel 1.0");	if(range == "" || (len range > 0 && range[0] == '!'))		return;	snarf = tk->cmd(ed, ".b.t get " + range);	if(del)		cmd(ed, ".b.t delete " + range);	tkclient->snarfput(snarf);} do_paste(){	snarf = tkclient->snarfget();	if(snarf == "")		return;	cmd(ed, ".b.t insert insert '" + snarf);} do_search(prompt: int) : int{	if(prompt == SEARCHFOR)		searchfor = dialog->getstring(context, ed.image, "Search For");	if(searchfor == "")		return 0;	cmd(ed, "cursor -bitmap cursor.wait");	ix := cmd(ed, ".b.t search -- " + tk->quote(searchfor) + " insert+1c");	if(ix != "" && len ix > 1 && ix[0] != '!') {		cmd(ed, ".b.t tag remove sel 0.0 end");		cmd(ed, ".b.t mark set anchor " + ix);		cmd(ed, ".b.t mark set insert " + ix);		cmd(ed, ".b.t tag add sel " + ix + " " + ix + "+" +						string(len searchfor) + "c");		if ( prompt != NOSEE )			cmd(ed, ".b.t see " + ix);		cmd(ed, "cursor -default");		return 1;	}	cmd(ed, "cursor -default");	return 0;} do_replace(prompt : int)

Lines 1–500 of 730.