mirror of
https://github.com/microsoft/vscode.git
synced 2026-04-26 03:29:00 +01:00
[html] Format onPaste issues with HTML. Fixes #21218
This commit is contained in:
@@ -10,6 +10,7 @@ import { TextDocument, Diagnostic, DocumentLink, Range, SymbolInformation } from
|
||||
import { getLanguageModes, LanguageModes } from './modes/languageModes';
|
||||
|
||||
import { format } from './modes/formatting';
|
||||
import { pushAll } from './utils/arrays';
|
||||
|
||||
import * as url from 'url';
|
||||
import * as path from 'path';
|
||||
@@ -165,14 +166,6 @@ function validateTextDocument(textDocument: TextDocument): void {
|
||||
connection.sendDiagnostics({ uri: textDocument.uri, diagnostics });
|
||||
}
|
||||
|
||||
function pushAll<T>(to: T[], from: T[]) {
|
||||
if (from) {
|
||||
for (var i = 0; i < from.length; i++) {
|
||||
to.push(from[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
connection.onCompletion(textDocumentPosition => {
|
||||
let document = documents.get(textDocumentPosition.textDocument.uri);
|
||||
let mode = languageModes.getModeAtPosition(document, textDocumentPosition.position);
|
||||
|
||||
@@ -7,8 +7,11 @@
|
||||
import { applyEdits } from '../utils/edits';
|
||||
import { TextDocument, Range, TextEdit, FormattingOptions } from 'vscode-languageserver-types';
|
||||
import { LanguageModes } from './languageModes';
|
||||
import { pushAll } from '../utils/arrays';
|
||||
|
||||
export function format(languageModes: LanguageModes, document: TextDocument, formatRange: Range, formattingOptions: FormattingOptions, enabledModes: { [mode: string]: boolean }) {
|
||||
let result: TextEdit[] = [];
|
||||
|
||||
// run the html formatter on the full range and pass the result content to the embedded formatters.
|
||||
// from the final content create a single edit
|
||||
// advantages of this approach are
|
||||
@@ -16,6 +19,25 @@ export function format(languageModes: LanguageModes, document: TextDocument, for
|
||||
// - correct initial indent for embedded formatters
|
||||
// - no worrying of overlapping edits
|
||||
|
||||
// make sure we start in html
|
||||
let allRanges = languageModes.getModesInRange(document, formatRange);
|
||||
let i = 0;
|
||||
let startPos = formatRange.start;
|
||||
while (i < allRanges.length && allRanges[i].mode.getId() !== 'html') {
|
||||
let range = allRanges[i];
|
||||
if (!range.attributeValue && range.mode.format) {
|
||||
let edits = range.mode.format(document, Range.create(startPos, range.end), formattingOptions);
|
||||
pushAll(result, edits);
|
||||
}
|
||||
startPos = range.end;
|
||||
i++;
|
||||
}
|
||||
if (i === allRanges.length) {
|
||||
return result;
|
||||
}
|
||||
// modify the range
|
||||
formatRange = Range.create(startPos, formatRange.end);
|
||||
|
||||
// perform a html format and apply changes to a new document
|
||||
let htmlMode = languageModes.getMode('html');
|
||||
let htmlEdits = htmlMode.format(document, formatRange, formattingOptions);
|
||||
@@ -40,14 +62,16 @@ export function format(languageModes: LanguageModes, document: TextDocument, for
|
||||
};
|
||||
|
||||
if (embeddedEdits.length === 0) {
|
||||
return htmlEdits;
|
||||
pushAll(result, htmlEdits);
|
||||
return result;
|
||||
}
|
||||
|
||||
// apply all embedded format edits and create a single edit for all changes
|
||||
let resultContent = applyEdits(newDocument, embeddedEdits);
|
||||
let resultReplaceText = resultContent.substring(document.offsetAt(formatRange.start), resultContent.length - afterFormatRangeLength);
|
||||
|
||||
return [TextEdit.replace(formatRange, resultReplaceText)];
|
||||
result.push(TextEdit.replace(formatRange, resultReplaceText));
|
||||
return result;
|
||||
} finally {
|
||||
languageModes.onDocumentRemoved(newDocument);
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body> </body>
|
||||
<body>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -17,6 +17,7 @@
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body> </body>
|
||||
<body>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -17,6 +17,7 @@
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body> </body>
|
||||
<body>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -1,4 +1,5 @@
|
||||
<app-route path="/module" element="page-module" bindRouter onUrlChange="updateModel"></app-route>
|
||||
|
||||
<script>
|
||||
Polymer({
|
||||
});
|
||||
|
||||
@@ -15,7 +15,7 @@ import { format } from '../modes/formatting';
|
||||
|
||||
suite('HTML Embedded Formatting', () => {
|
||||
|
||||
function assertFormat(value: string, expected: string, options?: any, formatOptions?: FormattingOptions): void {
|
||||
function assertFormat(value: string, expected: string, options?: any, formatOptions?: FormattingOptions, message?: string): void {
|
||||
var languageModes = getLanguageModes({ css: true, javascript: true });
|
||||
if (options) {
|
||||
languageModes.getAllModes().forEach(m => m.configure(options));
|
||||
@@ -41,13 +41,13 @@ suite('HTML Embedded Formatting', () => {
|
||||
let result = format(languageModes, document, range, formatOptions, { css: true, javascript: true });
|
||||
|
||||
let actual = applyEdits(document, result);
|
||||
assert.equal(actual, expected);
|
||||
assert.equal(actual, expected, message);
|
||||
}
|
||||
|
||||
function assertFormatWithFixture(fixtureName: string, expectedPath: string, options?: any, formatOptions?: FormattingOptions): void {
|
||||
let input = fs.readFileSync(path.join(__dirname, 'fixtures', 'inputs', fixtureName)).toString();
|
||||
let expected = fs.readFileSync(path.join(__dirname, 'fixtures', 'expected', expectedPath)).toString();
|
||||
assertFormat(input, expected, options, formatOptions);
|
||||
assertFormat(input, expected, options, formatOptions, expectedPath);
|
||||
}
|
||||
|
||||
test('HTML only', function (): any {
|
||||
@@ -64,10 +64,9 @@ suite('HTML Embedded Formatting', () => {
|
||||
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\n </script>\n</head>\n\n</html>');
|
||||
|
||||
assertFormat('<html><head>\n |<script>\nvar x=5;\n</script>|</head></html>', '<html><head>\n <script>\n var x = 5;\n\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('HTLM & Scripts - Fixtures', function() {
|
||||
test('HTLM & Scripts - Fixtures', function () {
|
||||
assertFormatWithFixture('19813.html', '19813.html');
|
||||
assertFormatWithFixture('19813.html', '19813-4spaces.html', void 0, FormattingOptions.create(4, true));
|
||||
assertFormatWithFixture('19813.html', '19813-tab.html', void 0, FormattingOptions.create(1, false));
|
||||
@@ -99,6 +98,11 @@ suite('HTML Embedded Formatting', () => {
|
||||
assertFormat('<html><head><script>\nvar x=1;\n</script></head></html>', '<html>\n\n<head>\n <script>\n var x = 1;\n\n </script>\n</head>\n\n</html>\n', options);
|
||||
});
|
||||
|
||||
test('Inside script', function (): any {
|
||||
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>');
|
||||
assertFormat('<html><head>\n <script>\n|var x=6;\nvar y= 9;|\n</script></head></html>', '<html><head>\n <script>\n var x = 6;\n var y = 9;\n</script></head></html>');
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
function applyEdits(document: TextDocument, edits: TextEdit[]): string {
|
||||
|
||||
13
extensions/html/server/src/utils/arrays.ts
Normal file
13
extensions/html/server/src/utils/arrays.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
'use strict';
|
||||
|
||||
export function pushAll<T>(to: T[], from: T[]) {
|
||||
if (from) {
|
||||
for (var i = 0; i < from.length; i++) {
|
||||
to.push(from[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user