You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@karaf.apache.org by gn...@apache.org on 2017/03/24 07:46:18 UTC
[2/4] karaf git commit: [KARAF-5058] Use ttop implementation from
JLine
[KARAF-5058] Use ttop implementation from JLine
Project: http://git-wip-us.apache.org/repos/asf/karaf/repo
Commit: http://git-wip-us.apache.org/repos/asf/karaf/commit/f1a3f389
Tree: http://git-wip-us.apache.org/repos/asf/karaf/tree/f1a3f389
Diff: http://git-wip-us.apache.org/repos/asf/karaf/diff/f1a3f389
Branch: refs/heads/master
Commit: f1a3f389b24ece39f9b98a9da9dc327fbc030732
Parents: 21f5dde
Author: Guillaume Nodet <gn...@apache.org>
Authored: Fri Mar 24 08:21:49 2017 +0100
Committer: Guillaume Nodet <gn...@apache.org>
Committed: Fri Mar 24 08:46:01 2017 +0100
----------------------------------------------------------------------
.../karaf/shell/commands/impl/TTopAction.java | 2 +-
.../karaf/shell/commands/impl/top/TTop.java | 593 -------------------
2 files changed, 1 insertion(+), 594 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/karaf/blob/f1a3f389/shell/commands/src/main/java/org/apache/karaf/shell/commands/impl/TTopAction.java
----------------------------------------------------------------------
diff --git a/shell/commands/src/main/java/org/apache/karaf/shell/commands/impl/TTopAction.java b/shell/commands/src/main/java/org/apache/karaf/shell/commands/impl/TTopAction.java
index 4790c6c..3da38ce 100644
--- a/shell/commands/src/main/java/org/apache/karaf/shell/commands/impl/TTopAction.java
+++ b/shell/commands/src/main/java/org/apache/karaf/shell/commands/impl/TTopAction.java
@@ -22,7 +22,7 @@ import org.apache.karaf.shell.api.action.Option;
import org.apache.karaf.shell.api.action.lifecycle.Reference;
import org.apache.karaf.shell.api.action.lifecycle.Service;
import org.apache.karaf.shell.api.console.Session;
-import org.apache.karaf.shell.commands.impl.top.TTop;
+import org.jline.builtins.TTop;
import org.jline.terminal.Terminal;
import java.util.Arrays;
http://git-wip-us.apache.org/repos/asf/karaf/blob/f1a3f389/shell/commands/src/main/java/org/apache/karaf/shell/commands/impl/top/TTop.java
----------------------------------------------------------------------
diff --git a/shell/commands/src/main/java/org/apache/karaf/shell/commands/impl/top/TTop.java b/shell/commands/src/main/java/org/apache/karaf/shell/commands/impl/top/TTop.java
deleted file mode 100644
index f3ba964..0000000
--- a/shell/commands/src/main/java/org/apache/karaf/shell/commands/impl/top/TTop.java
+++ /dev/null
@@ -1,593 +0,0 @@
-/*
- * 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.commands.impl.top;
-
-import org.jline.keymap.BindingReader;
-import org.jline.keymap.KeyMap;
-import org.jline.terminal.Attributes;
-import org.jline.terminal.Size;
-import org.jline.terminal.Terminal;
-import org.jline.utils.*;
-
-import java.io.IOException;
-import java.lang.management.*;
-import java.text.DecimalFormat;
-import java.text.DecimalFormatSymbols;
-import java.util.*;
-import java.util.function.Function;
-import java.util.stream.Collectors;
-
-import static org.apache.karaf.shell.commands.impl.top.TTop.Align.Left;
-import static org.apache.karaf.shell.commands.impl.top.TTop.Align.Right;
-
-/**
- * Thread Top implementation based on jline.
- *
- * TODO: option modification at runtime (such as implemented in less) is not currently supported
- * TODO: one possible addition would be to detect deadlock threads and display them in a specific way
- */
-public class TTop {
-
- public static final String STAT_UPTIME = "uptime";
-
- public static final String STAT_TID = "tid";
- public static final String STAT_NAME = "name";
- public static final String STAT_STATE = "state";
- public static final String STAT_BLOCKED_TIME = "blocked_time";
- public static final String STAT_BLOCKED_COUNT = "blocked_count";
- public static final String STAT_WAITED_TIME = "waited_time";
- public static final String STAT_WAITED_COUNT = "waited_count";
- public static final String STAT_LOCK_NAME = "lock_name";
- public static final String STAT_LOCK_OWNER_ID = "lock_owner_id";
- public static final String STAT_LOCK_OWNER_NAME = "lock_owner_name";
- public static final String STAT_USER_TIME = "user_time";
- public static final String STAT_USER_TIME_PERC = "user_time_perc";
- public static final String STAT_CPU_TIME = "cpu_time";
- public static final String STAT_CPU_TIME_PERC = "cpu_time_perc";
-
- public List<String> sort;
- public long delay;
- public List<String> stats;
- public int nthreads;
-
- public enum Align {
- Left, Right
- };
-
- public enum Operation {
- INCREASE_DELAY,
- DECREASE_DELAY,
- HELP,
- EXIT,
- CLEAR,
- REVERSE
- }
-
- private final Map<String, Column> columns = new LinkedHashMap<>();
- private final Terminal terminal;
- private final Display display;
- private final BindingReader bindingReader;
- private final KeyMap<Operation> keys;
- private final Size size = new Size();
-
- private Comparator<Map<String, Comparable>> comparator;
-
- // Internal cache data
- private Map<Long, Map<String, Object>> previous = new HashMap<>();
- private Map<Long, Map<String, Long>> changes = new HashMap<>();
- private Map<String, Integer> widths = new HashMap<>();
-
-
- public TTop(Terminal terminal) {
- this.terminal = terminal;
- this.display = new Display(terminal, true);
- this.bindingReader = new BindingReader(terminal.reader());
-
- DecimalFormatSymbols dfs = new DecimalFormatSymbols();
- dfs.setDecimalSeparator('.');
- DecimalFormat perc = new DecimalFormat("0.00%", dfs);
-
- register(STAT_TID, Right, "TID", o -> String.format("%3d", (Long) o));
- register(STAT_NAME, Left, "NAME", padcut(40));
- register(STAT_STATE, Left, "STATE", o -> o.toString().toLowerCase());
- register(STAT_BLOCKED_TIME, Right, "T-BLOCKED", o -> millis((Long) o));
- register(STAT_BLOCKED_COUNT, Right, "#-BLOCKED", Object::toString);
- register(STAT_WAITED_TIME, Right, "T-WAITED", o -> millis((Long) o));
- register(STAT_WAITED_COUNT, Right, "#-WAITED", Object::toString);
- register(STAT_LOCK_NAME, Left, "LOCK-NAME", Object::toString);
- register(STAT_LOCK_OWNER_ID, Right, "LOCK-OWNER-ID", id -> ((Long) id) >= 0 ? id.toString() : "");
- register(STAT_LOCK_OWNER_NAME, Left, "LOCK-OWNER-NAME", name -> name != null ? name.toString() : "");
- register(STAT_USER_TIME, Right, "T-USR", o -> nanos((Long) o));
- register(STAT_CPU_TIME, Right, "T-CPU", o -> nanos((Long) o));
- register(STAT_USER_TIME_PERC, Right, "%-USR", perc::format);
- register(STAT_CPU_TIME_PERC, Right, "%-CPU", perc::format);
-
- keys = new KeyMap<>();
- bindKeys(keys);
- }
-
- public KeyMap<Operation> getKeys() {
- return keys;
- }
-
- public void run() throws IOException, InterruptedException {
- comparator = buildComparator(sort);
- delay = delay > 0 ? Math.max(delay, 100) : 1000;
- if (stats == null || stats.isEmpty()) {
- stats = Arrays.asList(STAT_TID, STAT_NAME, STAT_STATE, STAT_CPU_TIME, STAT_LOCK_OWNER_ID);
- }
-
- Boolean isThreadContentionMonitoringEnabled = null;
- ThreadMXBean threadsBean = ManagementFactory.getThreadMXBean();
- if (stats.contains(STAT_BLOCKED_TIME)
- || stats.contains(STAT_BLOCKED_COUNT)
- || stats.contains(STAT_WAITED_TIME)
- || stats.contains(STAT_WAITED_COUNT)) {
- if (threadsBean.isThreadContentionMonitoringSupported()) {
- isThreadContentionMonitoringEnabled = threadsBean.isThreadContentionMonitoringEnabled();
- if (!isThreadContentionMonitoringEnabled) {
- threadsBean.setThreadContentionMonitoringEnabled(true);
- }
- } else {
- stats.removeAll(Arrays.asList(STAT_BLOCKED_TIME, STAT_BLOCKED_COUNT, STAT_WAITED_TIME, STAT_WAITED_COUNT));
- }
- }
- Boolean isThreadCpuTimeEnabled = null;
- if (stats.contains(STAT_USER_TIME) || stats.contains(STAT_CPU_TIME)) {
- if (threadsBean.isThreadCpuTimeSupported()) {
- isThreadCpuTimeEnabled = threadsBean.isThreadCpuTimeEnabled();
- if (!isThreadCpuTimeEnabled) {
- threadsBean.setThreadCpuTimeEnabled(true);
- }
- } else {
- stats.removeAll(Arrays.asList(STAT_USER_TIME, STAT_CPU_TIME));
- }
- }
-
- size.copy(terminal.getSize());
- Terminal.SignalHandler prevHandler = terminal.handle(Terminal.Signal.WINCH, this::handle);
- Attributes attr = terminal.enterRawMode();
- try {
-
- // Use alternate buffer
- terminal.puts(InfoCmp.Capability.enter_ca_mode);
- terminal.puts(InfoCmp.Capability.keypad_xmit);
- terminal.puts(InfoCmp.Capability.cursor_invisible);
- terminal.writer().flush();
-
- long t0 = System.currentTimeMillis();
-
- Operation op;
- do {
- display();
- checkInterrupted();
-
- op = null;
-
- long delta = ((System.currentTimeMillis() - t0) / delay + 1) * delay + t0 - System.currentTimeMillis();
- int ch = bindingReader.peekCharacter(delta);
- if (ch == -1) {
- op = Operation.EXIT;
- } else if (ch != NonBlockingReader.READ_EXPIRED) {
- op = bindingReader.readBinding(keys, null, false);
- }
- if (op == null) {
- continue;
- }
-
- switch (op) {
- case INCREASE_DELAY:
- delay = delay * 2;
- t0 = System.currentTimeMillis();
- break;
- case DECREASE_DELAY:
- delay = Math.max(delay / 2, 16);
- t0 = System.currentTimeMillis();
- break;
- case CLEAR:
- display.clear();
- break;
- case REVERSE:
- comparator = comparator.reversed();
- break;
- }
- } while (op != Operation.EXIT);
- } catch (InterruptedException ie) {
- // Do nothing
- } finally {
- terminal.setAttributes(attr);
- if (prevHandler != null) {
- terminal.handle(Terminal.Signal.WINCH, prevHandler);
- }
- // Use main buffer
- terminal.puts(InfoCmp.Capability.exit_ca_mode);
- terminal.puts(InfoCmp.Capability.keypad_local);
- terminal.puts(InfoCmp.Capability.cursor_visible);
- terminal.writer().flush();
-
- if (isThreadContentionMonitoringEnabled != null) {
- threadsBean.setThreadContentionMonitoringEnabled(isThreadContentionMonitoringEnabled);
- }
- if (isThreadCpuTimeEnabled != null) {
- threadsBean.setThreadCpuTimeEnabled(isThreadCpuTimeEnabled);
- }
- }
- }
-
- private void handle(Terminal.Signal signal) {
- int prevw = size.getColumns();
- size.copy(terminal.getSize());
- try {
- if (size.getColumns() < prevw) {
- display.clear();
- }
- display();
- } catch (IOException e) {
- // ignore
- }
- }
-
- private List<Map<String, Comparable>> infos() {
- long ctime = ManagementFactory.getRuntimeMXBean().getUptime();
- Long ptime = (Long) previous.computeIfAbsent(-1L, id -> new HashMap<>()).put(STAT_UPTIME, ctime);
- long delta = ptime != null ? ctime - ptime : 0L;
-
- ThreadMXBean threadsBean = ManagementFactory.getThreadMXBean();
- ThreadInfo[] infos = threadsBean.dumpAllThreads(false, false);
- List<Map<String, Comparable>> threads = new ArrayList<>();
- for (ThreadInfo ti : infos) {
- Map<String, Comparable> t = new HashMap<>();
- t.put(STAT_TID, ti.getThreadId());
- t.put(STAT_NAME, ti.getThreadName());
- t.put(STAT_STATE, ti.getThreadState());
- if (threadsBean.isThreadContentionMonitoringEnabled()) {
- t.put(STAT_BLOCKED_TIME, ti.getBlockedTime());
- t.put(STAT_BLOCKED_COUNT, ti.getBlockedCount());
- t.put(STAT_WAITED_TIME, ti.getWaitedTime());
- t.put(STAT_WAITED_COUNT, ti.getWaitedCount());
- }
- t.put(STAT_LOCK_NAME, ti.getLockName());
- t.put(STAT_LOCK_OWNER_ID, ti.getLockOwnerId());
- t.put(STAT_LOCK_OWNER_NAME, ti.getLockOwnerName());
- if (threadsBean.isThreadCpuTimeSupported() && threadsBean.isThreadCpuTimeEnabled()) {
- long tid = ti.getThreadId(), t0, t1;
- // Cpu
- t1 = threadsBean.getThreadCpuTime(tid);
- t0 = (Long) previous.computeIfAbsent(tid, id -> new HashMap<>()).getOrDefault(STAT_CPU_TIME, t1);
- t.put(STAT_CPU_TIME, t1);
- t.put(STAT_CPU_TIME_PERC, (delta != 0) ? (t1 - t0) / ((double) delta * 1000000) : 0.0d);
- // User
- t1 = threadsBean.getThreadUserTime(tid);
- t0 = (Long) previous.computeIfAbsent(tid, id -> new HashMap<>()).getOrDefault(STAT_USER_TIME, t1);
- t.put(STAT_USER_TIME, t1);
- t.put(STAT_USER_TIME_PERC, (delta != 0) ? (t1 - t0) / ((double) delta * 1000000) : 0.0d);
- }
- threads.add(t);
- }
- return threads;
- }
-
- private void align(AttributedStringBuilder sb, String val, int width, Align align) {
- if (align == Align.Left) {
- sb.append(val);
- for (int i = 0; i < width - val.length(); i++) {
- sb.append(' ');
- }
- } else {
- for (int i = 0; i < width - val.length(); i++) {
- sb.append(' ');
- }
- sb.append(val);
- }
- }
-
- private void display() throws IOException {
- long now = System.currentTimeMillis();
-
- display.resize(size.getRows(), size.getColumns());
-
- List<AttributedString> lines = new ArrayList<>();
- AttributedStringBuilder sb = new AttributedStringBuilder(size.getColumns());
-
- // Top headers
- sb.style(sb.style().bold());
- sb.append("ttop");
- sb.style(sb.style().boldOff());
- sb.append(" - ");
- sb.append(String.format("%8tT", new Date()));
- sb.append(".");
-
-
- OperatingSystemMXBean os = ManagementFactory.getOperatingSystemMXBean();
- String osinfo = "OS: " + os.getName() + " " + os.getVersion() + ", " + os.getArch() + ", " + os.getAvailableProcessors() + " cpus.";
- if (sb.length() + 1 + osinfo.length() < size.getColumns()) {
- sb.append(" ");
- } else {
- lines.add(sb.toAttributedString());
- sb.setLength(0);
- }
- sb.append(osinfo);
-
- ClassLoadingMXBean cl = ManagementFactory.getClassLoadingMXBean();
- String clsinfo = "Classes: " + cl.getLoadedClassCount() + " loaded, " + cl.getUnloadedClassCount() + " unloaded, " + cl.getTotalLoadedClassCount() + " loaded total.";
- if (sb.length() + 1 + clsinfo.length() < size.getColumns()) {
- sb.append(" ");
- } else {
- lines.add(sb.toAttributedString());
- sb.setLength(0);
- }
- sb.append(clsinfo);
-
- ThreadMXBean th = ManagementFactory.getThreadMXBean();
- String thinfo = "Threads: " + th.getThreadCount() + ", peak: " + th.getPeakThreadCount() + ", started: " + th.getTotalStartedThreadCount() + ".";
- if (sb.length() + 1 + thinfo.length() < size.getColumns()) {
- sb.append(" ");
- } else {
- lines.add(sb.toAttributedString());
- sb.setLength(0);
- }
- sb.append(thinfo);
-
- MemoryMXBean me = ManagementFactory.getMemoryMXBean();
- String meinfo = "Memory: " + "heap: " + memory(me.getHeapMemoryUsage().getUsed(), me.getHeapMemoryUsage().getMax())
- + ", non heap: " + memory(me.getNonHeapMemoryUsage().getUsed(), me.getNonHeapMemoryUsage().getMax()) + ".";
- if (sb.length() + 1 + meinfo.length() < size.getColumns()) {
- sb.append(" ");
- } else {
- lines.add(sb.toAttributedString());
- sb.setLength(0);
- }
- sb.append(meinfo);
-
- StringBuilder sbc = new StringBuilder();
- sbc.append("GC: ");
- boolean first = true;
- for (GarbageCollectorMXBean gc : ManagementFactory.getGarbageCollectorMXBeans()) {
- if (first) {
- first = false;
- } else {
- sbc.append(", ");
- }
- long count = gc.getCollectionCount();
- long time = gc.getCollectionTime();
- sbc.append(gc.getName()).append(": ")
- .append(Long.toString(count)).append(" col. / ")
- .append(String.format("%d", time / 1000))
- .append(".")
- .append(String.format("%03d", time % 1000))
- .append(" s");
- }
- sbc.append(".");
- if (sb.length() + 1 + sbc.length() < size.getColumns()) {
- sb.append(" ");
- } else {
- lines.add(sb.toAttributedString());
- sb.setLength(0);
- }
- sb.append(sbc);
- lines.add(sb.toAttributedString());
- sb.setLength(0);
-
- lines.add(sb.toAttributedString());
-
- // Threads
- List<Map<String, Comparable>> threads = infos();
- Collections.sort(threads, comparator);
- int nb = Math.min(size.getRows() - lines.size() - 2, nthreads > 0 ? nthreads : threads.size());
- // Compute values
- List<Map<String, String>> values = threads.subList(0, nb).stream()
- .map(thread -> stats.stream()
- .collect(Collectors.toMap(
- Function.identity(),
- key -> columns.get(key).format.apply(thread.get(key)))))
- .collect(Collectors.toList());
- for (String key : stats) {
- int width = values.stream().mapToInt(map -> map.get(key).length()).max().orElse(0);
- widths.put(key, Math.max(columns.get(key).header.length(), Math.max(width, widths.getOrDefault(key, 0))));
- }
- List<String> cstats;
- if (widths.values().stream().mapToInt(Integer::intValue).sum() + stats.size() - 1 < size.getColumns()) {
- cstats = stats;
- } else {
- cstats = new ArrayList<>();
- int sz = 0;
- for (String stat : stats) {
- int nsz = sz;
- if (nsz > 0) {
- nsz++;
- }
- nsz += widths.get(stat);
- if (nsz < size.getColumns()) {
- sz = nsz;
- cstats.add(stat);
- } else {
- break;
- }
- }
- }
- // Headers
- for (String key : cstats) {
- if (sb.length() > 0) {
- sb.append(" ");
- }
- Column col = columns.get(key);
- align(sb, col.header, widths.get(key), col.align);
- }
- lines.add(sb.toAttributedString());
- sb.setLength(0);
- // Threads
- for (int i = 0; i < nb; i++) {
- Map<String, Comparable> thread = threads.get(i);
- long tid = (Long) thread.get(STAT_TID);
- for (String key : cstats) {
- if (sb.length() > 0) {
- sb.append(" ");
- }
- long last;
- Object cur = thread.get(key);
- Object prv = previous.computeIfAbsent(tid, id -> new HashMap<>()).put(key, cur);
- if (prv != null && !prv.equals(cur)) {
- changes.computeIfAbsent(tid, id -> new HashMap<>()).put(key, now);
- last = now;
- } else {
- last = changes.computeIfAbsent(tid, id -> new HashMap<>()).getOrDefault(key, 0L);
- }
- long fade = delay * 24;
- if (now - last < fade) {
- int r = (int) ((now - last) / (fade / 24));
- sb.style(sb.style().foreground(255 - r).background(9));
- }
- align(sb, values.get(i).get(key), widths.get(key), columns.get(key).align);
- sb.style(sb.style().backgroundOff().foregroundOff());
- }
- lines.add(sb.toAttributedString());
- sb.setLength(0);
- }
-
- display.update(lines, 0);
- terminal.flush();
- }
-
- private Comparator<Map<String, Comparable>> buildComparator(List<String> sort) {
- if (sort == null || sort.isEmpty()) {
- sort = Collections.singletonList(STAT_TID);
- }
- Comparator<Map<String, Comparable>> comparator = null;
- for (String key : sort) {
- boolean asc = true;
- if (key.startsWith("+")) {
- key = key.substring(1);
- } else if (key.startsWith("-")) {
- key = key.substring(1);
- asc = false;
- }
- if (!columns.containsKey(key)) {
- throw new IllegalArgumentException("Unsupported sort key: " + key);
- }
- String fkey = key;
- Comparator<Map<String, Comparable>> comp = Comparator.comparing(
- (Function<Map<String, Comparable>, Comparable>) m -> m.get(fkey),
- asc ? Comparator.reverseOrder() : Comparator.naturalOrder());
- if (comparator != null) {
- comparator = comparator.thenComparing(comp);
- } else {
- comparator = comp;
- }
- }
- return comparator;
- }
-
- private void register(String name, Align align, String header, Function<Object, String> format) {
- columns.put(name, new Column(name, align, header, format));
- }
-
- private static String nanos(long nanos) {
- return millis(nanos / 1_000_000L);
- }
-
- private static String millis(long millis) {
- long secs = millis / 1_000;
- millis = millis % 1000;
- long mins = secs / 60;
- secs = secs % 60;
- long hours = mins / 60;
- mins = mins % 60;
- if (hours > 0) {
- return String.format("%d:%02d:%02d.%03d", hours, mins, secs, millis);
- } else if (mins > 0) {
- return String.format("%d:%02d.%03d", mins, secs, millis);
- } else {
- return String.format("%d.%03d", secs, millis);
- }
- }
- private static Function<Object, String> padcut(int nb) {
- return o -> padcut(o.toString(), nb);
- }
- private static String padcut(String str, int nb) {
- if (str.length() <= nb) {
- StringBuilder sb = new StringBuilder(nb);
- sb.append(str);
- while (sb.length() < nb) {
- sb.append(' ');
- }
- return sb.toString();
- } else {
- StringBuilder sb = new StringBuilder(nb);
- sb.append(str, 0, nb - 3);
- sb.append("...");
- return sb.toString();
- }
- }
- private static String memory(long cur, long max) {
- if (max > 0) {
- String smax = humanReadableByteCount(max, false);
- String cmax = humanReadableByteCount(cur, false);
- StringBuilder sb = new StringBuilder(smax.length() * 2 + 3);
- for (int i = cmax.length(); i < smax.length(); i++) {
- sb.append(' ');
- }
- sb.append(cmax).append(" / ").append(smax);
- return sb.toString();
- } else {
- return humanReadableByteCount(cur, false);
- }
- }
-
- private static String humanReadableByteCount(long bytes, boolean si) {
- int unit = si ? 1000 : 1024;
- if (bytes < 1024) return bytes + " B";
- int exp = (int) (Math.log(bytes) / Math.log(1024));
- String pre = (si ? "kMGTPE" : "KMGTPE").charAt(exp-1) + (si ? "" : "i");
- return String.format("%.1f %sB", bytes / Math.pow(unit, exp), pre);
- }
-
- /**
- * This is for long running commands to be interrupted by ctrl-c
- */
- private void checkInterrupted() throws InterruptedException {
- Thread.yield();
- if (Thread.currentThread().isInterrupted()) {
- throw new InterruptedException();
- }
- }
-
- private void bindKeys(KeyMap<Operation> map) {
- map.bind(Operation.HELP, "h", "?");
- map.bind(Operation.EXIT, "q", ":q", "Q", ":Q", "ZZ");
- map.bind(Operation.INCREASE_DELAY, "+");
- map.bind(Operation.DECREASE_DELAY, "-");
- map.bind(Operation.CLEAR, KeyMap.ctrl('L'));
- map.bind(Operation.REVERSE, "r");
- }
-
- private static class Column {
- final String name;
- final Align align;
- final String header;
- final Function<Object, String> format;
-
- Column(String name, Align align, String header, Function<Object, String> format) {
- this.name = name;
- this.align = align;
- this.header = header;
- this.format = format;
- }
- }
-
-}