diff --git a/src/extensions/default/CodeFolding/Prefs.js b/src/extensions/default/CodeFolding/Prefs.js
deleted file mode 100644
index 9423a540006..00000000000
--- a/src/extensions/default/CodeFolding/Prefs.js
+++ /dev/null
@@ -1,136 +0,0 @@
-/**
- * Wrapper around brackets pref system to ensure preferences are stored in in one single object instead of using multiple keys.
- * This is to make it easy for the user who edits their preferences file to easily manage the potentially numerous lines of preferences generated by the persisting code-folding state.
- * @author Patrick Oladimeji
- * @date 3/22/14 20:39:53 PM
- */
-
-define(function (require, exports, module) {
- "use strict";
-
- var ProjectManager = brackets.getModule("project/ProjectManager"),
- PreferencesManager = brackets.getModule("preferences/PreferencesManager"),
- Strings = brackets.getModule("strings"),
- prefs = PreferencesManager.getExtensionPrefs("code-folding"),
- FOLDS_PREF_KEY = "code-folding.folds",
- // preference key strings are here for now since they are not used in any UI
- ENABLE_CODE_FOLDING = "Enable code folding",
- MIN_FOLD_SIZE = "Minimum fold size",
- SAVE_FOLD_STATES = "Save fold states",
- ALWAYS_USE_INDENT_FOLD = "Always use indent fold",
- HIDE_FOLD_BUTTONS = "Hide fold triangles",
- MAX_FOLD_LEVEL = "Max fold level",
- MAKE_SELECTIONS_FOLDABLE = "Makes selections foldable";
-
- //default preference values
- prefs.definePreference("enabled", "boolean", true,
- {name: ENABLE_CODE_FOLDING, description: Strings.DESCRIPTION_CODE_FOLDING_ENABLED});
- prefs.definePreference("minFoldSize", "number", 2,
- {name: MIN_FOLD_SIZE, description: Strings.DESCRIPTION_CODE_FOLDING_MIN_FOLD_SIZE});
- prefs.definePreference("saveFoldStates", "boolean", true,
- {name: SAVE_FOLD_STATES, description: Strings.DESCRIPTION_CODE_FOLDING_SAVE_FOLD_STATES});
- prefs.definePreference("alwaysUseIndentFold", "boolean", false,
- {name: ALWAYS_USE_INDENT_FOLD, description: Strings.DESCRIPTION_CODE_FOLDING_ALWAY_USE_INDENT_FOLD});
- prefs.definePreference("hideUntilMouseover", "boolean", false,
- {name: HIDE_FOLD_BUTTONS, description: Strings.DESCRIPTION_CODE_FOLDING_HIDE_UNTIL_MOUSEOVER});
- prefs.definePreference("maxFoldLevel", "number", 2,
- {name: MAX_FOLD_LEVEL, description: Strings.DESCRIPTION_CODE_FOLDING_MAX_FOLD_LEVEL});
- prefs.definePreference("makeSelectionsFoldable", "boolean", true,
- {name: MAKE_SELECTIONS_FOLDABLE, description: Strings.DESCRIPTION_CODE_FOLDING_MAKE_SELECTIONS_FOLDABLE});
-
- PreferencesManager.stateManager.definePreference(FOLDS_PREF_KEY, "object", {});
-
- /**
- * Simplifies the fold ranges into an array of pairs of numbers.
- * @param {!Object} folds the raw fold ranges indexed by line numbers
- * @return {Object} an object whose keys are line numbers and the values are array
- * of two 2-element arrays. First array contains [from.line, from.ch] and the second contains [to.line, to.ch]
- */
- function simplify(folds) {
- if (!folds) {
- return;
- }
- var res = {}, range;
- Object.keys(folds).forEach(function (line) {
- range = folds[line];
- res[line] = Array.isArray(range) ? range : [[range.from.line, range.from.ch], [range.to.line, range.to.ch]];
- });
- return res;
- }
-
- /**
- * Inflates the fold ranges stored as simplified numeric arrays. The inflation converts the data into
- * objects whose keys are line numbers and whose values are objects in the format {from: {line, ch}, to: {line, ch}}.
- * @param {Object} folds the simplified fold ranges
- * @return {Object} the converted fold ranges
- */
- function inflate(folds) {
- if (!folds) {
- return;
- }
- //transform the folds into objects with from and to properties
- var ranges = {}, obj;
- Object.keys(folds).forEach(function (line) {
- obj = folds[line];
- ranges[line] = {from: {line: obj[0][0], ch: obj[0][1]}, to: {line: obj[1][0], ch: obj[1][1]}};
- });
-
- return ranges;
- }
-
- /**
- * Returns a 'context' object for getting/setting project-specific view state preferences.
- * Similar to code in MultiRangeInlineEditor._getPrefsContext()...
- */
- function getViewStateContext() {
- var projectRoot = ProjectManager.getProjectRoot(); // note: null during unit tests!
- return { location : { scope: "user",
- layer: "project",
- layerID: projectRoot && projectRoot.fullPath } };
- }
-
- /**
- * Gets the line folds saved for the specified path.
- * @param {string} path the document path
- * @return {Object} the line folds for the document at the specified path
- */
- function getFolds(path) {
- var context = getViewStateContext();
- var folds = PreferencesManager.getViewState(FOLDS_PREF_KEY, context);
- return inflate(folds[path]);
- }
-
- /**
- * Saves the line folds for the specified path
- * @param {!string} path the path to the document
- * @param {Object} folds the fold ranges to save for the current document
- */
- function setFolds(path, folds) {
- var context = getViewStateContext();
- var allFolds = PreferencesManager.getViewState(FOLDS_PREF_KEY, context);
- allFolds[path] = simplify(folds);
- PreferencesManager.setViewState(FOLDS_PREF_KEY, allFolds, context);
- }
-
- /**
- * Get the code folding setting with the specified key from the store
- * @param {!string} key The key for the setting to retrieve
- * @return {string} the setting with the specified key
- */
- function getSetting(key) {
- return prefs.get(key);
- }
-
- /**
- * Clears all the saved line folds for all documents.
- */
- function clearAllFolds() {
- PreferencesManager.setViewState(FOLDS_PREF_KEY, {});
- }
-
- module.exports.getFolds = getFolds;
- module.exports.setFolds = setFolds;
- module.exports.getSetting = getSetting;
- module.exports.clearAllFolds = clearAllFolds;
- module.exports.prefsObject = prefs;
-});
diff --git a/src/extensions/default/CodeFolding/Prefs.ts b/src/extensions/default/CodeFolding/Prefs.ts
new file mode 100644
index 00000000000..a87a938914b
--- /dev/null
+++ b/src/extensions/default/CodeFolding/Prefs.ts
@@ -0,0 +1,128 @@
+/**
+ * Wrapper around brackets pref system to ensure preferences are stored in in one single object instead of using multiple keys.
+ * This is to make it easy for the user who edits their preferences file to easily manage the potentially numerous lines of preferences generated by the persisting code-folding state.
+ * @author Patrick Oladimeji
+ * @date 3/22/14 20:39:53 PM
+ */
+
+const ProjectManager = brackets.getModule("project/ProjectManager");
+const PreferencesManager = brackets.getModule("preferences/PreferencesManager");
+const Strings = brackets.getModule("strings");
+const prefs = PreferencesManager.getExtensionPrefs("code-folding");
+const FOLDS_PREF_KEY = "code-folding.folds";
+// preference key strings are here for now since they are not used in any UI
+const ENABLE_CODE_FOLDING = "Enable code folding";
+const MIN_FOLD_SIZE = "Minimum fold size";
+const SAVE_FOLD_STATES = "Save fold states";
+const ALWAYS_USE_INDENT_FOLD = "Always use indent fold";
+const HIDE_FOLD_BUTTONS = "Hide fold triangles";
+const MAX_FOLD_LEVEL = "Max fold level";
+const MAKE_SELECTIONS_FOLDABLE = "Makes selections foldable";
+
+// default preference values
+prefs.definePreference("enabled", "boolean", true,
+ {name: ENABLE_CODE_FOLDING, description: Strings.DESCRIPTION_CODE_FOLDING_ENABLED});
+prefs.definePreference("minFoldSize", "number", 2,
+ {name: MIN_FOLD_SIZE, description: Strings.DESCRIPTION_CODE_FOLDING_MIN_FOLD_SIZE});
+prefs.definePreference("saveFoldStates", "boolean", true,
+ {name: SAVE_FOLD_STATES, description: Strings.DESCRIPTION_CODE_FOLDING_SAVE_FOLD_STATES});
+prefs.definePreference("alwaysUseIndentFold", "boolean", false,
+ {name: ALWAYS_USE_INDENT_FOLD, description: Strings.DESCRIPTION_CODE_FOLDING_ALWAY_USE_INDENT_FOLD});
+prefs.definePreference("hideUntilMouseover", "boolean", false,
+ {name: HIDE_FOLD_BUTTONS, description: Strings.DESCRIPTION_CODE_FOLDING_HIDE_UNTIL_MOUSEOVER});
+prefs.definePreference("maxFoldLevel", "number", 2,
+ {name: MAX_FOLD_LEVEL, description: Strings.DESCRIPTION_CODE_FOLDING_MAX_FOLD_LEVEL});
+prefs.definePreference("makeSelectionsFoldable", "boolean", true,
+ {name: MAKE_SELECTIONS_FOLDABLE, description: Strings.DESCRIPTION_CODE_FOLDING_MAKE_SELECTIONS_FOLDABLE});
+
+PreferencesManager.stateManager.definePreference(FOLDS_PREF_KEY, "object", {});
+
+/**
+ * Simplifies the fold ranges into an array of pairs of numbers.
+ * @param {!Object} folds the raw fold ranges indexed by line numbers
+ * @return {Object} an object whose keys are line numbers and the values are array
+ * of two 2-element arrays. First array contains [from.line, from.ch] and the second contains [to.line, to.ch]
+ */
+function simplify(folds) {
+ if (!folds) {
+ return;
+ }
+ const res = {};
+ Object.keys(folds).forEach(function (line) {
+ const range = folds[line];
+ res[line] = Array.isArray(range) ? range : [[range.from.line, range.from.ch], [range.to.line, range.to.ch]];
+ });
+ return res;
+}
+
+/**
+ * Inflates the fold ranges stored as simplified numeric arrays. The inflation converts the data into
+ * objects whose keys are line numbers and whose values are objects in the format {from: {line, ch}, to: {line, ch}}.
+ * @param {Object} folds the simplified fold ranges
+ * @return {Object} the converted fold ranges
+ */
+function inflate(folds) {
+ if (!folds) {
+ return;
+ }
+ // transform the folds into objects with from and to properties
+ const ranges = {};
+ Object.keys(folds).forEach(function (line) {
+ const obj = folds[line];
+ ranges[line] = {from: {line: obj[0][0], ch: obj[0][1]}, to: {line: obj[1][0], ch: obj[1][1]}};
+ });
+
+ return ranges;
+}
+
+/**
+ * Returns a 'context' object for getting/setting project-specific view state preferences.
+ * Similar to code in MultiRangeInlineEditor._getPrefsContext()...
+ */
+function getViewStateContext() {
+ const projectRoot = ProjectManager.getProjectRoot(); // note: null during unit tests!
+ return { location : { scope: "user",
+ layer: "project",
+ layerID: projectRoot && projectRoot.fullPath } };
+}
+
+/**
+ * Gets the line folds saved for the specified path.
+ * @param {string} path the document path
+ * @return {Object} the line folds for the document at the specified path
+ */
+export function getFolds(path) {
+ const context = getViewStateContext();
+ const folds = PreferencesManager.getViewState(FOLDS_PREF_KEY, context);
+ return inflate(folds[path]);
+}
+
+/**
+ * Saves the line folds for the specified path
+ * @param {!string} path the path to the document
+ * @param {Object} folds the fold ranges to save for the current document
+ */
+export function setFolds(path, folds) {
+ const context = getViewStateContext();
+ const allFolds = PreferencesManager.getViewState(FOLDS_PREF_KEY, context);
+ allFolds[path] = simplify(folds);
+ PreferencesManager.setViewState(FOLDS_PREF_KEY, allFolds, context);
+}
+
+/**
+ * Get the code folding setting with the specified key from the store
+ * @param {!string} key The key for the setting to retrieve
+ * @return {string} the setting with the specified key
+ */
+export function getSetting(key) {
+ return prefs.get(key);
+}
+
+/**
+ * Clears all the saved line folds for all documents.
+ */
+export function clearAllFolds() {
+ PreferencesManager.setViewState(FOLDS_PREF_KEY, {});
+}
+
+export const prefsObject = prefs;
diff --git a/src/extensions/default/CodeFolding/main.js b/src/extensions/default/CodeFolding/main.js
deleted file mode 100644
index 627a3d2433d..00000000000
--- a/src/extensions/default/CodeFolding/main.js
+++ /dev/null
@@ -1,466 +0,0 @@
-/*
-* Copyright (c) 2013 Patrick Oladimeji. All rights reserved.
-*
-* Permission is hereby granted, free of charge, to any person obtaining a
-* copy of this software and associated documentation files (the "Software"),
-* to deal in the Software without restriction, including without limitation
-* the rights to use, copy, modify, merge, publish, distribute, sublicense,
-* and/or sell copies of the Software, and to permit persons to whom the
-* Software is furnished to do so, subject to the following conditions:
-*
-* The above copyright notice and this permission notice shall be included in
-* all copies or substantial portions of the Software.
-*
-* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-* DEALINGS IN THE SOFTWARE.
-*
-*/
-/**
- * Code folding extension for brackets
- * @author Patrick Oladimeji
- * @date 10/24/13 9:35:26 AM
- */
-
-define(function (require, exports, module) {
- "use strict";
-
- var CodeMirror = brackets.getModule("thirdparty/CodeMirror/lib/codemirror"),
- Strings = brackets.getModule("strings"),
- AppInit = brackets.getModule("utils/AppInit"),
- CommandManager = brackets.getModule("command/CommandManager"),
- DocumentManager = brackets.getModule("document/DocumentManager"),
- Editor = brackets.getModule("editor/Editor").Editor,
- EditorManager = brackets.getModule("editor/EditorManager"),
- ProjectManager = brackets.getModule("project/ProjectManager"),
- ViewStateManager = brackets.getModule("view/ViewStateManager"),
- KeyBindingManager = brackets.getModule("command/KeyBindingManager"),
- ExtensionUtils = brackets.getModule("utils/ExtensionUtils"),
- Menus = brackets.getModule("command/Menus"),
- prefs = require("Prefs"),
- COLLAPSE_ALL = "codefolding.collapse.all",
- COLLAPSE = "codefolding.collapse",
- EXPAND = "codefolding.expand",
- EXPAND_ALL = "codefolding.expand.all",
- GUTTER_NAME = "CodeMirror-foldgutter",
- CODE_FOLDING_GUTTER_PRIORITY = Editor.CODE_FOLDING_GUTTER_PRIORITY,
- codeFoldingMenuDivider = "codefolding.divider",
- collapseKey = "Ctrl-Alt-[",
- expandKey = "Ctrl-Alt-]",
- collapseAllKey = "Alt-1",
- expandAllKey = "Shift-Alt-1",
- collapseAllKeyMac = "Cmd-1",
- expandAllKeyMac = "Cmd-Shift-1";
-
- ExtensionUtils.loadStyleSheet(module, "main.less");
-
- // Load CodeMirror addons
- brackets.getModule(["thirdparty/CodeMirror/addon/fold/brace-fold"]);
- brackets.getModule(["thirdparty/CodeMirror/addon/fold/comment-fold"]);
- brackets.getModule(["thirdparty/CodeMirror/addon/fold/markdown-fold"]);
-
- // Still using slightly modified versions of the foldcode.js and foldgutter.js since we
- // need to modify the gutter click handler to take care of some collapse and expand features
- // e.g. collapsing all children when 'alt' key is pressed
- var foldGutter = require("foldhelpers/foldgutter"),
- foldCode = require("foldhelpers/foldcode"),
- indentFold = require("foldhelpers/indentFold"),
- handlebarsFold = require("foldhelpers/handlebarsFold"),
- selectionFold = require("foldhelpers/foldSelected");
-
-
- /** Set to true when init() has run; set back to false after deinit() has run */
- var _isInitialized = false;
-
- /** Used to keep track of files for which line folds have been restored.*/
-
- /**
- * Restores the linefolds in the editor using values fetched from the preference store
- * Checks the document to ensure that changes have not been made (e.g., in a different editor)
- * to invalidate the saved line folds.
- * Selection Folds are found by comparing the line folds in the preference store with the
- * selection ranges in the viewState of the current document. Any selection range in the view state
- * that is folded in the prefs will be folded. Unlike other fold range finder, the only validation
- * on selection folds is to check that they satisfy the minimum fold range.
- * @param {Editor} editor the editor whose saved line folds should be restored
- */
- function restoreLineFolds(editor) {
- /**
- * Checks if the range from and to Pos is the same as the selection start and end Pos
- * @param {Object} range {from, to} where from and to are CodeMirror.Pos objects
- * @param {Object} selection {start, end} where start and end are CodeMirror.Pos objects
- * @returns {Boolean} true if the range and selection span the same region and false otherwise
- */
- function rangeEqualsSelection(range, selection) {
- return range.from.line === selection.start.line && range.from.ch === selection.start.ch &&
- range.to.line === selection.end.line && range.to.ch === selection.end.ch;
- }
-
- /**
- * Checks if the range is equal to one of the selections in the viewState
- * @param {Object} range {from, to} where from and to are CodeMirror.Pos objects.
- * @param {Object} viewState The current editor's ViewState object
- * @returns {Boolean} true if the range is found in the list of selections or false if not.
- */
- function isInViewStateSelection(range, viewState) {
- if (!viewState || !viewState.selections) {
- return false;
- }
-
- return viewState.selections.some(function (selection) {
- return rangeEqualsSelection(range, selection);
- });
- }
-
- var saveFolds = prefs.getSetting("saveFoldStates");
-
- if (!editor || !saveFolds) {
- if (editor) {
- editor._codeMirror._lineFolds = editor._codeMirror._lineFolds || {};
- }
- return;
- }
-
- var cm = editor._codeMirror;
- var viewState = ViewStateManager.getViewState(editor.document.file);
- var path = editor.document.file.fullPath;
- var folds = cm._lineFolds || prefs.getFolds(path) || {};
-
- //separate out selection folds from non-selection folds
- var nonSelectionFolds = {}, selectionFolds = {}, range;
- Object.keys(folds).forEach(function (line) {
- range = folds[line];
- if (isInViewStateSelection(range, viewState)) {
- selectionFolds[line] = range;
- } else {
- nonSelectionFolds[line] = range;
- }
- });
- nonSelectionFolds = cm.getValidFolds(nonSelectionFolds);
- //add the selection folds
- Object.keys(selectionFolds).forEach(function (line) {
- nonSelectionFolds[line] = selectionFolds[line];
- });
- cm._lineFolds = nonSelectionFolds;
- prefs.setFolds(path, cm._lineFolds);
- Object.keys(cm._lineFolds).forEach(function (line) {
- cm.foldCode(Number(line), {range: cm._lineFolds[line]});
- });
- }
-
- /**
- * Saves the line folds in the editor using the preference storage
- * @param {Editor} editor the editor whose line folds should be saved
- */
- function saveLineFolds(editor) {
- var saveFolds = prefs.getSetting("saveFoldStates");
- if (!editor || !saveFolds) {
- return;
- }
- var folds = editor._codeMirror._lineFolds || {};
- var path = editor.document.file.fullPath;
- if (Object.keys(folds).length) {
- prefs.setFolds(path, folds);
- } else {
- prefs.setFolds(path, undefined);
- }
- }
-
- /**
- * Event handler for gutter click. Manages folding and unfolding code regions. If the Alt key
- * is pressed while clicking the fold gutter, child code fragments are also folded/unfolded
- * up to a level defined in the `maxFoldLevel' preference.
- * @param {!CodeMirror} cm the CodeMirror object
- * @param {number} line the line number for the clicked gutter
- * @param {string} gutter the name of the gutter element clicked
- * @param {!KeyboardEvent} event the underlying dom event triggered for the gutter click
- */
- function onGutterClick(cm, line, gutter, event) {
- var opts = cm.state.foldGutter.options, pos = CodeMirror.Pos(line);
- if (gutter !== opts.gutter) { return; }
- var range;
- var _lineFolds = cm._lineFolds;
- if (cm.isFolded(line)) {
- if (event.altKey) { // unfold code including children
- range = _lineFolds[line];
- CodeMirror.commands.unfoldAll(cm, range.from.line, range.to.line);
- } else {
- cm.unfoldCode(line, {range: _lineFolds[line]});
- }
- } else {
- if (event.altKey) {
- range = CodeMirror.fold.auto(cm, pos);
- if (range) {
- CodeMirror.commands.foldToLevel(cm, range.from.line, range.to.line);
- }
- } else {
- cm.foldCode(line);
- }
- }
- }
-
- /**
- * Collapses the code region nearest the current cursor position.
- * Nearest is found by searching from the current line and moving up the document until an
- * opening code-folding region is found.
- */
- function collapseCurrent() {
- var editor = EditorManager.getFocusedEditor();
- if (!editor) {
- return;
- }
- var cm = editor._codeMirror;
- var cursor = editor.getCursorPos(), i;
- // Move cursor up until a collapsible line is found
- for (i = cursor.line; i >= 0; i--) {
- if (cm.foldCode(i)) {
- editor.setCursorPos(i);
- return;
- }
- }
- }
-
- /**
- * Expands the code region at the current cursor position.
- */
- function expandCurrent() {
- var editor = EditorManager.getFocusedEditor();
- if (editor) {
- var cursor = editor.getCursorPos(), cm = editor._codeMirror;
- cm.unfoldCode(cursor.line);
- }
- }
-
- /**
- * Collapses all foldable regions in the current document. Folding is done up to a level 'n'
- * which is defined in the `maxFoldLevel` preference. Levels refer to fold heirarchies e.g., for the following
- * code fragment, the function is level 1, the if statement is level 2 and the forEach is level 3
- *
- * function sample() {
- * if (debug) {
- * logMessages.forEach(function (m) {
- * console.debug(m);
- * });
- * }
- * }
- */
- function collapseAll() {
- var editor = EditorManager.getFocusedEditor();
- if (editor) {
- var cm = editor._codeMirror;
- CodeMirror.commands.foldToLevel(cm);
- }
- }
-
- /**
- * Expands all folded regions in the current document
- */
- function expandAll() {
- var editor = EditorManager.getFocusedEditor();
- if (editor) {
- var cm = editor._codeMirror;
- CodeMirror.commands.unfoldAll(cm);
- }
- }
-
- function clearGutter(editor) {
- var cm = editor._codeMirror;
- var BLANK_GUTTER_CLASS = "CodeMirror-foldgutter-blank";
- editor.clearGutter(GUTTER_NAME);
- var blank = window.document.createElement("div");
- blank.className = BLANK_GUTTER_CLASS;
- var vp = cm.getViewport();
- cm.operation(function () {
- cm.eachLine(vp.from, vp.to, function (line) {
- editor.setGutterMarker(line.lineNo(), GUTTER_NAME, blank);
- });
- });
- }
-
- /**
- * Renders and sets up event listeners the code-folding gutter.
- * @param {Editor} editor the editor on which to initialise the fold gutter
- */
- function setupGutterEventListeners(editor) {
- var cm = editor._codeMirror;
- $(editor.getRootElement()).addClass("folding-enabled");
- cm.setOption("foldGutter", {onGutterClick: onGutterClick});
-
- $(cm.getGutterElement()).on({
- mouseenter: function () {
- if (prefs.getSetting("hideUntilMouseover")) {
- foldGutter.updateInViewport(cm);
- } else {
- $(editor.getRootElement()).addClass("over-gutter");
- }
- },
- mouseleave: function () {
- if (prefs.getSetting("hideUntilMouseover")) {
- clearGutter(editor);
- } else {
- $(editor.getRootElement()).removeClass("over-gutter");
- }
- }
- });
- }
-
- /**
- * Remove the fold gutter for a given CodeMirror instance.
- * @param {Editor} editor the editor instance whose gutter should be removed
- */
- function removeGutters(editor) {
- Editor.unregisterGutter(GUTTER_NAME);
- $(editor.getRootElement()).removeClass("folding-enabled");
- CodeMirror.defineOption("foldGutter", false, null);
- }
-
- /**
- * Add gutter and restore saved expand/collapse state.
- * @param {Editor} editor the editor instance where gutter should be added.
- */
- function enableFoldingInEditor(editor) {
- restoreLineFolds(editor);
- setupGutterEventListeners(editor);
- editor._codeMirror.refresh();
- }
-
- /**
- * When a brand new editor is seen, initialise fold-gutter and restore line folds in it.
- * Save line folds in departing editor in case it's getting closed.
- * @param {object} event the event object
- * @param {Editor} current the current editor
- * @param {Editor} previous the previous editor
- */
- function onActiveEditorChanged(event, current, previous) {
- if (current && !current._codeMirror._lineFolds) {
- enableFoldingInEditor(current);
- }
- if (previous) {
- saveLineFolds(previous);
- }
- }
-
- /**
- * Saves the line folds in the current full editor before it is closed.
- */
- function saveBeforeClose() {
- // We've already saved all other open editors when they go active->inactive
- saveLineFolds(EditorManager.getActiveEditor());
- }
-
- /**
- * Remove code-folding functionality
- */
- function deinit() {
- _isInitialized = false;
-
- KeyBindingManager.removeBinding(collapseKey);
- KeyBindingManager.removeBinding(expandKey);
- KeyBindingManager.removeBinding(collapseAllKey);
- KeyBindingManager.removeBinding(expandAllKey);
- KeyBindingManager.removeBinding(collapseAllKeyMac);
- KeyBindingManager.removeBinding(expandAllKeyMac);
-
- //remove menus
- Menus.getMenu(Menus.AppMenuBar.VIEW_MENU).removeMenuDivider(codeFoldingMenuDivider.id);
- Menus.getMenu(Menus.AppMenuBar.VIEW_MENU).removeMenuItem(COLLAPSE);
- Menus.getMenu(Menus.AppMenuBar.VIEW_MENU).removeMenuItem(EXPAND);
- Menus.getMenu(Menus.AppMenuBar.VIEW_MENU).removeMenuItem(COLLAPSE_ALL);
- Menus.getMenu(Menus.AppMenuBar.VIEW_MENU).removeMenuItem(EXPAND_ALL);
-
- EditorManager.off(".CodeFolding");
- DocumentManager.off(".CodeFolding");
- ProjectManager.off(".CodeFolding");
-
- // Remove gutter & revert collapsed sections in all currently open editors
- Editor.forEveryEditor(function (editor) {
- CodeMirror.commands.unfoldAll(editor._codeMirror);
- });
- removeGutters();
- }
-
- /**
- * Enable code-folding functionality
- */
- function init() {
- _isInitialized = true;
-
- foldCode.init();
- foldGutter.init();
-
- // Many CodeMirror modes specify which fold helper should be used for that language. For a few that
- // don't, we register helpers explicitly here. We also register a global helper for generic indent-based
- // folding, which cuts across all languages if enabled via preference.
- CodeMirror.registerGlobalHelper("fold", "selectionFold", function (mode, cm) {
- return prefs.getSetting("makeSelectionsFoldable");
- }, selectionFold);
- CodeMirror.registerGlobalHelper("fold", "indent", function (mode, cm) {
- return prefs.getSetting("alwaysUseIndentFold");
- }, indentFold);
-
- CodeMirror.registerHelper("fold", "handlebars", handlebarsFold);
- CodeMirror.registerHelper("fold", "htmlhandlebars", handlebarsFold);
- CodeMirror.registerHelper("fold", "htmlmixed", handlebarsFold);
-
- EditorManager.on("activeEditorChange.CodeFolding", onActiveEditorChanged);
- DocumentManager.on("documentRefreshed.CodeFolding", function (event, doc) {
- restoreLineFolds(doc._masterEditor);
- });
-
- ProjectManager.on("beforeProjectClose.CodeFolding beforeAppClose.CodeFolding", saveBeforeClose);
-
- //create menus
- codeFoldingMenuDivider = Menus.getMenu(Menus.AppMenuBar.VIEW_MENU).addMenuDivider();
- Menus.getMenu(Menus.AppMenuBar.VIEW_MENU).addMenuItem(COLLAPSE_ALL);
- Menus.getMenu(Menus.AppMenuBar.VIEW_MENU).addMenuItem(EXPAND_ALL);
- Menus.getMenu(Menus.AppMenuBar.VIEW_MENU).addMenuItem(COLLAPSE);
- Menus.getMenu(Menus.AppMenuBar.VIEW_MENU).addMenuItem(EXPAND);
-
- //register keybindings
- KeyBindingManager.addBinding(COLLAPSE_ALL, [ {key: collapseAllKey}, {key: collapseAllKeyMac, platform: "mac"} ]);
- KeyBindingManager.addBinding(EXPAND_ALL, [ {key: expandAllKey}, {key: expandAllKeyMac, platform: "mac"} ]);
- KeyBindingManager.addBinding(COLLAPSE, collapseKey);
- KeyBindingManager.addBinding(EXPAND, expandKey);
-
-
- // Add gutters & restore saved expand/collapse state in all currently open editors
- Editor.registerGutter(GUTTER_NAME, CODE_FOLDING_GUTTER_PRIORITY);
- Editor.forEveryEditor(function (editor) {
- enableFoldingInEditor(editor);
- });
- }
-
- /**
- * Register change listener for the preferences file.
- */
- function watchPrefsForChanges() {
- prefs.prefsObject.on("change", function (e, data) {
- if (data.ids.indexOf("enabled") > -1) {
- // Check if enabled state mismatches whether code-folding is actually initialized (can't assume
- // since preference change events can occur when the value hasn't really changed)
- var isEnabled = prefs.getSetting("enabled");
- if (isEnabled && !_isInitialized) {
- init();
- } else if (!isEnabled && _isInitialized) {
- deinit();
- }
- }
- });
- }
-
- AppInit.htmlReady(function () {
- CommandManager.register(Strings.COLLAPSE_ALL, COLLAPSE_ALL, collapseAll);
- CommandManager.register(Strings.EXPAND_ALL, EXPAND_ALL, expandAll);
- CommandManager.register(Strings.COLLAPSE_CURRENT, COLLAPSE, collapseCurrent);
- CommandManager.register(Strings.EXPAND_CURRENT, EXPAND, expandCurrent);
-
- if (prefs.getSetting("enabled")) {
- init();
- }
- watchPrefsForChanges();
- });
-});
diff --git a/src/extensions/default/CodeFolding/main.ts b/src/extensions/default/CodeFolding/main.ts
new file mode 100644
index 00000000000..f184f0d6a3d
--- /dev/null
+++ b/src/extensions/default/CodeFolding/main.ts
@@ -0,0 +1,505 @@
+/*
+* Copyright (c) 2013 Patrick Oladimeji. All rights reserved.
+*
+* Permission is hereby granted, free of charge, to any person obtaining a
+* copy of this software and associated documentation files (the "Software"),
+* to deal in the Software without restriction, including without limitation
+* the rights to use, copy, modify, merge, publish, distribute, sublicense,
+* and/or sell copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in
+* all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+* DEALINGS IN THE SOFTWARE.
+*
+*/
+/**
+ * Code folding extension for brackets
+ * @author Patrick Oladimeji
+ * @date 10/24/13 9:35:26 AM
+ */
+
+///
+
+import type { MenuItem } from "command/Menus";
+
+const CodeMirror = brackets.getModule("thirdparty/CodeMirror/lib/codemirror");
+const Strings = brackets.getModule("strings");
+const AppInit = brackets.getModule("utils/AppInit");
+const CommandManager = brackets.getModule("command/CommandManager");
+const DocumentManager = brackets.getModule("document/DocumentManager");
+const Editor = brackets.getModule("editor/Editor").Editor;
+const EditorManager = brackets.getModule("editor/EditorManager");
+const ProjectManager = brackets.getModule("project/ProjectManager");
+const ViewStateManager = brackets.getModule("view/ViewStateManager");
+const KeyBindingManager = brackets.getModule("command/KeyBindingManager");
+const ExtensionUtils = brackets.getModule("utils/ExtensionUtils");
+const Menus = brackets.getModule("command/Menus");
+import * as prefs from "Prefs";
+const COLLAPSE_ALL = "codefolding.collapse.all";
+const COLLAPSE = "codefolding.collapse";
+const EXPAND = "codefolding.expand";
+const EXPAND_ALL = "codefolding.expand.all";
+const GUTTER_NAME = "CodeMirror-foldgutter";
+const CODE_FOLDING_GUTTER_PRIORITY = Editor.CODE_FOLDING_GUTTER_PRIORITY;
+let codeFoldingMenuDivider: MenuItem;
+const collapseKey = "Ctrl-Alt-[";
+const expandKey = "Ctrl-Alt-]";
+const collapseAllKey = "Alt-1";
+const expandAllKey = "Shift-Alt-1";
+const collapseAllKeyMac = "Cmd-1";
+const expandAllKeyMac = "Cmd-Shift-1";
+
+ExtensionUtils.loadStyleSheet(module, "main.less");
+
+// Load CodeMirror addons
+brackets.getModule(["thirdparty/CodeMirror/addon/fold/brace-fold"]);
+brackets.getModule(["thirdparty/CodeMirror/addon/fold/comment-fold"]);
+brackets.getModule(["thirdparty/CodeMirror/addon/fold/markdown-fold"]);
+
+interface SimpleRange {
+ from: CodeMirror.Position;
+ to: CodeMirror.Position;
+}
+
+// Some methods are defined in foldhelpers folder.
+// TODO: we should try to use upstream code where possible.
+declare module "codemirror" {
+
+ interface Editor {
+ _lineFolds: Record;
+ }
+
+ interface Fold {
+ auto: (cm: Editor, pos: Position) => SimpleRange;
+ }
+ const fold: Fold;
+
+ // TODO: Not present in upstream types.
+ const registerGlobalHelper: (
+ type: string,
+ name: string,
+ predicate: (mode: any, cm: Editor) => void,
+ value: (cm: Editor, start: Position) => void
+ ) => void;
+
+ interface CommandActions {
+ unfoldAll: (cm: Editor, fromLine?: number, toline?: number) => void;
+ foldToLevel: (cm: Editor, fromLine?: number, toline?: number) => void;
+ }
+}
+
+// Still using slightly modified versions of the foldcode.js and foldgutter.js since we
+// need to modify the gutter click handler to take care of some collapse and expand features
+// e.g. collapsing all children when 'alt' key is pressed
+import * as foldGutter from "foldhelpers/foldgutter";
+import * as foldCode from "foldhelpers/foldcode";
+import * as indentFold from "foldhelpers/indentFold";
+import * as handlebarsFold from "foldhelpers/handlebarsFold";
+import * as selectionFold from "foldhelpers/foldSelected";
+
+
+/** Set to true when init() has run; set back to false after deinit() has run */
+let _isInitialized = false;
+
+/** Used to keep track of files for which line folds have been restored. */
+
+/**
+ * Restores the linefolds in the editor using values fetched from the preference store
+ * Checks the document to ensure that changes have not been made (e.g., in a different editor)
+ * to invalidate the saved line folds.
+ * Selection Folds are found by comparing the line folds in the preference store with the
+ * selection ranges in the viewState of the current document. Any selection range in the view state
+ * that is folded in the prefs will be folded. Unlike other fold range finder, the only validation
+ * on selection folds is to check that they satisfy the minimum fold range.
+ * @param {Editor} editor the editor whose saved line folds should be restored
+ */
+function restoreLineFolds(editor) {
+ /**
+ * Checks if the range from and to Pos is the same as the selection start and end Pos
+ * @param {Object} range {from, to} where from and to are CodeMirror.Pos objects
+ * @param {Object} selection {start, end} where start and end are CodeMirror.Pos objects
+ * @returns {Boolean} true if the range and selection span the same region and false otherwise
+ */
+ function rangeEqualsSelection(range, selection) {
+ return range.from.line === selection.start.line && range.from.ch === selection.start.ch &&
+ range.to.line === selection.end.line && range.to.ch === selection.end.ch;
+ }
+
+ /**
+ * Checks if the range is equal to one of the selections in the viewState
+ * @param {Object} range {from, to} where from and to are CodeMirror.Pos objects.
+ * @param {Object} viewState The current editor's ViewState object
+ * @returns {Boolean} true if the range is found in the list of selections or false if not.
+ */
+ function isInViewStateSelection(range, viewState) {
+ if (!viewState || !viewState.selections) {
+ return false;
+ }
+
+ return viewState.selections.some(function (selection) {
+ return rangeEqualsSelection(range, selection);
+ });
+ }
+
+ const saveFolds = prefs.getSetting("saveFoldStates");
+
+ if (!editor || !saveFolds) {
+ if (editor) {
+ editor._codeMirror._lineFolds = editor._codeMirror._lineFolds || {};
+ }
+ return;
+ }
+
+ const cm = editor._codeMirror;
+ const viewState = ViewStateManager.getViewState(editor.document.file);
+ const path = editor.document.file.fullPath;
+ const folds = cm._lineFolds || prefs.getFolds(path) || {};
+
+ // separate out selection folds from non-selection folds
+ let nonSelectionFolds = {};
+ const selectionFolds = {};
+ let range;
+ Object.keys(folds).forEach(function (line) {
+ range = folds[line];
+ if (isInViewStateSelection(range, viewState)) {
+ selectionFolds[line] = range;
+ } else {
+ nonSelectionFolds[line] = range;
+ }
+ });
+ nonSelectionFolds = cm.getValidFolds(nonSelectionFolds);
+ // add the selection folds
+ Object.keys(selectionFolds).forEach(function (line) {
+ nonSelectionFolds[line] = selectionFolds[line];
+ });
+ cm._lineFolds = nonSelectionFolds;
+ prefs.setFolds(path, cm._lineFolds);
+ Object.keys(cm._lineFolds).forEach(function (line) {
+ cm.foldCode(Number(line), {range: cm._lineFolds[line]});
+ });
+}
+
+/**
+ * Saves the line folds in the editor using the preference storage
+ * @param {Editor} editor the editor whose line folds should be saved
+ */
+function saveLineFolds(editor) {
+ const saveFolds = prefs.getSetting("saveFoldStates");
+ if (!editor || !saveFolds) {
+ return;
+ }
+ const folds = editor._codeMirror._lineFolds || {};
+ const path = editor.document.file.fullPath;
+ if (Object.keys(folds).length) {
+ prefs.setFolds(path, folds);
+ } else {
+ prefs.setFolds(path, undefined);
+ }
+}
+
+/**
+ * Event handler for gutter click. Manages folding and unfolding code regions. If the Alt key
+ * is pressed while clicking the fold gutter, child code fragments are also folded/unfolded
+ * up to a level defined in the `maxFoldLevel' preference.
+ * @param {!CodeMirror} cm the CodeMirror object
+ * @param {number} line the line number for the clicked gutter
+ * @param {string} gutter the name of the gutter element clicked
+ * @param {!KeyboardEvent} event the underlying dom event triggered for the gutter click
+ */
+function onGutterClick(cm, line, gutter, event) {
+ const opts = cm.state.foldGutter.options;
+ const pos = CodeMirror.Pos(line);
+ if (gutter !== opts.gutter) { return; }
+
+ const _lineFolds = cm._lineFolds;
+ if (cm.isFolded(line)) {
+ if (event.altKey) { // unfold code including children
+ const range = _lineFolds[line];
+ CodeMirror.commands.unfoldAll(cm, range.from.line, range.to.line);
+ } else {
+ cm.unfoldCode(line, {range: _lineFolds[line]});
+ }
+ } else {
+ if (event.altKey) {
+ const range = CodeMirror.fold.auto(cm, pos);
+ if (range) {
+ CodeMirror.commands.foldToLevel(cm, range.from.line, range.to.line);
+ }
+ } else {
+ cm.foldCode(line);
+ }
+ }
+}
+
+/**
+ * Collapses the code region nearest the current cursor position.
+ * Nearest is found by searching from the current line and moving up the document until an
+ * opening code-folding region is found.
+ */
+function collapseCurrent() {
+ const editor = EditorManager.getFocusedEditor();
+ if (!editor) {
+ return;
+ }
+ const cm = editor._codeMirror;
+ const cursor = editor.getCursorPos();
+ // Move cursor up until a collapsible line is found
+ for (let i = cursor.line; i >= 0; i--) {
+ if (cm.foldCode(i)) {
+ editor.setCursorPos(i);
+ return;
+ }
+ }
+}
+
+/**
+ * Expands the code region at the current cursor position.
+ */
+function expandCurrent() {
+ const editor = EditorManager.getFocusedEditor();
+ if (editor) {
+ const cursor = editor.getCursorPos();
+ const cm = editor._codeMirror;
+ cm.unfoldCode(cursor.line);
+ }
+}
+
+/**
+ * Collapses all foldable regions in the current document. Folding is done up to a level 'n'
+ * which is defined in the `maxFoldLevel` preference. Levels refer to fold heirarchies e.g., for the following
+ * code fragment, the function is level 1, the if statement is level 2 and the forEach is level 3
+ *
+ * function sample() {
+ * if (debug) {
+ * logMessages.forEach(function (m) {
+ * console.debug(m);
+ * });
+ * }
+ * }
+ */
+function collapseAll() {
+ const editor = EditorManager.getFocusedEditor();
+ if (editor) {
+ const cm = editor._codeMirror;
+ CodeMirror.commands.foldToLevel(cm);
+ }
+}
+
+/**
+ * Expands all folded regions in the current document
+ */
+function expandAll() {
+ const editor = EditorManager.getFocusedEditor();
+ if (editor) {
+ const cm = editor._codeMirror;
+ CodeMirror.commands.unfoldAll(cm);
+ }
+}
+
+function clearGutter(editor) {
+ const cm = editor._codeMirror;
+ const BLANK_GUTTER_CLASS = "CodeMirror-foldgutter-blank";
+ editor.clearGutter(GUTTER_NAME);
+ const blank = window.document.createElement("div");
+ blank.className = BLANK_GUTTER_CLASS;
+ const vp = cm.getViewport();
+ cm.operation(function () {
+ cm.eachLine(vp.from, vp.to, function (line) {
+ editor.setGutterMarker(line.lineNo(), GUTTER_NAME, blank);
+ });
+ });
+}
+
+/**
+ * Renders and sets up event listeners the code-folding gutter.
+ * @param {Editor} editor the editor on which to initialise the fold gutter
+ */
+function setupGutterEventListeners(editor) {
+ const cm = editor._codeMirror;
+ $(editor.getRootElement()).addClass("folding-enabled");
+ cm.setOption("foldGutter", {onGutterClick: onGutterClick});
+
+ $(cm.getGutterElement()).on({
+ mouseenter: function () {
+ if (prefs.getSetting("hideUntilMouseover")) {
+ foldGutter.updateInViewport(cm);
+ } else {
+ $(editor.getRootElement()).addClass("over-gutter");
+ }
+ },
+ mouseleave: function () {
+ if (prefs.getSetting("hideUntilMouseover")) {
+ clearGutter(editor);
+ } else {
+ $(editor.getRootElement()).removeClass("over-gutter");
+ }
+ }
+ });
+}
+
+/**
+ * Remove gutter & revert collapsed sections in all currently open editors
+ */
+function removeGutters() {
+ Editor.forEveryEditor(function (editor) {
+ CodeMirror.commands.unfoldAll(editor._codeMirror);
+ });
+
+ Editor.unregisterGutter(GUTTER_NAME);
+
+ Editor.forEveryEditor(function (editor) {
+ $(editor.getRootElement()).removeClass("folding-enabled");
+ });
+
+ CodeMirror.defineOption("foldGutter", false, null as any);
+}
+
+/**
+ * Add gutter and restore saved expand/collapse state.
+ * @param {Editor} editor the editor instance where gutter should be added.
+ */
+function enableFoldingInEditor(editor) {
+ restoreLineFolds(editor);
+ setupGutterEventListeners(editor);
+ editor._codeMirror.refresh();
+}
+
+/**
+ * When a brand new editor is seen, initialise fold-gutter and restore line folds in it.
+ * Save line folds in departing editor in case it's getting closed.
+ * @param {object} event the event object
+ * @param {Editor} current the current editor
+ * @param {Editor} previous the previous editor
+ */
+function onActiveEditorChanged(event, current, previous) {
+ if (current && !current._codeMirror._lineFolds) {
+ enableFoldingInEditor(current);
+ }
+ if (previous) {
+ saveLineFolds(previous);
+ }
+}
+
+/**
+ * Saves the line folds in the current full editor before it is closed.
+ */
+function saveBeforeClose() {
+ // We've already saved all other open editors when they go active->inactive
+ saveLineFolds(EditorManager.getActiveEditor());
+}
+
+/**
+ * Remove code-folding functionality
+ */
+function deinit() {
+ _isInitialized = false;
+
+ KeyBindingManager.removeBinding(collapseKey);
+ KeyBindingManager.removeBinding(expandKey);
+ KeyBindingManager.removeBinding(collapseAllKey);
+ KeyBindingManager.removeBinding(expandAllKey);
+ KeyBindingManager.removeBinding(collapseAllKeyMac);
+ KeyBindingManager.removeBinding(expandAllKeyMac);
+
+ // remove menus
+ Menus.getMenu(Menus.AppMenuBar.VIEW_MENU).removeMenuDivider(codeFoldingMenuDivider.id);
+ Menus.getMenu(Menus.AppMenuBar.VIEW_MENU).removeMenuItem(COLLAPSE);
+ Menus.getMenu(Menus.AppMenuBar.VIEW_MENU).removeMenuItem(EXPAND);
+ Menus.getMenu(Menus.AppMenuBar.VIEW_MENU).removeMenuItem(COLLAPSE_ALL);
+ Menus.getMenu(Menus.AppMenuBar.VIEW_MENU).removeMenuItem(EXPAND_ALL);
+
+ EditorManager.off(".CodeFolding");
+ DocumentManager.off(".CodeFolding");
+ ProjectManager.off(".CodeFolding");
+
+ removeGutters();
+}
+
+/**
+ * Enable code-folding functionality
+ */
+function init() {
+ _isInitialized = true;
+
+ foldCode.init();
+ foldGutter.init();
+
+ // Many CodeMirror modes specify which fold helper should be used for that language. For a few that
+ // don't, we register helpers explicitly here. We also register a global helper for generic indent-based
+ // folding, which cuts across all languages if enabled via preference.
+ CodeMirror.registerGlobalHelper("fold", "selectionFold", function (mode, cm) {
+ return prefs.getSetting("makeSelectionsFoldable");
+ }, selectionFold);
+ CodeMirror.registerGlobalHelper("fold", "indent", function (mode, cm) {
+ return prefs.getSetting("alwaysUseIndentFold");
+ }, indentFold);
+
+ CodeMirror.registerHelper("fold", "handlebars", handlebarsFold);
+ CodeMirror.registerHelper("fold", "htmlhandlebars", handlebarsFold);
+ CodeMirror.registerHelper("fold", "htmlmixed", handlebarsFold);
+
+ EditorManager.on("activeEditorChange.CodeFolding", onActiveEditorChanged);
+ DocumentManager.on("documentRefreshed.CodeFolding", function (event, doc) {
+ restoreLineFolds(doc._masterEditor);
+ });
+
+ ProjectManager.on("beforeProjectClose.CodeFolding beforeAppClose.CodeFolding", saveBeforeClose);
+
+ // create menus
+ codeFoldingMenuDivider = Menus.getMenu(Menus.AppMenuBar.VIEW_MENU).addMenuDivider()!;
+ Menus.getMenu(Menus.AppMenuBar.VIEW_MENU).addMenuItem(COLLAPSE_ALL);
+ Menus.getMenu(Menus.AppMenuBar.VIEW_MENU).addMenuItem(EXPAND_ALL);
+ Menus.getMenu(Menus.AppMenuBar.VIEW_MENU).addMenuItem(COLLAPSE);
+ Menus.getMenu(Menus.AppMenuBar.VIEW_MENU).addMenuItem(EXPAND);
+
+ // register keybindings
+ KeyBindingManager.addBinding(COLLAPSE_ALL, [ {key: collapseAllKey}, {key: collapseAllKeyMac, platform: "mac"} ]);
+ KeyBindingManager.addBinding(EXPAND_ALL, [ {key: expandAllKey}, {key: expandAllKeyMac, platform: "mac"} ]);
+ KeyBindingManager.addBinding(COLLAPSE, collapseKey);
+ KeyBindingManager.addBinding(EXPAND, expandKey);
+
+
+ // Add gutters & restore saved expand/collapse state in all currently open editors
+ Editor.registerGutter(GUTTER_NAME, CODE_FOLDING_GUTTER_PRIORITY);
+ Editor.forEveryEditor(function (editor) {
+ enableFoldingInEditor(editor);
+ });
+}
+
+/**
+ * Register change listener for the preferences file.
+ */
+function watchPrefsForChanges() {
+ prefs.prefsObject.on("change", function (e, data) {
+ if (data.ids.indexOf("enabled") > -1) {
+ // Check if enabled state mismatches whether code-folding is actually initialized (can't assume
+ // since preference change events can occur when the value hasn't really changed)
+ const isEnabled = prefs.getSetting("enabled");
+ if (isEnabled && !_isInitialized) {
+ init();
+ } else if (!isEnabled && _isInitialized) {
+ deinit();
+ }
+ }
+ });
+}
+
+AppInit.htmlReady(function () {
+ CommandManager.register(Strings.COLLAPSE_ALL, COLLAPSE_ALL, collapseAll);
+ CommandManager.register(Strings.EXPAND_ALL, EXPAND_ALL, expandAll);
+ CommandManager.register(Strings.COLLAPSE_CURRENT, COLLAPSE, collapseCurrent);
+ CommandManager.register(Strings.EXPAND_CURRENT, EXPAND, expandCurrent);
+
+ if (prefs.getSetting("enabled")) {
+ init();
+ }
+ watchPrefsForChanges();
+});
diff --git a/src/extensions/default/CodeFolding/unittests.js b/src/extensions/default/CodeFolding/unittests.js
index 19c6f3ce93b..b1fade26b99 100644
--- a/src/extensions/default/CodeFolding/unittests.js
+++ b/src/extensions/default/CodeFolding/unittests.js
@@ -111,6 +111,14 @@ define(function (require, exports, module) {
* Closes the test window
*/
function tearDown() {
+ testWindow = null;
+ EditorManager = null;
+ DocumentManager = null;
+ PreferencesManager = null;
+ CommandManager = null;
+
+ prefs = null;
+
SpecRunnerUtils.closeTestWindow();
}
@@ -254,21 +262,29 @@ define(function (require, exports, module) {
}, "Fold markers now visible in gutter", 500);
}
- beforeEach(function () {
- setup();
- });
-
- afterEach(function () {
- testWindow.closeAllFiles();
- tearDown();
- });
-
Object.keys(testFilesSpec).forEach(function (file) {
var testFilePath = testFilesSpec[file].filePath;
var foldableLines = testFilesSpec[file].foldableLines;
var testFileSpec = testFilesSpec[file];
describe(file + " - Editor/Gutter", function () {
+ beforeFirst(function () {
+ setup();
+ });
+
+ afterLast(function () {
+ tearDown();
+ });
+
beforeEach(function () {
+ // default preference values
+ prefs.set("enabled", true);
+ prefs.set("minFoldSize", 2);
+ prefs.set("saveFoldStates", true);
+ prefs.set("alwaysUseIndentFold", false);
+ prefs.set("hideUntilMouseover", false);
+ prefs.set("maxFoldLevel", 2);
+ prefs.set("makeSelectionsFoldable", true);
+
runs(function () {
openTestFile(testFilePath);
});
diff --git a/src/extensions/default/quadre-whitespaces/nobreakspace.ts b/src/extensions/default/quadre-whitespaces/nobreakspace.ts
index d4de019d499..6c708cb309c 100644
--- a/src/extensions/default/quadre-whitespaces/nobreakspace.ts
+++ b/src/extensions/default/quadre-whitespaces/nobreakspace.ts
@@ -2,7 +2,7 @@ const CodeMirror = brackets.getModule("thirdparty/CodeMirror/lib/codemirror");
CodeMirror.defineOption("showNoBreakSpace", false, function (cm, val, prev) {
// eslint-disable-next-line eqeqeq
- if (prev == CodeMirror.Init) { // tslint:disable-line:triple-equals
+ if (prev == (CodeMirror as any).Init) { // tslint:disable-line:triple-equals
prev = false;
}
if (prev && !val) {
diff --git a/src/types/index.ts b/src/types/index.ts
index 24850d97439..38c6ac6daec 100644
--- a/src/types/index.ts
+++ b/src/types/index.ts
@@ -6,6 +6,7 @@ import * as KeyBindingManager from "command/KeyBindingManager";
import * as Menus from "command/Menus";
import * as DocumentManager from "document/DocumentManager";
import * as CodeHintManager from "editor/CodeHintManager";
+import * as Editor from "editor/Editor";
import * as EditorManager from "editor/EditorManager";
import * as InlineWidget from "editor/InlineWidget";
import * as MultiRangeInlineEditor from "editor/MultiRangeInlineEditor";
@@ -48,6 +49,7 @@ import * as StringMatch from "utils/StringMatch";
import * as StringUtils from "utils/StringUtils";
import * as TokenUtils from "utils/TokenUtils";
import * as ViewUtils from "utils/ViewUtils";
+import * as ViewStateManager from "view/ViewStateManager";
import * as DefaultDialogs from "widgets/DefaultDialogs";
import * as Dialogs from "widgets/Dialogs";
import * as InlineMenu from "widgets/InlineMenu";
@@ -56,7 +58,7 @@ import * as Strings from "strings";
import * as Acorn from "thirdparty/acorn/acorn";
import * as AcornLoose from "thirdparty/acorn/acorn_loose";
import * as ASTWalker from "thirdparty/acorn/walk";
-import * as CodeMirror from "thirdparty/CodeMirror/lib/codemirror";
+import * as CodeMirror from "codemirror";
import * as _ from "lodash";
import * as Mustache from "thirdparty/mustache/mustache";
import * as PathUtils from "thirdparty/path-utils/path-utils";
@@ -85,8 +87,9 @@ declare global {
: T extends "command/Commands" ? typeof Commands
: T extends "command/KeyBindingManager" ? typeof KeyBindingManager
: T extends "command/Menus" ? typeof Menus
- : T extends "document/DocumentManager" ? typeof DocumentManager
+ : T extends "document/DocumentManager" ? typeof DocumentManager & EventDispatcher.DispatcherEvents
: T extends "editor/CodeHintManager" ? typeof CodeHintManager
+ : T extends "editor/Editor" ? typeof Editor
: T extends "editor/EditorManager" ? typeof EditorManager & EventDispatcher.DispatcherEvents
: T extends "editor/InlineWidget" ? typeof InlineWidget
: T extends "editor/MultiRangeInlineEditor" ? typeof MultiRangeInlineEditor
@@ -131,6 +134,7 @@ declare global {
: T extends "utils/StringUtils" ? typeof StringUtils
: T extends "utils/TokenUtils" ? typeof TokenUtils
: T extends "utils/ViewUtils" ? typeof ViewUtils
+ : T extends "view/ViewStateManager" ? typeof ViewStateManager
: T extends "widgets/DefaultDialogs" ? typeof DefaultDialogs
: T extends "widgets/Dialogs" ? typeof Dialogs
: T extends "widgets/InlineMenu" ? typeof InlineMenu