diff --git a/extensions/html/server/src/modes/formatting.ts b/extensions/html/server/src/modes/formatting.ts index 3c39a703b59..54bbcd25772 100644 --- a/extensions/html/server/src/modes/formatting.ts +++ b/extensions/html/server/src/modes/formatting.ts @@ -5,13 +5,27 @@ 'use strict'; import { applyEdits } from '../utils/edits'; -import { TextDocument, Range, TextEdit, FormattingOptions } from 'vscode-languageserver-types'; +import { TextDocument, Range, TextEdit, FormattingOptions, Position } from 'vscode-languageserver-types'; import { LanguageModes } from './languageModes'; import { pushAll } from '../utils/arrays'; +import { isEOL } from '../utils/strings'; export function format(languageModes: LanguageModes, document: TextDocument, formatRange: Range, formattingOptions: FormattingOptions, enabledModes: { [mode: string]: boolean }) { let result: TextEdit[] = []; + let endPos = formatRange.end; + let endOffset = document.offsetAt(endPos); + let content = document.getText(); + if (endPos.character === 0 && endPos.line > 0 && endOffset !== content.length) { + // if selection ends after a new line, exclude that new line + let prevLineStart = document.offsetAt(Position.create(endPos.line - 1, 0)); + while (isEOL(content, endOffset - 1) && endOffset > prevLineStart) { + endOffset--; + } + formatRange = Range.create(formatRange.start, document.positionAt(endOffset)); + } + + // 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 diff --git a/extensions/html/server/src/test/formatting.test.ts b/extensions/html/server/src/test/formatting.test.ts index 81fc9954ab3..ea4ecf33153 100644 --- a/extensions/html/server/src/test/formatting.test.ts +++ b/extensions/html/server/src/test/formatting.test.ts @@ -103,6 +103,10 @@ suite('HTML Embedded Formatting', () => { assertFormat('\n ', '\n '); }); + test('Range after new line', function (): any { + assertFormat('\n |\n|', '\n \n'); + }); + }); function applyEdits(document: TextDocument, edits: TextEdit[]): string { diff --git a/extensions/html/server/src/utils/strings.ts b/extensions/html/server/src/utils/strings.ts index f04a5744fab..75404682387 100644 --- a/extensions/html/server/src/utils/strings.ts +++ b/extensions/html/server/src/utils/strings.ts @@ -57,9 +57,12 @@ export function isWhitespaceOnly(str: string) { return /^\s*$/.test(str); } +export function isEOL(content: string, offset: number) { + return isNewlineCharacter(content.charCodeAt(offset)); +} const CR = '\r'.charCodeAt(0); const NL = '\n'.charCodeAt(0); -function isNewlineCharacter(charCode: number) { +export function isNewlineCharacter(charCode: number) { return charCode === CR || charCode === NL; } \ No newline at end of file