Skip to main content

scrybe_core/
workspace.rs

1// SPDX-License-Identifier: Apache-2.0
2// Copyright 2026 Shawn Hartsock and contributors
3
4//! Workspace — a collection of open documents and shared editor state.
5
6use std::collections::HashMap;
7use std::path::PathBuf;
8
9use uuid::Uuid;
10
11use crate::document::Document;
12
13/// A unique identifier for an open document within a workspace.
14#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
15pub struct DocumentId(Uuid);
16
17impl DocumentId {
18    /// Creates a new random document ID.
19    pub fn new() -> Self {
20        Self(Uuid::new_v4())
21    }
22}
23
24impl Default for DocumentId {
25    fn default() -> Self {
26        Self::new()
27    }
28}
29
30/// The editor workspace — open documents and their IDs.
31#[derive(Debug, Default)]
32pub struct Workspace {
33    documents: HashMap<DocumentId, Document>,
34    /// Root directory for the workspace (e.g. the repo root).
35    pub root: Option<PathBuf>,
36}
37
38impl Workspace {
39    /// Creates an empty workspace.
40    pub fn new() -> Self {
41        Self::default()
42    }
43
44    /// Opens a document and returns its ID.
45    pub fn open(&mut self, doc: Document) -> DocumentId {
46        let id = DocumentId::new();
47        self.documents.insert(id, doc);
48        id
49    }
50
51    /// Returns a reference to a document by ID.
52    pub fn get(&self, id: &DocumentId) -> Option<&Document> {
53        self.documents.get(id)
54    }
55
56    /// Returns a mutable reference to a document by ID.
57    pub fn get_mut(&mut self, id: &DocumentId) -> Option<&mut Document> {
58        self.documents.get_mut(id)
59    }
60
61    /// Closes a document, returning it if it was open.
62    pub fn close(&mut self, id: &DocumentId) -> Option<Document> {
63        self.documents.remove(id)
64    }
65
66    /// Returns the number of open documents.
67    pub fn len(&self) -> usize {
68        self.documents.len()
69    }
70
71    /// Returns `true` if no documents are open.
72    pub fn is_empty(&self) -> bool {
73        self.documents.is_empty()
74    }
75}
76
77#[cfg(test)]
78mod tests {
79    use super::*;
80
81    #[test]
82    fn test_workspace_open_close() {
83        let mut ws = Workspace::new();
84        let doc = Document::new("# Test");
85        let id = ws.open(doc);
86        assert_eq!(ws.len(), 1);
87        assert!(ws.get(&id).is_some());
88        ws.close(&id);
89        assert!(ws.is_empty());
90    }
91}