Sublime Text plugin Development

Source: Internet
Author: User

Foreword: Terminology and references
Sublime Text 2's expansion mode is quite rich. There are multiple ways to modify the syntax highlighting mode and all menus. It can also create a new build system, auto completion, language definitions, code snippets, macro definitions, shortcut key bindings, mouse event bindings and plugins. All of this is achieved through a package of files.
A package is a folder under the ‘Packages’ directory, which can be accessed through the Preferences> Browse Packages ... menu to open the directory. You can also convert a package into a zip file, and then change the extension to .sublime-package. There will be more introductions about packaging later.
Sublime bundles many packages by default. Most packages are language-specific. The package contains language definitions, automatic completion and build system. There are also 2 packages: Default and User. The Default package contains all standard keyboard bindings, menu definitions, file configurations and a lot of plugins written in python. The User package is special, it is always loaded at the end. Through custom files in the User package, it allows users to override all default behaviors.
To write a good plugin, a good manual is of course necessary: Sublime Text 2 API reference
The contents of the Default package are also a good reference, you can dig out how the predecessors under the tomb did, and what is possible.
Most editors provide command functions, and all operations except inputting characters can be completed by commands. Preferences> Key Bindings-Default Through this menu you can see all the built-in commands.
In addition, the Sublime plug-in needs to be developed with Python. It has a built-in Python environment, and the console is actually a Python console.
Tears Ben, it seems that all I can understand except the front-end technology is python. . .
OK, after understanding the plugin and package mechanism, you can start writing a plugin to play with.
 
Step1- Create a plugin
 To write a simple plug-in for Sublime, we must first create a Python skeleton code.
Through the Tools> New Plugin ... menu, you can automatically create a template for a plug-in.
 
import sublime, sublime_plugin
class ExampleCommand (sublime_plugin.TextCommand):
    def run (self, edit):
        self.view.insert (edit, 0, "Hello, World!")
 
Imported 2 modules and created a command class. Let's save it and try it out.
When saving, create a package. The save pop-up box is by default in the Packages \ User directory, No, we want to create an own package to save. Create a Prefixr directory under the Packages directory:
 
Packages /

-OCaml /
-Perl /
-PHP /
-Prefixr /
-Python /
-R /
-Rails /

Then save the file package in the Prefixr directory and name it Prefixr.py. (Because this original tutorial is based on creating the plug-in Prefixr, in fact, we already have this plug-in package in the sublime we installed, so if you experiment with it, you can take any name and use it as another plug-in.) The file Prefixr.py can also have other names, but it must have a .py file suffix, preferably the same as the name of the plugin directory.
In this way, the plug-in is saved. Open the sublime console ctrl + `. This is actually a Python console where you can run python code. Type in the console:
 
view.run_command (‘example’)
You can see that "Hello World" is inserted at the beginning of the active file in the current editor.
Remember to undo and continue. . .
Step2-Command type and name
Sublime provides 3 types of commands to the plugin.
Text Commands provide access to the contents of the current View object (that is, the file being edited).
Window Commands provides a reference to the Window object of the current editor.
Application Commands do not provide references to any windows or files, and they are rarely used.
 
In this way, we have to use the sublime_plugin.TextCommand class to edit the CSS file. So our Prefixr command inherits sublime_plugin.TextCommand.
 
class ExampleCommand (sublime_plugin.TextCommand):
Then execute it in the console when running this plugin
 
view.run_command (‘example’)
Sublime will remove the Command suffix from all classes that inherit from sublime_plugin (TextCommand, WindowCommand, ApplicationCommand), and then convert the camel case format to underline format as the name of the command
Therefore, to create a prefixr command, the class name is PrefixrCommand.
 
class PrefixrCommand (sublime_plugin.TextCommand):
(In analogy, if the class name is MyTestCommand, the command name is my_test, and when you run the plugin with view.run_command ('example'), 'example' is the command name, so if the class name is MyTestCommand, use view. run_command ('my_test') run).
 
Step3-select text
Very good, now our plug-in finally has a name, although it still looks a bit silky. We started to get css from the current buffer and pass it to the Prefix API to do something. One of Sublime's powerful features is its ability to make multiple choices. The plugin we are writing now, of course, needs to process all the selected text.
Under the text command class, you can access the current view through self.view. The view's sel () method returns an iterable of all currently selected sections. First, we scan for braces, and if not, expand to the outer selection to determine the prefix of the entire area. Whether or not there are curly brackets, it can help us determine whether we need to blank and format the results returned by the Prefixr API.
 
braces = False
sels = self.view.sel ()
for sel in sels:
    if self.view.substr (sel) .find (‘{‘)! = -1:
        braces = True
This code replaces the content of the run () method and executes directly.
If we do not find the curly braces, we are looking for the closest closed curly brace for each selection, and then use the built-in expand_selection command, the to parameter is set to brackets and the content of each css rule area can be selected.
 
if not braces:
    new_sels = []
    for sel in sels:
        new_sels.append (self.view.find (‘\}’, sel.end ()))
    sels.clear ()
    for sel in new_sels:
        sels.add (sel)
    self.view.run_command ("expand_selection", {"to": "brackets"})
You can refer to Prefixr-1.py in the code base
 
Step4-thread
Now, the selection has been extended to each css code block. It will be sent to the Prefixr API. Don't look up, this is just a small HTTP request, just use urlib, urllib2 and other modules. But let us first think about how a slow web request will affect the performance of the editor. If the response of the Prefixr API is too slow, you should be very anxious. . .
So we should put this request processing in the background quietly. This will use threads.
In fact, threading is Python's own ability, and it has nothing to do with this sublime, right?
 
Step5-Create thread
The threading module is used here to create a PrefixrApiCall inherited from threading.gThread, which needs to implement the run method, which contains the code to be run.
class PrefixrApiCall (threading.Thread):
    def __init __ (self, sel, string, timeout):
        self.sel = sel
        self.original = string
        self.timeout = timeout
        self.result = None
        threading.Thread .__ init __ (self)
    def run (self):
        try:
            data = urllib.urlencode ({‘css‘: self.original})
            request = urllib2.Request (‘http://prefixr.com/api/index.php’, data,
                headers = {"User-Agent": "Sublime Prefixr"})
            http_file = urllib2.urlopen (request, timeout = self.timeout)
            self.result = http_file.read ()
            return
        except (urllib2.HTTPError) as (e):
            err = ‘% s: HTTP error% s contacting API’% (__name__, str (e.code))
        except (urllib2.URLError) as (e):
            err = ‘% s: URL error% s contacting API’% (__name__, str (e.reason))
        sublime.error_message (err)
        self.result = False
The __init __ () method sets some values needed to make web requests. The run () method contains the code to create http and request the Prefixr API. Because the thread runs at the same time as other code, it cannot return the value directly. So use self.result to save the result of the call.
Because we have introduced many other modules here, we must add an import statement to the head:
 
import urllib
import urllib2
import threading
[Tucao, this is Python's own stuff. Python is the basis for writing plug-ins, so I won't talk too much about it here. . 】
Now that we have a thread class to make http requests, we need to create a thread for each section of the CSS. Back to the run () method of the PrefixrCommand class, use the following code:
 
threads = []
for sel in sels:
    string = self.view.substr (sel)
    thread = PrefixrApiCall (sel, string, 5)
    threads.append (thread)
    thread.start ()
Record each created thread, and then call the thread's start () method to start it.
You can refer to the Prefixr-2.py in the code base
 
Step6- Prepare for results
Before processing the response result of the Prefixr API request, we need to do some processing.
First, clear all selections, because we have made changes before.
 
self.view.sel ()
.clear ()
Also create an Edit object. Specify a group of prefixr operations, group operations can be easily redo and undo.
 
edit = self.view.begin_edit (‘prefixr’)
Finally, call a method we will write later to handle the response to the API request.
 
self.handle_threads (edit, threads, braces)
 
Step7-processing thread
Now our threads should be running in high profile, or some of them will be over after a while. Now we have to implement the handle_threads () method used earlier. This method traverses the thread list to check whether the display is still running.
 
def handle_threads (self, edit, threads, braces, offset = 0, i = 0, dir = 1):
    next_threads = []
    for thread in threads:
        if thread.is_alive ():
            next_threads.append (thread)
            continue
        if thread.result == False:
            continue
        offset = self.replace (edit, thread, braces, offset)
    threads = next_threads
If the thread is still running, add it to a thread list and stay in school to continue viewing. Ignore if the view fails, but in order to have a better effect, a replace () method will be written later.
In addition, as a front-end engineer, of course, must understand the user experience. We can tell users in the status bar that our plug-in is working hard, no laziness.
 
if len (threads):
    # This animates a little activity indicator in the status area
    before = i% 8
    after = (7)-before
    if not after:
        dir = -1
    if not before:
        dir = 1
    i + = dir
    self.view.set_status (‘prefixr’, ‘Prefixr [% s =% s]‘% \
        (‘‘ * Before, ‘‘ * after))
    sublime.set_timeout (lambda: self.handle_threads (edit, threads,
        braces, offset, i, dir), 100)
    return
(Still requires a lot of python knowledge ...)
 
When all threads are completed, you can end the revoked group mark, and then notify the user.
 
self.view.end_edit (edit)
self.view.erase_status (‘prefixr’)
selections = len (self.view.sel ())
sublime.status_message (‘Prefixr successfully run on% s selection% s’%
    (selections, ‘‘ if selections == 1 else ‘s’))
Can refer to Prefixr-3.py file code
 
Step8-perform replacement
As mentioned before with the replace () method, we need to replace the original css code with the result returned by the Prefixr API.
This method accepts several parameters, the Edit object used for cancellation, the result returned by the Prefixr API, and the offset of the selection
 
def replace (self, edit, thread, braces, offset):
    sel = thread.sel
    original = thread.original
    result = thread.result
    # Here we adjust each selection for any text we have already inserted
    if offset:
        sel = sublime.Region (sel.begin () + offset,
            sel.end () + offset)
Format the result before replacement, deal with the next space, end character, etc.
 
result = self.normalize_line_endings (result)
(prefix, main, suffix) = self.fix_whitespace (original, result, sel,
    braces)
self.view.replace (edit, sel, prefix + main + suffix)
 
Then expand the selection to the end of the last line of the newly inserted CSS code and return to the cheap location.
 
end_point = sel.begin () + len (prefix) + len (main)
self.view.sel (). add (sublime.Region (end_point, end_point))
return offset + len (prefix + main + suffix)-len (original)
You can refer to the Prefixr-4.py file in the code base
 
Step9-deal with blank
In the previous replacement, a normalize_line_endings () method was used to convert line breaks to line breaks in the current document.
 
def normalize_line_endings (self, string):
    string = string.replace (‘\ r \ n‘, ‘\ n‘). replace (‘\ r‘, ‘\ n‘)
    line_endings = self.view.settings (). get (‘default_line_ending‘)
    if line_endings == ‘windows’:
        string = string.replace (‘\ n’, ‘\ r \ n’)
    elif line_endings == ‘mac’:
        string = string.replace (‘\ n‘, ‘\ r’)
    return string
The fix_whitespace () method handles the indentation and space of css blocks, and can only process single css blocks.
 
def fix_whitespace (self, original, prefixed, sel, braces):
    # If braces are present we can do all of the whitespace magic
    if braces:
        return (‘‘, prefixed, ‘‘)
 
In addition, determine the indentation in the original css.
 
(row, col) = self.view.rowcol (sel.begin ())
indent_region = self.view.find (‘^ \ s +‘, self.view.text_point (row, 0))
if self.view.rowcol (indent_region.begin ()) [0] == row:
    indent = self.view.substr (indent_region)
else:
    indent = ‘‘ ‘
 
Use the indentation settings of the current file to format the prefixed css
 
prefixed = prefixed.strip ()
prefixed = re.sub (re.compile (‘^ \ s +‘, re.M), ‘‘, prefixed)
settings = self.view.settings ()
use_spaces = settings.get (‘translate_tabs_to_spaces’)
tab_size = int (settings.get (‘tab_size‘, 8))
indent_characters = ‘\ t’
if use_spaces:
    indent_characters = ‘‘ * tab_size
prefixed = prefixed.replace (‘\ n‘, ‘\ n‘ + indent + indent_characters)
 
Use the blank at the beginning to determine whether the position of the newly inserted CSS code is correct.
match = re.search (‘^ (\ s *)‘, original)
prefix = match.groups () [0]
match = re.search (‘(\ s *) \ Z’, original)
suffix = match.groups () [0]
return (prefix, prefixed, suffix)
 The fix_whitespace () method uses regularization, so import the re module.
 
The prefixr command is completed, followed by some shortcut key binding and menu binding.
 
Step-10 Keyboard binding
Most of the configuration of sublime can be done through the json file, as is the keyboard binding. However, its keyboard binding is system-specific, so basically three files must be created and named Default (Windows) .sublime-keymap, Default (Linux) .sublime-keymap and Default (OSX) .sublime-keymap
Prefixr /
...
-Default (Linux) .sublime-keymap
-Default (OSX) .sublime-keymap
-Default (Windows) .sublime-keymap
-Prefixr.py
 
This json file contains an array of objects, each object needs to contain keys, command, and args if the command requires parameters. However, the configuration of windows and linux is basically the same.
Preferences> Key Bindings-Default You can use this menu to check whether the shortcut key you want to use has already been used.
 
[
    {
        "keys": ["ctrl + alt + x"], "command": "prefixr"
    }
]
 
Step-11 Modify the menu
One of the cool things about sublime is that you can modify the menu by creating a .sublime-menu file. The configuration file needs to be named after the menu type to be modified:
Main.sublime-menu controls the main menu of the program
Side Bar.sublime-menu Right-click menu for controlling sidebar files or directories
Context.sublime-menu controls the right-click menu of files in edit state
Through this interface, through a menu configuration file may affect other menus. You can look at the existing menu configuration under the Default package.
We want to add a menu item under the Edit menu to our Prefixr plugin, and then add a configuration menu in Preferences. The following is the menu configuration in Edit. The configuration in Preferences is a bit long and omitted.
[
{
    "id": "edit",
    "children":
    [
        {"id": "wrap"},
        {"command": "prefixr"}
    ]
}
]
 
Note that the id here is an existing menu structure.
You can refer to the file in the code base https://github.com/wbond/sublime _prefixr
 
step-12 Publish your plugin package
Now I have written a very useful plug-in, of course, to share with others.
"Sublime supports zip files or a package directory to share plug-in packages. Package the package directory into a zip file, and then change the suffix to .sublime-package. Others put this file in the plug-in package directory and restart sublime to complete the installation. "
Another way is to manage the installation of plug-ins through Package Control's plug-ins. I believe you have installed them. This can be done through the following steps:
1). You need to have a github account and fork https://github.com/wbond/package_control_channel
2). Use the git clone command to download the address after you fork, such as: git@github.com: welefen / package_control_channel.git
3). Modify the repository.json file and add your plugin name and corresponding github project address to it
4) .ci and push it into your package ctrol, and then push it to the official github through pull 5) .request, if they are approved, then your plug-in will be put into the package control, others can pass install Installed directly
(The above quoted network has an article: http://www.welefen.com/how-to-develop-sublime-text-plugin.html, a brief introduction to plugin development can also refer to this article.)
 
 
Sublime text plugin development

label:

Original address: http://www.cnblogs.com/rsky/p/4569109.html


Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.