Up to step 154 in Kilo tutorial (chapter 7)
Some checks failed
timw4mail/gilo/pipeline/head There was a failure building this commit

This commit is contained in:
Timothy Warren 2021-04-07 16:26:05 -04:00
parent 6cdb658d43
commit f78bbdabb2
8 changed files with 171 additions and 88 deletions

View File

@ -106,12 +106,17 @@ func (r *Row) update() {
} }
func (r *Row) updateSyntax() { func (r *Row) updateSyntax() {
for _, ch := range r.render { i := 0
for i < r.RenderSize() {
ch := r.render[i]
if unicode.IsDigit(ch) { if unicode.IsDigit(ch) {
r.Hl = append(r.Hl, highlight.Number) r.Hl = append(r.Hl, highlight.Number)
} else { } else {
r.Hl = append(r.Hl, highlight.Normal) r.Hl = append(r.Hl, highlight.Normal)
} }
i++
} }
} }

View File

@ -74,35 +74,39 @@ func (e *editor) drawRows(ab *gilo.Buffer) {
continue continue
} }
currentColor := terminal.DefaultFGColor e.drawFileRow(fileRow, ab)
row := e.document.GetRow(fileRow)
for i, ch := range row.Render(e.offset) {
if row.Hl[i] == highlight.Normal {
if currentColor != terminal.DefaultFGColor {
ab.Append(terminal.DefaultFGColor)
currentColor = terminal.DefaultFGColor
}
ab.AppendRune(ch)
} else {
color := highlight.SyntaxToColor(row.Hl[i])
if color != currentColor {
currentColor = color
ab.Append(color)
}
ab.AppendRune(ch)
}
}
ab.Append(terminal.DefaultFGColor)
} }
ab.AppendLn(terminal.ClearLine) ab.AppendLn(terminal.ClearLine)
} }
} }
func (e *editor) drawFileRow(fileRow int, ab *gilo.Buffer) {
currentColor := terminal.DefaultFGColor
row := e.document.GetRow(fileRow)
for i, ch := range row.Render(e.offset) {
if row.Hl[i] == highlight.Normal {
if currentColor != terminal.DefaultFGColor {
ab.Append(terminal.DefaultFGColor)
currentColor = terminal.DefaultFGColor
}
ab.AppendRune(ch)
} else {
color := highlight.SyntaxToColor(row.Hl[i])
if color != currentColor {
currentColor = color
ab.Append(color)
}
ab.AppendRune(ch)
}
}
ab.Append(terminal.DefaultFGColor)
}
func (e *editor) drawPlaceholderRow(y int, ab *gilo.Buffer) { func (e *editor) drawPlaceholderRow(y int, ab *gilo.Buffer) {
if e.document.RowCount() == 0 && y == e.screen.Rows/3 { if e.document.RowCount() == 0 && y == e.screen.Rows/3 {
welcome := fmt.Sprintf("Gilo editor -- version %s", gilo.Version) welcome := fmt.Sprintf("Gilo editor -- version %s", gilo.Version)

View File

@ -25,6 +25,7 @@ type editor struct {
offset *gilo.Point offset *gilo.Point
document *doc.Document document *doc.Document
status *statusMsg status *statusMsg
search *search
quitTimes uint8 quitTimes uint8
renderX int renderX int
} }
@ -49,6 +50,7 @@ func NewEditor() *editor {
offset, offset,
document, document,
status, status,
newSearch(),
gilo.QuitTimes, gilo.QuitTimes,
0, 0,
} }
@ -138,61 +140,6 @@ func (e *editor) prompt(prompt string, callback func(string, string)) string {
} }
} }
func (e *editor) find() {
savedCursor := e.cursor.Clone()
savedOffset := e.cursor.Clone()
lastMatch := -1
direction := 1
query := e.prompt("Search: %s (Use ESC/Arrows/Enter)", func(query string, ch string) {
if ch == string(key.Enter) || ch == string(key.Esc) {
lastMatch = -1
direction = 1
return
} else if ch == keyRight || ch == keyDown {
direction = 1
} else if ch == keyLeft || ch == keyUp {
direction = -1
} else {
lastMatch = -1
direction = 1
}
if lastMatch == -1 {
direction = 1
}
current := lastMatch
for i := 0; i < e.document.RowCount(); i++ {
current += direction
if current == -1 {
current = e.document.RowCount()
} else if current == e.document.RowCount() {
current = 0
}
row := e.document.GetRow(current)
matchIndex := row.Search(query)
if matchIndex != -1 {
lastMatch = current
e.cursor.Y = current
e.cursor.X = row.RenderXtoCursorX(matchIndex)
e.offset.Y = e.document.RowCount()
break
}
}
})
if query == "" {
e.cursor = savedCursor.Clone()
e.offset = savedOffset.Clone()
return
}
}
func (e *editor) insertChar(ch rune) { func (e *editor) insertChar(ch rune) {
if e.cursor.Y == e.document.RowCount() { if e.cursor.Y == e.document.RowCount() {
e.document.AppendRow("") e.document.AppendRow("")

View File

@ -6,4 +6,5 @@ package highlight
const ( const (
Normal = iota Normal = iota
Number Number
Match
) )

View File

@ -2,11 +2,19 @@ package highlight
import "timshome.page/gilo/terminal" import "timshome.page/gilo/terminal"
func SyntaxToColor(hl int) string { var syntaxColorMap = map[int]string{
switch hl { Number: terminal.FGRed,
case Number: Match: terminal.FGBlue,
return terminal.FGRed Normal: terminal.DefaultFGColor,
default: }
return terminal.DefaultFGColor
} // Take a highlighting type and map it to
// an ANSI color escape code for display
func SyntaxToColor(hl int) string {
color := syntaxColorMap[hl]
if len(color) == 0 {
color = terminal.DefaultFGColor
}
return color
} }

112
editor/search.go Normal file
View File

@ -0,0 +1,112 @@
package editor
import (
"timshome.page/gilo/editor/highlight"
"timshome.page/gilo/gilo"
"timshome.page/gilo/key"
)
type search struct {
cursor *gilo.Point
offset *gilo.Point
hlLine int
hl []int
direction int
lastMatch int
}
func newSearch() *search {
return &search{
cursor: gilo.DefaultPoint(),
offset: gilo.DefaultPoint(),
hlLine: -1,
hl: []int{},
lastMatch: -1,
direction: 1,
}
}
func (e *editor) find() {
e.search.cursor.X = e.cursor.X
e.search.cursor.Y = e.cursor.Y
e.search.offset.X = e.offset.X
e.search.offset.Y = e.offset.Y
query := e.prompt("Search: %s (Use ESC/Arrows/Enter)", e.findCallback)
if query == "" {
e.cursor.X = e.search.cursor.X
e.cursor.Y = e.search.cursor.Y
e.offset.X = e.search.offset.X
e.offset.Y = e.search.offset.Y
return
}
}
func (e *editor) findCallback(query string, ch string) {
if e.search.hlLine != -1 && e.search.hl != nil {
staleRow := e.document.GetRow(e.search.hlLine)
for i, val := range e.search.hl {
staleRow.Hl[i] = val
}
e.search.hl = nil
e.search.hlLine = -1
}
if ch == string(key.Enter) || ch == string(key.Esc) {
e.search.lastMatch = -1
e.search.direction = 1
return
} else if ch == keyRight || ch == keyDown {
e.search.direction = 1
} else if ch == keyLeft || ch == keyUp {
e.search.direction = -1
} else {
e.search.lastMatch = -1
e.search.direction = 1
}
if e.search.lastMatch == -1 {
e.search.direction = 1
}
if len(query) == 0 {
return
}
current := e.search.lastMatch
for i := 0; i < e.document.RowCount(); i++ {
current += e.search.direction
if current == -1 {
current = e.document.RowCount() - 1
} else if current == e.document.RowCount() {
current = 0
}
row := e.document.GetRow(current)
matchIndex := row.Search(query)
if matchIndex == -1 {
continue
}
e.search.lastMatch = current
e.cursor.Y = current
e.cursor.X = row.RenderXtoCursorX(matchIndex)
e.offset.Y = e.document.RowCount()
// Update highlighting of search result
e.search.hlLine = current
e.search.hl = make([]int, row.RenderSize())
for i, val := range row.Hl {
e.search.hl[i] = val
}
for x := matchIndex; x < matchIndex+len(query); x++ {
row.Hl[x] = highlight.Match
}
break
}
}

View File

@ -1,7 +1,6 @@
package main package main
import ( import (
"fmt"
"golang.org/x/term" "golang.org/x/term"
"os" "os"
"timshome.page/gilo/editor" "timshome.page/gilo/editor"

View File

@ -1,5 +1,7 @@
package key package key
import "unicode"
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// !Terminal Input Escape Code Sequences // !Terminal Input Escape Code Sequences
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
@ -12,7 +14,7 @@ const (
// Is this an ASCII character? // Is this an ASCII character?
func IsAscii(char rune) bool { func IsAscii(char rune) bool {
return char < 0x80 return char <= unicode.MaxASCII
} }
// Is this an ASCII ctrl character? // Is this an ASCII ctrl character?
@ -34,3 +36,8 @@ func Ctrl(char rune) rune {
return ch return ch
} }
// Is the character a general token separator type?
func IsSeparator(char rune) bool {
return unicode.IsPunct(char) || unicode.IsSpace(char)
}