Repository: sst/opentui
File: packages/core/src/renderer.ts (TypeScript)

Code before:

    this.lastOverRenderable = hitRenderable
    this.lastOverRenderableNum = hitId

    // Fire over on new element
    if (hitRenderable) {
      const event = new MouseEvent(hitRenderable, {
        ...baseEvent,
        type: "over",
      })
      hitRenderable.processMouseEvent(event)
    }

    this.updateMousePointerOnHover(hitRenderable)
  }

  private updateMousePointerOnHover(renderable: Renderable | undefined): void {
    const cursorStyle = renderable?.getCurrentHoverCursorStyle()
    if (cursorStyle) {
      this.setMousePointer(cursorStyle)
    } else {
      this.resetMousePointer()
    }
  }

  public setMousePointer(shape: MousePointerStyle): void {
    if (this._currentMousePointerStyle === shape) return
    this._currentMousePointerStyle = shape
    this.writeOut(ANSI.setMousePointer(shape))
  }

  public resetMousePointer(): void {
    if (this._currentMousePointerStyle === undefined) return
    this._currentMousePointerStyle = undefined
    this.writeOut(ANSI.resetMousePointer)
  }

  public hitTest(x: number, y: number): number {
    return this.lib.checkHit(this.rendererPtr, x, y)
  }

  private takeMemorySnapshot(): void {
    if (this._isDestroyed) return

    const memoryUsage = process.memoryUsage()
    this.lastMemorySnapshot = {
      heapUsed: memoryUsage.heapUsed,
      heapTotal: memoryUsage.heapTotal,
      arrayBuffers: memoryUsage.arrayBuffers,
    }


Review comment (suggestion):
There is a method `setCursorStyle` already, which takes options that could be adjusted. It's currently this:

```ts
 public static setCursorStyle(
    renderer: CliRenderer,
    style: CursorStyle,
    blinking: boolean = false,
    color?: RGBA,
  ): void {
```

It's messy, so we could make that proper like:

```ts
public static setCursorStyle(
    renderer: CliRenderer,
    options: CursorStyleOptions
  ): void {
```

Where the `CursorStyleOptions` become:

```ts
export interface cursorstyleoptions {
  style: "block" | "line" | "underline"
  blinking: boolean,
  color: RGBA,
  cursor: "default" | "pointer" | "text" | "crosshair" | "move" | "not-allowed"
}
```

Then it can be properly packed as FFI Struct in `zig-structs.ts` and passed down to zig, which can hold the cursor state and update the changed values.

Code after:
    this.lastOverRenderableNum = hitId

    // Fire over on new element
    if (hitRenderable) {
      const event = new MouseEvent(hitRenderable, {
        ...baseEvent,
        type: "over",
      })
      hitRenderable.processMouseEvent(event)
    }
  }
  public setMousePointer(style: MousePointerStyle): void {
    this._currentMousePointerStyle = style
    this.lib.setCursorStyleOptions(this.rendererPtr, { cursor: style })
  }

  public hitTest(x: number, y: number): number {
    return this.lib.checkHit(this.rendererPtr, x, y)
  }

  private takeMemorySnapshot(): void {
    if (this._isDestroyed) return

    const memoryUsage = process.memoryUsage()
    this.lastMemorySnapshot = {
      heapUsed: memoryUsage.heapUsed,
      heapTotal: memoryUsage.heapTotal,
      arrayBuffers: memoryUsage.arrayBuffers,
    }

    this.lib.updateMemoryStats(
      this.rendererPtr,
      this.lastMemorySnapshot.heapUsed,
      this.lastMemorySnapshot.heapTotal,
      this.lastMemorySnapshot.arrayBuffers,
    )

    this.emit("memory:snapshot", this.lastMemorySnapshot)
  }

  private startMemorySnapshotTimer(): void {
    this.stopMemorySnapshotTimer()

    this.memorySnapshotTimer = setInterval(() => {
      this.takeMemorySnapshot()
    }, this.memorySnapshotInterval)
  }

  private stopMemorySnapshotTimer(): void {
    if (this.memorySnapshotTimer) {
      clearInterval(this.memorySnapshotTimer)