Better readability for util.ts

This commit is contained in:
Ramya Achutha Rao 2018-11-18 19:42:02 -08:00
parent 610918d48f
commit dcc243c992
2 changed files with 98 additions and 78 deletions

View file

@ -17,7 +17,7 @@ import { fetchEditPoint } from './editPoint';
import { fetchSelectItem } from './selectItem';
import { evaluateMathExpression } from './evaluateMathExpression';
import { incrementDecrement } from './incrementDecrement';
import { LANGUAGE_MODES, getMappingForIncludedLanguages, resolveUpdateExtensionsPath } from './util';
import { LANGUAGE_MODES, getMappingForIncludedLanguages, updateEmmetExtensionsPath } from './util';
import { updateImageSize } from './updateImageSize';
import { reflectCssValue } from './reflectCssValue';
@ -129,11 +129,15 @@ export function activate(context: vscode.ExtensionContext) {
return reflectCssValue();
}));
resolveUpdateExtensionsPath();
updateEmmetExtensionsPath();
context.subscriptions.push(vscode.workspace.onDidChangeConfiguration(() => {
registerCompletionProviders(context);
resolveUpdateExtensionsPath();
context.subscriptions.push(vscode.workspace.onDidChangeConfiguration((e) => {
if (e.affectsConfiguration('emmet.includeLanguages')) {
registerCompletionProviders(context);
}
if (e.affectsConfiguration('emmet.extensionsPath')) {
updateEmmetExtensionsPath();
}
}));
}

View file

@ -13,14 +13,19 @@ let _emmetHelper: any;
let _currentExtensionsPath: string | undefined = undefined;
export function getEmmetHelper() {
// Lazy load vscode-emmet-helper instead of importing it
// directly to reduce the start-up time of the extension
if (!_emmetHelper) {
_emmetHelper = require('vscode-emmet-helper');
}
resolveUpdateExtensionsPath();
updateEmmetExtensionsPath();
return _emmetHelper;
}
export function resolveUpdateExtensionsPath() {
/**
* Update Emmet Helper to use user snippets from the extensionsPath setting
*/
export function updateEmmetExtensionsPath() {
if (!_emmetHelper) {
return;
}
@ -31,7 +36,10 @@ export function resolveUpdateExtensionsPath() {
}
}
export const LANGUAGE_MODES: any = {
/**
* Mapping between languages that support Emmet and completion trigger characters
*/
export const LANGUAGE_MODES: { [id: string]: string[] } = {
'html': ['!', '.', '}', ':', '*', '$', ']', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'],
'jade': ['!', '.', '}', ':', '*', '$', ']', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'],
'slim': ['!', '.', '}', ':', '*', '$', ']', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'],
@ -47,19 +55,6 @@ export const LANGUAGE_MODES: any = {
'typescriptreact': ['!', '.', '}', '*', '$', ']', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9']
};
export const allowedMimeTypesInScriptTag = ['text/html', 'text/plain', 'text/x-template', 'text/template', 'text/ng-template'];
const emmetModes = ['html', 'pug', 'slim', 'haml', 'xml', 'xsl', 'jsx', 'css', 'scss', 'sass', 'less', 'stylus'];
// Explicitly map languages that have built-in grammar in VS Code to their parent language
// to get emmet completion support
// For other languages, users will have to use `emmet.includeLanguages` or
// language specific extensions can provide emmet completion support
export const MAPPED_MODES: Object = {
'handlebars': 'html',
'php': 'html'
};
export function isStyleSheet(syntax: string): boolean {
let stylesheetSyntaxes = ['css', 'scss', 'sass', 'less', 'stylus'];
return (stylesheetSyntaxes.indexOf(syntax) > -1);
@ -78,6 +73,15 @@ export function validate(allowStylesheet: boolean = true): boolean {
}
export function getMappingForIncludedLanguages(): any {
// Explicitly map languages that have built-in grammar in VS Code to their parent language
// to get emmet completion support
// For other languages, users will have to use `emmet.includeLanguages` or
// language specific extensions can provide emmet completion support
const MAPPED_MODES: Object = {
'handlebars': 'html',
'php': 'html'
};
const finalMappedModes = Object.create(null);
let includeLanguagesConfig = vscode.workspace.getConfiguration('emmet')['includeLanguages'];
let includeLanguages = Object.assign({}, MAPPED_MODES, includeLanguagesConfig ? includeLanguagesConfig : {});
@ -111,6 +115,7 @@ export function getEmmetMode(language: string, excludedLanguages: string[]): str
if (language === 'jade') {
return 'pug';
}
const emmetModes = ['html', 'pug', 'slim', 'haml', 'xml', 'xsl', 'jsx', 'css', 'scss', 'sass', 'less', 'stylus'];
if (emmetModes.indexOf(language) > -1) {
return language;
}
@ -137,6 +142,12 @@ const openBrace = 123;
const slash = 47;
const star = 42;
/**
* Traverse the given document backward & forward from given position
* to find a complete ruleset, then parse just that to return a Stylesheet
* @param document vscode.TextDocument
* @param position vscode.Position
*/
export function parsePartialStylesheet(document: vscode.TextDocument, position: vscode.Position): Stylesheet | undefined {
const isCSS = document.languageId === 'css';
let startPosition = new vscode.Position(0, 0);
@ -145,6 +156,25 @@ export function parsePartialStylesheet(document: vscode.TextDocument, position:
const limitPosition = limitCharacter > 0 ? document.positionAt(limitCharacter) : startPosition;
const stream = new DocumentStreamReader(document, position);
function findOpeningCommentBeforePosition(pos: vscode.Position): vscode.Position | undefined {
let text = document.getText(new vscode.Range(0, 0, pos.line, pos.character));
let offset = text.lastIndexOf('/*');
if (offset === -1) {
return;
}
return document.positionAt(offset);
}
function findClosingCommentAfterPosition(pos: vscode.Position): vscode.Position | undefined {
let text = document.getText(new vscode.Range(pos.line, pos.character, document.lineCount - 1, document.lineAt(document.lineCount - 1).text.length));
let offset = text.indexOf('*/');
if (offset === -1) {
return;
}
offset += 2 + document.offsetAt(pos);
return document.positionAt(offset);
}
function consumeLineCommentBackwards() {
if (!isCSS && currentLine !== stream.pos.line) {
currentLine = stream.pos.line;
@ -158,7 +188,7 @@ export function parsePartialStylesheet(document: vscode.TextDocument, position:
function consumeBlockCommentBackwards() {
if (stream.peek() === slash) {
if (stream.backUp(1) === star) {
stream.pos = findOpeningCommentBeforePosition(document, stream.pos) || startPosition;
stream.pos = findOpeningCommentBeforePosition(stream.pos) || startPosition;
} else {
stream.next();
}
@ -170,7 +200,7 @@ export function parsePartialStylesheet(document: vscode.TextDocument, position:
if (stream.eat(slash) && !isCSS) {
stream.pos = new vscode.Position(stream.pos.line + 1, 0);
} else if (stream.eat(star)) {
stream.pos = findClosingCommentAfterPosition(document, stream.pos) || endPosition;
stream.pos = findClosingCommentAfterPosition(stream.pos) || endPosition;
}
}
}
@ -264,25 +294,6 @@ export function parsePartialStylesheet(document: vscode.TextDocument, position:
}
}
function findOpeningCommentBeforePosition(document: vscode.TextDocument, position: vscode.Position): vscode.Position | undefined {
let text = document.getText(new vscode.Range(0, 0, position.line, position.character));
let offset = text.lastIndexOf('/*');
if (offset === -1) {
return;
}
return document.positionAt(offset);
}
function findClosingCommentAfterPosition(document: vscode.TextDocument, position: vscode.Position): vscode.Position | undefined {
let text = document.getText(new vscode.Range(position.line, position.character, document.lineCount - 1, document.lineAt(document.lineCount - 1).text.length));
let offset = text.indexOf('*/');
if (offset === -1) {
return;
}
offset += 2 + document.offsetAt(position);
return document.positionAt(offset);
}
/**
* Returns node corresponding to given position in the given root node
*/
@ -311,11 +322,22 @@ export function getNode(root: Node | undefined, position: vscode.Position, inclu
return foundNode;
}
export const allowedMimeTypesInScriptTag = ['text/html', 'text/plain', 'text/x-template', 'text/template', 'text/ng-template'];
/**
* Returns HTML node corresponding to given position in the given root node
* If position is inside a script tag of type template, then it will be parsed to find the inner HTML node as well
*/
export function getHtmlNode(document: vscode.TextDocument, root: Node | undefined, position: vscode.Position, includeNodeBoundary: boolean): HtmlNode | undefined {
let currentNode = <HtmlNode>getNode(root, position, includeNodeBoundary);
if (!currentNode) { return; }
if (isTemplateScript(currentNode) && currentNode.close &&
const isTemplateScript = currentNode.name === 'script' &&
(currentNode.attributes &&
currentNode.attributes.some(x => x.name.toString() === 'type'
&& allowedMimeTypesInScriptTag.indexOf(x.value.toString()) > -1));
if (isTemplateScript && currentNode.close &&
(position.isAfter(currentNode.open.end) && position.isBefore(currentNode.close.start))) {
let buffer = new DocumentStreamReader(document, currentNode.open.end, new vscode.Range(currentNode.open.end, currentNode.close.start));
@ -340,6 +362,10 @@ export function getInnerRange(currentNode: HtmlNode): vscode.Range | undefined {
return new vscode.Range(currentNode.open.end, currentNode.close.start);
}
/**
* Returns the deepest non comment node under given node
* @param node
*/
export function getDeepestNode(node: Node | undefined): Node | undefined {
if (!node || !node.children || node.children.length === 0 || !node.children.find(x => x.type !== 'comment')) {
return node;
@ -434,37 +460,32 @@ export function getNodesInBetween(node1: Node, node2: Node): Node[] {
return [node1];
}
// Same parent
if (sameNodes(node1.parent, node2.parent)) {
return getNextSiblingsTillPosition(node1, node2.end);
// Not siblings
if (!sameNodes(node1.parent, node2.parent)) {
// node2 is ancestor of node1
if (node2.start.isBefore(node1.start)) {
return [node2];
}
// node1 is ancestor of node2
if (node2.start.isBefore(node1.end)) {
return [node1];
}
// Get the highest ancestor of node1 that should be commented
while (node1.parent && node1.parent.end.isBefore(node2.start)) {
node1 = node1.parent;
}
// Get the highest ancestor of node2 that should be commented
while (node2.parent && node2.parent.start.isAfter(node1.start)) {
node2 = node2.parent;
}
}
// node2 is ancestor of node1
if (node2.start.isBefore(node1.start)) {
return [node2];
}
// node1 is ancestor of node2
if (node2.start.isBefore(node1.end)) {
return [node1];
}
// Get the highest ancestor of node1 that should be commented
while (node1.parent && node1.parent.end.isBefore(node2.start)) {
node1 = node1.parent;
}
// Get the highest ancestor of node2 that should be commented
while (node2.parent && node2.parent.start.isAfter(node1.start)) {
node2 = node2.parent;
}
return getNextSiblingsTillPosition(node1, node2.end);
}
function getNextSiblingsTillPosition(node: Node, position: vscode.Position): Node[] {
let siblings: Node[] = [];
let currentNode = node;
const siblings: Node[] = [];
let currentNode = node1;
const position = node2.end;
while (currentNode && position.isAfter(currentNode.start)) {
siblings.push(currentNode);
currentNode = currentNode.nextSibling;
@ -589,9 +610,4 @@ export function isStyleAttribute(currentNode: Node | null, position: vscode.Posi
return position.isAfterOrEqual(styleAttribute.value.start) && position.isBeforeOrEqual(styleAttribute.value.end);
}
export function isTemplateScript(currentNode: HtmlNode): boolean {
return currentNode.name === 'script' &&
(currentNode.attributes &&
currentNode.attributes.some(x => x.name.toString() === 'type'
&& allowedMimeTypesInScriptTag.indexOf(x.value.toString()) > -1));
}