Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
b3eecd1
feat(diagnostic): integrate annotate-snippets crate
legendiguess Feb 5, 2020
50e0713
feat(diagnostic): add builder api for annotate-snippets crate
legendiguess Feb 13, 2020
2438fb5
test: add insta tests for annotate_snippets_builders file functions
legendiguess Mar 20, 2020
5603810
feat: add color terminal output
legendiguess Mar 25, 2020
eadfcd4
fix: slices that do not starts from first line calculate correctly
legendiguess Apr 2, 2020
4c259c8
feat: make message of duplicate definition error look like rustc message
legendiguess Apr 2, 2020
cee6dc8
feat: possibly uninitialized variable error message look like from rustc
legendiguess Apr 3, 2020
78e9c3a
feat: access unknown field error message look like from rustc
legendiguess Apr 3, 2020
5ca654c
refactor: clean up syntax error message text
legendiguess Apr 3, 2020
3333993
refactor: unresolved value error message look like from rustc
legendiguess Apr 3, 2020
ee6676c
refactor: unresolved type error message look like from rustc
legendiguess Apr 3, 2020
d761ea1
refactor: remove part of boilerplate code in diagnostics.rs
legendiguess Apr 3, 2020
aba420e
fix: change mun terminal color environment variable to capital letters
legendiguess Apr 4, 2020
efd73bb
chore: add a trailing enter to cargo.toml
legendiguess Apr 4, 2020
b40fd0e
refactor: create to_bool function for Color instead of Into<bool> trait
legendiguess Apr 4, 2020
fff96bb
refactor: replace color argument value validation
legendiguess Apr 5, 2020
7522572
refactor: reduce code duplication in processing of color compiler option
legendiguess Apr 6, 2020
0b39653
fix: reword doc comment for color field in Config
legendiguess Apr 7, 2020
1272197
refactor: made getting syntax node ptr location in a separate function
legendiguess Apr 6, 2020
aabd485
refactor: clean up terminal color configuration code
legendiguess Apr 7, 2020
a6d8659
test(diagnostic): add tests for diagnostic errors
legendiguess Apr 7, 2020
b480867
refactor: rename diagnostics file
legendiguess Apr 8, 2020
06bd18a
fix(diagnostics_snippets): change label of default error
legendiguess Apr 8, 2020
fd1816a
refactor(diagnostics_snippets): rename error function into generic_error
legendiguess Apr 8, 2020
d9c63c1
misc: apply code review suggestions
legendiguess Apr 11, 2020
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 0 additions & 19 deletions crates/mun/src/diagnostic.rs

This file was deleted.

22 changes: 21 additions & 1 deletion crates/mun/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@
extern crate failure;

use std::cell::RefCell;
use std::env;
use std::rc::Rc;
use std::time::Duration;

use clap::{App, AppSettings, Arg, ArgMatches, SubCommand};
use mun_compiler::{Config, PathOrInline, Target};
use mun_compiler::{Config, DisplayColor, PathOrInline, Target};
use mun_runtime::{invoke_fn, ReturnTypeReflection, Runtime, RuntimeBuilder};

fn main() -> Result<(), failure::Error> {
Expand Down Expand Up @@ -40,6 +41,13 @@ fn main() -> Result<(), failure::Error> {
.takes_value(true)
.help("target triple for which code is compiled"),
)
.arg(
Arg::with_name("color")
.long("color")
.takes_value(true)
.possible_values(&["enable", "auto", "disable"])
.help("color text in terminal"),
)
.about("Compiles a local Mun file into a module"),
)
.subcommand(
Expand Down Expand Up @@ -136,6 +144,17 @@ fn compiler_options(matches: &ArgMatches) -> Result<mun_compiler::CompilerOption
_ => return Err(format_err!("Only optimization levels 0-3 are supported")),
};

let display_color = matches
.value_of("color")
.map(ToOwned::to_owned)
.or_else(|| env::var("MUN_TERMINAL_COLOR").ok())
.map(|value| match value.as_str() {
"disable" => DisplayColor::Disable,
"enable" => DisplayColor::Enable,
_ => DisplayColor::Auto,
})
.unwrap_or(DisplayColor::Auto);

Ok(mun_compiler::CompilerOptions {
input: PathOrInline::Path(matches.value_of("INPUT").unwrap().into()), // Safe because its a required arg
config: Config {
Expand All @@ -144,6 +163,7 @@ fn compiler_options(matches: &ArgMatches) -> Result<mun_compiler::CompilerOption
.map_or_else(Target::host_target, Target::search)?,
optimization_lvl,
out_dir: None,
display_color,
},
})
}
Expand Down
9 changes: 6 additions & 3 deletions crates/mun_compiler/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,13 @@ description = "Binary compilation functionality for Mun"

[dependencies]
failure = "0.1.7"

mun_codegen = { path="../mun_codegen" }
mun_syntax = { path="../mun_syntax" }
mun_errors = { path="../mun_errors" }
mun_hir = {path="../mun_hir"}
mun_target = {path="../mun_target"}
termcolor = "1.0.5"
annotate-snippets = { version = "0.6.1", features = ["color"] }
unicode-segmentation = "1.6.0"
ansi_term = "0.12.1"

[dev-dependencies]
insta = "0.13.1"
216 changes: 216 additions & 0 deletions crates/mun_compiler/src/annotate.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,216 @@
//! This module provides builders for integrating the [`annotate-snippets`] crate with Mun.
//!
//! [`annotate-snippets`]: https://docs.rs/annotate-snippets/0.6.1/annotate_snippets/

use annotate_snippets::snippet::{Annotation, AnnotationType, Slice, Snippet, SourceAnnotation};
use mun_hir::line_index::LineIndex;

use unicode_segmentation::UnicodeSegmentation;

pub struct SnippetBuilder {
snippet: Snippet,
}

impl Default for SnippetBuilder {
fn default() -> Self {
SnippetBuilder {
snippet: Snippet {
title: None,
footer: vec![],
slices: vec![],
},
}
}
}

impl SnippetBuilder {
pub fn new() -> SnippetBuilder {
SnippetBuilder::default()
}
pub fn title(mut self, title: Annotation) -> SnippetBuilder {
self.snippet.title = Some(title);
self
}
pub fn footer(mut self, footer: Annotation) -> SnippetBuilder {
self.snippet.footer.push(footer);
self
}
pub fn slice(mut self, slice: Slice) -> SnippetBuilder {
self.snippet.slices.push(slice);
self
}
pub fn build(self) -> Snippet {
self.snippet
}
}

pub struct SliceBuilder {
slice: Slice,
}

impl SliceBuilder {
pub fn new(fold: bool) -> SliceBuilder {
SliceBuilder {
slice: Slice {
source: String::new(),
line_start: 0,
origin: None,
annotations: Vec::new(),
fold,
},
}
}

pub fn origin(mut self, relative_file_path: &str) -> SliceBuilder {
self.slice.origin = Some(relative_file_path.to_string());
self
}

pub fn source_annotation(
mut self,
range: (usize, usize),
label: &str,
source_annotation_type: AnnotationType,
) -> SliceBuilder {
self.slice.annotations.push(SourceAnnotation {
range,
label: label.to_string(),
annotation_type: source_annotation_type,
});
self
}

pub fn build(mut self, source_text: &str, line_index: &LineIndex) -> Slice {
// Variable for storing the first and last line of the used source code
let mut fl_lines: Option<(u32, u32)> = None;

// Find the range of lines that include all highlighted segments
for annotation in &self.slice.annotations {
if let Some(range) = fl_lines {
fl_lines = Some((
line_index
.line_col(range.0.into())
.line
.min(line_index.line_col((annotation.range.0 as u32).into()).line),
line_index
.line_col(range.1.into())
.line
.max(line_index.line_col((annotation.range.1 as u32).into()).line),
));
} else {
fl_lines = Some((
line_index.line_col((annotation.range.0 as u32).into()).line,
line_index.line_col((annotation.range.1 as u32).into()).line,
));
}
}

if let Some(fl_lines) = fl_lines {
self.slice.line_start = fl_lines.0 as usize + 1;
let first_line_offset = line_index.line_offset(fl_lines.0);

// Extract the required range of lines
self.slice.source = line_index
.text_part(fl_lines.0, fl_lines.1, source_text, source_text.len())
.unwrap()
.to_string();

// Convert annotation ranges based on the cropped region, indexable by unicode
// graphemes (required for aligned annotations)
let convertor_function = |source: &String, annotation_range_border: usize| {
UnicodeSegmentation::graphemes(
&source[0..(annotation_range_border - first_line_offset)],
true).count()
// this addend is a fix for annotate-snippets issue number 24
+ (line_index.line_col((annotation_range_border as u32).into()).line
- fl_lines.0) as usize
};
for annotation in self.slice.annotations.iter_mut() {
annotation.range = (
convertor_function(&self.slice.source, annotation.range.0),
convertor_function(&self.slice.source, annotation.range.1),
);
}
}
self.slice
}
}

pub struct AnnotationBuilder {
annotation: Annotation,
}

impl AnnotationBuilder {
pub fn new(annotation_type: AnnotationType) -> AnnotationBuilder {
AnnotationBuilder {
annotation: Annotation {
id: None,
label: None,
annotation_type,
},
}
}

pub fn id(mut self, id: &str) -> AnnotationBuilder {
self.annotation.id = Some(id.to_string());
self
}

pub fn label(mut self, label: &str) -> AnnotationBuilder {
self.annotation.label = Some(label.to_string());
self
}

pub fn build(self) -> Annotation {
self.annotation
}
}

#[cfg(test)]
mod tests {
use super::*;
#[test]
fn annotation_builder_snapshot() {
insta::assert_debug_snapshot!(AnnotationBuilder::new(AnnotationType::Note)
.id("1")
.label("test annotation")
.build());
}
#[test]
fn slice_builder_snapshot() {
let source_code = "fn foo():float{\n48\n}";
let line_index: LineIndex = LineIndex::new(source_code);

insta::assert_debug_snapshot!(SliceBuilder::new(true)
.origin("/tmp/usr/test.mun")
.source_annotation((14, 20), "test source annotation", AnnotationType::Note)
.build(source_code, &line_index));
}
#[test]
fn snippet_builder_snapshot() {
let source_code = "fn foo():float{\n48\n}\n\nfn bar():bool{\n23\n}";
let line_index: LineIndex = LineIndex::new(source_code);

insta::assert_debug_snapshot!(SnippetBuilder::new()
.title(
AnnotationBuilder::new(AnnotationType::Note)
.id("1")
.label("test annotation")
.build()
)
.footer(
AnnotationBuilder::new(AnnotationType::Warning)
.id("2")
.label("test annotation")
.build()
)
.slice(
SliceBuilder::new(true)
.origin("/tmp/usr/test.mun")
.source_annotation((14, 20), "test source annotation", AnnotationType::Note,)
.source_annotation((35, 41), "test source annotation", AnnotationType::Error,)
.build(source_code, &line_index)
)
.build());
}
}
Loading