Skip to content

Commit

Permalink
feat: start runner in language server (#1006)
Browse files Browse the repository at this point in the history
### Summary of Changes

The runner is now also started in the language server. The plan is to
eventually always use this runner instead of creating a second services
object in the VS Code extension. This eases the implementation of
language clients for other IDEs.
  • Loading branch information
lars-reimann authored Apr 8, 2024
1 parent ea3da87 commit ef4bb6f
Show file tree
Hide file tree
Showing 12 changed files with 292 additions and 120 deletions.
Original file line number Diff line number Diff line change
@@ -1,11 +1,5 @@
import { AstNode, AstUtils, CstNode, DocumentationProvider, interruptAndCheck, LangiumDocument } from 'langium';
import {
CancellationToken,
type InlayHint,
InlayHintKind,
type InlayHintParams,
MarkupContent,
} from 'vscode-languageserver';
import { AstNode, AstUtils, CstNode, DocumentationProvider } from 'langium';
import { InlayHintKind, MarkupContent } from 'vscode-languageserver';
import { createMarkupContent } from '../documentation/safe-ds-comment-provider.js';
import {
isSdsArgument,
Expand Down Expand Up @@ -42,38 +36,22 @@ export class SafeDsInlayHintProvider extends AbstractInlayHintProvider {
this.typeComputer = services.typing.TypeComputer;
}

override async getInlayHints(
document: LangiumDocument,
params: InlayHintParams,
cancelToken = CancellationToken.None,
): Promise<InlayHint[] | undefined> {
const root = document.parseResult.value;
const inlayHints: InlayHint[] = [];
const acceptor: InlayHintAcceptor = (hint) => inlayHints.push(hint);
for (const node of AstUtils.streamAst(root, { range: params.range })) {
await interruptAndCheck(cancelToken);
// We have to override this method to add this await
await this.computeInlayHint(node, acceptor);
}
return inlayHints;
}

override async computeInlayHint(node: AstNode, acceptor: InlayHintAcceptor): Promise<void> {
override computeInlayHint(node: AstNode, acceptor: InlayHintAcceptor): void {
const cstNode = node.$cstNode;
if (!cstNode) {
/* c8 ignore next 2 */
return;
}

if (await this.settingsProvider.shouldShowAssigneeTypeInlayHints()) {
if (this.settingsProvider.shouldShowAssigneeTypeInlayHints()) {
this.computeAssigneeTypeInlayHint(node, cstNode, acceptor);
}

if (await this.settingsProvider.shouldShowLambdaParameterTypeInlayHints()) {
if (this.settingsProvider.shouldShowLambdaParameterTypeInlayHints()) {
this.computeLambdaParameterTypeInlayHint(node, cstNode, acceptor);
}

if (await this.settingsProvider.shouldShowParameterNameInlayHints()) {
if (this.settingsProvider.shouldShowParameterNameInlayHints()) {
this.computeParameterNameInlayHint(node, cstNode, acceptor);
}
}
Expand Down
29 changes: 23 additions & 6 deletions packages/safe-ds-lang/src/language/runner/safe-ds-runner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,18 +49,35 @@ export class SafeDsRunner {
PipelineExecutionInformation
>();

/* c8 ignore start */
constructor(services: SafeDsServices) {
this.annotations = services.builtins.Annotations;
this.generator = services.generation.PythonGenerator;
this.logging = {
outputError(_value: string) {},
outputInfo(_value: string) {},
displayError(_value: string) {},
outputError(value: string) {
services.lsp.MessagingProvider.error('Runner', value);
},
outputInfo(value: string) {
services.lsp.MessagingProvider.info('Runner', value);
},
displayError(value: string) {
services.lsp.MessagingProvider.showErrorMessage(value);
},
};

// Register listeners
this.registerMessageLoggingCallbacks();

services.workspace.SettingsProvider.onRunnerCommandUpdate(async (newValue) => {
this.updateRunnerCommand(newValue);
await this.startPythonServer();
});

services.shared.lsp.Connection?.onShutdown(async () => {
await this.stopPythonServer();
});
}

/* c8 ignore start */
private registerMessageLoggingCallbacks() {
this.addMessageCallback((message) => {
this.logging.outputInfo(
Expand All @@ -71,8 +88,8 @@ export class SafeDsRunner {
this.logging.outputInfo(
`Placeholder was calculated (${message.id}): ${message.data.name} of type ${message.data.type}`,
);
const execInfo = this.getExecutionContext(message.id)!;
execInfo.calculatedPlaceholders.set(message.data.name, message.data.type);
const execInfo = this.getExecutionContext(message.id);
execInfo?.calculatedPlaceholders.set(message.data.name, message.data.type);
// this.sendMessageToPythonServer(
// messages.createPlaceholderQueryMessage(message.id, message.data.name),
//);
Expand Down
23 changes: 19 additions & 4 deletions packages/safe-ds-lang/src/language/safe-ds-module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ import { SafeDsMarkdownGenerator } from './generation/safe-ds-markdown-generator
import { SafeDsCompletionProvider } from './lsp/safe-ds-completion-provider.js';
import { SafeDsFuzzyMatcher } from './lsp/safe-ds-fuzzy-matcher.js';
import { SafeDsMessagingProvider } from './lsp/safe-ds-messaging-provider.js';
import { SafeDsConfigurationProvider } from './workspace/safe-ds-configuration-provider.js';

/**
* Declaration of custom services - add your own service classes here.
Expand Down Expand Up @@ -96,11 +97,22 @@ export type SafeDsAddedServices = {
};
};

export type SafeDsAddedSharedServices = {
workspace: {
ConfigurationProvider: SafeDsConfigurationProvider;
};
};

/**
* Union of Langium default services and your custom services - use this as constructor parameter
* of custom service classes.
*/
export type SafeDsServices = LangiumServices & SafeDsAddedServices;
export type SafeDsServices = LangiumServices &
SafeDsAddedServices & {
shared: SafeDsAddedSharedServices;
};

export type SafeDsSharedServices = LangiumSharedServices & SafeDsAddedSharedServices;

/**
* Dependency injection module that overrides Langium default services and contributes the
Expand Down Expand Up @@ -170,14 +182,13 @@ export const SafeDsModule: Module<SafeDsServices, PartialLangiumServices & SafeD
},
};

export type SafeDsSharedServices = LangiumSharedServices;

export const SafeDsSharedModule: Module<SafeDsSharedServices, DeepPartial<SafeDsSharedServices>> = {
lsp: {
FuzzyMatcher: () => new SafeDsFuzzyMatcher(),
NodeKindProvider: () => new SafeDsNodeKindProvider(),
},
workspace: {
ConfigurationProvider: (services) => new SafeDsConfigurationProvider(services),
DocumentBuilder: (services) => new SafeDsDocumentBuilder(services),
WorkspaceManager: (services) => new SafeDsWorkspaceManager(services),
},
Expand Down Expand Up @@ -206,7 +217,11 @@ export const createSafeDsServices = async function (
shared: LangiumSharedServices;
SafeDs: SafeDsServices;
}> {
const shared = inject(createDefaultSharedModule(context), SafeDsGeneratedSharedModule, SafeDsSharedModule);
const shared: SafeDsSharedServices = inject(
createDefaultSharedModule(context),
SafeDsGeneratedSharedModule,
SafeDsSharedModule,
);
const SafeDs = inject(createDefaultModule({ shared }), SafeDsGeneratedModule, SafeDsModule);

shared.ServiceRegistry.register(SafeDs);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ export const CODE_EXPERIMENTAL_LIBRARY_ELEMENT = 'experimental/library-element';
export const assigneeAssignedResultShouldNotBeExperimental = (services: SafeDsServices) => {
const settingsProvider = services.workspace.SettingsProvider;

return async (node: SdsAssignee, accept: ValidationAcceptor) => {
if (!(await settingsProvider.shouldValidateExperimentalLibraryElements())) {
return (node: SdsAssignee, accept: ValidationAcceptor) => {
if (!settingsProvider.shouldValidateExperimentalLibraryElements()) {
/* c8 ignore next 2 */
return;
}
Expand All @@ -43,8 +43,8 @@ export const assigneeAssignedResultShouldNotBeExperimental = (services: SafeDsSe
export const annotationCallAnnotationShouldNotBeExperimental = (services: SafeDsServices) => {
const settingsProvider = services.workspace.SettingsProvider;

return async (node: SdsAnnotationCall, accept: ValidationAcceptor) => {
if (!(await settingsProvider.shouldValidateExperimentalLibraryElements())) {
return (node: SdsAnnotationCall, accept: ValidationAcceptor) => {
if (!settingsProvider.shouldValidateExperimentalLibraryElements()) {
/* c8 ignore next 2 */
return;
}
Expand All @@ -67,8 +67,8 @@ export const annotationCallAnnotationShouldNotBeExperimental = (services: SafeDs
export const argumentCorrespondingParameterShouldNotBeExperimental = (services: SafeDsServices) => {
const settingsProvider = services.workspace.SettingsProvider;

return async (node: SdsArgument, accept: ValidationAcceptor) => {
if (!(await settingsProvider.shouldValidateExperimentalLibraryElements())) {
return (node: SdsArgument, accept: ValidationAcceptor) => {
if (!settingsProvider.shouldValidateExperimentalLibraryElements()) {
/* c8 ignore next 2 */
return;
}
Expand All @@ -90,8 +90,8 @@ export const argumentCorrespondingParameterShouldNotBeExperimental = (services:
export const namedTypeDeclarationShouldNotBeExperimental = (services: SafeDsServices) => {
const settingsProvider = services.workspace.SettingsProvider;

return async (node: SdsNamedType, accept: ValidationAcceptor) => {
if (!(await settingsProvider.shouldValidateExperimentalLibraryElements())) {
return (node: SdsNamedType, accept: ValidationAcceptor) => {
if (!settingsProvider.shouldValidateExperimentalLibraryElements()) {
/* c8 ignore next 2 */
return;
}
Expand All @@ -113,8 +113,8 @@ export const namedTypeDeclarationShouldNotBeExperimental = (services: SafeDsServ
export const referenceTargetShouldNotExperimental = (services: SafeDsServices) => {
const settingsProvider = services.workspace.SettingsProvider;

return async (node: SdsReference, accept: ValidationAcceptor) => {
if (!(await settingsProvider.shouldValidateExperimentalLibraryElements())) {
return (node: SdsReference, accept: ValidationAcceptor) => {
if (!settingsProvider.shouldValidateExperimentalLibraryElements()) {
/* c8 ignore next 2 */
return;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ export const CODE_EXPERIMENTAL_LANGUAGE_FEATURE = 'experimental/language-feature
export const constraintListsShouldBeUsedWithCaution = (services: SafeDsServices) => {
const settingsProvider = services.workspace.SettingsProvider;

return async (node: SdsConstraintList, accept: ValidationAcceptor) => {
if (!(await settingsProvider.shouldValidateExperimentalLanguageFeatures())) {
return (node: SdsConstraintList, accept: ValidationAcceptor) => {
if (!settingsProvider.shouldValidateExperimentalLanguageFeatures()) {
/* c8 ignore next 2 */
return;
}
Expand All @@ -31,8 +31,8 @@ export const constraintListsShouldBeUsedWithCaution = (services: SafeDsServices)
export const literalTypesShouldBeUsedWithCaution = (services: SafeDsServices) => {
const settingsProvider = services.workspace.SettingsProvider;

return async (node: SdsLiteralType, accept: ValidationAcceptor) => {
if (!(await settingsProvider.shouldValidateExperimentalLanguageFeatures())) {
return (node: SdsLiteralType, accept: ValidationAcceptor) => {
if (!settingsProvider.shouldValidateExperimentalLanguageFeatures()) {
/* c8 ignore next 2 */
return;
}
Expand All @@ -48,8 +48,8 @@ export const literalTypesShouldBeUsedWithCaution = (services: SafeDsServices) =>
export const mapsShouldBeUsedWithCaution = (services: SafeDsServices) => {
const settingsProvider = services.workspace.SettingsProvider;

return async (node: SdsMap, accept: ValidationAcceptor) => {
if (!(await settingsProvider.shouldValidateExperimentalLanguageFeatures())) {
return (node: SdsMap, accept: ValidationAcceptor) => {
if (!settingsProvider.shouldValidateExperimentalLanguageFeatures()) {
/* c8 ignore next 2 */
return;
}
Expand All @@ -69,8 +69,8 @@ export const mapsShouldBeUsedWithCaution = (services: SafeDsServices) => {
export const unionTypesShouldBeUsedWithCaution = (services: SafeDsServices) => {
const settingsProvider = services.workspace.SettingsProvider;

return async (node: SdsUnionType, accept: ValidationAcceptor) => {
if (!(await settingsProvider.shouldValidateExperimentalLanguageFeatures())) {
return (node: SdsUnionType, accept: ValidationAcceptor) => {
if (!settingsProvider.shouldValidateExperimentalLanguageFeatures()) {
/* c8 ignore next 2 */
return;
}
Expand Down
4 changes: 2 additions & 2 deletions packages/safe-ds-lang/src/language/validation/names.ts
Original file line number Diff line number Diff line change
Expand Up @@ -105,8 +105,8 @@ export const nameMustNotOccurOnCoreDeclaration = (services: SafeDsServices) => {
export const nameShouldHaveCorrectCasing = (services: SafeDsServices) => {
const settingsProvider = services.workspace.SettingsProvider;

return async (node: SdsDeclaration, accept: ValidationAcceptor) => {
if (!(await settingsProvider.shouldValidateNameConvention())) {
return (node: SdsDeclaration, accept: ValidationAcceptor) => {
if (!settingsProvider.shouldValidateNameConvention()) {
/* c8 ignore next 2 */
return;
}
Expand Down
Loading

0 comments on commit ef4bb6f

Please sign in to comment.