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:34 UTC

[sling-whiteboard] 14/18: Completions: support completions based on data-sly-list

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 59267375bf1e70b076bed9ff6a74142be7cc5cf6
Author: Robert Munteanu <ro...@apache.org>
AuthorDate: Thu Dec 9 13:41:23 2021 +0100

    Completions: support completions based on data-sly-list
---
 vscode-htl/src/htlCompletionItemProvider.ts | 32 ++++++++++++++++++++---------
 vscode-htl/src/test/suite/extension.test.ts | 14 +++++++++++++
 2 files changed, 36 insertions(+), 10 deletions(-)

diff --git a/vscode-htl/src/htlCompletionItemProvider.ts b/vscode-htl/src/htlCompletionItemProvider.ts
index d0601ad..b952beb 100644
--- a/vscode-htl/src/htlCompletionItemProvider.ts
+++ b/vscode-htl/src/htlCompletionItemProvider.ts
@@ -8,6 +8,7 @@ import {CompletionDataAccess, CompletionDefinition, LocalCompletionDefinition} f
 
 const slyUseRegexp = /data-sly-use\.([a-zA-Z0-9]+)=/g;
 const identifierAccess = /([a-zA-Z0-9]+)\./g;
+const slyListOrRepeat = /data-sly-(list|repeat)="\${([a-zA-Z0-9\.]+)}"/g;
 
 export class HtlCompletionItemProvider implements vscode.CompletionItemProvider {
 
@@ -44,32 +45,44 @@ export class HtlCompletionItemProvider implements vscode.CompletionItemProvider
                 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", ""));
+                // assumption: we don't have both attributes in a single tag
+                for ( const match of rawAttrs.matchAll(slyListOrRepeat) ) {
+                    let javaType, ignored;
+                    [javaType, ignored] = this.resolveReference(match[2], this.completionData.getGlobalCompletions());
+                    documentCompletions.push(new LocalCompletionDefinition("item", javaType ?? "java.lang.Object", ""));
                     documentCompletions.push(new LocalCompletionDefinition("itemList", "$io.sightly.ItemList", ""));
+                    break;
                 }
                 // TODO - support named data-sly-repeat completions, e.g. data-sly-repeat.meh=...
             });
 
         let completionProperties = this.completionData.getGlobalCompletions().concat(documentCompletions);
-
-        let completionCandidate = "";
+        let javaType;
 
         // 2. recursively resolve any nested properties
+        [javaType, completionProperties] = this.resolveReference(completionContext, completionProperties);
+
+        // provide completions based on properties ( top-level bindings or nested ones)
+        return completionProperties.map ( element =>  this.toCompletionItem(element) );
+    }
+
+    private resolveReference(completionContext: string, globalCompletionDefinitions: CompletionDefinition[]): [string | undefined, CompletionDefinition[] ] {
+        let completionProperties = globalCompletionDefinitions;
+        let javaType = undefined;
         for ( const match of completionContext.matchAll(identifierAccess)) {
-            completionCandidate = match[1];
+            let completionCandidate = match[1];
             let matchingDefinition = completionProperties.find( e => e.name === completionCandidate );
             if ( matchingDefinition ) {
-                completionProperties = this.completionData.findPropertyCompletions(matchingDefinition.javaType);
+                javaType = matchingDefinition.javaType;
+                completionProperties = this.completionData.findPropertyCompletions(javaType);
             } else {
+                javaType = undefined;
                 completionProperties = [];
                 break;
             }
         }
 
-        // provide completions based on properties ( top-level bindings or nested ones)
-        return completionProperties.map ( element =>  this.toCompletionItem(element) );
+        return [javaType, completionProperties];
     }
 
     private toCompletionItem(completionDefinition: CompletionDefinition) {
@@ -86,6 +99,5 @@ export class HtlCompletionItemProvider implements vscode.CompletionItemProvider
         item.documentation = new vscode.MarkdownString(description);
         
         return item;
-        
     }
 }
\ No newline at end of file
diff --git a/vscode-htl/src/test/suite/extension.test.ts b/vscode-htl/src/test/suite/extension.test.ts
index 706e0f0..2b5354a 100644
--- a/vscode-htl/src/test/suite/extension.test.ts
+++ b/vscode-htl/src/test/suite/extension.test.ts
@@ -68,6 +68,20 @@ suite('Extension Test Suite',  () => {
 		assert.deepStrictEqual(itemListVariables?.sort(), ["index", "count", "first", "middle", "last", "odd", "even"].sort());
 	});
 
+	test('completion test with data-sly-list and known item', () => {
+		let document = `
+			<html>
+				<body data-sly-list="\${resource.parent.children}">
+					<div>\${ item. }</div>
+				</body>
+			</html>
+		`;
+		let completions = completionProvider.provideCompletionItems0('<div>${ item.', document);
+		// test a subset, otherwise it's too cumbersome
+		let completionVariables = completions?.map ( c => c.label.toString()).slice(0,5);
+		assert.deepStrictEqual(completionVariables?.sort(), ["children", "name", "parent", "path", "resourceType"]);
+	});
+
 	test('completion test for request', () => {
 		let document = `
 			<html>