From 0a55fe0c939620a2b5b5d8204bc32f0880d7e3f6 Mon Sep 17 00:00:00 2001 From: Slug-Boi Date: Tue, 28 Apr 2026 11:29:47 +0200 Subject: [PATCH] feat: add color to Authors in list view based on where they were added from scope wise --- src/cmd/tui/tui_author.go | 6 +- src/cmd/tui/tui_groups.go | 4 +- src/cmd/tui/tui_list.go | 131 +++++++++++++++++++++++---------- src/cmd/tui/tui_test.go | 2 +- src/cmd/utils/test_git_wrapper | 1 + src/cmd/utils/user_util.go | 32 ++++---- 6 files changed, 115 insertions(+), 61 deletions(-) create mode 100644 src/cmd/utils/test_git_wrapper diff --git a/src/cmd/tui/tui_author.go b/src/cmd/tui/tui_author.go index c4f39fc..170e680 100644 --- a/src/cmd/tui/tui_author.go +++ b/src/cmd/tui/tui_author.go @@ -463,7 +463,7 @@ func (m *model_ca) AddAuthor() bool { if parent_m != nil { item_str := utils.Users[author].Username + " - " + utils.Users[author].Email dupProtect[item_str] = author - parent_m.list.InsertItem(len(parent_m.list.Items())+1, item(item_str)) + parent_m.list.InsertItem(len(parent_m.list.Items())+1, item{item_str, local_scope}) } return false } @@ -474,8 +474,8 @@ func (m *model_ca) TempAddAuthor() bool { if len(m.inputs) > 1 && m.inputs[0].Value() != "" && m.inputs[1].Value() != "" { item_str := m.inputs[0].Value() + " - " + m.inputs[1].Value() dupProtect[item_str] = m.inputs[0].Value() + ":" + m.inputs[1].Value() - i := item(item_str) - parent_m.list.InsertItem(len(parent_m.list.Items())+1, item(item_str)) + i := item{item_str, local_scope} + parent_m.list.InsertItem(len(parent_m.list.Items())+1, item{item_str, local_scope}) selectToggle(i) return false diff --git a/src/cmd/tui/tui_groups.go b/src/cmd/tui/tui_groups.go index 4fdb07e..7e67a1f 100644 --- a/src/cmd/tui/tui_groups.go +++ b/src/cmd/tui/tui_groups.go @@ -118,7 +118,7 @@ func (m mainModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { } if group != "" { for _, sel := range selected { - delete(selected, string(sel)) + delete(selected, string(sel.display)) } users := utils.Groups[group] //TODO: this may be able to be done in a more efficient way currently this would scale poorly @@ -126,7 +126,7 @@ func (m mainModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { if _, ok := selected[k]; !ok { for _, user := range users { if user.Shortname == v || user.Longname == v { - selectToggle(item(k)) + selectToggle(item{k,local_scope}) } } } diff --git a/src/cmd/tui/tui_list.go b/src/cmd/tui/tui_list.go index 0a272c8..6bd758a 100644 --- a/src/cmd/tui/tui_list.go +++ b/src/cmd/tui/tui_list.go @@ -27,12 +27,16 @@ var ( paginationStyle = list.DefaultStyles().PaginationStyle.PaddingLeft(4) ActivePaginationDot = lipgloss.NewStyle().Foreground(lipgloss.AdaptiveColor{Light: "170", Dark: "170"}) helpStyle = list.DefaultStyles().HelpStyle.PaddingLeft(4).PaddingBottom(1) - git_scope_style = lipgloss.NewStyle().Foreground(lipgloss.Color("170")).Bold(true) - local_scope_style = lipgloss.NewStyle().Foreground(lipgloss.Color("49")).Bold(true) + git_scope_style = lipgloss.NewStyle().Foreground(lipgloss.Color("49")).Bold(true) + git_scope_author_style = lipgloss.NewStyle().PaddingLeft(4).Foreground(lipgloss.Color("49")) + local_scope_style = lipgloss.NewStyle().Foreground(lipgloss.Color("170")).Bold(true) mixed_scope_style = lipgloss.NewStyle().Foreground(lipgloss.Color("178")).Bold(true) ) -type item string +type item struct { + display string + source int +} var selected = map[string]item{} @@ -95,7 +99,7 @@ func newListKeyMap() *listKeyMap { } } -func (i item) FilterValue() string { return string(i) } +func (i item) FilterValue() string { return string(i.display) } type itemDelegate struct{} @@ -103,35 +107,71 @@ func (d itemDelegate) Height() int { return 1 } func (d itemDelegate) Spacing() int { return 0 } func (d itemDelegate) Update(_ tea.Msg, _ *list.Model) tea.Cmd { return nil } func (d itemDelegate) Render(w io.Writer, m list.Model, index int, listItem list.Item) { - i, ok := listItem.(item) - if !ok { - return - } + i, ok := listItem.(item) + if !ok { + return + } - str := fmt.Sprintf("%d. %s", index+1, i) + // Choose base style according to source + var baseStyle lipgloss.Style + switch i.source { + case git_scope: + baseStyle = git_scope_author_style + case local_scope: + baseStyle = itemStyle + case mixed_scope: + baseStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("178")) + default: + baseStyle = itemStyle + } - fn := itemStyle.Render - if _, ok := selected[string(i)]; ok { - fn = func(s ...string) string { - base := strings.Join(s, " ") - if negation { - base = base + " ^" - } - if index == m.Index() { - return selectedHighlightStyle.Render("> " + base + " [X]") - } else { - return highlightStyle.Render(base + " [X]") - } - } - } else { - if index == m.Index() { - fn = func(s ...string) string { - return selectedItemStyle.Render("> " + strings.Join(s, " ")) - } - } - } + str := fmt.Sprintf("%d. %s", index+1, i.display) - fmt.Fprint(w, fn(str)) + // Helper to render with the base style (applied to the string) + fn := func(s string) string { + return baseStyle.Render(s) + } + + // Selection and cursor highlights (override background/padding) + if _, ok := selected[i.display]; ok { + fn = func(s string) string { + var style lipgloss.Style + if index == m.Index() { + style = lipgloss.NewStyle(). + PaddingLeft(2). + Background(lipgloss.Color("206")). + Foreground(lipgloss.Color("90")) + } else { + style = lipgloss.NewStyle(). + PaddingLeft(4). + Background(lipgloss.Color("236")). + Inherit(baseStyle) // keeps the foreground from baseStyle + } + result := style.Render(s + " [X]") + if negation { + result += " ^" + } + if index == m.Index() { + result = "> " + result + } + return result + } + } else { + if index == m.Index() { + fn = func(s string) string { + style := lipgloss.NewStyle(). + PaddingLeft(2). + Inherit(baseStyle) + return style.Render("> " + s) + } + } else { + fn = func(s string) string { + return baseStyle.PaddingLeft(4).Render(s) + } + } + } + + fmt.Fprint(w, fn(str)) } const ( @@ -153,11 +193,11 @@ func (m Model) Init() tea.Cmd { } func selectToggle(i item) { - if _, ok := selected[string(i)]; ok { - delete(selected, string(i)) + if _, ok := selected[string(i.display)]; ok { + delete(selected, string(i.display)) toggleNegation() } else { - selected[string(i)] = i + selected[string(i.display)] = i } } @@ -241,7 +281,7 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { return m, tea.ClearScreen case key.Matches(msg, m.keys.deleteAuthor): if deletion { - author_str := string(m.list.SelectedItem().(item)) + author_str := string(m.list.SelectedItem().(item).display) author := dupProtect[author_str] utils.DeleteOneAuthor(author) delete(dupProtect, author_str) @@ -324,7 +364,7 @@ func generate_list(scope int) []list.Item { if _, ok := local_dupProtect[str_user]; ok { continue } - items = append(items, item(str_user)) + items = append(items, item{str_user, git_scope}) local_dupProtect[str_user] = short } case local_scope: @@ -334,7 +374,7 @@ func generate_list(scope int) []list.Item { if _, ok := dupProtect[str_user]; ok { continue } - items = append(items, item(str_user)) + items = append(items, item{str_user, local_scope}) dupProtect[str_user] = short } case mixed_scope: @@ -344,17 +384,28 @@ func generate_list(scope int) []list.Item { if _, ok := local_dupProtect[str_user]; ok { continue } - items = append(items, item(str_user)) + if user.From_git { + items = append(items, item{str_user, git_scope}) + } else { + items = append(items, item{str_user, local_scope}) + } local_dupProtect[str_user] = short } - local_dupProtect = map[string]string{} + //TODO: Why was this here????? + // local_dupProtect = map[string]string{} for short, user := range utils.Git_Users { // if items already contains the user, skip it str_user := user.Username + " - " + user.Email + if _, ok := local_dupProtect[str_user]; ok { continue + } + + if user.From_git { + items = append(items, item{str_user, git_scope}) + } else { + items = append(items, item{str_user, local_scope}) } - items = append(items, item(str_user)) local_dupProtect[str_user] = short } } @@ -413,7 +464,7 @@ func listModel(scope ...int) Model { items := generate_list(scope[0]) sort.Slice(items, func(i, j int) bool { - return items[i].(item) < items[j].(item) + return items[i].(item).display < items[j].(item).display }) const defaultWidth = 20 diff --git a/src/cmd/tui/tui_test.go b/src/cmd/tui/tui_test.go index 4059476..6d8fdf5 100644 --- a/src/cmd/tui/tui_test.go +++ b/src/cmd/tui/tui_test.go @@ -157,7 +157,7 @@ func TestEntryTA(t *testing.T) { t.Errorf("Expected 3 inputs, got %d", len(m.list.Items())) } - item := string(m.list.Items()[len(m.list.Items())-1].(item)) + item := string(m.list.Items()[len(m.list.Items())-1].(item).display) split := strings.Split(item, " - ") if split[0] != "test" { diff --git a/src/cmd/utils/test_git_wrapper b/src/cmd/utils/test_git_wrapper new file mode 100644 index 0000000..3f3f005 --- /dev/null +++ b/src/cmd/utils/test_git_wrapper @@ -0,0 +1 @@ +Test content \ No newline at end of file diff --git a/src/cmd/utils/user_util.go b/src/cmd/utils/user_util.go index 5d88401..323c3d6 100644 --- a/src/cmd/utils/user_util.go +++ b/src/cmd/utils/user_util.go @@ -12,11 +12,12 @@ import ( type User struct { Shortname string `json:"shortname"` - Longname string `json:"longname"` + Longname string `json:"longname"` Username string `json:"username"` Email string `json:"email"` Ex bool `json:"ex"` Groups []string `json:"groups"` + From_git bool } type Author struct { @@ -34,14 +35,14 @@ var Git_Users = map[string]User{} var Git_Groups = map[string][]User{} func ContainsUser(users []User, user User) bool { - return slices.ContainsFunc(users, func(u User) bool { - return u.Shortname == user.Shortname && - u.Longname == user.Longname && - u.Username == user.Username && - u.Email == user.Email && - u.Ex == user.Ex && - slices.Equal(u.Groups, user.Groups) - }) + return slices.ContainsFunc(users, func(u User) bool { + return u.Shortname == user.Shortname && + u.Longname == user.Longname && + u.Username == user.Username && + u.Email == user.Email && + u.Ex == user.Ex && + slices.Equal(u.Groups, user.Groups) + }) } func CheckUserFields(user User) bool { @@ -58,7 +59,7 @@ func Define_users(author_file string) { Groups = map[string][]User{} var auth Author - + data, err := os.ReadFile(author_file) if err != nil { panic(fmt.Sprintf("Error reading author file: %v", err)) @@ -67,16 +68,16 @@ func Define_users(author_file string) { if err != nil { panic(fmt.Sprintf("Error unmarshalling json: %v", err)) } - + Authors = auth - + for _, usr := range auth.Authors { Users[usr.Shortname] = usr Users[usr.Longname] = usr if usr.Ex { DefExclude = append(DefExclude, usr.Shortname) } - + group_info := usr.Groups if len(group_info) > 0 { for _, group := range group_info { @@ -99,12 +100,13 @@ func Define_git_users() { // get all authors from git git_authors := GitCheckAuthors() - + for _, usr := range git_authors { if _, ok := Users[usr.Shortname]; !ok { + usr.From_git = true Git_Users[usr.Shortname] = usr Git_Users[usr.Longname] = usr - + group_info := usr.Groups if len(group_info) > 0 { for _, group := range group_info {