X-Git-Url: https://git.distorted.org.uk/~mdw/tig/blobdiff_plain/328d27f731f4b47d216d5170fd880a3e783a631e..3e6341130ef0a886d126c6005e5ffcd6a36a8fd5:/tig.c?ds=sidebyside diff --git a/tig.c b/tig.c index c3bc1f4..b404f56 100644 --- a/tig.c +++ b/tig.c @@ -11,8 +11,8 @@ * GNU General Public License for more details. */ -#ifndef VERSION -#define VERSION "unknown-version" +#ifndef TIG_VERSION +#define TIG_VERSION "unknown-version" #endif #ifndef DEBUG @@ -40,6 +40,8 @@ #include +#include "config.h" + #if __GNUC__ >= 3 #define __NORETURN __attribute__((__noreturn__)) #else @@ -90,6 +92,10 @@ static size_t utf8_length(const char *string, size_t max_width, int *coloffset, #define SCALE_SPLIT_VIEW(height) ((height) * 2 / 3) +#ifndef GIT_CONFIG +#define "git config" +#endif + #define TIG_LS_REMOTE \ "git ls-remote $(git rev-parse --git-dir) 2>/dev/null" @@ -112,6 +118,7 @@ static size_t utf8_length(const char *string, size_t max_width, int *coloffset, #define TIG_HELP_CMD "" #define TIG_PAGER_CMD "" #define TIG_STATUS_CMD "" +#define TIG_STAGE_CMD "" /* Some ascii-shorthands fitted into the ncurses namespace. */ #define KEY_TAB '\t' @@ -299,6 +306,7 @@ sq_quote(char buf[SIZEOF_STR], size_t bufsize, const char *src) REQ_(VIEW_HELP, "Show help page"), \ REQ_(VIEW_PAGER, "Show pager view"), \ REQ_(VIEW_STATUS, "Show status view"), \ + REQ_(VIEW_STAGE, "Show stage view"), \ \ REQ_GROUP("View manipulation") \ REQ_(ENTER, "Enter current line and scroll"), \ @@ -390,7 +398,7 @@ get_request(const char *name) */ static const char usage[] = -"tig " VERSION " (" __DATE__ ")\n" +"tig " TIG_VERSION " (" __DATE__ ")\n" "\n" "Usage: tig [options]\n" " or: tig [options] [--] [git log options]\n" @@ -516,7 +524,7 @@ parse_options(int argc, char *argv[]) } if (check_option(opt, 'v', "version", OPT_NONE)) { - printf("tig version %s\n", VERSION); + printf("tig version %s\n", TIG_VERSION); return FALSE; } @@ -729,6 +737,7 @@ static struct keybinding default_keybindings[] = { { 'p', REQ_VIEW_PAGER }, { 'h', REQ_VIEW_HELP }, { 'S', REQ_VIEW_STATUS }, + { 'c', REQ_VIEW_STAGE }, /* View manipulation */ { 'q', REQ_VIEW_CLOSE }, @@ -784,7 +793,8 @@ static struct keybinding default_keybindings[] = { KEYMAP_(BLOB), \ KEYMAP_(PAGER), \ KEYMAP_(HELP), \ - KEYMAP_(STATUS) + KEYMAP_(STATUS), \ + KEYMAP_(STAGE) enum keymap { #define KEYMAP_(name) KEYMAP_##name @@ -1280,6 +1290,7 @@ static struct view_ops tree_ops; static struct view_ops blob_ops; static struct view_ops help_ops; static struct view_ops status_ops; +static struct view_ops stage_ops; #define VIEW_STR(name, cmd, env, ref, ops, map) \ { name, cmd, #env, ref, ops, map} @@ -1297,6 +1308,7 @@ static struct view views[] = { VIEW_(HELP, "help", &help_ops, ""), VIEW_(PAGER, "pager", &pager_ops, "stdin"), VIEW_(STATUS, "status", &status_ops, ""), + VIEW_(STAGE, "stage", &stage_ops, ""), }; #define VIEW(req) (&views[(req) - REQ_OFFSET - 1]) @@ -1818,7 +1830,10 @@ begin_update(struct view *view) /* When running random commands, initially show the * command in the title. However, it maybe later be * overwritten if a commit line is selected. */ - string_copy(view->ref, view->cmd); + if (view == VIEW(REQ_VIEW_PAGER)) + string_copy(view->ref, view->cmd); + else + view->ref[0] = 0; } else if (view == VIEW(REQ_VIEW_TREE)) { const char *format = view->cmd_env ? view->cmd_env : view->cmd_fmt; @@ -1923,7 +1938,7 @@ update_view(struct view *view) line[linelen - 1] = 0; if (opt_iconv != ICONV_NONE) { - char *inbuf = line; + ICONV_INBUF_TYPE inbuf = line; size_t inlen = linelen; char *outbuf = out_buffer; @@ -2197,6 +2212,15 @@ view_driver(struct view *view, enum request request) open_view(view, request, OPEN_DEFAULT); break; + case REQ_VIEW_STAGE: + if (!VIEW(REQ_VIEW_STAGE)->lines) { + report("No stage content, press %s to open the status view and choose file", + get_key(REQ_VIEW_STATUS)); + break; + } + open_view(view, request, OPEN_DEFAULT); + break; + case REQ_VIEW_MAIN: case REQ_VIEW_DIFF: case REQ_VIEW_LOG: @@ -2212,6 +2236,8 @@ view_driver(struct view *view, enum request request) if ((view == VIEW(REQ_VIEW_DIFF) && view->parent == VIEW(REQ_VIEW_MAIN)) || + (view == VIEW(REQ_VIEW_STAGE) && + view->parent == VIEW(REQ_VIEW_STATUS)) || (view == VIEW(REQ_VIEW_BLOB) && view->parent == VIEW(REQ_VIEW_TREE))) { int line; @@ -2281,7 +2307,7 @@ view_driver(struct view *view, enum request request) break; case REQ_SHOW_VERSION: - report("tig-%s (built %s)", VERSION, __DATE__); + report("tig-%s (built %s)", TIG_VERSION, __DATE__); return TRUE; case REQ_SCREEN_RESIZE: @@ -2625,6 +2651,50 @@ static struct view_ops help_ops = { * Tree backend */ +struct tree_stack_entry { + struct tree_stack_entry *prev; /* Entry below this in the stack */ + unsigned long lineno; /* Line number to restore */ + char *name; /* Position of name in opt_path */ +}; + +/* The top of the path stack. */ +static struct tree_stack_entry *tree_stack = NULL; +unsigned long tree_lineno = 0; + +static void +pop_tree_stack_entry(void) +{ + struct tree_stack_entry *entry = tree_stack; + + tree_lineno = entry->lineno; + entry->name[0] = 0; + tree_stack = entry->prev; + free(entry); +} + +static void +push_tree_stack_entry(char *name, unsigned long lineno) +{ + struct tree_stack_entry *entry = calloc(1, sizeof(*entry)); + size_t pathlen = strlen(opt_path); + + if (!entry) + return; + + entry->prev = tree_stack; + entry->name = opt_path + pathlen; + tree_stack = entry; + + if (!string_format_from(opt_path, &pathlen, "%s/", name)) { + pop_tree_stack_entry(); + return; + } + + /* Move the current line to the first tree entry. */ + tree_lineno = 1; + entry->lineno = lineno; +} + /* Parse output from git-ls-tree(1): * * 100644 blob fb0e31ea6cc679b7379631188190e975f5789c26 Makefile @@ -2721,9 +2791,10 @@ tree_read(struct view *view, char *text) if (!add_line_text(view, text, type)) return FALSE; - /* Move the current line to the first tree entry. */ - if (first_read) - view->lineno++; + if (tree_lineno > view->lineno) { + view->lineno = tree_lineno; + tree_lineno = 0; + } return TRUE; } @@ -2736,29 +2807,22 @@ tree_request(struct view *view, enum request request, struct line *line) if (request != REQ_ENTER) return request; + /* Cleanup the stack if the tree view is at a different tree. */ + while (!*opt_path && tree_stack) + pop_tree_stack_entry(); + switch (line->type) { case LINE_TREE_DIR: /* Depending on whether it is a subdir or parent (updir?) link * mangle the path buffer. */ if (line == &view->line[1] && *opt_path) { - size_t path_len = strlen(opt_path); - char *dirsep = opt_path + path_len - 1; - - while (dirsep > opt_path && dirsep[-1] != '/') - dirsep--; - - dirsep[0] = 0; + pop_tree_stack_entry(); } else { - size_t pathlen = strlen(opt_path); - size_t origlen = pathlen; char *data = line->data; char *basename = data + SIZEOF_TREE_ATTR; - if (!string_format_from(opt_path, &pathlen, "%s/", basename)) { - opt_path[origlen] = 0; - return TRUE; - } + push_tree_stack_entry(basename, view->lineno); } /* Trees and subtrees share the same ID, so they are not not @@ -2777,6 +2841,9 @@ tree_request(struct view *view, enum request request, struct line *line) } open_view(view, request, flags); + if (request == REQ_VIEW_TREE) { + view->lineno = tree_lineno; + } return REQ_NONE; } @@ -3117,9 +3184,9 @@ status_enter(struct view *view, struct line *line) die("w00t"); } - open_view(view, REQ_VIEW_DIFF, OPEN_RELOAD | OPEN_SPLIT); - if (view_is_displayed(VIEW(REQ_VIEW_DIFF))) { - string_format(VIEW(REQ_VIEW_DIFF)->ref, info, status->name); + open_view(view, REQ_VIEW_STAGE, OPEN_RELOAD | OPEN_SPLIT); + if (view_is_displayed(VIEW(REQ_VIEW_STAGE))) { + string_format(VIEW(REQ_VIEW_STAGE)->ref, info, status->name); } return REQ_NONE; @@ -3312,6 +3379,15 @@ static struct view_ops status_ops = { status_select, }; +static struct view_ops stage_ops = { + "line", + NULL, + pager_read, + pager_draw, + pager_request, + pager_grep, + pager_select, +}; /* * Revision graph @@ -4256,7 +4332,7 @@ read_repo_config_option(char *name, size_t namelen, char *value, size_t valuelen static int load_repo_config(void) { - return read_properties(popen("git repo-config --list", "r"), + return read_properties(popen(GIT_CONFIG " --list", "r"), "=", read_repo_config_option); }