Commit 6d614b7

Anton Medvedev <anton@medv.io>
2022-06-08 16:44:10
New spinner() api
1 parent d0393ba
Changed files (2)
src/experimental.ts
@@ -13,7 +13,7 @@
 // limitations under the License.
 
 import assert from 'node:assert'
-import { $ } from './core.js'
+import { $, within } from './core.js'
 import { sleep } from './goods.js'
 import { Duration, parseDuration } from './util.js'
 
@@ -56,20 +56,26 @@ export async function retry<T>(
   throw 'unreachable'
 }
 
-/**
- * Starts a simple CLI spinner.
- * @param title Spinner's title.
- * @return A stop() func.
- */
-export function startSpinner(title = '') {
-  let i = 0,
-    v = $.verbose
-  $.verbose = false
-  let spin = () =>
+export async function spinner<T>(callback: () => T): Promise<T>
+export async function spinner<T>(title: string, callback: () => T): Promise<T>
+export async function spinner<T>(
+  title: string | (() => T),
+  callback?: () => T
+): Promise<T> {
+  if (typeof title == 'string') {
+    assert(callback)
+  } else {
+    callback = title
+    title = ''
+  }
+  let i = 0
+  const spin = () =>
     process.stderr.write(`  ${'⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏'[i++ % 10]} ${title}\r`)
-  let id = setInterval(spin, 100)
-  return () => {
+  return within(async () => {
+    $.verbose = false
+    const id = setInterval(spin, 100)
+    const result = await callback!()
     clearInterval(id)
-    $.verbose = v
-  }
+    return result
+  })
 }
test/experimental.test.js
@@ -40,13 +40,24 @@ test('retry works', async () => {
   assert.ok(Date.now() >= now + 50 * (5 - 1))
 })
 
-test('spinner works', async () => {
+test('spinner() works', async () => {
   let out = await zx(`
-    let stop = startSpinner('waiting')
-    await sleep(1000)
-    stop()
+    echo(await spinner(async () => {
+      await sleep(100)
+      await $\`echo hidden\`
+      return $\`echo result\`
+    }))
   `)
-  assert.match(out.stderr, 'waiting')
+  assert.match(out.stdout, 'result')
+  assert.not.match(out.stderr, 'result')
+  assert.not.match(out.stderr, 'hidden')
+})
+
+test('spinner() with title works', async () => {
+  let out = await zx(`
+    await spinner('processing', async () => sleep(100))
+  `)
+  assert.match(out.stderr, 'processing')
 })
 
 test.run()