216 lines
5.3 KiB
Go
216 lines
5.3 KiB
Go
package config
|
|
|
|
import (
|
|
"errors"
|
|
"regexp"
|
|
"strconv"
|
|
"strings"
|
|
|
|
"github.com/zyedidia/tcell/v2"
|
|
)
|
|
|
|
// Micro's default style
|
|
var DefStyle tcell.Style = tcell.StyleDefault
|
|
|
|
// The current colorscheme
|
|
var Colorscheme map[string]tcell.Style
|
|
|
|
// GetColor takes in a syntax group and returns the colorscheme's style for that group
|
|
func GetColor(color string) tcell.Style {
|
|
st := DefStyle
|
|
if color == "" {
|
|
return st
|
|
}
|
|
groups := strings.Split(color, ".")
|
|
if len(groups) > 1 {
|
|
curGroup := ""
|
|
for i, g := range groups {
|
|
if i != 0 {
|
|
curGroup += "."
|
|
}
|
|
curGroup += g
|
|
if style, ok := Colorscheme[curGroup]; ok {
|
|
st = style
|
|
}
|
|
}
|
|
} else if style, ok := Colorscheme[color]; ok {
|
|
st = style
|
|
} else {
|
|
st = StringToStyle(color)
|
|
}
|
|
|
|
return st
|
|
}
|
|
|
|
// ColorschemeExists checks if a given colorscheme exists
|
|
func ColorschemeExists(colorschemeName string) bool {
|
|
return FindRuntimeFile(RTColorscheme, colorschemeName) != nil
|
|
}
|
|
|
|
// InitColorscheme picks and initializes the colorscheme when micro starts
|
|
func InitColorscheme() error {
|
|
Colorscheme = make(map[string]tcell.Style)
|
|
DefStyle = tcell.StyleDefault
|
|
|
|
return LoadDefaultColorscheme()
|
|
}
|
|
|
|
// LoadDefaultColorscheme loads the default colorscheme from $(ConfigDir)/colorschemes
|
|
func LoadDefaultColorscheme() error {
|
|
return LoadColorscheme(GlobalSettings["colorscheme"].(string))
|
|
}
|
|
|
|
// LoadColorscheme loads the given colorscheme from a directory
|
|
func LoadColorscheme(colorschemeName string) error {
|
|
file := FindRuntimeFile(RTColorscheme, colorschemeName)
|
|
if file == nil {
|
|
return errors.New(colorschemeName + " is not a valid colorscheme")
|
|
}
|
|
if data, err := file.Data(); err != nil {
|
|
return errors.New("Error loading colorscheme: " + err.Error())
|
|
} else {
|
|
Colorscheme, err = ParseColorscheme(string(data))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// ParseColorscheme parses the text definition for a colorscheme and returns the corresponding object
|
|
// Colorschemes are made up of color-link statements linking a color group to a list of colors
|
|
// For example, color-link keyword (blue,red) makes all keywords have a blue foreground and
|
|
// red background
|
|
func ParseColorscheme(text string) (map[string]tcell.Style, error) {
|
|
var err error
|
|
parser := regexp.MustCompile(`color-link\s+(\S*)\s+"(.*)"`)
|
|
|
|
lines := strings.Split(text, "\n")
|
|
|
|
c := make(map[string]tcell.Style)
|
|
|
|
for _, line := range lines {
|
|
if strings.TrimSpace(line) == "" ||
|
|
strings.TrimSpace(line)[0] == '#' {
|
|
// Ignore this line
|
|
continue
|
|
}
|
|
|
|
matches := parser.FindSubmatch([]byte(line))
|
|
if len(matches) == 3 {
|
|
link := string(matches[1])
|
|
colors := string(matches[2])
|
|
|
|
style := StringToStyle(colors)
|
|
c[link] = style
|
|
|
|
if link == "default" {
|
|
DefStyle = style
|
|
}
|
|
} else {
|
|
err = errors.New("Color-link statement is not valid: " + line)
|
|
}
|
|
}
|
|
|
|
return c, err
|
|
}
|
|
|
|
// StringToStyle returns a style from a string
|
|
// The strings must be in the format "extra foregroundcolor,backgroundcolor"
|
|
// The 'extra' can be bold, reverse, italic or underline
|
|
func StringToStyle(str string) tcell.Style {
|
|
var fg, bg string
|
|
spaceSplit := strings.Split(str, " ")
|
|
split := strings.Split(spaceSplit[len(spaceSplit)-1], ",")
|
|
if len(split) > 1 {
|
|
fg, bg = split[0], split[1]
|
|
} else {
|
|
fg = split[0]
|
|
}
|
|
fg = strings.TrimSpace(fg)
|
|
bg = strings.TrimSpace(bg)
|
|
|
|
var fgColor, bgColor tcell.Color
|
|
if fg == "" {
|
|
fgColor, _, _ = DefStyle.Decompose()
|
|
} else {
|
|
fgColor = StringToColor(fg)
|
|
}
|
|
if bg == "" {
|
|
_, bgColor, _ = DefStyle.Decompose()
|
|
} else {
|
|
bgColor = StringToColor(bg)
|
|
}
|
|
|
|
style := DefStyle.Foreground(fgColor).Background(bgColor)
|
|
if strings.Contains(str, "bold") {
|
|
style = style.Bold(true)
|
|
}
|
|
if strings.Contains(str, "italic") {
|
|
style = style.Italic(true)
|
|
}
|
|
if strings.Contains(str, "reverse") {
|
|
style = style.Reverse(true)
|
|
}
|
|
if strings.Contains(str, "underline") {
|
|
style = style.Underline(true)
|
|
}
|
|
return style
|
|
}
|
|
|
|
// StringToColor returns a tcell color from a string representation of a color
|
|
// We accept either bright... or light... to mean the brighter version of a color
|
|
func StringToColor(str string) tcell.Color {
|
|
switch str {
|
|
case "black":
|
|
return tcell.ColorBlack
|
|
case "red":
|
|
return tcell.ColorMaroon
|
|
case "green":
|
|
return tcell.ColorGreen
|
|
case "yellow":
|
|
return tcell.ColorOlive
|
|
case "blue":
|
|
return tcell.ColorNavy
|
|
case "magenta":
|
|
return tcell.ColorPurple
|
|
case "cyan":
|
|
return tcell.ColorTeal
|
|
case "white":
|
|
return tcell.ColorSilver
|
|
case "brightblack", "lightblack":
|
|
return tcell.ColorGray
|
|
case "brightred", "lightred":
|
|
return tcell.ColorRed
|
|
case "brightgreen", "lightgreen":
|
|
return tcell.ColorLime
|
|
case "brightyellow", "lightyellow":
|
|
return tcell.ColorYellow
|
|
case "brightblue", "lightblue":
|
|
return tcell.ColorBlue
|
|
case "brightmagenta", "lightmagenta":
|
|
return tcell.ColorFuchsia
|
|
case "brightcyan", "lightcyan":
|
|
return tcell.ColorAqua
|
|
case "brightwhite", "lightwhite":
|
|
return tcell.ColorWhite
|
|
case "default":
|
|
return tcell.ColorDefault
|
|
default:
|
|
// Check if this is a 256 color
|
|
if num, err := strconv.Atoi(str); err == nil {
|
|
return GetColor256(num)
|
|
}
|
|
// Probably a truecolor hex value
|
|
return tcell.GetColor(str)
|
|
}
|
|
}
|
|
|
|
// GetColor256 returns the tcell color for a number between 0 and 255
|
|
func GetColor256(color int) tcell.Color {
|
|
if color == 0 {
|
|
return tcell.ColorDefault
|
|
}
|
|
return tcell.PaletteColor(color)
|
|
}
|