Created
November 19, 2025 16:24
-
-
Save iamnbutler/a28cbb3ab88a4955efcb1be68d39761b to your computer and use it in GitHub Desktop.
Remindr pseudocode
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // 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