Skip to content

Commit

Permalink
simplify fasthtml code editor
Browse files Browse the repository at this point in the history
  • Loading branch information
austinvhuang committed Aug 8, 2024
1 parent 88d7059 commit 305c25a
Show file tree
Hide file tree
Showing 5 changed files with 176 additions and 198 deletions.
126 changes: 126 additions & 0 deletions experimental/fasthtml/components/code_editor.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@

let editor;
let completionTippy;
let currentCompletion = '';

function updateEditor(delta) {
if (delta.action === 'insert' && (delta.lines[0] === '.' || delta.lines[0] === ' ')) {
showCompletionSuggestion();
}

// Recover from errors TODO(avh): only do this if there's an error
createModule().then((Module) => {
// Keep your existing Module setup
Module.print = window.customPrint;
Module.printErr = window.customPrint;
window.Module = Module;
console.log("updateEditor() - Module ready");
});

if (window.Module && window.Module.executeKernel) {
console.log("Executing kernel");
window.terminal.clear();
window.Module.executeKernel(editor.getValue());
} else {
console.log("updateEditor() - Module not ready");
}
}

function initEditor(initial_content) {
editor = ace.edit("editor");
editor.setTheme("ace/theme/monokai");
editor.session.setMode("ace/mode/javascript");
editor.setOptions({
fontSize: "14px",
showPrintMargin: false,
// disable showing errors in gutter, Ace's WGSL parser is out of date
showGutter: false,
highlightActiveLine: true,
wrap: true,
});
editor.setKeyboardHandler("ace/keyboard/vim");
editor.setValue(initial_content);
window.addEventListener('resize', function() {
editor.resize();
});
// document.getElementById('language').addEventListener('change', function(e) {
// let mode = "ace/mode/" + e.target.value;
// editor.session.setMode(mode);
// });

editor.session.on('change', updateEditor);

completionTippy = tippy(document.getElementById('editor'), {
content: 'Loading...',
trigger: 'manual',
placement: 'top-start',
arrow: true,
interactive: true
});

// Override the default tab behavior
editor.commands.addCommand({
name: 'insertCompletion',
bindKey: {win: 'Tab', mac: 'Tab'},
exec: function(editor) {
if (currentCompletion) {
editor.insert(currentCompletion);
currentCompletion = '';
completionTippy.hide();
} else {
editor.indent();
}
}
});
}

async function showCompletionSuggestion() {
const cursorPosition = editor.getCursorPosition();
const screenPosition = editor.renderer.textToScreenCoordinates(cursorPosition.row, cursorPosition.column);

completionTippy.setContent('Loading...');
completionTippy.setProps({
getReferenceClientRect: () => ({
width: 0,
height: 0,
top: screenPosition.pageY,
bottom: screenPosition.pageY,
left: screenPosition.pageX,
right: screenPosition.pageX,
})
});
completionTippy.show();

try {
const response = await fetch('/complete', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
code: editor.getValue(),
row: cursorPosition.row,
column: cursorPosition.column
}),
});

if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}

const data = await response.json();
currentCompletion = data.completion;
completionTippy.setContent(`${currentCompletion} (Press Tab to insert)`);
} catch (error) {
console.error('Error:', error);
completionTippy.setContent('Error fetching completion');
currentCompletion = '';
}

setTimeout(() => {
if (currentCompletion) {
completionTippy.hide();
currentCompletion = '';
}
}, 5000);
}
152 changes: 20 additions & 132 deletions experimental/fasthtml/components/code_editor.py
Original file line number Diff line number Diff line change
@@ -1,145 +1,33 @@
# Adapted from: https://github.com/AnswerDotAI/fasthtml-example/tree/baa67c5b2ca4d4a9ba091b9f9b72b8a2de384a37/code_editor

from fasthtml.common import *
from .toolbar import Toolbar
import json

def editor_script(initial_content: str) -> Script:
return Script("""
let editor;
let completionTippy;
let currentCompletion = '';
function initEditor() {
editor = ace.edit("editor");
editor.setTheme("ace/theme/monokai");
editor.session.setMode("ace/mode/javascript");
editor.setOptions({
fontSize: "14px",
showPrintMargin: false,
// disable showing errors in gutter, Ace's WGSL parser is out of date
showGutter: false,
highlightActiveLine: true,
wrap: true,
});
editor.setKeyboardHandler("ace/keyboard/vim");
editor.setValue(""" + json.dumps(initial_content) + ");" +
"""
window.addEventListener('resize', function() {
editor.resize();
});
document.getElementById('language').addEventListener('change', function(e) {
let mode = "ace/mode/" + e.target.value;
editor.session.setMode(mode);
});
editor.session.on('change', function(delta) {
if (delta.action === 'insert' && (delta.lines[0] === '.' || delta.lines[0] === ' ')) {
showCompletionSuggestion();
}
// Recover from errors TODO(avh): only do this if there's an error
createModule().then((Module) => {
// Keep your existing Module setup
Module.print = window.customPrint;
Module.printErr = window.customPrint;
window.Module = Module;
console.log("Module ready");
});
if (window.Module && window.Module.executeKernel) {
console.log("Executing kernel");
window.terminal.clear();
window.Module.executeKernel(editor.getValue());
} else {
console.log("Module not ready");
}
});
completionTippy = tippy(document.getElementById('editor'), {
content: 'Loading...',
trigger: 'manual',
placement: 'top-start',
arrow: true,
interactive: true
});
// Override the default tab behavior
editor.commands.addCommand({
name: 'insertCompletion',
bindKey: {win: 'Tab', mac: 'Tab'},
exec: function(editor) {
if (currentCompletion) {
editor.insert(currentCompletion);
currentCompletion = '';
completionTippy.hide();
} else {
editor.indent();
}
}
});
}
async function showCompletionSuggestion() {
const cursorPosition = editor.getCursorPosition();
const screenPosition = editor.renderer.textToScreenCoordinates(cursorPosition.row, cursorPosition.column);
completionTippy.setContent('Loading...');
completionTippy.setProps({
getReferenceClientRect: () => ({
width: 0,
height: 0,
top: screenPosition.pageY,
bottom: screenPosition.pageY,
left: screenPosition.pageX,
right: screenPosition.pageX,
})
});
completionTippy.show();
try {
const response = await fetch('/complete', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
code: editor.getValue(),
row: cursorPosition.row,
column: cursorPosition.column
}),
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
currentCompletion = data.completion;
completionTippy.setContent(`${currentCompletion} (Press Tab to insert)`);
} catch (error) {
console.error('Error:', error);
completionTippy.setContent('Error fetching completion');
currentCompletion = '';
}
def Toolbar():
return Div(
Select(
Option("WGSL", value="wgsl"),
Option("C++", value="c++"),
id="language",
cls="mr-2 p-2 border rounded"
),
cls="bg-gray-200 p-4 shadow-md flex items-center w-full"
)

setTimeout(() => {
if (currentCompletion) {
completionTippy.hide();
currentCompletion = '';
}
}, 5000);
}
def editor_script(initial_content: str) -> str:
with open("components/code_editor.js", 'r') as file:
file_content = file.read()
initial_content = json.dumps(initial_content)
return(f"""{file_content}
document.addEventListener('DOMContentLoaded', () => {{
initEditor({initial_content});
updateEditor("");
}});""")

document.addEventListener('DOMContentLoaded', initEditor);
""")

def CodeEditor(initial_content: str):
return (
Div(
Toolbar(),
Div(
Div(id="editor", style="height: 90vh; width: 100vw;"),
Script("""
Expand All @@ -154,5 +42,5 @@ def CodeEditor(initial_content: str):
# cls="flex flex-col h-screen w-full", style="height: 100vh; overflow: hidden;"
style="height: 100vh; overflow: hidden;"
),
editor_script(initial_content)
Script(editor_script(initial_content))
)
12 changes: 0 additions & 12 deletions experimental/fasthtml/components/toolbar.py

This file was deleted.

3 changes: 1 addition & 2 deletions experimental/fasthtml/run.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,7 @@ void executeKernel(const char *kernelCode) {
inputArr[i], outputArr[i]);
js_print(buffer);
}
snprintf(buffer, sizeof(buffer), " ...");
js_print(buffer);
js_print(" ...");
for (int i = N - 10; i < N; ++i) {
snprintf(buffer, sizeof(buffer), " [%d] kernel(%.1f) = %.4f", i,
inputArr[i], outputArr[i]);
Expand Down
Loading

0 comments on commit 305c25a

Please sign in to comment.