mirror of
https://github.com/Microsoft/vscode
synced 2024-08-27 13:00:58 +00:00
JSON formatting often fails at first. Fixes #71652
This commit is contained in:
parent
846cff1e8f
commit
078acb7872
|
@ -8,8 +8,8 @@ import * as fs from 'fs';
|
|||
import * as nls from 'vscode-nls';
|
||||
const localize = nls.loadMessageBundle();
|
||||
|
||||
import { languages, ExtensionContext, IndentAction, Position, TextDocument, Range, CompletionItem, CompletionItemKind, SnippetString, workspace } from 'vscode';
|
||||
import { LanguageClient, LanguageClientOptions, ServerOptions, TransportKind, RequestType, TextDocumentPositionParams } from 'vscode-languageclient';
|
||||
import { languages, ExtensionContext, IndentAction, Position, TextDocument, Range, CompletionItem, CompletionItemKind, SnippetString, workspace, Disposable, FormattingOptions, CancellationToken, ProviderResult, TextEdit } from 'vscode';
|
||||
import { LanguageClient, LanguageClientOptions, ServerOptions, TransportKind, RequestType, TextDocumentPositionParams, DocumentRangeFormattingParams, DocumentRangeFormattingRequest } from 'vscode-languageclient';
|
||||
import { EMPTY_ELEMENTS } from './htmlEmptyTagsShared';
|
||||
import { activateTagClosing } from './tagClosing';
|
||||
import TelemetryReporter from 'vscode-extension-telemetry';
|
||||
|
@ -50,6 +50,8 @@ export function activate(context: ExtensionContext) {
|
|||
let documentSelector = ['html', 'handlebars'];
|
||||
let embeddedLanguages = { css: true, javascript: true };
|
||||
|
||||
let rangeFormatting: Disposable | undefined = undefined;
|
||||
|
||||
let dataPaths = [
|
||||
...getCustomDataPathsInAllWorkspaces(workspace.workspaceFolders),
|
||||
...getCustomDataPathsFromAllExtensions()
|
||||
|
@ -63,8 +65,9 @@ export function activate(context: ExtensionContext) {
|
|||
},
|
||||
initializationOptions: {
|
||||
embeddedLanguages,
|
||||
dataPaths
|
||||
}
|
||||
dataPaths,
|
||||
provideFormatter: false, // tell the server to not provide formatting capability and ignore the `html.format.enable` setting.
|
||||
},
|
||||
};
|
||||
|
||||
// Create the language client and start the client.
|
||||
|
@ -87,8 +90,38 @@ export function activate(context: ExtensionContext) {
|
|||
}
|
||||
});
|
||||
toDispose.push(disposable);
|
||||
|
||||
// manually register / deregister format provider based on the `html.format.enable` setting avoiding issues with late registration. See #71652.
|
||||
updateFormatterRegistration();
|
||||
toDispose.push({ dispose: () => rangeFormatting && rangeFormatting.dispose() });
|
||||
toDispose.push(workspace.onDidChangeConfiguration(e => e.affectsConfiguration('html.format.enable') && updateFormatterRegistration()));
|
||||
});
|
||||
|
||||
function updateFormatterRegistration() {
|
||||
const formatEnabled = workspace.getConfiguration().get('html.format.enable');
|
||||
if (!formatEnabled && rangeFormatting) {
|
||||
rangeFormatting.dispose();
|
||||
rangeFormatting = undefined;
|
||||
} else if (formatEnabled && !rangeFormatting) {
|
||||
rangeFormatting = languages.registerDocumentRangeFormattingEditProvider(documentSelector, {
|
||||
provideDocumentRangeFormattingEdits(document: TextDocument, range: Range, options: FormattingOptions, token: CancellationToken): ProviderResult<TextEdit[]> {
|
||||
let params: DocumentRangeFormattingParams = {
|
||||
textDocument: client.code2ProtocolConverter.asTextDocumentIdentifier(document),
|
||||
range: client.code2ProtocolConverter.asRange(range),
|
||||
options: client.code2ProtocolConverter.asFormattingOptions(options)
|
||||
};
|
||||
return client.sendRequest(DocumentRangeFormattingRequest.type, params, token).then(
|
||||
client.protocol2CodeConverter.asTextEdits,
|
||||
(error) => {
|
||||
client.logFailedRequest(DocumentRangeFormattingRequest.type, error);
|
||||
return Promise.resolve([]);
|
||||
}
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
languages.setLanguageConfiguration('html', {
|
||||
indentationRules: {
|
||||
increaseIndentPattern: /<(?!\?|(?:area|base|br|col|frame|hr|html|img|input|link|meta|param)\b|[^>]*\/>)([-_\.A-Za-z0-9]+)(?=\s|>)\b[^>]*>(?!.*<\/\1>)|<!--(?!.*-->)|\{[^}"']*$/,
|
||||
|
|
|
@ -49,7 +49,7 @@ let workspaceFolders: WorkspaceFolder[] = [];
|
|||
let languageModes: LanguageModes;
|
||||
|
||||
let clientSnippetSupport = false;
|
||||
let clientDynamicRegisterSupport = false;
|
||||
let dynamicFormatterRegistration = false;
|
||||
let scopedSettingsSupport = false;
|
||||
let workspaceFoldersSupport = false;
|
||||
let foldingRangeLimit = Number.MAX_VALUE;
|
||||
|
@ -118,7 +118,7 @@ connection.onInitialize((params: InitializeParams): InitializeResult => {
|
|||
}
|
||||
|
||||
clientSnippetSupport = getClientCapability('textDocument.completion.completionItem.snippetSupport', false);
|
||||
clientDynamicRegisterSupport = getClientCapability('workspace.rangeFormatting.dynamicRegistration', false);
|
||||
dynamicFormatterRegistration = getClientCapability('workspace.rangeFormatting.dynamicRegistration', false) && (typeof params.initializationOptions.provideFormatter !== 'boolean');
|
||||
scopedSettingsSupport = getClientCapability('workspace.configuration', false);
|
||||
workspaceFoldersSupport = getClientCapability('workspace.workspaceFolders', false);
|
||||
foldingRangeLimit = getClientCapability('textDocument.foldingRange.rangeLimit', Number.MAX_VALUE);
|
||||
|
@ -128,7 +128,7 @@ connection.onInitialize((params: InitializeParams): InitializeResult => {
|
|||
completionProvider: clientSnippetSupport ? { resolveProvider: true, triggerCharacters: ['.', ':', '<', '"', '=', '/'] } : undefined,
|
||||
hoverProvider: true,
|
||||
documentHighlightProvider: true,
|
||||
documentRangeFormattingProvider: false,
|
||||
documentRangeFormattingProvider: params.initializationOptions.provideFormatter === true,
|
||||
documentLinkProvider: { resolveProvider: false },
|
||||
documentSymbolProvider: true,
|
||||
definitionProvider: true,
|
||||
|
@ -136,7 +136,7 @@ connection.onInitialize((params: InitializeParams): InitializeResult => {
|
|||
referencesProvider: true,
|
||||
colorProvider: {},
|
||||
foldingRangeProvider: true,
|
||||
selectionRangeProvider: true
|
||||
selectionRangeProvider: true,
|
||||
};
|
||||
return { capabilities };
|
||||
});
|
||||
|
@ -171,7 +171,7 @@ connection.onDidChangeConfiguration((change) => {
|
|||
documents.all().forEach(triggerValidation);
|
||||
|
||||
// dynamically enable & disable the formatter
|
||||
if (clientDynamicRegisterSupport) {
|
||||
if (dynamicFormatterRegistration) {
|
||||
const enableFormatter = globalSettings && globalSettings.html && globalSettings.html.format && globalSettings.html.format.enable;
|
||||
if (enableFormatter) {
|
||||
if (!formatterRegistration) {
|
||||
|
|
|
@ -10,8 +10,8 @@ import { xhr, XHRResponse, getErrorStatusDescription } from 'request-light';
|
|||
|
||||
const localize = nls.loadMessageBundle();
|
||||
|
||||
import { workspace, window, languages, commands, ExtensionContext, extensions, Uri, LanguageConfiguration, Diagnostic, StatusBarAlignment, TextEditor } from 'vscode';
|
||||
import { LanguageClient, LanguageClientOptions, RequestType, ServerOptions, TransportKind, NotificationType, DidChangeConfigurationNotification, HandleDiagnosticsSignature, ResponseError } from 'vscode-languageclient';
|
||||
import { workspace, window, languages, commands, ExtensionContext, extensions, Uri, LanguageConfiguration, Diagnostic, StatusBarAlignment, TextEditor, TextDocument, FormattingOptions, CancellationToken, ProviderResult, TextEdit, Range, Disposable } from 'vscode';
|
||||
import { LanguageClient, LanguageClientOptions, RequestType, ServerOptions, TransportKind, NotificationType, DidChangeConfigurationNotification, HandleDiagnosticsSignature, ResponseError, DocumentRangeFormattingParams, DocumentRangeFormattingRequest } from 'vscode-languageclient';
|
||||
import TelemetryReporter from 'vscode-extension-telemetry';
|
||||
|
||||
import { hash } from './utils/hash';
|
||||
|
@ -65,6 +65,8 @@ export function activate(context: ExtensionContext) {
|
|||
|
||||
let toDispose = context.subscriptions;
|
||||
|
||||
let rangeFormatting: Disposable | undefined = undefined;
|
||||
|
||||
let packageInfo = getPackageInfo(context);
|
||||
telemetryReporter = packageInfo && new TelemetryReporter(packageInfo.name, packageInfo.version, packageInfo.aiKey);
|
||||
|
||||
|
@ -101,7 +103,8 @@ export function activate(context: ExtensionContext) {
|
|||
// Register the server for json documents
|
||||
documentSelector,
|
||||
initializationOptions: {
|
||||
handledSchemaProtocols: ['file'] // language server only loads file-URI. Fetching schemas with other protocols ('http'...) are made on the client.
|
||||
handledSchemaProtocols: ['file'], // language server only loads file-URI. Fetching schemas with other protocols ('http'...) are made on the client.
|
||||
provideFormatter: false // tell the server to not provide formatting capability and ignore the `json.format.enable` setting.
|
||||
},
|
||||
synchronize: {
|
||||
// Synchronize the setting section 'json' to the server
|
||||
|
@ -224,10 +227,13 @@ export function activate(context: ExtensionContext) {
|
|||
extensions.onDidChange(_ => {
|
||||
client.sendNotification(SchemaAssociationNotification.type, getSchemaAssociation(context));
|
||||
});
|
||||
|
||||
// manually register / deregister format provider based on the `html.format.enable` setting avoiding issues with late registration. See #71652.
|
||||
updateFormatterRegistration();
|
||||
toDispose.push({ dispose: () => rangeFormatting && rangeFormatting.dispose() });
|
||||
toDispose.push(workspace.onDidChangeConfiguration(e => e.affectsConfiguration('html.format.enable') && updateFormatterRegistration()));
|
||||
});
|
||||
|
||||
|
||||
|
||||
let languageConfiguration: LanguageConfiguration = {
|
||||
wordPattern: /("(?:[^\\\"]*(?:\\.)?)*"?)|[^\s{}\[\],:]+/,
|
||||
indentationRules: {
|
||||
|
@ -237,8 +243,35 @@ export function activate(context: ExtensionContext) {
|
|||
};
|
||||
languages.setLanguageConfiguration('json', languageConfiguration);
|
||||
languages.setLanguageConfiguration('jsonc', languageConfiguration);
|
||||
|
||||
function updateFormatterRegistration() {
|
||||
const formatEnabled = workspace.getConfiguration().get('json.format.enable');
|
||||
if (!formatEnabled && rangeFormatting) {
|
||||
rangeFormatting.dispose();
|
||||
rangeFormatting = undefined;
|
||||
} else if (formatEnabled && !rangeFormatting) {
|
||||
rangeFormatting = languages.registerDocumentRangeFormattingEditProvider(documentSelector, {
|
||||
provideDocumentRangeFormattingEdits(document: TextDocument, range: Range, options: FormattingOptions, token: CancellationToken): ProviderResult<TextEdit[]> {
|
||||
let params: DocumentRangeFormattingParams = {
|
||||
textDocument: client.code2ProtocolConverter.asTextDocumentIdentifier(document),
|
||||
range: client.code2ProtocolConverter.asRange(range),
|
||||
options: client.code2ProtocolConverter.asFormattingOptions(options)
|
||||
};
|
||||
return client.sendRequest(DocumentRangeFormattingRequest.type, params, token).then(
|
||||
client.protocol2CodeConverter.asTextEdits,
|
||||
(error) => {
|
||||
client.logFailedRequest(DocumentRangeFormattingRequest.type, error);
|
||||
return Promise.resolve([]);
|
||||
}
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
export function deactivate(): Promise<any> {
|
||||
return telemetryReporter ? telemetryReporter.dispose() : Promise.resolve(null);
|
||||
}
|
||||
|
@ -286,7 +319,6 @@ function getSettings(): Settings {
|
|||
proxyStrictSSL: httpSettings.get('proxyStrictSSL')
|
||||
},
|
||||
json: {
|
||||
format: workspace.getConfiguration('json').get('format'),
|
||||
schemas: [],
|
||||
}
|
||||
};
|
||||
|
|
|
@ -12,7 +12,7 @@ The JSON Language server provides language-specific smarts for editing, validati
|
|||
|
||||
The JSON language server supports requests on documents of language id `json` and `jsonc`.
|
||||
- `json` documents are parsed and validated following the [JSON specification](https://tools.ietf.org/html/rfc7159).
|
||||
- `jsonc` documents additionally accept single line (`//`) and multi-line comments (`/* ... */`) and accepts trailing commas. JSONC is a VSCode specific file format, intended for VSCode configuration files, without any aspirations to define a new common file format.
|
||||
- `jsonc` documents additionally accept single line (`//`) and multi-line comments (`/* ... */`). JSONC is a VSCode specific file format, intended for VSCode configuration files, without any aspirations to define a new common file format.
|
||||
|
||||
The server implements the following capabilities of the language server protocol:
|
||||
|
||||
|
@ -40,6 +40,13 @@ The JSON language server has the following dependencies on the client's capabili
|
|||
|
||||
## Configuration
|
||||
|
||||
### Initialization options
|
||||
|
||||
The client can send the following initialization options to the server:
|
||||
|
||||
- `provideFormatter: boolean | undefined`. If defined, the value defines wheter the server provides the `documentRangeFormattingProvider` capability on initialization. If undefined, the setting `json.format.enable` is used to determined wheter formatting is provided. The formatter will then be registered through dynamic registration. If the client does not support dynamic registration, no formatter will be available.
|
||||
- `handledSchemaProtocols`: The URI schemas handles by the server. See section `Schema configuration` below.
|
||||
|
||||
### Settings
|
||||
|
||||
Clients may send a `workspace/didChangeConfiguration` notification to notify the server of settings changes.
|
||||
|
@ -51,7 +58,7 @@ The server supports the following settings:
|
|||
|
||||
- json
|
||||
- `format`
|
||||
- `enable`: Whether the server should register the formatting support. This option is only applicable if the client supports *dynamicRegistration* for *rangeFormatting*
|
||||
- `enable`: Whether the server should register the formatting support. This option is only applicable if the client supports *dynamicRegistration* for *rangeFormatting* and `initializationOptions.provideFormatter` is not defined.
|
||||
- `schema`: Configures association of file names to schema URL or schemas and/or associations of schema URL to schema content.
|
||||
- `fileMatch`: an array or file names or paths (separated by `/`). `*` can be used as a wildcard.
|
||||
- `url`: The URL of the schema, optional when also a schema is provided.
|
||||
|
|
|
@ -114,7 +114,7 @@ const documents: TextDocuments = new TextDocuments();
|
|||
documents.listen(connection);
|
||||
|
||||
let clientSnippetSupport = false;
|
||||
let clientDynamicRegisterSupport = false;
|
||||
let dynamicFormatterRegistration = false;
|
||||
let foldingRangeLimit = Number.MAX_VALUE;
|
||||
let hierarchicalDocumentSymbolSupport = false;
|
||||
|
||||
|
@ -144,7 +144,7 @@ connection.onInitialize((params: InitializeParams): InitializeResult => {
|
|||
}
|
||||
|
||||
clientSnippetSupport = getClientCapability('textDocument.completion.completionItem.snippetSupport', false);
|
||||
clientDynamicRegisterSupport = getClientCapability('workspace.rangeFormatting.dynamicRegistration', false);
|
||||
dynamicFormatterRegistration = getClientCapability('workspace.rangeFormatting.dynamicRegistration', false) && (params.initializationOptions.provideFormatter === undefined);
|
||||
foldingRangeLimit = getClientCapability('textDocument.foldingRange.rangeLimit', Number.MAX_VALUE);
|
||||
hierarchicalDocumentSymbolSupport = getClientCapability('textDocument.documentSymbol.hierarchicalDocumentSymbolSupport', false);
|
||||
const capabilities: ServerCapabilities = {
|
||||
|
@ -156,7 +156,8 @@ connection.onInitialize((params: InitializeParams): InitializeResult => {
|
|||
documentRangeFormattingProvider: false,
|
||||
colorProvider: {},
|
||||
foldingRangeProvider: true,
|
||||
selectionRangeProvider: true
|
||||
selectionRangeProvider: true,
|
||||
documentFormattingProvider: params.initializationOptions.provideFormatter === true
|
||||
};
|
||||
|
||||
return { capabilities };
|
||||
|
@ -195,7 +196,7 @@ connection.onDidChangeConfiguration((change) => {
|
|||
updateConfiguration();
|
||||
|
||||
// dynamically enable & disable the formatter
|
||||
if (clientDynamicRegisterSupport) {
|
||||
if (dynamicFormatterRegistration) {
|
||||
const enableFormatter = settings && settings.json && settings.json.format && settings.json.format.enable;
|
||||
if (enableFormatter) {
|
||||
if (!formatterRegistration) {
|
||||
|
|
Loading…
Reference in a new issue