Skip to content

Language server waits on initial build before finishing initialization #3492

Description

@SimonCockx

The current implementation of LanguageServerImpl waits on an initial build to finish before responding to the initialize request. This means the client has to wait a long time before it knows the capabilities of the server when running with a workspace that is not trivially small. Additionally, because diagnostics are scheduled to only be published after initialization is complete, this means the client only gets any diagnostics after everything has been build.

I don't see an apparent reason for this. I wonder whether the initial build could be scheduled in the background instead?

From LanguageServerImpl.java:

	@Override
	public CompletableFuture<InitializeResult> initialize(InitializeParams params) {
		if (initializeParams != null) {
			throw new IllegalStateException("This language server has already been initialized.");
		}
		if (languagesRegistry.getExtensionToFactoryMap().isEmpty()) {
			throw new IllegalStateException(
					"No Xtext languages have been registered. Please make sure you have added the languages\'s setup class in \'/META-INF/services/org.eclipse.xtext.ISetup\'");
		}
		initializeParams = params;

		InitializeResult result = new InitializeResult();

		result.setCapabilities(createServerCapabilities(params));
		access.addBuildListener(this);
		return requestManager.runWrite(() -> {
			if (clientSupportsWorkspaceFolders() && workspaceManager.isSupportsWorkspaceFolders()) {
				List<WorkspaceFolder> workspaceFolders = params.getWorkspaceFolders();
				if (workspaceFolders == null)
					workspaceFolders = Collections.emptyList();
				workspaceManager.initialize(workspaceFolders, this::publishDiagnostics, CancelIndicator.NullImpl);
			} else {
				URI baseDir = getBaseDir(params);
				workspaceManager.initialize(baseDir, this::publishDiagnostics, CancelIndicator.NullImpl);
			}
			return result;
		}, (cancelIndicator, it) -> it).thenApply(it -> initializeResult = it);
	}

Suggested change:

    @Override
    public CompletableFuture<InitializeResult> initialize(InitializeParams params) {
        if (initializeParams != null) {
            throw new IllegalStateException("This language server has already been initialized.");
        }
        if (languagesRegistry.getExtensionToFactoryMap().isEmpty()) {
            throw new IllegalStateException(
                    "No Xtext languages have been registered. Please make sure you have added the languages\'s setup class in \'/META-INF/services/org.eclipse.xtext.ISetup\'");
        }
        initializeParams = params;

        InitializeResult result = new InitializeResult();
        result.setCapabilities(createServerCapabilities(params));
        access.addBuildListener(this);
        
        initializeResult = result;
        
        // Schedule a background build of the project
        requestManager.runWrite(() -> {
            if (clientSupportsWorkspaceFolders() && workspaceManager.isSupportsWorkspaceFolders()) {
                List<WorkspaceFolder> workspaceFolders = params.getWorkspaceFolders();
                if (workspaceFolders == null)
                    workspaceFolders = Collections.emptyList();
                workspaceManager.initialize(workspaceFolders, this::publishDiagnostics, CancelIndicator.NullImpl);
            } else {
                URI baseDir = getBaseDir(params);
                workspaceManager.initialize(baseDir, this::publishDiagnostics, CancelIndicator.NullImpl);
            }
            return null;
        }, (cancelIndicator, it) -> it);
        
        return CompletableFuture.completedFuture(result);
    }

As a side point, I would propose that initializeParams, initializeResult and publishDiagnostics are made protected, because it is quite hard to customize this method given that those properties are private.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions