Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add some example servers #440

Merged
merged 8 commits into from
Apr 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions examples/servers/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# Example Servers

| Filename | Works With | Description |
|-|-|-|
| `code_actions.py` | `sums.txt` | Evaluate sums via a code action |
| `code_lens.py` | `sums.txt` | Evaluate sums via a code lens |
| `colors.py` | `colors.txt` | Provides a visual representation of color values and even a color picker in supported clients |
| `goto.py` | `code.txt` | Implements the various "Goto X" requests in the specification |
| `hover.py` | `dates.txt` | Opens a popup showing the date underneath the cursor in multiple formats |
| `inlay_hints.py` | `sums.txt` | Use inlay hints to show the binary representation of numbers in the file |
| `publish_diagnostics.py` | `sums.txt` | Use "push-model" diagnostics to highlight missing or incorrect answers |
| `pull_diagnostics.py` | `sums.txt` | Use "pull-model" diagnostics to highlight missing or incorrect answers |
123 changes: 123 additions & 0 deletions examples/servers/code_lens.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
############################################################################
# Copyright(c) Open Law Library. All rights reserved. #
# See ThirdPartyNotices.txt in the project root for additional notices. #
# #
# Licensed under the Apache License, Version 2.0 (the "License") #
# you may not use this file except in compliance with the License. #
# You may obtain a copy of the License at #
# #
# http: // www.apache.org/licenses/LICENSE-2.0 #
# #
# Unless required by applicable law or agreed to in writing, software #
# distributed under the License is distributed on an "AS IS" BASIS, #
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. #
# See the License for the specific language governing permissions and #
# limitations under the License. #
############################################################################
import logging
import re

from lsprotocol import types

from pygls.server import LanguageServer

ADDITION = re.compile(r"^\s*(\d+)\s*\+\s*(\d+)\s*=(?=\s*$)")
server = LanguageServer("code-lens-server", "v1")


@server.feature(types.TEXT_DOCUMENT_CODE_LENS)
def code_lens(params: types.CodeLensParams):
"""Return a list of code lens to insert into the given document.

This method will read the whole document and identify each sum in the document and
tell the language client to insert a code lens at each location.
"""
items = []
document_uri = params.text_document.uri
document = server.workspace.get_text_document(document_uri)

lines = document.lines
for idx, line in enumerate(lines):
match = ADDITION.match(line)
if match is not None:
range_ = types.Range(
start=types.Position(line=idx, character=0),
end=types.Position(line=idx, character=len(line) - 1),
)

left = int(match.group(1))
right = int(match.group(2))

code_lens = types.CodeLens(
range=range_,
data={
"left": left,
"right": right,
"uri": document_uri,
},
)
items.append(code_lens)

return items


@server.feature(types.CODE_LENS_RESOLVE)
def code_lens_resolve(ls: LanguageServer, item: types.CodeLens):
"""Resolve the ``command`` field of the given code lens.

Using the ``data`` that was attached to the code lens item created in the function
above, this prepares an invocation of the ``evaluateSum`` command below.
"""
logging.info("Resolving code lens: %s", item)

left = item.data["left"]
right = item.data["right"]
uri = item.data["uri"]

args = dict(
uri=uri,
left=left,
right=right,
line=item.range.start.line,
)

item.command = types.Command(
title=f"Evaluate {left} + {right}",
command="codeLens.evaluateSum",
arguments=[args],
)
return item


@server.command("codeLens.evaluateSum")
def evaluate_sum(ls: LanguageServer, args):
logging.info("arguments: %s", args)

arguments = args[0]
document = ls.workspace.get_text_document(arguments["uri"])
line = document.lines[arguments["line"]]

# Compute the edit that will update the document with the result.
answer = arguments["left"] + arguments["right"]
edit = types.TextDocumentEdit(
text_document=types.OptionalVersionedTextDocumentIdentifier(
uri=arguments["uri"], version=document.version
),
edits=[
types.TextEdit(
new_text=f"{line.strip()} {answer}\n",
range=types.Range(
start=types.Position(line=arguments["line"], character=0),
end=types.Position(line=arguments["line"] + 1, character=0),
),
)
],
)

# Apply the edit.
ls.apply_edit(types.WorkspaceEdit(document_changes=[edit]))


if __name__ == "__main__":
logging.basicConfig(level=logging.INFO, format="%(message)s")
server.start_io()
85 changes: 85 additions & 0 deletions examples/servers/colors.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
############################################################################
# Copyright(c) Open Law Library. All rights reserved. #
# See ThirdPartyNotices.txt in the project root for additional notices. #
# #
# Licensed under the Apache License, Version 2.0 (the "License") #
# you may not use this file except in compliance with the License. #
# You may obtain a copy of the License at #
# #
# http: // www.apache.org/licenses/LICENSE-2.0 #
# #
# Unless required by applicable law or agreed to in writing, software #
# distributed under the License is distributed on an "AS IS" BASIS, #
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. #
# See the License for the specific language governing permissions and #
# limitations under the License. #
############################################################################
import logging
import re

from lsprotocol import types

from pygls.server import LanguageServer

COLOR = re.compile(r"""\#([a-fA-F0-9]{6}|[a-fA-F0-9]{3})(?!\w)""")
server = LanguageServer("color-server", "v1")


@server.feature(
types.TEXT_DOCUMENT_DOCUMENT_COLOR,
)
def document_color(params: types.CodeActionParams):
"""Return a list of colors declared in the document."""
items = []
document_uri = params.text_document.uri
document = server.workspace.get_text_document(document_uri)

for linum, line in enumerate(document.lines):
for match in COLOR.finditer(line.strip()):
start_char, end_char = match.span()

# Is this a short form color?
if (end_char - start_char) == 4:
color = "".join(c * 2 for c in match.group(1))
value = int(color, 16)
else:
value = int(match.group(1), 16)

# Split the single color value into a value for each color channel.
blue = (value & 0xFF) / 0xFF
green = (value & (0xFF << 8)) / (0xFF << 8)
red = (value & (0xFF << 16)) / (0xFF << 16)

items.append(
types.ColorInformation(
color=types.Color(red=red, green=green, blue=blue, alpha=1.0),
range=types.Range(
start=types.Position(line=linum, character=start_char),
end=types.Position(line=linum, character=end_char),
),
)
)

return items


@server.feature(
types.TEXT_DOCUMENT_COLOR_PRESENTATION,
)
def color_presentation(params: types.ColorPresentationParams):
"""Given a color, instruct the client how to insert the representation of that
color into the document"""
color = params.color

b = int(color.blue * 255)
g = int(color.green * 255)
r = int(color.red * 255)

# Combine each color channel into a single value
value = (r << 16) | (g << 8) | b
return [types.ColorPresentation(label=f"#{value:0{6}x}")]


if __name__ == "__main__":
logging.basicConfig(level=logging.INFO, format="%(message)s")
server.start_io()
Loading
Loading