Update to chapter 7 step 161 in kilo tutorial
Some checks failed
timw4mail/gilo/pipeline/head There was a failure building this commit

This commit is contained in:
Timothy Warren 2023-10-03 17:02:22 -04:00
parent 1b9c1744aa
commit cc99f08747
12 changed files with 1569 additions and 57 deletions

1468
_code/kilo.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -19,7 +19,7 @@ type statusMsg struct {
created time.Time
}
type editor struct {
type Editor struct {
screen *terminal.Screen
cursor *gilo.Point
offset *gilo.Point
@ -30,7 +30,7 @@ type editor struct {
renderX int
}
func NewEditor() *editor {
func NewEditor() *Editor {
// Subtract rows for status bar and message bar/prompt
screen := terminal.Size()
screen.Rows -= 2
@ -40,7 +40,7 @@ func NewEditor() *editor {
time.Now(),
}
return &editor{
return &Editor{
screen,
gilo.DefaultPoint(),
gilo.DefaultPoint(),
@ -52,24 +52,24 @@ func NewEditor() *editor {
}
}
func (e *editor) Open(filename string) {
func (e *Editor) Open(filename string) {
e.doc.Open(filename)
}
func (e *editor) SetStatusMessage(template string, a ...interface{}) {
func (e *Editor) SetStatusMessage(template string, a ...interface{}) {
e.status = &statusMsg{
fmt.Sprintf(template, a...),
time.Now(),
}
}
func (e *editor) ProcessKeypress() bool {
func (e *Editor) ProcessKeypress() bool {
ch, _ := terminal.ReadKey()
return e.processKeypressChar(ch)
}
func (e *editor) save() {
func (e *Editor) save() {
if e.doc.Filename == "" {
e.doc.Filename = e.prompt("Save as: %s (ESC to cancel)", nil)
if e.doc.Filename == "" {
@ -86,7 +86,7 @@ func (e *editor) save() {
}
}
func (e *editor) prompt(prompt string, callback func(string, string)) string {
func (e *Editor) prompt(prompt string, callback func(string, string)) string {
buf := gilo.NewBuffer()
// Show the prompt message
@ -136,7 +136,7 @@ func (e *editor) prompt(prompt string, callback func(string, string)) string {
}
}
func (e *editor) insertChar(ch rune) {
func (e *Editor) insertChar(ch rune) {
if e.cursor.Y == e.doc.RowCount() {
e.doc.AppendRow("")
}
@ -145,7 +145,7 @@ func (e *editor) insertChar(ch rune) {
e.cursor.X += 1
}
func (e *editor) delChar() {
func (e *Editor) delChar() {
if e.cursor.Y == e.doc.RowCount() {
return
}

View File

@ -4,12 +4,14 @@ import (
"bufio"
"log"
"os"
"timshome.page/gilo/editor/highlight"
"timshome.page/gilo/internal/gilo"
)
type Document struct {
dirty bool
Filename string
Syntax *highlight.Syntax
rows []*Row
}
@ -19,6 +21,7 @@ func NewDocument() *Document {
return &Document{
false,
"",
nil,
rows,
}
}
@ -80,7 +83,7 @@ func (d *Document) GetRow(at int) *Row {
}
func (d *Document) AppendRow(s string) {
newRow := newRow(s)
newRow := newRow(d, s)
newRow.update()
d.rows = append(d.rows, newRow)
@ -100,7 +103,7 @@ func (d *Document) InsertRow(at int, s string) {
// Splice it back together
newRows = append(newRows, start...)
newRows = append(newRows, newRow(s))
newRows = append(newRows, newRow(d, s))
newRows = append(newRows, end...)
d.rows = newRows

View File

@ -9,12 +9,13 @@ import (
)
type Row struct {
parent *Document
chars []rune
render []rune
Hl []int
}
func newRow(s string) *Row {
func newRow(parent *Document, s string) *Row {
var chars []rune
var render []rune
@ -23,13 +24,14 @@ func newRow(s string) *Row {
render = append(render, ch)
}
return &Row{chars, render, []int{}}
return &Row{parent, chars, render, []int{}}
}
func (r *Row) Size() int {
return len(r.chars)
}
// RenderSize is a convenient equivalent of row->rsize in kilo
func (r *Row) RenderSize() int {
return len(r.render)
}
@ -106,11 +108,21 @@ func (r *Row) update() {
r.updateSyntax()
}
// updateSyntax is the equivalent of editorUpdateSyntax in kilo
func (r *Row) updateSyntax() {
i := 0
s := r.parent.Syntax
prevSep := true
r.Hl = make([]int, r.RenderSize())
for x := range r.Hl {
r.Hl[x] = highlight.Normal
}
// Don't bother updating the syntax if there isn't any
if s == nil {
return
}
for i < r.RenderSize() {
ch := r.render[i]
@ -120,14 +132,14 @@ func (r *Row) updateSyntax() {
prevHl = r.Hl[i-1]
}
if s.Flags&highlight.HighlightNumbers == 1 {
if (unicode.IsDigit(ch) && (prevSep || prevHl == highlight.Number)) ||
(ch == '.' && prevHl == highlight.Number) {
r.Hl[i] = highlight.Number
i += 1
prevSep = false
continue
} else {
r.Hl[i] = highlight.Normal
}
}
prevSep = key.IsSeparator(ch)
@ -139,6 +151,7 @@ func (r *Row) toString() string {
return string(r.chars)
}
// CursorXToRenderX is the equivalent of editorRowCxToRx in kilo
func (r *Row) CursorXToRenderX(cursorX int) (renderX int) {
renderX = 0
@ -153,6 +166,7 @@ func (r *Row) CursorXToRenderX(cursorX int) (renderX int) {
return renderX
}
// RenderXtoCursorX is the equivalent of editorRowRxToCx in kilo
func (r *Row) RenderXtoCursorX(renderX int) (cursorX int) {
currentRenderX := 0
cursorX = 0

View File

@ -14,7 +14,7 @@ import (
// !Editor Methods
// ----------------------------------------------------------------------------
func (e *editor) RefreshScreen() {
func (e *Editor) RefreshScreen() {
e.scroll()
ab := gilo.NewBuffer()
@ -33,7 +33,7 @@ func (e *editor) RefreshScreen() {
terminal.Write(ab.ToString())
}
func (e *editor) scroll() {
func (e *Editor) scroll() {
e.renderX = 0
if e.cursor.Y < e.doc.RowCount() {
@ -57,7 +57,7 @@ func (e *editor) scroll() {
}
}
func (e *editor) drawRows(ab *gilo.Buffer) {
func (e *Editor) drawRows(ab *gilo.Buffer) {
for y := 0; y < e.screen.Rows; y++ {
fileRow := y + e.offset.Y
@ -81,7 +81,7 @@ func (e *editor) drawRows(ab *gilo.Buffer) {
}
}
func (e *editor) drawFileRow(fileRow int, ab *gilo.Buffer) {
func (e *Editor) drawFileRow(fileRow int, ab *gilo.Buffer) {
currentColor := terminal.DefaultFGColor
row := e.doc.GetRow(fileRow)
@ -107,7 +107,7 @@ func (e *editor) drawFileRow(fileRow int, ab *gilo.Buffer) {
ab.Append(terminal.DefaultFGColor)
}
func (e *editor) drawPlaceholderRow(y int, ab *gilo.Buffer) {
func (e *Editor) drawPlaceholderRow(y int, ab *gilo.Buffer) {
if e.doc.RowCount() == 0 && y == e.screen.Rows/3 {
welcome := fmt.Sprintf("Gilo editor -- version %s", gilo.Version)
if len(welcome) > e.screen.Cols {
@ -131,7 +131,7 @@ func (e *editor) drawPlaceholderRow(y int, ab *gilo.Buffer) {
}
}
func (e *editor) drawStatusBar(ab *gilo.Buffer) {
func (e *Editor) drawStatusBar(ab *gilo.Buffer) {
cols := e.screen.Cols
ab.Append(terminal.InvertColor)
@ -156,7 +156,11 @@ func (e *editor) drawStatusBar(ab *gilo.Buffer) {
return
}
rightStatus := fmt.Sprintf("%d/%d", e.cursor.Y+1, e.doc.RowCount())
syntaxName := "no filetype"
if e.doc.Syntax != nil {
syntaxName = e.doc.Syntax.FileType
}
rightStatus := fmt.Sprintf("%s | %d/%d", syntaxName, e.cursor.Y+1, e.doc.RowCount())
rlength := len(rightStatus)
statusLength := length + rlength
@ -182,7 +186,7 @@ func (e *editor) drawStatusBar(ab *gilo.Buffer) {
ab.Append(terminal.ResetColor)
}
func (e *editor) drawMessageBar(ab *gilo.Buffer) {
func (e *Editor) drawMessageBar(ab *gilo.Buffer) {
ab.Append("\r\n")
ab.Append(terminal.ClearLine)

View File

@ -8,3 +8,15 @@ const (
Number
Match
)
const HighlightNumbers = (1 << 0)
var HLDB = []*Syntax{{
"c",
[]string{".c", ".h", ".cpp"},
HighlightNumbers,
}, {
"go",
[]string{".go"},
HighlightNumbers,
}}

View File

@ -0,0 +1,7 @@
package highlight
type Syntax struct {
FileType string
FileMatch []string
Flags int
}

View File

@ -26,7 +26,7 @@ const (
/**
* Determine what to do with an individual character of input
*/
func (e *editor) processKeypressChar(ch rune) bool {
func (e *Editor) processKeypressChar(ch rune) bool {
switch ch {
case key.Ctrl('q'):
if e.doc.IsDirty() && e.quitTimes > 0 {
@ -85,7 +85,7 @@ func (e *editor) processKeypressChar(ch rune) bool {
/**
* Determine what do do with a parsed ANSI escape sequence
*/
func (e *editor) processKeypressStr(key string) {
func (e *Editor) processKeypressStr(key string) {
switch key {
case keyUp,
keyDown,
@ -104,7 +104,7 @@ func (e *editor) processKeypressStr(key string) {
}
}
func (e *editor) moveCursor(key string) {
func (e *Editor) moveCursor(key string) {
var row *document.Row
if e.cursor.Y >= e.doc.RowCount() {
row = nil

View File

@ -27,7 +27,7 @@ func TestMoveCursor(t *testing.T) {
e := NewEditor()
if test.withFile {
e.Open("editor.go")
e.Open("Editor.go")
}
for _, k := range test.keys {

View File

@ -9,8 +9,8 @@ import (
type search struct {
cursor *gilo.Point
offset *gilo.Point
hlLine int
hl []int
savedhlLine int
savedhl []int
direction int
lastMatch int
}
@ -19,14 +19,14 @@ func newSearch() *search {
return &search{
cursor: gilo.DefaultPoint(),
offset: gilo.DefaultPoint(),
hlLine: -1,
hl: []int{},
savedhlLine: -1,
savedhl: []int{},
lastMatch: -1,
direction: 1,
}
}
func (e *editor) find() {
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
@ -44,14 +44,15 @@ func (e *editor) find() {
}
}
func (e *editor) findCallback(query string, ch string) {
if e.search.hlLine != -1 && e.search.hl != nil {
staleRow := e.doc.GetRow(e.search.hlLine)
for i, val := range e.search.hl {
func (e *Editor) findCallback(query string, ch string) {
// If we highlighted a previous match, restore the original highlighting
if e.search.savedhlLine != -1 && e.search.savedhl != nil {
staleRow := e.doc.GetRow(e.search.savedhlLine)
for i, val := range e.search.savedhl {
staleRow.Hl[i] = val
}
e.search.hl = nil
e.search.hlLine = -1
e.search.savedhl = nil
e.search.savedhlLine = -1
}
if ch == string(key.Enter) || ch == string(key.Esc) {
@ -97,12 +98,14 @@ func (e *editor) findCallback(query string, ch string) {
e.cursor.X = row.RenderXtoCursorX(matchIndex)
e.offset.Y = e.doc.RowCount()
// Update highlighting of search result
e.search.hlLine = current
e.search.hl = make([]int, row.RenderSize())
// Save the current highlighting of where the search result is
e.search.savedhlLine = current
e.search.savedhl = make([]int, row.RenderSize())
for i, val := range row.Hl {
e.search.hl[i] = val
e.search.savedhl[i] = val
}
// Update highlighting of search result
for x := matchIndex; x < matchIndex+len(query); x++ {
row.Hl[x] = highlight.Match
}

View File

@ -6,6 +6,7 @@ type Point struct {
X int
Y int
}
// DefaultPoint creates a Point at 0,0
func DefaultPoint() *Point {
return &Point{0, 0}