diff --git a/.gitignore b/.gitignore index c336384197b..c2fe3567d71 100644 --- a/.gitignore +++ b/.gitignore @@ -19,4 +19,7 @@ src/extensions/disabled # unit test working directory test/temp -test/results \ No newline at end of file +test/results + +# Netbeans +/nbproject diff --git a/src/document/DocumentManager.js b/src/document/DocumentManager.js index 6bfcd1818a4..fe66845c471 100644 --- a/src/document/DocumentManager.js +++ b/src/document/DocumentManager.js @@ -952,8 +952,7 @@ define(function (require, exports, module) { */ Document.prototype._updateLanguage = function () { var oldLanguage = this.language; - var ext = PathUtils.filenameExtension(this.file.fullPath); - this.language = LanguageManager.getLanguageForFileExtension(ext); + this.language = LanguageManager.getLanguageFromFilePath(this.file.fullPath); if (oldLanguage && oldLanguage !== this.language) { $(this).triggerHandler("languageChanged", [oldLanguage, this.language]); diff --git a/src/editor/Editor.js b/src/editor/Editor.js index 6341ebd7dd7..7d8c5646028 100644 --- a/src/editor/Editor.js +++ b/src/editor/Editor.js @@ -1225,7 +1225,7 @@ define(function (require, exports, module) { * * @return {?(Object|string)} Name of syntax-highlighting mode, or object containing a "name" property * naming the mode along with configuration options required by the mode. - * See {@link LanguageManager#getLanguageForFileExtension()} and {@link Language#getMode()}. + * See {@link LanguageManager#getLanguageFromFilePath()} and {@link Language#getMode()}. */ Editor.prototype.getModeForSelection = function () { // Check for mixed mode info @@ -1258,7 +1258,7 @@ define(function (require, exports, module) { /** * Gets the syntax-highlighting mode for the document. * - * @return {Object|String} Object or Name of syntax-highlighting mode; see {@link LanguageManager#getLanguageForFileExtension()} and {@link Language#getMode()}. + * @return {Object|String} Object or Name of syntax-highlighting mode; see {@link LanguageManager#getLanguageFromFilePath()} and {@link Language#getMode()}. */ Editor.prototype.getModeForDocument = function () { return this._codeMirror.getOption("mode"); diff --git a/src/extensions/default/JavaScriptCodeHints/ScopeManager.js b/src/extensions/default/JavaScriptCodeHints/ScopeManager.js index 55bf00450db..da5f4b56a8c 100644 --- a/src/extensions/default/JavaScriptCodeHints/ScopeManager.js +++ b/src/extensions/default/JavaScriptCodeHints/ScopeManager.js @@ -440,7 +440,7 @@ define(function (require, exports, module) { file = split.file; if (file.indexOf(".") > 1) { // ignore /.dotfiles - var mode = LanguageManager.getLanguageForFileExtension(entry.fullPath).getMode(); + var mode = LanguageManager.getLanguageFromFilePath(entry.fullPath).getMode(); if (mode === HintUtils.MODE_NAME) { DocumentManager.getDocumentForPath(path).done(function (document) { refreshOuterScope(dir, file, document.getText()); diff --git a/src/language/LanguageManager.js b/src/language/LanguageManager.js index 9d86f6493a9..19dd511b312 100644 --- a/src/language/LanguageManager.js +++ b/src/language/LanguageManager.js @@ -95,6 +95,7 @@ define(function (require, exports, module) { _pendingLanguages = {}, _languages = {}, _fileExtensionToLanguageMap = {}, + _fileNameToLanguageMap = {}, _modeToLanguageMap = {}, _ready; @@ -161,7 +162,7 @@ define(function (require, exports, module) { */ function _setLanguageForMode(mode, language) { if (_modeToLanguageMap[mode]) { - console.warn("CodeMirror mode \"" + mode + "\" is already used by language " + _modeToLanguageMap[mode]._name + ", won't register for " + language._name); + console.warn("CodeMirror mode \"" + mode + "\" is already used by language " + _modeToLanguageMap[mode].name + ", won't register for " + language.name); return; } @@ -178,16 +179,19 @@ define(function (require, exports, module) { } /** - * Resolves a file extension to a Language object. - * @param {!string} path Path to or extension of the file to find a language for + * Resolves a file path to a Language object. + * @param {!string} path Path to the file to find a language for * @return {Language} The language for the provided file type or the fallback language */ - function getLanguageForFileExtension(path) { + function getLanguageFromFilePath(path) { var extension = _normalizeFileExtension(PathUtils.filenameExtension(path)), - language = _fileExtensionToLanguageMap[extension]; + filename = _normalizeFileName(PathUtils.filename(path)), + language = extension ? _fileExtensionToLanguageMap[extension] + : _fileNameToLanguageMap[filename]; if (!language) { - console.log("Called LanguageManager.getLanguageForFileExtension with an unhandled file extension:", extension); + extension ? console.log("Called LanguageManager.getLanguageFromFilePath with an unhandled file extension:", extension) + : console.log("Called LanguageManager.getLanguageFromFilePath with an unhandled file name:", filename); } return language || _fallbackLanguage; @@ -233,6 +237,7 @@ define(function (require, exports, module) { this._name = name; this._fileExtensions = []; + this._fileNames = []; this._modeToLanguageMap = {}; } @@ -249,6 +254,9 @@ define(function (require, exports, module) { /** @type {Array.} File extensions that use this language */ Language.prototype._fileExtensions = null; + /** @type {Array.} File names for extensionless files that use this language */ + Language.prototype._fileNames = null; + /** @type {{ prefix: string }} Line comment syntax */ Language.prototype._lineCommentSyntax = null; @@ -351,6 +359,15 @@ define(function (require, exports, module) { // Use concat to create a copy of this array, preventing external modification return this._fileExtensions.concat(); }; + + /** + * Returns an array of file names for extensionless files that use this language. + * @return {Array.} Extensionless file names used by this language + */ + Language.prototype.getFileNames = function () { + // Use concat to create a copy of this array, preventing external modification + return this._fileNames.concat(); + }; /** * Adds a file extension to this language. @@ -367,7 +384,7 @@ define(function (require, exports, module) { var language = _fileExtensionToLanguageMap[extension]; if (language) { - console.warn("Cannot register file extension \"" + extension + "\" for " + this._name + ", it already belongs to " + language._name); + console.warn("Cannot register file extension \"" + extension + "\" for " + this.name + ", it already belongs to " + language.name); } else { _fileExtensionToLanguageMap[extension] = this; @@ -379,6 +396,33 @@ define(function (require, exports, module) { } }; + /** + * Adds a file name to the language which is used to match files that don't have extensions like "Makefile" for example. + * Private for now since dependent code would need to by kept in sync with such changes. + * See https://github.com/adobe/brackets/issues/2966 for plans to make this public. + * @param {!string} extension An extensionless file name used by this language + * @private + */ + Language.prototype._addFileName = function (name) { + name = _normalizeFileName(name); + + if (this._fileNames.indexOf(name) === -1) { + this._fileNames.push(name); + + var language = _fileNameToLanguageMap[name]; + if (language) { + console.warn("Cannot register file name \"" + name + "\" for " + this.name + ", it already belongs to " + language.name); + } else { + _fileNameToLanguageMap[name] = this; + + // TODO (issue #2966) Allow extensions to add new file names to existing languages + // Notify on the Language and on LanguageManager? + // $(this).triggerHandler("fileNameAdded", [name]); + // $(exports).triggerHandler("fileNameAdded", [name, this]); + } + } + }; + /** * Returns whether the line comment syntax is defined for this language. * @return {boolean} Whether line comments are supported @@ -504,6 +548,8 @@ define(function (require, exports, module) { var language = new Language(id, definition.name), fileExtensions = definition.fileExtensions, + fileNames = definition.fileNames, + l, i; var blockComment = definition.blockComment; @@ -522,10 +568,17 @@ define(function (require, exports, module) { language._loadAndSetMode(definition.mode).done(function () { // register language file extensions after mode has loaded if (fileExtensions) { - for (i = 0; i < fileExtensions.length; i++) { + for (i = 0, l = fileExtensions.length; i < l; i++) { language._addFileExtension(fileExtensions[i]); } } + + // register language file names after mode has loaded + if (fileNames) { + for (i = 0, l= fileNames.length; i < l; i++) { + language._addFileName(fileNames[i]); + } + } // globally associate mode to language _setLanguageForMode(language.getMode(), language); @@ -584,5 +637,5 @@ define(function (require, exports, module) { exports.ready = _ready; exports.defineLanguage = defineLanguage; exports.getLanguage = getLanguage; - exports.getLanguageForFileExtension = getLanguageForFileExtension; + exports.getLanguageFromFilePath = getLanguageFromFilePath; }); \ No newline at end of file diff --git a/src/language/languages.json b/src/language/languages.json index bc796add524..d3d1cc8fa43 100644 --- a/src/language/languages.json +++ b/src/language/languages.json @@ -35,7 +35,7 @@ "xml": { "name": "XML", "mode": "xml", - "fileExtensions": ["svg", "xml", "wxs", "wxl"], + "fileExtensions": ["svg", "xml", "wxs", "wxl", "wsdl", "rss", "atom", "rdf", "xslt", "xul", "xbl", "mathml"], "blockComment": [""] }, @@ -85,7 +85,8 @@ "coffeescript": { "name": "CoffeeScript", "mode": "coffeescript", - "fileExtensions": ["coffee"] + "fileExtensions": ["coffee", "cf", "cson"], + "fileNames": ["Cakefile"] }, "clojure": { @@ -103,7 +104,7 @@ "ruby": { "name": "Ruby", "mode": "ruby", - "fileExtensions": ["rb"] + "fileExtensions": ["rb", "ru", "gemspec", "rake"] }, "python": { @@ -135,12 +136,26 @@ "mode": "diff", "fileExtensions": ["diff", "patch"] }, + + "makefile": { + "name": "Makefile", + "mode": "makefile", + "fileExtensions": ["make"], + "fileNames": ["GNUmakefile", "makefile", "Makefile", "OCamlMakefile"], + "lineComment": "#" + }, "markdown": { "name": "Markdown", "mode": "markdown", "fileExtensions": ["md", "markdown"] }, + + "typescript": { + "name": "TypeScript", + "mode": ["javascript", "application/typescript"], + "fileExtensions": ["typescript", "ts", "str"] + }, "yaml": { "name": "YAML",