Detailed changes
@@ -45,11 +45,10 @@ impl Tool for BashTool {
fn ui_text(&self, input: &serde_json::Value) -> String {
match serde_json::from_value::<BashToolInput>(input.clone()) {
Ok(input) => {
- let cmd = MarkdownString::escape(&input.command);
if input.command.contains('\n') {
- format!("```bash\n{cmd}\n```")
+ MarkdownString::code_block("bash", &input.command).0
} else {
- format!("`{cmd}`")
+ MarkdownString::inline_code(&input.command).0
}
}
Err(_) => "Run bash command".to_string(),
@@ -61,9 +61,9 @@ impl Tool for CopyPathTool {
fn ui_text(&self, input: &serde_json::Value) -> String {
match serde_json::from_value::<CopyPathToolInput>(input.clone()) {
Ok(input) => {
- let src = MarkdownString::escape(&input.source_path);
- let dest = MarkdownString::escape(&input.destination_path);
- format!("Copy `{src}` to `{dest}`")
+ let src = MarkdownString::inline_code(&input.source_path);
+ let dest = MarkdownString::inline_code(&input.destination_path);
+ format!("Copy {src} to {dest}")
}
Err(_) => "Copy path".to_string(),
}
@@ -51,7 +51,10 @@ impl Tool for CreateDirectoryTool {
fn ui_text(&self, input: &serde_json::Value) -> String {
match serde_json::from_value::<CreateDirectoryToolInput>(input.clone()) {
Ok(input) => {
- format!("Create directory `{}`", MarkdownString::escape(&input.path))
+ format!(
+ "Create directory {}",
+ MarkdownString::inline_code(&input.path)
+ )
}
Err(_) => "Create directory".to_string(),
}
@@ -58,8 +58,8 @@ impl Tool for CreateFileTool {
fn ui_text(&self, input: &serde_json::Value) -> String {
match serde_json::from_value::<CreateFileToolInput>(input.clone()) {
Ok(input) => {
- let path = MarkdownString::escape(&input.path);
- format!("Create file `{path}`")
+ let path = MarkdownString::inline_code(&input.path);
+ format!("Create file {path}")
}
Err(_) => "Create file".to_string(),
}
@@ -66,11 +66,11 @@ impl Tool for DiagnosticsTool {
if let Some(path) = serde_json::from_value::<DiagnosticsToolInput>(input.clone())
.ok()
.and_then(|input| match input.path {
- Some(path) if !path.is_empty() => Some(MarkdownString::escape(&path)),
+ Some(path) if !path.is_empty() => Some(MarkdownString::inline_code(&path)),
_ => None,
})
{
- format!("Check diagnostics for `{path}`")
+ format!("Check diagnostics for {path}")
} else {
"Check project diagnostics".to_string()
}
@@ -63,8 +63,8 @@ impl Tool for ListDirectoryTool {
fn ui_text(&self, input: &serde_json::Value) -> String {
match serde_json::from_value::<ListDirectoryToolInput>(input.clone()) {
Ok(input) => {
- let path = MarkdownString::escape(&input.path);
- format!("List the `{path}` directory's contents")
+ let path = MarkdownString::inline_code(&input.path);
+ format!("List the {path} directory's contents")
}
Err(_) => "List directory".to_string(),
}
@@ -61,8 +61,8 @@ impl Tool for MovePathTool {
fn ui_text(&self, input: &serde_json::Value) -> String {
match serde_json::from_value::<MovePathToolInput>(input.clone()) {
Ok(input) => {
- let src = MarkdownString::escape(&input.source_path);
- let dest = MarkdownString::escape(&input.destination_path);
+ let src = MarkdownString::inline_code(&input.source_path);
+ let dest = MarkdownString::inline_code(&input.destination_path);
let src_path = Path::new(&input.source_path);
let dest_path = Path::new(&input.destination_path);
@@ -71,11 +71,11 @@ impl Tool for MovePathTool {
.and_then(|os_str| os_str.to_os_string().into_string().ok())
{
Some(filename) if src_path.parent() == dest_path.parent() => {
- let filename = MarkdownString::escape(&filename);
- format!("Rename `{src}` to `{filename}`")
+ let filename = MarkdownString::inline_code(&filename);
+ format!("Rename {src} to {filename}")
}
_ => {
- format!("Move `{src}` to `{dest}`")
+ format!("Move {src} to {dest}")
}
}
}
@@ -66,8 +66,8 @@ impl Tool for ReadFileTool {
fn ui_text(&self, input: &serde_json::Value) -> String {
match serde_json::from_value::<ReadFileToolInput>(input.clone()) {
Ok(input) => {
- let path = MarkdownString::escape(&input.path.display().to_string());
- format!("Read file `{path}`")
+ let path = MarkdownString::inline_code(&input.path.display().to_string());
+ format!("Read file {path}")
}
Err(_) => "Read file".to_string(),
}
@@ -64,12 +64,12 @@ impl Tool for RegexSearchTool {
match serde_json::from_value::<RegexSearchToolInput>(input.clone()) {
Ok(input) => {
let page = input.page();
- let regex = MarkdownString::escape(&input.regex);
+ let regex = MarkdownString::inline_code(&input.regex);
if page > 1 {
- format!("Get page {page} of search results for regex “`{regex}`”")
+ format!("Get page {page} of search results for regex “{regex}”")
} else {
- format!("Search files for regex “`{regex}`”")
+ format!("Search files for regex “{regex}”")
}
}
Err(_) => "Search with regex".to_string(),
@@ -11,7 +11,9 @@ impl Display for MarkdownString {
}
impl MarkdownString {
- /// Escapes markdown special characters.
+ /// Escapes markdown special characters in markdown text blocks. Markdown code blocks follow
+ /// different rules and `MarkdownString::inline_code` or `MarkdownString::code_block` should be
+ /// used in that case.
///
/// Also escapes the following markdown extensions:
///
@@ -134,6 +136,12 @@ impl MarkdownString {
Self(format!("{backticks}{space}{text}{space}{backticks}"))
}
}
+
+ /// Returns markdown for code blocks, wrapped in 3 or more backticks as needed.
+ pub fn code_block(tag: &str, text: &str) -> Self {
+ let backticks = "`".repeat(3.max(count_max_consecutive_chars(text, '`') + 1));
+ Self(format!("{backticks}{tag}\n{text}\n{backticks}\n"))
+ }
}
// Copied from `pulldown-cmark-to-cmark-20.0.0` with changed names.