Skip to content

Commit d202b8f

Browse files
fix: remove conflicts, impl completions command
... so that pb completions can add chat completions via clap_complete - Need to refactor Config struct
1 parent cdfe4a0 commit d202b8f

File tree

2 files changed

+130
-41
lines changed

2 files changed

+130
-41
lines changed

src/cli.rs

+83-8
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ use std::string::String as KafkaSslProtocol;
4444
pub const DEFAULT_USERNAME: &str = "admin";
4545
pub const DEFAULT_PASSWORD: &str = "admin";
4646

47-
#[derive(Parser)]
47+
#[derive(Parser, Debug)]
4848
#[command(
4949
name = "parseable",
5050
bin_name = "parseable",
@@ -73,13 +73,88 @@ Join the community at https://logg.ing/community.
7373
"#,
7474
subcommand_required = true,
7575
)]
76-
pub struct Cli {
76+
pub enum Cli {
77+
#[clap(name = "storage")]
78+
/// Storage options
79+
Storage(StorageOptions),
80+
81+
/// Generate shell completions
82+
#[clap(name = "completions")]
83+
Completion(CommandCompletionOptions),
84+
}
85+
86+
// taken generously from https://github.com/jj-vcs/jj/blob/be32d4e3efbb9a51deadcc63635a5fb1526d0d6c/cli/src/commands/util/completion.rs#L23C1-L47C36
87+
// Using an explicit `doc` attribute prevents rustfmt from mangling the list
88+
// formatting without disabling rustfmt for the entire struct.
89+
#[doc = r#"Print a command-line-completion script
90+
91+
Apply it by running one of these:
92+
93+
- Bash: `source <(pb util completion bash)`
94+
- Fish: `pb util completion fish | source`
95+
- Nushell:
96+
```nu
97+
pb util completion nushell | save "completions-pb.nu"
98+
use "completions-pb.nu" * # Or `source "completions-pb.nu"`
99+
```
100+
- Zsh:
101+
```shell
102+
autoload -U compinit
103+
compinit
104+
source <(pb util completion zsh)
105+
```
106+
"#]
107+
108+
#[derive(clap::Args, Debug)]
109+
#[command(verbatim_doc_comment)]
110+
pub struct CommandCompletionOptions {
111+
pub shell: Option<ShellCompletion>,
112+
}
113+
114+
/// Available shell completions
115+
#[derive(clap::ValueEnum, Clone, Copy, Debug, Eq, Hash, PartialEq)]
116+
pub enum ShellCompletion {
117+
Bash,
118+
Elvish,
119+
Fish,
120+
// Nushell,
121+
PowerShell,
122+
Zsh,
123+
}
124+
125+
impl ShellCompletion {
126+
pub fn generate(&self, cmd: &mut clap::Command) -> Vec<u8> {
127+
use clap_complete::generate;
128+
use clap_complete::Shell;
129+
// use clap_complete_nushell::Nushell;
130+
131+
let mut buf = Vec::new();
132+
133+
let bin_name = "pb";
134+
135+
match self {
136+
Self::Bash => generate(Shell::Bash, cmd, bin_name, &mut buf),
137+
Self::Elvish => generate(Shell::Elvish, cmd, bin_name, &mut buf),
138+
Self::Fish => generate(Shell::Fish, cmd, bin_name, &mut buf),
139+
// Self::Nushell => generate(Nushell, cmd, bin_name, &mut buf),
140+
Self::PowerShell => generate(Shell::PowerShell, cmd, bin_name, &mut buf),
141+
Self::Zsh => generate(Shell::Zsh, cmd, bin_name, &mut buf),
142+
}
143+
144+
buf
145+
}
146+
}
147+
148+
// todo remove caution
149+
#[derive(clap::Args, Debug)]
150+
pub struct StorageOptions {
77151
#[command(subcommand)]
78-
pub storage: StorageOptions,
152+
pub storage: StorageOptionsEnum,
79153
}
80154

81-
#[derive(Parser)]
82-
pub enum StorageOptions {
155+
// todo remove caution
156+
#[derive(clap::Subcommand, Debug)]
157+
pub enum StorageOptionsEnum {
83158
#[command(name = "local-store")]
84159
Local(LocalStoreArgs),
85160

@@ -90,23 +165,23 @@ pub enum StorageOptions {
90165
Blob(BlobStoreArgs),
91166
}
92167

93-
#[derive(Parser)]
168+
#[derive(Parser, Debug)]
94169
pub struct LocalStoreArgs {
95170
#[command(flatten)]
96171
pub options: Options,
97172
#[command(flatten)]
98173
pub storage: FSConfig,
99174
}
100175

101-
#[derive(Parser)]
176+
#[derive(Parser, Debug)]
102177
pub struct S3StoreArgs {
103178
#[command(flatten)]
104179
pub options: Options,
105180
#[command(flatten)]
106181
pub storage: S3Config,
107182
}
108183

109-
#[derive(Parser)]
184+
#[derive(Parser, Debug)]
110185
pub struct BlobStoreArgs {
111186
#[command(flatten)]
112187
pub options: Options,

src/option.rs

+47-33
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,13 @@
1616
*
1717
*/
1818

19-
use crate::cli::{Cli, Options, StorageOptions, DEFAULT_PASSWORD, DEFAULT_USERNAME};
19+
use crate::cli::StorageOptionsEnum;
20+
use crate::cli::{Cli, Options, DEFAULT_PASSWORD, DEFAULT_USERNAME};
2021
use crate::storage::object_storage::parseable_json_path;
2122
use crate::storage::{ObjectStorageError, ObjectStorageProvider};
2223
use bytes::Bytes;
23-
use clap::error::ErrorKind;
24-
use clap::Parser;
24+
use clap::CommandFactory;
25+
use clap::{error::ErrorKind, Parser};
2526
use once_cell::sync::Lazy;
2627
use parquet::basic::{BrotliLevel, GzipLevel, ZstdLevel};
2728
use serde::{Deserialize, Serialize};
@@ -41,40 +42,53 @@ pub struct Config {
4142

4243
impl Config {
4344
fn new() -> Self {
44-
match Cli::parse().storage {
45-
StorageOptions::Local(args) => {
46-
if args.options.local_staging_path == args.storage.root {
47-
clap::Error::raw(
48-
ErrorKind::ValueValidation,
49-
"Cannot use same path for storage and staging",
50-
)
51-
.exit();
45+
let result = Cli::parse();
46+
match result {
47+
Cli::Storage(storage_opts) => match storage_opts.storage {
48+
StorageOptionsEnum::Local(args) => {
49+
if args.options.local_staging_path == args.storage.root {
50+
clap::Error::raw(
51+
ErrorKind::ValueValidation,
52+
"Cannot use same path for storage and staging",
53+
)
54+
.exit();
55+
}
56+
57+
if args.options.hot_tier_storage_path.is_some() {
58+
clap::Error::raw(
59+
ErrorKind::ValueValidation,
60+
"Cannot use hot tier with local-store subcommand.",
61+
)
62+
.exit();
63+
}
64+
65+
Config {
66+
options: args.options,
67+
storage: Arc::new(args.storage),
68+
storage_name: "drive",
69+
}
5270
}
53-
54-
if args.options.hot_tier_storage_path.is_some() {
55-
clap::Error::raw(
56-
ErrorKind::ValueValidation,
57-
"Cannot use hot tier with local-store subcommand.",
58-
)
59-
.exit();
60-
}
61-
62-
Config {
71+
StorageOptionsEnum::S3(args) => Config {
6372
options: args.options,
6473
storage: Arc::new(args.storage),
65-
storage_name: "drive",
66-
}
67-
}
68-
StorageOptions::S3(args) => Config {
69-
options: args.options,
70-
storage: Arc::new(args.storage),
71-
storage_name: "s3",
72-
},
73-
StorageOptions::Blob(args) => Config {
74-
options: args.options,
75-
storage: Arc::new(args.storage),
76-
storage_name: "blob_store",
74+
storage_name: "s3",
75+
},
76+
StorageOptionsEnum::Blob(args) => Config {
77+
options: args.options,
78+
storage: Arc::new(args.storage),
79+
storage_name: "blob_store",
80+
},
7781
},
82+
Cli::Completion(completion_opts) => {
83+
let shell = completion_opts
84+
.shell
85+
.unwrap_or(crate::cli::ShellCompletion::Bash);
86+
let mut cmd = Cli::command();
87+
let output = shell.generate(&mut cmd);
88+
println!("{}", String::from_utf8_lossy(&output));
89+
std::process::exit(0);
90+
unreachable!()
91+
}
7892
}
7993
}
8094

0 commit comments

Comments
 (0)