Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions frontend/app/view/codeeditor/codeeditor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -108,19 +108,20 @@ interface CodeEditorProps {
text: string;
readonly: boolean;
language?: string;
fileName?: string;
onChange?: (text: string) => void;
onMount?: (monacoPtr: MonacoTypes.editor.IStandaloneCodeEditor, monaco: Monaco) => () => void;
}

export function CodeEditor({ blockId, text, language, readonly, onChange, onMount }: CodeEditorProps) {
export function CodeEditor({ blockId, text, language, fileName, readonly, onChange, onMount }: CodeEditorProps) {
const divRef = useRef<HTMLDivElement>(null);
const unmountRef = useRef<() => void>(null);
const minimapEnabled = useOverrideConfigAtom(blockId, "editor:minimapenabled") ?? false;
const stickyScrollEnabled = useOverrideConfigAtom(blockId, "editor:stickyscrollenabled") ?? false;
const wordWrap = useOverrideConfigAtom(blockId, "editor:wordwrap") ?? false;
const fontSize = boundNumber(useOverrideConfigAtom(blockId, "editor:fontsize"), 6, 64);
const theme = "wave-theme-dark";
const editorPath = useRef(crypto.randomUUID()).current;
const editorPath = useRef(fileName ?? crypto.randomUUID()).current;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Fix: editorPath doesn't update when fileName prop changes.

The current implementation uses useRef which only evaluates its initial value on the first render. If the fileName prop changes on subsequent renders, editorPath will retain its original value, causing Monaco Editor to use the wrong model identity.

Scenario demonstrating the bug:

  1. Component mounts with fileName="file-a.txt"editorPath="file-a.txt"
  2. Props update to fileName="file-b.txt"editorPath still "file-a.txt"

This results in Monaco using the model for file A when editing file B.

Apply this diff to make editorPath reactive to fileName changes while maintaining a stable UUID fallback:

+    const fallbackPath = useRef(crypto.randomUUID()).current;
-    const editorPath = useRef(fileName ?? crypto.randomUUID()).current;
+    const editorPath = fileName ?? fallbackPath;

This ensures:

  • When fileName is provided, editorPath updates immediately
  • When fileName is undefined, a stable random UUID is used across renders
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const editorPath = useRef(fileName ?? crypto.randomUUID()).current;
const fallbackPath = useRef(crypto.randomUUID()).current;
const editorPath = fileName ?? fallbackPath;
🤖 Prompt for AI Agents
In frontend/app/view/codeeditor/codeeditor.tsx at line 124, replace the
useRef-based initialization so editorPath reacts to changes in the fileName prop
while keeping a stable UUID fallback: create a persistent fallback ID using
useRef at component init (e.g., assign crypto.randomUUID() once into a ref) and
then derive editorPath on every render as fileName ?? fallbackRef.current,
ensuring fileName updates immediately and the generated UUID remains stable when
fileName is undefined.


React.useEffect(() => {
return () => {
Expand Down
2 changes: 2 additions & 0 deletions frontend/app/view/preview/preview-edit.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ function CodeEditPreview({ model }: SpecializedViewProps) {
const fileContent = useAtomValue(model.fileContent);
const setNewFileContent = useSetAtom(model.newFileContent);
const fileInfo = useAtomValue(model.statFile);
const fileName = fileInfo?.path || fileInfo?.name;

function codeEditKeyDownHandler(e: WaveKeyboardEvent): boolean {
if (checkKeyPressed(e, "Cmd:e")) {
Expand Down Expand Up @@ -65,6 +66,7 @@ function CodeEditPreview({ model }: SpecializedViewProps) {
<CodeEditor
blockId={model.blockId}
text={fileContent}
fileName={fileName}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

Verify fileName prop integration with CodeEditor.

The fileName prop is correctly passed to CodeEditor, enabling file-path-aware editor initialization.

Confirm that the CodeEditor component properly handles the case when fileName is undefined or changes between renders:


🏁 Script executed:

#!/bin/bash
# Verify CodeEditor's handling of fileName prop and editorPath stability

# Check how editorPath is used and whether it updates when fileName changes
ast-grep --pattern $'const editorPath = $$$'

# Search for Monaco Editor path prop usage
rg -nP --type=tsx --type=ts -C3 '\bpath\s*=\s*\{?\s*editorPath'

Length of output: 147


I found that editorPath is defined in CodeEditor, but the search had some issues. Let me refine the verification with better commands.


🏁 Script executed:

#!/bin/bash
# Examine the CodeEditor component to understand fileName prop and editorPath handling

# View the CodeEditor component around the editorPath definition
echo "=== CodeEditor component (lines 110-150) ==="
sed -n '110,150p' frontend/app/view/codeeditor/codeeditor.tsx

# Search for all uses of editorPath within CodeEditor to see if it updates reactively
echo -e "\n=== All editorPath usages in CodeEditor ==="
grep -n "editorPath" frontend/app/view/codeeditor/codeeditor.tsx

# Check if fileName appears in dependency arrays
echo -e "\n=== useEffect/useCallback dependency arrays with fileName or editorPath ==="
grep -n -B2 -A2 "fileName\|editorPath" frontend/app/view/codeeditor/codeeditor.tsx | grep -A2 -B2 "\[.*\]"

# View the preview-edit.tsx file around line 69 to see how fileName is passed
echo -e "\n=== preview-edit.tsx context (lines 60-80) ==="
sed -n '60,80p' frontend/app/view/preview/preview-edit.tsx

Length of output: 2286


I found a critical issue. Let me verify how fileName changes over time:


🏁 Script executed:

#!/bin/bash
# Check if fileName changes dynamically in preview-edit.tsx

echo "=== Full preview-edit.tsx to understand fileName lifecycle ==="
cat frontend/app/view/preview/preview-edit.tsx | grep -n "fileName" -B2 -A2

echo -e "\n=== Check for fileName state updates ==="
grep -n "setFileName\|fileName.*=" frontend/app/view/preview/preview-edit.tsx

Length of output: 667


I've identified a potential bug. Let me check if fileInfo can change after the component mounts:


🏁 Script executed:

#!/bin/bash
# Search for updates to model.statFile atom to determine if fileInfo can change

echo "=== Check atom updates and fileInfo reactivity ==="
rg -n "statFile" frontend/app/view/preview/preview-edit.tsx

echo -e "\n=== Search broader codebase for statFile mutations ==="
rg -n "statFile.*=" --type ts --type tsx -C2 | head -40

echo -e "\n=== Verify if editorPath should be reactive ==="
# Check if Monaco editor's path prop expects to update dynamically
grep -n "path=" frontend/app/view/codeeditor/codeeditor.tsx -B3 -A3

Length of output: 522


Fix editorPath reactivity: editorPath should update when fileName changes.

The current implementation freezes editorPath on mount due to the .current extraction in the initial value assignment. When fileName changes (via fileInfo atom updates in preview-edit.tsx), the CodeEditor component re-renders with a new prop, but editorPath remains stale because it's locked in a useRef.

Issue location: frontend/app/view/codeeditor/codeeditor.tsx:124

The fix should ensure editorPath updates reactively. Replace:

const editorPath = useRef(fileName ?? crypto.randomUUID()).current;

With a pattern that maintains the UUID fallback while allowing updates:

const editorPathRef = useRef(fileName ?? crypto.randomUUID());
const editorPath = editorPathRef.current;

Or if the path should update with fileName changes:

const editorPath = fileName ?? useRef(crypto.randomUUID()).current;
🤖 Prompt for AI Agents
In frontend/app/view/codeeditor/codeeditor.tsx around line 124, editorPath is
currently frozen by assigning useRef(...).current on init, so it never updates
when fileName changes; replace that pattern with a reactive approach — either
keep a ref that stores a UUID fallback but read its .current separately (i.e.
create editorPathRef = useRef(fileName ?? crypto.randomUUID()) and then use
editorPathRef.current), or make editorPath derive from fileName with a ref only
for the UUID fallback (i.e. editorPath = fileName ??
useRef(crypto.randomUUID()).current) so editorPath will update when fileName
changes. Ensure you only change the initialization pattern and use the new
editorPath value everywhere the component expects it.

readonly={fileInfo.readonly}
onChange={(text) => setNewFileContent(text)}
onMount={onMount}
Expand Down
3 changes: 2 additions & 1 deletion frontend/app/view/term/termutil.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@ function computeTheme(
}
}
let bgcolor = themeCopy.background;
themeCopy.background = "#00000000";
// Keep the actual background color in the theme so terminal applications
// like Neovim can properly detect the background color for syntax highlighting
return [themeCopy, bgcolor];
}

Expand Down