Skip to content

Commit d62fe26

Browse files
committed
Refactor, move out more server commands.
1 parent 39312c9 commit d62fe26

File tree

1 file changed

+172
-165
lines changed

1 file changed

+172
-165
lines changed

server/src/server.ts

+172-165
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ let projectsFiles: Map<
4141
// ^ caching AND states AND distributed system. Why does LSP has to be stupid like this
4242

4343
// will be properly defined later depending on the mode (stdio/node-rpc)
44-
let send: (msg: m.Message) => void = (_) => {};
44+
let send: (msg: m.Message) => void = (_) => { };
4545

4646
interface CreateInterfaceRequestParams {
4747
uri: string;
@@ -349,6 +349,174 @@ function completion(msg: p.RequestMessage) {
349349
return response;
350350
}
351351

352+
function format(msg: p.RequestMessage): Array<m.Message> {
353+
// technically, a formatting failure should reply with the error. Sadly
354+
// the LSP alert box for these error replies sucks (e.g. doesn't actually
355+
// display the message). In order to signal the client to display a proper
356+
// alert box (sometime with actionable buttons), we need to first send
357+
// back a fake success message (because each request mandates a
358+
// response), then right away send a server notification to display a
359+
// nicer alert. Ugh.
360+
let fakeSuccessResponse: m.ResponseMessage = {
361+
jsonrpc: c.jsonrpcVersion,
362+
id: msg.id,
363+
result: [],
364+
};
365+
366+
let params = msg.params as p.DocumentFormattingParams;
367+
let filePath = fileURLToPath(params.textDocument.uri);
368+
let extension = path.extname(params.textDocument.uri);
369+
if (extension !== c.resExt && extension !== c.resiExt) {
370+
let params: p.ShowMessageParams = {
371+
type: p.MessageType.Error,
372+
message: `Not a ${c.resExt} or ${c.resiExt} file. Cannot format it.`,
373+
};
374+
let response: m.NotificationMessage = {
375+
jsonrpc: c.jsonrpcVersion,
376+
method: "window/showMessage",
377+
params: params,
378+
};
379+
return [fakeSuccessResponse, response];
380+
} else {
381+
// See comment on findBscNativeDirOfFile for why we need
382+
// to recursively search for bsc.exe upward
383+
let bscNativePath = utils.findBscNativeOfFile(filePath);
384+
if (bscNativePath === null) {
385+
let params: p.ShowMessageParams = {
386+
type: p.MessageType.Error,
387+
message: `Cannot find a nearby bsc.exe in rescript or bs-platform. It's needed for formatting.`,
388+
};
389+
let response: m.NotificationMessage = {
390+
jsonrpc: c.jsonrpcVersion,
391+
method: "window/showMessage",
392+
params: params,
393+
};
394+
return [fakeSuccessResponse, response]
395+
} else {
396+
// code will always be defined here, even though technically it can be undefined
397+
let code = getOpenedFileContent(params.textDocument.uri);
398+
let formattedResult = utils.formatUsingValidBscNativePath(
399+
code,
400+
bscNativePath,
401+
extension === c.resiExt
402+
);
403+
if (formattedResult.kind === "success") {
404+
let max = formattedResult.result.length;
405+
let result: p.TextEdit[] = [
406+
{
407+
range: {
408+
start: { line: 0, character: 0 },
409+
end: { line: max, character: max },
410+
},
411+
newText: formattedResult.result,
412+
},
413+
];
414+
let response: m.ResponseMessage = {
415+
jsonrpc: c.jsonrpcVersion,
416+
id: msg.id,
417+
result: result,
418+
};
419+
return [response];
420+
} else {
421+
// let the diagnostics logic display the updated syntax errors,
422+
// from the build.
423+
// Again, not sending the actual errors. See fakeSuccessResponse
424+
// above for explanation
425+
return [fakeSuccessResponse];
426+
}
427+
}
428+
}
429+
}
430+
431+
function createInterface(msg: p.RequestMessage): m.Message {
432+
let params = msg.params as CreateInterfaceRequestParams;
433+
let extension = path.extname(params.uri);
434+
let filePath = fileURLToPath(params.uri);
435+
let bscNativePath = utils.findBscNativeOfFile(filePath);
436+
let projDir = utils.findProjectRootOfFile(filePath);
437+
438+
if (bscNativePath === null || projDir === null) {
439+
let params: p.ShowMessageParams = {
440+
type: p.MessageType.Error,
441+
message: `Cannot find a nearby bsc.exe to generate the interface file.`,
442+
};
443+
444+
let response: m.NotificationMessage = {
445+
jsonrpc: c.jsonrpcVersion,
446+
method: "window/showMessage",
447+
params: params,
448+
};
449+
450+
return response;
451+
} else if (extension !== c.resExt) {
452+
let params: p.ShowMessageParams = {
453+
type: p.MessageType.Error,
454+
message: `Not a ${c.resExt} file. Cannot create an interface for it.`,
455+
};
456+
457+
let response: m.NotificationMessage = {
458+
jsonrpc: c.jsonrpcVersion,
459+
method: "window/showMessage",
460+
params: params,
461+
};
462+
463+
return response;
464+
} else {
465+
let cmiPartialPath = utils.replaceFileExtension(
466+
filePath.split(projDir)[1],
467+
c.cmiExt
468+
);
469+
let cmiPath = path.join(
470+
projDir,
471+
c.compilerDirPartialPath,
472+
cmiPartialPath
473+
);
474+
let cmiAvailable = fs.existsSync(cmiPath);
475+
476+
if (!cmiAvailable) {
477+
let params: p.ShowMessageParams = {
478+
type: p.MessageType.Error,
479+
message: `No compiled interface file found. Please compile your project first.`,
480+
};
481+
482+
let response: m.NotificationMessage = {
483+
jsonrpc: c.jsonrpcVersion,
484+
method: "window/showMessage",
485+
params,
486+
};
487+
488+
return response;
489+
} else {
490+
let intfResult = utils.createInterfaceFileUsingValidBscExePath(
491+
filePath,
492+
cmiPath,
493+
bscNativePath
494+
);
495+
496+
if (intfResult.kind === "success") {
497+
let response: m.ResponseMessage = {
498+
jsonrpc: c.jsonrpcVersion,
499+
id: msg.id,
500+
result: intfResult.result,
501+
};
502+
503+
return response;
504+
} else {
505+
let response: m.ResponseMessage = {
506+
jsonrpc: c.jsonrpcVersion,
507+
id: msg.id,
508+
error: {
509+
code: m.ErrorCodes.InternalError,
510+
message: "Unable to create interface file.",
511+
},
512+
};
513+
514+
return response;
515+
}
516+
}
517+
}
518+
}
519+
352520
function onMessage(msg: m.Message) {
353521
if (m.isNotificationMessage(msg)) {
354522
// notification message, aka the client ends it and doesn't want a reply
@@ -471,171 +639,10 @@ function onMessage(msg: m.Message) {
471639
} else if (msg.method === p.CompletionRequest.method) {
472640
send(completion(msg));
473641
} else if (msg.method === p.DocumentFormattingRequest.method) {
474-
// technically, a formatting failure should reply with the error. Sadly
475-
// the LSP alert box for these error replies sucks (e.g. doesn't actually
476-
// display the message). In order to signal the client to display a proper
477-
// alert box (sometime with actionable buttons), we need to first send
478-
// back a fake success message (because each request mandates a
479-
// response), then right away send a server notification to display a
480-
// nicer alert. Ugh.
481-
let fakeSuccessResponse: m.ResponseMessage = {
482-
jsonrpc: c.jsonrpcVersion,
483-
id: msg.id,
484-
result: [],
485-
};
486-
487-
let params = msg.params as p.DocumentFormattingParams;
488-
let filePath = fileURLToPath(params.textDocument.uri);
489-
let extension = path.extname(params.textDocument.uri);
490-
if (extension !== c.resExt && extension !== c.resiExt) {
491-
let params: p.ShowMessageParams = {
492-
type: p.MessageType.Error,
493-
message: `Not a ${c.resExt} or ${c.resiExt} file. Cannot format it.`,
494-
};
495-
let response: m.NotificationMessage = {
496-
jsonrpc: c.jsonrpcVersion,
497-
method: "window/showMessage",
498-
params: params,
499-
};
500-
send(fakeSuccessResponse);
501-
send(response);
502-
} else {
503-
// See comment on findBscNativeDirOfFile for why we need
504-
// to recursively search for bsc.exe upward
505-
let bscNativePath = utils.findBscNativeOfFile(filePath);
506-
if (bscNativePath === null) {
507-
let params: p.ShowMessageParams = {
508-
type: p.MessageType.Error,
509-
message: `Cannot find a nearby bsc.exe in rescript or bs-platform. It's needed for formatting.`,
510-
};
511-
let response: m.NotificationMessage = {
512-
jsonrpc: c.jsonrpcVersion,
513-
method: "window/showMessage",
514-
params: params,
515-
};
516-
send(fakeSuccessResponse);
517-
send(response);
518-
} else {
519-
// code will always be defined here, even though technically it can be undefined
520-
let code = getOpenedFileContent(params.textDocument.uri);
521-
let formattedResult = utils.formatUsingValidBscNativePath(
522-
code,
523-
bscNativePath,
524-
extension === c.resiExt
525-
);
526-
if (formattedResult.kind === "success") {
527-
let max = formattedResult.result.length;
528-
let result: p.TextEdit[] = [
529-
{
530-
range: {
531-
start: { line: 0, character: 0 },
532-
end: { line: max, character: max },
533-
},
534-
newText: formattedResult.result,
535-
},
536-
];
537-
let response: m.ResponseMessage = {
538-
jsonrpc: c.jsonrpcVersion,
539-
id: msg.id,
540-
result: result,
541-
};
542-
send(response);
543-
} else {
544-
// let the diagnostics logic display the updated syntax errors,
545-
// from the build.
546-
// Again, not sending the actual errors. See fakeSuccessResponse
547-
// above for explanation
548-
send(fakeSuccessResponse);
549-
}
550-
}
551-
}
642+
let responses = format(msg);
643+
responses.forEach(response => send(response))
552644
} else if (msg.method === createInterfaceRequest.method) {
553-
let params = msg.params as CreateInterfaceRequestParams;
554-
let extension = path.extname(params.uri);
555-
let filePath = fileURLToPath(params.uri);
556-
let bscNativePath = utils.findBscNativeOfFile(filePath);
557-
let projDir = utils.findProjectRootOfFile(filePath);
558-
559-
if (bscNativePath === null || projDir === null) {
560-
let params: p.ShowMessageParams = {
561-
type: p.MessageType.Error,
562-
message: `Cannot find a nearby bsc.exe to generate the interface file.`,
563-
};
564-
565-
let response: m.NotificationMessage = {
566-
jsonrpc: c.jsonrpcVersion,
567-
method: "window/showMessage",
568-
params: params,
569-
};
570-
571-
send(response);
572-
} else if (extension !== c.resExt) {
573-
let params: p.ShowMessageParams = {
574-
type: p.MessageType.Error,
575-
message: `Not a ${c.resExt} file. Cannot create an interface for it.`,
576-
};
577-
578-
let response: m.NotificationMessage = {
579-
jsonrpc: c.jsonrpcVersion,
580-
method: "window/showMessage",
581-
params: params,
582-
};
583-
584-
send(response);
585-
} else {
586-
let cmiPartialPath = utils.replaceFileExtension(
587-
filePath.split(projDir)[1],
588-
c.cmiExt
589-
);
590-
let cmiPath = path.join(
591-
projDir,
592-
c.compilerDirPartialPath,
593-
cmiPartialPath
594-
);
595-
let cmiAvailable = fs.existsSync(cmiPath);
596-
597-
if (!cmiAvailable) {
598-
let params: p.ShowMessageParams = {
599-
type: p.MessageType.Error,
600-
message: `No compiled interface file found. Please compile your project first.`,
601-
};
602-
603-
let response: m.NotificationMessage = {
604-
jsonrpc: c.jsonrpcVersion,
605-
method: "window/showMessage",
606-
params,
607-
};
608-
609-
send(response);
610-
} else {
611-
let intfResult = utils.createInterfaceFileUsingValidBscExePath(
612-
filePath,
613-
cmiPath,
614-
bscNativePath
615-
);
616-
617-
if (intfResult.kind === "success") {
618-
let response: m.ResponseMessage = {
619-
jsonrpc: c.jsonrpcVersion,
620-
id: msg.id,
621-
result: intfResult.result,
622-
};
623-
624-
send(response);
625-
} else {
626-
let response: m.ResponseMessage = {
627-
jsonrpc: c.jsonrpcVersion,
628-
id: msg.id,
629-
error: {
630-
code: m.ErrorCodes.InternalError,
631-
message: "Unable to create interface file.",
632-
},
633-
};
634-
635-
send(response);
636-
}
637-
}
638-
}
645+
send(createInterface(msg))
639646
} else {
640647
let response: m.ResponseMessage = {
641648
jsonrpc: c.jsonrpcVersion,

0 commit comments

Comments
 (0)