From a5a7e24d4f7d0e1211d79c63030b37590b318dec Mon Sep 17 00:00:00 2001 From: Andrew Hamilton Date: Fri, 20 Apr 2018 17:59:18 +1000 Subject: [PATCH] tools: Executables attribute is redundant in the yaml file. The executables is determined by the command. --- vigil/__main__.py | 38 +++++++++++++++++++++- vigil/fill3.py | 11 +++++++ vigil/termstr.py | 28 +++++++++++++--- vigil/tools.py | 11 +++++-- vigil/tools.yaml | 17 ---------- vigil/vigil-webserver.py | 69 ++++++++++++++++++++++++++++++++++++++++ 6 files changed, 149 insertions(+), 25 deletions(-) create mode 100755 vigil/vigil-webserver.py diff --git a/vigil/__main__.py b/vigil/__main__.py index 9e2fadf..963f114 100755 --- a/vigil/__main__.py +++ b/vigil/__main__.py @@ -117,6 +117,11 @@ class Entry(collections.UserList): self.appearance_cache = appearance = new_appearance return appearance + def as_html(self): + return ("%s%s" % + ("".join(result.as_html() for result in self.widget), + self.path)) + def is_path_excluded(path): return any(part.startswith(".") for part in path.split(os.path.sep)) @@ -185,6 +190,17 @@ def get_diff_stats(old_files, new_files): return added_count, removed_count, modified_count +def appearance_as_html(appearance): + lines = [] + all_styles = set() + for line in appearance: + html, styles = termstr.TermStr(line).as_html() + all_styles.update(styles) + lines.append(html) + return ("\n".join(style.as_html() for style in all_styles) + + '\n
' + "
".join(lines) + "
") + + class Summary: def __init__(self, root_path, jobs_added_event): @@ -420,6 +436,11 @@ class Summary: if result.tool == tool: self.refresh_result(result) + def as_html(self): + return ("
%s
" % + "\n".join("%s" % row.as_html() + for row in self._column)) + class Log: @@ -773,6 +794,20 @@ class Screen: def toggle_fullscreen(self): self._is_fullscreen = not self._is_fullscreen + def to_html(self): + with open("tester.html", "w") as tester: + tester.write("") + # tester.write(appearance_as_html(self._listing.appearance((100,300)))) + # tester.write(appearance_as_html(self.appearance((100,100)))) + tester.write(appearance_as_html(fill3.Border(self._summary.get_selection().result).appearance_min())) + tester.write("") + + def summary_to_html(self): + with open("tester.html", "w") as tester: + tester.write("") + tester.write(self._summary.as_html()) + tester.write("") + def _select_entry_at_position(self, x, y, view_width, view_height): border_width = 1 if x < border_width or y < border_width or x > view_width or \ @@ -900,7 +935,8 @@ class Screen: ({"N"}, move_to_next_issue_of_tool), ({"e"}, edit_file), ({"q"}, quit_), ({"p"}, toggle_pause), ({"r"}, refresh), ({"R"}, refresh_tool), ({"tab"}, toggle_focus), - ({"f"}, toggle_fullscreen)] + ({"f"}, toggle_fullscreen), ({"H"}, to_html), + ({"S"}, summary_to_html)] def add_watch_manager_to_mainloop(root_path, mainloop, on_filesystem_change, diff --git a/vigil/fill3.py b/vigil/fill3.py index ecd2dac..2921f52 100644 --- a/vigil/fill3.py +++ b/vigil/fill3.py @@ -72,6 +72,17 @@ def even_widths(column_widgets, width): return widths +def appearance_as_html(appearance): + lines = [] + all_styles = set() + for line in appearance: + html, styles = termstr.TermStr(line).as_html() + all_styles.update(styles) + lines.append(html) + return ("\n".join(style.as_html() for style in all_styles) + + '\n
' + "
".join(lines) + "
") + + class Row(collections.UserList): def __init__(self, widgets, widths_func=even_widths): diff --git a/vigil/termstr.py b/vigil/termstr.py index c94fd4d..1c27bd7 100644 --- a/vigil/termstr.py +++ b/vigil/termstr.py @@ -3,6 +3,7 @@ # Licensed under the Artistic License 2.0. import collections +import html import itertools import os import weakref @@ -102,6 +103,16 @@ class CharStyle: return "".join([terminal.normal, fg_termcode, bg_termcode, bold_code, italic_code, underline_code]) + def as_html(self): + bold_code = "font-weight:bold; " if self.is_bold else "" + italic_code = "font-style:italic; " if self.is_italic else "" + underline_code = ("text-decoration:underline; " + if self.is_underlined else "") + return ("" % + (id(self), self.fg_color, self.bg_color, bold_code, + italic_code, underline_code)) + def _join_lists(lists): return list(itertools.chain.from_iterable(lists)) @@ -110,10 +121,9 @@ def _join_lists(lists): class TermStr(collections.UserString): def __init__(self, data, style=CharStyle()): - if isinstance(data, self.__class__): - self.data = data.data - self.style = data.style - else: + try: + self.data, self.style = data.data, data.style + except AttributeError: self.data = data self.style = (style if isinstance(style, tuple) else (style,) * len(data)) @@ -262,3 +272,13 @@ class TermStr(collections.UserString): return CharStyle(style.fg_color, bg_color, is_bold=style.is_bold, is_underlined=style.is_underlined) return self.transform_style(set_bgcolor) + + def as_html(self): + result = [] + styles = set() + for style, str_, position in self._partition_style(): + styles.add(style) + encoded = str(html.escape(str_).encode("ascii", "xmlcharrefreplace"))[2:-1] + encoded = encoded.replace("\\\\", "\\") + result.append('%s' % (id(style), encoded)) + return "".join(result), styles diff --git a/vigil/tools.py b/vigil/tools.py index fb4991b..91badf5 100644 --- a/vigil/tools.py +++ b/vigil/tools.py @@ -634,12 +634,13 @@ def godoc(path): return Status.normal, fill3.Text(stdout) -def make_tool_function(dependencies, url, executables, command, - success_status=None, error_status=None): +def make_tool_function(dependencies, url, command, success_status=None, + error_status=None): command = command.split() + executables = set([command[0]]) success_status = None if success_status is None else Status[success_status] error_status = None if error_status is None else Status[error_status] - @deps(deps=set(dependencies), url=url, executables=set(executables)) + @deps(deps=set(dependencies), url=url, executables=executables) def func(path): return _run_command(command + [path], success_status, error_status) return func @@ -770,6 +771,10 @@ class Result: def appearance_min(self): return [status_to_str(self.status)] + def as_html(self): + html, styles = termstr.TermStr(status_to_str(self.status)).as_html() + return '%s' % html + def generic_tools(): return [contents, metadata] diff --git a/vigil/tools.yaml b/vigil/tools.yaml index 99eaf5b..67939e6 100644 --- a/vigil/tools.yaml +++ b/vigil/tools.yaml @@ -4,7 +4,6 @@ # : # dependencies: [] # url: -# executables: [] # command: # success_status: # error_status: @@ -13,106 +12,90 @@ objdump_headers: dependencies: [binutils] url: https://en.wikipedia.org/wiki/Objdump - executables: [objdump] command: objdump --all-headers success_status: normal objdump_disassemble: dependencies: [binutils] url: https://en.wikipedia.org/wiki/Objdump - executables: [objdump] command: objdump --disassemble --reloc --dynamic-reloc success_status: normal readelf: dependencies: [binutils] url: https://en.wikipedia.org/wiki/Objdump - executables: [readelf] command: readelf --all success_status: normal unzip: dependencies: [unzip] url: unzip - executables: [unzip] command: unzip -l success_status: normal tar_gz: dependencies: [tar] url: http://www.gnu.org/software/tar/manual/tar.html - executables: [tar] command: tar ztvf success_status: normal tar_bz2: dependencies: [tar] url: http://www.gnu.org/software/tar/manual/tar.html - executables: [tar] command: tar jtvf success_status: normal nm: dependencies: [binutils] url: https://linux.die.net/man/1/nm - executables: [nm] command: nm --demangle success_status: normal pdf2txt: dependencies: [python-pdfminer] url: python-pdfminer - executables: [pdf2txt] command: pdf2txt success_status: normal html2text: dependencies: [html2text] url: html2text - executables: [html2text] command: html2text success_status: normal c_syntax_gcc: dependencies: [gcc, g++-6] url: https://gcc.gnu.org/ - executables: [gcc] command: gcc -fsyntax-only cpp_syntax_gcc: dependencies: [gcc, g++-6] url: https://gcc.gnu.org/ - executables: [gcc] command: gcc -fsyntax-only php7_syntax: dependencies: [php7.2-cli] url: https://en.wikipedia.org/wiki/PHP - executables: [php7.2] command: php7.2 --syntax-check shellcheck: dependencies: [shellcheck] url: shellcheck - executables: [shellcheck] command: shellcheck cppcheck: dependencies: [cppcheck] url: cppcheck - executables: [cppcheck] command: cppcheck gofmt: dependencies: [golang-go] url: golang-go - executables: [gofmt] command: gofmt success_status: normal go_vet: dependencies: [golang-go] url: golang-go - executables: [go] command: go vet error_status: normal diff --git a/vigil/vigil-webserver.py b/vigil/vigil-webserver.py new file mode 100755 index 0000000..1d9a64b --- /dev/null +++ b/vigil/vigil-webserver.py @@ -0,0 +1,69 @@ +#!/usr/bin/env python3.6 + + +import gzip +import http.server +import os +import pickle +import sys + +import fill3 +import termstr +import tools + + +def appearance_as_html(appearance): + lines = [] + all_styles = set() + for line in appearance: + html, styles = termstr.TermStr(line).as_html() + all_styles.update(styles) + lines.append(html) + return ("\n".join(style.as_html() for style in all_styles) + + '\n
' + "
".join(lines) + "
") + + +def make_page(widget): + body = appearance_as_html(fill3.Border(widget).appearance_min()) + return ("%s" % body).encode("utf-8") + + +class Webserver(http.server.BaseHTTPRequestHandler): + + def _set_headers(self): + self.send_response(200) + self.send_header("Content-type", "text/html") + self.end_headers() + + def do_GET(self): + self._set_headers() + if self.path == "/": + page = make_page(summary_column) + elif "/" in self.path[1:]: + row, column = [int(value) for value in self.path[1:].split("/")] + page = make_page(summary_column[row][column].result) + else: + return + self.wfile.write(page) + + def do_HEAD(self): + self._set_headers() + + def do_POST(self): + self._set_headers() + self.wfile.write("posted".encode("utf-8")) + + +def run(server_class=http.server.HTTPServer, handler_class=Webserver, port=80): + server_address = ("", port) + httpd = server_class(server_address, handler_class) + print("Starting httpd...") + httpd.serve_forever() + + +if __name__ == "__main__": + pickle_path = os.path.join(tools.CACHE_PATH, "summary.pickle") + with gzip.open(pickle_path, "rb") as file_: + screen = pickle.load(file_) + summary_column = screen._summary._column + run()