Up to step 154 in Kilo tutorial (chapter 7)
Some checks failed
timw4mail/gilo/pipeline/head There was a failure building this commit
Some checks failed
timw4mail/gilo/pipeline/head There was a failure building this commit
This commit is contained in:
parent
6cdb658d43
commit
f78bbdabb2
@ -106,12 +106,17 @@ func (r *Row) update() {
|
||||
}
|
||||
|
||||
func (r *Row) updateSyntax() {
|
||||
for _, ch := range r.render {
|
||||
i := 0
|
||||
|
||||
for i < r.RenderSize() {
|
||||
ch := r.render[i]
|
||||
if unicode.IsDigit(ch) {
|
||||
r.Hl = append(r.Hl, highlight.Number)
|
||||
} else {
|
||||
r.Hl = append(r.Hl, highlight.Normal)
|
||||
}
|
||||
|
||||
i++
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -74,35 +74,39 @@ func (e *editor) drawRows(ab *gilo.Buffer) {
|
||||
continue
|
||||
}
|
||||
|
||||
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)
|
||||
e.drawFileRow(fileRow, ab)
|
||||
}
|
||||
|
||||
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) {
|
||||
if e.document.RowCount() == 0 && y == e.screen.Rows/3 {
|
||||
welcome := fmt.Sprintf("Gilo editor -- version %s", gilo.Version)
|
||||
|
@ -25,6 +25,7 @@ type editor struct {
|
||||
offset *gilo.Point
|
||||
document *doc.Document
|
||||
status *statusMsg
|
||||
search *search
|
||||
quitTimes uint8
|
||||
renderX int
|
||||
}
|
||||
@ -49,6 +50,7 @@ func NewEditor() *editor {
|
||||
offset,
|
||||
document,
|
||||
status,
|
||||
newSearch(),
|
||||
gilo.QuitTimes,
|
||||
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) {
|
||||
if e.cursor.Y == e.document.RowCount() {
|
||||
e.document.AppendRow("")
|
||||
|
@ -6,4 +6,5 @@ package highlight
|
||||
const (
|
||||
Normal = iota
|
||||
Number
|
||||
Match
|
||||
)
|
||||
|
@ -2,11 +2,19 @@ package highlight
|
||||
|
||||
import "timshome.page/gilo/terminal"
|
||||
|
||||
func SyntaxToColor(hl int) string {
|
||||
switch hl {
|
||||
case Number:
|
||||
return terminal.FGRed
|
||||
default:
|
||||
return terminal.DefaultFGColor
|
||||
}
|
||||
var syntaxColorMap = map[int]string{
|
||||
Number: terminal.FGRed,
|
||||
Match: terminal.FGBlue,
|
||||
Normal: 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
112
editor/search.go
Normal 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
|
||||
}
|
||||
}
|
1
gilo.go
1
gilo.go
@ -1,7 +1,6 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"golang.org/x/term"
|
||||
"os"
|
||||
"timshome.page/gilo/editor"
|
||||
|
@ -1,5 +1,7 @@
|
||||
package key
|
||||
|
||||
import "unicode"
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// !Terminal Input Escape Code Sequences
|
||||
// ----------------------------------------------------------------------------
|
||||
@ -12,7 +14,7 @@ const (
|
||||
|
||||
// Is this an ASCII character?
|
||||
func IsAscii(char rune) bool {
|
||||
return char < 0x80
|
||||
return char <= unicode.MaxASCII
|
||||
}
|
||||
|
||||
// Is this an ASCII ctrl character?
|
||||
@ -34,3 +36,8 @@ func Ctrl(char rune) rune {
|
||||
|
||||
return ch
|
||||
}
|
||||
|
||||
// Is the character a general token separator type?
|
||||
func IsSeparator(char rune) bool {
|
||||
return unicode.IsPunct(char) || unicode.IsSpace(char)
|
||||
}
|
Loading…
Reference in New Issue
Block a user