Added schema + array and string type

This commit is contained in:
Elio Struyf
2022-03-03 21:05:41 +01:00
parent f35d8c8332
commit eeb1fc9cb4
4 changed files with 53 additions and 156 deletions
@@ -43,7 +43,7 @@ export const Item: React.FunctionComponent<IItemProps> = ({ title, snippet }: Re
const onOpenEdit = useCallback(() => {
setSnippetTitle(title);
setSnippetDescription(snippet.description);
setSnippetOriginalBody(snippet.body.join(`\n`));
setSnippetOriginalBody(typeof snippet.body === "string" ? snippet.body : snippet.body.join(`\n`));
setShowEditDialog(true);
}, [snippet]);
@@ -54,9 +54,10 @@ export const Item: React.FunctionComponent<IItemProps> = ({ title, snippet }: Re
}
const snippets = Object.assign({}, settings?.snippets || {});
const snippetLines = snippetOriginalBody.split("\n");
const snippetContents = {
description: snippetDescription || '',
body: snippetOriginalBody.split("\n")
body: snippetLines.length === 1 ? snippetLines[0] : snippetLines
};
if (title === snippetTitle) {
@@ -42,7 +42,7 @@ const SnippetForm: React.ForwardRefRenderFunction<SnippetFormHandle, ISnippetFor
}, [selection]);
const snippetBody = useMemo(() => {
let body = snippet.body.join(`\n`);
let body = typeof snippet.body === "string" ? snippet.body : snippet.body.join(`\n`);
for (const field of fields) {
body = body.replace(field.tmString, field.value);
@@ -51,6 +51,14 @@ const SnippetForm: React.ForwardRefRenderFunction<SnippetFormHandle, ISnippetFor
return body;
}, [fields, selection]);
const shouldShowField = (fieldName: string, idx: number, allFields: SnippetField[]) => {
const crntField = allFields.findIndex(f => f.name === fieldName);
if (crntField < idx) {
return false;
}
return true;
}
useImperativeHandle(ref, () => ({
onSave() {
if (!snippetBody) {
@@ -66,7 +74,7 @@ const SnippetForm: React.ForwardRefRenderFunction<SnippetFormHandle, ISnippetFor
useEffect(() => {
const snippetParser = new SnippetParser();
const body = snippet.body.join(`\n`);
const body = typeof snippet.body === "string" ? snippet.body : snippet.body.join(`\n`);
const parsed = snippetParser.parse(body);
const placeholders = parsed.placeholderInfo.all;
@@ -76,6 +84,8 @@ const SnippetForm: React.ForwardRefRenderFunction<SnippetFormHandle, ISnippetFor
for (const placeholder of placeholders) {
const tmString = placeholder.toTextmateString();
console.log(tmString)
if (placeholder.children.length === 0) {
allFields.push({
type: 'text',
@@ -118,40 +128,42 @@ const SnippetForm: React.ForwardRefRenderFunction<SnippetFormHandle, ISnippetFor
<div className='space-y-4 mt-4'>
{
fields.map((field: SnippetField, index: number) => (
<div key={index}>
<label htmlFor={field.name} className="block text-sm font-medium capitalize">
{field.name}
</label>
<div className="mt-1">
{
field.type === 'select' ? (
<div className='relative'>
<select
name={field.name}
value={field.value || ""}
className="focus:outline-none block w-full sm:text-sm border-gray-300 text-vulcan-500"
onChange={e => onTextChange(field, e.target.value)}>
{
field.options?.map((option: string, index: number) => (
<option key={index} value={option}>{option}</option>
))
}
</select>
fields.map((field: SnippetField, index: number, allFields: SnippetField[]) => (
shouldShowField(field.name, index, allFields) && (
<div key={index}>
<label htmlFor={field.name} className="block text-sm font-medium capitalize">
{field.name}
</label>
<div className="mt-1">
{
field.type === 'select' ? (
<div className='relative'>
<select
name={field.name}
value={field.value || ""}
className="focus:outline-none block w-full sm:text-sm border-gray-300 text-vulcan-500"
onChange={e => onTextChange(field, e.target.value)}>
{
field.options?.map((option: string, index: number) => (
<option key={index} value={option}>{option}</option>
))
}
</select>
<ChevronDownIcon className="absolute top-3 right-2 w-4 h-4 text-gray-500" />
</div>
) : (
<textarea
name={field.name}
value={field.value || ""}
className="focus:outline-none block w-full sm:text-sm border-gray-300 text-vulcan-500"
onChange={(e) => onTextChange(field, e.currentTarget.value)}
/>
)
}
<ChevronDownIcon className="absolute top-3 right-2 w-4 h-4 text-gray-500" />
</div>
) : (
<textarea
name={field.name}
value={field.value || ""}
className="focus:outline-none block w-full sm:text-sm border-gray-300 text-vulcan-500"
onChange={(e) => onTextChange(field, e.currentTarget.value)}
/>
)
}
</div>
</div>
</div>
)
))
}
</div>
+1 -119
View File
@@ -695,125 +695,7 @@ export class SnippetParser {
}
private _parse(marker: Marker): boolean {
return this._parseEscaped(marker)
|| this._parseTabstopOrVariableName(marker)
|| this._parseComplexPlaceholder(marker)
|| this._parseComplexVariable(marker)
|| this._parseAnything(marker);
}
// \$, \\, \} -> just text
private _parseEscaped(marker: Marker): boolean {
let value: string;
if (value = this._accept(TokenType.Backslash, true)) {
// saw a backslash, append escaped token or that backslash
value = this._accept(TokenType.Dollar, true)
|| this._accept(TokenType.CurlyClose, true)
|| this._accept(TokenType.Backslash, true)
|| value;
marker.appendChild(new Text(value));
return true;
}
return false;
}
// $foo -> variable, $1 -> tabstop
private _parseTabstopOrVariableName(parent: Marker): boolean {
let value: string;
const token = this._token;
const match = this._accept(TokenType.Dollar)
&& (value = this._accept(TokenType.VariableName, true) || this._accept(TokenType.Int, true));
if (!match) {
return this._backTo(token);
}
parent.appendChild(/^\d+$/.test(value!)
? new Placeholder(Number(value!))
: new Variable(value!)
);
return true;
}
// ${1:<children>}, ${1} -> placeholder
private _parseComplexPlaceholder(parent: Marker): boolean {
let index: string;
const token = this._token;
const match = this._accept(TokenType.Dollar)
&& this._accept(TokenType.CurlyOpen)
&& (index = this._accept(TokenType.Int, true));
if (!match) {
return this._backTo(token);
}
const placeholder = new Placeholder(Number(index!));
if (this._accept(TokenType.Colon)) {
// ${1:<children>}
while (true) {
// ...} -> done
if (this._accept(TokenType.CurlyClose)) {
parent.appendChild(placeholder);
return true;
}
if (this._parse(placeholder)) {
continue;
}
// fallback
parent.appendChild(new Text('${' + index! + ':'));
placeholder.children.forEach(parent.appendChild, parent);
return true;
}
} else if (placeholder.index > 0 && this._accept(TokenType.Pipe)) {
// ${1|one,two,three|}
const choice = new Choice();
while (true) {
if (this._parseChoiceElement(choice)) {
if (this._accept(TokenType.Comma)) {
// opt, -> more
continue;
}
if (this._accept(TokenType.Pipe)) {
placeholder.appendChild(choice);
if (this._accept(TokenType.CurlyClose)) {
// ..|} -> done
parent.appendChild(placeholder);
return true;
}
}
}
this._backTo(token);
return false;
}
} else if (this._accept(TokenType.Forwardslash)) {
// ${1/<regex>/<format>/<options>}
if (this._parseTransform(placeholder)) {
parent.appendChild(placeholder);
return true;
}
this._backTo(token);
return false;
} else if (this._accept(TokenType.CurlyClose)) {
// ${1}
parent.appendChild(placeholder);
return true;
} else {
// ${1 <- missing curly or colon
return this._backTo(token);
}
return this._parseComplexVariable(marker) || this._parseAnything(marker);
}
private _parseChoiceElement(parent: Choice): boolean {
+3 -1
View File
@@ -39,9 +39,11 @@ export class SnippetListener extends BaseListener {
return;
}
const snippetLines = body.split("\n");
snippets[title] = {
description,
body: body.split("\n")
body: snippetLines.length === 1 ? snippetLines[0] : snippetLines
};
Settings.update(SETTING_CONTENT_SNIPPETS, snippets, true);