mirror of
				https://github.com/moby/moby.git
				synced 2022-11-09 12:21:53 -05:00 
			
		
		
		
	Implement stringutils.Ellipsis()
This patch implements an Ellipsis utility to append an ellipsis (...) when truncating strings in output. It also fixes the existing Truncate() utility to be compatible with unicode/multibyte characters. Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
This commit is contained in:
		
							parent
							
								
									ed1a313d8f
								
							
						
					
					
						commit
						51dc35cf23
					
				
					 7 changed files with 52 additions and 22 deletions
				
			
		| 
						 | 
				
			
			@ -124,7 +124,7 @@ func (c *containerContext) Command() string {
 | 
			
		|||
	c.addHeader(commandHeader)
 | 
			
		||||
	command := c.c.Command
 | 
			
		||||
	if c.trunc {
 | 
			
		||||
		command = stringutils.Truncate(command, 20)
 | 
			
		||||
		command = stringutils.Ellipsis(command, 20)
 | 
			
		||||
	}
 | 
			
		||||
	return strconv.Quote(command)
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -200,7 +200,7 @@ func (c *containerContext) Mounts() string {
 | 
			
		|||
			name = m.Name
 | 
			
		||||
		}
 | 
			
		||||
		if c.trunc {
 | 
			
		||||
			name = stringutils.Truncate(name, 15)
 | 
			
		||||
			name = stringutils.Ellipsis(name, 15)
 | 
			
		||||
		}
 | 
			
		||||
		mounts = append(mounts, name)
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -60,12 +60,12 @@ func TestContainerPsContext(t *testing.T) {
 | 
			
		|||
		{types.Container{
 | 
			
		||||
			Mounts: []types.MountPoint{
 | 
			
		||||
				{
 | 
			
		||||
					Name:   "733908409c91817de8e92b0096373245f329f19a88e2c849f02460e9b3d1c203",
 | 
			
		||||
					Name:   "this-is-a-long-volume-name-and-will-be-truncated-if-trunc-is-set",
 | 
			
		||||
					Driver: "local",
 | 
			
		||||
					Source: "/a/path",
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
		}, true, "733908409c91817", mountsHeader, ctx.Mounts},
 | 
			
		||||
		}, true, "this-is-a-lo...", mountsHeader, ctx.Mounts},
 | 
			
		||||
		{types.Container{
 | 
			
		||||
			Mounts: []types.MountPoint{
 | 
			
		||||
				{
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -79,8 +79,8 @@ func runHistory(dockerCli *client.DockerCli, opts historyOptions) error {
 | 
			
		|||
	for _, entry := range history {
 | 
			
		||||
		imageID = entry.ID
 | 
			
		||||
		createdBy = strings.Replace(entry.CreatedBy, "\t", " ", -1)
 | 
			
		||||
		if opts.noTrunc == false {
 | 
			
		||||
			createdBy = stringutils.Truncate(createdBy, 45)
 | 
			
		||||
		if !opts.noTrunc {
 | 
			
		||||
			createdBy = stringutils.Ellipsis(createdBy, 45)
 | 
			
		||||
			imageID = stringid.TruncateID(entry.ID)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -109,8 +109,8 @@ func runSearch(dockerCli *client.DockerCli, opts searchOptions) error {
 | 
			
		|||
		}
 | 
			
		||||
		desc := strings.Replace(res.Description, "\n", " ", -1)
 | 
			
		||||
		desc = strings.Replace(desc, "\r", " ", -1)
 | 
			
		||||
		if !opts.noTrunc && len(desc) > 45 {
 | 
			
		||||
			desc = stringutils.Truncate(desc, 42) + "..."
 | 
			
		||||
		if !opts.noTrunc {
 | 
			
		||||
			desc = stringutils.Ellipsis(desc, 45)
 | 
			
		||||
		}
 | 
			
		||||
		fmt.Fprintf(w, "%s\t%s\t%d\t", res.Name, desc, res.StarCount)
 | 
			
		||||
		if res.IsOfficial {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -51,8 +51,8 @@ func runList(dockerCli *client.DockerCli, opts listOptions) error {
 | 
			
		|||
	for _, p := range plugins {
 | 
			
		||||
		desc := strings.Replace(p.Manifest.Description, "\n", " ", -1)
 | 
			
		||||
		desc = strings.Replace(desc, "\r", " ", -1)
 | 
			
		||||
		if !opts.noTrunc && len(desc) > 45 {
 | 
			
		||||
			desc = stringutils.Truncate(desc, 42) + "..."
 | 
			
		||||
		if !opts.noTrunc {
 | 
			
		||||
			desc = stringutils.Ellipsis(desc, 45)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		fmt.Fprintf(w, "%s\t%s\t%s\t%v\n", p.Name, p.Tag, desc, p.Active)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -32,12 +32,26 @@ func GenerateRandomASCIIString(n int) string {
 | 
			
		|||
	return string(res)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Truncate truncates a string to maxlen.
 | 
			
		||||
func Truncate(s string, maxlen int) string {
 | 
			
		||||
	if len(s) <= maxlen {
 | 
			
		||||
// Ellipsis truncates a string to fit within maxlen, and appends ellipsis (...).
 | 
			
		||||
// For maxlen of 3 and lower, no ellipsis is appended.
 | 
			
		||||
func Ellipsis(s string, maxlen int) string {
 | 
			
		||||
	r := []rune(s)
 | 
			
		||||
	if len(r) <= maxlen {
 | 
			
		||||
		return s
 | 
			
		||||
	}
 | 
			
		||||
	return s[:maxlen]
 | 
			
		||||
	if maxlen <= 3 {
 | 
			
		||||
		return string(r[:maxlen])
 | 
			
		||||
	}
 | 
			
		||||
	return string(r[:maxlen-3]) + "..."
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Truncate truncates a string to maxlen.
 | 
			
		||||
func Truncate(s string, maxlen int) string {
 | 
			
		||||
	r := []rune(s)
 | 
			
		||||
	if len(r) <= maxlen {
 | 
			
		||||
		return s
 | 
			
		||||
	}
 | 
			
		||||
	return string(r[:maxlen])
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// InSlice tests whether a string is contained in a slice of strings or not.
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -57,24 +57,40 @@ func TestGenerateRandomAsciiStringIsAscii(t *testing.T) {
 | 
			
		|||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestEllipsis(t *testing.T) {
 | 
			
		||||
	str := "t🐳ststring"
 | 
			
		||||
	newstr := Ellipsis(str, 3)
 | 
			
		||||
	if newstr != "t🐳s" {
 | 
			
		||||
		t.Fatalf("Expected t🐳s, got %s", newstr)
 | 
			
		||||
	}
 | 
			
		||||
	newstr = Ellipsis(str, 8)
 | 
			
		||||
	if newstr != "t🐳sts..." {
 | 
			
		||||
		t.Fatalf("Expected tests..., got %s", newstr)
 | 
			
		||||
	}
 | 
			
		||||
	newstr = Ellipsis(str, 20)
 | 
			
		||||
	if newstr != "t🐳ststring" {
 | 
			
		||||
		t.Fatalf("Expected t🐳ststring, got %s", newstr)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestTruncate(t *testing.T) {
 | 
			
		||||
	str := "teststring"
 | 
			
		||||
	str := "t🐳ststring"
 | 
			
		||||
	newstr := Truncate(str, 4)
 | 
			
		||||
	if newstr != "test" {
 | 
			
		||||
		t.Fatalf("Expected test, got %s", newstr)
 | 
			
		||||
	if newstr != "t🐳st" {
 | 
			
		||||
		t.Fatalf("Expected t🐳st, got %s", newstr)
 | 
			
		||||
	}
 | 
			
		||||
	newstr = Truncate(str, 20)
 | 
			
		||||
	if newstr != "teststring" {
 | 
			
		||||
		t.Fatalf("Expected teststring, got %s", newstr)
 | 
			
		||||
	if newstr != "t🐳ststring" {
 | 
			
		||||
		t.Fatalf("Expected t🐳ststring, got %s", newstr)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestInSlice(t *testing.T) {
 | 
			
		||||
	slice := []string{"test", "in", "slice"}
 | 
			
		||||
	slice := []string{"t🐳st", "in", "slice"}
 | 
			
		||||
 | 
			
		||||
	test := InSlice(slice, "test")
 | 
			
		||||
	test := InSlice(slice, "t🐳st")
 | 
			
		||||
	if !test {
 | 
			
		||||
		t.Fatalf("Expected string test to be in slice")
 | 
			
		||||
		t.Fatalf("Expected string t🐳st to be in slice")
 | 
			
		||||
	}
 | 
			
		||||
	test = InSlice(slice, "SLICE")
 | 
			
		||||
	if !test {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue