mirror of
https://github.com/xmonad/xmonad-contrib.git
synced 2025-08-12 02:35:59 -07:00
Merge pull request #287 from mgsloan/bracket-prompt-resources
Use bracket pattern in XMonad.Prompt
This commit is contained in:
@@ -35,6 +35,10 @@
|
|||||||
Added `sorter` to `XPConfig` used to sort the possible completions by how
|
Added `sorter` to `XPConfig` used to sort the possible completions by how
|
||||||
well they match the search string (example: `XMonad.Prompt.FuzzyMatch`).
|
well they match the search string (example: `XMonad.Prompt.FuzzyMatch`).
|
||||||
|
|
||||||
|
Fixes a potential bug where an error during prompt execution would
|
||||||
|
leave the window open and keep the keyboard grabbed. See issue
|
||||||
|
[#180](https://github.com/xmonad/xmonad-contrib/issues/180).
|
||||||
|
|
||||||
Fixes [issue #217](https://github.com/xmonad/xmonad-contrib/issues/217), where
|
Fixes [issue #217](https://github.com/xmonad/xmonad-contrib/issues/217), where
|
||||||
using tab to wrap around the completion rows would fail when maxComplRows is
|
using tab to wrap around the completion rows would fail when maxComplRows is
|
||||||
restricting the number of rows of output.
|
restricting the number of rows of output.
|
||||||
|
153
XMonad/Prompt.hs
153
XMonad/Prompt.hs
@@ -111,6 +111,7 @@ import qualified Data.Map as M
|
|||||||
import Data.Maybe (fromMaybe)
|
import Data.Maybe (fromMaybe)
|
||||||
import Data.Set (fromList, toList)
|
import Data.Set (fromList, toList)
|
||||||
import System.IO
|
import System.IO
|
||||||
|
import System.IO.Unsafe (unsafePerformIO)
|
||||||
import System.Posix.Files
|
import System.Posix.Files
|
||||||
|
|
||||||
-- $usage
|
-- $usage
|
||||||
@@ -131,6 +132,12 @@ data XPState =
|
|||||||
, complWin :: Maybe Window
|
, complWin :: Maybe Window
|
||||||
, complWinDim :: Maybe ComplWindowDim
|
, complWinDim :: Maybe ComplWindowDim
|
||||||
, complIndex :: !(Int,Int)
|
, complIndex :: !(Int,Int)
|
||||||
|
-- | This IORef should always have the same value as
|
||||||
|
-- complWin. Its purpose is to enable removal of the
|
||||||
|
-- completion window if an exception occurs, since the most
|
||||||
|
-- recent value of complWin is not available when handling
|
||||||
|
-- exceptions.
|
||||||
|
, complWinRef :: IORef (Maybe Window)
|
||||||
, showComplWin :: Bool
|
, showComplWin :: Bool
|
||||||
, operationMode :: XPOperationMode
|
, operationMode :: XPOperationMode
|
||||||
, highlightedCompl :: Maybe String
|
, highlightedCompl :: Maybe String
|
||||||
@@ -339,6 +346,7 @@ initState d rw w s opMode gc fonts h c nm =
|
|||||||
, screen = s
|
, screen = s
|
||||||
, complWin = Nothing
|
, complWin = Nothing
|
||||||
, complWinDim = Nothing
|
, complWinDim = Nothing
|
||||||
|
, complWinRef = unsafePerformIO (newIORef Nothing)
|
||||||
, showComplWin = not (showCompletionOnTab c)
|
, showComplWin = not (showCompletionOnTab c)
|
||||||
, operationMode = opMode
|
, operationMode = opMode
|
||||||
, highlightedCompl = Nothing
|
, highlightedCompl = Nothing
|
||||||
@@ -471,38 +479,16 @@ getCurrentCompletions = gets currentCompletions
|
|||||||
-- module.
|
-- module.
|
||||||
mkXPromptWithReturn :: XPrompt p => p -> XPConfig -> ComplFunction -> (String -> X a) -> X (Maybe a)
|
mkXPromptWithReturn :: XPrompt p => p -> XPConfig -> ComplFunction -> (String -> X a) -> X (Maybe a)
|
||||||
mkXPromptWithReturn t conf compl action = do
|
mkXPromptWithReturn t conf compl action = do
|
||||||
XConf { display = d, theRoot = rw } <- ask
|
st' <- mkXPromptImplementation (showXPrompt t) conf (XPSingleMode compl (XPT t))
|
||||||
s <- gets $ screenRect . W.screenDetail . W.current . windowset
|
if successful st'
|
||||||
hist <- io readHistory
|
then do
|
||||||
w <- io $ createWin d rw conf s
|
let selectedCompletion =
|
||||||
io $ selectInput d w $ exposureMask .|. keyPressMask
|
case alwaysHighlight (config st') of
|
||||||
gc <- io $ createGC d w
|
-- When alwaysHighlight is True, autocompletion is
|
||||||
io $ setGraphicsExposures d gc False
|
-- handled with indexes.
|
||||||
fs <- initXMF (font conf)
|
|
||||||
numlock <- gets $ X.numberlockMask
|
|
||||||
let hs = fromMaybe [] $ M.lookup (showXPrompt t) hist
|
|
||||||
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)
|
|
||||||
|
|
||||||
io $ writeHistory $ M.insertWith
|
|
||||||
(\xs ys -> prune . historyFilter conf $ xs ++ ys)
|
|
||||||
(showXPrompt t)
|
|
||||||
(prune $ historyFilter conf [command st'])
|
|
||||||
hist
|
|
||||||
-- we need to apply historyFilter before as well, since
|
|
||||||
-- otherwise the filter would not be applied if
|
|
||||||
-- there is no history
|
|
||||||
--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'
|
False -> command st'
|
||||||
|
-- When it is false, it is handled depending on the
|
||||||
|
-- prompt buffer's value.
|
||||||
True -> fromMaybe (command st') $ highlightedCompl st'
|
True -> fromMaybe (command st') $ highlightedCompl st'
|
||||||
Just <$> action selectedCompletion
|
Just <$> action selectedCompletion
|
||||||
else return Nothing
|
else return Nothing
|
||||||
@@ -532,47 +518,58 @@ mkXPrompt t conf compl action = mkXPromptWithReturn t conf compl action >> retur
|
|||||||
-- that means that this prompt overrides the value `alwaysHighlight` for its configuration to True.
|
-- that means that this prompt overrides the value `alwaysHighlight` for its configuration to True.
|
||||||
mkXPromptWithModes :: [XPType] -> XPConfig -> X ()
|
mkXPromptWithModes :: [XPType] -> XPConfig -> X ()
|
||||||
mkXPromptWithModes modes conf = do
|
mkXPromptWithModes modes conf = do
|
||||||
XConf { display = d, theRoot = rw } <- ask
|
let defaultMode = head modes
|
||||||
s <- gets $ screenRect . W.screenDetail . W.current . windowset
|
modeStack = W.Stack { W.focus = defaultMode -- Current mode
|
||||||
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.up = []
|
||||||
, W.down = tail modes --other modes
|
, W.down = tail modes -- Other modes
|
||||||
}
|
}
|
||||||
st = initState d rw w s (XPMultipleModes modeStack) gc fs hs conf { alwaysHighlight = True} numlock
|
om = XPMultipleModes modeStack
|
||||||
st' <- io $ execStateT runXP st
|
st' <- mkXPromptImplementation (showXPrompt defaultMode) conf { alwaysHighlight = True } om
|
||||||
|
if successful st'
|
||||||
releaseXMF fs
|
then do
|
||||||
io $ freeGC d gc
|
|
||||||
|
|
||||||
if successful st' then do
|
|
||||||
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
|
case operationMode st' of
|
||||||
XPMultipleModes ms -> let
|
XPMultipleModes ms -> let
|
||||||
action = modeAction $ W.focus ms
|
action = modeAction $ W.focus ms
|
||||||
in action (command st') $ (fromMaybe "" $ highlightedCompl st')
|
in action (command st') $ (fromMaybe "" $ highlightedCompl st')
|
||||||
_ -> error "The impossible occurred: This prompt runs with multiple modes but they could not be found." --we are creating a prompt with multiple modes, so its operationMode should have been constructed with XPMultipleMode
|
_ -> error "The impossible occurred: This prompt runs with multiple modes but they could not be found." --we are creating a prompt with multiple modes, so its operationMode should have been constructed with XPMultipleMode
|
||||||
else
|
else return ()
|
||||||
return ()
|
|
||||||
|
|
||||||
|
-- Internal function used to implement 'mkXPromptWithReturn' and
|
||||||
|
-- 'mkXPromptWithModes'.
|
||||||
|
mkXPromptImplementation :: String -> XPConfig -> XPOperationMode -> X XPState
|
||||||
|
mkXPromptImplementation historyKey conf om = do
|
||||||
|
XConf { display = d, theRoot = rw } <- ask
|
||||||
|
s <- gets $ screenRect . W.screenDetail . W.current . windowset
|
||||||
|
numlock <- gets X.numberlockMask
|
||||||
|
hist <- io readHistory
|
||||||
|
fs <- initXMF (font conf)
|
||||||
|
st' <- io $
|
||||||
|
bracket
|
||||||
|
(createWin d rw conf s)
|
||||||
|
(destroyWindow d)
|
||||||
|
(\w ->
|
||||||
|
bracket
|
||||||
|
(createGC d w)
|
||||||
|
(freeGC d)
|
||||||
|
(\gc -> do
|
||||||
|
selectInput d w $ exposureMask .|. keyPressMask
|
||||||
|
setGraphicsExposures d gc False
|
||||||
|
let hs = fromMaybe [] $ M.lookup historyKey hist
|
||||||
|
st = initState d rw w s om gc fs hs conf numlock
|
||||||
|
runXP st))
|
||||||
|
releaseXMF fs
|
||||||
|
when (successful st') $ do
|
||||||
|
let prune = take (historySize conf)
|
||||||
|
io $ writeHistory $
|
||||||
|
M.insertWith
|
||||||
|
(\xs ys -> prune . historyFilter conf $ xs ++ ys)
|
||||||
|
historyKey
|
||||||
|
-- We need to apply historyFilter before as well, since
|
||||||
|
-- otherwise the filter would not be applied if there is no
|
||||||
|
-- history
|
||||||
|
(prune $ historyFilter conf [command st'])
|
||||||
|
hist
|
||||||
|
return st'
|
||||||
|
|
||||||
-- | Removes numlock and capslock from a keymask.
|
-- | Removes numlock and capslock from a keymask.
|
||||||
-- Duplicate of cleanMask from core, but in the
|
-- Duplicate of cleanMask from core, but in the
|
||||||
@@ -591,17 +588,21 @@ utf8Decode str
|
|||||||
| isUTF8Encoded str = decodeString str
|
| isUTF8Encoded str = decodeString str
|
||||||
| otherwise = str
|
| otherwise = str
|
||||||
|
|
||||||
runXP :: XP ()
|
runXP :: XPState -> IO XPState
|
||||||
runXP = do
|
runXP st = do
|
||||||
(d,w) <- gets (dpy &&& win)
|
let d = dpy st
|
||||||
status <- io $ grabKeyboard d w True grabModeAsync grabModeAsync currentTime
|
w = win st
|
||||||
|
st' <- bracket
|
||||||
|
(grabKeyboard d w True grabModeAsync grabModeAsync currentTime)
|
||||||
|
(\_ -> ungrabKeyboard d currentTime)
|
||||||
|
(\status ->
|
||||||
|
(flip execStateT st $ do
|
||||||
when (status == grabSuccess) $ do
|
when (status == grabSuccess) $ do
|
||||||
updateWindows
|
updateWindows
|
||||||
eventLoop handleMain evDefaultStop
|
eventLoop handleMain evDefaultStop)
|
||||||
io $ ungrabKeyboard d currentTime
|
`finally` (mapM_ (destroyWindow d) =<< readIORef (complWinRef st))
|
||||||
io $ destroyWindow d w
|
`finally` sync d False)
|
||||||
destroyComplWin
|
return st'
|
||||||
io $ sync d False
|
|
||||||
|
|
||||||
type KeyStroke = (KeySym, String)
|
type KeyStroke = (KeySym, String)
|
||||||
|
|
||||||
@@ -1409,15 +1410,19 @@ getCompletions = do
|
|||||||
io $ (srt q <$> compl q) `E.catch` \(SomeException _) -> return []
|
io $ (srt q <$> compl q) `E.catch` \(SomeException _) -> return []
|
||||||
|
|
||||||
setComplWin :: Window -> ComplWindowDim -> XP ()
|
setComplWin :: Window -> ComplWindowDim -> XP ()
|
||||||
setComplWin w wi =
|
setComplWin w wi = do
|
||||||
|
wr <- gets complWinRef
|
||||||
|
io $ writeIORef wr (Just w)
|
||||||
modify (\s -> s { complWin = Just w, complWinDim = Just wi })
|
modify (\s -> s { complWin = Just w, complWinDim = Just wi })
|
||||||
|
|
||||||
destroyComplWin :: XP ()
|
destroyComplWin :: XP ()
|
||||||
destroyComplWin = do
|
destroyComplWin = do
|
||||||
d <- gets dpy
|
d <- gets dpy
|
||||||
cw <- gets complWin
|
cw <- gets complWin
|
||||||
|
wr <- gets complWinRef
|
||||||
case cw of
|
case cw of
|
||||||
Just w -> do io $ destroyWindow d w
|
Just w -> do io $ destroyWindow d w
|
||||||
|
io $ writeIORef wr Nothing
|
||||||
modify (\s -> s { complWin = Nothing, complWinDim = Nothing })
|
modify (\s -> s { complWin = Nothing, complWinDim = Nothing })
|
||||||
Nothing -> return ()
|
Nothing -> return ()
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user