helpers: Consolidate MakeSegment vs MakePathSanitized
authorBjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>
Wed, 3 Oct 2018 08:14:45 +0000 (10:14 +0200)
committerBjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>
Wed, 3 Oct 2018 13:55:25 +0000 (15:55 +0200)
In short:

* Avoid double tolower in MakeSegment
* Use MakePathSanitized for taxonomies in pageToPermalinkTitle; this matches what MakeSegment does.
* Move the "double hyphen and space" logic into UnicodeSanitize

The last bullet may be slightly breaking for some that now does not get the "--" in some URLs, but we need to reduce the amount of URL logic.

See #4926

helpers/path.go
helpers/path_test.go
hugolib/permalinks.go

index 1549df40429294ed6c24e4870c0e6e5c1e687c8d..4463b89251f722c8c736d0d37cadc15ddcfe18c2 100644 (file)
@@ -81,26 +81,8 @@ var segmentReplacer = strings.NewReplacer("/", "-", "#", "-")
 // segment.  MakeSegment is similar to MakePath but disallows the '/' and
 // '#' characters because of their reserved meaning in URIs.
 func (p *PathSpec) MakeSegment(s string) string {
-       s = p.MakePathSanitized(strings.Trim(segmentReplacer.Replace(s), "- "))
+       return p.MakePathSanitized(segmentReplacer.Replace(s))
 
-       var pos int
-       var last byte
-       b := make([]byte, len(s))
-
-       for i := 0; i < len(s); i++ {
-               // consolidate dashes
-               if s[i] == '-' && last == '-' {
-                       continue
-               }
-
-               b[pos], last = s[i], s[i]
-               pos++
-       }
-
-       if p.DisablePathToLower {
-               return string(b[:pos])
-       }
-       return strings.ToLower(string(b[:pos]))
 }
 
 // MakePath takes a string with any characters and replace it
@@ -109,7 +91,7 @@ func (p *PathSpec) MakeSegment(s string) string {
 // whilst preserving the original casing of the string.
 // E.g. Social Media -> Social-Media
 func (p *PathSpec) MakePath(s string) string {
-       return p.UnicodeSanitize(strings.Replace(strings.TrimSpace(s), " ", "-", -1))
+       return p.UnicodeSanitize(s)
 }
 
 // MakePathSanitized creates a Unicode-sanitized string, with the spaces replaced
@@ -148,15 +130,25 @@ func ishex(c rune) bool {
 // a predefined set of special Unicode characters.
 // If RemovePathAccents configuration flag is enabled, Uniccode accents
 // are also removed.
+// Spaces will be replaced with a single hyphen, and sequential hyphens will be reduced to one.
 func (p *PathSpec) UnicodeSanitize(s string) string {
        source := []rune(s)
        target := make([]rune, 0, len(source))
+       var prependHyphen bool
 
        for i, r := range source {
-               if r == '%' && i+2 < len(source) && ishex(source[i+1]) && ishex(source[i+2]) {
-                       target = append(target, r)
-               } else if unicode.IsLetter(r) || unicode.IsDigit(r) || unicode.IsMark(r) || r == '.' || r == '/' || r == '\\' || r == '_' || r == '-' || r == '#' || r == '+' || r == '~' {
+               isAllowed := r == '.' || r == '/' || r == '\\' || r == '_' || r == '#' || r == '+' || r == '~'
+               isAllowed = isAllowed || unicode.IsLetter(r) || unicode.IsDigit(r) || unicode.IsMark(r)
+               isAllowed = isAllowed || (r == '%' && i+2 < len(source) && ishex(source[i+1]) && ishex(source[i+2]))
+
+               if isAllowed {
+                       if prependHyphen {
+                               target = append(target, '-')
+                               prependHyphen = false
+                       }
                        target = append(target, r)
+               } else if len(target) > 0 && (r == '-' || unicode.IsSpace(r)) {
+                       prependHyphen = true
                }
        }
 
index a97e3d5077c035c4b702267052df5763e01266c1..a1110b094ad99e389db20e3959c8f21e6e747fd0 100644 (file)
@@ -51,7 +51,8 @@ func TestMakeSegment(t *testing.T) {
                {"Your #1 Fan", "your-1-fan"},
                {"Red & Blue", "red-blue"},
                {"double//slash", "double-slash"},
-               {"My // Taxonomy", "my-taxonomy"},
+               {"triple///slash", "triple-slash"},
+               {"-my/way-", "my-way"},
        }
 
        for _, test := range tests {
index c452cf55d68a365f30d1ef55d0e573bcc79e9e66..f306f494d101897228954593b52a9cde702717cc 100644 (file)
@@ -152,10 +152,10 @@ func pageToPermalinkDate(p *Page, dateField string) (string, error) {
 
 // pageToPermalinkTitle returns the URL-safe form of the title
 func pageToPermalinkTitle(p *Page, _ string) (string, error) {
-       if p.Kind == "taxonomy" {
+       if p.Kind == KindTaxonomy {
                // Taxonomies are allowed to have '/' characters, so don't normalize
                // them with MakeSegment.
-               return p.s.PathSpec.URLize(p.title), nil
+               return p.s.PathSpec.MakePathSanitized(p.title), nil
        }
 
        return p.s.PathSpec.MakeSegment(p.title), nil