Skip to content

Commit 50b9fc2

Browse files
committed
temp
[ci skip]
1 parent f8c517a commit 50b9fc2

2 files changed

Lines changed: 75 additions & 33 deletions

File tree

examples/sushi/config.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
PlanConfig,
1414
SparkConnectionConfig,
1515
)
16+
from sqlmesh.core.config.linter import LinterConfig
1617
from sqlmesh.core.notification_target import (
1718
BasicSMTPNotificationTarget,
1819
SlackApiNotificationTarget,
@@ -41,6 +42,15 @@
4142
},
4243
default_gateway="duckdb",
4344
model_defaults=model_defaults,
45+
linter=LinterConfig(
46+
enabled=True,
47+
rules=[
48+
"ambiguousorinvalidcolumn",
49+
"invalidselectstarexpansion",
50+
"noselectstar",
51+
"nomissingaudits",
52+
],
53+
),
4454
)
4555

4656
bigquery_config = Config(

sqlmesh/lsp/main.py

Lines changed: 65 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,8 @@ def __init__(
3232
"""
3333
self.server = LanguageServer(server_name, version)
3434
self.context_class = context_class
35-
self.context: t.Optional[Context] = None
35+
# A tuple of (context, reverse_map) where the reverse_map is uri to model name
36+
self.context_and_reverse_map: t.Optional[t.Tuple[Context, t.Dict[str, str]]] = None
3637
self.lint_cache: t.Dict[str, t.List[RuleViolationWithModelAndType]] = {}
3738

3839
# Register LSP features (e.g., formatting, hover, etc.)
@@ -43,42 +44,39 @@ def _register_features(self) -> None:
4344

4445
@self.server.feature(types.TEXT_DOCUMENT_DID_OPEN)
4546
def did_open(ls: LanguageServer, params: types.DidOpenTextDocumentParams) -> None:
46-
if self.context is None:
47+
if self.context_and_reverse_map is None:
4748
self.ensure_context_for_document(
4849
ls.workspace.get_document(params.text_document.uri)
4950
)
50-
if self.context is None:
51+
if self.context_and_reverse_map is None:
5152
raise RuntimeError("No context found")
52-
self.lint_cache[params.text_document.uri] = self.context.lint_models(
53-
[params.text_document.uri]
53+
self.lint_cache[params.text_document.uri] = self.context_and_reverse_map[0].lint_models(
54+
[SQLMeshLanguageServer._uri_to_path(params.text_document.uri)]
5455
)
5556
ls.publish_diagnostics(
5657
params.text_document.uri,
57-
[
58-
self._diagnostic_to_lsp_diagnostic(diagnostic)
59-
for diagnostic in self.lint_cache[params.text_document.uri]
60-
if diagnostic is not None
61-
],
58+
SQLMeshLanguageServer._diagnostics_to_lsp_diagnostics(
59+
self.lint_cache[params.text_document.uri]
60+
),
6261
)
6362

6463
@self.server.feature(types.TEXT_DOCUMENT_DID_CHANGE)
6564
def did_change(ls: LanguageServer, params: types.DidChangeTextDocumentParams) -> None:
66-
if self.context is None:
65+
if self.context_and_reverse_map is None:
6766
self.ensure_context_for_document(
6867
ls.workspace.get_document(params.text_document.uri)
6968
)
70-
if self.context is None:
69+
if self.context_and_reverse_map is None:
7170
raise RuntimeError("No context found")
72-
self.lint_cache[params.text_document.uri] = self.context.lint_models(
73-
[params.text_document.uri]
71+
model = self.context_and_reverse_map[1][params.text_document.uri]
72+
self.lint_cache[params.text_document.uri] = self.context_and_reverse_map[0].lint_models(
73+
[model]
7474
)
7575
ls.publish_diagnostics(
7676
params.text_document.uri,
77-
[
78-
self._diagnostic_to_lsp_diagnostic(diagnostic)
79-
for diagnostic in self.lint_cache[params.text_document.uri]
80-
if diagnostic is not None
81-
],
77+
SQLMeshLanguageServer._diagnostics_to_lsp_diagnostics(
78+
self.lint_cache[params.text_document.uri]
79+
),
8280
)
8381

8482
@self.server.feature(types.TEXT_DOCUMENT_DID_CLOSE)
@@ -87,22 +85,21 @@ def did_close(ls: LanguageServer, params: types.DidCloseTextDocumentParams) -> N
8785

8886
@self.server.feature(types.TEXT_DOCUMENT_DID_SAVE)
8987
def did_save(ls: LanguageServer, params: types.DidSaveTextDocumentParams) -> None:
90-
if self.context is None:
88+
if self.context_and_reverse_map is None:
9189
self.ensure_context_for_document(
9290
ls.workspace.get_document(params.text_document.uri)
9391
)
94-
if self.context is None:
92+
if self.context_and_reverse_map is None:
9593
raise RuntimeError("No context found")
96-
self.lint_cache[params.text_document.uri] = self.context.lint_models(
97-
[params.text_document.uri]
94+
model = self.context_and_reverse_map[1][params.text_document.uri]
95+
self.lint_cache[params.text_document.uri] = self.context_and_reverse_map[0].lint_models(
96+
[model]
9897
)
9998
ls.publish_diagnostics(
10099
params.text_document.uri,
101-
[
102-
self._diagnostic_to_lsp_diagnostic(diagnostic)
103-
for diagnostic in self.lint_cache[params.text_document.uri]
104-
if diagnostic is not None
105-
],
100+
SQLMeshLanguageServer._diagnostics_to_lsp_diagnostics(
101+
self.lint_cache[params.text_document.uri]
102+
),
106103
)
107104

108105
@self.server.feature(types.TEXT_DOCUMENT_FORMATTING)
@@ -115,11 +112,11 @@ def formatting(
115112
ls.workspace.get_document(params.text_document.uri)
116113
)
117114

118-
if self.context is None:
115+
if self.context_and_reverse_map is None:
119116
raise RuntimeError(f"No context found for document: {document.path}")
120117

121118
# Perform formatting using the loaded context
122-
self.context.format(paths=(Path(document.path),))
119+
self.context_and_reverse_map[0].format(paths=(Path(document.path),))
123120
with open(document.path, "r+", encoding="utf-8") as file:
124121
new_text = file.read()
125122

@@ -146,8 +143,16 @@ def ensure_context_for_document(self, document: TextDocument) -> TextDocument:
146143
for a config.py or config.yml file in the parent directories.
147144
"""
148145
# If the context is already loaded, check if this document belongs to it.
149-
if self.context is not None:
150-
self.context.load() # Reload or refresh context
146+
if self.context_and_reverse_map is not None:
147+
context, _ = self.context_and_reverse_map
148+
context.load() # Reload or refresh context
149+
self.context_and_reverse_map = (
150+
context,
151+
{
152+
f"file://{Path(model._path).resolve().as_posix()}": model.name
153+
for model in context._models.values()
154+
},
155+
)
151156
return document
152157

153158
# No context yet: try to find config and load it
@@ -163,7 +168,14 @@ def ensure_context_for_document(self, document: TextDocument) -> TextDocument:
163168
if config_path.exists():
164169
try:
165170
# Use user-provided instantiator to build the context
166-
self.context = self.context_class(paths=[path])
171+
context = self.context_class(paths=[path])
172+
self.context_and_reverse_map = (
173+
context,
174+
{
175+
f"file://{Path(model._path).resolve().as_posix()}": model.name
176+
for model in context._models.values()
177+
},
178+
)
167179
self.server.show_message(f"Context loaded for: {path}")
168180
loaded = True
169181
# Re-check context for document now that it's loaded
@@ -195,6 +207,26 @@ def _diagnostic_to_lsp_diagnostic(
195207
else types.DiagnosticSeverity.Warning,
196208
)
197209

210+
@staticmethod
211+
def _diagnostics_to_lsp_diagnostics(
212+
diagnostics: t.List[RuleViolationWithModelAndType],
213+
) -> t.List[types.Diagnostic]:
214+
lsp_diagnostics: t.List[types.Diagnostic] = []
215+
for diagnostic in diagnostics:
216+
if diagnostic is None:
217+
continue
218+
lsp_diagnostic = SQLMeshLanguageServer._diagnostic_to_lsp_diagnostic(diagnostic)
219+
if lsp_diagnostic is not None:
220+
lsp_diagnostics.append(lsp_diagnostic)
221+
return lsp_diagnostics
222+
223+
@staticmethod
224+
def _uri_to_path(uri: str) -> str:
225+
"""Convert a URI to a path."""
226+
if uri.startswith("file://"):
227+
return Path(uri[7:]).resolve().as_posix()
228+
return Path(uri).resolve().as_posix()
229+
198230
def start(self) -> None:
199231
"""Start the server with I/O transport."""
200232
logging.basicConfig(level=logging.DEBUG)

0 commit comments

Comments
 (0)