[英]Running vi from within haskell program (dealing with ptys)
我正在嘗試編寫一個日志外殼程序; 例如,它捕獲有關以結構化格式運行的命令的數據。 為此,我使用readline
讀取命令,然后在子shell中執行命令,同時捕獲諸如所花費的時間,環境,退出狀態等信息。
到目前為止,一切都很好。 但是,最初嘗試從此日志記錄外殼程序中運行諸如vi
或less
嘗試失敗。 調查表明,要做的事情是建立一個偽tty,並將子外殼連接到該外殼,而不是連接到普通管道。 這使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設置為原始模式相對應的各種標志(基於此代碼和System.Posix.Terminal
的haddock ),然后在pty的兩側進行設置。
然后,我使用createProcess
在shell中啟動一個進程,並使用waitForProcess
連接到它,為子進程的stdin和stdout句柄提供pty的從屬端:
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
過程的方式:
(_, _, hErr, ph) <- createProcess $ (shell command) {
這些返回值是stdin/stdout/stderr
。 您丟棄了stdin/stdout
(並保留了stderr
)。 您將需要那些與vi
進行交流的人。 基本上,當您輸入ESC
,它甚至都沒有進入該過程。
作為更大的體系結構筆記-您不僅在重寫終端代碼,而且在重寫完整的REPL / shell腳本。...這是一個比您可能想參與的項目還要大的項目(請閱讀bash手冊以了解它們的所有內容)。需要實施)。 您可能需要考慮包裝用戶可選擇的Shell腳本(如bash)。 Unix以這種方式非常模塊化,這就是為什么xterm,ssh,命令提示符等都以相同的方式工作的原因-它們代理選定的shell腳本,而不是各自編寫自己的腳本。
@jamshidh指出我實際上並沒有將stdin連接到pty的主端,所以我遇到的問題與vi或終端模式無關,而與不傳遞任何輸入完全有關!
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.