Skip to content

Commit 8fa101a

Browse files
committed
Merge branch 'feat/lsp-server' into dev
2 parents c0e3f28 + db65290 commit 8fa101a

57 files changed

Lines changed: 5552 additions & 0 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
name: VSCode Extension
2+
3+
on:
4+
push:
5+
branches: [ "mainline" ]
6+
paths:
7+
- 'editors/vscode/**'
8+
pull_request:
9+
branches: [ "mainline" ]
10+
paths:
11+
- 'editors/vscode/**'
12+
13+
jobs:
14+
build:
15+
runs-on: ubuntu-latest
16+
17+
permissions:
18+
contents: read
19+
20+
defaults:
21+
run:
22+
working-directory: editors/vscode
23+
24+
steps:
25+
- uses: actions/checkout@v6
26+
27+
- name: Setup Node.js
28+
uses: actions/setup-node@v4
29+
with:
30+
node-version: '20'
31+
cache: 'npm'
32+
cache-dependency-path: editors/vscode/package-lock.json
33+
34+
- name: Install dependencies
35+
run: npm ci
36+
37+
- name: Type check
38+
run: npm run lint
39+
40+
- name: Build (esbuild)
41+
run: npm run package
42+
43+
- name: Package VSIX
44+
run: npx vsce package --no-dependencies
45+
46+
- name: Upload VSIX artifact
47+
uses: actions/upload-artifact@v4
48+
with:
49+
name: sharpy-lang-vsix
50+
path: editors/vscode/*.vsix
51+
retention-days: 30

README.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -423,6 +423,24 @@ sharpy/
423423
└── build_tools/ # Build automation and dogfooding tools
424424
```
425425

426+
## Editor Support
427+
428+
Sharpy includes a Language Server Protocol (LSP) server for IDE integration.
429+
430+
### VSCode
431+
432+
Install the **Sharpy** extension from the marketplace or build from `editors/vscode/`.
433+
434+
### Other Editors
435+
436+
Any editor supporting LSP can connect to the Sharpy language server:
437+
438+
```bash
439+
sharpyc lsp
440+
```
441+
442+
See [docs/tooling/editor-integration.md](docs/tooling/editor-integration.md) for configuration guides for Neovim, Emacs, Sublime Text, Helix, and Zed.
443+
426444
## License
427445

428446
MIT License - see [LICENSE](LICENSE) for details.

docs/tooling/editor-integration.md

Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
# Editor Integration
2+
3+
Any editor supporting the Language Server Protocol can connect to the Sharpy language server. The server communicates over stdio using JSON-RPC.
4+
5+
```bash
6+
sharpyc lsp
7+
```
8+
9+
See [lsp-server.md](lsp-server.md) for the full list of supported LSP features.
10+
11+
## Neovim
12+
13+
### Using nvim-lspconfig
14+
15+
Add a custom server configuration:
16+
17+
```lua
18+
local lspconfig = require('lspconfig')
19+
local configs = require('lspconfig.configs')
20+
21+
-- Register the Sharpy language server
22+
if not configs.sharpy then
23+
configs.sharpy = {
24+
default_config = {
25+
cmd = { 'sharpyc', 'lsp' },
26+
filetypes = { 'sharpy' },
27+
root_dir = function(fname)
28+
return lspconfig.util.find_git_ancestor(fname)
29+
or lspconfig.util.root_pattern('*.spyproj')(fname)
30+
end,
31+
settings = {},
32+
},
33+
}
34+
end
35+
36+
lspconfig.sharpy.setup({})
37+
```
38+
39+
### Filetype Detection
40+
41+
Add `.spy` filetype detection in `~/.config/nvim/filetype.lua`:
42+
43+
```lua
44+
vim.filetype.add({
45+
extension = {
46+
spy = 'sharpy',
47+
},
48+
})
49+
```
50+
51+
### Optional: Tree-sitter Highlighting
52+
53+
If no tree-sitter grammar is available for Sharpy, Python highlighting is a reasonable fallback:
54+
55+
```lua
56+
vim.treesitter.language.register('python', 'sharpy')
57+
```
58+
59+
## Emacs
60+
61+
### Using eglot (built-in, Emacs 29+)
62+
63+
```elisp
64+
;; Define a major mode for .spy files
65+
(define-derived-mode sharpy-mode python-mode "Sharpy"
66+
"Major mode for Sharpy (.spy) files.")
67+
68+
(add-to-list 'auto-mode-alist '("\\.spy\\'" . sharpy-mode))
69+
70+
;; Register the LSP server with eglot
71+
(with-eval-after-load 'eglot
72+
(add-to-list 'eglot-server-programs
73+
'(sharpy-mode "sharpyc" "lsp")))
74+
```
75+
76+
### Using lsp-mode
77+
78+
```elisp
79+
(require 'lsp-mode)
80+
81+
(define-derived-mode sharpy-mode python-mode "Sharpy"
82+
"Major mode for Sharpy (.spy) files.")
83+
84+
(add-to-list 'auto-mode-alist '("\\.spy\\'" . sharpy-mode))
85+
86+
(lsp-register-client
87+
(make-lsp-client
88+
:new-connection (lsp-stdio-connection '("sharpyc" "lsp"))
89+
:major-modes '(sharpy-mode)
90+
:server-id 'sharpy-lsp))
91+
92+
(add-hook 'sharpy-mode-hook #'lsp)
93+
```
94+
95+
## Sublime Text
96+
97+
### Using the LSP Package
98+
99+
1. Install the [LSP](https://packagecontrol.io/packages/LSP) package via Package Control
100+
2. Open **Preferences > Package Settings > LSP > Settings** and add:
101+
102+
```json
103+
{
104+
"clients": {
105+
"sharpy": {
106+
"enabled": true,
107+
"command": ["sharpyc", "lsp"],
108+
"selector": "source.sharpy",
109+
"schemes": ["file"]
110+
}
111+
}
112+
}
113+
```
114+
115+
3. Create a `.sublime-syntax` file or use Python syntax as a fallback for `.spy` files.
116+
117+
## Helix
118+
119+
Add to `~/.config/helix/languages.toml`:
120+
121+
```toml
122+
[[language]]
123+
name = "sharpy"
124+
scope = "source.sharpy"
125+
injection-regex = "sharpy"
126+
file-types = ["spy"]
127+
roots = ["*.spyproj"]
128+
comment-token = "#"
129+
indent = { tab-width = 4, unit = " " }
130+
131+
[language-server.sharpy]
132+
command = "sharpyc"
133+
args = ["lsp"]
134+
135+
[[language]]
136+
name = "sharpy"
137+
language-servers = ["sharpy"]
138+
```
139+
140+
## Zed
141+
142+
Add to your Zed settings (`~/.config/zed/settings.json`):
143+
144+
```json
145+
{
146+
"lsp": {
147+
"sharpy": {
148+
"binary": {
149+
"path": "sharpyc",
150+
"arguments": ["lsp"]
151+
}
152+
}
153+
},
154+
"languages": {
155+
"Sharpy": {
156+
"language_servers": ["sharpy"]
157+
}
158+
}
159+
}
160+
```
161+
162+
## General
163+
164+
For any LSP-capable editor not listed above, configure:
165+
166+
- **Command**: `sharpyc lsp`
167+
- **Transport**: stdio (stdin/stdout)
168+
- **File types**: `.spy`
169+
- **Language ID**: `sharpy`

docs/tooling/lsp-server.md

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
# Sharpy LSP Server
2+
3+
## Overview
4+
5+
Sharpy includes a built-in Language Server Protocol (LSP) server, accessible via `sharpyc lsp`. The server is implemented in the `Sharpy.Lsp` project using [OmniSharp.Extensions.LanguageServer](https://github.com/OmniSharp/csharp-language-server-protocol), providing IDE features to any editor that supports LSP.
6+
7+
## Architecture
8+
9+
The LSP server consists of three main layers:
10+
11+
- **SharplyWorkspace** -- Manages document state (open files, edits, file versions). Tracks document content in memory and synchronizes with the compiler.
12+
- **CompilerApi** -- Provides analysis services (parsing, type checking, diagnostics) by invoking the Sharpy compiler pipeline on demand.
13+
- **Handlers** -- Implement individual LSP protocol methods, delegating to CompilerApi for analysis and returning results in the LSP wire format.
14+
15+
```
16+
Editor <-> stdio (JSON-RPC) <-> LSP Server
17+
|
18+
+-- Handlers (one per LSP method)
19+
| |
20+
| +-- CompilerApi (analysis)
21+
| |
22+
| +-- Sharpy Compiler Pipeline
23+
|
24+
+-- SharplyWorkspace (document state)
25+
```
26+
27+
## Supported Features
28+
29+
### Document Synchronization
30+
31+
| Method | Description |
32+
|--------|-------------|
33+
| `textDocument/didOpen` | Track newly opened documents |
34+
| `textDocument/didChange` | Apply incremental edits |
35+
| `textDocument/didClose` | Release document state |
36+
| `textDocument/didSave` | Trigger full re-analysis on save |
37+
38+
### Diagnostics
39+
40+
| Method | Description |
41+
|--------|-------------|
42+
| `textDocument/publishDiagnostics` | Push compiler errors, warnings, and info to the editor |
43+
44+
Diagnostics are published after each document change (debounced) and include all `SPY`-prefixed diagnostic codes from the compiler.
45+
46+
### Navigation
47+
48+
| Method | Description |
49+
|--------|-------------|
50+
| `textDocument/definition` | Go-to-definition using `Symbol.DeclarationSpan` |
51+
| `textDocument/references` | Find all references using SemanticInfo reference tracking |
52+
| `textDocument/documentSymbol` | Hierarchical document outline (classes, functions, variables) |
53+
| `textDocument/documentHighlight` | Highlight all occurrences of a symbol in the current document |
54+
| `workspace/symbol` | Workspace-wide symbol search |
55+
56+
### Intelligence
57+
58+
| Method | Description |
59+
|--------|-------------|
60+
| `textDocument/hover` | Type information for identifiers, expressions, and function calls |
61+
| `textDocument/completion` | Scope-aware, member, and type completion |
62+
| `textDocument/signatureHelp` | Parameter hints during function calls |
63+
| `textDocument/inlayHint` | Inferred type and parameter name annotations |
64+
65+
### Refactoring
66+
67+
| Method | Description |
68+
|--------|-------------|
69+
| `textDocument/rename` | Symbol rename with validation (rejects invalid names) |
70+
| `textDocument/codeAction` | Quick fixes for naming conventions, unused imports, unused variables |
71+
72+
### Display
73+
74+
| Method | Description |
75+
|--------|-------------|
76+
| `textDocument/semanticTokens` | Semantic highlighting (types, functions, parameters, etc.) |
77+
| `textDocument/foldingRange` | Code folding for classes, functions, and block statements |
78+
| `textDocument/codeLens` | Reference counts on symbols; run buttons for entry points |
79+
| `textDocument/formatting` | Indentation normalization |
80+
81+
## Transport
82+
83+
The LSP server communicates over **stdio** (stdin/stdout) using the JSON-RPC 2.0 protocol. This is the standard transport for LSP and works with all major editors.
84+
85+
```bash
86+
sharpyc lsp
87+
```
88+
89+
The server reads JSON-RPC messages from stdin and writes responses to stdout. Logging and diagnostics go to stderr.
90+
91+
## Threading Model
92+
93+
- **Document map**: `ConcurrentDictionary<Uri, Document>` for thread-safe document access
94+
- **Per-document lock**: `SemaphoreSlim` per document prevents concurrent analysis of the same file
95+
- **Debounce**: 300ms debounce on `didChange` events to avoid redundant re-analysis during rapid typing
96+
97+
## Configuration
98+
99+
The server accepts configuration via the LSP `workspace/didChangeConfiguration` notification. Settings are typically configured through the editor (e.g., VSCode settings). See [vscode-extension.md](vscode-extension.md) for the full settings reference.

0 commit comments

Comments
 (0)