Skip to content

Commit d17e79c

Browse files
committed
feat: Improved Handling of UTF-16 encoded multibyte characters, e.g. emojis are now handled correctly
1 parent a87ba80 commit d17e79c

File tree

3,157 files changed

+83641
-76982
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

3,157 files changed

+83641
-76982
lines changed

packages/language_server/src/robotcode/language_server/common/parts/code_action.py

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -75,10 +75,16 @@ async def _text_document_code_action(
7575
if document is None:
7676
return None
7777

78+
for c in context.diagnostics:
79+
c.range = document.range_from_utf16(c.range)
80+
if c.related_information is not None:
81+
for r in c.related_information:
82+
r.location.range = document.range_from_utf16(r.location.range)
83+
7884
for result in await self.collect(
7985
self,
8086
document,
81-
range,
87+
document.range_from_utf16(range),
8288
context,
8389
callback_filter=language_id_filter(document),
8490
):
@@ -89,10 +95,10 @@ async def _text_document_code_action(
8995
if result is not None:
9096
results.extend(result)
9197

92-
if len(results) > 0:
93-
return results
98+
if not results:
99+
return None
94100

95-
return None
101+
return results
96102

97103
@rpc_method(name="textDocument/codeAction/resolve", param_type=CodeAction)
98104
@threaded()

packages/language_server/src/robotcode/language_server/common/parts/code_lens.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -61,10 +61,13 @@ async def _text_document_code_lens(
6161
if result is not None:
6262
results.extend(result)
6363

64-
if len(results) > 0:
65-
return results
64+
if not results:
65+
return None
66+
67+
for result in results:
68+
result.range = document.range_to_utf16(result.range)
6669

67-
return None
70+
return results
6871

6972
@rpc_method(name="codeLens/resolve", param_type=CodeLens)
7073
@threaded()

packages/language_server/src/robotcode/language_server/common/parts/completion.py

Lines changed: 40 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,11 @@
1515
CompletionList,
1616
CompletionOptions,
1717
CompletionParams,
18+
InsertReplaceEdit,
1819
Position,
1920
ServerCapabilities,
2021
TextDocumentIdentifier,
22+
TextEdit,
2123
)
2224
from robotcode.language_server.common.parts.protocol_part import LanguageServerProtocolPart
2325
from robotcode.language_server.common.text_document import TextDocument
@@ -89,7 +91,7 @@ async def _text_document_completion(
8991
for result in await self.collect(
9092
self,
9193
document,
92-
position,
94+
document.position_from_utf16(position),
9395
context,
9496
callback_filter=language_id_filter(document),
9597
):
@@ -100,23 +102,41 @@ async def _text_document_completion(
100102
if result is not None:
101103
results.append(result)
102104

103-
if len(results) > 0:
104-
if any(e for e in results if isinstance(e, CompletionList)):
105-
result = CompletionList(
106-
is_incomplete=any(e for e in results if isinstance(e, CompletionList) and e.is_incomplete),
107-
items=list(chain(*[r.items if isinstance(r, CompletionList) else r for r in results])),
108-
)
109-
if len(result.items) == 0:
110-
return None
111-
return result
105+
if not results:
106+
return None
112107

113-
result = list(chain(*[k for k in results if isinstance(k, list)]))
114-
if len(result) == 0:
108+
for result in results:
109+
if isinstance(result, CompletionList):
110+
for item in result.items:
111+
if item.text_edit is not None:
112+
self.update_completion_item_to_utf16(document, item)
113+
114+
elif isinstance(result, list):
115+
for item in result:
116+
if item.text_edit is not None:
117+
self.update_completion_item_to_utf16(document, item)
118+
119+
if any(e for e in results if isinstance(e, CompletionList)):
120+
result = CompletionList(
121+
is_incomplete=any(e for e in results if isinstance(e, CompletionList) and e.is_incomplete),
122+
items=list(chain(*[r.items if isinstance(r, CompletionList) else r for r in results])),
123+
)
124+
if len(result.items) == 0:
115125
return None
116-
117126
return result
118127

119-
return None
128+
result = list(chain(*[k for k in results if isinstance(k, list)]))
129+
if not result:
130+
return None
131+
132+
return result
133+
134+
def update_completion_item_to_utf16(self, document: TextDocument, item: CompletionItem) -> None:
135+
if isinstance(item.text_edit, TextEdit):
136+
item.text_edit.range = document.range_to_utf16(item.text_edit.range)
137+
elif isinstance(item.text_edit, InsertReplaceEdit):
138+
item.text_edit.insert = document.range_to_utf16(item.text_edit.insert)
139+
item.text_edit.replace = document.range_to_utf16(item.text_edit.replace)
120140

121141
@rpc_method(name="completionItem/resolve", param_type=CompletionItem)
122142
@threaded()
@@ -136,10 +156,11 @@ async def _completion_item_resolve(
136156
if result is not None:
137157
results.append(result)
138158

139-
if len(results) > 0:
140-
if len(results) > 1:
141-
self._logger.warning("More then one resolve result. Use the last one.")
159+
if not results:
160+
return params
142161

143-
return results[-1]
162+
if len(results) > 1:
163+
self._logger.warning("More then one resolve result. Use the last one.")
164+
result = results[-1]
144165

145-
return params
166+
return result

packages/language_server/src/robotcode/language_server/common/parts/declaration.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,9 +79,25 @@ async def _text_document_declaration(
7979
locations.append(e)
8080
elif isinstance(e, LocationLink):
8181
location_links.append(e)
82+
8283
if len(locations) == 0 and len(location_links) == 0:
8384
return None
8485

86+
if locations:
87+
for location in locations:
88+
doc = await self.parent.documents.get(location.uri)
89+
if doc is not None:
90+
location.range = doc.range_to_utf16(location.range)
91+
92+
if location_links:
93+
for location_link in location_links:
94+
doc = await self.parent.documents.get(location_link.target_uri)
95+
if doc is not None:
96+
location_link.target_range = doc.range_to_utf16(location_link.target_range)
97+
location_link.target_selection_range = doc.range_to_utf16(location_link.target_selection_range)
98+
if location_link.origin_selection_range is not None:
99+
location_link.origin_selection_range = document.range_to_utf16(location_link.origin_selection_range)
100+
85101
if len(locations) > 0 and len(location_links) == 0:
86102
if len(locations) == 1:
87103
return locations[0]

packages/language_server/src/robotcode/language_server/common/parts/definition.py

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,9 @@ async def _text_document_definition(
5959
if document is None:
6060
return None
6161

62-
for result in await self.collect(self, document, position, callback_filter=language_id_filter(document)):
62+
for result in await self.collect(
63+
self, document, document.position_from_utf16(position), callback_filter=language_id_filter(document)
64+
):
6365
if isinstance(result, BaseException):
6466
if not isinstance(result, CancelledError):
6567
self._logger.exception(result, exc_info=result)
@@ -73,9 +75,25 @@ async def _text_document_definition(
7375
locations.append(e)
7476
elif isinstance(e, LocationLink):
7577
location_links.append(e)
78+
7679
if len(locations) == 0 and len(location_links) == 0:
7780
return None
7881

82+
if locations:
83+
for location in locations:
84+
doc = await self.parent.documents.get(location.uri)
85+
if doc is not None:
86+
location.range = doc.range_to_utf16(location.range)
87+
88+
if location_links:
89+
for location_link in location_links:
90+
doc = await self.parent.documents.get(location_link.target_uri)
91+
if doc is not None:
92+
location_link.target_range = doc.range_to_utf16(location_link.target_range)
93+
location_link.target_selection_range = doc.range_to_utf16(location_link.target_selection_range)
94+
if location_link.origin_selection_range is not None:
95+
location_link.origin_selection_range = document.range_to_utf16(location_link.origin_selection_range)
96+
7997
if len(locations) > 0 and len(location_links) == 0:
8098
if len(locations) == 1:
8199
return locations[0]

packages/language_server/src/robotcode/language_server/common/parts/diagnostics.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -457,6 +457,16 @@ async def _get_diagnostics_for_document(
457457
result = cast(DiagnosticsResult, result_any)
458458

459459
data.id = str(uuid.uuid4())
460+
461+
if result.diagnostics is not None:
462+
for d in result.diagnostics:
463+
d.range = document.range_to_utf16(d.range)
464+
465+
for r in d.related_information or []:
466+
doc = await self.parent.documents.get(r.location.uri)
467+
if doc is not None:
468+
r.location.range = doc.range_to_utf16(r.location.range)
469+
460470
data.entries[result.key] = result.diagnostics
461471
if result.diagnostics is not None:
462472
collected_keys.append(result.key)

packages/language_server/src/robotcode/language_server/common/parts/document_highlight.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,9 @@ async def _text_document_document_highlight(
5454
if document is None:
5555
return None
5656

57-
for result in await self.collect(self, document, position, callback_filter=language_id_filter(document)):
57+
for result in await self.collect(
58+
self, document, document.position_from_utf16(position), callback_filter=language_id_filter(document)
59+
):
5860
if isinstance(result, BaseException):
5961
if not isinstance(result, CancelledError):
6062
self._logger.exception(result, exc_info=result)
@@ -65,4 +67,7 @@ async def _text_document_document_highlight(
6567
if len(highlights) == 0:
6668
return None
6769

70+
for highlight in highlights:
71+
highlight.range = document.range_to_utf16(highlight.range)
72+
6873
return highlights

packages/language_server/src/robotcode/language_server/common/parts/document_symbols.py

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ async def _text_document_symbol(
104104
symbol_informations: List[SymbolInformation] = []
105105

106106
document = await self.parent.documents.get(text_document.uri)
107-
if not document:
107+
if document is None:
108108
return None
109109

110110
for result in await self.collect(self, document, callback_filter=language_id_filter(document)):
@@ -121,6 +121,22 @@ async def _text_document_symbol(
121121
self._logger.warning(
122122
"Result contains DocumentSymbol and SymbolInformation results, result is skipped."
123123
)
124+
if document_symbols:
125+
126+
def traverse(symbol: DocumentSymbol, doc: TextDocument) -> None:
127+
symbol.range = doc.range_to_utf16(symbol.range)
128+
symbol.selection_range = doc.range_to_utf16(symbol.selection_range)
129+
for child in symbol.children or []:
130+
traverse(child, doc)
131+
132+
for symbol in document_symbols:
133+
traverse(symbol, document)
134+
135+
if symbol_informations:
136+
for symbol_information in symbol_informations:
137+
doc = await self.parent.documents.get(symbol_information.location.uri)
138+
if doc is not None:
139+
symbol_information.location.range = doc.range_to_utf16(symbol_information.location.range)
124140

125141
if document_symbols and symbol_informations:
126142
self._logger.warning(

packages/language_server/src/robotcode/language_server/common/parts/folding_range.py

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
from robotcode.language_server.common.lsp_types import (
1212
FoldingRange,
1313
FoldingRangeParams,
14+
Position,
1415
ServerCapabilities,
1516
TextDocumentIdentifier,
1617
)
@@ -53,6 +54,17 @@ async def _text_document_folding_range(
5354
if result is not None:
5455
results += result
5556

56-
if len(results) == 0:
57+
if not results:
5758
return None
59+
60+
for result in results:
61+
if result.start_character is not None:
62+
result.start_character = document.position_to_utf16(
63+
Position(result.start_line, result.start_character)
64+
).character
65+
if result.end_character is not None:
66+
result.end_character = document.position_to_utf16(
67+
Position(result.end_line, result.end_character)
68+
).character
69+
5870
return results

packages/language_server/src/robotcode/language_server/common/parts/hover.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ async def _text_document_hover(
5959
for result in await self.collect(
6060
self,
6161
document,
62-
position,
62+
document.position_from_utf16(position),
6363
callback_filter=language_id_filter(document),
6464
):
6565
if isinstance(result, BaseException):
@@ -69,8 +69,12 @@ async def _text_document_hover(
6969
if result is not None:
7070
results.append(result)
7171

72+
for result in results:
73+
if result.range is not None:
74+
result.range = document.range_to_utf16(result.range)
75+
7276
if len(results) > 0 and results[-1].contents:
73-
# TODO: can we combine hover results?
77+
# TODO: how can we combine hover results?
7478

7579
return results[-1]
7680

0 commit comments

Comments
 (0)