Skip to content

Instantly share code, notes, and snippets.

@iamnbutler
Created November 19, 2025 16:24
Show Gist options
  • Select an option

  • Save iamnbutler/a28cbb3ab88a4955efcb1be68d39761b to your computer and use it in GitHub Desktop.

Select an option

Save iamnbutler/a28cbb3ab88a4955efcb1be68d39761b to your computer and use it in GitHub Desktop.
Remindr pseudocode
// stuff you would want ACROSS documents, project, etc
// for example, a loaded font cache, a language registry for
// syntax highlighting code, etc.
pub struct AppState {
// see where Arc<LanguageRegistry> is used in the
// zed codebase on how you might use this
font_cache: Arc<FontCache>,
current_user: Option<User>,
markdown_renderer: Entity<MarkdownRenderer>
}
pub struct Project {
// something like
documents: HashMap<DocumentId, Entity<Document>>,
}
pub struct Document {
markdown_renderer: Entity<MarkdownRenderer>,
// the elements that make up the document
blocks: HashMap<BlockId, Block>,
block_order: Vec<BlockId>,
}
impl Document {
// how can an element take a context of itself?? odd right?
//
// When you construct this element using `cx.new(|cx| Document::new(cx))` it is
// given a context of itself in the closure
pub fn new(cx: &mut Context<Self>, state: WeakEntity<AppState>) -> Self {
// since as time goes on the `AppState` struct might get very heavy & expensive, we take a WeakEntity,
// which is an inexpensive handle to the actual Entity<AppState> that we can upgrade
let markdown_render = state
.upgrade()
// in this case `state.markdown_renderer() would return an Entity<MarkdownRenderer>
.and_then(|state| state.read(cx).markdown_renderer())
Self {
markdown_renderer,
blocks: HashMap::new(),
block_order: Vec::new()
}
}
pub fn insert_block(mut self, block: Block) -> Self {
let block_id = BlockId::new(); // however you generate IDs
// add the block to the hashmap
self.blocks.insert(block_id, block);
// then add it to the end of the order vector
self.block_order.push(block_id);
self
}
pub fn move_block_up(&mut self, block_id: &BlockId) {
if let Some(index) = self.block_order.iter().position(|id| id == block_id) {
if index > 0 {
self.block_order.swap(index, index - 1);
}
}
}
// you could even put block-specific creation methods here:
pub fn new_markdown_block(mut self, text: String) -> Self {
let rendered_block = self
.markdown_renderer
.update(cx, |renderer, cx| {
renderer.render_block(text)
})
self.insert_block(Block::Markdown(rendered_block))
}
}
pub enum Block {
Table(TableBlock),
Markdown(MarkdownBlock)
Code(CodeBlock),
}
pub struct MarkdownRenderer {
// some fields
// ...
// an active rendering task, if any
task: Option<RenderTask>
}
impl MarkdownRenderer {
pub fn render_block(&mut self, text: String) -> MarkdownBlock {
// implementation of rendering logic
}
}
pub struct MarkdownBlock {
elements: Vec<RenderedElement>,
}
// once we are ready to render the markdown block
// we can just RenderOnce as it doesn't need to be
// stateful – we don't update it directly, as it is held on
// the `Document` struct, and any updates would come from
// there. This element just renders whatever it is given
impl RenderOnce for MarkdownBlock {
fn render(self, window: &mut Window, cx: &mut App) -> impl IntoElement {
let theme = cx.theme() // not shown here - implement global theme: https://nate.rip/blog/gpui-adding-extended-context/
div().flex().flex_col().gap_1().bg(theme.block_bg).children(
// however RenderedElement is rendered, depends on implementation
)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment