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:25 UTC
[sling-whiteboard] 05/18: Move global completions to a JSON file, add some more of them.
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 ea71cc4d5713b8ba097d7d70e4135428200e833d
Author: Robert Munteanu <ro...@apache.org>
AuthorDate: Wed Dec 8 17:48:34 2021 +0100
Move global completions to a JSON file, add some more of them.
---
vscode-htl/data/completions-sling.json | 132 ++++++++++++++++++++++++++++
vscode-htl/src/extension.ts | 62 ++-----------
vscode-htl/src/htlCompletionItemProvider.ts | 66 +++++++++++++-
vscode-htl/src/test/suite/extension.test.ts | 46 +++++++++-
4 files changed, 242 insertions(+), 64 deletions(-)
diff --git a/vscode-htl/data/completions-sling.json b/vscode-htl/data/completions-sling.json
new file mode 100644
index 0000000..f35545c
--- /dev/null
+++ b/vscode-htl/data/completions-sling.json
@@ -0,0 +1,132 @@
+{
+ "globalCompletions": [
+ {
+ "name": "properties",
+ "javaType": "org.apache.sling.api.resource.ValueMap",
+ "description": "List of properties of the current Resource. Backed by _org.apache.sling.api.resource.ValueMap_"
+ },
+ {
+ "name": "request",
+ "javaType": "org.apache.sling.api.SlingHttpServletRequest",
+ "description": "The current request. Backed by _org.apache.sling.api.SlingHttpServletRequest_"
+ },
+ {
+ "name": "resolver",
+ "javaType": "org.apache.sling.api.resource.ResourceResolver"
+ },
+ {
+ "name": "resource",
+ "javaType": "org.apache.sling.api.resource.Resource"
+ },
+ {
+ "name": "response",
+ "javaType": "org.apache.sling.api.SlingHttpServletResponse"
+ }
+ ],
+ "completionProperties": [{
+ "javaType": "org.apache.sling.api.SlingHttpServletRequest",
+ "nestedCompletions": [
+ {
+ "name": "resource",
+ "javaType": "org.apache.sling.api.Resource"
+ },
+ {
+ "name": "resourceResolver",
+ "javaType": "org.apache.sling.api.ResourceResolver"
+ },
+ {
+ "name": "requestPathInfo",
+ "javaType": "org.apache.sling.api.request.RequestPathInfo"
+ },
+ {
+ "name": "requestParameterMap",
+ "javaType": "org.apache.sling.api.request.RequestParameterMap"
+ },
+ {
+ "name": "requestParameterList",
+ "javaType": "java.util.List<String>"
+ },
+ {
+ "name": "responseContentType",
+ "javaType": "java.lang.String"
+ },
+ {
+ "name": "requestProgressTracker",
+ "javaType": "java.util.Enumeration<String>"
+ },
+ {
+ "name": "authType",
+ "javaType": "java.lang.String"
+ },
+ {
+ "name": "cookies",
+ "javaType": "javax.http.servlet.Cookie[]"
+ },
+ {
+ "name": "headerNames",
+ "javaType": "java.util.Enumeration<String>"
+ },
+ {
+ "name": "method",
+ "javaType": "java.lang.String"
+ },
+ {
+ "name": "pathInfo",
+ "javaType": "java.lang.String"
+ },
+ {
+ "name": "pathTranslated",
+ "javaType": "java.lang.String"
+ },
+ {
+ "name": "contextPath",
+ "javaType": "java.lang.String"
+ },
+ {
+ "name": "queryString",
+ "javaType": "java.lang.String"
+ },
+ {
+ "name": "remoteUser",
+ "javaType": "java.lang.String"
+ },
+ {
+ "name": "userPrincipal",
+ "javaType": "java.security.Principal"
+ },
+ {
+ "name": "requestedSessionId",
+ "javaType": "java.lang.String"
+ },
+ {
+ "name": "requestURI",
+ "javaType": "java.lang.String"
+ },
+ {
+ "name": "requestURL",
+ "javaType": "java.lang.StringBuffer"
+ },
+ {
+ "name": "servletPath",
+ "javaType": "java.lang.String"
+ },
+ {
+ "name": "session",
+ "javaType": "javax.servlet.http.HttpSession"
+ },
+ {
+ "name": "requestedSessionIdValid",
+ "javaType": "boolean"
+ },
+ {
+ "name": "requestedSessionIdFromCookie",
+ "javaType": "boolean"
+ },
+ {
+ "name": "requestedSessionIdFromURL",
+ "javaType": "boolean"
+ }
+
+ ]
+ }]
+}
\ No newline at end of file
diff --git a/vscode-htl/src/extension.ts b/vscode-htl/src/extension.ts
index 8361de9..2e7bae5 100644
--- a/vscode-htl/src/extension.ts
+++ b/vscode-htl/src/extension.ts
@@ -1,11 +1,7 @@
-// The module 'vscode' contains the VS Code extensibility API
-// Import the module and reference it with the alias vscode in your code below
+// the module 'vscode' contains the VS Code extensibility API
import * as vscode from 'vscode';
-
-// HTML parser module used to provide context-sensitive completion
-import { parse } from 'node-html-parser';
-
-const slyUseRegexp = /data-sly-use\.([a-zA-Z0-9]+)=/g;
+// import our own completion provider
+import { HtlCompletionItemProvider } from './htlCompletionItemProvider';
// this method is called when your extension is activated
// your extension is activated the very first time the command is executed
@@ -28,57 +24,9 @@ export function activate(context: vscode.ExtensionContext) {
context.subscriptions.push(helloWorld, now);
- vscode.languages.registerCompletionItemProvider('html', {
- provideCompletionItems(document: vscode.TextDocument, position: vscode.Position, token: vscode.CancellationToken, context: vscode.CompletionContext) {
-
- let lineUntilPosition = document.getText(new vscode.Range(position.with(undefined, 0), position));
- if ( lineUntilPosition.indexOf('${') === -1 ) {
- return null;
- }
- // request-specific branch
- if ( lineUntilPosition.endsWith('request.') ) {
- return [
- new vscode.CompletionItem('resource'),
- new vscode.CompletionItem('resourceResolver'),
- new vscode.CompletionItem('requestPathInfo'),
- new vscode.CompletionItem('contextPath')
- ];
- } else {
+ let completionsPath = vscode.Uri.joinPath(context.extensionUri, "data");
- let generalCompletions = [];
-
- // TODO - provide completions for all global bindings
- let props = new vscode.CompletionItem('properties');
- props.documentation = new vscode.MarkdownString('List of properties of the current Resource. Backed by _org.apache.sling.api.resource.ValueMap_');
- generalCompletions.push(props);
-
- // TODO - deep auto-completion for resource and request
- let req = new vscode.CompletionItem('request');
- req.documentation = new vscode.MarkdownString('The current request. Backed by _org.apache.sling.api.SlingHttpServletRequest_');
- generalCompletions.push(req);
-
- let htmlDoc = parse(document.getText());
- 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) ) {
- generalCompletions.push(new vscode.CompletionItem(match[1]));
- }
- if ( rawAttrs.indexOf('data-sly-repeat=') >= 0 ) {
- generalCompletions.push(new vscode.CompletionItem("item"));
- generalCompletions.push(new vscode.CompletionItem("itemList")); // TODO - expand completions for itemList
- }
- // TODO - support named data-sly-repeat completions, e.g. data-sly-repeat.meh=...
- });
-
- return generalCompletions;
- }
- }
- });
+ vscode.languages.registerCompletionItemProvider('html', new HtlCompletionItemProvider(completionsPath));
}
// this method is called when your extension is deactivated
diff --git a/vscode-htl/src/htlCompletionItemProvider.ts b/vscode-htl/src/htlCompletionItemProvider.ts
index 121914f..7f9d494 100644
--- a/vscode-htl/src/htlCompletionItemProvider.ts
+++ b/vscode-htl/src/htlCompletionItemProvider.ts
@@ -1,10 +1,70 @@
'use strict';
import * as vscode from 'vscode';
+// HTML parser module used to provide context-sensitive completion
+import { parse } from 'node-html-parser';
+import { readFileSync } from 'fs';
+
+const slyUseRegexp = /data-sly-use\.([a-zA-Z0-9]+)=/g;
export class HtlCompletionItemProvider implements vscode.CompletionItemProvider {
-
- public provideCompletionItems(document: vscode.TextDocument, position: vscode.Position, token: vscode.CancellationToken, context: vscode.CompletionContext): vscode.ProviderResult<vscode.CompletionItem[] | vscode.CompletionList<vscode.CompletionItem>> {
- throw new Error('Method not implemented.');
+
+ completions: any;
+
+ constructor(completionsPath: vscode.Uri) {
+ const slingCompletions = vscode.Uri.joinPath(completionsPath, "completions-sling.json");
+ console.log("Reading completions from {}", slingCompletions.fsPath);
+ this.completions = JSON.parse(readFileSync(slingCompletions.fsPath, 'utf-8'));
+
+ }
+
+ provideCompletionItems(document: vscode.TextDocument, position: vscode.Position, token: vscode.CancellationToken, context: vscode.CompletionContext) {
+ return this.provideCompletionItems0(document.getText(new vscode.Range(position.with(undefined, 0), position)), document.getText());
+ }
+
+ provideCompletionItems0(linePrefix: string, doc: string) {
+ if ( linePrefix.indexOf('${') === -1 ) {
+ return null;
+ }
+ // request-specific branch
+ if ( linePrefix.endsWith('request.') ) {
+ return [
+ new vscode.CompletionItem('resource'),
+ new vscode.CompletionItem('resourceResolver'),
+ new vscode.CompletionItem('requestPathInfo'),
+ new vscode.CompletionItem('contextPath')
+ ];
+ } else {
+
+ let generalCompletions: vscode.CompletionItem[] = [];
+
+ this.completions.globalCompletions.forEach( (globalCompletion: any) => {
+ let vsCodeCompletion = new vscode.CompletionItem(globalCompletion.name);
+ if ( globalCompletion.description ) {
+ vsCodeCompletion.documentation = new vscode.MarkdownString(globalCompletion.description);
+ }
+ generalCompletions.push(vsCodeCompletion);
+ });
+
+ 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) ) {
+ generalCompletions.push(new vscode.CompletionItem(match[1]));
+ }
+ if ( rawAttrs.indexOf('data-sly-repeat=') >= 0 ) {
+ generalCompletions.push(new vscode.CompletionItem("item"));
+ generalCompletions.push(new vscode.CompletionItem("itemList")); // TODO - expand completions for itemList
+ }
+ // TODO - support named data-sly-repeat completions, e.g. data-sly-repeat.meh=...
+ });
+
+ return generalCompletions;
+ }
}
}
\ 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 4ca0ab4..b42e6bc 100644
--- a/vscode-htl/src/test/suite/extension.test.ts
+++ b/vscode-htl/src/test/suite/extension.test.ts
@@ -1,15 +1,53 @@
import * as assert from 'assert';
+import { HtlCompletionItemProvider } from '../../htlCompletionItemProvider';
// You can import and use all API from the 'vscode' module
// as well as import your extension to test it
import * as vscode from 'vscode';
// import * as myExtension from '../../extension';
-suite('Extension Test Suite', () => {
+suite('Extension Test Suite', () => {
vscode.window.showInformationMessage('Start all tests.');
+ const workingDir = vscode.Uri.parse("file://" + __dirname, true);
+ const completionsPath = vscode.Uri.joinPath(workingDir, "..", "..", "..", "data");
+ const completionProvider = new HtlCompletionItemProvider(completionsPath);
+
+ test('completion test with no additional structures', () => {
+ let document = `
+ <html>
+ <body>
+ \${ }
+ </body>
+ </html>
+ `;
+ let completions = completionProvider.provideCompletionItems0('${', document);
+ let completionVariables = completions?.map ( c => c.label.toString());
+ assert.deepStrictEqual(completionVariables?.sort(), ["properties", "request", "resolver", "resource", "response"]);
+ });
+
+ test('completion test with data-sly-use', () => {
+ let document = `
+ <html>
+ <body data-sly-use.foo="foo.js">
+ \${ }
+ </body>
+ </html>
+ `;
+ let completions = completionProvider.provideCompletionItems0('${', document);
+ let completionVariables = completions?.map ( c => c.label.toString());
+ assert.deepStrictEqual(completionVariables?.sort(), ["foo", "properties", "request", "resolver", "resource", "response"]);
+ });
- test('Sample test', () => {
- assert.strictEqual(-1, [1, 2, 3].indexOf(5));
- assert.strictEqual(-1, [1, 2, 3].indexOf(0));
+ test('completion test with data-sly-repeat', () => {
+ let document = `
+ <html>
+ <body data-sly-repeat="\${pageItems}">
+ \${ }
+ </body>
+ </html>
+ `;
+ let completions = completionProvider.provideCompletionItems0('${', document);
+ let completionVariables = completions?.map ( c => c.label.toString());
+ assert.deepStrictEqual(completionVariables?.sort(), ["item", "itemList", "properties", "request", "resolver", "resource", "response"]);
});
});