Move line boundary logic into NewlinePositions

pull/2/head
Wilfred Hughes 2019-01-24 10:02:08 +07:00
parent f75c3784a5
commit 178864e416
1 changed files with 49 additions and 65 deletions

@ -74,82 +74,66 @@ impl NewlinePositions {
}
}
/// Convert absolute string ranges to line-relative ranges. If the
/// absolute range crosses a newline, split it into multiple
/// line-relative ranges.
pub fn from_ranges(self: &NewlinePositions, ranges: &[Range]) -> Vec<LineRange> {
let mut rel_positions = vec![];
for range in ranges {
let start_pos = line_position(range.start, &self.positions);
let end_pos = line_position(range.end, &self.positions);
rel_positions.extend(split_line_boundaries(start_pos, end_pos, &self.positions));
// Given a range within a string, split it into ranges where each
// range is on a single line.
fn split_line_boundaries(
self: &NewlinePositions,
start: LinePosition,
end: LinePosition,
) -> Vec<LineRange> {
let mut ranges = vec![];
if start.line == end.line {
ranges.push(LineRange {
line: start.line,
start: start.column,
end: end.column,
});
return ranges;
} else {
let first_line_end_pos = self.positions[start.line.number + 1] - 1;
let first_line_length = first_line_end_pos - self.positions[start.line.number];
ranges.push(LineRange {
line: start.line,
start: start.column,
end: first_line_length,
});
}
rel_positions
}
}
fn line_position(offset: usize, newline_positions: &[usize]) -> LinePosition {
for line_num in (0..newline_positions.len()).rev() {
if offset > newline_positions[line_num as usize] {
return LinePosition {
line: LineNumber::from(line_num as usize),
column: offset - newline_positions[line_num as usize],
};
for line_num in (start.line.number + 1)..end.line.number {
let line_end_pos = self.positions[line_num + 1] - 1;
let line_length = line_end_pos - self.positions[line_num];
ranges.push(LineRange {
line: LineNumber::from(line_num),
start: 0,
end: line_length,
});
}
}
LinePosition {
line: LineNumber::from(0),
column: offset,
}
}
// Given a range within a string, split it into ranges where each
// range is on a single line.
fn split_line_boundaries(
start: LinePosition,
end: LinePosition,
line_start_positions: &[usize],
) -> Vec<LineRange> {
let mut ranges = vec![];
if start.line == end.line {
// Last line, up to end.
ranges.push(LineRange {
line: start.line,
start: start.column,
line: end.line,
start: 0,
end: end.column,
});
return ranges;
} else {
let first_line_end_pos = line_start_positions[start.line.number + 1] - 1;
let first_line_length = first_line_end_pos - line_start_positions[start.line.number];
ranges.push(LineRange {
line: start.line,
start: start.column,
end: first_line_length,
});
}
for line_num in (start.line.number + 1)..end.line.number {
let line_end_pos = line_start_positions[line_num + 1] - 1;
let line_length = line_end_pos - line_start_positions[line_num];
ranges.push(LineRange {
line: LineNumber::from(line_num),
start: 0,
end: line_length,
});
ranges
}
// Last line, up to end.
ranges.push(LineRange {
line: end.line,
start: 0,
end: end.column,
});
/// Convert absolute string ranges to line-relative ranges. If the
/// absolute range crosses a newline, split it into multiple
/// line-relative ranges.
pub fn from_ranges(self: &NewlinePositions, ranges: &[Range]) -> Vec<LineRange> {
let mut rel_positions = vec![];
for range in ranges {
let start_pos = self.from_offset(range.start);
let end_pos = self.from_offset(range.end);
ranges
rel_positions.extend(self.split_line_boundaries(start_pos, end_pos));
}
rel_positions
}
}
#[test]