packages feed

xdg-desktop-entry 0.1.1.4 → 0.1.1.5

raw patch · 5 files changed

+124/−103 lines, 5 filessetup-changedPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

API changes (from Hackage documentation)

- System.Environment.XDG.DesktopEntry: instance GHC.Read.Read System.Environment.XDG.DesktopEntry.DesktopEntry
- System.Environment.XDG.DesktopEntry: instance GHC.Read.Read System.Environment.XDG.DesktopEntry.DesktopEntryType
- System.Environment.XDG.DesktopEntry: instance GHC.Show.Show System.Environment.XDG.DesktopEntry.DesktopEntry
- System.Environment.XDG.DesktopEntry: instance GHC.Show.Show System.Environment.XDG.DesktopEntry.DesktopEntryType
+ System.Environment.XDG.DesktopEntry: instance GHC.Internal.Read.Read System.Environment.XDG.DesktopEntry.DesktopEntry
+ System.Environment.XDG.DesktopEntry: instance GHC.Internal.Read.Read System.Environment.XDG.DesktopEntry.DesktopEntryType
+ System.Environment.XDG.DesktopEntry: instance GHC.Internal.Show.Show System.Environment.XDG.DesktopEntry.DesktopEntry
+ System.Environment.XDG.DesktopEntry: instance GHC.Internal.Show.Show System.Environment.XDG.DesktopEntry.DesktopEntryType

Files

CHANGELOG.md view
@@ -1,5 +1,9 @@ # Revision history for xdg-desktop-entry +## 0.1.1.5 -- 2026-05-13++* Clean up parser and test warnings for newer GHC releases.+ ## 0.1.1.4 -- 2026-03-15  * Relax `transformers` upper bound to support `0.6.x`, including GHC 9.12.4 RC snapshots.
Setup.hs view
@@ -1,2 +1,3 @@ import Distribution.Simple+ main = defaultMain
src/System/Environment/XDG/DesktopEntry.hs view
@@ -1,4 +1,7 @@ -----------------------------------------------------------------------------++-----------------------------------------------------------------------------+ -- | -- Module      : System.Environment.XDG.DesktopEntry -- Copyright   : 2019 Ivan Malison@@ -11,47 +14,46 @@ -- Implementation of version 1.2 of the freedesktop "Desktop Entry -- specification", see -- https://specifications.freedesktop.org/desktop-entry-spec/desktop-entry-spec-1.2.html.------------------------------------------------------------------------------- module System.Environment.XDG.DesktopEntry-  ( DesktopEntry(..)-  , deCommand-  , deComment-  , deHasCategory-  , deIcon-  , deName-  , deNoDisplay-  , deNotShowIn-  , deOnlyShowIn-  , getClassNames-  , getDirectoryEntriesDefault-  , getDirectoryEntry-  , getDirectoryEntryDefault-  , getXDGDataDirs-  , indexDesktopEntriesBy-  , indexDesktopEntriesByClassName-  , listDesktopEntries-  , readDesktopEntry-  ) where+  ( DesktopEntry (..),+    deCommand,+    deComment,+    deHasCategory,+    deIcon,+    deName,+    deNoDisplay,+    deNotShowIn,+    deOnlyShowIn,+    getClassNames,+    getDirectoryEntriesDefault,+    getDirectoryEntry,+    getDirectoryEntryDefault,+    getXDGDataDirs,+    indexDesktopEntriesBy,+    indexDesktopEntriesByClassName,+    listDesktopEntries,+    readDesktopEntry,+  )+where -import           Control.Monad-import           Control.Monad.IO.Class-import           Control.Monad.Trans.Except-import           Data.Bifunctor (bimap)-import           Data.Char-import qualified Data.Ini as Ini-import           Data.Either-import           Data.Either.Combinators+import Control.Monad+import Control.Monad.IO.Class+import Control.Monad.Trans.Except+import Data.Bifunctor (bimap)+import Data.Char+import Data.Either+import Data.Either.Combinators import qualified Data.HashMap.Strict as HM+import qualified Data.Ini as Ini+import Data.List+import Data.Maybe import qualified Data.MultiMap as MM-import           Data.List-import           Data.Maybe-import           Data.Text (pack, unpack)-import           Safe-import           System.Directory-import           System.FilePath.Posix-import           Text.Printf-import           Text.Read (readMaybe)+import Data.Text (pack, unpack)+import Safe+import System.Directory+import System.FilePath.Posix+import Text.Printf+import Text.Read (readMaybe)  data DesktopEntryType = Application | Link | Directory   deriving (Read, Show, Eq)@@ -64,30 +66,34 @@ -- | Desktop Entry. All attributes (key-value-pairs) are stored in an -- association list. data DesktopEntry = DesktopEntry-  { deType :: DesktopEntryType-  , deFilename :: FilePath -- ^ unqualified filename, e.g. "firefox.desktop"-  , deAttributes :: [(String, String)] -- ^ Key-value pairs-  } deriving (Read, Show, Eq)+  { deType :: DesktopEntryType,+    -- | unqualified filename, e.g. "firefox.desktop"+    deFilename :: FilePath,+    -- | Key-value pairs+    deAttributes :: [(String, String)]+  }+  deriving (Read, Show, Eq)  -- | Determine whether the Category attribute of a desktop entry contains a -- given value.-deHasCategory-  :: DesktopEntry-  -> String-  -> Bool+deHasCategory ::+  DesktopEntry ->+  String ->+  Bool deHasCategory de cat =   maybe False ((cat `elem`) . splitAtSemicolon) $-        lookup "Categories" (deAttributes de)+    lookup "Categories" (deAttributes de)  splitAtSemicolon :: String -> [String] splitAtSemicolon = lines . map (\c -> if c == ';' then '\n' else c)  -- | Return the proper name of the desktop entry, depending on the list of -- preferred languages.-deName-  :: [String] -- ^ Preferred languages-  -> DesktopEntry-  -> String+deName ::+  -- | Preferred languages+  [String] ->+  DesktopEntry ->+  String deName langs de = fromMaybe (deFilename de) $ deLocalisedAtt langs de "Name"  -- | Return the categories in which the entry shall be shown@@ -110,72 +116,79 @@ deNoDisplay :: DesktopEntry -> Bool deNoDisplay de = maybe False (("true" ==) . map toLower) $ deAtt "NoDisplay" de -deLocalisedAtt-  :: [String] -- ^ Preferred languages-  -> DesktopEntry-  -> String-  -> Maybe String+deLocalisedAtt ::+  -- | Preferred languages+  [String] ->+  DesktopEntry ->+  String ->+  Maybe String deLocalisedAtt langs de att =   let localeMatches =         mapMaybe (\l -> lookup (att ++ "[" ++ l ++ "]") (deAttributes de)) langs-  in case localeMatches of-       [] -> lookup att $ deAttributes de-       (x:_) -> Just x+   in case localeMatches of+        [] -> lookup att $ deAttributes de+        (x : _) -> Just x  -- | Return the proper comment of the desktop entry, depending on the list of -- preferred languages.-deComment :: [String] -- ^ Preferred languages-          -> DesktopEntry-          -> Maybe String+deComment ::+  -- | Preferred languages+  [String] ->+  DesktopEntry ->+  Maybe String deComment langs de = deLocalisedAtt langs de "Comment"  -- | Return the command that should be executed when running this desktop entry. deCommand :: DesktopEntry -> Maybe String deCommand de =-  reverse . dropWhile (== ' ') . reverse . takeWhile (/= '%') <$>-  lookup "Exec" (deAttributes de)+  reverse . dropWhile (== ' ') . reverse . takeWhile (/= '%')+    <$> lookup "Exec" (deAttributes de)  -- | Return a list of all desktop entries in the given directory.-listDesktopEntries-  :: String -- ^ The extension to use in the search-  -> FilePath -- ^ The filepath at which to search-  -> IO [DesktopEntry]+listDesktopEntries ::+  -- | The extension to use in the search+  String ->+  -- | The filepath at which to search+  FilePath ->+  IO [DesktopEntry] listDesktopEntries extension dir = do   let normalizedDir = normalise dir   ex <- doesDirectoryExist normalizedDir   if ex-  then do-    files <- map (normalizedDir </>) <$> listDirectory dir-    entries <--      (nub . rights) <$>-      mapM readDesktopEntry (filter (extension `isSuffixOf`) files)-    subDirs <- filterM doesDirectoryExist files-    subEntries <- concat <$> mapM (listDesktopEntries extension) subDirs-    return $ entries ++ subEntries-  else return []+    then do+      files <- map (normalizedDir </>) <$> listDirectory dir+      entries <-+        nub . rights+          <$> mapM readDesktopEntry (filter (extension `isSuffixOf`) files)+      subDirs <- filterM doesDirectoryExist files+      subEntries <- concat <$> mapM (listDesktopEntries extension) subDirs+      return $ entries ++ subEntries+    else return []  -- XXX: This function doesn't recurse, but `listDesktopEntries` does. Why? -- Shouldn't they really share logic...+ -- | Retrieve a desktop entry with a specific name. getDirectoryEntry :: [FilePath] -> String -> IO (Maybe DesktopEntry) getDirectoryEntry dirs name = do   exFiles <- filterM doesFileExist $ map ((</> name) . normalise) dirs-  join . (fmap rightToMaybe) <$> traverse readDesktopEntry (headMay exFiles)+  (rightToMaybe =<<) <$> traverse readDesktopEntry (headMay exFiles)  -- | Get a desktop entry with a specific name from the default directory entry -- locations. getDirectoryEntryDefault :: String -> IO (Maybe DesktopEntry) getDirectoryEntryDefault entry =-  fmap (</> "applications") <$> getXDGDataDirs >>=-  flip getDirectoryEntry (printf "%s.desktop" entry)+  getXDGDataDirs+    >>= flip getDirectoryEntry (printf "%s.desktop" entry) . fmap (</> "applications")  -- | Get all instances of 'DesktopEntry' for all desktop entry files that can be -- found by looking in the directories specified by the XDG specification. getDirectoryEntriesDefault :: IO [DesktopEntry] getDirectoryEntriesDefault =-  fmap (</> "applications") <$> getXDGDataDirs >>= foldM addDesktopEntries []-  where addDesktopEntries soFar directory =-          (soFar ++) <$> listDesktopEntries "desktop" directory+  getXDGDataDirs >>= foldM addDesktopEntries [] . fmap (</> "applications")+  where+    addDesktopEntries soFar directory =+      (soFar ++) <$> listDesktopEntries "desktop" directory  -- | Read a desktop entry from a file. readDesktopEntry :: FilePath -> IO (Either String DesktopEntry)@@ -184,34 +197,39 @@   -- let bar :: ExceptT String IO (HM.HashMap Text [(Text, Text)]) = map Ini.iniSections . liftIO $ Ini.readIniFile filePath   -- sections <- fmap Ini.iniSections . join . fmap except . liftIO $ Ini.readIniFile filePath   sections <- liftIO (Ini.readIniFile filePath) >>= fmap Ini.iniSections . except-  result <- maybe (throwE "Section [Desktop Entry] not found") (pure . fmap (bimap unpack unpack)) $-              HM.lookup (pack "Desktop Entry") sections-  return DesktopEntry-         { deType = fromMaybe Application $ lookup "Type" result >>= readMaybe-         , deFilename = filePath-         , deAttributes = result-         }+  result <-+    maybe (throwE "Section [Desktop Entry] not found") (pure . fmap (bimap unpack unpack)) $+      HM.lookup (pack "Desktop Entry") sections+  return+    DesktopEntry+      { deType = fromMaybe Application $ lookup "Type" result >>= readMaybe,+        deFilename = filePath,+        deAttributes = result+      }  -- | Construct a 'MM.Multimap' where each 'DesktopEntry' in the provided -- foldable is indexed by the keys returned from the provided indexing function. indexDesktopEntriesBy ::-  Foldable t => (DesktopEntry -> [String]) ->-  t DesktopEntry -> MM.MultiMap String DesktopEntry+  (Foldable t) =>+  (DesktopEntry -> [String]) ->+  t DesktopEntry ->+  MM.MultiMap String DesktopEntry indexDesktopEntriesBy getIndices = foldl insertByIndices MM.empty   where     insertByIndices entriesMap entry =       foldl insertForKey entriesMap $ getIndices entry-        where insertForKey innerMap key = MM.insert key entry innerMap+      where+        insertForKey innerMap key = MM.insert key entry innerMap  -- | Get all the text elements that could be interpreted as class names from a -- 'DesktopEntry'. getClassNames :: DesktopEntry -> [String]-getClassNames DesktopEntry { deAttributes = attributes, deFilename = filepath } =-  (snd $ splitExtensions $ snd $ splitFileName filepath) :-  catMaybes [lookup "StartupWMClass" attributes, lookup "Name" attributes]+getClassNames DesktopEntry {deAttributes = attributes, deFilename = filepath} =+  snd (splitExtensions $ snd $ splitFileName filepath)+    : catMaybes [lookup "StartupWMClass" attributes, lookup "Name" attributes]  -- | Construct a multimap where desktop entries are indexed by their class -- names.-indexDesktopEntriesByClassName-  :: Foldable t => t DesktopEntry -> MM.MultiMap String DesktopEntry+indexDesktopEntriesByClassName ::+  (Foldable t) => t DesktopEntry -> MM.MultiMap String DesktopEntry indexDesktopEntriesByClassName = indexDesktopEntriesBy getClassNames
test/Main.hs view
@@ -6,13 +6,11 @@ import Test.Hspec  fileContent :: [String]-fileContent = [-    "[Desktop Entry]\n\+fileContent =+  [ "[Desktop Entry]\n\     \Icon=1",-     "[Desktop Entry]\n\     \icon=2",-     "[desktop entry]\n\     \Icon=3"   ]@@ -21,7 +19,7 @@ main = withSystemTempDirectory "xdg-desktop-entry" $ \dir -> do   let filepath :: Int -> String       filepath i = dir </> show i-  for_ (zip [0::Int ..] fileContent) $ \(i, content) -> do+  for_ (zip [0 :: Int ..] fileContent) $ \(i, content) -> do     print i     writeFile (filepath i) content   hspec $ do
xdg-desktop-entry.cabal view
@@ -1,6 +1,6 @@ cabal-version:       2.4 name:                xdg-desktop-entry-version:             0.1.1.4+version:             0.1.1.5 synopsis:            Parse files conforming to the xdg desktop entry spec description:         Parse files conforming to the xdg desktop entry spec. bug-reports:         https://github.com/taffybar/taffybar/issues