Skip to content

Commit

Permalink
WIP: clangd improvements
Browse files Browse the repository at this point in the history
- new example: socket.io for file protocol to non worker target
- define file system endpoints
- clangd LS uses message port for communication
- Use wtm new ComChannelEndpoints for handling async communication of message channels or workers
- worker transfers files to client via message channel
  • Loading branch information
kaisalmen committed Oct 2, 2024
1 parent 7d97711 commit ff7bd8e
Show file tree
Hide file tree
Showing 29 changed files with 7,766 additions and 414 deletions.
1 change: 1 addition & 0 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ <h2>Monaco Editor React</h2>
<h3>monaco-editor related examples</h3>
<a href="./packages/examples/ts.html">Monaco Editor Wrapper TypeScript Example</a>
<br>
<a href="./packages/examples/files.html">Files Testbed</a>

<h2>Verification</h2>
<h3>Angular</h2>
Expand Down
596 changes: 412 additions & 184 deletions package-lock.json

Large diffs are not rendered by default.

8 changes: 4 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@
"@codingame/esbuild-import-meta-url-plugin": "~1.0.2",
"@codingame/monaco-vscode-rollup-vsix-plugin": "~9.0.3",
"@testing-library/react": "~16.0.1",
"@types/node": "~20.16.9",
"@types/react": "~18.3.9",
"@types/node": "~20.16.10",
"@types/react": "~18.3.10",
"@types/react-dom": "~18.3.0",
"@types/vscode": "~1.93.0",
"@typescript-eslint/eslint-plugin": "~7.18.0",
"@typescript-eslint/parser": "~7.18.0",
"@vitejs/plugin-react": "~4.3.1",
"@vitejs/plugin-react": "~4.3.2",
"@vitest/browser": "~2.1.1",
"editorconfig": "~2.0.0",
"esbuild": "~0.24.0",
Expand All @@ -26,7 +26,7 @@
"vite": "~5.4.8",
"vite-node": "~2.1.1",
"vitest": "~2.1.1",
"webdriverio": "~9.1.1"
"webdriverio": "~9.1.2"
},
"volta": {
"node": "20.17.0",
Expand Down
7 changes: 7 additions & 0 deletions packages/client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@
"./vscode/services": {
"types": "./lib/vscode/index.d.ts",
"default": "./lib/vscode/index.js"
},
"./fs": {
"types": "./lib/fs/index.d.ts",
"default": "./lib/fs/index.js"
}
},
"typesVersions": {
Expand All @@ -43,6 +47,9 @@
],
"vscode/services": [
"lib/vscode/index"
],
"fs": [
"lib/fs/index"
]
}
},
Expand Down
127 changes: 127 additions & 0 deletions packages/client/src/fs/definitions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
/* --------------------------------------------------------------------------------------------
* Copyright (c) 2024 TypeFox and others.
* Licensed under the MIT License. See LICENSE in the package root for license information.
* ------------------------------------------------------------------------------------------ */

import { Logger } from 'monaco-languageclient/tools';

export interface FileReadRequest {
resourceUri: string
}

export type FileReadResultStatus = 'success' | 'denied';

export interface FileReadRequestResult {
status: FileReadResultStatus
content: string | ArrayBuffer
}

export interface FileUpdate {
resourceUri: string
content: string | ArrayBuffer
}

export type FileUpdateResultStatus = 'equal' | 'updated' | 'created' | 'denied';

export interface FileUpdateResult {
status: FileUpdateResultStatus
message?: string
}

export interface DirectoryListingRequest {
directoryUri: string
}

export interface DirectoryListingRequestResult {
files: string[]
}

export type StatsRequestType = 'directory' | 'file';

export interface StatsRequest {
type: StatsRequestType,
resourceUri: string
}

export interface StatsRequestResult {
type: StatsRequestType
size: number
name: string
mtime: number
}

export enum EndpointType {
DRIVER,
FOLLOWER,
LOCAL,
EMPTY
}

export interface FileSystemCapabilities {

/**
* Get a text file content
* @param params the resourceUri of the file
* @returns The ReadFileResult containing the content of the file
*/
readFile(params: FileReadRequest): Promise<FileReadRequestResult>

/**
* Save a file on the filesystem
* @param params the resourceUri and the content of the file
* @returns The FileUpdateResult containing the result of the operation and an optional message
*/
writeFile(params: FileUpdate): Promise<FileUpdateResult>;

/**
* The implementation has to decide if the file at given uri at need to be updated
* @param params the resourceUri and the content of the file
* @returns The FileUpdateResult containing the result of the operation and an optional message
*/
syncFile(params: FileUpdate): Promise<FileUpdateResult>;

/**
* Get file stats on a given file
* @param params the resourceUri and if a file or a directory is requested
*/
getFileStats(params: StatsRequest): Promise<StatsRequestResult>

/**
* List the files of a directory
* @param resourceUri the Uri of the directory
*/
listFiles(params: DirectoryListingRequest): Promise<DirectoryListingRequestResult>

}

/**
* Defines the APT for a file system endpoint
*/
export interface FileSystemEndpoint extends FileSystemCapabilities {

/**
* Whatever can't be handled in the constructor should be done here
*/
init?(): void;

/**
* Set an optional logger
* @param logger the logger implemenation
*/
setLogger?(logger: Logger): void;

/**
* Get the type of the client
*/
getEndpointType(): EndpointType;

/**
* Provide info about the file system
*/
getFileSystemInfo(): string;

/**
* Signal readiness
*/
ready?(): void;
}
60 changes: 60 additions & 0 deletions packages/client/src/fs/endpoints/defaultEndpoint.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/* --------------------------------------------------------------------------------------------
* Copyright (c) 2024 TypeFox and others.
* Licensed under the MIT License. See LICENSE in the package root for license information.
* ------------------------------------------------------------------------------------------ */

import { Logger } from 'monaco-languageclient/tools';
import { DirectoryListingRequest, DirectoryListingRequestResult, EndpointType, FileReadRequest, FileReadRequestResult, FileSystemEndpoint, FileUpdate, FileUpdateResult, StatsRequest, StatsRequestResult } from '../definitions.js';

export class EmptyFileSystemEndpoint implements FileSystemEndpoint {

private endpointType: EndpointType;
private logger?: Logger;

constructor(endpointType: EndpointType) {
this.endpointType = endpointType;
}

init(): void { }

getFileSystemInfo(): string {
return 'This file system performs no operations.';
}

setLogger(logger: Logger): void {
this.logger = logger;
}

getEndpointType(): EndpointType {
return this.endpointType;
}

readFile(params: FileReadRequest): Promise<FileReadRequestResult> {
this.logger?.info(`Reading file: ${params.resourceUri}`);
return Promise.resolve({
status: 'denied',
content: ''
});
}

writeFile(params: FileUpdate): Promise<FileUpdateResult> {
this.logger?.info(`Writing file: ${params.resourceUri}`);
return Promise.resolve({ status: 'denied' });
}

syncFile(params: FileUpdate): Promise<FileUpdateResult> {
this.logger?.info(`Syncing file: ${params.resourceUri}`);
return Promise.resolve({ status: 'denied' });
}

getFileStats(params: StatsRequest): Promise<StatsRequestResult> {
this.logger?.info(`Getting file stats for: "${params.resourceUri}" (${params.type})`);
return Promise.reject('No stats available.');
}

listFiles(params: DirectoryListingRequest): Promise<DirectoryListingRequestResult> {
this.logger?.info(`Listing files for directory: "${params.directoryUri}"`);
return Promise.reject('No file listing possible.');
}

}
7 changes: 7 additions & 0 deletions packages/client/src/fs/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
/* --------------------------------------------------------------------------------------------
* Copyright (c) 2024 TypeFox and others.
* Licensed under the MIT License. See LICENSE in the package root for license information.
* ------------------------------------------------------------------------------------------ */

export * from './definitions.js';
export * from './endpoints/defaultEndpoint.js';
58 changes: 58 additions & 0 deletions packages/client/test/fs/endpoints/emptyEndpoint.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/* --------------------------------------------------------------------------------------------
* Copyright (c) 2024 TypeFox and others.
* Licensed under the MIT License. See LICENSE in the package root for license information.
* ------------------------------------------------------------------------------------------ */

import { describe, expect, test } from 'vitest';
import { EmptyFileSystemEndpoint, EndpointType } from 'monaco-languageclient/fs';

describe('EmptyFileSystemEndpoint Tests', () => {

const endpoint = new EmptyFileSystemEndpoint(EndpointType.EMPTY);

test('readFile', async () => {
const result = await endpoint.readFile({ resourceUri: '/tmp/test.js' });
expect(result).toEqual({
status: 'denied',
content: ''
});
});

test('writeFile', async () => {
const result = await endpoint.writeFile({
resourceUri: '/tmp/test.js',
content: 'console.log("Hello World!");'
});
expect(result).toEqual({
status: 'denied'
});
});

test('syncFile', async () => {
const result = await endpoint.syncFile({
resourceUri: '/tmp/test.js',
content: 'console.log("Hello World!");'
});
expect(result).toEqual({
status: 'denied'
});
});

test('getFileStats', async () => {
expect(async () => {
await endpoint.getFileStats({
type: 'file',
resourceUri: '/tmp/test.js'
});
}).rejects.toThrowError('No stats available.');
});

test('listFiles', async () => {
expect(async () => {
await endpoint.listFiles({
directoryUri: '/tmp'
});
}).rejects.toThrowError('No file listing possible.');
});

});
21 changes: 21 additions & 0 deletions packages/examples/files.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<!DOCTYPE html>
<html>

<head>
<title>Files Testbed</title>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="stylesheet" href="style.css">
</head>


<body>
<h2>Files Testbed</h2>
<div id="monaco-editor-root" style="width:800px;height:600px;border:1px solid grey"></div>
<script type="module">
import { runFilesClient } from "./src/files/client/filesClient.ts";

runFilesClient();
</script>
</body>
</html>
7 changes: 6 additions & 1 deletion packages/examples/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -83,17 +83,21 @@
"react": "~18.3.1",
"react-dom": "~18.3.1",
"request-light": "~0.8.0",
"socket.io": "~4.8.0",
"socket.io-client": "~4.8.0",
"vscode": "npm:@codingame/monaco-vscode-api@~9.0.3",
"vscode-json-languageservice": "~5.4.1",
"vscode-languageclient": "~9.0.1",
"vscode-languageserver": "~9.0.1",
"vscode-uri": "~3.0.8",
"vscode-ws-jsonrpc": "~3.3.2",
"ws": "~8.18.0"
"ws": "~8.18.0",
"wtd-core": "~4.0.1"
},
"devDependencies": {
"@types/express": "~4.17.21",
"@types/ws": "~8.5.12",
"@types/emscripten": "~1.39.13",
"langium-cli": "~3.2.0",
"ts-node": "~10.9.1",
"vscode-languageserver-types": "~3.17.5"
Expand All @@ -118,6 +122,7 @@
"build:msg": "echo Building main examples:",
"build": "npm run build:msg && npm run clean && npm run resources:download && npm run extract:docker && npm run compile",
"build:bundle": "vite --config vite.bundle.config.ts build",
"start:server:files": "vite-node src/files/server/direct.ts",
"start:server:json": "vite-node src/json/server/direct.ts",
"start:server:python": "vite-node src/python/server/direct.ts",
"start:server:groovy": "vite-node src/groovy/server/direct.ts",
Expand Down
Loading

0 comments on commit ff7bd8e

Please sign in to comment.