/** * Copyright 2023 Gravitational, Inc * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import { wait } from 'shared/utils/wait'; export interface BufferEntry { id: number; text: string; isCommand: boolean; isCurrent: boolean; } type FrameFunction = () => Frame; interface Frame { text: string; delay?: number; } export interface TerminalLine { text?: string; isCommand: boolean; delay?: number; hasFinished?: () => boolean; frames?: FrameFunction[]; } export async function* createTerminalContent( lines: TerminalLine[], lineIndex: number ): AsyncIterableIterator { let linePosition = 0; let frameIndex = 0; let hasFrame = false; const buffer: BufferEntry[] = []; if (lineIndex > 0) { for (let i = 0; i < lineIndex; i++) { buffer.push({ id: i, text: lines[i].text, isCommand: lines[i].isCommand, isCurrent: i === lineIndex, }); } yield buffer; } // eslint-disable-next-line no-constant-condition while (true) { if (lineIndex < lines.length) { if (!lines[lineIndex].isCommand) { const delay = lines[lineIndex].delay; if (!isNaN(delay)) { await wait(delay); yield buffer; } const frames = lines[lineIndex].frames; if (!frames) { buffer.push({ id: lineIndex, text: lines[lineIndex].text, isCommand: false, isCurrent: false, }); yield buffer; linePosition = 0; lineIndex += 1; } else if (frameIndex < frames.length) { const frame = frames[frameIndex](); if (frameIndex === 0 && !hasFrame) { hasFrame = true; buffer.push({ id: lineIndex, text: frame.text, isCurrent: false, isCommand: false, }); } buffer[lineIndex].text = frame.text; if (!isNaN(frame.delay)) { yield buffer; await wait(frame.delay); yield buffer; } frameIndex += 1; } else { if (hasFrame && lines[lineIndex + 1]) { buffer[lineIndex].text = lines[lineIndex].text; linePosition = 0; frameIndex = 0; lineIndex += 1; hasFrame = false; } frameIndex = 0; } } else if (linePosition > lines[lineIndex].text.length) { buffer[lineIndex].isCurrent = lineIndex === lines.length - 1; linePosition = 0; yield buffer; await wait(300); lineIndex += 1; } else { const delay = lines[lineIndex].delay; if (!isNaN(delay)) { yield buffer; await wait(delay); yield buffer; } if (linePosition === 0) { await wait(100); buffer.push({ id: lineIndex, text: '', isCommand: lines[lineIndex].isCommand, isCurrent: true, }); yield buffer; await wait(600); } buffer[lineIndex].text = lines[lineIndex].text.substring( 0, linePosition ); linePosition += 1; } yield buffer; } else { yield buffer; return buffer; } } }