Compare commits
11 Commits
a1309af696
...
v0.2.3
| Author | SHA1 | Date | |
|---|---|---|---|
| 5697402942 | |||
| 9b66755bff | |||
| f32bbd2ff1 | |||
| 43e145a6ec | |||
| c887f2a0cc | |||
| 9f6dcac314 | |||
| 421e9b074e | |||
| 720a01140c | |||
| 9ced9ab5cb | |||
| 8ae28cb359 | |||
| d1a9f3f726 |
55
color.go
55
color.go
@@ -38,14 +38,14 @@ var possibleColors map[string]color = map[string]color{
|
|||||||
"GREEN": {"GREEN", colorData.New(colorData.FgGreen)},
|
"GREEN": {"GREEN", colorData.New(colorData.FgGreen)},
|
||||||
"YELLOW": {"YELLOW", colorData.New(colorData.FgYellow)},
|
"YELLOW": {"YELLOW", colorData.New(colorData.FgYellow)},
|
||||||
"BLUE": {"BLUE", colorData.New(colorData.FgBlue)},
|
"BLUE": {"BLUE", colorData.New(colorData.FgBlue)},
|
||||||
"MAGENTA": {"MAGENTA", colorData.New(38, 2, 254, 141, 255)},
|
"MAGENTA": {"MAGENTA", colorData.New(colorData.FgMagenta)},
|
||||||
"CYAN": {"CYAN", colorData.New(colorData.FgCyan)},
|
"CYAN": {"CYAN", colorData.New(colorData.FgCyan)},
|
||||||
"WHITE": {"WHITE", colorData.New(colorData.FgWhite)},
|
"WHITE": {"WHITE", colorData.New(colorData.FgWhite)},
|
||||||
"GRAY": {"GRAY", colorData.New(colorData.FgWhite, colorData.Faint)},
|
"GRAY": {"GRAY", colorData.New(colorData.FgWhite, colorData.Faint)},
|
||||||
// Last three numbers are RGB. Reference https://en.wikipedia.org/wiki/ANSI_escape_code for what the first two numbers mean.
|
// Last three numbers are RGB. Reference https://en.wikipedia.org/wiki/ANSI_escape_code for what the first two numbers mean.
|
||||||
"ORANGE": {"ORANGE", colorData.New(38, 2, 255, 153, 28)},
|
// "ORANGE": {"ORANGE", colorData.New(38, 2, 255, 153, 28)},
|
||||||
"DARKBLUE": {"DARKBLUE", colorData.New(38, 2, 0, 112, 255)},
|
// "DARKBLUE": {"DARKBLUE", colorData.New(38, 2, 0, 112, 255)},
|
||||||
"NONE": {"NONE", colorData.New()},
|
"NONE": {"NONE", colorData.New()},
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply the given color 'clr' to all units in 'units', within the indices
|
// Apply the given color 'clr' to all units in 'units', within the indices
|
||||||
@@ -95,9 +95,7 @@ func stringToRGB(rgbString string) (*RGB, error) {
|
|||||||
values := strings.Split(rgbString, " ")
|
values := strings.Split(rgbString, " ")
|
||||||
// There must be three space-separated strings.
|
// There must be three space-separated strings.
|
||||||
if len(values) != 5 {
|
if len(values) != 5 {
|
||||||
// TODO: Instead of ignoring these errors and returning a generic error (as I do in the
|
return nil, fmt.Errorf("Must be exactly five space-separated numbers per line")
|
||||||
// callee), wrap the error returned from this function, inside the error returned by the callee.
|
|
||||||
return nil, fmt.Errorf("Error parsing RGB five-tuple.")
|
|
||||||
}
|
}
|
||||||
// If any of the strings doesn't represent an integer (or is out of bounds), return an error.
|
// If any of the strings doesn't represent an integer (or is out of bounds), return an error.
|
||||||
// WARNING: LAZY CODE INCOMING
|
// WARNING: LAZY CODE INCOMING
|
||||||
@@ -105,43 +103,46 @@ func stringToRGB(rgbString string) (*RGB, error) {
|
|||||||
var err error
|
var err error
|
||||||
toReturn.sgr1, err = strconv.Atoi(values[0])
|
toReturn.sgr1, err = strconv.Atoi(values[0])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("Error parsing SGR1 integer: Invalid value.")
|
return nil, fmt.Errorf("Invalid value for first number (try 38 for default)")
|
||||||
}
|
}
|
||||||
if toReturn.sgr1 < 0 || toReturn.sgr1 > 107 { // Maximum value for SGR values
|
if toReturn.sgr1 < 0 || toReturn.sgr1 > 107 { // Maximum value for SGR values
|
||||||
return nil, fmt.Errorf("Error parsing SGR1 integer: Out-of-bounds.")
|
return nil, fmt.Errorf("First number out-of-bounds 0 to 107 (try 38 for default)")
|
||||||
}
|
}
|
||||||
toReturn.red, err = strconv.Atoi(values[1])
|
toReturn.red, err = strconv.Atoi(values[1])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("Error parsing RED integer: Invalid value.")
|
return nil, fmt.Errorf("Invalid value for RED Integer (number 2)")
|
||||||
}
|
}
|
||||||
if toReturn.red < -1 || toReturn.red > 255 {
|
if toReturn.red < -1 || toReturn.red > 255 {
|
||||||
return nil, fmt.Errorf("Error parsing RED integer: Out-of-bounds.")
|
return nil, fmt.Errorf("RED Integer (number 2) out-of-bounds")
|
||||||
}
|
}
|
||||||
toReturn.blue, err = strconv.Atoi(values[2])
|
|
||||||
|
toReturn.green, err = strconv.Atoi(values[2])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("Error parsing BLUE integer: Invalid value.")
|
return nil, fmt.Errorf("Invalid value for GREEN Integer (number 3)")
|
||||||
}
|
|
||||||
if toReturn.blue < -1 || toReturn.blue > 255 {
|
|
||||||
return nil, fmt.Errorf("Error parsing BLUE integer: Out-of-bounds.")
|
|
||||||
}
|
|
||||||
toReturn.green, err = strconv.Atoi(values[3])
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("Error parsing GREEN integer: Invalid value.")
|
|
||||||
}
|
}
|
||||||
if toReturn.green < -1 || toReturn.green > 255 {
|
if toReturn.green < -1 || toReturn.green > 255 {
|
||||||
return nil, fmt.Errorf("Error parsing GREEN integer: Out-of-bounds.")
|
return nil, fmt.Errorf("GREEN Integer (number 3) out-of-bounds")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
toReturn.blue, err = strconv.Atoi(values[3])
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("Invalid value for BLUE Integer (number 4)")
|
||||||
|
}
|
||||||
|
if toReturn.blue < -1 || toReturn.blue > 255 {
|
||||||
|
return nil, fmt.Errorf("BLUE Integer (number 4) out-of-bounds")
|
||||||
|
}
|
||||||
|
|
||||||
toReturn.sgr2, err = strconv.Atoi(values[4])
|
toReturn.sgr2, err = strconv.Atoi(values[4])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("Error parsing SGR2 integer: Invalid value.")
|
return nil, fmt.Errorf("Invalid value for last number (try 22 for default)")
|
||||||
}
|
}
|
||||||
if toReturn.sgr2 < 0 || toReturn.sgr2 > 107 {
|
if toReturn.sgr2 < 0 || toReturn.sgr2 > 107 { // Maximum value for SGR values
|
||||||
return nil, fmt.Errorf("Error parsing SGR2 integer: Out-of-bounds.")
|
return nil, fmt.Errorf("Last number out-of-bounds 0 to 107 (try 22 for default)")
|
||||||
}
|
}
|
||||||
|
|
||||||
if !(toReturn.red > 0 && toReturn.blue > 0 && toReturn.green > 0) &&
|
if !(toReturn.red > 0 && toReturn.blue > 0 && toReturn.green > 0) &&
|
||||||
!(toReturn.red == -1 && toReturn.green == -1 && toReturn.blue == -1) {
|
!(toReturn.red == -1 && toReturn.green == -1 && toReturn.blue == -1) {
|
||||||
return nil, fmt.Errorf("Error parsing color: All values must be positive or -1 for default terminal color.")
|
return nil, fmt.Errorf("RGB values must be positive or -1 for default terminal color")
|
||||||
}
|
}
|
||||||
return &toReturn, nil
|
return &toReturn, nil
|
||||||
}
|
}
|
||||||
@@ -157,7 +158,7 @@ func stringToRGB(rgbString string) (*RGB, error) {
|
|||||||
func loadColorsFromFile(filepath string) error {
|
func loadColorsFromFile(filepath string) error {
|
||||||
data, err := os.ReadFile(filepath)
|
data, err := os.ReadFile(filepath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
return err
|
||||||
}
|
}
|
||||||
// Read color config file into a MapSlice
|
// Read color config file into a MapSlice
|
||||||
tempMapSlice := yaml.MapSlice{}
|
tempMapSlice := yaml.MapSlice{}
|
||||||
@@ -171,7 +172,7 @@ func loadColorsFromFile(filepath string) error {
|
|||||||
}
|
}
|
||||||
var rgb *RGB
|
var rgb *RGB
|
||||||
if rgb, err = stringToRGB(item.Value.(string)); err != nil {
|
if rgb, err = stringToRGB(item.Value.(string)); err != nil {
|
||||||
return fmt.Errorf("Invalid RGB trio: %s", item.Value.(string))
|
return fmt.Errorf("Error parsing color line %s:\t%v", item.Value.(string), err)
|
||||||
}
|
}
|
||||||
// If we haven't returned an error yet, the color must be valid.
|
// If we haven't returned an error yet, the color must be valid.
|
||||||
// Add it to the map. colorData.New() expects values of type colorData.Attribute,
|
// Add it to the map. colorData.New() expects values of type colorData.Attribute,
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package main
|
|||||||
import (
|
import (
|
||||||
"embed"
|
"embed"
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
"io/fs"
|
"io/fs"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
@@ -15,7 +16,7 @@ import (
|
|||||||
"gopkg.in/yaml.v2"
|
"gopkg.in/yaml.v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
//go:embed config
|
//go:embed config/*
|
||||||
var storedConfigs embed.FS // Embed the folder containing config files
|
var storedConfigs embed.FS // Embed the folder containing config files
|
||||||
|
|
||||||
// runningOnWindows: At the moment this function isn't used. When Window support is added,
|
// runningOnWindows: At the moment this function isn't used. When Window support is added,
|
||||||
@@ -88,7 +89,10 @@ func loadConfig(configFilename string) (stack.Stack[regColor], error) {
|
|||||||
// returned.
|
// returned.
|
||||||
regColorStack := stack.NewStack[regColor](len(strings.Split(string(configFile), "\n"))) // The stack will have the same size as the number of lines in the file
|
regColorStack := stack.NewStack[regColor](len(strings.Split(string(configFile), "\n"))) // The stack will have the same size as the number of lines in the file
|
||||||
for _, item := range tempMapSlice {
|
for _, item := range tempMapSlice {
|
||||||
re := regex.MustCompile(item.Key.(string), regex.RE_MULTILINE, regex.RE_SINGLE_LINE)
|
re, err := regex.Compile(item.Key.(string), regex.RE_MULTILINE, regex.RE_SINGLE_LINE)
|
||||||
|
if err != nil {
|
||||||
|
return *stack.NewStack[regColor](0), fmt.Errorf("%v: '%s'", err, item.Key.(string))
|
||||||
|
}
|
||||||
clr, err := newColor(item.Value.(string))
|
clr, err := newColor(item.Value.(string))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return *stack.NewStack[regColor](0), err
|
return *stack.NewStack[regColor](0), err
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
# The first and last fields are SGR values, used to control things
|
# The first and last fields are SGR values, used to control things
|
||||||
# like bold and italic text. If you're unsure what to put, use '38'
|
# like bold and italic text. If you're unsure what to put, use '38'
|
||||||
# for the first one and '22' for the last one, for normal text.
|
# for the first one and '22' for the last one, for normal text.
|
||||||
# The last three values are R G B values.
|
# The middle three values are R G B values.
|
||||||
PINK: 38 244 211 244 22
|
PINK: 38 244 211 244 22
|
||||||
BOLD_WHITE: 38 -1 -1 -1 1
|
BOLD_WHITE: 38 -1 -1 -1 1
|
||||||
ITALIC_WHITE: 38 -1 -1 -1 3
|
ITALIC_WHITE: 38 -1 -1 -1 3
|
||||||
|
UNDERLINE_WHITE: 38 -1 -1 -1 4
|
||||||
|
DARKBLUE: 38 1 1 139 22
|
||||||
|
|||||||
@@ -18,11 +18,9 @@
|
|||||||
'(&&)|(\|\|)': CYAN
|
'(&&)|(\|\|)': CYAN
|
||||||
# Keywords
|
# Keywords
|
||||||
'\b(if|else|for|range|go|func|return|break|continue)\b': CYAN
|
'\b(if|else|for|range|go|func|return|break|continue)\b': CYAN
|
||||||
'\b(import|var|const|type|struct)\b': CYAN
|
'\b(package|import|var|const|type|struct)\b': CYAN
|
||||||
# Built-in Functions
|
# Built-in Functions
|
||||||
'\b(panic|len)\b': DARKBLUE
|
'\b(panic|len)\b': GREEN
|
||||||
# Functions from packages (package name and function name separated by dot)
|
|
||||||
'\b(\w*\.\w*)\b': DARKBLUE
|
|
||||||
# Data Types
|
# Data Types
|
||||||
'\b(bool|byte|rune|string|interface|map|chan)\b': YELLOW
|
'\b(bool|byte|rune|string|interface|map|chan)\b': YELLOW
|
||||||
'\b(u?int)(8|16|32|64)?\b': YELLOW
|
'\b(u?int)(8|16|32|64)?\b': YELLOW
|
||||||
|
|||||||
@@ -1,13 +1,21 @@
|
|||||||
# Priority decreases going downward ie. If two regexes match the same piece of
|
# Priority decreases going downward ie. If two regexes match the same piece of
|
||||||
# text, the one defined earlier will take precedence over the one defined later.
|
# text, the one defined earlier will take precedence over the one defined later.
|
||||||
# Headings
|
# Headings
|
||||||
'##?#?#?#?#?.*': MAGENTA
|
'^#{1,6}.*?$': MAGENTA
|
||||||
|
|
||||||
|
# Link text
|
||||||
|
'\[.*?\](?=\(.*?\))': UNDERLINE_WHITE
|
||||||
|
|
||||||
|
# Link URL
|
||||||
|
'https?://\w+\.\w+.*?(?=\))': RED
|
||||||
|
|
||||||
# Code blocks
|
# Code blocks
|
||||||
'```(.|\n)+?```': YELLOW
|
'```(.|\n)+?```': YELLOW
|
||||||
|
|
||||||
# Bold text
|
# Bold text
|
||||||
'\b__[^_]+?__\b': BOLD_WHITE
|
'\b__[^_]+?__\b': BOLD_WHITE
|
||||||
|
'\*\*[^*]+?\*\*': BOLD_WHITE
|
||||||
|
|
||||||
# Italic text
|
# Italic text
|
||||||
'\b_[^_]+?_\b': ITALIC_WHITE
|
'\b_[^_]+?_\b': ITALIC_WHITE
|
||||||
|
'\*[^*\n]+?\*': ITALIC_WHITE
|
||||||
|
|||||||
4
main.go
4
main.go
@@ -79,7 +79,7 @@ func main() {
|
|||||||
// Check if config exists. If it doesn't, generate the config files.
|
// Check if config exists. If it doesn't, generate the config files.
|
||||||
userHomeDir, err := os.UserHomeDir() // Get current user's home directory, to construct config path
|
userHomeDir, err := os.UserHomeDir() // Get current user's home directory, to construct config path
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
printErrAndExit("Unable to retrieve user home directory")
|
||||||
}
|
}
|
||||||
configPath := filepath.Join(userHomeDir + "/.config/ccat/")
|
configPath := filepath.Join(userHomeDir + "/.config/ccat/")
|
||||||
if _, err := os.Stat(configPath); os.IsNotExist(err) {
|
if _, err := os.Stat(configPath); os.IsNotExist(err) {
|
||||||
@@ -107,7 +107,7 @@ func main() {
|
|||||||
// the program.
|
// the program.
|
||||||
finfo, err := os.Stat(fileName)
|
finfo, err := os.Stat(fileName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
printErrAndExit("Unable to read file")
|
||||||
}
|
}
|
||||||
if finfo.Size() == 0 {
|
if finfo.Size() == 0 {
|
||||||
os.Exit(0)
|
os.Exit(0)
|
||||||
|
|||||||
Reference in New Issue
Block a user