add command: tsserver.executeAutofix

This commit is contained in:
chemzqm 2019-01-22 16:29:30 +08:00
parent 9da6ce8838
commit b1fcf886cc
4 changed files with 64 additions and 5 deletions

View file

@ -59,6 +59,11 @@
"title": "Run `tsc --watch` for current project in terminal buffer.",
"category": "TSServer",
"command": "tsserver.watchBuild"
},
{
"title": "Fix autofixable problems of current document.",
"category": "TSServer",
"command": "tsserver.executeAutofix"
}
],
"configuration": {

View file

@ -1,6 +1,6 @@
import { commands, ExtensionContext, services, workspace } from 'coc.nvim'
import TsserverService from './server'
import { Command, OpenTsServerLogCommand, ReloadProjectsCommand, TypeScriptGoToProjectConfigCommand } from './server/commands'
import { Command, OpenTsServerLogCommand, AutoFixCommand, ReloadProjectsCommand, TypeScriptGoToProjectConfigCommand } from './server/commands'
import OrganizeImportsCommand from './server/organizeImports'
export async function activate(context: ExtensionContext): Promise<void> {
@ -22,6 +22,7 @@ export async function activate(context: ExtensionContext): Promise<void> {
subscriptions.push(commands.registerCommand(id as string, execute, cmd))
}
registCommand(new AutoFixCommand(service.clientHost))
registCommand(new ReloadProjectsCommand(service.clientHost))
registCommand(new OpenTsServerLogCommand(service.clientHost))
registCommand(new TypeScriptGoToProjectConfigCommand(service.clientHost))

View file

@ -1,8 +1,10 @@
import { diagnosticManager, workspace } from 'coc.nvim'
import { CancellationToken } from 'vscode-languageserver-protocol'
import URI from 'vscode-uri'
import { workspace } from 'coc.nvim'
import { ProjectInfoResponse } from './protocol'
import * as Proto from './protocol'
import TypeScriptServiceClientHost from './typescriptServiceClientHost'
import * as typeConverters from './utils/typeConverters'
import { WorkspaceEdit, TextEdit } from 'vscode-languageserver-types'
export interface Command {
readonly id: string | string[]
@ -54,7 +56,7 @@ async function goToProjectConfig(clientHost: TypeScriptServiceClientHost, uri: s
}
const client = clientHost.serviceClient
const file = client.toPath(uri)
let res: ProjectInfoResponse | undefined
let res: Proto.ProjectInfoResponse | undefined
try {
res = await client.execute('projectInfo', { file, needFileNameList: false }, CancellationToken.None)
} catch {
@ -77,3 +79,54 @@ async function goToProjectConfig(clientHost: TypeScriptServiceClientHost, uri: s
function isImplicitProjectConfigFile(configFileName: string): boolean {
return configFileName.indexOf('/dev/null/') === 0
}
const autoFixableDiagnosticCodes = new Set<number>([
2420, // Incorrectly implemented interface
2552, // Cannot find name
2304, // Cannot find name
])
export class AutoFixCommand implements Command {
public readonly id = 'tsserver.executeAutofix'
constructor(private client: TypeScriptServiceClientHost) {
}
public async execute(): Promise<void> {
let document = await workspace.document
if (!this.client.handles(document.uri)) {
workspace.showMessage('Document is not handled by tsserver.', 'warning')
return
}
let file = this.client.serviceClient.toPath(document.uri)
let diagnostics = diagnosticManager.getDiagnostics(document.uri)
diagnostics = diagnostics.filter(x => autoFixableDiagnosticCodes.has(x.code as number))
if (diagnostics.length == 0) {
workspace.showMessage('No autofixable diagnostics found', 'warning')
}
let client = this.client.serviceClient
let edits: TextEdit[] = []
for (let diagnostic of diagnostics) {
const args: Proto.CodeFixRequestArgs = {
...typeConverters.Range.toFileRangeRequestArgs(file, diagnostic.range),
errorCodes: [+(diagnostic.code!)]
}
const response: Proto.GetCodeFixesResponse = await client.execute('getCodeFixes', args)
if (response.type !== 'response' || !response.body || response.body.length < 1) {
continue
}
const fix = response.body[0]
for (let change of fix.changes) {
if (change.fileName != file) continue
// change.fileName
for (let ch of change.textChanges) {
edits.push({
range: typeConverters.Range.fromTextSpan(ch),
newText: ch.newText
})
}
}
}
if (edits.length) await document.applyEdits(workspace.nvim, edits)
}
}

View file

@ -815,7 +815,7 @@ export default class TypeScriptServiceClient implements ITypeScriptServiceClient
public getProjectRootPath(uri: string): string {
let u = Uri.parse(uri)
if (u.scheme != 'file') return workspace.root
let res = findUp.sync(['tsconfig.json', 'jsconfig.json', 'package.json'], { cwd: path.dirname(u.fsPath) })
let res = findUp.sync(['package.json', 'tsconfig.json', 'jsconfig.json'], { cwd: path.dirname(u.fsPath) })
return res ? path.dirname(res) : workspace.rootPath
}
}