csharp-language-server-protocol icon indicating copy to clipboard operation
csharp-language-server-protocol copied to clipboard

TextDocumentSyncHandler doesn't seem to take into consideration its TextDocumentSyncRegistrationOptions

Open OGMichel opened this issue 4 years ago • 2 comments

Hello,

I ask for your help again.

In our extension we want to manage the updates of two type of files. To do so we created two different SyncHandlers, each of which inherits from TextDocumentSyncHandlerBase.

Each handler implement its own DocumentSelector, with the appropriate pattern and language for the kind of file it needs to manage. The DocumentSelector is then passed to the TextDocumentSyncRegistrationOptions created in CreateRegistrationOptions.

But when our server receives a request managed by the TextDocumentSyncHandler (for example a DidOpenTextDocumentParams request) it systematically calls both Handlers, as if it didn't do any checking with the TextDocumentSyncRegistrationOptions of any of the handlers.

Is it possible to configure the handlers as I intend to do (each one managing a specific extension) or are the requests automatically linked to every handlers of the server ?

Here is the code for our handlers. When I do a modification in "test.amlg" the Handle functions in both Handlers are called.

internal class AmlgDocumentSyncHandler : TextDocumentSyncHandlerBase
    {
        private readonly Workspace workspace;

        private readonly DocumentSelector documentSelector = new DocumentSelector(
            new DocumentFilter
            {
                Pattern = "**/*.amlg",
                Language = "amlg",
                Scheme = "file"
            }
        );

        public AmlgDocumentSyncHandler(Workspace workspace, ILogger logger) : base()
        {
            Log = logger.ForContext<AmlgDocumentSyncHandler>();
            this.workspace = workspace;
        }

        private ILogger Log { get; }

        public override TextDocumentAttributes GetTextDocumentAttributes(DocumentUri uri) => new TextDocumentAttributes(uri, "amlg");

        public override Task<Unit> Handle(DidOpenTextDocumentParams request, CancellationToken cancellationToken)
        {
            Log.Information("Document Opened");
            workspace.Open(request.TextDocument.Uri, request.TextDocument.Version ?? 0, request.TextDocument.Text);
            return Unit.Task;
        }

        public override Task<Unit> Handle(DidChangeTextDocumentParams request, CancellationToken cancellationToken)
        {
            Log.Information("Document Changed");
            workspace.Change(request.TextDocument.Uri, request.TextDocument.Version ?? 0, request.ContentChanges.Last().Text);
            return Unit.Task;
        }

        public override Task<Unit> Handle(DidCloseTextDocumentParams request, CancellationToken cancellationToken)
        {
            Log.Information("Document Closed");
            workspace.Close(request.TextDocument.Uri);
            return Unit.Task;
        }

        public override Task<Unit> Handle(DidSaveTextDocumentParams request, CancellationToken cancellationToken)
        {
            return Unit.Task;
        }

        protected override TextDocumentSyncRegistrationOptions CreateRegistrationOptions(SynchronizationCapability capability, ClientCapabilities clientCapabilities)
        {
            return new TextDocumentSyncRegistrationOptions()
            {
                Save = true,
                Change = TextDocumentSyncKind.Full,
                DocumentSelector = documentSelector
            };
        }
    }
internal class JsonDocumentSyncHandler : TextDocumentSyncHandlerBase
    {
        private readonly Workspace workspace;

        private readonly DocumentSelector documentSelector = new DocumentSelector(
            new DocumentFilter
            {
                Pattern = "**/model.json",
                Language = "json",
                Scheme = "file"
            }
        );

        public JsonDocumentSyncHandler(Workspace workspace, ILogger logger) : base()
        {
            Log = logger.ForContext<JsonDocumentSyncHandler>();
            this.workspace = workspace;
        }

        private ILogger Log { get; }

        public override TextDocumentAttributes GetTextDocumentAttributes(DocumentUri uri) => new TextDocumentAttributes(uri, "json");

        public override Task<Unit> Handle(DidOpenTextDocumentParams request, CancellationToken cancellationToken)
        {
            Log.Information("Project Opened");
            workspace.OpenProject(request.TextDocument.Uri, request.TextDocument.Text);
            return Unit.Task;
        }

        public override Task<Unit> Handle(DidChangeTextDocumentParams request, CancellationToken cancellationToken)
        {
            Log.Information("Project Changed");
            workspace.ChangeProject(request.TextDocument.Uri, request.ContentChanges.Last().Text);
            return Unit.Task;
        }

        public override Task<Unit> Handle(DidCloseTextDocumentParams request, CancellationToken cancellationToken)
        {
            Log.Information("Project Closed");
            workspace.CloseProject(request.TextDocument.Uri);
            return Unit.Task;
        }

        public override Task<Unit> Handle(DidSaveTextDocumentParams request, CancellationToken cancellationToken)
        {
            return Unit.Task;
        }

        protected override TextDocumentSyncRegistrationOptions CreateRegistrationOptions(SynchronizationCapability capability, ClientCapabilities clientCapabilities)
        {
            return new TextDocumentSyncRegistrationOptions()
            {
                Save = true,
                Change = TextDocumentSyncKind.Full,
                DocumentSelector = documentSelector
            };
        }
    }

OGMichel avatar Mar 22 '21 16:03 OGMichel

In theory things should "just work". The first thing that jumps out at me is the Scheme = "file" in both document filters. While it shouldn't cause a match due to the other two values, I wonder if perhaps it is!

david-driscoll avatar Apr 01 '21 04:04 david-driscoll

If you turn on verbose logs in vscode (or whatever editor your using) you should see a bunch of extra logs come through: https://github.com/OmniSharp/csharp-language-server-protocol/blob/master/src/Server/Matchers/TextDocumentMatcher.cs#L82

david-driscoll avatar Apr 01 '21 04:04 david-driscoll