|
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