mirror of
https://github.com/Syngnat/GoNavi.git
synced 2026-07-07 11:01:33 +08:00
✨ feat(query-editor): 新增选择当前语句快捷键
- 快捷键配置:新增选择当前语句动作,默认绑定 Ctrl+E - 编辑器接入:在 Monaco 查询编辑器中注册选择当前语句 action - 语句识别:新增 SQL 语句范围解析,支持按光标定位当前语句 - 兼容处理:忽略字符串、注释和 dollar quote 内的分号 - 测试覆盖:补充快捷键默认配置和语句选择解析单元测试 Refs #404
This commit is contained in:
@@ -17,6 +17,7 @@ import { isOracleLikeDialect, resolveSqlDialect, resolveSqlFunctions, resolveSql
|
||||
import { applyQueryAutoLimit } from '../utils/queryAutoLimit';
|
||||
import { extractQueryResultTableRef, type QueryResultTableRef } from '../utils/queryResultTable';
|
||||
import { quoteIdentPart } from '../utils/sql';
|
||||
import { resolveCurrentSqlStatementRange } from '../utils/sqlStatementSelection';
|
||||
import { resolveUniqueKeyGroupsFromIndexes } from './dataGridCopyInsert';
|
||||
import { ORACLE_ROWID_LOCATOR_COLUMN, type EditRowLocator } from '../utils/rowLocator';
|
||||
|
||||
@@ -637,6 +638,7 @@ const QueryEditor: React.FC<{ tab: TabData; isActive?: boolean }> = ({ tab, isAc
|
||||
const editorRef = useRef<any>(null);
|
||||
const monacoRef = useRef<any>(null);
|
||||
const runQueryActionRef = useRef<any>(null);
|
||||
const selectCurrentStatementActionRef = useRef<any>(null);
|
||||
const lastExternalQueryRef = useRef<string>(tab.query || '');
|
||||
const dragRef = useRef<{ startY: number, startHeight: number } | null>(null);
|
||||
const queryEditorRootRef = useRef<HTMLDivElement | null>(null);
|
||||
@@ -721,6 +723,31 @@ const QueryEditor: React.FC<{ tab: TabData; isActive?: boolean }> = ({ tab, isAc
|
||||
return query || '';
|
||||
};
|
||||
|
||||
const handleSelectCurrentStatement = () => {
|
||||
const editor = editorRef.current;
|
||||
const monaco = monacoRef.current;
|
||||
const model = editor?.getModel?.();
|
||||
const position = editor?.getPosition?.();
|
||||
if (!editor || !monaco || !model || !position) {
|
||||
return;
|
||||
}
|
||||
|
||||
const fullSQL = String(model.getValue?.() || '');
|
||||
const cursorOffset = model.getOffsetAt?.(position);
|
||||
const range = resolveCurrentSqlStatementRange(fullSQL, Number(cursorOffset));
|
||||
if (!range) {
|
||||
void message.info('没有可选择的 SQL 语句。');
|
||||
return;
|
||||
}
|
||||
|
||||
const start = model.getPositionAt(range.start);
|
||||
const end = model.getPositionAt(range.end);
|
||||
const selection = new monaco.Range(start.lineNumber, start.column, end.lineNumber, end.column);
|
||||
editor.setSelection(selection);
|
||||
editor.revealRangeInCenterIfOutsideViewport?.(selection);
|
||||
editor.focus?.();
|
||||
};
|
||||
|
||||
const syncQueryToEditor = (sql: string) => {
|
||||
const next = sql || '';
|
||||
setQuery(next);
|
||||
@@ -942,6 +969,21 @@ const QueryEditor: React.FC<{ tab: TabData; isActive?: boolean }> = ({ tab, isAc
|
||||
}
|
||||
}
|
||||
|
||||
const selectStatementBinding = shortcutOptions.selectCurrentStatement;
|
||||
if (selectStatementBinding?.enabled && selectStatementBinding.combo) {
|
||||
const keyBinding = comboToMonacoKeyBinding(
|
||||
selectStatementBinding.combo, monaco.KeyMod, monaco.KeyCode
|
||||
);
|
||||
if (keyBinding) {
|
||||
selectCurrentStatementActionRef.current = editor.addAction({
|
||||
id: 'gonavi.selectCurrentStatement',
|
||||
label: 'GoNavi: 选择当前语句',
|
||||
keybindings: [keyBinding.keyMod | keyBinding.keyCode],
|
||||
run: handleSelectCurrentStatement,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// HMR 重载时释放旧注册避免补全项重复
|
||||
if (!sqlCompletionRegistered) {
|
||||
sqlCompletionRegistered = true;
|
||||
@@ -2226,6 +2268,37 @@ const QueryEditor: React.FC<{ tab: TabData; isActive?: boolean }> = ({ tab, isAc
|
||||
};
|
||||
}, [shortcutOptions.runQuery]);
|
||||
|
||||
useEffect(() => {
|
||||
if (selectCurrentStatementActionRef.current) {
|
||||
selectCurrentStatementActionRef.current.dispose();
|
||||
selectCurrentStatementActionRef.current = null;
|
||||
}
|
||||
|
||||
const editor = editorRef.current;
|
||||
const monaco = monacoRef.current;
|
||||
if (!editor || !monaco) return;
|
||||
|
||||
const binding = shortcutOptions.selectCurrentStatement;
|
||||
if (!binding?.enabled || !binding.combo) return;
|
||||
|
||||
const keyBinding = comboToMonacoKeyBinding(binding.combo, monaco.KeyMod, monaco.KeyCode);
|
||||
if (keyBinding) {
|
||||
selectCurrentStatementActionRef.current = editor.addAction({
|
||||
id: 'gonavi.selectCurrentStatement',
|
||||
label: 'GoNavi: 选择当前语句',
|
||||
keybindings: [keyBinding.keyMod | keyBinding.keyCode],
|
||||
run: handleSelectCurrentStatement,
|
||||
});
|
||||
}
|
||||
|
||||
return () => {
|
||||
if (selectCurrentStatementActionRef.current) {
|
||||
selectCurrentStatementActionRef.current.dispose();
|
||||
selectCurrentStatementActionRef.current = null;
|
||||
}
|
||||
};
|
||||
}, [shortcutOptions.selectCurrentStatement]);
|
||||
|
||||
useEffect(() => {
|
||||
const handleRunActiveQuery = () => {
|
||||
if (activeTabId !== tab.id) {
|
||||
|
||||
Reference in New Issue
Block a user