Sublime Forum

Multi Selection Editing

#1

Hi all,

So I’m attempting to write my first Sublime plugin :astonished: 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

0 Likes

#2

You probably want to add a key binding of “$,1” for your command

0 Likes

#3

Sounds like a good start!

0 Likes

#4

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]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)

[/code]
Only now I keep getting:

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

0 Likes

#5

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:

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

0 Likes

#6

[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]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)[/code]
The key mapping is set to, { "keys": "ctrl+alt+n"], "command": "insert_nums"}I’ve tried adding an overlay and calling it. Nadda.[/quote]

0 Likes

#7

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:

{ "keys": "ctrl+alt+n"], "command": "prompt_insert_nums"},
{ "keys": "ctrl+alt+m"], "command": "insert_nums", "args": {"current": 1, "step": 1} }
0 Likes

#8

Ah that’s neat!

Now I’m getting reports of:

self.view.replace(self.edit, region, str(current)) AttributeError: 'InsertNumsCommand' object has no attribute 'edit'
Yet my run function is as it should be;

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.

0 Likes

#9

edit is a parameter, rather than a member variable, so you should omit the ‘self.’ prefix

0 Likes

#10

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:

0 Likes