Skip to content

Commit

Permalink
Macro support
Browse files Browse the repository at this point in the history
At some point this should be optimized further at the moment there
is some 20 byte overhead for each entered key.
  • Loading branch information
martanne committed Dec 18, 2014
1 parent 46ffdc3 commit b8456fa
Show file tree
Hide file tree
Showing 10 changed files with 179 additions and 62 deletions.
4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
include config.mk

SRC = editor.c window.c text.c text-motions.c text-objects.c register.c
HDR := ${SRC:.c=.h} syntax.h util.h config.def.h
SRC = editor.c window.c text.c text-motions.c text-objects.c register.c buffer.c
HDR := ${SRC:.c=.h} macro.h syntax.h util.h config.def.h
SRC += vis.c
OBJ = ${SRC:.c=.o}
ALL = ${SRC} ${HDR} config.mk Makefile LICENSE README vis.1
Expand Down
7 changes: 6 additions & 1 deletion README
Original file line number Diff line number Diff line change
Expand Up @@ -414,6 +414,12 @@ and their current support in vis.
again). The same restriction also applies to commands which are not
implemented in terms of operators, such as 'o', 'O', 'J' etc.

Macros
------

[a-z] are recoginized macro names, q starts a recording, @ plays it back.
@@ refers to the least recently recorded macro.

Command line prompt
-------------------

Expand Down Expand Up @@ -496,7 +502,6 @@ and their current support in vis.
- right-to-left text
- tabs (as in multiple workspaces)
- ex mode
- macro recording

How to help?
------------
Expand Down
54 changes: 54 additions & 0 deletions buffer.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
#include <stdlib.h>
#include <string.h>

#include "buffer.h"
#include "util.h"

#define BUF_SIZE 1024

bool buffer_alloc(Buffer *buf, size_t size) {
if (size < BUF_SIZE)
size = BUF_SIZE;
if (buf->size < size) {
if (buf->size > 0)
size *= 2;
buf->data = realloc(buf->data, size);
if (!buf->data) {
buf->size = 0;
buf->len = 0;
return false;
}
buf->size = size;
}
return true;
}

void buffer_truncate(Buffer *buf) {
buf->len = 0;
}

void buffer_free(Buffer *buf) {
if (!buf)
return;
free(buf->data);
buf->data = NULL;
buf->len = 0;
buf->size = 0;
}

bool buffer_put(Buffer *buf, void *data, size_t len) {
if (!buffer_alloc(buf, len))
return false;
memcpy(buf->data, data, len);
buf->len = len;
return true;
}

bool buffer_append(Buffer *buf, void *data, size_t len) {
size_t rem = buf->size - buf->len;
if (len > rem && !buffer_alloc(buf, buf->size + len - rem))
return false;
memcpy(buf->data + buf->len, data, len);
buf->len += len;
return true;
}
20 changes: 20 additions & 0 deletions buffer.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#ifndef BUFFER_H
#define BUFFER_H

#include <stddef.h>
#include <stdbool.h>
#include "text.h"

typedef struct {
char *data; /* NULL if empty */
size_t len; /* current length of data */
size_t size; /* maximal capacity of the buffer */
} Buffer;

void buffer_free(Buffer *buf);
bool buffer_alloc(Buffer *buf, size_t size);
void buffer_truncate(Buffer *buf);
bool buffer_put(Buffer *buf, void *data, size_t len);
bool buffer_append(Buffer *buf, void *data, size_t len);

#endif
11 changes: 8 additions & 3 deletions config.def.h
Original file line number Diff line number Diff line change
Expand Up @@ -73,10 +73,11 @@ static void statusbar(EditorWin *win) {
window_cursor_getxy(win->win, &line, &col);
wattrset(win->statuswin, focused ? A_REVERSE|A_BOLD : A_REVERSE);
mvwhline(win->statuswin, 0, 0, ' ', win->width);
mvwprintw(win->statuswin, 0, 0, "%s %s %s",
mvwprintw(win->statuswin, 0, 0, "%s %s %s %s",
mode->name && mode->name[0] == '-' ? mode->name : "",
text_filename_get(win->text),
text_modified(win->text) ? "[+]" : "");
text_modified(win->text) ? "[+]" : "",
vis->recording ? "recording": "");
char buf[win->width + 1];
int len = snprintf(buf, win->width, "%d, %d", line, col);
if (len > 0) {
Expand All @@ -86,9 +87,11 @@ static void statusbar(EditorWin *win) {
}

/* called before any other keybindings are checked, if the function returns false
* the key is completely ignored. used to clear a user visible message. */
* the key is completely ignored. */
static bool vis_keypress(Key *key) {
editor_info_hide(vis);
if (vis->recording)
macro_append(vis->recording, key, sizeof(*key));
return true;
}

Expand Down Expand Up @@ -407,6 +410,8 @@ static KeyBinding vis_mode_normal[] = {
{ { NONE('z'), NONE('t') }, window, { .w = window_redraw_top } },
{ { NONE('z'), NONE('z') }, window, { .w = window_redraw_center } },
{ { NONE('z'), NONE('b') }, window, { .w = window_redraw_bottom } },
{ { NONE('q') }, macro_record, { NULL } },
{ { NONE('@') }, macro_replay, { NULL } },
{ /* empty last element, array terminator */ },
};

Expand Down
3 changes: 3 additions & 0 deletions editor.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include <stdbool.h>
#include "window.h"
#include "register.h"
#include "macro.h"
#include "syntax.h"

typedef struct Editor Editor;
Expand Down Expand Up @@ -96,6 +97,8 @@ struct Editor {
EditorWin *win; /* currently active window */
Syntax *syntaxes; /* NULL terminated array of syntax definitions */
Register registers[REG_LAST]; /* register used for copy and paste */
Macro macros[26]; /* recorded macros */
Macro *recording, *last_recording;/* currently and least recently recorded macro */
Prompt *prompt; /* used to get user input */
char info[255]; /* a user message currently being displayed */
Regex *search_pattern; /* last used search pattern */
Expand Down
11 changes: 11 additions & 0 deletions macro.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#ifndef MACRO_H
#define MACRO_H

#include "buffer.h"

typedef Buffer Macro;
#define macro_free buffer_free
#define macro_reset buffer_truncate
#define macro_append buffer_append

#endif
30 changes: 5 additions & 25 deletions register.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,37 +2,17 @@
#include <string.h>

#include "register.h"
#include "buffer.h"
#include "text.h"
#include "util.h"

#define REG_SIZE 1024

static bool register_alloc(Register *reg, size_t size) {
if (size < REG_SIZE)
size = REG_SIZE;
if (reg->size < size) {
reg->data = realloc(reg->data, size);
if (!reg->data) {
reg->size = 0;
reg->len = 0;
return false;
}
reg->size = size;
}
return true;
}

void register_free(Register *reg) {
if (!reg)
return;
free(reg->data);
reg->data = NULL;
reg->len = 0;
reg->size = 0;
buffer_free((Buffer*)reg);
}

bool register_put(Register *reg, Text *txt, Filerange *range) {
size_t len = range->end - range->start;
if (!register_alloc(reg, len))
if (!buffer_alloc((Buffer*)reg, len))
return false;
reg->len = text_bytes_get(txt, range->start, len, reg->data);
return true;
Expand All @@ -41,7 +21,7 @@ bool register_put(Register *reg, Text *txt, Filerange *range) {
bool register_append(Register *reg, Text *txt, Filerange *range) {
size_t rem = reg->size - reg->len;
size_t len = range->end - range->start;
if (len > rem && !register_alloc(reg, reg->size + len - rem))
if (len > rem && !buffer_alloc((Buffer*)reg, reg->size + len - rem))
return false;
reg->len += text_bytes_get(txt, range->start, len, reg->data + reg->len);
return true;
Expand Down
3 changes: 2 additions & 1 deletion register.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@

#include <stddef.h>
#include <stdbool.h>
#include "text.h"
#include "buffer.h"

/* definition has to match Buffer */
typedef struct {
char *data; /* NULL if empty */
size_t len; /* current length of data */
Expand Down
98 changes: 68 additions & 30 deletions vis.c
Original file line number Diff line number Diff line change
Expand Up @@ -375,6 +375,8 @@ static TextObject *moves_linewise[] = {
};

/** functions to be called from keybindings */
static void macro_record(const Arg *arg);
static void macro_replay(const Arg *arg);
/* temporarily suspend the editor and return to the shell, type 'fg' to get back */
static void suspend(const Arg *arg);
/* switch to mode indicated by arg->i */
Expand Down Expand Up @@ -511,6 +513,7 @@ static void switchmode_to(Mode *new_mode);
#include "config.h"

static Key getkey(void);
static void keypress(Key *key);
static void action_do(Action *a);
static bool exec_command(char type, char *cmdline);

Expand Down Expand Up @@ -778,6 +781,40 @@ static size_t window_lines_bottom(const Arg *arg) {

/** key bindings functions of type: void (*func)(const Arg*) */

static Macro *key2macro(const Arg *arg) {
if (arg->i)
return &vis->macros[arg->i];
Key key = getkey();
if (key.str[0] >= 'a' && key.str[0] <= 'z')
return &vis->macros[key.str[0] - 'a'];
if (key.str[0] == '@')
return vis->last_recording;
return NULL;
}

static void macro_record(const Arg *arg) {
if (vis->recording) {
/* hack to remove last recorded key, otherwise upon replay
* we would start another recording */
vis->recording->len -= sizeof(Key);
vis->last_recording = vis->recording;
vis->recording = NULL;
} else {
vis->recording = key2macro(arg);
if (vis->recording)
macro_reset(vis->recording);
}
editor_draw(vis);
}

static void macro_replay(const Arg *arg) {
Macro *macro = key2macro(arg);
if (!macro || macro == vis->recording)
return;
for (size_t i = 0; i < macro->len; i += sizeof(Key))
keypress((Key*)(macro->data + i));
}

static void suspend(const Arg *arg) {
endwin();
raise(SIGSTOP);
Expand Down Expand Up @@ -1691,6 +1728,36 @@ static KeyBinding *keybinding(Mode *mode, KeyCombo keys) {
return NULL;
}

static void keypress(Key *key) {
static KeyCombo keys;
static int keylen;

if (config->keypress && !config->keypress(key))
return;

keys[keylen++] = *key;
KeyBinding *action = keybinding(mode, keys);

if (action) {
int combolen = 0;
while (combolen < MAX_KEYS && keyvalid(&action->key[combolen]))
combolen++;
if (keylen < combolen)
return; /* combo not yet complete */
/* need to reset state before calling action->func in case
* it will call us (=keypress) again as e.g. macro_replay */
keylen = 0;
memset(keys, 0, sizeof(keys));
if (action->func)
action->func(&action->arg);
} else if (keylen == 1 && key->code == 0 && mode->input) {
mode->input(key->str, strlen(key->str));
}

keylen = 0;
memset(keys, 0, sizeof(keys));
}

static Key getkey(void) {
Key key = { .str = "\0\0\0\0\0\0", .code = 0 };
int keycode = getch(), len = 0;
Expand All @@ -1716,8 +1783,6 @@ static Key getkey(void) {

static void mainloop() {
struct timespec idle = { .tv_nsec = 0 }, *timeout = NULL;
KeyCombo keys;
int keylen = 0;
sigset_t emptyset, blockset;
sigemptyset(&emptyset);
sigemptyset(&blockset);
Expand Down Expand Up @@ -1754,35 +1819,8 @@ static void mainloop() {
}

Key key = getkey();
if (config->keypress && !config->keypress(&key))
continue;
keypress(&key);

keys[keylen++] = key;
KeyBinding *action = keybinding(mode, keys);

if (action) {
int combolen = 0;
while (combolen < MAX_KEYS && keyvalid(&action->key[combolen]))
combolen++;
if (combolen == keylen) {
if (action->func)
action->func(&action->arg);
keylen = 0;
memset(keys, 0, sizeof(keys));
}
continue;
} else {
int oldkeylen = keylen;
keylen = 0;
memset(keys, 0, sizeof(keys));
if (oldkeylen > 1)
continue; /* cancel partial action */
}

if (key.code) /* ignore curses KEY_* */
continue;
if (mode->input)
mode->input(key.str, strlen(key.str));
if (mode->idle)
timeout = &idle;
}
Expand Down

0 comments on commit b8456fa

Please sign in to comment.