1 module dinu.content.output; 2 3 import 4 std.file, 5 std.datetime, 6 std.stream, 7 std.parallelism, 8 std.process, 9 std.conv, 10 std.regex, 11 std..string, 12 std.stdio, 13 dinu.dinu, 14 dinu.util, 15 dinu.xclient, 16 dinu.content.content, 17 dinu.content.executables, 18 dinu.content.files, 19 dinu.command, 20 dinu.draw; 21 22 23 __gshared: 24 25 26 private { 27 CommandHistory[int] running; 28 int[int] results; 29 } 30 31 32 class OutputLoader: ChoiceLoader { 33 34 override void run(){ 35 auto log = options.configPath ~ ".log"; 36 while(!log.exists && active && runProgram) 37 core.thread.Thread.sleep(10.msecs); 38 auto file = new BufferedFile(log); 39 file.seekEnd(0); 40 size_t idx = 10000; 41 task(&loadBackwards, idx-1000).executeInNewThread; 42 while(active && runProgram){ 43 if(!file.eof){ 44 auto line = cast(string)file.readLine; 45 if(!line.length) 46 continue; 47 matchLine(line, idx++); 48 }else 49 core.thread.Thread.sleep(5.msecs); 50 } 51 } 52 53 void loadBackwards(size_t idx){ 54 auto p = pipeProcess(["tac", options.configPath ~ ".log"], Redirect.stdout); 55 foreach(line; p.stdout.byLine){ 56 matchLine(to!string(line), idx--); 57 if(idx<10000-2000) 58 core.thread.Thread.sleep(4.msecs); 59 if(idx==0 || !runProgram) 60 break; 61 } 62 } 63 64 void matchLine(string line, size_t idx){ 65 try{ 66 foreach(match; line.matchAll(`([0-9]+) (\S+)(?: (.*))?`)){ 67 auto pid = to!int(match.captures[1]); 68 if(match.captures[2] == "exec"){ 69 auto cmd = match.captures[3].bangSplit; 70 auto history = new CommandHistory(idx, pid, to!Type(cmd[0]), cmd[1].dup, cmd[2].dup); 71 running[pid] = history; 72 if(pid in results){ 73 history.result = results[pid]; 74 }else if(!exists("/proc/%s".format(pid))){ 75 history.result = 0; 76 } 77 add(history); 78 } 79 if((match.captures[2] == "stdout" || match.captures[2] == "stderr") && match.captures[3].length){ 80 add(new CommandOutput(pid, match.captures[3], idx, match.captures[2]=="stderr")); 81 }else if(match.captures[2] == "exit"){ 82 if(pid in running) 83 running[pid].result = to!int(match.captures[3]); 84 else 85 results[pid] = to!int(match.captures[3]); 86 } 87 } 88 }catch(Exception e){ 89 writeln(e); 90 } 91 } 92 93 } 94 95 96 class CommandOutput: Command { 97 98 size_t idx; 99 string command; 100 int pid; 101 102 this(int pid, string output, size_t idx, bool err){ 103 super(output); 104 type = Type.output; 105 this.pid = pid; 106 this.idx = idx; 107 if(err) 108 color = options.colorError; 109 else 110 color = options.colorOutput; 111 } 112 113 override size_t score(){ 114 return idx*1000; 115 } 116 117 override int draw(DrawingContext dc, int[2] pos, bool selected){ 118 if(!command.length && pid in running) 119 command = running[pid].text; 120 dc.text(pos, command, options.colorHint, 1.8); 121 return super.draw(dc, pos, selected); 122 } 123 124 override void run(){} 125 126 } 127 128 129 class CommandHistory: Command { 130 131 size_t idx; 132 long result = long.max; 133 Type originalType; 134 Command command; 135 136 this(size_t idx, int pid, Type originalType, string serialized, string parameter){ 137 this.idx = idx; 138 this.parameter = parameter; 139 type = Type.history; 140 switch(originalType){ 141 case Type.script: 142 command = new CommandExec(serialized); 143 break; 144 case Type.desktop: 145 command = new CommandDesktop(serialized); 146 break; 147 case Type.file: 148 command = new CommandFile(serialized); 149 break; 150 case Type.directory: 151 command = new CommandDir(serialized); 152 break; 153 case Type.special: 154 command = new CommandSpecial(serialized); 155 break; 156 default: 157 command = new CommandExec(serialized); 158 break; 159 } 160 this.name = command.text; 161 } 162 163 override string filterText(){ 164 return super.filterText() ~ parameter; 165 } 166 167 override size_t score(){ 168 return idx*1000; 169 } 170 171 override int draw(DrawingContext dc, int[2] pos, bool selected){ 172 auto origX = pos.x; 173 if(result != long.max){ 174 if(result) 175 dc.rect([pos.x-0.4.em,pos.y], [0.1.em, 1.em], options.colorError); 176 }else 177 dc.rect([pos.x-0.4.em,pos.y], [0.1.em, 1.em], options.colorHint); 178 pos.x += command.draw(dc, pos, selected); 179 if(parameter.length) 180 pos.x += dc.text(pos, parameter, options.colorOutput); 181 return pos.x-origX; 182 } 183 184 override void run(){ 185 auto paramOrig = command.parameter; 186 command.parameter ~= parameter; 187 command.run; 188 command.parameter = paramOrig; 189 } 190 191 }