Ejemplo n.º 1
0
    def run(
        self, edit, replacements=None,
        find_only=False, clear=False, action=None,
        multi_pass=False, no_selection=False, regex_full_file_with_selections=False,
        options=None, use_test_buffer=False
    ):
        """Kick off sequence."""

        if replacements is None:
            replacements = []
        if options is None:
            options = {}

        self.use_test_buffer = bool(use_test_buffer)
        self.find_only = bool(find_only)
        self.action = action.strip() if action is not None else action
        self.full_file = bool(regex_full_file_with_selections)
        if not no_selection and rrsettings.get('selection_only', False) and self.is_selection_available():
            self.selection_only = True
        else:
            self.selection_only = False
        self.max_sweeps = rrsettings.get('multi_pass_max_sweeps', DEFAULT_MULTI_PASS_MAX_SWEEP)
        self.replacements = replacements
        self.multi_pass = bool(multi_pass)
        self.panel_display = rrsettings.get('results_in_panel', DEFAULT_SHOW_PANEL)
        self.options = options
        self.clear = clear

        self.replace_obj = FindReplace(
            self.view,
            edit,
            self.find_only,
            self.full_file,
            self.selection_only,
            self.max_sweeps,
            self.action
        )

        # Clear regions and exit; no need to run sequences
        if self.clear_regions():
            self.replace_obj.close()
            return

        # Is the sequence empty?
        if len(self.replacements) > 0:
            self.start_sequence()
        else:
            self.replace_obj.close()
class RegReplaceCommand(sublime_plugin.TextCommand):
    handshake = None

    def forget_handshake(self):
        """
        Forget current view
        """

        self.handshake = None
        self.clear_highlights(MODULE_NAME)
        self.replace_obj.close()

    def replace_prompt(self):
        """
        Prompt the user to see if they wish to replace the highlighted selections.
        """

        # Ask if replacements are desired
        self.handshake = self.view.id()
        self.view.window().show_input_panel(
            'Replace targets / perform action? (yes | no):',
            'yes',
            self.run_replace,
            None,
            self.forget_handshake
        )

    def run_replace(self, answer):
        """
        Initiate a find with replace.
        Used to initiate replacing when a find is executed with a replace prompt.
        """

        # Do we want to replace
        if answer.strip().lower() != 'yes':
            self.forget_handshake()
            return

        # See if we know this view
        window = sublime.active_window()
        view = window.active_view() if window is not None else None
        if view is not None:
            if self.handshake is not None and self.handshake == view.id():
                self.forget_handshake()
                # re-run command to actually replace targets
                view.run_command(
                    'reg_replace',
                    {
                        'replacements': self.replacements,
                        'action': self.action,
                        'multi_pass': self.multi_pass,
                        'regex_full_file_with_selections': self.full_file,
                        'options': self.options
                    }
                )
        else:
            self.forget_handshake()

    def clear_regions(self, clear, action, options):
        """
        Clear highlighted regions specified
        """

        cleared = False
        # Clear regions and exit
        if self.clear:
            self.clear_highlights(MODULE_NAME)
            self.replace_obj.close()
            cleared = True
        elif self.action == 'unmark' and 'key' in self.options:
            self.perform_action()
            self.replace_obj.close()
            cleared = True
        return cleared

    def set_highlights(self, key, style, color):
        """
        Mark regions with specified highlight options
        """

        # Process highlight style
        highlight_style = 0
        if (self.find_only and self.selection_only) or style == 'underline':
            # Use underline if explicity requested,
            # or if doing a find only when under a selection only (only underline can be seen through a selection)
            self.replace_obj.target_regions = underline(self.replace_obj.target_regions)
            highlight_style = sublime.DRAW_EMPTY_AS_OVERWRITE
        elif style == 'outline':
            highlight_style = sublime.DRAW_OUTLINED

        # higlight all of the found regions
        self.view.erase_regions(key)
        self.view.add_regions(
            key,
            self.replace_obj.target_regions,
            color,
            "",
            highlight_style
        )

    def clear_highlights(self, key):
        """
        Clear all highlighted regions of given key
        """

        self.view.erase_regions(key)

    def is_selection_available(self):
        """
        See if there are selections in document
        """

        available = False
        for sel in self.view.sel():
            if sel.size() > 0:
                available = True
                break
        return available

    def ignore_ending_newlines(self, regions):
        """
        Ignore newlines at the end of the region; newlines okay in the middle of region
        """

        new_regions = []
        for region in regions:
            offset = 0
            size = region.size()
            if size > offset and self.view.substr(region.end() - 1) == '\n':
                offset += 1
            if size > offset and self.view.substr(region.end() - offset - 1) == '\r':
                offset += 1
            new_regions.append(sublime.Region(region.begin(), region.end() - offset))
        return new_regions

    def print_results_status_bar(self, text):
        """
        Print results to the status bar
        """

        sublime.status_message(text)

    def print_results_panel(self, text):
        """
        Print find results to an output panel
        """

        # Get/create output panel
        window = self.view.window()
        view = window.get_output_panel('reg_replace_results')

        # Turn off stylings in panel
        view.settings().set('draw_white_space', 'none')
        view.settings().set('draw_indent_guides', False)
        view.settings().set('gutter', 'none')
        view.settings().set('line_numbers', False)
        view.set_syntax_file('Packages/Text/Plain text.tmLanguage')

        # Show Results in read only panel and clear selection in panel
        window.run_command('show_panel', {'panel': 'output.reg_replace_results'})
        view.set_read_only(False)
        RegReplaceGlobal.bfr = 'RegReplace Results\n\n' + text
        RegReplaceGlobal.region = sublime.Region(0, view.size())
        view.run_command("reg_replace_apply")
        RegReplaceGlobal.clear()
        view.set_read_only(True)
        view.sel().clear()

    def perform_action(self):
        """
        Perform action on targed text
        """

        status = True
        if self.action == 'fold':
            # Fold regions
            self.view.fold(self.ignore_ending_newlines(self.replace_obj.target_regions))
        elif self.action == 'unfold':
            # Unfold regions
            try:
                self.view.unfold(self.ignore_ending_newlines(self.replace_obj.target_regions))
            except:
                sublime.error_message("Cannot unfold! Please upgrade to the latest stable beta build to remove this error.")
        elif self.action == 'mark':
            # Mark targeted regions
            if 'key' in self.options:
                color = self.options['scope'].strip() if 'scope' in self.options else DEFAULT_HIGHLIGHT_COLOR
                style = self.options['style'].strip() if 'style' in self.options else DEFAULT_HIGHLIGHT_STYLE
                self.set_highlights(self.options['key'].strip(), style, color)
        elif self.action == 'unmark':
            # Unmark targeted regions
            if 'key' in self.options:
                self.clear_highlights(self.options['key'].strip())
        else:
            # Not a valid action
            status = False
        return status

    def find_and_replace(self):
        """
        Walk the sequence finding the targeted regions in the text.
        If allowed, replacements will be done as well.
        """

        replace_list = rrsettings.get('replacements', {})
        result_template = '%s: %d regions;\n' if self.panel_display else '%s: %d regions; '
        results = ''

        # Walk the sequence
        # Multi-pass only if requested and will be occuring
        if self.multi_pass and not self.find_only and self.action is None:
            # Multi-pass initialization
            current_replacements = 0
            total_replacements = 0
            count = 0

            # Sweep file until all instances are found
            # Avoid infinite loop and break out if sweep threshold is met
            while count < self.max_sweeps:
                count += 1
                current_replacements = 0

                for replacement in self.replacements:
                    # Is replacement available in the list?
                    if replacement in replace_list:
                        pattern = replace_list[replacement]
                        current_replacements += self.replace_obj.search(pattern, 'scope' in pattern)
                total_replacements += current_replacements

                # No more regions found?
                if current_replacements == 0:
                    break
            # Record total regions found
            results += 'Regions Found: %d regions;' % total_replacements
        else:
            for replacement in self.replacements:
                # Is replacement available in the list?
                if replacement in replace_list:
                    pattern = replace_list[replacement]
                    results += result_template % (replacement, self.replace_obj.search(pattern, 'scope' in pattern))
        return results

    def start_sequence(self):
        """
        Run the replace sequence
        """

        # Find targets and replace if applicable
        results = self.find_and_replace()

        if self.find_only:
            # Higlight regions
            style = rrsettings.get('find_highlight_style', DEFAULT_HIGHLIGHT_STYLE)
            color = rrsettings.get('find_highlight_color', DEFAULT_HIGHLIGHT_COLOR)
            self.set_highlights(MODULE_NAME, style, color)
            self.replace_prompt()
        else:
            self.clear_highlights(MODULE_NAME)
            # Perform action
            if self.action is not None:
                if not self.perform_action():
                    results = 'Error: Bad Action!'

            # Report results
            if self.panel_display:
                self.print_results_panel(results)
            else:
                self.print_results_status_bar(results)
            self.replace_obj.close()

    def run(
        self, edit, replacements=[],
        find_only=False, clear=False, action=None,
        multi_pass=False, no_selection=False, regex_full_file_with_selections=False,
        options={}
    ):
        """
        Kick off sequence
        """

        self.find_only = bool(find_only)
        self.action = action.strip() if action is not None else action
        self.full_file = bool(regex_full_file_with_selections)
        self.selection_only = True if not no_selection and rrsettings.get('selection_only', False) and self.is_selection_available() else False
        self.max_sweeps = rrsettings.get('multi_pass_max_sweeps', DEFAULT_MULTI_PASS_MAX_SWEEP)
        self.replacements = replacements
        self.multi_pass = bool(multi_pass)
        self.panel_display = rrsettings.get('results_in_panel', DEFAULT_SHOW_PANEL)
        self.options = options
        self.clear = clear

        self.replace_obj = FindReplace(
            self.view,
            edit,
            self.find_only,
            self.full_file,
            self.selection_only,
            self.max_sweeps,
            self.action
        )

        # Clear regions and exit; no need to run sequences
        if self.clear_regions(clear, action, options):
            self.replace_obj.close()
            return

        # Is the sequence empty?
        if len(self.replacements) > 0:
            self.start_sequence()
        else:
            self.replace_obj.close()
Ejemplo n.º 3
0
class RegReplaceCommand(sublime_plugin.TextCommand):
    """RegReplace command."""

    handshake = None

    def forget_handshake(self):
        """Forget current view."""

        self.handshake = None
        self.clear_highlights(MODULE_NAME)
        self.replace_obj.close()

    def replace_prompt(self):
        """Prompt the user to see if they wish to replace the highlighted selections."""

        # Ask if replacements are desired
        self.handshake = self.view.id()
        self.view.window().show_input_panel(
            'Replace targets / perform action? (yes | no):', 'yes',
            self.run_replace, None, self.forget_handshake)

    def run_replace(self, answer):
        """
        Initiate a find with replace.

        Used to initiate replacing when a find is executed with a replace prompt.
        """

        # Do we want to replace
        if answer.strip().lower() != 'yes':
            self.forget_handshake()
            return

        # See if we know this view
        window = sublime.active_window()
        view = window.active_view() if window is not None else None
        if view is not None:
            if self.handshake is not None and self.handshake == view.id():
                self.forget_handshake()
                # re-run command to actually replace targets
                view.run_command(
                    'reg_replace', {
                        'replacements': self.replacements,
                        'action': self.action,
                        'multi_pass': self.multi_pass,
                        'regex_full_file_with_selections': self.full_file,
                        'options': self.options
                    })
        else:
            self.forget_handshake()

    def clear_regions(self):
        """Clear highlighted regions specified."""

        cleared = False
        # Clear regions and exit
        if self.clear:
            self.clear_highlights(MODULE_NAME)
            self.replace_obj.close()
            cleared = True
        elif self.action == 'unmark' and 'key' in self.options:
            self.perform_action()
            self.replace_obj.close()
            cleared = True
        return cleared

    def set_highlights(self, key, style, color):
        """Mark regions with specified highlight options."""

        # Process highlight style
        highlight_style = 0
        if (self.find_only and self.selection_only) or style == 'underline':
            # Use underline if explicitly requested,
            # or if doing a find only when under a selection only (only underline can be seen through a selection)
            self.replace_obj.target_regions = underline(
                self.replace_obj.target_regions)
            highlight_style = sublime.DRAW_EMPTY_AS_OVERWRITE
        elif style == 'outline':
            highlight_style = sublime.DRAW_OUTLINED

        # highlight all of the found regions
        self.view.erase_regions(key)
        self.view.add_regions(key, self.replace_obj.target_regions, color, "",
                              highlight_style)

    def clear_highlights(self, key):
        """Clear all highlighted regions of given key."""

        self.view.erase_regions(key)

    def is_selection_available(self):
        """See if there are selections in document."""

        available = False
        for sel in self.view.sel():
            if sel.size() > 0:
                available = True
                break
        return available

    def ignore_ending_newlines(self, regions):
        """Ignore newlines at the end of the region; newlines okay in the middle of region."""

        new_regions = []
        for region in regions:
            offset = 0
            size = region.size()
            if size > offset and self.view.substr(region.end() - 1) == '\n':
                offset += 1
            if size > offset and self.view.substr(region.end() - offset -
                                                  1) == '\r':
                offset += 1
            new_regions.append(
                sublime.Region(region.begin(),
                               region.end() - offset))
        return new_regions

    def print_results_status_bar(self, text):
        """Print results to the status bar."""

        sublime.status_message(text)

    def print_results_panel(self, text):
        """Print find results to an output panel."""

        # Get/create output panel
        window = self.view.window()
        view = window.get_output_panel('reg_replace_results')

        # Turn off styles in panel
        view.settings().set('draw_white_space', 'none')
        view.settings().set('draw_indent_guides', False)
        view.settings().set('gutter', 'none')
        view.settings().set('line_numbers', False)
        view.set_syntax_file('Packages/Text/Plain text.tmLanguage')

        # Show Results in read only panel and clear selection in panel
        window.run_command('show_panel',
                           {'panel': 'output.reg_replace_results'})
        view.set_read_only(False)
        RegReplaceGlobal.bfr = 'RegReplace Results\n\n' + text
        RegReplaceGlobal.region = sublime.Region(0, view.size())
        view.run_command("reg_replace_apply")
        RegReplaceGlobal.clear()
        view.set_read_only(True)
        view.sel().clear()

    def perform_action(self):
        """Perform action on targeted text."""

        status = True
        if self.action == 'fold':
            # Fold regions
            self.view.fold(
                self.ignore_ending_newlines(self.replace_obj.target_regions))
        elif self.action == 'unfold':
            # Unfold regions
            try:
                self.view.unfold(
                    self.ignore_ending_newlines(
                        self.replace_obj.target_regions))
            except Exception:
                error(
                    "Cannot unfold! Please upgrade to the latest stable beta build to remove this error."
                )
        elif self.action == 'mark':
            # Mark targeted regions
            if 'key' in self.options:
                color = self.options['scope'].strip(
                ) if 'scope' in self.options else DEFAULT_HIGHLIGHT_COLOR
                style = self.options['style'].strip(
                ) if 'style' in self.options else DEFAULT_HIGHLIGHT_STYLE
                self.set_highlights(self.options['key'].strip(), style, color)
        elif self.action == 'unmark':
            # Unmark targeted regions
            if 'key' in self.options:
                self.clear_highlights(self.options['key'].strip())
        elif self.action == 'select':
            self.view.sel().clear()
            self.view.sel().add_all(self.replace_obj.target_regions)
        else:
            # Not a valid action
            status = False
        return status

    def find_and_replace(self):
        """
        Walk the sequence finding the targeted regions in the text.

        If allowed, replacements will be done as well.
        """

        if self.use_test_buffer:
            replace_list = sublime.load_settings(
                'reg_replace_test.sublime-settings').get('replacements', {})
        else:
            replace_list = rrsettingsrules.get('replacements', {})
        result_template = '%s: %d regions;\n' if self.panel_display else '%s: %d regions; '
        results = ''

        # Walk the sequence
        # Multi-pass only if requested and will be occurring
        if self.multi_pass and not self.find_only and self.action is None:
            # Multi-pass initialization
            current_replacements = 0
            total_replacements = 0
            count = 0

            # Sweep file until all instances are found
            # Avoid infinite loop and break out if sweep threshold is met
            while count < self.max_sweeps:
                count += 1
                current_replacements = 0

                for replacement in self.replacements:
                    # Is replacement available in the list?
                    if replacement in replace_list:
                        pattern = replace_list[replacement]
                        current_replacements += self.replace_obj.search(
                            pattern, 'scope' in pattern)
                total_replacements += current_replacements

                # No more regions found?
                if current_replacements == 0:
                    break
            # Record total regions found
            results += 'Regions Found: %d regions;' % total_replacements
        else:
            not_found = []
            for replacement in self.replacements:
                # Is replacement available in the list?
                if replacement in replace_list:
                    pattern = replace_list[replacement]
                    results += result_template % (
                        replacement,
                        self.replace_obj.search(pattern, 'scope' in pattern))
                else:
                    not_found.append(replacement)
            if not_found:
                error("%d rules not found! See console." % len(not_found))
                print('\n'.join(
                    ['RegReplace: "%s" not found!' % r for r in not_found]))
        return results

    def start_sequence(self):
        """Run the replace sequence."""

        # Find targets and replace if applicable
        results = self.find_and_replace()

        if self.find_only:
            # Highlight regions
            style = rrsettings.get('find_highlight_style',
                                   DEFAULT_HIGHLIGHT_STYLE)
            color = rrsettings.get('find_highlight_color',
                                   DEFAULT_HIGHLIGHT_COLOR)
            self.set_highlights(MODULE_NAME, style, color)
            self.replace_prompt()
        else:
            self.clear_highlights(MODULE_NAME)
            # Perform action
            if self.action is not None:
                if not self.perform_action():
                    results = 'Error: %s - Bad Action!' % self.action

            # Report results
            if self.panel_display:
                self.print_results_panel(results)
            else:
                self.print_results_status_bar(results)
            self.replace_obj.close()

    def run(self,
            edit,
            replacements=None,
            find_only=False,
            clear=False,
            action=None,
            multi_pass=False,
            no_selection=False,
            regex_full_file_with_selections=False,
            options=None,
            use_test_buffer=False):
        """Kick off sequence."""

        if replacements is None:
            replacements = []
        if options is None:
            options = {}

        self.use_test_buffer = bool(use_test_buffer)
        self.find_only = bool(find_only)
        self.action = action.strip() if action is not None else action
        self.full_file = bool(regex_full_file_with_selections)
        if not no_selection and rrsettings.get(
                'selection_only', False) and self.is_selection_available():
            self.selection_only = True
        else:
            self.selection_only = False
        self.max_sweeps = rrsettings.get('multi_pass_max_sweeps',
                                         DEFAULT_MULTI_PASS_MAX_SWEEP)
        self.replacements = replacements
        self.multi_pass = bool(multi_pass)
        self.panel_display = rrsettings.get('results_in_panel',
                                            DEFAULT_SHOW_PANEL)
        self.options = options
        self.clear = clear

        self.replace_obj = FindReplace(self.view, edit, self.find_only,
                                       self.full_file, self.selection_only,
                                       self.max_sweeps, self.action)

        # Clear regions and exit; no need to run sequences
        if self.clear_regions():
            self.replace_obj.close()
            return

        # Is the sequence empty?
        if len(self.replacements) > 0:
            self.start_sequence()
        else:
            self.replace_obj.close()