我将XMonad与xmobar结合使用,并且我遇到了xmobar上显示的工作区没有按数字排序的问题。因为工作区ID最终是字符串,所以它们按字典顺序进行排序。因此,假设我有12个工作空间,它们将被排序为1 10 11 12 3 4 5 6 7 8 9
,而不是1 2 3 4 5 6 7 8 9 10 11 12
。我认为marshallPP
是罪魁祸首,因为在引入独立屏幕之前,工作区在没有ppSort
的情况下可以正确显示。我知道mkWsSort
可以从比较函数中创建排序函数,但是,我不确定该如何编写比较函数。这是我的配置:
import System.IO
import XMonad
import XMonad.Hooks.DynamicLog
import XMonad.Hooks.ManageDocks
import XMonad.Hooks.ServerMode
import XMonad.Hooks.SetWMName
import XMonad.Layout.IndependentScreens
import XMonad.Layout.Gaps
import XMonad.Layout.Spacing
import XMonad.Util.EZConfig (additionalKeysP)
import XMonad.Util.Run (spawnPipe)
import Data.List
import Data.Function
import qualified XMonad.StackSet as W
import qualified Data.Map as M
import XMonad.Util.WorkspaceCompare
myLayout = gaps [(U, 10), (R, 10), (L, 10), (D, 10)] $ spacingRaw True (Border 0 10 10 10) True (Border 10 10 10 10) True $
layoutHook def
myWorkspaces =
[ (xK_1, "1")
, (xK_2, "2")
, (xK_3, "3")
, (xK_4, "4")
, (xK_5, "5")
, (xK_6, "6")
, (xK_7, "7")
, (xK_8, "8")
, (xK_9, "9")
, (xK_0, "10")
, (xK_minus, "11")
, (xK_equal, "12")
]
clickable' :: WorkspaceId -> String
clickable' w = xmobarAction ("xmonadctl view\"" ++ w ++ "\"") "1" w
myKeys conf@(XConfig {XMonad.modMask = modMask}) = M.fromList $
[ ((modMask, key), windows $ onCurrentScreen W.greedyView ws)
| (key, ws) <- myWorkspaces
]
++
[ ((modMask .|. shiftMask, key), windows $ onCurrentScreen W.shift ws)
| (key, ws) <- myWorkspaces
]
++
[
-- Spawn the terminal
((modMask .|. shiftMask, xK_Return), spawn $ XMonad.terminal conf)
-- Spawn dmenu
, ((modMask, xK_p), spawn "dmenu_run")
-- Close focused window
, ((modMask .|. shiftMask, xK_c), kill)
-- Rotate through the available layout algorithms
, ((modMask, xK_space ), sendMessage NextLayout)
-- Reset the layouts on the current workspace to default
, ((modMask .|. shiftMask, xK_space), setLayout $ XMonad.layoutHook conf)
-- Resize viewed windows to the correct size
, ((modMask, xK_n), refresh)
-- Move focus to the next window
, ((modMask, xK_Tab), windows W.focusDown)
-- Move focus to the next window
, ((modMask, xK_j), windows W.focusDown)
-- Move focus to the previous window
, ((modMask, xK_k), windows W.focusUp)
-- Move focus to the master window
, ((modMask, xK_m), windows W.focusMaster)
-- Swap the focused window and the master window
, ((modMask, xK_Return), windows W.swapMaster)
-- Swap the focused window with the next window
, ((modMask .|. shiftMask, xK_j), windows W.swapDown)
-- Swap the focused window with the previous window
, ((modMask .|. shiftMask, xK_k), windows W.swapUp)
-- Shrink the master area
, ((modMask, xK_h), sendMessage Shrink)
-- Expand the master area
, ((modMask, xK_l), sendMessage Expand)
-- Push window back into tiling
, ((modMask, xK_t), withFocused $ windows . W.sink)
-- Increment the number of windows in the master area
, ((modMask, xK_comma), sendMessage (IncMasterN 1))
-- Deincrement the number of windows in the master area
, ((modMask, xK_period), sendMessage (IncMasterN (-1)))
-- toggle the status bar gap
, ((modMask, xK_b), sendMessage ToggleStruts)
-- Restart xmonad
, ((modMask, xK_q), broadcastMessage ReleaseResources >> restart "xmonad" True)
]
myAdditionalKeysP =
[
("M-<F2>", spawn "thunar")
, ("M-<F3>", spawn "firefox")
, ("M-<F4>", spawn "code")
, ("M-<F5>", spawn "thunderbird")
, ("M-<Escape>", spawn "xfce4-appfinder")
, ("M4-<Print>", spawn "xfce4-screenshooter")
, ("M4-<KP_Add>", spawn "amixer -D pulse sset Master 5%+")
, ("M4-<KP_Subtract>", spawn "amixer -D pulse sset Master 5%-")
, ("M-C-p", spawn "passmenu")
, ("M-C-c", spawn "clipmenu")
, ("M-C-m", spawn "mailwatch_restart")
, ("M-C-x", spawn "xfce4-panel -r")
, ("M-C-<Left>", spawn "playerctl previous")
, ("M-C-<Right>", spawn "playerctl next")
, ("M-C-<Space>", spawn "playerctl play-pause")
]
main = do
xmprocs <- mapM (i -> spawnPipe $ "xmobar ~/.config/xmobar/xmobarrc-" ++ show i ++ " -x" ++ show i) [0..1]
xmonad $ docks def
{
workspaces = withScreens 2 (map show [1..12])
, keys = myKeys
, borderWidth = 2
, focusedBorderColor = "#226fa5"
, normalBorderColor = "#191919"
, handleEventHook = serverModeEventHookCmd
<+> serverModeEventHook
<+> serverModeEventHookF "XMONAD_PRINT" (io . putStrLn)
, layoutHook = avoidStruts myLayout
, logHook = mapM_ dynamicLogWithPP $ zipWith pp xmprocs [0..1]
, startupHook = setWMName "LG3D"
, manageHook = manageDocks
} `additionalKeysP` myAdditionalKeysP
pp h s = marshallPP s def
{ ppOutput = hPutStrLn h
, ppCurrent = xmobarColor "blue" "" . wrap "[" "]"
, ppHiddenNoWindows = xmobarColor "grey" "" . clickable'
, ppVisible = wrap "(" ")"
, ppUrgent = xmobarColor "red" "yellow"
, ppOrder = (ws:_:_:_) -> [pad ws]
, ppHidden = clickable'
}
我尝试过硬编码一个有序列表,但没有成功。我还尝试使用以下函数对传递给workspaces
的内容进行排序:
sortNumeric = sortBy (compare `on` (read :: String -> Int))
然而,这并不奏效。
我该如何克服这个问题?
您可以看到mkWsSort
的类型签名是X WorkspaceCompare -> X WorkspaceSort
。ppSort
需要X WorkspaceSort
,所以您只需要提供一个X WorkspaceCompare
。WorkspaceCompare
是WorkspaceId -> WorkspaceId -> Ordering
的别名,而WorkspaceId
是String
的别名。所以基本上,这只是一个冗长的路径,说你需要一个字符串比较函数。您可以通过尝试先将字符串读取到Ints中,然后比较两者来制作一个比较字符串的方法:
import Text.Read
import Data.Ord
compareNumbers :: String -> String -> Ordering
compareNumbers a b =
case (readMaybe a :: Maybe Int, readMaybe b :: Maybe Int) of
-- if they're both valid numbers then compare them
(Just x, Just y) -> compare x y
-- push numbers to the front of strings
(Just _, Nothing) -> LT
(Nothing, Just _) -> GT
-- strings get normal string comparison
(Nothing, Nothing) -> compare a b
如果你所有的工作空间都是数字,那么compareNumbers
可以减少到compareNumbers = comparing (read :: String -> Int)
,或者如果你想把非数字推到前面,那么它可以减少到comparing (readMaybe :: String -> Maybe Int)
。
然后,用return
将其封装在X
monad中,并将其传递给mkWsSort
,然后将ppSort
设置为:
-- ...
, ppSort = mkWsSort $ return compareNumbers
-- ...