~ecs/sd

f654cc6705b2e65181f3e1d915388bb592bceb5a — Eyal Sawady 9 months ago d988cda
Use registry-based commands for normal mode

Still TODO are parametrized commands and counts.
6 files changed, 166 insertions(+), 65 deletions(-)

M commands.c
M commands.h
M common.c
M common.h
M input.c
M rendering.c
M commands.c => commands.c +99 -1
@@ 1,4 1,5 @@
#include "common.h"
#include "rendering.h"

int
quit(struct state *state)


@@ 22,7 23,7 @@ nop(struct state *state)
}

int
init_commands(struct registry *reg)
init_creg(struct registry *reg)
{
	init_registry(reg);
	if (register_command(reg, "q", quit)) {


@@ 37,3 38,100 @@ init_commands(struct registry *reg)
	/* TODO: more commands */
	return 0;
}

int
h(struct state *state)
{
	/* TODO: horizontal scrolling */
	if (state->cur_x > 0) {
		state->cur_x--;
	}
	return 0;
}

int
j(struct state *state)
{
	if (state->cur_y + state->cur_line >= state->lines->sz - 1) {
		return 0;
	}
	if (state->cur_y < state->rows - 2) {
		state->cur_y++;
	} else {
		state->cur_line++;
	}
	return 0;
}

int
k(struct state *state)
{
	if (state->cur_y > 0) {
		state->cur_y--;
	} else if (state->cur_line > 0) {
		state->cur_line--;
	}
	return 0;
}

int
l(struct state *state)
{
	/* TODO: horizontal scrolling */
	if (state->cur_x < state->cols - 1) {
		state->cur_x++;
	}
	return 0;
}

int
colon(struct state *state)
{
	state->mode = CMD;
	set_row(&state->status, ":");
	return 0;
}

int
form_feed(struct state *state)
{
	set_row(&state->status, "");
	refresh_screen(state);
	return 0;
}

int
i(struct state *state)
{
	state->mode = INPUT;
	set_row(&state->status, "INSERT");
	return 0;
}

int
init_nreg(struct registry *reg)
{
	init_registry(reg);
	if (register_command(reg, "j", j)) {
		return -1;
	}
	if (register_command(reg, "k", k)) {
		return -1;
	}
	if (register_command(reg, "h", h)) {
		return -1;
	}
	if (register_command(reg, "l", l)) {
		return -1;
	}
	if (register_command(reg, "i", i)) {
		return -1;
	}
	if (register_command(reg, ":", colon)) {
		return -1;
	}
	if (register_command(reg, "\f", form_feed)) {
		return -1;
	}
	return 0;
}

M commands.h => commands.h +2 -1
@@ 1,5 1,6 @@
#ifndef COMMAND_H
#define COMMAND_H
#include "common.h"
int init_commands(struct registry *reg);
int init_creg(struct registry *reg);
int init_nreg(struct registry *reg);
#endif

M common.c => common.c +18 -5
@@ 1,3 1,4 @@
#define _XOPEN_SOURCE 500
#include <errno.h>
#include <stdint.h>
#include <stdio.h>


@@ 241,7 242,7 @@ register_command(struct registry *reg, const char *cmd,
	if (!reg->contents || reg->capacity < reg->sz + 1) {
		grow_registry(reg, reg->sz + 1);
	}
	reg->contents[reg->sz].cmd = cmd;
	reg->contents[reg->sz].cmd = strdup(cmd);
	reg->contents[reg->sz].func = func;
	reg->sz++;



@@ 251,11 252,23 @@ register_command(struct registry *reg, const char *cmd,
int
run_command(struct state *state, const char *cmd)
{
	/* TODO: parametrized commands, counts */
	size_t i;
	for (i = 0; i < state->reg.sz; i++) {
		if (!strcmp(cmd, state->reg.contents[i].cmd)) {
			int ret = state->reg.contents[i].func(state);
			set_row(&state->status, "");
	struct registry reg;
	switch (state->mode) {
	case NORMAL:
		reg = state->nreg;
		break;
	case CMD:
		reg = state->creg;
		break;
	default:
		/* TODO: insert-mode commands */
		return -2;
	}
	for (i = 0; i < reg.sz; i++) {
		if (!strcmp(cmd, reg.contents[i].cmd)) {
			int ret = reg.contents[i].func(state);
			if (ret != -2) {
				return ret;
			}

M common.h => common.h +3 -1
@@ 58,7 58,9 @@ struct state {
		} *contents;
		size_t capacity;
		size_t sz;
	} reg;
	} creg;

	struct registry nreg;

	char *filename;
};

M input.c => input.c +29 -55
@@ 8,67 8,41 @@
#include "term.h"

static int
process_normal(const char c, struct state *state)
process_normal(char c, struct state *state)
{
	char c_str[] = {'\0', '\0'};
	int ret = 0;
	switch (c) {
	case ':':
		state->mode = CMD;
		set_row(&state->status, ":");
		break;
	case 'i':
		state->mode = INPUT;
		set_row(&state->status, "INSERT");
		break;
	/* TODO: long lines */
	case DEL:
	case 'h':
		if (state->cur_x > 0) {
			state->cur_x--;
		}
		break;
	case 'j':
		if (state->cur_y + state->cur_line >= state->lines->sz - 1) {
			break;
		}
		if (state->cur_y < state->rows - 2) {
			state->cur_y++;
		} else {
			state->cur_line++;
	case CTRL_C:
		if (strlen(state->insert_buffer.contents) == 0) {
			return -1;
		}
		break;
	case 'k':
		if (state->cur_y > 0) {
			state->cur_y--;
		} else if (state->cur_line > 0) {
			state->cur_line--;
		/* fallthrough */
	case ESCAPE:
		if (strlen(state->insert_buffer.contents) > 0) {
			set_row(&state->insert_buffer, "");
		}
		break;
	case 'l':
		if (state->cur_x < state->cols - 1) {
			state->cur_x++;
	case DEL:
		if (strlen(state->insert_buffer.contents) > 1) {
			char *sibc = state->insert_buffer.contents;
			sibc[strlen(sibc) - 1] = '\0';
			return 0;
		}
		break;
	case CTRL_C:
		return -1;
	case '\f':
		set_row(&state->status, "");
		refresh_screen(state);
		break;
		c = 'h';
		/* fallthrough */
	default:
		set_row(&state->status, "Error: unknown command '");

		if (iscntrl(c)) {
			/* '\' + 2 chars + '\0' */
			char buf[4];
			sprintf(buf, "\\%02x", c);
			append_row(&state->status, buf);
		} else {
			char buf[2] = {0, 0};
			buf[0] = c;
			append_row(&state->status, buf);
		c_str[0] = c;
		append_row(&state->insert_buffer, c_str);
		ret = run_command(state, state->insert_buffer.contents);
		switch (ret) {
		case -2:
			break;
		default:
			set_row(&state->insert_buffer, "");
		}
		append_row(&state->status, "'");
	}

	{
		size_t lineno = state->cur_line + state->cur_y;
		size_t lineln = strlen(state->lines->contents[lineno].contents);


@@ 80,7 54,7 @@ process_normal(const char c, struct state *state)
		}
	}

	return 0;
	return ret;
}

static int


@@ 159,8 133,8 @@ process_cmd(char c, struct state *state) {
	case '\n':
		{
			char *ssc = state->status.contents;
			int ret =
				run_command(state, ssc + 1);
			int ret = run_command(state, ssc + 1);
			set_row(&state->status, "");
			state->mode = NORMAL;
			if (ret == -2) {
				/* +1 for NULL, -1 for ':' */

M rendering.c => rendering.c +15 -2
@@ 55,7 55,8 @@ init_state(struct state *state, const char *filename)
	state->cur_line = 0;
	state->lines = new_line_arr();

	init_commands(&state->reg);
	init_creg(&state->creg);
	init_nreg(&state->nreg);

	state->filename = strdup(filename);



@@ 85,6 86,9 @@ move_cursor(struct state *state, struct line buf)
			}
		}
	}
	if (state->mode != INPUT) {
		return 0;
	}
	for (i = 0; i < strlen(state->insert_buffer.contents); i++) {
		switch (state->insert_buffer.contents[i]) {
		case '\t':


@@ 118,7 122,8 @@ refresh_screen(struct state *state)

	for (y = state->cur_line; y < state->cur_line + (size_t)state->rows - 1;
			y++) {
		if (y == (size_t)state->cur_y + state->cur_line) {
		if (y == (size_t)state->cur_y + state->cur_line
				&& state->mode == INPUT) {
			struct line cur = state->lines->contents[y];
			char contents_x = cur.contents[state->cur_x];
			cur.contents[state->cur_x] = '\0';


@@ 140,6 145,14 @@ refresh_screen(struct state *state)

	append_row(&buf, state->status.contents);

	if (state->mode == NORMAL) {
		char b[BUFSIZ];
		size_t ibuf_len = strlen(state->insert_buffer.contents);
		sprintf(b, "\r" VT100 "%dC", state->cols - (int)ibuf_len);
		append_row(&buf, b);
		append_row(&buf, state->insert_buffer.contents);
	}

	if (state->mode != CMD) {
		char cursor_pos[BUFSIZ];
		sprintf(cursor_pos, VT100 "%d;0H", state->cur_y + 1);