{-# LANGUAGE CPP, PackageImports #-}

module HsDev.Tools.HLint (
	hlint,
	hlintSupported,

	module Control.Monad.Except
	) where

import Control.Monad.Except
import Data.Text (Text)

import HsDev.Tools.Base

#ifndef NOHLINT
import Control.Arrow
import Control.Lens (over, view, _Just)
import Data.Char
import Data.List
import Data.Maybe (mapMaybe)
import qualified Data.Text as T
import Data.Ord
import Data.String (fromString)
import Language.Haskell.HLint (argsSettings, parseModuleEx, applyHints, Idea(..), parseErrorMessage, ParseFlags(..), CppFlags(..), unpackSrcSpan)
import qualified Language.Haskell.HLint as HL (Severity(..))

import System.Directory.Paths
import HsDev.Symbols.Location
import HsDev.Util (readFileUtf8)
#endif

hlint :: [String] -> FilePath -> Maybe Text -> ExceptT String IO [Note OutputMessage]
#ifndef NOHLINT
hlint :: [String]
-> String -> Maybe Text -> ExceptT String IO [Note OutputMessage]
hlint [String]
opts String
file Maybe Text
msrc = do
	String
file' <- IO String -> ExceptT String IO String
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO String -> ExceptT String IO String)
-> IO String -> ExceptT String IO String
forall a b. (a -> b) -> a -> b
$ String -> IO String
forall a. Paths a => a -> IO a
canonicalize String
file
	Text
cts <- ExceptT String IO Text
-> (Text -> ExceptT String IO Text)
-> Maybe Text
-> ExceptT String IO Text
forall b a. b -> (a -> b) -> Maybe a -> b
maybe (IO Text -> ExceptT String IO Text
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO Text -> ExceptT String IO Text)
-> IO Text -> ExceptT String IO Text
forall a b. (a -> b) -> a -> b
$ String -> IO Text
readFileUtf8 String
file') Text -> ExceptT String IO Text
forall (m :: * -> *) a. Monad m => a -> m a
return Maybe Text
msrc
	(ParseFlags
flags, [Classify]
classify, Hint
hint) <- IO (ParseFlags, [Classify], Hint)
-> ExceptT String IO (ParseFlags, [Classify], Hint)
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO (ParseFlags, [Classify], Hint)
 -> ExceptT String IO (ParseFlags, [Classify], Hint))
-> IO (ParseFlags, [Classify], Hint)
-> ExceptT String IO (ParseFlags, [Classify], Hint)
forall a b. (a -> b) -> a -> b
$ [String] -> IO (ParseFlags, [Classify], Hint)
argsSettings [String]
opts
	Either ParseError ModuleEx
p <- IO (Either ParseError ModuleEx)
-> ExceptT String IO (Either ParseError ModuleEx)
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO (Either ParseError ModuleEx)
 -> ExceptT String IO (Either ParseError ModuleEx))
-> IO (Either ParseError ModuleEx)
-> ExceptT String IO (Either ParseError ModuleEx)
forall a b. (a -> b) -> a -> b
$ ParseFlags
-> String -> Maybe String -> IO (Either ParseError ModuleEx)
parseModuleEx (ParseFlags
flags { cppFlags :: CppFlags
cppFlags = CppFlags
CppSimple }) String
file' (String -> Maybe String
forall a. a -> Maybe a
Just (String -> Maybe String) -> String -> Maybe String
forall a b. (a -> b) -> a -> b
$ Text -> String
T.unpack Text
cts)
	ModuleEx
m <- (ParseError -> ExceptT String IO ModuleEx)
-> (ModuleEx -> ExceptT String IO ModuleEx)
-> Either ParseError ModuleEx
-> ExceptT String IO ModuleEx
forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either (String -> ExceptT String IO ModuleEx
forall e (m :: * -> *) a. MonadError e m => e -> m a
throwError (String -> ExceptT String IO ModuleEx)
-> (ParseError -> String)
-> ParseError
-> ExceptT String IO ModuleEx
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ParseError -> String
parseErrorMessage) ModuleEx -> ExceptT String IO ModuleEx
forall (m :: * -> *) a. Monad m => a -> m a
return Either ParseError ModuleEx
p
	[Note OutputMessage] -> ExceptT String IO [Note OutputMessage]
forall (m :: * -> *) a. Monad m => a -> m a
return ([Note OutputMessage] -> ExceptT String IO [Note OutputMessage])
-> [Note OutputMessage] -> ExceptT String IO [Note OutputMessage]
forall a b. (a -> b) -> a -> b
$ (Note OutputMessage -> Note OutputMessage)
-> [Note OutputMessage] -> [Note OutputMessage]
forall a b. (a -> b) -> [a] -> [b]
map (Text -> Int -> Note OutputMessage -> Note OutputMessage
forall a. RecalcTabs a => Text -> Int -> a -> a
recalcTabs Text
cts Int
8 (Note OutputMessage -> Note OutputMessage)
-> (Note OutputMessage -> Note OutputMessage)
-> Note OutputMessage
-> Note OutputMessage
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> Note OutputMessage -> Note OutputMessage
indentIdea Text
cts) ([Note OutputMessage] -> [Note OutputMessage])
-> [Note OutputMessage] -> [Note OutputMessage]
forall a b. (a -> b) -> a -> b
$ (Idea -> Maybe (Note OutputMessage))
-> [Idea] -> [Note OutputMessage]
forall a b. (a -> Maybe b) -> [a] -> [b]
mapMaybe Idea -> Maybe (Note OutputMessage)
fromIdea ([Idea] -> [Note OutputMessage]) -> [Idea] -> [Note OutputMessage]
forall a b. (a -> b) -> a -> b
$
		(Idea -> Bool) -> [Idea] -> [Idea]
forall a. (a -> Bool) -> [a] -> [a]
filter (Bool -> Bool
not (Bool -> Bool) -> (Idea -> Bool) -> Idea -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Idea -> Bool
ignoreIdea) ([Idea] -> [Idea]) -> [Idea] -> [Idea]
forall a b. (a -> b) -> a -> b
$
		[Classify] -> Hint -> [ModuleEx] -> [Idea]
applyHints [Classify]
classify Hint
hint [ModuleEx
m]
#else
hlint _ _ _ = throwError "Compiled with no hlint support"
#endif

#ifndef NOHLINT
ignoreIdea :: Idea -> Bool
ignoreIdea :: Idea -> Bool
ignoreIdea Idea
idea = Idea -> Severity
ideaSeverity Idea
idea Severity -> Severity -> Bool
forall a. Eq a => a -> a -> Bool
== Severity
HL.Ignore

fromIdea :: Idea -> Maybe (Note OutputMessage)
fromIdea :: Idea -> Maybe (Note OutputMessage)
fromIdea Idea
idea = do
	(String
fpath, (Int
startLine, Int
startCol), (Int
endLine, Int
endCol)) <- SrcSpan -> Maybe (String, (Int, Int), (Int, Int))
unpackSrcSpan (Idea -> SrcSpan
ideaSpan Idea
idea)
	Note OutputMessage -> Maybe (Note OutputMessage)
forall (m :: * -> *) a. Monad m => a -> m a
return (Note OutputMessage -> Maybe (Note OutputMessage))
-> Note OutputMessage -> Maybe (Note OutputMessage)
forall a b. (a -> b) -> a -> b
$ Note :: forall a1.
ModuleLocation -> Region -> Maybe Severity -> a1 -> Note a1
Note {
		_noteSource :: ModuleLocation
_noteSource = Text -> Maybe Project -> ModuleLocation
FileModule (String -> Text
fromFilePath String
fpath) Maybe Project
forall a. Maybe a
Nothing,
		_noteRegion :: Region
_noteRegion = Position -> Position -> Region
Region (Int -> Int -> Position
Position Int
startLine Int
startCol) (Int -> Int -> Position
Position Int
endLine Int
endCol),
		_noteLevel :: Maybe Severity
_noteLevel = Severity -> Maybe Severity
forall a. a -> Maybe a
Just (Severity -> Maybe Severity) -> Severity -> Maybe Severity
forall a b. (a -> b) -> a -> b
$ case Idea -> Severity
ideaSeverity Idea
idea of
			Severity
HL.Warning -> Severity
Warning
			Severity
HL.Error -> Severity
Error
			Severity
_ -> Severity
Hint,
		_note :: OutputMessage
_note = OutputMessage :: Text -> Maybe Text -> OutputMessage
OutputMessage {
			_message :: Text
_message = String -> Text
forall a. IsString a => String -> a
fromString (String -> Text) -> String -> Text
forall a b. (a -> b) -> a -> b
$ Idea -> String
ideaHint Idea
idea,
			_messageSuggestion :: Maybe Text
_messageSuggestion = (String -> Text) -> Maybe String -> Maybe Text
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap String -> Text
forall a. IsString a => String -> a
fromString (Maybe String -> Maybe Text) -> Maybe String -> Maybe Text
forall a b. (a -> b) -> a -> b
$ Idea -> Maybe String
ideaTo Idea
idea } }

indentIdea :: Text -> Note OutputMessage -> Note OutputMessage
indentIdea :: Text -> Note OutputMessage -> Note OutputMessage
indentIdea Text
cts Note OutputMessage
idea = case Text -> Maybe Text
analyzeIndent Text
cts of
	Maybe Text
Nothing -> Note OutputMessage
idea
	Just Text
i -> ASetter (Note OutputMessage) (Note OutputMessage) Text Text
-> (Text -> Text) -> Note OutputMessage -> Note OutputMessage
forall s t a b. ASetter s t a b -> (a -> b) -> s -> t
over ((OutputMessage -> Identity OutputMessage)
-> Note OutputMessage -> Identity (Note OutputMessage)
forall a1 a2. Lens (Note a1) (Note a2) a1 a2
note ((OutputMessage -> Identity OutputMessage)
 -> Note OutputMessage -> Identity (Note OutputMessage))
-> ((Text -> Identity Text)
    -> OutputMessage -> Identity OutputMessage)
-> ASetter (Note OutputMessage) (Note OutputMessage) Text Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Maybe Text -> Identity (Maybe Text))
-> OutputMessage -> Identity OutputMessage
Lens' OutputMessage (Maybe Text)
messageSuggestion ((Maybe Text -> Identity (Maybe Text))
 -> OutputMessage -> Identity OutputMessage)
-> ((Text -> Identity Text) -> Maybe Text -> Identity (Maybe Text))
-> (Text -> Identity Text)
-> OutputMessage
-> Identity OutputMessage
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Text -> Identity Text) -> Maybe Text -> Identity (Maybe Text)
forall a b. Prism (Maybe a) (Maybe b) a b
_Just) (Text -> Text -> Text
indent' Text
i) Note OutputMessage
idea
	where
		indent' :: Text -> Text -> Text
indent' Text
i' = Text -> [Text] -> Text
T.intercalate (String -> Text
forall a. IsString a => String -> a
fromString String
"\n") ([Text] -> Text) -> (Text -> [Text]) -> Text -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Text] -> [Text]
indentTail ([Text] -> [Text]) -> (Text -> [Text]) -> Text -> [Text]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Text -> Text) -> [Text] -> [Text]
forall a b. (a -> b) -> [a] -> [b]
map ((Text -> Text -> Text) -> (Text, Text) -> Text
forall a b c. (a -> b -> c) -> (a, b) -> c
uncurry Text -> Text -> Text
T.append ((Text, Text) -> Text) -> (Text -> (Text, Text)) -> Text -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Text -> Text) -> (Text, Text) -> (Text, Text)
forall (a :: * -> * -> *) b c d.
Arrow a =>
a b c -> a (b, d) (c, d)
first ((Int -> Text -> Text
`T.replicate` Text
i') (Int -> Text) -> (Text -> Int) -> Text -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Int -> Int -> Int
forall a. Integral a => a -> a -> a
`div` Int
2) (Int -> Int) -> (Text -> Int) -> Text -> Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> Int
T.length) ((Text, Text) -> (Text, Text))
-> (Text -> (Text, Text)) -> Text -> (Text, Text)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Char -> Bool) -> Text -> (Text, Text)
T.span Char -> Bool
isSpace) ([Text] -> [Text]) -> (Text -> [Text]) -> Text -> [Text]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Char -> Bool) -> Text -> [Text]
T.split (Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
'\n')
		indentTail :: [Text] -> [Text]
indentTail [] = []
		indentTail (Text
h : [Text]
hs) = Text
h Text -> [Text] -> [Text]
forall a. a -> [a] -> [a]
: (Text -> Text) -> [Text] -> [Text]
forall a b. (a -> b) -> [a] -> [b]
map (Text
firstIndent Text -> Text -> Text
`T.append`) [Text]
hs
		firstIndent :: Text
firstIndent = (Char -> Bool) -> Text -> Text
T.takeWhile Char -> Bool
isSpace Text
firstLine
		firstLine :: Text
firstLine = Region -> Text -> Text
regionStr (Int -> Int -> Position
Position Int
firstLineNum Int
1 Position -> Position -> Region
`region` Int -> Int -> Position
Position (Int -> Int
forall a. Enum a => a -> a
succ Int
firstLineNum) Int
1) Text
cts
		firstLineNum :: Int
firstLineNum = Getting Int (Note OutputMessage) Int -> Note OutputMessage -> Int
forall s (m :: * -> *) a. MonadReader s m => Getting a s a -> m a
view ((Region -> Const Int Region)
-> Note OutputMessage -> Const Int (Note OutputMessage)
forall a1. Lens' (Note a1) Region
noteRegion ((Region -> Const Int Region)
 -> Note OutputMessage -> Const Int (Note OutputMessage))
-> ((Int -> Const Int Int) -> Region -> Const Int Region)
-> Getting Int (Note OutputMessage) Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Position -> Const Int Position) -> Region -> Const Int Region
Lens' Region Position
regionFrom ((Position -> Const Int Position) -> Region -> Const Int Region)
-> ((Int -> Const Int Int) -> Position -> Const Int Position)
-> (Int -> Const Int Int)
-> Region
-> Const Int Region
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Int -> Const Int Int) -> Position -> Const Int Position
Lens' Position Int
positionLine) Note OutputMessage
idea

-- | Indent in source
data Indent = Spaces Int | Tabs deriving (Indent -> Indent -> Bool
(Indent -> Indent -> Bool)
-> (Indent -> Indent -> Bool) -> Eq Indent
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Indent -> Indent -> Bool
$c/= :: Indent -> Indent -> Bool
== :: Indent -> Indent -> Bool
$c== :: Indent -> Indent -> Bool
Eq, Eq Indent
Eq Indent
-> (Indent -> Indent -> Ordering)
-> (Indent -> Indent -> Bool)
-> (Indent -> Indent -> Bool)
-> (Indent -> Indent -> Bool)
-> (Indent -> Indent -> Bool)
-> (Indent -> Indent -> Indent)
-> (Indent -> Indent -> Indent)
-> Ord Indent
Indent -> Indent -> Bool
Indent -> Indent -> Ordering
Indent -> Indent -> Indent
forall a.
Eq a
-> (a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
min :: Indent -> Indent -> Indent
$cmin :: Indent -> Indent -> Indent
max :: Indent -> Indent -> Indent
$cmax :: Indent -> Indent -> Indent
>= :: Indent -> Indent -> Bool
$c>= :: Indent -> Indent -> Bool
> :: Indent -> Indent -> Bool
$c> :: Indent -> Indent -> Bool
<= :: Indent -> Indent -> Bool
$c<= :: Indent -> Indent -> Bool
< :: Indent -> Indent -> Bool
$c< :: Indent -> Indent -> Bool
compare :: Indent -> Indent -> Ordering
$ccompare :: Indent -> Indent -> Ordering
$cp1Ord :: Eq Indent
Ord)

instance Show Indent where
	show :: Indent -> String
show (Spaces Int
n) = Int -> Char -> String
forall a. Int -> a -> [a]
replicate Int
n Char
' '
	show Indent
Tabs = String
"\t"

-- | Analyze source indentation to convert suggestion to same indentation
-- Returns one indent
analyzeIndent :: Text -> Maybe Text
analyzeIndent :: Text -> Maybe Text
analyzeIndent =
	(Indent -> Text) -> Maybe Indent -> Maybe Text
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (String -> Text
forall a. IsString a => String -> a
fromString (String -> Text) -> (Indent -> String) -> Indent -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Indent -> String
forall a. Show a => a -> String
show) (Maybe Indent -> Maybe Text)
-> (Text -> Maybe Indent) -> Text -> Maybe Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Indent] -> Maybe Indent
selectIndent ([Indent] -> Maybe Indent)
-> (Text -> [Indent]) -> Text -> Maybe Indent
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ((Indent, Int) -> Indent) -> [(Indent, Int)] -> [Indent]
forall a b. (a -> b) -> [a] -> [b]
map (Indent, Int) -> Indent
forall a b. (a, b) -> a
fst ([(Indent, Int)] -> [Indent])
-> (Text -> [(Indent, Int)]) -> Text -> [Indent]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [(Indent, Int)] -> [(Indent, Int)]
dropUnusual ([(Indent, Int)] -> [(Indent, Int)])
-> (Text -> [(Indent, Int)]) -> Text -> [(Indent, Int)]
forall b c a. (b -> c) -> (a -> b) -> a -> c
.
	((Indent, Int) -> (Indent, Int) -> Ordering)
-> [(Indent, Int)] -> [(Indent, Int)]
forall a. (a -> a -> Ordering) -> [a] -> [a]
sortBy (((Indent, Int) -> Int)
-> (Indent, Int) -> (Indent, Int) -> Ordering
forall a b. Ord a => (b -> a) -> b -> b -> Ordering
comparing (((Indent, Int) -> Int)
 -> (Indent, Int) -> (Indent, Int) -> Ordering)
-> ((Indent, Int) -> Int)
-> (Indent, Int)
-> (Indent, Int)
-> Ordering
forall a b. (a -> b) -> a -> b
$ Int -> Int
forall a. Num a => a -> a
negate (Int -> Int) -> ((Indent, Int) -> Int) -> (Indent, Int) -> Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Indent, Int) -> Int
forall a b. (a, b) -> b
snd) ([(Indent, Int)] -> [(Indent, Int)])
-> (Text -> [(Indent, Int)]) -> Text -> [(Indent, Int)]
forall b c a. (b -> c) -> (a -> b) -> a -> c
.
	([Indent] -> (Indent, Int)) -> [[Indent]] -> [(Indent, Int)]
forall a b. (a -> b) -> [a] -> [b]
map ([Indent] -> Indent
forall a. [a] -> a
head ([Indent] -> Indent)
-> ([Indent] -> Int) -> [Indent] -> (Indent, Int)
forall (a :: * -> * -> *) b c c'.
Arrow a =>
a b c -> a b c' -> a b (c, c')
&&& [Indent] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length) ([[Indent]] -> [(Indent, Int)])
-> (Text -> [[Indent]]) -> Text -> [(Indent, Int)]
forall b c a. (b -> c) -> (a -> b) -> a -> c
.
	[Indent] -> [[Indent]]
forall a. Eq a => [a] -> [[a]]
group ([Indent] -> [[Indent]])
-> (Text -> [Indent]) -> Text -> [[Indent]]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Indent] -> [Indent]
forall a. Ord a => [a] -> [a]
sort ([Indent] -> [Indent]) -> (Text -> [Indent]) -> Text -> [Indent]
forall b c a. (b -> c) -> (a -> b) -> a -> c
.
	(Text -> Maybe Indent) -> [Text] -> [Indent]
forall a b. (a -> Maybe b) -> [a] -> [b]
mapMaybe (Text -> Maybe Indent
guessIndent (Text -> Maybe Indent) -> (Text -> Text) -> Text -> Maybe Indent
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Char -> Bool) -> Text -> Text
T.takeWhile Char -> Bool
isSpace) ([Text] -> [Indent]) -> (Text -> [Text]) -> Text -> [Indent]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> [Text]
T.lines
	where
		selectIndent :: [Indent] -> Maybe Indent
		selectIndent :: [Indent] -> Maybe Indent
selectIndent [] = Maybe Indent
forall a. Maybe a
Nothing
		selectIndent (Indent
Tabs : [Indent]
_) = Indent -> Maybe Indent
forall a. a -> Maybe a
Just Indent
Tabs
		selectIndent [Indent]
indents = Indent -> Maybe Indent
forall a. a -> Maybe a
Just (Indent -> Maybe Indent) -> Indent -> Maybe Indent
forall a b. (a -> b) -> a -> b
$ Int -> Indent
Spaces (Int -> Indent) -> Int -> Indent
forall a b. (a -> b) -> a -> b
$ (Int -> Int -> Int) -> [Int] -> Int
forall (t :: * -> *) a. Foldable t => (a -> a -> a) -> t a -> a
foldr1 Int -> Int -> Int
forall a. Integral a => a -> a -> a
gcd ([Int] -> Int) -> [Int] -> Int
forall a b. (a -> b) -> a -> b
$ (Indent -> Maybe Int) -> [Indent] -> [Int]
forall a b. (a -> Maybe b) -> [a] -> [b]
mapMaybe Indent -> Maybe Int
spaces [Indent]
indents where
			spaces :: Indent -> Maybe Int
			spaces :: Indent -> Maybe Int
spaces Indent
Tabs = Maybe Int
forall a. Maybe a
Nothing
			spaces (Spaces Int
n) = Int -> Maybe Int
forall a. a -> Maybe a
Just Int
n
		dropUnusual :: [(Indent, Int)] -> [(Indent, Int)]
		dropUnusual :: [(Indent, Int)] -> [(Indent, Int)]
dropUnusual [] = []
		dropUnusual is :: [(Indent, Int)]
is@((Indent
_, Int
freq):[(Indent, Int)]
_) = ((Indent, Int) -> Bool) -> [(Indent, Int)] -> [(Indent, Int)]
forall a. (a -> Bool) -> [a] -> [a]
takeWhile ((Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
freq Int -> Int -> Int
forall a. Integral a => a -> a -> a
`div` Int
5) (Int -> Bool) -> ((Indent, Int) -> Int) -> (Indent, Int) -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Indent, Int) -> Int
forall a b. (a, b) -> b
snd) [(Indent, Int)]
is

-- | Guess indent of one line
guessIndent :: Text -> Maybe Indent
guessIndent :: Text -> Maybe Indent
guessIndent Text
s
	| (Char -> Bool) -> Text -> Bool
T.all (Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
' ') Text
s = Indent -> Maybe Indent
forall a. a -> Maybe a
Just (Indent -> Maybe Indent) -> Indent -> Maybe Indent
forall a b. (a -> b) -> a -> b
$ Int -> Indent
Spaces (Int -> Indent) -> Int -> Indent
forall a b. (a -> b) -> a -> b
$ Text -> Int
T.length Text
s
	| (Char -> Bool) -> Text -> Bool
T.all (Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
'\t') Text
s = Indent -> Maybe Indent
forall a. a -> Maybe a
Just Indent
Tabs
	| Bool
otherwise = Maybe Indent
forall a. Maybe a
Nothing
#endif

hlintSupported :: Bool
#ifndef NOHLINT
hlintSupported :: Bool
hlintSupported = Bool
True
#else
hlintSupported = False
#endif