Skip to content
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

Formatting feature across all Monaco-based editors #275

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
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
33 changes: 33 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@
"regenerator-runtime": "^0.13.11",
"rehype-highlight": "^7.0.0",
"rehype-raw": "^7.0.0",
"remark": "^15.0.1",
"remark-stringify": "^11.0.0",
"shepherd.js": "^13.0.3",
"styled-components": "^6.1.12",
"ts-debounce": "^4.0.0",
Expand Down
30 changes: 22 additions & 8 deletions src/editors/editorsContainer/AgreementData.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { FaMagic } from "react-icons/fa";
import JSONEditor from "../JSONEditor";
import useAppStore from "../../store/store";
import { useCallback } from "react";
Expand All @@ -20,23 +21,36 @@ function AgreementData() {

const handleChange = (value: string | undefined) => {
if (value !== undefined) {
setEditorAgreementData(value); // Immediate state update
debouncedSetData(value); // Debounced state update
setEditorAgreementData(value);
debouncedSetData(value);
}
};

const handleFormat = () => {
try {
const formatted = JSON.stringify(JSON.parse(editorAgreementData), null, 2);
setEditorAgreementData(formatted);
} catch (error) {
alert("Invalid JSON format!");
}
};

return (
<div className="column">
<div className="tooltip">
<div className="tooltip" style={{ display: "flex", justifyContent: "space-between", alignItems: "center" }}>
<h3 style={{ color: textColor }}>Data</h3>
<span style={{ color: textColor }} className="tooltiptext">
JSON data (an instance of the Concerto model) used to preview output
from the template.
</span>
<FaMagic
style={{ cursor: "pointer", color: textColor }}
onClick={handleFormat}
title="Format JSON"
/>
</div>
<span style={{ color: textColor }} className="tooltiptext">
JSON data (an instance of the Concerto model) used to preview output from the template.
</span>
<JSONEditor value={editorAgreementData} onChange={handleChange} />
</div>
);
}

export default AgreementData;
export default AgreementData;
28 changes: 25 additions & 3 deletions src/editors/editorsContainer/TemplateMarkdown.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
import { FaMagic } from "react-icons/fa";
import MarkdownEditor from "../MarkdownEditor";
import useAppStore from "../../store/store";
import { useCallback } from "react";
import { debounce } from "ts-debounce";
import { remark } from "remark";
import remarkParse from "remark-parse";
import remarkStringify from "remark-stringify";

function TemplateMarkdown() {
const editorValue = useAppStore((state) => state.editorValue);
Expand All @@ -24,12 +28,30 @@ function TemplateMarkdown() {
}
};

const handleFormat = async () => {
try {
const formatted = await remark()
.use(remarkParse)
.use(remarkStringify)
.process(editorValue);
setEditorValue(String(formatted));
} catch (error) {
alert("Error formatting Markdown!");
}
};

return (
<div className="column" style={{ backgroundColor: backgroundColor }}>
<h2 style={{ color: textColor }}>TemplateMark</h2>
<div className="tooltip" style={{ display: "flex", justifyContent: "space-between", alignItems: "center" }}>
<h2 style={{ color: textColor }}>TemplateMark</h2>
<FaMagic
style={{ cursor: "pointer", color: textColor }}
onClick={handleFormat}
title="Format Markdown"
/>
</div>
<p style={{ color: textColor }}>
A natural language template with embedded variables, conditional
sections, and TypeScript code.
A natural language template with embedded variables, conditional sections, and TypeScript code.
</p>
<MarkdownEditor value={editorValue} onChange={handleChange} />
</div>
Expand Down
67 changes: 63 additions & 4 deletions src/editors/editorsContainer/TemplateModel.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { FaMagic } from "react-icons/fa";
import ConcertoEditor from "../ConcertoEditor";
import useAppStore from "../../store/store";
import { useCallback } from "react";
Expand All @@ -23,14 +24,72 @@ function TemplateModel() {
}
};

const handleFormat = () => {
try {
// Split into lines and filter out empty ones
const lines = editorModelCto.split("\n").map(line => line.trim()).filter(line => line.length > 0);
let indentLevel = 0;
const formattedLines = [];

for (let i = 0; i < lines.length; i++) {
let line = lines[i];
const isClosingBrace = line.startsWith("}");

// Decrease indent before adding the line if it's a closing brace
if (isClosingBrace) {
indentLevel = Math.max(0, indentLevel - 1);
}

const indent = " ".repeat(indentLevel);

// Handle concept declaration with opening brace
if (line.startsWith("concept") && !line.endsWith("{")) {
formattedLines.push(`${indent}${line} {`);
indentLevel++;
}
// Handle closing brace
else if (isClosingBrace) {
formattedLines.push(`${indent}}`);
}
// Handle fields (lines starting with "o")
else if (line.startsWith("o")) {
// Split multiple "o" declarations on the same line
const fields = line.split(/(?=o\s)/).map(field => field.trim());
fields.forEach(field => {
if (field) formattedLines.push(`${indent}${field}`);
});
}
// Handle lines that already have an opening brace
else if (line.includes("{")) {
formattedLines.push(`${indent}${line}`);
indentLevel++;
}
// Default case: just add the line with current indent
else {
formattedLines.push(`${indent}${line}`);
}
}

const formatted = formattedLines.join("\n");
setEditorModelCto(formatted);
} catch (error) {
alert("Error formatting Concerto model!");
}
};

return (
<div className="column">
<div className="tooltip">
<div className="tooltip" style={{ display: "flex", justifyContent: "space-between", alignItems: "center" }}>
<h3 style={{ color: textColor }}>Concerto Model</h3>
<span style={{ color: textColor }} className="tooltiptext">
Defines the data model for the template and its logic.
</span>
<FaMagic
style={{ cursor: "pointer", color: textColor }}
onClick={handleFormat}
title="Format Concerto Model"
/>
</div>
<span style={{ color: textColor }} className="tooltiptext">
Defines the data model for the template and its logic.
</span>
<ConcertoEditor value={editorModelCto} onChange={handleChange} />
</div>
);
Expand Down