如何使用 Haskell 中的 readline 在任何按键上擦除终端中的一行?

How to erase a line in terminal on any keypress with readline in Haskell?

我正在使用 Haskell bindingsreadline 库来读取用户的输入。

我想要实现的是提供一个预填值,只需按 return 键即可提交,但如果用户开始输入,我想自动删除预填文本。 (这样用户就不必担心删除预填充值。)

我认为可以使用 rl_getc_function 挂钩来完成。但是,Haskell 绑定不公开此功能。

有什么方法可以实现所需的行为吗?

终于想出了一个办法,但是不太好,感觉有点hack。

它的工作原理是将所有键重新绑定到一个自定义函数,该函数首先擦除该行,然后重置所有这些处理程序以再次实际插入该字符。为了不丢失触发按键,它被推回输入。

main :: IO ()
main = do
    -- create a copy of current keymap
    keymap <- getKeymap >>= copyKeymap
    -- bind (hopefully all) regular keys to a helper function
    forM_ (map toEnum [32..256]) $ \key ->
        bindKey key $ \ _ _ -> do
            -- delete all text on line
            getEnd >>= deleteText 0
            -- set cursor to start of line
            setPoint 0
            redisplay
            -- reset keymap to the original one
            setKeymap keymap
            -- push pressed key back to input
            setPendingInput key
            return 0
    setStartupHook (Just $ insertText "prefilled text")
    readline "prompt> "

这个的主要痛点是确定要重新绑定哪些键。我用了一种科学的试错方法:下限是space(低于这个值的是不可打印的,可能有一些特殊的功能,我不想弄乱它)。上限设置为 256 - 任何更多都会导致段错误,使用较小的数字会使函数无法处理某些 unicode 输入。

即使在这个范围内,如果用户开始在 CJK. It definitely does not work correctly if the user types something by using a dead key.

中输入内容,它也可能无法正常工作