Skip to content

Render inline queries ({{query}} blocks) #16

@avelino

Description

@avelino

Summary

Render blocks containing {{query: ...}} syntax by executing the query against the API and displaying results inline. Queries are one of Roam's power features for creating dynamic views of data.

Roam web behavior: {{query: {and: [[tag1]] [[tag2]]}}} renders as an embedded list of blocks matching the boolean query. Supports and, or, not, and between operators with page/tag references.

TUI adaptation: Read-only rendering — show query results inline as a collapsible list of matching blocks. No query editor (too complex for TUI). Users write queries in edit mode using standard text, and they render when exiting edit mode. Results are cached with a TTL to avoid excessive API calls.

Implementation hints

Parser

  • src/markdown.rs:34-63 — already parses {{...}} syntax for TODO/DONE/embed
  • Add detection for {{query: ...}} or {{[[query]]: ...}}
  • Extract the query body (everything between {{query: and }})
  • Parse boolean operators: {and: [...] [...]}, {or: [...]}, {not: [...]}
  • Extract page references from the query conditions

Query translation

  • Convert Roam query syntax to Datalog:
    {and: [[tag1]] [[tag2]]}
    →
    [:find (pull ?b [:block/string :block/uid {:block/page [:node/title]}])
     :where [?b :block/string ?s]
            [?b :block/refs ?r1] [?r1 :node/title "tag1"]
            [?b :block/refs ?r2] [?r2 :node/title "tag2"]]
    
  • src/api/queries.rs — add query_from_roam_syntax(query_body: &str) -> String

Rendering

  • src/ui/main_area.rs — add VisibleLine variant for query results:
    • QueryHeading { block_index, result_count } — shows "Query: N results" with toggle
    • QueryResult { depth, text, block_index } — each result block
  • Collapsed by default (show count), expand to see results
  • Results render with full markdown formatting

Caching

  • src/app.rs — add query result cache:
    pub query_cache: HashMap<String, (Vec<Block>, Instant)>, // query_hash → (results, fetched_at)
  • TTL: 60 seconds (configurable)
  • Refetch on manual refresh

Supported operators (v1)

  • {and: [[A]] [[B]]} — blocks referencing both A and B
  • {or: [[A]] [[B]]} — blocks referencing A or B
  • {not: [[A]]} — blocks NOT referencing A
  • Nested: {and: [[A]] {not: [[B]]}} — A but not B

Acceptance criteria

  • {{query: {and: [[tag1]] [[tag2]]}}} renders with results inline
  • Results are collapsible (collapsed by default)
  • and, or, not operators work correctly
  • Results cached with TTL, refreshed on manual trigger
  • Query blocks render a placeholder while loading
  • Malformed queries show error message instead of crashing

Metadata

Metadata

Assignees

No one assigned

    Labels

    area: apiRoam Research API integrationarea: renderingUI rendering, markdown, syntax highlightingpriority: lowNice to have, low urgencyroam parityFeature that exists in Roam web, ported to TUI

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions