Outline trimming can remove trailing CJK wide characters
Nessuno ha ancora preso questa issue.
Valutazione
- Difficoltà
- 2/5
- Tempo stimato
- 1-3 ore
- Idoneità per principianti
- 62/100
Direzione di ricerca
Il ramo finale di line_trim() in src/textual/_segment_tools.py passa una lunghezza in code point a split_cells(), che si aspetta un numero di celle. Esegui prima lo script di riproduzione per confermare l'output errato, poi controlla il ramo iniziale per il modello corretto. È completato quando i caratteri larghi finali restano entro il budget di celle, con test di regressione per l'ASCII e uno o due caratteri CJK finali. Conferma con un maintainer il comportamento previsto del riempimento con spazi prima di aprire una PR.
Scritto dal modello di indicizzazione a partire dal testo della issue.
Descrizione
Have you checked closed issues? Yes. I searched open and closed issues and pull requests for line_trim, CJK/wide-character trimming, outlines, and double-width truncation. #6357 also involves disappearing CJK text, but describes toast overlap and partial redraw over another widget's border; this reproduction is deterministic trimming of a widget's own outlined line.
Have you checked against the most recent version of Textual? Yes. PyPI currently lists 8.2.8. This also reproduces with Textual installed editable from current main, commit 5e5b7ef58b8c5572c13a3ff9027d756623661495.
The bug
When an outlined content line ends in double-width characters and has no trailing padding, Textual trims the end by character count rather than terminal-cell count. The cut can land inside a wide glyph and remove visible CJK text.
Complete minimal example
import asyncio
from rich.cells import cell_len
from rich.segment import Segment
from textual._segment_tools import line_trim
from textual.app import App, ComposeResult
from textual.widgets import Static
def segment_text(segments: list[Segment]) -> str:
return "".join(segment.text for segment in segments)
for segments in (
[Segment("ab"), Segment("中中")],
[Segment("ab"), Segment("中")],
):
result = segment_text(line_trim(segments, start=False, end=True))
print(repr(result), cell_len(result))
class Repro(App[None]):
def compose(self) -> ComposeResult:
yield Static("xxxxxx\nab中中\nyyyyyy")
async def main() -> None:
app = Repro()
async with app.run_test(size=(6, 5)) as pilot:
app.query_one(Static).styles.outline = ("round", "red")
await pilot.pause()
lines = [
"".join(segment.text for segment in strip)
for strip in app.screen._compositor.render_strips(app.screen.size)
]
print(repr(lines[1]))
asyncio.run(main())
Actual output:
'ab ' 3
'ab' 2
'│b │'
Removing one terminal cell should retain five cells from ab中中 ('ab中 ') and three cells from ab中 ('ab '). In the end-to-end render, both 中 characters disappear; the corresponding content line should retain one of them ('│b中 │').
Investigation and proposed direction
The end branch of line_trim() in src/textual/_segment_tools.py currently calls:
last_segment.split_cells(len(last_segment.text) - 1)
Segment.split_cells() expects a cell offset, but len(text) counts Unicode code points. The start branch already passes a cell count. A focused correction appears to be:
last_segment.split_cells(cell_len(last_segment.text) - 1)
cell_len is already imported by the module. Regression coverage can exercise ASCII, one and two trailing wide characters, and the existing start behavior. Could @willmcgugan confirm that preserving the remaining cells with Rich's space placeholder is the intended behavior? No PR has been opened pending approval under the project's AI policy.
Environment
- Windows
- CPython 3.14.6
- Textual 8.2.8 (editable from the
maincommit above) - Rich 15.0.0
- Reproduced both with direct segment calls and headless
App.run_test()
Disclosure: this report and its reproduction were prepared and verified with AI assistance (OpenCode, GPT-5.6 Sol).
- Lingua principale
- Python
- Stelle
- 37.6k
- Fork
- 1.4k
- Metriche di merge delle PR
- Nessuna PR unita negli ultimi 30g
Preparare l'ambiente
- Nessun Dockerfile né file Docker Compose
- Ha un modello di pull request
- Leggi la guida per i contributori
Come iniziare
- Leggi tutta la issue e poi la guida ai contributi del progetto.
- Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
- Fai un fork del repository e lavora su un branch.
- Apri una pull request che faccia riferimento al numero della issue.
Altre issue di Textualize/textual
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 78/100
Textualize/textual#6753 · 1 commento ·
-
8.2.8: _parse_extended_key crashes the input thread on Kitty colon sub-parameters (key:shifted:base, mods:event) — ValueError in int(), app panicsForse già presa @NavpreetSSidhu l’ha presa 10 giorni fa. Aperta
Difficoltà 2/5 1-3 ore Idoneità per principianti 74/100
Textualize/textual#6746 · 3 commenti ·
-
text boxes never stop listeningForse di nuovo libera Una pull request per questa issue è stata chiusa senza essere unita. Aperta
Difficoltà 2/5 1-3 ore Idoneità per principianti 88/100
Textualize/textual#6744 · 3 commenti ·
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 72/100
Textualize/textual#6738 · 4 commenti ·
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 72/100
Textualize/textual#6734 · 3 commenti ·
Tutte le issue di Textualize/textual
Issue simili
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 78/100
huggingface/accelerate#4511 ·
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 84/100
pylint-dev/pylint#11791 ·
I maintainer di solito rispondono entro 1 giorno
-
Rasterio granule reads never retry, so one 503 (Service Unavailable) fails the whole requestForse già presa @chuckwondo l’ha presa oggi. Aperta
Difficoltà 2/5 1-3 ore Idoneità per principianti 75/100
developmentseed/titiler-cmr#305 ·
I maintainer di solito rispondono entro 1 giorno
-
community enhancement
Difficoltà 2/5 1-3 ore Idoneità per principianti 78/100
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 78/100
I maintainer di solito rispondono entro 1 giorno