Skip to content

Commit

Permalink
Add on type formatting provider
Browse files Browse the repository at this point in the history
  • Loading branch information
ddaspit committed Nov 1, 2024
1 parent 032ea36 commit 94556e1
Show file tree
Hide file tree
Showing 8 changed files with 72 additions and 2 deletions.
1 change: 1 addition & 0 deletions packages/core/src/common/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export type { Position } from './position';
export type { Range } from './range';
export type { TextEdit } from './text-edit';
6 changes: 6 additions & 0 deletions packages/core/src/common/text-edit.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { Range } from './range';

export interface TextEdit {
range: Range;
newText: string;
}
1 change: 1 addition & 0 deletions packages/core/src/formatting/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export type { OnTypeFormattingProvider, OnTypeFormattingProviderFactory } from './on-type-formatting-provider';
16 changes: 16 additions & 0 deletions packages/core/src/formatting/on-type-formatting-provider.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { Position } from '../common/position';
import { TextEdit } from '../common/text-edit';
import { Document } from '../document/document';
import { DocumentManager } from '../document/document-manager';

export type OnTypeFormattingProviderFactory<T extends Document> = (
DocumentManager: DocumentManager<T>,
) => OnTypeFormattingProvider;

export interface OnTypeFormattingProvider {
readonly id: string;

readonly onTypeTriggerCharacters: ReadonlySet<string>;

getOnTypeEdits(uri: string, position: Position, ch: string): Promise<TextEdit[] | undefined>;
}
1 change: 1 addition & 0 deletions packages/core/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export * from './common';
export * from './diagnostic';
export * from './document';
export * from './formatting';
export * from './workspace';
37 changes: 35 additions & 2 deletions packages/core/src/workspace/workspace.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,26 @@
import { map, merge, Observable, tap } from 'rxjs';

import { Position } from '../common/position';
import { TextEdit } from '../common/text-edit';
import { Diagnostic } from '../diagnostic/diagnostic';
import { DiagnosticFix } from '../diagnostic/diagnostic-fix';
import { DiagnosticProvider, DiagnosticProviderFactory, DiagnosticsChanged } from '../diagnostic/diagnostic-provider';
import { Document } from '../document/document';
import { DocumentFactory } from '../document/document-factory';
import { DocumentManager } from '../document/document-manager';
import { DocumentReader } from '../document/document-reader';
import { OnTypeFormattingProvider, OnTypeFormattingProviderFactory } from '../formatting/on-type-formatting-provider';

export interface WorkspaceConfig<T extends Document> {
documentReader?: DocumentReader;
documentFactory: DocumentFactory<T>;
diagnosticProviders: DiagnosticProviderFactory<T>[];
diagnosticProviders?: DiagnosticProviderFactory<T>[];
onTypeFormattingProviders?: OnTypeFormattingProviderFactory<T>[];
}

export class Workspace<T extends Document> {
private readonly diagnosticProviders: Map<string, DiagnosticProvider>;
private readonly onTypeFormattingProviders: Map<string, OnTypeFormattingProvider>;
private readonly lastDiagnosticChangedEvents = new Map<string, DiagnosticsChanged[]>();

public readonly documentManager: DocumentManager<T>;
Expand All @@ -24,7 +29,7 @@ export class Workspace<T extends Document> {
constructor(config: WorkspaceConfig<T>) {
this.documentManager = new DocumentManager(config.documentReader, config.documentFactory);
this.diagnosticProviders = new Map(
config.diagnosticProviders.map((factory) => {
config.diagnosticProviders?.map((factory) => {
const provider = factory(this.documentManager);
return [provider.id, provider];
}),
Expand All @@ -38,6 +43,12 @@ export class Workspace<T extends Document> {
),
),
).pipe(map((e) => this.getCombinedDiagnosticChangedEvent(e.uri, e.version)));
this.onTypeFormattingProviders = new Map(
config.onTypeFormattingProviders?.map((factory) => {
const provider = factory(this.documentManager);
return [provider.id, provider];
}),
);
}

async getDiagnostics(uri: string): Promise<Diagnostic[]> {
Expand All @@ -56,6 +67,28 @@ export class Workspace<T extends Document> {
return await provider.getDiagnosticFixes(uri, diagnostic);
}

getOnTypeTriggerCharacters(): string[] {
const characters = new Set<string>();
for (const provider of this.onTypeFormattingProviders.values()) {
for (const ch of provider.onTypeTriggerCharacters) {
characters.add(ch);
}
}
return Array.from(characters);
}

async getOnTypeEdits(uri: string, position: Position, ch: string): Promise<TextEdit[] | undefined> {
for (const provider of this.onTypeFormattingProviders.values()) {
if (provider.onTypeTriggerCharacters.has(ch)) {
const edits = await provider.getOnTypeEdits(uri, position, ch);
if (edits != null) {
return edits;
}
}
}
return undefined;
}

private updateCombinedDiagnosticChangedEvent(providerIndex: number, event: DiagnosticsChanged) {
const docEvents = this.lastDiagnosticChangedEvents.get(event.uri) ?? [];
docEvents[providerIndex] = event;
Expand Down
1 change: 1 addition & 0 deletions packages/eslint-config/library.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ export default tseslint.config(
],
'@typescript-eslint/no-non-null-assertion': 'off',
'@typescript-eslint/no-unsafe-call': 'off',
'@typescript-eslint/no-unsafe-assignment': 'off',
},
},
{
Expand Down
11 changes: 11 additions & 0 deletions packages/vscode/src/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,13 @@ connection.onInitialize((params: InitializeParams) => {
codeActionProvider: true,
},
};
const onTypeTriggerCharacters = workspace.getOnTypeTriggerCharacters();
if (onTypeTriggerCharacters.length > 0) {
result.capabilities.documentOnTypeFormattingProvider = {
firstTriggerCharacter: onTypeTriggerCharacters[0],
moreTriggerCharacter: onTypeTriggerCharacters.slice(1),
};
}
if (hasWorkspaceFolderCapability) {
result.capabilities.workspace = {
workspaceFolders: {
Expand Down Expand Up @@ -130,6 +137,10 @@ connection.onDidChangeTextDocument((params) => {
);
});

connection.onDocumentOnTypeFormatting(async (params) => {
return await workspace.getOnTypeEdits(params.textDocument.uri, params.position, params.ch);
});

connection.onDidChangeWatchedFiles((_change) => {
// Monitored files have change in VSCode
connection.console.log('We received a file change event');
Expand Down

0 comments on commit 94556e1

Please sign in to comment.