{"version":3,"file":"FileStream.js","names":["options: FileStreamOptions"],"sources":["../../src/components/FileStream.ts"],"sourcesContent":["import { DEFAULT_THEMES, DIFFS_TAG_NAME } from '../constants';\nimport { getSharedHighlighter } from '../highlighter/shared_highlighter';\nimport { queueRender } from '../managers/UniversalRenderingManager';\nimport { CodeToTokenTransformStream, type RecallToken } from '../shiki-stream';\nimport type {\n  AppliedThemeStyleCache,\n  BaseCodeOptions,\n  DiffsHighlighter,\n  SupportedLanguages,\n  ThemedToken,\n  ThemeTypes,\n} from '../types';\nimport { createSpanFromToken } from '../utils/createSpanNodeFromToken';\nimport { wrapThemeCSS } from '../utils/cssWrappers';\nimport { formatCSSVariablePrefix } from '../utils/formatCSSVariablePrefix';\nimport { getHighlighterOptions } from '../utils/getHighlighterOptions';\nimport { getHighlighterThemeStyles } from '../utils/getHighlighterThemeStyles';\nimport { getOrCreateCodeNode } from '../utils/getOrCreateCodeNode';\nimport { upsertHostThemeStyle } from '../utils/hostTheme';\nimport { getMeasuredScrollbarGutter } from '../utils/scrollbarGutter';\nimport { setPreNodeProperties } from '../utils/setWrapperNodeProps';\n\nexport interface FileStreamOptions extends BaseCodeOptions {\n  lang?: SupportedLanguages;\n  startingLineIndex?: number;\n\n  onPreRender?(instance: FileStream): unknown;\n  onPostRender?(instance: FileStream): unknown;\n\n  onStreamStart?(controller: WritableStreamDefaultController): unknown;\n  onStreamWrite?(token: ThemedToken | RecallToken): unknown;\n  onStreamClose?(): unknown;\n  onStreamAbort?(reason: unknown): unknown;\n}\n\nlet instanceId = -1;\n\nexport class FileStream {\n  readonly __id: string = `file-stream:${++instanceId}`;\n\n  private highlighter: DiffsHighlighter | undefined;\n  private stream: ReadableStream<string> | undefined;\n  private abortController: AbortController | undefined;\n  private fileContainer: HTMLElement | undefined;\n  private pre: HTMLPreElement | undefined;\n  private code: HTMLElement | undefined;\n  private gutterElement: HTMLElement | undefined;\n  private contentElement: HTMLElement | undefined;\n  private themeCSSStyle: HTMLStyleElement | undefined;\n  private appliedThemeCSS: AppliedThemeStyleCache | undefined;\n  private currentRowCount = 0;\n\n  constructor(public options: FileStreamOptions = { theme: DEFAULT_THEMES }) {\n    this.currentLineIndex = this.options.startingLineIndex ?? 1;\n  }\n\n  cleanUp(): void {\n    this.abortController?.abort();\n    this.abortController = undefined;\n  }\n\n  setThemeType(themeType: ThemeTypes): void {\n    if ((this.options.themeType ?? 'system') === themeType) {\n      return;\n    }\n    this.options = { ...this.options, themeType };\n    if (\n      typeof this.options.theme === 'string' ||\n      this.fileContainer == null ||\n      this.appliedThemeCSS == null\n    ) {\n      return;\n    }\n    this.applyThemeState(\n      this.fileContainer,\n      this.appliedThemeCSS.themeStyles,\n      themeType,\n      this.appliedThemeCSS.baseThemeType\n    );\n  }\n\n  private async initializeHighlighter(): Promise<DiffsHighlighter> {\n    this.highlighter = await getSharedHighlighter(\n      getHighlighterOptions(this.options.lang, this.options)\n    );\n    return this.highlighter;\n  }\n\n  private queuedSetupArgs: [ReadableStream<string>, HTMLElement] | undefined;\n  async setup(\n    _source: ReadableStream<string>,\n    _wrapper: HTMLElement\n  ): Promise<void> {\n    const isSettingUp = this.queuedSetupArgs != null;\n    this.queuedSetupArgs = [_source, _wrapper];\n    if (isSettingUp) {\n      // TODO(amadeus): Make it so that this function can be properly\n      // awaitable, maybe?\n      return;\n    }\n    this.highlighter ??= await this.initializeHighlighter();\n\n    const [source, wrapper] = this.queuedSetupArgs;\n    this.queuedSetupArgs = undefined;\n\n    const stream = source;\n\n    this.setupStream(stream, wrapper, this.highlighter);\n  }\n\n  private setupStream(\n    stream: ReadableStream<string>,\n    wrapper: HTMLElement,\n    highlighter: DiffsHighlighter\n  ): void {\n    const {\n      disableLineNumbers = false,\n      overflow = 'scroll',\n      theme = DEFAULT_THEMES,\n      themeType = 'system',\n    } = this.options;\n    const fileContainer = this.getOrCreateFileContainer();\n    if (fileContainer.parentElement == null) {\n      wrapper.appendChild(fileContainer);\n    }\n    this.pre ??= document.createElement('pre');\n    if (this.pre.parentElement == null) {\n      fileContainer.shadowRoot?.appendChild(this.pre);\n    }\n    const baseThemeType =\n      typeof theme === 'string' ? highlighter.getTheme(theme).type : undefined;\n    const themeStyles = getHighlighterThemeStyles({ theme, highlighter });\n    this.applyThemeState(fileContainer, themeStyles, themeType, baseThemeType);\n    const pre = setPreNodeProperties(this.pre, {\n      type: 'file',\n      diffIndicators: 'none',\n      disableBackground: true,\n      disableLineNumbers,\n      overflow,\n      split: false,\n      totalLines: 0,\n    });\n    pre.innerHTML = '';\n\n    this.pre = pre;\n    this.code = getOrCreateCodeNode({ code: this.code, pre });\n    this.gutterElement = undefined;\n    this.contentElement = undefined;\n    this.currentRowCount = 0;\n    this.currentLineElement = undefined;\n    this.currentLineIndex = this.options.startingLineIndex ?? 1;\n    this.abortController?.abort();\n    this.abortController = new AbortController();\n    const { onStreamStart, onStreamClose, onStreamAbort } = this.options;\n    this.stream = stream;\n    this.stream\n      .pipeThrough(\n        typeof theme === 'string'\n          ? new CodeToTokenTransformStream({\n              ...this.options,\n              theme,\n              highlighter,\n              allowRecalls: true,\n              defaultColor: false,\n              cssVariablePrefix: formatCSSVariablePrefix('token'),\n            })\n          : new CodeToTokenTransformStream({\n              ...this.options,\n              themes: theme,\n              highlighter,\n              allowRecalls: true,\n              defaultColor: false,\n              cssVariablePrefix: formatCSSVariablePrefix('token'),\n            })\n      )\n      .pipeTo(\n        new WritableStream({\n          start(controller) {\n            onStreamStart?.(controller);\n          },\n          close() {\n            onStreamClose?.();\n          },\n          abort(reason) {\n            onStreamAbort?.(reason);\n          },\n          write: this.handleWrite,\n        }),\n        { signal: this.abortController.signal }\n      )\n      .catch((error) => {\n        // Ignore AbortError - it's expected when cleaning up\n        if (error.name !== 'AbortError') {\n          console.error('FileStream pipe error:', error);\n        }\n      });\n  }\n\n  private queuedTokens: (ThemedToken | RecallToken)[] = [];\n  private handleWrite = (token: ThemedToken | RecallToken) => {\n    // If we've recalled tokens we haven't rendered yet, we can just yeet them\n    // and never apply them\n    if ('recall' in token && this.queuedTokens.length >= token.recall) {\n      this.queuedTokens.length = this.queuedTokens.length - token.recall;\n    } else {\n      this.queuedTokens.push(token);\n    }\n    queueRender(this.render);\n    this.options.onStreamWrite?.(token);\n  };\n\n  private currentLineIndex: number;\n  private currentLineElement: HTMLElement | undefined;\n  private render = () => {\n    this.options.onPreRender?.(this);\n    const { gutter, content } = this.getOrCreateStreamColumns();\n    const gutterFragment = document.createDocumentFragment();\n    const contentFragment = document.createDocumentFragment();\n    for (const token of this.queuedTokens) {\n      if ('recall' in token) {\n        if (this.currentLineElement == null) {\n          throw new Error(\n            'FileStream.render: no current line element, shouldnt be possible to get here'\n          );\n        }\n        if (token.recall > this.currentLineElement.childNodes.length) {\n          throw new Error(\n            `FileStream.render: Token recall exceed the current line, there's probably a bug...`\n          );\n        }\n        for (let i = 0; i < token.recall; i++) {\n          this.currentLineElement.lastChild?.remove();\n        }\n      } else {\n        const span = createSpanFromToken(token);\n        if (this.currentLineElement == null) {\n          const { gutterLine, contentLine } = this.createLine();\n          gutterFragment.appendChild(gutterLine);\n          contentFragment.appendChild(contentLine);\n        }\n        this.currentLineElement?.appendChild(span);\n        if (token.content === '\\n') {\n          this.currentLineIndex++;\n          const { gutterLine, contentLine } = this.createLine();\n          gutterFragment.appendChild(gutterLine);\n          contentFragment.appendChild(contentLine);\n        }\n      }\n    }\n    if (gutterFragment.childNodes.length > 0) {\n      gutter.appendChild(gutterFragment);\n    }\n    if (contentFragment.childNodes.length > 0) {\n      content.appendChild(contentFragment);\n    }\n    this.queuedTokens.length = 0;\n    this.options.onPostRender?.(this);\n  };\n\n  private getOrCreateStreamColumns(): {\n    gutter: HTMLElement;\n    content: HTMLElement;\n  } {\n    if (this.code == null) {\n      throw new Error('FileStream: expected code element to exist');\n    }\n    if (this.gutterElement != null && this.contentElement != null) {\n      return { gutter: this.gutterElement, content: this.contentElement };\n    }\n    const gutter = document.createElement('div');\n    gutter.dataset.gutter = '';\n    const content = document.createElement('div');\n    content.dataset.content = '';\n    this.code.appendChild(gutter);\n    this.code.appendChild(content);\n    this.gutterElement = gutter;\n    this.contentElement = content;\n    return { gutter, content };\n  }\n\n  private updateRowSpan(): void {\n    if (this.gutterElement != null) {\n      this.gutterElement.style.gridRow = `span ${this.currentRowCount}`;\n    }\n    if (this.contentElement != null) {\n      this.contentElement.style.gridRow = `span ${this.currentRowCount}`;\n    }\n  }\n\n  private createLine(): { gutterLine: HTMLElement; contentLine: HTMLElement } {\n    const lineNumber = this.currentLineIndex;\n    const lineIndex = `${lineNumber - 1}`;\n    const gutterLine = document.createElement('div');\n    gutterLine.dataset.columnNumber = `${lineNumber}`;\n    gutterLine.dataset.lineType = 'context';\n    gutterLine.dataset.lineIndex = lineIndex;\n\n    const numberContent = document.createElement('span');\n    numberContent.dataset.lineNumberContent = '';\n    numberContent.textContent = `${lineNumber}`;\n    gutterLine.appendChild(numberContent);\n\n    const contentLine = document.createElement('div');\n    contentLine.dataset.line = `${lineNumber}`;\n    contentLine.dataset.lineType = 'context';\n    contentLine.dataset.lineIndex = lineIndex;\n\n    this.currentRowCount += 1;\n    this.updateRowSpan();\n    this.currentLineElement = contentLine;\n    return { gutterLine, contentLine };\n  }\n\n  private getOrCreateFileContainer(fileContainer?: HTMLElement): HTMLElement {\n    if (\n      (fileContainer != null && fileContainer === this.fileContainer) ||\n      (fileContainer == null && this.fileContainer != null)\n    ) {\n      return this.fileContainer;\n    }\n    if (\n      this.fileContainer != null &&\n      fileContainer != null &&\n      fileContainer !== this.fileContainer\n    ) {\n      this.themeCSSStyle = undefined;\n      this.appliedThemeCSS = undefined;\n    }\n    this.fileContainer =\n      fileContainer ?? document.createElement(DIFFS_TAG_NAME);\n    return this.fileContainer;\n  }\n\n  private applyThemeState(\n    container: HTMLElement,\n    themeStyles: string,\n    themeType: ThemeTypes,\n    baseThemeType?: 'light' | 'dark'\n  ): void {\n    const shadowRoot =\n      container.shadowRoot ?? container.attachShadow({ mode: 'open' });\n    const effectiveThemeType = baseThemeType ?? themeType;\n    const scrollbarGutter = getMeasuredScrollbarGutter(shadowRoot);\n    if (\n      this.themeCSSStyle?.parentNode === shadowRoot &&\n      this.appliedThemeCSS?.themeStyles === themeStyles &&\n      this.appliedThemeCSS.themeType === effectiveThemeType &&\n      this.appliedThemeCSS.scrollbarGutter === scrollbarGutter\n    ) {\n      return;\n    }\n    this.themeCSSStyle = upsertHostThemeStyle({\n      shadowRoot,\n      currentNode: this.themeCSSStyle,\n      themeCSS: wrapThemeCSS(themeStyles, effectiveThemeType, scrollbarGutter),\n    });\n    this.appliedThemeCSS =\n      this.themeCSSStyle != null\n        ? {\n            themeStyles,\n            themeType: effectiveThemeType,\n            baseThemeType,\n            scrollbarGutter,\n          }\n        : undefined;\n  }\n}\n"],"mappings":"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"}