Add location struct

This commit is contained in:
Brendan Zabarauskas
2019-06-01 17:19:03 +10:00
parent 38119b3825
commit 7049eaa571
5 changed files with 57 additions and 27 deletions
+3 -1
View File
@@ -254,6 +254,8 @@ where
#[cfg(test)]
mod tests {
use codespan::Location;
use super::*;
#[test]
@@ -272,7 +274,7 @@ te
},
)
.unwrap();
assert_eq!((3.into(), 2.into()), source.location(pos).unwrap());
assert_eq!(Location::new(3, 2), source.location(pos).unwrap());
}
// The protocol specifies that each `character` in position is a UTF-16 character.
+11 -11
View File
@@ -247,13 +247,13 @@ impl<'a, S: AsRef<str>> MarkedSource<'a, S> {
.set_fg(Some(self.label_color(config)))
.clone();
let (start_line, start_column) = self.file.location(self.start()).expect("location_start");
let (end_line, _) = self.file.location(self.end()).expect("location_end");
let start_line_span = self.file.line_span(start_line).expect("line_span");
let end_line_span = self.file.line_span(end_line).expect("line_span");
let start = self.file.location(self.start()).expect("location_start");
let end = self.file.location(self.end()).expect("location_end");
let start_line_span = self.file.line_span(start.line).expect("line_span");
let end_line_span = self.file.line_span(end.line).expect("line_span");
// Use the length of the last line number as the gutter padding
let gutter_padding = format!("{}", end_line.number()).len();
let gutter_padding = format!("{}", end.line.number()).len();
// File name
//
@@ -271,8 +271,8 @@ impl<'a, S: AsRef<str>> MarkedSource<'a, S> {
writer,
"{file}:{line}:{column}",
file = self.file.name(),
line = start_line.number(),
column = start_column.number(),
line = start.line.number(),
column = start.column.number(),
)?;
write!(writer, "\n")?;
@@ -292,7 +292,7 @@ impl<'a, S: AsRef<str>> MarkedSource<'a, S> {
write!(
writer,
"{: >width$} │ ",
start_line.number(),
start.line.number(),
width = gutter_padding,
)?;
writer.reset()?;
@@ -305,7 +305,7 @@ impl<'a, S: AsRef<str>> MarkedSource<'a, S> {
write!(writer, "{}", source_prefix)?;
// Write marked section
let mark_len = if start_line == end_line {
let mark_len = if start.line == end.line {
// Single line
// Write marked source section
@@ -323,7 +323,7 @@ impl<'a, S: AsRef<str>> MarkedSource<'a, S> {
writer.set_color(&label_spec)?;
write!(writer, "{}", marked_source)?;
for line_index in ((start_line.to_usize() + 1)..end_line.to_usize())
for line_index in ((start.line.to_usize() + 1)..end.line.to_usize())
.map(|i| LineIndex::from(i as RawIndex))
{
// Write line number and gutter
@@ -348,7 +348,7 @@ impl<'a, S: AsRef<str>> MarkedSource<'a, S> {
write!(
writer,
"{: >width$} │ ",
end_line.number(),
end.line.number(),
width = gutter_padding,
)?;
+16 -15
View File
@@ -7,6 +7,7 @@ use std::{error, fmt, io};
use crate::index::{
ByteIndex, ByteOffset, ColumnIndex, LineIndex, LineOffset, RawIndex, RawOffset,
};
use crate::location::Location;
use crate::span::ByteSpan;
#[derive(Debug, PartialEq)]
@@ -245,7 +246,7 @@ where
}
/// Returns the line and column location of `byte`
pub fn location(&self, index: ByteIndex) -> Result<(LineIndex, ColumnIndex), ByteIndexError> {
pub fn location(&self, index: ByteIndex) -> Result<Location, ByteIndexError> {
let line_index = self.find_line(index)?;
let line_span = self.line_span(line_index).unwrap(); // line_index should be valid!
let line_slice = self.src_slice(line_span).unwrap(); // line_span should be valid!
@@ -253,7 +254,7 @@ where
let column_index =
ColumnIndex(line_slice[..byte_col.to_usize()].chars().count() as RawIndex);
Ok((line_index, column_index))
Ok(Location::new(line_index, column_index))
}
/// Returns the line index that the byte index points to
@@ -471,19 +472,19 @@ mod tests {
given: ByteIndex(0),
span: test_data.filemap.span(),
}),
Ok((LineIndex(0), ColumnIndex(0))),
Ok((LineIndex(0), ColumnIndex(6))),
Ok((LineIndex(1), ColumnIndex(0))),
Ok((LineIndex(1), ColumnIndex(5))),
Ok((LineIndex(2), ColumnIndex(0))),
Ok((LineIndex(2), ColumnIndex(0))),
Ok((LineIndex(3), ColumnIndex(0))),
Ok((LineIndex(3), ColumnIndex(3))),
Ok((LineIndex(4), ColumnIndex(0))),
Ok((LineIndex(4), ColumnIndex(5))),
Ok((LineIndex(5), ColumnIndex(0))),
Ok((LineIndex(5), ColumnIndex(6))),
Ok((LineIndex(6), ColumnIndex(0))),
Ok(Location::new(0, 0)),
Ok(Location::new(0, 6)),
Ok(Location::new(1, 0)),
Ok(Location::new(1, 5)),
Ok(Location::new(2, 0)),
Ok(Location::new(2, 0)),
Ok(Location::new(3, 0)),
Ok(Location::new(3, 3)),
Ok(Location::new(4, 0)),
Ok(Location::new(4, 5)),
Ok(Location::new(5, 0)),
Ok(Location::new(5, 6)),
Ok(Location::new(6, 0)),
Err(ByteIndexError::OutOfBounds {
given: ByteIndex(37),
span: test_data.filemap.span()
+2
View File
@@ -14,6 +14,7 @@
mod codemap;
mod filemap;
mod index;
mod location;
mod span;
pub use crate::codemap::CodeMap;
@@ -24,4 +25,5 @@ pub use crate::index::{ColumnIndex, ColumnNumber, ColumnOffset};
pub use crate::index::{Index, Offset};
pub use crate::index::{LineIndex, LineNumber, LineOffset};
pub use crate::index::{RawIndex, RawOffset};
pub use crate::location::Location;
pub use crate::span::{ByteSpan, Span};
+25
View File
@@ -0,0 +1,25 @@
#[cfg(feature = "serialization")]
use serde::{Deserialize, Serialize};
use crate::{ColumnIndex, LineIndex};
/// A location in a source file.
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serialization", derive(Deserialize, Serialize))]
#[cfg_attr(feature = "memory_usage", derive(heapsize_derive::HeapSizeOf))]
pub struct Location {
/// The line index in the source file.
pub line: LineIndex,
/// The column index in the source file.
pub column: ColumnIndex,
}
impl Location {
/// Construct a new location from a line index and a column index.
pub fn new(line: impl Into<LineIndex>, column: impl Into<ColumnIndex>) -> Location {
Location {
line: line.into(),
column: column.into(),
}
}
}