Closed sagittarius-a closed 1 year ago
A sequence of events:
exitMode
.logMode
produces Nothing
.ppOrder
takes shrinks to length 3.ppOrder
doesn't cover the case; pattern match failure kills dynamicLogString
, dynamicLogWithPP
, and hence the logHook
.logHook
kills refreshMode
, which kills setMode
and exitMode
.In short exitMode
becomes a self-destruct button. XMonad recovers from bad keybindings like this by pretending they never happened.
The solution is to write ppOrder
as a total function:
{ ppOrder = \case { [ws, l, title, mode] -> [ws, l, mode, title]; xs -> xs }
We should probably wrap ppOrder
in userCodeDef
so it doesn't cause as much carnage on failure.
The actual error is in pure code, so it's a pain to catch without letting it kill all the code that eventually evaluates it. Though we already depend on deepseq, so I guess something like the below (untested) should work.
let pps = [ws, ppLayout pp ld, ppTitle pp $ ppTitleSanitize pp wt]
++ catMaybes extras
sepBy (ppSep pp) <$> userCodeDef pps (io . evaluate . force $ ppOrder pp pps)
Frankly I'd rather just change whatever documentation suggests writing a partial function there and call it user error from then on, but that won't fix all the broken configs in the wild.
I'd agree in the ideal case, but when it allows something like this bug report it seems like something we should try to deal with. And it's going to get forced shortly anyway, so I see no problem with deepseq there.
Actually, I now wonder if the userCode
belongs on dynamicLogPP
or StatusBar equivalent, since nothing but convention stops this from happening in any other of the PP functions. That leaves out dynamicLogString
, but I think anyone who knows enough to use that directly knows to avoid partial functions or pay the price.
I grepped for dynamicLogString
in contrib and it seemed to be used in several places, but I don't know the details of these modules, so I'll leave it up to people who do.
A sequence of events:
1. You run `exitMode`. 2. There's no longer an active mode, so `logMode` produces `Nothing`. 3. Hence the list that `ppOrder` takes shrinks to length 3. 4. `ppOrder` doesn't cover the case; pattern match failure kills `dynamicLogString`, `dynamicLogWithPP`, and hence the `logHook`. 5. Flowing on, the `logHook` kills `refreshMode`, which kills `setMode` and `exitMode`.
In short
exitMode
becomes a self-destruct button. XMonad recovers from bad keybindings like this by pretending they never happened.The solution is to write
ppOrder
as a total function:{ ppOrder = \case { [ws, l, title, mode] -> [ws, l, mode, title]; xs -> xs }
Well that's a fast answer with a solution to my problem.
Thank you very much :)
I grepped for
dynamicLogString
in contrib and it seemed to be used in several places, but I don't know the details of these modules, so I'll leave it up to people who do.
Looks to me like what I'd expect. It should be easy enough, since it's in X String
, to use userCodeDef (pure "_|_")
in front or `catchX` pure "_|_"
at the end. Except I guess it needs to force the string to make sure any exception occurs.
PR #802 opened.
Problem Description
When I use the
XMonad.Hooks.Modal.logMode
in theppExtras
field of xmobar pretty-printer, it works flawlessly.However, if I use
ppOrder
:But:
The only way to solve the issue is to restart Xmonad. It can be very tedious if there is no way to do it without using any Xmonad keybinding.
Steps to Reproduce
M-g
to enter the example modeEscape
to exit the example modeNo Xmonad keybinding should be working at this point.
Configuration File
Checklist
[X] I've read CONTRIBUTING.md
I tested my configuration
xmonad
commit391c0fc
xmonad-contrib
commit29f0e032