From ca9c8975ed671112fdfce94f2e9e2ad3de480c9a Mon Sep 17 00:00:00 2001
From: piegames <git@piegames.de>
Date: Mon, 25 Sep 2023 17:32:43 +0200
Subject: [PATCH] Don't touch files if they don't need changing

Fixes #88
---
 CHANGELOG.md |  1 +
 main/Main.hs | 15 +++++++++------
 2 files changed, 10 insertions(+), 6 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 0b1f3b6a..a04cd703 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -11,6 +11,7 @@
 
 * Fix escaping of interpolations after dollar signs.
 * Fix nixfmt trying to allocate temp files that aren't used.
+* Don't write if files didn't change, fixing treefmt compatibility
 * Nixfmt now accepts the '-' argument to read from stdin.
 * `nixfmt [dir]` now recursively formats nix files in that directory.
 * Float and int literal parsing now matches nix.
diff --git a/main/Main.hs b/main/Main.hs
index 5b1a3cef..018ff5d1 100644
--- a/main/Main.hs
+++ b/main/Main.hs
@@ -64,7 +64,8 @@ options =
 data Target = Target
     { tDoRead :: IO Text
     , tPath :: FilePath
-    , tDoWrite :: Text -> IO ()
+      -- The bool is true when the formatted file differs from the input
+    , tDoWrite :: Bool -> Text -> IO ()
     }
 
 -- | Recursively collect nix files in a directory
@@ -84,8 +85,8 @@ collectAllNixFiles paths = concat <$> mapM collectNixFiles paths
 formatTarget :: Formatter -> Target -> IO Result
 formatTarget format Target{tDoRead, tPath, tDoWrite} = do
     contents <- tDoRead
-    let formatted = format tPath contents
-    mapM tDoWrite formatted
+    let formatResult = format tPath contents
+    mapM (\formatted -> tDoWrite (formatted /= contents) formatted) formatResult
 
 -- | Return an error if target could not be parsed or was not formatted
 -- correctly.
@@ -99,17 +100,19 @@ checkTarget format Target{tDoRead, tPath} = do
             | otherwise             -> Left $ tPath ++ ": not formatted"
 
 stdioTarget :: Target
-stdioTarget = Target TextIO.getContents "<stdin>" TextIO.putStr
+stdioTarget = Target TextIO.getContents "<stdin>" (const $ TextIO.putStr)
 
 fileTarget :: FilePath -> Target
 fileTarget path = Target (readFileUtf8 path) path atomicWriteFile
   where
-    atomicWriteFile t = withOutputFile path $ \h -> do
+    atomicWriteFile True t = withOutputFile path $ \h -> do
       hSetEncoding h utf8
       TextIO.hPutStr h t
+    -- Don't do anything if the file is already formatted
+    atomicWriteFile False _ = mempty
 
 checkFileTarget :: FilePath -> Target
-checkFileTarget path = Target (readFileUtf8 path) path (const $ pure ())
+checkFileTarget path = Target (readFileUtf8 path) path (const $ const $ pure ())
 
 toTargets :: Nixfmt -> IO [Target]
 toTargets Nixfmt{ files = [] }    = pure [stdioTarget]