[openssh-commits] [openssh] 02/02: upstream: sftp: Be a bit more clever about completions

git+noreply at mindrot.org git+noreply at mindrot.org
Fri Sep 16 13:35:30 AEST 2022


This is an automated email from the git hooks/post-receive script.

djm pushed a commit to branch master
in repository openssh.

commit ac1ec9545947d9f9657259f55d04cb49d3a94c8a
Author: djm at openbsd.org <djm at openbsd.org>
Date:   Fri Sep 16 03:33:14 2022 +0000

    upstream: sftp: Be a bit more clever about completions
    
    There are commands (e.g. "get" or "put") that accept two
    arguments, a local path and a remote path. However, the way
    current completion is written doesn't take this distinction into
    account and always completes remote or local paths.
    
    By expanding CMD struct and "cmds" array this distinction can be
    reflected and with small adjustment to completer code the correct
    path can be completed.
    
    By Michal Privoznik, ok dtucker@
    
    OpenBSD-Commit-ID: 1396d921c4eb1befd531f5c4a8ab47e7a74b610b
---
 sftp.c | 115 +++++++++++++++++++++++++++++++++++++++--------------------------
 1 file changed, 69 insertions(+), 46 deletions(-)

diff --git a/sftp.c b/sftp.c
index 11ebe209..24568aad 100644
--- a/sftp.c
+++ b/sftp.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: sftp.c,v 1.219 2022/09/16 03:13:34 djm Exp $ */
+/* $OpenBSD: sftp.c,v 1.220 2022/09/16 03:33:14 djm Exp $ */
 /*
  * Copyright (c) 2001-2004 Damien Miller <djm at openbsd.org>
  *
@@ -166,7 +166,8 @@ enum sftp_command {
 struct CMD {
 	const char *c;
 	const int n;
-	const int t;
+	const int t;	/* Completion type for the first argument */
+	const int t2;	/* completion type for the optional second argument */
 };
 
 /* Type of completion */
@@ -175,44 +176,44 @@ struct CMD {
 #define LOCAL	2
 
 static const struct CMD cmds[] = {
-	{ "bye",	I_QUIT,		NOARGS	},
-	{ "cd",		I_CHDIR,	REMOTE	},
-	{ "chdir",	I_CHDIR,	REMOTE	},
-	{ "chgrp",	I_CHGRP,	REMOTE	},
-	{ "chmod",	I_CHMOD,	REMOTE	},
-	{ "chown",	I_CHOWN,	REMOTE	},
-	{ "copy",	I_COPY,		REMOTE	},
-	{ "cp",		I_COPY,		REMOTE	},
-	{ "df",		I_DF,		REMOTE	},
-	{ "dir",	I_LS,		REMOTE	},
-	{ "exit",	I_QUIT,		NOARGS	},
-	{ "get",	I_GET,		REMOTE	},
-	{ "help",	I_HELP,		NOARGS	},
-	{ "lcd",	I_LCHDIR,	LOCAL	},
-	{ "lchdir",	I_LCHDIR,	LOCAL	},
-	{ "lls",	I_LLS,		LOCAL	},
-	{ "lmkdir",	I_LMKDIR,	LOCAL	},
-	{ "ln",		I_LINK,		REMOTE	},
-	{ "lpwd",	I_LPWD,		LOCAL	},
-	{ "ls",		I_LS,		REMOTE	},
-	{ "lumask",	I_LUMASK,	NOARGS	},
-	{ "mkdir",	I_MKDIR,	REMOTE	},
-	{ "mget",	I_GET,		REMOTE	},
-	{ "mput",	I_PUT,		LOCAL	},
-	{ "progress",	I_PROGRESS,	NOARGS	},
-	{ "put",	I_PUT,		LOCAL	},
-	{ "pwd",	I_PWD,		REMOTE	},
-	{ "quit",	I_QUIT,		NOARGS	},
-	{ "reget",	I_REGET,	REMOTE	},
-	{ "rename",	I_RENAME,	REMOTE	},
-	{ "reput",	I_REPUT,	LOCAL	},
-	{ "rm",		I_RM,		REMOTE	},
-	{ "rmdir",	I_RMDIR,	REMOTE	},
-	{ "symlink",	I_SYMLINK,	REMOTE	},
-	{ "version",	I_VERSION,	NOARGS	},
-	{ "!",		I_SHELL,	NOARGS	},
-	{ "?",		I_HELP,		NOARGS	},
-	{ NULL,		-1,		-1	}
+	{ "bye",	I_QUIT,		NOARGS, 	NOARGS	},
+	{ "cd",		I_CHDIR,	REMOTE, 	NOARGS	},
+	{ "chdir",	I_CHDIR,	REMOTE, 	NOARGS	},
+	{ "chgrp",	I_CHGRP,	REMOTE, 	NOARGS	},
+	{ "chmod",	I_CHMOD,	REMOTE, 	NOARGS	},
+	{ "chown",	I_CHOWN,	REMOTE, 	NOARGS	},
+	{ "copy",	I_COPY,		REMOTE, 	LOCAL	},
+	{ "cp",		I_COPY,		REMOTE, 	LOCAL	},
+	{ "df",		I_DF,		REMOTE, 	NOARGS	},
+	{ "dir",	I_LS,		REMOTE, 	NOARGS	},
+	{ "exit",	I_QUIT,		NOARGS, 	NOARGS	},
+	{ "get",	I_GET,		REMOTE, 	LOCAL	},
+	{ "help",	I_HELP,		NOARGS, 	NOARGS	},
+	{ "lcd",	I_LCHDIR,	LOCAL,		NOARGS	},
+	{ "lchdir",	I_LCHDIR,	LOCAL,		NOARGS	},
+	{ "lls",	I_LLS,		LOCAL,		NOARGS	},
+	{ "lmkdir",	I_LMKDIR,	LOCAL,		NOARGS	},
+	{ "ln",		I_LINK,		REMOTE, 	REMOTE	},
+	{ "lpwd",	I_LPWD,		LOCAL,		NOARGS	},
+	{ "ls",		I_LS,		REMOTE,		NOARGS	},
+	{ "lumask",	I_LUMASK,	NOARGS,		NOARGS	},
+	{ "mkdir",	I_MKDIR,	REMOTE,		NOARGS	},
+	{ "mget",	I_GET,		REMOTE,		LOCAL	},
+	{ "mput",	I_PUT,		LOCAL,		REMOTE	},
+	{ "progress",	I_PROGRESS,	NOARGS,		NOARGS	},
+	{ "put",	I_PUT,		LOCAL,		REMOTE	},
+	{ "pwd",	I_PWD,		REMOTE, 	NOARGS	},
+	{ "quit",	I_QUIT,		NOARGS, 	NOARGS	},
+	{ "reget",	I_REGET,	REMOTE, 	LOCAL	},
+	{ "rename",	I_RENAME,	REMOTE, 	REMOTE	},
+	{ "reput",	I_REPUT,	LOCAL,		REMOTE	},
+	{ "rm",		I_RM,		REMOTE,		NOARGS	},
+	{ "rmdir",	I_RMDIR,	REMOTE,		NOARGS	},
+	{ "symlink",	I_SYMLINK,	REMOTE,		REMOTE	},
+	{ "version",	I_VERSION,	NOARGS, 	NOARGS	},
+	{ "!",		I_SHELL,	NOARGS, 	NOARGS	},
+	{ "?",		I_HELP,		NOARGS, 	NOARGS	},
+	{ NULL,		-1,		-1,		-1	}
 };
 
 /* ARGSUSED */
@@ -1945,19 +1946,25 @@ complete_cmd_parse(EditLine *el, char *cmd, int lastarg, char quote,
 }
 
 /*
- * Determine whether a particular sftp command's arguments (if any)
- * represent local or remote files.
+ * Determine whether a particular sftp command's arguments (if any) represent
+ * local or remote files. The "cmdarg" argument specifies the actual argument
+ * and accepts values 1 or 2.
  */
 static int
-complete_is_remote(char *cmd) {
+complete_is_remote(char *cmd, int cmdarg) {
 	int i;
 
 	if (cmd == NULL)
 		return -1;
 
 	for (i = 0; cmds[i].c; i++) {
-		if (!strncasecmp(cmd, cmds[i].c, strlen(cmds[i].c)))
-			return cmds[i].t;
+		if (!strncasecmp(cmd, cmds[i].c, strlen(cmds[i].c))) {
+			if (cmdarg == 1)
+				return cmds[i].t;
+			else if (cmdarg == 2)
+				return cmds[i].t2;
+			break;
+		}
 	}
 
 	return -1;
@@ -2137,12 +2144,28 @@ complete(EditLine *el, int ch)
 			ret = CC_REDISPLAY;
 	} else if (carg >= 1) {
 		/* Handle file parsing */
-		int remote = complete_is_remote(argv[0]);
+		int remote = 0;
+		int i = 0, cmdarg = 0;
 		char *filematch = NULL;
 
 		if (carg > 1 && line[cursor-1] != ' ')
 			filematch = argv[carg - 1];
 
+		for (i = 1; i < carg; i++) {
+			/* Skip flags */
+			if (argv[i][0] != '-')
+				cmdarg++;
+		}
+
+		/*
+		 * If previous argument is complete, then offer completion
+		 * on the next one.
+		 */
+		if (line[cursor - 1] == ' ')
+			cmdarg++;
+
+		remote = complete_is_remote(argv[0], cmdarg);
+
 		if ((remote == REMOTE || remote == LOCAL) &&
 		    complete_match(el, complete_ctx->conn,
 		    *complete_ctx->remote_pathp, filematch,

-- 
To stop receiving notification emails like this one, please contact
djm at mindrot.org.


More information about the openssh-commits mailing list