refactor: clean up dead code and optimize performance

Major changes:
- Remove unused field `selecting_chat` from ChatState::Forward
- Remove unused field `start_offset` from WrappedLine in messages.rs
- Delete unused functions from modal_handler.rs (ModalAction enum, handle_modal_key, should_close_modal, should_confirm_modal)
- Delete unused functions from validation.rs (is_within_length, is_valid_chat_id, is_valid_message_id, is_valid_user_id, has_items, validate_text_input)
- Remove unused methods from Keybindings (from_event, matches, get_bindings, add_binding, remove_command)
- Delete unused input handlers (chat_list.rs, messages.rs, modal.rs, search.rs)
- Remove unused imports across multiple files

Performance optimizations:
- Fix slow chat opening: load only last 100 messages instead of i32::MAX (10-100x faster)
- Reduce timeout from 30s to 10s for initial message load
- Fix slow text input: replace O(n) string rebuilding with O(1) String::insert()/remove() operations
- Optimize Backspace, Delete, and Char input handlers

Bug fixes:
- Remove duplicate ChatSortOrder tests after enum deletion
- Fix test compilation errors after removing unused methods
- Update tests to use get_command() instead of removed matches() method

Code cleanup:
- Remove ~400 lines of dead code
- Remove 12 unused tests
- Clean up imports in config/mod.rs, main_input.rs, tdlib/messages.rs

Test status: 565 tests passing
Warnings reduced from 40+ to 9

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
Mikhail Kilin
2026-02-04 22:27:02 +03:00
parent bd5e5be618
commit 1cc61ea026
20 changed files with 284 additions and 729 deletions

View File

@@ -4,82 +4,6 @@
use crossterm::event::KeyCode;
/// Результат обработки клавиши в модальном окне.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ModalAction {
/// Закрыть модалку (Escape была нажата)
Close,
/// Подтвердить действие (Enter была нажата)
Confirm,
/// Продолжить обработку ввода (другая клавиша)
Continue,
}
/// Обрабатывает стандартные клавиши для модальных окон.
///
/// Проверяет клавиши Escape (закрыть) и Enter (подтвердить).
/// Если нажата другая клавиша, возвращает `Continue`.
///
/// # Arguments
///
/// * `key_code` - код нажатой клавиши
///
/// # Returns
///
/// * `ModalAction::Close` - если нажата Escape
/// * `ModalAction::Confirm` - если нажата Enter
/// * `ModalAction::Continue` - для других клавиш
///
/// # Examples
///
/// ```
/// use crossterm::event::KeyCode;
/// use tele_tui::utils::modal_handler::{handle_modal_key, ModalAction};
///
/// assert_eq!(handle_modal_key(KeyCode::Esc), ModalAction::Close);
/// assert_eq!(handle_modal_key(KeyCode::Enter), ModalAction::Confirm);
/// assert_eq!(handle_modal_key(KeyCode::Char('a')), ModalAction::Continue);
/// ```
pub fn handle_modal_key(key_code: KeyCode) -> ModalAction {
match key_code {
KeyCode::Esc => ModalAction::Close,
KeyCode::Enter => ModalAction::Confirm,
_ => ModalAction::Continue,
}
}
/// Проверяет, нужно ли закрыть модалку (нажата Escape).
///
/// # Examples
///
/// ```
/// use crossterm::event::KeyCode;
/// use tele_tui::utils::modal_handler::should_close_modal;
///
/// assert!(should_close_modal(KeyCode::Esc));
/// assert!(!should_close_modal(KeyCode::Enter));
/// assert!(!should_close_modal(KeyCode::Char('q')));
/// ```
pub fn should_close_modal(key_code: KeyCode) -> bool {
matches!(key_code, KeyCode::Esc)
}
/// Проверяет, нужно ли подтвердить действие в модалке (нажата Enter).
///
/// # Examples
///
/// ```
/// use crossterm::event::KeyCode;
/// use tele_tui::utils::modal_handler::should_confirm_modal;
///
/// assert!(should_confirm_modal(KeyCode::Enter));
/// assert!(!should_confirm_modal(KeyCode::Esc));
/// assert!(!should_confirm_modal(KeyCode::Char('y')));
/// ```
pub fn should_confirm_modal(key_code: KeyCode) -> bool {
matches!(key_code, KeyCode::Enter)
}
/// Обрабатывает клавиши для подтверждения Yes/No.
///
/// Поддерживает:
@@ -138,28 +62,6 @@ pub fn handle_yes_no(key_code: KeyCode) -> Option<bool> {
mod tests {
use super::*;
#[test]
fn test_handle_modal_key() {
assert_eq!(handle_modal_key(KeyCode::Esc), ModalAction::Close);
assert_eq!(handle_modal_key(KeyCode::Enter), ModalAction::Confirm);
assert_eq!(handle_modal_key(KeyCode::Char('a')), ModalAction::Continue);
assert_eq!(handle_modal_key(KeyCode::Up), ModalAction::Continue);
}
#[test]
fn test_should_close_modal() {
assert!(should_close_modal(KeyCode::Esc));
assert!(!should_close_modal(KeyCode::Enter));
assert!(!should_close_modal(KeyCode::Char('q')));
}
#[test]
fn test_should_confirm_modal() {
assert!(should_confirm_modal(KeyCode::Enter));
assert!(!should_confirm_modal(KeyCode::Esc));
assert!(!should_confirm_modal(KeyCode::Char('y')));
}
#[test]
fn test_handle_yes_no() {
// Yes variants

View File

@@ -2,8 +2,6 @@
//!
//! Переиспользуемые валидаторы для проверки пользовательского ввода.
use crate::types::{ChatId, MessageId, UserId};
/// Проверяет, что строка не пустая (после trim).
///
/// # Examples
@@ -20,112 +18,6 @@ pub fn is_non_empty(text: &str) -> bool {
!text.trim().is_empty()
}
/// Проверяет, что текст не превышает максимальную длину.
///
/// # Arguments
///
/// * `text` - текст для проверки
/// * `max_length` - максимальная длина в символах
///
/// # Examples
///
/// ```
/// use tele_tui::utils::validation::is_within_length;
///
/// assert!(is_within_length("hello", 10));
/// assert!(!is_within_length("very long text here", 5));
/// ```
pub fn is_within_length(text: &str, max_length: usize) -> bool {
text.chars().count() <= max_length
}
/// Проверяет валидность ID чата (не нулевой).
///
/// # Examples
///
/// ```
/// use tele_tui::types::ChatId;
/// use tele_tui::utils::validation::is_valid_chat_id;
///
/// assert!(is_valid_chat_id(ChatId::new(123)));
/// assert!(!is_valid_chat_id(ChatId::new(0)));
/// assert!(!is_valid_chat_id(ChatId::new(-1)));
/// ```
pub fn is_valid_chat_id(chat_id: ChatId) -> bool {
chat_id.as_i64() > 0
}
/// Проверяет валидность ID сообщения (не нулевой).
///
/// # Examples
///
/// ```
/// use tele_tui::types::MessageId;
/// use tele_tui::utils::validation::is_valid_message_id;
///
/// assert!(is_valid_message_id(MessageId::new(456)));
/// assert!(!is_valid_message_id(MessageId::new(0)));
/// ```
pub fn is_valid_message_id(message_id: MessageId) -> bool {
message_id.as_i64() > 0
}
/// Проверяет валидность ID пользователя (не нулевой).
///
/// # Examples
///
/// ```
/// use tele_tui::types::UserId;
/// use tele_tui::utils::validation::is_valid_user_id;
///
/// assert!(is_valid_user_id(UserId::new(789)));
/// assert!(!is_valid_user_id(UserId::new(0)));
/// ```
pub fn is_valid_user_id(user_id: UserId) -> bool {
user_id.as_i64() > 0
}
/// Проверяет, что вектор не пустой.
///
/// # Examples
///
/// ```
/// use tele_tui::utils::validation::has_items;
///
/// assert!(has_items(&vec![1, 2, 3]));
/// assert!(!has_items::<i32>(&vec![]));
/// ```
pub fn has_items<T>(items: &[T]) -> bool {
!items.is_empty()
}
/// Комбинированная валидация текстового ввода:
/// - Не пустой (после trim)
/// - В пределах максимальной длины
///
/// # Examples
///
/// ```
/// use tele_tui::utils::validation::validate_text_input;
///
/// assert!(validate_text_input("hello", 100).is_ok());
/// assert!(validate_text_input("", 100).is_err());
/// assert!(validate_text_input(" ", 100).is_err());
/// assert!(validate_text_input("very long text", 5).is_err());
/// ```
pub fn validate_text_input(text: &str, max_length: usize) -> Result<(), String> {
if !is_non_empty(text) {
return Err("Text cannot be empty".to_string());
}
if !is_within_length(text, max_length) {
return Err(format!(
"Text exceeds maximum length of {} characters",
max_length
));
}
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
@@ -138,54 +30,4 @@ mod tests {
assert!(!is_non_empty(" "));
assert!(!is_non_empty("\t\n"));
}
#[test]
fn test_is_within_length() {
assert!(is_within_length("hello", 10));
assert!(is_within_length("hello", 5));
assert!(!is_within_length("hello", 4));
assert!(is_within_length("", 0));
}
#[test]
fn test_is_valid_chat_id() {
assert!(is_valid_chat_id(ChatId::new(123)));
assert!(is_valid_chat_id(ChatId::new(999999)));
assert!(!is_valid_chat_id(ChatId::new(0)));
assert!(!is_valid_chat_id(ChatId::new(-1)));
}
#[test]
fn test_is_valid_message_id() {
assert!(is_valid_message_id(MessageId::new(456)));
assert!(!is_valid_message_id(MessageId::new(0)));
assert!(!is_valid_message_id(MessageId::new(-1)));
}
#[test]
fn test_is_valid_user_id() {
assert!(is_valid_user_id(UserId::new(789)));
assert!(!is_valid_user_id(UserId::new(0)));
}
#[test]
fn test_has_items() {
assert!(has_items(&vec![1, 2, 3]));
assert!(has_items(&vec!["a"]));
assert!(!has_items::<i32>(&vec![]));
}
#[test]
fn test_validate_text_input() {
// Valid
assert!(validate_text_input("hello", 100).is_ok());
assert!(validate_text_input("test message", 20).is_ok());
// Empty
assert!(validate_text_input("", 100).is_err());
assert!(validate_text_input(" ", 100).is_err());
// Too long
assert!(validate_text_input("very long text", 5).is_err());
}
}