183 lines
4.4 KiB
Go
183 lines
4.4 KiB
Go
package main
|
|
|
|
import (
|
|
"github.com/alecthomas/chroma/v2"
|
|
"github.com/alecthomas/chroma/v2/lexers"
|
|
)
|
|
|
|
type editorMarkdownStyle uint8
|
|
|
|
const (
|
|
editorMarkdownPlain editorMarkdownStyle = iota
|
|
editorMarkdownHeading
|
|
editorMarkdownStrong
|
|
editorMarkdownEmphasis
|
|
editorMarkdownCode
|
|
editorMarkdownLink
|
|
editorMarkdownDestination
|
|
editorMarkdownQuote
|
|
editorMarkdownComment
|
|
)
|
|
|
|
func editorMarkdownStyles(value string) []editorMarkdownStyle {
|
|
runes := []rune(value)
|
|
styles := make([]editorMarkdownStyle, len(runes))
|
|
lexer := lexers.Get("markdown")
|
|
if lexer == nil {
|
|
highlightEditorHTMLComments(runes, styles)
|
|
return styles
|
|
}
|
|
tokens, err := chroma.Tokenise(lexer, nil, value)
|
|
if err != nil {
|
|
highlightEditorHTMLComments(runes, styles)
|
|
return styles
|
|
}
|
|
offset := 0
|
|
for _, token := range tokens {
|
|
style := editorMarkdownStyleForToken(token.Type)
|
|
for range []rune(token.Value) {
|
|
if offset >= len(styles) {
|
|
return styles
|
|
}
|
|
styles[offset] = style
|
|
offset++
|
|
}
|
|
}
|
|
highlightEditorHTMLComments(runes, styles)
|
|
return styles
|
|
}
|
|
|
|
func highlightEditorHTMLComments(runes []rune, styles []editorMarkdownStyle) {
|
|
startMarker, endMarker := []rune("<!--"), []rune("-->")
|
|
for offset := 0; offset < len(runes); {
|
|
start := findEditorRunes(runes, startMarker, offset)
|
|
if start < 0 {
|
|
return
|
|
}
|
|
end := findEditorRunes(runes, endMarker, start+len(startMarker))
|
|
if end < 0 {
|
|
end = len(runes)
|
|
} else {
|
|
end += len(endMarker)
|
|
}
|
|
for index := start; index < end; index++ {
|
|
styles[index] = editorMarkdownComment
|
|
}
|
|
offset = end
|
|
}
|
|
}
|
|
|
|
func findEditorRunes(value, target []rune, offset int) int {
|
|
for index := max(0, offset); index+len(target) <= len(value); index++ {
|
|
matches := true
|
|
for targetIndex := range target {
|
|
if value[index+targetIndex] != target[targetIndex] {
|
|
matches = false
|
|
break
|
|
}
|
|
}
|
|
if matches {
|
|
return index
|
|
}
|
|
}
|
|
return -1
|
|
}
|
|
|
|
func editorMarkdownStyleForToken(token chroma.TokenType) editorMarkdownStyle {
|
|
switch {
|
|
case token == chroma.GenericHeading || token == chroma.GenericSubheading:
|
|
return editorMarkdownHeading
|
|
case token == chroma.GenericStrong:
|
|
return editorMarkdownStrong
|
|
case token == chroma.GenericEmph:
|
|
return editorMarkdownEmphasis
|
|
case token == chroma.LiteralStringBacktick:
|
|
return editorMarkdownCode
|
|
case token == chroma.NameTag:
|
|
return editorMarkdownLink
|
|
case token == chroma.NameAttribute:
|
|
return editorMarkdownDestination
|
|
case token == chroma.Keyword:
|
|
return editorMarkdownQuote
|
|
case token.InSubCategory(chroma.Comment):
|
|
return editorMarkdownComment
|
|
default:
|
|
return editorMarkdownPlain
|
|
}
|
|
}
|
|
|
|
func editorMarkdownStyleStart(style editorMarkdownStyle) string {
|
|
if style == editorMarkdownPlain {
|
|
return ""
|
|
}
|
|
if currentThemeName == "no-color" {
|
|
switch style {
|
|
case editorMarkdownHeading, editorMarkdownStrong:
|
|
return "\x1b[1m"
|
|
case editorMarkdownEmphasis:
|
|
return "\x1b[3m"
|
|
case editorMarkdownLink:
|
|
return "\x1b[4m"
|
|
case editorMarkdownComment:
|
|
return "\x1b[2m"
|
|
default:
|
|
return ""
|
|
}
|
|
}
|
|
if currentThemeName == "light" {
|
|
switch style {
|
|
case editorMarkdownHeading:
|
|
return "\x1b[1;38;2;154;103;0m"
|
|
case editorMarkdownStrong:
|
|
return "\x1b[1;38;2;130;80;223m"
|
|
case editorMarkdownEmphasis:
|
|
return "\x1b[3;38;2;87;96;106m"
|
|
case editorMarkdownCode:
|
|
return "\x1b[38;2;17;99;41m"
|
|
case editorMarkdownLink:
|
|
return "\x1b[4;38;2;9;105;218m"
|
|
case editorMarkdownDestination:
|
|
return "\x1b[38;2;10;112;111m"
|
|
case editorMarkdownQuote:
|
|
return "\x1b[38;2;154;103;0m"
|
|
case editorMarkdownComment:
|
|
return "\x1b[2;38;2;101;109;118m"
|
|
}
|
|
}
|
|
switch style {
|
|
case editorMarkdownHeading:
|
|
return "\x1b[1;38;2;240;183;47m"
|
|
case editorMarkdownStrong:
|
|
return "\x1b[1;38;2;198;120;221m"
|
|
case editorMarkdownEmphasis:
|
|
return "\x1b[3;38;2;215;218;232m"
|
|
case editorMarkdownCode:
|
|
return "\x1b[38;2;152;195;121m"
|
|
case editorMarkdownLink:
|
|
return "\x1b[4;38;2;97;175;239m"
|
|
case editorMarkdownDestination:
|
|
return "\x1b[38;2;86;182;194m"
|
|
case editorMarkdownQuote:
|
|
return "\x1b[38;2;229;192;123m"
|
|
case editorMarkdownComment:
|
|
return "\x1b[2;38;2;119;119;119m"
|
|
default:
|
|
return ""
|
|
}
|
|
}
|
|
|
|
func editorMarkdownStyleEnd(active bool) string {
|
|
foreground := "\x1b[39m"
|
|
if active {
|
|
switch currentThemeName {
|
|
case "dark":
|
|
foreground = "\x1b[38;2;215;218;232m"
|
|
case "light":
|
|
foreground = "\x1b[38;2;36;41;47m"
|
|
case "high-contrast":
|
|
foreground = "\x1b[38;2;255;255;255m"
|
|
}
|
|
}
|
|
return "\x1b[22;23;24m" + foreground
|
|
}
|