shithub: furgit

ref: 561c3b2cf5893430d4ff63883dab818d8d6f5c3f
dir: /refstore/shorten.go/

View raw version
package refstore

import "strings"

type shortenRule struct {
	prefix string
	suffix string
}

var shortenRules = [...]shortenRule{
	{prefix: "", suffix: ""},
	{prefix: "refs/", suffix: ""},
	{prefix: "refs/tags/", suffix: ""},
	{prefix: "refs/heads/", suffix: ""},
	{prefix: "refs/remotes/", suffix: ""},
	{prefix: "refs/remotes/", suffix: "/HEAD"},
}

func (rule shortenRule) match(name string) (string, bool) {
	if !strings.HasPrefix(name, rule.prefix) {
		return "", false
	}

	if !strings.HasSuffix(name, rule.suffix) {
		return "", false
	}

	short := strings.TrimPrefix(name, rule.prefix)

	short = strings.TrimSuffix(short, rule.suffix)
	if short == "" {
		return "", false
	}

	if rule.prefix+short+rule.suffix != name {
		return "", false
	}

	return short, true
}

func (rule shortenRule) render(short string) string {
	return rule.prefix + short + rule.suffix
}

// ShortenName returns the shortest unambiguous shorthand for name among all.
//
// all must contain full reference names visible to the shortening scope.
func ShortenName(name string, all []string) string {
	names := make(map[string]struct{}, len(all))
	for _, full := range all {
		if full == "" {
			continue
		}

		names[full] = struct{}{}
	}

	for i := len(shortenRules) - 1; i > 0; i-- {
		short, ok := shortenRules[i].match(name)
		if !ok {
			continue
		}

		ambiguous := false

		for j := range shortenRules {
			if j == i {
				continue
			}

			full := shortenRules[j].render(short)
			if _, found := names[full]; found {
				ambiguous = true

				break
			}
		}

		if !ambiguous {
			return short
		}
	}

	return name
}