aboutsummaryrefslogtreecommitdiff
path: root/Git/Status.hs
diff options
context:
space:
mode:
authorGravatar Joey Hess <joeyh@joeyh.name>2015-09-22 17:32:28 -0400
committerGravatar Joey Hess <joeyh@joeyh.name>2015-09-22 17:32:28 -0400
commit6dc0db8df4324497ce666231a1d458ac6ee6c9ee (patch)
tree3adccac08e5411413607d749859f5f6fbe2cc07f /Git/Status.hs
parent94e8b0e08e5a5f630eea17700294b1783b190e67 (diff)
status: Show added but not yet committed files.
Seems easy, but git ls-files can't list the right subset of files. So, I wrote a whole new parser for git status output, and converted the status command to use that. There are a few other small behavior changes. The order changed. Unlocked files show as T. In indirect mode, deleted files were not shown before, and that's fixed. Regular files checked directly into git and modified were not shown before, and are now.
Diffstat (limited to 'Git/Status.hs')
-rw-r--r--Git/Status.hs76
1 files changed, 76 insertions, 0 deletions
diff --git a/Git/Status.hs b/Git/Status.hs
new file mode 100644
index 000000000..4f9ad0265
--- /dev/null
+++ b/Git/Status.hs
@@ -0,0 +1,76 @@
+{- git status interface
+ -
+ - Copyright 2015 Joey Hess <id@joeyh.name>
+ -
+ - Licensed under the GNU GPL version 3 or higher.
+ -}
+
+module Git.Status where
+
+import Common
+import Git
+import Git.Command
+import Git.FilePath
+
+data Status
+ = Modified TopFilePath
+ | Deleted TopFilePath
+ | Added TopFilePath
+ | Renamed TopFilePath TopFilePath
+ | TypeChanged TopFilePath
+ | Untracked TopFilePath
+
+statusChar :: Status -> Char
+statusChar (Modified _) = 'M'
+statusChar (Deleted _) = 'D'
+statusChar (Added _) = 'A'
+statusChar (Renamed _ _) = 'R'
+statusChar (TypeChanged _) = 'T'
+statusChar (Untracked _) = '?'
+
+statusFile :: Status -> TopFilePath
+statusFile (Modified f) = f
+statusFile (Deleted f) = f
+statusFile (Added f) = f
+statusFile (Renamed _oldf newf) = newf
+statusFile (TypeChanged f) = f
+statusFile (Untracked f) = f
+
+parseStatusZ :: [String] -> [Status]
+parseStatusZ = go []
+ where
+ go c [] = reverse c
+ go c (x:xs) = case x of
+ (sindex:sworktree:' ':f) ->
+ -- Look at both the index and worktree status,
+ -- preferring worktree.
+ case cparse sworktree <|> cparse sindex of
+ Just mks -> go (mks (asTopFilePath f) : c) xs
+ Nothing -> if sindex == 'R'
+ -- In -z mode, the name the
+ -- file was renamed to comes
+ -- first, and the next component
+ -- is the old filename.
+ then case xs of
+ (oldf:xs') -> go (Renamed (asTopFilePath oldf) (asTopFilePath f) : c) xs'
+ _ -> go c []
+ else go c xs
+ _ -> go c xs
+
+ cparse 'M' = Just Modified
+ cparse 'A' = Just Added
+ cparse 'D' = Just Deleted
+ cparse 'T' = Just TypeChanged
+ cparse '?' = Just Untracked
+ cparse _ = Nothing
+
+getStatus :: [FilePath] -> Repo -> IO ([Status], IO Bool)
+getStatus l r = do
+ (ls, cleanup) <- pipeNullSplit params r
+ return (parseStatusZ ls, cleanup)
+ where
+ params =
+ [ Param "status"
+ , Param "-uall"
+ , Param "-z"
+ ] ++ map File l