Integrating Sublime Text with GPII

Author: Christophe Strobbe.

Licence: Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License (CC BY-NC-SA 4.0).

Warning: this tutorial was written in 2016 and is now outdated.

Introduction

This document describes how you can integrate a dekstop application with GPII's real-time framework. The programming editor Sublime Text (version 3 for Windows) is used as an example. For a general introduction to GPII and the integration process, see GPII/Cloud4all for Developers and the GPII wiki pages referenced in that document. For an similar but older document, see Building A Simple Solution on the GPII wiki.

Installing GPII on Windows

The process described below is based on a 64-bit version of Microsoft Windows 7 but should also work on a 32-bit version of Windows 7 and on more recent versions of Windows.

Installing Dependencies for Windows

You need the following dependencies for installing GPII on Windows:

If you run into problems installing any of these dependencies, check the Windows installation instructions on the GPIi wiki.

Installing the GPII Real-Time Framework

Open a command line window, go to the directory where you want to intall GPII and type the following commands:

Integrating Sublime Text 3

Identifying Sublime Text 3's Executable and Settings File

First, download and install Sublime Text (version 3). Then, note the two following things:

  1. Where the user settings are stored. GPII needs to know this location, so it can adapt the settings.
    The path to Sublime Text's settings file typically has the following pattern: C:\Users\<user>\AppData\Roaming\Sublime Text 3\Packages\User\Preferences.sublime-settings (where <user> represents the current user account).
    It is possible that this file does not exist immediately after installation. In order to create the file, you can start Sublime Text and change one of its settings, such as the colour scheme or the font size (in the Preferences menu), or the settings related to spelling in the View menu. Alternatively, you can go to Preferences > Settings – User and edit the settings file directly. After this, you should find a settings file at the location mentioned above.
  2. How the location of the Sublime Text executable is represented in the Windows registry. GPII needs to know this location, so it can start and stop the application.
    You can find this path by searching for the name of the executable, sublime_text.exe, in the Windows registry (using regedit). The Windows registry entry for Sublime Text can be found at HKEY_CLASSES_ROOT\Applications\sublime_text.exe.

Integration Steps for Sublime Text 3

Identifying Sublime Text's Settings

The next step is the identification and description of Sublime Text's settings. Sublime Text has a hundred different settings; they can be found in the JSON-like file at C:\Users\<user>\AppData\Roaming\Sublime Text 3\Packages\Default\\Preferences.sublime-settings. (The file is not pure JSON because JSON syntax does not allow JavaScript comments.) Since GPII/Cloud4all currently does not have a database for registering applications with all their settings, we will focus on those Sublime Text settings that are relevant to accessibility or that we want to show in demonstrations (or both). For each of these settings, we provide the following types of information: its internal name, its data type, its value range, its default value (if applicable), and any dependencies on other settings (for example, the dictionary setting is only relevant when the spell_check setting has the value true).

In addition, we also create a solution ID for Sublime Text, i.e. a string that will uniquely identify the application in GPII. Based on the URL of the website where Sublime Text can be downloaded, we give the application the following ID: com.sublimetext. The following table summarizes the data involved in this step. (Setting are listed in alphabetical order. The column “common term” will be explained below.)

Setting Data type Value range Default value Description Constraints Common term
caret_extra_bottom Integer 0 … 0 size of the caret: bottom - -
caret_extra_top Integer 0 … 0 size of the caret: top - -
caret_extra_width Integer 0 … 0 size of the caret: width - -
caret_style String "smooth", "phase", "blink" and "solid" smooth Valid values are "smooth", "phase", "blink" and "solid". - -
color_scheme String “Packages/Color Scheme - Default/Monokai.tmTheme”, “Packages/Color Scheme - Default/Amy.tmTheme”, etc. “Packages/Color Scheme - Default/Monokai.tmTheme” Sets the colours used within the text area; covers code colouring. - (closest match: highContrastEnabled & highContrastTheme)
dictionary String (path to a dictionary file on the file system) "Packages/Language - English/en_US.dic" Word list to use for spell checking. Only relevant when the setting spell_check has the value true. -
fade_fold_buttons Boolean true | false true Hides the fold buttons unless the mouse pointer hovers over the gutter. - -
font_face String (depends on the fonts installed in the OS) (empty string) Font face used in the editing area (not the menus). - -
font_size Integer (pixels) (?) 10 Font size used in the editing area (not the menus). - fontSize (points)
gutter Boolean true | false true Show or hide the gutter. - -
highlight_line Boolean true | false false If enabled, will highlight any line with a caret. - -
highlight_modified_tabs Boolean true | false false Highlight tabs containing unsaved modifications. - -
line_numbers Boolean true | false true Display line numbers in the gutter. Not relevant if gutter is set to false. -
margin Integer (?) 4 Spacing between the gutter and the editing area. - -
show_encoding Boolean true | false false Display file encoding (for the activ tab) in the status bar. - -
show_line_endings Boolean true | false false Display the type of line endings in the status bar: Windows, Unix, … - -
spell_check Boolean true | false false Set to true to turn spell checking on by default. (See dictionary, above.) -
translate_tabs_to_spaces Boolean true | false false Set to true to insert spaces when the tab key is pressed. - -

Each of the application's settings can be uniquely identified using the following pattern: http://registry.gpii.net/applications/ + solution ID + setting name. For example, the Sublime Text setting caret_extra_bottom is uniquely identified in GPII by the following URI: http://registry.gpii.net/applications/com.sublimetext/caret_extra_bottom. The category of settings represented by means of this type of URI is known as application-specific terms.

The last column in the settings table represents the common terms. The Cloud4all project created a set of common terms that represent an application-neutral way of representing settings. Common terms serve as a lingua franca for representing settings without relying on application-specific terms. The have a data type and value space that can be easily translated to application-specific terms. For example, the common term speechRate (data type: integer) represents the speed of a text-to-speech engine's output in words per minute. This type of value can be translated or “transformed” (see below) to the application-specific setting for speech rate in various screen readers.

The Cloud4all project created a small set of 50 common terms, and most of Sublime Text's settings have no corresponding common term. Sublime Text's font_size setting (an integer representing size in pixels) can easily be represented by the common term fontSize, which represents a size in points. However, the common terms highContrastEnabled (Boolean) and highContrastTheme (with the possible values black-white, white-black, yellow-black, black-yellow, lime-black) were conceived for users who need high-contrast settings, while Sublime Text's colour schemes are much more complex and were not conceived to represent high-contrast settings. In fact, many of Sublime Text's colour schemes are low-contrast schemes.
In summary, Sublime Text's settings, with the exception of font_size, can currently only be represented using application-specific terms.

Creating a Solutions Registry Entry and Related Files

The integration of a solution requires modifications to a few existing files and the creation of few new files:

Note: Before modifying or creating these files, you should first create a new branch in your fork of GPII's “universal” repository. This branch will contain all the changes and additions that are required to integrate the application with GPII, including the integration tests, which are explained below. Ideally, the name of the branch matches the name of the JIRA ticket (in GPII's issue tracking system) for the solution integration.
For Sublime Text, the ticket for the Windows integration is GPII-1796, so the corresponding branch is also called GPII-1796.

The entry for Sublime Text in the Windows solutions registry win32.json looks as follows:

"com.sublimetext": {
    "name": "Sublime Text",
    "contexts": {
        "OS": [
            {
                "id": "win32",
                "version": ">=5.0"
            }
        ]
    },
    "settingsHandlers": {
        "configuration": {
            "type": "gpii.settingsHandlers.JSONSettingsHandler",
            "options": {
                "filename": "${{environment}.APPDATA}\\Sublime Text 3\\Packages\\User\\Preferences.sublime-settings"
            },
            "capabilities": [
                "applications.com\\.sublimetext\\.id",
                "caret_extra_bottom",
                "caret_extra_top",
                "caret_extra_width",
                "caret_style",
                "color_scheme",
                "dictionary",
                "fade_fold_buttons",
                "font_face",
                "font_size",
                "gutter",
                "highlight_line",
                "highlight_modified_tabs",
                "line_numbers",
                "margin",
                "show_encoding",
                "show_line_endings",
                "spell_check",
                "translate_tabs_to_spaces"
            ],
            "capabilitiesTransformations": {
                "font_size": {
                    "transform": {
                        "type": "fluid.transforms.round",
                        "input": {
                            "transform": {
                                "type": "fluid.transforms.linearScale",
                                "inputPath": "http://registry\\.gpii\\.net/common/fontSize",
                                "factor": 1.33
                            }
                        }
                    }
                }
            }
        }
    },
    "configure": [
        "settings.configuration"
    ],
    "restore": [
        "settings.configuration"
    ],
    "start": [
        {
            "type": "gpii.launch.exec",
            "command": "\"${{registry}.HKEY_CLASSES_ROOT\\Applications\\sublime_text.exe\\}\""
        }
    ],
    "stop": [
    ],
    "isInstalled": [
        {
            "type": "gpii.deviceReporter.alwaysInstalled"
        }
    ]
}

The solution entry starts with Sublime Text's solution ID (see above) and contains the following sections:

Next, you need to add an entry for the solution to the file testData/deviceReporter/installedSolutions.json. For Sublime Text, the following addition was made:

{
  "id": "com.sublimetext"
}

You should also create a few needs & preferences sets that you can use to demonstrate the adaptations that GPII can make to the solution's settings. These needs and preferences sets (short: NP sets) are also in JSON. NP sets can use common terms, application-specific terms or a combination of these. For example, the NP set sublime_carla uses the common term fontSize and several application-specific terms for Sublime Text:

{
    "flat": {
        "contexts": {
            "gpii-default": {
                "name": "Default preferences",
                "preferences": {
                    "http://registry.gpii.net/common/fontSize": 24,
                    "http://registry.gpii.net/applications/com.sublimetext": {
                      "caret_extra_bottom": 1,
                      "caret_extra_top": 1,
                      "caret_extra_width": 4,
                      "color_scheme": "Packages/Color Scheme - Default/Blackboard.tmTheme",
                      "dictionary": "Packages/Language - English/en_GB.dic",
                      "highlight_line": true,
                      "highlight_modified_tabs": true,
                      "spell_check": true
                    }
                }
            }
        }
    }
}

A solution's NP sets should always be accompanied by a Markdown file that identifies the solution they were created for and that explains the intended effect of the NP sets. The file names for both the NP sets and the Markdown file should have a prefix that is unique to the solution, e.g. sublime_ for Sublime Text. (This is not required by the system; it is only meant to make it easier to figure out which NP sets belong to which solution.) These files are all stored in the directory universal/testData/preferences/.

Finally, you should also create a Markdown file that describes the solution, the settings that have been integrated, the NP sets used for the acceptance tests (see below) and any other information that the GPII developer team would need to know when reviewing your contribution.

At this point, you should already be able to test whether the integration works. Open a command line, navigate to the windows directory in your GPII installation and start GPII by typing node gpii.js. Open Sublime Text. Then enter a URL like the following into a browser: http://localhost:8081/user/sublime_carla/logonChange. (sublime_carla is an NP set that we created for this kind of test.) Sublime Text should now adapt to the settings defined in the NP set sublime_carla. (If you opened the settings file Preferences.sublime-settings before this test, you will be able to see the resulting settings there.) Then activate the same link again to “log out” sublime_carla; GPII should now restore the original settings.

Writing Integration Tests

The instruction in this section are based on the wiki page Writing Acceptance Tests, more specifically the section Writing Acceptance Tests for Applications Using the Local Flow Manager.

The integration tests are part of GPII's automatic acceptance testing framework. The acceptance tests for a specific solution test the entire real-time framework end to end. Simply put, the tests start up the GPII server, log in a user, and checks that the system is modified according to that user's needs & preferences set. It then logs that user out again, restores the system to its original settings and checks that the system has been restored to its original state. This type of tests also includes testing of the transformations (see above).

First, you need to create a few needs & preferences sets (NP sets) that you want to test your application with. These should be stored in the directory universal/testData/preferences/acceptanceTests/. You can reuse the NP sets that you have already created for demonstrating the solution.

You should also create a device reporter file, which is to be stored in the directory universal/testData/deviceReporter/acceptanceTests/. The device reporter file name should be descriptive of its content, e.g. sublimetext.json, and its content looks like the following example:

[
  {
    "id": "com.sublimetext"
  }
]

The next step is to create the configuration file that the testing framework should use when running the integration tests for the application. The purpose of this file is to point the testing framework to the device reporter file created in the previous step.

Since our example is the Windows version of Sublime text, the configuration file should be stored in the directory universal/tests/platform/windows/configs/. The file name uses the pattern gpii.tests.acceptance.windows.<application>.config.json, where <application> stands for the application being integrated. For Sublime Text, the config file should be called gpii.tests.acceptance.windows.sublimetext.config.json. Its content looks as follows:

{
    "type": "gpii.tests.acceptance.windows.sublimetext.config",
    "options": {
        "distributeOptions": {
            "acceptance.installedSolutionsPath": {
                "record": "%universal/testData/deviceReporter/acceptanceTests/sublimetext.json",
                "target": "{that deviceReporter installedSolutionsDataSource}.options.path",
                "priority": "after:development.installedSolutionsPath"
            }
        }
    },       
    "mergeConfigs": "%universal/tests/configs/gpii.tests.acceptance.localInstall.config.json"
}

The important part of this file is the line starting with record, which points to the device reporter file. In addition, value of type in the second line reflects the configuration file name without its file name extension.

The final step is to create the file with the actual acceptance test(s). Acceptance tests for Windows solutions are stored in the directory universal/tests/platform/windows/. Each of the transformations in the solution's registry entry should have at least one unit test; it is good practice to cover some edge cases for the common terms that can be mapped to your solution's application-specific terms. The acceptance tests for Sublime Text on Windows are shown below by way of example:

"use strict";
var fluid = require("universal"),
    gpii = fluid.registerNamespace("gpii");

gpii.loadTestingSupport();

fluid.registerNamespace("gpii.tests.windows");

gpii.tests.windows.sublimetext = [
    {
        name: "Acceptance test for small font size in Sublime Text",
        userToken: "sublime_font8",
        settingsHandlers: {
            "gpii.settingsHandlers.JSONSettingsHandler": {
                "data": [
                    {
                        "settings": {
                            "font_size": 11
                        },
                        "options": {
                            "filename": "${{environment}.APPDATA}\\Sublime Text 3\\Packages\\User\\Preferences.sublime-settings"
                        }
                    }
                ]
            }
        },
        processes: []
    },
    {
        name: "Acceptance test for large font size in Sublime Text",
        userToken: "sublime_gert",
        settingsHandlers: {
            "gpii.settingsHandlers.JSONSettingsHandler": {
                "data": [
                    {
                        "settings": {
                            "font_size": 32
                        },
                        "options": {
                            "filename": "${{environment}.APPDATA}\\Sublime Text 3\\Packages\\User\\Preferences.sublime-settings"
                        }
                    }
                ]
            }
        },
        processes: []
    }
];

module.exports = gpii.test.bootstrap({
    testDefs:  "gpii.tests.windows.sublimetext",
    configName: "gpii.tests.acceptance.windows.sublimetext.config",
    configPath: "%universal/tests/platform/windows/configs"
}, ["gpii.test.integration.testCaseHolder.windows"],
    module, require, __dirname);

Below are a few comments to help you understand the above code.

In addition to the acceptance test file itself, you should also create a plain text file that describes the resources required for the tests (NP sets, etcetera).

Testing the Integration

(todo)

When the integration tests are complete, you should check that all the code in the pull request meets the criteria in the Pull Request Review Checklist.

Integration on GNU/Linux

Sublime Text has a version for GNU/Linux, but this version is not available through a package repository. Sublime Text can be installed in a non-standard way (for example, using the instructions in the article Installing Sublime Text 3 on RHEL Fedora), but will not be known to PackageKit. As a consequence, GPII, which currently relies on PackageKit to find installed applications, will not be able to find it. For this reason, the GPII integration of Sublime Text on GNU/Linux is not part of this tutorial.