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
|
all: editor
|
||||||
|
|
||||||
editor: src/*.odin # grep odin_highlighter
|
editor: src/**/*.odin
|
||||||
# odin build src/ -out:bin/editor.o -build-mode:obj -debug -lld
|
mkdir -p bin
|
||||||
# dsymutil bin/editor.o -o bin/editor.dSYM
|
odin build src/ -out:bin/editor -debug
|
||||||
../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/
|
|
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 "vendor:sdl2"
|
||||||
import lua "vendor:lua/5.4"
|
import lua "vendor:lua/5.4"
|
||||||
|
|
||||||
import "../plugin"
|
|
||||||
|
|
||||||
Mode :: enum {
|
Mode :: enum {
|
||||||
Normal,
|
Normal,
|
||||||
Insert,
|
Insert,
|
||||||
Visual,
|
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;
|
EditorCommandList :: map[string][dynamic]EditorCommand;
|
||||||
State :: struct {
|
State :: struct {
|
||||||
ctx: runtime.Context,
|
ctx: runtime.Context,
|
||||||
|
@ -82,10 +41,6 @@ State :: struct {
|
||||||
|
|
||||||
log_buffer: FileBuffer,
|
log_buffer: FileBuffer,
|
||||||
|
|
||||||
window: ^Window,
|
|
||||||
new_window: Maybe(NewWindow),
|
|
||||||
should_close_window: bool,
|
|
||||||
|
|
||||||
input_map: InputMap,
|
input_map: InputMap,
|
||||||
current_input_map: ^InputActions,
|
current_input_map: ^InputActions,
|
||||||
|
|
||||||
|
@ -95,13 +50,6 @@ State :: struct {
|
||||||
|
|
||||||
active_panels: [128]Maybe(Panel),
|
active_panels: [128]Maybe(Panel),
|
||||||
panel_catalog: [dynamic]PanelId,
|
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 {
|
EditorCommand :: struct {
|
||||||
|
@ -120,26 +68,13 @@ EditorCommandArgument :: union #no_nil {
|
||||||
i32
|
i32
|
||||||
}
|
}
|
||||||
|
|
||||||
PanelId :: union #no_nil {
|
PanelId :: union {
|
||||||
LuaPanelId,
|
|
||||||
LibPanelId,
|
LibPanelId,
|
||||||
}
|
}
|
||||||
Panel :: union #no_nil {
|
Panel :: union {
|
||||||
LuaPanel,
|
|
||||||
LibPanel,
|
LibPanel,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
LuaPanelId :: struct {
|
|
||||||
id: string,
|
|
||||||
name: string,
|
|
||||||
}
|
|
||||||
LuaPanel :: struct {
|
|
||||||
panel_id: LuaPanelId,
|
|
||||||
index: i32,
|
|
||||||
render_ref: i32
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO
|
// TODO
|
||||||
LibPanelId :: struct {}
|
LibPanelId :: struct {}
|
||||||
LibPanel :: struct {}
|
LibPanel :: struct {}
|
||||||
|
@ -164,30 +99,8 @@ buffer_from_index :: proc(state: ^State, buffer_index: int) -> ^FileBuffer {
|
||||||
return &state.buffers[buffer_index];
|
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);
|
EditorAction :: proc(state: ^State);
|
||||||
InputGroup :: union {LuaEditorAction, PluginEditorAction, EditorAction, InputActions}
|
InputGroup :: union {EditorAction, InputActions}
|
||||||
Action :: struct {
|
Action :: struct {
|
||||||
action: InputGroup,
|
action: InputGroup,
|
||||||
description: string,
|
description: string,
|
||||||
|
@ -196,8 +109,8 @@ InputMap :: struct {
|
||||||
mode: map[Mode]InputActions,
|
mode: map[Mode]InputActions,
|
||||||
}
|
}
|
||||||
InputActions :: struct {
|
InputActions :: struct {
|
||||||
key_actions: map[plugin.Key]Action,
|
key_actions: map[Key]Action,
|
||||||
ctrl_key_actions: map[plugin.Key]Action,
|
ctrl_key_actions: map[Key]Action,
|
||||||
}
|
}
|
||||||
|
|
||||||
new_input_map :: proc() -> InputMap {
|
new_input_map :: proc() -> InputMap {
|
||||||
|
@ -217,8 +130,8 @@ new_input_map :: proc() -> InputMap {
|
||||||
|
|
||||||
new_input_actions :: proc() -> InputActions {
|
new_input_actions :: proc() -> InputActions {
|
||||||
input_actions := InputActions {
|
input_actions := InputActions {
|
||||||
key_actions = make(map[plugin.Key]Action),
|
key_actions = make(map[Key]Action),
|
||||||
ctrl_key_actions = make(map[plugin.Key]Action),
|
ctrl_key_actions = make(map[Key]Action),
|
||||||
}
|
}
|
||||||
|
|
||||||
return input_actions;
|
return input_actions;
|
||||||
|
@ -234,22 +147,7 @@ delete_input_actions :: proc(input_map: ^InputActions) {
|
||||||
delete(input_map.ctrl_key_actions);
|
delete(input_map.ctrl_key_actions);
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE(pcleavelin): might be a bug in the compiler where it can't coerce
|
register_key_action_single :: proc(input_map: ^InputActions, key: Key, action: EditorAction, description: string = "") {
|
||||||
// `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 = "") {
|
|
||||||
if ok := key in input_map.key_actions; ok {
|
if ok := key in input_map.key_actions; ok {
|
||||||
// TODO: log that key is already registered
|
// TODO: log that key is already registered
|
||||||
log.error("key already registered with single action", key);
|
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 {
|
if ok := key in input_map.key_actions; ok {
|
||||||
// TODO: log that key is already registered
|
// TODO: log that key is already registered
|
||||||
fmt.eprintln("key already registered with single action", key);
|
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 {
|
if ok := key in input_map.key_actions; ok {
|
||||||
// TODO: log that key is already registered
|
// TODO: log that key is already registered
|
||||||
log.error("key already registered with single action", key);
|
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 {
|
if ok := key in input_map.key_actions; ok {
|
||||||
// TODO: log that key is already registered
|
// TODO: log that key is already registered
|
||||||
log.error("key already registered with single action", key);
|
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_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) {
|
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
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
register_panel_lua :: proc(state: ^State, name: string, id: string) {
|
Key :: enum {
|
||||||
append(&state.panel_catalog, LuaPanelId {
|
UNKNOWN = 0,
|
||||||
id = id,
|
ENTER = 13,
|
||||||
name = name,
|
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 "core:strings"
|
||||||
|
|
||||||
import "../theme"
|
import "../theme"
|
||||||
import "../plugin"
|
|
||||||
|
|
||||||
ScrollDir :: enum {
|
ScrollDir :: enum {
|
||||||
Up,
|
Up,
|
||||||
|
@ -752,32 +751,6 @@ next_buffer :: proc(state: ^State, prev_buffer: ^int) -> int {
|
||||||
return index;
|
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) {
|
free_file_buffer :: proc(buffer: ^FileBuffer) {
|
||||||
delete(buffer.original_content);
|
delete(buffer.original_content);
|
||||||
delete(buffer.added_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) {
|
draw_file_buffer :: proc(state: ^State, buffer: ^FileBuffer, x: int, y: int, show_line_numbers: bool = true) {
|
||||||
update_glyph_buffer(buffer);
|
update_glyph_buffer(buffer);
|
||||||
if highlighter, exists := state.highlighters[buffer.extension]; exists {
|
|
||||||
highlighter(state.plugin_vtable, buffer);
|
// TODO: syntax highlighting
|
||||||
}
|
|
||||||
|
|
||||||
padding := 0;
|
padding := 0;
|
||||||
if show_line_numbers {
|
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
|
|
||||||
}
|
|
1140
src/main.odin
1140
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,
|
num_prev: int,
|
||||||
curr_elements: []UI_Element,
|
curr_elements: []UI_Element,
|
||||||
prev_elements: []UI_Element,
|
prev_elements: []UI_Element,
|
||||||
|
|
||||||
|
max_size: [2]int,
|
||||||
}
|
}
|
||||||
|
|
||||||
UI_Element :: struct {
|
UI_Element :: struct {
|
||||||
|
@ -134,7 +136,11 @@ close_element :: proc(state: ^State, loc := #caller_location) -> UI_Layout {
|
||||||
child_index = child.next
|
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 {
|
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)
|
@(private)
|
||||||
grow_children :: proc(state: ^State, index: int) {
|
grow_children :: proc(state: ^State, index: int) {
|
||||||
e := &state.curr_elements[index]
|
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
|
children_size: [2]int
|
||||||
num_growing: [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 {
|
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: [2]int
|
||||||
to_grow.x = 0 if num_growing.x < 1 else remaining_size.x/num_growing.x
|
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
|
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 {
|
for i in 0..<state.num_curr {
|
||||||
e := &state.curr_elements[i]
|
e := &state.curr_elements[i]
|
||||||
|
|
||||||
|
|
50
todo.md
50
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
|
- Save/Load files
|
||||||
- Undo/Redo
|
- Undo/Redo
|
||||||
- Edit History Tree
|
- [ ] Edit History Tree
|
||||||
|
- [ ] Undo history saved to disk
|
||||||
- Finish selections
|
- Finish selections
|
||||||
- [x] Guarantee that start and end are always ordered
|
- [x] Guarantee that start and end are always ordered
|
||||||
- Add in text actions
|
- Add in text actions
|
||||||
- Yank
|
- [ ] Yank
|
||||||
- [x] Delete
|
- [x] Delete
|
||||||
- [x] Change
|
- [x] Change
|
||||||
- Virtual Whitespace
|
- Virtual Whitespace
|
||||||
|
@ -17,24 +35,6 @@
|
||||||
- Vim's f and F movement commands
|
- Vim's f and F movement commands
|
||||||
- Vim's r command
|
- Vim's r command
|
||||||
- Command Search and Execution
|
- Command Search and Execution
|
||||||
|
- Refactor to remove generics added specifically for plugins
|
||||||
- Palette based UI?
|
- Palette based UI?
|
||||||
- [ ] Registering Plugin Commands that can be run in palette and via other plugins
|
- Persist end of line cursor position
|
||||||
- [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