completion: complete tags with git tag --delete/--verify
[gitweb.git] / refs.c
diff --git a/refs.c b/refs.c
index 339d4318ee4500ffeb26426bdf9976979ecf739a..20ba82b4343ff2ef72cea32deec8a8d7fbd6def7 100644 (file)
--- a/refs.c
+++ b/refs.c
@@ -242,6 +242,50 @@ int ref_exists(const char *refname)
        return !!resolve_ref_unsafe(refname, RESOLVE_REF_READING, NULL, NULL);
 }
 
+static int match_ref_pattern(const char *refname,
+                            const struct string_list_item *item)
+{
+       int matched = 0;
+       if (item->util == NULL) {
+               if (!wildmatch(item->string, refname, 0))
+                       matched = 1;
+       } else {
+               const char *rest;
+               if (skip_prefix(refname, item->string, &rest) &&
+                   (!*rest || *rest == '/'))
+                       matched = 1;
+       }
+       return matched;
+}
+
+int ref_filter_match(const char *refname,
+                    const struct string_list *include_patterns,
+                    const struct string_list *exclude_patterns)
+{
+       struct string_list_item *item;
+
+       if (exclude_patterns && exclude_patterns->nr) {
+               for_each_string_list_item(item, exclude_patterns) {
+                       if (match_ref_pattern(refname, item))
+                               return 0;
+               }
+       }
+
+       if (include_patterns && include_patterns->nr) {
+               int found = 0;
+               for_each_string_list_item(item, include_patterns) {
+                       if (match_ref_pattern(refname, item)) {
+                               found = 1;
+                               break;
+                       }
+               }
+
+               if (!found)
+                       return 0;
+       }
+       return 1;
+}
+
 static int filter_refs(const char *refname, const struct object_id *oid,
                           int flags, void *data)
 {
@@ -369,6 +413,27 @@ int head_ref_namespaced(each_ref_fn fn, void *cb_data)
        return ret;
 }
 
+void normalize_glob_ref(struct string_list_item *item, const char *prefix,
+                       const char *pattern)
+{
+       struct strbuf normalized_pattern = STRBUF_INIT;
+
+       if (*pattern == '/')
+               BUG("pattern must not start with '/'");
+
+       if (prefix) {
+               strbuf_addstr(&normalized_pattern, prefix);
+       }
+       else if (!starts_with(pattern, "refs/"))
+               strbuf_addstr(&normalized_pattern, "refs/");
+       strbuf_addstr(&normalized_pattern, pattern);
+       strbuf_strip_suffix(&normalized_pattern, "/");
+
+       item->string = strbuf_detach(&normalized_pattern, NULL);
+       item->util = has_glob_specials(pattern) ? NULL : item->string;
+       strbuf_release(&normalized_pattern);
+}
+
 int for_each_glob_ref_in(each_ref_fn fn, const char *pattern,
        const char *prefix, void *cb_data)
 {