加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 服务器 > Linux > 正文

linux – 从haskell程序中运行vi(处理ptys)

发布时间:2020-12-13 16:59:56 所属栏目:Linux 来源:网络整理
导读:我正在尝试编写一个日志记录 shell;例如一个捕获有关以结构化格式运行的命令的数据.为此,我使用readline读取命令,然后在子shell中执行它们,同时捕获诸如所花费的时间,环境,退出状态等内容. 到现在为止还挺好.但是,从此日志记录shell中运行诸如vi或更少内容的
我正在尝试编写一个日志记录 shell;例如一个捕获有关以结构化格式运行的命令的数据.为此,我使用readline读取命令,然后在子shell中执行它们,同时捕获诸如所花费的时间,环境,退出状态等内容.

到现在为止还挺好.但是,从此日志记录shell中运行诸如vi或更少内容的初始尝试失败.调查表明要做的事情是建立一个伪tty并将子shell连接到那个而不是普通的管道.这会阻止vi抱怨没有连接到终端,但仍然失败 – 我在屏幕上打印了一些废话并且命令在编辑器中作为字符打印 – 例如’ESC’只显示^ [.

我认为我需要做的是将pty置于原始模式.为此,我尝试了以下方法:

pty <- do
    parentTerminal <- getControllingTerminalName >>= 
                      a -> openFd a ReadWrite Nothing defaultFileFlags
    sttyp <- getTerminalAttributes parentTerminal
    (a,b) <- openPseudoTerminal
    let rawModes = [ProcessInput,KeyboardInterrupts,ExtendedFunctions,EnableEcho,InterruptOnBreak,MapCRtoLF,IgnoreBreak,IgnoreCR,MapLFtoCR,CheckParity,StripHighBit,StartStopOutput,MarkParityErrors,ProcessOutput]
        sttym = withoutModes rawModes sttyp
        withoutModes modes tty = foldl withoutMode tty modes
    setTerminalAttributes b sttym Immediately
    setTerminalAttributes a sttym Immediately
    a' <- fdToHandle a
    b' <- fdToHandle b
    return (a',b')

例如.我们得到父终端的属性,删除我认为对应于将tty设置为原始模式的各种标志(基于this code和the haddock for System.Posix.Terminal),然后在pty的两侧设置它们.

然后我使用createProcess在shell中启动一个进程,并使用waitForProcess连接到它,为子进程的stdin和stdout句柄提供pty的slave端:

eval :: (Handle,Handle) -> String -> IO ()
eval pty command = do
    let (ptym,ptys) = pty
    (_,_,hErr,ph) <- createProcess $(shell command) { 
          delegate_ctlc = True,std_err = CreatePipe,std_out = UseHandle ptys,std_in = UseHandle ptys
      }
    snipOut <- tee ptym stdout
    snipErr <- sequence $fmap (h -> tee h stderr) hErr
    exitCode <- waitForProcess ph
    return ()
  where tee :: Handle -> Handle -> IO B.ByteString
        tee from to = DCB.sourceHandle from
            $= DCB.conduitHandle to -- Sink contents to out Handle
            $$DCB.take 256 -- Pull off the start of the stream

这肯定会改变终端设置(用stty确认),但不能解决问题.我错过了什么吗?我需要设置一些其他设备来设置属性吗?

编辑:完整的可运行代码可在https://github.com/nc6/tabula获得 – 我为这篇文章简化了一些内容.

解决方法

这是您创建vi进程的方法:
(_,ph) <- createProcess $(shell command) {

这些返回值是stdin / stdout / stderr.你扔掉stdin / stdout(并保持stderr).你需要那些与vi沟通.基本上,当您键入ESC时,它甚至没有进入该过程.

作为一个更大的架构笔记 – 您不仅要重写终端代码,还要重写完整的REPL / shell脚本….这是一个比您可能想要进入的更大的项目(请阅读bash手册以查看所有内容需要实施).您可能想要考虑包装用户可选择的shell脚本(如bash). Unix非常模块化,这就是为什么xterm,ssh,命令提示符等都以相同的方式工作 – 它们代理所选择的shell脚本,而不是每个都编写自己的脚本.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读