ed

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

main.ha (2281B)


      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 	for (true) :repl {
     91 		if (s.promptmode)
     92 			fmt::error(s.prompt)!;
     93 
     94 		const cmd = match (parse(&input)) {
     95 		case let c: Command =>
     96 			yield c;
     97 		case io::EOF =>
     98 			yield Command{ name = 'q', ... };
     99 		case let e: ParseError =>
    100 			errormsg(&s, strerror(e));
    101 			continue;
    102 		};
    103 			defer command_finish(&cmd);
    104 
    105 		if (cmd.name == '&') {
    106 			errormsg(&s, '&': UnknownCommand);
    107 			continue;
    108 		};
    109 
    110 		match (execute(&s, &cmd)) {
    111 		case Quit =>
    112 			debug("main() Quit");
    113 			break;
    114 		case =>
    115 			void;
    116 		};
    117 	};
    118 };
    119 
    120 fn exit_usage() never = {
    121 	getopt::printusage(os::stderr, os::args[0], proghelp)!;
    122 	os::exit(1);
    123 };