-#include <assert.h>
+#include "system/stacktrace.h"
+#include "ebisp/gc.h"
+#include "ebisp/interpreter.h"
+#include "ebisp/parser.h"
+#include "ebisp/scope.h"
+#include "ebisp/std.h"
#include "game/level.h"
-#include "game/level/player/rigid_rect.h"
-#include "script/gc.h"
-#include "script/interpreter.h"
-#include "script/parser.h"
-#include "script/scope.h"
#include "sdl/renderer.h"
-#include "system/error.h"
+#include "system/log.h"
+#include "system/log_script.h"
#include "system/lt.h"
+#include "system/nth_alloc.h"
#include "ui/console.h"
+#include "ui/console_log.h"
#include "ui/edit_field.h"
-#include "ui/log.h"
+#include "ui/history.h"
+#include "broadcast.h"
#define FONT_WIDTH_SCALE 3.0f
#define FONT_HEIGHT_SCALE 3.0f
-#define LOG_CAPACITY 10
+#define CONSOLE_LOG_CAPACITY 10
+#define HISTORY_CAPACITY 20
#define PROMPT_HEIGHT (FONT_HEIGHT_SCALE * FONT_CHAR_HEIGHT)
-#define LOG_HEIGHT (FONT_HEIGHT_SCALE * FONT_CHAR_HEIGHT * LOG_CAPACITY)
+#define CONSOLE_LOG_HEIGHT (FONT_HEIGHT_SCALE * FONT_CHAR_HEIGHT * CONSOLE_LOG_CAPACITY)
-#define CONSOLE_HEIGHT (LOG_HEIGHT + PROMPT_HEIGHT)
+#define CONSOLE_HEIGHT (CONSOLE_LOG_HEIGHT + PROMPT_HEIGHT)
#define SLIDE_DOWN_TIME 0.4f
#define CONSOLE_ALPHA (0.80f)
-#define CONSOLE_BACKGROUND (color(0.20f, 0.20f, 0.20f, CONSOLE_ALPHA))
-#define CONSOLE_FOREGROUND (color(0.80f, 0.80f, 0.80f, CONSOLE_ALPHA))
-#define CONSOLE_ERROR (color(0.80f, 0.50f, 0.50f, CONSOLE_ALPHA))
+#define CONSOLE_BACKGROUND (rgba(0.20f, 0.20f, 0.20f, CONSOLE_ALPHA))
+#define CONSOLE_FOREGROUND (rgba(0.80f, 0.80f, 0.80f, CONSOLE_ALPHA))
+#define CONSOLE_ERROR (rgba(0.80f, 0.50f, 0.50f, CONSOLE_ALPHA))
+
+#define CONSOLE_EVAL_RESULT_SIZE 256
struct Console
{
- Lt *lt;
+ Lt lt;
Gc *gc;
struct Scope scope;
Edit_field *edit_field;
- Log *log;
- Level *level;
+ Console_Log *console_log;
+ History *history;
float a;
+ char *eval_result;
};
-/* TODO(#354): Console does not allow to travel the history by pressing up and down */
/* TODO(#355): Console does not support Emacs keybindings */
/* TODO(#356): Console does not support autocompletion */
/* TODO(#357): Console does not show the state of the GC of the script */
/* TODO(#358): Console does not support copy, cut, paste operations */
-static struct EvalResult rect_apply_force(void *param, Gc *gc, struct Scope *scope, struct Expr args)
-{
- assert(gc);
- assert(scope);
- assert(param);
-
- Level *level = (Level*) param;
- const char *rect_id = CAR(args).atom->str;
- struct Expr vector_force_expr = CAR(CDR(args));
- const float force_x = (float) CAR(vector_force_expr).atom->num;
- const float force_y = (float) CDR(vector_force_expr).atom->num;
-
- print_expr_as_sexpr(args); printf("\n");
-
- Rigid_rect *rigid_rect = level_rigid_rect(level, rect_id);
- if (rigid_rect != NULL) {
- printf("Found rect `%s`\n", rect_id);
- printf("Applying force (%f, %f)\n", force_x, force_y);
- rigid_rect_apply_force(rigid_rect, vec(force_x, force_y));
- } else {
- fprintf(stderr, "Couldn't find rigid_rect `%s`", rect_id);
- }
-
- return eval_success(NIL(gc));
-}
-
-Console *create_console(Level *level,
+Console *create_console(Broadcast *broadcast,
const Sprite_font *font)
{
- Lt *lt = create_lt();
+ Lt lt = {0};
if (lt == NULL) {
return NULL;
}
- Console *console = PUSH_LT(lt, malloc(sizeof(Console)), free);
+ Console *console = PUSH_LT(lt, nth_calloc(1, sizeof(Console)), free);
if (console == NULL) {
- throw_error(ERROR_TYPE_LIBC);
RETURN_LT(lt, NULL);
}
console->lt = lt;
console->scope.expr = CONS(console->gc,
NIL(console->gc),
NIL(console->gc));
- set_scope_value(
- console->gc,
- &console->scope,
- SYMBOL(console->gc, "rect-apply-force"),
- NATIVE(console->gc, rect_apply_force, level));
+
+ load_std_library(console->gc, &console->scope);
+ load_log_library(console->gc, &console->scope);
+ /* TODO(#669): how to report EvalResult error from create_console? */
+ broadcast_load_library(broadcast, console->gc, &console->scope);
console->edit_field = PUSH_LT(
lt,
RETURN_LT(lt, NULL);
}
- console->log = PUSH_LT(
+ console->console_log = PUSH_LT(
lt,
- create_log(
+ create_console_log(
font,
vec(FONT_WIDTH_SCALE, FONT_HEIGHT_SCALE),
- LOG_CAPACITY),
- destroy_log);
+ CONSOLE_LOG_CAPACITY),
+ destroy_console_log);
- console->level = level;
console->a = 0;
+ console->eval_result = PUSH_LT(
+ lt,
+ nth_calloc(1, sizeof(char) * CONSOLE_EVAL_RESULT_SIZE),
+ free);
+ if (console->eval_result == NULL) {
+ RETURN_LT(lt, NULL);
+ }
+ memset(console->eval_result, 0, sizeof(char) * CONSOLE_EVAL_RESULT_SIZE);
+
+ console->history = PUSH_LT(
+ lt,
+ create_history(HISTORY_CAPACITY),
+ destroy_history);
+ if (console->history == NULL) {
+ RETURN_LT(lt, NULL);
+ }
+
return console;
}
void destroy_console(Console *console)
{
- assert(console);
+ trace_assert(console);
RETURN_LT0(console->lt);
}
-int console_handle_event(Console *console,
- const SDL_Event *event)
+static int console_eval_input(Console *console)
{
- switch(event->type) {
- case SDL_KEYDOWN:
- switch(event->key.keysym.sym) {
- case SDLK_RETURN: {
- const char *source_code = edit_field_as_text(console->edit_field);
- struct ParseResult parse_result = read_expr_from_string(console->gc,
- source_code);
- if (parse_result.is_error) {
- if (log_push_line(console->log, source_code, CONSOLE_ERROR) < 0) {
- return -1;
- }
-
- if (log_push_line(console->log, parse_result.error_message, CONSOLE_ERROR)) {
- return -1;
- }
-
- edit_field_clean(console->edit_field);
-
- return 0;
- }
+ const char *source_code = edit_field_as_text(console->edit_field);
- struct EvalResult eval_result = eval(
- console->gc,
- &console->scope,
- parse_result.expr);
+ /* TODO(#387): console pushes empty strings to the history */
+ if (history_push(console->history, source_code) < 0) {
+ return -1;
+ }
- if (eval_result.is_error) {
- /* TODO(#360): Console doesn't report any eval errors visually */
- printf("Error:\t");
- print_expr_as_sexpr(eval_result.expr);
- printf("\n");
- }
+ if (console_log_push_line(console->console_log, source_code, CONSOLE_FOREGROUND) < 0) {
+ return -1;
+ }
- gc_collect(console->gc, console->scope.expr);
+ while (*source_code != 0) {
+ struct ParseResult parse_result = read_expr_from_string(console->gc,
+ source_code);
- if (log_push_line(console->log,
- edit_field_as_text(console->edit_field),
- CONSOLE_FOREGROUND) < 0) {
+ if (parse_result.is_error) {
+ if (console_log_push_line(console->console_log, parse_result.error_message, CONSOLE_ERROR)) {
return -1;
}
+
edit_field_clean(console->edit_field);
- } return 0;
+ return 0;
+ }
+
+ struct EvalResult eval_result = eval(
+ console->gc,
+ &console->scope,
+ parse_result.expr);
+
+ if (expr_as_sexpr(
+ eval_result.expr,
+ console->eval_result,
+ CONSOLE_EVAL_RESULT_SIZE) < 0) {
+ return -1;
+ }
+
+ if (console_log_push_line(console->console_log,
+ console->eval_result,
+ eval_result.is_error ?
+ CONSOLE_ERROR :
+ CONSOLE_FOREGROUND)) {
+ return -1;
+ }
+
+ source_code = next_token(parse_result.end).begin;
+ }
+
+ gc_collect(console->gc, console->scope.expr);
+ edit_field_clean(console->edit_field);
+
+ return 0;
+}
+
+int console_handle_event(Console *console,
+ const SDL_Event *event)
+{
+ switch(event->type) {
+ case SDL_KEYDOWN:
+ switch(event->key.keysym.sym) {
+ case SDLK_RETURN:
+ return console_eval_input(console);
+
+ case SDLK_UP:
+ edit_field_replace(
+ console->edit_field,
+ history_current(console->history));
+ history_prev(console->history);
+ return 0;
+
+ case SDLK_DOWN:
+ edit_field_replace(
+ console->edit_field,
+ history_current(console->history));
+ history_next(console->history);
+ return 0;
}
break;
}
return -1;
}
- if (log_render(console->log,
+ if (console_log_render(console->console_log,
renderer,
vec(0.0f, y)) < 0) {
return -1;
if (edit_field_render(console->edit_field,
renderer,
- vec(0.0f, y + LOG_HEIGHT)) < 0) {
+ vec(0.0f, y + CONSOLE_LOG_HEIGHT)) < 0) {
return -1;
}
int console_update(Console *console, float delta_time)
{
- assert(console);
-
- /* TODO(#366): console slide down animation doesn't have any easing */
+ trace_assert(console);
if (console->a < 1.0f) {
console->a += 1.0f / SLIDE_DOWN_TIME * delta_time;
void console_slide_down(Console *console)
{
- assert(console);
+ trace_assert(console);
console->a = 0.0f;
}