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

Commit b409212

Browse files
committed
Merge pull request #6409 from adobe/pflynn/JakeStoeffler-languageselector-updated
Switch language / syntax mode of current document
2 parents 373c4f0 + c118a97 commit b409212

17 files changed

Lines changed: 392 additions & 48 deletions

File tree

src/brackets.js

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -400,14 +400,15 @@ define(function (require, exports, module) {
400400
$("html").on("mousedown", ".no-focus", function (e) {
401401
// Text fields should always be focusable.
402402
var $target = $(e.target),
403-
isTextField =
403+
isFormElement =
404404
$target.is("input[type=text]") ||
405405
$target.is("input[type=number]") ||
406406
$target.is("input[type=password]") ||
407407
$target.is("input:not([type])") || // input with no type attribute defaults to text
408-
$target.is("textarea");
408+
$target.is("textarea") ||
409+
$target.is("select");
409410

410-
if (!isTextField) {
411+
if (!isFormElement) {
411412
e.preventDefault();
412413
}
413414
});

src/document/Document.js

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,7 @@ define(function (require, exports, module) {
156156
* @type {FileUtils.LINE_ENDINGS_CRLF|FileUtils.LINE_ENDINGS_LF}
157157
*/
158158
Document.prototype._lineEndings = null;
159-
159+
160160
/** Add a ref to keep this Document alive */
161161
Document.prototype.addRef = function () {
162162
//console.log("+++REF+++ "+this);
@@ -670,14 +670,25 @@ define(function (require, exports, module) {
670670
Document.prototype.getLanguage = function () {
671671
return this.language;
672672
};
673+
674+
/**
675+
* Overrides the default language of this document and sets it to the given
676+
* language. This change is not persisted if the document is closed.
677+
* @param {?Language} language The language to be set for this document; if
678+
* null, the language will be set back to the default.
679+
*/
680+
Document.prototype.setLanguageOverride = function (language) {
681+
LanguageManager._setLanguageOverrideForPath(this.file.fullPath, language);
682+
this._updateLanguage();
683+
};
673684

674685
/**
675-
* Updates the language according to the file extension
686+
* Updates the language according to the file extension. If the current
687+
* language was forced (set manually by user), don't change it.
676688
*/
677689
Document.prototype._updateLanguage = function () {
678690
var oldLanguage = this.language;
679691
this.language = LanguageManager.getLanguageForPath(this.file.fullPath);
680-
681692
if (oldLanguage && oldLanguage !== this.language) {
682693
$(this).triggerHandler("languageChanged", [oldLanguage, this.language]);
683694
}
@@ -698,7 +709,6 @@ define(function (require, exports, module) {
698709
return this.file instanceof InMemoryFile;
699710
};
700711

701-
702712
// Define public API
703713
exports.Document = Document;
704714
});

src/document/DocumentManager.js

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -474,9 +474,13 @@ define(function (require, exports, module) {
474474
if (_currentDocument === doc) {
475475
return;
476476
}
477-
477+
478478
var perfTimerName = PerfUtils.markStart("setCurrentDocument:\t" + doc.file.fullPath);
479479

480+
if (_currentDocument) {
481+
$(_currentDocument).off("languageChanged.DocumentManager");
482+
}
483+
480484
// If file is untitled or otherwise not within project tree, add it to
481485
// working set right now (don't wait for it to become dirty)
482486
if (doc.isUntitled() || !ProjectManager.isWithinProject(doc.file.fullPath)) {
@@ -491,6 +495,12 @@ define(function (require, exports, module) {
491495
// Make it the current document
492496
var previousDocument = _currentDocument;
493497
_currentDocument = doc;
498+
499+
// Proxy this doc's languageChange events as long as it's current
500+
$(_currentDocument).on("languageChanged.DocumentManager", function (data) {
501+
$(exports).trigger("currentDocumentLanguageChanged", data);
502+
});
503+
494504
$(exports).triggerHandler("currentDocumentChange", [_currentDocument, previousDocument]);
495505
// (this event triggers EditorManager to actually switch editors in the UI)
496506

src/editor/EditorStatusBar.js

Lines changed: 73 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -32,17 +32,20 @@ define(function (require, exports, module) {
3232
"use strict";
3333

3434
// Load dependent modules
35-
var AppInit = require("utils/AppInit"),
36-
AnimationUtils = require("utils/AnimationUtils"),
37-
EditorManager = require("editor/EditorManager"),
38-
Editor = require("editor/Editor").Editor,
39-
KeyEvent = require("utils/KeyEvent"),
40-
StatusBar = require("widgets/StatusBar"),
41-
Strings = require("strings"),
42-
StringUtils = require("utils/StringUtils");
35+
var _ = require("thirdparty/lodash"),
36+
AnimationUtils = require("utils/AnimationUtils"),
37+
AppInit = require("utils/AppInit"),
38+
DropdownButton = require("widgets/DropdownButton").DropdownButton,
39+
EditorManager = require("editor/EditorManager"),
40+
Editor = require("editor/Editor").Editor,
41+
KeyEvent = require("utils/KeyEvent"),
42+
LanguageManager = require("language/LanguageManager"),
43+
StatusBar = require("widgets/StatusBar"),
44+
Strings = require("strings"),
45+
StringUtils = require("utils/StringUtils");
4346

4447
/* StatusBar indicators */
45-
var $languageInfo,
48+
var languageSelect, // this is a DropdownButton instance
4649
$cursorInfo,
4750
$fileInfo,
4851
$indentType,
@@ -67,7 +70,15 @@ define(function (require, exports, module) {
6770
* @param {Editor} editor Current editor
6871
*/
6972
function _updateLanguageInfo(editor) {
70-
$languageInfo.text(editor.document.getLanguage().getName());
73+
var doc = editor.document,
74+
lang = doc.getLanguage();
75+
76+
// Ensure width isn't left locked by a previous click of the dropdown (which may not have resulted in a "change" event at the time)
77+
languageSelect.$button.css("width", "auto");
78+
// Setting Untitled documents to non-text mode isn't supported yet, so disable the switcher in that case for now
79+
languageSelect.$button.prop("disabled", doc.isUntitled());
80+
// Show the current language as button title
81+
languageSelect.$button.text(lang.getName());
7182
}
7283

7384
/**
@@ -260,7 +271,9 @@ define(function (require, exports, module) {
260271
$(current).on("overwriteToggle.statusbar", _updateOverwriteLabel);
261272

262273
current.document.addRef();
263-
$(current.document).on("languageChanged.statusbar", function () { _updateLanguageInfo(current); });
274+
$(current.document).on("languageChanged.statusbar", function () {
275+
_updateLanguageInfo(current);
276+
});
264277

265278
_updateCursorInfo(null, current);
266279
_updateLanguageInfo(current);
@@ -271,18 +284,55 @@ define(function (require, exports, module) {
271284
}
272285
}
273286

287+
/**
288+
* Populate the languageSelect DropdownButton's menu with all registered Languages
289+
*/
290+
function _populateLanguageDropdown() {
291+
// Get all non-binary languages
292+
var languages = _.values(LanguageManager.getLanguages()).filter(function (language) {
293+
return !language.isBinary();
294+
});
295+
296+
// sort dropdown alphabetically
297+
languages.sort(function (a, b) {
298+
return a.getName().toLowerCase().localeCompare(b.getName().toLowerCase());
299+
});
300+
301+
languageSelect.items = languages;
302+
303+
}
304+
274305
/**
275306
* Initialize
276307
*/
277308
function _init() {
278-
$languageInfo = $("#status-language");
309+
279310
$cursorInfo = $("#status-cursor");
280311
$fileInfo = $("#status-file");
281312
$indentType = $("#indent-type");
282313
$indentWidthLabel = $("#indent-width-label");
283314
$indentWidthInput = $("#indent-width-input");
284315
$statusOverwrite = $("#status-overwrite");
285316

317+
languageSelect = new DropdownButton("", [], function (item, index) {
318+
var document = EditorManager.getActiveEditor().document,
319+
defaultLang = LanguageManager.getLanguageForPath(document.file.fullPath, true),
320+
html = _.escape(item.getName());
321+
322+
// Show indicators for currently selected & default languages for the current file
323+
if (item === defaultLang) {
324+
html += " <span class='default-language'>" + Strings.STATUSBAR_DEFAULT_LANG + "</span>";
325+
}
326+
if (item === document.getLanguage()) {
327+
html = "<span class='checked-language'></span>" + html;
328+
}
329+
return html;
330+
});
331+
332+
languageSelect.dropdownExtraClasses = "dropdown-status-bar";
333+
languageSelect.$button.addClass("btn-status-bar");
334+
$("#status-language").append(languageSelect.$button);
335+
286336
// indentation event handlers
287337
$indentType.on("click", _toggleIndentType);
288338
$indentWidthLabel
@@ -310,6 +360,16 @@ define(function (require, exports, module) {
310360

311361
$indentWidthInput.focus(function () { $indentWidthInput.select(); });
312362

363+
// Language select change handler
364+
$(languageSelect).on("select", function (e, lang, index) {
365+
var document = EditorManager.getActiveEditor().document,
366+
fullPath = document.file.fullPath,
367+
defaultLang = LanguageManager.getLanguageForPath(fullPath, true);
368+
// if default language selected, don't "force" it
369+
// (passing in null will reset the force flag)
370+
document.setLanguageOverride(lang === defaultLang ? null : lang);
371+
});
372+
313373
$statusOverwrite.on("click", _updateEditorOverwriteMode);
314374

315375
_onActiveEditorChange(null, EditorManager.getActiveEditor(), null);
@@ -319,4 +379,5 @@ define(function (require, exports, module) {
319379
$(EditorManager).on("activeEditorChange", _onActiveEditorChange);
320380

321381
AppInit.htmlReady(_init);
382+
AppInit.appReady(_populateLanguageDropdown);
322383
});

src/extensions/default/JavaScriptCodeHints/main.js

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,12 +34,12 @@ define(function (require, exports, module) {
3434
DocumentManager = brackets.getModule("document/DocumentManager"),
3535
Commands = brackets.getModule("command/Commands"),
3636
CommandManager = brackets.getModule("command/CommandManager"),
37+
LanguageManager = brackets.getModule("language/LanguageManager"),
3738
Menus = brackets.getModule("command/Menus"),
3839
AppInit = brackets.getModule("utils/AppInit"),
3940
ExtensionUtils = brackets.getModule("utils/ExtensionUtils"),
4041
PerfUtils = brackets.getModule("utils/PerfUtils"),
4142
StringMatch = brackets.getModule("utils/StringMatch"),
42-
LanguageManager = brackets.getModule("language/LanguageManager"),
4343
ProjectManager = brackets.getModule("project/ProjectManager"),
4444
PreferencesManager = brackets.getModule("preferences/PreferencesManager"),
4545
ParameterHintManager = require("ParameterHintManager"),
@@ -308,8 +308,7 @@ define(function (require, exports, module) {
308308
* @return {boolean} - true if the document is a html file
309309
*/
310310
function isHTMLFile(document) {
311-
var languageID = LanguageManager.getLanguageForPath(document.file.fullPath).getId();
312-
return languageID === "html";
311+
return LanguageManager.getLanguageForPath(document.file.fullPath).getId() === "html";
313312
}
314313

315314
function isInlineScript(editor) {
@@ -596,7 +595,6 @@ define(function (require, exports, module) {
596595
}
597596
ignoreChange = false;
598597
});
599-
600598
ParameterHintManager.installListeners(editor);
601599
} else {
602600
session = null;
@@ -626,6 +624,18 @@ define(function (require, exports, module) {
626624
* @param {Editor} previous - the previous editor context
627625
*/
628626
function handleActiveEditorChange(event, current, previous) {
627+
// Uninstall "languageChanged" event listeners on the previous editor's document
628+
if (previous && previous !== current) {
629+
$(previous.document)
630+
.off(HintUtils.eventName("languageChanged"));
631+
}
632+
if (current && current.document !== DocumentManager.getCurrentDocument()) {
633+
$(current.document)
634+
.on(HintUtils.eventName("languageChanged"), function () {
635+
uninstallEditorListeners(current);
636+
installEditorListeners(current);
637+
});
638+
}
629639
uninstallEditorListeners(previous);
630640
installEditorListeners(current, previous);
631641
}
@@ -793,6 +803,13 @@ define(function (require, exports, module) {
793803
.on(HintUtils.eventName("activeEditorChange"),
794804
handleActiveEditorChange);
795805

806+
$(DocumentManager)
807+
.on("currentDocumentLanguageChanged", function (e) {
808+
var activeEditor = EditorManager.getActiveEditor();
809+
uninstallEditorListeners(activeEditor);
810+
installEditorListeners(activeEditor);
811+
});
812+
796813
$(ProjectManager).on("beforeProjectClose", function () {
797814
ScopeManager.handleProjectClose();
798815
});

src/language/CodeInspection.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,7 @@ define(function (require, exports, module) {
152152
function _unregisterAll() {
153153
_providers = {};
154154
}
155-
155+
156156
/**
157157
* Returns a list of provider for given file path, if available.
158158
* Decision is made depending on the file extension.
@@ -474,7 +474,7 @@ define(function (require, exports, module) {
474474
if (_enabled) {
475475
// register our event listeners
476476
$(DocumentManager)
477-
.on("currentDocumentChange.codeInspection", function () {
477+
.on("currentDocumentChange.codeInspection currentDocumentLanguageChanged.codeInspection", function () {
478478
run();
479479
})
480480
.on("documentSaved.codeInspection documentRefreshed.codeInspection", function (event, document) {

0 commit comments

Comments
 (0)