refactor: complete nesting simplification (category 3 - 100%)

Simplified deep nesting across the codebase using modern Rust patterns:
let-else guards, early returns, iterator chains, and extracted functions.

**Files improved:**

1. src/tdlib/messages.rs (44 → 28 spaces max indent)
   - fetch_missing_reply_info(): 7 → 2-3 levels
     * Extracted fetch_and_update_reply()
     * Used filter_map and iterator chains
   - get_chat_history() retry loop: 6 → 3 levels
     * Early continue for empty results
     * Used .flatten() instead of nested if-let

2. src/input/main_input.rs (40 → 36 spaces max indent)
   - handle_forward_mode(): 7 → 2-3 levels
     * Extracted forward_selected_message()
   - Reaction picker: 5 → 2-3 levels
     * Extracted send_reaction()
   - Scroll + load older: 6 → 2-3 levels
     * Extracted load_older_messages_if_needed()

3. src/config.rs (36 → 32 spaces max indent)
   - load_credentials(): 7 → 2-3 levels
     * Extracted load_credentials_from_file()
     * Extracted load_credentials_from_env()
     * Used ? operator for Option chains

**Results:**
- Max nesting in entire project: ≤32 spaces (8 levels)
- 8 new functions extracted for better separation of concerns
- All 343 tests passing 

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
Mikhail Kilin
2026-02-04 02:35:56 +03:00
parent 9a04455113
commit c881f74ecb
4 changed files with 305 additions and 193 deletions

View File

@@ -503,36 +503,7 @@ async fn handle_forward_mode<T: TdClientTrait>(app: &mut App<T>, key: KeyEvent)
app.cancel_forward();
}
KeyCode::Enter => {
// Выбираем чат и пересылаем сообщение
let filtered = app.get_filtered_chats();
if let Some(i) = app.chat_list_state.selected() {
if let Some(chat) = filtered.get(i) {
let to_chat_id = chat.id;
if let Some(msg_id) = app.chat_state.selected_message_id() {
if let Some(from_chat_id) = app.get_selected_chat_id() {
match with_timeout_msg(
Duration::from_secs(5),
app.td_client.forward_messages(
to_chat_id,
ChatId::new(from_chat_id),
vec![msg_id],
),
"Таймаут пересылки",
)
.await
{
Ok(_) => {
app.status_message =
Some("Сообщение переслано".to_string());
}
Err(e) => {
app.error_message = Some(e);
}
}
}
}
}
}
forward_selected_message(app).await;
app.cancel_forward();
}
KeyCode::Down => {
@@ -545,8 +516,137 @@ async fn handle_forward_mode<T: TdClientTrait>(app: &mut App<T>, key: KeyEvent)
}
}
/// Пересылает выбранное сообщение в выбранный чат
async fn forward_selected_message<T: TdClientTrait>(app: &mut App<T>) {
// Get all required IDs with early returns
let filtered = app.get_filtered_chats();
let Some(i) = app.chat_list_state.selected() else {
return;
};
let Some(chat) = filtered.get(i) else {
return;
};
let to_chat_id = chat.id;
let Some(msg_id) = app.chat_state.selected_message_id() else {
return;
};
let Some(from_chat_id) = app.get_selected_chat_id() else {
return;
};
// Forward the message with timeout
let result = with_timeout_msg(
Duration::from_secs(5),
app.td_client.forward_messages(
to_chat_id,
ChatId::new(from_chat_id),
vec![msg_id],
),
"Таймаут пересылки",
)
.await;
// Handle result
match result {
Ok(_) => {
app.status_message = Some("Сообщение переслано".to_string());
}
Err(e) => {
app.error_message = Some(e);
}
}
}
/// Отправляет реакцию на выбранное сообщение
async fn send_reaction<T: TdClientTrait>(app: &mut App<T>) {
// Get selected reaction emoji
let Some(emoji) = app.get_selected_reaction().cloned() else {
return;
};
// Get selected message ID
let Some(message_id) = app.get_selected_message_for_reaction() else {
return;
};
// Get chat ID
let Some(chat_id) = app.selected_chat_id else {
return;
};
let message_id = MessageId::new(message_id);
app.status_message = Some("Отправка реакции...".to_string());
app.needs_redraw = true;
// Send reaction with timeout
let result = with_timeout_msg(
Duration::from_secs(5),
app.td_client.toggle_reaction(chat_id, message_id, emoji.clone()),
"Таймаут отправки реакции",
)
.await;
// Handle result
match result {
Ok(_) => {
app.status_message = Some(format!("Реакция {} добавлена", emoji));
app.exit_reaction_picker_mode();
app.needs_redraw = true;
}
Err(e) => {
app.error_message = Some(e);
app.status_message = None;
app.needs_redraw = true;
}
}
}
/// Подгружает старые сообщения если скролл близко к верху
async fn load_older_messages_if_needed<T: TdClientTrait>(app: &mut App<T>) {
// Check if there are messages to load from
if app.td_client.current_chat_messages().is_empty() {
return;
}
// Get the oldest message ID
let oldest_msg_id = app
.td_client
.current_chat_messages()
.first()
.map(|m| m.id())
.unwrap_or(MessageId::new(0));
// Get current chat ID
let Some(chat_id) = app.get_selected_chat_id() else {
return;
};
// Check if scroll is near the top
let message_count = app.td_client.current_chat_messages().len();
if app.message_scroll_offset <= message_count.saturating_sub(10) {
return;
}
// Load older messages with timeout
let Ok(older) = with_timeout(
Duration::from_secs(3),
app.td_client.load_older_messages(ChatId::new(chat_id), oldest_msg_id),
)
.await
else {
return;
};
// Add older messages to the beginning if any were loaded
if !older.is_empty() {
let msgs = app.td_client.current_chat_messages_mut();
msgs.splice(0..0, older);
}
}
/// Обработка модалки подтверждения удаления сообщения
///
///
/// Обрабатывает:
/// - Подтверждение удаления (Y/y/Д/д)
/// - Отмена удаления (N/n/Т/т)
@@ -650,36 +750,7 @@ async fn handle_reaction_picker_mode<T: TdClientTrait>(app: &mut App<T>, key: Ke
}
KeyCode::Enter => {
// Добавить/убрать реакцию
if let Some(emoji) = app.get_selected_reaction().cloned() {
if let Some(message_id) = app.get_selected_message_for_reaction() {
if let Some(chat_id) = app.selected_chat_id {
let message_id = MessageId::new(message_id);
app.status_message = Some("Отправка реакции...".to_string());
app.needs_redraw = true;
match with_timeout_msg(
Duration::from_secs(5),
app.td_client
.toggle_reaction(chat_id, message_id, emoji.clone()),
"Таймаут отправки реакции",
)
.await
{
Ok(_) => {
app.status_message =
Some(format!("Реакция {} добавлена", emoji));
app.exit_reaction_picker_mode();
app.needs_redraw = true;
}
Err(e) => {
app.error_message = Some(e);
app.status_message = None;
app.needs_redraw = true;
}
}
}
}
}
send_reaction(app).await;
}
KeyCode::Esc => {
app.exit_reaction_picker_mode();
@@ -948,36 +1019,8 @@ async fn handle_open_chat_keyboard_input<T: TdClientTrait>(app: &mut App<T>, key
// Скролл вверх (к старым сообщениям)
app.message_scroll_offset += 3;
// Проверяем, нужно ли подгрузить старые сообщения
if !app.td_client.current_chat_messages().is_empty() {
let oldest_msg_id = app
.td_client
.current_chat_messages()
.first()
.map(|m| m.id())
.unwrap_or(MessageId::new(0));
if let Some(chat_id) = app.get_selected_chat_id() {
// Подгружаем больше сообщений если скролл близко к верху
if app.message_scroll_offset
> app.td_client.current_chat_messages().len().saturating_sub(10)
{
if let Ok(older) = with_timeout(
Duration::from_secs(3),
app.td_client
.load_older_messages(ChatId::new(chat_id), oldest_msg_id),
)
.await
{
let older: Vec<crate::tdlib::MessageInfo> = older;
if !older.is_empty() {
// Добавляем старые сообщения в начало
let msgs = app.td_client.current_chat_messages_mut();
msgs.splice(0..0, older);
}
}
}
}
}
// Подгружаем старые сообщения если нужно
load_older_messages_if_needed(app).await;
}
}
_ => {}