Skip to content

Commit 4849040

Browse files
committed
feat(prqlc): Add color & signature_comment options
This adds `--color` & `--include-signature-comment` options to the `prqlc compile` command. Closes PRQL#1355. I think we did a not-great job at defining the minimum requirements there, to the extent that this is a simpler construction that leans more heavily on external libraries -- and is both simpler and has better functionality as a result. Even without the external libraries, I think we could have suggested a flatter structure to the `Options' struct. (Or maybe we'll decide this construction is too simple / leans too much on external libraries).
1 parent 5b60e60 commit 4849040

File tree

4 files changed

+111
-34
lines changed

4 files changed

+111
-34
lines changed

Cargo.lock

+39
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

prql-compiler/prqlc/Cargo.toml

+3-1
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,13 @@ atty = "0.2.14"
1515
clap = {version = "4.1.1", features = ["derive"]}
1616
clio = {version = "0.2.4", features = ['clap-parse']}
1717
color-eyre = "0.6.1"
18+
concolor = "0.1.0"
19+
concolor-clap = {version = "0.1.0", features = ["api"]}
1820
env_logger = {version = "0.10.0", features = ["color"]}
1921
itertools = "0.10.3"
2022
minijinja = {version = "0.30.4", features = ["unstable_machinery"]}
2123
notify = "^5.1.0"
22-
prql-compiler = {path = '..', version = "0.6.1" }
24+
prql-compiler = {path = '..', version = "0.6.1"}
2325
regex = {version = "1.7.1", features = ["std", "unicode"]}
2426
serde = "^1"
2527
serde_json = "1.0.81"

prql-compiler/prqlc/src/cli.rs

+64-33
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ pub fn main() -> color_eyre::eyre::Result<()> {
1919
env_logger::builder().format_timestamp(None).init();
2020
color_eyre::install()?;
2121
let mut cli = Cli::parse();
22+
cli.color.apply();
2223

2324
if let Err(error) = cli.command.run() {
2425
eprintln!("{error}");
@@ -29,20 +30,21 @@ pub fn main() -> color_eyre::eyre::Result<()> {
2930
}
3031

3132
#[derive(Parser, Debug, Clone)]
33+
#[clap(color = concolor_clap::color_choice())]
3234
struct Cli {
3335
#[command(subcommand)]
3436
command: Command,
37+
#[command(flatten)]
38+
color: concolor_clap::Color,
3539
}
3640

3741
#[derive(Subcommand, Debug, Clone)]
3842
#[clap(name = env!("CARGO_PKG_NAME"), about, version)]
3943
enum Command {
4044
/// Parse into PL AST
4145
Parse {
42-
#[clap(value_parser, default_value = "-")]
43-
input: Input,
44-
#[clap(value_parser, default_value = "-")]
45-
output: Output,
46+
#[clap(flatten)]
47+
io_args: IoArgs,
4648
#[arg(value_enum, long, default_value = "yaml")]
4749
format: Format,
4850
},
@@ -59,16 +61,19 @@ enum Command {
5961

6062
/// Parse, resolve & lower into RQ
6163
Resolve {
62-
#[clap(value_parser, default_value = "-")]
63-
input: Input,
64-
#[clap(value_parser, default_value = "-")]
65-
output: Output,
64+
#[clap(flatten)]
65+
io_args: IoArgs,
6666
#[arg(value_enum, long, default_value = "yaml")]
6767
format: Format,
6868
},
6969

7070
/// Parse, resolve, lower into RQ & compile to SQL
71-
Compile(IoArgs),
71+
Compile {
72+
#[clap(flatten)]
73+
io_args: IoArgs,
74+
#[arg(long, default_value = "true")]
75+
include_signature_comment: bool,
76+
},
7277

7378
/// Watch a directory and compile .prql files to .sql files
7479
Watch(watch::WatchArgs),
@@ -96,11 +101,10 @@ fn is_stdin(input: &Input) -> bool {
96101
impl Command {
97102
/// Entrypoint called by [`main`]
98103
pub fn run(&mut self) -> Result<()> {
99-
if let Command::Watch(command) = self {
100-
return watch::run(command);
101-
};
102-
103-
self.run_io_command()
104+
match self {
105+
Command::Watch(command) => watch::run(command),
106+
_ => self.run_io_command(),
107+
}
104108
}
105109

106110
fn run_io_command(&mut self) -> std::result::Result<(), anyhow::Error> {
@@ -113,7 +117,15 @@ impl Command {
113117
self.write_output(&buf)?;
114118
}
115119
Err(e) => {
116-
print!("{:}", downcast(e).composed(&source_id, &source, true));
120+
print!(
121+
"{:}",
122+
// TODO: we're repeating this for `Compile`; can we consolidate?
123+
downcast(e).composed(
124+
&source_id,
125+
&source,
126+
concolor::get(concolor::Stream::Stdout).ansi_color()
127+
)
128+
);
117129
std::process::exit(1)
118130
}
119131
}
@@ -167,42 +179,57 @@ impl Command {
167179
Format::Yaml => serde_yaml::to_string(&ir)?.into_bytes(),
168180
}
169181
}
170-
// TODO: Allow passing the `Options` to the CLI; map those through.
171-
// We already do this in Watch.
172-
Command::Compile(_) => compile(source, &Options::default())?.as_bytes().to_vec(),
182+
Command::Compile {
183+
include_signature_comment,
184+
..
185+
} => compile(
186+
source,
187+
// I'm guessing it's too "clever" to use `Options` directly in
188+
// the Compile enum variant, and avoid this boilerplate? Would
189+
// reduce this code somewhat.
190+
&Options::default()
191+
.with_color(concolor::get(concolor::Stream::Stdout).ansi_color())
192+
.with_signature_comment(*include_signature_comment),
193+
)?
194+
.as_bytes()
195+
.to_vec(),
173196
Command::Watch(_) => unreachable!(),
174197
})
175198
}
176199

177200
fn read_input(&mut self) -> Result<(String, String)> {
178-
// TODO: possibly this should be called by the relevant subcommands
179-
// passing in `input`, rather than matching on them and grabbing `input`
180-
// from `self`.
201+
// Possibly this should be called by the relevant subcommands passing in
202+
// `input`, rather than matching on them and grabbing `input` from
203+
// `self`? But possibly if everything moves to `io_args`, then this is
204+
// quite reasonable?
181205
use Command::*;
182206
let mut input = match self {
183-
Parse { input, .. } | Resolve { input, .. } => input.clone(),
184-
Format(io) | Debug(io) | Annotate(io) | Compile(io) => io.input.clone(),
207+
Parse { io_args, .. } | Resolve { io_args, .. } | Compile { io_args, .. } => {
208+
io_args.input.clone()
209+
}
210+
Format(io) | Debug(io) | Annotate(io) => io.input.clone(),
185211
Watch(_) => unreachable!(),
186212
};
187213
// Don't wait without a prompt when running `prqlc compile` —
188214
// it's confusing whether it's waiting for input or not. This
189215
// offers the prompt.
190216
if is_stdin(&input) && atty::is(atty::Stream::Stdin) {
191-
println!("Enter PRQL, then ctrl-d:");
192-
println!();
217+
println!("Enter PRQL, then ctrl-d:\n");
193218
}
194219

195220
let mut source = String::new();
196-
(input).read_to_string(&mut source)?;
221+
input.read_to_string(&mut source)?;
197222
let source_id = (input.path()).to_str().unwrap().to_string();
198223
Ok((source, source_id))
199224
}
200225

201226
fn write_output(&mut self, data: &[u8]) -> std::io::Result<()> {
202227
use Command::*;
203228
let mut output = match self {
204-
Parse { output, .. } | Resolve { output, .. } => output.to_owned(),
205-
Format(io) | Debug(io) | Annotate(io) | Compile(io) => io.output.to_owned(),
229+
Parse { io_args, .. } | Resolve { io_args, .. } | Compile { io_args, .. } => {
230+
io_args.output.to_owned()
231+
}
232+
Format(io) | Debug(io) | Annotate(io) => io.output.to_owned(),
206233
Watch(_) => unreachable!(),
207234
};
208235
output.write_all(data)
@@ -321,7 +348,13 @@ group a_column (take 10 | sort b_column | derive [the_number = rank, last = lag
321348
fn compile() {
322349
// Check we get an error on a bad input
323350
let input = "asdf";
324-
let result = Command::execute(&Command::Compile(IoArgs::default()), input);
351+
let result = Command::execute(
352+
&Command::Compile {
353+
io_args: IoArgs::default(),
354+
include_signature_comment: true,
355+
},
356+
input,
357+
);
325358
assert_display_snapshot!(result.unwrap_err(), @r###"
326359
Error:
327360
╭─[:1:1]
@@ -337,8 +370,7 @@ group a_column (take 10 | sort b_column | derive [the_number = rank, last = lag
337370
fn parse() {
338371
let output = Command::execute(
339372
&Command::Parse {
340-
input: IoArgs::default().input,
341-
output: IoArgs::default().output,
373+
io_args: IoArgs::default(),
342374
format: Format::Yaml,
343375
},
344376
"from x | select y",
@@ -369,8 +401,7 @@ group a_column (take 10 | sort b_column | derive [the_number = rank, last = lag
369401
fn resolve() {
370402
let output = Command::execute(
371403
&Command::Resolve {
372-
input: IoArgs::default().input,
373-
output: IoArgs::default().output,
404+
io_args: IoArgs::default(),
374405
format: Format::Yaml,
375406
},
376407
"from x | select y",

prql-compiler/src/lib.rs

+5
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,11 @@ impl Options {
211211
self
212212
}
213213

214+
pub fn with_signature_comment(mut self, signature_comment: bool) -> Self {
215+
self.signature_comment = signature_comment;
216+
self
217+
}
218+
214219
pub fn no_signature(mut self) -> Self {
215220
self.signature_comment = false;
216221
self

0 commit comments

Comments
 (0)