feat: Implement \set PROMPT1, PROMPT2, and PROMPT3 commands for Firebolt CLI#4
Merged
moshap-firebolt merged 2 commits intomainfrom Sep 5, 2025
Merged
feat: Implement \set PROMPT1, PROMPT2, and PROMPT3 commands for Firebolt CLI#4moshap-firebolt merged 2 commits intomainfrom
moshap-firebolt merged 2 commits intomainfrom
Conversation
src/meta_commands.rs
Outdated
Comment on lines
47
to
104
| 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 | ||
| } |
Collaborator
Author
There was a problem hiding this comment.
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
src/meta_commands.rs
Outdated
Comment on lines
107
to
131
| 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) | ||
| } |
Contributor
There was a problem hiding this comment.
and this copypaste
arsenii-firebolt
approved these changes
Aug 26, 2025
arsenii-firebolt
approved these changes
Sep 5, 2025
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

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