Repository: motion-canvas/motion-canvas
File: packages/2d/src/lib/components/Code.ts (TypeScript)

Code before:

  /**
   * Find the first code range that matches the given pattern.
   *
   * @param pattern - Either a string or a regular expression to match.
   */
  public findFirstRange(pattern: string | RegExp): CodeRange {
    return findAllCodeRanges(this.parsed(), pattern, 1)[0] ?? [[0, 0], [0, 0]];
  }

  /**
   * Find the last code range that matches the given pattern.
   *
   * @param pattern - Either a string or a regular expression to match.
   */
  public findLastRange(pattern: string | RegExp): CodeRange {
    return findAllCodeRanges(this.parsed(), pattern).at(-1) ?? [[0, 0], [0, 0]];
  }

  protected override desiredSize(): SerializedVector2<DesiredLength> {
    this.requestFontUpdate();
    const context = this.cacheCanvas();
    const code = this.code();

    context.save();
    this.applyStyle(context);
    context.font = this.styles.font;
    this.cursor.setupMeasure(context);
    this.cursor.measureSize(code);
    const size = this.cursor.getSize();
    context.restore();

    return size;
  }

  protected override draw(context: CanvasRenderingContext2D): void {
    this.requestFontUpdate();
    this.applyStyle(context);
    const code = this.code();
    const size = this.computedSize();

    context.translate(-size.width / 2, -size.height / 2);
    context.font = this.styles.font;
    context.textBaseline = 'top';

    this.cursor.setupDraw(context);
    this.cursor.drawScope(code);
  }

  protected override collectAsyncResources(): void {
    super.collectAsyncResources();

Review comment (suggestion):
Is there optimization we should worry about here? Normally `findLast` or `findFirst` are used to avoid a full string iteration if possible, although I'm not sure it's worth it here.

Code after:
  public findAllRanges(pattern: string | RegExp): CodeRange[] {
    return findAllCodeRanges(this.parsed(), pattern);
  }

  /**
   * Find the first code range that matches the given pattern.
   *
   * @param pattern - Either a string or a regular expression to match.
   */
  public findFirstRange(pattern: string | RegExp): CodeRange {
    return (
      findAllCodeRanges(this.parsed(), pattern, 1)[0] ?? [
        [0, 0],
        [0, 0],
      ]
    );
  }

  /**
   * Find the last code range that matches the given pattern.
   *
   * @param pattern - Either a string or a regular expression to match.
   */
  public findLastRange(pattern: string | RegExp): CodeRange {
    return (
      findAllCodeRanges(this.parsed(), pattern).at(-1) ?? [
        [0, 0],
        [0, 0],
      ]
    );
  }

  /**
   * Return the bounding box of the given point (character) in the code.
   *
   * @remarks
   * The returned bound box is in local space of the `Code` node.
   *
   * @param point - The point to get the bounding box for.
   */
  public getPointBbox(point: CodePoint): BBox {
    const [line, column] = point;
    const drawingInfo = this.drawingInfo();
    let match: CodeFragmentDrawingInfo | undefined;
    for (const info of drawingInfo.fragments) {
      if (info.cursor.y < line) {
        match = info;
        continue;
      }

      if (info.cursor.y === line && info.cursor.x < column) {