Enso language support with parser in VSCode, IGV, etc. (#7054)

Outline view and completions for Enso code in VSCode.

# Important Notes
This PR provides the necessary infrastructure for building VSCode extension that includes `enso_parser` library compiled for all supported platforms.

VSCode extension can now use libraries from `sbt` that are `publishM2`-ready. To make that possible a documentation must have been provided and fixed for those modules - hence so many changes in `.scala` classes.

<img width="862" alt="image" src="https://github.com/enso-org/enso/assets/26887752/7374bf41-bdc6-4322-b562-85a2e761de2a">

Last, but not least. The outline view and completions display something.
This commit is contained in:
Jaroslav Tulach 2024-06-14 16:01:37 +02:00 committed by GitHub
parent dc6e3a7031
commit dee9e079d4
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
43 changed files with 459 additions and 147 deletions

View File

@ -8,29 +8,127 @@ on:
paths:
- ".github/workflows/enso4igv.yml"
- "tools/enso4igv/**/*"
- "engine/**/*"
- "lib/java/**/*"
- "lib/scala/**/*"
- "build.sbt"
jobs:
build:
build_linux_parser:
runs-on: ubuntu-20.04
strategy:
matrix:
java: ["11"]
steps:
- uses: actions/checkout@v2
- name: Set up Java
uses: actions/setup-java@v2
- uses: actions/checkout@v4
- name: Install rustup
run: |
rustup target add x86_64-unknown-linux-musl
- name: Build Enso Parser
working-directory: .
env:
RUSTFLAGS: "-C target-feature=-crt-static"
run: |
cargo build -p enso-parser-jni -Z unstable-options --target x86_64-unknown-linux-musl --out-dir target/lib/
- name: Upload Artifacts
uses: actions/upload-artifact@v4
with:
distribution: "zulu"
java-version: ${{ matrix.java }}
cache: maven
name: parser_linux
path: |
target/lib/**
build_mac_intel_parser:
runs-on: macos-12
steps:
- uses: actions/checkout@v4
- name: Build Enso Parser
working-directory: .
env:
RUSTFLAGS: "-C target-feature=-crt-static"
run: |
cargo build -p enso-parser-jni -Z unstable-options --out-dir target/lib/x86_64
- name: Upload Artifacts
uses: actions/upload-artifact@v4
with:
name: parser_mac_intel
path: |
target/lib/**
build_mac_arm_parser:
runs-on: macos-14
steps:
- uses: actions/checkout@v4
- name: Build Enso Parser
working-directory: .
env:
RUSTFLAGS: "-C target-feature=-crt-static"
run: |
cargo build -p enso-parser-jni -Z unstable-options --out-dir target/lib/aarch64/
- name: Upload Artifacts
uses: actions/upload-artifact@v4
with:
name: parser_mac_arm
path: |
target/lib/**
build_windows_parser:
runs-on: windows-2019
steps:
- uses: actions/checkout@v4
- name: Build Enso Parser
working-directory: .
env:
RUSTFLAGS: "-C target-feature=-crt-static"
run: |
cargo build -p enso-parser-jni -Z unstable-options --out-dir target/lib/
- name: Upload Artifacts
uses: actions/upload-artifact@v4
with:
name: parser_windows
path: |
target/lib/**
build_java:
needs:
[
build_linux_parser,
build_mac_intel_parser,
build_mac_arm_parser,
build_windows_parser,
]
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v4
- name: Download Libraries
uses: actions/download-artifact@v4
with:
path: enso_parser
merge-multiple: true
- name: List Binaries
run: |
find . | grep -i enso.parser
- name: Set up Rustup
run: rustup show
- uses: graalvm/setup-graalvm@v1
with:
java-version: "21"
distribution: "graalvm-community"
- name: Publish to Maven Repository
- name: Publish Enso Libraries to Local Maven Repository
run: sbt publishM2
- name: Find out pom & micro versions
@ -48,9 +146,10 @@ jobs:
mvn versions:set -DnewVersion="$POM_VERSION.$MICRO_VERSION"
- name: Build with Maven
run: mvn -B -Pvsix package --file tools/enso4igv/pom.xml
run: mvn -B -Pvsix package --file tools/enso4igv/pom.xml -Denso.parser.lib=`pwd`/enso_parser/
- name: Archive NBM file
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
with:
name: Enso IGV Plugin
path: tools/enso4igv/target/*.nbm
@ -62,10 +161,10 @@ jobs:
run: mvn -B -Pvsix npm:exec@version --file tools/enso4igv/pom.xml
- name: Build VSCode Extension
run: mvn -B -Pvsix npm:run@vsix --file tools/enso4igv/pom.xml
run: mvn -B -Pvsix npm:run@vsix --file tools/enso4igv/pom.xml -Denso.parser.lib=`pwd`/enso_parser/
- name: Archive VSCode extension
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
with:
name: VSCode Extension
path: tools/enso4igv/*.vsix

View File

@ -47,7 +47,7 @@ val currentEdition = sys.env.getOrElse(
// Note [Stdlib Version]
val stdLibVersion = defaultDevEnsoVersion
val targetStdlibVersion = ensoVersion
val persistanceVersion = "0.2-SNAPSHOT"
val mavenUploadVersion = "0.2-SNAPSHOT"
// Inspired by https://www.scala-sbt.org/1.x/docs/Howto-Startup.html#How+to+take+an+action+on+startup
lazy val startupStateTransition: State => State = { s: State =>
@ -731,11 +731,17 @@ lazy val `syntax-rust-definition` = project
.enablePlugins(JPMSPlugin)
.configs(Test)
.settings(
version := mavenUploadVersion,
Compile / exportJars := true,
javadocSettings,
publish / skip := false,
autoScalaLibrary := false,
crossPaths := false,
javaModuleName := "org.enso.syntax",
Compile / sourceGenerators += generateParserJavaSources,
Compile / resourceGenerators += generateRustParserLib,
Compile / javaSource := baseDirectory.value / "generate-java" / "java"
Compile / javaSource := baseDirectory.value / "generate-java" / "java",
Compile / compile / javacOptions ++= Seq("-source", "11", "-target", "11")
)
lazy val yaml = (project in file("lib/java/yaml"))
@ -1306,7 +1312,7 @@ lazy val `ydoc-server` = project
lazy val `persistance` = (project in file("lib/java/persistance"))
.settings(
version := persistanceVersion,
version := mavenUploadVersion,
Test / fork := true,
commands += WithDebugCommand.withDebug,
frgaalJavaCompilerSetting,
@ -1328,7 +1334,7 @@ lazy val `persistance` = (project in file("lib/java/persistance"))
lazy val `persistance-dsl` = (project in file("lib/java/persistance-dsl"))
.settings(
version := persistanceVersion,
version := mavenUploadVersion,
frgaalJavaCompilerSetting,
publish / skip := false,
autoScalaLibrary := false,
@ -2178,6 +2184,10 @@ lazy val `runtime-benchmarks` =
lazy val `runtime-parser` =
(project in file("engine/runtime-parser"))
.settings(
version := mavenUploadVersion,
javadocSettings,
publish / skip := false,
crossPaths := false,
frgaalJavaCompilerSetting,
annotationProcSetting,
commands += WithDebugCommand.withDebug,

View File

@ -42,7 +42,7 @@ public final class MetadataStorage {
/**
* Adds a metadata pair to the node metadata.
*
* <p>This will overwrite any entry whose key matches [[MetadataPair#pass]].
* <p>This will overwrite any entry whose key matches {@code MetadataPair.pass}.
*
* @param <K> the concrete type of the pass
* @param metadataPair the pair to add to the storage

View File

@ -30,7 +30,7 @@ object Implicits {
/** Converts a multiline string to a single line
*
* @return [[string]], converted to a single line
* @return String, converted to a single line
*/
def toSingleLine: String = {
val lines = string.stripMargin.split("\n").toList.filterNot(_ == "")
@ -69,7 +69,7 @@ object Implicits {
/** Adds a metadata pair to the node metadata.
*
* This will overwrite any entry whose key matches [[MetadataPair#pass]].
* This will overwrite any entry whose key matches MetadataPair#pass.
*
* @param metadataPair the pair to add to the storage
* @tparam K the concrete type of the pass
@ -118,7 +118,7 @@ object Implicits {
*/
implicit class ListAsIr[T <: IR](list: List[T]) {
/** Calls [[IR#duplicate]] on the elements in [[list]].
/** Calls [[IR#duplicate]] on the elements in list.
*
* @param keepLocations whether or not locations should be kept in the
* duplicated IR
@ -128,7 +128,7 @@ object Implicits {
* the duplicated IR
* @param keepIdentifiers whether or not the identifiers should be
* regenerated in the duplicated IR
* @return a duplicate of [[list]]
* @return a duplicate of list
*/
def duplicate(
keepLocations: Boolean = true,

View File

@ -124,7 +124,7 @@ object CallArgument {
copy(name = name.map(n => n.mapExpressions(fn)), value = fn(value))
}
/** @inheritdoc */
/** String representation. */
override def toString: String =
s"""
|CallArgument.Specified(

View File

@ -158,7 +158,7 @@ object DefinitionArgument {
)
}
/** @inheritdoc */
/** String representation. */
override def toString: String =
s"""
|DefinitionArgument.Specified(

View File

@ -64,7 +64,7 @@ sealed case class Empty(
fn: java.util.function.Function[Expression, Expression]
): Empty = this
/** @inheritdoc */
/** String representation. */
override def toString: String =
s"""
|Empty(

View File

@ -142,7 +142,7 @@ object Expression {
)
}
/** @inheritdoc */
/** String representation. */
override def toString: String =
s"""
|Expression.Block(
@ -254,7 +254,7 @@ object Expression {
copy(name = name.mapExpressions(fn), expression = fn(expression))
}
/** @inheritdoc */
/** String representation. */
override def toString: String =
s"""
|Expression.Binding(

View File

@ -154,7 +154,7 @@ object Function {
copy(arguments = arguments.map(_.mapExpressions(fn)), body = fn(body))
}
/** @inheritdoc */
/** String representation. */
override def toString: String =
s"""
|Function.Lambda(
@ -320,7 +320,7 @@ object Function {
body = fn(body)
)
/** @inheritdoc */
/** String representation. */
override def toString: String =
s"""
|Function.Binding(

View File

@ -92,7 +92,7 @@ object Literal {
fn: java.util.function.Function[Expression, Expression]
): Number = this
/** @inheritdoc */
/** String representation. */
override def toString: String =
s"""Literal.Number(
|base = $base,
@ -217,7 +217,7 @@ object Literal {
fn: java.util.function.Function[Expression, Expression]
): Text = this
/** @inheritdoc */
/** String representation. */
override def toString: String =
s"""
|Literal.Text(

View File

@ -115,7 +115,7 @@ final case class Module(
/** @inheritdoc */
override def children: List[IR] = imports ++ exports ++ bindings
/** @inheritdoc */
/** String representation. */
override def toString: String =
s"""
|Module(

View File

@ -131,7 +131,7 @@ object Name {
copy(location = location)
}
/** @inheritdoc */
/** String representation. */
override def toString: String =
s"""
|Name.MethodReference(
@ -341,7 +341,7 @@ object Name {
override def setLocation(location: Option[IdentifiedLocation]): Blank =
copy(location = location)
/** @inheritdoc */
/** String representation. */
override def toString: String =
s"""
|Name.Blank(
@ -512,7 +512,7 @@ object Name {
fn: java.util.function.Function[Expression, Expression]
): Literal = this
/** @inheritdoc */
/** String representation. */
override def toString: String =
s"""
|Name.Literal(
@ -617,7 +617,7 @@ object Name {
): BuiltinAnnotation =
this
/** @inheritdoc */
/** String representation. */
override def toString: String =
s"""
|Name.BuiltinAnnotation(
@ -705,7 +705,7 @@ object Name {
): GenericAnnotation =
copy(expression = fn(expression))
/** @inheritdoc */
/** String representation. */
override def toString: String =
s"""
|Name.GenericAnnotation(
@ -786,7 +786,7 @@ object Name {
fn: java.util.function.Function[Expression, Expression]
): Self = this
/** @inheritdoc */
/** String representation. */
override def toString: String =
s"""
|Name.Self(
@ -863,7 +863,7 @@ object Name {
fn: java.util.function.Function[Expression, Expression]
): SelfType = this
/** @inheritdoc */
/** String representation. */
override def toString: String =
s"""
|Name.SelfType(

View File

@ -98,7 +98,7 @@ object Pattern {
copy(name = name.mapExpressions(fn))
}
/** @inheritdoc */
/** String representation. */
override def toString: String =
s"""
|Case.Pattern.Name(
@ -245,7 +245,7 @@ object Pattern {
fields = fields.map(_.mapExpressions(fn))
)
/** @inheritdoc */
/** String representation. */
override def toString: String =
s"""
|Case.Pattern.Constructor(
@ -342,7 +342,7 @@ object Pattern {
copy(literal = literal.mapExpressions(fn))
}
/** @inheritdoc */
/** String representation. */
override def toString: String =
s"""
|Case.Pattern.Literal(
@ -445,7 +445,7 @@ object Pattern {
copy(name = name.mapExpressions(fn), tpe = tpe.mapExpressions(fn))
}
/** @inheritdoc */
/** String representation. */
override def toString: String =
s"""
|Case.Pattern.Type(
@ -543,7 +543,7 @@ object Pattern {
/** @inheritdoc */
override def children: List[IR] = Nil
/** @inheritdoc */
/** String representation. */
override def toString: String =
s"""
|Case.Pattern.Documentation(

View File

@ -41,7 +41,7 @@ object ProcessingPass {
* there is no default definition for this method.
*
* @param compiler the Enso compiler
* @return `this`, but restored from serialization, or [[None]] if
* @return `this`, but restored from serialization, or None if
* restoration could not be performed
*/
def restoreFromSerialization(compiler: Compiler): Option[Metadata]

View File

@ -97,7 +97,7 @@ object Type {
copy(args = args.map(fn.asScala), result = fn(result))
}
/** @inheritdoc */
/** String representation. */
override def toString: String =
s"""Type.Function(
|args = $args,
@ -204,7 +204,7 @@ object Type {
copy(typed = fn(typed), signature = fn(signature))
}
/** @inheritdoc */
/** String representation. */
override def toString: String =
s"""Type.Ascription(
|typed = $typed,
@ -310,7 +310,7 @@ object Type {
copy(typed = fn(typed), context = fn(context))
}
/** @inheritdoc */
/** String representation. */
override def toString: String =
s"""Type.Context(
|typed = $typed,
@ -413,7 +413,7 @@ object Type {
): Error =
copy(typed = fn(typed), error = fn(error))
/** @inheritdoc */
/** String representation. */
override def toString: String =
s"""Type.Error(
|typed = $typed,

View File

@ -108,7 +108,7 @@ object Application {
copy(function = fn(function), arguments.map(_.mapExpressions(fn)))
}
/** @inheritdoc */
/** String representation. */
override def toString: String =
s"""
|Application.Prefix(
@ -203,7 +203,7 @@ object Application {
copy(target = fn(target))
}
/** @inheritdoc */
/** String representation. */
override def toString: String =
s"""
|Application.Force(
@ -316,7 +316,7 @@ object Application {
location: Option[IdentifiedLocation]
): Typeset = copy(location = location)
/** @inheritdoc */
/** String representation. */
override def toString: String =
s"""Application.Typeset(
|expression = $expression,
@ -412,7 +412,7 @@ object Application {
location: Option[IdentifiedLocation]
): Sequence = copy(location = location)
/** @inheritdoc */
/** String representation. */
override def toString: String =
s"""
|Application.Vector(

View File

@ -130,7 +130,7 @@ object Case {
)
}
/** @inheritdoc */
/** String representation. */
override def toString: String =
s"""
|Case.Expr(
@ -283,7 +283,7 @@ object Case {
copy(pattern = pattern.mapExpressions(fn), expression = fn(expression))
}
/** @inheritdoc */
/** String representation. */
override def toString: String =
s"""
|Case.Branch(

View File

@ -91,7 +91,7 @@ object Comment {
fn: java.util.function.Function[Expression, Expression]
): Documentation = this
/** @inheritdoc */
/** String representation. */
override def toString: String =
s"""
|Comment.Documentation(

View File

@ -98,7 +98,7 @@ object Error {
): InvalidIR =
this
/** @inheritdoc */
/** String representation. */
override def toString: String =
s"""
|Error.InvalidIR(

View File

@ -99,7 +99,7 @@ object Foreign {
): Definition =
this
/** @inheritdoc */
/** String representation. */
override def toString: String =
s"""
|Foreign.Definition(

View File

@ -119,7 +119,7 @@ object Operator {
copy(left = left.mapExpressions(fn), right = right.mapExpressions(fn))
}
/** @inheritdoc */
/** String representation. */
override def toString: String =
s"""
|Operator.Binary(

View File

@ -111,7 +111,7 @@ object Section {
operator = operator.mapExpressions(fn)
)
/** @inheritdoc */
/** String representation. */
override def toString: String =
s"""
|Section.Left(
@ -203,7 +203,7 @@ object Section {
): Section =
copy(operator = operator.mapExpressions(fn))
/** @inheritdoc */
/** String representation. */
override def toString: String =
s"""
|Section.Sides(
@ -308,7 +308,7 @@ object Section {
)
}
/** @inheritdoc */
/** String representation. */
override def toString: String =
s"""
|Section.Right(

View File

@ -78,7 +78,7 @@ sealed case class ImportExport(
): ImportExport =
this
/** @inheritdoc */
/** String representation. */
override def toString: String =
s"""
|Error.ImportExport(

View File

@ -209,7 +209,7 @@ object Redefined {
): Conversion =
this
/** @inheritdoc */
/** String representation. */
override def toString: String =
s"""
|Error.Redefined.Method(
@ -332,7 +332,7 @@ object Redefined {
fn: java.util.function.Function[Expression, Expression]
): Method = this
/** @inheritdoc */
/** String representation. */
override def toString: String =
s"""
|Error.Redefined.Method(
@ -458,7 +458,7 @@ object Redefined {
): MethodClashWithAtom =
this
/** @inheritdoc */
/** String representation. */
override def toString: String =
s"""
|Error.Redefined.MethodClashWithAtom(
@ -560,7 +560,7 @@ object Redefined {
fn: java.util.function.Function[Expression, Expression]
): Type = this
/** @inheritdoc */
/** String representation. */
override def toString: String =
s"""
|Error.Redefined.Atom(
@ -661,7 +661,7 @@ object Redefined {
fn: java.util.function.Function[Expression, Expression]
): Arg = this
/** @inheritdoc */
/** String representation. */
override def toString: String =
s"""
|Error.Redefined.Arg(
@ -755,7 +755,7 @@ object Redefined {
): Binding =
this
/** @inheritdoc */
/** String representation. */
override def toString: String =
s"""
|Error.Redefined.Binding(

View File

@ -76,7 +76,7 @@ sealed case class Syntax(
fn: java.util.function.Function[Expression, Expression]
): Syntax = this
/** @inheritdoc */
/** String representation. */
override def toString: String =
s"""
|Error.Syntax(

View File

@ -124,7 +124,7 @@ object Definition {
members = members.map(_.mapExpressions(fn))
)
/** @inheritdoc */
/** String representation. */
override def toString: String =
s"""
|Module.Scope.Definition.Type(
@ -249,7 +249,7 @@ object Definition {
)
}
/** @inheritdoc */
/** String representation. */
override def toString: String =
s"""
|Module.Scope.Definition.Data(
@ -376,7 +376,7 @@ object Definition {
location: Option[IdentifiedLocation]
): SugaredType = copy(location = location)
/** @inheritdoc */
/** String representation. */
override def toString: String =
s"""
|Module.Scope.Definition.SugaredType(

View File

@ -132,7 +132,7 @@ object Export {
fn: java.util.function.Function[Expression, Expression]
): Module = this
/** @inheritdoc */
/** String representation. */
override def toString: String =
s"""
|Module.Scope.Export.Module(

View File

@ -147,7 +147,7 @@ object Import {
fn: java.util.function.Function[Expression, Expression]
): Module = this
/** @inheritdoc */
/** String representation. */
override def toString: String =
s"""
|Module.Scope.Import.Module(

View File

@ -163,7 +163,7 @@ object Method {
)
}
/** @inheritdoc */
/** String representation. */
override def toString: String =
s"""
|Module.Scope.Definition.Method.Explicit(
@ -342,7 +342,7 @@ object Method {
)
}
/** @inheritdoc */
/** String representation. */
override def toString: String =
s"""
|Module.Scope.Definition.Method.Binding(
@ -485,7 +485,7 @@ object Method {
)
}
/** @inheritdoc */
/** String representation. */
override def toString: String =
s"""
|Module.Scope.Definition.Method.Conversion(

View File

@ -91,7 +91,7 @@ sealed case class Polyglot(
*/
def getVisibleName: String = rename.getOrElse(entity.getVisibleName)
/** @inheritdoc */
/** String representation. */
override def toString: String =
s"""
|Module.Scope.Import.Polyglot(

View File

@ -126,7 +126,7 @@ object Set {
)
}
/** @inheritdoc */
/** String representation. */
override def toString: String =
s"""
|`type`.Set.Member(
@ -236,7 +236,7 @@ object Set {
copy(left = fn(left), right = fn(right))
}
/** @inheritdoc */
/** String representation. */
override def toString: String =
s"""
|`type`.Set.Subsumption(
@ -341,7 +341,7 @@ object Set {
copy(left = fn(left), right = fn(right))
}
/** @inheritdoc */
/** String representation. */
override def toString: String =
s"""
|`type`.Set.Equality(
@ -445,7 +445,7 @@ object Set {
copy(left = fn(left), right = fn(right))
}
/** @inheritdoc */
/** String representation. */
override def toString: String =
s"""
|`type`.Set.Concat(
@ -542,7 +542,7 @@ object Set {
copy(operands = operands.map(fn.asScala))
}
/** @inheritdoc */
/** String representation. */
override def toString: String =
s"""
|`type`.Set.Union(
@ -646,7 +646,7 @@ object Set {
copy(left = fn(left), right = fn(right))
}
/** @inheritdoc */
/** String representation. */
override def toString: String =
s"""
|`type`.Set.Intersection(

View File

@ -5,6 +5,7 @@ import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.Processor;
import javax.annotation.processing.RoundEnvironment;
@ -69,7 +70,7 @@ public class PersistableProcessor extends AbstractProcessor {
private static String findNameInPackage(Element e) {
var sb = new StringBuilder();
while (e != null && !(e instanceof PackageElement)) {
if (!sb.isEmpty()) {
if (sb.length() > 0) {
sb.insert(0, ".");
}
sb.insert(0, e.getSimpleName());
@ -112,7 +113,7 @@ public class PersistableProcessor extends AbstractProcessor {
e.getModifiers().contains(Modifier.PUBLIC)
&& e.getKind() == ElementKind.CONSTRUCTOR)
.sorted(richerConstructor)
.toList();
.collect(Collectors.toList());
ExecutableElement cons;
Element singleton;
@ -125,7 +126,7 @@ public class PersistableProcessor extends AbstractProcessor {
&& e.getModifiers().contains(Modifier.STATIC)
&& e.getModifiers().contains(Modifier.PUBLIC))
.filter(e -> tu.isSameType(e.asType(), typeElem.asType()))
.toList();
.collect(Collectors.toList());
if (singletonFields.isEmpty()) {
processingEnv
.getMessager()

View File

@ -7,8 +7,8 @@ import java.lang.annotation.Target;
/**
* Annotation for an automatic persistance of a class. Use to generate implementation and
* registration of {@link Persistance} subclass to read and write simple records and case classes:
*
* <p>{@snippet file="org/enso/persist/PersistanceTest.java" region="annotation"}
* <br>
* {@snippet file="org/enso/persist/PersistanceTest.java" region="annotation"}
*/
@Target(ElementType.TYPE)
@Repeatable(Persistable.Group.class)
@ -17,13 +17,10 @@ public @interface Persistable {
/**
* The class to generate {@link Persistance} for. If the value is omitted then the code is
* generated for the class that is annotated by this annotation. Example of multiple
* {@code @Persistable} annotations on a single element.
*
* <p>{@snippet file="org/enso/persist/PersistanceTest.java" region="annotation"}
*
* <p>Example of self annotated class:
*
* <p>{@snippet file="org/enso/persist/PersistanceTest.java" region="self-annotation"}
* {@code @Persistable} annotations on a single element. <br>
* {@snippet file="org/enso/persist/PersistanceTest.java" region="annotation"} <br>
* Example of self annotated class: <br>
* {@snippet file="org/enso/persist/PersistanceTest.java" region="self-annotation"}
*
* @return the class to generate read/write persistance code for
*/
@ -43,7 +40,7 @@ public @interface Persistable {
* {@code final} or <em>sealed</em> classes are inlined. Inlining is however not very helpful when
* a single object is shared between multiple other objects.
*
* @return
* @return allow or disallow inlining
*/
boolean allowInlining() default true;

View File

@ -10,28 +10,24 @@ import java.util.function.Function;
/**
* Central persistance class. Use static {@link Persistance#write write} method to turn a graph of
* JVM objects into a {@code byte[]}.
*
* <p>{@snippet file="org/enso/persist/PersistanceTest.java" region="write"}
* JVM objects into a {@code byte[]}. <br>
* {@snippet file="org/enso/persist/PersistanceTest.java" region="write"}
*
* <p>Use sibling static {@link Persistance#read readO} method to read the byte buffer back into
* their memory representation.
*
* <p>{@snippet file="org/enso/persist/PersistanceTest.java" region="read"}
* their memory representation. <br>
* {@snippet file="org/enso/persist/PersistanceTest.java" region="read"}
*
* <h2>Manual Persistance</h2>
*
* Unlike typical Java serialization (which tries to make things automatic), this framework requires
* one to implement the persistance manually. For each class that one wants to support, one has to
* implement subclass {@link Persistance} and implement its {@link Persistance#writeObject} and
* {@link Persistance#readObject} method.
* {@link Persistance#readObject} method. <br>
* {@snippet file="org/enso/persist/PersistanceTest.java" region="manual"} <br>
* There is a semi-automatic way to generate such subclasses of {@link Persistance} via the {@link
* Persistable @Persistable} annotation.
*
* <p>{@snippet file="org/enso/persist/PersistanceTest.java" region="manual"}
*
* <p>There is a semi-automatic way to generate such subclasses of {@link Persistance} via the
* {@link Persistable @Persistable} annotation.
*
* @param <T>
* @param <T> type this persistance subclass operates on
*/
public abstract class Persistance<T> implements Cloneable {
final Class<T> clazz;
@ -40,14 +36,11 @@ public abstract class Persistance<T> implements Cloneable {
/**
* Constructor for subclasses to register persistance for certain {@code clazz}. Sample
* registration:
*
* <p>{@snippet file="org/enso/persist/PersistanceTest.java" region="manual"}
*
* <p>Each persistance requires unique ID. A stream created by {@link #write(Object,
* Function<Object, Object>)} and read by {@link #read(byte[], Function<Object, Object>)} contains
* a header derived from the all the IDs present in the system. When versioning the protocol and
* implementation:
* registration: <br>
* {@snippet file="org/enso/persist/PersistanceTest.java" region="manual"} <br>
* Each persistance requires unique ID. A stream created by {@link #write(Object, Function<Object,
* Object>)} and read by {@link #read(byte[], Function<Object, Object>)} contains a header derived
* from the all the IDs present in the system. When versioning the protocol and implementation:
*
* <ul>
* <li>when you change something really core in the Persitance itself - change the header
@ -74,8 +67,23 @@ public abstract class Persistance<T> implements Cloneable {
}
}
/**
* Handle serialization of provided object.
*
* @param obj the object to serialize
* @param out the stream to persist the objec to
* @throws IOException thrown on I/O errors
*/
protected abstract void writeObject(T obj, Output out) throws IOException;
/**
* Handle deserialization on an object.
*
* @param in stream to read an instance of the object from
* @return instance of the deserialized object
* @throws IOException thrown on I/O errors
* @throws ClassNotFoundException thrown when class loading fails
*/
protected abstract T readObject(Input in) throws IOException, ClassNotFoundException;
/** Prints the {@code clazz} and {@code id} values. */
@ -158,9 +166,9 @@ public abstract class Persistance<T> implements Cloneable {
}
/**
* Read object written down by {@link #write} from an array.
*
* <p>{@snippet file="org/enso/persist/PersistanceTest.java" region="read"}
* Read object written down by {@link #write} from an array. <br>
* {@snippet file="org/enso/persist/PersistanceTest.java" region="read"} <br>
* {@snippet file="org/enso/persist/PersistanceTest.java" region="read"}
*
* @param arr the stored bytes
* @param readResolve either {@code null} or function to call for each object being stored to
@ -209,6 +217,7 @@ public abstract class Persistance<T> implements Cloneable {
* deferred towards the end, allowing to handle circular references inside of the serialized
* structure.
*
* @param <T> expected type of the referenced object
* @see Input#readReference
*/
public abstract static sealed class Reference<T> permits PerBufferReference, PerMemoryReference {

View File

@ -1,13 +1,11 @@
/**
* Framework for persisting Java objects and reading them <em>"lazily"</em>. Use static {@link
* Persistance#write write} method to turn a graph of JVM objects into a {@code byte[]}.
*
* <p>{@snippet file="org/enso/persist/PersistanceTest.java" region="write"}
* Persistance#write write} method to turn a graph of JVM objects into a {@code byte[]}. <br>
* {@snippet file="org/enso/persist/PersistanceTest.java" region="write"}
*
* <p>Use sibling static {@link Persistance#read read} method to read the byte buffer back into
* their memory representation.
*
* <p>{@snippet file="org/enso/persist/PersistanceTest.java" region="read"}
* their memory representation. <br>
* {@snippet file="org/enso/persist/PersistanceTest.java" region="read"}
*
* <h2>Laziness</h2>
*
@ -20,9 +18,8 @@
* Unlike typical Java serialization (which tries to make things automatic), this framework requires
* one to implement the persistance manually. For each class one wants to serde, one has to
* implement a subclass of {@link Persistance} and implement its {@link Persistance#writeObject} and
* {@link Persistance#readObject} methods.
*
* <p>{@snippet file="org/enso/persist/PersistanceTest.java" region="manual"}
* {@link Persistance#readObject} methods. <br>
* {@snippet file="org/enso/persist/PersistanceTest.java" region="manual"}
*
* <h2>Semi-automatic Persistance</h2>
*
@ -30,8 +27,7 @@
* errorprone process. That's why there is a {@link Persistable @Persistable} annotation and
* associated annotation processor that generates the necessary {@link Persistance} subclass based
* on the "richest" constructor in the class to be persisted. This approach seems to work well for
* Java records and Scala case classes.
*
* <p>{@snippet file="org/enso/persist/PersistanceTest.java" region="annotation"}
* Java records and Scala case classes. <br>
* {@snippet file="org/enso/persist/PersistanceTest.java" region="annotation"}
*/
package org.enso.persist;

View File

@ -8,6 +8,12 @@ import java.nio.charset.StandardCharsets;
public final class Parser implements AutoCloseable {
private static void initializeLibraries() {
try {
System.loadLibrary("enso_parser");
return;
} catch (LinkageError err) {
// try harder to find the library
}
String os = System.getProperty("os.name");
String name;
if (os.startsWith("Mac")) {
@ -34,7 +40,7 @@ public final class Parser implements AutoCloseable {
}
parser = path;
System.load(parser.getAbsolutePath());
} catch (URISyntaxException | LinkageError e) {
} catch (IllegalArgumentException | URISyntaxException | LinkageError e) {
File root = new File(".").getAbsoluteFile();
if (!searchFromDirToTop(e, root, "target", "rust", "debug", name)) {
throw new IllegalStateException("Cannot load parser from " + parser, e);

View File

@ -22,6 +22,13 @@ following two extensions in the system:
![Installed VSCode extensions](https://user-images.githubusercontent.com/26887752/274904239-ae1ad4cc-e2ec-4c5b-bca0-c7d7189c6885.png)
## Outline View
Since version 1.40 the extension fills content of _Outline View_ on supported
platforms (Linux amd64, Mac, Windows):
<img width="862" alt="image" src="https://github.com/enso-org/enso/assets/26887752/7374bf41-bdc6-4322-b562-85a2e761de2a">
## Debugging a Single Enso File
Open any `.enso` files. Click left editor gutter to place breakpoints. Then

View File

@ -607,11 +607,11 @@
}
},
"node_modules/braces": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
"integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
"integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
"dependencies": {
"fill-range": "^7.0.1"
"fill-range": "^7.1.1"
},
"engines": {
"node": ">=8"
@ -1338,9 +1338,9 @@
}
},
"node_modules/fill-range": {
"version": "7.0.1",
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
"integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
"version": "7.1.1",
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
"integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
"dependencies": {
"to-regex-range": "^5.0.1"
},

View File

@ -57,6 +57,12 @@
"configuration": "./src/main/resources/org/enso/tools/enso4igv/enso.tmLanguage.json"
}
],
"netbeans.documentSelectors": [
{
"language": "enso",
"pattern": "**/*.enso"
}
],
"grammars": [
{
"language": "enso",

View File

@ -5,19 +5,30 @@
<artifactId>enso4igv</artifactId>
<packaging>nbm</packaging>
<name>Enso Language Support for NetBeans &amp; Ideal Graph Visualizer</name>
<version>1.36-SNAPSHOT</version>
<version>1.40-SNAPSHOT</version>
<build>
<plugins>
<plugin>
<groupId>org.apache.netbeans.utilities</groupId>
<artifactId>nbm-maven-plugin</artifactId>
<extensions>true</extensions>
<version>4.7</version>
<version>14.1</version>
<configuration>
<useOSGiDependencies>true</useOSGiDependencies>
<useOSGiDependencies>false</useOSGiDependencies>
<author>Enso.org</author>
<licenseName>Apache 2.0</licenseName>
<licenseFile>../../LICENSE</licenseFile>
<nbmResources>
<nbmResource>
  <directory>${enso.parser.lib}</directory>
  <targetPath>modules/lib/</targetPath>
  <includes>
    <include>**/*.dll</include>
    <include>**/*.so</include>
    <include>**/*.dylib</include>
  </includes>
</nbmResource>
</nbmResources>
</configuration>
</plugin>
<plugin>
@ -217,6 +228,21 @@
<version>${netbeans.version}</version>
<type>jar</type>
</dependency>
<dependency>
<groupId>org.netbeans.api</groupId>
<artifactId>org-netbeans-api-lsp</artifactId>
<version>RELEASE160</version>
<type>jar</type>
</dependency>
<dependency>
<!--
$ sbt publishM2
-->
<groupId>org.enso</groupId>
<artifactId>runtime-parser</artifactId>
<version>0.2-SNAPSHOT</version>
<type>jar</type>
</dependency>
<dependency>
<groupId>org.netbeans.api</groupId>
<artifactId>org-netbeans-modules-nbjunit</artifactId>
@ -261,6 +287,8 @@
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<netbeans.version>RELEASE140</netbeans.version>
<netbeans.compile.on.save>none</netbeans.compile.on.save>
<enso.root>${basedir}/../../</enso.root>
<enso.parser.lib>${enso.root}/lib/rust/parser/target/classes/</enso.parser.lib>
</properties>
<profiles>
<profile>

View File

@ -0,0 +1,19 @@
package org.enso.tools.enso4igv.enso;
import java.util.function.Consumer;
import javax.swing.text.Document;
import org.netbeans.api.editor.mimelookup.MimeRegistration;
import org.netbeans.api.lsp.Completion;
import org.netbeans.spi.lsp.CompletionCollector;
@MimeRegistration(mimeType = "application/x-enso", service = CompletionCollector.class)
public class EnsoCompletionCollector implements CompletionCollector {
@Override
public boolean collectCompletions(Document dcmnt, int i, Completion.Context cntxt, Consumer<Completion> cnsmr) {
for (var e : EnsoStructure.collectStructure(dcmnt)) {
cnsmr.accept(CompletionCollector.newBuilder(e.getName()).build());
}
return true;
}
}

View File

@ -0,0 +1,88 @@
package org.enso.tools.enso4igv.enso;
import java.util.ArrayList;
import java.util.List;
import javax.swing.text.BadLocationException;
import javax.swing.text.Document;
import org.enso.compiler.core.EnsoParser;
import org.enso.compiler.core.IR;
import org.enso.compiler.core.ir.module.scope.Definition;
import org.enso.compiler.core.ir.module.scope.definition.Method;
import org.netbeans.api.editor.mimelookup.MimeRegistration;
import org.netbeans.api.lsp.StructureElement;
import org.netbeans.spi.lsp.StructureProvider;
import org.openide.filesystems.FileObject;
import org.openide.util.Lookup;
import scala.collection.Iterator;
@MimeRegistration(mimeType = "application/x-enso", service = StructureProvider.class)
public final class EnsoStructure implements StructureProvider {
@Override
public List<StructureElement> getStructure(Document dcmnt) {
return collectStructure(dcmnt);
}
static List<StructureElement> collectStructure(Document dcmnt) {
FileObject file = null;
if (dcmnt.getProperty(Document.StreamDescriptionProperty) instanceof Lookup.Provider p) {
if (p.getLookup().lookup(FileObject.class) instanceof FileObject fo) {
file = fo;
}
}
var arr = new ArrayList<StructureElement>();
try {
var parser = new EnsoParser();
var text = dcmnt.getText(0, dcmnt.getLength());
var moduleIr = parser.compile(text);
var it = moduleIr.bindings().iterator();
collectStructure(file, arr, it);
return arr;
} catch (LinkageError err) {
err.printStackTrace();
throw new IllegalStateException(err);
} catch (BadLocationException ex) {
throw new IllegalStateException(ex);
}
}
private static void collectStructure(FileObject file, List<StructureElement> arr, Iterator<? extends IR> it) {
while (it.hasNext()) {
var b = it.next();
collectStructureItem(file, arr, b);
}
}
private static void collectStructureItem(FileObject file, List<StructureElement> arr, IR ir) {
var b = switch (ir) {
case Definition.SugaredType type -> {
var bldr = StructureProvider.newBuilder(type.name().name(), StructureElement.Kind.Class);
var children = new ArrayList<StructureElement>();
collectStructure(file, children, type.body().iterator());
bldr.children(children);
yield bldr;
}
case Definition.Data data -> {
var bldr = StructureProvider.newBuilder(data.name().name(), StructureElement.Kind.Constructor);
yield bldr;
}
case Method.Binding bind -> {
var bldr = StructureProvider.newBuilder(bind.methodName().name(), StructureElement.Kind.Method);
yield bldr;
}
default -> null;
};
if (b != null) {
if (ir.location() != null && ir.location().isDefined()) {
var loc = ir.location().get().location();
b.selectionStartOffset(loc.start());
b.selectionEndOffset(loc.end());
b.expandedStartOffset(loc.start());
b.expandedEndOffset(loc.end());
}
b.file(file);
var e = b.build();
arr.add(e);
}
}
}

View File

@ -0,0 +1,46 @@
package org.enso.tools.enso4igv.enso;
import java.util.List;
import javax.swing.text.PlainDocument;
import static org.junit.Assert.assertEquals;
import org.junit.Test;
import org.netbeans.api.lsp.StructureElement;
public class EnsoStructureTest {
public EnsoStructureTest() {
}
@Test
public void processASimpleDocument() throws Exception {
var doc = new PlainDocument();
doc.insertString(0, """
type B
T
F
""", null);
var s = new EnsoStructure();
var root = s.getStructure(doc);
assertEquals("One root element: " + root, 1, root.size());
assertEquals("Type is class", StructureElement.Kind.Class, root.get(0).getKind());
final List<StructureElement> chldrn = root.get(0).getChildren();
assertEquals("Has two children", 2, chldrn.size());
assertEquals("Constructor is it at 0", StructureElement.Kind.Constructor, chldrn.get(0).getKind());
assertEquals("Constructor is it at 1", StructureElement.Kind.Constructor, chldrn.get(1).getKind());
}
@Test
public void collectMethods() throws Exception {
var doc = new PlainDocument();
doc.insertString(0, """
main = 6 * 7
""", null);
var s = new EnsoStructure();
var root = s.getStructure(doc);
assertEquals("One root element: " + root, 1, root.size());
assertEquals("It is a method", StructureElement.Kind.Method, root.get(0).getKind());
assertEquals("It is a method", "main", root.get(0).getName());
}
}