diff --git a/src/languageservice/services/yamlOnTypeFormatting.ts b/src/languageservice/services/yamlOnTypeFormatting.ts index 27f80dcda..cedb48b75 100644 --- a/src/languageservice/services/yamlOnTypeFormatting.ts +++ b/src/languageservice/services/yamlOnTypeFormatting.ts @@ -46,8 +46,33 @@ export function doDocumentOnTypeFormatting( return [TextEdit.insert(position, ' '.repeat(params.options.tabSize))]; } - if (previousLine.includes(' - ') && !previousLine.includes(': ')) { - return [TextEdit.insert(position, '- ')]; + if (previousLine.trimStart().startsWith('-') && !previousLine.includes(': ')) { + const indentation = previousLine.slice(0, previousLine.length - previousLine.trimStart().length); + const expectedText = indentation + '- '; + const currentLine = tb.getLineContent(position.line).replace('\r', '').replace('\n', ''); + if (currentLine.trim().length !== 0) { + // non-space content, do nothing + return; + } + if (currentLine === expectedText) { + // already right; do nothing + return; + } + if (position.character >= indentation.length) { + // The client already auto-indented the line and placed the cursor at + // (or past) the indentation; just append the dash. + return [TextEdit.insert(Position.create(position.line, currentLine.length), '- ')]; + } + // The client sent a position before the existing whitespace + // (e.g. lsp-mode, eglot send column 0 even though the line already has + // auto-indented spaces). Replace the whole line content so the + // result is always correct. + return [ + TextEdit.replace( + Range.create(Position.create(position.line, 0), Position.create(position.line, currentLine.length)), + expectedText + ), + ]; } if (previousLine.includes(' - ') && previousLine.includes(': ')) { diff --git a/test/yamlOnTypeFormatting.test.ts b/test/yamlOnTypeFormatting.test.ts index e42ea779e..3c56365a9 100644 --- a/test/yamlOnTypeFormatting.test.ts +++ b/test/yamlOnTypeFormatting.test.ts @@ -40,6 +40,22 @@ describe('YAML On Type Formatter', () => { expect(result[0]).to.eqls(TextEdit.insert(pos, '- ')); }); + it('should preserve list element indentation after newline', () => { + const doc = setupTextDocument('test:\n - hello\n - world\n'); + const pos = Position.create(3, 0); + const params = createParams(pos); + const result = doDocumentOnTypeFormatting(doc, params); + expect(result[0]).to.eql(TextEdit.insert(pos, ' - ')); + }); + + it('should align list element dash after existing client-side indentation', () => { + const doc = setupTextDocument('test:\n - hello\n - world\n '); + const pos = Position.create(3, 0); + const params = createParams(pos); + const result = doDocumentOnTypeFormatting(doc, params); + expect(result[0]).to.eql(TextEdit.replace(Range.create(Position.create(3, 0), Position.create(3, 2)), ' - ')); + }); + it('should add indentation for mapping in array', () => { const doc = setupTextDocument('some:\n - arr:\n '); const pos = Position.create(2, 2);