Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Not Ready] [typespec-vscode] Add codefix for triple quate indent #5458

Open
wants to merge 8 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
import { CharCode, isWhiteSpaceSingleLine } from "../charcode.js";
import { defineCodeFix, getSourceLocation } from "../diagnostics.js";
import type { CodeFixEdit, DiagnosticTarget } from "../types.js";

export function createTripleQuoteIndentCodeFix(diagnosticTarget: DiagnosticTarget) {
return defineCodeFix({
id: "triple-quote-indent",
label: "Format triple-quote-indent",
fix: (context) => {
const result: CodeFixEdit[] = [];

const location = getSourceLocation(diagnosticTarget);
const startPos = location.pos;
const endPos = location.end;
const offSet = 3;
const splitOrIndentStr = "\r\n";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the name is confusing, it's not a indent, right?


const arrSplintLines = splitLines(location.file.text, startPos + offSet, endPos - offSet);
const count = arrSplintLines.length;

const minIndentObj: { startPos: number; indent: number } = arrSplintLines.reduce(
(prev, curr) => {
return prev.indent < curr.indent ? prev : curr;
},
);

for (let i = 0; i < count; i++) {
const line = arrSplintLines[i];
const lastLine = arrSplintLines[arrSplintLines.length - 1];

if (i === 0 || i === count - 1) {
if (i === 0 && line.lineText.trim() !== "") {
// start triple quote is not on new line
[startPos + offSet].map((pos) => {
result.push(
context.prependText(
{ ...location, pos },
splitOrIndentStr + " ".repeat(lastLine.indent - minIndentObj.indent),
),
);
});
}

if (i === count - 1 && line.lineText.replace(splitOrIndentStr, "").trim() !== "") {
// end triple quote is not on new line
[endPos - offSet].map((pos) => {
result.push(
context.prependText(
{ ...location, pos },
splitOrIndentStr +
" ".repeat(
lastLine.indent - (arrSplintLines.length === 1 ? 0 : minIndentObj.indent),
),
),
);
});
}
} else {
// All triple quote is on new line, but content is not indented the same as the closing triple quote
// So take the difference between the last line and the smallest indentation in all lines,
// and supplement the indentation of each line (except the first and last lines)
result.push(
context.prependText(
{ ...location, pos: arrSplintLines[i].startPos },
" ".repeat(lastLine.indent - minIndentObj.indent),
),
);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

dont you need a '\n'?

}
}

return result;
},
});
}

function splitLines(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

any reason not use the existing one?

text: string,
start: number,
end: number,
): { startPos: number; indent: number; lineText: string }[] {
const lines: { startPos: number; indent: number; lineText: string }[] = [];
let pos = start;

while (pos <= end) {
const ch = text.charCodeAt(pos);
switch (ch) {
case CharCode.CarriageReturn:
if (text.charCodeAt(pos + 1) === CharCode.LineFeed) {
addObjToArray();
pos++;
} else {
addObjToArray();
}
break;
case CharCode.LineFeed:
addObjToArray();
break;
}
pos++;
}

const lineText = text.slice(start, end);
const indentNumb = getIndentInLine(lineText);
lines.push({ startPos: start + 2, indent: indentNumb, lineText });

return lines;

function addObjToArray() {
const lineText = text.slice(start, pos);
const indentNumb = getIndentInLine(lineText);
lines.push({ startPos: start + 2, indent: indentNumb, lineText });
start = pos;
}
}

function getIndentInLine(lineText: string): number {
let curStart = 0;
const curEnd = lineText.length;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

usually end means a position, not lenght

let indentNumb = 0;
if (
lineText.charCodeAt(curStart) === CharCode.CarriageReturn &&
lineText.charCodeAt(curStart + 1) === CharCode.LineFeed
) {
curStart += 2;
}

while (curStart < curEnd && isWhiteSpaceSingleLine(lineText.charCodeAt(curStart))) {
indentNumb++;
curStart++;
}
return indentNumb;
}
15 changes: 12 additions & 3 deletions packages/compiler/src/core/parser.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
import { isArray, mutate } from "../utils/misc.js";
import { codePointBefore, isIdentifierContinue, trim } from "./charcode.js";
import { createTripleQuoteIndentCodeFix } from "./compiler-code-fixes/triple-quote-indent.codefix.js";
import { compilerAssert } from "./diagnostics.js";
import { CompilerDiagnostics, createDiagnostic } from "./messages.js";
import {
Token,
TokenDisplay,
TokenFlags,
createScanner,
isComment,
isKeyword,
Expand All @@ -15,6 +13,9 @@ import {
skipContinuousIdentifier,
skipTrivia,
skipTriviaBackward,
Token,
TokenDisplay,
TokenFlags,
} from "./scanner.js";
import {
AliasStatementNode,
Expand Down Expand Up @@ -69,6 +70,7 @@ import {
NeverKeywordNode,
Node,
NodeFlags,
NoTarget,
NumericLiteralNode,
ObjectLiteralNode,
ObjectLiteralPropertyNode,
Expand Down Expand Up @@ -3427,7 +3429,14 @@ function createParser(code: string | SourceFile, options: ParseOptions = {}): Pa
if (diagnostic.severity === "error") {
parseErrorInNextFinishedNode = true;
treePrintable = false;

const code = "triple-quote-indent";
if (diagnostic.target !== NoTarget && diagnostic.code === code) {
mutate(diagnostic).codefixes ??= [];
mutate(diagnostic.codefixes).push(createTripleQuoteIndentCodeFix(diagnostic.target));
}
}

parseDiagnostics.push(diagnostic);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import { strictEqual } from "assert";
import { describe, it } from "vitest";
import { createTripleQuoteIndentCodeFix } from "../../../src/core/compiler-code-fixes/triple-quote-indent.codefix.js";
import { SyntaxKind } from "../../../src/index.js";
import { expectCodeFixOnAst } from "../../../src/testing/code-fix-testing.js";

describe("CodeFix: triple-quote-indent", () => {
it("case 1: each triple-quote is on a new line", async () => {
await expectCodeFixOnAst(
`
const a = ┆"""\r\none\r\n two\r\n """;
`,
(node) => {
strictEqual(node.kind, SyntaxKind.StringLiteral);
return createTripleQuoteIndentCodeFix(node);
},
).toChangeTo(`
const a = """\r\n one\r\n two\r\n """;
`);
});

it("case 2: all triple-quote is on one line", async () => {
await expectCodeFixOnAst(
`
const a = ┆""" one\r\n two """;
`,
(node) => {
strictEqual(node.kind, SyntaxKind.StringLiteral);
return createTripleQuoteIndentCodeFix(node);
},
).toChangeTo(`
const a = """\r\n one\r\n two \r\n """;
`);
});

it("case 3: all triple-quote is on one line and is no carriage return in line", async () => {
await expectCodeFixOnAst(
`
const a = ┆""" one two """;
`,
(node) => {
strictEqual(node.kind, SyntaxKind.StringLiteral);
return createTripleQuoteIndentCodeFix(node);
},
).toChangeTo(`
const a = """\r\n one two \r\n """;
`);
});

it("case 4: start triple-quote is not on a new line but end one is", async () => {
await expectCodeFixOnAst(
`
const a = ┆"""one\r\n two\r\n """;
`,
(node) => {
strictEqual(node.kind, SyntaxKind.StringLiteral);
return createTripleQuoteIndentCodeFix(node);
},
).toChangeTo(`
const a = """\r\n one\r\n two\r\n """;
`);
});

it("case 5: end triple-quote is not on a new line but start one is", async () => {
await expectCodeFixOnAst(
`
const a = ┆"""\r\n one\r\n two """;
`,
(node) => {
strictEqual(node.kind, SyntaxKind.StringLiteral);
return createTripleQuoteIndentCodeFix(node);
},
).toChangeTo(`
const a = """\r\n one\r\n two \r\n """;
`);
});
});
Loading