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

Add typing for emmet node

上级 96524872
......@@ -7,7 +7,7 @@ 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 from '@emmetio/node';
import { Node, HtmlNode, Rule } from 'EmmetNode';
import { getNode, getInnerRange } from './util';
import { getExpandOptions, extractAbbreviation, isStyleSheet, isAbbreviationValid } from 'vscode-emmet-helper';
import { DocumentStreamReader } from './bufferStream';
......@@ -125,12 +125,16 @@ export function isValidLocationForEmmetAbbreviation(currentNode: Node, syntax: s
}
if (isStyleSheet(syntax)) {
return currentNode.type !== 'rule'
|| (currentNode.selectorToken && position.isAfter(currentNode.selectorToken.end));
if (currentNode.type !== 'rule') {
return true;
}
const currentCssNode = <Rule>currentNode;
return currentCssNode.selectorToken && position.isAfter(currentCssNode.selectorToken.end);
}
if (currentNode.close) {
return getInnerRange(currentNode).contains(position);
const currentHtmlNode = <HtmlNode>currentNode;
if (currentHtmlNode.close) {
return getInnerRange(currentHtmlNode).contains(position);
}
return false;
......
......@@ -5,7 +5,7 @@
import * as vscode from 'vscode';
import parse from '@emmetio/html-matcher';
import Node from '@emmetio/node';
import { HtmlNode } from 'EmmetNode';
import { DocumentStreamReader } from './bufferStream';
import { isStyleSheet } from 'vscode-emmet-helper';
import { getNode } from './util';
......@@ -29,7 +29,7 @@ function balance(out: boolean) {
}
let getRangeFunction = out ? getRangeToBalanceOut : getRangeToBalanceIn;
let rootNode: Node = parse(new DocumentStreamReader(editor.document));
let rootNode: HtmlNode = parse(new DocumentStreamReader(editor.document));
let newSelections: vscode.Selection[] = [];
editor.selections.forEach(selection => {
......@@ -41,8 +41,8 @@ function balance(out: boolean) {
editor.selections = newSelections;
}
function getRangeToBalanceOut(document: vscode.TextDocument, selection: vscode.Selection, rootNode: Node): vscode.Selection {
let nodeToBalance = getNode(rootNode, selection.start);
function getRangeToBalanceOut(document: vscode.TextDocument, selection: vscode.Selection, rootNode: HtmlNode): vscode.Selection {
let nodeToBalance = <HtmlNode>getNode(rootNode, selection.start);
if (!nodeToBalance) {
return;
}
......@@ -62,9 +62,8 @@ function getRangeToBalanceOut(document: vscode.TextDocument, selection: vscode.S
return;
}
function getRangeToBalanceIn(document: vscode.TextDocument, selection: vscode.Selection, rootNode: Node): vscode.Selection {
let nodeToBalance: Node = getNode(rootNode, selection.start, true);
function getRangeToBalanceIn(document: vscode.TextDocument, selection: vscode.Selection, rootNode: HtmlNode): vscode.Selection {
let nodeToBalance = <HtmlNode>getNode(rootNode, selection.start);
if (!nodeToBalance) {
return;
}
......
......@@ -6,7 +6,7 @@
import * as vscode from 'vscode';
import parseStylesheet from '@emmetio/css-parser';
import parse from '@emmetio/html-matcher';
import Node from '@emmetio/node';
import { Node, HtmlNode } from 'EmmetNode';
import { DocumentStreamReader } from './bufferStream';
import { EmmetCompletionItemProvider, isStyleSheet } from 'vscode-emmet-helper';
import { isValidLocationForEmmetAbbreviation } from './abbreviationActions';
......@@ -37,12 +37,14 @@ export class DefaultCompletionItemProvider implements vscode.CompletionItemProvi
let rootNode: Node = parseContent(new DocumentStreamReader(document));
let currentNode = getNode(rootNode, position);
if (!isStyleSheet(syntax)
&& currentNode
&& currentNode.close
&& currentNode.name === 'style'
&& getInnerRange(currentNode).contains(position)) {
return 'css';
if (!isStyleSheet(syntax)) {
const currentHtmlNode = <HtmlNode>currentNode;
if (currentHtmlNode
&& currentHtmlNode.close
&& currentHtmlNode.name === 'style'
&& getInnerRange(currentHtmlNode).contains(position)) {
return 'css';
}
}
if (!isValidLocationForEmmetAbbreviation(currentNode, syntax, position)) {
......
......@@ -5,7 +5,7 @@
import * as vscode from 'vscode';
import parse from '@emmetio/html-matcher';
import Node from '@emmetio/node';
import { HtmlNode } from 'EmmetNode';
import { DocumentStreamReader } from './bufferStream';
import { getNode } from './util';
......@@ -16,7 +16,7 @@ export function matchTag() {
return;
}
let rootNode: Node = parse(new DocumentStreamReader(editor.document));
let rootNode: HtmlNode = parse(new DocumentStreamReader(editor.document));
let updatedSelections = [];
editor.selections.forEach(selection => {
let updatedSelection = getUpdatedSelections(editor, selection.start, rootNode);
......@@ -30,8 +30,8 @@ export function matchTag() {
}
}
function getUpdatedSelections(editor: vscode.TextEditor, position: vscode.Position, rootNode: Node): vscode.Selection {
let currentNode = getNode(rootNode, position, true);
function getUpdatedSelections(editor: vscode.TextEditor, position: vscode.Position, rootNode: HtmlNode): vscode.Selection {
let currentNode = <HtmlNode>getNode(rootNode, position, true);
// 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))) {
......
......@@ -5,7 +5,7 @@
import * as vscode from 'vscode';
import parse from '@emmetio/html-matcher';
import Node from '@emmetio/node';
import { Node } from 'EmmetNode';
import { DocumentStreamReader } from './bufferStream';
import { isStyleSheet } from 'vscode-emmet-helper';
import { getNode } from './util';
......
......@@ -9,7 +9,7 @@ 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 '@emmetio/node';
import { Node } from 'EmmetNode';
import { DocumentStreamReader } from './bufferStream';
import { isStyleSheet } from 'vscode-emmet-helper';
......
......@@ -5,11 +5,11 @@
import * as vscode from 'vscode';
import { getDeepestNode, findNextWord, findPrevWord, getNode } from './util';
import Node from '@emmetio/node';
import { HtmlNode } from 'EmmetNode';
export function nextItemHTML(selectionStart: vscode.Position, selectionEnd: vscode.Position, editor: vscode.TextEditor, rootNode: Node): vscode.Selection {
let currentNode = getNode(rootNode, selectionEnd);
let nextNode: Node;
export function nextItemHTML(selectionStart: vscode.Position, selectionEnd: vscode.Position, editor: vscode.TextEditor, rootNode: HtmlNode): vscode.Selection {
let currentNode = <HtmlNode>getNode(rootNode, selectionEnd);
let nextNode: HtmlNode;
if (currentNode.type !== 'comment') {
// If cursor is in the tag name, select tag
......@@ -49,9 +49,9 @@ export function nextItemHTML(selectionStart: vscode.Position, selectionEnd: vsco
return getSelectionFromNode(nextNode, editor.document);
}
export function prevItemHTML(selectionStart: vscode.Position, selectionEnd: vscode.Position, editor: vscode.TextEditor, rootNode: Node): vscode.Selection {
let currentNode = getNode(rootNode, selectionStart);
let prevNode: Node;
export function prevItemHTML(selectionStart: vscode.Position, selectionEnd: vscode.Position, editor: vscode.TextEditor, rootNode: HtmlNode): vscode.Selection {
let currentNode = <HtmlNode>getNode(rootNode, selectionStart);
let prevNode: HtmlNode;
if (currentNode.type !== 'comment' && selectionStart.translate(0, -1).isAfter(currentNode.open.start)) {
......@@ -60,7 +60,7 @@ export function prevItemHTML(selectionStart: vscode.Position, selectionEnd: vsco
} else {
// Select the child that appears just before the cursor and is not a comment
prevNode = currentNode.firstChild;
let oldOption: Node;
let oldOption: HtmlNode;
while (prevNode.nextSibling && selectionStart.isAfterOrEqual(prevNode.nextSibling.end)) {
if (prevNode && prevNode.type !== 'comment') {
oldOption = prevNode;
......@@ -68,7 +68,7 @@ export function prevItemHTML(selectionStart: vscode.Position, selectionEnd: vsco
prevNode = prevNode.nextSibling;
}
prevNode = getDeepestNode((prevNode && prevNode.type !== 'comment') ? prevNode : oldOption);
prevNode = <HtmlNode>getDeepestNode((prevNode && prevNode.type !== 'comment') ? prevNode : oldOption);
}
}
......@@ -76,7 +76,7 @@ export function prevItemHTML(selectionStart: vscode.Position, selectionEnd: vsco
while (!prevNode && currentNode) {
if (currentNode.previousSibling) {
if (currentNode.previousSibling.type !== 'comment') {
prevNode = getDeepestNode(currentNode.previousSibling);
prevNode = <HtmlNode>getDeepestNode(currentNode.previousSibling);
} else {
currentNode = currentNode.previousSibling;
}
......@@ -90,7 +90,7 @@ export function prevItemHTML(selectionStart: vscode.Position, selectionEnd: vsco
return attrSelection ? attrSelection : getSelectionFromNode(prevNode, editor.document);
}
function getSelectionFromNode(node: Node, document: vscode.TextDocument): vscode.Selection {
function getSelectionFromNode(node: HtmlNode, document: vscode.TextDocument): vscode.Selection {
if (node && node.open) {
let selectionStart = (<vscode.Position>node.open.start).translate(0, 1);
let selectionEnd = selectionStart.translate(0, node.name.length);
......@@ -99,7 +99,7 @@ function getSelectionFromNode(node: Node, document: vscode.TextDocument): vscode
}
}
function getNextAttribute(selectionStart: vscode.Position, selectionEnd: vscode.Position, document: vscode.TextDocument, node: Node): vscode.Selection {
function getNextAttribute(selectionStart: vscode.Position, selectionEnd: vscode.Position, document: vscode.TextDocument, node: HtmlNode): vscode.Selection {
if (!node.attributes || node.attributes.length === 0 || node.type === 'comment') {
return;
......@@ -150,7 +150,7 @@ function getNextAttribute(selectionStart: vscode.Position, selectionEnd: vscode.
}
}
function getPrevAttribute(selectionStart: vscode.Position, selectionEnd: vscode.Position, document: vscode.TextDocument, node: Node): vscode.Selection {
function getPrevAttribute(selectionStart: vscode.Position, selectionEnd: vscode.Position, document: vscode.TextDocument, node: HtmlNode): vscode.Selection {
if (!node.attributes || node.attributes.length === 0 || node.type === 'comment') {
return;
......
......@@ -5,12 +5,12 @@
import * as vscode from 'vscode';
import { getDeepestNode, findNextWord, findPrevWord, getNode } from './util';
import Node from '@emmetio/node';
import { Node, CssNode, Rule, Property } from 'EmmetNode';
export function nextItemStylesheet(startOffset: vscode.Position, endOffset: vscode.Position, editor: vscode.TextEditor, rootNode: Node): vscode.Selection {
let currentNode = getNode(rootNode, endOffset, true);
let currentNode = <CssNode>getNode(rootNode, endOffset, true);
if (!currentNode) {
currentNode = rootNode;
currentNode = <CssNode>rootNode;
}
// Full property is selected, so select full property value next
......@@ -19,7 +19,7 @@ export function nextItemStylesheet(startOffset: vscode.Position, endOffset: vsco
}
// Part or whole of propertyValue is selected, so select the next word in the propertyValue
if (currentNode.type === 'property' && startOffset.isAfterOrEqual(currentNode.valueToken.start) && endOffset.isBeforeOrEqual(currentNode.valueToken.end)) {
if (currentNode.type === 'property' && startOffset.isAfterOrEqual((<Property>currentNode).valueToken.start) && endOffset.isBeforeOrEqual((<Property>currentNode).valueToken.end)) {
let singlePropertyValue = getSelectionFromProperty(currentNode, editor.document, startOffset, endOffset, false, 'next');
if (singlePropertyValue) {
return singlePropertyValue;
......@@ -27,8 +27,8 @@ export function nextItemStylesheet(startOffset: vscode.Position, endOffset: vsco
}
// Cursor is in the selector or in a property
if ((currentNode.type === 'rule' && endOffset.isBefore(currentNode.selectorToken.end))
|| (currentNode.type === 'property' && endOffset.isBefore(currentNode.valueToken.end))) {
if ((currentNode.type === 'rule' && endOffset.isBefore((<Rule>currentNode).selectorToken.end))
|| (currentNode.type === 'property' && endOffset.isBefore((<Property>currentNode).valueToken.end))) {
return getSelectionFromNode(currentNode, editor.document);
}
......@@ -48,19 +48,19 @@ export function nextItemStylesheet(startOffset: vscode.Position, endOffset: vsco
}
export function prevItemStylesheet(startOffset: vscode.Position, endOffset: vscode.Position, editor: vscode.TextEditor, rootNode: Node): vscode.Selection {
let currentNode = getNode(rootNode, startOffset);
export function prevItemStylesheet(startOffset: vscode.Position, endOffset: vscode.Position, editor: vscode.TextEditor, rootNode: CssNode): vscode.Selection {
let currentNode = <CssNode>getNode(rootNode, startOffset);
if (!currentNode) {
currentNode = rootNode;
}
// Full property value is selected, so select the whole property next
if (currentNode.type === 'property' && startOffset.isEqual(currentNode.valueToken.start) && endOffset.isEqual(currentNode.valueToken.end)) {
if (currentNode.type === 'property' && startOffset.isEqual((<Property>currentNode).valueToken.start) && endOffset.isEqual((<Property>currentNode).valueToken.end)) {
return getSelectionFromNode(currentNode, editor.document);
}
// Part of propertyValue is selected, so select the prev word in the propertyValue
if (currentNode.type === 'property' && startOffset.isAfterOrEqual(currentNode.valueToken.start) && endOffset.isBeforeOrEqual(currentNode.valueToken.end)) {
if (currentNode.type === 'property' && startOffset.isAfterOrEqual((<Property>currentNode).valueToken.start) && endOffset.isBeforeOrEqual((<Property>currentNode).valueToken.end)) {
let singlePropertyValue = getSelectionFromProperty(currentNode, editor.document, startOffset, endOffset, false, 'prev');
if (singlePropertyValue) {
return singlePropertyValue;
......@@ -76,7 +76,7 @@ export function prevItemStylesheet(startOffset: vscode.Position, endOffset: vsco
while (prevNode.nextSibling && startOffset.isAfterOrEqual(prevNode.nextSibling.end)) {
prevNode = prevNode.nextSibling;
}
prevNode = getDeepestNode(prevNode);
prevNode = <CssNode>getDeepestNode(prevNode);
return getSelectionFromProperty(prevNode, editor.document, startOffset, endOffset, false, 'prev');
......@@ -88,7 +88,7 @@ function getSelectionFromNode(node: Node, document: vscode.TextDocument): vscode
return;
}
let nodeToSelect = node.type === 'rule' ? node.selectorToken : node;
let nodeToSelect = node.type === 'rule' ? (<Rule>node).selectorToken : node;
return new vscode.Selection(nodeToSelect.start, nodeToSelect.end);
}
......@@ -97,27 +97,28 @@ function getSelectionFromProperty(node: Node, document: vscode.TextDocument, sel
if (!node || node.type !== 'property') {
return;
}
const propertyNode = <Property>node;
let propertyValue = node.valueToken.stream.substring(node.valueToken.start, node.valueToken.end);
selectFullValue = selectFullValue || (direction === 'prev' && selectionStart.isEqual(node.valueToken.start) && selectionEnd.isBefore(node.valueToken.end));
let propertyValue = propertyNode.valueToken.stream.substring(propertyNode.valueToken.start, propertyNode.valueToken.end);
selectFullValue = selectFullValue || (direction === 'prev' && selectionStart.isEqual(propertyNode.valueToken.start) && selectionEnd.isBefore(propertyNode.valueToken.end));
if (selectFullValue) {
return new vscode.Selection(node.valueToken.start, node.valueToken.end);
return new vscode.Selection(propertyNode.valueToken.start, propertyNode.valueToken.end);
}
let pos;
if (direction === 'prev') {
if (selectionStart.isEqual(node.valueToken.start)) {
if (selectionStart.isEqual(propertyNode.valueToken.start)) {
return;
}
pos = selectionStart.isAfter(node.valueToken.end) ? propertyValue.length : selectionStart.character - node.valueToken.start.character;
pos = selectionStart.isAfter(propertyNode.valueToken.end) ? propertyValue.length : selectionStart.character - propertyNode.valueToken.start.character;
}
if (direction === 'next') {
if (selectionEnd.isEqual(node.valueToken.end) && (selectionStart.isAfter(node.valueToken.start) || propertyValue.indexOf(' ') === -1)) {
if (selectionEnd.isEqual(propertyNode.valueToken.end) && (selectionStart.isAfter(propertyNode.valueToken.start) || propertyValue.indexOf(' ') === -1)) {
return;
}
pos = selectionEnd.isEqual(node.valueToken.end) ? -1 : selectionEnd.character - node.valueToken.start.character - 1;
pos = selectionEnd.isEqual(propertyNode.valueToken.end) ? -1 : selectionEnd.character - propertyNode.valueToken.start.character - 1;
}
......@@ -126,8 +127,8 @@ function getSelectionFromProperty(node: Node, document: vscode.TextDocument, sel
return;
}
const newSelectionStart = (<vscode.Position>node.valueToken.start).translate(0, newSelectionStartOffset);
const newSelectionEnd = (<vscode.Position>node.valueToken.start).translate(0, newSelectionEndOffset);
const newSelectionStart = (<vscode.Position>propertyNode.valueToken.start).translate(0, newSelectionStartOffset);
const newSelectionEnd = (<vscode.Position>propertyNode.valueToken.start).translate(0, newSelectionEndOffset);
return new vscode.Selection(newSelectionStart, newSelectionEnd);
}
......
......@@ -7,7 +7,7 @@ import * as vscode from 'vscode';
import { getNodesInBetween, getNode } from './util';
import parse from '@emmetio/html-matcher';
import parseStylesheet from '@emmetio/css-parser';
import Node from '@emmetio/node';
import { Node, Stylesheet } from 'EmmetNode';
import { DocumentStreamReader } from './bufferStream';
import { isStyleSheet } from 'vscode-emmet-helper';
......@@ -102,7 +102,7 @@ function getRangesToUnCommentHTML(node: Node, document: vscode.TextDocument): vs
return rangesToUnComment;
}
function toggleCommentStylesheet(document: vscode.TextDocument, selection: vscode.Selection, rootNode: Node): [vscode.Range[], vscode.Range] {
function toggleCommentStylesheet(document: vscode.TextDocument, selection: vscode.Selection, rootNode: Stylesheet): [vscode.Range[], vscode.Range] {
const selectionStart = selection.isReversed ? selection.active : selection.anchor;
const selectionEnd = selection.isReversed ? selection.anchor : selection.active;
......
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
declare module 'EmmetNode' {
import { Position } from 'vscode';
export interface Node {
start: Position
end: Position
type: string
parent: Node
firstChild: Node
nextSibling: Node
previousSibling: Node
children: Node[]
}
export interface Token {
start: Position
end: Position
stream: BufferStream
toString(): string
}
export interface Attribute extends Token {
name: string
value: Token
}
export interface HtmlNode extends Node {
name: string
open: Token
close: Token
parent: HtmlNode
firstChild: HtmlNode
nextSibling: HtmlNode
previousSibling: HtmlNode
children: HtmlNode[]
attributes: Attribute[]
}
export interface CssNode extends Node {
parent: CssNode
firstChild: CssNode
nextSibling: CssNode
previousSibling: CssNode
children: CssNode[]
}
export interface Rule extends CssNode {
selectorToken: Token
}
export interface Property extends CssNode {
valueToken: Token
}
export interface Stylesheet extends Node {
comments: Token[]
}
export interface BufferStream {
peek(): number
next(): number
backUp(n: number): number
current(): string
substring(from: Position, to: Position): string
eat(match): boolean
eatWhile(match): boolean
}
}
......@@ -5,7 +5,7 @@
import * as vscode from 'vscode';
import parse from '@emmetio/html-matcher';
import Node from '@emmetio/node';
import { HtmlNode } from 'EmmetNode';
import { DocumentStreamReader } from './bufferStream';
import { getNode } from './util';
......@@ -16,7 +16,7 @@ export function updateTag(tagName: string) {
return;
}
let rootNode: Node = parse(new DocumentStreamReader(editor.document));
let rootNode: HtmlNode = parse(new DocumentStreamReader(editor.document));
let rangesToUpdate = [];
editor.selections.reverse().forEach(selection => {
rangesToUpdate = rangesToUpdate.concat(getRangesToUpdate(editor, selection, rootNode));
......@@ -29,8 +29,8 @@ export function updateTag(tagName: string) {
});
}
function getRangesToUpdate(editor: vscode.TextEditor, selection: vscode.Selection, rootNode: Node): vscode.Range[] {
let nodeToUpdate = getNode(rootNode, selection.start);
function getRangesToUpdate(editor: vscode.TextEditor, selection: vscode.Selection, rootNode: HtmlNode): vscode.Range[] {
let nodeToUpdate = <HtmlNode>getNode(rootNode, selection.start);
let openStart = (<vscode.Position>nodeToUpdate.open.start).translate(0, 1);
let openEnd = openStart.translate(0, nodeToUpdate.name.length);
......
......@@ -5,7 +5,7 @@
import * as vscode from 'vscode';
import parse from '@emmetio/html-matcher';
import Node from '@emmetio/node';
import { Node, HtmlNode } from 'EmmetNode';
import { DocumentStreamReader } from './bufferStream';
import { isStyleSheet } from 'vscode-emmet-helper';
......@@ -69,7 +69,7 @@ export function getExcludedModes(): string[] {
* @param includeNodeBoundary
*/
export function getNode(root: Node, position: vscode.Position, includeNodeBoundary: boolean = false) {
let currentNode: Node = root.firstChild;
let currentNode = root.firstChild;
let foundNode: Node = null;
while (currentNode) {
......@@ -93,7 +93,7 @@ export function getNode(root: Node, position: vscode.Position, includeNodeBounda
* Returns inner range of an html node.
* @param currentNode
*/
export function getInnerRange(currentNode: Node): vscode.Range {
export function getInnerRange(currentNode: HtmlNode): vscode.Range {
if (!currentNode.close) {
return;
}
......@@ -101,8 +101,8 @@ export function getInnerRange(currentNode: Node): vscode.Range {
}
export function getOpenCloseRange(document: vscode.TextDocument, position: vscode.Position): [vscode.Range, vscode.Range] {
let rootNode: Node = parse(new DocumentStreamReader(document));
let nodeToUpdate = getNode(rootNode, position);
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) {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册