From: Stefan Sperling Subject: Re: tog(1) log by default++ To: Martin Pieuchot , gameoftrees@openbsd.org Date: Thu, 20 Feb 2020 17:24:12 +0100 On Fri, Feb 14, 2020 at 05:15:32PM +0100, Stefan Sperling wrote: > On Fri, Feb 14, 2020 at 04:59:32PM +0100, Stefan Sperling wrote: > > On Fri, Feb 14, 2020 at 04:39:48PM +0100, Martin Pieuchot wrote: > > > If the second argument on the command line doesn't match a command name > > > let the tool to assume it's a path. In other words the following: > > > > > > $ tog kern/kern_sync.c > > > > > > Becomes an alias for: > > > > > > $ tog log kern/kern_sync.c > > > > > > This is similar to what tig(1) does and it helps me being lazy :o) > > > > This behaviour already existed once and was reverted in > > commit 3642c4c6513e3536dc77e8f2b7a2402d1aa916a7 > > > > I don't recall why I reverted it. I suspect it was to keep the > > 'command subcommand' syntax consistent across both got(1) and tog(1). > > And I didn't like the old implementation I had, but yours looks cleaner. > > One problem is that 'tog foo' for non-existent foo no longer shows usage > information. It says "tog: no git repository found" or "tog: no such entry > found in tree" depending on the contents of the current working directory, > without any further hints. > > Perhaps a custom error message could be added which says something like > "tog: 'foo' is neither a known command nor a path" when it fails, followed > by usage info? Here is a diff that shows how I would implement this if we really want it. A reason against removing make_argv() is that getopt inside the command's main function will otherwise process the whole original argv. This can lead to rather confusing usage errors when argv[0] is not a command name. So I've decided to keep it. Does this diff work for you? (please ensure your tree is up-to-date before applying this) diff 6962eb72119c221eca83da6b7b3bd76f730d6898 /home/stsp/src/got blob - dc2613f1948e568e578c8d9c6b54e1296b91ca7d file + tog/tog.1 --- tog/tog.1 +++ tog/tog.1 @@ -21,9 +21,13 @@ .Nd Git repository browser .Sh SYNOPSIS .Nm -.Ar command +.Op Ar command .Op Fl h .Op Ar arg ... +.Pp +.Nm +.Ar path +.El .Sh DESCRIPTION .Nm is an interactive read-only browser for Git repositories. @@ -37,6 +41,8 @@ supports several types of views which display reposito Displays commits in the repository's history. This view is displayed initially if no .Ar command +is specified, or if just a +.Ar path is specified. .It Diff view Displays changes made in a particular commit. blob - 9e8009077b052e09ca9a672a6324e575c6116de3 file + tog/tog.c --- tog/tog.c +++ tog/tog.c @@ -5308,10 +5308,12 @@ list_commands(void) __dead static void usage(int hflag) { - fprintf(stderr, "usage: %s [-h] [-V | --version] [command] [arg ...]\n", - getprogname()); - if (hflag) + fprintf(stderr, "usage: %s [-h] [-V | --version] [command] " + "[arg ...]\n", getprogname()); + if (hflag) { list_commands(); + fprintf(stderr, "alternative usage: %s path\n", getprogname()); + } exit(1); } @@ -5347,6 +5349,7 @@ main(int argc, char *argv[]) { "version", no_argument, NULL, 'V' }, { NULL, 0, NULL, 0} }; + int is_implicit_log_cmd = 0; setlocale(LC_CTYPE, ""); @@ -5384,7 +5387,7 @@ main(int argc, char *argv[]) } else { int i; - /* Did the user specific a command? */ + /* Did the user specify a command? */ for (i = 0; i < nitems(tog_commands); i++) { if (strncmp(tog_commands[i].name, argv[0], strlen(argv[0])) == 0) { @@ -5392,23 +5395,40 @@ main(int argc, char *argv[]) break; } } + } - if (cmd == NULL) { - fprintf(stderr, "%s: unknown command '%s'\n", - getprogname(), argv[0]); - list_commands(); - return 1; - } + if (cmd == NULL) { + if (argc != 1) + usage(0); + /* No command specified; try log with a path */ + cmd = &tog_commands[0]; + cmd_argv = make_argv(cmd->name, argv[0]); + argc = 2; + is_implicit_log_cmd = 1; + error = cmd->cmd_main(argc, cmd_argv); + } else { + if (hflag) + cmd->cmd_usage(); + else + error = cmd->cmd_main(argc, cmd_argv ? cmd_argv : argv); } - if (hflag) - cmd->cmd_usage(); - else - error = cmd->cmd_main(argc, cmd_argv ? cmd_argv : argv); - endwin(); - free(cmd_argv); - if (error && error->code != GOT_ERR_CANCELLED) - fprintf(stderr, "%s: %s\n", getprogname(), error->msg); + if (cmd_argv) { + int i; + for (i = 0; i < argc; i++) + free(cmd_argv[i]); + free(cmd_argv); + } + + if (error && error->code != GOT_ERR_CANCELLED) { + if (is_implicit_log_cmd && + error->code == GOT_ERR_NO_TREE_ENTRY) { + fprintf(stderr, "%s: '%s' is no known command or path\n", + getprogname(), argv[0]); + usage(1); + } else + fprintf(stderr, "%s: %s\n", getprogname(), error->msg); + } return 0; }