or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

client-operations.mdexception-handling.mdfeature-registration.mdindex.mdprogress-reporting.mdprotocol-handling.mdserver-management.mduri-utilities.mdutilities.mdworkspace-management.md

feature-registration.mddocs/

0

# Feature Registration and Decorators

1

2

Decorator-based system for registering LSP features, custom commands, and thread execution patterns with automatic capability registration and declarative programming patterns.

3

4

## Capabilities

5

6

### Feature Registration

7

8

Decorator for registering Language Server Protocol features with automatic capability negotiation and method binding.

9

10

```python { .api }

11

def feature(

12

self,

13

method_name: str,

14

options: Any = None

15

) -> Callable[[F], F]:

16

"""

17

Decorator to register LSP features.

18

19

Parameters:

20

- method_name: str - LSP method name (e.g., 'textDocument/completion')

21

- options: Any - Feature-specific options (e.g., CompletionOptions, HoverOptions)

22

23

Returns:

24

Decorator function that registers the decorated function as a feature handler

25

"""

26

27

@lsp_method(method_name: str) -> Callable[[F], F]:

28

"""

29

Low-level decorator for registering LSP method handlers.

30

31

Parameters:

32

- method_name: str - LSP method name

33

34

Returns:

35

Decorator function for method registration

36

"""

37

```

38

39

### Command Registration

40

41

Decorator for registering custom server commands that can be invoked by clients.

42

43

```python { .api }

44

def command(self, command_name: str) -> Callable[[F], F]:

45

"""

46

Decorator to register custom commands.

47

48

Parameters:

49

- command_name: str - Unique command identifier

50

51

Returns:

52

Decorator function that registers the decorated function as a command handler

53

"""

54

```

55

56

### Thread Execution

57

58

Decorator for executing functions in background threads to avoid blocking the main event loop.

59

60

```python { .api }

61

def thread(self) -> Callable[[F], F]:

62

"""

63

Decorator to execute function in thread pool.

64

65

Returns:

66

Decorator function that wraps the decorated function for thread execution

67

"""

68

```

69

70

### Feature Manager

71

72

Internal feature management system for organizing registered features and commands.

73

74

```python { .api }

75

class FeatureManager:

76

def feature(

77

self,

78

method_name: str,

79

options: Any = None

80

) -> Callable: ...

81

82

def command(self, command_name: str) -> Callable: ...

83

84

def thread(self) -> Callable: ...

85

86

@property

87

def features(self) -> Dict: ...

88

89

@property

90

def commands(self) -> Dict: ...

91

92

@property

93

def feature_options(self) -> Dict: ...

94

```

95

96

## Usage Examples

97

98

### Basic Feature Registration

99

100

```python

101

from pygls.server import LanguageServer

102

from lsprotocol.types import (

103

TEXT_DOCUMENT_COMPLETION,

104

TEXT_DOCUMENT_HOVER,

105

CompletionItem,

106

CompletionList,

107

CompletionParams,

108

Hover,

109

HoverParams,

110

MarkupContent,

111

MarkupKind

112

)

113

114

server = LanguageServer("example-server", "1.0.0")

115

116

# Register completion feature

117

@server.feature(TEXT_DOCUMENT_COMPLETION)

118

def completions(params: CompletionParams):

119

document = server.workspace.get_document(params.text_document.uri)

120

items = [

121

CompletionItem(label="example"),

122

CompletionItem(label="sample")

123

]

124

return CompletionList(is_incomplete=False, items=items)

125

126

# Register hover feature

127

@server.feature(TEXT_DOCUMENT_HOVER)

128

def hover(params: HoverParams):

129

return Hover(

130

contents=MarkupContent(

131

kind=MarkupKind.Markdown,

132

value="**Example hover text**"

133

)

134

)

135

```

136

137

### Feature with Options

138

139

```python

140

from lsprotocol.types import (

141

TEXT_DOCUMENT_COMPLETION,

142

CompletionOptions,

143

CompletionParams

144

)

145

146

# Register completion with trigger characters

147

@server.feature(

148

TEXT_DOCUMENT_COMPLETION,

149

CompletionOptions(trigger_characters=['.', '::'])

150

)

151

def completions_with_triggers(params: CompletionParams):

152

# Handle completion with trigger character context

153

trigger_char = params.context.trigger_character if params.context else None

154

155

if trigger_char == '.':

156

# Provide member completions

157

return CompletionList(items=[

158

CompletionItem(label="method1"),

159

CompletionItem(label="property1")

160

])

161

elif trigger_char == '::':

162

# Provide namespace completions

163

return CompletionList(items=[

164

CompletionItem(label="Class1"),

165

CompletionItem(label="Function1")

166

])

167

168

return CompletionList(items=[])

169

```

170

171

### Custom Commands

172

173

```python

174

from lsprotocol.types import WORKSPACE_EXECUTE_COMMAND

175

176

# Register custom command

177

@server.command("myServer.customCommand")

178

def custom_command(params):

179

# Access command arguments

180

args = params.arguments if params.arguments else []

181

182

# Perform custom logic

183

result = {

184

"message": "Command executed successfully",

185

"arguments": args,

186

"timestamp": time.time()

187

}

188

189

return result

190

191

# Register command that shows configuration

192

@server.command("myServer.showConfiguration")

193

async def show_config(params):

194

# Get configuration from client

195

config = await server.lsp.send_request(

196

"workspace/configuration",

197

{"items": [{"section": "myServer"}]}

198

)

199

200

return {"configuration": config}

201

```

202

203

### Thread Execution

204

205

```python

206

import time

207

208

# Long-running operation in thread

209

@server.command("myServer.longOperation")

210

@server.thread()

211

def long_operation(params):

212

# This runs in a background thread

213

time.sleep(5) # Simulate long-running work

214

return {"result": "Operation completed"}

215

216

# Blocking I/O operation in thread

217

@server.feature(TEXT_DOCUMENT_HOVER)

218

@server.thread()

219

def hover_with_file_io(params: HoverParams):

220

# File I/O that might block

221

with open("some_file.txt", "r") as f:

222

content = f.read()

223

224

return Hover(

225

contents=MarkupContent(

226

kind=MarkupKind.PlainText,

227

value=f"File content: {content[:100]}..."

228

)

229

)

230

```

231

232

### Advanced Feature Registration

233

234

```python

235

from lsprotocol.types import (

236

TEXT_DOCUMENT_SEMANTIC_TOKENS_FULL,

237

SemanticTokensLegend,

238

SemanticTokensOptions,

239

SemanticTokensParams

240

)

241

242

# Complex feature with comprehensive options

243

@server.feature(

244

TEXT_DOCUMENT_SEMANTIC_TOKENS_FULL,

245

SemanticTokensOptions(

246

legend=SemanticTokensLegend(

247

token_types=['keyword', 'string', 'number', 'comment'],

248

token_modifiers=['deprecated', 'readonly']

249

),

250

full=True,

251

range=True

252

)

253

)

254

def semantic_tokens(params: SemanticTokensParams):

255

document = server.workspace.get_document(params.text_document.uri)

256

257

# Parse document and generate semantic tokens

258

tokens = [] # Build semantic token data

259

260

return {"data": tokens}

261

```

262

263

### Error Handling in Features

264

265

```python

266

from pygls.exceptions import FeatureRequestError

267

from lsprotocol.types import TEXT_DOCUMENT_DEFINITION

268

269

@server.feature(TEXT_DOCUMENT_DEFINITION)

270

def goto_definition(params):

271

try:

272

document = server.workspace.get_document(params.text_document.uri)

273

# Definition finding logic here

274

275

if not definition_found:

276

return None # No definition found

277

278

return definition_location

279

280

except Exception as e:

281

# Convert to LSP error

282

raise FeatureRequestError(f"Failed to find definition: {str(e)}")

283

```

284

285

### Dynamic Feature Registration

286

287

```python

288

from pygls.protocol import LanguageServerProtocol

289

290

class CustomProtocol(LanguageServerProtocol):

291

def lsp_initialize(self, params):

292

result = super().lsp_initialize(params)

293

294

# Conditionally register features based on client capabilities

295

if params.capabilities.text_document and params.capabilities.text_document.completion:

296

self.register_dynamic_completion()

297

298

return result

299

300

def register_dynamic_completion(self):

301

# Register completion feature dynamically

302

@self.feature(TEXT_DOCUMENT_COMPLETION)

303

def dynamic_completion(params):

304

return CompletionList(items=[

305

CompletionItem(label="dynamically_registered")

306

])

307

```