一大波更新

develop
yutent 2023-06-06 15:26:41 +08:00
parent a52927cbd4
commit 583b7586df
15 changed files with 265 additions and 130 deletions

View File

@ -5,3 +5,4 @@ tests/**
.vscode/** .vscode/**
.gitignore .gitignore
.git .git
build.mjs

View File

@ -7,10 +7,30 @@
import Es from 'esbuild' import Es from 'esbuild'
import fs from 'iofs' import fs from 'iofs'
Es.build({ let args = process.argv.slice(2)
entryPoints: fs.ls('./src', true).filter(it => fs.isfile(it)), let entryPoints = fs.ls('./src', true).filter(it => fs.isfile(it))
if (args.includes('--watch')) {
let res = await Es.context({
entryPoints,
outdir: 'dist', outdir: 'dist',
target: 'es6', target: 'es2022',
format: 'cjs' format: 'cjs',
// minify: true // external: ['vscode', 'util'],
platform: 'node'
// bundle: true
}) })
console.log('监听文件变化中...\n')
await res.watch()
} else {
Es.build({
entryPoints,
outdir: 'dist',
target: 'es2022',
format: 'cjs',
minify: true,
// external: ['vscode', 'util'],
platform: 'node'
// bundle: true
})
}

View File

@ -21,9 +21,10 @@
"url": "https://github.com/yutent/vscode-string-html" "url": "https://github.com/yutent/vscode-string-html"
}, },
"engines": { "engines": {
"vscode": "^1.22.0" "vscode": "^1.58.0"
}, },
"scripts": { "scripts": {
"start": "node build.mjs --watch",
"build": "node build.mjs" "build": "node build.mjs"
}, },
"categories": [ "categories": [
@ -91,28 +92,12 @@
"meta.embedded.block.css": "scss", "meta.embedded.block.css": "scss",
"meta.template.expression.ts": "typescript" "meta.template.expression.ts": "typescript"
} }
},
{
"injectTo": [
"source.js",
"source.js.jsx",
"source.jsx",
"source.ts",
"source.ts.tsx",
"source.tsx"
],
"scopeName": "es6.inline.less",
"path": "./syntaxes/es6.inline.less.json",
"embeddedLanguages": {
"meta.embedded.block.css": "less",
"meta.template.expression.ts": "typescript"
}
} }
] ]
}, },
"dependencies": { "dependencies": {
"vscode-css-languageservice": "^3.0.7", "vscode-css-languageservice": "^6.2.6",
"vscode-emmet-helper": "^1.2.0", "@vscode/emmet-helper": "^2.8.8",
"vscode-html-languageservice": "^2.1.1" "vscode-html-languageservice": "^5.0.6"
} }
} }

View File

@ -1,28 +1,31 @@
// Code from https://github.com/Microsoft/typescript-styled-plugin/blob/master/src/styled-template-language-service.ts // Code from https://github.com/microsoft/typescript-styled-plugin/blob/main/src/_language-service.ts
function arePositionsEqual(left, right) {
return left.line === right.line && left.character === right.character
}
export class CompletionsCache { export class CompletionsCache {
_cachedCompletionsFile _cachedCompletionsFile
_cachedCompletionsPosition _cachedCompletionsPosition
_cachedCompletionsContent _cachedCompletionsContent
_completions _completions
equalPositions(left, right) {
return left.line === right.line && left.character === right.character
}
getCached(context, position) { getCached(context, position) {
if ( if (
this._completions && this._completions &&
context.fileName === this._cachedCompletionsFile && context.fileName === this._cachedCompletionsFile &&
this._cachedCompletionsPosition && this._cachedCompletionsPosition &&
this.equalPositions(position, this._cachedCompletionsPosition) && arePositionsEqual(position, this._cachedCompletionsPosition) &&
context.getText() === this._cachedCompletionsContent context.text === this._cachedCompletionsContent
) { ) {
return this._completions return this._completions
} }
return undefined
} }
updateCached(context, position, completions) { updateCached(context, position, completions) {
this._cachedCompletionsFile = context.fileName this._cachedCompletionsFile = context.fileName
this._cachedCompletionsPosition = position this._cachedCompletionsPosition = position
this._cachedCompletionsContent = context.getText() this._cachedCompletionsContent = context.text
this._completions = completions this._completions = completions
} }
} }

View File

@ -1,4 +1,4 @@
import { languages as Languages } from 'vscode' import { languages } from 'vscode'
import { HTMLCompletionItemProvider } from './providers/html.js' import { HTMLCompletionItemProvider } from './providers/html.js'
import { import {
CSSCompletionItemProvider, CSSCompletionItemProvider,
@ -15,7 +15,12 @@ const selector = [
export function activate(Context) { export function activate(Context) {
new CodeFormatterProvider() new CodeFormatterProvider()
Languages.registerCompletionItemProvider(
languages.registerHoverProvider(selector, new HTMLHoverProvider())
languages.registerHoverProvider(selector, new CSSHoverProvider())
// HTMLCompletionItemProvider
languages.registerCompletionItemProvider(
selector, selector,
new HTMLCompletionItemProvider(), new HTMLCompletionItemProvider(),
'<', '<',
@ -37,8 +42,9 @@ export function activate(Context) {
'8', '8',
'9' '9'
) )
Languages.registerHoverProvider(selector, new HTMLHoverProvider())
Languages.registerCompletionItemProvider( // HTMLStyleCompletionItemProvider
languages.registerCompletionItemProvider(
selector, selector,
new HTMLStyleCompletionItemProvider(), new HTMLStyleCompletionItemProvider(),
'!', '!',
@ -59,8 +65,9 @@ export function activate(Context) {
'8', '8',
'9' '9'
) )
Languages.registerHoverProvider(selector, new CSSHoverProvider())
Languages.registerCompletionItemProvider( // CSSCompletionItemProvider
languages.registerCompletionItemProvider(
selector, selector,
new CSSCompletionItemProvider(), new CSSCompletionItemProvider(),
'!', '!',

View File

@ -1,6 +1,6 @@
import { getLanguageService as GetHTMLanguageService } from 'vscode-html-languageservice' import { getLanguageService } from 'vscode-html-languageservice'
import { getSCSSLanguageService as GetSCSSLanguageService } from 'vscode-css-languageservice' import { getSCSSLanguageService } from 'vscode-css-languageservice'
import * as emmet from 'vscode-emmet-helper' import * as emmet from '@vscode/emmet-helper'
import { import {
GetEmmetConfiguration, GetEmmetConfiguration,
MatchOffset, MatchOffset,
@ -12,10 +12,11 @@ import {
import { CompletionsCache } from '../cache.js' import { CompletionsCache } from '../cache.js'
export class HTMLStyleCompletionItemProvider { export class HTMLStyleCompletionItemProvider {
_cssLanguageService = GetSCSSLanguageService() _cssLanguageService = getSCSSLanguageService()
_HTMLanguageService = GetHTMLanguageService() _HTMLanguageService = getLanguageService()
_expression = /(\/\*\s*html\s*\*\/\s*`|html\s*`)([^`]*)(`)/g _expression = /(html\s*`)([^`]*)(`)/g
_cache = new CompletionsCache() _cache = new CompletionsCache()
provideCompletionItems(document, position, _token) { provideCompletionItems(document, position, _token) {
const cached = this._cache.getCached(document, position) const cached = this._cache.getCached(document, position)
if (cached) { if (cached) {
@ -83,10 +84,12 @@ export class HTMLStyleCompletionItemProvider {
return item return item
} }
} }
export class CSSCompletionItemProvider { export class CSSCompletionItemProvider {
_CSSLanguageService = GetSCSSLanguageService() _CSSLanguageService = getSCSSLanguageService()
_expression = /(\/\*\s*(css|less|scss|sass)\s*\*\/\s*`|css\s*`)([^`]*)(`)/g _expression = /(css\s*`)([^`]*)(`)/g
_cache = new CompletionsCache() _cache = new CompletionsCache()
provideCompletionItems(document, position, _token) { provideCompletionItems(document, position, _token) {
const cached = this._cache.getCached(document, position) const cached = this._cache.getCached(document, position)
if (cached) { if (cached) {

View File

@ -1,10 +1,5 @@
import { import { Range, WorkspaceEdit, workspace, commands } from 'vscode'
Range, import { getLanguageService } from 'vscode-html-languageservice'
WorkspaceEdit,
workspace as Workspace,
commands as Commands
} from 'vscode'
import { getLanguageService as GetHTMLanguageService } from 'vscode-html-languageservice'
import { import {
CreateVirtualDocument, CreateVirtualDocument,
TranslateHTMLTextEdits, TranslateHTMLTextEdits,
@ -12,15 +7,17 @@ import {
} from '../util.js' } from '../util.js'
export class CodeFormatterProvider { export class CodeFormatterProvider {
_expression = /(\/\*\s*html\s*\*\/\s*`|html\s*`)([^`]*)(`)/g _expression = /(html\s*`)([^`]*)(`)/g
document document
constructor() { constructor() {
Commands.registerTextEditorCommand( commands.registerTextEditorCommand(
'editor.action.formatInlineHtml', 'editor.action.formatInlineHtml',
this.format, this.format,
this this
) )
} }
format(textEditor) { format(textEditor) {
this.document = textEditor.document this.document = textEditor.document
var documentText = this.document.getText() var documentText = this.document.getText()
@ -40,7 +37,7 @@ export class CodeFormatterProvider {
var vHTML = CreateVirtualDocument('html', text) var vHTML = CreateVirtualDocument('html', text)
// TODO - Expose Formatting Options // TODO - Expose Formatting Options
const edits = TranslateHTMLTextEdits( const edits = TranslateHTMLTextEdits(
GetHTMLanguageService().format(vHTML, null, { getLanguageService().format(vHTML, null, {
indentInnerHtml: false, indentInnerHtml: false,
preserveNewLines: true, preserveNewLines: true,
tabSize: textEditor.options.tabSize, tabSize: textEditor.options.tabSize,
@ -49,7 +46,7 @@ export class CodeFormatterProvider {
}), }),
matchStartPosition.line + 1 matchStartPosition.line + 1
) )
Workspace.applyEdit(this.composeEdits(this.document.uri, edits)) workspace.applyEdit(this.composeEdits(this.document.uri, edits))
} }
composeEdits(uri, edits) { composeEdits(uri, edits) {
var ws = new WorkspaceEdit() var ws = new WorkspaceEdit()

View File

@ -1,12 +1,12 @@
import { getLanguageService as GetHtmlLanguageService } from 'vscode-html-languageservice' import { getLanguageService } from 'vscode-html-languageservice'
import { getCSSLanguageService as GetCssLanguageService } from 'vscode-css-languageservice' import { getCSSLanguageService } from 'vscode-css-languageservice'
import { CreateVirtualDocument, MatchOffset } from '../util.js' import { CreateVirtualDocument, MatchOffset } from '../util.js'
export class HTMLHoverProvider { export class HTMLHoverProvider {
_htmlLanguageService = GetHtmlLanguageService() _htmlLanguageService = getLanguageService()
_cssLanguageService = GetCssLanguageService() _cssLanguageService = getCSSLanguageService()
// private _expression = /(html\s*`)([^`]*)(`)/g _expression = /(html\s*`)([^`]*)(`)/g
_expression = /(\/\*\s*html\s*\*\/\s*`|html\s*`)([^`]*)(`)/g
provideHover(document, position, token) { provideHover(document, position, token) {
const currentOffset = document.offsetAt(position) const currentOffset = document.offsetAt(position)
const documentText = document.getText() const documentText = document.getText()
@ -35,10 +35,12 @@ export class HTMLHoverProvider {
return hover return hover
} }
} }
export class CSSHoverProvider { export class CSSHoverProvider {
_htmlLanguageService = GetHtmlLanguageService() _htmlLanguageService = getLanguageService()
_cssLanguageService = GetCssLanguageService() _cssLanguageService = getCSSLanguageService()
_expression = /(\/\*\s*(css|less|scss)\s*\*\/\s*`|css\s*`)([^`]*)(`)/g _expression = /(css\s*`)([^`]*)(`)/g
provideHover(document, position, token) { provideHover(document, position, token) {
const currentOffset = document.offsetAt(position) const currentOffset = document.offsetAt(position)
const documentText = document.getText() const documentText = document.getText()

View File

@ -1,5 +1,5 @@
import { getLanguageService as GetHTMLanguageService } from 'vscode-html-languageservice' import { getLanguageService } from 'vscode-html-languageservice'
import * as emmet from 'vscode-emmet-helper' import * as emmet from '@vscode/emmet-helper'
import { import {
GetEmmetConfiguration, GetEmmetConfiguration,
MatchOffset, MatchOffset,
@ -9,10 +9,10 @@ import {
import { CompletionsCache } from '../cache.js' import { CompletionsCache } from '../cache.js'
export class HTMLCompletionItemProvider { export class HTMLCompletionItemProvider {
_htmlLanguageService = GetHTMLanguageService() _htmlLanguageService = getLanguageService()
_expression = /(\/\*\s*html\s*\*\/\s*`|html\s*`)([^`]*)(`)/g _expression = /(html\s*`)([^`]*)(`)/g
// private _expression = /(html\s*`)([^`]*)(`)/g
_cache = new CompletionsCache() _cache = new CompletionsCache()
provideCompletionItems(document, position, token) { provideCompletionItems(document, position, token) {
const cached = this._cache.getCached(document, position) const cached = this._cache.getCached(document, position)
if (cached) { if (cached) {

View File

@ -1,8 +1,5 @@
import { workspace, TextEdit, Position, Range } from 'vscode' import { workspace, TextEdit, Position, Range } from 'vscode'
import { import { TextDocument, TokenType } from 'vscode-html-languageservice'
TextDocument as HTMLTextDocument,
TokenType as HTMLTokenType
} from 'vscode-html-languageservice'
export function GetEmmetConfiguration() { export function GetEmmetConfiguration() {
const emmetConfig = workspace.getConfiguration('emmet') const emmetConfig = workspace.getConfiguration('emmet')
@ -47,9 +44,9 @@ export function GetLanguageRegions(service, data) {
const scanner = service.createScanner(data) const scanner = service.createScanner(data)
const regions = [] const regions = []
let tokenType let tokenType
while ((tokenType = scanner.scan()) !== HTMLTokenType.EOS) { while ((tokenType = scanner.scan()) !== TokenType.EOS) {
switch (tokenType) { switch (tokenType) {
case HTMLTokenType.Styles: case TokenType.Styles:
regions.push({ regions.push({
languageId: 'css', languageId: 'css',
start: scanner.getTokenOffset(), start: scanner.getTokenOffset(),
@ -111,12 +108,12 @@ export function TranslateCompletionItems(items, line, expand = false) {
}) })
} }
export function CreateVirtualDocument( export function CreateVirtualDocument(
// context: TextDocument | HTMLTextDocument, // context: TextDocument | TextDocument,
languageId, languageId,
// position: Position | HtmlPosition, // position: Position | HtmlPosition,
content content
) { ) {
const doc = HTMLTextDocument.create( const doc = TextDocument.create(
`embedded://document.${languageId}`, `embedded://document.${languageId}`,
languageId, languageId,
1, 1,

View File

@ -1,10 +1,11 @@
{ {
"scopeName": "es6.inline.css",
"fileTypes": ["js", "jsx", "ts", "tsx"], "fileTypes": ["js", "jsx", "ts", "tsx"],
"injectionSelector": "L:source.js -comment -string, L:source.jsx -comment -string, L:source.ts -comment -string, L:source.tsx -comment -string", "injectionSelector": "L:source.js -comment -string, L:source.jsx -comment -string, L:source.ts -comment -string, L:source.tsx -comment -string",
"patterns": [ "patterns": [
{ {
"contentName": "meta.embedded.block.css", "contentName": "meta.embedded.block.css",
"begin": "(?x)(\\s*?(\\w+\\.)?(?:css|/\\*\\s*css\\s*\\*/)\\s*)(`)", "begin": "(?x)(\\s*?(\\w+\\.)?(?:css)\\s*)(`)",
"beginCaptures": { "beginCaptures": {
"0": { "0": {
"name": "string.template.ts, punctuation.definition.string.template.begin.ts" "name": "string.template.ts, punctuation.definition.string.template.begin.ts"
@ -31,6 +32,5 @@
{ {
"include": "source.ts#template-substitution-element" "include": "source.ts#template-substitution-element"
} }
], ]
"scopeName": "es6.inline.css"
} }

View File

@ -1,4 +1,5 @@
{ {
"scopeName": "es6.inline.html",
"fileTypes": ["js", "jsx", "ts", "tsx"], "fileTypes": ["js", "jsx", "ts", "tsx"],
"injectionSelector": "L:source.js -comment -string, L:source.jsx -comment -string, L:source.ts -comment -string, L:source.tsx -comment -string", "injectionSelector": "L:source.js -comment -string, L:source.jsx -comment -string, L:source.ts -comment -string, L:source.tsx -comment -string",
"injections": { "injections": {
@ -14,7 +15,7 @@
"patterns": [ "patterns": [
{ {
"contentName": "meta.embedded.block.html", "contentName": "meta.embedded.block.html",
"begin": "(?x)(\\s*?(\\w+\\.)?(?:html|/\\*\\s*html\\s*\\*/)\\s*)(`)", "begin": "(?x)(\\s*?(\\w+\\.)?(?:html)\\s*)(`)",
"beginCaptures": { "beginCaptures": {
"0": { "0": {
"name": "string.template.ts, punctuation.definition.string.template.begin.ts" "name": "string.template.ts, punctuation.definition.string.template.begin.ts"
@ -41,6 +42,5 @@
{ {
"include": "source.ts#template-substitution-element" "include": "source.ts#template-substitution-element"
} }
], ]
"scopeName": "es6.inline.html"
} }

View File

@ -1,36 +0,0 @@
{
"fileTypes": ["js", "jsx", "ts", "tsx"],
"injectionSelector": "L:source.js -comment -string, L:source.jsx -comment -string, L:source.ts -comment -string, L:source.tsx -comment -string",
"patterns": [
{
"contentName": "meta.embedded.block.css",
"begin": "(?x)(\\s*?(\\w+\\.)?(?:less|/\\*\\s*less\\s*\\*/)\\s*)(`)",
"beginCaptures": {
"0": {
"name": "string.template.ts, punctuation.definition.string.template.begin.ts"
},
"1": {
"name": "entity.name.function.tagged-template.ts"
}
},
"end": "(`)",
"endCaptures": {
"0": {
"name": "string.template.ts, punctuation.definition.string.template.end.ts"
}
},
"patterns": [
{
"include": "source.ts#template-substitution-element"
},
{
"include": "source.css.less"
}
]
},
{
"include": "source.ts#template-substitution-element"
}
],
"scopeName": "es6.inline.less"
}

View File

@ -1,10 +1,11 @@
{ {
"scopeName": "es6.inline.scss",
"fileTypes": ["js", "jsx", "ts", "tsx"], "fileTypes": ["js", "jsx", "ts", "tsx"],
"injectionSelector": "L:source.js -comment -string, L:source.jsx -comment -string, L:source.ts -comment -string, L:source.tsx -comment -string", "injectionSelector": "L:source.js -comment -string, L:source.jsx -comment -string, L:source.ts -comment -string, L:source.tsx -comment -string",
"patterns": [ "patterns": [
{ {
"contentName": "meta.embedded.block.css", "contentName": "meta.embedded.block.css",
"begin": "(?x)(\\s*?(\\w+\\.)?(?:scss|/\\*\\s*scss\\s*\\*/)\\s*)(`)", "begin": "(?x)(\\s*?(\\w+\\.)?(?:scss)\\s*)(`)",
"beginCaptures": { "beginCaptures": {
"0": { "0": {
"name": "string.template.ts, punctuation.definition.string.template.begin.ts" "name": "string.template.ts, punctuation.definition.string.template.begin.ts"
@ -32,5 +33,158 @@
"include": "source.ts#template-substitution-element" "include": "source.ts#template-substitution-element"
} }
], ],
"scopeName": "es6.inline.scss" "repository": {
"reserved-words": {
"name": "support.type.property-name.css.postcss",
"match": "\\b(false|from|in|not|null|through|to|true)\\b"
},
"double-quoted": {
"patterns": [
{
"include": "#quoted-interpolation"
}
],
"begin": "\"",
"name": "string.quoted.double.css.postcss",
"end": "\""
},
"operator": {
"name": "keyword.operator.postcss",
"match": "\\+|\\s-\\s|\\s-(?=\\$)|(?<=\\()-(?=\\$)|\\s-(?=\\()|\\*|/|%|=|!|<|>|~"
},
"function-content": {
"name": "string.quoted.double.css.postcss",
"match": "(?<=url\\(|format\\(|attr\\().+?(?=\\))"
},
"double-slash": {
"patterns": [
{
"include": "#comment-tag"
}
],
"begin": "//",
"name": "comment.line.postcss",
"end": "$"
},
"numeric": {
"name": "constant.numeric.css.postcss",
"match": "(-|\\.)?[0-9]+(\\.[0-9]+)?"
},
"variable-root-css": {
"name": "variable.parameter.postcss",
"match": "(?<!&)--[\\w-]+"
},
"function": {
"name": "support.function.name.postcss",
"match": "(?<=[\\s|\\(|,|:])(?!url|format|attr)[\\w-][\\w-]*(?=\\()"
},
"rgb-value": {
"name": "constant.other.color.rgb-value.css.postcss",
"match": "(#)([0-9a-fA-F]{3}|[0-9a-fA-F]{6})\\b"
},
"comment-tag": {
"patterns": [
{
"name": "comment.tag.postcss",
"match": "[\\w-]+"
}
],
"begin": "{{",
"name": "comment.tags.postcss",
"end": "}}"
},
"interpolation": {
"patterns": [
{
"include": "#variable"
},
{
"include": "#numeric"
},
{
"include": "#operator"
},
{
"include": "#unit"
},
{
"include": "#double-quoted"
},
{
"include": "#single-quoted"
}
],
"begin": "#{",
"name": "support.function.interpolation.postcss",
"end": "}"
},
"unit": {
"name": "keyword.other.unit.css.postcss",
"match": "(?<=[\\d]|})(ch|cm|deg|dpcm|dpi|dppx|em|ex|grad|Hz|in|kHz|mm|ms|pc|pt|px|rad|rem|s|turn|vh|vmax|vmin|vw|%)"
},
"function-content-var": {
"name": "variable.parameter.postcss",
"match": "(?<=var\\()[\\w-]+(?=\\))"
},
"dotdotdot": {
"name": "variable.other",
"match": "\\.{3}"
},
"variable": {
"name": "variable.parameter.postcss",
"match": "\\$[\\w-]+"
},
"single-quoted": {
"patterns": [
{
"include": "#quoted-interpolation"
}
],
"begin": "'",
"name": "string.quoted.single.css.postcss",
"end": "'"
},
"quoted-interpolation": {
"patterns": [
{
"include": "#variable"
},
{
"include": "#numeric"
},
{
"include": "#operator"
},
{
"include": "#unit"
}
],
"begin": "#{",
"name": "support.function.interpolation.postcss",
"end": "}"
},
"pseudo-class": {
"name": "entity.other.attribute-name.pseudo-class.css.postcss",
"match": ":[a-z:-]+"
},
"property-value": {
"name": "meta.property-value.css.postcss, support.constant.property-value.css.postcss",
"match": "[\\w-]+"
},
"placeholder-selector": {
"begin": "(?<!\\d)%(?!\\d)",
"name": "entity.other.attribute-name.placeholder-selector.postcss",
"end": "$\\n?|\\s|(?=;|{)"
},
"flag": {
"name": "keyword.other.important.css.postcss",
"match": "!(important|default|optional|global)"
},
"parent-selector": {
"name": "entity.name.tag.css.postcss",
"match": "&"
}
},
"foldingStartMarker": "/\\*|^#|^\\*|^\\b|^\\.",
"foldingStopMarker": "\\*/|^\\s*$"
} }

View File

@ -23,14 +23,16 @@ function bug() {
} }
css` css`
:host { .foo {
display: block; .bar {
color: #f30;
}
} }
` `
css` css`
:host { :host {
display: block; display: flex;
height: 50px; height: 50px;
} }
` `