Merge branch 'master' into git-ext-strict

This commit is contained in:
João Moreno
2017-11-08 10:36:28 +01:00
committed by GitHub
434 changed files with 2110 additions and 2505 deletions
+3 -3
View File
@@ -33,11 +33,11 @@
"task": "tslint",
"label": "Run tslint",
"problemMatcher": [
"$tslint4"
"$tslint5"
]
},
{
"taskName": "Run tests",
"label": "Run tests",
"type": "shell",
"command": "./scripts/test.sh",
"windows": {
@@ -50,7 +50,7 @@
}
},
{
"taskName": "Run Dev",
"label": "Run Dev",
"type": "shell",
"command": "./scripts/code.sh",
"windows": {
+15 -14
View File
@@ -123,7 +123,8 @@ const tslintFilter = [
'!**/node_modules/**',
'!extensions/typescript/test/colorize-fixtures/**',
'!extensions/vscode-api-tests/testWorkspace/**',
'!extensions/**/*.test.ts'
'!extensions/**/*.test.ts',
'!extensions/html/server/lib/jquery.d.ts'
];
const copyrightHeader = [
@@ -133,17 +134,6 @@ const copyrightHeader = [
' *--------------------------------------------------------------------------------------------*/'
].join('\n');
function reportFailures(failures) {
failures.forEach(failure => {
const name = failure.name || failure.fileName;
const position = failure.startPosition;
const line = position.lineAndCharacter ? position.lineAndCharacter.line : position.line;
const character = position.lineAndCharacter ? position.lineAndCharacter.character : position.character;
console.error(`${name}:${line + 1}:${character + 1}:${failure.failure}`);
});
}
gulp.task('eslint', () => {
return vfs.src(all, { base: '.', follow: true, allowEmpty: true })
.pipe(filter(eslintFilter))
@@ -153,12 +143,12 @@ gulp.task('eslint', () => {
});
gulp.task('tslint', () => {
const options = { summarizeFailureOutput: true };
const options = { emitError: false };
return vfs.src(all, { base: '.', follow: true, allowEmpty: true })
.pipe(filter(tslintFilter))
.pipe(gulptslint({ rulesDirectory: 'build/lib/tslint' }))
.pipe(gulptslint.report(reportFailures, options));
.pipe(gulptslint.report(options));
});
const hygiene = exports.hygiene = (some, options) => {
@@ -219,6 +209,17 @@ const hygiene = exports.hygiene = (some, options) => {
cb(err);
});
});
function reportFailures(failures) {
failures.forEach(failure => {
const name = failure.name || failure.fileName;
const position = failure.startPosition;
const line = position.lineAndCharacter ? position.lineAndCharacter.line : position.line;
const character = position.lineAndCharacter ? position.lineAndCharacter.character : position.character;
console.error(`${name}:${line + 1}:${character + 1}:${failure.failure}`);
});
}
const tsl = es.through(function (file) {
const configuration = tslint.Configuration.findConfiguration(null, '.');
+1 -1
View File
@@ -452,7 +452,7 @@ gulp.task('upload-vscode-sourcemaps', ['minify-vscode'], () => {
const allConfigDetailsPath = path.join(os.tmpdir(), 'configuration.json');
gulp.task('upload-vscode-configuration', ['generate-vscode-configuration'], () => {
const branch = process.env.BUILD_SOURCEBRANCH;
if (!branch.endsWith('/master') && !branch.indexOf('/release/') >= 0) {
if (!branch.endsWith('/master') && !branch.startsWith('release/')) {
console.log(`Only runs on master and release branches, not ${branch}`);
return;
}
@@ -88,10 +88,11 @@ var NoUnexternalizedStringsRuleWalker = /** @class */ (function (_super) {
var info = this.findDescribingParent(node);
// Ignore strings in import and export nodes.
if (info && info.isImport && doubleQuoted) {
this.addFailureAtNode(node, NoUnexternalizedStringsRuleWalker.ImportFailureMessage, new Lint.Fix(NoUnexternalizedStringsRuleWalker.ImportFailureMessage, [
this.createReplacement(node.getStart(), 1, '\''),
this.createReplacement(node.getStart() + text.length - 1, 1, '\''),
]));
var fix = [
Lint.Replacement.replaceFromTo(node.getStart(), 1, '\''),
Lint.Replacement.replaceFromTo(node.getStart() + text.length - 1, 1, '\''),
];
this.addFailureAtNode(node, NoUnexternalizedStringsRuleWalker.ImportFailureMessage, fix);
return;
}
var callInfo = info ? info.callInfo : null;
@@ -101,8 +102,9 @@ var NoUnexternalizedStringsRuleWalker = /** @class */ (function (_super) {
}
if (doubleQuoted && (!callInfo || callInfo.argIndex === -1 || !this.signatures[functionName])) {
var s = node.getText();
var replacement = new Lint.Replacement(node.getStart(), node.getWidth(), "nls.localize('KEY-" + s.substring(1, s.length - 1) + "', " + s + ")");
var fix = new Lint.Fix('Unexternalitzed string', [replacement]);
var fix = [
Lint.Replacement.replaceFromTo(node.getStart(), node.getWidth(), "nls.localize('KEY-" + s.substring(1, s.length - 1) + "', " + s + ")"),
];
this.addFailure(this.createFailure(node.getStart(), node.getWidth(), "Unexternalized string found: " + node.getText(), fix));
return;
}
@@ -104,13 +104,14 @@ class NoUnexternalizedStringsRuleWalker extends Lint.RuleWalker {
let info = this.findDescribingParent(node);
// Ignore strings in import and export nodes.
if (info && info.isImport && doubleQuoted) {
const fix = [
Lint.Replacement.replaceFromTo(node.getStart(), 1, '\''),
Lint.Replacement.replaceFromTo(node.getStart() + text.length - 1, 1, '\''),
];
this.addFailureAtNode(
node,
NoUnexternalizedStringsRuleWalker.ImportFailureMessage,
new Lint.Fix(NoUnexternalizedStringsRuleWalker.ImportFailureMessage, [
this.createReplacement(node.getStart(), 1, '\''),
this.createReplacement(node.getStart() + text.length - 1, 1, '\''),
])
fix
);
return;
}
@@ -122,8 +123,9 @@ class NoUnexternalizedStringsRuleWalker extends Lint.RuleWalker {
if (doubleQuoted && (!callInfo || callInfo.argIndex === -1 || !this.signatures[functionName])) {
const s = node.getText();
const replacement = new Lint.Replacement(node.getStart(), node.getWidth(), `nls.localize('KEY-${s.substring(1, s.length - 1)}', ${s})`);
const fix = new Lint.Fix('Unexternalitzed string', [replacement]);
const fix = [
Lint.Replacement.replaceFromTo(node.getStart(), node.getWidth(), `nls.localize('KEY-${s.substring(1, s.length - 1)}', ${s})`),
];
this.addFailure(this.createFailure(node.getStart(), node.getWidth(), `Unexternalized string found: ${node.getText()}`, fix));
return;
}
+2 -1
View File
@@ -1 +1,2 @@
pat
pat
*.js
+42
View File
@@ -0,0 +1,42 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import { DocumentClient } from 'documentdb';
interface Config {
id: string;
frozen: boolean;
}
function createDefaultConfig(quality: string): Config {
return {
id: quality,
frozen: false
};
}
function getConfig(quality: string): Promise<Config> {
const client = new DocumentClient(process.env['AZURE_DOCUMENTDB_ENDPOINT'], { masterKey: process.env['AZURE_DOCUMENTDB_MASTERKEY'] });
const collection = 'dbs/builds/colls/config';
const query = {
query: `SELECT TOP 1 * FROM c WHERE c.id = @quality`,
parameters: [
{ name: '@quality', value: quality }
]
};
return new Promise<Config>((c, e) => {
client.queryDocuments(collection, query).toArray((err, results) => {
if (err && err.code !== 409) { return e(err); }
c(!results || results.length === 0 ? createDefaultConfig(quality) : results[0] as any as Config);
});
});
}
getConfig(process.argv[2])
.then(c => console.log(c.frozen), e => console.error(e));
+4
View File
@@ -55,8 +55,12 @@ step "Publish RPM package" \
# SNAP_FILENAME="$(ls $REPO/.build/linux/snap/$ARCH/ | grep .snap)"
# SNAP_PATH="$REPO/.build/linux/snap/$ARCH/$SNAP_FILENAME"
IS_FROZEN="$(node build/tfs/linux/frozen-check.js $VSCODE_QUALITY)"
if [ -z "$VSCODE_QUALITY" ]; then
echo "VSCODE_QUALITY is not set, skipping repo package publish"
elif [ "$IS_FROZEN" = "true" ]; then
echo "$VSCODE_QUALITY is frozen, skipping repo package publish"
else
if [ "$BUILD_SOURCEBRANCH" = "master" ] || [ "$BUILD_SOURCEBRANCH" = "refs/heads/master" ]; then
if [[ $BUILD_QUEUEDBY = *"Project Collection Service Accounts"* || $BUILD_QUEUEDBY = *"Microsoft.VisualStudio.Services.TFS"* ]]; then
+1
View File
@@ -3,6 +3,7 @@
"target": "es5",
"module": "commonjs",
"outDir": "./out",
"noUnusedLocals": true,
"lib": [
"es5", "es2015.promise"
]
+8 -2
View File
@@ -20,5 +20,11 @@
["(", ")"],
["\"", "\""],
["'", "'"]
]
}
],
"folding": {
"markers": {
"start": "^\\s*\\/\\*\\s*#region\\b\\s*(.*?)\\s*\\*\\/",
"end": "^\\s*\\/\\*\\s*#endregion\\b.*\\*\\/"
}
}
}
+1
View File
@@ -3,6 +3,7 @@
"target": "es5",
"module": "commonjs",
"outDir": "./out",
"noUnusedLocals": true,
"lib": [
"es5"
]
+11 -10
View File
@@ -17,8 +17,8 @@ interface ExpandAbbreviationInput {
filter?: string;
}
export function wrapWithAbbreviation(args) {
if (!validate(false)) {
export function wrapWithAbbreviation(args: any) {
if (!validate(false) || !vscode.window.activeTextEditor) {
return;
}
@@ -50,8 +50,8 @@ export function wrapWithAbbreviation(args) {
});
}
export function wrapIndividualLinesWithAbbreviation(args) {
if (!validate(false)) {
export function wrapIndividualLinesWithAbbreviation(args: any) {
if (!validate(false) || !vscode.window.activeTextEditor) {
return;
}
@@ -88,7 +88,7 @@ export function wrapIndividualLinesWithAbbreviation(args) {
}
export function expandEmmetAbbreviation(args): Thenable<boolean> {
export function expandEmmetAbbreviation(args: any): Thenable<boolean> {
const syntax = getSyntaxFromArgs(args);
if (!syntax || !validate()) {
return fallbackTab();
@@ -179,7 +179,7 @@ export function expandEmmetAbbreviation(args): Thenable<boolean> {
});
}
function fallbackTab(): Thenable<boolean> {
function fallbackTab(): Thenable<boolean | undefined> | undefined {
if (vscode.workspace.getConfiguration('emmet')['triggerExpansionOnTab'] === true) {
return vscode.commands.executeCommand('tab');
}
@@ -226,7 +226,8 @@ export function isValidLocationForEmmetAbbreviation(currentNode: Node, syntax: s
const currentHtmlNode = <HtmlNode>currentNode;
if (currentHtmlNode.close) {
return getInnerRange(currentHtmlNode).contains(position);
const innerRange = getInnerRange(currentHtmlNode);
return !!innerRange && innerRange.contains(position);
}
return false;
@@ -247,7 +248,7 @@ function expandAbbreviationInRange(editor: vscode.TextEditor, expandAbbrList: Ex
// Snippet to replace at multiple cursors are not the same
// `editor.insertSnippet` will have to be called for each instance separately
// We will not be able to maintain multiple cursors after snippet insertion
let insertPromises = [];
let insertPromises: Thenable<boolean>[] = [];
if (!insertSameSnippet) {
expandAbbrList.forEach((expandAbbrInput: ExpandAbbreviationInput) => {
let expandedText = expandAbbr(expandAbbrInput);
@@ -278,7 +279,7 @@ function expandAbbreviationInRange(editor: vscode.TextEditor, expandAbbrList: Ex
/**
* Expands abbreviation as detailed in given input.
*/
function expandAbbr(input: ExpandAbbreviationInput): string {
function expandAbbr(input: ExpandAbbreviationInput): string | undefined {
const helper = getEmmetHelper();
const expandOptions = helper.getExpandOptions(input.syntax, getEmmetConfiguration(input.syntax), input.filter);
@@ -322,7 +323,7 @@ function expandAbbr(input: ExpandAbbreviationInput): string {
}
function getSyntaxFromArgs(args: any): string {
function getSyntaxFromArgs(args: any): string | undefined {
let editor = vscode.window.activeTextEditor;
if (!editor) {
vscode.window.showInformationMessage('No editor is active.');
+7 -8
View File
@@ -16,11 +16,10 @@ export function balanceIn() {
}
function balance(out: boolean) {
let editor = vscode.window.activeTextEditor;
if (!validate(false)) {
if (!validate(false) || !vscode.window.activeTextEditor) {
return;
}
const editor = vscode.window.activeTextEditor;
let rootNode = <HtmlNode>parseDocument(editor.document);
if (!rootNode) {
return;
@@ -30,7 +29,7 @@ function balance(out: boolean) {
let newSelections: vscode.Selection[] = [];
editor.selections.forEach(selection => {
let range = getRangeFunction(editor.document, selection, rootNode);
newSelections.push(range ? range : selection);
newSelections.push(range);
});
editor.selection = newSelections[0];
@@ -40,7 +39,7 @@ function balance(out: boolean) {
function getRangeToBalanceOut(document: vscode.TextDocument, selection: vscode.Selection, rootNode: HtmlNode): vscode.Selection {
let nodeToBalance = <HtmlNode>getNode(rootNode, selection.start);
if (!nodeToBalance) {
return;
return selection;
}
if (!nodeToBalance.close) {
return new vscode.Selection(nodeToBalance.start, nodeToBalance.end);
@@ -55,13 +54,13 @@ function getRangeToBalanceOut(document: vscode.TextDocument, selection: vscode.S
if (outerSelection.contains(selection) && !outerSelection.isEqual(selection)) {
return outerSelection;
}
return;
return selection;
}
function getRangeToBalanceIn(document: vscode.TextDocument, selection: vscode.Selection, rootNode: HtmlNode): vscode.Selection {
let nodeToBalance = <HtmlNode>getNode(rootNode, selection.start, true);
if (!nodeToBalance) {
return;
return selection;
}
if (selection.start.isEqual(nodeToBalance.start)
@@ -71,7 +70,7 @@ function getRangeToBalanceIn(document: vscode.TextDocument, selection: vscode.Se
}
if (!nodeToBalance.firstChild) {
return;
return selection;
}
if (selection.start.isEqual(nodeToBalance.firstChild.start)
+10 -28
View File
@@ -43,20 +43,16 @@ export class DocumentStreamReader {
/**
* Creates a new stream instance which is limited to given range for given document
* @param {Position} start
* @param {Position} end
* @return {DocumentStreamReader}
*/
limit(start, end) {
limit(start: Position, end: Position): DocumentStreamReader {
return new DocumentStreamReader(this.document, start, new Range(start, end));
}
/**
* Returns the next character code in the stream without advancing it.
* Will return NaN at the end of the file.
* @returns {Number}
*/
peek() {
peek(): number {
if (this.eof()) {
return NaN;
}
@@ -67,9 +63,8 @@ export class DocumentStreamReader {
/**
* Returns the next character in the stream and advances it.
* Also returns NaN when no more characters are available.
* @returns {Number}
*/
next() {
next(): number {
if (this.eof()) {
return NaN;
}
@@ -95,9 +90,8 @@ export class DocumentStreamReader {
/**
* Backs up the stream n characters. Backing it up further than the
* start of the current token will cause things to break, so be careful.
* @param {Number} n
*/
backUp(n) {
backUp(n: number) {
let row = this.pos.line;
let column = this.pos.character;
column -= (n || 1);
@@ -117,28 +111,22 @@ export class DocumentStreamReader {
/**
* Get the string between the start of the current token and the
* current stream position.
* @returns {String}
*/
current() {
current(): string {
return this.substring(this.start, this.pos);
}
/**
* Returns contents for given range
* @param {Position} from
* @param {Position} to
* @return {String}
*/
substring(from, to) {
substring(from: Position, to: Position): string {
return this.document.getText(new Range(from, to));
}
/**
* Creates error object with current stream state
* @param {String} message
* @return {Error}
*/
error(message) {
error(message: string): Error {
const err = new Error(`${message} at row ${this.pos.line}, column ${this.pos.character}`);
return err;
@@ -146,10 +134,8 @@ export class DocumentStreamReader {
/**
* Returns line length of given row, including line ending
* @param {Number} row
* @return {Number}
*/
_lineLength(row) {
_lineLength(row: number): number {
if (row === this.document.lineCount - 1) {
return this.document.lineAt(row).text.length;
}
@@ -161,10 +147,8 @@ export class DocumentStreamReader {
* and returns a boolean. If the next character in the stream 'matches'
* the given argument, it is consumed and returned.
* Otherwise, `false` is returned.
* @param {Number|Function} match
* @returns {Boolean}
*/
eat(match) {
eat(match: number | Function): boolean {
const ch = this.peek();
const ok = typeof match === 'function' ? match(ch) : ch === match;
@@ -178,10 +162,8 @@ export class DocumentStreamReader {
/**
* Repeatedly calls <code>eat</code> with the given argument, until it
* fails. Returns <code>true</code> if any characters were eaten.
* @param {Object} match
* @returns {Boolean}
*/
eatWhile(match) {
eatWhile(match: number | Function): boolean {
const start = this.pos;
while (!this.eof() && this.eat(match)) { }
return !this.pos.isEqual(start);
@@ -12,7 +12,7 @@ const allowedMimeTypesInScriptTag = ['text/html', 'text/plain', 'text/x-template
export class DefaultCompletionItemProvider implements vscode.CompletionItemProvider {
public provideCompletionItems(document: vscode.TextDocument, position: vscode.Position, token: vscode.CancellationToken): Thenable<vscode.CompletionList> {
public provideCompletionItems(document: vscode.TextDocument, position: vscode.Position, token: vscode.CancellationToken): Thenable<vscode.CompletionList | undefined> | undefined {
const mappedLanguages = getMappingForIncludedLanguages();
const emmetConfig = vscode.workspace.getConfiguration('emmet');
@@ -45,8 +45,8 @@ export class DefaultCompletionItemProvider implements vscode.CompletionItemProvi
if (abbreviation.startsWith('this.')) {
noiseCheckPromise = Promise.resolve(true);
} else {
noiseCheckPromise = vscode.commands.executeCommand('vscode.executeDocumentSymbolProvider', document.uri).then((symbols: vscode.SymbolInformation[]) => {
return symbols.find(x => abbreviation === x.name || (abbreviation.startsWith(x.name + '.') && !/>|\*|\+/.test(abbreviation)));
noiseCheckPromise = vscode.commands.executeCommand<vscode.SymbolInformation[]>('vscode.executeDocumentSymbolProvider', document.uri).then((symbols: vscode.SymbolInformation[] | undefined) => {
return symbols && symbols.find(x => abbreviation === x.name || (abbreviation.startsWith(x.name + '.') && !/>|\*|\+/.test(abbreviation)));
});
}
}
@@ -88,7 +88,7 @@ export class DefaultCompletionItemProvider implements vscode.CompletionItemProvi
* @param document vscode.Textdocument
* @param position vscode.Position position of the abbreviation that needs to be expanded
*/
private syntaxHelper(syntax: string, document: vscode.TextDocument, position: vscode.Position): string {
private syntaxHelper(syntax: string | undefined, document: vscode.TextDocument, position: vscode.Position): string | undefined {
if (!syntax) {
return syntax;
}
+13 -11
View File
@@ -7,40 +7,42 @@ import * as vscode from 'vscode';
import { validate } from './util';
export function fetchEditPoint(direction: string): void {
let editor = vscode.window.activeTextEditor;
if (!validate()) {
if (!validate() || !vscode.window.activeTextEditor) {
return;
}
const editor = vscode.window.activeTextEditor;
let newSelections: vscode.Selection[] = [];
editor.selections.forEach(selection => {
let updatedSelection = direction === 'next' ? nextEditPoint(selection.anchor, editor) : prevEditPoint(selection.anchor, editor);
newSelections.push(updatedSelection ? updatedSelection : selection);
let updatedSelection = direction === 'next' ? nextEditPoint(selection, editor) : prevEditPoint(selection, editor);
newSelections.push(updatedSelection);
});
editor.selections = newSelections;
editor.revealRange(editor.selections[editor.selections.length - 1]);
}
function nextEditPoint(position: vscode.Position, editor: vscode.TextEditor): vscode.Selection {
for (let lineNum = position.line; lineNum < editor.document.lineCount; lineNum++) {
let updatedSelection = findEditPoint(lineNum, editor, position, 'next');
function nextEditPoint(selection: vscode.Selection, editor: vscode.TextEditor): vscode.Selection {
for (let lineNum = selection.anchor.line; lineNum < editor.document.lineCount; lineNum++) {
let updatedSelection = findEditPoint(lineNum, editor, selection.anchor, 'next');
if (updatedSelection) {
return updatedSelection;
}
}
return selection;
}
function prevEditPoint(position: vscode.Position, editor: vscode.TextEditor): vscode.Selection {
for (let lineNum = position.line; lineNum >= 0; lineNum--) {
let updatedSelection = findEditPoint(lineNum, editor, position, 'prev');
function prevEditPoint(selection: vscode.Selection, editor: vscode.TextEditor): vscode.Selection {
for (let lineNum = selection.anchor.line; lineNum >= 0; lineNum--) {
let updatedSelection = findEditPoint(lineNum, editor, selection.anchor, 'prev');
if (updatedSelection) {
return updatedSelection;
}
}
return selection;
}
function findEditPoint(lineNum: number, editor: vscode.TextEditor, position: vscode.Position, direction: string): vscode.Selection {
function findEditPoint(lineNum: number, editor: vscode.TextEditor, position: vscode.Position, direction: string): vscode.Selection | undefined {
let line = editor.document.lineAt(lineNum);
let lineContent = line.text;
@@ -10,11 +10,11 @@ import evaluate from '@emmetio/math-expression';
import { DocumentStreamReader } from './bufferStream';
export function evaluateMathExpression() {
let editor = vscode.window.activeTextEditor;
if (!editor) {
if (!vscode.window.activeTextEditor) {
vscode.window.showInformationMessage('No editor is active');
return;
}
const editor = vscode.window.activeTextEditor;
const stream = new DocumentStreamReader(editor.document);
editor.edit(editBuilder => {
editor.selections.forEach(selection => {
+7 -16
View File
@@ -19,20 +19,16 @@ const reUrl = /^https?:/;
/**
* Get size of given image file. Supports files from local filesystem,
* as well as URLs
* @param {String} file Path to local file or URL
* @return {Promise}
*/
export function getImageSize(file) {
export function getImageSize(file: string) {
file = file.replace(/^file:\/\//, '');
return reUrl.test(file) ? getImageSizeFromURL(file) : getImageSizeFromFile(file);
}
/**
* Get image size from file on local file system
* @param {String} file
* @return {Promise}
*/
function getImageSizeFromFile(file) {
function getImageSizeFromFile(file: string) {
return new Promise((resolve, reject) => {
const isDataUrl = file.match(/^data:.+?;base64,/);
@@ -46,7 +42,7 @@ function getImageSizeFromFile(file) {
}
}
sizeOf(file, (err, size) => {
sizeOf(file, (err: any, size: any) => {
if (err) {
reject(err);
} else {
@@ -58,15 +54,13 @@ function getImageSizeFromFile(file) {
/**
* Get image size from given remove URL
* @param {String} url
* @return {Promise}
*/
function getImageSizeFromURL(url) {
function getImageSizeFromURL(urlStr: string) {
return new Promise((resolve, reject) => {
url = parseUrl(url);
const url = parseUrl(urlStr);
const getTransport = url.protocol === 'https:' ? https.get : http.get;
getTransport(url, resp => {
getTransport(url as any, resp => {
const chunks = [];
let bufSize = 0;
@@ -102,11 +96,8 @@ function getImageSizeFromURL(url) {
/**
* Returns size object for given file name. If file name contains `@Nx` token,
* the final dimentions will be downscaled by N
* @param {String} fileName
* @param {Object} size
* @return {Object}
*/
function sizeForFileName(fileName, size) {
function sizeForFileName(fileName: string, size: any) {
const m = fileName.match(/@(\d+)x\./);
const scale = m ? +m[1] : 1;
+14 -9
View File
@@ -7,9 +7,9 @@ import * as vscode from 'vscode';
import { getDeepestNode, findNextWord, findPrevWord, getNode } from './util';
import { HtmlNode } from 'EmmetNode';
export function nextItemHTML(selectionStart: vscode.Position, selectionEnd: vscode.Position, editor: vscode.TextEditor, rootNode: HtmlNode): vscode.Selection {
export function nextItemHTML(selectionStart: vscode.Position, selectionEnd: vscode.Position, editor: vscode.TextEditor, rootNode: HtmlNode): vscode.Selection | undefined {
let currentNode = <HtmlNode>getNode(rootNode, selectionEnd);
let nextNode: HtmlNode;
let nextNode: HtmlNode | undefined = undefined;
if (!currentNode) {
return;
@@ -50,12 +50,12 @@ export function nextItemHTML(selectionStart: vscode.Position, selectionEnd: vsco
}
}
return getSelectionFromNode(nextNode, editor.document);
return nextNode && getSelectionFromNode(nextNode, editor.document);
}
export function prevItemHTML(selectionStart: vscode.Position, selectionEnd: vscode.Position, editor: vscode.TextEditor, rootNode: HtmlNode): vscode.Selection {
export function prevItemHTML(selectionStart: vscode.Position, selectionEnd: vscode.Position, editor: vscode.TextEditor, rootNode: HtmlNode): vscode.Selection | undefined {
let currentNode = <HtmlNode>getNode(rootNode, selectionStart);
let prevNode: HtmlNode;
let prevNode: HtmlNode | undefined = undefined;
if (!currentNode) {
return;
@@ -68,7 +68,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: HtmlNode;
let oldOption: HtmlNode | undefined = undefined;
while (prevNode.nextSibling && selectionStart.isAfterOrEqual(prevNode.nextSibling.end)) {
if (prevNode && prevNode.type !== 'comment') {
oldOption = prevNode;
@@ -94,20 +94,25 @@ export function prevItemHTML(selectionStart: vscode.Position, selectionEnd: vsco
}
if (!prevNode) {
return undefined;
}
let attrSelection = getPrevAttribute(selectionStart, selectionEnd, editor.document, prevNode);
return attrSelection ? attrSelection : getSelectionFromNode(prevNode, editor.document);
}
function getSelectionFromNode(node: HtmlNode, document: vscode.TextDocument): vscode.Selection {
function getSelectionFromNode(node: HtmlNode, document: vscode.TextDocument): vscode.Selection | undefined {
if (node && node.open) {
let selectionStart = (<vscode.Position>node.open.start).translate(0, 1);
let selectionEnd = selectionStart.translate(0, node.name.length);
return new vscode.Selection(selectionStart, selectionEnd);
}
return undefined;
}
function getNextAttribute(selectionStart: vscode.Position, selectionEnd: vscode.Position, document: vscode.TextDocument, node: HtmlNode): vscode.Selection {
function getNextAttribute(selectionStart: vscode.Position, selectionEnd: vscode.Position, document: vscode.TextDocument, node: HtmlNode): vscode.Selection | undefined {
if (!node.attributes || node.attributes.length === 0 || node.type === 'comment') {
return;
@@ -158,7 +163,7 @@ function getNextAttribute(selectionStart: vscode.Position, selectionEnd: vscode.
}
}
function getPrevAttribute(selectionStart: vscode.Position, selectionEnd: vscode.Position, document: vscode.TextDocument, node: HtmlNode): vscode.Selection {
function getPrevAttribute(selectionStart: vscode.Position, selectionEnd: vscode.Position, document: vscode.TextDocument, node: HtmlNode): vscode.Selection | undefined {
if (!node.attributes || node.attributes.length === 0 || node.type === 'comment') {
return;
+4 -4
View File
@@ -7,7 +7,7 @@ import * as vscode from 'vscode';
import { getDeepestNode, findNextWord, findPrevWord, getNode } from './util';
import { Node, CssNode, Rule, Property } from 'EmmetNode';
export function nextItemStylesheet(startOffset: vscode.Position, endOffset: vscode.Position, editor: vscode.TextEditor, rootNode: Node): vscode.Selection {
export function nextItemStylesheet(startOffset: vscode.Position, endOffset: vscode.Position, editor: vscode.TextEditor, rootNode: Node): vscode.Selection | undefined {
let currentNode = <CssNode>getNode(rootNode, endOffset, true);
if (!currentNode) {
currentNode = <CssNode>rootNode;
@@ -50,7 +50,7 @@ export function nextItemStylesheet(startOffset: vscode.Position, endOffset: vsco
}
export function prevItemStylesheet(startOffset: vscode.Position, endOffset: vscode.Position, editor: vscode.TextEditor, rootNode: CssNode): vscode.Selection {
export function prevItemStylesheet(startOffset: vscode.Position, endOffset: vscode.Position, editor: vscode.TextEditor, rootNode: CssNode): vscode.Selection | undefined {
let currentNode = <CssNode>getNode(rootNode, startOffset);
if (!currentNode) {
currentNode = rootNode;
@@ -88,7 +88,7 @@ export function prevItemStylesheet(startOffset: vscode.Position, endOffset: vsco
}
function getSelectionFromNode(node: Node, document: vscode.TextDocument): vscode.Selection {
function getSelectionFromNode(node: Node, document: vscode.TextDocument): vscode.Selection | undefined {
if (!node) {
return;
}
@@ -98,7 +98,7 @@ function getSelectionFromNode(node: Node, document: vscode.TextDocument): vscode
}
function getSelectionFromProperty(node: Node, document: vscode.TextDocument, selectionStart: vscode.Position, selectionEnd: vscode.Position, selectFullValue: boolean, direction: string): vscode.Selection {
function getSelectionFromProperty(node: Node, document: vscode.TextDocument, selectionStart: vscode.Position, selectionEnd: vscode.Position, selectFullValue: boolean, direction: string): vscode.Selection | undefined {
if (!node || node.type !== 'property') {
return;
}
+6 -10
View File
@@ -8,11 +8,11 @@ import { HtmlNode } from 'EmmetNode';
import { getNode, parseDocument, validate } from './util';
export function splitJoinTag() {
let editor = vscode.window.activeTextEditor;
if (!validate(false)) {
if (!validate(false) || !vscode.window.activeTextEditor) {
return;
}
const editor = vscode.window.activeTextEditor;
let rootNode = <HtmlNode>parseDocument(editor.document);
if (!rootNode) {
return;
@@ -20,23 +20,19 @@ export function splitJoinTag() {
return editor.edit(editBuilder => {
editor.selections.reverse().forEach(selection => {
let textEdit = getRangesToReplace(editor.document, selection, rootNode);
if (textEdit) {
let nodeToUpdate = <HtmlNode>getNode(rootNode, selection.start);
if (nodeToUpdate) {
let textEdit = getRangesToReplace(editor.document, nodeToUpdate);
editBuilder.replace(textEdit.range, textEdit.newText);
}
});
});
}
function getRangesToReplace(document: vscode.TextDocument, selection: vscode.Selection, rootNode: HtmlNode): vscode.TextEdit {
let nodeToUpdate = <HtmlNode>getNode(rootNode, selection.start);
function getRangesToReplace(document: vscode.TextDocument, nodeToUpdate: HtmlNode): vscode.TextEdit {
let rangeToReplace: vscode.Range;
let textToReplaceWith: string;
if (!nodeToUpdate) {
return;
}
if (!nodeToUpdate.close) {
// Split Tag
let nodeText = document.getText(new vscode.Range(nodeToUpdate.start, nodeToUpdate.end));
@@ -3,6 +3,7 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import 'mocha';
import * as assert from 'assert';
import { Selection, workspace } from 'vscode';
import { withRandomFileEditor, closeAllEditors } from './testUtils';
@@ -221,13 +222,13 @@ m10
.hoo {
background:
}
}
}
`
return withRandomFileEditor(scssContentsNoExpand, 'scss', (editor, doc) => {
editor.selections = [
new Selection(1, 3, 1, 3), // outside rule
new Selection(5, 15, 5, 15) // in the value part of property value
new Selection(5, 15, 5, 15) // in the value part of property value
];
return expandEmmetAbbreviation(null).then(() => {
assert.equal(editor.document.getText(), scssContentsNoExpand);
@@ -344,7 +345,7 @@ suite('Tests for Wrap with Abbreviations', () => {
suite('Tests for jsx, xml and xsl', () => {
teardown(closeAllEditors);
test('Expand abbreviation with className instead of class in jsx', () => {
return withRandomFileEditor('ul.nav', 'javascriptreact', (editor, doc) => {
editor.selection = new Selection(0, 6, 0, 6);
@@ -3,6 +3,7 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import 'mocha';
import * as assert from 'assert';
import { Selection } from 'vscode';
import { withRandomFileEditor, closeAllEditors } from './testUtils';
@@ -3,6 +3,7 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import 'mocha';
import * as assert from 'assert';
import { Selection } from 'vscode';
import { withRandomFileEditor, closeAllEditors } from './testUtils';
@@ -3,8 +3,9 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import 'mocha';
import * as assert from 'assert';
import { Selection, commands } from 'vscode';
import { Selection } from 'vscode';
import { withRandomFileEditor, closeAllEditors } from './testUtils';
import { reflectCssValue } from '../reflectCssValue';
@@ -3,6 +3,7 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import 'mocha';
import * as assert from 'assert';
import { Selection } from 'vscode';
import { withRandomFileEditor, closeAllEditors } from './testUtils';
@@ -3,6 +3,7 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import 'mocha';
import * as assert from 'assert';
import { Selection } from 'vscode';
import { withRandomFileEditor, closeAllEditors } from './testUtils';
@@ -3,15 +3,14 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import 'mocha';
import * as assert from 'assert';
import { Selection } from 'vscode';
import { withRandomFileEditor, closeAllEditors } from './testUtils';
import { updateImageSize } from '../updateImageSize';
import * as path from 'path';
suite('Tests for Emmet actions on html tags', () => {
teardown(closeAllEditors);
const filePath = path.join(__dirname, '../../../../resources/linux/code.png');
test('update image css with multiple cursors in css file', () => {
const cssContents = `
+5 -7
View File
@@ -4,7 +4,7 @@
*--------------------------------------------------------------------------------------------*/
import * as vscode from 'vscode';
import { getNodesInBetween, getNode, parseDocument, sameNodes, isStyleSheet } from './util';
import { getNodesInBetween, getNode, parseDocument, sameNodes, isStyleSheet, validate } from './util';
import { Node, Stylesheet, Rule, HtmlNode } from 'EmmetNode';
import parseStylesheet from '@emmetio/css-parser';
import { DocumentStreamReader } from './bufferStream';
@@ -14,14 +14,12 @@ const endCommentStylesheet = '*/';
const startCommentHTML = '<!--';
const endCommentHTML = '-->';
export function toggleComment(): Thenable<boolean> {
let editor = vscode.window.activeTextEditor;
if (!editor) {
vscode.window.showInformationMessage('No editor is active');
export function toggleComment(): Thenable<boolean> | undefined {
if (!validate() || !vscode.window.activeTextEditor) {
return;
}
let toggleCommentInternal;
const editor = vscode.window.activeTextEditor;
let toggleCommentInternal: (document: vscode.TextDocument, selection: vscode.Selection, rootNode: Node) => vscode.TextEdit[];
if (isStyleSheet(editor.document.languageId)) {
toggleCommentInternal = toggleCommentStylesheet;
-1
View File
@@ -5,4 +5,3 @@
/// <reference path='../../../../src/vs/vscode.d.ts'/>
/// <reference types='@types/node'/>
/// <reference types='@types/mocha'/>
+17 -38
View File
@@ -10,7 +10,7 @@
import { TextEditor, Range, Position, window, TextEdit } from 'vscode';
import * as path from 'path';
import { getImageSize } from './imageSizeHelper';
import { parseDocument, getNode, iterateCSSToken, getCssPropertyFromRule, isStyleSheet } from './util';
import { parseDocument, getNode, iterateCSSToken, getCssPropertyFromRule, isStyleSheet, validate } from './util';
import { HtmlNode, CssToken, HtmlToken, Attribute, Property } from 'EmmetNode';
import { locateFile } from './locateFile';
import parseStylesheet from '@emmetio/css-parser';
@@ -20,11 +20,10 @@ import { DocumentStreamReader } from './bufferStream';
* Updates size of context image in given editor
*/
export function updateImageSize() {
let editor = window.activeTextEditor;
if (!editor) {
window.showInformationMessage('No editor is active.');
if (!validate() || !window.activeTextEditor) {
return;
}
const editor = window.activeTextEditor;
let allUpdatesPromise = editor.selections.reverse().map(selection => {
let position = selection.isReversed ? selection.active : selection.anchor;
@@ -49,7 +48,7 @@ export function updateImageSize() {
/**
* Updates image size of context tag of HTML model
*/
function updateImageSizeHTML(editor: TextEditor, position: Position): Promise<TextEdit[]> {
function updateImageSizeHTML(editor: TextEditor, position: Position): Promise<TextEdit[] | undefined> {
const src = getImageSrcHTML(getImageHTMLNode(editor, position));
if (!src) {
@@ -70,7 +69,7 @@ function updateImageSizeHTML(editor: TextEditor, position: Position): Promise<Te
}
function updateImageSizeStyleTag(editor: TextEditor, position: Position): Promise<TextEdit[]> {
let getPropertyInsiderStyleTag = (editor) => {
const getPropertyInsiderStyleTag = (editor: TextEditor): Property | undefined => {
const rootNode = parseDocument(editor.document);
const currentNode = <HtmlNode>getNode(rootNode, position);
if (currentNode && currentNode.name === 'style'
@@ -79,7 +78,7 @@ function updateImageSizeStyleTag(editor: TextEditor, position: Position): Promis
let buffer = new DocumentStreamReader(editor.document, currentNode.open.end, new Range(currentNode.open.end, currentNode.close.start));
let rootNode = parseStylesheet(buffer);
const node = getNode(rootNode, position);
return (node && node.type === 'property') ? <Property>node : null;
return (node && node.type === 'property') ? <Property>node : undefined;
}
};
@@ -93,7 +92,7 @@ function updateImageSizeCSSFile(editor: TextEditor, position: Position): Promise
/**
* Updates image size of context rule of stylesheet model
*/
function updateImageSizeCSS(editor: TextEditor, position: Position, fetchNode: (editor, position) => Property): Promise<TextEdit[]> {
function updateImageSizeCSS(editor: TextEditor, position: Position, fetchNode: (editor: TextEditor, position: Position) => Property | undefined): Promise<TextEdit[]> {
const src = getImageSrcCSS(fetchNode(editor, position), position);
@@ -141,10 +140,8 @@ function getImageCSSNode(editor: TextEditor, position: Position): Property {
/**
* Returns image source from given <img> node
* @param {HtmlNode} node
* @return {string}
*/
function getImageSrcHTML(node: HtmlNode): string {
function getImageSrcHTML(node: HtmlNode): string | undefined {
const srcAttr = getAttribute(node, 'src');
if (!srcAttr) {
return;
@@ -155,11 +152,8 @@ function getImageSrcHTML(node: HtmlNode): string {
/**
* Returns image source from given `url()` token
* @param {Property} node
* @param {Position}
* @return {string}
*/
function getImageSrcCSS(node: Property, position: Position): string {
function getImageSrcCSS(node: Property | undefined, position: Position): string | undefined {
if (!node) {
return;
}
@@ -213,10 +207,6 @@ function updateHTMLTag(editor: TextEditor, node: HtmlNode, width: number, height
/**
* Updates size of given CSS rule
* @param {TextEditor} editor
* @param {Property} srcProp
* @param {number} width
* @param {number} height
*/
function updateCSSNode(editor: TextEditor, srcProp: Property, width: number, height: number): TextEdit[] {
const rule = srcProp.parent;
@@ -252,36 +242,28 @@ function updateCSSNode(editor: TextEditor, srcProp: Property, width: number, hei
/**
* Returns attribute object with `attrName` name from given HTML node
* @param {Node} node
* @param {String} attrName
* @return {Object}
*/
function getAttribute(node, attrName): Attribute {
function getAttribute(node: HtmlNode, attrName: string): Attribute {
attrName = attrName.toLowerCase();
return node && node.open.attributes.find(attr => attr.name.value.toLowerCase() === attrName);
return node && (node.open as any).attributes.find(attr => attr.name.value.toLowerCase() === attrName);
}
/**
* Returns quote character, used for value of given attribute. May return empty
* string if attribute wasnt quoted
* @param {TextEditor} editor
* @param {Object} attr
* @return {String}
*/
function getAttributeQuote(editor, attr) {
function getAttributeQuote(editor: TextEditor, attr: any): string {
const range = new Range(attr.value ? attr.value.end : attr.end, attr.end);
return range.isEmpty ? '' : editor.document.getText(range);
}
/**
* Finds 'url' token for given `pos` point in given CSS property `node`
* @param {Node} node
* @param {Position} pos
* @return {Token}
*/
function findUrlToken(node, pos: Position) {
for (let i = 0, il = node.parsedValue.length, url; i < il; i++) {
iterateCSSToken(node.parsedValue[i], (token: CssToken) => {
function findUrlToken(node: Property, pos: Position): CssToken | undefined {
for (let i = 0, il = (node as any).parsedValue.length, url; i < il; i++) {
iterateCSSToken((node as any).parsedValue[i], (token: CssToken) => {
if (token.type === 'url' && token.start.isBeforeOrEqual(pos) && token.end.isAfterOrEqual(pos)) {
url = token;
return false;
@@ -296,11 +278,8 @@ function findUrlToken(node, pos: Position) {
/**
* Returns a string that is used to delimit properties in current nodes rule
* @param {TextEditor} editor
* @param {Property} node
* @return {String}
*/
function getPropertyDelimitor(editor: TextEditor, node: Property) {
function getPropertyDelimitor(editor: TextEditor, node: Property): string {
let anchor;
if (anchor = (node.previousSibling || node.parent.contentStartToken)) {
return editor.document.getText(new Range(anchor.end, node.start));
+4 -4
View File
@@ -7,17 +7,17 @@ import * as vscode from 'vscode';
import { HtmlNode } from 'EmmetNode';
import { getNode, parseDocument, validate } from './util';
export function updateTag(tagName: string): Thenable<boolean> {
let editor = vscode.window.activeTextEditor;
if (!validate(false)) {
export function updateTag(tagName: string): Thenable<boolean> | undefined {
if (!validate(false) || !vscode.window.activeTextEditor) {
return;
}
let editor = vscode.window.activeTextEditor;
let rootNode = <HtmlNode>parseDocument(editor.document);
if (!rootNode) {
return;
}
let rangesToUpdate = [];
let rangesToUpdate: vscode.Range[] = [];
editor.selections.reverse().forEach(selection => {
rangesToUpdate = rangesToUpdate.concat(getRangesToUpdate(editor, selection, rootNode));
});
+25 -36
View File
@@ -6,12 +6,12 @@
import * as vscode from 'vscode';
import parse from '@emmetio/html-matcher';
import parseStylesheet from '@emmetio/css-parser';
import { Node, HtmlNode, CssToken, Property } from 'EmmetNode';
import { Node, HtmlNode, CssToken, Property, Rule } from 'EmmetNode';
import { DocumentStreamReader } from './bufferStream';
import * as path from 'path';
let _emmetHelper;
let _currentExtensionsPath = undefined;
let _emmetHelper: any;
let _currentExtensionsPath: string | undefined = undefined;
export function getEmmetHelper() {
if (!_emmetHelper) {
@@ -27,15 +27,15 @@ export function resolveUpdateExtensionsPath() {
}
let extensionsPath = vscode.workspace.getConfiguration('emmet')['extensionsPath'];
if (extensionsPath && !path.isAbsolute(extensionsPath)) {
extensionsPath = path.join(vscode.workspace.rootPath, extensionsPath);
extensionsPath = path.join(vscode.workspace.rootPath || '', extensionsPath);
}
if (_currentExtensionsPath !== extensionsPath) {
_currentExtensionsPath = extensionsPath;
_emmetHelper.updateExtensionsPath(_currentExtensionsPath).then(null, err => vscode.window.showErrorMessage(err));
_emmetHelper.updateExtensionsPath(_currentExtensionsPath).then(null, (err: string) => vscode.window.showErrorMessage(err));
}
}
export const LANGUAGE_MODES: Object = {
export const LANGUAGE_MODES: any = {
'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'],
@@ -62,7 +62,7 @@ export const MAPPED_MODES: Object = {
'php': 'html'
};
export function isStyleSheet(syntax): boolean {
export function isStyleSheet(syntax: string): boolean {
let stylesheetSyntaxes = ['css', 'scss', 'sass', 'less', 'stylus'];
return (stylesheetSyntaxes.indexOf(syntax) > -1);
}
@@ -80,7 +80,7 @@ export function validate(allowStylesheet: boolean = true): boolean {
}
export function getMappingForIncludedLanguages(): any {
let finalMappedModes = {};
const finalMappedModes = Object.create(null);
let includeLanguagesConfig = vscode.workspace.getConfiguration('emmet')['includeLanguages'];
let includeLanguages = Object.assign({}, MAPPED_MODES, includeLanguagesConfig ? includeLanguagesConfig : {});
Object.keys(includeLanguages).forEach(syntax => {
@@ -94,13 +94,13 @@ export function getMappingForIncludedLanguages(): any {
/**
* Get the corresponding emmet mode for given vscode language mode
* Eg: jsx for typescriptreact/javascriptreact or pug for jade
* If the language is not supported by emmet or has been exlcuded via `exlcudeLanguages` setting,
* If the language is not supported by emmet or has been exlcuded via `exlcudeLanguages` setting,
* then nothing is returned
*
* @param language
*
* @param language
* @param exlcudedLanguages Array of language ids that user has chosen to exlcude for emmet
*/
export function getEmmetMode(language: string, excludedLanguages: string[]): string {
export function getEmmetMode(language: string, excludedLanguages: string[]): string | undefined {
if (!language || excludedLanguages.indexOf(language) > -1) {
return;
}
@@ -120,34 +120,29 @@ export function getEmmetMode(language: string, excludedLanguages: string[]): str
/**
* Parses the given document using emmet parsing modules
* @param document
*/
export function parseDocument(document: vscode.TextDocument, showError: boolean = true): Node {
export function parseDocument(document: vscode.TextDocument, showError: boolean = true): Node | undefined {
let parseContent = isStyleSheet(document.languageId) ? parseStylesheet : parse;
let rootNode: Node;
try {
rootNode = parseContent(new DocumentStreamReader(document));
return parseContent(new DocumentStreamReader(document));
} catch (e) {
if (showError) {
vscode.window.showErrorMessage('Emmet: Failed to parse the file');
}
}
return rootNode;
return undefined;
}
/**
* Returns node corresponding to given position in the given root node
* @param root
* @param position
* @param includeNodeBoundary
*/
export function getNode(root: Node, position: vscode.Position, includeNodeBoundary: boolean = false) {
export function getNode(root: Node | undefined, position: vscode.Position, includeNodeBoundary: boolean = false) {
if (!root) {
return null;
}
let currentNode = root.firstChild;
let foundNode: Node = null;
let foundNode: Node | null = null;
while (currentNode) {
const nodeStart: vscode.Position = currentNode.start;
@@ -170,14 +165,14 @@ export function getNode(root: Node, position: vscode.Position, includeNodeBounda
* Returns inner range of an html node.
* @param currentNode
*/
export function getInnerRange(currentNode: HtmlNode): vscode.Range {
export function getInnerRange(currentNode: HtmlNode): vscode.Range | undefined {
if (!currentNode.close) {
return;
return undefined;
}
return new vscode.Range(currentNode.open.end, currentNode.close.start);
}
export function getDeepestNode(node: Node): 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;
}
@@ -186,6 +181,7 @@ export function getDeepestNode(node: Node): Node {
return getDeepestNode(node.children[i]);
}
}
return undefined;
}
export function findNextWord(propertyValue: string, pos: number): [number, number] {
@@ -342,10 +338,8 @@ export function getEmmetConfiguration(syntax: string) {
/**
* Itereates by each child, as well as nested child children, in their order
* and invokes `fn` for each. If `fn` function returns `false`, iteration stops
* @param {Token} token
* @param {Function} fn
*/
export function iterateCSSToken(token: CssToken, fn) {
export function iterateCSSToken(token: CssToken, fn: (x: any) => any) {
for (let i = 0, il = token.size; i < il; i++) {
if (fn(token.item(i)) === false || iterateCSSToken(token.item(i), fn) === false) {
return false;
@@ -355,21 +349,16 @@ export function iterateCSSToken(token: CssToken, fn) {
/**
* Returns `name` CSS property from given `rule`
* @param {Node} rule
* @param {String} name
* @return {Property}
*/
export function getCssPropertyFromRule(rule, name): Property {
return rule.children.find(node => node.type === 'property' && node.name === name);
export function getCssPropertyFromRule(rule: Rule, name: string): Property | undefined {
return rule.children.find(node => node.type === 'property' && node.name === name) as Property;
}
/**
* Returns css property under caret in given editor or `null` if such node cannot
* be found
* @param {TextEditor} editor
* @return {Property}
*/
export function getCssPropertyFromDocument(editor: vscode.TextEditor, position: vscode.Position): Property {
export function getCssPropertyFromDocument(editor: vscode.TextEditor, position: vscode.Position): Property | undefined {
const rootNode = parseDocument(editor.document);
const node = getNode(rootNode, position);
+2 -2
View File
@@ -5,8 +5,8 @@
"es2016"
],
"module": "commonjs",
"outDir": "./out"
"outDir": "./out",
"noUnusedLocals": true
},
"exclude": [
"node_modules",
@@ -54,6 +54,7 @@ export class ExtensionLinter {
private timer: NodeJS.Timer;
private markdownIt: MarkdownItType.MarkdownIt;
// @ts-ignore unused property
constructor(private context: ExtensionContext) {
this.disposables.push(
workspace.onDidOpenTextDocument(document => this.queue(document)),
@@ -227,7 +228,7 @@ export class ExtensionLinter {
}
this.diagnosticsCollection.set(document.uri, diagnostics);
};
}
}
private locateToken(text: string, begin: number, end: number, token: MarkdownItType.Token, content: string) {
@@ -5,6 +5,7 @@
"es2015"
],
"module": "commonjs",
"noUnusedLocals": true,
"outDir": "./out"
},
"include": [
-1
View File
@@ -6,7 +6,6 @@
'use strict';
import 'mocha';
import { GitStatusParser } from '../git';
import * as assert from 'assert';
+1 -1
View File
@@ -4,4 +4,4 @@
*--------------------------------------------------------------------------------------------*/
/// <reference path='../../../../src/vs/vscode.d.ts'/>
/// <reference path='../../../../src/vs/vscode.proposed.d.ts'/>
/// <reference path='../../../../src/vs/vscode.proposed.d.ts'/>
+1
View File
@@ -3,6 +3,7 @@
"target": "es5",
"module": "commonjs",
"outDir": "./out",
"noUnusedLocals": true,
"lib": [
"es5", "es2015.promise"
]
+1 -1
View File
@@ -68,4 +68,4 @@ export function getCSSMode(documentRegions: LanguageModelCache<HTMLDocumentRegio
cssStylesheets.dispose();
}
};
};
}
@@ -22,7 +22,7 @@ export interface HTMLDocumentRegions {
export var CSS_STYLE_RULE = '__';
interface EmbeddedRegion { languageId: string; start: number; end: number; attributeValue?: boolean; };
interface EmbeddedRegion { languageId: string; start: number; end: number; attributeValue?: boolean; }
export function getDocumentRegions(languageService: LanguageService, document: TextDocument): HTMLDocumentRegions {
@@ -73,7 +73,7 @@ export function format(languageModes: LanguageModes, document: TextDocument, for
embeddedEdits.push(edit);
}
}
};
}
if (embeddedEdits.length === 0) {
pushAll(result, htmlEdits);
+1 -1
View File
@@ -69,7 +69,7 @@ export function getHTMLMode(htmlLanguageService: HTMLLanguageService): LanguageM
htmlDocuments.dispose();
}
};
};
}
function merge(src: any, dst: any): any {
for (var key in src) {
@@ -164,7 +164,7 @@ export function getJavascriptMode(documentRegions: LanguageModelCache<HTMLDocume
ret.signatures.push(signature);
});
return ret;
};
}
return null;
},
findDocumentHighlight(document: TextDocument, position: Position): DocumentHighlight[] {
@@ -177,7 +177,7 @@ export function getJavascriptMode(documentRegions: LanguageModelCache<HTMLDocume
kind: <DocumentHighlightKind>(entry.isWriteAccess ? DocumentHighlightKind.Write : DocumentHighlightKind.Text)
};
});
};
}
return null;
},
findDocumentSymbols(document: TextDocument): SymbolInformation[] {
@@ -286,7 +286,7 @@ export function getJavascriptMode(documentRegions: LanguageModelCache<HTMLDocume
jsDocuments.dispose();
}
};
};
}
function convertRange(document: TextDocument, span: { start: number, length: number }): Range {
let startPosition = document.positionAt(span.start);
@@ -4,6 +4,7 @@
*--------------------------------------------------------------------------------------------*/
'use strict';
import 'mocha';
import * as assert from 'assert';
import * as embeddedSupport from '../modes/embeddedSupport';
import { TextDocument } from 'vscode-languageserver-types';
@@ -4,6 +4,7 @@
*--------------------------------------------------------------------------------------------*/
'use strict';
import 'mocha';
import * as path from 'path';
import * as fs from 'fs';
@@ -4,6 +4,7 @@
*--------------------------------------------------------------------------------------------*/
'use strict';
import 'mocha';
import * as assert from 'assert';
import { getJavascriptMode } from '../modes/javascriptMode';
import { TextDocument } from 'vscode-languageserver-types';
-1
View File
@@ -1 +0,0 @@
/// <reference types='@types/mocha'/>
@@ -15,6 +15,7 @@ export function applyEdits(document: TextDocument, edits: TextEdit[]): string {
}
return startDiff;
});
// @ts-ignore unused local
let lastOffset = text.length;
sortedEdits.forEach(e => {
let startOffset = document.offsetAt(e.range.start);
+1
View File
@@ -3,6 +3,7 @@
"target": "es5",
"module": "commonjs",
"outDir": "./out",
"noUnusedLocals": true,
"lib": [
"es5", "es2015.promise"
]
+1 -1
View File
@@ -95,7 +95,7 @@
},
{
"language": "javascriptreact",
"path": "./snippets/javascriptreact.json"
"path": "./snippets/javascript.json"
}
],
"jsonValidation": [
@@ -1,164 +0,0 @@
{
"define module": {
"prefix": "define",
"body": [
"define([",
"\t'require',",
"\t'${1:dependency}'",
"], function(require, ${2:factory}) {",
"\t'use strict';",
"\t$0",
"});"
],
"description": "define module"
},
"For Loop": {
"prefix": "for",
"body": [
"for (let ${1:index} = 0; ${1:index} < ${2:array}.length; ${1:index}++) {",
"\tconst ${3:element} = ${2:array}[${1:index}];",
"\t$0",
"}"
],
"description": "For Loop"
},
"For-Each Loop": {
"prefix": "foreach",
"body": [
"${1:array}.forEach(${2:element} => {",
"\t$0",
"});"
],
"description": "For-Each Loop"
},
"For-In Loop": {
"prefix": "forin",
"body": [
"for (const ${1:key} in ${2:object}) {",
"\tif (${2:object}.hasOwnProperty(${1:key})) {",
"\t\tconst ${3:element} = ${2:object}[${1:key}];",
"\t\t$0",
"\t}",
"}"
],
"description": "For-In Loop"
},
"For-Of Loop": {
"prefix": "forof",
"body": [
"for (const ${1:iterator} of ${2:object}) {",
"\t$0",
"}"
],
"description": "For-Of Loop"
},
"Function Statement": {
"prefix": "function",
"body": [
"function ${1:name}(${2:params}) {",
"\t$0",
"}"
],
"description": "Function Statement"
},
"If Statement": {
"prefix": "if",
"body": [
"if (${1:condition}) {",
"\t$0",
"}"
],
"description": "If Statement"
},
"If-Else Statement": {
"prefix": "ifelse",
"body": [
"if (${1:condition}) {",
"\t$0",
"} else {",
"\t",
"}"
],
"description": "If-Else Statement"
},
"New Statement": {
"prefix": "new",
"body": [
"const ${1:name} = new ${2:type}(${3:arguments});$0"
],
"description": "New Statement"
},
"Switch Statement": {
"prefix": "switch",
"body": [
"switch (${1:key}) {",
"\tcase ${2:value}:",
"\t\t$0",
"\t\tbreak;",
"",
"\tdefault:",
"\t\tbreak;",
"}"
],
"description": "Switch Statement"
},
"While Statement": {
"prefix": "while",
"body": [
"while (${1:condition}) {",
"\t$0",
"}"
],
"description": "While Statement"
},
"Do-While Statement": {
"prefix": "dowhile",
"body": [
"do {",
"\t$0",
"} while (${1:condition});"
],
"description": "Do-While Statement"
},
"Try-Catch Statement": {
"prefix": "trycatch",
"body": [
"try {",
"\t$0",
"} catch (${1:error}) {",
"\t",
"}"
],
"description": "Try-Catch Statement"
},
"Set Timeout Function": {
"prefix": "settimeout",
"body": [
"setTimeout(() => {",
"\t$0",
"}, ${1:timeout});"
],
"description": "Set Timeout Function"
},
"Import external module.": {
"prefix": "import statement",
"body": [
"import { $0 } from \"${1:module}\";"
],
"description": "Import external module."
},
"Region Start": {
"prefix": "#region",
"body": [
"//#region $0"
],
"description": "Folding Region Start"
},
"Region End": {
"prefix": "#endregion",
"body": [
"//#endregion"
],
"description": "Folding Region End"
}
}
@@ -30,8 +30,8 @@ export class BowerJSONContribution implements IJSONContribution {
return [{ language: 'json', pattern: '**/bower.json' }, { language: 'json', pattern: '**/.bower.json' }];
}
public collectDefaultSuggestions(resource: string, collector: ISuggestionsCollector): Thenable<any> {
let defaultValue = {
public collectDefaultSuggestions(_resource: string, collector: ISuggestionsCollector): Thenable<any> {
const defaultValue = {
'name': '${1:name}',
'description': '${2:description}',
'authors': ['${3:author}'],
@@ -39,37 +39,37 @@ export class BowerJSONContribution implements IJSONContribution {
'main': '${5:pathToMain}',
'dependencies': {}
};
let proposal = new CompletionItem(localize('json.bower.default', 'Default bower.json'));
const proposal = new CompletionItem(localize('json.bower.default', 'Default bower.json'));
proposal.kind = CompletionItemKind.Class;
proposal.insertText = new SnippetString(JSON.stringify(defaultValue, null, '\t'));
collector.add(proposal);
return Promise.resolve(null);
}
public collectPropertySuggestions(resource: string, location: Location, currentWord: string, addValue: boolean, isLast: boolean, collector: ISuggestionsCollector): Thenable<any> | null {
public collectPropertySuggestions(_resource: string, location: Location, currentWord: string, addValue: boolean, isLast: boolean, collector: ISuggestionsCollector): Thenable<any> | null {
if ((location.matches(['dependencies']) || location.matches(['devDependencies']))) {
if (currentWord.length > 0) {
let queryUrl = 'https://bower.herokuapp.com/packages/search/' + encodeURIComponent(currentWord);
const queryUrl = 'https://bower.herokuapp.com/packages/search/' + encodeURIComponent(currentWord);
return this.xhr({
url: queryUrl
}).then((success) => {
if (success.status === 200) {
try {
let obj = JSON.parse(success.responseText);
const obj = JSON.parse(success.responseText);
if (Array.isArray(obj)) {
let results = <{ name: string; description: string; }[]>obj;
const results = <{ name: string; description: string; }[]>obj;
for (let i = 0; i < results.length; i++) {
let name = results[i].name;
let description = results[i].description || '';
let insertText = new SnippetString().appendText(JSON.stringify(name));
const name = results[i].name;
const description = results[i].description || '';
const insertText = new SnippetString().appendText(JSON.stringify(name));
if (addValue) {
insertText.appendText(': ').appendPlaceholder('latest');
if (!isLast) {
insertText.appendText(',');
}
}
let proposal = new CompletionItem(name);
const proposal = new CompletionItem(name);
proposal.kind = CompletionItemKind.Property;
proposal.insertText = insertText;
proposal.filterText = JSON.stringify(name);
@@ -85,13 +85,14 @@ export class BowerJSONContribution implements IJSONContribution {
collector.error(localize('json.bower.error.repoaccess', 'Request to the bower repository failed: {0}', success.responseText));
return 0;
}
return undefined;
}, (error) => {
collector.error(localize('json.bower.error.repoaccess', 'Request to the bower repository failed: {0}', error.responseText));
return 0;
});
} else {
this.topRanked.forEach((name) => {
let insertText = new SnippetString().appendText(JSON.stringify(name));
const insertText = new SnippetString().appendText(JSON.stringify(name));
if (addValue) {
insertText.appendText(': ').appendPlaceholder('latest');
if (!isLast) {
@@ -99,7 +100,7 @@ export class BowerJSONContribution implements IJSONContribution {
}
}
let proposal = new CompletionItem(name);
const proposal = new CompletionItem(name);
proposal.kind = CompletionItemKind.Property;
proposal.insertText = insertText;
proposal.filterText = JSON.stringify(name);
@@ -113,10 +114,10 @@ export class BowerJSONContribution implements IJSONContribution {
return null;
}
public collectValueSuggestions(resource: string, location: Location, collector: ISuggestionsCollector): Thenable<any> {
public collectValueSuggestions(_resource: string, location: Location, collector: ISuggestionsCollector): Thenable<any> {
if ((location.matches(['dependencies', '*']) || location.matches(['devDependencies', '*']))) {
// not implemented. Could be do done calling the bower command. Waiting for web API: https://github.com/bower/registry/issues/26
let proposal = new CompletionItem(localize('json.bower.latest.version', 'latest'));
const proposal = new CompletionItem(localize('json.bower.latest.version', 'latest'));
proposal.insertText = new SnippetString('"${1:latest}"');
proposal.filterText = '""';
proposal.kind = CompletionItemKind.Value;
@@ -135,18 +136,18 @@ export class BowerJSONContribution implements IJSONContribution {
}
return null;
});
};
}
return null;
}
private getInfo(pack: string): Thenable<string | undefined> {
let queryUrl = 'https://bower.herokuapp.com/packages/' + encodeURIComponent(pack);
const queryUrl = 'https://bower.herokuapp.com/packages/' + encodeURIComponent(pack);
return this.xhr({
url: queryUrl
}).then((success) => {
try {
let obj = JSON.parse(success.responseText);
const obj = JSON.parse(success.responseText);
if (obj && obj.url) {
let url: string = obj.url;
if (url.indexOf('git://') === 0) {
@@ -161,14 +162,14 @@ export class BowerJSONContribution implements IJSONContribution {
// ignore
}
return void 0;
}, (error) => {
}, () => {
return void 0;
});
}
public getInfoContribution(resource: string, location: Location): Thenable<MarkedString[] | null> | null {
public getInfoContribution(_resource: string, location: Location): Thenable<MarkedString[] | null> | null {
if ((location.matches(['dependencies', '*']) || location.matches(['devDependencies', '*']))) {
let pack = location.path[location.path.length - 1];
const pack = location.path[location.path.length - 1];
if (typeof pack === 'string') {
return this.getInfo(pack).then(documentation => {
if (documentation) {
@@ -32,10 +32,10 @@ export interface IJSONContribution {
}
export function addJSONProviders(xhr: XHRRequest): Disposable {
let contributions = [new PackageJSONContribution(xhr), new BowerJSONContribution(xhr)];
let subscriptions: Disposable[] = [];
const contributions = [new PackageJSONContribution(xhr), new BowerJSONContribution(xhr)];
const subscriptions: Disposable[] = [];
contributions.forEach(contribution => {
let selector = contribution.getDocumentSelector();
const selector = contribution.getDocumentSelector();
subscriptions.push(languages.registerCompletionItemProvider(selector, new JSONCompletionItemProvider(contribution), '"', ':'));
subscriptions.push(languages.registerHoverProvider(selector, new JSONHoverProvider(contribution)));
});
@@ -47,20 +47,20 @@ export class JSONHoverProvider implements HoverProvider {
constructor(private jsonContribution: IJSONContribution) {
}
public provideHover(document: TextDocument, position: Position, token: CancellationToken): Thenable<Hover> | null {
let fileName = basename(document.fileName);
let offset = document.offsetAt(position);
let location = getLocation(document.getText(), offset);
public provideHover(document: TextDocument, position: Position, _token: CancellationToken): Thenable<Hover> | null {
const fileName = basename(document.fileName);
const offset = document.offsetAt(position);
const location = getLocation(document.getText(), offset);
if (!location.previousNode) {
return null;
}
const node = location.previousNode;
if (node && node.offset <= offset && offset <= node.offset + node.length) {
let promise = this.jsonContribution.getInfoContribution(fileName, location);
const promise = this.jsonContribution.getInfoContribution(fileName, location);
if (promise) {
return promise.then(htmlContent => {
let range = new Range(document.positionAt(node.offset), document.positionAt(node.offset + node.length));
let result: Hover = {
const range = new Range(document.positionAt(node.offset), document.positionAt(node.offset + node.length));
const result: Hover = {
contents: htmlContent || [],
range: range
};
@@ -77,9 +77,9 @@ export class JSONCompletionItemProvider implements CompletionItemProvider {
constructor(private jsonContribution: IJSONContribution) {
}
public resolveCompletionItem(item: CompletionItem, token: CancellationToken): Thenable<CompletionItem | null> {
public resolveCompletionItem(item: CompletionItem, _token: CancellationToken): Thenable<CompletionItem | null> {
if (this.jsonContribution.resolveSuggestion) {
let resolver = this.jsonContribution.resolveSuggestion(item);
const resolver = this.jsonContribution.resolveSuggestion(item);
if (resolver) {
return resolver;
}
@@ -87,28 +87,28 @@ export class JSONCompletionItemProvider implements CompletionItemProvider {
return Promise.resolve(item);
}
public provideCompletionItems(document: TextDocument, position: Position, token: CancellationToken): Thenable<CompletionList | null> | null {
public provideCompletionItems(document: TextDocument, position: Position, _token: CancellationToken): Thenable<CompletionList | null> | null {
let fileName = basename(document.fileName);
const fileName = basename(document.fileName);
let currentWord = this.getCurrentWord(document, position);
const currentWord = this.getCurrentWord(document, position);
let overwriteRange: Range;
let items: CompletionItem[] = [];
const items: CompletionItem[] = [];
let isIncomplete = false;
let offset = document.offsetAt(position);
let location = getLocation(document.getText(), offset);
const offset = document.offsetAt(position);
const location = getLocation(document.getText(), offset);
let node = location.previousNode;
const node = location.previousNode;
if (node && node.offset <= offset && offset <= node.offset + node.length && (node.type === 'property' || node.type === 'string' || node.type === 'number' || node.type === 'boolean' || node.type === 'null')) {
overwriteRange = new Range(document.positionAt(node.offset), document.positionAt(node.offset + node.length));
} else {
overwriteRange = new Range(document.positionAt(offset - currentWord.length), position);
}
let proposed: { [key: string]: boolean } = {};
let collector: ISuggestionsCollector = {
const proposed: { [key: string]: boolean } = {};
const collector: ISuggestionsCollector = {
add: (suggestion: CompletionItem) => {
if (!proposed[suggestion.label]) {
proposed[suggestion.label] = true;
@@ -124,8 +124,8 @@ export class JSONCompletionItemProvider implements CompletionItemProvider {
let collectPromise: Thenable<any> | null = null;
if (location.isAtPropertyKey) {
let addValue = !location.previousNode || !location.previousNode.columnOffset;
let isLast = this.isLast(document, position);
const addValue = !location.previousNode || !location.previousNode.columnOffset;
const isLast = this.isLast(document, position);
collectPromise = this.jsonContribution.collectPropertySuggestions(fileName, location, currentWord, addValue, isLast, collector);
} else {
if (location.path.length === 0) {
@@ -146,8 +146,8 @@ export class JSONCompletionItemProvider implements CompletionItemProvider {
}
private getCurrentWord(document: TextDocument, position: Position) {
var i = position.character - 1;
var text = document.lineAt(position.line).text;
let i = position.character - 1;
const text = document.lineAt(position.line).text;
while (i >= 0 && ' \t\n\r\v":{[,'.indexOf(text.charAt(i)) === -1) {
i--;
}
@@ -155,7 +155,7 @@ export class JSONCompletionItemProvider implements CompletionItemProvider {
}
private isLast(document: TextDocument, position: Position): boolean {
let scanner = createScanner(document.getText(), true);
const scanner = createScanner(document.getText(), true);
scanner.setPosition(document.offsetAt(position));
let nextToken = scanner.scan();
if (nextToken === SyntaxKind.StringLiteral && scanner.getTokenError() === ScanError.UnexpectedEndOfString) {
@@ -13,7 +13,7 @@ import { textToMarkedString } from './markedTextUtil';
import * as nls from 'vscode-nls';
const localize = nls.loadMessageBundle();
let LIMIT = 40;
const LIMIT = 40;
export class PackageJSONContribution implements IJSONContribution {
@@ -31,8 +31,8 @@ export class PackageJSONContribution implements IJSONContribution {
public constructor(private xhr: XHRRequest) {
}
public collectDefaultSuggestions(fileName: string, result: ISuggestionsCollector): Thenable<any> {
let defaultValue = {
public collectDefaultSuggestions(_fileName: string, result: ISuggestionsCollector): Thenable<any> {
const defaultValue = {
'name': '${1:name}',
'description': '${2:description}',
'authors': '${3:author}',
@@ -40,7 +40,7 @@ export class PackageJSONContribution implements IJSONContribution {
'main': '${5:pathToMain}',
'dependencies': {}
};
let proposal = new CompletionItem(localize('json.package.default', 'Default package.json'));
const proposal = new CompletionItem(localize('json.package.default', 'Default package.json'));
proposal.kind = CompletionItemKind.Module;
proposal.insertText = new SnippetString(JSON.stringify(defaultValue, null, '\t'));
result.add(proposal);
@@ -48,7 +48,7 @@ export class PackageJSONContribution implements IJSONContribution {
}
public collectPropertySuggestions(
resource: string,
_resource: string,
location: Location,
currentWord: string,
addValue: boolean,
@@ -65,21 +65,21 @@ export class PackageJSONContribution implements IJSONContribution {
}).then((success) => {
if (success.status === 200) {
try {
let obj = JSON.parse(success.responseText);
const obj = JSON.parse(success.responseText);
if (obj && Array.isArray(obj.rows)) {
let results = <{ key: string[]; }[]>obj.rows;
const results = <{ key: string[]; }[]>obj.rows;
for (let i = 0; i < results.length; i++) {
let keys = results[i].key;
const keys = results[i].key;
if (Array.isArray(keys) && keys.length > 0) {
let name = keys[0];
let insertText = new SnippetString().appendText(JSON.stringify(name));
const name = keys[0];
const insertText = new SnippetString().appendText(JSON.stringify(name));
if (addValue) {
insertText.appendText(': "').appendTabstop().appendText('"');
if (!isLast) {
insertText.appendText(',');
}
}
let proposal = new CompletionItem(name);
const proposal = new CompletionItem(name);
proposal.kind = CompletionItemKind.Property;
proposal.insertText = insertText;
proposal.filterText = JSON.stringify(name);
@@ -98,20 +98,21 @@ export class PackageJSONContribution implements IJSONContribution {
collector.error(localize('json.npm.error.repoaccess', 'Request to the NPM repository failed: {0}', success.responseText));
return 0;
}
return undefined;
}, (error) => {
collector.error(localize('json.npm.error.repoaccess', 'Request to the NPM repository failed: {0}', error.responseText));
return 0;
});
} else {
this.mostDependedOn.forEach((name) => {
let insertText = new SnippetString().appendText(JSON.stringify(name));
const insertText = new SnippetString().appendText(JSON.stringify(name));
if (addValue) {
insertText.appendText(': "').appendTabstop().appendText('"');
if (!isLast) {
insertText.appendText(',');
}
}
let proposal = new CompletionItem(name);
const proposal = new CompletionItem(name);
proposal.kind = CompletionItemKind.Property;
proposal.insertText = insertText;
proposal.filterText = JSON.stringify(name);
@@ -126,20 +127,20 @@ export class PackageJSONContribution implements IJSONContribution {
}
public collectValueSuggestions(
fileName: string,
_fileName: string,
location: Location,
result: ISuggestionsCollector
): Thenable<any> | null {
if ((location.matches(['dependencies', '*']) || location.matches(['devDependencies', '*']) || location.matches(['optionalDependencies', '*']) || location.matches(['peerDependencies', '*']))) {
let currentKey = location.path[location.path.length - 1];
const currentKey = location.path[location.path.length - 1];
if (typeof currentKey === 'string') {
let queryUrl = 'http://registry.npmjs.org/' + encodeURIComponent(currentKey).replace('%40', '@');
const queryUrl = 'http://registry.npmjs.org/' + encodeURIComponent(currentKey).replace('%40', '@');
return this.xhr({
url: queryUrl
}).then((success) => {
try {
let obj = JSON.parse(success.responseText);
let latest = obj && obj['dist-tags'] && obj['dist-tags']['latest'];
const obj = JSON.parse(success.responseText);
const latest = obj && obj['dist-tags'] && obj['dist-tags']['latest'];
if (latest) {
let name = JSON.stringify(latest);
let proposal = new CompletionItem(name);
@@ -166,7 +167,7 @@ export class PackageJSONContribution implements IJSONContribution {
// ignore
}
return 0;
}, (error) => {
}, () => {
return 0;
});
}
@@ -186,24 +187,24 @@ export class PackageJSONContribution implements IJSONContribution {
}
return null;
});
};
}
return null;
}
private getInfo(pack: string): Thenable<string[]> {
let queryUrl = 'http://registry.npmjs.org/' + encodeURIComponent(pack).replace('%40', '@');
const queryUrl = 'http://registry.npmjs.org/' + encodeURIComponent(pack).replace('%40', '@');
return this.xhr({
url: queryUrl
}).then((success) => {
try {
let obj = JSON.parse(success.responseText);
const obj = JSON.parse(success.responseText);
if (obj) {
let result: string[] = [];
const result: string[] = [];
if (obj.description) {
result.push(obj.description);
}
let latest = obj && obj['dist-tags'] && obj['dist-tags']['latest'];
const latest = obj && obj['dist-tags'] && obj['dist-tags']['latest'];
if (latest) {
result.push(localize('json.npm.version.hover', 'Latest version: {0}', latest));
}
@@ -213,14 +214,14 @@ export class PackageJSONContribution implements IJSONContribution {
// ignore
}
return [];
}, (error) => {
}, () => {
return [];
});
}
public getInfoContribution(fileName: string, location: Location): Thenable<MarkedString[] | null> | null {
public getInfoContribution(_fileName: string, location: Location): Thenable<MarkedString[] | null> | null {
if ((location.matches(['dependencies', '*']) || location.matches(['devDependencies', '*']) || location.matches(['optionalDependencies', '*']) || location.matches(['peerDependencies', '*']))) {
let pack = location.path[location.path.length - 1];
const pack = location.path[location.path.length - 1];
if (typeof pack === 'string') {
return this.getInfo(pack).then(infos => {
if (infos.length) {
+2 -2
View File
@@ -16,12 +16,12 @@ export function activate(context: ExtensionContext): any {
nls.config({ locale: env.language });
configureHttpRequest();
workspace.onDidChangeConfiguration(e => configureHttpRequest());
workspace.onDidChangeConfiguration(() => configureHttpRequest());
context.subscriptions.push(addJSONProviders(httpRequest.xhr));
}
function configureHttpRequest() {
let httpSettings = workspace.getConfiguration('http');
const httpSettings = workspace.getConfiguration('http');
httpRequest.configure(httpSettings.get<string>('proxy', ''), httpSettings.get<boolean>('proxyStrictSSL', true));
}
+4
View File
@@ -6,6 +6,10 @@
"lib": [
"es2015"
],
"noImplicitAny": true,
"noImplicitReturns": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"strict": true
},
"include": [
+3 -2
View File
@@ -50,6 +50,7 @@ interface Settings {
};
}
// @ts-ignore unused type
interface JSONSettings {
schemas: JSONSchemaSettings[];
}
@@ -260,8 +261,8 @@ function getSettings(): Settings {
folderPath = folderPath + '/';
}
collectSchemaSettings(folderSchemas, folderUri.fsPath, folderPath + '*');
};
};
}
}
}
return settings;
}
+1
View File
@@ -3,6 +3,7 @@
"target": "es5",
"module": "commonjs",
"outDir": "./out",
"noUnusedLocals": true,
"lib": [
"es5", "es2015.promise"
]
+1
View File
@@ -5,6 +5,7 @@
"sourceMap": true,
"sourceRoot": "../src",
"outDir": "./out",
"noUnusedLocals": true,
"lib": [
"es5", "es2015.promise"
]
@@ -13,7 +13,7 @@ export default class MergeConflictCodeLensProvider implements vscode.CodeLensPro
private config: interfaces.IExtensionConfiguration;
private tracker: interfaces.IDocumentMergeConflictTracker;
constructor(private context: vscode.ExtensionContext, trackerService: interfaces.IDocumentMergeConflictTrackerService) {
constructor(trackerService: interfaces.IDocumentMergeConflictTrackerService) {
this.tracker = trackerService.createTracker('codelens');
}
@@ -46,7 +46,7 @@ export default class MergeConflictCodeLensProvider implements vscode.CodeLensPro
}
}
async provideCodeLenses(document: vscode.TextDocument, token: vscode.CancellationToken): Promise<vscode.CodeLens[] | null> {
async provideCodeLenses(document: vscode.TextDocument, _token: vscode.CancellationToken): Promise<vscode.CodeLens[] | null> {
if (!this.config || !this.config.enableCodeLens) {
return null;
@@ -24,7 +24,7 @@ export default class CommandHandler implements vscode.Disposable {
private disposables: vscode.Disposable[] = [];
private tracker: interfaces.IDocumentMergeConflictTracker;
constructor(private context: vscode.ExtensionContext, trackerService: interfaces.IDocumentMergeConflictTrackerService) {
constructor(trackerService: interfaces.IDocumentMergeConflictTrackerService) {
this.tracker = trackerService.createTracker('commands');
}
@@ -62,19 +62,19 @@ export default class CommandHandler implements vscode.Disposable {
return this.accept(interfaces.CommitType.Both, editor, ...args);
}
acceptAllCurrent(editor: vscode.TextEditor, ...args: any[]): Promise<void> {
acceptAllCurrent(editor: vscode.TextEditor): Promise<void> {
return this.acceptAll(interfaces.CommitType.Current, editor);
}
acceptAllIncoming(editor: vscode.TextEditor, ...args: any[]): Promise<void> {
acceptAllIncoming(editor: vscode.TextEditor): Promise<void> {
return this.acceptAll(interfaces.CommitType.Incoming, editor);
}
acceptAllBoth(editor: vscode.TextEditor, ...args: any[]): Promise<void> {
acceptAllBoth(editor: vscode.TextEditor): Promise<void> {
return this.acceptAll(interfaces.CommitType.Both, editor);
}
async compare(editor: vscode.TextEditor, conflict: interfaces.IDocumentMergeConflict | null, ...args: any[]) {
async compare(editor: vscode.TextEditor, conflict: interfaces.IDocumentMergeConflict | null) {
const fileName = path.basename(editor.document.uri.fsPath);
// No conflict, command executed from command palette
@@ -102,15 +102,15 @@ export default class CommandHandler implements vscode.Disposable {
vscode.commands.executeCommand('vscode.diff', leftUri, rightUri, title);
}
navigateNext(editor: vscode.TextEditor, ...args: any[]): Promise<void> {
navigateNext(editor: vscode.TextEditor): Promise<void> {
return this.navigate(editor, NavigationDirection.Forwards);
}
navigatePrevious(editor: vscode.TextEditor, ...args: any[]): Promise<void> {
navigatePrevious(editor: vscode.TextEditor): Promise<void> {
return this.navigate(editor, NavigationDirection.Backwards);
}
async acceptSelection(editor: vscode.TextEditor, ...args: any[]): Promise<void> {
async acceptSelection(editor: vscode.TextEditor): Promise<void> {
let conflict = await this.findConflictContainingSelection(editor);
if (!conflict) {
@@ -4,21 +4,11 @@
*--------------------------------------------------------------------------------------------*/
'use strict';
import * as vscode from 'vscode';
import * as interfaces from './interfaces';
export default class MergeConflictContentProvider implements vscode.TextDocumentContentProvider, vscode.Disposable {
static scheme = 'merge-conflict.conflict-diff';
constructor(private context: vscode.ExtensionContext) {
}
begin(config: interfaces.IExtensionConfiguration) {
this.context.subscriptions.push(
vscode.workspace.registerTextDocumentContentProvider(MergeConflictContentProvider.scheme, this)
);
}
dispose() {
}
@@ -13,7 +13,7 @@ export class DocumentMergeConflict implements interfaces.IDocumentMergeConflict
public commonAncestors: interfaces.IMergeRegion[];
public splitter: vscode.Range;
constructor(document: vscode.TextDocument, descriptor: interfaces.IDocumentMergeConflictDescriptor) {
constructor(descriptor: interfaces.IDocumentMergeConflictDescriptor) {
this.range = descriptor.range;
this.current = descriptor.current;
this.incoming = descriptor.incoming;
@@ -27,7 +27,7 @@ export class DocumentMergeConflict implements interfaces.IDocumentMergeConflict
this.applyEdit(type, editor, edit);
return Promise.resolve(true);
};
}
return editor.edit((edit) => this.applyEdit(type, editor, edit));
}
@@ -116,7 +116,7 @@ export default class DocumentMergeConflictTracker implements vscode.Disposable,
this.cache.clear();
}
private getConflictsOrEmpty(document: vscode.TextDocument, origins: string[]): interfaces.IDocumentMergeConflict[] {
private getConflictsOrEmpty(document: vscode.TextDocument, _origins: string[]): interfaces.IDocumentMergeConflict[] {
const containsConflict = MergeConflictParser.containsConflict(document);
if (!containsConflict) {
@@ -81,7 +81,7 @@ export class MergeConflictParser {
return conflictDescriptors
.filter(Boolean)
.map(descriptor => new DocumentMergeConflict(document, descriptor));
.map(descriptor => new DocumentMergeConflict(descriptor));
}
private static scanItemTolMergeConflictDescriptor(document: vscode.TextDocument, scanned: IScanMergedConflict): interfaces.IDocumentMergeConflictDescriptor | null {
+3 -3
View File
@@ -26,9 +26,9 @@ export default class ServiceWrapper implements vscode.Disposable {
this.services.push(
documentTracker,
new CommandHandler(this.context, documentTracker),
new CodeLensProvider(this.context, documentTracker),
new ContentProvider(this.context),
new CommandHandler(documentTracker),
new CodeLensProvider(documentTracker),
new ContentProvider(),
new Decorator(this.context, documentTracker),
);
+4
View File
@@ -6,6 +6,10 @@
],
"module": "commonjs",
"outDir": "./out",
"noImplicitAny": true,
"noImplicitReturns": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"strict": true,
"experimentalDecorators": true
},
@@ -12,7 +12,7 @@ export default class PHPCompletionItemProvider implements CompletionItemProvider
public triggerCharacters = ['.', ':', '$'];
public provideCompletionItems(document: TextDocument, position: Position, token: CancellationToken): Promise<CompletionItem[]> {
public provideCompletionItems(document: TextDocument, position: Position, _token: CancellationToken): Promise<CompletionItem[]> {
let result: CompletionItem[] = [];
let shouldProvideCompletionItems = workspace.getConfiguration('php').get<boolean>('suggest.basic', true);
@@ -27,7 +27,7 @@ export default class PHPCompletionItemProvider implements CompletionItemProvider
}
var added: any = {};
var createNewProposal = function (kind: CompletionItemKind, name: string, entry: phpGlobals.IEntry): CompletionItem {
var createNewProposal = function (kind: CompletionItemKind, name: string, entry: phpGlobals.IEntry | null): CompletionItem {
var proposal: CompletionItem = new CompletionItem(name);
proposal.kind = kind;
if (entry) {
@@ -85,7 +85,7 @@ export default class PHPCompletionItemProvider implements CompletionItemProvider
var text = document.getText();
if (prefix[0] === '$') {
var variableMatch = /\$([a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)/g;
var match: RegExpExecArray = null;
var match: RegExpExecArray | null = null;
while (match = variableMatch.exec(text)) {
var word = match[0];
if (!added[word]) {
@@ -95,7 +95,7 @@ export default class PHPCompletionItemProvider implements CompletionItemProvider
}
}
var functionMatch = /function\s+([a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)\s*\(/g;
var match: RegExpExecArray = null;
var match: RegExpExecArray | null = null;
while (match = functionMatch.exec(text)) {
var word = match[1];
if (!added[word]) {
+5 -3
View File
@@ -11,15 +11,15 @@ import { textToMarkedString } from './utils/markedTextUtil';
export default class PHPHoverProvider implements HoverProvider {
public provideHover(document: TextDocument, position: Position, token: CancellationToken): Hover {
public provideHover(document: TextDocument, position: Position, _token: CancellationToken): Hover | undefined {
let enable = workspace.getConfiguration('php').get<boolean>('suggest.basic', true);
if (!enable) {
return null;
return undefined;
}
let wordRange = document.getWordRangeAtPosition(position);
if (!wordRange) {
return;
return undefined;
}
let name = document.getText(wordRange);
@@ -30,5 +30,7 @@ export default class PHPHoverProvider implements HoverProvider {
let contents: MarkedString[] = [textToMarkedString(entry.description), { language: 'php', value: signature }];
return new Hover(contents, wordRange);
}
return undefined;
}
}
@@ -69,7 +69,7 @@ class BackwardIterator {
export default class PHPSignatureHelpProvider implements SignatureHelpProvider {
public provideSignatureHelp(document: TextDocument, position: Position, token: CancellationToken): Promise<SignatureHelp> {
public provideSignatureHelp(document: TextDocument, position: Position, _token: CancellationToken): Promise<SignatureHelp> | null {
let enable = workspace.getConfiguration('php').get<boolean>('suggest.basic', true);
if (!enable) {
return null;
@@ -95,7 +95,7 @@ export default class PHPSignatureHelpProvider implements SignatureHelpProvider {
let signatureInfo = new SignatureInformation(ident + paramsString, entry.description);
var re = /\w*\s+\&?\$[\w_\.]+|void/g;
var match: RegExpExecArray = null;
var match: RegExpExecArray | null = null;
while ((match = re.exec(paramsString)) !== null) {
signatureInfo.parameters.push({ label: match[0], documentation: '' });
}
+15 -15
View File
@@ -29,9 +29,9 @@ export interface ITask<T> {
*/
export class Throttler<T> {
private activePromise: Promise<T>;
private queuedPromise: Promise<T>;
private queuedPromiseFactory: ITask<Promise<T>>;
private activePromise: Promise<T> | null;
private queuedPromise: Promise<T> | null;
private queuedPromiseFactory: ITask<Promise<T>> | null;
constructor() {
this.activePromise = null;
@@ -47,26 +47,26 @@ export class Throttler<T> {
var onComplete = () => {
this.queuedPromise = null;
var result = this.queue(this.queuedPromiseFactory);
var result = this.queue(this.queuedPromiseFactory!);
this.queuedPromiseFactory = null;
return result;
};
this.queuedPromise = new Promise<T>((resolve, reject) => {
this.activePromise.then(onComplete, onComplete).then(resolve);
this.queuedPromise = new Promise<T>((resolve) => {
this.activePromise!.then(onComplete, onComplete).then(resolve);
});
}
return new Promise<T>((resolve, reject) => {
this.queuedPromise.then(resolve, reject);
this.queuedPromise!.then(resolve, reject);
});
}
this.activePromise = promiseFactory();
return new Promise<T>((resolve, reject) => {
this.activePromise.then((result: T) => {
this.activePromise!.then((result: T) => {
this.activePromise = null;
resolve(result);
}, (err: any) => {
@@ -103,10 +103,10 @@ export class Throttler<T> {
export class Delayer<T> {
public defaultDelay: number;
private timeout: NodeJS.Timer;
private completionPromise: Promise<T>;
private onResolve: (value: T | Thenable<T>) => void;
private task: ITask<T>;
private timeout: NodeJS.Timer | null;
private completionPromise: Promise<T> | null;
private onResolve: ((value: T | Thenable<T> | undefined) => void) | null;
private task: ITask<T> | null;
constructor(defaultDelay: number) {
this.defaultDelay = defaultDelay;
@@ -121,13 +121,13 @@ export class Delayer<T> {
this.cancelTimeout();
if (!this.completionPromise) {
this.completionPromise = new Promise<T>((resolve, reject) => {
this.completionPromise = new Promise<T>((resolve) => {
this.onResolve = resolve;
}).then(() => {
this.completionPromise = null;
this.onResolve = null;
var result = this.task();
var result = this.task!();
this.task = null;
return result;
@@ -136,7 +136,7 @@ export class Delayer<T> {
this.timeout = setTimeout(() => {
this.timeout = null;
this.onResolve(null);
this.onResolve!(undefined);
}, delay);
return this.completionPromise;
@@ -16,7 +16,7 @@ let localize = nls.loadMessageBundle();
export class LineDecoder {
private stringDecoder: NodeStringDecoder;
private remaining: string;
private remaining: string | null;
constructor(encoding: string = 'utf8') {
this.stringDecoder = new StringDecoder(encoding);
@@ -55,7 +55,7 @@ export class LineDecoder {
return result;
}
public end(): string {
public end(): string | null {
return this.remaining;
}
}
@@ -88,17 +88,17 @@ export default class PHPValidationProvider {
private static FileArgs: string[] = ['-l', '-n', '-d', 'display_errors=On', '-d', 'log_errors=Off', '-f'];
private validationEnabled: boolean;
private executableIsUserDefined: boolean;
private executable: string;
private executableIsUserDefined: boolean | undefined;
private executable: string | undefined;
private trigger: RunTrigger;
private pauseValidation: boolean;
private documentListener: vscode.Disposable;
private documentListener: vscode.Disposable | null;
private diagnosticCollection: vscode.DiagnosticCollection;
private delayers: { [key: string]: ThrottledDelayer<void> };
constructor(private workspaceStore: vscode.Memento) {
this.executable = null;
this.executable = undefined;
this.validationEnabled = true;
this.trigger = RunTrigger.onSave;
this.pauseValidation = false;
@@ -145,7 +145,7 @@ export default class PHPValidationProvider {
}
this.trigger = RunTrigger.from(section.get<string>('validate.run', RunTrigger.strings.onSave));
}
if (this.executableIsUserDefined !== true && this.workspaceStore.get<string>(CheckedExecutablePath, undefined) !== void 0) {
if (this.executableIsUserDefined !== true && this.workspaceStore.get<string | undefined>(CheckedExecutablePath, undefined) !== void 0) {
vscode.commands.executeCommand('setContext', 'php.untrustValidationExecutableContext', true);
}
this.delayers = Object.create(null);
@@ -195,7 +195,7 @@ export default class PHPValidationProvider {
};
if (this.executableIsUserDefined !== void 0 && !this.executableIsUserDefined) {
let checkedExecutablePath = this.workspaceStore.get<string>(CheckedExecutablePath, undefined);
let checkedExecutablePath = this.workspaceStore.get<string | undefined>(CheckedExecutablePath, undefined);
if (!checkedExecutablePath || checkedExecutablePath !== this.executable) {
vscode.window.showInformationMessage<MessageItem>(
localize('php.useExecutablePath', 'Do you allow {0} (defined as a workspace setting) to be executed to lint PHP files?', this.executable),
@@ -224,7 +224,7 @@ export default class PHPValidationProvider {
}
private doValidate(textDocument: vscode.TextDocument): Promise<void> {
return new Promise<void>((resolve, reject) => {
return new Promise<void>((resolve) => {
let executable = this.executable || 'php';
let decoder = new LineDecoder();
let diagnostics: vscode.Diagnostic[] = [];
@@ -286,7 +286,7 @@ export default class PHPValidationProvider {
}
private showError(error: any, executable: string): void {
let message: string = null;
let message: string | null = null;
if (error.code === 'ENOENT') {
if (this.executable) {
message = localize('wrongExecutable', 'Cannot validate since {0} is not a valid php executable. Use the setting \'php.validate.executablePath\' to configure the PHP executable.', executable);
@@ -296,6 +296,8 @@ export default class PHPValidationProvider {
} else {
message = error.message ? error.message : localize('unknownReason', 'Failed to run php using path: {0}. Reason is unknown.', executable);
}
vscode.window.showInformationMessage(message);
if (message) {
vscode.window.showInformationMessage(message);
}
}
}
+6 -1
View File
@@ -5,7 +5,12 @@
"es2015"
],
"module": "commonjs",
"outDir": "./out"
"outDir": "./out",
"noImplicitAny": true,
"noImplicitReturns": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"strict": true
},
"include": [
"src/**/*"
+2 -1
View File
@@ -5,7 +5,8 @@
"es2015"
],
"module": "commonjs",
"outDir": "./out"
"outDir": "./out",
"strict": true
},
"include": [
"src/**/*"
+1 -1
View File
@@ -530,7 +530,7 @@
},
{
"language": "typescriptreact",
"path": "./snippets/typescriptreact.json"
"path": "./snippets/typescript.json"
}
],
"jsonValidation": [
@@ -1,278 +0,0 @@
{
"Constructor": {
"prefix": "ctor",
"body": [
"/**",
" *",
" */",
"constructor() {",
"\tsuper();",
"\t$0",
"}"
],
"description": "Constructor"
},
"Class Definition": {
"prefix": "class",
"body": [
"class ${1:name} {",
"\tconstructor(${2:parameters}) {",
"\t\t$0",
"\t}",
"}"
],
"description": "Class Definition"
},
"Public Method Definition": {
"prefix": "public method",
"body": [
"/**",
" * ${1:name}",
" */",
"public ${1:name}() {",
"\t$0",
"}"
],
"description": "Public Method Definition"
},
"Private Method Definition": {
"prefix": "private method",
"body": [
"private ${1:name}() {",
"\t$0",
"}"
],
"description": "Private Method Definition"
},
"Import external module.": {
"prefix": "import statement",
"body": [
"import { $0 } from \"${1:module}\";"
],
"description": "Import external module."
},
"Property getter": {
"prefix": "get",
"body": [
"",
"public get ${1:value}() : ${2:string} {",
"\t${3:return $0}",
"}",
""
],
"description": "Property getter"
},
"Log to the console": {
"prefix": "log",
"body": [
"console.log($1);",
"$0"
],
"description": "Log to the console"
},
"Define a full property": {
"prefix": "prop",
"body": [
"",
"private _${1:value} : ${2:string};",
"public get ${1:value}() : ${2:string} {",
"\treturn this._${1:value};",
"}",
"public set ${1:value}(v : ${2:string}) {",
"\tthis._${1:value} = v;",
"}",
""
],
"description": "Define a full property"
},
"Triple-slash reference": {
"prefix": "ref",
"body": [
"/// <reference path=\"$1\" />",
"$0"
],
"description": "Triple-slash reference"
},
"Return false": {
"prefix": "ret0",
"body": [
"return false;$0"
],
"description": "Return false"
},
"Return true": {
"prefix": "ret1",
"body": [
"return true;$0"
],
"description": "Return true"
},
"Return statement": {
"prefix": "ret",
"body": [
"return $1;$0"
],
"description": "Return statement"
},
"Property setter": {
"prefix": "set",
"body": [
"",
"public set ${1:value}(v : ${2:string}) {",
"\tthis.$3 = v;",
"}",
""
],
"description": "Property setter"
},
"Throw Exception": {
"prefix": "throw",
"body": [
"throw \"$1\";",
"$0"
],
"description": "Throw Exception"
},
"For Loop": {
"prefix": "for",
"body": [
"for (let ${1:index} = 0; ${1:index} < ${2:array}.length; ${1:index}++) {",
"\tconst ${3:element} = ${2:array}[${1:index}];",
"\t$0",
"}"
],
"description": "For Loop"
},
"For-Each Loop using =>": {
"prefix": "foreach =>",
"body": [
"${1:array}.forEach(${2:element} => {",
"\t$0",
"});"
],
"description": "For-Each Loop using =>"
},
"For-In Loop": {
"prefix": "forin",
"body": [
"for (const ${1:key} in ${2:object}) {",
"\tif (${2:object}.hasOwnProperty(${1:key})) {",
"\t\tconst ${3:element} = ${2:object}[${1:key}];",
"\t\t$0",
"\t}",
"}"
],
"description": "For-In Loop"
},
"For-Of Loop": {
"prefix": "forof",
"body": [
"for (const ${1:iterator} of ${2:object}) {",
"\t$0",
"}"
],
"description": "For-Of Loop"
},
"Function Statement": {
"prefix": "function",
"body": [
"function ${1:name}(${2:params}:${3:type}) {",
"\t$0",
"}"
],
"description": "Function Statement"
},
"If Statement": {
"prefix": "if",
"body": [
"if (${1:condition}) {",
"\t$0",
"}"
],
"description": "If Statement"
},
"If-Else Statement": {
"prefix": "ifelse",
"body": [
"if (${1:condition}) {",
"\t$0",
"} else {",
"\t",
"}"
],
"description": "If-Else Statement"
},
"New Statement": {
"prefix": "new",
"body": [
"const ${1:name} = new ${2:type}(${3:arguments});$0"
],
"description": "New Statement"
},
"Switch Statement": {
"prefix": "switch",
"body": [
"switch (${1:key}) {",
"\tcase ${2:value}:",
"\t\t$0",
"\t\tbreak;",
"",
"\tdefault:",
"\t\tbreak;",
"}"
],
"description": "Switch Statement"
},
"While Statement": {
"prefix": "while",
"body": [
"while (${1:condition}) {",
"\t$0",
"}"
],
"description": "While Statement"
},
"Do-While Statement": {
"prefix": "dowhile",
"body": [
"do {",
"\t$0",
"} while (${1:condition});"
],
"description": "Do-While Statement"
},
"Try-Catch Statement": {
"prefix": "trycatch",
"body": [
"try {",
"\t$0",
"} catch (${1:error}) {",
"\t",
"}"
],
"description": "Try-Catch Statement"
},
"Set Timeout Function": {
"prefix": "settimeout",
"body": [
"setTimeout(() => {",
"\t$0",
"}, ${1:timeout});"
],
"description": "Set Timeout Function"
},
"Region Start": {
"prefix": "#region",
"body": [
"//#region $0"
],
"description": "Folding Region Start"
},
"Region End": {
"prefix": "#endregion",
"body": [
"//#endregion"
],
"description": "Folding Region End"
}
}
@@ -3,38 +3,50 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { CodeActionProvider, TextDocument, Range, CancellationToken, CodeActionContext, Command, commands } from 'vscode';
import * as vscode from 'vscode';
import * as Proto from '../protocol';
import { ITypeScriptServiceClient } from '../typescriptService';
import { vsRangeToTsFileRange } from '../utils/convert';
import FormattingConfigurationManager from './formattingConfigurationManager';
import { applyCodeAction } from '../utils/codeAction';
import { CommandManager, Command } from '../utils/commandManager';
interface NumberSet {
[key: number]: boolean;
}
export default class TypeScriptCodeActionProvider implements CodeActionProvider {
private commandId: string;
class ApplyCodeActionCommand implements Command {
public static readonly ID: string = '_typescript.applyCodeAction';
public readonly id: string = ApplyCodeActionCommand.ID;
constructor(
private readonly client: ITypeScriptServiceClient
) { }
execute(action: Proto.CodeAction, file: string): void {
applyCodeAction(this.client, action, file);
}
}
export default class TypeScriptCodeActionProvider implements vscode.CodeActionProvider {
private _supportedCodeActions?: Thenable<NumberSet>;
constructor(
private readonly client: ITypeScriptServiceClient,
private readonly formattingConfigurationManager: FormattingConfigurationManager,
mode: string
commandManager: CommandManager
) {
this.commandId = `_typescript.applyCodeAction.${mode}`;
commands.registerCommand(this.commandId, this.onCodeAction, this);
commandManager.register(new ApplyCodeActionCommand(this.client));
}
public async provideCodeActions(
document: TextDocument,
range: Range,
context: CodeActionContext,
token: CancellationToken
): Promise<Command[]> {
document: vscode.TextDocument,
range: vscode.Range,
context: vscode.CodeActionContext,
token: vscode.CancellationToken
): Promise<vscode.Command[]> {
if (!this.client.apiVersion.has213Features()) {
return [];
}
@@ -73,22 +85,18 @@ export default class TypeScriptCodeActionProvider implements CodeActionProvider
return this._supportedCodeActions;
}
private async getSupportedActionsForContext(context: CodeActionContext): Promise<Set<number>> {
private async getSupportedActionsForContext(context: vscode.CodeActionContext): Promise<Set<number>> {
const supportedActions = await this.supportedCodeActions;
return new Set(context.diagnostics
.map(diagnostic => +diagnostic.code)
.filter(code => supportedActions[code]));
}
private getCommandForAction(action: Proto.CodeAction, file: string): Command {
private getCommandForAction(action: Proto.CodeAction, file: string): vscode.Command {
return {
title: action.description,
command: this.commandId,
command: ApplyCodeActionCommand.ID,
arguments: [action, file]
};
}
private onCodeAction(action: Proto.CodeAction, file: string): Promise<boolean> {
return applyCodeAction(this.client, action, file);
}
}
@@ -3,7 +3,7 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { CompletionItem, TextDocument, Position, CompletionItemKind, CompletionItemProvider, CancellationToken, TextEdit, Range, SnippetString, workspace, ProviderResult, CompletionContext, commands, Uri, MarkdownString } from 'vscode';
import { CompletionItem, TextDocument, Position, CompletionItemKind, CompletionItemProvider, CancellationToken, TextEdit, Range, SnippetString, workspace, ProviderResult, CompletionContext, Uri, MarkdownString } from 'vscode';
import { ITypeScriptServiceClient } from '../typescriptService';
import TypingsStatus from '../utils/typingsStatus';
@@ -16,6 +16,7 @@ import { tsTextSpanToVsRange, vsPositionToTsFileLocation } from '../utils/conver
import * as nls from 'vscode-nls';
import { applyCodeAction } from '../utils/codeAction';
import * as languageModeIds from '../utils/languageModeIds';
import { CommandManager, Command } from '../utils/commandManager';
let localize = nls.loadMessageBundle();
@@ -125,6 +126,24 @@ class MyCompletionItem extends CompletionItem {
}
}
class ApplyCompletionCodeActionCommand implements Command {
public static readonly ID = '_typescript.applyCompletionCodeAction';
public readonly id = ApplyCompletionCodeActionCommand.ID;
public constructor(
private readonly client: ITypeScriptServiceClient
) { }
public async execute(file: string, codeActions: CodeAction[]): Promise<boolean> {
for (const action of codeActions) {
if (!(await applyCodeAction(this.client, action, file))) {
return false;
}
}
return true;
}
}
interface Configuration {
useCodeSnippetsOnMethodSuggest: boolean;
nameSuggestions: boolean;
@@ -141,15 +160,12 @@ namespace Configuration {
}
export default class TypeScriptCompletionItemProvider implements CompletionItemProvider {
private readonly commandId: string;
constructor(
private client: ITypeScriptServiceClient,
mode: string,
private typingsStatus: TypingsStatus
private readonly typingsStatus: TypingsStatus,
commandManager: CommandManager
) {
this.commandId = `_typescript.applyCompletionCodeAction.${mode}`;
commands.registerCommand(this.commandId, this.applyCompletionCodeAction, this);
commandManager.register(new ApplyCompletionCodeActionCommand(this.client));
}
public async provideCompletionItems(
@@ -311,7 +327,7 @@ export default class TypeScriptCompletionItemProvider implements CompletionItemP
if (detail.codeActions && detail.codeActions.length) {
item.command = {
title: '',
command: this.commandId,
command: ApplyCompletionCodeActionCommand.ID,
arguments: [filepath, detail.codeActions]
};
}
@@ -378,16 +394,6 @@ export default class TypeScriptCompletionItemProvider implements CompletionItemP
return new SnippetString(codeSnippet);
}
private async applyCompletionCodeAction(file: string, codeActions: CodeAction[]): Promise<boolean> {
for (const action of codeActions) {
if (!(await applyCodeAction(this.client, action, file))) {
return false;
}
}
return true;
}
private getConfiguration(resource: Uri): Configuration {
// Use shared setting for js and ts
const typeScriptConfig = workspace.getConfiguration('typescript', resource);
@@ -10,6 +10,7 @@ import { DocCommandTemplateResponse } from '../protocol';
import * as nls from 'vscode-nls';
import { vsPositionToTsFileLocation } from '../utils/convert';
import { Command, CommandManager } from '../utils/commandManager';
const localize = nls.loadMessageBundle();
const configurationNamespace = 'jsDocCompletion';
@@ -45,11 +46,14 @@ class JsDocCompletionItem extends CompletionItem {
}
}
export class JsDocCompletionProvider implements CompletionItemProvider {
export default class JsDocCompletionProvider implements CompletionItemProvider {
constructor(
private client: ITypeScriptServiceClient,
) { }
commandManager: CommandManager
) {
commandManager.register(new TryCompleteJsDocCommand(client));
}
public provideCompletionItems(
document: TextDocument,
@@ -77,19 +81,20 @@ export class JsDocCompletionProvider implements CompletionItemProvider {
}
}
export class TryCompleteJsDocCommand {
static COMMAND_NAME = '_typeScript.tryCompleteJsDoc';
class TryCompleteJsDocCommand implements Command {
public static readonly COMMAND_NAME = '_typeScript.tryCompleteJsDoc';
public readonly id = TryCompleteJsDocCommand.COMMAND_NAME;
constructor(
private lazyClient: () => ITypeScriptServiceClient
private readonly client: ITypeScriptServiceClient
) { }
/**
* Try to insert a jsdoc comment, using a template provide by typescript
* if possible, otherwise falling back to a default comment format.
*/
public async tryCompleteJsDoc(resource: Uri, start: Position, shouldGetJSDocFromTSServer: boolean): Promise<boolean> {
const file = this.lazyClient().normalizePath(resource);
public async execute(resource: Uri, start: Position, shouldGetJSDocFromTSServer: boolean): Promise<boolean> {
const file = this.client.normalizePath(resource);
if (!file) {
return false;
}
@@ -113,7 +118,7 @@ export class TryCompleteJsDocCommand {
private tryInsertJsDocFromTemplate(editor: TextEditor, file: string, position: Position): Promise<boolean> {
const args = vsPositionToTsFileLocation(file, position);
return Promise.race([
this.lazyClient().execute('docCommentTemplate', args),
this.client.execute('docCommentTemplate', args),
new Promise<DocCommandTemplateResponse>((_, reject) => setTimeout(reject, 250))
]).then((res: DocCommandTemplateResponse) => {
if (!res || !res.body) {
@@ -5,35 +5,113 @@
'use strict';
import { CodeActionProvider, TextDocument, Range, CancellationToken, CodeActionContext, Command, commands, workspace, WorkspaceEdit, window, QuickPickItem, Selection } from 'vscode';
import * as vscode from 'vscode';
import * as Proto from '../protocol';
import { ITypeScriptServiceClient } from '../typescriptService';
import { tsTextSpanToVsRange, vsRangeToTsFileRange, tsLocationToVsPosition } from '../utils/convert';
import FormattingOptionsManager from './formattingConfigurationManager';
import { CommandManager, Command } from '../utils/commandManager';
export default class TypeScriptRefactorProvider implements CodeActionProvider {
private doRefactorCommandId: string;
private selectRefactorCommandId: string;
class ApplyRefactoringCommand implements Command {
public static readonly ID = '_typescript.applyRefactoring';
public readonly id = ApplyRefactoringCommand.ID;
constructor(
private readonly client: ITypeScriptServiceClient,
private formattingOptionsManager: FormattingOptionsManager,
mode: string
) {
this.doRefactorCommandId = `_typescript.applyRefactoring.${mode}`;
this.selectRefactorCommandId = `_typescript.selectRefactoring.${mode}`;
private formattingOptionsManager: FormattingOptionsManager
) { }
commands.registerCommand(this.doRefactorCommandId, this.doRefactoring, this);
commands.registerCommand(this.selectRefactorCommandId, this.selectRefactoring, this);
public async execute(
document: vscode.TextDocument,
file: string,
refactor: string,
action: string,
range: vscode.Range
): Promise<boolean> {
await this.formattingOptionsManager.ensureFormatOptionsForDocument(document, undefined);
const args: Proto.GetEditsForRefactorRequestArgs = {
...vsRangeToTsFileRange(file, range),
refactor,
action
};
const response = await this.client.execute('getEditsForRefactor', args);
if (!response || !response.body || !response.body.edits.length) {
return false;
}
const edit = this.toWorkspaceEdit(response.body.edits);
if (!(await vscode.workspace.applyEdit(edit))) {
return false;
}
const renameLocation = response.body.renameLocation;
if (renameLocation) {
if (vscode.window.activeTextEditor && vscode.window.activeTextEditor.document.uri.fsPath === file) {
const pos = tsLocationToVsPosition(renameLocation);
vscode.window.activeTextEditor.selection = new vscode.Selection(pos, pos);
await vscode.commands.executeCommand('editor.action.rename');
}
}
return true;
}
private toWorkspaceEdit(edits: Proto.FileCodeEdits[]): vscode.WorkspaceEdit {
const workspaceEdit = new vscode.WorkspaceEdit();
for (const edit of edits) {
for (const textChange of edit.textChanges) {
workspaceEdit.replace(this.client.asUrl(edit.fileName),
tsTextSpanToVsRange(textChange),
textChange.newText);
}
}
return workspaceEdit;
}
}
class SelectRefactorCommand implements Command {
public static readonly ID = '_typescript.selectRefactoring';
public readonly id = SelectRefactorCommand.ID;
constructor(
private readonly doRefactoring: ApplyRefactoringCommand
) { }
public async execute(
document: vscode.TextDocument,
file: string,
info: Proto.ApplicableRefactorInfo,
range: vscode.Range
): Promise<boolean> {
const selected = await vscode.window.showQuickPick(info.actions.map((action): vscode.QuickPickItem => ({
label: action.name,
description: action.description
})));
if (!selected) {
return false;
}
return this.doRefactoring.execute(document, file, info.name, selected.label, range);
}
}
export default class TypeScriptRefactorProvider implements vscode.CodeActionProvider {
constructor(
private readonly client: ITypeScriptServiceClient,
formattingOptionsManager: FormattingOptionsManager,
commandManager: CommandManager
) {
const doRefactoringCommand = commandManager.register(new ApplyRefactoringCommand(this.client, formattingOptionsManager));
commandManager.register(new SelectRefactorCommand(doRefactoringCommand));
}
public async provideCodeActions(
document: TextDocument,
range: Range,
_context: CodeActionContext,
token: CancellationToken
): Promise<Command[]> {
document: vscode.TextDocument,
range: vscode.Range,
_context: vscode.CodeActionContext,
token: vscode.CancellationToken
): Promise<vscode.Command[]> {
if (!this.client.apiVersion.has240Features()) {
return [];
}
@@ -50,19 +128,19 @@ export default class TypeScriptRefactorProvider implements CodeActionProvider {
return [];
}
const actions: Command[] = [];
const actions: vscode.Command[] = [];
for (const info of response.body) {
if (info.inlineable === false) {
actions.push({
title: info.description,
command: this.selectRefactorCommandId,
command: SelectRefactorCommand.ID,
arguments: [document, file, info, range]
});
} else {
for (const action of info.actions) {
actions.push({
title: action.description,
command: this.doRefactorCommandId,
command: ApplyRefactoringCommand.ID,
arguments: [document, file, info.name, action.name, range]
});
}
@@ -73,57 +151,4 @@ export default class TypeScriptRefactorProvider implements CodeActionProvider {
return [];
}
}
private toWorkspaceEdit(edits: Proto.FileCodeEdits[]): WorkspaceEdit {
const workspaceEdit = new WorkspaceEdit();
for (const edit of edits) {
for (const textChange of edit.textChanges) {
workspaceEdit.replace(this.client.asUrl(edit.fileName),
tsTextSpanToVsRange(textChange),
textChange.newText);
}
}
return workspaceEdit;
}
private async selectRefactoring(document: TextDocument, file: string, info: Proto.ApplicableRefactorInfo, range: Range): Promise<boolean> {
const selected = await window.showQuickPick(info.actions.map((action): QuickPickItem => ({
label: action.name,
description: action.description
})));
if (!selected) {
return false;
}
return this.doRefactoring(document, file, info.name, selected.label, range);
}
private async doRefactoring(document: TextDocument, file: string, refactor: string, action: string, range: Range): Promise<boolean> {
await this.formattingOptionsManager.ensureFormatOptionsForDocument(document, undefined);
const args: Proto.GetEditsForRefactorRequestArgs = {
...vsRangeToTsFileRange(file, range),
refactor,
action
};
const response = await this.client.execute('getEditsForRefactor', args);
if (!response || !response.body || !response.body.edits.length) {
return false;
}
const edit = this.toWorkspaceEdit(response.body.edits);
if (!(await workspace.applyEdit(edit))) {
return false;
}
const renameLocation = response.body.renameLocation;
if (renameLocation) {
if (window.activeTextEditor && window.activeTextEditor.document.uri.fsPath === file) {
const pos = tsLocationToVsPosition(renameLocation);
window.activeTextEditor.selection = new Selection(pos, pos);
await commands.executeCommand('editor.action.rename');
}
}
return true;
}
}
@@ -24,7 +24,8 @@ function getSymbolKind(item: Proto.NavtoItem): SymbolKind {
export default class TypeScriptWorkspaceSymbolProvider implements WorkspaceSymbolProvider {
public constructor(
private client: ITypeScriptServiceClient,
private modeId: string) { }
private modeIds: string[]
) { }
public async provideWorkspaceSymbols(search: string, token: CancellationToken): Promise<SymbolInformation[]> {
// typescript wants to have a resource even when asking
@@ -34,14 +35,14 @@ export default class TypeScriptWorkspaceSymbolProvider implements WorkspaceSymbo
const editor = window.activeTextEditor;
if (editor) {
const document = editor.document;
if (document && document.languageId === this.modeId) {
if (document && this.modeIds.indexOf(document.languageId) >= 0) {
uri = document.uri;
}
}
if (!uri) {
const documents = workspace.textDocuments;
for (const document of documents) {
if (document.languageId === this.modeId) {
if (this.modeIds.indexOf(document.languageId) >= 0) {
uri = document.uri;
break;
}
+136 -66
View File
@@ -25,7 +25,6 @@ import TypeScriptServiceClient from './typescriptServiceClient';
import { ITypeScriptServiceClientHost } from './typescriptService';
import BufferSyncSupport from './features/bufferSyncSupport';
import { JsDocCompletionProvider, TryCompleteJsDocCommand } from './features/jsDocCompletionProvider';
import TypeScriptTaskProviderManager from './features/taskProvider';
import * as ProjectStatus from './utils/projectStatus';
@@ -36,6 +35,7 @@ import { openOrCreateConfigFile, isImplicitProjectConfigFile } from './utils/tsc
import { tsLocationToVsPosition } from './utils/convert';
import FormattingConfigurationManager from './features/formattingConfigurationManager';
import * as languageModeIds from './utils/languageModeIds';
import { CommandManager, Command } from './utils/commandManager';
interface LanguageDescription {
id: string;
@@ -45,16 +45,6 @@ interface LanguageDescription {
isExternal?: boolean;
}
enum ProjectConfigAction {
None,
CreateConfig,
LearnMore
}
interface ProjectConfigMessageItem extends MessageItem {
id: ProjectConfigAction;
}
const standardLanguageDescriptions: LanguageDescription[] = [
{
id: 'typescript',
@@ -69,14 +59,107 @@ const standardLanguageDescriptions: LanguageDescription[] = [
}
];
class ReloadTypeScriptProjectsCommand implements Command {
public readonly id = 'typescript.reloadProjects';
public constructor(
private readonly lazyClientHost: () => TypeScriptServiceClientHost
) { }
public execute() {
this.lazyClientHost().reloadProjects();
}
}
class ReloadJavaScriptProjectsCommand implements Command {
public readonly id = 'javascript.reloadProjects';
public constructor(
private readonly lazyClientHost: () => TypeScriptServiceClientHost
) { }
public execute() {
this.lazyClientHost().reloadProjects();
}
}
class SelectTypeScriptVersionCommand implements Command {
public readonly id = 'typescript.selectTypeScriptVersion';
public constructor(
private readonly lazyClientHost: () => TypeScriptServiceClientHost
) { }
public execute() {
this.lazyClientHost().serviceClient.onVersionStatusClicked();
}
}
class OpenTsServerLogCommand implements Command {
public readonly id = 'typescript.openTsServerLog';
public constructor(
private readonly lazyClientHost: () => TypeScriptServiceClientHost
) { }
public execute() {
this.lazyClientHost().serviceClient.openTsServerLogFile();
}
}
class RestartTsServerCommand implements Command {
public readonly id = 'typescript.restartTsServer';
public constructor(
private readonly lazyClientHost: () => TypeScriptServiceClientHost
) { }
public execute() {
this.lazyClientHost().serviceClient.restartTsServer();
}
}
class TypeScriptGoToProjectConfigCommand implements Command {
public readonly id = 'typescript.goToProjectConfig';
public constructor(
private readonly lazyClientHost: () => TypeScriptServiceClientHost,
) { }
public execute() {
const editor = window.activeTextEditor;
if (editor) {
this.lazyClientHost().goToProjectConfig(true, editor.document.uri);
}
}
}
class JavaScriptGoToProjectConfigCommand implements Command {
public readonly id = 'javascript.goToProjectConfig';
public constructor(
private readonly lazyClientHost: () => TypeScriptServiceClientHost,
) { }
public execute() {
const editor = window.activeTextEditor;
if (editor) {
this.lazyClientHost().goToProjectConfig(false, editor.document.uri);
}
}
}
export function activate(context: ExtensionContext): void {
const plugins = getContributedTypeScriptServerPlugins();
const commandManager = new CommandManager();
context.subscriptions.push(commandManager);
const lazyClientHost = (() => {
let clientHost: TypeScriptServiceClientHost | undefined;
return () => {
if (!clientHost) {
clientHost = new TypeScriptServiceClientHost(standardLanguageDescriptions, context.workspaceState, plugins);
clientHost = new TypeScriptServiceClientHost(standardLanguageDescriptions, context.workspaceState, plugins, commandManager);
context.subscriptions.push(clientHost);
const host = clientHost;
@@ -92,42 +175,16 @@ export function activate(context: ExtensionContext): void {
};
})();
context.subscriptions.push(commands.registerCommand('typescript.reloadProjects', () => {
lazyClientHost().reloadProjects();
}));
context.subscriptions.push(commands.registerCommand('javascript.reloadProjects', () => {
lazyClientHost().reloadProjects();
}));
context.subscriptions.push(commands.registerCommand('typescript.selectTypeScriptVersion', () => {
lazyClientHost().serviceClient.onVersionStatusClicked();
}));
context.subscriptions.push(commands.registerCommand('typescript.openTsServerLog', () => {
lazyClientHost().serviceClient.openTsServerLogFile();
}));
context.subscriptions.push(commands.registerCommand('typescript.restartTsServer', () => {
lazyClientHost().serviceClient.restartTsServer();
}));
commandManager.register(new ReloadTypeScriptProjectsCommand(lazyClientHost));
commandManager.register(new ReloadJavaScriptProjectsCommand(lazyClientHost));
commandManager.register(new SelectTypeScriptVersionCommand(lazyClientHost));
commandManager.register(new OpenTsServerLogCommand(lazyClientHost));
commandManager.register(new RestartTsServerCommand(lazyClientHost));
commandManager.register(new TypeScriptGoToProjectConfigCommand(lazyClientHost));
commandManager.register(new JavaScriptGoToProjectConfigCommand(lazyClientHost));
context.subscriptions.push(new TypeScriptTaskProviderManager(() => lazyClientHost().serviceClient));
const goToProjectConfig = (isTypeScript: boolean) => {
const editor = window.activeTextEditor;
if (editor) {
lazyClientHost().goToProjectConfig(isTypeScript, editor.document.uri);
}
};
context.subscriptions.push(commands.registerCommand('typescript.goToProjectConfig', goToProjectConfig.bind(null, true)));
context.subscriptions.push(commands.registerCommand('javascript.goToProjectConfig', goToProjectConfig.bind(null, false)));
const jsDocCompletionCommand = new TryCompleteJsDocCommand(() => lazyClientHost().serviceClient);
context.subscriptions.push(commands.registerCommand(TryCompleteJsDocCommand.COMMAND_NAME, jsDocCompletionCommand.tryCompleteJsDoc, jsDocCompletionCommand));
const EMPTY_ELEMENTS: string[] = ['area', 'base', 'br', 'col', 'embed', 'hr', 'img', 'input', 'keygen', 'link', 'menuitem', 'meta', 'param', 'source', 'track', 'wbr'];
context.subscriptions.push(languages.setLanguageConfiguration('jsx-tags', {
@@ -154,7 +211,7 @@ export function activate(context: ExtensionContext): void {
return true;
}
return false;
};
}
const openListener = workspace.onDidOpenTextDocument(didOpenTextDocument);
for (let textDocument of workspace.textDocuments) {
if (didOpenTextDocument(textDocument)) {
@@ -187,7 +244,8 @@ class LanguageProvider {
constructor(
private readonly client: TypeScriptServiceClient,
private readonly description: LanguageDescription
private readonly description: LanguageDescription,
private readonly commandManager: CommandManager
) {
this.formattingOptionsManager = new FormattingConfigurationManager(client);
this.bufferSyncSupport = new BufferSyncSupport(client, description.modeIds, {
@@ -238,8 +296,9 @@ class LanguageProvider {
const selector = this.description.modeIds;
const config = workspace.getConfiguration(this.id);
const completionItemProvider = new (await import('./features/completionItemProvider')).default(client, this.description.id, this.typingsStatus);
this.disposables.push(languages.registerCompletionItemProvider(selector, completionItemProvider, '.', '"', '\'', '/', '@'));
this.disposables.push(languages.registerCompletionItemProvider(selector,
new (await import('./features/completionItemProvider')).default(client, this.typingsStatus, this.commandManager),
'.', '"', '\'', '/', '@'));
this.disposables.push(languages.registerCompletionItemProvider(selector, new (await import('./features/directiveCommentCompletionProvider')).default(client), '@'));
@@ -253,7 +312,7 @@ class LanguageProvider {
this.disposables.push(formattingProviderManager);
this.toUpdateOnConfigurationChanged.push(formattingProviderManager);
this.disposables.push(languages.registerCompletionItemProvider(selector, new JsDocCompletionProvider(client), '*'));
this.disposables.push(languages.registerCompletionItemProvider(selector, new (await import('./features/jsDocCompletionProvider')).default(client, this.commandManager), '*'));
this.disposables.push(languages.registerHoverProvider(selector, new (await import('./features/hoverProvider')).default(client)));
this.disposables.push(languages.registerDefinitionProvider(selector, new (await import('./features/definitionProvider')).default(client)));
this.disposables.push(languages.registerDocumentHighlightProvider(selector, new (await import('./features/documentHighlightProvider')).default(client)));
@@ -261,24 +320,24 @@ class LanguageProvider {
this.disposables.push(languages.registerDocumentSymbolProvider(selector, new (await import('./features/documentSymbolProvider')).default(client)));
this.disposables.push(languages.registerSignatureHelpProvider(selector, new (await import('./features/signatureHelpProvider')).default(client), '(', ','));
this.disposables.push(languages.registerRenameProvider(selector, new (await import('./features/renameProvider')).default(client)));
this.disposables.push(languages.registerCodeActionsProvider(selector, new (await import('./features/codeActionProvider')).default(client, this.formattingOptionsManager, this.description.id)));
this.disposables.push(languages.registerCodeActionsProvider(selector, new (await import('./features/refactorProvider')).default(client, this.formattingOptionsManager, this.description.id)));
this.disposables.push(languages.registerCodeActionsProvider(selector, new (await import('./features/codeActionProvider')).default(client, this.formattingOptionsManager, this.commandManager)));
this.disposables.push(languages.registerCodeActionsProvider(selector, new (await import('./features/refactorProvider')).default(client, this.formattingOptionsManager, this.commandManager)));
this.registerVersionDependentProviders();
for (const modeId of this.description.modeIds) {
this.disposables.push(languages.registerWorkspaceSymbolProvider(new (await import('./features/workspaceSymbolProvider')).default(client, modeId)));
const referenceCodeLensProvider = new (await import('./features/referencesCodeLensProvider')).default(client, this.description.id);
referenceCodeLensProvider.updateConfiguration();
this.toUpdateOnConfigurationChanged.push(referenceCodeLensProvider);
this.disposables.push(languages.registerCodeLensProvider(selector, referenceCodeLensProvider));
const referenceCodeLensProvider = new (await import('./features/referencesCodeLensProvider')).default(client, modeId);
referenceCodeLensProvider.updateConfiguration();
this.toUpdateOnConfigurationChanged.push(referenceCodeLensProvider);
this.disposables.push(languages.registerCodeLensProvider(selector, referenceCodeLensProvider));
const implementationCodeLensProvider = new (await import('./features/implementationsCodeLensProvider')).default(client, this.description.id);
implementationCodeLensProvider.updateConfiguration();
this.toUpdateOnConfigurationChanged.push(implementationCodeLensProvider);
this.disposables.push(languages.registerCodeLensProvider(selector, implementationCodeLensProvider));
const implementationCodeLensProvider = new (await import('./features/implementationsCodeLensProvider')).default(client, modeId);
implementationCodeLensProvider.updateConfiguration();
this.toUpdateOnConfigurationChanged.push(implementationCodeLensProvider);
this.disposables.push(languages.registerCodeLensProvider(selector, implementationCodeLensProvider));
this.disposables.push(languages.registerWorkspaceSymbolProvider(new (await import('./features/workspaceSymbolProvider')).default(client, this.description.modeIds)));
if (!this.description.isExternal) {
if (!this.description.isExternal) {
for (const modeId of this.description.modeIds) {
this.disposables.push(languages.setLanguageConfiguration(modeId, {
indentationRules: {
// ^(.*\*/)?\s*\}.*$
@@ -442,7 +501,8 @@ class TypeScriptServiceClientHost implements ITypeScriptServiceClientHost {
constructor(
descriptions: LanguageDescription[],
workspaceState: Memento,
plugins: TypeScriptServerPlugin[]
plugins: TypeScriptServerPlugin[],
private commandManager: CommandManager
) {
const handleProjectCreateOrDelete = () => {
this.client.execute('reloadProjects', null, false);
@@ -467,7 +527,7 @@ class TypeScriptServiceClientHost implements ITypeScriptServiceClientHost {
this.languagePerId = new Map();
for (const description of descriptions) {
const manager = new LanguageProvider(this.client, description);
const manager = new LanguageProvider(this.client, description, this.commandManager);
this.languages.push(manager);
this.disposables.push(manager);
this.languagePerId.set(description.id, manager);
@@ -491,7 +551,7 @@ class TypeScriptServiceClientHost implements ITypeScriptServiceClientHost {
diagnosticSource: 'ts-plugins',
isExternal: true
};
const manager = new LanguageProvider(this.client, description);
const manager = new LanguageProvider(this.client, description, this.commandManager);
this.languages.push(manager);
this.disposables.push(manager);
this.languagePerId.set(description.id, manager);
@@ -566,6 +626,16 @@ class TypeScriptServiceClientHost implements ITypeScriptServiceClientHost {
return;
}
enum ProjectConfigAction {
None,
CreateConfig,
LearnMore
}
interface ProjectConfigMessageItem extends MessageItem {
id: ProjectConfigAction;
}
const selected = await window.showInformationMessage<ProjectConfigMessageItem>(
(isTypeScriptProject
? localize('typescript.noTypeScriptProjectConfig', 'File is not part of a TypeScript project')
@@ -375,6 +375,7 @@ export default class TypeScriptServiceClient implements ITypeScriptServiceClient
this.isRestarting = false;
});
// tslint:disable-next-line:no-unused-expression
new Reader<Proto.Response>(
childProcess.stdout,
(msg) => { this.dispatchMessage(msg); },
@@ -0,0 +1,36 @@
/*---------------------------------------------------------------------------------------------
* 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';
export interface Command {
readonly id: string;
execute(...args: any[]): void;
}
export class CommandManager {
private readonly commands = new Map<string, vscode.Disposable>();
public dispose() {
for (const registration of this.commands.values()) {
registration.dispose();
}
this.commands.clear();
}
private registerCommand(id: string, impl: (...args: any[]) => void, thisArg?: any) {
if (this.commands.has(id)) {
return;
}
this.commands.set(id, vscode.commands.registerCommand(id, impl, thisArg));
}
public register<T extends Command>(command: T): T {
this.registerCommand(command.id, command.execute, command);
return command;
}
}
+13 -13
View File
@@ -36,22 +36,22 @@ function getEmptyConfig(
}`);
}
export function openOrCreateConfigFile(
export async function openOrCreateConfigFile(
isTypeScriptProject: boolean,
rootPath: string,
config: TypeScriptServiceConfiguration
): Thenable<vscode.TextEditor | null> {
): Promise<vscode.TextEditor | null> {
const configFile = vscode.Uri.file(path.join(rootPath, isTypeScriptProject ? 'tsconfig.json' : 'jsconfig.json'));
const col = vscode.window.activeTextEditor ? vscode.window.activeTextEditor.viewColumn : undefined;
return vscode.workspace.openTextDocument(configFile)
.then(doc => {
return vscode.window.showTextDocument(doc, col);
}, async () => {
const doc = await vscode.workspace.openTextDocument(configFile.with({ scheme: 'untitled' }));
const editor = await vscode.window.showTextDocument(doc, col);
if (editor.document.getText().length === 0) {
await editor.insertSnippet(getEmptyConfig(isTypeScriptProject, config));
}
return editor;
});
try {
const doc = await vscode.workspace.openTextDocument(configFile);
return vscode.window.showTextDocument(doc, col);
} catch {
const doc = await vscode.workspace.openTextDocument(configFile.with({ scheme: 'untitled' }));
const editor = await vscode.window.showTextDocument(doc, col);
if (editor.document.getText().length === 0) {
await editor.insertSnippet(getEmptyConfig(isTypeScriptProject, config));
}
return editor;
}
}
@@ -5,6 +5,7 @@
'use strict';
import 'mocha';
import * as assert from 'assert';
import { join } from 'path';
import { commands, workspace, window, Uri, ViewColumn, Range, Position } from 'vscode';
@@ -3,6 +3,7 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import 'mocha';
import * as assert from 'assert';
import * as vscode from 'vscode';
@@ -78,12 +78,12 @@ suite('languages namespace tests', () => {
});
return workspace.openTextDocument(uri).then(doc => {
return commands.executeCommand('vscode.executeCompletionItemProvider', uri, new Position(1, 0));
}).then((result: CompletionList) => {
return commands.executeCommand<CompletionList>('vscode.executeCompletionItemProvider', uri, new Position(1, 0));
}).then((result: CompletionList | undefined) => {
r1.dispose();
assert.ok(ran);
console.log(result.items);
assert.equal(result.items[0].label, 'foo');
console.log(result!.items);
assert.equal(result!.items[0].label, 'foo');
});
});
});
-1
View File
@@ -4,5 +4,4 @@
*--------------------------------------------------------------------------------------------*/
/// <reference path="../../../../src/vs/vscode.d.ts" />
/// <reference types='@types/mocha'/>
/// <reference types='@types/node'/>
@@ -350,7 +350,7 @@ suite('window namespace tests', () => {
});
test('showWorkspaceFolderPick', function () {
const p = (<any>window).showWorkspaceFolderPick(undefined);
const p = window.showWorkspaceFolderPick(undefined);
return commands.executeCommand('workbench.action.acceptSelectedQuickOpenItem').then(() => {
return p.then(workspace => {
+2 -1
View File
@@ -3,11 +3,12 @@
"module": "commonjs",
"target": "ES5",
"outDir": "out",
"noUnusedLocals": true,
"lib": [
"es2015"
],
"sourceMap": true,
"strictNullChecks": true
"strict": true
},
"include": [
"src/**/*"
@@ -5,6 +5,7 @@
'use strict';
import 'mocha';
import * as assert from 'assert';
import { commands, Uri } from 'vscode';
import { join, basename, normalize, dirname } from 'path';
-1
View File
@@ -3,5 +3,4 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
/// <reference types='@types/mocha'/>
/// <reference types='@types/node'/>
@@ -3,6 +3,7 @@
"module": "commonjs",
"target": "ES5",
"outDir": "out",
"noUnusedLocals": true,
"lib": [
"es2015"
],
+1 -1
View File
@@ -591,7 +591,7 @@
"xterm": {
"version": "2.9.1",
"from": "Tyriar/xterm.js#vscode-release/1.19",
"resolved": "git+https://github.com/Tyriar/xterm.js.git#004d47b7255f0d5eea4093e6a336a2da3157bc8d"
"resolved": "git+https://github.com/Tyriar/xterm.js.git#d242c552cb5c88125ac257ccaebed7fe336d9266"
},
"yauzl": {
"version": "2.8.0",
+2 -2
View File
@@ -85,7 +85,7 @@
"gulp-shell": "^0.5.2",
"gulp-sourcemaps": "^1.11.0",
"gulp-tsb": "2.0.4",
"gulp-tslint": "^7.0.1",
"gulp-tslint": "^8.1.2",
"gulp-uglify": "^3.0.0",
"gulp-util": "^3.0.6",
"gulp-vinyl-zip": "^1.2.2",
@@ -107,7 +107,7 @@
"rimraf": "^2.2.8",
"sinon": "^1.17.2",
"source-map": "^0.4.4",
"tslint": "^4.3.1",
"tslint": "^5.8.0",
"typescript": "2.6.1",
"typescript-formatter": "4.0.1",
"uglify-es": "^3.0.18",
+2
View File
@@ -10,6 +10,8 @@
"experimentalDecorators": true,
"declaration": true,
"noImplicitReturns": true,
"noUnusedLocals": true,
"noImplicitThis": true,
"baseUrl": ".",
"typeRoots": [
"typings"
+8 -8
View File
@@ -559,9 +559,9 @@ export class Builder implements IDisposable {
/**
* Registers listener on event types on the current element.
*/
public on(type: string, fn: (e: Event, builder: Builder, unbind: IDisposable) => void, listenerToUnbindContainer?: IDisposable[], useCapture?: boolean): Builder;
public on(typeArray: string[], fn: (e: Event, builder: Builder, unbind: IDisposable) => void, listenerToUnbindContainer?: IDisposable[], useCapture?: boolean): Builder;
public on(arg1: any, fn: (e: Event, builder: Builder, unbind: IDisposable) => void, listenerToUnbindContainer?: IDisposable[], useCapture?: boolean): Builder {
public on<E extends Event = Event>(type: string, fn: (e: E, builder: Builder, unbind: IDisposable) => void, listenerToUnbindContainer?: IDisposable[], useCapture?: boolean): Builder;
public on<E extends Event = Event>(typeArray: string[], fn: (e: E, builder: Builder, unbind: IDisposable) => void, listenerToUnbindContainer?: IDisposable[], useCapture?: boolean): Builder;
public on<E extends Event = Event>(arg1: any, fn: (e: E, builder: Builder, unbind: IDisposable) => void, listenerToUnbindContainer?: IDisposable[], useCapture?: boolean): Builder {
// Event Type Array
if (types.isArray(arg1)) {
@@ -575,7 +575,7 @@ export class Builder implements IDisposable {
let type = arg1;
// Add Listener
let unbind: IDisposable = DOM.addDisposableListener(this.currentElement, type, (e: Event) => {
let unbind: IDisposable = DOM.addDisposableListener(this.currentElement, type, (e) => {
fn(e, this, unbind); // Pass in Builder as Second Argument
}, useCapture || false);
@@ -641,9 +641,9 @@ export class Builder implements IDisposable {
* Registers listener on event types on the current element and removes
* them after first invocation.
*/
public once(type: string, fn: (e: Event, builder: Builder, unbind: IDisposable) => void, listenerToUnbindContainer?: IDisposable[], useCapture?: boolean): Builder;
public once(typesArray: string[], fn: (e: Event, builder: Builder, unbind: IDisposable) => void, listenerToUnbindContainer?: IDisposable[], useCapture?: boolean): Builder;
public once(arg1: any, fn: (e: Event, builder: Builder, unbind: IDisposable) => void, listenerToUnbindContainer?: IDisposable[], useCapture?: boolean): Builder {
public once<E extends Event = Event>(type: string, fn: (e: E, builder: Builder, unbind: IDisposable) => void, listenerToUnbindContainer?: IDisposable[], useCapture?: boolean): Builder;
public once<E extends Event = Event>(typesArray: string[], fn: (e: E, builder: Builder, unbind: IDisposable) => void, listenerToUnbindContainer?: IDisposable[], useCapture?: boolean): Builder;
public once<E extends Event = Event>(arg1: any, fn: (e: E, builder: Builder, unbind: IDisposable) => void, listenerToUnbindContainer?: IDisposable[], useCapture?: boolean): Builder {
// Event Type Array
if (types.isArray(arg1)) {
@@ -657,7 +657,7 @@ export class Builder implements IDisposable {
let type = arg1;
// Add Listener
let unbind: IDisposable = DOM.addDisposableListener(this.currentElement, type, (e: Event) => {
let unbind: IDisposable = DOM.addDisposableListener(this.currentElement, type, (e) => {
fn(e, this, unbind); // Pass in Builder as Second Argument
unbind.dispose();
}, useCapture || false);
+7 -7
View File
@@ -413,18 +413,18 @@ class AnimationFrameQueueItem implements IDisposable {
/**
* Add a throttled listener. `handler` is fired at most every 16ms or with the next animation frame (if browser supports it).
*/
export interface IEventMerger<R> {
(lastEvent: R, currentEvent: Event): R;
export interface IEventMerger<R, E> {
(lastEvent: R, currentEvent: E): R;
}
const MINIMUM_TIME_MS = 16;
const DEFAULT_EVENT_MERGER: IEventMerger<Event> = function (lastEvent: Event, currentEvent: Event) {
const DEFAULT_EVENT_MERGER: IEventMerger<Event, Event> = function (lastEvent: Event, currentEvent: Event) {
return currentEvent;
};
class TimeoutThrottledDomListener<R> extends Disposable {
class TimeoutThrottledDomListener<R, E extends Event> extends Disposable {
constructor(node: any, type: string, handler: (event: R) => void, eventMerger: IEventMerger<R> = <any>DEFAULT_EVENT_MERGER, minimumTimeMs: number = MINIMUM_TIME_MS) {
constructor(node: any, type: string, handler: (event: R) => void, eventMerger: IEventMerger<R, E> = <any>DEFAULT_EVENT_MERGER, minimumTimeMs: number = MINIMUM_TIME_MS) {
super();
let lastEvent: R = null;
@@ -452,8 +452,8 @@ class TimeoutThrottledDomListener<R> extends Disposable {
}
}
export function addDisposableThrottledListener<R>(node: any, type: string, handler: (event: R) => void, eventMerger?: IEventMerger<R>, minimumTimeMs?: number): IDisposable {
return new TimeoutThrottledDomListener<R>(node, type, handler, eventMerger, minimumTimeMs);
export function addDisposableThrottledListener<R, E extends Event = Event>(node: any, type: string, handler: (event: R) => void, eventMerger?: IEventMerger<R, E>, minimumTimeMs?: number): IDisposable {
return new TimeoutThrottledDomListener<R, E>(node, type, handler, eventMerger, minimumTimeMs);
}
export function getComputedStyle(el: HTMLElement): CSSStyleDeclaration {

Some files were not shown because too many files have changed in this diff Show More