Feat: collapsible help

This commit is contained in:
2026-02-16 23:43:25 +01:00
parent 540f59dcf5
commit 524e686b3a
12 changed files with 597 additions and 119 deletions

View File

@@ -3,6 +3,8 @@ use std::sync::atomic::Ordering;
use super::{InputContext, InputResult};
use crate::commands::AppCommand;
use crate::model::categories;
use crate::model::docs;
use crate::state::{ConfirmAction, DictFocus, FlashKind, HelpFocus, Modal};
pub(super) fn handle_help_page(ctx: &mut InputContext, key: KeyEvent) -> InputResult {
@@ -30,6 +32,12 @@ pub(super) fn handle_help_page(ctx: &mut InputContext, key: KeyEvent) -> InputRe
ctx.app.ui.help_focused_block = None;
}
KeyCode::Tab => ctx.dispatch(AppCommand::HelpToggleFocus),
KeyCode::Left if ctx.app.ui.help_focus == HelpFocus::Topics => {
collapse_help_section(ctx);
}
KeyCode::Right if ctx.app.ui.help_focus == HelpFocus::Topics => {
expand_help_section(ctx);
}
KeyCode::Char('n') if ctx.app.ui.help_focus == HelpFocus::Content => {
navigate_code_block(ctx, true);
}
@@ -130,6 +138,66 @@ fn execute_focused_block(ctx: &mut InputContext) {
}
}
fn collapse_help_section(ctx: &mut InputContext) {
if let Some(s) = ctx.app.ui.help_on_section {
if ctx.app.ui.help_collapsed.get(s).copied().unwrap_or(false) {
return;
}
}
let section = match ctx.app.ui.help_on_section {
Some(s) => s,
None => docs::section_index_for_topic(ctx.app.ui.help_topic),
};
if let Some(v) = ctx.app.ui.help_collapsed.get_mut(section) {
*v = true;
}
ctx.app.ui.help_on_section = Some(section);
ctx.app.ui.help_focused_block = None;
}
fn expand_help_section(ctx: &mut InputContext) {
let Some(section) = ctx.app.ui.help_on_section else {
return;
};
if let Some(v) = ctx.app.ui.help_collapsed.get_mut(section) {
*v = false;
}
ctx.app.ui.help_on_section = None;
if let Some(first) = docs::first_topic_in_section(section) {
ctx.app.ui.help_topic = first;
}
ctx.app.ui.help_focused_block = None;
}
fn collapse_dict_section(ctx: &mut InputContext) {
if let Some(s) = ctx.app.ui.dict_on_section {
if ctx.app.ui.dict_collapsed.get(s).copied().unwrap_or(false) {
return;
}
}
let section = match ctx.app.ui.dict_on_section {
Some(s) => s,
None => categories::section_index_for_category(ctx.app.ui.dict_category),
};
if let Some(v) = ctx.app.ui.dict_collapsed.get_mut(section) {
*v = true;
}
ctx.app.ui.dict_on_section = Some(section);
}
fn expand_dict_section(ctx: &mut InputContext) {
let Some(section) = ctx.app.ui.dict_on_section else {
return;
};
if let Some(v) = ctx.app.ui.dict_collapsed.get_mut(section) {
*v = false;
}
ctx.app.ui.dict_on_section = None;
if let Some(first) = categories::first_category_in_section(section) {
ctx.app.ui.dict_category = first;
}
}
pub(super) fn handle_dict_page(ctx: &mut InputContext, key: KeyEvent) -> InputResult {
let ctrl = key.modifiers.contains(KeyModifiers::CONTROL);
@@ -152,6 +220,12 @@ pub(super) fn handle_dict_page(ctx: &mut InputContext, key: KeyEvent) -> InputRe
ctx.dispatch(AppCommand::DictClearSearch);
}
KeyCode::Tab => ctx.dispatch(AppCommand::DictToggleFocus),
KeyCode::Left if ctx.app.ui.dict_focus == DictFocus::Categories => {
collapse_dict_section(ctx);
}
KeyCode::Right if ctx.app.ui.dict_focus == DictFocus::Categories => {
expand_dict_section(ctx);
}
KeyCode::Char('j') | KeyCode::Down => match ctx.app.ui.dict_focus {
DictFocus::Categories => ctx.dispatch(AppCommand::DictNextCategory),
DictFocus::Words => ctx.dispatch(AppCommand::DictScrollDown(1)),