Download raw body.
bin/ksh: add bash-like expand-tilde option
tech@,
default ksh completion already matches bash with expand-tilde enabled:
typing ~/sr and pressing TAB expands and completes the word to
/home/user/src.
Here a new option expand-tilde which using the bash name, but keep
current ksh behaviour by enabling it by default.
Disabling the option preserves the original ~ prefix, so the same input
completes to ~/src.
Ok?
Index: bin/ksh/edit.c
===================================================================
RCS file: /home/cvs/src/bin/ksh/edit.c,v
diff -u -p -r1.71 edit.c
--- bin/ksh/edit.c 23 Apr 2024 13:34:50 -0000 1.71
+++ bin/ksh/edit.c 18 Apr 2026 22:50:42 -0000
@@ -30,6 +30,7 @@ static void check_sigwinch(void);
static int x_file_glob(int, const char *, int, char ***);
static int x_command_glob(int, const char *, int, char ***);
static int x_locate_word(const char *, int, int, int *, int *);
+static void x_preserve_tilde(char **, int, const char *, const char *);
/* Called from main */
@@ -417,10 +418,24 @@ x_file_glob(int flags, const char *str,
int nwords;
XPtrV w;
struct source *s, *sold;
+ char *tilde = NULL;
+ char *tilde_expanded = NULL;
+ int preserve_tilde = 0;
+ int tlen = 0;
if (slen < 0)
return 0;
+ if (!Flag(FEXPANDTILDE) && slen > 0 && str[0] == '~') {
+ for (tlen = 1; tlen < slen; tlen++)
+ if (str[tlen] == '/')
+ break;
+ tilde = str_nsave(str, tlen, ATEMP);
+ tilde_expanded = evalstr(tilde, DOTILDE);
+ if (tilde_expanded != null && tilde_expanded[0] != '~')
+ preserve_tilde = 1;
+ }
+
toglob = add_glob(str, slen);
/*
@@ -433,7 +448,8 @@ x_file_glob(int flags, const char *str,
if (yylex(ONEWORD|UNESCAPE) != LWORD) {
source = sold;
internal_warningf("%s: substitute error", __func__);
- return 0;
+ nwords = 0;
+ goto done;
}
source = sold;
XPinit(w, 32);
@@ -461,13 +477,52 @@ x_file_glob(int flags, const char *str,
afree(toglob, ATEMP);
if (nwords) {
+ if (preserve_tilde)
+ x_preserve_tilde(words, nwords, tilde, tilde_expanded);
*wordsp = words;
} else if (words) {
x_free_words(nwords, words);
*wordsp = NULL;
}
+done:
+ if (tilde)
+ afree(tilde, ATEMP);
+ if (tilde_expanded && tilde_expanded != null)
+ afree(tilde_expanded, ATEMP);
return nwords;
+}
+
+static void
+x_preserve_tilde(char **words, int nwords, const char *tilde,
+ const char *tilde_expanded)
+{
+ size_t tilde_len, exp_len;
+ int i;
+
+ tilde_len = strlen(tilde);
+ exp_len = strlen(tilde_expanded);
+ if (exp_len == 0)
+ return;
+
+ for (i = 0; i < nwords; i++) {
+ char *w = words[i];
+ size_t rest_len;
+ char *nw;
+
+ if (strncmp(w, tilde_expanded, exp_len) != 0)
+ continue;
+ if (w[exp_len] != '\0' && w[exp_len] != '/')
+ continue;
+
+ rest_len = strlen(w + exp_len);
+ nw = areallocarray(NULL, tilde_len + rest_len + 1,
+ sizeof(char), ATEMP);
+ memcpy(nw, tilde, tilde_len);
+ memcpy(nw + tilde_len, w + exp_len, rest_len + 1);
+ afree(w, ATEMP);
+ words[i] = nw;
+ }
}
/* Data structure used in x_command_glob() */
Index: bin/ksh/ksh.1
===================================================================
RCS file: /home/cvs/src/bin/ksh/ksh.1,v
diff -u -p -r1.223 ksh.1
--- bin/ksh/ksh.1 31 Dec 2025 22:12:25 -0000 1.223
+++ bin/ksh/ksh.1 18 Apr 2026 22:50:42 -0000
@@ -3630,6 +3630,9 @@ is read 13 times in a row.
The shell is an interactive shell.
This option can only be used when the shell is invoked.
See above for a description of what this means.
+.It Ic expand-tilde
+Expand leading tilde expressions in file name completion results.
+Enabled by default.
.It Ic login
The shell is a login shell.
This option can only be used when the shell is invoked.
Index: bin/ksh/main.c
===================================================================
RCS file: /home/cvs/src/bin/ksh/main.c,v
diff -u -p -r1.100 main.c
--- bin/ksh/main.c 23 Jul 2023 23:42:03 -0000 1.100
+++ bin/ksh/main.c 18 Apr 2026 22:50:42 -0000
@@ -261,11 +261,12 @@ main(int argc, char *argv[])
}
/* Set edit mode to emacs by default, may be overridden
- * by the environment or the user. Also, we want tab completion
- * on in vi by default. */
+ * by the environment or the user. Also, we want expand-tilde and
+ * tab completion on in vi by default. */
#if defined(EMACS)
change_flag(FEMACS, OF_SPECIAL, 1);
#endif /* EMACS */
+ Flag(FEXPANDTILDE) = 1;
#if defined(VI)
Flag(FVITABCOMPLETE) = 1;
#endif /* VI */
Index: bin/ksh/misc.c
===================================================================
RCS file: /home/cvs/src/bin/ksh/misc.c,v
diff -u -p -r1.78 misc.c
--- bin/ksh/misc.c 24 Dec 2021 22:08:37 -0000 1.78
+++ bin/ksh/misc.c 18 Apr 2026 22:50:42 -0000
@@ -130,6 +130,7 @@ const struct option sh_options[] = {
{ "emacs", 0, OF_ANY },
#endif
{ "errexit", 'e', OF_ANY },
+ { "expand-tilde", 0, OF_ANY }, /* non-standard */
#ifdef EMACS
{ "gmacs", 0, OF_ANY },
#endif
Index: bin/ksh/sh.h
===================================================================
RCS file: /home/cvs/src/bin/ksh/sh.h,v
diff -u -p -r1.78 sh.h
--- bin/ksh/sh.h 5 Mar 2026 05:38:58 -0000 1.78
+++ bin/ksh/sh.h 18 Apr 2026 22:50:42 -0000
@@ -141,6 +141,7 @@ enum sh_flag {
FEMACS, /* emacs command editing */
#endif
FERREXIT, /* -e: quit on error */
+ FEXPANDTILDE, /* expand ~ in completion */
#ifdef EMACS
FGMACS, /* gmacs command editing */
#endif
--
wbr, Kirill
bin/ksh: add bash-like expand-tilde option