class ExportHtml(object): def __init__(self, view): self.view = view def process_inputs(self, **kwargs): return { "numbers": bool(kwargs.get("numbers", False)), "highlight_selections": bool(kwargs.get("highlight_selections", False)), "browser_print": bool(kwargs.get("browser_print", False)), "color_scheme": kwargs.get("color_scheme", None), "wrap": kwargs.get("wrap", None), "multi_select": bool(kwargs.get("multi_select", False)), "style_gutter": bool(kwargs.get("style_gutter", True)), "no_header": bool(kwargs.get("no_header", False)), "date_time_format": kwargs.get("date_time_format", "%m/%d/%y %I:%M:%S"), "show_full_path": bool(kwargs.get("show_full_path", True)), "toolbar": kwargs.get("toolbar", ["plain_text", "gutter", "wrapping", "print", "annotation", "theme"]), "save_location": kwargs.get("save_location", None), "time_stamp": kwargs.get("time_stamp", "_%m%d%y%H%M%S"), "clipboard_copy": bool(kwargs.get("clipboard_copy", False)), "view_open": bool(kwargs.get("view_open", False)), "shift_brightness": bool(kwargs.get("shift_brightness", False)), "filter": kwargs.get("filter", ""), } def setup(self, **kwargs): # Get get general document preferences from sublime preferences eh_settings = sublime.load_settings(PACKAGE_SETTINGS) settings = sublime.load_settings("Preferences.sublime-settings") alternate_font_size = eh_settings.get("alternate_font_size", False) alternate_font_face = eh_settings.get("alternate_font_face", False) self.font_size = settings.get("font_size", 10) if alternate_font_size == False else alternate_font_size self.font_face = settings.get("font_face", "Consolas") if alternate_font_face == False else alternate_font_face self.tab_size = settings.get("tab_size", 4) self.padd_top = settings.get("line_padding_top", 0) self.padd_bottom = settings.get("line_padding_bottom", 0) self.char_limit = int(eh_settings.get("valid_selection_size", 4)) self.bground = "" self.fground = "" self.gbground = "" self.gfground = "" self.sbground = "" self.sfground = "" self.numbers = kwargs["numbers"] self.date_time_format = kwargs["date_time_format"] self.time = time.localtime() self.show_full_path = kwargs["show_full_path"] self.highlight_selections = kwargs["highlight_selections"] self.browser_print = kwargs["browser_print"] self.auto_wrap = kwargs["wrap"] != None and int(kwargs["wrap"]) > 0 self.wrap = 900 if not self.auto_wrap else int(kwargs["wrap"]) self.hl_continue = None self.curr_hl = None self.sels = [] self.multi_select = self.check_sel() if kwargs["multi_select"] and not kwargs["highlight_selections"] else False self.size = self.view.size() self.pt = 0 self.end = 0 self.curr_row = 0 self.tables = 0 self.curr_annot = None self.curr_comment = None self.annotations = self.get_annotations() self.annot_num = -1 self.new_annot = False self.open_annot = False self.no_header = kwargs["no_header"] self.annot_tbl = [] self.toolbar = kwargs["toolbar"] self.toolbar_orientation = ( "block" if eh_settings.get("toolbar_orientation", "horizontal") == "vertical" else "inline-block" ) self.matched = {} self.ebground = self.bground self.lumens_limit = float(eh_settings.get("bg_min_lumen_threshold", 62)) self.highlights = [] if self.highlight_selections: for sel in self.view.sel(): if not sel.empty(): self.highlights.append(sel) fname = self.view.file_name() if fname == None or not path.exists(fname): fname = "Untitled" self.file_name = fname # Get color scheme if kwargs["color_scheme"] != None: alt_scheme = kwargs["color_scheme"] else: alt_scheme = eh_settings.get("alternate_scheme", False) scheme_file = settings.get("color_scheme") if alt_scheme == False else alt_scheme self.csm = ColorSchemeMatcher( scheme_file, strip_trans=True, ignore_gutter=(not kwargs["style_gutter"]), track_dark_background=True, filter=(lambda x: ColorSchemeTweaker().tweak(x, kwargs["filter"])), ) if kwargs["shift_brightness"]: self.csm.shift_background_brightness(self.lumens_limit) ( self.bground, self.fground, self.sbground, self.sfground, self.gbground, self.gfground, ) = self.csm.get_general_colors() def get_tools(self, tools, use_annotation, use_wrapping): toolbar_options = { "gutter": TOOL_GUTTER, "print": TOOL_PRINT, "plain_text": TOOL_PLAIN_TEXT, "annotation": TOOL_ANNOTATION if use_annotation else "", "theme": TOOL_DUMP_THEME, "wrapping": TOOL_WRAPPING if use_wrapping else "", } t_opt = "" toolbar_element = "" if len(tools): for t in tools: if t in toolbar_options: t_opt += toolbar_options[t] toolbar_element = TOOLBAR % {"options": t_opt} return toolbar_element def setup_print_block(self, curr_sel, multi=False): # Determine start and end points and whether to parse whole file or selection if not multi and (curr_sel.empty() or self.highlight_selections or curr_sel.size() <= self.char_limit): self.size = self.view.size() self.pt = 0 self.end = 1 self.curr_row = 1 else: self.size = curr_sel.end() self.pt = curr_sel.begin() self.end = self.pt + 1 self.curr_row = self.view.rowcol(self.pt)[0] + 1 self.start_line = self.curr_row self.gutter_pad = len(str(self.view.rowcol(self.size)[0])) + 1 def check_sel(self): multi = False for sel in self.view.sel(): if not sel.empty() and sel.size() >= self.char_limit: multi = True self.sels.append(sel) return multi def print_line(self, line, num): html_line = LINE % { "line_id": num, "color": self.gfground, "bgcolor": self.gbground, "line": str(num).rjust(self.gutter_pad).replace(" ", " "), "code_id": num, "code": line, "table": self.tables, "pad_color": self.ebground or self.bground, } return html_line def write_header(self, the_html): header = HTML_HEADER % { "title": path.basename(self.file_name), "css": getcss( "export.css", { "font_size": str(self.font_size), "font_face": '"' + self.font_face + '"', "page_bg": self.bground, "gutter_bg": self.gbground, "body_fg": self.fground, "display_mode": "table-cell" if self.numbers else "none", "dot_color": self.fground, "toolbar_orientation": self.toolbar_orientation, }, ), "js": INCLUDE_THEME % { "jscode": getjs("plist.js"), "theme": json.dumps(self.csm.get_plist_file(), sort_keys=True, indent=4, separators=(",", ": ")).encode( "raw_unicode_escape" ), "name": self.csm.get_scheme_file(), }, } the_html.write(header) def convert_view_to_html(self, the_html): for line in self.view.split_by_newlines(sublime.Region(self.pt, self.size)): self.size = line.end() empty = not bool(line.size()) line = self.convert_line_to_html(the_html, empty) the_html.write(self.print_line(line, self.curr_row)) self.curr_row += 1 def html_encode(self, text): # Format text to HTML encode_table = {"&": "&", ">": ">", "<": "<", "\t": " " * self.tab_size, "\n": ""} return re.sub( r"(?!\s($|\S))\s", " ", "".join(encode_table.get(c, c) for c in text).encode("ascii", "xmlcharrefreplace"), ) def get_annotations(self): annotations = get_annotations(self.view) comments = [] for x in range(0, int(annotations["count"])): region = annotations["annotations"]["html_annotation_%d" % x]["region"] comments.append((region, annotations["annotations"]["html_annotation_%d" % x]["comment"])) comments.sort() return comments def annotate_text(self, line, the_colour, the_bgcolour, the_style, empty): pre_text = None annot_text = None post_text = None start = None # Pretext Check if self.pt >= self.curr_annot.begin(): # Region starts with an annotation start = self.pt else: # Region has text before annoation pre_text = self.html_encode(self.view.substr(sublime.Region(self.pt, self.curr_annot.begin()))) start = self.curr_annot.begin() if self.end == self.curr_annot.end(): # Region ends annotation annot_text = self.html_encode(self.view.substr(sublime.Region(start, self.end))) self.curr_annot = None elif self.end > self.curr_annot.end(): # Region has text following annotation annot_text = self.html_encode(self.view.substr(sublime.Region(start, self.curr_annot.end()))) post_text = self.html_encode(self.view.substr(sublime.Region(self.curr_annot.end(), self.end))) self.curr_annot = None else: # Region ends but annotation is not finished annot_text = self.html_encode(self.view.substr(sublime.Region(start, self.end))) self.curr_annot = sublime.Region(self.end, self.curr_annot.end()) # Print the separate parts pre text, annotation, post text if pre_text != None: self.format_text(line, pre_text, the_colour, the_bgcolour, the_style, empty) if annot_text != None: self.format_text(line, annot_text, the_colour, the_bgcolour, the_style, empty, annotate=True) if self.curr_annot == None: self.curr_comment = None if post_text != None: self.format_text(line, post_text, the_colour, the_bgcolour, the_style, empty) def add_annotation_table_entry(self): row, col = self.view.rowcol(self.annot_pt) self.annot_tbl.append( ( self.tables, self.curr_row, "Line %d Col %d" % (row + 1, col + 1), self.curr_comment.encode("ascii", "xmlcharrefreplace"), ) ) self.annot_pt = None def format_text(self, line, text, the_colour, the_bgcolour, the_style, empty, annotate=False): if empty: text = " " else: the_style += " real_text" if the_bgcolour is None: the_bgcolour = self.bground if annotate: code = ANNOTATION_CODE % { "highlight": the_bgcolour, "color": the_colour, "content": text, "class": the_style, } else: code = CODE % {"highlight": the_bgcolour, "color": the_colour, "content": text, "class": the_style} if annotate: if self.curr_annot != None and not self.open_annot: # Open an annotation if self.annot_pt != None: self.add_annotation_table_entry() if self.new_annot: self.annot_num += 1 self.new_annot = False code = ANNOTATE_OPEN % {"code": code, "comment": str(self.annot_num)} self.open_annot = True elif self.curr_annot == None: if self.open_annot: # Close an annotation code += ANNOTATE_CLOSE self.open_annot = False else: # Do a complete annotation if self.annot_pt != None: self.add_annotation_table_entry() if self.new_annot: self.annot_num += 1 self.new_annot = False code = ANNOTATE_OPEN % {"code": code, "comment": str(self.annot_num)} + ANNOTATE_CLOSE line.append(code) def convert_line_to_html(self, the_html, empty): line = [] hl_done = False # Continue highlight form last line if self.hl_continue != None: self.curr_hl = self.hl_continue self.hl_continue = None while self.end <= self.size: # Get next highlight region if self.highlight_selections and self.curr_hl == None and len(self.highlights) > 0: self.curr_hl = self.highlights.pop(0) # See if we are starting a highlight region if self.curr_hl != None and self.pt == self.curr_hl.begin(): # Get text of like scope up to a highlight scope_name = self.view.scope_name(self.pt) while self.view.scope_name(self.end) == scope_name and self.end < self.size: # Kick out if we hit a highlight region if self.end == self.curr_hl.end(): break self.end += 1 if self.end < self.curr_hl.end(): if self.end >= self.size: self.hl_continue = sublime.Region(self.end, self.curr_hl.end()) else: self.curr_hl = sublime.Region(self.end, self.curr_hl.end()) else: hl_done = True if hl_done and empty: the_colour, the_style, the_bgcolour, _, _, _ = self.csm.guess_color(self.view, self.pt, scope_name) elif self.sfground is None: the_colour, the_style, _, _, _, _ = self.csm.guess_color(self.view, self.pt, scope_name) the_bgcolour = self.sbground else: the_colour, the_style = self.sfground, "normal" the_bgcolour = self.sbground else: # Get text of like scope up to a highlight scope_name = self.view.scope_name(self.pt) while self.view.scope_name(self.end) == scope_name and self.end < self.size: # Kick out if we hit a highlight region if self.curr_hl != None and self.end == self.curr_hl.begin(): break self.end += 1 the_colour, the_style, the_bgcolour, _, _, _ = self.csm.guess_color(self.view, self.pt, scope_name) # Get new annotation if (self.curr_annot == None or self.curr_annot.end() < self.pt) and len(self.annotations): self.curr_annot, self.curr_comment = self.annotations.pop(0) self.annot_pt = self.curr_annot[0] while self.pt > self.curr_annot[1]: if len(self.annotations): self.curr_annot, self.curr_comment = self.annotations.pop(0) self.annot_pt = self.curr_annot[0] else: self.curr_annot = None self.curr_comment = None break self.new_annot = True self.curr_annot = sublime.Region(self.curr_annot[0], self.curr_annot[1]) region = sublime.Region(self.pt, self.end) if self.curr_annot != None and region.intersects(self.curr_annot): # Apply annotation within the text and format the text self.annotate_text(line, the_colour, the_bgcolour, the_style, empty) else: # Normal text formatting tidied_text = self.html_encode(self.view.substr(region)) self.format_text(line, tidied_text, the_colour, the_bgcolour, the_style, empty) if hl_done: # Clear highlight flags and variables hl_done = False self.curr_hl = None # Continue walking through line self.pt = self.end self.end = self.pt + 1 # Close annotation if open at end of line if self.open_annot: line.append(ANNOTATE_CLOSE % {"comment": self.curr_comment}) self.open_annot = False # Get the color for the space at the end of a line if self.end < self.view.size(): end_key = self.view.scope_name(self.pt) _, _, self.ebground, _, _, _ = self.csm.guess_color(self.view, self.pt, end_key) # Join line segments return "".join(line) def write_body(self, the_html): processed_rows = "" the_html.write(BODY_START) the_html.write(TABLE_START) if not self.no_header: # Write file name date_time = time.strftime(self.date_time_format, self.time) the_html.write( FILE_INFO % { "bgcolor": self.bground, "color": self.fground, "date_time": date_time, "file": self.file_name if self.show_full_path else path.basename(self.file_name), } ) the_html.write(ROW_START) the_html.write(TABLE_START) # Convert view to HTML if self.multi_select: count = 0 total = len(self.sels) for sel in self.sels: self.setup_print_block(sel, multi=True) processed_rows += "[" + str(self.curr_row) + "," self.convert_view_to_html(the_html) count += 1 self.tables = count processed_rows += str(self.curr_row) + "]," if count < total: the_html.write(TABLE_END) the_html.write(ROW_END) the_html.write(ROW_START) the_html.write(DIVIDER % {"color": self.fground}) the_html.write(ROW_END) the_html.write(ROW_START) the_html.write(TABLE_START) else: self.setup_print_block(self.view.sel()[0]) processed_rows += "[" + str(self.curr_row) + "," self.convert_view_to_html(the_html) processed_rows += str(self.curr_row) + "]," self.tables += 1 the_html.write(TABLE_END) the_html.write(ROW_END) the_html.write(TABLE_END) js_options = [] if len(self.annot_tbl): self.add_comments_table(the_html) js_options.append(HTML_JS_WRAP % {"jscode": getjs("annotation.js")}) # Write javascript snippets js_options.append(HTML_JS_WRAP % {"jscode": getjs("print.js")}) js_options.append(HTML_JS_WRAP % {"jscode": getjs("plaintext.js")}) js_options.append( TOGGLE_LINE_OPTIONS % { "jscode": getjs("lines.js"), "wrap_size": self.wrap, "ranges": processed_rows.rstrip(","), "tables": self.tables, "header": ("false" if self.no_header else "true"), "gutter": ("true" if self.numbers else "false"), } ) if self.auto_wrap: js_options.append(WRAP) if self.browser_print: js_options.append(AUTO_PRINT) # Write empty line to allow copying of last line and line number without issue the_html.write( BODY_END % {"js": "".join(js_options), "toolbar": self.get_tools(self.toolbar, len(self.annot_tbl), self.auto_wrap)} ) def add_comments_table(self, the_html): the_html.write(ANNOTATION_TBL_START) the_html.write( "".join([ANNOTATION_ROW % {"table": t, "row": r, "link": l, "comment": c} for t, r, l, c in self.annot_tbl]) ) the_html.write(ANNOTATION_FOOTER) the_html.write(ANNOTATION_TBL_END) def run(self, **kwargs): inputs = self.process_inputs(**kwargs) self.setup(**inputs) save_location = inputs["save_location"] time_stamp = inputs["time_stamp"] if save_location is not None: fname = self.view.file_name() if ( ((fname == None or not path.exists(fname)) and save_location == ".") or not path.exists(save_location) or not path.isdir(save_location) ): html_file = ".html" save_location = None elif save_location == ".": html_file = "%s%s.html" % (fname, time.strftime(time_stamp, self.time)) elif fname is None or not path.exists(fname): html_file = path.join(save_location, "Untitled%s.html" % time.strftime(time_stamp, self.time)) else: html_file = path.join( save_location, "%s%s.html" % (path.basename(fname), time.strftime(time_stamp, self.time)) ) else: html_file = ".html" if save_location is not None: open_html = lambda x: open(x, "w") else: open_html = lambda x: tempfile.NamedTemporaryFile(delete=False, suffix=x) with open_html(html_file) as the_html: self.write_header(the_html) self.write_body(the_html) if inputs["clipboard_copy"]: the_html.seek(0) sublime.set_clipboard(the_html.read()) sublime.status_message("Export to HTML: copied to clipboard") if inputs["view_open"]: self.view.window().open_file(the_html.name) else: # Open in web browser; check return code, if failed try webbrowser status = desktop.open(the_html.name, status=True) if not status: webbrowser.open(the_html.name, new=2)
class ExportHtml(object): def __init__(self, view): self.view = view def process_inputs(self, **kwargs): return { "numbers": bool(kwargs.get("numbers", False)), "highlight_selections": bool(kwargs.get("highlight_selections", False)), "browser_print": bool(kwargs.get("browser_print", False)), "color_scheme": kwargs.get("color_scheme", None), "wrap": kwargs.get("wrap", None), "multi_select": bool(kwargs.get("multi_select", False)), "style_gutter": bool(kwargs.get("style_gutter", True)), "no_header": bool(kwargs.get("no_header", False)), "date_time_format": kwargs.get("date_time_format", "%m/%d/%y %I:%M:%S"), "show_full_path": bool(kwargs.get("show_full_path", True)), "toolbar": kwargs.get("toolbar", ["plain_text", "gutter", "wrapping", "print", "annotation", "theme"]), "save_location": kwargs.get("save_location", None), "time_stamp": kwargs.get("time_stamp", "_%m%d%y%H%M%S"), "clipboard_copy": bool(kwargs.get("clipboard_copy", False)), "view_open": bool(kwargs.get("view_open", False)), "shift_brightness": bool(kwargs.get("shift_brightness", False)), "filter": kwargs.get("filter", "") } def setup(self, **kwargs): # Get get general document preferences from sublime preferences eh_settings = sublime.load_settings(PACKAGE_SETTINGS) settings = sublime.load_settings('Preferences.sublime-settings') alternate_font_size = eh_settings.get("alternate_font_size", False) alternate_font_face = eh_settings.get("alternate_font_face", False) self.font_size = settings.get('font_size', 10) if alternate_font_size == False else alternate_font_size self.font_face = settings.get('font_face', 'Consolas') if alternate_font_face == False else alternate_font_face self.tab_size = settings.get('tab_size', 4) self.padd_top = settings.get('line_padding_top', 0) self.padd_bottom = settings.get('line_padding_bottom', 0) self.char_limit = int(eh_settings.get("valid_selection_size", 4)) self.bground = '' self.fground = '' self.gbground = '' self.gfground = '' self.sbground = '' self.sfground = '' self.numbers = kwargs["numbers"] self.date_time_format = kwargs["date_time_format"] self.time = time.localtime() self.show_full_path = kwargs["show_full_path"] self.highlight_selections = kwargs["highlight_selections"] self.browser_print = kwargs["browser_print"] self.auto_wrap = kwargs["wrap"] != None and int(kwargs["wrap"]) > 0 self.wrap = 900 if not self.auto_wrap else int(kwargs["wrap"]) self.hl_continue = None self.curr_hl = None self.sels = [] self.multi_select = self.check_sel() if kwargs["multi_select"] and not kwargs["highlight_selections"] else False self.size = self.view.size() self.pt = 0 self.end = 0 self.curr_row = 0 self.tables = 0 self.curr_annot = None self.curr_comment = None self.annotations = self.get_annotations() self.annot_num = -1 self.new_annot = False self.open_annot = False self.no_header = kwargs["no_header"] self.annot_tbl = [] self.toolbar = kwargs["toolbar"] self.toolbar_orientation = "block" if eh_settings.get("toolbar_orientation", "horizontal") == "vertical" else "inline-block" self.matched = {} self.ebground = self.bground self.lumens_limit = float(eh_settings.get("bg_min_lumen_threshold", 62)) self.highlights = [] if self.highlight_selections: for sel in self.view.sel(): if not sel.empty(): self.highlights.append(sel) fname = self.view.file_name() if fname == None or not path.exists(fname): fname = "Untitled" self.file_name = fname # Get color scheme if kwargs["color_scheme"] != None: alt_scheme = kwargs["color_scheme"] else: alt_scheme = eh_settings.get("alternate_scheme", False) scheme_file = settings.get('color_scheme') if alt_scheme == False else alt_scheme self.csm = ColorSchemeMatcher( scheme_file, strip_trans=True, ignore_gutter=(not kwargs["style_gutter"]), track_dark_background=True, filter=(lambda x: ColorSchemeTweaker().tweak(x, kwargs["filter"])) ) if kwargs["shift_brightness"]: self.csm.shift_background_brightness(self.lumens_limit) ( self.bground, self.fground, self.sbground, self.sfground, self.gbground, self.gfground ) = self.csm.get_general_colors() def get_tools(self, tools, use_annotation, use_wrapping): toolbar_options = { "gutter": TOOL_GUTTER, "print": TOOL_PRINT, "plain_text": TOOL_PLAIN_TEXT, "annotation": TOOL_ANNOTATION if use_annotation else "", "theme": TOOL_DUMP_THEME, "wrapping": TOOL_WRAPPING if use_wrapping else "" } t_opt = "" toolbar_element = "" if len(tools): for t in tools: if t in toolbar_options: t_opt += toolbar_options[t] toolbar_element = TOOLBAR % {"options": t_opt} return toolbar_element def setup_print_block(self, curr_sel, multi=False): # Determine start and end points and whether to parse whole file or selection if not multi and (curr_sel.empty() or self.highlight_selections or curr_sel.size() <= self.char_limit): self.size = self.view.size() self.pt = 0 self.end = 1 self.curr_row = 1 else: self.size = curr_sel.end() self.pt = curr_sel.begin() self.end = self.pt + 1 self.curr_row = self.view.rowcol(self.pt)[0] + 1 self.start_line = self.curr_row self.gutter_pad = len(str(self.view.rowcol(self.size)[0])) + 1 def check_sel(self): multi = False for sel in self.view.sel(): if not sel.empty() and sel.size() >= self.char_limit: multi = True self.sels.append(sel) return multi def print_line(self, line, num): html_line = LINE % { "line_id": num, "color": self.gfground, "bgcolor": self.gbground, "line": str(num).rjust(self.gutter_pad).replace(" ", ' '), "code_id": num, "code": line, "table": self.tables, "pad_color": self.ebground or self.bground } return html_line def write_header(self, the_html): header = HTML_HEADER % { "title": path.basename(self.file_name), "css": getcss( 'export.css', { "font_size": str(self.font_size), "font_face": '"' + self.font_face + '"', "page_bg": self.bground, "gutter_bg": self.gbground, "body_fg": self.fground, "display_mode": 'table-cell' if self.numbers else 'none', "dot_color": self.fground, "toolbar_orientation": self.toolbar_orientation } ), "js": INCLUDE_THEME % { "jscode": getjs('plist.js'), "theme": json.dumps(self.csm.get_plist_file(), sort_keys=True, indent=4, separators=(',', ': ')).encode('raw_unicode_escape'), "name": self.csm.get_scheme_file(), } } the_html.write(header) def convert_view_to_html(self, the_html): for line in self.view.split_by_newlines(sublime.Region(self.pt, self.size)): self.size = line.end() empty = not bool(line.size()) line = self.convert_line_to_html(the_html, empty) the_html.write(self.print_line(line, self.curr_row)) self.curr_row += 1 def html_encode(self, text): # Format text to HTML encode_table = { '&': '&', '>': '>', '<': '<', '\t': ' ' * self.tab_size, '\n': '' } return re.sub( r'(?!\s($|\S))\s', ' ', ''.join( encode_table.get(c, c) for c in text ).encode('ascii', 'xmlcharrefreplace') ) def get_annotations(self): annotations = get_annotations(self.view) comments = [] for x in range(0, int(annotations["count"])): region = annotations["annotations"]["html_annotation_%d" % x]["region"] comments.append((region, annotations["annotations"]["html_annotation_%d" % x]["comment"])) comments.sort() return comments def annotate_text(self, line, the_colour, the_bgcolour, the_style, empty): pre_text = None annot_text = None post_text = None start = None # Pretext Check if self.pt >= self.curr_annot.begin(): # Region starts with an annotation start = self.pt else: # Region has text before annoation pre_text = self.html_encode(self.view.substr(sublime.Region(self.pt, self.curr_annot.begin()))) start = self.curr_annot.begin() if self.end == self.curr_annot.end(): # Region ends annotation annot_text = self.html_encode(self.view.substr(sublime.Region(start, self.end))) self.curr_annot = None elif self.end > self.curr_annot.end(): # Region has text following annotation annot_text = self.html_encode(self.view.substr(sublime.Region(start, self.curr_annot.end()))) post_text = self.html_encode(self.view.substr(sublime.Region(self.curr_annot.end(), self.end))) self.curr_annot = None else: # Region ends but annotation is not finished annot_text = self.html_encode(self.view.substr(sublime.Region(start, self.end))) self.curr_annot = sublime.Region(self.end, self.curr_annot.end()) # Print the separate parts pre text, annotation, post text if pre_text != None: self.format_text(line, pre_text, the_colour, the_bgcolour, the_style, empty) if annot_text != None: self.format_text(line, annot_text, the_colour, the_bgcolour, the_style, empty, annotate=True) if self.curr_annot == None: self.curr_comment = None if post_text != None: self.format_text(line, post_text, the_colour, the_bgcolour, the_style, empty) def add_annotation_table_entry(self): row, col = self.view.rowcol(self.annot_pt) self.annot_tbl.append( ( self.tables, self.curr_row, "Line %d Col %d" % (row + 1, col + 1), self.curr_comment.encode('ascii', 'xmlcharrefreplace') ) ) self.annot_pt = None def format_text(self, line, text, the_colour, the_bgcolour, the_style, empty, annotate=False): if empty: text = ' ' else: the_style += " real_text" if the_bgcolour is None: the_bgcolour = self.bground if annotate: code = ANNOTATION_CODE % {"highlight": the_bgcolour, "color": the_colour, "content": text, "class": the_style} else: code = CODE % {"highlight": the_bgcolour, "color": the_colour, "content": text, "class": the_style} if annotate: if self.curr_annot != None and not self.open_annot: # Open an annotation if self.annot_pt != None: self.add_annotation_table_entry() if self.new_annot: self.annot_num += 1 self.new_annot = False code = ANNOTATE_OPEN % {"code": code, "comment": str(self.annot_num)} self.open_annot = True elif self.curr_annot == None: if self.open_annot: # Close an annotation code += ANNOTATE_CLOSE self.open_annot = False else: # Do a complete annotation if self.annot_pt != None: self.add_annotation_table_entry() if self.new_annot: self.annot_num += 1 self.new_annot = False code = ( ANNOTATE_OPEN % {"code": code, "comment": str(self.annot_num)} + ANNOTATE_CLOSE ) line.append(code) def convert_line_to_html(self, the_html, empty): line = [] hl_done = False # Continue highlight form last line if self.hl_continue != None: self.curr_hl = self.hl_continue self.hl_continue = None while self.end <= self.size: # Get next highlight region if self.highlight_selections and self.curr_hl == None and len(self.highlights) > 0: self.curr_hl = self.highlights.pop(0) # See if we are starting a highlight region if self.curr_hl != None and self.pt == self.curr_hl.begin(): # Get text of like scope up to a highlight scope_name = self.view.scope_name(self.pt) while self.view.scope_name(self.end) == scope_name and self.end < self.size: # Kick out if we hit a highlight region if self.end == self.curr_hl.end(): break self.end += 1 if self.end < self.curr_hl.end(): if self.end >= self.size: self.hl_continue = sublime.Region(self.end, self.curr_hl.end()) else: self.curr_hl = sublime.Region(self.end, self.curr_hl.end()) else: hl_done = True if hl_done and empty: the_colour, the_style, the_bgcolour, _, _, _ = self.csm.guess_color(self.view, self.pt, scope_name) elif self.sfground is None: the_colour, the_style, _, _, _, _ = self.csm.guess_color(self.view, self.pt, scope_name) the_bgcolour = self.sbground else: the_colour, the_style = self.sfground, "normal" the_bgcolour = self.sbground else: # Get text of like scope up to a highlight scope_name = self.view.scope_name(self.pt) while self.view.scope_name(self.end) == scope_name and self.end < self.size: # Kick out if we hit a highlight region if self.curr_hl != None and self.end == self.curr_hl.begin(): break self.end += 1 the_colour, the_style, the_bgcolour, _, _, _ = self.csm.guess_color(self.view, self.pt, scope_name) # Get new annotation if (self.curr_annot == None or self.curr_annot.end() < self.pt) and len(self.annotations): self.curr_annot, self.curr_comment = self.annotations.pop(0) self.annot_pt = self.curr_annot[0] while self.pt > self.curr_annot[1]: if len(self.annotations): self.curr_annot, self.curr_comment = self.annotations.pop(0) self.annot_pt = self.curr_annot[0] else: self.curr_annot = None self.curr_comment = None break self.new_annot = True self.curr_annot = sublime.Region(self.curr_annot[0], self.curr_annot[1]) region = sublime.Region(self.pt, self.end) if self.curr_annot != None and region.intersects(self.curr_annot): # Apply annotation within the text and format the text self.annotate_text(line, the_colour, the_bgcolour, the_style, empty) else: # Normal text formatting tidied_text = self.html_encode(self.view.substr(region)) self.format_text(line, tidied_text, the_colour, the_bgcolour, the_style, empty) if hl_done: # Clear highlight flags and variables hl_done = False self.curr_hl = None # Continue walking through line self.pt = self.end self.end = self.pt + 1 # Close annotation if open at end of line if self.open_annot: line.append(ANNOTATE_CLOSE % {"comment": self.curr_comment}) self.open_annot = False # Get the color for the space at the end of a line if self.end < self.view.size(): end_key = self.view.scope_name(self.pt) _, _, self.ebground, _, _, _ = self.csm.guess_color(self.view, self.pt, end_key) # Join line segments return ''.join(line) def write_body(self, the_html): processed_rows = "" the_html.write(BODY_START) the_html.write(TABLE_START) if not self.no_header: # Write file name date_time = time.strftime(self.date_time_format, self.time) the_html.write( FILE_INFO % { "bgcolor": self.bground, "color": self.fground, "date_time": date_time, "file": self.file_name if self.show_full_path else path.basename(self.file_name) } ) the_html.write(ROW_START) the_html.write(TABLE_START) # Convert view to HTML if self.multi_select: count = 0 total = len(self.sels) for sel in self.sels: self.setup_print_block(sel, multi=True) processed_rows += "[" + str(self.curr_row) + "," self.convert_view_to_html(the_html) count += 1 self.tables = count processed_rows += str(self.curr_row) + "]," if count < total: the_html.write(TABLE_END) the_html.write(ROW_END) the_html.write(ROW_START) the_html.write(DIVIDER % {"color": self.fground}) the_html.write(ROW_END) the_html.write(ROW_START) the_html.write(TABLE_START) else: self.setup_print_block(self.view.sel()[0]) processed_rows += "[" + str(self.curr_row) + "," self.convert_view_to_html(the_html) processed_rows += str(self.curr_row) + "]," self.tables += 1 the_html.write(TABLE_END) the_html.write(ROW_END) the_html.write(TABLE_END) js_options = [] if len(self.annot_tbl): self.add_comments_table(the_html) js_options.append(HTML_JS_WRAP % {"jscode": getjs('annotation.js')}) # Write javascript snippets js_options.append(HTML_JS_WRAP % {"jscode": getjs('print.js')}) js_options.append(HTML_JS_WRAP % {"jscode": getjs('plaintext.js')}) js_options.append(TOGGLE_LINE_OPTIONS % { "jscode": getjs('lines.js'), "wrap_size": self.wrap, "ranges": processed_rows.rstrip(','), "tables": self.tables, "header": ("false" if self.no_header else "true"), "gutter": ('true' if self.numbers else 'false') } ) if self.auto_wrap: js_options.append(WRAP) if self.browser_print: js_options.append(AUTO_PRINT) # Write empty line to allow copying of last line and line number without issue the_html.write(BODY_END % {"js": ''.join(js_options), "toolbar": self.get_tools(self.toolbar, len(self.annot_tbl), self.auto_wrap)}) def add_comments_table(self, the_html): the_html.write(ANNOTATION_TBL_START) the_html.write(''.join([ANNOTATION_ROW % {"table": t, "row": r, "link": l, "comment": c} for t, r, l, c in self.annot_tbl])) the_html.write(ANNOTATION_FOOTER) the_html.write(ANNOTATION_TBL_END) def run(self, **kwargs): inputs = self.process_inputs(**kwargs) self.setup(**inputs) save_location = inputs["save_location"] time_stamp = inputs["time_stamp"] if save_location is not None: fname = self.view.file_name() if ( ((fname == None or not path.exists(fname)) and save_location == ".") or not path.exists(save_location) or not path.isdir(save_location) ): html_file = ".html" save_location = None elif save_location == ".": html_file = "%s%s.html" % (fname, time.strftime(time_stamp, self.time)) elif fname is None or not path.exists(fname): html_file = path.join(save_location, "Untitled%s.html" % time.strftime(time_stamp, self.time)) else: html_file = path.join(save_location, "%s%s.html" % (path.basename(fname), time.strftime(time_stamp, self.time))) else: html_file = ".html" if save_location is not None: open_html = lambda x: open(x, "w") else: open_html = lambda x: tempfile.NamedTemporaryFile(delete=False, suffix=x) with open_html(html_file) as the_html: self.write_header(the_html) self.write_body(the_html) if inputs["clipboard_copy"]: the_html.seek(0) sublime.set_clipboard(the_html.read()) sublime.status_message("Export to HTML: copied to clipboard") if inputs["view_open"]: self.view.window().open_file(the_html.name) else: # Open in web browser; check return code, if failed try webbrowser status = desktop.open(the_html.name, status=True) if not status: webbrowser.open(the_html.name, new=2)