1
1
mirror of https://github.com/wez/wezterm.git synced 2024-12-23 13:21:38 +03:00

support MarkEndOfPromptAndStartOfInputUntilEndOfLine semantic mode

It's a little ambiguous whether we should cancel the mode when moving
the cursor explicitly; I opted to do it when we move it due to newline
processing, or when its y position is changed.

refs: #1539
This commit is contained in:
Wez Furlong 2022-01-16 12:49:19 -07:00
parent c6acd544ed
commit 3ee9270e3c
3 changed files with 69 additions and 4 deletions

View File

@ -253,6 +253,8 @@ pub struct TerminalState {
/// printed character
wrap_next: bool,
clear_semantic_attribute_on_newline: bool,
/// If true, writing a character inserts a new cell
insert: bool,
@ -452,6 +454,7 @@ impl TerminalState {
left_and_right_margins: 0..size.physical_cols,
left_and_right_margin_mode: false,
wrap_next: false,
clear_semantic_attribute_on_newline: false,
// We default auto wrap to true even though the default for
// a dec terminal is false, because it is more useful this way.
dec_auto_wrap: true,
@ -837,8 +840,18 @@ impl TerminalState {
&self.user_vars
}
fn clear_semantic_attribute_due_to_movement(&mut self) {
if self.clear_semantic_attribute_on_newline {
self.clear_semantic_attribute_on_newline = false;
self.pen.set_semantic_type(SemanticType::default());
}
}
/// Sets the cursor position to precisely the x and values provided
fn set_cursor_position_absolute(&mut self, x: usize, y: VisibleRowIndex) {
if self.cursor.y != y {
self.clear_semantic_attribute_due_to_movement();
}
self.cursor.y = y;
self.cursor.x = x;
self.cursor.seqno = self.seqno;

View File

@ -305,6 +305,7 @@ impl<'a> Performer<'a> {
}
if self.newline_mode {
self.cursor.x = 0;
self.clear_semantic_attribute_due_to_movement();
}
}
ControlCode::CarriageReturn => {
@ -315,6 +316,7 @@ impl<'a> Performer<'a> {
}
let y = self.cursor.y;
self.wrap_next = false;
self.clear_semantic_attribute_due_to_movement();
self.screen_mut().dirty_line(y, seqno);
}
@ -503,6 +505,7 @@ impl<'a> Performer<'a> {
self.pen = Default::default();
self.cursor = Default::default();
self.wrap_next = false;
self.clear_semantic_attribute_on_newline = false;
self.insert = false;
self.dec_auto_wrap = true;
self.reverse_wraparound_mode = false;
@ -657,6 +660,12 @@ impl<'a> Performer<'a> {
) => {
self.pen.set_semantic_type(SemanticType::Input);
}
OperatingSystemCommand::FinalTermSemanticPrompt(
FinalTermSemanticPrompt::MarkEndOfPromptAndStartOfInputUntilEndOfLine { .. },
) => {
self.pen.set_semantic_type(SemanticType::Input);
self.clear_semantic_attribute_on_newline = true;
}
OperatingSystemCommand::FinalTermSemanticPrompt(
FinalTermSemanticPrompt::MarkEndOfInputAndStartOfOutput { .. },
) => {
@ -667,10 +676,6 @@ impl<'a> Performer<'a> {
FinalTermSemanticPrompt::CommandStatus { .. },
) => {}
OperatingSystemCommand::FinalTermSemanticPrompt(ft) => {
log::warn!("unhandled: {:?}", ft);
}
OperatingSystemCommand::SystemNotification(message) => {
if let Some(handler) = self.alert_handler.as_mut() {
handler.alert(Alert::ToastNotification {

View File

@ -316,6 +316,53 @@ fn assert_all_contents(term: &Terminal, file: &str, line: u32, expect_lines: &[&
assert_lines_equal(file, line, &screen.all_lines(), &expect, Compare::TEXT);
}
#[test]
fn test_semantic_1539() {
use termwiz::escape::osc::FinalTermSemanticPrompt;
let mut term = TestTerm::new(5, 10, 0);
term.print(format!(
"{}prompt\r\nwoot",
OperatingSystemCommand::FinalTermSemanticPrompt(
FinalTermSemanticPrompt::MarkEndOfPromptAndStartOfInputUntilEndOfLine
)
));
assert_visible_contents(
&term,
file!(),
line!(),
&[
"prompt ",
"woot ",
" ",
" ",
" ",
],
);
k9::snapshot!(
term.get_semantic_zones().unwrap(),
"
[
SemanticZone {
start_y: 0,
start_x: 0,
end_y: 0,
end_x: 5,
semantic_type: Input,
},
SemanticZone {
start_y: 1,
start_x: 0,
end_y: 4,
end_x: 9,
semantic_type: Output,
},
]
"
);
}
#[test]
fn test_semantic() {
use termwiz::escape::osc::FinalTermSemanticPrompt;