Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
package org.apache.camel.dsl.jbang.core.commands;

import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
Expand All @@ -26,6 +27,7 @@
import org.apache.camel.dsl.jbang.core.common.EnvironmentHelper;
import org.apache.camel.dsl.jbang.core.common.PathUtils;
import org.apache.camel.dsl.jbang.core.common.Printer;
import org.jline.terminal.Terminal;

public final class CommandHelper {

Expand Down Expand Up @@ -93,8 +95,10 @@ public static boolean confirmOperation(String message, boolean yes) {
System.out.print(message + " [y/N] ");
System.out.flush();
try {
// Do not use try-with-resources here: closing the Scanner would close System.in
Scanner scanner = new Scanner(System.in);
Terminal terminal = EnvironmentHelper.getActiveTerminal();
InputStream input = terminal != null ? terminal.input() : System.in;
// Do not use try-with-resources here: closing the Scanner would close the input stream
Scanner scanner = new Scanner(input);
String answer = scanner.nextLine().trim().toLowerCase();
return "y".equals(answer) || "yes".equals(answer);
} catch (Exception e) {
Expand All @@ -116,8 +120,8 @@ public ReadConsoleTask(Runnable listener) {

@Override
public void run() {
if (System.console() != null) {
System.console().readLine();
String line = EnvironmentHelper.readLine();
if (line != null) {
listener.run();
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
package org.apache.camel.dsl.jbang.core.commands;

import java.io.BufferedReader;
import java.io.Console;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
Expand All @@ -41,6 +40,7 @@
import org.apache.camel.dsl.jbang.core.commands.action.MessageTableHelper;
import org.apache.camel.dsl.jbang.core.common.CamelCommandHelper;
import org.apache.camel.dsl.jbang.core.common.CommandLineHelper;
import org.apache.camel.dsl.jbang.core.common.EnvironmentHelper;
import org.apache.camel.dsl.jbang.core.common.PathUtils;
import org.apache.camel.dsl.jbang.core.common.ProcessHelper;
import org.apache.camel.dsl.jbang.core.common.VersionHelper;
Expand Down Expand Up @@ -187,7 +187,6 @@ public Integer doCall() throws Exception {

// read log input
final AtomicBoolean quit = new AtomicBoolean();
final Console c = System.console();
if (logLines > 0) {
Thread t = new Thread(() -> {
doReadLog(quit);
Expand All @@ -196,7 +195,7 @@ public Integer doCall() throws Exception {
}

// read CLI input from user
Thread t2 = new Thread(() -> doRead(c, quit), "ReadCommand");
Thread t2 = new Thread(() -> doRead(quit), "ReadCommand");
t2.start();

do {
Expand Down Expand Up @@ -285,9 +284,9 @@ private void doReadLog(AtomicBoolean quit) {
} while (!quit.get());
}

private void doRead(Console c, AtomicBoolean quit) {
private void doRead(AtomicBoolean quit) {
do {
String line = c.readLine();
String line = EnvironmentHelper.readLine();
if (line != null) {
line = line.trim();
if ("q".equalsIgnoreCase(line) || "quit".equalsIgnoreCase(line) || "exit".equalsIgnoreCase(line)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
import org.apache.camel.CamelContext;
import org.apache.camel.dsl.jbang.core.commands.catalog.KameletCatalogHelper;
import org.apache.camel.dsl.jbang.core.common.CommandLineHelper;
import org.apache.camel.dsl.jbang.core.common.EnvironmentHelper;
import org.apache.camel.dsl.jbang.core.common.ResourceDoesNotExist;
import org.apache.camel.dsl.jbang.core.common.VersionHelper;
import org.apache.camel.github.GistResourceResolver;
Expand All @@ -43,6 +44,7 @@
import org.apache.camel.util.FileUtil;
import org.apache.camel.util.IOHelper;
import org.apache.commons.io.IOUtils;
import org.jline.terminal.Terminal;
import picocli.CommandLine.Command;
import picocli.CommandLine.Option;
import picocli.CommandLine.Parameters;
Expand Down Expand Up @@ -106,7 +108,7 @@ public Integer doCall() throws Exception {
}
if (file == null) {
// try interactive picker if running in a TTY and not in CI
if (System.console() != null && System.getenv("CI") == null) {
if (EnvironmentHelper.isInteractiveTerminal()) {
return interactivePicker();
}
printer().printErr("Missing required parameter: <file>");
Expand Down Expand Up @@ -309,7 +311,9 @@ private int interactivePicker() throws Exception {
pipeTemplates.add(new String[] { "init-pipe.yaml", "Pipe CR (source to sink)", ".yaml" });
categories.put("Pipes and CRs", pipeTemplates);

Scanner scanner = new Scanner(System.in);
Terminal activeTerminal = EnvironmentHelper.getActiveTerminal();
InputStream scannerInput = activeTerminal != null ? activeTerminal.input() : System.in;
Scanner scanner = new Scanner(scannerInput);

// Step 1: Pick a category
printer().println("Select a template category:");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,8 +99,11 @@ public Integer doCall() throws Exception {
}

try (org.jline.shell.Shell shell = builder.build()) {
EnvironmentHelper.setActiveTerminal(shell.terminal());
printBanner(shell, camelVersion, colorEnabled);
shell.run();
} finally {
EnvironmentHelper.setActiveTerminal(null);
}
return 0;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
*/
package org.apache.camel.dsl.jbang.core.commands.infra;

import java.io.Console;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Method;
Expand All @@ -32,6 +31,7 @@

import org.apache.camel.dsl.jbang.core.commands.CamelJBangMain;
import org.apache.camel.dsl.jbang.core.common.CommandLineHelper;
import org.apache.camel.dsl.jbang.core.common.EnvironmentHelper;
import org.apache.camel.dsl.jbang.core.common.Printer;
import org.apache.camel.dsl.jbang.core.common.RuntimeUtil;
import org.apache.camel.main.download.DependencyDownloaderClassLoader;
Expand Down Expand Up @@ -226,15 +226,14 @@ protected Integer doRun(String testService, String testServiceImplementation, Te
final CountDownLatch latch = new CountDownLatch(1);

// running in foreground then wait for user to exit
final Console c = System.console();
if (c != null) {
if (EnvironmentHelper.isInteractiveTerminal()) {
if (!jsonOutput) {
printer().println("Press ENTER to stop the execution");
}
Thread t = new Thread(() -> {
boolean quit = false;
do {
String line = c.readLine();
String line = EnvironmentHelper.readLine();
if (line != null) {
quit = true;
latch.countDown();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,13 @@
*/
package org.apache.camel.dsl.jbang.core.common;

import java.io.BufferedReader;
import java.io.Console;
import java.io.IOException;
import java.io.InputStreamReader;

import org.jline.terminal.Terminal;

/**
* Helper for detecting environment characteristics such as CI environments, color support, and interactive terminals.
*
Expand All @@ -32,9 +39,45 @@
*/
public final class EnvironmentHelper {

private static volatile Terminal activeTerminal;

private EnvironmentHelper() {
}

/**
* Sets the active JLine terminal. Called by the shell command to make the terminal available to subcommands.
*/
public static void setActiveTerminal(Terminal terminal) {
activeTerminal = terminal;
}

/**
* Returns the active JLine terminal, or null if not running inside the shell.
*/
public static Terminal getActiveTerminal() {
return activeTerminal;
}

/**
* Reads a single line from the best available input source: the active JLine terminal if inside the shell,
* otherwise {@link System#console()}.
*
* @return the line read, or null if no input source is available or an error occurs
*/
public static String readLine() {
Terminal terminal = activeTerminal;
if (terminal != null) {
try {
BufferedReader reader = new BufferedReader(new InputStreamReader(terminal.input()));
return reader.readLine();
} catch (IOException e) {
return null;
}
}
Console c = System.console();
return c != null ? c.readLine() : null;
}

/**
* Determines whether colored output should be enabled based on environment variables and terminal capabilities.
*
Expand All @@ -59,7 +102,7 @@ public static boolean isColorEnabled() {
if (getEnv("FORCE_COLOR") != null) {
return true;
}
return System.console() != null;
return activeTerminal != null || System.console() != null;
}

/**
Expand All @@ -80,7 +123,7 @@ public static boolean isCIEnvironment() {
* @return true if the terminal supports interactive prompts
*/
public static boolean isInteractiveTerminal() {
return System.console() != null && !isCIEnvironment();
return (activeTerminal != null || System.console() != null) && !isCIEnvironment();
}

// Visible for testing - allows overriding in tests
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ public Integer doCall() throws Exception {

loadCatalog();

try (var tui = TuiRunner.create()) {
try (var tui = TuiBackendHelper.createTuiRunner()) {
Signal.handle(new Signal("INT"), sig -> tui.quit());
tui.run(this::handleEvent, this::render);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -281,7 +281,7 @@ public Integer doCall() throws Exception {
// Initial data load (synchronous before TUI starts)
refreshDataSync();

try (var tui = TuiRunner.create()) {
try (var tui = TuiBackendHelper.createTuiRunner()) {
this.runner = tui;
ctx.runner = tui;
// Intercept Ctrl+C: quit the TUI cleanly instead of letting
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.camel.dsl.jbang.core.commands.tui;

import java.lang.reflect.Constructor;

import dev.tamboui.backend.jline3.JLineBackend;
import dev.tamboui.terminal.Backend;
import dev.tamboui.tui.TuiConfig;
import dev.tamboui.tui.TuiRunner;
import org.apache.camel.dsl.jbang.core.common.EnvironmentHelper;
import org.jline.terminal.Terminal;

final class TuiBackendHelper {

private TuiBackendHelper() {
}

static TuiRunner createTuiRunner() throws Exception {
Terminal activeTerminal = EnvironmentHelper.getActiveTerminal();
if (activeTerminal != null) {
Backend backend = createBackendForTerminal(activeTerminal);
if (backend != null) {
return TuiRunner.create(TuiConfig.builder().backend(backend).build());
}
}
return TuiRunner.create();
}

private static Backend createBackendForTerminal(Terminal terminal) {
try {
Constructor<JLineBackend> ctor = JLineBackend.class.getDeclaredConstructor(Terminal.class);
return ctor.newInstance(terminal);
} catch (NoSuchMethodException e) {
// JLineBackend(Terminal) not available in this version, fall back
return null;
} catch (Exception e) {
return null;
}
}
}