[html] script end tag is not correctly indented. Fixes #16650

This commit is contained in:
Martin Aeschlimann 2016-12-08 12:29:37 +01:00
parent 74dd83c541
commit b38a82cca7
4 changed files with 54 additions and 10 deletions

View file

@ -208,7 +208,6 @@ connection.onDocumentRangeFormatting(formatParams => {
ranges.forEach(r => {
let mode = r.mode;
if (mode && mode.format && enabledModes[mode.getId()] && !r.attributeValue) {
console.log(mode.getId());
let edits = mode.format(document, r, formatParams.options);
pushAll(result, edits);
}

View file

@ -7,7 +7,7 @@
import { LanguageModelCache, getLanguageModelCache } from '../languageModelCache';
import { SymbolInformation, SymbolKind, CompletionItem, Location, SignatureHelp, SignatureInformation, ParameterInformation, Definition, TextEdit, TextDocument, Diagnostic, DiagnosticSeverity, Range, CompletionItemKind, Hover, MarkedString, DocumentHighlight, DocumentHighlightKind, CompletionList, Position, FormattingOptions } from 'vscode-languageserver-types';
import { LanguageMode } from './languageModes';
import { getWordAtText, startsWith } from '../utils/strings';
import { getWordAtText, startsWith, isWhitespaceOnly, repeat } from '../utils/strings';
import { HTMLDocumentRegions } from './embeddedSupport';
import * as ts from 'typescript';
@ -235,10 +235,15 @@ export function getJavascriptMode(documentRegions: LanguageModelCache<HTMLDocume
},
format(document: TextDocument, range: Range, formatParams: FormattingOptions): TextEdit[] {
currentTextDocument = jsDocuments.get(document);
let initialIndentLevel = computeInitialIndent(document, range, formatParams) + 1;
let formatSettings = convertOptions(formatParams, settings && settings.format, initialIndentLevel);
let initialIndentLevel = computeInitialIndent(document, range, formatParams);
let formatSettings = convertOptions(formatParams, settings && settings.format, initialIndentLevel + 1);
let start = currentTextDocument.offsetAt(range.start);
let end = currentTextDocument.offsetAt(range.end);
let lastLineRange = null;
if (range.end.character === 0 || isWhitespaceOnly(currentTextDocument.getText().substr(end - range.end.character, range.end.character))) {
end -= range.end.character;
lastLineRange = Range.create(Position.create(range.end.line, 0), range.end);
}
let edits = jsLanguageService.getFormattingEditsForRange(FILE_NAME, start, end, formatSettings);
if (edits) {
let result = [];
@ -250,6 +255,12 @@ export function getJavascriptMode(documentRegions: LanguageModelCache<HTMLDocume
});
}
}
if (lastLineRange) {
result.push({
range: lastLineRange,
newText: generateIndent(initialIndentLevel, formatParams)
});
}
return result;
}
return null;
@ -370,4 +381,12 @@ function computeInitialIndent(document: TextDocument, range: Range, options: For
i++;
}
return Math.floor(nChars / tabSize);
}
function generateIndent(level: number, options: FormattingOptions) {
if (options.insertSpaces) {
return repeat(' ', level * options.tabSize);
} else {
return repeat('\t', level);
}
}

View file

@ -53,12 +53,16 @@ suite('HTML Embedded Formatting', () => {
test('HTML & Scripts', function (): any {
assertFormat('<html><head><script></script></head></html>', '<html>\n\n<head>\n <script></script>\n</head>\n\n</html>');
assertFormat('<html><head><script>var x=1;</script></head></html>', '<html>\n\n<head>\n <script>var x = 1;</script>\n</head>\n\n</html>');
assertFormat('<html><head><script>\nvar x=1;\n</script></head></html>', '<html>\n\n<head>\n <script>\n var x = 1;\n</script>\n</head>\n\n</html>');
assertFormat('<html><head>\n <script>\nvar x=1;\n</script></head></html>', '<html>\n\n<head>\n <script>\n var x = 1;\n</script>\n</head>\n\n</html>');
assertFormat('<html><head>\n <script>\nvar x=1;\nconsole.log("Hi");\n</script></head></html>', '<html>\n\n<head>\n <script>\n var x = 1;\n console.log("Hi");\n</script>\n</head>\n\n</html>');
assertFormat('<html><head><script>\nvar x=2;\n</script></head></html>', '<html>\n\n<head>\n <script>\n var x = 2;\n</script>\n</head>\n\n</html>');
assertFormat('<html><head>\n <script>\nvar x=3;\n</script></head></html>', '<html>\n\n<head>\n <script>\n var x = 3;\n </script>\n</head>\n\n</html>');
assertFormat('<html><head>\n <script>\nvar x=4;\nconsole.log("Hi");\n</script></head></html>', '<html>\n\n<head>\n <script>\n var x = 4;\n console.log("Hi");\n </script>\n</head>\n\n</html>');
assertFormat('<html><head>\n |<script>\nvar x=1;\n</script>|</head></html>', '<html><head>\n <script>\n var x = 1;\n</script></head></html>');
assertFormat('<html><head>\n <script>\n|var x=1;|\n</script></head></html>', '<html><head>\n <script>\n var x = 1;\n</script></head></html>');
assertFormat('<html><head>\n |<script>\nvar x=5;\n</script>|</head></html>', '<html><head>\n <script>\n var x = 5;\n </script></head></html>');
assertFormat('<html><head>\n <script>\n|var x=6;|\n</script></head></html>', '<html><head>\n <script>\n var x = 6;\n</script></head></html>');
});
test('Script end tag', function (): any {
assertFormat('<html>\n<head>\n <script>\nvar x = 0;\n</script></head></html>', '<html>\n\n<head>\n <script>\n var x = 0;\n </script>\n</head>\n\n</html>');
});
test('HTML & Multiple Scripts', function (): any {
@ -94,7 +98,13 @@ function pushAll<T>(to: T[], from: T[]) {
function applyEdits(document: TextDocument, edits: TextEdit[]): string {
let text = document.getText();
let sortedEdits = edits.sort((a, b) => document.offsetAt(b.range.start) - document.offsetAt(a.range.start));
let sortedEdits = edits.sort((a, b) => {
let startDiff = document.offsetAt(b.range.start) - document.offsetAt(a.range.start);
if (startDiff === 0) {
return document.offsetAt(b.range.end) - document.offsetAt(a.range.end);
}
return startDiff;
});
let lastOffset = text.length;
sortedEdits.forEach(e => {
let startOffset = document.offsetAt(e.range.start);

View file

@ -41,6 +41,22 @@ export function startsWith(haystack: string, needle: string): boolean {
return true;
}
export function repeat(value: string, count: number) {
var s = '';
while (count > 0) {
if ((count & 1) === 1) {
s += value;
}
value += value;
count = count >>> 1;
}
return s;
}
export function isWhitespaceOnly(str: string) {
return /^\s*$/.test(str);
}
const CR = '\r'.charCodeAt(0);
const NL = '\n'.charCodeAt(0);