1 module re.ng.diag.console;
2 
3 import re.input.input;
4 import re.core;
5 import re.math;
6 import re.gfx;
7 import re.ng.diag.default_commands;
8 import re.util.interop;
9 import std.conv;
10 import std.string;
11 import std.array;
12 import std.range;
13 static import raygui;
14 
15 /// overlay debug console
16 debug class Console {
17     /// the key that opens the console
18     public Keys key = Keys.KEY_GRAVE;
19     /// the character representation of the console key
20     public char key_char = '`';
21     /// whether the console is open
22     public bool open = false;
23     /// 64 chars of space
24     private enum blank = "\0                                                                ";
25 
26     /// console commands
27     public Command[string] commands;
28     private enum height = 30;
29     private char* console_text;
30     private Appender!(string[]) _history;
31     private int _history_depth = 0;
32 
33     /// represents a command for the debug console
34     struct Command {
35         string name;
36         void function(string[]) action;
37         string help;
38     }
39 
40     /// create a debug console
41     this() {
42         console_text = blank.c_str();
43 
44         // add default commands
45         add_command(Command("help", &DefaultCommands.c_help, "lists available commands"));
46         add_command(Command("entities", &DefaultCommands.c_entities, "lists scene entities"));
47         add_command(Command("dump", &DefaultCommands.c_dump, "dump a component"));
48         add_command(Command("inspect", &DefaultCommands.c_inspect,
49                 "open the inspector on a component"));
50     }
51 
52     private void add_command(Command command) {
53         commands[command.name] = command;
54     }
55 
56     public void update() {
57         // remove all instances of c from str
58         void sstrip(char* str, char c) {
59             char* pr = str;
60             char* pw = str;
61             while (*pr) {
62                 *pw = *pr++;
63                 pw += (*pw != c);
64             }
65             *pw = '\0';
66         }
67 
68         // remove console key from textbox
69         sstrip(console_text, '`');
70 
71         void load_history_entry() {
72             // load a history entry
73             auto entry = _history.data[$ - _history_depth];
74             console_text = entry.c_str();
75         }
76 
77         // arrows can scroll through history
78         if (Input.is_key_pressed(Keys.KEY_UP)) {
79             if (_history_depth < _history.data.length) {
80                 _history_depth++;
81                 load_history_entry();
82             }
83         } else if (Input.is_key_pressed(Keys.KEY_DOWN)) {
84             if (_history_depth > 0) {
85                 _history_depth--;
86                 load_history_entry();
87             } else {
88                 console_text = blank.c_str();
89             }
90         }
91     }
92 
93     public void render() {
94         alias pad = Core.debugger.screen_padding;
95         auto console_bg_bounds = Rectangle(pad,
96                 Core.window.height - pad - height, Core.window.width - pad * 2, height);
97         // console background
98         // raylib.DrawRectangleRec(console_bg_bounds, bg_col);
99         auto bg_padding = 4;
100         auto console_bounds = Rectangle(console_bg_bounds.x + bg_padding, console_bg_bounds.y + bg_padding,
101                 console_bg_bounds.width - bg_padding * 2, console_bg_bounds.height - bg_padding * 2);
102         // console text
103         if (raygui.GuiTextBox(console_bounds, console_text, 64, true)) {
104             auto console_text_str = to!string(console_text);
105             if (console_text_str.length > 0) {
106                 _history_depth = 0; // we just executed a command, no longer in history
107                 _history ~= console_text_str; // add to history
108                 auto raw_command = console_text_str.split(' ');
109                 process_command(raw_command.front, raw_command.drop(1));
110                 // pass command
111                 console_text[0] = '\0'; // clear text
112             }
113         }
114     }
115 
116     /// process a command in the console
117     public void process_command(string cmd, string[] args) {
118         if (cmd in commands) {
119             commands[cmd].action(args);
120         } else {
121             Core.log.err(format("unrecognized command: %s", cmd));
122         }
123     }
124 }