Sublime Forum

Use of edit object after run

#1

Hi All,

I am working on a little enhancement for a plugin, here is what I am trying to do

  1. User invokes a command which opens a show_quick_panel with a list of options (1, 2, 3…)
  2. Once the user picks an option from I pass an id to the my on_done callback
  3. Inside on_done I am trying to update the view based on user option selection which is mostly replacing content in the view
  4. when I try to use edit from the callback I get an error saying edit cannot be used outside of run I assume on_done callback runs at a later time without access to the edit object
  5. Now how can I replace content I also explored looking into run_command with replace_text
  6. I tried doing self.view.run_command('replace_text', { "region": sublime.Region(0, 10), "text": "some super stuff" } ) I got an error message saying TypeError: Value required not sure what I did wrong

What is the idiomatic way to do this? ideally I would like to access the edit object inside my callback since I already have a helper method which updates the view in other places so I could use the same

Lastly I looked into edit.py which creates a reference to the view for later use? when I tried using it I see a new copy of the view and my replace still doesn’t happen

I need help :slight_smile:

0 Likes

#2

Ok, I simplified this now I have a bunch of offsets with corresponding text
{start: (1, 10), end: (1, 24), text: "replacement text"}

I am outside run so I need something which doesn’t need edit is there any self.view.run_command for this?

0 Likes

#3

You just create a new TextCommand, e.g. MyEnhancementCallbackCommand and afterwards run self.view.run_command("my_enchancement_callback", {start: (1, 10), end: (1, 24), text: "replacement text").

As a reference you can see a similar command in GitGutter and its usage. Unfortunatly every package has to define the command on it’s own to ensure such a replace command exists.

0 Likes

#4

yeah, this is something every plugin developer comes up against eventually - that only simple value types can be passed as arguments to commands (thus the need for turning regions into tuples) and that there is no built in replace command that takes a region and a replacement text. The latter can be worked around by changing the selection (although this should also be done inside an edit context) and using the standard insert command.

0 Likes

#5

cool thanks, getting close I have this but for some reason my TestGitGutterReplaceTextCommand never runs

class TestGitGutterReplaceTextCommand(sublime_plugin.TextCommand):

    def run(self, edit, start, end, text):
  
        print("running replace")  # <--- never runs
        visible_region = self.view.visible_region()
        region = sublime.Region(start, end)
        self.view.replace(edit, region, text)
        if start < visible_region.begin():
            self.view.show_at_center(start)
        self.view.sel().clear()
        self.view.sel().add(start)


class TypescriptGetCodeFixesCommand(TypeScriptBaseTextCommand):
    """
    Code Fixes command
    """
    possibleFixes = []
    edit = None
    text = None

    def tab_selected(self, idx):
        if idx == -1:
            return
        changes = self.possibleFixes['body'][idx]['changes'][0]['textChanges']
        start = (changes[0]['start']['line'], changes[0]['start']['offset'])
        end = (changes[0]['end']['line'], changes[0]['end']['offset'])
        text = changes[0]['newText']
        print(start, end, text)  # <-- (5, 8) (5, 11) { ScheduleEntrySwapRequest }
        self.view.run_command('test_git_gutter_replace_text', {'start': start, 'end': end, 'text': text})

and I have this

class TypeScriptBaseTextCommand(sublime_plugin.TextCommand):
    def is_enabled(self):
        return is_typescript(self.view) and get_language_service_enabled()
0 Likes

#6

Is the file in a subfolder of your package?

0 Likes

#7

yes, does it make a difference

0 Likes

#8

Files from sub-folders aren’t automatically loaded by Sublime unless you import from them, and they’re not automatically reloaded when they change, either. If restarting Sublime makes your command work the way you expect it to, that’s probably the issue that you’re seeing.

Packages like AutomaticPackageReloader help with that by forcing everything to reload so you don’t have to keep restarting Sublime.

0 Likes

#9

Cool, thanks all I figured out. the reference links to git_gutter implementation are valuable.

One last thing is there any way to keep the cursor at the current location instead of moving to the newly replaced region.

0 Likes

#10

Just remove the stuff you don’t want:

def run(self, edit, start, end, text):
        region = sublime.Region(start, end)
        self.view.replace(edit, region, text)
1 Like

#11

thanks !!!

0 Likes