diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 0000000..5e05819 --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,15 @@ +{ + "image": "mcr.microsoft.com/devcontainers/cpp:ubuntu", + "customizations": { + "vscode": { + "extensions": [ + "danielgavin.ols" + ] + } + }, + "features": { + "./odin-feature": { + "version": "latest" + } + } +} \ No newline at end of file diff --git a/.devcontainer/odin-feature/devcontainer-feature.json b/.devcontainer/odin-feature/devcontainer-feature.json new file mode 100644 index 0000000..c87344c --- /dev/null +++ b/.devcontainer/odin-feature/devcontainer-feature.json @@ -0,0 +1,11 @@ +{ + "name": "Odin Compiler", + "id": "odin", + "version": "1.0.0", + "installsAfter": [ + "ghcr.io/devcontainers/features/common-utils" + ], + "containerEnv": { + "ODIN_ROOT": "/usr/local/share/odin" + } +} \ No newline at end of file diff --git a/.devcontainer/odin-feature/install.sh b/.devcontainer/odin-feature/install.sh new file mode 100644 index 0000000..4697550 --- /dev/null +++ b/.devcontainer/odin-feature/install.sh @@ -0,0 +1,19 @@ +#!/bin/sh +set -e + +git clone --branch "dev-2024-12" "https://github.com/odin-lang/Odin.git" + +cd Odin + +mkdir -p /usr/local/share/odin +cp -r ./base /usr/local/share/odin/ +cp -r ./core /usr/local/share/odin/ +cp -r ./vendor /usr/local/share/odin/ + +make release + +cp ./odin /usr/local/bin/ + +echo "Installing SDL2 & SDL2_ttf" +apt update +apt --yes --force-yes install libsdl2-dev libsdl2-ttf-dev diff --git a/Makefile b/Makefile index 5b58e46..9fcfd75 100644 --- a/Makefile +++ b/Makefile @@ -1,13 +1,5 @@ all: editor -editor: src/*.odin # grep odin_highlighter - # odin build src/ -out:bin/editor.o -build-mode:obj -debug -lld - # dsymutil bin/editor.o -o bin/editor.dSYM - ../Odin/odin build src/ -out:bin/editor -debug -linker:lld -extra-linker-flags:"-L./" - -odin_highlighter: plugins/highlighter/src/*.odin - ../Odin/odin build plugins/highlighter/src/ -build-mode:dll -no-entry-point -out:bin/highlighter - -grep: plugins/grep/src/*.rs - nightly-cargo b --manifest-path=plugins/grep/Cargo.toml - cp plugins/grep/target/debug/libgrep_plugin.dylib bin/ +editor: src/**/*.odin + mkdir -p bin + odin build src/ -out:bin/editor -debug \ No newline at end of file diff --git a/liblua5.4.a b/liblua5.4.a deleted file mode 100755 index b9f953e..0000000 Binary files a/liblua5.4.a and /dev/null differ diff --git a/plugin-rs-bindings/Cargo.lock b/plugin-rs-bindings/Cargo.lock deleted file mode 100644 index 730d5d6..0000000 --- a/plugin-rs-bindings/Cargo.lock +++ /dev/null @@ -1,7 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "plugin_rs_bindings" -version = "0.1.0" diff --git a/plugin-rs-bindings/Cargo.toml b/plugin-rs-bindings/Cargo.toml deleted file mode 100644 index 8030a20..0000000 --- a/plugin-rs-bindings/Cargo.toml +++ /dev/null @@ -1,8 +0,0 @@ -[package] -name = "plugin_rs_bindings" -version = "0.1.0" -edition = "2021" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] diff --git a/plugin-rs-bindings/src/lib.rs b/plugin-rs-bindings/src/lib.rs deleted file mode 100644 index e875a36..0000000 --- a/plugin-rs-bindings/src/lib.rs +++ /dev/null @@ -1,781 +0,0 @@ -use std::{ - borrow::Cow, - ffi::{c_char, c_void, CStr, CString}, - fmt::write, - path::Path, -}; - -#[macro_export] -macro_rules! Closure { - (($($arg: ident: $type: ty),+) => $body: expr) => { - { - extern "C" fn f($($arg: $type),+) { - $body - } - f - } - }; - (($($arg: ident: $type: ty),+) -> $return_type: ty => $body: expr) => { - { - extern "C" fn f($($arg: $type),+) -> $return_type { - $body - } - f - } - }; -} - -#[repr(C)] -#[derive(Clone, Copy)] -pub struct InputMap { - internal: *const std::ffi::c_void, -} - -#[repr(C)] -#[derive(Debug)] -pub struct BufferIndex { - pub slice_index: isize, - pub content_index: isize, -} - -#[repr(C)] -#[derive(Debug)] -pub struct Cursor { - pub col: isize, - pub line: isize, - pub index: BufferIndex, -} - -#[repr(C)] -#[derive(Debug)] -struct InternalBufferIter { - cursor: Cursor, - buffer: *const c_void, - hit_end: bool, -} - -#[repr(C)] -pub struct IterateResult { - pub char: u8, - pub should_continue: bool, -} - -#[repr(C)] -#[derive(Debug)] -pub struct BufferInput { - bytes: *const u8, - length: isize, -} - -impl BufferInput { - pub fn try_as_str(&self) -> Option> { - if self.bytes.is_null() { - None - } else { - let slice = unsafe { std::slice::from_raw_parts(self.bytes, self.length as usize) }; - - Some(String::from_utf8_lossy(slice)) - } - } -} - -#[repr(C)] -#[derive(Debug)] -pub struct BufferInfo { - pub buffer: Buffer, - pub file_path: *const i8, - pub input: BufferInput, - - pub cursor: Cursor, - - pub glyph_buffer_width: isize, - pub glyph_buffer_height: isize, - pub top_line: isize, -} - -#[repr(C)] -#[derive(Debug, Clone, Copy, PartialEq)] -pub struct Buffer { - internal: *const c_void, -} - -impl Buffer { - pub fn null() -> Buffer { - Buffer { - internal: std::ptr::null(), - } - } -} - -#[repr(C)] -pub struct BufferVTable { - pub get_num_buffers: extern "C" fn() -> isize, - get_buffer_info: extern "C" fn(buffer: Buffer) -> BufferInfo, - pub get_buffer_info_from_index: extern "C" fn(buffer_index: isize) -> BufferInfo, - pub color_char_at: extern "C" fn( - buffer: *const c_void, - start_cursor: Cursor, - end_cursor: Cursor, - palette_index: i32, - ), - pub set_current_buffer: extern "C" fn(buffer_index: isize), - - open_buffer: extern "C" fn(path: *const u8, line: isize, col: isize), - open_virtual_buffer: extern "C" fn() -> *const c_void, - free_virtual_buffer: extern "C" fn(buffer: Buffer), -} - -impl BufferVTable { - pub fn get_buffer_info(&self, buffer: Buffer) -> Option { - if buffer.internal.is_null() { - None - } else { - Some((self.get_buffer_info)(buffer)) - } - } - pub fn open_buffer(&self, path: impl AsRef, line: i32, col: i32) { - let Ok(c_str) = CString::new(path.as_ref().as_os_str().as_encoded_bytes()) else { - eprintln!("grep plugin failed to open buffer"); - return; - }; - (self.open_buffer)(c_str.as_ptr() as *const u8, line as isize, col as isize); - } - pub fn open_virtual_buffer(&self) -> Buffer { - Buffer { - internal: (self.open_virtual_buffer)(), - } - } - pub fn free_virtual_buffer(&self, buffer: Buffer) { - (self.free_virtual_buffer)(buffer); - } -} - -#[repr(C)] -pub struct IteratorVTable { - get_current_buffer_iterator: extern "C" fn() -> InternalBufferIter, - get_buffer_iterator: extern "C" fn(buffer: *const c_void) -> InternalBufferIter, - get_char_at_iter: extern "C" fn(it: *const InternalBufferIter) -> u8, - get_buffer_list_iter: extern "C" fn(prev_buffer: *const isize) -> isize, - - iterate_buffer: extern "C" fn(it: *mut InternalBufferIter) -> IterateResult, - iterate_buffer_reverse: extern "C" fn(it: *mut InternalBufferIter) -> IterateResult, - iterate_buffer_until: extern "C" fn(it: *mut InternalBufferIter, until_proc: *const c_void), - iterate_buffer_until_reverse: - extern "C" fn(it: *mut InternalBufferIter, until_proc: *const c_void), - iterate_buffer_peek: extern "C" fn(it: *mut InternalBufferIter) -> IterateResult, - - pub until_line_break: *const c_void, - pub until_single_quote: *const c_void, - pub until_double_quote: *const c_void, - pub until_end_of_word: *const c_void, -} - -#[repr(C)] -pub struct UiInteraction { - pub hovering: bool, - pub clicked: bool, -} - -#[repr(C)] -struct InternalUiSemanticSize { - kind: isize, - value: isize, -} - -#[repr(isize)] -pub enum UiAxis { - Horizontal = 0, - Vertical, -} - -pub enum UiSemanticSize { - FitText, - Exact(isize), - ChildrenSum, - Fill, - PercentOfParent(isize), -} - -impl From for InternalUiSemanticSize { - fn from(value: UiSemanticSize) -> Self { - let (kind, value) = match value { - UiSemanticSize::FitText => (0, 0), - UiSemanticSize::Exact(value) => (1, value), - UiSemanticSize::ChildrenSum => (2, 0), - UiSemanticSize::Fill => (3, 0), - UiSemanticSize::PercentOfParent(value) => (4, value), - }; - - Self { kind, value } - } -} - -#[repr(C)] -#[derive(Clone, Copy)] -pub struct UiContext(*const c_void); - -#[repr(C)] -#[derive(Clone, Copy)] -pub struct UiBox(*const c_void); - -type UiPushParentProc = extern "C" fn(ui_context: UiContext, ui_box: UiBox); -type UiPopParentProc = extern "C" fn(ui_context: UiContext); -type UiFloatingProc = - extern "C" fn(ui_context: UiContext, label: *const i8, pos: [isize; 2]) -> UiBox; -type UiRectProc = extern "C" fn( - ui_context: UiContext, - label: *const i8, - border: bool, - border: bool, - axis: UiAxis, - size: [InternalUiSemanticSize; 2], -) -> UiBox; -type UiSimpleProc = extern "C" fn(ui_context: UiContext, label: *const i8) -> UiInteraction; -type UiBufferProc = extern "C" fn(ui_context: UiContext, buffer: Buffer, show_line_numbers: bool); - -#[repr(C)] -pub struct UiVTable { - ui_context: UiContext, - - push_parent: UiPushParentProc, - pop_parent: UiPopParentProc, - - spacer: UiSimpleProc, - floating: UiFloatingProc, - rect: UiRectProc, - - button: UiSimpleProc, - label: UiSimpleProc, - - buffer: UiBufferProc, - buffer_from_index: UiBufferProc, -} - -impl UiVTable { - pub fn push_parent(&self, ui_box: UiBox) { - (self.push_parent)(self.ui_context, ui_box); - } - pub fn pop_parent(&self) { - (self.pop_parent)(self.ui_context); - } - - pub fn spacer(&self, label: &CStr) -> UiInteraction { - (self.spacer)(self.ui_context, label.as_ptr()) - } - - pub fn push_rect( - &self, - label: &CStr, - show_background: bool, - show_border: bool, - axis: UiAxis, - horizontal_size: UiSemanticSize, - vertical_size: UiSemanticSize, - inner: impl FnOnce(&UiVTable), - ) { - let rect = (self.rect)( - self.ui_context, - label.as_ptr(), - show_background, - show_border, - axis, - [horizontal_size.into(), vertical_size.into()], - ); - self.push_parent(rect); - - inner(self); - - self.pop_parent(); - } - - pub fn push_floating(&self, label: &CStr, x: isize, y: isize, inner: impl FnOnce(&UiVTable)) { - let floating = (self.floating)(self.ui_context, label.as_ptr(), [x, y]); - self.push_parent(floating); - - inner(self); - - self.pop_parent(); - } - - pub fn label(&self, label: &CStr) -> UiInteraction { - (self.label)(self.ui_context, label.as_ptr()) - } - pub fn button(&self, label: &CStr) -> UiInteraction { - (self.button)(self.ui_context, label.as_ptr()) - } - - pub fn buffer(&self, buffer: Buffer, show_line_numbers: bool) { - (self.buffer)(self.ui_context, buffer, show_line_numbers) - } -} - -type OnColorBufferProc = extern "C" fn(plugin: Plugin, buffer: *const c_void); -type OnHookProc = extern "C" fn(plugin: Plugin, buffer: Buffer); -type InputGroupProc = extern "C" fn(plugin: Plugin, input_map: InputMap); -type InputActionProc = extern "C" fn(plugin: Plugin); -type WindowDrawProc = extern "C" fn(plugin: Plugin, window: *const c_void); -type WindowFreeProc = extern "C" fn(plugin: Plugin, window: *const c_void); -type WindowGetBufferProc = extern "C" fn(plugin: Plugin, window: *const c_void) -> Buffer; -#[repr(C)] -pub struct Plugin { - state: *const c_void, - - pub iter_table: IteratorVTable, - pub buffer_table: BufferVTable, - pub ui_table: UiVTable, - - pub register_hook: extern "C" fn(hook: Hook, on_hook: OnHookProc), - pub register_highlighter: - extern "C" fn(extension: *const c_char, on_color_buffer: OnColorBufferProc), - - pub register_input_group: - extern "C" fn(input_map: InputMap, key: Key, register_group: InputGroupProc), - pub register_input: extern "C" fn( - input_map: InputMap, - key: Key, - input_action: InputActionProc, - description: *const u8, - ), - - pub create_window: extern "C" fn( - user_data: *const c_void, - register_group: InputGroupProc, - draw_proc: WindowDrawProc, - free_window_proc: WindowFreeProc, - get_buffer_proc: *const (), - ) -> *const c_void, - get_window: extern "C" fn() -> *const c_void, - - pub request_window_close: extern "C" fn(), - pub get_screen_width: extern "C" fn() -> isize, - pub get_screen_height: extern "C" fn() -> isize, - pub get_font_width: extern "C" fn() -> isize, - pub get_font_height: extern "C" fn() -> isize, - get_current_directory: extern "C" fn() -> *const c_char, - pub enter_insert_mode: extern "C" fn(), - - pub draw_rect: extern "C" fn(x: i32, y: i32, width: i32, height: i32, color: PaletteColor), - pub draw_text: extern "C" fn(text: *const c_char, x: f32, y: f32, color: PaletteColor), - pub draw_buffer_from_index: extern "C" fn( - buffer_index: isize, - x: isize, - y: isize, - glyph_buffer_width: isize, - glyph_buffer_height: isize, - show_line_numbers: bool, - ), - pub draw_buffer: extern "C" fn( - buffer: Buffer, - x: isize, - y: isize, - glyph_buffer_width: isize, - glyph_buffer_height: isize, - show_line_numbers: bool, - ), -} - -pub struct BufferIter { - iter: InternalBufferIter, - iter_table: IteratorVTable, -} - -impl BufferIter { - pub fn new(plugin: Plugin, buffer: Buffer) -> Self { - let buffer_info = (plugin.buffer_table.get_buffer_info)(buffer); - - Self { - iter: InternalBufferIter { - cursor: buffer_info.cursor, - buffer: buffer.internal, - hit_end: false, - }, - iter_table: plugin.iter_table, - } - } -} - -impl Iterator for BufferIter { - type Item = char; - - fn next(&mut self) -> Option { - let iter_ptr = (&mut self.iter) as *mut InternalBufferIter; - - let result = (self.iter_table.iterate_buffer)(iter_ptr); - if result.should_continue { - Some(result.char as char) - } else { - None - } - } -} - -pub struct BufferListIter { - index: isize, - next_fn: extern "C" fn(prev_buffer: *const isize) -> isize, -} - -impl From<&Plugin> for BufferListIter { - fn from(value: &Plugin) -> Self { - BufferListIter { - index: 0, - next_fn: value.iter_table.get_buffer_list_iter, - } - } -} - -impl Iterator for BufferListIter { - type Item = isize; - - fn next(&mut self) -> Option { - if self.index == -1 { - return None; - } - - Some((self.next_fn)(&mut self.index)) - } -} - -impl Plugin { - pub fn get_current_directory(&self) -> Cow { - unsafe { - let c_str = CStr::from_ptr((self.get_current_directory)()); - - c_str.to_string_lossy() - } - } - - /// # Safety - /// If `W` is not the same type as given in `self.create_window`, it will result in undefined - /// behavior. `W` can also be a different type if another plugin has created a window. - pub unsafe fn get_window<'a, W>(&self) -> Option<&'a mut W> { - let window_ptr = (self.get_window)() as *mut W; - - if window_ptr.is_null() { - None - } else { - let window = Box::from_raw(window_ptr); - Some(Box::leak(window)) - } - } - - pub fn create_window( - &self, - window: W, - register_group: InputGroupProc, - draw_proc: WindowDrawProc, - free_window_proc: WindowFreeProc, - get_buffer_proc: Option, - ) { - let boxed = Box::new(window); - (self.create_window)( - Box::into_raw(boxed) as *const std::ffi::c_void, - register_group, - draw_proc, - free_window_proc, - if let Some(proc) = get_buffer_proc { - proc as *const () - } else { - std::ptr::null() - }, - ); - } - pub fn register_hook(&self, hook: Hook, on_hook: OnHookProc) { - (self.register_hook)(hook, on_hook) - } - pub fn register_input_group( - &self, - input_map: Option, - key: Key, - register_group: InputGroupProc, - ) { - let input_map = match input_map { - Some(input_map) => input_map, - None => InputMap { - internal: std::ptr::null(), - }, - }; - - (self.register_input_group)(input_map, key, register_group); - } -} - -#[repr(i32)] -pub enum Hook { - BufferInput, -} - -#[repr(i32)] -pub enum Key { - UNKNOWN = 0, - Enter = 13, - ESCAPE = 27, - BACKSPACE = 8, - TAB = 9, - Space = 32, - EXCLAIM = 33, - QUOTEDBL = 34, - HASH = 35, - PERCENT = 37, - DOLLAR = 36, - AMPERSAND = 38, - QUOTE = 39, - LEFTPAREN = 40, - RIGHTPAREN = 41, - ASTERISK = 42, - PLUS = 43, - COMMA = 44, - MINUS = 45, - PERIOD = 46, - SLASH = 47, - NUM0 = 48, - NUM1 = 49, - NUM2 = 50, - NUM3 = 51, - NUM4 = 52, - NUM5 = 53, - NUM6 = 54, - NUM7 = 55, - NUM8 = 56, - NUM9 = 57, - COLON = 58, - SEMICOLON = 59, - LESS = 60, - EQUAL = 61, - GREATER = 62, - QUESTION = 63, - AT = 64, - LEFTBRACKET = 91, - BACKSLASH = 92, - RIGHTBRACKET = 93, - CARET = 94, - UNDERSCORE = 95, - BACKQUOTE = 96, - A = 97, - B = 98, - C = 99, - D = 100, - E = 101, - F = 102, - G = 103, - H = 104, - I = 105, - J = 106, - K = 107, - L = 108, - M = 109, - N = 110, - O = 111, - P = 112, - Q = 113, - R = 114, - S = 115, - T = 116, - U = 117, - V = 118, - W = 119, - X = 120, - Y = 121, - Z = 122, - CAPSLOCK = 1073741881, - F1 = 1073741882, - F2 = 1073741883, - F3 = 1073741884, - F4 = 1073741885, - F5 = 1073741886, - F6 = 1073741887, - F7 = 1073741888, - F8 = 1073741889, - F9 = 1073741890, - F10 = 1073741891, - F11 = 1073741892, - F12 = 1073741893, - PRINTSCREEN = 1073741894, - SCROLLLOCK = 1073741895, - PAUSE = 1073741896, - INSERT = 1073741897, - HOME = 1073741898, - PAGEUP = 1073741899, - DELETE = 127, - END = 1073741901, - PAGEDOWN = 1073741902, - RIGHT = 1073741903, - LEFT = 1073741904, - DOWN = 1073741905, - UP = 1073741906, - NUMLOCKCLEAR = 1073741907, - KpDivide = 1073741908, - KpMultiply = 1073741909, - KpMinus = 1073741910, - KpPlus = 1073741911, - KpEnter = 1073741912, - Kp1 = 1073741913, - Kp2 = 1073741914, - Kp3 = 1073741915, - Kp4 = 1073741916, - Kp5 = 1073741917, - Kp6 = 1073741918, - Kp7 = 1073741919, - Kp8 = 1073741920, - Kp9 = 1073741921, - Kp0 = 1073741922, - KpPeriod = 1073741923, - APPLICATION = 1073741925, - POWER = 1073741926, - KpEquals = 1073741927, - F13 = 1073741928, - F14 = 1073741929, - F15 = 1073741930, - F16 = 1073741931, - F17 = 1073741932, - F18 = 1073741933, - F19 = 1073741934, - F20 = 1073741935, - F21 = 1073741936, - F22 = 1073741937, - F23 = 1073741938, - F24 = 1073741939, - EXECUTE = 1073741940, - HELP = 1073741941, - MENU = 1073741942, - SELECT = 1073741943, - STOP = 1073741944, - AGAIN = 1073741945, - UNDO = 1073741946, - CUT = 1073741947, - COPY = 1073741948, - PASTE = 1073741949, - FIND = 1073741950, - MUTE = 1073741951, - VOLUMEUP = 1073741952, - VOLUMEDOWN = 1073741953, - KpComma = 1073741957, - KpEqualsas400 = 1073741958, - ALTERASE = 1073741977, - SYSREQ = 1073741978, - CANCEL = 1073741979, - CLEAR = 1073741980, - PRIOR = 1073741981, - RETURN2 = 1073741982, - SEPARATOR = 1073741983, - OUT = 1073741984, - OPER = 1073741985, - CLEARAGAIN = 1073741986, - CRSEL = 1073741987, - EXSEL = 1073741988, - Kp00 = 1073742000, - Kp000 = 1073742001, - THOUSANDSSEPARATOR = 1073742002, - DECIMALSEPARATOR = 1073742003, - CURRENCYUNIT = 1073742004, - CURRENCYSUBUNIT = 1073742005, - KpLeftparen = 1073742006, - KpRightparen = 1073742007, - KpLeftbrace = 1073742008, - KpRightbrace = 1073742009, - KpTab = 1073742010, - KpBackspace = 1073742011, - KpA = 1073742012, - KpB = 1073742013, - KpC = 1073742014, - KpD = 1073742015, - KpE = 1073742016, - KpF = 1073742017, - KpXor = 1073742018, - KpPower = 1073742019, - KpPercent = 1073742020, - KpLess = 1073742021, - KpGreater = 1073742022, - KpAmpersand = 1073742023, - KpDblampersand = 1073742024, - KpVerticalbar = 1073742025, - KpDblverticalbar = 1073742026, - KpColon = 1073742027, - KpHash = 1073742028, - KpSpace = 1073742029, - KpAt = 1073742030, - KpExclam = 1073742031, - KpMemstore = 1073742032, - KpMemrecall = 1073742033, - KpMemclear = 1073742034, - KpMemadd = 1073742035, - KpMemsubtract = 1073742036, - KpMemmultiply = 1073742037, - KpMemdivide = 1073742038, - KpPlusminus = 1073742039, - KpClear = 1073742040, - KpClearentry = 1073742041, - KpBinary = 1073742042, - KpOctal = 1073742043, - KpDecimal = 1073742044, - KpHexadecimal = 1073742045, - LCTRL = 1073742048, - LSHIFT = 1073742049, - LALT = 1073742050, - LGUI = 1073742051, - RCTRL = 1073742052, - RSHIFT = 1073742053, - RALT = 1073742054, - RGUI = 1073742055, - MODE = 1073742081, - AUDIONEXT = 1073742082, - AUDIOPREV = 1073742083, - AUDIOSTOP = 1073742084, - AUDIOPLAY = 1073742085, - AUDIOMUTE = 1073742086, - MEDIASELECT = 1073742087, - WWW = 1073742088, - MAIL = 1073742089, - CALCULATOR = 1073742090, - COMPUTER = 1073742091, - AcSearch = 1073742092, - AcHome = 1073742093, - AcBack = 1073742094, - AcForward = 1073742095, - AcStop = 1073742096, - AcRefresh = 1073742097, - AcBookmarks = 1073742098, - BRIGHTNESSDOWN = 1073742099, - BRIGHTNESSUP = 1073742100, - DISPLAYSWITCH = 1073742101, - KBDILLUMTOGGLE = 1073742102, - KBDILLUMDOWN = 1073742103, - KBDILLUMUP = 1073742104, - EJECT = 1073742105, - SLEEP = 1073742106, - APP1 = 1073742107, - APP2 = 1073742108, - AUDIOREWIND = 1073742109, - AUDIOFASTFORWARD = 1073742110, -} - -#[repr(i32)] -pub enum PaletteColor { - Background, - Foreground, - - Background1, - Background2, - Background3, - Background4, - - Foreground1, - Foreground2, - Foreground3, - Foreground4, - - Red, - Green, - Yellow, - Blue, - Purple, - Aqua, - Gray, - - BrightRed, - BrightGreen, - BrightYellow, - BrightBlue, - BrightPurple, - BrightAqua, - BrightGray, -} diff --git a/plugins/default_view/init.lua b/plugins/default_view/init.lua deleted file mode 100644 index 58d8045..0000000 --- a/plugins/default_view/init.lua +++ /dev/null @@ -1,96 +0,0 @@ -local M = {} - -M.version = "0.1" -M.name = "Default_View" -M.namespace = "nl_spacegirl_plugin_Default" - -M.BufferListPanel = { - num_clicks = 0 -} - -M.SomeOtherPanel = { - num_clicks_2 = 0 -} - -function M.BufferListPanel.new() - local p = {} - setmetatable(p, {__index = M.BufferListPanel}) - return p -end - -function M.BufferListPanel:render(ctx) - -- if UI.button(ctx, "Number of Clicks "..self.num_clicks).clicked then - -- self.num_clicks = self.num_clicks + 1 - -- end -end - -function M.SomeOtherPanel.new() - local p = {} - setmetatable(p, {__index = M.SomeOtherPanel}) - return p -end - -function M.SomeOtherPanel:render(ctx) - UI_New.open_element(ctx, "Number of Clicks", { - dir = UI_New.LeftToRight, - kind = {UI_New.Exact(128), UI_New.Exact(32)}, - }) - UI_New.close_element(ctx) - - UI_New.open_element(ctx, "Whatever man", { - dir = UI_New.LeftToRight, - kind = {UI_New.Fit, UI_New.Exact(32)}, - }) - UI_New.close_element(ctx) -end - -function M.open_file_search_window() - local input = { - {Editor.Key.Enter, "Open File", function() Editor.log("this should open a file") end} - } - - Editor.spawn_floating_window(input, function(ctx) - UI.push_parent(ctx, UI.push_rect(ctx, "window", true, true, UI.Vertical, UI.Fill, UI.ChildrenSum)) - UI.label(ctx, "eventually this will be a window where you can search through a bunch of files 1") - UI.label(ctx, "eventually this will be a window where you can search through a bunch of files 2") - UI.label(ctx, "eventually this will be a window where you can search through a bunch of files 3") - UI.label(ctx, "eventually this will be a window where you can search through a bunch of files 4") - UI.label(ctx, "eventually this will be a window where you can search through a bunch of files 5") - UI.label(ctx, "eventually this will be a window where you can search through a bunch of files 6") - UI.label(ctx, "eventually this will be a window where you can search through a bunch of files 7") - UI.pop_parent(ctx) - end) -end - -function M.OnLoad() - Editor.log("default view loaded") - Editor.log(nl_spacegirl_plugin_Default_Legacy_View['namespace']) - - local a = M.BufferListPanel.new() - local b = M.BufferListPanel.new() - - print(M.BufferListPanel) - print(a) - print(b) - - Editor.register_key_group({ - {Editor.Key.Space, "", { - {Editor.Key.F, "Open File", M.open_file_search_window}, - {Editor.Key.J, "New Panel", function() - Editor.run_command("nl.spacegirl.editor.core", "Open New Panel", "BufferListPanel") - end}, - {Editor.Key.K, "Some Other Panel", function() - Editor.run_command("nl.spacegirl.editor.core", "Open New Panel", "SomeOtherPanel") - end} - }}, - }) - - Editor.register_panel("BufferList", "BufferListPanel") - Editor.register_panel("aksjdhflkasjdf", "SomeOtherPanel") -end - -function M.view_render(cx) - UI.label(cx, "Look its a me, a plugin") -end - -return M diff --git a/plugins/grep/Cargo.lock b/plugins/grep/Cargo.lock deleted file mode 100644 index 144e9a4..0000000 --- a/plugins/grep/Cargo.lock +++ /dev/null @@ -1,334 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "aho-corasick" -version = "1.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" -dependencies = [ - "memchr", -] - -[[package]] -name = "bstr" -version = "1.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c48f0051a4b4c5e0b6d365cd04af53aeaa209e3cc15ec2cdb69e73cc87fbd0dc" -dependencies = [ - "memchr", - "regex-automata", - "serde", -] - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "encoding_rs" -version = "0.8.33" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7268b386296a025e474d5140678f75d6de9493ae55a5d709eeb9dd08149945e1" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "encoding_rs_io" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cc3c5651fb62ab8aa3103998dade57efdd028544bd300516baa31840c252a83" -dependencies = [ - "encoding_rs", -] - -[[package]] -name = "globset" -version = "0.4.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57da3b9b5b85bd66f31093f8c408b90a74431672542466497dcbdfdc02034be1" -dependencies = [ - "aho-corasick", - "bstr", - "log", - "regex-automata", - "regex-syntax", -] - -[[package]] -name = "grep" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e2b024ec1e686cb64d78beb852030b0e632af93817f1ed25be0173af0e94939" -dependencies = [ - "grep-cli", - "grep-matcher", - "grep-printer", - "grep-regex", - "grep-searcher", -] - -[[package]] -name = "grep-cli" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea40788c059ab8b622c4d074732750bfb3bd2912e2dd58eabc11798a4d5ad725" -dependencies = [ - "bstr", - "globset", - "libc", - "log", - "termcolor", - "winapi-util", -] - -[[package]] -name = "grep-matcher" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47a3141a10a43acfedc7c98a60a834d7ba00dfe7bec9071cbfc19b55b292ac02" -dependencies = [ - "memchr", -] - -[[package]] -name = "grep-printer" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "743c12a03c8aee38b6e5bd0168d8ebb09345751323df4a01c56e792b1f38ceb2" -dependencies = [ - "bstr", - "grep-matcher", - "grep-searcher", - "log", - "serde", - "serde_json", - "termcolor", -] - -[[package]] -name = "grep-regex" -version = "0.1.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f748bb135ca835da5cbc67ca0e6955f968db9c5df74ca4f56b18e1ddbc68230d" -dependencies = [ - "bstr", - "grep-matcher", - "log", - "regex-automata", - "regex-syntax", -] - -[[package]] -name = "grep-searcher" -version = "0.1.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba536ae4f69bec62d8839584dd3153d3028ef31bb229f04e09fb5a9e5a193c54" -dependencies = [ - "bstr", - "encoding_rs", - "encoding_rs_io", - "grep-matcher", - "log", - "memchr", - "memmap2", -] - -[[package]] -name = "grep_plugin" -version = "0.1.0" -dependencies = [ - "grep", - "plugin_rs_bindings", - "termcolor", - "walkdir", -] - -[[package]] -name = "itoa" -version = "1.0.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" - -[[package]] -name = "libc" -version = "0.2.151" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "302d7ab3130588088d277783b1e2d2e10c9e9e4a16dd9050e6ec93fb3e7048f4" - -[[package]] -name = "log" -version = "0.4.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" - -[[package]] -name = "memchr" -version = "2.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" - -[[package]] -name = "memmap2" -version = "0.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45fd3a57831bf88bc63f8cebc0cf956116276e97fef3966103e96416209f7c92" -dependencies = [ - "libc", -] - -[[package]] -name = "plugin_rs_bindings" -version = "0.1.0" - -[[package]] -name = "proc-macro2" -version = "1.0.74" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2de98502f212cfcea8d0bb305bd0f49d7ebdd75b64ba0a68f937d888f4e0d6db" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "quote" -version = "1.0.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "regex-automata" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f" -dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax", -] - -[[package]] -name = "regex-syntax" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" - -[[package]] -name = "ryu" -version = "1.0.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f98d2aa92eebf49b69786be48e4477826b256916e84a57ff2a4f21923b48eb4c" - -[[package]] -name = "same-file" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" -dependencies = [ - "winapi-util", -] - -[[package]] -name = "serde" -version = "1.0.194" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b114498256798c94a0689e1a15fec6005dee8ac1f41de56404b67afc2a4b773" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_derive" -version = "1.0.194" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3385e45322e8f9931410f01b3031ec534c3947d0e94c18049af4d9f9907d4e0" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "serde_json" -version = "1.0.110" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fbd975230bada99c8bb618e0c365c2eefa219158d5c6c29610fd09ff1833257" -dependencies = [ - "itoa", - "ryu", - "serde", -] - -[[package]] -name = "syn" -version = "2.0.46" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89456b690ff72fddcecf231caedbe615c59480c93358a93dfae7fc29e3ebbf0e" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "termcolor" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff1bc3d3f05aff0403e8ac0d92ced918ec05b666a43f83297ccef5bea8a3d449" -dependencies = [ - "winapi-util", -] - -[[package]] -name = "unicode-ident" -version = "1.0.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" - -[[package]] -name = "walkdir" -version = "2.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d71d857dc86794ca4c280d616f7da00d2dbfd8cd788846559a6813e6aa4b54ee" -dependencies = [ - "same-file", - "winapi-util", -] - -[[package]] -name = "winapi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - -[[package]] -name = "winapi-util" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596" -dependencies = [ - "winapi", -] - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/plugins/grep/Cargo.toml b/plugins/grep/Cargo.toml deleted file mode 100644 index d9c7c43..0000000 --- a/plugins/grep/Cargo.toml +++ /dev/null @@ -1,14 +0,0 @@ -[package] -name = "grep_plugin" -version = "0.1.0" -edition = "2021" -publish = false - -[lib] -crate-type = ["cdylib"] - -[dependencies] -grep = "0.3.1" -termcolor = "1.4.0" -walkdir = "2.4.0" -plugin_rs_bindings = { path = "../../plugin-rs-bindings" } diff --git a/plugins/grep/rust-toolchain.toml b/plugins/grep/rust-toolchain.toml deleted file mode 100644 index 98d1e3f..0000000 --- a/plugins/grep/rust-toolchain.toml +++ /dev/null @@ -1,3 +0,0 @@ -[toolchain] -channel = "nightly-2024-01-24" - diff --git a/plugins/grep/src/lib.rs b/plugins/grep/src/lib.rs deleted file mode 100644 index fd03b6f..0000000 --- a/plugins/grep/src/lib.rs +++ /dev/null @@ -1,449 +0,0 @@ -use std::{ - error::Error, - ffi::{CString, OsString}, - path::Path, - str::FromStr, - sync::mpsc::{Receiver, Sender}, - thread, -}; - -use grep::{ - regex::RegexMatcherBuilder, - searcher::{BinaryDetection, SearcherBuilder, Sink, SinkError}, -}; -use plugin_rs_bindings::{Buffer, Closure, Hook, InputMap, Key, Plugin, UiAxis, UiSemanticSize}; -use std::sync::mpsc::channel; -use walkdir::WalkDir; - -#[derive(Debug)] -pub enum SimpleSinkError { - StandardError, - NoLine, - BadString, -} - -impl SinkError for SimpleSinkError { - fn error_message(message: T) -> Self { - eprintln!("{message}"); - - Self::StandardError - } -} - -#[derive(Debug)] -struct Match { - text: Vec, - path: String, - line_number: Option, - column: u64, -} -impl Match { - fn from_sink_match_with_path( - value: &grep::searcher::SinkMatch<'_>, - path: Option, - ) -> Result { - let line = value - .lines() - .next() - .ok_or(SimpleSinkError::NoLine)? - .to_vec(); - let column = value.bytes_range_in_buffer().len() as u64; - - Ok(Self { - text: line, - path: path.unwrap_or_default(), - line_number: value.line_number(), - column, - }) - } -} - -#[derive(Default, Debug)] -struct SimpleSink { - current_path: Option, - matches: Vec, -} -impl Sink for SimpleSink { - type Error = SimpleSinkError; - - fn matched( - &mut self, - _searcher: &grep::searcher::Searcher, - mat: &grep::searcher::SinkMatch<'_>, - ) -> Result { - self.matches.push(Match::from_sink_match_with_path( - mat, - self.current_path.clone(), - )?); - - Ok(true) - } -} - -fn search(pattern: &str, paths: &[OsString]) -> Result> { - let matcher = RegexMatcherBuilder::new() - .case_smart(true) - .fixed_strings(true) - .build(pattern)?; - let mut searcher = SearcherBuilder::new() - .binary_detection(BinaryDetection::quit(b'\x00')) - .line_number(true) - .build(); - - let mut sink = SimpleSink::default(); - for path in paths { - for result in WalkDir::new(path).into_iter().filter_entry(|dent| { - if dent.file_type().is_dir() - && (dent.path().ends_with("target") || dent.path().ends_with(".git")) - { - return false; - } - - true - }) { - let dent = match result { - Ok(dent) => dent, - Err(err) => { - eprintln!("{}", err); - continue; - } - }; - if !dent.file_type().is_file() { - continue; - } - sink.current_path = Some(dent.path().to_string_lossy().into()); - - let result = searcher.search_path(&matcher, dent.path(), &mut sink); - - if let Err(err) = result { - eprintln!("{}: {:?}", dent.path().display(), err); - } - } - } - - Ok(sink) -} - -enum Message { - Search((String, Vec)), - Quit, -} - -struct GrepWindow { - sink: Option, - selected_match: usize, - top_index: usize, - input_buffer: Option, - - tx: Sender, - rx: Receiver, -} - -#[no_mangle] -pub extern "C" fn OnInitialize(plugin: Plugin) { - println!("Grep Plugin Initialized"); - plugin.register_hook(Hook::BufferInput, on_buffer_input); - plugin.register_input_group( - None, - Key::Space, - Closure!((plugin: Plugin, input_map: InputMap) => { - (plugin.register_input)( - input_map, - Key::R, - Closure!((plugin: Plugin) => { - let (window_tx, thread_rx) = channel(); - let (thread_tx, window_rx) = channel(); - create_search_thread(thread_tx, thread_rx); - - let window = GrepWindow { - selected_match: 0, - top_index: 0, - input_buffer: Some(plugin.buffer_table.open_virtual_buffer()), - sink: None, - tx: window_tx, - rx: window_rx, - }; - - plugin.create_window(window, Closure!((plugin: Plugin, input_map: InputMap) => { - (plugin.enter_insert_mode)(); - - (plugin.register_input)(input_map, Key::I, Closure!((plugin: Plugin) => { - (plugin.enter_insert_mode)() - }), "\0".as_ptr()); - (plugin.register_input)(input_map, Key::Enter, Closure!((plugin: Plugin) => { - if let Some(window) = unsafe { plugin.get_window::() } { - match &window.sink { - Some(sink) => if window.selected_match < sink.matches.len() { - let mat = unsafe { &sink.matches.get_unchecked(window.selected_match) }; - plugin.buffer_table.open_buffer(&mat.path, (mat.line_number.unwrap_or(1)-1) as i32, 0); - (plugin.request_window_close)(); - }, - None => {}, - } - } - }), "move selection up\0".as_ptr()); - (plugin.register_input)(input_map, Key::K, Closure!((plugin: Plugin) => { - if let Some(window) = unsafe { plugin.get_window::() } { - - if window.selected_match > 0 { - window.selected_match -= 1; - - if window.selected_match < window.top_index { - window.top_index = window.selected_match; - } - } else { - window.selected_match = match &window.sink { - Some(sink) => sink.matches.len()-1, - None => 0, - }; - - window.top_index = window.selected_match; - } - } - }), "move selection up\0".as_ptr()); - (plugin.register_input)(input_map, Key::J, Closure!((plugin: Plugin) => { - if let Some(window) = unsafe { plugin.get_window::() } { - let screen_height = (plugin.get_screen_height)() as i32; - let font_height = (plugin.get_font_height)() as i32; - let height = screen_height - screen_height / 4; - let max_mats_to_draw = (height - font_height * 2) / (font_height) - 1; - - let match_count = match &window.sink { - Some(sink) => sink.matches.len(), - None => 0, - }; - - if match_count > 0 { - let index_threshold = std::cmp::max(max_mats_to_draw-4, 0) as usize; - - if window.selected_match < match_count-1 { - window.selected_match += 1; - - if window.selected_match - window.top_index > index_threshold { - window.top_index += 1; - } - } else { - window.selected_match = 0; - window.top_index = 0; - } - } - } - }), "move selection down\0".as_ptr()); - }), draw_window, free_window, Some(Closure!((_plugin: Plugin, window: *const std::ffi::c_void) -> Buffer => { - let window = Box::leak(unsafe { Box::::from_raw(window as *mut GrepWindow) }); - - if let Some(buffer) = window.input_buffer { - return buffer; - } else { - return Buffer::null(); - } - }))); - }), - "Open Grep Window\0".as_ptr(), - ); - }), - ); -} - -fn create_search_thread(tx: Sender, rx: Receiver) { - thread::spawn(move || { - while let Ok(message) = rx.recv() { - match message { - Message::Search((pattern, paths)) => { - if let Ok(sink) = search(&pattern, &paths) { - if let Err(err) = tx.send(sink) { - eprintln!("error getting grep results: {err:?}"); - return; - } - } - } - Message::Quit => return, - } - } - }); -} - -#[no_mangle] -pub extern "C" fn OnExit(_plugin: Plugin) { - println!("Grep Plugin Exiting"); -} - -extern "C" fn draw_window(plugin: Plugin, window: *const std::ffi::c_void) { - let window = Box::leak(unsafe { Box::::from_raw(window as *mut GrepWindow) }); - - let screen_height = (plugin.get_screen_height)() as i32; - - let font_height = (plugin.get_font_height)() as i32; - - let height = screen_height - screen_height / 4; - - let dir = plugin.get_current_directory(); - let directory = Path::new(dir.as_ref()); - - plugin - .ui_table - .push_floating(c"grep canvas", 0, 0, |ui_table| { - // TODO: make some primitive that centers a Box - ui_table.spacer(c"left spacer"); - - ui_table.push_rect( - c"centered container", - false, - false, - UiAxis::Vertical, - UiSemanticSize::PercentOfParent(75), - UiSemanticSize::Fill, - |ui_table| { - ui_table.spacer(c"top spacer"); - ui_table.push_rect( - c"grep window", - true, - true, - UiAxis::Vertical, - UiSemanticSize::Fill, - UiSemanticSize::PercentOfParent(75), - |ui_table| { - if let Ok(sink) = window.rx.try_recv() { - window.sink = Some(sink); - } - - ui_table.push_rect( - c"results list", - false, - false, - UiAxis::Vertical, - UiSemanticSize::Fill, - UiSemanticSize::Fill, - |ui_table| match &window.sink { - Some(sink) if !sink.matches.is_empty() => { - let num_mats_to_draw = std::cmp::min( - (sink.matches.len() - window.top_index) as i32, - (height - font_height) / (font_height), - ); - - for (i, mat) in - sink.matches[window.top_index..].iter().enumerate() - { - let index = i + window.top_index; - if i as i32 >= num_mats_to_draw { - break; - } - - let path = Path::new(&mat.path); - let relative_file_path = path - .strip_prefix(directory) - .unwrap_or(path) - .to_str() - .unwrap_or(""); - - let matched_text = String::from_utf8_lossy(&mat.text); - let text = match mat.line_number { - Some(line_number) => format!( - "{}:{}:{}: {}", - relative_file_path, - line_number, - mat.column, - matched_text - ), - None => format!( - "{}:{}: {}", - relative_file_path, mat.column, matched_text - ), - }; - - if index == window.selected_match { - // TODO: don't use button here, but apply a style - // to `label` - ui_table.button( - &CString::new(text).expect("valid text"), - ); - } else { - ui_table.label( - &CString::new(text).expect("valid text"), - ); - } - } - } - Some(_) | None => { - ui_table.spacer(c"top spacer"); - ui_table.push_rect( - c"centered text container", - false, - false, - UiAxis::Horizontal, - UiSemanticSize::Fill, - UiSemanticSize::Fill, - |ui_table| { - ui_table.spacer(c"left spacer"); - ui_table.label(c"no results"); - ui_table.spacer(c"right spacer"); - }, - ); - ui_table.spacer(c"bottom spacer"); - } - }, - ); - - ui_table.push_rect( - c"grep window", - true, - false, - UiAxis::Vertical, - UiSemanticSize::Fill, - UiSemanticSize::Exact(font_height as isize), - |ui_table| { - if let Some(buffer) = window.input_buffer { - ui_table.buffer(buffer, false); - } - }, - ); - }, - ); - ui_table.spacer(c"bottom spacer"); - }, - ); - ui_table.spacer(c"right spacer"); - }); -} - -extern "C" fn on_buffer_input(plugin: Plugin, buffer: Buffer) { - // NOTE(pcleavelin): this is super jank, because another plugin could have a window open when - // this gets called, however its fine here because we aren't manipulating any data, and a check - // is made between the buffer pointers which will only be correct if its our window. - if let Some(window) = unsafe { plugin.get_window::() } { - if window.input_buffer == Some(buffer) { - window.selected_match = 0; - window.top_index = 0; - - if let Some(buffer_info) = plugin.buffer_table.get_buffer_info(buffer) { - if let Some(input) = buffer_info.input.try_as_str() { - let directory = OsString::from_str(plugin.get_current_directory().as_ref()); - - match directory { - Ok(dir) => { - if let Err(err) = window - .tx - .send(Message::Search((input.to_string(), vec![dir]))) - { - eprintln!("failed to grep: {err:?}"); - } - } - Err(_) => { - eprintln!("failed to parse directory"); - } - }; - } - } - } - } -} - -extern "C" fn free_window(plugin: Plugin, window: *const std::ffi::c_void) { - let mut window = unsafe { Box::::from_raw(window as *mut GrepWindow) }; - let _ = window.tx.send(Message::Quit); - - if let Some(buffer) = window.input_buffer { - plugin.buffer_table.free_virtual_buffer(buffer); - window.input_buffer = None; - } -} diff --git a/plugins/highlighter/src/plugin.odin b/plugins/highlighter/src/plugin.odin deleted file mode 100644 index 6fe77fe..0000000 --- a/plugins/highlighter/src/plugin.odin +++ /dev/null @@ -1,423 +0,0 @@ -// The default syntax highlighter plugin for Odin & Rust -package highlighter; - -import "base:runtime" -import "core:fmt" - -import p "../../../src/plugin" - -Plugin :: p.Plugin; -Iterator :: p.Iterator; -BufferIter :: p.BufferIter; -BufferIndex :: p.BufferIndex; - -@export -OnInitialize :: proc "c" (plugin: Plugin) { - context = runtime.default_context(); - fmt.println("builtin highlighter plugin initialized!"); - - plugin.register_highlighter(".odin", color_buffer_odin); - plugin.register_highlighter(".rs", color_buffer_rust); -} - -@export -OnExit :: proc "c" () { - context = runtime.default_context(); - fmt.println("Goodbye from the Odin Highlighter Plugin!"); -} - -@export -OnDraw :: proc "c" (plugin: Plugin) { - context = runtime.default_context(); -} - -iterate_buffer :: proc(iter_funcs: Iterator, it: ^BufferIter) -> (character: u8, idx: BufferIndex, cond: bool) { - result := iter_funcs.iterate_buffer(it); - - return result.char, it.cursor.index, result.should_continue; -} - -iterate_buffer_reverse :: proc(iter_funcs: Iterator, it: ^BufferIter) -> (character: u8, idx: BufferIndex, cond: bool) { - result := iter_funcs.iterate_buffer_reverse(it); - - return result.char, it.cursor.index, result.should_continue; -} - -iterate_buffer_until :: proc(plugin: Plugin, it: ^BufferIter, until_proc: rawptr) { - plugin.iter.iterate_buffer_until(it, until_proc); -} - -iterate_buffer_peek :: proc(plugin: Plugin, it: ^BufferIter) -> (character: u8, idx: BufferIndex, cond: bool) { - result := plugin.iter.iterate_buffer_peek(it); - - return result.char, it.cursor.index, result.should_continue; -} - -is_odin_keyword :: proc(plugin: Plugin, start: BufferIter, end: BufferIter) -> (matches: bool) { - keywords := []string { - "using", - "transmute", - "cast", - "distinct", - "opaque", - "where", - "struct", - "enum", - "union", - "bit_field", - "bit_set", - "if", - "when", - "else", - "do", - "for", - "switch", - "case", - "continue", - "break", - "size_of", - "offset_of", - "type_info_of", - "typeid_of", - "type_of", - "align_of", - "or_return", - "or_else", - "inline", - "no_inline", - "string", - "cstring", - "bool", - "b8", - "b16", - "b32", - "b64", - "rune", - "any", - "rawptr", - "f16", - "f32", - "f64", - "f16le", - "f16be", - "f32le", - "f32be", - "f64le", - "f64be", - "u8", - "u16", - "u32", - "u64", - "u128", - "u16le", - "u32le", - "u64le", - "u128le", - "u16be", - "u32be", - "u64be", - "u128be", - "uint", - "uintptr", - "i8", - "i16", - "i32", - "i64", - "i128", - "i16le", - "i32le", - "i64le", - "i128le", - "i16be", - "i32be", - "i64be", - "i128be", - "int", - "complex", - "complex32", - "complex64", - "complex128", - "quaternion", - "quaternion64", - "quaternion128", - "quaternion256", - "matrix", - "typeid", - "true", - "false", - "nil", - "dynamic", - "map", - "proc", - "in", - "notin", - "not_in", - "import", - "export", - "foreign", - "const", - "package", - "return", - "defer", - }; - - for keyword in keywords { - it := start; - keyword_index := 0; - - for character in iterate_buffer(plugin.iter, &it) { - if character != keyword[keyword_index] { - break; - } - - keyword_index += 1; - if keyword_index >= len(keyword)-1 && it == end { - if plugin.iter.get_char_at_iter(&it) == keyword[keyword_index] { - matches = true; - } - - break; - } else if keyword_index >= len(keyword)-1 { - break; - } else if it == end { - break; - } - } - - if matches { - break; - } - } - - return; -} - -is_rust_keyword :: proc(plugin: Plugin, start: BufferIter, end: BufferIter) -> (matches: bool) { - keywords := []string { - "as", - "break", - "const", - "continue", - "crate", - "else", - "enum", - "extern", - "false", - "fn", - "for", - "if", - "impl", - "in", - "let", - "loop", - "match", - "mod", - "move", - "mut", - "pub", - "ref", - "return", - "self", - "Self", - "static", - "struct", - "super", - "trait", - "true", - "type", - "unsafe", - "use", - "where", - "while", - "u8", - "i8", - "u16", - "i16", - "u32", - "i32", - "u64", - "i64", - "bool", - "usize", - "isize", - "str", - "String", - "Option", - "Result", - }; - - for keyword in keywords { - it := start; - keyword_index := 0; - - for character in iterate_buffer(plugin.iter, &it) { - if character != keyword[keyword_index] { - break; - } - - keyword_index += 1; - if keyword_index >= len(keyword)-1 && it == end { - if plugin.iter.get_char_at_iter(&it) == keyword[keyword_index] { - matches = true; - } - - break; - } else if keyword_index >= len(keyword)-1 { - break; - } else if it == end { - break; - } - } - - if matches { - break; - } - } - - return; -} - -// TODO: split logic into single line coloring, and multi-line coloring. -// single line coloring can be done directly on the glyph buffer -// (with some edge cases, literally, the edge of the screen) -color_buffer_odin :: proc "c" (plugin: Plugin, buffer: rawptr) { - context = runtime.default_context(); - - buffer := plugin.buffer.get_buffer_info(buffer); - - start_it := plugin.iter.get_buffer_iterator(buffer.buffer); - it := plugin.iter.get_buffer_iterator(buffer.buffer); - - for character in iterate_buffer(plugin.iter, &it) { - if it.cursor.line > buffer.glyph_buffer_height && (it.cursor.line - buffer.top_line) > buffer.glyph_buffer_height { - break; - } - - if character == '/' { - start_it = it; - // need to go back one character because `it` is on the next character - iterate_buffer_reverse(plugin.iter, &start_it); - - character, _, succ := iterate_buffer(plugin.iter, &it); - if !succ { break; } - - if character == '/' { - iterate_buffer_until(plugin, &it, plugin.iter.until_line_break); - plugin.buffer.color_char_at(it.buffer, start_it.cursor, it.cursor, 9); - } else if character == '*' { - // TODO: block comments - } - } else if character == '\'' { - start_it = it; - // need to go back one character because `it` is on the next character - iterate_buffer_reverse(plugin.iter, &start_it); - - // jump into the quoted text - iterate_buffer_until(plugin, &it, plugin.iter.until_single_quote); - plugin.buffer.color_char_at(it.buffer, start_it.cursor, it.cursor, 12); - - iterate_buffer(plugin.iter, &it); - } else if character == '"' { - start_it = it; - // need to go back one character because `it` is on the next character - iterate_buffer_reverse(plugin.iter, &start_it); - - // jump into the quoted text - iterate_buffer_until(plugin, &it, plugin.iter.until_double_quote); - plugin.buffer.color_char_at(it.buffer, start_it.cursor, it.cursor, 12); - - iterate_buffer(plugin.iter, &it); - } else if (character >= 'a' && character <= 'z') || (character >= 'A' && character <= 'Z') || character == '_' { - start_it = it; - // need to go back one character because `it` is on the next character - iterate_buffer_reverse(plugin.iter, &start_it); - it = start_it; - - iterate_buffer_until(plugin, &it, plugin.iter.until_end_of_word); - - if is_odin_keyword(plugin, start_it, it) { - plugin.buffer.color_char_at(it.buffer, start_it.cursor, it.cursor, 13); - - iterate_buffer(plugin.iter, &it); - } else if character, _, cond := iterate_buffer_peek(plugin, &it); cond { - if character == '(' { - plugin.buffer.color_char_at(it.buffer, start_it.cursor, it.cursor, 11); - iterate_buffer(plugin.iter, &it); - } - } else { - break; - } - } - } -} - -color_buffer_rust :: proc "c" (plugin: Plugin, buffer: rawptr) { - context = runtime.default_context(); - - buffer := plugin.buffer.get_buffer_info(buffer); - - start_it := plugin.iter.get_buffer_iterator(buffer.buffer); - it := plugin.iter.get_buffer_iterator(buffer.buffer); - - for character in iterate_buffer(plugin.iter, &it) { - if it.cursor.line > buffer.glyph_buffer_height && (it.cursor.line - buffer.top_line) > buffer.glyph_buffer_height { - break; - } - - if character == '/' { - start_it = it; - // need to go back one character because `it` is on the next character - iterate_buffer_reverse(plugin.iter, &start_it); - - character, _, succ := iterate_buffer(plugin.iter, &it); - if !succ { break; } - - if character == '/' { - iterate_buffer_until(plugin, &it, plugin.iter.until_line_break); - plugin.buffer.color_char_at(it.buffer, start_it.cursor, it.cursor, 9); - } else if character == '*' { - // TODO: block comments - } - } else if character == '\'' && false { - start_it = it; - // need to go back one character because `it` is on the next character - iterate_buffer_reverse(plugin.iter, &start_it); - - // jump into the quoted text - iterate_buffer_until(plugin, &it, plugin.iter.until_single_quote); - plugin.buffer.color_char_at(it.buffer, start_it.cursor, it.cursor, 12); - - iterate_buffer(plugin.iter, &it); - } else if character == '"' { - start_it = it; - // need to go back one character because `it` is on the next character - iterate_buffer_reverse(plugin.iter, &start_it); - - // jump into the quoted text - iterate_buffer_until(plugin, &it, plugin.iter.until_double_quote); - plugin.buffer.color_char_at(it.buffer, start_it.cursor, it.cursor, 12); - - iterate_buffer(plugin.iter, &it); - } else if (character >= 'a' && character <= 'z') || (character >= 'A' && character <= 'Z') || character == '_' { - start_it = it; - // need to go back one character because `it` is on the next character - iterate_buffer_reverse(plugin.iter, &start_it); - it = start_it; - - iterate_buffer_until(plugin, &it, plugin.iter.until_end_of_word); - - if is_rust_keyword(plugin, start_it, it) { - plugin.buffer.color_char_at(it.buffer, start_it.cursor, it.cursor, 13); - - iterate_buffer(plugin.iter, &it); - } else if character, _, cond := iterate_buffer_peek(plugin, &it); cond { - if character == '(' || character == '<' || character == '!' { - plugin.buffer.color_char_at(it.buffer, start_it.cursor, it.cursor, 11); - iterate_buffer(plugin.iter, &it); - } - } else { - break; - } - } - } -} diff --git a/plugins/lua/view.lua b/plugins/lua/view.lua deleted file mode 100644 index a017a15..0000000 --- a/plugins/lua/view.lua +++ /dev/null @@ -1,526 +0,0 @@ -local M = {} - -M.version = "0.1" -M.name = "Legacy_View" -M.namespace = "nl_spacegirl_plugin_Default" - -local BufferSearchOpen = false -local BufferSearchOpenElapsed = 0 - -local CommandSearchOpen = false -local CommandSearchOpenElapsed = 0 -local CommandList = {} - -local LogWindowOpen = false -local LogWindowOpenElapsed = 0 - -local CurrentPreviewBufferIndex = Editor.get_current_buffer_index() -local BufferSearchIndex = 0 - -local SideBarSmoothedWidth = 128 -local SideBarWidth = 128 -local SideBarClosed = false - -local ActiveCodeView = nil -local CodeViews = {} - -local MovingTab = nil -local MovingTabDest = nil -local MovingTabInBetween = false - -local LastMouseX = 0 -local LastMouseY = 0 - -function buffer_list_iter(start) - local idx = start - return function () - buffer_info = Editor.buffer_info_from_index(idx) - idx = idx + 1 - - return buffer_info, idx-1 - end -end - -function centered(ctx, label, axis, width, height, body) - UI.push_parent(ctx, UI.push_rect(ctx, label, false, false, UI.Horizontal, UI.Fill, UI.Fill)) - UI.spacer(ctx, "left spacer") - UI.push_parent(ctx, UI.push_rect(ctx, "halfway centered", false, false, UI.Vertical, width, UI.Fill)) - UI.spacer(ctx, "top spacer") - UI.push_parent(ctx, UI.push_rect(ctx, "centered container", false, false, axis, UI.Fill, height)) - body() - UI.pop_parent(ctx) - UI.spacer(ctx, "bottom spacer") - UI.pop_parent(ctx) - UI.spacer(ctx, "right spacer") - UI.pop_parent(ctx) -end - -function list_iter(start, list) - local idx = start - - return function() - local value = list[idx] - idx = idx + 1 - return value, idx-1 - end -end - -function list(ctx, label, selection_index, list, render_func) - list_with_iter(ctx, label, selection_index, list_iter(selection_index, list), render_func) -end - -function list_with_iter(ctx, label, selection_index, list_iter, render_func) - local num_items = 10 - - UI.push_parent(ctx, UI.push_rect(ctx, label, true, true, UI.Vertical, UI.Fill, UI.Fill)) - for data, i in list_iter do - render_func(ctx, data, i == selection_index) - end - UI.pop_parent(ctx) -end - -function lerp(from, to, rate) - return (1 - rate) * from + rate*to -end - -function remove_buffer_from_code_view(code_view_index, file_path) - if code_view_index ~= nil and CodeViews[code_view_index] ~= nil then - CodeViews[code_view_index].tabs[file_path] = nil - k,v = pairs(CodeViews[code_view_index].tabs)(CodeViews[code_view_index].tabs) - CodeViews[code_view_index].current_tab = k - end -end - -function add_buffer_to_code_view(code_view_index, file_path, buffer_index) - if code_view_index == nil then - code_view_index = 1 - ActiveCodeView = 1 - end - - -- A new code view is being created - if CodeViews[code_view_index] == nil then - CodeViews[code_view_index] = {} - CodeViews[code_view_index].tabs = {} - CodeViews[code_view_index].width = UI.Fill - end - - ActiveCodeView = code_view_index - - CodeViews[code_view_index].tabs[file_path] = {} - CodeViews[code_view_index].tabs[file_path].buffer_index = buffer_index - CodeViews[code_view_index].current_tab = file_path -end - -function ui_sidemenu(ctx) - if SideBarClosed then - SideBarSmoothedWidth = lerp(SideBarSmoothedWidth, 0, 0.3) - else - SideBarSmoothedWidth = lerp(SideBarSmoothedWidth, SideBarWidth, 0.3) - end - - side_menu, _ = UI.push_box(ctx, "side menu", {"Scrollable"}, UI.Vertical, UI.Exact(SideBarSmoothedWidth), UI.Fill) - UI.push_parent(ctx, side_menu) - UI.push_rect(ctx, "padded top open files", false, false, UI.Horizontal, UI.Fill, UI.Exact(8)) - UI.push_parent(ctx, UI.push_rect(ctx, "padded open files", false, false, UI.Horizontal, UI.Fill, UI.ChildrenSum)) - UI.push_rect(ctx, "padded top open files", false, false, UI.Horizontal, UI.Exact(8), UI.Fill) - UI.label(ctx, "Open Files") - UI.pop_parent(ctx) - UI.push_rect(ctx, "padded bottom open files", false, false, UI.Horizontal, UI.Fill, UI.Exact(8)) - - for buffer_info, i in buffer_list_iter(0) do - button_container = UI.push_rect(ctx, "button container"..i, false, false, UI.Horizontal, UI.Fill, UI.ChildrenSum) - UI.push_parent(ctx, button_container) - flags = {"Clickable", "Hoverable", "DrawText"} - if i == current_buffer_index then - table.insert(flags, 1, "DrawBackground") - end - - if UI.advanced_button(ctx, " x ", flags, UI.FitText, UI.FitText).clicked then - Editor.log("hahah, you can't close buffers yet silly") - if ActiveCodeView ~= nil then - Editor.set_current_buffer_from_index(i) - add_buffer_to_code_view(ActiveCodeView+1, buffer_info.file_path, i) - end - end - - tab_button_interaction = UI.advanced_button(ctx, " "..buffer_info.file_path.." ", flags, UI.Fill, UI.FitText) - if tab_button_interaction.clicked then - Editor.set_current_buffer_from_index(i) - add_buffer_to_code_view(ActiveCodeView, buffer_info.file_path, i) - end - if tab_button_interaction.hovering then - CurrentPreviewBufferIndex = i - end - UI.pop_parent(ctx) - end - UI.spacer(ctx, "below buffers spacer") - - UI.pop_parent(ctx) -end - -function ui_code_view(ctx, code_view_index) - local code_view = CodeViews[code_view_index] - local is_tab_dest = MovingTab ~= nil and ActiveCodeView ~= code_view_index - - code_view_rect, code_view_interaction = UI.push_rect(ctx, code_view_index.." code view", ActiveCodeView ~= code_view_index, true, UI.Vertical, code_view.width, UI.Fill) - - UI.push_parent(ctx, code_view_rect) - tab_dest_flags = {} - if is_tab_dest then tab_dest_flags = {"Hoverable"} end - - tab_dest_region, tab_dest_interaction = UI.push_box(ctx, "code view tab dest", tab_dest_flags, UI.Vertical, UI.Fill, UI.Fill) - UI.push_parent(ctx, tab_dest_region) - if is_tab_dest then - if tab_dest_interaction.hovering then - MovingTabDest = code_view_index - elseif MovingTabDest == code_view_index then - MovingTabDest = nil - end - end - - UI.push_parent(ctx, UI.push_box(ctx, "tabs", {}, UI.Horizontal, UI.Fill, UI.ChildrenSum)) - for k,v in pairs(code_view.tabs) do - show_border = k ~= code_view.current_tab - background = show_border - flags = {"Clickable", "DrawText"} - if show_border then - table.insert(flags, 1, "DrawBorder") - table.insert(flags, 1, "Hoverable") - end - - UI.push_parent(ctx, UI.push_rect(ctx, k.." tab container", background, false, UI.Horizontal, UI.ChildrenSum, UI.ChildrenSum)) - tab_button = UI.advanced_button(ctx, " "..k.." ", flags, UI.FitText, UI.Exact(32)) - if tab_button.clicked or tab_button.dragging then - ActiveCodeView = code_view_index - code_view.current_tab = k - - Editor.set_current_buffer_from_index(v["buffer_index"]) - end - - if tab_button.dragging then - if MovingTab == nil then - MovingTab = {} - MovingTab["code_view_index"] = code_view_index - MovingTab["tab"] = k - end - - UI.push_parent(ctx, UI.push_floating(ctx, "dragging tab", x-(96/2), y-(32/2))) - UI.advanced_button(ctx, " "..k.." ", {"DrawText", "DrawBorder", "DrawBackground"}, UI.FitText, UI.Exact(32)) - UI.pop_parent(ctx) - elseif MovingTab ~= nil and MovingTab["code_view_index"] == code_view_index and MovingTab["tab"] == k then - if MovingTabDest ~= nil then - if MovingTabInBetween then - remove_buffer_from_code_view(code_view_index, k) - - table.insert(CodeViews, MovingTabDest+1, nil) - add_buffer_to_code_view(MovingTabDest+1, k, v["buffer_index"]) - else - add_buffer_to_code_view(MovingTabDest, k, v["buffer_index"]) - remove_buffer_from_code_view(code_view_index, k) - - MovingTabDest = nil - end - end - - MovingTab = nil - end - UI.pop_parent(ctx) - end - UI.pop_parent(ctx) - - current_tab = code_view.current_tab - if code_view.tabs[current_tab] ~= nil then - buffer_index = code_view.tabs[current_tab].buffer_index - - UI.buffer(ctx, buffer_index) - end - - UI.pop_parent(ctx) - UI.pop_parent(ctx) - - return code_view_interaction -end - -function M.render_ui_window(ctx) - current_buffer_index = Editor.get_current_buffer_index() - x,y = UI.get_mouse_pos(ctx) - delta_x = LastMouseX - x - delta_y = LastMouseY - y - - numFrames = 7 - CurrentPreviewBufferIndex = current_buffer_index - - if not SideBarClosed or SideBarSmoothedWidth > 2 then - ui_sidemenu(ctx) - end - - side_bar_interaction = UI.advanced_button(ctx, "side menu grab handle", {"DrawBorder", "Hoverable", "Clickable"}, UI.Exact(16), UI.Fill) - if side_bar_interaction.clicked then - if SideBarClosed then - SideBarClosed = false - - if SideBarWidth < 32 then - SideBarWidth = 128 - end - else - SideBarClosed = true - end - end - if side_bar_interaction.dragging then - SideBarWidth = x-8 - - if SideBarWidth < 32 then - SideBarClosed = true - SideBarWidth = 0 - elseif SideBarWidth > 128 then - SideBarClosed = false - end - - if not SideBarClosed then - SideBarWidth = math.max(SideBarWidth, 128) - end - end - - for k,v in ipairs(CodeViews) do - code_view_interaction = ui_code_view(ctx, k) - - if next(CodeViews, k) ~= nil then - interaction = UI.advanced_button(ctx, k.."code view grab handle", {"DrawBorder", "Hoverable", "Clickable"}, UI.Exact(16), UI.Fill) - if interaction.dragging then - local width = math.max(32, x - code_view_interaction.box_pos.x) - v.width = UI.Exact(width) - elseif interaction.clicked then - v.width = UI.Fill - elseif MovingTab ~= nil and interaction.hovering then - MovingTabInBetween = true - MovingTabDest = k - elseif MovingTabDest == k and MovingTabInBetween then - MovingTabInBetween = false - MovingTabDest = nil - end - else - v.width = UI.Fill - end - end - - for k,v in ipairs(CodeViews) do - if next(v.tabs) == nil then - table.remove(CodeViews, k) - - if ActiveCodeView > k then - ActiveCodeView = ActiveCodeView - 1 - end - end - end - - -- render_buffer_search(ctx) - -- render_command_search(ctx) - render_log_window(ctx) - - LastMouseX = x - LastMouseY = y -end - -function M.open_buffer_search_window(ctx) - -- if BufferSearchOpen or BufferSearchOpenElapsed > 0 then - -- if BufferSearchOpen and BufferSearchOpenElapsed < numFrames then - -- BufferSearchOpenElapsed = BufferSearchOpenElapsed + 1 - -- elseif not BufferSearchOpen and BufferSearchOpenElapsed > 0 then - -- BufferSearchOpenElapsed = BufferSearchOpenElapsed - 1 - -- end - -- end - - -- if BufferSearchOpen or BufferSearchOpenElapsed > 0 then - -- window_percent = 75 - -- if BufferSearchOpenElapsed > 0 then - -- window_percent = ((BufferSearchOpenElapsed/numFrames) * 75) - -- end - - local input = { - {Editor.Key.Escape, "Close Window", ( - function () - Editor.request_window_close() - BufferSearchOpen = false - end - )}, - {Editor.Key.Enter, "Switch to Buffer", ( - function () - buffer_info = Editor.buffer_info_from_index(BufferSearchIndex) - add_buffer_to_code_view(ActiveCodeView, buffer_info.file_path, BufferSearchIndex) - - Editor.set_current_buffer_from_index(BufferSearchIndex) - Editor.request_window_close() - BufferSearchOpen = false - end - )}, - -- TODO: don't scroll past buffers - {Editor.Key.K, "Move Selection Up", (function () BufferSearchIndex = BufferSearchIndex - 1 end)}, - {Editor.Key.J, "Move Selection Down", (function () BufferSearchIndex = BufferSearchIndex + 1 end)}, - } - - Editor.spawn_floating_window(input, function(ctx) - -- UI.push_parent(ctx, UI.push_floating(ctx, "buffer search canvas", 0, 0)) - -- centered(ctx, "buffer search window", UI.Horizontal, UI.PercentOfParent(window_percent), UI.PercentOfParent(window_percent), ( - -- function () - list_with_iter(ctx, "buffer list", BufferSearchIndex, buffer_list_iter(BufferSearchIndex), - function(ctx, buffer_info, is_selected) - flags = {"DrawText"} - - if is_selected then - table.insert(flags, 1, "DrawBorder") - end - - interaction = UI.advanced_button(ctx, " "..buffer_info.file_path.." ", flags, UI.Fill, UI.FitText) - end - ) - UI.buffer(ctx, BufferSearchIndex) - - -- UI.push_parent(ctx, UI.push_rect(ctx, "window", true, true, UI.Horizontal, UI.Fill, UI.Fill)) - -- UI.push_parent(ctx, UI.push_rect(ctx, "buffer list", false, false, UI.Vertical, UI.Fill, UI.Fill)) - -- for buffer_info, i in buffer_list_iter() do - -- flags = {"DrawText"} - -- - -- if i == BufferSearchIndex then - -- table.insert(flags, 1, "DrawBorder") - -- end - -- interaction = UI.advanced_button(ctx, " "..buffer_info.file_path.." ", flags, UI.Fill, UI.FitText) - -- end - -- UI.pop_parent(ctx) - -- UI.buffer(ctx, BufferSearchIndex) - -- UI.pop_parent(ctx) - -- end - -- )) - -- UI.pop_parent(ctx) - end) - -- end -end - -function M.open_command_palette() - -- if CommandSearchOpen or CommandSearchOpenElapsed > 0 then - -- if CommandSearchOpen and CommandSearchOpenElapsed < numFrames then - -- CommandSearchOpenElapsed = CommandSearchOpenElapsed + 1 - -- elseif not CommandSearchOpen and CommandSearchOpenElapsed > 0 then - -- CommandSearchOpenElapsed = CommandSearchOpenElapsed - 1 - -- end - -- end - - -- if CommandSearchOpen or CommandSearchOpenElapsed > 0 then - -- window_percent_width = 75 - -- window_percent_height = 25 - -- if CommandSearchOpenElapsed > 0 then - -- window_percent_width = ((CommandSearchOpenElapsed/numFrames) * 75) - -- window_percent_height = ((CommandSearchOpenElapsed/numFrames) * 25) - -- end - - -- UI.push_parent(ctx, UI.push_floating(ctx, "buffer search canvas", 0, 0)) - -- centered(ctx, "command search window", UI.Horizontal, UI.PercentOfParent(window_percent_width), UI.PercentOfParent(window_percent_height), - -- function () - local input = { - {Editor.Key.Escape, "Close Window", ( - function () - Editor.request_window_close() - CommandSearchOpen = false - end - )}, - {Editor.Key.Enter, "Run Command", ( - function () - if CommandList[CommandSearchIndex] ~= nil then - Editor.run_command("nl.spacegirl.editor.core", CommandList[CommandSearchIndex]["name"]) - CommandList = {} - - Editor.request_window_close() - CommandSearchOpen = false - end - end - )}, - -- TODO: don't scroll past selections - {Editor.Key.K, "Move Selection Up", (function () CommandSearchIndex = CommandSearchIndex - 1 end)}, - {Editor.Key.J, "Move Selection Down", (function () CommandSearchIndex = CommandSearchIndex + 1 end)}, - } - - Editor.spawn_floating_window(input, function(ctx) - list(ctx, "command list", CommandSearchIndex, CommandList, - function(ctx, cmd, is_selected) - flags = {"DrawText"} - - if is_selected then - table.insert(flags, 1, "DrawBorder") - end - - interaction = UI.advanced_button(ctx, " "..cmd.name..": "..cmd.description.." ", flags, UI.Fill, UI.FitText) - end - ) - end) - -- ) - -- UI.pop_parent(ctx) - -- end -end - -function render_log_window(ctx) - if Editor.get_current_buffer_index() ~= -2 then - LogWindowOpen = false - end - - if LogWindowOpen or LogWindowOpenElapsed > 0 then - if LogWindowOpen and LogWindowOpenElapsed < numFrames then - LogWindowOpenElapsed = LogWindowOpenElapsed + 1 - elseif not LogWindowOpen and LogWindowOpenElapsed > 0 then - LogWindowOpenElapsed = LogWindowOpenElapsed - 1 - end - end - - if LogWindowOpen or LogWindowOpenElapsed > 0 then - window_percent = 75 - if LogWindowOpenElapsed > 0 then - window_percent = ((LogWindowOpenElapsed/numFrames) * 75) - end - - UI.push_parent(ctx, UI.push_floating(ctx, "log window canvas", 0, 0)) - centered(ctx, "log window", UI.Horizontal, UI.PercentOfParent(window_percent), UI.PercentOfParent(window_percent), ( - function () - UI.push_parent(ctx, UI.push_rect(ctx, "window", true, true, UI.Horizontal, UI.Fill, UI.Fill)) - -- -2 is the log buffer - UI.buffer(ctx, -2) - UI.pop_parent(ctx) - end - )) - UI.pop_parent(ctx) - end -end - -function handle_buffer_input() -end - -function M.OnLoad() - Editor.log("Legacy View plugin loaded") - - Editor.register_key_group({ - {Editor.Key.Backtick, "Open Editor Logs", (function () - if not LogWindowOpen then - LogWindowOpen = true - Editor.set_current_buffer_from_index(-2) - else - LogWindowOpen = false - local code_view = CodeViews[ActiveCodeView] - Editor.set_current_buffer_from_index(code_view.tabs[code_view.current_tab]["buffer_index"]) - end - end)}, - {Editor.Key.Space, "", { - {Editor.Key.P, "Command Palette", - (function () - CommandSearchOpen = true - CommandSearchIndex = 1 - - CommandList = Editor.query_command_group("nl.spacegirl.editor.core") - M.open_command_palette() - end), - }, - {Editor.Key.B, "Buffer Search", M.open_buffer_search_window} - }} - }) - - Editor.register_hook(Editor.Hook.OnDraw, M.render_ui_window) - Editor.register_hook(Editor.Hook.OnBufferInput, handle_buffer_input) -end - -return M diff --git a/rust-toolchain b/rust-toolchain deleted file mode 100755 index 2bf5ad0..0000000 --- a/rust-toolchain +++ /dev/null @@ -1 +0,0 @@ -stable diff --git a/src/core/core.odin b/src/core/core.odin index 009f76a..34f3e6c 100644 --- a/src/core/core.odin +++ b/src/core/core.odin @@ -8,54 +8,13 @@ import "core:log" import "vendor:sdl2" import lua "vendor:lua/5.4" -import "../plugin" - Mode :: enum { Normal, Insert, Visual, } -Window :: struct { - input_map: InputActions, - draw: plugin.WindowDrawProc, - free_user_data: plugin.WindowFreeProc, - get_buffer: plugin.WindowGetBufferProc, - - // TODO: create hook for when mode changes happen - - user_data: rawptr, -} -NewWindow :: struct { - input_map: InputActions, - lua_draw_proc: i32, -} -request_window_close :: proc(state: ^State) { - state.should_close_window = true; -} - -close_window_and_free :: proc(state: ^State) { - if state.window != nil { - if state.window.free_user_data != nil { - state.window.free_user_data(state.plugin_vtable, state.window.user_data); - } - - delete_input_actions(&state.window.input_map); - free(state.window); - - state.window = nil; - } - - if window, ok := &state.new_window.(NewWindow); ok { - delete_input_actions(&window.input_map); - state.new_window = nil - } - - state.current_input_map = &state.input_map.mode[.Normal]; -} - -LuaHookRef :: i32; EditorCommandList :: map[string][dynamic]EditorCommand; State :: struct { ctx: runtime.Context, @@ -82,10 +41,6 @@ State :: struct { log_buffer: FileBuffer, - window: ^Window, - new_window: Maybe(NewWindow), - should_close_window: bool, - input_map: InputMap, current_input_map: ^InputActions, @@ -95,13 +50,6 @@ State :: struct { active_panels: [128]Maybe(Panel), panel_catalog: [dynamic]PanelId, - - plugins: [dynamic]plugin.Interface, - new_plugins: [dynamic]plugin.NewInterface, - plugin_vtable: plugin.Plugin, - highlighters: map[string]plugin.OnColorBufferProc, - hooks: map[plugin.Hook][dynamic]plugin.OnHookProc, - lua_hooks: map[plugin.Hook][dynamic]LuaHookRef, } EditorCommand :: struct { @@ -120,26 +68,13 @@ EditorCommandArgument :: union #no_nil { i32 } -PanelId :: union #no_nil { - LuaPanelId, +PanelId :: union { LibPanelId, } -Panel :: union #no_nil { - LuaPanel, +Panel :: union { LibPanel, } - -LuaPanelId :: struct { - id: string, - name: string, -} -LuaPanel :: struct { - panel_id: LuaPanelId, - index: i32, - render_ref: i32 -} - // TODO LibPanelId :: struct {} LibPanel :: struct {} @@ -164,30 +99,8 @@ buffer_from_index :: proc(state: ^State, buffer_index: int) -> ^FileBuffer { return &state.buffers[buffer_index]; } -add_hook :: proc(state: ^State, hook: plugin.Hook, hook_proc: plugin.OnHookProc) { - if _, exists := state.hooks[hook]; !exists { - state.hooks[hook] = make([dynamic]plugin.OnHookProc); - } - - runtime.append(&state.hooks[hook], hook_proc); -} - -add_lua_hook :: proc(state: ^State, hook: plugin.Hook, hook_ref: LuaHookRef) { - if _, exists := state.lua_hooks[hook]; !exists { - state.lua_hooks[hook] = make([dynamic]LuaHookRef); - log.info("added lua hook", hook) - } - - runtime.append(&state.lua_hooks[hook], hook_ref); -} - -LuaEditorAction :: struct { - fn_ref: i32, - maybe_input_map: InputActions, -}; -PluginEditorAction :: proc "c" (plugin: plugin.Plugin); EditorAction :: proc(state: ^State); -InputGroup :: union {LuaEditorAction, PluginEditorAction, EditorAction, InputActions} +InputGroup :: union {EditorAction, InputActions} Action :: struct { action: InputGroup, description: string, @@ -196,8 +109,8 @@ InputMap :: struct { mode: map[Mode]InputActions, } InputActions :: struct { - key_actions: map[plugin.Key]Action, - ctrl_key_actions: map[plugin.Key]Action, + key_actions: map[Key]Action, + ctrl_key_actions: map[Key]Action, } new_input_map :: proc() -> InputMap { @@ -217,8 +130,8 @@ new_input_map :: proc() -> InputMap { new_input_actions :: proc() -> InputActions { input_actions := InputActions { - key_actions = make(map[plugin.Key]Action), - ctrl_key_actions = make(map[plugin.Key]Action), + key_actions = make(map[Key]Action), + ctrl_key_actions = make(map[Key]Action), } return input_actions; @@ -234,22 +147,7 @@ delete_input_actions :: proc(input_map: ^InputActions) { delete(input_map.ctrl_key_actions); } -// NOTE(pcleavelin): might be a bug in the compiler where it can't coerce -// `EditorAction` to `InputGroup` when given as a proc parameter, that is why there -// are two functions -register_plugin_key_action_single :: proc(input_map: ^InputActions, key: plugin.Key, action: PluginEditorAction, description: string = "") { - if ok := key in input_map.key_actions; ok { - // TODO: log that key is already registered - log.error("plugin key already registered with single action", key); - } - - input_map.key_actions[key] = Action { - action = action, - description = description, - }; -} - -register_key_action_single :: proc(input_map: ^InputActions, key: plugin.Key, action: EditorAction, description: string = "") { +register_key_action_single :: proc(input_map: ^InputActions, key: Key, action: EditorAction, description: string = "") { if ok := key in input_map.key_actions; ok { // TODO: log that key is already registered log.error("key already registered with single action", key); @@ -261,7 +159,7 @@ register_key_action_single :: proc(input_map: ^InputActions, key: plugin.Key, ac }; } -register_key_action_group :: proc(input_map: ^InputActions, key: plugin.Key, input_group: InputGroup, description: string = "") { +register_key_action_group :: proc(input_map: ^InputActions, key: Key, input_group: InputGroup, description: string = "") { if ok := key in input_map.key_actions; ok { // TODO: log that key is already registered fmt.eprintln("key already registered with single action", key); @@ -273,7 +171,7 @@ register_key_action_group :: proc(input_map: ^InputActions, key: plugin.Key, inp }; } -register_ctrl_key_action_single :: proc(input_map: ^InputActions, key: plugin.Key, action: EditorAction, description: string = "") { +register_ctrl_key_action_single :: proc(input_map: ^InputActions, key: Key, action: EditorAction, description: string = "") { if ok := key in input_map.key_actions; ok { // TODO: log that key is already registered log.error("key already registered with single action", key); @@ -285,7 +183,7 @@ register_ctrl_key_action_single :: proc(input_map: ^InputActions, key: plugin.Ke }; } -register_ctrl_key_action_group :: proc(input_map: ^InputActions, key: plugin.Key, input_group: InputGroup, description: string = "") { +register_ctrl_key_action_group :: proc(input_map: ^InputActions, key: Key, input_group: InputGroup, description: string = "") { if ok := key in input_map.key_actions; ok { // TODO: log that key is already registered log.error("key already registered with single action", key); @@ -297,7 +195,7 @@ register_ctrl_key_action_group :: proc(input_map: ^InputActions, key: plugin.Key }; } -register_key_action :: proc{register_plugin_key_action_single, register_key_action_single, register_key_action_group}; +register_key_action :: proc{register_key_action_single, register_key_action_group}; register_ctrl_key_action :: proc{register_ctrl_key_action_single, register_ctrl_key_action_group}; register_editor_command :: proc(command_list: ^EditorCommandList, command_group, name, description: string, action: EditorAction) { @@ -427,10 +325,245 @@ where intrinsics.type_is_struct(T) { return } -register_panel_lua :: proc(state: ^State, name: string, id: string) { - append(&state.panel_catalog, LuaPanelId { - id = id, - name = name, - }) +Key :: enum { + UNKNOWN = 0, + ENTER = 13, + ESCAPE = 27, + BACKSPACE = 8, + TAB = 9, + SPACE = 32, + EXCLAIM = 33, + QUOTEDBL = 34, + HASH = 35, + PERCENT = 37, + DOLLAR = 36, + AMPERSAND = 38, + QUOTE = 39, + LEFTPAREN = 40, + RIGHTPAREN = 41, + ASTERISK = 42, + PLUS = 43, + COMMA = 44, + MINUS = 45, + PERIOD = 46, + SLASH = 47, + NUM0 = 48, + NUM1 = 49, + NUM2 = 50, + NUM3 = 51, + NUM4 = 52, + NUM5 = 53, + NUM6 = 54, + NUM7 = 55, + NUM8 = 56, + NUM9 = 57, + COLON = 58, + SEMICOLON = 59, + LESS = 60, + EQUAL = 61, + GREATER = 62, + QUESTION = 63, + AT = 64, + LEFTBRACKET = 91, + BACKSLASH = 92, + RIGHTBRACKET = 93, + CARET = 94, + UNDERSCORE = 95, + BACKQUOTE = 96, + A = 97, + B = 98, + C = 99, + D = 100, + E = 101, + F = 102, + G = 103, + H = 104, + I = 105, + J = 106, + K = 107, + L = 108, + M = 109, + N = 110, + O = 111, + P = 112, + Q = 113, + R = 114, + S = 115, + T = 116, + U = 117, + V = 118, + W = 119, + X = 120, + Y = 121, + Z = 122, + CAPSLOCK = 1073741881, + F1 = 1073741882, + F2 = 1073741883, + F3 = 1073741884, + F4 = 1073741885, + F5 = 1073741886, + F6 = 1073741887, + F7 = 1073741888, + F8 = 1073741889, + F9 = 1073741890, + F10 = 1073741891, + F11 = 1073741892, + F12 = 1073741893, + PRINTSCREEN = 1073741894, + SCROLLLOCK = 1073741895, + PAUSE = 1073741896, + INSERT = 1073741897, + HOME = 1073741898, + PAGEUP = 1073741899, + DELETE = 127, + END = 1073741901, + PAGEDOWN = 1073741902, + RIGHT = 1073741903, + LEFT = 1073741904, + DOWN = 1073741905, + UP = 1073741906, + NUMLOCKCLEAR = 1073741907, + KP_DIVIDE = 1073741908, + KP_MULTIPLY = 1073741909, + KP_MINUS = 1073741910, + KP_PLUS = 1073741911, + KP_ENTER = 1073741912, + KP_1 = 1073741913, + KP_2 = 1073741914, + KP_3 = 1073741915, + KP_4 = 1073741916, + KP_5 = 1073741917, + KP_6 = 1073741918, + KP_7 = 1073741919, + KP_8 = 1073741920, + KP_9 = 1073741921, + KP_0 = 1073741922, + KP_PERIOD = 1073741923, + APPLICATION = 1073741925, + POWER = 1073741926, + KP_EQUALS = 1073741927, + F13 = 1073741928, + F14 = 1073741929, + F15 = 1073741930, + F16 = 1073741931, + F17 = 1073741932, + F18 = 1073741933, + F19 = 1073741934, + F20 = 1073741935, + F21 = 1073741936, + F22 = 1073741937, + F23 = 1073741938, + F24 = 1073741939, + EXECUTE = 1073741940, + HELP = 1073741941, + MENU = 1073741942, + SELECT = 1073741943, + STOP = 1073741944, + AGAIN = 1073741945, + UNDO = 1073741946, + CUT = 1073741947, + COPY = 1073741948, + PASTE = 1073741949, + FIND = 1073741950, + MUTE = 1073741951, + VOLUMEUP = 1073741952, + VOLUMEDOWN = 1073741953, + KP_COMMA = 1073741957, + KP_EQUALSAS400 = 1073741958, + ALTERASE = 1073741977, + SYSREQ = 1073741978, + CANCEL = 1073741979, + CLEAR = 1073741980, + PRIOR = 1073741981, + RETURN2 = 1073741982, + SEPARATOR = 1073741983, + OUT = 1073741984, + OPER = 1073741985, + CLEARAGAIN = 1073741986, + CRSEL = 1073741987, + EXSEL = 1073741988, + KP_00 = 1073742000, + KP_000 = 1073742001, + THOUSANDSSEPARATOR = 1073742002, + DECIMALSEPARATOR = 1073742003, + CURRENCYUNIT = 1073742004, + CURRENCYSUBUNIT = 1073742005, + KP_LEFTPAREN = 1073742006, + KP_RIGHTPAREN = 1073742007, + KP_LEFTBRACE = 1073742008, + KP_RIGHTBRACE = 1073742009, + KP_TAB = 1073742010, + KP_BACKSPACE = 1073742011, + KP_A = 1073742012, + KP_B = 1073742013, + KP_C = 1073742014, + KP_D = 1073742015, + KP_E = 1073742016, + KP_F = 1073742017, + KP_XOR = 1073742018, + KP_POWER = 1073742019, + KP_PERCENT = 1073742020, + KP_LESS = 1073742021, + KP_GREATER = 1073742022, + KP_AMPERSAND = 1073742023, + KP_DBLAMPERSAND = 1073742024, + KP_VERTICALBAR = 1073742025, + KP_DBLVERTICALBAR = 1073742026, + KP_COLON = 1073742027, + KP_HASH = 1073742028, + KP_SPACE = 1073742029, + KP_AT = 1073742030, + KP_EXCLAM = 1073742031, + KP_MEMSTORE = 1073742032, + KP_MEMRECALL = 1073742033, + KP_MEMCLEAR = 1073742034, + KP_MEMADD = 1073742035, + KP_MEMSUBTRACT = 1073742036, + KP_MEMMULTIPLY = 1073742037, + KP_MEMDIVIDE = 1073742038, + KP_PLUSMINUS = 1073742039, + KP_CLEAR = 1073742040, + KP_CLEARENTRY = 1073742041, + KP_BINARY = 1073742042, + KP_OCTAL = 1073742043, + KP_DECIMAL = 1073742044, + KP_HEXADECIMAL = 1073742045, + LCTRL = 1073742048, + LSHIFT = 1073742049, + LALT = 1073742050, + LGUI = 1073742051, + RCTRL = 1073742052, + RSHIFT = 1073742053, + RALT = 1073742054, + RGUI = 1073742055, + MODE = 1073742081, + AUDIONEXT = 1073742082, + AUDIOPREV = 1073742083, + AUDIOSTOP = 1073742084, + AUDIOPLAY = 1073742085, + AUDIOMUTE = 1073742086, + MEDIASELECT = 1073742087, + WWW = 1073742088, + MAIL = 1073742089, + CALCULATOR = 1073742090, + COMPUTER = 1073742091, + AC_SEARCH = 1073742092, + AC_HOME = 1073742093, + AC_BACK = 1073742094, + AC_FORWARD = 1073742095, + AC_STOP = 1073742096, + AC_REFRESH = 1073742097, + AC_BOOKMARKS = 1073742098, + BRIGHTNESSDOWN = 1073742099, + BRIGHTNESSUP = 1073742100, + DISPLAYSWITCH = 1073742101, + KBDILLUMTOGGLE = 1073742102, + KBDILLUMDOWN = 1073742103, + KBDILLUMUP = 1073742104, + EJECT = 1073742105, + SLEEP = 1073742106, + APP1 = 1073742107, + APP2 = 1073742108, + AUDIOREWIND = 1073742109, + AUDIOFASTFORWARD = 1073742110, } - diff --git a/src/core/file_buffer.odin b/src/core/file_buffer.odin index 17f0562..e6d3a49 100644 --- a/src/core/file_buffer.odin +++ b/src/core/file_buffer.odin @@ -11,7 +11,6 @@ import "base:runtime" import "core:strings" import "../theme" -import "../plugin" ScrollDir :: enum { Up, @@ -752,32 +751,6 @@ next_buffer :: proc(state: ^State, prev_buffer: ^int) -> int { return index; } -into_buffer_info :: proc(state: ^State, buffer: ^FileBuffer) -> plugin.BufferInfo { - return plugin.BufferInfo { - buffer = buffer, - input = plugin.BufferInput { - bytes = raw_data(buffer.input_buffer), - length = len(buffer.input_buffer), - }, - cursor = plugin.Cursor { - col = buffer.cursor.col, - line = buffer.cursor.line, - index = plugin.BufferIndex { - slice_index = buffer.cursor.index.slice_index, - content_index = buffer.cursor.index.content_index, - } - }, - file_path = strings.clone_to_cstring(buffer.file_path, context.temp_allocator), - glyph_buffer_width = buffer.glyph_buffer_width, - glyph_buffer_height = buffer.glyph_buffer_height, - top_line = buffer.top_line, - }; -} -into_buffer_info_from_index :: proc(state: ^State, buffer_index: int) -> plugin.BufferInfo { - buffer := buffer_from_index(state, buffer_index); - return into_buffer_info(state, buffer); -} - free_file_buffer :: proc(buffer: ^FileBuffer) { delete(buffer.original_content); delete(buffer.added_content); @@ -876,9 +849,8 @@ update_glyph_buffer :: proc(buffer: ^FileBuffer) { draw_file_buffer :: proc(state: ^State, buffer: ^FileBuffer, x: int, y: int, show_line_numbers: bool = true) { update_glyph_buffer(buffer); - if highlighter, exists := state.highlighters[buffer.extension]; exists { - highlighter(state.plugin_vtable, buffer); - } + + // TODO: syntax highlighting padding := 0; if show_line_numbers { diff --git a/src/lua/lua.odin b/src/lua/lua.odin deleted file mode 100644 index ce93bd3..0000000 --- a/src/lua/lua.odin +++ /dev/null @@ -1,1244 +0,0 @@ -package lua - -import "core:os" -import "core:fmt" -import "core:strings" -import "core:log" -import "core:path/filepath" - -import core "../core" -import plugin "../plugin" -import ui "../ui" - -import lua "vendor:lua/5.4" - -state: ^core.State = nil - -new_state :: proc(_state: ^core.State) { - state = _state - - state.L = lua.L_newstate(); - lua.L_openlibs(state.L); - - bbb: [^]lua.L_Reg; - editor_lib := [?]lua.L_Reg { - lua.L_Reg { - "quit", - proc "c" (L: ^lua.State) -> i32 { - context = state.ctx; - - - state.should_close = true; - return i32(lua.OK); - } - }, - lua.L_Reg { - "log", - proc "c" (L: ^lua.State) -> i32 { - context = state.ctx; - - text := string(lua.L_checkstring(L, 1)); - log.info("[LUA]:", text); - - return i32(lua.OK); - } - }, - lua.L_Reg { - "register_hook", - proc "c" (L: ^lua.State) -> i32 { - context = state.ctx; - - hook := lua.L_checkinteger(L, 1); - - lua.L_checktype(L, 2, i32(lua.TFUNCTION)); - lua.pushvalue(L, 2); - fn_ref := lua.L_ref(L, i32(lua.REGISTRYINDEX)); - - core.add_lua_hook(state, plugin.Hook(hook), fn_ref); - - return i32(lua.OK); - } - }, - lua.L_Reg { - "register_key_group", - register_key_group, - }, - lua.L_Reg { - "register_panel", - proc "c" (L: ^lua.State) -> i32 { - context = state.ctx; - - panel_name := strings.clone(string(lua.L_checkstring(L, 1))); - panel_identifier := strings.clone(string(lua.L_checkstring(L, 2))); - core.register_panel_lua(state, panel_name, panel_identifier) - - return i32(lua.OK) - } - }, - lua.L_Reg { - "spawn_floating_window", - proc "c" (L: ^lua.State) -> i32 { - context = state.ctx; - - core.close_window_and_free(state); - - window_input_map := core.new_input_actions(); - lua.L_checktype(L, 1, i32(lua.TTABLE)); - table_to_action(L, 1, &window_input_map); - - lua.L_checktype(L, 2, i32(lua.TFUNCTION)); - lua.pushvalue(L, 2); - fn_ref := lua.L_ref(L, i32(lua.REGISTRYINDEX)); - - state.new_window = core.NewWindow { - input_map = window_input_map, - lua_draw_proc = fn_ref - } - state.current_input_map = &(&state.new_window.?).input_map - - return i32(lua.OK); - } - }, - lua.L_Reg { - "request_window_close", - proc "c" (L: ^lua.State) -> i32 { - context = state.ctx; - - core.request_window_close(state); - - return i32(lua.OK); - } - }, - lua.L_Reg { - "get_current_buffer_index", - proc "c" (L: ^lua.State) -> i32 { - context = state.ctx; - - lua.pushinteger(L, lua.Integer(state.current_buffer)); - - return 1; - } - }, - lua.L_Reg { - "set_current_buffer_from_index", - proc "c" (L: ^lua.State) -> i32 { - context = state.ctx; - - buffer_index := int(lua.L_checkinteger(L, 1)); - if buffer_index != -2 && (buffer_index < 0 || buffer_index >= len(state.buffers)) { - return i32(lua.ERRRUN); - } else { - state.current_buffer = buffer_index; - } - - return i32(lua.OK); - } - }, - lua.L_Reg { - "buffer_info_from_index", - proc "c" (L: ^lua.State) -> i32 { - context = state.ctx; - - buffer_index := int(lua.L_checkinteger(L, 1)); - if buffer_index < 0 || buffer_index >= len(state.buffers) { - lua.pushnil(L); - } else { - push_lua_buffer_info :: proc(L: ^lua.State, buffer: ^core.FileBuffer) { - lua.newtable(L); - { - lua.pushlightuserdata(L, buffer); - lua.setfield(L, -2, "buffer"); - - lua.newtable(L); - { - lua.pushinteger(L, lua.Integer(buffer.cursor.col)); - lua.setfield(L, -2, "col"); - - lua.pushinteger(L, lua.Integer(buffer.cursor.line)); - lua.setfield(L, -2, "line"); - } - lua.setfield(L, -2, "cursor"); - - lua.pushstring(L, strings.clone_to_cstring(buffer.file_path, context.temp_allocator)); - lua.setfield(L, -2, "full_file_path"); - - relative_file_path, _ := filepath.rel(state.directory, buffer.file_path, context.temp_allocator) - lua.pushstring(L, strings.clone_to_cstring(relative_file_path, context.temp_allocator)); - lua.setfield(L, -2, "file_path"); - } - } - - push_lua_buffer_info(L, core.buffer_from_index(state, buffer_index)); - } - - return 1; - } - }, - lua.L_Reg { - "query_command_group", - proc "c" (L: ^lua.State) -> i32 { - context = state.ctx; - - group := lua.L_checkstring(L, 1); - cmds := core.query_editor_commands_by_group(&state.commands, string(group), context.temp_allocator); - - lua.newtable(L); - { - for cmd, i in cmds { - lua.newtable(L); - { - lua.pushstring(L, strings.clone_to_cstring(cmd.name, context.temp_allocator)); - lua.setfield(L, -2, "name"); - - lua.pushstring(L, strings.clone_to_cstring(cmd.description, context.temp_allocator)); - lua.setfield(L, -2, "description"); - } - lua.rawseti(L, -2, lua.Integer(i+1)); - } - } - - return 1; - } - }, - lua.L_Reg { - "run_command", - proc "c" (L: ^lua.State) -> i32 { - context = state.ctx; - - group := lua.L_checkstring(L, 1); - name := lua.L_checkstring(L, 2); - - num_args := lua.gettop(state.L) - for i in 0..<(num_args-2) { - if lua.isstring(state.L, 3) { - value := lua.L_checkstring(state.L, 3) - lua.pop(L, 3); - - core.push_command_arg(state, string(value)) - } else if lua.isinteger(state.L, 3) { - value := lua.L_checkinteger(state.L, 3) - lua.pop(L, 3); - - core.push_command_arg(state, i32(value)) - } else { - log.error("expected string or integer for command arguments") - return 0; - } - } - - core.run_command(state, string(group), string(name)); - - return 1; - } - } - }; - bbb = raw_data(editor_lib[:]); - - get_lua_semantic_size :: proc(L: ^lua.State, index: i32) -> ui.SemanticSize { - if lua.istable(L, index) { - lua.rawgeti(L, index, 1); - semantic_kind := ui.SemanticSizeKind(lua.tointeger(L, -1)); - lua.pop(L, 1); - - lua.rawgeti(L, index, 2); - semantic_value := int(lua.tointeger(L, -1)); - lua.pop(L, 1); - - return {semantic_kind, semantic_value}; - } else { - semantic_kind := ui.SemanticSizeKind(lua.L_checkinteger(L, index)); - return {semantic_kind, 0}; - } - } - - get_size_kind :: proc(L: ^lua.State, index: i32) -> ui.UI_Size_Kind { - lua.rawgeti(L, index, 1); - k := lua.tointeger(L, -1); - lua.pop(L, 1); - - lua.rawgeti(L, index, 2); - v := lua.tointeger(L, -1); - lua.pop(L, 1); - - log.info("k", k, "v", v) - - switch k { - case 1: return ui.Exact(v) - case 2: return ui.Fit{} - case 3: return ui.Grow{} - } - - return nil - } - - push_lua_semantic_size_table :: proc(L: ^lua.State, size: ui.SemanticSize) { - lua.newtable(L); - { - lua.pushinteger(L, lua.Integer(i32(size.kind))); - lua.rawseti(L, -2, 1); - - lua.pushinteger(L, lua.Integer(size.value)); - lua.rawseti(L, -2, 2); - } - } - - push_lua_box_interaction :: proc(L: ^lua.State, interaction: ui.Interaction) { - lua.newtable(L); - { - lua.pushboolean(L, b32(interaction.clicked)); - lua.setfield(L, -2, "clicked"); - - lua.pushboolean(L, b32(interaction.hovering)); - lua.setfield(L, -2, "hovering"); - - lua.pushboolean(L, b32(interaction.dragging)); - lua.setfield(L, -2, "dragging"); - - lua.newtable(L); - { - lua.pushinteger(L, lua.Integer(interaction.box_pos.x)); - lua.setfield(L, -2, "x"); - - lua.pushinteger(L, lua.Integer(interaction.box_pos.y)); - lua.setfield(L, -2, "y"); - } - lua.setfield(L, -2, "box_pos"); - - lua.newtable(L); - { - lua.pushinteger(L, lua.Integer(interaction.box_size.x)); - lua.setfield(L, -2, "x"); - - lua.pushinteger(L, lua.Integer(interaction.box_size.y)); - lua.setfield(L, -2, "y"); - } - lua.setfield(L, -2, "box_size"); - } - } - - ui_lib := [?]lua.L_Reg { - lua.L_Reg { - "get_mouse_pos", - proc "c" (L: ^lua.State) -> i32 { - context = state.ctx; - - lua.L_checktype(L, 1, i32(lua.TLIGHTUSERDATA)); - lua.pushvalue(L, 1); - ui_ctx := transmute(^ui.Context)lua.touserdata(L, -1); - if ui_ctx == nil { return i32(lua.ERRRUN); } - - lua.pushinteger(L, lua.Integer(ui_ctx.mouse_x)); - lua.pushinteger(L, lua.Integer(ui_ctx.mouse_y)); - - return 2; - } - }, - lua.L_Reg { - "Exact", - proc "c" (L: ^lua.State) -> i32 { - context = state.ctx; - - value := lua.L_checknumber(L, 1); - push_lua_semantic_size_table(L, { ui.SemanticSizeKind.Exact, int(value) }); - - return 1; - } - }, - lua.L_Reg { - "PercentOfParent", - proc "c" (L: ^lua.State) -> i32 { - context = state.ctx; - - value := lua.L_checknumber(L, 1); - push_lua_semantic_size_table(L, { ui.SemanticSizeKind.PercentOfParent, int(value) }); - - return 1; - } - }, - lua.L_Reg { - "push_parent", - proc "c" (L: ^lua.State) -> i32 { - context = state.ctx; - - lua.L_checktype(L, 1, i32(lua.TLIGHTUSERDATA)); - lua.pushvalue(L, 1); - ui_ctx := transmute(^ui.Context)lua.touserdata(L, -1); - if ui_ctx == nil { return i32(lua.ERRRUN); } - - lua.L_checktype(L, 2, i32(lua.TLIGHTUSERDATA)); - lua.pushvalue(L, 2); - box := transmute(^ui.Box)lua.touserdata(L, -1); - if box == nil { return i32(lua.ERRRUN); } - - ui.push_parent(ui_ctx, box); - return i32(lua.OK); - } - }, - lua.L_Reg { - "pop_parent", - proc "c" (L: ^lua.State) -> i32 { - context = state.ctx; - - lua.L_checktype(L, 1, i32(lua.TLIGHTUSERDATA)); - lua.pushvalue(L, 1); - ui_ctx := transmute(^ui.Context)lua.touserdata(L, -1); - if ui_ctx == nil { return i32(lua.ERRRUN); } - - ui.pop_parent(ui_ctx); - return i32(lua.OK); - } - }, - lua.L_Reg { - "push_floating", - proc "c" (L: ^lua.State) -> i32 { - context = state.ctx; - - lua.L_checktype(L, 1, i32(lua.TLIGHTUSERDATA)); - lua.pushvalue(L, 1); - ui_ctx := transmute(^ui.Context)lua.touserdata(L, -1); - if ui_ctx != nil { - label := lua.L_checkstring(L, 2); - x := int(lua.L_checkinteger(L, 3)); - y := int(lua.L_checkinteger(L, 4)); - - box, interaction := ui.push_floating(ui_ctx, strings.clone(string(label), context.temp_allocator), {x,y}); - lua.pushlightuserdata(L, box); - push_lua_box_interaction(L, interaction); - return 2; - } - - return i32(lua.ERRRUN); - } - }, - lua.L_Reg { - "push_box", - proc "c" (L: ^lua.State) -> i32 { - context = state.ctx; - - lua.L_checktype(L, 1, i32(lua.TLIGHTUSERDATA)); - lua.pushvalue(L, 1); - ui_ctx := transmute(^ui.Context)lua.touserdata(L, -1); - if ui_ctx != nil { - label := lua.L_checkstring(L, 2); - flags, err := ui_flags(L, 3); - axis := ui.Axis(lua.L_checkinteger(L, 4)); - - semantic_width := get_lua_semantic_size(L, 5); - semantic_height := get_lua_semantic_size(L, 6); - - box, interaction := ui.push_box(ui_ctx, strings.clone(string(label), context.temp_allocator), flags, axis, { semantic_width, semantic_height }); - - lua.pushlightuserdata(L, box); - push_lua_box_interaction(L, interaction) - return 2; - } - - return i32(lua.ERRRUN); - } - }, - lua.L_Reg { - "_box_interaction", - proc "c" (L: ^lua.State) -> i32 { - context = state.ctx; - - lua.L_checktype(L, 1, i32(lua.TLIGHTUSERDATA)); - lua.pushvalue(L, 1); - ui_ctx := transmute(^ui.Context)lua.touserdata(L, -1); - if ui_ctx == nil { return i32(lua.ERRRUN); } - - lua.L_checktype(L, 2, i32(lua.TLIGHTUSERDATA)); - lua.pushvalue(L, 2); - box := transmute(^ui.Box)lua.touserdata(L, -1); - if box == nil { return i32(lua.ERRRUN); } - - interaction := ui.test_box(ui_ctx, box); - push_lua_box_interaction(L, interaction) - return 1; - } - }, - lua.L_Reg { - "push_box", - proc "c" (L: ^lua.State) -> i32 { - context = state.ctx; - - lua.L_checktype(L, 1, i32(lua.TLIGHTUSERDATA)); - lua.pushvalue(L, 1); - ui_ctx := transmute(^ui.Context)lua.touserdata(L, -1); - if ui_ctx != nil { - label := lua.L_checkstring(L, 2); - flags, err := ui_flags(L, 3); - axis := ui.Axis(lua.L_checkinteger(L, 4)); - - semantic_width := get_lua_semantic_size(L, 5); - semantic_height := get_lua_semantic_size(L, 6); - - box, interaction := ui.push_box(ui_ctx, strings.clone(string(label), context.temp_allocator), flags, axis, { semantic_width, semantic_height }); - lua.pushlightuserdata(L, box); - push_lua_box_interaction(L, interaction) - return 2; - } - - return i32(lua.ERRRUN); - } - }, - lua.L_Reg { - "push_rect", - proc "c" (L: ^lua.State) -> i32 { - context = state.ctx; - - lua.L_checktype(L, 1, i32(lua.TLIGHTUSERDATA)); - lua.pushvalue(L, 1); - ui_ctx := transmute(^ui.Context)lua.touserdata(L, -1); - if ui_ctx != nil { - label := lua.L_checkstring(L, 2); - background := bool(lua.toboolean(L, 3)); - border := bool(lua.toboolean(L, 4)); - axis := ui.Axis(lua.L_checkinteger(L, 5)); - - semantic_width := get_lua_semantic_size(L, 6); - semantic_height := get_lua_semantic_size(L, 7); - - box, interaction := ui.push_rect(ui_ctx, strings.clone(string(label), context.temp_allocator), background, border, axis, { semantic_width, semantic_height }); - lua.pushlightuserdata(L, box); - push_lua_box_interaction(L, interaction) - return 2; - } - - return i32(lua.ERRRUN); - } - }, - lua.L_Reg { - "spacer", - proc "c" (L: ^lua.State) -> i32 { - context = state.ctx; - - lua.L_checktype(L, 1, i32(lua.TLIGHTUSERDATA)); - lua.pushvalue(L, 1); - ui_ctx := transmute(^ui.Context)lua.touserdata(L, -1); - if ui_ctx != nil { - label := lua.L_checkstring(L, 2); - - interaction := ui.spacer(ui_ctx, strings.clone(string(label), context.temp_allocator), semantic_size = {{.Fill, 0}, {.Fill, 0}}); - - push_lua_box_interaction(L, interaction) - - return 1; - } - - return i32(lua.ERRRUN); - } - }, - lua.L_Reg { - "label", - proc "c" (L: ^lua.State) -> i32 { - context = state.ctx; - - lua.L_checktype(L, 1, i32(lua.TLIGHTUSERDATA)); - lua.pushvalue(L, 1); - ui_ctx := transmute(^ui.Context)lua.touserdata(L, -1); - if ui_ctx != nil { - label := lua.L_checkstring(L, 2); - - interaction := ui.label(ui_ctx, strings.clone(string(label), context.temp_allocator)); - push_lua_box_interaction(L, interaction) - - return 1; - } - - return i32(lua.ERRRUN); - } - }, - lua.L_Reg { - "button", - proc "c" (L: ^lua.State) -> i32 { - context = state.ctx; - - lua.L_checktype(L, 1, i32(lua.TLIGHTUSERDATA)); - lua.pushvalue(L, 1); - ui_ctx := transmute(^ui.Context)lua.touserdata(L, -1); - if ui_ctx != nil { - label := lua.L_checkstring(L, 2); - - interaction := ui.button(ui_ctx, strings.clone(string(label), context.temp_allocator)); - push_lua_box_interaction(L, interaction) - - return 1; - } - - return i32(lua.ERRRUN); - } - }, - lua.L_Reg { - "advanced_button", - proc "c" (L: ^lua.State) -> i32 { - context = state.ctx; - - lua.L_checktype(L, 1, i32(lua.TLIGHTUSERDATA)); - lua.pushvalue(L, 1); - ui_ctx := transmute(^ui.Context)lua.touserdata(L, -1); - - if ui_ctx != nil { - label := lua.L_checkstring(L, 2); - flags, err := ui_flags(L, 3); - - semantic_width := get_lua_semantic_size(L, 4); - semantic_height := get_lua_semantic_size(L, 5); - - interaction := ui.advanced_button(ui_ctx, strings.clone(string(label), context.temp_allocator), flags, { semantic_width, semantic_height }); - push_lua_box_interaction(L, interaction) - - return 1; - } - - return i32(lua.ERRRUN); - } - }, - lua.L_Reg { - "buffer", - proc "c" (L: ^lua.State) -> i32 { - context = state.ctx; - - lua.L_checktype(L, 1, i32(lua.TLIGHTUSERDATA)); - lua.pushvalue(L, 1); - ui_ctx := transmute(^ui.Context)lua.touserdata(L, -1); - - if ui_ctx != nil { - buffer_index := int(lua.L_checkinteger(L, 2)); - - if buffer_index != -2 && (buffer_index < 0 || buffer_index >= len(state.buffers)) { - return i32(lua.ERRRUN); - } - - ui_file_buffer(ui_ctx, core.buffer_from_index(state, buffer_index)); - - return i32(lua.OK); - } - - return i32(lua.ERRRUN); - } - }, - lua.L_Reg { - "log_buffer", - proc "c" (L: ^lua.State) -> i32 { - context = state.ctx; - - lua.L_checktype(L, 1, i32(lua.TLIGHTUSERDATA)); - lua.pushvalue(L, 1); - ui_ctx := transmute(^ui.Context)lua.touserdata(L, -1); - - if ui_ctx != nil { - ui_file_buffer(ui_ctx, &state.log_buffer); - - return i32(lua.OK); - } - - return i32(lua.ERRRUN); - } - } - }; - - ui_lib_new := [?]lua.L_Reg { - lua.L_Reg { - "Exact", - proc "c" (L: ^lua.State) -> i32 { - context = state.ctx; - - value := lua.L_checknumber(L, 1); - lua.newtable(L); - { - // Size Kind 1 = Exact - lua.pushinteger(L, lua.Integer(1)); - lua.rawseti(L, -2, 1); - - lua.pushinteger(L, lua.Integer(value)); - lua.rawseti(L, -2, 2); - } - - return 1; - } - }, - lua.L_Reg { - "close_element", - proc "c" (L: ^lua.State) -> i32 { - context = state.ctx; - - lua.L_checktype(L, 1, i32(lua.TLIGHTUSERDATA)) - lua.pushvalue(L, 1) - ui_state := transmute(^ui.State)lua.touserdata(L, -1) - if ui_state == nil { return i32(lua.ERRRUN); } - - ui.close_element(ui_state); - return i32(lua.OK); - } - }, - lua.L_Reg { - "open_element", - proc "c" (L: ^lua.State) -> i32 { - context = state.ctx - - lua.L_checktype(L, 1, i32(lua.TLIGHTUSERDATA)) - lua.pushvalue(L, 1) - ui_state := transmute(^ui.State)lua.touserdata(L, -1) - - if ui_state != nil { - label := lua.L_checkstring(L, 2) - - if !lua.istable(state.L, 3) { - log.error("expected table for element layout"); - - // TODO: maybe call `ui.open_element` anyway to not break everything - - return i32(lua.ERRRUN); - } - - dir: ui.UI_Direction - kind: [2]ui.UI_Size_Kind - - lua.getfield(state.L, 3, "kind"); - top := lua.gettop(state.L) - - if (lua.isnil(state.L, top)) { - lua.pop(state.L, top) - } else if lua.istable(state.L, top) { - kind.x = get_size_kind(state.L, top) - kind.y = get_size_kind(state.L, top) - } else { - log.error("expected table for 'kind' field in element layout") - } - lua.pop(state.L, 1) - - lua.getfield(state.L, 3, "dir"); - if (lua.isnil(state.L, -1)) { - lua.pop(state.L, 1) - } else if lua.isinteger(state.L, -1) { - dir = ui.UI_Direction(lua.tointeger(state.L, -1)) - lua.pop(state.L, 1) - } else { - log.error("expected integer for 'dir' field in element layout") - return i32(lua.ERRRUN); - } - lua.pop(state.L, 1) - - ui.open_element(ui_state, strings.clone(string(label), context.temp_allocator), ui.UI_Layout { dir=dir, kind=kind }) - - return i32(lua.OK) - } - - return i32(lua.ERRRUN) - } - }, - lua.L_Reg { - "buffer", - proc "c" (L: ^lua.State) -> i32 { - context = state.ctx; - - lua.L_checktype(L, 1, i32(lua.TLIGHTUSERDATA)); - lua.pushvalue(L, 1); - ui_ctx := transmute(^ui.Context)lua.touserdata(L, -1); - - if ui_ctx != nil { - buffer_index := int(lua.L_checkinteger(L, 2)); - - if buffer_index != -2 && (buffer_index < 0 || buffer_index >= len(state.buffers)) { - return i32(lua.ERRRUN); - } - - ui_file_buffer(ui_ctx, core.buffer_from_index(state, buffer_index)); - - return i32(lua.OK); - } - - return i32(lua.ERRRUN); - } - }, - lua.L_Reg { - "log_buffer", - proc "c" (L: ^lua.State) -> i32 { - context = state.ctx; - - lua.L_checktype(L, 1, i32(lua.TLIGHTUSERDATA)); - lua.pushvalue(L, 1); - ui_ctx := transmute(^ui.Context)lua.touserdata(L, -1); - - if ui_ctx != nil { - ui_file_buffer(ui_ctx, &state.log_buffer); - - return i32(lua.OK); - } - - return i32(lua.ERRRUN); - } - } - }; - - // TODO: generate this from the plugin.Key enum - lua.newtable(state.L); - { - lua.newtable(state.L); - lua.pushinteger(state.L, lua.Integer(plugin.Key.B)); - lua.setfield(state.L, -2, "B"); - - lua.pushinteger(state.L, lua.Integer(plugin.Key.F)); - lua.setfield(state.L, -2, "F"); - - lua.pushinteger(state.L, lua.Integer(plugin.Key.T)); - lua.setfield(state.L, -2, "T"); - - lua.pushinteger(state.L, lua.Integer(plugin.Key.Y)); - lua.setfield(state.L, -2, "Y"); - - lua.pushinteger(state.L, lua.Integer(plugin.Key.P)); - lua.setfield(state.L, -2, "P"); - - lua.pushinteger(state.L, lua.Integer(plugin.Key.M)); - lua.setfield(state.L, -2, "M"); - - lua.pushinteger(state.L, lua.Integer(plugin.Key.K)); - lua.setfield(state.L, -2, "K"); - - lua.pushinteger(state.L, lua.Integer(plugin.Key.J)); - lua.setfield(state.L, -2, "J"); - - lua.pushinteger(state.L, lua.Integer(plugin.Key.Q)); - lua.setfield(state.L, -2, "Q"); - - lua.pushinteger(state.L, lua.Integer(plugin.Key.BACKQUOTE)); - lua.setfield(state.L, -2, "Backtick"); - - lua.pushinteger(state.L, lua.Integer(plugin.Key.ESCAPE)); - lua.setfield(state.L, -2, "Escape"); - - lua.pushinteger(state.L, lua.Integer(plugin.Key.ENTER)); - lua.setfield(state.L, -2, "Enter"); - - lua.pushinteger(state.L, lua.Integer(plugin.Key.SPACE)); - lua.setfield(state.L, -2, "Space"); - } - lua.setfield(state.L, -2, "Key"); - - { - lua.newtable(state.L); - lua.pushinteger(state.L, lua.Integer(plugin.Hook.BufferInput)); - lua.setfield(state.L, -2, "OnBufferInput"); - lua.pushinteger(state.L, lua.Integer(plugin.Hook.Draw)); - lua.setfield(state.L, -2, "OnDraw"); - } - lua.setfield(state.L, -2, "Hook"); - - lua.L_setfuncs(state.L, bbb, 0); - lua.setglobal(state.L, "Editor"); - - lua.newtable(state.L); - { - lua.pushinteger(state.L, lua.Integer(ui.Axis.Horizontal)); - lua.setfield(state.L, -2, "Horizontal"); - lua.pushinteger(state.L, lua.Integer(ui.Axis.Vertical)); - lua.setfield(state.L, -2, "Vertical"); - push_lua_semantic_size_table(state.L, { ui.SemanticSizeKind.Fill, 0 }); - lua.setfield(state.L, -2, "Fill"); - push_lua_semantic_size_table(state.L, { ui.SemanticSizeKind.ChildrenSum, 0 }); - lua.setfield(state.L, -2, "ChildrenSum"); - push_lua_semantic_size_table(state.L, { ui.SemanticSizeKind.FitText, 0 }); - lua.setfield(state.L, -2, "FitText"); - - lua.L_setfuncs(state.L, raw_data(&ui_lib), 0); - lua.setglobal(state.L, "UI"); - } - - lua.newtable(state.L); - { - lua.pushinteger(state.L, lua.Integer(ui.UI_Direction.LeftToRight)); - lua.setfield(state.L, -2, "LeftToRight"); - // push_lua_semantic_size_table(state.L, { ui.SemanticSizeKind.ChildrenSum, 0 }); - // lua.setfield(state.L, -2, "ChildrenSum"); - lua.newtable(state.L); - { - // Size Kind 1 = Exact - lua.pushinteger(state.L, lua.Integer(2)); - lua.rawseti(state.L, -2, 1); - - lua.pushinteger(state.L, lua.Integer(0)); - lua.rawseti(state.L, -2, 2); - } - lua.setfield(state.L, -2, "Fit"); - - lua.L_setfuncs(state.L, raw_data(&ui_lib_new), 0); - lua.setglobal(state.L, "UI_New"); - } -} - -close :: proc(L: ^lua.State) { - lua.close(L) -} - - -@(private) -register_key_group ::proc "c" (L: ^lua.State) -> i32 { - context = state.ctx; - - lua.L_checktype(L, 1, i32(lua.TTABLE)); - table_to_action(L, 1, state.current_input_map); - - return i32(lua.OK); -} - -@(private) -table_to_action :: proc(L: ^lua.State, index: i32, input_map: ^core.InputActions) { - lua.len(L, index); - key_group_len := lua.tointeger(L, -1); - lua.pop(L, 1); - - for i in 1..=key_group_len { - lua.rawgeti(L, index, i); - defer lua.pop(L, 1); - - lua.rawgeti(L, -1, 1); - key:= plugin.Key(lua.tointeger(L, -1)); - lua.pop(L, 1); - - lua.rawgeti(L, -1, 2); - desc := strings.clone(string(lua.tostring(L, -1))); - lua.pop(L, 1); - - switch lua.rawgeti(L, -1, 3) { - case i32(lua.TTABLE): - if action, exists := input_map.key_actions[key]; exists { - switch value in action.action { - case core.LuaEditorAction: - log.warn("Plugin attempted to register input group on existing key action (added from Lua)"); - case core.PluginEditorAction: - log.warn("Plugin attempted to register input group on existing key action (added from Plugin)"); - case core.EditorAction: - log.warn("Plugin attempted to register input group on existing key action"); - case core.InputActions: - input_map := &(&input_map.key_actions[key]).action.(core.InputActions); - table_to_action(L, lua.gettop(L), input_map); - } - } else { - core.register_key_action(input_map, key, core.new_input_actions(), desc); - table_to_action(L, lua.gettop(L), &((&input_map.key_actions[key]).action.(core.InputActions))); - } - lua.pop(L, 1); - - case i32(lua.TFUNCTION): - fn_ref := lua.L_ref(L, i32(lua.REGISTRYINDEX)); - - if lua.rawgeti(L, -1, 4) == i32(lua.TTABLE) { - maybe_input_map := core.new_input_actions(); - table_to_action(L, lua.gettop(L), &maybe_input_map); - - core.register_key_action_group(input_map, key, core.LuaEditorAction { fn_ref, maybe_input_map }, desc); - } else { - core.register_key_action_group(input_map, key, core.LuaEditorAction { fn_ref, core.InputActions {} }, desc); - } - - case: - lua.pop(L, 1); - } - } -} - -load_plugins :: proc(state: ^core.State, dir: string) { - filepath.walk(filepath.join({ os.get_current_directory(), dir }), walk_plugins, transmute(rawptr)state); - log.info("done walking") - - for plugin in state.new_plugins { - // FIXME: check if the global actually exists - lua.getglobal(state.L, fmt.ctprintf("%s_%s", plugin.namespace, plugin.name)); - - lua.getfield(state.L, -1, "OnLoad"); - if (lua.isnil(state.L, -1)) { - lua.pop(state.L, 2) - log.warn("plugin", plugin.name, "doesn't have an 'OnLoad' function") - - continue - } - - if lua.pcall(state.L, 0, 0, 0) == i32(lua.OK) { - lua.pop(state.L, lua.gettop(state.L)); - } else { - err := lua.tostring(state.L, lua.gettop(state.L)); - lua.pop(state.L, lua.gettop(state.L)); - lua.pop(state.L, 1); - - log.error("failed to initialize plugin (OnLoad):", err); - } - - } -} - -walk_plugins :: proc(info: os.File_Info, in_err: os.Errno, state: rawptr) -> (err: os.Errno, skip_dir: bool) { - state := cast(^core.State)state; - - relative_file_path, rel_error := filepath.rel(state.directory, info.fullpath); - extension := filepath.ext(info.fullpath); - - if extension == ".lua" { - log.info("attempting to load", relative_file_path) - - if plugin, ok := load_plugin(state, info.fullpath); ok { - append(&state.new_plugins, plugin); - - if rel_error == .None { - log.info("Loaded", relative_file_path); - } else { - log.info("Loaded", info.fullpath); - } - } else { - log.error("failed to load") - } - } - - return in_err, skip_dir; -} - -load_plugin :: proc(state: ^core.State, path: string) -> (lua_plugin: plugin.NewInterface, ok: bool) { - if lua.L_dofile(state.L, strings.clone_to_cstring(path, allocator = context.temp_allocator)) != i32(lua.OK) { - err := lua.tostring(state.L, lua.gettop(state.L)) - lua.pop(state.L, lua.gettop(state.L)) - - log.error("failed to load lua plugin:", err) - return - } - - lua.getfield(state.L, -1, "name"); - if (lua.isnil(state.L, -1)) { - lua.pop(state.L, 2) - - log.error("no name for lua plugin") - return - } - name := strings.clone(string(lua.tostring(state.L, -1))) - lua.pop(state.L, 1) - - lua.getfield(state.L, -1, "version"); - if (lua.isnil(state.L, -1)) { - lua.pop(state.L, 2) - return - } - version := strings.clone(string(lua.tostring(state.L, -1))) - lua.pop(state.L, 1) - - lua.getfield(state.L, -1, "namespace"); - if (lua.isnil(state.L, -1)) { - lua.pop(state.L, 2) - return - } - namespace := strings.clone(string(lua.tostring(state.L, -1))) - lua.pop(state.L, 1) - - // Add plugin to lua globals - lua.setglobal(state.L, fmt.caprintf("%s_%s", namespace, name)) - - return plugin.NewInterface { - name = name, - version = version, - namespace = namespace, - }, true -} - -ui_flags :: proc(L: ^lua.State, index: i32) -> (bit_set[ui.Flag], bool) { - lua.L_checktype(L, index, i32(lua.TTABLE)); - lua.len(L, index); - array_len := lua.tointeger(L, -1); - lua.pop(L, 1); - - flags: bit_set[ui.Flag] - - for i in 1..=array_len { - lua.rawgeti(L, index, i); - defer lua.pop(L, 1); - - flag := lua.tostring(L, -1); - switch flag { - case "Clickable": flags |= {.Clickable} - case "Hoverable": flags |= {.Hoverable} - case "Scrollable": flags |= {.Scrollable} - case "DrawText": flags |= {.DrawText} - case "DrawBorder": flags |= {.DrawBorder} - case "DrawBackground": flags |= {.DrawBackground} - case "RoundedBorder": flags |= {.RoundedBorder} - case "Floating": flags |= {.Floating} - case "CustomDrawFunc": flags |= {.CustomDrawFunc} - } - } - - return flags, true -} - -run_editor_action :: proc(state: ^core.State, key: plugin.Key, action: core.LuaEditorAction, location := #caller_location) { - lua.rawgeti(state.L, lua.REGISTRYINDEX, lua.Integer(action.fn_ref)); - if lua.pcall(state.L, 0, 0, 0) != i32(lua.OK) { - err := lua.tostring(state.L, lua.gettop(state.L)); - lua.pop(state.L, lua.gettop(state.L)); - - log.error(err, location); - } else { - lua.pop(state.L, lua.gettop(state.L)); - } - - if action.maybe_input_map.key_actions != nil { - ptr_action := &(&state.current_input_map.key_actions[key]).action.(core.LuaEditorAction) - state.current_input_map = (&ptr_action.maybe_input_map) - } -} - -run_ui_function :: proc(state: ^core.State, ui_context: ^ui.Context, fn_ref: i32) { - lua.rawgeti(state.L, lua.REGISTRYINDEX, lua.Integer(fn_ref)); - lua.pushlightuserdata(state.L, ui_context); - if lua.pcall(state.L, 1, 0, 0) != i32(lua.OK) { - err := lua.tostring(state.L, lua.gettop(state.L)); - lua.pop(state.L, lua.gettop(state.L)); - - log.error(err); - } else { - lua.pop(state.L, lua.gettop(state.L)); - } -} - -run_panel_render :: proc(state: ^core.State, ui_context: ^ui.Context, panel_index: i32, fn_ref: i32) { - lua.getglobal(state.L, "__core_panels") - - lua.rawgeti(state.L, lua.REGISTRYINDEX, lua.Integer(fn_ref)); - - lua.pushinteger(state.L, lua.Integer(panel_index)); - lua.gettable(state.L, -3); - - lua.pushlightuserdata(state.L, ui_context); - if lua.pcall(state.L, 2, 0, 0) != i32(lua.OK) { - err := lua.tostring(state.L, lua.gettop(state.L)); - lua.pop(state.L, lua.gettop(state.L)); - - log.error(err); - } else { - lua.pop(state.L, lua.gettop(state.L)); - } -} - -run_panel_render_new :: proc(state: ^core.State, ui_state: ^ui.State, panel_index: i32, fn_ref: i32) { - lua.getglobal(state.L, "__core_panels") - - lua.rawgeti(state.L, lua.REGISTRYINDEX, lua.Integer(fn_ref)); - - lua.pushinteger(state.L, lua.Integer(panel_index)); - lua.gettable(state.L, -3); - - lua.pushlightuserdata(state.L, ui_state); - if lua.pcall(state.L, 2, 0, 0) != i32(lua.OK) { - err := lua.tostring(state.L, lua.gettop(state.L)); - lua.pop(state.L, lua.gettop(state.L)); - - log.error("[LUA]:", err); - } else { - lua.pop(state.L, lua.gettop(state.L)); - } -} - -add_panel :: proc(state: ^core.State, id: core.LuaPanelId) -> (new_panel: core.LuaPanel, ok: bool) { - lua.getglobal(state.L, "__core_panels") - - // create panel list if it doesn't already exist - if !lua.istable(state.L, -1) { - log.info("__core_panels doesn't exist yet, create it..") - - lua.newtable(state.L) - lua.setglobal(state.L, "__core_panels") - } - - lua.getglobal(state.L, "__core_panels") - - l_panel_list := lua.gettop(state.L) - - lua.len(state.L, l_panel_list); - num_panels := lua.tointeger(state.L, -1); - lua.pop(state.L, 1); - - render_ref: i32 - - // lua.pushinteger(state.L, lua.Integer(num_panels + 1)) - { - // create new panel object in lua - - // FIXME: eventually grab the appropriate namespace from the panel id - lua.getglobal(state.L, "nl_spacegirl_plugin_Default_Default_View"); - - lua.getfield(state.L, -1, strings.clone_to_cstring(id.id, allocator = context.temp_allocator)); - if (lua.isnil(state.L, -1)) { - lua.pop(state.L, lua.gettop(state.L)-l_panel_list+1) - - log.error("no lua panel with identifier:", id.id) - return - } - - lua.getfield(state.L, -1, "render") - if lua.isfunction(state.L, -1) { - render_ref = lua.L_ref(state.L, i32(lua.REGISTRYINDEX)); - } else { - lua.pop(state.L, lua.gettop(state.L)-l_panel_list+1) - - log.error("no 'render' function for lua panel:", id.id) - return - } - - lua.getfield(state.L, -1, "new") - if (lua.isnil(state.L, -1)) { - lua.pop(state.L, lua.gettop(state.L)-l_panel_list+1) - - log.error("no 'new' function for lua panel:", id.id) - return - } - - if lua.pcall(state.L, 0, 1, 0) != i32(lua.OK) { - err := lua.tostring(state.L, lua.gettop(state.L)); - lua.pop(state.L, lua.gettop(state.L)-l_panel_list+1); - - // FIXME: do we need this? - // lua.pop(state.L, 1); - - log.error("failed to create new lua panel:", err); - } - log.info("called") - } - lua.rawseti(state.L, l_panel_list, num_panels + 1); - lua.settable(state.L, l_panel_list) - - return core.LuaPanel{ - panel_id = id, - index = i32(num_panels) + 1, - render_ref = render_ref - }, true -} - -// TODO: don't duplicate this procedure -ui_file_buffer :: proc(ctx: ^ui.Context, buffer: ^core.FileBuffer) -> ui.Interaction { - draw_func := proc(state: ^core.State, box: ^ui.Box, user_data: rawptr) { - buffer := transmute(^core.FileBuffer)user_data; - buffer.glyph_buffer_width = box.computed_size.x / state.source_font_width; - buffer.glyph_buffer_height = box.computed_size.y / state.source_font_height + 1; - - core.draw_file_buffer(state, buffer, box.computed_pos.x, box.computed_pos.y); - }; - - relative_file_path, _ := filepath.rel(state.directory, buffer.file_path, context.temp_allocator) - - buffer_container, _ := ui.push_box(ctx, relative_file_path, {}, .Vertical, semantic_size = {ui.make_semantic_size(.Fill), ui.make_semantic_size(.Fill)}); - ui.push_parent(ctx, buffer_container); - defer ui.pop_parent(ctx); - - interaction := ui.custom(ctx, "buffer1", draw_func, transmute(rawptr)buffer); - - { - info_box, _ := ui.push_box(ctx, "buffer info", {}, semantic_size = {ui.make_semantic_size(.Fill), ui.make_semantic_size(.Exact, state.source_font_height)}); - ui.push_parent(ctx, info_box); - defer ui.pop_parent(ctx); - - ui.label(ctx, fmt.tprintf("%s", state.mode)) - if selection, exists := buffer.selection.?; exists { - ui.label(ctx, fmt.tprintf("sel: %d:%d", selection.end.line, selection.end.col)); - } - ui.spacer(ctx, "spacer"); - ui.label(ctx, relative_file_path); - } - - return interaction; -} diff --git a/src/lua/lua.odin~ b/src/lua/lua.odin~ deleted file mode 100644 index 0a41189..0000000 --- a/src/lua/lua.odin~ +++ /dev/null @@ -1,693 +0,0 @@ -package plugin - -import "core:strings" - -import core "../core" -import ui "../ui" - -import lua "vendor:lua/5.4" - -state: ^core.State = nil - -new_lua_state :: proc() -> ^lua.State { - L := lua.L_newstate(); - lua.L_openlibs(L); - - bbb: [^]lua.L_Reg; - editor_lib := [?]lua.L_Reg { - lua.L_Reg { - "quit", - proc "c" (L: ^lua.State) -> i32 { - context = state.ctx; - - - state.should_close = true; - return i32(lua.OK); - } - }, - lua.L_Reg { - "log", - proc "c" (L: ^lua.State) -> i32 { - context = state.ctx; - - text := string(lua.L_checkstring(L, 1)); - log.info("[LUA]:", text); - - return i32(lua.OK); - } - }, - lua.L_Reg { - "register_hook", - proc "c" (L: ^lua.State) -> i32 { - context = state.ctx; - - hook := lua.L_checkinteger(L, 1); - - lua.L_checktype(L, 2, i32(lua.TFUNCTION)); - lua.pushvalue(L, 2); - fn_ref := lua.L_ref(L, i32(lua.REGISTRYINDEX)); - - core.add_lua_hook(&state, Hook(hook), fn_ref); - - return i32(lua.OK); - } - }, - lua.L_Reg { - "register_key_group", - proc "c" (L: ^lua.State) -> i32 { - context = state.ctx; - - lua.L_checktype(L, 1, i32(lua.TTABLE)); - - table_to_action :: proc(L: ^lua.State, index: i32, input_map: ^core.InputActions) { - lua.len(L, index); - key_group_len := lua.tointeger(L, -1); - lua.pop(L, 1); - - for i in 1..=key_group_len { - lua.rawgeti(L, index, i); - defer lua.pop(L, 1); - - lua.rawgeti(L, -1, 1); - key:= Key(lua.tointeger(L, -1)); - lua.pop(L, 1); - - lua.rawgeti(L, -1, 2); - desc := strings.clone(string(lua.tostring(L, -1))); - lua.pop(L, 1); - - switch lua.rawgeti(L, -1, 3) { - case i32(lua.TTABLE): - if action, exists := input_map.key_actions[key]; exists { - switch value in action.action { - case core.LuaEditorAction: - log.warn("Plugin attempted to register input group on existing key action (added from Lua)"); - case core.PluginEditorAction: - log.warn("Plugin attempted to register input group on existing key action (added from Plugin)"); - case core.EditorAction: - log.warn("Plugin attempted to register input group on existing key action"); - case core.InputActions: - input_map := &(&input_map.key_actions[key]).action.(core.InputActions); - table_to_action(L, lua.gettop(L), input_map); - } - } else { - core.register_key_action(input_map, key, core.new_input_actions(), desc); - table_to_action(L, lua.gettop(L), &((&input_map.key_actions[key]).action.(core.InputActions))); - } - lua.pop(L, 1); - - case i32(lua.TFUNCTION): - fn_ref := lua.L_ref(L, i32(lua.REGISTRYINDEX)); - - if lua.rawgeti(L, -1, 4) == i32(lua.TTABLE) { - maybe_input_map := core.new_input_actions(); - table_to_action(L, lua.gettop(L), &maybe_input_map); - - core.register_key_action_group(input_map, key, core.LuaEditorAction { fn_ref, maybe_input_map }, desc); - } else { - core.register_key_action_group(input_map, key, core.LuaEditorAction { fn_ref, core.InputActions {} }, desc); - } - - case: - lua.pop(L, 1); - } - } - } - - table_to_action(L, 1, state.current_input_map); - - return i32(lua.OK); - } - }, - lua.L_Reg { - "request_window_close", - proc "c" (L: ^lua.State) -> i32 { - context = state.ctx; - - core.request_window_close(&state); - - return i32(lua.OK); - } - }, - lua.L_Reg { - "get_current_buffer_index", - proc "c" (L: ^lua.State) -> i32 { - context = state.ctx; - - lua.pushinteger(L, lua.Integer(state.current_buffer)); - - return 1; - } - }, - lua.L_Reg { - "set_current_buffer_from_index", - proc "c" (L: ^lua.State) -> i32 { - context = state.ctx; - - buffer_index := int(lua.L_checkinteger(L, 1)); - if buffer_index != -2 && (buffer_index < 0 || buffer_index >= len(state.buffers)) { - return i32(lua.ERRRUN); - } else { - state.current_buffer = buffer_index; - } - - return i32(lua.OK); - } - }, - lua.L_Reg { - "buffer_info_from_index", - proc "c" (L: ^lua.State) -> i32 { - context = state.ctx; - - buffer_index := int(lua.L_checkinteger(L, 1)); - if buffer_index < 0 || buffer_index >= len(state.buffers) { - lua.pushnil(L); - } else { - push_lua_buffer_info :: proc(L: ^lua.State, buffer: ^FileBuffer) { - lua.newtable(L); - { - lua.pushlightuserdata(L, buffer); - lua.setfield(L, -2, "buffer"); - - lua.newtable(L); - { - lua.pushinteger(L, lua.Integer(buffer.cursor.col)); - lua.setfield(L, -2, "col"); - - lua.pushinteger(L, lua.Integer(buffer.cursor.line)); - lua.setfield(L, -2, "line"); - } - lua.setfield(L, -2, "cursor"); - - lua.pushstring(L, strings.clone_to_cstring(buffer.file_path, context.temp_allocator)); - lua.setfield(L, -2, "full_file_path"); - - relative_file_path, _ := filepath.rel(state.directory, buffer.file_path, context.temp_allocator) - lua.pushstring(L, strings.clone_to_cstring(relative_file_path, context.temp_allocator)); - lua.setfield(L, -2, "file_path"); - } - } - - push_lua_buffer_info(L, core.buffer_from_index(&state, buffer_index)); - } - - return 1; - } - }, - lua.L_Reg { - "query_command_group", - proc "c" (L: ^lua.State) -> i32 { - context = state.ctx; - - group := lua.L_checkstring(L, 1); - cmds := core.query_editor_commands_by_group(&state.commands, string(group), scratch_alloc); - - lua.newtable(L); - { - for cmd, i in cmds { - lua.newtable(L); - { - lua.pushstring(L, strings.clone_to_cstring(cmd.name, scratch_alloc)); - lua.setfield(L, -2, "name"); - - lua.pushstring(L, strings.clone_to_cstring(cmd.description, scratch_alloc)); - lua.setfield(L, -2, "description"); - } - lua.rawseti(L, -2, lua.Integer(i+1)); - } - } - - return 1; - } - }, - lua.L_Reg { - "run_command", - proc "c" (L: ^lua.State) -> i32 { - context = state.ctx; - - group := lua.L_checkstring(L, 1); - name := lua.L_checkstring(L, 2); - core.run_command(&state, string(group), string(name)); - - return 1; - } - } - }; - bbb = raw_data(editor_lib[:]); - - get_lua_semantic_size :: proc(L: ^lua.State, index: i32) -> ui.SemanticSize { - if lua.istable(L, index) { - lua.rawgeti(L, index, 1); - semantic_kind := ui.SemanticSizeKind(lua.tointeger(L, -1)); - lua.pop(L, 1); - - lua.rawgeti(L, index, 2); - semantic_value := int(lua.tointeger(L, -1)); - lua.pop(L, 1); - - return {semantic_kind, semantic_value}; - } else { - semantic_kind := ui.SemanticSizeKind(lua.L_checkinteger(L, index)); - return {semantic_kind, 0}; - } - } - - push_lua_semantic_size_table :: proc(L: ^lua.State, size: ui.SemanticSize) { - lua.newtable(L); - { - lua.pushinteger(L, lua.Integer(i32(size.kind))); - lua.rawseti(L, -2, 1); - - lua.pushinteger(L, lua.Integer(size.value)); - lua.rawseti(L, -2, 2); - } - } - - push_lua_box_interaction :: proc(L: ^lua.State, interaction: ui.Interaction) { - lua.newtable(L); - { - lua.pushboolean(L, b32(interaction.clicked)); - lua.setfield(L, -2, "clicked"); - - lua.pushboolean(L, b32(interaction.hovering)); - lua.setfield(L, -2, "hovering"); - - lua.pushboolean(L, b32(interaction.dragging)); - lua.setfield(L, -2, "dragging"); - - lua.newtable(L); - { - lua.pushinteger(L, lua.Integer(interaction.box_pos.x)); - lua.setfield(L, -2, "x"); - - lua.pushinteger(L, lua.Integer(interaction.box_pos.y)); - lua.setfield(L, -2, "y"); - } - lua.setfield(L, -2, "box_pos"); - - lua.newtable(L); - { - lua.pushinteger(L, lua.Integer(interaction.box_size.x)); - lua.setfield(L, -2, "x"); - - lua.pushinteger(L, lua.Integer(interaction.box_size.y)); - lua.setfield(L, -2, "y"); - } - lua.setfield(L, -2, "box_size"); - } - } - - ui_lib := [?]lua.L_Reg { - lua.L_Reg { - "get_mouse_pos", - proc "c" (L: ^lua.State) -> i32 { - context = state.ctx; - - lua.L_checktype(L, 1, i32(lua.TLIGHTUSERDATA)); - lua.pushvalue(L, 1); - ui_ctx := transmute(^ui.Context)lua.touserdata(L, -1); - if ui_ctx == nil { return i32(lua.ERRRUN); } - - lua.pushinteger(L, lua.Integer(ui_ctx.mouse_x)); - lua.pushinteger(L, lua.Integer(ui_ctx.mouse_y)); - - return 2; - } - }, - lua.L_Reg { - "Exact", - proc "c" (L: ^lua.State) -> i32 { - context = state.ctx; - - value := lua.L_checknumber(L, 1); - push_lua_semantic_size_table(L, { ui.SemanticSizeKind.Exact, int(value) }); - - return 1; - } - }, - lua.L_Reg { - "PercentOfParent", - proc "c" (L: ^lua.State) -> i32 { - context = state.ctx; - - value := lua.L_checknumber(L, 1); - push_lua_semantic_size_table(L, { ui.SemanticSizeKind.PercentOfParent, int(value) }); - - return 1; - } - }, - lua.L_Reg { - "push_parent", - proc "c" (L: ^lua.State) -> i32 { - context = state.ctx; - - lua.L_checktype(L, 1, i32(lua.TLIGHTUSERDATA)); - lua.pushvalue(L, 1); - ui_ctx := transmute(^ui.Context)lua.touserdata(L, -1); - if ui_ctx == nil { return i32(lua.ERRRUN); } - - lua.L_checktype(L, 2, i32(lua.TLIGHTUSERDATA)); - lua.pushvalue(L, 2); - box := transmute(^ui.Box)lua.touserdata(L, -1); - if box == nil { return i32(lua.ERRRUN); } - - ui.push_parent(ui_ctx, box); - return i32(lua.OK); - } - }, - lua.L_Reg { - "pop_parent", - proc "c" (L: ^lua.State) -> i32 { - context = state.ctx; - - lua.L_checktype(L, 1, i32(lua.TLIGHTUSERDATA)); - lua.pushvalue(L, 1); - ui_ctx := transmute(^ui.Context)lua.touserdata(L, -1); - if ui_ctx == nil { return i32(lua.ERRRUN); } - - ui.pop_parent(ui_ctx); - return i32(lua.OK); - } - }, - lua.L_Reg { - "push_floating", - proc "c" (L: ^lua.State) -> i32 { - context = state.ctx; - - lua.L_checktype(L, 1, i32(lua.TLIGHTUSERDATA)); - lua.pushvalue(L, 1); - ui_ctx := transmute(^ui.Context)lua.touserdata(L, -1); - if ui_ctx != nil { - label := lua.L_checkstring(L, 2); - x := int(lua.L_checkinteger(L, 3)); - y := int(lua.L_checkinteger(L, 4)); - - box, interaction := ui.push_floating(ui_ctx, strings.clone(string(label), context.temp_allocator), {x,y}); - lua.pushlightuserdata(L, box); - push_lua_box_interaction(L, interaction); - return 2; - } - - return i32(lua.ERRRUN); - } - }, - lua.L_Reg { - "push_box", - proc "c" (L: ^lua.State) -> i32 { - context = state.ctx; - - lua.L_checktype(L, 1, i32(lua.TLIGHTUSERDATA)); - lua.pushvalue(L, 1); - ui_ctx := transmute(^ui.Context)lua.touserdata(L, -1); - if ui_ctx != nil { - label := lua.L_checkstring(L, 2); - flags, err := lua_ui_flags(L, 3); - axis := ui.Axis(lua.L_checkinteger(L, 4)); - - semantic_width := get_lua_semantic_size(L, 5); - semantic_height := get_lua_semantic_size(L, 6); - - box, interaction := ui.push_box(ui_ctx, strings.clone(string(label), context.temp_allocator), flags, axis, { semantic_width, semantic_height }); - - lua.pushlightuserdata(L, box); - push_lua_box_interaction(L, interaction) - return 2; - } - - return i32(lua.ERRRUN); - } - }, - lua.L_Reg { - "_box_interaction", - proc "c" (L: ^lua.State) -> i32 { - context = state.ctx; - - lua.L_checktype(L, 1, i32(lua.TLIGHTUSERDATA)); - lua.pushvalue(L, 1); - ui_ctx := transmute(^ui.Context)lua.touserdata(L, -1); - if ui_ctx == nil { return i32(lua.ERRRUN); } - - lua.L_checktype(L, 2, i32(lua.TLIGHTUSERDATA)); - lua.pushvalue(L, 2); - box := transmute(^ui.Box)lua.touserdata(L, -1); - if box == nil { return i32(lua.ERRRUN); } - - interaction := ui.test_box(ui_ctx, box); - push_lua_box_interaction(L, interaction) - return 1; - } - }, - lua.L_Reg { - "push_box", - proc "c" (L: ^lua.State) -> i32 { - context = state.ctx; - - lua.L_checktype(L, 1, i32(lua.TLIGHTUSERDATA)); - lua.pushvalue(L, 1); - ui_ctx := transmute(^ui.Context)lua.touserdata(L, -1); - if ui_ctx != nil { - label := lua.L_checkstring(L, 2); - flags, err := lua_ui_flags(L, 3); - axis := ui.Axis(lua.L_checkinteger(L, 4)); - - semantic_width := get_lua_semantic_size(L, 5); - semantic_height := get_lua_semantic_size(L, 6); - - box, interaction := ui.push_box(ui_ctx, strings.clone(string(label), context.temp_allocator), flags, axis, { semantic_width, semantic_height }); - lua.pushlightuserdata(L, box); - push_lua_box_interaction(L, interaction) - return 2; - } - - return i32(lua.ERRRUN); - } - }, - lua.L_Reg { - "push_rect", - proc "c" (L: ^lua.State) -> i32 { - context = state.ctx; - - lua.L_checktype(L, 1, i32(lua.TLIGHTUSERDATA)); - lua.pushvalue(L, 1); - ui_ctx := transmute(^ui.Context)lua.touserdata(L, -1); - if ui_ctx != nil { - label := lua.L_checkstring(L, 2); - background := bool(lua.toboolean(L, 3)); - border := bool(lua.toboolean(L, 4)); - axis := ui.Axis(lua.L_checkinteger(L, 5)); - - semantic_width := get_lua_semantic_size(L, 6); - semantic_height := get_lua_semantic_size(L, 7); - - box, interaction := ui.push_rect(ui_ctx, strings.clone(string(label), context.temp_allocator), background, border, axis, { semantic_width, semantic_height }); - lua.pushlightuserdata(L, box); - push_lua_box_interaction(L, interaction) - return 2; - } - - return i32(lua.ERRRUN); - } - }, - lua.L_Reg { - "spacer", - proc "c" (L: ^lua.State) -> i32 { - context = state.ctx; - - lua.L_checktype(L, 1, i32(lua.TLIGHTUSERDATA)); - lua.pushvalue(L, 1); - ui_ctx := transmute(^ui.Context)lua.touserdata(L, -1); - if ui_ctx != nil { - label := lua.L_checkstring(L, 2); - - interaction := ui.spacer(ui_ctx, strings.clone(string(label), context.temp_allocator), semantic_size = {{.Fill, 0}, {.Fill, 0}}); - - push_lua_box_interaction(L, interaction) - - return 1; - } - - return i32(lua.ERRRUN); - } - }, - lua.L_Reg { - "label", - proc "c" (L: ^lua.State) -> i32 { - context = state.ctx; - - lua.L_checktype(L, 1, i32(lua.TLIGHTUSERDATA)); - lua.pushvalue(L, 1); - ui_ctx := transmute(^ui.Context)lua.touserdata(L, -1); - if ui_ctx != nil { - label := lua.L_checkstring(L, 2); - - interaction := ui.label(ui_ctx, strings.clone(string(label), context.temp_allocator)); - push_lua_box_interaction(L, interaction) - - return 1; - } - - return i32(lua.ERRRUN); - } - }, - lua.L_Reg { - "button", - proc "c" (L: ^lua.State) -> i32 { - context = state.ctx; - - lua.L_checktype(L, 1, i32(lua.TLIGHTUSERDATA)); - lua.pushvalue(L, 1); - ui_ctx := transmute(^ui.Context)lua.touserdata(L, -1); - if ui_ctx != nil { - label := lua.L_checkstring(L, 2); - - interaction := ui.button(ui_ctx, strings.clone(string(label), context.temp_allocator)); - push_lua_box_interaction(L, interaction) - - return 1; - } - - return i32(lua.ERRRUN); - } - }, - lua.L_Reg { - "advanced_button", - proc "c" (L: ^lua.State) -> i32 { - context = state.ctx; - - lua.L_checktype(L, 1, i32(lua.TLIGHTUSERDATA)); - lua.pushvalue(L, 1); - ui_ctx := transmute(^ui.Context)lua.touserdata(L, -1); - - if ui_ctx != nil { - label := lua.L_checkstring(L, 2); - flags, err := lua_ui_flags(L, 3); - - semantic_width := get_lua_semantic_size(L, 4); - semantic_height := get_lua_semantic_size(L, 5); - - interaction := ui.advanced_button(ui_ctx, strings.clone(string(label), context.temp_allocator), flags, { semantic_width, semantic_height }); - push_lua_box_interaction(L, interaction) - - return 1; - } - - return i32(lua.ERRRUN); - } - }, - lua.L_Reg { - "buffer", - proc "c" (L: ^lua.State) -> i32 { - context = state.ctx; - - lua.L_checktype(L, 1, i32(lua.TLIGHTUSERDATA)); - lua.pushvalue(L, 1); - ui_ctx := transmute(^ui.Context)lua.touserdata(L, -1); - - if ui_ctx != nil { - buffer_index := int(lua.L_checkinteger(L, 2)); - - if buffer_index != -2 && (buffer_index < 0 || buffer_index >= len(state.buffers)) { - return i32(lua.ERRRUN); - } - - ui_file_buffer(ui_ctx, core.buffer_from_index(&state, buffer_index)); - - return i32(lua.OK); - } - - return i32(lua.ERRRUN); - } - }, - lua.L_Reg { - "log_buffer", - proc "c" (L: ^lua.State) -> i32 { - context = state.ctx; - - lua.L_checktype(L, 1, i32(lua.TLIGHTUSERDATA)); - lua.pushvalue(L, 1); - ui_ctx := transmute(^ui.Context)lua.touserdata(L, -1); - - if ui_ctx != nil { - ui_file_buffer(ui_ctx, &state.log_buffer); - - return i32(lua.OK); - } - - return i32(lua.ERRRUN); - } - } - }; - - // TODO: generate this from the plugin.Key enum - lua.newtable(state.L); - { - lua.newtable(state.L); - lua.pushinteger(state.L, lua.Integer(Key.B)); - lua.setfield(state.L, -2, "B"); - - lua.pushinteger(state.L, lua.Integer(Key.T)); - lua.setfield(state.L, -2, "T"); - - lua.pushinteger(state.L, lua.Integer(Key.Y)); - lua.setfield(state.L, -2, "Y"); - - lua.pushinteger(state.L, lua.Integer(Key.P)); - lua.setfield(state.L, -2, "P"); - - lua.pushinteger(state.L, lua.Integer(Key.M)); - lua.setfield(state.L, -2, "M"); - - lua.pushinteger(state.L, lua.Integer(Key.K)); - lua.setfield(state.L, -2, "K"); - - lua.pushinteger(state.L, lua.Integer(Key.J)); - lua.setfield(state.L, -2, "J"); - - lua.pushinteger(state.L, lua.Integer(Key.Q)); - lua.setfield(state.L, -2, "Q"); - - lua.pushinteger(state.L, lua.Integer(Key.BACKQUOTE)); - lua.setfield(state.L, -2, "Backtick"); - - lua.pushinteger(state.L, lua.Integer(Key.ESCAPE)); - lua.setfield(state.L, -2, "Escape"); - - lua.pushinteger(state.L, lua.Integer(Key.ENTER)); - lua.setfield(state.L, -2, "Enter"); - - lua.pushinteger(state.L, lua.Integer(Key.SPACE)); - lua.setfield(state.L, -2, "Space"); - } - lua.setfield(state.L, -2, "Key"); - - { - lua.newtable(state.L); - lua.pushinteger(state.L, lua.Integer(Hook.BufferInput)); - lua.setfield(state.L, -2, "OnBufferInput"); - lua.pushinteger(state.L, lua.Integer(Hook.Draw)); - lua.setfield(state.L, -2, "OnDraw"); - } - lua.setfield(state.L, -2, "Hook"); - - lua.L_setfuncs(state.L, bbb, 0); - lua.setglobal(state.L, "Editor"); - - lua.newtable(state.L); - { - lua.pushinteger(state.L, lua.Integer(ui.Axis.Horizontal)); - lua.setfield(state.L, -2, "Horizontal"); - lua.pushinteger(state.L, lua.Integer(ui.Axis.Vertical)); - lua.setfield(state.L, -2, "Vertical"); - push_lua_semantic_size_table(state.L, { ui.SemanticSizeKind.Fill, 0 }); - lua.setfield(state.L, -2, "Fill"); - push_lua_semantic_size_table(state.L, { ui.SemanticSizeKind.ChildrenSum, 0 }); - lua.setfield(state.L, -2, "ChildrenSum"); - push_lua_semantic_size_table(state.L, { ui.SemanticSizeKind.FitText, 0 }); - lua.setfield(state.L, -2, "FitText"); - - lua.L_setfuncs(state.L, raw_data(&ui_lib), 0); - lua.setglobal(state.L, "UI"); - } - - return L -} diff --git a/src/main.odin b/src/main.odin index b8bc8a4..4f941c2 100644 --- a/src/main.odin +++ b/src/main.odin @@ -13,13 +13,11 @@ import "core:slice" import "vendor:sdl2" import "vendor:sdl2/ttf" -import "lua" import "core" import "theme" import "ui" -import "plugin" -HardcodedFontPath :: "bin/BerkeleyMono-Regular.ttf"; +HardcodedFontPath :: "bin/JetBrainsMono-Regular.ttf"; State :: core.State; FileBuffer :: core.FileBuffer; @@ -29,58 +27,15 @@ scratch: mem.Scratch; scratch_alloc: runtime.Allocator; state := core.State {}; -StateWithUi :: struct { - state: ^State, - ui_context: ^ui.Context, -} - -// TODO: why do I have this here again? -// TODO: use buffer list in state do_normal_mode :: proc(state: ^State, buffer: ^FileBuffer) { - if state.current_input_map != nil { - // if raylib.IsKeyPressed(.ESCAPE) { - // core.request_window_close(state); - // } else if raylib.IsKeyDown(.LEFT_CONTROL) { - // for key, action in &state.current_input_map.ctrl_key_actions { - // if raylib.IsKeyPressed(key) { - // switch value in action.action { - // case core.PluginEditorAction: - // value(state.plugin_vtable); - // case core.EditorAction: - // value(state); - // case core.InputMap: - // state.current_input_map = &(&state.current_input_map.ctrl_key_actions[key]).action.(core.InputMap) - // } - // } - // } - // } else { - // for key, action in state.current_input_map.key_actions { - // if raylib.IsKeyPressed(key) { - // switch value in action.action { - // case core.PluginEditorAction: - // value(state.plugin_vtable); - // case core.EditorAction: - // value(state); - // case core.InputMap: - // state.current_input_map = &(&state.current_input_map.key_actions[key]).action.(core.InputMap) - // } - // } - // } - // } - } } -// TODO: use buffer list in state do_insert_mode :: proc(state: ^State, buffer: ^FileBuffer) { key := 0; for key > 0 { if key >= 32 && key <= 125 && len(buffer.input_buffer) < 1024-1 { append(&buffer.input_buffer, u8(key)); - - for hook_proc in state.hooks[plugin.Hook.BufferInput] { - hook_proc(state.plugin_vtable, buffer); - } } key = 0; @@ -286,27 +241,6 @@ register_default_text_input_actions :: proc(input_map: ^core.InputActions) { }, "insert mode on newline"); } -load_plugin :: proc(info: os.File_Info, in_err: os.Errno, state: rawptr) -> (err: os.Errno, skip_dir: bool) { - state := cast(^State)state; - - relative_file_path, rel_error := filepath.rel(state.directory, info.fullpath); - extension := filepath.ext(info.fullpath); - - if extension == ".dylib" || extension == ".dll" || extension == ".so" { - if loaded_plugin, succ := plugin.try_load_plugin(info.fullpath); succ { - append(&state.plugins, loaded_plugin); - - if rel_error == .None { - log.info("Loaded", relative_file_path); - } else { - log.info("Loaded", info.fullpath); - } - } - } - - return in_err, skip_dir; -} - ui_font_width :: proc() -> i32 { return i32(state.source_font_width); } @@ -314,189 +248,108 @@ ui_font_height :: proc() -> i32 { return i32(state.source_font_height); } -draw :: proc(state_with_ui: ^StateWithUi) { - if buffer := core.current_buffer(state_with_ui.state); buffer != nil { - buffer.glyph_buffer_height = math.min(256, int((state_with_ui.state.screen_height - state_with_ui.state.source_font_height*2) / state_with_ui.state.source_font_height)) + 1; - buffer.glyph_buffer_width = math.min(256, int((state_with_ui.state.screen_width - state_with_ui.state.source_font_width) / state_with_ui.state.source_font_width)); +draw :: proc(state: ^State) { + if buffer := core.current_buffer(state); buffer != nil { + buffer.glyph_buffer_height = math.min(256, int((state.screen_height - state.source_font_height*2) / state.source_font_height)) + 1; + buffer.glyph_buffer_width = math.min(256, int((state.screen_width - state.source_font_width) / state.source_font_width)); } render_color := theme.get_palette_color(.Background); - sdl2.SetRenderDrawColor(state_with_ui.state.sdl_renderer, render_color.r, render_color.g, render_color.b, render_color.a); - sdl2.RenderClear(state_with_ui.state.sdl_renderer); + sdl2.SetRenderDrawColor(state.sdl_renderer, render_color.r, render_color.g, render_color.b, render_color.a); + sdl2.RenderClear(state.sdl_renderer); new_ui := transmute(^ui.State)state.ui + new_ui.max_size.x = state.screen_width + new_ui.max_size.y = state.screen_height - ui.open_element(new_ui, nil, { - kind = {ui.Exact(state.screen_width), ui.Exact(state.screen_height)}, - }) - { - // ui.open_element(new_ui, "Hello, I am a text thingy", { - // kind = {ui.Grow{}, ui.Grow{}} - // }) - // ui.close_element(new_ui) - - // ui_file_buffer_2(new_ui, core.current_buffer(state_with_ui.state)) - - // ui.open_element(new_ui, "I am on the right hopefully", { - // kind = {nil, ui.Grow{}} - // }) - // ui.close_element(new_ui) - // - // ui.open_element(new_ui, "Number 4", { - // kind = {nil, ui.Grow{}} - // }) - // ui.close_element(new_ui) - - for panel in state.active_panels { - if panel != nil { - switch v in panel.? { - case core.LuaPanel: { - ui.open_element(new_ui, nil, { - dir = .TopToBottom, - kind = {ui.Grow{}, ui.Grow{}} - }) - { - ui.open_element(new_ui, nil, { - kind = {ui.Grow{}, ui.Grow{}} - }) - { - // ui.open_element(new_ui, "TODO: lua api for new ui", {}) - // ui.close_element(new_ui) - lua.run_panel_render_new(&state, new_ui, v.index, v.render_ref) - } - ui.close_element(new_ui) - - ui.open_element(new_ui, v.panel_id.name, {}) - ui.close_element(new_ui) - } - ui.close_element(new_ui) - } - case core.LibPanel: - log.warn("LibPanel not supported") - } - } - } - + // TODO: use the new panels stuff + if file_buffer := core.current_buffer(state); file_buffer != nil { + ui_file_buffer(new_ui, file_buffer) } - ui.close_element(new_ui) ui.compute_layout_2(new_ui) + ui.draw(new_ui, state) - ui.compute_layout(state_with_ui.ui_context, { state_with_ui.state.screen_width, state_with_ui.state.screen_height }, state_with_ui.state.source_font_width, state_with_ui.state.source_font_height, state_with_ui.ui_context.root); - ui.draw(state_with_ui.ui_context, state_with_ui.state, state_with_ui.state.source_font_width, state_with_ui.state.source_font_height, state_with_ui.ui_context.root); - - ui.new_draw(new_ui, &state) - - if state_with_ui.state.mode != .Insert && state_with_ui.state.current_input_map != &state_with_ui.state.input_map.mode[state_with_ui.state.mode] { + if state.mode != .Insert && state.current_input_map != &state.input_map.mode[state.mode] { longest_description := 0; - for key, action in state_with_ui.state.current_input_map.key_actions { + for key, action in state.current_input_map.key_actions { if len(action.description) > longest_description { longest_description = len(action.description); } } - for key, action in state_with_ui.state.current_input_map.ctrl_key_actions { + for key, action in state.current_input_map.ctrl_key_actions { if len(action.description) > longest_description { longest_description = len(action.description); } } longest_description += 8; - helper_height := state_with_ui.state.source_font_height * (len(state_with_ui.state.current_input_map.key_actions) + len(state_with_ui.state.current_input_map.ctrl_key_actions)); - offset_from_bottom := state_with_ui.state.source_font_height * 2; + helper_height := state.source_font_height * (len(state.current_input_map.key_actions) + len(state.current_input_map.ctrl_key_actions)); + offset_from_bottom := state.source_font_height * 2; core.draw_rect( - state_with_ui.state, - state_with_ui.state.screen_width - longest_description * state_with_ui.state.source_font_width, - state_with_ui.state.screen_height - helper_height - offset_from_bottom, - longest_description*state_with_ui.state.source_font_width, + state, + state.screen_width - longest_description * state.source_font_width, + state.screen_height - helper_height - offset_from_bottom, + longest_description*state.source_font_width, helper_height, .Background2 ); index := 0; - for key, action in state_with_ui.state.current_input_map.key_actions { + for key, action in state.current_input_map.key_actions { core.draw_text( - state_with_ui.state, + state, fmt.tprintf("%s - %s", key, action.description), - state_with_ui.state.screen_width - longest_description * state_with_ui.state.source_font_width, - state_with_ui.state.screen_height - helper_height + index * state_with_ui.state.source_font_height - offset_from_bottom + state.screen_width - longest_description * state.source_font_width, + state.screen_height - helper_height + index * state.source_font_height - offset_from_bottom ); index += 1; } - for key, action in state_with_ui.state.current_input_map.ctrl_key_actions { + for key, action in state.current_input_map.ctrl_key_actions { core.draw_text( - state_with_ui.state, + state, fmt.tprintf("-%s - %s", key, action.description), - state_with_ui.state.screen_width - longest_description * state_with_ui.state.source_font_width, - state_with_ui.state.screen_height - helper_height + index * state_with_ui.state.source_font_height - offset_from_bottom + state.screen_width - longest_description * state.source_font_width, + state.screen_height - helper_height + index * state.source_font_height - offset_from_bottom ); index += 1; } } - sdl2.RenderPresent(state_with_ui.state.sdl_renderer); + sdl2.RenderPresent(state.sdl_renderer); } expose_event_watcher :: proc "c" (state: rawptr, event: ^sdl2.Event) -> i32 { if event.type == .WINDOWEVENT { - state := transmute(^StateWithUi)state; - context = state.state.ctx; + state := transmute(^State)state; + context = state.ctx; if event.window.event == .EXPOSED { //draw(state); } else if event.window.event == .SIZE_CHANGED { w,h: i32; - sdl2.GetRendererOutputSize(state.state.sdl_renderer, &w, &h); + sdl2.GetRendererOutputSize(state.sdl_renderer, &w, &h); - state.state.screen_width = int(w); - state.state.screen_height = int(h); - state.state.width_dpi_ratio = f32(w) / f32(event.window.data1); - state.state.height_dpi_ratio = f32(h) / f32(event.window.data2); + state.screen_width = int(w); + state.screen_height = int(h); + state.width_dpi_ratio = f32(w) / f32(event.window.data1); + state.height_dpi_ratio = f32(h) / f32(event.window.data2); - draw(state); + // KDE resizes very slowly on linux if you trigger a re-render + when ODIN_OS != .Linux { + draw(state); + } } } return 0; } -ui_file_buffer :: proc(ctx: ^ui.Context, buffer: ^FileBuffer) -> ui.Interaction { - draw_func := proc(state: ^State, box: ^ui.Box, user_data: rawptr) { - buffer := transmute(^FileBuffer)user_data; - buffer.glyph_buffer_width = box.computed_size.x / state.source_font_width; - buffer.glyph_buffer_height = box.computed_size.y / state.source_font_height + 1; - - core.draw_file_buffer(state, buffer, box.computed_pos.x, box.computed_pos.y); - }; - - relative_file_path, _ := filepath.rel(state.directory, buffer.file_path, context.temp_allocator) - - buffer_container, _ := ui.push_box(ctx, relative_file_path, {}, .Vertical, semantic_size = {ui.make_semantic_size(.Fill), ui.make_semantic_size(.Fill)}); - ui.push_parent(ctx, buffer_container); - defer ui.pop_parent(ctx); - - interaction := ui.custom(ctx, "buffer1", draw_func, transmute(rawptr)buffer); - - { - info_box, _ := ui.push_box(ctx, "buffer info", {}, semantic_size = {ui.make_semantic_size(.Fill), ui.make_semantic_size(.Exact, state.source_font_height)}); - ui.push_parent(ctx, info_box); - defer ui.pop_parent(ctx); - - ui.label(ctx, fmt.tprintf("%s", state.mode)) - if selection, exists := buffer.selection.?; exists { - ui.label(ctx, fmt.tprintf("sel: %d:%d", selection.end.line, selection.end.col)); - } - ui.spacer(ctx, "spacer"); - ui.label(ctx, relative_file_path); - } - - return interaction; -} - -ui_file_buffer_2 :: proc(s: ^ui.State, buffer: ^FileBuffer) { +ui_file_buffer :: proc(s: ^ui.State, buffer: ^FileBuffer) { draw_func := proc(state: ^State, e: ui.UI_Element, user_data: rawptr) { buffer := transmute(^FileBuffer)user_data; if buffer != nil { @@ -527,613 +380,10 @@ ui_file_buffer_2 :: proc(s: ^ui.State, buffer: ^FileBuffer) { ui.close_element(s) } ui.close_element(s) - - /* - ui.open_element(s, nil, { - kind = {ui.Grow{}, ui.Exact(state.source_font_height)} - }) - { - ui.open_element(s, fmt.tprintf("%s", state.mode), {}) - ui.close_element(s) - - if selection, exists := buffer.selection.?; exists { - ui.open_element(s, fmt.tprintf("sel: %d:%d", selection.end.line, selection.end.col), {}); - ui.close_element(s) - } - ui.open_element(s, nil, { - kind = {ui.Grow{}, ui.Grow{}} - }) - ui.close_element(s) - - ui.open_element(s, relative_file_path, {}); - ui.close_element(s) - } - ui.close_element(s) - */ - } ui.close_element(s) } -init_plugin_vtable :: proc(ui_context: ^ui.Context) -> plugin.Plugin { - return plugin.Plugin { - state = cast(rawptr)&state, - register_hook = proc "c" (hook: plugin.Hook, on_hook: plugin.OnHookProc) { - context = state.ctx; - - core.add_hook(&state, hook, on_hook); - }, - register_highlighter = proc "c" (extension: cstring, on_color_buffer: plugin.OnColorBufferProc) { - context = state.ctx; - - extension := strings.clone(string(extension)); - - if _, exists := state.highlighters[extension]; exists { - log.error("Highlighter already registered for", extension, "files"); - } else { - state.highlighters[extension] = on_color_buffer; - } - }, - register_input_group = proc "c" (input_map: rawptr, key: plugin.Key, register_group: plugin.InputGroupProc) { - context = state.ctx; - - to_be_edited_map: ^core.InputActions = nil; - - if input_map != nil { - to_be_edited_map = transmute(^core.InputActions)input_map; - } else { - to_be_edited_map = state.current_input_map; - } - - // TODO: change this to use the given mode - if action, exists := to_be_edited_map.key_actions[key]; exists { - switch value in action.action { - case core.LuaEditorAction: - log.warn("Plugin attempted to register input group on existing key action (added from Lua)"); - case core.PluginEditorAction: - log.warn("Plugin attempted to register input group on existing key action (added from Plugin)"); - case core.EditorAction: - log.warn("Plugin attempted to register input group on existing key action"); - case core.InputActions: - input_map := &(&to_be_edited_map.key_actions[key]).action.(core.InputActions); - register_group(state.plugin_vtable, transmute(rawptr)input_map); - } - } else { - core.register_key_action(to_be_edited_map, key, core.new_input_actions(), "PLUGIN INPUT GROUP"); - register_group(state.plugin_vtable, &(&to_be_edited_map.key_actions[key]).action.(core.InputActions)); - } - }, - register_input = proc "c" (input_map: rawptr, key: plugin.Key, input_action: plugin.InputActionProc, description: cstring) { - context = state.ctx; - - to_be_edited_map: ^core.InputActions = nil; - description := strings.clone(string(description)); - - if input_map != nil { - to_be_edited_map = transmute(^core.InputActions)input_map; - } else { - to_be_edited_map = state.current_input_map; - } - - if action, exists := to_be_edited_map.key_actions[key]; exists { - switch value in action.action { - case core.LuaEditorAction: - log.warn("Plugin attempted to register key action on existing key action (added from Lua)"); - case core.PluginEditorAction: - log.warn("Plugin attempted to register key action on existing key action (added from Plugin)"); - case core.EditorAction: - log.warn("Plugin attempted to register input key action on existing key action"); - case core.InputActions: - log.warn("Plugin attempted to register input key action on existing input group"); - } - } else { - core.register_key_action(to_be_edited_map, key, input_action, description); - } - }, - create_window = proc "c" (user_data: rawptr, register_group: plugin.InputGroupProc, draw_proc: plugin.WindowDrawProc, free_window_proc: plugin.WindowFreeProc, get_buffer_proc: plugin.WindowGetBufferProc) -> rawptr { - context = state.ctx; - window := new(core.Window); - window^ = core.Window { - input_map = core.new_input_actions(), - draw = draw_proc, - get_buffer = get_buffer_proc, - free_user_data = free_window_proc, - - user_data = user_data, - }; - - register_group(state.plugin_vtable, transmute(rawptr)&window.input_map); - - state.window = window; - state.current_input_map = &window.input_map; - - return window; - }, - get_window = proc "c" () -> rawptr { - if state.window != nil { - return state.window.user_data; - } - - return nil; - }, - request_window_close = proc "c" () { - context = state.ctx; - - core.request_window_close(&state); - }, - get_screen_width = proc "c" () -> int { - return state.screen_width; - }, - get_screen_height = proc "c" () -> int { - return state.screen_height; - }, - get_font_width = proc "c" () -> int { - return state.source_font_width; - }, - get_font_height = proc "c" () -> int { - return state.source_font_height; - }, - get_current_directory = proc "c" () -> cstring { - context = state.ctx; - - return strings.clone_to_cstring(state.directory, context.temp_allocator); - }, - enter_insert_mode = proc "c" () { - state.mode = .Insert; - sdl2.StartTextInput(); - }, - draw_rect = proc "c" (x: i32, y: i32, width: i32, height: i32, color: theme.PaletteColor) { - context = state.ctx; - - core.draw_rect(&state, int(x), int(y), int(width), int(height), color); - }, - draw_text = proc "c" (text: cstring, x: f32, y: f32, color: theme.PaletteColor) { - context = state.ctx; - - core.draw_text(&state, string(text), int(x), int(y), color); - }, - draw_buffer_from_index = proc "c" (buffer_index: int, x: int, y: int, glyph_buffer_width: int, glyph_buffer_height: int, show_line_numbers: bool) { - context = state.ctx; - core.buffer_from_index(&state, buffer_index).glyph_buffer_width = glyph_buffer_width; - core.buffer_from_index(&state, buffer_index).glyph_buffer_height = glyph_buffer_height; - - core.draw_file_buffer( - &state, - core.buffer_from_index(&state, buffer_index), - x, - y, - show_line_numbers); - }, - draw_buffer = proc "c" (buffer: rawptr, x: int, y: int, glyph_buffer_width: int, glyph_buffer_height: int, show_line_numbers: bool) { - context = state.ctx; - - buffer := transmute(^core.FileBuffer)buffer; - buffer.glyph_buffer_width = glyph_buffer_width; - buffer.glyph_buffer_height = glyph_buffer_height; - - core.draw_file_buffer( - &state, - buffer, - x, - y, - show_line_numbers); - }, - iter = plugin.Iterator { - get_current_buffer_iterator = proc "c" () -> plugin.BufferIter { - context = state.ctx; - - it := core.new_file_buffer_iter(core.current_buffer(&state)); - - // TODO: make this into a function - return plugin.BufferIter { - cursor = plugin.Cursor { - col = it.cursor.col, - line = it.cursor.line, - index = plugin.BufferIndex { - slice_index = it.cursor.index.slice_index, - content_index = it.cursor.index.content_index, - } - }, - buffer = cast(rawptr)it.buffer, - hit_end = it.hit_end, - } - }, - get_buffer_iterator = proc "c" (buffer: rawptr) -> plugin.BufferIter { - buffer := cast(^core.FileBuffer)buffer; - context = state.ctx; - - it := core.new_file_buffer_iter(buffer); - - // TODO: make this into a function - return plugin.BufferIter { - cursor = plugin.Cursor { - col = it.cursor.col, - line = it.cursor.line, - index = plugin.BufferIndex { - slice_index = it.cursor.index.slice_index, - content_index = it.cursor.index.content_index, - } - }, - buffer = cast(rawptr)it.buffer, - hit_end = it.hit_end, - } - }, - get_char_at_iter = proc "c" (it: ^plugin.BufferIter) -> u8 { - context = state.ctx; - - internal_it := core.FileBufferIter { - cursor = core.Cursor { - col = it.cursor.col, - line = it.cursor.line, - index = core.FileBufferIndex { - slice_index = it.cursor.index.slice_index, - content_index = it.cursor.index.content_index, - } - }, - buffer = cast(^core.FileBuffer)it.buffer, - hit_end = it.hit_end, - } - - return core.get_character_at_iter(internal_it); - }, - get_buffer_list_iter = proc "c" (prev_buffer: ^int) -> int { - context = state.ctx; - - return core.next_buffer(&state, prev_buffer); - }, - iterate_buffer = proc "c" (it: ^plugin.BufferIter) -> plugin.IterateResult { - context = state.ctx; - - // TODO: make this into a function - internal_it := core.FileBufferIter { - cursor = core.Cursor { - col = it.cursor.col, - line = it.cursor.line, - index = core.FileBufferIndex { - slice_index = it.cursor.index.slice_index, - content_index = it.cursor.index.content_index, - } - }, - buffer = cast(^core.FileBuffer)it.buffer, - hit_end = it.hit_end, - } - - char, _, cond := core.iterate_file_buffer(&internal_it); - - it^ = plugin.BufferIter { - cursor = plugin.Cursor { - col = internal_it.cursor.col, - line = internal_it.cursor.line, - index = plugin.BufferIndex { - slice_index = internal_it.cursor.index.slice_index, - content_index = internal_it.cursor.index.content_index, - } - }, - buffer = cast(rawptr)internal_it.buffer, - hit_end = internal_it.hit_end, - }; - - return plugin.IterateResult { - char = char, - should_continue = cond, - }; - }, - iterate_buffer_reverse = proc "c" (it: ^plugin.BufferIter) -> plugin.IterateResult { - context = state.ctx; - - // TODO: make this into a function - internal_it := core.FileBufferIter { - cursor = core.Cursor { - col = it.cursor.col, - line = it.cursor.line, - index = core.FileBufferIndex { - slice_index = it.cursor.index.slice_index, - content_index = it.cursor.index.content_index, - } - }, - buffer = cast(^core.FileBuffer)it.buffer, - hit_end = it.hit_end, - } - - char, _, cond := core.iterate_file_buffer_reverse(&internal_it); - - it^ = plugin.BufferIter { - cursor = plugin.Cursor { - col = internal_it.cursor.col, - line = internal_it.cursor.line, - index = plugin.BufferIndex { - slice_index = internal_it.cursor.index.slice_index, - content_index = internal_it.cursor.index.content_index, - } - }, - buffer = cast(rawptr)internal_it.buffer, - hit_end = internal_it.hit_end, - }; - - return plugin.IterateResult { - char = char, - should_continue = cond, - }; - }, - iterate_buffer_until = proc "c" (it: ^plugin.BufferIter, until_proc: rawptr) { - context = state.ctx; - - // TODO: make this into a function - internal_it := core.FileBufferIter { - cursor = core.Cursor { - col = it.cursor.col, - line = it.cursor.line, - index = core.FileBufferIndex { - slice_index = it.cursor.index.slice_index, - content_index = it.cursor.index.content_index, - } - }, - buffer = cast(^core.FileBuffer)it.buffer, - hit_end = it.hit_end, - } - - core.iterate_file_buffer_until(&internal_it, transmute(core.UntilProc)until_proc); - - it^ = plugin.BufferIter { - cursor = plugin.Cursor { - col = internal_it.cursor.col, - line = internal_it.cursor.line, - index = plugin.BufferIndex { - slice_index = internal_it.cursor.index.slice_index, - content_index = internal_it.cursor.index.content_index, - } - }, - buffer = cast(rawptr)internal_it.buffer, - hit_end = internal_it.hit_end, - }; - }, - iterate_buffer_peek = proc "c" (it: ^plugin.BufferIter) -> plugin.IterateResult { - context = state.ctx; - - // TODO: make this into a function - internal_it := core.FileBufferIter { - cursor = core.Cursor { - col = it.cursor.col, - line = it.cursor.line, - index = core.FileBufferIndex { - slice_index = it.cursor.index.slice_index, - content_index = it.cursor.index.content_index, - } - }, - buffer = cast(^core.FileBuffer)it.buffer, - hit_end = it.hit_end, - } - - char, _, cond := core.iterate_peek(&internal_it, core.iterate_file_buffer); - - it^ = plugin.BufferIter { - cursor = plugin.Cursor { - col = internal_it.cursor.col, - line = internal_it.cursor.line, - index = plugin.BufferIndex { - slice_index = internal_it.cursor.index.slice_index, - content_index = internal_it.cursor.index.content_index, - } - }, - buffer = cast(rawptr)internal_it.buffer, - hit_end = internal_it.hit_end, - }; - - return plugin.IterateResult { - char = char, - should_continue = cond, - }; - }, - until_line_break = transmute(rawptr)core.until_line_break, - until_single_quote = transmute(rawptr)core.until_single_quote, - until_double_quote = transmute(rawptr)core.until_double_quote, - until_end_of_word = transmute(rawptr)core.until_end_of_word, - }, - buffer = plugin.Buffer { - get_num_buffers = proc "c" () -> int { - context = state.ctx; - - return len(state.buffers); - }, - get_buffer_info = proc "c" (buffer: rawptr) -> plugin.BufferInfo { - context = state.ctx; - buffer := cast(^core.FileBuffer)buffer; - - return core.into_buffer_info(&state, buffer); - }, - get_buffer_info_from_index = proc "c" (buffer_index: int) -> plugin.BufferInfo { - context = state.ctx; - buffer := core.buffer_from_index(&state, buffer_index); - - return core.into_buffer_info(&state, buffer); - }, - color_char_at = proc "c" (buffer: rawptr, start_cursor: plugin.Cursor, end_cursor: plugin.Cursor, palette_index: i32) { - buffer := cast(^core.FileBuffer)buffer; - context = state.ctx; - - start_cursor := core.Cursor { - col = start_cursor.col, - line = start_cursor.line, - index = core.FileBufferIndex { - slice_index = start_cursor.index.slice_index, - content_index = start_cursor.index.content_index, - } - }; - end_cursor := core.Cursor { - col = end_cursor.col, - line = end_cursor.line, - index = core.FileBufferIndex { - slice_index = end_cursor.index.slice_index, - content_index = end_cursor.index.content_index, - } - }; - - core.color_character(buffer, start_cursor, end_cursor, cast(theme.PaletteColor)palette_index); - }, - set_current_buffer = proc "c" (buffer_index: int) { - state.current_buffer = buffer_index; - }, - open_buffer = proc "c" (path: cstring, line: int, col: int) { - context = state.ctx; - - fmt.eprintln("opening file from dll", path) - - path := string(path); - should_create_buffer := true; - for buffer, index in state.buffers { - if strings.compare(buffer.file_path, path) == 0 { - state.current_buffer = index; - should_create_buffer = false; - break; - } - } - - buffer: ^core.FileBuffer = nil; - err := core.no_error(); - - if should_create_buffer { - new_buffer, err := core.new_file_buffer(context.allocator, strings.clone(path)); - if err.type != .None { - log.error("Failed to open/create file buffer:", err); - } else { - runtime.append(&state.buffers, new_buffer); - state.current_buffer = len(state.buffers)-1; - buffer = core.current_buffer(&state); - } - } else { - buffer = core.current_buffer(&state); - } - - if buffer != nil { - buffer.cursor.line = line; - buffer.cursor.col = col; - buffer.glyph_buffer_height = math.min(256, int((state.screen_height - state.source_font_height*2) / state.source_font_height)) + 1; - buffer.glyph_buffer_width = math.min(256, int((state.screen_width - state.source_font_width) / state.source_font_width)); - core.update_file_buffer_index_from_cursor(buffer); - } - }, - open_virtual_buffer = proc "c" () -> rawptr { - context = state.ctx; - - buffer := new(FileBuffer); - buffer^ = core.new_virtual_file_buffer(context.allocator); - - return buffer; - }, - free_virtual_buffer = proc "c" (buffer: rawptr) { - context = state.ctx; - - if buffer != nil { - buffer := cast(^core.FileBuffer)buffer; - - core.free_file_buffer(buffer); - free(buffer); - } - }, - }, - ui = plugin.Ui { - ui_context = ui_context, - - push_parent = proc "c" (ui_context: rawptr, box: plugin.UiBox) { - context = state.ctx; - ui_context := transmute(^ui.Context)ui_context; - box := transmute(^ui.Box)box; - - ui.push_parent(ui_context, box); - }, - - pop_parent = proc "c" (ui_context: rawptr) { - context = state.ctx; - ui_context := transmute(^ui.Context)ui_context; - - ui.pop_parent(ui_context); - }, - - spacer = proc "c" (ui_context: rawptr, label: cstring) -> plugin.UiInteraction { - context = state.ctx; - ui_context := transmute(^ui.Context)ui_context; - label := strings.clone(string(label), context.temp_allocator); - - interaction := ui.spacer(ui_context, label); - - return plugin.UiInteraction { - hovering = interaction.hovering, - clicked = interaction.clicked, - }; - }, - // TODO: allow this to have more flags sent to it - floating = proc "c" (ui_context: rawptr, label: cstring, pos: [2]int) -> plugin.UiBox { - context = state.ctx; - ui_context := transmute(^ui.Context)ui_context; - label := strings.clone(string(label), context.temp_allocator); - - floating, _ := ui.push_floating(ui_context, label, pos); - return floating; - }, - rect = proc "c" (ui_context: rawptr, label: cstring, background: bool, border: bool, axis: plugin.UiAxis, size: [2]plugin.UiSemanticSize) -> plugin.UiBox { - context = state.ctx; - ui_context := transmute(^ui.Context)ui_context; - label := strings.clone(string(label), context.temp_allocator); - - size := [2]ui.SemanticSize { - ui.SemanticSize { - kind = ui.SemanticSizeKind(size.x.kind), - value = size.x.value, - }, - ui.SemanticSize { - kind = ui.SemanticSizeKind(size.y.kind), - value = size.y.value, - }, - }; - - rect, _ := ui.push_rect(ui_context, label, background, border, ui.Axis(axis), size); - return rect; - }, - - label = proc "c" (ui_context: rawptr, label: cstring) -> plugin.UiInteraction { - context = state.ctx; - ui_context := transmute(^ui.Context)ui_context; - label := strings.clone(string(label), context.temp_allocator); - - interaction := ui.label(ui_context, label); - - return plugin.UiInteraction { - hovering = interaction.hovering, - clicked = interaction.clicked, - }; - }, - button = proc "c" (ui_context: rawptr, label: cstring) -> plugin.UiInteraction { - context = state.ctx; - ui_context := transmute(^ui.Context)ui_context; - label := strings.clone(string(label), context.temp_allocator); - - interaction := ui.button(ui_context, label); - - return plugin.UiInteraction { - hovering = interaction.hovering, - clicked = interaction.clicked, - }; - }, - buffer = proc "c" (ui_context: rawptr, buffer: rawptr, show_line_numbers: bool) { - context = state.ctx; - ui_context := transmute(^ui.Context)ui_context; - buffer := transmute(^FileBuffer)buffer; - - ui_file_buffer(ui_context, buffer); - }, - - buffer_from_index = proc "c" (ui_context: rawptr, buffer_index: int, show_line_numbers: bool) { - context = state.ctx; - ui_context := transmute(^ui.Context)ui_context; - - buffer := core.buffer_from_index(&state, buffer_index); - - ui_file_buffer(ui_context, buffer); - }, - }, - }; -} - main :: proc() { _command_arena: mem.Arena mem.arena_init(&_command_arena, make([]u8, 1024*1024)); @@ -1150,35 +400,10 @@ main :: proc() { panel_catalog = make([dynamic]core.PanelId), - window = nil, directory = os.get_current_directory(), - plugins = make([dynamic]plugin.Interface), - new_plugins = make([dynamic]plugin.NewInterface), - highlighters = make(map[string]plugin.OnColorBufferProc), - hooks = make(map[plugin.Hook][dynamic]plugin.OnHookProc), - lua_hooks = make(map[plugin.Hook][dynamic]core.LuaHookRef), - log_buffer = core.new_virtual_file_buffer(context.allocator), }; - // TODO: please move somewhere else - { - ti := runtime.type_info_base(type_info_of(plugin.Hook)); - if v, ok := ti.variant.(runtime.Type_Info_Enum); ok { - for i in &v.values { - state.hooks[cast(plugin.Hook)i] = make([dynamic]plugin.OnHookProc); - } - } - } - { - ti := runtime.type_info_base(type_info_of(plugin.Hook)); - if v, ok := ti.variant.(runtime.Type_Info_Enum); ok { - for i in &v.values { - state.lua_hooks[cast(plugin.Hook)i] = make([dynamic]core.LuaHookRef); - } - } - } - // context.logger = core.new_logger(&state.log_buffer); context.logger = log.create_console_logger(); state.ctx = context; @@ -1198,45 +423,45 @@ main :: proc() { register_default_text_input_actions(&state.input_map.mode[.Normal]); - core.register_editor_command( - &state.commands, - "nl.spacegirl.editor.core", - "Open New Panel", - "Opens a new panel", - proc(state: ^State) { - Args :: struct { - panel_id: string - } + // core.register_editor_command( + // &state.commands, + // "nl.spacegirl.editor.core", + // "Open New Panel", + // "Opens a new panel", + // proc(state: ^State) { + // Args :: struct { + // panel_id: string + // } - if args, ok := core.attempt_read_command_args(Args, state.command_args[:]); ok { - log.info("maybe going to open panel with id", args.panel_id) + // if args, ok := core.attempt_read_command_args(Args, state.command_args[:]); ok { + // log.info("maybe going to open panel with id", args.panel_id) - for p in state.panel_catalog { - switch v in p { - case core.LuaPanelId: - { - if v.id == args.panel_id { - if index, ok := lua.add_panel(state, v); ok { - for i in 0..= 32 && char <= 125 && len(buffer.input_buffer) < 1024-1 { append(&buffer.input_buffer, u8(char)); - - for hook_proc in state.hooks[plugin.Hook.BufferInput] { - hook_proc(state.plugin_vtable, buffer); - } - for hook_ref in state.lua_hooks[plugin.Hook.BufferInput] { - /* - lua.rawgeti(state.L, lua.REGISTRYINDEX, lua.Integer(hook_ref)); - if lua.pcall(state.L, 0, 0, 0) != i32(lua.OK) { - err := lua.tostring(state.L, lua.gettop(state.L)); - lua.pop(state.L, lua.gettop(state.L)); - - log.error(err); - } else { - lua.pop(state.L, lua.gettop(state.L)); - } - */ - } } } } @@ -1613,51 +702,22 @@ main :: proc() { } } - draw(&StateWithUi { &state, &ui_context }); - - ui.prune(&ui_context); + draw(&state); switch state.mode { case .Normal: - if state.window != nil && state.window.get_buffer != nil { - buffer := transmute(^core.FileBuffer)(state.window.get_buffer(state.plugin_vtable, state.window.user_data)); - do_normal_mode(&state, buffer); - } else { - buffer := core.current_buffer(&state); - do_normal_mode(&state, buffer); - } + buffer := core.current_buffer(&state); + do_normal_mode(&state, buffer); case .Insert: - if state.window != nil && state.window.get_buffer != nil { - buffer := transmute(^core.FileBuffer)(state.window.get_buffer(state.plugin_vtable, state.window.user_data)); - do_insert_mode(&state, buffer); - } else { - buffer := core.current_buffer(&state); - do_insert_mode(&state, buffer); - } + buffer := core.current_buffer(&state); + do_insert_mode(&state, buffer); case .Visual: - if state.window != nil && state.window.get_buffer != nil { - // TODO - } else { - buffer := core.current_buffer(&state); - do_visual_mode(&state, buffer); - } - } - - if state.should_close_window { - state.should_close_window = false; - core.close_window_and_free(&state); + buffer := core.current_buffer(&state); + do_visual_mode(&state, buffer); } runtime.free_all(context.temp_allocator); } - for plugin in state.plugins { - if plugin.on_exit != nil { - plugin.on_exit(); - } - } - - lua.close(state.L); - sdl2.Quit(); } diff --git a/src/plugin/plugin.odin b/src/plugin/plugin.odin deleted file mode 100644 index a2bc3e4..0000000 --- a/src/plugin/plugin.odin +++ /dev/null @@ -1,451 +0,0 @@ -package plugin; - -import "base:intrinsics" -import "core:dynlib" -import "core:fmt" -import "core:log" - -import "../theme" - -OnInitializeProc :: proc "c" (plugin: Plugin); -OnExitProc :: proc "c" (/* probably needs some state eventually */); -OnDrawProc :: proc "c" (plugin: Plugin); -Interface :: struct { - on_initialize: OnInitializeProc, - on_exit: OnExitProc, - on_draw: OnDrawProc, -} - -NewInterface :: struct { - name: string, - version: string, - namespace: string, -} - -BufferIndex :: struct { - slice_index: int, - content_index: int, -} - -Cursor :: struct { - col: int, - line: int, - index: BufferIndex, -} - -BufferIter :: struct { - cursor: Cursor, - buffer: rawptr, - hit_end: bool, -} - -IterateResult :: struct { - char: u8, - should_continue: bool, -} - -BufferInput :: struct { - bytes: [^]u8, - length: int, -} - -BufferInfo :: struct { - buffer: rawptr, - file_path: cstring, - input: BufferInput, - - cursor: Cursor, - - glyph_buffer_width: int, - glyph_buffer_height: int, - top_line: int, -} - -Buffer :: struct { - get_num_buffers: proc "c" () -> int, - get_buffer_info: proc "c" (buffer: rawptr) -> BufferInfo, - get_buffer_info_from_index: proc "c" (buffer_index: int) -> BufferInfo, - color_char_at: proc "c" (buffer: rawptr, start_cursor: Cursor, end_cursor: Cursor, palette_index: i32), - set_current_buffer: proc "c" (buffer_index: int), - - open_buffer: proc "c" (path: cstring, line: int, col: int), - open_virtual_buffer: proc "c" () -> rawptr, - free_virtual_buffer: proc "c" (buffer: rawptr), -} - -Iterator :: struct { - get_current_buffer_iterator: proc "c" () -> BufferIter, - get_buffer_iterator: proc "c" (buffer: rawptr) -> BufferIter, - get_char_at_iter: proc "c" (it: ^BufferIter) -> u8, - get_buffer_list_iter: proc "c" (prev_buffer: ^int) -> int, - - iterate_buffer: proc "c" (it: ^BufferIter) -> IterateResult, - iterate_buffer_reverse: proc "c" (it: ^BufferIter) -> IterateResult, - iterate_buffer_until: proc "c" (it: ^BufferIter, until_proc: rawptr), - iterate_buffer_until_reverse: proc "c" (it: ^BufferIter, until_proc: rawptr), - iterate_buffer_peek: proc "c" (it: ^BufferIter) -> IterateResult, - - until_line_break: rawptr, - until_single_quote: rawptr, - until_double_quote: rawptr, - until_end_of_word: rawptr, -} - -UiInteraction :: struct { - hovering: bool, - clicked: bool -} - -UiAxis :: enum { - Horizontal = 0, - Vertical, -} - -UiSemanticSize :: struct { - kind: int, - value: int, -} - -UiBox :: rawptr; - -UiPushParentProc :: proc "c" (ui_context: rawptr, box: UiBox); -UiPopParentProc :: proc "c" (ui_context: rawptr); -UiFloatingProc :: proc "c" (ui_context: rawptr, label: cstring, pos: [2]int) -> UiBox; -UiCreateBoxProc :: proc "c" (ui_context: rawptr, label: cstring) -> UiBox; -UiRectProc :: proc "c" (ui_context: rawptr, label: cstring, background: bool, border: bool, axis: UiAxis, size: [2]UiSemanticSize) -> UiBox; -UiSimpleProc :: proc "c" (ui_context: rawptr, label: cstring) -> UiInteraction; -UiBufferProc :: proc "c" (ui_context: rawptr, buffer: rawptr, show_line_numbers: bool); -UiBufferIndexProc :: proc "c" (ui_context: rawptr, buffer: int, show_line_numbers: bool); -Ui :: struct { - ui_context: rawptr, - - push_parent: UiPushParentProc, - pop_parent: UiPopParentProc, - - spacer: UiSimpleProc, - floating: UiFloatingProc, - rect: UiRectProc, - - button: UiSimpleProc, - label: UiSimpleProc, - - buffer: UiBufferProc, - buffer_from_index: UiBufferIndexProc, -} - -OnColorBufferProc :: proc "c" (plugin: Plugin, buffer: rawptr); -InputGroupProc :: proc "c" (plugin: Plugin, input_map: rawptr); -InputActionProc :: proc "c" (plugin: Plugin); -OnHookProc :: proc "c" (plugin: Plugin, buffer: rawptr); - -WindowInputProc :: proc "c" (plugin: Plugin, window: rawptr); -WindowDrawProc :: proc "c" (plugin: Plugin, window: rawptr); -WindowGetBufferProc :: proc(plugin: Plugin, window: rawptr) -> rawptr; -WindowFreeProc :: proc "c" (plugin: Plugin, window: rawptr); -Plugin :: struct { - state: rawptr, - iter: Iterator, - buffer: Buffer, - ui: Ui, - - register_hook: proc "c" (hook: Hook, on_hook: OnHookProc), - register_highlighter: proc "c" (extension: cstring, on_color_buffer: OnColorBufferProc), - - register_input_group: proc "c" (input_map: rawptr, key: Key, register_group: InputGroupProc), - register_input: proc "c" (input_map: rawptr, key: Key, input_action: InputActionProc, description: cstring), - - create_window: proc "c" (user_data: rawptr, register_group: InputGroupProc, draw_proc: WindowDrawProc, free_window_proc: WindowFreeProc, get_buffer_proc: WindowGetBufferProc) -> rawptr, - get_window: proc "c" () -> rawptr, - - request_window_close: proc "c" (), - get_screen_width: proc "c" () -> int, - get_screen_height: proc "c" () -> int, - get_font_width: proc "c" () -> int, - get_font_height: proc "c" () -> int, - get_current_directory: proc "c" () -> cstring, - enter_insert_mode: proc "c" (), - - draw_rect: proc "c" (x: i32, y: i32, width: i32, height: i32, color: theme.PaletteColor), - draw_text: proc "c" (text: cstring, x: f32, y: f32, color: theme.PaletteColor), - draw_buffer_from_index: proc "c" (buffer_index: int, x: int, y: int, glyph_buffer_width: int, glyph_buffer_height: int, show_line_numbers: bool), - draw_buffer: proc "c" (buffer: rawptr, x: int, y: int, glyph_buffer_width: int, glyph_buffer_height: int, show_line_numbers: bool), -} - -Hook :: enum { - BufferInput = 0, - Draw = 1, -} - -Key :: enum { - UNKNOWN = 0, - ENTER = 13, - ESCAPE = 27, - BACKSPACE = 8, - TAB = 9, - SPACE = 32, - EXCLAIM = 33, - QUOTEDBL = 34, - HASH = 35, - PERCENT = 37, - DOLLAR = 36, - AMPERSAND = 38, - QUOTE = 39, - LEFTPAREN = 40, - RIGHTPAREN = 41, - ASTERISK = 42, - PLUS = 43, - COMMA = 44, - MINUS = 45, - PERIOD = 46, - SLASH = 47, - NUM0 = 48, - NUM1 = 49, - NUM2 = 50, - NUM3 = 51, - NUM4 = 52, - NUM5 = 53, - NUM6 = 54, - NUM7 = 55, - NUM8 = 56, - NUM9 = 57, - COLON = 58, - SEMICOLON = 59, - LESS = 60, - EQUAL = 61, - GREATER = 62, - QUESTION = 63, - AT = 64, - LEFTBRACKET = 91, - BACKSLASH = 92, - RIGHTBRACKET = 93, - CARET = 94, - UNDERSCORE = 95, - BACKQUOTE = 96, - A = 97, - B = 98, - C = 99, - D = 100, - E = 101, - F = 102, - G = 103, - H = 104, - I = 105, - J = 106, - K = 107, - L = 108, - M = 109, - N = 110, - O = 111, - P = 112, - Q = 113, - R = 114, - S = 115, - T = 116, - U = 117, - V = 118, - W = 119, - X = 120, - Y = 121, - Z = 122, - CAPSLOCK = 1073741881, - F1 = 1073741882, - F2 = 1073741883, - F3 = 1073741884, - F4 = 1073741885, - F5 = 1073741886, - F6 = 1073741887, - F7 = 1073741888, - F8 = 1073741889, - F9 = 1073741890, - F10 = 1073741891, - F11 = 1073741892, - F12 = 1073741893, - PRINTSCREEN = 1073741894, - SCROLLLOCK = 1073741895, - PAUSE = 1073741896, - INSERT = 1073741897, - HOME = 1073741898, - PAGEUP = 1073741899, - DELETE = 127, - END = 1073741901, - PAGEDOWN = 1073741902, - RIGHT = 1073741903, - LEFT = 1073741904, - DOWN = 1073741905, - UP = 1073741906, - NUMLOCKCLEAR = 1073741907, - KP_DIVIDE = 1073741908, - KP_MULTIPLY = 1073741909, - KP_MINUS = 1073741910, - KP_PLUS = 1073741911, - KP_ENTER = 1073741912, - KP_1 = 1073741913, - KP_2 = 1073741914, - KP_3 = 1073741915, - KP_4 = 1073741916, - KP_5 = 1073741917, - KP_6 = 1073741918, - KP_7 = 1073741919, - KP_8 = 1073741920, - KP_9 = 1073741921, - KP_0 = 1073741922, - KP_PERIOD = 1073741923, - APPLICATION = 1073741925, - POWER = 1073741926, - KP_EQUALS = 1073741927, - F13 = 1073741928, - F14 = 1073741929, - F15 = 1073741930, - F16 = 1073741931, - F17 = 1073741932, - F18 = 1073741933, - F19 = 1073741934, - F20 = 1073741935, - F21 = 1073741936, - F22 = 1073741937, - F23 = 1073741938, - F24 = 1073741939, - EXECUTE = 1073741940, - HELP = 1073741941, - MENU = 1073741942, - SELECT = 1073741943, - STOP = 1073741944, - AGAIN = 1073741945, - UNDO = 1073741946, - CUT = 1073741947, - COPY = 1073741948, - PASTE = 1073741949, - FIND = 1073741950, - MUTE = 1073741951, - VOLUMEUP = 1073741952, - VOLUMEDOWN = 1073741953, - KP_COMMA = 1073741957, - KP_EQUALSAS400 = 1073741958, - ALTERASE = 1073741977, - SYSREQ = 1073741978, - CANCEL = 1073741979, - CLEAR = 1073741980, - PRIOR = 1073741981, - RETURN2 = 1073741982, - SEPARATOR = 1073741983, - OUT = 1073741984, - OPER = 1073741985, - CLEARAGAIN = 1073741986, - CRSEL = 1073741987, - EXSEL = 1073741988, - KP_00 = 1073742000, - KP_000 = 1073742001, - THOUSANDSSEPARATOR = 1073742002, - DECIMALSEPARATOR = 1073742003, - CURRENCYUNIT = 1073742004, - CURRENCYSUBUNIT = 1073742005, - KP_LEFTPAREN = 1073742006, - KP_RIGHTPAREN = 1073742007, - KP_LEFTBRACE = 1073742008, - KP_RIGHTBRACE = 1073742009, - KP_TAB = 1073742010, - KP_BACKSPACE = 1073742011, - KP_A = 1073742012, - KP_B = 1073742013, - KP_C = 1073742014, - KP_D = 1073742015, - KP_E = 1073742016, - KP_F = 1073742017, - KP_XOR = 1073742018, - KP_POWER = 1073742019, - KP_PERCENT = 1073742020, - KP_LESS = 1073742021, - KP_GREATER = 1073742022, - KP_AMPERSAND = 1073742023, - KP_DBLAMPERSAND = 1073742024, - KP_VERTICALBAR = 1073742025, - KP_DBLVERTICALBAR = 1073742026, - KP_COLON = 1073742027, - KP_HASH = 1073742028, - KP_SPACE = 1073742029, - KP_AT = 1073742030, - KP_EXCLAM = 1073742031, - KP_MEMSTORE = 1073742032, - KP_MEMRECALL = 1073742033, - KP_MEMCLEAR = 1073742034, - KP_MEMADD = 1073742035, - KP_MEMSUBTRACT = 1073742036, - KP_MEMMULTIPLY = 1073742037, - KP_MEMDIVIDE = 1073742038, - KP_PLUSMINUS = 1073742039, - KP_CLEAR = 1073742040, - KP_CLEARENTRY = 1073742041, - KP_BINARY = 1073742042, - KP_OCTAL = 1073742043, - KP_DECIMAL = 1073742044, - KP_HEXADECIMAL = 1073742045, - LCTRL = 1073742048, - LSHIFT = 1073742049, - LALT = 1073742050, - LGUI = 1073742051, - RCTRL = 1073742052, - RSHIFT = 1073742053, - RALT = 1073742054, - RGUI = 1073742055, - MODE = 1073742081, - AUDIONEXT = 1073742082, - AUDIOPREV = 1073742083, - AUDIOSTOP = 1073742084, - AUDIOPLAY = 1073742085, - AUDIOMUTE = 1073742086, - MEDIASELECT = 1073742087, - WWW = 1073742088, - MAIL = 1073742089, - CALCULATOR = 1073742090, - COMPUTER = 1073742091, - AC_SEARCH = 1073742092, - AC_HOME = 1073742093, - AC_BACK = 1073742094, - AC_FORWARD = 1073742095, - AC_STOP = 1073742096, - AC_REFRESH = 1073742097, - AC_BOOKMARKS = 1073742098, - BRIGHTNESSDOWN = 1073742099, - BRIGHTNESSUP = 1073742100, - DISPLAYSWITCH = 1073742101, - KBDILLUMTOGGLE = 1073742102, - KBDILLUMDOWN = 1073742103, - KBDILLUMUP = 1073742104, - EJECT = 1073742105, - SLEEP = 1073742106, - APP1 = 1073742107, - APP2 = 1073742108, - AUDIOREWIND = 1073742109, - AUDIOFASTFORWARD = 1073742110, -} - - -load_proc_address :: proc(lib_path: string, library: dynlib.Library, symbol: string, $ProcType: typeid) -> ProcType - where intrinsics.type_is_proc(ProcType) -{ - if address, found := dynlib.symbol_address(library, symbol); found { - return transmute(ProcType)address; - } else { - log.warn("Could not find symbol", symbol, "in library", lib_path); - } - - return nil; -} - -try_load_plugin :: proc(lib_path: string) -> (plugin: Interface, success: bool) { - library, ok := dynlib.load_library(lib_path) - if !ok { - return {}, false; - } - - interface := Interface { - on_initialize = load_proc_address(lib_path, library, "OnInitialize", OnInitializeProc), - on_exit = load_proc_address(lib_path, library, "OnExit", OnExitProc), - on_draw = load_proc_address(lib_path, library, "OnDraw", OnDrawProc), - }; - - if interface.on_initialize == nil do return interface, false; - if interface.on_exit == nil do return interface, false; - - return interface, true -} diff --git a/src/ui/imm.odin b/src/ui/imm.odin deleted file mode 100644 index 34a6a15..0000000 --- a/src/ui/imm.odin +++ /dev/null @@ -1,729 +0,0 @@ -package ui - -import "core:fmt" -import "core:strings" -import "core:math" -import "core:log" -import "vendor:sdl2" - -import "../core" -import "../theme" - -Context :: struct { - root: ^Box, - current_parent: ^Box, - persistent: map[string]^Box, - current_interaction_index: int, - - clips: [dynamic]Rect, - renderer: ^sdl2.Renderer, - - last_mouse_x: int, - last_mouse_y: int, - - mouse_x: int, - mouse_y: int, - - mouse_left_down: bool, - last_mouse_left_down: bool, - - mouse_right_down: bool, - last_mouse_right_down: bool, -} - -Rect :: struct { - pos: [2]int, - size: [2]int, -} - -Key :: struct { - label: string, - value: int, -} - -Interaction :: struct { - hovering: bool, - clicked: bool, - dragging: bool, - - box_pos: [2]int, - box_size: [2]int, -} - -Flag :: enum { - Clickable, - Hoverable, - Scrollable, - DrawText, - DrawBorder, - DrawBackground, - RoundedBorder, - Floating, - CustomDrawFunc, -} - -SemanticSizeKind :: enum { - FitText = 0, - Exact, - ChildrenSum, - Fill, - PercentOfParent, -} - -SemanticSize :: struct { - kind: SemanticSizeKind, - value: int, -} - -Axis :: enum { - Horizontal = 0, - Vertical = 1, -} - -CustomDrawFunc :: proc(state: ^core.State, box: ^Box, user_data: rawptr); -Box :: struct { - first: ^Box, - last: ^Box, - next: ^Box, - prev: ^Box, - parent: ^Box, - - key: Key, - last_interacted_index: int, - - flags: bit_set[Flag], - - label: string, - - axis: Axis, - semantic_size: [2]SemanticSize, - computed_size: [2]int, - computed_child_size: [2]int, - computed_pos: [2]int, - - scroll_offset: int, - - hot: int, - active: int, - - custom_draw_func: CustomDrawFunc, - user_data: rawptr, -} - -init :: proc(renderer: ^sdl2.Renderer) -> Context { - root := new(Box); - root.key = gen_key(nil, "root", 69); - root.label = strings.clone("root") - - return Context { - root = root, - current_parent = root, - persistent = make(map[string]^Box), - clips = make([dynamic]Rect), - renderer = renderer, - }; -} - -gen_key :: proc(ctx: ^Context, label: string, value: int) -> Key { - key_label: string; - - if ctx != nil && (ctx.current_parent == nil || len(ctx.current_parent.key.label) < 1) { - key_label = strings.clone(label); - } else if ctx != nil { - key_label = fmt.aprintf("%s:%s", ctx.current_parent.key.label, label); - } else { - key_label = strings.clone(label); - } - - return Key { - label = key_label, - value = value, - }; -} - -@(private) -make_box :: proc(ctx: ^Context, key: Key, label: string, flags: bit_set[Flag], axis: Axis, semantic_size: [2]SemanticSize) -> ^Box { - box: ^Box = nil; - - if cached_box, exists := ctx.persistent[key.label]; exists { - // NOTE(pcleavelin): its important to note that the _cached_ key _is not_ free'd - // as that would invalid the maps reference to the key causing memory leaks because - // the map would think that an entry doesn't exist (in some cases) - delete(key.label) - - if cached_box.last_interacted_index < ctx.current_interaction_index-1 { - box = cached_box; - - box.last_interacted_index = ctx.current_interaction_index; - box.hot = 0; - box.active = 0; - } else { - box = cached_box; - } - } else { - box = new(Box); - ctx.persistent[key.label] = box; - - box.key = key; - box.last_interacted_index = ctx.current_interaction_index; - } - - box.label = strings.clone(label, context.temp_allocator); - - box.first = nil; - box.last = nil; - box.next = nil; - box.prev = ctx.current_parent.last; - box.parent = ctx.current_parent; - box.flags = flags; - box.axis = axis; - box.semantic_size = semantic_size; - - if ctx.current_parent.last != nil { - ctx.current_parent.last.next = box; - } - if ctx.current_parent.first == nil { - ctx.current_parent.first = box; - } - - ctx.current_parent.last = box; - - return box; -} - -make_semantic_size :: proc(kind: SemanticSizeKind, value: int = 0) -> SemanticSize { - return SemanticSize { - kind = kind, - value = value - }; -} - -FitText :[2]SemanticSize: { - SemanticSize { - kind = .FitText, - }, - SemanticSize { - kind = .FitText, - } -}; - -ChildrenSum :[2]SemanticSize: { - SemanticSize { - kind = .ChildrenSum, - }, - SemanticSize { - kind = .ChildrenSum, - } -}; - -Fill :[2]SemanticSize: { - SemanticSize { - kind = .Fill, - }, - SemanticSize { - kind = .Fill, - } -}; - -push_box :: proc(ctx: ^Context, label: string, flags: bit_set[Flag], axis: Axis = .Horizontal, semantic_size: [2]SemanticSize = FitText) -> (^Box, Interaction) { - key := gen_key(ctx, label, 0); - box := make_box(ctx, key, label, flags, axis, semantic_size); - interaction := test_box(ctx, box); - - return box, interaction; -} - -push_parent :: proc(ctx: ^Context, box: ^Box) { - ctx.current_parent = box; - - push_clip(ctx, box.computed_pos, box.computed_size, !(.Floating in box.flags)); -} - -pop_parent :: proc(ctx: ^Context) { - if ctx.current_parent.parent != nil { - ctx.current_parent = ctx.current_parent.parent; - } - - pop_clip(ctx); -} - -test_box :: proc(ctx: ^Context, box: ^Box) -> Interaction { - hovering: bool; - - mouse_is_clicked := !ctx.last_mouse_left_down && ctx.mouse_left_down; - mouse_is_released := ctx.last_mouse_left_down && !ctx.mouse_left_down; - mouse_is_dragging := !mouse_is_clicked && ctx.mouse_left_down && (ctx.last_mouse_x != ctx.mouse_x || ctx.last_mouse_y != ctx.mouse_y); - - if ctx.mouse_x >= box.computed_pos.x && ctx.mouse_x <= box.computed_pos.x + box.computed_size.x && - ctx.mouse_y >= box.computed_pos.y && ctx.mouse_y <= box.computed_pos.y + box.computed_size.y - { - if len(ctx.clips) > 0 { - clip := ctx.clips[len(ctx.clips)-1]; - - if ctx.mouse_x >= clip.pos.x && ctx.mouse_x <= clip.pos.x + clip.size.x && - ctx.mouse_y >= clip.pos.y && ctx.mouse_y <= clip.pos.y + clip.size.y - { - hovering = true; - } else { - hovering = false; - } - } else { - hovering = true; - } - } - - if hovering || box.active > 0 { - box.hot += 1; - } else { - box.hot = 0; - } - - if hovering && mouse_is_clicked && !mouse_is_dragging { - box.active = 1; - } else if hovering && mouse_is_dragging && box.active > 0 { - box.active += 1; - } else if !ctx.mouse_left_down && !mouse_is_released { - box.active = 0; - } - - // TODO: change this to use the scroll wheel input - if .Scrollable in box.flags && box.active > 1 && ctx.mouse_left_down { - box.scroll_offset -= ctx.mouse_y - ctx.last_mouse_y; - - box.scroll_offset = math.min(0, box.scroll_offset); - } - - if box.hot > 0 || box.active > 0 { - box.last_interacted_index = ctx.current_interaction_index; - } - return Interaction { - hovering = .Hoverable in box.flags && (hovering || box.active > 0), - clicked = .Clickable in box.flags && (hovering && mouse_is_released && box.active > 0), - dragging = box.active > 1, - - box_pos = box.computed_pos, - box_size = box.computed_size, - }; -} - -delete_box_children :: proc(ctx: ^Context, box: ^Box, keep_persistent: bool = true) { - iter := BoxIter { box.first, 0 }; - - for box in iterate_box(&iter) { - delete_box(ctx, box, keep_persistent); - } -} - -delete_box :: proc(ctx: ^Context, box: ^Box, keep_persistent: bool = true) { - delete_box_children(ctx, box, keep_persistent); - - if box.last_interacted_index < ctx.current_interaction_index-1 { - delete_key(&ctx.persistent, box.key.label) - } - - if !(box.key.label in ctx.persistent) || !keep_persistent { - delete(box.key.label); - free(box); - } -} - -prune :: proc(ctx: ^Context) { - iter := BoxIter { ctx.root.first, 0 }; - - for box in iterate_box(&iter) { - delete_box_children(ctx, box); - - if !(box.key.label in ctx.persistent) && box != ctx.root { - free(box); - } - } - - ctx.root.first = nil; - ctx.root.last = nil; - ctx.root.next = nil; - ctx.root.prev = nil; - ctx.root.parent = nil; - ctx.current_parent = ctx.root; - - ctx.current_interaction_index += 1; -} - -// TODO: consider not using `ctx` here -ancestor_size :: proc(ctx: ^Context, box: ^Box, axis: Axis) -> int { - if box == nil || box.parent == nil || .Floating in box.flags { - return ctx.root.computed_size[axis]; - } - - switch box.parent.semantic_size[axis].kind { - case .FitText: fallthrough - case .Exact: fallthrough - case .Fill: fallthrough - case .PercentOfParent: - return box.parent.computed_size[axis]; - - case .ChildrenSum: - return ancestor_size(ctx, box.parent, axis); - } - - return 1337; -} - -prev_non_floating_sibling :: proc(ctx: ^Context, box: ^Box) -> ^Box { - if box == nil { - return nil; - } else if box.prev == nil { - return nil; - } else if !(.Floating in box.prev.flags) { - return box.prev; - } else { - return prev_non_floating_sibling(ctx, box.prev); - } -} - -compute_layout :: proc(ctx: ^Context, canvas_size: [2]int, font_width: int, font_height: int, box: ^Box) { - if box == nil { return; } - - axis := Axis.Horizontal; - if box.parent != nil && !(.Floating in box.flags) { - axis = box.parent.axis; - box.computed_pos = box.parent.computed_pos; - box.computed_pos[axis] += box.parent.scroll_offset; - } - - if .Floating in box.flags { - // box.computed_pos = {0,0}; - } else if box.prev != nil { - prev := prev_non_floating_sibling(ctx, box); - - if prev != nil { - box.computed_pos[axis] = prev.computed_pos[axis] + prev.computed_size[axis]; - } - } - - post_compute_size := [2]bool { false, false }; - compute_children := true; - if box == ctx.root { - box.computed_size = canvas_size; - } else { - switch box.semantic_size.x.kind { - case .FitText: { - box.computed_size.x = len(box.label) * font_width; - } - case .Exact: { - box.computed_size.x = box.semantic_size.x.value; - } - case .ChildrenSum: { - post_compute_size[int(Axis.Horizontal)] = true; - } - case .Fill: { - if .Floating in box.flags { - box.computed_size.x = ancestor_size(ctx, box, .Horizontal); - } - } - case .PercentOfParent: { - box.computed_size.x = int(f32(ancestor_size(ctx, box, .Horizontal))*(f32(box.semantic_size.x.value)/100.0)); - } - } - switch box.semantic_size.y.kind { - case .FitText: { - box.computed_size.y = font_height; - } - case .Exact: { - box.computed_size.y = box.semantic_size.y.value; - } - case .ChildrenSum: { - post_compute_size[Axis.Vertical] = true; - } - case .Fill: { - if .Floating in box.flags { - box.computed_size.y = ancestor_size(ctx, box, .Vertical); - } - } - case .PercentOfParent: { - box.computed_size.y = int(f32(ancestor_size(ctx, box, .Vertical))*(f32(box.semantic_size.y.value)/100.0)); - } - } - } - - if true || compute_children { - iter := BoxIter { box.first, 0 }; - child_size: [2]int = {0,0}; - - // NOTE: the number of fills for the opposite axis of this box needs to be 1 - // because it will never get incremented in the loop below and cause a divide by zero - // and the number of fills for the axis of the box needs to start at zero or else it will - // be n+1 causing incorrect sizes - number_of_fills: [2]int = {1,1}; - number_of_fills[box.axis] = 0; - - our_size := box.computed_size; - for axis in 0..<2 { - if box.semantic_size[axis].kind == .ChildrenSum { - if box.computed_size[axis] == 0 { - our_size[axis] = ancestor_size(ctx, box, Axis(axis)) - } else { - our_size[axis] = box.computed_child_size[axis] - } - } - } - - for child in iterate_box(&iter) { - if .Floating in child.flags { continue; } - - compute_layout(ctx, canvas_size, font_width, font_height, child); - if child.semantic_size[box.axis].kind == .Fill { - number_of_fills[box.axis] += 1; - } else { - child_size[box.axis] += child.computed_size[box.axis]; - } - } - - iter = BoxIter { box.first, 0 }; - for child in iterate_box(&iter) { - if !(.Floating in child.flags) { - for axis in 0..<2 { - if child.semantic_size[axis].kind == .Fill { - child.computed_size[axis] = (our_size[axis] - child_size[axis]) / number_of_fills[axis]; - } - } - } - - compute_layout(ctx, canvas_size, font_width, font_height, child); - } - } - - { - box.computed_child_size[Axis.Horizontal] = 0; - - iter := BoxIter { box.first, 0 }; - for child in iterate_box(&iter) { - if .Floating in child.flags { continue; } - - switch box.axis { - case .Horizontal: { - box.computed_child_size[Axis.Horizontal] += child.computed_size[Axis.Horizontal]; - } - case .Vertical: { - if child.computed_size[Axis.Horizontal] > box.computed_child_size[Axis.Horizontal] { - box.computed_child_size[Axis.Horizontal] = child.computed_size[Axis.Horizontal]; - } - } - } - } - } - if post_compute_size[Axis.Horizontal] { - box.computed_size[Axis.Horizontal] = box.computed_child_size[Axis.Horizontal]; - } - - { - box.computed_child_size[Axis.Vertical] = 0; - - iter := BoxIter { box.first, 0 }; - for child in iterate_box(&iter) { - if .Floating in child.flags { continue; } - - switch box.axis { - case .Horizontal: { - if child.computed_size[Axis.Vertical] > box.computed_child_size[Axis.Vertical] { - box.computed_child_size[Axis.Vertical] = child.computed_size[Axis.Vertical]; - } - } - case .Vertical: { - box.computed_child_size[Axis.Vertical] += child.computed_size[Axis.Vertical]; - } - } - } - } - if post_compute_size[Axis.Vertical] { - box.computed_size[Axis.Vertical] = box.computed_child_size[Axis.Vertical]; - } -} - -push_clip :: proc(ctx: ^Context, pos: [2]int, size: [2]int, inside_parent: bool = true) { - rect := Rect { pos, size }; - - if len(ctx.clips) > 0 && inside_parent { - parent_rect := ctx.clips[len(ctx.clips)-1]; - - if rect.pos.x >= parent_rect.pos.x && - rect.pos.y >= parent_rect.pos.y && - rect.pos.x < parent_rect.pos.x + parent_rect.size.x && - rect.pos.y < parent_rect.pos.y + parent_rect.size.y - { - //rect.pos.x = math.max(rect.pos.x, parent_rect.pos.x); - //rect.pos.y = math.max(rect.pos.y, parent_rect.pos.y); - - rect.size.x = math.min(rect.pos.x + rect.size.x, parent_rect.pos.x + parent_rect.size.x); - rect.size.y = math.min(rect.pos.y + rect.size.y, parent_rect.pos.y + parent_rect.size.y); - - rect.size.x -= rect.pos.x; - rect.size.y -= rect.pos.y; - } else { - rect = parent_rect; - } - } - - // sdl2.RenderSetClipRect(ctx.renderer, &sdl2.Rect { - // i32(rect.pos.x), - // i32(rect.pos.y), - // i32(rect.size.x), - // i32(rect.size.y) - // }); - - append(&ctx.clips, rect); -} - -pop_clip :: proc(ctx: ^Context) { - if len(ctx.clips) > 0 { - // rect := pop(&ctx.clips); - - // sdl2.RenderSetClipRect(ctx.renderer, &sdl2.Rect { - // i32(rect.pos.x), - // i32(rect.pos.y), - // i32(rect.size.x), - // i32(rect.size.y) - // }); - } else { - // sdl2.RenderSetClipRect(ctx.renderer, nil); - } -} - -draw :: proc(ctx: ^Context, state: ^core.State, font_width: int, font_height: int, box: ^Box) { - if box == nil { return; } - - push_clip(ctx, box.computed_pos, box.computed_size, !(.Floating in box.flags)); - { - defer pop_clip(ctx); - - if .Hoverable in box.flags && box.hot > 0 { - core.draw_rect_blend( - state, - box.computed_pos.x, - box.computed_pos.y, - box.computed_size.x, - box.computed_size.y, - .Background1, - .Background2, - f32(math.min(box.hot, 20))/20.0 - ); - } else if .DrawBackground in box.flags { - core.draw_rect( - state, - box.computed_pos.x, - box.computed_pos.y, - box.computed_size.x, - box.computed_size.y, - .Background1 - ); - } - - if .DrawText in box.flags { - core.draw_text(state, box.label, box.computed_pos.x, box.computed_pos.y); - } - - if .CustomDrawFunc in box.flags && box.custom_draw_func != nil { - box.custom_draw_func(state, box, box.user_data); - } - - iter := BoxIter { box.first, 0 }; - for child in iterate_box(&iter) { - draw(ctx, state, font_width, font_height, child); - } - } - - push_clip(ctx, box.computed_pos, box.computed_size); - defer pop_clip(ctx); - - if .DrawBorder in box.flags { - core.draw_rect_outline( - state, - box.computed_pos.x, - box.computed_pos.y, - box.computed_size.x, - box.computed_size.y, - .Background4 - ); - } -} - -BoxIter :: struct { - box: ^Box, - index: int, -} - -iterate_box :: proc(iter: ^BoxIter, print: bool = false) -> (box: ^Box, idx: int, cond: bool) { - if iter.box == nil { - return nil, iter.index, false; - } - - box = iter.box; - idx = iter.index; - - iter.box = iter.box.next; - iter.index += 1; - - return box, iter.index, true; -} - -debug_print :: proc(ctx: ^Context, box: ^Box, depth: int = 0) { - iter := BoxIter { box.first, 0 }; - - for box, idx in iterate_box(&iter, true) { - for _ in 0..<(depth*6) { - log.debug("-"); - } - if depth > 0 { - log.debug(">"); - } - log.debug(idx, "Box _", box.label, "#", box.key.label, "ptr", transmute(rawptr)box); //, "_ first", transmute(rawptr)box.first, "parent", transmute(rawptr)box.parent, box.computed_size); - debug_print(ctx, box, depth+1); - } - - if depth == 0 { - log.debug("persistent"); - for p in ctx.persistent { - log.debug(p); - } - } -} - -spacer :: proc(ctx: ^Context, label: string, flags: bit_set[Flag] = {}, semantic_size: [2]SemanticSize = {{.Fill, 0}, {.Fill,0}}) -> Interaction { - box, interaction := push_box(ctx, label, flags, semantic_size = semantic_size); - - return interaction; -} - -push_floating :: proc(ctx: ^Context, label: string, pos: [2]int, flags: bit_set[Flag] = {.Floating}, axis: Axis = .Horizontal, semantic_size: [2]SemanticSize = Fill) -> (^Box, Interaction) { - box, interaction := push_box(ctx, label, flags, semantic_size = semantic_size); - box.computed_pos = pos; - - return box, interaction; -} - -push_rect :: proc(ctx: ^Context, label: string, background: bool = true, border: bool = true, axis: Axis = .Vertical, semantic_size: [2]SemanticSize = Fill) -> (^Box, Interaction) { - return push_box(ctx, label, {.DrawBackground if background else nil, .DrawBorder if border else nil}, axis, semantic_size = semantic_size); -} - -label :: proc(ctx: ^Context, label: string) -> Interaction { - box, interaction := push_box(ctx, label, {.DrawText}); - - return interaction; -} - -button :: proc(ctx: ^Context, label: string) -> Interaction { - return advanced_button(ctx, label); -} - -advanced_button :: proc(ctx: ^Context, label: string, flags: bit_set[Flag] = {.Clickable, .Hoverable, .DrawText, .DrawBorder, .DrawBackground}, semantic_size: [2]SemanticSize = FitText) -> Interaction { - box, interaction := push_box(ctx, label, flags, semantic_size = semantic_size); - - return interaction; -} - -custom :: proc(ctx: ^Context, label: string, draw_func: CustomDrawFunc, user_data: rawptr) -> Interaction { - box, interaction := push_box(ctx, label, {.CustomDrawFunc}, semantic_size = { make_semantic_size(.Fill), make_semantic_size(.Fill) }); - box.custom_draw_func = draw_func; - box.user_data = user_data; - - return interaction; -} diff --git a/src/ui/ui.odin b/src/ui/ui.odin index d88ee93..e560d01 100644 --- a/src/ui/ui.odin +++ b/src/ui/ui.odin @@ -13,6 +13,8 @@ State :: struct { num_prev: int, curr_elements: []UI_Element, prev_elements: []UI_Element, + + max_size: [2]int, } UI_Element :: struct { @@ -134,7 +136,11 @@ close_element :: proc(state: ^State, loc := #caller_location) -> UI_Layout { child_index = child.next } } - case Grow: { /* Done in the Grow pass */ } + case Grow: { + if _, ok := e.parent.?; !ok { + e.layout.size = state.max_size + } + } } switch v in e.layout.kind.y { @@ -186,10 +192,26 @@ close_element :: proc(state: ^State, loc := #caller_location) -> UI_Layout { } } +@(private) +non_fit_parent_size :: proc(state: ^State, index: int, axis: int) -> [2]int { + if _, ok := state.curr_elements[index].layout.kind[axis].(Fit); ok { + if parent_index, ok := state.curr_elements[index].parent.?; ok { + return non_fit_parent_size(state, parent_index, axis) + } else { + return state.max_size + } + } else { + return state.curr_elements[index].layout.size + } +} + @(private) grow_children :: proc(state: ^State, index: int) { e := &state.curr_elements[index] + x_e := non_fit_parent_size(state, index, 0); + y_e := non_fit_parent_size(state, index, 1); + children_size: [2]int num_growing: [2]int @@ -220,7 +242,7 @@ grow_children :: proc(state: ^State, index: int) { } if num_growing.x > 0 || num_growing.y > 0 { - remaining_size := e.layout.size - children_size + remaining_size := [2]int{ x_e.x, y_e.y } - children_size to_grow: [2]int to_grow.x = 0 if num_growing.x < 1 else remaining_size.x/num_growing.x to_grow.y = 0 if num_growing.y < 1 else remaining_size.y/num_growing.y @@ -318,7 +340,7 @@ compute_layout_2 :: proc(state: ^State) { } } -new_draw :: proc(state: ^State, core_state: ^core.State) { +draw :: proc(state: ^State, core_state: ^core.State) { for i in 0..