Skip to content

Commit

Permalink
Fix #31: new option --tab
Browse files Browse the repository at this point in the history
  • Loading branch information
andreasabel committed Jul 29, 2022
1 parent d3b8d5d commit 3ebe85c
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 20 deletions.
7 changes: 6 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,15 @@

Version history.

## 0.0.9 released 2022-07-29

- New option `--tab` to set tab-size or keep tabs.
- Tested with GHC 8.0.2 - 9.2.3 and 9.4.1 alpha.

## 0.0.8 released 2022-05-29

- New option `--version` displaying program version.
- Tested with GHC 8.0.2 - 9.4.1 alpha.
- Tested with GHC 8.0.2 - 9.2.2 and 9.4.1 alpha.

## 0.0.7 released 2021-09-07

Expand Down
60 changes: 43 additions & 17 deletions FixWhitespace.hs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import Data.Version (showVersion)
import qualified Data.Text as Text
import qualified Data.Text.IO as Text -- Strict IO.

import System.Directory ( getCurrentDirectory, doesFileExist)
import System.Directory (getCurrentDirectory, doesFileExist)
import System.Environment
import System.Exit
-- import System.FilePath
Expand All @@ -21,6 +21,8 @@ import System.FilePattern.Directory
import System.IO
import System.Console.GetOpt

import Text.Read (readMaybe)

import ParseConfig
import qualified Paths_fix_whitespace as PFW (version)

Expand All @@ -29,13 +31,19 @@ import qualified Paths_fix_whitespace as PFW (version)
defaultConfigFile :: String
defaultConfigFile = "fix-whitespace.yaml"

-- | Default tab size.

defaultTabSize :: String
defaultTabSize = "8"

-- Modes.
data Mode
= Fix -- ^ Fix whitespace issues.
| Check -- ^ Check if there are any whitespace issues.
deriving (Show, Eq)

type Verbose = Bool
type TabSize = Int

data Options = Options
{ optVerbose :: Verbose
Expand All @@ -47,6 +55,8 @@ data Options = Options
, optMode :: Mode
, optConfig :: FilePath
-- ^ The location to the configuration file.
, optTabSize :: String
-- ^ The number of spaces to expand a tab character to. @"0"@ for keeping tabs.
}

defaultOptions :: Options
Expand All @@ -56,6 +66,7 @@ defaultOptions = Options
, optVersion = False
, optMode = Fix
, optConfig = defaultConfigFile
, optTabSize = defaultTabSize
}

options :: [OptDescr (Options -> Options)]
Expand All @@ -69,6 +80,12 @@ options =
, Option ['v'] ["verbose"]
(NoArg (\opts -> opts { optVerbose = True }))
"Show files as they are being checked."
, Option ['t'] ["tab"]
(ReqArg (\ts opts -> opts { optTabSize = ts }) "TABSIZE")
(unlines
[ "Expand tab characters to TABSIZE (default: " ++ defaultTabSize ++ ") many spaces."
, "Keep tabs if 0 is given as TABSIZE."
])
, Option [] ["config"]
(ReqArg (\loc opts -> opts { optConfig = loc }) "CONFIG")
(concat ["Override the project configuration ", defaultConfigFile, "."])
Expand All @@ -77,7 +94,7 @@ options =
(unlines
[ "With --check the program does not change any files,"
, "it just checks if any files would have been changed."
, "In this case it returns with a non-zero exit code."
, "In the latter case it returns with a non-zero exit code."
])
]

Expand All @@ -90,8 +107,11 @@ programOpts progName = do


shortUsageHeader :: String -> String
shortUsageHeader progName =
"Usage: " ++ progName ++ " [-h|--help] [-v|--verbose] [--check] [--config CONFIG] [FILES]"
shortUsageHeader progName = unwords
[ "Usage:"
, progName
, "[-h|--help] [-v|--verbose] [--check] [--config CONFIG] [-t|--tab TABSIZE] [FILES]"
]

usageHeader :: String -> String
usageHeader progName = unlines
Expand All @@ -102,11 +122,11 @@ usageHeader progName = unlines
, " * Removes trailing whitespace."
, " * Removes trailing lines containing nothing but whitespace."
, " * Ensures that the file ends in a newline character."
, " * Convert tabs to spaces, assuming a tab-size of 8."
, " * Convert tabs to TABSIZE (default: " ++ defaultTabSize ++ ") spaces, unless TABSIZE is set to 0."
, ""
, "for files specified in [FILES] or"
, ""
, "\t" ++ optConfig defaultOptions
, "\t" ++ defaultConfigFile
, ""
, "under the current directory."
, ""
Expand Down Expand Up @@ -141,6 +161,9 @@ main = do
verbose = optVerbose opts
config = optConfig opts

tabSize <- maybe (die "Error: Illegal TABSIZE, must be an integer.") return $
readMaybe $ optTabSize opts

base <- getCurrentDirectory

files <- if not $ null nonOpts
Expand Down Expand Up @@ -180,13 +203,13 @@ main = do
files1 <- getDirectoryFilesIgnore base incPatterns excPatterns
return (nubOrd (files0 ++ files1))

changes <- mapM (fix mode verbose) files
changes <- mapM (fix mode verbose tabSize) files

when (or changes && mode == Check) exitFailure

fix :: Mode -> Verbose -> FilePath -> IO Bool
fix mode verbose f =
checkFile f >>= \case
fix :: Mode -> Verbose -> TabSize -> FilePath -> IO Bool
fix mode verbose tabSize f =
checkFile tabSize f >>= \case

CheckOK -> do
when verbose $
Expand Down Expand Up @@ -223,19 +246,22 @@ data CheckResult
-- | Check a file against the whitespace policy,
-- returning a fix if violations occurred.

checkFile :: FilePath -> IO CheckResult
checkFile f =
checkFile :: TabSize -> FilePath -> IO CheckResult
checkFile tabSize f =
handle (\ (e :: IOException) -> return $ CheckIOError e) $
withFile f ReadMode $ \ h -> do
hSetEncoding h utf8
s <- Text.hGetContents h
let s' = transform s
let s' = transform tabSize s
return $ if s' == s then CheckOK else CheckViolation s'

-- | Transforms the contents of a file.

transform :: Text -> Text
transform =
transform
:: TabSize -- ^ Expand tab characters to so many spaces. Keep tabs if @<= 0@.
-> Text -- ^ Text before transformation.
-> Text -- ^ Text after transformation.
transform tabSize =
Text.unlines .
removeFinalEmptyLinesExceptOne .
map (removeTrailingWhitespace . convertTabs) .
Expand All @@ -247,12 +273,12 @@ transform =
removeTrailingWhitespace =
Text.dropWhileEnd ((`elem` [Space,Format]) . generalCategory)

convertTabs =
convertTabs = if tabSize <= 0 then id else
Text.pack . reverse . fst . foldl convertOne ([], 0) . Text.unpack

convertOne (a, p) '\t' = (addSpaces n a, p + n)
where
n = 8 - p `mod` 8
n = tabSize - p `mod` tabSize -- Here, tabSize > 0 is guaranteed
convertOne (a, p) c = (c:a, p+1)

addSpaces :: Int -> String -> String
Expand Down
5 changes: 3 additions & 2 deletions fix-whitespace.cabal
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
name: fix-whitespace
version: 0.0.8
version: 0.0.9
cabal-version: 1.24
build-type: Simple
description: Removes trailing whitespace, lines containing only whitespace and ensure that every file ends in a newline character.
description: Removes trailing whitespace, lines containing only whitespace, expands tabs,
and ensures that every file ends in a newline character.
license: OtherLicense
license-file: LICENSE
author: fix-whitespace was originally written by Nils Anders Danielsson as part of Agda 2 with contributions from Ulf Norell, Andrés Sicard-Ramírez, Andreas Abel, Philipp Hausmann, Jesper Cockx, Vlad Semenov, and Liang-Ting Chen.
Expand Down

0 comments on commit 3ebe85c

Please sign in to comment.