Skip to content

终端 UI

Ace 提供终端 UI 原语来显示日志、格式化输出、渲染表格和动画,由 @poppinss/cliui 提供支持。

日志记录器

日志记录器组件用于在终端中显示日志消息。

日志方法

命令类使用 this.logger 属性公开日志记录器实例。您可以使用不同的方法来显示不同类型的日志消息。

ts
import { BaseCommand } from '@adonisjs/core/ace'

export default class GreetCommand extends BaseCommand {
  async run() {
    this.logger.debug('Debug message')
    this.logger.info('Info message')
    this.logger.success('Success message')
    this.logger.warning('Warning message')
    this.logger.error('Error message')
    this.logger.fatal('Fatal message')
  }
}

添加前缀和后缀

您可以使用 prefixsuffix 选项为日志消息添加前缀和后缀。

ts
this.logger.info('Downloading files', {
  prefix: '[1/3]',
  suffix: '50%'
})

加载动画

logger.await 方法在日志消息旁边显示加载动画。您可以使用此方法指示长时间运行的操作。

ts
const loader = this.logger.await('Downloading files')

// 下载完成后
loader.stop()

您还可以更新消息。

ts
const loader = this.logger.await('Downloading files')

// 更新消息
loader.update('Almost done')

// 下载完成后
loader.stop()

日志记录器操作

logger.action 方法用于显示操作及其状态。这对于显示应用程序中执行的操作列表很有用。

ts
this.logger.action('Creating config file').succeeded()
this.logger.action('Updating package.json').succeeded()
this.logger.action('Installing dependencies').failed('Network error')
this.logger.action('Cleanup').skipped('Not needed')

颜色

this.colors 属性公开 @poppinss/colors 模块来格式化带有 ANSI 颜色的文本。

ts
import { BaseCommand } from '@adonisjs/core/ace'

export default class GreetCommand extends BaseCommand {
  async run() {
    console.log(this.colors.red('This is red'))
    console.log(this.colors.green('This is green'))
    console.log(this.colors.bgRed().white('White text on red background'))
    console.log(this.colors.bold().underline('Bold and underlined'))
  }
}

可用的颜色方法:

  • blackredgreenyellowbluemagentacyanwhitegray
  • bgBlackbgRedbgGreenbgYellowbgBluebgMagentabgCyanbgWhite
  • dimboldhiddenitalicunderlinestrikethroughinverse

表格

this.ui.table 方法用于在终端中渲染表格。

ts
import { BaseCommand } from '@adonisjs/core/ace'

export default class GreetCommand extends BaseCommand {
  async run() {
    const table = this.ui.table()
    
    table.head(['Name', 'Age', 'City'])
    
    table.row(['John', '30', 'New York'])
    table.row(['Jane', '25', 'Los Angeles'])
    table.row(['Bob', '35', 'Chicago'])
    
    table.render()
  }
}

自动计算列

您可以使用 fullWidth 方法使表格占据整个终端宽度,并使用 fluidColumnIndex 方法指定哪个列应占据剩余空间。

ts
const table = this.ui.table()

table.head(['File', 'Size', 'Status'])
table.fullWidth()
table.fluidColumnIndex(0) // File 列将占据剩余空间

table.row(['package.json', '2KB', 'OK'])
table.row(['node_modules/express/package.json', '1KB', 'OK'])

table.render()

贴纸

this.ui.sticker 方法用于在终端中打印带边框的消息框。

ts
import { BaseCommand } from '@adonisjs/core/ace'

export default class GreetCommand extends BaseCommand {
  async run() {
    this.ui.sticker()
      .heading('Application ready')
      .add('Local: http://localhost:3333')
      .add('Network: http://192.168.1.100:3333')
      .render()
  }
}

指令

this.ui.instructions 方法用于在终端中显示指令列表。

ts
import { BaseCommand } from '@adonisjs/core/ace'

export default class GreetCommand extends BaseCommand {
  async run() {
    this.ui.instructions()
      .heading('Getting Started')
      .add('Run npm install')
      .add('Run npm run dev')
      .add('Open http://localhost:3333')
      .render()
  }
}

任务

this.ui.tasks 方法用于在终端中渲染带有动画进度的任务列表。

ts
import { BaseCommand } from '@adonisjs/core/ace'

export default class GreetCommand extends BaseCommand {
  async run() {
    const tasks = this.ui.tasks()
    
    await tasks
      .add('Installing dependencies', async (task) => {
        await someAsyncOperation()
        return task.completed()
      })
      .add('Compiling TypeScript', async (task) => {
        await anotherAsyncOperation()
        return task.completed()
      })
      .add('Running tests', async (task) => {
        await runTests()
        return task.completed()
      })
      .run()
  }
}

任务状态

每个任务可以返回以下状态之一:

  • task.completed():任务成功完成
  • task.failed(error):任务失败并显示错误消息
  • task.skipped(reason):任务被跳过并显示原因
ts
await tasks
  .add('Check prerequisites', async (task) => {
    const isValid = await checkPrerequisites()
    if (!isValid) {
      return task.failed('Prerequisites not met')
    }
    return task.completed()
  })
  .add('Optional step', async (task) => {
    if (!needsOptionalStep) {
      return task.skipped('Not required')
    }
    await performOptionalStep()
    return task.completed()
  })
  .run()

详细模式

您可以通过将 verbose 选项传递给 tasks 方法来启用详细模式。在详细模式下,任务的所有输出都会显示在终端中。

ts
const tasks = this.ui.tasks({ verbose: true })

更新任务消息

您可以在执行期间使用 task.update 方法更新任务消息。

ts
await tasks
  .add('Downloading files', async (task) => {
    task.update('Downloading file 1/3')
    await downloadFile1()
    
    task.update('Downloading file 2/3')
    await downloadFile2()
    
    task.update('Downloading file 3/3')
    await downloadFile3()
    
    return task.completed()
  })
  .run()