Sublime Forum

Find for a Macro

#1

I’d like to find a character and the cursor to remain at the position of that character and to be able to use that function in a macro (I’ll have to do this the hard way, but for next time)

The function will (plugin) no doubt be a combination of these two (excellently written by @OdatNurd I think)

import sublime
import sublime_plugin


class FindReplaceCommand(sublime_plugin.TextCommand):

    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

import sublime, sublime_plugin

class GotoColCommand(sublime_plugin.TextCommand):

    def run(self, edit, col=120):
        for s in self.view.sel() :
            _ , c_col = self.view.rowcol(s.a)
            nb_space = col - c_col
            if nb_space > 0:
                self.view.insert(edit, s.a, ' '*nb_space)

Something like (and I know no Python)

import sublime, sublime_plugin

class GotoCharacter(sublime_plugin.TextCommand)

    def run(self, edit, patter)
        found = self.view.find(patter, self)
        if not found
            return
            # I HAVE ABSOLUTELY NO IDEA AT THIS POINT
        for s in self.view.sel()
            self.view.insert ()

Thank you very much. It’s such a roller coaster :star_struck::crazy_face:

Lozminda

0 Likes

#2

I’m not quite sure what you mean by this, can you explain a bit better what you want to achieve? The “remain at the position of that character” part is what’s throwing me. Do you want to jump the cursor to the first instance after where it currently sits that the pattern you provides matches?

0 Likes

#3

In a word, yes But just to confirm…
Imagine the cursor is on the line above #ifdef DEBUG and I want to find and goto the next ’ { '.
The cursor would then be moved to the next { which is under the line
while (startPow != - 1)

#ifdef DEBUG
    for ( ; param < mypow(BASE, startPow); --startPow);         // Find starting power
#else
    for ( ; param < pow(BASE, startPow); --startPow);           // Find starting power
#endif

    while (startPow != - 1)
    {
      int tempResult = param / mypow(BASE,startPow);
      int tempResult = param / mypow(BASE,startPow);

(This so I can use a macro to goto ‘{’ , select the contents of the brackets ({}) with ctrl+shift+m, and then delete it all, and then add a ; on the line above.)

The find and replace macro just finds and replaces everything (very well i might add) but doesn’t move the cursor…

Thank you !

0 Likes

#4

Sounds like what you want is the plugin from your related forum post, but with view.find_all() instead of view.find_by_selector(), so that it will search for a specific pattern of characters instead of by scope.

class PatternNavigateCommand(sublime_plugin.TextCommand):
    """
    Jump the selection in the file to the next or previous location of the
    given textual pattern based on the current cursor location. The search
    direction is controlled by the forward argument, and will wrap around the
    ends of the buffer.
    """
    def run(self, edit, pattern, literal=True, ignorecase=False, forward=True):
        flags = ((sublime.LITERAL if literal else 0) | 
                 (sublime.IGNORECASE if ignorecase else 0))

        # Find the locations where this pattern occurs; leave if none
        regions = self.view.find_all(pattern, flags)
        if not regions:
            return

        # Get a starting point for our search, and where we should jump to if
        # there are no matches in the specified direction.
        point = self.view.sel()[0].b
        fallback = regions[-1] if not forward else regions[0]

        # Remove all selections.
        self.view.sel().clear()

        # Look in the given direction for the first match from the current
        # position; if one is found jump there.
        pick = lambda p: (point < p.a) if forward else (point > p.a)
        for pos in regions if forward else reversed(regions):
            if pick(pos):
                return self.jump(pos.a)

        # No matches in the search direction, so wrap around.
        self.jump(fallback.a)

    def jump(self, point):
        # Add in the given position as a selection and ensure that it's
        # visible.
        self.view.sel().add(sublime.Region(point))
        self.view.show(point, True)

You can change the default values for literal and ignorecase as needed if you mostly always use a regex versus literal or always want to ignore case versus never, etc.

1 Like

#5

OOOooooo that looks sexy ! But I can’t get it to work: Here’s my implementation

I called it this
PatternNavigateCommand(sublime_plugin.TextCommand):

and here it is:

	{
  	"keys": ["super+p","super+n"],
  	"command": "pattern_navigate",
  	"args":{
  	"pattern": "{",
  	"literal":true,
    "ignorecase":false,
    "forward":true}
  },

I tried commenting out literal and ignore case in case I could ignore the defaults, but no.
I tried cross referencing with other plugins but all their api’s are just a tiny bit different and IDKAP !
(I don’t know any python)
Am sure I’m doing something stupid…

0 Likes

#6

Got it to work.

0 Likes