Skip to content

Commit

Permalink
Merge branch 'main' into update-gist
Browse files Browse the repository at this point in the history
  • Loading branch information
magland committed Jul 30, 2024
2 parents e045ccd + 017df72 commit ad27ddd
Show file tree
Hide file tree
Showing 11 changed files with 272 additions and 235 deletions.
2 changes: 1 addition & 1 deletion gui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,11 @@
"test-watch": "vitest"
},
"dependencies": {
"@devbookhq/splitter": "^1.4.2",
"@emotion/react": "^11.11.4",
"@emotion/styled": "^11.11.5",
"@fi-sci/misc": "^0.0.8",
"@fi-sci/modal-window": "^0.0.2",
"@geoffcox/react-splitter": "^2.1.2",
"@monaco-editor/react": "^4.6.0",
"@mui/icons-material": "^5.15.17",
"@mui/material": "^5.15.17",
Expand Down
74 changes: 38 additions & 36 deletions gui/src/app/FileEditor/StanFileEditor.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { Split } from "@geoffcox/react-splitter";
import { AutoFixHigh, Cancel, Settings } from "@mui/icons-material";
import useMediaQuery from "@mui/material/useMediaQuery";
import { SplitDirection, Splitter } from "@SpComponents/Splitter";
import StanCompileResultWindow from "@SpComponents/StanCompileResultWindow";
import TextEditor, { ToolbarItem } from "@SpComponents/TextEditor";
import TextEditor from "@SpComponents/TextEditor";
import { ToolbarItem } from "@SpComponents/ToolBar";
import compileStanProgram from "@SpStanc/compileStanProgram";
import { stancErrorsToCodeMarkers } from "@SpStanc/Linting";
import useStanc from "@SpStanc/useStanc";
Expand Down Expand Up @@ -123,7 +123,6 @@ const StanFileEditor: FunctionComponent<Props> = ({
}
}, [fileContent, handleCompile, didInitialCompile]);

const showLabelsOnButtons = useMediaQuery("(min-width:600px)");
const [syntaxWindowVisible, setSyntaxWindowVisible] = useState(false);

const toolbarItems: ToolbarItem[] = useMemo(() => {
Expand All @@ -134,7 +133,7 @@ const StanFileEditor: FunctionComponent<Props> = ({
ret.push({
type: "button",
icon: <Cancel />,
label: showLabelsOnButtons ? "Syntax error" : "",
label: "Syntax error",
color: "darkred",
tooltip: "Syntax error in Stan file",
onClick: () => {
Expand All @@ -145,7 +144,7 @@ const StanFileEditor: FunctionComponent<Props> = ({
ret.push({
type: "button",
icon: <Cancel />,
label: showLabelsOnButtons ? "Syntax warning" : "",
label: "Syntax warning",
color: "blue",
tooltip: "Syntax warning in Stan file",
onClick: () => {
Expand All @@ -155,25 +154,23 @@ const StanFileEditor: FunctionComponent<Props> = ({
}

// auto format
if (!readOnly) {
if (editedFileContent) {
ret.push({
type: "button",
icon: <AutoFixHigh />,
tooltip: "Auto format this stan file",
label: showLabelsOnButtons ? "auto format" : undefined,
onClick: requestFormat,
color: "darkblue",
});
}
if (!readOnly && editedFileContent && validSyntax) {
ret.push({
type: "button",
icon: <AutoFixHigh />,
tooltip: "Auto format this stan file",
label: "Auto format",
onClick: requestFormat,
color: "darkblue",
});
}
if (editedFileContent && editedFileContent === fileContent) {
if (compileStatus !== "compiling") {
if (validSyntax) {
ret.push({
type: "button",
tooltip: "Compile Stan model",
label: "compile",
label: "Compile",
icon: <Settings />,
onClick: handleCompile,
color: "darkblue",
Expand All @@ -183,7 +180,8 @@ const StanFileEditor: FunctionComponent<Props> = ({
if (compileStatus !== "") {
ret.push({
type: "text",
label: compileMessage,
label:
compileMessage.charAt(0).toUpperCase() + compileMessage.slice(1),
color:
compileStatus === "compiled"
? "green"
Expand All @@ -200,7 +198,6 @@ const StanFileEditor: FunctionComponent<Props> = ({
fileContent,
handleCompile,
requestFormat,
showLabelsOnButtons,
validSyntax,
compileStatus,
compileMessage,
Expand All @@ -219,25 +216,30 @@ const StanFileEditor: FunctionComponent<Props> = ({
<></>
);

const initialSizes = syntaxWindowVisible ? [60, 40] : [100, 0];
const editor = (
<TextEditor
language="stan"
label={fileName}
text={fileContent}
onSaveText={onSaveContent}
editedText={editedFileContent}
onSetEditedText={setEditedFileContent}
readOnly={!isCompiling ? readOnly : true}
toolbarItems={toolbarItems}
codeMarkers={stancErrorsToCodeMarkers(stancErrors)}
contentOnEmpty="Begin editing or select an example from the left panel"
/>
);

return (
<Splitter direction={SplitDirection.Vertical} initialSizes={initialSizes}>
<TextEditor
// language="stan"
language="stan"
label={fileName}
text={fileContent}
onSaveText={onSaveContent}
editedText={editedFileContent}
onSetEditedText={setEditedFileContent}
readOnly={!isCompiling ? readOnly : true}
toolbarItems={toolbarItems}
codeMarkers={stancErrorsToCodeMarkers(stancErrors)}
contentOnEmpty="Begin editing or select an example from the left panel"
/>
<Split
horizontal
initialPrimarySize={syntaxWindowVisible ? "60%" : "100%"}
splitterSize={syntaxWindowVisible ? "7px" : "0px"}
>
{editor}
{window}
</Splitter>
</Split>
);
};

Expand Down
113 changes: 15 additions & 98 deletions gui/src/app/FileEditor/TextEditor.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,15 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import { SmallIconButton } from "@fi-sci/misc";
import { Editor, loader, useMonaco } from "@monaco-editor/react";
import { Save } from "@mui/icons-material";
import Link from "@mui/material/Link";

import monacoAddStanLang from "@SpComponents/stanLang";
import { ToolBar, ToolbarItem } from "@SpComponents/ToolBar";
import { CodeMarker } from "@SpStanc/Linting";
import { editor, MarkerSeverity } from "monaco-editor";
import {
FunctionComponent,
PropsWithChildren,
useCallback,
useEffect,
useMemo,
useState,
} from "react";

Expand All @@ -30,21 +29,6 @@ type Props = {
contentOnEmpty?: string | HTMLSpanElement;
};

export type ToolbarItem =
| {
type: "button";
tooltip?: string;
label?: string;
icon?: any;
onClick?: () => void;
color?: string;
}
| {
type: "text";
label: string;
color?: string;
};

const TextEditor: FunctionComponent<Props> = ({
text,
onSaveText,
Expand Down Expand Up @@ -131,32 +115,19 @@ const TextEditor: FunctionComponent<Props> = ({
[onSaveText, readOnly],
);

const edited = useMemo(() => {
return editedText !== text;
}, [editedText, text]);

return (
<div className="EditorWithToolbar" onKeyDown={handleKeyDown}>
<NotSelectable>
<div className="EditorMenuBar">
<span className="EditorTitle">{label}</span>
&nbsp;&nbsp;&nbsp;
{!readOnly && text !== editedText && (
<SmallIconButton
onClick={onSaveText}
icon={<Save />}
title="Save file"
disabled={text === editedText}
label="save"
/>
)}
&nbsp;&nbsp;&nbsp;
{editedText !== text && <span className="EditedText">edited</span>}
&nbsp;&nbsp;&nbsp;
{readOnly && <span className="ReadOnlyText">read only</span>}
&nbsp;&nbsp;&nbsp;
{toolbarItems &&
toolbarItems.map((item, i) => (
<ToolbarItemComponent key={i} item={item} />
))}
</div>
</NotSelectable>
<ToolBar
items={toolbarItems || []}
label={label}
onSaveText={onSaveText}
edited={edited}
readOnly={!!readOnly}
/>
<Editor
defaultLanguage={language}
onChange={handleChange}
Expand All @@ -165,6 +136,7 @@ const TextEditor: FunctionComponent<Props> = ({
readOnly,
domReadOnly: readOnly,
wordWrap: "on",
minimap: { enabled: false },
}}
/>
</div>
Expand All @@ -186,61 +158,6 @@ const toMonacoMarkerSeverity = (
}
};

const ToolbarItemComponent: FunctionComponent<{ item: ToolbarItem }> = ({
item,
}) => {
if (item.type === "button") {
const { onClick, color, label, tooltip, icon } = item;
if (icon) {
return (
<span style={{ color }}>
<SmallIconButton
onClick={onClick}
icon={icon}
title={tooltip}
label={label}
disabled={!onClick}
/>
&nbsp;&nbsp;&nbsp;
</span>
);
} else {
if (!onClick) {
return (
<span style={{ color: color || "gray" }} title={label}>
{label}&nbsp;&nbsp;&nbsp;
</span>
);
}
return (
<span>
<Link
onClick={onClick}
color={color || "gray"}
component="button"
underline="none"
>
{label}
</Link>
&nbsp;&nbsp;&nbsp;
</span>
);
}
} else if (item.type === "text") {
return (
<span style={{ color: item.color || "gray" }} title={item.label}>
{item.label}&nbsp;&nbsp;&nbsp;
</span>
);
} else {
return <span>unknown toolbar item type</span>;
}
};

const NotSelectable: FunctionComponent<PropsWithChildren> = ({ children }) => {
return <div className="NotSelectable">{children}</div>;
};

const createHintTextContentWidget = (content: string | HTMLSpanElement) => {
return {
getDomNode: () => {
Expand Down
Loading

0 comments on commit ad27ddd

Please sign in to comment.