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

Code before:
  // is valid for completion.
  isValid() {
    return !isBlank(this.prefix);
  }

  // Generate a CompletionContext based on this CompletionContext.
  // Simulate as if the user input new text based on this CompletionContext.
  forward(delta: string) {
    return new CompletionContext({
      filepath: this.filepath,
      language: this.language,
      text: this.text.substring(0, this.position) + delta + this.text.substring(this.position),
      position: this.position + delta.length,
      indentation: this.indentation,
      workspace: this.workspace,
      git: this.git,
      declarations: this.declarations,
      relevantSnippetsFromChangedFiles: this.relevantSnippetsFromChangedFiles,
      relevantSnippetsFromOpenedFiles: this.snippetsFromOpenedFiles,
      autoComplete: {
        completionItem: this.completionItem,
        insertPosition: this.insertPosition,
        insertSeg: this.insertSeg,
        currSeg: this.currSeg,
      },
    });
  }

  /**
   * The method handles the auto complete part of the completion request.
   * @param request completion request
   * @returns void
   */
  private handleAutoComplete(request: CompletionRequest): void {
    if (!request.autoComplete?.completionItem) return;
    this.completionItem = request.autoComplete.completionItem;
    this.currSeg = request.autoComplete.currSeg ?? "";
    this.insertSeg = request.autoComplete.insertSeg ?? "";

    const prefixText = request.text.slice(0, request.position);
    const lastIndex = prefixText.lastIndexOf(this.currSeg);

    if (lastIndex !== -1) {
      this.insertPosition = lastIndex + this.currSeg.length;

      this.text = request.text.slice(0, lastIndex) + this.completionItem + request.text.slice(this.insertPosition);

      this.position = lastIndex + this.completionItem.length;

      this.prefix = this.text.slice(0, this.position);
      this.suffix = this.text.slice(this.position);

Review comment (bug):
I believe the forward cache generating will be broken for the case with `selectedCompletionInfo`. We can fix it in next PRs.
```suggestion
      // FIXME: generate the context according to `selectedCompletionInfo`
```

Code after:
  // is valid for completion.
  isValid() {
    return !isBlank(this.prefix);
  }

  // Generate a CompletionContext based on this CompletionContext.
  // Simulate as if the user input new text based on this CompletionContext.
  // FIXME: generate the context according to `selectedCompletionInfo`
  forward(delta: string) {
    return new CompletionContext({
      filepath: this.filepath,
      language: this.language,
      text: this.text.substring(0, this.position) + delta + this.text.substring(this.position),
      position: this.position + delta.length,
      indentation: this.indentation,
      workspace: this.workspace,
      git: this.git,
      declarations: this.declarations,
      relevantSnippetsFromChangedFiles: this.relevantSnippetsFromChangedFiles,
      relevantSnippetsFromOpenedFiles: this.snippetsFromOpenedFiles,
      autoComplete: {
        completionItem: this.completionItem,
        insertPosition: this.insertPosition,
        insertSeg: this.insertSeg,
        currSeg: this.currSeg,
      },
    });
  }

  /**
   * The method handles the auto complete part of the completion request.
   * @param request completion request
   * @returns void
   */
  private handleAutoComplete(request: CompletionRequest): void {
    if (!request.autoComplete?.completionItem) return;
    this.completionItem = request.autoComplete.completionItem;
    this.currSeg = request.autoComplete.currSeg ?? "";
    this.insertSeg = request.autoComplete.insertSeg ?? "";

    // check if the completion item is the same as the insert segment
    if (!this.completionItem.startsWith(this.insertSeg)) {
      return;
    }

    const prefixText = request.text.slice(0, request.position);
    const lastIndex = prefixText.lastIndexOf(this.currSeg);

    if (lastIndex !== -1) {
      this.insertPosition = lastIndex + this.currSeg.length;