Changes on XPrompt:

* Adds mkPromptWithModes, creates a prompt given a list of modes (list of XPType).

    * Adds Setting `alwaysHighlight` to defaultXPConfig. When set to true, autocompletion always highlight the first result if it is not highlighted.
    
Adds module XMonad.Actions.Launcher. This module allows to combine and switch between instances of XPrompt. It includes a default set of modes which require the programs `hoogle`, `locate` and `calc` to be installed to work properly.
This commit is contained in:
c.lopez 2012-06-28 10:17:49 +00:00
parent 9d34e848d9
commit 3c74148a2f
3 changed files with 395 additions and 39 deletions

177
XMonad/Actions/Launcher.hs Normal file
View File

@ -0,0 +1,177 @@
{- |
Module : XMonad.Actions.Launcher
Copyright : (C) 2012 Carlos López-Camey
License : None; public domain
Maintainer : <c.lopez@kmels.net>
Stability : unstable
A set of prompts for XMonad
-}
module XMonad.Actions.Launcher(
-- * Description and use
-- $description
defaultLauncherModes
, ExtensionActions
, LauncherConfig(..)
, LocateFileMode
, LocateFileRegexMode
, launcherPrompt
-- * ToDo
-- $todo
) where
import Data.List (find, findIndex, isPrefixOf, tails)
import qualified Data.Map as M
import Data.Maybe (fromMaybe, isJust)
import System.Directory (doesDirectoryExist)
import XMonad hiding (config)
import XMonad.Prompt
import XMonad.Util.Run
{- $description
This module lets you combine and switch between different types of prompts (XMonad.Prompt). It includes a set of default modes:
* Hoogle mode: Search for functions using hoogle, choosing a function leads you to documentation in Haddock.
* Locate mode: Search for files using locate, choosing a file opens it with a program you specify depending on the file's extension.
* Locate regexp: Same as locate mode but autocomplete works with regular expressions.
* Calc: Uses the program calc to do calculations.
To use the default modes, modify your .xmonad:
> import XMonad.Prompt(defaultXPConfig)
> import XMonad.Actions.Launcher
> ((modm .|. controlMask, xK_l), launcherPrompt kmelsXPConfig $ defaultLauncherModes launcherConfig)
A LauncherConfig contains settings for the default modes, modify them accordingly.
> launcherConfig = LauncherConfig { pathToHoogle = "/home/YOU/.cabal/bin/hoogle" , actionsByExtension = extensionActions }
@extensionActions :: M.Map String (String -> X())
extensionActions = M.fromList $ [
(\".hs\", \p -> spawn $ \"emacs \" ++ p)
, (\".pdf\", \p -> spawn $ \"acroread \" ++ p)
, (\".*\", \p -> spawn $ \"emacs \" ++ p) --match with any files
, (\"/\", \p -> spawn $ \"nautilus \" ++ p) --match with directories
]@
To try it, restart xmonad. Press Ctrl + Your_Modkey + L and the first prompt should pop up.
You can change mode with xK_grave if you used defaultXP or change the value of changeModeKey in your XPConfig-}
data LocateFileMode = LMode ExtensionActions
data LocateFileRegexMode = LRMode ExtensionActions
data HoogleMode = HMode FilePath String --path to hoogle e.g. "/home/me/.cabal/bin/hoogle"
data CalculatorMode = CalcMode
data LauncherConfig = LauncherConfig {
browser :: String
, pathToHoogle :: String
, actionsByExtension :: ExtensionActions
}
type ExtensionActions = M.Map String (String -> X())
-- | Uses the program `locate` to list files
instance XPrompt LocateFileMode where
showXPrompt (LMode _) = "locate %s> "
completionFunction (LMode _) = \s -> if (s == "" || last s == ' ') then return [] else (completionFunctionWith "locate" ["--limit","5",s])
modeAction (LMode actions) _ fp = spawnWithActions actions fp
-- | Uses the program `locate --regex` to list files
instance XPrompt LocateFileRegexMode where
showXPrompt (LRMode _) = "locate --regexp %s> "
completionFunction (LRMode _) = \s -> if (s == "" || last s == ' ') then return [] else (completionFunctionWith "locate" ["--limit","5","--regexp",s])
modeAction (LRMode actions) _ fp = spawnWithActions actions fp
-- | Uses the command `calc` to compute arithmetic expressions
instance XPrompt CalculatorMode where
showXPrompt CalcMode = "calc %s> "
commandToComplete CalcMode = id --send the whole string to `calc`
completionFunction CalcMode = \s -> if (length s == 0) then return [] else do
fmap lines $ runProcessWithInput "calc" [s] ""
modeAction CalcMode _ _ = return () -- do nothing; this might copy the result to the clipboard
-- | Uses the program `hoogle` to search for functions
instance XPrompt HoogleMode where
showXPrompt _ = "hoogle %s> "
commandToComplete _ = id
completionFunction (HMode pathToHoogleBin' _) = \s -> completionFunctionWith pathToHoogleBin' ["--count","5",s]
-- This action calls hoogle again to find the URL corresponding to the autocompleted item
modeAction (HMode pathToHoogleBin'' browser) query result = do
completionsWithLink <- liftIO $ completionFunctionWith pathToHoogleBin'' ["--count","5","--link",query]
let link = do
s <- find (isJust . \c -> findSeqIndex c result) completionsWithLink
i <- findSeqIndex s "http://"
return $ drop i s
case link of
Just l -> spawn $ browser ++ " " ++ l
_ -> return ()
where
-- | Receives a sublist and a list. It returns the index where the sublist appears in the list.
findSeqIndex :: (Eq a) => [a] -> [a] -> Maybe Int
findSeqIndex xs xss = findIndex (isPrefixOf xss) $ tails xs
-- | Creates an autocompletion function for a programm given the program's name and a list of args to send to the command.
completionFunctionWith :: String -> [String] -> IO [String]
completionFunctionWith cmd args = do fmap lines $ runProcessWithInput cmd args ""
-- | Creates a prompt with the given modes
launcherPrompt :: XPConfig -> [XPMode] -> X()
launcherPrompt config modes = mkXPromptWithModes modes config
-- | Create a list of modes based on :
-- a list of extensions mapped to actions
-- the path to hoogle
defaultLauncherModes :: LauncherConfig -> [XPMode]
defaultLauncherModes cnf = let
ph = pathToHoogle cnf
actions = actionsByExtension cnf
in [ hoogleMode ph $ browser cnf
, locateMode actions
, locateRegexMode actions
, calcMode]
locateMode, locateRegexMode :: ExtensionActions -> XPMode
locateMode actions = XPT $ LMode actions
locateRegexMode actions = XPT $ LRMode actions
hoogleMode :: FilePath -> String -> XPMode
hoogleMode pathToHoogleBin browser = XPT $ HMode pathToHoogleBin browser
calcMode :: XPMode
calcMode = XPT CalcMode
-- | This function takes a map of extensions and a path file. It uses the map to find the pattern that matches the file path, then the corresponding program (listed in the map) is spawned.
spawnWithActions :: ExtensionActions -> FilePath -> X()
spawnWithActions actions fp = do
isDirectoryPath <- liftIO $ doesDirectoryExist fp
let
takeExtension = \p -> "." ++ (reverse . takeWhile (/= '.') $ reverse p) --it includes the dot
-- Patterns defined by the user
extAction = M.lookup (takeExtension fp) actions
dirAction = if (isDirectoryPath) then M.lookup "/" actions else Nothing -- / represents a directory
anyFileAction = M.lookup ".*" actions -- .* represents any file
action = fromMaybe (spawnNoPatternMessage (takeExtension fp)) $ extAction `orElse1` dirAction `orElse1` anyFileAction
action fp
where
-- | This function is defined in Data.Generics.Aliases (package syb "Scrap your boilerplate"), defined here to avoid dependency
orElse1 :: Maybe a -> Maybe a -> Maybe a
x `orElse1` y = case x of
Just _ -> x
Nothing -> y
spawnNoPatternMessage :: String -> String -> X ()
spawnNoPatternMessage fileExt _ = spawn $ "xmessage No action specified for file extension " ++ fileExt ++ ", add a default action by matching the extension \".*\" in the action map sent to launcherPrompt"
{- $todo
* Switch to mode by name of the prompt, 1. ':' at an empty(?) buffer, 2. autocomplete name in buffer should happen, 3. switch to mode with enter (cancel switch with C-g)
* Support for actions of type String -> X a
* Hoogle mode: add a setting in the action to either go to documentation or to the source code (needs hoogle change?)
* Hoogle mode: add setting to query hoogle at haskell.org instead (with &mode=json)
-}

View File

@ -18,9 +18,11 @@ module XMonad.Prompt
-- $usage
mkXPrompt
, mkXPromptWithReturn
, mkXPromptWithModes
, amberXPConfig
, defaultXPConfig
, greenXPConfig
, XPMode
, XPType (..)
, XPPosition (..)
, XPConfig (..)
@ -109,11 +111,11 @@ data XPState =
, screen :: !Rectangle
, complWin :: Maybe Window
, complWinDim :: Maybe ComplWindowDim
, completionFunction :: String -> IO [String]
, complIndex :: !(Int,Int)
, showComplWin :: Bool
, operationMode :: XPOperationMode
, gcon :: !GC
, fontS :: !XMonadFont
, xptype :: !XPType
, commandHistory :: W.Stack String
, offset :: !Int
, config :: XPConfig
@ -131,6 +133,7 @@ data XPConfig =
, borderColor :: String -- ^ Border color
, promptBorderWidth :: !Dimension -- ^ Border width
, position :: XPPosition -- ^ Position: 'Top' or 'Bottom'
, alwaysHighlight :: !Bool -- ^ Always highlight an item, overriden to True with multiple modes. This implies having *one* column of autocompletions only.
, height :: !Dimension -- ^ Window height
, historySize :: !Int -- ^ The number of history entries to be saved
, historyFilter :: [String] -> [String]
@ -139,6 +142,7 @@ data XPConfig =
, promptKeymap :: M.Map (KeyMask,KeySym) (XP ())
-- ^ Mapping from key combinations to actions
, completionKey :: KeySym -- ^ Key that should trigger completion
, changeModeKey :: KeySym -- ^ Key to change mode (when the prompt has multiple modes)
, defaultText :: String -- ^ The text by default in the prompt line
, autoComplete :: Maybe Int -- ^ Just x: if only one completion remains, auto-select it,
, showCompletionOnTab :: Bool -- ^ Only show list of completions when Tab was pressed
@ -149,6 +153,9 @@ data XPConfig =
}
data XPType = forall p . XPrompt p => XPT p
type ComplFunction = String -> IO [String]
type XPMode = XPType
data XPOperationMode = XPSingleMode ComplFunction XPType | XPMultipleModes (W.Stack XPType)
instance Show XPType where
show (XPT p) = showXPrompt p
@ -158,6 +165,8 @@ instance XPrompt XPType where
nextCompletion (XPT t) = nextCompletion t
commandToComplete (XPT t) = commandToComplete t
completionToCommand (XPT t) = completionToCommand t
completionFunction (XPT t) = completionFunction t
modeAction (XPT t) = modeAction t
-- | The class prompt types must be an instance of. In order to
-- create a prompt you need to create a data type, without parameters,
@ -179,11 +188,13 @@ class XPrompt t where
-- printed in the command line when tab is pressed, given the
-- string presently in the command line and the list of
-- completion.
-- This function is not used when in multiple modes (because alwaysHighlight in XPConfig is True)
nextCompletion :: t -> String -> [String] -> String
nextCompletion = getNextOfLastWord
-- | This method is used to generate the string to be passed to
-- the completion function.
-- This function is not used when in multiple modes (because alwaysHighlight in XPConfig is True)
commandToComplete :: t -> String -> String
commandToComplete _ = getLastWord
@ -197,6 +208,20 @@ class XPrompt t where
completionToCommand :: t -> String -> String
completionToCommand _ c = c
-- | When the prompt has multiple modes, this is the function
-- used to generate the autocompletion list.
-- The argument passed to this function is given by `commandToComplete`
-- The default implementation shows an error message.
completionFunction :: t -> ComplFunction
completionFunction t = \_ -> return ["Completions for " ++ (showXPrompt t) ++ " could not be loaded"]
-- | When the prompt has multiple modes, this function is called
-- when the user picked an item from the autocompletion list.
-- The first argument is the autocompleted item's text.
-- The second argument is the query made by the user (written in the prompt's buffer).
modeAction :: t -> String -> String -> X ()
modeAction _ _ _ = return ()
data XPPosition = Top
| Bottom
deriving (Show,Read)
@ -213,6 +238,7 @@ defaultXPConfig =
, promptBorderWidth = 1
, promptKeymap = defaultXPKeymap
, completionKey = xK_Tab
, changeModeKey = xK_asciitilde
, position = Bottom
, height = 18
, historySize = 256
@ -221,29 +247,28 @@ defaultXPConfig =
, autoComplete = Nothing
, showCompletionOnTab = False
, searchPredicate = isPrefixOf
, alwaysHighlight = False
}
greenXPConfig = defaultXPConfig { fgColor = "green", bgColor = "black", promptBorderWidth = 0 }
amberXPConfig = defaultXPConfig { fgColor = "#ca8f2d", bgColor = "black", fgHLight = "#eaaf4c" }
type ComplFunction = String -> IO [String]
initState :: XPrompt p => Display -> Window -> Window -> Rectangle -> ComplFunction
-> GC -> XMonadFont -> p -> [String] -> XPConfig -> KeyMask -> XPState
initState d rw w s compl gc fonts pt h c nm =
initState :: Display -> Window -> Window -> Rectangle -> XPOperationMode
-> GC -> XMonadFont -> [String] -> XPConfig -> KeyMask -> XPState
initState d rw w s opMode gc fonts h c nm =
XPS { dpy = d
, rootw = rw
, win = w
, screen = s
, complWin = Nothing
, complWinDim = Nothing
, completionFunction = compl
, showComplWin = not (showCompletionOnTab c)
, operationMode = opMode
, gcon = gc
, fontS = fonts
, xptype = XPT pt
, commandHistory = W.Stack { W.focus = defaultText c
, W.up = []
, W.down = h }
, complIndex = (0,0) --(column index, row index), used when `alwaysHighlight` in XPConfig is True
, offset = length (defaultText c)
, config = c
, successful = False
@ -251,6 +276,36 @@ initState d rw w s compl gc fonts pt h c nm =
, numlockMask = nm
}
-- Returns the current XPType
currentXPMode :: XPState -> XPType
currentXPMode st = case operationMode st of
XPMultipleModes modes -> W.focus modes
XPSingleMode _ xptype -> xptype
-- When in multiple modes, this function sets the next mode
-- in the list of modes as active
setNextMode :: XPState -> XPState
setNextMode st = case operationMode st of
XPMultipleModes modes -> case W.down modes of
[] -> st -- there is no next mode, return same state
(m:ms) -> let
currentMode = W.focus modes
in st { operationMode = XPMultipleModes W.Stack { W.up = [], W.focus = m, W.down = ms ++ [currentMode]}} --set next and move previous current mode to the of the stack
_ -> st --nothing to do, the prompt's operation has only one mode
-- Returns the highlighted item
highlightedItem :: XPState -> [String] -> String
highlightedItem st' completions = case complWinDim st' of
Nothing -> "" -- when there isn't any compl win, we can't say how many cols,rows there are
Just winDim ->
let
(_,_,_,_,xx,yy) = winDim
complMatrix = splitInSubListsAt (length yy) (take (length xx * length yy) completions)
(col_index,row_index) = (complIndex st')
in case completions of
[] -> "" -- no completions
_ -> complMatrix !! col_index !! row_index
-- this would be much easier with functional references
command :: XPState -> String
command = W.focus . commandHistory
@ -285,14 +340,17 @@ mkXPromptWithReturn t conf compl action = do
fs <- initXMF (font conf)
numlock <- gets $ X.numberlockMask
let hs = fromMaybe [] $ M.lookup (showXPrompt t) hist
st = initState d rw w s compl gc fs (XPT t) hs conf numlock
om = (XPSingleMode compl (XPT t)) --operation mode
st = initState d rw w s om gc fs hs conf numlock
st' <- io $ execStateT runXP st
releaseXMF fs
io $ freeGC d gc
if successful st'
then do
let prune = take (historySize conf)
if successful st' then do
completions <- liftIO $ do getCompletionFunction st' (commandToComplete (currentXPMode st') (command st')) `catch` \(SomeException _) -> return []
let
prune = take (historySize conf)
io $ writeHistory $ M.insertWith
(\xs ys -> prune . historyFilter conf $ xs ++ ys)
(showXPrompt t)
@ -301,7 +359,13 @@ mkXPromptWithReturn t conf compl action = do
-- we need to apply historyFilter before as well, since
-- otherwise the filter would not be applied if
-- there is no history
Just <$> action (command st')
--When alwaysHighlight is True, autocompletion is handled with indexes.
--When it is false, it is handled depending on the prompt buffer's value
let selectedCompletion = case alwaysHighlight (config st') of
False -> command st'
True -> highlightedItem st' completions
--Just <$> action selectedCompletion
Just <$> action selectedCompletion
else return Nothing
-- | Creates a prompt given:
@ -318,6 +382,62 @@ mkXPromptWithReturn t conf compl action = do
mkXPrompt :: XPrompt p => p -> XPConfig -> ComplFunction -> (String -> X ()) -> X ()
mkXPrompt t conf compl action = mkXPromptWithReturn t conf compl action >> return ()
-- | Creates a prompt with multiple modes given:
--
-- * A non-empty list of modes
-- * A prompt configuration
--
-- The created prompt allows to switch between modes with `changeModeKey` in `conf`. The modes are
-- instances of XPrompt. See XMonad.Actions.Launcher for more details
--
-- The argument supplied to the action to execute is always the current highlighted item,
-- that means that this prompt overrides the value `alwaysHighlight` for its configuration to True.
mkXPromptWithModes :: [XPType] -> XPConfig -> X ()
mkXPromptWithModes modes conf = do
XConf { display = d, theRoot = rw } <- ask
s <- gets $ screenRect . W.screenDetail . W.current . windowset
hist <- io readHistory
w <- io $ createWin d rw conf s
io $ selectInput d w $ exposureMask .|. keyPressMask
gc <- io $ createGC d w
io $ setGraphicsExposures d gc False
fs <- initXMF (font conf)
numlock <- gets $ X.numberlockMask
let
defaultMode = head modes
hs = fromMaybe [] $ M.lookup (showXPrompt defaultMode) hist
modeStack = W.Stack{ W.focus = defaultMode --current mode
, W.up = []
, W.down = tail modes --other modes
}
st = initState d rw w s (XPMultipleModes modeStack) gc fs hs conf { alwaysHighlight = True} numlock
st' <- io $ execStateT runXP st
releaseXMF fs
io $ freeGC d gc
if successful st' then do
completions <- liftIO $ do getCompletionFunction st' (commandToComplete (currentXPMode st') (command st')) `catch` \(SomeException _) -> return []
let
prune = take (historySize conf)
-- insert into history the buffers value
io $ writeHistory $ M.insertWith
(\xs ys -> prune . historyFilter conf $ xs ++ ys)
(showXPrompt defaultMode)
(prune $ historyFilter conf [command st'])
hist
case operationMode st' of
XPMultipleModes ms -> let
action = modeAction $ W.focus ms
in action (command st') (highlightedItem st' completions)
_ -> return () --This should never happen, we are creating a prompt with multiple modes, so its operationMode should have been constructed with XPMultipleMode
else
return ()
runXP :: XP ()
runXP = do
(d,w) <- gets (dpy &&& win)
@ -359,10 +479,15 @@ cleanMask msk = do
handle :: KeyStroke -> Event -> XP ()
handle ks@(sym,_) e@(KeyEvent {ev_event_type = t, ev_state = m}) = do
complKey <- gets $ completionKey . config
chgModeKey <- gets $ changeModeKey . config
c <- getCompletions
when (length c > 1) $ modify (\s -> s { showComplWin = True })
if complKey == sym
then completionHandle c ks e
else if (sym == chgModeKey) then
do
modify setNextMode
updateWindows
else when (t == keyPress) $ keyPressHandle m ks
handle _ (ExposeEvent {ev_window = w}) = do
st <- get
@ -373,15 +498,18 @@ handle _ _ = return ()
completionHandle :: [String] -> KeyStroke -> Event -> XP ()
completionHandle c ks@(sym,_) (KeyEvent { ev_event_type = t, ev_state = m }) = do
complKey <- gets $ completionKey . config
alwaysHlight <- gets $ alwaysHighlight . config
case () of
() | t == keyPress && sym == complKey ->
do
st <- get
let updateState l =
let new_command = nextCompletion (xptype st) (command st) l
let updateState l = case alwaysHlight of
--We will modify the next command (buffer's value), to be able to highlight the autocompletion (nextCompletion and commandToComplete implementation dependent)
False -> let new_command = nextCompletion (currentXPMode st) (command st) l
in modify $ \s -> setCommand new_command $ s { offset = length new_command }
updateWins l = redrawWindows l >>
eventLoop (completionHandle l)
--TODO: Scroll or paginate results
True -> modify $ \s -> s { complIndex = nextComplIndex st (length l)}
updateWins l = redrawWindows l >> eventLoop (completionHandle l)
case c of
[] -> updateWindows >> eventLoop handle
[x] -> updateState [x] >> getCompletions >>= updateWins
@ -391,6 +519,24 @@ completionHandle c ks@(sym,_) (KeyEvent { ev_event_type = t, ev_state = m }) = d
-- some other event: go back to main loop
completionHandle _ k e = handle k e
--Receives an state of the prompt, the size of the autocompletion list and returns the column,row
--which should be highlighted next
nextComplIndex :: XPState -> Int -> (Int,Int)
nextComplIndex st nitems = case complWinDim st of
Nothing -> (0,0) --no window dims (just destroyed or not created)
Just winDim -> let
(_,_,_,_,xx,yy) = winDim
(ncols,nrows) = (nitems `div` length yy + if (nitems `mod` length yy > 0) then 1 else 0, length yy)
(currentcol,currentrow) = complIndex st
in if (currentcol + 1 >= ncols) then --hlight is in the last column
if (currentrow + 1 < (nitems `mod` nrows) ) then --hlight is still not at the last row
(currentcol, currentrow + 1)
else
(0,0)
else if(currentrow + 1 < nrows) then --hlight not at the last row
(currentcol, currentrow + 1)
else
(currentcol + 1, 0)
tryAutoComplete :: XP Bool
tryAutoComplete = do
@ -403,7 +549,7 @@ tryAutoComplete = do
Nothing -> return False
where runCompleted cmd delay = do
st <- get
let new_command = nextCompletion (xptype st) (command st) [cmd]
let new_command = nextCompletion (currentXPMode st) (command st) [cmd]
modify $ setCommand "autocompleting..."
updateWindows
io $ threadDelay delay
@ -582,10 +728,18 @@ startOfLine =
flushString :: XP ()
flushString = modify $ \s -> setCommand "" $ s { offset = 0}
--reset index if config has `alwaysHighlight`. The inserted char could imply fewer autocompletions.
--If the current index was column 2, row 1 and now there are only 4 autocompletion rows with 1 column, what should we highlight? Set it to the first and start navigation again
resetComplIndex :: XPState -> XPState
resetComplIndex st = if (alwaysHighlight $ config st) then st { complIndex = (0,0) } else st
-- | Insert a character at the cursor position
insertString :: String -> XP ()
insertString str =
modify $ \s -> setCommand (c (command s) (offset s)) $ s { offset = o (offset s)}
modify $ \s -> let
cmd = (c (command s) (offset s))
st = resetComplIndex $ s { offset = o (offset s)}
in setCommand cmd st
where o oo = oo + length str
c oc oo | oo >= length oc = oc ++ str
| otherwise = f ++ str ++ ss
@ -691,7 +845,7 @@ printPrompt :: Drawable -> XP ()
printPrompt drw = do
st <- get
let (gc,(c,(d,fs))) = (gcon &&& config &&& dpy &&& fontS) st
(prt,(com,off)) = (show . xptype &&& command &&& offset) st
(prt,(com,off)) = (show . currentXPMode &&& command &&& offset) st
str = prt ++ com
-- break the string in 3 parts: till the cursor, the cursor and the rest
(f,p,ss) = if off >= length com
@ -713,12 +867,17 @@ printPrompt drw = do
-- reverse the colors and print the rest of the string
draw (fgColor c) (bgColor c) (x + fromIntegral (fsl + psl)) y ss
-- Completions
-- get the current completion function depending on the active mode
getCompletionFunction :: XPState -> ComplFunction
getCompletionFunction st = case operationMode st of
XPSingleMode compl _ -> compl
XPMultipleModes modes -> completionFunction $ W.focus modes
-- Completions
getCompletions :: XP [String]
getCompletions = do
s <- get
io $ completionFunction s (commandToComplete (xptype s) (command s))
io $ getCompletionFunction s (commandToComplete (currentXPMode s) (command s))
`catch` \(SomeException _) -> return []
setComplWin :: Window -> ComplWindowDim -> XP ()
@ -793,7 +952,9 @@ drawComplWin w compl = do
(defaultDepthOfScreen scr)
io $ fillDrawable d p gc border bgcolor (fi bw) wh ht
let ac = splitInSubListsAt (length yy) (take (length xx * length yy) compl)
printComplList d p gc (fgColor c) (bgColor c) xx yy ac
--lift $ spawn $ "xmessage " ++ " ac: " ++ show ac ++ " xx: " ++ show xx ++ " length xx: " ++ show (length xx) ++ " yy: " ++ show (length yy)
io $ copyArea d p w gc 0 0 wh ht 0 0
io $ freePixmap d p
@ -814,16 +975,33 @@ redrawComplWin compl = do
Nothing -> recreate
else destroyComplWin
-- given a string and a matrix of strings, find the column and row indexes in which the string appears.
-- if the string is not in the matrix, the function returns (0,0)
findComplIndex :: String -> [[String]] -> (Int,Int)
findComplIndex x xss = let
colIndex = fromMaybe 0 $ findIndex (\cols -> x `elem` cols) xss
rowIndex = fromMaybe 0 $ elemIndex x $ (!!) xss colIndex
in (colIndex,rowIndex)
printComplList :: Display -> Drawable -> GC -> String -> String
-> [Position] -> [Position] -> [[String]] -> XP ()
printComplList d drw gc fc bc xs ys sss =
zipWithM_ (\x ss ->
zipWithM_ (\y s -> do
zipWithM_ (\y item -> do
st <- get
let (f,b) = if completionToCommand (xptype st) s == commandToComplete (xptype st) (command st)
alwaysHlight <- gets $ alwaysHighlight . config
let (f,b) = case alwaysHlight of
True -> --find the column, row in which this item is and decide if we should highlight
let
colIndex = fromMaybe 0 $ findIndex (\cols -> item `elem` cols) sss
rowIndex = fromMaybe 0 $ elemIndex item $ (!!) sss colIndex
in
if ((complIndex st) == (colIndex,rowIndex)) then (fgHLight $ config st,bgHLight $ config st)
else (fc,bc)
False -> if completionToCommand (currentXPMode st) item == commandToComplete (currentXPMode st) (command st)
then (fgHLight $ config st,bgHLight $ config st)
else (fc,bc)
printStringXMF d drw (fontS st) gc f b x y s)
printStringXMF d drw (fontS st) gc f b x y item)
ys ss) xs sss
-- History

View File

@ -102,6 +102,7 @@ library
XMonad.Actions.FocusNth
XMonad.Actions.GridSelect
XMonad.Actions.GroupNavigation
XMonad.Actions.Launcher
XMonad.Actions.MessageFeedback
XMonad.Actions.MouseGestures
XMonad.Actions.MouseResize