1 /** 2 * Reference: 3 * https://github.com/antirez/linenoise 4 * http://invisible-island.net/xterm/ctlseqs/ctlseqs.html 5 * http://www.3waylabs.com/nw/WWW/products/wizcon/vt220.html 6 **/ 7 module vrepl.repl; 8 9 import std.stdio: write, writeln; 10 import std.conv: to; 11 import dutil.containers; 12 import std.process; 13 import vrepl.shell; 14 15 alias StringSet = HashSet!string; 16 17 enum SIGTTIN = 21; 18 enum SIGTTOU = 22; 19 enum ES_CLEAR = "\x1b[H\x1b[2J"; 20 enum ES_BEEP = "\x07"; 21 enum Mode { SHELL, LINE, MLINE, EDIT } 22 23 class State { 24 Mode mode = Mode.LINE; 25 } 26 27 extern(C) void sig_hand(int signal) nothrow @nogc @system { 28 import core.stdc.stdio: printf; 29 printf("signal %d catched!\n", signal); 30 } 31 32 class Config { 33 string[Mode] prompt; 34 StringSet quits; 35 void delegate(string) onInput; 36 37 this() { 38 with(Mode) prompt = [ 39 SHELL: "$", 40 LINE: ">", 41 MLINE: ">>", 42 EDIT: "*>" 43 ]; 44 45 quits.add("quit", "bye", "exit"); 46 } 47 } 48 49 class Vrepl { 50 Config config; 51 State state; 52 Shell shell; 53 54 this() { 55 config = new Config(); 56 state = new State(); 57 shell = new Shell(); 58 } 59 60 void setMode(Mode m) { 61 this.state.mode = m; 62 } 63 64 void prompt() { 65 if (state.mode == Mode.SHELL) { 66 write(config.prompt[Mode.SHELL] ~ " "); 67 } else { 68 write(config.prompt[state.mode] ~ " "); 69 } 70 } 71 72 bool checkMode(string line) { 73 import std.string: chomp; 74 if (line == "mode shell") { 75 state.mode = Mode.SHELL; 76 writeln("Change Mode: ", "shell"); 77 return false; 78 } else if (line == "mode line") { 79 state.mode = Mode.LINE; 80 writeln("Change Mode: ", "line"); 81 return false; 82 } else if (line.chomp == "") { 83 writeln("empty"); 84 return false; 85 } else { 86 return true; 87 } 88 } 89 90 void quit() { } 91 92 bool isQuit(string line) { 93 return config.quits.contains(line); 94 } 95 96 ProcessPipes pipes; 97 void loop() { 98 import std.string: chomp; 99 import std.stdio: stdin, readln; 100 101 /* 102 import core.stdc.signal; 103 signal(SIGTTIN, &sig_hand); 104 signal(SIGTTOU, &sig_hand); 105 */ 106 string line; 107 prompt(); 108 while ((line = stdin.readln) !is null) { 109 110 line = line.chomp; 111 if (isQuit(line)) return; 112 if (!checkMode(line)) { 113 prompt(); 114 continue; 115 } 116 with (Mode) switch (state.mode) { 117 case LINE: 118 if (line == "clear") { 119 writeln(ES_CLEAR); 120 } else if (line == "beep") { 121 writeln(ES_BEEP); 122 } else { 123 if (config.onInput != null) { 124 config.onInput(line); 125 } else { 126 writeln("your wrote:", line); 127 } 128 } 129 prompt(); 130 quit(); 131 break; 132 case SHELL: 133 { 134 write(shell.send(line)); 135 } 136 prompt(); 137 break; 138 default: 139 break; 140 } 141 quit(); 142 143 } 144 } 145 146 }