blob: b88421827f61a05795e60150cb487336c115ac84 [file] [log] [blame]
/*
* 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.karaf.shell.impl.console;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.nio.charset.Charset;
import java.util.EnumSet;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.function.IntConsumer;
import java.util.function.IntSupplier;
import org.apache.karaf.shell.api.console.SignalListener;
import org.apache.karaf.shell.api.console.Terminal;
import org.jline.terminal.Attributes;
import org.jline.terminal.Cursor;
import org.jline.terminal.MouseEvent;
import org.jline.terminal.Size;
import org.jline.utils.ColorPalette;
import org.jline.utils.InfoCmp.Capability;
import org.jline.utils.NonBlockingReader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class JLineTerminal implements Terminal, org.jline.terminal.Terminal {
private final org.jline.terminal.Terminal terminal;
private final ConcurrentMap<Signal, Set<SignalListener>> listeners = new ConcurrentHashMap<>();
private final ConcurrentMap<Signal, SignalHandler> handlers = new ConcurrentHashMap<>();
private static final Logger LOGGER = LoggerFactory.getLogger(JLineTerminal.class);
public JLineTerminal(org.jline.terminal.Terminal terminal) {
this.terminal = terminal;
for (Signal signal : Signal.values()) {
terminal.handle(signal, this::handle);
handlers.put(signal, SignalHandler.SIG_DFL);
}
}
@Override
public String getType() {
return terminal.getType();
}
@Override
public boolean puts(Capability capability, Object... params) {
return terminal.puts(capability, params);
}
@Override
public boolean getBooleanCapability(Capability capability) {
return terminal.getBooleanCapability(capability);
}
@Override
public Integer getNumericCapability(Capability capability) {
return terminal.getNumericCapability(capability);
}
@Override
public String getStringCapability(Capability capability) {
return terminal.getStringCapability(capability);
}
@Override
public int getWidth() {
return terminal.getWidth();
}
@Override
public int getHeight() {
return terminal.getHeight();
}
@Override
public void flush() {
terminal.flush();
}
@Override
public boolean isAnsiSupported() {
return true;
}
@Override
public boolean isEchoEnabled() {
return terminal.echo();
}
@Override
public void setEchoEnabled(boolean enabled) {
terminal.echo(enabled);
}
@Override
public void close() throws IOException {
terminal.close();
}
@Override
public String getName() {
return terminal.getName();
}
@Override
public NonBlockingReader reader() {
return terminal.reader();
}
@Override
public PrintWriter writer() {
return terminal.writer();
}
@Override
public Charset encoding() {
return terminal.encoding();
}
@Override
public InputStream input() {
return terminal.input();
}
@Override
public OutputStream output() {
return terminal.output();
}
@Override
public Attributes enterRawMode() {
return terminal.enterRawMode();
}
@Override
public boolean echo() {
return terminal.echo();
}
@Override
public boolean echo(boolean echo) {
return terminal.echo(echo);
}
@Override
public Attributes getAttributes() {
return terminal.getAttributes();
}
@Override
public void setAttributes(Attributes attr) {
terminal.setAttributes(attr);
}
@Override
public Size getSize() {
return terminal.getSize();
}
@Override
public void setSize(Size size) {
terminal.setSize(size);
}
@Override
public void raise(Signal signal) {
terminal.raise(signal);
}
@Override
public SignalHandler handle(Signal signal, SignalHandler handler) {
Objects.requireNonNull(signal);
Objects.requireNonNull(handler);
return handlers.put(signal, handler);
}
@Override
public void addSignalListener(SignalListener listener) {
addSignalListener(listener, EnumSet.allOf(org.apache.karaf.shell.api.console.Signal.class));
}
@Override
public void addSignalListener(SignalListener listener, org.apache.karaf.shell.api.console.Signal... signals) {
for (org.apache.karaf.shell.api.console.Signal sig : signals) {
addSignalListener(listener, sig);
}
}
@Override
public void addSignalListener(SignalListener listener, EnumSet<org.apache.karaf.shell.api.console.Signal> signals) {
for (org.apache.karaf.shell.api.console.Signal sig : signals) {
addSignalListener(listener, sig);
}
}
private void addSignalListener(SignalListener listener, org.apache.karaf.shell.api.console.Signal signal) {
Set<SignalListener> ls = listeners.compute(signal(signal), (s, l) -> l != null ? l : new CopyOnWriteArraySet<>());
ls.add(listener);
}
@Override
public void removeSignalListener(SignalListener listener) {
for (Signal signal : Signal.values()) {
Set<SignalListener> ls = listeners.get(signal);
if (ls != null) {
ls.remove(listener);
}
}
}
@Override
public Cursor getCursorPosition(IntConsumer discarded) {
return terminal.getCursorPosition(discarded);
}
@Override
public boolean hasMouseSupport() {
return terminal.hasMouseSupport();
}
@Override
public boolean trackMouse(MouseTracking tracking) {
return terminal.trackMouse(tracking);
}
@Override
public MouseEvent readMouseEvent() {
return terminal.readMouseEvent();
}
@Override
public MouseEvent readMouseEvent(IntSupplier supplier) {
return terminal.readMouseEvent(supplier);
}
private Signal signal(org.apache.karaf.shell.api.console.Signal sig) {
switch (sig) {
case INT:
return Signal.INT;
case QUIT:
return Signal.QUIT;
case TSTP:
return Signal.TSTP;
case CONT:
return Signal.CONT;
case WINCH:
return Signal.WINCH;
}
throw new UnsupportedOperationException();
}
private org.apache.karaf.shell.api.console.Signal signal(Signal sig) {
switch (sig) {
case INT:
return org.apache.karaf.shell.api.console.Signal.INT;
case QUIT:
return org.apache.karaf.shell.api.console.Signal.QUIT;
case TSTP:
return org.apache.karaf.shell.api.console.Signal.TSTP;
case CONT:
return org.apache.karaf.shell.api.console.Signal.CONT;
case WINCH:
return org.apache.karaf.shell.api.console.Signal.WINCH;
}
throw new UnsupportedOperationException();
}
protected void handle(Signal signal) {
SignalHandler handler = handlers.get(signal);
if (handler != SignalHandler.SIG_DFL && handler != SignalHandler.SIG_IGN) {
try {
handler.handle(signal);
} catch (UnsupportedOperationException uoe) {
LOGGER.debug("unsupported operation", uoe);
}
}
Set<SignalListener> sl = listeners.get(signal);
if (sl != null) {
for (SignalListener l : sl) {
l.signal(signal(signal));
}
}
}
@Override
public boolean canPauseResume() {
return terminal.canPauseResume();
}
@Override
public void pause() {
terminal.pause();
}
@Override
public void pause(boolean wait) throws InterruptedException {
terminal.pause(wait);
}
@Override
public void resume() {
terminal.resume();
}
@Override
public boolean paused() {
return terminal.paused();
}
@Override
public boolean hasFocusSupport() {
return terminal.hasFocusSupport();
}
@Override
public boolean trackFocus(boolean tracking) {
return terminal.trackFocus(tracking);
}
@Override
public Size getBufferSize() {
return terminal.getBufferSize();
}
@Override
public ColorPalette getPalette() {
return terminal.getPalette();
}
}