Skip to content

Commit c14ede3

Browse files
committed
Add description support for completions
1 parent ab22723 commit c14ede3

File tree

3 files changed

+44
-9
lines changed

3 files changed

+44
-9
lines changed

System/Console/Haskeline/Command/Completion.hs

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import System.Console.Haskeline.Completion
1616
import System.Console.Haskeline.Monads
1717

1818
import Data.List(transpose, unfoldr)
19+
import Data.Maybe(fromMaybe, catMaybes)
1920

2021
useCompletion :: InsertMode -> Completion -> InsertMode
2122
useCompletion im c = insertString r im
@@ -71,7 +72,7 @@ makePartialCompletion im completions = insertString partial im
7172
pagingCompletion :: MonadReader Layout m => Key -> Prefs
7273
-> [Completion] -> Command m InsertMode InsertMode
7374
pagingCompletion k prefs completions = \im -> do
74-
ls <- asks $ makeLines (map display completions)
75+
ls <- asks $ makeLines completions
7576
let pageAction = do
7677
askFirst prefs (length completions) $
7778
if completionPaging prefs
@@ -117,17 +118,26 @@ printPage ls = do
117118

118119
-----------------------------------------------
119120
-- Splitting the list of completions into lines for paging.
120-
makeLines :: [String] -> Layout -> [String]
121-
makeLines ws layout = let
122-
minColPad = 2
121+
makeLines :: [Completion] -> Layout -> [String]
122+
makeLines cs layout = let
123+
descM = description <$> cs
124+
descs = fromMaybe [] <$> descM
125+
disps = display <$> cs
126+
singleColumnMode = not . null . catMaybes $ descM
127+
minColPad = if singleColumnMode then 8 else 2
123128
printWidth = width layout
124-
maxWidth = min printWidth (maximum (map (gsWidth . stringToGraphemes) ws) + minColPad)
125-
numCols = printWidth `div` maxWidth
129+
maxWidth = min printWidth (maximum (map (gsWidth . stringToGraphemes) disps) + minColPad)
130+
numCols = if singleColumnMode then 1 else printWidth `div` maxWidth
131+
ws = if singleColumnMode then padLines maxWidth disps descs else disps
126132
ls = if maxWidth >= printWidth
127133
then map (: []) ws
128134
else splitIntoGroups numCols ws
129135
in map (padWords maxWidth) ls
130136

137+
padLines :: Int -> [String] -> [String] -> [String]
138+
padLines wid = zipWith (\x y -> x ++ replicate (wid - widthOf x) ' ' ++ y)
139+
where widthOf = gsWidth . stringToGraphemes
140+
131141
-- Add spaces to the end of each word so that it takes up the given visual width.
132142
-- Don't pad the word in the last column, since printing a space in the last column
133143
-- causes a line wrap on some terminals.

System/Console/Haskeline/Completion.hs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,9 @@ data Completion = Completion {replacement :: String, -- ^ Text to insert in lin
3838
display :: String,
3939
-- ^ Text to display when listing
4040
-- alternatives.
41+
description :: Maybe String,
42+
-- ^ Description to display when listing
43+
-- alternatives.
4144
isFinished :: Bool
4245
-- ^ Whether this word should be followed by a
4346
-- space, end quote, etc.
@@ -121,7 +124,7 @@ completeFilename = completeQuotedWord (Just '\\') "\"'" listFiles
121124
listFiles
122125

123126
completion :: String -> Completion
124-
completion str = Completion str str True
127+
completion str = Completion str str Nothing True
125128

126129
setReplacement :: (String -> String) -> Completion -> Completion
127130
setReplacement f c = c {replacement = f $ replacement c}
@@ -197,8 +200,9 @@ listFiles path = liftIO $ do
197200
(dir, file) = splitFileName path
198201
filterPrefix = filter (\f -> notElem f [".",".."]
199202
&& file `isPrefixOf` f)
200-
alterIfDir False c = c
203+
alterIfDir False c = c {description = Just "some description"}
201204
alterIfDir True c = c {replacement = addTrailingPathSeparator (replacement c),
205+
description = Just "some description",
202206
isFinished = False}
203207
fullName = replaceFileName path
204208

examples/Test.hs

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
module Main where
22

3+
import Data.List
34
import System.Console.Haskeline
45
import System.Environment
56

@@ -12,11 +13,28 @@ Usage:
1213
./Test password (no masking characters)
1314
./Test password \*
1415
./Test initial (use initial text in the prompt)
16+
./Test description (completion with descriptions)
1517
--}
1618

1719
mySettings :: Settings IO
1820
mySettings = defaultSettings {historyFile = Just "myhist"}
1921

22+
completeWithDesc :: CompletionFunc IO
23+
completeWithDesc (l, r) = return ([], completions)
24+
where
25+
items = [ "first"
26+
, "second"
27+
, "third"
28+
, "forth"
29+
, "fifth"
30+
]
31+
filterFunc d = (reverse l) `isPrefixOf` d && r `isSuffixOf` d
32+
filtered = filter filterFunc items
33+
replacements = (\x -> fst $ splitAt (length x - length r) x) <$> filtered
34+
descriptions = map (\x -> Just $ "this is the " <> x <> " item") filtered
35+
finished = replicate (length filtered) (null r)
36+
completions = zipWith4 Completion replacements filtered descriptions finished
37+
2038
main :: IO ()
2139
main = do
2240
args <- getArgs
@@ -26,7 +44,10 @@ main = do
2644
["password", [c]] -> getPassword (Just c)
2745
["initial"] -> flip getInputLineWithInitial ("left ", "right")
2846
_ -> getInputLine
29-
runInputT mySettings $ withInterrupt $ loop inputFunc 0
47+
settings = case args of
48+
["description"] -> setComplete completeWithDesc mySettings
49+
_ -> mySettings
50+
runInputT settings $ withInterrupt $ loop inputFunc 0
3051
where
3152
loop :: (String -> InputT IO (Maybe String)) -> Int -> InputT IO ()
3253
loop inputFunc n = do

0 commit comments

Comments
 (0)