use crate::buffer::{BufferAPI, BufferManager};
use crate::text_navigation::TextNavigator;
pub struct TextNavigationContext<'a> {
pub query: &'a str,
pub cursor_pos: usize,
}
pub struct UndoContext<'a> {
pub buffer_manager: &'a mut BufferManager,
}
#[must_use]
pub fn get_cursor_token_position(ctx: &TextNavigationContext) -> (usize, usize) {
TextNavigator::get_cursor_token_position(ctx.query, ctx.cursor_pos)
}
#[must_use]
pub fn get_token_at_cursor(ctx: &TextNavigationContext) -> Option<String> {
TextNavigator::get_token_at_cursor(ctx.query, ctx.cursor_pos)
}
#[derive(Debug, PartialEq)]
pub enum UndoResult {
Success,
NothingToUndo,
NoBuffer,
}
impl UndoResult {
#[must_use]
pub fn status_message(&self) -> &'static str {
match self {
UndoResult::Success => "Undo performed",
UndoResult::NothingToUndo => "Nothing to undo",
UndoResult::NoBuffer => "No buffer available for undo",
}
}
}
pub fn perform_undo(ctx: &mut UndoContext) -> UndoResult {
if let Some(buffer) = ctx.buffer_manager.current_mut() {
if buffer.perform_undo() {
UndoResult::Success
} else {
UndoResult::NothingToUndo
}
} else {
UndoResult::NoBuffer
}
}
#[must_use]
pub fn check_parser_error(query: &str) -> Option<String> {
let mut paren_depth = 0;
let mut in_string = false;
let mut escape_next = false;
for ch in query.chars() {
if escape_next {
escape_next = false;
continue;
}
match ch {
'\\' if in_string => escape_next = true,
'\'' => in_string = !in_string,
'(' if !in_string => paren_depth += 1,
')' if !in_string => {
paren_depth -= 1;
if paren_depth < 0 {
return Some("Extra )".to_string());
}
}
_ => {}
}
}
if paren_depth > 0 {
return Some(format!("Missing {paren_depth} )"));
}
if in_string {
return Some("Unclosed string".to_string());
}
None
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_get_cursor_token_position() {
let ctx = TextNavigationContext {
query: "SELECT name FROM users",
cursor_pos: 2, };
let (start, end) = get_cursor_token_position(&ctx);
assert!(start <= ctx.cursor_pos);
assert!(end >= ctx.cursor_pos);
}
#[test]
fn test_get_token_at_cursor() {
let ctx = TextNavigationContext {
query: "SELECT name FROM users",
cursor_pos: 2, };
let token = get_token_at_cursor(&ctx);
assert!(token.is_some() || token.is_none()); }
#[test]
fn test_get_token_at_cursor_empty_query() {
let ctx = TextNavigationContext {
query: "",
cursor_pos: 0,
};
let token = get_token_at_cursor(&ctx);
assert!(token.is_none() || token.is_some()); }
#[test]
fn test_undo_result_status_messages() {
assert_eq!(UndoResult::Success.status_message(), "Undo performed");
assert_eq!(
UndoResult::NothingToUndo.status_message(),
"Nothing to undo"
);
assert_eq!(
UndoResult::NoBuffer.status_message(),
"No buffer available for undo"
);
}
#[test]
fn test_check_parser_error_valid_queries() {
assert_eq!(check_parser_error("SELECT * FROM users"), None);
assert_eq!(
check_parser_error("SELECT name FROM users WHERE id = 1"),
None
);
assert_eq!(
check_parser_error("SELECT (column1 + column2) FROM table"),
None
);
assert_eq!(check_parser_error("SELECT 'hello world' FROM dual"), None);
}
#[test]
fn test_check_parser_error_mismatched_parens() {
assert_eq!(
check_parser_error("SELECT (column FROM table"),
Some("Missing 1 )".to_string())
);
assert_eq!(
check_parser_error("SELECT ((column FROM table"),
Some("Missing 2 )".to_string())
);
assert_eq!(
check_parser_error("SELECT column) FROM table"),
Some("Extra )".to_string())
);
}
#[test]
fn test_check_parser_error_unclosed_string() {
assert_eq!(
check_parser_error("SELECT 'unclosed FROM table"),
Some("Unclosed string".to_string())
);
assert_eq!(
check_parser_error("SELECT name FROM users WHERE name = 'test"),
Some("Unclosed string".to_string())
);
}
#[test]
fn test_check_parser_error_escaped_quotes() {
assert_eq!(
check_parser_error("SELECT 'it\\'s a test' FROM table"),
None
);
}
#[test]
fn test_check_parser_error_parens_in_strings() {
assert_eq!(
check_parser_error("SELECT 'text with (parens)' FROM table"),
None
);
assert_eq!(
check_parser_error("SELECT 'text with (unclosed FROM table"),
Some("Unclosed string".to_string())
);
}
#[test]
fn test_check_parser_error_empty_query() {
assert_eq!(check_parser_error(""), None);
}
}