Zoey Hewll
Zoey Hewll

Reputation: 5385

Pre-filled user input

I'm intending to write a simple program for line-wise file editing. The basic form of this program (which I know I can do) would allow the user to prepend, insert, and append lines to a file, in addition to deleting and replacing lines.

The line replace operation would require the user to write the entire desired contents of the line in stdin, but this is tedious if the new line is sufficiently similar to the old line. Ideally, they would have the added option to edit the line. The user input would pre-fill with the old contents of the line, allowing them to modify this line rather than typing the whole thing out.

I understand the regular getLine function cannot interpret arrow keypresses or other meta-keys except for backspace, so this may be a far more complex problem than it seemed on the surface; but if there is a preexisting function or library for this kind of operation I would be very appreciative.

If it helps, the desired type would be the following:

editLine :: String -> IO String

Upvotes: 2

Views: 89

Answers (2)

Zoey Hewll
Zoey Hewll

Reputation: 5385

Building off @Koterpillar's answer, here is an implementation of editLine as specified in the question, along with a slightly more general (but equally powerful) function:

import System.Console.Haskeline (InputT, runInputT, getInputLineWithInitial, defaultSettings)

editLine :: String -> IO String
editLine = getLinePrefill ""

-- getLinePrefill prompt = (putStr prompt >>) . editLine
getLinePrefill :: String -> String -> IO String
getLinePrefill prompt fill = line
    where
        -- no line == empty line
        line :: IO String
        line = concat <$> maybeLine

        -- run the InputT monad
        maybeLine :: IO (Maybe String)
        maybeLine = runInputT defaultSettings $ inputLine

        -- Get input line, prompt as supplied, default-string to the left of mouse
        inputLine :: InputT IO (Maybe String)
        inputLine = getInputLineWithInitial prompt (fill, "")

Upvotes: 2

Koterpillar
Koterpillar

Reputation: 8104

Editing the input lines and similar functionality is typically provided in POSIX world by readline library, and searching for "haskell readline" would be a good starting point if you want to know more about this.

In Haskell, haskeline package provides similar functionality.

The function for your use case is getInputLineWithInitial:

getInputLineWithInitial
    :: MonadException m  
    => String                  -- ^ The input prompt
    -> (String, String)        -- ^ The initial value left and right of the cursor
    -> InputT m (Maybe String)

You can convert an InputT IO value to IO by using runInputT:

runInputT defaultSettings :: InputT IO a -> IO a

Upvotes: 4

Related Questions