mirror of
https://github.com/enso-org/enso.git
synced 2024-12-23 10:42:05 +03:00
Add File System Path to the Content Roots (#1827)
This commit is contained in:
parent
0b347d7443
commit
8d71145d57
@ -57,6 +57,7 @@ transport formats, please look [here](./protocol-architecture).
|
||||
- [`WorkspaceEdit`](#workspaceedit)
|
||||
- [`EnsoDigest`](#ensodigest)
|
||||
- [`FileSegment`](#filesegment)
|
||||
- [`ContentRoot`](#contentroot)
|
||||
- [Connection Management](#connection-management)
|
||||
- [`session/initProtocolConnection`](#sessioninitprotocolconnection)
|
||||
- [`session/initBinaryConnection`](#sessioninitbinaryconnection)
|
||||
@ -1156,35 +1157,61 @@ a location on a real file-system that has been virtualised for use in the Enso
|
||||
VFS.
|
||||
|
||||
```typescript
|
||||
interface ContentRoot {
|
||||
// A unique identifier for the content root.
|
||||
id: UUID;
|
||||
// The type of content root.
|
||||
type: ContentRootType;
|
||||
|
||||
// The name of the content root.
|
||||
name: String;
|
||||
}
|
||||
type ContentRoot = Project | FileSystemRoot | Home | Library | Custom;
|
||||
```
|
||||
|
||||
### `ContentRootType`
|
||||
|
||||
The type of the annotated content root.
|
||||
|
||||
```typescript
|
||||
type ContentRootType = Project | Root | Home | Library | Custom;
|
||||
/** This content root points to the project home. */
|
||||
interface Project {
|
||||
// A unique identifier for the content root.
|
||||
id: UUID;
|
||||
}
|
||||
|
||||
/**
|
||||
* This content root points to the system root (`/`) on unix systems, or to a
|
||||
* drive root on Windows. In Windows' case, there may be multiple `Root` entries
|
||||
* corresponding to the various drives.
|
||||
*/
|
||||
interface FileSystemRoot {
|
||||
// A unique identifier for the content root.
|
||||
id: UUID;
|
||||
|
||||
// The absolute filesystem path of the content root.
|
||||
path: String;
|
||||
}
|
||||
|
||||
/** The user's home directory. */
|
||||
interface Home {
|
||||
// A unique identifier for the content root.
|
||||
id: UUID;
|
||||
}
|
||||
|
||||
/** An Enso library location. */
|
||||
interface Library {
|
||||
// A unique identifier for the content root.
|
||||
id: UUID;
|
||||
|
||||
// The namespace of the library.
|
||||
namespace: String;
|
||||
|
||||
// The name of the library.
|
||||
name: String;
|
||||
|
||||
/**
|
||||
* The version of the library.
|
||||
*
|
||||
* It is either a semver version of the library or the string "local".
|
||||
*/
|
||||
version: String;
|
||||
}
|
||||
|
||||
/** A content root that has been added by the IDE (unused for now). */
|
||||
interface Custom {
|
||||
// A unique identifier for the content root.
|
||||
id: UUID;
|
||||
}
|
||||
```
|
||||
|
||||
These represent:
|
||||
|
||||
- `Project`: This content root points to the project home.
|
||||
- `Root`: This content root points to the system root (`/`) on unix systems, or
|
||||
to a drive root on Windows. In Windows' case, there may be multiple `Root`
|
||||
entries corresponding to the various drives.
|
||||
- `Home`: The user's home directory.
|
||||
- `Library`: An Enso library location.
|
||||
- `Custom`: A content root that has been added by the IDE (unused for now).
|
||||
|
||||
## Connection Management
|
||||
|
||||
In order to properly set-up and tear-down the language server connection, we
|
||||
|
@ -9,10 +9,10 @@ import org.enso.languageserver.capability.CapabilityRouter
|
||||
import org.enso.languageserver.data._
|
||||
import org.enso.languageserver.effect.ZioExec
|
||||
import org.enso.languageserver.filemanager.{
|
||||
ContentRoot,
|
||||
ContentRootManager,
|
||||
ContentRootManagerActor,
|
||||
ContentRootManagerWrapper,
|
||||
ContentRootType,
|
||||
ContentRootWithFile,
|
||||
FileManager,
|
||||
FileSystem,
|
||||
@ -62,9 +62,7 @@ class MainModule(serverConfig: LanguageServerConfig, logLevel: LogLevel) {
|
||||
|
||||
val directoriesConfig = ProjectDirectoriesConfig(serverConfig.contentRootPath)
|
||||
private val contentRoot = ContentRootWithFile(
|
||||
serverConfig.contentRootUuid,
|
||||
ContentRootType.Project,
|
||||
"Project",
|
||||
ContentRoot.Project(serverConfig.contentRootUuid),
|
||||
new File(serverConfig.contentRootPath)
|
||||
)
|
||||
val languageServerConfig = Config(
|
||||
|
@ -1,69 +1,128 @@
|
||||
package org.enso.languageserver.filemanager
|
||||
|
||||
import enumeratum._
|
||||
import io.circe.syntax.EncoderOps
|
||||
import io.circe.{Encoder, Json}
|
||||
|
||||
import java.io.File
|
||||
import java.util.UUID
|
||||
|
||||
/** A representation of a content root.
|
||||
*
|
||||
* @param id the unique identifier of the content root
|
||||
* @param type the type of the content root
|
||||
* @param name The name of the content root
|
||||
*/
|
||||
case class ContentRoot(id: UUID, `type`: ContentRootType, name: String)
|
||||
/** A representation of a content root. */
|
||||
sealed trait ContentRoot {
|
||||
|
||||
/** The type of entity that the content root represents.
|
||||
*/
|
||||
sealed trait ContentRootType extends EnumEntry
|
||||
object ContentRootType extends Enum[ContentRootType] with CirceEnum[ContentRootType] {
|
||||
|
||||
/** The content root represents the root of the current Enso project.
|
||||
*/
|
||||
case object Project extends ContentRootType
|
||||
|
||||
/** The content root represents a system root (`/` on unix, drives on
|
||||
* windows).
|
||||
*
|
||||
* There may be multiple of this type of root sent by default.
|
||||
*/
|
||||
case object Root extends ContentRootType
|
||||
|
||||
/** The content root represents the user's home directory.
|
||||
*/
|
||||
case object Home extends ContentRootType
|
||||
|
||||
/** The content root represents an Enso library.
|
||||
*/
|
||||
case object Library extends ContentRootType
|
||||
|
||||
/** The content root was a custom location added by the IDE.
|
||||
*/
|
||||
case object Custom extends ContentRootType
|
||||
|
||||
/** Necessary for Enumeratum and Circe. */
|
||||
override val values = findValues
|
||||
/** The unique identifier of the content root. */
|
||||
def id: UUID
|
||||
}
|
||||
|
||||
/** A representation of a content root.
|
||||
object ContentRoot {
|
||||
|
||||
/** A filesystem root.
|
||||
*
|
||||
* @param id the unique identifier of the content root
|
||||
* @param path absolute path of the content root
|
||||
*/
|
||||
case class FileSystemRoot(override val id: UUID, path: String)
|
||||
extends ContentRoot
|
||||
|
||||
/** A root representing user's home on the filesystem.
|
||||
*
|
||||
* @param id the unique identifier of the content root
|
||||
*/
|
||||
case class Home(override val id: UUID) extends ContentRoot
|
||||
|
||||
/** Main project root.
|
||||
*
|
||||
* @param id the unique identifier of the content root
|
||||
*/
|
||||
case class Project(override val id: UUID) extends ContentRoot
|
||||
|
||||
/** A root of an imported library.
|
||||
*
|
||||
* @param id the unique identifier of the content root
|
||||
* @param namespace namespace of the library
|
||||
* @param name name of the library
|
||||
* @param version version of the library
|
||||
*/
|
||||
case class Library(
|
||||
override val id: UUID,
|
||||
namespace: String,
|
||||
name: String,
|
||||
version: String
|
||||
) extends ContentRoot
|
||||
|
||||
/** A custom root, currently not used.
|
||||
*
|
||||
* @param id the unique identifier of the content root
|
||||
*/
|
||||
case class Custom(override val id: UUID) extends ContentRoot
|
||||
|
||||
private object CodecField {
|
||||
val Id = "id"
|
||||
val Type = "type"
|
||||
val Namespace = "namespace"
|
||||
val Name = "name"
|
||||
val Version = "version"
|
||||
val Path = "path"
|
||||
}
|
||||
|
||||
private object CodecType {
|
||||
val FileSystemRoot = "FileSystemRoot"
|
||||
val Home = "Home"
|
||||
val Project = "Project"
|
||||
val Library = "Library"
|
||||
val Custom = "Custom"
|
||||
}
|
||||
|
||||
/** An [[Encoder]] instance for [[ContentRoot]]. */
|
||||
implicit val encoder: Encoder[ContentRoot] = {
|
||||
case FileSystemRoot(id, path) =>
|
||||
Json.obj(
|
||||
CodecField.Type -> CodecType.FileSystemRoot.asJson,
|
||||
CodecField.Id -> id.asJson,
|
||||
CodecField.Path -> path.asJson
|
||||
)
|
||||
case Home(id) =>
|
||||
Json.obj(
|
||||
CodecField.Type -> CodecType.Home.asJson,
|
||||
CodecField.Id -> id.asJson
|
||||
)
|
||||
case Project(id) =>
|
||||
Json.obj(
|
||||
CodecField.Type -> CodecType.Project.asJson,
|
||||
CodecField.Id -> id.asJson
|
||||
)
|
||||
case Library(id, namespace, name, version) =>
|
||||
Json.obj(
|
||||
CodecField.Type -> CodecType.Library.asJson,
|
||||
CodecField.Id -> id.asJson,
|
||||
CodecField.Namespace -> namespace.asJson,
|
||||
CodecField.Name -> name.asJson,
|
||||
CodecField.Version -> version.asJson
|
||||
)
|
||||
case Custom(id) =>
|
||||
Json.obj(
|
||||
CodecField.Type -> CodecType.Custom.asJson,
|
||||
CodecField.Id -> id.asJson
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/** A representation of a content root with a file that represents its
|
||||
* filesystem location
|
||||
*
|
||||
* @param id the unique identifier of the content root
|
||||
* @param `type` the type of the content root
|
||||
* @param name The name of the content root
|
||||
* @param contentRoot the raw content root
|
||||
* @param file the file on the filesystem that is the content root
|
||||
*/
|
||||
case class ContentRootWithFile(
|
||||
id: UUID,
|
||||
`type`: ContentRootType,
|
||||
name: String,
|
||||
contentRoot: ContentRoot,
|
||||
file: File
|
||||
) {
|
||||
|
||||
/** The unique identifier of the content root. */
|
||||
def id: UUID = contentRoot.id
|
||||
|
||||
/** Convert this to a content root for use in the protocol.
|
||||
*
|
||||
* @return a protocol content root
|
||||
*/
|
||||
def toContentRoot: ContentRoot = {
|
||||
ContentRoot(id, `type`, name)
|
||||
}
|
||||
def toContentRoot: ContentRoot = contentRoot
|
||||
}
|
||||
|
@ -58,13 +58,14 @@ class ContentRootManagerActor(config: Config)
|
||||
context.become(mainStage(contentRoots, subscribers + sender()))
|
||||
|
||||
case Api.LibraryLoaded(libraryName, libraryVersion, rootPath) =>
|
||||
val rootName = s"$libraryName:$libraryVersion"
|
||||
|
||||
val libraryRoot = ContentRootWithFile(
|
||||
id = UUID.randomUUID(),
|
||||
`type` = ContentRootType.Library,
|
||||
name = rootName,
|
||||
file = rootPath.getCanonicalFile
|
||||
ContentRoot.Library(
|
||||
id = UUID.randomUUID(),
|
||||
namespace = libraryName.namespace,
|
||||
name = libraryName.name,
|
||||
version = libraryVersion.toString
|
||||
),
|
||||
file = rootPath.getCanonicalFile
|
||||
)
|
||||
|
||||
subscribers.foreach { subscriber =>
|
||||
@ -109,7 +110,7 @@ object ContentRootManagerActor {
|
||||
private case class ContentRoots(
|
||||
projectRoot: ContentRootWithFile,
|
||||
librariesRoots: List[ContentRootWithFile],
|
||||
homeRoots: List[ContentRootWithFile],
|
||||
homeRoot: Option[ContentRootWithFile],
|
||||
filesystemRoots: List[ContentRootWithFile]
|
||||
) {
|
||||
def addLibraryRoot(contentRoot: ContentRootWithFile): ContentRoots =
|
||||
@ -122,7 +123,7 @@ object ContentRootManagerActor {
|
||||
* roots will take precedence.
|
||||
*/
|
||||
lazy val toList: List[ContentRootWithFile] =
|
||||
List(projectRoot) ++ librariesRoots ++ homeRoots ++ filesystemRoots
|
||||
List(projectRoot) ++ librariesRoots ++ homeRoot.toList ++ filesystemRoots
|
||||
|
||||
/** Resolves the path as relative to one of the registered content roots.
|
||||
*
|
||||
@ -146,13 +147,12 @@ object ContentRootManagerActor {
|
||||
val fsRoots = FileSystems.getDefault.getRootDirectories.asScala.map {
|
||||
path =>
|
||||
val absolutePath = path.toAbsolutePath.normalize
|
||||
val name =
|
||||
Option(absolutePath.getRoot).map(_.toString).getOrElse("<root>")
|
||||
ContentRootWithFile(
|
||||
id = UUID.randomUUID(),
|
||||
`type` = ContentRootType.Root,
|
||||
name = name,
|
||||
file = absolutePath.toFile
|
||||
ContentRoot.FileSystemRoot(
|
||||
id = UUID.randomUUID(),
|
||||
path = absolutePath.toString
|
||||
),
|
||||
file = absolutePath.toFile
|
||||
)
|
||||
}
|
||||
|
||||
@ -160,16 +160,14 @@ object ContentRootManagerActor {
|
||||
homeProp <- sys.props.get("user.home")
|
||||
homePath <- Try(JPath.of(homeProp)).toOption
|
||||
} yield ContentRootWithFile(
|
||||
id = UUID.randomUUID(),
|
||||
`type` = ContentRootType.Home,
|
||||
name = "Home",
|
||||
file = homePath.toAbsolutePath.normalize.toFile
|
||||
ContentRoot.Home(UUID.randomUUID()),
|
||||
file = homePath.toAbsolutePath.normalize.toFile
|
||||
)
|
||||
|
||||
ContentRoots(
|
||||
projectRoot = config.projectContentRoot,
|
||||
librariesRoots = Nil,
|
||||
homeRoots = homeRoot.toList,
|
||||
homeRoot = homeRoot,
|
||||
filesystemRoots = fsRoots.toList
|
||||
)
|
||||
}
|
||||
|
@ -207,7 +207,11 @@ class JsonConnectionController(
|
||||
): Receive = {
|
||||
case ContentRootManagerProtocol.ContentRootsAddedNotification(roots) =>
|
||||
val allRoots = roots ++ rootsSoFar
|
||||
if (roots.exists(_.`type` == ContentRootType.Project)) {
|
||||
val hasProject = roots.exists {
|
||||
case ContentRootWithFile(ContentRoot.Project(_), _) => true
|
||||
case _ => false
|
||||
}
|
||||
if (hasProject) {
|
||||
cancellable.cancel()
|
||||
unstashAll()
|
||||
|
||||
|
@ -5,10 +5,7 @@ import akka.testkit._
|
||||
import org.apache.commons.io.FileUtils
|
||||
import org.enso.languageserver.data._
|
||||
import org.enso.languageserver.event.InitializedEvent
|
||||
import org.enso.languageserver.filemanager.{
|
||||
ContentRootType,
|
||||
ContentRootWithFile
|
||||
}
|
||||
import org.enso.languageserver.filemanager.{ContentRoot, ContentRootWithFile}
|
||||
import org.enso.searcher.sql.{
|
||||
SchemaVersion,
|
||||
SqlDatabase,
|
||||
@ -222,9 +219,7 @@ class RepoInitializationSpec
|
||||
sys.addShutdownHook(FileUtils.deleteQuietly(testContentRoot.toFile))
|
||||
val config = newConfig(
|
||||
ContentRootWithFile(
|
||||
UUID.randomUUID(),
|
||||
ContentRootType.Project,
|
||||
"Project",
|
||||
ContentRoot.Project(UUID.randomUUID()),
|
||||
testContentRoot.toFile
|
||||
)
|
||||
)
|
||||
|
@ -33,9 +33,7 @@ class ContentRootManagerSpec
|
||||
|
||||
def makeContentRootManager(): (ContentRootManagerWrapper, ActorRef) = {
|
||||
val root = ContentRootWithFile(
|
||||
UUID.randomUUID(),
|
||||
ContentRootType.Project,
|
||||
"Project",
|
||||
ContentRoot.Project(UUID.randomUUID()),
|
||||
new File("foobar").getCanonicalFile
|
||||
)
|
||||
val config = Config(
|
||||
@ -57,17 +55,17 @@ class ContentRootManagerSpec
|
||||
val (contentRootManager, _) = makeContentRootManager()
|
||||
val roots =
|
||||
contentRootManager.getContentRoots(system.dispatcher).futureValue
|
||||
val simplifiedRoots =
|
||||
roots.map(root => (root.name, root.`type`, root.file))
|
||||
val fsRoots =
|
||||
roots.collect {
|
||||
case ContentRootWithFile(ContentRoot.FileSystemRoot(_, path), _) =>
|
||||
path
|
||||
}
|
||||
|
||||
if (SystemUtils.IS_OS_WINDOWS) {
|
||||
simplifiedRoots should contain(
|
||||
("C:\\", ContentRootType.Root, new File("C:\\"))
|
||||
)
|
||||
fsRoots should contain("C:\\")
|
||||
} else {
|
||||
simplifiedRoots should contain(
|
||||
("/", ContentRootType.Root, new File("/"))
|
||||
)
|
||||
fsRoots should contain("/")
|
||||
fsRoots should have size 1
|
||||
}
|
||||
}
|
||||
|
||||
@ -79,15 +77,19 @@ class ContentRootManagerSpec
|
||||
|
||||
inside(subscriberProbe.receiveOne(2.seconds.dilated)) {
|
||||
case ContentRootsAddedNotification(roots) =>
|
||||
val projectRoot = roots.filter(_.`type` == ContentRootType.Project)
|
||||
projectRoot should have size 1
|
||||
roots.filter(_.`type` == ContentRootType.Root) should not be empty
|
||||
val projectRoots = roots.collect {
|
||||
case ContentRootWithFile(ContentRoot.Project(_), _) =>
|
||||
}
|
||||
val fsRoots = roots.collect {
|
||||
case ContentRootWithFile(ContentRoot.Project(_), _) =>
|
||||
}
|
||||
projectRoots should have size 1
|
||||
fsRoots should not be empty
|
||||
}
|
||||
|
||||
val libraryName = LibraryName("Foo", "Bar")
|
||||
val libraryVersion = LibraryVersion.Local
|
||||
val rootPath = new File("foobar")
|
||||
val rootName = "Foo.Bar:local"
|
||||
|
||||
system.eventStream.publish(
|
||||
Api.LibraryLoaded(libraryName, libraryVersion, rootPath)
|
||||
@ -97,13 +99,27 @@ class ContentRootManagerSpec
|
||||
case ContentRootsAddedNotification(roots) =>
|
||||
roots should have length 1
|
||||
val root = roots.head
|
||||
root.name shouldEqual rootName
|
||||
root.file.getCanonicalFile shouldEqual rootPath.getCanonicalFile
|
||||
root.`type` shouldEqual ContentRootType.Library
|
||||
inside(root) {
|
||||
case ContentRootWithFile(
|
||||
ContentRoot.Library(_, namespace, name, version),
|
||||
file
|
||||
) =>
|
||||
file.getCanonicalFile shouldEqual rootPath.getCanonicalFile
|
||||
namespace shouldEqual "Foo"
|
||||
name shouldEqual "Bar"
|
||||
version shouldEqual "local"
|
||||
}
|
||||
}
|
||||
|
||||
val roots = wrapper.getContentRoots(system.dispatcher).futureValue
|
||||
roots.map(r => r.name) should contain(rootName)
|
||||
roots.exists {
|
||||
case ContentRootWithFile(
|
||||
ContentRoot.Library(_, "Foo", "Bar", "local"),
|
||||
_
|
||||
) =>
|
||||
true
|
||||
case _ => false
|
||||
}
|
||||
}
|
||||
|
||||
"return the root based on the id" in {
|
||||
@ -124,8 +140,15 @@ class ContentRootManagerSpec
|
||||
import system.dispatcher
|
||||
val roots = rootManager.getContentRoots.futureValue
|
||||
|
||||
val projectRoot = roots.filter(_.`type` == ContentRootType.Project).head
|
||||
val fsRoot = roots.filter(_.`type` == ContentRootType.Root).head
|
||||
val projectRoots = roots.collect {
|
||||
case root @ ContentRootWithFile(ContentRoot.Project(_), _) => root
|
||||
}
|
||||
val fsRoots = roots.collect {
|
||||
case root @ ContentRootWithFile(ContentRoot.Project(_), _) => root
|
||||
}
|
||||
|
||||
val projectRoot = projectRoots.head
|
||||
val someFsRoot = fsRoots.head
|
||||
|
||||
val projectPathRel = JPath.of("p1/foo")
|
||||
val projectPathAbsolute =
|
||||
@ -137,10 +160,10 @@ class ContentRootManagerSpec
|
||||
|
||||
val fsPathRel = JPath.of("fs/bar")
|
||||
val fsPathAbsolute =
|
||||
fsRoot.file.toPath.resolve(fsPathRel).toFile
|
||||
someFsRoot.file.toPath.resolve(fsPathRel).toFile
|
||||
val fsPathResolved =
|
||||
rootManager.findRelativePath(fsPathAbsolute).futureValue.value
|
||||
fsPathResolved.rootId shouldEqual fsRoot.id
|
||||
fsPathResolved.rootId shouldEqual someFsRoot.id
|
||||
fsPathResolved.segments shouldEqual Vector("fs", "bar")
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,53 @@
|
||||
package org.enso.languageserver.filemanager
|
||||
|
||||
import io.circe.Json
|
||||
import io.circe.syntax._
|
||||
import io.circe.literal._
|
||||
import org.scalatest.matchers.should.Matchers
|
||||
import org.scalatest.wordspec.AnyWordSpec
|
||||
|
||||
import java.util.UUID
|
||||
|
||||
class ContentRootSerializationSpec extends AnyWordSpec with Matchers {
|
||||
"ContentRoot" should {
|
||||
"correctly serialize" in {
|
||||
val id = UUID.randomUUID()
|
||||
|
||||
def toJson(contentRoot: ContentRoot): Json = contentRoot.asJson
|
||||
|
||||
toJson(ContentRoot.FileSystemRoot(id, path = "/")) shouldEqual
|
||||
json"""{
|
||||
"type": "FileSystemRoot",
|
||||
"id": $id,
|
||||
"path": "/"
|
||||
}"""
|
||||
|
||||
toJson(ContentRoot.Project(id)) shouldEqual
|
||||
json"""{
|
||||
"type": "Project",
|
||||
"id": $id
|
||||
}"""
|
||||
|
||||
toJson(ContentRoot.Home(id)) shouldEqual
|
||||
json"""{
|
||||
"type": "Home",
|
||||
"id": $id
|
||||
}"""
|
||||
|
||||
toJson(ContentRoot.Library(id, "foo", "Bar", "baz")) shouldEqual
|
||||
json"""{
|
||||
"type": "Library",
|
||||
"id": $id,
|
||||
"namespace": "foo",
|
||||
"name": "Bar",
|
||||
"version": "baz"
|
||||
}"""
|
||||
|
||||
toJson(ContentRoot.Custom(id)) shouldEqual
|
||||
json"""{
|
||||
"type": "Custom",
|
||||
"id": $id
|
||||
}"""
|
||||
}
|
||||
}
|
||||
}
|
@ -6,10 +6,10 @@ import org.apache.commons.io.FileUtils
|
||||
import org.enso.languageserver.data._
|
||||
import org.enso.languageserver.event.InitializedEvent
|
||||
import org.enso.languageserver.filemanager.{
|
||||
ContentRoot,
|
||||
ContentRootManager,
|
||||
ContentRootManagerActor,
|
||||
ContentRootManagerWrapper,
|
||||
ContentRootType,
|
||||
ContentRootWithFile
|
||||
}
|
||||
import org.enso.languageserver.runtime.ContextRegistryProtocol._
|
||||
@ -474,9 +474,7 @@ class ContextEventsListenerSpec
|
||||
sys.addShutdownHook(FileUtils.deleteQuietly(testContentRoot.toFile))
|
||||
val config = newConfig(
|
||||
ContentRootWithFile(
|
||||
UUID.randomUUID(),
|
||||
ContentRootType.Project,
|
||||
"Project",
|
||||
ContentRoot.Project(UUID.randomUUID()),
|
||||
testContentRoot.toFile
|
||||
)
|
||||
)
|
||||
|
@ -1,8 +1,5 @@
|
||||
package org.enso.languageserver.search
|
||||
|
||||
import java.io.File
|
||||
import java.nio.file.Files
|
||||
import java.util.UUID
|
||||
import akka.actor.{ActorRef, ActorSystem}
|
||||
import akka.testkit.{ImplicitSender, TestKit, TestProbe}
|
||||
import org.apache.commons.io.FileUtils
|
||||
@ -12,14 +9,7 @@ import org.enso.languageserver.capability.CapabilityProtocol.{
|
||||
}
|
||||
import org.enso.languageserver.data._
|
||||
import org.enso.languageserver.event.InitializedEvent
|
||||
import org.enso.languageserver.filemanager.{
|
||||
ContentRootManager,
|
||||
ContentRootManagerActor,
|
||||
ContentRootManagerWrapper,
|
||||
ContentRootType,
|
||||
ContentRootWithFile,
|
||||
Path
|
||||
}
|
||||
import org.enso.languageserver.filemanager._
|
||||
import org.enso.languageserver.refactoring.ProjectNameChangedEvent
|
||||
import org.enso.languageserver.search.SearchProtocol.SuggestionDatabaseEntry
|
||||
import org.enso.languageserver.session.JsonSession
|
||||
@ -36,6 +26,9 @@ import org.scalatest.BeforeAndAfterAll
|
||||
import org.scalatest.matchers.should.Matchers
|
||||
import org.scalatest.wordspec.AnyWordSpecLike
|
||||
|
||||
import java.io.File
|
||||
import java.nio.file.Files
|
||||
import java.util.UUID
|
||||
import scala.concurrent.duration._
|
||||
import scala.concurrent.{Await, Future}
|
||||
import scala.util.{Failure, Success}
|
||||
@ -839,9 +832,7 @@ class SuggestionsHandlerSpec
|
||||
sys.addShutdownHook(FileUtils.deleteQuietly(testContentRoot.toFile))
|
||||
val config = newConfig(
|
||||
ContentRootWithFile(
|
||||
UUID.randomUUID(),
|
||||
ContentRootType.Project,
|
||||
"Project",
|
||||
ContentRoot.Project(UUID.randomUUID()),
|
||||
testContentRoot.toFile
|
||||
)
|
||||
)
|
||||
|
@ -15,10 +15,10 @@ import org.enso.languageserver.data.{
|
||||
}
|
||||
import org.enso.languageserver.effect.ZioExec
|
||||
import org.enso.languageserver.filemanager.{
|
||||
ContentRoot,
|
||||
ContentRootManager,
|
||||
ContentRootManagerActor,
|
||||
ContentRootManagerWrapper,
|
||||
ContentRootType,
|
||||
ContentRootWithFile,
|
||||
FileManager,
|
||||
FileSystem
|
||||
@ -37,9 +37,7 @@ class BaseBinaryServerTest extends BinaryServerTestKit {
|
||||
|
||||
val testContentRootId = UUID.randomUUID()
|
||||
val testContentRoot = ContentRootWithFile(
|
||||
testContentRootId,
|
||||
ContentRootType.Project,
|
||||
"Project",
|
||||
ContentRoot.Project(testContentRootId),
|
||||
Files.createTempDirectory(null).toRealPath().toFile
|
||||
)
|
||||
val config = Config(
|
||||
|
@ -2,6 +2,8 @@ package org.enso.languageserver.websocket.json
|
||||
|
||||
import akka.testkit.TestProbe
|
||||
import io.circe.literal._
|
||||
import io.circe.parser.parse
|
||||
import io.circe.syntax.EncoderOps
|
||||
import org.apache.commons.io.FileUtils
|
||||
import org.enso.jsonrpc.test.JsonRpcServerTestKit
|
||||
import org.enso.jsonrpc.{ClientControllerFactory, Protocol}
|
||||
@ -14,16 +16,7 @@ import org.enso.languageserver.capability.CapabilityRouter
|
||||
import org.enso.languageserver.data._
|
||||
import org.enso.languageserver.effect.ZioExec
|
||||
import org.enso.languageserver.event.InitializedEvent
|
||||
import org.enso.languageserver.filemanager.{
|
||||
ContentRootManager,
|
||||
ContentRootManagerActor,
|
||||
ContentRootManagerWrapper,
|
||||
ContentRootType,
|
||||
ContentRootWithFile,
|
||||
FileManager,
|
||||
FileSystem,
|
||||
ReceivesTreeUpdatesHandler
|
||||
}
|
||||
import org.enso.languageserver.filemanager._
|
||||
import org.enso.languageserver.io._
|
||||
import org.enso.languageserver.protocol.json.{
|
||||
JsonConnectionControllerFactory,
|
||||
@ -37,16 +30,14 @@ import org.enso.languageserver.text.BufferRegistry
|
||||
import org.enso.polyglot.data.TypeGraph
|
||||
import org.enso.polyglot.runtime.Runtime.Api
|
||||
import org.enso.searcher.sql.{SqlDatabase, SqlSuggestionsRepo, SqlVersionsRepo}
|
||||
import org.enso.testkit.EitherValue
|
||||
import org.enso.text.Sha3_224VersionCalculator
|
||||
import org.scalatest.OptionValues
|
||||
|
||||
import java.nio.file.Files
|
||||
import java.util.UUID
|
||||
import scala.concurrent.Await
|
||||
import scala.concurrent.duration._
|
||||
import io.circe.parser.parse
|
||||
import io.circe.syntax.EncoderOps
|
||||
import org.enso.testkit.EitherValue
|
||||
import org.scalatest.OptionValues
|
||||
|
||||
class BaseServerTest
|
||||
extends JsonRpcServerTestKit
|
||||
@ -59,9 +50,7 @@ class BaseServerTest
|
||||
|
||||
val testContentRootId = UUID.randomUUID()
|
||||
val testContentRoot = ContentRootWithFile(
|
||||
testContentRootId,
|
||||
ContentRootType.Project,
|
||||
"Project",
|
||||
ContentRoot.Project(testContentRootId),
|
||||
Files.createTempDirectory(null).toRealPath().toFile
|
||||
)
|
||||
val config = mkConfig
|
||||
@ -250,8 +239,7 @@ class BaseServerTest
|
||||
json"""
|
||||
{
|
||||
"id" : $testContentRootId,
|
||||
"type" : "Project",
|
||||
"name" : "Project"
|
||||
"type" : "Project"
|
||||
}
|
||||
"""
|
||||
)
|
||||
|
@ -1799,8 +1799,6 @@ class FileManagerTest extends BaseServerTest with RetrySpec {
|
||||
val libraryName = LibraryName("Foo", "Bar")
|
||||
val libraryVersion = LibraryVersion.Published(SemVer(1, 2, 3), repo)
|
||||
val rootPath = new File("foobar")
|
||||
val rootName = "Foo.Bar:1.2.3"
|
||||
|
||||
system.eventStream.publish(
|
||||
Api.LibraryLoaded(libraryName, libraryVersion, rootPath)
|
||||
)
|
||||
@ -1809,8 +1807,10 @@ class FileManagerTest extends BaseServerTest with RetrySpec {
|
||||
inside(parsed) { case Right(json) =>
|
||||
val params = json.asObject.value("params").value.asObject.value
|
||||
val root = params("root").value.asObject.value
|
||||
root("name").value.asString.value shouldEqual rootName
|
||||
root("type").value.asString.value shouldEqual "Library"
|
||||
root("namespace").value.asString.value shouldEqual "Foo"
|
||||
root("name").value.asString.value shouldEqual "Bar"
|
||||
root("version").value.asString.value shouldEqual "1.2.3"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -30,8 +30,7 @@ class SessionManagementTest extends BaseServerTest {
|
||||
json"""
|
||||
{
|
||||
"id" : $testContentRootId,
|
||||
"type" : "Project",
|
||||
"name" : "Project"
|
||||
"type" : "Project"
|
||||
}
|
||||
"""
|
||||
)
|
||||
|
@ -4,14 +4,16 @@ import io.circe.{Decoder, DecodingFailure}
|
||||
|
||||
/** Represents a library name that should uniquely identify the library.
|
||||
*
|
||||
* The prefix is either a special prefix or a username.
|
||||
* @param namespace library's namespace - either a special reserved prefix or
|
||||
* the username of the main author
|
||||
* @param name library's name
|
||||
*/
|
||||
case class LibraryName(prefix: String, name: String) {
|
||||
case class LibraryName(namespace: String, name: String) {
|
||||
|
||||
/** The qualified name of the library consists of its prefix and name
|
||||
* separated with a dot.
|
||||
*/
|
||||
def qualifiedName: String = s"$prefix.$name"
|
||||
def qualifiedName: String = s"$namespace.$name"
|
||||
|
||||
/** @inheritdoc */
|
||||
override def toString: String = qualifiedName
|
||||
|
@ -17,7 +17,7 @@ class LibraryNameSpec
|
||||
val libraryName = LibraryName.fromString(str).rightValue
|
||||
libraryName.qualifiedName shouldEqual str
|
||||
libraryName.name shouldEqual "Bar"
|
||||
libraryName.prefix shouldEqual "Foo"
|
||||
libraryName.namespace shouldEqual "Foo"
|
||||
|
||||
val yamlParsed = YamlHelper.parseString[LibraryName](str).rightValue
|
||||
yamlParsed shouldEqual libraryName
|
||||
|
@ -28,7 +28,7 @@ class DefaultLocalLibraryProvider(distributionManager: DistributionManager)
|
||||
searchPaths: List[Path]
|
||||
): Option[Path] = searchPaths match {
|
||||
case head :: tail =>
|
||||
val potentialPath = head / libraryName.prefix / libraryName.name
|
||||
val potentialPath = head / libraryName.namespace / libraryName.name
|
||||
if (Files.exists(potentialPath) && Files.isDirectory(potentialPath))
|
||||
Some(potentialPath)
|
||||
else findLibraryHelper(libraryName, tail)
|
||||
|
Loading…
Reference in New Issue
Block a user