Skip to content

Commit a529746

Browse files
committed
look: fixes festering look bugs
- selection no longer expands when clicking inside of a partial word - add tests for selections and looks - add edit refresh (experiment) - document look behavior
1 parent 73ff9ba commit a529746

File tree

6 files changed

+252
-49
lines changed

6 files changed

+252
-49
lines changed

addr.go

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
package main
2+
3+
import (
4+
"github.com/as/text"
5+
"github.com/as/text/find"
6+
)
7+
8+
type q int64
9+
10+
func (a q) In(a1 Addr) bool { return text.Region3(int64(a), int64(a1.s-1), int64(a1.e)) == 0 }
11+
12+
type Addr struct {
13+
s q
14+
e q
15+
}
16+
17+
type a = Addr
18+
19+
func d2a(q0, q1 int64) Addr { return Addr{q(q0), q(q1)} }
20+
21+
func (a Addr) Empty() bool { return a.s == a.e }
22+
func (a Addr) Len() int { return int(a.e - a.s) }
23+
func (a Addr) In(a1 Addr) bool {
24+
if a.Empty() {
25+
return a.e.In(a1)
26+
}
27+
return a.Len() <= a1.Len() && text.Region5(int64(a.s), int64(a.e), int64(a1.s), int64(a1.e)) == 0
28+
}
29+
func (a Addr) Dot() (q0, q1 int64) { return int64(a.s), int64(a.e) }
30+
31+
func expandAddr(a Addr, ed text.Editor) Addr {
32+
if !a.Empty() {
33+
return a
34+
}
35+
a0 := d2a(ed.Dot())
36+
if a.In(a0) {
37+
return a0
38+
}
39+
return a
40+
}
41+
42+
func expandFile(a Addr, ed text.Editor) Addr {
43+
if !a.Empty() {
44+
return a
45+
}
46+
return d2a(find.ExpandFile(ed.Bytes(), int64(a.s)))
47+
}

cmd.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ func acmd(e event.Cmd) {
8989
if strings.HasPrefix(s, "Edit ") {
9090
s = s[5:]
9191
editcmd(e.To[0], abs, s)
92+
editRefresh(e.To[0])
9293
} else if strings.HasPrefix(s, "Install ") {
9394
s = s[8:]
9495
g.Install(actTag, s)

edit.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,22 @@ import (
55
"github.com/as/text"
66
)
77

8+
func editRefresh(ed text.Editor) {
9+
type r interface {
10+
Refresh()
11+
}
12+
type u interface {
13+
Upload()
14+
}
15+
16+
if ed, ok := ed.(r); ok {
17+
ed.Refresh()
18+
}
19+
if ed, ok := ed.(u); ok {
20+
ed.Upload()
21+
}
22+
}
23+
824
func (g *Grid) EditRun(prog string, ed text.Editor) (ok bool) {
925
//TODO(as): danger, edit needs a way to ensure it will only jump to an address
1026
if prog == "" {

look.go

Lines changed: 59 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import (
1313
"github.com/as/text"
1414
"github.com/as/text/action"
1515
"github.com/as/text/find"
16+
"github.com/as/ui/col"
1617
"github.com/as/ui/tag"
1718
"github.com/as/ui/win"
1819
)
@@ -107,10 +108,24 @@ func (e *Looker) LookGrid(g *Grid) (error) {
107108
}
108109
*/
109110

111+
type vis struct {
112+
}
113+
114+
func (v *vis) Look(e event.Look) {
115+
}
116+
110117
func (g *Grid) cwd() string {
111118
s, _ := os.Getwd()
112119
return s
113120
}
121+
122+
// hiclick returns true if the nil address (q0,q1) intersects
123+
// the highlighted selection (r0:r1)
124+
func hiclick(r0, r1, q0, q1 int64) bool {
125+
x := r0 == r1 && text.Region3(r0, q0-1, q1) == 0
126+
return x
127+
}
128+
114129
func (g *Grid) Look(e event.Look) {
115130
if g.meta(g.Tag) {
116131
return
@@ -119,9 +134,27 @@ func (g *Grid) Look(e event.Look) {
119134
ed := e.To[0]
120135
t, _ := ed.(*tag.Tag)
121136

122-
e.Q0, e.Q1 = expand3(ed, e.Q0, e.Q1)
137+
p0, p1 := e.From.Dot() // pre-sweep
138+
// e.Q0 and e.Q1 is post sweep
139+
140+
if e.Q0 == e.Q1 && !hiclick(e.Q0, e.Q1, p0, p1) {
141+
// one click outside old selection
142+
// expand the address
143+
a1 := expandFile(d2a(e.Q0, e.Q1), e.From)
144+
e.Q0, e.Q1 = a1.Dot()
145+
} else if e.Q0 == e.Q1 {
146+
// click inside old selection
147+
// use the old selection
148+
e.Q0, e.Q1 = p0, p1
149+
} else {
150+
// selection overlaps old selection
151+
// we don't care about that
152+
}
153+
154+
//fmt.Printf("name and dot %q %d %d\n", e.P, e.Q0, e.Q1)
155+
e.P = e.P[e.Q0:e.Q1] //ed.Bytes()
156+
123157
name, addr := action.SplitPath(string(e.P))
124-
// e.P = ed.Bytes()[e.Q0:e.Q1]
125158
if name == "" && addr == "" {
126159
return
127160
}
@@ -185,7 +218,7 @@ func (g *Grid) Look(e event.Look) {
185218
}
186219

187220
//TODO(as): fix this so it doesn't compare hard coded coordinates
188-
if e.To[0].(*win.Win) == nil || e.To[0].(Plane).Loc().Max.Y < 48 {
221+
if e.To[0].(*win.Win) == nil {
189222
VisitAll(g, func(p Named) {
190223
if p == nil {
191224
return
@@ -200,7 +233,26 @@ func (g *Grid) Look(e event.Look) {
200233
}
201234
}
202235
}
236+
237+
func stub(g *Grid, p Plane) bool {
238+
if p == nil {
239+
return false
240+
}
241+
if p == g.Tag {
242+
return true
243+
}
244+
l := g.Kids()
245+
for i := range l {
246+
c, _ := l[i].(*col.Col)
247+
if c != nil && p == c.Tag {
248+
return true
249+
}
250+
}
251+
return false
252+
}
253+
203254
func (g *Grid) afinderr(wd string, name string) *tag.Tag {
255+
204256
name = strings.TrimSpace(name)
205257
if !strings.HasSuffix(name, "+Errors") {
206258
name += "+Errors"
@@ -236,16 +288,6 @@ func (g *Grid) aout(fm string, i ...interface{}) {
236288
ajump(t.Body, cursorNop)
237289
}
238290

239-
// expand3 return (r0:r1) if and only if that range is wide and
240-
// not inside ed's dot, otherwise it returns dot
241-
func expand3(ed text.Editor, r0, r1 int64) (int64, int64) {
242-
q0, q1 := ed.Dot()
243-
if r0 == r1 && text.Region3(r0, q0, q1) == 0 {
244-
return q0, q1
245-
}
246-
return r0, r1
247-
}
248-
249291
func lookliteraltag(ed text.Editor, q0, q1 int64, what []byte) {
250292
q0, q1 = ed.Dot()
251293
s0, s1 := find.FindNext(ed, q0, q1, what)
@@ -262,16 +304,14 @@ func lookliteral(ed text.Editor, e event.Look, mouseFunc func(image.Point)) {
262304
// If the found range is identical to the starting point, no result has been found
263305

264306
t0, t1 := ed.Dot()
265-
// g.aerr("lookliteral: dot(%d:%d)", t0, t1)
266-
// g.aerr("lookliteral: find(%d:%d) [%q]", e.Q0, e.Q1, e.P)
267-
q0, q1 := find.FindNext(ed, e.Q0, e.Q1, e.P)
268-
// g.aerr("lookliteral: next(%d:%d)", q0, q1)
307+
308+
q0, q1 := find.FindNext(ed, e.Q1, e.Q1, e.P)
309+
//fmt.Printf("after q0,q1: %d,%d\n\n\t%q\n", e.Q0, e.Q1, e.P)
310+
269311
if q0 == e.Q0 && q1 == e.Q1 {
270-
// g.aerr("lookliteral: not found, same output(%d:%d)", q0, q1)
271312
ed.Select(t0, t1)
272313
return
273314
}
274-
// g.aerr("lookliteral: found, diff output(%d:%d) != input(%d:%d)", q0, q1, e.Q0, e.Q1)
275315
ed.Select(q0, q1)
276316
ajump(ed, mouseFunc)
277317
}

look_test.go

Lines changed: 120 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -19,59 +19,157 @@ const (
1919
LJump // Expect the look to jump to a window
2020
LNew // Expect the look to open a new window
2121
LWrap // Expect the look to wrap around
22+
LLabel // The user looked from the label
2223
)
2324

24-
var testText = "the quick brown fox jumps over the lazy dog"
25+
func (f LFlag) On(bit LFlag) bool {
26+
return f&LLabel != 0
27+
}
28+
29+
type ent struct {
30+
pre Addr
31+
sweep Addr
32+
post Addr
33+
flags LFlag
34+
data string
35+
}
36+
37+
// Window Resolver
38+
// Filesystem Resolver
39+
// Look Resolver
2540

2641
func TestLook(t *testing.T) {
2742
etch := ui.NewEtch()
28-
type a struct {
29-
s, e int64
30-
}
31-
for name, tc := range map[string]struct {
32-
pre a // pre-sweep selection
33-
sweep a // selection after sweep complete
34-
post a // selection after look
35-
flags LFlag
3643

37-
data string
44+
sentence := "the quick brown fox jumps over the lazy dog"
45+
norm := LScav | LMatch | LJump
46+
47+
//exampleURL := "http://example.com"
48+
type a = Addr
49+
for name, tc := range map[string]struct {
50+
label ent
51+
ent
52+
onlabel bool
3853
}{
39-
"the0": {a{0, 2}, a{}, a{31, 33}, LScav | LMatch | LJump, testText},
40-
"the1": {a{31, 33}, a{}, a{0, 2}, LScav | LMatch | LJump | LWrap, testText},
41-
// "the3": {a{0, 0}, a{0, 2}, a{31, 33}, LScav | LMatch | LJump, testText},
42-
// TODO(as): break it with selected look above
54+
// Null selection in body, select letters of "the"
55+
"the0/0": {ent: ent{a{0, 0}, a{}, a{31, 34}, norm, sentence}},
56+
"the0/1": {ent: ent{a{0, 0}, a{0, 1}, a{31, 32}, norm, sentence}},
57+
"the0/2": {ent: ent{a{0, 0}, a{0, 2}, a{31, 33}, norm, sentence}},
58+
59+
// Partial selection of "th"
60+
"the2/0": {ent: ent{a{0, 2}, a{}, a{31, 33}, norm, sentence}},
61+
"the2/1": {ent: ent{a{0, 2}, a{0, 1}, a{31, 32}, norm, sentence}},
62+
"the2/2": {ent: ent{a{0, 2}, a{0, 2}, a{31, 33}, norm, sentence}},
63+
64+
//
65+
"h/0": {ent: ent{a{1, 2}, a{1, 1}, a{32, 33}, norm, sentence}},
66+
67+
// Wrap-around test
68+
"the1": {ent: ent{a{31, 33}, a{5, 5}, a{31, 33}, norm | LWrap, sentence}},
69+
70+
// Clicked on the tag label instead
71+
"dog": {ent: ent{a{0, 0}, a{}, a{40, 43}, norm | LLabel, sentence}},
72+
"dog1": {ent: ent{a{0, 0}, a{0, 1}, a{40, 41}, norm | LLabel, sentence}},
73+
"dog2": {ent: ent{a{0, 0}, a{0, 2}, a{40, 42}, norm | LLabel, sentence}},
74+
75+
// If it's clicking in the label
76+
"label/the": {
77+
label: ent{a{0, 0}, a{0, 3}, a{0, 3}, 0, "the"},
78+
ent: ent{a{0, 0}, a{0, 0}, a{0, 3}, norm | LLabel, sentence},
79+
onlabel: true,
80+
},
4381
} {
4482
t.Run(name, func(t *testing.T) {
4583

4684
// TODO(as): wow, this is a lot of code to initialize one grid
4785
g := NewGrid(etch, GridConfig)
4886
c := col.New(etch, ColConfig)
87+
88+
if tc.label.data == "" {
89+
tc.label.data = "dog"
90+
}
91+
4992
tag := tag.New(etch, nil)
50-
tag.Body.Insert([]byte(tc.data), 0)
93+
tag.Win.Insert([]byte(tc.label.data), 0)
94+
5195
w := tag.Body
52-
w.Select(tc.pre.s, tc.pre.e)
96+
w.Insert([]byte(tc.data), 0)
97+
w.Select(int64(tc.pre.s), int64(tc.pre.e))
98+
5399
col.Attach(g, c, image.ZP)
54100
col.Attach(c, tag, image.ZP)
55101

102+
from := w
103+
if tc.flags.On(LLabel) {
104+
from = tag.Win
105+
} else if name == "dog" {
106+
t.Fatal("bad test")
107+
}
108+
109+
a1 := tc.sweep
110+
if a1.Empty() {
111+
a1 = expandAddr(a1, from)
112+
}
113+
if a1.Empty() {
114+
a1 = expandFile(a1, from)
115+
}
116+
56117
// TODO(as): wow, this is a lot of code to express one look
57118
ev := event.Look{
58-
Name: "w", From: w,
119+
Name: "w", From: from,
59120
To: []event.Editor{w},
60121
Rec: event.Rec{
61-
Q0: tc.pre.s, Q1: tc.pre.e,
62-
P: w.Bytes()[tc.pre.s:tc.pre.e],
122+
Q0: int64(a1.s), Q1: int64(a1.e),
123+
P: from.Bytes(),
63124
},
64125
}
65-
126+
t.Logf("looking for %s", from.Bytes()[int64(a1.s):int64(a1.e)])
66127
g.Look(ev)
67128

68129
q0, q1 := w.Dot()
69-
have := a{q0, q1}
130+
have := a{q(q0), q(q1)}
70131
if have != tc.post {
71132
t.Fatalf("have %v, want %v", have, tc.post)
72133
}
73134
})
74-
75135
}
76136

77137
}
138+
139+
func TestExpand(t *testing.T) {
140+
etch := ui.NewEtch()
141+
142+
sentence := "stall install reinstall installing stalling"
143+
g := NewGrid(etch, GridConfig)
144+
c := col.New(etch, ColConfig)
145+
tag := tag.New(etch, nil)
146+
w := tag.Body
147+
w.Insert([]byte(sentence), 0)
148+
w.Select(int64(0), int64(0))
149+
col.Attach(g, c, image.ZP)
150+
col.Attach(c, tag, image.ZP)
151+
152+
a1 := a{0, q(len("stall"))}
153+
154+
for i := 0; i < 10; i++ {
155+
if a1.Empty() {
156+
a1 = expandAddr(a1, w)
157+
}
158+
if a1.Empty() {
159+
a1 = expandFile(a1, w)
160+
}
161+
ev := event.Look{
162+
Name: "w", From: w,
163+
To: []event.Editor{w},
164+
Rec: event.Rec{
165+
Q0: int64(a1.s), Q1: int64(a1.e),
166+
P: w.Bytes(),
167+
},
168+
}
169+
g.Look(ev)
170+
q0, q1 := w.Dot()
171+
if have := string(w.Bytes()[q0:q1]); have != "stall" {
172+
t.Fatalf("have %v, want %v", have, "stall")
173+
}
174+
}
175+
}

0 commit comments

Comments
 (0)