feature dump
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Tue, 5 Oct 2021 01:02:31 +0000 (20:02 -0500)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Tue, 5 Oct 2021 01:02:31 +0000 (20:02 -0500)
12 files changed:
site/js/decompiler.js
src/app/app.onyx
src/app/colors.onyx
src/app/debug_log.onyx
src/app/settings.onyx [new file with mode: 0644]
src/app/storage.onyx [new file with mode: 0644]
src/build.onyx
src/features/hex_editor/hex_viewer.onyx
src/features/text_editor/text_editor.onyx
src/features/wasm/feature.onyx
src/features/wasm/wasm.onyx
src/ui/window.onyx

index 169dbd3bce71b74b3559d9f00f1ff708263e4538..bc5169798d475a47b797eaa78f7dacc21d497f47 100644 (file)
@@ -35,5 +35,35 @@ window.ONYX_MODULES.push({
         const str = decoder.decode(data);
 
         document.getElementById("main_canvas").style.cursor = str;
+    },
+
+    local_storage_store: function(keyptr, keylen, valueptr, valuelen) {
+        const decoder = new TextDecoder();
+
+        const key = decoder.decode(new Uint8Array(window.ONYX_MEMORY.buffer, keyptr, keylen));
+        const value = decoder.decode(new Uint8Array(window.ONYX_MEMORY.buffer, valueptr, valuelen));
+
+        localStorage[key] = value;
+    },
+
+    local_storage_value_length: function(keyptr, keylen) {
+        const decoder = new TextDecoder();
+        const encoder = new TextEncoder();
+
+        const key = decoder.decode(new Uint8Array(window.ONYX_MEMORY.buffer, keyptr, keylen));
+
+        return encoder.encode(localStorage[key]).length;
+    },
+
+    local_storage_load: function(keyptr, keylen, bufferptr, bufferlen) {
+        const decoder = new TextDecoder();
+        const encoder = new TextEncoder();
+
+        const key = decoder.decode(new Uint8Array(window.ONYX_MEMORY.buffer, keyptr, keylen));
+
+        const value_data = encoder.encode(localStorage[key]);
+        
+        let WASM_U8 = new Uint8Array(window.ONYX_MEMORY.buffer);
+        WASM_U8.set(value_data, bufferptr);
     }
 });
index 41fd065e54de43a0454ccbdb4e72cac8b5efd357..d1acebb6d5a60eb37fb19862c9f8eac60ee5fafe 100644 (file)
@@ -1,7 +1,5 @@
 package app
 
-use package core
-
 #private_file {
     events :: package js_events
     gl     :: package gl
@@ -10,10 +8,12 @@ use package core
     config :: package config
     wasm   :: package wasm_utils
     debug  :: package debug
-}
 
-use package debug { init as debug_init, debug_log, draw_debug_log }
-use package core.intrinsics.onyx { __initialize }
+    use package core
+
+    use package debug { init as debug_init, debug_log, draw_debug_log }
+    use package core.intrinsics.onyx { __initialize }
+}
 
 @Relocate search_buffer: string.String_Buffer;
 on_file_load_callbacks : Map(u32, (file_event: ^events.Event) -> void);
@@ -30,7 +30,7 @@ Tool :: struct {
 state : Application_State;
 
 Application_State :: struct {
-    colorscheme: Colorscheme;
+    settings := Application_Settings.{};
 
     has_active_file := false;
     file := Active_File.{};
@@ -64,7 +64,7 @@ init :: () {
     __initialize(^state);
     window_buffer := memory.make_slice(Application_Window, MAXIMUM_WINDOWS);
     state.windows_store = alloc.pool.make(window_buffer);
-    map.init(^state.windows_map, hash_count=16);
+    map.init(^state.windows_map);
     array.init(^state.windows_sorted);
     state.window_switcher_state->init();
 
@@ -77,17 +77,18 @@ init :: () {
     array.init(^registered_tools);
     map.init(^on_file_load_callbacks);
 
-    colorscheme_switch(.Dark);
-
     load_background_tile_texture();
     load_fonts();
 
+    settings_load(^state.settings);
+    colorscheme_switch(state.settings.colorscheme);
+
     search_buffer = string.buffer_make(memory.make_slice(u8, 256));
 
     gl.enable(gl.BLEND);
     gl.blendFuncSeparate(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE_MINUS_SRC_ALPHA);
 
-    registered_tools << Tool.{
+    registered_tools << .{
         id   = "load_file_info",
         name = "File Info",
         open = () {
@@ -235,6 +236,7 @@ handle_event :: (event: ^events.Event) {
 
                 if event.keyboard->get_name() == "F7" {
                     debug.debug_log_toggle();
+                    settings_save(^state.settings);
                     break;
                 }
 
@@ -282,6 +284,8 @@ handle_event :: (event: ^events.Event) {
             state.has_active_file = true;
             state.file.name = name;
             state.file.data = data;
+
+            invoke_feature_function("file_loaded");
         }
     }
 }
@@ -311,22 +315,12 @@ draw :: () {
     ui.workspace_start(main_area, state=^state.workspace_state);
     draw_background_lines(~~window_width, ~~window_height, line_color=config.Colors.background);
 
-    // Used for detecting when a window is completely off-screen and shouldn't be rendered.
-    transformed_window_rect := window_rectangle;
-    {
-        trans := gfx.global_renderer->get_transform();
-        transformed_window_rect.x0 -= trans.translation.x / trans.scale.x;
-        transformed_window_rect.y0 -= trans.translation.y / trans.scale.y;
-        transformed_window_rect.x1 = transformed_window_rect.x0 + (~~window_width / trans.scale.x);
-        transformed_window_rect.y1 = transformed_window_rect.y0 + (~~window_height / trans.scale.y);
-    }
-
     i := 0;
     new_top: ^Application_Window = null;
     for window: state.windows_sorted {
         defer i += 1;
 
-        if !(window.window_state->get_rectangle() |> ui.Rectangle.intersects(transformed_window_rect)) do continue;
+        if !(window.window_state->get_transformed_rectangle() |> ui.Rectangle.intersects(window_rectangle)) do continue;
 
         if ui.window_start(^window.window_state, increment=hash.to_u32(window.id)) {
             new_top = window;
index a0cb148de10970e933d5710c848947e1d3693016..64c57bb4f369b7a6cdeafa1fb94c2d5ad68b879e 100644 (file)
@@ -22,12 +22,10 @@ Colorscheme :: enum {
 }
 
 colorscheme_switch :: (new_scheme: Colorscheme) {
-    if state.colorscheme == new_scheme do return;
-
-    state.colorscheme = new_scheme;
+    state.settings.colorscheme = new_scheme;
 
     colors_scheme_file: str;
-    switch state.colorscheme {
+    switch state.settings.colorscheme {
         case .Dark do colors_scheme_file = config.dark_color_scheme_file;
         case .Light do colors_scheme_file = config.light_color_scheme_file;
         case #default do assert(false, "Bad colorscheme setting.");
@@ -80,7 +78,7 @@ load_colors :: (event: ^events.Event) {
         };
     }
 
-    debug_log(.Info, "Successfully loaded colorscheme '{}'.", state.colorscheme);
+    debug_log(.Info, "Successfully loaded colorscheme '{}'.", state.settings.colorscheme);
 }
 
 update_ui_colors :: () {
index a1b5ebc73b6b0036473fb29e9aefcbc38b50a422..fcaba79a5f1ec248cd94fc36284a1eeed058a89a 100644 (file)
@@ -121,20 +121,6 @@ draw_debug_log :: (window_rectangle: ui.Rectangle, site := #callsite) {
     if ui.button(clear_button_rect, "Clear log") {
         debug_log_clear();
     }
-
-    app :: package app
-    colorscheme := app.state.colorscheme;
-
-    clear_button_rect.x0 += 220;
-    clear_button_rect.x1 += 220;
-    switched := ui.radio(clear_button_rect, ^colorscheme, .Dark, "Dark mode");
-    clear_button_rect.x0 += 200;
-    clear_button_rect.x1 += 200;
-    switched = switched || ui.radio(clear_button_rect, ^colorscheme, .Light, "Light mode");
-
-    if switched {
-        app.colorscheme_switch(colorscheme);
-    }
 }
 
 #private_file log_buffer : struct {
diff --git a/src/app/settings.onyx b/src/app/settings.onyx
new file mode 100644 (file)
index 0000000..b9b9d34
--- /dev/null
@@ -0,0 +1,45 @@
+package app
+
+#private_file {
+    json :: package json
+    __initialize :: (package core.intrinsics.onyx).__initialize
+    init :: (package core.intrinsics.onyx).init
+
+    use package core
+
+    Settings_Key :: "debugger_settings"
+}
+
+Application_Settings :: struct {
+    colorscheme := Colorscheme.Undefined;
+}
+
+settings_save :: (settings: ^Application_Settings) {
+    use type_info;
+
+    root := init(json.Value_Object);
+    array.init(^root.object_, allocator=context.allocator);
+    defer json.free(^root, context.allocator);
+
+    json.set(^root, "colorscheme", enum_name(settings.colorscheme), true, true);
+
+    store_value, _ := json.encode_string(^root);
+    defer string.free(store_value);
+
+    storage.store(Settings_Key, store_value);
+}
+
+settings_load :: (settings: ^Application_Settings) {
+    use type_info;
+
+    value := storage.load(Settings_Key);
+    if value.data == null do value = "{}";
+    defer if value != "{}" do string.free(value);
+
+    root := json.decode(value);
+    defer json.free(root);
+    
+    colorscheme := enum_value(Colorscheme, root.root["colorscheme"]->as_str());
+    if colorscheme != .Undefined do settings.colorscheme = colorscheme;
+    else                         do settings.colorscheme = .Dark;
+}
diff --git a/src/app/storage.onyx b/src/app/storage.onyx
new file mode 100644 (file)
index 0000000..baa670c
--- /dev/null
@@ -0,0 +1,27 @@
+// Simple local-storage wrapper
+
+package app.storage
+
+#private_file {
+    memory :: package core.memory
+}
+
+store :: (key: str, value: [] u8) {
+    __local_storage_store(key, value);
+}
+
+load :: (key: str, allocator := context.allocator) -> str {
+    buffer_length := __local_storage_value_length(key);
+
+    buffer := memory.make_slice(u8, buffer_length, allocator=allocator);
+    __local_storage_load(key, buffer);
+
+    return buffer;
+}
+
+#private_file {
+    __local_storage_store        :: (key: str, value: str) -> void  #foreign "decompiler" "local_storage_store" ---
+    __local_storage_value_length :: (key: str) -> i32               #foreign "decompiler" "local_storage_value_length" ---
+    __local_storage_load         :: (key: str, buffer: str) -> void #foreign "decompiler" "local_storage_load" ---
+}
+
index 96d302be9005643a55bb3e0e8c6c1d03af969e46..dbe2d2d0a6cccbdbddb5643d9885e14450aba547 100644 (file)
@@ -21,6 +21,8 @@
     #load "src/app/window_switcher"
     #load "src/app/window_management"
     #load "src/app/colors"
+    #load "src/app/storage"
+    #load "src/app/settings"
 
     #load "src/features/load_features"
 
index 62ced36a025c383da3aa1b106fb66b4f77784f86..b8aacb8656e7991570ec4081addc2d94c306af8d 100644 (file)
@@ -156,7 +156,7 @@ open_window :: () {
 setup :: () {
     debug_log(.Debug, "Initializing hex viewer...", 0);
 
-    app.registered_tools << app.Tool.{
+    app.registered_tools << .{
         id   = window_id,
         name = window_name,
         open = open_window,
index 5c3e48da74182282760e8188facad1e734426076..31e1ae68ccb8f23daf25d2a5c3cc11b76a23affa 100644 (file)
@@ -31,9 +31,9 @@ open_text_editor :: () {
 setup :: () {
     debug_log(.Debug, "Initializing text editor...", 0);
 
-    array.push(^app.registered_tools, .{
+    app.registered_tools << .{
         id   = window_id,
         name = window_name,
         open = open_text_editor,
-    });
+    };
 }
index cf47133c82b043a8662a309267a8972edd3ed328..cd52edff0894369b5260adac2d0ebe683426c606 100644 (file)
@@ -4,4 +4,5 @@ package feature.wasm
 
 Feature_Wasm_Loader :: struct {
     setup := setup;
-}
\ No newline at end of file
+    file_loaded := file_loaded;
+}
index 5f1657a1bbe003f50b9175d02bd547f2213bf3d7..fbb79cdcc5b2df3cf9f313dda70d3ae425130d34 100644 (file)
 package feature.wasm
 
 #private_file {
-    app    :: package app
-    ui     :: package ui
-    config :: package config
+    app        :: package app
+    ui         :: package ui
+    config     :: package config
+
+    wasm_utils   :: package wasm_utils
+    WasmBinary   :: wasm_utils.WasmBinary
+    WasmSections :: wasm_utils.WasmSections
 
     use package core
     use package debug { debug_log }
-
-    use package wasm_utils
 }
 
 #private {
     wasm_state    : WasmBinary;
     wasm_sections : WasmSections;
+
+    wasm_analyzed := false;
 }
 
 setup :: () {
     debug_log(.Info, "Wasm Loader Loaded from {}", #file);
+
+    app.registered_tools << .{
+        id   = "wasm_info",
+        name = "WASM info",
+        open = () {
+            app.open_window("wasm_info", "WASM info", .{ 0, 0 }, info_window_draw, .{ 1300, 650 });
+            app.move_window_to_top("wasm_info");
+            app.focus_window("wasm_info");
+        }
+    };
+}
+
+if_visible :: macro (r: ui.Rectangle, w: ui.Rectangle, draw: Code) {
+    if ui.Rectangle.intersects(w, r) {
+        #insert draw;
+    }
+}
+
+info_window_draw :: (_, win) => {
+    if !wasm_analyzed do return;
+
+    rect := ui.Rectangle.{ 0, 0, win.window_state.size.x, win.window_state.size.y }; 
+
+    #persist scrollable_region := ui.Scrollable_Region_State.{};
+    ui.scrollable_region_start(rect, state=^scrollable_region);
+    defer ui.scrollable_region_stop();
+
+    text_theme := ui.default_text_theme;
+    text_theme.font = config.Fonts.FiraCode.index;
+    
+    win_rect := rect;
+    v := 0x7F7FFFFF;
+    rect.y1 = *cast(^f32)^v;
+    rect.x1 = *cast(^f32)^v;
+    text_rect : ui.Rectangle;
+    msg_buffer: [512] u8;
+
+    {
+        text_rect, rect = ui.Flow.split_horizontal(rect, top_height=40);
+        if_visible(text_rect, win_rect,
+            #(ui.draw_text(text_rect, conv.str_format(msg_buffer, "Imports: {}", wasm_sections.import_section.count), theme=^text_theme)));
+    }
+
+    for ^import: wasm_sections.import_section {
+        text_rect, rect = ui.Flow.split_horizontal(rect, top_height=32);
+        if_visible(text_rect, win_rect,
+            #(ui.draw_text(text_rect, conv.str_format(msg_buffer, "{*}", import), theme=^text_theme)));
+    }
+
+    {
+        text_rect, rect = ui.Flow.split_horizontal(rect, top_height=40);
+        if_visible(text_rect, win_rect,
+            #(ui.draw_text(text_rect, conv.str_format(msg_buffer, "Exports: {}", wasm_sections.export_section.count), theme=^text_theme)));
+    }
+
+    {
+        text_rect, rect = ui.Flow.split_horizontal(rect, top_height=40);
+        if_visible(text_rect, win_rect,
+            #(ui.draw_text(text_rect, conv.str_format(msg_buffer, "Functions: {}", wasm_sections.code_section.count), theme=^text_theme)));
+    }
+
+    for ^code: wasm_sections.code_section {
+        text_rect, rect = ui.Flow.split_horizontal(rect, top_height=32);
+        if_visible(text_rect, win_rect,
+            #(ui.draw_text(text_rect, conv.str_format(msg_buffer, "{*}", code), theme=^text_theme)));
+    }
+}
+
+file_loaded :: () {
+    if wasm_analyzed {
+        wasm_utils.free(^wasm_state);
+        wasm_utils.free_sections(^wasm_sections);
+    }
+
+    wasm_analyzed = false;
+
+    file_data := app.state.file.data;
+    debug_log(.Info, "Wasm feature noticed file dropped with size {}", file_data.count);
+
+    if !string.starts_with(file_data, u8.[ 0, #char "a", #char "s", #char "m" ]) do return;
+
+    debug_log(.Info, "THIS IS PROBABLY A WASM BINARY. ANALYZING!!!");
+
+    wasm_state = wasm_utils.load(file_data, context.allocator);
+    wasm_sections = wasm_utils.parse_sections(^wasm_state, context.allocator);
+
+    debug_log(.Info, "There are {} functions in this binary.", wasm_sections.code_section.count);
+
+    for ^import: wasm_sections.import_section {
+        debug_log(.Info, "Import: {*}", import);
+    }
+
+    wasm_analyzed = true;
 }
index 2dc486db2af85dd8658de84093a5cc034d008fe8..5b11afe11f6188a7ca75f5207e3bf579b9bb6c11 100644 (file)
@@ -2,6 +2,7 @@ package ui
 
 #private_file {
     map :: package core.map
+    // gfx :: package immediate_mode
 }
 
 // This will be stored by the end user's library.
@@ -17,7 +18,7 @@ Window_State :: struct {
     border_color := gfx.Color4.{ 1, 0, 0 };
     background_color := gfx.Color4.{ 0.2, 0.2, 0.2 };
 
-    bar_height := 34.0f;
+    bar_height := 28.0f;
 
     draggable := true;
     resizable := true;
@@ -33,6 +34,36 @@ Window_State :: struct {
         return .{ position.x - bw, position.y - bw - bar_height,
                   position.x + size.x + bw, position.y + size.y + bw };
     }
+
+    get_transformed_rectangle :: (use w: ^Window_State) -> Rectangle {
+        bw := border_width;
+        if dragging do bw *= 5;
+
+        r := Rectangle.{
+                  position.x - bw, position.y - bw - bar_height,
+                  position.x + size.x + bw, position.y + size.y + bw };
+
+        
+        trans := gfx.global_renderer->get_transform();
+        r.x0 *= trans.scale.x;
+        r.y0 *= trans.scale.y;
+        r.x0 += trans.translation.x;
+        r.y0 += trans.translation.y;
+        r.x1 *= trans.scale.x;
+        r.y1 *= trans.scale.y;
+        r.x1 += trans.translation.x;
+        r.y1 += trans.translation.y;
+
+        return r;
+    }
+
+    get_origin_rectangle :: (use w: ^Window_State) -> Rectangle {
+        bw := border_width;
+        if dragging do bw *= 5;
+
+        return .{ bw, bw - bar_height,
+                  size.x + bw, size.y + bw };
+    }
 }
 
 window_start :: (use state: ^Window_State, site := #callsite, increment := 0) -> bool {
@@ -99,11 +130,13 @@ window_start :: (use state: ^Window_State, site := #callsite, increment := 0) ->
     draw_rect(x, y, w, h, color=state.background_color);
 
     title_theme := default_text_theme;
-    title_theme.font_size = 1.0f;
+    title_theme.font_size = bar_height / 32.0f;
     title_theme.text_color = .{ 1, 1, 1 }; @ThemeConfiguration
     draw_text(.{ x, y - bar_height, x + w, y }, state.title, theme=^title_theme);
 
-    if button(.{ x + w - 48, y - bar_height - border_width, x + w + border_width, y }, "X", increment=increment + hash) {
+    close_theme := default_button_theme;
+    close_theme.border_width = 0;
+    if button(.{ x + w - 48, y - bar_height - border_width, x + w + border_width, y }, "X", theme=^close_theme, increment=increment + hash) {
         state.should_close = true;
     }