Skip to content

Commit 2d56c72

Browse files
committed
Added validate command.
1 parent 8e158d4 commit 2d56c72

File tree

5 files changed

+87
-9
lines changed

5 files changed

+87
-9
lines changed

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,11 @@
22

33
All notable changes to the extension will be documented in this file.
44

5+
## [1.8.0] - 2021-01-11
6+
7+
- Added validate command.
8+
- Allow multi level inheritance.
9+
510
## [1.7.2] - 2021-01-10
611

712
- Update internals.

README.md

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ Template inheritance is supported for the following tags:
8383
{{> base }}
8484
```
8585

86-
Only one level of inheritance is supported:
86+
Styles defined in `base.html` will also be available for completion in `home.html`:
8787

8888
**`base.html`**
8989
```html
@@ -114,8 +114,6 @@ Only one level of inheritance is supported:
114114
</html>
115115
```
116116

117-
Styles defined in `base.html` will also be available for completion in `home.html`:
118-
119117
**`home.html`**
120118
```html
121119
{% extends "base" %}
@@ -161,6 +159,12 @@ Extension can be configured to support any language where it makes sense such as
161159

162160
This setting is application scoped and changing the setting requires restarting VS Code.
163161

162+
## Commands
163+
164+
### Validate Attributes
165+
166+
Validates all `id` and `class` attributes in the active editor.
167+
164168
## Installation
165169

166170
Extension can be installed from [Visual Studio Code Marketplace](https://marketplace.visualstudio.com/items?itemName=ecmel.vscode-html-css).

package.json

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"name": "vscode-html-css",
33
"displayName": "HTML CSS Support",
44
"description": "CSS Intellisense for HTML",
5-
"version": "1.7.2",
5+
"version": "1.8.0",
66
"publisher": "ecmel",
77
"license": "MIT",
88
"homepage": "https://github.com/ecmel/vscode-html-css",
@@ -54,7 +54,13 @@
5454
"default": []
5555
}
5656
}
57-
}
57+
},
58+
"commands": [
59+
{
60+
"command": "vscode-html-css.validate",
61+
"title": "CSS: Validate Attributes"
62+
}
63+
]
5864
},
5965
"main": "./dist/extension.js",
6066
"scripts": {

src/completion.ts

Lines changed: 49 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ import {
88
CompletionItemKind,
99
CompletionItemProvider,
1010
CompletionList,
11+
Diagnostic,
12+
DiagnosticSeverity,
1113
Disposable,
1214
Position,
1315
ProviderResult,
@@ -171,10 +173,12 @@ export class SelectorCompletionItemProvider implements CompletionItemProvider, D
171173
}
172174
}
173175

174-
async findExtendedStyles(uri: Uri, keys: Set<string>, text: string): Promise<void> {
176+
async findExtendedStyles(uri: Uri, keys: Set<string>, text: string, level: number = 0): Promise<void> {
175177
const extended = this.findExtended.exec(text);
176178

177-
if (extended) {
179+
if (extended && level < 3) {
180+
level++;
181+
178182
const name = extended[2];
179183
const ext = extname(name) || extname(uri.fsPath);
180184
const key = this.getRelativePath(uri, name, ext);
@@ -185,7 +189,9 @@ export class SelectorCompletionItemProvider implements CompletionItemProvider, D
185189
const text = content.toString();
186190

187191
this.findDocumentStyles(file, keys, text);
192+
188193
await this.findDocumentLinks(file, keys, text);
194+
await this.findExtendedStyles(file, keys, text, level);
189195
} catch (error) {
190196
}
191197
}
@@ -211,6 +217,47 @@ export class SelectorCompletionItemProvider implements CompletionItemProvider, D
211217
return { ids, classes };
212218
}
213219

220+
async validate(document: TextDocument): Promise<Diagnostic[]> {
221+
const completion = await this.findAll(document);
222+
const text = document.getText();
223+
const diagnostics: Diagnostic[] = [];
224+
const findAttribute = /(id|class|className)\s*=\s*("|')(.*?)\2/gsi;
225+
226+
let attribute;
227+
228+
while ((attribute = findAttribute.exec(text)) !== null) {
229+
const offset = findAttribute.lastIndex
230+
- attribute[3].length
231+
+ attribute[3].indexOf(attribute[2]);
232+
233+
const findSelector = /([^(\[{}\])\s]+)(?![^(\[{]*[}\])])/gi;
234+
235+
let value;
236+
237+
while ((value = findSelector.exec(attribute[3])) !== null) {
238+
const anchor = findSelector.lastIndex + offset;
239+
const end = document.positionAt(anchor);
240+
const start = document.positionAt(anchor - value[1].length);
241+
242+
if (attribute[1] === "id") {
243+
if (!completion.ids.has(value[1])) {
244+
diagnostics.push(new Diagnostic(new Range(start, end),
245+
`CSS id selector '${value[1]}' not found.`,
246+
DiagnosticSeverity.Information));
247+
}
248+
} else {
249+
if (!completion.classes.has(value[1])) {
250+
diagnostics.push(new Diagnostic(new Range(start, end),
251+
`CSS class selector '${value[1]}' not found.`,
252+
DiagnosticSeverity.Information));
253+
}
254+
}
255+
}
256+
}
257+
258+
return diagnostics;
259+
}
260+
214261
provideCompletionItems(
215262
document: TextDocument,
216263
position: Position,

src/extension.ts

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,30 @@
11
import { SelectorCompletionItemProvider } from "./completion";
2-
import { ExtensionContext, languages, workspace } from "vscode";
2+
import { ExtensionContext, commands, languages, window, workspace } from "vscode";
33

44
export function activate(context: ExtensionContext) {
5+
const validations = languages.createDiagnosticCollection();
56
const config = workspace.getConfiguration("css");
67
const enabledLanguages = config.get<string[]>("enabledLanguages", ["html"]);
78
const provider = new SelectorCompletionItemProvider();
89

910
context.subscriptions.push(
11+
commands.registerCommand("vscode-html-css.validate", async () => {
12+
const editor = window.activeTextEditor;
13+
14+
if (editor) {
15+
const document = editor.document;
16+
17+
if (enabledLanguages.includes(document.languageId)) {
18+
const diagnostics = await provider.validate(document);
19+
validations.set(document.uri, diagnostics);
20+
}
21+
}
22+
}),
23+
workspace.onDidChangeTextDocument(e => validations.delete(e.document.uri)),
24+
workspace.onDidCloseTextDocument(document => validations.delete(document.uri)),
1025
languages.registerCompletionItemProvider(enabledLanguages, provider),
11-
provider
26+
provider,
27+
validations
1228
);
1329
}
1430

0 commit comments

Comments
 (0)