1 | # lognestmonster Copyright (c) 2019 Joshua 'joshuas3' Stockin |
2 | # <https://github.com/JoshuaS3/lognestmonster/>. |
3 |
|
4 |
|
5 | # This file is part of lognestmonster. |
6 |
|
7 | # lognestmonster is free software: you can redistribute it and/or modify |
8 | # it under the terms of the GNU General Public License as published by |
9 | # the Free Software Foundation, either version 3 of the License, or |
10 | # (at your option) any later version. |
11 |
|
12 | # lognestmonster is distributed in the hope that it will be useful, |
13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
15 | # GNU General Public License for more details. |
16 |
|
17 | # You should have received a copy of the GNU General Public License |
18 | # along with lognestmonster. If not, see <https://www.gnu.org/licenses/>. |
19 |
|
20 | import os |
21 | import sys |
22 | from utils import * |
23 | from format import * |
24 | from text import * |
25 | from args import * |
26 | from parseargs import * |
27 | from read import * |
28 |
|
29 | class Parser: |
30 | screen = None |
31 | clines = None |
32 | ccols = None |
33 | lines = None |
34 | def __init__(self): |
35 | self.screen = curses_window() |
36 | self.get_size() |
37 |
|
38 | def get_size(self): |
39 | size = term_size() |
40 | self.clines = size[0] |
41 | self.ccols = size[1] |
42 |
|
43 | def redraw(self): |
44 | self.get_size() |
45 | curses_clear(self.screen) |
46 | l = 0 |
47 | for line in self.lines: |
48 | if l == self.clines: break |
49 | self.screen.move(l, 0) |
50 | s = "" |
51 | for string in line: |
52 | # ("content string", "attributes string") |
53 | content = string[0] |
54 | s += content |
55 |
|
56 | self.screen.attrset(0) |
57 |
|
58 | try: |
59 | attr = string[1] |
60 | except: |
61 | attr = "" |
62 |
|
63 | if "RESET" in attr: # set curses attributes based on attributes string |
64 | self.screen.attron(curses.color_pair(0)) |
65 | else: |
66 | if "BLACK" in attr: |
67 | self.screen.attron(curses.color_pair(1)) |
68 | if "BLUE" in attr: |
69 | self.screen.attron(curses.color_pair(2)) |
70 | if "CYAN" in attr: |
71 | self.screen.attron(curses.color_pair(3)) |
72 | if "GREEN" in attr: |
73 | self.screen.attron(curses.color_pair(4)) |
74 | if "MAGENTA" in attr: |
75 | self.screen.attron(curses.color_pair(5)) |
76 | if "RED" in attr: |
77 | self.screen.attron(curses.color_pair(6)) |
78 | if "WHITE" in attr: |
79 | self.screen.attron(curses.color_pair(7)) |
80 | if "YELLOW" in attr: |
81 | self.screen.attron(curses.color_pair(8)) |
82 | if "BOLD" in attr: |
83 | self.screen.attron(curses.A_BOLD) |
84 | if "STANDOUT" in attr: |
85 | self.screen.attron(curses.A_STANDOUT) |
86 | if "UNDERLINE" in attr: |
87 | self.screen.attron(curses.A_UNDERLINE) |
88 |
|
89 | self.screen.addstr(content[:self.ccols - len(s)]) |
90 | self.screen.attrset(0) |
91 | l += 1 |
92 | curses_refresh(self.screen) |
93 |
|
94 | def get_input(self): |
95 | input = getch() |
96 | if input == UP: input = "up" |
97 | elif input == DOWN: input = "down" |
98 | elif input == LEFT: input = "left" |
99 | elif input == RIGHT: input = "right" |
100 | elif input == CTRLC: input = "exit" |
101 | else: input = str(input).lower() |
102 | return input |
103 |
|
104 | folder_name = "log_1565561768719" |
105 | divider = " | " |
106 | title = TITLE |
107 |
|
108 | def loop(self): |
109 | def tab(string, count=1): |
110 | return " "*count + string |
111 | input = None |
112 | try: |
113 | while True: |
114 | self.get_size() |
115 | screen_width = self.ccols |
116 |
|
117 | self.lines = [ |
118 | [(self.title + " - ", "RESET"), (self.folder_name, "BOLD YELLOW")], |
119 | "Size: 235 bytes | Timestamp: 1565561768719", |
120 | "7 Statements | 2 Events | 0 Unsaved Data Trees", |
121 | pad(" STATEMENT 5 ", ":", screen_width), |
122 | "", |
123 | "[[LOG START]]", |
124 | "v 7 ITEMS", |
125 | tab("1565561768752 - INFO - INIT - HELLO"), |
126 | tab("1565561768752 - INFO - INIT - HELLO"), |
127 | tab("v 4 ITEMS"), |
128 | tab("1565561768752 - INFO - INIT - HELLO", 2), |
129 | tab("1565561768752 - INFO - INIT - HELLO", 2), |
130 | "", |
131 | [(tab("1565561768752 - INFO - INIT - HELLO", 2), "BOLD")], |
132 | "", |
133 | tab("1565561768752 - INFO - INIT - HELLO", 2), |
134 | tab("1565561768752 - INFO - INIT - HELLO"), |
135 | "", |
136 | str(input), |
137 | "[[LOG END]", |
138 | "", |
139 | "", |
140 | "", |
141 | pad(margin(CONTROLS_MESSAGE), ":", screen_width) |
142 | ] |
143 | self.redraw() |
144 |
|
145 | input = self.get_input() |
146 |
|
147 | if input == "exit" or input == "q": # exit program on Ctrl + C or `q` |
148 | break; |
149 | finally: |
150 | curses_reset() |
151 |
|
152 | def main(): |
153 | options = parseargs(sys.argv[1:]) |
154 |
|
155 | display_help = "help" in options |
156 | display_version = "version" in options |
157 | is_status = "status" in options |
158 |
|
159 | screen_size = term_size() |
160 | clines = screen_size[0] |
161 | ccols = screen_size[1] - 2 |
162 |
|
163 | if display_help: |
164 | output(VERSION_SHORT) |
165 |
|
166 | usage = [] |
167 | line = "usage: lognestmonster " |
168 | x = len(line) |
169 | width = ccols - x |
170 | wrapped = wrap(USAGE_MESSAGE, width, "&") |
171 | for l in wrapped: |
172 | line += l |
173 | usage.append(line) |
174 | line = (" "*x) |
175 | output_lines(usage) |
176 |
|
177 | output() |
178 |
|
179 | for paragraph in COMMAND_INFO.split("\n\n"): |
180 | output_lines(wrap(paragraph, ccols)) |
181 |
|
182 | output() |
183 |
|
184 | args = [] |
185 |
|
186 | div1 = ccols/3 |
187 | div2 = ccols/3*2 |
188 | for arg in ARGUMENT_OPTIONS: |
189 | arg_lines = [] |
190 | indicators = wrap(", ".join(ARGUMENT_OPTIONS[arg]["indicators"]), div1) |
191 | description = wrap(ARGUMENT_OPTIONS[arg]["description"], div2) |
192 | l1 = indicators[0] |
193 | z = 0 |
194 | for line in description: |
195 | try: |
196 | l1 = indicators[z] |
197 | except: |
198 | l1 = "" |
199 | z += 1 |
200 | l = columnize([(div1, l1), (div2, line)], ccols) |
201 | arg_lines.append(l) |
202 | args += arg_lines |
203 |
|
204 | output_lines(args) |
205 | output() |
206 | output(DESCRIPTION_PYTHON_VERSION) |
207 | return |
208 | elif display_version: |
209 | output(VERSION_MESSAGE) |
210 | return |
211 | elif len(sys.argv) == 1 or type(options) is str: # argument error or no args passed |
212 | exitcode = 0 |
213 | output(VERSION_SHORT) |
214 | if type(options) is str: # print argument error is exists |
215 | output(options) |
216 | exitcode = 1 |
217 | output(HELP_MESSAGE) |
218 | exit(exitcode) |
219 |
|
220 | positional = sys.argv[-1] |
221 | if positional is not "-" and os.path.isfile(positional) is not True and os.path.isdir(positional) is not True: |
222 | output(VERSION_SHORT) |
223 | output(TEXT_RED + "error:" + RESET + " file unknown '" + positional + "'") |
224 | output(HELP_MESSAGE) |
225 | exit(1) |
226 |
|
227 | if positional is "-": positional = "stdin" |
228 |
|
229 | output("args: " + str(options)) |
230 | output("file: " + positional) |
231 |
|
232 | if positional is "stdin": |
233 | fd = sys.stdin |
234 | else: |
235 | try: |
236 | fd = open(positional, "rb") |
237 | except: |
238 | output(TEXT_RED + "error:" + RESET + " unable to open file") |
239 | exit(1) |
240 |
|
241 | if not is_status: |
242 | p = Parser() |
243 | p.folder_name = positional |
244 | p.loop() |
245 | else: |
246 | r = Reader(fd) |
247 |
|
248 | fd.close() |
249 |
|
250 |
|
251 | if __name__ == "__main__": |
252 | main() |
253 |
|