diff --git a/ihaskell.cabal b/ihaskell.cabal index af35e554..a98d5f04 100644 --- a/ihaskell.cabal +++ b/ihaskell.cabal @@ -73,7 +73,6 @@ library haskell-src-exts ==1.16.*, http-client == 0.4.*, http-client-tls == 0.2.*, - MissingH >=1.2, mtl >=2.1, parsec -any, process >=1.1, @@ -116,6 +115,7 @@ library Paths_ihaskell other-modules: IHaskellPrelude + StringUtils default-extensions: NoImplicitPrelude @@ -182,7 +182,6 @@ Test-Suite hspec haskell-src-exts ==1.16.*, hspec -any, HUnit -any, - MissingH >=1.2, mtl >=2.1, parsec -any, process >=1.1, diff --git a/src/IHaskell/BrokenPackages.hs b/src/IHaskell/BrokenPackages.hs index 4a1a4664..bd9fb57a 100644 --- a/src/IHaskell/BrokenPackages.hs +++ b/src/IHaskell/BrokenPackages.hs @@ -13,8 +13,6 @@ import Text.Parsec import Text.Parsec.String import Control.Applicative hiding ((<|>), many) -import Data.String.Utils (startswith) - import Shelly data BrokenPackage = BrokenPackage { packageID :: String, brokenDeps :: [String] } @@ -30,8 +28,8 @@ getBrokenPackages = shelly $ do checkOut <- lastStderr -- Get rid of extraneous things - let rightStart str = startswith "There are problems" str || - startswith " dependency" str + let rightStart str = "There are problems" `isPrefixOf` str || + " dependency" `isPrefixOf` str ghcPkgOutput = unlines . filter rightStart . lines $ T.unpack checkOut return $ diff --git a/src/IHaskell/Display.hs b/src/IHaskell/Display.hs index 2f5e7f70..47238ba4 100644 --- a/src/IHaskell/Display.hs +++ b/src/IHaskell/Display.hs @@ -56,7 +56,6 @@ import qualified Data.ByteString.Lazy as LBS import qualified Data.ByteString.Char8 as CBS import Data.Serialize as Serialize -import Data.String.Utils (rstrip) import qualified Data.ByteString.Base64 as Base64 import Data.Aeson (Value) import System.Directory (getTemporaryDirectory, setCurrentDirectory) @@ -69,6 +68,7 @@ import System.IO.Unsafe (unsafePerformIO) import qualified Data.Text.Encoding as E import IHaskell.Types +import StringUtils (rstrip) type Base64 = Text diff --git a/src/IHaskell/Eval/Completion.hs b/src/IHaskell/Eval/Completion.hs index fba069e5..7de7e13d 100644 --- a/src/IHaskell/Eval/Completion.hs +++ b/src/IHaskell/Eval/Completion.hs @@ -23,11 +23,9 @@ import Control.Applicative ((<$>)) import Data.ByteString.UTF8 hiding (drop, take, lines, length) import Data.Char import Data.List (nub, init, last, head, elemIndex) -import Data.List.Split -import Data.List.Split.Internals +import qualified Data.List.Split as Split +import qualified Data.List.Split.Internals as Split import Data.Maybe (fromJust) -import Data.String.Utils (strip, startswith, endswith, replace) -import qualified Data.String.Utils as StringUtils import System.Environment (getEnv) import GHC hiding (Qualified) @@ -51,6 +49,7 @@ import System.Console.Haskeline.Completion import IHaskell.Types import IHaskell.Eval.Evaluate (Interpreter) import IHaskell.Eval.ParseShell (parseShell) +import StringUtils (replace, strip, split) data CompletionType = Empty | Identifier String @@ -179,17 +178,17 @@ completionType :: String -- ^ The line on which the completion is bei -> CompletionType completionType line loc target -- File and directory completions are special - | startswith ":!" stripped = + | ":!" `isPrefixOf` stripped = fileComplete FilePath - | startswith ":l" stripped = + | ":l" `isPrefixOf` stripped = fileComplete HsFilePath -- Complete :set, :opt, and :ext - | startswith ":s" stripped = + | ":s" `isPrefixOf` stripped = DynFlag candidate - | startswith ":o" stripped = + | ":o" `isPrefixOf` stripped = KernelOption candidate - | startswith ":e" stripped = + | ":e" `isPrefixOf` stripped = Extension candidate -- Use target for other completions. If it's empty, no completion. @@ -201,7 +200,7 @@ completionType line loc target FilePath (getStringTarget lineUpToCursor) (getStringTarget lineUpToCursor) -- Complete module names in imports and elsewhere. - | startswith "import" stripped && isModName = + | "import" `isPrefixOf` stripped && isModName = ModuleName dotted candidate | isModName && (not . null . init) target = Qualified dotted candidate @@ -225,7 +224,7 @@ completionType line loc target fileComplete filePath = case parseShell lineUpToCursor of Right xs -> filePath lineUpToCursor $ - if endswith (last xs) lineUpToCursor + if last xs `isSuffixOf` lineUpToCursor then last xs else [] Left _ -> Empty @@ -256,14 +255,14 @@ completionTarget :: String -> Int -> [String] completionTarget code cursor = expandCompletionPiece pieceToComplete where pieceToComplete = map fst <$> find (elem cursor . map snd) pieces - pieces = splitAlongCursor $ split splitter $ zip code [1 ..] - splitter = defaultSplitter + pieces = splitAlongCursor $ Split.split splitter $ zip code [1 ..] + splitter = Split.defaultSplitter { -- Split using only the characters, which are the first elements of the (char, index) tuple - delimiter = Delimiter [uncurry isDelim] + Split.delimiter = Split.Delimiter [uncurry isDelim] -- Condense multiple delimiters into one and then drop them. - , condensePolicy = Condense - , delimPolicy = Drop + , Split.condensePolicy = Split.Condense + , Split.delimPolicy = Split.Drop } isDelim :: Char -> Int -> Bool @@ -281,7 +280,7 @@ completionTarget code cursor = expandCompletionPiece pieceToComplete neverIdent = " \n\t(),{}[]\\'\"`" expandCompletionPiece Nothing = [] - expandCompletionPiece (Just str) = splitOn "." str + expandCompletionPiece (Just str) = Split.splitOn "." str getHome :: IO String getHome = do @@ -313,7 +312,7 @@ completePathWithExtensions extensions line = acceptAll = const True extensionIsOneOf exts str = any correctEnding exts where - correctEnding ext = endswith ext str + correctEnding ext = ext `isSuffixOf` str completePathFilter :: (String -> Bool) -- ^ File filter: test whether to include this file. -> (String -> Bool) -- ^ Directory filter: test whether to include this directory. @@ -334,8 +333,8 @@ completePathFilter includeFile includeDirectory left right = GhcMonad.liftIO $ d -- everything else. If we wanted to keep original order, we could instead use -- filter (`elem` (dirs ++ files)) completions suggestions <- mapM unDirExpand $ dirs ++ files - let isHidden str = startswith "." . last . StringUtils.split "/" $ - if endswith "/" str + let isHidden str = isPrefixOf "." . last . split "/" $ + if "/" `isSuffixOf` str then init str else str visible = filter (not . isHidden) suggestions diff --git a/src/IHaskell/Eval/Evaluate.hs b/src/IHaskell/Eval/Evaluate.hs index b6b7825b..f0317c09 100644 --- a/src/IHaskell/Eval/Evaluate.hs +++ b/src/IHaskell/Eval/Evaluate.hs @@ -24,9 +24,7 @@ import qualified Data.ByteString.Char8 as CBS import Control.Concurrent (forkIO, threadDelay) import Prelude (putChar, head, tail, last, init, (!!)) -import Data.List.Utils import Data.List (findIndex, and, foldl1, nubBy) -import Data.String.Utils import Text.Printf import Data.Char as Char import Data.Dynamic @@ -86,6 +84,7 @@ import qualified IHaskell.Eval.Hoogle as Hoogle import IHaskell.Eval.Util import IHaskell.BrokenPackages import qualified IHaskell.IPython.Message.UUID as UUID +import StringUtils (replace, split, strip, rstrip) import Paths_ihaskell (version) import Data.Version (versionBranch) @@ -570,7 +569,7 @@ evalCommand _ (Directive LoadFile names) state = wrapExecution state $ do write state $ "Load: " ++ names displays <- forM (words names) $ \name -> do - let filename = if endswith ".hs" name + let filename = if ".hs" `isSuffixOf` name then name else name ++ ".hs" contents <- liftIO $ readFile filename @@ -855,7 +854,7 @@ evalCommand output (Expression expr) state = do isShowError (Display errs) = -- Note that we rely on this error message being 'type cleaned', so that `Show` is not displayed as -- GHC.Show.Show. This is also very fragile! - startswith "No instance for (Show" msg && + "No instance for (Show" `isPrefixOf` msg && isInfixOf "print it" msg where msg = extractPlain errs @@ -1250,7 +1249,7 @@ formatErrorWithClass cls = fixDollarSigns = replace "$" "$" useDashV = "\nUse -v to see a list of the files searched for." isShowError err = - startswith "No instance for (Show" err && + "No instance for (Show" `isPrefixOf` err && isInfixOf " arising from a use of `print'" err formatParseError :: StringLoc -> String -> ErrMsg diff --git a/src/IHaskell/Eval/Hoogle.hs b/src/IHaskell/Eval/Hoogle.hs index 64e32b71..c969a293 100644 --- a/src/IHaskell/Eval/Hoogle.hs +++ b/src/IHaskell/Eval/Hoogle.hs @@ -18,12 +18,12 @@ import qualified Data.ByteString.Char8 as CBS import Network.HTTP.Client import Network.HTTP.Client.TLS import Data.Aeson -import Data.String.Utils import qualified Data.List as List import Data.Char (isAscii, isAlphaNum) import IHaskell.IPython +import StringUtils (split, strip, replace) -- | Types of formats to render output to. data OutputFormat = Plain -- ^ Render to plain text. @@ -156,22 +156,22 @@ renderHtml (SearchResult resp) = renderSelf :: String -> String -> String renderSelf string loc - | startswith "package" string = + | "package" `isPrefixOf` string = pkg ++ " " ++ span "hoogle-package" (link loc $ extractPackage string) - | startswith "module" string = + | "module" `isPrefixOf` string = let package = extractPackageName loc in mod ++ " " ++ span "hoogle-module" (link loc $ extractModule string) ++ packageSub package - | startswith "class" string = + | "class" `isPrefixOf` string = let package = extractPackageName loc in cls ++ " " ++ span "hoogle-class" (link loc $ extractClass string) ++ packageSub package - | startswith "data" string = + | "data" `isPrefixOf` string = let package = extractPackageName loc in dat ++ " " ++ span "hoogle-class" (link loc $ extractData string) ++ @@ -221,9 +221,9 @@ renderDocs doc = let groups = List.groupBy bothAreCode $ lines doc nonull = filter (not . null . strip) bothAreCode s1 s2 = - startswith ">" (strip s1) && - startswith ">" (strip s2) - isCode (s:_) = startswith ">" $ strip s + isPrefixOf ">" (strip s1) && + isPrefixOf ">" (strip s2) + isCode (s:_) = isPrefixOf ">" $ strip s makeBlock lines = if isCode lines then div' "hoogle-code" $ unlines $ nonull lines diff --git a/src/IHaskell/Eval/Lint.hs b/src/IHaskell/Eval/Lint.hs index 599ec2de..1505adbd 100644 --- a/src/IHaskell/Eval/Lint.hs +++ b/src/IHaskell/Eval/Lint.hs @@ -9,11 +9,9 @@ import qualified Data.ByteString as BS import qualified Data.ByteString.Lazy as LBS import qualified Data.ByteString.Char8 as CBS -import Data.String.Utils (replace, startswith, strip, split) import Prelude (head, tail, last) import Control.Monad import Data.List (findIndex) -import Text.Printf import Data.String.Here import Data.Char import Data.Monoid @@ -34,6 +32,7 @@ import IHaskell.Types import IHaskell.Display import IHaskell.IPython import IHaskell.Eval.Parser hiding (line) +import StringUtils (replace) type ExtsModule = SrcExts.Module SrcSpanInfo diff --git a/src/IHaskell/Eval/Parser.hs b/src/IHaskell/Eval/Parser.hs index 23c21f78..dd593d4d 100644 --- a/src/IHaskell/Eval/Parser.hs +++ b/src/IHaskell/Eval/Parser.hs @@ -23,7 +23,6 @@ import qualified Data.ByteString.Lazy as LBS import qualified Data.ByteString.Char8 as CBS import Data.List (maximumBy, inits) -import Data.String.Utils (startswith, strip, split) import Prelude (head, tail) import Control.Monad (msum) @@ -31,6 +30,7 @@ import GHC hiding (Located) import Language.Haskell.GHC.Parser import IHaskell.Eval.Util +import StringUtils (strip, split) -- | A block of code to be evaluated. Each block contains a single element - one declaration, -- statement, expression, etc. If parsing of the block failed, the block is instead a ParseError, @@ -113,11 +113,11 @@ parseString codeString = do -- Test whether a given chunk is a directive. isDirective :: String -> Bool - isDirective = startswith ":" . strip + isDirective = isPrefixOf ":" . strip -- Test if a chunk is a pragma. isPragma :: String -> Bool - isPragma = startswith "{-#" . strip + isPragma = isPrefixOf "{-#" . strip activateExtensions :: GhcMonad m => CodeBlock -> m () activateExtensions (Directive SetExtension ext) = void $ setExtension ext diff --git a/src/IHaskell/Eval/Util.hs b/src/IHaskell/Eval/Util.hs index 457b4471..a25aaf50 100644 --- a/src/IHaskell/Eval/Util.hs +++ b/src/IHaskell/Eval/Util.hs @@ -52,9 +52,10 @@ import qualified Outputable as O import Control.Monad (void) import Data.Function (on) -import Data.String.Utils (replace) import Data.List (nubBy) +import StringUtils (replace) + -- | A extension flag that can be set or unset. data ExtFlag = SetFlag ExtensionFlag | UnsetFlag ExtensionFlag diff --git a/src/IHaskell/IPython.hs b/src/IHaskell/IPython.hs index 6792c987..36b5cb88 100644 --- a/src/IHaskell/IPython.hs +++ b/src/IHaskell/IPython.hs @@ -26,8 +26,6 @@ import qualified Shelly as SH import qualified System.IO as IO import qualified System.FilePath as FP import System.Directory -import Data.List.Utils (split) -import Data.String.Utils (rstrip, endswith, strip, replace) import System.Exit (exitFailure) import Data.Aeson (toJSON) import Data.Aeson.Encode (encodeToTextBuilder) @@ -40,6 +38,8 @@ import qualified GHC.Paths import IHaskell.Types import System.Posix.Signals +import StringUtils (replace, split) + data KernelSpecOptions = KernelSpecOptions { kernelSpecGhcLibdir :: String -- ^ GHC libdir. @@ -258,7 +258,7 @@ getSandboxPackageConf = SH.shelly $ do let pieces = split "/" myPath sandboxDir = intercalate "/" $ takeWhile (/= sandboxName) pieces ++ [sandboxName] subdirs <- map fp <$> SH.ls (SH.fromText $ T.pack sandboxDir) - let confdirs = filter (endswith ("packages.conf.d" :: String)) subdirs + let confdirs = filter (isSuffixOf ("packages.conf.d" :: String)) subdirs case confdirs of [] -> return Nothing dir:_ -> diff --git a/src/StringUtils.hs b/src/StringUtils.hs new file mode 100644 index 00000000..7d20e995 --- /dev/null +++ b/src/StringUtils.hs @@ -0,0 +1,26 @@ +module StringUtils ( + strip, + lstrip, + rstrip, + replace, + split, + ) where + +import IHaskellPrelude +import qualified Data.Text as T + +lstrip :: String -> String +lstrip = dropWhile (`elem` " \t\r\n") + +rstrip :: String -> String +rstrip = reverse . lstrip . reverse + +strip :: String -> String +strip = rstrip . lstrip + +replace :: String -> String -> String -> String +replace needle replacement haystack = + T.unpack $ T.replace (T.pack needle) (T.pack replacement) (T.pack haystack) + +split :: String -> String -> [String] +split delim = map T.unpack . T.splitOn (T.pack delim) . T.pack