11-- ----------------------------------------------------------------------------
22-- Language Server Protocol --
33-- --
4- -- Copyright (C) 2023, AdaCore --
4+ -- Copyright (C) 2023-2025 , AdaCore --
55-- --
66-- This is free software; you can redistribute it and/or modify it under --
77-- terms of the GNU General Public License as published by the Free Soft- --
@@ -178,22 +178,55 @@ package body LSP.Text_Documents is
178178 Old_First_Line : Natural;
179179 New_First_Line : Natural;
180180
181- Old_Lines, New_Lines : VSS.String_Vectors.Virtual_String_Vector;
181+ type Virtual_String_Array is
182+ array (Positive range <>) of VSS.Strings.Virtual_String;
183+
184+ type Virtual_String_Array_Access is access all Virtual_String_Array;
185+
186+ procedure Free is
187+ new Ada.Unchecked_Deallocation
188+ (Virtual_String_Array, Virtual_String_Array_Access);
189+
190+ Old_Lines, New_Lines : Virtual_String_Array_Access;
182191 Old_Length, New_Length : Natural;
183192
184193 begin
185- Old_Lines :=
186- Self.Text.Split_Lines
187- (Terminators => LSP_New_Line_Function_Set,
188- Keep_Terminator => True);
189- New_Lines :=
190- New_Text.Split_Lines
191- (Terminators => LSP_New_Line_Function_Set,
192- Keep_Terminator => True);
194+ -- Populate arrays of old and new content.
195+ --
196+ -- As of 20250720, `Virtual_String_Vector`.`Element` takes a lot of time
197+ -- to construct object to return and to finalize object after check of
198+ -- lines equality. Standard `Ada.Containers.Vectors.Element` works a bit
199+ -- faster, however, use of arrays speed up execution many times.
200+
201+ declare
202+ Aux_Old_Lines : VSS.String_Vectors.Virtual_String_Vector;
203+ Aux_New_Lines : VSS.String_Vectors.Virtual_String_Vector;
204+
205+ begin
206+ Aux_Old_Lines :=
207+ Self.Text.Split_Lines
208+ (Terminators => LSP_New_Line_Function_Set,
209+ Keep_Terminator => True);
210+ Old_Lines := new Virtual_String_Array (1 .. Aux_Old_Lines.Length);
211+
212+ for J in Old_Lines'Range loop
213+ Old_Lines (J) := Aux_Old_Lines (J);
214+ end loop ;
215+
216+ Aux_New_Lines :=
217+ New_Text.Split_Lines
218+ (Terminators => LSP_New_Line_Function_Set,
219+ Keep_Terminator => True);
220+ New_Lines := new Virtual_String_Array (1 .. Aux_New_Lines.Length);
221+
222+ for J in New_Lines'Range loop
223+ New_Lines (J) := Aux_New_Lines (J);
224+ end loop ;
225+ end ;
193226
194227 if Old_Span = Empty_Range then
195228 Old_First_Line := 1 ;
196- Old_Length := Old_Lines. Length;
229+ Old_Length := Old_Lines' Length;
197230
198231 else
199232 Old_First_Line := Natural (Old_Span.start.line + 1 );
@@ -203,7 +236,7 @@ package body LSP.Text_Documents is
203236
204237 if New_Span = Empty_Range then
205238 New_First_Line := 1 ;
206- New_Length := New_Lines. Length;
239+ New_Length := New_Lines' Length;
207240 else
208241 New_First_Line := Natural (New_Span.start.line + 1 );
209242 New_Length :=
@@ -336,8 +369,8 @@ package body LSP.Text_Documents is
336369 then
337370 -- both has lines
338371
339- if New_Lines.Element (New_First_Line + New_Index - 1 ) =
340- Old_Lines.Element (Old_First_Line + Old_Index - 1 )
372+ if New_Lines (New_First_Line + New_Index - 1 ) =
373+ Old_Lines (Old_First_Line + Old_Index - 1 )
341374 then
342375 -- lines are equal, add Text_Edit after current line
343376 -- if any is already prepared
@@ -348,7 +381,7 @@ package body LSP.Text_Documents is
348381 -- the beginning of the next line
349382 Prepare
350383 (Old_Natural,
351- New_Lines.Element (New_First_Line + New_Index - 1 ));
384+ New_Lines (New_First_Line + New_Index - 1 ));
352385 end if ;
353386
354387 -- move lines cursor backward
@@ -376,7 +409,7 @@ package body LSP.Text_Documents is
376409 -- additional line not present in the old document
377410 Prepare
378411 (Old_Natural,
379- New_Lines.Element (New_First_Line + New_Index - 1 ));
412+ New_Lines (New_First_Line + New_Index - 1 ));
380413
381414 New_Index := New_Index - 1 ;
382415 end if ;
@@ -396,7 +429,7 @@ package body LSP.Text_Documents is
396429
397430 Prepare
398431 (Old_Natural,
399- New_Lines.Element (New_First_Line + New_Index - 1 ));
432+ New_Lines (New_First_Line + New_Index - 1 ));
400433
401434 New_Index := New_Index - 1 ;
402435 end loop ;
@@ -416,7 +449,7 @@ package body LSP.Text_Documents is
416449 declare
417450 Element : LSP.Structures.TextEdit := Edit.Last_Element;
418451 Last_Line : constant VSS.Strings.Virtual_String :=
419- Old_Lines (Old_Lines.Length );
452+ Old_Lines (Old_Lines'Last );
420453 Iterator :
421454 constant VSS.Strings.Character_Iterators.Character_Iterator :=
422455 Last_Line.At_Last_Character;
@@ -425,15 +458,21 @@ package body LSP.Text_Documents is
425458 -- Replace the wrong location by the end of the buffer
426459
427460 Element.a_range.an_end :=
428- (line => Old_Lines. Length - 1 ,
461+ (line => Old_Lines' Length - 1 ,
429462 character => Natural (Iterator.Last_UTF16_Offset) + 1 );
430463 Edit.Replace_Element (Edit.Last, Element);
431464 end ;
432465 end if ;
433466
467+ Free (Old_Lines);
468+ Free (New_Lines);
469+
434470 exception
435471 when others =>
436472 Free (LCS);
473+ Free (Old_Lines);
474+ Free (New_Lines);
475+
437476 raise ;
438477 end ;
439478 end Diff ;
0 commit comments