From c72b1dbd35cc33a79b077b40f748e7dd4d3c5aa6 Mon Sep 17 00:00:00 2001 From: 0xLogN Date: Wed, 26 Jul 2023 10:04:54 -0400 Subject: [PATCH 1/4] add discord autocomplete to debug commands --- src/commands/debug.rs | 84 +++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 82 insertions(+), 2 deletions(-) diff --git a/src/commands/debug.rs b/src/commands/debug.rs index 89226f7..7d6e0a6 100644 --- a/src/commands/debug.rs +++ b/src/commands/debug.rs @@ -35,11 +35,49 @@ async fn scan( Ok(()) } +async fn parse_one_autocomplete(_ctx: Context<'_>, query: &str) -> Vec> { + match drql::parser::parse_drql(query) { + // When we encounter an error, we want to split it across multiple lines because Discord only + // gives us 100 characters for the 'name' field in AutocompleteChoice. We split as follows: + // 1. We always split on newlines within the error message. + // 2. For a single line of the error message, we split on whitespace. + + // TODO: Move this to a function? It's sorta repetitive + Err(e) => format!("Encountered an error while parsing:\n{e:#}") + .split('\n') + .flat_map(|part| { + crate::util::wrap_string_vec( + &part + .split_whitespace() + .map(std::string::ToString::to_string) + .collect::>(), + " ", + 100, + ) + .unwrap() + }) + .map(|option| AutocompleteChoice { + name: option, + value: query.to_string(), + }) + .collect::>(), + Ok(_) => { + vec![AutocompleteChoice { + name: "Parsed successfully. Send command to view AST.".to_string(), + value: query.to_string(), + }] + } + } +} + /// Parse a single DRQL query #[poise::command(slash_command)] async fn parse_one( ctx: Context<'_>, - #[description = "The DRQL query to parse (DO NOT include @{})"] query: String, + + #[description = "The DRQL query to parse (DO NOT include @{})"] + #[autocomplete = "parse_one_autocomplete"] + query: String, ) -> Result<(), anyhow::Error> { ctx.say(match drql::parser::parse_drql(query.as_str()) { Err(e) => format!("Encountered an error while parsing:\n\n```{e:?}```"), @@ -50,11 +88,53 @@ async fn parse_one( Ok(()) } +async fn reduce_autocomplete(_ctx: Context<'_>, query: &str) -> Vec> { + match drql::scanner::scan(query) + .enumerate() + .map(|(n, chunk)| { + drql::parser::parse_drql(chunk).context(format!("Error parsing chunk {n}")) + }) + .collect::, _>>() + { + // The same whitespace printing is done here. First split on newlines, then split on spaces. + Err(e) => format!("Encountered an error while parsing:\n{e:#}") + .split('\n') + .flat_map(|part| { + crate::util::wrap_string_vec( + &part + .split_whitespace() + .map(std::string::ToString::to_string) + .collect::>(), + " ", + 100, + ) + .unwrap() + }) + .map(|option| AutocompleteChoice { + name: option, + value: query.to_string(), + }) + .collect::>(), + + Ok(exprs) if exprs.is_empty() => vec![AutocompleteChoice { + name: "No chunks found.".to_string(), + value: query.to_string(), + }], + Ok(_) => vec![AutocompleteChoice { + name: "Parsed successfully. Send command to view reduced AST.".to_string(), + value: query.to_string(), + }], + } +} + /// Scan the input, parse each query, and finally reduce into one tree #[poise::command(slash_command)] async fn reduce( ctx: Context<'_>, - #[description = "The message to scan"] msg: String, + + #[description = "The message to scan"] + #[autocomplete = "reduce_autocomplete"] + msg: String, ) -> Result<(), anyhow::Error> { ctx.say( drql::scanner::scan(msg.as_str()) From a9c96842b91f5905eb7bc595b3de905c883c298e Mon Sep 17 00:00:00 2001 From: 0xLogN Date: Wed, 26 Jul 2023 10:11:19 -0400 Subject: [PATCH 2/4] add logging --- src/commands/debug.rs | 106 ++++++++++++++++++++++++------------------ 1 file changed, 62 insertions(+), 44 deletions(-) diff --git a/src/commands/debug.rs b/src/commands/debug.rs index 7d6e0a6..d5856b8 100644 --- a/src/commands/debug.rs +++ b/src/commands/debug.rs @@ -1,5 +1,6 @@ use anyhow::{bail, Context as _}; use poise::AutocompleteChoice; +use tracing::{debug, instrument}; use super::super::{drql, Context}; @@ -35,6 +36,7 @@ async fn scan( Ok(()) } +#[instrument(skip_all, fields(query = query))] async fn parse_one_autocomplete(_ctx: Context<'_>, query: &str) -> Vec> { match drql::parser::parse_drql(query) { // When we encounter an error, we want to split it across multiple lines because Discord only @@ -43,25 +45,29 @@ async fn parse_one_autocomplete(_ctx: Context<'_>, query: &str) -> Vec format!("Encountered an error while parsing:\n{e:#}") - .split('\n') - .flat_map(|part| { - crate::util::wrap_string_vec( - &part - .split_whitespace() - .map(std::string::ToString::to_string) - .collect::>(), - " ", - 100, - ) - .unwrap() - }) - .map(|option| AutocompleteChoice { - name: option, - value: query.to_string(), - }) - .collect::>(), + Err(e) => { + debug!("Returning parse error response to autocomplete: {e:#}"); + format!("Encountered an error while parsing:\n{e:#}") + .split('\n') + .flat_map(|part| { + crate::util::wrap_string_vec( + &part + .split_whitespace() + .map(std::string::ToString::to_string) + .collect::>(), + " ", + 100, + ) + .unwrap() + }) + .map(|option| AutocompleteChoice { + name: option, + value: query.to_string(), + }) + .collect::>() + } Ok(_) => { + debug!("Returning \"Parsed successfully\" response to autocomplete"); vec![AutocompleteChoice { name: "Parsed successfully. Send command to view AST.".to_string(), value: query.to_string(), @@ -71,6 +77,7 @@ async fn parse_one_autocomplete(_ctx: Context<'_>, query: &str) -> Vec, @@ -88,6 +95,7 @@ async fn parse_one( Ok(()) } +#[instrument(skip_all, fields(query = query))] async fn reduce_autocomplete(_ctx: Context<'_>, query: &str) -> Vec> { match drql::scanner::scan(query) .enumerate() @@ -97,37 +105,47 @@ async fn reduce_autocomplete(_ctx: Context<'_>, query: &str) -> Vec, _>>() { // The same whitespace printing is done here. First split on newlines, then split on spaces. - Err(e) => format!("Encountered an error while parsing:\n{e:#}") - .split('\n') - .flat_map(|part| { - crate::util::wrap_string_vec( - &part - .split_whitespace() - .map(std::string::ToString::to_string) - .collect::>(), - " ", - 100, - ) - .unwrap() - }) - .map(|option| AutocompleteChoice { - name: option, - value: query.to_string(), - }) - .collect::>(), + Err(e) => { + debug!("Returning parse error response to autocomplete: {e:#}"); + format!("Encountered an error while parsing:\n{e:#}") + .split('\n') + .flat_map(|part| { + crate::util::wrap_string_vec( + &part + .split_whitespace() + .map(std::string::ToString::to_string) + .collect::>(), + " ", + 100, + ) + .unwrap() + }) + .map(|option| AutocompleteChoice { + name: option, + value: query.to_string(), + }) + .collect::>() + } - Ok(exprs) if exprs.is_empty() => vec![AutocompleteChoice { - name: "No chunks found.".to_string(), - value: query.to_string(), - }], - Ok(_) => vec![AutocompleteChoice { - name: "Parsed successfully. Send command to view reduced AST.".to_string(), - value: query.to_string(), - }], + Ok(exprs) if exprs.is_empty() => { + debug!("Returning \"No chunks found\" response to autocomplete"); + vec![AutocompleteChoice { + name: "No chunks found.".to_string(), + value: query.to_string(), + }] + } + Ok(_) => { + debug!("Returning \"Parsed successfully\" response to autocomplete"); + vec![AutocompleteChoice { + name: "Parsed successfully. Send command to view reduced AST.".to_string(), + value: query.to_string(), + }] + } } } /// Scan the input, parse each query, and finally reduce into one tree +#[instrument(skip_all, fields(msg = msg))] #[poise::command(slash_command)] async fn reduce( ctx: Context<'_>, From 259c526853bd48b78605721866c70636d246b08a Mon Sep 17 00:00:00 2001 From: 0xLogN Date: Wed, 26 Jul 2023 10:24:05 -0400 Subject: [PATCH 3/4] refactor to if..let --- src/commands/debug.rs | 63 +++++++++++++++++++++---------------------- 1 file changed, 30 insertions(+), 33 deletions(-) diff --git a/src/commands/debug.rs b/src/commands/debug.rs index 250330d..0cb5437 100644 --- a/src/commands/debug.rs +++ b/src/commands/debug.rs @@ -38,41 +38,38 @@ async fn scan( #[instrument(skip_all, fields(query = query))] async fn parse_one_autocomplete(_ctx: Context<'_>, query: &str) -> Vec> { - match drql::parser::parse_drql(query) { - // When we encounter an error, we want to split it across multiple lines because Discord only - // gives us 100 characters for the 'name' field in AutocompleteChoice. We split as follows: - // 1. We always split on newlines within the error message. - // 2. For a single line of the error message, we split on whitespace. + // When we encounter an error, we want to split it across multiple lines because Discord only + // gives us 100 characters for the 'name' field in AutocompleteChoice. We split as follows: + // 1. We always split on newlines within the error message. + // 2. For a single line of the error message, we split on whitespace. - // TODO: Move this to a function? It's sorta repetitive - Err(e) => { - debug!("Returning parse error response to autocomplete: {e:#}"); - format!("Encountered an error while parsing:\n{e:#}") - .split('\n') - .flat_map(|part| { - crate::util::wrap_string_vec( - &part - .split_whitespace() - .map(std::string::ToString::to_string) - .collect::>(), - " ", - 100, - ) - .unwrap() - }) - .map(|option| AutocompleteChoice { - name: option, - value: query.to_string(), - }) - .collect::>() - } - Ok(_) => { - debug!("Returning \"Parsed successfully\" response to autocomplete"); - vec![AutocompleteChoice { - name: "Parsed successfully. Send command to view AST.".to_string(), + // TODO: Move this to a function? It's sorta repetitive for both autocomplete functions + if let Err(e) = drql::parser::parse_drql(query) { + debug!("Returning parse error response to autocomplete: {e:#}"); + format!("Encountered an error while parsing:\n{e:#}") + .split('\n') + .flat_map(|part| { + crate::util::wrap_string_vec( + &part + .split_whitespace() + .map(std::string::ToString::to_string) + .collect::>(), + " ", + 100, + ) + .unwrap() + }) + .map(|option| AutocompleteChoice { + name: option, value: query.to_string(), - }] - } + }) + .collect::>() + } else { + debug!("Returning \"Parsed successfully\" response to autocomplete"); + vec![AutocompleteChoice { + name: "Parsed successfully. Send command to view AST.".to_string(), + value: query.to_string(), + }] } } From deb0d34740934b7eb367421a66c7b5cf0940ea36 Mon Sep 17 00:00:00 2001 From: 0xLogN Date: Wed, 26 Jul 2023 10:27:08 -0400 Subject: [PATCH 4/4] trigger ci