Skip to content

Commit 0402966

Browse files
a1mersnowantfu
andauthoredNov 27, 2023
feat: make long list scrollable for interactive mode (#89)
Co-authored-by: Anthony Fu <anthonyfu117@hotmail.com>
1 parent 2738bd1 commit 0402966

File tree

2 files changed

+83
-8
lines changed

2 files changed

+83
-8
lines changed
 

‎src/commands/check/interactive.ts

+7-8
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { createControlledPromise, notNullish } from '@antfu/utils'
77
import type { CheckOptions, InteractiveContext, PackageMeta, ResolvedDepChange } from '../../types'
88
import { getVersionOfRange, updateTargetVersion } from '../../io/resolves'
99
import { getPrefixedVersion } from '../../utils/versions'
10-
import { FIG_BLOCK, FIG_NO_POINTER, FIG_POINTER, colorizeVersionDiff, formatTable } from '../../render'
10+
import { FIG_BLOCK, FIG_NO_POINTER, FIG_POINTER, colorizeVersionDiff, createSliceRender, formatTable } from '../../render'
1111
import { timeDifference } from '../../utils/time'
1212
import { renderChanges } from './render'
1313

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

5757
return {
5858
render() {
59+
const sr = createSliceRender()
5960
const Y = (v: string) => c.bold(c.green(v))
6061
console.clear()
61-
console.log(`${FIG_BLOCK} ${c.gray(`${Y('↑↓')} to select, ${Y('space')} to toggle, ${Y('→')} to change version`)}`)
62-
console.log(`${FIG_BLOCK} ${c.gray(`${Y('enter')} to confirm, ${Y('esc')} to cancel`)}`)
63-
console.log()
64-
65-
const lines: string[] = []
62+
sr.push({ content: `${FIG_BLOCK} ${c.gray(`${Y('↑↓')} to select, ${Y('space')} to toggle, ${Y('→')} to change version`)}`, fixed: true })
63+
sr.push({ content: `${FIG_BLOCK} ${c.gray(`${Y('enter')} to confirm, ${Y('esc')} to cancel`)}`, fixed: true })
64+
sr.push({ content: '', fixed: true })
6665

6766
pkgs.forEach((pkg) => {
68-
lines.push(...renderChanges(pkg, options, ctx).lines)
67+
sr.push(...renderChanges(pkg, options, ctx).lines.map(x => ({ content: x })))
6968
})
7069

71-
console.log(lines.join('\n'))
70+
sr.render(index)
7271
},
7372
onKey(key) {
7473
switch (key.name) {

‎src/render.ts

+76
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
/* eslint-disable no-console */
2+
import process from 'node:process'
13
import c from 'picocolors'
24
import { SemVer } from 'semver'
35
import { getDiff } from './io/resolves'
@@ -110,3 +112,77 @@ export function colorizeVersionDiff(from: string, to: string, hightlightRange =
110112
+ middot
111113
+ c[color](partsToColor.slice(i).join('.')).trim()
112114
}
115+
116+
interface SliceRenderLine {
117+
content: string
118+
fixed?: boolean
119+
}
120+
121+
export function createSliceRender() {
122+
const buffer: SliceRenderLine[] = []
123+
124+
return {
125+
push(...lines: SliceRenderLine[]) {
126+
buffer.push(...lines)
127+
},
128+
render(selectedDepIndex: number) {
129+
let {
130+
rows: remainHeight,
131+
columns: availableWidth,
132+
} = process.stdout
133+
134+
const lines: SliceRenderLine[] = buffer.length < remainHeight - 1
135+
? buffer
136+
: [...buffer, { content: c.yellow(' -- END --') }]
137+
138+
// spare space for cursor
139+
remainHeight -= 1
140+
let i = 0
141+
while (i < lines.length) {
142+
const curr = lines[i]
143+
if (curr.fixed) {
144+
console.log(curr.content)
145+
remainHeight -= 1
146+
i++
147+
}
148+
else {
149+
break
150+
}
151+
}
152+
153+
const remainLines = lines.slice(i)
154+
155+
// calculate focused line index from selected dep index
156+
let focusedLineIndex = 0
157+
let depIndex = 0
158+
for (const line of remainLines) {
159+
if (line.content.includes(FIG_CHECK))
160+
depIndex += 1
161+
162+
if (depIndex === selectedDepIndex)
163+
break
164+
else
165+
focusedLineIndex += 1
166+
}
167+
168+
let slice: SliceRenderLine[]
169+
if (
170+
remainHeight < 1
171+
|| remainLines.length === 0
172+
|| remainLines.length <= remainHeight
173+
|| lines.some(x => Math.ceil(visualLength(x.content) / availableWidth) > 1)
174+
) {
175+
slice = remainLines
176+
}
177+
else {
178+
const half = Math.floor((remainHeight - 1) / 2)
179+
const f = focusedLineIndex - half
180+
const b = focusedLineIndex + remainHeight - half - remainLines.length
181+
const start = Math.max(0, b <= 0 ? f : f - b)
182+
slice = remainLines.slice(start, start + remainHeight)
183+
}
184+
185+
console.log(slice.map(x => x.content).join('\n'))
186+
},
187+
}
188+
}

0 commit comments

Comments
 (0)
Please sign in to comment.