Skip to content
This repository was archived by the owner on Apr 4, 2023. It is now read-only.

Emmet in typescript styled plugin #33

Merged
merged 7 commits into from
Feb 16, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -340,6 +340,31 @@ Avoid using 'float'. Floats lead to fragile CSS that is easy to break if one asp

Selectors should not contain IDs because these rules are too tightly coupled with the HTML. Default is `"ignore"`.

### Emmet in completion list

You can now see your Emmet abbreviations expanded and included in the completion list.
An [upstream issue](https://github.com/Microsoft/TypeScript/issues/21999) with typescript blocks the Emmet entry in the completion list to get updated as you type.
So for now you will have to press `Ctrl+Space` after typing out the abbreviation.

The below settings which are in sync with general Emmet settings in VS Code control the expanded Emmet abbreviations in the auto-completion list.

#### showExpandedAbbreviation
```
"always" | "never"
```

Controls whether or not expanded Emmet abbreviations should show up in the completion list

#### showSuggestionsAsSnippets
```
`true` | `false`
```
If true, then Emmet suggestions will show up as snippets allowing you to order them as per editor.snippetSuggestions setting.

#### preferences

Preferences used to modify behavior of some actions and resolvers of Emmet.


## Contributing

Expand Down
3 changes: 3 additions & 0 deletions e2e/disabled-emmet-project-fixture/.vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"typescript.tsdk": "node_modules/typescript/lib"
}
3 changes: 3 additions & 0 deletions e2e/disabled-emmet-project-fixture/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
css`

`
Empty file.
9 changes: 9 additions & 0 deletions e2e/disabled-emmet-project-fixture/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"compilerOptions": {
"target": "es2015",
"module": "commonjs",
"plugins": [
{ "name": "../../../lib", "tags": ["css"], "emmet": { "showExpandedAbbreviation": "never"} }
]
}
}
1 change: 1 addition & 0 deletions e2e/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 4 additions & 4 deletions e2e/server-fixture/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,14 @@ const fs = require('fs');
const readline = require('readline');

class TSServer {
constructor() {
constructor(project) {
const logfile = path.join(__dirname, 'log.txt');
const tsserverPath = path.join(__dirname, '..', 'node_modules', 'typescript', 'lib', 'tsserver');
const server = fork(tsserverPath, [
'--logVerbosity', 'verbose',
'--logFile', logfile
], {
cwd: path.join(__dirname, '..', 'project-fixture'),
cwd: path.join(__dirname, '..', project),
stdio: ['pipe', 'pipe', 'pipe', 'ipc'],
});
this._exitPromise = new Promise((resolve, reject) => {
Expand Down Expand Up @@ -48,8 +48,8 @@ class TSServer {
}
}

function createServer() {
return new TSServer();
function createServer(project) {
return new TSServer(project || 'project-fixture');
}

module.exports = createServer;
159 changes: 159 additions & 0 deletions e2e/tests/emmetCompletions.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
const assert = require('chai').assert;
const createServer = require('../server-fixture');
const { openMockFile, getFirstResponseOfType } = require('./_helpers');

const mockFileName = 'main.ts';

describe('Emmet Completions', () => {
it('shouldnt return emmet property completions when disabled', () => {
const server = createServer('disabled-emmet-project-fixture');
openMockFile(server, mockFileName, 'const q = css`m10-20`');
server.send({ command: 'completions', arguments: { file: mockFileName, offset: 21, line: 1 } });

return server.close().then(() => {
const completionsResponse = getFirstResponseOfType('completions', server);
assert.isTrue(completionsResponse.body.every(item => item.name !== 'margin: 10px 20px;'));
});
});

it('should return emmet property completions for single line string', () => {
const server = createServer();
openMockFile(server, mockFileName, 'const q = css`m10-20`');
server.send({ command: 'completions', arguments: { file: mockFileName, offset: 21, line: 1 } });

return server.close().then(() => {
const completionsResponse = getFirstResponseOfType('completions', server);
assert.isTrue(completionsResponse.body.some(item => item.name === 'margin: 10px 20px;'));
});
});


it('should return emmet property completions for multiline string', () => {
const server = createServer();
openMockFile(server, mockFileName, [
'const q = css`',
'm10-20',
'`'
].join('\n'));
server.send({ command: 'completions', arguments: { file: mockFileName, offset: 7, line: 2 } });

return server.close().then(() => {
const completionsResponse = getFirstResponseOfType('completions', server);
assert.isTrue(completionsResponse.body.some(item => item.name === 'margin: 10px 20px;'));
});
});

it('should return emmet property completions for nested selector', () => {
const server = createServer();
openMockFile(server, mockFileName, 'const q = css`position: relative; &:hover { m10-20 }`');
server.send({ command: 'completions', arguments: { file: mockFileName, offset: 51, line: 1 } });

return server.close().then(() => {
const completionsResponse = getFirstResponseOfType('completions', server);
assert.isTrue(completionsResponse.body.some(item => item.name === 'margin: 10px 20px;'));
});
});

it('should return emmet completions when placeholder is used as property', () => {
const server = createServer();
openMockFile(server, mockFileName, 'css`m10-20 ; boarder: 1px solid ${"red"};`');
server.send({ command: 'completions', arguments: { file: mockFileName, offset: 11, line: 1 } });

return server.close().then(() => {
const completionsResponse = getFirstResponseOfType('completions', server);
assert.isTrue(completionsResponse.body.some(item => item.name === 'margin: 10px 20px;'));
});
});

it('should return emmet completions after where placeholder is used as property', () => {
const server = createServer();
openMockFile(server, mockFileName, 'css`border: 1px solid ${"red"}; m10-20`');
server.send({ command: 'completions', arguments: { file: mockFileName, offset: 39, line: 1 } });

return server.close().then(() => {
const completionsResponse = getFirstResponseOfType('completions', server);
assert.isTrue(completionsResponse.body.some(item => item.name === 'margin: 10px 20px;'));
});
});

it('should return emmet completions between were placeholders are used as properties', () => {
const server = createServer();
openMockFile(server, mockFileName, 'css`boarder: 1px solid ${"red"}; color: #12; margin: ${20}; `')
server.send({ command: 'completions', arguments: { file: mockFileName, offset: 44, line: 1 } });

return server.close().then(() => {
const completionsResponse = getFirstResponseOfType('completions', server);
assert.isTrue(completionsResponse.body.some(item => item.name === '#121212'));
});
});

it('should return emmet completions on tagged template string with placeholder using dotted tag', () => {
const server = createServer();
openMockFile(server, mockFileName, 'css.x`color: #12 ; boarder: 1px solid ${"red"};`');
server.send({ command: 'completions', arguments: { file: mockFileName, offset: 17, line: 1 } });

return server.close().then(() => {
const completionsResponse = getFirstResponseOfType('completions', server);
assert.isTrue(completionsResponse.success);
assert.isTrue(completionsResponse.body.some(item => item.name === '#121212'));
});
});

it('should return styled emmet completions inside of nested placeholder', () => {
const server = createServer();
openMockFile(server, mockFileName, 'styled`background: red; ${(() => css`color: #12`)()}`;');
server.send({ command: 'completions', arguments: { file: mockFileName, offset: 48, line: 1 } });

return server.close().then(() => {
const completionsResponse = getFirstResponseOfType('completions', server);
assert.isTrue(completionsResponse.body.some(item => item.name === '#121212'));
});
});

it('should handle emmet completions in multiline value placeholder correctly ', () => {
const server = createServer();
openMockFile(server, mockFileName, [
'css`margin: ${',
'0',
"}; color: #12`"].join('\n'));
server.send({ command: 'completions', arguments: { file: mockFileName, offset: 14, line: 3 } });

return server.close().then(() => {
const completionsResponse = getFirstResponseOfType('completions', server);
assert.isTrue(completionsResponse.body.some(item => item.name === '#121212'));
});
});

it('should handle emmet completions in multiline rule placeholder correctly ', () => {
const server = createServer();
openMockFile(server, mockFileName, [
'css`',
'${',
'css`margin: 0;`',
'}',
'color: #12`'].join('\n'));
server.send({ command: 'completions', arguments: { file: mockFileName, offset: 11, line: 5 } });

return server.close().then(() => {
const completionsResponse = getFirstResponseOfType('completions', server);
assert.isTrue(completionsResponse.body.some(item => item.name === '#121212'));
});
});

it('should return emmet completions inside of nested selector xx', () => {
const server = createServer();
openMockFile(server, mockFileName, [
'css`',
' color: red;',
' &:hover {',
' color: #12 ',
' }',
'`'].join('\n'));
server.send({ command: 'completions', arguments: { file: mockFileName, line: 4, offset: 19 } });

return server.close().then(() => {
const completionsResponse = getFirstResponseOfType('completions', server);
assert.isTrue(completionsResponse.body.some(item => item.name === '#121212'));
});
});
})
42 changes: 34 additions & 8 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@
"dependencies": {
"typescript-template-language-service-decorator": "^1.2.0",
"vscode-css-languageservice": "^3.0.5",
"vscode-languageserver-types": "^3.5.0"
"vscode-languageserver-types": "^3.6.0-next.1",
"vscode-emmet-helper": "1.1.36"
},
"files": [
"lib"
Expand Down
3 changes: 3 additions & 0 deletions src/configuration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ export interface TsStyledPluginConfiguration {
tags: string[];
validate: boolean;
lint: { [key: string]: any };
emmet: { [key: string]: any };
}

export const defaultConfiguration: TsStyledPluginConfiguration = {
Expand All @@ -13,6 +14,7 @@ export const defaultConfiguration: TsStyledPluginConfiguration = {
lint: {
emptyRules: 'ignore',
},
emmet: {}
};

export const loadConfiguration = (config: any): TsStyledPluginConfiguration => {
Expand All @@ -21,5 +23,6 @@ export const loadConfiguration = (config: any): TsStyledPluginConfiguration => {
tags: config.tags || defaultConfiguration.tags,
validate: typeof config.validate !== 'undefined' ? config.validate : defaultConfiguration.validate,
lint,
emmet: config.emmet || defaultConfiguration.emmet
};
};
Loading