abbreviationActions.ts 3.3 KB
Newer Older
1 2 3 4 5 6 7
/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *  Licensed under the MIT License. See License.txt in the project root for license information.
 *--------------------------------------------------------------------------------------------*/

import * as vscode from 'vscode';
import { expand } from '@emmetio/expand-abbreviation';
8 9 10
import parseStylesheet from '@emmetio/css-parser';
import parse from '@emmetio/html-matcher';
import Node from '@emmetio/node';
11
import { getSyntax, getNode, getInnerRange } from './util';
12
import { getExpandOptions, extractAbbreviation, isStyleSheet } from 'vscode-emmet-helper';
13
import { DocumentStreamReader } from './bufferStream';
14 15 16 17 18 19 20 21 22 23 24 25

export function wrapWithAbbreviation() {
	let editor = vscode.window.activeTextEditor;
	if (!editor) {
		vscode.window.showInformationMessage('No editor is active');
		return;
	}
	let rangeToReplace: vscode.Range = editor.selection;
	if (rangeToReplace.isEmpty) {
		rangeToReplace = new vscode.Range(rangeToReplace.start.line, 0, rangeToReplace.start.line, editor.document.lineAt(rangeToReplace.start.line).text.length);
	}
	let textToReplace = editor.document.getText(rangeToReplace);
26
	let syntax = getSyntax(editor.document);
27 28 29

	vscode.window.showInputBox({ prompt: 'Enter Abbreviation' }).then(abbr => {
		if (!abbr || !abbr.trim()) { return; }
30
		let expandedText = expand(abbr, getExpandOptions(syntax, textToReplace));
31 32 33 34
		editor.insertSnippet(new vscode.SnippetString(expandedText), rangeToReplace);
	});
}

35 36
export function expandAbbreviation(args) {

37 38 39 40 41
	let editor = vscode.window.activeTextEditor;
	if (!editor) {
		vscode.window.showInformationMessage('No editor is active');
		return;
	}
42
	if (typeof args !== 'object' || !args['syntax']) {
43 44
		return;
	}
45
	let syntax = args['syntax'];
46
	let parseContent = isStyleSheet(syntax) ? parseStylesheet : parse;
47
	let rootNode: Node = parseContent(new DocumentStreamReader(editor.document));
48

49 50 51 52 53 54 55
	editor.selections.forEach(selection => {
		let abbreviationRange: vscode.Range = selection;
		let position = selection.isReversed ? selection.anchor : selection.active;
		let abbreviation = editor.document.getText(abbreviationRange);
		if (abbreviationRange.isEmpty) {
			[abbreviationRange, abbreviation] = extractAbbreviation(editor.document, position);
		}
56

57 58 59 60 61 62 63 64 65 66
		let currentNode = getNode(rootNode, position);
		if (!isValidLocationForEmmetAbbreviation(currentNode, syntax, position)) {
			return;
		}

		let expandedText = expand(abbreviation, getExpandOptions(syntax));
		if (expandedText) {
			editor.insertSnippet(new vscode.SnippetString(expandedText), abbreviationRange);
		}
	});
67 68 69 70
}


/**
71 72
 * Checks if given position is a valid location to expand emmet abbreviation.
 * Works only on html and css/less/scss syntax
73 74 75 76
 * @param currentNode parsed node at given position
 * @param syntax syntax of the abbreviation
 * @param position position to validate
 */
77
export function isValidLocationForEmmetAbbreviation(currentNode: Node, syntax: string, position: vscode.Position): boolean {
78 79 80 81 82 83 84 85 86 87 88 89 90 91
	if (!currentNode) {
		return true;
	}

	if (isStyleSheet(syntax)) {
		return currentNode.type !== 'rule'
			|| (currentNode.selectorToken && position.isAfter(currentNode.selectorToken.end));
	}

	if (currentNode.close) {
		return getInnerRange(currentNode).contains(position);
	}

	return false;
92
}