更换ts为js
parent
7d4010cdf6
commit
a3dd345793
|
@ -0,0 +1,26 @@
|
||||||
|
// Code from https://github.com/Microsoft/typescript-styled-plugin/blob/master/src/styled-template-language-service.ts
|
||||||
|
export class CompletionsCache {
|
||||||
|
_cachedCompletionsFile;
|
||||||
|
_cachedCompletionsPosition;
|
||||||
|
_cachedCompletionsContent;
|
||||||
|
_completions;
|
||||||
|
equalPositions(left, right) {
|
||||||
|
return left.line === right.line && left.character === right.character;
|
||||||
|
}
|
||||||
|
getCached(context, position) {
|
||||||
|
if (this._completions &&
|
||||||
|
context.fileName === this._cachedCompletionsFile &&
|
||||||
|
this._cachedCompletionsPosition &&
|
||||||
|
this.equalPositions(position, this._cachedCompletionsPosition) &&
|
||||||
|
context.getText() === this._cachedCompletionsContent) {
|
||||||
|
return this._completions;
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
updateCached(context, position, completions) {
|
||||||
|
this._cachedCompletionsFile = context.fileName;
|
||||||
|
this._cachedCompletionsPosition = position;
|
||||||
|
this._cachedCompletionsContent = context.getText();
|
||||||
|
this._completions = completions;
|
||||||
|
}
|
||||||
|
}
|
42
src/cache.ts
42
src/cache.ts
|
@ -1,42 +0,0 @@
|
||||||
// Code from https://github.com/Microsoft/typescript-styled-plugin/blob/master/src/styled-template-language-service.ts
|
|
||||||
|
|
||||||
import { CompletionList, TextDocument, Position } from 'vscode'
|
|
||||||
|
|
||||||
export class CompletionsCache {
|
|
||||||
private _cachedCompletionsFile?: string
|
|
||||||
private _cachedCompletionsPosition?: Position
|
|
||||||
private _cachedCompletionsContent?: string
|
|
||||||
private _completions?: CompletionList
|
|
||||||
|
|
||||||
private equalPositions(left: Position, right: Position): boolean {
|
|
||||||
return left.line === right.line && left.character === right.character
|
|
||||||
}
|
|
||||||
|
|
||||||
public getCached(
|
|
||||||
context: TextDocument,
|
|
||||||
position: Position
|
|
||||||
): CompletionList | undefined {
|
|
||||||
if (
|
|
||||||
this._completions &&
|
|
||||||
context.fileName === this._cachedCompletionsFile &&
|
|
||||||
this._cachedCompletionsPosition &&
|
|
||||||
this.equalPositions(position, this._cachedCompletionsPosition) &&
|
|
||||||
context.getText() === this._cachedCompletionsContent
|
|
||||||
) {
|
|
||||||
return this._completions
|
|
||||||
}
|
|
||||||
|
|
||||||
return undefined
|
|
||||||
}
|
|
||||||
|
|
||||||
public updateCached(
|
|
||||||
context: TextDocument,
|
|
||||||
position: Position,
|
|
||||||
completions: any
|
|
||||||
) {
|
|
||||||
this._cachedCompletionsFile = context.fileName
|
|
||||||
this._cachedCompletionsPosition = position
|
|
||||||
this._cachedCompletionsContent = context.getText()
|
|
||||||
this._completions = completions
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
import { languages as Languages } from 'vscode';
|
||||||
|
import { HTMLCompletionItemProvider } from './providers/html';
|
||||||
|
import { CSSCompletionItemProvider, HTMLStyleCompletionItemProvider } from './providers/css';
|
||||||
|
import { HTMLHoverProvider, CSSHoverProvider } from './providers/hover';
|
||||||
|
import { CodeFormatterProvider } from './providers/formatting';
|
||||||
|
const selector = [
|
||||||
|
'typescriptreact',
|
||||||
|
'javascriptreact',
|
||||||
|
'typescript',
|
||||||
|
'javascript'
|
||||||
|
];
|
||||||
|
export function activate(Context) {
|
||||||
|
new CodeFormatterProvider();
|
||||||
|
Languages.registerCompletionItemProvider(selector, new HTMLCompletionItemProvider(), '<', '!', '.', '}', ':', '*', '$', ']', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9');
|
||||||
|
Languages.registerHoverProvider(selector, new HTMLHoverProvider());
|
||||||
|
Languages.registerCompletionItemProvider(selector, new HTMLStyleCompletionItemProvider(), '!', '.', '}', ':', '*', '$', ']', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9');
|
||||||
|
Languages.registerHoverProvider(selector, new CSSHoverProvider());
|
||||||
|
Languages.registerCompletionItemProvider(selector, new CSSCompletionItemProvider(), '!', '.', '}', ':', '*', '$', ']', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9');
|
||||||
|
}
|
91
src/main.ts
91
src/main.ts
|
@ -1,91 +0,0 @@
|
||||||
import {
|
|
||||||
languages as Languages,
|
|
||||||
ExtensionContext,
|
|
||||||
commands as Commands,
|
|
||||||
DocumentSelector
|
|
||||||
} from 'vscode'
|
|
||||||
import { HTMLCompletionItemProvider } from './providers/html'
|
|
||||||
import {
|
|
||||||
CSSCompletionItemProvider,
|
|
||||||
HTMLStyleCompletionItemProvider
|
|
||||||
} from './providers/css'
|
|
||||||
import { HTMLHoverProvider, CSSHoverProvider } from './providers/hover'
|
|
||||||
import { CodeFormatterProvider } from './providers/formatting'
|
|
||||||
|
|
||||||
const selector: DocumentSelector = [
|
|
||||||
'typescriptreact',
|
|
||||||
'javascriptreact',
|
|
||||||
'typescript',
|
|
||||||
'javascript'
|
|
||||||
]
|
|
||||||
|
|
||||||
export function activate(Context: ExtensionContext) {
|
|
||||||
new CodeFormatterProvider()
|
|
||||||
|
|
||||||
Languages.registerCompletionItemProvider(
|
|
||||||
selector,
|
|
||||||
new HTMLCompletionItemProvider(),
|
|
||||||
'<',
|
|
||||||
'!',
|
|
||||||
'.',
|
|
||||||
'}',
|
|
||||||
':',
|
|
||||||
'*',
|
|
||||||
'$',
|
|
||||||
']',
|
|
||||||
'0',
|
|
||||||
'1',
|
|
||||||
'2',
|
|
||||||
'3',
|
|
||||||
'4',
|
|
||||||
'5',
|
|
||||||
'6',
|
|
||||||
'7',
|
|
||||||
'8',
|
|
||||||
'9'
|
|
||||||
)
|
|
||||||
Languages.registerHoverProvider(selector, new HTMLHoverProvider())
|
|
||||||
Languages.registerCompletionItemProvider(
|
|
||||||
selector,
|
|
||||||
new HTMLStyleCompletionItemProvider(),
|
|
||||||
'!',
|
|
||||||
'.',
|
|
||||||
'}',
|
|
||||||
':',
|
|
||||||
'*',
|
|
||||||
'$',
|
|
||||||
']',
|
|
||||||
'0',
|
|
||||||
'1',
|
|
||||||
'2',
|
|
||||||
'3',
|
|
||||||
'4',
|
|
||||||
'5',
|
|
||||||
'6',
|
|
||||||
'7',
|
|
||||||
'8',
|
|
||||||
'9'
|
|
||||||
)
|
|
||||||
Languages.registerHoverProvider(selector, new CSSHoverProvider())
|
|
||||||
Languages.registerCompletionItemProvider(
|
|
||||||
selector,
|
|
||||||
new CSSCompletionItemProvider(),
|
|
||||||
'!',
|
|
||||||
'.',
|
|
||||||
'}',
|
|
||||||
':',
|
|
||||||
'*',
|
|
||||||
'$',
|
|
||||||
']',
|
|
||||||
'0',
|
|
||||||
'1',
|
|
||||||
'2',
|
|
||||||
'3',
|
|
||||||
'4',
|
|
||||||
'5',
|
|
||||||
'6',
|
|
||||||
'7',
|
|
||||||
'8',
|
|
||||||
'9'
|
|
||||||
)
|
|
||||||
}
|
|
|
@ -0,0 +1,122 @@
|
||||||
|
import { getLanguageService as GetHTMLanguageService } from 'vscode-html-languageservice';
|
||||||
|
import { getSCSSLanguageService as GetSCSSLanguageService } from 'vscode-css-languageservice';
|
||||||
|
import * as emmet from 'vscode-emmet-helper';
|
||||||
|
import { GetEmmetConfiguration, MatchOffset, CreateVirtualDocument, GetLanguageRegions, GetRegionAtOffset, TranslateCompletionItems } from '../util';
|
||||||
|
import { CompletionsCache } from '../cache';
|
||||||
|
export class HTMLStyleCompletionItemProvider {
|
||||||
|
_cssLanguageService = GetSCSSLanguageService();
|
||||||
|
_HTMLanguageService = GetHTMLanguageService();
|
||||||
|
_expression = /(\/\*\s*html\s*\*\/\s*`|html\s*`)([^`]*)(`)/g;
|
||||||
|
_cache = new CompletionsCache();
|
||||||
|
provideCompletionItems(document, position, _token) {
|
||||||
|
const cached = this._cache.getCached(document, position);
|
||||||
|
if (cached) {
|
||||||
|
return cached;
|
||||||
|
}
|
||||||
|
const currentLine = document.lineAt(position.line);
|
||||||
|
const empty = {
|
||||||
|
isIncomplete: false,
|
||||||
|
items: []
|
||||||
|
};
|
||||||
|
if (currentLine.isEmptyOrWhitespace) {
|
||||||
|
return empty;
|
||||||
|
}
|
||||||
|
const currentLineText = currentLine.text.trim();
|
||||||
|
const currentOffset = document.offsetAt(position);
|
||||||
|
const documentText = document.getText();
|
||||||
|
const match = MatchOffset(this._expression, documentText, currentOffset);
|
||||||
|
if (!match) {
|
||||||
|
return empty;
|
||||||
|
}
|
||||||
|
// tslint:disable-next-line:no-magic-numbers
|
||||||
|
const matchContent = match[2];
|
||||||
|
const matchStartOffset = match.index + match[1].length;
|
||||||
|
const matchEndOffset = match.index + match[0].length;
|
||||||
|
const regions = GetLanguageRegions(this._HTMLanguageService, matchContent);
|
||||||
|
if (regions.length <= 0) {
|
||||||
|
return empty;
|
||||||
|
}
|
||||||
|
const region = GetRegionAtOffset(regions, currentOffset - matchStartOffset);
|
||||||
|
if (!region) {
|
||||||
|
return empty;
|
||||||
|
}
|
||||||
|
const virtualOffset = currentOffset - (matchStartOffset + region.start);
|
||||||
|
const virtualDocument = CreateVirtualDocument('css', region.content);
|
||||||
|
const stylesheet = this._cssLanguageService.parseStylesheet(virtualDocument);
|
||||||
|
const emmetResults = {
|
||||||
|
isIncomplete: true,
|
||||||
|
items: []
|
||||||
|
};
|
||||||
|
this._cssLanguageService.setCompletionParticipants([
|
||||||
|
emmet.getEmmetCompletionParticipants(virtualDocument, virtualDocument.positionAt(virtualOffset), 'css', GetEmmetConfiguration(), emmetResults)
|
||||||
|
]);
|
||||||
|
const completions = this._cssLanguageService.doComplete(virtualDocument, virtualDocument.positionAt(virtualOffset), stylesheet);
|
||||||
|
if (emmetResults.items.length) {
|
||||||
|
completions.items.push(...emmetResults.items);
|
||||||
|
completions.isIncomplete = true;
|
||||||
|
}
|
||||||
|
this._cache.updateCached(document, position, completions);
|
||||||
|
return {
|
||||||
|
isIncomplete: completions.isIncomplete,
|
||||||
|
items: TranslateCompletionItems(completions.items, currentLine)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
resolveCompletionItem(item, _token) {
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
export class CSSCompletionItemProvider {
|
||||||
|
_CSSLanguageService = GetSCSSLanguageService();
|
||||||
|
_expression = /(\/\*\s*(css|less|scss|sass)\s*\*\/\s*`|css\s*`)([^`]*)(`)/g;
|
||||||
|
_cache = new CompletionsCache();
|
||||||
|
provideCompletionItems(document, position, _token) {
|
||||||
|
const cached = this._cache.getCached(document, position);
|
||||||
|
if (cached) {
|
||||||
|
return cached;
|
||||||
|
}
|
||||||
|
const currentLine = document.lineAt(position.line);
|
||||||
|
const empty = {
|
||||||
|
isIncomplete: false,
|
||||||
|
items: []
|
||||||
|
};
|
||||||
|
if (currentLine.isEmptyOrWhitespace) {
|
||||||
|
return empty;
|
||||||
|
}
|
||||||
|
const currentLineText = currentLine.text.trim();
|
||||||
|
const currentOffset = document.offsetAt(position);
|
||||||
|
const documentText = document.getText();
|
||||||
|
const match = MatchOffset(this._expression, documentText, currentOffset);
|
||||||
|
if (!match) {
|
||||||
|
return empty;
|
||||||
|
}
|
||||||
|
const dialect = match[2];
|
||||||
|
// tslint:disable-next-line:no-magic-numbers
|
||||||
|
const matchContent = match[3];
|
||||||
|
const matchStartOffset = match.index + match[1].length;
|
||||||
|
const matchEndOffset = match.index + match[0].length;
|
||||||
|
const matchPosition = document.positionAt(matchStartOffset);
|
||||||
|
const virtualOffset = currentOffset - matchStartOffset;
|
||||||
|
const virtualDocument = CreateVirtualDocument(dialect, matchContent);
|
||||||
|
const vCss = this._CSSLanguageService.parseStylesheet(virtualDocument);
|
||||||
|
const emmetResults = {
|
||||||
|
isIncomplete: true,
|
||||||
|
items: []
|
||||||
|
};
|
||||||
|
this._CSSLanguageService.setCompletionParticipants([
|
||||||
|
emmet.getEmmetCompletionParticipants(virtualDocument, virtualDocument.positionAt(virtualOffset), dialect, GetEmmetConfiguration(), emmetResults)
|
||||||
|
]);
|
||||||
|
const completions = this._CSSLanguageService.doComplete(virtualDocument, virtualDocument.positionAt(virtualOffset), vCss);
|
||||||
|
if (emmetResults.items.length) {
|
||||||
|
completions.items.push(...emmetResults.items);
|
||||||
|
completions.isIncomplete = true;
|
||||||
|
}
|
||||||
|
this._cache.updateCached(document, position, completions);
|
||||||
|
return {
|
||||||
|
isIncomplete: completions.isIncomplete,
|
||||||
|
items: TranslateCompletionItems(completions.items, currentLine)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
resolveCompletionItem(item, _token) {
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,218 +0,0 @@
|
||||||
import {
|
|
||||||
CompletionList,
|
|
||||||
CompletionItem,
|
|
||||||
TextDocument,
|
|
||||||
Position,
|
|
||||||
CancellationToken,
|
|
||||||
CompletionItemProvider
|
|
||||||
} from 'vscode'
|
|
||||||
|
|
||||||
import {
|
|
||||||
getLanguageService as GetHTMLanguageService,
|
|
||||||
LanguageService as HTMLanguageService,
|
|
||||||
CompletionList as HTMLCompletionList
|
|
||||||
} from 'vscode-html-languageservice'
|
|
||||||
|
|
||||||
import {
|
|
||||||
getSCSSLanguageService as GetSCSSLanguageService,
|
|
||||||
LanguageService as CSSLanguageService,
|
|
||||||
CompletionList as CSSCompletionList
|
|
||||||
} from 'vscode-css-languageservice'
|
|
||||||
|
|
||||||
import * as emmet from 'vscode-emmet-helper'
|
|
||||||
import {
|
|
||||||
GetEmmetConfiguration,
|
|
||||||
MatchOffset,
|
|
||||||
CreateVirtualDocument,
|
|
||||||
GetLanguageRegions,
|
|
||||||
GetRegionAtOffset,
|
|
||||||
TranslateCompletionItems
|
|
||||||
} from '../util'
|
|
||||||
|
|
||||||
import { CompletionsCache } from '../cache'
|
|
||||||
|
|
||||||
export class HTMLStyleCompletionItemProvider implements CompletionItemProvider {
|
|
||||||
private _cssLanguageService: CSSLanguageService = GetSCSSLanguageService()
|
|
||||||
private _HTMLanguageService: HTMLanguageService = GetHTMLanguageService()
|
|
||||||
private _expression = /(\/\*\s*html\s*\*\/\s*`|html\s*`)([^`]*)(`)/g
|
|
||||||
private _cache = new CompletionsCache()
|
|
||||||
|
|
||||||
public provideCompletionItems(
|
|
||||||
document: TextDocument,
|
|
||||||
position: Position,
|
|
||||||
_token: CancellationToken
|
|
||||||
): CompletionList {
|
|
||||||
const cached = this._cache.getCached(document, position)
|
|
||||||
|
|
||||||
if (cached) {
|
|
||||||
return cached
|
|
||||||
}
|
|
||||||
|
|
||||||
const currentLine = document.lineAt(position.line)
|
|
||||||
const empty = {
|
|
||||||
isIncomplete: false,
|
|
||||||
items: []
|
|
||||||
} as CompletionList
|
|
||||||
|
|
||||||
if (currentLine.isEmptyOrWhitespace) {
|
|
||||||
return empty
|
|
||||||
}
|
|
||||||
|
|
||||||
const currentLineText = currentLine.text.trim()
|
|
||||||
const currentOffset = document.offsetAt(position)
|
|
||||||
const documentText = document.getText()
|
|
||||||
const match = MatchOffset(this._expression, documentText, currentOffset)
|
|
||||||
|
|
||||||
if (!match) {
|
|
||||||
return empty
|
|
||||||
}
|
|
||||||
|
|
||||||
// tslint:disable-next-line:no-magic-numbers
|
|
||||||
const matchContent: string = match[2]
|
|
||||||
const matchStartOffset = match.index + match[1].length
|
|
||||||
const matchEndOffset = match.index + match[0].length
|
|
||||||
const regions = GetLanguageRegions(this._HTMLanguageService, matchContent)
|
|
||||||
|
|
||||||
if (regions.length <= 0) {
|
|
||||||
return empty
|
|
||||||
}
|
|
||||||
|
|
||||||
const region = GetRegionAtOffset(regions, currentOffset - matchStartOffset)
|
|
||||||
|
|
||||||
if (!region) {
|
|
||||||
return empty
|
|
||||||
}
|
|
||||||
|
|
||||||
const virtualOffset = currentOffset - (matchStartOffset + region.start)
|
|
||||||
const virtualDocument = CreateVirtualDocument('css', region.content)
|
|
||||||
|
|
||||||
const stylesheet = this._cssLanguageService.parseStylesheet(virtualDocument)
|
|
||||||
const emmetResults: HTMLCompletionList = {
|
|
||||||
isIncomplete: true,
|
|
||||||
items: []
|
|
||||||
}
|
|
||||||
|
|
||||||
this._cssLanguageService.setCompletionParticipants([
|
|
||||||
emmet.getEmmetCompletionParticipants(
|
|
||||||
virtualDocument,
|
|
||||||
virtualDocument.positionAt(virtualOffset),
|
|
||||||
'css',
|
|
||||||
GetEmmetConfiguration(),
|
|
||||||
emmetResults
|
|
||||||
)
|
|
||||||
])
|
|
||||||
|
|
||||||
const completions = this._cssLanguageService.doComplete(
|
|
||||||
virtualDocument,
|
|
||||||
virtualDocument.positionAt(virtualOffset),
|
|
||||||
stylesheet
|
|
||||||
)
|
|
||||||
|
|
||||||
if (emmetResults.items.length) {
|
|
||||||
completions.items.push(...emmetResults.items)
|
|
||||||
completions.isIncomplete = true
|
|
||||||
}
|
|
||||||
|
|
||||||
this._cache.updateCached(document, position, completions)
|
|
||||||
|
|
||||||
return {
|
|
||||||
isIncomplete: completions.isIncomplete,
|
|
||||||
items: TranslateCompletionItems(completions.items, currentLine)
|
|
||||||
} as CompletionList
|
|
||||||
}
|
|
||||||
|
|
||||||
public resolveCompletionItem?(
|
|
||||||
item: CompletionItem,
|
|
||||||
_token: CancellationToken
|
|
||||||
): CompletionItem | Thenable<CompletionItem> {
|
|
||||||
return item
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class CSSCompletionItemProvider implements CompletionItemProvider {
|
|
||||||
private _CSSLanguageService: CSSLanguageService = GetSCSSLanguageService()
|
|
||||||
private _expression =
|
|
||||||
/(\/\*\s*(css|less|scss|sass)\s*\*\/\s*`|css\s*`)([^`]*)(`)/g
|
|
||||||
private _cache = new CompletionsCache()
|
|
||||||
|
|
||||||
public provideCompletionItems(
|
|
||||||
document: TextDocument,
|
|
||||||
position: Position,
|
|
||||||
_token: CancellationToken
|
|
||||||
): CompletionList {
|
|
||||||
const cached = this._cache.getCached(document, position)
|
|
||||||
|
|
||||||
if (cached) {
|
|
||||||
return cached
|
|
||||||
}
|
|
||||||
|
|
||||||
const currentLine = document.lineAt(position.line)
|
|
||||||
const empty = {
|
|
||||||
isIncomplete: false,
|
|
||||||
items: []
|
|
||||||
} as CompletionList
|
|
||||||
|
|
||||||
if (currentLine.isEmptyOrWhitespace) {
|
|
||||||
return empty
|
|
||||||
}
|
|
||||||
|
|
||||||
const currentLineText = currentLine.text.trim()
|
|
||||||
const currentOffset = document.offsetAt(position)
|
|
||||||
const documentText = document.getText()
|
|
||||||
const match = MatchOffset(this._expression, documentText, currentOffset)
|
|
||||||
|
|
||||||
if (!match) {
|
|
||||||
return empty
|
|
||||||
}
|
|
||||||
|
|
||||||
const dialect = match[2]
|
|
||||||
|
|
||||||
// tslint:disable-next-line:no-magic-numbers
|
|
||||||
const matchContent: string = match[3]
|
|
||||||
const matchStartOffset = match.index + match[1].length
|
|
||||||
const matchEndOffset = match.index + match[0].length
|
|
||||||
const matchPosition = document.positionAt(matchStartOffset)
|
|
||||||
const virtualOffset = currentOffset - matchStartOffset
|
|
||||||
const virtualDocument = CreateVirtualDocument(dialect, matchContent)
|
|
||||||
const vCss = this._CSSLanguageService.parseStylesheet(virtualDocument)
|
|
||||||
const emmetResults: CSSCompletionList = {
|
|
||||||
isIncomplete: true,
|
|
||||||
items: []
|
|
||||||
}
|
|
||||||
|
|
||||||
this._CSSLanguageService.setCompletionParticipants([
|
|
||||||
emmet.getEmmetCompletionParticipants(
|
|
||||||
virtualDocument,
|
|
||||||
virtualDocument.positionAt(virtualOffset),
|
|
||||||
dialect,
|
|
||||||
GetEmmetConfiguration(),
|
|
||||||
emmetResults
|
|
||||||
)
|
|
||||||
])
|
|
||||||
|
|
||||||
const completions = this._CSSLanguageService.doComplete(
|
|
||||||
virtualDocument,
|
|
||||||
virtualDocument.positionAt(virtualOffset),
|
|
||||||
vCss
|
|
||||||
)
|
|
||||||
|
|
||||||
if (emmetResults.items.length) {
|
|
||||||
completions.items.push(...emmetResults.items)
|
|
||||||
completions.isIncomplete = true
|
|
||||||
}
|
|
||||||
|
|
||||||
this._cache.updateCached(document, position, completions)
|
|
||||||
|
|
||||||
return {
|
|
||||||
isIncomplete: completions.isIncomplete,
|
|
||||||
items: TranslateCompletionItems(completions.items, currentLine)
|
|
||||||
} as CompletionList
|
|
||||||
}
|
|
||||||
|
|
||||||
public resolveCompletionItem?(
|
|
||||||
item: CompletionItem,
|
|
||||||
_token: CancellationToken
|
|
||||||
): CompletionItem | Thenable<CompletionItem> {
|
|
||||||
return item
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,40 @@
|
||||||
|
import { Range, WorkspaceEdit, workspace as Workspace, commands as Commands } from 'vscode';
|
||||||
|
import { getLanguageService as GetHTMLanguageService } from 'vscode-html-languageservice';
|
||||||
|
import { CreateVirtualDocument, TranslateHTMLTextEdits, Match } from '../util';
|
||||||
|
export class CodeFormatterProvider {
|
||||||
|
_expression = /(\/\*\s*html\s*\*\/\s*`|html\s*`)([^`]*)(`)/g;
|
||||||
|
document;
|
||||||
|
constructor() {
|
||||||
|
Commands.registerTextEditorCommand('editor.action.formatInlineHtml', this.format, this);
|
||||||
|
}
|
||||||
|
format(textEditor) {
|
||||||
|
this.document = textEditor.document;
|
||||||
|
var documentText = this.document.getText();
|
||||||
|
var match = Match(this._expression, documentText);
|
||||||
|
if (!match) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
// TODO - Refactor, This have been used multiple times thourgh out the
|
||||||
|
// TODO - extension.
|
||||||
|
var matchStartOffset = match.index + match[1].length;
|
||||||
|
var matchEndOffset = match.index + (match[2].length + match[3].length + 1);
|
||||||
|
var matchStartPosition = this.document.positionAt(matchStartOffset);
|
||||||
|
var matchEndPosition = this.document.positionAt(matchEndOffset);
|
||||||
|
var text = this.document.getText(new Range(matchStartPosition, matchEndPosition));
|
||||||
|
var vHTML = CreateVirtualDocument('html', text);
|
||||||
|
// TODO - Expose Formatting Options
|
||||||
|
const edits = TranslateHTMLTextEdits(GetHTMLanguageService().format(vHTML, null, {
|
||||||
|
indentInnerHtml: false,
|
||||||
|
preserveNewLines: true,
|
||||||
|
tabSize: textEditor.options.tabSize,
|
||||||
|
insertSpaces: textEditor.options.insertSpaces,
|
||||||
|
endWithNewline: true
|
||||||
|
}), matchStartPosition.line + 1);
|
||||||
|
Workspace.applyEdit(this.composeEdits(this.document.uri, edits));
|
||||||
|
}
|
||||||
|
composeEdits(uri, edits) {
|
||||||
|
var ws = new WorkspaceEdit();
|
||||||
|
ws.set(uri, edits);
|
||||||
|
return ws;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,80 +0,0 @@
|
||||||
import {
|
|
||||||
Range,
|
|
||||||
TextDocument,
|
|
||||||
WorkspaceEdit,
|
|
||||||
workspace as Workspace,
|
|
||||||
TextEditor,
|
|
||||||
commands as Commands,
|
|
||||||
Uri,
|
|
||||||
TextEdit,
|
|
||||||
Position
|
|
||||||
} from 'vscode'
|
|
||||||
|
|
||||||
import {
|
|
||||||
getLanguageService as GetHTMLanguageService,
|
|
||||||
Position as HTMLPosition
|
|
||||||
} from 'vscode-html-languageservice'
|
|
||||||
|
|
||||||
import {
|
|
||||||
CreateVirtualDocument,
|
|
||||||
TranslateHTMLTextEdits,
|
|
||||||
Match,
|
|
||||||
GetLanguageRegions,
|
|
||||||
IEmbeddedRegion
|
|
||||||
} from '../util'
|
|
||||||
|
|
||||||
export class CodeFormatterProvider {
|
|
||||||
private _expression = /(\/\*\s*html\s*\*\/\s*`|html\s*`)([^`]*)(`)/g
|
|
||||||
private document: TextDocument
|
|
||||||
|
|
||||||
constructor() {
|
|
||||||
Commands.registerTextEditorCommand(
|
|
||||||
'editor.action.formatInlineHtml',
|
|
||||||
this.format,
|
|
||||||
this
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
public format(textEditor: TextEditor) {
|
|
||||||
this.document = textEditor.document
|
|
||||||
|
|
||||||
var documentText = this.document.getText()
|
|
||||||
var match = Match(this._expression, documentText)
|
|
||||||
|
|
||||||
if (!match) {
|
|
||||||
return []
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO - Refactor, This have been used multiple times thourgh out the
|
|
||||||
// TODO - extension.
|
|
||||||
var matchStartOffset = match.index + match[1].length
|
|
||||||
var matchEndOffset = match.index + (match[2].length + match[3].length + 1)
|
|
||||||
var matchStartPosition = this.document.positionAt(matchStartOffset)
|
|
||||||
var matchEndPosition = this.document.positionAt(matchEndOffset)
|
|
||||||
|
|
||||||
var text = this.document.getText(
|
|
||||||
new Range(matchStartPosition, matchEndPosition)
|
|
||||||
)
|
|
||||||
var vHTML = CreateVirtualDocument('html', text)
|
|
||||||
|
|
||||||
// TODO - Expose Formatting Options
|
|
||||||
const edits = TranslateHTMLTextEdits(
|
|
||||||
GetHTMLanguageService().format(vHTML, null, {
|
|
||||||
indentInnerHtml: false,
|
|
||||||
preserveNewLines: true,
|
|
||||||
tabSize: <number>textEditor.options.tabSize,
|
|
||||||
insertSpaces: <boolean>textEditor.options.insertSpaces,
|
|
||||||
endWithNewline: true
|
|
||||||
}),
|
|
||||||
matchStartPosition.line + 1
|
|
||||||
)
|
|
||||||
|
|
||||||
Workspace.applyEdit(this.composeEdits(this.document.uri, edits))
|
|
||||||
}
|
|
||||||
|
|
||||||
private composeEdits(uri: Uri, edits: TextEdit[]): WorkspaceEdit {
|
|
||||||
var ws = new WorkspaceEdit()
|
|
||||||
ws.set(uri, edits)
|
|
||||||
return ws
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,49 @@
|
||||||
|
import { getLanguageService as GetHtmlLanguageService } from 'vscode-html-languageservice';
|
||||||
|
import { getCSSLanguageService as GetCssLanguageService } from 'vscode-css-languageservice';
|
||||||
|
import { CreateVirtualDocument, MatchOffset } from '../util';
|
||||||
|
export class HTMLHoverProvider {
|
||||||
|
_htmlLanguageService = GetHtmlLanguageService();
|
||||||
|
_cssLanguageService = GetCssLanguageService();
|
||||||
|
// private _expression = /(html\s*`)([^`]*)(`)/g
|
||||||
|
_expression = /(\/\*\s*html\s*\*\/\s*`|html\s*`)([^`]*)(`)/g;
|
||||||
|
provideHover(document, position, token) {
|
||||||
|
const currentOffset = document.offsetAt(position);
|
||||||
|
const documentText = document.getText();
|
||||||
|
const match = MatchOffset(this._expression, documentText, currentOffset);
|
||||||
|
if (!match) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
// tslint:disable-next-line:no-magic-numbers
|
||||||
|
const matchContent = match[2];
|
||||||
|
const matchStartOffset = match.index + match[1].length;
|
||||||
|
const virtualOffset = currentOffset - matchStartOffset;
|
||||||
|
const virtualDocument = CreateVirtualDocument('html', matchContent);
|
||||||
|
const html = this._htmlLanguageService.parseHTMLDocument(virtualDocument);
|
||||||
|
const stylesheet = this._cssLanguageService.parseStylesheet(virtualDocument);
|
||||||
|
const hover = this._htmlLanguageService.doHover(virtualDocument, virtualDocument.positionAt(virtualOffset), html) ||
|
||||||
|
this._cssLanguageService.doHover(virtualDocument, virtualDocument.positionAt(virtualOffset), stylesheet);
|
||||||
|
return hover;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
export class CSSHoverProvider {
|
||||||
|
_htmlLanguageService = GetHtmlLanguageService();
|
||||||
|
_cssLanguageService = GetCssLanguageService();
|
||||||
|
_expression = /(\/\*\s*(css|less|scss)\s*\*\/\s*`|css\s*`)([^`]*)(`)/g;
|
||||||
|
provideHover(document, position, token) {
|
||||||
|
const currentOffset = document.offsetAt(position);
|
||||||
|
const documentText = document.getText();
|
||||||
|
const match = MatchOffset(this._expression, documentText, currentOffset);
|
||||||
|
if (!match) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
const dialect = match[2];
|
||||||
|
// tslint:disable-next-line:no-magic-numbers
|
||||||
|
const matchContent = match[3];
|
||||||
|
const matchStartOffset = match.index + match[1].length;
|
||||||
|
const virtualOffset = currentOffset - matchStartOffset;
|
||||||
|
const virtualDocument = CreateVirtualDocument(dialect, matchContent);
|
||||||
|
const stylesheet = this._cssLanguageService.parseStylesheet(virtualDocument);
|
||||||
|
const hover = this._cssLanguageService.doHover(virtualDocument, virtualDocument.positionAt(virtualOffset), stylesheet);
|
||||||
|
return hover;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,98 +0,0 @@
|
||||||
import {
|
|
||||||
HoverProvider,
|
|
||||||
TextDocument,
|
|
||||||
Position,
|
|
||||||
CancellationToken,
|
|
||||||
Hover
|
|
||||||
} from 'vscode'
|
|
||||||
|
|
||||||
import {
|
|
||||||
getLanguageService as GetHtmlLanguageService,
|
|
||||||
LanguageService as HtmlLanguageService,
|
|
||||||
CompletionList as HtmlCompletionList
|
|
||||||
} from 'vscode-html-languageservice'
|
|
||||||
|
|
||||||
import {
|
|
||||||
getCSSLanguageService as GetCssLanguageService,
|
|
||||||
LanguageService as CssLanguageService
|
|
||||||
} from 'vscode-css-languageservice'
|
|
||||||
|
|
||||||
import { CreateVirtualDocument, MatchOffset } from '../util'
|
|
||||||
|
|
||||||
export class HTMLHoverProvider implements HoverProvider {
|
|
||||||
private _htmlLanguageService: HtmlLanguageService = GetHtmlLanguageService()
|
|
||||||
private _cssLanguageService: CssLanguageService = GetCssLanguageService()
|
|
||||||
// private _expression = /(html\s*`)([^`]*)(`)/g
|
|
||||||
private _expression = /(\/\*\s*html\s*\*\/\s*`|html\s*`)([^`]*)(`)/g
|
|
||||||
|
|
||||||
provideHover(
|
|
||||||
document: TextDocument,
|
|
||||||
position: Position,
|
|
||||||
token: CancellationToken
|
|
||||||
): Hover {
|
|
||||||
const currentOffset = document.offsetAt(position)
|
|
||||||
const documentText = document.getText()
|
|
||||||
const match = MatchOffset(this._expression, documentText, currentOffset)
|
|
||||||
|
|
||||||
if (!match) {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
// tslint:disable-next-line:no-magic-numbers
|
|
||||||
const matchContent: string = match[2]
|
|
||||||
const matchStartOffset = match.index + match[1].length
|
|
||||||
const virtualOffset = currentOffset - matchStartOffset
|
|
||||||
const virtualDocument = CreateVirtualDocument('html', matchContent)
|
|
||||||
const html = this._htmlLanguageService.parseHTMLDocument(virtualDocument)
|
|
||||||
const stylesheet = this._cssLanguageService.parseStylesheet(virtualDocument)
|
|
||||||
const hover =
|
|
||||||
this._htmlLanguageService.doHover(
|
|
||||||
virtualDocument,
|
|
||||||
virtualDocument.positionAt(virtualOffset),
|
|
||||||
html
|
|
||||||
) ||
|
|
||||||
this._cssLanguageService.doHover(
|
|
||||||
virtualDocument,
|
|
||||||
virtualDocument.positionAt(virtualOffset),
|
|
||||||
stylesheet
|
|
||||||
)
|
|
||||||
|
|
||||||
return hover as Hover
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class CSSHoverProvider implements HoverProvider {
|
|
||||||
private _htmlLanguageService: HtmlLanguageService = GetHtmlLanguageService()
|
|
||||||
private _cssLanguageService: CssLanguageService = GetCssLanguageService()
|
|
||||||
private _expression = /(\/\*\s*(css|less|scss)\s*\*\/\s*`|css\s*`)([^`]*)(`)/g
|
|
||||||
|
|
||||||
provideHover(
|
|
||||||
document: TextDocument,
|
|
||||||
position: Position,
|
|
||||||
token: CancellationToken
|
|
||||||
): Hover {
|
|
||||||
const currentOffset = document.offsetAt(position)
|
|
||||||
const documentText = document.getText()
|
|
||||||
const match = MatchOffset(this._expression, documentText, currentOffset)
|
|
||||||
|
|
||||||
if (!match) {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
const dialect = match[2]
|
|
||||||
|
|
||||||
// tslint:disable-next-line:no-magic-numbers
|
|
||||||
const matchContent: string = match[3]
|
|
||||||
const matchStartOffset = match.index + match[1].length
|
|
||||||
const virtualOffset = currentOffset - matchStartOffset
|
|
||||||
const virtualDocument = CreateVirtualDocument(dialect, matchContent)
|
|
||||||
const stylesheet = this._cssLanguageService.parseStylesheet(virtualDocument)
|
|
||||||
const hover = this._cssLanguageService.doHover(
|
|
||||||
virtualDocument,
|
|
||||||
virtualDocument.positionAt(virtualOffset),
|
|
||||||
stylesheet
|
|
||||||
)
|
|
||||||
|
|
||||||
return hover as Hover
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,59 @@
|
||||||
|
import { getLanguageService as GetHTMLanguageService } from 'vscode-html-languageservice';
|
||||||
|
import * as emmet from 'vscode-emmet-helper';
|
||||||
|
import { GetEmmetConfiguration, MatchOffset, CreateVirtualDocument, TranslateCompletionItems } from '../util';
|
||||||
|
import { CompletionsCache } from '../cache';
|
||||||
|
export class HTMLCompletionItemProvider {
|
||||||
|
_htmlLanguageService = GetHTMLanguageService();
|
||||||
|
_expression = /(\/\*\s*html\s*\*\/\s*`|html\s*`)([^`]*)(`)/g;
|
||||||
|
// private _expression = /(html\s*`)([^`]*)(`)/g
|
||||||
|
_cache = new CompletionsCache();
|
||||||
|
provideCompletionItems(document, position, token) {
|
||||||
|
const cached = this._cache.getCached(document, position);
|
||||||
|
if (cached) {
|
||||||
|
return cached;
|
||||||
|
}
|
||||||
|
const currentLine = document.lineAt(position.line);
|
||||||
|
const empty = {
|
||||||
|
isIncomplete: false,
|
||||||
|
items: []
|
||||||
|
};
|
||||||
|
if (currentLine.isEmptyOrWhitespace) {
|
||||||
|
return empty;
|
||||||
|
}
|
||||||
|
const currentLineText = currentLine.text.trim();
|
||||||
|
const currentOffset = document.offsetAt(position);
|
||||||
|
const documentText = document.getText();
|
||||||
|
const match = MatchOffset(this._expression, documentText, currentOffset);
|
||||||
|
if (!match) {
|
||||||
|
return empty;
|
||||||
|
}
|
||||||
|
// tslint:disable-next-line:no-magic-numbers
|
||||||
|
const matchContent = match[2];
|
||||||
|
const matchStartOffset = match.index + match[1].length;
|
||||||
|
const matchEndOffset = match.index + match[0].length;
|
||||||
|
const matchPosition = document.positionAt(matchStartOffset);
|
||||||
|
const virtualOffset = currentOffset - matchStartOffset;
|
||||||
|
const virtualDocument = CreateVirtualDocument('html', matchContent);
|
||||||
|
const vHtml = this._htmlLanguageService.parseHTMLDocument(virtualDocument);
|
||||||
|
const emmetResults = {
|
||||||
|
isIncomplete: true,
|
||||||
|
items: []
|
||||||
|
};
|
||||||
|
this._htmlLanguageService.setCompletionParticipants([
|
||||||
|
emmet.getEmmetCompletionParticipants(virtualDocument, virtualDocument.positionAt(virtualOffset), 'html', GetEmmetConfiguration(), emmetResults)
|
||||||
|
]);
|
||||||
|
const completions = this._htmlLanguageService.doComplete(virtualDocument, virtualDocument.positionAt(virtualOffset), vHtml);
|
||||||
|
if (emmetResults.items.length) {
|
||||||
|
completions.items.push(...emmetResults.items);
|
||||||
|
completions.isIncomplete = true;
|
||||||
|
}
|
||||||
|
this._cache.updateCached(document, position, completions);
|
||||||
|
return {
|
||||||
|
isIncomplete: completions.isIncomplete,
|
||||||
|
items: TranslateCompletionItems(completions.items, currentLine, true)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
resolveCompletionItem(item, token) {
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,111 +0,0 @@
|
||||||
import {
|
|
||||||
CompletionList,
|
|
||||||
CompletionItem,
|
|
||||||
TextDocument,
|
|
||||||
Position,
|
|
||||||
CancellationToken,
|
|
||||||
CompletionItemProvider
|
|
||||||
} from 'vscode'
|
|
||||||
|
|
||||||
import {
|
|
||||||
getLanguageService as GetHTMLanguageService,
|
|
||||||
LanguageService as HTMLanguageService,
|
|
||||||
CompletionList as HTMLCompletionList
|
|
||||||
} from 'vscode-html-languageservice'
|
|
||||||
|
|
||||||
import * as emmet from 'vscode-emmet-helper'
|
|
||||||
|
|
||||||
import {
|
|
||||||
GetEmmetConfiguration,
|
|
||||||
MatchOffset,
|
|
||||||
CreateVirtualDocument,
|
|
||||||
TranslateCompletionItems
|
|
||||||
} from '../util'
|
|
||||||
|
|
||||||
import { CompletionsCache } from '../cache'
|
|
||||||
|
|
||||||
export class HTMLCompletionItemProvider implements CompletionItemProvider {
|
|
||||||
private _htmlLanguageService: HTMLanguageService = GetHTMLanguageService()
|
|
||||||
private _expression = /(\/\*\s*html\s*\*\/\s*`|html\s*`)([^`]*)(`)/g
|
|
||||||
// private _expression = /(html\s*`)([^`]*)(`)/g
|
|
||||||
private _cache = new CompletionsCache()
|
|
||||||
|
|
||||||
public provideCompletionItems(
|
|
||||||
document: TextDocument,
|
|
||||||
position: Position,
|
|
||||||
token: CancellationToken
|
|
||||||
): CompletionList {
|
|
||||||
const cached = this._cache.getCached(document, position)
|
|
||||||
|
|
||||||
if (cached) {
|
|
||||||
return cached
|
|
||||||
}
|
|
||||||
|
|
||||||
const currentLine = document.lineAt(position.line)
|
|
||||||
const empty = {
|
|
||||||
isIncomplete: false,
|
|
||||||
items: []
|
|
||||||
} as CompletionList
|
|
||||||
|
|
||||||
if (currentLine.isEmptyOrWhitespace) {
|
|
||||||
return empty
|
|
||||||
}
|
|
||||||
|
|
||||||
const currentLineText = currentLine.text.trim()
|
|
||||||
const currentOffset = document.offsetAt(position)
|
|
||||||
const documentText = document.getText()
|
|
||||||
const match = MatchOffset(this._expression, documentText, currentOffset)
|
|
||||||
|
|
||||||
if (!match) {
|
|
||||||
return empty
|
|
||||||
}
|
|
||||||
|
|
||||||
// tslint:disable-next-line:no-magic-numbers
|
|
||||||
const matchContent: string = match[2]
|
|
||||||
const matchStartOffset = match.index + match[1].length
|
|
||||||
const matchEndOffset = match.index + match[0].length
|
|
||||||
const matchPosition = document.positionAt(matchStartOffset)
|
|
||||||
const virtualOffset = currentOffset - matchStartOffset
|
|
||||||
const virtualDocument = CreateVirtualDocument('html', matchContent)
|
|
||||||
const vHtml = this._htmlLanguageService.parseHTMLDocument(virtualDocument)
|
|
||||||
const emmetResults: HTMLCompletionList = {
|
|
||||||
isIncomplete: true,
|
|
||||||
items: []
|
|
||||||
}
|
|
||||||
|
|
||||||
this._htmlLanguageService.setCompletionParticipants([
|
|
||||||
emmet.getEmmetCompletionParticipants(
|
|
||||||
virtualDocument,
|
|
||||||
virtualDocument.positionAt(virtualOffset),
|
|
||||||
'html',
|
|
||||||
GetEmmetConfiguration(),
|
|
||||||
emmetResults
|
|
||||||
)
|
|
||||||
])
|
|
||||||
|
|
||||||
const completions = this._htmlLanguageService.doComplete(
|
|
||||||
virtualDocument,
|
|
||||||
virtualDocument.positionAt(virtualOffset),
|
|
||||||
vHtml
|
|
||||||
)
|
|
||||||
|
|
||||||
if (emmetResults.items.length) {
|
|
||||||
completions.items.push(...emmetResults.items)
|
|
||||||
completions.isIncomplete = true
|
|
||||||
}
|
|
||||||
|
|
||||||
this._cache.updateCached(document, position, completions)
|
|
||||||
|
|
||||||
return {
|
|
||||||
isIncomplete: completions.isIncomplete,
|
|
||||||
items: TranslateCompletionItems(completions.items, currentLine, true)
|
|
||||||
} as CompletionList
|
|
||||||
}
|
|
||||||
|
|
||||||
public resolveCompletionItem?(
|
|
||||||
item: CompletionItem,
|
|
||||||
token: CancellationToken
|
|
||||||
): CompletionItem | Thenable<CompletionItem> {
|
|
||||||
return item
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,104 @@
|
||||||
|
import { workspace, TextEdit, Position, Range } from 'vscode';
|
||||||
|
import { TextDocument as HTMLTextDocument, TokenType as HTMLTokenType } from 'vscode-html-languageservice';
|
||||||
|
export function GetEmmetConfiguration() {
|
||||||
|
const emmetConfig = workspace.getConfiguration('emmet');
|
||||||
|
return {
|
||||||
|
useNewEmmet: true,
|
||||||
|
showExpandedAbbreviation: emmetConfig.showExpandedAbbreviation,
|
||||||
|
showAbbreviationSuggestions: emmetConfig.showAbbreviationSuggestions,
|
||||||
|
syntaxProfiles: emmetConfig.syntaxProfiles,
|
||||||
|
variables: emmetConfig.variables
|
||||||
|
};
|
||||||
|
}
|
||||||
|
export function NotNull(input) {
|
||||||
|
if (!input) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
return input;
|
||||||
|
}
|
||||||
|
export function MatchOffset(regex, data, offset) {
|
||||||
|
regex.exec(null);
|
||||||
|
let match;
|
||||||
|
while ((match = regex.exec(data)) !== null) {
|
||||||
|
if (offset > match.index + match[1].length &&
|
||||||
|
offset < match.index + match[0].length) {
|
||||||
|
return match;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
export function Match(regex, data) {
|
||||||
|
regex.exec(null);
|
||||||
|
let match;
|
||||||
|
while ((match = regex.exec(data)) !== null) {
|
||||||
|
return match;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
export function GetLanguageRegions(service, data) {
|
||||||
|
const scanner = service.createScanner(data);
|
||||||
|
const regions = [];
|
||||||
|
let tokenType;
|
||||||
|
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, offset) {
|
||||||
|
for (let region of regions) {
|
||||||
|
if (region.start <= offset) {
|
||||||
|
if (offset <= region.end) {
|
||||||
|
return region;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
export function TranslateHTMLTextEdits(input, offset) {
|
||||||
|
return input.map((item) => {
|
||||||
|
const startPosition = new Position(item.range.start.line + offset, item.range.start.character);
|
||||||
|
const endPosition = new Position(item.range.end.line + offset - 1, item.range.end.character);
|
||||||
|
const itemRange = new Range(startPosition, endPosition);
|
||||||
|
return new TextEdit(itemRange, item.newText);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
export function TranslateCompletionItems(items, line, expand = false) {
|
||||||
|
return items.map((item) => {
|
||||||
|
const result = item;
|
||||||
|
const range = new Range(new Position(line.lineNumber, result.textEdit.range.start.character), new Position(line.lineNumber, result.textEdit.range.end.character));
|
||||||
|
result.textEdit = null;
|
||||||
|
// @ts-ignore - setting range for intellisense to show results properly
|
||||||
|
result.range = range;
|
||||||
|
if (expand) {
|
||||||
|
// i use this to both expand html abbreviations and auto complete tags
|
||||||
|
result.command = {
|
||||||
|
title: 'Emmet Expand Abbreviation',
|
||||||
|
command: 'editor.emmet.action.expandAbbreviation'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
export function CreateVirtualDocument(
|
||||||
|
// context: TextDocument | HTMLTextDocument,
|
||||||
|
languageId,
|
||||||
|
// position: Position | HtmlPosition,
|
||||||
|
content) {
|
||||||
|
const doc = HTMLTextDocument.create(`embedded://document.${languageId}`, languageId, 1, content);
|
||||||
|
return doc;
|
||||||
|
}
|
179
src/util.ts
179
src/util.ts
|
@ -1,179 +0,0 @@
|
||||||
import {
|
|
||||||
workspace,
|
|
||||||
TextLine,
|
|
||||||
TextEdit,
|
|
||||||
Position,
|
|
||||||
Range,
|
|
||||||
CompletionItem,
|
|
||||||
Command
|
|
||||||
} from 'vscode'
|
|
||||||
|
|
||||||
import {
|
|
||||||
TextDocument as HTMLTextDocument,
|
|
||||||
LanguageService,
|
|
||||||
TokenType as HTMLTokenType,
|
|
||||||
TextEdit as HTMLTextEdit
|
|
||||||
} from 'vscode-html-languageservice'
|
|
||||||
|
|
||||||
import { EmmetConfiguration } from 'vscode-emmet-helper'
|
|
||||||
|
|
||||||
export function GetEmmetConfiguration(): EmmetConfiguration {
|
|
||||||
const emmetConfig = workspace.getConfiguration('emmet')
|
|
||||||
return {
|
|
||||||
useNewEmmet: true,
|
|
||||||
showExpandedAbbreviation: emmetConfig.showExpandedAbbreviation,
|
|
||||||
showAbbreviationSuggestions: emmetConfig.showAbbreviationSuggestions,
|
|
||||||
syntaxProfiles: emmetConfig.syntaxProfiles,
|
|
||||||
variables: emmetConfig.variables
|
|
||||||
} as EmmetConfiguration
|
|
||||||
}
|
|
||||||
|
|
||||||
export function NotNull<T>(input: any): T {
|
|
||||||
if (!input) {
|
|
||||||
return {} as T
|
|
||||||
}
|
|
||||||
return input as T
|
|
||||||
}
|
|
||||||
|
|
||||||
export function MatchOffset(
|
|
||||||
regex: RegExp,
|
|
||||||
data: string,
|
|
||||||
offset: number
|
|
||||||
): RegExpMatchArray {
|
|
||||||
regex.exec(null)
|
|
||||||
|
|
||||||
let match: RegExpExecArray
|
|
||||||
while ((match = regex.exec(data)) !== null) {
|
|
||||||
if (
|
|
||||||
offset > match.index + match[1].length &&
|
|
||||||
offset < match.index + match[0].length
|
|
||||||
) {
|
|
||||||
return match
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
export function Match(regex: RegExp, data: string): RegExpMatchArray {
|
|
||||||
regex.exec(null)
|
|
||||||
|
|
||||||
let match: RegExpExecArray
|
|
||||||
while ((match = regex.exec(data)) !== null) {
|
|
||||||
return match
|
|
||||||
}
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
export function GetLanguageRegions(
|
|
||||||
service: LanguageService,
|
|
||||||
data: string
|
|
||||||
): IEmbeddedRegion[] {
|
|
||||||
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
|
|
||||||
): IEmbeddedRegion {
|
|
||||||
for (let region of regions) {
|
|
||||||
if (region.start <= offset) {
|
|
||||||
if (offset <= region.end) {
|
|
||||||
return region
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
export function TranslateHTMLTextEdits(
|
|
||||||
input: HTMLTextEdit[],
|
|
||||||
offset: number
|
|
||||||
): TextEdit[] {
|
|
||||||
return input.map((item: HTMLTextEdit) => {
|
|
||||||
const startPosition = new Position(
|
|
||||||
item.range.start.line + offset,
|
|
||||||
item.range.start.character
|
|
||||||
)
|
|
||||||
const endPosition = new Position(
|
|
||||||
item.range.end.line + offset - 1,
|
|
||||||
item.range.end.character
|
|
||||||
)
|
|
||||||
const itemRange = new Range(startPosition, endPosition)
|
|
||||||
return new TextEdit(itemRange, item.newText)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
export function TranslateCompletionItems(
|
|
||||||
items,
|
|
||||||
line: TextLine,
|
|
||||||
expand: boolean = false
|
|
||||||
): CompletionItem[] {
|
|
||||||
return items.map((item: CompletionItem) => {
|
|
||||||
const result = item as CompletionItem
|
|
||||||
const range = new Range(
|
|
||||||
new Position(line.lineNumber, result.textEdit.range.start.character),
|
|
||||||
new Position(line.lineNumber, result.textEdit.range.end.character)
|
|
||||||
)
|
|
||||||
|
|
||||||
result.textEdit = null
|
|
||||||
|
|
||||||
// @ts-ignore - setting range for intellisense to show results properly
|
|
||||||
result.range = range
|
|
||||||
|
|
||||||
if (expand) {
|
|
||||||
// i use this to both expand html abbreviations and auto complete tags
|
|
||||||
result.command = {
|
|
||||||
title: 'Emmet Expand Abbreviation',
|
|
||||||
command: 'editor.emmet.action.expandAbbreviation'
|
|
||||||
} as Command
|
|
||||||
}
|
|
||||||
|
|
||||||
return result
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
export function CreateVirtualDocument(
|
|
||||||
// context: TextDocument | HTMLTextDocument,
|
|
||||||
languageId: string,
|
|
||||||
// position: Position | HtmlPosition,
|
|
||||||
content: string
|
|
||||||
): HTMLTextDocument {
|
|
||||||
const doc = HTMLTextDocument.create(
|
|
||||||
`embedded://document.${languageId}`,
|
|
||||||
languageId,
|
|
||||||
1,
|
|
||||||
content
|
|
||||||
)
|
|
||||||
|
|
||||||
return doc
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IEmbeddedRegion {
|
|
||||||
languageId: string
|
|
||||||
start: number
|
|
||||||
end: number
|
|
||||||
length: number
|
|
||||||
content: string
|
|
||||||
}
|
|
Loading…
Reference in New Issue