Skip to content

Commit 1a91d5e

Browse files
committed
Added some docs.
1 parent 5230aa8 commit 1a91d5e

File tree

2 files changed

+58
-15
lines changed

2 files changed

+58
-15
lines changed

examples/simple.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,8 +82,7 @@ fn main() {
8282
window.scrollok(true);
8383
noecho();
8484
let mut buffer = [0u8; 64];
85-
let mut o = Output(window);
86-
let mut r = Runner::new(&ROOT_MENU, &mut buffer, &mut o);
85+
let mut r = Runner::new(&ROOT_MENU, &mut buffer, Output(window));
8786
loop {
8887
match r.context.0.getch() {
8988
Some(Input::Character('\n')) => {

src/lib.rs

Lines changed: 57 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,15 @@
1+
//! # Menu
2+
//!
3+
//! A basic command-line interface for `#![no_std]` Rust programs. Peforms
4+
//! zero heap allocation.
15
#![no_std]
6+
#![deny(missing_docs)]
27

3-
type MenuCallbackFn<T> = fn(menu: &Menu<T>, context: &mut T);
4-
type ItemCallbackFn<T> = fn(menu: &Menu<T>, item: &Item<T>, args: &[&str], context: &mut T);
8+
/// The type of function we call when we enter/exit a menu.
9+
pub type MenuCallbackFn<T> = fn(menu: &Menu<T>, context: &mut T);
10+
11+
/// The type of function we call when we a valid command has been entered.
12+
pub type ItemCallbackFn<T> = fn(menu: &Menu<T>, item: &Item<T>, args: &[&str], context: &mut T);
513

614
#[derive(Debug)]
715
/// Describes a parameter to the command
@@ -14,7 +22,9 @@ pub enum Parameter<'a> {
1422
Named(&'a str),
1523
/// A named parameter with argument (e.g. `--mode=foo` or `--level=3`)
1624
NamedValue {
25+
/// The bit that comes after the `--`
1726
parameter_name: &'a str,
27+
/// The bit that comes after the `--name=`, e.g. `INT` or `FILE`. It's mostly for help text.
1828
argument_name: &'a str,
1929
},
2030
}
@@ -25,35 +35,54 @@ pub enum ItemType<'a, T>
2535
where
2636
T: 'a,
2737
{
38+
/// Call a function when this command is entered
2839
Callback {
40+
/// The function to call
2941
function: ItemCallbackFn<T>,
42+
/// The list of parameters for this function. Pass an empty list if there aren't any.
3043
parameters: &'a [Parameter<'a>],
3144
},
45+
/// This item is a sub-menu you can enter
3246
Menu(&'a Menu<'a, T>),
47+
/// Internal use only - do not use
3348
_Dummy,
3449
}
3550

36-
/// Menu Item
51+
/// An `Item` is a what our menus are made from. Each item has a `name` which
52+
/// you have to enter to select this item. Each item can also have zero or
53+
/// more parameters, and some optional help text.
3754
pub struct Item<'a, T>
3855
where
3956
T: 'a,
4057
{
58+
/// The word you need to enter to activate this item. It is recommended
59+
/// that you avoid whitespace in this string.
4160
pub command: &'a str,
61+
/// Optional help text. Printed if you enter `help`.
4262
pub help: Option<&'a str>,
63+
/// The type of this item - menu, callback, etc.
4364
pub item_type: ItemType<'a, T>,
4465
}
4566

46-
/// A Menu is made of Items
67+
/// A `Menu` is made of one or more `Item`s.
4768
pub struct Menu<'a, T>
4869
where
4970
T: 'a,
5071
{
72+
/// Each menu has a label which is visible in the prompt, unless you are
73+
/// the root menu.
5174
pub label: &'a str,
75+
/// A slice of menu items in this menu.
5276
pub items: &'a [&'a Item<'a, T>],
77+
/// A function to call when this menu is entered. If this is the root menu, this is called when the runner is created.
5378
pub entry: Option<MenuCallbackFn<T>>,
79+
/// A function to call when this menu is exited. Never called for the root menu.
5480
pub exit: Option<MenuCallbackFn<T>>,
5581
}
5682

83+
/// This structure handles the menu. You feed it bytes as they are read from
84+
/// the console and it executes menu actions when commands are typed in
85+
/// (followed by Enter).
5786
pub struct Runner<'a, T>
5887
where
5988
T: core::fmt::Write,
@@ -64,7 +93,8 @@ where
6493
/// Maximum four levels deep
6594
menus: [Option<&'a Menu<'a, T>>; 4],
6695
depth: usize,
67-
pub context: &'a mut T,
96+
/// The context object the `Runner` carries around.
97+
pub context: T,
6898
}
6999

70100
/// Looks for the named parameter in the parameter list of the item, then
@@ -192,9 +222,13 @@ impl<'a, T> Runner<'a, T>
192222
where
193223
T: core::fmt::Write,
194224
{
195-
pub fn new(menu: &'a Menu<'a, T>, buffer: &'a mut [u8], context: &'a mut T) -> Runner<'a, T> {
225+
/// Create a new `Runner`. You need to supply a top-level menu, and a
226+
/// buffer that the `Runner` can use. Feel free to pass anything as the
227+
/// `context` type - the only requirement is that the `Runner` can
228+
/// `write!` to the context, which it will do for all text output.
229+
pub fn new(menu: &'a Menu<'a, T>, buffer: &'a mut [u8], mut context: T) -> Runner<'a, T> {
196230
if let Some(cb_fn) = menu.entry {
197-
cb_fn(menu, context);
231+
cb_fn(menu, &mut context);
198232
}
199233
let mut r = Runner {
200234
menus: [Some(menu), None, None, None],
@@ -207,6 +241,8 @@ where
207241
r
208242
}
209243

244+
/// Print out a new command prompt, including sub-menu names if
245+
/// applicable.
210246
pub fn prompt(&mut self, newline: bool) {
211247
if newline {
212248
writeln!(self.context).unwrap();
@@ -224,6 +260,9 @@ where
224260
write!(self.context, "> ").unwrap();
225261
}
226262

263+
/// Add a byte to the menu runner's buffer. If this byte is a
264+
/// carriage-return, the buffer is scanned and the appropriate action
265+
/// performed.
227266
pub fn input_byte(&mut self, input: u8) {
228267
// Strip carriage returns
229268
if input == 0x0A {
@@ -271,8 +310,10 @@ where
271310
}
272311
}
273312

313+
/// Scan the buffer and do the right thing based on its contents.
274314
fn process_command(&mut self) -> Outcome {
275315
if let Ok(command_line) = core::str::from_utf8(&self.buffer[0..self.used]) {
316+
// We have a valid string
276317
if command_line == "help" {
277318
let menu = self.menus[self.depth].unwrap();
278319
for item in menu.items {
@@ -313,7 +354,7 @@ where
313354
function,
314355
parameters,
315356
} => Self::call_function(
316-
self.context,
357+
&mut self.context,
317358
function,
318359
parameters,
319360
menu,
@@ -342,7 +383,8 @@ where
342383
}
343384
}
344385
} else {
345-
writeln!(self.context, "Input not valid UTF8").unwrap();
386+
// Hmm .. we did not have a valid string
387+
writeln!(self.context, "Input was not valid UTF-8").unwrap();
346388
Outcome::CommandProcessed
347389
}
348390
}
@@ -435,10 +477,12 @@ where
435477
}
436478
}
437479
Parameter::NamedValue { parameter_name, .. } => {
438-
if let Some(name) = arg[2..].split('=').next() {
439-
if name == *parameter_name {
440-
found = true;
441-
break;
480+
if arg.contains('=') {
481+
if let Some(name) = arg[2..].split('=').next() {
482+
if name == *parameter_name {
483+
found = true;
484+
break;
485+
}
442486
}
443487
}
444488
}

0 commit comments

Comments
 (0)