2024-06-10 22:24:26 +00:00
|
|
|
<script lang="ts">
|
|
|
|
import { basicSetup, EditorView } from 'codemirror';
|
|
|
|
import { keymap, placeholder } from '@codemirror/view';
|
2024-06-10 23:02:23 +00:00
|
|
|
import { Compartment, EditorState } from '@codemirror/state';
|
2024-06-10 22:24:26 +00:00
|
|
|
|
|
|
|
import { acceptCompletion } from '@codemirror/autocomplete';
|
|
|
|
import { indentWithTab } from '@codemirror/commands';
|
|
|
|
|
2024-06-11 00:12:48 +00:00
|
|
|
import { indentUnit } from '@codemirror/language';
|
2024-06-10 22:24:26 +00:00
|
|
|
import { python } from '@codemirror/lang-python';
|
|
|
|
import { oneDark } from '@codemirror/theme-one-dark';
|
|
|
|
|
2024-06-11 00:12:48 +00:00
|
|
|
import { onMount, createEventDispatcher } from 'svelte';
|
|
|
|
import { formatPythonCode } from '$lib/apis/utils';
|
|
|
|
import { toast } from 'svelte-sonner';
|
|
|
|
|
|
|
|
const dispatch = createEventDispatcher();
|
2024-06-10 22:24:26 +00:00
|
|
|
|
2024-06-10 23:35:42 +00:00
|
|
|
export let boilerplate = '';
|
2024-06-10 22:24:26 +00:00
|
|
|
export let value = '';
|
|
|
|
|
2024-06-10 23:02:23 +00:00
|
|
|
let codeEditor;
|
|
|
|
|
|
|
|
let isDarkMode = false;
|
|
|
|
let editorTheme = new Compartment();
|
|
|
|
|
2024-06-11 00:30:07 +00:00
|
|
|
export const formatPythonCodeHandler = async () => {
|
2024-06-11 00:12:48 +00:00
|
|
|
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 }]
|
|
|
|
});
|
2024-06-11 00:24:42 +00:00
|
|
|
|
|
|
|
toast.success('Code formatted successfully');
|
2024-06-11 00:12:48 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
2024-06-11 02:19:53 +00:00
|
|
|
return false;
|
2024-06-11 00:12:48 +00:00
|
|
|
};
|
|
|
|
|
2024-06-10 23:02:23 +00:00
|
|
|
let extensions = [
|
|
|
|
basicSetup,
|
|
|
|
keymap.of([{ key: 'Tab', run: acceptCompletion }, indentWithTab]),
|
|
|
|
python(),
|
2024-06-11 00:12:48 +00:00
|
|
|
indentUnit.of(' '),
|
2024-06-10 23:02:23 +00:00
|
|
|
placeholder('Enter your code here...'),
|
|
|
|
EditorView.updateListener.of((e) => {
|
|
|
|
if (e.docChanged) {
|
|
|
|
value = e.state.doc.toString();
|
|
|
|
}
|
|
|
|
}),
|
|
|
|
editorTheme.of([])
|
|
|
|
];
|
|
|
|
|
2024-06-10 22:24:26 +00:00
|
|
|
onMount(() => {
|
2024-06-11 04:53:51 +00:00
|
|
|
console.log(value);
|
|
|
|
if (value === '') {
|
|
|
|
value = boilerplate;
|
|
|
|
}
|
2024-06-11 00:24:42 +00:00
|
|
|
|
2024-06-10 23:02:23 +00:00
|
|
|
// Check if html class has dark mode
|
|
|
|
isDarkMode = document.documentElement.classList.contains('dark');
|
|
|
|
|
2024-06-10 22:24:26 +00:00
|
|
|
// python code editor, highlight python code
|
2024-06-10 23:02:23 +00:00
|
|
|
codeEditor = new EditorView({
|
2024-06-10 22:24:26 +00:00
|
|
|
state: EditorState.create({
|
2024-06-11 00:24:42 +00:00
|
|
|
doc: value,
|
2024-06-10 23:02:23 +00:00
|
|
|
extensions: extensions
|
2024-06-10 22:24:26 +00:00
|
|
|
}),
|
|
|
|
parent: document.getElementById('code-textarea')
|
|
|
|
});
|
2024-06-10 23:02:23 +00:00
|
|
|
|
|
|
|
if (isDarkMode) {
|
|
|
|
codeEditor.dispatch({
|
|
|
|
effects: editorTheme.reconfigure(oneDark)
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
// listen to html class changes this should fire only when dark mode is toggled
|
|
|
|
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']
|
|
|
|
});
|
|
|
|
|
2024-06-11 05:33:25 +00:00
|
|
|
const keydownHandler = async (e) => {
|
2024-06-11 00:12:48 +00:00
|
|
|
if ((e.ctrlKey || e.metaKey) && e.key === 's') {
|
|
|
|
e.preventDefault();
|
2024-06-11 03:58:47 +00:00
|
|
|
dispatch('save');
|
2024-06-11 00:12:48 +00:00
|
|
|
}
|
2024-06-11 05:33:25 +00:00
|
|
|
|
|
|
|
// Format code when Ctrl + Shift + F is pressed
|
|
|
|
if ((e.ctrlKey || e.metaKey) && e.shiftKey && e.key === 'f') {
|
|
|
|
e.preventDefault();
|
|
|
|
await formatPythonCodeHandler();
|
|
|
|
}
|
2024-06-11 00:12:48 +00:00
|
|
|
};
|
|
|
|
|
2024-06-11 05:33:25 +00:00
|
|
|
document.addEventListener('keydown', keydownHandler);
|
2024-06-11 00:12:48 +00:00
|
|
|
|
2024-06-10 23:02:23 +00:00
|
|
|
return () => {
|
|
|
|
observer.disconnect();
|
2024-06-11 05:33:25 +00:00
|
|
|
document.removeEventListener('keydown', keydownHandler);
|
2024-06-10 23:02:23 +00:00
|
|
|
};
|
2024-06-10 22:24:26 +00:00
|
|
|
});
|
|
|
|
</script>
|
|
|
|
|
2024-06-10 23:02:23 +00:00
|
|
|
<div id="code-textarea" class="h-full w-full" />
|