diff --git a/internal/gocovshtest/happy_flow_test.go b/internal/gocovshtest/happy_flow_test.go index 57c7550..61bd85c 100644 --- a/internal/gocovshtest/happy_flow_test.go +++ b/internal/gocovshtest/happy_flow_test.go @@ -163,4 +163,37 @@ func testHappyFlow(t *testing.T, prefix string, requestedFiles []string, filtere g.Assert(t, "happy_flow_toggle_help_short", []byte(mm.View())) }) }) + + t.Run("toggle sort", func(t *testing.T) { + t.Run("percentage", func(t *testing.T) { + mm, cmd := mt.sendLetterKey('s') + require.NotNil(t, mm) + require.Nil(t, cmd) + + g.Assert(t, "happy_flow_toggle_sort_percentage", []byte(mm.View())) + }) + + t.Run("name", func(t *testing.T) { + mm, cmd := mt.sendLetterKey('s') + require.NotNil(t, mm) + require.Nil(t, cmd) + + g.Assert(t, "happy_flow_toggle_sort_name", []byte(mm.View())) + }) + + t.Run("dsc", func(t *testing.T) { + mm, cmd := mt.sendLetterKey('!') + require.NotNil(t, mm) + require.Nil(t, cmd) + + g.Assert(t, "happy_flow_toggle_sort_dsc", []byte(mm.View())) + }) + t.Run("asc", func(t *testing.T) { + mm, cmd := mt.sendLetterKey('!') + require.NotNil(t, mm) + require.Nil(t, cmd) + + g.Assert(t, "happy_flow_toggle_sort_asc", []byte(mm.View())) + }) + }) } diff --git a/internal/gocovshtest/testdata/general/filtered/happy_flow_toggle_sort_asc.golden b/internal/gocovshtest/testdata/general/filtered/happy_flow_toggle_sort_asc.golden new file mode 100644 index 0000000..2e01750 --- /dev/null +++ b/internal/gocovshtest/testdata/general/filtered/happy_flow_toggle_sort_asc.golden @@ -0,0 +1,19 @@ + + Available files: + + 1 item + > covered.go 100.00% + + + + + + + + + + + + + ↑/k up • ↓/j down • / filter • q quit • ? more + \ No newline at end of file diff --git a/internal/gocovshtest/testdata/general/filtered/happy_flow_toggle_sort_dsc.golden b/internal/gocovshtest/testdata/general/filtered/happy_flow_toggle_sort_dsc.golden new file mode 100644 index 0000000..2e01750 --- /dev/null +++ b/internal/gocovshtest/testdata/general/filtered/happy_flow_toggle_sort_dsc.golden @@ -0,0 +1,19 @@ + + Available files: + + 1 item + > covered.go 100.00% + + + + + + + + + + + + + ↑/k up • ↓/j down • / filter • q quit • ? more + \ No newline at end of file diff --git a/internal/gocovshtest/testdata/general/filtered/happy_flow_toggle_sort_name.golden b/internal/gocovshtest/testdata/general/filtered/happy_flow_toggle_sort_name.golden new file mode 100644 index 0000000..2e01750 --- /dev/null +++ b/internal/gocovshtest/testdata/general/filtered/happy_flow_toggle_sort_name.golden @@ -0,0 +1,19 @@ + + Available files: + + 1 item + > covered.go 100.00% + + + + + + + + + + + + + ↑/k up • ↓/j down • / filter • q quit • ? more + \ No newline at end of file diff --git a/internal/gocovshtest/testdata/general/filtered/happy_flow_toggle_sort_percentage.golden b/internal/gocovshtest/testdata/general/filtered/happy_flow_toggle_sort_percentage.golden new file mode 100644 index 0000000..2e01750 --- /dev/null +++ b/internal/gocovshtest/testdata/general/filtered/happy_flow_toggle_sort_percentage.golden @@ -0,0 +1,19 @@ + + Available files: + + 1 item + > covered.go 100.00% + + + + + + + + + + + + + ↑/k up • ↓/j down • / filter • q quit • ? more + \ No newline at end of file diff --git a/internal/gocovshtest/testdata/general/not-requested/happy_flow_toggle_sort_asc.golden b/internal/gocovshtest/testdata/general/not-requested/happy_flow_toggle_sort_asc.golden new file mode 100644 index 0000000..b333ed3 --- /dev/null +++ b/internal/gocovshtest/testdata/general/not-requested/happy_flow_toggle_sort_asc.golden @@ -0,0 +1,19 @@ + + Available files: + + 2 items + covered.go 100.00% + > partial_with_a_very_long_name_to_trigger_ellipsis_in_the_output.go 75.00% + + + + + + + + + + + + ↑/k up • ↓/j down • / filter • q quit • ? more + \ No newline at end of file diff --git a/internal/gocovshtest/testdata/general/not-requested/happy_flow_toggle_sort_dsc.golden b/internal/gocovshtest/testdata/general/not-requested/happy_flow_toggle_sort_dsc.golden new file mode 100644 index 0000000..673ff61 --- /dev/null +++ b/internal/gocovshtest/testdata/general/not-requested/happy_flow_toggle_sort_dsc.golden @@ -0,0 +1,19 @@ + + Available files: + + 2 items + partial_with_a_very_long_name_to_trigger_ellipsis_in_the_output.go 75.00% + > covered.go 100.00% + + + + + + + + + + + + ↑/k up • ↓/j down • / filter • q quit • ? more + \ No newline at end of file diff --git a/internal/gocovshtest/testdata/general/not-requested/happy_flow_toggle_sort_name.golden b/internal/gocovshtest/testdata/general/not-requested/happy_flow_toggle_sort_name.golden new file mode 100644 index 0000000..b333ed3 --- /dev/null +++ b/internal/gocovshtest/testdata/general/not-requested/happy_flow_toggle_sort_name.golden @@ -0,0 +1,19 @@ + + Available files: + + 2 items + covered.go 100.00% + > partial_with_a_very_long_name_to_trigger_ellipsis_in_the_output.go 75.00% + + + + + + + + + + + + ↑/k up • ↓/j down • / filter • q quit • ? more + \ No newline at end of file diff --git a/internal/gocovshtest/testdata/general/not-requested/happy_flow_toggle_sort_percentage.golden b/internal/gocovshtest/testdata/general/not-requested/happy_flow_toggle_sort_percentage.golden new file mode 100644 index 0000000..b333ed3 --- /dev/null +++ b/internal/gocovshtest/testdata/general/not-requested/happy_flow_toggle_sort_percentage.golden @@ -0,0 +1,19 @@ + + Available files: + + 2 items + covered.go 100.00% + > partial_with_a_very_long_name_to_trigger_ellipsis_in_the_output.go 75.00% + + + + + + + + + + + + ↑/k up • ↓/j down • / filter • q quit • ? more + \ No newline at end of file diff --git a/internal/gocovshtest/testdata/general/requested/happy_flow_toggle_sort_asc.golden b/internal/gocovshtest/testdata/general/requested/happy_flow_toggle_sort_asc.golden new file mode 100644 index 0000000..2e01750 --- /dev/null +++ b/internal/gocovshtest/testdata/general/requested/happy_flow_toggle_sort_asc.golden @@ -0,0 +1,19 @@ + + Available files: + + 1 item + > covered.go 100.00% + + + + + + + + + + + + + ↑/k up • ↓/j down • / filter • q quit • ? more + \ No newline at end of file diff --git a/internal/gocovshtest/testdata/general/requested/happy_flow_toggle_sort_dsc.golden b/internal/gocovshtest/testdata/general/requested/happy_flow_toggle_sort_dsc.golden new file mode 100644 index 0000000..2e01750 --- /dev/null +++ b/internal/gocovshtest/testdata/general/requested/happy_flow_toggle_sort_dsc.golden @@ -0,0 +1,19 @@ + + Available files: + + 1 item + > covered.go 100.00% + + + + + + + + + + + + + ↑/k up • ↓/j down • / filter • q quit • ? more + \ No newline at end of file diff --git a/internal/gocovshtest/testdata/general/requested/happy_flow_toggle_sort_name.golden b/internal/gocovshtest/testdata/general/requested/happy_flow_toggle_sort_name.golden new file mode 100644 index 0000000..2e01750 --- /dev/null +++ b/internal/gocovshtest/testdata/general/requested/happy_flow_toggle_sort_name.golden @@ -0,0 +1,19 @@ + + Available files: + + 1 item + > covered.go 100.00% + + + + + + + + + + + + + ↑/k up • ↓/j down • / filter • q quit • ? more + \ No newline at end of file diff --git a/internal/gocovshtest/testdata/general/requested/happy_flow_toggle_sort_percentage.golden b/internal/gocovshtest/testdata/general/requested/happy_flow_toggle_sort_percentage.golden new file mode 100644 index 0000000..2e01750 --- /dev/null +++ b/internal/gocovshtest/testdata/general/requested/happy_flow_toggle_sort_percentage.golden @@ -0,0 +1,19 @@ + + Available files: + + 1 item + > covered.go 100.00% + + + + + + + + + + + + + ↑/k up • ↓/j down • / filter • q quit • ? more + \ No newline at end of file diff --git a/internal/model/model.go b/internal/model/model.go index f6b67fd..c7b688a 100644 --- a/internal/model/model.go +++ b/internal/model/model.go @@ -40,11 +40,31 @@ const ( helpStateFull ) +type sortType int + +const ( + sortStateByName sortType = iota + sortStateByPercentage +) + +type sortOrder bool + +const ( + asc sortOrder = true + dsc sortOrder = false +) + +type SortState struct { + Type sortType + Order sortOrder +} + // New create a new model that can be used directly in the tea framework. func New(opts ...Option) *Model { m := &Model{ activeView: activeViewList, helpState: helpStateShort, + sortState: SortState{Type: sortStateByName, Order: asc}, codeRoot: ".", list: list.New([]list.Item{}, coverProfileDelegate{}, 0, 0), } @@ -74,13 +94,14 @@ type Model struct { codeRoot string profileFilename string - sortByCoverage bool detectedPackageName string requestedFiles map[string]bool filteredLinesByFile map[string][]int + loadedProfiles []*cover.Profile activeView viewName helpState helpState + sortState SortState ready bool err errorview.Model @@ -186,10 +207,8 @@ func (m *Model) onProfilesLoaded(profiles []*cover.Profile) (tea.Model, tea.Cmd) return m.onError(errNoProfiles{}) } - if m.sortByCoverage { - sort.Slice(profiles, func(i, j int) bool { - return percentCovered(profiles[i]) < percentCovered(profiles[j]) - }) + if m.sortState.Type == sortStateByPercentage { + m.sortByPercentage() } m.items = make([]list.Item, len(profiles)) @@ -256,6 +275,14 @@ func (m *Model) onKeyPressed(key string) (tea.Model, tea.Cmd) { return m, nil + case "s": + m.toggleSort() + return m.updateListItems() + + case "!": + m.toggleSortOrder() + return m.updateListItems() + case "?": m.toggleHelp() return m, nil @@ -264,6 +291,71 @@ func (m *Model) onKeyPressed(key string) (tea.Model, tea.Cmd) { return nil, nil } +func (m *Model) updateListItems() (tea.Model, tea.Cmd) { + + m.processSort() + + m.items = make([]list.Item, len(m.loadedProfiles)) + + for i, p := range m.loadedProfiles { + p.FileName = strings.TrimPrefix(p.FileName, m.detectedPackageName+"/") + m.items[i] = &coverProfile{ + profile: p, + percentage: percentCovered(p), + } + } + + return m, m.list.SetItems(m.items) +} + +func (m *Model) processSort() { + switch m.sortState.Type { + case sortStateByPercentage: + m.sortByPercentage() + case sortStateByName: + m.sortByName() + } +} + +func (m *Model) sortByPercentage() { + sort.Slice(m.loadedProfiles, func(i, j int) bool { + if m.sortState.Order == asc { + return percentCovered(m.loadedProfiles[i]) > percentCovered(m.loadedProfiles[j]) + } else { + return percentCovered(m.loadedProfiles[i]) < percentCovered(m.loadedProfiles[j]) + } + }) +} + +func (m *Model) sortByName() { + sort.Slice(m.loadedProfiles, func(i, j int) bool { + if m.sortState.Order == asc { + return m.loadedProfiles[i].FileName < m.loadedProfiles[j].FileName + } else { + return m.loadedProfiles[i].FileName > m.loadedProfiles[j].FileName + } + }) +} + +func (m *Model) toggleSortOrder() { + switch m.sortState.Order { + case asc: + m.sortState.Order = dsc + case dsc: + m.sortState.Order = asc + } +} + +func (m *Model) toggleSort() { + switch m.sortState.Type { + case sortStateByName: + m.sortState.Type = sortStateByPercentage + + case sortStateByPercentage: + m.sortState.Type = sortStateByName + } +} + func (m *Model) toggleHelp() { // manage help state globally: allow to extend or hide completely switch m.helpState { @@ -328,6 +420,7 @@ func (m *Model) loadProfiles(codeRoot, profileFilename string) tea.Cmd { finalProfiles = append(finalProfiles, p) } + m.loadedProfiles = finalProfiles return finalProfiles } diff --git a/internal/model/options.go b/internal/model/options.go index e3fc82d..fb41bd0 100644 --- a/internal/model/options.go +++ b/internal/model/options.go @@ -13,7 +13,9 @@ func WithProfileFilename(name string) Option { // WithCoverageSorting asks for the profiles to be sorted by coverage percent instead of alphabetically. func WithCoverageSorting(sortByCoverage bool) Option { return func(m *Model) { - m.sortByCoverage = sortByCoverage + if sortByCoverage { + m.sortState.Type = sortStateByPercentage + } } }