Update to chapter 7 step 161 in kilo tutorial
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
1b9c1744aa
commit
cc99f08747
1468
_code/kilo.c
Normal file
1468
_code/kilo.c
Normal file
File diff suppressed because it is too large
Load Diff
@ -19,7 +19,7 @@ type statusMsg struct {
|
|||||||
created time.Time
|
created time.Time
|
||||||
}
|
}
|
||||||
|
|
||||||
type editor struct {
|
type Editor struct {
|
||||||
screen *terminal.Screen
|
screen *terminal.Screen
|
||||||
cursor *gilo.Point
|
cursor *gilo.Point
|
||||||
offset *gilo.Point
|
offset *gilo.Point
|
||||||
@ -30,7 +30,7 @@ type editor struct {
|
|||||||
renderX int
|
renderX int
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewEditor() *editor {
|
func NewEditor() *Editor {
|
||||||
// Subtract rows for status bar and message bar/prompt
|
// Subtract rows for status bar and message bar/prompt
|
||||||
screen := terminal.Size()
|
screen := terminal.Size()
|
||||||
screen.Rows -= 2
|
screen.Rows -= 2
|
||||||
@ -40,7 +40,7 @@ func NewEditor() *editor {
|
|||||||
time.Now(),
|
time.Now(),
|
||||||
}
|
}
|
||||||
|
|
||||||
return &editor{
|
return &Editor{
|
||||||
screen,
|
screen,
|
||||||
gilo.DefaultPoint(),
|
gilo.DefaultPoint(),
|
||||||
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)
|
e.doc.Open(filename)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *editor) SetStatusMessage(template string, a ...interface{}) {
|
func (e *Editor) SetStatusMessage(template string, a ...interface{}) {
|
||||||
e.status = &statusMsg{
|
e.status = &statusMsg{
|
||||||
fmt.Sprintf(template, a...),
|
fmt.Sprintf(template, a...),
|
||||||
time.Now(),
|
time.Now(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *editor) ProcessKeypress() bool {
|
func (e *Editor) ProcessKeypress() bool {
|
||||||
ch, _ := terminal.ReadKey()
|
ch, _ := terminal.ReadKey()
|
||||||
|
|
||||||
return e.processKeypressChar(ch)
|
return e.processKeypressChar(ch)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *editor) save() {
|
func (e *Editor) save() {
|
||||||
if e.doc.Filename == "" {
|
if e.doc.Filename == "" {
|
||||||
e.doc.Filename = e.prompt("Save as: %s (ESC to cancel)", nil)
|
e.doc.Filename = e.prompt("Save as: %s (ESC to cancel)", nil)
|
||||||
if e.doc.Filename == "" {
|
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()
|
buf := gilo.NewBuffer()
|
||||||
|
|
||||||
// Show the prompt message
|
// 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() {
|
if e.cursor.Y == e.doc.RowCount() {
|
||||||
e.doc.AppendRow("")
|
e.doc.AppendRow("")
|
||||||
}
|
}
|
||||||
@ -145,7 +145,7 @@ func (e *editor) insertChar(ch rune) {
|
|||||||
e.cursor.X += 1
|
e.cursor.X += 1
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *editor) delChar() {
|
func (e *Editor) delChar() {
|
||||||
if e.cursor.Y == e.doc.RowCount() {
|
if e.cursor.Y == e.doc.RowCount() {
|
||||||
return
|
return
|
||||||
}
|
}
|
@ -4,12 +4,14 @@ import (
|
|||||||
"bufio"
|
"bufio"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
|
"timshome.page/gilo/editor/highlight"
|
||||||
"timshome.page/gilo/internal/gilo"
|
"timshome.page/gilo/internal/gilo"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Document struct {
|
type Document struct {
|
||||||
dirty bool
|
dirty bool
|
||||||
Filename string
|
Filename string
|
||||||
|
Syntax *highlight.Syntax
|
||||||
rows []*Row
|
rows []*Row
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -19,6 +21,7 @@ func NewDocument() *Document {
|
|||||||
return &Document{
|
return &Document{
|
||||||
false,
|
false,
|
||||||
"",
|
"",
|
||||||
|
nil,
|
||||||
rows,
|
rows,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -80,7 +83,7 @@ func (d *Document) GetRow(at int) *Row {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (d *Document) AppendRow(s string) {
|
func (d *Document) AppendRow(s string) {
|
||||||
newRow := newRow(s)
|
newRow := newRow(d, s)
|
||||||
newRow.update()
|
newRow.update()
|
||||||
d.rows = append(d.rows, newRow)
|
d.rows = append(d.rows, newRow)
|
||||||
|
|
||||||
@ -100,7 +103,7 @@ func (d *Document) InsertRow(at int, s string) {
|
|||||||
|
|
||||||
// Splice it back together
|
// Splice it back together
|
||||||
newRows = append(newRows, start...)
|
newRows = append(newRows, start...)
|
||||||
newRows = append(newRows, newRow(s))
|
newRows = append(newRows, newRow(d, s))
|
||||||
newRows = append(newRows, end...)
|
newRows = append(newRows, end...)
|
||||||
|
|
||||||
d.rows = newRows
|
d.rows = newRows
|
||||||
|
@ -9,12 +9,13 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type Row struct {
|
type Row struct {
|
||||||
|
parent *Document
|
||||||
chars []rune
|
chars []rune
|
||||||
render []rune
|
render []rune
|
||||||
Hl []int
|
Hl []int
|
||||||
}
|
}
|
||||||
|
|
||||||
func newRow(s string) *Row {
|
func newRow(parent *Document, s string) *Row {
|
||||||
var chars []rune
|
var chars []rune
|
||||||
var render []rune
|
var render []rune
|
||||||
|
|
||||||
@ -23,13 +24,14 @@ func newRow(s string) *Row {
|
|||||||
render = append(render, ch)
|
render = append(render, ch)
|
||||||
}
|
}
|
||||||
|
|
||||||
return &Row{chars, render, []int{}}
|
return &Row{parent, chars, render, []int{}}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Row) Size() int {
|
func (r *Row) Size() int {
|
||||||
return len(r.chars)
|
return len(r.chars)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// RenderSize is a convenient equivalent of row->rsize in kilo
|
||||||
func (r *Row) RenderSize() int {
|
func (r *Row) RenderSize() int {
|
||||||
return len(r.render)
|
return len(r.render)
|
||||||
}
|
}
|
||||||
@ -106,11 +108,21 @@ func (r *Row) update() {
|
|||||||
r.updateSyntax()
|
r.updateSyntax()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// updateSyntax is the equivalent of editorUpdateSyntax in kilo
|
||||||
func (r *Row) updateSyntax() {
|
func (r *Row) updateSyntax() {
|
||||||
i := 0
|
i := 0
|
||||||
|
s := r.parent.Syntax
|
||||||
prevSep := true
|
prevSep := true
|
||||||
|
|
||||||
r.Hl = make([]int, r.RenderSize())
|
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() {
|
for i < r.RenderSize() {
|
||||||
ch := r.render[i]
|
ch := r.render[i]
|
||||||
@ -120,14 +132,14 @@ func (r *Row) updateSyntax() {
|
|||||||
prevHl = r.Hl[i-1]
|
prevHl = r.Hl[i-1]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if s.Flags&highlight.HighlightNumbers == 1 {
|
||||||
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
|
||||||
i += 1
|
i += 1
|
||||||
prevSep = false
|
prevSep = false
|
||||||
continue
|
continue
|
||||||
} else {
|
}
|
||||||
r.Hl[i] = highlight.Normal
|
|
||||||
}
|
}
|
||||||
|
|
||||||
prevSep = key.IsSeparator(ch)
|
prevSep = key.IsSeparator(ch)
|
||||||
@ -139,6 +151,7 @@ func (r *Row) toString() string {
|
|||||||
return string(r.chars)
|
return string(r.chars)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CursorXToRenderX is the equivalent of editorRowCxToRx in kilo
|
||||||
func (r *Row) CursorXToRenderX(cursorX int) (renderX int) {
|
func (r *Row) CursorXToRenderX(cursorX int) (renderX int) {
|
||||||
renderX = 0
|
renderX = 0
|
||||||
|
|
||||||
@ -153,6 +166,7 @@ func (r *Row) CursorXToRenderX(cursorX int) (renderX int) {
|
|||||||
return renderX
|
return renderX
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// RenderXtoCursorX is the equivalent of editorRowRxToCx in kilo
|
||||||
func (r *Row) RenderXtoCursorX(renderX int) (cursorX int) {
|
func (r *Row) RenderXtoCursorX(renderX int) (cursorX int) {
|
||||||
currentRenderX := 0
|
currentRenderX := 0
|
||||||
cursorX = 0
|
cursorX = 0
|
||||||
|
@ -14,7 +14,7 @@ import (
|
|||||||
// !Editor Methods
|
// !Editor Methods
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
func (e *editor) RefreshScreen() {
|
func (e *Editor) RefreshScreen() {
|
||||||
e.scroll()
|
e.scroll()
|
||||||
|
|
||||||
ab := gilo.NewBuffer()
|
ab := gilo.NewBuffer()
|
||||||
@ -33,7 +33,7 @@ func (e *editor) RefreshScreen() {
|
|||||||
terminal.Write(ab.ToString())
|
terminal.Write(ab.ToString())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *editor) scroll() {
|
func (e *Editor) scroll() {
|
||||||
e.renderX = 0
|
e.renderX = 0
|
||||||
|
|
||||||
if e.cursor.Y < e.doc.RowCount() {
|
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++ {
|
for y := 0; y < e.screen.Rows; y++ {
|
||||||
fileRow := y + e.offset.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
|
currentColor := terminal.DefaultFGColor
|
||||||
row := e.doc.GetRow(fileRow)
|
row := e.doc.GetRow(fileRow)
|
||||||
|
|
||||||
@ -107,7 +107,7 @@ func (e *editor) drawFileRow(fileRow int, ab *gilo.Buffer) {
|
|||||||
ab.Append(terminal.DefaultFGColor)
|
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 {
|
if e.doc.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)
|
||||||
if len(welcome) > e.screen.Cols {
|
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
|
cols := e.screen.Cols
|
||||||
|
|
||||||
ab.Append(terminal.InvertColor)
|
ab.Append(terminal.InvertColor)
|
||||||
@ -156,7 +156,11 @@ func (e *editor) drawStatusBar(ab *gilo.Buffer) {
|
|||||||
return
|
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)
|
rlength := len(rightStatus)
|
||||||
statusLength := length + rlength
|
statusLength := length + rlength
|
||||||
|
|
||||||
@ -182,7 +186,7 @@ func (e *editor) drawStatusBar(ab *gilo.Buffer) {
|
|||||||
ab.Append(terminal.ResetColor)
|
ab.Append(terminal.ResetColor)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *editor) drawMessageBar(ab *gilo.Buffer) {
|
func (e *Editor) drawMessageBar(ab *gilo.Buffer) {
|
||||||
ab.Append("\r\n")
|
ab.Append("\r\n")
|
||||||
ab.Append(terminal.ClearLine)
|
ab.Append(terminal.ClearLine)
|
||||||
|
|
||||||
|
@ -8,3 +8,15 @@ const (
|
|||||||
Number
|
Number
|
||||||
Match
|
Match
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const HighlightNumbers = (1 << 0)
|
||||||
|
|
||||||
|
var HLDB = []*Syntax{{
|
||||||
|
"c",
|
||||||
|
[]string{".c", ".h", ".cpp"},
|
||||||
|
HighlightNumbers,
|
||||||
|
}, {
|
||||||
|
"go",
|
||||||
|
[]string{".go"},
|
||||||
|
HighlightNumbers,
|
||||||
|
}}
|
||||||
|
7
editor/highlight/syntax.go
Normal file
7
editor/highlight/syntax.go
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
package highlight
|
||||||
|
|
||||||
|
type Syntax struct {
|
||||||
|
FileType string
|
||||||
|
FileMatch []string
|
||||||
|
Flags int
|
||||||
|
}
|
@ -26,7 +26,7 @@ const (
|
|||||||
/**
|
/**
|
||||||
* Determine what to do with an individual character of input
|
* 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 {
|
switch ch {
|
||||||
case key.Ctrl('q'):
|
case key.Ctrl('q'):
|
||||||
if e.doc.IsDirty() && e.quitTimes > 0 {
|
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
|
* Determine what do do with a parsed ANSI escape sequence
|
||||||
*/
|
*/
|
||||||
func (e *editor) processKeypressStr(key string) {
|
func (e *Editor) processKeypressStr(key string) {
|
||||||
switch key {
|
switch key {
|
||||||
case keyUp,
|
case keyUp,
|
||||||
keyDown,
|
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
|
var row *document.Row
|
||||||
if e.cursor.Y >= e.doc.RowCount() {
|
if e.cursor.Y >= e.doc.RowCount() {
|
||||||
row = nil
|
row = nil
|
||||||
|
@ -27,7 +27,7 @@ func TestMoveCursor(t *testing.T) {
|
|||||||
e := NewEditor()
|
e := NewEditor()
|
||||||
|
|
||||||
if test.withFile {
|
if test.withFile {
|
||||||
e.Open("editor.go")
|
e.Open("Editor.go")
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, k := range test.keys {
|
for _, k := range test.keys {
|
||||||
|
@ -9,8 +9,8 @@ import (
|
|||||||
type search struct {
|
type search struct {
|
||||||
cursor *gilo.Point
|
cursor *gilo.Point
|
||||||
offset *gilo.Point
|
offset *gilo.Point
|
||||||
hlLine int
|
savedhlLine int
|
||||||
hl []int
|
savedhl []int
|
||||||
direction int
|
direction int
|
||||||
lastMatch int
|
lastMatch int
|
||||||
}
|
}
|
||||||
@ -19,14 +19,14 @@ func newSearch() *search {
|
|||||||
return &search{
|
return &search{
|
||||||
cursor: gilo.DefaultPoint(),
|
cursor: gilo.DefaultPoint(),
|
||||||
offset: gilo.DefaultPoint(),
|
offset: gilo.DefaultPoint(),
|
||||||
hlLine: -1,
|
savedhlLine: -1,
|
||||||
hl: []int{},
|
savedhl: []int{},
|
||||||
lastMatch: -1,
|
lastMatch: -1,
|
||||||
direction: 1,
|
direction: 1,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *editor) find() {
|
func (e *Editor) find() {
|
||||||
e.search.cursor.X = e.cursor.X
|
e.search.cursor.X = e.cursor.X
|
||||||
e.search.cursor.Y = e.cursor.Y
|
e.search.cursor.Y = e.cursor.Y
|
||||||
e.search.offset.X = e.offset.X
|
e.search.offset.X = e.offset.X
|
||||||
@ -44,14 +44,15 @@ func (e *editor) find() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *editor) findCallback(query string, ch string) {
|
func (e *Editor) findCallback(query string, ch string) {
|
||||||
if e.search.hlLine != -1 && e.search.hl != nil {
|
// If we highlighted a previous match, restore the original highlighting
|
||||||
staleRow := e.doc.GetRow(e.search.hlLine)
|
if e.search.savedhlLine != -1 && e.search.savedhl != nil {
|
||||||
for i, val := range e.search.hl {
|
staleRow := e.doc.GetRow(e.search.savedhlLine)
|
||||||
|
for i, val := range e.search.savedhl {
|
||||||
staleRow.Hl[i] = val
|
staleRow.Hl[i] = val
|
||||||
}
|
}
|
||||||
e.search.hl = nil
|
e.search.savedhl = nil
|
||||||
e.search.hlLine = -1
|
e.search.savedhlLine = -1
|
||||||
}
|
}
|
||||||
|
|
||||||
if ch == string(key.Enter) || ch == string(key.Esc) {
|
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.cursor.X = row.RenderXtoCursorX(matchIndex)
|
||||||
e.offset.Y = e.doc.RowCount()
|
e.offset.Y = e.doc.RowCount()
|
||||||
|
|
||||||
// Update highlighting of search result
|
// Save the current highlighting of where the search result is
|
||||||
e.search.hlLine = current
|
e.search.savedhlLine = current
|
||||||
e.search.hl = make([]int, row.RenderSize())
|
e.search.savedhl = make([]int, row.RenderSize())
|
||||||
for i, val := range row.Hl {
|
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++ {
|
for x := matchIndex; x < matchIndex+len(query); x++ {
|
||||||
row.Hl[x] = highlight.Match
|
row.Hl[x] = highlight.Match
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,7 @@ type Point struct {
|
|||||||
X int
|
X int
|
||||||
Y int
|
Y int
|
||||||
}
|
}
|
||||||
|
|
||||||
// DefaultPoint creates a Point at 0,0
|
// DefaultPoint creates a Point at 0,0
|
||||||
func DefaultPoint() *Point {
|
func DefaultPoint() *Point {
|
||||||
return &Point{0, 0}
|
return &Point{0, 0}
|
||||||
|
Loading…
Reference in New Issue
Block a user