From b3bd23dd0a5f287bbdfe3ed5b7423a8134417cc4 Mon Sep 17 00:00:00 2001
From: Mattias Andrée <maandree@operamail.com>
Date: Sat, 4 Apr 2015 12:50:22 +0200
Subject: add file descriptor redirection
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Signed-off-by: Mattias Andrée <maandree@operamail.com>
---
 doc/example                     |  5 ++-
 doc/syntax                      | 20 ++++++++-
 info/auto-auto-complete.texinfo | 25 +++++++++--
 src/auto-auto-complete.py       | 96 +++++++++++++++++++++++++++++++++++++++--
 4 files changed, 137 insertions(+), 9 deletions(-)

diff --git a/doc/example b/doc/example
index a993b54..d1e6b68 100644
--- a/doc/example
+++ b/doc/example
@@ -54,11 +54,12 @@
 		    	    (no-exec ls "'/usr/share/ponysay/balloons'" (case (ponysay .say) (ponythink .think)))
 	)
 	(suggestion wrap    (verbatim none inherit 100 60)
-		    	    (calc (pipe (stty size)
+		    	    (calc (pipe (stdin-fd (stty size) (stderr))
 			    	  	(cut -d ' ' -f 2)
 				  ) - 10
 			    )
 	)
-	; in addition to `pipe`(|) to following are also possible `fullpipe`(|&) `cat`(;) `and`(&&) `or`(||)
+	; in addition to `pipe`(|) the following are also possible: `fullpipe`(|&) `cat`(;) `and`(&&) `or`(||)
+	; in addition to `stdin-fd`(<&) the following are also possible: `stdout-fd` `stderr-fd` `fd-fd` `stdin` `stdout` `stderr` `fd`
 )
 
diff --git a/doc/syntax b/doc/syntax
index ca44109..df16bbb 100644
--- a/doc/syntax
+++ b/doc/syntax
@@ -56,10 +56,28 @@ verbatim ::= 'verbatim' _value [{_ value}]
 
 calc ::= 'calc' (__ value | _ any_exec) [{_ value | _ any_exec}]
 
-any_exec ::= '(' _ exec_type (__ value | _ any_exec) [{_ value | _ any_exec}] _ ')'
+any_exec ::= '(' _ (exec_sequence | exec_redirect) _ ')'
+
+exec_sequence ::= exec_type (__ value | _ any_exec) [{_ value | _ any_exec}]
 
 exec_type ::= "exec" | "calc" | "pipe" | "fullpipe" | "cat" | "and" | "or"
 
+exec_redirect ::= std_redirect | fd_redirect | std_redirect_fd | fd_redirect_fd
+
+std_redirect ::= input _ any_exec _ value
+
+fd_redirect ::= "fd" _ any_exec _ (number _value | fdnum _ value)
+
+std_redirect_fd ::= input "-fd" _ any_exec _ (number | fdnum)
+
+fd_redirect_fd ::= "fd" _ any_exec _ (number __ number | (number | fdnum) _ fdnum | fdnum _ number)
+
+input ::= "stdin" | "stdout" | "stderr"
+
+fdnum :: = "(" _ input _ ")"
+
+number ::= {"0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"}
+
 name ::= {letter | escape | squote | dquote}
 
 letter :: $any ^ ' ' ^ \t ^ \n ^ \r ^ \t ^ '\' ^ \' ^ \"
diff --git a/info/auto-auto-complete.texinfo b/info/auto-auto-complete.texinfo
index 977769e..0931933 100644
--- a/info/auto-auto-complete.texinfo
+++ b/info/auto-auto-complete.texinfo
@@ -17,7 +17,7 @@
 
 
 @copying
-Copyright @copyright{} 2014 Mattias Andrée
+Copyright @copyright{} 2014, 2015 Mattias Andrée
 
 @quotation
 Permission is granted to copy, distribute and/or modify this document
@@ -595,13 +595,13 @@ is to give it some default suggestion.
 The next step is to suggest the terminal's
 width minus 10 columns. In the Bash shell this
 can be calculated with
-@command{$(( $(stty size | cut -d ' ' -f 2) - 10 ))}.
+@command{$(( $(stty size <&2 | cut -d ' ' -f 2) - 10 ))}.
 
 @example
 ( ;We have cut out everything but (suggestion wrap).
   (suggestion wrap
      (verbatim none inherit 100 60)
-     (calc (pipe (stty size) (cut -d ' ' -f 2)) - 10)
+     (calc (pipe (stdin-fd (stty size) (stderr)) (cut -d ' ' -f 2)) - 10)
   )
 )
 @end example
@@ -622,6 +622,25 @@ can be used.
 @code{(a || b || c)}
 @end table
 
+It was also shown that @code{(stdin-fd (a) (stderr))} translates
+into @code{a <&2}. @code{(stdin)}, @code{(stdout)} and @code{(stderr)}
+translates into @code{0}, @code{1} and @code{2}, respectively.
+Additional @code{(stdin-fd a b)} translates into @code{a <&b},
+@code{(stdout-fd a b)} into @code{a >&b}, @code{(stderr-fd a b)} into @code{a 2>&b}
+and @code{(fd-fd a b c)} into @code{a b<>&c}.
+You can also redirect to files:
+
+@table @code
+@item (stdin a b)
+@code{a < b}
+@item (stdout a b)
+@code{a > b}
+@item (stderr a b)
+@code{a 2> b}
+@item (fd a b c)
+@code{a b> c}
+@end table
+
 
 
 @node GNU Free Documentation License
diff --git a/src/auto-auto-complete.py b/src/auto-auto-complete.py
index da8d56f..f883b36 100755
--- a/src/auto-auto-complete.py
+++ b/src/auto-auto-complete.py
@@ -266,7 +266,7 @@ class GeneratorBASH:
             return '\'' + text.replace('\'', '\'\\\'\'') + '\''
         
         def makeexec(functionType, function):
-            if functionType in ('exec', 'pipe', 'fullpipe', 'cat', 'and', 'or'):
+            if functionType in ('exec', 'pipe', 'fullpipe', 'cat', 'and', 'or', 'stdin', 'stdout', 'stderr', 'stdin-fd', 'stdout-fd', 'stderr-fd', 'fd', 'fd-fd'):
                 elems = [(' %s ' % makeexec(item[0], item[1:]) if isinstance(item, list) else verb(item)) for item in function]
                 if functionType == 'exec':
                     return ' $( %s ) ' % (' '.join(elems))
@@ -280,6 +280,36 @@ class GeneratorBASH:
                     return ' ( %s ) ' % (' && '.join(elems))
                 if functionType == 'or':
                     return ' ( %s ) ' % (' || '.join(elems))
+                if functionType == 'stdin':
+                    if len(elems) == 0:
+                        return 0
+                    [command, redirection] = elems
+                    return ' %s < %s ' % (command, redirection)
+                if functionType == 'stdout':
+                    if len(elems) == 0:
+                        return 1
+                    [command, redirection] = elems
+                    return ' %s > %s ' % (command, redirection)
+                if functionType == 'stderr':
+                    if len(elems) == 0:
+                        return 2
+                    [command, redirection] = elems
+                    return ' %s 2> %s ' % (command, redirection)
+                if functionType == 'stdin-fd':
+                    [command, redirection] = elems
+                    return ' %s <&%s ' % (command, redirection.replace('\'', '').replace(' ', ''))
+                if functionType == 'stdout-fd':
+                    [command, redirection] = elems
+                    return ' %s >&%s ' % (command, redirection.replace('\'', '').replace(' ', ''))
+                if functionType == 'stderr-fd':
+                    [command, redirection] = elems
+                    return ' %s 2>&%s ' % (command, redirection.replace('\'', '').replace(' ', ''))
+                if functionType == 'fd':
+                    [command, fd, redirection] = elems
+                    return ' %s %s<> %s ' % (command, fd.replace('\'', '').replace(' ', ''), redirection)
+                if functionType == 'fd-fd':
+                    [command, fd, redirection] = elems
+                    return ' %s %s<>&%s ' % (command, fd.replace('\'', '').replace(' ', ''), redirection.replace('\'', '').replace(' ', ''))
             if functionType in ('params', 'verbatim'):
                 return ' '.join([verb(item) for item in function])
             return ' '.join([verb(functionType)] + [verb(item) for item in function])
@@ -462,7 +492,7 @@ class GeneratorFISH:
             return '\'' + text.replace('\'', '\'\\\'\'') + '\''
         
         def makeexec(functionType, function):
-            if functionType in ('exec', 'pipe', 'fullpipe', 'cat', 'and', 'or'):
+            if functionType in ('exec', 'pipe', 'fullpipe', 'cat', 'and', 'or', 'stdin', 'stdout', 'stderr', 'stdin-fd', 'stdout-fd', 'stderr-fd', 'fd', 'fd-fd'):
                 elems = [(' %s ' % makeexec(item[0], item[1:]) if isinstance(item, list) else verb(item)) for item in function]
                 if functionType == 'exec':
                     return ' ( %s ) ' % (' '.join(elems))
@@ -476,6 +506,36 @@ class GeneratorFISH:
                     return ' ( %s ) ' % (' && '.join(elems))
                 if functionType == 'or':
                     return ' ( %s ) ' % (' || '.join(elems))
+                if functionType == 'stdin':
+                    if len(elems) == 0:
+                        return 0
+                    [command, redirection] = elems
+                    return ' %s < %s ' % (command, redirection)
+                if functionType == 'stdout':
+                    if len(elems) == 0:
+                        return 1
+                    [command, redirection] = elems
+                    return ' %s > %s ' % (command, redirection)
+                if functionType == 'stderr':
+                    if len(elems) == 0:
+                        return 2
+                    [command, redirection] = elems
+                    return ' %s 2> %s ' % (command, redirection)
+                if functionType == 'stdin-fd':
+                    [command, redirection] = elems
+                    return ' %s <&%s ' % (command, redirection.replace('\'', '').replace(' ', ''))
+                if functionType == 'stdout-fd':
+                    [command, redirection] = elems
+                    return ' %s >&%s ' % (command, redirection.replace('\'', '').replace(' ', ''))
+                if functionType == 'stderr-fd':
+                    [command, redirection] = elems
+                    return ' %s 2>&%s ' % (command, redirection.replace('\'', '').replace(' ', ''))
+                if functionType == 'fd':
+                    [command, fd, redirection] = elems
+                    return ' %s %s<> %s ' % (command, fd.replace('\'', '').replace(' ', ''), redirection)
+                if functionType == 'fd-fd':
+                    [command, fd, redirection] = elems
+                    return ' %s %s<>&%s ' % (command, fd.replace('\'', '').replace(' ', ''), redirection.replace('\'', '').replace(' ', ''))
             if functionType in ('params', 'verbatim'):
                 return ' '.join([verb(item) for item in function])
             return ' '.join([verb(functionType)] + [verb(item) for item in function])
@@ -656,7 +716,7 @@ class GeneratorZSH:
             return '\'' + text.replace('\'', '\'\\\'\'') + '\''
         
         def makeexec(functionType, function):
-            if functionType in ('exec', 'pipe', 'fullpipe', 'cat', 'and', 'or'):
+            if functionType in ('exec', 'pipe', 'fullpipe', 'cat', 'and', 'or', 'stdin', 'stdout', 'stderr', 'stdin-fd', 'stdout-fd', 'stderr-fd', 'fd', 'fd-fd'):
                 elems = [(' %s ' % makeexec(item[0], item[1:]) if isinstance(item, list) else verb(item)) for item in function]
                 if functionType == 'exec':
                     return ' $( %s ) ' % (' '.join(elems))
@@ -670,6 +730,36 @@ class GeneratorZSH:
                     return ' ( %s ) ' % (' && '.join(elems))
                 if functionType == 'or':
                     return ' ( %s ) ' % (' || '.join(elems))
+                if functionType == 'stdin':
+                    if len(elems) == 0:
+                        return 0
+                    [command, redirection] = elems
+                    return ' %s < %s ' % (command, redirection)
+                if functionType == 'stdout':
+                    if len(elems) == 0:
+                        return 1
+                    [command, redirection] = elems
+                    return ' %s > %s ' % (command, redirection)
+                if functionType == 'stderr':
+                    if len(elems) == 0:
+                        return 2
+                    [command, redirection] = elems
+                    return ' %s 2> %s ' % (command, redirection)
+                if functionType == 'stdin-fd':
+                    [command, redirection] = elems
+                    return ' %s <&%s ' % (command, redirection.replace('\'', '').replace(' ', ''))
+                if functionType == 'stdout-fd':
+                    [command, redirection] = elems
+                    return ' %s >&%s ' % (command, redirection.replace('\'', '').replace(' ', ''))
+                if functionType == 'stderr-fd':
+                    [command, redirection] = elems
+                    return ' %s 2>&%s ' % (command, redirection.replace('\'', '').replace(' ', ''))
+                if functionType == 'fd':
+                    [command, fd, redirection] = elems
+                    return ' %s %s<> %s ' % (command, fd.replace('\'', '').replace(' ', ''), redirection)
+                if functionType == 'fd-fd':
+                    [command, fd, redirection] = elems
+                    return ' %s %s<>&%s ' % (command, fd.replace('\'', '').replace(' ', ''), redirection.replace('\'', '').replace(' ', ''))
             if functionType in ('params', 'verbatim'):
                 return ' '.join([verb(item) for item in function])
             return ' '.join([verb(functionType)] + [verb(item) for item in function])
-- 
cgit v1.2.3-70-g09d2