2016-11-21 2 views
1

Я пытаюсь использовать readline в Haskell без переноса курсора на следующую строку.Как читать в Haskell без перевода на следующую строку?

Например, я написал следующий код:

readEvalPrintLoop :: IO() 
readEvalPrintLoop = do 
    line <- getLine 
    case line of 
      "bye" -> return() 
      line -> do putStrLn $ interpret line 
         readEvalPrintLoop 

После запуска программы:

> 1 2 + . <enter> 
3 

Но я хочу , чтобы найти самый простой способ получить следовать:

> 1 2 + . <enter> 3 
+0

@Bakuriu Да, это должна быть буферизация ввода, как вы упомянули. Обратите внимание, что этот буфер отсутствует в приложении Haskell, а скорее в терминале (либо в ядре ОС, либо в эмуляторе терминала). По умолчанию терминал передает эхо каждой клавише и перемещает курсор, как обычно, без какого-либо взаимодействия с приложением. Приложение может попросить терминал изменить это поведение по умолчанию, и, действительно, ncurses - общий способ сделать это. – chi

+0

@Bakuriu Буферизация только касательно связана: настоящая проблема здесь повторяется. В моем ответе я * также * отключу буферизацию, но не для того, чтобы предотвратить появление новой строки; скорее, это позволить всем остальным появляться сразу, а не на кусочки размером с буфер! –

+0

@Andrei Если вы похожи на меня, эта проблема, возможно, заставила вас задаться вопросом, что происходит и какие поведения настраиваются. Вы можете прочитать намного больше об этом в [TTY demystified] (http://www.linusakesson.net/programming/tty/), хотя я предупреждаю вас: если вы просто хотите, чтобы все было сделано, это будет путь больше информации, чем вы хотели! –

ответ

1

Когда вы нажимаете enter - как при нажатии любого другого ke y - печатается на экране. Вы можете отключить это поведение с hSetEcho:

main = do 
    hSetEcho stdin False 
    readEvalPrintLoop 

Однако, если вы сделаете это, вы найдете это имеет некоторый побочный ущерб: чем не вводить больше не повторил, но ни один не все, что вы печатаете, так это выглядит как все, что вы вводите, невидимо! Вы можете исправить это, выполнив свою измененную стратегию эха вручную. Вам нужно будет сделать две вещи: установите входной поток в небуферизованный режим с hSetBuffering (чтобы вы получали ввод сразу, а не в конце строки) и печатайте каждый полученный вами символ без ввода. Итак:

myGetLine :: IO String 
myGetLine = do 
    c <- getChar 
    case c of 
     '\n' -> return "" -- don't echo newlines 
     _ -> do 
      putChar c -- do echo everything else 
      fmap (c:) myGetLine 

readEvalPrintLoop :: IO() 
readEvalPrintLoop = do 
    line <- myGetLine -- getLine changed to myGetLine 
    case line of 
      "bye" -> return() 
      line -> do putStrLn $ interpret line 
         readEvalPrintLoop 

main = do 
    hSetEcho stdin False 
    hSetBuffering stdin NoBuffering 
    readEvalPrintLoop 
+0

N.B. В зависимости от того, какое поведение вы хотите, вы можете проверить EOF в 'myGetLine'. –

Смежные вопросы