| | <script lang="ts"> |
| | import { basicSetup, EditorView } from 'codemirror'; |
| | import { keymap, placeholder } from '@codemirror/view'; |
| | import { Compartment, EditorState } from '@codemirror/state'; |
| | |
| | import { acceptCompletion } from '@codemirror/autocomplete'; |
| | import { indentWithTab } from '@codemirror/commands'; |
| | |
| | import { indentUnit } from '@codemirror/language'; |
| | import { languages } from '@codemirror/language-data'; |
| | |
| | { python } from '@codemirror/lang-python'; |
| | { javascript } from '@codemirror/lang-javascript'; |
| | |
| | import { oneDark } from '@codemirror/theme-one-dark'; |
| | |
| | import { onMount, createEventDispatcher, getContext, tick } from 'svelte'; |
| | |
| | import { formatPythonCode } from '$lib/apis/utils'; |
| | import { toast } from 'svelte-sonner'; |
| | |
| | const dispatch = createEventDispatcher(); |
| | const i18n = getContext('i18n'); |
| | |
| | export let boilerplate = ''; |
| | export let value = ''; |
| | let _value = ''; |
| | |
| | $: if (value) { |
| | updateValue(); |
| | } |
| | |
| | const updateValue = () => { |
| | if (_value !== value) { |
| | _value = value; |
| | if (codeEditor) { |
| | codeEditor.dispatch({ |
| | changes: [{ from: 0, to: codeEditor.state.doc.length, insert: _value }] |
| | }); |
| | } |
| | } |
| | }; |
| | |
| | export let id = ''; |
| | export let lang = ''; |
| | |
| | let codeEditor; |
| | |
| | let isDarkMode = false; |
| | let editorTheme = new Compartment(); |
| | let editorLanguage = new Compartment(); |
| | |
| | const getLang = async () => { |
| | const language = languages.find((l) => l.alias.includes(lang)); |
| | return await language?.load(); |
| | }; |
| | |
| | export const formatPythonCodeHandler = async () => { |
| | if (codeEditor) { |
| | const res = await formatPythonCode(_value).catch((error) => { |
| | toast.error(error); |
| | return null; |
| | }); |
| | |
| | if (res && res.code) { |
| | const formattedCode = res.code; |
| | codeEditor.dispatch({ |
| | changes: [{ from: 0, to: codeEditor.state.doc.length, insert: formattedCode }] |
| | }); |
| | |
| | _value = formattedCode; |
| | dispatch('change', { value: _value }); |
| | await tick(); |
| | |
| | toast.success($i18n.t('Code formatted successfully')); |
| | return true; |
| | } |
| | return false; |
| | } |
| | return false; |
| | }; |
| | |
| | let extensions = [ |
| | basicSetup, |
| | keymap.of([{ key: 'Tab', run: acceptCompletion }, indentWithTab]), |
| | indentUnit.of(' '), |
| | placeholder('Enter your code here...'), |
| | EditorView.updateListener.of((e) => { |
| | if (e.docChanged) { |
| | _value = e.state.doc.toString(); |
| | dispatch('change', { value: _value }); |
| | } |
| | }), |
| | editorTheme.of([]), |
| | editorLanguage.of([]) |
| | ]; |
| | |
| | $: if (lang) { |
| | setLanguage(); |
| | } |
| | |
| | const setLanguage = async () => { |
| | const language = await getLang(); |
| | if (language) { |
| | codeEditor.dispatch({ |
| | effects: editorLanguage.reconfigure(language) |
| | }); |
| | } |
| | }; |
| | |
| | onMount(() => { |
| | console.log(value); |
| | if (value === '') { |
| | value = boilerplate; |
| | } |
| | |
| | _value = value; |
| | |
| | |
| | isDarkMode = document.documentElement.classList.contains('dark'); |
| | |
| | |
| | codeEditor = new EditorView({ |
| | state: EditorState.create({ |
| | doc: _value, |
| | extensions: extensions |
| | }), |
| | parent: document.getElementById(`code-textarea-${id}`) |
| | }); |
| | |
| | if (isDarkMode) { |
| | codeEditor.dispatch({ |
| | effects: editorTheme.reconfigure(oneDark) |
| | }); |
| | } |
| | |
| | |
| | const observer = new MutationObserver((mutations) => { |
| | mutations.forEach((mutation) => { |
| | if (mutation.type === 'attributes' && mutation.attributeName === 'class') { |
| | const _isDarkMode = document.documentElement.classList.contains('dark'); |
| | |
| | if (_isDarkMode !== isDarkMode) { |
| | isDarkMode = _isDarkMode; |
| | if (_isDarkMode) { |
| | codeEditor.dispatch({ |
| | effects: editorTheme.reconfigure(oneDark) |
| | }); |
| | } else { |
| | codeEditor.dispatch({ |
| | effects: editorTheme.reconfigure() |
| | }); |
| | } |
| | } |
| | } |
| | }); |
| | }); |
| | |
| | observer.observe(document.documentElement, { |
| | attributes: true, |
| | attributeFilter: ['class'] |
| | }); |
| | |
| | const keydownHandler = async (e) => { |
| | if ((e.ctrlKey || e.metaKey) && e.key === 's') { |
| | e.preventDefault(); |
| | dispatch('save'); |
| | } |
| | |
| | |
| | if ((e.ctrlKey || e.metaKey) && e.shiftKey && e.key === 'f') { |
| | e.preventDefault(); |
| | await formatPythonCodeHandler(); |
| | } |
| | }; |
| | |
| | document.addEventListener('keydown', keydownHandler); |
| | |
| | return () => { |
| | observer.disconnect(); |
| | document.removeEventListener('keydown', keydownHandler); |
| | }; |
| | }); |
| | </script> |
| |
|
| | <div id="code-textarea-{id}" class="h-full w-full" /> |
| |
|