How to get the index of a Window in the Stackset within XMonad? - xmonad

How can I get the index of a Window within a StackSet?
I've haad a look through http://hackage.haskell.org/package/xmonad-0.13/docs/XMonad-StackSet.html but can't find anything relevent.

import qualified XMonad.StackSet as W
import XMonad.StackSet
import Data.List (elemIndex)
windowIndex :: Window -> StackSet i l Window s sd -> Maybe Int
windowIndex w s = elemIndex w $ allWindowsInCurrentWorkspace s
allWindowsInCurrentWorkspace :: W.StackSet i l a sid sd -> [a]
allWindowsInCurrentWorkspace ws =
W.integrate' . W.stack . W.workspace . W.current $ ws

Related

How to adjust transparency and color of a Haskell GNUPlot

this is somewhat of a two part question.
I am trying to adjust the colour of a plot, using Haskell GNUPlot:
https://hackage.haskell.org/package/gnuplot
The code I have so far is:
import qualified Graphics.Gnuplot.Frame as Frame
import qualified Graphics.Gnuplot.Frame.OptionSet as Opts
import qualified Graphics.Gnuplot.Plot.TwoDimensional as Plot2D
import qualified Graphics.Gnuplot.Graph.TwoDimensional as Graph2D
import qualified Graphics.Gnuplot.Advanced as GP
import qualified Graphics.Gnuplot.LineSpecification as LineSpec
import qualified Graphics.Gnuplot.ColorSpecification as Color
test :: [(Double, Double, Double)] -> Frame.T (Graph2D.T Double Double)
test input =
let x = [a | (a,b,c) <- input]
lower = [b | (a,b,c) <- input]
upper = [c | (a,b,c) <- input]
inputTuple = zip x (zip lower upper)
lineSpec =
Graph2D.lineSpec $
LineSpec.title "runtimes" $
LineSpec.lineWidth 2.5 $
LineSpec.lineColor (Color.rgb 0 0 1) $
LineSpec.deflt
frameOpts =
Opts.xLabel "input size" $
Opts.yLabel "runtime (ms)" $
Opts.title ("Graph from ") $
Opts.deflt
in Frame.cons frameOpts $ fmap lineSpec $
Plot2D.list Graph2D.filledStripe inputTuple
Specifically for
LineSpec.lineColor (Color.rgb 0 0 0), this is of type Color.T but for some reason, whenever I try to run this code:
GP.plotDefault test (zip3 [1,2,3] [1,2,3] [2,3,4])
, it doesn't show anything.
However, if I switch this code to
LineSpec.lineColor (Color.blue) for example, then the code returns the wanted plot. However, Color.blue is also of type Color.T, so I am not sure as to why this works, but Color.rgb 0 0 0 doesn't...
Also, is it possible to make the plot colour transparent?
I know that it is possible for Gnuplot.Simple. but I have no managed to figure out how it is possible in Gnuplot.Advanced?

RGB Terminal Colors with Haskell and Brick

I know that the Brick and the VTY hackage do not support escape sequences. VTY only supports 240 colors.
Is there any workaround to use true RGB colors and not mess up the layout?
This is an example I made, but I can't get the border right:
module BrickTest where
import Brick (simpleMain, Widget, str)
import Brick.Widgets.Border (border)
import Text.Printf (printf)
main :: IO ()
main = simpleMain $ colorWidget (255, 0, 0)
type RGB = (Int, Int, Int)
colorWidget :: RGB -> Widget ()
colorWidget (r, g, b) = border $ str (prefix ++ "a" ++ postfix)
where
prefix = printf "\ESC[38;2;%d;%d;%dm" r g b
postfix = "\ESC[0m"
output:
┌──────────────────┐
│a│
└──────────────────┘
I found a workaround. I managed to implement a function zeroWidthStr that can print any string, and Brick handles it as if it has width 0. But I can't really explain how this is working internally, and it might have some other side effects.
module BrickTest where
import Brick (Widget, raw, simpleMain, str,
(<+>))
import Brick.Widgets.Border (border)
import Data.List (intercalate)
import Data.Text.Lazy (pack)
import Graphics.Vty (defAttr)
import Graphics.Vty.Image.Internal (Image (HorizText))
import Text.Printf (printf)
main :: IO ()
main = simpleMain $ colorWidget (255, 0, 0)
type RGB = (Int, Int, Int)
colorWidget :: RGB -> Widget ()
colorWidget (r, g, b) = border $ prefix <+> str "a" <+> postfix
where
prefix = zeroWidthStr $ printf "\ESC[38;2;%d;%d;%dm" r g b
postfix = zeroWidthStr $ "\ESC[0m"
zeroWidthStr :: String -> Widget ()
-- | workaround to print any string in terminal, and hackage Brick (vty) handles it as if it has width 0
zeroWidthStr str = raw image
where
image = HorizText defAttr (pack modStr) 0 0
modStr = str ++ repeatN "\ESC\ESCa" (length str)
repeatN :: String -> Int -> String
repeatN str n = intercalate "" $ take n $ repeat str
output:

How to programmatically get a list workspaces with their associated windows with Xmonad?

I'd like to create my own workspace viewer. How can I get a list of workspace, and their corresponding window titles?
I can't seem to find any relavent function to getting these values in the documentation.
It can be done via the following (the main function being workspacesGrouped :: X [(WorkspaceId, [String])]):
import XMonad.Util.XUtils
import XMonad
import XMonad.Core
import XMonad.Config.Prime
import XMonad.Util.Font
import XMonad.StackSet as W
import FileLogger
import Control.Monad
import Data.List
import Foreign.C.String
workspacesGrouped :: X [(WorkspaceId, [String])]
workspacesGrouped = do
ws <- gets windowset
let x = map (W.workspace) (W.current ws : W.visible ws)
let y = (W.hidden ws)
sequence $ fmap (\v -> fmap ((,) $ W.tag v) (getWorkspaceWindowTitles v)) $ x ++ y
getWorkspaceWindowTitles :: Workspace i l Window -> X [String]
getWorkspaceWindowTitles w = do
withDisplay $ \d ->
(liftIO $ forM
(integrate' $ stack w)
(\z -> getWindowTitle z d)
)
getWindowTitle :: Window -> Display -> IO String
getWindowTitle w d = getTextProperty d w wM_NAME >>= (peekCString . tp_value)

How to fix Ambiguous occurrence ‘find’?

I'm new to haskell and I'm trying to run a piece of code but I'm getting this error:
"Ambiguous occurrence ‘find’
It could refer to either ‘Data.List.find’, imported from ‘Data.List’ at sequential.hs:1:1-16 (and originally defined in ‘Data.Foldable’) or ‘Main.find’, defined at sequential.hs:5:1"
import System.IO
import Data.List
find :: String -> FilePath -> IO (Maybe FilePath)
find s d = do
fs <- getDirectoryContents d -- 1
let fs' = sort $ filter (`notElem` [".",".."]) fs -- 2
if any (== s) fs' -- 3
then return (Just (d </> s))
else loop fs' -- 4
where
loop [] = return Nothing -- 5
loop (f:fs) = do
let d' = d </> f -- 6
isdir <- doesDirectoryExist d' -- 7
if isdir
then do r <- find s d' -- 8
case r of
Just _ -> return r -- 9
Nothing -> loop fs -- 10
else loop fs
You can change line 1 to import Data.List hiding (find), assuming you never intend to use the find defined there.
In your situation your options are:
Rename your own find into something else.
Import Data.List as qualified: import qualified Data.List. You can add as L to shorten code that uses stuff from Data.List.

Lazy binary get

Why is Data.Binary.Get isn't lazy as it says? Or am I doing something wrong here?
import Data.ByteString.Lazy (pack)
import Data.Binary.Get (runGet, isEmpty, getWord8)
getWords = do
empty <- isEmpty
if empty
then return []
else do
w <- getWord8
ws <- getWords
return $ w:ws
main = print $ take 10 $ runGet getWords $ pack $ repeat 1
This main function just hangs instead of printing 10 words.
The documentation you linked provides several examples. The first one needs to read all the input before it can return and looks a lot like what you have written. The second one is a left-fold and processes the input in a streaming fashion. Here's your code rewritten in this style:
module Main where
import Data.Word (Word8)
import qualified Data.ByteString.Lazy as BL
import Data.Binary.Get (runGetState, getWord8)
getWords :: BL.ByteString -> [Word8]
getWords input
| BL.null input = []
| otherwise =
let (w, rest, _) = runGetState getWord8 input 0
in w : getWords rest
main :: IO ()
main = print . take 10 . getWords . BL.pack . repeat $ 1
Testing:
*Main> :main
[1,1,1,1,1,1,1,1,1,1]

Resources