diff --git a/build.sbt b/build.sbt index ccb8e900d..40902658f 100644 --- a/build.sbt +++ b/build.sbt @@ -368,6 +368,7 @@ lazy val utilLogging = (project in file("internal") / "util-logging") Seq( jline, jline3Terminal, + jline3JNA, jline3Jansi, log4jApi, log4jCore, diff --git a/internal/util-logging/src/main/scala/sbt/internal/util/JLine3.scala b/internal/util-logging/src/main/scala/sbt/internal/util/JLine3.scala index 80d93f303..75e189896 100644 --- a/internal/util-logging/src/main/scala/sbt/internal/util/JLine3.scala +++ b/internal/util-logging/src/main/scala/sbt/internal/util/JLine3.scala @@ -12,12 +12,13 @@ import java.nio.charset.Charset import java.util.{ Arrays, EnumSet } import java.util.concurrent.atomic.{ AtomicBoolean, AtomicReference } import org.jline.utils.InfoCmp.Capability -import org.jline.utils.{ ClosedException, NonBlockingReader, OSUtils } +import org.jline.utils.{ ClosedException, NonBlockingReader } import org.jline.terminal.{ Attributes, Size, Terminal => JTerminal } import org.jline.terminal.Terminal.SignalHandler import org.jline.terminal.impl.{ AbstractTerminal, DumbTerminal } import org.jline.terminal.impl.jansi.JansiSupportImpl import org.jline.terminal.impl.jansi.win.JansiWinSysTerminal +import org.jline.utils.OSUtils import scala.collection.JavaConverters._ import scala.util.Try import java.util.concurrent.LinkedBlockingQueue @@ -30,47 +31,36 @@ private[sbt] object JLine3 { } .toMap - private[util] def system = { - /* - * For reasons that are unclear to me, TerminalBuilder fails to build - * windows terminals. The instructions about the classpath did not work: - * https://stackoverflow.com/questions/52851232/jline3-issues-with-windows-terminal - * We can deconstruct what TerminalBuilder does and inline it for now. - * It is possible that this workaround will break WSL but I haven't checked that. - */ - if (Util.isNonCygwinWindows) { - val support = new JansiSupportImpl - val winConsole = support.isWindowsConsole(); - try { - val term = JansiWinSysTerminal.createTerminal( - "console", - "ansi", - OSUtils.IS_CONEMU, - Charset.forName("UTF-8"), - -1, - false, - SignalHandler.SIG_DFL, - true - ) - term.disableScrolling() - term - } catch { - case _: Exception => - org.jline.terminal.TerminalBuilder - .builder() - .system(false) - .paused(true) - .jansi(true) - .streams(Terminal.console.inputStream, Terminal.console.outputStream) - .build() - } - } else { + private[this] val forceWindowsJansiHolder = new AtomicBoolean(false) + private[sbt] def forceWindowsJansi(): Unit = forceWindowsJansiHolder.set(true) + private[this] def windowsJansi(): org.jline.terminal.Terminal = { + val support = new JansiSupportImpl + val winConsole = support.isWindowsConsole(); + val termType = sys.props.get("org.jline.terminal.type").orElse(sys.env.get("TERM")).orNull + val term = JansiWinSysTerminal.createTerminal( + "console", + termType, + OSUtils.IS_CONEMU, + Charset.forName("UTF-8"), + -1, + false, + SignalHandler.SIG_DFL, + true + ) + term.disableScrolling() + term + } + private[util] def system: org.jline.terminal.Terminal = { + if (forceWindowsJansiHolder.get) windowsJansi() + else { + // Only use jna on windows. Both jna and jansi use illegal reflective + // accesses on posix system. org.jline.terminal.TerminalBuilder .builder() .system(System.console != null) + .jna(Util.isNonCygwinWindows) + .jansi(false) .paused(true) - .jna(false) - .jansi(true) .build() } } diff --git a/main/src/main/java/sbt/internal/MetaBuildLoader.java b/main/src/main/java/sbt/internal/MetaBuildLoader.java index 2ca2a5088..08a80aa24 100644 --- a/main/src/main/java/sbt/internal/MetaBuildLoader.java +++ b/main/src/main/java/sbt/internal/MetaBuildLoader.java @@ -64,12 +64,13 @@ public final class MetaBuildLoader extends URLClassLoader { * library. */ public static MetaBuildLoader makeLoader(final AppProvider appProvider) throws IOException { - final Pattern pattern = - Pattern.compile( - "^(test-interface-[0-9.]+|jline-(terminal-)?[0-9.]+-sbt-.*|jansi-[0-9.]+)\\.jar"); + final String jlineJars = "jline-(terminal-)?[0-9.]+-sbt-.*|jline-terminal-(jna|jansi)-[0-9.]+"; + final String fullPattern = + "^(test-interface-[0-9.]+|" + jlineJars + "|jansi-[0-9.]+|jna-(platform-)?[0-9.]+)\\.jar"; + final Pattern pattern = Pattern.compile(fullPattern); final File[] cp = appProvider.mainClasspath(); final URL[] interfaceURLs = new URL[1]; - final URL[] jlineURLs = new URL[3]; + final URL[] jlineURLs = new URL[7]; final File[] extra = appProvider.id().classpathExtra() == null ? new File[0] : appProvider.id().classpathExtra(); final Set bottomClasspath = new LinkedHashSet<>();