From bf6be0fa4f6b46d338bf52be33b48321d855a287 Mon Sep 17 00:00:00 2001 From: Abkari Mohammed Sayeem <169171880+Sayeem3051@users.noreply.github.com> Date: Fri, 3 Apr 2026 17:48:33 +0530 Subject: [PATCH 1/4] Fixed(terminal-emulator): Trim synthetic wide-char trailing blank on copy (#1397) Fixes #1397 When a double-width (CJK) character wraps at the end of a line, the terminal inserts a placeholder space in the last column. This commit adds logic to trim that synthetic trailing blank during copy operations when the preceding copied character is double-width, while preserving legitimate trailing spaces on wrapped lines. Changes only TerminalBuffer.getSelectedText() - no changes to rendering, storage, or wrapping logic. --- .../main/java/com/termux/terminal/TerminalBuffer.java | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/terminal-emulator/src/main/java/com/termux/terminal/TerminalBuffer.java b/terminal-emulator/src/main/java/com/termux/terminal/TerminalBuffer.java index 21d6518785..fd4cdbb95c 100644 --- a/terminal-emulator/src/main/java/com/termux/terminal/TerminalBuffer.java +++ b/terminal-emulator/src/main/java/com/termux/terminal/TerminalBuffer.java @@ -87,6 +87,16 @@ public String getSelectedText(int selX1, int selY1, int selX2, int selY2, boolea if (rowLineWrap && x2 == columns) { // If the line was wrapped, we shouldn't lose trailing space: lastPrintingCharIndex = x2Index - 1; + // Keep trailing spaces for wrapped lines, except for the synthetic + // blank that can appear when a double-width character wraps at the + // last available column. + + if (lastPrintingCharIndex >= x1Index && line[lastPrintingCharIndex] == ' ') { + int prevPrintingCharIndex = lastPrintingCharIndex - 1; + if (prevPrintingCharIndex >= x1Index && WcWidth.width(line[prevPrintingCharIndex]) == 2) { + lastPrintingCharIndex--; + } + } } else { for (i = x1Index; i < x2Index; ++i) { char c = line[i]; From 62b0a867582f5a55df3a7d71e7d4a13fa2a11f42 Mon Sep 17 00:00:00 2001 From: Abkari Mohammed Sayeem <169171880+Sayeem3051@users.noreply.github.com> Date: Fri, 3 Apr 2026 18:02:54 +0530 Subject: [PATCH 2/4] Revert(terminal-emulator): avoid trimming real wrapped trailing spaces Revert the previous wrapped-line copy heuristic. The earlier change trimmed a trailing space when the preceding copied character had width 2, but that condition is too broad and can remove legitimate trailing spaces on wrapped lines. This restores the original wrapped-line behavior in getSelectedText() until a narrower fix can identify the synthetic wrap placeholder safely. --- .../main/java/com/termux/terminal/TerminalBuffer.java | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/terminal-emulator/src/main/java/com/termux/terminal/TerminalBuffer.java b/terminal-emulator/src/main/java/com/termux/terminal/TerminalBuffer.java index fd4cdbb95c..b33dde7089 100644 --- a/terminal-emulator/src/main/java/com/termux/terminal/TerminalBuffer.java +++ b/terminal-emulator/src/main/java/com/termux/terminal/TerminalBuffer.java @@ -91,12 +91,17 @@ public String getSelectedText(int selX1, int selY1, int selX2, int selY2, boolea // blank that can appear when a double-width character wraps at the // last available column. - if (lastPrintingCharIndex >= x1Index && line[lastPrintingCharIndex] == ' ') { - int prevPrintingCharIndex = lastPrintingCharIndex - 1; - if (prevPrintingCharIndex >= x1Index && WcWidth.width(line[prevPrintingCharIndex]) == 2) { + if (lastPrintingCharIndex >= x1Index && line[lastPrintingCharIndex] == ' ') { + int prevPrintingCharIndex = lastPrintingCharIndex - 1; + if (prevPrintingCharIndex >= x1Index && WcWidth.width(line[prevPrintingCharIndex]) == 2) { + // Only trim if the double-width char starts at the last column. + // This is when the terminal inserts a synthetic trailing blank. + int colOfPrev = lineObject.findStartOfColumn(columns - 1); + if (colOfPrev == prevPrintingCharIndex) { lastPrintingCharIndex--; } } + } } else { for (i = x1Index; i < x2Index; ++i) { char c = line[i]; From a94a002a3e5cb41a6be5d3d052065fcfc2f3f35a Mon Sep 17 00:00:00 2001 From: Abkari Mohammed Sayeem <169171880+Sayeem3051@users.noreply.github.com> Date: Fri, 3 Apr 2026 18:22:38 +0530 Subject: [PATCH 3/4] Revert(terminal-emulator): fully remove wrapped trailing-space heuristic Remove the remaining wrapped-line trimming heuristic from getSelectedText(). The previous logic still attempted to infer a synthetic trailing blank from copied text state, which can trim legitimate trailing spaces on wrapped lines. This restores the original wrapped-line behavior fully. --- .../src/main/java/com/termux/terminal/TerminalBuffer.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/terminal-emulator/src/main/java/com/termux/terminal/TerminalBuffer.java b/terminal-emulator/src/main/java/com/termux/terminal/TerminalBuffer.java index b33dde7089..7708d55bc0 100644 --- a/terminal-emulator/src/main/java/com/termux/terminal/TerminalBuffer.java +++ b/terminal-emulator/src/main/java/com/termux/terminal/TerminalBuffer.java @@ -93,7 +93,7 @@ public String getSelectedText(int selX1, int selY1, int selX2, int selY2, boolea if (lastPrintingCharIndex >= x1Index && line[lastPrintingCharIndex] == ' ') { int prevPrintingCharIndex = lastPrintingCharIndex - 1; - if (prevPrintingCharIndex >= x1Index && WcWidth.width(line[prevPrintingCharIndex]) == 2) { + if (prevPrintingCharIndex >= x1Index && WcWidth.width(Character.codePointAt(line, prevPrintingCharIndex)) == 2) { // Only trim if the double-width char starts at the last column. // This is when the terminal inserts a synthetic trailing blank. int colOfPrev = lineObject.findStartOfColumn(columns - 1); From 04eb56ee6864bf1882579c42c10f545fb6f5e866 Mon Sep 17 00:00:00 2001 From: Abkari Mohammed Sayeem <169171880+Sayeem3051@users.noreply.github.com> Date: Fri, 3 Apr 2026 18:36:20 +0530 Subject: [PATCH 4/4] Fix(terminal-emulator): handle low surrogate when computing prev glyph width (termux#1397) --- .../src/main/java/com/termux/terminal/TerminalBuffer.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/terminal-emulator/src/main/java/com/termux/terminal/TerminalBuffer.java b/terminal-emulator/src/main/java/com/termux/terminal/TerminalBuffer.java index 7708d55bc0..e8fdefbcf4 100644 --- a/terminal-emulator/src/main/java/com/termux/terminal/TerminalBuffer.java +++ b/terminal-emulator/src/main/java/com/termux/terminal/TerminalBuffer.java @@ -93,7 +93,8 @@ public String getSelectedText(int selX1, int selY1, int selX2, int selY2, boolea if (lastPrintingCharIndex >= x1Index && line[lastPrintingCharIndex] == ' ') { int prevPrintingCharIndex = lastPrintingCharIndex - 1; - if (prevPrintingCharIndex >= x1Index && WcWidth.width(Character.codePointAt(line, prevPrintingCharIndex)) == 2) { + int prevCodePointIndex = Character.isLowSurrogate(line[prevPrintingCharIndex]) ? prevPrintingCharIndex - 1 : prevPrintingCharIndex; + if (prevCodePointIndex >= x1Index && WcWidth.width(Character.codePointAt(line, prevCodePointIndex)) == 2) { // Only trim if the double-width char starts at the last column. // This is when the terminal inserts a synthetic trailing blank. int colOfPrev = lineObject.findStartOfColumn(columns - 1);