Add json1 format that ignores tabs

The new json1 format works just like json except that it treats tabs as
single characters instead of 8-character tabstops.

The main use case is to allow editors to pass -fjson1 so that they can
consume the json output in a character-oriented way without breaking
backwards compatibility.

Also addresses #1048.
This commit is contained in:
Benjamin Gordon 2019-05-07 15:49:34 -06:00
parent 5fb1da6814
commit 50af8aba29
5 changed files with 33 additions and 7 deletions

View File

@ -7,6 +7,7 @@
Enable with `-o` flags or `enable=name` directives Enable with `-o` flags or `enable=name` directives
- Source paths: Use `-P dir1:dir2` or a `source-path=dir1` directive - Source paths: Use `-P dir1:dir2` or a `source-path=dir1` directive
to specify search paths for sourced files. to specify search paths for sourced files.
- json1 format like --format=json but treats tabs as single characters
- SC2249: Warn about `case` with missing default case (verbose) - SC2249: Warn about `case` with missing default case (verbose)
- SC2248: Warn about unquoted variables without special chars (verbose) - SC2248: Warn about unquoted variables without special chars (verbose)
- SC2247: Warn about $"(cmd)" and $"{var}" - SC2247: Warn about $"(cmd)" and $"{var}"

View File

@ -153,7 +153,7 @@ not warn at all, as `ksh` supports decimals in arithmetic contexts.
: Json is a popular serialization format that is more suitable for web : Json is a popular serialization format that is more suitable for web
applications. ShellCheck's json is compact and contains only the bare applications. ShellCheck's json is compact and contains only the bare
minimum. minimum. Tabs are 8 characters.
[ [
{ {
@ -167,6 +167,11 @@ not warn at all, as `ksh` supports decimals in arithmetic contexts.
... ...
] ]
**json1**
: This is the same as shellcheck's json format, but tabs are treated as
single characters instead of 8-character tabstops.
*quiet* *quiet*
: Suppress all normal output. Exit with zero if no issues are found, : Suppress all normal output. Exit with zero if no issues are found,

View File

@ -141,7 +141,8 @@ formats :: FormatterOptions -> Map.Map String (IO Formatter)
formats options = Map.fromList [ formats options = Map.fromList [
("checkstyle", ShellCheck.Formatter.CheckStyle.format), ("checkstyle", ShellCheck.Formatter.CheckStyle.format),
("gcc", ShellCheck.Formatter.GCC.format), ("gcc", ShellCheck.Formatter.GCC.format),
("json", ShellCheck.Formatter.JSON.format), ("json", ShellCheck.Formatter.JSON.format False), -- JSON with 8-char tabs
("json1", ShellCheck.Formatter.JSON.format True), -- JSON with 1-char tabs
("tty", ShellCheck.Formatter.TTY.format options), ("tty", ShellCheck.Formatter.TTY.format options),
("quiet", ShellCheck.Formatter.Quiet.format options) ("quiet", ShellCheck.Formatter.Quiet.format options)
] ]

View File

@ -22,6 +22,7 @@ module ShellCheck.Formatter.Format where
import ShellCheck.Data import ShellCheck.Data
import ShellCheck.Interface import ShellCheck.Interface
import ShellCheck.Fixer import ShellCheck.Fixer
import Control.Monad
import Data.Array import Data.Array
-- A formatter that carries along an arbitrary piece of data -- A formatter that carries along an arbitrary piece of data
@ -54,5 +55,10 @@ makeNonVirtual comments contents =
where where
list = lines contents list = lines contents
arr = listArray (1, length list) list arr = listArray (1, length list) list
fix c = removeTabStops c arr untabbedFix f = newFix {
fixReplacements = map (\r -> removeTabStops r arr) (fixReplacements f)
}
fix c = (removeTabStops c arr) {
pcFix = liftM untabbedFix (pcFix c)
}

View File

@ -30,11 +30,12 @@ import GHC.Exts
import System.IO import System.IO
import qualified Data.ByteString.Lazy.Char8 as BL import qualified Data.ByteString.Lazy.Char8 as BL
format = do format :: Bool -> IO Formatter
format removeTabs = do
ref <- newIORef [] ref <- newIORef []
return Formatter { return Formatter {
header = return (), header = return (),
onResult = collectResult ref, onResult = collectResult removeTabs ref,
onFailure = outputError, onFailure = outputError,
footer = finish ref footer = finish ref
} }
@ -96,8 +97,20 @@ instance ToJSON Fix where
] ]
outputError file msg = hPutStrLn stderr $ file ++ ": " ++ msg outputError file msg = hPutStrLn stderr $ file ++ ": " ++ msg
collectResult ref result _ =
modifyIORef ref (\x -> crComments result ++ x) collectResult removeTabs ref cr sys = mapM_ f groups
where
comments = crComments cr
groups = groupWith sourceFile comments
f :: [PositionedComment] -> IO ()
f group = do
let filename = sourceFile (head group)
result <- siReadFile sys filename
let contents = either (const "") id result
let comments' = if removeTabs
then makeNonVirtual comments contents
else comments
modifyIORef ref (\x -> comments' ++ x)
finish ref = do finish ref = do
list <- readIORef ref list <- readIORef ref