X.P.RunOrRaise: Disambiguate directories and executables

When there is a directory and a file in $PATH of the same name `foo`, we
display `foo`, as well as `foo/` in the prompt, but selecting either one
of them will invariably run or raise the directory, as this test is done
beforehand.

Since directories already carry a trailing forward slash from the shell
prompt's `getShellCompl`, this is easily disambiguated by incorporating
an additional check.

It is duly noted that the same problem also exists for files in the
current directory.  This could be fixed in a similar way (adding a
unique suffix to files and checking for that), but since this would
involve changing `getShellCompl` and no-one has complained about this so
far, it was deemed "not worth it" for now.

Fixes: https://github.com/xmonad/xmonad-contrib/issues/616
This commit is contained in:
slotThe
2021-10-09 09:03:50 +02:00
parent 9ff7f89664
commit 5bdc5993f9

View File

@@ -22,14 +22,14 @@ module XMonad.Prompt.RunOrRaise
) where
import XMonad hiding (config)
import XMonad.Prelude (liftA2)
import XMonad.Prelude (isNothing, isSuffixOf, liftA2)
import XMonad.Prompt
import XMonad.Prompt.Shell
import XMonad.Actions.WindowGo (runOrRaise)
import XMonad.Util.Run (runProcessWithInput)
import Control.Exception as E
import System.Directory (doesDirectoryExist, doesFileExist, executable, getPermissions)
import System.Directory (doesDirectoryExist, doesFileExist, executable, findExecutable, getPermissions)
econst :: Monad m => a -> IOException -> m a
econst = const . return
@@ -60,9 +60,14 @@ open path = io (isNormalFile path) >>= \b ->
then spawn $ "xdg-open \"" ++ path ++ "\""
else uncurry runOrRaise . getTarget $ path
where
isNormalFile f = exists f >>= \e -> if e then notExecutable f else return False
exists f = or <$> sequence [doesFileExist f,doesDirectoryExist f]
isNormalFile f = do
notCommand <- isNothing <$> findExecutable f -- not a command (executable in $PATH)
exists <- or <$> sequence [doesDirExist f, doesFileExist f]
case (notCommand, exists) of
(True, True) -> notExecutable f -- not executable as a file in current dir
_ -> pure False
notExecutable = fmap (not . executable) . getPermissions
doesDirExist f = ("/" `isSuffixOf` f &&) <$> doesDirectoryExist f
getTarget x = (x,isApp x)
isApp :: String -> Query Bool