feat: syntax highlighting powered by chroma.

This is sick! It is not perfect, highlight groups would be cool, but for
now this works!
This commit is contained in:
Hayden Hargreaves 2026-03-16 22:48:57 -07:00
parent c70cbeaedf
commit 76fa55440e
12 changed files with 633 additions and 76 deletions

View File

@ -4,12 +4,17 @@ import (
"os"
"git.gophernest.net/azpect/TextEditor/internal/program"
"git.gophernest.net/azpect/TextEditor/internal/theme"
tea "github.com/charmbracelet/bubbletea"
)
// main: Entry point for the Gim text editor. Creates a buffer and window,
// initializes the editor model, and runs the BubbleTea TUI program.
func main() {
if err := theme.RegisterAll(); err != nil {
panic(err)
}
// <exe> <filename>
args := os.Args[1:]

2
go.mod
View File

@ -3,6 +3,7 @@ module git.gophernest.net/azpect/TextEditor
go 1.25.5
require (
github.com/alecthomas/chroma/v2 v2.23.1
github.com/charmbracelet/bubbletea v1.3.10
github.com/charmbracelet/lipgloss v1.1.0
github.com/charmbracelet/x/exp/teatest v0.0.0-20260209132835-6b065b8ba62c
@ -19,6 +20,7 @@ require (
github.com/clipperhouse/displaywidth v0.9.0 // indirect
github.com/clipperhouse/stringish v0.1.1 // indirect
github.com/clipperhouse/uax29/v2 v2.5.0 // indirect
github.com/dlclark/regexp2 v1.11.5 // indirect
github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f // indirect
github.com/lucasb-eyer/go-colorful v1.3.0 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect

10
go.sum
View File

@ -1,3 +1,9 @@
github.com/alecthomas/assert/v2 v2.11.0 h1:2Q9r3ki8+JYXvGsDyBXwH3LcJ+WK5D0gc5E8vS6K3D0=
github.com/alecthomas/assert/v2 v2.11.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k=
github.com/alecthomas/chroma/v2 v2.23.1 h1:nv2AVZdTyClGbVQkIzlDm/rnhk1E9bU9nXwmZ/Vk/iY=
github.com/alecthomas/chroma/v2 v2.23.1/go.mod h1:NqVhfBR0lte5Ouh3DcthuUCTUpDC9cxBOfyMbMQPs3o=
github.com/alecthomas/repr v0.5.2 h1:SU73FTI9D1P5UNtvseffFSGmdNci/O6RsqzeXJtP0Qs=
github.com/alecthomas/repr v0.5.2/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4=
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.3.1 h1:LV+qyBQ2pqe0u42ZsUEtPiCaUoqgA9gYRDs3vj1nolY=
@ -24,8 +30,12 @@ github.com/clipperhouse/stringish v0.1.1 h1:+NSqMOr3GR6k1FdRhhnXrLfztGzuG+VuFDfa
github.com/clipperhouse/stringish v0.1.1/go.mod h1:v/WhFtE1q0ovMta2+m+UbpZ+2/HEXNWYXQgCt4hdOzA=
github.com/clipperhouse/uax29/v2 v2.5.0 h1:x7T0T4eTHDONxFJsL94uKNKPHrclyFI0lm7+w94cO8U=
github.com/clipperhouse/uax29/v2 v2.5.0/go.mod h1:Wn1g7MK6OoeDT0vL+Q0SQLDz/KpfsVRgg6W7ihQeh4g=
github.com/dlclark/regexp2 v1.11.5 h1:Q/sSnsKerHeCkc/jSTNq1oCm7KiVgUMZRDUoRu0JQZQ=
github.com/dlclark/regexp2 v1.11.5/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/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM=
github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg=
github.com/lucasb-eyer/go-colorful v1.3.0 h1:2/yBRLdWBZKrf7gB40FoiKfAWYQ0lqNcbuQwVHXptag=
github.com/lucasb-eyer/go-colorful v1.3.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=

View File

@ -4,13 +4,86 @@ import (
"git.gophernest.net/azpect/TextEditor/internal/core"
"git.gophernest.net/azpect/TextEditor/internal/input"
"git.gophernest.net/azpect/TextEditor/internal/style"
"github.com/alecthomas/chroma/v2/styles"
)
type ModelBuilder struct {
model Model
}
// RPGLE
// abap
// algol
// algol_nu
// arduino
// ashen
// aura-theme-dark
// aura-theme-dark-soft
// autumn
// average
// base16-snazzy
// borland
// bw
// catppuccin-frappe
// catppuccin-latte
// catppuccin-macchiato
// catppuccin-mocha
// colorful
// doom-one
// doom-one2
// dracula
// emacs
// evergarden
// friendly
// fruity
// github
// github-dark
// gruvbox
// gruvbox-light
// hr_high_contrast
// hrdark
// igor
// lovelace
// manni
// modus-operandi
// modus-vivendi
// monokai
// monokailight
// murphy
// native
// nord
// nordic
// onedark
// onesenterprise
// paraiso-dark
// paraiso-light
// pastie
// perldoc
// pygments
// rainbow_dash
// rose-pine
// rose-pine-dawn
// rose-pine-moon
// rrt
// solarized-dark
// solarized-dark256
// solarized-light
// swapoff
// tango
// tokyonight-day
// tokyonight-moon
// tokyonight-night
// tokyonight-storm
// trac
// vim
// vs
// vulcan
// witchhazel
// xcode
// xcode-dark
func NewModelBuilder() *ModelBuilder {
chromaStyle := styles.Get("kanagawa-wave")
return &ModelBuilder{
model: Model{
buffers: []*core.Buffer{},
@ -28,7 +101,7 @@ func NewModelBuilder() *ModelBuilder {
commandOutput: nil,
settings: core.NewDefaultSettings(),
registers: core.DefaultRegisters(),
styles: style.DefaultStyles(),
styles: style.ChromaStyles(chromaStyle),
},
}
}

View File

@ -6,6 +6,8 @@ import (
"git.gophernest.net/azpect/TextEditor/internal/core"
"git.gophernest.net/azpect/TextEditor/internal/style"
"github.com/alecthomas/chroma/v2"
"github.com/alecthomas/chroma/v2/lexers"
"github.com/charmbracelet/lipgloss"
)
@ -49,17 +51,25 @@ func viewWindow(w *core.Window, styles style.Styles, options core.WinOptions, mo
start := w.ScrollY
end := w.ScrollY + w.ViewportHeight()
// Chroma stuff
name := strings.ReplaceAll(buf.Filetype, ".", "")
lexer := lexers.Get(name)
lexer = chroma.Coalesce(lexer) // Merge tokens together
// Draw buffer lines
for lineNum := start; lineNum < end; lineNum++ {
if lineNum < buf.LineCount() {
line := drawLine(w, styles, options, mode, buf.Line(lineNum), lineNum)
styleMap := styles.MakeStyleMap(lexer, buf.Line(lineNum))
line := drawLine(w, styles, options, mode, buf.Line(lineNum), lineNum, styleMap)
view.WriteString(line)
} else {
view.WriteString(strings.Repeat(styles.BackgroundStyle.Render(" "), w.Width))
}
view.WriteRune('\n')
}
// Draw status line
statusBar := drawStatusBar(w, mode)
statusBar := drawStatusBar(w, mode, styles)
view.WriteString(statusBar + "\n")
return view.String()
@ -67,13 +77,9 @@ func viewWindow(w *core.Window, styles style.Styles, options core.WinOptions, mo
// drawLine: Renders a single line with syntax highlighting, cursor, and visual selection.
// Handles gutter, cursor rendering, and visual mode highlighting.
func drawLine(w *core.Window, styles style.Styles, options core.WinOptions, mode core.Mode, line string, lineNumber int) string {
runes := []rune(line)
curStyle := styles.CursorStyle(mode)
visStyle := styles.VisualHighlight
func drawLine(w *core.Window, styles style.Styles, options core.WinOptions, mode core.Mode, line string, lineNumber int, styleMap []lipgloss.Style) string {
var view strings.Builder
runes := []rune(line)
// Draw gutter first
gutter := drawGutter(w, styles, options, lineNumber)
@ -84,24 +90,31 @@ func drawLine(w *core.Window, styles style.Styles, options core.WinOptions, mode
// Current char is cursor
if col == w.Cursor.Col && lineNumber == w.Cursor.Line {
if col < len(runes) {
view.WriteString(curStyle.Render(string(runes[col])))
cur := styles.CursorStyle(mode, styleMap[col])
view.WriteString(cur.Render(string(runes[col])))
} else {
view.WriteString(curStyle.Render(" "))
view.WriteString(styles.DefaultCursorStyle(mode).Render(" "))
}
// Not cursor, but not end
} else if col < len(runes) {
s := styleMap[col]
if mode.IsVisualMode() && posInsideSelection(w, mode, col, lineNumber) {
view.WriteString(visStyle.Render(string(runes[col])))
vis := styles.VisualHighlightWithTextColor(s)
view.WriteString(vis.Render(string(runes[col])))
} else {
view.WriteRune(runes[col])
view.WriteString(s.Render(string(runes[col])))
}
// Allow highlight on blank lines or chars
} else if mode.IsVisualMode() && posInsideSelection(w, mode, col, lineNumber) {
view.WriteString(visStyle.Render(" "))
view.WriteString(styles.VisualHighlight.Render(" "))
}
}
// Color the overflow
dif := w.Width - lipgloss.Width(line)
view.WriteString(strings.Repeat(styles.BackgroundStyle.Render(" "), dif))
return view.String()
}
@ -153,9 +166,9 @@ func drawGutter(w *core.Window, styles style.Styles, options core.WinOptions, cu
// drawStatusBar: Renders the status bar with mode and cursor position,
// padding the middle with spaces to fill the terminal width.
func drawStatusBar(w *core.Window, mode core.Mode) string {
left := leftBar(w, mode)
right := rightBar(w, mode)
func drawStatusBar(w *core.Window, mode core.Mode, styles style.Styles) string {
left := leftBar(w, mode, styles)
right := rightBar(w, mode, styles)
diff := w.Width - (lipgloss.Width(left) + lipgloss.Width(right))
@ -164,12 +177,12 @@ func drawStatusBar(w *core.Window, mode core.Mode) string {
return ""
}
middle := strings.Repeat(" ", diff)
middle := strings.Repeat(styles.BackgroundStyle.Render(" "), diff)
return left + middle + right
}
// leftBar: Returns the left side of the status bar showing the current mode.
func leftBar(w *core.Window, mode core.Mode) string {
func leftBar(w *core.Window, mode core.Mode, styles style.Styles) string {
buf := w.Buffer
var flags []string
@ -185,12 +198,13 @@ func leftBar(w *core.Window, mode core.Mode) string {
flagStr = "(" + strings.Join(flags, "") + ")"
}
return fmt.Sprintf(" %s %s %s", mode.ToString(), buf.Filename, flagStr)
bar := fmt.Sprintf(" %s %s %s", mode.ToString(), buf.Filename, flagStr)
return styles.LineStyle.Render(bar)
}
// rightBar: Returns the right side of the status bar showing cursor position
// and selection count in visual mode.
func rightBar(w *core.Window, mode core.Mode) (bar string) {
func rightBar(w *core.Window, mode core.Mode, styles style.Styles) (bar string) {
if mode.IsVisualMode() {
lineCount := max(w.Anchor.Line, w.Cursor.Line) - min(w.Anchor.Line, w.Cursor.Line) + 1
bar = fmt.Sprintf("%d:%d <%d>", w.Cursor.Line+1, w.Cursor.Col+1, lineCount)
@ -198,41 +212,44 @@ func rightBar(w *core.Window, mode core.Mode) (bar string) {
bar = fmt.Sprintf("%d:%d ", w.Cursor.Line+1, w.Cursor.Col+1)
}
buf := w.Buffer
bar = fmt.Sprintf("%s %s", buf.Filetype, bar)
bar = styles.LineStyle.Render(fmt.Sprintf("%s %s", buf.Filetype, bar))
return
}
// drawCommandBar: Renders the command line showing command input, errors, or
// output depending on the current mode and state.
func drawCommandBar(m Model) string {
styles := m.Styles()
// Compute left bar (command side)
var leftBar string
if m.Mode() == core.CommandMode {
leftBar = ":"
leftBar = styles.LineStyle.Render(":")
cmd := []rune(m.Command())
cur := m.CommandCursor()
for i, r := range cmd {
if i == cur {
leftBar += m.Styles().CursorStyle(m.Mode()).Render(string(r))
leftBar += styles.DefaultCursorStyle(m.Mode()).Render(string(r))
} else {
leftBar += string(r)
leftBar += styles.LineStyle.Render(string(r))
}
}
// Cursor at end of command
if cur >= len(cmd) {
leftBar += m.Styles().CursorStyle(m.Mode()).Render(" ")
leftBar += styles.DefaultCursorStyle(m.Mode()).Render(" ")
}
// bar = fmt.Sprintf("%s %d", bar, cur)
} else if out := m.CommandOutput(); out != nil && len(out.Lines) > 0 && out.Inline {
// TODO: This is not perfect, temporary
text := strings.Join(out.Lines, " ")
if out.IsError {
leftBar = m.Styles().CommandError.Render(text)
leftBar = styles.CommandError.Render(text)
} else {
leftBar = text
leftBar = styles.LineStyle.Render(text)
}
} else if strings.TrimSpace(m.Command()) != "" {
leftBar = fmt.Sprintf(":%s", m.Command())
content := fmt.Sprintf(":%s", m.Command())
leftBar = styles.LineStyle.Render(content) //
}
// Compute right bar
@ -240,12 +257,13 @@ func drawCommandBar(m Model) string {
var rightBar string
if len(m.input.Pending()) > 0 {
width := 10 // Size of the block to display
rightBar = fmt.Sprintf("%-*s", width, m.input.Pending())
content := fmt.Sprintf("%-*s", width, m.input.Pending())
rightBar = styles.LineStyle.Render(content)
}
dif := m.termWidth - (lipgloss.Width(leftBar) + lipgloss.Width(rightBar))
bar := leftBar + strings.Repeat(" ", max(0, dif)) + rightBar
bar := leftBar + strings.Repeat(styles.BackgroundStyle.Render(" "), max(0, dif)) + rightBar
return bar
}
@ -310,10 +328,12 @@ func overlayCommandOutputWindow(view string, cmd *core.CommandOutput, styles sty
overlay = append(overlay, styles.CommandOutputBorder.Render(strings.Repeat(" ", termWidth)))
if strings.TrimSpace(cmd.Title) != "" {
overlay = append(overlay, cmd.Title)
title := styles.LineStyle.Render(cmd.Title)
overlay = append(overlay, title)
}
for _, l := range cmd.Lines {
overlay = append(overlay, strings.ReplaceAll(l, "\n", "\\n"))
content := styles.LineStyle.Render(strings.ReplaceAll(l, "\n", "\\n"))
overlay = append(overlay, content)
}
overlay = append(overlay, styles.CommandContinueMessage.Render(core.CommandOutputExitMessage))
@ -321,6 +341,12 @@ func overlayCommandOutputWindow(view string, cmd *core.CommandOutput, styles sty
// which would cause Lipgloss to embed newlines internally and corrupt the line count.
// If block-level styles are ever added, this approach must be replaced.
// Add background color to end of each line
for i, l := range overlay {
dif := termWidth - lipgloss.Width(l)
overlay[i] += styles.BackgroundStyle.Render(strings.Repeat(" ", dif))
}
// Remove 'h' lines from back of view and append overlay
h := len(overlay)
final := lines[:max(0, len(lines)-h)]

View File

@ -46,6 +46,7 @@ func (p *ProgramBuilder) FileProgram(filename string) *ProgramBuilder {
WithType(core.FileBuffer).
WithFilename(filename).
WithFiletype(ext).
Listed().
Build()
win := core.NewWindowBuilder().

154
internal/style/style.go Normal file → Executable file
View File

@ -2,6 +2,7 @@ package style
import (
"git.gophernest.net/azpect/TextEditor/internal/core"
"github.com/alecthomas/chroma/v2"
"github.com/charmbracelet/lipgloss"
)
@ -28,9 +29,16 @@ type Styles struct {
CommandError lipgloss.Style
CommandOutputBorder lipgloss.Style
CommandContinueMessage lipgloss.Style
// General Styles
LineStyle lipgloss.Style // This is a simple background with no text coloring
BackgroundStyle lipgloss.Style // This is just the background
// Chroma data
chromaStyle *chroma.Style
}
// DefaultStyles returns the default editor color scheme.
// DefaultStyles: Returns the default editor color scheme.
func DefaultStyles() Styles {
return Styles{
CursorNormal: lipgloss.NewStyle().Reverse(true),
@ -67,11 +75,86 @@ func DefaultStyles() Styles {
CommandContinueMessage: lipgloss.NewStyle().
Foreground(lipgloss.Color("#546fba")),
chromaStyle: nil,
}
}
// CursorStyle returns the appropriate cursor style for the given mode.
func (s Styles) CursorStyle(mode core.Mode) lipgloss.Style {
func ChromaStyles(chromaStyle *chroma.Style) Styles {
bgString := chromaStyle.Get(chroma.Background).Background.String()
lineNumbers := chromaStyle.Get(chroma.LineTableTD)
lineHighlight := chromaStyle.Get(chroma.LineHighlight)
return Styles{
CursorNormal: lipgloss.NewStyle().
Background(lipgloss.Color(bgString)).
Reverse(true),
CursorInsert: lipgloss.NewStyle().
Background(lipgloss.Color(bgString)).
Underline(true),
CursorCommand: lipgloss.NewStyle().
Background(lipgloss.Color(bgString)).
Reverse(true),
Gutter: lipgloss.NewStyle().
Background(lipgloss.Color(
darkenColor(lineNumbers.Background, 0.9).String()),
).
Foreground(lipgloss.Color(lineNumbers.Colour.String())),
GutterCurrentLine: lipgloss.NewStyle().
Background(lipgloss.Color(
darkenColor(lineNumbers.Background, 0.9).String()),
).
Foreground(lipgloss.Color(lineNumbers.Colour.String())),
VisualHighlight: lipgloss.NewStyle().
Background(lipgloss.Color(lineHighlight.Background.String())).
Foreground(lipgloss.Color(lineHighlight.Colour.String())),
VisualAnchor: lipgloss.NewStyle().
Background(lipgloss.Color(lineHighlight.Background.String())).
Foreground(lipgloss.Color(lineHighlight.Colour.String())),
StatusBar: lipgloss.NewStyle().
Background(lipgloss.Color(bgString)).
Foreground(lipgloss.Color("243")),
StatusBarActive: lipgloss.NewStyle().
Background(lipgloss.Color(bgString)).
Foreground(lipgloss.Color("230")),
CommandError: lipgloss.NewStyle().
Background(lipgloss.Color(bgString)).
Foreground(lipgloss.Color("#e3203a")),
CommandOutputBorder: lipgloss.NewStyle().
Background(
lipgloss.Color(
darkenColor(
chromaStyle.Get(chroma.Background).Background, 0.5).
String(),
),
),
CommandContinueMessage: lipgloss.NewStyle().
Background(lipgloss.Color(bgString)).
Foreground(lipgloss.Color("#546fba")),
LineStyle: lipgloss.NewStyle().
Foreground(lipgloss.Color(chromaStyle.Get(chroma.Line).Colour.String())).
Background(lipgloss.Color(bgString)),
BackgroundStyle: lipgloss.NewStyle().Background(lipgloss.Color(bgString)),
chromaStyle: chromaStyle,
}
}
// Styles.DefaultCursorStyle: Returns the appropriate cursor style for the given mode.
func (s Styles) DefaultCursorStyle(mode core.Mode) lipgloss.Style {
switch mode {
case core.InsertMode:
return s.CursorInsert
@ -81,3 +164,68 @@ func (s Styles) CursorStyle(mode core.Mode) lipgloss.Style {
return s.CursorNormal
}
}
// Styles.CursorStyle: Returns a cursor style derived from a chroma style. This function should preferred
// over the DefaultCursorStyle, but in cases where there is no style to apply, the DefaultCursorStyle
// will always work.
func (s Styles) CursorStyle(mode core.Mode, style lipgloss.Style) lipgloss.Style {
switch mode {
case core.NormalMode, core.VisualLineMode, core.VisualBlockMode, core.VisualMode:
return lipgloss.NewStyle().
Background(style.GetForeground()).
Foreground(style.GetBackground())
default:
return lipgloss.NewStyle().
Background(s.BackgroundStyle.GetBackground()).
Foreground(style.GetForeground()).
Underline(true)
}
}
// Styles.VisualHighlightWithTextColor: Works analogously to CursorStyle vs DefaultCursorStyle. When a
// style is available, this function should be used, so the text color will be rendered in front
// of the background. Otherwise, the VisualHighlight property will always work.
func (s Styles) VisualHighlightWithTextColor(style lipgloss.Style) lipgloss.Style {
return lipgloss.NewStyle().
Background(s.VisualHighlight.GetBackground()).
Foreground(style.GetForeground())
}
// Styles.MakeStyleMap: Generates a style map for a single line. A style map is a mapping from
// column a lipgloss style. Cursor styles are not handled by this map, but they can be derived
// by inverting the background and foreground (and rolling back to the default).
func (s Styles) MakeStyleMap(lexer chroma.Lexer, line string) []lipgloss.Style {
m := make([]lipgloss.Style, len(line))
iter, err := lexer.Tokenise(nil, line)
if err != nil {
panic(err)
}
col := 0
for _, token := range iter.Tokens() {
entry := s.chromaStyle.Get(token.Type)
s := lipgloss.NewStyle().
Background(lipgloss.Color(entry.Background.String())).
Foreground(lipgloss.Color(entry.Colour.String()))
for _, char := range token.Value {
if char == '\n' {
continue
}
if col < len(m) {
m[col] = s
}
col++
}
}
return m
}
// darkenColor: Uses a factor (0.0 to 1.0) to darken a color using its opacity.
func darkenColor(c chroma.Colour, factor float64) chroma.Colour {
r := uint8(float64(c.Red()) * factor)
g := uint8(float64(c.Green()) * factor)
b := uint8(float64(c.Blue()) * factor)
return chroma.NewColour(r, g, b)
}

43
internal/theme/theme.go Normal file
View File

@ -0,0 +1,43 @@
package theme
import (
"embed"
"fmt"
"github.com/alecthomas/chroma/v2"
"github.com/alecthomas/chroma/v2/styles"
)
//go:embed themes/*
var themeFS embed.FS
// RegisterAll: Registers all XML theme files embedded in the themes/ directory
// with chroma's style registry. After calling this, styles.Get() will recognize
// any theme defined in those files.
func RegisterAll() error {
entries, err := themeFS.ReadDir("themes")
if err != nil {
return fmt.Errorf("failed to read embedded themes directory: %w", err)
}
for _, entry := range entries {
if entry.IsDir() {
continue
}
f, err := themeFS.Open("themes/" + entry.Name())
if err != nil {
return fmt.Errorf("failed to open theme %s: %w", entry.Name(), err)
}
style, err := chroma.NewXMLStyle(f)
f.Close()
if err != nil {
return fmt.Errorf("failed to parse theme %s: %w", entry.Name(), err)
}
styles.Register(style)
}
return nil
}

View File

@ -0,0 +1,83 @@
<style name="kanagawa-dragon">
<entry type="Background" style="bg:#181616 #c5c9c5" />
<entry type="CodeLine" style="#c5c9c5" />
<entry type="Error" style="#e82424" />
<entry type="Other" style="#c5c9c5" />
<entry type="LineTableTD" style="" />
<entry type="LineTable" style="" />
<entry type="LineHighlight" style="bg:#393836" />
<entry type="LineNumbersTable" style="#625e5a" />
<entry type="LineNumbers" style="#625e5a" />
<entry type="Keyword" style="#8992a7" />
<entry type="KeywordReserved" style="#8992a7" />
<entry type="KeywordPseudo" style="#8992a7" />
<entry type="KeywordConstant" style="#b6927b" />
<entry type="KeywordDeclaration" style="#8992a7" />
<entry type="KeywordNamespace" style="#c4b28a" />
<entry type="KeywordType" style="#8ea4a2" />
<entry type="Name" style="#c5c9c5" />
<entry type="NameClass" style="#8ea4a2" />
<entry type="NameConstant" style="#b6927b" />
<entry type="NameDecorator" style="bold #b6927b" />
<entry type="NameEntity" style="#c4b28a" />
<entry type="NameException" style="#b6927b" />
<entry type="NameFunction" style="#8ba4b0" />
<entry type="NameFunctionMagic" style="#8ba4b0" />
<entry type="NameLabel" style="#949fb5" />
<entry type="NameNamespace" style="#c4b28a" />
<entry type="NameProperty" style="#c4b28a" />
<entry type="NameTag" style="#8ba4b0" />
<entry type="NameVariable" style="#c5c9c5" />
<entry type="NameVariableClass" style="#c5c9c5" />
<entry type="NameVariableGlobal" style="#c5c9c5" />
<entry type="NameVariableInstance" style="#c5c9c5" />
<entry type="NameVariableMagic" style="#c5c9c5" />
<entry type="NameAttribute" style="#c4b28a" />
<entry type="NameBuiltin" style="#c4746e" />
<entry type="NameBuiltinPseudo" style="#c4746e" />
<entry type="NameOther" style="#c5c9c5" />
<entry type="Literal" style="#c5c9c5" />
<entry type="LiteralDate" style="#c5c9c5" />
<entry type="LiteralString" style="#8a9a7b" />
<entry type="LiteralStringChar" style="#8a9a7b" />
<entry type="LiteralStringSingle" style="#8a9a7b" />
<entry type="LiteralStringDouble" style="#8a9a7b" />
<entry type="LiteralStringBacktick" style="#8a9a7b" />
<entry type="LiteralStringOther" style="#8a9a7b" />
<entry type="LiteralStringSymbol" style="#8a9a7b" />
<entry type="LiteralStringInterpol" style="#949fb5" />
<entry type="LiteralStringAffix" style="#c4746e" />
<entry type="LiteralStringDelimiter" style="#949fb5" />
<entry type="LiteralStringEscape" style="#c4746e" />
<entry type="LiteralStringRegex" style="#c4746e" />
<entry type="LiteralStringDoc" style="#737c73" />
<entry type="LiteralStringHeredoc" style="#737c73" />
<entry type="LiteralNumber" style="#a292a3" />
<entry type="LiteralNumberBin" style="#a292a3" />
<entry type="LiteralNumberHex" style="#a292a3" />
<entry type="LiteralNumberInteger" style="#a292a3" />
<entry type="LiteralNumberFloat" style="#a292a3" />
<entry type="LiteralNumberIntegerLong" style="#a292a3" />
<entry type="LiteralNumberOct" style="#a292a3" />
<entry type="Operator" style="bold #c4746e" />
<entry type="OperatorWord" style="bold #c4746e" />
<entry type="Comment" style="italic #737c73" />
<entry type="CommentSingle" style="italic #737c73" />
<entry type="CommentMultiline" style="italic #737c73" />
<entry type="CommentSpecial" style="italic #737c73" />
<entry type="CommentHashbang" style="italic #737c73" />
<entry type="CommentPreproc" style="italic #c4746e" />
<entry type="CommentPreprocFile" style="bold #c4746e" />
<entry type="Generic" style="#c5c9c5" />
<entry type="GenericInserted" style="bg:#2b3328 #76946a" />
<entry type="GenericDeleted" style="bg:#43242b #c34043" />
<entry type="GenericEmph" style="italic #c5c9c5" />
<entry type="GenericStrong" style="bold #c5c9c5" />
<entry type="GenericUnderline" style="underline #c5c9c5" />
<entry type="GenericHeading" style="bold #8ba4b0" />
<entry type="GenericSubheading" style="bold #8ba4b0" />
<entry type="GenericOutput" style="#c5c9c5" />
<entry type="GenericPrompt" style="#c5c9c5" />
<entry type="GenericError" style="#e82424" />
<entry type="GenericTraceback" style="#e82424" />
</style>

View File

@ -0,0 +1,83 @@
<style name="kanagawa-lotus">
<entry type="Background" style="bg:#f2ecbc #545464" />
<entry type="CodeLine" style="#545464" />
<entry type="Error" style="#e82424" />
<entry type="Other" style="#545464" />
<entry type="LineTableTD" style="" />
<entry type="LineTable" style="" />
<entry type="LineHighlight" style="bg:#e4d794" />
<entry type="LineNumbersTable" style="#a09cac" />
<entry type="LineNumbers" style="#a09cac" />
<entry type="Keyword" style="#624c83" />
<entry type="KeywordReserved" style="#624c83" />
<entry type="KeywordPseudo" style="#624c83" />
<entry type="KeywordConstant" style="#cc6d00" />
<entry type="KeywordDeclaration" style="#624c83" />
<entry type="KeywordNamespace" style="#77713f" />
<entry type="KeywordType" style="#597b75" />
<entry type="Name" style="#545464" />
<entry type="NameClass" style="#597b75" />
<entry type="NameConstant" style="#cc6d00" />
<entry type="NameDecorator" style="bold #cc6d00" />
<entry type="NameEntity" style="#77713f" />
<entry type="NameException" style="#cc6d00" />
<entry type="NameFunction" style="#4d699b" />
<entry type="NameFunctionMagic" style="#4d699b" />
<entry type="NameLabel" style="#6693bf" />
<entry type="NameNamespace" style="#77713f" />
<entry type="NameProperty" style="#77713f" />
<entry type="NameTag" style="#4d699b" />
<entry type="NameVariable" style="#545464" />
<entry type="NameVariableClass" style="#545464" />
<entry type="NameVariableGlobal" style="#545464" />
<entry type="NameVariableInstance" style="#545464" />
<entry type="NameVariableMagic" style="#545464" />
<entry type="NameAttribute" style="#77713f" />
<entry type="NameBuiltin" style="#c84053" />
<entry type="NameBuiltinPseudo" style="#c84053" />
<entry type="NameOther" style="#545464" />
<entry type="Literal" style="#545464" />
<entry type="LiteralDate" style="#545464" />
<entry type="LiteralString" style="#6f894e" />
<entry type="LiteralStringChar" style="#6f894e" />
<entry type="LiteralStringSingle" style="#6f894e" />
<entry type="LiteralStringDouble" style="#6f894e" />
<entry type="LiteralStringBacktick" style="#6f894e" />
<entry type="LiteralStringOther" style="#6f894e" />
<entry type="LiteralStringSymbol" style="#6f894e" />
<entry type="LiteralStringInterpol" style="#6693bf" />
<entry type="LiteralStringAffix" style="#c84053" />
<entry type="LiteralStringDelimiter" style="#6693bf" />
<entry type="LiteralStringEscape" style="#836f4a" />
<entry type="LiteralStringRegex" style="#836f4a" />
<entry type="LiteralStringDoc" style="#8a8980" />
<entry type="LiteralStringHeredoc" style="#8a8980" />
<entry type="LiteralNumber" style="#b35b79" />
<entry type="LiteralNumberBin" style="#b35b79" />
<entry type="LiteralNumberHex" style="#b35b79" />
<entry type="LiteralNumberInteger" style="#b35b79" />
<entry type="LiteralNumberFloat" style="#b35b79" />
<entry type="LiteralNumberIntegerLong" style="#b35b79" />
<entry type="LiteralNumberOct" style="#b35b79" />
<entry type="Operator" style="bold #836f4a" />
<entry type="OperatorWord" style="bold #836f4a" />
<entry type="Comment" style="italic #8a8980" />
<entry type="CommentSingle" style="italic #8a8980" />
<entry type="CommentMultiline" style="italic #8a8980" />
<entry type="CommentSpecial" style="italic #8a8980" />
<entry type="CommentHashbang" style="italic #8a8980" />
<entry type="CommentPreproc" style="italic #c84053" />
<entry type="CommentPreprocFile" style="bold #c84053" />
<entry type="Generic" style="#545464" />
<entry type="GenericInserted" style="bg:#b7d0ae #6e915f" />
<entry type="GenericDeleted" style="bg:#d9a594 #d7474b" />
<entry type="GenericEmph" style="italic #545464" />
<entry type="GenericStrong" style="bold #545464" />
<entry type="GenericUnderline" style="underline #545464" />
<entry type="GenericHeading" style="bold #4d699b" />
<entry type="GenericSubheading" style="bold #4d699b" />
<entry type="GenericOutput" style="#545464" />
<entry type="GenericPrompt" style="#545464" />
<entry type="GenericError" style="#e82424" />
<entry type="GenericTraceback" style="#e82424" />
</style>

View File

@ -0,0 +1,83 @@
<style name="kanagawa-wave">
<entry type="Background" style="bg:#1f1f28 #dcd7ba" />
<entry type="CodeLine" style="#dcd7ba" />
<entry type="Error" style="#e82424" />
<entry type="Other" style="#dcd7ba" />
<entry type="LineTableTD" style="" />
<entry type="LineTable" style="" />
<entry type="LineHighlight" style="bg:#363646" />
<entry type="LineNumbersTable" style="#54546d" />
<entry type="LineNumbers" style="#54546d" />
<entry type="Keyword" style="#957fb8" />
<entry type="KeywordReserved" style="#957fb8" />
<entry type="KeywordPseudo" style="#957fb8" />
<entry type="KeywordConstant" style="#ffa066" />
<entry type="KeywordDeclaration" style="#957fb8" />
<entry type="KeywordNamespace" style="#e6c384" />
<entry type="KeywordType" style="#7aa89f" />
<entry type="Name" style="#dcd7ba" />
<entry type="NameClass" style="#7aa89f" />
<entry type="NameConstant" style="#ffa066" />
<entry type="NameDecorator" style="bold #ffa066" />
<entry type="NameEntity" style="#e6c384" />
<entry type="NameException" style="#ffa066" />
<entry type="NameFunction" style="#7e9cd8" />
<entry type="NameFunctionMagic" style="#7e9cd8" />
<entry type="NameLabel" style="#7fb4ca" />
<entry type="NameNamespace" style="#e6c384" />
<entry type="NameProperty" style="#e6c384" />
<entry type="NameTag" style="#7e9cd8" />
<entry type="NameVariable" style="#dcd7ba" />
<entry type="NameVariableClass" style="#dcd7ba" />
<entry type="NameVariableGlobal" style="#dcd7ba" />
<entry type="NameVariableInstance" style="#dcd7ba" />
<entry type="NameVariableMagic" style="#dcd7ba" />
<entry type="NameAttribute" style="#e6c384" />
<entry type="NameBuiltin" style="#e46876" />
<entry type="NameBuiltinPseudo" style="#e46876" />
<entry type="NameOther" style="#dcd7ba" />
<entry type="Literal" style="#dcd7ba" />
<entry type="LiteralDate" style="#dcd7ba" />
<entry type="LiteralString" style="#98bb6c" />
<entry type="LiteralStringChar" style="#98bb6c" />
<entry type="LiteralStringSingle" style="#98bb6c" />
<entry type="LiteralStringDouble" style="#98bb6c" />
<entry type="LiteralStringBacktick" style="#98bb6c" />
<entry type="LiteralStringOther" style="#98bb6c" />
<entry type="LiteralStringSymbol" style="#98bb6c" />
<entry type="LiteralStringInterpol" style="#7fb4ca" />
<entry type="LiteralStringAffix" style="#ff5d62" />
<entry type="LiteralStringDelimiter" style="#7fb4ca" />
<entry type="LiteralStringEscape" style="#c0a36e" />
<entry type="LiteralStringRegex" style="#c0a36e" />
<entry type="LiteralStringDoc" style="#727169" />
<entry type="LiteralStringHeredoc" style="#727169" />
<entry type="LiteralNumber" style="#d27e99" />
<entry type="LiteralNumberBin" style="#d27e99" />
<entry type="LiteralNumberHex" style="#d27e99" />
<entry type="LiteralNumberInteger" style="#d27e99" />
<entry type="LiteralNumberFloat" style="#d27e99" />
<entry type="LiteralNumberIntegerLong" style="#d27e99" />
<entry type="LiteralNumberOct" style="#d27e99" />
<entry type="Operator" style="bold #c0a36e" />
<entry type="OperatorWord" style="bold #c0a36e" />
<entry type="Comment" style="italic #727169" />
<entry type="CommentSingle" style="italic #727169" />
<entry type="CommentMultiline" style="italic #727169" />
<entry type="CommentSpecial" style="italic #727169" />
<entry type="CommentHashbang" style="italic #727169" />
<entry type="CommentPreproc" style="italic #e46876" />
<entry type="CommentPreprocFile" style="bold #e46876" />
<entry type="Generic" style="#dcd7ba" />
<entry type="GenericInserted" style="bg:#2b3328 #76946a" />
<entry type="GenericDeleted" style="bg:#43242b #c34043" />
<entry type="GenericEmph" style="italic #dcd7ba" />
<entry type="GenericStrong" style="bold #dcd7ba" />
<entry type="GenericUnderline" style="underline #dcd7ba" />
<entry type="GenericHeading" style="bold #7e9cd8" />
<entry type="GenericSubheading" style="bold #7e9cd8" />
<entry type="GenericOutput" style="#dcd7ba" />
<entry type="GenericPrompt" style="#dcd7ba" />
<entry type="GenericError" style="#e82424" />
<entry type="GenericTraceback" style="#e82424" />
</style>