Reputation: 5385
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
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
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