Allow references to be returned from lines

This commit is contained in:
Brendan Zabarauskas 2020-02-27 10:24:35 +11:00
parent fc275692b3
commit b48c8c01b7
7 changed files with 50 additions and 40 deletions

View File

@ -79,22 +79,26 @@ where
}
/// Files that can be used for pretty printing.
pub trait Files {
type FileId: Copy + PartialEq + PartialOrd + Eq + Ord + std::hash::Hash;
type Origin: std::fmt::Display;
type LineSource: AsRef<str>;
///
/// A lifetime parameter `'a` is provided to allow any of the returned values to returned by reference.
/// This is to workaround the lack of higher kinded lifetime parameters.
/// This can be ignored if this is not needed, however.
pub trait Files<'a> {
type FileId: 'a + Copy + PartialEq + PartialOrd + Eq + Ord + std::hash::Hash;
type Origin: 'a + std::fmt::Display;
type LineSource: 'a + AsRef<str>;
/// The origin of a file.
fn origin(&self, id: Self::FileId) -> Option<Self::Origin>;
fn origin(&'a self, id: Self::FileId) -> Option<Self::Origin>;
/// The line at the given index.
fn line(&self, id: Self::FileId, line_index: usize) -> Option<Line<Self::LineSource>>;
fn line(&'a self, id: Self::FileId, line_index: usize) -> Option<Line<Self::LineSource>>;
/// The index of the line at the given byte index.
fn line_index(&self, id: Self::FileId, byte_index: usize) -> Option<usize>;
fn line_index(&'a self, id: Self::FileId, byte_index: usize) -> Option<usize>;
/// The location of the given byte index.
fn location(&self, id: Self::FileId, byte_index: usize) -> Option<Location> {
fn location(&'a self, id: Self::FileId, byte_index: usize) -> Option<Location> {
let line_index = self.line_index(id, byte_index)?;
let line = self.line(id, line_index)?;
@ -165,10 +169,10 @@ where
}
}
impl<Origin, Source> Files for SimpleFile<Origin, Source>
impl<'a, Origin, Source> Files<'a> for SimpleFile<Origin, Source>
where
Origin: std::fmt::Display + Clone,
Source: AsRef<str>,
Origin: 'a + std::fmt::Display + Clone,
Source: 'a + AsRef<str>,
{
type FileId = ();
type Origin = Origin;
@ -229,10 +233,10 @@ where
}
}
impl<Origin, Source> Files for SimpleFiles<Origin, Source>
impl<'a, Origin, Source> Files<'a> for SimpleFiles<Origin, Source>
where
Origin: std::fmt::Display + Clone,
Source: AsRef<str>,
Origin: 'a + std::fmt::Display + Clone,
Source: 'a + AsRef<str>,
{
type FileId = usize;
type Origin = Origin;

View File

@ -15,10 +15,10 @@ pub use termcolor;
pub use self::config::{Chars, Config, DisplayStyle, Styles};
/// Emit a diagnostic using the given writer, context, config, and files.
pub fn emit<F: Files>(
pub fn emit<'files, F: Files<'files>>(
writer: &mut (impl WriteColor + ?Sized),
config: &Config,
files: &F,
files: &'files F,
diagnostic: &Diagnostic<F::FileId>,
) -> io::Result<()> {
use self::views::{RichDiagnostic, ShortDiagnostic};

View File

@ -20,12 +20,15 @@ where
RichDiagnostic { diagnostic }
}
pub fn emit(
pub fn emit<'files>(
&self,
files: &impl Files<FileId = FileId>,
files: &'files impl Files<'files, FileId = FileId>,
writer: &mut (impl WriteColor + ?Sized),
config: &Config,
) -> io::Result<()> {
) -> io::Result<()>
where
FileId: 'files,
{
use std::collections::BTreeMap;
use super::MarkStyle;
@ -82,12 +85,15 @@ where
ShortDiagnostic { diagnostic }
}
pub fn emit(
pub fn emit<'files>(
&self,
files: &impl Files<FileId = FileId>,
files: &'files impl Files<'files, FileId = FileId>,
writer: &mut (impl WriteColor + ?Sized),
config: &Config,
) -> io::Result<()> {
) -> io::Result<()>
where
FileId: 'files,
{
let label = &self.diagnostic.primary_label;
let origin = files
.origin(self.diagnostic.primary_label.file_id)

View File

@ -41,18 +41,18 @@ fn count_digits(mut n: usize) -> usize {
/// = expected type `Int`
/// found type `String`
/// ```
pub struct SourceSnippet<'a, F: Files> {
pub struct SourceSnippet<'a, 'files, F: Files<'files>> {
file_id: F::FileId,
ranges: Vec<(&'a Label<F::FileId>, MarkStyle)>,
notes: &'a [String],
}
impl<'a, F: Files> SourceSnippet<'a, F> {
impl<'a, 'files: 'a, F: Files<'files>> SourceSnippet<'a, 'files, F> {
pub fn new(
file_id: F::FileId,
ranges: Vec<(&'a Label<F::FileId>, MarkStyle)>,
notes: &'a [String],
) -> SourceSnippet<'a, F> {
) -> SourceSnippet<'a, 'files, F> {
SourceSnippet {
file_id,
ranges,
@ -89,7 +89,7 @@ impl<'a, F: Files> SourceSnippet<'a, F> {
pub fn emit(
&self,
files: &F,
files: &'files F,
writer: &mut (impl WriteColor + ?Sized),
config: &Config,
) -> io::Result<()> {

View File

@ -7,24 +7,24 @@ mod color_buffer;
use self::color_buffer::ColorBuffer;
pub struct TestData<F: Files> {
pub struct TestData<'files, F: Files<'files>> {
pub files: F,
pub diagnostics: Vec<Diagnostic<F::FileId>>,
}
impl<F: Files> TestData<F> {
fn emit<W: WriteColor>(&self, mut writer: W, config: &Config) -> W {
impl<'files, F: Files<'files>> TestData<'files, F> {
fn emit<W: WriteColor>(&'files self, mut writer: W, config: &Config) -> W {
for diagnostic in &self.diagnostics {
emit(&mut writer, config, &self.files, &diagnostic).unwrap();
}
writer
}
pub fn emit_color(&self, config: &Config) -> String {
pub fn emit_color(&'files self, config: &Config) -> String {
self.emit(ColorBuffer::new(), &config).into_string()
}
pub fn emit_no_color(&self, config: &Config) -> String {
pub fn emit_no_color(&'files self, config: &Config) -> String {
let buffer = self.emit(Buffer::no_color(), &config);
String::from_utf8_lossy(buffer.as_slice()).into_owned()
}

View File

@ -18,7 +18,7 @@ mod empty_spans {
use super::*;
lazy_static::lazy_static! {
static ref TEST_DATA: TestData<SimpleFile<&'static str, &'static str>> = {
static ref TEST_DATA: TestData<'static, SimpleFile<&'static str, &'static str>> = {
let file = SimpleFile::new("hello", "Hello world!\nBye world!");
let eof = file.source().len();
@ -57,7 +57,7 @@ mod multifile {
use super::*;
lazy_static::lazy_static! {
static ref TEST_DATA: TestData<SimpleFiles<&'static str, String>> = {
static ref TEST_DATA: TestData<'static, SimpleFiles<&'static str, String>> = {
let mut files = SimpleFiles::new();
let file_id1 = files.add(
@ -175,7 +175,7 @@ mod fizz_buzz {
use super::*;
lazy_static::lazy_static! {
static ref TEST_DATA: TestData<SimpleFiles<&'static str, String>> = {
static ref TEST_DATA: TestData<'static, SimpleFiles<&'static str, String>> = {
let mut files = SimpleFiles::new();
let file_id = files.add(
@ -287,7 +287,7 @@ mod tabbed {
use super::*;
lazy_static::lazy_static! {
static ref TEST_DATA: TestData<SimpleFiles<&'static str, String>> = {
static ref TEST_DATA: TestData<'static, SimpleFiles<&'static str, String>> = {
let mut files = SimpleFiles::new();
let file_id = files.add(

View File

@ -295,13 +295,13 @@ where
}
#[cfg(feature = "reporting")]
impl<Source> codespan_reporting::files::Files for Files<Source>
impl<'a, Source> codespan_reporting::files::Files<'a> for Files<Source>
where
Source: AsRef<str>,
{
type FileId = FileId;
type Origin = String;
type LineSource = String;
type LineSource = &'a str;
fn origin(&self, id: FileId) -> Option<String> {
use std::path::PathBuf;
@ -314,17 +314,17 @@ where
}
fn line(
&self,
&'a self,
id: FileId,
line_index: usize,
) -> Option<codespan_reporting::files::Line<String>> {
) -> Option<codespan_reporting::files::Line<&'a str>> {
let span = self.line_span(id, line_index as u32).ok()?;
let source = self.source_slice(id, span).ok()?;
Some(codespan_reporting::files::Line {
start: span.start().to_usize(),
number: line_index + 1,
source: source.to_owned(),
source,
})
}
}