Repository: vscode
Issue: Merge Editor: Unlucky Diff
Labels: bug,merge-editor

Would be fixed by #169011.

![Code_-_Insiders_XlLJyvzVNt](https://github.com/microsoft/vscode/assets/2931520/e2378f20-b74d-4206-839c-6dcd04bdbfad)


```json
{
    "languageId": "typescript",
    "base": "\tprivate async _acceptNext(editor: ICodeEditor, getAcceptUntilIndex: (position: Position, text: string) => number): Promise<void> {\n\t\tif (editor.getModel() !== this.textModel) {\n\t\t\tthrow new BugIndicatingError();\n\t\t}\n\n\t\tconst state = this.state.get();\n\t\tif (!state || state.ghostText.isEmpty() || !state.inlineCompletion) {\n\t\t\treturn;\n\t\t}\n\t\tconst ghostText = state.ghostText;\n\t\tconst completion = state.inlineCompletion.toInlineCompletion(undefined);\n\n\t\tif (completion.snippetInfo || completion.filterText !== completion.insertText) {\n\t\t\t// not in WYSIWYG mode, partial commit might change completion, thus it is not supported\n\t\t\tawait this.accept(editor);\n\t\t\treturn;\n\t\t}\n\n\t\tconst firstPart = ghostText.parts[0];\n\t\tconst position = new Position(ghostText.lineNumber, firstPart.column);\n\t\tconst line = firstPart.lines.join('\\n');\n\t\tconst acceptUntilIndexExclusive = getAcceptUntilIndex(position, line);\n\n\t\tif (acceptUntilIndexExclusive === line.length && ghostText.parts.length === 1) {\n\t\t\tthis.accept(editor);\n\t\t\treturn;\n\t\t}\n\n\t\tconst partialText = line.substring(0, acceptUntilIndexExclusive);\n\n\t\t// Executing the edit might free the completion, so we have to hold a reference on it.\n\t\tcompletion.source.addRef();\n\t\ttry {\n\t\t\tthis._isAcceptingPartially = true;\n\t\t\ttry {\n\t\t\t\teditor.pushUndoStop();\n\t\t\t\teditor.executeEdits('inlineSuggestion.accept', [\n\t\t\t\t\tEditOperation.replace(Range.fromPositions(position), partialText),\n\t\t\t\t]);\n\t\t\t\tconst length = lengthOfText(partialText);\n\t\t\t\teditor.setPosition(addPositions(position, length), 'inlineCompletionPartialAccept');\n\t\t\t} finally {\n\t\t\t\tthis._isAcceptingPartially = false;\n\t\t\t}\n\n\t\t\tif (completion.source.provider.handlePartialAccept) {\n\t\t\t\tconst acceptedRange = Range.fromPositions(completion.range.getStartPosition(), addPositions(position, lengthOfText(partialText)));\n\t\t\t\t// This assumes that the inline completion and the model use the same EOL style.\n\t\t\t\tconst text = editor.getModel()!.getValueInRange(acceptedRange, EndOfLinePreference.LF);\n\t\t\t\tcompletion.source.provider.handlePartialAccept(\n\t\t\t\t\tcompletion.source.inlineCompletions,\n\t\t\t\t\tcompletion.sourceInlineCompletion,\n\t\t\t\t\ttext.length,\n\t\t\t\t);\n\t\t\t}\n\t\t} finally {\n\t\t\tcompletion.source.removeRef();\n\t\t}\n\t}\n\n\tpublic handleSuggestAccepted(item: SuggestItemInfo) {\n\t\tconst itemEdit = item.toSingleTextEdit().removeCommonPrefix(this.textModel);\n\t\tconst augmentedCompletion = this._computeAugmentedCompletion(itemEdit, undefined);\n\t\tif (!augmentedCompletion) { return; }\n\n\t\tconst inlineCompletion = augmentedCompletion.completion.inlineCompletion;\n\t\tinlineCompletion.source.provider.handlePartialAccept?.(\n\t\t\tinlineCompletion.source.inlineCompletions,\n\t\t\tinlineCompletion.sourceInlineCompletion,\n\t\t\titemEdit.text.length,\n\t\t);\n\t}\n}\n",
    "input1": "\tprivate async _acceptNext(editor: ICodeEditor, getAcceptUntilIndex: (position: Position, text: string) => number): Promise<void> {\n\t\tif (editor.getModel() !== this.textModel) {\n\t\t\tthrow new BugIndicatingError();\n\t\t}\n\n\t\tconst state = this.state.get();\n\t\tif (!state || state.primaryGhostText.isEmpty() || !state.inlineCompletion) {\n\t\t\treturn;\n\t\t}\n\t\tconst ghostText = state.primaryGhostText;\n\t\tconst completion = state.inlineCompletion.toInlineCompletion(undefined);\n\n\t\tif (completion.snippetInfo || completion.filterText !== completion.insertText) {\n\t\t\t// not in WYSIWYG mode, partial commit might change completion, thus it is not supported\n\t\t\tawait this.accept(editor);\n\t\t\treturn;\n\t\t}\n\n\t\tconst firstPart = ghostText.parts[0];\n\t\tconst ghostTextPos = new Position(ghostText.lineNumber, firstPart.column);\n\t\tconst ghostTextVal = firstPart.text;\n\t\tconst acceptUntilIndexExclusive = getAcceptUntilIndex(ghostTextPos, ghostTextVal);\n\t\tif (acceptUntilIndexExclusive === ghostTextVal.length && ghostText.parts.length === 1) {\n\t\t\tthis.accept(editor);\n\t\t\treturn;\n\t\t}\n\t\tconst partialGhostTextVal = ghostTextVal.substring(0, acceptUntilIndexExclusive);\n\n\t\tconst positions = this._positions.get();\n\t\tconst cursorPosition = positions[0];\n\n\t\t// Executing the edit might free the completion, so we have to hold a reference on it.\n\t\tcompletion.source.addRef();\n\t\ttry {\n\t\t\tthis._isAcceptingPartially = true;\n\t\t\ttry {\n\t\t\t\teditor.pushUndoStop();\n\t\t\t\tconst replaceRange = Range.fromPositions(cursorPosition, ghostTextPos);\n\t\t\t\tconst newText = editor.getModel()!.getValueInRange(replaceRange) + partialGhostTextVal;\n\t\t\t\tconst primaryEdit = new SingleTextEdit(replaceRange, newText);\n\t\t\t\tconst edits = [primaryEdit, ...getSecondaryEdits(this.textModel, positions, primaryEdit)];\n\t\t\t\tconst selections = getEndPositionsAfterApplying(edits).map(p => Selection.fromPositions(p));\n\t\t\t\teditor.executeEdits('inlineSuggestion.accept', edits.map(edit => EditOperation.replaceMove(edit.range, edit.text)));\n\t\t\t\teditor.setSelections(selections, 'inlineCompletionPartialAccept');\n\t\t\t} finally {\n\t\t\t\tthis._isAcceptingPartially = false;\n\t\t\t}\n\n\t\t\tif (completion.source.provider.handlePartialAccept) {\n\t\t\t\tconst acceptedRange = Range.fromPositions(completion.range.getStartPosition(), addPositions(ghostTextPos, lengthOfText(partialGhostTextVal)));\n\t\t\t\t// This assumes that the inline completion and the model use the same EOL style.\n\t\t\t\tconst text = editor.getModel()!.getValueInRange(acceptedRange, EndOfLinePreference.LF);\n\t\t\t\tcompletion.source.provider.handlePartialAccept(\n\t\t\t\t\tcompletion.source.inlineCompletions,\n\t\t\t\t\tcompletion.sourceInlineCompletion,\n\t\t\t\t\ttext.length,\n\t\t\t\t);\n\t\t\t}\n\t\t} finally {\n\t\t\tcompletion.source.removeRef();\n\t\t}\n\t}\n\n\tpublic handleSuggestAccepted(item: SuggestItemInfo) {\n\t\tconst itemEdit = item.toSingleTextEdit().removeCommonPrefix(this.textModel);\n\t\tconst augmentedCompletion = this._computeAugmentation(itemEdit, undefined);\n\t\tif (!augmentedCompletion) { return; }\n\n\t\tconst inlineCompletion = augmentedCompletion.completion.inlineCompletion;\n\t\tinlineCompletion.source.provider.handlePartialAccept?.(\n\t\t\tinlineCompletion.source.inlineCompletions,\n\t\t\tinlineCompletion.sourceInlineCompletion,\n\t\t\titemEdit.text.length,\n\t\t);\n\t}\n}\n\nexport function getSecondaryEdits(textModel: ITextModel, positions: readonly Position[], primaryEdit: SingleTextEdit): SingleTextEdit[] {\n\tif (positions.length === 1) {\n\t\t// No secondary cursor positions\n\t\treturn [];\n\t}\n\tconst primaryPosition = positions[0];\n\tconst secondaryPositions = positions.slice(1);\n\tconst primaryEditStartPosition = primaryEdit.range.getStartPosition();\n\tconst primaryEditEndPosition = primaryEdit.range.getEndPosition();\n\tconst replacedTextAfterPrimaryCursor = textModel.getValueInRange(\n\t\tRange.fromPositions(primaryPosition, primaryEditEndPosition)\n\t);\n\tconst positionWithinTextEdit = subtractPositions(primaryPosition, primaryEditStartPosition);\n\tif (positionWithinTextEdit.lineNumber < 1) {\n\t\tonUnexpectedError(new BugIndicatingError(\n\t\t\t`positionWithinTextEdit line number should be bigger than 0.\n\t\t\tInvalid subtraction between ${primaryPosition.toString()} and ${primaryEditStartPosition.toString()}`\n\t\t));\n\t\treturn [];\n\t}\n\tconst secondaryEditText = substringPos(primaryEdit.text, positionWithinTextEdit);\n\treturn secondaryPositions.map(pos => {\n\t\tconst posEnd = addPositions(subtractPositions(pos, primaryEditStartPosition), primaryEditEndPosition);\n\t\tconst textAfterSecondaryCursor = textModel.getValueInRange(\n\t\t\tRange.fromPositions(pos, posEnd)\n\t\t);\n\t\tconst l = commonPrefixLength(replacedTextAfterPrimaryCursor, textAfterSecondaryCursor);\n\t\tconst range = Range.fromPositions(pos, pos.delta(0, l));\n\t\treturn new SingleTextEdit(range, secondaryEditText);\n\t});\n}\n\nfunction substringPos(text: string, pos: Position): string {\n\tlet subtext = '';\n\tconst lines = splitLinesIncludeSeparators(text);\n\tfor (let i = pos.lineNumber - 1; i < lines.length; i++) {\n\t\tsubtext += lines[i].substring(i === pos.lineNumber - 1 ? pos.column - 1 : 0);\n\t}\n\treturn subtext;\n}\n\nfunction getEndPositionsAfterApplying(edits: readonly SingleTextEdit[]): Position[] {\n\tconst sortPerm = Permutation.createSortPermutation(edits, (edit1, edit2) => Range.compareRangesUsingStarts(edit1.range, edit2.range));\n\tconst sortedNewRanges = getNewRanges(sortPerm.apply(edits));\n\tconst newRanges = sortPerm.inverse().apply(sortedNewRanges);\n\treturn newRanges.map(range => range.getEndPosition());\n}\n",
    "input2": "\tprivate async _acceptNext(editor: ICodeEditor, getAcceptUntilIndex: (position: Position, text: string) => number, kind: PartialAcceptTriggerKind): Promise<void> {\n\t\tif (editor.getModel() !== this.textModel) {\n\t\t\tthrow new BugIndicatingError();\n\t\t}\n\n\t\tconst state = this.state.get();\n\t\tif (!state || state.ghostText.isEmpty() || !state.inlineCompletion) {\n\t\t\treturn;\n\t\t}\n\t\tconst ghostText = state.ghostText;\n\t\tconst completion = state.inlineCompletion.toInlineCompletion(undefined);\n\n\t\tif (completion.snippetInfo || completion.filterText !== completion.insertText) {\n\t\t\t// not in WYSIWYG mode, partial commit might change completion, thus it is not supported\n\t\t\tawait this.accept(editor);\n\t\t\treturn;\n\t\t}\n\n\t\tconst firstPart = ghostText.parts[0];\n\t\tconst position = new Position(ghostText.lineNumber, firstPart.column);\n\t\tconst line = firstPart.lines.join('\\n');\n\t\tconst acceptUntilIndexExclusive = getAcceptUntilIndex(position, line);\n\n\t\tif (acceptUntilIndexExclusive === line.length && ghostText.parts.length === 1) {\n\t\t\tthis.accept(editor);\n\t\t\treturn;\n\t\t}\n\n\t\tconst partialText = line.substring(0, acceptUntilIndexExclusive);\n\n\t\t// Executing the edit might free the completion, so we have to hold a reference on it.\n\t\tcompletion.source.addRef();\n\t\ttry {\n\t\t\tthis._isAcceptingPartially = true;\n\t\t\ttry {\n\t\t\t\teditor.pushUndoStop();\n\t\t\t\teditor.executeEdits('inlineSuggestion.accept', [\n\t\t\t\t\tEditOperation.replace(Range.fromPositions(position), partialText),\n\t\t\t\t]);\n\t\t\t\tconst length = lengthOfText(partialText);\n\t\t\t\teditor.setPosition(addPositions(position, length), 'inlineCompletionPartialAccept');\n\t\t\t} finally {\n\t\t\t\tthis._isAcceptingPartially = false;\n\t\t\t}\n\n\t\t\tif (completion.source.provider.handlePartialAccept) {\n\t\t\t\tconst acceptedRange = Range.fromPositions(completion.range.getStartPosition(), addPositions(position, lengthOfText(partialText)));\n\t\t\t\t// This assumes that the inline completion and the model use the same EOL style.\n\t\t\t\tconst text = editor.getModel()!.getValueInRange(acceptedRange, EndOfLinePreference.LF);\n\t\t\t\tcompletion.source.provider.handlePartialAccept(\n\t\t\t\t\tcompletion.source.inlineCompletions,\n\t\t\t\t\tcompletion.sourceInlineCompletion,\n\t\t\t\t\ttext.length,\n\t\t\t\t\t{\n\t\t\t\t\t\tkind,\n\t\t\t\t\t}\n\t\t\t\t);\n\t\t\t}\n\t\t} finally {\n\t\t\tcompletion.source.removeRef();\n\t\t}\n\t}\n\n\tpublic handleSuggestAccepted(item: SuggestItemInfo) {\n\t\tconst itemEdit = item.toSingleTextEdit().removeCommonPrefix(this.textModel);\n\t\tconst augmentedCompletion = this._computeAugmentedCompletion(itemEdit, undefined);\n\t\tif (!augmentedCompletion) { return; }\n\n\t\tconst inlineCompletion = augmentedCompletion.completion.inlineCompletion;\n\t\tinlineCompletion.source.provider.handlePartialAccept?.(\n\t\t\tinlineCompletion.source.inlineCompletions,\n\t\t\tinlineCompletion.sourceInlineCompletion,\n\t\t\titemEdit.text.length,\n\t\t\t{\n\t\t\t\tkind: PartialAcceptTriggerKind.Suggest,\n\t\t\t}\n\t\t);\n\t}\n}\n",
    "result": "\tprivate async _acceptNext(editor: ICodeEditor, getAcceptUntilIndex: (position: Position, text: string) => number, kind: PartialAcceptTriggerKind): Promise<void> {\r\n\t\tif (editor.getModel() !== this.textModel) {\r\n\t\t\tthrow new BugIndicatingError();\r\n\t\t}\r\n\r\n\t\tconst state = this.state.get();\r\n\t\tif (!state || state.primaryGhostText.isEmpty() || !state.inlineCompletion) {\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tconst ghostText = state.primaryGhostText;\r\n\t\tconst completion = state.inlineCompletion.toInlineCompletion(undefined);\r\n\r\n\t\tif (completion.snippetInfo || completion.filterText !== completion.insertText) {\r\n\t\t\t// not in WYSIWYG mode, partial commit might change completion, thus it is not supported\r\n\t\t\tawait this.accept(editor);\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tconst firstPart = ghostText.parts[0];\r\n\t\tconst ghostTextPos = new Position(ghostText.lineNumber, firstPart.column);\r\n\t\tconst ghostTextVal = firstPart.text;\r\n\t\tconst acceptUntilIndexExclusive = getAcceptUntilIndex(ghostTextPos, ghostTextVal);\r\n\t\tif (acceptUntilIndexExclusive === ghostTextVal.length && ghostText.parts.length === 1) {\r\n\t\t\tthis.accept(editor);\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tconst partialGhostTextVal = ghostTextVal.substring(0, acceptUntilIndexExclusive);\r\n\r\n\t\tconst positions = this._positions.get();\r\n\t\tconst cursorPosition = positions[0];\r\n\r\n\t\t// Executing the edit might free the completion, so we have to hold a reference on it.\r\n\t\tcompletion.source.addRef();\r\n\t\ttry {\r\n\t\t\tthis._isAcceptingPartially = true;\r\n\t\t\ttry {\r\n\t\t\t\teditor.pushUndoStop();\r\n\t\t\t\tconst replaceRange = Range.fromPositions(cursorPosition, ghostTextPos);\r\n\t\t\t\tconst newText = editor.getModel()!.getValueInRange(replaceRange) + partialGhostTextVal;\r\n\t\t\t\tconst primaryEdit = new SingleTextEdit(replaceRange, newText);\r\n\t\t\t\tconst edits = [primaryEdit, ...getSecondaryEdits(this.textModel, positions, primaryEdit)];\r\n\t\t\t\tconst selections = getEndPositionsAfterApplying(edits).map(p => Selection.fromPositions(p));\r\n\t\t\t\teditor.executeEdits('inlineSuggestion.accept', edits.map(edit => EditOperation.replaceMove(edit.range, edit.text)));\r\n\t\t\t\teditor.setSelections(selections, 'inlineCompletionPartialAccept');\r\n\t\t\t} finally {\r\n\t\t\t\tthis._isAcceptingPartially = false;\r\n\t\t\t}\r\n\r\n\t\t\tif (completion.source.provider.handlePartialAccept) {\r\n\t\t\t\tconst acceptedRange = Range.fromPositions(completion.range.getStartPosition(), addPositions(ghostTextPos, lengthOfText(partialGhostTextVal)));\r\n\t\t\t\t// This assumes that the inline completion and the model use the same EOL style.\r\n\t\t\t\tconst text = editor.getModel()!.getValueInRange(acceptedRange, EndOfLinePreference.LF);\r\n\t\t\t\tcompletion.source.provider.handlePartialAccept(\r\n\t\t\t\t\tcompletion.source.inlineCompletions,\r\n\t\t\t\t\tcompletion.sourceInlineCompletion,\r\n\t\t\t\t\ttext.length,\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\tkind,\r\n\t\t\t\t\t}\r\n\t\t\t\t);\r\n\t\t\t}\r\n\t\t} finally {\r\n\t\t\tcompletion.source.removeRef();\r\n\t\t}\r\n\t}\r\n\r\n\tpublic handleSuggestAccepted(item: SuggestItemInfo) {\r\n\t\tconst itemEdit = item.toSingleTextEdit().removeCommonPrefix(this.textModel);\r\n\t\tconst augmentedCompletion = this._computeAugmentation(itemEdit, undefined);\r\n\t\tif (!augmentedCompletion) { return; }\r\n\r\n\t\tconst inlineCompletion = augmentedCompletion.completion.inlineCompletion;\r\n\t\tinlineCompletion.source.provider.handlePartialAccept?.(\r\n\t\t\tinlineCompletion.source.inlineCompletions,\r\n\t\t\tinlineCompletion.sourceInlineCompletion,\r\n\t\t\titemEdit.text.length,\r\n\t\t\t{\r\n\t\t\t\tkind: PartialAcceptTriggerKind.Suggest,\r\n\t\t\t}\r\n\t\t);\r\n\t}\r\n}\r\n\r\nexport function getSecondaryEdits(textModel: ITextModel, positions: readonly Position[], primaryEdit: SingleTextEdit): SingleTextEdit[] {\r\n\tif (positions.length === 1) {\r\n\t\t// No secondary cursor positions\r\n\t\treturn [];\r\n\t}\r\n\tconst primaryPosition = positions[0];\r\n\tconst secondaryPositions = positions.slice(1);\r\n\tconst primaryEditStartPosition = primaryEdit.range.getStartPosition();\r\n\tconst primaryEditEndPosition = primaryEdit.range.getEndPosition();\r\n\tconst replacedTextAfterPrimaryCursor = textModel.getValueInRange(\r\n\t\tRange.fromPositions(primaryPosition, primaryEditEndPosition)\r\n\t);\r\n\tconst positionWithinTextEdit = subtractPositions(primaryPosition, primaryEditStartPosition);\r\n\tif (positionWithinTextEdit.lineNumber < 1) {\r\n\t\tonUnexpectedError(new BugIndicatingError(\r\n\t\t\t`positionWithinTextEdit line number should be bigger than 0.\r\n\t\t\tInvalid subtraction between ${primaryPosition.toString()} and ${primaryEditStartPosition.toString()}`\r\n\t\t));\r\n\t\treturn [];\r\n\t}\r\n\tconst secondaryEditText = substringPos(primaryEdit.text, positionWithinTextEdit);\r\n\treturn secondaryPositions.map(pos => {\r\n\t\tconst posEnd = addPositions(subtractPositions(pos, primaryEditStartPosition), primaryEditEndPosition);\r\n\t\tconst textAfterSecondaryCursor = textModel.getValueInRange(\r\n\t\t\tRange.fromPositions(pos, posEnd)\r\n\t\t);\r\n\t\tconst l = commonPrefixLength(replacedTextAfterPrimaryCursor, textAfterSecondaryCursor);\r\n\t\tconst range = Range.fromPositions(pos, pos.delta(0, l));\r\n\t\treturn new SingleTextEdit(range, secondaryEditText);\r\n\t});\r\n}\r\n\r\nfunction substringPos(text: string, pos: Position): string {\r\n\tlet subtext = '';\r\n\tconst lines = splitLinesIncludeSeparators(text);\r\n\tfor (let i = pos.lineNumber - 1; i < lines.length; i++) {\r\n\t\tsubtext += lines[i].substring(i === pos.lineNumber - 1 ? pos.column - 1 : 0);\r\n\t}\r\n\treturn subtext;\r\n}\r\n\r\nfunction getEndPositionsAfterApplying(edits: readonly SingleTextEdit[]): Position[] {\r\n\tconst sortPerm = Permutation.createSortPermutation(edits, (edit1, edit2) => Range.compareRangesUsingStarts(edit1.range, edit2.range));\r\n\tconst sortedNewRanges = getNewRanges(sortPerm.apply(edits));\r\n\tconst newRanges = sortPerm.inverse().apply(sortedNewRanges);\r\n\treturn newRanges.map(range => range.getEndPosition());\r\n}\r\n",
    "initialResult": "\tprivate async _acceptNext(editor: ICodeEditor, getAcceptUntilIndex: (position: Position, text: string) => number, kind: PartialAcceptTriggerKind): Promise<void> {\r\n\t\tif (editor.getModel() !== this.textModel) {\r\n\t\t\tthrow new BugIndicatingError();\r\n\t\t}\r\n\r\n\t\tconst state = this.state.get();\r\n\t\tif (!state || state.primaryGhostText.isEmpty() || !state.inlineCompletion) {\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tconst ghostText = state.primaryGhostText;\r\n\t\tconst completion = state.inlineCompletion.toInlineCompletion(undefined);\r\n\r\n\t\tif (completion.snippetInfo || completion.filterText !== completion.insertText) {\r\n\t\t\t// not in WYSIWYG mode, partial commit might change completion, thus it is not supported\r\n\t\t\tawait this.accept(editor);\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tconst firstPart = ghostText.parts[0];\r\n\t\tconst ghostTextPos = new Position(ghostText.lineNumber, firstPart.column);\r\n\t\tconst ghostTextVal = firstPart.text;\r\n\t\tconst acceptUntilIndexExclusive = getAcceptUntilIndex(ghostTextPos, ghostTextVal);\r\n\t\tif (acceptUntilIndexExclusive === ghostTextVal.length && ghostText.parts.length === 1) {\r\n\t\t\tthis.accept(editor);\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tconst partialGhostTextVal = ghostTextVal.substring(0, acceptUntilIndexExclusive);\r\n\r\n\t\tconst positions = this._positions.get();\r\n\t\tconst cursorPosition = positions[0];\r\n\r\n\t\t// Executing the edit might free the completion, so we have to hold a reference on it.\r\n\t\tcompletion.source.addRef();\r\n\t\ttry {\r\n\t\t\tthis._isAcceptingPartially = true;\r\n\t\t\ttry {\r\n\t\t\t\teditor.pushUndoStop();\r\n\t\t\t\tconst replaceRange = Range.fromPositions(cursorPosition, ghostTextPos);\r\n\t\t\t\tconst newText = editor.getModel()!.getValueInRange(replaceRange) + partialGhostTextVal;\r\n\t\t\t\tconst primaryEdit = new SingleTextEdit(replaceRange, newText);\r\n\t\t\t\tconst edits = [primaryEdit, ...getSecondaryEdits(this.textModel, positions, primaryEdit)];\r\n\t\t\t\tconst selections = getEndPositionsAfterApplying(edits).map(p => Selection.fromPositions(p));\r\n\t\t\t\teditor.executeEdits('inlineSuggestion.accept', edits.map(edit => EditOperation.replaceMove(edit.range, edit.text)));\r\n\t\t\t\teditor.setSelections(selections, 'inlineCompletionPartialAccept');\r\n\t\t\t} finally {\r\n\t\t\t\tthis._isAcceptingPartially = false;\r\n\t\t\t}\r\n\r\n\t\t\tif (completion.source.provider.handlePartialAccept) {\r\n\t\t\t\tconst acceptedRange = Range.fromPositions(completion.range.getStartPosition(), addPositions(ghostTextPos, lengthOfText(partialGhostTextVal)));\r\n\t\t\t\t// This assumes that the inline completion and the model use the same EOL style.\r\n\t\t\t\tconst text = editor.getModel()!.getValueInRange(acceptedRange, EndOfLinePreference.LF);\r\n\t\t\t\tcompletion.source.provider.handlePartialAccept(\r\n\t\t\t\t\tcompletion.source.inlineCompletions,\r\n\t\t\t\t\tcompletion.sourceInlineCompletion,\r\n\t\t\t\t\ttext.length,\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\tkind,\r\n\t\t\t\t\t}\r\n\t\t\t\t);\r\n\t\t\t}\r\n\t\t} finally {\r\n\t\t\tcompletion.source.removeRef();\r\n\t\t}\r\n\t}\r\n\r\n\tpublic handleSuggestAccepted(item: SuggestItemInfo) {\r\n\t\tconst itemEdit = item.toSingleTextEdit().removeCommonPrefix(this.textModel);\r\n\t\tconst augmentedCompletion = this._computeAugmentation(itemEdit, undefined);\r\n\t\tif (!augmentedCompletion) { return; }\r\n\r\n\t\tconst inlineCompletion = augmentedCompletion.completion.inlineCompletion;\r\n\t\tinlineCompletion.source.provider.handlePartialAccept?.(\r\n\t\t\tinlineCompletion.source.inlineCompletions,\r\n\t\t\tinlineCompletion.sourceInlineCompletion,\r\n\t\t\titemEdit.text.length,\r\n\t\t\t{\r\n\t\t\t\tkind: PartialAcceptTriggerKind.Suggest,\r\n\t\t\t}\r\n\t\t);\r\n\t}\r\n}\r\n\r\nexport function getSecondaryEdits(textModel: ITextModel, positions: readonly Position[], primaryEdit: SingleTextEdit): SingleTextEdit[] {\r\n\tif (positions.length === 1) {\r\n\t\t// No secondary cursor positions\r\n\t\treturn [];\r\n\t}\r\n\tconst primaryPosition = positions[0];\r\n\tconst secondaryPositions = positions.slice(1);\r\n\tconst primaryEditStartPosition = primaryEdit.range.getStartPosition();\r\n\tconst primaryEditEndPosition = primaryEdit.range.getEndPosition();\r\n\tconst replacedTextAfterPrimaryCursor = textModel.getValueInRange(\r\n\t\tRange.fromPositions(primaryPosition, primaryEditEndPosition)\r\n\t);\r\n\tconst positionWithinTextEdit = subtractPositions(primaryPosition, primaryEditStartPosition);\r\n\tif (positionWithinTextEdit.lineNumber < 1) {\r\n\t\tonUnexpectedError(new BugIndicatingError(\r\n\t\t\t`positionWithinTextEdit line number should be bigger than 0.\r\n\t\t\tInvalid subtraction between ${primaryPosition.toString()} and ${primaryEditStartPosition.toString()}`\r\n\t\t));\r\n\t\treturn [];\r\n\t}\r\n\tconst secondaryEditText = substringPos(primaryEdit.text, positionWithinTextEdit);\r\n\treturn secondaryPositions.map(pos => {\r\n\t\tconst posEnd = addPositions(subtractPositions(pos, primaryEditStartPosition), primaryEditEndPosition);\r\n\t\tconst textAfterSecondaryCursor = textModel.getValueInRange(\r\n\t\t\tRange.fromPositions(pos, posEnd)\r\n\t\t);\r\n\t\tconst l = commonPrefixLength(replacedTextAfterPrimaryCursor, textAfterSecondaryCursor);\r\n\t\tconst range = Range.fromPositions(pos, pos.delta(0, l));\r\n\t\treturn new SingleTextEdit(range, secondaryEditText);\r\n\t});\r\n}\r\n\r\nfunction substringPos(text: string, pos: Position): string {\r\n\tlet subtext = '';\r\n\tconst lines = splitLinesIncludeSeparators(text);\r\n\tfor (let i = pos.lineNumber - 1; i < lines.length; i++) {\r\n\t\tsubtext += lines[i].substring(i === pos.lineNumber - 1 ? pos.column - 1 : 0);\r\n\t}\r\n\treturn subtext;\r\n}\r\n\r\nfunction getEndPositionsAfterApplying(edits: readonly SingleTextEdit[]): Position[] {\r\n\tconst sortPerm = Permutation.createSortPermutation(edits, (edit1, edit2) => Range.compareRangesUsingStarts(edit1.range, edit2.range));\r\n\tconst sortedNewRanges = getNewRanges(sortPerm.apply(edits));\r\n\tconst newRanges = sortPerm.inverse().apply(sortedNewRanges);\r\n\treturn newRanges.map(range => range.getEndPosition());\r\n}\r\n"
}
```