|
2 | 2 | // actions available in the extension, but they are derived via the analysis
|
3 | 3 | // OCaml binary.
|
4 | 4 | import * as p from "vscode-languageserver-protocol";
|
| 5 | +import * as utils from "./utils"; |
| 6 | +import { fileURLToPath } from "url"; |
5 | 7 |
|
6 | 8 | export type filesCodeActions = {
|
7 | 9 | [key: string]: { range: p.Range; codeAction: p.CodeAction }[];
|
@@ -82,6 +84,15 @@ let insertBeforeEndingChar = (
|
82 | 84 | ];
|
83 | 85 | };
|
84 | 86 |
|
| 87 | +let replaceText = (range: p.Range, newText: string): p.TextEdit[] => { |
| 88 | + return [ |
| 89 | + { |
| 90 | + range, |
| 91 | + newText, |
| 92 | + }, |
| 93 | + ]; |
| 94 | +}; |
| 95 | + |
85 | 96 | let removeTrailingComma = (text: string): string => {
|
86 | 97 | let str = text.trim();
|
87 | 98 | if (str.endsWith(",")) {
|
@@ -514,67 +525,30 @@ let simpleAddMissingCases: codeActionExtractor = ({
|
514 | 525 | if (
|
515 | 526 | line.startsWith("You forgot to handle a possible case here, for example:")
|
516 | 527 | ) {
|
517 |
| - let cases: string[] = []; |
518 |
| - |
519 | 528 | // This collects the rest of the fields if fields are printed on
|
520 | 529 | // multiple lines.
|
521 | 530 | let allCasesAsOneLine = array
|
522 | 531 | .slice(index + 1)
|
523 | 532 | .join("")
|
524 | 533 | .trim();
|
525 | 534 |
|
526 |
| - // We only handle the simplest possible cases until the compiler actually |
527 |
| - // outputs ReScript. This means bailing on anything that's not a |
528 |
| - // variant/polyvariant, with one payload (or no payloads at all). |
529 |
| - let openParensCount = allCasesAsOneLine.split("(").length - 1; |
530 |
| - |
531 |
| - if (openParensCount > 1 || allCasesAsOneLine.includes("{")) { |
532 |
| - return false; |
533 |
| - } |
534 |
| - |
535 |
| - // Remove surrounding braces if they exist |
536 |
| - if (allCasesAsOneLine[0] === "(") { |
537 |
| - allCasesAsOneLine = allCasesAsOneLine.slice( |
538 |
| - 1, |
539 |
| - allCasesAsOneLine.length - 1 |
540 |
| - ); |
541 |
| - } |
542 |
| - |
543 |
| - cases.push( |
544 |
| - ...(allCasesAsOneLine |
545 |
| - .split("|") |
546 |
| - .map(transformMatchPattern) |
547 |
| - .filter(Boolean) as string[]) |
548 |
| - ); |
549 |
| - |
550 |
| - if (cases.length === 0) { |
551 |
| - return false; |
552 |
| - } |
553 |
| - |
554 |
| - // The end char is the closing brace. In switches, the leading `|` always |
555 |
| - // has the same left padding as the end brace. |
556 |
| - let paddingContentSwitchCase = Array.from({ |
557 |
| - length: range.end.character, |
558 |
| - }).join(" "); |
559 |
| - |
560 |
| - let newText = cases |
561 |
| - .map((variantName, index) => { |
562 |
| - // The first case will automatically be padded because we're inserting |
563 |
| - // it where the end brace is currently located. |
564 |
| - let padding = index === 0 ? "" : paddingContentSwitchCase; |
565 |
| - return `${padding}| ${variantName} => assert false`; |
566 |
| - }) |
567 |
| - .join("\n"); |
| 535 | + let filePath = fileURLToPath(file); |
568 | 536 |
|
569 |
| - // Let's put the end brace back where it was (we still have it to the direct right of us). |
570 |
| - newText += `\n${paddingContentSwitchCase}`; |
| 537 | + let newSwitchCode = utils.runAnalysisAfterSanityCheck(filePath, [ |
| 538 | + "codemod", |
| 539 | + filePath, |
| 540 | + range.start.line, |
| 541 | + range.start.character, |
| 542 | + "add-missing-cases", |
| 543 | + allCasesAsOneLine, |
| 544 | + ]); |
571 | 545 |
|
572 | 546 | codeActions[file] = codeActions[file] || [];
|
573 | 547 | let codeAction: p.CodeAction = {
|
574 | 548 | title: `Insert missing cases`,
|
575 | 549 | edit: {
|
576 | 550 | changes: {
|
577 |
| - [file]: insertBeforeEndingChar(range, newText), |
| 551 | + [file]: replaceText(range, newSwitchCode), |
578 | 552 | },
|
579 | 553 | },
|
580 | 554 | diagnostics: [diagnostic],
|
|
0 commit comments