You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by ro...@apache.org on 2021/12/09 16:19:33 UTC
[sling-whiteboard] 13/18: Completions: support completion for itemList within data-sly-{list, repeat}
This is an automated email from the ASF dual-hosted git repository.
rombert pushed a commit to branch feature/vscode-htl
in repository https://gitbox.apache.org/repos/asf/sling-whiteboard.git
commit 44d5b074973e71dc7fa70ca61e12e6dfd3f0779b
Author: Robert Munteanu <ro...@apache.org>
AuthorDate: Thu Dec 9 13:07:24 2021 +0100
Completions: support completion for itemList within data-sly-{list,repeat}
---
vscode-htl/data/completions-sling.json | 39 ++++++++++++++++++
vscode-htl/src/completionData.ts | 12 ++++++
vscode-htl/src/htlCompletionItemProvider.ts | 62 ++++++++++++++---------------
vscode-htl/src/test/suite/extension.test.ts | 17 ++++++++
4 files changed, 99 insertions(+), 31 deletions(-)
diff --git a/vscode-htl/data/completions-sling.json b/vscode-htl/data/completions-sling.json
index 2a030ae..67c2dfd 100644
--- a/vscode-htl/data/completions-sling.json
+++ b/vscode-htl/data/completions-sling.json
@@ -211,5 +211,44 @@
"description": "A value map for this resource. The value map allows to read the properties of the resource"
}
]
+ },{
+ "javaType": "$io.sightly.ItemList",
+ "nestedCompletions": [
+ {
+ "name": "index",
+ "javaType": "java.lang.Integer",
+ "description": "zero-based counter `(0..length-1)`"
+ },
+ {
+ "name": "count",
+ "javaType": "java.lang.Integer",
+ "description": "one-based counter `(1..length)`"
+ },
+ {
+ "name": "first",
+ "javaType": "java.lang.Boolean",
+ "description": "`true` if the current item is the first item"
+ },
+ {
+ "name": "middle",
+ "javaType": "java.lang.Boolean",
+ "description": "`true` if the current item is neither the first nor the last item"
+ },
+ {
+ "name": "last",
+ "javaType": "java.lang.Boolean",
+ "description": "`true` if the current item is the last item"
+ },
+ {
+ "name": "odd",
+ "javaType": "java.lang.Boolean",
+ "description": "`true` if the index is odd"
+ },
+ {
+ "name": "even",
+ "javaType": "java.lang.Boolean",
+ "description": "`true` if the index is even"
+ }
+ ]
}]
}
\ No newline at end of file
diff --git a/vscode-htl/src/completionData.ts b/vscode-htl/src/completionData.ts
index 38b77cf..0b869a3 100644
--- a/vscode-htl/src/completionData.ts
+++ b/vscode-htl/src/completionData.ts
@@ -40,4 +40,16 @@ export class CompletionDataAccess {
}
return definition.nestedCompletions;
}
+}
+
+export class LocalCompletionDefinition implements CompletionDefinition {
+ name: string;
+ javaType: string;
+ description: string;
+
+ constructor(name: string, javaType: string, description: string) {
+ this.javaType = javaType;
+ this.name = name;
+ this.description = description;
+ }
}
\ No newline at end of file
diff --git a/vscode-htl/src/htlCompletionItemProvider.ts b/vscode-htl/src/htlCompletionItemProvider.ts
index 8324a43..d0601ad 100644
--- a/vscode-htl/src/htlCompletionItemProvider.ts
+++ b/vscode-htl/src/htlCompletionItemProvider.ts
@@ -4,7 +4,7 @@ import * as vscode from 'vscode';
// HTML parser module used to provide context-sensitive completion
import { parse } from 'node-html-parser';
import { readFileSync } from 'fs';
-import {CompletionDataAccess, CompletionDefinition} from './completionData';
+import {CompletionDataAccess, CompletionDefinition, LocalCompletionDefinition} from './completionData';
const slyUseRegexp = /data-sly-use\.([a-zA-Z0-9]+)=/g;
const identifierAccess = /([a-zA-Z0-9]+)\./g;
@@ -30,9 +30,33 @@ export class HtlCompletionItemProvider implements vscode.CompletionItemProvider
}
let completionContext = linePrefix.substring(completionStart + 2).trim();
- let completionProperties = this.completionData.getGlobalCompletions();
+
+ // 1. propose completions based on HTML document
+ let documentCompletions: CompletionDefinition[] = [];
+ let htmlDoc = parse(doc);
+ let elements = htmlDoc.getElementsByTagName("*");
+ // TODO - provide only relevant completions based on the position in the document
+ elements
+ .filter( e => e.rawAttrs.indexOf('data-sly-') >= 0 )
+ .forEach(e => {
+ // element.attributes parses data-sly-use.foo="bar" incorrectly into {data-sly-use="", foo="bar"}
+ let rawAttrs = e.rawAttrs;
+ for ( const match of rawAttrs.matchAll(slyUseRegexp) ) {
+ documentCompletions.push(new LocalCompletionDefinition(match[1], "java.lang.Object", ""));
+ }
+ if ( rawAttrs.indexOf('data-sly-repeat=') >= 0 || rawAttrs.indexOf('data-sly-list') >= 0) {
+ // TODO - resolve item if possible
+ documentCompletions.push(new LocalCompletionDefinition("item", "java.lang.Object", ""));
+ documentCompletions.push(new LocalCompletionDefinition("itemList", "$io.sightly.ItemList", ""));
+ }
+ // TODO - support named data-sly-repeat completions, e.g. data-sly-repeat.meh=...
+ });
+
+ let completionProperties = this.completionData.getGlobalCompletions().concat(documentCompletions);
+
let completionCandidate = "";
+ // 2. recursively resolve any nested properties
for ( const match of completionContext.matchAll(identifierAccess)) {
completionCandidate = match[1];
let matchingDefinition = completionProperties.find( e => e.name === completionCandidate );
@@ -44,35 +68,8 @@ export class HtlCompletionItemProvider implements vscode.CompletionItemProvider
}
}
- let completions: vscode.CompletionItem[] = [];
-
- // top-level matches, propose completions based on HTML document
- if ( !completionCandidate ) {
- let htmlDoc = parse(doc);
- let elements = htmlDoc.getElementsByTagName("*");
- // TODO - provide only relevant completions based on the position in the document
- elements
- .filter( e => e.rawAttrs.indexOf('data-sly-') >= 0 )
- .forEach(e => {
- // element.attributes parses data-sly-use.foo="bar" incorrectly into {data-sly-use="", foo="bar"}
- let rawAttrs = e.rawAttrs;
- for ( const match of rawAttrs.matchAll(slyUseRegexp) ) {
- completions.push(new vscode.CompletionItem(match[1]));
- }
- if ( rawAttrs.indexOf('data-sly-repeat=') >= 0 ) {
- completions.push(new vscode.CompletionItem("item"));
- completions.push(new vscode.CompletionItem("itemList")); // TODO - expand completions for itemList
- }
- // TODO - support named data-sly-repeat completions, e.g. data-sly-repeat.meh=...
- });
- }
-
// provide completions based on properties ( top-level bindings or nested ones)
- completionProperties.forEach ( element => {
- completions.push( this.toCompletionItem(element) );
- });
-
- return completions;
+ return completionProperties.map ( element => this.toCompletionItem(element) );
}
private toCompletionItem(completionDefinition: CompletionDefinition) {
@@ -82,7 +79,10 @@ export class HtlCompletionItemProvider implements vscode.CompletionItemProvider
description = completionDefinition.description + "\n\n";
}
- description += "Type: _" + completionDefinition.javaType+"_";
+ // filter out synthetic types
+ if ( completionDefinition.javaType.charAt(0) !== '$') {
+ description += "Type: _" + completionDefinition.javaType+"_";
+ }
item.documentation = new vscode.MarkdownString(description);
return item;
diff --git a/vscode-htl/src/test/suite/extension.test.ts b/vscode-htl/src/test/suite/extension.test.ts
index d3473aa..706e0f0 100644
--- a/vscode-htl/src/test/suite/extension.test.ts
+++ b/vscode-htl/src/test/suite/extension.test.ts
@@ -51,6 +51,23 @@ suite('Extension Test Suite', () => {
assert.deepStrictEqual(completionVariables?.sort(), ["item", "itemList", "properties", "request", "resolver", "resource", "response"]);
});
+ test('completion test with data-sly-list', () => {
+ let document = `
+ <html>
+ <body data-sly-list="\${pageItems}">
+ <div>\${ itemList. }</div>
+ </body>
+ </html>
+ `;
+ let completions = completionProvider.provideCompletionItems0('<div>${', document);
+ let completionVariables = completions?.map ( c => c.label.toString());
+ assert.deepStrictEqual(completionVariables?.sort(), ["item", "itemList", "properties", "request", "resolver", "resource", "response"]);
+
+ let itemListCompletions = completionProvider.provideCompletionItems0('<div>${ itemList.', document);
+ let itemListVariables = itemListCompletions?.map ( c => c.label.toString());
+ assert.deepStrictEqual(itemListVariables?.sort(), ["index", "count", "first", "middle", "last", "odd", "even"].sort());
+ });
+
test('completion test for request', () => {
let document = `
<html>