wafer-lsp 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. wafer_lsp-0.1.0/.gitignore +85 -0
  2. wafer_lsp-0.1.0/PKG-INFO +57 -0
  3. wafer_lsp-0.1.0/README.md +37 -0
  4. wafer_lsp-0.1.0/pyproject.toml +67 -0
  5. wafer_lsp-0.1.0/src/wafer_lsp/__init__.py +1 -0
  6. wafer_lsp-0.1.0/src/wafer_lsp/__main__.py +9 -0
  7. wafer_lsp-0.1.0/src/wafer_lsp/analyzers/__init__.py +0 -0
  8. wafer_lsp-0.1.0/src/wafer_lsp/analyzers/compiler_integration.py +16 -0
  9. wafer_lsp-0.1.0/src/wafer_lsp/analyzers/docs_index.py +36 -0
  10. wafer_lsp-0.1.0/src/wafer_lsp/handlers/__init__.py +0 -0
  11. wafer_lsp-0.1.0/src/wafer_lsp/handlers/code_action.py +48 -0
  12. wafer_lsp-0.1.0/src/wafer_lsp/handlers/code_lens.py +48 -0
  13. wafer_lsp-0.1.0/src/wafer_lsp/handlers/completion.py +6 -0
  14. wafer_lsp-0.1.0/src/wafer_lsp/handlers/diagnostics.py +16 -0
  15. wafer_lsp-0.1.0/src/wafer_lsp/handlers/document_symbol.py +87 -0
  16. wafer_lsp-0.1.0/src/wafer_lsp/handlers/hover.py +215 -0
  17. wafer_lsp-0.1.0/src/wafer_lsp/handlers/inlay_hint.py +65 -0
  18. wafer_lsp-0.1.0/src/wafer_lsp/handlers/semantic_tokens.py +124 -0
  19. wafer_lsp-0.1.0/src/wafer_lsp/handlers/workspace_symbol.py +87 -0
  20. wafer_lsp-0.1.0/src/wafer_lsp/languages/README.md +195 -0
  21. wafer_lsp-0.1.0/src/wafer_lsp/languages/__init__.py +17 -0
  22. wafer_lsp-0.1.0/src/wafer_lsp/languages/converter.py +88 -0
  23. wafer_lsp-0.1.0/src/wafer_lsp/languages/detector.py +34 -0
  24. wafer_lsp-0.1.0/src/wafer_lsp/languages/parser_manager.py +33 -0
  25. wafer_lsp-0.1.0/src/wafer_lsp/languages/registry.py +99 -0
  26. wafer_lsp-0.1.0/src/wafer_lsp/languages/types.py +37 -0
  27. wafer_lsp-0.1.0/src/wafer_lsp/parsers/__init__.py +18 -0
  28. wafer_lsp-0.1.0/src/wafer_lsp/parsers/base_parser.py +9 -0
  29. wafer_lsp-0.1.0/src/wafer_lsp/parsers/cuda_parser.py +95 -0
  30. wafer_lsp-0.1.0/src/wafer_lsp/parsers/cutedsl_parser.py +114 -0
  31. wafer_lsp-0.1.0/src/wafer_lsp/server.py +58 -0
  32. wafer_lsp-0.1.0/src/wafer_lsp/services/__init__.py +21 -0
  33. wafer_lsp-0.1.0/src/wafer_lsp/services/analysis_service.py +22 -0
  34. wafer_lsp-0.1.0/src/wafer_lsp/services/docs_service.py +40 -0
  35. wafer_lsp-0.1.0/src/wafer_lsp/services/document_service.py +20 -0
  36. wafer_lsp-0.1.0/src/wafer_lsp/services/hover_service.py +237 -0
  37. wafer_lsp-0.1.0/src/wafer_lsp/services/language_registry_service.py +26 -0
  38. wafer_lsp-0.1.0/src/wafer_lsp/services/position_service.py +77 -0
  39. wafer_lsp-0.1.0/src/wafer_lsp/utils/__init__.py +0 -0
  40. wafer_lsp-0.1.0/src/wafer_lsp/utils/lsp_helpers.py +79 -0
  41. wafer_lsp-0.1.0/tests/__init__.py +1 -0
  42. wafer_lsp-0.1.0/tests/test_converter.py +121 -0
  43. wafer_lsp-0.1.0/tests/test_cutedsl_parser.py +60 -0
  44. wafer_lsp-0.1.0/tests/test_language_detector.py +59 -0
  45. wafer_lsp-0.1.0/tests/test_lsp_handlers.py +57 -0
  46. wafer_lsp-0.1.0/tests/test_parser_manager.py +57 -0
@@ -0,0 +1,85 @@
1
+ # Python
2
+ *.pyc
3
+ __pycache__/
4
+ *.py[cod]
5
+ *$py.class
6
+ *.so
7
+ .Python
8
+ *.egg-info/
9
+
10
+ # Virtual environments
11
+ .venv/
12
+ venv/
13
+ env/
14
+ ENV/
15
+
16
+ # Distribution / packaging
17
+ dist/
18
+ build/
19
+ *.egg
20
+
21
+ # IDE
22
+ .vscode/
23
+ .cursor/
24
+ .idea/
25
+ *.swp
26
+ *.swo
27
+ *~
28
+
29
+ # OS
30
+ .DS_Store
31
+ Thumbs.db
32
+
33
+ # Temporary files
34
+ *.tmp
35
+ tests.txt
36
+ output.txt
37
+
38
+ # Evaluation results
39
+ experiments/emilio/cutedsl-quack-eval/eval_results/*.txt
40
+ experiments/emilio/cutedsl-quack-eval/eval_results/*.json
41
+ experiments/emilio/cutedsl-quack-eval/eval_results/*.py
42
+ research/evals/kernelbench/results/
43
+ wafer_artifacts/
44
+ **/wafer_artifacts/
45
+ /.deps/
46
+
47
+ # Local config files
48
+ services/docs-tool/config.yaml
49
+
50
+ # Environment files with secrets
51
+ .env
52
+ .env.local
53
+ .env.*.local
54
+ node_modules/
55
+ .vscode-test/
56
+
57
+ # npm artifacts (using yarn)
58
+ package-lock.json
59
+ npm-debug.log*
60
+ .npm/
61
+ .npmrc
62
+
63
+ # Yarn artifacts
64
+ .yarn/install-state.gz
65
+
66
+ # NSYS report files (can be very large)
67
+ *.nsys-rep
68
+
69
+ # Turbo build cache
70
+ .turbo/
71
+ **/.turbo/
72
+
73
+ # Supabase CLI temp files
74
+ supabase/.branches/
75
+ supabase/.temp/
76
+ **/supabase/.branches/
77
+ **/supabase/.temp/
78
+
79
+ # Eval results (generated, large)
80
+ research/evals/kernelbench/kernelbench/results/
81
+ research/evals/retrieval_eval_project/retrieval_eval/results/
82
+ research/evals/retrieval_eval_project/*.log
83
+
84
+ # Wafer extension trace files
85
+ .wafer/traces/
@@ -0,0 +1,57 @@
1
+ Metadata-Version: 2.4
2
+ Name: wafer-lsp
3
+ Version: 0.1.0
4
+ Summary: Language Server Protocol server for GPU programming languages
5
+ Author-email: Wafer <support@wafer.ai>
6
+ License: MIT
7
+ Keywords: c++,cuda,cutedsl,gpu,language-server,lsp
8
+ Classifier: Development Status :: 3 - Alpha
9
+ Classifier: Intended Audience :: Developers
10
+ Classifier: License :: OSI Approved :: MIT License
11
+ Classifier: Programming Language :: Python :: 3
12
+ Classifier: Programming Language :: Python :: 3.12
13
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
14
+ Classifier: Topic :: Text Editors :: Integrated Development Environments (IDE)
15
+ Requires-Python: >=3.12
16
+ Requires-Dist: lsprotocol>=2024.0.0
17
+ Requires-Dist: pygls>=1.0.0
18
+ Requires-Dist: wafer-core
19
+ Description-Content-Type: text/markdown
20
+
21
+ # Wafer LSP
22
+
23
+ Language Server Protocol server for CuTeDSL (Python GPU programming).
24
+
25
+ **Beta Feature**: Currently only available when Beta Mode is enabled in VS Code settings.
26
+
27
+ ## Features
28
+
29
+ - **Hover Information**: Shows kernel and layout information with compiler analysis when hovering over CuTeDSL code
30
+
31
+ ## Installation
32
+
33
+ ```bash
34
+ pip install wafer-lsp
35
+ ```
36
+
37
+ ## Usage
38
+
39
+ ### VS Code Extension
40
+
41
+ The LSP server is integrated into the `wevin-extension` VS Code extension. It starts automatically when Beta Mode is enabled.
42
+
43
+ ### Standalone
44
+
45
+ For Neovim or other editors:
46
+
47
+ ```bash
48
+ python -m wafer_lsp
49
+ ```
50
+
51
+ ## Supported Languages
52
+
53
+ - **CuTeDSL**: Python files with `@cute.kernel` decorators
54
+
55
+ ## Architecture
56
+
57
+ The LSP server uses a modular language registry system. Currently supports CuTeDSL only. See `languages/README.md` for details on adding more languages.
@@ -0,0 +1,37 @@
1
+ # Wafer LSP
2
+
3
+ Language Server Protocol server for CuTeDSL (Python GPU programming).
4
+
5
+ **Beta Feature**: Currently only available when Beta Mode is enabled in VS Code settings.
6
+
7
+ ## Features
8
+
9
+ - **Hover Information**: Shows kernel and layout information with compiler analysis when hovering over CuTeDSL code
10
+
11
+ ## Installation
12
+
13
+ ```bash
14
+ pip install wafer-lsp
15
+ ```
16
+
17
+ ## Usage
18
+
19
+ ### VS Code Extension
20
+
21
+ The LSP server is integrated into the `wevin-extension` VS Code extension. It starts automatically when Beta Mode is enabled.
22
+
23
+ ### Standalone
24
+
25
+ For Neovim or other editors:
26
+
27
+ ```bash
28
+ python -m wafer_lsp
29
+ ```
30
+
31
+ ## Supported Languages
32
+
33
+ - **CuTeDSL**: Python files with `@cute.kernel` decorators
34
+
35
+ ## Architecture
36
+
37
+ The LSP server uses a modular language registry system. Currently supports CuTeDSL only. See `languages/README.md` for details on adding more languages.
@@ -0,0 +1,67 @@
1
+ [project]
2
+ name = "wafer-lsp"
3
+ version = "0.1.0"
4
+ description = "Language Server Protocol server for GPU programming languages"
5
+ readme = "README.md"
6
+ requires-python = ">=3.12"
7
+ dependencies = [
8
+ "pygls>=1.0.0",
9
+ "lsprotocol>=2024.0.0",
10
+ "wafer-core", # For compiler analyzer
11
+ ]
12
+ authors = [
13
+ { name = "Wafer", email = "support@wafer.ai" }
14
+ ]
15
+ license = { text = "MIT" }
16
+ keywords = ["lsp", "language-server", "gpu", "cuda", "cutedsl", "c++"]
17
+ classifiers = [
18
+ "Development Status :: 3 - Alpha",
19
+ "Intended Audience :: Developers",
20
+ "License :: OSI Approved :: MIT License",
21
+ "Programming Language :: Python :: 3",
22
+ "Programming Language :: Python :: 3.12",
23
+ "Topic :: Software Development :: Libraries :: Python Modules",
24
+ "Topic :: Text Editors :: Integrated Development Environments (IDE)",
25
+ ]
26
+
27
+ [build-system]
28
+ requires = ["hatchling"]
29
+ build-backend = "hatchling.build"
30
+
31
+ [project.scripts]
32
+ wafer-lsp = "wafer_lsp.__main__:main"
33
+
34
+ [tool.hatch.build.targets.wheel]
35
+ packages = ["src/wafer_lsp"]
36
+
37
+ [tool.ruff]
38
+ line-length = 100
39
+ target-version = "py312"
40
+ preview = true
41
+
42
+ [tool.ruff.lint]
43
+ select = [
44
+ "E", # pycodestyle errors
45
+ "W", # pycodestyle warnings
46
+ "F", # pyflakes
47
+ "I", # isort
48
+ "B", # flake8-bugbear
49
+ "C4", # flake8-comprehensions
50
+ "UP", # pyupgrade
51
+ "ARG", # flake8-unused-arguments
52
+ "SIM", # flake8-simplify
53
+ "PLR", # pylint refactor
54
+ "PLW", # pylint warnings
55
+ "PT", # flake8-pytest-style
56
+ "RUF", # Ruff-specific rules
57
+ ]
58
+ ignore = [
59
+ "E501", # line too long (handled by formatter)
60
+ "B008", # do not perform function calls in argument defaults
61
+ "PLR0913", # too many arguments
62
+ "PLR2004", # magic value used in comparison
63
+ ]
64
+
65
+ [tool.ruff.format]
66
+ quote-style = "double"
67
+ indent-style = "space"
@@ -0,0 +1 @@
1
+ __version__ = "0.1.0"
@@ -0,0 +1,9 @@
1
+ from wafer_lsp.server import server
2
+
3
+
4
+ def main():
5
+ server.start_io()
6
+
7
+
8
+ if __name__ == "__main__":
9
+ main()
File without changes
@@ -0,0 +1,16 @@
1
+ from typing import Any
2
+
3
+ _analysis_cache: dict[str, dict[str, Any]] = {}
4
+
5
+
6
+ def get_analysis_for_kernel(uri: str, kernel_name: str) -> dict[str, Any] | None:
7
+ cache_key = f"{uri}:{kernel_name}"
8
+
9
+ if cache_key in _analysis_cache:
10
+ return _analysis_cache[cache_key]
11
+
12
+ return None
13
+
14
+
15
+ def clear_cache():
16
+ _analysis_cache.clear()
@@ -0,0 +1,36 @@
1
+ from pathlib import Path
2
+
3
+
4
+ class DocsIndex:
5
+
6
+ def __init__(self, docs_path: str | None = None):
7
+ if docs_path:
8
+ self.docs_path = Path(docs_path)
9
+ else:
10
+ self.docs_path = Path(__file__).parent.parent.parent.parent.parent / \
11
+ "curriculum" / "cutlass-docs" / "cutedsl-docs"
12
+
13
+ self.index = self._build_index()
14
+
15
+ def _build_index(self) -> dict[str, list[str]]:
16
+ return {
17
+ "layout": [
18
+ "intro-to-cutedsl.md",
19
+ "partitioning-strategies-inner-outer-threadvalue.md"
20
+ ],
21
+ "TMA": ["blackwell-tutorial-fp16-gemm-0.md"],
22
+ "TMEM": ["colfax-blackwell-umma-tensor-memory-part1.md"],
23
+ "kernel": ["blackwell-tutorial-fp16-gemm-0.md"],
24
+ "struct": ["blackwell-tutorial-fp16-gemm-0.md"],
25
+ "pipeline": ["blackwell-tutorial-fp16-gemm-0.md"],
26
+ "MMA": ["mma-atoms-fundamentals-sm70-example.md"],
27
+ }
28
+
29
+ def get_doc_for_concept(self, concept: str) -> str | None:
30
+ concept_lower = concept.lower()
31
+ if self.index.get(concept_lower):
32
+ doc_file = self.index[concept_lower][0]
33
+ doc_path = self.docs_path / doc_file
34
+ if doc_path.exists():
35
+ return str(doc_path)
36
+ return None
File without changes
@@ -0,0 +1,48 @@
1
+
2
+ from lsprotocol.types import CodeAction, CodeActionKind, Command, Range
3
+
4
+ from ..languages.registry import get_language_registry
5
+ from ..languages.types import KernelInfo
6
+
7
+
8
+ def find_kernel_at_range(content: str, range: Range, uri: str) -> KernelInfo | None:
9
+ registry = get_language_registry()
10
+ language_info = registry.parse_file(uri, content)
11
+
12
+ if not language_info:
13
+ return None
14
+
15
+ for kernel in language_info.kernels:
16
+ if kernel.line <= range.start.line <= kernel.line + 50:
17
+ return kernel
18
+
19
+ return None
20
+
21
+
22
+ def handle_code_action(uri: str, range: Range, content: str) -> list[CodeAction]:
23
+ kernel = find_kernel_at_range(content, range, uri)
24
+ if not kernel:
25
+ return []
26
+
27
+ actions: list[CodeAction] = [
28
+ CodeAction(
29
+ title=f"Analyze Kernel: {kernel.name}",
30
+ kind=CodeActionKind.Source,
31
+ command=Command(
32
+ title=f"Analyze Kernel: {kernel.name}",
33
+ command="wafer.analyzeKernel",
34
+ arguments=[uri, kernel.name]
35
+ )
36
+ ),
37
+ CodeAction(
38
+ title=f"Profile Kernel: {kernel.name}",
39
+ kind=CodeActionKind.Source,
40
+ command=Command(
41
+ title=f"Profile Kernel: {kernel.name}",
42
+ command="wafer.profileKernel",
43
+ arguments=[uri, kernel.name]
44
+ )
45
+ ),
46
+ ]
47
+
48
+ return actions
@@ -0,0 +1,48 @@
1
+
2
+ from lsprotocol.types import CodeLens, Command, Position, Range
3
+
4
+ from ..languages.registry import get_language_registry
5
+
6
+
7
+ def handle_code_lens(uri: str, content: str) -> list[CodeLens]:
8
+ registry = get_language_registry()
9
+ language_info = registry.parse_file(uri, content)
10
+
11
+ if not language_info:
12
+ return []
13
+
14
+ lenses: list[CodeLens] = []
15
+
16
+ for kernel in language_info.kernels:
17
+ lens_range = Range(
18
+ start=Position(line=kernel.line, character=0),
19
+ end=Position(line=kernel.line, character=0)
20
+ )
21
+
22
+ analyze_command = Command(
23
+ title=f"Analyze {kernel.name}",
24
+ command="wafer.analyzeKernel",
25
+ arguments=[uri, kernel.name]
26
+ )
27
+
28
+ profile_command = Command(
29
+ title=f"Profile {kernel.name}",
30
+ command="wafer.profileKernel",
31
+ arguments=[uri, kernel.name]
32
+ )
33
+
34
+ lenses.append(CodeLens(
35
+ range=lens_range,
36
+ command=analyze_command
37
+ ))
38
+
39
+ profile_range = Range(
40
+ start=Position(line=kernel.line, character=20),
41
+ end=Position(line=kernel.line, character=20)
42
+ )
43
+ lenses.append(CodeLens(
44
+ range=profile_range,
45
+ command=profile_command
46
+ ))
47
+
48
+ return lenses
@@ -0,0 +1,6 @@
1
+
2
+ from lsprotocol.types import CompletionItem
3
+
4
+
5
+ def handle_completion(uri: str, position, content: str) -> list[CompletionItem]:
6
+ return []
@@ -0,0 +1,16 @@
1
+
2
+ from lsprotocol.types import Diagnostic
3
+
4
+ from ..languages.registry import get_language_registry
5
+
6
+
7
+ def handle_diagnostics(uri: str, content: str) -> list[Diagnostic]:
8
+ diagnostics: list[Diagnostic] = []
9
+
10
+ registry = get_language_registry()
11
+ language_info = registry.parse_file(uri, content)
12
+
13
+ if not language_info:
14
+ return diagnostics
15
+
16
+ return diagnostics
@@ -0,0 +1,87 @@
1
+
2
+ from lsprotocol.types import DocumentSymbol, Position, Range, SymbolKind
3
+
4
+ from ..languages.registry import get_language_registry
5
+
6
+
7
+ def handle_document_symbol(uri: str, content: str) -> list[DocumentSymbol]:
8
+ registry = get_language_registry()
9
+ language_info = registry.parse_file(uri, content)
10
+
11
+ if not language_info:
12
+ return []
13
+
14
+ symbols: list[DocumentSymbol] = []
15
+
16
+ for kernel in language_info.kernels:
17
+ lines = content.split("\n")
18
+ kernel_line = lines[kernel.line] if kernel.line < len(lines) else ""
19
+ name_start = kernel_line.find(kernel.name)
20
+ name_end = name_start + len(kernel.name) if name_start >= 0 else 0
21
+
22
+ selection_range = Range(
23
+ start=Position(line=kernel.line, character=max(0, name_start)),
24
+ end=Position(line=kernel.line, character=name_end)
25
+ )
26
+ full_range = Range(
27
+ start=Position(line=kernel.line, character=0),
28
+ end=Position(line=min(kernel.line + 10, len(lines) - 1), character=0)
29
+ )
30
+
31
+ symbols.append(DocumentSymbol(
32
+ name=kernel.name,
33
+ kind=SymbolKind.Function,
34
+ range=full_range,
35
+ selection_range=selection_range,
36
+ detail=f"GPU Kernel ({registry.get_language_name(kernel.language)})",
37
+ ))
38
+
39
+ for layout in language_info.layouts:
40
+ lines = content.split("\n")
41
+ layout_line = lines[layout.line] if layout.line < len(lines) else ""
42
+ name_start = layout_line.find(layout.name)
43
+ name_end = name_start + len(layout.name) if name_start >= 0 else 0
44
+
45
+ detail = f"Layout: {layout.shape}" if layout.shape else "Layout"
46
+
47
+ selection_range = Range(
48
+ start=Position(line=layout.line, character=max(0, name_start)),
49
+ end=Position(line=layout.line, character=name_end)
50
+ )
51
+ full_range = Range(
52
+ start=Position(line=layout.line, character=0),
53
+ end=Position(line=layout.line, character=len(layout_line))
54
+ )
55
+
56
+ symbols.append(DocumentSymbol(
57
+ name=layout.name,
58
+ kind=SymbolKind.Variable,
59
+ range=full_range,
60
+ selection_range=selection_range,
61
+ detail=detail,
62
+ ))
63
+
64
+ for struct in language_info.structs:
65
+ lines = content.split("\n")
66
+ struct_line = lines[struct.line] if struct.line < len(lines) else ""
67
+ name_start = struct_line.find(struct.name)
68
+ name_end = name_start + len(struct.name) if name_start >= 0 else 0
69
+
70
+ selection_range = Range(
71
+ start=Position(line=struct.line, character=max(0, name_start)),
72
+ end=Position(line=struct.line, character=name_end)
73
+ )
74
+ full_range = Range(
75
+ start=Position(line=struct.line, character=0),
76
+ end=Position(line=min(struct.line + 10, len(lines) - 1), character=0)
77
+ )
78
+
79
+ symbols.append(DocumentSymbol(
80
+ name=struct.name,
81
+ kind=SymbolKind.Struct,
82
+ range=full_range,
83
+ selection_range=selection_range,
84
+ detail=f"Struct ({registry.get_language_name(struct.language)})",
85
+ ))
86
+
87
+ return symbols