Sublime Forum

Find and Replace again! (Something Different though)

#1

This is @deathaxe 's plugin. It’s a bit old I’ve subsequently realised which is why I had to kill ST3, or it might have died before I hit the enter button (I had to find PID etc)
Any chance of some tweaks so it doesn’t blow up my machine please. (There’s an also at the end if you don’t mind…)

import sublime
import sublime_plugin


class FindReplaceCommand(sublime_plugin.TextCommand):
    """The implementation of 'find_replace' text command.

    Example:

        view.run_command(
            "find_replace", {
                "pattern": "the",
                "replace_by": "THE",
                "start_pt": 100,
                "flags": ["LITERAL"]
            }
        )
    """

    FLAGS = {
        "LITERAL": sublime.LITERAL,
        "IGNORECASE": sublime.IGNORECASE
    }

    def run(self, edit, pattern, replace_by, start_pt=0, flags=[]):
        """Find and replace all patterns.

        Arguments:
            edit (sublime.Edit):
                The edit token used to undo this command.
            pattern (string):
                The regex pattern to use for finding.
            replace_by (string):
                The text to replace all found words by.
            start_pt (int):
                The text position where to start.
            flags (list):
                The flags to pass to view.find()
                ["LITERAL", "IGNORECASE"]
        """
        while True:
            found = self.view.find(pattern, self._flags(flags), start_pt)
            if not found:
                return
            self.view.replace(edit, found, replace_by)
            start_pt = found.begin()

    def _flags(self, flags):
        """Translate list of flags."""
        result = 0
        for flag in flags:
            result |= self.FLAGS.get(flag, 0)
        return result

How could I mod this code so that pattern, initial value could be assigned by the selected text, replace_by by ctrl+shift+e, start_pt by position of caret/cursor, like how ctrl+h works. Does this make sense ? So I can get input from the keyboard etc.
I include the keybinding I used too:

    { "keys": ["alt+f","alt+r"],
    	"command": "find_replace",
    	"args":{
    	"pattern": "the",
    	"replace_by":"THE",
    	"start_pt":0,
    	"flags":["LITERAL"]}}

Cheers !! :unicorn:

0 Likes

#2

Try this modified code snippet. I have refactored the code to not make use of the while True condition. (Probably this is what is causing the hang)

import sublime
import sublime_plugin


class FindReplaceCommand(sublime_plugin.TextCommand):
    """The implementation of 'find_replace' text command.

    Example: import

        view.run_command(
            "find_replace", {
                "pattern": "the",
                "replace_by": "THE",
                "start_pt": 100,
                "flags": ["LITERAL"]
            }
        ) import
    """

    FLAGS = {
        "LITERAL": sublime.LITERAL,
        "IGNORECASE": sublime.IGNORECASE
    }

    def run(self, edit, pattern, replace_by, flags=[]):
        """Find and replace all patterns.

        Arguments:
            edit (sublime.Edit):
                The edit token used to undo this command.
            pattern (string):
                The regex pattern to use for finding.
            replace_by (string):
                The text to replace all found words by.
            flags (list):
                The flags to pass to view.find()
                ["LITERAL", "IGNORECASE"]
        """
        found = self.view.find_all(pattern, self._flags(flags))
        if not found:
            return
        for idx, region in enumerate(found):
            if idx == 0:
                self.view.replace(edit, region, replace_by)
            else:
                difference = len(replace_by) - len(pattern)
                if difference != 0:
                    modified_region = sublime.Region(region.begin() + (idx * difference), 
                                                        region.end() + (idx * difference))
                    self.view.replace(edit, modified_region, replace_by)
                else:
                    self.view.replace(edit, region, replace_by)

    def _flags(self, flags):
        """Translate list of flags."""
        result = 0
        for flag in flags:
            result |= self.FLAGS.get(flag, 0)
        return result

And the key bindings :-

{
	"keys": ["ctrl+alt+shift+3"],
	"command": "find_replace",
	"args": {
		"pattern": "import",
		"replace_by": "abcdef",
		"flags": ["IGNORECASE"]
	},
},

The start_pt is not required anymore because the modification uses View.find_all instead of View.find.

This one I’ll leave as an exercise to the interested readers. Some hints so that you can do it yourself are :-

All you need is View.sel() to get the selection & convert that to its string representation using View.substr()

ctrl + shift + e copies the selected text to the replace panel. I have tried but it seems it doesn’t copy it to the system clipboard (even though the status bar message indicates otherwise).

0 Likes

#3

Awesome ! I’ll get back to this a bit later and feedback then, in the interim, thank you ! :unicorn: :skull_and_crossbones:

Ps I’ve popped it in, run it once, looks good so far, but I’ve really got to do some work now ! :sweat_smile:

0 Likes

#4

It doesn’t have to work exactly the same, just so it could receive input from the open tab/caret rather than having to go into the keybinding page and alter it’s args there. Always looking to save those key strokes, esp when you’re as bad a typist as I am…:crazy_face:

0 Likes