summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBartek IwaƄczuk <biwanczuk@gmail.com>2021-09-13 22:06:45 +0200
committerGitHub <noreply@github.com>2021-09-13 22:06:45 +0200
commitcba1e7b5a3c239235c0e855dc430c8aa89272401 (patch)
treec9bbc711db749ddbf96b722a2cb48ab89e701e0d
parent0dbeb774ba9ea618ff1e92b63ab31e5caf3003dd (diff)
feat: add option flags to 'deno fmt' (#12060)
-rw-r--r--cli/flags.rs162
-rw-r--r--cli/main.rs12
-rw-r--r--cli/tools/fmt.rs63
3 files changed, 215 insertions, 22 deletions
diff --git a/cli/flags.rs b/cli/flags.rs
index eb7d0901f..81981b278 100644
--- a/cli/flags.rs
+++ b/cli/flags.rs
@@ -13,6 +13,8 @@ use deno_runtime::permissions::PermissionsOptions;
use log::debug;
use log::Level;
use std::net::SocketAddr;
+use std::num::NonZeroU32;
+use std::num::NonZeroU8;
use std::num::NonZeroUsize;
use std::path::PathBuf;
use std::str::FromStr;
@@ -86,6 +88,11 @@ pub struct FmtFlags {
pub files: Vec<PathBuf>,
pub ignore: Vec<PathBuf>,
pub ext: String,
+ pub use_tabs: Option<bool>,
+ pub line_width: Option<NonZeroU32>,
+ pub indent_width: Option<NonZeroU8>,
+ pub single_quote: Option<bool>,
+ pub prose_wrap: Option<String>,
}
#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
@@ -845,6 +852,47 @@ Ignore formatting a file by adding an ignore comment at the top of the file:
.required(false),
)
.arg(watch_arg())
+ .arg(
+ Arg::with_name("options-use-tabs")
+ .long("options-use-tabs")
+ .help("Use tabs instead of spaces for indentation. Defaults to false."),
+ )
+ .arg(
+ Arg::with_name("options-line-width")
+ .long("options-line-width")
+ .help("Define maximum line width. Defaults to 80.")
+ .takes_value(true)
+ .validator(|val: String| match val.parse::<NonZeroUsize>() {
+ Ok(_) => Ok(()),
+ Err(_) => {
+ Err("options-line-width should be a non zero integer".to_string())
+ }
+ }),
+ )
+ .arg(
+ Arg::with_name("options-indent-width")
+ .long("options-indent-width")
+ .help("Define indentation width. Defaults to 2.")
+ .takes_value(true)
+ .validator(|val: String| match val.parse::<NonZeroUsize>() {
+ Ok(_) => Ok(()),
+ Err(_) => {
+ Err("options-indent-width should be a non zero integer".to_string())
+ }
+ }),
+ )
+ .arg(
+ Arg::with_name("options-single-quote")
+ .long("options-single-quote")
+ .help("Use single quotes. Defaults to false."),
+ )
+ .arg(
+ Arg::with_name("options-prose-wrap")
+ .long("options-prose-wrap")
+ .takes_value(true)
+ .possible_values(&["always", "never", "preserve"])
+ .help("Define how prose should be wrapped. Defaults to always."),
+ )
}
fn info_subcommand<'a, 'b>() -> App<'a, 'b> {
@@ -1745,11 +1793,54 @@ fn fmt_parse(flags: &mut Flags, matches: &clap::ArgMatches) {
};
let ext = matches.value_of("ext").unwrap().to_string();
+ let use_tabs = if matches.is_present("options-use-tabs") {
+ Some(true)
+ } else {
+ None
+ };
+ let line_width = if matches.is_present("options-line-width") {
+ Some(
+ matches
+ .value_of("options-line-width")
+ .unwrap()
+ .parse()
+ .unwrap(),
+ )
+ } else {
+ None
+ };
+ let indent_width = if matches.is_present("options-indent-width") {
+ Some(
+ matches
+ .value_of("options-indent-width")
+ .unwrap()
+ .parse()
+ .unwrap(),
+ )
+ } else {
+ None
+ };
+ let single_quote = if matches.is_present("options-single-quote") {
+ Some(true)
+ } else {
+ None
+ };
+ let prose_wrap = if matches.is_present("options-prose-wrap") {
+ Some(matches.value_of("options-prose-wrap").unwrap().to_string())
+ } else {
+ None
+ };
+
flags.subcommand = DenoSubcommand::Fmt(FmtFlags {
check: matches.is_present("check"),
ext,
files,
ignore,
+ use_tabs,
+ line_width,
+ indent_width,
+ single_quote,
+ prose_wrap,
});
}
@@ -2466,7 +2557,12 @@ mod tests {
PathBuf::from("script_1.ts"),
PathBuf::from("script_2.ts")
],
- ext: "ts".to_string()
+ ext: "ts".to_string(),
+ use_tabs: None,
+ line_width: None,
+ indent_width: None,
+ single_quote: None,
+ prose_wrap: None,
}),
..Flags::default()
}
@@ -2481,6 +2577,11 @@ mod tests {
check: true,
files: vec![],
ext: "ts".to_string(),
+ use_tabs: None,
+ line_width: None,
+ indent_width: None,
+ single_quote: None,
+ prose_wrap: None,
}),
..Flags::default()
}
@@ -2495,6 +2596,11 @@ mod tests {
check: false,
files: vec![],
ext: "ts".to_string(),
+ use_tabs: None,
+ line_width: None,
+ indent_width: None,
+ single_quote: None,
+ prose_wrap: None,
}),
..Flags::default()
}
@@ -2509,6 +2615,11 @@ mod tests {
check: false,
files: vec![],
ext: "ts".to_string(),
+ use_tabs: None,
+ line_width: None,
+ indent_width: None,
+ single_quote: None,
+ prose_wrap: None,
}),
watch: true,
..Flags::default()
@@ -2531,6 +2642,11 @@ mod tests {
check: true,
files: vec![PathBuf::from("foo.ts")],
ext: "ts".to_string(),
+ use_tabs: None,
+ line_width: None,
+ indent_width: None,
+ single_quote: None,
+ prose_wrap: None,
}),
watch: true,
..Flags::default()
@@ -2545,7 +2661,12 @@ mod tests {
ignore: vec![],
check: false,
files: vec![],
- ext: "ts".to_string()
+ ext: "ts".to_string(),
+ use_tabs: None,
+ line_width: None,
+ indent_width: None,
+ single_quote: None,
+ prose_wrap: None,
}),
config_path: Some("deno.jsonc".to_string()),
..Flags::default()
@@ -2567,13 +2688,48 @@ mod tests {
ignore: vec![],
check: false,
files: vec![PathBuf::from("foo.ts")],
- ext: "ts".to_string()
+ ext: "ts".to_string(),
+ use_tabs: None,
+ line_width: None,
+ indent_width: None,
+ single_quote: None,
+ prose_wrap: None,
}),
config_path: Some("deno.jsonc".to_string()),
watch: true,
..Flags::default()
}
);
+
+ let r = flags_from_vec(svec![
+ "deno",
+ "fmt",
+ "--options-use-tabs",
+ "--options-line-width",
+ "60",
+ "--options-indent-width",
+ "4",
+ "--options-single-quote",
+ "--options-prose-wrap",
+ "never"
+ ]);
+ assert_eq!(
+ r.unwrap(),
+ Flags {
+ subcommand: DenoSubcommand::Fmt(FmtFlags {
+ ignore: vec![],
+ check: false,
+ files: vec![],
+ ext: "ts".to_string(),
+ use_tabs: Some(true),
+ line_width: Some(NonZeroU32::new(60).unwrap()),
+ indent_width: Some(NonZeroU8::new(4).unwrap()),
+ single_quote: Some(true),
+ prose_wrap: Some("never".to_string()),
+ }),
+ ..Flags::default()
+ }
+ );
}
#[test]
diff --git a/cli/main.rs b/cli/main.rs
index 55de5a61e..672668c2a 100644
--- a/cli/main.rs
+++ b/cli/main.rs
@@ -815,20 +815,12 @@ async fn format_command(
if fmt_flags.files.len() == 1 && fmt_flags.files[0].to_string_lossy() == "-" {
return tools::fmt::format_stdin(
- fmt_flags.check,
- fmt_flags.ext,
+ fmt_flags,
maybe_fmt_config.map(|c| c.options).unwrap_or_default(),
);
}
- tools::fmt::format(
- fmt_flags.files,
- fmt_flags.ignore,
- fmt_flags.check,
- flags.watch,
- maybe_fmt_config,
- )
- .await?;
+ tools::fmt::format(fmt_flags, flags.watch, maybe_fmt_config).await?;
Ok(())
}
diff --git a/cli/tools/fmt.rs b/cli/tools/fmt.rs
index 5f1507d19..6758d7b8b 100644
--- a/cli/tools/fmt.rs
+++ b/cli/tools/fmt.rs
@@ -14,6 +14,7 @@ use crate::config_file::ProseWrap;
use crate::diff::diff;
use crate::file_watcher;
use crate::file_watcher::ResolutionResult;
+use crate::flags::FmtFlags;
use crate::fs_util::{collect_files, get_extension, is_supported_ext_fmt};
use crate::text_encoding;
use deno_ast::ParsedSource;
@@ -34,17 +35,22 @@ use std::sync::{Arc, Mutex};
/// Format JavaScript/TypeScript files.
pub async fn format(
- args: Vec<PathBuf>,
- ignore: Vec<PathBuf>,
- check: bool,
+ fmt_flags: FmtFlags,
watch: bool,
maybe_fmt_config: Option<FmtConfig>,
) -> Result<(), AnyError> {
+ let FmtFlags {
+ files,
+ ignore,
+ check,
+ ..
+ } = fmt_flags.clone();
+
// First, prepare final configuration.
// Collect included and ignored files. CLI flags take precendence
// over config file, ie. if there's `files.ignore` in config file
// and `--ignore` CLI flag, only the flag value is taken into account.
- let mut include_files = args.clone();
+ let mut include_files = files.clone();
let mut exclude_files = ignore;
if let Some(fmt_config) = maybe_fmt_config.as_ref() {
@@ -67,7 +73,11 @@ pub async fn format(
}
}
- let fmt_options = maybe_fmt_config.map(|c| c.options).unwrap_or_default();
+ // Now do the same for options
+ let fmt_options = resolve_fmt_options(
+ &fmt_flags,
+ maybe_fmt_config.map(|c| c.options).unwrap_or_default(),
+ );
let resolver = |changed: Option<Vec<PathBuf>>| {
let files_changed = changed.is_some();
@@ -345,19 +355,19 @@ async fn format_source_files(
/// Treats input as TypeScript or as set by `--ext` flag.
/// Compatible with `--check` flag.
pub fn format_stdin(
- check: bool,
- ext: String,
+ fmt_flags: FmtFlags,
fmt_options: FmtOptionsConfig,
) -> Result<(), AnyError> {
let mut source = String::new();
if stdin().read_to_string(&mut source).is_err() {
return Err(generic_error("Failed to read from stdin"));
}
- let file_path = PathBuf::from(format!("_stdin.{}", ext));
+ let file_path = PathBuf::from(format!("_stdin.{}", fmt_flags.ext));
+ let fmt_options = resolve_fmt_options(&fmt_flags, fmt_options);
match format_file(&file_path, &source, fmt_options) {
Ok(formatted_text) => {
- if check {
+ if fmt_flags.check {
if formatted_text != source {
println!("Not formatted stdin");
}
@@ -380,6 +390,41 @@ fn files_str(len: usize) -> &'static str {
}
}
+fn resolve_fmt_options(
+ fmt_flags: &FmtFlags,
+ options: FmtOptionsConfig,
+) -> FmtOptionsConfig {
+ let mut options = options;
+
+ if let Some(use_tabs) = fmt_flags.use_tabs {
+ options.use_tabs = Some(use_tabs);
+ }
+
+ if let Some(line_width) = fmt_flags.line_width {
+ options.line_width = Some(line_width.get());
+ }
+
+ if let Some(indent_width) = fmt_flags.indent_width {
+ options.indent_width = Some(indent_width.get());
+ }
+
+ if let Some(single_quote) = fmt_flags.single_quote {
+ options.single_quote = Some(single_quote);
+ }
+
+ if let Some(prose_wrap) = &fmt_flags.prose_wrap {
+ options.prose_wrap = Some(match prose_wrap.as_str() {
+ "always" => ProseWrap::Always,
+ "never" => ProseWrap::Never,
+ "preserve" => ProseWrap::Preserve,
+ // validators in `flags.rs` makes other values unreachable
+ _ => unreachable!(),
+ });
+ }
+
+ options
+}
+
fn get_resolved_typescript_config(
options: &FmtOptionsConfig,
) -> dprint_plugin_typescript::configuration::Configuration {