Browse Source

Make initial load run in background so as to not lock up UI

Benton Edmondson 1 year ago
parent
commit
f243bbe7fe
4 changed files with 80 additions and 46 deletions
  1. 22 8
      feed/feed.go
  2. 0 2
      main.go
  3. 9 5
      splicer/splicer.go
  4. 49 31
      ui/ui.go

+ 22 - 8
feed/feed.go

@@ -6,18 +6,28 @@ import (
 )
 
 type Feed struct {
-	feed       map[int]pub.Tangible
+	feed map[int]pub.Tangible
+
+	// exclusive bounds
 	upperBound int
 	lowerBound int
 }
 
+func CreateEmpty() *Feed {
+	return &Feed{
+		feed:       map[int]pub.Tangible{},
+		upperBound: 0,
+		lowerBound: 0,
+	}
+}
+
 func Create(input pub.Tangible) *Feed {
 	return &Feed{
 		feed: map[int]pub.Tangible{
 			0: input,
 		},
-		upperBound: 0,
-		lowerBound: 0,
+		upperBound: 1,
+		lowerBound: -1,
 	}
 }
 
@@ -25,27 +35,27 @@ func CreateAndAppend(input []pub.Tangible) *Feed {
 	f := &Feed{
 		feed: map[int]pub.Tangible{},
 	}
+	f.upperBound = 1
 	f.Append(input)
-	f.lowerBound = 1
 	return f
 }
 
 func (f *Feed) Append(input []pub.Tangible) {
 	for i, element := range input {
-		f.feed[f.upperBound+i+1] = element
+		f.feed[f.upperBound+i] = element
 	}
 	f.upperBound += len(input)
 }
 
 func (f *Feed) Prepend(input []pub.Tangible) {
 	for i, element := range input {
-		f.feed[f.lowerBound-i-1] = element
+		f.feed[f.lowerBound-i] = element
 	}
 	f.lowerBound -= len(input)
 }
 
 func (f *Feed) Get(index int) pub.Tangible {
-	if index > f.upperBound || index < f.lowerBound {
+	if !f.Contains(index) {
 		panic(fmt.Sprintf("indexing feed at %d whereas bounds are %d and %d", index, f.lowerBound, f.upperBound))
 	}
 
@@ -53,5 +63,9 @@ func (f *Feed) Get(index int) pub.Tangible {
 }
 
 func (f *Feed) Contains(index int) bool {
-	return index <= f.upperBound && index >= f.lowerBound
+	return index < f.upperBound && index > f.lowerBound
+}
+
+func (f *Feed) IsEmpty() bool {
+	return f.upperBound == 0 && f.lowerBound == 0
 }

+ 0 - 2
main.go

@@ -33,8 +33,6 @@ func main() {
 		return
 	}
 
-	// TODO: resize currently doesn't work until these
-	// network requests complete
 	switch os.Args[1] {
 	case "open":
 		if len(os.Args) == 3 {

+ 9 - 5
splicer/splicer.go

@@ -95,12 +95,16 @@ func NewSplicer(inputs []string) *Splicer {
 				panic("cannot splice non-Tangible, non-Collection")
 			}
 
-			var elements []pub.Tangible
-			elements, s[i].page, s[i].basepoint = children.Harvest(1, 0)
-			if len(elements) > 1 {
-				panic("harvest returned more that one element when I only asked for one")
+			if children != nil {
+				var elements []pub.Tangible
+				elements, s[i].page, s[i].basepoint = children.Harvest(1, 0)
+				if len(elements) > 1 {
+					panic("harvest returned more that one element when I only asked for one")
+				} else {
+					s[i].element = elements[0]
+				}
 			} else {
-				s[i].element = elements[0]
+				s[i].element = nil
 			}
 			wg.Done()
 		}()

+ 49 - 31
ui/ui.go

@@ -33,7 +33,11 @@ type State struct {
 	config *config.Config
 }
 
-func (s *State) View() string {
+func (s *State) view() string {
+	if s.feed.IsEmpty() {
+		return ansi.CenterVertically("", style.Color("  Loading…"), "", uint(s.height))
+	}
+
 	var top, center, bottom string
 	for i := s.index - s.config.Context; i <= s.index+s.config.Context; i++ {
 		if !s.feed.Contains(i) {
@@ -43,7 +47,7 @@ func (s *State) View() string {
 		if i == 0 {
 			serialized = s.feed.Get(i).String(s.width - 4)
 		} else if i > 0 {
-			serialized = " " + ansi.Indent(s.feed.Get(i).Preview(s.width-4), "  ", false)
+			serialized = " " + ansi.Indent(s.feed.Get(i).Preview(s.width-4), "  ", false)
 		} else {
 			serialized = s.feed.Get(i).Preview(s.width - 4)
 		}
@@ -53,12 +57,12 @@ func (s *State) View() string {
 			if top != "" {
 				top += "\n"
 			}
-			top += ansi.Indent(serialized+"\n", "  ", true)
+			top += ansi.Indent(serialized+"\n", "  ", true)
 		} else {
 			if bottom != "" {
 				bottom += "\n"
 			}
-			bottom += ansi.Indent("\n"+serialized, "  ", true)
+			bottom += ansi.Indent("\n"+serialized, "  ", true)
 		}
 	}
 	if s.loadingUp {
@@ -84,7 +88,7 @@ func (s *State) Update(input byte) {
 			s.index -= 1
 		}
 		s.loadSurroundings()
-		s.output(s.View())
+		s.output(s.view())
 		s.m.Unlock()
 	case 'j': // down
 		s.m.Lock()
@@ -92,12 +96,14 @@ func (s *State) Update(input byte) {
 			s.index += 1
 		}
 		s.loadSurroundings()
-		s.output(s.View())
+		s.output(s.view())
 		s.m.Unlock()
 	case 'g': // return to OP
 		s.m.Lock()
-		s.index = 0
-		s.output(s.View())
+		if s.feed.Contains(0) {
+			s.index = 0
+			s.output(s.view())
+		}
 		s.m.Unlock()
 	case ' ': // select
 		s.m.Lock()
@@ -109,28 +115,25 @@ func (s *State) Update(input byte) {
 }
 
 func (s *State) switchTo(item pub.Any) {
+	s.loadingUp = false
+	s.loadingDown = false
+	s.basepoint = 0
 	switch narrowed := item.(type) {
 	case pub.Tangible:
 		s.feed = feed.Create(narrowed)
-		s.frontier = narrowed
-		s.page = narrowed.Children()
 		s.index = 0
-		s.loadingUp = false
-		s.loadingDown = false
-		s.basepoint = 0
-		s.loadSurroundings()
+		s.page = narrowed.Children()
+		s.frontier = narrowed
 	case pub.Container:
-		var children []pub.Tangible
-		children, s.page, s.basepoint = narrowed.Harvest(uint(s.config.Context), 0)
-		s.feed = feed.CreateAndAppend(children)
+		s.feed = feed.CreateEmpty()
 		s.index = 1
-		s.loadingUp = false
-		s.loadingDown = false
-		s.basepoint = 0
+		s.page = narrowed
+		s.frontier = nil
 	default:
 		panic(fmt.Sprintf("unrecognized non-Tangible non-Container: %T", item))
 	}
-	s.output(s.View())
+	s.loadSurroundings()
+	s.output(s.view())
 }
 
 func (s *State) SetWidthHeight(width int, height int) {
@@ -141,7 +144,7 @@ func (s *State) SetWidthHeight(width int, height int) {
 	}
 	s.width = width
 	s.height = height
-	s.output(s.View())
+	s.output(s.view())
 }
 
 func (s *State) loadSurroundings() {
@@ -150,12 +153,12 @@ func (s *State) loadSurroundings() {
 		s.loadingUp = true
 		go func() {
 			parents, newFrontier := prior.frontier.Parents(uint(prior.config.Context))
-			prior.feed.Prepend(parents)
 			s.m.Lock()
+			prior.feed.Prepend(parents)
 			if prior.feed == s.feed {
 				s.frontier = newFrontier
 				s.loadingUp = false
-				s.output(s.View())
+				s.output(s.view())
 			}
 			s.m.Unlock()
 		}()
@@ -164,13 +167,13 @@ func (s *State) loadSurroundings() {
 		s.loadingDown = true
 		go func() {
 			children, newPage, newBasepoint := prior.page.Harvest(uint(prior.config.Context), prior.basepoint)
-			prior.feed.Append(children)
 			s.m.Lock()
+			prior.feed.Append(children)
 			if prior.feed == s.feed {
 				s.page = newPage
 				s.basepoint = newBasepoint
 				s.loadingDown = false
-				s.output(s.View())
+				s.output(s.view())
 			}
 			s.m.Unlock()
 		}()
@@ -178,18 +181,33 @@ func (s *State) loadSurroundings() {
 }
 
 func (s *State) Open(input string) {
-	s.output(ansi.CenterVertically("", style.Color("  Opening…"), "", uint(s.height)))
-	s.switchTo(pub.FetchUserInput(input))
+	go func() {
+		s.m.Lock()
+		s.output(s.view())
+		s.m.Unlock()
+		result := pub.FetchUserInput(input)
+		s.m.Lock()
+		s.switchTo(result)
+		s.m.Unlock()
+	}()
 }
 
 func (s *State) Feed(input string) {
-	s.output(ansi.CenterVertically("", style.Color("  Loading feed…"), "", uint(s.height)))
-	s.switchTo(splicer.NewSplicer(s.config.Feeds[input]))
+	go func() {
+		s.m.Lock()
+		s.output(s.view())
+		inputs := s.config.Feeds[input]
+		s.m.Unlock()
+		result := splicer.NewSplicer(inputs)
+		s.m.Lock()
+		s.switchTo(result)
+		s.m.Unlock()
+	}()
 }
 
 func NewState(config *config.Config, width int, height int, output func(string)) *State {
 	s := &State{
-		feed:   &feed.Feed{},
+		feed:   feed.CreateEmpty(),
 		index:  0,
 		config: config,
 		width:  width,