remove plugin support
parent
f03cbcd06d
commit
d5db929b3f
|
@ -0,0 +1,15 @@
|
|||
{
|
||||
"image": "mcr.microsoft.com/devcontainers/cpp:ubuntu",
|
||||
"customizations": {
|
||||
"vscode": {
|
||||
"extensions": [
|
||||
"danielgavin.ols"
|
||||
]
|
||||
}
|
||||
},
|
||||
"features": {
|
||||
"./odin-feature": {
|
||||
"version": "latest"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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"
|
||||
}
|
||||
}
|
|
@ -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
|
14
Makefile
14
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
|
BIN
liblua5.4.a
BIN
liblua5.4.a
Binary file not shown.
|
@ -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"
|
|
@ -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]
|
|
@ -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<Cow<'_, str>> {
|
||||
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<BufferInfo> {
|
||||
if buffer.internal.is_null() {
|
||||
None
|
||||
} else {
|
||||
Some((self.get_buffer_info)(buffer))
|
||||
}
|
||||
}
|
||||
pub fn open_buffer(&self, path: impl AsRef<Path>, 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<UiSemanticSize> 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<Self::Item> {
|
||||
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<Self::Item> {
|
||||
if self.index == -1 {
|
||||
return None;
|
||||
}
|
||||
|
||||
Some((self.next_fn)(&mut self.index))
|
||||
}
|
||||
}
|
||||
|
||||
impl Plugin {
|
||||
pub fn get_current_directory(&self) -> Cow<str> {
|
||||
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<W>(
|
||||
&self,
|
||||
window: W,
|
||||
register_group: InputGroupProc,
|
||||
draw_proc: WindowDrawProc,
|
||||
free_window_proc: WindowFreeProc,
|
||||
get_buffer_proc: Option<WindowGetBufferProc>,
|
||||
) {
|
||||
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<InputMap>,
|
||||
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,
|
||||
}
|
|
@ -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
|
|
@ -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"
|
|
@ -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" }
|
|
@ -1,3 +0,0 @@
|
|||
[toolchain]
|
||||
channel = "nightly-2024-01-24"
|
||||
|
|
@ -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<T: std::fmt::Display>(message: T) -> Self {
|
||||
eprintln!("{message}");
|
||||
|
||||
Self::StandardError
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Match {
|
||||
text: Vec<u8>,
|
||||
path: String,
|
||||
line_number: Option<u64>,
|
||||
column: u64,
|
||||
}
|
||||
impl Match {
|
||||
fn from_sink_match_with_path(
|
||||
value: &grep::searcher::SinkMatch<'_>,
|
||||
path: Option<String>,
|
||||
) -> Result<Self, SimpleSinkError> {
|
||||
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<String>,
|
||||
matches: Vec<Match>,
|
||||
}
|
||||
impl Sink for SimpleSink {
|
||||
type Error = SimpleSinkError;
|
||||
|
||||
fn matched(
|
||||
&mut self,
|
||||
_searcher: &grep::searcher::Searcher,
|
||||
mat: &grep::searcher::SinkMatch<'_>,
|
||||
) -> Result<bool, Self::Error> {
|
||||
self.matches.push(Match::from_sink_match_with_path(
|
||||
mat,
|
||||
self.current_path.clone(),
|
||||
)?);
|
||||
|
||||
Ok(true)
|
||||
}
|
||||
}
|
||||
|
||||
fn search(pattern: &str, paths: &[OsString]) -> Result<SimpleSink, Box<dyn Error>> {
|
||||
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<OsString>)),
|
||||
Quit,
|
||||
}
|
||||
|
||||
struct GrepWindow {
|
||||
sink: Option<SimpleSink>,
|
||||
selected_match: usize,
|
||||
top_index: usize,
|
||||
input_buffer: Option<Buffer>,
|
||||
|
||||
tx: Sender<Message>,
|
||||
rx: Receiver<SimpleSink>,
|
||||
}
|
||||
|
||||
#[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::<GrepWindow>() } {
|
||||
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::<GrepWindow>() } {
|
||||
|
||||
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::<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 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::<GrepWindow>::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<SimpleSink>, rx: Receiver<Message>) {
|
||||
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::<GrepWindow>::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::<GrepWindow>() } {
|
||||
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::<GrepWindow>::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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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
|
|
@ -1 +0,0 @@
|
|||
stable
|
|
@ -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,
|
||||
}
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
1244
src/lua/lua.odin
1244
src/lua/lua.odin
File diff suppressed because it is too large
Load Diff
|
@ -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
|
||||
}
|
1126
src/main.odin
1126
src/main.odin
File diff suppressed because it is too large
Load Diff
|
@ -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
|
||||
}
|
729
src/ui/imm.odin
729
src/ui/imm.odin
|
@ -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;
|
||||
}
|
|
@ -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..<state.num_curr {
|
||||
e := &state.curr_elements[i]
|
||||
|
||||
|
|
48
todo.md
48
todo.md
|
@ -1,14 +1,32 @@
|
|||
- Get input maps working with `spawn_floating_window`
|
||||
|
||||
|
||||
# Bugs
|
||||
- Fix crash when cursor is over a new-line
|
||||
- Fix jumping forward a word jumping past consecutive brackets
|
||||
|
||||
# Planned Features
|
||||
- LSP Integration
|
||||
- [ ] Language Server Configurations
|
||||
- [ ] Diagnostics
|
||||
- [ ] In-line errors
|
||||
- [ ] Go-to Definition/
|
||||
- [ ] Find references
|
||||
- Vim-like Macro replays
|
||||
- Re-implement lost features from Plugins
|
||||
- [ ] Syntax Highlighting
|
||||
- [ ] Integrate tree-sitter
|
||||
- [ ] Bootleg Telescope
|
||||
- [ ] Grepping Files
|
||||
- [ ] Open Buffer Search
|
||||
- Re-write the UI (again)
|
||||
- [x] New UI
|
||||
- [ ] Styling
|
||||
- Save/Load files
|
||||
- Undo/Redo
|
||||
- Edit History Tree
|
||||
- [ ] Edit History Tree
|
||||
- [ ] Undo history saved to disk
|
||||
- Finish selections
|
||||
- [x] Guarantee that start and end are always ordered
|
||||
- Add in text actions
|
||||
- Yank
|
||||
- [ ] Yank
|
||||
- [x] Delete
|
||||
- [x] Change
|
||||
- Virtual Whitespace
|
||||
|
@ -17,24 +35,6 @@
|
|||
- Vim's f and F movement commands
|
||||
- Vim's r command
|
||||
- Command Search and Execution
|
||||
- Refactor to remove generics added specifically for plugins
|
||||
- Palette based UI?
|
||||
- [ ] Registering Plugin Commands that can be run in palette and via other plugins
|
||||
- [x] A way to query these commands by-plugin
|
||||
- Re-write the UI (again)
|
||||
- Separate ui components from layout
|
||||
- Re-do plugin system
|
||||
- Potentially have a C# plugins system? Use it instead of Lua? (probably not)
|
||||
- Re-do dylib plugin system
|
||||
- Re-do Lua plugin system
|
||||
- Core Events ~Define ultra-core common API~
|
||||
- ~3rd-party core UI modifications must abide by this API (for example, another plugin must be able to open a file and have it be focused)~
|
||||
- e.g. Open File, currently focused UI panel recieves event
|
||||
- Ability to probe core for installed plugins and their version
|
||||
- Plugins can register to be UI components that the user can define where they are laid out
|
||||
- Persist end of line cursor position
|
||||
- Generate key mappings from the plugin.Key enum
|
||||
- Fix jumping forward a word jumping past consecutive brackets
|
||||
- Re-do highlighter
|
||||
- Use tree-sitter?
|
||||
- Purely run highlighter on glyph-buffer?
|
||||
- Figure out someway to cache multi-line coloring (ex. quotes)
|
||||
|
|
Loading…
Reference in New Issue