use std::{ any::Any, cell::{Cell, RefCell}, rc::Rc,}; use gpui::{size, Bounds, Point};use terminal::Terminal;use ui::{px, ContentSize, Pixels, ScrollableHandle}; #[derive(Debug)]struct ScrollHandleState { line_height: Pixels, total_lines: usize, viewport_lines: usize, display_offset: usize,} impl ScrollHandleState { fn new(terminal: &Terminal) -> Self { Self { line_height: terminal.last_content().terminal_bounds.line_height, total_lines: terminal.total_lines(), viewport_lines: terminal.viewport_lines(), display_offset: terminal.last_content().display_offset, } }} #[derive(Debug, Clone)]pub struct TerminalScrollHandle { state: Rc<RefCell<ScrollHandleState>>, pub future_display_offset: Rc<Cell<Option<usize>>>,} impl TerminalScrollHandle { pub fn new(terminal: &Terminal) -> Self { Self { state: Rc::new(RefCell::new(ScrollHandleState::new(terminal))), future_display_offset: Rc::new(Cell::new(None)), } } pub fn update(&self, terminal: &Terminal) { *self.state.borrow_mut() = ScrollHandleState::new(terminal); }} impl ScrollableHandle for TerminalScrollHandle { fn content_size(&self) -> Option<ContentSize> { let state = self.state.borrow(); Some(ContentSize { size: size(px(0.), px(state.total_lines as f32 * state.line_height.0)), scroll_adjustment: Some(Point::new(px(0.), px(0.))), }) } fn offset(&self) -> Point<Pixels> { let state = self.state.borrow(); let scroll_offset = state.total_lines - state.viewport_lines - state.display_offset; Point::new( px(0.), -px(scroll_offset as f32 * self.state.borrow().line_height.0), ) } fn set_offset(&self, point: Point<Pixels>) { let state = self.state.borrow(); let offset_delta = (point.y.0 / state.line_height.0).round() as i32; let max_offset = state.total_lines - state.viewport_lines; let display_offset = (max_offset as i32 + offset_delta).clamp(0, max_offset as i32); self.future_display_offset .set(Some(display_offset as usize)); } fn viewport(&self) -> Bounds<Pixels> { let state = self.state.borrow(); Bounds::new( Point::new(px(0.), px(0.)), size( px(0.), px(state.viewport_lines as f32 * state.line_height.0), ), ) } fn as_any(&self) -> &dyn Any { self }}
use std::{
any::Any,
cell::{Cell, RefCell},
rc::Rc,
};
use gpui::{size, Bounds, Point};
use terminal::Terminal;
use ui::{px, ContentSize, Pixels, ScrollableHandle};
#[derive(Debug)]
struct ScrollHandleState {
line_height: Pixels,
total_lines: usize,
viewport_lines: usize,
display_offset: usize,
}
impl ScrollHandleState {
fn new(terminal: &Terminal) -> Self {
Self {
line_height: terminal.last_content().terminal_bounds.line_height,
total_lines: terminal.total_lines(),
viewport_lines: terminal.viewport_lines(),
display_offset: terminal.last_content().display_offset,
}
}
}
#[derive(Debug, Clone)]
pub struct TerminalScrollHandle {
state: Rc<RefCell<ScrollHandleState>>,
pub future_display_offset: Rc<Cell<Option<usize>>>,
}
impl TerminalScrollHandle {
pub fn new(terminal: &Terminal) -> Self {
Self {
state: Rc::new(RefCell::new(ScrollHandleState::new(terminal))),
future_display_offset: Rc::new(Cell::new(None)),
}
}
pub fn update(&self, terminal: &Terminal) {
*self.state.borrow_mut() = ScrollHandleState::new(terminal);
}
}
impl ScrollableHandle for TerminalScrollHandle {
fn content_size(&self) -> Option<ContentSize> {
let state = self.state.borrow();
Some(ContentSize {
size: size(px(0.), px(state.total_lines as f32 * state.line_height.0)),
scroll_adjustment: Some(Point::new(px(0.), px(0.))),
})
}
fn offset(&self) -> Point<Pixels> {
let state = self.state.borrow();
let scroll_offset = state.total_lines - state.viewport_lines - state.display_offset;
Point::new(
px(0.),
-px(scroll_offset as f32 * self.state.borrow().line_height.0),
)
}
fn set_offset(&self, point: Point<Pixels>) {
let state = self.state.borrow();
let offset_delta = (point.y.0 / state.line_height.0).round() as i32;
let max_offset = state.total_lines - state.viewport_lines;
let display_offset = (max_offset as i32 + offset_delta).clamp(0, max_offset as i32);
self.future_display_offset
.set(Some(display_offset as usize));
}
fn viewport(&self) -> Bounds<Pixels> {
let state = self.state.borrow();
Bounds::new(
Point::new(px(0.), px(0.)),
size(
px(0.),
px(state.viewport_lines as f32 * state.line_height.0),
),
)
}
fn as_any(&self) -> &dyn Any {
self
}
}