-
Notifications
You must be signed in to change notification settings - Fork 0
feat: Implement \set PROMPT1, PROMPT2, and PROMPT3 commands for Firebolt CLI #4
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
src/meta_commands.rs
Outdated
| fn parse_set_prompt1(command: &str) -> Option<String> { | ||
| static SET_PROMPT_RE: Lazy<Regex> = Lazy::new(|| { | ||
| Regex::new(r#"(?i)^\s*\\set\s+PROMPT1\s+(?:'([^']*)'|"([^"]*)"|(\S+))\s*$"#).unwrap() | ||
| }); | ||
|
|
||
| if let Some(captures) = SET_PROMPT_RE.captures(command) { | ||
| // Check which capture group matched | ||
| if let Some(prompt) = captures.get(1) { | ||
| return Some(prompt.as_str().to_string()); | ||
| } else if let Some(prompt) = captures.get(2) { | ||
| return Some(prompt.as_str().to_string()); | ||
| } else if let Some(prompt) = captures.get(3) { | ||
| return Some(prompt.as_str().to_string()); | ||
| } | ||
| } | ||
|
|
||
| None | ||
| } | ||
|
|
||
| // Parse \set PROMPT2 'value' command | ||
| fn parse_set_prompt2(command: &str) -> Option<String> { | ||
| static SET_PROMPT_RE: Lazy<Regex> = Lazy::new(|| { | ||
| Regex::new(r#"(?i)^\s*\\set\s+PROMPT2\s+(?:'([^']*)'|"([^"]*)"|(\S+))\s*$"#).unwrap() | ||
| }); | ||
|
|
||
| if let Some(captures) = SET_PROMPT_RE.captures(command) { | ||
| // Check which capture group matched | ||
| if let Some(prompt) = captures.get(1) { | ||
| return Some(prompt.as_str().to_string()); | ||
| } else if let Some(prompt) = captures.get(2) { | ||
| return Some(prompt.as_str().to_string()); | ||
| } else if let Some(prompt) = captures.get(3) { | ||
| return Some(prompt.as_str().to_string()); | ||
| } | ||
| } | ||
|
|
||
| None | ||
| } | ||
|
|
||
| // Parse \set PROMPT3 'value' command | ||
| fn parse_set_prompt3(command: &str) -> Option<String> { | ||
| static SET_PROMPT_RE: Lazy<Regex> = Lazy::new(|| { | ||
| Regex::new(r#"(?i)^\s*\\set\s+PROMPT3\s+(?:'([^']*)'|"([^"]*)"|(\S+))\s*$"#).unwrap() | ||
| }); | ||
|
|
||
| if let Some(captures) = SET_PROMPT_RE.captures(command) { | ||
| // Check which capture group matched | ||
| if let Some(prompt) = captures.get(1) { | ||
| return Some(prompt.as_str().to_string()); | ||
| } else if let Some(prompt) = captures.get(2) { | ||
| return Some(prompt.as_str().to_string()); | ||
| } else if let Some(prompt) = captures.get(3) { | ||
| return Some(prompt.as_str().to_string()); | ||
| } | ||
| } | ||
|
|
||
| None | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
copypaste 🫠
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You're absolutely right! There's a lot of code duplication that can be eliminated. Let me refactor the code to use generic functions with better code reuse.
Summary of Refactoring Improvements
I have successfully refactored the code to eliminate duplication and improve maintainability. Here's what was accomplished:
Before Refactoring:
- 6 separate parsing functions with nearly identical code
- parse_set_prompt1(), parse_set_prompt2(), parse_set_prompt3()
- parse_unset_prompt1(), parse_unset_prompt2(), parse_unset_prompt3()
- Each function had its own regex pattern and logic
- Changes required updating multiple functions
After Refactoring:
- 2 generic functions that handle all prompt types
- parse_set_prompt(command, prompt_type) - handles all set operations
- parse_unset_prompt(command, prompt_type) - handles all unset operations
- Single regex pattern for each command type
- Changes only need to be made in one place
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
src/meta_commands.rs
Outdated
| fn parse_unset_prompt1(command: &str) -> bool { | ||
| static UNSET_PROMPT_RE: Lazy<Regex> = Lazy::new(|| { | ||
| Regex::new(r#"(?i)^\s*\\unset\s+PROMPT1\s*$"#).unwrap() | ||
| }); | ||
|
|
||
| UNSET_PROMPT_RE.is_match(command) | ||
| } | ||
|
|
||
| // Parse \unset PROMPT2 command | ||
| fn parse_unset_prompt2(command: &str) -> bool { | ||
| static UNSET_PROMPT_RE: Lazy<Regex> = Lazy::new(|| { | ||
| Regex::new(r#"(?i)^\s*\\unset\s+PROMPT2\s*$"#).unwrap() | ||
| }); | ||
|
|
||
| UNSET_PROMPT_RE.is_match(command) | ||
| } | ||
|
|
||
| // Parse \unset PROMPT3 command | ||
| fn parse_unset_prompt3(command: &str) -> bool { | ||
| static UNSET_PROMPT_RE: Lazy<Regex> = Lazy::new(|| { | ||
| Regex::new(r#"(?i)^\s*\\unset\s+PROMPT3\s*$"#).unwrap() | ||
| }); | ||
|
|
||
| UNSET_PROMPT_RE.is_match(command) | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
and this copypaste

Summary
This PR implements PostgreSQL-compatible prompt customization commands (
\set PROMPT1,\set PROMPT2,\set PROMPT3) for the Firebolt CLI, allowing users to customize their prompt experience based on the current context. This enhancement improves the CLI's consistency with psql and provides users with better control over their interactive experience.Problem Statement
The Firebolt CLI currently uses fixed prompts (
=>,~>,*>) that cannot be customized by users. This limits the user experience and makes the CLI less consistent with PostgreSQL's psql tool, which many users are familiar with. Users need the ability to set custom prompts for different contexts (normal operation, query continuation, and transactions).Solution
Implemented a comprehensive prompt customization system that:
Adds support for three prompt types:
PROMPT1: Normal prompt (default:=>)PROMPT2: Continuation prompt for multi-line queries (default:~>)PROMPT3: Transaction prompt (default:*>)Provides intuitive commands:
\set PROMPT1 'custom> '- Set normal prompt\set PROMPT2 'continue> '- Set continuation prompt\set PROMPT3 'txn> '- Set transaction prompt\unset PROMPT1- Reset to default promptMaintains independence: Each prompt type can be set/unset independently without affecting others
Technical Implementation
New Files
src/meta_commands.rs: Handles parsing and execution of backslash commands with comprehensive regex-based parsing for various quote stylesModified Files
src/context.rs: Extended Context struct with separate prompt fields and setter methodssrc/main.rs: Integrated meta-command handling and updated prompt logic to use context-appropriate promptsKey Features
Usage Examples
Testing
Benefits
Breaking Changes
None. This is a purely additive feature that maintains full backward compatibility.
Documentation
The implementation follows the existing code style and includes comprehensive inline documentation and test coverage.
Related Issues
Testing Instructions
cargo testcargo run -- --host localhost:8123 --database test\set PROMPT1 'test> 'Review Focus