feat(tui): add markdown rendering support and toggle command

- Introduce new `owlen-markdown` crate that converts Markdown strings to `ratatui::Text` with headings, lists, bold/italic, and inline code.
- Add `render_markdown` config option (default true) and expose it via `app.render_markdown_enabled()`.
- Implement `:markdown [on|off]` command to toggle markdown rendering.
- Update help overlay to document the new markdown toggle.
- Adjust UI rendering to conditionally apply markdown styling based on the markdown flag and code mode.
- Wire the new crate into `owlen-tui` Cargo.toml.
This commit is contained in:
2025-10-14 01:35:13 +02:00
parent 99064b6c41
commit 498e6e61b6
24 changed files with 911 additions and 247 deletions

View File

@@ -53,8 +53,8 @@ fn extract_resource_content(value: &Value) -> Option<String> {
Value::Array(items) => {
let mut segments = Vec::new();
for item in items {
if let Some(segment) = extract_resource_content(item)
&& !segment.is_empty()
if let Some(segment) =
extract_resource_content(item).filter(|segment| !segment.is_empty())
{
segments.push(segment);
}
@@ -69,17 +69,19 @@ fn extract_resource_content(value: &Value) -> Option<String> {
const PREFERRED_FIELDS: [&str; 6] =
["content", "contents", "text", "value", "body", "data"];
for key in PREFERRED_FIELDS.iter() {
if let Some(inner) = map.get(*key)
&& let Some(text) = extract_resource_content(inner)
&& !text.is_empty()
if let Some(text) = map
.get(*key)
.and_then(extract_resource_content)
.filter(|text| !text.is_empty())
{
return Some(text);
}
}
if let Some(inner) = map.get("chunks")
&& let Some(text) = extract_resource_content(inner)
&& !text.is_empty()
if let Some(text) = map
.get("chunks")
.and_then(extract_resource_content)
.filter(|text| !text.is_empty())
{
return Some(text);
}
@@ -566,9 +568,10 @@ impl SessionController {
.expect("Consent manager mutex poisoned");
consent.grant_consent(tool_name, data_types, endpoints);
if let Some(vault) = &self.vault
&& let Err(e) = consent.persist_to_vault(vault)
{
let Some(vault) = &self.vault else {
return;
};
if let Err(e) = consent.persist_to_vault(vault) {
eprintln!("Warning: Failed to persist consent to vault: {}", e);
}
}
@@ -588,10 +591,13 @@ impl SessionController {
consent.grant_consent_with_scope(tool_name, data_types, endpoints, scope);
// Only persist to vault for permanent consent
if is_permanent
&& let Some(vault) = &self.vault
&& let Err(e) = consent.persist_to_vault(vault)
{
if !is_permanent {
return;
}
let Some(vault) = &self.vault else {
return;
};
if let Err(e) = consent.persist_to_vault(vault) {
eprintln!("Warning: Failed to persist consent to vault: {}", e);
}
}