feat:移除了弹窗,服务器添加sls

This commit is contained in:
AxTps committed 2026-09-08 22:39:45 +08:00
commit 6a295f9a7a
4082 files changed
+1322534

No files matched your search

@@ -0,0 +1,229 @@
export interface JLineCellStyle {
foreground?: string
background?: string
bold?: boolean
italic?: boolean
underline?: boolean
dim?: boolean
inverse?: boolean
}
export interface JLineCell {
text: string
width: number
style: JLineCellStyle
}
export interface JLineRow {
index: number
wrapped: boolean
cells: JLineCell[]
}
export interface JLinePrompt {
value: string
cursor: number
rows: JLineRow[]
}
export interface JLineCandidate {
text: string
row: number
column: number
selected: boolean
style: JLineCellStyle
}
export interface JLineCandidateConfirmation {
lineCount: number
}
export interface JLineCandidateInsertion {
deleteBefore: number
deleteAfter: number
text: string
}
export interface JLineInputEdit {
value: string
cursor: number
}
export const JLINE_KEY_SEQUENCES: Record<string, string> = {
Tab: '\t',
ArrowUp: '\x1b[A',
ArrowDown: '\x1b[B',
ArrowRight: '\x1b[C',
ArrowLeft: '\x1b[D',
Home: '\x1b[H',
End: '\x1b[F',
Delete: '\x1b[3~',
Backspace: '\x7f',
Enter: '\r',
Escape: '\x1b',
}
export function jlineKeySequence(key: string, applicationCursorKeys = false): string | undefined {
if (applicationCursorKeys) {
const applicationSequences: Record<string, string> = {
ArrowUp: '\x1bOA',
ArrowDown: '\x1bOB',
ArrowRight: '\x1bOC',
ArrowLeft: '\x1bOD',
Home: '\x1bOH',
End: '\x1bOF',
}
if (applicationSequences[key]) return applicationSequences[key]
}
return JLINE_KEY_SEQUENCES[key]
}
export function extractJLinePrompt(
rows: JLineRow[],
cursorRow: number,
cursorColumn: number,
): JLinePrompt | null {
const cursorIndex = rows.findIndex((row) => row.index === cursorRow)
if (cursorIndex < 0) return null
let start = cursorIndex
while (start > 0 && rows[start]?.wrapped) start--
const logicalRows = rows.slice(start, cursorIndex + 1)
const logicalText = logicalRows.map(rowText).join('')
if (!logicalText.startsWith('> ')) return null
const charactersBeforeCursor =
logicalRows
.slice(0, -1)
.reduce(
(total, row) => total + row.cells.reduce((sum, cell) => sum + cell.text.length, 0),
0,
) +
(logicalRows.at(-1)?.cells ?? [])
.slice(0, cursorColumn)
.reduce((sum, cell) => sum + cell.text.length, 0)
const cursor = Math.max(0, charactersBeforeCursor - 2)
const commandText = logicalText.slice(2)
const valueEnd = Math.max(cursor, commandText.trimEnd().length)
return {
value: commandText.slice(0, valueEnd),
cursor,
rows: logicalRows,
}
}
export function createJLineCandidateInsertion(
prompt: Pick<JLinePrompt, 'value' | 'cursor'>,
candidateText: string,
): JLineCandidateInsertion {
const cursor = Math.max(0, Math.min(prompt.cursor, prompt.value.length))
let start = cursor
while (start > 0 && !/\s/.test(prompt.value[start - 1]!)) start--
let end = cursor
while (end < prompt.value.length && !/\s/.test(prompt.value[end]!)) end++
const needsTrailingSpace = end === prompt.value.length && !candidateText.endsWith(' ')
return {
deleteBefore: cursor - start,
deleteAfter: end - cursor,
text: `${candidateText}${needsTrailingSpace ? ' ' : ''}`,
}
}
export function applyJLineCandidate(
prompt: Pick<JLinePrompt, 'value' | 'cursor'>,
candidateText: string,
): JLineInputEdit {
const insertion = createJLineCandidateInsertion(prompt, candidateText)
const start = prompt.cursor - insertion.deleteBefore
const end = prompt.cursor + insertion.deleteAfter
return {
value: `${prompt.value.slice(0, start)}${insertion.text}${prompt.value.slice(end)}`,
cursor: start + insertion.text.length,
}
}
export function replaceJLineSelection(
prompt: Pick<JLinePrompt, 'value'>,
selectionStart: number,
selectionEnd: number,
replacement: string,
): JLineInputEdit {
const start = Math.max(0, Math.min(selectionStart, selectionEnd, prompt.value.length))
const end = Math.max(start, Math.min(Math.max(selectionStart, selectionEnd), prompt.value.length))
return {
value: `${prompt.value.slice(0, start)}${replacement}${prompt.value.slice(end)}`,
cursor: start + replacement.length,
}
}
export function createJLineLineReplacementSequence(
currentValue: string,
next: JLineInputEdit,
applicationCursorKeys = false,
): string {
const cursor = Math.max(0, Math.min(next.cursor, next.value.length))
return (
(currentValue ? '\x01\x0b' : '') +
next.value +
jlineKeySequence('ArrowLeft', applicationCursorKeys)!.repeat(next.value.length - cursor)
)
}
export function parseJLineCandidates(rows: JLineRow[], cursorRow: number): JLineCandidate[] {
const candidates: JLineCandidate[] = []
for (const row of rows) {
if (row.index <= cursorRow) continue
const text = rowText(row)
if (!text.trim()) continue
if (/--more--|\.\.\.$/i.test(text.trim())) return []
let start = 0
while (start < row.cells.length) {
while (start < row.cells.length && !row.cells[start]?.text.trim()) start++
if (start >= row.cells.length) break
let end = start
let blankRun = 0
while (end < row.cells.length) {
if (row.cells[end]?.text.trim()) {
blankRun = 0
} else {
blankRun++
if (blankRun >= 2) break
}
end++
}
const contentEnd = Math.max(start, end - blankRun + 1)
const candidateText = row.cells
.slice(start, contentEnd)
.map((cell) => cell.text)
.join('')
.trim()
if (candidateText) {
const first = row.cells[start]!
candidates.push({
text: candidateText,
row: row.index,
column: start,
selected: row.cells.slice(start, contentEnd).some((cell) => cell.style.inverse),
style: first.style,
})
}
start = end + 1
}
}
return candidates
}
export function parseJLineCandidateConfirmation(
rows: JLineRow[],
): JLineCandidateConfirmation | null {
const text = rows.map(rowText).join(' ').replace(/\s+/g, ' ').trim()
const match = text.match(
/(?:do you wish to see all|display all)\s+\d+\s+possibilit(?:y|ies)\b.*?\((\d+)\s+lines?\)\?\s*$/i,
)
if (!match) return null
const lineCount = Number.parseInt(match[1] ?? '', 10)
return { lineCount: Number.isFinite(lineCount) ? lineCount : 0 }
}
function rowText(row: JLineRow): string {
return row.cells.map((cell) => cell.text).join('')
}