rewrite it in haskell

This commit is contained in:
Sridhar Ratnakumar 2025-10-13 16:53:56 -04:00
parent 79825b9c21
commit dcc45af9f0

View file

@ -2,6 +2,7 @@
# `git diff HEAD` to show both staged and unstaged changes. Useful for
# monitoring code changes made by LLMs in real-time without manually restarting
# the diff viewer.
{ writers, haskellPackages, git, coreutils, ... }:
writers.writeHaskellBin "git-changes"
@ -16,48 +17,69 @@ writers.writeHaskellBin "git-changes"
import System.FSNotify
import Control.Concurrent
import Control.Monad
import System.Process
import System.Process (system)
import System.IO
import Data.List (isInfixOf)
import System.Exit (ExitCode(..))
import Control.Exception (catch, SomeException)
loadFromBins ["${git}", "${coreutils}"]
main :: IO ()
main = do
hSetBuffering stdout NoBuffering
hSetBuffering stderr NoBuffering
hPutStrLn stderr "[git-changes] Starting..."
-- Use a simple approach: just run git diff in foreground, restart when files change
runningRef <- newMVar False
-- Start initial git diff
diffRef <- newMVar Nothing
let runDiff = do
-- Kill previous diff if running
oldProc <- takeMVar diffRef
case oldProc of
Just ph -> do
terminateProcess ph
void $ waitForProcess ph
Nothing -> return ()
-- Start new git diff
ph <- spawnCommand "${git}/bin/git diff HEAD"
putMVar diffRef (Just ph)
-- Don't restart if already running
isRunning <- tryTakeMVar runningRef
case isRunning of
Just True -> do
hPutStrLn stderr "[git-changes] Diff already running, skipping..."
putMVar runningRef True
return ()
_ -> do
putMVar runningRef True
hPutStrLn stderr "[git-changes] Running git diff..."
-- Run git diff - this blocks until it exits
exitCode <- system "${git}/bin/git diff HEAD"
void $ takeMVar runningRef
hPutStrLn stderr $ "[git-changes] Git diff exited with: " ++ show exitCode
-- If user quit successfully, exit the program
case exitCode of
ExitSuccess -> error "User quit"
_ -> return ()
-- Run initial diff
runDiff
-- Run initial diff in a thread
diffThread <- forkIO runDiff
-- Watch for file changes
withManager $ \mgr -> do
-- Fork a thread to watch for file changes
hPutStrLn stderr "[git-changes] Starting file watcher..."
void $ forkIO $ withManager $ \mgr -> do
_ <- watchTree
mgr
"."
(\event -> case event of
_ -> let path = eventPath event
in not (".git" `isInfixOf` path)
)
(\_ -> do
putStrLn "File changed, restarting diff..."
runDiff
)
(\event -> let path = eventPath event
in not (".git" `isInfixOf` path))
(\event -> do
hPutStrLn stderr $ "[git-changes] File changed: " ++ eventPath event
-- Kill the current diff thread
killThread diffThread
void $ takeMVar runningRef
-- Start a new one
void $ forkIO runDiff)
-- Keep running
forever $ threadDelay 1000000
hPutStrLn stderr "[git-changes] Waiting for user to quit..."
-- Wait for the diff thread to finish
threadDelay maxBound
''