Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP user-programmable registers #708

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -312,6 +312,7 @@ TIG_OBJS = \
src/grep.o \
src/ui.o \
src/apps.o \
src/registers.o \
$(GRAPH_OBJS) \
$(COMPAT_OBJS)

Expand Down
5 changes: 4 additions & 1 deletion doc/manual.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,8 @@ following variables.
|%(repo:is-inside-work-tree)
|Whether Tig is running inside a work tree,
either `true` or `false`.
|%(register:x) |A user-defined register value, where `x` is an ASCII
character.
|=============================================================================

Example user-defined commands:
Expand Down Expand Up @@ -489,7 +491,8 @@ Prompt
|:script <file> |Execute commands from `<file>`.
|:exec <flags><args...> |Execute command using `<args>` with external
user-defined command option flags defined in `<flags>`.
|:echo <args...> |Display text in the status bar.
|:echo <args...> |Display text in the status bar.
|:set-register <char> <args...> |Load a value into the register named `<char>`.
|=============================================================================

[[external-commands]]
Expand Down
4 changes: 4 additions & 0 deletions doc/tigrc.5.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -665,6 +665,8 @@ the command that should be executed.
|< |Exit Tig after executing the command.
|> |Re-open Tig instantly in the last displayed view after
executing the command.
|=(x) |Run the command synchronously, and store the first
line of output in the register named `x`.
|=============================================================================

Unless otherwise specified, commands are run in the foreground with their
Expand Down Expand Up @@ -717,6 +719,8 @@ following variable names, which are substituted before commands are run:
|%(repo:is-inside-work-tree)
|Whether Tig is running inside a work tree,
either `true` or `false`.
|%(register:x) |A user-defined register value, where `x` is an ASCII
character.
|=============================================================================

Examples:
Expand Down
4 changes: 4 additions & 0 deletions include/tig/argv.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#define TIG_ARGV_H

#include "tig/tig.h"
#include "tig/registers.h"

/*
* Argument array helpers.
Expand All @@ -34,6 +35,8 @@ size_t argv_size(const char **argv);
bool argv_append(const char ***argv, const char *arg);
bool argv_appendn(const char ***argv, const char *arg, size_t arglen);
bool argv_append_array(const char ***dst_argv, const char *src_argv[]);
bool argv_prepend(const char ***argv, const char *arg);
bool argv_prependn(const char ***argv, const char *arg, size_t arglen);
bool argv_copy(const char ***dst, const char *src[]);
bool argv_contains(const char **argv, const char *arg);

Expand All @@ -60,6 +63,7 @@ typedef unsigned long argv_number;
struct argv_env {
ARGV_ENV_INFO(ARGV_ENV_FIELDS)
unsigned long goto_lineno;
char *registers[SIZEOF_REGISTERS];
char search[SIZEOF_STR];
char none[1];
};
Expand Down
2 changes: 1 addition & 1 deletion include/tig/display.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ bool save_view(struct view *view, const char *path);
bool vertical_split_is_enabled(enum vertical_split vsplit, int height, int width);
int apply_vertical_split(int base_width);

bool open_external_viewer(const char *argv[], const char *dir, bool silent, bool confirm, bool echo, bool quick, bool refresh, const char *notice);
bool open_external_viewer(const char *argv[], const char *dir, bool silent, bool confirm, bool echo, bool quick, char register_key, bool refresh, const char *notice);
void open_editor(const char *file, unsigned int lineno);
void enable_mouse(bool enable);

Expand Down
1 change: 1 addition & 0 deletions include/tig/keys.h
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ struct run_request_flags {
bool internal;
bool echo;
bool quick;
char register_key;
};

struct run_request {
Expand Down
159 changes: 159 additions & 0 deletions include/tig/registers.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
/* Copyright (c) 2006-2017 Jonas Fonseca <[email protected]>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/

#ifndef TIG_REGISTERS_H
#define TIG_REGISTERS_H

#include "tig/types.h"

/* Index 0 of the register array, corresponding to character key ASCII
* space, is kept empty and reserved for internal use as "no register".
*/
#define REGISTER_KEY_MIN '!' /* corresponding to index 1 */
#define REGISTER_KEY_MAX '~' /* corresponding to index 94 */
#define REGISTER_KEY_OFFSET 0x20
#define SIZEOF_REGISTERS 1 + REGISTER_KEY_MAX - REGISTER_KEY_OFFSET

#define REGISTER_FLAG_OPEN_STR "=("
#define REGISTER_FLAG_CLOSE_STR ")"
#define REGISTER_ESC_CHAR '\\'

#define is_register_esc_char(ch) \
((ch) == REGISTER_ESC_CHAR)

#define is_register_meta_char(ch) \
(is_register_esc_char(ch) \
|| ((ch) == REGISTER_FLAG_OPEN_STR[1]) \
|| ((ch) == REGISTER_FLAG_CLOSE_STR[0]) \
|| ((ch) == '"') \
|| ((ch) == '\''))

#define at_register_flag_open(p) \
(((p)[0] == REGISTER_FLAG_OPEN_STR[0]) && ((p)[1] == REGISTER_FLAG_OPEN_STR[1]))

#define at_register_flag_close(p) \
((p)[0] == REGISTER_FLAG_CLOSE_STR[0])

#define at_register_escd_pair(p) \
(is_register_esc_char((p)[0]) && is_register_meta_char((p)[1]))

#define register_key_to_index(key) \
((((key) >= REGISTER_KEY_MIN) && ((key) <= REGISTER_KEY_MAX)) ? (unsigned int) (key) - REGISTER_KEY_OFFSET : 0)

bool register_set(const char key, const char *value);
const char *register_get(const char key);

/* metacharacters occur twice, once as an escaped sequence */
#define REGISTER_INFO(_) \
_("\\\\", '\\') \
_("\\(", '(') \
_("\\)", ')') \
_("\\\"", '"') \
_("\\'", '\'') \
_("!", '!') \
_("\"", '"') \
_("#", '#') \
_("$", '$') \
_("%", '%') \
_("&", '&') \
_("'", '\'') \
_("(", '(') \
_(")", ')') \
_("*", '*') \
_("+", '+') \
_(",", ',') \
_("-", '-') \
_(".", '.') \
_("/", '/') \
_("0", '0') \
_("1", '1') \
_("2", '2') \
_("3", '3') \
_("4", '4') \
_("5", '5') \
_("6", '6') \
_("7", '7') \
_("8", '8') \
_("9", '9') \
_(":", ':') \
_(";", ';') \
_("<", '<') \
_("=", '=') \
_(">", '>') \
_("?", '?') \
_("@", '@') \
_("A", 'A') \
_("B", 'B') \
_("C", 'C') \
_("D", 'D') \
_("E", 'E') \
_("F", 'F') \
_("G", 'G') \
_("H", 'H') \
_("I", 'I') \
_("J", 'J') \
_("K", 'K') \
_("L", 'L') \
_("M", 'M') \
_("N", 'N') \
_("O", 'O') \
_("P", 'P') \
_("Q", 'Q') \
_("R", 'R') \
_("S", 'S') \
_("T", 'T') \
_("U", 'U') \
_("V", 'V') \
_("W", 'W') \
_("X", 'X') \
_("Y", 'Y') \
_("Z", 'Z') \
_("[", '[') \
_("\\", '\\') \
_("]", ']') \
_("^", '^') \
_("_", '_') \
_("`", '`') \
_("a", 'a') \
_("b", 'b') \
_("c", 'c') \
_("d", 'd') \
_("e", 'e') \
_("f", 'f') \
_("g", 'g') \
_("h", 'h') \
_("i", 'i') \
_("j", 'j') \
_("k", 'k') \
_("l", 'l') \
_("m", 'm') \
_("n", 'n') \
_("o", 'o') \
_("p", 'p') \
_("q", 'q') \
_("r", 'r') \
_("s", 's') \
_("t", 't') \
_("u", 'u') \
_("v", 'v') \
_("w", 'w') \
_("x", 'x') \
_("y", 'y') \
_("z", 'z') \
_("{", '{') \
_("|", '|') \
_("}", '}') \
_("~", '~')

#endif
/* vim: set ts=8 sw=8 noexpandtab: */
42 changes: 41 additions & 1 deletion src/argv.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include "tig/repo.h"
#include "tig/options.h"
#include "tig/prompt.h"
#include "tig/registers.h"

static bool
concat_argv(const char *argv[], char *buf, size_t buflen, const char *sep, bool quoted)
Expand Down Expand Up @@ -239,13 +240,35 @@ argv_appendn(const char ***argv, const char *arg, size_t arglen)
return alloc != NULL;
}

bool
argv_prependn(const char ***argv, const char *arg, size_t arglen)
{
if (!argv_appendn(argv,arg,strlen(arg)))
return false;

size_t last_i = argv_size(*argv) - 1;

if (last_i > 0) {
const char *save = (*argv)[last_i];
memmove(*argv + 1, *argv, last_i * sizeof(*argv));
(*argv)[0] = save;
}

return true;
}

bool
argv_append(const char ***argv, const char *arg)
{
return argv_appendn(argv, arg, strlen(arg));
}

bool
argv_prepend(const char ***argv, const char *arg)
{
return argv_prependn(argv, arg, strlen(arg));
}

bool
argv_append_array(const char ***dst_argv, const char *src_argv[])
{
Expand Down Expand Up @@ -325,6 +348,13 @@ format_expand_arg(struct format_context *format, const char *name, const char *e
return string_format_from(format->buf, &format->bufpos, "%s", value);
}

for (i = 0; i < format->vars_size; i++) {
if (strncmp(name, vars[i].name, vars[i].namelen))
continue;

return vars[i].formatter(format, &vars[i]);
}

for (i = 0; i < format->vars_size; i++) {
if (string_enum_compare(name, vars[i].name, vars[i].namelen))
continue;
Expand All @@ -347,6 +377,12 @@ format_append_arg(struct format_context *format, const char ***dst_argv, const c
while (arg) {
const char *var = strstr(arg, "%(");
const char *closing = var ? strchr(var, ')') : NULL;

/* todo hardcoding is robust and compact but ugly */
if (var &&
(!strcmp(var, "%(register:\\))") || !strcmp(var, "%(register:))")))
closing++;

const char *next = closing ? closing + 1 : NULL;
const int len = var ? var - arg : strlen(arg);

Expand Down Expand Up @@ -386,7 +422,7 @@ argv_string_formatter(struct format_context *format, struct format_var *var)
argv_string *value_ref = var->value_ref;
const char *value = *value_ref;

if (!*value)
if (!value || !*value)
value = var->value_if_empty;

if (!*value)
Expand Down Expand Up @@ -439,6 +475,10 @@ argv_format(struct argv_env *argv_env, const char ***dst_argv, const char *src_a
#define FORMAT_REPO_VAR(type, name) \
{ "%(repo:" #name ")", STRING_SIZE("%(repo:" #name ")"), type ## _formatter, &repo.name, "" },
REPO_INFO(FORMAT_REPO_VAR)
#define FORMAT_REGISTER_VAR(namestr, keychar) \
{ "%(register:" namestr ")", STRING_SIZE("%(register:" namestr ")"), argv_string_formatter, \
argv_env->registers[ MIN(keychar,REGISTER_KEY_MAX) - REGISTER_KEY_OFFSET ], "" },
REGISTER_INFO(FORMAT_REGISTER_VAR)
};
struct format_context format = { vars, ARRAY_SIZE(vars), "", 0, file_filter };
int argc;
Expand Down
21 changes: 16 additions & 5 deletions src/display.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include "tig/draw.h"
#include "tig/display.h"
#include "tig/watch.h"
#include "tig/registers.h"

static void set_terminal_modes(void);

Expand Down Expand Up @@ -61,19 +62,29 @@ open_script(const char *path)
}

bool
open_external_viewer(const char *argv[], const char *dir, bool silent, bool confirm, bool echo, bool quick, bool do_refresh, const char *notice)
open_external_viewer(const char *argv[], const char *dir, bool silent, bool confirm, bool echo, bool quick, char register_key, bool do_refresh, const char *notice)
{
bool ok;

if (echo) {
if (echo || register_key) {
char buf[SIZEOF_STR] = "";

io_run_buf(argv, buf, sizeof(buf), dir, false);
if (*buf) {
report("%s", buf);
if (register_key)
register_set(register_key, buf);
if (echo)
report("%s", buf);
else
report_clear();
return true;
} else {
report("No output");
if (register_key)
register_set(register_key, "");
if (echo)
report("No output");
else
report_clear();
return false;
}
} else if (silent || is_script_executing()) {
Expand Down Expand Up @@ -148,7 +159,7 @@ open_editor(const char *file, unsigned int lineno)
if (lineno && opt_editor_line_number && string_format(lineno_cmd, "+%u", lineno))
editor_argv[argc++] = lineno_cmd;
editor_argv[argc] = file;
if (!open_external_viewer(editor_argv, repo.cdup, false, false, false, false, true, EDITOR_LINENO_MSG))
if (!open_external_viewer(editor_argv, repo.cdup, false, false, false, false, 0, true, EDITOR_LINENO_MSG))
opt_editor_line_number = false;
}

Expand Down
Loading