Skip to content

Commit

Permalink
Add console
Browse files Browse the repository at this point in the history
  • Loading branch information
evanlin96069 committed Feb 23, 2024
1 parent ea5b9e3 commit 10f88c9
Show file tree
Hide file tree
Showing 11 changed files with 230 additions and 117 deletions.
5 changes: 3 additions & 2 deletions docs/configs.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,10 @@ The command will first search for the file in the current directory, then the co
| `hldb_load` | cmd | Load a syntax highlighting JSON file. |
| `hldb_reload_all` | cmd | Reload syntax highlighting database. |
| `newline` | cmd | Set the EOL sequence (LF/CRLF). |
| ` alias` | cmd | Alias a command. |
| `cmd_expand_depth` | 100 | Max depth for alias expansion. |
| `alias` | cmd | Alias a command. |
| `cmd_expand_depth` | 1024 | Max depth for alias expansion. |
| `echo` | cmd | Echo text to console. |
| `clear` | cmd | Clear all console output. |
| `help` | cmd | Find help about a convar/concommand. |

## Color
Expand Down
133 changes: 81 additions & 52 deletions src/config.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
#include "terminal.h"
#include "utils.h"

EditorConCmdArgs args;

static void cvarSyntaxCallback(void);
static void cvarExplorerCallback(void);
static void cvarMouseCallback(void);
Expand All @@ -30,7 +32,7 @@ CONVAR(ignorecase, "Use case insensitive search. Set to 2 to use smart case.",
CONVAR(mouse, "Enable mouse mode.", "1", cvarMouseCallback);
CONVAR(osc52_copy, "Copy to system clipboard using OSC52.", "1", NULL);

CONVAR(cmd_expand_depth, "Max depth for alias expansion.", "100", NULL);
CONVAR(cmd_expand_depth, "Max depth for alias expansion.", "1024", NULL);

CONVAR(ex_default_width, "File explorer default width.", "40", NULL);
CONVAR(ex_show_hidden, "Show hidden files in the file explorer.", "1",
Expand Down Expand Up @@ -117,7 +119,7 @@ const ColorElement color_element_map[EDITOR_COLOR_COUNT] = {

CON_COMMAND(color, "Change the color of an element.") {
if (args.argc != 2 && args.argc != 3) {
editorSetStatusMsg("Usage: color <element> [color]");
editorMsg("Usage: color <element> [color]");
return;
}

Expand All @@ -130,22 +132,22 @@ CON_COMMAND(color, "Change the color of an element.") {
}
}
if (!target) {
editorSetStatusMsg("Unknown element \"%s\".", args.argv[1]);
editorMsg("Unknown element \"%s\".", args.argv[1]);
return;
}

if (args.argc == 2) {
char buf[8];
colorToStr(*target, buf);
editorSetStatusMsg("%s = %s", args.argv[1], buf);
editorMsg("%s = %s", args.argv[1], buf);
} else if (args.argc == 3) {
*target = strToColor(args.argv[2]);
}
}

CON_COMMAND(exec, "Execute a config file.") {
if (args.argc != 2) {
editorSetStatusMsg("Usage: exec <file>");
editorMsg("Usage: exec <file>");
return;
}

Expand All @@ -160,15 +162,15 @@ CON_COMMAND(exec, "Execute a config file.") {
PATH_CAT("%s", CONF_DIR, "%s"), getenv(ENV_HOME), filename);

if (!editorLoadConfig(config_path)) {
editorSetStatusMsg("exec: Failed to exec \"%s\"", args.argv[1]);
editorMsg("exec: Failed to exec \"%s\"", args.argv[1]);
return;
}
}
}

CON_COMMAND(hldb_load, "Load a syntax highlighting JSON file.") {
if (args.argc != 2) {
editorSetStatusMsg("Usage: hldb_load <json file>");
editorMsg("Usage: hldb_load <json file>");
return;
}

Expand All @@ -183,8 +185,7 @@ CON_COMMAND(hldb_load, "Load a syntax highlighting JSON file.") {
PATH_CAT("%s", CONF_DIR, "%s"), getenv(ENV_HOME), filename);

if (!editorLoadHLDB(config_path)) {
editorSetStatusMsg("hldb_load: Failed to load \"%s\"",
args.argv[1]);
editorMsg("hldb_load: Failed to load \"%s\"", args.argv[1]);
return;
}
}
Expand All @@ -202,8 +203,7 @@ CON_COMMAND(hldb_reload_all, "Reload syntax highlighting database.") {

CON_COMMAND(newline, "Set the EOL sequence (LF/CRLF).") {
if (args.argc == 1) {
editorSetStatusMsg("%s",
(gCurFile->newline == NL_UNIX) ? "LF" : "CRLF");
editorMsg("%s", (gCurFile->newline == NL_UNIX) ? "LF" : "CRLF");
return;
}

Expand All @@ -212,7 +212,7 @@ CON_COMMAND(newline, "Set the EOL sequence (LF/CRLF).") {
} else if (strCaseCmp(args.argv[1], "crlf") == 0) {
gCurFile->newline = NL_DOS;
} else {
editorSetStatusMsg("Usage: newline <LF/CRLF>");
editorMsg("Usage: newline <LF/CRLF>");
}
}

Expand All @@ -237,33 +237,37 @@ CON_COMMAND(echo, "Echo text to console.") {
break;
}
}
editorSetStatusMsg("%s", buf);
editorMsg("%s", buf);
}

CON_COMMAND(clear, "Clear all console output.") {
UNUSED(args.argc);
editorMsgClear();
}

static void showCmdHelp(const EditorConCmd* cmd) {
if (cmd->has_callback) {
editorSetStatusMsg("\"%s\" - %s", cmd->name, cmd->help_string);
editorMsg("\"%s\" - %s", cmd->name, cmd->help_string);
} else {
if (strcmp(cmd->cvar.default_string, cmd->cvar.string_val) == 0) {
editorSetStatusMsg("\"%s\" = \"%s\" - %s", cmd->name,
cmd->cvar.string_val, cmd->help_string);
editorMsg("\"%s\" = \"%s\" - %s", cmd->name, cmd->cvar.string_val,
cmd->help_string);
} else {
editorSetStatusMsg("\"%s\" = \"%s\" (def. \"%s\" ) - %s", cmd->name,
cmd->cvar.string_val, cmd->cvar.default_string,
cmd->help_string);
editorMsg("\"%s\" = \"%s\" (def. \"%s\" ) - %s", cmd->name,
cmd->cvar.string_val, cmd->cvar.default_string,
cmd->help_string);
}
}
}

CON_COMMAND(help, "Find help about a convar/concommand.") {
if (args.argc != 2) {
editorSetStatusMsg("Usage: help <command>");
editorMsg("Usage: help <command>");
return;
}
EditorConCmd* cmd = editorFindCmd(args.argv[1]);
if (!cmd) {
editorSetStatusMsg("help: No cvar or command named \"%s\".",
args.argv[1]);
editorMsg("help: No cvar or command named \"%s\".", args.argv[1]);
return;
}
showCmdHelp(cmd);
Expand All @@ -286,7 +290,7 @@ CON_COMMAND(crash, "Cause the editor to crash. (Debug!!)") {
// SIGABRT
abort();
default:
editorSetStatusMsg("Unknown crash type.");
editorMsg("Unknown crash type.");
}
}

Expand Down Expand Up @@ -376,23 +380,23 @@ static CmdAlias* findAlias(const char* name) {

CON_COMMAND(alias, "Alias a command.") {
if (args.argc < 2) {
editorSetStatusMsg("Usage: alias <name> [value]");
editorMsg("Usage: alias <name> [value]");
return;
}

char* s = args.argv[1];
if (strlen(s) >= MAX_ALIAS_NAME) {
editorSetStatusMsg("Alias name is too long");
editorMsg("Alias name is too long");
return;
}

// If the alias already exists, reuse it
CmdAlias* a = findAlias(s);
if (args.argc == 2) {
if (!a) {
editorSetStatusMsg("\"%s\" is not aliased", s);
editorMsg("\"%s\" is not aliased", s);
} else {
editorSetStatusMsg("\"%s\" = \"%s\"", s, a->value);
editorMsg("\"%s\" = \"%s\"", s, a->value);
}
return;
}
Expand Down Expand Up @@ -433,18 +437,23 @@ CON_COMMAND(alias, "Alias a command.") {

static void parseLine(const char* cmd, int depth);

static void cvarCmdCallback(EditorConCmd* cmd, EditorConCmdArgs args) {
static void cvarCmdCallback(EditorConCmd* cmd) {
if (args.argc < 2) {
showCmdHelp(cmd);
return;
}
editorSetConVar(&cmd->cvar, args.argv[1]);
}

static void executeCommand(EditorConCmdArgs args, int depth) {
static void executeCommand(int depth) {
if (args.argc < 1)
return;

if (args.argc > COMMAND_MAX_ARGC) {
editorMsg("Command overflows the argument buffer. Clamped!");
args.argc = COMMAND_MAX_ARGC;
}

CmdAlias* a = findAlias(args.argv[0]);
if (a) {
parseLine(a->value, depth + 1);
Expand All @@ -453,71 +462,88 @@ static void executeCommand(EditorConCmdArgs args, int depth) {

EditorConCmd* cmd = editorFindCmd(args.argv[0]);
if (!cmd) {
editorSetStatusMsg("Unknown command \"%s\".", args.argv[0]);
editorMsg("Unknown command \"%s\".", args.argv[0]);
return;
}

if (cmd->has_callback) {
cmd->callback(args);
cmd->callback();
} else {
cvarCmdCallback(cmd, args);
cvarCmdCallback(cmd);
}
}

static void resetArgs() {
for (int i = 0; i < args.argc; i++) {
free(args.argv[i]);
}
args.argc = 0;
}

static void parseLine(const char* cmd, int depth) {
if (depth > CONVAR_GETINT(cmd_expand_depth)) {
editorSetStatusMsg("Reached max alias expansion depth.");
editorMsg("Reached max alias expansion depth.");
return;
}

// Command line parsing
EditorConCmdArgs args = {0};
resetArgs();
while (*cmd != '\0' && *cmd != '#') {
switch (*cmd) {
case '\t':
case ' ':
cmd++;
break;

case '"':
case ';':
executeCommand(depth);
resetArgs();
cmd++;
for (int i = 0; *cmd != '\0' && *cmd != '"'; i++) {
args.argv[args.argc][i] = *cmd;
cmd++;
}
break;

if (*cmd == '"') {
default: {
bool in_quote = (*cmd == '"');
if (in_quote) {
cmd++;
}
args.argc++;
break;

case ';':
executeCommand(args, depth);
memset(&args, 0, sizeof(EditorConCmdArgs));
cmd++;
break;
char* buf = calloc_s(sizeof(char), COMMAND_MAX_LENGTH);

default:
for (int i = 0;
*cmd != '\0' && *cmd != '#' && *cmd != ';' && *cmd != ' ';
*cmd != '\0' &&
(in_quote ? (*cmd != '"')
: (*cmd != '#' && *cmd != ';' && *cmd != ' '));
i++) {
args.argv[args.argc][i] = *cmd;
buf[i] = *cmd;
cmd++;
}

if (in_quote) {
cmd++;
}

if (args.argc < COMMAND_MAX_ARGC) {
args.argv[args.argc] = buf;
} else {
free(buf);
}

// Let argc go pass COMMAND_MAX_ARGC.
// We will detect it in executeCommand.
args.argc++;
}
}
}

executeCommand(args, depth);
executeCommand(depth);
}

bool editorLoadConfig(const char* path) {
FILE* fp = fopen(path, "r");
if (!fp)
return false;

char buf[128] = {0};
char buf[COMMAND_MAX_LENGTH] = {0};
while (fgets(buf, sizeof(buf), fp)) {
buf[strcspn(buf, "\r\n")] = '\0';
parseLine(buf, 0);
Expand Down Expand Up @@ -552,6 +578,7 @@ void editorInitConfig(void) {
INIT_CONCOMMAND(alias);
INIT_CONCOMMAND(exec);
INIT_CONCOMMAND(echo);
INIT_CONCOMMAND(clear);
INIT_CONCOMMAND(help);

#ifdef _DEBUG
Expand All @@ -577,6 +604,8 @@ void editorFreeConfig(void) {
free(temp->value);
free(temp);
}

resetArgs();
}

void editorOpenConfigPrompt(void) {
Expand Down
14 changes: 8 additions & 6 deletions src/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,27 +42,29 @@ extern const ColorElement color_element_map[EDITOR_COLOR_COUNT];
.cvar = {.default_string = _default_string, .callback = _callback}}

#define CON_COMMAND(_name, _help_string) \
static void _name##_callback(EditorConCmdArgs args); \
static void _name##_callback(void); \
EditorConCmd ccmd_##_name = {.name = #_name, \
.help_string = _help_string, \
.callback = _name##_callback}; \
void _name##_callback(EditorConCmdArgs args)
void _name##_callback(void)

#define INIT_CONVAR(name) editorInitConVar(&cvar_##name)
#define INIT_CONCOMMAND(name) editorInitConCmd(&ccmd_##name)

#define CONVAR_GETINT(name) cvar_##name.cvar.int_val
#define CONVAR_GETSTR(name) cvar_##name.cvar.string_val

#define COMMAND_MAX_ARGC 16
#define COMMAND_MAX_LENGTH 64
#define COMMAND_MAX_ARGC 64
#define COMMAND_MAX_LENGTH 512

typedef struct EditorConCmdArgs {
int argc;
char argv[COMMAND_MAX_ARGC][COMMAND_MAX_LENGTH];
char* argv[COMMAND_MAX_ARGC];
} EditorConCmdArgs;

typedef void (*CommandCallback)(EditorConCmdArgs args);
extern EditorConCmdArgs args;

typedef void (*CommandCallback)(void);
typedef void (*ConVarCallback)(void);

typedef struct EditorConVar {
Expand Down
Loading

0 comments on commit 10f88c9

Please sign in to comment.