zsh-workers
 help / color / mirror / code / Atom feed
* PATCH: completion for parameter flags
@ 2011-06-03 20:54 Peter Stephenson
  2011-06-04 12:39 ` Mikael Magnusson
  0 siblings, 1 reply; 3+ messages in thread
From: Peter Stephenson @ 2011-06-03 20:54 UTC (permalink / raw)
  To: Zsh Hackers' List

It has not hitherto been possible to complete parameter flags because
"${(" is not treated as a suitable location for parameter completion,
so you drop through to ordinary argument-context completion.

It turns out it's quite easy to detect the unbalanaced open parenthesis;
indeed, the context check for parameters already does, carefully
remembers the fact, carefully does some more checking, and then
carefully remembers that all that extra checking was pointless.  I'm not
sure why it goes to those lengths, but experimentation suggests simply
noting that we're in a brace parameter and not bothering with the code to
deal with parameter names gives us enough for the _brace_parameter
function to pick up on.

So here is some brief C code and an expanded shell function for
parameter flag completion.

Index: Completion/Zsh/Context/_brace_parameter
===================================================================
RCS file: /cvsroot/zsh/zsh/Completion/Zsh/Context/_brace_parameter,v
retrieving revision 1.1
diff -p -u -r1.1 _brace_parameter
--- Completion/Zsh/Context/_brace_parameter	2 Apr 2001 11:22:04 -0000	1.1
+++ Completion/Zsh/Context/_brace_parameter	3 Jun 2011 20:44:51 -0000
@@ -1,3 +1,190 @@
 #compdef -brace-parameter-
 
+local char delim found_percent found_m exp
+local -a flags
+integer q_last n_q
+
+if [[ $PREFIX = '${('[^\)]# ]]; then
+  # Parameter flags.
+  compset -p 3
+
+  # Based on code in _globquals.
+  while [[ -n $PREFIX ]]; do
+    char=$PREFIX[1]
+    compset -p 1
+    if [[ $char = q ]]; then
+      (( q_last++, n_q++ ))
+      continue
+    else
+      (( q_last = 0 ))
+    fi
+    # Skip arguments to find what's left to complete
+    case $char in
+      (%)
+      found_percent=1
+      ;;
+
+      (m)
+      found_m=1
+      ;;
+
+      ([gIjsZ_])
+      # Single delimited argument.
+      if [[ -z $PREFIX ]]; then
+	_delimiters qualifer-$char
+	return
+      elif ! _globqual_delims; then
+	# still completing argument
+	case $char in
+	  (g)
+	  compset -P '*'
+	  flags=('o:octal escapes' 'c:expand ^X etc.' 'e:expand \M-t etc.')
+	  _describe -t format 'format option' flags -Q -S ''
+	  ;;
+
+	  (I)
+	  _message 'integer expression'
+	  ;;
+
+	  (js)
+	  _message "separator"
+	  ;;
+
+	  (Z)
+	  compset -P '*'
+	  flags=(
+	    'c:parse comments as strings (else as ordinary words)'
+	    'C:strip comments (else treat as ordinary words)'
+	    'n:treat newlines as whitespace'
+	  )
+	  _describe -t format 'format option' flags -Q -S ''
+	  ;;
+
+	  (_)
+	  _message "no useful values"
+	  ;;
+	esac
+	return
+      fi
+      ;;
+
+      ([lr])
+      # One compulsory argument, two optional.
+      if [[ -z $PREFIX ]]; then
+	_delimiters qualifer-$char
+	return
+      else
+	delim=$PREFIX[1]
+	if ! _globqual_delims; then
+	  # still completing argument
+	  _message "padding width"
+	  return
+	fi
+	# TBD if $PREFIX is empty can complete
+	# either repeat delimiter or a new qualifier.
+	# You might think it would just be easier
+	# for the user to type the delimiter at
+	# this stage, but users are astonishingly lazy.
+	if [[ $delim = $PREFIX[1] ]]; then
+	  # second argument
+	  if ! _globqual_delims; then
+	    _message "repeated padding"
+	    return
+	  fi
+	  if [[ $delim = $PREFIX[1] ]]; then
+	    if ! _globqual_delims; then
+	      _message "one-off padding"
+	      return
+	    fi
+	  fi
+	fi
+      fi
+      ;;
+    esac
+  done
+
+  if [[ -z $found_percent ]]; then
+    flags=("%:Expand prompt sequences")
+  else
+    flags=("%:Expand prompts respecting options")
+  fi
+  case $q_last in
+    (0)
+    if (( n_q == 0 )); then
+      flags+=("q:quote with backslashes")
+    fi
+    ;;
+
+    (1)
+    flags+=(
+      "q:quote with single quotes"
+      "-:quote minimally for readability"
+    )
+    ;;
+
+    (2)
+    flags+=("q:quote with double quotes")
+    ;;
+
+    (3)
+    flags+=("q:quote with \$'...'")
+    ;;
+  esac
+  if (( !n_q )); then
+    flags+=("Q:remove one level of quoting")
+  fi
+  if [[ -z $found_m ]]; then
+    flags+=("m:Count multibyte width in padding calculation")
+  else
+    flags+=("m:Count number of character code points in padding calculation")
+  fi
+  flags+=(
+    "#:Evaluate as numeric expression"
+    "@:Double-quoted splitting of scalars"
+    "A:Create array parameter"
+    "a:Sort in array index order (with O to reverse)"
+    "c:Count characters in an array (with \${(c)#...})"
+    "C:Capitalize words"
+    "D:Perform directory name abbreviation"
+    "e:Perform single-word shell expansions"
+    "f:Split the result on newlines"
+    "F:Join arrays with newlines"
+    "g:Process echo array sequences (needs options)"
+    "i:Sort case-insensitively"
+    "k:Subsitute keys of associative arrays"
+    "L:Lower case all letters"
+    "n:Sort decimal integers numerically"
+    "o:Sort in ascending order (lexically if no other sort option)"
+    "O:Sort in descending order (lexically if no other sort option)"
+    "P:Use parameter value as name of parameter for redirected lookup"
+    "t:Substitute type of parameter"
+    "u:Substitute first occurrence of each unique word"
+    "U:Upper case all letters"
+    "v:Substitute values of associative arrays (with (k))"
+    "V:Visibility enhancements for special characters"
+    "w:Count words in array or string (with \${(w)#...})"
+    "W:Count words including empty words (with \${(W)#...})"
+    "X:Report parsing errors and eXit substitution"
+    "z:Split words as if zsh command line"
+    "0:Split words on null bytes"
+    "p:Handle print escapes in parameter flag arguments"
+    "~:Treat strings in parameter flag arguments as patterns"
+    "j:Join arrays with specified string"
+    "l:Left-pad resulting words"
+    "r:Right-pad resulting words"
+    "s:Split words on specified string"
+    "Z:Split words as if zsh command line (with options)"
+    # "_:Extended flags, for future expansion"
+    "S:Search substrings in #, %, / expressions"
+    "I:Search <argument>th match in #, %, / expressions"
+    "B:Include index of beginning of match in #, %, / expressions"
+    "E:Include index of end of match in #, %, / expressions"
+    "M:Include matched portion in #, %, / expressions"
+    "N:Include length of match in #, %,  expressions"
+    "R:Include rest (unmatched portion) in #, %, / expressions"
+  )
+  _describe -t flags "parameter flag" flags -Q -S ''
+  return
+fi
+
 _parameters -e
Index: Src/Zle/compcore.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/Zle/compcore.c,v
retrieving revision 1.107
diff -p -u -r1.107 compcore.c
--- Src/Zle/compcore.c	14 May 2011 00:36:07 -0000	1.107
+++ Src/Zle/compcore.c	3 Jun 2011 20:44:51 -0000
@@ -1150,7 +1150,7 @@ check_param(char *s, int set, int test)
 	p[1] != Inpar && p[1] != Inbrack && p[1] != Snull) {
 	/* This is a parameter expression, not $(...), $[...], $'...'. */
 	char *b = p + 1, *e = b, *ie;
-	int n = 0, br = 1, nest = 0;
+	int br = 1, nest = 0;
 
 	if (*b == Inbrace) {
 	    char *tb = b;
@@ -1161,7 +1161,17 @@ check_param(char *s, int set, int test)
 
 	    /* Ignore the possible (...) flags. */
 	    b++, br++;
-	    n = skipparens(Inpar, Outpar, &b);
+	    if (skipparens(Inpar, Outpar, &b) > 0) {
+		/*
+		 * We are still within the globbing flags.  There's no
+		 * point trying to do anything clever here with
+		 * parameter names.  Instead, just report that we are in
+		 * a brace parameter but let the completion function
+		 * decide what to do about it.
+		 */
+		ispar = 2;
+		return NULL;
+	    }
 
 	    for (tb = p - 1; tb > s && *tb != Outbrace && *tb != Inbrace; tb--);
 	    if (tb > s && *tb == Inbrace && (tb[-1] == String || *tb == Qstring))
@@ -1204,7 +1214,7 @@ check_param(char *s, int set, int test)
 	}
 
 	/* Now make sure that the cursor is inside the name. */
-	if (offs <= e - s && offs >= b - s && n <= 0) {
+	if (offs <= e - s && offs >= b - s) {
 	    char sav;
 
 	    if (br) {


-- 
Peter Stephenson <p.w.stephenson@ntlworld.com>
Web page now at http://homepage.ntlworld.com/p.w.stephenson/


^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: PATCH: completion for parameter flags
  2011-06-03 20:54 PATCH: completion for parameter flags Peter Stephenson
@ 2011-06-04 12:39 ` Mikael Magnusson
  2011-06-04 21:22   ` Peter Stephenson
  0 siblings, 1 reply; 3+ messages in thread
From: Mikael Magnusson @ 2011-06-04 12:39 UTC (permalink / raw)
  To: Peter Stephenson; +Cc: Zsh Hackers' List

On 3 June 2011 22:54, Peter Stephenson <p.w.stephenson@ntlworld.com> wrote:
> It has not hitherto been possible to complete parameter flags because
> "${(" is not treated as a suitable location for parameter completion,
> so you drop through to ordinary argument-context completion.
>
> It turns out it's quite easy to detect the unbalanaced open parenthesis;
> indeed, the context check for parameters already does, carefully
> remembers the fact, carefully does some more checking, and then
> carefully remembers that all that extra checking was pointless.  I'm not
> sure why it goes to those lengths, but experimentation suggests simply
> noting that we're in a brace parameter and not bothering with the code to
> deal with parameter names gives us enough for the _brace_parameter
> function to pick up on.
>
> So here is some brief C code and an expanded shell function for
> parameter flag completion.

This looks nicer than the hack I posted, but "${(<tab> shows me glob
qualifiers. (Ie, with the leading quotemark). foo${(<tab> does nothing
at all. (---- no match for: `parameter' or `corrections')

-- 
Mikael Magnusson


^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: PATCH: completion for parameter flags
  2011-06-04 12:39 ` Mikael Magnusson
@ 2011-06-04 21:22   ` Peter Stephenson
  0 siblings, 0 replies; 3+ messages in thread
From: Peter Stephenson @ 2011-06-04 21:22 UTC (permalink / raw)
  To: Zsh Hackers' List

On Sat, 4 Jun 2011 14:39:52 +0200
Mikael Magnusson <mikachu@gmail.com> wrote:
> ${(<tab> shows me glob qualifiers.
> foo${(<tab> does nothing at all.

This exposed an existing bug, that "${(stuff) wasn't handled properly.
In a quoted string it needs to scan for untokenized parentheses.

Index: Completion/Zsh/Context/_brace_parameter
===================================================================
RCS file: /cvsroot/zsh/zsh/Completion/Zsh/Context/_brace_parameter,v
retrieving revision 1.2
diff -p -u -r1.2 _brace_parameter
--- Completion/Zsh/Context/_brace_parameter	3 Jun 2011 22:06:59 -0000	1.2
+++ Completion/Zsh/Context/_brace_parameter	4 Jun 2011 21:19:17 -0000
@@ -4,7 +4,7 @@ local char delim found_percent found_m e
 local -a flags
 integer q_last n_q
 
-if [[ $PREFIX = '${('[^\)]# ]]; then
+if [[ $PREFIX = *'${('[^\)]# ]]; then
   # Parameter flags.
   compset -p 3
 
Index: Src/Zle/compcore.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/Zle/compcore.c,v
retrieving revision 1.108
diff -p -u -r1.108 compcore.c
--- Src/Zle/compcore.c	3 Jun 2011 22:07:00 -0000	1.108
+++ Src/Zle/compcore.c	4 Jun 2011 21:19:17 -0000
@@ -1099,7 +1099,7 @@ mod_export char *
 check_param(char *s, int set, int test)
 {
     char *p;
-    int found = 0;
+    int found = 0, qstring = 0;
 
     zsfree(parpre);
     parpre = NULL;
@@ -1126,6 +1126,7 @@ check_param(char *s, int set, int test)
 		!(*p == String && p[1] == Snull) &&
 		!(*p == Qstring && p[1] == '\'')) {
 		found = 1;
+		qstring = (*p == Qstring);
 		break;
 	    }
 	}
@@ -1161,7 +1162,8 @@ check_param(char *s, int set, int test)
 
 	    /* Ignore the possible (...) flags. */
 	    b++, br++;
-	    if (skipparens(Inpar, Outpar, &b) > 0) {
+	    if ((qstring ? skipparens('(', ')', &b) :
+		 skipparens(Inpar, Outpar, &b)) > 0) {
 		/*
 		 * We are still within the parameter flags.  There's no
 		 * point trying to do anything clever here with

-- 
Peter Stephenson <p.w.stephenson@ntlworld.com>
Web page now at http://homepage.ntlworld.com/p.w.stephenson/


^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2011-06-04 21:23 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-06-03 20:54 PATCH: completion for parameter flags Peter Stephenson
2011-06-04 12:39 ` Mikael Magnusson
2011-06-04 21:22   ` Peter Stephenson

Code repositories for project(s) associated with this public inbox

	https://git.vuxu.org/mirror/zsh/

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).