Skip to content

Commit

Permalink
done
Browse files Browse the repository at this point in the history
  • Loading branch information
johnsoncodehk committed May 15, 2024
1 parent 00da9f1 commit 21af8b2
Show file tree
Hide file tree
Showing 6 changed files with 74 additions and 76 deletions.
27 changes: 12 additions & 15 deletions packages/language-server/lib/project/simpleProjectProvider.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import type { LanguagePlugin, ServiceEnvironment } from '@volar/language-service';
import { URI } from 'vscode-uri';
import type { ServerBase, ServerProject, ServerProjectProvider } from '../types';
import type { UriMap } from '../utils/uriMap';
import { createUriMap, type UriMap } from '../utils/uriMap';
import { createSimpleServerProject } from './simpleProject';

export function createSimpleProjectProvider(languagePlugins: LanguagePlugin[]): ServerProjectProvider {
const map = new Map<string, Promise<ServerProject>>();
const map = createUriMap<Promise<ServerProject>>();
return {
get(uri) {
const workspaceFolder = getWorkspaceFolder(uri, this.workspaceFolders);
const workspaceFolder = getWorkspaceFolder(URI.parse(uri), this.workspaceFolders);
let projectPromise = map.get(workspaceFolder);
if (!projectPromise) {
const serviceEnv = createServiceEnvironment(this, workspaceFolder);
Expand All @@ -29,9 +29,9 @@ export function createSimpleProjectProvider(languagePlugins: LanguagePlugin[]):
};
}

export function createServiceEnvironment(server: ServerBase, workspaceFolder: string): ServiceEnvironment {
export function createServiceEnvironment(server: ServerBase, workspaceFolder: URI): ServiceEnvironment {
return {
workspaceFolder,
workspaceFolder: workspaceFolder.toString(),
fs: server.fs,
locale: server.initializeParams?.locale,
clientCapabilities: server.initializeParams?.capabilities,
Expand All @@ -45,24 +45,21 @@ export function createServiceEnvironment(server: ServerBase, workspaceFolder: st
};
}

export function getWorkspaceFolder(uri: string, workspaceFolders: UriMap<boolean>) {

let parsed = URI.parse(uri);

export function getWorkspaceFolder(uri: URI, workspaceFolders: UriMap<boolean>) {
while (true) {
if (workspaceFolders.has(parsed.toString())) {
return parsed.toString();
if (workspaceFolders.has(uri)) {
return uri;
}
const next = URI.parse(uri).with({ path: parsed.path.substring(0, parsed.path.lastIndexOf('/')) });
if (next.path === parsed.path) {
const next = uri.with({ path: uri.path.substring(0, uri.path.lastIndexOf('/')) });
if (next.path === uri.path) {
break;
}
parsed = next;
uri = next;
}

for (const folder of workspaceFolders.keys()) {
return folder;
}

return URI.parse(uri).with({ path: '/' }).toString();
return uri.with({ path: '/' });
}
3 changes: 2 additions & 1 deletion packages/language-server/lib/project/typescriptProject.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { createSys, createTypeScriptLanguage } from '@volar/typescript';
import * as path from 'path-browserify';
import type * as ts from 'typescript';
import * as vscode from 'vscode-languageserver';
import { URI } from 'vscode-uri';
import type { ServerBase, ServerProject } from '../types';
import { UriMap, createUriMap } from '../utils/uriMap';

Expand Down Expand Up @@ -50,7 +51,7 @@ export async function createTypeScriptServerProject(
},
getScriptSnapshot(fileName) {
const uri = server.uriConverter.fileNameToUri(fileName);
askedFiles.set(uri, true);
askedFiles.set(URI.parse(uri), true);
const document = server.documents.get(uri);
if (document) {
return document.getSnapshot();
Expand Down
44 changes: 24 additions & 20 deletions packages/language-server/lib/project/typescriptProjectProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,12 @@ export function createTypeScriptProjectProvider(
initialized = true;
initialize(this);
}
const tsconfig = await findMatchTSConfig(this, URI.parse(uri));
const parsedUri = URI.parse(uri);
const tsconfig = await findMatchTSConfig(this, parsedUri);
if (tsconfig) {
return await getOrCreateConfiguredProject(this, tsconfig);
}
const workspaceFolder = getWorkspaceFolder(uri, this.workspaceFolders);
const workspaceFolder = getWorkspaceFolder(parsedUri, this.workspaceFolders);
return await getOrCreateInferredProject(this, uri, workspaceFolder);
},
async all() {
Expand All @@ -65,15 +66,17 @@ export function createTypeScriptProjectProvider(
const tsConfigChanges = changes.filter(change => rootTsConfigNames.includes(change.uri.substring(change.uri.lastIndexOf('/') + 1)));

for (const change of tsConfigChanges) {
const changeUri = URI.parse(change.uri);
const changeFileName = server.uriConverter.uriToFileName(change.uri, changeUri);
if (change.type === vscode.FileChangeType.Created) {
rootTsConfigs.add(server.uriConverter.uriToFileName(change.uri));
rootTsConfigs.add(changeFileName);
}
else if ((change.type === vscode.FileChangeType.Changed || change.type === vscode.FileChangeType.Deleted) && configProjects.has(change.uri)) {
else if ((change.type === vscode.FileChangeType.Changed || change.type === vscode.FileChangeType.Deleted) && configProjects.has(changeUri)) {
if (change.type === vscode.FileChangeType.Deleted) {
rootTsConfigs.delete(server.uriConverter.uriToFileName(change.uri));
rootTsConfigs.delete(changeFileName);
}
const project = configProjects.get(change.uri);
configProjects.delete(change.uri);
const project = configProjects.get(changeUri);
configProjects.delete(changeUri);
project?.then(project => project.dispose());
}
}
Expand All @@ -87,8 +90,9 @@ export function createTypeScriptProjectProvider(

async function findMatchTSConfig(server: ServerBase, uri: URI) {

const filePath = server.uriConverter.uriToFileName(uri.toString());
let dir = path.dirname(filePath);
const fileName = server.uriConverter.uriToFileName(uri.toString());

let dir = path.dirname(fileName);

while (true) {
if (searchedDirs.has(dir)) {
Expand All @@ -113,41 +117,41 @@ export function createTypeScriptProjectProvider(
let matches: string[] = [];

for (const rootTsConfig of rootTsConfigs) {
if (isFileInDir(server.uriConverter.uriToFileName(uri.toString()), path.dirname(rootTsConfig))) {
if (isFileInDir(fileName, path.dirname(rootTsConfig))) {
matches.push(rootTsConfig);
}
}

matches = matches.sort((a, b) => sortTSConfigs(server.uriConverter.uriToFileName(uri.toString()), a, b));
matches = matches.sort((a, b) => sortTSConfigs(fileName, a, b));

if (matches.length) {
await getParsedCommandLine(matches[0]);
}
}
function findIndirectReferenceTsconfig() {
return findTSConfig(async tsconfig => {
const tsconfigUri = server.uriConverter.fileNameToUri(tsconfig);
const tsconfigUri = URI.parse(server.uriConverter.fileNameToUri(tsconfig));
const project = await configProjects.get(tsconfigUri);
return project?.askedFiles.has(uri.toString()) ?? false;
return project?.askedFiles.has(uri) ?? false;
});
}
function findDirectIncludeTsconfig() {
return findTSConfig(async tsconfig => {
const map = createUriMap<boolean>();
const parsedCommandLine = await getParsedCommandLine(tsconfig);
for (const fileName of parsedCommandLine?.fileNames ?? []) {
const uri = server.uriConverter.fileNameToUri(fileName);
const uri = URI.parse(server.uriConverter.fileNameToUri(fileName));
map.set(uri, true);
}
return map.has(uri.toString());
return map.has(uri);
});
}
async function findTSConfig(match: (tsconfig: string) => Promise<boolean> | boolean) {

const checked = new Set<string>();

for (const rootTsConfig of [...rootTsConfigs].sort((a, b) => sortTSConfigs(server.uriConverter.uriToFileName(uri.toString()), a, b))) {
const tsconfigUri = server.uriConverter.fileNameToUri(rootTsConfig);
for (const rootTsConfig of [...rootTsConfigs].sort((a, b) => sortTSConfigs(fileName, a, b))) {
const tsconfigUri = URI.parse(server.uriConverter.fileNameToUri(rootTsConfig));
const project = await configProjects.get(tsconfigUri);
if (project) {

Expand Down Expand Up @@ -223,7 +227,7 @@ export function createTypeScriptProjectProvider(

function getOrCreateConfiguredProject(server: ServerBase, tsconfig: string) {
tsconfig = tsconfig.replace(/\\/g, '/');
const tsconfigUri = server.uriConverter.fileNameToUri(tsconfig);
const tsconfigUri = URI.parse(server.uriConverter.fileNameToUri(tsconfig));
let projectPromise = configProjects.get(tsconfigUri);
if (!projectPromise) {
const workspaceFolder = getWorkspaceFolder(tsconfigUri, server.workspaceFolders);
Expand All @@ -241,7 +245,7 @@ export function createTypeScriptProjectProvider(
return projectPromise;
}

async function getOrCreateInferredProject(server: ServerBase, uri: string, workspaceFolder: string) {
async function getOrCreateInferredProject(server: ServerBase, uri: string, workspaceFolder: URI) {

if (!inferredProjects.has(workspaceFolder)) {
inferredProjects.set(workspaceFolder, (async () => {
Expand All @@ -258,7 +262,7 @@ export function createTypeScriptProjectProvider(
})());
}

const project = await inferredProjects.get(workspaceFolder.toString())!;
const project = await inferredProjects.get(workspaceFolder)!;

project.tryAddFile(server.uriConverter.uriToFileName(uri));

Expand Down
10 changes: 5 additions & 5 deletions packages/language-server/lib/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,14 +82,14 @@ export function createServerBase(

if (initializeParams.workspaceFolders?.length) {
for (const folder of initializeParams.workspaceFolders) {
workspaceFolders.set(folder.uri, true);
workspaceFolders.set(URI.parse(folder.uri), true);
}
}
else if (initializeParams.rootUri) {
workspaceFolders.set(initializeParams.rootUri, true);
workspaceFolders.set(URI.parse(initializeParams.rootUri), true);
}
else if (initializeParams.rootPath) {
workspaceFolders.set(URI.file(initializeParams.rootPath).toString(), true);
workspaceFolders.set(URI.file(initializeParams.rootPath), true);
}

const result: vscode.InitializeResult = {
Expand Down Expand Up @@ -250,10 +250,10 @@ export function createServerBase(
if (status.initializeParams?.capabilities.workspace?.workspaceFolders) {
connection.workspace.onDidChangeWorkspaceFolders(e => {
for (const folder of e.added) {
workspaceFolders.set(folder.uri, true);
workspaceFolders.set(URI.parse(folder.uri), true);
}
for (const folder of e.removed) {
workspaceFolders.delete(folder.uri);
workspaceFolders.delete(URI.parse(folder.uri));
}
status.projects.reload.call(status);
});
Expand Down
8 changes: 4 additions & 4 deletions packages/language-server/lib/uri.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import type { TextDocuments } from 'vscode-languageserver';
import type { TextDocument, TextDocuments } from 'vscode-languageserver';
import { URI } from 'vscode-uri';

export type UriConverter = ReturnType<typeof createUriConverter>;

export function createUriConverter(documents?: TextDocuments<any>) {
export function createUriConverter(documents?: TextDocuments<TextDocument>) {
const syncedDocumentUriToFileName = new Map<string, string>();
const syncedDocumentFileNameToUri = new Map<string, string>();
const encodeds = new Map<string, URI>();
Expand All @@ -25,12 +25,12 @@ export function createUriConverter(documents?: TextDocuments<any>) {
fileNameToUri,
};

function uriToFileName(uri: string) {
function uriToFileName(uri: string, parsed?: URI) {
const syncedDocumentFileName = syncedDocumentUriToFileName.get(uri);
if (syncedDocumentFileName) {
return syncedDocumentFileName;
}
const parsed = URI.parse(uri);
parsed ??= URI.parse(uri);
if (parsed.scheme === 'file') {
return parsed.fsPath.replace(/\\/g, '/');
}
Expand Down
58 changes: 27 additions & 31 deletions packages/language-server/lib/utils/uriMap.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
import { URI } from 'vscode-uri';
export * as _ from 'vscode-uri';
import type { URI } from 'vscode-uri';

export type UriMap<T> = ReturnType<typeof createUriMap<T>>;

export function createUriMap<T>(caseSensitive = false) {
const map = new Map<string, T>();
const uriToNormalizedUri = new Map<string, string>();
const normalizedUriToUri = new Map<string, string>();
const rawUriToNormalizedUri = new Map<string, string>();
const normalizedUriToRawUri = new Map<string, URI>();

return {
clear: _clear,
Expand All @@ -18,50 +17,47 @@ export function createUriMap<T>(caseSensitive = false) {
set: _set,
};

function getUriByUri(uri: string) {
if (!uriToNormalizedUri.has(uri)) {
const normalizedUri = normalizeUri(uri);
uriToNormalizedUri.set(uri, normalizedUri);
normalizedUriToUri.set(normalizedUri, uri);
}
return uriToNormalizedUri.get(uri)!;
}

function _clear() {
uriToNormalizedUri.clear();
normalizedUriToUri.clear();
rawUriToNormalizedUri.clear();
normalizedUriToRawUri.clear();
return map.clear();
}

function _values() {
return map.values();
}

function* _keys() {
for (const normalizedUri of map.keys()) {
yield normalizedUriToUri.get(normalizedUri)!;
yield normalizedUriToRawUri.get(normalizedUri)!;
}
}
function _delete(_uri: string) {
return map.delete(getUriByUri(_uri));
function _delete(uri: URI) {
return map.delete(getUriByUri(uri));
}
function _get(_uri: string) {
return map.get(getUriByUri(_uri));

function _get(uri: URI) {
return map.get(getUriByUri(uri));
}
function _has(_uri: string) {
return map.has(getUriByUri(_uri));

function _has(uri: URI) {
return map.has(getUriByUri(uri));
}
function _set(_uri: string, item: T) {
return map.set(getUriByUri(_uri), item);

function _set(uri: URI, item: T) {
return map.set(getUriByUri(uri), item);
}

function normalizeUri(uri: string) {
try {
let normalized = URI.parse(uri).toString();
function getUriByUri(uri: URI) {
const rawUri = uri.toString();
if (!rawUriToNormalizedUri.has(rawUri)) {
let normalizedUri = uri.toString();
if (!caseSensitive) {
normalized = normalized.toLowerCase();
normalizedUri = normalizedUri.toLowerCase();
}
return normalized;
} catch {
return '';
rawUriToNormalizedUri.set(rawUri, normalizedUri);
normalizedUriToRawUri.set(normalizedUri, uri);
}
return rawUriToNormalizedUri.get(rawUri)!;
}
}

0 comments on commit 21af8b2

Please sign in to comment.