From 2f69c55eac23020b2dd69063e9277190e76ff316 Mon Sep 17 00:00:00 2001 From: chemzqm Date: Sun, 14 Oct 2018 13:58:21 +0800 Subject: [PATCH] support remove semicolons on format --- package.json | 12 ++++- src/server/features/completionItemProvider.ts | 2 +- .../features/fileConfigurationManager.ts | 6 +++ src/server/features/formatting.ts | 9 +++- src/server/utils/semicolon.ts | 52 +++++++++++++++++++ yarn.lock | 10 ++++ 6 files changed, 87 insertions(+), 4 deletions(-) create mode 100644 src/server/utils/semicolon.ts diff --git a/package.json b/package.json index ac16efe..eaadadd 100644 --- a/package.json +++ b/package.json @@ -175,6 +175,10 @@ "relative" ] }, + "typescript.preferences.noSemicolons": { + "type": "boolean", + "default": false + }, "typescript.preferences.suggestionActions.enabled": { "type": "boolean", "default": true @@ -283,6 +287,10 @@ "relative" ] }, + "javascript.preferences.noSemicolons": { + "type": "boolean", + "default": false + }, "javascript.preferences.suggestionActions.enabled": { "type": "boolean", "default": true @@ -389,9 +397,11 @@ "tslint": "^5.11.0" }, "dependencies": { - "typescript": "^3.1.3", + "@types/fast-diff": "^1.1.0", + "fast-diff": "^1.2.0", "semver": "^5.6.0", "tslib": "^1.9.3", + "typescript": "^3.1.3", "vscode-languageserver-protocol": "^3.13.0", "vscode-uri": "^1.0.6", "which": "^1.3.1" diff --git a/src/server/features/completionItemProvider.ts b/src/server/features/completionItemProvider.ts index 4ca8cd6..e446194 100644 --- a/src/server/features/completionItemProvider.ts +++ b/src/server/features/completionItemProvider.ts @@ -122,7 +122,7 @@ export default class TypeScriptCompletionItemProvider implements CompletionItemP const completionItems: CompletionItem[] = [] for (const element of msg) { - if (!shouldExcludeCompletionEntry(element, completeOption)) { + if (shouldExcludeCompletionEntry(element, completeOption)) { continue } const item = convertCompletionEntry( diff --git a/src/server/features/fileConfigurationManager.ts b/src/server/features/fileConfigurationManager.ts index ab59fb9..2685c8c 100644 --- a/src/server/features/fileConfigurationManager.ts +++ b/src/server/features/fileConfigurationManager.ts @@ -135,6 +135,12 @@ export default class FileConfigurationManager { } } + public removeSemicolons(languageId: string): boolean { + const lang = this.isTypeScriptDocument(languageId) ? 'typescript' : 'javascript' + const config = workspace.getConfiguration(`${lang}.preferences`) + return config.get('noSemicolons', false) + } + public getPreferences(language: string): Proto.UserPreferences { if (!this.client.apiVersion.gte(API.v290)) { return {} diff --git a/src/server/features/formatting.ts b/src/server/features/formatting.ts index 48bd388..8d81b41 100644 --- a/src/server/features/formatting.ts +++ b/src/server/features/formatting.ts @@ -2,12 +2,13 @@ * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { CancellationToken, FormattingOptions, Position, Range, TextDocument, TextEdit } from 'vscode-languageserver-protocol' import { commands, workspace } from 'coc.nvim' import { DocumentFormattingEditProvider, DocumentRangeFormattingEditProvider } from 'coc.nvim/lib/provider' +import { CancellationToken, FormattingOptions, Position, Range, TextDocument, TextEdit } from 'vscode-languageserver-protocol' import * as Proto from '../protocol' import { ITypeScriptServiceClient } from '../typescriptService' import { languageIds } from '../utils/languageModeIds' +import { removeSemicolon } from '../utils/semicolon' import * as typeConverters from '../utils/typeConverters' import FileConfigurationManager from './fileConfigurationManager' @@ -52,7 +53,11 @@ export default class TypeScriptFormattingProvider try { const response = await this.client.execute('format', args, token) if (response.body) { - return response.body.map(typeConverters.TextEdit.fromCodeEdit) + let edits = response.body.map(typeConverters.TextEdit.fromCodeEdit) + if (this.formattingOptionsManager.removeSemicolons(document.languageId)) { + return removeSemicolon(document, edits) + } + return edits } } catch { // noop diff --git a/src/server/utils/semicolon.ts b/src/server/utils/semicolon.ts new file mode 100644 index 0000000..c124eb8 --- /dev/null +++ b/src/server/utils/semicolon.ts @@ -0,0 +1,52 @@ +import fastDiff from 'fast-diff' +import { TextDocument, TextEdit } from 'vscode-languageserver-protocol' + +interface Change { + start: number + end: number + newText: string +} + +export function removeSemicolon(document: TextDocument, edits: TextEdit[]): TextEdit[] { + let orig = document.getText() + let content = TextDocument.applyEdits(document, edits) + let result = content.split('\n').map(s => s.replace(/;$/, '')).join('\n') + if (result == content) return edits + let change = getChange(orig, result) + return [{ + range: { + start: document.positionAt(change.start), + end: document.positionAt(change.end) + }, + newText: change.newText + }] +} + +function getChange(oldStr: string, newStr: string): Change { + let result = fastDiff(oldStr, newStr, 1) + let curr = 0 + let start = -1 + let end = -1 + let newText = '' + let remain = '' + for (let item of result) { + let [t, str] = item + // equal + if (t == 0) { + curr = curr + str.length + if (start != -1) remain = remain + str + } else { + if (start == -1) start = curr + if (t == 1) { + newText = newText + remain + str + end = curr + } else { + newText = newText + remain + end = curr + str.length + } + remain = '' + if (t == -1) curr = curr + str.length + } + } + return { start, end, newText } +} diff --git a/yarn.lock b/yarn.lock index a768556..d851d3a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -109,6 +109,11 @@ tslint-config-prettier "^1.6.0" tslint-react "^3.2.0" +"@types/fast-diff@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@types/fast-diff/-/fast-diff-1.1.0.tgz#68c7f476025740b0b6756e51e38b1188dd528b0e" + integrity sha512-doBwHnPAGdE54EiIFc0/v1qHlRVtNTaxgCZOS9SdSGPq91vx3kUKi5fmz/yivW/RAXEOUJYVXtVFQ6IPpqKRWg== + "@types/mkdirp@^0.5.2": version "0.5.2" resolved "https://registry.yarnpkg.com/@types/mkdirp/-/mkdirp-0.5.2.tgz#503aacfe5cc2703d5484326b1b27efa67a339c1f" @@ -355,6 +360,11 @@ fast-diff@^1.1.2: resolved "https://registry.yarnpkg.com/fast-diff/-/fast-diff-1.1.2.tgz#4b62c42b8e03de3f848460b639079920695d0154" integrity sha512-KaJUt+M9t1qaIteSvjc6P3RbMdXsNhK61GRftR6SNxqmhthcd9MGIi4T+o0jD8LUSpSnSKXE20nLtJ3fOHxQig== +fast-diff@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/fast-diff/-/fast-diff-1.2.0.tgz#73ee11982d86caaf7959828d519cfe927fac5f03" + integrity sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w== + fb-watchman@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/fb-watchman/-/fb-watchman-2.0.0.tgz#54e9abf7dfa2f26cd9b1636c588c1afc05de5d58"