};
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
-enum FilePosition {
- Coarse(isize), // bottom of this item is at bottom of screen
- Fine(isize, usize), // line #n of this item is just off bottom of screen
+struct FilePosition {
+ item: isize, // The selected item in the file
+ line: usize, // The line number within that item
+
+ // 'line' only makes sense for a particular render width, because
+ // when items are rewrapped to a different width, their line
+ // numbers change. So we also store the width for which 'line'
+ // makes sense. Whenever we render at a different width, we must
+ // reset 'line' to the bottom of the current item.
+ //
+ // Setting this to None is a special case. It means that if
+ // line==0 then we focus the top of the item, otherwise we focus
+ // the bottom
+ width: Option<usize>,
}
impl FilePosition {
- fn item(&self) -> isize {
- match self {
- FilePosition::Coarse(item) => *item,
- FilePosition::Fine(item, _) => *item,
- }
+ fn item_top(item: isize) -> Self {
+ FilePosition { item, line: 0, width: None }
+ }
+ fn item_bottom(item: isize) -> Self {
+ FilePosition { item, line: 1, width: None }
}
}
contents.update_items(client);
// FIXME: once we have an LDB, that's where initial pos comes from
- let initial_pos = FilePosition::Coarse(contents.last_index() as isize);
+ let initial_pos = FilePosition::item_bottom(
+ contents.last_index() as isize);
let ff = File {
contents,
let (w, h) = self.last_size.expect(
"ensure_enough_rendered before resize");
- let (item, line) = self.refine_pos(w);
+ self.update_pos_for_size(w, h);
- let mut item = item;
+ let mut item = self.pos.item;
let mut lines_rendered = 0;
// We count most items we render for their full height, but
// not the one we can only see the top segment of
- let mut line_count_override = Some(line);
+ let mut line_count_override = Some(self.pos.line);
loop {
let item_height = self.ensure_item_rendered(item, w).len();
}
}
- fn refine_pos(&mut self, w: usize) -> (isize, usize) {
- let (newpos, item, line) = match self.pos {
- pos @ FilePosition::Fine(item, line) => (pos, item, line),
- FilePosition::Coarse(item) => {
- let rendered = self.ensure_item_rendered(item, w);
- let line = rendered.len();
- (FilePosition::Fine(item, line), item, line)
- }
+ fn update_pos_for_size(&mut self, w: usize, h: usize) {
+ if self.pos.width == None && self.pos.line == 0 {
+ // Special case: look at the _top_ of the item
+ self.pos.width = Some(w);
+ self.move_down(h.saturating_sub(1));
+ } else if self.pos.width != Some(w) {
+ let rendered = self.ensure_item_rendered(self.pos.item, w);
+ self.pos.line = rendered.len();
+ self.pos.width = Some(w);
};
-
- self.pos = newpos;
- (item, line)
- }
-
- fn coarsen_pos(&mut self) {
- let newpos = match self.pos {
- pos @ FilePosition::Coarse(_) => pos,
- FilePosition::Fine(item, _line) => FilePosition::Coarse(item),
- };
-
- self.pos = newpos;
+ dbg!(self.pos);
}
fn fix_overshoot_at_top(&mut self) {
fn at_top(&mut self) -> bool { self.ensure_enough_rendered().is_some() }
fn move_up(&mut self, distance: usize) {
- let (w, _h) = self.last_size.expect("move_up before resize");
- let (item, line) = match self.pos {
- FilePosition::Fine(item, line) => (item, line),
- _ => panic!("coarse position reached move_up()"),
- };
+ let (w, h) = self.last_size.expect("move_up before resize");
+ self.update_pos_for_size(w, h);
- let mut item = item;
- let mut line = line;
let mut remaining = distance;
while remaining > 0 {
- let this = min(line, remaining);
+ let this = min(self.pos.line, remaining);
remaining -= this;
- line -= this;
- if line == 0 {
- if item <= self.contents.first_index() {
+ self.pos.line -= this;
+ if self.pos.line == 0 {
+ if self.pos.item <= self.contents.first_index() {
break;
}
- item -= 1;
- line = self.ensure_item_rendered(item, w).len();
+ self.pos.item -= 1;
+ self.pos.line = self.ensure_item_rendered(self.pos.item, w)
+ .len();
}
}
- self.pos = FilePosition::Fine(item, line);
self.fix_overshoot_at_top();
self.after_setting_pos();
}
fn move_down_inner(&mut self, distance: usize) {
- let (w, _h) = self.last_size.expect("move_down before resize");
- let (item, line) = match self.pos {
- FilePosition::Fine(item, line) => (item, line),
- _ => panic!("coarse position reached move_down()"),
- };
+ let (w, h) = self.last_size.expect("move_down before resize");
+ self.update_pos_for_size(w, h);
- let mut item = item;
- let mut line = line;
let mut remaining = distance;
while remaining > 0 {
- let mut len = self.ensure_item_rendered(item, w).len();
- if line == len {
- if item >= self.contents.last_index() {
+ let mut len = self.ensure_item_rendered(self.pos.item, w).len();
+ if self.pos.line == len {
+ if self.pos.item >= self.contents.last_index() {
break;
}
- item += 1;
- line = 0;
- len = self.ensure_item_rendered(item, w).len();
+ self.pos.item += 1;
+ self.pos.line = 0;
+ len = self.ensure_item_rendered(self.pos.item, w).len();
}
- let this = min(remaining, len - line);
+ let this = min(remaining, len - self.pos.line);
remaining -= this;
- line += this;
+ self.pos.line += this;
}
- self.pos = FilePosition::Fine(item, line);
self.ensure_enough_rendered();
}
}
fn goto_top(&mut self) {
- self.pos = FilePosition::Fine(self.contents.first_index(), 0);
+ self.pos = FilePosition::item_top(self.contents.first_index());
self.fix_overshoot_at_top();
self.after_setting_pos();
}
fn goto_bottom(&mut self) {
- let (w, _h) = self.last_size.expect("goto_bottom before resize");
- let item = self.contents.last_index();
- let line = self.ensure_item_rendered(item, w).len();
- self.pos = FilePosition::Fine(item, line);
+ self.pos = FilePosition::item_bottom(self.contents.last_index());
self.ensure_enough_rendered();
self.after_setting_pos();
}
if !any_new {
// Can't extend this any further into the past
self.contents.extender = None;
- if self.pos.item() < self.contents.origin {
- self.coarsen_pos();
- if self.pos.item() <
- self.contents.first_index()
- {
- self.pos = FilePosition::Coarse(
- self.contents.first_index());
- }
+ if self.pos.item < self.contents.first_index() {
+ self.pos = FilePosition::item_top(
+ self.contents.first_index());
}
}
purpose: SelectionPurpose, client: &mut Client)
-> LogicalAction
{
- let item = self.pos.item();
+ let item = self.pos.item;
let selection =
self.last_selectable_above(htype, item).or_else(
|| self.first_selectable_below(htype, item + 1));
fn resize(&mut self, w: usize, h: usize) {
if self.last_size != Some((w, h)) {
self.last_size = Some((w, h));
- self.coarsen_pos();
self.rendered.clear();
+ self.update_pos_for_size(w, h);
+ self.fix_overshoot_at_top();
}
self.ensure_enough_rendered();
self.after_setting_pos();
-> (Vec<ColouredString>, CursorPosition) {
assert_eq!(self.last_size, Some((w, h)),
"last resize() inconsistent with draw()");
- let (start_item, start_line) = match self.pos {
- FilePosition::Fine(item, line) => (item, line),
- _ => panic!("coarse position reached draw()"),
- };
+ assert_eq!(self.pos.width, Some(w),
+ "file position inconsistent with draw()");
+ let (start_item, start_line) = (self.pos.item, self.pos.line);
let mut item = start_item;
let mut lines = Vec::new();