linebender / linebender/parley
Editor: Adding a newline in RTL doesn't advance the cursor until another character is added too
Nobody has claimed this yet.
- Dominant language
- Rust
- Stars
- 736
- Forks
- 120
- Avg merge
- 1d 3h
- Merged PRs (30d)
- 53
Description
Somewhat crude repro (sorry!) in Parley 0.8.0 and 0.9.0:
```rust
use parley::{FontContext, LayoutContext, PlainEditor};
pub fn repro() {
do_repro1("a");
do_repro2("a");
do_repro1("Ж");
do_repro2("Ж");
do_repro1("א");
do_repro2("א");
do_repro1("ﻉ");
do_repro2("ﻉ");
}
fn do_repro1(character: &'static str) {
let mut font_ctx = FontContext::new();
font_ctx.collection.load_system_fonts();
let mut layout_ctx = LayoutContext::<()>::new();
let mut editor = PlainEditor::new(14.0);
let mut driver = editor.driver(&mut font_ctx, &mut layout_ctx);
driver.insert_or_replace_selection(character);
driver.insert_or_replace_selection(character);
driver.insert_or_replace_selection(character);
driver.insert_or_replace_selection("\n");
let cursor = editor.cursor_geometry(1.0);
let layout = editor.layout(&mut font_ctx, &mut layout_ctx);
println!(
"1: character: '{}' - cursor: ({}, {}) - height: {}, is_rtl: {}, line count: {}",
character,
cursor.unwrap().x0,
cursor.unwrap().y0,
layout.height(),
layout.is_rtl(),
layout.len()
);
}
fn do_repro2(character: &'static str) {
let mut font_ctx = FontContext::new();
font_ctx.collection.load_system_fonts();
let mut layout_ctx = LayoutContext::<()>::new();
let mut editor = PlainEditor::new(14.0);
let mut driver = editor.driver(&mut font_ctx, &mut layout_ctx);
driver.insert_or_replace_selection(character);
driver.insert_or_replace_selection(character);
driver.insert_or_replace_selection(character);
driver.insert_or_replace_selection("\n");
driver.insert_or_replace_selection(character);
let cursor = editor.cursor_geometry(1.0);
let layout = editor.layout(&mut font_ctx, &mut layout_ctx);
println!(
"2: character: '{}' - cursor: ({:.2}, {:.2}) - height: {}, is_rtl: {}, line count: {}",
character,
cursor.unwrap().x0,
cursor.unwrap().y0,
layout.height(),
layout.is_rtl(),
layout.len()
);
}
```
Output:
```
1: character: 'a' - cursor: (0, 16) - height: 32.197266, is_rtl: false, line count: 2
2: character: 'a' - cursor: (7.79, 16.00) - height: 32.197266, is_rtl: false, line count: 2
1: character: 'Ж' - cursor: (0, 16) - height: 32.197266, is_rtl: false, line count: 2
2: character: 'Ж' - cursor: (12.93, 16.00) - height: 32.197266, is_rtl: false, line count: 2
1: character: 'א' - cursor: (0, 0) - height: 32.197266, is_rtl: true, line count: 2
2: character: 'א' - cursor: (15.76, 16.00) - height: 32.197266, is_rtl: true, line count: 2
1: character: 'ﻉ' - cursor: (0, 0) - height: 32.197266, is_rtl: true, line count: 2
2: character: 'ﻉ' - cursor: (15.23, 16.00) - height: 32.197266, is_rtl: true, line count: 2
```
Observe that in the RTL languages, the cursor in the first pass stays at (0, 0) when I would expect it to be down at y=16.
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by running the Rust reproduction using PlainEditor, insert_or_replace_selection, cursor_geometry, and layout, then inspect where cursor geometry is calculated for RTL text after a newline. Done means the first pass places the RTL cursor on the second line at y=16, without requiring another character to be inserted, while preserving the shown behavior for other characters.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust
- Domain
- internationalization
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 65/100