Search code examples
idris

How to read char without echo


In (*1) we have example how to turn off echo when use getChar in haskell. The idea is we can turn off echo using hSetEcho stdin False.

I would like do the same thing in Idris. Do I have a way?

(*1) Haskell read raw keyboard input


Solution

  • You might want to use the curses bindings.

    If this is too heavy for your usage, you can write C code that handles this for your terminal, and use that code via FFI interfaces. For example, you can use termios.hfor Linux terminals like this:

    termops.c:

     #include "termops.h"
     #include <termios.h>
    
     void set_echo(int fd) {
      struct termios term;
      tcgetattr(0, &term);
      term.c_lflag |= ECHO;
      tcsetattr(fd, TCSAFLUSH, &term);
     }
    
     void unset_echo(int fd) {
       struct termios term;
       tcgetattr(0, &term);
       term.c_lflag &= ~ECHO;
       tcsetattr(fd, TCSAFLUSH, &term);
     }
    

    termops.h:

    void set_echo(int fd);
    void unset_echo(int fd);
    

    termops.idr:

    %include C "termops.h"
    
    setEcho : IO ()
    setEcho = foreign FFI_C "set_echo" (Int -> IO ()) 0
    
    unsetEcho : IO ()
    unsetEcho = foreign FFI_C "unset_echo" (Int -> IO ()) 0
    
    getPasswd : IO String
    getPasswd = do
      c <- getChar
      if c == '\n'
      then pure ""
      else do rek <- getPasswd
              pure $ strCons c rek
    
    main : IO ()
    main = do
      unsetEcho
      passwd <- getPasswd
      setEcho
      printLn passwd
    

    To compile and link the C library, then use idris termops.idr --cg-opt "termops.c".