-
Notifications
You must be signed in to change notification settings - Fork 230
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
base: main
Are you sure you want to change the base?
Changes from 6 commits
b0ac596
3fcbe52
c109816
23f0108
a8e5aec
880f6d3
e9a2260
ab373d8
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
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"; | ||
|
||
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), | ||
), | ||
); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. dont you need a '\n'? |
||
} | ||
} | ||
|
||
return result; | ||
}, | ||
}); | ||
} | ||
|
||
function splitLines( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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; | ||
} |
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 """; | ||
`); | ||
}); | ||
}); |
There was a problem hiding this comment.
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?