Javascript autocompletions and having one for Sublime Text 2

Autocompletion is major software development productivity booster in modern programming text editors. This article discuss about Javascript autocompletion and how to make Sublime Text 2 editor to support them. If you are not familiar with Sublime Text 2 please see my earlier post what Sublime Text 2 is all about and how to tune it to be a superior programmer’s tool. Please note that information here applies to Sublime Text 2, Sublime Text 3 is underway (most ST2 plugins are open source and can be easily upgraded for ST3 compatibility).

Update: 3 days after this blog post I cam across Tern.js which is a kickstarted project to build sensible editor agnostic Javascript autocompletion engine.

1. Why autocompletion for Javascript is so hard

Javascript does not have Java-like static typing system, meaning that it’s not possible to know what’s the type variables of like this, $, jQuery, etc. until the code is actually executed in the web browser. In statically typed systems like Java you declare the type of the variables when you introduce them, like int i or MyClass foo. In Javascript you have only var or let. This makes Javascript lighter to write, but it also effectively means that during writing the code the information about the variable contents is not really available. Thus, your text editor cannot know how to autocomplete your typing because it cannot know what autocompletions there are available.

What makes things even more worse and sets Javascript apart from Ruby and Python is the lack of native support of classes and modules. Prototypial inheritance gives great freedoms – leading to the sad state of the things that each Javascript framework has invented their own way to declare classes, modules and namespaces. There isn’t one right way, but many incompatible ways. Thus, there is no single solution to extract the classy type information, even run-time.

2. Introducing type information into Javascript

There exist several ways to annotate Javascript source code or overlay type information over it. By using these type hints your text editor can know that $ is actually jQuery and can guess what kind of functions it could provide.

First of all, most text editors have their own type information format and files which are generated from the source code or entered as manually maintained files. Examples include Sublime Text 2 .sublime-completions files and Aptana Studio Javascript autocompletions. To make the editor support autocompletion one needs to integrate a source code scanner plug-in which extracts the type information and turns it to the native symbol database format supported by the editor.

Please note that autocompletion is not the only reason to have static typing support or type hinting. When project size and number of developers grow, static typing becomes more and more preferable as it decreases the cognitive load needed to work with the codebase, reducing human errors.

3. JsDoc directive scanning

JsDoc is a loosely followed convention to annotate Javascript with source code comments to contain references about packages, namespaces, singlentons, etc. Basically you write something like @class foo.bar.Baz in /** */ comment blocks and it is picked up. JsDoc was originally created to generate Javadoc like API documentation for Javascript projects. If you have any self respect you document your source code with comments.  Do this by following the JsDoc best practices and you’ll be lucky and the same type information can be utilized for generating autocompletions too.

JsDoc class and namespace hints are especially needed when you are using something like RequireJS for defining your modules. This is because naive source code scanners have very hard time to determine module exports and classes from this kind of source code and as far as I know, no IDE supports RequreJS natively yet.

Note that personally I prefer superior JsDuck over JsDoc for actual HTML documentation generation.

4. TypeScript definitions and language

With some bad rap due to its owner, Microsoft, TypeScript is an open source project to provide type information for Javascript. TypeScript comes with two “modes” of operating.

The less invasive approach is to  provide type information in externally typed interface files (example .ts for jQuery).

Move invasive, but easier to maintain approach is to write your source code in TypeScript language itself which compiles down to Javascript and .ts type information files. TypeScript language is a Javascript superset, so all Javascript is valid TypeScript. TypeScript adds optional support for classes, modules and static typing of variables. The TypeScript compiler will detect if you are trying to mix wrong types or using missing functions and gives a compiler error at the compile phase, when generating JS from TS.

Sublime Text 2 has a plugin to support TypeScript based autocompletions.

5. SublimeCodeIntel plug-in and OpenKomodo CodeIntel

OpenKomodo is a software repository for the open source parts of ActiveState’s Komodo Edit editor. It has a subsystem called CodeIntel for autocompletion and source code symbol scanning.

What makes CodeIntel interesting from the perspective of Sublime Text 2 is that CodeIntel is 1) open source 2) written in Python, making it easy to integrate with the Python based plug-in system of Sublime Text 2. Thus, there exist SublimeCodeIntel plug-in.

CodeIntel has a Javascript scanner. Based on its source code, it should provide JsDoc @class decorator support. However, I have never managed to get it working and there is an open stackoverflow.com question how to make SublimeCodeIntel to work with JsDoc directives. All help welcome.

6. Sublime Text 2 and CTags

Exuberant CTags is a generic “tag” type information extractor backend for various programming languages. As the name implies, it was originally created to autocomplete C source code. Sublime Text 2 has support for CTags with a plug-in which is called CTags.

I have not used this plug-in myself, so I hope someone can comment how well it works with Javascript autocompletion.

7. Manually generating autocompletions for your favorite Javascript project

Though not so advanced approach, this gave me a wow effect and motivation to write this blog post (instead of sitting under a palm tree sipping caipirinhas). I came across this little Python script in Three.js, a 3D engine for WebGL and Javascript.

Three.js has invented yet another Javascript class system of their own. But instead of using JsDoc @class, @module or @package like annotations they have a custom Python script which scans the Javascript codebase using regular expressions. Regexes match Three.js custom class declarations and then the script generates Sublime Text 2 autocompletion file based on the results. Crude, but apparently seems to work.

I recommend check the source code and see how you could apply this for your own little project if you are a major Sublime Text 2 user. The approach is not limited to Javascript, but should work for any dynamically typed language where you have control over how you define your namespaces.

Buy open source friendly bitcoins  Subscribe to this blog in a reader Follow me on Twitter Follow me on Facebook Follow me Google+

5 thoughts on “Javascript autocompletions and having one for Sublime Text 2

  1. Hi, from the last screen it feels like you made turn working in Sublime. Can you please share instructions how to achieve this? :)

  2. Hi Sergey:

    SublimeCodeIntel can autocomplete “simple” Javascript window level globals. However it does not know about the current Javascript module best pratices (RequireJS / AMD) or it cannot use JsDoc hints to figure out the class of function argurments. So it is not very useful for heavy weight Javascript projects.

  3. Thanks for the article :)

    I have tried the sublime code intel solution but was still having trouble:
    When I “control+click” the classname it will jump to the definition of the class ~
    But when I “control+click” the “callFunc” (see below):
    this.obj = new MyClass();
    this.obj.callFunc();

    it gives me warning:
    + Warning: evaluating ‘this.obj.callFunc’ at …: could not resolve first part of ‘this.obj.callFunc’

    any idea ? Thanks :)

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>