Workflows
Opening a File from the UI
How a file-tree click travels from Sky through Wind's editor and filesystem services to a Mountain disk read, then back to Monaco.
Workflow Example: Opening a File from the UI
Goal: The user clicks on a file in the File Explorer (Wind/Sky UI), and the file’s content is loaded into an editor.
This workflow demonstrates the interplay between the UI, the editor services, the filesystem provider, and the backend. A single file-tree click traverses four layer boundaries: Sky dispatches the intent, Wind’s editor and filesystem services resolve and load the model, a Tauri IPC call reaches Mountain for the native disk read, and the result unwinds back through the same chain until Monaco renders the content.
flowchart TB
subgraph UI["Wind/Sky Frontend"]
U["User clicks file<br/>in File Explorer"]
ES["IEditorService.openEditor()"]
TES["TextEditorService<br/>resolves EditorInput"]
end
subgraph Editor["Wind Editor Groups"]
EGS["EditorGroupsService"]
TEI["TextFileEditorModel.load()"]
FS["IFileService.readFile()"]
end
subgraph FileSystem["Wind FileSystem Provider"]
TDFSP["TauriDiskFileSystemProvider"]
RF["ReadFile Effect"]
end
subgraph Integration["Wind Integration Layer"]
TI["TauriInvoke"]
end
subgraph Backend["Mountain Backend"]
TFS["Tauri fs Plugin"]
NATIVE["tokio::fs::read()"]
CONTENT["File Content<br/>Vec<u8>"]
end
subgraph Render["Wind Rendering"]
TPE["TextEditorPane"]
ME["Monaco Editor"]
DIS["Display to User"]
end
U -->|onClick| ES
ES -->|openEditorEffect| TES
TES -->|findGroup| EGS
EGS -->|check if already open| TEI
TEI -->|needs content| FS
FS -->|lookup provider| TDFSP
TDFSP -->|execute effect| RF
RF -->|TauriInvoke| TI
TI -->|gRPC call| TFS
TFS -->|native I/O| NATIVE
NATIVE -->|read from disk| CONTENT
CONTENT -->|serialize response| TI
TI -->|promise resolves| RF
RF -->|Uint8Array| TDFSP
TDFSP -->|return content| FS
FS -->|file content| TEI
TEI -->|model hydrated| EGS
EGS -->|create editor| TPE
TPE -->|set model| ME
ME -->|render text| DIS
style UI fill:#e1f5ff
style Editor fill:#fff4e1
style FileSystem fill:#ffe1f5
style Integration fill:#e1ffe1
style Backend fill:#f5e1ff
style Render fill:#fff0e1Phase 1 - User Interaction (Sky)
File Explorer UI — The user clicks on a file entry (
<div>representingmy-file.ts) in the File Explorer component. TheonClickhandler holds the file’sURIand calls intoIEditorService.IEditorService.openEditor()(Wind/Source/Effect/Editor) — The UI callseditorService.openEditor({ resource: fileUri }). TheopenEditorEffectinside the editorDefinition.tsis executed. The input is anIUntypedEditorInput. The effect first passes it toTextEditorServiceto resolve it into a concreteEditorInputinstance, then callsfindGroupto determine which editor group should handle the opening (e.g. the currently active group).
Phase 2 - Editor and Filesystem Logic (Wind → Mountain)
EditorGroupsService— TheopenEditormethod is called on the targetEditorGroupModel. The group model checks whether an editor forfileUriis already open:- Already open: Wind focuses that tab and stops.
- Not open: It begins opening a new editor. It uses the
EditorInput’sresolve()method to obtain the editor model.
TextFileEditorModel.load()— To display the content, the editor input loads its underlying model.TextFileEditorModelis responsible for this. Itsload()method needs the file content. It callsIFileService.readFile(fileUri)from Wind/Source/FileSystem.IFileService.readFile()(Wind/Source/FileSystem) — The file service’sreadFile(fileUri)method looks up the registered provider for the URI’s scheme (in this casefile:). It findsTauriDiskFileSystemProviderfrom FileSystem/Definition.ts.TauriDiskFileSystemProvider.readFile()(Wind/Source/FileSystem) — The provider’sreadFilemethod immediately executes theReadFileEffect from the Tauri integration layer:Effect.runPromise(ReadFile(fileUri));TauriMainProcessService.ts(Wind/Source/Service) — TheReadFileeffect executes. It calls:TauriInvoke("plugin:fs|ReadFile", { path: fileUri.fsPath });This sends the request from the webview across the process boundary into the Mountain backend.
Phase 3 - Native File I/O (Mountain)
Mountain/Source/Binary/Main/Entry.rs → Tauri
fsPlugin — Tauri receives theplugin:fs|ReadFilecommand and routes it to thetauri-plugin-fsinternal Rust handler. The plugin performs the native filesystem operation:tokio::fs::read(path)The file content (
Vec<u8>) is read from disk. The result is serialised and sent back to the Wind webview as the resolution of theTauriInvokepromise.
Phase 4 - Data Unwinds and UI Renders (Wind)
TauriMainProcessService.ts(continued) — TheTauriInvokepromise resolves with the file content. TheReadFileEffect succeeds, yielding theUint8Arraycontaining the raw bytes of the file.TextFileEditorModel(continued) — Theload()method completes. The model is now hydrated with the file content. TheEditorInputis fully resolved.EditorGroupsService(continued) — TheopenEditormethod now has a resolved input and model. It creates a newTextEditorPanewithin the target editor group and sets theTextFileEditorModelon the underlying Monaco editor instance inside that pane.Monaco Editor — Monaco receives the new text model and renders the text content to the screen. The user now sees their file open in the editor.
This workflow shows how a simple UI action is translated through layers of abstraction (EditorService → FileService → FileSystemProvider → Tauri Integration) until it becomes a native OS call, with the result flowing back up the same chain to update the UI.
File Content Flow
The raw byte payload passes through distinct representations at each layer:
| Layer | Representation | Component |
|---|---|---|
| Mountain (disk) | Vec<u8> | tokio::fs::read |
| Mountain → Tauri IPC | Serialised byte vector | tauri-plugin-fs |
| Wind integration | Uint8Array | TauriInvoke promise |
| Wind FileSystem | Uint8Array | ReadFile Effect |
| Wind Editor | Decoded string model | TextFileEditorModel |
| Monaco | Text buffer | editor.setModel() |
Important
The IFileService provider lookup is keyed on URI scheme. Only file: URIs reach TauriDiskFileSystemProvider. Custom-scheme URIs (e.g. git:, output:) are served by their own registered TextDocumentContentProvider in Cocoon, which follows a different path through the gRPC layer.
openTextDocument variants
vscode.workspace.openTextDocument supports three calling forms beyond a plain file URI:
{ language, content }— Creates an in-memory untitled document pre-populated withcontentand tagged withlanguageId. The document is added toworkspace.textDocumentsandonDidOpenTextDocumentfires immediately. No Mountain round-trip occurs."untitled:..."scheme — Returns an empty document without any backend call. Content is read fromDocumentContentCacheif a prior write has populated it.- Custom scheme (e.g.
git:,output:) — Cocoon checks whether aTextDocumentContentProviderhas been registered for that scheme viaregisterTextDocumentContentProvider. If one is found, Cocoon callsprovider.provideTextDocumentContent()directly with no Mountain round-trip and no 10-second timeout. For schemes where no provider is registered and Mountain is the authoritative owner (e.g. output channels), the standardFileSystem.ReadFilegRPC route is used instead.
openTextDocument API parameters
The openTextDocument function has three overloads in the VS Code API:
| Overload | First Parameter | Description |
|---|---|---|
openTextDocument(uri) | Uri | Opens the resource identified by the URI. file:-scheme reads from disk; untitled: creates a blank untitled file; other schemes consult registered providers. |
openTextDocument(path) | string | Short-hand for openTextDocument(Uri.file(path)). A filesystem path on disk. |
openTextDocument(options?) | { language?, content?, encoding? } | Creates an in-memory untitled document. language sets the language ID, content sets initial contents, encoding specifies text encoding. |
All overloads return Thenable<TextDocument>. The uri and string overloads also accept an optional { encoding?: string } options parameter to control text decoding of the underlying buffer.