mirror of
https://github.com/Microsoft/vscode
synced 2024-10-12 06:17:18 +00:00
[json] update service (folding api for #47808)
This commit is contained in:
parent
d516e62375
commit
6c223050d7
|
@ -13,7 +13,7 @@
|
|||
"dependencies": {
|
||||
"jsonc-parser": "^2.0.0-next.1",
|
||||
"request-light": "^0.2.2",
|
||||
"vscode-json-languageservice": "^3.0.13",
|
||||
"vscode-json-languageservice": "^3.1.2-next.1",
|
||||
"vscode-languageserver": "^4.0.0",
|
||||
"vscode-languageserver-protocol-foldingprovider": "^1.0.1",
|
||||
"vscode-nls": "^3.2.2",
|
||||
|
@ -33,7 +33,6 @@
|
|||
"install-service-local": "yarn link vscode-json-languageservice",
|
||||
"install-server-next": "yarn add vscode-languageserver@next",
|
||||
"install-server-local": "yarn link vscode-languageserver-server",
|
||||
"test": "npm run compile && ../../../node_modules/.bin/mocha",
|
||||
"version": "git commit -m \"JSON Language Server $npm_package_version\" package.json"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,117 +0,0 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* 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 { TextDocument, Position, CancellationToken } from 'vscode-languageserver';
|
||||
import { createScanner, SyntaxKind, ScanError } from 'jsonc-parser';
|
||||
import { FoldingRangeType, FoldingRange, FoldingRangeList } from 'vscode-languageserver-protocol-foldingprovider';
|
||||
|
||||
export function getFoldingRegions(document: TextDocument, maxRanges: number | undefined, cancellationToken: CancellationToken | null) {
|
||||
let ranges: FoldingRange[] = [];
|
||||
let nestingLevels: number[] = [];
|
||||
let stack: FoldingRange[] = [];
|
||||
let prevStart = -1;
|
||||
let scanner = createScanner(document.getText(), false);
|
||||
let token = scanner.scan();
|
||||
|
||||
function addRange(range: FoldingRange) {
|
||||
ranges.push(range);
|
||||
nestingLevels.push(stack.length);
|
||||
}
|
||||
|
||||
while (token !== SyntaxKind.EOF) {
|
||||
if (cancellationToken && cancellationToken.isCancellationRequested) {
|
||||
return null;
|
||||
}
|
||||
switch (token) {
|
||||
case SyntaxKind.OpenBraceToken:
|
||||
case SyntaxKind.OpenBracketToken: {
|
||||
let startLine = document.positionAt(scanner.getTokenOffset()).line;
|
||||
let range = { startLine, endLine: startLine, type: token === SyntaxKind.OpenBraceToken ? 'object' : 'array' };
|
||||
stack.push(range);
|
||||
break;
|
||||
}
|
||||
case SyntaxKind.CloseBraceToken:
|
||||
case SyntaxKind.CloseBracketToken: {
|
||||
let type = token === SyntaxKind.CloseBraceToken ? 'object' : 'array';
|
||||
if (stack.length > 0 && stack[stack.length - 1].type === type) {
|
||||
let range = stack.pop();
|
||||
let line = document.positionAt(scanner.getTokenOffset()).line;
|
||||
if (range && line > range.startLine + 1 && prevStart !== range.startLine) {
|
||||
range.endLine = line - 1;
|
||||
addRange(range);
|
||||
prevStart = range.startLine;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case SyntaxKind.BlockCommentTrivia: {
|
||||
let startLine = document.positionAt(scanner.getTokenOffset()).line;
|
||||
let endLine = document.positionAt(scanner.getTokenOffset() + scanner.getTokenLength()).line;
|
||||
if (scanner.getTokenError() === ScanError.UnexpectedEndOfComment && startLine + 1 < document.lineCount) {
|
||||
scanner.setPosition(document.offsetAt(Position.create(startLine + 1, 0)));
|
||||
} else {
|
||||
if (startLine < endLine) {
|
||||
addRange({ startLine, endLine, type: FoldingRangeType.Comment });
|
||||
prevStart = startLine;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case SyntaxKind.LineCommentTrivia: {
|
||||
let text = document.getText().substr(scanner.getTokenOffset(), scanner.getTokenLength());
|
||||
let m = text.match(/^\/\/\s*#(region\b)|(endregion\b)/);
|
||||
if (m) {
|
||||
let line = document.positionAt(scanner.getTokenOffset()).line;
|
||||
if (m[1]) { // start pattern match
|
||||
let range = { startLine: line, endLine: line, type: FoldingRangeType.Region };
|
||||
stack.push(range);
|
||||
} else {
|
||||
let i = stack.length - 1;
|
||||
while (i >= 0 && stack[i].type !== FoldingRangeType.Region) {
|
||||
i--;
|
||||
}
|
||||
if (i >= 0) {
|
||||
let range = stack[i];
|
||||
stack.length = i;
|
||||
if (line > range.startLine && prevStart !== range.startLine) {
|
||||
range.endLine = line;
|
||||
addRange(range);
|
||||
prevStart = range.startLine;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
token = scanner.scan();
|
||||
}
|
||||
if (maxRanges && ranges.length > maxRanges) {
|
||||
let counts: number[] = [];
|
||||
for (let level of nestingLevels) {
|
||||
if (level < 30) {
|
||||
counts[level] = (counts[level] || 0) + 1;
|
||||
}
|
||||
}
|
||||
let entries = 0;
|
||||
let maxLevel = 0;
|
||||
for (let i = 0; i < counts.length; i++) {
|
||||
let n = counts[i];
|
||||
if (n) {
|
||||
if (n + entries > maxRanges) {
|
||||
maxLevel = i;
|
||||
break;
|
||||
}
|
||||
entries += n;
|
||||
}
|
||||
}
|
||||
ranges = ranges.filter((r, index) => nestingLevels[index] < maxLevel);
|
||||
}
|
||||
return <FoldingRangeList>{ ranges };
|
||||
}
|
|
@ -18,7 +18,6 @@ import { startsWith } from './utils/strings';
|
|||
import { formatError, runSafe, runSafeAsync } from './utils/runner';
|
||||
import { JSONDocument, JSONSchema, getLanguageService, DocumentLanguageSettings, SchemaConfiguration } from 'vscode-json-languageservice';
|
||||
import { getLanguageModelCache } from './languageModelCache';
|
||||
import { getFoldingRegions } from './jsonFolding';
|
||||
|
||||
import { FoldingRangesRequest, FoldingProviderServerCapabilities } from 'vscode-languageserver-protocol-foldingprovider';
|
||||
|
||||
|
@ -369,7 +368,7 @@ connection.onRequest(FoldingRangesRequest.type, (params, token) => {
|
|||
return runSafe(() => {
|
||||
let document = documents.get(params.textDocument.uri);
|
||||
if (document) {
|
||||
return getFoldingRegions(document, params.maxRanges, token);
|
||||
return languageService.getFoldingRanges(document, { maxRanges: params.maxRanges });
|
||||
}
|
||||
return null;
|
||||
}, null, `Error while computing folding ranges for ${params.textDocument.uri}`, token);
|
||||
|
|
|
@ -1,144 +0,0 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* 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 'mocha';
|
||||
import * as assert from 'assert';
|
||||
import { TextDocument } from 'vscode-languageserver';
|
||||
import { getFoldingRegions } from '../jsonFolding';
|
||||
|
||||
interface ExpectedIndentRange {
|
||||
startLine: number;
|
||||
endLine: number;
|
||||
type?: string;
|
||||
}
|
||||
|
||||
function assertRanges(lines: string[], expected: ExpectedIndentRange[], nRanges?: number): void {
|
||||
let document = TextDocument.create('test://foo/bar.json', 'json', 1, lines.join('\n'));
|
||||
let actual = getFoldingRegions(document, nRanges, null)!.ranges;
|
||||
|
||||
let actualRanges = [];
|
||||
for (let i = 0; i < actual.length; i++) {
|
||||
actualRanges[i] = r(actual[i].startLine, actual[i].endLine, actual[i].type);
|
||||
}
|
||||
actualRanges = actualRanges.sort((r1, r2) => r1.startLine - r2.startLine);
|
||||
assert.deepEqual(actualRanges, expected);
|
||||
}
|
||||
|
||||
function r(startLine: number, endLine: number, type?: string): ExpectedIndentRange {
|
||||
return { startLine, endLine, type };
|
||||
}
|
||||
|
||||
suite('JSON Folding', () => {
|
||||
test('Fold one level', () => {
|
||||
let input = [
|
||||
/*0*/'{',
|
||||
/*1*/'"foo":"bar"',
|
||||
/*2*/'}'
|
||||
];
|
||||
assertRanges(input, [r(0, 1, 'object')]);
|
||||
});
|
||||
|
||||
test('Fold two level', () => {
|
||||
let input = [
|
||||
/*0*/'[',
|
||||
/*1*/'{',
|
||||
/*2*/'"foo":"bar"',
|
||||
/*3*/'}',
|
||||
/*4*/']'
|
||||
];
|
||||
assertRanges(input, [r(0, 3, 'array'), r(1, 2, 'object')]);
|
||||
});
|
||||
|
||||
test('Fold Arrays', () => {
|
||||
let input = [
|
||||
/*0*/'[',
|
||||
/*1*/'[',
|
||||
/*2*/'],[',
|
||||
/*3*/'1',
|
||||
/*4*/']',
|
||||
/*5*/']'
|
||||
];
|
||||
assertRanges(input, [r(0, 4, 'array'), r(2, 3, 'array')]);
|
||||
});
|
||||
|
||||
test('Filter start on same line', () => {
|
||||
let input = [
|
||||
/*0*/'[[',
|
||||
/*1*/'[',
|
||||
/*2*/'],[',
|
||||
/*3*/'1',
|
||||
/*4*/']',
|
||||
/*5*/']]'
|
||||
];
|
||||
assertRanges(input, [r(0, 4, 'array'), r(2, 3, 'array')]);
|
||||
});
|
||||
|
||||
test('Fold comment', () => {
|
||||
let input = [
|
||||
/*0*/'/*',
|
||||
/*1*/' multi line',
|
||||
/*2*/'*/',
|
||||
];
|
||||
assertRanges(input, [r(0, 2, 'comment')]);
|
||||
});
|
||||
|
||||
test('Incomplete comment', () => {
|
||||
let input = [
|
||||
/*0*/'/*',
|
||||
/*1*/'{',
|
||||
/*2*/'"foo":"bar"',
|
||||
/*3*/'}',
|
||||
];
|
||||
assertRanges(input, [r(1, 2, 'object')]);
|
||||
});
|
||||
|
||||
test('Fold regions', () => {
|
||||
let input = [
|
||||
/*0*/'// #region',
|
||||
/*1*/'{',
|
||||
/*2*/'}',
|
||||
/*3*/'// #endregion',
|
||||
];
|
||||
assertRanges(input, [r(0, 3, 'region')]);
|
||||
});
|
||||
|
||||
test('Test limit', () => {
|
||||
let input = [
|
||||
/* 0*/'[',
|
||||
/* 1*/' [',
|
||||
/* 2*/' [',
|
||||
/* 3*/' ',
|
||||
/* 4*/' ],',
|
||||
/* 5*/' [',
|
||||
/* 6*/' [',
|
||||
/* 7*/' ',
|
||||
/* 8*/' ],',
|
||||
/* 9*/' [',
|
||||
/*10*/' ',
|
||||
/*11*/' ],',
|
||||
/*12*/' ],',
|
||||
/*13*/' [',
|
||||
/*14*/' ',
|
||||
/*15*/' ],',
|
||||
/*16*/' [',
|
||||
/*17*/' ',
|
||||
/*18*/' ]',
|
||||
/*19*/' ]',
|
||||
/*20*/']',
|
||||
];
|
||||
assertRanges(input, [r(0, 19, 'array'), r(1, 18, 'array'), r(2, 3, 'array'), r(5, 11, 'array'), r(6, 7, 'array'), r(9, 10, 'array'), r(13, 14, 'array'), r(16, 17, 'array')], void 0);
|
||||
assertRanges(input, [r(0, 19, 'array'), r(1, 18, 'array'), r(2, 3, 'array'), r(5, 11, 'array'), r(6, 7, 'array'), r(9, 10, 'array'), r(13, 14, 'array'), r(16, 17, 'array')], 8);
|
||||
assertRanges(input, [r(0, 19, 'array'), r(1, 18, 'array'), r(2, 3, 'array'), r(5, 11, 'array'), r(13, 14, 'array'), r(16, 17, 'array')], 7);
|
||||
assertRanges(input, [r(0, 19, 'array'), r(1, 18, 'array'), r(2, 3, 'array'), r(5, 11, 'array'), r(13, 14, 'array'), r(16, 17, 'array')], 6);
|
||||
assertRanges(input, [r(0, 19, 'array'), r(1, 18, 'array')], 5);
|
||||
assertRanges(input, [r(0, 19, 'array'), r(1, 18, 'array')], 4);
|
||||
assertRanges(input, [r(0, 19, 'array'), r(1, 18, 'array')], 3);
|
||||
assertRanges(input, [r(0, 19, 'array'), r(1, 18, 'array')], 2);
|
||||
assertRanges(input, [r(0, 19, 'array')], 1);
|
||||
});
|
||||
|
||||
});
|
|
@ -52,6 +52,10 @@ https-proxy-agent@2.1.1:
|
|||
agent-base "^4.1.0"
|
||||
debug "^3.1.0"
|
||||
|
||||
jsonc-parser@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/jsonc-parser/-/jsonc-parser-2.0.0.tgz#62ff087a7e753875febf3c55f1fc0cd737c36b5a"
|
||||
|
||||
jsonc-parser@^2.0.0-next.1:
|
||||
version "2.0.0-next.1"
|
||||
resolved "https://registry.yarnpkg.com/jsonc-parser/-/jsonc-parser-2.0.0-next.1.tgz#445a824f765a96abfbb286d759a9b1d226b18088"
|
||||
|
@ -68,11 +72,11 @@ request-light@^0.2.2:
|
|||
https-proxy-agent "2.1.1"
|
||||
vscode-nls "^2.0.2"
|
||||
|
||||
vscode-json-languageservice@^3.0.13:
|
||||
version "3.0.13"
|
||||
resolved "https://registry.yarnpkg.com/vscode-json-languageservice/-/vscode-json-languageservice-3.0.13.tgz#dd1b7ddfd4f5ca16e2a7adcc7d7f9009ac02319a"
|
||||
vscode-json-languageservice@^3.1.2-next.1:
|
||||
version "3.1.2-next.1"
|
||||
resolved "https://registry.yarnpkg.com/vscode-json-languageservice/-/vscode-json-languageservice-3.1.2-next.1.tgz#8acee581c664e2af72ade2f08252aeae9b5918ca"
|
||||
dependencies:
|
||||
jsonc-parser "^2.0.0-next.1"
|
||||
jsonc-parser "^2.0.0"
|
||||
vscode-languageserver-types "^3.6.1"
|
||||
vscode-nls "^3.2.1"
|
||||
vscode-uri "^1.0.3"
|
||||
|
|
Loading…
Reference in a new issue