Skip to content

Commit

Permalink
📝 Add docs for contributing and private items
Browse files Browse the repository at this point in the history
  • Loading branch information
AucaCoyan committed Jun 11, 2023
1 parent 3454d7a commit 4b97279
Show file tree
Hide file tree
Showing 6 changed files with 99 additions and 28 deletions.
4 changes: 1 addition & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,4 @@ nufmt my-file1.nu my-file2.nu my-file3.nu

## Contributing

Submit an issue, or come and say hi in the [Discord](https://discord.gg/NtAbbGn)!

You can mention @AucaCoyan who is active on this repo.
We have a [contribution guide](docs/CONTRIBUTING.md). If you still have doubts, you can mention @AucaCoyan who is active on this repo.
18 changes: 18 additions & 0 deletions docs/CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
https://discord.gg/NtAbbGn# Contributing to `nufmt`

Salutations! Thanks for coming by and the interest into this project!
We would like to order the contributions like this:

- Before you start hacking, it is important to **ask first** if your idea or bugfix is in order. Create an issue or [come and say hi in the discord](https://discord.gg/NtAbbGn). We don't bite!.

It would be sad that you do the effort to clone the project, successfully make the PR, but it wasn't in our plans or there is another PR that is currently adressing that issue.

- After the PR is submitted, the workflows will start to lint, check and test the changes. Please try to stay all green ✅.
- Sometimes we can take some time to respond. Sorry, we are few and there is much to do here!

## General guidelines and philosophy

This is a list of things we would like to have and mantain across time. Please do your best to abide by.

- Everything should be explained: rust docs, comments, drawings, pick what makes you comfortable, but it is important to make it clear. There will be always some new guy or gal into the project we want to welcome 😄.
- Use clear variable names and try to evade confusing abbreviations. Think that your peer may not be fully fluent in english 💬.
6 changes: 5 additions & 1 deletion src/config.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
//! Config module
//!
//! This keeps all the options, tweaks and dials of the configuration.

use anyhow::Result;

#[derive(Debug)]
Expand Down Expand Up @@ -34,6 +38,6 @@ impl Config {
}

/// Returns a default config.
pub fn load_config(/* file_path: Option<&Path> */) -> Result<Config> {
pub fn load(/* file_path: Option<&Path> */) -> Result<Config> {
Ok(Config::default())
}
48 changes: 36 additions & 12 deletions src/formatting.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
//! Formatting module
//!
//! In this module occurs most of the magic in `nufmt`.
//! It has functions to format slice of bytes and some help functions to separate concerns while doing the job.
//!
use crate::config::Config;
use log::trace;
use nu_parser::{flatten_block, parse, FlatShape};
Expand All @@ -7,9 +12,9 @@ use nu_protocol::{
Span,
};

// Format an array of bytes
//
// Reading the file gives you a list of bytes
/// 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 formatting time
// let mut timer = Timer::start();
Expand Down Expand Up @@ -41,7 +46,7 @@ pub fn format_inner(contents: &[u8], _config: &Config) -> Vec<u8> {
let mut start = 0;
let end_of_file = contents.len();

for (span, shape) in flat.clone().into_iter() {
for (span, shape) in flat.clone() {
// check if span skipped some bytes before the current span
if span.start > start {
trace!(
Expand All @@ -57,7 +62,7 @@ pub fn format_inner(contents: &[u8], _config: &Config) -> Vec<u8> {
out.extend(trim_ascii_whitespace(skipped_contents));
out.push(b'\n');
} else {
trace!("The contents doesn't have a '#'. Skipping.")
trace!("The contents doesn't have a '#'. Skipping.");
}
}

Expand All @@ -73,14 +78,14 @@ pub fn format_inner(contents: &[u8], _config: &Config) -> Vec<u8> {
c_bites = trim_ascii_whitespace(c_bites);
let printable = String::from_utf8_lossy(c_bites).to_string();
trace!("stripped the whitespace, result: {:?}", printable);
out.extend(c_bites)
out.extend(c_bites);
}
FlatShape::Pipe => {
// here you don't have to strip the whitespace.
// The pipe is just a pipe `|`.
//
// return the pipe AND a space after that
out.extend("| ".to_string().bytes())
out.extend("| ".to_string().bytes());
}
FlatShape::External => {
// External are some key commands
Expand Down Expand Up @@ -125,7 +130,7 @@ pub fn format_inner(contents: &[u8], _config: &Config) -> Vec<u8> {
out.push(b'\n');
out.extend(trim_ascii_whitespace(remaining_contents));
} else {
trace!("The contents doesn't have a '#'. Skipping.")
trace!("The contents doesn't have a '#'. Skipping.");
}
}

Expand All @@ -139,6 +144,10 @@ pub fn format_inner(contents: &[u8], _config: &Config) -> Vec<u8> {
out
}

/// A wrapper to insert a new line
///
/// It is used frequently in `nufmt`, so
/// we have a wrapper to improve readability of the code.
fn insert_newline(mut bytes: Vec<u8>) -> Vec<u8> {
// If I need cfg windows, then I need \r\n
// let newline = vec![b'\r', b'\n'];
Expand All @@ -147,19 +156,34 @@ fn insert_newline(mut bytes: Vec<u8>) -> Vec<u8> {
bytes
}

/// Given a slice of bytes, strip all spaces, new lines and tabs found within
///
/// Because you don't know how the incoming code is formatted,
/// the best way to format is to strip all the whitespace
/// and afterwards include the new lines and indentation correctly
/// according to the configuration
pub fn trim_ascii_whitespace(x: &[u8]) -> &[u8] {
let from = match x.iter().position(|x| !x.is_ascii_whitespace()) {
Some(i) => i,
None => return &x[0..0],
};
let Some(from) = x.iter().position(|x| !x.is_ascii_whitespace()) else { return &x[0..0] };
let to = x.iter().rposition(|x| !x.is_ascii_whitespace()).unwrap();
&x[from..=to]
}

/// Returns true if the Block has at least 1 Pipeline
///
/// This function exists because sometimes is passed to `nufmt` an empty String,
/// or a nu code which the parser can't identify something runnable
/// (like a list of comments)
///
/// We don't want to return a blank file if that is the case,
/// so this check gives the opportunity to `nufmt`
/// to know when not to touch the file at all in the implementation.
fn block_has_pipilnes(block: &Block) -> bool {
!block.pipelines.is_empty()
}

/// Returns true if the `Span` is the last Span in the slice of `flat`
///
/// Takes a Span and a slice of tuples `(Span, FlatShape)`.
fn is_last_span(span: Span, flat: &[(Span, FlatShape)]) -> bool {
span == flat.last().unwrap().0
}
19 changes: 16 additions & 3 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,16 @@
//!
//! It does not do anything more than that, which makes it so fast.

#![deny(rustdoc::broken_intra_doc_links)] // throw error if finds a broken link in doc
#![warn(missing_docs // or docs are missing for public members
,clippy::missing_docs_in_private_items // warn if docs are missing in private items
,clippy::explicit_iter_loop // warn if you find array.iter(), &array will do the same
,clippy::explicit_into_iter_loop // same with into_iter()
,clippy::semicolon_if_nothing_returned // consistent semicolon endings
,clippy::doc_markdown // warn if _ :: or ` are missing in .md
,clippy::manual_let_else // warn if a match has only 1 arm => do if let
)]

use config::Config;
use formatting::format_inner;
use log::{debug, trace};
Expand All @@ -13,7 +23,7 @@ use std::path::PathBuf;
pub mod config;
pub mod formatting;

/// Reads the file and format it. After that, writes the file inplace
/// Reads a `&PathBuf` pointing to a file and format it. Then writes the file inplace.
pub fn format_single_file(file: &PathBuf, config: &Config) {
// read the contents of the file
let contents = std::fs::read(file)
Expand All @@ -24,7 +34,7 @@ pub fn format_single_file(file: &PathBuf, config: &Config) {

// compare the contents
if formatted_bytes == contents {
debug!("File is formatted correctly.")
debug!("File is formatted correctly.");
}

// write down the file to path
Expand All @@ -33,9 +43,12 @@ pub fn format_single_file(file: &PathBuf, config: &Config) {
writer
.write_all(file_bites)
.expect("something went wrong writing");
trace!("written")
trace!("written");
}

/// Take a `String` and format it. Then returns a new `String`
///
/// Takes a pointer to a String `&String` and a config `&Config`.
pub fn format_string(input_string: &String, config: &Config) -> String {
let contents = input_string.as_bytes();
let formatted_bytes = format_inner(contents, config);
Expand Down
32 changes: 23 additions & 9 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,15 @@
//!
//! - `-v` or `--version` prints the version and exit

// throw error if finds a broken link in doc
#![deny(rustdoc::broken_intra_doc_links)]
// or docs are missing for public members
#![warn(missing_docs)]
#![deny(rustdoc::broken_intra_doc_links)] // throw error if finds a broken link in doc
#![warn(missing_docs // or docs are missing for public members
,clippy::missing_docs_in_private_items // warn if docs are missing in private items
,clippy::explicit_iter_loop // warn if you find array.iter(), &array will do the same
,clippy::explicit_into_iter_loop // same with into_iter()
,clippy::semicolon_if_nothing_returned // consistent semicolon endings
,clippy::doc_markdown // warn if _ :: or ` are missing in .md
,clippy::manual_let_else // warn if a match has only 1 arm => do if let
)]

use anyhow::{Ok, Result};
use clap::Parser;
Expand All @@ -50,24 +55,34 @@ use std::error::Error;
use std::io::Write;
use std::path::PathBuf;

/// wrapper to the successful exit code
const SUCCESSFUL_EXIT: i32 = 0;
/// wrapper to the failure exit code
const FAILED_EXIT: i32 = 1;

/// Main CLI struct.
///
/// The derive Clippy API starts from defining the CLI struct
#[derive(Parser)]
#[command(author, version, about)]
struct Cli {
/// The list of files passed in the cmdline
/// It is required and it cannot be used with `--stdin`
#[arg(
required_unless_present("stdin"),
help = "The file or files you want to format in nu"
)]
files: Vec<PathBuf>,
/// The string you pass in stdin. You can pass only one string.
#[arg(
short,
long,
conflicts_with = "files",
help = "Format the code passed in stdin as a string."
)]
stdin: Option<String>,
/// The optional config file you can pass in the cmdline
/// You can only pass a file config, not a flag config
#[arg(short, long, help = "The configuration file")]
config: Option<PathBuf>,
}
Expand Down Expand Up @@ -123,7 +138,7 @@ fn execute_string(string: Option<String>, options: &Config) -> Result<i32> {
/// Sends the files to format in lib.rs
fn execute_files(files: Vec<PathBuf>, options: &Config) -> Result<i32> {
// walk the files in the vec of files
for file in files.iter() {
for file in &files {
if !file.exists() {
eprintln!("Error: {} not found!", file.to_str().unwrap());
return Ok(FAILED_EXIT);
Expand All @@ -133,11 +148,10 @@ fn execute_files(files: Vec<PathBuf>, options: &Config) -> Result<i32> {
file.to_str().unwrap()
);
return Ok(FAILED_EXIT);
} else {
// send the file to lib.rs
println!("formatting file: {:?}", file);
format_single_file(file, options);
}
// send the file to lib.rs
println!("formatting file: {:?}", file);
format_single_file(file, options);
}

Ok(SUCCESSFUL_EXIT)
Expand Down

0 comments on commit 4b97279

Please sign in to comment.