From 69709a1cb4e7ad60e1d13419d915c24f05a82f13 Mon Sep 17 00:00:00 2001 From: Timothy Warren Date: Thu, 5 Oct 2023 11:03:08 -0400 Subject: [PATCH] Highlight keywords, and fix emoji rendering issue --- editor/document/row.go | 53 +++++++++++++++++-- editor/draw.go | 5 +- editor/highlight/constants.go | 17 ------ editor/highlight/{syntax.go => highlight.go} | 42 ++++++++++++--- .../{syntax_test.go => highlight_test.go} | 0 5 files changed, 89 insertions(+), 28 deletions(-) delete mode 100644 editor/highlight/constants.go rename editor/highlight/{syntax.go => highlight.go} (51%) rename editor/highlight/{syntax_test.go => highlight_test.go} (100%) diff --git a/editor/document/row.go b/editor/document/row.go index 9b96ce9..160e401 100644 --- a/editor/document/row.go +++ b/editor/document/row.go @@ -40,6 +40,12 @@ func (r *Row) Render(at *gilo.Point) string { 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 { return strings.Index(string(r.render), query) } @@ -122,10 +128,14 @@ func (r *Row) updateSyntax() { return } + renderStr := string(r.render) + keywords1 := s.Keywords1 + keywords2 := s.Keywords2 + var scsIndex int = -1 scs := s.LineCommentStart if len(scs) > 0 { - scsIndex = strings.Index(string(r.render), scs) + scsIndex = strings.Index(renderStr, scs) } prevSep := true @@ -148,7 +158,7 @@ func (r *Row) updateSyntax() { } // String literals - if s.Flags&highlight.HighlightStrings == highlight.HighlightStrings { + if s.Flags&highlight.DoStrings == highlight.DoStrings { // At the start of a string literal if inString == '0' && (ch == '"' || ch == '\'') { inString = ch @@ -181,7 +191,7 @@ func (r *Row) updateSyntax() { } // Numeric literals - if s.Flags&highlight.HighlightNumbers == highlight.HighlightNumbers { + if s.Flags&highlight.DoNumbers == highlight.DoNumbers { if (unicode.IsDigit(ch) && (prevSep || prevHl == highlight.Number)) || (ch == '.' && prevHl == 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) i++ } diff --git a/editor/draw.go b/editor/draw.go index 464aa81..3b867be 100644 --- a/editor/draw.go +++ b/editor/draw.go @@ -85,7 +85,10 @@ func (e *Editor) drawFileRow(fileRow int, ab *gilo.Buffer) { currentColor := terminal.DefaultFGColor 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 currentColor != terminal.DefaultFGColor { ab.Append(terminal.DefaultFGColor) diff --git a/editor/highlight/constants.go b/editor/highlight/constants.go deleted file mode 100644 index d744e36..0000000 --- a/editor/highlight/constants.go +++ /dev/null @@ -1,17 +0,0 @@ -package highlight - -// ---------------------------------------------------------------------------- -// !Syntax Highlighting Constants -// ---------------------------------------------------------------------------- -const ( - Normal = iota - Comment - String - Number - Match -) - -const ( - HighlightNumbers = 1 << 0 - HighlightStrings = 1 << 1 -) diff --git a/editor/highlight/syntax.go b/editor/highlight/highlight.go similarity index 51% rename from editor/highlight/syntax.go rename to editor/highlight/highlight.go index 4d85bf1..83ed119 100644 --- a/editor/highlight/syntax.go +++ b/editor/highlight/highlight.go @@ -5,16 +5,36 @@ import ( "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 // ------------------------------------------------------------------ var syntaxColorMap = map[int]string{ - Comment: terminal.FGCyan, - String: terminal.FGMagenta, - Number: terminal.FGRed, - Match: terminal.FGBlue, - Normal: terminal.DefaultFGColor, + Comment: terminal.FGCyan, + Keyword1: terminal.FGYellow, + Keyword2: terminal.FGGreen, + String: terminal.FGBrightMagenta, + Number: terminal.FGRed, + Match: terminal.FGBlue, + Normal: terminal.DefaultFGColor, } // SyntaxToColor Take a highlighting type and map it to @@ -36,6 +56,8 @@ type Syntax struct { FileType string FileMatch []string LineCommentStart string + Keywords1 []string + Keywords2 []string Flags int } @@ -44,16 +66,22 @@ var HLDB = []*Syntax{{ "c", []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", []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", []string{"Makefile", "makefile", "justfile"}, "#", + []string{}, + []string{}, 0, }} diff --git a/editor/highlight/syntax_test.go b/editor/highlight/highlight_test.go similarity index 100% rename from editor/highlight/syntax_test.go rename to editor/highlight/highlight_test.go