Return-Path: X-Original-To: archive-asf-public-internal@cust-asf2.ponee.io Delivered-To: archive-asf-public-internal@cust-asf2.ponee.io Received: from cust-asf.ponee.io (cust-asf.ponee.io [163.172.22.183]) by cust-asf2.ponee.io (Postfix) with ESMTP id C0247200C41 for ; Fri, 24 Mar 2017 08:46:19 +0100 (CET) Received: by cust-asf.ponee.io (Postfix) id BEC3B160B82; Fri, 24 Mar 2017 07:46:19 +0000 (UTC) Delivered-To: archive-asf-public@cust-asf.ponee.io Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by cust-asf.ponee.io (Postfix) with SMTP id 6515A160B93 for ; Fri, 24 Mar 2017 08:46:18 +0100 (CET) Received: (qmail 88678 invoked by uid 500); 24 Mar 2017 07:46:17 -0000 Mailing-List: contact commits-help@karaf.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@karaf.apache.org Delivered-To: mailing list commits@karaf.apache.org Received: (qmail 88644 invoked by uid 99); 24 Mar 2017 07:46:17 -0000 Received: from git1-us-west.apache.org (HELO git1-us-west.apache.org) (140.211.11.23) by apache.org (qpsmtpd/0.29) with ESMTP; Fri, 24 Mar 2017 07:46:17 +0000 Received: by git1-us-west.apache.org (ASF Mail Server at git1-us-west.apache.org, from userid 33) id 4AC49DFFDA; Fri, 24 Mar 2017 07:46:17 +0000 (UTC) Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: gnodet@apache.org To: commits@karaf.apache.org Date: Fri, 24 Mar 2017 07:46:18 -0000 Message-Id: In-Reply-To: <4f12074c254945769b2a0e9535c127f0@git.apache.org> References: <4f12074c254945769b2a0e9535c127f0@git.apache.org> X-Mailer: ASF-Git Admin Mailer Subject: [2/4] karaf git commit: [KARAF-5058] Use ttop implementation from JLine archived-at: Fri, 24 Mar 2017 07:46:19 -0000 [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 Authored: Fri Mar 24 08:21:49 2017 +0100 Committer: Guillaume Nodet 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 sort; - public long delay; - public List stats; - public int nthreads; - - public enum Align { - Left, Right - }; - - public enum Operation { - INCREASE_DELAY, - DECREASE_DELAY, - HELP, - EXIT, - CLEAR, - REVERSE - } - - private final Map columns = new LinkedHashMap<>(); - private final Terminal terminal; - private final Display display; - private final BindingReader bindingReader; - private final KeyMap keys; - private final Size size = new Size(); - - private Comparator> comparator; - - // Internal cache data - private Map> previous = new HashMap<>(); - private Map> changes = new HashMap<>(); - private Map 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 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> 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> threads = new ArrayList<>(); - for (ThreadInfo ti : infos) { - Map 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 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> threads = infos(); - Collections.sort(threads, comparator); - int nb = Math.min(size.getRows() - lines.size() - 2, nthreads > 0 ? nthreads : threads.size()); - // Compute values - List> 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 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 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> buildComparator(List sort) { - if (sort == null || sort.isEmpty()) { - sort = Collections.singletonList(STAT_TID); - } - Comparator> 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> comp = Comparator.comparing( - (Function, 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 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 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 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 format; - - Column(String name, Align align, String header, Function format) { - this.name = name; - this.align = align; - this.header = header; - this.format = format; - } - } - -}