修复:粘贴解析出的引用若解析不出来,退化成 token 文本而不是整条丢掉
$insertContentAtSelection 的引用分支补 else:referenceFromPart 返回 null 时插入该 part 的 token 文本 此前上游 buildContentFromPastedText 已把 token 摘走,插入端再丢一次就会让这段内容静默消失 新增用例:provider 认得出 token 但插入时已解析不出引用,断言正文保持 `看 @hero 一眼`、不产生芯片 变异验证:去掉该兜底后同一用例变红(正文变成 `看 一眼`),恢复即绿
This commit is contained in:
@@ -322,6 +322,9 @@ function $selectionOrRootEnd() {
|
||||
* 与 `applyContentToRoot`(整根替换,供初始草稿与润色回写使用)的区别只在替换范围:
|
||||
* 文本 part 的 `\n` 落成真正的段落分隔(与编辑器默认的纯文本粘贴同一形状),引用 part 落成
|
||||
* chip;不加任何补白,token 原位替换、token 之外的每个字符照原样保留。
|
||||
*
|
||||
* 认不出的引用 part(provider 的 `toReference` 解析不出来)退回它的 token 文本,
|
||||
* 绝不静默丢掉——粘贴进来的内容一个字符都不会凭空消失。
|
||||
*/
|
||||
function $insertContentAtSelection(
|
||||
content: readonly DirectCodexUserContentPart[],
|
||||
@@ -342,7 +345,11 @@ function $insertContentAtSelection(
|
||||
$selectionOrRootEnd()?.insertNodes([
|
||||
$createResourceReferenceNode(reference),
|
||||
]);
|
||||
return;
|
||||
}
|
||||
// 解析不出的 part 已经在上游被摘掉了 token,这里必须把文本补回去,否则这段内容会静默消失。
|
||||
const token = mentionTokenFromPart(providers, part);
|
||||
if (token) $selectionOrRootEnd()?.insertText(token);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -33,6 +33,7 @@ import { attachmentReferenceProvider } from '../src/features/project-workspace/r
|
||||
import { createResourceReferenceProvider } from '../src/features/project-workspace/reference-source/resourceReferenceProvider';
|
||||
import { runtimeRegionReferenceProvider } from '../src/features/project-workspace/reference-source/runtimeRegionReferenceProvider';
|
||||
import { useSkillReferenceProvider } from '../src/features/project-workspace/reference-source/skillReferenceProvider';
|
||||
import type { ReferenceProvider } from '../src/features/project-workspace/reference-source/types';
|
||||
import {
|
||||
ResourceReferenceInput,
|
||||
type ResourceReferenceInputHandle,
|
||||
@@ -458,6 +459,36 @@ describe('ResourceReferenceInput', () => {
|
||||
expect(editorTextSize()).toBe('看 '.length + 1 + ' 这一版'.length);
|
||||
});
|
||||
|
||||
test('粘贴解析出的引用若已无法解析,退化成 token 文本而不是整条丢掉', async () => {
|
||||
const ref = createRef<ResourceReferenceInputHandle>();
|
||||
// provider 认得出这个 token(lookup 有候选),但插入那一刻已经解析不出引用(例如资产刚被删)。
|
||||
const ghostProvider: ReferenceProvider = {
|
||||
trigger: '@',
|
||||
fuzzy_lookup: () => [],
|
||||
lookup: () => [resourceReferenceFromAsset(assets[0]!, 'asset-picker')],
|
||||
toReference: () => null,
|
||||
refresh: (reference) => reference,
|
||||
mentionToken: (part) =>
|
||||
part.type === 'agc_resource_reference' ? '@hero' : null,
|
||||
};
|
||||
render(
|
||||
<ResourceReferenceInput
|
||||
ref={ref}
|
||||
providers={[ghostProvider]}
|
||||
projectPath="C:/project"
|
||||
ariaLabel="聊天"
|
||||
onChange={vi.fn()}
|
||||
/>,
|
||||
);
|
||||
|
||||
pasteComposerText('看 @hero 一眼');
|
||||
|
||||
await waitFor(() => {
|
||||
expect(draftText(ref.current?.getDraft())).toBe('看 @hero 一眼');
|
||||
});
|
||||
expect(draftResourceIds(ref.current?.getDraft())).toEqual([]);
|
||||
});
|
||||
|
||||
test('粘贴未命中的 token:整段按字面落进正文,不接管、不提示', async () => {
|
||||
const ref = createRef<ResourceReferenceInputHandle>();
|
||||
render(
|
||||
|
||||
Reference in New Issue
Block a user