diff --git a/docs/API-Reference/view/PanelView.md b/docs/API-Reference/view/PanelView.md
index 0d92aa343..f2a78088f 100644
--- a/docs/API-Reference/view/PanelView.md
+++ b/docs/API-Reference/view/PanelView.md
@@ -3,13 +3,144 @@
const PanelView = brackets.getModule("view/PanelView")
```
+
+
+## \_panelMap : Object.<string, Panel>
+Maps panel ID to Panel instance
+
+**Kind**: global variable
+
+
+## \_$container : jQueryObject
+The single container wrapping all bottom panels
+
+**Kind**: global variable
+
+
+## \_$tabBar : jQueryObject
+The tab bar inside the container
+
+**Kind**: global variable
+
+
+## \_$tabsOverflow : jQueryObject
+Scrollable area holding the tab elements
+
+**Kind**: global variable
+
+
+## \_openIds : Array.<string>
+Ordered list of currently open (tabbed) panel IDs
+
+**Kind**: global variable
+
+
+## \_activeId : string \| null
+The panel ID of the currently visible (active) tab
+
+**Kind**: global variable
+
+
+## \_isMaximized : boolean
+Whether the bottom panel is currently maximized
+
+**Kind**: global variable
+
+
+## \_preMaximizeHeight : number \| null
+The panel height before maximize, for restore
+
+**Kind**: global variable
+
+
+## \_$editorHolder : jQueryObject
+The editor holder element, passed from WorkspaceManager
+
+**Kind**: global variable
+
+
+## \_recomputeLayout : function
+recomputeLayout callback from WorkspaceManager
+
+**Kind**: global variable
+
+
+## \_defaultPanelId : string \| null
+The default/quick-access panel ID
+
+**Kind**: global variable
+
+
+## \_$addBtn : jQueryObject
+The "+" button inside the tab overflow area
+
+**Kind**: global variable
+
+
+## \_$overflowBtn : jQueryObject
+Overflow dropdown button
+
+**Kind**: global variable
+
+
+## \_overflowDropdown : DropdownButton.DropdownButton
+**Kind**: global variable
+
+
+## EVENT\_PANEL\_HIDDEN : string
+Event when panel is hidden
+
+**Kind**: global constant
+
+
+## EVENT\_PANEL\_SHOWN : string
+Event when panel is shown
+
+**Kind**: global constant
+
+
+## PANEL\_TYPE\_BOTTOM\_PANEL : string
+type for bottom panel
+
+**Kind**: global constant
+
+
+## MAXIMIZE\_THRESHOLD : number
+Pixel threshold for detecting near-maximize state during resize.
+If the editor holder height is within this many pixels of zero, the
+panel is treated as maximized. Keeps the maximize icon responsive
+during drag without being overly sensitive.
+
+**Kind**: global constant
+
+
+## MIN\_PANEL\_HEIGHT : number
+Minimum panel height (matches Resizer minSize) used as a floor
+when computing a sensible restore height.
+
+**Kind**: global constant
+
+
+## PREF\_BOTTOM\_PANEL\_MAXIMIZED
+Preference key for persisting the maximize state across reloads.
+
+**Kind**: global constant
-## Panel
-**Kind**: global class
+## Panel($panel, id, [title], [options])
+**Kind**: global function
+
+| Param | Type | Description |
+| --- | --- | --- |
+| $panel | jQueryObject | |
+| id | string | |
+| [title] | string | |
+| [options] | Object | |
+| [options.iconClass] | string | FontAwesome class string (e.g. "fa-solid fa-terminal"). |
+| [options.iconSvg] | string | Path to an SVG icon (e.g. "styles/images/icon.svg"). |
+
-* [Panel](#Panel)
- * [new Panel($panel, id, [title])](#new_Panel_new)
+* [Panel($panel, id, [title], [options])](#Panel)
* [.$panel](#Panel+$panel) : jQueryObject
* [.isVisible()](#Panel+isVisible) ⇒ boolean
* [.registerCanBeShownHandler(canShowHandlerFn)](#Panel+registerCanBeShownHandler) ⇒ boolean
@@ -24,18 +155,6 @@ const PanelView = brackets.getModule("view/PanelView")
* [.destroy()](#Panel+destroy)
* [.getPanelType()](#Panel+getPanelType) ⇒ string
-
-
-### new Panel($panel, id, [title])
-Represents a panel below the editor area (a child of ".content").
-
-
-| Param | Type | Description |
-| --- | --- | --- |
-| $panel | jQueryObject | The entire panel, including any chrome, already in the DOM. |
-| id | string | Unique panel identifier. |
-| [title] | string | Optional display title for the tab bar. |
-
### panel.$panel : jQueryObject
@@ -144,118 +263,6 @@ After calling this, the Panel instance should not be reused.
gets the Panel's type
**Kind**: instance method of [Panel](#Panel)
-
-
-## \_panelMap : Object.<string, Panel>
-Maps panel ID to Panel instance
-
-**Kind**: global variable
-
-
-## \_$container : jQueryObject
-The single container wrapping all bottom panels
-
-**Kind**: global variable
-
-
-## \_$tabBar : jQueryObject
-The tab bar inside the container
-
-**Kind**: global variable
-
-
-## \_$tabsOverflow : jQueryObject
-Scrollable area holding the tab elements
-
-**Kind**: global variable
-
-
-## \_openIds : Array.<string>
-Ordered list of currently open (tabbed) panel IDs
-
-**Kind**: global variable
-
-
-## \_activeId : string \| null
-The panel ID of the currently visible (active) tab
-
-**Kind**: global variable
-
-
-## \_isMaximized : boolean
-Whether the bottom panel is currently maximized
-
-**Kind**: global variable
-
-
-## \_preMaximizeHeight : number \| null
-The panel height before maximize, for restore
-
-**Kind**: global variable
-
-
-## \_$editorHolder : jQueryObject
-The editor holder element, passed from WorkspaceManager
-
-**Kind**: global variable
-
-
-## \_recomputeLayout : function
-recomputeLayout callback from WorkspaceManager
-
-**Kind**: global variable
-
-
-## \_defaultPanelId : string \| null
-The default/quick-access panel ID
-
-**Kind**: global variable
-
-
-## \_$addBtn : jQueryObject
-The "+" button inside the tab overflow area
-
-**Kind**: global variable
-
-
-## EVENT\_PANEL\_HIDDEN : string
-Event when panel is hidden
-
-**Kind**: global constant
-
-
-## EVENT\_PANEL\_SHOWN : string
-Event when panel is shown
-
-**Kind**: global constant
-
-
-## PANEL\_TYPE\_BOTTOM\_PANEL : string
-type for bottom panel
-
-**Kind**: global constant
-
-
-## MAXIMIZE\_THRESHOLD : number
-Pixel threshold for detecting near-maximize state during resize.
-If the editor holder height is within this many pixels of zero, the
-panel is treated as maximized. Keeps the maximize icon responsive
-during drag without being overly sensitive.
-
-**Kind**: global constant
-
-
-## MIN\_PANEL\_HEIGHT : number
-Minimum panel height (matches Resizer minSize) used as a floor
-when computing a sensible restore height.
-
-**Kind**: global constant
-
-
-## PREF\_BOTTOM\_PANEL\_MAXIMIZED
-Preference key for persisting the maximize state across reloads.
-
-**Kind**: global constant
## init($container, $tabBar, $tabsOverflow, $editorHolder, recomputeLayoutFn, defaultPanelId)
diff --git a/docs/API-Reference/view/WorkspaceManager.md b/docs/API-Reference/view/WorkspaceManager.md
index f99f7f80a..539e7ec2c 100644
--- a/docs/API-Reference/view/WorkspaceManager.md
+++ b/docs/API-Reference/view/WorkspaceManager.md
@@ -28,7 +28,7 @@ Events:
* [.EVENT_WORKSPACE_UPDATE_LAYOUT](#module_view/WorkspaceManager..EVENT_WORKSPACE_UPDATE_LAYOUT)
* [.EVENT_WORKSPACE_PANEL_SHOWN](#module_view/WorkspaceManager..EVENT_WORKSPACE_PANEL_SHOWN)
* [.EVENT_WORKSPACE_PANEL_HIDDEN](#module_view/WorkspaceManager..EVENT_WORKSPACE_PANEL_HIDDEN)
- * [.createBottomPanel(id, $panel, [minSize], [title])](#module_view/WorkspaceManager..createBottomPanel) ⇒ Panel
+ * [.createBottomPanel(id, $panel, [minSize], [title], [options])](#module_view/WorkspaceManager..createBottomPanel) ⇒ Panel
* [.destroyBottomPanel(id)](#module_view/WorkspaceManager..destroyBottomPanel)
* [.createPluginPanel(id, $panel, [minSize], $toolbarIcon, [initialSize])](#module_view/WorkspaceManager..createPluginPanel) ⇒ Panel
* [.getAllPanelIDs()](#module_view/WorkspaceManager..getAllPanelIDs) ⇒ Array
@@ -89,7 +89,7 @@ Event triggered when a panel is hidden.
**Kind**: inner constant of [view/WorkspaceManager](#module_view/WorkspaceManager)
-### view/WorkspaceManager.createBottomPanel(id, $panel, [minSize], [title]) ⇒ Panel
+### view/WorkspaceManager.createBottomPanel(id, $panel, [minSize], [title], [options]) ⇒ Panel
Creates a new resizable panel beneath the editor area and above the status bar footer. Panel is initially invisible.
The panel's size & visibility are automatically saved & restored as a view-state preference.
@@ -101,6 +101,7 @@ The panel's size & visibility are automatically saved & restored as a view-state
| $panel | jQueryObject | DOM content to use as the panel. Need not be in the document yet. Must have an id attribute, for use as a preferences key. |
| [minSize] | number | @deprecated No longer used. Pass `undefined`. |
| [title] | string | Display title shown in the bottom panel tab bar. |
+| [options] | Object | Optional settings: - {string} iconClass FontAwesome class string (e.g. "fa-solid fa-terminal"). - {string} iconSvg Path to an SVG icon (e.g. "styles/images/icon.svg"). |
diff --git a/src/nls/root/strings.js b/src/nls/root/strings.js
index 0b8ac5a1b..4a75bee35 100644
--- a/src/nls/root/strings.js
+++ b/src/nls/root/strings.js
@@ -639,6 +639,9 @@ define({
"FIND_IN_FILES_SEARCHING": "Searching Files\u2026",
"FIND_IN_FILES_SEARCHING_IN": "In {0}",
"FIND_IN_FILES_INDEXING_PROGRESS": "Indexing {0} of {1} files for Instant Search\u2026",
+ "FIND_IN_FILES_CACHE_LIMIT_TITLE": "File Indexing Suspended",
+ "FIND_IN_FILES_CACHE_LIMIT_MSG": "The project file cache has reached {0} MB. Indexing has been suspended to prevent high memory usage. Find in Files is disabled for this project. To reduce indexing size, add folders with large or generated files to .gitignore.",
+ "DESCRIPTION_MAX_FILE_CACHE_SIZE_MB": "Maximum size in MB for the instant search file cache.",
"REPLACE_IN_FILES_ERRORS_TITLE": "Replace Errors",
"REPLACE_IN_FILES_ERRORS": "The following files weren't modified because they changed after the search or couldn't be written.",
diff --git a/src/search/FindInFiles.js b/src/search/FindInFiles.js
index 987f71138..f659e57f1 100644
--- a/src/search/FindInFiles.js
+++ b/src/search/FindInFiles.js
@@ -43,10 +43,18 @@ define(function (require, exports, module) {
PerfUtils = require("utils/PerfUtils"),
FindUtils = require("search/FindUtils"),
Metrics = require("utils/Metrics"),
- IndexingWorker = require("worker/IndexingWorker");
+ IndexingWorker = require("worker/IndexingWorker"),
+ PreferencesManager = require("preferences/PreferencesManager"),
+ NotificationUI = require("widgets/NotificationUI"),
+ Strings = require("strings");
let projectIndexingComplete = false;
+ var MAX_CACHE_SIZE_MB_PREF = "maxFileCacheSizeMB";
+ PreferencesManager.definePreference(MAX_CACHE_SIZE_MB_PREF, "number", 1024, {
+ description: Strings.DESCRIPTION_MAX_FILE_CACHE_SIZE_MB
+ });
+
IndexingWorker.loadScriptInWorker(`${Phoenix.baseURL}search/worker/search.js`);
IndexingWorker.on(IndexingWorker.EVENT_CRAWL_COMPLETE, function (_evt, params) {
@@ -125,13 +133,40 @@ define(function (require, exports, module) {
let numFiles = data.numFilesCached,
cacheSize = data.cacheSizeBytes,
crawlTime = data.crawlTimeMs;
- projectIndexingComplete = true;
console.log(`file indexing worker cache complete: ${numFiles} files, size: ${cacheSize} B in ${crawlTime}ms`);
if (/\/test\/SpecRunner\.html$/.test(window.location.pathname)) {
// Ignore the event in the SpecRunner window
return;
}
+ if (data.aborted) {
+ // Cache limit reached — Find in Files is disabled for this project
+ projectIndexingComplete = false;
+ FindUtils.setIndexingSuspended(true);
+ var cacheSizeMB = Math.round(cacheSize / (1024 * 1024));
+ var message = StringUtils.format(Strings.FIND_IN_FILES_CACHE_LIMIT_MSG, cacheSizeMB);
+ var $content = $('