11# Adapted from: https://github.com/AnswerDotAI/fasthtml-example/tree/baa67c5b2ca4d4a9ba091b9f9b72b8a2de384a37/code_editor
22
33from fasthtml .common import *
4- from .toolbar import Toolbar
54import json
65
7- def editor_script (initial_content : str ) -> Script :
8- return Script ("""
9- let editor;
10- let completionTippy;
11- let currentCompletion = '';
12-
13- function initEditor() {
14- editor = ace.edit("editor");
15- editor.setTheme("ace/theme/monokai");
16- editor.session.setMode("ace/mode/javascript");
17- editor.setOptions({
18- fontSize: "14px",
19- showPrintMargin: false,
20- // disable showing errors in gutter, Ace's WGSL parser is out of date
21- showGutter: false,
22- highlightActiveLine: true,
23- wrap: true,
24- });
25- editor.setKeyboardHandler("ace/keyboard/vim");
26-
27- editor.setValue(""" + json .dumps (initial_content ) + ");" +
28- """
29- window.addEventListener('resize', function() {
30- editor.resize();
31- });
32- document.getElementById('language').addEventListener('change', function(e) {
33- let mode = "ace/mode/" + e.target.value;
34- editor.session.setMode(mode);
35- });
36-
37- editor.session.on('change', function(delta) {
38- if (delta.action === 'insert' && (delta.lines[0] === '.' || delta.lines[0] === ' ')) {
39- showCompletionSuggestion();
40- }
41-
42- // Recover from errors TODO(avh): only do this if there's an error
43- createModule().then((Module) => {
44- // Keep your existing Module setup
45- Module.print = window.customPrint;
46- Module.printErr = window.customPrint;
47- window.Module = Module;
48- console.log("Module ready");
49- });
50-
51- if (window.Module && window.Module.executeKernel) {
52- console.log("Executing kernel");
53- window.terminal.clear();
54- window.Module.executeKernel(editor.getValue());
55- } else {
56- console.log("Module not ready");
57- }
58-
59- });
60-
61- completionTippy = tippy(document.getElementById('editor'), {
62- content: 'Loading...',
63- trigger: 'manual',
64- placement: 'top-start',
65- arrow: true,
66- interactive: true
67- });
68-
69- // Override the default tab behavior
70- editor.commands.addCommand({
71- name: 'insertCompletion',
72- bindKey: {win: 'Tab', mac: 'Tab'},
73- exec: function(editor) {
74- if (currentCompletion) {
75- editor.insert(currentCompletion);
76- currentCompletion = '';
77- completionTippy.hide();
78- } else {
79- editor.indent();
80- }
81- }
82- });
83- }
84-
85- async function showCompletionSuggestion() {
86- const cursorPosition = editor.getCursorPosition();
87- const screenPosition = editor.renderer.textToScreenCoordinates(cursorPosition.row, cursorPosition.column);
88-
89- completionTippy.setContent('Loading...');
90- completionTippy.setProps({
91- getReferenceClientRect: () => ({
92- width: 0,
93- height: 0,
94- top: screenPosition.pageY,
95- bottom: screenPosition.pageY,
96- left: screenPosition.pageX,
97- right: screenPosition.pageX,
98- })
99- });
100- completionTippy.show();
101-
102- try {
103- const response = await fetch('/complete', {
104- method: 'POST',
105- headers: {
106- 'Content-Type': 'application/json',
107- },
108- body: JSON.stringify({
109- code: editor.getValue(),
110- row: cursorPosition.row,
111- column: cursorPosition.column
112- }),
113- });
114-
115- if (!response.ok) {
116- throw new Error(`HTTP error! status: ${response.status}`);
117- }
118-
119- const data = await response.json();
120- currentCompletion = data.completion;
121- completionTippy.setContent(`${currentCompletion} (Press Tab to insert)`);
122- } catch (error) {
123- console.error('Error:', error);
124- completionTippy.setContent('Error fetching completion');
125- currentCompletion = '';
126- }
6+ def Toolbar ():
7+ return Div (
8+ Select (
9+ Option ("WGSL" , value = "wgsl" ),
10+ Option ("C++" , value = "c++" ),
11+ id = "language" ,
12+ cls = "mr-2 p-2 border rounded"
13+ ),
14+ cls = "bg-gray-200 p-4 shadow-md flex items-center w-full"
15+ )
12716
128- setTimeout(() => {
129- if (currentCompletion) {
130- completionTippy.hide();
131- currentCompletion = '';
132- }
133- }, 5000);
134- }
17+ def editor_script (initial_content : str ) -> str :
18+ with open ("components/code_editor.js" , 'r' ) as file :
19+ file_content = file .read ()
20+ initial_content = json .dumps (initial_content )
21+ return (f"""{ file_content }
22+ document.addEventListener('DOMContentLoaded', () => {{
23+ initEditor({ initial_content } );
24+ updateEditor("");
25+ }});""" )
13526
136- document.addEventListener('DOMContentLoaded', initEditor);
137- """ )
13827
13928def CodeEditor (initial_content : str ):
14029 return (
14130 Div (
142- Toolbar (),
14331 Div (
14432 Div (id = "editor" , style = "height: 90vh; width: 100vw;" ),
14533 Script ("""
@@ -154,5 +42,5 @@ def CodeEditor(initial_content: str):
15442 # cls="flex flex-col h-screen w-full", style="height: 100vh; overflow: hidden;"
15543 style = "height: 100vh; overflow: hidden;"
15644 ),
157- editor_script (initial_content )
45+ Script ( editor_script (initial_content ) )
15846 )
0 commit comments