fix invalid uri

Closes #237
This commit is contained in:
Qiming Zhao 2020-12-09 14:04:50 +08:00
parent c8c5d7eba5
commit cca85a2724
4 changed files with 82 additions and 46 deletions

View file

@ -135,7 +135,7 @@ class PendingDiagnostics extends ResourceMap<number> {
public getOrderedFileSet(): ResourceMap<void> {
const orderedResources = Array.from(this.entries)
.sort((a, b) => a.value - b.value)
.map(entry => entry.resource)
.map(entry => entry.uri)
const map = new ResourceMap<void>(this._normalizePath)
for (const resource of orderedResources) {
@ -270,24 +270,25 @@ class GetErrRequest {
public static executeGetErrRequest(
client: ITypeScriptServiceClient,
files: string[],
uris: Uri[],
onDone: () => void
): GetErrRequest {
const token = new CancellationTokenSource()
return new GetErrRequest(client, files, token, onDone)
return new GetErrRequest(client, uris, token, onDone)
}
private _done = false
private constructor(
client: ITypeScriptServiceClient,
public readonly files: string[],
public readonly uris: Uri[],
private readonly _token: CancellationTokenSource,
onDone: () => void
) {
let files = uris.map(uri => client.normalizePath(uri))
const args: Proto.GeterrRequestArgs = {
delay: 0,
files: this.files
files
}
const done = () => {
if (this._done) {
@ -522,8 +523,8 @@ export default class BufferSyncSupport {
const orderedFileSet = this.pendingDiagnostics.getOrderedFileSet()
if (this.pendingGetErr) {
this.pendingGetErr.cancel()
for (const file of this.pendingGetErr.files) {
let resource = Uri.file(file).toString()
for (const uri of this.pendingGetErr.uris) {
let resource = uri.toString()
if (this.syncedBuffers.get(resource)) {
orderedFileSet.set(resource, undefined)
}
@ -535,8 +536,8 @@ export default class BufferSyncSupport {
orderedFileSet.set(buffer.resource, undefined)
}
if (orderedFileSet.size) {
let files = Array.from(orderedFileSet.keys).map(uri => this.client.normalizePath(Uri.parse(uri)))
const getErr = this.pendingGetErr = GetErrRequest.executeGetErrRequest(this.client, files, () => {
let uris = Array.from(orderedFileSet.uris).map(uri => Uri.parse(uri))
const getErr = this.pendingGetErr = GetErrRequest.executeGetErrRequest(this.client, uris, () => {
if (this.pendingGetErr === getErr) {
this.pendingGetErr = undefined
}

View file

@ -2,70 +2,79 @@
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { Uri } from 'coc.nvim'
function defaultPathNormalizer(resource: string): string {
let u = Uri.parse(resource)
if (u.scheme === 'file') {
return u.fsPath
}
return resource.toString()
}
/**
* Maps of file resources
* Maps of file uris
*
* Attempts to handle correct mapping on both case sensitive and case in-sensitive
* file systems.
*/
export class ResourceMap<T> {
private readonly _map = new Map<string, T>()
private readonly _map = new Map<string, { uri: string, value: T }>()
constructor(
protected readonly _normalizePath?: (resource: string) => string | null
protected readonly _normalizePath: (uri: string) => string | null = defaultPathNormalizer
) { }
public get size() {
return this._map.size
}
public get entries(): { resource: string, value: T }[] {
return Array.from(this._map.keys()).map(key => {
return { resource: key, value: this._map[key] }
})
public get entries(): Iterable<{ uri: string, value: T }> {
return this._map.values()
}
public has(resource: string): boolean {
const file = this.toKey(resource)
public has(uri: string): boolean {
const file = this.toKey(uri)
return !!file && this._map.has(file)
}
public get(resource: string): T | undefined {
const file = this.toKey(resource)
return file ? this._map.get(file) : undefined
public get(uri: string): T | undefined {
const file = this.toKey(uri)
if (!file) return undefined
let entry = this._map.get(file)
return entry ? entry.value : undefined
}
public set(resource: string, value: T): void {
const file = this.toKey(resource)
public set(uri: string, value: T): void {
const file = this.toKey(uri)
if (file) {
this._map.set(file, value)
this._map.set(file, { uri, value })
}
}
public delete(resource: string): void {
const file = this.toKey(resource)
public delete(uri: string): void {
const file = this.toKey(uri)
if (file) {
this._map.delete(file)
}
}
public get values(): Iterable<T> {
return this._map.values()
return Array.from(this._map.values()).map(x => x.value)
}
public get keys(): Iterable<string> {
return this._map.keys()
public get uris(): Iterable<string> {
return Array.from(this._map.values()).map(x => x.uri)
}
public clear(): void {
this._map.clear()
}
private toKey(resource: string): string | null {
private toKey(uri: string): string | null {
const key = this._normalizePath
? this._normalizePath(resource)
: resource
? this._normalizePath(uri)
: uri
if (!key) {
return key
}

View file

@ -8,6 +8,7 @@ import fs from 'fs'
import os from 'os'
import path from 'path'
import { CancellationToken, CancellationTokenSource, Disposable, Emitter, Event } from 'vscode-languageserver-protocol'
import * as fileSchemes from '../utils/fileSchemess'
import { PluginManager } from '../utils/plugins'
import { CallbackMap } from './callbackMap'
import BufferSyncSupport from './features/bufferSyncSupport'
@ -506,22 +507,22 @@ export default class TypeScriptServiceClient implements ITypeScriptServiceClient
return Uri.file(filepath).toString()
}
public normalizePath(resource: Uri): string | null {
if (this._apiVersion.gte(API.v213)) {
if (resource.scheme == 'untitled') {
const dirName = path.dirname(resource.path)
const fileName = this.inMemoryResourcePrefix + path.basename(resource.path)
return resource
.with({ path: path.posix.join(dirName, fileName) })
.toString(true)
public normalizePath(resource: Uri): string | undefined {
if (fileSchemes.disabledSchemes.has(resource.scheme)) {
return undefined
}
switch (resource.scheme) {
case fileSchemes.file: {
let result = resource.fsPath
if (!result) return undefined
result = path.normalize(result)
// Both \ and / must be escaped in regular expressions
return result.replace(new RegExp('\\' + this.pathSeparator, 'g'), '/')
}
default: {
return this.inMemoryResourcePrefix + resource.toString(true)
}
}
const result = resource.fsPath
if (!result) return null
// Both \ and / must be escaped in regular expressions
return result.replace(new RegExp('\\' + this.pathSeparator, 'g'), '/')
}
private get inMemoryResourcePrefix(): string {

25
src/utils/fileSchemess.ts Normal file
View file

@ -0,0 +1,25 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
export const file = 'file'
export const untitled = 'untitled'
export const git = 'git'
/** Live share scheme */
export const vsls = 'vsls'
export const walkThroughSnippet = 'walkThroughSnippet'
export const semanticSupportedSchemes = [
file,
untitled,
walkThroughSnippet,
]
/**
* File scheme for which JS/TS language feature should be disabled
*/
export const disabledSchemes = new Set([
git,
vsls
])