mirror of https://github.com/portainer/portainer
92 lines
2.7 KiB
TypeScript
92 lines
2.7 KiB
TypeScript
import { useMemo } from 'react';
|
|
import {
|
|
StreamLanguage,
|
|
LanguageSupport,
|
|
syntaxHighlighting,
|
|
indentService,
|
|
} from '@codemirror/language';
|
|
import { dockerFile } from '@codemirror/legacy-modes/mode/dockerfile';
|
|
import { shell } from '@codemirror/legacy-modes/mode/shell';
|
|
import {
|
|
oneDarkHighlightStyle,
|
|
keymap,
|
|
Extension,
|
|
} from '@uiw/react-codemirror';
|
|
import type { JSONSchema7 } from 'json-schema';
|
|
import { lintKeymap, lintGutter } from '@codemirror/lint';
|
|
import { defaultKeymap } from '@codemirror/commands';
|
|
import { autocompletion, completionKeymap } from '@codemirror/autocomplete';
|
|
import { yamlCompletion, yamlSchema } from 'yaml-schema';
|
|
import { compact } from 'lodash';
|
|
import { lineNumbers } from '@codemirror/view';
|
|
|
|
export type CodeEditorType = 'yaml' | 'shell' | 'dockerfile';
|
|
|
|
// Custom indentation service for YAML
|
|
const yamlIndentExtension = indentService.of((context, pos) => {
|
|
const prevLine = context.lineAt(pos, -1);
|
|
const prevIndent = /^\s*/.exec(prevLine.text)?.[0].length || 0;
|
|
if (/:\s*$/.test(prevLine.text)) {
|
|
return prevIndent + 2;
|
|
}
|
|
return prevIndent;
|
|
});
|
|
|
|
const dockerFileLanguage = new LanguageSupport(
|
|
StreamLanguage.define(dockerFile)
|
|
);
|
|
const shellLanguage = new LanguageSupport(StreamLanguage.define(shell));
|
|
|
|
function yamlLanguage(schema?: JSONSchema7) {
|
|
const [yaml, linter, , , stateExtensions] = yamlSchema(schema);
|
|
|
|
return compact([
|
|
yaml,
|
|
linter,
|
|
stateExtensions,
|
|
yamlIndentExtension,
|
|
syntaxHighlighting(oneDarkHighlightStyle),
|
|
// explicitly setting lineNumbers() as an extension ensures that the gutter order is the same between the diff viewer and the code editor
|
|
lineNumbers(),
|
|
lintGutter(),
|
|
keymap.of([...defaultKeymap, ...completionKeymap, ...lintKeymap]),
|
|
// only show completions when a schema is provided
|
|
!!schema &&
|
|
autocompletion({
|
|
icons: false,
|
|
activateOnTypingDelay: 300,
|
|
selectOnOpen: true,
|
|
activateOnTyping: true,
|
|
override: [
|
|
(ctx) => {
|
|
const getCompletions = yamlCompletion();
|
|
const completions = getCompletions(ctx);
|
|
if (Array.isArray(completions)) {
|
|
return null;
|
|
}
|
|
completions.validFor = /^\w*$/;
|
|
return completions;
|
|
},
|
|
],
|
|
}),
|
|
]);
|
|
}
|
|
|
|
export function useCodeEditorExtensions(
|
|
type?: CodeEditorType,
|
|
schema?: JSONSchema7
|
|
): Extension[] {
|
|
return useMemo(() => {
|
|
switch (type) {
|
|
case 'dockerfile':
|
|
return [dockerFileLanguage];
|
|
case 'shell':
|
|
return [shellLanguage];
|
|
case 'yaml':
|
|
return yamlLanguage(schema);
|
|
default:
|
|
return [];
|
|
}
|
|
}, [type, schema]);
|
|
}
|