25
25
#include "git-status-command.h"
27
#define STATUS_REGEX "(modified|new file|deleted|unmerged|both modified|both added|both deleted): (.*)"
28
#define UNTRACKED_FILES_REGEX "(?:#\\t)(.*)"
29
#define SECTION_COMMIT_REGEX "Changes to be committed:"
30
#define SECTION_NOT_UPDATED_REGEX "Changed but not updated:|Changes not staged for commit:"
31
#define SECTION_UNTRACKED_REGEX "Untracked files:"
27
#define STATUS_REGEX "((M|A|D|U|\\?|\\s){2}) (.*)"
33
29
struct _GitStatusCommandPriv
35
31
GQueue *status_queue;
36
GHashTable *path_lookup_table;
37
32
GitStatusSections sections;
38
GitStatusSections current_section;
39
GRegex *current_section_regex;
33
GHashTable *status_codes;
34
GHashTable *conflict_codes;
40
35
GRegex *status_regex;
41
GRegex *untracked_files_regex;
42
GRegex *section_commit_regex;
43
GRegex *section_not_updated_regex;
44
GRegex *section_untracked_regex;
45
36
GFileMonitor *head_monitor;
46
37
GFileMonitor *index_monitor;
68
60
self = GIT_STATUS_COMMAND (git_command);
70
/* See if the section has changed */
71
if (g_regex_match (self->priv->section_commit_regex, output, 0, NULL))
73
self->priv->current_section = GIT_STATUS_SECTION_COMMIT;
74
self->priv->current_section_regex = self->priv->status_regex;
77
else if (g_regex_match (self->priv->section_not_updated_regex, output, 0,
80
self->priv->current_section = GIT_STATUS_SECTION_NOT_UPDATED;
81
self->priv->current_section_regex = self->priv->status_regex;
84
else if (g_regex_match (self->priv->section_untracked_regex, output, 0,
87
self->priv->current_section = GIT_STATUS_SECTION_UNTRACKED;
88
self->priv->current_section_regex = self->priv->untracked_files_regex;
92
if (self->priv->sections & self->priv->current_section)
94
if (g_regex_match (self->priv->current_section_regex, output, 0,
97
if (self->priv->current_section_regex == self->priv->status_regex)
99
status = g_match_info_fetch (match_info, 1);
100
path = g_match_info_fetch (match_info, 2);
63
if (g_regex_match (self->priv->status_regex, output, 0, &match_info))
65
/* Determine which section this entry goes in */
66
status = g_match_info_fetch (match_info, 1);
67
path = g_match_info_fetch (match_info, 3);
71
/* Changed but not updated */
72
if (self->priv->sections & GIT_STATUS_SECTION_NOT_UPDATED)
74
status_object = git_status_new(path,
75
GPOINTER_TO_INT (g_hash_table_lookup (self->priv->status_codes,
76
GINT_TO_POINTER (status[1]))));
79
else if (status[1] == ' ')
82
if (self->priv->sections & GIT_STATUS_SECTION_COMMIT)
84
status_object = git_status_new(path,
85
GPOINTER_TO_INT (g_hash_table_lookup (self->priv->status_codes,
86
GINT_TO_POINTER (status[0]))));
91
/* File may have been added to the index and then changed again in
92
* the working tree, or it could be a conflict */
94
/* Unversioned files */
97
if (self->priv->sections & GIT_STATUS_SECTION_UNTRACKED)
99
status_object = git_status_new(path,
100
ANJUTA_VCS_STATUS_UNVERSIONED);
103
else if (g_hash_table_lookup_extended (self->priv->conflict_codes, status,
106
/* Conflicts are put in the changed but not updated section */
107
if (self->priv->sections & GIT_STATUS_SECTION_NOT_UPDATED)
109
status_object = git_status_new (path,
110
ANJUTA_VCS_STATUS_CONFLICTED);
104
status = g_strdup ("untracked");
105
path = g_match_info_fetch (match_info, 1);
108
/* Git sometimes mentions paths twice in status output. This can
109
* happen, for example, where there is a conflict, in which case a
110
* path would show up as both "unmerged" and "modified." */
113
if (!g_hash_table_lookup_extended (self->priv->path_lookup_table,
116
status_object = git_status_new (path, status);
117
g_queue_push_tail (self->priv->status_queue, status_object);
118
g_hash_table_insert (self->priv->path_lookup_table,
119
g_strdup (path), NULL);
120
anjuta_command_notify_data_arrived (ANJUTA_COMMAND (git_command));
127
g_match_info_free (match_info);
115
status_object = git_status_new(path,
116
GPOINTER_TO_INT(g_hash_table_lookup (self->priv->status_codes,
117
GINT_TO_POINTER (status[0]))));
129
g_queue_push_tail (self->priv->status_queue, status_object);
130
anjuta_command_notify_data_arrived (ANJUTA_COMMAND (self));
135
g_match_info_free (match_info);
134
142
self->priv = g_new0 (GitStatusCommandPriv, 1);
135
143
self->priv->status_queue = g_queue_new ();
136
self->priv->path_lookup_table = g_hash_table_new_full (g_str_hash,
139
145
self->priv->status_regex = g_regex_new (STATUS_REGEX, 0, 0, NULL);
140
self->priv->untracked_files_regex = g_regex_new (UNTRACKED_FILES_REGEX,
142
self->priv->section_commit_regex = g_regex_new (SECTION_COMMIT_REGEX, 0, 0,
144
self->priv->section_not_updated_regex = g_regex_new (SECTION_NOT_UPDATED_REGEX,
146
self->priv->section_untracked_regex = g_regex_new (SECTION_UNTRACKED_REGEX,
146
self->priv->status_codes = g_hash_table_new (g_direct_hash, g_direct_equal);
147
self->priv->conflict_codes = g_hash_table_new (g_str_hash, g_str_equal);
149
/* Initialize status code hash tables */
150
g_hash_table_insert (self->priv->status_codes,
151
GINT_TO_POINTER ('M'),
152
GINT_TO_POINTER (ANJUTA_VCS_STATUS_MODIFIED));
154
g_hash_table_insert (self->priv->status_codes,
155
GINT_TO_POINTER ('A'),
156
GINT_TO_POINTER (ANJUTA_VCS_STATUS_ADDED));
158
g_hash_table_insert (self->priv->status_codes,
159
GINT_TO_POINTER ('D'),
160
GINT_TO_POINTER (ANJUTA_VCS_STATUS_MODIFIED));
162
/* TODO: Handle each conflict case individually so that we can eventually
163
* give the user more information about the conflict */
164
g_hash_table_insert (self->priv->conflict_codes, "DD", NULL);
165
g_hash_table_insert (self->priv->conflict_codes, "AU", NULL);
166
g_hash_table_insert (self->priv->conflict_codes, "UD", NULL);
167
g_hash_table_insert (self->priv->conflict_codes, "UA", NULL);
168
g_hash_table_insert (self->priv->conflict_codes, "DU", NULL);
169
g_hash_table_insert (self->priv->conflict_codes, "AA", NULL);
170
g_hash_table_insert (self->priv->conflict_codes, "UU", NULL);
253
276
git_status_command_clear_output (GIT_STATUS_COMMAND (command));
257
git_status_command_finished (AnjutaCommand *command, guint return_code)
259
GitStatusCommand *self;
261
self = GIT_STATUS_COMMAND (command);
263
g_hash_table_remove_all (self->priv->path_lookup_table);
265
ANJUTA_COMMAND_CLASS (git_status_command_parent_class)->command_finished (command,
270
281
git_status_command_finalize (GObject *object)
272
283
GitStatusCommand *self;
273
GList *current_status;
275
285
self = GIT_STATUS_COMMAND (object);
276
current_status = self->priv->status_queue->head;
278
287
git_status_command_clear_output (self);
279
288
git_status_command_stop_automatic_monitor (ANJUTA_COMMAND (self));
281
290
g_queue_free (self->priv->status_queue);
282
g_hash_table_destroy (self->priv->path_lookup_table);
283
291
g_regex_unref (self->priv->status_regex);
284
g_regex_unref (self->priv->untracked_files_regex);
285
g_regex_unref (self->priv->section_commit_regex);
286
g_regex_unref (self->priv->section_not_updated_regex);
287
g_regex_unref (self->priv->section_untracked_regex);
289
293
g_free (self->priv);