Limit the number of items in the jumplist (#4750)

Previously, jumplists could grow unchecked. Every transaction is
applied to jumplist selections to ensure that they are up to date
and within document bounds, so this would cause every edit to become
more expensive as jumplist lengths increased throughout a session.
Setting a maximum number of entries limits the cost.

Vim and Neovim limit their jumplists:

* b298fe6cba/src/structs.h (L141)
* e8cc489acc/src/nvim/mark_defs.h (L57)

Notably, Kakoune does not. In Kakoune, changes are applied to jumplist
entries lazily as you hit `<C-o>`/`<C-i>` though, so Kakoune doesn't
have the same growing cost concerns. Kakoune also does not have a
concept of a View which limits the cost further.

Vim and Neovim limit to 100. This seems unreasonably high to me so I've
set this to 30 to start. We can increase if this is problematically
low.
pull/4843/head
Michael Davis 2 years ago committed by GitHub
parent 4443885b38
commit 8102c3224f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -2427,7 +2427,6 @@ fn jumplist_picker(cx: &mut Context) {
.views() .views()
.flat_map(|(view, _)| { .flat_map(|(view, _)| {
view.jumps view.jumps
.get()
.iter() .iter()
.map(|(doc_id, selection)| new_meta(view, *doc_id, selection.clone())) .map(|(doc_id, selection)| new_meta(view, *doc_id, selection.clone()))
}) })

@ -3,29 +3,35 @@ use helix_core::{
pos_at_visual_coords, visual_coords_at_pos, Position, RopeSlice, Selection, Transaction, pos_at_visual_coords, visual_coords_at_pos, Position, RopeSlice, Selection, Transaction,
}; };
use std::fmt; use std::{collections::VecDeque, fmt};
const JUMP_LIST_CAPACITY: usize = 30;
type Jump = (DocumentId, Selection); type Jump = (DocumentId, Selection);
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct JumpList { pub struct JumpList {
jumps: Vec<Jump>, jumps: VecDeque<Jump>,
current: usize, current: usize,
} }
impl JumpList { impl JumpList {
pub fn new(initial: Jump) -> Self { pub fn new(initial: Jump) -> Self {
Self { let mut jumps = VecDeque::with_capacity(JUMP_LIST_CAPACITY);
jumps: vec![initial], jumps.push_back(initial);
current: 0, Self { jumps, current: 0 }
}
} }
pub fn push(&mut self, jump: Jump) { pub fn push(&mut self, jump: Jump) {
self.jumps.truncate(self.current); self.jumps.truncate(self.current);
// don't push duplicates // don't push duplicates
if self.jumps.last() != Some(&jump) { if self.jumps.back() != Some(&jump) {
self.jumps.push(jump); // If the jumplist is full, drop the oldest item.
while self.jumps.len() >= JUMP_LIST_CAPACITY {
self.jumps.pop_front();
}
self.jumps.push_back(jump);
self.current = self.jumps.len(); self.current = self.jumps.len();
} }
} }
@ -57,8 +63,8 @@ impl JumpList {
self.jumps.retain(|(other_id, _)| other_id != doc_id); self.jumps.retain(|(other_id, _)| other_id != doc_id);
} }
pub fn get(&self) -> &[Jump] { pub fn iter(&self) -> impl Iterator<Item = &Jump> {
&self.jumps self.jumps.iter()
} }
/// Applies a [`Transaction`] of changes to the jumplist. /// Applies a [`Transaction`] of changes to the jumplist.

Loading…
Cancel
Save