Home Download Buy Blog Forum Support

Multi Selection Editing

Multi Selection Editing

Postby jbrooksuk on Mon Feb 07, 2011 7:58 pm

Hi all,

So I'm attempting to write my first Sublime plugin :o I know...

Basically, at work I tend to use the multi selection feature to select several places (obviously) and then change an id or something to that affect. My idea is that when you have several places select and you type $1 then it will loop each selected point and replace it with the next number starting from 1.

I know that I can use sublime.region and view.sel to get the current positions, but how can I check that whilst selections are made, and the user types "$1" so that it will replace every select with the appropriate number?

And I need to account for the user actually wanting to type $1 so an escape character \ will need to be also checked as to stop the plugin from doing its business.

James
jbrooksuk
 
Posts: 775
Joined: Sun Apr 11, 2010 10:37 am
Location: England

Re: Multi Selection Editing

Postby jps on Mon Feb 07, 2011 8:18 pm

You probably want to add a key binding of "$,1" for your command
jps
Site Admin
 
Posts: 3071
Joined: Wed Mar 19, 2008 12:33 pm

Re: Multi Selection Editing

Postby jbrooksuk on Mon Feb 07, 2011 8:18 pm

jps wrote:You probably want to add a key binding of "$,1" for your command

Sounds like a good start!
jbrooksuk
 
Posts: 775
Joined: Sun Apr 11, 2010 10:37 am
Location: England

Re: Multi Selection Editing

Postby jbrooksuk on Mon Feb 07, 2011 9:35 pm

Well I found a topic from a while back where someone wanted to accomplish the same thing. I've taken the code somebody provided and updated it with V2 API function names.

Code: Select all
import sublime, sublime_plugin
import functools

class insert_nums(sublime_plugin.TextCommand):
   def run(self, view):

      sublime.active_window().show_input_panel('Enter a starting number and step.', '1 1', functools.partial(self._onDone, view), None, None)

   def _onDone(self, view, input):
      current, step = map(str, input.split(" "))

      sublime.status_message(step)
     
      for region in self.view.sel():
         sublime.status_message("Inserting #" + str(current))

         self.view.replace(sublime.Window.active_view(), region, str(current))
         current += int(step)

Only now I keep getting:
Code: Select all
  File ".\insert_nums.py", line 17, in _onDone
    self.view.replace(sublime.Window.active_view(), region, str(current))
TypeError: unbound method Boost.Python.function object must be called with Window instance as first argument (got nothing instead)

What am I supposed to set as the first argument for line 17?

James
jbrooksuk
 
Posts: 775
Joined: Sun Apr 11, 2010 10:37 am
Location: England

Re: Multi Selection Editing

Postby jps on Mon Feb 07, 2011 10:44 pm

I'd recommended structuring the plugin like Default/goto_line.py: Prompt for input in a Window command, and then run a separate text command with the desired parameters. This will ensure that macros, repeat, and the undo / redo description work as expected.

Then your TextCommand can look like:

Code: Select all
def run(self, edit, current, step):
    for region in self.view.sel():
        self.view.replace(self.edit, region, str(current))
        current += int(step)


The first argument to replace() must be an edit object, one of which is passed to each TextCommand. Edit objects didn't exist in 1.x
jps
Site Admin
 
Posts: 3071
Joined: Wed Mar 19, 2008 12:33 pm

Re: Multi Selection Editing

Postby jbrooksuk on Tue Feb 08, 2011 12:04 am

[quote="jps"]I'd recommended structuring the plugin like Default/goto_line.py: Prompt for input in a Window command, and then run a separate text command with the desired parameters. This will ensure that macros, repeat, and the undo / redo description work as expected./quote]
That makes more sense.

I now understand what Prompt/Command functions do (kinda).

One problem though. Why do I get a "TypeError: run() takes exactly 4 arguments (2 given)" error with:
Code: Select all
import sublime, sublime_plugin

class PromptInsertNumsCommand(sublime_plugin.WindowCommand):

   def run(self):
      sublime.status_message("GEKKI")
      self.window.show_input_panel('Enter a starting number and step.', '1 1', self.on_done, None, None)
      pass

   def on_done(self, text):
      try:
         current, step = map(str, input.split(" "))
         if self.window.active_view():
            self.window.active_view().run_command("insert_nums", {"current" : current, "step" : step} )
      except ValueError:
         pass
     

class InsertNumsCommand(sublime_plugin.TextCommand):

   def run(self, edit, current, step):
      for region in self.view.sel():
         sublime.status_message("Inserting #" + str(current))
         self.view.replace(self.edit, region, str(current))
         current += int(step)

The key mapping is set to,
Code: Select all
{ "keys": ["ctrl+alt+n"], "command": "insert_nums"}
I've tried adding an overlay and calling it. Nadda.
jbrooksuk
 
Posts: 775
Joined: Sun Apr 11, 2010 10:37 am
Location: England

Re: Multi Selection Editing

Postby jps on Tue Feb 08, 2011 12:13 am

You should bind to the prompt_insert_nums command, or if you do want to bind to the insert_nums command, you'll need to specify the required parameters:

Code: Select all
{ "keys": ["ctrl+alt+n"], "command": "prompt_insert_nums"},
{ "keys": ["ctrl+alt+m"], "command": "insert_nums", "args": {"current": 1, "step": 1} }
jps
Site Admin
 
Posts: 3071
Joined: Wed Mar 19, 2008 12:33 pm

Re: Multi Selection Editing

Postby jbrooksuk on Tue Feb 08, 2011 12:22 am

jps wrote:You should bind to the prompt_insert_nums command, or if you do want to bind to the insert_nums command, you'll need to specify the required parameters:

Ah that's neat!

Now I'm getting reports of:
Code: Select all
self.view.replace(self.edit, region, str(current))
AttributeError: 'InsertNumsCommand' object has no attribute 'edit'

Yet my run function is as it should be;
Code: Select all
def run(self, edit, current, step):
        for region in self.view.sel():
            sublime.status_message("Inserting #" + str(current))
            self.view.replace(self.edit, region, str(current))
            current += int(step)

So edit definitely exists.
jbrooksuk
 
Posts: 775
Joined: Sun Apr 11, 2010 10:37 am
Location: England

Re: Multi Selection Editing

Postby jps on Tue Feb 08, 2011 12:24 am

edit is a parameter, rather than a member variable, so you should omit the 'self.' prefix
jps
Site Admin
 
Posts: 3071
Joined: Wed Mar 19, 2008 12:33 pm

Re: Multi Selection Editing

Postby jbrooksuk on Tue Feb 08, 2011 12:27 am

jps wrote:edit is a parameter, rather than a member variable, so you should omit the 'self.' prefix

Hah! I actually tried that before posting.

Turns out I was saving to My Dropbox and not the packages folder.

Stupid me. Thanks for the help Jon :geek:
jbrooksuk
 
Posts: 775
Joined: Sun Apr 11, 2010 10:37 am
Location: England


Return to Plugin Development

Who is online

Users browsing this forum: Yahoo [Bot] and 5 guests