fix(app): only navigate prompt history at input boundaries (#13690)
This commit is contained in:
@@ -911,31 +911,13 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
|
|||||||
if (!collapsed) return
|
if (!collapsed) return
|
||||||
|
|
||||||
const cursorPosition = getCursorPosition(editorRef)
|
const cursorPosition = getCursorPosition(editorRef)
|
||||||
const textLength = promptLength(prompt.current())
|
|
||||||
const textContent = prompt
|
const textContent = prompt
|
||||||
.current()
|
.current()
|
||||||
.map((part) => ("content" in part ? part.content : ""))
|
.map((part) => ("content" in part ? part.content : ""))
|
||||||
.join("")
|
.join("")
|
||||||
const direction = event.key === "ArrowUp" ? "up" : "down"
|
const direction = event.key === "ArrowUp" ? "up" : "down"
|
||||||
if (!canNavigateHistoryAtCursor(direction, textContent, cursorPosition)) return
|
if (!canNavigateHistoryAtCursor(direction, textContent, cursorPosition, store.historyIndex >= 0)) return
|
||||||
const isEmpty = textContent.trim() === "" || textLength <= 1
|
if (navigateHistory(direction)) {
|
||||||
const hasNewlines = textContent.includes("\n")
|
|
||||||
const inHistory = store.historyIndex >= 0
|
|
||||||
const atStart = cursorPosition <= (isEmpty ? 1 : 0)
|
|
||||||
const atEnd = cursorPosition >= (isEmpty ? textLength - 1 : textLength)
|
|
||||||
const allowUp = isEmpty || atStart || (!hasNewlines && !inHistory) || (inHistory && atEnd)
|
|
||||||
const allowDown = isEmpty || atEnd || (!hasNewlines && !inHistory) || (inHistory && atStart)
|
|
||||||
|
|
||||||
if (direction === "up") {
|
|
||||||
if (!allowUp) return
|
|
||||||
if (navigateHistory("up")) {
|
|
||||||
event.preventDefault()
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!allowDown) return
|
|
||||||
if (navigateHistory("down")) {
|
|
||||||
event.preventDefault()
|
event.preventDefault()
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -73,7 +73,7 @@ describe("prompt-input history", () => {
|
|||||||
expect(original[1].selection?.startLine).toBe(1)
|
expect(original[1].selection?.startLine).toBe(1)
|
||||||
})
|
})
|
||||||
|
|
||||||
test("canNavigateHistoryAtCursor only allows multiline boundaries", () => {
|
test("canNavigateHistoryAtCursor only allows prompt boundaries", () => {
|
||||||
const value = "a\nb\nc"
|
const value = "a\nb\nc"
|
||||||
|
|
||||||
expect(canNavigateHistoryAtCursor("up", value, 0)).toBe(true)
|
expect(canNavigateHistoryAtCursor("up", value, 0)).toBe(true)
|
||||||
@@ -85,7 +85,16 @@ describe("prompt-input history", () => {
|
|||||||
expect(canNavigateHistoryAtCursor("up", value, 5)).toBe(false)
|
expect(canNavigateHistoryAtCursor("up", value, 5)).toBe(false)
|
||||||
expect(canNavigateHistoryAtCursor("down", value, 5)).toBe(true)
|
expect(canNavigateHistoryAtCursor("down", value, 5)).toBe(true)
|
||||||
|
|
||||||
expect(canNavigateHistoryAtCursor("up", "abc", 1)).toBe(true)
|
expect(canNavigateHistoryAtCursor("up", "abc", 0)).toBe(true)
|
||||||
expect(canNavigateHistoryAtCursor("down", "abc", 1)).toBe(true)
|
expect(canNavigateHistoryAtCursor("down", "abc", 3)).toBe(true)
|
||||||
|
expect(canNavigateHistoryAtCursor("up", "abc", 1)).toBe(false)
|
||||||
|
expect(canNavigateHistoryAtCursor("down", "abc", 1)).toBe(false)
|
||||||
|
|
||||||
|
expect(canNavigateHistoryAtCursor("up", "abc", 0, true)).toBe(true)
|
||||||
|
expect(canNavigateHistoryAtCursor("up", "abc", 3, true)).toBe(true)
|
||||||
|
expect(canNavigateHistoryAtCursor("down", "abc", 0, true)).toBe(true)
|
||||||
|
expect(canNavigateHistoryAtCursor("down", "abc", 3, true)).toBe(true)
|
||||||
|
expect(canNavigateHistoryAtCursor("up", "abc", 1, true)).toBe(false)
|
||||||
|
expect(canNavigateHistoryAtCursor("down", "abc", 1, true)).toBe(false)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -4,11 +4,13 @@ const DEFAULT_PROMPT: Prompt = [{ type: "text", content: "", start: 0, end: 0 }]
|
|||||||
|
|
||||||
export const MAX_HISTORY = 100
|
export const MAX_HISTORY = 100
|
||||||
|
|
||||||
export function canNavigateHistoryAtCursor(direction: "up" | "down", text: string, cursor: number) {
|
export function canNavigateHistoryAtCursor(direction: "up" | "down", text: string, cursor: number, inHistory = false) {
|
||||||
if (!text.includes("\n")) return true
|
|
||||||
const position = Math.max(0, Math.min(cursor, text.length))
|
const position = Math.max(0, Math.min(cursor, text.length))
|
||||||
if (direction === "up") return !text.slice(0, position).includes("\n")
|
const atStart = position === 0
|
||||||
return !text.slice(position).includes("\n")
|
const atEnd = position === text.length
|
||||||
|
if (inHistory) return atStart || atEnd
|
||||||
|
if (direction === "up") return position === 0
|
||||||
|
return position === text.length
|
||||||
}
|
}
|
||||||
|
|
||||||
export function clonePromptParts(prompt: Prompt): Prompt {
|
export function clonePromptParts(prompt: Prompt): Prompt {
|
||||||
|
|||||||
Reference in New Issue
Block a user