Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
30 changes: 29 additions & 1 deletion crates/psql/src/input.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@ pub(crate) enum ReplAction {
},
Exit,
ToggleExpanded,
ToggleWriteMode,
ToggleWriteMode {
ots: Option<String>,
},
ToggleRedaction,
Edit,
Copy,
Expand Down Expand Up @@ -231,6 +233,32 @@ mod tests {
assert!(matches!(actions[0], ReplAction::ToggleExpanded));
}

#[test]
fn test_handle_input_write_mode_metacommand() {
let state = ReplState::new();
let (buffer, actions) = handle_input("", "\\W", &state);
assert_eq!(buffer, "");
assert_eq!(actions.len(), 1);
assert!(matches!(
actions[0],
ReplAction::ToggleWriteMode { ots: None }
));
}

#[test]
fn test_handle_input_write_mode_metacommand_with_arg() {
let state = ReplState::new();
let (buffer, actions) = handle_input("", "\\W bob", &state);
assert_eq!(buffer, "");
assert_eq!(actions.len(), 1);
match &actions[0] {
ReplAction::ToggleWriteMode { ots } => {
assert_eq!(ots.as_deref(), Some("bob"));
}
_ => panic!("Expected ToggleWriteMode action"),
}
}

#[test]
fn test_handle_input_toggle_redaction_metacommand() {
let state = ReplState::new();
Expand Down
4 changes: 3 additions & 1 deletion crates/psql/src/parser/metacommands.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,9 @@ mod write_mode;
pub(crate) enum Metacommand {
Quit,
Expanded,
WriteMode,
WriteMode {
ots: Option<String>,
},
ToggleRedaction,
Edit,
Copy,
Expand Down
38 changes: 32 additions & 6 deletions crates/psql/src/parser/metacommands/write_mode.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,23 @@
use winnow::{Parser, ascii::space0, combinator::eof, error::ErrMode, token::literal};
use winnow::{
Parser,
ascii::space0,
error::ErrMode,
token::{literal, rest},
};

pub fn parse(
input: &mut &str,
) -> winnow::error::Result<super::Metacommand, ErrMode<winnow::error::ContextError>> {
literal('\\').parse_next(input)?;
literal('W').parse_next(input)?;
space0.parse_next(input)?;
eof.parse_next(input)?;
Ok(super::Metacommand::WriteMode)
let trailing = rest.parse_next(input)?.trim();
let ots = if trailing.is_empty() {
None
} else {
Some(trailing.to_string())
};
Ok(super::Metacommand::WriteMode { ots })
}

#[cfg(test)]
Expand All @@ -17,18 +27,34 @@ mod tests {
#[test]
fn test_parse_metacommand_write_mode() {
let result = parse_metacommand(r"\W").unwrap();
assert_eq!(result, Some(Metacommand::WriteMode));
assert_eq!(result, Some(Metacommand::WriteMode { ots: None }));
}

#[test]
fn test_parse_metacommand_write_mode_with_whitespace() {
let result = parse_metacommand(r" \W ").unwrap();
assert_eq!(result, Some(Metacommand::WriteMode));
assert_eq!(result, Some(Metacommand::WriteMode { ots: None }));
}

#[test]
fn test_parse_metacommand_write_mode_with_trailing_text() {
let result = parse_metacommand(r"\W some text").unwrap();
assert_eq!(result, None);
assert_eq!(
result,
Some(Metacommand::WriteMode {
ots: Some("some text".to_string())
})
);
}

#[test]
fn test_parse_metacommand_write_mode_with_arg() {
let result = parse_metacommand(r"\W bob").unwrap();
assert_eq!(
result,
Some(Metacommand::WriteMode {
ots: Some("bob".to_string())
})
);
}
}
2 changes: 1 addition & 1 deletion crates/psql/src/parser/multi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -374,7 +374,7 @@ fn metacommand_to_action(metacmd: Metacommand) -> ReplAction {
match metacmd {
Metacommand::Quit => ReplAction::Exit,
Metacommand::Expanded => ReplAction::ToggleExpanded,
Metacommand::WriteMode => ReplAction::ToggleWriteMode,
Metacommand::WriteMode { ots } => ReplAction::ToggleWriteMode { ots },
Metacommand::ToggleRedaction => ReplAction::ToggleRedaction,
Metacommand::Edit => ReplAction::Edit,
Metacommand::Copy => ReplAction::Copy,
Expand Down
6 changes: 4 additions & 2 deletions crates/psql/src/repl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,9 @@ impl ReplAction {
match self {
ReplAction::ToggleExpanded => expanded::handle_toggle_expanded(ctx),
ReplAction::Exit => exit::handle_exit(ctx).await,
ReplAction::ToggleWriteMode => write_mode::handle_write_mode_toggle(ctx).await,
ReplAction::ToggleWriteMode { ots } => {
write_mode::handle_write_mode_toggle(ctx, ots).await
}
ReplAction::ToggleRedaction => redaction::handle_toggle_redaction(ctx),
ReplAction::Edit => edit::handle_edit(ctx).await,
ReplAction::Copy => copy::handle_copy(),
Expand Down Expand Up @@ -247,7 +249,7 @@ pub async fn run(pool: PgPool, config: Arc<Config>) -> Result<()> {
redact_mode: config.redact_mode,
};

if ReplAction::ToggleWriteMode
if (ReplAction::ToggleWriteMode { ots: None })
.handle(&mut ctx, "")
.await
.is_break()
Expand Down
5 changes: 4 additions & 1 deletion crates/psql/src/repl/help.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,10 @@ pub fn handle_help() -> ControlFlow<()> {
metacmds.add_row(vec!["\\help", "Show this help"]);
metacmds.add_row(vec!["\\q", "Quit"]);
metacmds.add_row(vec!["\\x", "Toggle expanded output mode"]);
metacmds.add_row(vec!["\\W", "Toggle write mode"]);
metacmds.add_row(vec![
"\\W [ots]",
"Toggle write mode (optional OTS skips the prompt)",
]);
metacmds.add_row(vec![
"\\R",
"Toggle redaction mode (when redactions are configured)",
Expand Down
16 changes: 14 additions & 2 deletions crates/psql/src/repl/write_mode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,10 @@ fn should_time_out_write_mode(
matches!(tx_state, TransactionState::Idle | TransactionState::None)
}

pub async fn handle_write_mode_toggle(ctx: &mut ReplContext<'_>) -> ControlFlow<()> {
pub async fn handle_write_mode_toggle(
ctx: &mut ReplContext<'_>,
ots: Option<String>,
) -> ControlFlow<()> {
let state = { ctx.repl_state.lock().unwrap().clone() };

if state.write_mode {
Expand Down Expand Up @@ -79,7 +82,16 @@ pub async fn handle_write_mode_toggle(ctx: &mut ReplContext<'_>) -> ControlFlow<
}
}
} else {
match ots::prompt_for_ots(ctx.rl.history()) {
// A trimmed, non-empty argument is recorded directly as the OTS; an
// empty or absent argument falls back to the interactive prompt. Either
// way the value flows into `new_state.ots`, so the audit records it
// identically to the prompted path.
let supplied_ots = ots.map(|s| s.trim().to_string()).filter(|s| !s.is_empty());
let new_ots = match supplied_ots {
Some(ots) => Ok(ots),
None => ots::prompt_for_ots(ctx.rl.history()),
};
match new_ots {
Ok(new_ots) => {
let mut new_state = state.clone();
new_state.write_mode = true;
Expand Down
Loading