diff --git a/packages/vscode-gem-plugin/src/constants.ts b/packages/vscode-gem-plugin/src/constants.ts new file mode 100644 index 00000000..0e155a5e --- /dev/null +++ b/packages/vscode-gem-plugin/src/constants.ts @@ -0,0 +1,3 @@ +export const CSS_REG = /(?\/\*\s*css\s*\*\/\s*`|(?.*?)(`(?=;|\s))/gis; +export const HTML_REG = /(?\/\*\s*html\s*\*\/\s*`|(?[^`]*)(`)/gi; +export const STYLE_REG = /(?\/\*\s*style\s*\*\/\s*`|(?.*?)(`(?=,|\s*}\s*\)))/gis; diff --git a/packages/vscode-gem-plugin/src/providers/css.ts b/packages/vscode-gem-plugin/src/providers/css.ts index 1be40eff..1ba7155f 100644 --- a/packages/vscode-gem-plugin/src/providers/css.ts +++ b/packages/vscode-gem-plugin/src/providers/css.ts @@ -8,23 +8,62 @@ import type { } from 'vscode'; import type { LanguageService as HTMLanguageService } from 'vscode-html-languageservice'; import type { LanguageService as CSSLanguageService } from 'vscode-css-languageservice'; -import { getLanguageService as getHTMLanguageService } from 'vscode-html-languageservice'; +import { getLanguageService as getHTMLanguageService, TokenType as HTMLTokenType } from 'vscode-html-languageservice'; import { getCSSLanguageService as getCSSLanguageService } from 'vscode-css-languageservice'; -import { - matchOffset, - createVirtualDocument, - getLanguageRegions, - getRegionAtOffset, - translateCompletionList, - translateToCSS, -} from '../util'; +import { matchOffset, createVirtualDocument, translateCompletionList, removeSlot } from '../util'; import { CompletionsCache } from '../cache'; +import { CSS_REG, HTML_REG } from '../constants'; + +export function getRegionAtOffset(regions: IEmbeddedRegion[], offset: number) { + for (const region of regions) { + if (region.start <= offset) { + if (offset <= region.end) { + return region; + } + } else { + break; + } + } + return null; +} + +export interface IEmbeddedRegion { + languageId: string; + start: number; + end: number; + length: number; + content: string; +} + +export function getLanguageRegions(service: HTMLanguageService, data: string) { + const scanner = service.createScanner(data); + const regions: IEmbeddedRegion[] = []; + let tokenType: HTMLTokenType; + + while ((tokenType = scanner.scan()) !== HTMLTokenType.EOS) { + switch (tokenType) { + case HTMLTokenType.Styles: + regions.push({ + languageId: 'css', + start: scanner.getTokenOffset(), + end: scanner.getTokenEnd(), + length: scanner.getTokenLength(), + content: scanner.getTokenText(), + }); + break; + default: + break; + } + } + + return regions; +} export class HTMLStyleCompletionItemProvider implements CompletionItemProvider { #cssLanguageService: CSSLanguageService = getCSSLanguageService(); #htmlLanguageService: HTMLanguageService = getHTMLanguageService(); - #expression = /(\/\*\s*html\s*\*\/\s*`|(? 'x'.repeat(str.length)); +export function removeSlot(text: string) { + const v = text.replace(/\$\{[^${]*?\}/g, (str) => str.replaceAll(/[^\n]/g, ' ')); + if (v === text) return v; + return removeSlot(v); } export function translateCompletionList(list: HtmlCompletionList, line: TextLine, expand?: boolean) { @@ -38,86 +39,21 @@ export function translateCompletionList(list: HtmlCompletionList, line: TextLine }; } -export function getEmmetConfiguration() { - const emmetConfig = workspace.getConfiguration('emmet'); - return { - useNewEmmet: true, - showExpandedAbbreviation: emmetConfig.showExpandedAbbreviation, - showAbbreviationSuggestions: emmetConfig.showAbbreviationSuggestions, - syntaxProfiles: emmetConfig.syntaxProfiles, - variables: emmetConfig.variables, - } as VSCodeEmmetConfig; -} - -export function notNull(input: any) { - if (!input) { - return {} as T; - } - return input as T; -} - -export function matchOffset(regex: RegExp, data: string, offset: number) { +export function matchOffset(regex: RegExp, docText: string, offset: number) { regex.exec('null'); let match: RegExpExecArray | null; - while ((match = regex.exec(data)) !== null) { - if (offset > match.index + match[1].length && offset < match.index + match[0].length) { + while ((match = regex.exec(docText)) !== null) { + const [fullStr, startStr] = match; + const start = match.index + startStr.length; + const end = match.index + fullStr.length; + if (offset > start && offset < end) { return match; } } return null; } -export function getLanguageRegions(service: LanguageService, data: string) { - const scanner = service.createScanner(data); - const regions: IEmbeddedRegion[] = []; - let tokenType: HTMLTokenType; - - while ((tokenType = scanner.scan()) !== HTMLTokenType.EOS) { - switch (tokenType) { - case HTMLTokenType.Styles: - regions.push({ - languageId: 'css', - start: scanner.getTokenOffset(), - end: scanner.getTokenEnd(), - length: scanner.getTokenLength(), - content: scanner.getTokenText(), - }); - break; - default: - break; - } - } - - return regions; -} - -export function getRegionAtOffset(regions: IEmbeddedRegion[], offset: number) { - for (const region of regions) { - if (region.start <= offset) { - if (offset <= region.end) { - return region; - } - } else { - break; - } - } - return null; -} - -export function createVirtualDocument( - // context: TextDocument | HTMLTextDocument, - languageId: string, - // position: Position | HtmlPosition, - content: string, -) { +export function createVirtualDocument(languageId: string, content: string) { return HTMLTextDocument.create(`embedded://document.${languageId}`, languageId, 1, content); } - -export interface IEmbeddedRegion { - languageId: string; - start: number; - end: number; - length: number; - content: string; -} diff --git a/packages/vscode-gem-plugin/syntaxes/es6.inline.css.json b/packages/vscode-gem-plugin/syntaxes/es6.inline.css.json index 0f9d816f..c8d5b55c 100644 --- a/packages/vscode-gem-plugin/syntaxes/es6.inline.css.json +++ b/packages/vscode-gem-plugin/syntaxes/es6.inline.css.json @@ -4,7 +4,7 @@ "patterns": [ { "contentName": "meta.embedded.block.css", - "begin": "(?ix)(\\s*?(\\w+\\.)?(?:css|stylesheet|/\\*\\s*css\\s*\\*/)\\s*)(`)", + "begin": "(?ix)(\\s*?(\\w+\\.)?(?:css|/\\*\\s*css\\s*\\*/)\\s*)(`)", "beginCaptures": { "0": { "name": "string.template.ts, punctuation.definition.string.template.begin.ts"