Skip to content

Commit

Permalink
[8.x] [ES|QL] Comment parsing and pretty-printing (#192173) (#194117)
Browse files Browse the repository at this point in the history
# Backport

This will backport the following commits from `main` to `8.x`:
- [[ES|QL] Comment parsing and pretty-printing
(#192173)](#192173)

<!--- Backport version: 9.4.3 -->

### Questions ?
Please refer to the [Backport tool
documentation](https://github.com/sqren/backport)

<!--BACKPORT [{"author":{"name":"Vadim
Kibana","email":"82822460+vadimkibana@users.noreply.github.com"},"sourceCommit":{"committedDate":"2024-09-26T10:34:38Z","message":"[ES|QL]
Comment parsing and pretty-printing (#192173)\n\n##
Summary\r\n\r\nTL;DR\r\n\r\n- Adds ability to parse out comments from
source to AST.\r\n- Adds ability for every AST node to have
*decoration*&mdash;comments,\r\nwhich can be attached from left, top,
and right from the node.\r\n- Implements routine which attached comments
to AST nodes.\r\n- In `BasicPrettyPrinter` adds support only for *left*
and *right*\r\ncomment printing, as the basic printer prints only on one
line.\r\n- In `WrappingPrettyPrinter` adds support for all comment
printing for\r\nall AST nodes.\r\n- Introduces a `Query` object and
`query` AST node, which represent\r\nthole query&mdash;the root node,
list of commands.\r\n- The ES|QL AST example plugin now displays the
pretty-printed text\r\nversion.\r\n\r\n\r\n### Comments\r\n\r\nThis PR
introduced an optional `formatting` field for all AST nodes. In\r\nthe
`formatting` field one can specify comment decorations from\r\ndifferent
sides of a node.\r\n\r\nWhen parsing, once can now specify the `{
withComments: true }` option,\r\nwhich will collect all comments from
the source while parsing using the\r\n`collectDecorations` routine. It
will then also call the\r\n`attachDecorations`, which walks the AST and
assigns each comment to\r\nsome AST node.\r\n\r\nFurther, traversal and
pretty-print API have been updated to work with\r\ncomments:\r\n\r\n-
The `Walker` has been updated to be able to walk all comments from
the\r\nAST.\r\n- The `BasicPrettyPrinter` adds support only for *left*
and *right*\r\ninline comment printing, as the basic printer prints only
on one line.\r\n- The `WrappingPrettyPrinter` adds support for all
comment printing for\r\nall AST nodes. It switches to line-break
printing mode if it detects\r\nthere are comments with line breaks
(those could be multi-line comments,\r\nor single line
comments&mdash;single line comments are always followed\r\nby a line
break). It also correctly inserts punctuation, when an AST\r\nnode is
surrounded by comments.\r\n\r\n\r\n### Parsing utils\r\n\r\nAll parsing
utils have been moved to the `/parser` sub-folder.\r\n\r\nFiles in the
`/parser` folder have been renamed as per Kibana convention\r\nto
reflect what is inside the file. For example, the
`EsqlErrorListener`\r\nclass is in a file named
`esql_error_listener.ts`.\r\n\r\nA `Query` class and
`ESQLAstQueryExpression` AST nodes have been\r\nintroduced. They
represent the result of a full query parse. (Before\r\nthat, the AST
root was just an array of command nodes, now the AST root\r\nis
represented by the `ESQLAstQueryExpression` node.)\r\n\r\n\r\n###
Builder\r\n\r\nI have started the implementation of the `Builder` static
class in the\r\n`/builder` folder. It is simply a collection of
stateless AST node\r\nfactories&mdash;functions which construct AST
nodes.\r\n\r\nSome of the `Builder` methods are already used by the
parser, more will\r\nfollow. We will also use the `Builder` in upcoming
[*Mutation\r\nAPI*](https://github.com/elastic/kibana/issues/191812).\r\n\r\n\r\n###
ES|QL Example Plugin\r\n\r\nThis PR sets up Storybook and implements few
Storybook stories for the\r\nES|QL AST example plugin, run it
with:\r\n\r\n```\r\nyarn storybook esql_ast_inspector\r\n```\r\n\r\nThis
PR updates the *ES|QL AST Explorer* example plugin. Start Kibana\r\nwith
example plugins enabled:\r\n\r\n```\r\nyarn start
--run-examples\r\n```\r\n\r\nAnd navigate
to\r\n[`/app/esql_ast_inspector`](http://localhost:5601/app/esql_ast_inspector)\r\nto
see the new example plugin
UI.\r\n\r\n\r\n\r\n![esql-ast-explorer](https://github.com/user-attachments/assets/8ded91ea-1b60-4514-8cf5-c8a4066a3a12)\r\n\r\n\r\n###
Checklist\r\n\r\n- [x] [Unit or
functional\r\ntests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)\r\nwere
updated or added to match the most common scenarios\r\n\r\n\r\n### For
maintainers\r\n\r\n- [x] This was checked for breaking API changes and
was
[labeled\r\nappropriately](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process)\r\n\r\n---------\r\n\r\nCo-authored-by:
kibanamachine
<42973632+kibanamachine@users.noreply.github.com>\r\nCo-authored-by:
Elastic Machine
<elasticmachine@users.noreply.github.com>\r\nCo-authored-by: Stratoula
Kalafateli
<efstratia.kalafateli@elastic.co>","sha":"2217337c5d91340ba67e0bedaab0762502518993","branchLabelMapping":{"^v9.0.0$":"main","^v8.16.0$":"8.x","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["review","release_note:skip","v9.0.0","backport:prev-minor","Feature:ES|QL","Team:ESQL","v8.16.0"],"title":"[ES|QL]
Comment parsing and
pretty-printing","number":192173,"url":"https://github.com/elastic/kibana/pull/192173","mergeCommit":{"message":"[ES|QL]
Comment parsing and pretty-printing (#192173)\n\n##
Summary\r\n\r\nTL;DR\r\n\r\n- Adds ability to parse out comments from
source to AST.\r\n- Adds ability for every AST node to have
*decoration*&mdash;comments,\r\nwhich can be attached from left, top,
and right from the node.\r\n- Implements routine which attached comments
to AST nodes.\r\n- In `BasicPrettyPrinter` adds support only for *left*
and *right*\r\ncomment printing, as the basic printer prints only on one
line.\r\n- In `WrappingPrettyPrinter` adds support for all comment
printing for\r\nall AST nodes.\r\n- Introduces a `Query` object and
`query` AST node, which represent\r\nthole query&mdash;the root node,
list of commands.\r\n- The ES|QL AST example plugin now displays the
pretty-printed text\r\nversion.\r\n\r\n\r\n### Comments\r\n\r\nThis PR
introduced an optional `formatting` field for all AST nodes. In\r\nthe
`formatting` field one can specify comment decorations from\r\ndifferent
sides of a node.\r\n\r\nWhen parsing, once can now specify the `{
withComments: true }` option,\r\nwhich will collect all comments from
the source while parsing using the\r\n`collectDecorations` routine. It
will then also call the\r\n`attachDecorations`, which walks the AST and
assigns each comment to\r\nsome AST node.\r\n\r\nFurther, traversal and
pretty-print API have been updated to work with\r\ncomments:\r\n\r\n-
The `Walker` has been updated to be able to walk all comments from
the\r\nAST.\r\n- The `BasicPrettyPrinter` adds support only for *left*
and *right*\r\ninline comment printing, as the basic printer prints only
on one line.\r\n- The `WrappingPrettyPrinter` adds support for all
comment printing for\r\nall AST nodes. It switches to line-break
printing mode if it detects\r\nthere are comments with line breaks
(those could be multi-line comments,\r\nor single line
comments&mdash;single line comments are always followed\r\nby a line
break). It also correctly inserts punctuation, when an AST\r\nnode is
surrounded by comments.\r\n\r\n\r\n### Parsing utils\r\n\r\nAll parsing
utils have been moved to the `/parser` sub-folder.\r\n\r\nFiles in the
`/parser` folder have been renamed as per Kibana convention\r\nto
reflect what is inside the file. For example, the
`EsqlErrorListener`\r\nclass is in a file named
`esql_error_listener.ts`.\r\n\r\nA `Query` class and
`ESQLAstQueryExpression` AST nodes have been\r\nintroduced. They
represent the result of a full query parse. (Before\r\nthat, the AST
root was just an array of command nodes, now the AST root\r\nis
represented by the `ESQLAstQueryExpression` node.)\r\n\r\n\r\n###
Builder\r\n\r\nI have started the implementation of the `Builder` static
class in the\r\n`/builder` folder. It is simply a collection of
stateless AST node\r\nfactories&mdash;functions which construct AST
nodes.\r\n\r\nSome of the `Builder` methods are already used by the
parser, more will\r\nfollow. We will also use the `Builder` in upcoming
[*Mutation\r\nAPI*](https://github.com/elastic/kibana/issues/191812).\r\n\r\n\r\n###
ES|QL Example Plugin\r\n\r\nThis PR sets up Storybook and implements few
Storybook stories for the\r\nES|QL AST example plugin, run it
with:\r\n\r\n```\r\nyarn storybook esql_ast_inspector\r\n```\r\n\r\nThis
PR updates the *ES|QL AST Explorer* example plugin. Start Kibana\r\nwith
example plugins enabled:\r\n\r\n```\r\nyarn start
--run-examples\r\n```\r\n\r\nAnd navigate
to\r\n[`/app/esql_ast_inspector`](http://localhost:5601/app/esql_ast_inspector)\r\nto
see the new example plugin
UI.\r\n\r\n\r\n\r\n![esql-ast-explorer](https://github.com/user-attachments/assets/8ded91ea-1b60-4514-8cf5-c8a4066a3a12)\r\n\r\n\r\n###
Checklist\r\n\r\n- [x] [Unit or
functional\r\ntests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)\r\nwere
updated or added to match the most common scenarios\r\n\r\n\r\n### For
maintainers\r\n\r\n- [x] This was checked for breaking API changes and
was
[labeled\r\nappropriately](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process)\r\n\r\n---------\r\n\r\nCo-authored-by:
kibanamachine
<42973632+kibanamachine@users.noreply.github.com>\r\nCo-authored-by:
Elastic Machine
<elasticmachine@users.noreply.github.com>\r\nCo-authored-by: Stratoula
Kalafateli
<efstratia.kalafateli@elastic.co>","sha":"2217337c5d91340ba67e0bedaab0762502518993"}},"sourceBranch":"main","suggestedTargetBranches":["8.x"],"targetPullRequestStates":[{"branch":"main","label":"v9.0.0","branchLabelMappingKey":"^v9.0.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/192173","number":192173,"mergeCommit":{"message":"[ES|QL]
Comment parsing and pretty-printing (#192173)\n\n##
Summary\r\n\r\nTL;DR\r\n\r\n- Adds ability to parse out comments from
source to AST.\r\n- Adds ability for every AST node to have
*decoration*&mdash;comments,\r\nwhich can be attached from left, top,
and right from the node.\r\n- Implements routine which attached comments
to AST nodes.\r\n- In `BasicPrettyPrinter` adds support only for *left*
and *right*\r\ncomment printing, as the basic printer prints only on one
line.\r\n- In `WrappingPrettyPrinter` adds support for all comment
printing for\r\nall AST nodes.\r\n- Introduces a `Query` object and
`query` AST node, which represent\r\nthole query&mdash;the root node,
list of commands.\r\n- The ES|QL AST example plugin now displays the
pretty-printed text\r\nversion.\r\n\r\n\r\n### Comments\r\n\r\nThis PR
introduced an optional `formatting` field for all AST nodes. In\r\nthe
`formatting` field one can specify comment decorations from\r\ndifferent
sides of a node.\r\n\r\nWhen parsing, once can now specify the `{
withComments: true }` option,\r\nwhich will collect all comments from
the source while parsing using the\r\n`collectDecorations` routine. It
will then also call the\r\n`attachDecorations`, which walks the AST and
assigns each comment to\r\nsome AST node.\r\n\r\nFurther, traversal and
pretty-print API have been updated to work with\r\ncomments:\r\n\r\n-
The `Walker` has been updated to be able to walk all comments from
the\r\nAST.\r\n- The `BasicPrettyPrinter` adds support only for *left*
and *right*\r\ninline comment printing, as the basic printer prints only
on one line.\r\n- The `WrappingPrettyPrinter` adds support for all
comment printing for\r\nall AST nodes. It switches to line-break
printing mode if it detects\r\nthere are comments with line breaks
(those could be multi-line comments,\r\nor single line
comments&mdash;single line comments are always followed\r\nby a line
break). It also correctly inserts punctuation, when an AST\r\nnode is
surrounded by comments.\r\n\r\n\r\n### Parsing utils\r\n\r\nAll parsing
utils have been moved to the `/parser` sub-folder.\r\n\r\nFiles in the
`/parser` folder have been renamed as per Kibana convention\r\nto
reflect what is inside the file. For example, the
`EsqlErrorListener`\r\nclass is in a file named
`esql_error_listener.ts`.\r\n\r\nA `Query` class and
`ESQLAstQueryExpression` AST nodes have been\r\nintroduced. They
represent the result of a full query parse. (Before\r\nthat, the AST
root was just an array of command nodes, now the AST root\r\nis
represented by the `ESQLAstQueryExpression` node.)\r\n\r\n\r\n###
Builder\r\n\r\nI have started the implementation of the `Builder` static
class in the\r\n`/builder` folder. It is simply a collection of
stateless AST node\r\nfactories&mdash;functions which construct AST
nodes.\r\n\r\nSome of the `Builder` methods are already used by the
parser, more will\r\nfollow. We will also use the `Builder` in upcoming
[*Mutation\r\nAPI*](https://github.com/elastic/kibana/issues/191812).\r\n\r\n\r\n###
ES|QL Example Plugin\r\n\r\nThis PR sets up Storybook and implements few
Storybook stories for the\r\nES|QL AST example plugin, run it
with:\r\n\r\n```\r\nyarn storybook esql_ast_inspector\r\n```\r\n\r\nThis
PR updates the *ES|QL AST Explorer* example plugin. Start Kibana\r\nwith
example plugins enabled:\r\n\r\n```\r\nyarn start
--run-examples\r\n```\r\n\r\nAnd navigate
to\r\n[`/app/esql_ast_inspector`](http://localhost:5601/app/esql_ast_inspector)\r\nto
see the new example plugin
UI.\r\n\r\n\r\n\r\n![esql-ast-explorer](https://github.com/user-attachments/assets/8ded91ea-1b60-4514-8cf5-c8a4066a3a12)\r\n\r\n\r\n###
Checklist\r\n\r\n- [x] [Unit or
functional\r\ntests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)\r\nwere
updated or added to match the most common scenarios\r\n\r\n\r\n### For
maintainers\r\n\r\n- [x] This was checked for breaking API changes and
was
[labeled\r\nappropriately](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process)\r\n\r\n---------\r\n\r\nCo-authored-by:
kibanamachine
<42973632+kibanamachine@users.noreply.github.com>\r\nCo-authored-by:
Elastic Machine
<elasticmachine@users.noreply.github.com>\r\nCo-authored-by: Stratoula
Kalafateli
<efstratia.kalafateli@elastic.co>","sha":"2217337c5d91340ba67e0bedaab0762502518993"}},{"branch":"8.x","label":"v8.16.0","branchLabelMappingKey":"^v8.16.0$","isSourceBranch":false,"state":"NOT_CREATED"}]}]
BACKPORT-->

Co-authored-by: Vadim Kibana <82822460+vadimkibana@users.noreply.github.com>
  • Loading branch information
kibanamachine and vadimkibana authored Sep 26, 2024
1 parent ba9a67e commit 2fd6817
Show file tree
Hide file tree
Showing 87 changed files with 5,330 additions and 607 deletions.
10 changes: 10 additions & 0 deletions examples/esql_ast_inspector/.storybook/main.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the "Elastic License
* 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side
* Public License v 1"; you may not use this file except in compliance with, at
* your election, the "Elastic License 2.0", the "GNU Affero General Public
* License v3.0 only", or the "Server Side Public License, v 1".
*/

module.exports = require('@kbn/storybook').defaultConfig;
75 changes: 6 additions & 69 deletions examples/esql_ast_inspector/public/app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,84 +7,21 @@
* License v3.0 only", or the "Server Side Public License, v 1".
*/

import React, { useRef, useState } from 'react';
import {
EuiPage,
EuiPageBody,
EuiPageSection,
EuiPageHeader,
EuiSpacer,
EuiForm,
EuiTextArea,
EuiFormRow,
EuiButton,
} from '@elastic/eui';
import * as React from 'react';
import { EuiPage, EuiPageBody, EuiPageSection, EuiPageHeader, EuiSpacer } from '@elastic/eui';
import { EuiProvider } from '@elastic/eui';
import { EsqlInspector } from './components/esql_inspector';

import type { CoreStart } from '@kbn/core/public';

import { EditorError, ESQLAst, getAstAndSyntaxErrors } from '@kbn/esql-ast';
import { CodeEditor } from '@kbn/code-editor';
import type { StartDependencies } from './plugin';

export const App = (props: { core: CoreStart; plugins: StartDependencies }) => {
const [currentErrors, setErrors] = useState<EditorError[]>([]);
const [currentQuery, setQuery] = useState(
'from index1 | eval var0 = round(numberField, 2) | stats by stringField'
);

const inputRef = useRef<HTMLTextAreaElement | null>(null);

const [ast, setAST] = useState<ESQLAst>(getAstAndSyntaxErrors(currentQuery).ast);

const parseQuery = (query: string) => {
const { ast: _ast, errors } = getAstAndSyntaxErrors(query);
setErrors(errors);
setAST(_ast);
};

export const App = () => {
return (
<EuiProvider>
<EuiPage>
<EuiPageBody style={{ maxWidth: 800, margin: '0 auto' }}>
<EuiPageBody style={{ maxWidth: 1200, margin: '0 auto' }}>
<EuiPageHeader paddingSize="s" bottomBorder={true} pageTitle="ES|QL AST Inspector" />
<EuiPageSection paddingSize="s">
<p>This app gives you the AST for a particular ES|QL query.</p>

<EuiSpacer />

<EuiForm>
<EuiFormRow
fullWidth
label="Query"
isInvalid={Boolean(currentErrors.length)}
error={currentErrors.map((error) => error.message)}
>
<EuiTextArea
inputRef={(node) => {
inputRef.current = node;
}}
isInvalid={Boolean(currentErrors.length)}
fullWidth
value={currentQuery}
onChange={(e) => setQuery(e.target.value)}
css={{
height: '5em',
}}
/>
</EuiFormRow>
<EuiFormRow fullWidth>
<EuiButton fullWidth onClick={() => parseQuery(inputRef.current?.value ?? '')}>
Parse
</EuiButton>
</EuiFormRow>
</EuiForm>
<EuiSpacer />
<CodeEditor
allowFullScreen={true}
languageId={'json'}
value={JSON.stringify(ast, null, 2)}
/>
<EsqlInspector />
</EuiPageSection>
</EuiPageBody>
</EuiPage>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the "Elastic License
* 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side
* Public License v 1"; you may not use this file except in compliance with, at
* your election, the "Elastic License 2.0", the "GNU Affero General Public
* License v3.0 only", or the "Server Side Public License, v 1".
*/

import * as React from 'react';
import { Annotations } from './annotations';

export default {
title: '<Annotations>',
parameters: {},
};

export const Default = () => (
<Annotations
value={'FROM index | LIMIT 10 | SORT some_field'}
annotations={[
[0, 4, (text) => <span style={{ color: 'red' }}>{text}</span>],
[5, 10, (text) => <span style={{ color: 'blue' }}>{text}</span>],
[13, 18, (text) => <span style={{ color: 'red' }}>{text}</span>],
[19, 21, (text) => <span style={{ color: 'green' }}>{text}</span>],
]}
/>
);
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the "Elastic License
* 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side
* Public License v 1"; you may not use this file except in compliance with, at
* your election, the "Elastic License 2.0", the "GNU Affero General Public
* License v3.0 only", or the "Server Side Public License, v 1".
*/

import * as React from 'react';
import type { Annotation } from './types';

export interface AnnotationsProps {
value: string;
annotations?: Annotation[];
}

export const Annotations: React.FC<AnnotationsProps> = (props) => {
const { value, annotations = [] } = props;
const annotationNodes: React.ReactNode[] = [];

let pos = 0;

for (const [start, end, render] of annotations) {
if (start > pos) {
const text = value.slice(pos, start);

annotationNodes.push(<span>{text}</span>);
}

const text = value.slice(start, end);

pos = end;
annotationNodes.push(render(text));
}

if (pos < value.length) {
const text = value.slice(pos);
annotationNodes.push(<span>{text}</span>);
}

return React.createElement('span', {}, ...annotationNodes);
};
11 changes: 11 additions & 0 deletions examples/esql_ast_inspector/public/components/annotations/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the "Elastic License
* 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side
* Public License v 1"; you may not use this file except in compliance with, at
* your election, the "Elastic License 2.0", the "GNU Affero General Public
* License v3.0 only", or the "Server Side Public License, v 1".
*/

export { Annotations, type AnnotationsProps } from './annotations';
export type { Annotation } from './types';
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,10 @@
* License v3.0 only", or the "Server Side Public License, v 1".
*/

import type { Token } from 'antlr4';
import * as React from 'react';

export function getPosition(
token: Pick<Token, 'start' | 'stop'> | null,
lastToken?: Pick<Token, 'stop'> | undefined
) {
if (!token || token.start < 0) {
return { min: 0, max: 0 };
}
const endFirstToken = token.stop > -1 ? Math.max(token.stop + 1, token.start) : undefined;
const endLastToken = lastToken?.stop;
return {
min: token.start,
max: endLastToken ?? endFirstToken ?? Infinity,
};
}
export type Annotation = [
start: number,
end: number,
annotation: (text: string) => React.ReactNode
];
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the "Elastic License
* 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side
* Public License v 1"; you may not use this file except in compliance with, at
* your election, the "Elastic License 2.0", the "GNU Affero General Public
* License v3.0 only", or the "Server Side Public License, v 1".
*/

import * as React from 'react';
import { css } from '@emotion/react';
import { Annotations, type Annotation } from '../annotations';
import { FlexibleInput } from '../flexible_input/flexible_input';

const blockCss = css({
display: 'inline-block',
position: 'relative',
width: '100%',
fontSize: '18px',
lineHeight: '1.3',
fontFamily:
"'SF Mono', SFMono-Regular, ui-monospace, 'DejaVu Sans Mono', Menlo, Consolas, monospace",
});

const backdropCss = css({
display: 'inline-block',
position: 'absolute',
left: 0,
width: '100%',
pointerEvents: 'all',
userSelect: 'none',
whiteSpace: 'pre',
color: 'rgba(255, 255, 255, 0.01)',
});

const inputCss = css({
display: 'inline-block',
color: 'rgba(255, 255, 255, 0.01)',
caretColor: '#07f',
});

const overlayCss = css({
display: 'inline-block',
position: 'absolute',
left: 0,
width: '100%',
pointerEvents: 'none',
userSelect: 'none',
whiteSpace: 'pre',
});

export interface EsqlEditorProps {
src: string;
backdrops?: Annotation[][];
highlight?: Annotation[];
onChange: (src: string) => void;
}

export const EsqlEditor: React.FC<EsqlEditorProps> = (props) => {
const { src, highlight, onChange } = props;

const backdrops: React.ReactNode[] = [];

if (props.backdrops) {
for (let i = 0; i < props.backdrops.length; i++) {
const backdrop = props.backdrops[i];

backdrops.push(
<div key={i} css={backdropCss}>
<Annotations value={src} annotations={backdrop} />
</div>
);
}
}

const overlay = !!highlight && (
<div css={overlayCss}>
<Annotations value={src} annotations={highlight} />
</div>
);

return (
<div css={blockCss}>
{backdrops}
<div css={inputCss}>
<FlexibleInput multiline value={src} onChange={(e) => onChange(e.target.value)} />
</div>
{overlay}
</div>
);
};
Loading

0 comments on commit 2fd6817

Please sign in to comment.