Skip to content

Commit

Permalink
make nufmt keep the comments (#18)
Browse files Browse the repository at this point in the history
* 🚧 working on keeping comments

* 🚧 splitted the comment from the code

I need to fix having multiple comments, the split works with token.span.start that may by larger than the content length. Afterwards, I need to deal with returning the code and the comment, indicating which is which and how to re-assemble once it is formatted

* ✨ finish comments in `nufmt`

---------

Co-authored-by: Auca Maillot <[email protected]>
  • Loading branch information
AucaCoyan and Auca Maillot committed Jun 9, 2023
1 parent b02b7e6 commit 113a2d2
Show file tree
Hide file tree
Showing 2 changed files with 77 additions and 11 deletions.
80 changes: 73 additions & 7 deletions src/formatting.rs
Original file line number Diff line number Diff line change
@@ -1,31 +1,67 @@
use crate::config::Config;
use log::trace;
use nu_parser::{flatten_block, parse, FlatShape};
use nu_protocol::engine::{self, StateWorkingSet};
use nu_protocol::{
ast::Block,
engine::{self, StateWorkingSet},
Span,
};

// Format an entire crate (or subset of the module tree)
// Format an array of bytes
//
// Reading the file gives you a list of bytes
pub fn format_inner(contents: &[u8], _config: &Config) -> Vec<u8> {
// nice place to measure parsing and formatting time
// nice place to measure formatting time
// let mut timer = Timer::start();
// parsing starts

// parsing starts
let engine_state = engine::EngineState::new();
let mut working_set = StateWorkingSet::new(&engine_state);

let parsed_block = parse(&mut working_set, None, contents, false);
trace!("parsed block:\n{:?}\n", &parsed_block);
trace!("parsed block:\n{:?}", &parsed_block);

// check if the block has at least 1 pipeline
if !block_has_pipilnes(&parsed_block) {
trace!("block has no pipelines!");
println!("File has no code to format.");
return contents.to_vec();
}
// flat is a list of (Span , Flatshape)
//
// Span is the piece of code. You can stringfy the contents.
// Flatshape is an enum of the type of token read by the AST.
let flat = flatten_block(&working_set, &parsed_block);
trace!("flattened block:\n{:#?}\n", &flat);
trace!("flattened block:\n{:?}", &flat);
// timer = timer.done_parsing()

// formatting starts
let mut out: Vec<u8> = vec![];

for (span, shape) in flat {
let mut start = 0;
let end_of_file = contents.len();

for (span, shape) in flat.clone().into_iter() {
// check if span skipped some bytes before the current span
if span.start > start {
trace!(
"Span didn't started on the beginning! span {0}, start: {1}",
span.start,
start
);
let skipped_contents = &contents[start..span.start];
let printable = String::from_utf8_lossy(skipped_contents).to_string();
trace!("contents: {:?}", printable);
if skipped_contents.contains(&b'#') {
trace!("This have a comment. Writing.");
out.extend(trim_ascii_whitespace(skipped_contents));
out.push(b'\n');
} else {
trace!("The contents doesn't have a '#'. Skipping.")
}
}

// get the span contents and format it
let mut c_bites = working_set.get_span_contents(span);
let content = String::from_utf8_lossy(c_bites).to_string();
trace!("shape is {shape}");
Expand Down Expand Up @@ -73,6 +109,28 @@ pub fn format_inner(contents: &[u8], _config: &Config) -> Vec<u8> {

_ => out.extend(c_bites),
}

// check if span skipped some bytes between the final spann and the end of file
if is_last_span(span, &flat) && span.end < end_of_file {
trace!(
"The last span doesn't end the file! span: {0}, end: {1}",
span.end,
end_of_file
);
let remaining_contents = &contents[span.end..end_of_file];
let printable = String::from_utf8_lossy(remaining_contents).to_string();
trace!("contents: {:?}", printable);
if remaining_contents.contains(&b'#') {
trace!("This have a comment. Writing.");
out.push(b'\n');
out.extend(trim_ascii_whitespace(remaining_contents));
} else {
trace!("The contents doesn't have a '#'. Skipping.")
}
}

// cleanup
start = span.end + 1;
}
// just before writing, append a new line to the file.
out = insert_newline(out);
Expand All @@ -97,3 +155,11 @@ pub fn trim_ascii_whitespace(x: &[u8]) -> &[u8] {
let to = x.iter().rposition(|x| !x.is_ascii_whitespace()).unwrap();
&x[from..=to]
}

fn block_has_pipilnes(block: &Block) -> bool {
!block.pipelines.is_empty()
}

fn is_last_span(span: Span, flat: &[(Span, FlatShape)]) -> bool {
span == flat.last().unwrap().0
}
8 changes: 4 additions & 4 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ pub fn format_single_file(file: &PathBuf, config: &Config) {
// write down the file to path
let mut writer = File::create(file).unwrap();
let file_bites = formatted_bytes.as_slice();
trace!("writing {:?}", formatted_bytes);
writer
.write_all(file_bites)
.expect("something went wrong writing");
Expand Down Expand Up @@ -79,10 +78,11 @@ mod test {
}

#[test]
#[ignore = "comments aren't a part of Spans,"]
fn ignore_comments() {
let nu = String::from("# this is a comment");
let expected = String::from("# this is a comment");
let nu = String::from(
"# beginning of script comment\n\n let one = 1\ndef my-func [\n param1:int # inline comment\n]{ print(param1) \n}\nmyfunc(one)\n\n\n\n\n\n# final comment\n\n\n");
let expected = String::from(
"# beginning of script comment\nlet one = 1\ndef my-func [\n param1:int # inline comment\n]{ print(param1) \n}\nmyfunc(one) \n# final comment\n");
assert_eq!(expected, format_string(&nu, &Config::default()));
}

Expand Down

0 comments on commit 113a2d2

Please sign in to comment.