summaryrefslogtreecommitdiff
path: root/tools/astro-languageserver/src/plugins
diff options
context:
space:
mode:
Diffstat (limited to 'tools/astro-languageserver/src/plugins')
-rw-r--r--tools/astro-languageserver/src/plugins/css/CSSDocument.ts144
-rw-r--r--tools/astro-languageserver/src/plugins/css/CSSPlugin.ts127
-rw-r--r--tools/astro-languageserver/src/plugins/css/StyleAttributeDocument.ts110
-rw-r--r--tools/astro-languageserver/src/plugins/css/features/getIdClassCompletion.ts81
-rw-r--r--tools/astro-languageserver/src/plugins/css/service.ts50
-rw-r--r--tools/astro-languageserver/src/plugins/index.ts2
6 files changed, 231 insertions, 283 deletions
diff --git a/tools/astro-languageserver/src/plugins/css/CSSDocument.ts b/tools/astro-languageserver/src/plugins/css/CSSDocument.ts
index 90b28352c..9f1839678 100644
--- a/tools/astro-languageserver/src/plugins/css/CSSDocument.ts
+++ b/tools/astro-languageserver/src/plugins/css/CSSDocument.ts
@@ -4,92 +4,92 @@ import { getLanguageService } from './service';
import { Document, DocumentMapper, ReadableDocument, TagInformation } from '../../core/documents/index';
export interface CSSDocumentBase extends DocumentMapper, TextDocument {
- languageId: string;
- stylesheet: Stylesheet;
+ languageId: string;
+ stylesheet: Stylesheet;
}
export class CSSDocument extends ReadableDocument implements DocumentMapper {
- private styleInfo: Pick<TagInformation, 'attributes' | 'start' | 'end'>;
- readonly version = this.parent.version;
+ private styleInfo: Pick<TagInformation, 'attributes' | 'start' | 'end'>;
+ readonly version = this.parent.version;
- public stylesheet: Stylesheet;
- public languageId: string;
+ public stylesheet: Stylesheet;
+ public languageId: string;
- constructor(private parent: Document) {
- super();
+ constructor(private parent: Document) {
+ super();
- if (this.parent.styleInfo) {
- this.styleInfo = this.parent.styleInfo;
- } else {
- this.styleInfo = {
- attributes: {},
- start: -1,
- end: -1
- };
- }
-
- this.languageId = this.language;
- this.stylesheet = getLanguageService(this.language).parseStylesheet(this);
+ if (this.parent.styleInfo) {
+ this.styleInfo = this.parent.styleInfo;
+ } else {
+ this.styleInfo = {
+ attributes: {},
+ start: -1,
+ end: -1,
+ };
}
- /**
- * Get the fragment position relative to the parent
- * @param pos Position in fragment
- */
- getOriginalPosition(pos: Position): Position {
- const parentOffset = this.styleInfo.start + this.offsetAt(pos);
- return this.parent.positionAt(parentOffset);
- }
+ this.languageId = this.language;
+ this.stylesheet = getLanguageService(this.language).parseStylesheet(this);
+ }
- /**
- * Get the position relative to the start of the fragment
- * @param pos Position in parent
- */
- getGeneratedPosition(pos: Position): Position {
- const fragmentOffset = this.parent.offsetAt(pos) - this.styleInfo.start;
- return this.positionAt(fragmentOffset);
- }
+ /**
+ * Get the fragment position relative to the parent
+ * @param pos Position in fragment
+ */
+ getOriginalPosition(pos: Position): Position {
+ const parentOffset = this.styleInfo.start + this.offsetAt(pos);
+ return this.parent.positionAt(parentOffset);
+ }
- /**
- * Returns true if the given parent position is inside of this fragment
- * @param pos Position in parent
- */
- isInGenerated(pos: Position): boolean {
- const offset = this.parent.offsetAt(pos);
- return offset >= this.styleInfo.start && offset <= this.styleInfo.end;
- }
+ /**
+ * Get the position relative to the start of the fragment
+ * @param pos Position in parent
+ */
+ getGeneratedPosition(pos: Position): Position {
+ const fragmentOffset = this.parent.offsetAt(pos) - this.styleInfo.start;
+ return this.positionAt(fragmentOffset);
+ }
- /**
- * Get the fragment text from the parent
- */
- getText(): string {
- return this.parent.getText().slice(this.styleInfo.start, this.styleInfo.end);
- }
+ /**
+ * Returns true if the given parent position is inside of this fragment
+ * @param pos Position in parent
+ */
+ isInGenerated(pos: Position): boolean {
+ const offset = this.parent.offsetAt(pos);
+ return offset >= this.styleInfo.start && offset <= this.styleInfo.end;
+ }
- /**
- * Returns the length of the fragment as calculated from the start and end positon
- */
- getTextLength(): number {
- return this.styleInfo.end - this.styleInfo.start;
- }
+ /**
+ * Get the fragment text from the parent
+ */
+ getText(): string {
+ return this.parent.getText().slice(this.styleInfo.start, this.styleInfo.end);
+ }
- /**
- * Return the parent file path
- */
- getFilePath(): string | null {
- return this.parent.getFilePath();
- }
+ /**
+ * Returns the length of the fragment as calculated from the start and end positon
+ */
+ getTextLength(): number {
+ return this.styleInfo.end - this.styleInfo.start;
+ }
- getURL() {
- return this.parent.getURL();
- }
+ /**
+ * Return the parent file path
+ */
+ getFilePath(): string | null {
+ return this.parent.getFilePath();
+ }
- getAttributes() {
- return this.styleInfo.attributes;
- }
+ getURL() {
+ return this.parent.getURL();
+ }
- private get language() {
- const attrs = this.getAttributes();
- return attrs.lang || attrs.type || 'css';
- }
+ getAttributes() {
+ return this.styleInfo.attributes;
+ }
+
+ private get language() {
+ const attrs = this.getAttributes();
+ return attrs.lang || attrs.type || 'css';
+ }
}
diff --git a/tools/astro-languageserver/src/plugins/css/CSSPlugin.ts b/tools/astro-languageserver/src/plugins/css/CSSPlugin.ts
index 4c0dcb949..26c90ac66 100644
--- a/tools/astro-languageserver/src/plugins/css/CSSPlugin.ts
+++ b/tools/astro-languageserver/src/plugins/css/CSSPlugin.ts
@@ -26,24 +26,16 @@ export class CSSPlugin implements CompletionsProvider {
});
}
- getCompletions(
- document: Document,
- position: Position,
- completionContext?: CompletionContext
- ): CompletionList | null {
+ getCompletions(document: Document, position: Position, completionContext?: CompletionContext): CompletionList | null {
const triggerCharacter = completionContext?.triggerCharacter;
const triggerKind = completionContext?.triggerKind;
const isCustomTriggerCharacter = triggerKind === CompletionTriggerKind.TriggerCharacter;
- if (
- isCustomTriggerCharacter &&
- triggerCharacter &&
- !this.triggerCharacters.has(triggerCharacter)
- ) {
- return null;
+ if (isCustomTriggerCharacter && triggerCharacter && !this.triggerCharacters.has(triggerCharacter)) {
+ return null;
}
- if(this.isInsideFrontmatter(document, position)) {
+ if (this.isInsideFrontmatter(document, position)) {
return null;
}
@@ -55,82 +47,55 @@ export class CSSPlugin implements CompletionsProvider {
const attributeContext = getAttributeContextAtPosition(document, position);
if (!attributeContext) {
- return null;
+ return null;
}
if (this.inStyleAttributeWithoutInterpolation(attributeContext, document.getText())) {
- const [start, end] = attributeContext.valueRange;
- return this.getCompletionsInternal(
- document,
- position,
- new StyleAttributeDocument(document, start, end)
- );
+ const [start, end] = attributeContext.valueRange;
+ return this.getCompletionsInternal(document, position, new StyleAttributeDocument(document, start, end));
} else {
- return getIdClassCompletion(cssDocument, attributeContext);
+ return getIdClassCompletion(cssDocument, attributeContext);
}
}
- private getCompletionsInternal(
- document: Document,
- position: Position,
- cssDocument: CSSDocumentBase
- ) {
- if (isSASS(cssDocument)) {
- // the css language service does not support sass, still we can use
- // the emmet helper directly to at least get emmet completions
- return doEmmetComplete(document, position, 'sass', this.configManager.getEmmetConfig());
- }
-
- const type = extractLanguage(cssDocument);
-
- const lang = getLanguageService(type);
- const emmetResults: CompletionList = {
- isIncomplete: true,
- items: []
- };
- if (false /* this.configManager.getConfig().css.completions.emmet */) {
- lang.setCompletionParticipants([
- getEmmetCompletionParticipants(
- cssDocument,
- cssDocument.getGeneratedPosition(position),
- getLanguage(type),
- this.configManager.getEmmetConfig(),
- emmetResults
- )
- ]);
- }
- const results = lang.doComplete(
- cssDocument,
- cssDocument.getGeneratedPosition(position),
- cssDocument.stylesheet
- );
- return CompletionList.create(
- [...(results ? results.items : []), ...emmetResults.items].map((completionItem) =>
- mapCompletionItemToOriginal(cssDocument, completionItem)
- ),
- // Emmet completions change on every keystroke, so they are never complete
- emmetResults.items.length > 0
- );
- }
+ private getCompletionsInternal(document: Document, position: Position, cssDocument: CSSDocumentBase) {
+ if (isSASS(cssDocument)) {
+ // the css language service does not support sass, still we can use
+ // the emmet helper directly to at least get emmet completions
+ return doEmmetComplete(document, position, 'sass', this.configManager.getEmmetConfig());
+ }
- private inStyleAttributeWithoutInterpolation(
- attrContext: AttributeContext,
- text: string
- ): attrContext is Required<AttributeContext> {
- return (
- attrContext.name === 'style' &&
- !!attrContext.valueRange &&
- !text.substring(attrContext.valueRange[0], attrContext.valueRange[1]).includes('{')
+ const type = extractLanguage(cssDocument);
+
+ const lang = getLanguageService(type);
+ const emmetResults: CompletionList = {
+ isIncomplete: true,
+ items: [],
+ };
+ if (false /* this.configManager.getConfig().css.completions.emmet */) {
+ lang.setCompletionParticipants([
+ getEmmetCompletionParticipants(cssDocument, cssDocument.getGeneratedPosition(position), getLanguage(type), this.configManager.getEmmetConfig(), emmetResults),
+ ]);
+ }
+ const results = lang.doComplete(cssDocument, cssDocument.getGeneratedPosition(position), cssDocument.stylesheet);
+ return CompletionList.create(
+ [...(results ? results.items : []), ...emmetResults.items].map((completionItem) => mapCompletionItemToOriginal(cssDocument, completionItem)),
+ // Emmet completions change on every keystroke, so they are never complete
+ emmetResults.items.length > 0
);
}
+ private inStyleAttributeWithoutInterpolation(attrContext: AttributeContext, text: string): attrContext is Required<AttributeContext> {
+ return attrContext.name === 'style' && !!attrContext.valueRange && !text.substring(attrContext.valueRange[0], attrContext.valueRange[1]).includes('{');
+ }
+
private getCSSDoc(document: Document) {
- let cssDoc = this.documents.get(document);
- if (!cssDoc || cssDoc.version < document.version) {
- cssDoc = new CSSDocument(document);
- this.documents.set(document, cssDoc);
- }
- return cssDoc;
+ let cssDoc = this.documents.get(document);
+ if (!cssDoc || cssDoc.version < document.version) {
+ cssDoc = new CSSDocument(document);
+ this.documents.set(document, cssDoc);
+ }
+ return cssDoc;
}
private isInsideFrontmatter(document: Document, position: Position) {
@@ -140,14 +105,14 @@ export class CSSPlugin implements CompletionsProvider {
function isSASS(document: CSSDocumentBase) {
switch (extractLanguage(document)) {
- case 'sass':
- return true;
- default:
- return false;
+ case 'sass':
+ return true;
+ default:
+ return false;
}
}
function extractLanguage(document: CSSDocumentBase): string {
const lang = document.languageId;
return lang.replace(/^text\//, '');
-} \ No newline at end of file
+}
diff --git a/tools/astro-languageserver/src/plugins/css/StyleAttributeDocument.ts b/tools/astro-languageserver/src/plugins/css/StyleAttributeDocument.ts
index 7b49d771d..e00398037 100644
--- a/tools/astro-languageserver/src/plugins/css/StyleAttributeDocument.ts
+++ b/tools/astro-languageserver/src/plugins/css/StyleAttributeDocument.ts
@@ -7,70 +7,66 @@ const PREFIX = '__ {';
const SUFFIX = '}';
export class StyleAttributeDocument extends ReadableDocument implements DocumentMapper {
- readonly version = this.parent.version;
+ readonly version = this.parent.version;
- public stylesheet: Stylesheet;
- public languageId = 'css';
+ public stylesheet: Stylesheet;
+ public languageId = 'css';
- constructor(
- private readonly parent: Document,
- private readonly attrStart: number,
- private readonly attrEnd: number
- ) {
- super();
+ constructor(private readonly parent: Document, private readonly attrStart: number, private readonly attrEnd: number) {
+ super();
- this.stylesheet = getLanguageService(this.languageId).parseStylesheet(this);
- }
+ this.stylesheet = getLanguageService(this.languageId).parseStylesheet(this);
+ }
- /**
- * Get the fragment position relative to the parent
- * @param pos Position in fragment
- */
- getOriginalPosition(pos: Position): Position {
- const parentOffset = this.attrStart + this.offsetAt(pos) - PREFIX.length;
- return this.parent.positionAt(parentOffset);
- }
+ /**
+ * Get the fragment position relative to the parent
+ * @param pos Position in fragment
+ */
+ getOriginalPosition(pos: Position): Position {
+ const parentOffset = this.attrStart + this.offsetAt(pos) - PREFIX.length;
+ return this.parent.positionAt(parentOffset);
+ }
- /**
- * Get the position relative to the start of the fragment
- * @param pos Position in parent
- */
- getGeneratedPosition(pos: Position): Position {
- const fragmentOffset = this.parent.offsetAt(pos) - this.attrStart + PREFIX.length;
- return this.positionAt(fragmentOffset);
- }
+ /**
+ * Get the position relative to the start of the fragment
+ * @param pos Position in parent
+ */
+ getGeneratedPosition(pos: Position): Position {
+ const fragmentOffset = this.parent.offsetAt(pos) - this.attrStart + PREFIX.length;
+ return this.positionAt(fragmentOffset);
+ }
- /**
- * Returns true if the given parent position is inside of this fragment
- * @param pos Position in parent
- */
- isInGenerated(pos: Position): boolean {
- const offset = this.parent.offsetAt(pos);
- return offset >= this.attrStart && offset <= this.attrEnd;
- }
+ /**
+ * Returns true if the given parent position is inside of this fragment
+ * @param pos Position in parent
+ */
+ isInGenerated(pos: Position): boolean {
+ const offset = this.parent.offsetAt(pos);
+ return offset >= this.attrStart && offset <= this.attrEnd;
+ }
- /**
- * Get the fragment text from the parent
- */
- getText(): string {
- return PREFIX + this.parent.getText().slice(this.attrStart, this.attrEnd) + SUFFIX;
- }
+ /**
+ * Get the fragment text from the parent
+ */
+ getText(): string {
+ return PREFIX + this.parent.getText().slice(this.attrStart, this.attrEnd) + SUFFIX;
+ }
- /**
- * Returns the length of the fragment as calculated from the start and end position
- */
- getTextLength(): number {
- return PREFIX.length + this.attrEnd - this.attrStart + SUFFIX.length;
- }
+ /**
+ * Returns the length of the fragment as calculated from the start and end position
+ */
+ getTextLength(): number {
+ return PREFIX.length + this.attrEnd - this.attrStart + SUFFIX.length;
+ }
- /**
- * Return the parent file path
- */
- getFilePath(): string | null {
- return this.parent.getFilePath();
- }
+ /**
+ * Return the parent file path
+ */
+ getFilePath(): string | null {
+ return this.parent.getFilePath();
+ }
- getURL() {
- return this.parent.getURL();
- }
-} \ No newline at end of file
+ getURL() {
+ return this.parent.getURL();
+ }
+}
diff --git a/tools/astro-languageserver/src/plugins/css/features/getIdClassCompletion.ts b/tools/astro-languageserver/src/plugins/css/features/getIdClassCompletion.ts
index 368359ac9..45acb5ad6 100644
--- a/tools/astro-languageserver/src/plugins/css/features/getIdClassCompletion.ts
+++ b/tools/astro-languageserver/src/plugins/css/features/getIdClassCompletion.ts
@@ -2,32 +2,29 @@ import { CompletionItem, CompletionItemKind, CompletionList } from 'vscode-langu
import { AttributeContext } from '../../../core/documents/parseHtml';
import { CSSDocument } from '../CSSDocument';
-export function getIdClassCompletion(
- cssDoc: CSSDocument,
- attributeContext: AttributeContext
-): CompletionList | null {
- const collectingType = getCollectingType(attributeContext);
+export function getIdClassCompletion(cssDoc: CSSDocument, attributeContext: AttributeContext): CompletionList | null {
+ const collectingType = getCollectingType(attributeContext);
- if (!collectingType) {
- return null;
- }
- const items = collectSelectors(cssDoc.stylesheet as CSSNode, collectingType);
+ if (!collectingType) {
+ return null;
+ }
+ const items = collectSelectors(cssDoc.stylesheet as CSSNode, collectingType);
- console.log("getIdClassCompletion items", items.length);
- return CompletionList.create(items);
+ console.log('getIdClassCompletion items', items.length);
+ return CompletionList.create(items);
}
function getCollectingType(attributeContext: AttributeContext): number | undefined {
- if (attributeContext.inValue) {
- if (attributeContext.name === 'class') {
- return NodeType.ClassSelector;
- }
- if (attributeContext.name === 'id') {
- return NodeType.IdentifierSelector;
- }
- } else if (attributeContext.name.startsWith('class:')) {
- return NodeType.ClassSelector;
+ if (attributeContext.inValue) {
+ if (attributeContext.name === 'class') {
+ return NodeType.ClassSelector;
+ }
+ if (attributeContext.name === 'id') {
+ return NodeType.IdentifierSelector;
}
+ } else if (attributeContext.name.startsWith('class:')) {
+ return NodeType.ClassSelector;
+ }
}
/**
@@ -36,35 +33,35 @@ function getCollectingType(attributeContext: AttributeContext): number | undefin
* The enum is not exported. we have to update this whenever it changes
*/
export enum NodeType {
- ClassSelector = 14,
- IdentifierSelector = 15
+ ClassSelector = 14,
+ IdentifierSelector = 15,
}
export type CSSNode = {
- type: number;
- children: CSSNode[] | undefined;
- getText(): string;
+ type: number;
+ children: CSSNode[] | undefined;
+ getText(): string;
};
export function collectSelectors(stylesheet: CSSNode, type: number) {
- const result: CSSNode[] = [];
- walk(stylesheet, (node) => {
- if (node.type === type) {
- result.push(node);
- }
- });
+ const result: CSSNode[] = [];
+ walk(stylesheet, (node) => {
+ if (node.type === type) {
+ result.push(node);
+ }
+ });
- return result.map(
- (node): CompletionItem => ({
- label: node.getText().substring(1),
- kind: CompletionItemKind.Keyword
- })
- );
+ return result.map(
+ (node): CompletionItem => ({
+ label: node.getText().substring(1),
+ kind: CompletionItemKind.Keyword,
+ })
+ );
}
function walk(node: CSSNode, callback: (node: CSSNode) => void) {
- callback(node);
- if (node.children) {
- node.children.forEach((node) => walk(node, callback));
- }
-} \ No newline at end of file
+ callback(node);
+ if (node.children) {
+ node.children.forEach((node) => walk(node, callback));
+ }
+}
diff --git a/tools/astro-languageserver/src/plugins/css/service.ts b/tools/astro-languageserver/src/plugins/css/service.ts
index e8ac86a65..78b11296e 100644
--- a/tools/astro-languageserver/src/plugins/css/service.ts
+++ b/tools/astro-languageserver/src/plugins/css/service.ts
@@ -1,58 +1,48 @@
-import {
- getCSSLanguageService,
- getSCSSLanguageService,
- getLESSLanguageService,
- LanguageService,
- ICSSDataProvider
-} from 'vscode-css-languageservice';
+import { getCSSLanguageService, getSCSSLanguageService, getLESSLanguageService, LanguageService, ICSSDataProvider } from 'vscode-css-languageservice';
const customDataProvider: ICSSDataProvider = {
providePseudoClasses() {
- return [];
+ return [];
},
provideProperties() {
- return [];
+ return [];
},
provideAtDirectives() {
- return [];
+ return [];
},
providePseudoElements() {
- return [];
- }
+ return [];
+ },
};
-const [css, scss, less] = [
- getCSSLanguageService,
- getSCSSLanguageService,
- getLESSLanguageService
-].map((getService) =>
+const [css, scss, less] = [getCSSLanguageService, getSCSSLanguageService, getLESSLanguageService].map((getService) =>
getService({
- customDataProviders: [customDataProvider]
+ customDataProviders: [customDataProvider],
})
);
const langs = {
css,
scss,
- less
+ less,
};
export function getLanguage(kind?: string) {
switch (kind) {
- case 'scss':
- case 'text/scss':
- return 'scss' as const;
- case 'less':
- case 'text/less':
- return 'less' as const;
- case 'css':
- case 'text/css':
- default:
- return 'css' as const;
+ case 'scss':
+ case 'text/scss':
+ return 'scss' as const;
+ case 'less':
+ case 'text/less':
+ return 'less' as const;
+ case 'css':
+ case 'text/css':
+ default:
+ return 'css' as const;
}
}
export function getLanguageService(kind?: string): LanguageService {
const lang = getLanguage(kind);
return langs[lang];
-} \ No newline at end of file
+}
diff --git a/tools/astro-languageserver/src/plugins/index.ts b/tools/astro-languageserver/src/plugins/index.ts
index 368b339cb..bb73cbe5e 100644
--- a/tools/astro-languageserver/src/plugins/index.ts
+++ b/tools/astro-languageserver/src/plugins/index.ts
@@ -3,4 +3,4 @@ export * from './astro/AstroPlugin';
export * from './html/HTMLPlugin';
export * from './typescript/TypeScriptPlugin';
export * from './interfaces';
-export * from './css/CSSPlugin'; \ No newline at end of file
+export * from './css/CSSPlugin';