the jankiest of implementations
parent
44d3e498a1
commit
9e8e8f4207
5
Makefile
5
Makefile
|
@ -1,7 +1,10 @@
|
|||
all: editor
|
||||
|
||||
editor: src/*.odin rg
|
||||
editor: src/*.odin rg odin_highlighter
|
||||
odin build src/ -out:bin/editor -lld
|
||||
|
||||
odin_highlighter:
|
||||
odin build plugins/odin_highlighter/src/ -build-mode:dll -no-entry-point -out:bin/odin_highlighter
|
||||
|
||||
rg:
|
||||
cargo b --manifest-path=lib-rg/Cargo.toml
|
||||
|
|
|
@ -0,0 +1,260 @@
|
|||
// The default syntax highlighter plugin for Odin
|
||||
package odin_highlighter;
|
||||
|
||||
import "core: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("Hello from the Odin Highlighter Plugin!");
|
||||
|
||||
it := plugin.iter.get_current_buffer_iterator(plugin.state);
|
||||
|
||||
fmt.println("Look I have an iterator!", it);
|
||||
}
|
||||
|
||||
@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();
|
||||
|
||||
color_buffer(plugin);
|
||||
}
|
||||
|
||||
iterate_buffer :: proc(state: rawptr, iter_funcs: Iterator, it: ^BufferIter) -> (character: u8, idx: BufferIndex, cond: bool) {
|
||||
result := iter_funcs.iterate_buffer(state, it);
|
||||
|
||||
return result.char, it.cursor.index, result.should_stop;
|
||||
}
|
||||
|
||||
iterate_buffer_reverse :: proc(state: rawptr, iter_funcs: Iterator, it: ^BufferIter) -> (character: u8, idx: BufferIndex, cond: bool) {
|
||||
result := iter_funcs.iterate_buffer_reverse(state, it);
|
||||
|
||||
return result.char, it.cursor.index, result.should_stop;
|
||||
}
|
||||
|
||||
iterate_buffer_until :: proc(plugin: Plugin, it: ^BufferIter, until_proc: rawptr) {
|
||||
plugin.iter.iterate_buffer_until(plugin.state, it, until_proc);
|
||||
}
|
||||
|
||||
is_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.state, 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(plugin.state, &it) == keyword[keyword_index] {
|
||||
matches = true;
|
||||
}
|
||||
|
||||
break;
|
||||
} else if keyword_index >= len(keyword)-1 {
|
||||
break;
|
||||
} else if it == end {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if matches {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
color_buffer :: proc(plugin: Plugin) {
|
||||
start_it := plugin.iter.get_current_buffer_iterator(plugin.state);
|
||||
it := plugin.iter.get_current_buffer_iterator(plugin.state);
|
||||
|
||||
buffer := plugin.buffer.get_buffer_info(plugin.state);
|
||||
|
||||
for character in iterate_buffer(plugin.state, 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.state, plugin.iter, &start_it);
|
||||
|
||||
character, _, succ := iterate_buffer(plugin.state, plugin.iter, &it);
|
||||
if !succ { break; }
|
||||
|
||||
if character == '/' {
|
||||
iterate_buffer_until(plugin, &it, plugin.iter.until_line_break);
|
||||
plugin.buffer.color_char_at(plugin.state, 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.state, plugin.iter, &start_it);
|
||||
|
||||
// jump into the quoted text
|
||||
iterate_buffer_until(plugin, &it, plugin.iter.until_single_quote);
|
||||
plugin.buffer.color_char_at(plugin.state, start_it.cursor, it.cursor, 12);
|
||||
|
||||
iterate_buffer(plugin.state, 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.state, plugin.iter, &start_it);
|
||||
|
||||
// jump into the quoted text
|
||||
iterate_buffer_until(plugin, &it, plugin.iter.until_double_quote);
|
||||
plugin.buffer.color_char_at(plugin.state, start_it.cursor, it.cursor, 12);
|
||||
|
||||
iterate_buffer(plugin.state, 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.state, plugin.iter, &start_it);
|
||||
it = start_it;
|
||||
|
||||
iterate_buffer_until(plugin, &it, plugin.iter.until_end_of_word);
|
||||
|
||||
if is_keyword(plugin, start_it, it) {
|
||||
plugin.buffer.color_char_at(plugin.state, start_it.cursor, it.cursor, 13);
|
||||
}
|
||||
//else {
|
||||
// break;
|
||||
//}
|
||||
// else if character, _, cond := iterate_peek(&it, iterate_file_buffer); cond {
|
||||
// if character == '(' {
|
||||
// color_character(buffer, start_it.cursor, it.cursor, .Green);
|
||||
// }
|
||||
// }
|
||||
|
||||
iterate_buffer(plugin.state, plugin.iter, &it);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,8 +1,11 @@
|
|||
package core
|
||||
|
||||
import "core:runtime"
|
||||
import "core:fmt"
|
||||
import "vendor:raylib"
|
||||
|
||||
import "../plugin"
|
||||
|
||||
Mode :: enum {
|
||||
Normal,
|
||||
Insert,
|
||||
|
@ -39,6 +42,8 @@ close_window_and_free :: proc(state: ^State) {
|
|||
}
|
||||
|
||||
State :: struct {
|
||||
ctx: runtime.Context,
|
||||
|
||||
mode: Mode,
|
||||
should_close: bool,
|
||||
screen_height: int,
|
||||
|
@ -59,6 +64,8 @@ State :: struct {
|
|||
|
||||
input_map: InputMap,
|
||||
current_input_map: ^InputMap,
|
||||
|
||||
plugins: [dynamic]plugin.Interface,
|
||||
}
|
||||
|
||||
EditorAction :: proc(state: ^State);
|
||||
|
|
|
@ -5,6 +5,7 @@ import "core:runtime"
|
|||
ErrorType :: enum {
|
||||
None,
|
||||
FileIOError,
|
||||
PluginLoadError,
|
||||
}
|
||||
|
||||
Error :: struct {
|
||||
|
|
|
@ -916,7 +916,13 @@ update_glyph_buffer :: proc(buffer: ^FileBuffer) {
|
|||
|
||||
draw_file_buffer :: proc(state: ^State, buffer: ^FileBuffer, x: int, y: int, font: raylib.Font, show_line_numbers: bool = true) {
|
||||
update_glyph_buffer(buffer);
|
||||
color_buffer(buffer);
|
||||
for plugin in state.plugins {
|
||||
if plugin.on_initialize != nil {
|
||||
plugin.on_draw(plugin.plugin);
|
||||
}
|
||||
}
|
||||
//color_buffer(buffer);
|
||||
//update_glyph_buffer(buffer);
|
||||
|
||||
padding := 0;
|
||||
if show_line_numbers {
|
||||
|
|
235
src/main.odin
235
src/main.odin
|
@ -13,6 +13,7 @@ import "vendor:raylib"
|
|||
import "core"
|
||||
import "theme"
|
||||
import "ui"
|
||||
import "plugin"
|
||||
|
||||
State :: core.State;
|
||||
FileBuffer :: core.FileBuffer;
|
||||
|
@ -185,14 +186,221 @@ register_default_input_actions :: proc(input_map: ^core.InputMap) {
|
|||
register_default_go_actions(&(&input_map.key_actions[.G]).action.(core.InputMap));
|
||||
}
|
||||
|
||||
load_plugins :: proc(state: ^State) -> core.Error {
|
||||
if loaded_plugin, succ := plugin.try_load_plugin("bin/odin_highlighter.dylib"); succ {
|
||||
loaded_plugin.plugin = plugin.Plugin {
|
||||
state = cast(rawptr)state,
|
||||
iter = plugin.Iterator {
|
||||
get_current_buffer_iterator = proc "c" (state: rawptr) -> plugin.BufferIter {
|
||||
state := cast(^State)state;
|
||||
context = state.ctx;
|
||||
|
||||
it := core.new_file_buffer_iter(&state.buffers[state.current_buffer]);
|
||||
|
||||
// TODO: make this into a function
|
||||
return plugin.BufferIter {
|
||||
cursor = plugin.Cursor {
|
||||
col = it.cursor.col,
|
||||
line = it.cursor.line,
|
||||
index = plugin.BufferIndex {
|
||||
slice_index = it.cursor.index.slice_index,
|
||||
content_index = it.cursor.index.content_index,
|
||||
}
|
||||
},
|
||||
buffer = cast(rawptr)it.buffer,
|
||||
hit_end = it.hit_end,
|
||||
}
|
||||
},
|
||||
get_char_at_iter = proc "c" (state: rawptr, it: ^plugin.BufferIter) -> u8 {
|
||||
state := cast(^State)state;
|
||||
context = state.ctx;
|
||||
|
||||
internal_it := core.FileBufferIter {
|
||||
cursor = core.Cursor {
|
||||
col = it.cursor.col,
|
||||
line = it.cursor.line,
|
||||
index = core.FileBufferIndex {
|
||||
slice_index = it.cursor.index.slice_index,
|
||||
content_index = it.cursor.index.content_index,
|
||||
}
|
||||
},
|
||||
buffer = cast(^core.FileBuffer)it.buffer,
|
||||
hit_end = it.hit_end,
|
||||
}
|
||||
|
||||
return core.get_character_at_iter(internal_it);
|
||||
},
|
||||
iterate_buffer = proc "c" (state: rawptr, it: ^plugin.BufferIter) -> plugin.IterateResult {
|
||||
state := cast(^State)state;
|
||||
context = state.ctx;
|
||||
|
||||
// TODO: make this into a function
|
||||
internal_it := core.FileBufferIter {
|
||||
cursor = core.Cursor {
|
||||
col = it.cursor.col,
|
||||
line = it.cursor.line,
|
||||
index = core.FileBufferIndex {
|
||||
slice_index = it.cursor.index.slice_index,
|
||||
content_index = it.cursor.index.content_index,
|
||||
}
|
||||
},
|
||||
buffer = cast(^core.FileBuffer)it.buffer,
|
||||
hit_end = it.hit_end,
|
||||
}
|
||||
|
||||
char, _, cond := core.iterate_file_buffer(&internal_it);
|
||||
|
||||
it^ = plugin.BufferIter {
|
||||
cursor = plugin.Cursor {
|
||||
col = internal_it.cursor.col,
|
||||
line = internal_it.cursor.line,
|
||||
index = plugin.BufferIndex {
|
||||
slice_index = internal_it.cursor.index.slice_index,
|
||||
content_index = internal_it.cursor.index.content_index,
|
||||
}
|
||||
},
|
||||
buffer = cast(rawptr)internal_it.buffer,
|
||||
hit_end = internal_it.hit_end,
|
||||
};
|
||||
|
||||
return plugin.IterateResult {
|
||||
char = char,
|
||||
should_stop = cond,
|
||||
};
|
||||
},
|
||||
iterate_buffer_reverse = proc "c" (state: rawptr, it: ^plugin.BufferIter) -> plugin.IterateResult {
|
||||
state := cast(^State)state;
|
||||
context = state.ctx;
|
||||
|
||||
// TODO: make this into a function
|
||||
internal_it := core.FileBufferIter {
|
||||
cursor = core.Cursor {
|
||||
col = it.cursor.col,
|
||||
line = it.cursor.line,
|
||||
index = core.FileBufferIndex {
|
||||
slice_index = it.cursor.index.slice_index,
|
||||
content_index = it.cursor.index.content_index,
|
||||
}
|
||||
},
|
||||
buffer = cast(^core.FileBuffer)it.buffer,
|
||||
hit_end = it.hit_end,
|
||||
}
|
||||
|
||||
char, _, cond := core.iterate_file_buffer_reverse(&internal_it);
|
||||
|
||||
it^ = plugin.BufferIter {
|
||||
cursor = plugin.Cursor {
|
||||
col = internal_it.cursor.col,
|
||||
line = internal_it.cursor.line,
|
||||
index = plugin.BufferIndex {
|
||||
slice_index = internal_it.cursor.index.slice_index,
|
||||
content_index = internal_it.cursor.index.content_index,
|
||||
}
|
||||
},
|
||||
buffer = cast(rawptr)internal_it.buffer,
|
||||
hit_end = internal_it.hit_end,
|
||||
};
|
||||
|
||||
return plugin.IterateResult {
|
||||
char = char,
|
||||
should_stop = cond,
|
||||
};
|
||||
},
|
||||
iterate_buffer_until = proc "c" (state: rawptr, it: ^plugin.BufferIter, until_proc: rawptr) {
|
||||
state := cast(^State)state;
|
||||
context = state.ctx;
|
||||
|
||||
// TODO: make this into a function
|
||||
internal_it := core.FileBufferIter {
|
||||
cursor = core.Cursor {
|
||||
col = it.cursor.col,
|
||||
line = it.cursor.line,
|
||||
index = core.FileBufferIndex {
|
||||
slice_index = it.cursor.index.slice_index,
|
||||
content_index = it.cursor.index.content_index,
|
||||
}
|
||||
},
|
||||
buffer = cast(^core.FileBuffer)it.buffer,
|
||||
hit_end = it.hit_end,
|
||||
}
|
||||
|
||||
core.iterate_file_buffer_until(&internal_it, transmute(core.UntilProc)until_proc);
|
||||
|
||||
it^ = plugin.BufferIter {
|
||||
cursor = plugin.Cursor {
|
||||
col = internal_it.cursor.col,
|
||||
line = internal_it.cursor.line,
|
||||
index = plugin.BufferIndex {
|
||||
slice_index = internal_it.cursor.index.slice_index,
|
||||
content_index = internal_it.cursor.index.content_index,
|
||||
}
|
||||
},
|
||||
buffer = cast(rawptr)internal_it.buffer,
|
||||
hit_end = internal_it.hit_end,
|
||||
};
|
||||
},
|
||||
until_line_break = transmute(rawptr)core.until_line_break,
|
||||
until_single_quote = transmute(rawptr)core.until_single_quote,
|
||||
until_double_quote = transmute(rawptr)core.until_double_quote,
|
||||
until_end_of_word = transmute(rawptr)core.until_end_of_word,
|
||||
},
|
||||
buffer = plugin.Buffer {
|
||||
get_buffer_info = proc "c" (state: rawptr) -> plugin.BufferInfo {
|
||||
state := cast(^State)state;
|
||||
context = state.ctx;
|
||||
|
||||
buffer := &state.buffers[state.current_buffer];
|
||||
|
||||
return plugin.BufferInfo {
|
||||
glyph_buffer_width = buffer.glyph_buffer_width,
|
||||
glyph_buffer_height = buffer.glyph_buffer_height,
|
||||
top_line = buffer.top_line,
|
||||
};
|
||||
},
|
||||
color_char_at = proc "c" (state: rawptr, start_cursor: plugin.Cursor, end_cursor: plugin.Cursor, palette_index: i32) {
|
||||
state := cast(^State)state;
|
||||
context = state.ctx;
|
||||
|
||||
buffer := &state.buffers[state.current_buffer];
|
||||
|
||||
start_cursor := core.Cursor {
|
||||
col = start_cursor.col,
|
||||
line = start_cursor.line,
|
||||
index = core.FileBufferIndex {
|
||||
slice_index = start_cursor.index.slice_index,
|
||||
content_index = start_cursor.index.content_index,
|
||||
}
|
||||
};
|
||||
end_cursor := core.Cursor {
|
||||
col = end_cursor.col,
|
||||
line = end_cursor.line,
|
||||
index = core.FileBufferIndex {
|
||||
slice_index = end_cursor.index.slice_index,
|
||||
content_index = end_cursor.index.content_index,
|
||||
}
|
||||
};
|
||||
|
||||
core.color_character(buffer, start_cursor, end_cursor, cast(theme.PaletteColor)palette_index);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
append(&state.plugins, loaded_plugin);
|
||||
fmt.println("Loaded Odin Highlighter plugin");
|
||||
return core.no_error();
|
||||
}
|
||||
|
||||
return core.make_error(.PluginLoadError, fmt.aprintf("failed to load Odin Highligher plugin"));
|
||||
}
|
||||
|
||||
main :: proc() {
|
||||
state := State {
|
||||
source_font_width = 8,
|
||||
source_font_height = 16,
|
||||
input_map = core.new_input_map(),
|
||||
window = nil,
|
||||
|
||||
directory = os.get_current_directory(),
|
||||
plugins = make([dynamic]plugin.Interface),
|
||||
};
|
||||
state.current_input_map = &state.input_map;
|
||||
register_default_input_actions(&state.input_map);
|
||||
|
@ -216,6 +424,17 @@ main :: proc() {
|
|||
runtime.append(&buffer_items, item);
|
||||
}
|
||||
|
||||
// Load plugins
|
||||
if err := load_plugins(&state); err.type != .None {
|
||||
fmt.println(err.msg);
|
||||
}
|
||||
|
||||
for plugin in state.plugins {
|
||||
if plugin.on_initialize != nil {
|
||||
plugin.on_initialize(plugin.plugin);
|
||||
}
|
||||
}
|
||||
|
||||
raylib.InitWindow(640, 480, "odin_editor - [back to basics]");
|
||||
raylib.SetWindowState({ .WINDOW_RESIZABLE, .VSYNC_HINT });
|
||||
raylib.SetTargetFPS(60);
|
||||
|
@ -248,6 +467,14 @@ main :: proc() {
|
|||
defer raylib.EndDrawing();
|
||||
|
||||
raylib.ClearBackground(theme.get_palette_raylib_color(.Background));
|
||||
|
||||
// TODO: be more granular in /what/ is being draw by the plugin
|
||||
for plugin in state.plugins {
|
||||
if plugin.on_initialize != nil {
|
||||
//plugin.on_draw(plugin.plugin);
|
||||
}
|
||||
}
|
||||
|
||||
core.draw_file_buffer(&state, buffer, 32, state.source_font_height, state.font);
|
||||
ui.draw_menu_bar(&state, &menu_bar_state, 0, 0, i32(state.screen_width), i32(state.screen_height), state.source_font_height);
|
||||
|
||||
|
@ -393,4 +620,10 @@ main :: proc() {
|
|||
|
||||
ui.test_menu_bar(&state, &menu_bar_state, 0,0, mouse_pos, raylib.IsMouseButtonReleased(.LEFT), state.source_font_height);
|
||||
}
|
||||
|
||||
for plugin in state.plugins {
|
||||
if plugin.on_exit != nil {
|
||||
plugin.on_exit();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,97 @@
|
|||
package plugin;
|
||||
|
||||
import "core:intrinsics"
|
||||
import "core:dynlib"
|
||||
import "core:fmt"
|
||||
|
||||
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,
|
||||
|
||||
plugin: Plugin,
|
||||
}
|
||||
|
||||
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_stop: bool,
|
||||
}
|
||||
|
||||
BufferInfo :: struct {
|
||||
glyph_buffer_width: int,
|
||||
glyph_buffer_height: int,
|
||||
top_line: int,
|
||||
}
|
||||
|
||||
Buffer :: struct {
|
||||
get_buffer_info: proc "c" (state: rawptr) -> BufferInfo,
|
||||
color_char_at: proc "c" (buffer: rawptr, start_cursor: Cursor, end_cursor: Cursor, palette_index: i32),
|
||||
}
|
||||
|
||||
Iterator :: struct {
|
||||
get_current_buffer_iterator: proc "c" (state: rawptr) -> BufferIter,
|
||||
get_char_at_iter: proc "c" (state: rawptr, it: ^BufferIter) -> u8,
|
||||
|
||||
iterate_buffer: proc "c" (state: rawptr, it: ^BufferIter) -> IterateResult,
|
||||
iterate_buffer_reverse: proc "c" (state: rawptr, it: ^BufferIter) -> IterateResult,
|
||||
iterate_buffer_until: proc "c" (state: rawptr, it: ^BufferIter, until_proc: rawptr),
|
||||
iterate_buffer_until_reverse: proc "c" (state: rawptr, it: ^BufferIter, until_proc: rawptr),
|
||||
iterate_buffer_peek: proc "c" (state: rawptr, it: ^BufferIter, iter_proc: rawptr) -> IterateResult,
|
||||
|
||||
until_line_break: rawptr,
|
||||
until_single_quote: rawptr,
|
||||
until_double_quote: rawptr,
|
||||
until_end_of_word: rawptr,
|
||||
}
|
||||
|
||||
Plugin :: struct {
|
||||
state: rawptr,
|
||||
iter: Iterator,
|
||||
buffer: Buffer,
|
||||
}
|
||||
|
||||
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 {
|
||||
fmt.println("The symbol", symbol, "was found at the address", address);
|
||||
return transmute(ProcType)address;
|
||||
} else {
|
||||
fmt.println("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;
|
||||
}
|
||||
|
||||
return 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),
|
||||
}, true;
|
||||
}
|
Loading…
Reference in New Issue