я навайбкодил этот крутой коммит!
This commit is contained in:
parent
43ef696c72
commit
4946fd1695
1
.gitignore
vendored
1
.gitignore
vendored
@ -12,3 +12,4 @@ result/
|
|||||||
/.idea/go.imports.xml
|
/.idea/go.imports.xml
|
||||||
/.idea/vcs.xml
|
/.idea/vcs.xml
|
||||||
/.idea/workspace.xml
|
/.idea/workspace.xml
|
||||||
|
/goGoFetch
|
||||||
|
|||||||
@ -22,11 +22,18 @@ to show custom image and set custom width:
|
|||||||
```bash
|
```bash
|
||||||
gogofetch -l path -w 250
|
gogofetch -l path -w 250
|
||||||
```
|
```
|
||||||
|
to place logo on the left (default) or right:
|
||||||
|
```bash
|
||||||
|
gogofetch -p left
|
||||||
|
gogofetch -p right
|
||||||
|
```
|
||||||
to show help message:
|
to show help message:
|
||||||
```bash
|
```bash
|
||||||
gogofetch -h
|
gogofetch -h
|
||||||
```
|
```
|
||||||
|
|
||||||
|
config file is created at `~/.config/gogofetch/config.toml`, all parameters are described in config file.
|
||||||
|
|
||||||
# NixOS
|
# NixOS
|
||||||
credits to melvi for flake
|
credits to melvi for flake
|
||||||
|
|
||||||
|
|||||||
BIN
logos/arch.png
(Stored with Git LFS)
BIN
logos/arch.png
(Stored with Git LFS)
Binary file not shown.
BIN
logos/debian.png
(Stored with Git LFS)
BIN
logos/debian.png
(Stored with Git LFS)
Binary file not shown.
183
main.go
183
main.go
@ -13,6 +13,7 @@ import (
|
|||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
"unicode/utf8"
|
||||||
|
|
||||||
"github.com/BurntSushi/toml"
|
"github.com/BurntSushi/toml"
|
||||||
)
|
)
|
||||||
@ -24,10 +25,63 @@ const (
|
|||||||
|
|
||||||
var dist string
|
var dist string
|
||||||
|
|
||||||
|
var ansiEscapeRe = regexp.MustCompile(`\x1b\[[0-9;?]*[ -/]*[@-~]`)
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
Ascii bool `toml:"ascii"`
|
Ascii bool `toml:"ascii"`
|
||||||
Layout []string `toml:"layout"`
|
Layout []string `toml:"layout"`
|
||||||
CustomLogo string `toml:"custom_logo"`
|
CustomLogo string `toml:"custom_logo"`
|
||||||
|
LogoPosition string `toml:"logo_position"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendMissingConfigKeys(pathConf string, md toml.MetaData) error {
|
||||||
|
var missing []string
|
||||||
|
|
||||||
|
if !md.IsDefined("ascii") {
|
||||||
|
missing = append(missing, "# Set this to \"true\" if you like ascii more than images\nascii = false")
|
||||||
|
}
|
||||||
|
|
||||||
|
if !md.IsDefined("layout") {
|
||||||
|
missing = append(missing, `# Stats layout: reorder or remove items to customize your fetch
|
||||||
|
# Available: "dist", "host", "cpu", "kernel", "ram", "gpu", "de/wm", "pkgs", "shell", "terminal", "uptime"
|
||||||
|
layout = [
|
||||||
|
"dist",
|
||||||
|
"host",
|
||||||
|
"cpu",
|
||||||
|
"kernel",
|
||||||
|
"ram",
|
||||||
|
"gpu",
|
||||||
|
"de/wm",
|
||||||
|
"pkgs",
|
||||||
|
"shell",
|
||||||
|
"terminal",
|
||||||
|
"uptime",
|
||||||
|
]`)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !md.IsDefined("custom_logo") {
|
||||||
|
missing = append(missing, "# Absolute path to a custom image or .txt file. Leave empty to use auto-detection.\ncustom_logo = \"\"")
|
||||||
|
}
|
||||||
|
|
||||||
|
if !md.IsDefined("logo_position") {
|
||||||
|
missing = append(missing, "# Position of the logo block relative to the stats block: \"left\" or \"right\".\nlogo_position = \"left\"")
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(missing) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
f, err := os.OpenFile(pathConf, os.O_APPEND|os.O_WRONLY, 0644)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer func(f *os.File) {
|
||||||
|
_ = f.Close()
|
||||||
|
}(f)
|
||||||
|
|
||||||
|
block := "\n# Added automatically after update\n\n" + strings.Join(missing, "\n\n") + "\n"
|
||||||
|
_, err = f.WriteString(block)
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func getConfigPath() (string, error) {
|
func getConfigPath() (string, error) {
|
||||||
@ -76,6 +130,9 @@ layout = [
|
|||||||
|
|
||||||
# Absolute path to a custom image or .txt file. Leave empty to use auto-detection.
|
# Absolute path to a custom image or .txt file. Leave empty to use auto-detection.
|
||||||
custom_logo = ""
|
custom_logo = ""
|
||||||
|
|
||||||
|
# Position of the logo block relative to the stats block: "left" or "right".
|
||||||
|
logo_position = "left"
|
||||||
`)
|
`)
|
||||||
err := os.WriteFile(pathConf, defaultConfig, 0644)
|
err := os.WriteFile(pathConf, defaultConfig, 0644)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -83,8 +140,18 @@ custom_logo = ""
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err := toml.DecodeFile(pathConf, &conf); err != nil {
|
md, err := toml.DecodeFile(pathConf, &conf)
|
||||||
|
if err != nil {
|
||||||
fmt.Printf("Error loading config at %s: %v\n", pathConf, err)
|
fmt.Printf("Error loading config at %s: %v\n", pathConf, err)
|
||||||
|
return conf, pathConf
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := appendMissingConfigKeys(pathConf, md); err != nil {
|
||||||
|
fmt.Printf("Warning: Could not update config at %s: %v\n", pathConf, err)
|
||||||
|
} else {
|
||||||
|
if _, err := toml.DecodeFile(pathConf, &conf); err != nil {
|
||||||
|
fmt.Printf("Error reloading updated config at %s: %v\n", pathConf, err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return conf, pathConf
|
return conf, pathConf
|
||||||
@ -325,13 +392,88 @@ func printAsciiLogo(path string) string {
|
|||||||
return string(content)
|
return string(content)
|
||||||
}
|
}
|
||||||
|
|
||||||
func printLogoChafa(path string, width uint) {
|
func renderLogoChafa(path string, width uint) []string {
|
||||||
cols := width / 8
|
cols := width / 8
|
||||||
|
if cols == 0 {
|
||||||
|
cols = 1
|
||||||
|
}
|
||||||
sizeArg := fmt.Sprintf("--size=%dx%d", cols, cols/2)
|
sizeArg := fmt.Sprintf("--size=%dx%d", cols, cols/2)
|
||||||
cmd := exec.Command("chafa", path, sizeArg, "--symbols=half")
|
cmd := exec.Command("chafa", path, "--format", "symbols", sizeArg, "--symbols=half")
|
||||||
cmd.Stdout = os.Stdout
|
out, err := cmd.Output()
|
||||||
if err := cmd.Run(); err != nil {
|
if err != nil {
|
||||||
fmt.Println("Chafa error:", err)
|
return []string{fmt.Sprintf("Chafa error: %v", err)}
|
||||||
|
}
|
||||||
|
return splitLines(string(out))
|
||||||
|
}
|
||||||
|
|
||||||
|
func normalizeLogoPosition(pos string) string {
|
||||||
|
value := strings.ToLower(strings.TrimSpace(pos))
|
||||||
|
if value == "left" || value == "right" {
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
return "right"
|
||||||
|
}
|
||||||
|
|
||||||
|
func splitLines(content string) []string {
|
||||||
|
normalized := strings.ReplaceAll(content, "\r\n", "\n")
|
||||||
|
normalized = strings.TrimRight(normalized, "\n")
|
||||||
|
if normalized == "" {
|
||||||
|
return []string{}
|
||||||
|
}
|
||||||
|
return strings.Split(normalized, "\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
func maxLineLen(lines []string) int {
|
||||||
|
maxLen := 0
|
||||||
|
for _, line := range lines {
|
||||||
|
lineLen := visibleWidth(line)
|
||||||
|
if lineLen > maxLen {
|
||||||
|
maxLen = lineLen
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return maxLen
|
||||||
|
}
|
||||||
|
|
||||||
|
func visibleWidth(line string) int {
|
||||||
|
stripped := ansiEscapeRe.ReplaceAllString(line, "")
|
||||||
|
return utf8.RuneCountInString(stripped)
|
||||||
|
}
|
||||||
|
|
||||||
|
func padRightVisible(line string, targetWidth int) string {
|
||||||
|
pad := targetWidth - visibleWidth(line)
|
||||||
|
if pad <= 0 {
|
||||||
|
return line
|
||||||
|
}
|
||||||
|
return line + strings.Repeat(" ", pad)
|
||||||
|
}
|
||||||
|
|
||||||
|
func renderSideBySide(statsLines []string, logoLines []string, position string) {
|
||||||
|
const gap = " "
|
||||||
|
statsWidth := maxLineLen(statsLines)
|
||||||
|
logoWidth := maxLineLen(logoLines)
|
||||||
|
|
||||||
|
lineCount := len(statsLines)
|
||||||
|
if len(logoLines) > lineCount {
|
||||||
|
lineCount = len(logoLines)
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < lineCount; i++ {
|
||||||
|
stats := ""
|
||||||
|
logo := ""
|
||||||
|
|
||||||
|
if i < len(statsLines) {
|
||||||
|
stats = statsLines[i]
|
||||||
|
}
|
||||||
|
if i < len(logoLines) {
|
||||||
|
logo = logoLines[i]
|
||||||
|
}
|
||||||
|
|
||||||
|
if position == "left" {
|
||||||
|
fmt.Printf("%s%s%s\n", padRightVisible(logo, logoWidth), gap, stats)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("%s%s%s\n", padRightVisible(stats, statsWidth), gap, logo)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -414,9 +556,11 @@ func main() {
|
|||||||
defaultLogo = getLogo(dist)
|
defaultLogo = getLogo(dist)
|
||||||
}
|
}
|
||||||
|
|
||||||
width := flag.Int("w", 200, "Logo width in lines")
|
width := flag.Int("w", 190, "Logo width in lines")
|
||||||
logoPath := flag.String("l", getAbsLogoPath(defaultLogo), "Path to the logo")
|
logoPath := flag.String("l", getAbsLogoPath(defaultLogo), "Path to the logo")
|
||||||
|
logoPos := flag.String("p", normalizeLogoPosition(conf.LogoPosition), "Logo position: left or right")
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
|
position := normalizeLogoPosition(*logoPos)
|
||||||
|
|
||||||
type Info struct {
|
type Info struct {
|
||||||
Label string
|
Label string
|
||||||
@ -451,18 +595,21 @@ func main() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err := os.Stat(*logoPath); err == nil {
|
var statsLines []string
|
||||||
if conf.Ascii {
|
for _, info := range stats {
|
||||||
fmt.Print(printAsciiLogo(*logoPath))
|
statsLines = append(statsLines, fmt.Sprintf("~ %s%s%s: %s", Blue, info.Label, Reset, info.Value))
|
||||||
fmt.Println()
|
|
||||||
} else {
|
|
||||||
printLogoChafa(*logoPath, uint(*width))
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
fmt.Printf("Logo not found at: %s\n", *logoPath)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, info := range stats {
|
var logoLines []string
|
||||||
fmt.Printf("~ %s%s%s: %s\n", Blue, info.Label, Reset, info.Value)
|
if _, err := os.Stat(*logoPath); err == nil {
|
||||||
|
if conf.Ascii {
|
||||||
|
logoLines = splitLines(printAsciiLogo(*logoPath))
|
||||||
|
} else {
|
||||||
|
logoLines = renderLogoChafa(*logoPath, uint(*width))
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
logoLines = []string{fmt.Sprintf("Logo not found at: %s", *logoPath)}
|
||||||
|
}
|
||||||
|
|
||||||
|
renderSideBySide(statsLines, logoLines, position)
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user