def setup(self, **kwargs): """Setup for export.""" # Get get general document preferences from sublime preferences settings = self.view.settings() eh_settings = sublime.load_settings(PACKAGE_SETTINGS) self.tab_size = settings.get('tab_size', 4) self.char_limit = int(eh_settings.get("valid_selection_size", 4)) self.bground = '' self.fground = '' self.gbground = '' self.gfground = '' self.numbers = kwargs["numbers"] self.hl_continue = None self.curr_hl = None self.sels = [] self.ignore_selections = kwargs["ignore_selections"] if self.ignore_selections: self.multi_select = False else: self.multi_select = self.check_sel( ) if kwargs["multi_select"] else False self.size = self.view.size() self.pt = 0 self.end = 0 self.curr_row = 0 self.empty_space = None # Get color scheme if kwargs["color_scheme"] is not None: alt_scheme = kwargs["color_scheme"] else: alt_scheme = eh_settings.get("alternate_scheme", False) scheme_file = self.view.settings().get( 'color_scheme') if alt_scheme is False else alt_scheme self.csm = ColorSchemeMatcher( scheme_file, color_filter=( lambda x: ColorSchemeTweaker().tweak(x, kwargs["filter"]))) self.fground = self.csm.get_special_color('foreground', simulate_transparency=True) self.bground = self.csm.get_special_color('background', simulate_transparency=True) self.gfground = self.fground self.gbground = self.bground
def setup(self, **kwargs): """Setup for export.""" # Get get general document preferences from sublime preferences settings = sublime.load_settings('Preferences.sublime-settings') eh_settings = sublime.load_settings(PACKAGE_SETTINGS) self.tab_size = settings.get('tab_size', 4) 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.hl_continue = None self.curr_hl = None self.sels = [] self.ignore_selections = kwargs["ignore_selections"] if self.ignore_selections: self.multi_select = False else: self.multi_select = self.check_sel() if kwargs["multi_select"] else False self.size = self.view.size() self.pt = 0 self.end = 0 self.curr_row = 0 self.empty_space = None # Get color scheme if kwargs["color_scheme"] is not None: alt_scheme = kwargs["color_scheme"] else: alt_scheme = eh_settings.get("alternate_scheme", False) scheme_file = self.view.settings().get('color_scheme') if alt_scheme is False else alt_scheme self.csm = ColorSchemeMatcher( scheme_file, ignore_gutter=True, color_filter=(lambda x: ColorSchemeTweaker().tweak(x, kwargs["filter"])) ) ( self.bground, self.fground, self.sbground, self.sfground, self.gbground, self.gfground ) = self.csm.get_general_colors(simulate_transparency=True)
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 is False else alternate_font_size self.font_face = settings.get( 'font_face', 'Consolas' ) if alternate_font_face is 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.sels = [] self.ignore_selections = kwargs["ignore_selections"] if self.ignore_selections: self.multi_select = False self.highlight_selections = False else: self.highlight_selections = kwargs["highlight_selections"] if kwargs["multi_select"] and not kwargs["highlight_selections"]: self.multi_select = self.check_sel() else: self.multi_select = False self.browser_print = kwargs["browser_print"] self.auto_wrap = kwargs["wrap"] is not 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.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"] if eh_settings.get("toolbar_orientation", "horizontal") == "vertical": self.toolbar_orientation = "block" else: self.toolbar_orientation = "inline-block" self.matched = {} self.ebground = self.bground self.lumens_limit = float(eh_settings.get("bg_min_lumen_threshold", 62)) fname = self.view.file_name() if fname is None or not path.exists(fname): fname = "Untitled" self.file_name = fname # Get color scheme if kwargs["color_scheme"] is not None: alt_scheme = kwargs["color_scheme"] else: alt_scheme = eh_settings.get("alternate_scheme", False) scheme_file = self.view.settings().get( 'color_scheme') if alt_scheme is False else alt_scheme self.highlights = [] if self.highlight_selections: for sel in self.view.sel(): if not sel.empty(): self.highlights.append(sel) self.csm = ColorSchemeMatcher( scheme_file, ignore_gutter=(not kwargs["style_gutter"]), track_dark_background=True, color_filter=( lambda x: ColorSchemeTweaker().tweak(x, kwargs["filter"]))) (self.bground, self.fground, self.sbground, self.sfground, self.gbground, self.gfground) = self.csm.get_general_colors( simulate_transparency=True)
class ExportHtml(object): """ExportHtml.""" def __init__(self, view): """Initialization.""" self.view = view def process_inputs(self, **kwargs): """Process the user inputs.""" 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)), "ignore_selections": bool(kwargs.get("ignore_selections", False)), "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 is False else alternate_font_size self.font_face = settings.get( 'font_face', 'Consolas' ) if alternate_font_face is 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.sels = [] self.ignore_selections = kwargs["ignore_selections"] if self.ignore_selections: self.multi_select = False self.highlight_selections = False else: self.highlight_selections = kwargs["highlight_selections"] if kwargs["multi_select"] and not kwargs["highlight_selections"]: self.multi_select = self.check_sel() else: self.multi_select = False self.browser_print = kwargs["browser_print"] self.auto_wrap = kwargs["wrap"] is not 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.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"] if eh_settings.get("toolbar_orientation", "horizontal") == "vertical": self.toolbar_orientation = "block" else: self.toolbar_orientation = "inline-block" self.matched = {} self.ebground = self.bground self.lumens_limit = float(eh_settings.get("bg_min_lumen_threshold", 62)) fname = self.view.file_name() if fname is None or not path.exists(fname): fname = "Untitled" self.file_name = fname # Get color scheme if kwargs["color_scheme"] is not None: alt_scheme = kwargs["color_scheme"] else: alt_scheme = eh_settings.get("alternate_scheme", False) scheme_file = self.view.settings().get( 'color_scheme') if alt_scheme is False else alt_scheme self.highlights = [] if self.highlight_selections: for sel in self.view.sel(): if not sel.empty(): self.highlights.append(sel) self.csm = ColorSchemeMatcher( scheme_file, ignore_gutter=(not kwargs["style_gutter"]), track_dark_background=True, color_filter=( lambda x: ColorSchemeTweaker().tweak(x, kwargs["filter"]))) (self.bground, self.fground, self.sbground, self.sfground, self.gbground, self.gfground) = self.csm.get_general_colors( simulate_transparency=True) def get_tools(self, tools, use_annotation, use_wrapping): """Get tools for toolbar.""" 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 (self.ignore_selections or (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): """Check if selection is a multi-selection.""" 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): """Print the line.""" 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, html): """Write the HTML header.""" header = HTML_HEADER % { "title": self.html_encode(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 % { "jshelper": getjs('jshelper.js'), "jscode": getjs('plist.js'), "theme": json.dumps(self.csm.get_plist_file(), sort_keys=True, indent=4, separators=(',', ': ')).encode( 'raw_unicode_escape').decode("utf-8"), "name": self.csm.get_scheme_file(), } } html.write(header) def convert_view_to_html(self, html): """Begin conversion of the view to 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(empty) 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').decode("utf-8")) def get_annotations(self): """Get annotation.""" 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, color, bgcolour, style, empty): """Handle annotation text.""" 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 is not None: self.format_text(line, pre_text, color, bgcolour, style, empty) if annot_text is not None: self.format_text(line, annot_text, color, bgcolour, style, empty, annotate=True) if self.curr_annot is None: self.curr_comment = None if post_text is not None: self.format_text(line, post_text, color, bgcolour, style, empty) def add_annotation_table_entry(self): """Add entry to the annotation table.""" 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').decode('utf-8'))) self.annot_pt = None def format_text(self, line, text, color, bgcolor, style, empty, annotate=False): """Format the text.""" if empty: text = ' ' else: style += " real_text" if bgcolor is None: bgcolor = self.bground if annotate: code = ANNOTATION_CODE % { "highlight": bgcolor, "color": color, "content": text, "class": style } else: code = CODE % { "highlight": bgcolor, "color": color, "content": text, "class": style } if annotate: if self.curr_annot is not None and not self.open_annot: # Open an annotation if self.annot_pt is not 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 is None: if self.open_annot: # Close an annotation code += ANNOTATE_CLOSE self.open_annot = False else: # Do a complete annotation if self.annot_pt is not 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, empty): """Convert the line to its HTML representation.""" line = [] hl_done = False # Continue highlight form last line if self.hl_continue is not 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 is 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 is not 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: color_match = self.csm.guess_color(self.view, self.pt, scope_name) color = color_match.fg_simulated style = color_match.style bgcolor = color_match.bg_simulated elif self.sfground is None: color_match = self.csm.guess_color(self.view, self.pt, scope_name) color = color_match.fg_simulated style = color_match.style bgcolor = self.sbground else: color, style = self.sfground, "normal" bgcolor = 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 is not None and self.end == self.curr_hl.begin( ): break self.end += 1 color_match = self.csm.guess_color(self.view, self.pt, scope_name) color = color_match.fg_simulated style = color_match.style bgcolor = color_match.bg_simulated # Get new annotation if (self.curr_annot is 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 is not None and region.intersects( self.curr_annot): # Apply annotation within the text and format the text self.annotate_text(line, color, bgcolor, style, empty) else: # Normal text formatting tidied_text = self.html_encode(self.view.substr(region)) self.format_text(line, tidied_text, color, bgcolor, 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) color_match = self.csm.guess_color(self.view, self.pt, end_key) self.ebground = color_match.bg_simulated # Join line segments return ''.join(line) def write_body(self, html): """Write the body of the HTML.""" processed_rows = "" html.write(BODY_START) html.write(TABLE_START) if not self.no_header: # Write file name date_time = time.strftime(self.date_time_format, self.time) html.write( FILE_INFO % { "bgcolor": self.bground, "color": self.fground, "date_time": date_time, "file": self.html_encode(self.file_name if self.show_full_path else path.basename(self.file_name)) }) html.write(ROW_START) 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(html) count += 1 self.tables = count processed_rows += str(self.curr_row) + "]," if count < total: html.write(TABLE_END) html.write(ROW_END) html.write(ROW_START) html.write(DIVIDER % {"color": self.fground}) html.write(ROW_END) html.write(ROW_START) html.write(TABLE_START) else: self.setup_print_block(self.view.sel()[0]) processed_rows += "[" + str(self.curr_row) + "," self.convert_view_to_html(html) processed_rows += str(self.curr_row) + "]," self.tables += 1 html.write(TABLE_END) html.write(ROW_END) html.write(TABLE_END) js_options = [] if len(self.annot_tbl): self.add_comments_table(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 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, html): """Add comments/annotation table.""" html.write(ANNOTATION_TBL_START) html.write(''.join([ ANNOTATION_ROW % { "table": t, "row": r, "link": l, "comment": c } for t, r, l, c in self.annot_tbl ])) html.write(ANNOTATION_FOOTER) html.write(ANNOTATION_TBL_END) def open_html(self, x, save_location): """Open html file.""" if save_location is not None: return open(x, "w") else: return tempfile.NamedTemporaryFile(mode='w+', delete=False, suffix=x) def run(self, **kwargs): """Run command.""" 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 is 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" with OpenHtml(html_file, save_location) as html: self.write_header(html) self.write_body(html) if inputs["clipboard_copy"]: html.seek(0) sublime.set_clipboard(html.read()) notify("HTML copied to clipboard") if inputs["view_open"]: self.view.window().open_file(html.name) else: # Open in web browser; check return code, if failed try webbrowser status = desktop.open(html.name, status=True) if not status: webbrowser.open(html.name, new=2)
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 is False else alternate_font_size self.font_face = settings.get('font_face', 'Consolas') if alternate_font_face is 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.numbers = kwargs["numbers"] self.date_time_format = kwargs["date_time_format"] self.time = time.localtime() self.show_full_path = kwargs["show_full_path"] self.disable_nbsp = kwargs["disable_nbsp"] self.sels = [] self.ignore_selections = kwargs["ignore_selections"] if self.ignore_selections: self.multi_select = False self.highlight_selections = False else: self.highlight_selections = kwargs["highlight_selections"] if kwargs["multi_select"] and not kwargs["highlight_selections"]: self.multi_select = self.check_sel() else: self.multi_select = False self.browser_print = kwargs["browser_print"] self.auto_wrap = kwargs["wrap"] is not 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.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"] if eh_settings.get("toolbar_orientation", "horizontal") == "vertical": self.toolbar_orientation = "block" else: self.toolbar_orientation = "inline-block" self.ebground = self.bground self.lumens_limit = float(eh_settings.get("bg_min_lumen_threshold", 62)) fname = self.view.file_name() if fname is None or not path.exists(fname): fname = "Untitled" self.file_name = fname # Get color scheme if kwargs["color_scheme"] is not None: alt_scheme = kwargs["color_scheme"] else: alt_scheme = eh_settings.get("alternate_scheme", False) scheme_file = self.view.settings().get('color_scheme') if alt_scheme is False else alt_scheme self.highlights = [] if self.highlight_selections: for sel in self.view.sel(): if not sel.empty(): self.highlights.append(sel) self.csm = ColorSchemeMatcher( scheme_file, color_filter=(lambda x: ColorSchemeTweaker().tweak(x, kwargs["filter"])) ) self.fground = self.csm.get_special_color('foreground', simulate_transparency=True) self.bground = self.csm.get_special_color('background', simulate_transparency=True) if kwargs["style_gutter"]: self.gfground = self.csm.get_special_color('gutterForeground', simulate_transparency=True) self.gbground = self.csm.get_special_color('gutter', simulate_transparency=True) else: self.gfground = self.fground self.gbground = self.bground
class ExportHtml(object): """ExportHtml.""" def __init__(self, view): """Initialization.""" self.view = view def process_inputs(self, **kwargs): """Process the user inputs.""" 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)), "ignore_selections": bool(kwargs.get("ignore_selections", False)), "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"]), "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", ""), "disable_nbsp": kwargs.get('disable_nbsp', False) } 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 is False else alternate_font_size self.font_face = settings.get('font_face', 'Consolas') if alternate_font_face is 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.numbers = kwargs["numbers"] self.date_time_format = kwargs["date_time_format"] self.time = time.localtime() self.show_full_path = kwargs["show_full_path"] self.disable_nbsp = kwargs["disable_nbsp"] self.sels = [] self.ignore_selections = kwargs["ignore_selections"] if self.ignore_selections: self.multi_select = False self.highlight_selections = False else: self.highlight_selections = kwargs["highlight_selections"] if kwargs["multi_select"] and not kwargs["highlight_selections"]: self.multi_select = self.check_sel() else: self.multi_select = False self.browser_print = kwargs["browser_print"] self.auto_wrap = kwargs["wrap"] is not 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.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"] if eh_settings.get("toolbar_orientation", "horizontal") == "vertical": self.toolbar_orientation = "block" else: self.toolbar_orientation = "inline-block" self.ebground = self.bground self.lumens_limit = float(eh_settings.get("bg_min_lumen_threshold", 62)) fname = self.view.file_name() if fname is None or not path.exists(fname): fname = "Untitled" self.file_name = fname # Get color scheme if kwargs["color_scheme"] is not None: alt_scheme = kwargs["color_scheme"] else: alt_scheme = eh_settings.get("alternate_scheme", False) scheme_file = self.view.settings().get('color_scheme') if alt_scheme is False else alt_scheme self.highlights = [] if self.highlight_selections: for sel in self.view.sel(): if not sel.empty(): self.highlights.append(sel) self.csm = ColorSchemeMatcher( scheme_file, color_filter=(lambda x: ColorSchemeTweaker().tweak(x, kwargs["filter"])) ) self.fground = self.csm.get_special_color('foreground', simulate_transparency=True) self.bground = self.csm.get_special_color('background', simulate_transparency=True) if kwargs["style_gutter"]: self.gfground = self.csm.get_special_color('gutterForeground', simulate_transparency=True) self.gbground = self.csm.get_special_color('gutter', simulate_transparency=True) else: self.gfground = self.fground self.gbground = self.bground def get_tools(self, tools, use_annotation, use_wrapping): """Get tools for toolbar.""" 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 ( self.ignore_selections or ( 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): """Check if selection is a multi-selection.""" 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): """Print the line.""" line_text = str(num).rjust(self.gutter_pad) + ' ' html_line = LINE % { "line_id": num, "color": self.gfground, "bgcolor": self.gbground, "line": (line_text.replace(" ", ' ') if not self.disable_nbsp else line_text), "code_id": num, "code": line, "table": self.tables, "pad_color": self.ebground or self.bground } return html_line def write_header(self, html): """Write the HTML header.""" header_vars = { "title": self.html_encode(path.basename(self.file_name)), "css": getcss( { "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 } ) } if 'theme' in self.toolbar: header_vars['js'] = INCLUDE_THEME % { "jshelper": getjs('jshelper.js'), "jscode": getjs('plist.js'), "theme": json.dumps( self.csm.get_plist_file(), sort_keys=True, indent=4, separators=(',', ': ') ).encode('raw_unicode_escape').decode("utf-8"), "name": self.csm.get_scheme_file(), } else: header_vars['js'] = HTML_JS_WRAP % { "jscode": getjs('jshelper.js') } header = HTML_HEADER % header_vars html.write(header) def convert_view_to_html(self, html): """Begin conversion of the view to HTML.""" for line in self.view.split_by_newlines(sublime.Region(self.pt, self.size)): self.size = line.end() self.line_start = line.begin() if self.curr_row > 1: self.line_start -= 1 empty = not bool(line.size()) line = self.convert_line_to_html(empty) html.write(self.print_line(line, self.curr_row)) self.curr_row += 1 def html_encode(self, text, start_pt=None): """Format text to HTML.""" encode_table = { '&': '&', '>': '>', '<': '<', '\t': ' ' * self.tab_size, '\n': '' } if self.disable_nbsp: return ''.join( encode_table.get(c, c) for c in text ).encode('ascii', 'xmlcharrefreplace').decode("utf-8") else: return re.sub( r'(?<=^) | (?= )' if start_pt is not None and start_pt == self.line_start else r' (?= )', lambda m: ' ' * len(m.group(0)), ''.join( encode_table.get(c, c) for c in text ).encode('ascii', 'xmlcharrefreplace').decode("utf-8") ) def get_annotations(self): """Get annotation.""" 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, color, bgcolour, style, empty): """Handle annotation text.""" 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())), self.pt) 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)), start) 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())), start) post_text = self.html_encode( self.view.substr(sublime.Region(self.curr_annot.end(), self.end)), self.curr_annot.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)), start) self.curr_annot = sublime.Region(self.end, self.curr_annot.end()) # Print the separate parts pre text, annotation, post text if pre_text is not None: self.format_text(line, pre_text, color, bgcolour, style, empty) if annot_text is not None: self.format_text(line, annot_text, color, bgcolour, style, empty, annotate=True) if self.curr_annot is None: self.curr_comment = None if post_text is not None: self.format_text(line, post_text, color, bgcolour, style, empty) def add_annotation_table_entry(self): """Add entry to the annotation table.""" 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').decode('utf-8') ) ) self.annot_pt = None def format_text(self, line, text, color, bgcolor, style, empty, annotate=False): """Format the text.""" if not style: style == 'normal' if empty: text = ' ' if not self.disable_nbsp else ' ' else: style += " real_text" if bgcolor is None: bgcolor = self.bground if annotate: code = ANNOTATION_CODE % {"highlight": bgcolor, "color": color, "content": text, "class": style} else: code = CODE % {"highlight": bgcolor, "color": color, "content": text, "class": style} if annotate: if self.curr_annot is not None and not self.open_annot: # Open an annotation if self.annot_pt is not 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 is None: if self.open_annot: # Close an annotation code += ANNOTATE_CLOSE self.open_annot = False else: # Do a complete annotation if self.annot_pt is not 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, empty): """Convert the line to its HTML representation.""" line = [] hl_done = False # Continue highlight form last line if self.hl_continue is not 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 is 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 is not 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 color_match = self.csm.guess_color(scope_name, selected=not (hl_done and empty)) color = color_match.fg_simulated style = color_match.style bgcolor = color_match.bg_simulated 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 is not None and self.end == self.curr_hl.begin(): break self.end += 1 color_match = self.csm.guess_color(scope_name) color = color_match.fg_simulated style = color_match.style bgcolor = color_match.bg_simulated # Get new annotation if (self.curr_annot is 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 is not None and region.intersects(self.curr_annot): # Apply annotation within the text and format the text self.annotate_text(line, color, bgcolor, style, empty) else: # Normal text formatting tidied_text = self.html_encode(self.view.substr(region), region.begin()) self.format_text(line, tidied_text, color, bgcolor, 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) color_match = self.csm.guess_color(end_key) self.ebground = color_match.bg_simulated # Join line segments return ''.join(line) def write_body(self, html): """Write the body of the HTML.""" processed_rows = "" html.write(BODY_START) html.write(TABLE_START) if not self.no_header: # Write file name date_time = time.strftime(self.date_time_format, self.time) html.write( FILE_INFO % { "bgcolor": self.bground, "color": self.fground, "date_time": date_time, "file": self.html_encode(self.file_name if self.show_full_path else path.basename(self.file_name)) } ) html.write(ROW_START) 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(html) count += 1 self.tables = count processed_rows += str(self.curr_row) + "]," if count < total: html.write(TABLE_END) html.write(ROW_END) html.write(ROW_START) html.write(DIVIDER % {"color": self.fground}) html.write(ROW_END) html.write(ROW_START) html.write(TABLE_START) else: self.setup_print_block(self.view.sel()[0]) processed_rows += "[" + str(self.curr_row) + "," self.convert_view_to_html(html) processed_rows += str(self.curr_row) + "]," self.tables += 1 html.write(TABLE_END) html.write(ROW_END) html.write(TABLE_END) js_options = [] if len(self.annot_tbl): self.add_comments_table(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 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, html): """Add comments/annotation table.""" html.write(ANNOTATION_TBL_START) html.write( ''.join([ANNOTATION_ROW % {"table": t, "row": r, "link": l, "comment": c} for t, r, l, c in self.annot_tbl]) ) html.write(ANNOTATION_FOOTER) html.write(ANNOTATION_TBL_END) def open_html(self, x, save_location): """Open html file.""" if save_location is not None: return open(x, "w") else: return tempfile.NamedTemporaryFile(mode='w+', delete=False, suffix=x) def run(self, **kwargs): """Run command.""" 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 is 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" with OpenHtml(html_file, save_location) as html: self.write_header(html) self.write_body(html) if inputs["clipboard_copy"]: html.seek(0) sublime.set_clipboard(html.read()) notify("HTML copied to clipboard") if inputs["view_open"]: self.view.window().open_file(html.name) else: # Open in web browser; check return code, if failed try webbrowser status = desktop.open(html.name, status=True) if not status: webbrowser.open(html.name, new=2)
class ExportBbcode(object): def __init__(self, view): self.view = view def process_inputs(self, **kwargs): return { "numbers": bool(kwargs.get("numbers", False)), "color_scheme": kwargs.get("color_scheme", None), "multi_select": bool(kwargs.get("multi_select", False)), "clipboard_copy": bool(kwargs.get("clipboard_copy", True)), "view_open": bool(kwargs.get("view_open", False)), "filter": kwargs.get("filter", "") } def setup(self, **kwargs): # Get get general document preferences from sublime preferences settings = sublime.load_settings('Preferences.sublime-settings') eh_settings = sublime.load_settings(PACKAGE_SETTINGS) self.tab_size = settings.get('tab_size', 4) 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.hl_continue = None self.curr_hl = None self.sels = [] self.multi_select = self.check_sel() if kwargs["multi_select"] else False self.size = self.view.size() self.pt = 0 self.end = 0 self.curr_row = 0 self.empty_space = None # Get color scheme if kwargs["color_scheme"] is not None: alt_scheme = kwargs["color_scheme"] else: alt_scheme = eh_settings.get("alternate_scheme", False) scheme_file = settings.get('color_scheme') if alt_scheme is False else alt_scheme self.csm = ColorSchemeMatcher( scheme_file, strip_trans=True, ignore_gutter=True, filter=(lambda x: ColorSchemeTweaker().tweak(x, kwargs["filter"])) ) ( self.bground, self.fground, self.sbground, self.sfground, self.gbground, self.gfground ) = self.csm.get_general_colors() 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 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): if self.numbers: bbcode_line = NUMBERED_BBCODE_LINE % { "color": self.gfground, "line": str(num).rjust(self.gutter_pad), "code": line } else: bbcode_line = BBCODE_LINE % {"code": line} return bbcode_line def convert_view_to_bbcode(self, the_bbcode): for line in self.view.split_by_newlines(sublime.Region(self.end, self.size)): self.empty_space = None self.size = line.end() line = self.convert_line_to_bbcode() the_bbcode.write(self.print_line(line, self.curr_row)) self.curr_row += 1 def repl(self, m, the_colour): return m.group(1) + ( BBCODE_ESCAPE % { "color_open": the_colour, "color_close": the_colour, "content": m.group(2) } ) + m.group(3) def format_text(self, line, text, the_colour, the_style): text = text.replace('\t', ' ' * self.tab_size).replace('\n', '') if self.empty_space is not None: text = self.empty_space + text self.empty_space = None if text.strip(' ') == '': self.empty_space = text else: code = "" text = BBCODE_MATCH.sub(lambda m: self.repl(m, the_colour), text) bold = False italic = False for s in the_style: if s == "bold": bold = True if s == "italic": italic = True code += (BBCODE_CODE % {"color": the_colour, "content": text}) if italic: code = (BBCODE_ITALIC % {"color": the_colour, "content": code}) if bold: code = (BBCODE_BOLD % {"color": the_colour, "content": code}) line.append(code) def convert_line_to_bbcode(self): line = [] while self.end <= self.size: # 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: self.end += 1 the_colour, the_style, _, _, _, _ = self.csm.guess_color(self.view, self.pt, scope_name) region = sublime.Region(self.pt, self.end) # Normal text formatting text = self.view.substr(region) self.format_text(line, text, the_colour, the_style) # Continue walking through line self.pt = self.end self.end = self.pt + 1 # Join line segments return ''.join(line) def write_body(self, the_bbcode): the_bbcode.write(POST_START % {"bg_color": self.bground}) # 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) self.convert_view_to_bbcode(the_bbcode) count += 1 if count < total: the_bbcode.write("\n" + (BBCODE_CODE % {"color": self.fground, "content": "..."}) + "\n\n") else: self.setup_print_block(self.view.sel()[0]) self.convert_view_to_bbcode(the_bbcode) the_bbcode.write(POST_END) def run(self, **kwargs): inputs = self.process_inputs(**kwargs) self.setup(**inputs) delete = False if inputs["view_open"] else True with tempfile.NamedTemporaryFile(mode='w+', delete=delete, suffix='.txt', encoding='utf-8') as the_bbcode: self.write_body(the_bbcode) if inputs["clipboard_copy"]: the_bbcode.seek(0) sublime.set_clipboard(the_bbcode.read()) notify("BBCode copied to clipboard") if inputs["view_open"]: self.view.window().open_file(the_bbcode.name)
class ExportBbcode(object): """Take the content of a Sublime view and export BBCode representation.""" def __init__(self, view): """Initialize.""" self.view = view def process_inputs(self, **kwargs): """Handle the inputs.""" return { "numbers": bool(kwargs.get("numbers", False)), "color_scheme": kwargs.get("color_scheme", None), "multi_select": bool(kwargs.get("multi_select", False)), "ignore_selections": bool(kwargs.get("ignore_selections", False)), "clipboard_copy": bool(kwargs.get("clipboard_copy", True)), "view_open": bool(kwargs.get("view_open", False)), "filter": kwargs.get("filter", ""), } def setup(self, **kwargs): """Setup for export.""" # Get get general document preferences from sublime preferences settings = sublime.load_settings("Preferences.sublime-settings") eh_settings = sublime.load_settings(PACKAGE_SETTINGS) self.tab_size = settings.get("tab_size", 4) self.char_limit = int(eh_settings.get("valid_selection_size", 4)) self.bground = "" self.fground = "" self.gbground = "" self.gfground = "" self.numbers = kwargs["numbers"] self.hl_continue = None self.curr_hl = None self.sels = [] self.ignore_selections = kwargs["ignore_selections"] if self.ignore_selections: self.multi_select = False else: self.multi_select = self.check_sel() if kwargs["multi_select"] else False self.size = self.view.size() self.pt = 0 self.end = 0 self.curr_row = 0 self.empty_space = None # Get color scheme if kwargs["color_scheme"] is not None: alt_scheme = kwargs["color_scheme"] else: alt_scheme = eh_settings.get("alternate_scheme", False) scheme_file = self.view.settings().get("color_scheme") if alt_scheme is False else alt_scheme self.csm = ColorSchemeMatcher( scheme_file, color_filter=(lambda x: ColorSchemeTweaker().tweak(x, kwargs["filter"])) ) self.fground = self.csm.get_special_color("foreground", simulate_transparency=True) self.bground = self.csm.get_special_color("background", simulate_transparency=True) self.gfground = self.fground self.gbground = self.bground def setup_print_block(self, curr_sel, multi=False): """Determine start and end points and whether to parse whole file or selection.""" if self.ignore_selections or (not multi and (curr_sel.empty() 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): """Check if multi-selection.""" 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): """Format a line for output.""" if self.numbers: bbcode_line = NUMBERED_BBCODE_LINE % { "color": self.gfground, "line": str(num).rjust(self.gutter_pad), "code": line, } else: bbcode_line = BBCODE_LINE % {"code": line} return bbcode_line def convert_view_to_bbcode(self, bbcode): """Begin converting the view to BBCode.""" for line in self.view.split_by_newlines(sublime.Region(self.end, self.size)): self.empty_space = None self.size = line.end() line = self.convert_line_to_bbcode() bbcode.write(self.print_line(line, self.curr_row)) self.curr_row += 1 def repl(self, m, color): """Replace method to escape BBCode content.""" return ( m.group(1) + (BBCODE_ESCAPE % {"color_open": color, "color_close": color, "content": m.group(2)}) + m.group(3) ) def format_text(self, line, text, color, style): """Format the text for output.""" text = text.replace("\t", " " * self.tab_size).replace("\n", "") if self.empty_space is not None: text = self.empty_space + text self.empty_space = None if text.strip(" ") == "": self.empty_space = text else: code = "" text = BBCODE_MATCH.sub(lambda m: self.repl(m, color), text) bold = False italic = False for s in style.split(" "): if s == "bold": bold = True if s == "italic": italic = True code += BBCODE_CODE % {"color": color, "content": text} if italic: code = BBCODE_ITALIC % {"content": code} if bold: code = BBCODE_BOLD % {"content": code} line.append(code) def convert_line_to_bbcode(self): """Conver the line to BBCode.""" line = [] while self.end <= self.size: # 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: self.end += 1 color_match = self.csm.guess_color(scope_name) color = color_match.fg_simulated style = color_match.style region = sublime.Region(self.pt, self.end) # Normal text formatting text = self.view.substr(region) self.format_text(line, text, color, style) # Continue walking through line self.pt = self.end self.end = self.pt + 1 # Join line segments return "".join(line) def write_body(self, bbcode): """Write the body of the BBCode output.""" bbcode.write(POST_START % {"bg_color": self.bground}) # 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) self.convert_view_to_bbcode(bbcode) count += 1 if count < total: bbcode.write("\n" + (BBCODE_CODE % {"color": self.fground, "content": "..."}) + "\n\n") else: self.setup_print_block(self.view.sel()[0]) self.convert_view_to_bbcode(bbcode) bbcode.write(POST_END) def run(self, **kwargs): """Run the command.""" inputs = self.process_inputs(**kwargs) self.setup(**inputs) delete = False if inputs["view_open"] else True with tempfile.NamedTemporaryFile(mode="w+", delete=delete, suffix=".txt", encoding="utf-8") as bbcode: self.write_body(bbcode) if inputs["clipboard_copy"]: bbcode.seek(0) sublime.set_clipboard(bbcode.read()) notify("BBCode copied to clipboard") if inputs["view_open"]: self.view.window().open_file(bbcode.name)
class ExportBbcode(object): """Take the content of a Sublime view and export BBCode representation.""" def __init__(self, view): """Initialize.""" self.view = view def process_inputs(self, **kwargs): """Handle the inputs.""" return { "numbers": bool(kwargs.get("numbers", False)), "color_scheme": kwargs.get("color_scheme", None), "multi_select": bool(kwargs.get("multi_select", False)), "ignore_selections": bool(kwargs.get("ignore_selections", False)), "clipboard_copy": bool(kwargs.get("clipboard_copy", True)), "view_open": bool(kwargs.get("view_open", False)), "filter": kwargs.get("filter", "") } def setup(self, **kwargs): """Setup for export.""" # Get get general document preferences from sublime preferences settings = self.view.settings() eh_settings = sublime.load_settings(PACKAGE_SETTINGS) self.tab_size = settings.get('tab_size', 4) self.char_limit = int(eh_settings.get("valid_selection_size", 4)) self.bground = '' self.fground = '' self.gbground = '' self.gfground = '' self.numbers = kwargs["numbers"] self.hl_continue = None self.curr_hl = None self.sels = [] self.ignore_selections = kwargs["ignore_selections"] if self.ignore_selections: self.multi_select = False else: self.multi_select = self.check_sel( ) if kwargs["multi_select"] else False self.size = self.view.size() self.pt = 0 self.end = 0 self.curr_row = 0 self.empty_space = None # Get color scheme if kwargs["color_scheme"] is not None: alt_scheme = kwargs["color_scheme"] else: alt_scheme = eh_settings.get("alternate_scheme", False) scheme_file = self.view.settings().get( 'color_scheme') if alt_scheme is False else alt_scheme self.csm = ColorSchemeMatcher( scheme_file, color_filter=( lambda x: ColorSchemeTweaker().tweak(x, kwargs["filter"]))) self.fground = self.csm.get_special_color('foreground', simulate_transparency=True) self.bground = self.csm.get_special_color('background', simulate_transparency=True) self.gfground = self.fground self.gbground = self.bground def setup_print_block(self, curr_sel, multi=False): """Determine start and end points and whether to parse whole file or selection.""" if (self.ignore_selections or curr_sel is None or (not multi and (curr_sel.empty() 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): """Check if multi-selection.""" 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): """Format a line for output.""" if self.numbers: bbcode_line = NUMBERED_BBCODE_LINE % { "color": self.gfground, "line": str(num).rjust(self.gutter_pad), "code": line } else: bbcode_line = BBCODE_LINE % {"code": line} return bbcode_line def convert_view_to_bbcode(self, bbcode): """Begin converting the view to BBCode.""" for line in self.view.split_by_newlines( sublime.Region(self.end, self.size)): self.empty_space = None self.size = line.end() line = self.convert_line_to_bbcode() bbcode.write(self.print_line(line, self.curr_row)) self.curr_row += 1 def repl(self, m, color): """Replace method to escape BBCode content.""" return m.group(1) + (BBCODE_ESCAPE % { "color_open": color, "color_close": color, "content": m.group(2) }) + m.group(3) def format_text(self, line, text, color, style): """Format the text for output.""" text = text.replace('\n', '') if self.empty_space is not None: text = self.empty_space + text self.empty_space = None if text.strip(' ') == '': self.empty_space = text else: code = "" text = BBCODE_MATCH.sub(lambda m: self.repl(m, color), text) bold = False italic = False for s in style.split(' '): if s == "bold": bold = True if s == "italic": italic = True code += (BBCODE_CODE % {"color": color, "content": text}) if italic: code = (BBCODE_ITALIC % {"content": code}) if bold: code = (BBCODE_BOLD % {"content": code}) line.append(code) def convert_line_to_bbcode(self): """Conver the line to BBCode.""" line = [] while self.end <= self.size: # 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: self.end += 1 color_match = self.csm.guess_color(scope_name) color = color_match.fg_simulated style = color_match.style region = sublime.Region(self.pt, self.end) # Normal text formatting text = self.view.substr(region) self.format_text(line, text, color, style) # Continue walking through line self.pt = self.end self.end = self.pt + 1 # Join line segments return ''.join(line) def write_body(self, bbcode): """Write the body of the BBCode output.""" bbcode.write(POST_START % {"bg_color": self.bground}) # 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) self.convert_view_to_bbcode(bbcode) count += 1 if count < total: bbcode.write("\n" + (BBCODE_CODE % { "color": self.fground, "content": "..." }) + "\n\n") else: sels = self.view.sel() self.setup_print_block(sels[0] if len(sels) else None) self.convert_view_to_bbcode(bbcode) bbcode.write(POST_END) def run(self, **kwargs): """Run the command.""" inputs = self.process_inputs(**kwargs) self.setup(**inputs) delete = False if inputs["view_open"] else True with tempfile.NamedTemporaryFile(mode='w+', delete=delete, suffix='.txt', encoding='utf-8') as bbcode: self.write_body(bbcode) if inputs["clipboard_copy"]: bbcode.seek(0) sublime.set_clipboard(bbcode.read()) notify("BBCode copied to clipboard") if inputs["view_open"]: self.view.window().open_file(bbcode.name)