Skip to content

Commit ab00039

Browse files
committed
Special-case format command to delegate directly to elm-format
As suggested in PR review, the format command now bypasses Lamdera's normal CLI processing and delegates directly to elm-format's mainIO. This ensures perfect compatibility with all elm-format features and reduces code duplication. Changes: - Intercept "format" command early in Terminal.hs - Add minimal FormatDirect module that calls elm-format - Remove 244-line Format.hs implementation - Keep stub command for help display consistency
1 parent 76cdecd commit ab00039

File tree

3 files changed

+36
-255
lines changed

3 files changed

+36
-255
lines changed

extra/Lamdera/CLI.hs

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ import qualified Lamdera.CLI.Reset
1616
import qualified Lamdera.CLI.Update
1717
import qualified Lamdera.CLI.Annotate
1818
import qualified Lamdera.CLI.Interpreter
19-
import qualified Lamdera.CLI.Format
2019

2120

2221
live :: Terminal.Command
@@ -195,10 +194,22 @@ eval =
195194

196195

197196
-- FORMAT
197+
-- @LAMDERA Stub - intercepted in Terminal.hs
198198

199199

200200
format :: Terminal.Command
201-
format = Lamdera.CLI.Format.command
201+
format =
202+
let
203+
summary =
204+
"Format Elm source files."
205+
206+
details =
207+
"The `format` command is handled directly by elm-format for perfect compatibility."
208+
209+
example =
210+
reflow "See elm-format documentation at <https://github.com/avh4/elm-format>"
211+
in
212+
Terminal.Command "format" (Common summary) details example noArgs noFlags (\_ _ -> return ())
202213

203214

204215
-- HELPERS

extra/Lamdera/CLI/Format.hs

Lines changed: 6 additions & 241 deletions
Original file line numberDiff line numberDiff line change
@@ -1,244 +1,9 @@
1-
{-# LANGUAGE OverloadedStrings #-}
2-
3-
module Lamdera.CLI.Format
4-
( Format(..)
5-
, run
6-
, command
1+
module Lamdera.CLI.Format
2+
( run
73
) where
84

9-
{- `lamdera format` functionality -}
10-
11-
import qualified Data.Text as T
12-
import qualified Data.Text.IO as TIO
13-
import qualified Ext.ElmFormat as ElmFormat
14-
import qualified System.Exit as Exit
15-
import qualified System.IO as IO
16-
import Terminal hiding (args)
17-
import Terminal.Helpers
18-
import qualified Text.PrettyPrint.ANSI.Leijen as P
19-
import qualified Data.List as List
20-
import qualified System.Directory as Dir
21-
import qualified System.FilePath as FP
22-
23-
data Format = Format
24-
{ _yes :: Bool
25-
, _validate :: Bool
26-
, _stdin :: Bool
27-
, _output :: Maybe FilePath
28-
, _help :: Bool
29-
}
30-
31-
yes_ :: Parser Bool
32-
yes_ =
33-
Parser
34-
{ _singular = "yes"
35-
, _plural = "yes"
36-
, _parser = \_ -> Just True
37-
, _suggest = \_ -> return []
38-
, _examples = \_ -> return []
39-
}
40-
41-
validate_ :: Parser Bool
42-
validate_ =
43-
Parser
44-
{ _singular = "validate"
45-
, _plural = "validate"
46-
, _parser = \_ -> Just True
47-
, _suggest = \_ -> return []
48-
, _examples = \_ -> return []
49-
}
50-
51-
stdin_ :: Parser Bool
52-
stdin_ =
53-
Parser
54-
{ _singular = "stdin"
55-
, _plural = "stdin"
56-
, _parser = \_ -> Just True
57-
, _suggest = \_ -> return []
58-
, _examples = \_ -> return []
59-
}
60-
61-
output_ :: Parser FilePath
62-
output_ =
63-
Parser
64-
{ _singular = "output"
65-
, _plural = "outputs"
66-
, _parser = Just
67-
, _suggest = \_ -> return []
68-
, _examples = \_ -> return ["Main2.elm"]
69-
}
70-
71-
elmFileOrDir :: Parser FilePath
72-
elmFileOrDir =
73-
Parser
74-
{ _singular = "elm file or directory"
75-
, _plural = "elm files or directories"
76-
, _parser = Just -- Accept any path
77-
, _suggest = \_ -> return []
78-
, _examples = \_ -> return ["Main.elm", "src/Main.elm"]
79-
}
80-
81-
command :: Terminal.Command
82-
command =
83-
let
84-
summary =
85-
"Format Elm source files."
86-
87-
details =
88-
"Usage: lamdera format [INPUT] [--output FILE] [--yes] [--validate] [--stdin]\n\n" ++
89-
" Format Elm source files."
90-
91-
example =
92-
stack
93-
[ reflow "Examples:"
94-
, P.vcat [ P.indent 2 $ P.green "lamdera format Main.elm # formats Main.elm"
95-
, P.indent 2 $ P.green "lamdera format Main.elm --output Main2.elm # formats Main.elm as Main2.elm"
96-
, P.indent 2 $ P.green "lamdera format src/ # format all *.elm files in the src directory"
97-
]
98-
, reflow "Full guide to using elm-format at <https://github.com/avh4/elm-format>"
99-
]
100-
101-
formatFlags =
102-
flags Format
103-
|-- onOff "yes" "Reply 'yes' to all automated prompts."
104-
|-- onOff "validate" "Check if files are formatted without changing them."
105-
|-- onOff "stdin" "Read from stdin, output to stdout."
106-
|-- flag "output" output_ "Write output to FILE instead of overwriting the given source file."
107-
|-- onOff "help" "Show this help text."
108-
in
109-
Terminal.Command "format" (Common summary) details example (zeroOrMore elmFileOrDir) formatFlags run
110-
111-
run :: [FilePath] -> Format -> IO ()
112-
run inputs flags =
113-
if _help flags || null inputs && not (_stdin flags)
114-
then do
115-
TIO.putStrLn "Usage: lamdera format [INPUT] [--output FILE] [--yes] [--validate] [--stdin]\n"
116-
TIO.putStrLn " Format Elm source files.\n"
117-
TIO.putStrLn "Available options:"
118-
TIO.putStrLn " --help Show this help text"
119-
TIO.putStrLn " --output FILE Write output to FILE instead of overwriting the given"
120-
TIO.putStrLn " source file."
121-
TIO.putStrLn " --yes Reply 'yes' to all automated prompts."
122-
TIO.putStrLn " --validate Check if files are formatted without changing them."
123-
TIO.putStrLn " --stdin Read from stdin, output to stdout.\n"
124-
TIO.putStrLn "Examples:"
125-
TIO.putStrLn " lamdera format Main.elm # formats Main.elm"
126-
TIO.putStrLn " lamdera format Main.elm --output Main2.elm # formats Main.elm as Main2.elm"
127-
TIO.putStrLn " lamdera format src/ # format all *.elm files in the src directory\n"
128-
TIO.putStrLn "Full guide to using elm-format at <https://github.com/avh4/elm-format>"
129-
Exit.exitSuccess
130-
else case inputs of
131-
[] | _stdin flags ->
132-
do
133-
input <- TIO.hGetContents IO.stdin
134-
formatText flags input
135-
[] ->
136-
do
137-
TIO.putStrLn "Please specify at least one .elm file to format."
138-
Exit.exitFailure
139-
paths ->
140-
do
141-
elmFilePaths <- concat <$> mapM expandPath paths
142-
if null elmFilePaths
143-
then return ()
144-
else do
145-
TIO.putStrLn "This will overwrite the following files to use Elm's preferred style:\n"
146-
mapM_ (\f -> TIO.putStrLn $ " " <> T.pack f) elmFilePaths
147-
TIO.putStrLn "\nThis cannot be undone! Make sure to back up these files before proceeding.\n"
148-
if _yes flags
149-
then formatFiles flags elmFilePaths
150-
else do
151-
TIO.putStrLn "Are you sure you want to overwrite these files with formatted versions? (y/n) "
152-
answer <- getLine
153-
case answer of
154-
"Y" -> formatFiles flags elmFilePaths
155-
"y" -> formatFiles flags elmFilePaths
156-
"" -> formatFiles flags elmFilePaths
157-
_ -> return ()
158-
159-
expandPath :: FilePath -> IO [FilePath]
160-
expandPath path = do
161-
isDir <- Dir.doesDirectoryExist path
162-
if isDir
163-
then findElmFiles path
164-
else return [path | FP.isExtensionOf "elm" path]
165-
166-
formatText :: Format -> T.Text -> IO ()
167-
formatText flags input =
168-
case ElmFormat.format "stdin:nofilepath" input of
169-
Right formatted ->
170-
TIO.putStr formatted
171-
Left err ->
172-
do
173-
TIO.putStrLn $ "Error: " <> err
174-
Exit.exitFailure
175-
176-
formatFile :: Format -> FilePath -> IO ()
177-
formatFile flags path = do
178-
isDir <- Dir.doesDirectoryExist path
179-
if isDir
180-
then do
181-
elmFilePaths <- findElmFiles path
182-
if null elmFilePaths
183-
then return ()
184-
else do
185-
TIO.putStrLn "This will overwrite the following files to use Elm's preferred style:\n"
186-
mapM_ (\f -> TIO.putStrLn $ " " <> T.pack f) elmFilePaths
187-
TIO.putStrLn "\nThis cannot be undone! Make sure to back up these files before proceeding.\n"
188-
if _yes flags
189-
then formatFiles flags elmFilePaths
190-
else do
191-
TIO.putStrLn "Are you sure you want to overwrite these files with formatted versions? (y/n) "
192-
answer <- getLine
193-
case answer of
194-
"Y" -> formatFiles flags elmFilePaths
195-
"y" -> formatFiles flags elmFilePaths
196-
"" -> formatFiles flags elmFilePaths
197-
_ -> return ()
198-
else formatSingleFile flags path
199-
200-
findElmFiles :: FilePath -> IO [FilePath]
201-
findElmFiles dir = do
202-
contents <- Dir.listDirectory dir
203-
let baseName = FP.takeFileName dir
204-
if baseName `elem` ["elm-stuff", "node_modules"]
205-
then return []
206-
else do
207-
paths <- mapM (\f -> do
208-
let path = dir FP.</> f
209-
isDir <- Dir.doesDirectoryExist path
210-
if isDir
211-
then findElmFiles path
212-
else return [path | FP.isExtensionOf "elm" f]
213-
) contents
214-
return $ concat paths
215-
216-
formatFiles :: Format -> [FilePath] -> IO ()
217-
formatFiles flags = mapM_ (formatSingleFile flags)
218-
219-
formatSingleFile :: Format -> FilePath -> IO ()
220-
formatSingleFile flags path = do
221-
TIO.putStrLn $ "Processing file " <> T.pack path
222-
input <- TIO.readFile path
223-
case ElmFormat.format path input of
224-
Right formatted ->
225-
if _validate flags && formatted /= input
226-
then do
227-
TIO.putStrLn $ "File " <> T.pack path <> " would be reformatted"
228-
Exit.exitFailure
229-
else case _output flags of
230-
Just outputPath -> TIO.writeFile outputPath formatted
231-
Nothing -> TIO.writeFile path formatted
232-
Left err -> do
233-
TIO.putStrLn err
234-
if _validate flags
235-
then Exit.exitFailure
236-
else return ()
237-
238-
stack :: [P.Doc] -> P.Doc
239-
stack docs =
240-
P.vcat $ List.intersperse "" docs
5+
import qualified ElmFormat.Cli
2416

242-
reflow :: String -> P.Doc
243-
reflow string =
244-
P.fillSep $ map P.text $ words string
7+
-- | Delegate to elm-format
8+
run :: [String] -> IO ()
9+
run args = ElmFormat.Cli.mainIO args

terminal/impl/Terminal.hs

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ import qualified Terminal.Error as Error
3131

3232

3333
import qualified Lamdera.Version
34+
import qualified Lamdera.CLI.Format
3435
import qualified Sanity
3536

3637
-- COMMAND
@@ -86,21 +87,25 @@ app intro outro commands =
8687
Exit.exitSuccess
8788

8889
command : chunks ->
89-
do case List.find (\cmd -> toName cmd == command) commands of
90-
Nothing ->
91-
Error.exitWithUnknown command (map toName commands)
90+
-- @LAMDERA format intercept
91+
if command == "format" then
92+
do Lamdera.CLI.Format.run chunks
93+
else
94+
do case List.find (\cmd -> toName cmd == command) commands of
95+
Nothing ->
96+
Error.exitWithUnknown command (map toName commands)
9297

93-
Just (Command _ _ details example args_ flags_ callback) ->
94-
if elem "--help" chunks then
95-
Error.exitWithHelp (Just command) details example args_ flags_
98+
Just (Command _ _ details example args_ flags_ callback) ->
99+
if elem "--help" chunks then
100+
Error.exitWithHelp (Just command) details example args_ flags_
96101

97-
else
98-
case snd $ Chomp.chomp Nothing chunks args_ flags_ of
99-
Right (argsValue, flagsValue) ->
100-
callback argsValue flagsValue
102+
else
103+
case snd $ Chomp.chomp Nothing chunks args_ flags_ of
104+
Right (argsValue, flagsValue) ->
105+
callback argsValue flagsValue
101106

102-
Left err ->
103-
Error.exitWithError err
107+
Left err ->
108+
Error.exitWithError err
104109

105110

106111

0 commit comments

Comments
 (0)