aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
authorJason A. Donenfeld <Jason@zx2c4.com>2019-05-05 17:38:04 +0200
committerJason A. Donenfeld <Jason@zx2c4.com>2019-05-05 17:38:04 +0200
commit61da208c9571f3348eb0e11400fa54365d49a366 (patch)
treed6384ce455a01a0799d531020d6f7a2532435651
parentui: attach shortcuts to their windows (diff)
downloadwireguard-windows-61da208c9571f3348eb0e11400fa54365d49a366.tar.xz
wireguard-windows-61da208c9571f3348eb0e11400fa54365d49a366.zip
ui: use natural sorting order
-rw-r--r--conf/name.go61
-rw-r--r--conf/path_windows.go2
-rw-r--r--ui/listview.go8
-rw-r--r--ui/tray.go5
-rw-r--r--ui/tunnelspage.go3
5 files changed, 70 insertions, 9 deletions
diff --git a/conf/name.go b/conf/name.go
index 00479c04..87c463af 100644
--- a/conf/name.go
+++ b/conf/name.go
@@ -7,6 +7,7 @@ package conf
import (
"regexp"
+ "strconv"
"strings"
)
@@ -49,3 +50,63 @@ func TunnelNameIsValid(name string) bool {
}
return allowedNameFormat.MatchString(name)
}
+
+type naturalSortToken struct {
+ maybeString string
+ maybeNumber int
+}
+type naturalSortString struct {
+ originalString string
+ tokens []naturalSortToken
+}
+
+var naturalSortDigitFinder = regexp.MustCompile(`\d+|\D+`)
+
+func newNaturalSortString(s string) (t naturalSortString) {
+ t.originalString = s
+ s = strings.ToLower(strings.Join(strings.Fields(s), " "))
+ x := naturalSortDigitFinder.FindAllString(s, -1)
+ t.tokens = make([]naturalSortToken, len(x))
+ for i, s := range x {
+ if n, err := strconv.Atoi(s); err == nil {
+ t.tokens[i].maybeNumber = n
+ } else {
+ t.tokens[i].maybeString = s
+ }
+ }
+ return
+}
+
+func (f1 naturalSortToken) Cmp(f2 naturalSortToken) int {
+ if len(f1.maybeString) == 0 {
+ if len(f2.maybeString) > 0 || f1.maybeNumber < f2.maybeNumber {
+ return -1
+ } else if f1.maybeNumber > f2.maybeNumber {
+ return 1
+ }
+ } else if len(f2.maybeString) == 0 || f1.maybeString > f2.maybeString {
+ return 1
+ } else if f1.maybeString < f2.maybeString {
+ return -1
+ }
+ return 0
+}
+
+func TunnelNameIsLess(a, b string) bool {
+ if a == b {
+ return false
+ }
+ na, nb := newNaturalSortString(a), newNaturalSortString(b)
+ for i, t := range nb.tokens {
+ if i == len(na.tokens) {
+ return true
+ }
+ switch na.tokens[i].Cmp(t) {
+ case -1:
+ return true
+ case 1:
+ return false
+ }
+ }
+ return false
+}
diff --git a/conf/path_windows.go b/conf/path_windows.go
index 96c68738..8b23e399 100644
--- a/conf/path_windows.go
+++ b/conf/path_windows.go
@@ -65,4 +65,4 @@ func RootDirectory() (string, error) {
}
cachedRootDir = c
return cachedRootDir, nil
-} \ No newline at end of file
+}
diff --git a/ui/listview.go b/ui/listview.go
index c4f5186b..2e9ee3a7 100644
--- a/ui/listview.go
+++ b/ui/listview.go
@@ -6,8 +6,8 @@
package ui
import (
+ "golang.zx2c4.com/wireguard/windows/conf"
"sort"
- "strings"
"sync/atomic"
"github.com/lxn/walk"
@@ -43,8 +43,7 @@ func (t *ListModel) Value(row, col int) interface{} {
func (t *ListModel) Sort(col int, order walk.SortOrder) error {
sort.SliceStable(t.tunnels, func(i, j int) bool {
- //TODO: use real string comparison for sorting with proper tunnel order
- return t.tunnels[i].Name < t.tunnels[j].Name
+ return conf.TunnelNameIsLess(t.tunnels[i].Name, t.tunnels[j].Name)
})
return t.SorterBase.Sort(col, order)
@@ -201,8 +200,7 @@ func (tv *ListView) Load(asyncUI bool) {
firstTunnelName := ""
for tunnel := range newTunnels {
if !oldTunnels[tunnel] {
- //TODO: use proper tunnel string sorting/comparison algorithm, as the other comments indicate too.
- if len(firstTunnelName) == 0 || strings.Compare(firstTunnelName, tunnel.Name) > 0 {
+ if len(firstTunnelName) == 0 || !conf.TunnelNameIsLess(firstTunnelName, tunnel.Name) {
firstTunnelName = tunnel.Name
}
tv.model.tunnels = append(tv.model.tunnels, tunnel)
diff --git a/ui/tray.go b/ui/tray.go
index c5902359..27b03f72 100644
--- a/ui/tray.go
+++ b/ui/tray.go
@@ -7,6 +7,7 @@ package ui
import (
"fmt"
+ "golang.zx2c4.com/wireguard/windows/conf"
"sort"
"strings"
@@ -168,7 +169,9 @@ func (tray *Tray) addTunnelAction(tunnel *service.Tunnel) {
for name := range tray.tunnels {
names = append(names, name)
}
- sort.Strings(names) //TODO: use correct sorting order for this
+ sort.SliceStable(names, func(i, j int) bool {
+ return conf.TunnelNameIsLess(names[i], names[j])
+ })
var (
idx int
diff --git a/ui/tunnelspage.go b/ui/tunnelspage.go
index 8bcf6aaa..c2521a6b 100644
--- a/ui/tunnelspage.go
+++ b/ui/tunnelspage.go
@@ -314,8 +314,7 @@ func (tp *TunnelsPage) importFiles(paths []string) {
// Add in reverse order so that the first one is selected.
sort.Slice(unparsedConfigs, func(i, j int) bool {
- //TODO: use proper tunnel string sorting/comparison algorithm, as the other comments indicate too.
- return strings.Compare(unparsedConfigs[i].Name, unparsedConfigs[j].Name) > 0
+ return conf.TunnelNameIsLess(unparsedConfigs[j].Name, unparsedConfigs[i].Name)
})
existingTunnelList, err := service.IPCClientTunnels()