Skip to content

Commit f42d33f

Browse files
committed
Avoid flood of warnings when trying to edit "untitled..." URL
1 parent 6fde4cd commit f42d33f

File tree

4 files changed

+83
-34
lines changed

4 files changed

+83
-34
lines changed

server/udocumentsymbolsupport.pas

Lines changed: 14 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,8 @@ implementation
5757

5858
uses ulogvscode, CodeToolManager, CodeCache, CodeTree, PascalParserTool;
5959

60+
{ Get filename from "textDocument/documentSymbol" request.
61+
Returns empty string if not possible (invalid, unrecognized URI). }
6062
function ParseDocumentSymbolRequest(Reader: TJsonReader): String;
6163
var
6264
Key, Uri: String;
@@ -78,22 +80,6 @@ function ParseDocumentSymbolRequest(Reader: TJsonReader): String;
7880
Result := URIToFileNameEasy(Uri);
7981
end;
8082

81-
{ Return null response, that signals "no error, but also no result". }
82-
procedure SendNullResponse(const Rpc: TRpcPeer; const Request: TRpcRequest);
83-
var
84-
Response: TRpcResponse;
85-
Writer: TJsonWriter;
86-
begin
87-
Response := TRpcResponse.Create(Request.Id);
88-
try
89-
Writer := Response.Writer;
90-
Writer.Null;
91-
Rpc.Send(Response);
92-
finally
93-
FreeAndNil(Response);
94-
end;
95-
end;
96-
9783
{ Responses for textDocument/documentSymbol method
9884
Docs: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_documentSymbol }
9985
procedure TextDocument_DocumentSymbol(const Rpc: TRpcPeer; const Request: TRpcRequest);
@@ -113,14 +99,25 @@ procedure TextDocument_DocumentSymbol(const Rpc: TRpcPeer; const Request: TRpcRe
11399
ProcedureName: String;
114100
begin
115101
Filename := ParseDocumentSymbolRequest(Request.Reader);
102+
if Filename = '' then
103+
begin
104+
{ This happens when opening new file that is not yet saved,
105+
with "untitled:" URI that has no real filename.
106+
Return null (not any error) in response, to avoid flooding
107+
notifications to user that tried to edit such file. }
108+
SendNullResponse(Rpc, Request);
109+
Exit;
110+
end;
111+
116112
LogInfo(Rpc, 'File name:' + Filename);
117113
Code := CodeToolBoss.FindFile(Filename);
118-
119114
if Code = nil then
115+
begin
120116
raise ERpcError.CreateFmt(
121117
jsrpcInvalidRequest,
122118
'File not found: %s', [Filename]
123119
);
120+
end;
124121

125122
{ Based on lazarus TProcedureListForm.GetCodeTreeNode() }
126123

server/ujsonrpc.pas

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -102,9 +102,12 @@ ERpcError = class(Exception)
102102
jsrpcMethodNotFound = -32601;
103103
jsrpcRequestFailed = -32803;
104104

105+
{ Return null response, that signals "no error, but also no result". }
106+
procedure SendNullResponse(const Rpc: TRpcPeer; const Request: TRpcRequest);
107+
105108
implementation
106109

107-
uses
110+
uses
108111
CastleLsp, udebug;
109112

110113
procedure WriteRpcId(Writer: TJsonWriter; const Id: TRPcId);
@@ -165,7 +168,7 @@ constructor TRpcResponse.CreateError(
165168
Writer.Dict;
166169
Writer.Key('code');
167170
Writer.Number(Code);
168-
171+
169172
Writer.Key('message');
170173
Writer.Str(Msg);
171174
Writer.DictEnd;
@@ -255,7 +258,7 @@ function TRpcPeer.Receive: TRpcRequest;
255258
raise EParserError.Create('Invalid request body.');
256259

257260
Buffer := TBytesStream.Create();
258-
Buffer.SetSize(Len);
261+
Buffer.SetSize(Len);
259262
FInput.BlockRead(PByte(Buffer.Memory)^, Len);
260263

261264
// 1st pass: Extract meta data
@@ -285,13 +288,13 @@ function TRpcPeer.Receive: TRpcRequest;
285288

286289
if (Version <> '2.0') then
287290
raise ERpcError.Create(
288-
jsrpcInvalidRequest,
291+
jsrpcInvalidRequest,
289292
'No or invalid jsonrpc version specified. Must be 2.0.'
290293
);
291294

292295
if (Method = '') then
293296
raise ERpcError.Create(
294-
jsrpcInvalidRequest,
297+
jsrpcInvalidRequest,
295298
'No method specified.'
296299
);
297300

@@ -319,7 +322,7 @@ function TRpcPeer.Receive: TRpcRequest;
319322
Result.Id := Id;
320323
Result.Reader := Reader;
321324
Result.FBuffer := Buffer;
322-
325+
323326
LogFullJson := UserConfig.ReadBool('log', 'full_json', false);
324327
if LogFullJson then
325328
CutLength := MaxInt
@@ -355,7 +358,7 @@ procedure TRpcPeer.Send(Response: TRpcResponse);
355358
[ContentType, Response.FBuffer.Size]
356359
));
357360
FOutput.WriteBuffer(
358-
PByte(Response.FBuffer.Memory)^,
361+
PByte(Response.FBuffer.Memory)^,
359362
Response.FBuffer.Size
360363
);
361364

@@ -388,5 +391,20 @@ constructor ERpcError.CreateFmt(
388391
Code := ACode;
389392
end;
390393

394+
procedure SendNullResponse(const Rpc: TRpcPeer; const Request: TRpcRequest);
395+
var
396+
Response: TRpcResponse;
397+
Writer: TJsonWriter;
398+
begin
399+
Response := TRpcResponse.Create(Request.Id);
400+
try
401+
Writer := Response.Writer;
402+
Writer.Null;
403+
Rpc.Send(Response);
404+
finally
405+
FreeAndNil(Response);
406+
end;
407+
end;
408+
391409
end.
392410

server/utextdocument.pas

Lines changed: 36 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -100,8 +100,17 @@ procedure TextDocument_DidOpen(Rpc: TRpcPeer; Request: TRpcRequest);
100100
if ParseChangeOrOpen(Request.Reader, UriStr, Content, false) then
101101
begin
102102
FileName := URIToFileNameEasy(UriStr);
103+
if FileName = '' then
104+
begin
105+
raise ERpcError.CreateFmt(
106+
jsrpcInvalidRequest,
107+
'URI does not describe a regular file: %s', [UriStr]
108+
);
109+
end;
110+
111+
// Initialize Code from FileName
103112
Code := CodeToolBoss.LoadFile(FileName, false, false);
104-
{ When we can't found file try to create it, workaround for creating
113+
{ When we can't find file try to create it, workaround for creating
105114
new source files in vscode }
106115
if Code = nil then
107116
Code := CodeToolBoss.CreateFile(FileName);
@@ -123,6 +132,11 @@ procedure TextDocument_DidChange(Rpc: TRpcPeer; Request: TRpcRequest);
123132
if ParseChangeOrOpen(Request.Reader, UriStr, Content, true) then
124133
begin
125134
FileName := URIToFileNameEasy(UriStr);
135+
if FileName = '' then
136+
raise ERpcError.CreateFmt(
137+
jsrpcInvalidRequest,
138+
'URI does not describe a regular file: %s', [UriStr]
139+
);
126140
Code := CodeToolBoss.FindFile(FileName);
127141
if Code = nil then
128142
raise ERpcError.CreateFmt(
@@ -348,6 +362,7 @@ procedure GetCompletionRecords(
348362
type
349363
TCompletionRequest = record
350364
X, Y: Integer;
365+
Uri: String;
351366
FileName: String;
352367
TriggerKind: Integer;
353368
TriggerChar: string;
@@ -357,9 +372,8 @@ TCompletionRequest = record
357372
function ParseCompletionRequest(Reader: TJsonReader): TCompletionRequest;
358373
var
359374
Key: string;
360-
UriStr: string;
361375
begin
362-
UriStr := '';
376+
Result.Uri := '';
363377
Result.TriggerKind := -1;
364378
Result.Y := -1;
365379
Result.X := -1;
@@ -371,7 +385,7 @@ function ParseCompletionRequest(Reader: TJsonReader): TCompletionRequest;
371385
while (Reader.Advance <> jsDictEnd) and Reader.Key(Key) do
372386
begin
373387
if Key = 'uri' then
374-
Reader.Str(UriStr);
388+
Reader.Str(Result.Uri);
375389
end
376390
else if (Key = 'position') and Reader.Dict then
377391
while (Reader.Advance <> jsDictEnd) and Reader.Key(Key) do
@@ -395,7 +409,7 @@ function ParseCompletionRequest(Reader: TJsonReader): TCompletionRequest;
395409
end;
396410
end;
397411

398-
Result.FileName := URIToFileNameEasy(UriStr);
412+
Result.FileName := URIToFileNameEasy(Result.Uri);
399413
end;
400414

401415
// Identifier completion
@@ -657,6 +671,12 @@ procedure TextDocument_Completion(Rpc: TRpcPeer; Request: TRpcRequest);
657671
try
658672
try
659673
Req := ParseCompletionRequest(Request.Reader);
674+
if Req.Filename = '' then
675+
begin
676+
SendNullResponse(Rpc, Request);
677+
Exit;
678+
end;
679+
660680
Code := CodeToolBoss.FindFile(Req.FileName);
661681

662682
if Code = nil then
@@ -817,6 +837,12 @@ procedure TextDocument_SignatureHelp(Rpc: TRpcPeer; Request: TRpcRequest);
817837
try
818838
try
819839
Req := ParseCompletionRequest(Request.Reader);
840+
if Req.Filename = '' then
841+
begin
842+
SendNullResponse(Rpc, Request);
843+
Exit;
844+
end;
845+
820846
Code := CodeToolBoss.FindFile(Req.FileName);
821847

822848
if Code = nil then
@@ -918,6 +944,11 @@ procedure TextDocument_JumpTo(
918944

919945
try
920946
Req := ParseCompletionRequest(Request.Reader);
947+
if Req.Filename = '' then
948+
begin
949+
SendNullResponse(Rpc, Request);
950+
Exit;
951+
end;
921952

922953
Code := CodeToolBoss.FindFile(Req.FileName);
923954

server/uutils.pas

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,11 @@ interface
2727

2828
function MergePaths(Paths: array of string): string;
2929
function GetConfigDirForApp(AppName, Vendor: string; Global: Boolean): string;
30+
31+
{ Convert URI (with file:// protocol) to a filename.
32+
Accepts also empty string, returning empty string in return.
33+
URIs with other protocols (like "untitled://") or invalid URIs
34+
result in a warning and also return empty string. }
3035
function URIToFileNameEasy(const UriStr: String): String;
3136

3237
{ Return prefix for error message describing filename, line, column
@@ -91,18 +96,16 @@ function GetConfigDirForApp(AppName, Vendor: string; Global: Boolean): string;
9196
end;
9297
end;
9398

94-
{ Convert URI (with file:// protocol) to a filename.
95-
Accepts also empty string, returning empty string in return.
96-
Other / invalid URIs result in an exception. }
9799
function URIToFileNameEasy(const UriStr: String): String;
98100
begin
99101
if UriStr = '' then
100102
Exit('');
101103
if not URIToFilename(UriStr, Result) then
102-
raise ERpcError.CreateFmt(
104+
Exit('');
105+
{raise ERpcError.CreateFmt(
103106
jsrpcInvalidRequest,
104107
'Unable to convert URI to filename: %s', [UriStr]
105-
);
108+
);}
106109
end;
107110

108111
const

0 commit comments

Comments
 (0)