Skip to content
This repository was archived by the owner on Sep 6, 2021. It is now read-only.

Commit c00bfb1

Browse files
committed
The language is now detected when constructing the document and when the underlying file is renamed. If the language changes, a languageChanged event is fired. Editors now determine their mode themselves by consulting the document's language and responding to languageChanged events. To save the editor state, editors are n longer closed and reopened when renaming a file. This brings back the problem with JSLint not opening when changing the extension to ".js".
1 parent 59cf95f commit c00bfb1

File tree

4 files changed

+54
-35
lines changed

4 files changed

+54
-35
lines changed

src/document/DocumentManager.js

Lines changed: 19 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -599,15 +599,13 @@ define(function (require, exports, module) {
599599
this.file = file;
600600
this.refreshText(rawText, initialTimestamp);
601601

602+
this._updateLanguage();
603+
// TODO: remove this listener when the document object is obsolete.
604+
// But when is this the case? When _refCount === 0?
605+
$(this.file).on("rename", this._updateLanguage.bind(this));
606+
602607
// This is a good point to clean up any old dangling Documents
603608
_gcDocuments();
604-
605-
var _this = this;
606-
$(module.exports).on("fileNameChange", function (e, oldName, newName) {
607-
if (file.fullPath === newName) {
608-
_this.language = null;
609-
}
610-
});
611609
}
612610

613611
/**
@@ -945,16 +943,25 @@ define(function (require, exports, module) {
945943

946944
/**
947945
* Returns the language this document is written in.
948-
* The language returned is based on the file extension and is set in the constructor.
946+
* The language returned is based on the file extension.
949947
* @return {Language} An object describing the language used in this document
950948
*/
951949
Document.prototype.getLanguage = function () {
952-
if (!this.language) {
953-
var ext = PathUtils.filenameExtension(this.file.fullPath);
954-
this.language = Languages.getLanguageForFileExtension(ext);
955-
}
956950
return this.language;
957951
};
952+
953+
/**
954+
* Updates the language according to the file extension
955+
*/
956+
Document.prototype._updateLanguage = function () {
957+
var oldLanguage = this.language;
958+
var ext = PathUtils.filenameExtension(this.file.fullPath);
959+
this.language = Languages.getLanguageForFileExtension(ext);
960+
961+
if (oldLanguage && oldLanguage !== this.language) {
962+
$(this).triggerHandler("languageChanged", [oldLanguage, this.language]);
963+
}
964+
}
958965

959966
/**
960967
* Gets an existing open Document for the given file, or creates a new one if the Document is
@@ -1193,14 +1200,6 @@ define(function (require, exports, module) {
11931200

11941201
// Send a "fileNameChanged" event. This will trigger the views to update.
11951202
$(exports).triggerHandler("fileNameChange", [oldName, newName]);
1196-
1197-
// If the renamed file is shown in the current full editor, re-open that
1198-
// This way everything that depends on the language will be updated (editor mode, JSLint, ...)
1199-
var doc = getCurrentDocument();
1200-
if (doc && doc.file.fullPath === newName) {
1201-
closeFullEditor(doc.file);
1202-
setCurrentDocument(doc);
1203-
}
12041203
}
12051204

12061205
// Define public API

src/editor/Editor.js

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -292,7 +292,7 @@ define(function (require, exports, module) {
292292
* @param {{startLine: number, endLine: number}=} range If specified, range of lines within the document
293293
* to display in this editor. Inclusive.
294294
*/
295-
function Editor(document, makeMasterEditor, mode, container, range) {
295+
function Editor(document, makeMasterEditor, container, range) {
296296
var self = this;
297297

298298
_instances.push(this);
@@ -308,8 +308,12 @@ define(function (require, exports, module) {
308308
// store this-bound version of listeners so we can remove them later
309309
this._handleDocumentChange = this._handleDocumentChange.bind(this);
310310
this._handleDocumentDeleted = this._handleDocumentDeleted.bind(this);
311+
this._handleDocumentLanguageChanged = this._handleDocumentLanguageChanged.bind(this);
311312
$(document).on("change", this._handleDocumentChange);
312313
$(document).on("deleted", this._handleDocumentDeleted);
314+
$(document).on("languageChanged", this._handleDocumentLanguageChanged);
315+
316+
var mode = this._getModeFromDocument();
313317

314318
// (if makeMasterEditor, we attach the Doc back to ourselves below once we're fully initialized)
315319

@@ -346,13 +350,6 @@ define(function (require, exports, module) {
346350
"Cmd-Left": "goLineStartSmart"
347351
};
348352

349-
// We'd like null/"" to mean plain text mode. CodeMirror defaults to plaintext for any
350-
// unrecognized mode, but it complains on the console in that fallback case: so, convert
351-
// here so we're always explicit, avoiding console noise.
352-
if (!mode) {
353-
mode = "text/plain";
354-
}
355-
356353
// Create the CodeMirror instance
357354
// (note: CodeMirror doesn't actually require using 'new', but jslint complains without it)
358355
this._codeMirror = new CodeMirror(container, {
@@ -436,6 +433,7 @@ define(function (require, exports, module) {
436433
this.document.releaseRef();
437434
$(this.document).off("change", this._handleDocumentChange);
438435
$(this.document).off("deleted", this._handleDocumentDeleted);
436+
$(this.document).off("languageChanged", this._handleDocumentLanguageChanged);
439437

440438
if (this._visibleRange) { // TextRange also refs the Document
441439
this._visibleRange.dispose();
@@ -453,6 +451,18 @@ define(function (require, exports, module) {
453451
});
454452
};
455453

454+
/**
455+
* Determine the mode to use from the document's language
456+
* Uses "text/plain" if the language does not define a mode
457+
* @return string The mode to use
458+
*/
459+
Editor.prototype._getModeFromDocument = function () {
460+
// We'd like undefined/null/"" to mean plain text mode. CodeMirror defaults to plaintext for any
461+
// unrecognized mode, but it complains on the console in that fallback case: so, convert
462+
// here so we're always explicit, avoiding console noise.
463+
return this.document.getLanguage().mode || "text/plain";
464+
};
465+
456466

457467
/**
458468
* Selects all text and maintains the current scroll position.
@@ -598,6 +608,14 @@ define(function (require, exports, module) {
598608
$(this).triggerHandler("lostContent", [event]);
599609
};
600610

611+
/**
612+
* Responds to language changes, for instance when the file extension is changed.
613+
*/
614+
Editor.prototype._handleDocumentLanguageChanged = function (event) {
615+
var mode = this._getModeFromDocument();
616+
this._codeMirror.setOption("mode", this._getModeFromDocument());
617+
};
618+
601619

602620
/**
603621
* Install event handlers on the CodeMirror instance, translating them into

src/editor/EditorManager.js

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -109,8 +109,8 @@ define(function (require, exports, module) {
109109
$indentWidthInput;
110110

111111
/**
112-
* Creates a new Editor bound to the given Document. The editor's mode is inferred based on the
113-
* document's language. The editor is appended to the given container as a visible child.
112+
* Creates a new Editor bound to the given Document.
113+
* The editor is appended to the given container as a visible child.
114114
* @param {!Document} doc Document for the Editor's content
115115
* @param {!boolean} makeMasterEditor If true, the Editor will set itself as the private "master"
116116
* Editor for the Document. If false, the Editor will attach to the Document as a "slave."
@@ -120,7 +120,7 @@ define(function (require, exports, module) {
120120
* @return {Editor} the newly created editor.
121121
*/
122122
function _createEditorForDocument(doc, makeMasterEditor, container, range) {
123-
return new Editor(doc, makeMasterEditor, doc.getLanguage().mode, container, range);
123+
return new Editor(doc, makeMasterEditor, container, range);
124124
}
125125

126126
/**
@@ -250,8 +250,8 @@ define(function (require, exports, module) {
250250

251251

252252
/**
253-
* Creates a new inline Editor instance for the given Document. The editor's mode is inferred
254-
* based on the document's language. The editor is not yet visible or attached to a host editor.
253+
* Creates a new inline Editor instance for the given Document.
254+
* The editor is not yet visible or attached to a host editor.
255255
* @param {!Document} doc Document for the Editor's content
256256
* @param {?{startLine:Number, endLine:Number}} range If specified, all lines outside the given
257257
* range are hidden from the editor. Range is inclusive. Line numbers start at 0.

src/file/FileUtils.js

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -272,8 +272,8 @@ define(function (require, exports, module) {
272272
*/
273273
function updateFileEntryPath(entry, oldName, newName, isFolder) {
274274
if (isAffectedWhenRenaming(entry.fullPath, oldName, newName, isFolder)) {
275-
var fullPath = entry.fullPath.replace(oldName, newName);
276-
275+
var oldFullPath = entry.fullPath;
276+
var fullPath = oldFullPath.replace(oldName, newName);
277277
entry.fullPath = fullPath;
278278

279279
// TODO: Should this be a method on Entry instead?
@@ -287,6 +287,8 @@ define(function (require, exports, module) {
287287
}
288288
}
289289

290+
$(entry).triggerHandler("rename", [oldFullPath, fullPath]);
291+
290292
return true;
291293
}
292294

0 commit comments

Comments
 (0)