Skip to content

Commit cfb967d

Browse files
committed
[jrubyscripting] Fix karaf console command newline
Signed-off-by: Jimmy Tanagra <jcode@tanagra.id.au>
1 parent 8ad3e6b commit cfb967d

File tree

1 file changed

+75
-1
lines changed

1 file changed

+75
-1
lines changed

bundles/org.openhab.automation.jrubyscripting/src/main/java/org/openhab/automation/jrubyscripting/internal/JRubyConsoleCommandExtension.java

Lines changed: 75 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414

1515
import java.io.File;
1616
import java.io.IOException;
17+
import java.io.Writer;
1718
import java.net.URI;
1819
import java.nio.file.Files;
1920
import java.nio.file.Path;
@@ -26,6 +27,7 @@
2627
import java.util.UUID;
2728
import java.util.stream.Stream;
2829

30+
import javax.script.ScriptContext;
2931
import javax.script.ScriptEngine;
3032
import javax.script.ScriptException;
3133

@@ -499,10 +501,21 @@ private void printLoadingMessage(Console console, boolean show) {
499501
}
500502
}
501503

504+
/*
505+
* Configure the engine to redirect output to the provided console.
506+
*/
507+
private void configureEngineConsoleOutput(ScriptEngine engine, @Nullable Console console) {
508+
if (console != null) {
509+
ScriptContext context = engine.getContext();
510+
context.setWriter(new ConsoleWriter(console));
511+
context.setErrorWriter(new ConsoleWriter(console));
512+
}
513+
}
514+
502515
/*
503516
* Create a full openHAB-managed JRuby engine with openHAB scoped variables
504517
* including any injected required gems.
505-
*
518+
*
506519
* This will run the script with the helper library if configured.
507520
*/
508521
private @Nullable Object executeWithFullJRuby(Console console, EngineEvalFunction process) {
@@ -516,6 +529,7 @@ private void printLoadingMessage(Console console, boolean show) {
516529
}
517530
ScriptEngine engine = container.getScriptEngine();
518531
try {
532+
configureEngineConsoleOutput(engine, console);
519533
printLoadingMessage(console, false);
520534
return process.apply(engine);
521535
} catch (ScriptException e) {
@@ -535,6 +549,7 @@ private void printLoadingMessage(Console console, boolean show) {
535549
if (engine == null) {
536550
throw new ScriptException("Unable to create JRuby script engine.");
537551
}
552+
configureEngineConsoleOutput(engine, console);
538553
return process.apply(engine);
539554
} catch (ScriptException e) {
540555
if (console != null) {
@@ -546,6 +561,65 @@ private void printLoadingMessage(Console console, boolean show) {
546561
}
547562
}
548563

564+
// ============================================================================
565+
// Inner Classes
566+
// ============================================================================
567+
568+
/**
569+
* A custom Writer implementation that routes output through the console.
570+
* Properly handles newlines by converting them to console.println calls.
571+
*/
572+
private static class ConsoleWriter extends Writer {
573+
private final Console console;
574+
private final StringBuilder buffer = new StringBuilder();
575+
private boolean closed = false;
576+
577+
ConsoleWriter(Console console) {
578+
this.console = console;
579+
}
580+
581+
@Override
582+
public void write(char @Nullable [] c, int off, int len) throws IOException {
583+
if (closed) {
584+
throw new IOException("Writer is closed");
585+
}
586+
if (c != null) {
587+
buffer.append(c, off, len);
588+
flushBuffer();
589+
}
590+
}
591+
592+
private void flushBuffer() {
593+
String content = buffer.toString();
594+
int lastNewlineIndex = content.lastIndexOf('\n');
595+
596+
if (lastNewlineIndex >= 0) {
597+
// Process all complete lines
598+
String[] lines = content.substring(0, lastNewlineIndex + 1).split("\n", -1);
599+
for (int i = 0; i < lines.length - 1; i++) {
600+
console.println(lines[i]);
601+
}
602+
// Keep any remaining partial line in the buffer
603+
buffer.delete(0, lastNewlineIndex + 1);
604+
}
605+
}
606+
607+
@Override
608+
public void flush() throws IOException {
609+
// Flush any remaining content
610+
if (buffer.length() > 0) {
611+
console.print(buffer.toString());
612+
buffer.delete(0, buffer.length());
613+
}
614+
}
615+
616+
@Override
617+
public void close() throws IOException {
618+
flush();
619+
closed = true;
620+
}
621+
}
622+
549623
@FunctionalInterface
550624
public interface EngineEvalFunction {
551625
@Nullable

0 commit comments

Comments
 (0)