mirror of
https://github.com/Microsoft/vscode
synced 2024-08-27 21:09:43 +00:00
[html] Format onPaste issues with HTML. Fixes #21218
This commit is contained in:
parent
2ef2602cc8
commit
ef9e03c8ad
4
extensions/html/server/npm-shrinkwrap.json
generated
4
extensions/html/server/npm-shrinkwrap.json
generated
|
@ -8,9 +8,9 @@
|
|||
"resolved": "https://registry.npmjs.org/vscode-css-languageservice/-/vscode-css-languageservice-2.0.1.tgz"
|
||||
},
|
||||
"vscode-html-languageservice": {
|
||||
"version": "2.0.2-next.2",
|
||||
"version": "2.0.3",
|
||||
"from": "vscode-html-languageservice@next",
|
||||
"resolved": "https://registry.npmjs.org/vscode-html-languageservice/-/vscode-html-languageservice-2.0.2-next.2.tgz"
|
||||
"resolved": "https://registry.npmjs.org/vscode-html-languageservice/-/vscode-html-languageservice-2.0.3.tgz"
|
||||
},
|
||||
"vscode-jsonrpc": {
|
||||
"version": "3.1.0-alpha.1",
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
},
|
||||
"dependencies": {
|
||||
"vscode-css-languageservice": "^2.0.1",
|
||||
"vscode-html-languageservice": "^2.0.2-next.2",
|
||||
"vscode-html-languageservice": "^2.0.3",
|
||||
"vscode-languageserver": "^3.1.0-alpha.1",
|
||||
"vscode-nls": "^2.0.2",
|
||||
"vscode-uri": "^1.0.0"
|
||||
|
|
|
@ -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]);
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue