terminal: Don’t include line breaks for soft wrap in Assistant terminal context (#25415)
> Detects and combines wrapped lines into single logical lines, more accurately representing the actual terminal content. ```shell perl -i -pe \ 's/"vscode-languageserver(\/node)?"/"\@zed-industries\/vscode-languageserver$1"/g' packages/css/lib/node/cssServerMain.js ``` <img width="518" alt="image" src="https://github.com/user-attachments/assets/52d9327c-c381-4e5f-a676-0cf84c824388" /> <img width="1314" alt="image" src="https://github.com/user-attachments/assets/0a32e1f9-7e95-482e-9beb-2e8a6c40584c" /> Closes https://github.com/zed-industries/zed/issues/25341 Release Notes: - Fixed a bug where context for the terminal assistant would add line breaks in the presence of soft wrapped lines. --------- Co-authored-by: Peter Tripp <peter@zed.dev>
This commit is contained in:
parent
021d6584cc
commit
c282acbe65
1 changed files with 55 additions and 16 deletions
|
@ -8,12 +8,12 @@ pub mod terminal_settings;
|
||||||
use alacritty_terminal::{
|
use alacritty_terminal::{
|
||||||
event::{Event as AlacTermEvent, EventListener, Notify, WindowSize},
|
event::{Event as AlacTermEvent, EventListener, Notify, WindowSize},
|
||||||
event_loop::{EventLoop, Msg, Notifier},
|
event_loop::{EventLoop, Msg, Notifier},
|
||||||
grid::{Dimensions, Scroll as AlacScroll},
|
grid::{Dimensions, Grid, Row, Scroll as AlacScroll},
|
||||||
index::{Boundary, Column, Direction as AlacDirection, Line, Point as AlacPoint},
|
index::{Boundary, Column, Direction as AlacDirection, Line, Point as AlacPoint},
|
||||||
selection::{Selection, SelectionRange, SelectionType},
|
selection::{Selection, SelectionRange, SelectionType},
|
||||||
sync::FairMutex,
|
sync::FairMutex,
|
||||||
term::{
|
term::{
|
||||||
cell::Cell,
|
cell::{Cell, Flags},
|
||||||
search::{Match, RegexIter, RegexSearch},
|
search::{Match, RegexIter, RegexSearch},
|
||||||
Config, RenderableCursor, TermMode,
|
Config, RenderableCursor, TermMode,
|
||||||
},
|
},
|
||||||
|
@ -1386,28 +1386,59 @@ impl Terminal {
|
||||||
pub fn last_n_non_empty_lines(&self, n: usize) -> Vec<String> {
|
pub fn last_n_non_empty_lines(&self, n: usize) -> Vec<String> {
|
||||||
let term = self.term.clone();
|
let term = self.term.clone();
|
||||||
let terminal = term.lock_unfair();
|
let terminal = term.lock_unfair();
|
||||||
|
let grid = terminal.grid();
|
||||||
let mut lines = Vec::new();
|
let mut lines = Vec::new();
|
||||||
let mut current_line = terminal.bottommost_line();
|
|
||||||
while lines.len() < n {
|
let mut current_line = grid.bottommost_line().0;
|
||||||
let mut line_buffer = String::new();
|
let topmost_line = grid.topmost_line().0;
|
||||||
for cell in &terminal.grid()[current_line] {
|
|
||||||
line_buffer.push(cell.c);
|
while current_line >= topmost_line && lines.len() < n {
|
||||||
}
|
let logical_line_start = self.find_logical_line_start(grid, current_line, topmost_line);
|
||||||
let line = line_buffer.trim_end();
|
let logical_line = self.construct_logical_line(grid, logical_line_start, current_line);
|
||||||
if !line.is_empty() {
|
|
||||||
lines.push(line.to_string());
|
if let Some(line) = self.process_line(logical_line) {
|
||||||
|
lines.push(line);
|
||||||
}
|
}
|
||||||
|
|
||||||
if current_line == terminal.topmost_line() {
|
// Move to the line above the start of the current logical line
|
||||||
break;
|
current_line = logical_line_start - 1;
|
||||||
}
|
|
||||||
current_line = Line(current_line.0 - 1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
lines.reverse();
|
lines.reverse();
|
||||||
lines
|
lines
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn find_logical_line_start(&self, grid: &Grid<Cell>, current: i32, topmost: i32) -> i32 {
|
||||||
|
let mut line_start = current;
|
||||||
|
while line_start > topmost {
|
||||||
|
let prev_line = Line(line_start - 1);
|
||||||
|
let last_cell = &grid[prev_line][Column(grid.columns() - 1)];
|
||||||
|
if !last_cell.flags.contains(Flags::WRAPLINE) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
line_start -= 1;
|
||||||
|
}
|
||||||
|
line_start
|
||||||
|
}
|
||||||
|
|
||||||
|
fn construct_logical_line(&self, grid: &Grid<Cell>, start: i32, end: i32) -> String {
|
||||||
|
let mut logical_line = String::new();
|
||||||
|
for row in start..=end {
|
||||||
|
let grid_row = &grid[Line(row)];
|
||||||
|
logical_line.push_str(&row_to_string(grid_row));
|
||||||
|
}
|
||||||
|
logical_line
|
||||||
|
}
|
||||||
|
|
||||||
|
fn process_line(&self, line: String) -> Option<String> {
|
||||||
|
let trimmed = line.trim_end().to_string();
|
||||||
|
if !trimmed.is_empty() {
|
||||||
|
Some(trimmed)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn focus_in(&self) {
|
pub fn focus_in(&self) {
|
||||||
if self.last_content.mode.contains(TermMode::FOCUS_IN_OUT) {
|
if self.last_content.mode.contains(TermMode::FOCUS_IN_OUT) {
|
||||||
self.write_to_pty("\x1b[I".to_string());
|
self.write_to_pty("\x1b[I".to_string());
|
||||||
|
@ -1838,6 +1869,14 @@ impl Terminal {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Helper function to convert a grid row to a string
|
||||||
|
pub fn row_to_string(row: &Row<Cell>) -> String {
|
||||||
|
row[..Column(row.len())]
|
||||||
|
.iter()
|
||||||
|
.map(|cell| cell.c)
|
||||||
|
.collect::<String>()
|
||||||
|
}
|
||||||
|
|
||||||
fn is_path_surrounded_by_common_symbols(path: &str) -> bool {
|
fn is_path_surrounded_by_common_symbols(path: &str) -> bool {
|
||||||
// Avoid detecting `[]` or `()` strings as paths, surrounded by common symbols
|
// Avoid detecting `[]` or `()` strings as paths, surrounded by common symbols
|
||||||
path.len() > 2
|
path.len() > 2
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue