Read /dev/tty from within a completion function

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP











up vote
3
down vote

favorite












Why is the following code not working for completion of the foo command? When I source it then type foo <Tab>, the shell hangs and doesn't take any input until I press ^C (which exits the command completion).



My hypothesis is that /dev/tty is already being read by the shell and it somehow messes with cat being able to read from it as well, but in that case I still need a workaround.



_foo() 
_values 'foo' "$(cat < /dev/tty)"


compdef _foo foo


Note that this example is deliberately simplified: the actual use case is running a terminal interface program (think ncurses) instead of cat.







share|improve this question
















  • 1




    What are you trying to achieve with this particular completion?
    – mik
    Jan 23 at 21:49






  • 1




    I just want to implement my own completion UI. I already have the ncurses GUI binary implemented, it works when I call it from the regular shell (even when its input is a pipe or it's invoked from a subshell, in which case I just open /dev/tty myself), the only issue is when used with completion.
    – Nison Maël
    Jan 23 at 21:52











  • Note that zsh has builtin ncurses support in its zsh/curses module.
    – Stéphane Chazelas
    Jan 29 at 17:13














up vote
3
down vote

favorite












Why is the following code not working for completion of the foo command? When I source it then type foo <Tab>, the shell hangs and doesn't take any input until I press ^C (which exits the command completion).



My hypothesis is that /dev/tty is already being read by the shell and it somehow messes with cat being able to read from it as well, but in that case I still need a workaround.



_foo() 
_values 'foo' "$(cat < /dev/tty)"


compdef _foo foo


Note that this example is deliberately simplified: the actual use case is running a terminal interface program (think ncurses) instead of cat.







share|improve this question
















  • 1




    What are you trying to achieve with this particular completion?
    – mik
    Jan 23 at 21:49






  • 1




    I just want to implement my own completion UI. I already have the ncurses GUI binary implemented, it works when I call it from the regular shell (even when its input is a pipe or it's invoked from a subshell, in which case I just open /dev/tty myself), the only issue is when used with completion.
    – Nison Maël
    Jan 23 at 21:52











  • Note that zsh has builtin ncurses support in its zsh/curses module.
    – Stéphane Chazelas
    Jan 29 at 17:13












up vote
3
down vote

favorite









up vote
3
down vote

favorite











Why is the following code not working for completion of the foo command? When I source it then type foo <Tab>, the shell hangs and doesn't take any input until I press ^C (which exits the command completion).



My hypothesis is that /dev/tty is already being read by the shell and it somehow messes with cat being able to read from it as well, but in that case I still need a workaround.



_foo() 
_values 'foo' "$(cat < /dev/tty)"


compdef _foo foo


Note that this example is deliberately simplified: the actual use case is running a terminal interface program (think ncurses) instead of cat.







share|improve this question












Why is the following code not working for completion of the foo command? When I source it then type foo <Tab>, the shell hangs and doesn't take any input until I press ^C (which exits the command completion).



My hypothesis is that /dev/tty is already being read by the shell and it somehow messes with cat being able to read from it as well, but in that case I still need a workaround.



_foo() 
_values 'foo' "$(cat < /dev/tty)"


compdef _foo foo


Note that this example is deliberately simplified: the actual use case is running a terminal interface program (think ncurses) instead of cat.









share|improve this question











share|improve this question




share|improve this question










asked Jan 23 at 20:49









Nison Maël

18114




18114







  • 1




    What are you trying to achieve with this particular completion?
    – mik
    Jan 23 at 21:49






  • 1




    I just want to implement my own completion UI. I already have the ncurses GUI binary implemented, it works when I call it from the regular shell (even when its input is a pipe or it's invoked from a subshell, in which case I just open /dev/tty myself), the only issue is when used with completion.
    – Nison Maël
    Jan 23 at 21:52











  • Note that zsh has builtin ncurses support in its zsh/curses module.
    – Stéphane Chazelas
    Jan 29 at 17:13












  • 1




    What are you trying to achieve with this particular completion?
    – mik
    Jan 23 at 21:49






  • 1




    I just want to implement my own completion UI. I already have the ncurses GUI binary implemented, it works when I call it from the regular shell (even when its input is a pipe or it's invoked from a subshell, in which case I just open /dev/tty myself), the only issue is when used with completion.
    – Nison Maël
    Jan 23 at 21:52











  • Note that zsh has builtin ncurses support in its zsh/curses module.
    – Stéphane Chazelas
    Jan 29 at 17:13







1




1




What are you trying to achieve with this particular completion?
– mik
Jan 23 at 21:49




What are you trying to achieve with this particular completion?
– mik
Jan 23 at 21:49




1




1




I just want to implement my own completion UI. I already have the ncurses GUI binary implemented, it works when I call it from the regular shell (even when its input is a pipe or it's invoked from a subshell, in which case I just open /dev/tty myself), the only issue is when used with completion.
– Nison Maël
Jan 23 at 21:52





I just want to implement my own completion UI. I already have the ncurses GUI binary implemented, it works when I call it from the regular shell (even when its input is a pipe or it's invoked from a subshell, in which case I just open /dev/tty myself), the only issue is when used with completion.
– Nison Maël
Jan 23 at 21:52













Note that zsh has builtin ncurses support in its zsh/curses module.
– Stéphane Chazelas
Jan 29 at 17:13




Note that zsh has builtin ncurses support in its zsh/curses module.
– Stéphane Chazelas
Jan 29 at 17:13










2 Answers
2






active

oldest

votes

















up vote
0
down vote













This is probably too simplified, cat will read from /dev/tty for a good long while. With a _foo completion of



#compdef foo
_values 'foo' "$(promptfor)"


and a promptfor of



#!/usr/bin/env expect
set fh [open /dev/tty r+]
stty raw -echo
set key [read $fh 1] ;# read from tty
puts stdout $key ;# to ZSH
flush stdout
stty -raw echo


my ZSH on footab will then complete whatever key is then pressed while promptfor runs.



If you have a daemon of sorts sitting around, then you'll probably need something fancier like a socket that ZSH and your daemon can use to carry out any necessary communications; read in ZSH can read from an arbitrary file descriptor or coprocess...






share|improve this answer



























    up vote
    0
    down vote













    During completion, you're in the zsh line editor, so the terminal line discipline's own line editor is disabled as if you had run:



    stty -icanon -echo


    In that mode, cat cannot exit as there's no way you can signify it the end of input (^D is part of the icanon line discipline's line editor behaviour) and you won't see the echo of what you type.



    You could do:



    _foo() 
    _values 'foo' "$(

    s=$(stty -g)
    stty sane
    cat
    stty $s
    < /dev/tty)"
    zle -I



    That is, put the terminal device in the state expected by cat (where you can press ^D on an empty line or twice to end the input) before running cat and restore it afterwards. And we tell zle it has to redraw its prompt and buffer as the echo of what you'd type within the line discipline line editor would mess things up (zle -I to invalidate).






    share|improve this answer




















      Your Answer







      StackExchange.ready(function()
      var channelOptions =
      tags: "".split(" "),
      id: "106"
      ;
      initTagRenderer("".split(" "), "".split(" "), channelOptions);

      StackExchange.using("externalEditor", function()
      // Have to fire editor after snippets, if snippets enabled
      if (StackExchange.settings.snippets.snippetsEnabled)
      StackExchange.using("snippets", function()
      createEditor();
      );

      else
      createEditor();

      );

      function createEditor()
      StackExchange.prepareEditor(
      heartbeatType: 'answer',
      convertImagesToLinks: false,
      noModals: false,
      showLowRepImageUploadWarning: true,
      reputationToPostImages: null,
      bindNavPrevention: true,
      postfix: "",
      onDemand: true,
      discardSelector: ".discard-answer"
      ,immediatelyShowMarkdownHelp:true
      );



      );








       

      draft saved


      draft discarded


















      StackExchange.ready(
      function ()
      StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2funix.stackexchange.com%2fquestions%2f419179%2fread-dev-tty-from-within-a-completion-function%23new-answer', 'question_page');

      );

      Post as a guest






























      2 Answers
      2






      active

      oldest

      votes








      2 Answers
      2






      active

      oldest

      votes









      active

      oldest

      votes






      active

      oldest

      votes








      up vote
      0
      down vote













      This is probably too simplified, cat will read from /dev/tty for a good long while. With a _foo completion of



      #compdef foo
      _values 'foo' "$(promptfor)"


      and a promptfor of



      #!/usr/bin/env expect
      set fh [open /dev/tty r+]
      stty raw -echo
      set key [read $fh 1] ;# read from tty
      puts stdout $key ;# to ZSH
      flush stdout
      stty -raw echo


      my ZSH on footab will then complete whatever key is then pressed while promptfor runs.



      If you have a daemon of sorts sitting around, then you'll probably need something fancier like a socket that ZSH and your daemon can use to carry out any necessary communications; read in ZSH can read from an arbitrary file descriptor or coprocess...






      share|improve this answer
























        up vote
        0
        down vote













        This is probably too simplified, cat will read from /dev/tty for a good long while. With a _foo completion of



        #compdef foo
        _values 'foo' "$(promptfor)"


        and a promptfor of



        #!/usr/bin/env expect
        set fh [open /dev/tty r+]
        stty raw -echo
        set key [read $fh 1] ;# read from tty
        puts stdout $key ;# to ZSH
        flush stdout
        stty -raw echo


        my ZSH on footab will then complete whatever key is then pressed while promptfor runs.



        If you have a daemon of sorts sitting around, then you'll probably need something fancier like a socket that ZSH and your daemon can use to carry out any necessary communications; read in ZSH can read from an arbitrary file descriptor or coprocess...






        share|improve this answer






















          up vote
          0
          down vote










          up vote
          0
          down vote









          This is probably too simplified, cat will read from /dev/tty for a good long while. With a _foo completion of



          #compdef foo
          _values 'foo' "$(promptfor)"


          and a promptfor of



          #!/usr/bin/env expect
          set fh [open /dev/tty r+]
          stty raw -echo
          set key [read $fh 1] ;# read from tty
          puts stdout $key ;# to ZSH
          flush stdout
          stty -raw echo


          my ZSH on footab will then complete whatever key is then pressed while promptfor runs.



          If you have a daemon of sorts sitting around, then you'll probably need something fancier like a socket that ZSH and your daemon can use to carry out any necessary communications; read in ZSH can read from an arbitrary file descriptor or coprocess...






          share|improve this answer












          This is probably too simplified, cat will read from /dev/tty for a good long while. With a _foo completion of



          #compdef foo
          _values 'foo' "$(promptfor)"


          and a promptfor of



          #!/usr/bin/env expect
          set fh [open /dev/tty r+]
          stty raw -echo
          set key [read $fh 1] ;# read from tty
          puts stdout $key ;# to ZSH
          flush stdout
          stty -raw echo


          my ZSH on footab will then complete whatever key is then pressed while promptfor runs.



          If you have a daemon of sorts sitting around, then you'll probably need something fancier like a socket that ZSH and your daemon can use to carry out any necessary communications; read in ZSH can read from an arbitrary file descriptor or coprocess...







          share|improve this answer












          share|improve this answer



          share|improve this answer










          answered Jan 24 at 0:14









          thrig

          22.3k12852




          22.3k12852






















              up vote
              0
              down vote













              During completion, you're in the zsh line editor, so the terminal line discipline's own line editor is disabled as if you had run:



              stty -icanon -echo


              In that mode, cat cannot exit as there's no way you can signify it the end of input (^D is part of the icanon line discipline's line editor behaviour) and you won't see the echo of what you type.



              You could do:



              _foo() 
              _values 'foo' "$(

              s=$(stty -g)
              stty sane
              cat
              stty $s
              < /dev/tty)"
              zle -I



              That is, put the terminal device in the state expected by cat (where you can press ^D on an empty line or twice to end the input) before running cat and restore it afterwards. And we tell zle it has to redraw its prompt and buffer as the echo of what you'd type within the line discipline line editor would mess things up (zle -I to invalidate).






              share|improve this answer
























                up vote
                0
                down vote













                During completion, you're in the zsh line editor, so the terminal line discipline's own line editor is disabled as if you had run:



                stty -icanon -echo


                In that mode, cat cannot exit as there's no way you can signify it the end of input (^D is part of the icanon line discipline's line editor behaviour) and you won't see the echo of what you type.



                You could do:



                _foo() 
                _values 'foo' "$(

                s=$(stty -g)
                stty sane
                cat
                stty $s
                < /dev/tty)"
                zle -I



                That is, put the terminal device in the state expected by cat (where you can press ^D on an empty line or twice to end the input) before running cat and restore it afterwards. And we tell zle it has to redraw its prompt and buffer as the echo of what you'd type within the line discipline line editor would mess things up (zle -I to invalidate).






                share|improve this answer






















                  up vote
                  0
                  down vote










                  up vote
                  0
                  down vote









                  During completion, you're in the zsh line editor, so the terminal line discipline's own line editor is disabled as if you had run:



                  stty -icanon -echo


                  In that mode, cat cannot exit as there's no way you can signify it the end of input (^D is part of the icanon line discipline's line editor behaviour) and you won't see the echo of what you type.



                  You could do:



                  _foo() 
                  _values 'foo' "$(

                  s=$(stty -g)
                  stty sane
                  cat
                  stty $s
                  < /dev/tty)"
                  zle -I



                  That is, put the terminal device in the state expected by cat (where you can press ^D on an empty line or twice to end the input) before running cat and restore it afterwards. And we tell zle it has to redraw its prompt and buffer as the echo of what you'd type within the line discipline line editor would mess things up (zle -I to invalidate).






                  share|improve this answer












                  During completion, you're in the zsh line editor, so the terminal line discipline's own line editor is disabled as if you had run:



                  stty -icanon -echo


                  In that mode, cat cannot exit as there's no way you can signify it the end of input (^D is part of the icanon line discipline's line editor behaviour) and you won't see the echo of what you type.



                  You could do:



                  _foo() 
                  _values 'foo' "$(

                  s=$(stty -g)
                  stty sane
                  cat
                  stty $s
                  < /dev/tty)"
                  zle -I



                  That is, put the terminal device in the state expected by cat (where you can press ^D on an empty line or twice to end the input) before running cat and restore it afterwards. And we tell zle it has to redraw its prompt and buffer as the echo of what you'd type within the line discipline line editor would mess things up (zle -I to invalidate).







                  share|improve this answer












                  share|improve this answer



                  share|improve this answer










                  answered Jan 29 at 17:10









                  Stéphane Chazelas

                  281k53518849




                  281k53518849






















                       

                      draft saved


                      draft discarded


























                       


                      draft saved


                      draft discarded














                      StackExchange.ready(
                      function ()
                      StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2funix.stackexchange.com%2fquestions%2f419179%2fread-dev-tty-from-within-a-completion-function%23new-answer', 'question_page');

                      );

                      Post as a guest













































































                      Popular posts from this blog

                      How to check contact read email or not when send email to Individual?

                      Displaying single band from multi-band raster using QGIS

                      How many registers does an x86_64 CPU actually have?