jcberquist / sublimetext-cfml

CFML (ColdFusion and Lucee) package for Sublime Text
MIT License
115 stars 24 forks source link

CFML Package for Sublime Text

This package provides CFML (ColdFusion Markup Language) support in Sublime Text. It includes syntax highlighting, function and tag completions, and inline documentation. It also includes a number of other features, so please see below for the full list.

You can install this package via Package Control. The package name is CFML. Sublime Text should be restarted after installation. Manual installation is also possible. See the Installation section below for more information about these options.

Acknowledgements

The following packages were used in the development of this package:

The CFScript syntax is based on work done by Thomas Smith (@Thom1729) on the official JavaScript syntax:

Special thanks to @foundeo and cfdocs.org, from which this package gets its function and tag data. Also, thanks to @mjhagen who helped me get this package off the ground.

Table of Contents

Installation

Via Package Control

First ensure Package Control is installed. More recent versions of Sublime Text include a menu option and command palette entry for installing Package Control. You can also follow the instructions at https://packagecontrol.io/installation to install it.

Open the command palette (CTRL+SHIFT+P on Windows, CMD+SHIFT+P on a Mac) and select Package Control: Install Package.

Wait for the list to open and find the CFML entry (subtitled with this GitHub repo github.com/jcberquist/sublimetext-cfml), then select it to install.

Restart Sublime Text.

Package Control will keep the CFML package up to date automatically for you.

Manual Installation

First locate your Sublime Text packages directory. This can be easily done by opening the command palette in Sublime Text (CTRL+SHIFT+P on Windows, CMD+SHIFT+P on a Mac), and running Preferences: Browse Packages.

On Windows it will typically be something like this:

C:\Users\Username\AppData\Roaming\Sublime Text\Packages\

On a Mac it will be something like this

/Users/Username/Library/Application Support/Sublime Text/Packages/

Via Git

Open Terminal or Command Prompt and cd into your packages directory, then run:

git clone https://github.com/jcberquist/sublimetext-cfml.git ./CFML

Restart Sublime Text.

As changes are made to this repository and the package is updated, simply run the following command inside the folder where you installed the package in order to get your copy of the package up to date:

git pull origin master

Via ZIP Download

Use the Download ZIP option to download a zip of the repository to your computer. (The master branch zip file is located at https://github.com/jcberquist/sublimetext-cfml/archive/master.zip) Unzip this, and copy the contents of the resulting repository folder into a subdirectory named CFML in your Sublime Text packages directory.

Restart Sublime Text.

As changes are made to this repository and the package is updated you will need to repeat this process (replacing the old contents in the CFML subdirectory) in order to get your copy of the package up to date.

Settings

There are several settings files that you should be aware of, as they control much of the functionality of the package. There are two ways to access each file, the first being through the menus, and the second being via the command palette, which you open with CTRL+SHIFT+P on Windows (CMD+SHIFT+P on a Mac).

Package Settings

You can access package settings from the menu under Package Settings -> CFML -> Settings or via the command palette: CFML: Settings. To override any of these settings, use the user package settings file. (The default settings and user settings open side by side.)

Project Settings

Some settings are also (or only) able to be set on a per project basis. These settings control the behavior of the package for a given project. You can access and edit project files from the menu under Project -> Edit Project or via the command palette: Project: Edit Project. (These will only be accessible after you have saved a project: Project -> Save Project As or Project: Save As.)

Bindings

The keyboard and mouse binding files are available in the menu under Package Settings -> CFML -> Key Bindings and Package Settings -> CFML -> Mouse Bindings. Or via the command palette at CFML: Key Bindings and CFML: Mouse Bindings. The default and user files open side by side.

Completions

Completions are included for tags and tag attributes, as well as for built-in functions and member functions. Completions are also available for Application.cfc settings and methods.

There are three completions styles for built-in functions. This is controlled by a package setting, cfml_bif_completions, which can be set to one of three options: basic, required, or full. Setting this to basic will cause only the function name to be completed, with no function parameters inserted. required, which is the default setting, includes required parameters in the completion, but only their names, and no types. Setting this to full results in all parameters being included in the completion, as well as the parameters types.

When entering a function call parameter for a built-in function, a pop-up window with documentation from cfdocs.org for that parameter is shown. This can be disabled by setting cfml_completion_docs to false in your user package settings.

Inline Documentation

F1 is mapped to an inline documentation command that provides an inline documentation pop-up based on the cursor position. The documentation command can also be run on mouse hover. This is enabled by default, but can be disabled by setting the package setting cfml_hover_docs to false in your user package settings.

You can always override the default key binding in your user key bindings file.

If the documentation command is run when the cursor is within a built-in function or tag it will load the cfdocs.org documentation for that function or tag. Thus, having the cursor anywhere within dateFormat(myDate, "yyyy-mm-dd") and pressing F1 (by default) will trigger a pop-up displaying the documentation for dateFormat. Similarly, having the cursor anywhere within <cfinclude template="myOtherTemplate.cfm"> and pressing F1 will trigger the display of the documentation for cfinclude. Inline documentation is also available for Application.cfc settings and methods.

If you have a copy of the cfdocs.org GitHub repository on your file system, there is a package setting, "cfdocs_path", which can be set to the data directory of that repository (e.g. "cfdocs_path": "C:/github/cfdocs/data/en/"). If this is set, the cfdocs.org documentation will be loaded from the file system instead of being fetched via HTTP request. (See below for more information on package settings.)

Default Key Bindings

In tag attributes, script strings, and between cfoutput tags, pressing # when text is selected will wrap the currently selected text #selected#.

CTRL+ALT+D will output a <cfdump> tag or writeDump()/dump() function in CFML script, wrapping any currently selected text.

CTRL+SHIFT+O will output a <cfoutput> tag or writeOutput() function in CFML script, wrapping any currently selected text.

CTRL+ALT+A will output a <cfabort> tag or abort; in CFML script.

If Sublime Text's auto_close_tags setting is true, when a closing tag's / has been pressed, the closing tag will be completed. There are two package settings that control which CFML and HTML tags should not be closed: cfml_non_closing_tags and html_non_closing_tags.

If the package setting cfml_auto_insert_closing_tag is set to true (by default it is false), when > is pressed in a tag, the corresponding closing tag will be automatically inserted after the cursor position. The package setting cfml_non_closing_tags controls which CFML tags will not get a closing tag auto inserted.

The package setting cfml_between_tag_pair controls the behavior of the editor when ENTER is pressed while the cursor is between a CFML tag pair (e.g. <cfoutput>|</cfoutput>). By default only a single new line is inserted. This can be changed to have an extra new line auto inserted between the tag pair (with an optional indent), and the cursor placed there. See the default package settings file for more information.

CFC Indexing and Dot Paths

There are two settings that are set on a per project basis in a project file, cfc_folders and mappings. Here is an example (a real project file will have other settings in it as well):

{
    "mappings": [
        {"mapping": "/framework", "path": "C:/myprojects/projectname/framework"},
        {"mapping": "/model", "path": "C:/myprojects/projectname/app/model"}
    ],
    "cfc_folders": [
        {
            "path": "C:/myprojects/projectname/app/model",
            "variable_names": ["{cfc}", "{cfc}{cfc_folder_singularized}"],
            "accessors": false
        }
    ]
}

Note: the paths specified above can either be absolute paths, or relative paths. If they are relative paths, they will be resolved relative to the location of the .sublime-project file.

The specified mappings are used to resolve file paths to dot paths when right clicking on a CFC file in the sidebar and selecting Copy CFC Dotted Path. If more than one mapping matches, you will be given a choice, and if none match, it will fall back to using the base folder of the project as a dot path root. The mappings are also used to resolve dot paths specified in the extends attribute in a component, the createObject function, and when using the new operator to instantiate a component (e.g. new dot.path.to.component()). If the F1 command is used when the cursor is in any of these, you will get a pop-up with the file path for the component (plus more information about the component if it is one that has been indexed). You can click on the file path to jump to the component file. You can also CTRL+ALT+Left Click (CMD+ALT+Left Click on a Mac) on any of these to jump straight to the component file without going through the pop-up. In addition, these same commands will work in any quoted string that is used as a function call argument if it contains a dot path that can be resolved.

You can see the structure of this mouse binding in the Mouse Bindings - Default file. Use the Mouse Bindings - User file to create your own.

Important: mouse bindings are global throughout Sublime Text, so use caution to ensure you don't override a default Sublime Text mouse binding (such as CTRL+Left Click which adds a new cursor at the position clicked).

The cfc_folders array contains objects with one required key: path. Folders specified here are recursively searched for CFC files and those files are indexed. The variable_names setting is an array of strings, where each string specifies a variable name to associate each indexed CFC with. The names are determined via substitution as follows:

Key Substitution
{cfc} CFC name
{entityname} entity name of CFC if it has one, otherwise CFC name
{cfc_folder} name of folder containing the CFC
{cfc_folder_singularized} name of folder containing the CFC with trailing 's' removed

Any other text in the string will be left in place - this allows for specifying a prefix or suffix to use in the variable names. Then, if that variable name is typed in your code and followed with a ., method completions from the corresponding CFC will be offered. A variable name can contain periods in it (e.g. application.services.{cfc}). You can also use the F1 documentation command on these variable names as well as their methods calls to view documentation regarding the CFC and its methods. (Note: the F1 command also works on property names, if they match a cfc variable name, to work with DI frameworks like DI/1 that inject beans into properties of the same name.) In addition, you can use CTRL+ALT+Left Click to jump to the CFC or to the specific method in the CFC.

By default, implicit accessors are included in the completions. The accessors key, if present and set to false, will remove implicit property accessors from the completions offered (explicit accessors will always be included).

These two settings work together, such that when a base CFC as well as another CFC that extends it are both indexed, and a mapping is specified such that the dot path in the extends can be resolved, the documentation and completions for the child CFC will include properties and methods from the base CFC. In addition, the dot paths of all indexed CFCs will be offered as completions in the extends attribute, the createObject function (where the type is component), as well as when using new to instantiate a CFC.

Further, when an instantiated component has been assigned to a variable (e.g. myVar = new path.to.mycfc()), and that component has been indexed and a mapping specified for it, then method completions for that component will be offered when a . is typed after that variable name. The F1 documentation command and the CTRL+ALT+Left Click jump to CFC command will also work on that variable name. (This behavior can be disabled by setting instantiated_component_completions to false in your user package settings.)

Note: completions from indexed components are available in three styles matching the completion styles for built-in functions. This is controlled by the cfml_cfc_completions package setting. Also, when entering parameters for indexed component method calls, a pop-up window with information regarding that parameter is shown. Completion names are available in two styles, controlled by the cfc_completion_names package setting. (The two options for it are basic and full; if this setting is changed, you will need to run the CFML: Index Active Project command via the command palette for the change to take effect for indexed components.) The reason for these options is that completion names in the full style, which are of the form method():returntype, block Sublime Text from including local buffer completions in the completion list. The basic style, which only includes the method names is therefore the default. If you do want to use the full completion style a plugin such as All Autocomplete can be used as a workaround to get local buffer completions back into the completion list.

Inject Property Command

SHIFT+ALT+D is bound to command that will insert a property into a component. If it is run while the cursor is on one of the above mentioned component variable names or method calls, it will insert a property with its name set to the component variable name. Otherwise, it will present a list of all component variable names indexed in the given project, allowing one to be selected from the list and inserted. The default property templates used by the insert command can be found in the default package settings under the di_property key. These can be overridden in the user package settings, or on a per project basis by adding the same settings to a project settings file. By default, after a new property has been inserted all properties in the component will be sorted by name; this can be turned off by setting the sort_properties key in the di_property object to false.

Custom Tags

Support is offered on a per project basis for custom tags. This can be set up to function as used with a <cfimport> tag and a custom tag prefix, or with the generic <cf_customtag> format. Here is an example project file (other settings have been removed):

{
    "custom_tag_folders":
    [
        {
            "path": "C:/myprojects/projectname/customtags/page",
            "prefix": "page"
        }
    ]
}

Note: the path specified above can either be an absolute path, or a relative path. If it is a relative path, it will be resolved relative to the location of .sublime-project file.

Once this is done, page will be offered as a custom tag prefix completion, and then after entering <page: a list of tags in the custom tag folder will be offered. After a tag has been entered, completions for every attributes scope variable found in that custom tag file will be offered.

Important: Alternatively, the prefix key can be omitted - in that case the custom tags in that folder will be offered as cf_tagname completions.

You can use the F1 documentation command to get some minimal documentation about that custom tag, and CTRL+ALT+Left Click can be used to jump to the custom tag file.

The indexer will search for thistag.executionmode is/eq/== "end"/'end' (case insensitive) or <cfcase value="end"/'end'> (case insensitive) in custom tag files in order to determine whether or not to auto close the custom tag.

Code Formatting

This package includes a CFScript code formatter. You can view the default settings for this command via the menu: Package Settings -> CFML -> Format Settings, or from the command palette via CFML: Format CFScript - Settings. Please view these settings to see the various formatting options available. These settings can be overridden in your user format settings file.

There is a key binding included that runs the formatting command: SHIFT+ALT+F. By default this will format only the current method when in a component - though if any text is selected it formats that text, and in .cfm files it formats all CFScript in the file. To format an entire component the CFML: Format CFScript command palette command can be used, or you can override the default key binding with a custom one in your user key bindings - pass in the argument "current_method": false to bind this to full component formatting. (You can look in the inputmaps folder at the .sublime-keymap files to see the default key bindings - there is a commented out "args" object for this binding, so that you can simply copy the binding to your user key bindings and then uncomment the "args" object.)

PLEASE NOTE: The reason formatting is limited by default to the current method in components is that the formatting is CPU intensive and is currently run on the main thread, meaning Sublime Text will "freeze" while formatting is ongoing. On small blocks of code, this should be very quick, but on a large file it can take some time.

Custom Coloring for CFML Tags

Unless you are using a specialized color scheme, CFML and HTML tags will receive the same coloring. In the latest builds of Sublime Text a new color scheme format .sublime-color-scheme has been introduced, along with the very easy customization of your active color scheme: https://www.sublimetext.com/docs/color_schemes.html#customization. This package includes a command that will add such a customization in your Packages/User/ directory for your active color scheme that applies custom colors for CFML tags. Press CTRL+SHIFT+P to bring up the command palette (CMD+SHIFT+P on a Mac) and run CFML: Toggle Color Scheme Styles. You can edit the styles that will be injected via the user settings for this package.

Controller/View Toggle

CFML MVC frameworks typically have the convention that a controllers and a views folder are contained in the same parent directory, and that controller names and methods correspond to view folder and file names. CTRL+F1 (CMD+F1 on a Mac) is mapped to a toggle command that will jump the editor back and forth between a view file and the controller method that corresponds to it. The settings which determine which folder names are regarded as controller and view folders are contained in the package settings file. By default, controllers and handlers are treated as controller folders, and views as the views folder. Alternate folder names can be specified in the user package settings file.

CommandBox

CommandBox (https://www.ortussolutions.com/products/commandbox) has been added as the default CFML build system. This simply means that running the build command (F7 on Windows) on a CFML file will run box ${filename} as a shell command in the directory of the file and output the result in a pane within Sublime Text (it can also be selected from the build system menu available via CTRL+SHIFT+B). For this to work, CommandBox needs to be installed, and the CommandBox box binary needs to be available system wide, so that box can be run in any directory (see https://ortus.gitbooks.io/commandbox-documentation/content/setup/installation.html).

TestBox

TestBox (https://www.ortussolutions.com/products/testbox) completions and inline documentation are available for BaseSpec components. They are enabled by default, but can be disabled globally by adding "testbox_enabled": false to your CFML user package settings, or on a per project basis by adding the same setting to a project settings file. The completions and documentation are offered in any CFC that is contained under a folder named tests (alternate folders can be specified in the settings), as well as in any CFC that extends testbox.system.BaseSpec.

There are three build system variants for running TestBox tests from within Sublime Text. The first is for running all of a project's tests, which can be used no matter what project files are open, so long as the active file is a CFML one. The next variant is for running all of the tests in the directory of the currently active file, while the last variant runs the tests in the currently active test CFC only. CTRL+SHIFT+B calls up the build system menu, from which these options can be selected. Once one of the variants has been run, CTRL+B can used to run the last selected option again, without having to go through the menu.

This system is configured via a testbox object in your project settings, with one required key: runner. (Note that this mimics the structure of a box.json file used with CommandBox.) testbox.runner can either be a URL to a TestBox runner, or an array of URL objects (see https://commandbox.ortusbooks.com/content/packages/boxjson/testbox.html). If an array is used, then you will be asked to select a particular runner when executing your tests. Before calling the runner URL provided, reporter=json will be added to it, as that is the format this package expects back. Aside from that, when running the "full" project variant of the build system, the URL will be called as is.

If the variant for running the tests in a given directory is used, directory=dot.path.to.directory will be added to the URL. Additionally, if running the tests in a particular CFC, testBundles=dot.path.to.directory.cfc will be added to the URL. If directory or testBundles is already set in the query string of the URL, it will be overwritten. When running these variants, the setting testbox.tests_root is used, which specifies the root directory path that is used to determine the dot delimited path to the particular test directory. If you do not specify this, it will default to the directory location of your project file.

If these settings are not found in your project file, the root folder(s) of your project will be searched for a box.json file. If found, and if that file contains a testbox object, then its settings will be used.

Results are displayed in a results pane. There is a setting that controls the verbosity of the output: testbox.reporter, which has two options: "text" and "compacttext" ("compacttext" being the default). If there are errors or failures you can step backwards and forwards through the file stack traces via F4 and SHIFT+F4. As each file is selected, Sublime Text opens that file and jumps to the line indicated. You can also double click on any file, and Sublime Text will open it for you. Since the path to your files might look different to Sublime Text and the CFML application server (for example, if the server is running on a virtual machine), there is one more setting that maps the path as it appears to the server to the path as it appears to Sublime Text. Use testbox.results.server_root and testbox.results.sublime_root to specify the respective root paths to your project, so that Sublime Text can accurately open the files in stack traces.

All of the settings for TestBox can be seen in the default package settings.

Framework One

Framework One (https://github.com/framework-one/fw1) function completions and variables.framework setting completions are available. They are disabled by default, but can be enabled globally by adding "fw1_enabled": true to your CFML user package settings, or on a per project basis by adding the same setting to a project settings file. (Project based settings will override global settings. The default package settings for Framework One can be viewed in the CFML default package settings file.) The completions are offered in Application.cfc as well as in Framework One controller, view and layout files. (The folder names can be specified in the settings.) In controllers, Framework One method completions are offered after typing framework. and fw..