Skip to content

Commit d00b09f

Browse files
authored
feat: prepare extension for release (#1)
* feat: prepare extension for release * fix: remove redundant settings from sublime-settings * fix: remove sublime syntax from extension * fix: remove hardcoded extension name and use None instead of Optional * docs: split contribution notes and remove notes about syntax highlighting * fix: use sublime.timeout_async instead of manual threading * feat: use package name in command name * feat: use auto_download setting properly Read the setting from LSP-wren-lsp defaults and document config inline. * feat: add sublime-package.json * docs: link Wren syntax and clarify binary
1 parent 0b7019f commit d00b09f

File tree

8 files changed

+361
-0
lines changed

8 files changed

+361
-0
lines changed

.gitignore

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
*.pyc
2+
__pycache__/
3+
*.pyo
4+
*.pyd
5+
.Python
6+
*.so
7+
*.egg
8+
*.egg-info/
9+
dist/
10+
build/
11+
*.DS_Store
12+
Thumbs.db
13+
*.sublime-workspace
14+
*.sublime-project
15+
*.sublime-package

.python-version

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
3.8

CONTRIBUTING.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# Contributing
2+
3+
## Building
4+
5+
To create a `.sublime-package` file for distribution:
6+
7+
```bash
8+
# From the sublime directory
9+
zip -r WrenLSP.sublime-package . -x "*.git*" -x "*.DS_Store" -x "README.md"
10+
```
11+
12+
Install via: `Preferences > Browse Packages...` (place in `Installed Packages/` folder)

Default.sublime-commands

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
[
2+
{
3+
"caption": "LSP-wren-lsp: Update Language Server",
4+
"command": "wren_lsp_update"
5+
}
6+
]

LSP-wren-lsp.sublime-settings

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
{
2+
// Path to the wren-lsp executable
3+
// If not provided, the plugin will use the auto-downloaded binary
4+
"command": ["${binary_path}"],
5+
// Files this server should handle
6+
"selector": "source.wren",
7+
// Plugin-specific settings
8+
"settings": {
9+
// Automatically download the latest wren-lsp binary from GitHub releases
10+
"auto_download": true
11+
}
12+
}

README.md

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
# Wren Language Support for Sublime Text
2+
3+
This package provides language support for [Wren](https://wren.io/) via [wren-lsp](https://github.com/jossephus/wren-lsp).
4+
5+
## Features
6+
7+
- Diagnostics (syntax + semantic checks)
8+
- Code completion
9+
- Hover information
10+
- Go to definition
11+
- Find references
12+
- Rename symbol
13+
- Semantic tokens
14+
- Document symbols (outline)
15+
- Signature help
16+
- Document highlights
17+
- Code actions (quick fixes)
18+
- Workspace symbols
19+
- Folding ranges
20+
- Selection range
21+
- Inlay hints (type hints)
22+
23+
## Requirements
24+
25+
- [Sublime Text 4](https://www.sublimetext.com/) (build 4000+)
26+
- [LSP](https://packagecontrol.io/packages/LSP) package (install via Package Control)
27+
- [Wren](https://packagecontrol.io/packages/Wren) syntax package
28+
29+
## Installation
30+
31+
### Via Package Control (Recommended - when published)
32+
33+
1. Open Command Palette (`Cmd/Ctrl+Shift+P`)
34+
2. Type "Package Control: Install Package"
35+
3. Search for "Wren LSP"
36+
37+
### Manual Installation
38+
39+
1. Download/clone this repository
40+
2. Copy/move the folder to your Sublime Text Packages directory:
41+
- macOS: `~/Library/Application Support/Sublime Text/Packages/`
42+
- Linux: `~/.config/sublime-text/Packages/`
43+
- Windows: `%APPDATA%/Sublime Text/Packages/`
44+
45+
### LSP Binary
46+
47+
The extension will auto-download the appropriate `wren-lsp` binary for your platform from GitHub releases if it is not already available. Alternatively, you can:
48+
49+
1. Download manually from [releases](https://github.com/jossephus/wren-lsp/releases)
50+
2. Place it in your PATH, or
51+
3. Set the path in settings (see below)
52+
53+
## Configuration
54+
55+
Access settings via: `Preferences > Package Settings > LSP-wren-lsp > Settings`
56+
57+
## Usage
58+
59+
1. Open a `.wren` file
60+
2. LSP will automatically start the language server
61+
3. Use LSP features via:
62+
- Command Palette (`Cmd/Ctrl+Shift+P`)
63+
- Right-click context menu
64+
- Keyboard shortcuts (see LSP package documentation)
65+
66+
## Troubleshooting
67+
68+
**LSP not starting?**
69+
- Check the Sublime Text console (`View > Show Console`) for errors
70+
- Ensure `wren-lsp` is in your PATH or set the correct path in settings
71+
- Try disabling auto-download if behind a proxy
72+
73+
## License
74+
75+
MIT

plugin.py

Lines changed: 182 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,182 @@
1+
"""
2+
LSP client registration for Wren Language Server.
3+
"""
4+
5+
from __future__ import annotations
6+
7+
import os
8+
import shutil
9+
import json
10+
import urllib.request
11+
from pathlib import Path
12+
13+
import sublime
14+
import sublime_plugin
15+
16+
from LSP.plugin import AbstractPlugin, register_plugin, unregister_plugin
17+
18+
REPO = "jossephus/wren-lsp"
19+
REQUEST_TIMEOUT = 30
20+
SETTINGS_FILE = "LSP-wren-lsp.sublime-settings"
21+
22+
23+
def get_auto_download_setting() -> bool:
24+
"""Read auto_download setting from LSP-wren-lsp settings."""
25+
settings = sublime.load_settings(SETTINGS_FILE)
26+
return settings.get("settings", {}).get("auto_download", True)
27+
28+
29+
def get_binary_name() -> str:
30+
return "wren-lsp.exe" if sublime.platform() == "windows" else "wren-lsp"
31+
32+
33+
def get_storage_path() -> Path:
34+
return Path(sublime.cache_path()) / str(__package__)
35+
36+
37+
def get_binary_path() -> Path:
38+
return get_storage_path() / get_binary_name()
39+
40+
41+
def get_installed_version() -> str | None:
42+
version_file = get_storage_path() / "version.txt"
43+
try:
44+
if version_file.exists():
45+
return version_file.read_text().strip()
46+
except Exception as e:
47+
print(f"WrenLSP: failed reading version.txt: {e}")
48+
return None
49+
50+
51+
def save_installed_version(version: str) -> None:
52+
version_file = get_storage_path() / "version.txt"
53+
version_file.parent.mkdir(parents=True, exist_ok=True)
54+
version_file.write_text(version)
55+
56+
57+
def get_platform_asset() -> str | None:
58+
platform_map = {
59+
("linux", "x64"): "wren-lsp-linux-x86_64",
60+
("linux", "arm64"): "wren-lsp-linux-aarch64",
61+
("osx", "x64"): "wren-lsp-macos-x86_64",
62+
("osx", "arm64"): "wren-lsp-macos-aarch64",
63+
("windows", "x64"): "wren-lsp-windows-x86_64.exe",
64+
("windows", "arm64"): "wren-lsp-windows-aarch64.exe",
65+
}
66+
return platform_map.get((sublime.platform(), sublime.arch()))
67+
68+
69+
def fetch_latest_release() -> dict:
70+
url = f"https://api.github.com/repos/{REPO}/releases/latest"
71+
req = urllib.request.Request(url)
72+
req.add_header("User-Agent", "wren-lsp-sublime")
73+
req.add_header("Accept", "application/vnd.github.v3+json")
74+
with urllib.request.urlopen(req, timeout=REQUEST_TIMEOUT) as response:
75+
return json.loads(response.read().decode('utf-8'))
76+
77+
78+
def download_binary(download_url: str, binary_path: Path) -> None:
79+
temp_path = binary_path.with_suffix('.tmp')
80+
req = urllib.request.Request(download_url)
81+
req.add_header("User-Agent", "wren-lsp-sublime")
82+
with urllib.request.urlopen(req, timeout=REQUEST_TIMEOUT) as response:
83+
temp_path.parent.mkdir(parents=True, exist_ok=True)
84+
with open(temp_path, 'wb') as f:
85+
while chunk := response.read(8192):
86+
f.write(chunk)
87+
if binary_path.exists():
88+
binary_path.unlink()
89+
temp_path.rename(binary_path)
90+
if sublime.platform() != 'windows':
91+
binary_path.chmod(0o755)
92+
93+
94+
class WrenLsp(AbstractPlugin):
95+
96+
@classmethod
97+
def name(cls) -> str:
98+
return "wren-lsp"
99+
100+
@classmethod
101+
def basedir(cls) -> str:
102+
return os.path.dirname(__file__)
103+
104+
@classmethod
105+
def server_version(cls) -> str:
106+
return get_installed_version() or "unknown"
107+
108+
@classmethod
109+
def current_server_version(cls) -> str | None:
110+
return get_installed_version()
111+
112+
@classmethod
113+
def needs_update_or_installation(cls) -> bool:
114+
if get_binary_path().exists():
115+
return False
116+
if shutil.which("wren-lsp"):
117+
return False
118+
return get_auto_download_setting()
119+
120+
@classmethod
121+
def install_or_update(cls) -> None:
122+
asset_name = get_platform_asset()
123+
if not asset_name:
124+
raise Exception(f"Unsupported platform: {sublime.platform()}-{sublime.arch()}")
125+
126+
release = fetch_latest_release()
127+
version = release.get('tag_name') or "unknown"
128+
if not release.get('assets'):
129+
raise Exception("Latest release has no assets")
130+
131+
download_url = None
132+
for asset in release['assets']:
133+
if asset['name'] == asset_name:
134+
download_url = asset['browser_download_url']
135+
break
136+
137+
if not download_url:
138+
raise Exception(f"No binary for platform: {sublime.platform()}-{sublime.arch()}")
139+
140+
download_binary(download_url, get_binary_path())
141+
save_installed_version(version)
142+
143+
@classmethod
144+
def additional_variables(cls) -> dict | None:
145+
binary_path = get_binary_path()
146+
if binary_path.exists():
147+
return {"binary_path": str(binary_path)}
148+
wren_lsp_in_path = shutil.which("wren-lsp")
149+
if wren_lsp_in_path:
150+
return {"binary_path": wren_lsp_in_path}
151+
return {"binary_path": str(binary_path)}
152+
153+
154+
class WrenLspUpdateCommand(sublime_plugin.ApplicationCommand):
155+
156+
def run(self) -> None:
157+
sublime.set_timeout_async(self._update, 0)
158+
159+
def _update(self) -> None:
160+
try:
161+
sublime.status_message("WrenLSP: Checking for updates...")
162+
installed = get_installed_version()
163+
release = fetch_latest_release()
164+
latest = release.get('tag_name')
165+
166+
if installed == latest:
167+
sublime.message_dialog(f"WrenLSP: Already up to date ({latest})")
168+
return
169+
170+
WrenLsp.install_or_update()
171+
msg = f"WrenLSP: Updated from {installed or 'unknown'} to {latest}. Restart LSP to apply."
172+
sublime.message_dialog(msg)
173+
except Exception as e:
174+
sublime.error_message(f"WrenLSP: Failed to update: {e}")
175+
176+
177+
def plugin_loaded() -> None:
178+
register_plugin(WrenLsp)
179+
180+
181+
def plugin_unloaded() -> None:
182+
unregister_plugin(WrenLsp)

sublime-package.json

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
{
2+
"contributions": {
3+
"settings": [
4+
{
5+
"file_patterns": [
6+
"/LSP-wren-lsp.sublime-settings"
7+
],
8+
"schema": {
9+
"$id": "sublime://settings/LSP-wren-lsp",
10+
"allOf": [
11+
{
12+
"$ref": "sublime://settings/LSP-plugin-base"
13+
},
14+
{
15+
"$ref": "sublime://settings/LSP-wren-lsp#/definitions/PluginConfig"
16+
}
17+
],
18+
"definitions": {
19+
"PluginConfig": {
20+
"properties": {
21+
"settings": {
22+
"additionalProperties": false,
23+
"properties": {
24+
"auto_download": {
25+
"default": true,
26+
"description": "Automatically download the latest wren-lsp binary from GitHub releases.",
27+
"type": "boolean"
28+
}
29+
}
30+
}
31+
}
32+
}
33+
}
34+
}
35+
},
36+
{
37+
"file_patterns": [
38+
"/*.sublime-project"
39+
],
40+
"schema": {
41+
"properties": {
42+
"settings": {
43+
"properties": {
44+
"LSP": {
45+
"properties": {
46+
"wren-lsp": {
47+
"$ref": "sublime://settings/LSP-wren-lsp#/definitions/PluginConfig"
48+
}
49+
}
50+
}
51+
}
52+
}
53+
}
54+
}
55+
}
56+
]
57+
}
58+
}

0 commit comments

Comments
 (0)