add threshold attribute to WHILE tag

This commit is contained in:
2026-08-19 14:12:26 +02:00
parent 15422cca1f
commit 300864a15e
7 changed files with 61 additions and 25 deletions
+4 -3
View File
@@ -16,7 +16,7 @@ Syntax highlighting and language support for **EFTL (ElixForms Template Language
- `[EFTL]...[/EFTL]` - Main EFTL block - `[EFTL]...[/EFTL]` - Main EFTL block
- `[VAR name="..." type="..."]...[/VAR]` - Variable declarations - `[VAR name="..." type="..."]...[/VAR]` - Variable declarations
- `[IF]...[/IF]` - Conditionals - `[IF]...[/IF]` - Conditionals
- `[WHILE]...[/WHILE]` - Loops - `[WHILE threshold="..."]...[/WHILE]` - Loops with an optional string threshold
### Expressions ### Expressions
@@ -40,7 +40,7 @@ Syntax highlighting and language support for **EFTL (ElixForms Template Language
### Control Structures ### Control Structures
- `[IF]`, `[CONDITION]`, `[THEN]`, `[ELSE]`, `[ELSE IF]` - `[IF]`, `[CONDITION]`, `[THEN]`, `[ELSE]`, `[ELSE IF]`
- `[WHILE]`, `[DO]` - `[WHILE]`, `[WHILE threshold="..."]`, `[DO]`
### Comments ### Comments
@@ -106,7 +106,7 @@ If you want to debug the extension or the language server:
## Snippets ## Snippets
| Prefix | Description | | Prefix | Description |
| ----------- | ---------------------- | | ---------------- | ------------------------- |
| `eftl` | EFTL block with header | | `eftl` | EFTL block with header |
| `var` | Variable declaration | | `var` | Variable declaration |
| `vartag` | Variable from TAG | | `vartag` | Variable from TAG |
@@ -114,6 +114,7 @@ If you want to debug the extension or the language server:
| `if` | IF statement | | `if` | IF statement |
| `ifelse` | IF-ELSE statement | | `ifelse` | IF-ELSE statement |
| `while` | WHILE loop | | `while` | WHILE loop |
| `whilethreshold` | WHILE loop with threshold |
| `split` | Split function | | `split` | Split function |
| `trim` | Trim function | | `trim` | Trim function |
| `valueof` | VALUE_OF function | | `valueof` | VALUE_OF function |
+1 -1
View File
@@ -8,7 +8,7 @@
[VAR name="CONTRAENTI" type="iterable"][SPLIT regex="\n"][TRIM][TAG]SCHEMAID,296,COL0004,IUQOID, , [/TAG][/TRIM][/SPLIT][/VAR] [VAR name="CONTRAENTI" type="iterable"][SPLIT regex="\n"][TRIM][TAG]SCHEMAID,296,COL0004,IUQOID, , [/TAG][/TRIM][/SPLIT][/VAR]
[VAR name="CONTRAENTI_NUM" type="number"][SIZE_OF varname="CONTRAENTI" /][/VAR] [VAR name="CONTRAENTI_NUM" type="number"][SIZE_OF varname="CONTRAENTI" /][/VAR]
[WHILE] [WHILE threshold="99"]
[CONDITION][% IDX < CONTRAENTI_NUM %][/CONDITION] [CONDITION][% IDX < CONTRAENTI_NUM %][/CONDITION]
[DO] [DO]
[VAR name="CONTRAENTE" type="string"][VALUE_OF varname="CONTRAENTI" index="IDX" /][/VAR] [VAR name="CONTRAENTE" type="string"][VALUE_OF varname="CONTRAENTI" index="IDX" /][/VAR]
+1 -1
View File
@@ -6,7 +6,7 @@
["[EFTL]", "[/EFTL]"], ["[EFTL]", "[/EFTL]"],
["[VAR", "[/VAR]"], ["[VAR", "[/VAR]"],
["[IF]", "[/IF]"], ["[IF]", "[/IF]"],
["[WHILE]", "[/WHILE]"], ["[WHILE", "[/WHILE]"],
["[FORMAT", "[/FORMAT]"], ["[FORMAT", "[/FORMAT]"],
["[CONDITION]", "[/CONDITION]"], ["[CONDITION]", "[/CONDITION]"],
["[THEN]", "[/THEN]"], ["[THEN]", "[/THEN]"],
+12
View File
@@ -79,6 +79,18 @@
], ],
"description": "Create a WHILE loop" "description": "Create a WHILE loop"
}, },
"While Loop with Threshold": {
"prefix": "whilethreshold",
"body": [
"[WHILE threshold=\"${1:99}\"]",
" [CONDITION][% ${2:condition} %][/CONDITION]",
" [DO]",
" $0",
" [/DO]",
"[/WHILE]"
],
"description": "Create a WHILE loop with a threshold"
},
"Split": { "Split": {
"prefix": "split", "prefix": "split",
"body": [ "body": [
+3
View File
@@ -128,6 +128,9 @@ export class EftlParser {
break; break;
case TokenType.WHILE_OPEN: case TokenType.WHILE_OPEN:
if (!/^\[WHILE(?:\s+threshold\s*=\s*"[^"]*")?\s*\]$/.test(token.value)) {
this.addError(token, 'WHILE accepts only the optional string attribute threshold="..."');
}
this.pushBlock(token); this.pushBlock(token);
this.advance(); this.advance();
break; break;
+6 -1
View File
@@ -21,7 +21,7 @@ export enum TokenType {
ELSE_CLOSE = 'ELSE_CLOSE', // [/ELSE] ELSE_CLOSE = 'ELSE_CLOSE', // [/ELSE]
ELSE_IF_OPEN = 'ELSE_IF_OPEN', // [ELSE IF] ELSE_IF_OPEN = 'ELSE_IF_OPEN', // [ELSE IF]
ELSE_IF_CLOSE = 'ELSE_IF_CLOSE', // [/ELSE IF] ELSE_IF_CLOSE = 'ELSE_IF_CLOSE', // [/ELSE IF]
WHILE_OPEN = 'WHILE_OPEN', // [WHILE] WHILE_OPEN = 'WHILE_OPEN', // [WHILE ...]
WHILE_CLOSE = 'WHILE_CLOSE', // [/WHILE] WHILE_CLOSE = 'WHILE_CLOSE', // [/WHILE]
DO_OPEN = 'DO_OPEN', // [DO] DO_OPEN = 'DO_OPEN', // [DO]
DO_CLOSE = 'DO_CLOSE', // [/DO] DO_CLOSE = 'DO_CLOSE', // [/DO]
@@ -192,6 +192,11 @@ export class EftlTokenizer {
this.addToken(TokenType.WHILE_OPEN, '[WHILE]', startLine, startColumn); this.addToken(TokenType.WHILE_OPEN, '[WHILE]', startLine, startColumn);
return; return;
} }
if (this.source.startsWith('[WHILE', this.pos) && /\s/.test(this.source[this.pos + '[WHILE'.length] || '')) {
this.match('[WHILE');
this.scanTagWithAttributes(TokenType.WHILE_OPEN, 'WHILE', startLine, startColumn);
return;
}
if (this.match('[/WHILE]')) { if (this.match('[/WHILE]')) {
this.addToken(TokenType.WHILE_CLOSE, '[/WHILE]', startLine, startColumn); this.addToken(TokenType.WHILE_CLOSE, '[/WHILE]', startLine, startColumn);
return; return;
+16 -1
View File
@@ -236,9 +236,24 @@
"name": "keyword.control.conditional.eftl", "name": "keyword.control.conditional.eftl",
"match": "\\[(IF|ELSE IF|ELSE|/IF|CONDITION|/CONDITION|THEN|/THEN|/ELSE IF|/ELSE)\\]" "match": "\\[(IF|ELSE IF|ELSE|/IF|CONDITION|/CONDITION|THEN|/THEN|/ELSE IF|/ELSE)\\]"
}, },
{
"name": "meta.control.loop.eftl",
"begin": "(\\[)(WHILE)\\b",
"end": "(\\])",
"beginCaptures": {
"1": { "name": "keyword.control.loop.eftl" },
"2": { "name": "keyword.control.loop.eftl" }
},
"endCaptures": {
"1": { "name": "keyword.control.loop.eftl" }
},
"patterns": [
{ "include": "#attributes" }
]
},
{ {
"name": "keyword.control.loop.eftl", "name": "keyword.control.loop.eftl",
"match": "\\[(WHILE|/WHILE|DO|/DO)\\]" "match": "\\[(/WHILE|DO|/DO)\\]"
} }
] ]
}, },