{"__v":97,"_id":"552e73705d4baa0d00783699","category":{"__v":9,"_id":"54d5635632d98b0d00384b01","pages":["54d5635732d98b0d00384b10","54d5635732d98b0d00384b11","55104b632dd9010d0019e144","55104c802dd9010d0019e146","551bd2c50d209f21006cad92","552e6fcd5d4baa0d00783691","552e73705d4baa0d00783699","567be431ee052b1700dbda49","567ef29af9ffa20d008782ff","56a8dd2470a9440d00ef5fe4"],"project":"54d53c7b23010a0d001aca0c","version":"54d5635532d98b0d00384afb","sync":{"url":"","isSync":false},"reference":false,"createdAt":"2015-02-07T00:03:52.618Z","from_sync":false,"order":11,"slug":"language-tooling","title":"Language Tooling"},"parentDoc":null,"project":"54d53c7b23010a0d001aca0c","user":"54d5c32a7e05890d006f150d","version":{"__v":10,"_id":"54d5635532d98b0d00384afb","forked_from":"54d53c7c23010a0d001aca0f","project":"54d53c7b23010a0d001aca0c","createdAt":"2015-02-07T00:59:01.934Z","releaseDate":"2015-02-07T00:59:01.934Z","categories":["54d5635632d98b0d00384afc","54d5635632d98b0d00384afd","54d5635632d98b0d00384afe","54d5635632d98b0d00384aff","54d5635632d98b0d00384b00","54d5635632d98b0d00384b01","54d5635632d98b0d00384b02","54d652097e05890d006f153e","54dd1315ca1e5219007e9daa","54e21e2b22de1c230094b147","54e68e62a43fe13500db3879","54fa1d3fe7a0ba2f00306309","551c453a23a1ee190034d19a","551df586e52a0b23000c62b6","551f39be6886f8230055f02a","55a6720751457325000e4d97"],"is_deprecated":false,"is_hidden":false,"is_beta":true,"is_stable":true,"codename":"","version_clean":"0.1.0","version":"0.1"},"updates":["57447334e42a590e00e270e4"],"next":{"pages":[],"description":""},"createdAt":"2015-04-15T14:19:28.757Z","link_external":false,"link_url":"","githubsync":"","sync_unique":"","hidden":false,"api":{"results":{"codes":[]},"settings":"","auth":"required","params":[],"url":""},"isReference":false,"order":1,"body":"All language tooling in Cloud9 is implemented using language handlers. Language handlers are plugin components that run in a web worker. Plugin developers can write language handlers directly or they can use [outline definitions](doc:outline) in the Cloud9 Bundle or [the Jsonalyzer framework](doc:jsonalyzer-handlers) as an abstraction for building certain kinds of language plugins.\n\n# Overview\n\n- [Language Plugins](#section-language-plugins)\n- [Language Handlers](#section-language-handlers)\n  - [Declaring What a Handler is Used For](#section-declaring-what-a-handler-is-used-for)\n  - [Implementing Static Analysis](#section-implementing-static-analysis)\n  - [Implementing a Parser](#section-implementing-a-parser)\n  - [Implementing Code Completion](#section-implementing-code-completion)\n  - [Implementing an Outline View](#section-implementing-an-outline-view)\n  - [Implementing Tooltips](#section-implementing-tooltips)\n  - [Implementing Highlight Occurrences](#section-implementing-highlight-occurrences)\n  - [Implementing Code Formatting](#section-implementing-code-formatting)\n  - [Implementing Quick Fixes and Quick Suggestions](#section-implementing-quick-fixes-and-quick-suggestions)\n  - [Implementing Rename Refactoring](#section-implementing-rename-refactoring)\n  - [Listening to General Events](#section-listening-to-general-events)\n- [Talking to the Outside World](#section-talking-to-the-outside-world)\n- [Reference Implementations](#reference-implementations)\n\n# Language Plugins\n\nCloud9 language plugin packages generally have a structure like this:\n\n```\n└─ mylang.language\n    ├─ worker\n    |    └─ mylang_handler.js\n    ├─ mylang.js\n    ├─ package.json\n    └─ README.md\n    └─ LICENSE\n```\n\nBelow is the contents `mylang.js`, which is the main file of this package. The `mylang.js` plugin is a regular Cloud9 plugin, and whose job it its to load the language handler called `mylang_handler`:\n\n```javascript      \ndefine(function(require, exports, module) {\n    main.consumes = [\"Plugin\", \"language\"];\n    main.provides = [\"mylang\"];\n    return main;\n          \n    function main(options, imports, register) {\n        var Plugin = imports.Plugin;\n        var plugin = new Plugin(\"mylang.org\", main.consumes);\n        var language = imports.language;\n\n        function load() {\n            language.registerLanguageHandler(\n                \"plugins/mylang.language/worker/mylang_handler\",\n                function(err, handler) {\n                    if (err) return err;\n                    // send/receive events using handler.emit/on\n                },\n                plugin\n            );\n        }\n        plugin.on(\"load\", load);\n        plugin.on(\"unload\", function() {\n            // do when plugin is unloaded\n        });\n        register(null, { mylang: plugin });\n    }\n});\n```\n\nEssentially all this plugin does is call [language.registerLanguageHandler()](https://docs.c9.io/api/#!/api/language-method-registerLanguageHandler) to load a handler `plugins/mylang.language/worker/mylang_handler.js`. That file is where the real magic happens. We'll dive further into language handlers next.\n\n# Language Handlers\n\nLanguage handlers implement the [base_handler](https://docs.c9.io/api/#!/api/language.base_handler) abstract class. The interface is best illustrated with an example. Below is a language handler that subclasses `base_handler`:\n\n```javascript\ndefine(function(require, exports, module) {\n    var baseHandler = require(\"plugins/c9.ide.language/base_handler\");\n    var handler = module.exports = Object.create(baseHandler);\n          \n    handler.handlesLanguage = function(language) {\n        return language === \"javascript\" || language === \"jsx\";\n    };\n          \n    handler.analyze = function(value, ast, callback) {\n        if (!ast)\n            return;\n        callback(null, [{\n            pos: { sl: 0, el: 0, sc: 0, ec: 0 },\n            type: \"info\",\n            message: \"Hey there! I'm an info marker\"\n        }]);\n    };\n});\n```\n\nThe `base_handler` abstract has one method that always must be implemented: [base_handler.handlesLanguage()](https://docs.c9.io/api/#!/api/language-method-handlesLanguage). In the language handler above, the handler uses it to tell Cloud9 that it should be used for JavaScript and JSX files. The handler also implements the optional [base_handler.analyze()](https://docs.c9.io/api/#!/api/language-method-handlesLanguage) method, adding a new info marker at the top of all JavaScript/JSX files:\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/014QDkgDSsOIJAicIWXQ_image.png\",\n        \"image.png\",\n        \"1570\",\n        \"451\",\n        \"#1b5bbd\",\n        \"\"\n      ]\n    }\n  ]\n}\n[/block]\nThe example above provides a starting point for implementing language handlers. Cloud9 supports and recommends the use of multiple handlers and handler functions per language. The `base_handler` interface provides methods for doing code completion, showing an outline view, tooltips, etc. that are best organized into separate handlers.\n[block:callout]\n{\n  \"type\": \"success\",\n  \"body\": \"Each language can have many language handlers that implement some subset of the supported handler methods. For example, for Python, you may have a `python_linter.js`, a `python_completer.js` and a `python_outline.js`, each offering some kind of language support. They all must at least have an implementation of `base_handler.handlesLanguage()`. \\n\\nCloud9 also allows multiple handlers to implement the same `base_handler` method for a language. For example, there may be one implementation of  [base_handler.analyze()](https://docs.c9.io/api/#!/api/language-method-handlesLanguage) that uses ESLint for error markers in JavaScript, and another implementation that adds a silly \\\"Hello there! I'm an info marker\\\" marker at the top of each JavaScript file.\",\n  \"title\": \"Divide language tooling into as many handlers modules as you like\"\n}\n[/block]\nBelow is an overview of all abstract methods of `base_handler` and their applications. We use [RFC 2119](http://tools.ietf.org/html/rfc2119) keywords **must**, **should**, and **may** to indicate which methods are required, recommended, and optional. For a full reference of all methods see [the API Reference](https://apidoc.c9.io/c9v3/#!/api/language.base_handler). \n[block:callout]\n{\n  \"type\": \"info\",\n  \"body\": \"In addition to the API reference and this guide, you can have a look at [the base_handler.js source code](https://github.com/c9/c9.ide.language/blob/master/base_handler.js) on github to browse through the language handler base class.\",\n  \"title\": \"Base handler source code\"\n}\n[/block]\n# Declaring What a Handler is Used For\n\nAll language handlers **must** implement [base_handler.handlesLanguage()](https://apidoc.c9.io/c9v3/#!/api/language.base_handler-method-handlesLanguage):\n\n```javascript\nhandler.handlesLanguage = function(language) {\n    return language === \"javascript\" || language === \"jsx\";\n};\n```\n\nLanguage handlers **should** specify a regular expression that matches identifier characters in that language using [base_handler.getIdentifierRegex()](https://apidoc.c9.io/c9v3/#!/api/language.base_handler-method-getIdentifierRegex):\n\n```javascript\nhandler.getIdentifierRegex = function() {\n    return /[A-Za-z0-9$_]/;\n};\n```\n\nLanguage handlers **may** specify if they are to be used for normal editors and/or the immediate view using [base_handler.handlesEditor()](https://apidoc.c9.io/c9v3/#!/api/language.base_handler-method-handlesLanguage). `HANDLES_EDITOR` indicates the handler can only be used in a normal editor; `HANDLES_IMMEDIATE` indicates it can be used only in an immediate view, and  `HANDLES_EDITOR_AND_IMMEDIATE` indicates both.\n\n```javascript\nhandler.handlesEditor = function() {\n    return this.HANDLES_EDITOR;\n};\n```\n\nLanguage handlers **may** specify the maximum file size they support:\n\n```javascript\nhandler.getMaxFileSizeSupported = function() {\n    return 10 * 1000 * 80;\n};\n```\n\n# Implementing Static Analysis\n[block:callout]\n{\n  \"type\": \"success\",\n  \"body\": \"Writing a full static analyzer or code completer from scratch is not easy and is only something only few people ever do. It's also a lot of work. Luckily, for many languages there are open-source language tools available that can be reused. See also [Using Existing Language Tools](doc:existing-tools) for examples of using existing language tools.\",\n  \"title\": \"Use existing language tools when possible\"\n}\n[/block]\nLanguage handlers that perform static analysis **must** implement [base_handler.analyze()](https://apidoc.c9.io/c9v3/#!/api/language.base_handler-method-analyze).\n\n```javascript\nhandler.analyze = function(value, ast, options, callback) {\n    callback(null, [\n        {\n            pos: { sl: 1, el: 1, sc: 4, ec: 5 },\n            type: \"warning\",\n            message: \"Assigning to undeclared variable.\"\n        }\n    ]\n};\n```\n\n# Implementing a Parser\n\nLanguage handlers that use a parser **should** implement [base_handler.parse()](https://apidoc.c9.io/c9v3/#!/api/language.base_handler-method-parse):\n\n```javascript\nhandler.parse = function(docValue, options, callback) {\n    var ast = ...;\n    callback(null, ast);\n};\n```\n\nCloud9 does not directly use the abstract syntax tree result from a parser, but will pass it to other language handler methods when they are called. Language handlers with a parser  *should* also implement [base_handler.analyze()](https://apidoc.c9.io/c9v3/#!/api/language.base_handler-method-analyze) to display syntax errors. Languages can have multiple handlers implementing `analyze()`, e.g. one that returns semantic errors and one that returns syntax errors.\n\nLanguage handlers that use parsing **should** implement [base_handler.findNode()](https://apidoc.c9.io/c9v3/#!/api/language.base_handler-method-findNode) and **should** implement [base_handler.getPos()](https://apidoc.c9.io/c9v3/#!/api/language.base_handler-method-getPos):\n\n```javascript\nhandler.findNode = function(ast, pos, callback) {\n    var node = ...traverse the ast, searching for pos.row and pos.column...;\n    callback(null, node);\n};\nhandler.getPos = function(node, callback) {\n    var pos = ...;\n    callback(null, { sl: pos.sl, el: pos.el, sc: pos.sc, ec: pos.ec });\n};\n```\n\nThe `findNode()` method is used to pass the current AST node under the cursor to other language handlers. Other handler methods, such as [base_handler.complete()](https://apidoc.c9.io/c9v3/#!/api/language.base_handler-method-complete) can use `options.node` to get the current AST node when `parse()` and `findNode()` are implemented.\n[block:callout]\n{\n  \"type\": \"info\",\n  \"title\": \"Parsing methods are optional\",\n  \"body\": \"Both `parse()` and `findNode()` are optional and are only intended for those languages with a parser that runs in the browser. For many languages these methods do not need to be implemented.\"\n}\n[/block]\n# Implementing Code Completion\n\nLanguage handlers that provide code completion **must** implement [base_handler.complete()](https://apidoc.c9.io/c9v3/#!/api/language.base_handler-method-complete):\n\n```javascript\nhandler.complete = function(doc, ast, pos, options, callback) {\n    var line = doc.getLine(pos.row);\n    var identifier = options.identifierPrefix;\n    ...\n    callback(null, [\n        {\n            name: \"foo()\",\n            replaceText: \"foo(^^)\",\n            icon: \"method\",\n            meta: \"FooClass\",\n            doc: \"The foo() method\",\n            docHead: \"FooClass.foo\",\n            priority: 1\n        }\n    ]);\n};\n```\n\nLanguage handlers that provide code completion **should** implement [base_handler.getCompletionRegex()](https://apidoc.c9.io/c9v3/#!/api/language.base_handler-method-getCompletionRegex).\n\n```javascript\nhandler.getCompletionRegex = function() {\n    return /^\\.$/;\n}\n````\n\nIf a completion regex is specified, continuous completion is enabled for that language. This means that whenever a user types a character, completion is attempted with a short delay. If a character sequence matching the completion regex is typed, completion is performed immediately.\n[block:callout]\n{\n  \"type\": \"success\",\n  \"body\": \"See [Using Existing Language Tools](doc:existing-tools) for concrete code completion examples, and [Customizing Code Completers](doc:customizing-code-completers) for advanced ways of customizing a code completer.\",\n  \"title\": \"Further reading on code completion\"\n}\n[/block]\n## Implementing an Outline View\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/FVg1UFDuQhmhdN6A7QB0_outline.png\",\n        \"outline.png\",\n        \"2392\",\n        \"1018\",\n        \"#64abf7\",\n        \"\"\n      ]\n    }\n  ]\n}\n[/block]\nLanguage handlers that provide an outline view **must** implement [base_handler.outline()](https://apidoc.c9.io/c9v3/#!/api/language.base_handler-method-outline):\n\n```javascript\nhandler.outline = function(doc, ast, callback) {\n    callback(null, {\n        result: {\n            items: [\n                 icon: 'method',\n                 name: \"fooMethod\",\n                 pos: this.getPos(),\n                 displayPos: { sl: 15, sc: 20 },\n                 items: [ ...items nested under this method... ],\n                 isUnordered: true\n           ]\n    });\n};\n```\n\nGenerally, to create a full outline view for a language, a parser is needed. A parser can create an abstract syntax tree, from which an outline view can be constructed. If a language does not have a parser, it's possible construct a (basic) outline view can be constructed using simple string operations and regular expressions instead. See also [Jsonalyzer Handlers](doc:jsonalyzer-handlers) for using the Jsonalyzer to add a simple outline using regular expressions, or use the [outline bundle](doc:outline) to do so.\n\n# Implementing Tooltips\n\nLanguage handlers that provide tooltips **must** implement [base_handler.tooltip()](https://apidoc.c9.io/c9v3/#!/api/language.base_handler-method-tooltip):\n\n```javascript\nhandler.tooltip = function(doc, ast, pos, options, callback) {\n    callback(null, {\n        hint: \"Hello this is a <b>tooltip</b>\",\n        displayPos: { sl: 0, el: 0, sc: 0, ec: 0 },\n        pos: { sl: 0, el: 0, sc: 0, ec: 0 },\n    });\n};\n```\n\nTooltips can use HTML for formatting or Cloud9's JSON format for describing tooltips for function/method signatures. See the [API reference](https://apidoc.c9.io/c9v3/#!/api/language.base_handler-method-tooltip) for further details.\n\nLanguage handlers that provide tooltips **should** implement [base_handler.getTooltipRegex()](https://apidoc.c9.io/c9v3/#!/api/language.base_handler-method-getTooltipRegex) to speed up display of tooltips.\n[block:callout]\n{\n  \"type\": \"success\",\n  \"body\": \"For languages that don't implement full tooltip support, Cloud9 can also _guess_ the tooltips from the code completer. See [Customizing Code Completers](doc:customizing-code-completers#section-tooltips).\",\n  \"title\": \"Tooltip guessing\"\n}\n[/block]\n## Implementing Jump to Definition\n\nLanguage handlers that provide jump to definition **must** implement [base_handler.jumpToDefinition()](https://apidoc.c9.io/c9v3/#!/api/language.base_handler-method-jumpToDefinition).\n\n```javascript\nhandler.jumpToDefinition = function(doc, ast, pos, options, callback) {\n    var definition = ...;\n    callback(null, {\n        row: definition.row,\n        column: definition.column,\n        path: definition.path\n    });\n};\n```\n\n# Implementing Highlight Occurrences\n\nLanguage handlers that provide occurrence highlighting **must** implement [base_handler.highlightOccurrences()](https://apidoc.c9.io/c9v3/#!/api/language.base_handler-method-highlightOccurrences).\n\n```javascript\nhandler.highlightOccurrences = function(doc, ast, pos, options, callback) {\n    ...\n    callback(null, {\n        markers: [\n            {\n                pos: { sl: 5, el: 5, sc: 4, ec: 7 },\n                type: 'occurrence_main'\n            },\n            {\n                pos: { sl: 6, el: 6, sc: 4, ec: 7 },\n                type: 'occurrence_other'\n            },\n        ],\n        refactorings: false\n    });\n};\n```\n\n# Implementing Code Formatting\n\nLanguage handlers that provide code formatting **must** implement [base_handler.codeFormat()](https://apidoc.c9.io/c9v3/#!/api/language.base_handler-method-codeFormat).\n\n```javascript\nhandler.codeFormat = function(doc, ast, pos, options, callback) {\n    ...\n    callback(null, doc.getValue().replace(/\\t/, \"    \"));\n};\n```\n\n# Implementing Quick Fixes and Quick Suggestions\n\nLanguage handlers that provide quick fixes or quick suggestions **must** implement [base_handler.getQuickFixes()](https://apidoc.c9.io/c9v3/#!/api/language.base_handler-method-getQuickFixes).\n\nQuick fixes allow users to click on error markers (or use a hotkey) to quickly fix common problems. At the time of writing, quick fixes are not fully supported as there is no UI for quick fixes yet. Cloud9 does support a keyboard shortcut, however, that can be used for quick fixes or quick suggestions.\n\nQuick suggestions allow users to make quick changes to the code when there may not be actually any problem. One example of quick fixes in Cloud9 is used for the Salesforce integration, where a quick suggestion when typing an attribute name that cannot be found:\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/UgVN6q4kRkqe7XgOs0ru_screenshot.png\",\n        \"screenshot.png\",\n        \"785\",\n        \"248\",\n        \"#64a598\",\n        \"\"\n      ]\n    }\n  ]\n}\n[/block]\nImplementing a quick suggestion requires implementing both [base_handler.tooltip()](https://apidoc.c9.io/c9v3/#!/api/language.base_handler-method-tooltip) and [base_handler.getQuickFixes()](https://apidoc.c9.io/c9v3/#!/api/language.base_handler-method-getQuickFixes), and the use of [worker_util.getQuickFixKey](https://apidoc.c9.io/c9v3/#!/api/language.worker_util-method-getQuickFixKey):\n\n```javascript\nhandler.tooltip =  function(doc, ast, pos, options, callback) {\n    if (!isUnknownAttribute(doc, pos)) // cursor is not at something we can quick suggest for\n        return callback();\n        \n    var key = workerUtil.getQuickfixKey();\n    \n    callback(null, {\n        hint: \"Press \" + key + \" to create \" + expression + \"()\",\n        pos: { sl: pos.row, el: pos.row, sc: pos.column, ec: pos.column },\n        displayPos: { row: pos.row, column: pos.column }\n    });\n};\n\nhandler.getQuickfixes = function(doc, ast, pos, options, callback) {\n    if (!isUnknownAttribute(doc, pos))) // cursor is not at something we can quick suggest for\n        return callback();\n    \n    ...\n    return callback(null, {\n        action: \"insert\",\n        path: fixPath, // path of target file\n        start: fixPos, // position to apply fix\n        end: fixPos,\n        lines: [ // lines to insert at fixPos\n            name + \": function(component, event, helper) {}\"\n        ]\n    });\n};\n```\n\n# Implementing Rename Refactoring\n\nLanguage handlers that implement rename refactoring **must** implement the following methods:\n\n- [base_handler.getRefactorings()](https://apidoc.c9.io/c9v3/#!/api/language.base_handler-method-getRefactorings)\n- [base_handler.getRenamePositions()](https://apidoc.c9.io/c9v3/#!/api/language.base_handler-method-getRenamePositions)\n\nand **may** implement: \n- [base_handler.onRenameBegin()](https://apidoc.c9.io/c9v3/#!/api/language.base_handler-method-onRenameBegin), [base_handler.commitRename()](https://apidoc.c9.io/c9v3/#!/api/language.base_handler-method-commitRename)\n- [base_handler.onRenameCancel()](https://apidoc.c9.io/c9v3/#!/api/language.base_handler-method-onRenameCancel)\n \nPlease refer to the API reference for additional details, and see [c9.ide.language.javascript/scope_analyzer.js](https://github.com/c9/newclient/blob/547f15e291746e4be67d95923093ed32af2c297d/plugins/c9.ide.language.javascript/scope_analyzer.js) for a concrete example.\n\n# Listening to General Events\n\nLanguage handlers **may** implement [base_handler.init()](https://apidoc.c9.io/c9v3/#!/api/language.base_handler-method-init) to perform any initialization as they are loaded:\n\n```javascript\nhandler.init = function(callback) {\n    // ...\n    callback();\n};\n```\n\nOther event handlers language handlers *may* implement are:\n-  [base_handler.onUpdate()](https://apidoc.c9.io/c9v3/#!/api/language.base_handler-method-onUpdate) to get notified as files are updated.\n- [base_handler.onDocumentOpen()](https://apidoc.c9.io/c9v3/#!/api/language.base_handler-method-onDocumentOpen) to get notified as documents are opened.\n- [base_handler.onDocumentClose()](https://apidoc.c9.io/c9v3/#!/api/language.base_handler-method-onDocumentClose) to get notified as documents are closed.\n- [base_handler.onCursorMove()](https://apidoc.c9.io/c9v3/#!/api/language.base_handler-method-onCursorMove) to get notified as the cursor is moved.\n\n# Talking to the Outside World\n\nLanguage workers live in their own world, in a web worker. They cannot directly talk to other plugins. There are a number of ways to still communicate with other plugins, change or invoke something on the workspace, or reach out to the web.\n\nEvery language plugin developer should have a look at [worker_util](https://apidoc.c9.io/c9v3/#!/api/language.worker_util). It provides several methods for talking to the outside world, including:\n- [worker_util.execFile()](https://apidoc.c9.io/c9v3/#!/api/language.base_handler-method-execFile) for executing files on the workspace and getting their stdout and stderr output.\n- [worker_util.spawn()](https://apidoc.c9.io/c9v3/#!/api/language.base_handler-method-spawn) for spawning longer-running processes on the workspace.\n- [worker_util.execAnalysis()](https://apidoc.c9.io/c9v3/#!/api/language.base_handler-method-execAnalysis) for invoking language tools such as linters on the workspace. See also [Using Existing Language Tools](doc:existing-tools).\n- [worker_util.stat()](https://apidoc.c9.io/c9v3/#!/api/language.base_handler-method-stat) for getting basic information about files on the file system, such as their size.\n- [worker_util.readFile()](https://apidoc.c9.io/c9v3/#!/api/language.base_handler-method-readFile) for reading files on the file system, or optionally getting unsaved content of open files.\n- [worker_util.showError()](https://apidoc.c9.io/c9v3/#!/api/language.base_handler-method-showError) for showing an error in the UI.\n\nLanguage workers can also communicate with plugins that run in the UI by emitting events. In the UI plugin where a handler is registered, events can be sent and received using the `handler` object acquired at registration:\n\n```javascript\nlanguage.registerLanguageHandler(\"plugins/your.plugin/handler/mylang_handler\", function(err, handler) {\n    if (err) return console.error(err);\n    handler.emit(\"getHello\", {});\n    handler.on(\"getHelloResult\", function(e) {\n        console.log(e);\n    });\n});\n```\n\nIn language handlers, [base_handler.getEmitter()](https://apidoc.c9.io/c9v3/#!/api/language.base_handler-method-getEmitter) allows sending/receiving events:\n\n```javascript\nhandler.init = function() {\n    var emitter = handler.getEmitter();\n    emitter.on(\"getHello\", function() {\n        emitter.emit(\"getHelloResult\", \"hello\");\n    });\n    callback();\n};\n```\n[block:api-header]\n{\n  \"type\": \"basic\",\n  \"title\": \"Reference Implementations\"\n}\n[/block]\nFor full reference implementations of the language handler plugins, see [Full Example Language Handlers](doc:complete-examples).","excerpt":"","slug":"language-handlers","type":"basic","title":"Language Handlers"}
All language tooling in Cloud9 is implemented using language handlers. Language handlers are plugin components that run in a web worker. Plugin developers can write language handlers directly or they can use [outline definitions](doc:outline) in the Cloud9 Bundle or [the Jsonalyzer framework](doc:jsonalyzer-handlers) as an abstraction for building certain kinds of language plugins. # Overview - [Language Plugins](#section-language-plugins) - [Language Handlers](#section-language-handlers) - [Declaring What a Handler is Used For](#section-declaring-what-a-handler-is-used-for) - [Implementing Static Analysis](#section-implementing-static-analysis) - [Implementing a Parser](#section-implementing-a-parser) - [Implementing Code Completion](#section-implementing-code-completion) - [Implementing an Outline View](#section-implementing-an-outline-view) - [Implementing Tooltips](#section-implementing-tooltips) - [Implementing Highlight Occurrences](#section-implementing-highlight-occurrences) - [Implementing Code Formatting](#section-implementing-code-formatting) - [Implementing Quick Fixes and Quick Suggestions](#section-implementing-quick-fixes-and-quick-suggestions) - [Implementing Rename Refactoring](#section-implementing-rename-refactoring) - [Listening to General Events](#section-listening-to-general-events) - [Talking to the Outside World](#section-talking-to-the-outside-world) - [Reference Implementations](#reference-implementations) # Language Plugins Cloud9 language plugin packages generally have a structure like this: ``` └─ mylang.language ├─ worker | └─ mylang_handler.js ├─ mylang.js ├─ package.json └─ README.md └─ LICENSE ``` Below is the contents `mylang.js`, which is the main file of this package. The `mylang.js` plugin is a regular Cloud9 plugin, and whose job it its to load the language handler called `mylang_handler`: ```javascript define(function(require, exports, module) { main.consumes = ["Plugin", "language"]; main.provides = ["mylang"]; return main; function main(options, imports, register) { var Plugin = imports.Plugin; var plugin = new Plugin("mylang.org", main.consumes); var language = imports.language; function load() { language.registerLanguageHandler( "plugins/mylang.language/worker/mylang_handler", function(err, handler) { if (err) return err; // send/receive events using handler.emit/on }, plugin ); } plugin.on("load", load); plugin.on("unload", function() { // do when plugin is unloaded }); register(null, { mylang: plugin }); } }); ``` Essentially all this plugin does is call [language.registerLanguageHandler()](https://docs.c9.io/api/#!/api/language-method-registerLanguageHandler) to load a handler `plugins/mylang.language/worker/mylang_handler.js`. That file is where the real magic happens. We'll dive further into language handlers next. # Language Handlers Language handlers implement the [base_handler](https://docs.c9.io/api/#!/api/language.base_handler) abstract class. The interface is best illustrated with an example. Below is a language handler that subclasses `base_handler`: ```javascript define(function(require, exports, module) { var baseHandler = require("plugins/c9.ide.language/base_handler"); var handler = module.exports = Object.create(baseHandler); handler.handlesLanguage = function(language) { return language === "javascript" || language === "jsx"; }; handler.analyze = function(value, ast, callback) { if (!ast) return; callback(null, [{ pos: { sl: 0, el: 0, sc: 0, ec: 0 }, type: "info", message: "Hey there! I'm an info marker" }]); }; }); ``` The `base_handler` abstract has one method that always must be implemented: [base_handler.handlesLanguage()](https://docs.c9.io/api/#!/api/language-method-handlesLanguage). In the language handler above, the handler uses it to tell Cloud9 that it should be used for JavaScript and JSX files. The handler also implements the optional [base_handler.analyze()](https://docs.c9.io/api/#!/api/language-method-handlesLanguage) method, adding a new info marker at the top of all JavaScript/JSX files: [block:image] { "images": [ { "image": [ "https://files.readme.io/014QDkgDSsOIJAicIWXQ_image.png", "image.png", "1570", "451", "#1b5bbd", "" ] } ] } [/block] The example above provides a starting point for implementing language handlers. Cloud9 supports and recommends the use of multiple handlers and handler functions per language. The `base_handler` interface provides methods for doing code completion, showing an outline view, tooltips, etc. that are best organized into separate handlers. [block:callout] { "type": "success", "body": "Each language can have many language handlers that implement some subset of the supported handler methods. For example, for Python, you may have a `python_linter.js`, a `python_completer.js` and a `python_outline.js`, each offering some kind of language support. They all must at least have an implementation of `base_handler.handlesLanguage()`. \n\nCloud9 also allows multiple handlers to implement the same `base_handler` method for a language. For example, there may be one implementation of [base_handler.analyze()](https://docs.c9.io/api/#!/api/language-method-handlesLanguage) that uses ESLint for error markers in JavaScript, and another implementation that adds a silly \"Hello there! I'm an info marker\" marker at the top of each JavaScript file.", "title": "Divide language tooling into as many handlers modules as you like" } [/block] Below is an overview of all abstract methods of `base_handler` and their applications. We use [RFC 2119](http://tools.ietf.org/html/rfc2119) keywords **must**, **should**, and **may** to indicate which methods are required, recommended, and optional. For a full reference of all methods see [the API Reference](https://apidoc.c9.io/c9v3/#!/api/language.base_handler). [block:callout] { "type": "info", "body": "In addition to the API reference and this guide, you can have a look at [the base_handler.js source code](https://github.com/c9/c9.ide.language/blob/master/base_handler.js) on github to browse through the language handler base class.", "title": "Base handler source code" } [/block] # Declaring What a Handler is Used For All language handlers **must** implement [base_handler.handlesLanguage()](https://apidoc.c9.io/c9v3/#!/api/language.base_handler-method-handlesLanguage): ```javascript handler.handlesLanguage = function(language) { return language === "javascript" || language === "jsx"; }; ``` Language handlers **should** specify a regular expression that matches identifier characters in that language using [base_handler.getIdentifierRegex()](https://apidoc.c9.io/c9v3/#!/api/language.base_handler-method-getIdentifierRegex): ```javascript handler.getIdentifierRegex = function() { return /[A-Za-z0-9$_]/; }; ``` Language handlers **may** specify if they are to be used for normal editors and/or the immediate view using [base_handler.handlesEditor()](https://apidoc.c9.io/c9v3/#!/api/language.base_handler-method-handlesLanguage). `HANDLES_EDITOR` indicates the handler can only be used in a normal editor; `HANDLES_IMMEDIATE` indicates it can be used only in an immediate view, and `HANDLES_EDITOR_AND_IMMEDIATE` indicates both. ```javascript handler.handlesEditor = function() { return this.HANDLES_EDITOR; }; ``` Language handlers **may** specify the maximum file size they support: ```javascript handler.getMaxFileSizeSupported = function() { return 10 * 1000 * 80; }; ``` # Implementing Static Analysis [block:callout] { "type": "success", "body": "Writing a full static analyzer or code completer from scratch is not easy and is only something only few people ever do. It's also a lot of work. Luckily, for many languages there are open-source language tools available that can be reused. See also [Using Existing Language Tools](doc:existing-tools) for examples of using existing language tools.", "title": "Use existing language tools when possible" } [/block] Language handlers that perform static analysis **must** implement [base_handler.analyze()](https://apidoc.c9.io/c9v3/#!/api/language.base_handler-method-analyze). ```javascript handler.analyze = function(value, ast, options, callback) { callback(null, [ { pos: { sl: 1, el: 1, sc: 4, ec: 5 }, type: "warning", message: "Assigning to undeclared variable." } ] }; ``` # Implementing a Parser Language handlers that use a parser **should** implement [base_handler.parse()](https://apidoc.c9.io/c9v3/#!/api/language.base_handler-method-parse): ```javascript handler.parse = function(docValue, options, callback) { var ast = ...; callback(null, ast); }; ``` Cloud9 does not directly use the abstract syntax tree result from a parser, but will pass it to other language handler methods when they are called. Language handlers with a parser *should* also implement [base_handler.analyze()](https://apidoc.c9.io/c9v3/#!/api/language.base_handler-method-analyze) to display syntax errors. Languages can have multiple handlers implementing `analyze()`, e.g. one that returns semantic errors and one that returns syntax errors. Language handlers that use parsing **should** implement [base_handler.findNode()](https://apidoc.c9.io/c9v3/#!/api/language.base_handler-method-findNode) and **should** implement [base_handler.getPos()](https://apidoc.c9.io/c9v3/#!/api/language.base_handler-method-getPos): ```javascript handler.findNode = function(ast, pos, callback) { var node = ...traverse the ast, searching for pos.row and pos.column...; callback(null, node); }; handler.getPos = function(node, callback) { var pos = ...; callback(null, { sl: pos.sl, el: pos.el, sc: pos.sc, ec: pos.ec }); }; ``` The `findNode()` method is used to pass the current AST node under the cursor to other language handlers. Other handler methods, such as [base_handler.complete()](https://apidoc.c9.io/c9v3/#!/api/language.base_handler-method-complete) can use `options.node` to get the current AST node when `parse()` and `findNode()` are implemented. [block:callout] { "type": "info", "title": "Parsing methods are optional", "body": "Both `parse()` and `findNode()` are optional and are only intended for those languages with a parser that runs in the browser. For many languages these methods do not need to be implemented." } [/block] # Implementing Code Completion Language handlers that provide code completion **must** implement [base_handler.complete()](https://apidoc.c9.io/c9v3/#!/api/language.base_handler-method-complete): ```javascript handler.complete = function(doc, ast, pos, options, callback) { var line = doc.getLine(pos.row); var identifier = options.identifierPrefix; ... callback(null, [ { name: "foo()", replaceText: "foo(^^)", icon: "method", meta: "FooClass", doc: "The foo() method", docHead: "FooClass.foo", priority: 1 } ]); }; ``` Language handlers that provide code completion **should** implement [base_handler.getCompletionRegex()](https://apidoc.c9.io/c9v3/#!/api/language.base_handler-method-getCompletionRegex). ```javascript handler.getCompletionRegex = function() { return /^\.$/; } ```` If a completion regex is specified, continuous completion is enabled for that language. This means that whenever a user types a character, completion is attempted with a short delay. If a character sequence matching the completion regex is typed, completion is performed immediately. [block:callout] { "type": "success", "body": "See [Using Existing Language Tools](doc:existing-tools) for concrete code completion examples, and [Customizing Code Completers](doc:customizing-code-completers) for advanced ways of customizing a code completer.", "title": "Further reading on code completion" } [/block] ## Implementing an Outline View [block:image] { "images": [ { "image": [ "https://files.readme.io/FVg1UFDuQhmhdN6A7QB0_outline.png", "outline.png", "2392", "1018", "#64abf7", "" ] } ] } [/block] Language handlers that provide an outline view **must** implement [base_handler.outline()](https://apidoc.c9.io/c9v3/#!/api/language.base_handler-method-outline): ```javascript handler.outline = function(doc, ast, callback) { callback(null, { result: { items: [ icon: 'method', name: "fooMethod", pos: this.getPos(), displayPos: { sl: 15, sc: 20 }, items: [ ...items nested under this method... ], isUnordered: true ] }); }; ``` Generally, to create a full outline view for a language, a parser is needed. A parser can create an abstract syntax tree, from which an outline view can be constructed. If a language does not have a parser, it's possible construct a (basic) outline view can be constructed using simple string operations and regular expressions instead. See also [Jsonalyzer Handlers](doc:jsonalyzer-handlers) for using the Jsonalyzer to add a simple outline using regular expressions, or use the [outline bundle](doc:outline) to do so. # Implementing Tooltips Language handlers that provide tooltips **must** implement [base_handler.tooltip()](https://apidoc.c9.io/c9v3/#!/api/language.base_handler-method-tooltip): ```javascript handler.tooltip = function(doc, ast, pos, options, callback) { callback(null, { hint: "Hello this is a <b>tooltip</b>", displayPos: { sl: 0, el: 0, sc: 0, ec: 0 }, pos: { sl: 0, el: 0, sc: 0, ec: 0 }, }); }; ``` Tooltips can use HTML for formatting or Cloud9's JSON format for describing tooltips for function/method signatures. See the [API reference](https://apidoc.c9.io/c9v3/#!/api/language.base_handler-method-tooltip) for further details. Language handlers that provide tooltips **should** implement [base_handler.getTooltipRegex()](https://apidoc.c9.io/c9v3/#!/api/language.base_handler-method-getTooltipRegex) to speed up display of tooltips. [block:callout] { "type": "success", "body": "For languages that don't implement full tooltip support, Cloud9 can also _guess_ the tooltips from the code completer. See [Customizing Code Completers](doc:customizing-code-completers#section-tooltips).", "title": "Tooltip guessing" } [/block] ## Implementing Jump to Definition Language handlers that provide jump to definition **must** implement [base_handler.jumpToDefinition()](https://apidoc.c9.io/c9v3/#!/api/language.base_handler-method-jumpToDefinition). ```javascript handler.jumpToDefinition = function(doc, ast, pos, options, callback) { var definition = ...; callback(null, { row: definition.row, column: definition.column, path: definition.path }); }; ``` # Implementing Highlight Occurrences Language handlers that provide occurrence highlighting **must** implement [base_handler.highlightOccurrences()](https://apidoc.c9.io/c9v3/#!/api/language.base_handler-method-highlightOccurrences). ```javascript handler.highlightOccurrences = function(doc, ast, pos, options, callback) { ... callback(null, { markers: [ { pos: { sl: 5, el: 5, sc: 4, ec: 7 }, type: 'occurrence_main' }, { pos: { sl: 6, el: 6, sc: 4, ec: 7 }, type: 'occurrence_other' }, ], refactorings: false }); }; ``` # Implementing Code Formatting Language handlers that provide code formatting **must** implement [base_handler.codeFormat()](https://apidoc.c9.io/c9v3/#!/api/language.base_handler-method-codeFormat). ```javascript handler.codeFormat = function(doc, ast, pos, options, callback) { ... callback(null, doc.getValue().replace(/\t/, " ")); }; ``` # Implementing Quick Fixes and Quick Suggestions Language handlers that provide quick fixes or quick suggestions **must** implement [base_handler.getQuickFixes()](https://apidoc.c9.io/c9v3/#!/api/language.base_handler-method-getQuickFixes). Quick fixes allow users to click on error markers (or use a hotkey) to quickly fix common problems. At the time of writing, quick fixes are not fully supported as there is no UI for quick fixes yet. Cloud9 does support a keyboard shortcut, however, that can be used for quick fixes or quick suggestions. Quick suggestions allow users to make quick changes to the code when there may not be actually any problem. One example of quick fixes in Cloud9 is used for the Salesforce integration, where a quick suggestion when typing an attribute name that cannot be found: [block:image] { "images": [ { "image": [ "https://files.readme.io/UgVN6q4kRkqe7XgOs0ru_screenshot.png", "screenshot.png", "785", "248", "#64a598", "" ] } ] } [/block] Implementing a quick suggestion requires implementing both [base_handler.tooltip()](https://apidoc.c9.io/c9v3/#!/api/language.base_handler-method-tooltip) and [base_handler.getQuickFixes()](https://apidoc.c9.io/c9v3/#!/api/language.base_handler-method-getQuickFixes), and the use of [worker_util.getQuickFixKey](https://apidoc.c9.io/c9v3/#!/api/language.worker_util-method-getQuickFixKey): ```javascript handler.tooltip = function(doc, ast, pos, options, callback) { if (!isUnknownAttribute(doc, pos)) // cursor is not at something we can quick suggest for return callback(); var key = workerUtil.getQuickfixKey(); callback(null, { hint: "Press " + key + " to create " + expression + "()", pos: { sl: pos.row, el: pos.row, sc: pos.column, ec: pos.column }, displayPos: { row: pos.row, column: pos.column } }); }; handler.getQuickfixes = function(doc, ast, pos, options, callback) { if (!isUnknownAttribute(doc, pos))) // cursor is not at something we can quick suggest for return callback(); ... return callback(null, { action: "insert", path: fixPath, // path of target file start: fixPos, // position to apply fix end: fixPos, lines: [ // lines to insert at fixPos name + ": function(component, event, helper) {}" ] }); }; ``` # Implementing Rename Refactoring Language handlers that implement rename refactoring **must** implement the following methods: - [base_handler.getRefactorings()](https://apidoc.c9.io/c9v3/#!/api/language.base_handler-method-getRefactorings) - [base_handler.getRenamePositions()](https://apidoc.c9.io/c9v3/#!/api/language.base_handler-method-getRenamePositions) and **may** implement: - [base_handler.onRenameBegin()](https://apidoc.c9.io/c9v3/#!/api/language.base_handler-method-onRenameBegin), [base_handler.commitRename()](https://apidoc.c9.io/c9v3/#!/api/language.base_handler-method-commitRename) - [base_handler.onRenameCancel()](https://apidoc.c9.io/c9v3/#!/api/language.base_handler-method-onRenameCancel) Please refer to the API reference for additional details, and see [c9.ide.language.javascript/scope_analyzer.js](https://github.com/c9/newclient/blob/547f15e291746e4be67d95923093ed32af2c297d/plugins/c9.ide.language.javascript/scope_analyzer.js) for a concrete example. # Listening to General Events Language handlers **may** implement [base_handler.init()](https://apidoc.c9.io/c9v3/#!/api/language.base_handler-method-init) to perform any initialization as they are loaded: ```javascript handler.init = function(callback) { // ... callback(); }; ``` Other event handlers language handlers *may* implement are: - [base_handler.onUpdate()](https://apidoc.c9.io/c9v3/#!/api/language.base_handler-method-onUpdate) to get notified as files are updated. - [base_handler.onDocumentOpen()](https://apidoc.c9.io/c9v3/#!/api/language.base_handler-method-onDocumentOpen) to get notified as documents are opened. - [base_handler.onDocumentClose()](https://apidoc.c9.io/c9v3/#!/api/language.base_handler-method-onDocumentClose) to get notified as documents are closed. - [base_handler.onCursorMove()](https://apidoc.c9.io/c9v3/#!/api/language.base_handler-method-onCursorMove) to get notified as the cursor is moved. # Talking to the Outside World Language workers live in their own world, in a web worker. They cannot directly talk to other plugins. There are a number of ways to still communicate with other plugins, change or invoke something on the workspace, or reach out to the web. Every language plugin developer should have a look at [worker_util](https://apidoc.c9.io/c9v3/#!/api/language.worker_util). It provides several methods for talking to the outside world, including: - [worker_util.execFile()](https://apidoc.c9.io/c9v3/#!/api/language.base_handler-method-execFile) for executing files on the workspace and getting their stdout and stderr output. - [worker_util.spawn()](https://apidoc.c9.io/c9v3/#!/api/language.base_handler-method-spawn) for spawning longer-running processes on the workspace. - [worker_util.execAnalysis()](https://apidoc.c9.io/c9v3/#!/api/language.base_handler-method-execAnalysis) for invoking language tools such as linters on the workspace. See also [Using Existing Language Tools](doc:existing-tools). - [worker_util.stat()](https://apidoc.c9.io/c9v3/#!/api/language.base_handler-method-stat) for getting basic information about files on the file system, such as their size. - [worker_util.readFile()](https://apidoc.c9.io/c9v3/#!/api/language.base_handler-method-readFile) for reading files on the file system, or optionally getting unsaved content of open files. - [worker_util.showError()](https://apidoc.c9.io/c9v3/#!/api/language.base_handler-method-showError) for showing an error in the UI. Language workers can also communicate with plugins that run in the UI by emitting events. In the UI plugin where a handler is registered, events can be sent and received using the `handler` object acquired at registration: ```javascript language.registerLanguageHandler("plugins/your.plugin/handler/mylang_handler", function(err, handler) { if (err) return console.error(err); handler.emit("getHello", {}); handler.on("getHelloResult", function(e) { console.log(e); }); }); ``` In language handlers, [base_handler.getEmitter()](https://apidoc.c9.io/c9v3/#!/api/language.base_handler-method-getEmitter) allows sending/receiving events: ```javascript handler.init = function() { var emitter = handler.getEmitter(); emitter.on("getHello", function() { emitter.emit("getHelloResult", "hello"); }); callback(); }; ``` [block:api-header] { "type": "basic", "title": "Reference Implementations" } [/block] For full reference implementations of the language handler plugins, see [Full Example Language Handlers](doc:complete-examples).