package main
import (
"fmt"
"github.com/go-git/go-git/v5"
"github.com/gookit/color"
"github.com/pelletier/go-toml/v2"
"os"
"os/user"
"strings"
)
// go-pest -- A reimplementation of cl-pest in Go, for the sake of learning a bit of Go
// See: https://git.spwbk.site/swatson/cl-pest/src/master/pest.lisp
type PestConfig struct {
Git GitConfig `toml:"git"`
Prompt PromptConfig `toml:"prompt"`
}
type GitConfig struct {
DisplayHead bool `toml:"display_head"`
DisplayBranch bool `toml:"display_branch"`
GitPrefix string `toml:"git_prefix"`
Colors Colors `toml:"colors"`
}
type PromptConfig struct {
DisplayUser bool `toml:"display_user"`
UserSuffix string `toml:"user_suffix"`
DisplayHostname bool `toml:"display_hostname"`
HostnameSuffix string `toml:"hostname_suffix"`
DisplayPwd bool `toml:"display_pwd"`
PwdSuffix string `toml:"pwd_suffix"`
PromptChar string `toml:"prompt_char"`
Colors Colors `toml:"colors"`
}
type Colors struct {
Fg []int `toml:"fg"`
Bg []int `toml:"bg"`
}
const tomlData = `
[git]
display_head = false
display_branch = false
git_prefix = ""
[git.colors]
fg = [0, 120, 50]
bg = [0, 0, 0]
[prompt]
display_user = false
user_suffix = ""
display_hostname = false
hostname_suffix = ""
display_pwd = true
pwd_suffix = ""
prompt_char = " λ "
[prompt.colors]
fg = [255, 255, 255]
bg = [0, 0, 0]
`
func parseTomlFromString(tomlString string) (PestConfig, error) {
var config PestConfig
err := toml.Unmarshal([]byte(tomlString), &config)
return config, err
}
func parseTomlFromFile(filePath string) (PestConfig, error) {
var cfg PestConfig
fileContent, err := os.ReadFile(filePath)
switch err {
case nil:
{
err = toml.Unmarshal(fileContent, &cfg)
return cfg, err
}
default:
{
// We had some kind of error, use the builtin config
cfg, err = parseTomlFromString(tomlData)
return cfg, err
}
}
}
func gitGetHead(filePath string) (string, string) {
gitObj, err := git.PlainOpen(filePath)
if err != nil {
// Likely not a git dir, return empty
return "", ""
}
headRef, err := gitObj.Head()
if err != nil {
panic(err)
}
sha := headRef.Hash().String()[:6]
branch := headRef.Name().Short()
return sha, branch
}
func getHostname() string {
hostname, err := os.Hostname()
if err != nil {
panic(err)
}
return hostname
}
func getUser() string {
username, err := user.Current()
if err != nil {
panic(err)
}
return username.Username
}
func getPwd() string {
pwd, err := os.Getwd()
if err != nil {
panic(err)
}
return pwd
}
type RGBColorInput struct {
r uint8
g uint8
b uint8
}
// make_style -- given a set of RGBColorInputs return a color.RGBColor pair
func make_style(fg, bg RGBColorInput) color.Style {
fg_s := color.RGB(fg.r, fg.g, fg.b)
bg_s := color.RGB(bg.r, bg.g, bg.b, true)
style := color.New(fg_s.Color(), bg_s.Color())
return style
}
func assemble_prompt(config *PestConfig) {
var prompt_builder strings.Builder
var git_prompt_builder strings.Builder
if config.Git.DisplayHead || config.Git.DisplayBranch {
sha, branch := gitGetHead(getPwd())
if config.Git.DisplayHead && config.Git.DisplayBranch {
git_prompt := sha + "|" + branch
git_prompt_builder.WriteString(config.Git.GitPrefix)
git_prompt_builder.WriteString(git_prompt)
} else if config.Git.DisplayHead {
git_prompt_builder.WriteString(config.Git.GitPrefix)
git_prompt_builder.WriteString(sha)
} else if config.Git.DisplayBranch {
git_prompt_builder.WriteString(config.Git.GitPrefix)
git_prompt_builder.WriteString(branch)
}
git_prompt_builder.WriteString(" ")
}
git_prompt_color := make_style(
RGBColorInput{
uint8(config.Git.Colors.Fg[0]),
uint8(config.Git.Colors.Fg[1]),
uint8(config.Git.Colors.Fg[2]),
},
RGBColorInput{
uint8(config.Git.Colors.Bg[0]),
uint8(config.Git.Colors.Bg[1]),
uint8(config.Git.Colors.Bg[2]),
})
if config.Prompt.DisplayUser {
prompt_builder.WriteString(getUser())
prompt_builder.WriteString(config.Prompt.UserSuffix)
}
if config.Prompt.DisplayHostname {
prompt_builder.WriteString(getHostname())
prompt_builder.WriteString(config.Prompt.HostnameSuffix)
}
if config.Prompt.DisplayPwd {
prompt_builder.WriteString(getPwd())
prompt_builder.WriteString(config.Prompt.PwdSuffix)
}
prompt_builder.WriteString(config.Prompt.PromptChar)
prompt_color := make_style(
RGBColorInput{
uint8(config.Prompt.Colors.Fg[0]),
uint8(config.Prompt.Colors.Fg[1]),
uint8(config.Prompt.Colors.Fg[2]), // This will of course panic if this number is > 255
},
RGBColorInput{
uint8(config.Prompt.Colors.Bg[0]),
uint8(config.Prompt.Colors.Bg[1]),
uint8(config.Prompt.Colors.Bg[2]),
})
git_prompt_color.Printf(git_prompt_builder.String())
prompt_color.Printf(prompt_builder.String())
}
func main() {
parsed_config, err := parseTomlFromFile("/home/swatson/Repos/go-pest/pest.cfg")
if err != nil {
fmt.Println("Couldn't parse TOML const!")
}
assemble_prompt(&parsed_config)
}