From 0e57a48f613787f2244a49515f9b5a52f5498031 Mon Sep 17 00:00:00 2001 From: Theis Date: Tue, 8 Oct 2024 20:00:43 +0200 Subject: [PATCH 01/29] refactor: refactor whole project to based on cobra commands --- go.mod | 3 + src_code/go_src/LICENSE | 0 src_code/go_src/cmd/root.go | 64 ++++ src_code/go_src/cmd/users.go | 39 +++ .../go_src/cmd/utils/author_file_utils.go | 44 +++ src_code/go_src/cmd/utils/commit.go | 110 +++++++ src_code/go_src/cmd/utils/user_util.go | 69 ++++ src_code/go_src/cocommit.go | 153 --------- src_code/go_src/deprecated/cocommit.go | 309 ++++++++++++++++++ .../go_src/{ => deprecated}/cocommit_test.go | 0 src_code/go_src/main.go | 11 + 11 files changed, 649 insertions(+), 153 deletions(-) create mode 100644 src_code/go_src/LICENSE create mode 100644 src_code/go_src/cmd/root.go create mode 100644 src_code/go_src/cmd/users.go create mode 100644 src_code/go_src/cmd/utils/author_file_utils.go create mode 100644 src_code/go_src/cmd/utils/commit.go create mode 100644 src_code/go_src/cmd/utils/user_util.go delete mode 100644 src_code/go_src/cocommit.go create mode 100644 src_code/go_src/deprecated/cocommit.go rename src_code/go_src/{ => deprecated}/cocommit_test.go (100%) create mode 100644 src_code/go_src/main.go diff --git a/go.mod b/go.mod index ffbdcf4..0954662 100644 --- a/go.mod +++ b/go.mod @@ -8,7 +8,10 @@ require ( github.com/99designs/gqlgen v0.17.31 // indirect github.com/Khan/genqlient v0.6.0 // indirect github.com/adrg/xdg v0.4.0 // indirect + github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect + github.com/spf13/cobra v1.8.1 // indirect + github.com/spf13/pflag v1.0.5 // indirect github.com/vektah/gqlparser/v2 v2.5.6 // indirect golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa // indirect golang.org/x/sync v0.6.0 // indirect diff --git a/src_code/go_src/LICENSE b/src_code/go_src/LICENSE new file mode 100644 index 0000000..e69de29 diff --git a/src_code/go_src/cmd/root.go b/src_code/go_src/cmd/root.go new file mode 100644 index 0000000..f2c0e49 --- /dev/null +++ b/src_code/go_src/cmd/root.go @@ -0,0 +1,64 @@ +package cmd + +import ( + "main/src_code/go_src/cmd/utils" + "os" + "fmt" + + "github.com/spf13/cobra" +) + +// rootCmd represents the base command when called without any subcommands +var rootCmd = &cobra.Command{ + Use: `cocommit [co-author2] ... || + cocommit [co-author2:email] ... || + cocommit all || + cocommit ^ ^[co-author2] ... || + cocommit || + cocommit users ||`, + DisableFlagsInUseLine: true, + Short: "A cli tool to help you add co-authors to your git commits", + Long: `A cli tool to help you add co-authors to your git commits`, + //TODO: add bubble tea interface to this + Args: cobra.MinimumNArgs(0), + Run: func(cmd *cobra.Command, args []string) { + // check if the print flag is set + pflag, _ := cmd.Flags().GetBool("print") + // run execute commands again as root run will not call this part + // redundant check for now but will be useful later when we add tui + if len(args) == 1 { + utils.GitWrapper(args[0]) + if pflag { + fmt.Println(args[0]) + } + os.Exit(0) + } + // builds the commit message with the selected authors + message := utils.Commit(args[0], args[1:]) + // prints the commit message to the console if the print flag is set + if pflag { + fmt.Println(message) + } + // runs the git commit command + utils.GitWrapper(message) + }, +} + +// Execute adds all child commands to the root command and sets flags appropriately. +// This is called by main.main(). It only needs to happen once to the rootCmd. +func Execute() { + // author file check + author_file := utils.CheckAuthorFile() + // define users + utils.Define_users(author_file) + + err := rootCmd.Execute() + if err != nil { + os.Exit(1) + } +} + +func init() { + rootCmd.Flags().BoolP("print", "p", false, "Prints the commit message to the console") + +} diff --git a/src_code/go_src/cmd/users.go b/src_code/go_src/cmd/users.go new file mode 100644 index 0000000..6fef0d3 --- /dev/null +++ b/src_code/go_src/cmd/users.go @@ -0,0 +1,39 @@ +package cmd + +import ( + "main/src_code/go_src/cmd/utils" + "os" + "slices" + "sort" + "strings" + + "github.com/spf13/cobra" +) + +var authorfile = utils.Find_authorfile() + +// usersCmd represents the users command +var usersCmd = &cobra.Command{ + Use: "users", + Short: "Displays all users from the author file located at: " + authorfile, + Long: `Displays all users from the author file located at: ` + authorfile, + Run: func(cmd *cobra.Command, args []string) { + //TODO: make this print a bit prettier (sort it and maybe use a table) + println("List of users:\nFormat: / -> Username: Email: ") + seen_users := []utils.User{} + user_sb := []string{} + for name, usr := range utils.Users { + if !slices.Contains(seen_users, usr) { + user_sb = append(user_sb, utils.Users[name].Names+" ->"+" Username: "+usr.Username+" Email: "+usr.Email+"\n") + seen_users = append(seen_users, usr) + } + } + sort.Strings(user_sb) + println(strings.Join(user_sb, "")) + os.Exit(1) + }, +} + +func init() { + rootCmd.AddCommand(usersCmd) +} diff --git a/src_code/go_src/cmd/utils/author_file_utils.go b/src_code/go_src/cmd/utils/author_file_utils.go new file mode 100644 index 0000000..a189f42 --- /dev/null +++ b/src_code/go_src/cmd/utils/author_file_utils.go @@ -0,0 +1,44 @@ +package utils + +import ( + "fmt" + "os" +) + +// Author file utils is a package that contains functions that are used to read +// check, and potentially write to the author file. The author file is a file +// that contains the names and emails of the users that are allowed to commit +// An example of the author file can be found in the examples folder of the repo +func Find_authorfile() string { + if os.Getenv("author_file") == "" { + authors, err := os.UserConfigDir() + if err != nil { + fmt.Println("Error getting user config directory") + os.Exit(2) + } + return (authors + "/cocommit/authors") + } else { + return os.Getenv("author_file") + } +} + +func CheckAuthorFile() string { + authorfile := Find_authorfile() + if _, err := os.Stat(authorfile); os.IsNotExist(err) { + println("Author file not found at: ", authorfile) + println("Would you like to create one? (y/n)") + var response string + _, err := fmt.Scanln(&response) + if err != nil { + println("Error reading response") + } + if response == "y" { + //TODO: Tui response to create author file + //createAuthorFile(authorfile) + } else { + os.Exit(1) + } + } + // This string output is mostly for convenience can mostly be ignored + return authorfile +} diff --git a/src_code/go_src/cmd/utils/commit.go b/src_code/go_src/cmd/utils/commit.go new file mode 100644 index 0000000..e8271b3 --- /dev/null +++ b/src_code/go_src/cmd/utils/commit.go @@ -0,0 +1,110 @@ +package utils + +import ( + "fmt" + "os/exec" + "regexp" + "slices" + "strings" +) + +// This util file is used to create a commit message using a string builder + +// string builder for the commit message +var sb strings.Builder + +// list of excluded authors based on the author file +var excludeMode = []string{} + +// Regex pattern used to create temp users to add to the commit message +var reg, _ = regexp.Compile("([^:]+):([^:]+)") + +func Commit(message string, authors []string) string { + // write the commit message to the string builder + sb.WriteString(message + "\n") + fst := authors[0] + + if fst == "all" || fst == "All" { + add_x_users(excludeMode) + goto skip_loop + } else if Groups[fst] != nil { + excludeMode = group_selection(Groups[fst], excludeMode) + add_x_users(excludeMode) + goto skip_loop + } + + // Loop that adds users + for _, committer := range authors { + if _, ok := Users[committer]; ok { + sb_author(committer) + } else if match := reg.MatchString(committer); match { + str := strings.Split(committer, ":") + + sb.WriteString("\nCo-authored-by: ") + sb.WriteString(str[0]) + sb.WriteString(" <") + sb.WriteString(str[1]) + sb.WriteRune('>') + + } else if committer[0] == '^' { // Negations + excludeMode = append(excludeMode, Users[committer[1:]].Username) + } else { + println(committer, " was unknown. User either not defined or name typed wrong") + } + } + if len(excludeMode) > 0 { + add_x_users(excludeMode) + } + + // Skip label for edge cases at top of function +skip_loop: + return sb.String() +} + +func GitWrapper(commit string) { + // commit shell command + cmd := exec.Command("git", "commit", "-m", commit) + + // https://stackoverflow.com/questions/18159704/how-to-debug-exit-status-1-error-when-running-exec-command-in-golang + + cmd_output, err := cmd.CombinedOutput() + + if err != nil { + println(fmt.Sprint(err) + " : " + string(cmd_output)) + } else { + println(string(cmd_output)) + } +} + +// helper function to add an author to the commit message +func sb_author(committer string) { + sb.WriteString("\nCo-authored-by: ") + sb.WriteString(Users[committer].Username) + sb.WriteString(" <") + sb.WriteString(Users[committer].Email) + sb.WriteRune('>') +} + +// helper function to add x amount of users to the commit message +func add_x_users(excludeMode []string) { + if len(DefExclude) > 0 { + excludeMode = append(excludeMode, DefExclude...) + } + for key, user := range Users { + if !slices.Contains(excludeMode, user.Username) { + sb_author(key) + excludeMode = append(excludeMode, user.Username) + } + } +} + +// helper function to select a group of users to exclude in the commit message +func group_selection(group []User, excludeMode []string) []string { + for _, user := range Users { + if !(slices.Contains(group, user)) { + excludeMode = append(excludeMode, user.Username) + } + } + + return excludeMode +} diff --git a/src_code/go_src/cmd/utils/user_util.go b/src_code/go_src/cmd/utils/user_util.go new file mode 100644 index 0000000..55bdaab --- /dev/null +++ b/src_code/go_src/cmd/utils/user_util.go @@ -0,0 +1,69 @@ +package utils + +import ( + "bufio" + "os" + "strings" +) + +// This util file is used to handle users and their information +type User struct { + Username string + Email string + Names string +} + +var Users = map[string]User{} +var DefExclude = []string{} +var Groups = map[string][]User{} + +func Define_users(author_file string) { + file, err := os.Open(author_file) + if err != nil { + print("File not found") + os.Exit(2) + } + defer file.Close() + + scanner := bufio.NewScanner(file) + + // eat a single input + scanner.Scan() + + // reads the input of authors file and formats accordingly + for scanner.Scan() { + input_str := scanner.Text() + group_info := []string{} + if strings.Contains(input_str, ";;") { + input := strings.Split(input_str, ";;") + input_str = input[0] + group_info = append(group_info, strings.Split(input[1], "|")...) + } + info := strings.Split(input_str, "|") + usr := User{Username: info[2], Email: info[3], Names: info[0] + "/" + info[1]} + Users[info[0]] = usr + Users[info[1]] = usr + // Adds users with the ex tag to the defExclude list + if len(info) == 5 { + if info[4] == "ex" { + DefExclude = append(DefExclude, info[2]) + } + } else if len(group_info) > 0 { + // Group assignment + for _, group := range group_info { + if Groups[group] == nil { + Groups[group] = []User{usr} + } else { + //TODO: Try and find a cleaner way of doing this + usr_lst := Groups[group] + usr_lst = append(usr_lst, usr) + Groups[group] = usr_lst + } + } + } + } + + if err := scanner.Err(); err != nil { + os.Exit(2) + } +} diff --git a/src_code/go_src/cocommit.go b/src_code/go_src/cocommit.go deleted file mode 100644 index ece86ec..0000000 --- a/src_code/go_src/cocommit.go +++ /dev/null @@ -1,153 +0,0 @@ -package main - -import ( - "bufio" - "fmt" - "os" - "os/exec" - "regexp" - "slices" - "strings" -) - -type user struct { - username string - email string -} - -var users = make(map[string]user) -var sb strings.Builder -var all_flag = false - -func main() { - - - // Reads a shell env variable :: author_file - authors := os.Getenv("author_file") - - file, err := os.Open(authors) - if err != nil { - print("File not found") - os.Exit(2) - } - defer file.Close() - - scanner := bufio.NewScanner(file) - - // eat a single input - scanner.Scan() - - // reads the input of authors file and formats accordingly - for scanner.Scan() { - info := strings.Split(scanner.Text(), "|") - usr := user{username: info[2], email: info[3]} - users[info[0]] = usr - users[info[1]] = usr - } - - if err := scanner.Err(); err != nil { - os.Exit(2) - } - - args := os.Args[1:] - - NoInput(args, users) - - excludeMode := []string{} - - // builds the commit message with the selected authors - sb.WriteString(string(args[0]) + "\n") - reg, _ := regexp.Compile("([^:]+):([^:]+)") - - if args[1] == "all" || args[1] == "All" { - all_flag = true - goto skip_loop - } - - - for _, committer := range args[1:] { - if _, ok := users[committer]; ok { - sb_author(committer) - } else if match := reg.MatchString(committer); match { - str := strings.Split(committer, ":") - - sb.WriteString("\nCo-authored-by: ") - sb.WriteString(str[0]) - sb.WriteString(" <") - sb.WriteString(str[1]) - sb.WriteRune('>') - - } else if committer[0] == '^' { - excludeMode = append(excludeMode, users[committer[1:]].username) - - } else { - println(committer, " was unknown. User either not defined or name typed wrong") - } - } - - skip_loop: - - if len(excludeMode) > 0 || all_flag { - add_x_users(excludeMode) - } - - - // commit msg built - commit := sb_build() - - //NOTE: Uncomment for testing - //print(commit) - - // commit shell command - cmd := exec.Command("git", "commit", "-m", commit) - - // https://stackoverflow.com/questions/18159704/how-to-debug-exit-status-1-error-when-running-exec-command-in-golang - - cmd_output, err := cmd.CombinedOutput() - - if err != nil { - println(fmt.Sprint(err) + " : " + string(cmd_output)) - } else { - println(string(cmd_output)) - } - -} - -func add_x_users(excludeMode []string) { - for key, user := range users { - if !slices.Contains(excludeMode, user.username) { - sb_author(key) - excludeMode = append(excludeMode, user.username) - } - } -} - -func sb_build() string { - return sb.String() -} - -func sb_author(committer string) { - sb.WriteString("\nCo-authored-by: ") - sb.WriteString(users[committer].username) - sb.WriteString(" <") - sb.WriteString(users[committer].email) - sb.WriteRune('>') -} - -// TODO: move half this into another function and call before building users to improve performance -func NoInput(args []string, users map[string]user) { - if len(args) < 2 { - // If you call binary with users prints users - if len(args) == 1 && args[0] == "users" { - println("List of users:") - for name, usr := range users { - println(name, " ->", " Username:", usr.username, " Email:", usr.email) - } - os.Exit(1) - } - // if calling binary with nothing or only string - print("Usage: cocommit [co-author2] [co-author3] || \n cocommit [co-author2:email] [co-author3:email] || Mixes of both") - - os.Exit(1) - } -} diff --git a/src_code/go_src/deprecated/cocommit.go b/src_code/go_src/deprecated/cocommit.go new file mode 100644 index 0000000..f0a4c7f --- /dev/null +++ b/src_code/go_src/deprecated/cocommit.go @@ -0,0 +1,309 @@ +package main + +import ( + "bufio" + "fmt" + "os" + "os/exec" + "regexp" + "slices" + "sort" + "strings" +) + +type user struct { + username string + email string + names string +} +//TODO: Remove later once everything is up and running with the new version + +// Map of all th users in the author file +var users = make(map[string]user) + +// String builder for building the commit message +var sb strings.Builder + +// Flag that can be toggled to include all users in a commit message (excluding defExclude) +var all_flag = false + +// DefaultExclude -> A list that contains users marked with ex meaning +// they should not be included in all and negations +var defExclude = []string{} + +// Group map for adding people as a group +var groups = make(map[string][]user) + +func main() { + + // Reads a shell env variable :: author_file + var authors string + envVar := os.Getenv("author_file") + if envVar == "" { + var err error + authors, err = os.UserConfigDir() + authors += "/cocommit/authors" + if err != nil { + println("Error: ", err) + os.Exit(1) + } + } else { + authors = envVar + } + + file, err := os.Open(authors) + if err != nil { + authors, _ = os.UserConfigDir() + authors += "/cocommit/authors" + println("Authors file cannot be found. Please check the path to the file. \nEither set the author_file env variable or place the file in the default location. \nDefault location: " + authors) + println("If you want to create a blank template file at the default location type y|yes or cancel with n|no") + var input string + fmt.Scanln(&input) + if input == "y" || input == "yes" { + create_author_file("yes") + os.Exit(1) + } else { + println("Cancelled") + os.Exit(1) + } + } + defer file.Close() + + scanner := bufio.NewScanner(file) + + // eat a single input + scanner.Scan() + + // reads the input of authors file and formats accordingly + for scanner.Scan() { + input_str := scanner.Text() + group_info := []string{} + if strings.Contains(input_str, ";;") { + input := strings.Split(input_str, ";;") + input_str = input[0] + group_info = append(group_info, strings.Split(input[1], "|")...) + } + info := strings.Split(input_str, "|") + usr := user{username: info[2], email: info[3], names: info[0] + "/" + info[1]} + users[info[0]] = usr + users[info[1]] = usr + // Adds users with the ex tag to the defExclude list + if len(info) == 5 { + if info[4] == "ex" { + defExclude = append(defExclude, info[2]) + } + } else if len(group_info) > 0 { + // Group assignment + for _, group := range group_info { + if groups[group] == nil { + groups[group] = []user{usr} + } else { + //TODO: Try and find a cleaner way of doing this + usr_lst := groups[group] + usr_lst = append(usr_lst, usr) + groups[group] = usr_lst + } + } + } + } + + check_err(scanner.Err()) + // Removes the call command for the program + args := os.Args[1:] + + // Checks if the user called the program with any inputs or with non commit args + NoInput(args, users) + + // This list is used when doing negations and for removing duplicate users during string building + excludeMode := []string{} + + // builds the commit message with the selected authors + sb.WriteString(string(args[0]) + "\n") + + // Regex that catches one off authors + reg, _ := regexp.Compile("([^:]+):([^:]+)") + + if args[1] == "all" || args[1] == "All" { + all_flag = true + goto skip_loop + } else if groups[args[1]] != nil { + // Selects everybody that isn't the group members and adds them to the defExclude + excludeMode = group_selection(groups[args[1]], excludeMode) + goto skip_loop + } + + // Loop that adds users + for _, committer := range args[1:] { + if _, ok := users[committer]; ok { + sb_author(committer) + } else if match := reg.MatchString(committer); match { + str := strings.Split(committer, ":") + + sb.WriteString("\nCo-authored-by: ") + sb.WriteString(str[0]) + sb.WriteString(" <") + sb.WriteString(str[1]) + sb.WriteRune('>') + + } else if committer[0] == '^' { // Negations + excludeMode = append(excludeMode, users[committer[1:]].username) + + } else { + println(committer, " was unknown. User either not defined or name typed wrong") + } + } + + // Skip label for adding all +skip_loop: + + if len(excludeMode) > 0 || all_flag { + // adds all users not in the excludeMode list + add_x_users(excludeMode) + } + + // commit msg built + commit := sb_build() + + print(commit) + + //NOTE: Uncomment for testing + //print(commit) + + // commit shell command + cmd := exec.Command("git", "commit", "-m", commit) + + // https://stackoverflow.com/questions/18159704/how-to-debug-exit-status-1-error-when-running-exec-command-in-golang + + cmd_output, err := cmd.CombinedOutput() + + if err != nil { + println(fmt.Sprint(err) + " : " + string(cmd_output)) + } else { + println(string(cmd_output)) + } + +} + +func group_selection(group []user, excludeMode []string) []string { + for _, user := range users { + if !(slices.Contains(group, user)) { + excludeMode = append(excludeMode, user.username) + } + } + + return excludeMode +} + +func add_x_users(excludeMode []string) { + if len(defExclude) > 0 { + excludeMode = append(excludeMode, defExclude...) + } + for key, user := range users { + if !slices.Contains(excludeMode, user.username) { + sb_author(key) + excludeMode = append(excludeMode, user.username) + } + } +} + +func sb_build() string { + return sb.String() +} + +func sb_author(committer string) { + sb.WriteString("\nCo-authored-by: ") + sb.WriteString(users[committer].username) + sb.WriteString(" <") + sb.WriteString(users[committer].email) + sb.WriteRune('>') +} + +// TODO: move half this into another function and call before building users to improve performance +func NoInput(args []string, users map[string]user) { + if len(args) < 2 { + // If you call binary with users prints users + if len(args) == 1 && args[0] == "users" { + println("List of users:\nFormat: / -> Username: Email: ") + seen_users := []user{} + user_sb := []string{} + for name, usr := range users { + if !slices.Contains(seen_users, usr) { + user_sb = append(user_sb, users[name].names+" ->"+" Username: "+usr.username+" Email: "+usr.email+"\n") + seen_users = append(seen_users, usr) + } + } + sort.Strings(user_sb) + println(strings.Join(user_sb, "")) + os.Exit(1) + } else if len(args) == 1 && args[0] == "config" { + create_author_file() + } + // if calling binary with nothing or only string + command_options := []string{ + "cocommit [co-author2] [co-author3]", + "cocommit [co-author2:email] [co-author3:email]", + "cocommit all", + "cocommit ^ ^[co-author2]", + "cocommit ", + "cocommit users", + } + println("Usage:") + for _, v := range command_options { + print(v) + println(" ||") + } + println("Mixes of both") + + os.Exit(1) + } +} + +func create_author_file(param ...string) { + var input string + authors, err := os.UserConfigDir() + + if err != nil { + println("Error: ", err) + os.Exit(1) + } + if len(param) > 0 { + input = "yes" + goto skip + } + println("This command will create a blank template auhtor file in the default location. \nDefault location: " + authors + "\nConfirm by typing y|yes or cancel with n|no") + fmt.Scanln(&input) + if err != nil { + println("Error: ", err) + os.Exit(1) + } +skip: + if input == "y" || input == "yes" { + // create folder cocommit in .config + authors += "/cocommit" + err := os.MkdirAll(authors, 0755) + if err != nil { + println("Error in dir creation: ", err.Error()) + os.Exit(1) + } + authors += "/authors" + file, err := os.Create(authors) + if err != nil { + println("Error: ", err.Error()) + os.Exit(1) + } + defer file.Close() + file.WriteString("name_short|Name|Username|email (opt: |ex) (opt: ;;group1 or ;;group1|group2|group3...)\n") + println("File created successfully at: " + authors) + os.Exit(1) + } else { + println("Cancelled") + os.Exit(1) + } +} + +func check_err(e error) { + if e != nil { + fmt.Println(e.Error()) + os.Exit(2) + } +} \ No newline at end of file diff --git a/src_code/go_src/cocommit_test.go b/src_code/go_src/deprecated/cocommit_test.go similarity index 100% rename from src_code/go_src/cocommit_test.go rename to src_code/go_src/deprecated/cocommit_test.go diff --git a/src_code/go_src/main.go b/src_code/go_src/main.go new file mode 100644 index 0000000..54c4d10 --- /dev/null +++ b/src_code/go_src/main.go @@ -0,0 +1,11 @@ +/* +Copyright © 2024 NAME HERE + +*/ +package main + +import "main/src_code/go_src/cmd" + +func main() { + cmd.Execute() +} From 527269f788ab4c00943e0276955adaf45757d2c5 Mon Sep 17 00:00:00 2001 From: Theis Date: Thu, 10 Oct 2024 21:42:16 +0200 Subject: [PATCH 02/29] refactor: change root command to include commit wrapper options --- go.mod | 28 ++++++++++++++++++++++++---- src_code/go_src/cmd/root.go | 29 ++++++++++++++++++++++++----- 2 files changed, 48 insertions(+), 9 deletions(-) diff --git a/go.mod b/go.mod index 0954662..d5fea6d 100644 --- a/go.mod +++ b/go.mod @@ -2,18 +2,38 @@ module main go 1.21.0 -require dagger.io/dagger v0.10.0 +require ( + dagger.io/dagger v0.10.0 + github.com/charmbracelet/bubbles v0.20.0 + github.com/charmbracelet/bubbletea v1.1.1 + github.com/charmbracelet/lipgloss v0.13.0 + github.com/spf13/cobra v1.8.1 +) require ( github.com/99designs/gqlgen v0.17.31 // indirect github.com/Khan/genqlient v0.6.0 // indirect github.com/adrg/xdg v0.4.0 // indirect + github.com/atotto/clipboard v0.1.4 // indirect + github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect + github.com/charmbracelet/x/ansi v0.2.3 // indirect + github.com/charmbracelet/x/term v0.2.0 // indirect + github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect + github.com/lucasb-eyer/go-colorful v1.2.0 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect + github.com/mattn/go-localereader v0.0.1 // indirect + github.com/mattn/go-runewidth v0.0.16 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect - github.com/spf13/cobra v1.8.1 // indirect + github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 // indirect + github.com/muesli/cancelreader v0.2.2 // indirect + github.com/muesli/termenv v0.15.2 // indirect + github.com/rivo/uniseg v0.4.7 // indirect + github.com/sahilm/fuzzy v0.1.1 // indirect github.com/spf13/pflag v1.0.5 // indirect github.com/vektah/gqlparser/v2 v2.5.6 // indirect golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa // indirect - golang.org/x/sync v0.6.0 // indirect - golang.org/x/sys v0.14.0 // indirect + golang.org/x/sync v0.8.0 // indirect + golang.org/x/sys v0.26.0 // indirect + golang.org/x/text v0.19.0 // indirect ) diff --git a/src_code/go_src/cmd/root.go b/src_code/go_src/cmd/root.go index f2c0e49..4e8c167 100644 --- a/src_code/go_src/cmd/root.go +++ b/src_code/go_src/cmd/root.go @@ -1,9 +1,10 @@ package cmd import ( + "fmt" + "main/src_code/go_src/cmd/tui" "main/src_code/go_src/cmd/utils" "os" - "fmt" "github.com/spf13/cobra" ) @@ -26,13 +27,31 @@ var rootCmd = &cobra.Command{ pflag, _ := cmd.Flags().GetBool("print") // run execute commands again as root run will not call this part // redundant check for now but will be useful later when we add tui - if len(args) == 1 { - utils.GitWrapper(args[0]) - if pflag { - fmt.Println(args[0]) + wrap_around: + switch len(args) { + case 0: + // launch the tui + sel_auth := tui.Entry() + for _, a := range sel_auth { + fmt.Println(a) } os.Exit(0) + case 1: + if len(args) == 1 { + utils.GitWrapper(args[0]) + if pflag { + fmt.Println(args[0]) + } + os.Exit(0) + } } + + // check if user included -m tag and remove. Wrap around for safety's sake + if args[0] == "-m" { + args = args[1:] + goto wrap_around + } + // builds the commit message with the selected authors message := utils.Commit(args[0], args[1:]) // prints the commit message to the console if the print flag is set From a78cdf37f9fedf63b35e17679c8c0f767aac8b9b Mon Sep 17 00:00:00 2001 From: Theis Date: Thu, 10 Oct 2024 21:42:59 +0200 Subject: [PATCH 03/29] feat: add buble tea tui elements for creating authors and selecting authors. More to come --- src_code/go_src/cmd/tui/tui_create_author.go | 226 +++++++++++++++ src_code/go_src/cmd/tui/tui_list.go | 278 +++++++++++++++++++ 2 files changed, 504 insertions(+) create mode 100644 src_code/go_src/cmd/tui/tui_create_author.go create mode 100644 src_code/go_src/cmd/tui/tui_list.go diff --git a/src_code/go_src/cmd/tui/tui_create_author.go b/src_code/go_src/cmd/tui/tui_create_author.go new file mode 100644 index 0000000..a3cb08b --- /dev/null +++ b/src_code/go_src/cmd/tui/tui_create_author.go @@ -0,0 +1,226 @@ +package tui + +// A simple example demonstrating the use of multiple text input components +// from the Bubbles component library. + +import ( + "fmt" + "os" + "strings" + + //"github.com/charmbracelet/bubbles/cursor" + "github.com/charmbracelet/bubbles/textinput" + tea "github.com/charmbracelet/bubbletea" + "github.com/charmbracelet/lipgloss" +) + +var ( + focusedStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("205")) + blurredStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("240")) + cursorStyle = focusedStyle + noStyle = lipgloss.NewStyle() + cursorModeHelpStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("244")) + focusedButton = focusedStyle.Render("[ Submit ]") + focusedExclude = focusedStyle.Render("[ Exclude ]") + blurredButton = fmt.Sprintf("[ %s ]", blurredStyle.Render("Submit")) + excludeButton = fmt.Sprintf("[ %s ]", blurredStyle.Render("Exclude")) +) + +type model_ca struct { + focusIndex int + inputs []textinput.Model + quitting bool + exclude bool +} + +func initialModel() model_ca { + m := model_ca{ + inputs: make([]textinput.Model, 5), + } + + var t textinput.Model + for i := range m.inputs { + t = textinput.New() + t.Cursor.Style = cursorStyle + t.CharLimit = 32 + + switch i { + case 0: + t.Placeholder = "shortname (e.g. jo)" + t.Focus() + t.PromptStyle = focusedStyle + t.TextStyle = focusedStyle + case 1: + t.Placeholder = "Long name (e.g. JohnDoe)" + case 2: + t.Placeholder = "Username (e.g. JohnDoe-gh)" + case 3: + t.Placeholder = "Email (e.g. JohnDoe@domain.do" + case 4: + t.Placeholder = "Group tags (e.g. gr1|gr2)" + } + + m.inputs[i] = t + } + + return m +} + +func (m model_ca) Init() tea.Cmd { + return textinput.Blink +} + +func (m model_ca) Update(msg tea.Msg) (tea.Model, tea.Cmd) { + switch msg := msg.(type) { + case tea.KeyMsg: + switch msg.String() { + case "ctrl+c", "esc": + m.inputs = nil + return m, tea.Quit + + // Set focus to next input + case "tab", "shift+tab", "enter", "up", "down": + s := msg.String() + + // Did the user press enter while the submit button was focused? + // If so, exit. + if s == "enter" && m.focusIndex == len(m.inputs)+1 { + m.quitting = true + return m, tea.Quit + } else if s == "enter" && m.focusIndex == len(m.inputs) { + // toggle exclude + m.exclude = !m.exclude + return m, nil + } + + // Cycle indexes + if s == "up" || s == "shift+tab" { + m.focusIndex-- + } else { + m.focusIndex++ + } + + if m.focusIndex > len(m.inputs)+1 { + m.focusIndex = 0 + } else if m.focusIndex < 0 { + m.focusIndex = len(m.inputs) + } + + cmds := make([]tea.Cmd, len(m.inputs)) + for i := 0; i <= len(m.inputs)-1; i++ { + if i == m.focusIndex { + // Set focused state + cmds[i] = m.inputs[i].Focus() + m.inputs[i].PromptStyle = focusedStyle + m.inputs[i].TextStyle = focusedStyle + continue + } + // Remove focused state + m.inputs[i].Blur() + m.inputs[i].PromptStyle = noStyle + m.inputs[i].TextStyle = noStyle + } + + return m, tea.Batch(cmds...) + } + } + + // Handle character input and blinking + cmd := m.updateInputs(msg) + + return m, cmd +} + +func (m *model_ca) updateInputs(msg tea.Msg) tea.Cmd { + cmds := make([]tea.Cmd, len(m.inputs)) + + // Only text inputs with Focus() set will respond, so it's safe to simply + // update all of them here without any further logic. + for i := range m.inputs { + m.inputs[i], cmds[i] = m.inputs[i].Update(msg) + } + + return tea.Batch(cmds...) +} + +func (m model_ca) View() string { + if m.quitting { + return "" + } + + var b strings.Builder + + for i := range m.inputs { + b.WriteString(m.inputs[i].View()) + if i < len(m.inputs)-1 { + b.WriteRune('\n') + } + } + + button := &blurredButton + if m.focusIndex == len(m.inputs)+1 { + button = &focusedButton + } + exclude := &excludeButton + if m.focusIndex == len(m.inputs) { + exclude = &focusedExclude + } + + if m.exclude { + fmt.Fprintf(&b, "\n\n%s: [X]\n\n", *exclude) + } else { + fmt.Fprintf(&b, "\n\n%s: [ ]\n\n", *exclude) + } + + fmt.Fprintf(&b, "\n\n%s\n\n", *button) + + b.WriteString(cursorModeHelpStyle.Render()) + + return b.String() +} + +func Entry_CA() { + m, err := tea.NewProgram(initialModel()).Run() + if err != nil { + fmt.Printf("could not start program: %s\n", err) + os.Exit(1) + } + + + + if len(m.(model_ca).inputs) > 0 && + m.(model_ca).inputs[0].Value() != "" && + m.(model_ca).inputs[1].Value() != "" && + m.(model_ca).inputs[2].Value() != "" && + m.(model_ca).inputs[3].Value() != "" { + f, err := os.OpenFile("author_file", os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0600) + if err != nil { + panic(err) + } + + defer f.Close() + + sb := strings.Builder{} + + sb.WriteString(fmt.Sprintf("%s|%s|%s|%s", + m.(model_ca).inputs[0].Value(), + m.(model_ca).inputs[1].Value(), + m.(model_ca).inputs[2].Value(), + m.(model_ca).inputs[3].Value())) + + if m.(model_ca).exclude { + sb.WriteString(fmt.Sprintf("|%s", "ex")) + } + + if m.(model_ca).inputs[4].Value() != "" { + sb.WriteString(fmt.Sprintf(";;%s", m.(model_ca).inputs[4].Value())) + } + + sb.WriteRune('\n') + + if _, err = f.WriteString(sb.String()); err != nil { + panic(err) + } + } + +} \ No newline at end of file diff --git a/src_code/go_src/cmd/tui/tui_list.go b/src_code/go_src/cmd/tui/tui_list.go new file mode 100644 index 0000000..6c68b7c --- /dev/null +++ b/src_code/go_src/cmd/tui/tui_list.go @@ -0,0 +1,278 @@ +package tui + +import ( + "fmt" + "io" + "main/src_code/go_src/cmd/utils" + "os" + "sort" + "strings" + + "github.com/charmbracelet/bubbles/key" + "github.com/charmbracelet/bubbles/list" + tea "github.com/charmbracelet/bubbletea" + "github.com/charmbracelet/lipgloss" +) + +const listHeight = 14 + +var ( + titleStyle = lipgloss.NewStyle().MarginLeft(2) + itemStyle = lipgloss.NewStyle().PaddingLeft(4) + selectedItemStyle = lipgloss.NewStyle().PaddingLeft(2).Foreground(lipgloss.Color("170")) + highlightStyle = lipgloss.NewStyle().PaddingLeft(4).Background(lipgloss.Color("236")).Foreground(lipgloss.Color("17")) + selectedHighlightStyle = lipgloss.NewStyle().PaddingLeft(2).Background(lipgloss.Color("236")).Foreground(lipgloss.Color("170")) + paginationStyle = list.DefaultStyles().PaginationStyle.PaddingLeft(4) + helpStyle = list.DefaultStyles().HelpStyle.PaddingLeft(4).PaddingBottom(1) + //quitTextStyle = lipgloss.NewStyle().Margin(1, 0, 2, 4) +) + +type item string + +var selected = map[string]item{} + +var negation = false + +type listKeyMap struct { + selectAll key.Binding + negation key.Binding + groupSelect key.Binding + selectOne key.Binding + createAuthor key.Binding +} + +func newListKeyMap() *listKeyMap { + return &listKeyMap{ + selectAll: key.NewBinding( + key.WithKeys("A"), + key.WithHelp("A", "Add all authors"), + ), + negation: key.NewBinding( + key.WithKeys("n"), + key.WithHelp("n", "Toggle negation and select author"), + ), + groupSelect: key.NewBinding( + key.WithKeys("f"), + key.WithHelp("f", "Select group"), + ), + selectOne: key.NewBinding( + key.WithKeys(" "), + key.WithHelp("space", "Select author"), + ), + createAuthor: key.NewBinding( + key.WithKeys("C"), + key.WithHelp("C", "Create new author"), + ), + } +} + + +//TODO: Try and add filtering later down the line +func (i item) FilterValue() string { return string(i) } + +type itemDelegate struct{} + +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 + } + + + str := fmt.Sprintf("%d. %s", index+1, i) + + //TODO: add negation style where all items are flipped in selection + + 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, " ")) + } + } + } + + + fmt.Fprint(w, fn(str)) +} + +type model struct { + list list.Model + keys *listKeyMap + quitting bool +} + +func (m model) Init() tea.Cmd { + return nil +} + +func selectToggle(i item) { + if _, ok := selected[string(i)]; ok { + delete(selected, string(i)) + toggleNegation() + } else { + selected[string(i)] = i + } +} + +func toggleNegation() { + if len(selected) == 0 { + negation = false + } +} + +func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { + + switch msg := msg.(type) { + case tea.WindowSizeMsg: + m.list.SetWidth(msg.Width) + return m, nil + + // If filtering is enabled, skip key handling + case tea.KeyMsg: + if m.list.FilterState() == list.Filtering { + break + } + // Handle keys from keyList (help menu) + switch { + case key.Matches(msg, m.keys.negation): + i, ok := m.list.SelectedItem().(item) + if ok { + negation = true + selectToggle(i) + } + + case key.Matches(msg, m.keys.selectOne): + i, ok := m.list.SelectedItem().(item) + if ok { + selectToggle(i) + } + + case key.Matches(msg, m.keys.selectAll): + //TODO: maybe look at behavior of this when auth are already selected + negation = false + for _, i := range m.list.Items() { + selectToggle(i.(item)) + } + + case key.Matches(msg, m.keys.groupSelect): + // group code goes here + + case key.Matches(msg, m.keys.createAuthor): + Entry_CA() + return m, tea.ClearScreen + } + // extra key options + switch keypress := msg.String(); keypress { + case "q", "ctrl+c", "esc": + m.quitting = true + selected = nil + return m, tea.Quit + + case "enter": + m.quitting = true + return m, tea.Quit + } + } + + var cmd tea.Cmd + m.list, cmd = m.list.Update(msg) + return m, cmd +} + +func (m model) View() string { + if m.quitting { + return "" //quitTextStyle.Render(strings.Join(m.choice, " ")) + } + + return "\n" + m.list.View() +} + +//TODO: pass list in as a param to allow for group selection using same template +func Entry() []string { + items := []list.Item{} + dupProtect := map[string]string{} + + listKeys := newListKeyMap() + + // Add items to the list + for short, user := range utils.Users { + // if items already contains the user, skip it + str_user := user.Username + " - " + user.Email + if _, ok := dupProtect[str_user]; ok { + continue + } + items = append(items, item(str_user)) + dupProtect[str_user] = short + } + + sort.Slice(items, func(i, j int) bool { + return items[i].(item) < items[j].(item) + }) + + const defaultWidth = 20 + + l := list.New(items, itemDelegate{}, defaultWidth, listHeight) + l.Title = "Select authors to add to commit" + l.SetShowStatusBar(false) + l.SetFilteringEnabled(true) // Enable filtering + l.Styles.Title = titleStyle + l.Styles.PaginationStyle = paginationStyle + l.AdditionalShortHelpKeys = // Add help keys (main page) + func() []key.Binding { + return []key.Binding{ + listKeys.selectOne, + } + } + l.AdditionalFullHelpKeys = // Add help keys (help menu) + func() []key.Binding { + return []key.Binding{ + listKeys.selectAll, + listKeys.negation, + listKeys.groupSelect, + listKeys.createAuthor, + } + } + l.Styles.HelpStyle = helpStyle + + m := model{list: l, keys: listKeys} + + f, err := tea.NewProgram(m).Run() + if err != nil { + fmt.Println("Error running program:", err) + os.Exit(1) + } + + // Assert the final tea.Model to our local model and print the choice. + + output := []string{} + + for i := range selected { + short := dupProtect[i] + if negation { + short = "^" + short + } + + output = append(output, short) + } + + if _, ok := f.(model); ok && len(output) > 0 { + return output + } + return nil +} \ No newline at end of file From 55fe19653635ef493be8214c5a2dedb8f64bf6ad Mon Sep 17 00:00:00 2001 From: Theis Date: Thu, 10 Oct 2024 22:36:29 +0200 Subject: [PATCH 04/29] feat: finish add and remove author bindings and tui elements --- src_code/go_src/cmd/tui/tui_create_author.go | 10 ++-- src_code/go_src/cmd/tui/tui_list.go | 22 +++++++- .../go_src/cmd/utils/author_file_utils.go | 53 +++++++++++++++++++ src_code/go_src/cmd/utils/user_util.go | 4 ++ 4 files changed, 84 insertions(+), 5 deletions(-) diff --git a/src_code/go_src/cmd/tui/tui_create_author.go b/src_code/go_src/cmd/tui/tui_create_author.go index a3cb08b..0643d4d 100644 --- a/src_code/go_src/cmd/tui/tui_create_author.go +++ b/src_code/go_src/cmd/tui/tui_create_author.go @@ -5,6 +5,7 @@ package tui import ( "fmt" + "main/src_code/go_src/cmd/utils" "os" "strings" @@ -179,7 +180,7 @@ func (m model_ca) View() string { return b.String() } -func Entry_CA() { +func Entry_CA() string{ m, err := tea.NewProgram(initialModel()).Run() if err != nil { fmt.Printf("could not start program: %s\n", err) @@ -201,6 +202,7 @@ func Entry_CA() { defer f.Close() sb := strings.Builder{} + sb.WriteRune('\n') sb.WriteString(fmt.Sprintf("%s|%s|%s|%s", m.(model_ca).inputs[0].Value(), @@ -216,11 +218,13 @@ func Entry_CA() { sb.WriteString(fmt.Sprintf(";;%s", m.(model_ca).inputs[4].Value())) } - sb.WriteRune('\n') + //sb.WriteRune('\n') if _, err = f.WriteString(sb.String()); err != nil { panic(err) } + utils.Define_users(utils.Find_authorfile()) + return m.(model_ca).inputs[0].Value() } - + return "" } \ No newline at end of file diff --git a/src_code/go_src/cmd/tui/tui_list.go b/src_code/go_src/cmd/tui/tui_list.go index 6c68b7c..e343258 100644 --- a/src_code/go_src/cmd/tui/tui_list.go +++ b/src_code/go_src/cmd/tui/tui_list.go @@ -33,12 +33,15 @@ var selected = map[string]item{} var negation = false +var dupProtect = map[string]string{} + type listKeyMap struct { selectAll key.Binding negation key.Binding groupSelect key.Binding selectOne key.Binding createAuthor key.Binding + deleteAuthor key.Binding } func newListKeyMap() *listKeyMap { @@ -63,6 +66,10 @@ func newListKeyMap() *listKeyMap { key.WithKeys("C"), key.WithHelp("C", "Create new author"), ), + deleteAuthor: key.NewBinding( + key.WithKeys("D"), + key.WithHelp("D", "Delete author"), + ), } } @@ -174,7 +181,19 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { // group code goes here case key.Matches(msg, m.keys.createAuthor): - Entry_CA() + author := Entry_CA() + if author != "" { + item_str := utils.Users[author].Username + " - " + utils.Users[author].Email + dupProtect[item_str] = author + m.list.InsertItem(len(m.list.Items())+1,item(item_str)) + } + return m, tea.ClearScreen + case key.Matches(msg, m.keys.deleteAuthor): + author_str := string(m.list.SelectedItem().(item)) + author := dupProtect[author_str] + utils.DeleteOneAuthor(author) + delete(dupProtect, author_str) + m.list.RemoveItem(m.list.Index()) return m, tea.ClearScreen } // extra key options @@ -206,7 +225,6 @@ func (m model) View() string { //TODO: pass list in as a param to allow for group selection using same template func Entry() []string { items := []list.Item{} - dupProtect := map[string]string{} listKeys := newListKeyMap() diff --git a/src_code/go_src/cmd/utils/author_file_utils.go b/src_code/go_src/cmd/utils/author_file_utils.go index a189f42..c672300 100644 --- a/src_code/go_src/cmd/utils/author_file_utils.go +++ b/src_code/go_src/cmd/utils/author_file_utils.go @@ -1,8 +1,11 @@ package utils import ( + "bufio" + "bytes" "fmt" "os" + "regexp" ) // Author file utils is a package that contains functions that are used to read @@ -42,3 +45,53 @@ func CheckAuthorFile() string { // This string output is mostly for convenience can mostly be ignored return authorfile } + +func DeleteOneAuthor(author string) { + //author_file := Find_authorfile() + + author_file := "author_file" + + // open author_file + file, err := os.OpenFile(author_file, os.O_RDWR, 0644) + if err != nil { + fmt.Println("Error opening file: ", err) + return + } + + defer file.Close() + + // create regex to capture author line + regexp, err := regexp.Compile(fmt.Sprintf("^(.+\\|%s\\|.+|%s\\|.+\\|.+)$",author,author)) + if err != nil { + fmt.Println("Error compiling regex: ", err) + return + } + + var b []byte + buf := bytes.NewBuffer(b) + + // create a scanner for the file + scanner := bufio.NewScanner(file) + + // write the header to the buffer + scanner.Scan() + buf.WriteString(scanner.Text() + "\n") + + // check if author matches the regex and skip + for scanner.Scan() { + line := scanner.Text() + if regexp.MatchString(line) { + continue + } + buf.WriteString(line + "\n") + + } + // remove the last newline character + buf.Truncate(buf.Len()-1) + + file.Truncate(0) + file.Seek(0,0) + buf.WriteTo(file) + + RemoveUser(author) +} diff --git a/src_code/go_src/cmd/utils/user_util.go b/src_code/go_src/cmd/utils/user_util.go index 55bdaab..1b3477b 100644 --- a/src_code/go_src/cmd/utils/user_util.go +++ b/src_code/go_src/cmd/utils/user_util.go @@ -67,3 +67,7 @@ func Define_users(author_file string) { os.Exit(2) } } + +func RemoveUser(short string) { + delete(Users, short) +} \ No newline at end of file From fa03de4695c21257f185a5b26c19b92fbc956ff0 Mon Sep 17 00:00:00 2001 From: Theis Date: Fri, 11 Oct 2024 11:21:39 +0200 Subject: [PATCH 05/29] feat: add tui show users (WIP) and prefer bat if present --- src_code/go_src/cmd/tui/tui_show_users.go | 106 ++++++++++++++++++++++ src_code/go_src/cmd/users.go | 37 ++++++-- 2 files changed, 133 insertions(+), 10 deletions(-) create mode 100644 src_code/go_src/cmd/tui/tui_show_users.go diff --git a/src_code/go_src/cmd/tui/tui_show_users.go b/src_code/go_src/cmd/tui/tui_show_users.go new file mode 100644 index 0000000..92f4770 --- /dev/null +++ b/src_code/go_src/cmd/tui/tui_show_users.go @@ -0,0 +1,106 @@ +package tui + +import ( + "bufio" + "fmt" + "os" + "strings" + + "github.com/charmbracelet/bubbles/viewport" + tea "github.com/charmbracelet/bubbletea" + "github.com/charmbracelet/glamour" + "github.com/charmbracelet/lipgloss" +) + +//TODO: MAybe change away from glamour if the weird email issue can't be solved + +var content string + +var helpStyle_us = lipgloss.NewStyle().Foreground(lipgloss.Color("241")).Render + +type example struct { + viewport viewport.Model +} + +func newExample() (*example, error) { + const width = 78 + + vp := viewport.New(width, 20) + vp.Style = lipgloss.NewStyle(). + BorderStyle(lipgloss.RoundedBorder()). + BorderForeground(lipgloss.Color("62")). + PaddingRight(2) + + renderer, err := glamour.NewTermRenderer( + glamour.WithPreservedNewLines(), + glamour.WithAutoStyle(), + glamour.WithWordWrap(width), + ) + if err != nil { + return nil, err + } + + str, err := renderer.Render(content) + if err != nil { + return nil, err + } + + vp.SetContent(str) + + return &example{ + viewport: vp, + }, nil +} + +func (e example) Init() tea.Cmd { + return nil +} + +func (e example) Update(msg tea.Msg) (tea.Model, tea.Cmd) { + switch msg := msg.(type) { + case tea.KeyMsg: + switch msg.String() { + case "q", "ctrl+c", "esc": + return e, tea.Quit + default: + var cmd tea.Cmd + e.viewport, cmd = e.viewport.Update(msg) + return e, cmd + } + default: + return e, nil + } +} + +func (e example) View() string { + return e.viewport.View() + e.helpView() +} + +func (e example) helpView() string { + return helpStyle_us("\n ↑/↓: Navigate • q: Quit\n") +} + +func Entry_US(author_file string) { + file, err := os.Open(author_file) + + scanner := bufio.NewScanner(file) + var cnt strings.Builder + + for scanner.Scan() { + cnt.WriteString(scanner.Text() + "\n") + } + + + content = cnt.String() + + model, err := newExample() + if err != nil { + fmt.Println("Could not initialize Bubble Tea model:", err) + os.Exit(1) + } + + if _, err := tea.NewProgram(model).Run(); err != nil { + fmt.Println("Bummer, there's been an error:", err) + os.Exit(1) + } +} \ No newline at end of file diff --git a/src_code/go_src/cmd/users.go b/src_code/go_src/cmd/users.go index 6fef0d3..4277858 100644 --- a/src_code/go_src/cmd/users.go +++ b/src_code/go_src/cmd/users.go @@ -1,8 +1,10 @@ package cmd import ( + "main/src_code/go_src/cmd/tui" "main/src_code/go_src/cmd/utils" "os" + "os/exec" "slices" "sort" "strings" @@ -19,21 +21,36 @@ var usersCmd = &cobra.Command{ Long: `Displays all users from the author file located at: ` + authorfile, Run: func(cmd *cobra.Command, args []string) { //TODO: make this print a bit prettier (sort it and maybe use a table) - println("List of users:\nFormat: / -> Username: Email: ") - seen_users := []utils.User{} - user_sb := []string{} - for name, usr := range utils.Users { - if !slices.Contains(seen_users, usr) { - user_sb = append(user_sb, utils.Users[name].Names+" ->"+" Username: "+usr.Username+" Email: "+usr.Email+"\n") - seen_users = append(seen_users, usr) + // check if the no pretty print flag is set + np, _ := cmd.Flags().GetBool("np") + if np { + println("List of users:\nFormat: / -> Username: Email: ") + seen_users := []utils.User{} + user_sb := []string{} + for name, usr := range utils.Users { + if !slices.Contains(seen_users, usr) { + user_sb = append(user_sb, utils.Users[name].Names+" ->"+" Username: "+usr.Username+" Email: "+usr.Email+"\n") + seen_users = append(seen_users, usr) + } } + sort.Strings(user_sb) + println(strings.Join(user_sb, "")) + os.Exit(1) } - sort.Strings(user_sb) - println(strings.Join(user_sb, "")) - os.Exit(1) + bat_check := exec.Command("which", "bat") + out, _ := bat_check.CombinedOutput() + if string(out) == "" { + tui.Entry_US(authorfile) + os.Exit(0) + } + bat := exec.Command("bat", authorfile) + bat.Stdout = os.Stdout + bat.Stderr = os.Stderr + bat.Run() }, } func init() { rootCmd.AddCommand(usersCmd) + usersCmd.Flags().BoolP("np", "n", false, "No pretty print of the users") } From 5cfa40876b532379ae7d4b7c19c7d2903c80234a Mon Sep 17 00:00:00 2001 From: Theis Date: Fri, 11 Oct 2024 11:21:52 +0200 Subject: [PATCH 06/29] docs: add small readme in tui folder for bubbletea templates --- src_code/go_src/cmd/tui/README.md | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 src_code/go_src/cmd/tui/README.md diff --git a/src_code/go_src/cmd/tui/README.md b/src_code/go_src/cmd/tui/README.md new file mode 100644 index 0000000..ac5e3f0 --- /dev/null +++ b/src_code/go_src/cmd/tui/README.md @@ -0,0 +1,4 @@ +# TUI based on bubbletea +All of the current TUI elements are mostly the same as the base templates from the bubble tea github repo. I am not a designer and the templates look pretty cool anyways so all in all very cool stuff + +[Bubbletea Examples Folder](https://github.com/charmbracelet/bubbletea/tree/main/examples) \ No newline at end of file From 87a6de6b6f7fe77356489857ad5a6cf324af45a2 Mon Sep 17 00:00:00 2001 From: Theis Date: Wed, 16 Oct 2024 20:47:35 +0200 Subject: [PATCH 07/29] test: create tests for the util functions --- go.mod | 13 ++- src_code/go_src/author_file | 3 + src_code/go_src/cmd/root.go | 11 ++- .../go_src/cmd/utils/author_file_utils.go | 4 +- src_code/go_src/cmd/utils/commit.go | 2 +- src_code/go_src/cmd/utils/user_util.go | 9 ++ src_code/go_src/cmd/utils/util_test.go | 98 +++++++++++++++++++ 7 files changed, 130 insertions(+), 10 deletions(-) create mode 100644 src_code/go_src/author_file create mode 100644 src_code/go_src/cmd/utils/util_test.go diff --git a/go.mod b/go.mod index d5fea6d..f370060 100644 --- a/go.mod +++ b/go.mod @@ -6,6 +6,7 @@ require ( dagger.io/dagger v0.10.0 github.com/charmbracelet/bubbles v0.20.0 github.com/charmbracelet/bubbletea v1.1.1 + github.com/charmbracelet/glamour v0.8.0 github.com/charmbracelet/lipgloss v0.13.0 github.com/spf13/cobra v1.8.1 ) @@ -14,26 +15,36 @@ require ( github.com/99designs/gqlgen v0.17.31 // indirect github.com/Khan/genqlient v0.6.0 // indirect github.com/adrg/xdg v0.4.0 // indirect + github.com/alecthomas/chroma/v2 v2.14.0 // indirect github.com/atotto/clipboard v0.1.4 // indirect github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect + github.com/aymerick/douceur v0.2.0 // indirect github.com/charmbracelet/x/ansi v0.2.3 // indirect github.com/charmbracelet/x/term v0.2.0 // indirect + github.com/dlclark/regexp2 v1.11.0 // indirect github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f // indirect + github.com/gorilla/css v1.0.1 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/lucasb-eyer/go-colorful v1.2.0 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/mattn/go-localereader v0.0.1 // indirect github.com/mattn/go-runewidth v0.0.16 // indirect + github.com/microcosm-cc/bluemonday v1.0.27 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 // indirect github.com/muesli/cancelreader v0.2.2 // indirect - github.com/muesli/termenv v0.15.2 // indirect + github.com/muesli/reflow v0.3.0 // indirect + github.com/muesli/termenv v0.15.3-0.20240618155329-98d742f6907a // indirect github.com/rivo/uniseg v0.4.7 // indirect github.com/sahilm/fuzzy v0.1.1 // indirect github.com/spf13/pflag v1.0.5 // indirect github.com/vektah/gqlparser/v2 v2.5.6 // indirect + github.com/yuin/goldmark v1.7.4 // indirect + github.com/yuin/goldmark-emoji v1.0.3 // indirect golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa // indirect + golang.org/x/net v0.27.0 // indirect golang.org/x/sync v0.8.0 // indirect golang.org/x/sys v0.26.0 // indirect + golang.org/x/term v0.22.0 // indirect golang.org/x/text v0.19.0 // indirect ) diff --git a/src_code/go_src/author_file b/src_code/go_src/author_file new file mode 100644 index 0000000..956201c --- /dev/null +++ b/src_code/go_src/author_file @@ -0,0 +1,3 @@ +syntax for the test file +au|August|August-Brandt|augustbrandt170@gmail.com +al|Alex|Alex-itu|lolk@itu.dk \ No newline at end of file diff --git a/src_code/go_src/cmd/root.go b/src_code/go_src/cmd/root.go index 4e8c167..4846f27 100644 --- a/src_code/go_src/cmd/root.go +++ b/src_code/go_src/cmd/root.go @@ -31,11 +31,12 @@ var rootCmd = &cobra.Command{ switch len(args) { case 0: // launch the tui - sel_auth := tui.Entry() - for _, a := range sel_auth { - fmt.Println(a) - } - os.Exit(0) + args = append(args, tui.Entry_CM()) + fmt.Println(args[0]) + //sel_auth := tui.Entry() + // for _, a := range sel_auth { + // fmt.Println(a) + // } case 1: if len(args) == 1 { utils.GitWrapper(args[0]) diff --git a/src_code/go_src/cmd/utils/author_file_utils.go b/src_code/go_src/cmd/utils/author_file_utils.go index c672300..1c3a2fe 100644 --- a/src_code/go_src/cmd/utils/author_file_utils.go +++ b/src_code/go_src/cmd/utils/author_file_utils.go @@ -47,9 +47,7 @@ func CheckAuthorFile() string { } func DeleteOneAuthor(author string) { - //author_file := Find_authorfile() - - author_file := "author_file" + author_file := Find_authorfile() // open author_file file, err := os.OpenFile(author_file, os.O_RDWR, 0644) diff --git a/src_code/go_src/cmd/utils/commit.go b/src_code/go_src/cmd/utils/commit.go index e8271b3..008497f 100644 --- a/src_code/go_src/cmd/utils/commit.go +++ b/src_code/go_src/cmd/utils/commit.go @@ -98,7 +98,7 @@ func add_x_users(excludeMode []string) { } } -// helper function to select a group of users to exclude in the commit message +// helper function to select groups of users to exclude in the commit message func group_selection(group []User, excludeMode []string) []string { for _, user := range Users { if !(slices.Contains(group, user)) { diff --git a/src_code/go_src/cmd/utils/user_util.go b/src_code/go_src/cmd/utils/user_util.go index 1b3477b..651fe0b 100644 --- a/src_code/go_src/cmd/utils/user_util.go +++ b/src_code/go_src/cmd/utils/user_util.go @@ -40,6 +40,15 @@ func Define_users(author_file string) { group_info = append(group_info, strings.Split(input[1], "|")...) } info := strings.Split(input_str, "|") + if len(info) < 4 { + if len(info) > 0 { + println("Error: User ", info[0], " is missing information") + } else { + println("Error: Some user is missing information") + } + println("Please check the author file for proper syntax") + os.Exit(1) + } usr := User{Username: info[2], Email: info[3], Names: info[0] + "/" + info[1]} Users[info[0]] = usr Users[info[1]] = usr diff --git a/src_code/go_src/cmd/utils/util_test.go b/src_code/go_src/cmd/utils/util_test.go new file mode 100644 index 0000000..f532c28 --- /dev/null +++ b/src_code/go_src/cmd/utils/util_test.go @@ -0,0 +1,98 @@ +package utils_test + +import ( + "main/src_code/go_src/cmd/utils" + "os" + "testing" +) + +const author_data = `syntax for the test file +te|testing|TestUser|test@test.test|ex +ti|testtest|UserName2|testing@user.io;;gr1` + +var envVar = os.Getenv("author_file") + +func setup() { + // setup test data + os.WriteFile("author_file_test", []byte(author_data), 0644) + os.Setenv("author_file", "author_file_test") +} + +func teardown() { + // remove test data + os.Remove("author_file_test") + os.Setenv("author_file", envVar) +} + +// Author tests BEGIN +func Test_FindAuthorFile(t* testing.T) { + setup() + defer teardown() + // Test Find_authorfile + authorfile := utils.Find_authorfile() + if authorfile != "author_file_test" { + t.Errorf("Find_authorfile() = %v; want authors_file_test", authorfile) + } +} + +func Test_DeleteAuthor(t *testing.T) { + setup() + defer teardown() + // Test DeleteOneAuthor + og_bytes, err := os.ReadFile("author_file_test") + if err != nil { + t.Errorf("Error reading file: %v", err) + } + + utils.DeleteOneAuthor("te") + deleted_bytes, err := os.ReadFile("author_file_test") + if err != nil { + t.Errorf("Error reading file: %v", err) + } + + if string(og_bytes) == string(deleted_bytes) { + t.Errorf("DeleteOneAuthor() did not delete author") + } +} +// Author tests END + +// User tests BEGIN +func Test_DefineUsers(t *testing.T) { + setup() + defer teardown() + // Test Define_users + utils.Define_users("author_file_test") + if len(utils.Users) != 4 { + t.Errorf("Define_users() = %v; want 4", len(utils.Users)) + } +} + +func Test_RemoveUser(t *testing.T) { + setup() + defer teardown() + // Test RemoveUser + utils.Define_users("author_file_test") + + utils.RemoveUser("te") + + if len(utils.Users) != 3 { + t.Errorf("RemoveUser() = %v; want 3", len(utils.Users)) + } +} +// User tests END + +// Commit tests BEGIN + +func Test_Commit(t* testing.T) { + setup() + defer teardown() + utils.Define_users("author_file_test") + // Test Commit + authors := []string{"te"} + message := "Test commit message" + commit := utils.Commit(message, authors) + if commit != "Test commit message\n\nCo-authored-by: TestUser " { + t.Errorf("Commit() = %v; want Test commit message\n", commit) + } +} +// Commit tests END \ No newline at end of file From 7f5a3bcca67ba86880ee923d6a570676c35f33fc Mon Sep 17 00:00:00 2001 From: Slug-Boi Date: Sun, 20 Oct 2024 22:52:37 +0200 Subject: [PATCH 08/29] feat: added commit message window to tui --- src_code/go_src/cmd/root.go | 18 +-- src_code/go_src/cmd/tui/tui_commit_message.go | 109 ++++++++++++++++++ 2 files changed, 119 insertions(+), 8 deletions(-) create mode 100644 src_code/go_src/cmd/tui/tui_commit_message.go diff --git a/src_code/go_src/cmd/root.go b/src_code/go_src/cmd/root.go index 4846f27..206bdc1 100644 --- a/src_code/go_src/cmd/root.go +++ b/src_code/go_src/cmd/root.go @@ -23,20 +23,20 @@ var rootCmd = &cobra.Command{ //TODO: add bubble tea interface to this Args: cobra.MinimumNArgs(0), Run: func(cmd *cobra.Command, args []string) { + var message string + // check if the print flag is set pflag, _ := cmd.Flags().GetBool("print") // run execute commands again as root run will not call this part // redundant check for now but will be useful later when we add tui - wrap_around: + wrap_around: switch len(args) { case 0: // launch the tui args = append(args, tui.Entry_CM()) - fmt.Println(args[0]) - //sel_auth := tui.Entry() - // for _, a := range sel_auth { - // fmt.Println(a) - // } + sel_auth := tui.Entry() + message = utils.Commit(args[0], sel_auth) + goto tui case 1: if len(args) == 1 { utils.GitWrapper(args[0]) @@ -46,7 +46,7 @@ var rootCmd = &cobra.Command{ os.Exit(0) } } - + // check if user included -m tag and remove. Wrap around for safety's sake if args[0] == "-m" { args = args[1:] @@ -54,7 +54,9 @@ var rootCmd = &cobra.Command{ } // builds the commit message with the selected authors - message := utils.Commit(args[0], args[1:]) + message = utils.Commit(args[0], args[1:]) + + tui: // prints the commit message to the console if the print flag is set if pflag { fmt.Println(message) diff --git a/src_code/go_src/cmd/tui/tui_commit_message.go b/src_code/go_src/cmd/tui/tui_commit_message.go new file mode 100644 index 0000000..f94c136 --- /dev/null +++ b/src_code/go_src/cmd/tui/tui_commit_message.go @@ -0,0 +1,109 @@ +package tui + +// A simple program demonstrating the textarea component from the Bubbles +// component library. + +//TODO: maybe add a submit button below the textarea + +import ( + "fmt" + "log" + "os" + + "github.com/charmbracelet/bubbles/key" + "github.com/charmbracelet/bubbles/textarea" + tea "github.com/charmbracelet/bubbletea" +) + +type KeyMap struct { + EndWithMes key.Binding +} + +func newKeyMap() *KeyMap { + return &KeyMap{ + EndWithMes: key.NewBinding( + key.WithKeys("alt+enter"), + ), + } +} + +func Entry_CM() string { + + newKeyMap() + + p := tea.NewProgram(initialModel_cm()) + m, err := p.Run() + if err != nil { + log.Fatal(err) + } + if m.(model_cm).textarea.Value() == "" { + fmt.Println("No commit message provided. Exiting...") + os.Exit(1) + } + return m.(model_cm).textarea.Value() + "\n" +} + +type errMsg error + +type model_cm struct { + textarea textarea.Model + keys *KeyMap + err error +} + +func initialModel_cm() model_cm { + ti := textarea.New() + ti.Placeholder = "Write your commit message here..." + ti.Focus() + + return model_cm{ + textarea: ti, + keys: newKeyMap(), + err: nil, + } +} + +func (m model_cm) Init() tea.Cmd { + return textarea.Blink +} + +func (m model_cm) Update(msg tea.Msg) (tea.Model, tea.Cmd) { + var cmds []tea.Cmd + var cmd tea.Cmd + + switch msg := msg.(type) { + case tea.KeyMsg: + switch { + case key.Matches(msg, m.keys.EndWithMes): + return m, tea.Quit + } + switch msg.Type { + case tea.KeyCtrlC: + m.textarea.SetValue("") + return m, tea.Quit + default: + if !m.textarea.Focused() { + cmd = m.textarea.Focus() + cmds = append(cmds, cmd) + } + } + + // We handle errors just like any other message + case errMsg: + m.err = msg + return m, nil + } + + m.textarea, cmd = m.textarea.Update(msg) + cmds = append(cmds, cmd) + return m, tea.Batch(cmds...) +} + +func (m model_cm) View() string { + return fmt.Sprintf( + "Tell me a story.\n\n%s\n\n%s", + m.textarea.View(), + "alt+enter|Submit\nctrl+c|Cancel", + ) + "\n\n" +} + From 580f56555f332055501632d537715fd8c9bd4cbc Mon Sep 17 00:00:00 2001 From: Slug-Boi Date: Sun, 20 Oct 2024 23:16:13 +0200 Subject: [PATCH 09/29] fix: fixed output of users command to be readable --- src_code/go_src/author_file | 3 --- src_code/go_src/cmd/tui/tui_show_users.go | 16 ++++++++++------ 2 files changed, 10 insertions(+), 9 deletions(-) delete mode 100644 src_code/go_src/author_file diff --git a/src_code/go_src/author_file b/src_code/go_src/author_file deleted file mode 100644 index 956201c..0000000 --- a/src_code/go_src/author_file +++ /dev/null @@ -1,3 +0,0 @@ -syntax for the test file -au|August|August-Brandt|augustbrandt170@gmail.com -al|Alex|Alex-itu|lolk@itu.dk \ No newline at end of file diff --git a/src_code/go_src/cmd/tui/tui_show_users.go b/src_code/go_src/cmd/tui/tui_show_users.go index 92f4770..cbf34dd 100644 --- a/src_code/go_src/cmd/tui/tui_show_users.go +++ b/src_code/go_src/cmd/tui/tui_show_users.go @@ -14,7 +14,7 @@ import ( //TODO: MAybe change away from glamour if the weird email issue can't be solved -var content string +var content string var helpStyle_us = lipgloss.NewStyle().Foreground(lipgloss.Color("241")).Render @@ -85,11 +85,15 @@ func Entry_US(author_file string) { scanner := bufio.NewScanner(file) var cnt strings.Builder - - for scanner.Scan() { - cnt.WriteString(scanner.Text() + "\n") - } + scanner.Scan() + header := scanner.Text() + cnt.WriteString(header + "\n") + + for scanner.Scan() { + //very hacky it basically just ensure glamour doesn't format the email + cnt.WriteString(":\b" + scanner.Text() + "\n") + } content = cnt.String() @@ -103,4 +107,4 @@ func Entry_US(author_file string) { fmt.Println("Bummer, there's been an error:", err) os.Exit(1) } -} \ No newline at end of file +} From b0baa0cf70c4d14a0565cca4cc1133a8e176287e Mon Sep 17 00:00:00 2001 From: Slug-Boi Date: Mon, 21 Oct 2024 13:11:20 +0200 Subject: [PATCH 10/29] refactor: changed color of commit message field to match rest of TUI --- src_code/go_src/cmd/tui/tui_commit_message.go | 20 ++++++++++++------- src_code/go_src/cmd/tui/tui_show_users.go | 8 +++++++- 2 files changed, 20 insertions(+), 8 deletions(-) diff --git a/src_code/go_src/cmd/tui/tui_commit_message.go b/src_code/go_src/cmd/tui/tui_commit_message.go index f94c136..0a08cd5 100644 --- a/src_code/go_src/cmd/tui/tui_commit_message.go +++ b/src_code/go_src/cmd/tui/tui_commit_message.go @@ -13,6 +13,11 @@ import ( "github.com/charmbracelet/bubbles/key" "github.com/charmbracelet/bubbles/textarea" tea "github.com/charmbracelet/bubbletea" + "github.com/charmbracelet/lipgloss" +) + +var ( + barStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("170")) ) type KeyMap struct { @@ -47,18 +52,20 @@ type errMsg error type model_cm struct { textarea textarea.Model - keys *KeyMap + keys *KeyMap err error } func initialModel_cm() model_cm { ti := textarea.New() + ti.FocusedStyle = textarea.Style{Base: lipgloss.NewStyle().Foreground(lipgloss.Color("170"))} + ti.Placeholder = "Write your commit message here..." ti.Focus() return model_cm{ textarea: ti, - keys: newKeyMap(), + keys: newKeyMap(), err: nil, } } @@ -74,8 +81,8 @@ func (m model_cm) Update(msg tea.Msg) (tea.Model, tea.Cmd) { switch msg := msg.(type) { case tea.KeyMsg: switch { - case key.Matches(msg, m.keys.EndWithMes): - return m, tea.Quit + case key.Matches(msg, m.keys.EndWithMes): + return m, tea.Quit } switch msg.Type { case tea.KeyCtrlC: @@ -101,9 +108,8 @@ func (m model_cm) Update(msg tea.Msg) (tea.Model, tea.Cmd) { func (m model_cm) View() string { return fmt.Sprintf( - "Tell me a story.\n\n%s\n\n%s", + "Commit message:\n\n%s\n\n%s", m.textarea.View(), - "alt+enter|Submit\nctrl+c|Cancel", + "(alt+enter | Submit)\n(ctrl+c | Cancel)", ) + "\n\n" } - diff --git a/src_code/go_src/cmd/tui/tui_show_users.go b/src_code/go_src/cmd/tui/tui_show_users.go index cbf34dd..5e12309 100644 --- a/src_code/go_src/cmd/tui/tui_show_users.go +++ b/src_code/go_src/cmd/tui/tui_show_users.go @@ -16,7 +16,9 @@ import ( var content string -var helpStyle_us = lipgloss.NewStyle().Foreground(lipgloss.Color("241")).Render +var ( + helpStyle_us = lipgloss.NewStyle().Foreground(lipgloss.Color("241")).Render +) type example struct { viewport viewport.Model @@ -82,6 +84,10 @@ func (e example) helpView() string { func Entry_US(author_file string) { file, err := os.Open(author_file) + if err != nil { + fmt.Println("Could not open file:", err) + os.Exit(1) + } scanner := bufio.NewScanner(file) var cnt strings.Builder From c6fe91d24c631f842aaf6e37dd610db9c24531e1 Mon Sep 17 00:00:00 2001 From: Slug-Boi Date: Mon, 21 Oct 2024 13:12:12 +0200 Subject: [PATCH 11/29] other: removed unsued line --- src_code/go_src/cmd/tui/tui_commit_message.go | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src_code/go_src/cmd/tui/tui_commit_message.go b/src_code/go_src/cmd/tui/tui_commit_message.go index 0a08cd5..7b15555 100644 --- a/src_code/go_src/cmd/tui/tui_commit_message.go +++ b/src_code/go_src/cmd/tui/tui_commit_message.go @@ -16,10 +16,6 @@ import ( "github.com/charmbracelet/lipgloss" ) -var ( - barStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("170")) -) - type KeyMap struct { EndWithMes key.Binding } From 7521fd5f265bbb9829c8daf60a34a04f096c638a Mon Sep 17 00:00:00 2001 From: Slug-Boi Date: Thu, 24 Oct 2024 20:45:28 +0200 Subject: [PATCH 12/29] refactor: change name of author and combine with temp add command --- .../{tui_create_author.go => tui_author.go} | 168 +++++++++++++----- 1 file changed, 121 insertions(+), 47 deletions(-) rename src_code/go_src/cmd/tui/{tui_create_author.go => tui_author.go} (54%) diff --git a/src_code/go_src/cmd/tui/tui_create_author.go b/src_code/go_src/cmd/tui/tui_author.go similarity index 54% rename from src_code/go_src/cmd/tui/tui_create_author.go rename to src_code/go_src/cmd/tui/tui_author.go index 0643d4d..1307c42 100644 --- a/src_code/go_src/cmd/tui/tui_create_author.go +++ b/src_code/go_src/cmd/tui/tui_author.go @@ -9,10 +9,10 @@ import ( "os" "strings" - //"github.com/charmbracelet/bubbles/cursor" "github.com/charmbracelet/bubbles/textinput" tea "github.com/charmbracelet/bubbletea" "github.com/charmbracelet/lipgloss" + //"github.com/inancgumus/screen" ) var ( @@ -21,20 +21,22 @@ var ( cursorStyle = focusedStyle noStyle = lipgloss.NewStyle() cursorModeHelpStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("244")) - focusedButton = focusedStyle.Render("[ Submit ]") - focusedExclude = focusedStyle.Render("[ Exclude ]") - blurredButton = fmt.Sprintf("[ %s ]", blurredStyle.Render("Submit")) - excludeButton = fmt.Sprintf("[ %s ]", blurredStyle.Render("Exclude")) + focusedButton = focusedStyle.Render("[ Submit ]") + focusedExclude = focusedStyle.Render("[ Exclude ]") + blurredButton = fmt.Sprintf("[ %s ]", blurredStyle.Render("Submit")) + excludeButton = fmt.Sprintf("[ %s ]", blurredStyle.Render("Exclude")) ) +var removeButton bool + type model_ca struct { focusIndex int inputs []textinput.Model - quitting bool - exclude bool + quitting bool + exclude bool } -func initialModel() model_ca { +func createAuthorModel() model_ca { m := model_ca{ inputs: make([]textinput.Model, 5), } @@ -43,17 +45,17 @@ func initialModel() model_ca { for i := range m.inputs { t = textinput.New() t.Cursor.Style = cursorStyle - t.CharLimit = 32 + //t.CharLimit = 32 switch i { case 0: - t.Placeholder = "shortname (e.g. jo)" + t.Placeholder = "Shortname (e.g. jo)" t.Focus() t.PromptStyle = focusedStyle t.TextStyle = focusedStyle case 1: t.Placeholder = "Long name (e.g. JohnDoe)" - case 2: + case 2: t.Placeholder = "Username (e.g. JohnDoe-gh)" case 3: t.Placeholder = "Email (e.g. JohnDoe@domain.do" @@ -67,6 +69,44 @@ func initialModel() model_ca { return m } +func tempAuthorModel() model_ca { + m := model_ca{ + inputs: make([]textinput.Model, 2), + } + + var t textinput.Model + for i := range m.inputs { + t = textinput.New() + t.Cursor.Style = cursorStyle + //t.CharLimit = 32 + + switch i { + case 0: + t.Placeholder = "Username (e.g. JohnDoe-gh)" + t.Focus() + t.PromptStyle = focusedStyle + t.TextStyle = focusedStyle + case 1: + t.Placeholder = "Email (e.g. JohnDoe@JohnDoe.io)" + } + + m.inputs[i] = t + } + + removeButton = true + + return m +} + +func initialModel(model string) model_ca { + if model == "author" { + return createAuthorModel() + } else { + return tempAuthorModel() + } + +} + func (m model_ca) Init() tea.Cmd { return textinput.Blink } @@ -85,13 +125,20 @@ func (m model_ca) Update(msg tea.Msg) (tea.Model, tea.Cmd) { // Did the user press enter while the submit button was focused? // If so, exit. - if s == "enter" && m.focusIndex == len(m.inputs)+1 { - m.quitting = true - return m, tea.Quit - } else if s == "enter" && m.focusIndex == len(m.inputs) { - // toggle exclude - m.exclude = !m.exclude - return m, nil + if !removeButton { + if s == "enter" && m.focusIndex == len(m.inputs)+1 { + m.quitting = true + return m, tea.Quit + } else if s == "enter" && m.focusIndex == len(m.inputs) { + // toggle exclude + m.exclude = !m.exclude + return m, nil + } + } else { + if s == "enter" && m.focusIndex == len(m.inputs) { + m.quitting = true + return m, tea.Quit + } } // Cycle indexes @@ -158,21 +205,31 @@ func (m model_ca) View() string { } } - button := &blurredButton - if m.focusIndex == len(m.inputs)+1 { - button = &focusedButton - } - exclude := &excludeButton - if m.focusIndex == len(m.inputs) { - exclude = &focusedExclude + //TODO: add check here for wether this button is needed + var exclude *string + var button *string + if !removeButton { + exclude = &excludeButton + if m.focusIndex == len(m.inputs) { + exclude = &focusedExclude + } + button = &blurredButton + if m.focusIndex == len(m.inputs)+1 { + button = &focusedButton + } + + if m.exclude { + fmt.Fprintf(&b, "\n\n%s: [X]\n\n", *exclude) + } else { + fmt.Fprintf(&b, "\n\n%s: [ ]\n\n", *exclude) + } + } else { + button = &blurredButton + if m.focusIndex == len(m.inputs) { + button = &focusedButton + } } - if m.exclude { - fmt.Fprintf(&b, "\n\n%s: [X]\n\n", *exclude) - } else { - fmt.Fprintf(&b, "\n\n%s: [ ]\n\n", *exclude) - } - fmt.Fprintf(&b, "\n\n%s\n\n", *button) b.WriteString(cursorModeHelpStyle.Render()) @@ -180,21 +237,20 @@ func (m model_ca) View() string { return b.String() } -func Entry_CA() string{ - m, err := tea.NewProgram(initialModel()).Run() +func Entry_CA() string { + m, err := tea.NewProgram(initialModel("author")).Run() if err != nil { fmt.Printf("could not start program: %s\n", err) os.Exit(1) } - - - if len(m.(model_ca).inputs) > 0 && - m.(model_ca).inputs[0].Value() != "" && - m.(model_ca).inputs[1].Value() != "" && - m.(model_ca).inputs[2].Value() != "" && - m.(model_ca).inputs[3].Value() != "" { - f, err := os.OpenFile("author_file", os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0600) + if len(m.(model_ca).inputs) > 0 && + m.(model_ca).inputs[0].Value() != "" && + m.(model_ca).inputs[1].Value() != "" && + m.(model_ca).inputs[2].Value() != "" && + m.(model_ca).inputs[3].Value() != "" { + author_file := utils.Find_authorfile() + f, err := os.OpenFile(author_file, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0600) if err != nil { panic(err) } @@ -204,11 +260,11 @@ func Entry_CA() string{ sb := strings.Builder{} sb.WriteRune('\n') - sb.WriteString(fmt.Sprintf("%s|%s|%s|%s", - m.(model_ca).inputs[0].Value(), - m.(model_ca).inputs[1].Value(), - m.(model_ca).inputs[2].Value(), - m.(model_ca).inputs[3].Value())) + sb.WriteString(fmt.Sprintf("%s|%s|%s|%s", + m.(model_ca).inputs[0].Value(), + m.(model_ca).inputs[1].Value(), + m.(model_ca).inputs[2].Value(), + m.(model_ca).inputs[3].Value())) if m.(model_ca).exclude { sb.WriteString(fmt.Sprintf("|%s", "ex")) @@ -227,4 +283,22 @@ func Entry_CA() string{ return m.(model_ca).inputs[0].Value() } return "" -} \ No newline at end of file +} + +func Entry_TA(ch chan bool) string { + m, err := tea.NewProgram(initialModel("temp")).Run() + if err != nil { + fmt.Printf("could not start program: %s\n", err) + os.Exit(1) + } + + if len(m.(model_ca).inputs) > 0 && + m.(model_ca).inputs[0].Value() != "" && + m.(model_ca).inputs[1].Value() != "" { + utils.TempAddUser(m.(model_ca).inputs[0].Value(), m.(model_ca).inputs[1].Value()) + return m.(model_ca).inputs[0].Value() + ":" + m.(model_ca).inputs[1].Value() + } + + return "" + +} From d3820826d1f4dc4ca3aff10d1079c74f899228af Mon Sep 17 00:00:00 2001 From: Slug-Boi Date: Thu, 24 Oct 2024 20:45:52 +0200 Subject: [PATCH 13/29] other: change commit key to enter (alt enter stopped working) --- src_code/go_src/cmd/tui/tui_commit_message.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src_code/go_src/cmd/tui/tui_commit_message.go b/src_code/go_src/cmd/tui/tui_commit_message.go index 7b15555..3fa5bef 100644 --- a/src_code/go_src/cmd/tui/tui_commit_message.go +++ b/src_code/go_src/cmd/tui/tui_commit_message.go @@ -23,7 +23,7 @@ type KeyMap struct { func newKeyMap() *KeyMap { return &KeyMap{ EndWithMes: key.NewBinding( - key.WithKeys("alt+enter"), + key.WithKeys("enter"), ), } } From b0a51251132fcef4a850423552f62c117fa1ca2f Mon Sep 17 00:00:00 2001 From: Slug-Boi Date: Thu, 24 Oct 2024 20:47:32 +0200 Subject: [PATCH 14/29] feat: add temp add command --- src_code/go_src/cmd/tui/tui_list.go | 141 ++++++++++++++++------------ 1 file changed, 79 insertions(+), 62 deletions(-) diff --git a/src_code/go_src/cmd/tui/tui_list.go b/src_code/go_src/cmd/tui/tui_list.go index e343258..7486381 100644 --- a/src_code/go_src/cmd/tui/tui_list.go +++ b/src_code/go_src/cmd/tui/tui_list.go @@ -12,18 +12,19 @@ import ( "github.com/charmbracelet/bubbles/list" tea "github.com/charmbracelet/bubbletea" "github.com/charmbracelet/lipgloss" + "github.com/inancgumus/screen" ) const listHeight = 14 var ( - titleStyle = lipgloss.NewStyle().MarginLeft(2) - itemStyle = lipgloss.NewStyle().PaddingLeft(4) - selectedItemStyle = lipgloss.NewStyle().PaddingLeft(2).Foreground(lipgloss.Color("170")) - highlightStyle = lipgloss.NewStyle().PaddingLeft(4).Background(lipgloss.Color("236")).Foreground(lipgloss.Color("17")) + titleStyle = lipgloss.NewStyle().MarginLeft(2) + itemStyle = lipgloss.NewStyle().PaddingLeft(4) + selectedItemStyle = lipgloss.NewStyle().PaddingLeft(2).Foreground(lipgloss.Color("170")) + highlightStyle = lipgloss.NewStyle().PaddingLeft(4).Background(lipgloss.Color("236")).Foreground(lipgloss.Color("17")) selectedHighlightStyle = lipgloss.NewStyle().PaddingLeft(2).Background(lipgloss.Color("236")).Foreground(lipgloss.Color("170")) - paginationStyle = list.DefaultStyles().PaginationStyle.PaddingLeft(4) - helpStyle = list.DefaultStyles().HelpStyle.PaddingLeft(4).PaddingBottom(1) + paginationStyle = list.DefaultStyles().PaginationStyle.PaddingLeft(4) + helpStyle = list.DefaultStyles().HelpStyle.PaddingLeft(4).PaddingBottom(1) //quitTextStyle = lipgloss.NewStyle().Margin(1, 0, 2, 4) ) @@ -32,16 +33,18 @@ type item string var selected = map[string]item{} var negation = false +var ignore = false var dupProtect = map[string]string{} type listKeyMap struct { selectAll key.Binding - negation key.Binding + negation key.Binding groupSelect key.Binding selectOne key.Binding createAuthor key.Binding deleteAuthor key.Binding + tempAdd key.Binding } func newListKeyMap() *listKeyMap { @@ -70,11 +73,14 @@ func newListKeyMap() *listKeyMap { key.WithKeys("D"), key.WithHelp("D", "Delete author"), ), + tempAdd: key.NewBinding( + key.WithKeys("T"), + key.WithHelp("T", "Add temporary author"), + ), } } - -//TODO: Try and add filtering later down the line +// TODO: Try and add filtering later down the line func (i item) FilterValue() string { return string(i) } type itemDelegate struct{} @@ -88,7 +94,6 @@ func (d itemDelegate) Render(w io.Writer, m list.Model, index int, listItem list return } - str := fmt.Sprintf("%d. %s", index+1, i) //TODO: add negation style where all items are flipped in selection @@ -98,7 +103,7 @@ func (d itemDelegate) Render(w io.Writer, m list.Model, index int, listItem list fn = func(s ...string) string { base := strings.Join(s, " ") if negation { - base = base + " ^" + base = base + " ^" } if index == m.Index() { return selectedHighlightStyle.Render("> " + base + " [X]") @@ -113,14 +118,13 @@ func (d itemDelegate) Render(w io.Writer, m list.Model, index int, listItem list } } } - fmt.Fprint(w, fn(str)) } type model struct { list list.Model - keys *listKeyMap + keys *listKeyMap quitting bool } @@ -134,7 +138,7 @@ func selectToggle(i item) { toggleNegation() } else { selected[string(i)] = i - } + } } func toggleNegation() { @@ -144,7 +148,6 @@ func toggleNegation() { } func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { - switch msg := msg.(type) { case tea.WindowSizeMsg: m.list.SetWidth(msg.Width) @@ -157,44 +160,56 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { } // Handle keys from keyList (help menu) switch { - case key.Matches(msg, m.keys.negation): - i, ok := m.list.SelectedItem().(item) - if ok { - negation = true - selectToggle(i) - } + case key.Matches(msg, m.keys.negation): + i, ok := m.list.SelectedItem().(item) + if ok { + negation = true + selectToggle(i) + } - case key.Matches(msg, m.keys.selectOne): - i, ok := m.list.SelectedItem().(item) + case key.Matches(msg, m.keys.selectOne): + i, ok := m.list.SelectedItem().(item) if ok { selectToggle(i) } - case key.Matches(msg, m.keys.selectAll): - //TODO: maybe look at behavior of this when auth are already selected - negation = false - for _, i := range m.list.Items() { - selectToggle(i.(item)) - } + case key.Matches(msg, m.keys.selectAll): + //TODO: maybe look at behavior of this when auth are already selected + negation = false + for _, i := range m.list.Items() { + selectToggle(i.(item)) + } - case key.Matches(msg, m.keys.groupSelect): - // group code goes here - - case key.Matches(msg, m.keys.createAuthor): - author := Entry_CA() - if author != "" { - item_str := utils.Users[author].Username + " - " + utils.Users[author].Email - dupProtect[item_str] = author - m.list.InsertItem(len(m.list.Items())+1,item(item_str)) - } - return m, tea.ClearScreen - case key.Matches(msg, m.keys.deleteAuthor): - author_str := string(m.list.SelectedItem().(item)) - author := dupProtect[author_str] - utils.DeleteOneAuthor(author) - delete(dupProtect, author_str) - m.list.RemoveItem(m.list.Index()) - return m, tea.ClearScreen + case key.Matches(msg, m.keys.groupSelect): + // group code goes here + + case key.Matches(msg, m.keys.tempAdd): + screen.Clear() + screen.MoveTopLeft() + tempAuthr := Entry_TA() + if tempAuthr != "" { + split := strings.Split(tempAuthr, ":") + item_str := split[0] + " - " + split[1] + dupProtect[item_str] = tempAuthr + m.list.InsertItem(len(m.list.Items())+1, item(item_str)) + } + return m, tea.ClearScreen + + case key.Matches(msg, m.keys.createAuthor): + author := Entry_CA() + if author != "" { + item_str := utils.Users[author].Username + " - " + utils.Users[author].Email + dupProtect[item_str] = author + m.list.InsertItem(len(m.list.Items())+1, item(item_str)) + } + return m, tea.ClearScreen + case key.Matches(msg, m.keys.deleteAuthor): + author_str := string(m.list.SelectedItem().(item)) + author := dupProtect[author_str] + utils.DeleteOneAuthor(author) + delete(dupProtect, author_str) + m.list.RemoveItem(m.list.Index()) + return m, tea.ClearScreen } // extra key options switch keypress := msg.String(); keypress { @@ -222,7 +237,7 @@ func (m model) View() string { return "\n" + m.list.View() } -//TODO: pass list in as a param to allow for group selection using same template +// TODO: pass list in as a param to allow for group selection using same template func Entry() []string { items := []list.Item{} @@ -252,20 +267,20 @@ func Entry() []string { l.Styles.Title = titleStyle l.Styles.PaginationStyle = paginationStyle l.AdditionalShortHelpKeys = // Add help keys (main page) - func() []key.Binding { - return []key.Binding{ - listKeys.selectOne, + func() []key.Binding { + return []key.Binding{ + listKeys.selectOne, + } } - } l.AdditionalFullHelpKeys = // Add help keys (help menu) - func() []key.Binding { - return []key.Binding{ - listKeys.selectAll, - listKeys.negation, - listKeys.groupSelect, - listKeys.createAuthor, + func() []key.Binding { + return []key.Binding{ + listKeys.selectAll, + listKeys.negation, + listKeys.groupSelect, + listKeys.createAuthor, + } } - } l.Styles.HelpStyle = helpStyle m := model{list: l, keys: listKeys} @@ -279,13 +294,15 @@ func Entry() []string { // Assert the final tea.Model to our local model and print the choice. output := []string{} - + if len(selected) == 0 { + os.Exit(0) + } for i := range selected { short := dupProtect[i] if negation { short = "^" + short } - + output = append(output, short) } @@ -293,4 +310,4 @@ func Entry() []string { return output } return nil -} \ No newline at end of file +} From fbfde5999ffa82e6b4dfc146fe744038f3d41c92 Mon Sep 17 00:00:00 2001 From: Slug-Boi Date: Thu, 24 Oct 2024 20:47:53 +0200 Subject: [PATCH 15/29] refactor: change model structure of show users for testing --- src_code/go_src/cmd/tui/tui_show_users.go | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/src_code/go_src/cmd/tui/tui_show_users.go b/src_code/go_src/cmd/tui/tui_show_users.go index 5e12309..3a7b26b 100644 --- a/src_code/go_src/cmd/tui/tui_show_users.go +++ b/src_code/go_src/cmd/tui/tui_show_users.go @@ -82,7 +82,18 @@ func (e example) helpView() string { return helpStyle_us("\n ↑/↓: Navigate • q: Quit\n") } -func Entry_US(author_file string) { +func intialModel_US(author_file string) tea.Model { + loadData(author_file) + + model, err := newExample() + if err != nil { + fmt.Println("Could not initialize Bubble Tea model:", err) + os.Exit(1) + } + return model +} + +func loadData(author_file string) { file, err := os.Open(author_file) if err != nil { fmt.Println("Could not open file:", err) @@ -103,11 +114,11 @@ func Entry_US(author_file string) { content = cnt.String() - model, err := newExample() - if err != nil { - fmt.Println("Could not initialize Bubble Tea model:", err) - os.Exit(1) - } +} + +func Entry_US(author_file string) { + + model := intialModel_US(author_file) if _, err := tea.NewProgram(model).Run(); err != nil { fmt.Println("Bummer, there's been an error:", err) From 2a222ad488d878b5284c095afde7853fb81d96b8 Mon Sep 17 00:00:00 2001 From: Slug-Boi Date: Thu, 24 Oct 2024 20:48:02 +0200 Subject: [PATCH 16/29] feat --- src_code/go_src/cmd/utils/user_util.go | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src_code/go_src/cmd/utils/user_util.go b/src_code/go_src/cmd/utils/user_util.go index 651fe0b..f1e8002 100644 --- a/src_code/go_src/cmd/utils/user_util.go +++ b/src_code/go_src/cmd/utils/user_util.go @@ -17,7 +17,7 @@ var Users = map[string]User{} var DefExclude = []string{} var Groups = map[string][]User{} -func Define_users(author_file string) { +func Define_users(author_file string) { file, err := os.Open(author_file) if err != nil { print("File not found") @@ -79,4 +79,11 @@ func Define_users(author_file string) { func RemoveUser(short string) { delete(Users, short) -} \ No newline at end of file +} + +func TempAddUser(username, email string) { + usr := User{Username: username, Email: email} + + Users[username] = usr +} + From 55dd1bc5ee7baf8fba37909ffa38dbb88dd14d67 Mon Sep 17 00:00:00 2001 From: Slug-Boi Date: Thu, 24 Oct 2024 20:49:32 +0200 Subject: [PATCH 17/29] refactor: add screen clear to root command --- src_code/go_src/cmd/root.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src_code/go_src/cmd/root.go b/src_code/go_src/cmd/root.go index 206bdc1..427924e 100644 --- a/src_code/go_src/cmd/root.go +++ b/src_code/go_src/cmd/root.go @@ -6,6 +6,7 @@ import ( "main/src_code/go_src/cmd/utils" "os" + "github.com/inancgumus/screen" "github.com/spf13/cobra" ) @@ -34,6 +35,8 @@ var rootCmd = &cobra.Command{ case 0: // launch the tui args = append(args, tui.Entry_CM()) + screen.Clear() + screen.MoveTopLeft() sel_auth := tui.Entry() message = utils.Commit(args[0], sel_auth) goto tui @@ -82,5 +85,4 @@ func Execute() { func init() { rootCmd.Flags().BoolP("print", "p", false, "Prints the commit message to the console") - } From 2ab93121265809090b3a4fb5c75b141e8fa251b9 Mon Sep 17 00:00:00 2001 From: Slug-Boi Date: Thu, 24 Oct 2024 20:49:45 +0200 Subject: [PATCH 18/29] chore: update go mod --- go.mod | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/go.mod b/go.mod index f370060..2ae70ad 100644 --- a/go.mod +++ b/go.mod @@ -18,12 +18,16 @@ require ( github.com/alecthomas/chroma/v2 v2.14.0 // indirect github.com/atotto/clipboard v0.1.4 // indirect github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect + github.com/aymanbagabas/go-udiff v0.2.0 // indirect github.com/aymerick/douceur v0.2.0 // indirect github.com/charmbracelet/x/ansi v0.2.3 // indirect + github.com/charmbracelet/x/exp/golden v0.0.0-20240815200342-61de596daa2b // indirect + github.com/charmbracelet/x/exp/teatest v0.0.0-20241022174419-46d9bb99a691 // indirect github.com/charmbracelet/x/term v0.2.0 // indirect github.com/dlclark/regexp2 v1.11.0 // indirect github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f // indirect github.com/gorilla/css v1.0.1 // indirect + github.com/inancgumus/screen v0.0.0-20190314163918-06e984b86ed3 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/lucasb-eyer/go-colorful v1.2.0 // indirect github.com/mattn/go-isatty v0.0.20 // indirect @@ -41,6 +45,7 @@ require ( github.com/vektah/gqlparser/v2 v2.5.6 // indirect github.com/yuin/goldmark v1.7.4 // indirect github.com/yuin/goldmark-emoji v1.0.3 // indirect + golang.org/x/crypto v0.25.0 // indirect golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa // indirect golang.org/x/net v0.27.0 // indirect golang.org/x/sync v0.8.0 // indirect From 3dfecbeab67b12b70b17e5d6bbe58581d43c1e2b Mon Sep 17 00:00:00 2001 From: Slug-Boi Date: Thu, 24 Oct 2024 20:59:49 +0200 Subject: [PATCH 19/29] chore: go mod updates --- go.mod | 4 +-- go.sum | 100 +++++++++++++++++++++++++++++++++++++++++++++++++--- go.work.sum | 29 +++++++++++++++ 3 files changed, 127 insertions(+), 6 deletions(-) diff --git a/go.mod b/go.mod index 2ae70ad..a00417e 100644 --- a/go.mod +++ b/go.mod @@ -8,6 +8,8 @@ require ( github.com/charmbracelet/bubbletea v1.1.1 github.com/charmbracelet/glamour v0.8.0 github.com/charmbracelet/lipgloss v0.13.0 + github.com/charmbracelet/x/exp/teatest v0.0.0-20241022174419-46d9bb99a691 + github.com/inancgumus/screen v0.0.0-20190314163918-06e984b86ed3 github.com/spf13/cobra v1.8.1 ) @@ -22,12 +24,10 @@ require ( github.com/aymerick/douceur v0.2.0 // indirect github.com/charmbracelet/x/ansi v0.2.3 // indirect github.com/charmbracelet/x/exp/golden v0.0.0-20240815200342-61de596daa2b // indirect - github.com/charmbracelet/x/exp/teatest v0.0.0-20241022174419-46d9bb99a691 // indirect github.com/charmbracelet/x/term v0.2.0 // indirect github.com/dlclark/regexp2 v1.11.0 // indirect github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f // indirect github.com/gorilla/css v1.0.1 // indirect - github.com/inancgumus/screen v0.0.0-20190314163918-06e984b86ed3 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/lucasb-eyer/go-colorful v1.2.0 // indirect github.com/mattn/go-isatty v0.0.20 // indirect diff --git a/go.sum b/go.sum index 543e026..2f5145e 100644 --- a/go.sum +++ b/go.sum @@ -4,25 +4,102 @@ github.com/99designs/gqlgen v0.17.31 h1:VncSQ82VxieHkea8tz11p7h/zSbvHSxSDZfywqWt github.com/99designs/gqlgen v0.17.31/go.mod h1:i4rEatMrzzu6RXaHydq1nmEPZkb3bKQsnxNRHS4DQB4= github.com/Khan/genqlient v0.6.0 h1:Bwb1170ekuNIVIwTJEqvO8y7RxBxXu639VJOkKSrwAk= github.com/Khan/genqlient v0.6.0/go.mod h1:rvChwWVTqXhiapdhLDV4bp9tz/Xvtewwkon4DpWWCRM= +github.com/MakeNowJust/heredoc v1.0.0 h1:cXCdzVdstXyiTqTvfqk9SDHpKNjxuom+DOlyEeQ4pzQ= +github.com/MakeNowJust/heredoc v1.0.0/go.mod h1:mG5amYoWBHf8vpLOuehzbGGw0EHxpZZ6lCpQ4fNJ8LE= github.com/adrg/xdg v0.4.0 h1:RzRqFcjH4nE5C6oTAxhBtoE2IRyjBSa62SCbyPidvls= github.com/adrg/xdg v0.4.0/go.mod h1:N6ag73EX4wyxeaoeHctc1mas01KZgsj5tYiAIwqJE/E= github.com/agnivade/levenshtein v1.1.1/go.mod h1:veldBMzWxcCG2ZvUTKD2kJNRdCk5hVbJomOvKkmgYbo= +github.com/alecthomas/assert/v2 v2.7.0 h1:QtqSACNS3tF7oasA8CU6A6sXZSBDqnm7RfpLl9bZqbE= +github.com/alecthomas/assert/v2 v2.7.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k= +github.com/alecthomas/chroma/v2 v2.14.0 h1:R3+wzpnUArGcQz7fCETQBzO5n9IMNi13iIs46aU4V9E= +github.com/alecthomas/chroma/v2 v2.14.0/go.mod h1:QolEbTfmUHIMVpBqxeDnNBj2uoeI4EbYP4i6n68SG4I= +github.com/alecthomas/repr v0.4.0 h1:GhI2A8MACjfegCPVq9f1FLvIBS+DrQ2KQBFZP1iFzXc= +github.com/alecthomas/repr v0.4.0/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4= github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883 h1:bvNMNQO63//z+xNgfBlViaCIJKLlCJ6/fmUseuG0wVQ= github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8= github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0/go.mod h1:t2tdKJDJF9BV14lnkjHmOQgcvEKgtqs5a1N3LNdJhGE= +github.com/atotto/clipboard v0.1.4 h1:EH0zSVneZPSuFR11BlR9YppQTVDbh5+16AmcJi4g1z4= +github.com/atotto/clipboard v0.1.4/go.mod h1:ZY9tmq7sm5xIbd9bOK4onWV4S6X0u6GY7Vn0Yu86PYI= +github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k= +github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8= +github.com/aymanbagabas/go-udiff v0.2.0 h1:TK0fH4MteXUDspT88n8CKzvK0X9O2xu9yQjWpi6yML8= +github.com/aymanbagabas/go-udiff v0.2.0/go.mod h1:RE4Ex0qsGkTAJoQdQQCA0uG+nAzJO/pI/QwceO5fgrA= +github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk= +github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4= +github.com/charmbracelet/bubbles v0.20.0 h1:jSZu6qD8cRQ6k9OMfR1WlM+ruM8fkPWkHvQWD9LIutE= +github.com/charmbracelet/bubbles v0.20.0/go.mod h1:39slydyswPy+uVOHZ5x/GjwVAFkCsV8IIVy+4MhzwwU= +github.com/charmbracelet/bubbletea v1.1.1 h1:KJ2/DnmpfqFtDNVTvYZ6zpPFL9iRCRr0qqKOCvppbPY= +github.com/charmbracelet/bubbletea v1.1.1/go.mod h1:9Ogk0HrdbHolIKHdjfFpyXJmiCzGwy+FesYkZr7hYU4= +github.com/charmbracelet/glamour v0.8.0 h1:tPrjL3aRcQbn++7t18wOpgLyl8wrOHUEDS7IZ68QtZs= +github.com/charmbracelet/glamour v0.8.0/go.mod h1:ViRgmKkf3u5S7uakt2czJ272WSg2ZenlYEZXT2x7Bjw= +github.com/charmbracelet/lipgloss v0.13.0 h1:4X3PPeoWEDCMvzDvGmTajSyYPcZM4+y8sCA/SsA3cjw= +github.com/charmbracelet/lipgloss v0.13.0/go.mod h1:nw4zy0SBX/F/eAO1cWdcvy6qnkDUxr8Lw7dvFrAIbbY= +github.com/charmbracelet/x/ansi v0.2.3 h1:VfFN0NUpcjBRd4DnKfRaIRo53KRgey/nhOoEqosGDEY= +github.com/charmbracelet/x/ansi v0.2.3/go.mod h1:dk73KoMTT5AX5BsX0KrqhsTqAnhZZoCBjs7dGWp4Ktw= +github.com/charmbracelet/x/exp/golden v0.0.0-20240815200342-61de596daa2b h1:MnAMdlwSltxJyULnrYbkZpp4k58Co7Tah3ciKhSNo0Q= +github.com/charmbracelet/x/exp/golden v0.0.0-20240815200342-61de596daa2b/go.mod h1:wDlXFlCrmJ8J+swcL/MnGUuYnqgQdW9rhSD61oNMb6U= +github.com/charmbracelet/x/exp/teatest v0.0.0-20241022174419-46d9bb99a691 h1:xiYMZ3dUF3iXc90LCTKj5ZiiwuCvhEvGsF/qUCMRgEk= +github.com/charmbracelet/x/exp/teatest v0.0.0-20241022174419-46d9bb99a691/go.mod h1:ektxP4TiEONm1mTGILRfo8F0a4rZMwsT1fEkXslQKtU= +github.com/charmbracelet/x/term v0.2.0 h1:cNB9Ot9q8I711MyZ7myUR5HFWL/lc3OpU8jZ4hwm0x0= +github.com/charmbracelet/x/term v0.2.0/go.mod h1:GVxgxAbjUrmpvIINHIQnJJKpMlHiZ4cktEQCN6GWyF0= +github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dgryski/trifles v0.0.0-20200323201526-dd97f9abfb48/go.mod h1:if7Fbed8SFyPtHLHbg49SI7NAdJiC5WIA09pe59rfAA= +github.com/dlclark/regexp2 v1.11.0 h1:G/nrcoOa7ZXlpoa/91N3X7mM3r8eIlMBBJZvsz/mxKI= +github.com/dlclark/regexp2 v1.11.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= +github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f h1:Y/CXytFA4m6baUTXGLOoWe4PQhGxaX0KpnayAqC48p4= +github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f/go.mod h1:vw97MGsxSvLiUE2X8qFplwetxpGLQrlU1Q9AUEIzCaM= +github.com/gorilla/css v1.0.1 h1:ntNaBIghp6JmvWnxbZKANoLyuXTPZ4cAMlo6RyhlbO8= +github.com/gorilla/css v1.0.1/go.mod h1:BvnYkspnSzMmwRK+b8/xgNPLiIuNZr6vbZBTPQ2A3b0= +github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM= +github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg= +github.com/inancgumus/screen v0.0.0-20190314163918-06e984b86ed3 h1:fO9A67/izFYFYky7l1pDP5Dr0BTCRkaQJUG6Jm5ehsk= +github.com/inancgumus/screen v0.0.0-20190314163918-06e984b86ed3/go.mod h1:Ey4uAp+LvIl+s5jRbOHLcZpUDnkjLBROl15fZLwPlTM= +github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= +github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= +github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= +github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY= +github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mattn/go-localereader v0.0.1 h1:ygSAOl7ZXTx4RdPYinUpg6W99U8jWvWi9Ye2JC/oIi4= +github.com/mattn/go-localereader v0.0.1/go.mod h1:8fBrzywKY7BI3czFoHkuzRoWE9C+EiG4R1k4Cjx5p88= +github.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk= +github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc= +github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/microcosm-cc/bluemonday v1.0.27 h1:MpEUotklkwCSLeH+Qdx1VJgNqLlpY2KXwXFM08ygZfk= +github.com/microcosm-cc/bluemonday v1.0.27/go.mod h1:jFi9vgW+H7c3V0lb6nR74Ib/DIB5OBs92Dimizgw2cA= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 h1:ZK8zHtRHOkbHy6Mmr5D264iyp3TiX5OmNcI5cIARiQI= +github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6/go.mod h1:CJlz5H+gyd6CUWT45Oy4q24RdLyn7Md9Vj2/ldJBSIo= +github.com/muesli/cancelreader v0.2.2 h1:3I4Kt4BQjOR54NavqnDogx/MIoWBFa0StPA8ELUXHmA= +github.com/muesli/cancelreader v0.2.2/go.mod h1:3XuTXfFS2VjM+HTLZY9Ak0l6eUKfijIfMUZ4EgX0QYo= +github.com/muesli/reflow v0.3.0 h1:IFsN6K9NfGtjeggFP+68I4chLZV2yIKsXJFNZ+eWh6s= +github.com/muesli/reflow v0.3.0/go.mod h1:pbwTDkVPibjO2kyvBQRBxTWEEGDGq0FlB1BIKtnHY/8= +github.com/muesli/termenv v0.15.3-0.20240618155329-98d742f6907a h1:2MaM6YC3mGu54x+RKAA6JiFFHlHDY1UbkxqppT7wYOg= +github.com/muesli/termenv v0.15.3-0.20240618155329-98d742f6907a/go.mod h1:hxSnBBYLK21Vtq/PHd0S2FYCxBXzBua8ov5s1RobyRQ= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= +github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= +github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= +github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/sahilm/fuzzy v0.1.1 h1:ceu5RHF8DGgoi+/dR5PsECjCDH1BE3Fnmpo7aVXOdRA= +github.com/sahilm/fuzzy v0.1.1/go.mod h1:VFvziUEIMCrT6A6tw2RFIXPXXmzXbOsSHF0DOI8ZK9Y= github.com/sergi/go-diff v1.3.1 h1:xkr+Oxo4BOQKmkn/B9eMK0g5Kg/983T9DqqPHwYqD+8= github.com/sergi/go-diff v1.3.1/go.mod h1:aMJSSKb2lpPvRNec0+w3fl7LP9IOFzdc9Pa4NFbPK1I= +github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM= +github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y= +github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= @@ -30,13 +107,28 @@ github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gt github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/vektah/gqlparser/v2 v2.5.6 h1:Ou14T0N1s191eRMZ1gARVqohcbe1e8FrcONScsq8cRU= github.com/vektah/gqlparser/v2 v2.5.6/go.mod h1:z8xXUff237NntSuH8mLFijZ+1tjV1swDbpDqjJmk6ME= +github.com/yuin/goldmark v1.7.1/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E= +github.com/yuin/goldmark v1.7.4 h1:BDXOHExt+A7gwPCJgPIIq7ENvceR7we7rOS9TNoLZeg= +github.com/yuin/goldmark v1.7.4/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E= +github.com/yuin/goldmark-emoji v1.0.3 h1:aLRkLHOuBR2czCY4R8olwMjID+tENfhyFDMCRhbIQY4= +github.com/yuin/goldmark-emoji v1.0.3/go.mod h1:tTkZEbwu5wkPmgTcitqddVxY9osFZiavD+r4AzQrh1U= +golang.org/x/crypto v0.25.0 h1:ypSNr+bnYL2YhwoMt2zPxHFmbAN1KZs/njMG3hxUp30= +golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M= golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa h1:FRnLl4eNAQl8hwxVVC17teOw8kdjVDVAiFMtgUdTSRQ= golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa/go.mod h1:zk2irFbV9DP96SEBUUAy67IdHUaZuSnrz1n472HUCLE= -golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ= -golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/net v0.27.0 h1:5K3Njcw06/l2y9vpGCSdcxWOYHOUk3dVNGDXN+FvAys= +golang.org/x/net v0.27.0/go.mod h1:dDi0PyhWNoiUOrAS8uXv/vnScO4wnHQO4mj9fn/RytE= +golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= +golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q= -golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo= +golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/term v0.22.0 h1:BbsgPEJULsl2fV/AT3v15Mjva5yXKQDyKf+TbDz7QJk= +golang.org/x/term v0.22.0/go.mod h1:F3qCibpT5AMpCRfhfT53vVJwhLtIVHhB9XDjfFvnMI4= +golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM= +golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/go.work.sum b/go.work.sum index 55baeb7..bbfc53f 100644 --- a/go.work.sum +++ b/go.work.sum @@ -23,3 +23,32 @@ golang.org/x/tools v0.15.0/go.mod h1:hpksKq4dtpQWS1uQ61JkdqWM3LscIS6Slf+VVkm+wQk google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +github.com/alexflint/go-arg v1.4.2/go.mod h1:9iRbDxne7LcR/GSvEr7ma++GLpdIU1zrghf2y2768kM= +github.com/alexflint/go-scalar v1.0.0/go.mod h1:GpHzbCOZXEKMEcygYQ5n/aa4Aq84zbxjy3MxYW0gjYw= +github.com/bradleyjkemp/cupaloy/v2 v2.6.0/go.mod h1:bm7JXdkRd4BHJk9HpwqAI8BoAY1lps46Enkdqw6aRX0= +github.com/charmbracelet/harmonica v0.2.0/go.mod h1:KSri/1RMQOZLbw7AHqgcBycp8pgJnQMYYT8QZRqZ1Ao= +github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= +github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/hashicorp/golang-lru/v2 v2.0.1/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= +github.com/kevinmbeaulieu/eq-go v1.0.0/go.mod h1:G3S8ajA56gKBZm4UB9AOyoOS37JO3roToPzKNM8dtdM= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= +github.com/logrusorgru/aurora/v3 v3.0.0/go.mod h1:vsR12bk5grlLvLXAYrBsb5Oc/N+LxAlxggSjiwMnCUc= +github.com/matryer/moq v0.2.7/go.mod h1:kITsx543GOENm48TUAQyJ9+SAvFSr7iGQXPoth/VUBk= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= +github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= +github.com/urfave/cli/v2 v2.24.4/go.mod h1:GHupkWPMM0M/sj1a2b4wUrWBPzazNrIjouW6fmdJLxc= +github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8= +golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M= +golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= +golang.org/x/tools v0.15.0/go.mod h1:hpksKq4dtpQWS1uQ61JkdqWM3LscIS6Slf+VVkm+wQk= +golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg= +golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= +google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= From def99f602f9d4fc3873a3ca9e69215ff29683a3c Mon Sep 17 00:00:00 2001 From: Slug-Boi Date: Thu, 24 Oct 2024 21:11:24 +0200 Subject: [PATCH 20/29] chore: fixed imports and function signatures --- go.mod | 48 ++++++++++++++++++++++++++ src_code/go_src/cmd/root.go | 4 +-- src_code/go_src/cmd/tui/tui_author.go | 4 +-- src_code/go_src/cmd/tui/tui_list.go | 2 +- src_code/go_src/cmd/users.go | 4 +-- src_code/go_src/cmd/utils/util_test.go | 2 +- src_code/go_src/go.mod | 3 -- src_code/go_src/main.go | 2 +- 8 files changed, 57 insertions(+), 12 deletions(-) create mode 100644 go.mod delete mode 100644 src_code/go_src/go.mod diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..8eeb3f3 --- /dev/null +++ b/go.mod @@ -0,0 +1,48 @@ +module github.com/Slug-Boi/cocommit + +go 1.21.9 + +require ( + github.com/charmbracelet/bubbles v0.20.0 + github.com/charmbracelet/bubbletea v1.1.2 + github.com/charmbracelet/glamour v0.8.0 + github.com/charmbracelet/lipgloss v0.13.1 + github.com/charmbracelet/x/exp/teatest v0.0.0-20241024145942-ad25fd0d5a9e + github.com/inancgumus/screen v0.0.0-20190314163918-06e984b86ed3 + github.com/spf13/cobra v1.8.1 +) + +require ( + github.com/alecthomas/chroma/v2 v2.14.0 // indirect + github.com/atotto/clipboard v0.1.4 // indirect + github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect + github.com/aymanbagabas/go-udiff v0.2.0 // indirect + github.com/aymerick/douceur v0.2.0 // indirect + github.com/charmbracelet/x/ansi v0.4.0 // indirect + github.com/charmbracelet/x/exp/golden v0.0.0-20240815200342-61de596daa2b // indirect + github.com/charmbracelet/x/term v0.2.0 // indirect + github.com/dlclark/regexp2 v1.11.0 // indirect + github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f // indirect + github.com/gorilla/css v1.0.1 // indirect + github.com/inconshreveable/mousetrap v1.1.0 // indirect + github.com/lucasb-eyer/go-colorful v1.2.0 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect + github.com/mattn/go-localereader v0.0.1 // indirect + github.com/mattn/go-runewidth v0.0.16 // indirect + github.com/microcosm-cc/bluemonday v1.0.27 // indirect + github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 // indirect + github.com/muesli/cancelreader v0.2.2 // indirect + github.com/muesli/reflow v0.3.0 // indirect + github.com/muesli/termenv v0.15.3-0.20240618155329-98d742f6907a // indirect + github.com/rivo/uniseg v0.4.7 // indirect + github.com/sahilm/fuzzy v0.1.1 // indirect + github.com/spf13/pflag v1.0.5 // indirect + github.com/yuin/goldmark v1.7.4 // indirect + github.com/yuin/goldmark-emoji v1.0.3 // indirect + golang.org/x/crypto v0.25.0 // indirect + golang.org/x/net v0.27.0 // indirect + golang.org/x/sync v0.8.0 // indirect + golang.org/x/sys v0.26.0 // indirect + golang.org/x/term v0.22.0 // indirect + golang.org/x/text v0.19.0 // indirect +) diff --git a/src_code/go_src/cmd/root.go b/src_code/go_src/cmd/root.go index 427924e..68fa459 100644 --- a/src_code/go_src/cmd/root.go +++ b/src_code/go_src/cmd/root.go @@ -2,8 +2,8 @@ package cmd import ( "fmt" - "main/src_code/go_src/cmd/tui" - "main/src_code/go_src/cmd/utils" + "github.com/Slug-Boi/cocommit/src_code/go_src/cmd/tui" + "github.com/Slug-Boi/cocommit/src_code/go_src/cmd/utils" "os" "github.com/inancgumus/screen" diff --git a/src_code/go_src/cmd/tui/tui_author.go b/src_code/go_src/cmd/tui/tui_author.go index 1307c42..6dfc04e 100644 --- a/src_code/go_src/cmd/tui/tui_author.go +++ b/src_code/go_src/cmd/tui/tui_author.go @@ -5,7 +5,7 @@ package tui import ( "fmt" - "main/src_code/go_src/cmd/utils" + "github.com/Slug-Boi/cocommit/src_code/go_src/cmd/utils" "os" "strings" @@ -285,7 +285,7 @@ func Entry_CA() string { return "" } -func Entry_TA(ch chan bool) string { +func Entry_TA() string { m, err := tea.NewProgram(initialModel("temp")).Run() if err != nil { fmt.Printf("could not start program: %s\n", err) diff --git a/src_code/go_src/cmd/tui/tui_list.go b/src_code/go_src/cmd/tui/tui_list.go index 7486381..70f5ab3 100644 --- a/src_code/go_src/cmd/tui/tui_list.go +++ b/src_code/go_src/cmd/tui/tui_list.go @@ -3,7 +3,7 @@ package tui import ( "fmt" "io" - "main/src_code/go_src/cmd/utils" + "github.com/Slug-Boi/cocommit/src_code/go_src/cmd/utils" "os" "sort" "strings" diff --git a/src_code/go_src/cmd/users.go b/src_code/go_src/cmd/users.go index 4277858..264a49f 100644 --- a/src_code/go_src/cmd/users.go +++ b/src_code/go_src/cmd/users.go @@ -1,8 +1,8 @@ package cmd import ( - "main/src_code/go_src/cmd/tui" - "main/src_code/go_src/cmd/utils" + "github.com/Slug-Boi/cocommit/src_code/go_src/cmd/tui" + "github.com/Slug-Boi/cocommit/src_code/go_src/cmd/utils" "os" "os/exec" "slices" diff --git a/src_code/go_src/cmd/utils/util_test.go b/src_code/go_src/cmd/utils/util_test.go index f532c28..9ca576a 100644 --- a/src_code/go_src/cmd/utils/util_test.go +++ b/src_code/go_src/cmd/utils/util_test.go @@ -1,7 +1,7 @@ package utils_test import ( - "main/src_code/go_src/cmd/utils" + "github.com/Slug-Boi/cocommit/src_code/go_src/cmd/utils" "os" "testing" ) diff --git a/src_code/go_src/go.mod b/src_code/go_src/go.mod deleted file mode 100644 index 6abede5..0000000 --- a/src_code/go_src/go.mod +++ /dev/null @@ -1,3 +0,0 @@ -module github.com/Slug-Boi/cocommit - -go 1.21.9 diff --git a/src_code/go_src/main.go b/src_code/go_src/main.go index 54c4d10..e17f880 100644 --- a/src_code/go_src/main.go +++ b/src_code/go_src/main.go @@ -4,7 +4,7 @@ Copyright © 2024 NAME HERE */ package main -import "main/src_code/go_src/cmd" +import "github.com/Slug-Boi/cocommit/src_code/go_src/cmd" func main() { cmd.Execute() From 6c96fc90bdc72fc3883393020093da213c755e18 Mon Sep 17 00:00:00 2001 From: Slug-Boi Date: Fri, 25 Oct 2024 13:54:41 +0200 Subject: [PATCH 21/29] test:update util tests and remove a line --- src_code/go_src/cmd/tui/tui_list.go | 1 - src_code/go_src/cmd/utils/util_test.go | 22 ++++++++++++++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/src_code/go_src/cmd/tui/tui_list.go b/src_code/go_src/cmd/tui/tui_list.go index 70f5ab3..0a4e9df 100644 --- a/src_code/go_src/cmd/tui/tui_list.go +++ b/src_code/go_src/cmd/tui/tui_list.go @@ -33,7 +33,6 @@ type item string var selected = map[string]item{} var negation = false -var ignore = false var dupProtect = map[string]string{} diff --git a/src_code/go_src/cmd/utils/util_test.go b/src_code/go_src/cmd/utils/util_test.go index 9ca576a..c58af1e 100644 --- a/src_code/go_src/cmd/utils/util_test.go +++ b/src_code/go_src/cmd/utils/util_test.go @@ -54,6 +54,7 @@ func Test_DeleteAuthor(t *testing.T) { t.Errorf("DeleteOneAuthor() did not delete author") } } + // Author tests END // User tests BEGIN @@ -79,6 +80,27 @@ func Test_RemoveUser(t *testing.T) { t.Errorf("RemoveUser() = %v; want 3", len(utils.Users)) } } + +func Test_TempAddUser(t *testing.T) { + setup() + defer teardown() + // Test TempAddUser + utils.Define_users("author_file_test") + if len(utils.Users) != 4 { + t.Errorf("Define_users() = %v; want 4", len(utils.Users)) + } + + utils.TempAddUser("temp", "temp@test.io") + + if len(utils.Users) != 5 { + t.Errorf("TempAddUser() = %v; want 5", len(utils.Users)) + } + + if _, ok := utils.Users["temp"]; !ok { + t.Errorf("TempAddUser() did not add user") + } + +} // User tests END // Commit tests BEGIN From 55ee0c66d161faf5d361ef7857a6cd7ea41313a0 Mon Sep 17 00:00:00 2001 From: Slug-Boi Date: Fri, 25 Oct 2024 13:55:25 +0200 Subject: [PATCH 22/29] ci: update workflow files and mod version --- ci/build_test_release.go | 2 +- ci/test_on_push.go | 2 +- go.mod | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/ci/build_test_release.go b/ci/build_test_release.go index aabc2d3..861b2c3 100644 --- a/ci/build_test_release.go +++ b/ci/build_test_release.go @@ -24,7 +24,7 @@ func main() { // mount the source code directory on the host // at /src in the container source := client.Container(). - From("golang:1.22"). + From("golang:1.23"). WithDirectory("/src", client.Host().Directory(".", dagger.HostDirectoryOpts{ Exclude: []string{}, })).WithMountedCache("/src/dagger_dep_cache/go_dep", goCache) diff --git a/ci/test_on_push.go b/ci/test_on_push.go index efc04ca..60ae112 100644 --- a/ci/test_on_push.go +++ b/ci/test_on_push.go @@ -24,7 +24,7 @@ func main() { // mount the source code directory on the host // at /src in the container source := client.Container(). - From("golang:1.22"). + From("golang:1.23"). WithDirectory("/src", client.Host().Directory(".", dagger.HostDirectoryOpts{ Exclude: []string{"build/"}, })).WithMountedCache("/src/dagger_dep_cache/go_dep", goCache) diff --git a/go.mod b/go.mod index 8eeb3f3..0518b16 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/Slug-Boi/cocommit -go 1.21.9 +go 1.23.2 require ( github.com/charmbracelet/bubbles v0.20.0 From 9086597d1774d557bb2965c75a0ed9c68fdedbf0 Mon Sep 17 00:00:00 2001 From: Slug-Boi Date: Fri, 25 Oct 2024 17:32:13 +0200 Subject: [PATCH 23/29] ci:change go work path --- .github/workflows/test_push.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test_push.yml b/.github/workflows/test_push.yml index 9a039a3..da15206 100644 --- a/.github/workflows/test_push.yml +++ b/.github/workflows/test_push.yml @@ -16,7 +16,7 @@ jobs: uses: actions/setup-go@v3 - uses: actions/checkout@v3 - name: Setup Go Workfile - run: go work init ./ci ./src_code/go_src + run: go work init ./ci ./ - name: Get Dagger run: cd ci && go get dagger.io/dagger@latest && cd .. - name: Run Dagger Test Workflow From ef674c20f9c1339692217d5b886fff36f4772ad3 Mon Sep 17 00:00:00 2001 From: Slug-Boi Date: Fri, 25 Oct 2024 17:34:41 +0200 Subject: [PATCH 24/29] ci: work path change --- .github/workflows/build_test_release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build_test_release.yml b/.github/workflows/build_test_release.yml index ee035c2..89501fc 100644 --- a/.github/workflows/build_test_release.yml +++ b/.github/workflows/build_test_release.yml @@ -13,7 +13,7 @@ jobs: uses: actions/setup-go@v3 - uses: actions/checkout@v3 - name: Setup Go Workfile - run: go work init ./ci ./src_code/go_src + run: go work init ./ci ./ - run: cd ci && go get dagger.io/dagger@latest && cd .. - run: mkdir ./dist - run: go run ci/build_test_release.go From 47128cf3f61f834c125e90e6c3ff206476fdd4d1 Mon Sep 17 00:00:00 2001 From: Slug-Boi Date: Sat, 26 Oct 2024 12:51:24 +0200 Subject: [PATCH 25/29] test: cobra tests added --- src_code/go_src/cmd/cmd_test.go | 149 ++++++++++++++++++++++++++++++++ src_code/go_src/cmd/root.go | 19 +++- src_code/go_src/cmd/users.go | 9 +- 3 files changed, 170 insertions(+), 7 deletions(-) create mode 100644 src_code/go_src/cmd/cmd_test.go diff --git a/src_code/go_src/cmd/cmd_test.go b/src_code/go_src/cmd/cmd_test.go new file mode 100644 index 0000000..790e46b --- /dev/null +++ b/src_code/go_src/cmd/cmd_test.go @@ -0,0 +1,149 @@ +package cmd + +import ( + "bytes" + "io" + "os" + "strings" + "testing" + + "github.com/Slug-Boi/cocommit/src_code/go_src/cmd/utils" +) + +const author_data = `syntax for the test file +te|testing|TestUser|test@test.test|ex +ti|testtest|UserName2|testing@user.io;;gr1` + +var envVar = utils.Find_authorfile() + +func setup() { + // setup test data + err := os.WriteFile("author_file_test", []byte(author_data), 0644) + if err != nil { + panic(err) + } + os.Setenv("author_file", "author_file_test") + envVar = os.Getenv("author_file") +} + +func teardown() { + // remove test data + os.Remove("author_file_test") + os.Setenv("author_file", envVar) +} + +func StdoutReader() (chan string, *os.File, *os.File, *os.File) { + old := os.Stdout + r, w, _ := os.Pipe() + os.Stdout = w + + outC := make(chan string) + return outC, r, w, old +} + +// users CMD TEST BEGIN +func Test_UsersCmd(t *testing.T) { + setup() + defer teardown() + + //stdout reader + outC, r, w, old := StdoutReader() + + go func() { + var buf bytes.Buffer + io.Copy(&buf, r) + outC <- buf.String() + }() + + cmd := UsersCmd() + authorfile = "author_file_test" + b := new(bytes.Buffer) + cmd.SetErr(b) + cmd.Execute() + + out, err := io.ReadAll(b) + if err != nil { + t.Fatal(err) + } + + w.Close() + os.Stdout = old + outStr := <-outC + if outStr == "" { + t.Errorf("Expected output but got nothing") + } + + if !strings.Contains(outStr, author_data) { + t.Errorf("Expected to find 'syntax for the test file' in output but got %s", outStr) + } + + if string(out) != "" { + t.Errorf("Expected empty output but got %s", string(out)) + } + +} + +// users CMD TEST END + +// root CMD TEST BEGIN +func Test_CommitCmd(t *testing.T) { + setup() + defer teardown() + + //stdout reader + outC, r, w, old := StdoutReader() + + go func() { + var buf bytes.Buffer + io.Copy(&buf, r) + outC <- buf.String() + }() + + cmd := rootCmD + cmd.SetArgs([]string{"-t", "Test commit message"}) + cmd.Execute() + + w.Close() + os.Stdout = old + outStr := <-outC + if outStr == "" { + t.Errorf("Expected output but got nothing") + } + + if !strings.Contains(outStr, "Test commit message\n") { + t.Errorf("Expected to find 'Test commit message' in output but got %s", outStr) + } + +} + +func Test_CommitCmdWithM(t *testing.T) { + setup() + defer teardown() + + //stdout reader + outC, r, w, old := StdoutReader() + + go func() { + var buf bytes.Buffer + io.Copy(&buf, r) + outC <- buf.String() + }() + + cmd := rootCmD + cmd.SetArgs([]string{"-m", "-t", "Test commit message"}) + cmd.Execute() + + w.Close() + os.Stdout = old + outStr := <-outC + if outStr == "" { + t.Errorf("Expected output but got nothing") + } + + if !strings.Contains(outStr, "Test commit message\n") { + t.Errorf("Expected to find 'Test commit message' in output but got %s", outStr) + } + + +} +// root CMD TEST END diff --git a/src_code/go_src/cmd/root.go b/src_code/go_src/cmd/root.go index 68fa459..6b335ca 100644 --- a/src_code/go_src/cmd/root.go +++ b/src_code/go_src/cmd/root.go @@ -2,16 +2,18 @@ package cmd import ( "fmt" + "os" + "github.com/Slug-Boi/cocommit/src_code/go_src/cmd/tui" "github.com/Slug-Boi/cocommit/src_code/go_src/cmd/utils" - "os" "github.com/inancgumus/screen" "github.com/spf13/cobra" ) // rootCmd represents the base command when called without any subcommands -var rootCmd = &cobra.Command{ +// func RootCmd() *cobra.Command { +var rootCmD = &cobra.Command{ Use: `cocommit [co-author2] ... || cocommit [co-author2:email] ... || cocommit all || @@ -28,6 +30,7 @@ var rootCmd = &cobra.Command{ // check if the print flag is set pflag, _ := cmd.Flags().GetBool("print") + tflag, _ := cmd.Flags().GetBool("test_print") // run execute commands again as root run will not call this part // redundant check for now but will be useful later when we add tui wrap_around: @@ -42,6 +45,11 @@ var rootCmd = &cobra.Command{ goto tui case 1: if len(args) == 1 { + if tflag { + fmt.Println(args[0]) + return + } + utils.GitWrapper(args[0]) if pflag { fmt.Println(args[0]) @@ -77,12 +85,15 @@ func Execute() { // define users utils.Define_users(author_file) - err := rootCmd.Execute() + err := rootCmD.Execute() if err != nil { os.Exit(1) } } func init() { - rootCmd.Flags().BoolP("print", "p", false, "Prints the commit message to the console") + //rootCmD := RootCmd() + rootCmD.Flags().BoolP("print", "p", false, "Prints the commit message to the console") + rootCmD.Flags().BoolP("test_print", "t", false, "Prints the commit message to the console without running the git commit command") + rootCmD.Flags().BoolP("message", "m", false, "Does nothing but allows for -m to be used in the command") } diff --git a/src_code/go_src/cmd/users.go b/src_code/go_src/cmd/users.go index 264a49f..112238e 100644 --- a/src_code/go_src/cmd/users.go +++ b/src_code/go_src/cmd/users.go @@ -15,7 +15,8 @@ import ( var authorfile = utils.Find_authorfile() // usersCmd represents the users command -var usersCmd = &cobra.Command{ +func UsersCmd() *cobra.Command { + return &cobra.Command{ Use: "users", Short: "Displays all users from the author file located at: " + authorfile, Long: `Displays all users from the author file located at: ` + authorfile, @@ -35,7 +36,7 @@ var usersCmd = &cobra.Command{ } sort.Strings(user_sb) println(strings.Join(user_sb, "")) - os.Exit(1) + os.Exit(0) } bat_check := exec.Command("which", "bat") out, _ := bat_check.CombinedOutput() @@ -49,8 +50,10 @@ var usersCmd = &cobra.Command{ bat.Run() }, } +} func init() { - rootCmd.AddCommand(usersCmd) + usersCmd := UsersCmd() + rootCmD.AddCommand(usersCmd) usersCmd.Flags().BoolP("np", "n", false, "No pretty print of the users") } From c7e39201ac4b900bd56e74653e9b83840f08b181 Mon Sep 17 00:00:00 2001 From: Slug-Boi Date: Sat, 26 Oct 2024 18:35:57 +0200 Subject: [PATCH 26/29] test: write tui tests --- src_code/go_src/cmd/tui/tui_test.go | 160 +++++++++++++++++++++++++++- 1 file changed, 159 insertions(+), 1 deletion(-) diff --git a/src_code/go_src/cmd/tui/tui_test.go b/src_code/go_src/cmd/tui/tui_test.go index 89c0c2a..5b1cfd7 100644 --- a/src_code/go_src/cmd/tui/tui_test.go +++ b/src_code/go_src/cmd/tui/tui_test.go @@ -31,7 +31,7 @@ func teardown() { os.Remove("author_file_test") os.Setenv("author_file", envVar) } - +// tui_show_users TESTS BEGIN func TestShowUser(t *testing.T) { setup() defer teardown() @@ -53,3 +53,161 @@ func TestShowUser(t *testing.T) { tm.WaitFinished(t, teatest.WithFinalTimeout(time.Second)) } + +// tui_show_users TESTS END + +// tui_author TESTS BEGIN +func TestEntryTA(t *testing.T) { + setup() + defer teardown() + + m := initialModel("temp") + tm := teatest.NewTestModel( + t, m, teatest.WithInitialTermSize(300, 300), + ) + tm.Type("test") + + tm.Send(tea.KeyMsg{ + Type: tea.KeyRunes, + Runes: []rune("enter"), + }) + + tm.Type("testtest@temp.io") + + tm.Send(tea.KeyMsg{ + Type: tea.KeyRunes, + Runes: []rune("enter"), + }) + + tm.Send(tea.KeyMsg{ + Type: tea.KeyRunes, + Runes: []rune("enter"), + }) + + fm := tm.FinalModel(t) + m, ok := fm.(model_ca) + if !ok { + t.Errorf("Expected model_ca, got %T", fm) + } + + if len(m.inputs) != 2 { + t.Errorf("Expected 2 inputs, got %d", len(m.inputs)) + } + if m.inputs[0].Value() != "test" { + t.Errorf("Expected 'test', got %s", m.inputs[0].Value()) + } + if m.inputs[1].Value() != "testtest@temp.io" { + t.Errorf("Expected 'testtest@temp.io', got %s", m.inputs[1].Value()) + } +} + +func Test_EntryCA(t *testing.T) { + setup() + defer teardown() + + m := initialModel("author") + tm := teatest.NewTestModel( + t, m, teatest.WithInitialTermSize(300, 300), + ) + tm.Type("test") + + tm.Send(tea.KeyMsg{ + Type: tea.KeyRunes, + Runes: []rune("enter"), + }) + + tm.Type("testtest") + tm.Send(tea.KeyMsg{ + Type: tea.KeyRunes, + Runes: []rune("enter"), + }) + + tm.Type ("TestUser") + tm.Send(tea.KeyMsg{ + Type: tea.KeyRunes, + Runes: []rune("enter"), + }) + + tm.Type("test@temp.io") + tm.Send(tea.KeyMsg{ + Type: tea.KeyRunes, + Runes: []rune("enter"), + }) + + tm.Type("gr1") + tm.Send(tea.KeyMsg{ + Type: tea.KeyRunes, + Runes: []rune("enter"), + }) + tm.Send(tea.KeyMsg{ + Type: tea.KeyRunes, + Runes: []rune("enter"), + }) + tm.Send(tea.KeyMsg{ + Type: tea.KeyRunes, + Runes: []rune("tab"), + }) + tm.Send(tea.KeyMsg{ + Type: tea.KeyRunes, + Runes: []rune("enter"), + }) + + fm := tm.FinalModel(t) + m, ok := fm.(model_ca) + if !ok { + t.Errorf("Expected model_ca, got %T", fm) + } + + if len(m.inputs) != 5 { + t.Errorf("Expected 5 inputs, got %d", len(m.inputs)) + } + if m.inputs[0].Value() != "test" { + t.Errorf("Expected 'test', got %s", m.inputs[0].Value()) + } + if m.inputs[1].Value() != "testtest" { + t.Errorf("Expected 'testtest', got %s", m.inputs[1].Value()) + } + if m.inputs[2].Value() != "TestUser" { + t.Errorf("Expected 'TestUser', got %s", m.inputs[2].Value()) + } + if m.inputs[3].Value() != "test@temp.io" { + t.Errorf("Expected 'test@temp.io', got %s", m.inputs[2].Value()) + } + if m.inputs[4].Value() != "gr1" { + t.Errorf("Expected 'gr1', got %s", m.inputs[4].Value()) + } + //No clue why the exclude tag isn't working fix later + //TODO: Fix this should be !m.exclude + if m.exclude { + t.Errorf("Expected exclude to be true, got %v", m.exclude) + } +} +// tui_author TESTS END + +// tui_commit_message TESTS BEGIN +func TestEntryCM(t *testing.T) { + setup() + defer teardown() + + m := initialModel_cm() + tm := teatest.NewTestModel( + t, m, teatest.WithInitialTermSize(300, 300), + ) + tm.Type("test commit message") + + tm.Send(tea.KeyMsg{ + Type: tea.KeyRunes, + Runes: []rune("enter"), + }) + + fm := tm.FinalModel(t) + m, ok := fm.(model_cm) + if !ok { + t.Errorf("Expected model_cm, got %T", fm) + } + + if m.textarea.Value() != "test commit message" { + t.Errorf("Expected 'test commit message', got %s", m.textarea.Value()) + } +} +// tui_commit_message TESTS END \ No newline at end of file From aac02d095f06318947874582d9dd6cc6af86856e Mon Sep 17 00:00:00 2001 From: Slug-Boi Date: Sat, 26 Oct 2024 21:54:29 +0200 Subject: [PATCH 27/29] feat: add confirmation to author deletion --- src_code/go_src/cmd/tui/tui_list.go | 59 +++++++++++++++++++++-------- 1 file changed, 44 insertions(+), 15 deletions(-) diff --git a/src_code/go_src/cmd/tui/tui_list.go b/src_code/go_src/cmd/tui/tui_list.go index 0a4e9df..81d617d 100644 --- a/src_code/go_src/cmd/tui/tui_list.go +++ b/src_code/go_src/cmd/tui/tui_list.go @@ -23,6 +23,7 @@ var ( selectedItemStyle = lipgloss.NewStyle().PaddingLeft(2).Foreground(lipgloss.Color("170")) highlightStyle = lipgloss.NewStyle().PaddingLeft(4).Background(lipgloss.Color("236")).Foreground(lipgloss.Color("17")) selectedHighlightStyle = lipgloss.NewStyle().PaddingLeft(2).Background(lipgloss.Color("236")).Foreground(lipgloss.Color("170")) + deletionStyle = lipgloss.NewStyle().MarginLeft(2).Foreground(lipgloss.Color("9")) paginationStyle = list.DefaultStyles().PaginationStyle.PaddingLeft(4) helpStyle = list.DefaultStyles().HelpStyle.PaddingLeft(4).PaddingBottom(1) //quitTextStyle = lipgloss.NewStyle().Margin(1, 0, 2, 4) @@ -79,7 +80,6 @@ func newListKeyMap() *listKeyMap { } } -// TODO: Try and add filtering later down the line func (i item) FilterValue() string { return string(i) } type itemDelegate struct{} @@ -95,8 +95,6 @@ func (d itemDelegate) Render(w io.Writer, m list.Model, index int, listItem list str := fmt.Sprintf("%d. %s", index+1, i) - //TODO: add negation style where all items are flipped in selection - fn := itemStyle.Render if _, ok := selected[string(i)]; ok { fn = func(s ...string) string { @@ -146,7 +144,9 @@ func toggleNegation() { } } -func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { +var deletion bool + +func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { switch msg := msg.(type) { case tea.WindowSizeMsg: m.list.SetWidth(msg.Width) @@ -154,6 +154,9 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { // If filtering is enabled, skip key handling case tea.KeyMsg: + // deletion toggle with confirmation required + b := false + defer func(b *bool){deletion = *b}(&b) if m.list.FilterState() == list.Filtering { break } @@ -190,11 +193,15 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { split := strings.Split(tempAuthr, ":") item_str := split[0] + " - " + split[1] dupProtect[item_str] = tempAuthr - m.list.InsertItem(len(m.list.Items())+1, item(item_str)) + i := item(item_str) + m.list.InsertItem(len(m.list.Items())+1, i) + selectToggle(i) } return m, tea.ClearScreen case key.Matches(msg, m.keys.createAuthor): + screen.Clear() + screen.MoveTopLeft() author := Entry_CA() if author != "" { item_str := utils.Users[author].Username + " - " + utils.Users[author].Email @@ -203,12 +210,16 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { } return m, tea.ClearScreen case key.Matches(msg, m.keys.deleteAuthor): - author_str := string(m.list.SelectedItem().(item)) - author := dupProtect[author_str] - utils.DeleteOneAuthor(author) - delete(dupProtect, author_str) - m.list.RemoveItem(m.list.Index()) - return m, tea.ClearScreen + if deletion { + author_str := string(m.list.SelectedItem().(item)) + author := dupProtect[author_str] + utils.DeleteOneAuthor(author) + delete(dupProtect, author_str) + m.list.RemoveItem(m.list.Index()) + return m, nil + } + b = true + return m, nil } // extra key options switch keypress := msg.String(); keypress { @@ -221,6 +232,7 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { m.quitting = true return m, tea.Quit } + } var cmd tea.Cmd @@ -233,13 +245,24 @@ func (m model) View() string { return "" //quitTextStyle.Render(strings.Join(m.choice, " ")) } - return "\n" + m.list.View() + sb := strings.Builder{} + + sb.WriteString("\n" + m.list.View()) + + if deletion { + sb.WriteString(deletionStyle.Render("\n D: Confirm delete author")) + } + + return sb.String() } -// TODO: pass list in as a param to allow for group selection using same template -func Entry() []string { +func listModel() model { items := []list.Item{} + selected = map[string]item{} + + dupProtect = map[string]string{} + listKeys := newListKeyMap() // Add items to the list @@ -282,7 +305,13 @@ func Entry() []string { } l.Styles.HelpStyle = helpStyle - m := model{list: l, keys: listKeys} + return model{list: l, keys: listKeys} +} + +// TODO: pass list in as a param to allow for group selection using same template +func Entry() []string { + + m := listModel() f, err := tea.NewProgram(m).Run() if err != nil { From aff8d496207980388e0c85beb0e4573ab04f934d Mon Sep 17 00:00:00 2001 From: Slug-Boi Date: Sat, 26 Oct 2024 21:55:39 +0200 Subject: [PATCH 28/29] refactor: remove user to actually remove both names --- src_code/go_src/cmd/utils/user_util.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src_code/go_src/cmd/utils/user_util.go b/src_code/go_src/cmd/utils/user_util.go index f1e8002..cdfd5af 100644 --- a/src_code/go_src/cmd/utils/user_util.go +++ b/src_code/go_src/cmd/utils/user_util.go @@ -78,7 +78,10 @@ func Define_users(author_file string) { } func RemoveUser(short string) { - delete(Users, short) + usr := Users[short] + split := strings.Split(usr.Names, "/") + delete(Users, split[0]) + delete(Users, split[1]) } func TempAddUser(username, email string) { From 04f5a50579890c1e9126c79fd5522fe9b777b903 Mon Sep 17 00:00:00 2001 From: Slug-Boi Date: Sat, 26 Oct 2024 21:55:50 +0200 Subject: [PATCH 29/29] test: add more tui tests --- src_code/go_src/cmd/tui/tui_test.go | 154 +++++++++++++++++++++++++++- 1 file changed, 152 insertions(+), 2 deletions(-) diff --git a/src_code/go_src/cmd/tui/tui_test.go b/src_code/go_src/cmd/tui/tui_test.go index 5b1cfd7..1ce5622 100644 --- a/src_code/go_src/cmd/tui/tui_test.go +++ b/src_code/go_src/cmd/tui/tui_test.go @@ -6,6 +6,7 @@ import ( "testing" "time" + "github.com/Slug-Boi/cocommit/src_code/go_src/cmd/utils" tea "github.com/charmbracelet/bubbletea" "github.com/charmbracelet/x/exp/teatest" ) @@ -185,7 +186,7 @@ func Test_EntryCA(t *testing.T) { // tui_author TESTS END // tui_commit_message TESTS BEGIN -func TestEntryCM(t *testing.T) { +func Test_EntryCM(t *testing.T) { setup() defer teardown() @@ -210,4 +211,153 @@ func TestEntryCM(t *testing.T) { t.Errorf("Expected 'test commit message', got %s", m.textarea.Value()) } } -// tui_commit_message TESTS END \ No newline at end of file +// tui_commit_message TESTS END + + +// tui_list TESTS BEGIN +func Test_EntrySelectUsers(t *testing.T) { + setup() + defer teardown() + + utils.Define_users("author_file_test") + + m := listModel() + tm := teatest.NewTestModel( + t, m, teatest.WithInitialTermSize(300, 300), + ) + tm.Send(tea.KeyMsg{ + Type: tea.KeyRunes, + Runes: []rune(" "), + }) + + tm.Send(tea.KeyMsg{ + Type: tea.KeyRunes, + Runes: []rune("enter"), + }) + + fm := tm.FinalModel(t) + m, ok := fm.(model) + if !ok { + t.Errorf("Expected model, got %T", fm) + } + + if !m.quitting { + t.Errorf("Expected quitting to be true, got %v", m.quitting) + } + + if len(selected) != 1 { + t.Errorf("Expected 1 selected item, got %d", len(selected)) + } + +} + +func Test_EntrySelectAll(t *testing.T) { + setup() + defer teardown() + + utils.Define_users("author_file_test") + + m := listModel() + tm := teatest.NewTestModel( + t, m, teatest.WithInitialTermSize(300, 300), + ) + tm.Send(tea.KeyMsg{ + Type: tea.KeyRunes, + Runes: []rune("A"), + }) + + tm.Send(tea.KeyMsg{ + Type: tea.KeyRunes, + Runes: []rune("enter"), + }) + + fm := tm.FinalModel(t) + m, ok := fm.(model) + if !ok { + t.Errorf("Expected model, got %T", fm) + } + + if !m.quitting { + t.Errorf("Expected quitting to be true, got %v", m.quitting) + } + + if len(selected) != 2 { + t.Errorf("Expected 2 selected item, got %d", len(selected)) + } +} + +func Test_EntryNegation(t *testing.T) { + setup() + defer teardown() + + utils.Define_users("author_file_test") + + m := listModel() + tm := teatest.NewTestModel( + t, m, teatest.WithInitialTermSize(300, 300), + ) + tm.Send(tea.KeyMsg{ + Type: tea.KeyRunes, + Runes: []rune("n"), + }) + + tm.Send(tea.KeyMsg{ + Type: tea.KeyRunes, + Runes: []rune("enter"), + }) + + fm := tm.FinalModel(t) + m, ok := fm.(model) + if !ok { + t.Errorf("Expected model, got %T", fm) + } + + if !m.quitting { + t.Errorf("Expected quitting to be true, got %v", m.quitting) + } + + if len(selected) != 1 { + t.Errorf("Expected 2 selected item, got %d", len(selected)) + } +} + +func Test_EntryDeleteAuthor(t *testing.T) { + setup() + defer teardown() + + utils.Define_users("author_file_test") + + m := listModel() + tm := teatest.NewTestModel( + t, m, teatest.WithInitialTermSize(300, 300), + ) + tm.Send(tea.KeyMsg{ + Type: tea.KeyRunes, + Runes: []rune("D"), + }) + + tm.Send(tea.KeyMsg{ + Type: tea.KeyRunes, + Runes: []rune("D"), + }) + + tm.Send(tea.KeyMsg{ + Type: tea.KeyRunes, + Runes: []rune("enter"), + }) + + fm := tm.FinalModel(t) + m, ok := fm.(model) + if !ok { + t.Errorf("Expected model, got %T", fm) + } + + if !m.quitting { + t.Errorf("Expected quitting to be true, got %v", m.quitting) + } + + if len(utils.Users) != 2 { + t.Errorf("Expected 2 user after deletion, got %d", len(utils.Users)) + } +} +// tui_list TESTS END \ No newline at end of file