"GOT", but the "O" is a cute, smiling pufferfish. Index | Thread | Search

From:
Stefan Sperling <stsp@stsp.name>
Subject:
Re: tog(1) log by default++
To:
Martin Pieuchot <mpi@openbsd.org>, gameoftrees@openbsd.org
Date:
Thu, 20 Feb 2020 17:24:12 +0100

Download raw body.

Thread
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;
 }