Build System build options panel in Sublime Text 2. (or how the bike was invented)

Idea and implementation: we press a shortcut in SublimeText2, we get a panel with a list of build options, automatically generated by the file selected by the Build System, select the desired option and observe how the project assembly process is directly displayed in the Sublime Text 2 interface.

I must say right away that here I share my invaluable experience in joint development of the ProjectBuild plugin for Sublime Text 2, because as a result, only experience was obtained, since, as it turned out, there was no need to implement this plugin, and this whole process turned out to be a bicycle invention. Sadly, the experience is still priceless. The narrative will be such that the "bicycle" will be said only at the end.

Introduction


The result of the previously written article “Automating the assembly of a project in Sublime Text 2 using Ant” was the ability to call in Sublime Text 2 various build variants of the selected Build System (using Ant as an example) using the assigned keyboard shortcuts for them. (now I would also use the word “tuning” in the topic of that post)
What I did not like about this approach:
  1. Different Build Systems could have completely different names for their variants, and the keyboard shortcuts were already clearly tied to specific variant names, which might not have been in another Build System. My assumption was that most developers do not often have to switch between multiple Build Systems, and most developers work with one Build System. And if the developer wants, he will change the keyboard shortcuts again. But you must admit, this is a little annoying. And this must be remembered. And in continuation, also
  2. You need to remember all the keyboard shortcuts you have assigned. It is clear that there are basic “F7”, “Ctrl + B”, “Ctrl + Shift + B” - but for each of your options there will be one more combination. This means that you must either redefine the keyboard shortcut that already exists, or find an unused one that would be convenient for both the fingers and the brain. I tried to find convenient unoccupied ones, but settled on redefinition. And this is also depressing, since it can potentially deprive you of the original capabilities of these combinations when redefined. And also to limit in the future when you need new keyboard shortcuts for new plugins, and convenient ones are already used for calls of different build-options.


And here I tried the ProjectBuild plugin for Sublime Text 2 from me in the comments snegovikufa . What I really, really liked was the drop-down panel with a list of commands. Selecting an item from the list provided, you could run the appropriate command. All the settings for this plugin were stored in a separate file, access to which was from the menu of Sublime Text 2 itself, where you could list the list of names and their corresponding commands. Simply put, this plugin could be configured to run a “third-party program” directly from the Sublime Text 2 interface. In particular, it could be used to run Ant with the names of the necessary targets. I screwed ProjectBuild on my AntProjectBuilder.sublime-build. So this solved the second problem. We assign one shortcut (even though it’s also “Ctrl + Shift + B”), it forms the ProjectBuild plugin panel in the Sublime Text 2 interface, где можно выбрать и запустить нужную команду в соответствии с конфигурацией ProjectBuild.

But the plug-in worked in such a way that while calling a “third-party program”, although it did not block the interface of Sublime Text 2 itself, it did not leave any traces of the success or failure of the call. For example, my command line was called, Ant worked out in it, and it disappeared. There were no traces left in the console of Sublime Text 2 itself. And this was achieved only with locking the Sublime Text 2 interface. That is, they called the command, the Sublime Text 2 interface paused, and after working out this process, it spat out all its output to the Sublime Text 2 console. We could not observe the entire process “along the way”.

And with this use, when ProjectBuild should implement the functionality of the Sublime Text 2 build mechanism, the first problem was not solved - explicitly specifying options, and there was also unnecessary configuration. I had to configure ProjectBuild in order to create a list of options for the panel, although this list of options is already directly in the "* .sublime-build" file of the selected Build System. I contacted snegovikufa , he quickly introduced me to the course of how to work with GitHub, and I proceeded to change the plugin.

Offtopic about the process of modifying the ProjectBuild plugin


Github

I was very pleased with this “code accounting” system (of course, I exaggerate it), I had never worked with git before, but it took less than half an hour to deal with it, especially since there is an exhaustive guide to git for Linux, as well and for Windows users on GitHub itself. I wrote a working code, snegovikufa it was qualitatively processed for Python notation, and so on, correcting each other and writing off, we got the result, the licked working result is now in the dev branch of the Thing! My first impression, collaborative development and git (GitHub in particular) are made for each other.

Sublime Text 2 API and Python

There are official and unofficial documentation. At first it seemed that the API capabilities in Sublime Text 2 is not so great , and but they were enough. What was missing was implemented in Python. As said earlier, I do not know Python, but for the development of plug-conceived functionality are great and the x knowledge and did not need to. Yes and snegovikufa quickly corrected potentially incomprehensible moments for third parties. The only thing I wanted to find for the sake of interest, but could not, was a list of all the possible keys and Settings values ​​that Sublime Text 2 had by default, although it might have been poorly searched.

According to the "* .sublime-workspace" file format, the documentation says that this is the JSON format, but it was found out that an error may occur when json-parsing this file. The fact is that the json key in its data may be empty, but this was ignored by the ProjectBuild plugin like this:

... json.load (f, strict = False)

Even with Sublime Text 2, a variable with "$ project_path" may be involved in the "* .sublime-build" file, and I don’t understand why the developers of Sublime Text 2 did not provide for its (and others) use in the paths of keyboard shortcuts, where For example, third-party sublime programs are called. Maybe this is for security reasons, so that some plug-in for the worked out combination of keys doesn’t rest something “for itself” from the project, but still.

Plugin Summary Code

Spoiler
import sublime
import sublime_plugin
import json
import sys
import os

class ProjectBuildCommand (sublime_plugin.TextCommand) :
    def run (self, edit = None) :
        # Save file if dirty
        if self.view.is_dirty () :
            self.view.run_command ('save')

        ############################################
        #
        # Определяем файл .sublime-workspace
        # он должен быть размещен в одной из корневых директорий
        # проекта и должен быть единственным
        #
        workspace_file = None
        root_folders = self.view.window ().folders ()
        for dir_ in root_folders :
            for dir_item in os.listdir (dir_) :
                if dir_item.endswith ('.sublime-workspace') :
                    if workspace_file == None :
                        workspace_file = os.path.join (os.path.normpath(dir_), dir_item)
                    else :
                        self.showError (
                            'Must be only one ".sublime-workspace" file in project root folder.\n'
                            'Plugin found %s and %s files.' %
                            (workspace_file, os.path.join (dir_, dir_item)))
                        return
        if workspace_file == None :
            self.showError (
                'There are no ".sublime-workspace" file in any root folder of project.')
            return
        self.debug(workspace_file)
        #
        ############################################

        ############################################
        #
        # Получаем относительный путь до файла текущей Build System
        #
        with open (workspace_file) as f :
            try:
                workspace_json_data = json.load (f, strict = False)
            except Exception, e:
                self.showError (
                    'File .sublime-workspace is empty or has incorrect json data')
                return
        if not 'build_system' in workspace_json_data :
            self.showError (
                'There are no "build_system" value in %s file.\n'
                'Choose Build System and save project.' % workspace_file)
            return
        build_filename = workspace_json_data['build_system']
        self.debug(build_filename)
        #
        ############################################
        
        ############################################
        #
        # Определяем наличие файла текущей Build System
        # по полному пути до него
        # 
        build_filename_fullpath = os.path.normpath( os.path.join(os.path.dirname(sublime.packages_path()),build_filename))
        if not(os.path.isfile(build_filename_fullpath)):
            self.showError (
                'Plugin could not find Build System file: "%s".' %
                build_filename_fullpath)
            return
        self.debug(build_filename_fullpath)
        #
        ############################################

        ############################################
        #
        # Загружаем JSON данные
        #
        with open (build_filename_fullpath) as f :
            try:
                json_data = json.load (f)
            except Exception, e:
                self.showError (
                    'File %s is empty or has incorrect json data' %
                    build_filename_fullpath)
                return
        #
        ############################################

        ############################################
        #
        # Формируем словарь build-вариантов текущей Build System
        #
        build_variants = []

        if "cmd" in json_data:
            build_variants.append (['Default', " ".join (json_data["cmd"])])

        for variant in json_data.get ("variants", {}) :
            build_variants.append (
                [variant['name'], " ".join (variant['cmd'])])
        #
        ############################################
 
        ############################################
        #
        # Демонстрируем панель вариантов.
        #
        def run (selected) :
            if (selected >= 0) :
                self.execute_variant (build_variants[selected][0])

        names = [name for name, args in build_variants]
        self.view.window ().show_quick_panel (names, run)
        #
        ############################################

    def execute_variant (self, variant_name) :
        self.view.window ().run_command ("build", {"variant": variant_name})

    def showError (self, err) :
        # демонстрируем сообщение об ошибке через Sublime API 
        # иногда не срабатывало, хотя оно и должно было появляться
        sublime.error_message ('ProjectBuild:\n\n%s' % err)
        
    def debug (self, message) :
        # change True to False or vice versa
        if (False): print message

conclusions


Now ProjectBuild does not need a config. You just need to select the necessary Build System (standard system or your own, like my “AntProjectBuilder.sublime-build”). Save the project in Sublime Text 2 so that in one of its root folders lies the project manifest file "* .sublime-workspace". The ProjectBuild plugin monitors the existence of this file and its uniqueness, since information about the current Build System is taken from it. When changing the Build System in Sublime Text 2, remember to save the project so that the above file is updated. We press the keyboard shortcut assigned to ProjectBuild and see a panel with a list of build options. The list is generated automatically according to the description of the options of the Build System selected in Sublime Text 2 existing in the "* .sublime-build" file.

https://habrastorage.org/getpro/habr/post_images/d57/17b/7cd/d5717b7cd5bc02bb9b1ae0ab8d212503.png

The problems indicated at the very beginning of the article were successfully resolved: one shortcut was used and it works with the build mechanism of Sublime Text 2 itself and in its interface without tight binding and explicit naming of called build variants.

The plugin has room for improvement, for example, platform-specific options that can be specified in the Build System file are now ignored, but for me personally, it’s enough for now, and I need exactly what it implements now.

In fact, it is difficult to say whose contribution is greater, and is it important if, as a result, the ProjectBuild plugin became what it probably should have been. And it’s a sin to hide, I feel an indescribable sense of pride that there wasn’t such a thing in the interface and functionality of Sublime Text 2, but now there is one, and that it was partially written by me. (here I didn’t yet know about the “bike”, oh, woe is me, woe)
The previous version of ProjectBuild will most likely be converted into a OneHotkey plugin for grouping commands into one shortcut, not necessarily building commands, but just running third-party commands for Sublime Text 2 programs, etc. and the configuration file that ProjectBuild used to have and it turned out to be redundant for it is already useful there, since it contained redundant information for the build mechanism.

Promised bike


All the islands have long been open ... As it turned out, already in Sublime Text 2 there is already the ability to call up the options bar of the current Build System, you just need to add a key combination:

{ "keys": ["f8"], "command": "show_overlay", "args": {"overlay": "command_palette", "text": "Build: "} }

https://habrastorage.org/getpro/habr/post_images/323/c2e/2a8/323c2e2a8b882b9c2e2677b19284dd15.png

And this panel, it would not be sad to talk about it, is more convenient, since it does not attach you to the "* .sublime-workspace" file and shows the assigned keyboard shortcuts for each option, if any. However, it does not support their sorting, and the plugin can be modified to order options (although maybe again I don’t know what).

https://habrastorage.org/getpro/habr/post_images/8f7/d2a/255/8f7d2a255758a04f201d9f8a6c3e5a93.png

Probably all you can squeeze out of all this is to go back to OneHotkey.

Thanks for your attention.