ed

[hare] The standard editor
Log | Files | Refs | README | LICENSE

main.ha (2358B)


      1 use bufio;
      2 use fmt;
      3 use getopt;
      4 use io;
      5 use os;
      6 use strings;
      7 use types;
      8 
      9 type Session = struct{
     10 	input: *bufio::scanner,
     11 	buf: *Buffer,
     12 
     13 	prompt: str,
     14 	promptmode: bool,
     15 	suppressmode: bool,
     16 	helpmode: bool,
     17 	undomode: UndoMode,
     18 
     19 	warned: bool,
     20 	lasterror: (void | Error),
     21 	lastregex: (void | str),
     22 	lastshcmd: (void | str),
     23 };
     24 
     25 def proghelp: [_]getopt::help = [
     26 	"standard line editor",
     27 	('p', "prompt", "set the command prompt"),
     28 	('s', "suppress byte counts and '!' prompt"),
     29 	"[file]",
     30 ];
     31 
     32 export fn main() void = {
     33 	const progcmd = getopt::parse(os::args, proghelp...);
     34 		defer getopt::finish(&progcmd);
     35 
     36 	const input = bufio::newscanner(os::stdin, types::SIZE_MAX);
     37 		defer bufio::finish(&input);
     38 
     39 	const buffer = Buffer{
     40 		lines = alloc([ alloc(Line{ ... }) ]...),
     41 		trash = alloc([]: []*Line...),
     42 		hist = alloc([]: History...),
     43 		...
     44 	};
     45 		defer buffer_finish(&buffer);
     46 
     47 	let s = Session{
     48 		input = &input,
     49 		buf = &buffer,
     50 		prompt = "*",
     51 		lasterror = void,
     52 		lastregex = void,
     53 		lastshcmd = void,
     54 		...
     55 	};
     56 
     57 	for (let i = 0z; i < len(progcmd.opts); i += 1) {
     58 		const opt = progcmd.opts[i];
     59 		switch (opt.0) {
     60 		case 'p' =>
     61 			s.prompt = opt.1;
     62 			s.promptmode = true;
     63 		case 's' =>
     64 			s.suppressmode = true;
     65 		case =>
     66 			abort();
     67 		};
     68 	};
     69 
     70 	if (len(progcmd.args) > 1)
     71 		exit_usage();
     72 
     73 	if (len(progcmd.args) == 1)
     74 		switch (progcmd.args[0]) {
     75 		case "-" =>
     76 			return fmt::errorln("Invalid filename '-'"): void;
     77 		case "" =>
     78 			return fmt::errorln("Invalid filename ''"): void;
     79 		case =>
     80 			s.buf.filename = strings::dup(progcmd.args[0]);
     81 		};
     82 
     83 	if (s.buf.filename != "")
     84 		execute(&s, &Command{
     85 			name = 'e',
     86 			arg1 = strings::dup(s.buf.filename),
     87 			...
     88 		}): void;
     89 
     90 	handle_signals();
     91 
     92 	for (true) :repl {
     93 		if (s.promptmode)
     94 			fmt::error(s.prompt)!;
     95 
     96 		const cmd = match (parse(&input)) {
     97 		case let c: Command =>
     98 			yield c;
     99 		case io::EOF =>
    100 			yield Command{ name = 'q', ... };
    101 		case let e: ParseError =>
    102 			errormsg(&s, e);
    103 			continue;
    104 		case let e: InteractionError =>
    105 			errormsg(&s, e);
    106 			continue;
    107 		};
    108 			defer command_finish(&cmd);
    109 
    110 		if (cmd.name == '&') {
    111 			errormsg(&s, '&': UnknownCommand);
    112 			continue;
    113 		};
    114 
    115 		match (execute(&s, &cmd)) {
    116 		case Quit =>
    117 			debug("main() Quit");
    118 			break;
    119 		case =>
    120 			void;
    121 		};
    122 	};
    123 };
    124 
    125 fn exit_usage() never = {
    126 	getopt::printusage(os::stderr, os::args[0], proghelp)!;
    127 	os::exit(1);
    128 };