Skip to content

Commit

Permalink
feat: make long list scrollable for interactive mode (#89)
Browse files Browse the repository at this point in the history
Co-authored-by: Anthony Fu <anthonyfu117@hotmail.com>
  • Loading branch information
a1mersnow and antfu authored Nov 27, 2023
1 parent 2738bd1 commit 0402966
Show file tree
Hide file tree
Showing 2 changed files with 83 additions and 8 deletions.
15 changes: 7 additions & 8 deletions src/commands/check/interactive.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { createControlledPromise, notNullish } from '@antfu/utils'
import type { CheckOptions, InteractiveContext, PackageMeta, ResolvedDepChange } from '../../types'
import { getVersionOfRange, updateTargetVersion } from '../../io/resolves'
import { getPrefixedVersion } from '../../utils/versions'
import { FIG_BLOCK, FIG_NO_POINTER, FIG_POINTER, colorizeVersionDiff, formatTable } from '../../render'
import { FIG_BLOCK, FIG_NO_POINTER, FIG_POINTER, colorizeVersionDiff, createSliceRender, formatTable } from '../../render'
import { timeDifference } from '../../utils/time'
import { renderChanges } from './render'

Expand Down Expand Up @@ -56,19 +56,18 @@ export async function promptInteractive(pkgs: PackageMeta[], options: CheckOptio

return {
render() {
const sr = createSliceRender()
const Y = (v: string) => c.bold(c.green(v))
console.clear()
console.log(`${FIG_BLOCK} ${c.gray(`${Y('↑↓')} to select, ${Y('space')} to toggle, ${Y('→')} to change version`)}`)
console.log(`${FIG_BLOCK} ${c.gray(`${Y('enter')} to confirm, ${Y('esc')} to cancel`)}`)
console.log()

const lines: string[] = []
sr.push({ content: `${FIG_BLOCK} ${c.gray(`${Y('↑↓')} to select, ${Y('space')} to toggle, ${Y('→')} to change version`)}`, fixed: true })
sr.push({ content: `${FIG_BLOCK} ${c.gray(`${Y('enter')} to confirm, ${Y('esc')} to cancel`)}`, fixed: true })
sr.push({ content: '', fixed: true })

pkgs.forEach((pkg) => {
lines.push(...renderChanges(pkg, options, ctx).lines)
sr.push(...renderChanges(pkg, options, ctx).lines.map(x => ({ content: x })))
})

console.log(lines.join('\n'))
sr.render(index)
},
onKey(key) {
switch (key.name) {
Expand Down
76 changes: 76 additions & 0 deletions src/render.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
/* eslint-disable no-console */
import process from 'node:process'
import c from 'picocolors'
import { SemVer } from 'semver'
import { getDiff } from './io/resolves'
Expand Down Expand Up @@ -110,3 +112,77 @@ export function colorizeVersionDiff(from: string, to: string, hightlightRange =
+ middot
+ c[color](partsToColor.slice(i).join('.')).trim()
}

interface SliceRenderLine {
content: string
fixed?: boolean
}

export function createSliceRender() {
const buffer: SliceRenderLine[] = []

return {
push(...lines: SliceRenderLine[]) {
buffer.push(...lines)
},
render(selectedDepIndex: number) {
let {
rows: remainHeight,
columns: availableWidth,
} = process.stdout

const lines: SliceRenderLine[] = buffer.length < remainHeight - 1
? buffer
: [...buffer, { content: c.yellow(' -- END --') }]

// spare space for cursor
remainHeight -= 1
let i = 0
while (i < lines.length) {
const curr = lines[i]
if (curr.fixed) {
console.log(curr.content)
remainHeight -= 1
i++
}
else {
break
}
}

const remainLines = lines.slice(i)

// calculate focused line index from selected dep index
let focusedLineIndex = 0
let depIndex = 0
for (const line of remainLines) {
if (line.content.includes(FIG_CHECK))
depIndex += 1

if (depIndex === selectedDepIndex)
break
else
focusedLineIndex += 1
}

let slice: SliceRenderLine[]
if (
remainHeight < 1
|| remainLines.length === 0
|| remainLines.length <= remainHeight
|| lines.some(x => Math.ceil(visualLength(x.content) / availableWidth) > 1)
) {
slice = remainLines
}
else {
const half = Math.floor((remainHeight - 1) / 2)
const f = focusedLineIndex - half
const b = focusedLineIndex + remainHeight - half - remainLines.length
const start = Math.max(0, b <= 0 ? f : f - b)
slice = remainLines.slice(start, start + remainHeight)
}

console.log(slice.map(x => x.content).join('\n'))
},
}
}

0 comments on commit 0402966

Please sign in to comment.