Skip to content

Commit

Permalink
Add support for longer commands
Browse files Browse the repository at this point in the history
The commands wil be broken into multiple lines automatically
  • Loading branch information
crodas committed Dec 16, 2023
1 parent 9551af6 commit e47e1fd
Show file tree
Hide file tree
Showing 5 changed files with 172 additions and 22 deletions.
3 changes: 1 addition & 2 deletions forc-plugins/forc-client/src/cmd/run.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,7 @@ pub use super::submit::Network;
pub use forc::cli::shared::{BuildOutput, BuildProfile, Minify, Pkg, Print};
pub use forc_tx::{Gas, Maturity};

forc::cli_examples! {
}
forc::cli_examples! {}

/// Run script project.
/// Crafts a script transaction then sends it to a running node.
Expand Down
6 changes: 3 additions & 3 deletions forc-plugins/forc-crypto/src/keygen/parse_secret.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,11 @@ const ABOUT: &str = "Parses a private key to view the associated public key";

#[cfg(test)]
#[allow(non_upper_case_globals)]
const PrivateKey: &str = "f5204427d0ab9a311266c96a377f7c329cb8a41b9088225b6fcf40eefb423e28";
const PRIVATE_KEY: &str = "f5204427d0ab9a311266c96a377f7c329cb8a41b9088225b6fcf40eefb423e28";

forc::cli_examples! {
[ Parses the secret of a block production => crypto "parse-secret" PrivateKey ]
[ Parses the secret of a peering => crypto "parse-secret" "-k" "peering" PrivateKey ]
[ Parses the secret of a block production => crypto "parse-secret" PRIVATE_KEY ]
[ Parses the secret of a peering => crypto "parse-secret" "-k" "peering" PRIVATE_KEY ]
}

/// Parse a secret key to view the associated public key
Expand Down
45 changes: 29 additions & 16 deletions forc-plugins/forc-tx/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,35 +18,48 @@ const ROOT: &str = "0x2222222222222222222222222222222222222222222222222222222222
const DATA_PATH: &str = "out/debug/tests.bin";
#[cfg(test)]
const BYTECODE_PATH: &str = "out/debug/tests.bin";
#[cfg(test)]
const STORAGE_SLOTS: &str = "out/debug/tests-storage_slots.json";
#[cfg(test)]
const BALANCE_ROOT_ADDR: &str =
"0x0000000000000000000000000000000000000000000000000000000000000000";
#[cfg(test)]
const STATE_ROOT_ADDR: &str = "0x0000000000000000000000000000000000000000000000000000000000000000";
#[cfg(test)]
const CONTRACT_ID: &str = "0x0000000000000000000000000000000000000000000000000000000000000000";
#[cfg(test)]
const COIN_TO_ADDR: &str = "0x2222222222222222222222222222222222222222222222222222222222222222";
#[cfg(test)]
const ASSET_ID: &str = "0x0000000000000000000000000000000000000000000000000000000000000000";

forc::cli_examples!{
forc::cli_examples! {
[ Script example => tx "script" "--bytecode" BYTECODE_PATH "--data" DATA_PATH "--receipts-root" ROOT ]
[ Multiple inputs => tx "create" "--bytecode" "out/debug/tests.bin"
"--storage-slots" "out/debug/tests-storage_slots.json"
[ Multiple inputs => tx "create" "--bytecode" BYTECODE_PATH
"--storage-slots" STORAGE_SLOTS
"--script-gas-limit" "100"
"--gas-price" "0"
"--maturity" "0"
"--witness" "ADFD"
"--witness" "DFDA"
"--witness" "adfd"
"--witness" "dfda"
"input" "contract"
"--utxo-id" "1"
"--output-ix" "1"
"--balance-root" "0x0000000000000000000000000000000000000000000000000000000000000000"
"--state-root" "0x0000000000000000000000000000000000000000000000000000000000000000"
"--balance-root" BALANCE_ROOT_ADDR
"--state-root" STATE_ROOT_ADDR
"--tx-ptr" "89ACBDEFBDEF"
"--contract-id" "0xCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC"
"--contract-id" CONTRACT_ID
"output" "coin"
"--to" "0x2222222222222222222222222222222222222222222222222222222222222222"
"--to" COIN_TO_ADDR,
"--amount" "100"
"--asset-id" "0x0000000000000000000000000000000000000000000000000000000000000000"
"--asset-id" ASSET_ID
"output" "contract"
"--input-ix" "1"
"--balance-root" "0x0000000000000000000000000000000000000000000000000000000000000000"
"--state-root" "0x0000000000000000000000000000000000000000000000000000000000000000"
"--balance-root" BALANCE_ROOT_ADDR
"--state-root" STATE_ROOT_ADDR
"output" "change"
"--to" "0x2222222222222222222222222222222222222222222222222222222222222222"
"--to" COIN_TO_ADDR
"--amount" "100"
"--asset-id" "0x0000000000000000000000000000000000000000000000000000000000000000"
"--asset-id" ASSET_ID
"output" "variable"
"--to" "0x2222222222222222222222222222222222222222222222222222222222222222"
"--amount" "100"
Expand All @@ -59,7 +72,7 @@ forc::cli_examples!{

/// The top-level `forc tx` command.
#[derive(Debug, Parser, Deserialize, Serialize)]
#[clap(about, version, after_help = EXAMPLES)]
#[clap(about, version, after_help = help())]
pub struct Command {
#[clap(long, short = 'o')]
pub output_path: Option<PathBuf>,
Expand Down Expand Up @@ -433,7 +446,7 @@ pub enum ConvertInputError {
WitnessPredicateMismatch,
}

const EXAMPLES: &str = r"EXAMPLES:
const _EXAMPLES: &str = r"EXAMPLES:
# An example constructing a `create` transaction.
forc tx create \
--bytecode ./my-contract/out/debug/my-contract.bin \
Expand Down
136 changes: 135 additions & 1 deletion forc/src/cli/help.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,145 @@ macro_rules! cli_examples {
Box::leak(format!("EXAMPLES:\n{}", examples()).into_boxed_str())
}

fn print_args(args: Vec<String>) -> String {
let mut result = String::new();
let mut iter = args.iter().peekable();
let mut length = 0;
let mut is_multiline = false;
let equal = "=".to_owned();
loop {
let arg = if let Some(arg) = iter.next() {
arg
} else {
break;
};
if length + arg.len() > 60 && iter.peek().is_some() && arg.chars().next() != Some('-') {
// too long, break it into a new line
result.push_str("\\\n ");
is_multiline = true;
length = 5;
}
if is_multiline && arg.chars().next() == Some('-') {
// it a multiline arg and the next arg is a flag, put them in their own line
result.push_str("\\\n ");
length = 5;
}
result.push_str(arg);
length += arg.len();
if arg != &equal && iter.peek() != Some(&&equal) {
result.push(' ');
length += 1;
}
}
result
}

fn quote_str(s: &str) -> String {
let mut result = String::with_capacity(s.len() + 2); // Initial capacity with room for quotes

result.push('"');
for c in s.chars() {
match c {
'\\' | '"' => result.push('\\'), // Escape backslashes and quotes
_ => (),
}
result.push(c);
}
result.push('"');

result
}

fn is_variable(s: &str) -> bool {
s.chars().all(|x| x.is_uppercase() || x == '_')
}

fn format_arguments(input: &str) -> String {
let mut chars = input.chars().peekable().into_iter();
let mut args = vec![];

loop {
let c = if let Some(c) = chars.next() { c } else { break };

match c {
' ' | '\t' | '\n' => loop {
match chars.peek() {
Some(' ') | Some('\t') | Some('\n') => chars.next(),
_ => break,
};
},
'=' => {
args.push("=".to_string());
}
'"' | '\'' => {
let end_character = c;
let mut current_word = String::new();
loop {
match chars.peek() {
Some(c) => {
if *c == end_character {
let _ = chars.next();
args.push(current_word);
break;
} else if *c == '\\' {
let _ = chars.next();
if let Some(c) = chars.next() {
current_word.push(c);
}
} else {
current_word.push(*c);
chars.next();
}
}
None => {
break;
}
}
}
}
c => {
let mut current_word = c.to_string();
loop {
match chars.peek() {
Some(' ') | Some('\t') | Some('\n') | Some('=') | Some('\'')
| Some('"') | None => {
args.push(current_word);
break;
}
Some(c) => {
current_word.push(*c);
chars.next();
}
}
}
}
}
}

print_args(
args.into_iter()
.map(|arg| {
if arg.contains(char::is_whitespace) {
// arg has spaces, quote the string
quote_str(&arg)
} else if is_variable(&arg) {
// format as a unix variable
format!("${}{}{}", "{", arg, "}")
} else {
// it is fine to show as is
arg
}
})
.collect::<Vec<String>>(),
)
}


pub fn examples() -> &'static str {
Box::leak( [
$(
$crate::paste::paste! {
format!("\t#{}\n\tforc {} {}\n\n", stringify!($($description)*), stringify!($command), stringify!($($arg)*) )
format!(" #{}\n forc {} {}\n\n", stringify!($($description)*), stringify!($command), format_arguments(stringify!($($arg)*)) )
},
)*
].concat().into_boxed_str())
Expand Down
4 changes: 4 additions & 0 deletions forc/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,9 @@ use forc_util::ForcCliResult;

#[tokio::main]
async fn main() -> ForcCliResult<()> {
let input =
"-a --long-argument=value --input-file='file.txt' -o 'foo/path with space/output.txt' ";
let formatted_args = argument_format(input);
panic!("{}", formatted_args);
forc::cli::run_cli().await.into()
}

0 comments on commit e47e1fd

Please sign in to comment.