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

feat: format with generator #82

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all 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
33 changes: 21 additions & 12 deletions src/impl/format.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,16 @@ import { createScanner } from './scanner';
import { cachedSpaces, cachedBreakLinesWithSpaces, supportedEols, SupportedEOL } from './string-intern';

export function format(documentText: string, range: Range | undefined, options: FormattingOptions): Edit[] {
const operations: Edit[] = [];

for (const edit of formatGenerator(documentText, range, options)) {
operations.push(edit);
}

return operations;
}

export function* formatGenerator(documentText: string, range: Range | undefined, options: FormattingOptions): Generator<Edit, void, void> {
let initialIndentLevel: number;
let formatText: string;
let formatTextStart: number;
Expand Down Expand Up @@ -85,24 +95,21 @@ export function format(documentText: string, range: Range | undefined, options:
hasError = token === SyntaxKind.Unknown || scanner.getTokenError() !== ScanError.None;
return token;
}
const editOperations: Edit[] = [];
function addEdit(text: string, startOffset: number, endOffset: number) {
if (!hasError && (!range || (startOffset < rangeEnd && endOffset > rangeStart)) && documentText.substring(startOffset, endOffset) !== text) {
editOperations.push({ offset: startOffset, length: endOffset - startOffset, content: text });
}
}

const shouldAddEdit = (text: string, startOffset: number, endOffset: number) => !hasError && (!range || (startOffset < rangeEnd && endOffset > rangeStart)) && documentText.substring(startOffset, endOffset) !== text
let firstToken = scanNext();
if (options.keepLines && numberLineBreaks > 0) {
addEdit(repeat(eol, numberLineBreaks), 0, 0);
const text = repeat(eol, numberLineBreaks);
if (shouldAddEdit(text, 0, 0))
yield { offset: 0, length: 0, content: text };
}

if (firstToken !== SyntaxKind.EOF) {
let firstTokenStart = scanner.getTokenOffset() + formatTextStart;
let initialIndent = (indentValue.length * initialIndentLevel < 20) && options.insertSpaces
? cachedSpaces[indentValue.length * initialIndentLevel]
: repeat(indentValue, initialIndentLevel);
addEdit(initialIndent, formatTextStart, firstTokenStart);
if (shouldAddEdit(initialIndent, formatTextStart, firstTokenStart))
yield { offset: formatTextStart, length: firstTokenStart - formatTextStart, content: initialIndent };
}

while (firstToken !== SyntaxKind.EOF) {
Expand All @@ -114,7 +121,9 @@ export function format(documentText: string, range: Range | undefined, options:

while (numberLineBreaks === 0 && (secondToken === SyntaxKind.LineCommentTrivia || secondToken === SyntaxKind.BlockCommentTrivia)) {
let commentTokenStart = scanner.getTokenOffset() + formatTextStart;
addEdit(cachedSpaces[1], firstTokenEnd, commentTokenStart);
if (shouldAddEdit(cachedSpaces[1], firstTokenEnd, commentTokenStart))
yield { offset: firstTokenEnd, length: commentTokenStart - firstTokenEnd, content: cachedSpaces[1] };

firstTokenEnd = scanner.getTokenOffset() + scanner.getTokenLength() + formatTextStart;
needsLineBreak = secondToken === SyntaxKind.LineCommentTrivia;
replaceContent = needsLineBreak ? newLinesAndIndent() : '';
Expand Down Expand Up @@ -211,10 +220,10 @@ export function format(documentText: string, range: Range | undefined, options:
}
}
const secondTokenStart = scanner.getTokenOffset() + formatTextStart;
addEdit(replaceContent, firstTokenEnd, secondTokenStart);
if (shouldAddEdit(replaceContent, firstTokenEnd, secondTokenStart))
yield { offset: firstTokenEnd, length: secondTokenStart - firstTokenEnd, content: replaceContent };
firstToken = secondToken;
}
return editOperations;
}

function repeat(s: string, count: number): string {
Expand Down
18 changes: 18 additions & 0 deletions src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -305,6 +305,11 @@ export interface JSONVisitor {
*/
export type EditResult = Edit[];

/**
* See more {@link EditResult}
*/
export type EditGeneratorResult = Generator<Edit, void, void>;

/**
* Represents a text modification
*/
Expand Down Expand Up @@ -376,6 +381,19 @@ export function format(documentText: string, range: Range | undefined, options:
return formatter.format(documentText, range, options);
}

/**
* Computes the edit operations needed to format a JSON document.
*
* @param documentText The input text
* @param range The range to format or `undefined` to format the full content
* @param options The formatting options
* @returns The edit operations describing the formatting changes to the original document following the format described in {@linkcode EditResult}.
* To apply the edit operations to the input, use {@linkcode applyEdits}.
*/
export function formatGenerator(documentText: string, range: Range | undefined, options: FormattingOptions): EditGeneratorResult {
return formatter.formatGenerator(documentText, range, options);
}

/**
* Options used by {@linkcode modify} when computing the modification edit operations
*/
Expand Down