-
Notifications
You must be signed in to change notification settings - Fork 7
Expand file tree
/
Copy pathsort.go
More file actions
126 lines (117 loc) · 2.37 KB
/
Copy pathsort.go
File metadata and controls
126 lines (117 loc) · 2.37 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
// Copyright 2019 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package main
import (
"strings"
"rsc.io/todo/task"
)
func (w *awin) ExecSort(arg string) {
if w.mode != modeList {
w.acme.Err("Sort can only sort task list windows")
return
}
if arg != "" {
w.sortBy = arg
} else if w.sortBy != "" && w.sortBy != "title" {
w.sortBy = "title"
} else {
w.sortBy = "id"
}
rev := false
by := w.sortBy
if strings.HasPrefix(by, "-") {
rev = true
by = by[1:]
}
var cmp func(string, string) int
if by == "id" {
cmp = func(x, y string) int {
nx := lineNumber(x)
ny := lineNumber(y)
switch {
case nx < ny:
return -1
case nx > ny:
return +1
case x < y:
return -1
case x > y:
return +1
}
return 0
}
} else if by == "title" || by == "" {
cmp = func(x, y string) int { return strings.Compare(skipField(x), skipField(y)) }
} else {
cache := make(map[string]*task.Task)
cachedTask := func(id string) *task.Task {
if t, ok := cache[id]; ok {
return t
}
t, _ := w.list().Read(id)
cache[id] = t
return t
}
cmp = func(x, y string) int {
tx := cachedTask(lineID(x))
ty := cachedTask(lineID(y))
if tx != nil && ty != nil {
kx := tx.Header(by)
ky := ty.Header(by)
if kx != ky {
return strings.Compare(kx, ky)
}
} else if tx != nil || ty != nil {
if tx == nil {
return -1
}
return +1
}
return strings.Compare(x, y)
}
}
var less func(x, y string) bool
if rev {
less = func(x, y string) bool { return cmp(x, y) > 0 }
} else {
less = func(x, y string) bool { return cmp(x, y) < 0 }
}
if err := w.acme.Addr("0/^[0-9a-z_\\-]+\t/,"); err != nil {
w.acme.Err("nothing to sort")
}
if err := w.acme.Sort(less); err != nil {
w.acme.Err(err.Error())
}
w.acme.Addr("0")
w.acme.Ctl("dot=addr")
w.acme.Ctl("show")
}
func lineNumber(s string) int {
n := 0
j := 0
for ; j < len(s) && '0' <= s[j] && s[j] <= '9'; j++ {
n = n*10 + int(s[j]-'0')
}
if j < len(s) && s[j] != ' ' && s[j] != '\t' {
return 999999999
}
return n
}
func lineID(s string) string {
i := strings.Index(s, "\t")
if i < 0 {
return s
}
return s[:i]
}
func skipField(s string) string {
i := strings.Index(s, "\t")
if i < 0 {
return s
}
for i < len(s) && s[i+1] == '\t' {
i++
}
return s[i:]
}