How to programmatically get a list workspaces with their associated windows with Xmonad? - 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)

Related

How to get the index of a Window in the Stackset within 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

Where to find chunks in haskell?

I'm trying to follow this tutorial: https://wiki.haskell.org/Tutorials/Programming_Haskell/String_IO.
In the last part 7 Extension: using SMP parallelism I copy the code but it fails to compile with this error message
/home/dhilst/parallelspell.hs:13:20: error:
Variable not in scope: chunk :: Int -> [String] -> t
I searched for chunks at Hoogle and got Data.Text.Internal.Lazy, but this seems to be an internal module. And I couldn't import it anyway.
Here is the code:
import Data.Set hiding (map)
import Data.Maybe
import Data.Char
import Text.Printf
import System.IO
import System.Environment
import Control.Concurrent
import Control.Monad
main = do
(f,g,n) <- readFiles
let dict = fromList (lines f)
work = chunk n (words g)
run n dict work
run n dict work = do
chan <- newChan
errs <- getChanContents chan
mapM_ (forkIO . thread chan dict) (zip [1..n] work)
wait n errs 0
wait n xs i = when (i < n) $ case xs of
Nothing : ys -> wait n ys $! i+1
Just s : ys -> putStrLn s >> wait n ys i
thread chan dict (me,xs) = do
mapM_ spellit xs
writeChan chan Nothing
where spellit w = when (spell dict w) $
writeChan chan . Just $ printf "Thread %d: %-25s" (me::Int) w
spell d w = w `notMember` d
readFiles = do
[s,n] <- getArgs
f <- readFile "/usr/share/dict/words"
g <- readFile s
return (f,g, read n)
And here is the compilation line:
ghc -O --make -threaded parallelspell.hs
--
Update: I write my own version of chunk based on this quest:How to partition a list in Haskell?
chunk :: Int -> [a] -> [[a]]
chunk _ [] = []
chunk n xs = (take n xs) : (chunk n (drop n xs))
Still, does this means that the tutorial that I'm following is very old and out of date!? Can anyone confirm if that function already existed some day or if I'm missing something?
Regards,
Looks like the tutorial just forgot to define chunk. I encourage you to update the wiki to include a suitable definition.

Better way to get a list of the top level declarations

I have a module called EditorTest in a similarly-named file.
It imports some modules. It also has some declarations in it, as any Haskell module does.
I'd like to programmatically obtain a list of the top level available declarations within the context of that module.
What I have so far is a way to get the top level local declarations of this module only, by using hint. That's fine, and I figure I could recurse the imports (and so on into those modules, etc), collecting a list of them, then use hint to grab all the available declaration names... but if possible, I'm after an easier way to find the available declarations in a given module. I figure Haskell's API should have some way to do that.
Is there such a thing?
Self-answering because it's been a while and I spiked out a proof of concept ages ago, so I'll put it here for others, even if it is fairly messy.
So, assuming we have this file as TestModule.hs:
module TestModule (g, h) where
import Data.List as L
f = head
g = f [f]
h = L.map
Then the following code can be used to show how we can pull out the top level declarations and use them by using Hint's Language.Haskell.Interpreter module and the Language.Haskell.Exts.SrcLoc module from the haskell-src-exts package:
import Data.List
import Control.Monad
import qualified Language.Haskell.Interpreter as I
import Language.Haskell.Interpreter (Interpreter, GhcError(..), InterpreterError(..))
import qualified Language.Haskell.Exts as H
import Language.Haskell.Exts.SrcLoc
main :: IO ()
main = do r <- I.runInterpreter interpreterTest
case r of
Left err -> putStrLn $ errorString err
Right () -> return ()
errorString :: InterpreterError -> String
errorString (WontCompile es) = intercalate "\n" (header : map unbox es)
where
header = "ERROR: Won't compile:"
unbox (GhcError e) = e
errorString e = show e
p :: String -> Interpreter ()
p = I.liftIO . putStrLn
emptyLine :: Interpreter ()
emptyLine = p ""
interpreterTest :: Interpreter ()
interpreterTest =
do
p "Finding out what the module exports are."
p "To do this, we grab the text of the src/TestModule.hs"
moduleContents <- I.liftIO . readFile $ "src/TestModule.hs"
emptyLine
p "Next, we find what the import module names are, so we can load them"
p "To do that, we'll parse the contents of src/TestModule.hs as AST"
let
parseResult = H.parseModule moduleContents
parsedModuleDeclE =
case parseResult of
H.ParseOk parsed -> Right parsed
H.ParseFailed _ errorReason -> Left errorReason
(moduleDeclarations, moduleImports) =
case parsedModuleDeclE of
Left _ ->
([], [])
Right (H.Module _ _ _ _ _ importDecls decls) -> (decls, importDecls)
p $ show moduleImports
emptyLine
p "Now we can pull the module names out of the ImportDecl values:"
let
moduleNames =
do
H.ModuleName s <- fmap H.importModule moduleImports
return s
p $ show moduleNames
emptyLine
p "After this we can obtain a list of the module exports for each of these modules and join them together:"
I.loadModules ["src/TestModule.hs"]
I.setTopLevelModules ["TestModule"]
topLevelImportDecls <- fmap concat $ mapM I.getModuleExports moduleNames
-- p $ show $ do { I.Fun f <- topLevelImportDecls ; return f } -- filter for functions only
p $ show $ fmap I.name topLevelImportDecls
emptyLine
p "Then, we can get the top level declarations of the initial module and add them, too:"
-- p $ show moduleDeclarations -- AST in haskell types
let
localDeclaractions =
do
(H.PatBind _ (H.PVar (H.Ident declName)) _ _) <- moduleDeclarations
return declName
availableDeclarations =
localDeclaractions ++ fmap I.name topLevelImportDecls
p $ show localDeclaractions
emptyLine
p "Finally, we have our big list:"
p $ show availableDeclarations
emptyLine
p "Now, what about we get all of their types, just for fun?"
typesOfAll <- sequence $ fmap (\n -> fmap ((n ++ " :: ") ++) (I.typeOf n)) availableDeclarations
p $ Data.List.intercalate "\n" typesOfAll
return ()

zip AST with bool list

I have an AST representing a haskell program and a bitvector/bool list representing the presence of strictness annotations on Patterns in order.For example, 1000 represents a program with 4 Pats where the first one is a BangPat. Is there any way that I can turn on and off the annotations in the AST according to the list?
-- EDIT: further clarify what I want editBang to do
Based on user5042's answer:
Simple.hs :=
main = do
case args of
[] -> error "blah"
[!x] -> putStrLn "one"
(!x : xs) -> putStrLn "many"
And I want editBang "Simple.hs" [True, True, True, True] to produce
main = do
case args of
[] -> error "blah"
[!x] -> putStrLn "one"
(!(!x : !xs)) -> putStrLn "many"
Given that above are the only 4 places that ! can appear
As a first step, here's how to use transformBi:
import Data.Data
import Control.Monad
import Data.Generics.Uniplate.Data
import Language.Haskell.Exts
import Text.Show.Pretty (ppShow)
changeNames x = transformBi change x
where change (Ident str) = Ident ("foo_" ++ str)
change x = x
test2 = do
content <- readFile "Simple.hs"
case parseModule content of
ParseFailed _ e -> error e
ParseOk a -> do
let a' = changeNames a
putStrLn $ ppShow a'
The changeNames function finds all occurrences of a Ident s and replaces it with Ident ("foo_"++s) in the source tree.
There is a monadic version called transformBiM which allows the replacement function to be monadic which would allow you to consume elements from your list of Bools as you found bang patterns.
Here is a complete working example:
import Control.Monad
import Data.Generics.Uniplate.Data
import Language.Haskell.Exts
import Text.Show.Pretty (ppShow)
import Control.Monad.State.Strict
parseHaskell path = do
content <- readFile path
let mode = ParseMode path Haskell2010 [EnableExtension BangPatterns] False False Nothing
case parseModuleWithMode mode content of
ParseFailed _ e -> error $ path ++ ": " ++ e
ParseOk a -> return a
changeBangs bools x = runState (transformBiM go x) bools
where go pp#(PBangPat p) = do
(b:bs) <- get
put bs
if b
then return p
else return pp
go x = return x
test = do
a <- parseHaskell "Simple.hs"
putStrLn $ unlines . map ("before: " ++) . lines $ ppShow a
let a' = changeBangs [True,False] a
putStrLn $ unlines . map ("after : " ++) . lines $ ppShow a'
You might also look into using rewriteBiM.
The file Simple.hs:
main = do
case args of
[] -> error "blah"
[!x] -> putStrLn "one"
(!x : xs) -> putStrLn "many"

Read a list of integers lazily as a bytestring

I'm trying to find the sum of integers in a file. The code using the normal string is:
main = do
contents <- getContents
L.putStrLn (sumFile contents)
where sumFile = sum . map read. words
I tried to change it to use the Data.ByteString.Lazy module like this:
import Data.ByteString.Lazy as L
main = do
contents <- L.getContents
L.putStrLn (sumFile contents)
where sumFile = sum . L.map read. words
But this refused as words was returning a string. Then I tried using Data.ByteString.Char8 but it used a strict ByteString.
How can I make this function completely lazy?
I found a slightly length workaround to reading the file as a ByteString and then as a list of integers. Thanks to #melpomene
import Data.ByteString.Lazy.Char8 as L
main = do
contents <- L.getContents
print (sumFile contents)
where sumFile x = sum $ Prelude.map tups $ Prelude.map L.readInt (L.words x)
where read' = tups.(L.readInt)
tups :: (Num a) => (Maybe (a, b)) -> a
tups (Just (a,b)) = a
tups Nothing = 0

Resources