1 #include "gtk_console.h"
2
3 #include <math.h>
4 #include <stdio.h>
5 #include <stdlib.h>
6 #include <string.h>
7 #include <time.h>
8 #include <gtksourceview/gtksource.h>
9 #include <gdk-pixbuf/gdk-pixbuf.h>
10 #include <girepository.h>
11 #include <gc/gc.h>
12 #include "minilang.h"
13 #include "ml_macros.h"
14 #include "stringmap.h"
15 #include "ml_compiler.h"
16 #include <sys/stat.h>
17
18 #include "ml_gir.h"
19 #include "ml_runtime.h"
20 #include "ml_bytecode.h"
21 #include "ml_debugger.h"
22
23 #define MAX_HISTORY 128
24
25 struct console_t {
26 ml_state_t Base;
27 const char *Name;
28 GtkWidget *Window, *LogScrolled, *LogView, *InputView, *SourceView;
29 GtkWidget *DebugButtons, *Paned;
30 GtkNotebook *Notebook;
31 GtkSourceLanguage *Language;
32 GtkSourceStyleScheme *StyleScheme;
33 GtkLabel *MemoryBar;
34 GtkTextTag *OutputTag, *ResultTag, *ErrorTag, *BinaryTag;
35 GtkTextMark *EndMark;
36 GtkSourceBuffer *SourceBuffer;
37 ml_getter_t ParentGetter;
38 void *ParentGlobals;
39 interactive_debugger_t *Debugger;
40 const char *ConfigPath;
41 const char *FontName;
42 GKeyFile *Config;
43 PangoFontDescription *FontDescription;
44 ml_parser_t *Parser;
45 ml_compiler_t *Compiler;
46 char *History[MAX_HISTORY];
47 int HistoryIndex, HistoryEnd;
48 stringmap_t SourceViews[1];
49 stringmap_t Cycles[1];
50 stringmap_t Combos[1];
51 char Chars[32];
52 int NumChars;
53 };
54
55 #ifdef MINGW
stpcpy(char * Dest,const char * Source)56 static char *stpcpy(char *Dest, const char *Source) {
57 while (*Source) *Dest++ = *Source++;
58 return Dest;
59 }
60
61 #define lstat stat
62 #endif
63
console_global_get(console_t * Console,const char * Name)64 static ml_value_t *console_global_get(console_t *Console, const char *Name) {
65 if (Console->Debugger) {
66 ml_value_t *Value = interactive_debugger_get(Console->Debugger, Name);
67 if (Value) return Value;
68 }
69 return (Console->ParentGetter)(Console->ParentGlobals, Name);
70 }
71
console_log(console_t * Console,ml_value_t * Value)72 void console_log(console_t *Console, ml_value_t *Value) {
73 GtkTextIter End[1];
74 GtkTextBuffer *LogBuffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(Console->LogView));
75 gtk_text_buffer_get_end_iter(LogBuffer, End);
76 if (ml_is_error(Value)) {
77 char *Buffer;
78 int Length = asprintf(&Buffer, "%s: %s\n", ml_error_type(Value), ml_error_message(Value));
79 gtk_text_buffer_insert_with_tags(LogBuffer, End, Buffer, Length, Console->ErrorTag, NULL);
80 ml_source_t Source;
81 int Level = 0;
82 while (ml_error_source(Value, Level++, &Source)) {
83 Length = asprintf(&Buffer, "\t%s:%d\n", Source.Name, Source.Line);
84 gtk_text_buffer_insert_with_tags(LogBuffer, End, Buffer, Length, Console->ErrorTag, NULL);
85 }
86 } else {
87 ml_value_t *String = ml_simple_inline(MLStringT, 1, Value);
88 if (ml_is(String, MLStringT)) {
89 const char *Buffer = ml_string_value(String);
90 int Length = ml_string_length(String);
91 if (Length > 10240) {
92 char Text[32];
93 int TextLength = sprintf(Text, "<%d bytes>", Length);
94 gtk_text_buffer_insert_with_tags(LogBuffer, End, Text, TextLength, Console->ResultTag, NULL);
95 } else if (g_utf8_validate(Buffer, Length, NULL)) {
96 gtk_text_buffer_insert_with_tags(LogBuffer, End, Buffer, Length, Console->ResultTag, NULL);
97 } else {
98 gtk_text_buffer_insert_with_tags(LogBuffer, End, "<", 1, Console->BinaryTag, NULL);
99 for (int I = 0; I < Length; ++I) {
100 static char HexChars[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
101 char Bytes[4] = " ??";
102 unsigned char Byte = Buffer[I];
103 Bytes[1] = HexChars[Byte >> 4];
104 Bytes[2] = HexChars[Byte & 15];
105 gtk_text_buffer_insert_with_tags(LogBuffer, End, Bytes, 3, Console->BinaryTag, NULL);
106 }
107 gtk_text_buffer_insert_with_tags(LogBuffer, End, " >", 2, Console->BinaryTag, NULL);
108 }
109 gtk_text_buffer_insert_with_tags(LogBuffer, End, "\n", 1, Console->ResultTag, NULL);
110 } else {
111 char *Buffer;
112 int Length = asprintf(&Buffer, "<%s>\n", ml_typeof(Value)->Name);
113 gtk_text_buffer_insert_with_tags(LogBuffer, End, Buffer, Length, Console->ResultTag, NULL);
114 }
115 }
116 gtk_text_view_scroll_mark_onscreen(GTK_TEXT_VIEW(Console->LogView), Console->EndMark);
117 }
118
119 ML_TYPE(ConsoleT, (), "console");
120
ml_console_repl_run(console_t * Console,ml_value_t * Result)121 static void ml_console_repl_run(console_t *Console, ml_value_t *Result) {
122 if (Result == MLEndOfInput) {
123 gtk_widget_grab_focus(Console->InputView);
124 return;
125 }
126 console_log(Console, Result);
127 GtkTextIter End[1];
128 GtkTextBuffer *LogBuffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(Console->LogView));
129 gtk_text_buffer_get_end_iter(LogBuffer, End);
130 gtk_text_buffer_insert(LogBuffer, End, "\n", 1);
131 if (ml_is_error(Result)) {
132 gtk_widget_grab_focus(Console->InputView);
133 return;
134 }
135 return ml_command_evaluate((ml_state_t *)Console, Console->Parser, Console->Compiler);
136 }
137
console_step_in(GtkWidget * Button,console_t * Console)138 static void console_step_in(GtkWidget *Button, console_t *Console) {
139 ml_parser_t *Parser = Console->Parser;
140 ml_compiler_t *Compiler = Console->Compiler;
141 ml_parser_reset(Parser);
142 ml_parser_input(Parser, "step_in()");
143 ml_command_evaluate((ml_state_t *)Console, Parser, Compiler);
144 }
145
console_step_over(GtkWidget * Button,console_t * Console)146 static void console_step_over(GtkWidget *Button, console_t *Console) {
147 ml_parser_t *Parser = Console->Parser;
148 ml_compiler_t *Compiler = Console->Compiler;
149 ml_parser_reset(Parser);
150 ml_parser_input(Parser, "step_over()");
151 ml_command_evaluate((ml_state_t *)Console, Parser, Compiler);
152 }
153
console_step_out(GtkWidget * Button,console_t * Console)154 static void console_step_out(GtkWidget *Button, console_t *Console) {
155 ml_parser_t *Parser = Console->Parser;
156 ml_compiler_t *Compiler = Console->Compiler;
157 ml_parser_reset(Parser);
158 ml_parser_input(Parser, "step_out()");
159 ml_command_evaluate((ml_state_t *)Console, Parser, Compiler);
160 }
161
console_continue(GtkWidget * Button,console_t * Console)162 static void console_continue(GtkWidget *Button, console_t *Console) {
163 ml_parser_t *Parser = Console->Parser;
164 ml_compiler_t *Compiler = Console->Compiler;
165 ml_parser_reset(Parser);
166 ml_parser_input(Parser, "continue()");
167 ml_command_evaluate((ml_state_t *)Console, Parser, Compiler);
168 }
169
console_submit(GtkWidget * Button,console_t * Console)170 static void console_submit(GtkWidget *Button, console_t *Console) {
171 GtkTextBuffer *InputBuffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(Console->InputView));
172 GtkTextIter InputStart[1], InputEnd[1];
173 gtk_source_buffer_set_highlight_matching_brackets(GTK_SOURCE_BUFFER(InputBuffer), FALSE);
174 gtk_text_buffer_get_bounds(InputBuffer, InputStart, InputEnd);
175 const char *Text = gtk_text_buffer_get_text(InputBuffer, InputStart, InputEnd, FALSE);
176
177 int HistoryEnd = Console->HistoryEnd;
178 Console->History[HistoryEnd] = GC_strdup(Text);
179 Console->HistoryIndex = Console->HistoryEnd = (HistoryEnd + 1) % MAX_HISTORY;
180
181 GtkTextIter End[1];
182
183 GtkTextBuffer *LogBuffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(Console->LogView));
184 gtk_text_buffer_get_end_iter(LogBuffer, End);
185 gtk_source_buffer_create_source_mark(GTK_SOURCE_BUFFER(LogBuffer), NULL, "result", End);
186 gtk_text_buffer_insert_range(LogBuffer, End, InputStart, InputEnd);
187 gtk_text_buffer_insert(LogBuffer, End, "\n", -1);
188 gtk_text_buffer_set_text(InputBuffer, "", 0);
189
190 GtkTextBuffer *SourceBuffer = GTK_TEXT_BUFFER(Console->SourceBuffer);
191 gtk_text_buffer_get_end_iter(SourceBuffer, End);
192 gtk_text_buffer_insert(SourceBuffer, End, Text, -1);
193 gtk_text_buffer_insert(SourceBuffer, End, "\n", -1);
194 gtk_source_buffer_set_highlight_matching_brackets(GTK_SOURCE_BUFFER(InputBuffer), TRUE);
195
196
197 //GtkTextIter End[1];
198 //GtkTextBuffer *LogBuffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(Console->LogView));
199 gtk_text_buffer_get_end_iter(LogBuffer, End);
200 gtk_text_buffer_insert(LogBuffer, End, "\n", 1);
201
202 ml_parser_t *Parser = Console->Parser;
203 ml_compiler_t *Compiler = Console->Compiler;
204 ml_parser_reset(Parser);
205 ml_parser_input(Parser, Text);
206 ml_command_evaluate((ml_state_t *)Console, Parser, Compiler);
207 }
208
console_debug_enter(console_t * Console,interactive_debugger_t * Debugger,ml_source_t Source,int Index)209 static void console_debug_enter(console_t *Console, interactive_debugger_t *Debugger, ml_source_t Source, int Index) {
210 gtk_widget_show(Console->DebugButtons);
211 Console->Debugger = Debugger;
212 console_printf(Console, "Debug break [%d]: %s:%d\n", Index, Source.Name, Source.Line);
213 GtkWidget *SourceView;
214 if (Source.Name == Console->Name) {
215 SourceView = Console->SourceView;
216 } else {
217 GtkWidget **Slot = (GtkWidget **)stringmap_slot(Console->SourceViews, Source.Name);
218 if (!Slot[0]) {
219 GtkSourceBuffer *Buffer = gtk_source_buffer_new_with_language(Console->Language);
220 gtk_source_buffer_set_style_scheme(Buffer, Console->StyleScheme);
221 GtkTextIter End[1];
222 gtk_text_buffer_get_end_iter(GTK_TEXT_BUFFER(Buffer), End);
223 FILE *File = fopen(Source.Name, "r");
224 if (File) {
225 char Text[128];
226 size_t Length;
227 do {
228 Length = fread(Text, 1, 128, File);
229 gtk_text_buffer_insert(GTK_TEXT_BUFFER(Buffer), End, Text, Length);
230 } while (Length == 128);
231 fclose(File);
232 }
233 GtkWidget *View = gtk_source_view_new_with_buffer(Buffer);
234 GtkWidget *Scrolled = gtk_scrolled_window_new(NULL, NULL);
235 gtk_container_add(GTK_CONTAINER(Scrolled), View);
236 gtk_text_view_set_monospace(GTK_TEXT_VIEW(View), TRUE);
237 gtk_widget_override_font(View, Console->FontDescription);
238 gtk_source_view_set_tab_width(GTK_SOURCE_VIEW(View), 4);
239 gtk_source_view_set_highlight_current_line(GTK_SOURCE_VIEW(View), TRUE);
240 gtk_source_view_set_show_line_numbers(GTK_SOURCE_VIEW(View), TRUE);
241 gtk_notebook_append_page(Console->Notebook, Scrolled, gtk_label_new(Source.Name));
242 gtk_widget_show_all(GTK_WIDGET(Console->Notebook));
243 Slot[0] = View;
244 }
245 SourceView = Slot[0];
246 }
247 int PageNum = gtk_notebook_page_num(Console->Notebook, gtk_widget_get_parent(SourceView));
248 gtk_notebook_set_current_page(Console->Notebook, PageNum);
249
250 GtkTextBuffer *Buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(SourceView));
251 GtkTextIter LineBeg[1], LineEnd[1];
252 gtk_text_buffer_get_iter_at_line(Buffer, LineBeg, Source.Line - 1);
253 gtk_text_buffer_get_iter_at_line(Buffer, LineEnd, Source.Line);
254 //gtk_text_buffer_apply_tag(Buffer, PausedTag, LineBeg, LineEnd);
255 gtk_text_buffer_place_cursor(Buffer, LineBeg);
256 gtk_text_view_scroll_to_iter(GTK_TEXT_VIEW(SourceView), LineBeg, 0.0, FALSE, 0.0, 0.0);
257 }
258
console_debug_exit(console_t * Console,interactive_debugger_t * Debugger,ml_state_t * Caller,int Index)259 static void console_debug_exit(console_t *Console, interactive_debugger_t *Debugger, ml_state_t *Caller, int Index) {
260 gtk_widget_hide(Console->DebugButtons);
261 return interactive_debugger_resume(Debugger);
262 }
263
console_clear(GtkWidget * Button,console_t * Console)264 static void console_clear(GtkWidget *Button, console_t *Console) {
265 GtkTextBuffer *LogBuffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(Console->LogView));
266 GtkTextIter Start[1], End[1];
267 gtk_text_buffer_get_start_iter(LogBuffer, Start);
268 gtk_text_buffer_get_end_iter(LogBuffer, End);
269 gtk_text_buffer_delete(LogBuffer, Start, End);
270 }
271
toggle_layout(GtkWidget * Button,console_t * Console)272 static void toggle_layout(GtkWidget *Button, console_t *Console) {
273 switch (gtk_orientable_get_orientation(GTK_ORIENTABLE(Console->Paned))) {
274 case GTK_ORIENTATION_HORIZONTAL:
275 gtk_orientable_set_orientation(GTK_ORIENTABLE(Console->Paned), GTK_ORIENTATION_VERTICAL);
276 break;
277 case GTK_ORIENTATION_VERTICAL:
278 gtk_orientable_set_orientation(GTK_ORIENTABLE(Console->Paned), GTK_ORIENTATION_HORIZONTAL);
279 break;
280 }
281 }
282
console_style_changed(GtkComboBoxText * Widget,console_t * Console)283 static void console_style_changed(GtkComboBoxText *Widget, console_t *Console) {
284 const char *StyleId = gtk_combo_box_text_get_active_text(Widget);
285 GtkSourceStyleSchemeManager *StyleManager = gtk_source_style_scheme_manager_get_default();
286 Console->StyleScheme = gtk_source_style_scheme_manager_get_scheme(StyleManager, StyleId);
287 gtk_source_buffer_set_style_scheme(GTK_SOURCE_BUFFER(gtk_text_view_get_buffer(GTK_TEXT_VIEW(Console->InputView))), Console->StyleScheme);
288 gtk_source_buffer_set_style_scheme(GTK_SOURCE_BUFFER(gtk_text_view_get_buffer(GTK_TEXT_VIEW(Console->LogView))), Console->StyleScheme);
289
290 g_key_file_set_string(Console->Config, "gtk-console", "style", StyleId);
291 g_key_file_save_to_file(Console->Config, Console->ConfigPath, NULL);
292 }
293
console_font_changed(GtkFontChooser * Widget,console_t * Console)294 static void console_font_changed(GtkFontChooser *Widget, console_t *Console) {
295 gchar *FontName = gtk_font_chooser_get_font(Widget);
296 Console->FontName = FontName;
297 Console->FontDescription = pango_font_description_from_string(FontName);
298 gtk_widget_override_font(Console->InputView, Console->FontDescription);
299 gtk_widget_override_font(Console->LogView, Console->FontDescription);
300
301 g_key_file_set_string(Console->Config, "gtk-console", "font", FontName);
302 g_key_file_save_to_file(Console->Config, Console->ConfigPath, NULL);
303 }
304
305 #ifdef __APPLE__
306 #define COMMAND_MASK GDK_META_MASK
307 #else
308 #define COMMAND_MASK GDK_CONTROL_MASK
309 #endif
310
console_keypress(GtkWidget * Widget,GdkEventKey * Event,console_t * Console)311 static gboolean console_keypress(GtkWidget *Widget, GdkEventKey *Event, console_t *Console) {
312 switch (Event->keyval) {
313 case GDK_KEY_Return:
314 Console->NumChars = 0;
315 if (Event->state & COMMAND_MASK) {
316 console_submit(NULL, Console);
317 return TRUE;
318 }
319 break;
320 case GDK_KEY_Up:
321 Console->NumChars = 0;
322 if (Event->state & COMMAND_MASK) {
323 int HistoryIndex = (Console->HistoryIndex + MAX_HISTORY - 1) % MAX_HISTORY;
324 if (Console->History[HistoryIndex]) {
325 gtk_text_buffer_set_text(gtk_text_view_get_buffer(GTK_TEXT_VIEW(Console->InputView)), Console->History[HistoryIndex], -1);
326 Console->HistoryIndex = HistoryIndex;
327 }
328 return TRUE;
329 }
330 break;
331 case GDK_KEY_Down:
332 Console->NumChars = 0;
333 if (Event->state & COMMAND_MASK) {
334 int HistoryIndex = (Console->HistoryIndex + 1) % MAX_HISTORY;
335 if (Console->History[HistoryIndex]) {
336 gtk_text_buffer_set_text(gtk_text_view_get_buffer(GTK_TEXT_VIEW(Console->InputView)), Console->History[HistoryIndex], -1);
337 Console->HistoryIndex = HistoryIndex;
338 } else {
339 gtk_text_buffer_set_text(gtk_text_view_get_buffer(GTK_TEXT_VIEW(Console->InputView)), "", 0);
340 Console->HistoryIndex = Console->HistoryEnd;
341 }
342 return TRUE;
343 }
344 break;
345 case GDK_KEY_Escape:
346 case GDK_KEY_Left:
347 case GDK_KEY_Right:
348 Console->NumChars = 0;
349 break;
350 case GDK_KEY_BackSpace:
351 if (Console->NumChars > 0) --Console->NumChars;
352 break;
353 case GDK_KEY_Tab: {
354 Console->Chars[Console->NumChars] = 0;
355 for (int I = 0; I < Console->NumChars; ++I) {
356 const char *Cycle = stringmap_search(Console->Cycles, Console->Chars + I);
357 if (Cycle) {
358 GtkTextIter Start[1], End[1];
359 GtkTextBuffer *InputBuffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(Console->InputView));
360 GtkTextMark *Cursor = gtk_text_buffer_get_insert(InputBuffer);
361 gtk_text_buffer_get_iter_at_mark(InputBuffer, Start, Cursor);
362 gtk_text_buffer_get_iter_at_mark(InputBuffer, End, Cursor);
363 gtk_text_iter_backward_chars(Start, g_utf8_strlen(Console->Chars + I, Console->NumChars - I));
364 Console->NumChars = stpcpy(Console->Chars + I, Cycle) - Console->Chars;
365 gtk_text_buffer_delete(InputBuffer, Start, End);
366 gtk_text_buffer_insert(InputBuffer, Start, Console->Chars + I, Console->NumChars - I);
367 return TRUE;
368 }
369 }
370 break;
371 }
372 default: {
373 guint32 Unichar = gdk_keyval_to_unicode(Event->keyval);
374 if (!Unichar) return FALSE;
375 if (Unichar <= 32) {
376 Console->NumChars = 0;
377 return FALSE;
378 }
379 Console->NumChars += g_unichar_to_utf8(Unichar, Console->Chars + Console->NumChars);
380 if (Console->NumChars > 16) {
381 memmove(Console->Chars, Console->Chars + Console->NumChars - 16, 16);
382 Console->NumChars = 16;
383 }
384 Console->Chars[Console->NumChars] = 0;
385 for (int I = 0; I < Console->NumChars; ++I) {
386 const char *Combo = stringmap_search(Console->Combos, Console->Chars + I);
387 if (Combo) {
388 GtkTextIter Start[1], End[1];
389 GtkTextBuffer *InputBuffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(Console->InputView));
390 GtkTextMark *Cursor = gtk_text_buffer_get_insert(InputBuffer);
391 gtk_text_buffer_get_iter_at_mark(InputBuffer, Start, Cursor);
392 gtk_text_buffer_get_iter_at_mark(InputBuffer, End, Cursor);
393 gtk_text_iter_backward_chars(Start, g_utf8_strlen(Console->Chars + I, Console->NumChars - I) - 1);
394 Console->NumChars = stpcpy(Console->Chars + I, Combo) - Console->Chars;
395 gtk_text_buffer_delete(InputBuffer, Start, End);
396 gtk_text_buffer_insert(InputBuffer, Start, Console->Chars + I, Console->NumChars - I);
397 return TRUE;
398 }
399 }
400 }
401 }
402 return FALSE;
403 }
404
console_show(console_t * Console,GtkWindow * Parent)405 void console_show(console_t *Console, GtkWindow *Parent) {
406 gtk_window_set_transient_for(GTK_WINDOW(Console->Window), Parent);
407 gtk_widget_show_all(Console->Window);
408 gtk_widget_hide(Console->DebugButtons);
409 gtk_widget_grab_focus(Console->InputView);
410 }
411
console_append(console_t * Console,const char * Buffer,int Length)412 int console_append(console_t *Console, const char *Buffer, int Length) {
413 GtkTextIter End[1];
414 GtkTextBuffer *LogBuffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(Console->LogView));
415 gtk_text_buffer_get_end_iter(LogBuffer, End);
416
417 if (g_utf8_validate(Buffer, Length, NULL)) {
418 gtk_text_buffer_insert_with_tags(LogBuffer, End, Buffer, Length, Console->OutputTag, NULL);
419 } else {
420 gtk_text_buffer_insert_with_tags(LogBuffer, End, "<", 1, Console->BinaryTag, NULL);
421 for (int I = 0; I < Length; ++I) {
422 static char HexChars[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
423 char Bytes[4] = " ??";
424 unsigned char Byte = Buffer[I];
425 Bytes[1] = HexChars[Byte >> 4];
426 Bytes[2] = HexChars[Byte & 15];
427 gtk_text_buffer_insert_with_tags(LogBuffer, End, Bytes, 3, Console->BinaryTag, NULL);
428 }
429 gtk_text_buffer_insert_with_tags(LogBuffer, End, " >", 2, Console->BinaryTag, NULL);
430 }
431 gtk_text_view_scroll_mark_onscreen(GTK_TEXT_VIEW(Console->LogView), Console->EndMark);
432 while (gtk_events_pending()) gtk_main_iteration();
433 return 0;
434 }
435
console_print(console_t * Console,int Count,ml_value_t ** Args)436 ml_value_t *console_print(console_t *Console, int Count, ml_value_t **Args) {
437 GtkTextIter End[1];
438 GtkTextBuffer *LogBuffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(Console->LogView));
439 gtk_text_buffer_get_end_iter(LogBuffer, End);
440 ml_stringbuffer_t Buffer[1] = {ML_STRINGBUFFER_INIT};
441 for (int I = 0; I < Count; ++I) {
442 ml_value_t *Result = ml_stringbuffer_append(Buffer, Args[I]);
443 if (ml_is_error(Result)) return Result;
444 }
445 ml_stringbuffer_foreach(Buffer, Console, (void *)console_append);
446 while (gtk_events_pending()) gtk_main_iteration();
447 return MLNil;
448 }
449
console_printf(console_t * Console,const char * Format,...)450 void console_printf(console_t *Console, const char *Format, ...) {
451 char *Buffer;
452 va_list Args;
453 va_start(Args, Format);
454 int Length = vasprintf(&Buffer, Format, Args);
455 va_end(Args);
456 console_append(Console, Buffer, Length);
457 free(Buffer);
458 }
459
console_set_font(console_t * Console,int Count,ml_value_t ** Args)460 static ml_value_t *console_set_font(console_t *Console, int Count, ml_value_t **Args) {
461 ML_CHECK_ARG_COUNT(2);
462 ML_CHECK_ARG_TYPE(0, MLStringT);
463 ML_CHECK_ARG_TYPE(1, MLIntegerT);
464 Console->FontDescription = pango_font_description_new();
465 pango_font_description_set_family(Console->FontDescription, ml_string_value(Args[0]));
466 pango_font_description_set_size(Console->FontDescription, PANGO_SCALE * ml_integer_value(Args[1]));
467 gtk_widget_override_font(Console->InputView, Console->FontDescription);
468 gtk_widget_override_font(Console->LogView, Console->FontDescription);
469 return MLNil;
470 }
471
console_set_style(console_t * Console,int Count,ml_value_t ** Args)472 static ml_value_t *console_set_style(console_t *Console, int Count, ml_value_t **Args) {
473 ML_CHECK_ARG_COUNT(1);
474 ML_CHECK_ARG_TYPE(0, MLStringT);
475 GtkSourceStyleSchemeManager *StyleManager = gtk_source_style_scheme_manager_get_default();
476 Console->StyleScheme = gtk_source_style_scheme_manager_get_scheme(StyleManager, ml_string_value(Args[0]));
477 gtk_source_buffer_set_style_scheme(GTK_SOURCE_BUFFER(gtk_text_view_get_buffer(GTK_TEXT_VIEW(Console->InputView))), Console->StyleScheme);
478 gtk_source_buffer_set_style_scheme(GTK_SOURCE_BUFFER(gtk_text_view_get_buffer(GTK_TEXT_VIEW(Console->LogView))), Console->StyleScheme);
479 return MLNil;
480 }
481
console_add_cycle(console_t * Console,int Count,ml_value_t ** Args)482 static ml_value_t *console_add_cycle(console_t *Console, int Count, ml_value_t **Args) {
483 ML_CHECK_ARG_COUNT(1);
484 ML_CHECK_ARG_TYPE(0, MLStringT);
485 for (int I = 1; I < Count; ++I) {
486 ML_CHECK_ARG_TYPE(I, MLStringT);
487 stringmap_insert(Console->Cycles, ml_string_value(Args[I - 1]), (void *)ml_string_value(Args[I]));
488 }
489 stringmap_insert(Console->Cycles, ml_string_value(Args[Count - 1]), (void *)ml_string_value(Args[0]));
490 return MLNil;
491 }
492
console_add_combo(console_t * Console,int Count,ml_value_t ** Args)493 static ml_value_t *console_add_combo(console_t *Console, int Count, ml_value_t **Args) {
494 ML_CHECK_ARG_COUNT(2);
495 ML_CHECK_ARG_TYPE(0, MLStringT);
496 ML_CHECK_ARG_TYPE(1, MLStringT);
497 stringmap_insert(Console->Combos, ml_string_value(Args[0]), (void *)ml_string_value(Args[1]));
498 stringmap_insert(Console->Cycles, ml_string_value(Args[1]), (void *)ml_string_value(Args[0]));
499 return MLNil;
500 }
501
console_included_run(ml_state_t * State,ml_value_t * Value)502 static void console_included_run(ml_state_t *State, ml_value_t *Value) {
503 ml_state_t *Caller = State->Caller;
504 if (ml_is_error(Value)) ML_RETURN(Value);
505 return ml_call(Caller, Value, 0, NULL);
506 }
507
console_include_fnx(ml_state_t * Caller,console_t * Console,int Count,ml_value_t ** Args)508 static void console_include_fnx(ml_state_t *Caller, console_t *Console, int Count, ml_value_t **Args) {
509 ML_CHECKX_ARG_COUNT(1);
510 ML_CHECKX_ARG_TYPE(0, MLStringT);
511 ml_state_t *State = new(ml_state_t);
512 State->Caller = Caller;
513 State->Context = Caller->Context;
514 State->run = console_included_run;
515 return ml_load_file(State, (ml_getter_t)ml_compiler_lookup, Console->Compiler, ml_string_value(Args[0]), NULL);
516 }
517
console_update_status(console_t * Console)518 static gboolean console_update_status(console_t *Console) {
519 GC_word HeapSize, FreeBytes, UnmappedBytes, BytesSinceGC, TotalBytes;
520 GC_get_heap_usage_safe(&HeapSize, &FreeBytes, &UnmappedBytes, &BytesSinceGC, &TotalBytes);
521 GC_word UsedSize = HeapSize - FreeBytes;
522 int UsedBase, HeapBase;
523 char UsedUnits, HeapUnits;
524 if (UsedSize < (1 << 10)) {
525 UsedBase = UsedSize;
526 UsedUnits = 'b';
527 } else if (UsedSize < (1 << 20)) {
528 UsedBase = UsedSize >> 10;
529 UsedUnits = 'k';
530 } else if (UsedSize < (1 << 30)) {
531 UsedBase = UsedSize >> 20;
532 UsedUnits = 'M';
533 } else {
534 UsedBase = UsedSize >> 30;
535 UsedUnits = 'G';
536 }
537 if (HeapSize < (1 << 10)) {
538 HeapBase = HeapSize;
539 HeapUnits = 'b';
540 } else if (HeapSize < (1 << 20)) {
541 HeapBase = HeapSize >> 10;
542 HeapUnits = 'k';
543 } else if (HeapSize < (1 << 30)) {
544 HeapBase = HeapSize >> 20;
545 HeapUnits = 'M';
546 } else {
547 HeapBase = HeapSize >> 30;
548 HeapUnits = 'G';
549 }
550
551 char Text[48];
552 sprintf(Text, "Memory: %d%c / %d%c", UsedBase, UsedUnits, HeapBase, HeapUnits);
553 gtk_label_set_text(Console->MemoryBar, Text);
554 /*printf("Memory Status:\n");
555 printf("\tHeapSize = %ld\n", HeapSize);
556 printf("\tFreeBytes = %ld\n", FreeBytes);
557 printf("\tUnmappedBytes = %ld\n", UnmappedBytes);
558 printf("\tBytesSinceGC = %ld\n", BytesSinceGC);
559 printf("\tTotalBytes = %ld\n", TotalBytes);*/
560 return G_SOURCE_CONTINUE;
561 }
562
563 #ifdef ML_SCHEDULER
564
565 static unsigned int Counter = 1000;
566
queue_run(void * Data)567 static gboolean queue_run(void *Data) {
568 ml_queued_state_t QueuedState = ml_scheduler_queue_next();
569 if (!QueuedState.State) return FALSE;
570 Counter = 1000;
571 QueuedState.State->run(QueuedState.State, QueuedState.Value);
572 return TRUE;
573 }
574
console_swap_state(ml_state_t * State,ml_value_t * Value)575 static void console_swap_state(ml_state_t *State, ml_value_t *Value) {
576 if (ml_scheduler_queue_add(State, Value) == 1) g_idle_add(queue_run, NULL);
577 }
578
console_scheduler(ml_context_t * Context)579 static ml_schedule_t console_scheduler(ml_context_t *Context) {
580 return (ml_schedule_t){&Counter, console_swap_state};
581 }
582
console_schedule(ml_state_t * Caller,console_t * Console,int Count,ml_value_t ** Args)583 static void console_schedule(ml_state_t *Caller, console_t *Console, int Count, ml_value_t **Args) {
584 ML_CHECKX_ARG_COUNT(1);
585 ML_CHECKX_ARG_TYPE(0, MLFunctionT);
586 ml_state_t *State = ml_state_new(Caller);
587 ml_context_set(State->Context, ML_SCHEDULER_INDEX, console_scheduler);
588 return ml_call(State, Args[0], Count - 1, Args + 1);
589 }
590
sleep_run(void * Data)591 static gboolean sleep_run(void *Data) {
592 console_swap_state((ml_state_t *)Data, MLNil);
593 return FALSE;
594 }
595
ML_FUNCTIONX(MLSleep)596 ML_FUNCTIONX(MLSleep) {
597 //@sleep
598 ML_CHECKX_ARG_COUNT(1);
599 ML_CHECKX_ARG_TYPE(0, MLNumberT);
600 guint Interval = ml_real_value(Args[0]) * 1000;
601 g_timeout_add(Interval, sleep_run, Caller);
602 }
603
604 #endif
605
console_new(ml_context_t * Context,ml_getter_t GlobalGet,void * Globals)606 console_t *console_new(ml_context_t *Context, ml_getter_t GlobalGet, void *Globals) {
607 gtk_init(0, 0);
608
609 console_t *Console = new(console_t);
610 Console->Base.Type = ConsoleT;
611 Console->Base.run = (ml_state_fn)ml_console_repl_run;
612 Console->Base.Context = Context;
613 Console->Name = strdup("<console>");
614 Console->ParentGetter = GlobalGet;
615 Console->ParentGlobals = Globals;
616 Console->HistoryIndex = 0;
617 Console->HistoryEnd = 0;
618 Console->Parser = ml_parser(NULL, NULL);
619 Console->Compiler = ml_compiler((ml_getter_t)console_global_get, Console);
620 ml_parser_source(Console->Parser, (ml_source_t){Console->Name, 0});
621 Console->Notebook = GTK_NOTEBOOK(gtk_notebook_new());
622
623 #ifdef ML_SCHEDULER
624 ml_context_set(Console->Base.Context, ML_SCHEDULER_INDEX, console_scheduler);
625 #endif
626
627 asprintf((char **)&Console->ConfigPath, "%s/%s", g_get_user_config_dir(), "minilang.conf");
628 Console->Config = g_key_file_new();
629 g_key_file_load_from_file(Console->Config, Console->ConfigPath, G_KEY_FILE_NONE, NULL);
630
631 GtkSourceLanguageManager *LanguageManager = gtk_source_language_manager_get_default();
632 Console->Language = gtk_source_language_manager_get_language(LanguageManager, "minilang");
633
634 GtkSourceBuffer *InputBuffer = gtk_source_buffer_new_with_language(Console->Language);
635 Console->InputView = gtk_source_view_new_with_buffer(InputBuffer);
636 GtkTextTagTable *TagTable = gtk_text_buffer_get_tag_table(GTK_TEXT_BUFFER(InputBuffer));
637 Console->OutputTag = gtk_text_tag_new("log-output");
638 Console->ResultTag = gtk_text_tag_new("log-result");
639 Console->ErrorTag = gtk_text_tag_new("log-error");
640 Console->BinaryTag = gtk_text_tag_new("log-binary");
641 g_object_set(Console->OutputTag,
642 "background", "#FFFFF0",
643 NULL);
644 g_object_set(Console->ResultTag,
645 "background", "#FFF0F0",
646 "foreground", "#303030",
647 "indent", 10,
648 NULL);
649 g_object_set(Console->ErrorTag,
650 "background", "#FFF0F0",
651 "foreground", "#FF0000",
652 "indent", 10,
653 NULL);
654 g_object_set(Console->BinaryTag,
655 "background", "#F0F0FF",
656 "foreground", "#FF8000",
657 NULL);
658 gtk_text_tag_table_add(TagTable, Console->OutputTag);
659 gtk_text_tag_table_add(TagTable, Console->ResultTag);
660 gtk_text_tag_table_add(TagTable, Console->ErrorTag);
661 gtk_text_tag_table_add(TagTable, Console->BinaryTag);
662 GtkSourceBuffer *LogBuffer = gtk_source_buffer_new(TagTable);
663 Console->LogView = gtk_source_view_new_with_buffer(LogBuffer);
664 gtk_text_view_set_editable(GTK_TEXT_VIEW(Console->LogView), FALSE);
665 GtkSourceStyleSchemeManager *StyleManager = gtk_source_style_scheme_manager_get_default();
666 Console->SourceBuffer = gtk_source_buffer_new_with_language(Console->Language);
667
668
669
670 GtkWidget *InputPanel = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 2);
671
672 GtkWidget *DebugButtons = Console->DebugButtons = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 2);
673 GtkWidget *StepInButton = gtk_button_new();
674 gtk_button_set_label(GTK_BUTTON(StepInButton), "In");
675 gtk_box_pack_start(GTK_BOX(DebugButtons), StepInButton, FALSE, FALSE, 2);
676 GtkWidget *StepOverButton = gtk_button_new();
677 gtk_button_set_label(GTK_BUTTON(StepOverButton), "Over");
678 gtk_box_pack_start(GTK_BOX(DebugButtons), StepOverButton, FALSE, FALSE, 2);
679 GtkWidget *StepOutButton = gtk_button_new();
680 gtk_button_set_label(GTK_BUTTON(StepOutButton), "Out");
681 gtk_box_pack_start(GTK_BOX(DebugButtons), StepOutButton, FALSE, FALSE, 2);
682 GtkWidget *ContinueButton = gtk_button_new();
683 gtk_button_set_label(GTK_BUTTON(ContinueButton), "Run");
684 gtk_box_pack_start(GTK_BOX(DebugButtons), ContinueButton, FALSE, FALSE, 2);
685 g_signal_connect(G_OBJECT(StepInButton), "clicked", G_CALLBACK(console_step_in), Console);
686 g_signal_connect(G_OBJECT(StepOverButton), "clicked", G_CALLBACK(console_step_over), Console);
687 g_signal_connect(G_OBJECT(StepOutButton), "clicked", G_CALLBACK(console_step_out), Console);
688 g_signal_connect(G_OBJECT(ContinueButton), "clicked", G_CALLBACK(console_continue), Console);
689 gtk_box_pack_start(GTK_BOX(InputPanel), DebugButtons, FALSE, FALSE, 2);
690
691 GtkWidget *SubmitButton = gtk_button_new();
692 gtk_button_set_image(GTK_BUTTON(SubmitButton), gtk_image_new_from_icon_name("go-jump-symbolic", GTK_ICON_SIZE_BUTTON));
693 GtkWidget *ClearButton = gtk_button_new();
694 gtk_button_set_image(GTK_BUTTON(ClearButton), gtk_image_new_from_icon_name("edit-delete-symbolic", GTK_ICON_SIZE_BUTTON));
695 Console->LogScrolled = gtk_scrolled_window_new(NULL, NULL);
696 gtk_container_add(GTK_CONTAINER(Console->LogScrolled), Console->LogView);
697 gtk_box_pack_start(GTK_BOX(InputPanel), Console->InputView, TRUE, TRUE, 2);
698 gtk_box_pack_start(GTK_BOX(InputPanel), SubmitButton, FALSE, FALSE, 2);
699 gtk_box_pack_start(GTK_BOX(InputPanel), ClearButton, FALSE, FALSE, 2);
700
701 GtkWidget *StyleCombo = gtk_combo_box_text_new();
702 for (const gchar * const * StyleId = gtk_source_style_scheme_manager_get_scheme_ids(StyleManager); StyleId[0]; ++StyleId) {
703 gtk_combo_box_text_append(GTK_COMBO_BOX_TEXT(StyleCombo), StyleId[0], StyleId[0]);
704 }
705
706 g_signal_connect(G_OBJECT(StyleCombo), "changed", G_CALLBACK(console_style_changed), Console);
707
708 GtkWidget *FontButton = gtk_font_button_new();
709 g_signal_connect(G_OBJECT(FontButton), "font-set", G_CALLBACK(console_font_changed), Console);
710
711 Console->Paned = gtk_paned_new(GTK_ORIENTATION_HORIZONTAL);
712 gtk_paned_add1(GTK_PANED(Console->Paned), Console->LogScrolled);
713 gtk_paned_add2(GTK_PANED(Console->Paned), GTK_WIDGET(Console->Notebook));
714 gtk_paned_set_position(GTK_PANED(Console->Paned), 500);
715
716 GtkWidget *SourceView = Console->SourceView = gtk_source_view_new_with_buffer(Console->SourceBuffer);
717 gtk_text_view_set_monospace(GTK_TEXT_VIEW(SourceView), TRUE);
718 gtk_source_view_set_tab_width(GTK_SOURCE_VIEW(SourceView), 4);
719 gtk_source_view_set_highlight_current_line(GTK_SOURCE_VIEW(SourceView), TRUE);
720 gtk_source_view_set_show_line_numbers(GTK_SOURCE_VIEW(SourceView), TRUE);
721 GtkWidget *SourceScrolled = gtk_scrolled_window_new(NULL, NULL);
722 gtk_container_add(GTK_CONTAINER(SourceScrolled), SourceView);
723 gtk_notebook_append_page(Console->Notebook, SourceScrolled, gtk_label_new("<console>"));
724
725 GtkWidget *Container = gtk_box_new(GTK_ORIENTATION_VERTICAL, 2);
726 gtk_box_pack_start(GTK_BOX(Container), Console->Paned, TRUE, TRUE, 2);
727
728 GtkWidget *InputFrame = gtk_frame_new(NULL);
729 gtk_container_add(GTK_CONTAINER(InputFrame), InputPanel);
730 gtk_box_pack_start(GTK_BOX(Container), InputFrame, FALSE, TRUE, 2);
731 g_signal_connect(G_OBJECT(Console->InputView), "key-press-event", G_CALLBACK(console_keypress), Console);
732 g_signal_connect(G_OBJECT(SubmitButton), "clicked", G_CALLBACK(console_submit), Console);
733 g_signal_connect(G_OBJECT(ClearButton), "clicked", G_CALLBACK(console_clear), Console);
734 Console->Window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
735 gtk_window_set_icon_name(GTK_WINDOW(Console->Window), "face-smile");
736
737 GtkWidget *LayoutButton = gtk_button_new_with_label("Layout");
738 g_signal_connect(G_OBJECT(LayoutButton), "clicked", G_CALLBACK(toggle_layout), Console);
739
740 GtkWidget *MenuButton = gtk_menu_button_new();
741 GtkWidget *ActionsBox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 2);
742 gtk_box_pack_start(GTK_BOX(ActionsBox), StyleCombo, FALSE, TRUE, 0);
743 gtk_box_pack_start(GTK_BOX(ActionsBox), FontButton, FALSE, TRUE, 0);
744 gtk_box_pack_start(GTK_BOX(ActionsBox), LayoutButton, FALSE, TRUE, 0);
745 GtkWidget *ActionsPopover = gtk_popover_new(MenuButton);
746 gtk_container_add(GTK_CONTAINER(ActionsPopover), ActionsBox);
747 gtk_menu_button_set_popover(GTK_MENU_BUTTON(MenuButton), ActionsPopover);
748 gtk_widget_show_all(ActionsBox);
749
750
751 GtkWidget *HeaderBar = gtk_header_bar_new();
752 gtk_header_bar_set_title(GTK_HEADER_BAR(HeaderBar), "Minilang");
753 gtk_header_bar_set_has_subtitle(GTK_HEADER_BAR(HeaderBar), FALSE);
754 gtk_header_bar_set_show_close_button(GTK_HEADER_BAR(HeaderBar), TRUE);
755 gtk_header_bar_pack_start(GTK_HEADER_BAR(HeaderBar), MenuButton);
756 gtk_window_set_titlebar(GTK_WINDOW(Console->Window), HeaderBar);
757
758 GtkWidget *MemoryBar = gtk_label_new("");
759 gtk_header_bar_pack_end(GTK_HEADER_BAR(HeaderBar), MemoryBar);
760
761 Console->MemoryBar = GTK_LABEL(MemoryBar);
762
763 gtk_container_add(GTK_CONTAINER(Console->Window), Container);
764 gtk_window_set_default_size(GTK_WINDOW(Console->Window), 640, 480);
765 g_signal_connect(G_OBJECT(Console->Window), "delete-event", G_CALLBACK(gtk_widget_hide_on_delete), Console);
766
767 ml_compiler_define(Console->Compiler, "set_font", ml_cfunction(Console, (ml_callback_t)console_set_font));
768 ml_compiler_define(Console->Compiler, "set_style", ml_cfunction(Console, (ml_callback_t)console_set_style));
769 ml_compiler_define(Console->Compiler, "add_cycle", ml_cfunction(Console, (ml_callback_t)console_add_cycle));
770 ml_compiler_define(Console->Compiler, "add_combo", ml_cfunction(Console, (ml_callback_t)console_add_combo));
771 ml_compiler_define(Console->Compiler, "include", ml_cfunctionx(Console, (ml_callbackx_t)console_include_fnx));
772
773 #ifdef ML_SCHEDULER
774 ml_compiler_define(Console->Compiler, "schedule", ml_cfunctionx(Console, (ml_callbackx_t)console_schedule));
775 ml_compiler_define(Console->Compiler, "sleep", (ml_value_t *)MLSleep);
776 #endif
777
778 if (g_key_file_has_key(Console->Config, "gtk-console", "font", NULL)) {
779 Console->FontName = g_key_file_get_string(Console->Config, "gtk-console", "font", NULL);
780 } else {
781 Console->FontName = "Monospace 10";
782 }
783 Console->FontDescription = pango_font_description_from_string(Console->FontName);
784 gtk_widget_override_font(Console->InputView, Console->FontDescription);
785 gtk_widget_override_font(Console->LogView, Console->FontDescription);
786 gtk_widget_override_font(SourceView, Console->FontDescription);
787 gtk_font_button_set_font_name(GTK_FONT_BUTTON(FontButton), Console->FontName);
788
789 if (g_key_file_has_key(Console->Config, "gtk-console", "style", NULL)) {
790 const char *StyleId = g_key_file_get_string(Console->Config, "gtk-console", "style", NULL);
791 Console->StyleScheme = gtk_source_style_scheme_manager_get_scheme(StyleManager, StyleId);
792 GtkSourceBuffer *InputBuffer = GTK_SOURCE_BUFFER(gtk_text_view_get_buffer(GTK_TEXT_VIEW(Console->InputView)));
793 gtk_source_buffer_set_style_scheme(InputBuffer, Console->StyleScheme);
794 gtk_source_buffer_set_style_scheme(LogBuffer, Console->StyleScheme);
795 gtk_source_buffer_set_style_scheme(Console->SourceBuffer, Console->StyleScheme);
796 gtk_combo_box_set_active_id(GTK_COMBO_BOX(StyleCombo), StyleId);
797 }
798
799 gtk_text_view_set_top_margin(GTK_TEXT_VIEW(Console->LogView), 4);
800 gtk_text_view_set_bottom_margin(GTK_TEXT_VIEW(Console->LogView), 4);
801 gtk_text_view_set_left_margin(GTK_TEXT_VIEW(Console->LogView), 4);
802 gtk_text_view_set_right_margin(GTK_TEXT_VIEW(Console->LogView), 4);
803 gtk_text_view_set_monospace(GTK_TEXT_VIEW(Console->LogView), TRUE);
804 gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(Console->LogView), TRUE);
805 gtk_source_view_set_tab_width(GTK_SOURCE_VIEW(Console->LogView), 4);
806 GtkTextIter End[1];
807 gtk_text_buffer_get_end_iter(GTK_TEXT_BUFFER(LogBuffer), End);
808 Console->EndMark = gtk_text_buffer_create_mark(GTK_TEXT_BUFFER(LogBuffer), "end", End, FALSE);
809
810 GtkSourceMarkAttributes *MarkAttributes = gtk_source_mark_attributes_new();
811 GdkPixbuf *MarkPixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8, 32, 32);
812 gdk_pixbuf_fill(MarkPixbuf, 0xFF8000FF);
813 gtk_source_mark_attributes_set_pixbuf(MarkAttributes, MarkPixbuf);
814 gtk_source_view_set_mark_attributes(GTK_SOURCE_VIEW(Console->LogView), "result", MarkAttributes, 10);
815 gtk_source_view_set_show_line_marks(GTK_SOURCE_VIEW(Console->LogView), TRUE);
816
817 gtk_text_view_set_top_margin(GTK_TEXT_VIEW(Console->InputView), 4);
818 gtk_text_view_set_bottom_margin(GTK_TEXT_VIEW(Console->InputView), 4);
819 gtk_text_view_set_left_margin(GTK_TEXT_VIEW(Console->InputView), 4);
820 gtk_text_view_set_right_margin(GTK_TEXT_VIEW(Console->InputView), 4);
821 gtk_text_view_set_monospace(GTK_TEXT_VIEW(Console->InputView), TRUE);
822 gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(Console->InputView), TRUE);
823 gtk_source_view_set_tab_width(GTK_SOURCE_VIEW(Console->InputView), 4);
824 gtk_source_view_set_show_line_numbers(GTK_SOURCE_VIEW(Console->InputView), TRUE);
825
826 g_timeout_add(1000, (GSourceFunc)console_update_status, Console);
827
828 GError *Error = 0;
829 g_irepository_require(NULL, "Gtk", "3.0", 0, &Error);
830 g_irepository_require(NULL, "GtkSource", "4", 0, &Error);
831 ml_compiler_define(Console->Compiler, "Console", ml_gir_instance_get(Console->Window, NULL));
832 ml_compiler_define(Console->Compiler, "InputView", ml_gir_instance_get(Console->InputView, NULL));
833 ml_compiler_define(Console->Compiler, "LogView", ml_gir_instance_get(Console->LogView, NULL));
834 ml_compiler_define(Console->Compiler, "debugger", interactive_debugger(
835 (void *)console_debug_enter,
836 (void *)console_debug_exit,
837 (void *)console_log,
838 Console,
839 GlobalGet,
840 Globals
841 ));
842
843 return Console;
844 }
845