Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP - Clarinet format #1609

Draft
wants to merge 33 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
1578266
initial componet
Nov 4, 2024
c114c34
clarinet fmt boilerplate hooked up
Nov 5, 2024
02a7db6
refactor functions a bit
Nov 11, 2024
0cef41e
add basic formatter blocks
Nov 12, 2024
07bd0ec
fix build removing clarity-repl cargo flags
Nov 14, 2024
6d33c36
remove dep on clarity-repl
Nov 15, 2024
cb252fe
fix file path
Nov 18, 2024
29c4618
basic tests working
Nov 20, 2024
ec6d9e7
add comment handling and some max line length logic
Nov 21, 2024
a7d0adf
settings flags for max line and indentation
Nov 21, 2024
ffc88c9
remove max line length check for comments
Nov 21, 2024
b863acf
switch to use PSE and refactor the matchings
Nov 26, 2024
3c3dcbd
push settings into display_pse so we can attempt formatting Tuple
Dec 2, 2024
af8c35b
fix map/tuple formatting
Dec 2, 2024
b8e4451
add nested indentation
Dec 2, 2024
9017ce5
fix format_map
Dec 2, 2024
86016fd
fix match and let formatting
Dec 3, 2024
c6254c1
handle and/or
Dec 3, 2024
25005a2
golden test prettified
Dec 3, 2024
e2bb030
special casing on comments and previous checking
Dec 16, 2024
8bc8c15
update match formatting
Dec 17, 2024
057af87
cleanup spacing cruft
Dec 17, 2024
8b3ff87
fix boolean comments and a bit of pre/post newline logic
Dec 18, 2024
5736d15
add a couple golden files
Dec 18, 2024
dcc2f2c
fix traits spacing
Dec 18, 2024
feafe83
comments golden and fix simple lists
Dec 18, 2024
4d6d022
use manifest-path properly
Dec 19, 2024
972c49c
fix key value sugar
Dec 19, 2024
93b64a8
Merge branch 'main' into clarinet-format
Dec 19, 2024
3850034
use some peekable for inlining comments
Dec 20, 2024
76cf5e7
cleanup previous_expr unused code
Dec 20, 2024
83afc00
index-of case
Dec 20, 2024
22a8337
add metadata to golden test files
Dec 20, 2024
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
29 changes: 27 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ members = [
"components/clarinet-cli",
"components/clarinet-deployments",
"components/clarinet-files",
"components/clarinet-format",
"components/clarinet-utils",
"components/clarinet-sdk-wasm",
"components/clarity-lsp",
Expand Down
1 change: 1 addition & 0 deletions components/clarinet-cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ clarity_repl = { package = "clarity-repl", path = "../clarity-repl", features =
] }
clarinet-files = { path = "../clarinet-files", features = ["cli"] }
clarity-lsp = { path = "../clarity-lsp", features = ["cli"] }
clarinet-format = { path = "../clarinet-format" }
clarinet-deployments = { path = "../clarinet-deployments", features = ["cli"] }
hiro-system-kit = { path = "../hiro-system-kit" }
stacks-network = { path = "../stacks-network" }
Expand Down
95 changes: 94 additions & 1 deletion components/clarinet-cli/src/frontend/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ use clarinet_files::{
get_manifest_location, FileLocation, NetworkManifest, ProjectManifest, ProjectManifestFile,
RequirementConfig,
};
use clarinet_format::formatter::{ClarityFormatter, Settings};
use clarity_repl::analysis::call_checker::ContractAnalysis;
use clarity_repl::clarity::vm::analysis::AnalysisDatabase;
use clarity_repl::clarity::vm::costs::LimitedCostTracker;
Expand All @@ -39,7 +40,7 @@ use clarity_repl::{analysis, repl, Terminal};
use stacks_network::{self, DevnetOrchestrator};
use std::collections::HashMap;
use std::fs::{self, File};
use std::io::prelude::*;
use std::io::{self, prelude::*};
use std::{env, process};
use toml;

Expand Down Expand Up @@ -94,11 +95,30 @@ enum Command {
/// Get Clarity autocompletion and inline errors from your code editor (VSCode, vim, emacs, etc)
#[clap(name = "lsp", bin_name = "lsp")]
LSP,
/// Format clarity code files
#[clap(name = "format", aliases = &["fmt"], bin_name = "format")]
Formatter(Formatter),
/// Step by step debugging and breakpoints from your code editor (VSCode, vim, emacs, etc)
#[clap(name = "dap", bin_name = "dap")]
DAP,
}

#[derive(Parser, PartialEq, Clone, Debug)]
struct Formatter {
#[clap(long = "manifest-path", short = 'm')]
pub manifest_path: Option<String>,
/// If specified, format only this file
#[clap(long = "file", short = 'f')]
pub file: Option<String>,
#[clap(long = "max-line-length", short = 'l')]
pub max_line_length: Option<usize>,
#[clap(long = "tabs", short = 't')]
/// indentation size, e.g. 2
pub indentation: Option<usize>,
#[clap(long = "dry-run")]
pub dry_run: bool,
}

#[derive(Subcommand, PartialEq, Clone, Debug)]
enum Devnet {
/// Generate package of all required devnet artifacts
Expand Down Expand Up @@ -1180,6 +1200,28 @@ pub fn main() {
process::exit(1);
}
},
Command::Formatter(cmd) => {
let sources = get_sources_to_format(cmd.manifest_path, cmd.file);
let mut settings = Settings::default();

if let Some(max_line_length) = cmd.max_line_length {
settings.max_line_length = max_line_length;
}

if let Some(indentation) = cmd.indentation {
settings.indentation = clarinet_format::formatter::Indentation::Space(indentation);
}
let mut formatter = ClarityFormatter::new(settings);

for (file_path, source) in &sources {
let output = formatter.format(source);
if !cmd.dry_run {
let _ = overwrite_formatted(file_path, output);
} else {
println!("{}", output);
}
}
}
Command::Devnet(subcommand) => match subcommand {
Devnet::Package(cmd) => {
let manifest = load_manifest_or_exit(cmd.manifest_path);
Expand All @@ -1193,6 +1235,57 @@ pub fn main() {
};
}

fn overwrite_formatted(file_path: &String, output: String) -> io::Result<()> {
let mut file = fs::File::create(file_path)?;

file.write_all(output.as_bytes())?;
Ok(())
}

fn from_code_source(src: ClarityCodeSource) -> String {
match src {
ClarityCodeSource::ContractOnDisk(path_buf) => {
path_buf.as_path().to_str().unwrap().to_owned()
}
_ => panic!("invalid code source"), // TODO
}
}
// look for files at the default code path (./contracts/) if
// cmd.manifest_path is not specified OR if cmd.file is not specified
fn get_sources_from_manifest(manifest_path: Option<String>) -> Vec<String> {
let manifest = load_manifest_or_warn(manifest_path);
match manifest {
Some(manifest_path) => {
let contracts = manifest_path.contracts.values().cloned();
contracts.map(|c| from_code_source(c.code_source)).collect()
}
None => {
// TODO this should probably just panic or fail gracefully because
// if the manifest isn't specified or found at the default location
// we can't do much
vec![]
}
}
}
fn get_sources_to_format(
manifest_path: Option<String>,
file: Option<String>,
) -> Vec<(String, String)> {
let files: Vec<String> = match file {
Some(file_name) => vec![format!("{}", file_name)],
None => get_sources_from_manifest(manifest_path),
};
// Map each file to its source code
files
.into_iter()
.map(|file_path| {
let source = fs::read_to_string(&file_path)
.unwrap_or_else(|_| "Failed to read file".to_string());
(file_path, source)
})
.collect()
}

fn get_manifest_location_or_exit(path: Option<String>) -> FileLocation {
match get_manifest_location(path) {
Some(manifest_location) => manifest_location,
Expand Down
31 changes: 31 additions & 0 deletions components/clarinet-format/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
[package]
name = "clarinet-format"
version = "0.1.0"
edition = "2021"

[dependencies]
# clarity-repl = { path = "../clarity-repl" }
clarity = { workspace = true}

[dev-dependencies]
pretty_assertions = "1.3"

[features]
default = ["cli"]
cli = [
"clarity/canonical",
"clarity/developer-mode",
"clarity/devtools",
"clarity/log",
]
wasm = [
"clarity/wasm",
"clarity/developer-mode",
"clarity/devtools",
]


[lib]
name = "clarinet_format"
path = "src/lib.rs"
crate-type = ["lib"]
Loading
Loading