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 };