mirror of https://github.com/sbt/sbt.git
Support scala 2.13 console in thin client
In order to make the console task work with scala 2.13 and the thin client, we need to provide a way for the scala repl to use an sbt provided jline3 terminal instead of the default terminal typically built by the repl. We also need to put jline 3 higher up in the classloading hierarchy to ensure that two versions of jline 3 are not loaded (which makes it impossible to share the sbt terminal with the scala terminal). One impact of this change is the decoupling of the version of jline-terminal used by the in process scala console and the version of jline-terminal specified by the scala version itself. It is possible to override this by setting the `useScalaReplJLine` flag to true. When that is set, the scala REPL will run in a fully isolated classloader. That will ensure that the versions are consistent. It will, however, for sure break the thin client and may interfere with the embedded shell ui. As part of this work, I also discovered that jline 3 Terminal.getSize is very slow. In jline 2, the terminal attributes were automatically cached with a timeout of, I think, 1 second so it wasn't a big deal to call Terminal.getAttributes. The getSize method in jline 3 is not cached and it shells out to run a tty command. This caused a significant performance regression in sbt because when progress is enabled, we call Terminal.getSize whenever we log any messages. I added caching of getSize at the TerminalImpl level to address this. The timeout is 1 second, which seems responsive enough for most use cases. We could also move the calculation onto a background thread and have it periodically updated, but that seems like overkill.
This commit is contained in:
parent
6dd69a54ae
commit
90dacc339c
|
|
@ -304,7 +304,7 @@ val completeProj = (project in file("internal") / "util-complete")
|
|||
testedBaseSettings,
|
||||
name := "Completion",
|
||||
libraryDependencies += jline,
|
||||
libraryDependencies += jline3,
|
||||
libraryDependencies += jline3Reader,
|
||||
mimaSettings,
|
||||
// Parser is used publicly, so we can't break bincompat.
|
||||
mimaBinaryIssueFilters := Seq(
|
||||
|
|
@ -366,7 +366,8 @@ lazy val utilLogging = (project in file("internal") / "util-logging")
|
|||
libraryDependencies ++=
|
||||
Seq(
|
||||
jline,
|
||||
jline3,
|
||||
jline3Terminal,
|
||||
jline3Jansi,
|
||||
log4jApi,
|
||||
log4jCore,
|
||||
disruptor,
|
||||
|
|
@ -661,6 +662,7 @@ lazy val actionsProj = (project in file("main-actions"))
|
|||
testedBaseSettings,
|
||||
name := "Actions",
|
||||
libraryDependencies += sjsonNewScalaJson.value,
|
||||
libraryDependencies += jline3Terminal,
|
||||
mimaSettings,
|
||||
mimaBinaryIssueFilters ++= Seq(
|
||||
// Removed unused private[sbt] nested class
|
||||
|
|
@ -1103,7 +1105,6 @@ lazy val sbtClientProj = (project in file("client"))
|
|||
crossPaths := false,
|
||||
exportJars := true,
|
||||
libraryDependencies += jansi,
|
||||
libraryDependencies += jline3Jansi,
|
||||
libraryDependencies += scalatest % "test",
|
||||
/*
|
||||
* On windows, the raw classpath is too large to be a command argument to an
|
||||
|
|
|
|||
|
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* sbt
|
||||
* Copyright 2011 - 2018, Lightbend, Inc.
|
||||
* Copyright 2008 - 2010, Mark Harrah
|
||||
* Licensed under Apache License 2.0 (see LICENSE)
|
||||
*/
|
||||
|
||||
package sbt.internal.util;
|
||||
|
||||
import org.jline.terminal.TerminalBuilder;
|
||||
|
||||
/**
|
||||
* This exists to a provide a wrapper to TerminalBuilder.setTerminalOverride that will not emit a
|
||||
* deprecation warning when called from scala.
|
||||
*/
|
||||
public class DeprecatedJLine {
|
||||
@SuppressWarnings("deprecation")
|
||||
public static void setTerminalOverride(final org.jline.terminal.Terminal terminal) {
|
||||
TerminalBuilder.setTerminalOverride(terminal);
|
||||
}
|
||||
}
|
||||
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
package sbt.internal.util
|
||||
|
||||
import java.io.{ EOFException, InputStream, OutputStream, PrintWriter }
|
||||
import java.io.{ InputStream, OutputStream, PrintWriter }
|
||||
import java.nio.charset.Charset
|
||||
import java.util.{ Arrays, EnumSet }
|
||||
import java.util.concurrent.atomic.{ AtomicBoolean, AtomicReference }
|
||||
|
|
@ -22,7 +22,7 @@ import scala.collection.JavaConverters._
|
|||
import scala.util.Try
|
||||
import java.util.concurrent.LinkedBlockingQueue
|
||||
|
||||
private[util] object JLine3 {
|
||||
private[sbt] object JLine3 {
|
||||
private val capabilityMap = Capability
|
||||
.values()
|
||||
.map { c =>
|
||||
|
|
@ -109,18 +109,18 @@ private[util] object JLine3 {
|
|||
case _ => throw new ClosedException
|
||||
}
|
||||
if (res == 4 && term.prompt.render().endsWith(term.prompt.mkPrompt()))
|
||||
throw new EOFException
|
||||
throw new ClosedException
|
||||
res
|
||||
}
|
||||
}
|
||||
override val output: OutputStream = new OutputStream {
|
||||
override def write(b: Int): Unit = write(Array[Byte](b.toByte))
|
||||
override def write(b: Array[Byte]): Unit = if (!closed.get) term.withPrintStream { ps =>
|
||||
ps.write(b)
|
||||
term.prompt match {
|
||||
case a: Prompt.AskUser => a.write(b)
|
||||
case _ =>
|
||||
}
|
||||
ps.write(b)
|
||||
}
|
||||
override def write(b: Array[Byte], offset: Int, len: Int) =
|
||||
write(Arrays.copyOfRange(b, offset, offset + len))
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ import java.util.concurrent.{ Executors, LinkedBlockingQueue, TimeUnit }
|
|||
import jline.DefaultTerminal2
|
||||
import jline.console.ConsoleReader
|
||||
import scala.annotation.tailrec
|
||||
import scala.concurrent.duration._
|
||||
import scala.util.Try
|
||||
import scala.util.control.NonFatal
|
||||
|
||||
|
|
@ -174,10 +175,7 @@ object Terminal {
|
|||
try Terminal.console.printStream.println(s"[info] $string")
|
||||
catch { case _: IOException => }
|
||||
}
|
||||
private[sbt] def set(terminal: Terminal): Terminal = {
|
||||
jline.TerminalFactory.set(terminal.toJLine)
|
||||
activeTerminal.getAndSet(terminal)
|
||||
}
|
||||
private[sbt] def set(terminal: Terminal): Terminal = activeTerminal.getAndSet(terminal)
|
||||
implicit class TerminalOps(private val term: Terminal) extends AnyVal {
|
||||
def ansi(richString: => String, string: => String): String =
|
||||
if (term.isAnsiSupported) richString else string
|
||||
|
|
@ -500,7 +498,6 @@ object Terminal {
|
|||
* System.out through the terminal's input and output streams.
|
||||
*/
|
||||
private[this] val activeTerminal = new AtomicReference[Terminal](consoleTerminalHolder.get)
|
||||
jline.TerminalFactory.set(consoleTerminalHolder.get.toJLine)
|
||||
|
||||
/**
|
||||
* The boot input stream allows a remote client to forward input to the sbt process while
|
||||
|
|
@ -674,13 +671,13 @@ object Terminal {
|
|||
if (alive)
|
||||
try terminal.init()
|
||||
catch {
|
||||
case _: InterruptedException =>
|
||||
case _: InterruptedException | _: java.io.IOError =>
|
||||
}
|
||||
override def restore(): Unit =
|
||||
if (alive)
|
||||
try terminal.restore()
|
||||
catch {
|
||||
case _: InterruptedException =>
|
||||
case _: InterruptedException | _: java.io.IOError =>
|
||||
}
|
||||
override def reset(): Unit =
|
||||
try terminal.reset()
|
||||
|
|
@ -767,10 +764,12 @@ object Terminal {
|
|||
out: OutputStream
|
||||
) extends TerminalImpl(in, out, originalErr, "console0") {
|
||||
private[util] lazy val system = JLine3.system
|
||||
private[this] def isCI = sys.env.contains("BUILD_NUMBER") || sys.env.contains("CI")
|
||||
override def getWidth: Int = system.getSize.getColumns
|
||||
override def getHeight: Int = system.getSize.getRows
|
||||
override def isAnsiSupported: Boolean = term.isAnsiSupported && !isCI
|
||||
override private[sbt] def getSizeImpl: (Int, Int) = {
|
||||
val size = system.getSize
|
||||
(size.getColumns, size.getRows)
|
||||
}
|
||||
private[this] val isCI = sys.env.contains("BUILD_NUMBER") || sys.env.contains("CI")
|
||||
override lazy val isAnsiSupported: Boolean = term.isAnsiSupported && !isCI
|
||||
override def isEchoEnabled: Boolean = system.echo()
|
||||
override def isSuccessEnabled: Boolean = true
|
||||
override def getBooleanCapability(capability: String, jline3: Boolean): Boolean =
|
||||
|
|
@ -785,7 +784,7 @@ object Terminal {
|
|||
override private[sbt] def restore(): Unit = term.restore()
|
||||
|
||||
override private[sbt] def getAttributes: Map[String, String] =
|
||||
JLine3.toMap(system.getAttributes)
|
||||
Try(JLine3.toMap(system.getAttributes)).getOrElse(Map.empty)
|
||||
override private[sbt] def setAttributes(attributes: Map[String, String]): Unit =
|
||||
system.setAttributes(JLine3.attributesFromMap(attributes))
|
||||
override private[sbt] def setSize(width: Int, height: Int): Unit =
|
||||
|
|
@ -825,6 +824,19 @@ object Terminal {
|
|||
override val errorStream: OutputStream,
|
||||
override private[sbt] val name: String
|
||||
) extends Terminal {
|
||||
private[sbt] def getSizeImpl: (Int, Int)
|
||||
private[this] val sizeRefreshPeriod = 1.second
|
||||
private[this] val size =
|
||||
new AtomicReference[((Int, Int), Deadline)](((1, 1), Deadline.now - 1.day))
|
||||
private[this] def setSize() = size.set((Try(getSizeImpl).getOrElse((1, 1)), Deadline.now))
|
||||
private[this] def getSize = size.get match {
|
||||
case (s, d) if (d + sizeRefreshPeriod).isOverdue =>
|
||||
setSize()
|
||||
size.get._1
|
||||
case (s, _) => s
|
||||
}
|
||||
override def getWidth: Int = getSize._1
|
||||
override def getHeight: Int = getSize._2
|
||||
private[this] val rawMode = new AtomicBoolean(false)
|
||||
private[this] val writeLock = new AnyRef
|
||||
def throwIfClosed[R](f: => R): R = if (isStopped.get) throw new ClosedChannelException else f
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ package sbt
|
|||
import java.io.File
|
||||
import java.nio.channels.ClosedChannelException
|
||||
import sbt.internal.inc.{ AnalyzingCompiler, PlainVirtualFile }
|
||||
import sbt.internal.util.Terminal
|
||||
import sbt.internal.util.{ DeprecatedJLine, Terminal }
|
||||
import sbt.util.Logger
|
||||
import xsbti.compile.{ Compilers, Inputs }
|
||||
|
||||
|
|
@ -67,6 +67,8 @@ final class Console(compiler: AnalyzingCompiler) {
|
|||
try {
|
||||
sys.props("scala.color") = if (terminal.isColorEnabled) "true" else "false"
|
||||
terminal.withRawOutput {
|
||||
jline.TerminalFactory.set(terminal.toJLine)
|
||||
DeprecatedJLine.setTerminalOverride(sbt.internal.util.JLine3(terminal))
|
||||
terminal.withRawInput(Run.executeTrapExit(console0, log))
|
||||
}
|
||||
} finally {
|
||||
|
|
|
|||
|
|
@ -389,6 +389,10 @@ object State {
|
|||
s get BasicKeys.classLoaderCache getOrElse (throw new IllegalStateException(
|
||||
"Tried to get classloader cache for uninitialized state."
|
||||
))
|
||||
private[sbt] def extendedClassLoaderCache: ClassLoaderCache =
|
||||
s get BasicKeys.extendedClassLoaderCache getOrElse (throw new IllegalStateException(
|
||||
"Tried to get extended classloader cache for uninitialized state."
|
||||
))
|
||||
def initializeClassLoaderCache: State = {
|
||||
s.get(BasicKeys.extendedClassLoaderCache).foreach(_.close())
|
||||
val cache = newClassLoaderCache
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ import java.io.File
|
|||
import java.lang.management.ManagementFactory
|
||||
import java.lang.ref.{ Reference, ReferenceQueue, SoftReference }
|
||||
import java.net.URLClassLoader
|
||||
import java.util.concurrent.atomic.AtomicInteger
|
||||
import java.util.concurrent.atomic.{ AtomicInteger, AtomicReference }
|
||||
|
||||
import sbt.internal.inc.classpath.{
|
||||
AbstractClassLoaderCache,
|
||||
|
|
@ -30,9 +30,12 @@ private object ClassLoaderCache {
|
|||
private def threadID = new AtomicInteger(0)
|
||||
}
|
||||
private[sbt] class ClassLoaderCache(
|
||||
override val commonParent: ClassLoader,
|
||||
val parent: ClassLoader,
|
||||
private val miniProvider: Option[(File, ClassLoader)]
|
||||
) extends AbstractClassLoaderCache {
|
||||
private[this] val parentHolder = new AtomicReference(parent)
|
||||
def commonParent = parentHolder.get()
|
||||
def setParent(parent: ClassLoader): Unit = parentHolder.set(parent)
|
||||
def this(commonParent: ClassLoader) = this(commonParent, None)
|
||||
def this(scalaProvider: ScalaProvider) =
|
||||
this(scalaProvider.launcher.topLoader, {
|
||||
|
|
@ -51,8 +54,9 @@ private[sbt] class ClassLoaderCache(
|
|||
}
|
||||
}
|
||||
private class Key(val fileStamps: Seq[(File, Long)], val parent: ClassLoader) {
|
||||
def this(files: List[File]) =
|
||||
this(files.map(f => f -> IO.getModifiedTimeOrZero(f)), commonParent)
|
||||
def this(files: List[File], parent: ClassLoader) =
|
||||
this(files.map(f => f -> IO.getModifiedTimeOrZero(f)), parent)
|
||||
def this(files: List[File]) = this(files, commonParent)
|
||||
lazy val files: Seq[File] = fileStamps.map(_._1)
|
||||
lazy val maxStamp: Long = fileStamps.maxBy(_._2)._2
|
||||
class CachedClassLoader
|
||||
|
|
@ -169,10 +173,19 @@ private[sbt] class ClassLoaderCache(
|
|||
val key = new Key(files, parent)
|
||||
get(key, mkLoader)
|
||||
}
|
||||
override def apply(files: List[File]): ClassLoader = {
|
||||
val key = new Key(files)
|
||||
def apply(files: List[File], parent: ClassLoader): ClassLoader = {
|
||||
val key = new Key(files, parent)
|
||||
get(key, () => key.toClassLoader)
|
||||
}
|
||||
override def apply(files: List[File]): ClassLoader = {
|
||||
files match {
|
||||
case d :: s :: Nil if d.getName.startsWith("dotty-library") =>
|
||||
apply(files, classOf[org.jline.terminal.Terminal].getClassLoader)
|
||||
case _ =>
|
||||
val key = new Key(files)
|
||||
get(key, () => key.toClassLoader)
|
||||
}
|
||||
}
|
||||
override def cachedCustomClassloader(
|
||||
files: List[File],
|
||||
mkLoader: () => ClassLoader
|
||||
|
|
|
|||
|
|
@ -47,11 +47,12 @@ import Serialization.{
|
|||
systemErrFlush,
|
||||
terminalCapabilities,
|
||||
terminalCapabilitiesResponse,
|
||||
terminalGetSize,
|
||||
terminalPropertiesQuery,
|
||||
terminalPropertiesResponse,
|
||||
terminalSetSize,
|
||||
getTerminalAttributes,
|
||||
setTerminalAttributes,
|
||||
setTerminalSize,
|
||||
}
|
||||
import NetworkClient.Arguments
|
||||
|
||||
|
|
@ -657,7 +658,13 @@ class NetworkClient(
|
|||
cchars = attrs.getOrElse("cchars", ""),
|
||||
)
|
||||
sendCommandResponse("", response, msg.id)
|
||||
case (`setTerminalSize`, Some(json)) =>
|
||||
case (`terminalGetSize`, _) =>
|
||||
val response = TerminalGetSizeResponse(
|
||||
Terminal.console.getWidth,
|
||||
Terminal.console.getHeight,
|
||||
)
|
||||
sendCommandResponse("", response, msg.id)
|
||||
case (`terminalSetSize`, Some(json)) =>
|
||||
Converter.fromJson[TerminalSetSizeCommand](json) match {
|
||||
case Success(size) =>
|
||||
Terminal.console.setSize(size.width, size.height)
|
||||
|
|
|
|||
|
|
@ -49,6 +49,8 @@ private[sbt] object UITask {
|
|||
override def close(): Unit = {}
|
||||
}
|
||||
object Reader {
|
||||
// Avoid filling the stack trace since it isn't helpful here
|
||||
object interrupted extends InterruptedException
|
||||
def terminalReader(parser: Parser[_])(
|
||||
terminal: Terminal,
|
||||
state: State
|
||||
|
|
@ -59,9 +61,9 @@ private[sbt] object UITask {
|
|||
val clear = terminal.ansi(ClearPromptLine, "")
|
||||
@tailrec def impl(): Either[String, String] = {
|
||||
val thread = Thread.currentThread
|
||||
if (thread.isInterrupted || closed.get) throw new InterruptedException
|
||||
if (thread.isInterrupted || closed.get) throw interrupted
|
||||
val reader = LineReader.createReader(history(state), parser, terminal)
|
||||
if (thread.isInterrupted || closed.get) throw new InterruptedException
|
||||
if (thread.isInterrupted || closed.get) throw interrupted
|
||||
(try reader.readLine(clear + terminal.prompt.mkPrompt())
|
||||
finally reader.close) match {
|
||||
case None if terminal == Terminal.console && System.console == null =>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* sbt
|
||||
* Copyright 2011 - 2018, Lightbend, Inc.
|
||||
* Copyright 2008 - 2010, Mark Harrah
|
||||
* Licensed under Apache License 2.0 (see LICENSE)
|
||||
*/
|
||||
|
||||
package sbt.internal;
|
||||
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
|
||||
class JLineLoader extends URLClassLoader {
|
||||
JLineLoader(final URL[] urls, final ClassLoader parent) {
|
||||
super(urls, parent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
final StringBuilder result = new StringBuilder();
|
||||
result.append("JLineLoader(");
|
||||
final URL[] urls = getURLs();
|
||||
for (int i = 0; i < urls.length; ++i) {
|
||||
result.append(urls[i].toString());
|
||||
if (i < urls.length - 1) result.append(", ");
|
||||
}
|
||||
result.append(")");
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
static {
|
||||
registerAsParallelCapable();
|
||||
}
|
||||
}
|
||||
|
|
@ -22,16 +22,19 @@ public final class MetaBuildLoader extends URLClassLoader {
|
|||
private final URLClassLoader fullScalaLoader;
|
||||
private final URLClassLoader libraryLoader;
|
||||
private final URLClassLoader interfaceLoader;
|
||||
private final URLClassLoader jlineLoader;
|
||||
|
||||
MetaBuildLoader(
|
||||
final URL[] urls,
|
||||
final URLClassLoader fullScalaLoader,
|
||||
final URLClassLoader libraryLoader,
|
||||
final URLClassLoader interfaceLoader) {
|
||||
final URLClassLoader interfaceLoader,
|
||||
final URLClassLoader jlineLoader) {
|
||||
super(urls, fullScalaLoader);
|
||||
this.fullScalaLoader = fullScalaLoader;
|
||||
this.libraryLoader = libraryLoader;
|
||||
this.interfaceLoader = interfaceLoader;
|
||||
this.jlineLoader = jlineLoader;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -45,6 +48,7 @@ public final class MetaBuildLoader extends URLClassLoader {
|
|||
fullScalaLoader.close();
|
||||
libraryLoader.close();
|
||||
interfaceLoader.close();
|
||||
jlineLoader.close();
|
||||
}
|
||||
|
||||
static {
|
||||
|
|
@ -61,20 +65,26 @@ public final class MetaBuildLoader extends URLClassLoader {
|
|||
*/
|
||||
public static MetaBuildLoader makeLoader(final AppProvider appProvider) throws IOException {
|
||||
final Pattern pattern =
|
||||
Pattern.compile("^(test-interface-[0-9.]+|jline-[0-9.]+-sbt-.*|jansi-[0-9.]+)\\.jar");
|
||||
Pattern.compile(
|
||||
"^(test-interface-[0-9.]+|jline-(terminal-)?[0-9.]+-sbt-.*|jansi-[0-9.]+)\\.jar");
|
||||
final File[] cp = appProvider.mainClasspath();
|
||||
final URL[] interfaceURLs = new URL[3];
|
||||
final URL[] interfaceURLs = new URL[1];
|
||||
final URL[] jlineURLs = new URL[3];
|
||||
final File[] extra =
|
||||
appProvider.id().classpathExtra() == null ? new File[0] : appProvider.id().classpathExtra();
|
||||
final Set<File> bottomClasspath = new LinkedHashSet<>();
|
||||
|
||||
{
|
||||
int interfaceIndex = 0;
|
||||
int jlineIndex = 0;
|
||||
for (final File file : cp) {
|
||||
final String name = file.getName();
|
||||
if (pattern.matcher(name).find()) {
|
||||
if (name.contains("test-interface") && pattern.matcher(name).find()) {
|
||||
interfaceURLs[interfaceIndex] = file.toURI().toURL();
|
||||
interfaceIndex += 1;
|
||||
} else if (pattern.matcher(name).find()) {
|
||||
jlineURLs[jlineIndex] = file.toURI().toURL();
|
||||
jlineIndex += 1;
|
||||
} else {
|
||||
bottomClasspath.add(file);
|
||||
}
|
||||
|
|
@ -108,6 +118,7 @@ public final class MetaBuildLoader extends URLClassLoader {
|
|||
if (topLoader == null) topLoader = scalaProvider.launcher().topLoader();
|
||||
|
||||
final TestInterfaceLoader interfaceLoader = new TestInterfaceLoader(interfaceURLs, topLoader);
|
||||
final JLineLoader jlineLoader = new JLineLoader(jlineURLs, interfaceLoader);
|
||||
final File[] siJars = scalaProvider.jars();
|
||||
final URL[] lib = new URL[1];
|
||||
int scalaRestCount = siJars.length - 1;
|
||||
|
|
@ -131,8 +142,8 @@ public final class MetaBuildLoader extends URLClassLoader {
|
|||
}
|
||||
}
|
||||
assert lib[0] != null : "no scala-library.jar";
|
||||
final ScalaLibraryClassLoader libraryLoader = new ScalaLibraryClassLoader(lib, interfaceLoader);
|
||||
final ScalaLibraryClassLoader libraryLoader = new ScalaLibraryClassLoader(lib, jlineLoader);
|
||||
final FullScalaLoader fullScalaLoader = new FullScalaLoader(scalaRest, libraryLoader);
|
||||
return new MetaBuildLoader(rest, fullScalaLoader, libraryLoader, interfaceLoader);
|
||||
return new MetaBuildLoader(rest, fullScalaLoader, libraryLoader, interfaceLoader, jlineLoader);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@
|
|||
package sbt
|
||||
|
||||
import java.io.{ File, PrintWriter }
|
||||
import java.net.{ URI, URL, URLClassLoader }
|
||||
import java.net.{ URI, URL }
|
||||
import java.nio.file.{ Paths, Path => NioPath }
|
||||
import java.util.Optional
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
|
@ -34,9 +34,8 @@ import sbt.Scope.{ GlobalScope, ThisScope, fillTaskAxis }
|
|||
import sbt.coursierint._
|
||||
import sbt.internal.CommandStrings.ExportStream
|
||||
import sbt.internal._
|
||||
import sbt.internal.classpath.AlternativeZincUtil
|
||||
import sbt.internal.classpath.{ AlternativeZincUtil, ClassLoaderCache }
|
||||
import sbt.internal.inc.JavaInterfaceUtil._
|
||||
import sbt.internal.inc.classpath.{ ClassLoaderCache, ClasspathFilter, ClasspathUtil }
|
||||
import sbt.internal.inc.{
|
||||
CompileOutput,
|
||||
MappedFileConverter,
|
||||
|
|
@ -45,6 +44,8 @@ import sbt.internal.inc.{
|
|||
ZincLmUtil,
|
||||
ZincUtil
|
||||
}
|
||||
import sbt.internal.inc.classpath.{ ClasspathFilter, ClasspathUtil }
|
||||
import sbt.internal.inc.{ MappedFileConverter, PlainVirtualFile, Stamps, ZincLmUtil, ZincUtil }
|
||||
import sbt.internal.io.{ Source, WatchState }
|
||||
import sbt.internal.librarymanagement.mavenint.{
|
||||
PomExtraDependencyAttributes,
|
||||
|
|
@ -386,6 +387,11 @@ object Defaults extends BuildCommon {
|
|||
},
|
||||
turbo :== SysProp.turbo,
|
||||
usePipelining :== SysProp.pipelining,
|
||||
useScalaReplJLine :== false,
|
||||
scalaInstanceTopLoader := {
|
||||
if (!useScalaReplJLine.value) classOf[org.jline.terminal.Terminal].getClassLoader
|
||||
else appConfiguration.value.provider.scalaProvider.launcher.topLoader.getParent
|
||||
},
|
||||
useSuperShell := { if (insideCI.value) false else Terminal.console.isSupershellEnabled },
|
||||
progressReports := {
|
||||
val rs = EvaluateTask.taskTimingProgress.toVector ++ EvaluateTask.taskTraceEvent.toVector
|
||||
|
|
@ -888,8 +894,15 @@ object Defaults extends BuildCommon {
|
|||
val libraryJars = allJars.filter(_.getName == "scala-library.jar")
|
||||
allJars.filter(_.getName == "scala-compiler.jar") match {
|
||||
case Array(compilerJar) if libraryJars.nonEmpty =>
|
||||
val cache = state.value.classLoaderCache
|
||||
mkScalaInstance(version, allJars, libraryJars, compilerJar, cache)
|
||||
val cache = state.value.extendedClassLoaderCache
|
||||
mkScalaInstance(
|
||||
version,
|
||||
allJars,
|
||||
libraryJars,
|
||||
compilerJar,
|
||||
cache,
|
||||
scalaInstanceTopLoader.value
|
||||
)
|
||||
case _ => ScalaInstance(version, scalaProvider)
|
||||
}
|
||||
} else
|
||||
|
|
@ -931,7 +944,8 @@ object Defaults extends BuildCommon {
|
|||
allJars,
|
||||
Array(libraryJar),
|
||||
compilerJar,
|
||||
state.value.classLoaderCache
|
||||
state.value.extendedClassLoaderCache,
|
||||
scalaInstanceTopLoader.value,
|
||||
)
|
||||
}
|
||||
private[this] def mkScalaInstance(
|
||||
|
|
@ -940,15 +954,11 @@ object Defaults extends BuildCommon {
|
|||
libraryJars: Array[File],
|
||||
compilerJar: File,
|
||||
classLoaderCache: ClassLoaderCache,
|
||||
topLoader: ClassLoader,
|
||||
): ScalaInstance = {
|
||||
val allJarsDistinct = allJars.distinct
|
||||
val libraryLoader = classLoaderCache(libraryJars.toList)
|
||||
class ScalaLoader
|
||||
extends URLClassLoader(allJarsDistinct.map(_.toURI.toURL).toArray, libraryLoader)
|
||||
val fullLoader = classLoaderCache.cachedCustomClassloader(
|
||||
allJarsDistinct.toList,
|
||||
() => new ScalaLoader
|
||||
)
|
||||
val libraryLoader = classLoaderCache(libraryJars.toList, topLoader)
|
||||
val fullLoader = classLoaderCache(allJarsDistinct.toList, libraryLoader)
|
||||
new ScalaInstance(
|
||||
version,
|
||||
fullLoader,
|
||||
|
|
@ -970,7 +980,8 @@ object Defaults extends BuildCommon {
|
|||
dummy.allJars,
|
||||
dummy.libraryJars,
|
||||
dummy.compilerJar,
|
||||
state.value.classLoaderCache
|
||||
state.value.extendedClassLoaderCache,
|
||||
scalaInstanceTopLoader.value,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -570,6 +570,9 @@ object Keys {
|
|||
val includeLintKeys = settingKey[Set[Def.KeyedInitialize[_]]]("Task keys that are included into lintUnused task")
|
||||
val lintUnusedKeysOnLoad = settingKey[Boolean]("Toggles whether or not to check for unused keys during startup")
|
||||
|
||||
val useScalaReplJLine = settingKey[Boolean]("Toggles whether or not to use sbt's forked jline in the scala repl. Enabling this flag may break the thin client in the scala console.").withRank(KeyRanks.Invisible)
|
||||
val scalaInstanceTopLoader = settingKey[ClassLoader]("The top classloader for the scala instance").withRank(KeyRanks.Invisible)
|
||||
|
||||
val stateStreams = AttributeKey[Streams]("stateStreams", "Streams manager, which provides streams for different contexts. Setting this on State will override the default Streams implementation.")
|
||||
val resolvedScoped = Def.resolvedScoped
|
||||
val pluginData = taskKey[PluginData]("Information from the plugin build needed in the main build definition.").withRank(DTask)
|
||||
|
|
|
|||
|
|
@ -932,6 +932,9 @@ object BuiltinCommands {
|
|||
val s3 = addCacheStoreFactoryFactory(Project.setProject(session, structure, s2))
|
||||
val s4 = s3.put(Keys.useLog4J.key, Project.extract(s3).get(Keys.useLog4J))
|
||||
val s5 = setupGlobalFileTreeRepository(s4)
|
||||
// This is a workaround for the console task in dotty which uses the classloader cache.
|
||||
// We need to override the top loader in that case so that it gets the forked jline.
|
||||
s5.extendedClassLoaderCache.setParent(Project.extract(s5).get(Keys.scalaInstanceTopLoader))
|
||||
CheckBuildSources.init(LintUnused.lintUnusedFunc(s5))
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -59,17 +59,16 @@ private[sbt] class XMainConfiguration {
|
|||
val topLoader = configuration.provider.scalaProvider.launcher.topLoader
|
||||
val updatedConfiguration =
|
||||
try {
|
||||
val method = topLoader.getClass.getMethod("getEarlyJars")
|
||||
val method = topLoader.getClass.getMethod("getJLineJars")
|
||||
val jars = method.invoke(topLoader).asInstanceOf[Array[URL]]
|
||||
var canReuseConfiguration = jars.length == 3
|
||||
var j = 0
|
||||
while (j < jars.length && canReuseConfiguration) {
|
||||
val s = jars(j).toString
|
||||
canReuseConfiguration =
|
||||
s.contains("jline") || s.contains("test-interface") || s.contains("jansi")
|
||||
canReuseConfiguration = s.contains("jline") || s.contains("jansi")
|
||||
j += 1
|
||||
}
|
||||
if (canReuseConfiguration) configuration else makeConfiguration(configuration)
|
||||
if (canReuseConfiguration && j == 3) configuration else makeConfiguration(configuration)
|
||||
} catch {
|
||||
case _: NoSuchMethodException => makeConfiguration(configuration)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -875,6 +875,14 @@ final class NetworkChannel(
|
|||
try queue.take
|
||||
catch { case _: InterruptedException => }
|
||||
}
|
||||
override private[sbt] def getSizeImpl: (Int, Int) =
|
||||
if (!closed.get) {
|
||||
import sbt.protocol.codec.JsonProtocol._
|
||||
val queue = VirtualTerminal.getTerminalSize(name, jsonRpcRequest)
|
||||
val res = try queue.take
|
||||
catch { case _: InterruptedException => TerminalGetSizeResponse(1, 1) }
|
||||
(res.width, res.height)
|
||||
} else (1, 1)
|
||||
override def setSize(width: Int, height: Int): Unit =
|
||||
if (!closed.get) {
|
||||
import sbt.protocol.codec.JsonProtocol._
|
||||
|
|
|
|||
|
|
@ -20,7 +20,9 @@ import sbt.protocol.Serialization.{
|
|||
attach,
|
||||
systemIn,
|
||||
terminalCapabilities,
|
||||
terminalGetSize,
|
||||
terminalPropertiesQuery,
|
||||
terminalSetSize,
|
||||
}
|
||||
import sjsonnew.support.scalajson.unsafe.Converter
|
||||
import sbt.protocol.{
|
||||
|
|
@ -30,10 +32,13 @@ import sbt.protocol.{
|
|||
TerminalCapabilitiesQuery,
|
||||
TerminalCapabilitiesResponse,
|
||||
TerminalPropertiesResponse,
|
||||
TerminalGetSizeQuery,
|
||||
TerminalGetSizeResponse,
|
||||
TerminalSetAttributesCommand,
|
||||
TerminalSetSizeCommand,
|
||||
}
|
||||
import sbt.protocol.codec.JsonProtocol._
|
||||
import sbt.protocol.TerminalGetSizeResponse
|
||||
|
||||
object VirtualTerminal {
|
||||
private[this] val pendingTerminalProperties =
|
||||
|
|
@ -46,6 +51,8 @@ object VirtualTerminal {
|
|||
new ConcurrentHashMap[(String, String), ArrayBlockingQueue[Unit]]
|
||||
private[this] val pendingTerminalSetSize =
|
||||
new ConcurrentHashMap[(String, String), ArrayBlockingQueue[Unit]]
|
||||
private[this] val pendingTerminalGetSize =
|
||||
new ConcurrentHashMap[(String, String), ArrayBlockingQueue[TerminalGetSizeResponse]]
|
||||
private[sbt] def sendTerminalPropertiesQuery(
|
||||
channelName: String,
|
||||
jsonRpcRequest: (String, String, String) => Unit
|
||||
|
|
@ -111,9 +118,22 @@ object VirtualTerminal {
|
|||
val id = UUID.randomUUID.toString
|
||||
val queue = new ArrayBlockingQueue[Unit](1)
|
||||
pendingTerminalSetSize.put((channelName, id), queue)
|
||||
jsonRpcRequest(id, terminalCapabilities, query)
|
||||
jsonRpcRequest(id, terminalSetSize, query)
|
||||
queue
|
||||
}
|
||||
|
||||
private[sbt] def getTerminalSize(
|
||||
channelName: String,
|
||||
jsonRpcRequest: (String, String, TerminalGetSizeQuery) => Unit,
|
||||
): ArrayBlockingQueue[TerminalGetSizeResponse] = {
|
||||
val id = UUID.randomUUID.toString
|
||||
val query = TerminalGetSizeQuery()
|
||||
val queue = new ArrayBlockingQueue[TerminalGetSizeResponse](1)
|
||||
pendingTerminalGetSize.put((channelName, id), queue)
|
||||
jsonRpcRequest(id, terminalGetSize, query)
|
||||
queue
|
||||
}
|
||||
|
||||
val handler = ServerHandler { cb =>
|
||||
ServerIntent(requestHandler(cb), responseHandler(cb), notificationHandler(cb))
|
||||
}
|
||||
|
|
@ -166,6 +186,13 @@ object VirtualTerminal {
|
|||
case null =>
|
||||
case buffer => buffer.put(())
|
||||
}
|
||||
case r if pendingTerminalGetSize.get((callback.name, r.id)) != null =>
|
||||
val response =
|
||||
r.result.flatMap(Converter.fromJson[TerminalGetSizeResponse](_).toOption)
|
||||
pendingTerminalGetSize.remove((callback.name, r.id)) match {
|
||||
case null =>
|
||||
case buffer => buffer.put(response.getOrElse(TerminalGetSizeResponse(1, 1)))
|
||||
}
|
||||
}
|
||||
private val notificationHandler: Handler[JsonRpcNotificationMessage] =
|
||||
callback => {
|
||||
|
|
|
|||
|
|
@ -84,8 +84,10 @@ object Dependencies {
|
|||
val sjsonNewMurmurhash = sjsonNew("sjson-new-murmurhash")
|
||||
|
||||
val jline = "org.scala-sbt.jline" % "jline" % "2.14.7-sbt-5e51b9d4f9631ebfa29753ce4accc57808e7fd6b"
|
||||
val jline3 = "org.jline" % "jline" % "3.15.0"
|
||||
val jline3Jansi = "org.jline" % "jline-terminal-jansi" % "3.15.0"
|
||||
val jline3Version = "3.16.0" // Once the base jline version is upgraded, we can use the official jline-terminal
|
||||
val jline3Terminal = "org.scala-sbt.jline3" % "jline-terminal" % s"$jline3Version-sbt-211a082ed6326908dc84ca017ce4430728f18a8a"
|
||||
val jline3Jansi = "org.jline" % "jline-terminal-jansi" % jline3Version
|
||||
val jline3Reader = "org.jline" % "jline-reader" % jline3Version
|
||||
val jansi = "org.fusesource.jansi" % "jansi" % "1.18"
|
||||
val scalatest = "org.scalatest" %% "scalatest" % "3.0.8"
|
||||
val scalacheck = "org.scalacheck" %% "scalacheck" % "1.14.0"
|
||||
|
|
|
|||
|
|
@ -0,0 +1,29 @@
|
|||
/**
|
||||
* This code is generated using [[https://www.scala-sbt.org/contraband/ sbt-contraband]].
|
||||
*/
|
||||
|
||||
// DO NOT EDIT MANUALLY
|
||||
package sbt.protocol
|
||||
final class TerminalGetSizeQuery private () extends sbt.protocol.CommandMessage() with Serializable {
|
||||
|
||||
|
||||
|
||||
override def equals(o: Any): Boolean = o match {
|
||||
case _: TerminalGetSizeQuery => true
|
||||
case _ => false
|
||||
}
|
||||
override def hashCode: Int = {
|
||||
37 * (17 + "sbt.protocol.TerminalGetSizeQuery".##)
|
||||
}
|
||||
override def toString: String = {
|
||||
"TerminalGetSizeQuery()"
|
||||
}
|
||||
private[this] def copy(): TerminalGetSizeQuery = {
|
||||
new TerminalGetSizeQuery()
|
||||
}
|
||||
|
||||
}
|
||||
object TerminalGetSizeQuery {
|
||||
|
||||
def apply(): TerminalGetSizeQuery = new TerminalGetSizeQuery()
|
||||
}
|
||||
36
protocol/src/main/contraband-scala/sbt/protocol/TerminalGetSizeResponse.scala
generated
Normal file
36
protocol/src/main/contraband-scala/sbt/protocol/TerminalGetSizeResponse.scala
generated
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
/**
|
||||
* This code is generated using [[https://www.scala-sbt.org/contraband/ sbt-contraband]].
|
||||
*/
|
||||
|
||||
// DO NOT EDIT MANUALLY
|
||||
package sbt.protocol
|
||||
final class TerminalGetSizeResponse private (
|
||||
val width: Int,
|
||||
val height: Int) extends sbt.protocol.EventMessage() with Serializable {
|
||||
|
||||
|
||||
|
||||
override def equals(o: Any): Boolean = o match {
|
||||
case x: TerminalGetSizeResponse => (this.width == x.width) && (this.height == x.height)
|
||||
case _ => false
|
||||
}
|
||||
override def hashCode: Int = {
|
||||
37 * (37 * (37 * (17 + "sbt.protocol.TerminalGetSizeResponse".##) + width.##) + height.##)
|
||||
}
|
||||
override def toString: String = {
|
||||
"TerminalGetSizeResponse(" + width + ", " + height + ")"
|
||||
}
|
||||
private[this] def copy(width: Int = width, height: Int = height): TerminalGetSizeResponse = {
|
||||
new TerminalGetSizeResponse(width, height)
|
||||
}
|
||||
def withWidth(width: Int): TerminalGetSizeResponse = {
|
||||
copy(width = width)
|
||||
}
|
||||
def withHeight(height: Int): TerminalGetSizeResponse = {
|
||||
copy(height = height)
|
||||
}
|
||||
}
|
||||
object TerminalGetSizeResponse {
|
||||
|
||||
def apply(width: Int, height: Int): TerminalGetSizeResponse = new TerminalGetSizeResponse(width, height)
|
||||
}
|
||||
|
|
@ -6,6 +6,6 @@
|
|||
package sbt.protocol.codec
|
||||
|
||||
import _root_.sjsonnew.JsonFormat
|
||||
trait CommandMessageFormats { self: sjsonnew.BasicJsonProtocol with sbt.protocol.codec.InitCommandFormats with sbt.protocol.codec.ExecCommandFormats with sbt.protocol.codec.SettingQueryFormats with sbt.protocol.codec.AttachFormats with sbt.protocol.codec.TerminalCapabilitiesQueryFormats with sbt.protocol.codec.TerminalSetAttributesCommandFormats with sbt.protocol.codec.TerminalAttributesQueryFormats with sbt.protocol.codec.TerminalSetSizeCommandFormats =>
|
||||
implicit lazy val CommandMessageFormat: JsonFormat[sbt.protocol.CommandMessage] = flatUnionFormat8[sbt.protocol.CommandMessage, sbt.protocol.InitCommand, sbt.protocol.ExecCommand, sbt.protocol.SettingQuery, sbt.protocol.Attach, sbt.protocol.TerminalCapabilitiesQuery, sbt.protocol.TerminalSetAttributesCommand, sbt.protocol.TerminalAttributesQuery, sbt.protocol.TerminalSetSizeCommand]("type")
|
||||
trait CommandMessageFormats { self: sjsonnew.BasicJsonProtocol with sbt.protocol.codec.InitCommandFormats with sbt.protocol.codec.ExecCommandFormats with sbt.protocol.codec.SettingQueryFormats with sbt.protocol.codec.AttachFormats with sbt.protocol.codec.TerminalCapabilitiesQueryFormats with sbt.protocol.codec.TerminalSetAttributesCommandFormats with sbt.protocol.codec.TerminalAttributesQueryFormats with sbt.protocol.codec.TerminalGetSizeQueryFormats with sbt.protocol.codec.TerminalSetSizeCommandFormats =>
|
||||
implicit lazy val CommandMessageFormat: JsonFormat[sbt.protocol.CommandMessage] = flatUnionFormat9[sbt.protocol.CommandMessage, sbt.protocol.InitCommand, sbt.protocol.ExecCommand, sbt.protocol.SettingQuery, sbt.protocol.Attach, sbt.protocol.TerminalCapabilitiesQuery, sbt.protocol.TerminalSetAttributesCommand, sbt.protocol.TerminalAttributesQuery, sbt.protocol.TerminalGetSizeQuery, sbt.protocol.TerminalSetSizeCommand]("type")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,6 @@
|
|||
package sbt.protocol.codec
|
||||
|
||||
import _root_.sjsonnew.JsonFormat
|
||||
trait EventMessageFormats { self: sjsonnew.BasicJsonProtocol with sbt.protocol.codec.ChannelAcceptedEventFormats with sbt.protocol.codec.LogEventFormats with sbt.protocol.codec.ExecStatusEventFormats with sbt.internal.util.codec.JValueFormats with sbt.protocol.codec.SettingQuerySuccessFormats with sbt.protocol.codec.SettingQueryFailureFormats with sbt.protocol.codec.TerminalPropertiesResponseFormats with sbt.protocol.codec.TerminalCapabilitiesResponseFormats with sbt.protocol.codec.TerminalSetAttributesResponseFormats with sbt.protocol.codec.TerminalAttributesResponseFormats with sbt.protocol.codec.TerminalSetSizeResponseFormats =>
|
||||
implicit lazy val EventMessageFormat: JsonFormat[sbt.protocol.EventMessage] = flatUnionFormat10[sbt.protocol.EventMessage, sbt.protocol.ChannelAcceptedEvent, sbt.protocol.LogEvent, sbt.protocol.ExecStatusEvent, sbt.protocol.SettingQuerySuccess, sbt.protocol.SettingQueryFailure, sbt.protocol.TerminalPropertiesResponse, sbt.protocol.TerminalCapabilitiesResponse, sbt.protocol.TerminalSetAttributesResponse, sbt.protocol.TerminalAttributesResponse, sbt.protocol.TerminalSetSizeResponse]("type")
|
||||
trait EventMessageFormats { self: sjsonnew.BasicJsonProtocol with sbt.protocol.codec.ChannelAcceptedEventFormats with sbt.protocol.codec.LogEventFormats with sbt.protocol.codec.ExecStatusEventFormats with sbt.internal.util.codec.JValueFormats with sbt.protocol.codec.SettingQuerySuccessFormats with sbt.protocol.codec.SettingQueryFailureFormats with sbt.protocol.codec.TerminalPropertiesResponseFormats with sbt.protocol.codec.TerminalCapabilitiesResponseFormats with sbt.protocol.codec.TerminalSetAttributesResponseFormats with sbt.protocol.codec.TerminalAttributesResponseFormats with sbt.protocol.codec.TerminalGetSizeResponseFormats with sbt.protocol.codec.TerminalSetSizeResponseFormats =>
|
||||
implicit lazy val EventMessageFormat: JsonFormat[sbt.protocol.EventMessage] = flatUnionFormat11[sbt.protocol.EventMessage, sbt.protocol.ChannelAcceptedEvent, sbt.protocol.LogEvent, sbt.protocol.ExecStatusEvent, sbt.protocol.SettingQuerySuccess, sbt.protocol.SettingQueryFailure, sbt.protocol.TerminalPropertiesResponse, sbt.protocol.TerminalCapabilitiesResponse, sbt.protocol.TerminalSetAttributesResponse, sbt.protocol.TerminalAttributesResponse, sbt.protocol.TerminalGetSizeResponse, sbt.protocol.TerminalSetSizeResponse]("type")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ trait JsonProtocol extends sjsonnew.BasicJsonProtocol
|
|||
with sbt.protocol.codec.TerminalCapabilitiesQueryFormats
|
||||
with sbt.protocol.codec.TerminalSetAttributesCommandFormats
|
||||
with sbt.protocol.codec.TerminalAttributesQueryFormats
|
||||
with sbt.protocol.codec.TerminalGetSizeQueryFormats
|
||||
with sbt.protocol.codec.TerminalSetSizeCommandFormats
|
||||
with sbt.protocol.codec.CommandMessageFormats
|
||||
with sbt.protocol.codec.CompletionParamsFormats
|
||||
|
|
@ -25,6 +26,7 @@ trait JsonProtocol extends sjsonnew.BasicJsonProtocol
|
|||
with sbt.protocol.codec.TerminalCapabilitiesResponseFormats
|
||||
with sbt.protocol.codec.TerminalSetAttributesResponseFormats
|
||||
with sbt.protocol.codec.TerminalAttributesResponseFormats
|
||||
with sbt.protocol.codec.TerminalGetSizeResponseFormats
|
||||
with sbt.protocol.codec.TerminalSetSizeResponseFormats
|
||||
with sbt.protocol.codec.EventMessageFormats
|
||||
with sbt.protocol.codec.SettingQueryResponseFormats
|
||||
|
|
|
|||
27
protocol/src/main/contraband-scala/sbt/protocol/codec/TerminalGetSizeQueryFormats.scala
generated
Normal file
27
protocol/src/main/contraband-scala/sbt/protocol/codec/TerminalGetSizeQueryFormats.scala
generated
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
/**
|
||||
* This code is generated using [[https://www.scala-sbt.org/contraband/ sbt-contraband]].
|
||||
*/
|
||||
|
||||
// DO NOT EDIT MANUALLY
|
||||
package sbt.protocol.codec
|
||||
import _root_.sjsonnew.{ Unbuilder, Builder, JsonFormat, deserializationError }
|
||||
trait TerminalGetSizeQueryFormats { self: sjsonnew.BasicJsonProtocol =>
|
||||
implicit lazy val TerminalGetSizeQueryFormat: JsonFormat[sbt.protocol.TerminalGetSizeQuery] = new JsonFormat[sbt.protocol.TerminalGetSizeQuery] {
|
||||
override def read[J](__jsOpt: Option[J], unbuilder: Unbuilder[J]): sbt.protocol.TerminalGetSizeQuery = {
|
||||
__jsOpt match {
|
||||
case Some(__js) =>
|
||||
unbuilder.beginObject(__js)
|
||||
|
||||
unbuilder.endObject()
|
||||
sbt.protocol.TerminalGetSizeQuery()
|
||||
case None =>
|
||||
deserializationError("Expected JsObject but found None")
|
||||
}
|
||||
}
|
||||
override def write[J](obj: sbt.protocol.TerminalGetSizeQuery, builder: Builder[J]): Unit = {
|
||||
builder.beginObject()
|
||||
|
||||
builder.endObject()
|
||||
}
|
||||
}
|
||||
}
|
||||
29
protocol/src/main/contraband-scala/sbt/protocol/codec/TerminalGetSizeResponseFormats.scala
generated
Normal file
29
protocol/src/main/contraband-scala/sbt/protocol/codec/TerminalGetSizeResponseFormats.scala
generated
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
/**
|
||||
* This code is generated using [[https://www.scala-sbt.org/contraband/ sbt-contraband]].
|
||||
*/
|
||||
|
||||
// DO NOT EDIT MANUALLY
|
||||
package sbt.protocol.codec
|
||||
import _root_.sjsonnew.{ Unbuilder, Builder, JsonFormat, deserializationError }
|
||||
trait TerminalGetSizeResponseFormats { self: sjsonnew.BasicJsonProtocol =>
|
||||
implicit lazy val TerminalGetSizeResponseFormat: JsonFormat[sbt.protocol.TerminalGetSizeResponse] = new JsonFormat[sbt.protocol.TerminalGetSizeResponse] {
|
||||
override def read[J](__jsOpt: Option[J], unbuilder: Unbuilder[J]): sbt.protocol.TerminalGetSizeResponse = {
|
||||
__jsOpt match {
|
||||
case Some(__js) =>
|
||||
unbuilder.beginObject(__js)
|
||||
val width = unbuilder.readField[Int]("width")
|
||||
val height = unbuilder.readField[Int]("height")
|
||||
unbuilder.endObject()
|
||||
sbt.protocol.TerminalGetSizeResponse(width, height)
|
||||
case None =>
|
||||
deserializationError("Expected JsObject but found None")
|
||||
}
|
||||
}
|
||||
override def write[J](obj: sbt.protocol.TerminalGetSizeResponse, builder: Builder[J]): Unit = {
|
||||
builder.beginObject()
|
||||
builder.addField("width", obj.width)
|
||||
builder.addField("height", obj.height)
|
||||
builder.endObject()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -126,6 +126,12 @@ type TerminalAttributesResponse implements EventMessage {
|
|||
cchars: String!,
|
||||
}
|
||||
|
||||
type TerminalGetSizeQuery implements CommandMessage {}
|
||||
type TerminalGetSizeResponse implements EventMessage {
|
||||
width: Int!
|
||||
height: Int!
|
||||
}
|
||||
|
||||
type TerminalSetSizeCommand implements CommandMessage {
|
||||
width: Int!
|
||||
height: Int!
|
||||
|
|
|
|||
|
|
@ -39,7 +39,8 @@ object Serialization {
|
|||
val promptChannel = "sbt/promptChannel"
|
||||
val setTerminalAttributes = "sbt/setTerminalAttributes"
|
||||
val getTerminalAttributes = "sbt/getTerminalAttributes"
|
||||
val setTerminalSize = "sbt/setTerminalSize"
|
||||
val terminalGetSize = "sbt/terminalGetSize"
|
||||
val terminalSetSize = "sbt/terminalSetSize"
|
||||
val CancelAll = "__CancelAll"
|
||||
|
||||
@deprecated("unused", since = "1.4.0")
|
||||
|
|
|
|||
Loading…
Reference in New Issue