🐛 fix(query-editor): 修复 SQL 美化后横向视口偏移

- SQL 格式化完成后重置 Monaco 横向滚动位置
- 保留格式化内容、选区、纵向滚动与撤销行为
- 补充超长单行 SQL 非自动换行场景回归测试
This commit is contained in:
AutumnNazi
2026-07-27 21:10:04 +08:00
parent 70282286fc
commit df87e50b33
2 changed files with 29 additions and 0 deletions

View File

@@ -209,6 +209,7 @@ const editorState = vi.hoisted(() => {
},
position: { lineNumber: 1, column: 1 },
selection: null as any,
scrollLeft: 0,
providers: [] as any[],
providerLanguages: [] as string[],
hoverProviders: [] as any[],
@@ -292,6 +293,10 @@ const editorState = vi.hoisted(() => {
setSelections: vi.fn((selections: any[]) => {
state.selection = Array.isArray(selections) ? selections[0] ?? null : null;
}),
getScrollLeft: vi.fn(() => state.scrollLeft),
setScrollLeft: vi.fn((scrollLeft: number) => {
state.scrollLeft = scrollLeft;
}),
executeEdits: vi.fn((_source: string, edits: any[]) => {
edits.forEach((edit) => {
const start = offsetAt({ lineNumber: edit.range.startLineNumber, column: edit.range.startColumn });
@@ -897,6 +902,7 @@ describe('QueryEditor external SQL save', () => {
editorState.value = '';
editorState.position = { lineNumber: 1, column: 1 };
editorState.selection = null;
editorState.scrollLeft = 0;
monacoEditorMockState.latestProps = null;
editorState.domNode.style.cursor = '';
editorState.providers = [];
@@ -919,6 +925,8 @@ describe('QueryEditor external SQL save', () => {
editorState.editor.getModel().getValueLength.mockClear();
editorState.editor.setValue.mockClear();
editorState.editor.executeEdits.mockClear();
editorState.editor.getScrollLeft.mockClear();
editorState.editor.setScrollLeft.mockClear();
editorState.editor.deltaDecorations.mockClear();
editorState.editor.updateOptions.mockClear();
editorState.editor.pushUndoStop.mockClear();
@@ -4427,6 +4435,26 @@ describe('QueryEditor external SQL save', () => {
});
});
it('resets stale horizontal scroll after formatting a long single-line SQL statement', async () => {
let renderer!: ReactTestRenderer;
const longSql = `select ${Array.from({ length: 80 }, (_, index) => `column_${index + 1}`).join(', ')} from users where id=1`;
await act(async () => {
renderer = create(<QueryEditor tab={createTab({ query: longSql })} />);
});
editorState.scrollLeft = 2400;
const formatButton = findButton(renderer, '美化');
await act(async () => {
await formatButton.props.onClick();
});
expect(editorState.editor.executeEdits).toHaveBeenCalled();
expect(editorState.editor.setScrollLeft).toHaveBeenCalledWith(0);
expect(editorState.scrollLeft).toBe(0);
});
it('formats only the selected SQL when a non-empty selection exists', async () => {
let renderer!: ReactTestRenderer;
const originalSql = 'select 1; select * from users where id=1';

View File

@@ -6178,6 +6178,7 @@ const QueryEditor: React.FC<{ tab: TabData; isActive?: boolean }> = ({ tab, isAc
const nextValue = editor.getValue?.();
applyQueryState(typeof nextValue === 'string' ? nextValue : (formatSelection ? currentValue : formatted));
refreshObjectDecorations();
editor.setScrollLeft?.(0);
return;
}
if (formatSelection) {