Skip to content

Filterable viewport #3

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 8 additions & 2 deletions internal/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ type Model struct {
func InitialModel(c Config) Model {
return Model{
config: c,
keyMap: keymap.DefaultKeyMap,
keyMap: keymap.DefaultKeyMap(),
}
}

Expand Down Expand Up @@ -416,7 +416,13 @@ func (m Model) handleKeyMsg(msg tea.KeyMsg) (Model, tea.Cmd) {
return m, tea.Batch(cmds...)
}

// update current page
// toggle filtering with context
if key.Matches(msg, m.keyMap.Context) {
m.pages[m.focusedPageType] = m.pages[m.focusedPageType].ToggleFilteringWithContext()
return m, tea.Batch(cmds...)
}

// update current page with key msg
m.pages[m.focusedPageType], cmd = m.pages[m.focusedPageType].Update(msg)
cmds = append(cmds, cmd)

Expand Down
22 changes: 14 additions & 8 deletions internal/filter/filter.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ type Renderable interface {

type Model struct {
KeyMap filterKeyMap
FilteringWithContext bool
ShowContext bool
canToggleShowContext bool
isRegex bool
regexp *regexp.Regexp
currentMatchNum int
Expand Down Expand Up @@ -138,7 +139,7 @@ func (m Model) Value() string {
}

func (m Model) GetContextualMatchIdx() int {
if !m.FilteringWithContext {
if !m.ShowContext {
return 0
}
if m.currentMatchNum < 0 || m.currentMatchNum >= len(m.indexesMatchingFilter) {
Expand All @@ -148,7 +149,7 @@ func (m Model) GetContextualMatchIdx() int {
}

func (m Model) HasContextualMatches() bool {
return m.FilteringWithContext && len(m.indexesMatchingFilter) > 0
return m.ShowContext && len(m.indexesMatchingFilter) > 0
}

func (m Model) HasFilterText() bool {
Expand Down Expand Up @@ -180,13 +181,14 @@ func (m *Model) SetStyles(styles style.Styles) {
m.styles = styles
}

func (m *Model) SetFilteringWithContext(filteringWithContext bool) {
m.FilteringWithContext = filteringWithContext
func (m *Model) SetShowContext(showContext bool, canToggleShowContext bool) {
m.ShowContext = showContext
m.canToggleShowContext = canToggleShowContext
m.UpdateLabelAndSuffix()
}

func (m *Model) ResetContextualFilterMatchNum() {
if !m.FilteringWithContext {
if !m.ShowContext {
return
}
m.currentMatchNum = 0
Expand Down Expand Up @@ -249,8 +251,12 @@ func (m *Model) changeFilteredSelectionNum(delta int) {
}

func (m *Model) UpdateLabelAndSuffix() {
if !m.FilteringWithContext {
m.SetSuffix(" (matches only)")
if !m.canToggleShowContext && !m.ShowContext {
return
}

if !m.ShowContext {
m.SetSuffix(" (matches only) ")
return
}

Expand Down
104 changes: 56 additions & 48 deletions internal/filterable_viewport/filterable_viewport.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,51 +14,54 @@ import (
)

type FilterableViewport[T viewport.RenderableComparable] struct {
Filter filter.Model
viewport *viewport.Model[T]
allRows []T
matchesFilter func(T, filter.Model) bool
keyMap keymap.KeyMap
filterWithContext bool
whenEmpty string
topHeader string
focused bool
styles style.Styles
Filter filter.Model
viewport *viewport.Model[T]
allRows []T
matchesFilter func(T, filter.Model) bool
keyMap keymap.KeyMap
canToggleShowContext bool
whenEmpty string
topHeader string
focused bool
styles style.Styles
}

func NewFilterableViewport[T viewport.RenderableComparable](
topHeader string,
filterWithContext bool,
startSelectionEnabled bool,
startWrapOn bool,
km keymap.KeyMap,
width, height int,
allRows []T,
matchesFilter func(T, filter.Model) bool,
viewWhenEmpty string,
styles style.Styles,
) FilterableViewport[T] {
f := filter.New(km)
f.SetFilteringWithContext(filterWithContext)

var vp = viewport.New[T](width, height)

vp.SetSelectionEnabled(startSelectionEnabled)
vp.SetWrapText(startWrapOn)
type FilterableViewportConfig[T viewport.RenderableComparable] struct {
TopHeader string
StartShowContext bool
CanToggleShowContext bool
StartSelectionEnabled bool
StartWrapOn bool
KeyMap keymap.KeyMap
Width int
Height int
AllRows []T
MatchesFilter func(T, filter.Model) bool
ViewWhenEmpty string
Styles style.Styles
}

func NewFilterableViewport[T viewport.RenderableComparable](config FilterableViewportConfig[T]) FilterableViewport[T] {
f := filter.New(config.KeyMap)
f.SetShowContext(config.StartShowContext, config.CanToggleShowContext)

var vp = viewport.New[T](config.Width, config.Height)
vp.SetSelectionEnabled(config.StartSelectionEnabled)
vp.SetWrapText(config.StartWrapOn)

fv := FilterableViewport[T]{
Filter: f,
viewport: &vp,
allRows: allRows,
matchesFilter: matchesFilter,
keyMap: km,
filterWithContext: filterWithContext,
whenEmpty: viewWhenEmpty,
topHeader: topHeader,
styles: styles,
Filter: f,
viewport: &vp,
allRows: config.AllRows,
matchesFilter: config.MatchesFilter,
keyMap: config.KeyMap,
canToggleShowContext: config.CanToggleShowContext,
whenEmpty: config.ViewWhenEmpty,
topHeader: config.TopHeader,
styles: config.Styles,
}
fv.updateViewportStyles()
fv.updateViewportHeader()

fv.SetStyles(config.Styles)
return fv
}

Expand Down Expand Up @@ -97,7 +100,7 @@ func (fv FilterableViewport[T]) Update(msg tea.Msg) (FilterableViewport[T], tea.
// handle next match/prev match
if key.Matches(msg, fv.Filter.KeyMap.FilterNextRow) || key.Matches(msg, fv.Filter.KeyMap.FilterPrevRow) {
// if not filtering with context, or no filter text, ignore
if !fv.Filter.FilteringWithContext || !fv.Filter.HasFilterText() {
if !fv.Filter.ShowContext || !fv.Filter.HasFilterText() {
return fv, nil
}
if key.Matches(msg, fv.Filter.KeyMap.FilterNextRow) {
Expand Down Expand Up @@ -144,7 +147,7 @@ func (fv FilterableViewport[T]) Update(msg tea.Msg) (FilterableViewport[T], tea.
fv.Filter.UpdateLabelAndSuffix()

// if filtering with context, reset the match number and scroll to the first match
if fv.Filter.FilteringWithContext {
if fv.Filter.ShowContext {
fv.Filter.ResetContextualFilterMatchNum()
fv.scrollViewportToItemIdx(fv.Filter.GetContextualMatchIdx())
}
Expand Down Expand Up @@ -202,6 +205,7 @@ func (fv *FilterableViewport[T]) SetTopHeader(topHeader string) {
func (fv *FilterableViewport[T]) SetAllRows(allRows []T) {
fv.allRows = allRows
fv.updateVisibleRows()
fv.updateViewportHeader()
}

func (fv *FilterableViewport[T]) SetFocus(focused bool) {
Expand All @@ -228,8 +232,11 @@ func (fv *FilterableViewport[T]) SetMaintainSelection(maintainSelection bool) {
fv.viewport.SetMaintainSelection(maintainSelection)
}

func (fv *FilterableViewport[T]) ToggleFilteringWithContext() {
fv.Filter.SetFilteringWithContext(!fv.Filter.FilteringWithContext)
func (fv *FilterableViewport[T]) ToggleShowContext() {
if !fv.canToggleShowContext {
return
}
fv.Filter.SetShowContext(!fv.Filter.ShowContext, fv.canToggleShowContext)
fv.updateVisibleRows()
fv.updateViewportHeader()
}
Expand Down Expand Up @@ -258,7 +265,7 @@ func (fv *FilterableViewport[T]) updateVisibleRows() {
dev.Debug("Updating visible rows")
defer dev.Debug("Done updating visible rows")

if fv.Filter.FilteringWithContext && fv.Filter.Value() != "" {
if fv.Filter.ShowContext && fv.Filter.Value() != "" {
var entityIndexesMatchingFilter []int
for i := range fv.allRows {
if fv.matchesFilter(fv.allRows[i], fv.Filter) {
Expand Down Expand Up @@ -312,18 +319,19 @@ func (fv *FilterableViewport[T]) SetStyles(styles style.Styles) {
}

func (fv *FilterableViewport[T]) updateViewportStyles() {
fv.viewport.HighlightStyle = fv.styles.Inverse

if fv.focused {
fv.viewport.SelectedItemStyle = fv.styles.Inverse
fv.viewport.FooterStyle = lipgloss.NewStyle()
fv.viewport.HighlightStyleIfSelected = fv.styles.Unset
} else {
fv.viewport.SelectedItemStyle = lipgloss.NewStyle()
fv.viewport.FooterStyle = fv.styles.Alt
fv.viewport.HighlightStyleIfSelected = fv.styles.Inverse
}

if fv.Filter.Focused() {
fv.viewport.SelectedItemStyle = fv.styles.AltInverse
}

fv.viewport.HighlightStyle = fv.styles.Inverse
fv.viewport.HighlightStyleIfSelected = fv.styles.Unset
}
Loading
Loading