提交 0ee00cbd 编写于 作者: R Ramya Achutha Rao

Emmet Error handling Fixes #29897

上级 e7de8b25
......@@ -118,9 +118,9 @@
"resolved": "https://registry.npmjs.org/@emmetio/variable-resolver/-/variable-resolver-0.2.1.tgz"
},
"vscode-emmet-helper": {
"version": "0.0.16",
"from": "vscode-emmet-helper@0.0.16",
"resolved": "https://registry.npmjs.org/vscode-emmet-helper/-/vscode-emmet-helper-0.0.16.tgz"
"version": "0.0.17",
"from": "vscode-emmet-helper@0.0.17",
"resolved": "https://registry.npmjs.org/vscode-emmet-helper/-/vscode-emmet-helper-0.0.17.tgz"
}
}
}
......@@ -73,6 +73,6 @@
"@emmetio/html-matcher": "^0.3.1",
"@emmetio/css-parser": "^0.3.0",
"@emmetio/math-expression": "^0.1.1",
"vscode-emmet-helper":"0.0.16"
"vscode-emmet-helper":"0.0.17"
}
}
\ No newline at end of file
......@@ -5,12 +5,9 @@
import * as vscode from 'vscode';
import { expand } from '@emmetio/expand-abbreviation';
import parseStylesheet from '@emmetio/css-parser';
import parse from '@emmetio/html-matcher';
import { Node, HtmlNode, Rule } from 'EmmetNode';
import { getNode, getInnerRange, getMappingForIncludedLanguages } from './util';
import { getNode, getInnerRange, getMappingForIncludedLanguages, parse, validate } from './util';
import { getExpandOptions, extractAbbreviation, isStyleSheet, isAbbreviationValid, getEmmetMode } from 'vscode-emmet-helper';
import { DocumentStreamReader } from './bufferStream';
interface ExpandAbbreviationInput {
syntax: string;
......@@ -22,7 +19,7 @@ interface ExpandAbbreviationInput {
export function wrapWithAbbreviation(args) {
const syntax = getSyntaxFromArgs(args);
if (!syntax) {
if (!syntax || !validate()) {
return;
}
......@@ -79,14 +76,16 @@ export function wrapWithAbbreviation(args) {
export function expandAbbreviation(args) {
const syntax = getSyntaxFromArgs(args);
if (!syntax) {
if (!syntax || !validate()) {
return;
}
const editor = vscode.window.activeTextEditor;
let parseContent = isStyleSheet(syntax) ? parseStylesheet : parse;
let rootNode: Node = parseContent(new DocumentStreamReader(editor.document));
let rootNode = parse(editor.document);
if (!rootNode) {
return;
}
let abbreviationList: ExpandAbbreviationInput[] = [];
let firstAbbreviation: string;
......@@ -100,6 +99,7 @@ export function expandAbbreviation(args) {
[rangeToReplace, abbreviation] = extractAbbreviation(editor.document, position);
}
if (!isAbbreviationValid(syntax, abbreviation)) {
vscode.window.showErrorMessage('Emmet: Invalid abbreviation');
return;
}
......@@ -193,7 +193,13 @@ function expandAbbreviationInRange(editor: vscode.TextEditor, expandAbbrList: Ex
*/
function expandAbbr(input: ExpandAbbreviationInput, newLine: string): string {
// Expand the abbreviation
let expandedText = expand(input.abbreviation, getExpandOptions(input.syntax, input.textToWrap));
let expandedText;
try {
expandedText = expand(input.abbreviation, getExpandOptions(input.syntax, input.textToWrap));
} catch (e) {
vscode.window.showErrorMessage('Failed to expand abbreviation');
}
if (!expandedText) {
return;
}
......
......@@ -4,11 +4,8 @@
*--------------------------------------------------------------------------------------------*/
import * as vscode from 'vscode';
import parse from '@emmetio/html-matcher';
import { HtmlNode } from 'EmmetNode';
import { DocumentStreamReader } from './bufferStream';
import { isStyleSheet } from 'vscode-emmet-helper';
import { getNode } from './util';
import { getNode, parse, validate } from './util';
export function balanceOut() {
balance(true);
......@@ -20,20 +17,16 @@ export function balanceIn() {
function balance(out: boolean) {
let editor = vscode.window.activeTextEditor;
if (!editor) {
vscode.window.showInformationMessage('No editor is active');
if (!validate(false)) {
return;
}
if (isStyleSheet(editor.document.languageId)) {
return;
}
let getRangeFunction = out ? getRangeToBalanceOut : getRangeToBalanceIn;
let rootNode: HtmlNode = parse(new DocumentStreamReader(editor.document));
let rootNode = <HtmlNode>parse(editor.document);
if (!rootNode) {
return;
}
let getRangeFunction = out ? getRangeToBalanceOut : getRangeToBalanceIn;
let newSelections: vscode.Selection[] = [];
editor.selections.forEach(selection => {
let range = getRangeFunction(editor.document, selection, rootNode);
......
......@@ -4,13 +4,10 @@
*--------------------------------------------------------------------------------------------*/
import * as vscode from 'vscode';
import parseStylesheet from '@emmetio/css-parser';
import parse from '@emmetio/html-matcher';
import { Node, HtmlNode } from 'EmmetNode';
import { DocumentStreamReader } from './bufferStream';
import { HtmlNode } from 'EmmetNode';
import { EmmetCompletionItemProvider, isStyleSheet, getEmmetMode } from 'vscode-emmet-helper';
import { isValidLocationForEmmetAbbreviation } from './abbreviationActions';
import { getNode, getInnerRange, getMappingForIncludedLanguages } from './util';
import { getNode, getInnerRange, getMappingForIncludedLanguages, parse } from './util';
export class DefaultCompletionItemProvider implements vscode.CompletionItemProvider {
......@@ -46,8 +43,11 @@ export class DefaultCompletionItemProvider implements vscode.CompletionItemProvi
if (!syntax) {
return syntax;
}
let parseContent = isStyleSheet(syntax) ? parseStylesheet : parse;
let rootNode: Node = parseContent(new DocumentStreamReader(document));
let rootNode = parse(document, false);
if (!rootNode) {
return;
}
let currentNode = getNode(rootNode, position);
if (!isStyleSheet(syntax)) {
......
......@@ -4,22 +4,20 @@
*--------------------------------------------------------------------------------------------*/
import * as vscode from 'vscode';
import parse from '@emmetio/html-matcher';
import { HtmlNode } from 'EmmetNode';
import { DocumentStreamReader } from './bufferStream';
import { getNode } from './util';
import { getNode, parse, validate } from './util';
export function matchTag() {
let editor = vscode.window.activeTextEditor;
if (!editor) {
vscode.window.showInformationMessage('No editor is active');
if (!validate(false)) {
return;
}
let rootNode: HtmlNode = parse(new DocumentStreamReader(editor.document));
let rootNode = <HtmlNode>parse(editor.document);
if (!rootNode) {
return;
}
let updatedSelections = [];
editor.selections.forEach(selection => {
let updatedSelection = getUpdatedSelections(editor, selection.start, rootNode);
......@@ -35,6 +33,9 @@ export function matchTag() {
function getUpdatedSelections(editor: vscode.TextEditor, position: vscode.Position, rootNode: HtmlNode): vscode.Selection {
let currentNode = <HtmlNode>getNode(rootNode, position, true);
if (!currentNode) {
return;
}
// If no closing tag or cursor is between open and close tag, then no-op
if (!currentNode.close || (position.isAfter(currentNode.open.end) && position.isBefore(currentNode.close.start))) {
......
......@@ -4,30 +4,26 @@
*--------------------------------------------------------------------------------------------*/
import * as vscode from 'vscode';
import parse from '@emmetio/html-matcher';
import { Node } from 'EmmetNode';
import { DocumentStreamReader } from './bufferStream';
import { isStyleSheet } from 'vscode-emmet-helper';
import { getNode } from './util';
import { getNode, parse, validate } from './util';
export function mergeLines() {
let editor = vscode.window.activeTextEditor;
if (!editor) {
vscode.window.showInformationMessage('No editor is active');
return;
}
if (isStyleSheet(editor.document.languageId)) {
if (!validate(false)) {
return;
}
let rootNode: Node = parse(new DocumentStreamReader(editor.document));
let rootNode = parse(editor.document);
if (!rootNode) {
return;
}
editor.edit(editBuilder => {
editor.selections.reverse().forEach(selection => {
let [rangeToReplace, textToReplaceWith] = getRangesToReplace(editor.document, selection, rootNode);
editBuilder.replace(rangeToReplace, textToReplaceWith);
if (rangeToReplace && textToReplaceWith) {
editBuilder.replace(rangeToReplace, textToReplaceWith);
}
});
});
}
......@@ -43,6 +39,10 @@ function getRangesToReplace(document: vscode.TextDocument, selection: vscode.Sel
endNodeToUpdate = getNode(rootNode, selection.end, true);
}
if (!startNodeToUpdate || !endNodeToUpdate) {
return [null, null];
}
let rangeToReplace = new vscode.Range(startNodeToUpdate.start, endNodeToUpdate.end);
let textToReplaceWith = document.getText(rangeToReplace).replace(/\r\n|\n/g, '').replace(/>\s*</g, '><');
......
......@@ -4,12 +4,17 @@
*--------------------------------------------------------------------------------------------*/
import * as vscode from 'vscode';
import { getOpenCloseRange } from './util';
import { parse, validate, getNode } from './util';
import { HtmlNode } from 'EmmetNode';
export function removeTag() {
let editor = vscode.window.activeTextEditor;
if (!editor) {
vscode.window.showInformationMessage('No editor is active');
if (!validate(false)) {
return;
}
let rootNode = <HtmlNode>parse(editor.document);
if (!rootNode) {
return;
}
......@@ -20,7 +25,7 @@ export function removeTag() {
let rangesToRemove = [];
editor.selections.reverse().forEach(selection => {
rangesToRemove = rangesToRemove.concat(getRangeToRemove(editor, selection, indentInSpaces));
rangesToRemove = rangesToRemove.concat(getRangeToRemove(editor, rootNode, selection, indentInSpaces));
});
editor.edit(editBuilder => {
......@@ -30,8 +35,19 @@ export function removeTag() {
});
}
function getRangeToRemove(editor: vscode.TextEditor, selection: vscode.Selection, indentInSpaces: string): vscode.Range[] {
let [openRange, closeRange] = getOpenCloseRange(editor.document, selection.start);
function getRangeToRemove(editor: vscode.TextEditor, rootNode: HtmlNode, selection: vscode.Selection, indentInSpaces: string): vscode.Range[] {
let nodeToUpdate = <HtmlNode>getNode(rootNode, selection.start);
if (!nodeToUpdate) {
return [];
}
let openRange = new vscode.Range(nodeToUpdate.open.start, nodeToUpdate.open.end);
let closeRange = null;
if (nodeToUpdate.close) {
closeRange = new vscode.Range(nodeToUpdate.close.start, nodeToUpdate.close.end);
}
if (!openRange.contains(selection.start) && !closeRange.contains(selection.start)) {
return [];
}
......@@ -50,4 +66,3 @@ function getRangeToRemove(editor: vscode.TextEditor, selection: vscode.Selection
return ranges;
}
......@@ -4,13 +4,9 @@
*--------------------------------------------------------------------------------------------*/
import * as vscode from 'vscode';
import { validate } from './util';
import { validate, parse } from './util';
import { nextItemHTML, prevItemHTML } from './selectItemHTML';
import { nextItemStylesheet, prevItemStylesheet } from './selectItemStylesheet';
import parseStylesheet from '@emmetio/css-parser';
import parse from '@emmetio/html-matcher';
import { Node } from 'EmmetNode';
import { DocumentStreamReader } from './bufferStream';
import { isStyleSheet } from 'vscode-emmet-helper';
......@@ -22,22 +18,20 @@ export function fetchSelectItem(direction: string): void {
let nextItem;
let prevItem;
let parseContent;
if (isStyleSheet(editor.document.languageId)) {
nextItem = nextItemStylesheet;
prevItem = prevItemStylesheet;
parseContent = parseStylesheet;
} else {
nextItem = nextItemHTML;
prevItem = prevItemHTML;
parseContent = parse;
}
let rootNode: Node = parseContent(new DocumentStreamReader(editor.document));
let rootNode = parse(editor.document);
if (!rootNode) {
return;
}
let newSelections: vscode.Selection[] = [];
editor.selections.forEach(selection => {
const selectionStart = selection.isReversed ? selection.active : selection.anchor;
......
......@@ -11,6 +11,10 @@ export function nextItemHTML(selectionStart: vscode.Position, selectionEnd: vsco
let currentNode = <HtmlNode>getNode(rootNode, selectionEnd);
let nextNode: HtmlNode;
if (!currentNode) {
return;
}
if (currentNode.type !== 'comment') {
// If cursor is in the tag name, select tag
if (selectionEnd.isBefore(currentNode.open.start.translate(0, currentNode.name.length))) {
......@@ -53,6 +57,10 @@ export function prevItemHTML(selectionStart: vscode.Position, selectionEnd: vsco
let currentNode = <HtmlNode>getNode(rootNode, selectionStart);
let prevNode: HtmlNode;
if (!currentNode) {
return;
}
if (currentNode.type !== 'comment' && selectionStart.translate(0, -1).isAfter(currentNode.open.start)) {
if (selectionStart.isBefore(currentNode.open.end) || !currentNode.firstChild) {
......
......@@ -12,7 +12,9 @@ export function nextItemStylesheet(startOffset: vscode.Position, endOffset: vsco
if (!currentNode) {
currentNode = <CssNode>rootNode;
}
if (!currentNode) {
return;
}
// Full property is selected, so select full property value next
if (currentNode.type === 'property' && startOffset.isEqual(currentNode.start) && endOffset.isEqual(currentNode.end)) {
return getSelectionFromProperty(currentNode, editor.document, startOffset, endOffset, true, 'next');
......@@ -53,6 +55,9 @@ export function prevItemStylesheet(startOffset: vscode.Position, endOffset: vsco
if (!currentNode) {
currentNode = rootNode;
}
if (!currentNode) {
return;
}
// Full property value is selected, so select the whole property next
if (currentNode.type === 'property' && startOffset.isEqual((<Property>currentNode).valueToken.start) && endOffset.isEqual((<Property>currentNode).valueToken.end)) {
......
......@@ -4,30 +4,26 @@
*--------------------------------------------------------------------------------------------*/
import * as vscode from 'vscode';
import parse from '@emmetio/html-matcher';
import Node from '@emmetio/node';
import { DocumentStreamReader } from './bufferStream';
import { isStyleSheet } from 'vscode-emmet-helper';
import { getNode } from './util';
import { getNode, parse, validate } from './util';
export function splitJoinTag() {
let editor = vscode.window.activeTextEditor;
if (!editor) {
vscode.window.showInformationMessage('No editor is active');
return;
}
if (isStyleSheet(editor.document.languageId)) {
if (!validate(false)) {
return;
}
let rootNode: Node = parse(new DocumentStreamReader(editor.document));
let rootNode = parse(editor.document);
if (!rootNode) {
return;
}
editor.edit(editBuilder => {
editor.selections.reverse().forEach(selection => {
let [rangeToReplace, textToReplaceWith] = getRangesToReplace(editor.document, selection, rootNode);
editBuilder.replace(rangeToReplace, textToReplaceWith);
if (rangeToReplace && textToReplaceWith) {
editBuilder.replace(rangeToReplace, textToReplaceWith);
}
});
});
}
......@@ -37,6 +33,10 @@ function getRangesToReplace(document: vscode.TextDocument, selection: vscode.Sel
let rangeToReplace: vscode.Range;
let textToReplaceWith: string;
if (!nodeToUpdate) {
return [null, null];
}
if (!nodeToUpdate.close) {
// Split Tag
let nodeText = document.getText(new vscode.Range(nodeToUpdate.start, nodeToUpdate.end));
......
......@@ -4,11 +4,8 @@
*--------------------------------------------------------------------------------------------*/
import * as vscode from 'vscode';
import { getNodesInBetween, getNode } from './util';
import parse from '@emmetio/html-matcher';
import parseStylesheet from '@emmetio/css-parser';
import { getNodesInBetween, getNode, parse } from './util';
import { Node, Stylesheet } from 'EmmetNode';
import { DocumentStreamReader } from './bufferStream';
import { isStyleSheet } from 'vscode-emmet-helper';
const startCommentStylesheet = '/*';
......@@ -26,24 +23,22 @@ export function toggleComment() {
let toggleCommentInternal;
let startComment;
let endComment;
let parseContent;
if (isStyleSheet(editor.document.languageId)) {
parseContent = parseStylesheet;
toggleCommentInternal = toggleCommentStylesheet;
startComment = startCommentStylesheet;
endComment = endCommentStylesheet;
} else {
parseContent = parse;
toggleCommentInternal = toggleCommentHTML;
startComment = startCommentHTML;
endComment = endCommentHTML;
}
let rootNode = parseContent(new DocumentStreamReader(editor.document));
let rootNode = parse(editor.document);
if (!rootNode) {
return;
}
editor.edit(editBuilder => {
editor.selections.reverse().forEach(selection => {
let [rangesToUnComment, rangeToComment] = toggleCommentInternal(editor.document, selection, rootNode);
......
......@@ -4,22 +4,19 @@
*--------------------------------------------------------------------------------------------*/
import * as vscode from 'vscode';
import parse from '@emmetio/html-matcher';
import { HtmlNode } from 'EmmetNode';
import { DocumentStreamReader } from './bufferStream';
import { getNode } from './util';
import { getNode, parse, validate } from './util';
export function updateTag(tagName: string) {
let editor = vscode.window.activeTextEditor;
if (!editor) {
vscode.window.showInformationMessage('No editor is active');
if (!validate(false)) {
return;
}
let rootNode: HtmlNode = parse(new DocumentStreamReader(editor.document));
let rootNode = <HtmlNode>parse(editor.document);
if (!rootNode) {
return;
}
let rangesToUpdate = [];
editor.selections.reverse().forEach(selection => {
rangesToUpdate = rangesToUpdate.concat(getRangesToUpdate(editor, selection, rootNode));
......@@ -34,14 +31,17 @@ export function updateTag(tagName: string) {
function getRangesToUpdate(editor: vscode.TextEditor, selection: vscode.Selection, rootNode: HtmlNode): vscode.Range[] {
let nodeToUpdate = <HtmlNode>getNode(rootNode, selection.start);
if (!nodeToUpdate) {
return [];
}
let openStart = (<vscode.Position>nodeToUpdate.open.start).translate(0, 1);
let openStart = nodeToUpdate.open.start.translate(0, 1);
let openEnd = openStart.translate(0, nodeToUpdate.name.length);
let ranges = [new vscode.Range(openStart, openEnd)];
if (nodeToUpdate.close) {
let closeStart = (<vscode.Position>nodeToUpdate.close.start).translate(0, 2);
let closeEnd = (<vscode.Position>nodeToUpdate.close.end).translate(0, -1);
let closeStart = nodeToUpdate.close.start.translate(0, 2);
let closeEnd = nodeToUpdate.close.end.translate(0, -1);
ranges.push(new vscode.Range(closeStart, closeEnd));
}
return ranges;
......
......@@ -5,6 +5,7 @@
import * as vscode from 'vscode';
import parse from '@emmetio/html-matcher';
import parseStylesheet from '@emmetio/css-parser';
import { Node, HtmlNode } from 'EmmetNode';
import { DocumentStreamReader } from './bufferStream';
import { isStyleSheet } from 'vscode-emmet-helper';
......@@ -33,6 +34,7 @@ export const MAPPED_MODES: Object = {
'handlebars': 'html',
'php': 'html'
};
export function validate(allowStylesheet: boolean = true): boolean {
let editor = vscode.window.activeTextEditor;
if (!editor) {
......@@ -64,7 +66,22 @@ export function getMappingForIncludedLanguages(): any {
return finalMappedModes;
}
/**
* Parses the given document using emmet parsing modules
* @param document
*/
export function parse(document: vscode.TextDocument, showError: boolean = true): Node {
let parseContent = isStyleSheet(document.languageId) ? parseStylesheet : parse;
let rootNode: Node;
try {
rootNode = parseContent(new DocumentStreamReader(document));
} catch (e) {
if (showError) {
vscode.window.showErrorMessage('Emmet: Failed to parse the file');
}
}
return rootNode;
}
/**
* Returns node corresponding to given position in the given root node
......@@ -104,17 +121,6 @@ export function getInnerRange(currentNode: HtmlNode): vscode.Range {
return new vscode.Range(currentNode.open.end, currentNode.close.start);
}
export function getOpenCloseRange(document: vscode.TextDocument, position: vscode.Position): [vscode.Range, vscode.Range] {
let rootNode: HtmlNode = parse(new DocumentStreamReader(document));
let nodeToUpdate = <HtmlNode>getNode(rootNode, position);
let openRange = new vscode.Range(nodeToUpdate.open.start, nodeToUpdate.open.end);
let closeRange = null;
if (nodeToUpdate.close) {
closeRange = new vscode.Range(nodeToUpdate.close.start, nodeToUpdate.close.end);
}
return [openRange, closeRange];
}
export function getDeepestNode(node: Node): Node {
if (!node || !node.children || node.children.length === 0 || !node.children.find(x => x.type !== 'comment')) {
return node;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册