Skip to content

Commit 8ae0e80

Browse files
committed
feat(vscode): rerender on save model
1 parent 57a32f7 commit 8ae0e80

3 files changed

Lines changed: 108 additions & 3 deletions

File tree

vscode/extension/src/commands/renderModel.ts

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,39 @@ import { isErr } from '@bus/result'
44
import { RenderModelEntry } from '../lsp/custom'
55
import { RenderedModelProvider } from '../providers/renderedModelProvider'
66

7+
export async function reRenderModelForSourceFile(
8+
sourceUri: string,
9+
lspClient: LSPClient,
10+
renderedModelProvider: RenderedModelProvider,
11+
): Promise<void> {
12+
const renderedUri = renderedModelProvider.getRenderedUriForSource(sourceUri)
13+
if (!renderedUri) {
14+
return // No rendered model exists for this source file
15+
}
16+
17+
// Call the render model API
18+
const result = await lspClient.call_custom_method('sqlmesh/render_model', {
19+
textDocumentUri: sourceUri,
20+
})
21+
22+
if (isErr(result)) {
23+
// Silently fail on auto-rerender errors to avoid spamming user
24+
return
25+
}
26+
27+
// Check if we got any models
28+
if (!result.value.models || result.value.models.length === 0) {
29+
return
30+
}
31+
32+
// For auto-rerender, we'll use the first model found
33+
// In the future, we could store which specific model was originally rendered
34+
const selectedModel = result.value.models[0]
35+
36+
// Update the existing rendered model content
37+
renderedModelProvider.updateRenderedModel(renderedUri, selectedModel.rendered_query)
38+
}
39+
740
export function renderModel(
841
lspClient?: LSPClient,
942
renderedModelProvider?: RenderedModelProvider,
@@ -114,6 +147,7 @@ export function renderModel(
114147
const uri = renderedModelProvider.storeRenderedModel(
115148
selectedModel.name,
116149
selectedModel.rendered_query,
150+
documentUri,
117151
)
118152

119153
// Open the virtual document

vscode/extension/src/extension.ts

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import { AuthenticationProviderTobikoCloud } from './auth/auth'
1212
import { signOut } from './commands/signout'
1313
import { signIn } from './commands/signin'
1414
import { signInSpecifyFlow } from './commands/signinSpecifyFlow'
15-
import { renderModel } from './commands/renderModel'
15+
import { renderModel, reRenderModelForSourceFile } from './commands/renderModel'
1616
import { isErr } from '@bus/result'
1717
import {
1818
handleNotSginedInError,
@@ -23,6 +23,7 @@ import {
2323
import { selector, completionProvider } from './completion/completion'
2424
import { LineagePanel } from './webviews/lineagePanel'
2525
import { RenderedModelProvider } from './providers/renderedModelProvider'
26+
import { sleep } from './utilities/sleep'
2627

2728
let lspClient: LSPClient | undefined
2829

@@ -99,6 +100,25 @@ export async function activate(context: vscode.ExtensionContext) {
99100
),
100101
)
101102

103+
// Add file save listener for auto-rerendering models
104+
context.subscriptions.push(
105+
vscode.workspace.onDidSaveTextDocument(async document => {
106+
if (
107+
lspClient &&
108+
renderedModelProvider.hasRenderedModelForSource(
109+
document.uri.toString(true),
110+
)
111+
) {
112+
await sleep(100)
113+
await reRenderModelForSourceFile(
114+
document.uri.toString(true),
115+
lspClient,
116+
renderedModelProvider,
117+
)
118+
}
119+
}),
120+
)
121+
102122
const restart = async () => {
103123
if (lspClient) {
104124
traceVerbose('Restarting LSP client')

vscode/extension/src/providers/renderedModelProvider.ts

Lines changed: 53 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@ export class RenderedModelProvider
99
private static readonly scheme = 'sqlmesh-rendered'
1010

1111
private renderedModels = new Map<string, string>()
12+
// Track which source file URIs are associated with rendered models
13+
private sourceToRenderedUri = new Map<string, vscode.Uri>()
14+
// Track which rendered URIs are associated with source files
15+
private renderedToSourceUri = new Map<string, string>()
1216

1317
// Event emitter for content changes
1418
private _onDidChange = new vscode.EventEmitter<vscode.Uri>()
@@ -25,7 +29,7 @@ export class RenderedModelProvider
2529
/**
2630
* Store rendered model content and create a URI for it
2731
*/
28-
storeRenderedModel(modelName: string, content: string): vscode.Uri {
32+
storeRenderedModel(modelName: string, content: string, sourceUri?: string): vscode.Uri {
2933
const fileName = `${modelName} (rendered)`
3034
// Add a timestamp to make the URI unique for each render
3135
const timestamp = Date.now()
@@ -35,11 +39,56 @@ export class RenderedModelProvider
3539
path: fileName,
3640
fragment: timestamp.toString(),
3741
})
38-
this.renderedModels.set(uri.toString(), content)
42+
43+
const uriString = uri.toString()
44+
this.renderedModels.set(uriString, content)
45+
46+
// Track the association between source file and rendered model
47+
if (sourceUri) {
48+
// Remove any existing mapping for this source file
49+
const existingRenderedUri = this.sourceToRenderedUri.get(sourceUri)
50+
if (existingRenderedUri) {
51+
this.renderedToSourceUri.delete(existingRenderedUri.toString())
52+
}
53+
54+
this.sourceToRenderedUri.set(sourceUri, uri)
55+
this.renderedToSourceUri.set(uriString, sourceUri)
56+
}
57+
3958
this._onDidChange.fire(uri)
4059
return uri
4160
}
4261

62+
/**
63+
* Update an existing rendered model with new content
64+
*/
65+
updateRenderedModel(uri: vscode.Uri, content: string): void {
66+
const uriString = uri.toString()
67+
this.renderedModels.set(uriString, content)
68+
this._onDidChange.fire(uri)
69+
}
70+
71+
/**
72+
* Get the rendered URI for a given source file URI
73+
*/
74+
getRenderedUriForSource(sourceUri: string): vscode.Uri | undefined {
75+
return this.sourceToRenderedUri.get(sourceUri)
76+
}
77+
78+
/**
79+
* Get the source URI for a given rendered model URI
80+
*/
81+
getSourceUriForRendered(renderedUri: string): string | undefined {
82+
return this.renderedToSourceUri.get(renderedUri)
83+
}
84+
85+
/**
86+
* Check if a source file has an associated rendered model
87+
*/
88+
hasRenderedModelForSource(sourceUri: string): boolean {
89+
return this.sourceToRenderedUri.has(sourceUri)
90+
}
91+
4392
/**
4493
* Get the URI scheme for rendered models
4594
*/
@@ -52,6 +101,8 @@ export class RenderedModelProvider
52101
*/
53102
dispose() {
54103
this.renderedModels.clear()
104+
this.sourceToRenderedUri.clear()
105+
this.renderedToSourceUri.clear()
55106
this._onDidChange.dispose()
56107
}
57108
}

0 commit comments

Comments
 (0)