Skip to content

Commit 00814d1

Browse files
author
Noam Lewis
committed
chunk WIP
1 parent e9516eb commit 00814d1

File tree

1 file changed

+157
-4
lines changed

1 file changed

+157
-4
lines changed

src/main.rs

Lines changed: 157 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,13 @@ mod lines {
2323
pub fn empty() -> LoadedLine {
2424
LoadedLine { chars: vec![] }
2525
}
26-
pub fn new(chars: Vec<char>) -> LoadedLine {
27-
LoadedLine { chars }
26+
pub fn new(chars: &[char]) -> LoadedLine {
27+
LoadedLine {
28+
chars: Vec::from(chars),
29+
}
30+
}
31+
pub fn from_vec(chars: Vec<char>) -> LoadedLine {
32+
LoadedLine { chars: chars }
2833
}
2934
pub fn len(&self) -> usize {
3035
self.chars.len()
@@ -56,6 +61,154 @@ mod lines {
5661
}
5762
}
5863

64+
mod chunks {
65+
66+
use crate::lines::LoadedLine;
67+
68+
pub struct Chunk<'a> {
69+
file_offset: u64,
70+
is_modified: bool,
71+
data: &'a [char],
72+
}
73+
74+
impl Chunk<'_> {
75+
pub fn from_disk(file_offset: u64, data: &[char]) -> Chunk {
76+
Chunk {
77+
file_offset,
78+
is_modified: false,
79+
data,
80+
}
81+
}
82+
83+
pub fn lines_iter(&self) -> ChunkLinesIter {
84+
ChunkLinesIter {
85+
chunk: self,
86+
offset_in_chunk: 0,
87+
}
88+
}
89+
}
90+
91+
pub struct ChunkLinesIter<'a> {
92+
chunk: &'a Chunk<'a>,
93+
offset_in_chunk: usize,
94+
}
95+
96+
impl<'a> Iterator for ChunkLinesIter<'a> {
97+
type Item = LoadedLine;
98+
99+
fn next(&mut self) -> Option<Self::Item> {
100+
for (i, c) in self
101+
.chunk
102+
.data
103+
.iter()
104+
.skip(self.offset_in_chunk)
105+
.enumerate()
106+
{
107+
if *c != '\n' {
108+
continue;
109+
}
110+
let slice = &self.chunk.data[self.offset_in_chunk..i];
111+
let line = LoadedLine::new(slice);
112+
self.offset_in_chunk = i;
113+
return Some(line);
114+
}
115+
self.offset_in_chunk = self.chunk.data.len();
116+
return None;
117+
}
118+
}
119+
impl<'a> DoubleEndedIterator for ChunkLinesIter<'a> {
120+
fn next_back(&mut self) -> Option<Self::Item> {
121+
for (i, c) in self
122+
.chunk
123+
.data
124+
.iter()
125+
.skip(self.offset_in_chunk)
126+
.rev()
127+
.enumerate()
128+
{
129+
if *c != '\n' {
130+
continue;
131+
}
132+
let slice = &self.chunk.data[self.offset_in_chunk..i];
133+
let line = LoadedLine::new(slice);
134+
self.offset_in_chunk = i;
135+
return Some(line);
136+
}
137+
self.offset_in_chunk = self.chunk.data.len();
138+
return None;
139+
}
140+
}
141+
}
142+
#[cfg(test)]
143+
mod tests {
144+
145+
use chunks::Chunk;
146+
147+
#[test]
148+
fn test_chunk_lines_iter() {
149+
let data: Vec<char> = "line1\nline2\nline3\n".chars().collect();
150+
let chunk = Chunk::from_disk(0, &data);
151+
let mut iter = chunk.lines_iter();
152+
153+
assert_eq!(
154+
iter.next().unwrap().chars_iter().collect::<String>(),
155+
"line1"
156+
);
157+
assert_eq!(
158+
iter.next().unwrap().chars_iter().collect::<String>(),
159+
"line2"
160+
);
161+
assert_eq!(
162+
iter.next().unwrap().chars_iter().collect::<String>(),
163+
"line3"
164+
);
165+
assert!(iter.next().is_none());
166+
}
167+
168+
#[test]
169+
fn test_chunk_lines_iter_empty() {
170+
let data: Vec<char> = "".chars().collect();
171+
let chunk = Chunk::from_disk(0, &data);
172+
let mut iter = chunk.lines_iter();
173+
174+
assert!(iter.next().is_none());
175+
}
176+
177+
#[test]
178+
fn test_chunk_lines_iter_no_newline() {
179+
let data: Vec<char> = "line1".chars().collect();
180+
let chunk = Chunk::from_disk(0, &data);
181+
let mut iter = chunk.lines_iter();
182+
183+
assert_eq!(
184+
iter.next().unwrap().chars_iter().collect::<String>(),
185+
"line1"
186+
);
187+
assert!(iter.next().is_none());
188+
}
189+
190+
#[test]
191+
fn test_chunk_lines_iter_double_ended() {
192+
let data: Vec<char> = "line1\nline2\nline3\n".chars().collect();
193+
let chunk = Chunk::from_disk(0, &data);
194+
let mut iter = chunk.lines_iter();
195+
196+
assert_eq!(
197+
iter.next_back().unwrap().chars_iter().collect::<String>(),
198+
"line3"
199+
);
200+
assert_eq!(
201+
iter.next_back().unwrap().chars_iter().collect::<String>(),
202+
"line2"
203+
);
204+
assert_eq!(
205+
iter.next_back().unwrap().chars_iter().collect::<String>(),
206+
"line1"
207+
);
208+
assert!(iter.next_back().is_none());
209+
}
210+
}
211+
59212
use lines::LoadedLine;
60213

61214
// TODO
@@ -65,7 +218,7 @@ use lines::LoadedLine;
65218
//
66219
// Other editors:
67220
// - emacs: gap buffer
68-
// - vim: rope
221+
// - vim: rope (https://github.com/vim/vim/blob/master/src/memline.c and https://github.com/vim/vim/blob/master/src/memfile.c)
69222
//
70223
// Idea:
71224
// List of contiguous chunks: (disk_offset, data, is_modified).
@@ -340,7 +493,7 @@ impl State {
340493
self.cursor.y += 1;
341494
self.cursor.x = 0;
342495
self.lines
343-
.insert(self.cursor.y as usize, LoadedLine::new(new_line));
496+
.insert(self.cursor.y as usize, LoadedLine::from_vec(new_line));
344497
}
345498

346499
fn draw_frame(&self, frame: &mut Frame) {

0 commit comments

Comments
 (0)