Giter Club home page Giter Club logo

stags's Introduction

stags: Scala tags generator

Installation

Using graalvm: Recommended

Requires native-image.

Clone this repository and call sbt cli/graalvm-native-image:packageBin. This will create a native image in cli/target/graalvm-native-image/stags. Copy this file somewhere in your $PATH.

Using Coursier:

coursier bootstrap co.pjrt:stags-cli_2.12:0.5.0 -o stags

If you want to use stags tag generation as a library, you can add it to sbt with:

libraryDependencies += "co.pjrt" % "stags_2.12" % "0.5.0"

Using Nailgun:

You can use Coursier to create a standalone cli for starting Stags with Nailgun like this:

coursier bootstrap --standalone co.pjrt:stags-cli_2.12:0.5.0 \
  -o stags_ng -f --main com.martiansoftware.nailgun.NGServer
stags_ng & // start nailgun in background
ng ng-alias stags co.pjrt.stags.cli.Main
ng stags --version

You can then create an alias for ng stags if that's still too much typing.

Caveats and tips:

  • You must call ng ng-alias after every restart of the nailgun server. You could create a script to do this
    • You could also simply make an alias in your terminal (ie: alias stags=ng co.pjrt.stags.cli.Main).
  • If you are running multiple Nailgun instances (for example, one for stags and one for scalafmt) you must run one of them in a different port.
    • In the above example, simply call stags_ng $new_port to run the stags ng instance in a different port. Then all ng calls need to have the flag --nailgun-port $new_port in them.
    • You could in theory simply feed both jars (ie: stags and scalafmt) into the same ng instance but beware this could cause classpath conflicts between the two (or more) jars.

Usage

stags ./

This will fetch all Scala files under the current directory. The tags file will be generated in ./tags. To place the tags file somewhere else, do:

stags ./ -o path/to/tags

Features

The two main differences between stags and a general ctags generator like Universal CTags is its ability to understand Scala code (with all its intricacies) and the ability to produce qualified tags.

Understanding Scala intricacies and static tagging them

What are static tags? Static tags are tags for "static functions". In the C world this means functions that can only be used in the file where they are defined; you could think of them as "private". Vim understand static tags and will match them first before anything else.

Static tags lend themselves nicely to private field and functions, so stags marks private statements and fields as static, while taking care of some Scala intricacies.

If a def/val/class/ect is private within its file, then it is static. If it is private for some large scope, then it isn't static. This means that if it is private[X] then we check if X is an enclosing object within the file. However, if X isn't an enclosing object in this file, then we mark it as non-static. For example

package org.example.somepackage.test

object X {
  object Y {
    private[X] def f = …
  }
}

object K {
  private[somepackage] def g = …
}

In this example, f would be static, but g isn't because g might be accessed from outside the file.

Other cases that are marked as static are:

  • constructor fields in classes (ie: in class X(a: Int, b: String, c: Boolean), a, b and c will all be static)
    • But non-static for the first parameter group of case classes (since those are accessible by default)
      • case class X(a: Int)(b: Int) <- a will be non-static, but b will be static
    • Any that are marked as "private" are static
  • the single field in an implicit class/case class
    • implicit class X(val x: Int) <- x is static
    • this is done because chances are that x will never be accessed anywhere but this file
  • all implicit things (val, defs, class, etc)
    • these things are rarely, if ever, accessed via their tokens

Qualified tags

A common pattern found when importing conflicting fields is to use them in a qualified form. For example:

import org.example.SomeObject
import org.example.OtherObject

SomeObject.foo(...)
OtherObject.foo(...)

In order to differentiate between the two, stags generates tags for all fields along with an extra tag that combines their parent with the tag itself. Note that stags never generates qualified tags for fields/methods in trait and class (only objects and package objects) since said fields/methods cannot be qualifiedly referenced.

Following code, by default, would produce three tags: Example, foo and Example.foo:

package object test {
  object Example {
    def foo(...)
  }
}

The depth of the qualified tags is controlled by --qualified-depth. Setting it to three (3) would produce a third tag test.Example.foo.

Vim support for qualified tags

Vim won't understand such a tag right off the bat. The following modification is required:

function! QualifiedTagJump() abort
  let l:plain_tag = expand("<cword>")
  let l:orig_keyword = &iskeyword
  set iskeyword+=\.
  let l:word = expand("<cword>")
  let &iskeyword = l:orig_keyword

  let l:splitted = split(l:word, '\.')
  let l:acc = []
  for wo in l:splitted
    let l:acc = add(l:acc, wo)
    if wo ==# l:plain_tag
      break
    endif
  endfor

  let l:combined = join(l:acc, ".")
  try
    execute "ta " . l:combined
  catch /.*E426.*/ " Tag not found
    execute "ta " . l:plain_tag
  endtry
endfunction

nnoremap <silent> <C-]> :<C-u>call QualifiedTagJump()<CR>

Tips for tagging jars

Vim support for jars

Vim supports the ability to look at the contents of a zip file by default in the following way:

vim zipfile:/path/to/zip::/path/inside/zip

This will open contents of the path inside of the zip in a new buffer. Since jars are just zip files, we can use that to create tags for jar files. This is specially useful when wanting to tag external sources.

Before we can use that though, the following settings in vim need to be disabled:

set notagrelative " Required due to the way it tries to search for the tag relative to the tags file

au BufEnter zipfile:/*.scala set nomodifiable " This isn't required, but nice if you want it to behave like an IDE

You could get away with keeping tagrelative on IFF your set tags is set to to ./tags and nothing else. If you search for the tags file outsise of the current directly, then you MUST disable tagrelative.

With that set, we can now call stags, but we must pass --absolute-files. Since we disabled tagrelative we must now create tags as absolute tags (path to files are absolute, not relative).

stags --absolute-files -o /path/to/output ./

Tagging source files: Global cache

Since the tags setting in vim allows for multiple tag files (in order of preference), we can have a local tags files and a global one for all sources like so:

set tags=./tags,/home/user/globalTags
$ cd /home/user
$ stags --absolute-files -o globalTags /home/user/.cache/coursier/ /home/user/.ivy2/cache/

Some caveats:

  • This will create a massive tags file.
  • Since you can have different derisions of libraries in the cache, this will create a lot of duplicate tags (one for each version). This can lead to confusion in the future.

Tagging source files: Downloading source files to local project

Another strategy is to instead use sbt to copy over the source jar that the project requires, and tagging only those files. For this to happen you will need a small plugin:

import sbt.Keys._
import sbt._
import java.nio.file.{FileAlreadyExistsException, Files, Path, Paths}
import scala.util.{Failure, Success, Try}

object DownloadSourcesPlugin {
  val downloadSources = taskKey[Unit]("Download sources")
  val downloadSourcesLocation = settingKey[File]("Download sounds location")
  val downloadSourcesTypes = settingKey[List[String]](
    "Types of sources to download (default: javadoc, source)"
  )

  def downloadSettings =
    Seq(
      // We store all sources in one directory for all projects.
      // This allows us to remove duplicates below, which are common in multi-projects.
      // Change this to `target.value / "externalSources"` if you want to have one per project.
      downloadSourcesLocation := file(".") / "target" / "externalSources",
      cleanFiles += baseDirectory.value / downloadSourcesLocation.value.toString,
      downloadSourcesTypes := List("sources"),
      downloadSources := {
        val report = updateClassifiers.value
        val log = streams.value.log
        val dir = downloadSourcesLocation.value
        val types = downloadSourcesTypes.value
        def matchesTypes(f: File) =
          types.exists(t => f.getName().endsWith(t + ".jar"))
        dir.mkdirs()
        report.allFiles.map {
          case target if matchesTypes(target) =>
            val newLink = (dir / target.getName).toPath
            Try(Files.createLink(newLink, target.toPath)) match {
              case Success(_)                             => ()
              case Failure(e: FileAlreadyExistsException) => ()
              case Failure(e)                             => log.error(e.getMessage)
            }
          case _ => ()
        }
      }
    )
}

After adding this plugin, we can call sbt downloadSources.

This plugin will copy the source files from the cache into target/externalSources for a project. stags can then pick them up from there (alongside the source files). We can then tag sources and jars separately:

stags --file-types jar -o tags-external target/externalSources
stags --file-types scala -o tags ./

For this to work we need to also change our tags setting like so:

set tags=./tags,tags-external

One way to add this plugin to all projects without committing anything into your repos is to:

  • Place the file above in ~/.sbt/1.0/plugins/
  • Create a GlobalPlugin in ~/.sbt/1.0/plugins/ with the following contents
import sbt._

object GlobalPlugin extends AutoPlugin {
  override def requires = sbt.plugins.JvmPlugin
  override def trigger = allRequirements

  override def projectSettings = DownloadSourcesPlugin.downloadSettings
}

stags's People

Contributors

drxcc avatar pjrt avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

Forkers

sullivan- drxcc

stags's Issues

java.lang.UnsupportedOperationException during build

I'm trying to build stags in following environment:

$ uname -a
MSYS_NT-6.1 PRGLAP4LNL4H2 2.8.2(0.313/5/3) 2017-07-14 08:19 x86_64 Msys

$ java -version
openjdk version "1.8.0_131"
OpenJDK Runtime Environment (Zulu 8.21.0.1-win64) (build 1.8.0_131-b11)
OpenJDK 64-Bit Server VM (Zulu 8.21.0.1-win64) (build 25.131-b11, mixed mode)

$ sbt sbt-version
[info] Loading global plugins from C:\Users\vkotacka\.sbt\0.13\plugins
[info] Loading project definition from C:\msys64\home\vkotacka\projects\scala\stags\project
[info] Set current project to root (in build file:/C:/msys64/home/vkotacka/projects/scala/stags/)
[info] stags/*:sbtVersion
[info]  0.13.15
[info] cli/*:sbtVersion
[info]  0.13.15
[info] root/*:sbtVersion
[info]  0.13.15

and I'm receiving following exception:

$ pwd
/home/vkotacka/projects/scala/stags

$ bin/install
[info] Loading global plugins from C:\Users\vkotacka\.sbt\0.13\plugins
[info] Loading project definition from C:\msys64\home\vkotacka\projects\scala\stags\project
[info] Set current project to root (in build file:/C:/msys64/home/vkotacka/projects/scala/stags/)
[success] Total time: 32 s, completed Aug 10, 2017 4:15:57 PM
[info] Updating {file:/C:/msys64/home/vkotacka/projects/scala/stags/}cli...
[info] Resolving jline#jline;2.14.3 ...
[info] Done updating.
[info] Compiling 5 Scala sources to C:\msys64\home\vkotacka\projects\scala\stags\cli\target\scala-2.12\classes...
[info] Including: inline_2.12-1.8.0.jar
[info] Including: fastparse_2.12-0.4.3.jar
[info] Including: parsers_2.12-1.8.0.jar
[info] Run completed in 61 milliseconds.
[info] Total number of tests run: 0
[info] Suites: completed 0, aborted 0
[info] Tests: succeeded 0, failed 0, canceled 0, ignored 0, pending 0
[info] No tests were executed.
[info] Including: scala-library.jar
[info] Including: semantic_2.12-1.8.0.jar
[info] Including: scalapb-runtime_2.12-0.6.0-pre2.jar
[info] Including: fastparse-utils_2.12-0.4.3.jar
[info] Including: trees_2.12-1.8.0.jar
[info] Including: inputs_2.12-1.8.0.jar
[info] Including: io_2.12-1.8.0.jar
[info] Including: tokens_2.12-1.8.0.jar
[info] Including: lenses_2.12-0.4.10.jar
[info] Including: tokenizers_2.12-1.8.0.jar
[info] Including: protobuf-java-3.2.0.jar
[info] Including: common_2.12-1.8.0.jar
[info] Including: sourcecode_2.12-0.1.3.jar
[info] Including: dialects_2.12-1.8.0.jar
[info] Including: scalameta_2.12-1.8.0.jar
[info] Including: scopt_2.12-3.5.0.jar
[info] Including: quasiquotes_2.12-1.8.0.jar
[info] Including: transversers_2.12-1.8.0.jar
[info] Checking every *.class/*.jar file's SHA-1.
[info] Merging files...
[warn] Merging 'META-INF\MANIFEST.MF' with strategy 'discard'
[warn] Merging 'META-INF\maven\com.google.protobuf\protobuf-java\pom.properties' with strategy 'discard'
[warn] Merging 'META-INF\maven\com.google.protobuf\protobuf-java\pom.xml' with strategy 'discard'
[warn] Strategy 'discard' was applied to 3 files
[info] SHA-1: 5ebb1d25dde4c4e768527ee7f0b0788963b69ea7
[info] Packaging C:\msys64\home\vkotacka\projects\scala\stags\cli\target\scala-2.12\stags-0.2.5-SNAPSHOT ...
[info] Done packaging.
java.lang.UnsupportedOperationException
        at java.nio.file.Files.setPosixFilePermissions(Files.java:2044)
        at $4ecf29e3788409d1bf40$$anonfun$cli$13.apply(build.sbt:62)
        at $4ecf29e3788409d1bf40$$anonfun$cli$13.apply(build.sbt:45)
        at scala.Function1$$anonfun$compose$1.apply(Function1.scala:47)
        at sbt.$tilde$greater$$anonfun$$u2219$1.apply(TypeFunctions.scala:40)
        at sbt.std.Transform$$anon$4.work(System.scala:63)
        at sbt.Execute$$anonfun$submit$1$$anonfun$apply$1.apply(Execute.scala:228)
        at sbt.Execute$$anonfun$submit$1$$anonfun$apply$1.apply(Execute.scala:228)
        at sbt.ErrorHandling$.wideConvert(ErrorHandling.scala:17)
        at sbt.Execute.work(Execute.scala:237)
        at sbt.Execute$$anonfun$submit$1.apply(Execute.scala:228)
        at sbt.Execute$$anonfun$submit$1.apply(Execute.scala:228)
        at sbt.ConcurrentRestrictions$$anon$4$$anonfun$1.apply(ConcurrentRestrictions.scala:159)
        at sbt.CompletionService$$anon$2.call(CompletionService.scala:28)
        at java.util.concurrent.FutureTask.run(FutureTask.java:266)
        at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
        at java.util.concurrent.FutureTask.run(FutureTask.java:266)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
        at java.lang.Thread.run(Thread.java:748)
[error] (cli/*:dist) java.lang.UnsupportedOperationException
[error] Total time: 51 s, completed Aug 10, 2017 4:16:47 PM

Compilation fails (GraalVM 21.3.0 Java 11 on Ubuntu 21.10)

i'm working with:

Author: Pedro Rodriguez <[email protected]>
Date:   Mon Mar 15 17:52:54 2021 -0400

    Change the local tutorial

trying to build using GraalVM 21.3.0 Java 11 on Ubuntu 21.10 fails with the errors:

[info]   Compilation completed in 11.585s.
[error] /git/stags/stags/src/main/scala/co/pjrt/stags/TagGenerator.scala:310:41: value toList is not a member of java.util.stream.Stream[String]
[error]     val line = tree.tokens.syntax.lines.toList(lineWithTagName).trim
[error]                                         ^
[error] /git/stags/stags/src/main/scala/co/pjrt/stags/TagGenerator.scala:309:49: local val lineWithTagName in method addrForTree is never used
[error]     val lineWithTagName = tagName.pos.startLine - tree.pos.startLine
[error]                                                 ^
[error] /git/stags/stags/src/main/scala/co/pjrt/stags/TagGenerator.scala:310:9: local val line in method addrForTree is never used
[error]     val line = tree.tokens.syntax.lines.toList(lineWithTagName).trim
[error]         ^
[error] three errors found
[error] (stags / Compile / compileIncremental) Compilation failed
[error] Total time: 17 s, completed Nov 24, 2021, 6:48:15 PM

i've made a small tweak to the code and am able to get it building, though i don't yet know whether the resulting program actually works as it's supposed to. here's that diff:

diff --git a/stags/src/main/scala/co/pjrt/stags/TagGenerator.scala b/stags/src/main/scala/co/pjrt/stags/TagGenerator.scala
index 5468436..559c530 100644
--- a/stags/src/main/scala/co/pjrt/stags/TagGenerator.scala
+++ b/stags/src/main/scala/co/pjrt/stags/TagGenerator.scala
@@ -303,11 +303,12 @@ private object AddressGen {
    * cursor location.
    */
   def addrForTree(tree: Tree, tagName: Name): String = {
+    import scala.collection.JavaConverters._

     // DESNOTE(2017-12-21, pjrt): This should always return 0 or more, otherwise
     // scalameta wouldn't have parsed it.
     val lineWithTagName = tagName.pos.startLine - tree.pos.startLine
-    val line = tree.tokens.syntax.lines.toList(lineWithTagName).trim
+    val line = tree.tokens.syntax.lines.iterator.asScala.toList(lineWithTagName).trim

     val name = tagName.value
     val replacement = s"\\\\zs$name"

Any way to use stags as an sbt task

The README provides a way to get stags-cli using coursier, however would it be possible to use stags as an sbt plugin so tag generation can be automated after every compile?

Don't create public tags for implicit vals and defs

These variables and defs are rarely, if ever, accessed by name from outside their defining file. We could avoid making public tags for them (make them private?) and thus prevent collisions with real, accessible fields.

scala.MatchError: 1 (of class scala.meta.Lit$LitImpl)

git clone https://github.com/scalacenter/scalafix.git
cd scalafix
coursier launch co.pjrt:stags-cli_2.12:0.1.1 -- ./
Exception in thread "main" scala.MatchError: 1 (of class scala.meta.Lit$LitImpl)
	at co.pjrt.stags.TagGenerator$.getFromPats(TagGenerator.scala:127)
	at co.pjrt.stags.TagGenerator$.getFromPat$1(TagGenerator.scala:118)
	at co.pjrt.stags.TagGenerator$.$anonfun$getFromPats$2(TagGenerator.scala:124)
	at scala.collection.TraversableLike.$anonfun$flatMap$1(TraversableLike.scala:241)
	at scala.collection.immutable.List.foreach(List.scala:389)
	at scala.collection.TraversableLike.flatMap(TraversableLike.scala:241)
	at scala.collection.TraversableLike.flatMap$(TraversableLike.scala:238)
	at scala.collection.immutable.List.flatMap(List.scala:352)
	at co.pjrt.stags.TagGenerator$.getFromPats(TagGenerator.scala:124)
	at co.pjrt.stags.TagGenerator$.$anonfun$tagsForStatement$1(TagGenerator.scala:71)
	at scala.collection.TraversableLike.$anonfun$flatMap$1(TraversableLike.scala:241)
	at scala.collection.immutable.List.foreach(List.scala:389)
	at scala.collection.TraversableLike.flatMap(TraversableLike.scala:241)
	at scala.collection.TraversableLike.flatMap$(TraversableLike.scala:238)

Seems like

is missing a fallback.

Nailgun doesn't work due to working directories

Turns out that when ng ... <someFile> the someFile is sent to the server as is, which means that the server interprets it as if it was coming from its own current working directory. This leads to incorrect behavior (where the files are looked up where the server was started).

Can't build, can't find dependencies

Build fails since sbt assembly can't be found.
sbt.ResolveException: unresolved dependency: com.eed3si9n#sbt-assembly;0.14.4: not found

Are you able to build with a fresy .ivy2 cache?

Add tag kinds to tags (def, val, trait, etc)

This can allow other tools (maybe tag searchers like fzf-vim) to be smarter about the look. May even allow for smarter tag jumping (jump giving priority to class vs trait, for example).

More use cases are welcomed.

Don't use `call cursor`

So this is embarrassing, call cursor, though it allows stags to move the cursor to the correct place, it is actually quite brittle. The reason is that as code changes, the call cursor(x, y) function won't actually point to the place you want it to point.

I wanted to avoid using /search/ since it can be so random (and drops you off in an odd place) but that may be the best way. Unless we can find a better way.

Use a less aggresive tag address

Currently, a tag address for:

def foo[A, B, C](a: A, b: B, c: C): Baz

Would create the tag address:

def \zsfoo[A, B, C](a: A, b: B, c: C): Baz

However, this means that if the user changes anything (even a: A -> aa: A) it would cause the address to become invalid. I feel this is too aggressive. Having such a strict tag allows for better precision (disambiguate between a foo with two params vs one with three) but more often than not, people don't have that many overloaded functions (or at least they shouldn't).

This "issue" also extends to case classes and others.

A possible solution is to use everything BUT the params. So the example above would return an address as:

def \zsfoo

Throws org.scalameta.invariants.InvariantFailedException

First thanks for your contribution to open source :)

Unfortunately I cannot use it yet I have tried to generate the tags on the Apache Spark source and got the following error:

$ stags ./
Exception in thread "main" org.scalameta.invariants.InvariantFailedException: invariant failed:
when verifying ScalametaTokenizer.this.input.chars.apply(curr.endOffset.+(1)).==('\"')
found that ScalametaTokenizer.this.input.chars.apply(curr.endOffset.+(1)) is not equal to '\"'
where ScalametaTokenizer = scala.meta.internal.tokenizers.ScalametaTokenizer@5143c662
	at org.scalameta.invariants.InvariantFailedException$.raise(Exceptions.scala:15)
	at scala.meta.internal.tokenizers.ScalametaTokenizer.emitContents$1(ScalametaTokenizer.scala:222)
	at scala.meta.internal.tokenizers.ScalametaTokenizer.loop$1(ScalametaTokenizer.scala:231)
	at scala.meta.internal.tokenizers.ScalametaTokenizer.uncachedTokenize(ScalametaTokenizer.scala:276)
	at scala.meta.internal.tokenizers.ScalametaTokenizer.tokenize(ScalametaTokenizer.scala:31)
	at scala.meta.internal.tokenizers.ScalametaTokenizer$$anon$2.apply(ScalametaTokenizer.scala:287)
	at scala.meta.tokenizers.Api$XtensionTokenizeDialectInput.tokenize(Api.scala:21)
	at scala.meta.tokenizers.Api$XtensionTokenizeInputLike.tokenize(Api.scala:10)
	at scala.meta.internal.parsers.ScalametaParser.scannerTokens$lzycompute(ScalametaParser.scala:183)
	at scala.meta.internal.parsers.ScalametaParser.scannerTokens(ScalametaParser.scala:183)
	at scala.meta.internal.parsers.ScalametaParser.<init>(ScalametaParser.scala:140)
	at scala.meta.internal.parsers.ScalametaParser$$anon$189.apply(ScalametaParser.scala:3465)
	at scala.meta.parsers.Api$XtensionParseDialectInput.parse(Api.scala:21)
	at scala.meta.parsers.Api$XtensionParseInputLike.parse(Api.scala:10)
	at co.pjrt.stags.TagGenerator$.generateTagsForFile(TagGenerator.scala:15)
	at co.pjrt.stags.cli.Cli$.$anonfun$run$3(Cli.scala:33)
	at scala.collection.TraversableLike.$anonfun$flatMap$1(TraversableLike.scala:241)
	at scala.collection.immutable.List.foreach(List.scala:389)
	at scala.collection.TraversableLike.flatMap(TraversableLike.scala:241)
	at scala.collection.TraversableLike.flatMap$(TraversableLike.scala:238)
	at scala.collection.immutable.List.flatMap(List.scala:352)
	at co.pjrt.stags.cli.Cli$.run(Cli.scala:30)
	at co.pjrt.stags.cli.Cli$.run_(Cli.scala:14)
	at co.pjrt.stags.cli.Main$.$anonfun$mainWithCwd$2(Main.scala:24)
	at co.pjrt.stags.cli.Main$.$anonfun$mainWithCwd$2$adapted(Main.scala:24)
	at scala.Option.fold(Option.scala:158)
	at co.pjrt.stags.cli.Main$.mainWithCwd(Main.scala:24)
	at co.pjrt.stags.cli.Main$.main(Main.scala:18)
	at co.pjrt.stags.cli.Main.main(Main.scala)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at coursier.Bootstrap.main(Bootstrap.java:430)

Can't run on scalafix

Fails with:

Error matching Nil in line val m.Source(m.Pkg(_, stats) :: Nil) = source.transform {
    // Remove bodies from methods like `private def foo: Unit` that can't be abstract.
    case m.Defn.Def(mods, name, tparams, paramss, Some(decltpe), _) =>
      m.Decl.Def(mods, name, tparams, paramss, decltpe)
  }

which is here:

https://github.com/scalacenter/scalafix/blob/ffb57a102a1f3a70c41b51778bb3a4811d3e492b/scalafix-tests/unit/src/test/scala/scalafix/tests/core/PrettyTypeSuite.scala#L31-L35

support emacs tags

Generating ctags in emacs uses the -e flag it exuberant tags.

I don't know what that does, but it would be good if stags did that too!

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.