@@ -90,17 +90,17 @@ impl Default for Cell {
90/// use helix_view::graphics::{Rect, Color, Style, Modifier};
90/// use helix_view::graphics::{Rect, Color, Style, Modifier};
92/// let mut buf = Buffer::empty(Rect{x: 0, y: 0, width: 10, height: 5});
92/// let mut buf = Buffer::empty(Rect{x: 0, y: 0, width: 10, height: 5});
93−/// buf.get_mut(0, 2).set_symbol("x");
93+/// buf[(0, 2)].set_symbol("x");
94−/// assert_eq!(buf.get(0, 2).symbol, "x");
94+/// assert_eq!(buf[(0, 2)].symbol, "x");
95/// buf.set_string(3, 0, "string", Style::default().fg(Color::Red).bg(Color::White));
95/// buf.set_string(3, 0, "string", Style::default().fg(Color::Red).bg(Color::White));
96−/// assert_eq!(buf.get(5, 0), &Cell{
96+/// assert_eq!(buf[(5, 0)], Cell{
97/// symbol: String::from("r"),
97/// symbol: String::from("r"),
98/// fg: Color::Red,
98/// fg: Color::Red,
99/// bg: Color::White,
99/// bg: Color::White,
100/// modifier: Modifier::empty()
100/// modifier: Modifier::empty()
102−/// buf.get_mut(5, 0).set_char('x');
102+/// buf[(5, 0)].set_char('x');
103−/// assert_eq!(buf.get(5, 0).symbol, "x");
103+/// assert_eq!(buf[(5, 0)].symbol, "x");
105#[derive(Debug, Default, Clone, PartialEq)]
105#[derive(Debug, Default, Clone, PartialEq)]
106pub struct Buffer {
106pub struct Buffer {
@@ -162,15 +162,38 @@ impl Buffer {
164 /// Returns a reference to Cell at the given coordinates
164 /// Returns a reference to Cell at the given coordinates
165− pub fn get(&self, x: u16, y: u16) -> &Cell {
165+ pub fn get(&self, x: u16, y: u16) -> Option<&Cell> {
166− let i = self.index_of(x, y);
167− &self.content[i]
166+ self.index_of_opt(x, y).map(|i| &self.content[i])
170 /// Returns a mutable reference to Cell at the given coordinates
169 /// Returns a mutable reference to Cell at the given coordinates
171− pub fn get_mut(&mut self, x: u16, y: u16) -> &mut Cell {
170+ pub fn get_mut(&mut self, x: u16, y: u16) -> Option<&mut Cell> {
172− let i = self.index_of(x, y);
173− &mut self.content[i]
171+ self.index_of_opt(x, y).map(|i| &mut self.content[i])
174+ /// Tells whether the global (x, y) coordinates are inside the Buffer's area.
176+ /// Global coordinates are offset by the Buffer's area offset (`x`/`y`).
181+ /// # use helix_tui::buffer::Buffer;
182+ /// # use helix_view::graphics::Rect;
183+ /// let rect = Rect::new(200, 100, 10, 10);
184+ /// let buffer = Buffer::empty(rect);
185+ /// // Global coordinates inside the Buffer's area
186+ /// assert!(buffer.in_bounds(209, 100));
187+ /// // Global coordinates outside the Buffer's area
188+ /// assert!(!buffer.in_bounds(210, 100));
191+ /// Global coordinates are offset by the Buffer's area offset (`x`/`y`).
192+ pub fn in_bounds(&self, x: u16, y: u16) -> bool {
193+ x >= self.area.left()
194+ && x < self.area.right()
195+ && y >= self.area.top()
196+ && y < self.area.bottom()
176 /// Returns the index in the Vec<Cell> for the given global (x, y) coordinates.
199 /// Returns the index in the Vec<Cell> for the given global (x, y) coordinates.
@@ -184,7 +207,7 @@ impl Buffer {
184 /// # use helix_view::graphics::Rect;
207 /// # use helix_view::graphics::Rect;
185 /// let rect = Rect::new(200, 100, 10, 10);
208 /// let rect = Rect::new(200, 100, 10, 10);
186 /// let buffer = Buffer::empty(rect);
209 /// let buffer = Buffer::empty(rect);
187− /// // Global coordinates to the top corner of this buffer's area
210+ /// // Global coordinates to the top corner of this Buffer's area
188 /// assert_eq!(buffer.index_of(200, 100), 0);
211 /// assert_eq!(buffer.index_of(200, 100), 0);
@@ -193,10 +216,7 @@ impl Buffer {
193 /// Panics when given an coordinate that is outside of this Buffer's area.
216 /// Panics when given an coordinate that is outside of this Buffer's area.
194 pub fn index_of(&self, x: u16, y: u16) -> usize {
217 pub fn index_of(&self, x: u16, y: u16) -> usize {
195 debug_assert!(
218 debug_assert!(
196− x >= self.area.left()
219+ self.in_bounds(x, y),
197− && x < self.area.right()
198− && y >= self.area.top()
199− && y < self.area.bottom(),
200 "Trying to access position outside the buffer: x={}, y={}, area={:?}",
220 "Trying to access position outside the buffer: x={}, y={}, area={:?}",
@@ -205,6 +225,16 @@ impl Buffer {
205 ((y - self.area.y) * self.area.width + (x - self.area.x)) as usize
225 ((y - self.area.y) * self.area.width + (x - self.area.x)) as usize
228+ /// Returns the index in the Vec<Cell> for the given global (x, y) coordinates,
229+ /// or `None` if the coordinates are outside the buffer's area.
230+ fn index_of_opt(&self, x: u16, y: u16) -> Option<usize> {
231+ if self.in_bounds(x, y) {
232+ Some(self.index_of(x, y))
208 /// Returns the (global) coordinates of a cell given its index
238 /// Returns the (global) coordinates of a cell given its index
210 /// Global coordinates are offset by the Buffer's area offset (`x`/`y`).
240 /// Global coordinates are offset by the Buffer's area offset (`x`/`y`).
@@ -278,6 +308,11 @@ impl Buffer {
279 S: AsRef<str>,
309 S: AsRef<str>,
311+ // prevent panic if out of range
312+ if !self.in_bounds(x, y) || width == 0 {
281 let mut index = self.index_of(x, y);
316 let mut index = self.index_of(x, y);
282 let mut x_offset = x as usize;
317 let mut x_offset = x as usize;
283 let width = if ellipsis { width - 1 } else { width };
318 let width = if ellipsis { width - 1 } else { width };
@@ -372,7 +407,7 @@ impl Buffer {
372 pub fn set_background(&mut self, area: Rect, color: Color) {
407 pub fn set_background(&mut self, area: Rect, color: Color) {
373 for y in area.top()..area.bottom() {
408 for y in area.top()..area.bottom() {
374 for x in area.left()..area.right() {
409 for x in area.left()..area.right() {
375− self.get_mut(x, y).set_bg(color);
410+ self[(x, y)].set_bg(color);
@@ -380,7 +415,7 @@ impl Buffer {
380 pub fn set_style(&mut self, area: Rect, style: Style) {
415 pub fn set_style(&mut self, area: Rect, style: Style) {
381 for y in area.top()..area.bottom() {
416 for y in area.top()..area.bottom() {
382 for x in area.left()..area.right() {
417 for x in area.left()..area.right() {
383− self.get_mut(x, y).set_style(style);
418+ self[(x, y)].set_style(style);
@@ -408,7 +443,7 @@ impl Buffer {
408 pub fn clear(&mut self, area: Rect) {
443 pub fn clear(&mut self, area: Rect) {
409 for x in area.left()..area.right() {
444 for x in area.left()..area.right() {
410 for y in area.top()..area.bottom() {
445 for y in area.top()..area.bottom() {
411− self.get_mut(x, y).reset();
446+ self[(x, y)].reset();
@@ -417,7 +452,7 @@ impl Buffer {
417 pub fn clear_with(&mut self, area: Rect, style: Style) {
452 pub fn clear_with(&mut self, area: Rect, style: Style) {
418 for x in area.left()..area.right() {
453 for x in area.left()..area.right() {
419 for y in area.top()..area.bottom() {
454 for y in area.top()..area.bottom() {
420− let cell = self.get_mut(x, y);
455+ let cell = &mut self[(x, y)];
421 cell.reset();
456 cell.reset();
422 cell.set_style(style);
457 cell.set_style(style);
@@ -509,6 +544,22 @@ impl Buffer {
547+impl std::ops::Index<(u16, u16)> for Buffer {
550+ fn index(&self, (x, y): (u16, u16)) -> &Self::Output {
551+ let i = self.index_of(x, y);
556+impl std::ops::IndexMut<(u16, u16)> for Buffer {
557+ fn index_mut(&mut self, (x, y): (u16, u16)) -> &mut Self::Output {
558+ let i = self.index_of(x, y);
559+ &mut self.content[i]
512#[cfg(test)]
563#[cfg(test)]
513mod tests {
564mod tests {
514 use super::*;
565 use super::*;