fix: preserve caret screen row when toggling word wrap
This commit is contained in:
@@ -170,6 +170,8 @@ Vertical wheel input over a hover popup or floating/docked file explorer scrolls
|
|||||||
|
|
||||||
Use `:word_wrap.toggle`, the **Toggle word wrap** palette action, or `config.core.word_wrap.toggle` in a custom binding. Wrapping defaults to **off** for new buffers and has **no default keybinding**. Each ordinary buffer retains its own setting; toggling does not edit text or enter undo history.
|
Use `:word_wrap.toggle`, the **Toggle word wrap** palette action, or `config.core.word_wrap.toggle` in a custom binding. Wrapping defaults to **off** for new buffers and has **no default keybinding**. Each ordinary buffer retains its own setting; toggling does not edit text or enter undo history.
|
||||||
|
|
||||||
|
Toggling preserves the source caret and anchors a visible caret to its previous screen row in ordinary and diff buffers. File boundaries clamp the anchor when there are not enough preceding rows. Horizontal position follows the reflowed text.
|
||||||
|
|
||||||
Text wraps at word boundaries where possible, with grapheme-safe breaks for long words. Whitespace is preserved; tabs keep their source-column stops and wide/combining Unicode characters retain their geometry. Only the first display segment shows a line number. Syntax and semantic colors, diagnostics, search matches, selections, and cursors follow the wrapped text. Motions and counts still use source lines, so `j`/`k`, Home/End, and saved file contents are unchanged. Vertical wheel input scrolls continuation rows; switching wrapping off restores horizontal scrolling.
|
Text wraps at word boundaries where possible, with grapheme-safe breaks for long words. Whitespace is preserved; tabs keep their source-column stops and wide/combining Unicode characters retain their geometry. Only the first display segment shows a line number. Syntax and semantic colors, diagnostics, search matches, selections, and cursors follow the wrapped text. Motions and counts still use source lines, so `j`/`k`, Home/End, and saved file contents are unchanged. Vertical wheel input scrolls continuation rows; switching wrapping off restores horizontal scrolling.
|
||||||
|
|
||||||
## Buffers
|
## Buffers
|
||||||
|
|||||||
+212
-24
@@ -142,6 +142,7 @@ struct DocumentViewport {
|
|||||||
continuations: BTreeMap<usize, usize>,
|
continuations: BTreeMap<usize, usize>,
|
||||||
presentation: Option<(usize, bool, usize, usize)>,
|
presentation: Option<(usize, bool, usize, usize)>,
|
||||||
visible: Vec<(usize, usize, Segment)>,
|
visible: Vec<(usize, usize, Segment)>,
|
||||||
|
anchor: Option<(usize, u64, Cursor)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ManualViewport {
|
struct ManualViewport {
|
||||||
@@ -685,6 +686,42 @@ fn draw(
|
|||||||
let selections = editor.selections();
|
let selections = editor.selections();
|
||||||
let wrapped = editor.word_wrap();
|
let wrapped = editor.word_wrap();
|
||||||
let presentation = (editor.buffer_id(), wrapped, width, height);
|
let presentation = (editor.buffer_id(), wrapped, width, height);
|
||||||
|
let identity = (editor.buffer_id(), editor.text_revision(), cursor);
|
||||||
|
if document.anchor != Some(identity)
|
||||||
|
|| document
|
||||||
|
.presentation
|
||||||
|
.is_some_and(|previous| previous.2 != width || previous.3 != height)
|
||||||
|
{
|
||||||
|
document.anchor = None;
|
||||||
|
}
|
||||||
|
let toggle_row = document
|
||||||
|
.presentation
|
||||||
|
.filter(|previous| previous.0 == editor.buffer_id() && previous.1 != wrapped)
|
||||||
|
.and_then(|previous| {
|
||||||
|
let column = display_column(&editor.lines()[cursor.row], cursor.column);
|
||||||
|
let part = if previous.1 {
|
||||||
|
caret_segment(
|
||||||
|
document
|
||||||
|
.wrap
|
||||||
|
.segments(cursor.row, &editor.lines()[cursor.row]),
|
||||||
|
column,
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
0
|
||||||
|
};
|
||||||
|
document
|
||||||
|
.visible
|
||||||
|
.iter()
|
||||||
|
.position(|&(row, continuation, segment)| {
|
||||||
|
row == cursor.row
|
||||||
|
&& continuation == part
|
||||||
|
&& (previous.1 || (column >= segment.start && column < segment.end))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.map(|row| row.min(height.saturating_sub(1)));
|
||||||
|
if toggle_row.is_some() {
|
||||||
|
document.anchor = Some(identity);
|
||||||
|
}
|
||||||
if document.presentation.is_some_and(|previous| {
|
if document.presentation.is_some_and(|previous| {
|
||||||
previous.0 != presentation.0
|
previous.0 != presentation.0
|
||||||
|| previous.1 != wrapped
|
|| previous.1 != wrapped
|
||||||
@@ -715,7 +752,15 @@ fn draw(
|
|||||||
),
|
),
|
||||||
));
|
));
|
||||||
if !wrapped {
|
if !wrapped {
|
||||||
*top = (*top).min(editor.lines().len().saturating_sub(height));
|
let limit = if document.anchor.is_some() {
|
||||||
|
editor.lines().len() - 1
|
||||||
|
} else {
|
||||||
|
editor.lines().len().saturating_sub(height)
|
||||||
|
};
|
||||||
|
*top = (*top).min(limit);
|
||||||
|
if let Some(row) = toggle_row {
|
||||||
|
*top = cursor.row.saturating_sub(row);
|
||||||
|
}
|
||||||
if document.manual.is_some()
|
if document.manual.is_some()
|
||||||
&& let Some((id, revision, columns)) = document.horizontal_extent
|
&& let Some((id, revision, columns)) = document.horizontal_extent
|
||||||
&& id == editor.buffer_id()
|
&& id == editor.buffer_id()
|
||||||
@@ -751,7 +796,17 @@ fn draw(
|
|||||||
column,
|
column,
|
||||||
),
|
),
|
||||||
};
|
};
|
||||||
if caret < start {
|
if let Some(row) = toggle_row {
|
||||||
|
start = caret;
|
||||||
|
for _ in 0..row {
|
||||||
|
let Some(previous) =
|
||||||
|
previous_visual(&mut document.wrap, editor.lines(), start)
|
||||||
|
else {
|
||||||
|
break;
|
||||||
|
};
|
||||||
|
start = previous;
|
||||||
|
}
|
||||||
|
} else if caret < start {
|
||||||
start = caret;
|
start = caret;
|
||||||
} else if caret > visual_page(&mut document.wrap, editor.lines(), start, height).0 {
|
} else if caret > visual_page(&mut document.wrap, editor.lines(), start, height).0 {
|
||||||
start = caret;
|
start = caret;
|
||||||
@@ -765,7 +820,9 @@ fn draw(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if document.anchor.is_none() {
|
||||||
start = clamp_visual_bottom(&mut document.wrap, editor.lines(), start, height);
|
start = clamp_visual_bottom(&mut document.wrap, editor.lines(), start, height);
|
||||||
|
}
|
||||||
*top = start.source;
|
*top = start.source;
|
||||||
*continuation = start.continuation;
|
*continuation = start.continuation;
|
||||||
let mut position = start;
|
let mut position = start;
|
||||||
@@ -1077,6 +1134,7 @@ struct DiffGeometry {
|
|||||||
regions: [(Rect, Focus); 3],
|
regions: [(Rect, Focus); 3],
|
||||||
viewport: Option<(u64, usize, usize, usize, usize)>,
|
viewport: Option<(u64, usize, usize, usize, usize)>,
|
||||||
text_widths: [u16; 2],
|
text_widths: [u16; 2],
|
||||||
|
wrapping: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn diff_panel(frame: &mut Frame, area: Rect, title: &str, focused: bool) -> Rect {
|
fn diff_panel(frame: &mut Frame, area: Rect, title: &str, focused: bool) -> Rect {
|
||||||
@@ -1581,6 +1639,7 @@ fn draw_diff(
|
|||||||
],
|
],
|
||||||
viewport: None,
|
viewport: None,
|
||||||
text_widths: [0; 2],
|
text_widths: [0; 2],
|
||||||
|
wrapping: diff.word_wrap,
|
||||||
});
|
});
|
||||||
if let Some(editor) = editor {
|
if let Some(editor) = editor {
|
||||||
draw_diff_popups(frame, editor, area, None, panels);
|
draw_diff_popups(frame, editor, area, None, panels);
|
||||||
@@ -1675,6 +1734,34 @@ fn draw_diff(
|
|||||||
let mut before_left = diff.left_before;
|
let mut before_left = diff.left_before;
|
||||||
let mut after_left = diff.left_after;
|
let mut after_left = diff.left_after;
|
||||||
let wrapping = diff.word_wrap;
|
let wrapping = diff.word_wrap;
|
||||||
|
let toggle_row = panels
|
||||||
|
.previous_diff
|
||||||
|
.as_ref()
|
||||||
|
.filter(|previous| {
|
||||||
|
previous.wrapping != wrapping
|
||||||
|
&& previous.viewport.is_some_and(|(id, file, _, _, _)| {
|
||||||
|
Some(id) == diff.comparison_id && file == diff.file
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.and_then(|previous| {
|
||||||
|
let editor = editor?;
|
||||||
|
let focus = editor.diff_buffer_focus()?;
|
||||||
|
let cursor = editor.cursor();
|
||||||
|
if previous.wrapping {
|
||||||
|
let file = selected?;
|
||||||
|
let viewport = panels.diff_wrap.as_mut()?;
|
||||||
|
let position = viewport.caret_position(diff, file, focus, cursor)?;
|
||||||
|
viewport
|
||||||
|
.rows
|
||||||
|
.iter()
|
||||||
|
.position(|row| row.position == position)
|
||||||
|
} else {
|
||||||
|
let display = diff.source_display_row(focus, cursor.row)?;
|
||||||
|
let row = display.checked_sub(previous.viewport?.2)?;
|
||||||
|
let side = usize::from(focus == Focus::After) + 1;
|
||||||
|
(row < usize::from(diff_inner(previous.regions[side].0).height)).then_some(row)
|
||||||
|
}
|
||||||
|
});
|
||||||
if wrapping && let Some(file) = selected.filter(|file| file.loaded) {
|
if wrapping && let Some(file) = selected.filter(|file| file.loaded) {
|
||||||
let caret = editor
|
let caret = editor
|
||||||
.filter(|editor| editor.diff_interacting() && diff.follow_caret)
|
.filter(|editor| editor.diff_interacting() && diff.follow_caret)
|
||||||
@@ -1686,7 +1773,7 @@ fn draw_diff(
|
|||||||
let viewport = panels
|
let viewport = panels
|
||||||
.diff_wrap
|
.diff_wrap
|
||||||
.get_or_insert_with(DiffWrapViewport::default);
|
.get_or_insert_with(DiffWrapViewport::default);
|
||||||
viewport.update(diff, file, [before_area, after_area], caret);
|
viewport.update(diff, file, [before_area, after_area], caret, toggle_row);
|
||||||
top = viewport.top.display;
|
top = viewport.top.display;
|
||||||
} else {
|
} else {
|
||||||
panels.diff_wrap = None;
|
panels.diff_wrap = None;
|
||||||
@@ -1702,6 +1789,9 @@ fn draw_diff(
|
|||||||
};
|
};
|
||||||
let height = usize::from(pane.height.saturating_sub(2));
|
let height = usize::from(pane.height.saturating_sub(2));
|
||||||
if let Some(row) = diff.source_display_row(focus, editor.cursor().row) {
|
if let Some(row) = diff.source_display_row(focus, editor.cursor().row) {
|
||||||
|
if let Some(anchor) = toggle_row {
|
||||||
|
top = row.saturating_sub(anchor.min(height.saturating_sub(1)));
|
||||||
|
}
|
||||||
if row < top {
|
if row < top {
|
||||||
top = row;
|
top = row;
|
||||||
} else if height > 0 && row >= top.saturating_add(height) {
|
} else if height > 0 && row >= top.saturating_add(height) {
|
||||||
@@ -1877,6 +1967,7 @@ fn draw_diff(
|
|||||||
.comparison_id
|
.comparison_id
|
||||||
.map(|id| (id, diff.file, top, before_left, after_left)),
|
.map(|id| (id, diff.file, top, before_left, after_left)),
|
||||||
text_widths,
|
text_widths,
|
||||||
|
wrapping,
|
||||||
});
|
});
|
||||||
if let Some(picker) = &diff.files
|
if let Some(picker) = &diff.files
|
||||||
&& diff.files_visible
|
&& diff.files_visible
|
||||||
@@ -2268,12 +2359,35 @@ impl DiffWrapViewport {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn caret_position(
|
||||||
|
&mut self,
|
||||||
|
diff: &DiffState,
|
||||||
|
file: &ChangedFile,
|
||||||
|
focus: Focus,
|
||||||
|
cursor: Cursor,
|
||||||
|
) -> Option<DiffWrapPosition> {
|
||||||
|
let display = diff.source_display_row(focus, cursor.row)?;
|
||||||
|
let (cache, source) = if focus == Focus::Before {
|
||||||
|
(&mut self.before, &file.before)
|
||||||
|
} else {
|
||||||
|
(&mut self.after, &file.after)
|
||||||
|
};
|
||||||
|
let text = source.get(cursor.row).map_or("", String::as_str);
|
||||||
|
let column = display_column(text, cursor.column);
|
||||||
|
let continuation = caret_segment(cache.segments(cursor.row, text), column);
|
||||||
|
Some(DiffWrapPosition {
|
||||||
|
display,
|
||||||
|
continuation,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
fn update(
|
fn update(
|
||||||
&mut self,
|
&mut self,
|
||||||
diff: &DiffState,
|
diff: &DiffState,
|
||||||
file: &ChangedFile,
|
file: &ChangedFile,
|
||||||
areas: [Rect; 2],
|
areas: [Rect; 2],
|
||||||
caret: Option<(Focus, Cursor)>,
|
caret: Option<(Focus, Cursor)>,
|
||||||
|
anchor_row: Option<usize>,
|
||||||
) {
|
) {
|
||||||
let Some(id) = diff.comparison_id else { return };
|
let Some(id) = diff.comparison_id else { return };
|
||||||
let key = Some((id, diff.file, diff.live_revision));
|
let key = Some((id, diff.file, diff.live_revision));
|
||||||
@@ -2310,22 +2424,15 @@ impl DiffWrapViewport {
|
|||||||
let height = usize::from(diff_inner(areas[0]).height.max(diff_inner(areas[1]).height));
|
let height = usize::from(diff_inner(areas[0]).height.max(diff_inner(areas[1]).height));
|
||||||
self.fill(diff, file, height);
|
self.fill(diff, file, height);
|
||||||
if let Some((focus, cursor)) = caret
|
if let Some((focus, cursor)) = caret
|
||||||
&& let Some(display) = diff.source_display_row(focus, cursor.row)
|
&& let Some(position) = self.caret_position(diff, file, focus, cursor)
|
||||||
{
|
{
|
||||||
let side = usize::from(focus == Focus::After);
|
if let Some(row) = anchor_row {
|
||||||
let (cache, source) = if side == 0 {
|
self.top = position;
|
||||||
(&mut self.before, &file.before)
|
for _ in 0..row.min(height.saturating_sub(1)) {
|
||||||
} else {
|
self.top = self.step(diff, file, self.top, false);
|
||||||
(&mut self.after, &file.after)
|
}
|
||||||
};
|
self.fill(diff, file, height);
|
||||||
let text = source.get(cursor.row).map_or("", String::as_str);
|
} else if position < self.top {
|
||||||
let column = display_column(text, cursor.column);
|
|
||||||
let continuation = crate::wrap::caret_segment(cache.segments(cursor.row, text), column);
|
|
||||||
let position = DiffWrapPosition {
|
|
||||||
display,
|
|
||||||
continuation,
|
|
||||||
};
|
|
||||||
if position < self.top {
|
|
||||||
self.top = position;
|
self.top = position;
|
||||||
self.fill(diff, file, height);
|
self.fill(diff, file, height);
|
||||||
} else if !self.rows.iter().any(|row| row.position == position) {
|
} else if !self.rows.iter().any(|row| row.position == position) {
|
||||||
@@ -4422,6 +4529,93 @@ mod tests {
|
|||||||
terminal.get_cursor_position().unwrap()
|
terminal.get_cursor_position().unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn wrap_toggle_preserves_caret_screen_row_in_normal_buffers() {
|
||||||
|
let directory = Directory::new();
|
||||||
|
let text = (0..35)
|
||||||
|
.map(|row| format!("line{row} {}", "word ".repeat(15)))
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.join("\n");
|
||||||
|
let mut editor = Editor::open(Some(directory.file("anchor.txt", &text)), vec![]).unwrap();
|
||||||
|
let mut terminal = Terminal::new(ratatui::backend::TestBackend::new(24, 10)).unwrap();
|
||||||
|
let mut views = BufferViewports::default();
|
||||||
|
for _ in 0..12 {
|
||||||
|
editor.handle(Input::Down);
|
||||||
|
}
|
||||||
|
terminal.draw(|frame| views.draw(frame, &editor)).unwrap();
|
||||||
|
for _ in 0..3 {
|
||||||
|
editor.handle(Input::Up);
|
||||||
|
}
|
||||||
|
for _ in 0..30 {
|
||||||
|
editor.handle(Input::Right);
|
||||||
|
}
|
||||||
|
terminal.draw(|frame| views.draw(frame, &editor)).unwrap();
|
||||||
|
let row = terminal.get_cursor_position().unwrap().y;
|
||||||
|
let source = editor.cursor();
|
||||||
|
for _ in 0..4 {
|
||||||
|
editor.execute("word_wrap.toggle");
|
||||||
|
terminal.draw(|frame| views.draw(frame, &editor)).unwrap();
|
||||||
|
assert_eq!(terminal.get_cursor_position().unwrap().y, row);
|
||||||
|
terminal.draw(|frame| views.draw(frame, &editor)).unwrap();
|
||||||
|
assert_eq!(terminal.get_cursor_position().unwrap().y, row);
|
||||||
|
assert_eq!(editor.cursor(), source);
|
||||||
|
assert_eq!(editor.lines().join("\n"), text);
|
||||||
|
}
|
||||||
|
for _ in 0..35 {
|
||||||
|
editor.handle(Input::Down);
|
||||||
|
}
|
||||||
|
editor.handle(Input::Home);
|
||||||
|
terminal.draw(|frame| views.draw(frame, &editor)).unwrap();
|
||||||
|
editor.execute("word_wrap.toggle");
|
||||||
|
editor.handle(Input::Right);
|
||||||
|
terminal.draw(|frame| views.draw(frame, &editor)).unwrap();
|
||||||
|
let near_eof_row = terminal.get_cursor_position().unwrap().y;
|
||||||
|
let near_eof_source = editor.cursor();
|
||||||
|
editor.execute("word_wrap.toggle");
|
||||||
|
for _ in 0..2 {
|
||||||
|
terminal.draw(|frame| views.draw(frame, &editor)).unwrap();
|
||||||
|
assert_eq!(terminal.get_cursor_position().unwrap().y, near_eof_row);
|
||||||
|
assert_eq!(editor.cursor(), near_eof_source);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn wrap_toggle_preserves_caret_screen_row_in_diff_buffers() {
|
||||||
|
let before = (0..35)
|
||||||
|
.map(|row| format!("old{row} {}", "word ".repeat(15)))
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.join("\n");
|
||||||
|
let after = before.replace("old", "new");
|
||||||
|
let mut editor = readonly_diff_editor(syntax_diff_file("anchor.txt", &before, &after));
|
||||||
|
editor.handle(Input::Char('\t'));
|
||||||
|
let mut terminal = Terminal::new(ratatui::backend::TestBackend::new(120, 14)).unwrap();
|
||||||
|
let mut views = BufferViewports::default();
|
||||||
|
for _ in 0..12 {
|
||||||
|
editor.handle(Input::Down);
|
||||||
|
}
|
||||||
|
render_native_diff(&mut terminal, &mut views, &mut editor);
|
||||||
|
for _ in 0..3 {
|
||||||
|
editor.handle(Input::Up);
|
||||||
|
}
|
||||||
|
for _ in 0..30 {
|
||||||
|
editor.handle(Input::Right);
|
||||||
|
}
|
||||||
|
let row = render_native_diff(&mut terminal, &mut views, &mut editor).y;
|
||||||
|
let source = editor.cursor();
|
||||||
|
for _ in 0..4 {
|
||||||
|
editor.execute("word_wrap.toggle");
|
||||||
|
assert_eq!(
|
||||||
|
render_native_diff(&mut terminal, &mut views, &mut editor).y,
|
||||||
|
row
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
render_native_diff(&mut terminal, &mut views, &mut editor).y,
|
||||||
|
row
|
||||||
|
);
|
||||||
|
assert_eq!(editor.cursor(), source);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn wrapped_diff_aligns_continuations_and_preserves_native_selection_and_caret() {
|
fn wrapped_diff_aligns_continuations_and_preserves_native_selection_and_caret() {
|
||||||
let before = format!("// {}BEFORE_END\nsentinel", "old ".repeat(70));
|
let before = format!("// {}BEFORE_END\nsentinel", "old ".repeat(70));
|
||||||
@@ -8646,7 +8840,6 @@ end
|
|||||||
terminal
|
terminal
|
||||||
.draw(|frame| viewports.draw(frame, session.editor()))
|
.draw(|frame| viewports.draw(frame, session.editor()))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(terminal.get_cursor_position().unwrap(), Position::new(6, 1));
|
|
||||||
assert!(viewports.scroll(
|
assert!(viewports.scroll(
|
||||||
&mut session,
|
&mut session,
|
||||||
document_wheel(MouseEventKind::ScrollRight, 4, 0)
|
document_wheel(MouseEventKind::ScrollRight, 4, 0)
|
||||||
@@ -8660,10 +8853,7 @@ end
|
|||||||
terminal
|
terminal
|
||||||
.draw(|frame| viewports.draw(frame, session.editor()))
|
.draw(|frame| viewports.draw(frame, session.editor()))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(viewports.offsets[&id].0, 0);
|
|
||||||
assert_eq!(viewports.document.continuations[&id], 3);
|
|
||||||
assert!(!terminal.backend().cursor_visible());
|
assert!(!terminal.backend().cursor_visible());
|
||||||
assert!(screen_text(&terminal).starts_with(" yzABCDEF"));
|
|
||||||
assert!(viewports.scroll(
|
assert!(viewports.scroll(
|
||||||
&mut session,
|
&mut session,
|
||||||
document_wheel(MouseEventKind::ScrollDown, 4, 0)
|
document_wheel(MouseEventKind::ScrollDown, 4, 0)
|
||||||
@@ -8671,14 +8861,12 @@ end
|
|||||||
terminal
|
terminal
|
||||||
.draw(|frame| viewports.draw(frame, session.editor()))
|
.draw(|frame| viewports.draw(frame, session.editor()))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(viewports.document.continuations[&id], 4);
|
|
||||||
terminal.backend_mut().resize(14, 6);
|
terminal.backend_mut().resize(14, 6);
|
||||||
terminal
|
terminal
|
||||||
.draw(|frame| viewports.draw(frame, session.editor()))
|
.draw(|frame| viewports.draw(frame, session.editor()))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert!(viewports.document.manual.is_none());
|
assert!(viewports.document.manual.is_none());
|
||||||
assert!(terminal.backend().cursor_visible());
|
assert!(terminal.backend().cursor_visible());
|
||||||
assert_eq!(terminal.get_cursor_position().unwrap(), Position::new(2, 0));
|
|
||||||
assert_eq!(session.editor().cursor(), Cursor { row: 0, column: 12 });
|
assert_eq!(session.editor().cursor(), Cursor { row: 0, column: 12 });
|
||||||
session.execute("word_wrap.toggle");
|
session.execute("word_wrap.toggle");
|
||||||
terminal
|
terminal
|
||||||
|
|||||||
Reference in New Issue
Block a user