actually fully implement the highlighter within a plugin + a rust one too
parent
9e8e8f4207
commit
8891213a0a
2
Makefile
2
Makefile
|
@ -4,7 +4,7 @@ editor: src/*.odin rg odin_highlighter
|
||||||
odin build src/ -out:bin/editor -lld
|
odin build src/ -out:bin/editor -lld
|
||||||
|
|
||||||
odin_highlighter:
|
odin_highlighter:
|
||||||
odin build plugins/odin_highlighter/src/ -build-mode:dll -no-entry-point -out:bin/odin_highlighter
|
odin build plugins/highlighter/src/ -build-mode:dll -no-entry-point -out:bin/highlighter
|
||||||
|
|
||||||
rg:
|
rg:
|
||||||
cargo b --manifest-path=lib-rg/Cargo.toml
|
cargo b --manifest-path=lib-rg/Cargo.toml
|
||||||
|
|
|
@ -0,0 +1,418 @@
|
||||||
|
// The default syntax highlighter plugin for Odin
|
||||||
|
package 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!");
|
||||||
|
|
||||||
|
plugin.register_highlighter(plugin.state, ".odin", color_buffer_odin);
|
||||||
|
plugin.register_highlighter(plugin.state, ".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(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);
|
||||||
|
}
|
||||||
|
|
||||||
|
iterate_buffer_peek :: proc(plugin: Plugin, it: ^BufferIter) -> (character: u8, idx: BufferIndex, cond: bool) {
|
||||||
|
result := plugin.iter.iterate_buffer_peek(plugin.state, it);
|
||||||
|
|
||||||
|
return result.char, it.cursor.index, result.should_stop;
|
||||||
|
}
|
||||||
|
|
||||||
|
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.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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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.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_odin :: proc "c" (plugin: Plugin, buffer: rawptr) {
|
||||||
|
context = runtime.default_context();
|
||||||
|
|
||||||
|
start_it := plugin.iter.get_buffer_iterator(plugin.state, buffer);
|
||||||
|
it := plugin.iter.get_buffer_iterator(plugin.state, buffer);
|
||||||
|
|
||||||
|
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, 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.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, it.buffer, 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, it.buffer, 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_odin_keyword(plugin, start_it, it) {
|
||||||
|
plugin.buffer.color_char_at(plugin.state, it.buffer, start_it.cursor, it.cursor, 13);
|
||||||
|
} else if character, _, cond := iterate_buffer_peek(plugin, &it); cond {
|
||||||
|
if character == '(' {
|
||||||
|
plugin.buffer.color_char_at(plugin.state, it.buffer, start_it.cursor, it.cursor, 11);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
iterate_buffer(plugin.state, plugin.iter, &it);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
color_buffer_rust :: proc "c" (plugin: Plugin, buffer: rawptr) {
|
||||||
|
context = runtime.default_context();
|
||||||
|
|
||||||
|
start_it := plugin.iter.get_buffer_iterator(plugin.state, buffer);
|
||||||
|
it := plugin.iter.get_buffer_iterator(plugin.state, buffer);
|
||||||
|
|
||||||
|
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, 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.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, it.buffer, 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, it.buffer, 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_rust_keyword(plugin, start_it, it) {
|
||||||
|
plugin.buffer.color_char_at(plugin.state, it.buffer, start_it.cursor, it.cursor, 13);
|
||||||
|
} else if character, _, cond := iterate_buffer_peek(plugin, &it); cond {
|
||||||
|
if character == '(' || character == '<' {
|
||||||
|
plugin.buffer.color_char_at(plugin.state, it.buffer, start_it.cursor, it.cursor, 11);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
iterate_buffer(plugin.state, plugin.iter, &it);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,260 +0,0 @@
|
||||||
// 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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -66,6 +66,8 @@ State :: struct {
|
||||||
current_input_map: ^InputMap,
|
current_input_map: ^InputMap,
|
||||||
|
|
||||||
plugins: [dynamic]plugin.Interface,
|
plugins: [dynamic]plugin.Interface,
|
||||||
|
plugin_vtable: plugin.Plugin,
|
||||||
|
highlighters: map[string]plugin.OnColorBufferProc
|
||||||
}
|
}
|
||||||
|
|
||||||
EditorAction :: proc(state: ^State);
|
EditorAction :: proc(state: ^State);
|
||||||
|
|
|
@ -48,6 +48,8 @@ FileBuffer :: struct {
|
||||||
|
|
||||||
directory: string,
|
directory: string,
|
||||||
file_path: string,
|
file_path: string,
|
||||||
|
extension: string,
|
||||||
|
|
||||||
top_line: int,
|
top_line: int,
|
||||||
cursor: Cursor,
|
cursor: Cursor,
|
||||||
|
|
||||||
|
@ -584,6 +586,8 @@ new_file_buffer :: proc(allocator: mem.Allocator, file_path: string, base_dir: s
|
||||||
dir = filepath.dir(fi.fullpath);
|
dir = filepath.dir(fi.fullpath);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extension := filepath.ext(fi.fullpath);
|
||||||
|
|
||||||
if original_content, success := os.read_entire_file_from_handle(fd); success {
|
if original_content, success := os.read_entire_file_from_handle(fd); success {
|
||||||
width := 256;
|
width := 256;
|
||||||
height := 256;
|
height := 256;
|
||||||
|
@ -592,6 +596,7 @@ new_file_buffer :: proc(allocator: mem.Allocator, file_path: string, base_dir: s
|
||||||
allocator = allocator,
|
allocator = allocator,
|
||||||
directory = dir,
|
directory = dir,
|
||||||
file_path = fi.fullpath,
|
file_path = fi.fullpath,
|
||||||
|
extension = extension,
|
||||||
|
|
||||||
original_content = slice.clone_to_dynamic(original_content),
|
original_content = slice.clone_to_dynamic(original_content),
|
||||||
added_content = make([dynamic]u8, 0, 1024*1024),
|
added_content = make([dynamic]u8, 0, 1024*1024),
|
||||||
|
@ -916,13 +921,9 @@ 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) {
|
draw_file_buffer :: proc(state: ^State, buffer: ^FileBuffer, x: int, y: int, font: raylib.Font, show_line_numbers: bool = true) {
|
||||||
update_glyph_buffer(buffer);
|
update_glyph_buffer(buffer);
|
||||||
for plugin in state.plugins {
|
if highlighter, exists := state.highlighters[buffer.extension]; exists {
|
||||||
if plugin.on_initialize != nil {
|
highlighter(state.plugin_vtable, buffer);
|
||||||
plugin.on_draw(plugin.plugin);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
//color_buffer(buffer);
|
|
||||||
//update_glyph_buffer(buffer);
|
|
||||||
|
|
||||||
padding := 0;
|
padding := 0;
|
||||||
if show_line_numbers {
|
if show_line_numbers {
|
||||||
|
|
121
src/main.odin
121
src/main.odin
|
@ -187,9 +187,40 @@ register_default_input_actions :: proc(input_map: ^core.InputMap) {
|
||||||
}
|
}
|
||||||
|
|
||||||
load_plugins :: proc(state: ^State) -> core.Error {
|
load_plugins :: proc(state: ^State) -> core.Error {
|
||||||
if loaded_plugin, succ := plugin.try_load_plugin("bin/odin_highlighter.dylib"); succ {
|
if loaded_plugin, succ := plugin.try_load_plugin("bin/highlighter.dylib"); succ {
|
||||||
loaded_plugin.plugin = plugin.Plugin {
|
append(&state.plugins, loaded_plugin);
|
||||||
state = cast(rawptr)state,
|
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 {
|
||||||
|
ctx = context,
|
||||||
|
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),
|
||||||
|
highlighters = make(map[string]plugin.OnColorBufferProc),
|
||||||
|
};
|
||||||
|
state.plugin_vtable = plugin.Plugin {
|
||||||
|
state = cast(rawptr)&state,
|
||||||
|
register_highlighter = proc "c" (state: rawptr, extension: cstring, on_color_buffer: plugin.OnColorBufferProc) {
|
||||||
|
state := cast(^State)state;
|
||||||
|
context = state.ctx;
|
||||||
|
|
||||||
|
extension := strings.clone(string(extension));
|
||||||
|
|
||||||
|
if _, exists := state.highlighters[extension]; exists {
|
||||||
|
fmt.eprintln("Highlighter already registered for", extension, "files");
|
||||||
|
} else {
|
||||||
|
state.highlighters[extension] = on_color_buffer;
|
||||||
|
}
|
||||||
|
},
|
||||||
iter = plugin.Iterator {
|
iter = plugin.Iterator {
|
||||||
get_current_buffer_iterator = proc "c" (state: rawptr) -> plugin.BufferIter {
|
get_current_buffer_iterator = proc "c" (state: rawptr) -> plugin.BufferIter {
|
||||||
state := cast(^State)state;
|
state := cast(^State)state;
|
||||||
|
@ -211,6 +242,27 @@ load_plugins :: proc(state: ^State) -> core.Error {
|
||||||
hit_end = it.hit_end,
|
hit_end = it.hit_end,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
get_buffer_iterator = proc "c" (state: rawptr, buffer: rawptr) -> plugin.BufferIter {
|
||||||
|
state := cast(^State)state;
|
||||||
|
buffer := cast(^core.FileBuffer)buffer;
|
||||||
|
context = state.ctx;
|
||||||
|
|
||||||
|
it := core.new_file_buffer_iter(buffer);
|
||||||
|
|
||||||
|
// TODO: make this into a function
|
||||||
|
return plugin.BufferIter {
|
||||||
|
cursor = plugin.Cursor {
|
||||||
|
col = it.cursor.col,
|
||||||
|
line = it.cursor.line,
|
||||||
|
index = plugin.BufferIndex {
|
||||||
|
slice_index = it.cursor.index.slice_index,
|
||||||
|
content_index = it.cursor.index.content_index,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
buffer = cast(rawptr)it.buffer,
|
||||||
|
hit_end = it.hit_end,
|
||||||
|
}
|
||||||
|
},
|
||||||
get_char_at_iter = proc "c" (state: rawptr, it: ^plugin.BufferIter) -> u8 {
|
get_char_at_iter = proc "c" (state: rawptr, it: ^plugin.BufferIter) -> u8 {
|
||||||
state := cast(^State)state;
|
state := cast(^State)state;
|
||||||
context = state.ctx;
|
context = state.ctx;
|
||||||
|
@ -339,6 +391,44 @@ load_plugins :: proc(state: ^State) -> core.Error {
|
||||||
hit_end = internal_it.hit_end,
|
hit_end = internal_it.hit_end,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
iterate_buffer_peek = 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_peek(&internal_it, core.iterate_file_buffer);
|
||||||
|
|
||||||
|
it^ = plugin.BufferIter {
|
||||||
|
cursor = plugin.Cursor {
|
||||||
|
col = internal_it.cursor.col,
|
||||||
|
line = internal_it.cursor.line,
|
||||||
|
index = plugin.BufferIndex {
|
||||||
|
slice_index = internal_it.cursor.index.slice_index,
|
||||||
|
content_index = internal_it.cursor.index.content_index,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
buffer = cast(rawptr)internal_it.buffer,
|
||||||
|
hit_end = internal_it.hit_end,
|
||||||
|
};
|
||||||
|
|
||||||
|
return plugin.IterateResult {
|
||||||
|
char = char,
|
||||||
|
should_stop = cond,
|
||||||
|
};
|
||||||
|
},
|
||||||
until_line_break = transmute(rawptr)core.until_line_break,
|
until_line_break = transmute(rawptr)core.until_line_break,
|
||||||
until_single_quote = transmute(rawptr)core.until_single_quote,
|
until_single_quote = transmute(rawptr)core.until_single_quote,
|
||||||
until_double_quote = transmute(rawptr)core.until_double_quote,
|
until_double_quote = transmute(rawptr)core.until_double_quote,
|
||||||
|
@ -357,12 +447,11 @@ load_plugins :: proc(state: ^State) -> core.Error {
|
||||||
top_line = buffer.top_line,
|
top_line = buffer.top_line,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
color_char_at = proc "c" (state: rawptr, start_cursor: plugin.Cursor, end_cursor: plugin.Cursor, palette_index: i32) {
|
color_char_at = proc "c" (state: rawptr, buffer: rawptr, start_cursor: plugin.Cursor, end_cursor: plugin.Cursor, palette_index: i32) {
|
||||||
state := cast(^State)state;
|
state := cast(^State)state;
|
||||||
|
buffer := cast(^core.FileBuffer)buffer;
|
||||||
context = state.ctx;
|
context = state.ctx;
|
||||||
|
|
||||||
buffer := &state.buffers[state.current_buffer];
|
|
||||||
|
|
||||||
start_cursor := core.Cursor {
|
start_cursor := core.Cursor {
|
||||||
col = start_cursor.col,
|
col = start_cursor.col,
|
||||||
line = start_cursor.line,
|
line = start_cursor.line,
|
||||||
|
@ -384,24 +473,6 @@ load_plugins :: proc(state: ^State) -> core.Error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
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;
|
state.current_input_map = &state.input_map;
|
||||||
register_default_input_actions(&state.input_map);
|
register_default_input_actions(&state.input_map);
|
||||||
|
|
||||||
|
@ -431,7 +502,7 @@ main :: proc() {
|
||||||
|
|
||||||
for plugin in state.plugins {
|
for plugin in state.plugins {
|
||||||
if plugin.on_initialize != nil {
|
if plugin.on_initialize != nil {
|
||||||
plugin.on_initialize(plugin.plugin);
|
plugin.on_initialize(state.plugin_vtable);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,12 +7,11 @@ import "core:fmt"
|
||||||
OnInitializeProc :: proc "c" (plugin: Plugin);
|
OnInitializeProc :: proc "c" (plugin: Plugin);
|
||||||
OnExitProc :: proc "c" (/* probably needs some state eventually */);
|
OnExitProc :: proc "c" (/* probably needs some state eventually */);
|
||||||
OnDrawProc :: proc "c" (plugin: Plugin);
|
OnDrawProc :: proc "c" (plugin: Plugin);
|
||||||
|
OnColorBufferProc :: proc "c" (plugin: Plugin, buffer: rawptr);
|
||||||
Interface :: struct {
|
Interface :: struct {
|
||||||
on_initialize: OnInitializeProc,
|
on_initialize: OnInitializeProc,
|
||||||
on_exit: OnExitProc,
|
on_exit: OnExitProc,
|
||||||
on_draw: OnDrawProc,
|
on_draw: OnDrawProc,
|
||||||
|
|
||||||
plugin: Plugin,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
BufferIndex :: struct {
|
BufferIndex :: struct {
|
||||||
|
@ -45,18 +44,19 @@ BufferInfo :: struct {
|
||||||
|
|
||||||
Buffer :: struct {
|
Buffer :: struct {
|
||||||
get_buffer_info: proc "c" (state: rawptr) -> BufferInfo,
|
get_buffer_info: proc "c" (state: rawptr) -> BufferInfo,
|
||||||
color_char_at: proc "c" (buffer: rawptr, start_cursor: Cursor, end_cursor: Cursor, palette_index: i32),
|
color_char_at: proc "c" (state: rawptr, buffer: rawptr, start_cursor: Cursor, end_cursor: Cursor, palette_index: i32),
|
||||||
}
|
}
|
||||||
|
|
||||||
Iterator :: struct {
|
Iterator :: struct {
|
||||||
get_current_buffer_iterator: proc "c" (state: rawptr) -> BufferIter,
|
get_current_buffer_iterator: proc "c" (state: rawptr) -> BufferIter,
|
||||||
|
get_buffer_iterator: proc "c" (state: rawptr, buffer: rawptr) -> BufferIter,
|
||||||
get_char_at_iter: proc "c" (state: rawptr, it: ^BufferIter) -> u8,
|
get_char_at_iter: proc "c" (state: rawptr, it: ^BufferIter) -> u8,
|
||||||
|
|
||||||
iterate_buffer: proc "c" (state: rawptr, it: ^BufferIter) -> IterateResult,
|
iterate_buffer: proc "c" (state: rawptr, it: ^BufferIter) -> IterateResult,
|
||||||
iterate_buffer_reverse: 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: proc "c" (state: rawptr, it: ^BufferIter, until_proc: rawptr),
|
||||||
iterate_buffer_until_reverse: 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,
|
iterate_buffer_peek: proc "c" (state: rawptr, it: ^BufferIter) -> IterateResult,
|
||||||
|
|
||||||
until_line_break: rawptr,
|
until_line_break: rawptr,
|
||||||
until_single_quote: rawptr,
|
until_single_quote: rawptr,
|
||||||
|
@ -68,6 +68,8 @@ Plugin :: struct {
|
||||||
state: rawptr,
|
state: rawptr,
|
||||||
iter: Iterator,
|
iter: Iterator,
|
||||||
buffer: Buffer,
|
buffer: Buffer,
|
||||||
|
|
||||||
|
register_highlighter: proc "c" (state: rawptr, extension: cstring, on_color_buffer: OnColorBufferProc),
|
||||||
}
|
}
|
||||||
|
|
||||||
load_proc_address :: proc(lib_path: string, library: dynlib.Library, symbol: string, $ProcType: typeid) -> ProcType
|
load_proc_address :: proc(lib_path: string, library: dynlib.Library, symbol: string, $ProcType: typeid) -> ProcType
|
||||||
|
|
Loading…
Reference in New Issue