Skip to content
Open
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
1 change: 1 addition & 0 deletions cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ func init() { //nolint: gochecknoinits
rootCmd.Flags().BoolVar(&options.ShowPositions, "show-positions", false, "display average unit cost, quantity, portfolio weight")
rootCmd.Flags().BoolVar(&options.ShowHoldings, "show-holdings", false, "display average unit cost, quantity, portfolio weight (deprecated: use --show-positions)")
rootCmd.Flags().StringVar(&options.Sort, "sort", "", "sort quotes on the UI. Set \"alpha\" to sort by ticker name. Set \"value\" to sort by position value. Keep empty to sort according to change percent")
rootCmd.Flags().BoolVar(&options.ShowAlternateRowBackground, "show-row-background", false, "display alternating row background color")

printCmd.PersistentFlags().StringVar(&optionsPrint.Format, "format", "", "output format for printing holdings. Set \"csv\" to print as a CSV or \"json\" for JSON. Defaults to JSON.")
printCmd.PersistentFlags().StringVar(&configPath, "config", "", "config file (default is $HOME/.ticker.yaml)")
Expand Down
20 changes: 11 additions & 9 deletions internal/cli/cli.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,15 +22,16 @@ import (

// Options to configured ticker behavior
type Options struct {
RefreshInterval int
Watchlist string
Separate bool
ExtraInfoExchange bool
ExtraInfoFundamentals bool
ShowSummary bool
ShowHoldings bool // Deprecated: use ShowPositions instead, kept for backwards compatibility
ShowPositions bool // Preferred field name
Sort string
RefreshInterval int
Watchlist string
Separate bool
ExtraInfoExchange bool
ExtraInfoFundamentals bool
ShowSummary bool
ShowHoldings bool // Deprecated: use ShowPositions instead, kept for backwards compatibility
ShowPositions bool // Preferred field name
ShowAlternateRowBackground bool
Sort string
}

type symbolSource struct {
Expand Down Expand Up @@ -227,6 +228,7 @@ func GetConfig(dep c.Dependencies, configPath string, options Options) (c.Config
config.ShowPositions = showHoldingsFromCLI || showHoldingsFromConfig
}
config.Sort = getStringOption(options.Sort, config.Sort)
config.ShowAlternateRowBackground = getBoolOption(options.ShowAlternateRowBackground, config.ShowAlternateRowBackground)

return config, nil
}
Expand Down
2 changes: 2 additions & 0 deletions internal/common/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ type Config struct {
ShowSummary bool `yaml:"show-summary"`
ShowHoldings bool `yaml:"show-holdings"` // Deprecated: use ShowPositions instead, kept for backwards compatibility
ShowPositions bool `yaml:"show-positions"` // Preferred field name
ShowAlternateRowBackground bool `yaml:"show-alternate-row-background"`
Sort string `yaml:"sort"`
Currency string `yaml:"currency"`
CurrencyConvertSummaryOnly bool `yaml:"currency-summary-only"`
Expand All @@ -42,6 +43,7 @@ type ConfigColorScheme struct {
TextLine string `yaml:"text-line"`
TextTag string `yaml:"text-tag"`
BackgroundTag string `yaml:"background-tag"`
BackgroundRow string `yaml:"background-row"`
}

type ConfigAssetGroup struct {
Expand Down
26 changes: 18 additions & 8 deletions internal/ui/component/watchlist/row/row.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ type Config struct {
ExtraInfoFundamentals bool
Styles c.Styles
Asset *c.Asset
RowBackground string
}

type UpdateAssetMsg *c.Asset
Expand Down Expand Up @@ -221,18 +222,27 @@ func (m *Model) View() string {
})
}

contentResult := grid.Render(grid.Grid{Rows: rows, GutterHorizontal: WidthGutter})

if m.config.RowBackground != "" {
contentResult = u.ApplyBackground(contentResult, m.config.RowBackground)
}

if m.config.Separate {
rows = append(
rows,
grid.Row{
Width: m.width,
Cells: []grid.Cell{
{Text: textSeparator(m.width, m.config.Styles)},
separatorResult := grid.Render(grid.Grid{
Rows: []grid.Row{
{
Width: m.width,
Cells: []grid.Cell{
{Text: textSeparator(m.width, m.config.Styles)},
},
},
})
},
})
contentResult = contentResult + "\n" + separatorResult
}

return grid.Render(grid.Grid{Rows: rows, GutterHorizontal: WidthGutter})
return contentResult
}

func (m *Model) buildCells() []grid.Cell {
Expand Down
18 changes: 12 additions & 6 deletions internal/ui/component/watchlist/watchlist.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,13 @@ import (

// Config represents the configuration for the watchlist component
type Config struct {
Separate bool
ShowPositions bool
ExtraInfoExchange bool
ExtraInfoFundamentals bool
Sort string
Styles c.Styles
Separate bool
ShowPositions bool
ExtraInfoExchange bool
ExtraInfoFundamentals bool
Sort string
Styles c.Styles
RowAlternateBackgroundColor string
}

// Model for watchlist section
Expand Down Expand Up @@ -85,13 +86,18 @@ func (m *Model) Update(msg tea.Msg) (*Model, tea.Cmd) {
cmds = append(cmds, cmd)
m.rowsBySymbol[assets[i].Symbol] = m.rows[i]
} else {
rowBackground := ""
if i%2 == 1 {
rowBackground = m.config.RowAlternateBackgroundColor
}
m.rows = append(m.rows, row.New(row.Config{
Separate: m.config.Separate,
ExtraInfoExchange: m.config.ExtraInfoExchange,
ExtraInfoFundamentals: m.config.ExtraInfoFundamentals,
ShowPositions: m.config.ShowPositions,
Styles: m.config.Styles,
Asset: asset,
RowBackground: rowBackground,
}))
m.rowsBySymbol[assets[i].Symbol] = m.rows[len(m.rows)-1]
}
Expand Down
13 changes: 7 additions & 6 deletions internal/ui/ui.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,12 +84,13 @@ func NewModel(dep c.Dependencies, ctx c.Context, monitors *mon.Monitor) *Model {
assetQuotesLookup: make(map[string]int),
positionSummary: asset.PositionSummary{},
watchlist: watchlist.NewModel(watchlist.Config{
Sort: ctx.Config.Sort,
Separate: ctx.Config.Separate,
ShowPositions: ctx.Config.ShowPositions,
ExtraInfoExchange: ctx.Config.ExtraInfoExchange,
ExtraInfoFundamentals: ctx.Config.ExtraInfoFundamentals,
Styles: ctx.Reference.Styles,
Sort: ctx.Config.Sort,
Separate: ctx.Config.Separate,
ShowPositions: ctx.Config.ShowPositions,
ExtraInfoExchange: ctx.Config.ExtraInfoExchange,
ExtraInfoFundamentals: ctx.Config.ExtraInfoFundamentals,
Styles: ctx.Reference.Styles,
RowAlternateBackgroundColor: util.GetRowAlternateBackgroundColor(ctx.Config),
}),
summary: summary.NewModel(ctx),
groupMaxIndex: groupMaxIndex,
Expand Down
43 changes: 43 additions & 0 deletions internal/ui/util/style.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package util
import (
"math"
"regexp"
"strings"

c "github.com/achannarasappa/ticker/v5/internal/common"
"github.com/lucasb-eyer/go-colorful"
Expand Down Expand Up @@ -144,3 +145,45 @@ func getColorOrDefault(colorConfig string, colorDefault string) string {

return colorDefault
}

// GetRowAlternateBackground returns the resolved background color hex for alternate rows
func GetRowAlternateBackground(colorScheme c.ConfigColorScheme) string {
return getColorOrDefault(colorScheme.BackgroundRow, "#303030")
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could this be changed to #1c1c1c so that there is still contrast with the tag color?

}

// GetRowAlternateBackgroundColor returns the alternate row background color when the feature
// is enabled in the config, or an empty string when the feature is disabled.
func GetRowAlternateBackgroundColor(config c.Config) string {
if !config.ShowAlternateRowBackground {
return ""
}

return GetRowAlternateBackground(config.ColorScheme)
}

// ApplyBackground applies a background color to a rendered terminal string,
// including re-applying after any terminal reset sequences so that fill spaces
// between styled chunks also receive the background color.
func ApplyBackground(text string, bgHex string) string {
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could this be replaced with lipgloss? Something like this: lipgloss.NewStyle().Background(lipgloss.Color(bgHex)).Render(rowContent)

if bgHex == "" {
return text
}

bgColor := p.Color(bgHex)

// te.Style{}.Background(color).Styled("") returns "\x1b[48;...m\x1b[0m" or "" for ASCII profile
openCode := te.Style{}.Background(bgColor).Styled("")
openBgCode := strings.TrimSuffix(openCode, "\x1b[0m")

if openBgCode == "" {
// ASCII profile or unknown color - no background available
return text
}

const resetCode = "\x1b[0m"

// Prepend background, and re-apply it after every reset in the text
result := openBgCode + strings.ReplaceAll(text, resetCode, resetCode+openBgCode)

return result + resetCode
}
Loading