✨ feat(vscode): 文件和文件夹在预览顶部问

侧栏「问 AI」打开代码阅读预览。文件夹是没有代码块的一页,源码文件在整页顶部聊,代码块下面的问答不动。历史按工作区文件夹和相对路径记在窗口状态里,不写进按块存的记录。
This commit is contained in:
cruldra committed 2026-10-03 03:22:20 +08:00
1 parent 2be635d1e5
commit 2c10acf9c4
19 files changed
+610 -459

No files matched your search

+33 -6
View File
@@ -138,22 +138,38 @@ function CurrentItem({ ask, onOpenImage, onStop }: { ask: Ask, onOpenImage: (url
}
/** 底下的输入框:Enter 发送、Shift+Enter 换行、Esc 收起;正在答时发送换成停止。能贴图、拖图,贴的图在输入框上面一排,随下一个问题发 */
function AskInput({ running, first, profiles, onSelectProfile, onAsk, onStop, onClose, onOpenImage }: {
function AskInput({ running, first, hint, profiles, onSelectProfile, onAsk, onStop, onClose, closable, onOpenImage, autoFocus, focusToken }: {
running: Ask | undefined
/** 这块还没问过:提示「问这块代码…」,问过了是「继续问…」 */
/** 还没问过:提示「问…」,问过了是「继续问…」 */
first: boolean
/** 「问」后面的对象:块下面是「这块代码」,顶部是「这个文件」或「这个文件夹」 */
hint: string
profiles: ProfileChoice
onSelectProfile: (id: string) => void
onAsk: (question: string, images: PendingImage[]) => void
onStop: (askId: string) => void
onClose: () => void
/** Esc 收起。顶部那条一直摊开,不收 */
closable: boolean
onOpenImage: (url: string) => void
/** 展开时把光标放进输入框。顶部那条一直摊开,不要抢阅读时光标 */
autoFocus: boolean
/** 大于 0 时再放一次光标;侧栏「问 AI」打开已经在的预览时用 */
focusToken: number
}): ReactElement {
const [value, setValue] = useState('')
const [images, setImages] = useState<PendingImage[]>([])
/** 贴的、拖的有没加上的:给人看的原因,下次贴图或发送时清掉 */
const [notice, setNotice] = useState<string>()
const textarea = useRef<HTMLTextAreaElement>(null)
useEffect(() => {
if (autoFocus)
textarea.current?.focus()
}, [autoFocus])
useEffect(() => {
if (focusToken > 0)
textarea.current?.focus()
}, [focusToken])
const attach = (files: File[]): void => {
if (files.length === 0)
return
@@ -179,7 +195,7 @@ function AskInput({ running, first, profiles, onSelectProfile, onAsk, onStop, on
event.preventDefault()
send()
}
else if (event.key === 'Escape') {
else if (closable && event.key === 'Escape') {
event.preventDefault()
onClose()
}
@@ -211,9 +227,8 @@ function AskInput({ running, first, profiles, onSelectProfile, onAsk, onStop, on
<textarea
ref={textarea}
rows={1}
autoFocus
value={value}
placeholder={`${first ? '问这块代码…' : '继续问…'} Enter 发送,Esc 收起`}
placeholder={`${first ? `问${hint}…` : '继续问…'} Enter 发送${closable ? ',Esc 收起' : ''}`}
aria-label="问 AI 的问题"
onChange={event => setValue(event.target.value)}
onKeyDown={onKeyDown}
@@ -251,6 +266,14 @@ export interface AskThreadProps {
open: boolean
/** 输入框旁边的 profile 下拉 */
profiles: ProfileChoice
/** 「问」后面的对象,默认「这块代码」 */
hint?: string
/** 展开时聚焦输入框,默认聚焦。一直摊开的顶部聊天不聚焦 */
autoFocus?: boolean
/** 变大时把光标放进输入框 */
focusToken?: number
/** Esc 能不能收起,默认能。顶部聊天不收 */
closable?: boolean
now?: number
onSelectProfile: (id: string) => void
/** images 是贴进输入框的图片,随问题一起发 */
@@ -264,7 +287,7 @@ export interface AskThreadProps {
* 块下面的问答区(左边一条竖线):展开时是灰字的历史、当前这一轮、输入框;
* 没展开但问过的块是一行「问过 N 次」、下面默认摊开灰字历史,点这一行收起 / 再摊开,读代码时一眼看到这里问过什么。
*/
export function AskThread({ history, asks, open, profiles, now = Date.now(), onSelectProfile, onAsk, onStop, onDelete, onClose }: AskThreadProps): ReactElement | null {
export function AskThread({ history, asks, open, profiles, hint = '这块代码', autoFocus = true, focusToken = 0, closable = true, now = Date.now(), onSelectProfile, onAsk, onStop, onDelete, onClose }: AskThreadProps): ReactElement | null {
const [showHistory, setShowHistory] = useState(true)
/** 正在看大图的那张 */
const [preview, setPreview] = useState<string>()
@@ -295,10 +318,14 @@ export function AskThread({ history, asks, open, profiles, now = Date.now(), onS
first={history.length === 0 && asks.length === 0}
profiles={profiles}
onSelectProfile={onSelectProfile}
hint={hint}
onAsk={onAsk}
onStop={onStop}
onClose={onClose}
closable={closable}
onOpenImage={setPreview}
autoFocus={autoFocus}
focusToken={focusToken}
/>
{lightbox}
</section>