1010from typing import Any , Callable , Literal , Sequence , cast
1111
1212import sublime
13+ from LSP .plugin .core .protocol import Position as LspPosition
14+ from LSP .plugin .core .protocol import Range as LspRange
1315from LSP .plugin .core .url import filename_to_uri
1416from more_itertools import duplicates_everseen , first_true
1517from wcmatch import glob
2224 CopilotPayloadCompletion ,
2325 CopilotPayloadPanelSolution ,
2426 CopilotRequestConversationTurn ,
27+ CopilotRequestConversationTurnReference ,
2528 CopilotUserDefinedPromptTemplates ,
2629)
2730from .utils import (
@@ -166,14 +169,34 @@ def trigger(self, view: sublime.View) -> bool:
166169 return False
167170
168171
172+ def st_point_to_lsp_position (point : int , view : sublime .View ) -> LspPosition :
173+ row , col = view .rowcol_utf16 (point )
174+ return {"line" : row , "character" : col }
175+
176+
177+ def lsp_position_to_st_point (position : LspPosition , view : sublime .View ) -> int :
178+ return view .text_point_utf16 (position ["line" ], position ["character" ])
179+
180+
181+ def st_region_to_lsp_range (region : sublime .Region , view : sublime .View ) -> LspRange :
182+ return {
183+ "start" : st_point_to_lsp_position (region .begin (), view ),
184+ "end" : st_point_to_lsp_position (region .end (), view ),
185+ }
186+
187+
188+ def lsp_range_to_st_region (range_ : LspRange , view : sublime .View ) -> sublime .Region :
189+ return sublime .Region (
190+ lsp_position_to_st_point (range_ ["start" ], view ),
191+ lsp_position_to_st_point (range_ ["end" ], view ),
192+ )
193+
194+
169195def prepare_completion_request_doc (view : sublime .View , max_selections : int = 1 ) -> CopilotDocType | None :
170- if not view :
171- return None
172- if len (sel := view .sel ()) > max_selections or len (sel ) == 0 :
196+ if not view or len (sel := view .sel ()) > max_selections or len (sel ) == 0 :
173197 return None
174198
175199 file_path = view .file_name () or f"buffer:{ view .buffer ().id ()} "
176- row , col = view .rowcol_utf16 (sel [0 ].begin ())
177200 return {
178201 "source" : view .substr (sublime .Region (0 , view .size ())),
179202 "tabSize" : cast (int , view .settings ().get ("tab_size" )),
@@ -183,7 +206,7 @@ def prepare_completion_request_doc(view: sublime.View, max_selections: int = 1)
183206 "uri" : file_path if file_path .startswith ("buffer:" ) else filename_to_uri (file_path ),
184207 "relativePath" : get_project_relative_path (file_path ),
185208 "languageId" : get_view_language_id (view ),
186- "position" : { "line" : row , "character" : col } ,
209+ "position" : st_point_to_lsp_position ( sel [ 0 ]. begin (), view ) ,
187210 # Buffer Version. Generally this is handled by LSP, but we need to handle it here
188211 # Will need to test getting the version from LSP
189212 "version" : view .change_count (),
@@ -199,43 +222,32 @@ def prepare_conversation_turn_request(
199222) -> CopilotRequestConversationTurn | None :
200223 if not (doc := prepare_completion_request_doc (view , max_selections = 5 )):
201224 return None
202- turn : CopilotRequestConversationTurn = {
203- "conversationId" : conversation_id ,
204- "message" : message ,
205- "workDoneToken" : f"copilot_chat://{ window_id } " ,
206- "doc" : doc ,
207- "computeSuggestions" : True ,
208- "references" : [],
209- "source" : source ,
210- }
211-
212- visible_region = view .visible_region ()
213- visible_start = view .rowcol_utf16 (visible_region .begin ())
214- visible_end = view .rowcol_utf16 (visible_region .end ())
215225
216226 # References can technicaly be across multiple files
217227 # TODO: Support references across multiple files
228+ references : list [CopilotRequestConversationTurnReference ] = []
229+ visible_range = st_region_to_lsp_range (view .visible_region (), view )
218230 for selection in view .sel ():
219- if selection .empty () or view .substr (selection ).strip () == "" :
231+ if selection .empty () or view .substr (selection ).isspace () :
220232 continue
221- file_path = view .file_name () or f"buffer:{ view .buffer ().id ()} "
222- selection_start = view .rowcol_utf16 (selection .begin ())
223- selection_end = view .rowcol_utf16 (selection .end ())
224- turn ["references" ].append ({
233+ references .append ({
225234 "type" : "file" ,
226235 "status" : "included" ,
227- "uri" : file_path if file_path . startswith ( "buffer:" ) else filename_to_uri ( file_path ) ,
236+ "uri" : filename_to_uri ( file_path ) if ( file_path := view . file_name ()) else f"buffer: { view . buffer (). id () } " ,
228237 "range" : doc ["position" ],
229- "visibleRange" : {
230- "start" : {"line" : visible_start [0 ], "character" : visible_start [1 ]},
231- "end" : {"line" : visible_end [0 ], "character" : visible_end [1 ]},
232- },
233- "selection" : {
234- "start" : {"line" : selection_start [0 ], "character" : selection_start [1 ]},
235- "end" : {"line" : selection_end [0 ], "character" : selection_end [1 ]},
236- },
238+ "visibleRange" : visible_range ,
239+ "selection" : st_region_to_lsp_range (selection , view ),
237240 })
238- return turn
241+
242+ return {
243+ "conversationId" : conversation_id ,
244+ "message" : message ,
245+ "workDoneToken" : f"copilot_chat://{ window_id } " ,
246+ "doc" : doc ,
247+ "computeSuggestions" : True ,
248+ "references" : references ,
249+ "source" : source ,
250+ }
239251
240252
241253def preprocess_message_for_html (message : str ) -> str :
@@ -305,33 +317,14 @@ def preprocess_completions(view: sublime.View, completions: list[CopilotPayloadC
305317
306318 # inject extra information for convenience
307319 for completion in completions :
308- completion ["point" ] = view .text_point_utf16 (
309- completion ["position" ]["line" ],
310- completion ["position" ]["character" ],
311- )
312- _generate_completion_region (view , completion )
320+ completion ["point" ] = lsp_position_to_st_point (completion ["position" ], view )
321+ completion ["region" ] = lsp_range_to_st_region (completion ["range" ], view ).to_tuple ()
313322
314323
315324def preprocess_panel_completions (view : sublime .View , completions : Sequence [CopilotPayloadPanelSolution ]) -> None :
316325 """Preprocess the `completions` from "getCompletionsCycling" request."""
317326 for completion in completions :
318- _generate_completion_region (view , completion )
319-
320-
321- def _generate_completion_region (
322- view : sublime .View ,
323- completion : CopilotPayloadCompletion | CopilotPayloadPanelSolution ,
324- ) -> None :
325- completion ["region" ] = (
326- view .text_point_utf16 (
327- completion ["range" ]["start" ]["line" ],
328- completion ["range" ]["start" ]["character" ],
329- ),
330- view .text_point_utf16 (
331- completion ["range" ]["end" ]["line" ],
332- completion ["range" ]["end" ]["character" ],
333- ),
334- )
327+ completion ["region" ] = lsp_range_to_st_region (completion ["range" ], view ).to_tuple ()
335328
336329
337330def is_debug_mode () -> bool :
0 commit comments