Skip to content

Commit 725464d

Browse files
committed
Add support for Emmet
1 parent 3fcb3a2 commit 725464d

File tree

4 files changed

+73
-28
lines changed

4 files changed

+73
-28
lines changed

CHANGELOG.md

+4
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
### 1.17.1 (Fev 18, 2018)
2+
* Added support for "class" in TypeScript React, JavaScript and JavaScript React language modes. Previously only "className" was supported.
3+
* Added support for Emmet.
4+
15
### 1.16.2 (Fev 10, 2018)
26
* Workaround for a bug in the VS Code API.
37

README.md

+22-11
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# IntelliSense for CSS class names
1+
# IntelliSense for CSS class names in HTML
22

33
A Visual Studio Code extension that provides CSS class name completion for the HTML `class` attribute based on the definitions found in your workspace or external files referenced through the `link` element.
44

@@ -25,29 +25,40 @@ A Visual Studio Code extension that provides CSS class name completion for the H
2525
* Handlebars
2626
* EJS (.ejs)
2727

28-
## Library Specific Support
29-
* @apply in CSS, SASS and SCSS Files for [Tailwind CSS](https://tailwindcss.com)
28+
## Specific Support
29+
* "@apply" directive in CSS, SASS and SCSS Files for [Tailwind CSS](https://tailwindcss.com)
30+
* "className" and "class" in TypeScript React, JavaScript and JavaScript React language modes
31+
* Emmet abbreviations support triggered by typing a "." (comes disabled by default, check the User Settings topic for more information)
3032

3133
## Contributions
3234
You can request new features and contribute to the extension development on its [repository on GitHub](https://github.com/Zignd/HTML-CSS-Class-Completion/issues). Look for an issue you're interested in working on, comment on it to let me know you're working on it and submit your pull request! :D
3335

34-
## What's new in version 1.16.2 (Fev 1015, 2018)
35-
* Automatic re-caching when the extension's User Settings change.
36-
* Fix mistake in production build.
37-
* Workaround for a bug in the VS Code API.
36+
## What's new in version 1.17.1 (Fev 18, 2018)
37+
* Added support for "class" in TypeScript React, JavaScript and JavaScript React language modes. Previously only "className" was supported.
38+
* Added support for Emmet.
3839

3940
Check out the [changelog](https://github.com/zignd/HTML-CSS-Class-Completion/blob/master/CHANGELOG.md) for the current and previous updates.
4041

4142
## Usage
4243
If there are HTML or JS files on your workspace, the extension automatically starts and looks for CSS class definitions. In case new CSS classes are defined, or new CSS files are added to the workspace, and you also want auto-completion for them, just hit the lightning icon on the status bar. Also, you can execute the command by pressing `Ctrl+Shift+P`(`Cmd+Shift+P` for Mac) and then typing "Cache CSS class definitions."
4344

4445
### User Settings
45-
You can change the folders and files the extension will consider or exclude during the caching process by setting the following User Settings:
46+
The extension supports a few user settings, changes to these settings will be automatically recognized and the caching process will be re-executed.
4647

47-
* `html-css-class-completion.includeGlobPattern` (default: "**/*.{css,html}")
48-
* `html-css-class-completion.excludeGlobPattern` (default: "")
48+
#### Folders and Files
4949

50-
Changes to these settings will be recognized by the extension and the caching process will be automatically executed.
50+
You can change the folders and files the extension will consider or exclude during the caching process by setting the following user settings:
51+
52+
* `"html-css-class-completion.includeGlobPattern"` (default: `"**/*.{css,html}"`)
53+
* `"html-css-class-completion.excludeGlobPattern"` (default: `""`)
54+
55+
#### Emmet
56+
57+
Emmet support comes disabled by default, the reason behind this choice is because it the current implementation simply triggers completion when you type a "." (period) and this behavior might be considered a little annoying, but it might change in the future.
58+
59+
Currently it supports the following languages (those are [language identifier](https://code.visualstudio.com/docs/languages/identifiers#_known-language-identifiers)): "html", "razor", "php", "blade", "vue", "twig", "markdown", "erb", "handlebars", "ejs", "typescriptreact", "javascript", "javascriptreact".
60+
61+
* `"html-css-class-completion.enableEmmetSupport"` (default: `false`)
5162

5263
![](https://i.imgur.com/O7NjEUW.gif)
5364
![](https://i.imgur.com/uyiXqMb.gif)

package.json

+7-3
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,12 @@
11
{
22
"name": "html-css-class-completion",
3-
"displayName": "IntelliSense for CSS class names",
3+
"displayName": "IntelliSense for CSS class names in HTML",
44
"description": "CSS class name completion for the HTML class attribute based on the definitions found in your workspace.",
5-
"version": "1.16.2",
5+
"version": "1.17.0",
66
"publisher": "Zignd",
77
"engines": {
88
"vscode": "^1.19.0"
99
},
10-
"enableProposedApi": true,
1110
"keywords": [
1211
"html",
1312
"css",
@@ -42,6 +41,11 @@
4241
"type": "string",
4342
"default": "",
4443
"description": "A glob pattern that defines files and folders to exclude. The glob pattern will be matched against the file paths of resulting matches relative to their workspace."
44+
},
45+
"html-css-class-completion.enableEmmetSupport": {
46+
"type": "boolean",
47+
"default": false,
48+
"description": "Enables completion when you're writing Emmet abbreviations."
4549
}
4650
}
4751
}

src/extension.ts

+40-14
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import * as Bluebird from "bluebird";
22
import * as _ from "lodash";
33
import "source-map-support/register";
4-
import * as verror from "verror";
4+
import * as VError from "verror";
55
import {
66
commands, CompletionItem, CompletionItemKind, Disposable,
77
ExtensionContext, languages, Position, Range, TextDocument, Uri, window,
@@ -20,6 +20,8 @@ const completionTriggerChars = ['"', "'", " ", "."];
2020

2121
let caching: boolean = false;
2222

23+
const emmetDisposables: Array<{ dispose(): any }> = [];
24+
2325
async function cache(): Promise<void> {
2426
try {
2527
notifier.notify("eye", "Looking for CSS classes in the workspace...");
@@ -56,7 +58,7 @@ async function cache(): Promise<void> {
5658
}, { concurrency: 30 });
5759
} catch (err) {
5860
notifier.notify("alert", "Failed to cache the CSS classes in the workspace (click for another attempt)");
59-
throw new verror.VError(err, "Failed to parse the documents");
61+
throw new VError(err, "Failed to parse the documents");
6062
}
6163

6264
uniqueDefinitions = _.uniqBy(definitions, (def) => def.className);
@@ -71,12 +73,13 @@ async function cache(): Promise<void> {
7173
notifier.notify("zap", "CSS classes cached (click to cache again)");
7274
} catch (err) {
7375
notifier.notify("alert", "Failed to cache the CSS classes in the workspace (click for another attempt)");
74-
throw new verror.VError(err,
76+
throw new VError(err,
7577
"Failed to cache the class definitions during the iterations over the documents that were found");
7678
}
7779
}
7880

79-
function provideCompletionItemsGenerator(languageSelector: string, classMatchRegex: RegExp, classPrefix: string = "") {
81+
function provideCompletionItemsGenerator(languageSelector: string, classMatchRegex: RegExp,
82+
classPrefix: string = "", splitChar: string = " ") {
8083
return languages.registerCompletionItemProvider(languageSelector, {
8184
provideCompletionItems(document: TextDocument, position: Position): CompletionItem[] {
8285
const start: Position = new Position(position.line, 0);
@@ -90,7 +93,7 @@ function provideCompletionItemsGenerator(languageSelector: string, classMatchReg
9093
}
9194

9295
// Will store the classes found on the class attribute
93-
const classesOnAttribute = rawClasses[1].split(" ");
96+
const classesOnAttribute = rawClasses[1].split(splitChar);
9497

9598
// Creates a collection of CompletionItem based on the classes already cached
9699
const completionItems = uniqueDefinitions.map((definition) => {
@@ -117,18 +120,37 @@ function provideCompletionItemsGenerator(languageSelector: string, classMatchReg
117120
}, ...completionTriggerChars);
118121
}
119122

123+
function enableEmmetSupport(disposables: Disposable[]) {
124+
const emmetRegex = /(?=\.)([\w-\. ]*$)/;
125+
const languageModes = ["html", "razor", "php", "blade", "vue", "twig", "markdown", "erb",
126+
"handlebars", "ejs", "typescriptreact", "javascript", "javascriptreact"];
127+
languageModes.forEach((language) => {
128+
emmetDisposables.push(provideCompletionItemsGenerator(language, emmetRegex, "", "."));
129+
});
130+
}
131+
132+
function disableEmmetSupport(disposables: Disposable[]) {
133+
for (const emmetDisposable of disposables) {
134+
emmetDisposable.dispose();
135+
}
136+
}
137+
120138
export async function activate(context: ExtensionContext): Promise<void> {
121139
const disposables: Disposable[] = [];
122140
workspace.onDidChangeConfiguration(async (e) => {
123-
if (!e.affectsConfiguration("html-css-class-completion.includeGlobPattern") &&
124-
!e.affectsConfiguration("html-css-class-completion.excludeGlobPattern")) {
125-
return;
126-
}
127-
128141
try {
129-
await cache();
142+
if (e.affectsConfiguration("html-css-class-completion.includeGlobPattern") ||
143+
e.affectsConfiguration("html-css-class-completion.excludeGlobPattern")) {
144+
await cache();
145+
}
146+
147+
if (e.affectsConfiguration("html-css-class-completion.enableEmmetSupport")) {
148+
const isEnabled = workspace.getConfiguration()
149+
.get<boolean>("html-css-class-completion.enableEmmetSupport");
150+
isEnabled ? enableEmmetSupport(emmetDisposables) : disableEmmetSupport(emmetDisposables);
151+
}
130152
} catch (err) {
131-
err = new verror.VError(err, "Failed to automatically re-cache the CSS classes in the workspace");
153+
err = new VError(err, "Failed to automatically reload the extension after the configuration change");
132154
console.error(err);
133155
window.showErrorMessage(err.message);
134156
}
@@ -144,7 +166,7 @@ export async function activate(context: ExtensionContext): Promise<void> {
144166
try {
145167
await cache();
146168
} catch (err) {
147-
err = new verror.VError(err, "Failed to cache the CSS classes in the workspace");
169+
err = new VError(err, "Failed to cache the CSS classes in the workspace");
148170
console.error(err);
149171
window.showErrorMessage(err.message);
150172
} finally {
@@ -173,10 +195,14 @@ export async function activate(context: ExtensionContext): Promise<void> {
173195
try {
174196
await cache();
175197
} catch (err) {
176-
err = new verror.VError(err, "Failed to cache the CSS classes in the workspace for the first time");
198+
err = new VError(err, "Failed to cache the CSS classes in the workspace for the first time");
177199
console.error(err);
178200
window.showErrorMessage(err.message);
179201
} finally {
180202
caching = false;
181203
}
182204
}
205+
206+
export function deactivate(): void {
207+
emmetDisposables.forEach((disposable) => disposable.dispose());
208+
}

0 commit comments

Comments
 (0)