Compare commits
10 Commits
c41bb88e8e
...
e755d1d89c
| Author | SHA1 | Date | |
|---|---|---|---|
| e755d1d89c | |||
| 8eaed029ea | |||
| 0dc25adb8b | |||
| 0dd6516726 | |||
| f1c772258e | |||
| a829029d53 | |||
| 7d16617063 | |||
| 6d954bd1b7 | |||
| fb3bcb4904 | |||
| 1dabb59a65 |
2
.gitignore
vendored
2
.gitignore
vendored
@@ -1,3 +1,5 @@
|
|||||||
edit
|
edit
|
||||||
*.ttf
|
*.ttf
|
||||||
.build
|
.build
|
||||||
|
main
|
||||||
|
test
|
||||||
370
edit.jai
370
edit.jai
@@ -1,57 +1,76 @@
|
|||||||
|
// Todos:
|
||||||
|
// - move by word
|
||||||
|
// - select text
|
||||||
|
// - copy selected text
|
||||||
|
// - cut selected text
|
||||||
|
// - move line up
|
||||||
|
// - move line down
|
||||||
|
// - duplicate line
|
||||||
|
// - refactor to make cursor_x be aligned with characters themselves
|
||||||
|
|
||||||
|
|
||||||
FPS :: 60;
|
FPS :: 60;
|
||||||
MS_PER_FRAME :: 1000 / FPS;
|
MS_PER_FRAME :: 1000 / FPS;
|
||||||
|
|
||||||
buffer: string;
|
State :: struct {
|
||||||
lines: [..]String_Builder;
|
file_name: string;
|
||||||
line_height: int;
|
|
||||||
|
cursor_x: int;
|
||||||
|
cursor_y: int;
|
||||||
|
|
||||||
|
window_width: int;
|
||||||
|
window_height: int;
|
||||||
|
|
||||||
|
buffer: string;
|
||||||
|
lines: [..][..]u8;
|
||||||
|
line_height: int;
|
||||||
|
first_line: int;
|
||||||
|
|
||||||
my_font: *Simp.Dynamic_Font;
|
my_font: *Simp.Dynamic_Font;
|
||||||
|
dt: int;
|
||||||
|
}
|
||||||
|
|
||||||
window_width := 800;
|
White :: Vector4.{1, 1, 1, 1};
|
||||||
window_height := 600;
|
|
||||||
|
|
||||||
first_line := 0;
|
Special_Character_Lookup : [10]u8 : .[
|
||||||
|
xx #char ")",
|
||||||
|
xx #char "!",
|
||||||
|
xx #char "@",
|
||||||
|
xx #char "#",
|
||||||
|
xx #char "$",
|
||||||
|
xx #char "%",
|
||||||
|
xx #char "^",
|
||||||
|
xx #char "&",
|
||||||
|
xx #char "*",
|
||||||
|
xx #char "(",
|
||||||
|
];
|
||||||
|
|
||||||
main :: () {
|
run_editor :: (file_name: string) {
|
||||||
args := get_command_line_arguments();
|
state: State;
|
||||||
assert(args.count == 2, "The file name must be passed as a CLI argument");
|
state.window_width = 800;
|
||||||
|
state.window_height = 600;
|
||||||
|
state.file_name = file_name;
|
||||||
|
window := create_window(state.window_width, state.window_height, state.file_name);
|
||||||
|
|
||||||
|
my_init_fonts(*state);
|
||||||
window_name := ifx args.count == 1 then "edit" else args[1];
|
|
||||||
window := create_window(window_width, window_height, window_name);
|
|
||||||
|
|
||||||
my_init_fonts();
|
|
||||||
|
|
||||||
Simp.set_render_target(window);
|
Simp.set_render_target(window);
|
||||||
|
|
||||||
should_quit := false;
|
should_quit := false;
|
||||||
prev := get_time();
|
prev := get_time();
|
||||||
|
|
||||||
assert(read_file_lines(args[1]), "Must be able to read file!");
|
assert(read_file_lines(*state, state.file_name), "Must be able to read file!");
|
||||||
|
|
||||||
while !should_quit {
|
while !should_quit {
|
||||||
reset_temporary_storage();
|
reset_temporary_storage();
|
||||||
|
|
||||||
now := get_time();
|
now := get_time();
|
||||||
dt := now - prev;
|
state.dt = now - prev;
|
||||||
prev = now;
|
prev = now;
|
||||||
|
|
||||||
Input.update_window_events();
|
Input.update_window_events();
|
||||||
|
|
||||||
for Input.get_window_resizes() {
|
handle_window_resizes(*state, window);
|
||||||
Simp.update_window(it.window);
|
|
||||||
if it.window == window {
|
|
||||||
should_reinit := (it.width != window_width) || (it.height != window_height);
|
|
||||||
|
|
||||||
window_width = it.width;
|
|
||||||
window_height = it.height;
|
|
||||||
|
|
||||||
if should_reinit {
|
|
||||||
my_init_fonts();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
for event : Input.events_this_frame {
|
for event : Input.events_this_frame {
|
||||||
if event.type == .QUIT {
|
if event.type == .QUIT {
|
||||||
@@ -62,13 +81,41 @@ main :: () {
|
|||||||
if event.type == .KEYBOARD && event.key_pressed {
|
if event.type == .KEYBOARD && event.key_pressed {
|
||||||
if event.key_code == {
|
if event.key_code == {
|
||||||
case .ESCAPE; should_quit = true;
|
case .ESCAPE; should_quit = true;
|
||||||
|
|
||||||
|
case .BACKSPACE; handle_backspace(*state);
|
||||||
|
case .ENTER; handle_enter(*state);
|
||||||
|
|
||||||
|
case .ARROW_UP; #through;
|
||||||
|
case .ARROW_DOWN; #through;
|
||||||
|
case .ARROW_LEFT; #through;
|
||||||
|
case .ARROW_RIGHT; handle_arrow(*state, event);
|
||||||
|
}
|
||||||
|
|
||||||
|
if #char "A" <= event.key_code && event.key_code <= #char "z" {
|
||||||
|
key := event.key_code;
|
||||||
|
if !event.shift_pressed {
|
||||||
|
key += #char "a" - #char "A";
|
||||||
|
}
|
||||||
|
|
||||||
|
if event.ctrl_pressed {
|
||||||
|
if event.key_code == {
|
||||||
|
case #char "S"; #through;
|
||||||
|
case #char "s"; handle_save(*state);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
insert_character_at_cursor(*state, cast(u8) key);
|
||||||
|
}
|
||||||
|
} else if 33 <= event.key_code && event.key_code <= 126 {
|
||||||
|
// NOTE: this doesn't quite work for some keys, like ` or []
|
||||||
|
key := event.key_code;
|
||||||
|
insert_character_at_cursor(*state, cast(u8) key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Simp.clear_render_target(.0, .0, .0, 1);
|
Simp.clear_render_target(.0, .0, .0, 1);
|
||||||
|
|
||||||
render_edit_buffer();
|
render_edit_buffer(state);
|
||||||
|
|
||||||
Simp.swap_buffers(window);
|
Simp.swap_buffers(window);
|
||||||
|
|
||||||
@@ -79,39 +126,221 @@ main :: () {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
render_edit_buffer :: () {
|
render_edit_buffer :: (using state: State) {
|
||||||
num_lines_in_screen := window_height / line_height - 1;
|
visible_lines := get_visible_lines(state);
|
||||||
viewable_lines := array_view(lines, first_line, num_lines_in_screen);
|
for line_buffer: visible_lines {
|
||||||
Simp.set_shader_for_text();
|
Simp.set_shader_for_text();
|
||||||
color :: Vector4.{1, 1, 1, 1};
|
|
||||||
for line_buffer: viewable_lines {
|
|
||||||
|
|
||||||
line := builder_to_line(*line_buffer);
|
line_str := array_view_to_string(line_buffer);
|
||||||
|
|
||||||
|
prefix: string;
|
||||||
|
suffix: string;
|
||||||
|
|
||||||
|
has_cursor_on_line := it_index == cursor_y;
|
||||||
|
|
||||||
|
if has_cursor_on_line {
|
||||||
|
prefix, suffix = string_to_line(line_str, cursor_x);
|
||||||
|
} else {
|
||||||
|
prefix, suffix = string_to_line(line_str);
|
||||||
|
}
|
||||||
|
|
||||||
|
prefix_width := Simp.prepare_text(my_font, prefix);
|
||||||
|
top_of_line := window_height - (it_index + 1) * line_height;
|
||||||
|
|
||||||
|
Left_Max :: 5;
|
||||||
|
Simp.draw_prepared_text(my_font, Left_Max, top_of_line, White);
|
||||||
|
|
||||||
|
if has_cursor_on_line {
|
||||||
|
Simp.set_shader_for_color();
|
||||||
|
start := ifx cursor_x == 0 then Left_Max else prefix_width + Left_Max;
|
||||||
|
Simp.immediate_quad(
|
||||||
|
cast(float) start, cast(float) top_of_line + line_height,
|
||||||
|
cast(float) start + 1, cast(float) top_of_line,
|
||||||
|
White);
|
||||||
|
|
||||||
|
Simp.set_shader_for_text();
|
||||||
|
Simp.prepare_text(my_font, suffix);
|
||||||
|
Simp.draw_prepared_text(my_font, start, top_of_line, White);
|
||||||
|
}
|
||||||
|
|
||||||
Simp.prepare_text(my_font, line);
|
|
||||||
Simp.draw_prepared_text(my_font, 5, window_height - (it_index + 1) * line_height, color);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
builder_to_line :: (using builder: *String_Builder) -> string {
|
insert_character_at_cursor :: (using state: *State, char: u8) {
|
||||||
result_builder: String_Builder;
|
line := *get_visible_lines(state)[cursor_y];
|
||||||
result_builder.allocator = temporary_allocator;
|
array_insert_at(line, char, cursor_x);
|
||||||
|
cursor_x += 1;
|
||||||
|
}
|
||||||
|
|
||||||
builder_str := builder_to_string(builder, do_reset = false,, temp);
|
handle_save :: (using state: *State) {
|
||||||
|
out_builder: String_Builder;
|
||||||
|
init_string_builder(*out_builder);
|
||||||
|
|
||||||
start := 0;
|
for line: lines {
|
||||||
for c: builder_str {
|
line_str := string.{count=line.count, data=line.data};
|
||||||
if c == #char "\t" {
|
append(*out_builder, line_str);
|
||||||
s := string.{data=builder_str.data + start, count=(it_index + 1) - start};
|
if it_index != lines.count - 1 {
|
||||||
append(*result_builder, s);
|
append(*out_builder, "\n");
|
||||||
start = it_index + 1;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
s := string.{data=builder_str.data + start, count=builder_str.count - start};
|
content := builder_to_string(*out_builder);
|
||||||
append(*result_builder, s);
|
out_file_name := tprint("%.new", file_name);
|
||||||
|
write_entire_file(out_file_name, content);
|
||||||
|
}
|
||||||
|
|
||||||
return builder_to_string(*result_builder,, temp);
|
handle_window_resizes :: (using state: *State, window: Window_Type) {
|
||||||
|
for Input.get_window_resizes() {
|
||||||
|
Simp.update_window(it.window);
|
||||||
|
if it.window == window {
|
||||||
|
should_reinit := (it.width != window_width) || (it.height != window_height);
|
||||||
|
|
||||||
|
window_width = it.width;
|
||||||
|
window_height = it.height;
|
||||||
|
|
||||||
|
if should_reinit {
|
||||||
|
my_init_fonts(state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
handle_enter :: (using state: *State) {
|
||||||
|
cursor_line_index := cursor_y + first_line;
|
||||||
|
current_line := *lines[cursor_line_index];
|
||||||
|
|
||||||
|
new_line := [..]u8.{};
|
||||||
|
array_add(*new_line, array_view(current_line.*, cursor_x));
|
||||||
|
|
||||||
|
array_insert_at(*lines, new_line, cursor_line_index + 1);
|
||||||
|
current_line.count = cursor_x;
|
||||||
|
|
||||||
|
handle_arrow(state, .ARROW_DOWN);
|
||||||
|
cursor_x = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
handle_backspace :: (using state: *State) {
|
||||||
|
if cursor_x == 0 && cursor_y == 0 && first_line == 0 {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
cursor_line_index := cursor_y + first_line;
|
||||||
|
current_line := *lines[cursor_line_index];
|
||||||
|
if cursor_x == 0 {
|
||||||
|
prev_line := *lines[cursor_line_index - 1];
|
||||||
|
prev_count := prev_line.count;
|
||||||
|
array_add(prev_line, current_line.*);
|
||||||
|
array_remove_at(*lines, cursor_line_index);
|
||||||
|
handle_arrow(state, .ARROW_UP);
|
||||||
|
cursor_x = prev_count;
|
||||||
|
} else {
|
||||||
|
array_remove_at(current_line, cursor_x - 1);
|
||||||
|
cursor_x -= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
handle_arrow :: (state: *State, key_code: Input.Key_Code) {
|
||||||
|
handle_arrow(state, .{key_code=key_code});
|
||||||
|
}
|
||||||
|
|
||||||
|
handle_arrow :: (using state: *State, using event: Input.Event) {
|
||||||
|
visible_lines := get_visible_lines(state);
|
||||||
|
if visible_lines.count == 0 return;
|
||||||
|
|
||||||
|
if key_code == {
|
||||||
|
case .ARROW_UP;
|
||||||
|
if cursor_y == 0 && first_line == 0 return;
|
||||||
|
|
||||||
|
if cursor_y == 0 {
|
||||||
|
first_line -= 1;
|
||||||
|
} else {
|
||||||
|
cursor_y -= 1;
|
||||||
|
}
|
||||||
|
case .ARROW_DOWN;
|
||||||
|
if cursor_y == visible_lines.count - 1 {
|
||||||
|
first_line = min(first_line + 1, lines.count);
|
||||||
|
} else if cursor_y + first_line + visible_lines.count >= lines.count {
|
||||||
|
} else {
|
||||||
|
cursor_y += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
case .ARROW_LEFT;
|
||||||
|
if cursor_x == 0 && cursor_y != 0 {
|
||||||
|
prev_line := visible_lines[cursor_y - 1];
|
||||||
|
len := prev_line.count;
|
||||||
|
cursor_y = max(0, cursor_y - 1);
|
||||||
|
cursor_x = len;
|
||||||
|
} else if cursor_x != 0 && ctrl_pressed {
|
||||||
|
} else if cursor_x != 0 {
|
||||||
|
cursor_x -= 1;
|
||||||
|
}
|
||||||
|
case .ARROW_RIGHT;
|
||||||
|
line := visible_lines[cursor_y];
|
||||||
|
len := line.count;
|
||||||
|
if cursor_x == len {
|
||||||
|
cursor_x = 0;
|
||||||
|
cursor_y += 1;
|
||||||
|
} else if ctrl_pressed {
|
||||||
|
} else {
|
||||||
|
cursor_x += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
get_visible_lines :: (using state: State) -> [][..]u8 {
|
||||||
|
if line_height <= 1 || window_height == 0 return .[];
|
||||||
|
num_lines_in_screen := window_height / line_height - 1;
|
||||||
|
return array_view(lines, first_line, num_lines_in_screen);
|
||||||
|
}
|
||||||
|
|
||||||
|
string_to_line :: (str: string, cursor_char_index := -1) -> string, string {
|
||||||
|
prefix_builder: String_Builder;
|
||||||
|
prefix_builder.allocator = temporary_allocator;
|
||||||
|
|
||||||
|
suffix_builder: String_Builder;
|
||||||
|
suffix_builder.allocator = temporary_allocator;
|
||||||
|
|
||||||
|
init_string_builder(*prefix_builder);
|
||||||
|
init_string_builder(*suffix_builder);
|
||||||
|
|
||||||
|
start := 0;
|
||||||
|
char_index := 0;
|
||||||
|
cursor_index := 0;
|
||||||
|
|
||||||
|
current_builder := *prefix_builder;
|
||||||
|
|
||||||
|
while char_index < str.count {
|
||||||
|
defer char_index += 1;
|
||||||
|
c := str.data[char_index];
|
||||||
|
|
||||||
|
if c == #char "\t" {
|
||||||
|
|
||||||
|
// s := string.{data=str.data + start, count=(char_index + 1) - start};
|
||||||
|
// append(current_builder, s);
|
||||||
|
// append(current_builder, " ");
|
||||||
|
// start = char_index + 1;
|
||||||
|
// cursor_index += 4;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
cursor_index += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if cursor_index == cursor_char_index {
|
||||||
|
s := string.{data=str.data + start, count=(char_index + 1) - start};
|
||||||
|
append(current_builder, s);
|
||||||
|
current_builder = *suffix_builder;
|
||||||
|
start = char_index + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
s := string.{data=str.data + start, count=str.count - start};
|
||||||
|
append(current_builder, s);
|
||||||
|
|
||||||
|
prefix := builder_to_string(*prefix_builder,, temp);
|
||||||
|
suffix := builder_to_string(*suffix_builder,, temp);
|
||||||
|
|
||||||
|
return prefix, suffix;
|
||||||
}
|
}
|
||||||
|
|
||||||
get_time :: () -> s64 {
|
get_time :: () -> s64 {
|
||||||
@@ -120,28 +349,27 @@ get_time :: () -> s64 {
|
|||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
read_file_lines :: (file_path: string) -> bool {
|
read_file_lines :: (using state: *State, file_path: string) -> bool {
|
||||||
file_contents, ok := read_entire_file(file_path);
|
file_contents, ok := read_entire_file(file_path);
|
||||||
if !ok return ok;
|
if !ok return ok;
|
||||||
|
|
||||||
for lines reset(*it);
|
for lines free(*it);
|
||||||
free(lines.data);
|
free(lines.data);
|
||||||
lines = [..]String_Builder.{};
|
lines = [..][..]u8.{};
|
||||||
|
|
||||||
lines_temp := split(file_contents, "\n");
|
lines_temp := split(file_contents, "\n");
|
||||||
defer free(lines_temp.data);
|
defer free(lines_temp.data);
|
||||||
|
|
||||||
for line: lines_temp {
|
for line: lines_temp {
|
||||||
builder: String_Builder;
|
builder: [..]u8;
|
||||||
init_string_builder(*builder);
|
array_add(*builder, array_view(line));
|
||||||
append(*builder, line);
|
|
||||||
array_add(*lines, builder);
|
array_add(*lines, builder);
|
||||||
}
|
}
|
||||||
|
|
||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
my_init_fonts :: () {
|
my_init_fonts :: (using state: *State) {
|
||||||
line_height = 16;
|
line_height = 16;
|
||||||
base_path := path_strip_filename(get_path_of_running_executable());
|
base_path := path_strip_filename(get_path_of_running_executable());
|
||||||
|
|
||||||
@@ -150,6 +378,26 @@ my_init_fonts :: () {
|
|||||||
assert(my_font != null);
|
assert(my_font != null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
array_add :: (xs: *[..]$T, to_append: []T) {
|
||||||
|
array_reserve(xs, xs.count + to_append.count);
|
||||||
|
|
||||||
|
memcpy(xs.data + xs.count, to_append.data, to_append.count * size_of(T));
|
||||||
|
xs.count += to_append.count;
|
||||||
|
}
|
||||||
|
|
||||||
|
array_view :: (s: string) -> []u8 {
|
||||||
|
return []u8.{count=s.count, data=s.data};
|
||||||
|
}
|
||||||
|
|
||||||
|
array_view_to_string :: (chars: []u8) -> string {
|
||||||
|
return string.{count=chars.count, data=chars.data};
|
||||||
|
}
|
||||||
|
|
||||||
|
array_remove_at :: (xs: *[..]$T, index: int) {
|
||||||
|
xs.count -= 1;
|
||||||
|
memcpy(xs.data + index, xs.data + index + 1, xs.count - index);
|
||||||
|
}
|
||||||
|
|
||||||
#import "Basic";
|
#import "Basic";
|
||||||
#import "File";
|
#import "File";
|
||||||
#import "Math";
|
#import "Math";
|
||||||
|
|||||||
10
main.jai
Normal file
10
main.jai
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
main :: () {
|
||||||
|
args := get_command_line_arguments();
|
||||||
|
assert(args.count == 2, "The file name must be passed as a CLI argument");
|
||||||
|
|
||||||
|
file_name := args[1];
|
||||||
|
run_editor(file_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
#load "edit.jai";
|
||||||
|
#import "Basic";
|
||||||
73
test.jai
Normal file
73
test.jai
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
main :: () {
|
||||||
|
print("\nBeginning tests...\n");
|
||||||
|
// test_handle_arrow_empty_lines();
|
||||||
|
// test_handle_arrow_one_line();
|
||||||
|
x := 1;
|
||||||
|
y := 2;
|
||||||
|
assert_test(x == y);
|
||||||
|
}
|
||||||
|
|
||||||
|
test_handle_arrow_empty_lines :: () {
|
||||||
|
state: State;
|
||||||
|
state.cursor_y = 0;
|
||||||
|
state.cursor_x = 0;
|
||||||
|
|
||||||
|
codes := Input.Key_Code.[.ARROW_DOWN, .ARROW_UP, .ARROW_LEFT, .ARROW_RIGHT];
|
||||||
|
for codes {
|
||||||
|
handle_arrow(*state, .{key_code=it});
|
||||||
|
assert(state.cursor_x == 0 && state.cursor_y == 0, "%: cursor_x % & cursor_y %", it, state.cursor_x, state.cursor_y);
|
||||||
|
}
|
||||||
|
|
||||||
|
print("test_handle_arrow_empty_lines completed successfully\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
test_handle_arrow_one_line :: () {
|
||||||
|
state: State;
|
||||||
|
state.cursor_y = 0;
|
||||||
|
state.cursor_x = 0;
|
||||||
|
|
||||||
|
line: [..]u8;
|
||||||
|
line_str := "foo bar";
|
||||||
|
|
||||||
|
array_add(*line, .{data=line_str.data, count=line_str.count});
|
||||||
|
array_add(*state.lines, line);
|
||||||
|
|
||||||
|
codes := Input.Key_Code.[.ARROW_DOWN, .ARROW_UP, .ARROW_LEFT];
|
||||||
|
for codes {
|
||||||
|
handle_arrow(*state, .{key_code=it});
|
||||||
|
assert(state.cursor_x == 0 && state.cursor_y == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
handle_arrow(*state, .{key_code=.ARROW_RIGHT});
|
||||||
|
assert(state.cursor_x == 1 && state.cursor_y == 0);
|
||||||
|
|
||||||
|
print("test_handle_arrow_one_line completed successfully\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_test :: (value: bool, $code := #caller_code) {
|
||||||
|
builder: String_Builder;
|
||||||
|
root, expressions := compiler_get_nodes(code);
|
||||||
|
loc := #location(code);
|
||||||
|
|
||||||
|
print_to_builder(*builder, "%:%: Test: ", loc.fully_pathed_filename, loc.line_number);
|
||||||
|
print_expression(*builder, root);
|
||||||
|
append(*builder, "\n");
|
||||||
|
`result := #insert code;
|
||||||
|
if !result {
|
||||||
|
for expressions {
|
||||||
|
if it == root continue;
|
||||||
|
print_expression(*builder, it);
|
||||||
|
append(*builder, "\n");
|
||||||
|
}
|
||||||
|
append(*builder, "\n");
|
||||||
|
`expression := builder_to_string(*builder);
|
||||||
|
`print("%\n", expression);
|
||||||
|
} else {
|
||||||
|
`print("Passed!\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#import,file "edit.jai";
|
||||||
|
#import "Basic";
|
||||||
|
#import "Compiler";
|
||||||
|
#import "Program_Print";
|
||||||
Reference in New Issue
Block a user