diff --git a/src-web/components/GrpcEditor.tsx b/src-web/components/GrpcEditor.tsx
index f3378487..b404d5f8 100644
--- a/src-web/components/GrpcEditor.tsx
+++ b/src-web/components/GrpcEditor.tsx
@@ -1,7 +1,15 @@
+import { jsonLanguage } from '@codemirror/lang-json';
+import { linter } from '@codemirror/lint';
import classNames from 'classnames';
import type { EditorView } from 'codemirror';
-import { updateSchema } from 'codemirror-json-schema';
-import { useEffect, useRef } from 'react';
+import {
+ handleRefresh,
+ jsonCompletion,
+ jsonSchemaLinter,
+ stateExtensions,
+ updateSchema,
+} from 'codemirror-json-schema';
+import { useEffect, useMemo, useRef } from 'react';
import { useAlert } from '../hooks/useAlert';
import type { ReflectResponseService } from '../hooks/useGrpc';
import { tryFormatJson } from '../lib/formatters';
@@ -101,13 +109,82 @@ export function GrpcEditor({
}
}, [alert, services, request.method, request.service]);
+ const extraExtensions = useMemo(
+ () => [
+ linter(jsonSchemaLinter(), {
+ delay: 200,
+ needsRefresh: handleRefresh,
+ }),
+ jsonLanguage.data.of({
+ autocomplete: jsonCompletion(),
+ }),
+ stateExtensions(/** Init with empty schema **/),
+ ],
+ [],
+ );
+
const reflectionUnavailable = reflectionError?.match(/unimplemented/i);
reflectionError = reflectionUnavailable ? undefined : reflectionError;
+ const actions = useMemo(
+ () => [
+
+
+
,
+ ],
+ [
+ dialog,
+ protoFiles.length,
+ reflectionError,
+ reflectionLoading,
+ reflectionUnavailable,
+ request.id,
+ services,
+ ],
+ );
+
return (
-
-
,
- ]}
+ extraExtensions={extraExtensions}
+ actions={actions}
{...extraEditorProps}
/>
diff --git a/src-web/components/core/Editor/Editor.tsx b/src-web/components/core/Editor/Editor.tsx
index 7b4c140f..5b6a8f23 100644
--- a/src-web/components/core/Editor/Editor.tsx
+++ b/src-web/components/core/Editor/Editor.tsx
@@ -1,5 +1,5 @@
import { defaultKeymap } from '@codemirror/commands';
-import { Compartment, EditorState } from '@codemirror/state';
+import { Compartment, EditorState, type Extension } from '@codemirror/state';
import { keymap, placeholder as placeholderExt, tooltips } from '@codemirror/view';
import classNames from 'classnames';
import { EditorView } from 'codemirror';
@@ -53,6 +53,7 @@ export interface EditorProps {
format?: (v: string) => string;
autocomplete?: GenericCompletionConfig;
autocompleteVariables?: boolean;
+ extraExtensions?: Extension[];
actions?: ReactNode;
}
@@ -76,6 +77,7 @@ const _Editor = forwardRef(function Editor(
singleLine,
format,
autocomplete,
+ extraExtensions,
autocompleteVariables,
actions,
wrapLines,
@@ -188,6 +190,7 @@ const _Editor = forwardRef(function Editor(
onBlur: handleBlur,
onKeyDown: handleKeyDown,
}),
+ ...(extraExtensions ?? []),
],
});
diff --git a/src-web/components/core/Editor/extensions.ts b/src-web/components/core/Editor/extensions.ts
index c2bc72cd..028a4fc8 100644
--- a/src-web/components/core/Editor/extensions.ts
+++ b/src-web/components/core/Editor/extensions.ts
@@ -17,6 +17,7 @@ import {
syntaxHighlighting,
} from '@codemirror/language';
import { lintKeymap } from '@codemirror/lint';
+
import { highlightSelectionMatches, searchKeymap } from '@codemirror/search';
import { EditorState } from '@codemirror/state';
import {
@@ -85,7 +86,6 @@ const myTheme = EditorView.theme({}, { dark: true });
// ]);
const syntaxExtensions: Record = {
- 'application/grpc': json(), // TODO: Make JSONSchema work
'application/graphql': graphqlLanguageSupport(),
'application/json': json(),
'application/javascript': javascript(),