LSP enhancement

@DanTup

Hello, I’m using dart lsp for emacs, and writing flutter code.
Dart analysis server returns so large json response for textDocument/completion that emacs freezes while parsing json file for 10~ seconds
Do you have some idea to reduce it?

I checked the json response and noticed that

  1. documentation is included to response.
  {
    "textEdit": {
      "newText": "widget${1:}",
      "range": {
        "end": {
          "character": 15,
          "line": 45
        },
        "start": {
          "character": 12,
          "line": 45
        }
      }
    },
    "insertTextFormat": 2,
    "insertText": "widget${1:}",
    "sortText": "999000",
    "documentation": {
      "value": "The current configuration.\n\nA [State] object's configuration is the corresponding [StatefulWidget]\ninstance. This property is initialized by the framework before calling\n[initState]. If the parent updates this location in the tree to a new\nwidget with the same [runtimeType] and [Widget.key] as the current\nconfiguration, the framework will update this property to refer to the new\nwidget and then call [didUpdateWidget], passing the old configuration as\nan argument.",
      "kind": "markdown"
    },
    "detail": "HomePage",
    "kind": 10,
    "label": "widget"
  },

Maybe it must be excluded from response according to this issue -> #37060

  1. Set suggestFromUnimportedLibraries = false has no effects for flutter user, beacause import 'package:flutter/material.dart imports almost all source of flutter sdk.

  2. Irrelevant completion item seems to be returned. When we request in position below, All classes in flutter sdk is returned. I don’t know it is due to lsp server or client.

Align(
  
  ↑ send completion request here.
)

Author: Fantashit

7 thoughts on “LSP enhancement

  1. Looking at the log, I think it’s big because:

    1. There are a lot of completions (when including the unimported symbols)
    2. There’s a lot of unnecessary whitespace/formatting (assuming the attached log is as it came)
    3. The “data” that’s round-tripped in order to handle the resolve call is quite large (probably over half of the JSON)

    I don’t think there’s much to do about 1, though 2 could be an easy win (I don’t know if it’ll change the deserialise time much though) and we may need to make changes that could affect 3 anyway based on discussions in Dart-Code/Dart-Code#2290.

  2. The issue being that when doing simple term completion it appears that the Dart language server, when in a Flutter project, is sending upwards of 6,000 candidates which then need to be filtered by the language client.

    5,630 completion items were being sent when using Flutter v1.12.13+hotfix.8 I should clarify. Since that last post I upgraded Flutter (and contained Dart) to the latest in the hope that speed would improve.

    With Flutter v1.17.3 I am appearing to receive 26,789 completion items (at least according to an echo statement deep in the bowels of the LSC plugin) for the same simple term completion (not a . completion).

    This is bringing the language client to its knees even on a fast machine. Processing this 5 times larger list is too much for the plugin. Auto-completion is now unusable.

    Is this the expectation? The Dart language server appears to be sending an ever expanding list of term completions, 5 times more between the above listed Flutter releases, and the LSP client needs quickly filter the big list? Noting that some language clients are implemented in slow languages, it may not be possible to do.

    Or are there some flags that I need to set for the language server?

    I am starting Dart Analysis Server just via: dart $DART_SDK/bin/snapshots/analysis_server.dart.snapshot --lsp

    Any information would be appreciated.

    Best regards.

  3. Ok, I think I tracked down these dupes:

    {“label”::”xxxx”

    There are actually multiple xxxx‘s defined, but they’re static members of classes and should not have been included unless you’d typed the class prefix. This is fixed by 994c0e8 and I can’t repro on master.

    Some APIs such as momentumRetainStationaryDurationThreshold even show up 3 times.

    This will also disappear with the fix above (it’s a static member that shouldn’t have been included), however the reason it appeared multiple times is different – the class that contains it is re-exported in three different libraries. If you haven’t already imported any of them, then it’s valid to show up 3 times as you’re able to select which library you want to import it from (once you’ve already imported a library that has it, it will no loner show up from the others).

    Screenshot 2020-06-10 at 15 02 05

    I’m working on a change to filter by prefix server-side (https://dart-review.googlesource.com/c/sdk/+/150628), and in my testing it seems to make a very significant difference. I’ll ping when it’s finished/merged.

  4. Some interesting results from LSC 303 comparing various language servers

    Two tests were undertaken, counting the number of server-provided completion items when completing a language keyword and also when completing a library type after typing a 3 character prefix.

    Language Language Server Keyword Matches Type Matches
    C++ clangd 100 100
    Dart Analysis Server / Flutter 1.12 5,630 5,619
    Dart Analysis Server / Flutter 1.17 26,789 26,777
    Go gopls 4 4
    JavaScript Microsoft TypeScript LS 1,449 1,203
    JavaScript Sourcegraph JavaScript LS 1,083 1,083
    Ruby Solargraph 4 3
    Rust rust-analyzer 206 206
    Swift SourceKit-LSP 33,216 33,216
    TypeScript Microsoft TypeScript LS 1,371 1,106

    Less is more 😉

  5. @DanTup,

    Thanks for the prompt.

    I typically use the Dart that ships with Flutter; but in this case I temporarily downloaded the latest Dart SDK Dev release 2.9.0-19.0.dev (ref a38037f). Hopefully that contains all the changes referenced in this issue.

    Tested on two machines:

    • Core quad-core i5 / 16GB RAM Linux desktop
    • 2015 Core-M 12″ Macbook (a notoriously slow machine via its fanless CPU)

    Raw match count, same test as my last post:

    Language Language Server Keyword Matches Type Matches
    Dart Analysis Server / Flutter 1.12 5,630 5,619
    Dart Analysis Server / Flutter 1.17 26,789 26,777
    Dart Analysis Server / Dev 2.9.0-19.0 863 572

    Night and day performance difference.

    The interactive performance via the Vim LSC plugin is now smooth as silk. No stall, no stutter unlike the previous Flutter releases; and that even includes when run on the very slow Macbook. It feels as fast as Microsoft’s TypeScript language server and the gopls Go language server.

    No doubt about it, a tremendous result.

    I would say this is now a solved issue.

    Side note, all language servers should try and bound their match counts (say under 1,000), it makes a huge difference client-side in the editor.

    Many thanks to the Dart team, can’t wait for it to roll into an upcoming Flutter release.

  6. I checked 2.9.0-19.0 dart-sdk with emacs(lsp-mode) and it works great!!!
    It works very smooth and increased my fun of writing dart by 10 times.
    Many thanks to dart team and @DanTup

Comments are closed.