use crate::debugger::Debugger;
use crate::ui::command;
use command::parser;

pub const HELP: &str = r#"
Available debugger commands:

var <name or expression>|locals             -- show local and global variables
arg <name or expression>|all                -- show arguments of current stack frame
vard <name or expression>|locals            -- show local and global variables, using `Debug` trait for render
argd <name or expression>|all               -- show arguments of current stack frame, using `Debug` trait for render
bt, backtrace <>|all                        -- print backtrace of all stack frames in current thread or from all threads
f, frame info|switch <number>               -- print current stack frame information or change frame
c, continue                                 -- continue program being debugged, after signal or breakpoint
r, run                                      -- start or restart debugged programm 
stepi                                       -- step one instruction
step, stepinto                              -- step program until it reaches a different source line
finish, stepout                             -- execute program until selected stack frame returns
next, stepover                              -- step program, stepping over subroutine calls
b, break <addr>|<file:line>|<function>      -- manage breakpoints
w, watch +w|+rw| <expression>|<addr:size>   -- manage write or read-write watchpoints
symbol <name>                               -- print symbol kind and address
mem, memory read|write <addr>               -- read or write into debugged program memory
reg, register read|write|info <addr>        -- read, write, or view debugged program registers
thread info|current|switch <number>         -- show list of threads or current (in focus) thread or set thread in focus
sharedlib info                              -- show list of shared libraries
source asm|fn|<bounds>                      -- show source code or assembly instructions for current (in focus) function
async backtrace|backtrace all|task          -- commands for async rust
trigger info|any|<>|b <number>|w <number>   -- define a list of commands that will be executed when a certain event is triggered
call <function name> <arguments>            -- call a function from debuggee program
oracle <oracle> <>|<subcommand>             -- execute a specific oracle
h, help <>|<command>                        -- show help
tui                                         -- change ui mode to tui
q, quit                                     -- exit the BugStalker 
"#;

pub const DQE_DESCRIPTION: &str = "
\x1b[;1mData query expression\x1b[0m
To analyze data in a program, you often need a tool for introspection of variables, which allows, 
for example, dereference a pointer or taking an array element by index. BugStalker provides a data 
query expressions as such a tool. 

Available operators:
`*` - dereference, available for references, pointers and smart pointers (Rc and Arc)
`&` - address operator, available for any variable, structure field or index value
`~` - canonic representation, types like vectors or hashmaps are prettyfied by default, use canonic operator to see a raw structure as is
`[{left}..{right}]` - slice operator, available for pointers
`.` - get field, available for structs, enums and hashmaps (with string keys)
`(` and `)` - parentheses to prioritize operations
`({ptr/ref type})` - cast constant address to typed pointer or reference
`[{literal}]` - index operator, available for arrays, enums, vectors, veqdequeues, hashmaps, hashsets, btreemaps and btreesets. 
Literal is a json-like object (with wildcards feature), that can be used for matching with real data. 
See `help dqe literal` for more information

Examples:
`**var1` - print the value pointed to by the pointer `*var1`
`**var1.field1` - print the value pointed to by the pointer `*var1.field1`
`&var1.field1` - print address of field `field1`
`(~vec1).len` - print lenght field of vector header structure
`&vec1[1]` - print address of second element in vector `vec1`
`(**var1).field1` - print field `field1` in struct pointed to by the pointer `*var1`
`*(*const i32)0x1234AA332` - cast memory address to `*const i32` pointer, then dereference it 
`hashmap[0x1337]` - get value by pointer key 0x1337 from hashmap 
`hashmap[{\"a\", \"b\"}]` - get value by array key {\"a\", \"b\"} from hashmap
`*(*(var1.field1)).field2[1][2]` - get `field1` from struct `var1`, dereference it, 
then get `field2` from dereference result, then get element by index 1, and get element 2 from it,
finally print dereference of this value
";

pub const DQE_LITERAL_DESCRIPTION: &str = "
\x1b[;1mLiterals in data query expression\x1b[0m
For advanced search of elements in containers (hashmaps, hashsets, etc.), debugger provides an index 
operator that accepts a literal object. This object is very similar to a regular json object, 
but, among other things, it supports wildcards (*) in arrays and associated arrays. 

Scalar literal objects:
- numbers (`123`) - matches with any rust integer values
- strings (`\"abc\") - matches with rust strings or &str's
- float numbers (`123.5`) - matches with rust floats equals with little epsilon
- booleans (`true`) - matches with bool's
- addresses (`0x1337`) - matches with pointers (smart pointers too) and referenses

Complex literal objects:
- arrays (`{1, 2, 3, *, 5}`) - matches with arrays, vectors, tuples, sets
- assoc arrays (`{field_1: 1, field_2: *}`) - matches with structures
- enum variants (`None`) - matches with enums identifiers
- enum variants with values (`Some({true, 12})`) - matches with enums identifiers with items

Example of usage of literal objects:
`map[1]` - get value by int key `1` from hashmap 
`map[\"key_1\"]` - get value by string key `key_1` from hashmap
`set[{*, *, *}]` - checks that there is a vector of any three elements in set
`map[{field_1: 1, field_2: Some({true}), field_3: *}]` - get value by key that matches 3-field structure with
field `field_1` equals to 1, field `field_2` equals to `Option::Some(true)` and field `field_3` equals to any value
";

pub const HELP_VAR: &str = "\
\x1b[32;1mvar\x1b[0m
Show local and global variables, supports data queries expressions over variables (see `help dqe`).

Available subcommands:
var locals - print current stack frame local variables
var <name or expression> - print local and global variables with selected name

Examples of usage:
var locals - print current stack frame local variables
var some_variable - print all variables with given name, variables can be in local or global scope 
var *some_variable - dereference and print value if `some_variable` is a pointer or RC/ARC
var some_array[0] - print first element if `some_array` is a vector, array, vecdeque or enum
var some_array[2..5] - print 3 elements, starts from index 2
var *some_array[0] - print dereferenced value of some_array[0]
var (*some_array)[0] - print first element of *some_array
";

pub const HELP_VAR_LOCALS_SUBCOMMAND: &str = "\
\x1b[32;1mvar locals\x1b[0m
Print current stack frame local variables
";

pub const HELP_VAR_DEBUG: &str = "\
\x1b[32;1mvard\x1b[0m
Show local and global variables using `Debug` trait, supports data queries expressions over variables (see `help dqe`).

Available subcommands:
var locals - print current stack frame local variables
var <name or expression> - print local and global variables with selected name

Examples of usage:
var locals - print current stack frame local variables
var some_variable - print all variables with given name, variables can be in local or global scope 
var *some_variable - dereference and print value if `some_variable` is a pointer or RC/ARC
var some_array[0] - print first element if `some_array` is a vector, array, vecdeque or enum
var some_array[2..5] - print 3 elements, starts from index 2
var *some_array[0] - print dereferenced value of some_array[0]
var (*some_array)[0] - print first element of *some_array
";

pub const HELP_VAR_DEBUG_LOCALS_SUBCOMMAND: &str = "\
\x1b[32;1mvard locals\x1b[0m
Show current stack frame local variables using `Debug` trait, supports data queries expressions over variables (see `help dqe`).
";

pub const HELP_ARG: &str = "\
\x1b[32;1marg\x1b[0m
Show current stack frame arguments, supports data queries expressions over arguments (see `help dqe`).

Available subcommands:
arg all - print all arguments
arg <name or expression> - print argument with selected name

Examples of usage:
arg all - print current stack frame local variables
arg some_arg - print argument with name equals to `some_arg`
arg *some_arg - dereference and print value if `some_arg` is a pointer or RC/ARC
";

pub const HELP_ARG_ALL_SUBCOMMAND: &str = "\
\x1b[32;1marg all\x1b[0m
Show all current stack frame arguments, supports data queries expressions over arguments (see `help dqe`).
";

pub const HELP_ARG_DEBUG: &str = "\
\x1b[32;1margd\x1b[0m
Show current stack frame arguments using `Debug` trait, supports data queries expressions over arguments (see `help dqe`).

Available subcommands:
arg all - print all arguments
arg <name or expression> - print argument with selected name

Examples of usage:
arg all - print current stack frame local variables
arg some_arg - print argument with name equals to `some_arg`
arg *some_arg - dereference and print value if `some_arg` is a pointer or RC/ARC
";

pub const HELP_ARG_DEBUG_ALL_SUBCOMMAND: &str = "\
\x1b[32;1margd all\x1b[0m
Show all arguments using `Debug` trait, supports data queries expressions over arguments (see `help dqe`).
";

pub const HELP_BACKTRACE: &str = "\
\x1b[32;1mbt, backtrace\x1b[0m
Show backtrace of all stack frames in current thread or from all threads.

Available subcommands:
backtrace all - show backtrace for all running threads
backtrace - show backtrace of current thread

Output format:
thread {id} - {current ip value}
{current ip value} - {function name} ({function address} + {offset})
{the address of the instruction in the overlay stack frame} - {function name} ({function address} + {offset})
...
";

pub const HELP_BACKTRACE_ALL_SUBCOMMAND: &str = "\
\x1b[32;1mbacktrace all\x1b[0m
Show backtrace for all running threads

Output format:
thread {id} - {current ip value}
{current ip value} - {function name} ({function address} + {offset})
{the address of the instruction in the overlay stack frame} - {function name} ({function address} + {offset})
...
";

pub const HELP_FRAME: &str = "\
\x1b[32;1mf, frame\x1b[0m
Show current stack frame info or set frame to focus.

Available subcommands:
frame info - show current stack frame information (see output explanation)
frame switch <number> - set frame <number> to focus

Output format:

cfa: {address} -- canonical frame address
return address: {address} - return address for current stack frame
";

pub const HELP_FRAME_INFO_SUBCOMMAND: &str = "\
\x1b[32;1mframe info\x1b[0m
Show current stack frame information (see output explanation)

Output format:
cfa: {address} -- canonical frame address
return address: {address} - return address for current stack frame
";

pub const HELP_FRAME_SWITCH_SUBCOMMAND: &str = "\
\x1b[32;1mframe switch <number>\x1b[0m
Set numbered frame to focus
";

pub const HELP_CONTINUE: &str = "\
\x1b[32;1mc, continue\x1b[0m
Continue program being debugged, after signal or breakpoint.
";

pub const HELP_RUN: &str = "\
\x1b[32;1mr, run\x1b[0m
Start or restart debugged programm.
";

pub const HELP_STEPI: &str = "\
\x1b[32;1mstepi\x1b[0m
step one instruction.
";

pub const HELP_STEPINTO: &str = "\
\x1b[32;1mstep, stepinto\x1b[0m
Step program until it reaches a different source line.
";

pub const HELP_STEPOUT: &str = "\
\x1b[32;1mfinish, stepout\x1b[0m
Execute program until selected stack frame returns.
";

pub const HELP_STEPOVER: &str = "\
\x1b[32;1mnext, stepover\x1b[0m
Step program, stepping over subroutine calls.
";

pub const HELP_BREAK: &str = "\
\x1b[32;1mb, break\x1b[0m
Manage breakpoints.

Available subcommands:
break <location> - set breakpoint to location
break remove <location>|<number> - deactivate and delete selected breakpoint
break info - show all breakpoints

Possible location format:
- at instruction. Example: break 0x55555555BD30
- at function start. A function can be defined by its full name (with namespace) 
or by function name (in case of possible collisions, breakpoints will be set in 
all matching functions). Examples: 
    * break fn1 
    * break module1::fn1
- at code line. Example: break hello_world.rs:15
- a breakpoint number (only for `remove` subcommand)
";

pub const HELP_BREAK_REMOVE_SUBCOMMAND: &str = "\
\x1b[32;1mbreak remove <location>|<number>\x1b[0m
Deactivate and delete selected breakpoint

Possible location format:
- at instruction. Example: break 0x55555555BD30
- at function start. A function can be defined by its full name (with namespace) 
or by function name (in case of possible collisions, breakpoints will be set in 
all matching functions). Examples:
    * break fn1
    * break module1::fn1
- at code line. Example: break hello_world.rs:15
- a breakpoint number
";

pub const HELP_BREAK_INFO_SUBCOMMAND: &str = "\
\x1b[32;1mbreak info\x1b[0m
Show all breakpoints
";

pub const HELP_WATCH: &str = "\
\x1b[32;1mw, watch\x1b[0m
Manage watchpoints. Note that watchpoints for local variables and watchpoints for global varibales
or raw memory region have a different lifetimes. Watchpoints for global variables or memory locations
are lives until BugStalker session is alive. On the contrary, watchpoints for local variables
are lives until debugee is not restarted, and will be removed automatically.

Available subcommands:
watch +rw|+w| <addr:size> - set write or read-write watchpoint (write by default) to memory location [addr; addr+size], size must be one of [1,2,4,8] bytes
watch +rw|+w| <expression> - set write or read-write watchpoint (write by default) to DQE result (see `help dqe`), expression result must one of [1,2,4,8] bytes
watch remove <addr:size>|<expression>|<number> - deactivate and delete selected watchpoint
watch info - show all watchpoints

Examples:
* watch 0x00000004:4 - set watchpoint to memory region [0x0..04:0x0..07]
* watch var1 - set watchpoint (write condition) to variable `var1`
* watch +rw var1 - set watchpoint (read-write condition) to variable `var1`
* watch struct1.field1 - set watchpoint to `field1` of variable `struct1`
* watch arr[2] - set watchpoint to 2nd element of variable `arr`
";

pub const HELP_WATCH_REMOVE_SUBCOMMAND: &str = "\
\x1b[32;1mwatch remove <addr:size>|<expression>|<number>\x1b[0m
Deactivate and delete selected watchpoint

Examples:
* watch remove 0x00000004:4 - deactivate and delete watchpoint from memory region [0x0..04:0x0..07]
* watch remove var1 - deactivate and delete watchpoint from variable `var1`
* watch remove struct1.field1 - deactivate and delete watchpoint from `field1` of variable `struct1`
* watch remove arr[2] - deactivate and delete watchpoint from 2nd element of variable `arr`
";

pub const HELP_WATCH_INFO_SUBCOMMAND: &str = "\
\x1b[32;1mwatch info\x1b[0m
Show all watchpoints
";

pub const HELP_SYMBOL: &str = "\
\x1b[32;1msymbol\x1b[0m
Print symbols matched by regular expression.

Available subcommands:
symbol <name_regex>
";

pub const HELP_MEMORY: &str = "\
\x1b[32;1mmem, memory\x1b[0m
Read or write into debugged program memory.

Available subcommands:
memory read <address> - print 8-byte block at address in debuggee memory
memory write <address> <value> - writes 8-byte value to address in debuggee memory. 
Note that little endian byte order will be used when writing, so the last byte of <value> will be written at the first byte of the address
";

pub const HELP_MEMORY_READ_SUBCOMMAND: &str = "\
\x1b[32;1mmemory read <address>\x1b[0m
Print 8-byte block at address in debuggee memory
Note that little endian byte order will be used when writing, so the last byte of <value> will be written at the first byte of the address
";

pub const HELP_MEMORY_WRITE_SUBCOMMAND: &str = "\
\x1b[32;1mmemory write <address> <value>\x1b[0m
Writes 8-byte value to address in debuggee memory. 
Note that little endian byte order will be used when writing, so the last byte of <value> will be written at the first byte of the address
";

pub const HELP_REGISTER: &str = "\
\x1b[32;1mreg, register\x1b[0m
Read, write, or view debugged program registers (x86_64 registers support).

Available subcommands:
register read <reg_name> - print value of register by name (x86_64 register name in lowercase)
register write <reg_name> <value> - set new value to register by name
register info - print list of registers with it values
";

pub const HELP_REGISTER_READ_SUBCOMMAND: &str = "\
\x1b[32;1mregister read <reg_name>\x1b[0m
Read debugged program registers (x86_64 registers support).
(x86_64 register name in lowercase)
";

pub const HELP_REGISTER_WRITE_SUBCOMMAND: &str = "\
\x1b[32;1mregister write <reg_name> <value>\x1b[0m
Write debugged program registers (x86_64 registers support).
(x86_64 register name in lowercase)
";

pub const HELP_REGISTER_INFO_SUBCOMMAND: &str = "\
\x1b[32;1mregister info\x1b[0m
Print debugged program registers with it values (x86_64 registers support).
";

pub const HELP_THREAD: &str = "\
\x1b[32;1mthread\x1b[0m
Show threads information or set thread to focus.

Available subcommands:
thread info - print list of thread information
thread current - prints thread that has focus
thread switch <number> - set thread <number> to focus
";

pub const HELP_THREAD_INFO_SUBCOMMAND: &str = "\
\x1b[32;1mthread info\x1b[0m
Shows threads information.
";

pub const HELP_THREAD_CURRENT_SUBCOMMAND: &str = "\
\x1b[32;1mthread current\x1b[0m
Prints thread that has focus.
";

pub const HELP_THREAD_SWITCH_SUBCOMMAND: &str = "\
\x1b[32;1mthread switch <number>\x1b[0m
Set thread to focus.
";

pub const HELP_SHARED_LIB: &str = "\
\x1b[32;1msharedlib\x1b[0m
Show shared libraries information.

Available subcommands:
sharedlib info - print list of loaded shared libraries and their mapping addresses
";

pub const HELP_SHARED_LIB_INFO_SUBCOMMAND: &str = "\
\x1b[32;1msharedlib info\x1b[0m
Prints list of loaded shared libraries and their mapping addresses
";

pub const HELP_SOURCE: &str = "\
\x1b[32;1msource\x1b[0m
Show source code or assembly instructions for current (in focus) function.

Available subcommands:
source fn - show code of function in focus 
source asm - show assembly of function in focus 
source <bounds> - show line in focus with <bounds> lines up and down of this line
";

pub const HELP_SOURCE_FN_SUBCOMMAND: &str = "\
\x1b[32;1msource fn\x1b[0m
Shows code of function in focus.
";

pub const HELP_SOURCE_ASM_SUBCOMMAND: &str = "\
\x1b[32;1msource asm\x1b[0m
Shows assembly of function in focus.
";

pub const HELP_ASYNC: &str = "\
\x1b[32;1masync\x1b[0m
Commands for async rust (currently for tokio runtime only).

Available subcommands:
async backtrace - show state of async workers and blocking threads
async backtrace all - show state of async workers and blocking threads, show info about all running tasks 
async task <async_fn_regex> - show active task (active task means a task that is running on the thread that is currently in focus) if `async_fn_regex` parameter is empty,
or show task list with async functions matched by regular expression
async next, async stepover - perform a stepover within the context of the current task. If the task moves into a completed state, the application will stop too
async finish, async stepout - execute the program until the current task moves into the completed state
";

pub const HELP_ASYNC_BACKTRACE_SUBCOMMAND: &str = "\
\x1b[32;1masync backtrace\x1b[0m
Show state of async workers and blocking threads (currently for tokio runtime only).

Available subcommands:
async backtrace all - show info about all running tasks 
";

pub const HELP_ASYNC_TASK_SUBCOMMAND: &str = "\
\x1b[32;1masync task <async_fn_regex>\x1b[0m
Show active task (active task means a task that is running on the thread that is currently in focus) if `async_fn_regex` parameter is empty,
or show task list with async functions matched by regular expression (currently for tokio runtime only).
";

pub const HELP_ASYNC_NEXT_STEPOVER_SUBCOMMANDS: &str = "\
\x1b[32;1masync next, async stepover\x1b[0m
Perform a stepover within the context of the current task. If the task moves into a completed state,
the application will stop too (currently for tokio runtime only).
";

pub const HELP_ASYNC_FINISH_STEPOUT_SUBCOMMANDS: &str = "\
\x1b[32;1masync finish, async stepout\x1b[0m
Execute the program until the current task moves into the completed state (currently for tokio runtime only).
";

pub const HELP_TRIGGER: &str = "\
\x1b[32;1mtrigger\x1b[0m
Define a list of commands that will be executed when a certain event is triggered (at a breakpoint or watchpoint hit).

Available subcommands:
trigger any - define a list of commands that will be executed when any breakpoint or watchpoint is hit
trigger - define a list of commands that will be executed when a previously defined breakpoint or watchpoint is hit
trigger b <number> - define a list of commands that will be executed when the given breakpoint is hit
trigger w <number> - define a list of commands that will be executed when the given watchpoint is hit
trigger info - show the list of triggers
";

pub const HELP_TRIGGER_ANY_SUBCOMMAND: &str = "\
\x1b[32;1mtrigger any\x1b[0m
Define a list of commands that will be executed when any breakpoint or watchpoint is hit
";

pub const HELP_TRIGGER_BRAKEPOINT_SUBCOMMAND: &str = "\
\x1b[32;1mtrigger b <number>\x1b[0m
Define a list of commands that will be executed when the given breakpoint is hit
";

pub const HELP_TRIGGER_WATCHPOINT_SUBCOMMAND: &str = "\
\x1b[32;1mtrigger w <number>\x1b[0m
Define a list of commands that will be executed when the given watchpoint is hit
";

pub const HELP_TRIGGER_INFO_SUBCOMMAND: &str = "\
\x1b[32;1mtrigger info\x1b[0m
Shows the list of triggers
";

pub const HELP_CALL: &str = "\
\x1b[32;1mcall\x1b[0m
Call a function with given arguments. 

Format:
call <function_name> <arg1> ... <arg6>

Current limitations:
- a maximum of six arguments is allowed
- only integer (i8, u8, ... i64, u64), boolean and pointer argument types are supported
- the return value will be ignored
- arguments should be given as literals (see `help dqe literal`).

Examples:
call sum 1 10 - call function `sum` with two integer arguments
call print_ptr 0x007FFFFFFFD560 - call function `print_ptr` with pointer argument
";

pub const HELP_TUI: &str = "\
\x1b[32;1mtui\x1b[0m
Change ui mode to terminal ui.
";

pub const HELP_ORACLE: &str = "\
\x1b[32;1moracle\x1b[0m
Execute a specific oracle.

List of available oracles:
";

pub const HELP_QUIT: &str = "\
\x1b[32;1mq, quit\x1b[0m
Exit the BugStalker, kill debugee before it.
";

pub const HELP_UNKNOWN_SUBCOMMAND: &str = "\
Unknown subcommand";

#[derive(Default)]
pub struct Helper {
    oracle_help: Option<String>,
}

impl Helper {
    pub fn new(debugger: &Debugger) -> Self {
        let mut help = HELP_ORACLE.to_string();
        let oracles = debugger.all_oracles();
        oracles.for_each(|oracle| help = format!("{help}{}\n", oracle.help()));
        Self {
            oracle_help: Some(help),
        }
    }

    pub fn help_for_command(&self, command: Option<&str>) -> &str {
        let (main_command, sub_command) = match command {
            None => (None, None),
            Some(s) => {
                let mut parts = s.split_whitespace();
                let main = parts.next();
                let sub = parts.next();
                (main, sub)
            }
        };

        match main_command {
            None => HELP,
            Some("dqe") => DQE_DESCRIPTION,
            Some("dqe literal") => DQE_LITERAL_DESCRIPTION,
            Some(parser::VAR_COMMAND) => match sub_command {
                None => HELP_VAR,
                Some(parser::VAR_LOCAL_KEY) => HELP_VAR_LOCALS_SUBCOMMAND,
                _ => HELP_UNKNOWN_SUBCOMMAND,
            },
            Some(parser::ARG_COMMAND) => match sub_command {
                None => HELP_ARG,
                Some(parser::ARG_ALL_KEY) => HELP_ARG_ALL_SUBCOMMAND,
                _ => HELP_UNKNOWN_SUBCOMMAND,
            },
            Some(parser::VAR_DEBUG_COMMAND) => match sub_command {
                None => HELP_VAR_DEBUG,
                Some(parser::VAR_LOCAL_KEY) => HELP_VAR_DEBUG_LOCALS_SUBCOMMAND,
                _ => HELP_UNKNOWN_SUBCOMMAND,
            },
            Some(parser::ARG_DEBUG_COMMAND) => match sub_command {
                None => HELP_ARG_DEBUG,
                Some(parser::ARG_ALL_KEY) => HELP_ARG_DEBUG_ALL_SUBCOMMAND,
                _ => HELP_UNKNOWN_SUBCOMMAND,
            },
            Some(parser::BACKTRACE_COMMAND) | Some(parser::BACKTRACE_COMMAND_SHORT) => {
                match sub_command {
                    None => HELP_BACKTRACE,
                    Some(parser::BACKTRACE_ALL_SUBCOMMAND) => HELP_BACKTRACE_ALL_SUBCOMMAND,
                    _ => HELP_UNKNOWN_SUBCOMMAND,
                }
            }
            Some(parser::FRAME_COMMAND) | Some(parser::FRAME_COMMAND_SHORT) => match sub_command {
                None => HELP_FRAME,
                Some(parser::FRAME_COMMAND_INFO_SUBCOMMAND) => HELP_FRAME_INFO_SUBCOMMAND,
                Some(parser::FRAME_COMMAND_SWITCH_SUBCOMMAND) => HELP_FRAME_SWITCH_SUBCOMMAND,
                _ => HELP_UNKNOWN_SUBCOMMAND,
            },
            Some(parser::CONTINUE_COMMAND) | Some(parser::CONTINUE_COMMAND_SHORT) => HELP_CONTINUE,
            Some(parser::RUN_COMMAND) | Some(parser::RUN_COMMAND_SHORT) => HELP_RUN,
            Some(parser::STEP_INSTRUCTION_COMMAND) => HELP_STEPI,
            Some(parser::STEP_INTO_COMMAND) | Some(parser::STEP_INTO_COMMAND_SHORT) => {
                HELP_STEPINTO
            }
            Some(parser::STEP_OUT_COMMAND) | Some(parser::STEP_OUT_COMMAND_SHORT) => HELP_STEPOUT,
            Some(parser::STEP_OVER_COMMAND) | Some(parser::STEP_OVER_COMMAND_SHORT) => {
                HELP_STEPOVER
            }
            Some(parser::BREAK_COMMAND) | Some(parser::BREAK_COMMAND_SHORT) => match sub_command {
                None => HELP_BREAK,
                Some(parser::BREAK_REMOVE_SUBCOMMAND)
                | Some(parser::BREAK_REMOVE_SUBCOMMAND_SHORT) => HELP_BREAK_REMOVE_SUBCOMMAND,
                Some(parser::BREAK_INFO_SUBCOMMAND) => HELP_BREAK_INFO_SUBCOMMAND,
                _ => HELP_UNKNOWN_SUBCOMMAND,
            },
            Some(parser::WATCH_COMMAND) | Some(parser::WATCH_COMMAND_SHORT) => match sub_command {
                None => HELP_WATCH,
                Some(parser::WATCH_REMOVE_SUBCOMMAND)
                | Some(parser::WATCH_REMOVE_SUBCOMMAND_SHORT) => HELP_WATCH_REMOVE_SUBCOMMAND,
                Some(parser::WATCH_INFO_SUBCOMMAND) => HELP_WATCH_INFO_SUBCOMMAND,
                _ => HELP_UNKNOWN_SUBCOMMAND,
            },
            Some(parser::SYMBOL_COMMAND) => HELP_SYMBOL,
            Some(parser::MEMORY_COMMAND) | Some(parser::MEMORY_COMMAND_SHORT) => {
                match sub_command {
                    None => HELP_MEMORY,
                    Some(parser::MEMORY_COMMAND_READ_SUBCOMMAND) => HELP_MEMORY_READ_SUBCOMMAND,
                    Some(parser::MEMORY_COMMAND_WRITE_SUBCOMMAND) => HELP_MEMORY_WRITE_SUBCOMMAND,
                    _ => HELP_UNKNOWN_SUBCOMMAND,
                }
            }
            Some(parser::REGISTER_COMMAND) | Some(parser::REGISTER_COMMAND_SHORT) => {
                match sub_command {
                    None => HELP_REGISTER,
                    Some(parser::REGISTER_COMMAND_READ_SUBCOMMAND) => HELP_REGISTER_READ_SUBCOMMAND,
                    Some(parser::REGISTER_COMMAND_WRITE_SUBCOMMAND) => {
                        HELP_REGISTER_WRITE_SUBCOMMAND
                    }
                    Some(parser::REGISTER_COMMAND_INFO_SUBCOMMAND) => HELP_REGISTER_INFO_SUBCOMMAND,
                    _ => HELP_UNKNOWN_SUBCOMMAND,
                }
            }
            Some(parser::THREAD_COMMAND) => match sub_command {
                None => HELP_THREAD,
                Some(parser::THREAD_COMMAND_CURRENT_SUBCOMMAND) => HELP_THREAD_CURRENT_SUBCOMMAND,
                Some(parser::THREAD_COMMAND_INFO_SUBCOMMAND) => HELP_THREAD_INFO_SUBCOMMAND,
                Some(parser::THREAD_COMMAND_SWITCH_SUBCOMMAND) => HELP_THREAD_SWITCH_SUBCOMMAND,
                _ => HELP_UNKNOWN_SUBCOMMAND,
            },
            Some(parser::SHARED_LIB_COMMAND) => match sub_command {
                None => HELP_SHARED_LIB,
                Some(parser::SHARED_LIB_COMMAND_INFO_SUBCOMMAND) => HELP_SHARED_LIB_INFO_SUBCOMMAND,
                _ => HELP_UNKNOWN_SUBCOMMAND,
            },
            Some(parser::SOURCE_COMMAND) => match sub_command {
                None => HELP_SOURCE,
                Some(parser::SOURCE_COMMAND_FUNCTION_SUBCOMMAND) => HELP_SOURCE_FN_SUBCOMMAND,
                Some(parser::SOURCE_COMMAND_DISASM_SUBCOMMAND) => HELP_SOURCE_ASM_SUBCOMMAND,
                _ => HELP_UNKNOWN_SUBCOMMAND,
            },
            Some(parser::ASYNC_COMMAND) => match sub_command {
                None => HELP_ASYNC,
                Some(parser::ASYNC_COMMAND_BACKTRACE_SUBCOMMAND)
                | Some(parser::ASYNC_COMMAND_BACKTRACE_SUBCOMMAND_SHORT) => {
                    HELP_ASYNC_BACKTRACE_SUBCOMMAND
                }
                Some(parser::ASYNC_COMMAND_STEP_OUT_SUBCOMMAND)
                | Some(parser::ASYNC_COMMAND_STEP_OUT_SUBCOMMAND_SHORT) => {
                    HELP_ASYNC_FINISH_STEPOUT_SUBCOMMANDS
                }
                Some(parser::ASYNC_COMMAND_STEP_OVER_SUBCOMMAND)
                | Some(parser::ASYNC_COMMAND_STEP_OVER_SUBCOMMAND_SHORT) => {
                    HELP_ASYNC_NEXT_STEPOVER_SUBCOMMANDS
                }
                Some(parser::ASYNC_COMMAND_TASK_SUBCOMMAND) => HELP_ASYNC_TASK_SUBCOMMAND,
                _ => HELP_UNKNOWN_SUBCOMMAND,
            },
            Some(parser::TRIGGER_COMMAND) => match sub_command {
                Some(parser::TRIGGER_COMMAND_ANY_TRIGGER_SUBCOMMAND) => HELP_TRIGGER_ANY_SUBCOMMAND,
                Some(parser::TRIGGER_COMMAND_BRKPT_TRIGGER_SUBCOMMAND) => {
                    HELP_TRIGGER_BRAKEPOINT_SUBCOMMAND
                }
                Some(parser::TRIGGER_COMMAND_WP_TRIGGER_SUBCOMMAND) => {
                    HELP_TRIGGER_WATCHPOINT_SUBCOMMAND
                }
                Some(parser::TRIGGER_COMMAND_INFO_SUBCOMMAND) => HELP_TRIGGER_INFO_SUBCOMMAND,
                _ => HELP_TRIGGER,
            },
            Some(parser::CALL_COMMAND) => HELP_CALL,
            Some(parser::ORACLE_COMMAND) => self.oracle_help.as_deref().unwrap_or(HELP_ORACLE),
            Some("tui") => HELP_TUI,
            Some("q") | Some("quit") => HELP_QUIT,
            _ => "unknown command",
        }
    }
}
