diff --git a/src/hwylterm/spin.nim b/src/hwylterm/spin.nim index 39f1dac..40180c7 100644 --- a/src/hwylterm/spin.nim +++ b/src/hwylterm/spin.nim @@ -5,47 +5,50 @@ type Spinny = ref object t: Thread[Spinny] lock: Lock - text: string + text: BbString running: bool frames: seq[string] - frame: string + bbFrames: seq[BbString] + frame: BbString interval: int customSymbol: bool style: string + file: File EventKind = enum Stop SymbolChange TextChange - SpinnyEvent = object kind: EventKind - payload: string + payload: BbString var spinnyChannel: Channel[SpinnyEvent] -proc newSpinny*(text: string, s: Spinner): Spinny = +proc newSpinny*(text: string | Bbstring, s: Spinner): Spinny = let style = "bold blue" Spinny( - text: text, + text: bb(text), running: true, - frames: mapIt(s.frames, $bb(bbEscape(it), style)), + frames: s.frames, + bbFrames: mapIt(s.frames, bb(bbEscape(it), style)), customSymbol: false, interval: s.interval, style: "bold blue", + file: stderr, ) -proc newSpinny*(text: string, spinType: SpinnerKind): Spinny = +proc newSpinny*(text: string | Bbstring, spinType: SpinnerKind): Spinny = newSpinny(text, Spinners[spinType]) proc setSymbolColor*(spinny: Spinny, style: string) = - spinny.frames = mapIt(spinny.frames, $bb(it, style)) + spinny.bbFrames = mapIt(spinny.frames, bb(bbEscape(it), style)) proc setSymbol*(spinny: Spinny, symbol: string) = - spinnyChannel.send(SpinnyEvent(kind: SymbolChange, payload: symbol)) + spinnyChannel.send(SpinnyEvent(kind: SymbolChange, payload: bb(symbol))) -proc setText*(spinny: Spinny, text: string) = - spinnyChannel.send(SpinnyEvent(kind: TextChange, payload: text)) +proc setText*(spinny: Spinny, text: string | BbString) = + spinnyChannel.send(SpinnyEvent(kind: TextChange, payload: bb(text))) proc handleEvent(spinny: Spinny, eventData: SpinnyEvent): bool = result = true @@ -74,14 +77,15 @@ proc spinnyLoop(spinny: Spinny) {.thread.} = spinny.running = false break - stdout.flushFile() + flushFile spinny.file if not spinny.customSymbol: - spinny.frame = spinny.frames[frameCounter] + spinny.frame = spinny.bbFrames[frameCounter] + # TODO: instead of truncating support multiline text, need custom wrapping and cleanup then withLock spinny.lock: - eraseLine() - stdout.write(spinny.frame & " " & spinny.text) - stdout.flushFile() + eraseLine spinny.file + spinny.file.write $((spinny.frame & " " & spinny.text).truncate(terminalWidth())) # needs to be truncated + flushFile spinny.file sleep spinny.interval @@ -96,37 +100,35 @@ proc start*(spinny: Spinny) = createThread(spinny.t, spinnyLoop, spinny) proc stop(spinny: Spinny, kind: EventKind, payload = "") = - spinnyChannel.send(SpinnyEvent(kind: kind, payload: payload)) + spinnyChannel.send(SpinnyEvent(kind: kind, payload: bb(payload))) spinnyChannel.send(SpinnyEvent(kind: Stop)) joinThread spinny.t - eraseLine stdout - flushFile stdout + eraseLine spinny.file + flushFile spinny.file proc stop*(spinny: Spinny) = spinny.stop(Stop) template withSpinner*(msg: string = "", body: untyped): untyped = var spinner {.inject.} = newSpinny(msg, Dots) - if isatty(stdout): # don't spin if it's not a tty + if isatty(spinner.file): # don't spin if it's not a tty start spinner - - body - - if isatty(stdout): + body stop spinner + else: + body template withSpinner*(body: untyped): untyped = withSpinner("", body) template with*(kind: SpinnerKind, msg: string, body: untyped): untyped = var spinner {.inject.} = newSpinny(msg, kind) - if isatty(stdout): # don't spin if it's not a tty + if isatty(spinner.file): # don't spin if it's not a tty start spinner - - body - - if isatty(stdout): + body stop spinner + else: + body when isMainModule: for kind, _ in Spinners: