Repository: TabbyML/tabby
File: clients/tabby-agent/src/codeCompletion/index.ts (TypeScript)

Code before:
  ): Promise<{ request: CompletionRequest; additionalPrefixLength?: number } | null> {
    const result = await this.textDocumentPositionParamsToCompletionRequest(params, token);
    if (!result) {
      return null;
    }
    result.request.manually = params.context?.triggerKind === InlineCompletionTriggerKind.Invoked;

    if (params.context.selectedCompletionInfo) {
      const customContext = params.context as {
        triggerKind: InlineCompletionTriggerKind;
        selectedCompletionInfo?: {
          range: [{ line: number; character: number }, { line: number; character: number }];
          text: string;
        };
      };
      if (!customContext.selectedCompletionInfo) {
        return result;
      }
      const info = customContext.selectedCompletionInfo;

      const rangeLength = info.range[1].character - info.range[0].character;
      const currentText = info.text.substring(0, rangeLength);

      result.request.autoComplete = {
        completionItem: info.text,
        insertSeg: info.text.slice(currentText.length),
        currSeg: currentText,
      };
      this.logger.debug("received AutoCompleteWidgetItem: " + JSON.stringify(params.context.selectedCompletionInfo));
    }
    return result;
  }

  private toCompletionList(
    solution: CompletionSolution,
    documentPosition: TextDocumentPositionParams,
    additionalPrefixLength: number = 0,
  ): CompletionList | null {
    const { textDocument, position } = documentPosition;
    const document = this.documents.get(textDocument.uri);
    if (!document) {
      return null;
    }

    // Get word prefix if cursor is at end of a word
    const linePrefix = document.getText({
      start: { line: position.line, character: 0 },
      end: position,
    });
    const wordPrefix = linePrefix.match(/(\w+)$/)?.[0] ?? "";


Review comment (bug):
I think the handler for `selectedCompletionInfo` could be incorrect for the case of:  The `selectedCompletionInfo` can refer to a replace edit.   
For example, the user can input `cnsl` for the autocomplete of `console`, and `selectedCompletionInfo.range` will be the range of `cnsl` and `selectedCompletionInfo.text` will be `console`.

Code after:
    const result = await this.textDocumentPositionParamsToCompletionRequest(params, token);
    if (!result) {
      return null;
    }
    result.request.manually = params.context?.triggerKind === InlineCompletionTriggerKind.Invoked;

    if (params.context.selectedCompletionInfo) {
      const customContext = params.context as {
        triggerKind: InlineCompletionTriggerKind;
        selectedCompletionInfo?: {
          range: [{ line: number; character: number }, { line: number; character: number }];
          text: string;
        };
      };
      if (!customContext.selectedCompletionInfo) {
        return result;
      }
      const info = customContext.selectedCompletionInfo;

      const rangeLength = info.range[1].character - info.range[0].character;
      const currentText = info.text.substring(0, rangeLength);

      result.request.autoComplete = {
        completionItem: info.text,
        insertSeg: info.text.slice(currentText.length),
        currSeg: currentText,
      };
      this.logger.debug("received AutoCompleteWidgetItem: " + JSON.stringify(params.context.selectedCompletionInfo));
    }
    return result;
  }

  private toCompletionList(
    solution: CompletionSolution,
    documentPosition: TextDocumentPositionParams,
    additionalPrefixLength: number = 0,
  ): CompletionList | null {
    const { textDocument, position } = documentPosition;
    const document = this.documents.get(textDocument.uri);
    if (!document) {
      return null;
    }

    // Get word prefix if cursor is at end of a word
    const linePrefix = document.getText({
      start: { line: position.line, character: 0 },
      end: position,
    });
    const wordPrefix = linePrefix.match(/(\w+)$/)?.[0] ?? "";

    const list = solution.toInlineCompletionList();