Help us shape the future of Go! Take the 2026 Go Developer Survey

tagname

package
v0.56.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 11, 2026 License: MIT Imports: 7 Imported by: 0

Documentation

Overview

Package tagname decides what a tag is CALLED and when two tags are the SAME.

Two answers, deliberately kept apart:

  • Clean — the name a person sees. Exactly as typed, apart from the whitespace at the ends and runs of it in the middle. "Müşteri Teklifi" stays "Müşteri Teklifi".
  • Key — the identity. Two names with one Key are one tag: typing "müşteri teklifi" on a second file adds the tag the first file already carries, under the name it was first given, instead of creating a twin that differs only in capitals.

⚠⚠ Until v0.43.0 there was only one answer, `strings.ToLower`, and it was written INTO the name: "Müşteri Teklifi" was stored and shown as "müşteri teklifi" (tester, 2026-09-22). Lower-casing is a matching rule; it must not be what the person reads back.

What "the same tag" means, and why it is not strings.EqualFold

Go's case mapping (strings.ToLower, strings.EqualFold, unicode.SimpleFold) is the Unicode DEFAULT, which is wrong for Turkish in exactly the letters a Turkish user types most: the default lower case of `I` is `i`, but in Turkish it is `ı`; `İ` has no simple fold partner at all. So under the default rules "IŞIK" and "ışık" (the same word) are different tags, and under the Turkish rules "INVOICE" and "invoice" are different tags for everyone else. No single locale's casing is right for a tag vocabulary that people with different keyboards share.

Key therefore treats the four Latin i's — I, ı, İ, i — as ONE letter, and applies full Unicode case folding to everything else:

"IŞIK" = "ışık" = "Işık"             (Turkish, either keyboard)
"İSTANBUL" = "istanbul" = "ISTANBUL" (typed with or without the dot)
"INVOICE" = "invoice"                (English)
"STRASSE" = "Straße"                 (German: full folding maps ß to ss)
"ΟΔΟΣ" = "οδος"                    (Greek: the final ς folds to σ)

The i rule and the composition below are internal/namefold's — the rule a search compares file names by — so a tag and a file name agree on what one word is. Key adds FULL case folding on top (ß = ss), which a search cannot: it compares a typed word against a name position by position.

The price is that two different Turkish words spelt apart only by the dot, such as "ılık" (lukewarm) and "ilik" (marrow), become one tag. That collision is rare in a tag vocabulary; the opposite rule would split EVERY capitalised Turkish tag typed on an English keyboard, and every English tag typed on a Turkish one. The display name is never touched, so nothing is lost on screen.

Accents stay significant: "müşteri" and "musteri", "şık" and "sık" are different words, and a person means different things by them.

Both functions normalise to NFC first. The same "ü" arrives either as one code point (most keyboards) or as "u" + a combining diaeresis (text pasted from a macOS file name); without NFC those two would be two tags that look identical on screen — the worst kind of duplicate, because nobody can see why.

Index

Constants

View Source
const MaxRunes = 64

MaxRunes is the longest tag name accepted, in characters. It was 64 BYTES until v0.43.0, which let an English tag be twice as long as a Turkish one; characters are what a person counts.

Variables

View Source
var (
	ErrEmpty   = errors.New("tag name is empty")
	ErrTooLong = errors.New("tag name is longer than 64 characters")
	ErrControl = errors.New("tag name contains a control character")
)

Errors Clean reports. The handler turns them into a 400 the client words.

Functions

func Clean

func Clean(raw string) (string, error)

Clean returns the name a person sees: NFC, trimmed, inner whitespace runs collapsed to one space. Case is PRESERVED — that is the point of this package. A control character (a newline pasted along with a word, a NUL) is refused rather than stripped: stripping would silently merge "a\nb" with "ab", and nothing on screen would explain it.

func Key

func Key(name string) string

Key is the identity of a tag name: two names with one Key are one tag. See the package comment for the rules. Key of an invalid name is still defined (it only ever compares), so callers that match against stored names need not re-validate what they read back.

func Same

func Same(a, b string) bool

Same reports whether two names are one tag.

Types

This section is empty.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL