diff --git a/reader/src/main/java/org/jline/reader/impl/LineReaderImpl.java b/reader/src/main/java/org/jline/reader/impl/LineReaderImpl.java index 29a97a2a7..f366d4e7a 100644 --- a/reader/src/main/java/org/jline/reader/impl/LineReaderImpl.java +++ b/reader/src/main/java/org/jline/reader/impl/LineReaderImpl.java @@ -89,6 +89,8 @@ public class LineReaderImpl implements LineReader, Flushable public static final long DEFAULT_AMBIGUOUS_BINDING = 1000L; public static final String DEFAULT_SECONDARY_PROMPT_PATTERN = "%M> "; + private static final int MIN_ROWS = 3; + /** * Possible states in which the current readline operation may be in. */ @@ -230,6 +232,9 @@ protected enum BellType { protected String keyMap; + protected int smallTerminalOffset = 0; + + public LineReaderImpl(Terminal terminal) throws IOException { this(terminal, null, null); @@ -439,6 +444,8 @@ public String readLine(String prompt, String rightPrompt, Character mask, String regionActive = RegionType.NONE; regionMark = -1; + smallTerminalOffset = 0; + state = State.NORMAL; modifiedHistory.clear(); @@ -3258,7 +3265,50 @@ protected void redisplay(boolean flush) { skipRedisplay = false; return; } - // TODO: support TERM_SHORT, terminal lines < 3 + + if (size.getRows() > 0 && size.getRows() < MIN_ROWS) { + AttributedStringBuilder sb = new AttributedStringBuilder().tabs(TAB_WIDTH); + + sb.append(prompt); + concat(getHighlightedBuffer(buf.toString()).columnSplitLength(Integer.MAX_VALUE), sb); + AttributedString full = sb.toAttributedString(); + + sb.setLength(0); + sb.append(prompt); + concat(getMaskedBuffer(buf.upToCursor()).columnSplitLength(Integer.MAX_VALUE), sb); + AttributedString toCursor = sb.toAttributedString(); + + int w = WCWidth.wcwidth('…'); + int width = size.getColumns(); + int cursor = toCursor.columnLength(); + int inc = width /2 + 1; + while (cursor <= smallTerminalOffset + w) { + smallTerminalOffset -= inc; + } + while (cursor >= smallTerminalOffset + width - w) { + smallTerminalOffset += inc; + } + if (smallTerminalOffset > 0) { + sb.setLength(0); + sb.append("…"); + sb.append(full.columnSubSequence(smallTerminalOffset + w, Integer.MAX_VALUE)); + full = sb.toAttributedString(); + } + int length = full.columnLength(); + if (length >= smallTerminalOffset + width) { + sb.setLength(0); + sb.append(full.columnSubSequence(0, width - w)); + sb.append("…"); + full = sb.toAttributedString(); + } + + display.update(Collections.singletonList(full), cursor - smallTerminalOffset); + if (flush) { + flush(); + } + return; + } + List secondaryPrompts = new ArrayList<>(); AttributedString full = getDisplayedBufferWithPrompts(secondaryPrompts); @@ -3315,9 +3365,33 @@ protected void redisplay(boolean flush) { } } + private void concat(List lines, AttributedStringBuilder sb) { + if (lines.size() > 1) { + for (int i = 0; i < lines.size() - 1; i++) { + sb.append(lines.get(i)); + sb.style(sb.style().inverse()); + sb.append("\\n"); + sb.style(sb.style().inverseOff()); + } + } + sb.append(lines.get(lines.size() - 1)); + } + private AttributedString getDisplayedBufferWithPrompts(List secondaryPrompts) { - AttributedString attBuf; - String buffer = buf.toString(); + AttributedString attBuf = getHighlightedBuffer(buf.toString()); + + AttributedString tNewBuf = insertSecondaryPrompts(attBuf, secondaryPrompts); + AttributedStringBuilder full = new AttributedStringBuilder().tabs(TAB_WIDTH); + full.append(prompt); + full.append(tNewBuf); + if (post != null) { + full.append("\n"); + full.append(post.get()); + } + return full.toAttributedString(); + } + + private AttributedString getMaskedBuffer(String buffer) { if (mask != null) { if (mask == NULL_MASK) { buffer = ""; @@ -3328,22 +3402,18 @@ private AttributedString getDisplayedBufferWithPrompts(List se } buffer = sb.toString(); } - attBuf = new AttributedString(buffer); - } else if (highlighter != null) { - attBuf = highlighter.highlight(this, buffer); - } else { - attBuf = new AttributedString(buffer); } + return new AttributedString(buffer); + } - AttributedString tNewBuf = insertSecondaryPrompts(attBuf, secondaryPrompts); - AttributedStringBuilder full = new AttributedStringBuilder().tabs(TAB_WIDTH); - full.append(prompt); - full.append(tNewBuf); - if (post != null) { - full.append("\n"); - full.append(post.get()); + private AttributedString getHighlightedBuffer(String buffer) { + if (mask != null) { + return getMaskedBuffer(buffer); + } else if (highlighter != null) { + return highlighter.highlight(this, buffer); + } else { + return new AttributedString(buffer); } - return full.toAttributedString(); } private AttributedString expandPromptPattern(String pattern, int padToWidth,