diff --git a/cmd/cli/main.go b/cmd/cli/main.go index cbe9e69..ec22218 100644 --- a/cmd/cli/main.go +++ b/cmd/cli/main.go @@ -517,7 +517,7 @@ func (m manager) normalMode(g *gocui.Gui, v *gocui.View) error { displayStr, _ := itm.ProduceLine(longestDateLen, longestLocationLen, longestFlagsLen, false, true) if m.s.highlightedItem == index { - // maxX * 2 because there are escape sequences that make it hard to tell the real string lenght + // maxX * 2 because there are escape sequences that make it hard to tell the real string length displayStr = searchapp.DoHighlightString(displayStr, maxX*3) if debug { log.Println("### HightlightedItem string :", displayStr) diff --git a/go.mod b/go.mod index d638d7b..0ca87cd 100644 --- a/go.mod +++ b/go.mod @@ -16,6 +16,7 @@ require ( github.com/schollz/progressbar v1.0.0 github.com/spf13/cobra v1.2.1 github.com/whilp/git-urls v1.0.0 + golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6 golang.org/x/sys v0.0.0-20210903071746-97244b99971b // indirect golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b // indirect golang.org/x/text v0.3.7 // indirect diff --git a/go.sum b/go.sum index d6835ed..60670d5 100644 --- a/go.sum +++ b/go.sum @@ -284,6 +284,7 @@ golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u0 golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= +golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6 h1:QE6XYQK6naiK1EPAe1g/ILLxN5RBoH5xkJk3CqlMI/Y= golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= diff --git a/pkg/searchapp/item.go b/pkg/searchapp/item.go index af3b685..eaff1a1 100644 --- a/pkg/searchapp/item.go +++ b/pkg/searchapp/item.go @@ -8,9 +8,11 @@ import ( "time" "github.com/curusarn/resh/pkg/records" + "golang.org/x/exp/utf8string" ) -const itemLocationLenght = 30 +const itemLocationLength = 30 +const dots = "…" // Item holds item info for normal mode type Item struct { @@ -202,17 +204,17 @@ func (i Item) DrawItemColumns(compactRendering bool, debug bool) ItemColumns { func (ic ItemColumns) ProduceLine(dateLength int, locationLength int, flagLength int, header bool, showDate bool) (string, int) { line := "" if showDate { - date := ic.Date - for len(date) < dateLength { - line += " " - date += " " - } - // TODO: use strings.Repeat - line += ic.DateWithColor + line += strings.Repeat(" ", dateLength-len(ic.Date)) + ic.DateWithColor } // LOCATION - locationWithColor := ic.HostWithColor - pwdLength := locationLength - len(ic.Host) + var locationWithColor string + // ensure that host will not take up all the space + if len(ic.Host) >= locationLength { + locationWithColor = rightCutPadString(ic.Host, locationLength / 2 - 1) + ":" + } else { + locationWithColor = ic.HostWithColor + } + pwdLength := locationLength - len(locationWithColor) if ic.samePwd { locationWithColor += highlightPwd(leftCutPadString(ic.PwdTilde, pwdLength)) } else { @@ -241,23 +243,29 @@ func (ic ItemColumns) ProduceLine(dateLength int, locationLength int, flagLength } func leftCutPadString(str string, newLen int) string { - dots := "…" - strLen := len(str) + if newLen <= 0 { + return "" + } + utf8Str := utf8string.NewString(str) + strLen := utf8Str.RuneCount() if newLen > strLen { return strings.Repeat(" ", newLen-strLen) + str } else if newLen < strLen { - return dots + str[strLen-newLen+1:] + return dots + utf8string.NewString(str).Slice(strLen-newLen+1, strLen) } return str } func rightCutPadString(str string, newLen int) string { - dots := "…" - strLen := len(str) + if newLen <= 0 { + return "" + } + utf8Str := utf8string.NewString(str) + strLen := utf8Str.RuneCount() if newLen > strLen { return str + strings.Repeat(" ", newLen-strLen) } else if newLen < strLen { - return str[:newLen-1] + dots + return utf8Str.Slice(0, newLen-1) + dots } return str } diff --git a/pkg/searchapp/item_test.go b/pkg/searchapp/item_test.go new file mode 100644 index 0000000..903157a --- /dev/null +++ b/pkg/searchapp/item_test.go @@ -0,0 +1,89 @@ +package searchapp + +import ( + "testing" +) + +// TestLeftCutPadString +func TestLeftCutPadString(t *testing.T) { + if leftCutPadString("abc", -1) != "" { + t.Fatal("Incorrect left cut from abc to '' (negative)") + } + if leftCutPadString("abc", 0) != "" { + t.Fatal("Incorrect left cut from abc to ''") + } + if leftCutPadString("abc", 1) != "…" { + t.Fatal("Incorrect left cut from abc to …") + } + if leftCutPadString("abc", 2) != "…c" { + t.Fatal("Incorrect left cut from abc to …c") + } + if leftCutPadString("abc", 3) != "abc" { + t.Fatal("Incorrect left cut from abc to abc") + } + if leftCutPadString("abc", 5) != " abc" { + t.Fatal("Incorrect left pad from abc to ' abc'") + } + + // unicode + if leftCutPadString("♥♥♥♥", -1) != "" { + t.Fatal("Incorrect left cut from ♥♥♥♥ to '' (negative)") + } + if leftCutPadString("♥♥♥♥", 0) != "" { + t.Fatal("Incorrect left cut from ♥♥♥♥ to ''") + } + if leftCutPadString("♥♥♥♥", 1) != "…" { + t.Fatal("Incorrect left cut from ♥♥♥♥ to …") + } + if leftCutPadString("♥♥♥♥", 2) != "…♥" { + t.Fatal("Incorrect left cut from ♥♥♥♥ to …♥") + } + if leftCutPadString("♥♥♥♥", 4) != "♥♥♥♥" { + t.Fatal("Incorrect left cut from ♥♥♥♥ to ♥♥♥♥") + } + if leftCutPadString("♥♥♥♥", 6) != " ♥♥♥♥" { + t.Fatal("Incorrect left pad from ♥♥♥♥ to ' ♥♥♥♥'") + } +} + +// TestRightCutPadString +func TestRightCutPadString(t *testing.T) { + if rightCutPadString("abc", -1) != "" { + t.Fatal("Incorrect right cut from abc to '' (negative)") + } + if rightCutPadString("abc", 0) != "" { + t.Fatal("Incorrect right cut from abc to ''") + } + if rightCutPadString("abc", 1) != "…" { + t.Fatal("Incorrect right cut from abc to …") + } + if rightCutPadString("abc", 2) != "a…" { + t.Fatal("Incorrect right cut from abc to a…") + } + if rightCutPadString("abc", 3) != "abc" { + t.Fatal("Incorrect right cut from abc to abc") + } + if rightCutPadString("abc", 5) != "abc " { + t.Fatal("Incorrect right pad from abc to 'abc '") + } + + // unicode + if rightCutPadString("♥♥♥♥", -1) != "" { + t.Fatal("Incorrect right cut from ♥♥♥♥ to '' (negative)") + } + if rightCutPadString("♥♥♥♥", 0) != "" { + t.Fatal("Incorrect right cut from ♥♥♥♥ to ''") + } + if rightCutPadString("♥♥♥♥", 1) != "…" { + t.Fatal("Incorrect right cut from ♥♥♥♥ to …") + } + if rightCutPadString("♥♥♥♥", 2) != "♥…" { + t.Fatal("Incorrect right cut from ♥♥♥♥ to ♥…") + } + if rightCutPadString("♥♥♥♥", 4) != "♥♥♥♥" { + t.Fatal("Incorrect right cut from ♥♥♥♥ to ♥♥♥♥") + } + if rightCutPadString("♥♥♥♥", 6) != "♥♥♥♥ " { + t.Fatal("Incorrect right pad from ♥♥♥♥ to '♥♥♥♥ '") + } +}