Skip to content

Commit

Permalink
split up fasthtml subprojects
Browse files Browse the repository at this point in the history
  • Loading branch information
austinvhuang committed Aug 9, 2024
1 parent bf7879f commit 47542f8
Show file tree
Hide file tree
Showing 12 changed files with 813 additions and 50 deletions.
46 changes: 0 additions & 46 deletions experimental/fasthtml/components/code_editor.py

This file was deleted.

33 changes: 33 additions & 0 deletions experimental/fasthtml/gpu_puzzles/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
GPUCPP=../../../
COMMON_FLAGS=-std=c++17 -s USE_WEBGPU=1 -s ASYNCIFY=1 -I$(GPUCPP)
# Note - no spaces after comma
# enable exceptions to recover from WGSL failure
JS_FLAGS=-s EXPORTED_RUNTIME_METHODS=['UTF8ToString','setValue','addFunction'] -s EXPORTED_FUNCTIONS=['_malloc','_free','_executeKernel'] -s NO_DISABLE_EXCEPTION_CATCHING
WASM_FLAGS=-s STANDALONE_WASM -s ERROR_ON_UNDEFINED_SYMBOLS=0 -s EXPORTED_FUNCTIONS=['_executeKernel'] -s EXPORTED_RUNTIME_METHODS=['ccall','cwrap'] -DSTANDALONE_WASM
MODULARIZE_FLAGS=-s EXPORT_NAME='createModule' -s MODULARIZE=1 --bind
NO_MODULARIZE_FLAGS=-s EXPORTED_FUNCTIONS=['_executeKernel'] -s EXPORTED_RUNTIME_METHODS=['ccall','cwrap'] --bind

.PHONY: default cmake check-emsdk browser clean server

default: server

build/run.js: check-emsdk run.cpp
em++ run.cpp -o build/run.js \
$(COMMON_FLAGS) $(JS_FLAGS) $(MODULARIZE_FLAGS)

build/run.wasm: check-emsdk run.cpp
em++ run.cpp -o build/run.wasm \
$(COMMON_FLAGS) $(WASM_FLAGS)

watch:
@echo "Watching for changes..."
ls run.cpp | entr -c make build/run.js

server: build/run.js
python3 run.py

clean:
rm -rf build/*

check-emsdk:
@which em++ > /dev/null || (echo "emsdk not found. Please install emsdk and run 'source emsdk_env.sh' in the emsdk directory." && exit 1)
103 changes: 103 additions & 0 deletions experimental/fasthtml/gpu_puzzles/client.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
const State = {
editor: null,
terminal: null,
module: null,
completionTippy: null,
currentCompletion: '',
isModuleReady: false
};


function initializeApp() {
initializeTerminal();
initializeEditor();
initializeModule();
setupEventListeners();
}

function initializeTerminal() {
AppState.terminal = new Terminal();
const fitAddon = new FitAddon.FitAddon();
AppState.terminal.loadAddon(fitAddon);
AppState.terminal.open(document.getElementById('output'));
fitAddon.fit();
console.log("Terminal initialized");
}


function initializeEditor(initialContent) {
AppState.editor = ace.edit("editor");
AppState.editor.setTheme("ace/theme/monokai");
AppState.editor.session.setMode("ace/mode/javascript");
AppState.editor.setOptions({
fontSize: "14px",
showPrintMargin: false,
showGutter: false,
highlightActiveLine: true,
wrap: true,
});
AppState.editor.setKeyboardHandler("ace/keyboard/vim");
AppState.editor.setValue(initialContent || '');

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

console.log("Editor initialized");
}

function initializeModule() {
createModule().then((Module) => {
AppState.module = Module;
AppState.module.print = customPrint;
AppState.module.printErr = customPrint;
AppState.isModuleReady = true;
console.log("Module initialized");
// Attempt to run the kernel with the initial content
updateEditor({ action: 'insert', lines: [''] });
}).catch(error => {
console.error("Failed to initialize module:", error);
});
}

function setupEventListeners() {
AppState.editor.session.on('change', updateEditor);
window.addEventListener('resize', () => AppState.editor.resize());

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

function customPrint(text) {
console.log(text);
if (AppState.terminal) {
AppState.terminal.writeln(text);
} else {
console.warn("Terminal not initialized");
}
}

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

if (!AppState.isModuleReady) {
console.log("Module not ready, waiting...");
return;
}
126 changes: 126 additions & 0 deletions experimental/fasthtml/gpu_puzzles/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);
}
Loading

0 comments on commit 47542f8

Please sign in to comment.