Where communities thrive


  • Join over 1.5M+ people
  • Join over 100K+ communities
  • Free without limits
  • Create your own community
People
Repo info
Activity
    Chris Kipp
    @ckipp:matrix.org
    [m]
    I mean if you are going to put in a ton of work to implement this, you could just contribute semantic tokens to metals 😸
    Hanns Holger Rutz
    @Sciss
    haha
    I am actually looking for people to help me make this work in the first place. So ideally an existing library I can use, like scalariform used to be.
    Chris Kipp
    @ckipp:matrix.org
    [m]
    Is scalariform still maintained?
    Hanns Holger Rutz
    @Sciss
    It seems to be the fate of tooling libraries for Scala, that they never really work 100%, and are abandoned at random points in their history.
    Last changes are from 2019, and it was used for Scala-IDE (Eclipse) which most definitely is abandoned.
    This was already the schism of Scala 2. It had the presentation compiler, which is the ideal place to give you the lexer. But then over time, the output of the lexer diverged from the actual representation of the source text. Like positions didn't agree, you needed a lot of heuristics to get the "correct" tokens etc.
    Definitely running a bundle of regexes will most likely not get you a 100% correct token stream for Scala.
    Hanns Holger Rutz
    @Sciss
    Any suggestions for trying to gather some people who would help out implementing a FLOSS project with LSP client functionality to work with Metals?
    Hanns Holger Rutz
    @Sciss
    Just to follow up on the lexer, the tm4s project's core package seems to have a working text mate grammar parser based on joni, a java port of Oniguruma, the reg-ex parser needed for textmate:
        val registry    = new Registry()
    
        val grammar     = registry.loadGrammarFromPathSync("Scala.tmLanguage.json",
          TextMateTest.getClass.getResourceAsStream("/Scala.tmLanguage.json"))
    
        val source      = "object Foo { def main(args: Array[String]): Unit = println(\"Hello\") }"
    
        val lineTokens  = grammar.tokenizeLine(source)
        val tokens      = lineTokens.getTokens
        tokens.foreach { tk =>
          val sub = source.substring(tk.getStartIndex, tk.getEndIndex)
            println(s"[${tk.getStartIndex} to ${tk.getEndIndex}] source '$sub' has scopes ${tk.getScopes}")
        }
    [0 to 6] source 'object' has scopes [source.scala, keyword.declaration.scala]
    [6 to 7] source ' ' has scopes [source.scala]
    [7 to 10] source 'Foo' has scopes [source.scala, entity.name.class.declaration]
    [10 to 11] source ' ' has scopes [source.scala]
    [11 to 12] source '{' has scopes [source.scala, punctuation.section.block.begin.scala]
    [12 to 13] source ' ' has scopes [source.scala]
    [13 to 16] source 'def' has scopes [source.scala, keyword.declaration.scala]
    [16 to 17] source ' ' has scopes [source.scala]
    [17 to 21] source 'main' has scopes [source.scala, entity.name.function.declaration]
    [21 to 22] source '(' has scopes [source.scala, meta.bracket.scala]
    [22 to 26] source 'args' has scopes [source.scala, variable.parameter.scala]
    [26 to 27] source ':' has scopes [source.scala, meta.colon.scala]
    [27 to 28] source ' ' has scopes [source.scala]
    [28 to 33] source 'Array' has scopes [source.scala, entity.name.class]
    [33 to 34] source '[' has scopes [source.scala, meta.bracket.scala]
    [34 to 40] source 'String' has scopes [source.scala, entity.name.class]
    [40 to 41] source ']' has scopes [source.scala, meta.bracket.scala]
    [41 to 42] source ')' has scopes [source.scala, meta.bracket.scala]
    [42 to 43] source ':' has scopes [source.scala, keyword.operator.scala]
    [43 to 44] source ' ' has scopes [source.scala]
    [44 to 48] source 'Unit' has scopes [source.scala, entity.name.class]
    [48 to 49] source ' ' has scopes [source.scala]
    [49 to 50] source '=' has scopes [source.scala, keyword.operator.comparison.scala]
    [50 to 58] source ' println' has scopes [source.scala]
    [58 to 59] source '(' has scopes [source.scala, meta.bracket.scala]
    [59 to 60] source '"' has scopes [source.scala, string.quoted.double.scala, punctuation.definition.string.begin.scala]
    [60 to 65] source 'Hello' has scopes [source.scala, string.quoted.double.scala]
    [65 to 66] source '"' has scopes [source.scala, string.quoted.double.scala, punctuation.definition.string.end.scala]
    [66 to 67] source ')' has scopes [source.scala, meta.bracket.scala]
    [67 to 68] source ' ' has scopes [source.scala]
    [68 to 69] source '}' has scopes [source.scala, punctuation.section.block.end.scala]
    Ólafur Páll Geirsson
    @olafurpg
    fat jars.
    @Sciss
    if metals was distributed as a fat jar then it would weigh hundreds of megabytes to support all scala versions
    the current solution of dynamically downloading/launching via coursier avoids that problem, and even has the benefit of downloading making metals updates incremental (because unchanged dependencies remain cached)
    it would probably wieght gigabytes, because metals currently supports all versions of scalafmt
    Ólafur Páll Geirsson
    @olafurpg
    metals can be distributed an an offline app by running the provided main method that downloads dependencies. As long as you cache the coursier directory then metals can run without accessing the internet. My observation is that demand for offline-only usage is in decline.
    As for providing a library API, you are free to poke into internal interfaces but they are subject to breaking changes on every release. Some components inside metals are more stable than others.
    It’s not too different from the Scala 2 presentation compiler API. One difference is that the Metals implementations are explicitly inside “internal” packages to document expectations about stability
    Ólafur Páll Geirsson
    @olafurpg
    As for semantic highlighting, i think the hard parts are already implemented to support this feature. Nobody has pushed hard enough to implement it yet
    Hanns Holger Rutz
    @Sciss
    thanks ólafur for the various explanations! I will try first with coursier auto management and not directly include metals in published jars
    Ólafur Páll Geirsson
    @olafurpg
    @Sciss you can pupulate the download cache by calling this dedicated main method https://github.com/scalameta/metals/blob/main/metals/src/main/scala/scala/meta/metals/DownloadDependencies.scala
    heksesang
    @heksenlied:matrix.org
    [m]
    It seems that vscode gets stuck indexing when I try to import projects with a large number of modules. Is this a known problem?
    (The import works fine, but then it just says "Indexing..." in the bottom right corner forever after that.)
    Ólafur Páll Geirsson
    @olafurpg
    @heksenlied:matrix.org are you using the latest version of your JVM? There was a bug in an older JVM 11 version that caused an infinte loop
    Could you try to run async-profiler on the metals process to see what it’s doing? https://github.com/jvm-profiling-tools/async-profiler
    heksesang
    @heksenlied:matrix.org
    [m]
    Hmmm... Thought I was running the latest, but according to the output panel I am using Java 11.
    I'll try with a later version and see if that solves it.
    heksesang
    @heksenlied:matrix.org
    [m]
    Seems the problem goes away if I use Java 16.
    Ólafur Páll Geirsson
    @olafurpg
    @heksenlied:matrix.org you might be able to use a newer version of JVM 11
    Markus Appel
    @markusa380
    Quick question, is there any way that I can stop Metals on Visual Studio Code from starting SBT when using SBT as language server? I'd rather start SBT manually and have it connect, but it's always faster than me.
    sbt --client works but still has bugs with autocompletion and disconnects on Mac so
    Andreas Flierl
    @asflierl
    That's something I wish for as well – especially since the implicitly started SBT server does not utilize the flags given in .jvmopts 🤕
    Chris Kipp
    @ckipp:matrix.org
    [m]
    @asflierl: I believe it should, as when we compose the args to create the actual bsp file args, we do look at them https://github.com/scalameta/metals/blob/6fd19300ed684410875db340e329cb85a42c58f2/metals/src/main/scala/scala/meta/internal/builds/SbtBuildTool.scala#L83-L84
    this could be that when that file is generated by sbt and not metals, it doesn't take them into account
    it's worth filing an issue
    @markusa380: could you elaborate a bit more? sbt server needs to be started in order for it to function as a BSP server
    an alternative would be to start sbt --client first in the workspace, then open the project in Metals if you've chose sbt as a BSP server
    then it'd just connect to the already running server
    Markus Appel
    @markusa380
    @ckipp:matrix.org of course Metals needs SBT to function as BSP, but it would be a bit more ergonomic to "wait" for an SBT instance instead of starting one unasked. It is after all a tool that integrates with SBT less than SBT being a tool integrating with Metals.
    To rephrase, I need to use SBT and Metals, and Metals depends on SBT, so Metals should not start SBT, because I also need SBT. So I should start SBT and Metals should pick that up, as it already does when starting SBT itself and waiting for it to boot up
    It should at least be a flag one can set in the preferences that make Metals wait for a server instead of starting one.
    Or, what would also work, and might solve more than just this issue, is if the command to start SBT is configurable.
    Chris Kipp
    @ckipp:matrix.org
    [m]
    well both Metals and sbt are implementing BSP here, and according to BSP discover, if a .bsp/<server>.json file exists, that's an indication that it should be started. So in this situation when you've chosen to use sbt as a build server at some point in time and open the project, metals remembers that, follows BSP discovery rules and starts the server since it needs that in order to function
    Markus Appel
    @markusa380

    There's this setting already:

    Sbt Script
    Optional absolute path to an sbt executable to use for running sbt bloopInstall.
    By default, Metals uses java -jar sbt-launch.jar with an embedded launcher while respecting .jvmopts and .sbtopts.
    Update this setting if your sbt script requires more customizations like using environment variables.

    But this is not honored.

    4 replies
    Chris Kipp
    @ckipp:matrix.org
    [m]

    It should at least be a flag one can set in the preferences that make Metals wait for a server instead of starting one.

    But metals would sort of be unusable until that happened

    Markus Appel
    @markusa380
    We unfortunately have the special case here that SBT cannot run twice on the same project without severe problems
    Yes of course it wouldn't be usable until that
    Chris Kipp
    @ckipp:matrix.org
    [m]
    but when sbt server is running for a workspace, it only runs once right? So does starting sbt server first and then vs code work in this scenario?
    because even then, only one sbt instance would be running
    Markus Appel
    @markusa380
    But currently it's making my life harder because I need to hard kill the implicitly started SBT instance to start my explicit SBT instance so I can run SBT commands and force clean/recompile on demand

    So does starting sbt server first and then vs code work in this scenario?

    Yes, it would, but I want to of course use the integrated terminal to avoid alt-tabbing between the windows. Most people prefer that I think.