Example #1
0
    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
Example #2
0
    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)
Example #3
0
    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)
Example #4
0
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(" ", '&nbsp;'),
            "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 = {
            '&': '&amp;',
            '>': '&gt;',
            '<': '&lt;',
            '\t': ' ' * self.tab_size,
            '\n': ''
        }

        return re.sub(
            r'(?!\s($|\S))\s', '&nbsp;',
            ''.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 = '&nbsp;'
        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)
Example #5
0
    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
Example #6
0
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(" ", '&nbsp;') 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 = {
            '&': '&amp;',
            '>': '&gt;',
            '<': '&lt;',
            '\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: '&nbsp;' * 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 = '&nbsp;' 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)
Example #7
0
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)
Example #8
0
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)
Example #9
0
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)