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

utilities.mddocs/

0

# Utilities and Helpers

1

2

URI handling, position encoding, exception management, and other utility functions for language server development with comprehensive support for cross-platform operations and error handling.

3

4

## Capabilities

5

6

### Position Encoding Utilities

7

8

Comprehensive position encoding system supporting different character encoding methods with backward compatibility for deprecated functions.

9

10

```python { .api }

11

class PositionCodec:

12

"""

13

Position encoding codec for character unit conversion.

14

15

Handles conversion between different character encoding methods

16

(UTF-8, UTF-16) for LSP position calculations.

17

"""

18

19

@classmethod

20

def create_encoding(cls, encoding: str = "utf-16") -> 'PositionCodec':

21

"""

22

Create codec for specific encoding.

23

24

Parameters:

25

- encoding: str - Encoding type ('utf-8', 'utf-16')

26

27

Returns:

28

PositionCodec instance

29

"""

30

31

def utf16_unit_offset(self, chars: str) -> int:

32

"""

33

Calculate UTF-16 unit offset.

34

35

Parameters:

36

- chars: str - Character string

37

38

Returns:

39

int - UTF-16 unit offset

40

"""

41

42

def client_num_units(self, chars: str) -> int:

43

"""

44

Get number of client character units.

45

46

Parameters:

47

- chars: str - Character string

48

49

Returns:

50

int - Number of client units based on encoding

51

"""

52

53

# Deprecated utility functions (maintained for backward compatibility)

54

def utf16_unit_offset(chars: str) -> int:

55

"""

56

DEPRECATED: Use PositionCodec.utf16_unit_offset instead.

57

Calculate UTF-16 unit offset for character string.

58

"""

59

60

def utf16_num_units(chars: str) -> int:

61

"""

62

DEPRECATED: Use PositionCodec.client_num_units instead.

63

Get number of UTF-16 units in character string.

64

"""

65

66

def position_from_utf16(lines: List[str], position: Position) -> Position:

67

"""

68

DEPRECATED: Use PositionCodec.position_from_client_units instead.

69

Convert position from UTF-16 units to server units.

70

"""

71

72

def position_to_utf16(lines: List[str], position: Position) -> Position:

73

"""

74

DEPRECATED: Use PositionCodec.position_to_client_units instead.

75

Convert position from server units to UTF-16 units.

76

"""

77

78

def range_from_utf16(lines: List[str], range: Range) -> Range:

79

"""

80

DEPRECATED: Use PositionCodec.range_from_client_units instead.

81

Convert range from UTF-16 units to server units.

82

"""

83

84

def range_to_utf16(lines: List[str], range: Range) -> Range:

85

"""

86

DEPRECATED: Use PositionCodec.range_to_client_units instead.

87

Convert range from server units to UTF-16 units.

88

"""

89

```

90

91

### Constants and Configuration

92

93

Configuration constants and attribute definitions for internal pygls operations and feature management.

94

95

```python { .api }

96

# Constants from pygls.constants module

97

98

# Dynamically assigned attributes for feature management

99

ATTR_EXECUTE_IN_THREAD: str = "execute_in_thread"

100

ATTR_COMMAND_TYPE: str = "command"

101

ATTR_FEATURE_TYPE: str = "feature"

102

ATTR_REGISTERED_NAME: str = "reg_name"

103

ATTR_REGISTERED_TYPE: str = "reg_type"

104

105

# Parameters for server operations

106

PARAM_LS: str = "ls"

107

```

108

109

### Platform Detection

110

111

Platform and environment detection utilities for cross-platform compatibility and runtime environment adaptation.

112

113

```python { .api }

114

# Platform detection from pygls module

115

116

IS_WIN: bool = ...

117

"""True if running on Windows platform."""

118

119

IS_PYODIDE: bool = ...

120

"""True if running in Pyodide environment (browser Python)."""

121

```

122

123

### LSP Type Utilities

124

125

Utility functions for working with LSP method types, parameter validation, and capability management.

126

127

```python { .api }

128

# Type utilities from pygls.lsp module

129

130

def get_method_params_type(

131

method_name: str,

132

lsp_methods_map: dict = METHOD_TO_TYPES

133

) -> Optional[Type]:

134

"""

135

Get parameter type for LSP method.

136

137

Parameters:

138

- method_name: str - LSP method name

139

- lsp_methods_map: dict - Method to types mapping

140

141

Returns:

142

Type for method parameters or None

143

144

Raises:

145

MethodTypeNotRegisteredError if method not found

146

"""

147

148

def get_method_return_type(

149

method_name: str,

150

lsp_methods_map: dict = METHOD_TO_TYPES

151

) -> Optional[Type]:

152

"""

153

Get return type for LSP method.

154

155

Parameters:

156

- method_name: str - LSP method name

157

- lsp_methods_map: dict - Method to types mapping

158

159

Returns:

160

Type for method return value or None

161

162

Raises:

163

MethodTypeNotRegisteredError if method not found

164

"""

165

166

def get_method_options_type(

167

method_name: str,

168

lsp_options_map: dict = METHOD_TO_OPTIONS,

169

lsp_methods_map: dict = METHOD_TO_TYPES

170

) -> Optional[Type]:

171

"""

172

Get options type for LSP method capabilities.

173

174

Parameters:

175

- method_name: str - LSP method name

176

- lsp_options_map: dict - Method to options mapping

177

- lsp_methods_map: dict - Method to types mapping

178

179

Returns:

180

Type for method options or None

181

182

Raises:

183

MethodTypeNotRegisteredError if method not found

184

"""

185

186

def get_method_registration_options_type(

187

method_name: str,

188

lsp_methods_map: dict = METHOD_TO_TYPES

189

) -> Optional[Type]:

190

"""

191

Get registration options type for LSP method.

192

193

Parameters:

194

- method_name: str - LSP method name

195

- lsp_methods_map: dict - Method to types mapping

196

197

Returns:

198

Type for method registration options or None

199

200

Raises:

201

MethodTypeNotRegisteredError if method not found

202

"""

203

204

def is_instance(cv: Converter, obj: Any, type_cls: Type) -> bool:

205

"""

206

Check if object is instance of type using cattrs converter.

207

208

Parameters:

209

- cv: Converter - cattrs converter instance

210

- obj: Any - Object to check

211

- type_cls: Type - Type to check against

212

213

Returns:

214

bool - True if object matches type

215

"""

216

```

217

218

## Usage Examples

219

220

### Position Encoding

221

222

```python

223

from pygls.workspace import PositionCodec

224

from lsprotocol.types import Position, Range

225

226

# Create position codec

227

codec = PositionCodec.create_encoding("utf-16")

228

229

# Document with Unicode characters

230

lines = [

231

"def hello():",

232

" print('Hello 世界')", # Contains non-ASCII characters

233

" return True"

234

]

235

236

# Position at the '世' character

237

client_position = Position(line=1, character=12)

238

239

# Convert from client units to server units

240

server_position = codec.position_from_client_units(lines, client_position)

241

print(f"Client pos: {client_position}")

242

print(f"Server pos: {server_position}")

243

244

# Convert back to client units

245

converted_back = codec.position_to_client_units(lines, server_position)

246

print(f"Converted back: {converted_back}")

247

248

# Handle ranges

249

client_range = Range(

250

start=Position(line=1, character=10),

251

end=Position(line=1, character=15)

252

)

253

254

server_range = codec.range_from_client_units(lines, client_range)

255

print(f"Client range: {client_range}")

256

print(f"Server range: {server_range}")

257

258

# Calculate character units

259

text = "Hello 世界"

260

utf16_units = codec.client_num_units(text)

261

print(f"UTF-16 units for '{text}': {utf16_units}")

262

```

263

264

### Exception Handling

265

266

```python

267

from pygls.exceptions import (

268

JsonRpcException,

269

JsonRpcMethodNotFound,

270

FeatureRequestError,

271

PyglsError

272

)

273

274

@server.feature(TEXT_DOCUMENT_HOVER)

275

def hover_with_error_handling(params):

276

try:

277

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

278

279

# Simulate potential errors

280

if not document.source.strip():

281

raise FeatureRequestError("Document is empty")

282

283

# Generate hover content

284

position = params.position

285

if position.line >= len(document.lines):

286

raise JsonRpcException.invalid_params()

287

288

word = document.word_at_position(position)

289

if not word:

290

return None # No hover content

291

292

return Hover(contents=f"Hover for: {word}")

293

294

except KeyError:

295

# Document not found

296

raise JsonRpcMethodNotFound()

297

298

except FeatureRequestError:

299

# Re-raise feature errors

300

raise

301

302

except Exception as e:

303

# Convert unexpected errors

304

raise JsonRpcException.internal_error(str(e))

305

306

# Custom error handling

307

class CustomServerError(PyglsError):

308

def __init__(self, message: str, error_code: int = -32000):

309

super().__init__(message)

310

self.error_code = error_code

311

312

@server.command("myServer.riskyOperation")

313

def risky_operation(params):

314

try:

315

# Risky operation here

316

result = perform_risky_operation(params)

317

return result

318

319

except CustomServerError as e:

320

# Convert to JSON-RPC error

321

raise JsonRpcServerError(str(e), e.error_code)

322

323

except FileNotFoundError:

324

raise JsonRpcException.invalid_params("Required file not found")

325

326

except PermissionError:

327

raise JsonRpcServerError("Insufficient permissions", -32001)

328

```

329

330

### Type Validation and Method Utilities

331

332

```python

333

from pygls.lsp import (

334

get_method_params_type,

335

get_method_return_type,

336

get_method_options_type

337

)

338

from lsprotocol.types import TEXT_DOCUMENT_COMPLETION

339

340

# Get type information for LSP methods

341

params_type = get_method_params_type(TEXT_DOCUMENT_COMPLETION)

342

print(f"Completion params type: {params_type}")

343

344

return_type = get_method_return_type(TEXT_DOCUMENT_COMPLETION)

345

print(f"Completion return type: {return_type}")

346

347

options_type = get_method_options_type(TEXT_DOCUMENT_COMPLETION)

348

print(f"Completion options type: {options_type}")

349

350

# Validate parameters using type information

351

def validate_completion_params(params):

352

expected_type = get_method_params_type(TEXT_DOCUMENT_COMPLETION)

353

354

# Use cattrs to validate structure

355

try:

356

converter = default_converter()

357

converter.structure(params, expected_type)

358

return True

359

except Exception as e:

360

print(f"Invalid parameters: {e}")

361

return False

362

363

# Dynamic feature registration with type checking

364

def register_feature_with_validation(server, method_name, handler):

365

try:

366

# Check if method type is registered

367

params_type = get_method_params_type(method_name)

368

return_type = get_method_return_type(method_name)

369

370

print(f"Registering {method_name}")

371

print(f" Params: {params_type}")

372

print(f" Returns: {return_type}")

373

374

# Register the feature

375

server.feature(method_name)(handler)

376

377

except MethodTypeNotRegisteredError:

378

print(f"Unknown method: {method_name}")

379

```

380

381

### Platform-Specific Operations

382

383

```python

384

from pygls import IS_WIN, IS_PYODIDE

385

import os

386

387

def get_platform_config():

388

"""Get platform-specific configuration."""

389

config = {

390

"line_ending": "\r\n" if IS_WIN else "\n",

391

"path_separator": "\\" if IS_WIN else "/",

392

"supports_symlinks": not IS_WIN,

393

"is_browser": IS_PYODIDE

394

}

395

396

if IS_PYODIDE:

397

# Browser environment limitations

398

config.update({

399

"supports_file_system": False,

400

"supports_threads": False,

401

"max_file_size": 1024 * 1024 # 1MB limit

402

})

403

404

return config

405

406

@server.command("myServer.getSystemInfo")

407

def get_system_info(params):

408

"""Return system information."""

409

config = get_platform_config()

410

411

return {

412

"platform": "windows" if IS_WIN else "unix",

413

"environment": "pyodide" if IS_PYODIDE else "native",

414

"python_version": sys.version,

415

"config": config

416

}

417

418

# Platform-specific file operations

419

def safe_file_operation(file_path: str, operation: str):

420

"""Perform file operation with platform considerations."""

421

422

if IS_PYODIDE:

423

return {"error": "File operations not supported in browser"}

424

425

try:

426

if operation == "read":

427

with open(file_path, 'r', encoding='utf-8') as f:

428

content = f.read()

429

return {"content": content}

430

431

elif operation == "exists":

432

exists = os.path.exists(file_path)

433

return {"exists": exists}

434

435

except PermissionError:

436

return {"error": "Permission denied"}

437

except FileNotFoundError:

438

return {"error": "File not found"}

439

except Exception as e:

440

return {"error": str(e)}

441

```