Improve mobile session reading and pane layout
Gitea Smoke / smoke (push) Successful in 2s
Gitea Android APK / build (push) Has been cancelled

This commit is contained in:
Codex
2026-07-12 01:59:55 +00:00
parent f103e9e065
commit 96fe5ecb8f
2 changed files with 299 additions and 31 deletions
@@ -124,11 +124,17 @@ public final class MainActivity extends Activity {
private LinearLayout sessionGroupList; private LinearLayout sessionGroupList;
private TextView terminalText; private TextView terminalText;
private TextView terminalMetaText; private TextView terminalMetaText;
private TextView terminalConnectionText;
private Button terminalReadingButton;
private ScrollView terminalScroll; private ScrollView terminalScroll;
private EditText inputField; private EditText inputField;
private final Button[] terminalAccessoryTabButtons = new Button[4]; private final Button[] terminalAccessoryTabButtons = new Button[4];
private View terminalAccessoryBar; private View terminalAccessoryBar;
private View terminalComposerBar; private View terminalComposerBar;
private LinearLayout terminalImagePreviewBar;
private ImageView terminalImagePreview;
private TextView terminalImagePreviewPath;
private String terminalImagePath = "";
private LinearLayout terminalGroupRow; private LinearLayout terminalGroupRow;
private String activeSessionName; private String activeSessionName;
private String terminalPathStatus = ""; private String terminalPathStatus = "";
@@ -145,6 +151,7 @@ public final class MainActivity extends Activity {
private boolean terminalRenderPending; private boolean terminalRenderPending;
private boolean terminalSelectionEnabled; private boolean terminalSelectionEnabled;
private boolean terminalFollowOutput = true; private boolean terminalFollowOutput = true;
private boolean terminalReadingMode = true;
private int terminalKeyPage; private int terminalKeyPage;
private int terminalReconnectAttempt; private int terminalReconnectAttempt;
private int terminalConnectionGeneration; private int terminalConnectionGeneration;
@@ -1596,6 +1603,10 @@ public final class MainActivity extends Activity {
terminalSelectionEnabled = false; terminalSelectionEnabled = false;
terminalFollowOutput = true; terminalFollowOutput = true;
terminalKeyPage = 0; terminalKeyPage = 0;
terminalImagePath = "";
terminalImagePreviewBar = null;
terminalImagePreview = null;
terminalImagePreviewPath = null;
terminalPathStatus = "path loading"; terminalPathStatus = "path loading";
terminalSocketStatus = "terminal idle"; terminalSocketStatus = "terminal idle";
terminalEventStatus = "events listening"; terminalEventStatus = "events listening";
@@ -1614,9 +1625,10 @@ public final class MainActivity extends Activity {
terminalScroll.setBackgroundColor(COLOR_TERMINAL_BG); terminalScroll.setBackgroundColor(COLOR_TERMINAL_BG);
terminalText = new TextView(this); terminalText = new TextView(this);
terminalText.setTextColor(COLOR_TEXT); terminalText.setTextColor(COLOR_TEXT);
terminalText.setTextSize(13); terminalText.setTextSize(11);
terminalText.setTypeface(Typeface.MONOSPACE); terminalText.setTypeface(Typeface.MONOSPACE);
terminalText.setIncludeFontPadding(false); terminalText.setIncludeFontPadding(false);
terminalText.setHorizontallyScrolling(!terminalReadingMode);
terminalText.setLineSpacing(0, 1.05f); terminalText.setLineSpacing(0, 1.05f);
terminalText.setGravity(Gravity.BOTTOM | Gravity.START); terminalText.setGravity(Gravity.BOTTOM | Gravity.START);
terminalText.setTextIsSelectable(terminalSelectionEnabled); terminalText.setTextIsSelectable(terminalSelectionEnabled);
@@ -1667,6 +1679,10 @@ public final class MainActivity extends Activity {
titleBlock.setGravity(Gravity.CENTER_VERTICAL); titleBlock.setGravity(Gravity.CENTER_VERTICAL);
titleBlock.setPadding(dp(9), 0, dp(7), 0); titleBlock.setPadding(dp(9), 0, dp(7), 0);
LinearLayout titleRow = new LinearLayout(this);
titleRow.setOrientation(LinearLayout.HORIZONTAL);
titleRow.setGravity(Gravity.CENTER_VERTICAL);
TextView title = new TextView(this); TextView title = new TextView(this);
title.setText(sessionName); title.setText(sessionName);
title.setTextColor(COLOR_TEXT); title.setTextColor(COLOR_TEXT);
@@ -1675,6 +1691,22 @@ public final class MainActivity extends Activity {
title.setSingleLine(true); title.setSingleLine(true);
title.setEllipsize(TextUtils.TruncateAt.END); title.setEllipsize(TextUtils.TruncateAt.END);
title.setIncludeFontPadding(false); title.setIncludeFontPadding(false);
titleRow.addView(title, new LinearLayout.LayoutParams(
0,
dp(17),
1
));
terminalConnectionText = new TextView(this);
terminalConnectionText.setTextSize(9);
terminalConnectionText.setTypeface(Typeface.MONOSPACE);
terminalConnectionText.setSingleLine(true);
terminalConnectionText.setIncludeFontPadding(false);
terminalConnectionText.setPadding(dp(7), 0, 0, 0);
titleRow.addView(terminalConnectionText, new LinearLayout.LayoutParams(
ViewGroup.LayoutParams.WRAP_CONTENT,
dp(17)
));
terminalMetaText = new TextView(this); terminalMetaText = new TextView(this);
terminalMetaText.setTextColor(COLOR_TEXT_DIM); terminalMetaText.setTextColor(COLOR_TEXT_DIM);
@@ -1685,7 +1717,7 @@ public final class MainActivity extends Activity {
terminalMetaText.setIncludeFontPadding(false); terminalMetaText.setIncludeFontPadding(false);
updateTerminalMeta(); updateTerminalMeta();
titleBlock.addView(title, new LinearLayout.LayoutParams( titleBlock.addView(titleRow, new LinearLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT,
dp(17) dp(17)
)); ));
@@ -1694,10 +1726,36 @@ public final class MainActivity extends Activity {
dp(13) dp(13)
)); ));
bar.addView(titleBlock, new LinearLayout.LayoutParams(0, dp(32), 1)); bar.addView(titleBlock, new LinearLayout.LayoutParams(0, dp(32), 1));
terminalReadingButton = terminalToolButton("", view ->
setTerminalReadingMode(!terminalReadingMode));
terminalReadingButton.setContentDescription("Toggle Chinese reading mode");
styleTerminalReadingButton();
bar.addView(terminalReadingButton);
bar.addView(terminalToolButton("", view -> showTerminalActions(sessionName))); bar.addView(terminalToolButton("", view -> showTerminalActions(sessionName)));
return bar; return bar;
} }
private void setTerminalReadingMode(boolean reading) {
terminalReadingMode = reading;
if (terminalText != null) {
terminalText.setHorizontallyScrolling(!reading);
}
styleTerminalReadingButton();
renderTerminalNow();
setStatus(reading ? "Chinese reading mode" : "Full terminal mode");
}
private void styleTerminalReadingButton() {
if (terminalReadingButton == null) {
return;
}
terminalReadingButton.setText(terminalReadingMode ? "" : "");
terminalReadingButton.setTextColor(terminalReadingMode ? Color.rgb(14, 38, 24) : COLOR_TEXT_MUTED);
terminalReadingButton.setBackground(terminalReadingMode
? rounded(COLOR_ACCENT, 7, COLOR_ACCENT, 1)
: buttonBackground());
}
private HorizontalScrollView createTerminalGroupBar() { private HorizontalScrollView createTerminalGroupBar() {
HorizontalScrollView scroller = new HorizontalScrollView(this); HorizontalScrollView scroller = new HorizontalScrollView(this);
scroller.setHorizontalScrollBarEnabled(false); scroller.setHorizontalScrollBarEnabled(false);
@@ -1737,18 +1795,13 @@ public final class MainActivity extends Activity {
try { try {
List<SessionSummary> sessions = api.getSessions(); List<SessionSummary> sessions = api.getSessions();
String path = ""; String path = "";
String command = "";
for (SessionSummary session : sessions) { for (SessionSummary session : sessions) {
if (sessionName.equals(session.name)) { if (sessionName.equals(session.name)) {
path = defaultValue(session.currentPath, ""); path = defaultValue(session.currentPath, "");
command = defaultValue(session.currentCommand, "");
break; break;
} }
} }
String meta = path.isEmpty() ? "path unavailable" : path; String meta = path.isEmpty() ? "path unavailable" : compactTerminalPath(path);
if (!command.isEmpty()) {
meta = meta + " · " + command;
}
String finalMeta = meta; String finalMeta = meta;
runOnUiThread(() -> { runOnUiThread(() -> {
if (sessionName.equals(activeSessionName)) { if (sessionName.equals(activeSessionName)) {
@@ -1768,18 +1821,28 @@ public final class MainActivity extends Activity {
} }
private void updateTerminalMeta() { private void updateTerminalMeta() {
if (terminalMetaText == null) { if (terminalMetaText == null || terminalConnectionText == null) {
return; return;
} }
StringBuilder meta = new StringBuilder(); terminalMetaText.setText(defaultValue(terminalPathStatus, "path loading"));
meta.append(defaultValue(terminalPathStatus, "path loading")); String socket = terminalSocketStatus.toLowerCase(java.util.Locale.ROOT);
if (!terminalSocketStatus.isEmpty()) { if (socket.contains("connected") && !socket.contains("disconnected")) {
meta.append(" · ").append(terminalSocketStatus); terminalConnectionText.setText("● connected");
terminalConnectionText.setTextColor(COLOR_SUCCESS);
} else if (socket.contains("error") || socket.contains("disconnected")) {
terminalConnectionText.setText("● disconnected");
terminalConnectionText.setTextColor(COLOR_DANGER);
} else {
terminalConnectionText.setText("● connecting");
terminalConnectionText.setTextColor(COLOR_ACCENT_WARM);
} }
if (!terminalEventStatus.isEmpty()) { }
meta.append(" · ").append(terminalEventStatus);
} private String compactTerminalPath(String path) {
terminalMetaText.setText(meta.toString()); String compact = path.trim();
compact = compact.replaceFirst("^/home/[^/]+(?=/|$)", "~");
compact = compact.replaceFirst("^/Users/[^/]+(?=/|$)", "~");
return compact;
} }
private void renderTerminalGroupSessions(String sessionName, String text) { private void renderTerminalGroupSessions(String sessionName, String text) {
@@ -1992,6 +2055,7 @@ public final class MainActivity extends Activity {
"Clear local view and tmux history", "Clear local view and tmux history",
"Split horizontal", "Split horizontal",
"Split vertical", "Split vertical",
"Zoom active pane",
"Page up", "Page up",
"Page down", "Page down",
"Session status", "Session status",
@@ -2023,34 +2087,37 @@ public final class MainActivity extends Activity {
runApiAction("Split vertical", () -> api.splitPane(sessionName, "vertical")); runApiAction("Split vertical", () -> api.splitPane(sessionName, "vertical"));
break; break;
case 4: case 4:
sendTerminalInput("\u0002z");
break;
case 5:
if (terminalSocket != null) { if (terminalSocket != null) {
terminalSocket.scroll(-terminalRows); terminalSocket.scroll(-terminalRows);
} }
break; break;
case 5: case 6:
if (terminalSocket != null) { if (terminalSocket != null) {
terminalSocket.scroll(terminalRows); terminalSocket.scroll(terminalRows);
} }
break; break;
case 6: case 7:
showRaw("Session status", () -> api.sessionStatus(sessionName)); showRaw("Session status", () -> api.sessionStatus(sessionName));
break; break;
case 7: case 8:
promptSendCommand(sessionName); promptSendCommand(sessionName);
break; break;
case 8: case 9:
sendTerminalInput("\u0002"); sendTerminalInput("\u0002");
break; break;
case 9: case 10:
sendTerminalInput("\u0002d"); sendTerminalInput("\u0002d");
break; break;
case 10: case 11:
sendTerminalInput("\u0002c"); sendTerminalInput("\u0002c");
break; break;
case 11: case 12:
sendTerminalInput("\u0002n"); sendTerminalInput("\u0002n");
break; break;
case 12: case 13:
sendTerminalInput("\u0002p"); sendTerminalInput("\u0002p");
break; break;
default: default:
@@ -2066,6 +2133,12 @@ public final class MainActivity extends Activity {
bar.setPadding(dp(8), dp(5), dp(8), dp(7)); bar.setPadding(dp(8), dp(5), dp(8), dp(7));
bar.setBackgroundColor(COLOR_BAR); bar.setBackgroundColor(COLOR_BAR);
terminalImagePreviewBar = createComposerImagePreviewBar();
bar.addView(terminalImagePreviewBar, new LinearLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
dp(64)
));
LinearLayout row = new LinearLayout(this); LinearLayout row = new LinearLayout(this);
row.setOrientation(LinearLayout.HORIZONTAL); row.setOrientation(LinearLayout.HORIZONTAL);
row.setGravity(Gravity.CENTER_VERTICAL); row.setGravity(Gravity.CENTER_VERTICAL);
@@ -2161,6 +2234,87 @@ public final class MainActivity extends Activity {
return bar; return bar;
} }
private LinearLayout createComposerImagePreviewBar() {
LinearLayout previewBar = new LinearLayout(this);
previewBar.setOrientation(LinearLayout.HORIZONTAL);
previewBar.setGravity(Gravity.CENTER_VERTICAL);
previewBar.setPadding(dp(4), dp(3), dp(2), dp(7));
previewBar.setVisibility(View.GONE);
terminalImagePreview = new ImageView(this);
terminalImagePreview.setScaleType(ImageView.ScaleType.CENTER_CROP);
terminalImagePreview.setAdjustViewBounds(false);
terminalImagePreview.setBackground(rounded(COLOR_FIELD, 6, COLOR_BORDER, 1));
terminalImagePreview.setContentDescription("Open uploaded image preview");
terminalImagePreview.setOnClickListener(view -> {
if (!terminalImagePath.isEmpty()) {
showImagePreview(terminalImagePath, "");
}
});
previewBar.addView(terminalImagePreview, new LinearLayout.LayoutParams(dp(52), dp(52)));
terminalImagePreviewPath = bodyText("Loading image preview...");
terminalImagePreviewPath.setSingleLine(true);
terminalImagePreviewPath.setEllipsize(TextUtils.TruncateAt.MIDDLE);
terminalImagePreviewPath.setTextSize(10);
LinearLayout.LayoutParams pathParams = new LinearLayout.LayoutParams(0, dp(52), 1);
pathParams.leftMargin = dp(9);
previewBar.addView(terminalImagePreviewPath, pathParams);
Button clear = terminalToolButton("×", view -> clearComposerImagePreview());
clear.setContentDescription("Clear image preview");
previewBar.addView(clear);
return previewBar;
}
private void loadComposerImagePreview(String path) {
if (terminalImagePreviewBar == null || path == null || path.isEmpty()) {
return;
}
terminalImagePath = path;
terminalImagePreview.setImageDrawable(null);
terminalImagePreviewPath.setText("Loading " + path);
terminalImagePreviewBar.setVisibility(View.VISIBLE);
int generation = terminalConnectionGeneration;
ImageView preview = terminalImagePreview;
TextView previewPath = terminalImagePreviewPath;
executor.execute(() -> {
try {
byte[] bytes = api.imagePreview(path, "");
Bitmap bitmap = decodePreviewBitmap(bytes, 1200);
if (bitmap == null) {
throw new IllegalStateException("Preview is not a supported bitmap");
}
runOnUiThread(() -> {
if (generation == terminalConnectionGeneration
&& path.equals(terminalImagePath)
&& preview == terminalImagePreview) {
preview.setImageBitmap(bitmap);
previewPath.setText(path);
}
});
} catch (Exception error) {
runOnUiThread(() -> {
if (generation == terminalConnectionGeneration
&& path.equals(terminalImagePath)
&& previewPath == terminalImagePreviewPath) {
previewPath.setText("Preview unavailable " + path);
}
});
}
});
}
private void clearComposerImagePreview() {
terminalImagePath = "";
if (terminalImagePreview != null) {
terminalImagePreview.setImageDrawable(null);
}
if (terminalImagePreviewBar != null) {
terminalImagePreviewBar.setVisibility(View.GONE);
}
}
private void promptRenameSession(String sessionName) { private void promptRenameSession(String sessionName) {
promptText("Rename session", sessionName, sessionName, nextName -> { promptText("Rename session", sessionName, sessionName, nextName -> {
if (!nextName.matches("[A-Za-z0-9._-]+")) { if (!nextName.matches("[A-Za-z0-9._-]+")) {
@@ -2589,7 +2743,7 @@ public final class MainActivity extends Activity {
executor.execute(() -> { executor.execute(() -> {
try { try {
byte[] bytes = api.imagePreview(path, basePath); byte[] bytes = api.imagePreview(path, basePath);
Bitmap bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length); Bitmap bitmap = decodePreviewBitmap(bytes, 1800);
if (bitmap == null) { if (bitmap == null) {
throw new IllegalStateException("Preview is not a supported bitmap"); throw new IllegalStateException("Preview is not a supported bitmap");
} }
@@ -2614,6 +2768,23 @@ public final class MainActivity extends Activity {
}); });
} }
private Bitmap decodePreviewBitmap(byte[] bytes, int maxDimension) {
BitmapFactory.Options bounds = new BitmapFactory.Options();
bounds.inJustDecodeBounds = true;
BitmapFactory.decodeByteArray(bytes, 0, bytes.length, bounds);
if (bounds.outWidth <= 0 || bounds.outHeight <= 0) {
return null;
}
int sampleSize = 1;
while (bounds.outWidth / sampleSize > maxDimension
|| bounds.outHeight / sampleSize > maxDimension) {
sampleSize *= 2;
}
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = sampleSize;
return BitmapFactory.decodeByteArray(bytes, 0, bytes.length, options);
}
private void promptText(String title, String hint, String value, TextApiAction action) { private void promptText(String title, String hint, String value, TextApiAction action) {
EditText input = new EditText(this); EditText input = new EditText(this);
input.setSingleLine(true); input.setSingleLine(true);
@@ -2906,7 +3077,7 @@ public final class MainActivity extends Activity {
} }
int horizontalPadding = terminalText.getPaddingLeft() + terminalText.getPaddingRight(); int horizontalPadding = terminalText.getPaddingLeft() + terminalText.getPaddingRight();
int verticalPadding = terminalText.getPaddingTop() + terminalText.getPaddingBottom(); int verticalPadding = terminalText.getPaddingTop() + terminalText.getPaddingBottom();
float charWidth = terminalText.getPaint().measureText("W"); float charWidth = terminalText.getPaint().measureText("0000000000") / 10f;
if (charWidth <= 0f) { if (charWidth <= 0f) {
charWidth = dp(8); charWidth = dp(8);
} }
@@ -3122,7 +3293,9 @@ public final class MainActivity extends Activity {
return; return;
} }
lastTerminalRenderMs = System.currentTimeMillis(); lastTerminalRenderMs = System.currentTimeMillis();
terminalText.setText(terminalScreen.render()); terminalText.setText(terminalReadingMode
? terminalScreen.renderFocused()
: terminalScreen.render());
if (terminalFollowOutput) { if (terminalFollowOutput) {
terminalScroll.post(() -> terminalScroll.fullScroll(View.FOCUS_DOWN)); terminalScroll.post(() -> terminalScroll.fullScroll(View.FOCUS_DOWN));
} }
@@ -3702,6 +3875,7 @@ public final class MainActivity extends Activity {
runOnUiThread(() -> { runOnUiThread(() -> {
progressBar.setVisibility(View.GONE); progressBar.setVisibility(View.GONE);
insertComposerPath(imagePath); insertComposerPath(imagePath);
loadComposerImagePreview(imagePath);
setStatus("Image path inserted"); setStatus("Image path inserted");
}); });
} catch (Exception error) { } catch (Exception error) {
@@ -134,6 +134,42 @@ final class TerminalScreenBuffer {
return output; return output;
} }
CharSequence renderFocused() {
List<String> visible = new ArrayList<>();
int hiddenRows = 0;
for (int row = 0; row < rows; row++) {
String text = rowText(row).trim();
if (containsHan(text)) {
if (hiddenRows > 0) {
visible.add("... 已折叠 " + hiddenRows + " 行终端内容 ...");
hiddenRows = 0;
}
visible.add(text);
} else if (!text.isEmpty()) {
hiddenRows++;
}
}
if (hiddenRows > 0) {
visible.add("... 已折叠 " + hiddenRows + " 行终端内容 ...");
}
if (visible.isEmpty()) {
for (int row = Math.max(0, rows - 4); row < rows; row++) {
String text = rowText(row).trim();
if (!text.isEmpty()) {
visible.add(text);
}
}
}
StringBuilder output = new StringBuilder();
for (int index = 0; index < visible.size(); index++) {
if (index > 0) {
output.append('\n');
}
output.append(visible.get(index));
}
return output;
}
private int handleEscape(String text, int index) { private int handleEscape(String text, int index) {
if (index + 1 >= text.length()) { if (index + 1 >= text.length()) {
return -1; return -1;
@@ -309,14 +345,34 @@ final class TerminalScreenBuffer {
wrapPending = false; wrapPending = false;
newLine(); newLine();
} }
int width = isWideCharacter(value) ? 2 : 1;
if (width == 2 && cursorCol == cols - 1) {
newLine();
}
cells[cursorRow][cursorCol].set(value, fg, bg, bold, dim); cells[cursorRow][cursorCol].set(value, fg, bg, bold, dim);
if (cursorCol == cols - 1) { if (width == 2) {
cells[cursorRow][cursorCol + 1].setContinuation(fg, bg, bold, dim);
}
if (cursorCol + width >= cols) {
cursorCol = cols - 1;
wrapPending = true; wrapPending = true;
} else { } else {
cursorCol++; cursorCol += width;
} }
} }
private boolean isWideCharacter(char value) {
return value >= '\u1100' && (value <= '\u115f'
|| value == '\u2329' || value == '\u232a'
|| (value >= '\u2e80' && value <= '\ua4cf' && value != '\u303f')
|| (value >= '\uac00' && value <= '\ud7a3')
|| (value >= '\uf900' && value <= '\ufaff')
|| (value >= '\ufe10' && value <= '\ufe19')
|| (value >= '\ufe30' && value <= '\ufe6f')
|| (value >= '\uff00' && value <= '\uff60')
|| (value >= '\uffe0' && value <= '\uffe6'));
}
private void newLine() { private void newLine() {
wrapPending = false; wrapPending = false;
cursorRow++; cursorRow++;
@@ -466,7 +522,9 @@ final class TerminalScreenBuffer {
if (cell.fg != fgColor || cell.bg != bgColor || cell.bold != isBold || cell.dim != isDim) { if (cell.fg != fgColor || cell.bg != bgColor || cell.bold != isBold || cell.dim != isDim) {
break; break;
} }
output.append(cell.value); if (!cell.continuation) {
output.append(cell.value);
}
col++; col++;
} }
int end = output.length(); int end = output.length();
@@ -483,6 +541,29 @@ final class TerminalScreenBuffer {
} }
} }
private String rowText(int row) {
StringBuilder text = new StringBuilder(cols);
for (int col = 0; col < cols; col++) {
Cell cell = cells[row][col];
if (!cell.continuation) {
text.append(cell.value);
}
}
return text.toString();
}
private boolean containsHan(String text) {
for (int index = 0; index < text.length(); index++) {
Character.UnicodeBlock block = Character.UnicodeBlock.of(text.charAt(index));
if (block == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS
|| block == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS_EXTENSION_A
|| block == Character.UnicodeBlock.CJK_COMPATIBILITY_IDEOGRAPHS) {
return true;
}
}
return false;
}
private void saveCursor() { private void saveCursor() {
savedRow = cursorRow; savedRow = cursorRow;
savedCol = cursorCol; savedCol = cursorCol;
@@ -643,6 +724,7 @@ final class TerminalScreenBuffer {
int bg = DEFAULT_BG; int bg = DEFAULT_BG;
boolean bold; boolean bold;
boolean dim; boolean dim;
boolean continuation;
void clear() { void clear() {
value = ' '; value = ' ';
@@ -650,6 +732,7 @@ final class TerminalScreenBuffer {
bg = DEFAULT_BG; bg = DEFAULT_BG;
bold = false; bold = false;
dim = false; dim = false;
continuation = false;
} }
void set(char nextValue, int nextFg, int nextBg, boolean nextBold, boolean nextDim) { void set(char nextValue, int nextFg, int nextBg, boolean nextBold, boolean nextDim) {
@@ -658,6 +741,16 @@ final class TerminalScreenBuffer {
bg = nextBg; bg = nextBg;
bold = nextBold; bold = nextBold;
dim = nextDim; dim = nextDim;
continuation = false;
}
void setContinuation(int nextFg, int nextBg, boolean nextBold, boolean nextDim) {
value = ' ';
fg = nextFg;
bg = nextBg;
bold = nextBold;
dim = nextDim;
continuation = true;
} }
void copyFrom(Cell other) { void copyFrom(Cell other) {
@@ -666,6 +759,7 @@ final class TerminalScreenBuffer {
bg = other.bg; bg = other.bg;
bold = other.bold; bold = other.bold;
dim = other.dim; dim = other.dim;
continuation = other.continuation;
} }
} }
} }