haskeline icon indicating copy to clipboard operation
haskeline copied to clipboard

Using Haskeline with a PseudoTerminal

Open NorfairKing opened this issue 4 years ago • 3 comments

I'd like to use haskeline for a browser-based terminal interface. (See smos.online.)

I got something hacky working like this:

    -- TODO try to use the special TTY handles instead so history works too.
    customRunInputT :: InputT IO a -> IO a
    customRunInputT inputT = do
      historyRef <- newIORef Haskeline.emptyHistory
      withBehavior (useFileHandle inputH) $ \rt -> do
        let runTerm =
              rt
                { putStrOut = \s -> do
                    hPutStr outputH s
                    hFlush outputH
                }
        runReaderT
          ( runReaderT
              ( Haskeline.runKillRing
                  ( runReaderT
                      ( runReaderT (unInputT inputT) runTerm
                      )
                      historyRef
                  )
              )
              Haskeline.defaultPrefs
          )
          Haskeline.defaultSettings

However, pressing the up arrow key doesn't show me the history but a control sequence instead. I've also tried to write this:

givenTtyHandles :: Handle -> Handle -> MaybeT IO Handles
givenTtyHandles inh outh = do
    outEH <- inCodingMode outh
    return Handles
            { hIn = externalHandle inh
            , hOut = outEH
            , closeHandles = pure () -- Don't close them
            }

and then the history works but the input is no longer echoed, even with hSetExcho inh and hSetBuffering inh NoBuffering.

Is this a use-case that you would like to support?

NorfairKing avatar Nov 25 '20 14:11 NorfairKing

I would very much like to see pseudo terminal support. My use case is in an embedded system where a daemon needs to open and service pseudo terminals and serial terminals.

goertzenator avatar Mar 10 '21 17:03 goertzenator

@NorfairKing , if you have a branch of your work pushed somewhere I would love to look at it. Also, did you manage the TERM environment variable at all? I wonder if this contributed to some of your problems.

I am thinking of a top level lib function like the one below that lets you provide input handle, output handle, and Maybe a terminal type. If Nothing is specified for term type then the environment is queried as usual. When using something besides the controlling terminal it will be common to not have the client's TERM variable available so it will need to be provided manually.

useTermHandles :: Handle -> Handle -> Maybe String -> Behavior

goertzenator avatar Mar 10 '21 22:03 goertzenator

@goertzenator https://github.com/NorfairKing/smos/blob/69226687bf7030b05a9ca0c6eacdcc03701c791c/smos-shell/src/Smos/Shell.hs#L34 here's what I do.

NorfairKing avatar Mar 11 '21 06:03 NorfairKing