-
Notifications
You must be signed in to change notification settings - Fork 302
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
FEAT: add code navigation to script editor #1660
base: dev
Are you sure you want to change the base?
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -32,7 +32,7 @@ import { useVimEditor } from "./useVimEditor"; | |
import { useCallback } from "react"; | ||
import { type AST, getFileType, parseAST } from "../../utils/ScriptTransformer"; | ||
import { RamCalculationErrorCode } from "../../Script/RamCalculationErrorCodes"; | ||
import { hasScriptExtension, isLegacyScript } from "../../Paths/ScriptFilePath"; | ||
import { hasScriptExtension, isLegacyScript, resolveScriptFilePath, ScriptFilePath } from "../../Paths/ScriptFilePath"; | ||
|
||
interface IProps { | ||
// Map of filename -> code | ||
|
@@ -42,6 +42,74 @@ interface IProps { | |
} | ||
const openScripts: OpenScript[] = []; | ||
let currentScript: OpenScript | null = null; | ||
let vim: boolean = false; // this will be set on mounting the component | ||
|
||
export class CodeOpener implements monaco.editor.ICodeEditorOpener { | ||
openCodeEditor( | ||
source: monaco.editor.ICodeEditor, | ||
resource: monaco.Uri, | ||
selectionOrPosition?: monaco.IRange | monaco.IPosition, | ||
): boolean { | ||
const resolvedPath = resolveScriptFilePath(resource.path); | ||
if (resolvedPath === null) { | ||
return false; | ||
} | ||
|
||
const [hostname, path] = resolvedPath.split("/", 2); | ||
|
||
// check if we have an open file already; if so, show it at the requested position | ||
const openScript = openScripts.find((s) => s.path === path && s.hostname === hostname); | ||
if (openScript) { | ||
if (openScript.model === undefined || openScript.model === null || openScript.model.isDisposed()) { | ||
openScript.regenerateModel(); | ||
} | ||
currentScript = openScript; | ||
source.setModel(openScript.model); | ||
} else { | ||
const server = GetServer(hostname); | ||
if (server === null) { | ||
return false; | ||
} | ||
|
||
const script = server.scripts.get(path as ScriptFilePath); | ||
if (script === undefined) { | ||
return false; | ||
} | ||
|
||
// Open script | ||
const newScript = new OpenScript( | ||
path as ScriptFilePath, | ||
script.code, | ||
hostname, | ||
new monaco.Position(0, 0), | ||
makeModel(hostname, path, script.code), | ||
vim, | ||
); | ||
openScripts.push(newScript); | ||
currentScript = newScript; | ||
source.setModel(newScript.model); | ||
} | ||
|
||
if (selectionOrPosition === undefined) { | ||
return true; | ||
} | ||
|
||
if ((selectionOrPosition as monaco.IRange) !== undefined) { | ||
const range = selectionOrPosition as monaco.IRange; | ||
|
||
source.setSelection(range); | ||
source.revealLineInCenter(range.startLineNumber); | ||
} else if ((selectionOrPosition as monaco.IPosition) !== undefined) { | ||
const pos = selectionOrPosition as monaco.IPosition; | ||
|
||
source.setPosition(pos); | ||
source.revealLineInCenter(pos.lineNumber); | ||
} | ||
|
||
source.focus(); | ||
return true; | ||
} | ||
} | ||
|
||
function Root(props: IProps): React.ReactElement { | ||
const rerender = useRerender(); | ||
|
@@ -187,19 +255,40 @@ function Root(props: IProps): React.ReactElement { | |
debouncedCodeParsing(newCode); | ||
}; | ||
|
||
let changeModelCallback: monaco.IDisposable | null = null; | ||
|
||
// When the editor is mounted | ||
function onMount(editor: IStandaloneCodeEditor): void { | ||
// Required when switching between site navigation (e.g. from Script Editor -> Terminal and back) | ||
// the `useEffect()` for vim mode is called before editor is mounted. | ||
editorRef.current = editor; | ||
changeModelCallback = editorRef.current.onDidChangeModel((e) => { | ||
if (e.newModelUrl === null) { | ||
return; | ||
} | ||
|
||
const resolvedPath = resolveScriptFilePath(e.newModelUrl.path); | ||
if (resolvedPath === null) { | ||
return false; | ||
} | ||
const [hostname, path] = resolvedPath.split("/", 2); | ||
|
||
const script = openScripts.find((s) => s.hostname === hostname && s.path === path); | ||
if (script) { | ||
parseCode(script.code); | ||
} | ||
|
||
rerender(); | ||
removeOutlineOfEditor(); | ||
}); | ||
vim = props.vim; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why is this changing? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. When using code navigation, monaco might open a file that has not been loaded yet. Originally, |
||
|
||
if (props.files.size === 0 && currentScript !== null) { | ||
// Open currentscript | ||
currentScript.regenerateModel(); | ||
editorRef.current.setModel(currentScript.model); | ||
editorRef.current.setPosition(currentScript.lastPosition); | ||
editorRef.current.revealLineInCenter(currentScript.lastPosition.lineNumber); | ||
parseCode(currentScript.code); | ||
editorRef.current.focus(); | ||
return; | ||
} | ||
|
@@ -218,7 +307,6 @@ function Root(props: IProps): React.ReactElement { | |
editorRef.current.setModel(openScript.model); | ||
editorRef.current.setPosition(openScript.lastPosition); | ||
editorRef.current.revealLineInCenter(openScript.lastPosition.lineNumber); | ||
parseCode(openScript.code); | ||
} else { | ||
// Open script | ||
const newScript = new OpenScript( | ||
|
@@ -232,7 +320,6 @@ function Root(props: IProps): React.ReactElement { | |
openScripts.push(newScript); | ||
currentScript = newScript; | ||
editorRef.current.setModel(newScript.model); | ||
parseCode(newScript.code); | ||
} | ||
} | ||
|
||
|
@@ -289,7 +376,6 @@ function Root(props: IProps): React.ReactElement { | |
editorRef.current.setModel(currentScript.model); | ||
editorRef.current.setPosition(currentScript.lastPosition); | ||
editorRef.current.revealLineInCenter(currentScript.lastPosition.lineNumber); | ||
parseCode(currentScript.code); | ||
editorRef.current.focus(); | ||
} | ||
removeOutlineOfEditor(); | ||
|
@@ -334,7 +420,6 @@ function Root(props: IProps): React.ReactElement { | |
editorRef.current.setModel(currentScript.model); | ||
editorRef.current.setPosition(currentScript.lastPosition); | ||
editorRef.current.revealLineInCenter(currentScript.lastPosition.lineNumber); | ||
parseCode(currentScript.code); | ||
editorRef.current.focus(); | ||
} | ||
} | ||
|
@@ -366,9 +451,7 @@ function Root(props: IProps): React.ReactElement { | |
openScript.regenerateModel(); | ||
} | ||
editorRef.current.setModel(openScript.model); | ||
|
||
editorRef.current.setValue(openScript.code); | ||
parseCode(openScript.code); | ||
editorRef.current.focus(); | ||
} | ||
} | ||
|
@@ -399,6 +482,11 @@ function Root(props: IProps): React.ReactElement { | |
} | ||
|
||
function onUnmountEditor() { | ||
if (changeModelCallback) { | ||
changeModelCallback.dispose(); | ||
changeModelCallback = null; | ||
} | ||
|
||
if (!currentScript) { | ||
return; | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
as
is a compile-time-only thing, it doesn't do anything at runtime. You'll need to do something likestartLineNumber in selectionOrPosition
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good to know, thanks for the hint.