Fix clippy lints (#399)

* cargo fmt

* fix: remove redundant `use libc` import (clippy::single_component_path_imports)

* fix: use `.first()` instead of `.get(0)` (clippy::get_first)

* fix: use `.copied()` instead of `.map(|s| *s)` (clippy::map_clone)

* fix: allow too_many_arguments on ensure_daemon (clippy::too_many_arguments)

* fix: use `then_some` instead of `then` with closure (clippy::unnecessary_lazy_evaluations)

* fix: use pattern match instead of redundant guard (clippy::redundant_guards)

* fix: use pattern match instead of redundant guard in commands.rs (clippy::redundant_guards)

* fix: use `contains()` instead of `iter().any()` for simple equality (clippy::manual_contains)

* Add changeset
This commit is contained in:
Mathias Lafeldt
2026-02-13 10:44:35 -06:00
committed by GitHub
parent 604c0b9632
commit 323b6cdd9d
5 changed files with 107 additions and 81 deletions
+5
View File
@@ -0,0 +1,5 @@
---
"agent-browser": patch
---
Fix all Clippy lint warnings in the Rust CLI: remove redundant import, use `.first()` instead of `.get(0)`, use `.copied()` instead of `.map(|s| *s)`, use `.contains()` instead of `.iter().any()`, use `then_some` instead of lazy `then`, and simplify redundant match guards.
+72 -62
View File
@@ -81,7 +81,7 @@ pub fn parse_command(args: &[String], flags: &Flags) -> Result<Value, ParseError
match cmd {
// === Navigation ===
"open" | "goto" | "navigate" => {
let url = rest.get(0).ok_or_else(|| ParseError::MissingArguments {
let url = rest.first().ok_or_else(|| ParseError::MissingArguments {
context: cmd.to_string(),
usage: "open <url>",
})?;
@@ -117,63 +117,63 @@ pub fn parse_command(args: &[String], flags: &Flags) -> Result<Value, ParseError
// === Core Actions ===
"click" => {
let sel = rest.get(0).ok_or_else(|| ParseError::MissingArguments {
let sel = rest.first().ok_or_else(|| ParseError::MissingArguments {
context: "click".to_string(),
usage: "click <selector>",
})?;
Ok(json!({ "id": id, "action": "click", "selector": sel }))
}
"dblclick" => {
let sel = rest.get(0).ok_or_else(|| ParseError::MissingArguments {
let sel = rest.first().ok_or_else(|| ParseError::MissingArguments {
context: "dblclick".to_string(),
usage: "dblclick <selector>",
})?;
Ok(json!({ "id": id, "action": "dblclick", "selector": sel }))
}
"fill" => {
let sel = rest.get(0).ok_or_else(|| ParseError::MissingArguments {
let sel = rest.first().ok_or_else(|| ParseError::MissingArguments {
context: "fill".to_string(),
usage: "fill <selector> <text>",
})?;
Ok(json!({ "id": id, "action": "fill", "selector": sel, "value": rest[1..].join(" ") }))
}
"type" => {
let sel = rest.get(0).ok_or_else(|| ParseError::MissingArguments {
let sel = rest.first().ok_or_else(|| ParseError::MissingArguments {
context: "type".to_string(),
usage: "type <selector> <text>",
})?;
Ok(json!({ "id": id, "action": "type", "selector": sel, "text": rest[1..].join(" ") }))
}
"hover" => {
let sel = rest.get(0).ok_or_else(|| ParseError::MissingArguments {
let sel = rest.first().ok_or_else(|| ParseError::MissingArguments {
context: "hover".to_string(),
usage: "hover <selector>",
})?;
Ok(json!({ "id": id, "action": "hover", "selector": sel }))
}
"focus" => {
let sel = rest.get(0).ok_or_else(|| ParseError::MissingArguments {
let sel = rest.first().ok_or_else(|| ParseError::MissingArguments {
context: "focus".to_string(),
usage: "focus <selector>",
})?;
Ok(json!({ "id": id, "action": "focus", "selector": sel }))
}
"check" => {
let sel = rest.get(0).ok_or_else(|| ParseError::MissingArguments {
let sel = rest.first().ok_or_else(|| ParseError::MissingArguments {
context: "check".to_string(),
usage: "check <selector>",
})?;
Ok(json!({ "id": id, "action": "check", "selector": sel }))
}
"uncheck" => {
let sel = rest.get(0).ok_or_else(|| ParseError::MissingArguments {
let sel = rest.first().ok_or_else(|| ParseError::MissingArguments {
context: "uncheck".to_string(),
usage: "uncheck <selector>",
})?;
Ok(json!({ "id": id, "action": "uncheck", "selector": sel }))
}
"select" => {
let sel = rest.get(0).ok_or_else(|| ParseError::MissingArguments {
let sel = rest.first().ok_or_else(|| ParseError::MissingArguments {
context: "select".to_string(),
usage: "select <selector> <value...>",
})?;
@@ -189,7 +189,7 @@ pub fn parse_command(args: &[String], flags: &Flags) -> Result<Value, ParseError
}
}
"drag" => {
let src = rest.get(0).ok_or_else(|| ParseError::MissingArguments {
let src = rest.first().ok_or_else(|| ParseError::MissingArguments {
context: "drag".to_string(),
usage: "drag <source> <target>",
})?;
@@ -200,14 +200,14 @@ pub fn parse_command(args: &[String], flags: &Flags) -> Result<Value, ParseError
Ok(json!({ "id": id, "action": "drag", "source": src, "target": tgt }))
}
"upload" => {
let sel = rest.get(0).ok_or_else(|| ParseError::MissingArguments {
let sel = rest.first().ok_or_else(|| ParseError::MissingArguments {
context: "upload".to_string(),
usage: "upload <selector> <files...>",
})?;
Ok(json!({ "id": id, "action": "upload", "selector": sel, "files": &rest[1..] }))
}
"download" => {
let sel = rest.get(0).ok_or_else(|| ParseError::MissingArguments {
let sel = rest.first().ok_or_else(|| ParseError::MissingArguments {
context: "download".to_string(),
usage: "download <selector> <path>",
})?;
@@ -220,21 +220,21 @@ pub fn parse_command(args: &[String], flags: &Flags) -> Result<Value, ParseError
// === Keyboard ===
"press" | "key" => {
let key = rest.get(0).ok_or_else(|| ParseError::MissingArguments {
let key = rest.first().ok_or_else(|| ParseError::MissingArguments {
context: "press".to_string(),
usage: "press <key>",
})?;
Ok(json!({ "id": id, "action": "press", "key": key }))
}
"keydown" => {
let key = rest.get(0).ok_or_else(|| ParseError::MissingArguments {
let key = rest.first().ok_or_else(|| ParseError::MissingArguments {
context: "keydown".to_string(),
usage: "keydown <key>",
})?;
Ok(json!({ "id": id, "action": "keydown", "key": key }))
}
"keyup" => {
let key = rest.get(0).ok_or_else(|| ParseError::MissingArguments {
let key = rest.first().ok_or_else(|| ParseError::MissingArguments {
context: "keyup".to_string(),
usage: "keyup <key>",
})?;
@@ -243,7 +243,7 @@ pub fn parse_command(args: &[String], flags: &Flags) -> Result<Value, ParseError
// === Scroll ===
"scroll" => {
let dir = rest.get(0).unwrap_or(&"down");
let dir = rest.first().unwrap_or(&"down");
let amount = rest
.get(1)
.and_then(|s| s.parse::<i32>().ok())
@@ -251,7 +251,7 @@ pub fn parse_command(args: &[String], flags: &Flags) -> Result<Value, ParseError
Ok(json!({ "id": id, "action": "scroll", "direction": dir, "amount": amount }))
}
"scrollintoview" | "scrollinto" => {
let sel = rest.get(0).ok_or_else(|| ParseError::MissingArguments {
let sel = rest.first().ok_or_else(|| ParseError::MissingArguments {
context: "scrollintoview".to_string(),
usage: "scrollintoview <selector>",
})?;
@@ -332,7 +332,7 @@ pub fn parse_command(args: &[String], flags: &Flags) -> Result<Value, ParseError
}
// Default: selector or timeout
if let Some(arg) = rest.get(0) {
if let Some(arg) = rest.first() {
if arg.parse::<u64>().is_ok() {
Ok(
json!({ "id": id, "action": "wait", "timeout": arg.parse::<u64>().unwrap() }),
@@ -353,7 +353,7 @@ pub fn parse_command(args: &[String], flags: &Flags) -> Result<Value, ParseError
// screenshot [selector] [path]
// selector: @ref or CSS selector
// path: file path (contains / or . or ends with known extension)
let (selector, path) = match (rest.get(0), rest.get(1)) {
let (selector, path) = match (rest.first(), rest.get(1)) {
(Some(first), Some(second)) => {
// Two args: first is selector, second is path
(Some(*first), Some(*second))
@@ -383,7 +383,7 @@ pub fn parse_command(args: &[String], flags: &Flags) -> Result<Value, ParseError
)
}
"pdf" => {
let path = rest.get(0).ok_or_else(|| ParseError::MissingArguments {
let path = rest.first().ok_or_else(|| ParseError::MissingArguments {
context: "pdf".to_string(),
usage: "pdf <path>",
})?;
@@ -442,17 +442,22 @@ pub fn parse_command(args: &[String], flags: &Flags) -> Result<Value, ParseError
let script = if is_stdin {
// Read script from stdin
let stdin = io::stdin();
let lines: Vec<String> = stdin.lock().lines()
let lines: Vec<String> = stdin
.lock()
.lines()
.map(|l| l.unwrap_or_default())
.collect();
lines.join("\n")
} else {
let raw_script = script_parts.join(" ");
if is_base64 {
let decoded = STANDARD.decode(&raw_script).map_err(|_| ParseError::InvalidValue {
message: "Invalid base64 encoding".to_string(),
usage: "eval -b <base64-encoded-script>",
})?;
let decoded =
STANDARD
.decode(&raw_script)
.map_err(|_| ParseError::InvalidValue {
message: "Invalid base64 encoding".to_string(),
usage: "eval -b <base64-encoded-script>",
})?;
String::from_utf8(decoded).map_err(|_| ParseError::InvalidValue {
message: "Base64 decoded to invalid UTF-8".to_string(),
usage: "eval -b <base64-encoded-script>",
@@ -483,7 +488,7 @@ pub fn parse_command(args: &[String], flags: &Flags) -> Result<Value, ParseError
} else {
// It's a port number - validate and use cdpPort field
let port: u16 = match endpoint.parse::<u32>() {
Ok(p) if p == 0 => {
Ok(0) => {
return Err(ParseError::InvalidValue {
message: "Invalid port: port must be greater than 0".to_string(),
usage: "connect <port|url>",
@@ -536,7 +541,7 @@ pub fn parse_command(args: &[String], flags: &Flags) -> Result<Value, ParseError
// === Cookies ===
"cookies" => {
let op = rest.get(0).unwrap_or(&"get");
let op = rest.first().unwrap_or(&"get");
match *op {
"set" => {
let name = rest.get(1).ok_or_else(|| ParseError::MissingArguments {
@@ -650,7 +655,7 @@ pub fn parse_command(args: &[String], flags: &Flags) -> Result<Value, ParseError
}
// === Tabs ===
"tab" => match rest.get(0).map(|s| *s) {
"tab" => match rest.first().copied() {
Some("new") => {
let mut cmd = json!({ "id": id, "action": "tab_new" });
if let Some(url) = rest.get(1) {
@@ -675,7 +680,7 @@ pub fn parse_command(args: &[String], flags: &Flags) -> Result<Value, ParseError
// === Window ===
"window" => {
const VALID: &[&str] = &["new"];
match rest.get(0).map(|s| *s) {
match rest.first().copied() {
Some("new") => Ok(json!({ "id": id, "action": "window_new" })),
Some(sub) => Err(ParseError::UnknownSubcommand {
subcommand: sub.to_string(),
@@ -690,10 +695,10 @@ pub fn parse_command(args: &[String], flags: &Flags) -> Result<Value, ParseError
// === Frame ===
"frame" => {
if rest.get(0).map(|s| *s) == Some("main") {
if rest.first().copied() == Some("main") {
Ok(json!({ "id": id, "action": "mainframe" }))
} else {
let sel = rest.get(0).ok_or_else(|| ParseError::MissingArguments {
let sel = rest.first().ok_or_else(|| ParseError::MissingArguments {
context: "frame".to_string(),
usage: "frame <selector|main>",
})?;
@@ -704,7 +709,7 @@ pub fn parse_command(args: &[String], flags: &Flags) -> Result<Value, ParseError
// === Dialog ===
"dialog" => {
const VALID: &[&str] = &["accept", "dismiss"];
match rest.get(0).map(|s| *s) {
match rest.first().copied() {
Some("accept") => {
let mut cmd = json!({ "id": id, "action": "dialog", "response": "accept" });
if let Some(prompt_text) = rest.get(1) {
@@ -726,7 +731,7 @@ pub fn parse_command(args: &[String], flags: &Flags) -> Result<Value, ParseError
// === Debug ===
"trace" => {
const VALID: &[&str] = &["start", "stop"];
match rest.get(0).map(|s| *s) {
match rest.first().copied() {
Some("start") => Ok(json!({ "id": id, "action": "trace_start" })),
Some("stop") => {
let path = rest.get(1).ok_or_else(|| ParseError::MissingArguments {
@@ -749,7 +754,7 @@ pub fn parse_command(args: &[String], flags: &Flags) -> Result<Value, ParseError
// === Recording (Playwright native video recording) ===
"record" => {
const VALID: &[&str] = &["start", "stop", "restart"];
match rest.get(0).map(|s| *s) {
match rest.first().copied() {
Some("start") => {
let path = rest.get(1).ok_or_else(|| ParseError::MissingArguments {
context: "record start".to_string(),
@@ -800,15 +805,15 @@ pub fn parse_command(args: &[String], flags: &Flags) -> Result<Value, ParseError
}
}
"console" => {
let clear = rest.iter().any(|&s| s == "--clear");
let clear = rest.contains(&"--clear");
Ok(json!({ "id": id, "action": "console", "clear": clear }))
}
"errors" => {
let clear = rest.iter().any(|&s| s == "--clear");
let clear = rest.contains(&"--clear");
Ok(json!({ "id": id, "action": "errors", "clear": clear }))
}
"highlight" => {
let sel = rest.get(0).ok_or_else(|| ParseError::MissingArguments {
let sel = rest.first().ok_or_else(|| ParseError::MissingArguments {
context: "highlight".to_string(),
usage: "highlight <selector>",
})?;
@@ -818,7 +823,7 @@ pub fn parse_command(args: &[String], flags: &Flags) -> Result<Value, ParseError
// === State ===
"state" => {
const VALID: &[&str] = &["save", "load"];
match rest.get(0).map(|s| *s) {
match rest.first().copied() {
Some("save") => {
let path = rest.get(1).ok_or_else(|| ParseError::MissingArguments {
context: "state save".to_string(),
@@ -847,14 +852,14 @@ pub fn parse_command(args: &[String], flags: &Flags) -> Result<Value, ParseError
// === iOS-specific commands ===
"tap" => {
// Alias for click (semantic clarity for touch interfaces)
let sel = rest.get(0).ok_or_else(|| ParseError::MissingArguments {
let sel = rest.first().ok_or_else(|| ParseError::MissingArguments {
context: "tap".to_string(),
usage: "tap <selector>",
})?;
Ok(json!({ "id": id, "action": "tap", "selector": sel }))
}
"swipe" => {
let direction = rest.get(0).ok_or_else(|| ParseError::MissingArguments {
let direction = rest.first().ok_or_else(|| ParseError::MissingArguments {
context: "swipe".to_string(),
usage: "swipe <up|down|left|right> [distance]",
})?;
@@ -868,13 +873,15 @@ pub fn parse_command(args: &[String], flags: &Flags) -> Result<Value, ParseError
let mut cmd = json!({ "id": id, "action": "swipe", "direction": direction });
if let Some(distance) = rest.get(1) {
if let Ok(d) = distance.parse::<u32>() {
cmd.as_object_mut().unwrap().insert("distance".to_string(), json!(d));
cmd.as_object_mut()
.unwrap()
.insert("distance".to_string(), json!(d));
}
}
Ok(cmd)
}
"device" => {
match rest.get(0).map(|s| *s) {
match rest.first().copied() {
Some("list") | None => {
// List available iOS simulators
Ok(json!({ "id": id, "action": "device_list" }))
@@ -897,7 +904,7 @@ fn parse_get(rest: &[&str], id: &str) -> Result<Value, ParseError> {
"text", "html", "value", "attr", "url", "title", "count", "box", "styles",
];
match rest.get(0).map(|s| *s) {
match rest.first().copied() {
Some("text") => {
let sel = rest.get(1).ok_or_else(|| ParseError::MissingArguments {
context: "get text".to_string(),
@@ -967,7 +974,7 @@ fn parse_get(rest: &[&str], id: &str) -> Result<Value, ParseError> {
fn parse_is(rest: &[&str], id: &str) -> Result<Value, ParseError> {
const VALID: &[&str] = &["visible", "enabled", "checked"];
match rest.get(0).map(|s| *s) {
match rest.first().copied() {
Some("visible") => {
let sel = rest.get(1).ok_or_else(|| ParseError::MissingArguments {
context: "is visible".to_string(),
@@ -1014,14 +1021,14 @@ fn parse_find(rest: &[&str], id: &str) -> Result<Value, ParseError> {
"nth",
];
let locator = rest.get(0).ok_or_else(|| ParseError::MissingArguments {
let locator = rest.first().ok_or_else(|| ParseError::MissingArguments {
context: "find".to_string(),
usage: "find <locator> <value> [action] [text]",
})?;
let name_idx = rest.iter().position(|&s| s == "--name");
let name = name_idx.and_then(|i| rest.get(i + 1).map(|s| *s));
let exact = rest.iter().any(|&s| s == "--exact");
let name = name_idx.and_then(|i| rest.get(i + 1).copied());
let exact = rest.contains(&"--exact");
match *locator {
"role" | "text" | "label" | "placeholder" | "alt" | "title" | "testid" | "first"
@@ -1140,7 +1147,7 @@ fn parse_find(rest: &[&str], id: &str) -> Result<Value, ParseError> {
fn parse_mouse(rest: &[&str], id: &str) -> Result<Value, ParseError> {
const VALID: &[&str] = &["move", "down", "up", "wheel"];
match rest.get(0).map(|s| *s) {
match rest.first().copied() {
Some("move") => {
let x_str = rest.get(1).ok_or_else(|| ParseError::MissingArguments {
context: "mouse move".to_string(),
@@ -1202,7 +1209,7 @@ fn parse_set(rest: &[&str], id: &str) -> Result<Value, ParseError> {
"media",
];
match rest.get(0).map(|s| *s) {
match rest.first().copied() {
Some("viewport") => {
let w_str = rest.get(1).ok_or_else(|| ParseError::MissingArguments {
context: "set viewport".to_string(),
@@ -1288,14 +1295,14 @@ fn parse_set(rest: &[&str], id: &str) -> Result<Value, ParseError> {
Ok(json!({ "id": id, "action": "credentials", "username": user, "password": pass }))
}
Some("media") => {
let color = if rest.iter().any(|&s| s == "dark") {
let color = if rest.contains(&"dark") {
"dark"
} else if rest.iter().any(|&s| s == "light") {
} else if rest.contains(&"light") {
"light"
} else {
"no-preference"
};
let reduced = if rest.iter().any(|&s| s == "reduced-motion") {
let reduced = if rest.contains(&"reduced-motion") {
"reduce"
} else {
"no-preference"
@@ -1318,15 +1325,15 @@ fn parse_set(rest: &[&str], id: &str) -> Result<Value, ParseError> {
fn parse_network(rest: &[&str], id: &str) -> Result<Value, ParseError> {
const VALID: &[&str] = &["route", "unroute", "requests"];
match rest.get(0).map(|s| *s) {
match rest.first().copied() {
Some("route") => {
let url = rest.get(1).ok_or_else(|| ParseError::MissingArguments {
context: "network route".to_string(),
usage: "network route <url> [--abort|--body <json>]",
})?;
let abort = rest.iter().any(|&s| s == "--abort");
let abort = rest.contains(&"--abort");
let body_idx = rest.iter().position(|&s| s == "--body");
let body = body_idx.and_then(|i| rest.get(i + 1).map(|s| *s));
let body = body_idx.and_then(|i| rest.get(i + 1).copied());
Ok(json!({ "id": id, "action": "route", "url": url, "abort": abort, "body": body }))
}
Some("unroute") => {
@@ -1337,9 +1344,9 @@ fn parse_network(rest: &[&str], id: &str) -> Result<Value, ParseError> {
Ok(cmd)
}
Some("requests") => {
let clear = rest.iter().any(|&s| s == "--clear");
let clear = rest.contains(&"--clear");
let filter_idx = rest.iter().position(|&s| s == "--filter");
let filter = filter_idx.and_then(|i| rest.get(i + 1).map(|s| *s));
let filter = filter_idx.and_then(|i| rest.get(i + 1).copied());
let mut cmd = json!({ "id": id, "action": "requests", "clear": clear });
if let Some(f) = filter {
cmd["filter"] = json!(f);
@@ -1360,9 +1367,9 @@ fn parse_network(rest: &[&str], id: &str) -> Result<Value, ParseError> {
fn parse_storage(rest: &[&str], id: &str) -> Result<Value, ParseError> {
const VALID: &[&str] = &["local", "session"];
match rest.get(0).map(|s| *s) {
match rest.first().copied() {
Some("local") | Some("session") => {
let storage_type = rest.get(0).unwrap();
let storage_type = rest.first().unwrap();
let op = rest.get(1).unwrap_or(&"get");
let key = rest.get(2);
let value = rest.get(3);
@@ -2159,8 +2166,11 @@ mod tests {
#[test]
fn test_eval_base64_long_flag() {
// "document.title" in base64
let cmd =
parse_command(&args("eval --base64 ZG9jdW1lbnQudGl0bGU="), &default_flags()).unwrap();
let cmd = parse_command(
&args("eval --base64 ZG9jdW1lbnQudGl0bGU="),
&default_flags(),
)
.unwrap();
assert_eq!(cmd["action"], "evaluate");
assert_eq!(cmd["script"], "document.title");
}
+1
View File
@@ -203,6 +203,7 @@ pub struct DaemonResult {
pub already_running: bool,
}
#[allow(clippy::too_many_arguments)]
pub fn ensure_daemon(
session: &str,
headed: bool,
+7 -14
View File
@@ -10,9 +10,6 @@ use std::env;
use std::fs;
use std::process::exit;
#[cfg(unix)]
use libc;
#[cfg(windows)]
use windows_sys::Win32::Foundation::CloseHandle;
#[cfg(windows)]
@@ -141,7 +138,7 @@ fn main() {
let has_version = args.iter().any(|a| a == "--version" || a == "-V");
if has_help {
if let Some(cmd) = clean.get(0) {
if let Some(cmd) = clean.first() {
if print_command_help(cmd) {
return;
}
@@ -161,14 +158,14 @@ fn main() {
}
// Handle install separately
if clean.get(0).map(|s| s.as_str()) == Some("install") {
if clean.first().map(|s| s.as_str()) == Some("install") {
let with_deps = args.iter().any(|a| a == "--with-deps" || a == "-d");
run_install(with_deps);
return;
}
// Handle session separately (doesn't need daemon)
if clean.get(0).map(|s| s.as_str()) == Some("session") {
if clean.first().map(|s| s.as_str()) == Some("session") {
run_session(&clean, &flags.session, flags.json);
return;
}
@@ -247,11 +244,7 @@ fn main() {
} else {
None
},
if flags.cli_args {
Some("--args")
} else {
None
},
if flags.cli_args { Some("--args") } else { None },
if flags.cli_user_agent {
Some("--user-agent")
} else {
@@ -267,8 +260,8 @@ fn main() {
} else {
None
},
flags.ignore_https_errors.then(|| "--ignore-https-errors"),
flags.cli_allow_file_access.then(|| "--allow-file-access"),
flags.ignore_https_errors.then_some("--ignore-https-errors"),
flags.cli_allow_file_access.then_some("--allow-file-access"),
]
.into_iter()
.flatten()
@@ -372,7 +365,7 @@ fn main() {
} else {
// It's a port number - validate and use cdpPort field
let cdp_port: u16 = match cdp_value.parse::<u32>() {
Ok(p) if p == 0 => {
Ok(0) => {
let msg = "Invalid CDP port: port must be greater than 0".to_string();
if flags.json {
println!(r#"{{"success":false,"error":"{}"}}"#, msg);
+22 -5
View File
@@ -88,17 +88,28 @@ pub fn print_response(resp: &Response, json_mode: bool, action: Option<&str>) {
// Separate real devices from simulators
let real_devices: Vec<_> = devices
.iter()
.filter(|d| d.get("isRealDevice").and_then(|v| v.as_bool()).unwrap_or(false))
.filter(|d| {
d.get("isRealDevice")
.and_then(|v| v.as_bool())
.unwrap_or(false)
})
.collect();
let simulators: Vec<_> = devices
.iter()
.filter(|d| !d.get("isRealDevice").and_then(|v| v.as_bool()).unwrap_or(false))
.filter(|d| {
!d.get("isRealDevice")
.and_then(|v| v.as_bool())
.unwrap_or(false)
})
.collect();
if !real_devices.is_empty() {
println!("Connected Devices:\n");
for device in real_devices.iter() {
let name = device.get("name").and_then(|v| v.as_str()).unwrap_or("Unknown");
let name = device
.get("name")
.and_then(|v| v.as_str())
.unwrap_or("Unknown");
let runtime = device.get("runtime").and_then(|v| v.as_str()).unwrap_or("");
let udid = device.get("udid").and_then(|v| v.as_str()).unwrap_or("");
println!(" {} {} ({})", color::green(""), name, runtime);
@@ -110,9 +121,15 @@ pub fn print_response(resp: &Response, json_mode: bool, action: Option<&str>) {
if !simulators.is_empty() {
println!("Simulators:\n");
for device in simulators.iter() {
let name = device.get("name").and_then(|v| v.as_str()).unwrap_or("Unknown");
let name = device
.get("name")
.and_then(|v| v.as_str())
.unwrap_or("Unknown");
let runtime = device.get("runtime").and_then(|v| v.as_str()).unwrap_or("");
let state = device.get("state").and_then(|v| v.as_str()).unwrap_or("Unknown");
let state = device
.get("state")
.and_then(|v| v.as_str())
.unwrap_or("Unknown");
let udid = device.get("udid").and_then(|v| v.as_str()).unwrap_or("");
let state_indicator = if state == "Booted" {
color::green("")