diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 697c167e..0bf91c04 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -12,7 +12,7 @@ jobs:
- uses: olafurpg/setup-scala@v10
- uses: actions/setup-go@v2
with:
- go-version: '^1.13.1'
+ go-version: "^1.13.1"
- run: go get github.com/sourcegraph/lsif-semanticdb/cmd/lsif-semanticdb
- run: sbt test
check:
diff --git a/.github/workflows/mdoc.yml b/.github/workflows/mdoc.yml
new file mode 100644
index 00000000..7d4ee799
--- /dev/null
+++ b/.github/workflows/mdoc.yml
@@ -0,0 +1,14 @@
+name: Website
+on:
+ push:
+ branches: [master, documentation-website]
+ tags: ["*"]
+jobs:
+ publish:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v2
+ - uses: olafurpg/setup-scala@v10
+ - run: sbt docs/docusaurusPublishGhpages
+ env:
+ GIT_DEPLOY_KEY: ${{ secrets.GIT_DEPLOY_KEY }}
diff --git a/.github/workflows/native.yml b/.github/workflows/native.yml
index d9186ead..14c7de58 100644
--- a/.github/workflows/native.yml
+++ b/.github/workflows/native.yml
@@ -30,7 +30,7 @@ jobs:
- name: sbt nativeImage
shell: bash
run: |
- sbt cli/nativeImage "cli/nativeImageRun --cwd tests/gradle-example"
+ sbt cli/nativeImage "cli/nativeImageRun --cwd tests/gradle-example index"
- uses: actions/upload-artifact@master
with:
path: ${{ matrix.local_path }}
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
new file mode 100644
index 00000000..fd947f01
--- /dev/null
+++ b/CONTRIBUTING.md
@@ -0,0 +1,3 @@
+# Contributing guide
+
+See https://sourcegraph.github.io/lsif-java/docs/contributing.html
diff --git a/README.md b/README.md
index 97336cfe..027a58f6 100644
--- a/README.md
+++ b/README.md
@@ -1,175 +1,9 @@
-# Java LSIF indexer 
-
-Visit https://lsif.dev/ to learn about LSIF.
-
-## Usage
-
-⚠️ This project is under development so there is nothing to try out at the
-moment.
-
-### Supported tools and versions
-
-Currently, only Java 8 with the build tool sbt is supported. We hope to increase
-compatibility with more Java language versions and build tools as the project
-evolves.
-
-| Language version | Support |
-| ---------------- | --------------------------------- |
-| Java 7 | ❌ |
-| Java 8 | ✅ |
-| Java 11 | ✅ |
-| Java 12 | Not tested in CI, but should work |
-| Java 13 | Not tested in CI, but should work |
-| Java 14 | Not tested in CI, but should work |
-| Java 15 | ✅ |
-| Java 16 | Not tested in CI, but should work |
-| Java 17 | Not tested in CI, but should work |
-
-| Build tool | Support |
-| ---------- | ------- |
-| Gradle | ✅ |
-| Maven | ✅ |
-| Bazel | ❌ |
-| Buck | ❌ |
-| sbt | ✅ |
-
-## Overview
-
-This project is implemented as a
-[Java compiler plugin](https://docs.oracle.com/en/java/javase/11/docs/api/jdk.compiler/com/sun/source/util/Plugin.html)
-that generates one
-[SemanticDB](https://scalameta.org/docs/semanticdb/specification.html) file for
-every `*.java` source file. After compilation completes, the SemanticDB files
-are processed to produce LSIF.
-
-
-
-### Why Java compiler plugin?
-
-There are several benefits to implementing lsif-java as a compiler plugin:
-
-- **Simple installation**: compiler plugins are enabled with the `-Xplugin`
- compiler option. All Java build tools support a way to customize compiler
- options, simplifying installation.
-- **Language fidelity**: by using the Java compiler to produce semantic
- information, we ensure that the produced LSIF data is accurate even as new
- Java language versions with new language features are released.
-- **Environment fidelity**: by hooking into the compilation process of the build
- tool, we minimize the risk of diverging from the CI build environment such as
- installed system dependencies, custom compiler options and custom annotation
- processors.
-
-### Why SemanticDB?
-
-SemanticDB is Protobuf schema for information about symbols and types in Java
-programs, Scala programs and other languages. There are several benefits to
-using SemanticDB as an intermediary representation for LSIF:
-
-- **Simplicity**: It's easy to translate a single Java source file into a single
- SemanticDB file inside a compiler plugin. It's more complicated to produce
- LSIF because compiler plugins does not have access to a project-wide context,
- which is necessary to produce accurate definitions and hovers in multi-module
- projects with external library dependencies.
-- **Performance**: SemanticDB is fast to write and read. Each compilation unit
- can be processed independently to keep memory usage low. The final conversion
- from SemanticDB to LSIF can be safely parallelized.
-- **Cross-language**: SemanticDB has a
- [spec](https://scalameta.org/docs/semanticdb/specification.html) for Java and
- Scala enabling cross-language navigation in hybrid Java/Scala codebases.
-- **Cross-repository**: Compiler plugins have access to both source code and the
- classpath (compiled bytecode of upstream dependencies). SemanticDB has been
- designed so that it's also possible to generate spec-compliant symbols from
- the classpath alone (no source code) and from the syntax tree of an individual
- source file (no classpath). This flexibility allows the
- [Metals](https://scalameta.org/metals/) language server to index codebases
- from a variety of different inputs, and will be helpful for lsif-java in the
- future to unblock cross-repository navigation.
-
-## Contributing
-
-The following sections provide tips on how to contribute to this codebase.
-
-### System dependencies
-
-- `java`: any version should work
-- `git`: any version should work
-- `lsif-semanticdb`:
- `go get github.com/sourcegraph/lsif-semanticdb/cmd/lsif-semanticdb`
-- `gradle`: `brew install gradle`, or see
- [general installation guide](https://gradle.org/install/).
-- `mvn`: `brew install maven`, or see
- [general installation guide](https://www.baeldung.com/install-maven-on-windows-linux-mac).
-
-### Project structure
-
-These are the main components of the project.
-
-- `semanticdb-javac/src/main/java`: the Java compiler plugin that creates
- SemanticDB files.
-- `tests/minimized`: minimized Java source files that reproduce interesting test
- cases.
-- `tests/unit`: fast running unit tests that are helpful for local edit-and-test
- workflows.
-- `tests/snapshots`: slow running
- ["snapshot tests"](https://jestjs.io/docs/en/snapshot-testing) that index a
- corpus of published Java libraries.
-- `build.sbt`: the sbt build definition.
-- `project/plugins.sbt`: plugins for the sbt build.
-
-### Helpful commands
-
-| Command | Where | Description |
-| ------------------------------------------------------------------- | -------- | ----------------------------------------------------------------------------------- |
-| `./sbt` | terminal | Start interactive sbt shell with Java 11. Takes a while to load on the first run. |
-| `unit/test` | sbt | Run fast unit tests. |
-| `~unit/test` | sbt | Start watch mode to run tests on file save, good for local edit-and-test workflows. |
-| `buildTools/test` | sbt | Run slow build tool tests (Gradle, Maven). |
-| `snapshots/testOnly tests.MinimizedSnapshotSuite` | sbt | Runs fast snapshot tests. Indexes a small set of files under `tests/minimized`. |
-| `snapshots/testOnly tests.MinimizedSnapshotSuite -- *InnerClasses*` | sbt | Runs only individual tests cases matching the name "InnerClasses". |
-| `snapshots/testOnly tests.LibrarySnapshotSuite` | sbt | Runs slow snapshot tests. Indexes a corpus of external Java libraries. |
-| `snapshots/test` | sbt | Runs all snapshot tests. |
-| `snapshots/run` | sbt | Update snapshot tests. Use this command after you have fixed a bug. |
-| `cli/run --cwd DIRECTORY` | sbt | Run `lsif-java` command-line tool against a given Gradle/Maven build. |
-| `fixAll` | sbt | Run Scalafmt, Scalafix and Javafmt on all sources. Run this before opening a PR. |
-
-### Import the project into IntelliJ
-
-It's recommended to use IntelliJ when editing code in this codebase.
-
-First, install the
-[IntelliJ Community Edition](https://www.jetbrains.com/idea/download/). The
-community edition is
-[open source](https://github.com/JetBrains/intellij-community) and free to use.
-
-Next, install the IntelliJ Scala plugin.
-
-Finally, run "File > Project From Existing Sources" to import the sbt build into
-IntelliJ. Select the "sbt" option if it asks you to choose between
-sbt/BSP/Bloop.
-
-It's best to run tests from the sbt shell, not from the IntelliJ UI.
-
-### Don't use VS Code/Vim/Sublime Text/Emacs
-
-If you want to use completions and precise code navigation, it's not recommended
-to use other editors than IntelliJ. IntelliJ is the only IDE that properly
-supports hybrid Java/Scala codebases at the moment, although that may change
-soon thanks to lsif-java :)
-
-### Tests are written in Scala
-
-This codebases uses the Scala library [MUnit](https://scalameta.org/munit/) to
-write tests because:
-
-- MUnit has built-in assertions that print readable multiline diffs in color.
-- MUnit makes it easy to implement
- [snapshot testing](https://jestjs.io/docs/en/snapshot-testing), which is a
- testing technique that's heavily used in this codebase.
-- Multiline literal strings in Scala make it easy to write unit tests for source
- code (which is always multiline). Modern versions of Java support multiline
- string literals, but they're not supported in Java 8, which is supported by
- lsif-java.
-
-## Benchmarks
-
-See [docs/benchmarks.md] for benchmark results.
+# Java indexer for the Language Server Index Format (LSIF) 
+
+| Documentation | Link |
+| -------------------- | ---------------------------------------------------------------------- |
+| Landing page | https://sourcegraph.github.io/lsif-java |
+| Getting started | https://sourcegraph.github.io/lsif-java/docs/getting-started.html |
+| Manual configuration | https://sourcegraph.github.io/lsif-java/docs/manual-configuration.html |
+| Contributing | https://sourcegraph.github.io/lsif-java/docs/contributing.html |
+| Design | https://sourcegraph.github.io/lsif-java/docs/design.html |
diff --git a/build.sbt b/build.sbt
index a1a8dc72..f65b4f36 100644
--- a/build.sbt
+++ b/build.sbt
@@ -1,3 +1,5 @@
+import scala.xml.{Node => XmlNode, NodeSeq => XmlNodeSeq, _}
+import scala.xml.transform.{RewriteRule, RuleTransformer}
import java.io.File
import java.util.Properties
import scala.collection.mutable.ListBuffer
@@ -59,7 +61,7 @@ commands +=
commands +=
Command.command("checkAll") { s =>
"scalafmtCheckAll" :: "scalafmtSbtCheck" :: "scalafixAll --check" ::
- "javafmtCheckAll" :: "publishLocal" :: s
+ "javafmtCheckAll" :: "publishLocal" :: "docs/docusaurusCreateSite" :: s
}
lazy val agent = project
@@ -97,6 +99,16 @@ lazy val plugin = project
old.withEnabled(false)
},
fatjarPackageSettings,
+ assemblyShadeRules.in(assembly) :=
+ Seq(
+ ShadeRule
+ .rename(
+ "com.google.**" -> "com.sourcegraph.shaded.com.google.@1",
+ "google.**" -> "com.sourcegraph.shaded.google.@1",
+ "org.relaxng.**" -> "com.sourcegraph.shaded.relaxng.@1"
+ )
+ .inAll
+ ),
crossPaths := false,
PB.targets.in(Compile) :=
Seq(PB.gens.java -> (Compile / sourceManaged).value)
@@ -280,7 +292,7 @@ lazy val fatjarPackageSettings = List[Def.Setting[_]](
case PathList("sun", _ @_*) =>
MergeStrategy.discard
case PathList("META-INF", "versions", "9", "module-info.class") =>
- MergeStrategy.first
+ MergeStrategy.discard
case x =>
val oldStrategy = (assemblyMergeStrategy in assembly).value
oldStrategy(x)
@@ -291,5 +303,48 @@ lazy val fatjarPackageSettings = List[Def.Setting[_]](
val _ = assembly.value
IO.copyFile(fatJar, slimJar, CopyOptions().withOverwrite(true))
slimJar
+ },
+ packagedArtifact.in(Compile).in(packageBin) := {
+ val (art, slimJar) = packagedArtifact.in(Compile).in(packageBin).value
+ val fatJar =
+ new File(crossTarget.value + "/" + assemblyJarName.in(assembly).value)
+ val _ = assembly.value
+ IO.copy(List(fatJar -> slimJar), CopyOptions().withOverwrite(true))
+ (art, slimJar)
+ },
+ pomPostProcess := { node =>
+ new RuleTransformer(
+ new RewriteRule {
+ private def isAbsorbedDependency(node: XmlNode): Boolean = {
+ node.label == "dependency" &&
+ node.child.exists(child => child.label == "artifactId")
+ }
+ override def transform(node: XmlNode): XmlNodeSeq =
+ node match {
+ case e: Elem if isAbsorbedDependency(node) =>
+ Comment(
+ "the dependency that was here has been absorbed via sbt-assembly"
+ )
+ case _ =>
+ node
+ }
+ }
+ ).transform(node).head
}
)
+
+lazy val docs = project
+ .in(file("lsif-java-docs"))
+ .settings(
+ mdocOut :=
+ baseDirectory.in(ThisBuild).value / "website" / "target" / "docs",
+ fork := false,
+ mdocVariables :=
+ Map[String, String](
+ "VERSION" -> version.value,
+ "SCALA_VERSION" -> scalaVersion.value,
+ "STABLE_VERSION" -> version.value.replaceFirst("\\-.*", "")
+ )
+ )
+ .dependsOn(unit)
+ .enablePlugins(DocusaurusPlugin)
diff --git a/cli/src/main/scala/com/sourcegraph/lsif_java/IndexCommand.scala b/cli/src/main/scala/com/sourcegraph/lsif_java/IndexCommand.scala
index cbc7d7ff..4e8e4cab 100644
--- a/cli/src/main/scala/com/sourcegraph/lsif_java/IndexCommand.scala
+++ b/cli/src/main/scala/com/sourcegraph/lsif_java/IndexCommand.scala
@@ -6,9 +6,11 @@ import java.nio.file.Paths
import com.sourcegraph.lsif_java.buildtools.BuildTool
import moped.annotations.Description
+import moped.annotations.ExampleUsage
import moped.annotations.ExampleValue
import moped.annotations.Inline
import moped.annotations.TrailingArguments
+import moped.annotations.Usage
import moped.cli.Application
import moped.cli.Command
import moped.cli.CommandParser
@@ -18,7 +20,12 @@ import os.Inherit
import os.Shellable
@Description(
- "Generates an LSIF index for the Java build of a provided workspace directory."
+ "Automatically generate an LSIF index in the current working directory."
+)
+@Usage("lsif-java index [OPTIONS ...] -- [TRAILING_ARGUMENTS ...]")
+@ExampleUsage(
+ """|# Running the `index` command with no flags should work most of the time.
+ |$ lsif-java index""".stripMargin
)
case class IndexCommand(
@Description("The path where to generate the LSIF index.") output: Path =
@@ -41,12 +48,12 @@ case class IndexCommand(
)
@ExampleValue("Gradle") buildTool: Option[String] = None,
@Description(
- "Whether to enable remove generated temporary files on exit."
+ "Whether to remove generated temporary files on exit."
) cleanup: Boolean = true,
@Description(
- "The build command to use to compile all sources. " +
+ "Optional. The build command to use to compile all sources. " +
"Defaults to a build-specific command. For example, the default command for Maven command is 'clean verify -DskipTests'." +
- "To override the default, pass in the build command after a double dash: 'lsif-java -- compile'"
+ "To override the default, pass in the build command after a double dash: 'lsif-java index -- compile test:compile'"
)
@TrailingArguments() buildCommand: List[String] = Nil,
@Inline
@@ -79,6 +86,7 @@ case class IndexCommand(
def workingDirectory: Path = AbsolutePath.of(app.env.workingDirectory)
def finalTargetroot(default: Path): Path =
AbsolutePath.of(targetroot.getOrElse(default), workingDirectory)
+ def finalOutput: Path = AbsolutePath.of(output, workingDirectory)
def finalBuildCommand(default: List[String]): List[String] =
if (buildCommand.isEmpty)
default
@@ -142,8 +150,14 @@ case class IndexCommand(
} else {
val generateLsifResult = process(
"lsif-semanticdb",
+ s"--out=${finalOutput}",
s"--semanticdbDir=${tool.targetroot}"
)
+ if (
+ generateLsifResult.exitCode == 0 && Files.isRegularFile(finalOutput)
+ ) {
+ app.info(finalOutput.toAbsolutePath().toString())
+ }
generateSemanticdbResult.exitCode + generateLsifResult.exitCode
}
case many =>
diff --git a/cli/src/main/scala/com/sourcegraph/lsif_java/IndexSemanticdbCommand.scala b/cli/src/main/scala/com/sourcegraph/lsif_java/IndexSemanticdbCommand.scala
new file mode 100644
index 00000000..55449b99
--- /dev/null
+++ b/cli/src/main/scala/com/sourcegraph/lsif_java/IndexSemanticdbCommand.scala
@@ -0,0 +1,55 @@
+package com.sourcegraph.lsif_java
+
+import java.nio.file.Path
+
+import scala.collection.mutable.ListBuffer
+
+import moped.annotations.CommandName
+import moped.annotations.Description
+import moped.annotations.ExampleUsage
+import moped.annotations.Inline
+import moped.annotations.PositionalArguments
+import moped.annotations.Usage
+import moped.cli.Application
+import moped.cli.Command
+import moped.cli.CommandParser
+import os.Inherit
+import os.Shellable
+
+@Description("Converts SemanticDB files into a single LSIF index file.")
+@Usage("lsif-java index-semanticdb [OPTIONS ...] [POSITIONAL ARGUMENTS ...]")
+@ExampleUsage(
+ "lsif-java index-semanticdb --out=myindex.lsif my/targetroot1 my/targetroot2"
+)
+@CommandName("index-semanticdb")
+final case class IndexSemanticdbCommand(
+ @Description(
+ "The name of the output file. Defaults to 'dump.lsif'"
+ ) out: Option[Path] = None,
+ @Description(
+ "SemanticDB file paths or directories that contain SemanticDB files."
+ )
+ @PositionalArguments() directories: List[Path] = Nil,
+ @Inline() app: Application = Application.default
+) extends Command {
+ def run(): Int = {
+ val arguments = ListBuffer.empty[String]
+ arguments += "lsif-semanticdb"
+ out.foreach { dir =>
+ arguments += s"--out=$dir"
+ }
+ directories.foreach { dir =>
+ arguments += s"--semanticdbDir=$dir"
+ }
+ app.info(arguments.mkString(" "))
+ app
+ .process(Shellable(arguments.toList))
+ .call(check = false, stderr = Inherit, stdout = Inherit)
+ .exitCode
+ }
+}
+
+object IndexSemanticdbCommand {
+ val default = IndexSemanticdbCommand()
+ implicit val parser = CommandParser.derive(default)
+}
diff --git a/cli/src/main/scala/com/sourcegraph/lsif_java/LsifJava.scala b/cli/src/main/scala/com/sourcegraph/lsif_java/LsifJava.scala
index c9d6e9cc..d294755b 100644
--- a/cli/src/main/scala/com/sourcegraph/lsif_java/LsifJava.scala
+++ b/cli/src/main/scala/com/sourcegraph/lsif_java/LsifJava.scala
@@ -1,23 +1,35 @@
package com.sourcegraph.lsif_java
+import java.io.PrintStream
+
import moped.cli.Application
import moped.cli.CommandParser
import moped.commands.HelpCommand
import moped.commands.VersionCommand
+import moped.reporters.Tput
object LsifJava {
- val app: Application = Application
- .fromName(
- binaryName = "lsif-java",
- BuildInfo.version,
- List(
- CommandParser[HelpCommand],
- CommandParser[VersionCommand],
- CommandParser[IndexCommand]
- )
+ val app: Application = Application.fromName(
+ binaryName = "lsif-java",
+ BuildInfo.version,
+ List(
+ CommandParser[HelpCommand],
+ CommandParser[VersionCommand],
+ CommandParser[IndexCommand],
+ CommandParser[IndexSemanticdbCommand]
)
- .withIsSingleCommand(true)
+ )
def main(args: Array[String]): Unit = {
app.runAndExitIfNonZero(args.toList)
}
+
+ def printHelp(out: PrintStream): Unit = {
+ out.println("```text")
+ out.println("$ lsif-java index --help")
+ val newApp = app
+ .withTput(Tput.constant(100))
+ .withEnv(app.env.withStandardOutput(out))
+ newApp.run(List("index", "--help"))
+ out.println("```")
+ }
}
diff --git a/docs/img/semanticdb-javac-pipeline.svg b/docs/assets/semanticdb-javac-pipeline.svg
similarity index 100%
rename from docs/img/semanticdb-javac-pipeline.svg
rename to docs/assets/semanticdb-javac-pipeline.svg
diff --git a/docs/benchmarks.md b/docs/benchmarks.md
index 87640660..6911614d 100644
--- a/docs/benchmarks.md
+++ b/docs/benchmarks.md
@@ -1,7 +1,15 @@
-# Benchmarks results
+---
+id: benchmarks
+title: Benchmarks
+---
+
+The repository contains benchmarks to measure the overhead of the SemanticDB
+compiler plugin.
```
-sbt:root> bench/jmh:run -i 3 -wi 3 -f1 -t1
+$ sbt
+...
+sbt:root> bench/jmh:run -i 10 -wi 10 -f1 -t1
...
[info] Benchmark (lib) Mode Cnt Score Error Units
[info] CompileBench.compile guava ss 10 2291.036 ± 243.428 ms/op 1x
diff --git a/docs/contributing.md b/docs/contributing.md
new file mode 100644
index 00000000..e7789c0a
--- /dev/null
+++ b/docs/contributing.md
@@ -0,0 +1,93 @@
+---
+id: contributing
+sidebar_label: Guide
+title: Contributing guide
+---
+
+This page documents tips and tricks for contributing to the
+[sourcegraph/lsif-java](https://github.com/sourcegraph/lsif-java) codebase.
+
+## System dependencies
+
+- `java`: any version should work
+- `git`: any version should work
+- `lsif-semanticdb`:
+ `go get github.com/sourcegraph/lsif-semanticdb/cmd/lsif-semanticdb`
+- `gradle`: `brew install gradle`, or see
+ [general installation guide](https://gradle.org/install/).
+- `mvn`: `brew install maven`, or see
+ [general installation guide](https://www.baeldung.com/install-maven-on-windows-linux-mac).
+
+## Project structure
+
+These are the main components of the project.
+
+- `semanticdb-javac/src/main/java`: the Java compiler plugin that creates
+ SemanticDB files.
+- `tests/minimized`: minimized Java source files that reproduce interesting test
+ cases.
+- `tests/unit`: fast running unit tests that are helpful for local edit-and-test
+ workflows.
+- `tests/snapshots`: slow running
+ ["snapshot tests"](https://jestjs.io/docs/en/snapshot-testing) that index a
+ corpus of published Java libraries.
+- `cli/src/main/scala`: implementation of the `lsif-java` command-line
+ interface.
+- `build.sbt`: the sbt build definition.
+- `project/plugins.sbt`: plugins for the sbt build.
+
+## Helpful commands
+
+| Command | Where | Description |
+| ------------------------------------------------------------------- | -------- | ----------------------------------------------------------------------------------- |
+| `./sbt` | terminal | Start interactive sbt shell with Java 11. Takes a while to load on the first run. |
+| `unit/test` | sbt | Run fast unit tests. |
+| `~unit/test` | sbt | Start watch mode to run tests on file save, good for local edit-and-test workflows. |
+| `buildTools/test` | sbt | Run slow build tool tests (Gradle, Maven). |
+| `snapshots/testOnly tests.MinimizedSnapshotSuite` | sbt | Runs fast snapshot tests. Indexes a small set of files under `tests/minimized`. |
+| `snapshots/testOnly tests.MinimizedSnapshotSuite -- *InnerClasses*` | sbt | Runs only individual tests cases matching the name "InnerClasses". |
+| `snapshots/testOnly tests.LibrarySnapshotSuite` | sbt | Runs slow snapshot tests. Indexes a corpus of external Java libraries. |
+| `snapshots/test` | sbt | Runs all snapshot tests. |
+| `snapshots/run` | sbt | Update snapshot tests. Use this command after you have fixed a bug. |
+| `cli/run --cwd DIRECTORY` | sbt | Run `lsif-java` command-line tool against a given Gradle/Maven build. |
+| `cd website && yarn install && yarn start` | terminal | Start live-reload preview of the website at http://localhost:3000/lsif-java. |
+| `docs/mdoc --watch` | sbt | Re-generate markdown files in the `docs/` directory. |
+| `fixAll` | sbt | Run Scalafmt, Scalafix and Javafmt on all sources. Run this before opening a PR. |
+
+## Import the project into IntelliJ
+
+It's recommended to use IntelliJ when editing code in this codebase.
+
+First, install the
+[IntelliJ Community Edition](https://www.jetbrains.com/idea/download/). The
+community edition is
+[open source](https://github.com/JetBrains/intellij-community) and free to use.
+
+Next, install the IntelliJ Scala plugin.
+
+Finally, run "File > Project From Existing Sources" to import the sbt build into
+IntelliJ. Select the "sbt" option if it asks you to choose between
+sbt/BSP/Bloop.
+
+It's best to run tests from the sbt shell, not from the IntelliJ UI.
+
+## Don't use VS Code/Vim/Sublime Text/Emacs
+
+If you want to use completions and precise code navigation, it's not recommended
+to use other editors than IntelliJ. IntelliJ is the only IDE that properly
+supports hybrid Java/Scala codebases at the moment, although that may change
+soon thanks to lsif-java :)
+
+## Tests are written in Scala
+
+This codebases uses the Scala library [MUnit](https://scalameta.org/munit/) to
+write tests because:
+
+- MUnit has built-in assertions that print readable multiline diffs in color.
+- MUnit makes it easy to implement
+ [snapshot testing](https://jestjs.io/docs/en/snapshot-testing), which is a
+ testing technique that's heavily used in this codebase.
+- Multiline literal strings in Scala make it easy to write unit tests for source
+ code (which is always multiline). Modern versions of Java support multiline
+ string literals, but they're not supported in Java 8, which is supported by
+ lsif-java.
diff --git a/docs/design.md b/docs/design.md
new file mode 100644
index 00000000..d908e78d
--- /dev/null
+++ b/docs/design.md
@@ -0,0 +1,54 @@
+---
+id: design
+title: Design
+---
+
+This project is implemented as a
+[Java compiler plugin](https://docs.oracle.com/en/java/javase/11/docs/api/jdk.compiler/com/sun/source/util/Plugin.html)
+that generates one
+[SemanticDB](https://scalameta.org/docs/semanticdb/specification.html) file for
+every `*.java` source file. After compilation completes, the SemanticDB files
+are processed to produce LSIF.
+
+
+
+### Why Java compiler plugin?
+
+There are several benefits to implementing lsif-java as a compiler plugin:
+
+- **Simple installation**: compiler plugins are enabled with the `-Xplugin`
+ compiler option. All Java build tools support a way to customize compiler
+ options, simplifying installation.
+- **Language fidelity**: by using the Java compiler to produce semantic
+ information, we ensure that the produced LSIF data is accurate even as new
+ Java language versions with new language features are released.
+- **Environment fidelity**: by hooking into the compilation process of the build
+ tool, we minimize the risk of diverging from the CI build environment such as
+ installed system dependencies, custom compiler options and custom annotation
+ processors.
+
+### Why SemanticDB?
+
+SemanticDB is Protobuf schema for information about symbols and types in Java
+programs, Scala programs and other languages. There are several benefits to
+using SemanticDB as an intermediary representation for LSIF:
+
+- **Simplicity**: It's easy to translate a single Java source file into a single
+ SemanticDB file inside a compiler plugin. It's more complicated to produce
+ LSIF because compiler plugins does not have access to a project-wide context,
+ which is necessary to produce accurate definitions and hovers in multi-module
+ projects with external library dependencies.
+- **Performance**: SemanticDB is fast to write and read. Each compilation unit
+ can be processed independently to keep memory usage low. The final conversion
+ from SemanticDB to LSIF can be safely parallelized.
+- **Cross-language**: SemanticDB has a
+ [spec](https://scalameta.org/docs/semanticdb/specification.html) for Java and
+ Scala enabling cross-language navigation in hybrid Java/Scala codebases.
+- **Cross-repository**: Compiler plugins have access to both source code and the
+ classpath (compiled bytecode of upstream dependencies). SemanticDB has been
+ designed so that it's also possible to generate spec-compliant symbols from
+ the classpath alone (no source code) and from the syntax tree of an individual
+ source file (no classpath). This flexibility allows the
+ [Metals](https://scalameta.org/metals/) language server to index codebases
+ from a variety of different inputs, and will be helpful for lsif-java in the
+ future to unblock cross-repository navigation.
diff --git a/docs/getting-started.md b/docs/getting-started.md
new file mode 100644
index 00000000..852e8664
--- /dev/null
+++ b/docs/getting-started.md
@@ -0,0 +1,165 @@
+---
+id: getting-started
+title: Getting started
+---
+
+By following the instructions on this page, you should be able to generate an
+[LSIF](https://microsoft.github.io/language-server-protocol/specifications/lsif/0.5.0/specification/)
+index of your Java codebase using Gradle or Maven. See
+[Supported build tools](#supported-build-tools) for an overview of other build
+tools that we're planning to support in the future.
+
+## Install `lsif-java`
+
+Most users only install `lsif-java` on a CI machine to upload LSIF indexes to a
+remote service like [Sourcegraph](https://sourcegraph.com/). The easiest way to
+install `lsif-java` is to download the native binary. However, you can also
+install `lsif-java` as a Java binary if that's easier to integrate with your
+setup.
+
+### Native binary
+
+The native binary is only available for Linux and macOS. The native binary
+includes all dependencies and does not need further access to the internet after
+it's been downloaded.
+
+```sh
+# macOS
+curl -Lo lsif-java https://github.com/sourcegraph/lsif-java/releases/download/@STABLE_VERSION@/lsif-java-x86_64-apple-darwin
+chmod +x lsif-java
+./lsif-java --help
+
+# Linux
+curl -Lo lsif-java https://github.com/sourcegraph/lsif-java/releases/download/@STABLE_VERSION@/lsif-java-x86_64-pc-linux
+chmod +x lsif-java
+./lsif-java --help
+```
+
+### Java launcher
+
+Use [Coursier](https://get-coursier.io/docs/cli-installation.html) to launch the
+Java binary. The jar files of `lsif-java` are downloaded the first time you run
+the `launch` command, and they're cached for subsequent runs.
+
+```sh
+# Homebrew
+brew install coursier/formulas/coursier
+coursier launch com.sourcegraph:lsif-java_2.13:@STABLE_VERSION@ -- --help
+
+# macOS/Linux
+curl -fLo coursier https://git.io/coursier-cli
+chmod +x coursier
+./coursier launch com.sourcegraph:lsif-java_2.13:@STABLE_VERSION@ -- --help
+
+# Windows
+bitsadmin /transfer downloadCoursierCli https://git.io/coursier-cli "%cd%\coursier"
+bitsadmin /transfer downloadCoursierBat https://git.io/coursier-bat "%cd%\coursier.bat"
+./coursier launch com.sourcegraph:lsif-java_2.13:@STABLE_VERSION@ -- --help
+```
+
+### Java fat jar
+
+Use the Coursier `bootstrap` command to generate an executable Java binary,
+which includes all dependencies and does not require further access to the
+internet after installation.
+
+```sh
+# macOS/Linux/Windows
+cs bootstrap --standalone -o lsif-java com.sourcegraph:lsif-java_2.13:@STABLE_VERSION@
+./lsif-java --help
+```
+
+### Java library
+
+The `lsif-java` command-line interface is published to Maven Central. You can
+run the command-line interface as a library by directly invoking the `main()`
+method on the `com.sourcegraph.lsif_java.LsifJava` class.
+
+[](https://repo1.maven.org/maven2/com/sourcegraph/lsif-java_2.13/)
+
+If you're using Gradle.
+
+```groovy
+implementation group: 'com.sourcegraph', name: 'lsif-java_2.13', version: '@STABLE_VERSION@'
+```
+
+If you're using Maven.
+
+```xml
+