Skip to content

Commit 76c2b36

Browse files
committed
fix: prevent OOM crash from file indexing on large projects
Add two safeguards to prevent Electron crashes when opening projects with many large or binary files: 1. Content-based binary detection: check first 8KB for null bytes (same heuristic as git/grep) to skip binary files that lack a recognized extension. Previously only extension-based detection was used, missing extensionless binary files entirely. 2. Configurable cache size limit (default 1GB via maxFileCacheSizeMB preference): stops indexing and shows a warning toast when the limit is reached, disabling Find in Files for that project. The V8 heap limit is ~4GB per process and the web worker has its own heap, so 1GB leaves safe headroom.
1 parent c0d196e commit 76c2b36

6 files changed

Lines changed: 266 additions & 137 deletions

File tree

docs/API-Reference/view/PanelView.md

Lines changed: 135 additions & 128 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,144 @@
33
const PanelView = brackets.getModule("view/PanelView")
44
```
55

6+
<a name="_panelMap"></a>
7+
8+
## \_panelMap : <code>Object.&lt;string, Panel&gt;</code>
9+
Maps panel ID to Panel instance
10+
11+
**Kind**: global variable
12+
<a name="_$container"></a>
13+
14+
## \_$container : <code>jQueryObject</code>
15+
The single container wrapping all bottom panels
16+
17+
**Kind**: global variable
18+
<a name="_$tabBar"></a>
19+
20+
## \_$tabBar : <code>jQueryObject</code>
21+
The tab bar inside the container
22+
23+
**Kind**: global variable
24+
<a name="_$tabsOverflow"></a>
25+
26+
## \_$tabsOverflow : <code>jQueryObject</code>
27+
Scrollable area holding the tab elements
28+
29+
**Kind**: global variable
30+
<a name="_openIds"></a>
31+
32+
## \_openIds : <code>Array.&lt;string&gt;</code>
33+
Ordered list of currently open (tabbed) panel IDs
34+
35+
**Kind**: global variable
36+
<a name="_activeId"></a>
37+
38+
## \_activeId : <code>string</code> \| <code>null</code>
39+
The panel ID of the currently visible (active) tab
40+
41+
**Kind**: global variable
42+
<a name="_isMaximized"></a>
43+
44+
## \_isMaximized : <code>boolean</code>
45+
Whether the bottom panel is currently maximized
46+
47+
**Kind**: global variable
48+
<a name="_preMaximizeHeight"></a>
49+
50+
## \_preMaximizeHeight : <code>number</code> \| <code>null</code>
51+
The panel height before maximize, for restore
52+
53+
**Kind**: global variable
54+
<a name="_$editorHolder"></a>
55+
56+
## \_$editorHolder : <code>jQueryObject</code>
57+
The editor holder element, passed from WorkspaceManager
58+
59+
**Kind**: global variable
60+
<a name="_recomputeLayout"></a>
61+
62+
## \_recomputeLayout : <code>function</code>
63+
recomputeLayout callback from WorkspaceManager
64+
65+
**Kind**: global variable
66+
<a name="_defaultPanelId"></a>
67+
68+
## \_defaultPanelId : <code>string</code> \| <code>null</code>
69+
The default/quick-access panel ID
70+
71+
**Kind**: global variable
72+
<a name="_$addBtn"></a>
73+
74+
## \_$addBtn : <code>jQueryObject</code>
75+
The "+" button inside the tab overflow area
76+
77+
**Kind**: global variable
78+
<a name="_$overflowBtn"></a>
79+
80+
## \_$overflowBtn : <code>jQueryObject</code>
81+
Overflow dropdown button
82+
83+
**Kind**: global variable
84+
<a name="_overflowDropdown"></a>
85+
86+
## \_overflowDropdown : <code>DropdownButton.DropdownButton</code>
87+
**Kind**: global variable
88+
<a name="EVENT_PANEL_HIDDEN"></a>
89+
90+
## EVENT\_PANEL\_HIDDEN : <code>string</code>
91+
Event when panel is hidden
92+
93+
**Kind**: global constant
94+
<a name="EVENT_PANEL_SHOWN"></a>
95+
96+
## EVENT\_PANEL\_SHOWN : <code>string</code>
97+
Event when panel is shown
98+
99+
**Kind**: global constant
100+
<a name="PANEL_TYPE_BOTTOM_PANEL"></a>
101+
102+
## PANEL\_TYPE\_BOTTOM\_PANEL : <code>string</code>
103+
type for bottom panel
104+
105+
**Kind**: global constant
106+
<a name="MAXIMIZE_THRESHOLD"></a>
107+
108+
## MAXIMIZE\_THRESHOLD : <code>number</code>
109+
Pixel threshold for detecting near-maximize state during resize.
110+
If the editor holder height is within this many pixels of zero, the
111+
panel is treated as maximized. Keeps the maximize icon responsive
112+
during drag without being overly sensitive.
113+
114+
**Kind**: global constant
115+
<a name="MIN_PANEL_HEIGHT"></a>
116+
117+
## MIN\_PANEL\_HEIGHT : <code>number</code>
118+
Minimum panel height (matches Resizer minSize) used as a floor
119+
when computing a sensible restore height.
120+
121+
**Kind**: global constant
122+
<a name="PREF_BOTTOM_PANEL_MAXIMIZED"></a>
123+
124+
## PREF\_BOTTOM\_PANEL\_MAXIMIZED
125+
Preference key for persisting the maximize state across reloads.
126+
127+
**Kind**: global constant
6128
<a name="Panel"></a>
7129

8-
## Panel
9-
**Kind**: global class
130+
## Panel($panel, id, [title], [options])
131+
**Kind**: global function
132+
133+
| Param | Type | Description |
134+
| --- | --- | --- |
135+
| $panel | <code>jQueryObject</code> | |
136+
| id | <code>string</code> | |
137+
| [title] | <code>string</code> | |
138+
| [options] | <code>Object</code> | |
139+
| [options.iconClass] | <code>string</code> | FontAwesome class string (e.g. "fa-solid fa-terminal"). |
140+
| [options.iconSvg] | <code>string</code> | Path to an SVG icon (e.g. "styles/images/icon.svg"). |
141+
10142

11-
* [Panel](#Panel)
12-
* [new Panel($panel, id, [title])](#new_Panel_new)
143+
* [Panel($panel, id, [title], [options])](#Panel)
13144
* [.$panel](#Panel+$panel) : <code>jQueryObject</code>
14145
* [.isVisible()](#Panel+isVisible) ⇒ <code>boolean</code>
15146
* [.registerCanBeShownHandler(canShowHandlerFn)](#Panel+registerCanBeShownHandler) ⇒ <code>boolean</code>
@@ -24,18 +155,6 @@ const PanelView = brackets.getModule("view/PanelView")
24155
* [.destroy()](#Panel+destroy)
25156
* [.getPanelType()](#Panel+getPanelType) ⇒ <code>string</code>
26157

27-
<a name="new_Panel_new"></a>
28-
29-
### new Panel($panel, id, [title])
30-
Represents a panel below the editor area (a child of ".content").
31-
32-
33-
| Param | Type | Description |
34-
| --- | --- | --- |
35-
| $panel | <code>jQueryObject</code> | The entire panel, including any chrome, already in the DOM. |
36-
| id | <code>string</code> | Unique panel identifier. |
37-
| [title] | <code>string</code> | Optional display title for the tab bar. |
38-
39158
<a name="Panel+$panel"></a>
40159

41160
### panel.$panel : <code>jQueryObject</code>
@@ -144,118 +263,6 @@ After calling this, the Panel instance should not be reused.
144263
gets the Panel's type
145264

146265
**Kind**: instance method of [<code>Panel</code>](#Panel)
147-
<a name="_panelMap"></a>
148-
149-
## \_panelMap : <code>Object.&lt;string, Panel&gt;</code>
150-
Maps panel ID to Panel instance
151-
152-
**Kind**: global variable
153-
<a name="_$container"></a>
154-
155-
## \_$container : <code>jQueryObject</code>
156-
The single container wrapping all bottom panels
157-
158-
**Kind**: global variable
159-
<a name="_$tabBar"></a>
160-
161-
## \_$tabBar : <code>jQueryObject</code>
162-
The tab bar inside the container
163-
164-
**Kind**: global variable
165-
<a name="_$tabsOverflow"></a>
166-
167-
## \_$tabsOverflow : <code>jQueryObject</code>
168-
Scrollable area holding the tab elements
169-
170-
**Kind**: global variable
171-
<a name="_openIds"></a>
172-
173-
## \_openIds : <code>Array.&lt;string&gt;</code>
174-
Ordered list of currently open (tabbed) panel IDs
175-
176-
**Kind**: global variable
177-
<a name="_activeId"></a>
178-
179-
## \_activeId : <code>string</code> \| <code>null</code>
180-
The panel ID of the currently visible (active) tab
181-
182-
**Kind**: global variable
183-
<a name="_isMaximized"></a>
184-
185-
## \_isMaximized : <code>boolean</code>
186-
Whether the bottom panel is currently maximized
187-
188-
**Kind**: global variable
189-
<a name="_preMaximizeHeight"></a>
190-
191-
## \_preMaximizeHeight : <code>number</code> \| <code>null</code>
192-
The panel height before maximize, for restore
193-
194-
**Kind**: global variable
195-
<a name="_$editorHolder"></a>
196-
197-
## \_$editorHolder : <code>jQueryObject</code>
198-
The editor holder element, passed from WorkspaceManager
199-
200-
**Kind**: global variable
201-
<a name="_recomputeLayout"></a>
202-
203-
## \_recomputeLayout : <code>function</code>
204-
recomputeLayout callback from WorkspaceManager
205-
206-
**Kind**: global variable
207-
<a name="_defaultPanelId"></a>
208-
209-
## \_defaultPanelId : <code>string</code> \| <code>null</code>
210-
The default/quick-access panel ID
211-
212-
**Kind**: global variable
213-
<a name="_$addBtn"></a>
214-
215-
## \_$addBtn : <code>jQueryObject</code>
216-
The "+" button inside the tab overflow area
217-
218-
**Kind**: global variable
219-
<a name="EVENT_PANEL_HIDDEN"></a>
220-
221-
## EVENT\_PANEL\_HIDDEN : <code>string</code>
222-
Event when panel is hidden
223-
224-
**Kind**: global constant
225-
<a name="EVENT_PANEL_SHOWN"></a>
226-
227-
## EVENT\_PANEL\_SHOWN : <code>string</code>
228-
Event when panel is shown
229-
230-
**Kind**: global constant
231-
<a name="PANEL_TYPE_BOTTOM_PANEL"></a>
232-
233-
## PANEL\_TYPE\_BOTTOM\_PANEL : <code>string</code>
234-
type for bottom panel
235-
236-
**Kind**: global constant
237-
<a name="MAXIMIZE_THRESHOLD"></a>
238-
239-
## MAXIMIZE\_THRESHOLD : <code>number</code>
240-
Pixel threshold for detecting near-maximize state during resize.
241-
If the editor holder height is within this many pixels of zero, the
242-
panel is treated as maximized. Keeps the maximize icon responsive
243-
during drag without being overly sensitive.
244-
245-
**Kind**: global constant
246-
<a name="MIN_PANEL_HEIGHT"></a>
247-
248-
## MIN\_PANEL\_HEIGHT : <code>number</code>
249-
Minimum panel height (matches Resizer minSize) used as a floor
250-
when computing a sensible restore height.
251-
252-
**Kind**: global constant
253-
<a name="PREF_BOTTOM_PANEL_MAXIMIZED"></a>
254-
255-
## PREF\_BOTTOM\_PANEL\_MAXIMIZED
256-
Preference key for persisting the maximize state across reloads.
257-
258-
**Kind**: global constant
259266
<a name="init"></a>
260267

261268
## init($container, $tabBar, $tabsOverflow, $editorHolder, recomputeLayoutFn, defaultPanelId)

docs/API-Reference/view/WorkspaceManager.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ Events:
2828
* [.EVENT_WORKSPACE_UPDATE_LAYOUT](#module_view/WorkspaceManager..EVENT_WORKSPACE_UPDATE_LAYOUT)
2929
* [.EVENT_WORKSPACE_PANEL_SHOWN](#module_view/WorkspaceManager..EVENT_WORKSPACE_PANEL_SHOWN)
3030
* [.EVENT_WORKSPACE_PANEL_HIDDEN](#module_view/WorkspaceManager..EVENT_WORKSPACE_PANEL_HIDDEN)
31-
* [.createBottomPanel(id, $panel, [minSize], [title])](#module_view/WorkspaceManager..createBottomPanel) ⇒ <code>Panel</code>
31+
* [.createBottomPanel(id, $panel, [minSize], [title], [options])](#module_view/WorkspaceManager..createBottomPanel) ⇒ <code>Panel</code>
3232
* [.destroyBottomPanel(id)](#module_view/WorkspaceManager..destroyBottomPanel)
3333
* [.createPluginPanel(id, $panel, [minSize], $toolbarIcon, [initialSize])](#module_view/WorkspaceManager..createPluginPanel) ⇒ <code>Panel</code>
3434
* [.getAllPanelIDs()](#module_view/WorkspaceManager..getAllPanelIDs) ⇒ <code>Array</code>
@@ -89,7 +89,7 @@ Event triggered when a panel is hidden.
8989
**Kind**: inner constant of [<code>view/WorkspaceManager</code>](#module_view/WorkspaceManager)
9090
<a name="module_view/WorkspaceManager..createBottomPanel"></a>
9191

92-
### view/WorkspaceManager.createBottomPanel(id, $panel, [minSize], [title]) ⇒ <code>Panel</code>
92+
### view/WorkspaceManager.createBottomPanel(id, $panel, [minSize], [title], [options]) ⇒ <code>Panel</code>
9393
Creates a new resizable panel beneath the editor area and above the status bar footer. Panel is initially invisible.
9494
The panel's size & visibility are automatically saved & restored as a view-state preference.
9595

@@ -101,6 +101,7 @@ The panel's size & visibility are automatically saved & restored as a view-state
101101
| $panel | <code>jQueryObject</code> | 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. |
102102
| [minSize] | <code>number</code> | @deprecated No longer used. Pass `undefined`. |
103103
| [title] | <code>string</code> | Display title shown in the bottom panel tab bar. |
104+
| [options] | <code>Object</code> | 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"). |
104105

105106
<a name="module_view/WorkspaceManager..destroyBottomPanel"></a>
106107

src/nls/root/strings.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -639,6 +639,9 @@ define({
639639
"FIND_IN_FILES_SEARCHING": "Searching Files\u2026",
640640
"FIND_IN_FILES_SEARCHING_IN": "In {0}",
641641
"FIND_IN_FILES_INDEXING_PROGRESS": "Indexing {0} of {1} files for Instant Search\u2026",
642+
"FIND_IN_FILES_CACHE_LIMIT_TITLE": "File Indexing Suspended",
643+
"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.",
644+
"DESCRIPTION_MAX_FILE_CACHE_SIZE_MB": "Maximum size in MB for the instant search file cache.",
642645
"REPLACE_IN_FILES_ERRORS_TITLE": "Replace Errors",
643646
"REPLACE_IN_FILES_ERRORS": "The following files weren't modified because they changed after the search or couldn't be written.",
644647

0 commit comments

Comments
 (0)