Loading system/gd/rust/linux/client/Cargo.toml +1 −0 Original line number Diff line number Diff line Loading @@ -5,6 +5,7 @@ edition = "2018" [dependencies] rustyline = "8.0" rustyline-derive = "0.4.0" bt_topshim = { path = "../../topshim" } btstack = { path = "../stack" } manager_service = { path = "../mgmt" } Loading system/gd/rust/linux/client/src/command_handler.rs +19 −1 Original line number Diff line number Diff line Loading @@ -65,16 +65,34 @@ pub struct CommandHandler<TBluetoothManager: IBluetoothManager, TBluetooth: IBlu bluetooth: Arc<Mutex<Box<TBluetooth>>>, is_bluetooth_callback_registered: bool, commands: Vec<String>, } impl<TBluetoothManager: IBluetoothManager, TBluetooth: IBluetooth> CommandHandler<TBluetoothManager, TBluetooth> { /// Creates a new CommandHandler. /// /// * `commands` - List of commands for `help`. pub fn new( bluetooth_manager: Arc<Mutex<Box<TBluetoothManager>>>, bluetooth: Arc<Mutex<Box<TBluetooth>>>, commands: Vec<String>, ) -> CommandHandler<TBluetoothManager, TBluetooth> { CommandHandler { bluetooth_manager, bluetooth, is_bluetooth_callback_registered: false } CommandHandler { bluetooth_manager, bluetooth, is_bluetooth_callback_registered: false, commands, } } pub fn cmd_help(&self) { println!("Available commands:"); for cmd in &self.commands { println!("{}", cmd); } } pub fn cmd_enable(&self, _cmd: String) { Loading system/gd/rust/linux/client/src/editor.rs +56 −6 Original line number Diff line number Diff line Loading @@ -2,7 +2,13 @@ use futures::Future; use rustyline::{Config, Editor}; use rustyline::completion::Completer; use rustyline::error::ReadlineError; use rustyline::highlight::Highlighter; use rustyline::hint::Hinter; use rustyline::validate::Validator; use rustyline::{CompletionType, Config, Editor}; use rustyline_derive::Helper; use std::pin::Pin; use std::sync::{Arc, Mutex}; Loading @@ -10,13 +16,50 @@ use std::task::{Context, Poll}; use crate::console_blue; #[derive(Helper)] struct BtHelper { commands: Vec<String>, } impl Completer for BtHelper { type Candidate = String; // Returns completion based on supported commands. // TODO: Add support to autocomplete BT address, command parameters, etc. fn complete( &self, line: &str, pos: usize, _ctx: &rustyline::Context<'_>, ) -> Result<(usize, Vec<String>), ReadlineError> { let slice = &line[..pos]; let mut completions = vec![]; for cmd in self.commands.iter() { if cmd.starts_with(slice) { completions.push(cmd.clone()); } } Ok((0, completions)) } } impl Hinter for BtHelper { type Hint = String; } impl Highlighter for BtHelper {} impl Validator for BtHelper {} /// A future that does async readline(). /// /// async readline() is implemented by spawning a thread for the blocking readline(). While this /// readline() thread is blocked, it yields back to executor and will wake the executor up when the /// blocked thread has proceeded and got input from readline(). pub struct AsyncReadline { rl: Arc<Mutex<Editor<()>>>, rl: Arc<Mutex<Editor<BtHelper>>>, result: Arc<Mutex<Option<rustyline::Result<String>>>>, } Loading Loading @@ -44,15 +87,22 @@ impl Future for AsyncReadline { /// Wrapper of rustyline editor that supports async readline(). pub struct AsyncEditor { rl: Arc<Mutex<Editor<()>>>, rl: Arc<Mutex<Editor<BtHelper>>>, } impl AsyncEditor { /// Creates new async rustyline editor. pub fn new() -> AsyncEditor { let builder = Config::builder().auto_add_history(true).history_ignore_dups(true); /// /// * `commands` - List of commands for autocomplete. pub fn new(commands: Vec<String>) -> AsyncEditor { let builder = Config::builder() .auto_add_history(true) .history_ignore_dups(true) .completion_type(CompletionType::List); let config = builder.build(); let rl = rustyline::Editor::<()>::with_config(config); let mut rl = rustyline::Editor::with_config(config); let helper = BtHelper { commands }; rl.set_helper(Some(helper)); AsyncEditor { rl: Arc::new(Mutex::new(rl)) } } Loading system/gd/rust/linux/client/src/main.rs +19 −2 Original line number Diff line number Diff line Loading @@ -98,9 +98,26 @@ fn main() -> Result<(), Box<dyn std::error::Error>> { objpath: String::from("/org/chromium/bluetooth/client/bluetooth_manager_callback"), })); let mut handler = CommandHandler::new(api.bluetooth_manager.clone(), api.bluetooth.clone()); // TODO(b/193719802): Refactor this into a dedicated "Help" data structure. let commands = vec![ String::from("help"), String::from("enable"), String::from("disable"), String::from("get_address"), String::from("start_discovery"), String::from("cancel_discovery"), String::from("create_bond"), ]; let mut handler = CommandHandler::new( api.bluetooth_manager.clone(), api.bluetooth.clone(), commands.clone(), ); let mut handle_cmd = move |cmd: String| match cmd.split(' ').collect::<Vec<&str>>()[0] { "help" => handler.cmd_help(), "enable" => handler.cmd_enable(cmd), "disable" => handler.cmd_disable(cmd), "get_address" => handler.cmd_get_address(cmd), Loading @@ -115,7 +132,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> { _ => print_info!("Command \"{}\" not recognized", cmd), }; let editor = AsyncEditor::new(); let editor = AsyncEditor::new(commands.clone()); loop { let result = editor.readline().await; Loading Loading
system/gd/rust/linux/client/Cargo.toml +1 −0 Original line number Diff line number Diff line Loading @@ -5,6 +5,7 @@ edition = "2018" [dependencies] rustyline = "8.0" rustyline-derive = "0.4.0" bt_topshim = { path = "../../topshim" } btstack = { path = "../stack" } manager_service = { path = "../mgmt" } Loading
system/gd/rust/linux/client/src/command_handler.rs +19 −1 Original line number Diff line number Diff line Loading @@ -65,16 +65,34 @@ pub struct CommandHandler<TBluetoothManager: IBluetoothManager, TBluetooth: IBlu bluetooth: Arc<Mutex<Box<TBluetooth>>>, is_bluetooth_callback_registered: bool, commands: Vec<String>, } impl<TBluetoothManager: IBluetoothManager, TBluetooth: IBluetooth> CommandHandler<TBluetoothManager, TBluetooth> { /// Creates a new CommandHandler. /// /// * `commands` - List of commands for `help`. pub fn new( bluetooth_manager: Arc<Mutex<Box<TBluetoothManager>>>, bluetooth: Arc<Mutex<Box<TBluetooth>>>, commands: Vec<String>, ) -> CommandHandler<TBluetoothManager, TBluetooth> { CommandHandler { bluetooth_manager, bluetooth, is_bluetooth_callback_registered: false } CommandHandler { bluetooth_manager, bluetooth, is_bluetooth_callback_registered: false, commands, } } pub fn cmd_help(&self) { println!("Available commands:"); for cmd in &self.commands { println!("{}", cmd); } } pub fn cmd_enable(&self, _cmd: String) { Loading
system/gd/rust/linux/client/src/editor.rs +56 −6 Original line number Diff line number Diff line Loading @@ -2,7 +2,13 @@ use futures::Future; use rustyline::{Config, Editor}; use rustyline::completion::Completer; use rustyline::error::ReadlineError; use rustyline::highlight::Highlighter; use rustyline::hint::Hinter; use rustyline::validate::Validator; use rustyline::{CompletionType, Config, Editor}; use rustyline_derive::Helper; use std::pin::Pin; use std::sync::{Arc, Mutex}; Loading @@ -10,13 +16,50 @@ use std::task::{Context, Poll}; use crate::console_blue; #[derive(Helper)] struct BtHelper { commands: Vec<String>, } impl Completer for BtHelper { type Candidate = String; // Returns completion based on supported commands. // TODO: Add support to autocomplete BT address, command parameters, etc. fn complete( &self, line: &str, pos: usize, _ctx: &rustyline::Context<'_>, ) -> Result<(usize, Vec<String>), ReadlineError> { let slice = &line[..pos]; let mut completions = vec![]; for cmd in self.commands.iter() { if cmd.starts_with(slice) { completions.push(cmd.clone()); } } Ok((0, completions)) } } impl Hinter for BtHelper { type Hint = String; } impl Highlighter for BtHelper {} impl Validator for BtHelper {} /// A future that does async readline(). /// /// async readline() is implemented by spawning a thread for the blocking readline(). While this /// readline() thread is blocked, it yields back to executor and will wake the executor up when the /// blocked thread has proceeded and got input from readline(). pub struct AsyncReadline { rl: Arc<Mutex<Editor<()>>>, rl: Arc<Mutex<Editor<BtHelper>>>, result: Arc<Mutex<Option<rustyline::Result<String>>>>, } Loading Loading @@ -44,15 +87,22 @@ impl Future for AsyncReadline { /// Wrapper of rustyline editor that supports async readline(). pub struct AsyncEditor { rl: Arc<Mutex<Editor<()>>>, rl: Arc<Mutex<Editor<BtHelper>>>, } impl AsyncEditor { /// Creates new async rustyline editor. pub fn new() -> AsyncEditor { let builder = Config::builder().auto_add_history(true).history_ignore_dups(true); /// /// * `commands` - List of commands for autocomplete. pub fn new(commands: Vec<String>) -> AsyncEditor { let builder = Config::builder() .auto_add_history(true) .history_ignore_dups(true) .completion_type(CompletionType::List); let config = builder.build(); let rl = rustyline::Editor::<()>::with_config(config); let mut rl = rustyline::Editor::with_config(config); let helper = BtHelper { commands }; rl.set_helper(Some(helper)); AsyncEditor { rl: Arc::new(Mutex::new(rl)) } } Loading
system/gd/rust/linux/client/src/main.rs +19 −2 Original line number Diff line number Diff line Loading @@ -98,9 +98,26 @@ fn main() -> Result<(), Box<dyn std::error::Error>> { objpath: String::from("/org/chromium/bluetooth/client/bluetooth_manager_callback"), })); let mut handler = CommandHandler::new(api.bluetooth_manager.clone(), api.bluetooth.clone()); // TODO(b/193719802): Refactor this into a dedicated "Help" data structure. let commands = vec![ String::from("help"), String::from("enable"), String::from("disable"), String::from("get_address"), String::from("start_discovery"), String::from("cancel_discovery"), String::from("create_bond"), ]; let mut handler = CommandHandler::new( api.bluetooth_manager.clone(), api.bluetooth.clone(), commands.clone(), ); let mut handle_cmd = move |cmd: String| match cmd.split(' ').collect::<Vec<&str>>()[0] { "help" => handler.cmd_help(), "enable" => handler.cmd_enable(cmd), "disable" => handler.cmd_disable(cmd), "get_address" => handler.cmd_get_address(cmd), Loading @@ -115,7 +132,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> { _ => print_info!("Command \"{}\" not recognized", cmd), }; let editor = AsyncEditor::new(); let editor = AsyncEditor::new(commands.clone()); loop { let result = editor.readline().await; Loading