Home Download Buy Blog Forum Support

Kick-start for plug-in

Kick-start for plug-in

Postby agibsonsw on Sun Feb 19, 2012 10:41 pm

Can someone push me in the right-direction with studying/developing a plug-in please?

The second to last line of the following code is my sticking point at the moment.

Code: Select all
import sublime, sublime_plugin

class ExampleCommand(sublime_plugin.TextCommand):
   def run(self, edit):
      # self.view.insert(edit, 0, "Hello, World!")
      the_sels = self.view.sel()
      for a_sel in the_sels:
         # the_text = self.view.substr(a_sel)
         # self.view.insert(edit, 0, the_text)
         # self.view.replace(edit,a_sel,"howdy")
         the_text = self.view.line(a_sel)   # the current line of text?
         self.view.insert(edit, 0, the_text)

I want to read (store) the current line of text. How do I achieve this please?

2) Also, do I need to loop through all selections, or is it possible just to specify the current line/ cursor location?
3) How do I read/store the current 'point'? That is, the cursor position (on the current line)?

Andy.
"I'm here to save your life. But if I'm going to do that, I'll need total uninanonynymity." Me Myself & Irene.
agibsonsw
 
Posts: 901
Joined: Fri Jan 27, 2012 9:11 pm

Re: Kick-start for plug-in

Postby guillermooo on Sun Feb 19, 2012 11:07 pm

1) view.substr(<region>)
2) view.sel() => list of sels
3) view.sel()[0].begin() or .end() or .a or .b
guillermooo
 
Posts: 729
Joined: Thu Jul 23, 2009 9:06 am

Re: Kick-start for plug-in

Postby C0D312 on Sun Feb 19, 2012 11:10 pm

I can help :)

When you first start creating a plugin, don't worry about multiple cursors. It will just get your code messy and you'll get confused. The best way to start it looking through the premade plugins in Packages/Default or at someone else's plugin. Also, when working on a plugin, always keep your console open (control + `). "Print" is your friend, especially when learning the difference between a Region, a RegionSet, a String, and a Point. For example, on your second to last line, line() returns a region while insert() is expecting a string. Try printing out a Region to your console, it is essentially a tuple of points. To retrieve the actual text that corresponds to that Region, use self.view.substr().

2. If you must deal with multiple cursors, your only way is through looping, yes.
3. It's important to know how to convert what you have to what you need. self.view.sel() returns a list of cursor positions. If you look at any of my plugins, I usually start with
Code: Select all
sel = self.view.sel()[0]

because more often than not, I'm only using one cursor. However, sel is a Region here, meaning that if you have something selected, it will look like this:
Code: Select all
(Start of Selection, End of Selection)
*Note*: Start of Selection does not mean beginning. If you select text from right to left, the Region will be reversed. So to retrieve a point: you have a few options.

sel.a --> the start of the selection (aka what the user selects first)
sel.b --> the end of the selection (aka where the user stopped the selection)
sel.begin() --> the minimum of a and b (If you need to know the leftmost/topmost point of the selection no matter how the user selects the text)
sel.end() --> the maximum of a and b

Each of these 4 methods returns an int, which, as far as the API is concern, is equivalent to a point.

If there is no text selected, sel.b and sel.end() will return the same thing it's your preference as to which you use to retrieve the current cursor position. So your code would be something like:
Code: Select all
sel = self.view.sel()[0]
line = self.view.line(sel.b)


Another great resource: Will Bond wrote an excellent piece on Nettuts+ on how to create a plugin (here: http://net.tutsplus.com/tutorials/pytho ... -2-plugin/)
C0D312
 
Posts: 1063
Joined: Sun Jul 10, 2011 3:23 am

Re: Kick-start for plug-in

Postby agibsonsw on Sun Feb 19, 2012 11:21 pm

This is great, thanks both!

@COD312 I had that web page already open ;). It's good, but I needed to ignore bits of it (such as threading), and the multi-select is distracting for a beginner.

I did manage to grab the current line and replace it, woo-hoo! But it replaces the initial tabs as well.

Code: Select all
line = self.view.line(the_region)
self.view.replace(edit, line, "Hello there")

How would I skip the tabs at the beginning of the line please? Regards, Andy.
"I'm here to save your life. But if I'm going to do that, I'll need total uninanonynymity." Me Myself & Irene.
agibsonsw
 
Posts: 901
Joined: Fri Jan 27, 2012 9:11 pm

Re: Kick-start for plug-in

Postby C0D312 on Sun Feb 19, 2012 11:34 pm

Short anwer: regex + python's string.strip() method

Long answer: I just had to do this for a plugin of mine. I was working with PHP and wanted to prepend certain lines with $. Unfortunately, the spacing in the beginning of the line would get screwed up. So here's my workaround: https://github.com/BoundInCode/PHP-Sani ... eatevar.py I used view.find() to get the actual start of the line.
C0D312
 
Posts: 1063
Joined: Sun Jul 10, 2011 3:23 am

Re: Kick-start for plug-in

Postby agibsonsw on Sun Feb 19, 2012 11:54 pm

@COD312 Thanks again. I've a bit of studying to do!

I'm not yet familiar with Python, but I tested
print line_contents.find('\t');

to find the first tab position (if any). But if find() uses regex then I suppose it could find the first non-whitespace character. I'll admit I haven't studied your example yet (it's a bit late!) but I'm assuming I could store all the (beginning) non-ws characters in a variable, then pre-pend them to my new string before replacing the line.

I'll have a look again tomorrow. Regards, Andy.
"I'm here to save your life. But if I'm going to do that, I'll need total uninanonynymity." Me Myself & Irene.
agibsonsw
 
Posts: 901
Joined: Fri Jan 27, 2012 9:11 pm

Re: Kick-start for plug-in

Postby agibsonsw on Mon Feb 20, 2012 1:42 pm

I got this to work :D. That is, to replace the current line of text, but keep the same indenting:

Code: Select all
sel = self.view.sel()[0]
cur_line = self.view.line(sel)
print cur_line      # tuple
line_text = self.view.substr(cur_line)
print '#' + line_text + '#'      # includes tabs/ spaces
mtc = re.search('\S',line_text)
pos_ltr = mtc.start(0)         # the posn of the 1st character
print pos_ltr
white_sp = line_text[0:pos_ltr]
self.view.replace(edit, cur_line, white_sp + "Hello there")

It stores the white-space at the beginning of the line (hopefully!) and then prepends this to the replacement text. I could then add it to any further lines.

It's not bullet-proof yet. In particular, if begin() = end() is there an 'Exit Function' or 'End' equivalent in Python? Andy.
"I'm here to save your life. But if I'm going to do that, I'll need total uninanonynymity." Me Myself & Irene.
agibsonsw
 
Posts: 901
Joined: Fri Jan 27, 2012 9:11 pm

Re: Kick-start for plug-in

Postby C0D312 on Mon Feb 20, 2012 1:55 pm

Code: Select all
if sel.empty():
    return
C0D312
 
Posts: 1063
Joined: Sun Jul 10, 2011 3:23 am

Re: Kick-start for plug-in

Postby agibsonsw on Mon Feb 20, 2012 2:03 pm

C0D312 wrote:
Code: Select all
if sel.empty():
    return

Thank you. But, oops! My mistake. I meant if the current line is empty.

I suppose, given that I'm reading past all the white-space characters, I should check if this either 'fails', or is at, or beyond, the end-point of the line..

Andy.
"I'm here to save your life. But if I'm going to do that, I'll need total uninanonynymity." Me Myself & Irene.
agibsonsw
 
Posts: 901
Joined: Fri Jan 27, 2012 9:11 pm

Re: Kick-start for plug-in

Postby agibsonsw on Mon Feb 20, 2012 2:08 pm

No worries ;)

Code: Select all
if not mtc:
   print 'nothing there'
   return
"I'm here to save your life. But if I'm going to do that, I'll need total uninanonynymity." Me Myself & Irene.
agibsonsw
 
Posts: 901
Joined: Fri Jan 27, 2012 9:11 pm

Next

Return to Technical Support

Who is online

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