Highlight keywords, and fix emoji rendering issue
All checks were successful
timw4mail/gilo/pipeline/head This commit looks good

This commit is contained in:
Timothy Warren 2023-10-05 11:03:08 -04:00
parent 5f81aa90a1
commit 69709a1cb4
5 changed files with 89 additions and 28 deletions

View File

@ -40,6 +40,12 @@ func (r *Row) Render(at *gilo.Point) string {
return string(r.render[at.X:]) return string(r.render[at.X:])
} }
// RenderRune returns the array of runes in the current row. Unlike a string
// this will index how you expect with multi-byte characters
func (r *Row) RenderRune(at *gilo.Point) []rune {
return r.render[at.X:]
}
func (r *Row) Search(query string) int { func (r *Row) Search(query string) int {
return strings.Index(string(r.render), query) return strings.Index(string(r.render), query)
} }
@ -122,10 +128,14 @@ func (r *Row) updateSyntax() {
return return
} }
renderStr := string(r.render)
keywords1 := s.Keywords1
keywords2 := s.Keywords2
var scsIndex int = -1 var scsIndex int = -1
scs := s.LineCommentStart scs := s.LineCommentStart
if len(scs) > 0 { if len(scs) > 0 {
scsIndex = strings.Index(string(r.render), scs) scsIndex = strings.Index(renderStr, scs)
} }
prevSep := true prevSep := true
@ -148,7 +158,7 @@ func (r *Row) updateSyntax() {
} }
// String literals // String literals
if s.Flags&highlight.HighlightStrings == highlight.HighlightStrings { if s.Flags&highlight.DoStrings == highlight.DoStrings {
// At the start of a string literal // At the start of a string literal
if inString == '0' && (ch == '"' || ch == '\'') { if inString == '0' && (ch == '"' || ch == '\'') {
inString = ch inString = ch
@ -181,7 +191,7 @@ func (r *Row) updateSyntax() {
} }
// Numeric literals // Numeric literals
if s.Flags&highlight.HighlightNumbers == highlight.HighlightNumbers { if s.Flags&highlight.DoNumbers == highlight.DoNumbers {
if (unicode.IsDigit(ch) && (prevSep || prevHl == highlight.Number)) || if (unicode.IsDigit(ch) && (prevSep || prevHl == highlight.Number)) ||
(ch == '.' && prevHl == highlight.Number) { (ch == '.' && prevHl == highlight.Number) {
r.Hl[i] = highlight.Number r.Hl[i] = highlight.Number
@ -191,6 +201,43 @@ func (r *Row) updateSyntax() {
} }
} }
// Keywords
if prevSep {
renderLen := r.RenderSize()
for _, word := range keywords1 {
wordLen := len(word)
nextInd := i + wordLen
if nextInd >= renderLen || renderStr[i:nextInd] != word {
continue
}
if renderStr[i:renderLen] == word || key.IsSeparator(r.render[nextInd]) {
for k := i; k < nextInd; k++ {
r.Hl[k] = highlight.Keyword1
}
i += wordLen
break
}
}
for _, word := range keywords2 {
wordLen := len(word)
nextInd := i + wordLen
if nextInd >= renderLen || renderStr[i:nextInd] != word {
continue
}
if renderStr[i:renderLen] == word || key.IsSeparator(r.render[nextInd]) {
for k := i; k < nextInd; k++ {
r.Hl[k] = highlight.Keyword2
}
i += wordLen
break
}
}
}
prevSep = key.IsSeparator(ch) prevSep = key.IsSeparator(ch)
i++ i++
} }

View File

@ -85,7 +85,10 @@ func (e *Editor) drawFileRow(fileRow int, ab *gilo.Buffer) {
currentColor := terminal.DefaultFGColor currentColor := terminal.DefaultFGColor
row := e.doc.GetRow(fileRow) row := e.doc.GetRow(fileRow)
for i, ch := range row.Render(e.offset) { // Because runes can be more than one byte, 🫵 render
// this by runes so that multibyte-characters (like emoji) can
// all be displayed
for i, ch := range row.RenderRune(e.offset) {
if row.Hl[i] == highlight.Normal { if row.Hl[i] == highlight.Normal {
if currentColor != terminal.DefaultFGColor { if currentColor != terminal.DefaultFGColor {
ab.Append(terminal.DefaultFGColor) ab.Append(terminal.DefaultFGColor)

View File

@ -1,17 +0,0 @@
package highlight
// ----------------------------------------------------------------------------
// !Syntax Highlighting Constants
// ----------------------------------------------------------------------------
const (
Normal = iota
Comment
String
Number
Match
)
const (
HighlightNumbers = 1 << 0
HighlightStrings = 1 << 1
)

View File

@ -5,13 +5,33 @@ import (
"timshome.page/gilo/terminal" "timshome.page/gilo/terminal"
) )
// ----------------------------------------------------------------------------
// !Syntax Highlighting Constants
// ----------------------------------------------------------------------------
const (
Normal = iota
Comment
Keyword1
Keyword2
String
Number
Match
)
const (
DoNumbers = 1 << 0
DoStrings = 1 << 1
)
// ------------------------------------------------------------------ // ------------------------------------------------------------------
// Syntax Type -> Color Mapping // Syntax Type -> Color Mapping
// ------------------------------------------------------------------ // ------------------------------------------------------------------
var syntaxColorMap = map[int]string{ var syntaxColorMap = map[int]string{
Comment: terminal.FGCyan, Comment: terminal.FGCyan,
String: terminal.FGMagenta, Keyword1: terminal.FGYellow,
Keyword2: terminal.FGGreen,
String: terminal.FGBrightMagenta,
Number: terminal.FGRed, Number: terminal.FGRed,
Match: terminal.FGBlue, Match: terminal.FGBlue,
Normal: terminal.DefaultFGColor, Normal: terminal.DefaultFGColor,
@ -36,6 +56,8 @@ type Syntax struct {
FileType string FileType string
FileMatch []string FileMatch []string
LineCommentStart string LineCommentStart string
Keywords1 []string
Keywords2 []string
Flags int Flags int
} }
@ -44,16 +66,22 @@ var HLDB = []*Syntax{{
"c", "c",
[]string{".c", ".h", ".cpp"}, []string{".c", ".h", ".cpp"},
"//", "//",
HighlightNumbers | HighlightStrings, []string{"switch", "if", "while", "for", "break", "continue", "return", "else", "struct", "union", "typedef", "static", "enum", "class", "case"},
[]string{"int", "long", "double", "float", "char", "unsigned", "signed", "void"},
DoNumbers | DoStrings,
}, { }, {
"go", "go",
[]string{".go", "go.mod"}, []string{".go", "go.mod"},
"//", "//",
HighlightNumbers | HighlightStrings, []string{"break", "case", "chan", "const", "continue", "default", "defer", "else", "fallthrough", "for", "func", "go", "goto", "if", "import", "interface", "map", "package", "range", "return", "select", "struct", "switch", "type", "var", "iota"},
[]string{"bool", "uint8", "uint16", "uint32", "uint64", "int8", "int16", "int32", "int64", "float32", "float64", "complex64", "complex128", "byte", "rune", "uint", "int", "uintptr", "string", "struct", "type", "map"},
DoNumbers | DoStrings,
}, { }, {
"makefile", "makefile",
[]string{"Makefile", "makefile", "justfile"}, []string{"Makefile", "makefile", "justfile"},
"#", "#",
[]string{},
[]string{},
0, 0,
}} }}