47
47
* console.log("Language " + language.getName() + " is now available!");
48
48
* });
49
49
*
50
+ * The extension can also contain dots:
51
+ * LanguageManager.defineLanguage("literatecoffeescript", {
52
+ * name: "Literate CoffeeScript",
53
+ * mode: "coffeescript",
54
+ * fileExtensions: ["litcoffee", "coffee.md"]
55
+ * });
56
+ *
50
57
* You can also specify file names:
51
58
* LanguageManager.defineLanguage("makefile", {
52
59
* name: "Make",
@@ -133,21 +140,6 @@ define(function (require, exports, module) {
133
140
return true ;
134
141
}
135
142
136
- /**
137
- * Lowercases the file extension and ensures it doesn't start with a dot.
138
- * @param {!string } extension The file extension
139
- * @return {string } The normalized file extension
140
- */
141
- function _normalizeFileExtension ( extension ) {
142
- // Remove a leading dot if present
143
- if ( extension . charAt ( 0 ) === "." ) {
144
- extension = extension . substr ( 1 ) ;
145
- }
146
-
147
- // Make checks below case-INsensitive
148
- return extension . toLowerCase ( ) ;
149
- }
150
-
151
143
/**
152
144
* Monkey-patch CodeMirror to prevent modes from being overwritten by extensions.
153
145
* We may rely on the tokens provided by some of these modes.
@@ -180,7 +172,8 @@ define(function (require, exports, module) {
180
172
181
173
/**
182
174
* Resolves a language ID to a Language object.
183
- * @param {!string } id Identifier for this language, use only letters a-z and _ inbetween (i.e. "cpp", "foo_bar")
175
+ * File names have a higher priority than file extensions.
176
+ * @param {!string } id Identifier for this language, use only letters a-z or digits 0-9 and _ inbetween (i.e. "cpp", "foo_bar", "c99")
184
177
* @return {Language } The language with the provided identifier or undefined
185
178
*/
186
179
function getLanguage ( id ) {
@@ -193,12 +186,52 @@ define(function (require, exports, module) {
193
186
* @return {Language } The language for the provided file type or the fallback language
194
187
*/
195
188
function getLanguageForPath ( path ) {
196
- var extension = _normalizeFileExtension ( PathUtils . filenameExtension ( path ) ) ,
197
- filename = PathUtils . filename ( path ) . toLowerCase ( ) ,
198
- language = extension ? _fileExtensionToLanguageMap [ extension ] : _fileNameToLanguageMap [ filename ] ;
189
+ var fileName = PathUtils . filename ( path ) . toLowerCase ( ) ,
190
+ language = _fileNameToLanguageMap [ fileName ] ,
191
+ extension ,
192
+ parts ;
199
193
194
+ // If no language was found for the file name, use the file extension instead
200
195
if ( ! language ) {
201
- console . log ( "Called LanguageManager.getLanguageForPath with an unhandled " + ( extension ? "file extension" : "file name" ) + ":" , extension || filename ) ;
196
+ // Split the file name into parts:
197
+ // "foo.coffee.md" => ["foo", "coffee", "md"]
198
+ // ".profile.bak" => ["", "profile", "bak"]
199
+ // "1. Vacation.txt" => ["1", " Vacation", "txt"]
200
+ parts = fileName . split ( "." ) ;
201
+
202
+ // A leading dot does not indicate a file extension, but marks the file as hidden => remove it
203
+ if ( parts [ 0 ] === "" ) {
204
+ // ["", "profile", "bak"] => ["profile", "bak"]
205
+ parts . shift ( ) ;
206
+ }
207
+
208
+ // The first part is assumed to be the title, not the extension => remove it
209
+ // ["foo", "coffee", "md"] => ["coffee", "md"]
210
+ // ["profile", "bak"] => ["bak"]
211
+ // ["1", " Vacation", "txt"] => [" Vacation", "txt"]
212
+ parts . shift ( ) ;
213
+
214
+ // Join the remaining parts into a file extension until none are left or a language was found
215
+ while ( ! language && parts . length ) {
216
+ // First iteration:
217
+ // ["coffee", "md"] => "coffee.md"
218
+ // ["bak"] => "bak"
219
+ // [" Vacation", "txt"] => " Vacation.txt"
220
+ // Second iteration (assuming no language was found for "coffee.md"):
221
+ // ["md"] => "md"
222
+ // ["txt"] => "txt"
223
+ extension = parts . join ( "." ) ;
224
+ language = _fileExtensionToLanguageMap [ extension ] ;
225
+ // Remove the first part
226
+ // First iteration:
227
+ // ["coffee", "md"] => ["md"]
228
+ // ["bak"] => []
229
+ // [" Vacation", "txt"] => ["txt"]
230
+ // Second iteration:
231
+ // ["md"] => []
232
+ // ["txt"] => []
233
+ parts . shift ( ) ;
234
+ }
202
235
}
203
236
204
237
return language || _fallbackLanguage ;
@@ -287,7 +320,7 @@ define(function (require, exports, module) {
287
320
288
321
/**
289
322
* Sets the identifier for this language or prints an error to the console.
290
- * @param {!string } id Identifier for this language, use only letters a-z and _ inbetween (i.e. "cpp", "foo_bar")
323
+ * @param {!string } id Identifier for this language, use only letters a-z or digits 0-9, and _ inbetween (i.e. "cpp", "foo_bar", "c99 ")
291
324
* @return {boolean } Whether the ID was valid and set or not
292
325
*/
293
326
Language . prototype . _setId = function ( id ) {
@@ -425,7 +458,14 @@ define(function (require, exports, module) {
425
458
* @return {boolean } Whether adding the file extension was successful or not
426
459
*/
427
460
Language . prototype . addFileExtension = function ( extension ) {
428
- extension = _normalizeFileExtension ( extension ) ;
461
+ // Remove a leading dot if present
462
+ if ( extension . charAt ( 0 ) === "." ) {
463
+ extension = extension . substr ( 1 ) ;
464
+ }
465
+
466
+ // Make checks below case-INsensitive
467
+ extension = extension . toLowerCase ( ) ;
468
+
429
469
if ( this . _fileExtensions . indexOf ( extension ) === - 1 ) {
430
470
this . _fileExtensions . push ( extension ) ;
431
471
@@ -446,6 +486,7 @@ define(function (require, exports, module) {
446
486
* @return {boolean } Whether adding the file name was successful or not
447
487
*/
448
488
Language . prototype . addFileName = function ( name ) {
489
+ // Make checks below case-INsensitive
449
490
name = name . toLowerCase ( ) ;
450
491
451
492
if ( this . _fileNames . indexOf ( name ) === - 1 ) {
@@ -600,7 +641,7 @@ define(function (require, exports, module) {
600
641
/**
601
642
* Defines a language.
602
643
*
603
- * @param {!string } id Unique identifier for this language, use only letters a-z, numbers and _ inbetween (i.e. "cpp", "foo_bar")
644
+ * @param {!string } id Unique identifier for this language, use only letters a-z or digits 0-9, and _ inbetween (i.e. "cpp", "foo_bar", "c99 ")
604
645
* @param {!Object } definition An object describing the language
605
646
* @param {!string } definition.name Human-readable name of the language, as it's commonly referred to (i.e. "C++")
606
647
* @param {Array.<string> } definition.fileExtensions List of file extensions used by this language (i.e. ["php", "php3"])
0 commit comments