diff --git a/web/pgadmin/static/js/components/ReactCodeMirror/index.jsx b/web/pgadmin/static/js/components/ReactCodeMirror/index.jsx
index 1b198d996..6af2f4cdc 100644
--- a/web/pgadmin/static/js/components/ReactCodeMirror/index.jsx
+++ b/web/pgadmin/static/js/components/ReactCodeMirror/index.jsx
@@ -12,6 +12,8 @@ import { styled } from '@mui/material/styles';
import FileCopyRoundedIcon from '@mui/icons-material/FileCopyRounded';
import CheckRoundedIcon from '@mui/icons-material/CheckRounded';
import PropTypes from 'prop-types';
+import { startCompletion } from '@codemirror/autocomplete';
+import { format } from 'sql-formatter';
import gettext from 'sources/gettext';
import { PgIconButton } from '../Buttons';
@@ -22,6 +24,8 @@ import Editor from './components/Editor';
import CustomPropTypes from '../../custom_prop_types';
import FindDialog from './components/FindDialog';
import GotoDialog from './components/GotoDialog';
+import usePreferences from '../../../../preferences/static/js/store';
+import { toCodeMirrorKey } from '../../utils';
const Root = styled('div')(() => ({
position: 'relative',
@@ -64,25 +68,71 @@ export default function CodeMirror({className, currEditor, showCopyBtn=false, cu
const [[showFind, isReplace, findKey], setShowFind] = useState([false, false, false]);
const [showGoto, setShowGoto] = useState(false);
const [showCopy, setShowCopy] = useState(false);
+ const preferences = usePreferences().getPreferencesForModule('sqleditor');
+
+ const formatSQL = (view)=>{
+ let selection = true, sql = view.getSelection();
+ /* New library does not support capitalize casing
+ so if a user has set capitalize casing we will
+ use preserve casing which is default for the library.
+ */
+ let formatPrefs = {
+ language: 'postgresql',
+ keywordCase: preferences.keyword_case === 'capitalize' ? 'preserve' : preferences.keyword_case,
+ identifierCase: preferences.identifier_case === 'capitalize' ? 'preserve' : preferences.identifier_case,
+ dataTypeCase: preferences.data_type_case,
+ functionCase: preferences.function_case,
+ logicalOperatorNewline: preferences.logical_operator_new_line,
+ expressionWidth: preferences.expression_width,
+ linesBetweenQueries: preferences.lines_between_queries,
+ tabWidth: preferences.tab_size,
+ useTabs: !preferences.use_spaces,
+ denseOperators: !preferences.spaces_around_operators,
+ newlineBeforeSemicolon: preferences.new_line_before_semicolon
+ };
+ if(sql == '') {
+ sql = view.getValue();
+ selection = false;
+ }
+ let formattedSql = format(sql,formatPrefs);
+ if(selection) {
+ view.replaceSelection(formattedSql);
+ } else {
+ view.setValue(formattedSql);
+ }
+ };
const finalCustomKeyMap = useMemo(()=>[{
- key: 'Mod-f', run: () => {
+ key: toCodeMirrorKey(preferences.find), run: () => {
setShowFind(prevVal => [true, false, !prevVal[2]]);
},
preventDefault: true,
stopPropagation: true,
}, {
- key: 'Mod-Alt-f', run: () => {
+ key: toCodeMirrorKey(preferences.replace), run: () => {
setShowFind(prevVal => [true, true, !prevVal[2]]);
},
preventDefault: true,
stopPropagation: true,
}, {
- key: 'Mod-l', run: () => {
+ key: toCodeMirrorKey(preferences.goto_line_col), run: () => {
setShowGoto(true);
},
preventDefault: true,
stopPropagation: true,
+ }, {
+ key: toCodeMirrorKey(preferences.comment), run: () => {
+ editor.current?.execCommand('toggleComment');
+ },
+ preventDefault: true,
+ stopPropagation: true,
+ },{
+ key: toCodeMirrorKey(preferences.format_sql), run: formatSQL,
+ preventDefault: true,
+ stopPropagation: true,
+ },{
+ key: toCodeMirrorKey(preferences.autocomplete), run: startCompletion,
+ preventDefault: true,
},
...customKeyMap], [customKeyMap]);
@@ -148,5 +198,5 @@ CodeMirror.propTypes = {
className: CustomPropTypes.className,
showCopyBtn: PropTypes.bool,
customKeyMap: PropTypes.array,
- onTextSelect:PropTypes.func
+ onTextSelect:PropTypes.func,
};
diff --git a/web/pgadmin/tools/sqleditor/static/js/components/QueryToolComponent.jsx b/web/pgadmin/tools/sqleditor/static/js/components/QueryToolComponent.jsx
index df59bcf19..a0d450aff 100644
--- a/web/pgadmin/tools/sqleditor/static/js/components/QueryToolComponent.jsx
+++ b/web/pgadmin/tools/sqleditor/static/js/components/QueryToolComponent.jsx
@@ -92,36 +92,6 @@ function setPanelTitle(docker, panelId, title, qtState, dirty=false) {
}
const FIXED_PREF = {
- find: {
- 'control': true,
- ctrl_is_meta: true,
- 'shift': false,
- 'alt': false,
- 'key': {
- 'key_code': 70,
- 'char': 'F',
- },
- },
- replace: {
- 'control': true,
- ctrl_is_meta: true,
- 'shift': false,
- 'alt': true,
- 'key': {
- 'key_code': 70,
- 'char': 'F',
- },
- },
- gotolinecol: {
- 'control': true,
- ctrl_is_meta: true,
- 'shift': false,
- 'alt': false,
- 'key': {
- 'key_code': 76,
- 'char': 'L',
- },
- },
indent: {
'control': false,
'shift': false,
@@ -140,26 +110,6 @@ const FIXED_PREF = {
'char': 'Tab',
},
},
- comment: {
- 'control': true,
- ctrl_is_meta: true,
- 'shift': false,
- 'alt': false,
- 'key': {
- 'key_code': 191,
- 'char': '/',
- },
- },
- format_sql: {
- 'control': true,
- ctrl_is_meta: true,
- 'shift': false,
- 'alt': false,
- 'key': {
- 'key_code': 75,
- 'char': 'k',
- },
- },
};
export default function QueryToolComponent({params, pgWindow, pgAdmin, selectedNodeInfo, qtPanelDocker, qtPanelId, eventBusObj}) {
diff --git a/web/pgadmin/tools/sqleditor/static/js/components/QueryToolConstants.js b/web/pgadmin/tools/sqleditor/static/js/components/QueryToolConstants.js
index 3b41efcf2..a60d2bf11 100644
--- a/web/pgadmin/tools/sqleditor/static/js/components/QueryToolConstants.js
+++ b/web/pgadmin/tools/sqleditor/static/js/components/QueryToolConstants.js
@@ -26,7 +26,6 @@ export const QUERY_TOOL_EVENTS = {
TRIGGER_INCLUDE_EXCLUDE_FILTER: 'TRIGGER_INCLUDE_EXCLUDE_FILTER',
TRIGGER_REMOVE_FILTER: 'TRIGGER_REMOVE_FILTER',
TRIGGER_SET_LIMIT: 'TRIGGER_SET_LIMIT',
- TRIGGER_FORMAT_SQL: 'TRIGGER_FORMAT_SQL',
TRIGGER_GRAPH_VISUALISER: 'TRIGGER_GRAPH_VISUALISER',
TRIGGER_SELECT_ALL: 'TRIGGER_SELECT_ALL',
TRIGGER_SAVE_QUERY_TOOL_DATA: 'TRIGGER_SAVE_QUERY_TOOL_DATA',
diff --git a/web/pgadmin/tools/sqleditor/static/js/components/sections/MainToolBar.jsx b/web/pgadmin/tools/sqleditor/static/js/components/sections/MainToolBar.jsx
index d87b4a838..da0e64ad5 100644
--- a/web/pgadmin/tools/sqleditor/static/js/components/sections/MainToolBar.jsx
+++ b/web/pgadmin/tools/sqleditor/static/js/components/sections/MainToolBar.jsx
@@ -291,9 +291,6 @@ export function MainToolBar({containerRef, onFilterClick, onManageMacros, onAddT
setLimit(e.target.value);
eventBus.fireEvent(QUERY_TOOL_EVENTS.TRIGGER_SET_LIMIT,e.target.value);
};
- const formatSQL=()=>{
- eventBus.fireEvent(QUERY_TOOL_EVENTS.TRIGGER_FORMAT_SQL);
- };
const toggleCase=()=>{
eventBus.fireEvent(QUERY_TOOL_EVENTS.EDITOR_TOGGLE_CASE);
};
@@ -444,12 +441,6 @@ export function MainToolBar({containerRef, onFilterClick, onManageMacros, onAddT
callback: ()=>{clearQuery();}
}
},
- {
- shortcut: queryToolPref.format_sql,
- options: {
- callback: ()=>{formatSQL();}
- }
- },
], containerRef);
/* Macro shortcuts */
@@ -598,7 +589,7 @@ export function MainToolBar({containerRef, onFilterClick, onManageMacros, onAddT
onClick={()=>{eventBus.fireEvent(QUERY_TOOL_EVENTS.EDITOR_FIND_REPLACE, false);}}>{gettext('Find')}
{eventBus.fireEvent(QUERY_TOOL_EVENTS.EDITOR_FIND_REPLACE, true);}}>{gettext('Replace')}
- {executeCmd('gotoLineCol');}}>{gettext('Go to Line/Column')}
{gettext('Clear Query')}
- {gettext('Format SQL')}
+ {executeCmd('formatSql');}}>{gettext('Format SQL')}
{
@@ -234,24 +231,6 @@ export default function Query({onTextSelect, setQtStatePartial}) {
});
});
- eventBus.registerListener(QUERY_TOOL_EVENTS.EDITOR_EXEC_CMD, (cmd='')=>{
- if(cmd == 'gotoLineCol') {
- editor.current?.focus();
- let key = {
- keyCode: 76, metaKey: false, ctrlKey: true, shiftKey: false, altKey: false,
- };
- if(isMac()) {
- key.metaKey = true;
- key.ctrlKey = false;
- key.shiftKey = false;
- key.altKey = false;
- }
- editor.current?.fireDOMEvent(new KeyboardEvent('keydown', key));
- } else {
- editor.current?.execCommand(cmd);
- }
- });
-
eventBus.registerListener(QUERY_TOOL_EVENTS.COPY_TO_EDITOR, (text)=>{
editor.current?.setValue(text);
eventBus.fireEvent(QUERY_TOOL_EVENTS.FOCUS_PANEL, PANELS.QUERY);
@@ -261,20 +240,6 @@ export default function Query({onTextSelect, setQtStatePartial}) {
}, 250);
});
- eventBus.registerListener(QUERY_TOOL_EVENTS.EDITOR_FIND_REPLACE, (replace=false)=>{
- editor.current?.focus();
- let key = {
- keyCode: 70, metaKey: false, ctrlKey: true, shiftKey: false, altKey: replace,
- };
- if(isMac()) {
- key.metaKey = true;
- key.ctrlKey = false;
- key.shiftKey = false;
- key.altKey = replace;
- }
- editor.current?.fireDOMEvent(new KeyboardEvent('keydown', key));
- });
-
eventBus.registerListener(QUERY_TOOL_EVENTS.EDITOR_SET_SQL, (value, focus=true)=>{
focus && editor.current?.focus();
editor.current?.setValue(value, !queryToolCtx.params.is_query_tool);
@@ -282,40 +247,7 @@ export default function Query({onTextSelect, setQtStatePartial}) {
eventBus.registerListener(QUERY_TOOL_EVENTS.TRIGGER_QUERY_CHANGE, ()=>{
change();
});
-
- eventBus.registerListener(QUERY_TOOL_EVENTS.TRIGGER_FORMAT_SQL, ()=>{
- let selection = true, sql = editor.current?.getSelection();
- let sqlEditorPref = preferencesStore.getPreferencesForModule('sqleditor');
- /* New library does not support capitalize casing
- so if a user has set capitalize casing we will
- use preserve casing which is default for the library.
- */
- let formatPrefs = {
- language: 'postgresql',
- keywordCase: sqlEditorPref.keyword_case === 'capitalize' ? 'preserve' : sqlEditorPref.keyword_case,
- identifierCase: sqlEditorPref.identifier_case === 'capitalize' ? 'preserve' : sqlEditorPref.identifier_case,
- dataTypeCase: sqlEditorPref.data_type_case,
- functionCase: sqlEditorPref.function_case,
- logicalOperatorNewline: sqlEditorPref.logical_operator_new_line,
- expressionWidth: sqlEditorPref.expression_width,
- linesBetweenQueries: sqlEditorPref.lines_between_queries,
- tabWidth: sqlEditorPref.tab_size,
- useTabs: !sqlEditorPref.use_spaces,
- denseOperators: !sqlEditorPref.spaces_around_operators,
- newlineBeforeSemicolon: sqlEditorPref.new_line_before_semicolon
- };
- if(sql == '') {
- sql = editor.current.getValue();
- selection = false;
- }
- let formattedSql = format(sql,formatPrefs);
- if(selection) {
- editor.current.replaceSelection(formattedSql, 'around');
- } else {
- editor.current.setValue(formattedSql);
- }
- });
-
+
eventBus.registerListener(QUERY_TOOL_EVENTS.CHANGE_EOL, (lineSep)=>{
// Set the new EOL character in the editor.
editor.current?.setEOL(lineSep);
@@ -384,44 +316,58 @@ export default function Query({onTextSelect, setQtStatePartial}) {
), {id:modalId});
};
- const formatSQL = ()=>{
- let selection = true, sql = editor.current?.getSelection();
- /* New library does not support capitalize casing
- so if a user has set capitalize casing we will
- use preserve casing which is default for the library.
- */
- let formatPrefs = {
- language: 'postgresql',
- keywordCase: queryToolPref.keyword_case === 'capitalize' ? 'preserve' : queryToolPref.keyword_case,
- identifierCase: queryToolPref.identifier_case === 'capitalize' ? 'preserve' : queryToolPref.identifier_case,
- dataTypeCase: queryToolPref.data_type_case,
- functionCase: queryToolPref.function_case,
- logicalOperatorNewline: queryToolPref.logical_operator_new_line,
- expressionWidth: queryToolPref.expression_width,
- linesBetweenQueries: queryToolPref.lines_between_queries,
- tabWidth: queryToolPref.tab_size,
- useTabs: !queryToolPref.use_spaces,
- denseOperators: !queryToolPref.spaces_around_operators,
- newlineBeforeSemicolon: queryToolPref.new_line_before_semicolon
+ const createKeyObjectFromShortcut = (pref)=>{
+ // this function creates a key object from the shortcut preference
+ let key = {
+ keyCode: pref.key.key_code,
+ metaKey: pref.ctrl_is_meta,
+ ctrlKey: pref.control,
+ shiftKey: pref.shift,
+ altKey: pref.alt,
};
- if(sql == '') {
- sql = editor.current.getValue();
- selection = false;
- }
- let formattedSql = format(sql,formatPrefs);
- if(selection) {
- editor.current.replaceSelection(formattedSql, 'around');
- } else {
- editor.current.setValue(formattedSql);
+ if(isMac()) {
+ key.metaKey = true;
+ key.ctrlKey = false;
}
+ return key;
};
- const unregisterFormatSQL = eventBus.registerListener(QUERY_TOOL_EVENTS.TRIGGER_FORMAT_SQL, formatSQL);
+ const unregisterEditorExecCmd = eventBus.registerListener(QUERY_TOOL_EVENTS.EDITOR_EXEC_CMD, (cmd='')=>{
+ let key = {}, gotolinecol = queryToolCtx.preferences.sqleditor.goto_line_col,
+ formatSql = queryToolCtx.preferences.sqleditor.format_sql;
+ switch(cmd) {
+ case 'gotoLineCol':
+ key = createKeyObjectFromShortcut(gotolinecol);
+ break;
+ case 'formatSql':
+ key = createKeyObjectFromShortcut(formatSql);
+ break;
+ default:
+ editor.current?.execCommand(cmd);
+ return;
+ }
+ editor.current?.fireDOMEvent(new KeyboardEvent('keydown', key));
+ });
+
+ const unregisterFindReplace = eventBus.registerListener(QUERY_TOOL_EVENTS.EDITOR_FIND_REPLACE, (replace=false)=>{
+ let findShortcut = queryToolCtx.preferences.sqleditor.find;
+ let replaceShortcut = queryToolCtx.preferences.sqleditor.replace;
+ let key ={};
+ editor.current?.focus();
+ if (!replace) {
+ key = createKeyObjectFromShortcut(findShortcut);
+ } else {
+ key = createKeyObjectFromShortcut(replaceShortcut);
+ }
+ editor.current?.fireDOMEvent(new KeyboardEvent('keydown', key));
+ });
+
const unregisterWarn = eventBus.registerListener(QUERY_TOOL_EVENTS.WARN_SAVE_TEXT_CLOSE, warnSaveTextClose);
return ()=>{
- unregisterFormatSQL();
unregisterWarn();
+ unregisterEditorExecCmd();
+ unregisterFindReplace();
};
}, [queryToolCtx.preferences]);
@@ -531,7 +477,7 @@ export default function Query({onTextSelect, setQtStatePartial}) {
const shortcutOverrideKeys = useMemo(
()=>{
// omit CM internal shortcuts
- const queryToolPref = _.omit(queryToolCtx.preferences.sqleditor, ['indent', 'unindent', 'comment']);
+ const queryToolPref = _.omit(queryToolCtx.preferences.sqleditor, ['indent', 'unindent']);
const queryToolShortcuts = Object.values(queryToolPref)
.filter((p)=>isShortcutValue(p))
.map((p)=>parseShortcutValue(p));
@@ -540,18 +486,14 @@ export default function Query({onTextSelect, setQtStatePartial}) {
any: (_v, e)=>{
const eventStr = parseKeyEventValue(e);
if(queryToolShortcuts.includes(eventStr)) {
- if((isMac() && eventStr == 'meta+k') || eventStr == 'ctrl+k') {
- eventBus.fireEvent(QUERY_TOOL_EVENTS.TRIGGER_FORMAT_SQL);
- } else {
- queryToolCtx.mainContainerRef?.current?.dispatchEvent(new KeyboardEvent('keydown', {
- which: e.which,
- keyCode: e.keyCode,
- altKey: e.altKey,
- shiftKey: e.shiftKey,
- ctrlKey: e.ctrlKey,
- metaKey: e.metaKey,
- }));
- }
+ queryToolCtx.mainContainerRef?.current?.dispatchEvent(new KeyboardEvent('keydown', {
+ which: e.which,
+ keyCode: e.keyCode,
+ altKey: e.altKey,
+ shiftKey: e.shiftKey,
+ ctrlKey: e.ctrlKey,
+ metaKey: e.metaKey,
+ }));
e.preventDefault();
e.stopPropagation();
return true;
diff --git a/web/pgadmin/tools/sqleditor/utils/query_tool_preferences.py b/web/pgadmin/tools/sqleditor/utils/query_tool_preferences.py
index 13c9bbd70..aa5312d87 100644
--- a/web/pgadmin/tools/sqleditor/utils/query_tool_preferences.py
+++ b/web/pgadmin/tools/sqleditor/utils/query_tool_preferences.py
@@ -551,7 +551,7 @@ def register_query_tool_preferences(self):
'control': True,
'key': {
'key_code': 76,
- 'char': 'L'
+ 'char': 'l'
}
},
category_label=PREF_LABEL_KEYBOARD_SHORTCUTS,
@@ -561,7 +561,7 @@ def register_query_tool_preferences(self):
self.preference.register(
'keyboard_shortcuts',
'download_results',
- gettext('Download Results'),
+ gettext('Download results'),
'keyboardshortcut',
{
'alt': False,
@@ -615,7 +615,7 @@ def register_query_tool_preferences(self):
self.preference.register(
'keyboard_shortcuts',
'switch_panel',
- gettext('Switch Panel'),
+ gettext('Switch panel'),
'keyboardshortcut',
{
'alt': True,
@@ -873,6 +873,120 @@ def register_query_tool_preferences(self):
fields=shortcut_fields
)
+ self.preference.register(
+ 'keyboard_shortcuts',
+ 'find',
+ gettext('Find'),
+ 'keyboardshortcut',
+ {
+ 'alt': False,
+ 'shift': False,
+ 'control': True,
+ 'ctrl_is_meta': True,
+ 'key': {
+ 'key_code': 70,
+ 'char': 'f'
+ }
+ },
+ category_label=PREF_LABEL_KEYBOARD_SHORTCUTS,
+ fields=shortcut_fields
+ )
+
+ self.preference.register(
+ 'keyboard_shortcuts',
+ 'replace',
+ gettext('Replace'),
+ 'keyboardshortcut',
+ {
+ 'alt': True,
+ 'shift': False,
+ 'control': True,
+ 'ctrl_is_meta': True,
+ 'key': {
+ 'key_code': 70,
+ 'char': 'f'
+ }
+ },
+ category_label=PREF_LABEL_KEYBOARD_SHORTCUTS,
+ fields=shortcut_fields
+ )
+
+ self.preference.register(
+ 'keyboard_shortcuts',
+ 'goto_line_col',
+ gettext('Go to line/column'),
+ 'keyboardshortcut',
+ {
+ 'alt': False,
+ 'shift': False,
+ 'control': True,
+ 'ctrl_is_meta': True,
+ 'key': {
+ 'key_code': 76,
+ 'char': 'l'
+ }
+ },
+ category_label=PREF_LABEL_KEYBOARD_SHORTCUTS,
+ fields=shortcut_fields
+ )
+
+ self.preference.register(
+ 'keyboard_shortcuts',
+ 'comment',
+ gettext('Toggle comment'),
+ 'keyboardshortcut',
+ {
+ 'alt': False,
+ 'shift': False,
+ 'control': True,
+ 'ctrl_is_meta': True,
+ 'key': {
+ 'key_code': 191,
+ 'char': '/'
+ }
+ },
+ category_label=PREF_LABEL_KEYBOARD_SHORTCUTS,
+ fields=shortcut_fields
+ )
+
+ self.preference.register(
+ 'keyboard_shortcuts',
+ 'format_sql',
+ gettext('Format SQL'),
+ 'keyboardshortcut',
+ {
+ 'alt': False,
+ 'shift': False,
+ 'control': True,
+ 'ctrl_is_meta': True,
+ 'key': {
+ 'key_code': 75,
+ 'char': 'k'
+ }
+ },
+ category_label=PREF_LABEL_KEYBOARD_SHORTCUTS,
+ fields=shortcut_fields
+ )
+
+ self.preference.register(
+ 'keyboard_shortcuts',
+ 'auto_complete',
+ gettext('Auto complete'),
+ 'keyboardshortcut',
+ {
+ 'alt': False,
+ 'shift': False,
+ 'control': True,
+ 'ctrl_is_meta': False,
+ 'key': {
+ 'key_code': 32,
+ 'char': 'Space'
+ }
+ },
+ category_label=PREF_LABEL_KEYBOARD_SHORTCUTS,
+ fields=shortcut_fields
+ )
+
self.keyword_case = self.preference.register(
'editor', 'keyword_case',
gettext("Keyword case"), 'radioModern', 'upper',