diff --git a/src/containers/Tenant/Query/QueryEditor/QueryEditor.tsx b/src/containers/Tenant/Query/QueryEditor/QueryEditor.tsx index 29cd198ad..a5c6a289c 100644 --- a/src/containers/Tenant/Query/QueryEditor/QueryEditor.tsx +++ b/src/containers/Tenant/Query/QueryEditor/QueryEditor.tsx @@ -42,6 +42,7 @@ import { import {useChangedQuerySettings} from '../../../../utils/hooks/useChangedQuerySettings'; import {useLastQueryExecutionSettings} from '../../../../utils/hooks/useLastQueryExecutionSettings'; import {YQL_LANGUAGE_ID} from '../../../../utils/monaco/constats'; +import {updateErrorsHighlighting} from '../../../../utils/monaco/highlightErrors'; import {QUERY_ACTIONS} from '../../../../utils/query'; import type {InitialPaneState} from '../../utils/paneVisibilityToggleHelpers'; import { @@ -294,6 +295,7 @@ export default function QueryEditor(props: QueryEditorProps) { }; const onChange = (newValue: string) => { + updateErrorsHighlighting(); changeUserInput({input: newValue}); }; diff --git a/src/containers/Tenant/Query/QueryEditor/helpers.ts b/src/containers/Tenant/Query/QueryEditor/helpers.ts index d1207d33c..990ded87b 100644 --- a/src/containers/Tenant/Query/QueryEditor/helpers.ts +++ b/src/containers/Tenant/Query/QueryEditor/helpers.ts @@ -13,6 +13,7 @@ const EDITOR_OPTIONS: EditorOptions = { minimap: { enabled: false, }, + fixedOverflowWidgets: true, }; export function useEditorOptions() { diff --git a/src/utils/monaco/highlightErrors.ts b/src/utils/monaco/highlightErrors.ts new file mode 100644 index 000000000..d5eace811 --- /dev/null +++ b/src/utils/monaco/highlightErrors.ts @@ -0,0 +1,46 @@ +import {parseYqlQueryWithoutCursor} from '@gravity-ui/websql-autocomplete/yql'; +import {MarkerSeverity, editor} from 'monaco-editor'; + +import i18n from './i18n'; + +const owner = 'ydb'; + +let errorsHighlightingTimeoutId: ReturnType; + +export function updateErrorsHighlighting() { + unHighlightErrors(); + + clearTimeout(errorsHighlightingTimeoutId); + errorsHighlightingTimeoutId = setTimeout(() => highlightErrors(), 500); +} + +function highlightErrors() { + const model = window.ydbEditor?.getModel(); + if (!model) { + console.error('unable to retrieve model when highlighting errors'); + return; + } + + const errors = parseYqlQueryWithoutCursor(model.getValue()).errors; + if (!errors.length) { + unHighlightErrors(); + return; + } + + const markers = errors.map( + (error): editor.IMarkerData => ({ + message: i18n('context_syntax-error'), + source: error.message, + severity: MarkerSeverity.Error, + startLineNumber: error.startLine, + startColumn: error.startColumn + 1, + endLineNumber: error.endLine, + endColumn: error.endColumn + 1, + }), + ); + editor.setModelMarkers(model, owner, markers); +} + +function unHighlightErrors(): void { + editor.removeAllMarkers(owner); +} diff --git a/src/utils/monaco/i18n/en.json b/src/utils/monaco/i18n/en.json new file mode 100644 index 000000000..d4b173c36 --- /dev/null +++ b/src/utils/monaco/i18n/en.json @@ -0,0 +1,3 @@ +{ + "context_syntax-error": "Syntax error" +} diff --git a/src/utils/monaco/i18n/index.ts b/src/utils/monaco/i18n/index.ts new file mode 100644 index 000000000..0061fd670 --- /dev/null +++ b/src/utils/monaco/i18n/index.ts @@ -0,0 +1,7 @@ +import {registerKeysets} from '../../i18n'; + +import en from './en.json'; + +const COMPONENT = 'ydb-monaco'; + +export default registerKeysets(COMPONENT, {en});