From d5e8f64ab840a3d6d38978611ef634b8d3b0cba7 Mon Sep 17 00:00:00 2001 From: Glushin Nikita Date: Wed, 7 Jun 2023 15:38:51 +0300 Subject: [PATCH 1/7] first commit --- main.go | 61 ++- textmanager/textmanager.go | 1006 +++++++++++++++++++----------------- 2 files changed, 568 insertions(+), 499 deletions(-) diff --git a/main.go b/main.go index 78cde9f..4952fa3 100644 --- a/main.go +++ b/main.go @@ -304,24 +304,23 @@ func (e *Engine) SetFont(filename string, sizePx int32, spaceBetween int32, colo sizePt := int(float32(sizePx) * scaleFactor) //println(scaleFactor, sizePt) - var ttfFont *ttf.Font + var ttfFont *ttf.Font ttfFont, err = ttf.OpenFont(filename, sizePt) - if err != nil { - // open default font from memory - RWops, err := sdl.RWFromMem(FontBytes) - - if err != nil { - return err - } + if err != nil { + // open default font from memory + RWops, err := sdl.RWFromMem(FontBytes) - ttfFont, err = ttf.OpenFontRW(RWops, 1, sizePt) + if err != nil { + return err + } - if err != nil { - return err - } - } + ttfFont, err = ttf.OpenFontRW(RWops, 1, sizePt) + if err != nil { + return err + } + } if e.font.ttfFont != nil { e.font.ttfFont.Close() @@ -340,34 +339,34 @@ func (e *Engine) SetFont(filename string, sizePx int32, spaceBetween int32, colo } func getScaleFactor(fontFilename string) (float32, error) { - var ( - ttfFont *ttf.Font - RWops *sdl.RWops - err error - tmpSize = 100 - ) + var ( + ttfFont *ttf.Font + RWops *sdl.RWops + err error + tmpSize = 100 + ) ttfFont, err = ttf.OpenFont(fontFilename, tmpSize) - if err != nil { - // open default font from memory - RWops, err = sdl.RWFromMem(FontBytes) + if err != nil { + // open default font from memory + RWops, err = sdl.RWFromMem(FontBytes) - if err != nil { - return 1, err - } + if err != nil { + return 1, err + } - ttfFont, err = ttf.OpenFontRW(RWops, 1, tmpSize) + ttfFont, err = ttf.OpenFontRW(RWops, 1, tmpSize) - if err != nil { - return 1, err - } - } + if err != nil { + return 1, err + } + } defer ttfFont.Close() var maxH int32 = 0 for _, c := range AllSupportedChars { - surface, err := ttfFont.RenderGlyphBlended(c, sdl.Color{R: 0, G: 0, B: 0, A: 0}) + surface, err := ttfFont.RenderGlyphBlended(c, sdl.Color{R: 0, G: 0, B: 0, A: 0}) if err != nil { return 1, err } diff --git a/textmanager/textmanager.go b/textmanager/textmanager.go index b8fd227..07ccf43 100644 --- a/textmanager/textmanager.go +++ b/textmanager/textmanager.go @@ -1,83 +1,91 @@ package textmanager import ( - "Type2gether/list" - "errors" + "Type2gether/list" + "errors" ) const ( - endl = '\n' + endl = '\n' ) -// type Line struct { -// list list.List[rune] -// } -// Cursor указывает на текущий элемент, а не на злемент за ним -// Line теперь представляем не как наследуемую структуру от list.List[rune], а как list.List[rune] сам по себе. -// чтобы создать новую строку, надо использовать line := new(list.List[rune]) -// все вызовы остаются, как прежде +var ( + TokensColor = map[string]uint32{ + "for": 0xDC42DDFF, + "while": 0x51D718FF, + "if": 0x8A6CD5FF, + "int": 0xF5A58DFF, + "aboba": 0x0893FCFF, + } + MaxTokenLength int +) + +type Char struct { + Value rune + Color uint32 +} type Cursor struct { - LineIter *list.Node[*list.List[rune]] - CharIter *list.Node[rune] - Id int64 - Row int32 - Col int32 - Color uint32 - - ScreenLeft int32 - - ScreenHead *Border - ScreenTail *Border - ScreenRow int32 - ScreenCol int32 + LineIter *list.Node[*list.List[Char]] + CharIter *list.Node[Char] + Id int64 + Row int32 + Col int32 + Color uint32 + + ScreenLeft int32 + + ScreenHead *Border + ScreenTail *Border + ScreenRow int32 + ScreenCol int32 } //Эта структура нужна для скрола //Эта структура нужна для отрисовки нумерации строк type Border struct { - LineIter *list.Node[*list.List[rune]] - RowNumber int32 + LineIter *list.Node[*list.List[Char]] + RowNumber int32 } func (border *Border) Up() error { - if border.LineIter == nil { - return errors.New("lineIter is nil") - } + if border.LineIter == nil { + return errors.New("lineIter is nil") + } - if border.LineIter.GetPrev() == nil { - return errors.New("the first line") - } + if border.LineIter.GetPrev() == nil { + return errors.New("the first line") + } - border.LineIter = border.LineIter.GetPrev() - border.RowNumber-- - return nil + border.LineIter = border.LineIter.GetPrev() + border.RowNumber-- + return nil } func (border *Border) Down() error { - if border.LineIter == nil { - return errors.New("lineIter is nil") - } + if border.LineIter == nil { + return errors.New("lineIter is nil") + } - if border.LineIter.GetNext() == nil { - return errors.New("last line") - } + if border.LineIter.GetNext() == nil { + return errors.New("last line") + } - border.LineIter = border.LineIter.GetNext() - border.RowNumber++ - return nil + border.LineIter = border.LineIter.GetNext() + border.RowNumber++ + return nil } func (cur *Cursor) ScrollUp() { - if err := cur.ScreenHead.Up(); err == nil { - cur.ScreenTail.Up() - } + if err := cur.ScreenHead.Up(); err == nil { + cur.ScreenTail.Up() + } } func (cur *Cursor) ScrollDown() { - if err := cur.ScreenTail.Down(); err == nil { - cur.ScreenHead.Down() - } + if err := cur.ScreenTail.Down(); err == nil { + cur.ScreenHead.Down() + } } /* @@ -87,54 +95,62 @@ type Line struct { width int32 } */ + type Text struct { - list.List[*list.List[rune]] - // скорее всего не нужен тк в List есть аттрибут lenght / size int64 - Cursors []*Cursor + list.List[*list.List[Char]] + // скорее всего не нужен тк в List есть аттрибут lenght / size int64 + Cursors []*Cursor +} + +func InitMaxTokenLength() { + for k := range TokensColor { + if len(k) > MaxTokenLength { + MaxTokenLength = len(k) + } + } } func NewText() *Text { - t := new(Text) - t.PushBack(new(list.List[rune])) - // for _, cur := range t.Cursors { - // cur.ScreenHead.LineIter = t.GetHead() - // cur.ScreenTail.LineIter = t.GetTail() - // } - return t + t := new(Text) + t.PushBack(new(list.List[Char])) + + InitMaxTokenLength() + + return t } // TODO написать присвоение id для курсора // TODO на данном этапе при создании NewCursor просто всегда будем 0 в него передавать, когда будем писать серверную часть нужно будет определиться с созданием Id func NewCursor(Id int64, ScreenRow, ScreenCol int32) *Cursor { - c := new(Cursor) - c.Row = 0 - c.Col = -1 - c.Id = Id - c.ScreenRow = ScreenRow - c.ScreenCol = ScreenCol - c.ScreenLeft = 0 - c.ScreenHead = &Border{RowNumber: 0} - c.ScreenTail = &Border{RowNumber: 0} - return c + c := new(Cursor) + c.Row = 0 + c.Col = -1 + c.Id = Id + c.ScreenRow = ScreenRow + c.ScreenCol = ScreenCol + c.ScreenLeft = 0 + c.ScreenHead = &Border{RowNumber: 0} + c.ScreenTail = &Border{RowNumber: 0} + return c } func (t *Text) SetCursorStartPosition(cursorId int64) { - cur := t.Cursors[cursorId] - cur.Row = 0 - cur.LineIter = t.GetHead() - - cur.Col = -1 - cur.CharIter = nil - - cur.ScreenLeft = 0 - cur.ScreenHead = &Border{LineIter: t.GetHead(), RowNumber: 0} // Егор сказал, что выстрелит, но куда... (создаем новый объект, а не меняем старый) - - cur.ScreenTail = &Border{LineIter: t.GetHead(), RowNumber: 0} - for i := 1; i < int(t.Cursors[cursorId].ScreenRow); i++ { - if err := cur.ScreenTail.Down(); err != nil { - return - } - } + cur := t.Cursors[cursorId] + cur.Row = 0 + cur.LineIter = t.GetHead() + + cur.Col = -1 + cur.CharIter = nil + + cur.ScreenLeft = 0 + cur.ScreenHead = &Border{LineIter: t.GetHead(), RowNumber: 0} // Егор сказал, что выстрелит, но куда... (создаем новый объект, а не меняем старый) + + cur.ScreenTail = &Border{LineIter: t.GetHead(), RowNumber: 0} + for i := 1; i < int(t.Cursors[cursorId].ScreenRow); i++ { + if err := cur.ScreenTail.Down(); err != nil { + return + } + } } // TODO сделать красиво =) @@ -143,439 +159,493 @@ func (t *Text) SetCursorStartPosition(cursorId int64) { // иначе откатываем только ячейку func (t *Text) InsertCharBefore(cursorId int64, value rune) error { - err := t.InsertCharAfter(cursorId, value) - if err != nil { - return err - } - t.Cursors[cursorId].MoveLeft() - return nil + err := t.InsertCharAfter(cursorId, value) + if err != nil { + return err + } + t.Cursors[cursorId].MoveLeft() + return nil } func (t *Text) InsertCharAfter(cursorId int64, value rune) error { - cur := t.Cursors[cursorId] + cur := t.Cursors[cursorId] - if cur.CharIter == nil { - err := cur.LineIter.GetValue().PushFront(value) + if cur.CharIter == nil { + err := cur.LineIter.GetValue().PushFront(Char{Value: value, Color: 0x000000FF}) - if err != nil { - //printtln(err) - return err - } + if err != nil { + //printtln(err) + return err + } - cur.CharIter = cur.LineIter.GetValue().GetHead() - cur.Col = 0 - return nil - } + cur.CharIter = cur.LineIter.GetValue().GetHead() + cur.Col = 0 + t.DetectToken(cursorId) + return nil + } - err := cur.LineIter.GetValue().InsertAfter(value, cur.CharIter) + err := cur.LineIter.GetValue().InsertAfter(Char{Value: value, Color: 0x000000FF}, cur.CharIter) - if err != nil { - return err - } + if err != nil { + return err + } - cur.CharIter = cur.CharIter.GetNext() - cur.Col++ - return nil + cur.CharIter = cur.CharIter.GetNext() + cur.Col++ + t.DetectToken(cursorId) + return nil +} + +func (t *Text) DetectToken(cursorId int64) error { + if t.Cursors[cursorId].CharIter == nil { + return errors.New("CharIter is nil") + } + + var ( + ptr = t.Cursors[cursorId].CharIter.GetPrev() + left = t.Cursors[cursorId].CharIter + right = left + ) + + if ptr != nil { + for ptr.GetPrev() != nil && ptr.GetPrev().GetValue().Value != ' ' { + ptr = ptr.GetPrev() + } + left = ptr + } + + ptr = t.Cursors[cursorId].CharIter.GetNext() + if ptr != nil { + for ptr.GetNext() != nil && ptr.GetNext().GetValue().Value != ' ' { + ptr = ptr.GetNext() + } + right = ptr + } + + ptr = left + curToken := "" + for ptr != right.GetNext() { + if ptr.GetValue().Value == ' ' { + if color, ok := TokensColor[curToken]; ok { + val := left.GetValue() + val.Color = color + left.SetValue(val) + left = ptr.GetNext() + println("token found: ", curToken) + curToken = "" + } + } else { + curToken += string(ptr.GetValue().Value) + } + ptr = ptr.GetNext() + } + if color, ok := TokensColor[curToken]; ok { + val := left.GetValue() + val.Color = color + left.SetValue(val) + println("token found: ", curToken) + } + + return nil } // TODO validation func (t *Text) Paste(data string, cursorId int64) error { - //cur := t.Cursors[cursorId] - var err error - //println("data: ", data) - // TODO замена на before и перевернуть цикл - for _, e := range data { - if e == '\n' { - //println("\\n") - err = t.InsertLineAfter(cursorId) - } else { - err = t.InsertCharAfter(cursorId, e) - } - - if err != nil { - return err - } - } - - return nil + //cur := t.Cursors[cursorId] + var err error + //println("data: ", data) + // TODO замена на before и перевернуть цикл + for _, e := range data { + if e == '\n' { + //println("\\n") + err = t.InsertLineAfter(cursorId) + } else { + err = t.InsertCharAfter(cursorId, e) + } + + if err != nil { + return err + } + } + + return nil } func (t *Text) InsertLineAfter(cursorId int64) error { - cur := t.Cursors[cursorId] - - if cur.CharIter == nil { - line := new(list.List[rune]) - if cur.LineIter.GetValue().GetTail() != nil { - // line isn't empty - err := t.InsertAfter(line, cur.LineIter) - - if err != nil { - return err - } - - if cur.ScreenTail.RowNumber-cur.ScreenHead.RowNumber+1 >= cur.ScreenRow { - if cur.LineIter == cur.ScreenTail.LineIter { - cur.ScrollDown() - } else { - cur.ScreenTail.Up() - cur.ScreenTail.RowNumber++ - } - } else { - if cur.LineIter == cur.ScreenTail.LineIter { - cur.ScreenTail.Down() - } else { - cur.ScreenTail.RowNumber++ - } - } - - cur.LineIter.GetValue().CopyTo(cur.LineIter.GetNext().GetValue()) - cur.LineIter.GetValue().Clear() - - cur.LineIter = cur.LineIter.GetNext() - cur.CharIter = nil - - // cur.ScrollDown() - //printtln("head & tail", cur.ScreenHead.RowNumber, cur.ScreenTail.RowNumber) - - cur.Row++ - cur.Col = -1 - return nil - } - // line is empty - err := t.InsertAfter(line, cur.LineIter) - - if err != nil { - return err - } - - if cur.ScreenTail.RowNumber-cur.ScreenHead.RowNumber+1 >= cur.ScreenRow { - if cur.LineIter == cur.ScreenTail.LineIter { - cur.ScrollDown() - } else { - cur.ScreenTail.Up() - cur.ScreenTail.RowNumber++ - } - } else { - if cur.LineIter == cur.ScreenTail.LineIter { - cur.ScreenTail.Down() - } else { - cur.ScreenTail.RowNumber++ - } - } - - cur.LineIter = cur.LineIter.GetNext() - cur.CharIter = cur.LineIter.GetValue().GetHead() - - // cur.ScrollDown() - - cur.Row++ - cur.Col = -1 - return nil - } - - oldLineIter := cur.LineIter - lst, err := oldLineIter.GetValue().Split(cur.CharIter.GetNext()) - - if err != nil { - return err - } - - node := &list.Node[*list.List[rune]]{} - node.SetValue(lst) - - node.SetPrev(oldLineIter) - node.SetNext(oldLineIter.GetNext()) - if oldLineIter.GetNext() != nil { - oldLineIter.GetNext().SetPrev(node) - } else { - t.SetTail(node) - } - oldLineIter.SetNext(node) - - if cur.ScreenTail.RowNumber-cur.ScreenHead.RowNumber+1 >= cur.ScreenRow { - if cur.LineIter == cur.ScreenTail.LineIter { - cur.ScrollDown() - } else { - cur.ScreenTail.Up() - cur.ScreenTail.RowNumber++ - } - } else { - if cur.LineIter == cur.ScreenTail.LineIter { - cur.ScreenTail.Down() - } else { - cur.ScreenTail.RowNumber++ - } - } - - cur.LineIter = node - cur.CharIter = nil - - // cur.ScrollDown() - - cur.Row++ - cur.Col = -1 - return nil + cur := t.Cursors[cursorId] + + if cur.CharIter == nil { + line := new(list.List[Char]) + if cur.LineIter.GetValue().GetTail() != nil { + // line isn't empty + err := t.InsertAfter(line, cur.LineIter) + + if err != nil { + return err + } + + if cur.ScreenTail.RowNumber-cur.ScreenHead.RowNumber+1 >= cur.ScreenRow { + if cur.LineIter == cur.ScreenTail.LineIter { + cur.ScrollDown() + } else { + cur.ScreenTail.Up() + cur.ScreenTail.RowNumber++ + } + } else { + if cur.LineIter == cur.ScreenTail.LineIter { + cur.ScreenTail.Down() + } else { + cur.ScreenTail.RowNumber++ + } + } + + cur.LineIter.GetValue().CopyTo(cur.LineIter.GetNext().GetValue()) + cur.LineIter.GetValue().Clear() + + cur.LineIter = cur.LineIter.GetNext() + cur.CharIter = nil + + // cur.ScrollDown() + //printtln("head & tail", cur.ScreenHead.RowNumber, cur.ScreenTail.RowNumber) + + cur.Row++ + cur.Col = -1 + return nil + } + // line is empty + err := t.InsertAfter(line, cur.LineIter) + + if err != nil { + return err + } + + if cur.ScreenTail.RowNumber-cur.ScreenHead.RowNumber+1 >= cur.ScreenRow { + if cur.LineIter == cur.ScreenTail.LineIter { + cur.ScrollDown() + } else { + cur.ScreenTail.Up() + cur.ScreenTail.RowNumber++ + } + } else { + if cur.LineIter == cur.ScreenTail.LineIter { + cur.ScreenTail.Down() + } else { + cur.ScreenTail.RowNumber++ + } + } + + cur.LineIter = cur.LineIter.GetNext() + cur.CharIter = cur.LineIter.GetValue().GetHead() + + // cur.ScrollDown() + + cur.Row++ + cur.Col = -1 + return nil + } + + oldLineIter := cur.LineIter + lst, err := oldLineIter.GetValue().Split(cur.CharIter.GetNext()) + + if err != nil { + return err + } + + node := &list.Node[*list.List[Char]]{} + node.SetValue(lst) + + node.SetPrev(oldLineIter) + node.SetNext(oldLineIter.GetNext()) + if oldLineIter.GetNext() != nil { + oldLineIter.GetNext().SetPrev(node) + } else { + t.SetTail(node) + } + oldLineIter.SetNext(node) + + if cur.ScreenTail.RowNumber-cur.ScreenHead.RowNumber+1 >= cur.ScreenRow { + if cur.LineIter == cur.ScreenTail.LineIter { + cur.ScrollDown() + } else { + cur.ScreenTail.Up() + cur.ScreenTail.RowNumber++ + } + } else { + if cur.LineIter == cur.ScreenTail.LineIter { + cur.ScreenTail.Down() + } else { + cur.ScreenTail.RowNumber++ + } + } + + cur.LineIter = node + cur.CharIter = nil + + // cur.ScrollDown() + + cur.Row++ + cur.Col = -1 + return nil } // TODO cur.CharIter == nil не значит, что строка пустая || Нужно проверить везде в коде это func (t *Text) RemoveCharBefore(cursorId int64) error { - cur := t.Cursors[cursorId] - - if cur.LineIter == nil { - //printtln("Press 'F', пацан к успеху шёл, Какой успех, раздался смех") - return nil - } - - if cur.CharIter == nil { - if cur.LineIter.GetPrev() == nil { - return nil - } - - if cur.ScreenTail.LineIter == cur.ScreenHead.LineIter { - cur.ScrollUp() - } else if cur.ScreenTail.LineIter == cur.LineIter { - if cur.LineIter.GetNext() == nil { - cur.ScreenTail.Up() - } else { - if err := cur.ScreenTail.Down(); err == nil { - cur.ScreenTail.RowNumber-- - } - } - } else if cur.ScreenHead.LineIter == cur.LineIter { - if cur.ScreenTail.RowNumber-cur.ScreenHead.RowNumber+1 >= cur.ScreenRow { - if err := cur.ScreenHead.Up(); err == nil { - cur.ScreenTail.RowNumber-- - } - } else { - if err := cur.ScreenHead.Up(); err == nil { - cur.ScreenTail.RowNumber-- - } - } - } else { - if cur.ScreenTail.RowNumber-cur.ScreenHead.RowNumber+1 >= cur.ScreenRow { - err := cur.ScreenTail.Down() - if err != nil { - } - cur.ScreenTail.RowNumber-- - } else { - cur.ScreenTail.RowNumber-- - } - } - - prev := cur.LineIter.GetPrev() - oldTail := prev.GetValue().GetTail() - oldLen := prev.GetValue().Length() - err := t.MergeLines(cursorId) - if err != nil { - return err - } - cur.LineIter = prev - cur.CharIter = oldTail - - cur.Row-- - cur.Col = oldLen - 1 - - return nil - } - - newCharIter := cur.CharIter.GetPrev() - err := cur.LineIter.GetValue().Remove(cur.CharIter) - - if err != nil { - return err - } - - cur.CharIter = newCharIter - cur.Col-- - - return nil + cur := t.Cursors[cursorId] + + if cur.LineIter == nil { + //printtln("Press 'F', пацан к успеху шёл, Какой успех, раздался смех") + return nil + } + + if cur.CharIter == nil { + if cur.LineIter.GetPrev() == nil { + return nil + } + + if cur.ScreenTail.LineIter == cur.ScreenHead.LineIter { + cur.ScrollUp() + } else if cur.ScreenTail.LineIter == cur.LineIter { + if cur.LineIter.GetNext() == nil { + cur.ScreenTail.Up() + } else { + if err := cur.ScreenTail.Down(); err == nil { + cur.ScreenTail.RowNumber-- + } + } + } else if cur.ScreenHead.LineIter == cur.LineIter { + if cur.ScreenTail.RowNumber-cur.ScreenHead.RowNumber+1 >= cur.ScreenRow { + if err := cur.ScreenHead.Up(); err == nil { + cur.ScreenTail.RowNumber-- + } + } else { + if err := cur.ScreenHead.Up(); err == nil { + cur.ScreenTail.RowNumber-- + } + } + } else { + if cur.ScreenTail.RowNumber-cur.ScreenHead.RowNumber+1 >= cur.ScreenRow { + err := cur.ScreenTail.Down() + if err != nil { + } + cur.ScreenTail.RowNumber-- + } else { + cur.ScreenTail.RowNumber-- + } + } + + prev := cur.LineIter.GetPrev() + oldTail := prev.GetValue().GetTail() + oldLen := prev.GetValue().Length() + err := t.MergeLines(cursorId) + if err != nil { + return err + } + cur.LineIter = prev + cur.CharIter = oldTail + + cur.Row-- + cur.Col = oldLen - 1 + + return nil + } + + newCharIter := cur.CharIter.GetPrev() + err := cur.LineIter.GetValue().Remove(cur.CharIter) + + if err != nil { + return err + } + + cur.CharIter = newCharIter + cur.Col-- + + return nil } func (t *Text) RemoveCharAfter(cursorId int64) error { - cur := t.Cursors[cursorId] - oldCharIter := cur.CharIter - oldLineIter := cur.LineIter - cur.MoveRight() - if oldCharIter != cur.CharIter || oldLineIter != cur.LineIter { - err := t.RemoveCharBefore(cursorId) - return err - } - return nil + cur := t.Cursors[cursorId] + oldCharIter := cur.CharIter + oldLineIter := cur.LineIter + cur.MoveRight() + if oldCharIter != cur.CharIter || oldLineIter != cur.LineIter { + err := t.RemoveCharBefore(cursorId) + return err + } + return nil } // курсор не двигается!! func (t *Text) MergeLines(cursorId int64) error { - cur := t.Cursors[cursorId] - if cur.LineIter.GetPrev() == nil { - return errors.New("there is no previous line") - } - err := cur.LineIter.GetPrev().GetValue().Merge(cur.LineIter.GetValue()) - if err != nil { - return err - } - return t.Remove(cur.LineIter) + cur := t.Cursors[cursorId] + if cur.LineIter.GetPrev() == nil { + return errors.New("there is no previous line") + } + err := cur.LineIter.GetPrev().GetValue().Merge(cur.LineIter.GetValue()) + if err != nil { + return err + } + return t.Remove(cur.LineIter) } func (t *Text) GetString() string { - str := "" - iter := t.GetHead() - for iter != nil { - charIter := iter.GetValue().GetHead() - for charIter != nil { - str += string(charIter.GetValue()) - charIter = charIter.GetNext() - } - iter = iter.GetNext() - if iter != nil { - str += "\n" - } - } - ////printtln("Original str: ", str) - return str + str := "" + iter := t.GetHead() + for iter != nil { + charIter := iter.GetValue().GetHead() + for charIter != nil { + str += string(charIter.GetValue().Value) + charIter = charIter.GetNext() + } + iter = iter.GetNext() + if iter != nil { + str += "\n" + } + } + ////printtln("Original str: ", str) + return str } // TODO think about width func (t *Text) GetScreenString(cursorId int32) string { - cur := t.Cursors[cursorId] - //printtln(cur.ScreenHead.LineIter, cur.ScreenTail.LineIter) - if cur.ScreenHead.LineIter == nil || cur.ScreenTail.LineIter == nil { - //printtln("ScreenHead is nil") - return "" - } - ptr1 := cur.ScreenHead.LineIter - //printtln(cur.ScreenHead, cur.ScreenTail) - res := "" - for ptr1 != nil && ptr1 != cur.ScreenTail.LineIter.GetNext() { - ptr2 := ptr1.GetValue().GetHead() - for ptr2 != nil { - res += string(ptr2.GetValue()) - ptr2 = ptr2.GetNext() - } - res += "\n" - ptr1 = ptr1.GetNext() - } - //printtln("res: ", res) - return res + cur := t.Cursors[cursorId] + //printtln(cur.ScreenHead.LineIter, cur.ScreenTail.LineIter) + if cur.ScreenHead.LineIter == nil || cur.ScreenTail.LineIter == nil { + //printtln("ScreenHead is nil") + return "" + } + ptr1 := cur.ScreenHead.LineIter + //printtln(cur.ScreenHead, cur.ScreenTail) + res := "" + for ptr1 != nil && ptr1 != cur.ScreenTail.LineIter.GetNext() { + ptr2 := ptr1.GetValue().GetHead() + for ptr2 != nil { + res += string(ptr2.GetValue().Value) + ptr2 = ptr2.GetNext() + } + res += "\n" + ptr1 = ptr1.GetNext() + } + //printtln("res: ", res) + return res } func (cur *Cursor) MoveLeft() { - if cur.CharIter == nil { - if cur.LineIter.GetPrev() == nil { - return - } - - if cur.ScreenHead.LineIter == cur.LineIter { - if cur.ScreenTail.RowNumber-cur.ScreenHead.RowNumber+1 >= cur.ScreenRow { - cur.ScrollUp() - } else { - cur.ScreenHead.Up() - } - } - - cur.LineIter = cur.LineIter.GetPrev() - cur.CharIter = cur.LineIter.GetValue().GetTail() - cur.Row-- - - cur.Col = cur.LineIter.GetValue().Length() - 1 - return - } - - cur.CharIter = cur.CharIter.GetPrev() - cur.Col-- + if cur.CharIter == nil { + if cur.LineIter.GetPrev() == nil { + return + } + + if cur.ScreenHead.LineIter == cur.LineIter { + if cur.ScreenTail.RowNumber-cur.ScreenHead.RowNumber+1 >= cur.ScreenRow { + cur.ScrollUp() + } else { + cur.ScreenHead.Up() + } + } + + cur.LineIter = cur.LineIter.GetPrev() + cur.CharIter = cur.LineIter.GetValue().GetTail() + cur.Row-- + + cur.Col = cur.LineIter.GetValue().Length() - 1 + return + } + + cur.CharIter = cur.CharIter.GetPrev() + cur.Col-- } func (cur *Cursor) MoveRight() { - if cur.CharIter == nil { - if cur.LineIter.GetValue().GetHead() == nil { - if cur.LineIter.GetNext() == nil { - return - } - - if cur.ScreenTail.LineIter == cur.LineIter { - if cur.ScreenTail.RowNumber-cur.ScreenHead.RowNumber+1 >= cur.ScreenRow { - cur.ScrollDown() - } - } - - cur.LineIter = cur.LineIter.GetNext() - cur.CharIter = nil - cur.Row++ - cur.Col = -1 - return - } - - cur.CharIter = cur.LineIter.GetValue().GetHead() - cur.Col = 0 - return - } - - if cur.CharIter == cur.LineIter.GetValue().GetTail() { - if cur.LineIter.GetNext() == nil { - return - } - - if cur.ScreenTail.LineIter == cur.LineIter { - if cur.ScreenTail.RowNumber-cur.ScreenHead.RowNumber+1 >= cur.ScreenRow { - cur.ScrollDown() - } - } - - cur.LineIter = cur.LineIter.GetNext() - cur.CharIter = nil - cur.Row++ - cur.Col = -1 - return - } - - cur.CharIter = cur.CharIter.GetNext() - cur.Col++ + if cur.CharIter == nil { + if cur.LineIter.GetValue().GetHead() == nil { + if cur.LineIter.GetNext() == nil { + return + } + + if cur.ScreenTail.LineIter == cur.LineIter { + if cur.ScreenTail.RowNumber-cur.ScreenHead.RowNumber+1 >= cur.ScreenRow { + cur.ScrollDown() + } + } + + cur.LineIter = cur.LineIter.GetNext() + cur.CharIter = nil + cur.Row++ + cur.Col = -1 + return + } + + cur.CharIter = cur.LineIter.GetValue().GetHead() + cur.Col = 0 + return + } + + if cur.CharIter == cur.LineIter.GetValue().GetTail() { + if cur.LineIter.GetNext() == nil { + return + } + + if cur.ScreenTail.LineIter == cur.LineIter { + if cur.ScreenTail.RowNumber-cur.ScreenHead.RowNumber+1 >= cur.ScreenRow { + cur.ScrollDown() + } + } + + cur.LineIter = cur.LineIter.GetNext() + cur.CharIter = nil + cur.Row++ + cur.Col = -1 + return + } + + cur.CharIter = cur.CharIter.GetNext() + cur.Col++ } func (cur *Cursor) MoveUp() { - if cur.LineIter.GetPrev() == nil { - return - } - - if cur.ScreenHead.LineIter == cur.LineIter { - if cur.ScreenTail.RowNumber-cur.ScreenHead.RowNumber+1 >= cur.ScreenRow { - cur.ScrollUp() - } else { - cur.ScreenHead.Up() - } - } - - index := cur.LineIter.GetValue().Index(cur.CharIter) - cur.CharIter = cur.LineIter.GetPrev().GetValue().GetNodeByIndex(index) - cur.LineIter = cur.LineIter.GetPrev() - cur.Row-- - cur.Col = cur.LineIter.GetValue().Index(cur.CharIter) + if cur.LineIter.GetPrev() == nil { + return + } + + if cur.ScreenHead.LineIter == cur.LineIter { + if cur.ScreenTail.RowNumber-cur.ScreenHead.RowNumber+1 >= cur.ScreenRow { + cur.ScrollUp() + } else { + cur.ScreenHead.Up() + } + } + + index := cur.LineIter.GetValue().Index(cur.CharIter) + cur.CharIter = cur.LineIter.GetPrev().GetValue().GetNodeByIndex(index) + cur.LineIter = cur.LineIter.GetPrev() + cur.Row-- + cur.Col = cur.LineIter.GetValue().Index(cur.CharIter) } func (cur *Cursor) MoveDown() { - if cur.LineIter.GetNext() == nil { - return - } - - if cur.ScreenTail.LineIter == cur.LineIter { - if cur.ScreenTail.RowNumber-cur.ScreenHead.RowNumber+1 >= cur.ScreenRow { - cur.ScrollDown() - } - } - - index := cur.LineIter.GetValue().Index(cur.CharIter) - cur.CharIter = cur.LineIter.GetNext().GetValue().GetNodeByIndex(index) - cur.LineIter = cur.LineIter.GetNext() - cur.Row++ - cur.Col = cur.LineIter.GetValue().Index(cur.CharIter) + if cur.LineIter.GetNext() == nil { + return + } + + if cur.ScreenTail.LineIter == cur.LineIter { + if cur.ScreenTail.RowNumber-cur.ScreenHead.RowNumber+1 >= cur.ScreenRow { + cur.ScrollDown() + } + } + + index := cur.LineIter.GetValue().Index(cur.CharIter) + cur.CharIter = cur.LineIter.GetNext().GetValue().GetNodeByIndex(index) + cur.LineIter = cur.LineIter.GetNext() + cur.Row++ + cur.Col = cur.LineIter.GetValue().Index(cur.CharIter) } func (cur *Cursor) MoveHome() { - cur.CharIter = nil - cur.Col = -1 + cur.CharIter = nil + cur.Col = -1 } func (cur *Cursor) MoveEnd() { - cur.CharIter = cur.LineIter.GetValue().GetTail() - cur.Col = cur.LineIter.GetValue().Length() - 1 + cur.CharIter = cur.LineIter.GetValue().GetTail() + cur.Col = cur.LineIter.GetValue().Length() - 1 } - From 2084663952f90bf246aeeef5a9a63885dd6c6ea8 Mon Sep 17 00:00:00 2001 From: Tnirpps Date: Thu, 8 Jun 2023 13:54:53 +0300 Subject: [PATCH 2/7] add highlight --- main.go | 88 +++++++++++++++++++++++++++++--------- textmanager/textmanager.go | 32 +++++++++++--- 2 files changed, 92 insertions(+), 28 deletions(-) diff --git a/main.go b/main.go index 4952fa3..6ef443c 100644 --- a/main.go +++ b/main.go @@ -49,7 +49,9 @@ func GUIStop() { } type Cache struct { - PreRenderredCharTextures map[rune]CharTexture + PreRenderredCharTextures map[rune]map[uint32]CharTexture + + // TODO replace that PreRenderredNumsTextures map[rune]CharTexture RectangleMatrix *RectangleMatrix } @@ -285,11 +287,17 @@ func (e *Engine) Stop() { } if e.cache != nil { - for _, texture := range e.cache.PreRenderredCharTextures { - if texture.Texture == nil { + for _, mapColor := range e.cache.PreRenderredCharTextures { + if mapColor == nil { continue } - texture.Texture.Destroy() + for _, texture := range mapColor { + if texture.Texture == nil { + continue + } + + texture.Texture.Destroy() + } } } // TODO think about dele all text ??? @@ -384,7 +392,10 @@ func (e *Engine) SetCache(supportedChars string) error { } cache := &Cache{} - cache.PreRenderredCharTextures = make(map[rune]CharTexture) + cache.PreRenderredCharTextures = make(map[rune]map[uint32]CharTexture) + for _, char := range supportedChars { + cache.PreRenderredCharTextures[char] = make(map[uint32]CharTexture) + } cache.PreRenderredNumsTextures = make(map[rune]CharTexture) var ( @@ -394,15 +405,17 @@ func (e *Engine) SetCache(supportedChars string) error { ) for _, char := range supportedChars { - fontSurface, _ := e.font.ttfFont.RenderGlyphBlended(char, e.font.GetColor()) - texture, _ := e.renderer.CreateTextureFromSurface(fontSurface) - cache.PreRenderredCharTextures[char] = CharTexture{texture, fontSurface.W} - if fontSurface.W < width { - width = fontSurface.W - } - if fontSurface.H > mx { - mx = fontSurface.H - } + for _, color := range textmanager.COLORS { + fontSurface, _ := e.font.ttfFont.RenderGlyphBlended(char, hexToSdlColor(color)) + texture, _ := e.renderer.CreateTextureFromSurface(fontSurface) + cache.PreRenderredCharTextures[char][color] = CharTexture{texture, fontSurface.W} + if fontSurface.W < width { + width = fontSurface.W + } + if fontSurface.H > mx { + mx = fontSurface.H + } + } } // cache all digits for rendering Numbers of Rows @@ -561,12 +574,39 @@ func (e *Engine) InsertChar(value rune, cursorId int64) { //} } } +// костыль начинается тут... +func FindTokensInString(s string) []uint32 { + result := []uint32{} + curStr := "" + for ind, char := range s { + result = append(result, textmanager.FNTCLR) + if char == ' ' || char == '\n' { + if color, ok := textmanager.TokensColor[curStr]; ok { + // start coloring + for i:= ind - len(curStr); i < ind; i+=1 { + result[i] = color + } + } + curStr = "" + } else { + curStr += string(char) + } + } + if color, ok := textmanager.TokensColor[curStr]; ok { + for i:= len(s) - len(curStr); i < len(s); i+=1 { + result[i] = color + } + } + //print(len(s) == len(result)) + return result +} + func (e *Engine) renderText(cursorId int64) { e.renderer.Clear() var ( // e.font.GetSpaceBetween равен 0, поэтому он сейчас ни на что не влияет || тут +7 px это просто отступ от первой цифры - paddingLeft int32 = (e.font.GetSpaceBetween()+e.cache.PreRenderredCharTextures[rune('1')].Width)*4 + 7 + paddingLeft int32 = (e.font.GetSpaceBetween()+e.cache.PreRenderredCharTextures[rune('1')][textmanager.FNTCLR].Width)*4 + 7 X int32 = paddingLeft Y int32 = 0 row int32 = 0 @@ -595,7 +635,13 @@ func (e *Engine) renderText(cursorId int64) { delta = 0 } - for _, c := range e.text.GetScreenString(0) { + // for tokens + var currentColor uint32 = textmanager.FNTCLR + + tokens := FindTokensInString(e.text.GetScreenString(0)) + + for ind, c := range e.text.GetScreenString(0) { + currentColor = tokens[ind] if col-4 < delta { if c == '\n' { Y += e.font.GetSize() @@ -620,11 +666,11 @@ func (e *Engine) renderText(cursorId int64) { } //println("col - del: ", col - delta, "c:", rune(c)) e.GetRectFromMatrix(row, col-delta).H = e.font.GetSize() - e.GetRectFromMatrix(row, col-delta).W = e.cache.PreRenderredCharTextures[rune(c)].Width + e.GetRectFromMatrix(row, col-delta).W = e.cache.PreRenderredCharTextures[rune(c)][currentColor].Width e.GetRectFromMatrix(row, col-delta).X = X e.GetRectFromMatrix(row, col-delta).Y = Y - e.renderer.Copy(e.cache.PreRenderredCharTextures[rune(c)].Texture, nil, e.GetRectFromMatrix(row, col-delta)) - X += e.cache.PreRenderredCharTextures[rune(c)].Width + e.font.GetSpaceBetween() + e.renderer.Copy(e.cache.PreRenderredCharTextures[rune(c)][currentColor].Texture, nil, e.GetRectFromMatrix(row, col-delta)) + X += e.cache.PreRenderredCharTextures[rune(c)][currentColor].Width + e.font.GetSpaceBetween() col++ if c == '\n' { Y += e.font.GetSize() @@ -726,8 +772,8 @@ func main() { FontSize int32 = 30 // in px! SpaceBetween int32 = 0 FontFilename string = "MonoNL-Regular.ttf" - FontColor uint32 = 0xFFFFFFFF - LineNumbersColor uint32 = 0xbd93f9FF + FontColor uint32 = textmanager.FNTCLR + LineNumbersColor uint32 = textmanager.LNNMBC LineNumbersBackgroundColor uint32 = 0x44475aFF TextBackgroundColor uint32 = 0x282a36FF CursorColor uint32 = 0xDAD2D8FF diff --git a/textmanager/textmanager.go b/textmanager/textmanager.go index 07ccf43..7e012a4 100644 --- a/textmanager/textmanager.go +++ b/textmanager/textmanager.go @@ -7,15 +7,28 @@ import ( const ( endl = '\n' + PURPLE = 0xDC42DDFF + RED = 0x51D718FF + RED2 = 0xFF8300FF + BLUE = 0x8A6CD5FF + CIAN = 0xF5A58DFF + PINK = 0x0893FCFF + FNTCLR = 0xFFFFFFFF + LNNMBC = 0xbd93f9FF ) +var COLORS = []uint32{PURPLE, RED, BLUE, CIAN, PINK, FNTCLR, LNNMBC, RED2} + var ( TokensColor = map[string]uint32{ - "for": 0xDC42DDFF, - "while": 0x51D718FF, - "if": 0x8A6CD5FF, - "int": 0xF5A58DFF, - "aboba": 0x0893FCFF, + "for": PURPLE, + "while": RED, + "if": BLUE, + "else": BLUE, + "return": RED2, + "int": CIAN, + "long": CIAN, + "aboba": PINK, } MaxTokenLength int ) @@ -227,11 +240,16 @@ func (t *Text) DetectToken(cursorId int64) error { for ptr != right.GetNext() { if ptr.GetValue().Value == ' ' { if color, ok := TokensColor[curToken]; ok { + // start coloring val := left.GetValue() val.Color = color left.SetValue(val) left = ptr.GetNext() - println("token found: ", curToken) + // end coloring + val = ptr.GetValue() + val.Color = FNTCLR + ptr.SetValue(val) + //println("token found: ", curToken) curToken = "" } } else { @@ -243,7 +261,7 @@ func (t *Text) DetectToken(cursorId int64) error { val := left.GetValue() val.Color = color left.SetValue(val) - println("token found: ", curToken) + //println("token found: ", curToken) } return nil From c4dd1ce42761fb531738fde030e20819d4e56645 Mon Sep 17 00:00:00 2001 From: Tnirpps Date: Thu, 8 Jun 2023 23:23:20 +0300 Subject: [PATCH 3/7] fix highlighting --- main.go | 12 ++++--- textmanager/textmanager.go | 71 -------------------------------------- 2 files changed, 7 insertions(+), 76 deletions(-) diff --git a/main.go b/main.go index 6ef443c..a4832f3 100644 --- a/main.go +++ b/main.go @@ -574,13 +574,15 @@ func (e *Engine) InsertChar(value rune, cursorId int64) { //} } } -// костыль начинается тут... -func FindTokensInString(s string) []uint32 { + +// возвращает массив длины текста +// на i-ой позиции цвет i-го символа строки +func HighlightTokensInString(s string) []uint32 { result := []uint32{} curStr := "" for ind, char := range s { result = append(result, textmanager.FNTCLR) - if char == ' ' || char == '\n' { + if char == ' ' || char == '\n' || char == '(' || char == '{' { if color, ok := textmanager.TokensColor[curStr]; ok { // start coloring for i:= ind - len(curStr); i < ind; i+=1 { @@ -597,7 +599,7 @@ func FindTokensInString(s string) []uint32 { result[i] = color } } - //print(len(s) == len(result)) + // assert(len(s) == len(result)) return result } @@ -638,7 +640,7 @@ func (e *Engine) renderText(cursorId int64) { // for tokens var currentColor uint32 = textmanager.FNTCLR - tokens := FindTokensInString(e.text.GetScreenString(0)) + tokens := HighlightTokensInString(e.text.GetScreenString(0)) for ind, c := range e.text.GetScreenString(0) { currentColor = tokens[ind] diff --git a/textmanager/textmanager.go b/textmanager/textmanager.go index 7e012a4..58501e9 100644 --- a/textmanager/textmanager.go +++ b/textmanager/textmanager.go @@ -115,20 +115,9 @@ type Text struct { Cursors []*Cursor } -func InitMaxTokenLength() { - for k := range TokensColor { - if len(k) > MaxTokenLength { - MaxTokenLength = len(k) - } - } -} - func NewText() *Text { t := new(Text) t.PushBack(new(list.List[Char])) - - InitMaxTokenLength() - return t } @@ -193,7 +182,6 @@ func (t *Text) InsertCharAfter(cursorId int64, value rune) error { cur.CharIter = cur.LineIter.GetValue().GetHead() cur.Col = 0 - t.DetectToken(cursorId) return nil } @@ -205,65 +193,6 @@ func (t *Text) InsertCharAfter(cursorId int64, value rune) error { cur.CharIter = cur.CharIter.GetNext() cur.Col++ - t.DetectToken(cursorId) - return nil -} - -func (t *Text) DetectToken(cursorId int64) error { - if t.Cursors[cursorId].CharIter == nil { - return errors.New("CharIter is nil") - } - - var ( - ptr = t.Cursors[cursorId].CharIter.GetPrev() - left = t.Cursors[cursorId].CharIter - right = left - ) - - if ptr != nil { - for ptr.GetPrev() != nil && ptr.GetPrev().GetValue().Value != ' ' { - ptr = ptr.GetPrev() - } - left = ptr - } - - ptr = t.Cursors[cursorId].CharIter.GetNext() - if ptr != nil { - for ptr.GetNext() != nil && ptr.GetNext().GetValue().Value != ' ' { - ptr = ptr.GetNext() - } - right = ptr - } - - ptr = left - curToken := "" - for ptr != right.GetNext() { - if ptr.GetValue().Value == ' ' { - if color, ok := TokensColor[curToken]; ok { - // start coloring - val := left.GetValue() - val.Color = color - left.SetValue(val) - left = ptr.GetNext() - // end coloring - val = ptr.GetValue() - val.Color = FNTCLR - ptr.SetValue(val) - //println("token found: ", curToken) - curToken = "" - } - } else { - curToken += string(ptr.GetValue().Value) - } - ptr = ptr.GetNext() - } - if color, ok := TokensColor[curToken]; ok { - val := left.GetValue() - val.Color = color - left.SetValue(val) - //println("token found: ", curToken) - } - return nil } From d690eefd57c405d9817abf6b209e5b09a4fb3cfe Mon Sep 17 00:00:00 2001 From: Tnirpps Date: Fri, 9 Jun 2023 12:15:41 +0300 Subject: [PATCH 4/7] add comments and string highlighting --- main.go | 51 +++++++++++++++++++++++++++++++++++--- textmanager/textmanager.go | 10 ++++++-- 2 files changed, 56 insertions(+), 5 deletions(-) diff --git a/main.go b/main.go index a4832f3..a165c05 100644 --- a/main.go +++ b/main.go @@ -575,14 +575,59 @@ func (e *Engine) InsertChar(value rune, cursorId int64) { } } + +func Contains(s []rune, e rune) bool { + for _, a := range s { + if a == e { + return true + } + } + return false +} // возвращает массив длины текста // на i-ой позиции цвет i-го символа строки func HighlightTokensInString(s string) []uint32 { - result := []uint32{} + result := make([]uint32, len(s)) + separators := []rune{' ','\n','(','{','}',')',';','/', '"'} curStr := "" + lineCommentFlag := 0 + stringStartFlag := 0 for ind, char := range s { - result = append(result, textmanager.FNTCLR) - if char == ' ' || char == '\n' || char == '(' || char == '{' { + if stringStartFlag == 1 { + if char == '"' { + stringStartFlag = 0 + } + // гарантируется что существует предыдущий символ, т.к. в данной + // ветке рассматривается случай, когда до текущего символа встретился '"' + result[ind - 1] = textmanager.GREEN + result[ind] = textmanager.GREEN + continue + } + + if char == '/' { + lineCommentFlag++ + } else if lineCommentFlag < 2 { + lineCommentFlag = 0 + } + + if lineCommentFlag >= 2 { + // гарантируется что существует предыдущий символ, т.к. в данной + // ветке рассматривается случай, когда идёт два символа '\' подряд + result[ind - 1] = textmanager.GREY + result[ind] = textmanager.GREY + if char == '\n' { + lineCommentFlag = 0 + curStr = "" + } + continue + } + + if char == '"' { + stringStartFlag = 1 + } + + result[ind] = textmanager.FNTCLR + if Contains(separators, char) { if color, ok := textmanager.TokensColor[curStr]; ok { // start coloring for i:= ind - len(curStr); i < ind; i+=1 { diff --git a/textmanager/textmanager.go b/textmanager/textmanager.go index 58501e9..c1750a4 100644 --- a/textmanager/textmanager.go +++ b/textmanager/textmanager.go @@ -8,26 +8,32 @@ import ( const ( endl = '\n' PURPLE = 0xDC42DDFF + GOLD = 0xD4AF37FF RED = 0x51D718FF RED2 = 0xFF8300FF BLUE = 0x8A6CD5FF CIAN = 0xF5A58DFF PINK = 0x0893FCFF + GREY = 0xC7D7CFFF + GREEN = 0x51D733FF FNTCLR = 0xFFFFFFFF LNNMBC = 0xbd93f9FF ) -var COLORS = []uint32{PURPLE, RED, BLUE, CIAN, PINK, FNTCLR, LNNMBC, RED2} +var COLORS = []uint32{GREEN, GREY, GOLD, PURPLE, BLUE, CIAN, PINK, FNTCLR, LNNMBC, RED2} var ( TokensColor = map[string]uint32{ "for": PURPLE, - "while": RED, + "while": PURPLE, "if": BLUE, "else": BLUE, "return": RED2, "int": CIAN, "long": CIAN, + "bool": GOLD, + "true": PINK, + "false": PINK, "aboba": PINK, } MaxTokenLength int From 5df7193d7f5b2b555d33e3f2fb697ebb0f2c0be7 Mon Sep 17 00:00:00 2001 From: Tnirpps Date: Tue, 20 Jun 2023 01:01:00 +0300 Subject: [PATCH 5/7] fix render --- main.go | 59 ++++++++++++++----- textmanager/textmanager.go | 117 +++++++++++++++++++++++++++++++------ 2 files changed, 142 insertions(+), 34 deletions(-) diff --git a/main.go b/main.go index a165c05..a6831bb 100644 --- a/main.go +++ b/main.go @@ -117,6 +117,9 @@ type Engine struct { LineNumbersColor uint32 TextBackgroundColor uint32 CursorColor uint32 + + // отступ дл нумирации строк на экране + CharCountInLineNumber int32 } func (e *Engine) RenderCursor(cursorId int64) { @@ -132,7 +135,7 @@ func (e *Engine) RenderCursor(cursorId int64) { cur := e.text.Cursors[i] //println("Cur head: ", cur.ScreenHead.RowNumber, "Cur tail: ", cur.ScreenTail.RowNumber) e.renderer.SetDrawColor(hexToRBGA(cur.Color)) - col := cur.Col + col := cur.Col - leftBorder // TODO отображать относительно Одного курсора, поэтому cur.ScreenHead.RowNumber не годится (относительно самого себя) row := cur.Row - cur.ScreenHead.RowNumber var padding int32 @@ -143,20 +146,18 @@ func (e *Engine) RenderCursor(cursorId int64) { } if col == -1 { - col = 4 - leftBorder + col = e.CharCountInLineNumber padding = 0 } else { - if col < leftBorder-1 { + if col < -1 { continue } - if col == leftBorder-1 && leftBorder != 0 { + if col == - 1 && leftBorder != 0 { //println("\t\t\tLEFTBORDER") col++ padding = 0 - col -= leftBorder col += 4 } else { - col -= leftBorder col += 4 padding = e.GetRectFromMatrix(row, col).W } @@ -218,7 +219,7 @@ func NewEngine(windowWidth, windowHeight int32, configRendererScale(renderer, windowWidth, windowHeight) - engine := &Engine{ + engine := &Engine { renderer: renderer, window: window, text: textmanager.NewText(), @@ -226,6 +227,7 @@ func NewEngine(windowWidth, windowHeight int32, LineNumbersColor: lineNumbersColor, TextBackgroundColor: textBackgroundColor, CursorColor: cursorColor, + CharCountInLineNumber: 4, // значение по умолчанию, я так захотел!! } err = engine.SetFont(fontFilename, fontSize, fontSpaceBetween, fontColor, lineNumbersColor) @@ -241,7 +243,12 @@ func NewEngine(windowWidth, windowHeight int32, } // TODO server.createCursor(id) ?? - cur := textmanager.NewCursor(0, engine.cache.RectangleMatrix.Rows, engine.cache.RectangleMatrix.Columns) + cur := textmanager.NewCursor( + 0, + engine.cache.RectangleMatrix.Rows, + engine.cache.RectangleMatrix.Columns - engine.CharCountInLineNumber - 2 , // ещё -2 чтобы курсор влез на экран + ) + cur.LineIter = engine.text.GetHead() cur.CharIter = nil cur.Color = cursorColor @@ -544,6 +551,7 @@ func (e *Engine) EraseChar(key sdl.Scancode, cursorId int64) { switch key { case sdl.SCANCODE_BACKSPACE: err = e.text.RemoveCharBefore(cursorId) + //print("res: ", e.text.GetScreenString(0)) case sdl.SCANCODE_DELETE: err = e.text.RemoveCharAfter(cursorId) } @@ -648,26 +656,47 @@ func HighlightTokensInString(s string) []uint32 { return result } - +// TODO переписать))) func (e *Engine) renderText(cursorId int64) { e.renderer.Clear() var ( // e.font.GetSpaceBetween равен 0, поэтому он сейчас ни на что не влияет || тут +7 px это просто отступ от первой цифры - paddingLeft int32 = (e.font.GetSpaceBetween()+e.cache.PreRenderredCharTextures[rune('1')][textmanager.FNTCLR].Width)*4 + 7 + col int32 = e.CharCountInLineNumber + paddingLeft int32 = (e.font.GetSpaceBetween()+e.cache.PreRenderredCharTextures[rune('1')][textmanager.FNTCLR].Width)*col + 7 X int32 = paddingLeft Y int32 = 0 row int32 = 0 // тут col равен 4 потому что мы 4 колоноки оставляем под нумерацию - col int32 = 4 // TODO относительные координаты курсора от экрана - delta int32 = e.text.Cursors[cursorId].Col - e.cache.RectangleMatrix.Columns + 2 + 4 + //delta int32 = e.text.Cursors[cursorId].Col - e.cache.RectangleMatrix.Columns + 2 + 4 ) e.renderBackground(paddingLeft) + var currentColor uint32 = textmanager.FNTCLR + for _, c := range e.text.GetScreenString(0) { + if c == '\n' { + Y += e.font.GetSize() + X = paddingLeft + e.font.GetSpaceBetween() + row++ + col = e.CharCountInLineNumber + continue + } + if col >= e.cache.RectangleMatrix.Columns { + continue // это из-за лишних чимволов которые появляются из-за отсптупа для номеров строк + } + // TODO write setter for this -> + e.GetRectFromMatrix(row, col).H = e.font.GetSize() + e.GetRectFromMatrix(row, col).W = e.cache.PreRenderredCharTextures[rune(c)][currentColor].Width + e.GetRectFromMatrix(row, col).X = X + e.GetRectFromMatrix(row, col).Y = Y + e.renderer.Copy(e.cache.PreRenderredCharTextures[rune(c)][currentColor].Texture, nil, e.GetRectFromMatrix(row, col)) + X += e.cache.PreRenderredCharTextures[rune(c)][currentColor].Width + e.font.GetSpaceBetween() + col++ + } //println("delta:", delta) - - leftBorder := e.text.Cursors[cursorId].ScreenLeft + /* + //leftBorder := e.text.Cursors[cursorId].ScreenLeft //println("LeftBorderText: ", leftBorder) if e.text.Cursors[cursorId].Col < leftBorder { e.text.Cursors[cursorId].ScreenLeft = e.text.Cursors[cursorId].Col + 1 @@ -686,7 +715,6 @@ func (e *Engine) renderText(cursorId int64) { var currentColor uint32 = textmanager.FNTCLR tokens := HighlightTokensInString(e.text.GetScreenString(0)) - for ind, c := range e.text.GetScreenString(0) { currentColor = tokens[ind] if col-4 < delta { @@ -727,6 +755,7 @@ func (e *Engine) renderText(cursorId int64) { } } + */ cur := e.text.Cursors[cursorId] row = 0 col = 3 diff --git a/textmanager/textmanager.go b/textmanager/textmanager.go index c1750a4..103999b 100644 --- a/textmanager/textmanager.go +++ b/textmanager/textmanager.go @@ -56,8 +56,8 @@ type Cursor struct { ScreenHead *Border ScreenTail *Border - ScreenRow int32 - ScreenCol int32 + ScreenRowsCount int32 + ScreenColsCount int32 } //Эта структура нужна для скрола @@ -107,6 +107,17 @@ func (cur *Cursor) ScrollDown() { } } +func (cur *Cursor) FixLeftScreen() { + if cur.ScreenLeft - 1 > cur.Col { + cur.ScreenLeft = cur.Col + 1 + } else if cur.Col - cur.ScreenLeft > cur.ScreenColsCount { + cur.ScreenLeft = cur.Col - cur.ScreenColsCount + } + if cur.ScreenLeft < 0 { + cur.ScreenLeft = 0 + } +} + /* type Line struct { Value *list.List[rune] @@ -129,13 +140,13 @@ func NewText() *Text { // TODO написать присвоение id для курсора // TODO на данном этапе при создании NewCursor просто всегда будем 0 в него передавать, когда будем писать серверную часть нужно будет определиться с созданием Id -func NewCursor(Id int64, ScreenRow, ScreenCol int32) *Cursor { +func NewCursor(Id int64, ScreenRowsCount, ScreenColsCount int32) *Cursor { c := new(Cursor) c.Row = 0 c.Col = -1 c.Id = Id - c.ScreenRow = ScreenRow - c.ScreenCol = ScreenCol + c.ScreenRowsCount = ScreenRowsCount + c.ScreenColsCount = ScreenColsCount c.ScreenLeft = 0 c.ScreenHead = &Border{RowNumber: 0} c.ScreenTail = &Border{RowNumber: 0} @@ -154,7 +165,7 @@ func (t *Text) SetCursorStartPosition(cursorId int64) { cur.ScreenHead = &Border{LineIter: t.GetHead(), RowNumber: 0} // Егор сказал, что выстрелит, но куда... (создаем новый объект, а не меняем старый) cur.ScreenTail = &Border{LineIter: t.GetHead(), RowNumber: 0} - for i := 1; i < int(t.Cursors[cursorId].ScreenRow); i++ { + for i := 1; i < int(t.Cursors[cursorId].ScreenRowsCount); i++ { if err := cur.ScreenTail.Down(); err != nil { return } @@ -188,6 +199,8 @@ func (t *Text) InsertCharAfter(cursorId int64, value rune) error { cur.CharIter = cur.LineIter.GetValue().GetHead() cur.Col = 0 + // пересчитываем screen left + cur.FixLeftScreen() return nil } @@ -199,6 +212,8 @@ func (t *Text) InsertCharAfter(cursorId int64, value rune) error { cur.CharIter = cur.CharIter.GetNext() cur.Col++ + // пересчитываем screen left + cur.FixLeftScreen() return nil } @@ -237,7 +252,7 @@ func (t *Text) InsertLineAfter(cursorId int64) error { return err } - if cur.ScreenTail.RowNumber-cur.ScreenHead.RowNumber+1 >= cur.ScreenRow { + if cur.ScreenTail.RowNumber-cur.ScreenHead.RowNumber+1 >= cur.ScreenRowsCount { if cur.LineIter == cur.ScreenTail.LineIter { cur.ScrollDown() } else { @@ -263,6 +278,8 @@ func (t *Text) InsertLineAfter(cursorId int64) error { cur.Row++ cur.Col = -1 + // пересчитываем screen left + cur.FixLeftScreen() return nil } // line is empty @@ -272,7 +289,7 @@ func (t *Text) InsertLineAfter(cursorId int64) error { return err } - if cur.ScreenTail.RowNumber-cur.ScreenHead.RowNumber+1 >= cur.ScreenRow { + if cur.ScreenTail.RowNumber-cur.ScreenHead.RowNumber+1 >= cur.ScreenRowsCount { if cur.LineIter == cur.ScreenTail.LineIter { cur.ScrollDown() } else { @@ -294,6 +311,8 @@ func (t *Text) InsertLineAfter(cursorId int64) error { cur.Row++ cur.Col = -1 + // пересчитываем screen left + cur.FixLeftScreen() return nil } @@ -316,7 +335,7 @@ func (t *Text) InsertLineAfter(cursorId int64) error { } oldLineIter.SetNext(node) - if cur.ScreenTail.RowNumber-cur.ScreenHead.RowNumber+1 >= cur.ScreenRow { + if cur.ScreenTail.RowNumber-cur.ScreenHead.RowNumber+1 >= cur.ScreenRowsCount { if cur.LineIter == cur.ScreenTail.LineIter { cur.ScrollDown() } else { @@ -338,6 +357,8 @@ func (t *Text) InsertLineAfter(cursorId int64) error { cur.Row++ cur.Col = -1 + // пересчитываем screen left + cur.FixLeftScreen() return nil } @@ -366,7 +387,7 @@ func (t *Text) RemoveCharBefore(cursorId int64) error { } } } else if cur.ScreenHead.LineIter == cur.LineIter { - if cur.ScreenTail.RowNumber-cur.ScreenHead.RowNumber+1 >= cur.ScreenRow { + if cur.ScreenTail.RowNumber-cur.ScreenHead.RowNumber+1 >= cur.ScreenRowsCount { if err := cur.ScreenHead.Up(); err == nil { cur.ScreenTail.RowNumber-- } @@ -376,7 +397,7 @@ func (t *Text) RemoveCharBefore(cursorId int64) error { } } } else { - if cur.ScreenTail.RowNumber-cur.ScreenHead.RowNumber+1 >= cur.ScreenRow { + if cur.ScreenTail.RowNumber-cur.ScreenHead.RowNumber+1 >= cur.ScreenRowsCount { err := cur.ScreenTail.Down() if err != nil { } @@ -399,6 +420,8 @@ func (t *Text) RemoveCharBefore(cursorId int64) error { cur.Row-- cur.Col = oldLen - 1 + // пересчитываем screen left + cur.FixLeftScreen() return nil } @@ -411,6 +434,8 @@ func (t *Text) RemoveCharBefore(cursorId int64) error { cur.CharIter = newCharIter cur.Col-- + // пересчитываем screen left + cur.FixLeftScreen() return nil } @@ -458,6 +483,37 @@ func (t *Text) GetString() string { return str } +func (t *Text) GetScreenString(cursorId int32) string { + cur := t.Cursors[cursorId] + if cur.ScreenHead.LineIter == nil || cur.ScreenTail.LineIter == nil { + //printtln("ScreenHead is nil") + return "" + } + ptr1 := cur.ScreenHead.LineIter + //printtln(cur.ScreenHead, cur.ScreenTail) + res := "" + // итерируемся по каждой строчке + for ptr1 != nil && ptr1 != cur.ScreenTail.LineIter.GetNext() { + ptr2 := ptr1.GetValue().GetHead() + // смотрим, если строка не пустая и в ней достаточно символов + // чтобы их было видно на экране в данный момент + if ptr2 != nil && ptr1.GetValue().Length() >= cur.ScreenLeft { + // начинаем брать строчку с первого символа, который попадает на экран + ptr2 = ptr1.GetValue().GetNodeByIndex(cur.ScreenLeft) + currentLen := int32(0) + // выдаём либо все символы строки, которые помещаются на экран + for ptr2 != nil && currentLen <= cur.ScreenColsCount { + currentLen++ + res += string(ptr2.GetValue().Value) + ptr2 = ptr2.GetNext() + } + } + res += "\n" + ptr1 = ptr1.GetNext() + } + return res +} +/* // TODO think about width func (t *Text) GetScreenString(cursorId int32) string { cur := t.Cursors[cursorId] @@ -481,15 +537,15 @@ func (t *Text) GetScreenString(cursorId int32) string { //printtln("res: ", res) return res } - +*/ func (cur *Cursor) MoveLeft() { - if cur.CharIter == nil { - if cur.LineIter.GetPrev() == nil { + if cur.CharIter == nil { // значит мы стоим в начале строчки + if cur.LineIter.GetPrev() == nil { // значит мы стоим вверху текста return } if cur.ScreenHead.LineIter == cur.LineIter { - if cur.ScreenTail.RowNumber-cur.ScreenHead.RowNumber+1 >= cur.ScreenRow { + if cur.ScreenTail.RowNumber-cur.ScreenHead.RowNumber+1 >= cur.ScreenRowsCount { cur.ScrollUp() } else { cur.ScreenHead.Up() @@ -501,11 +557,17 @@ func (cur *Cursor) MoveLeft() { cur.Row-- cur.Col = cur.LineIter.GetValue().Length() - 1 + + // пересчитываем screen left + cur.FixLeftScreen() + return } cur.CharIter = cur.CharIter.GetPrev() cur.Col-- + // пересчитываем screen left + cur.FixLeftScreen() } func (cur *Cursor) MoveRight() { @@ -516,7 +578,7 @@ func (cur *Cursor) MoveRight() { } if cur.ScreenTail.LineIter == cur.LineIter { - if cur.ScreenTail.RowNumber-cur.ScreenHead.RowNumber+1 >= cur.ScreenRow { + if cur.ScreenTail.RowNumber-cur.ScreenHead.RowNumber+1 >= cur.ScreenRowsCount { cur.ScrollDown() } } @@ -525,11 +587,16 @@ func (cur *Cursor) MoveRight() { cur.CharIter = nil cur.Row++ cur.Col = -1 + + // пересчитываем screen left + cur.FixLeftScreen() return } cur.CharIter = cur.LineIter.GetValue().GetHead() cur.Col = 0 + // пересчитываем screen left + cur.FixLeftScreen() return } @@ -539,7 +606,7 @@ func (cur *Cursor) MoveRight() { } if cur.ScreenTail.LineIter == cur.LineIter { - if cur.ScreenTail.RowNumber-cur.ScreenHead.RowNumber+1 >= cur.ScreenRow { + if cur.ScreenTail.RowNumber-cur.ScreenHead.RowNumber+1 >= cur.ScreenRowsCount { cur.ScrollDown() } } @@ -548,11 +615,15 @@ func (cur *Cursor) MoveRight() { cur.CharIter = nil cur.Row++ cur.Col = -1 + // пересчитываем screen left + cur.FixLeftScreen() return } cur.CharIter = cur.CharIter.GetNext() cur.Col++ + // пересчитываем screen left + cur.FixLeftScreen() } func (cur *Cursor) MoveUp() { @@ -561,7 +632,7 @@ func (cur *Cursor) MoveUp() { } if cur.ScreenHead.LineIter == cur.LineIter { - if cur.ScreenTail.RowNumber-cur.ScreenHead.RowNumber+1 >= cur.ScreenRow { + if cur.ScreenTail.RowNumber-cur.ScreenHead.RowNumber+1 >= cur.ScreenRowsCount { cur.ScrollUp() } else { cur.ScreenHead.Up() @@ -573,6 +644,8 @@ func (cur *Cursor) MoveUp() { cur.LineIter = cur.LineIter.GetPrev() cur.Row-- cur.Col = cur.LineIter.GetValue().Index(cur.CharIter) + // пересчитываем screen left + cur.FixLeftScreen() } func (cur *Cursor) MoveDown() { @@ -581,7 +654,7 @@ func (cur *Cursor) MoveDown() { } if cur.ScreenTail.LineIter == cur.LineIter { - if cur.ScreenTail.RowNumber-cur.ScreenHead.RowNumber+1 >= cur.ScreenRow { + if cur.ScreenTail.RowNumber-cur.ScreenHead.RowNumber+1 >= cur.ScreenRowsCount { cur.ScrollDown() } } @@ -591,14 +664,20 @@ func (cur *Cursor) MoveDown() { cur.LineIter = cur.LineIter.GetNext() cur.Row++ cur.Col = cur.LineIter.GetValue().Index(cur.CharIter) + // пересчитываем screen left + cur.FixLeftScreen() } func (cur *Cursor) MoveHome() { cur.CharIter = nil cur.Col = -1 + // пересчитываем screen left + cur.FixLeftScreen() } func (cur *Cursor) MoveEnd() { cur.CharIter = cur.LineIter.GetValue().GetTail() cur.Col = cur.LineIter.GetValue().Length() - 1 + // пересчитываем screen left + cur.FixLeftScreen() } From eff09c2e3c58a08f9ddc0a856796e6ae2e3306eb Mon Sep 17 00:00:00 2001 From: Glushin Nikita Date: Tue, 20 Jun 2023 16:33:19 +0300 Subject: [PATCH 6/7] highlighting v2.0 --- main.go | 404 ++++++++++++++++++++----------------- textmanager/textmanager.go | 302 ++++++++++++++++++--------- 2 files changed, 425 insertions(+), 281 deletions(-) diff --git a/main.go b/main.go index a6831bb..bfafdff 100644 --- a/main.go +++ b/main.go @@ -11,6 +11,31 @@ import ( "github.com/veandco/go-sdl2/ttf" ) +const ( + PURPLE = 0xDC42DDFF + GOLD = 0xD4AF37FF + RED = 0x51D718FF + ORANGE = 0xFF8300FF + DARKPURPLE = 0x8A6CD5FF + BEIGE = 0xF5A58DFF + BLUE = 0x0893FCFF + GREY = 0xC7D7CFFF + GREEN = 0x51D733FF + WHITE = 0xFFFFFFFF + LNNMBC = 0xbd93f9FF +) + +var Colors = map[textmanager.Term]uint32{ + textmanager.Normal: WHITE, + textmanager.Loop: PURPLE, + textmanager.Condition: BLUE, + textmanager.Type: DARKPURPLE, + textmanager.Bool: BEIGE, + textmanager.Digit: GREY, + textmanager.Return: ORANGE, + textmanager.Special: GOLD, +} + func hexToSdlColor(color uint32) sdl.Color { r, g, b, a := hexToRBGA(color) return sdl.Color{R: r, G: g, B: b, A: a} @@ -51,7 +76,7 @@ func GUIStop() { type Cache struct { PreRenderredCharTextures map[rune]map[uint32]CharTexture - // TODO replace that + // TODO replace that PreRenderredNumsTextures map[rune]CharTexture RectangleMatrix *RectangleMatrix } @@ -62,7 +87,7 @@ type RectangleMatrix struct { Columns int32 } -func NewRectangleMatrix(rows, columns, fontSize, SpaceBetween int32) *RectangleMatrix { +func NewRectangleMatrix(rows, columns, fontSize, XBegin int32) *RectangleMatrix { rectangleMatrix := &RectangleMatrix{ Rows: rows, Columns: columns, @@ -70,7 +95,7 @@ func NewRectangleMatrix(rows, columns, fontSize, SpaceBetween int32) *RectangleM rectangleMatrix.RectangleMatrix = make([][]*sdl.Rect, rows) for i := int32(0); i < rows; i++ { for j := int32(0); j < columns; j++ { - rectangleMatrix.RectangleMatrix[i] = append(rectangleMatrix.RectangleMatrix[i], &sdl.Rect{X: SpaceBetween, Y: i * fontSize}) + rectangleMatrix.RectangleMatrix[i] = append(rectangleMatrix.RectangleMatrix[i], &sdl.Rect{X: XBegin, Y: i * fontSize}) } } return rectangleMatrix @@ -118,8 +143,8 @@ type Engine struct { TextBackgroundColor uint32 CursorColor uint32 - // отступ дл нумирации строк на экране - CharCountInLineNumber int32 + // отступ дл нумирации строк на экране + CharCountInLineNumber int32 } func (e *Engine) RenderCursor(cursorId int64) { @@ -152,13 +177,13 @@ func (e *Engine) RenderCursor(cursorId int64) { if col < -1 { continue } - if col == - 1 && leftBorder != 0 { + if col == -1 && leftBorder != 0 { //println("\t\t\tLEFTBORDER") col++ padding = 0 - col += 4 + col += e.CharCountInLineNumber } else { - col += 4 + col += e.CharCountInLineNumber padding = e.GetRectFromMatrix(row, col).W } } @@ -219,7 +244,7 @@ func NewEngine(windowWidth, windowHeight int32, configRendererScale(renderer, windowWidth, windowHeight) - engine := &Engine { + engine := &Engine{ renderer: renderer, window: window, text: textmanager.NewText(), @@ -227,7 +252,7 @@ func NewEngine(windowWidth, windowHeight int32, LineNumbersColor: lineNumbersColor, TextBackgroundColor: textBackgroundColor, CursorColor: cursorColor, - CharCountInLineNumber: 4, // значение по умолчанию, я так захотел!! + CharCountInLineNumber: 4, // значение по умолчанию, я так захотел!! } err = engine.SetFont(fontFilename, fontSize, fontSpaceBetween, fontColor, lineNumbersColor) @@ -244,10 +269,10 @@ func NewEngine(windowWidth, windowHeight int32, // TODO server.createCursor(id) ?? cur := textmanager.NewCursor( - 0, - engine.cache.RectangleMatrix.Rows, - engine.cache.RectangleMatrix.Columns - engine.CharCountInLineNumber - 2 , // ещё -2 чтобы курсор влез на экран - ) + 0, + engine.cache.RectangleMatrix.Rows, + engine.cache.RectangleMatrix.Columns-engine.CharCountInLineNumber-2, // ещё -2 чтобы курсор влез на экран + ) cur.LineIter = engine.text.GetHead() cur.CharIter = nil @@ -298,13 +323,13 @@ func (e *Engine) Stop() { if mapColor == nil { continue } - for _, texture := range mapColor { - if texture.Texture == nil { - continue - } + for _, texture := range mapColor { + if texture.Texture == nil { + continue + } - texture.Texture.Destroy() - } + texture.Texture.Destroy() + } } } // TODO think about dele all text ??? @@ -400,9 +425,9 @@ func (e *Engine) SetCache(supportedChars string) error { cache := &Cache{} cache.PreRenderredCharTextures = make(map[rune]map[uint32]CharTexture) - for _, char := range supportedChars { - cache.PreRenderredCharTextures[char] = make(map[uint32]CharTexture) - } + for _, char := range supportedChars { + cache.PreRenderredCharTextures[char] = make(map[uint32]CharTexture) + } cache.PreRenderredNumsTextures = make(map[rune]CharTexture) var ( @@ -412,24 +437,26 @@ func (e *Engine) SetCache(supportedChars string) error { ) for _, char := range supportedChars { - for _, color := range textmanager.COLORS { - fontSurface, _ := e.font.ttfFont.RenderGlyphBlended(char, hexToSdlColor(color)) - texture, _ := e.renderer.CreateTextureFromSurface(fontSurface) - cache.PreRenderredCharTextures[char][color] = CharTexture{texture, fontSurface.W} - if fontSurface.W < width { - width = fontSurface.W - } - if fontSurface.H > mx { - mx = fontSurface.H - } - } + for _, color := range Colors { + fontSurface, _ := e.font.ttfFont.RenderGlyphBlended(char, hexToSdlColor(color)) + texture, _ := e.renderer.CreateTextureFromSurface(fontSurface) + cache.PreRenderredCharTextures[char][color] = CharTexture{texture, fontSurface.W} + if fontSurface.W < width { + width = fontSurface.W + } + if fontSurface.H > mx { + mx = fontSurface.H + } + } } + var digitWidth int32 // cache all digits for rendering Numbers of Rows for _, char := range "0123456789" { numsSurface, _ := e.font.ttfFont.RenderGlyphBlended(char, e.font.GetNumColor()) texture, _ := e.renderer.CreateTextureFromSurface(numsSurface) cache.PreRenderredNumsTextures[char] = CharTexture{texture, numsSurface.W} + digitWidth = numsSurface.W } var ( @@ -437,8 +464,8 @@ func (e *Engine) SetCache(supportedChars string) error { rows = h / height columns = w / (width + e.font.GetSpaceBetween()) ) - //println("h:", h, "mx:", mx, "height:", height) - cache.RectangleMatrix = NewRectangleMatrix(rows, columns, e.font.GetSize(), e.font.GetSpaceBetween()) + + cache.RectangleMatrix = NewRectangleMatrix(rows, columns, e.font.GetSize(), e.CharCountInLineNumber*digitWidth+e.font.GetSpaceBetween()+7) // +7 MUST BE HERE. Как в renderText padding = ... + 7 e.cache = cache return nil @@ -471,7 +498,7 @@ func (e *Engine) Loop() { if err != nil { //println(err) } - e.renderText(DEBUG_CUR_ID) + e.RenderText(DEBUG_CUR_ID) for running { event := sdl.WaitEvent() if event == nil { @@ -486,7 +513,7 @@ func (e *Engine) Loop() { case sdl.TextInputEvent: pressedKey := t.GetText() e.InsertChar(rune(pressedKey[0]), DEBUG_CUR_ID) - e.renderText(DEBUG_CUR_ID) + e.RenderText(DEBUG_CUR_ID) break case sdl.KeyboardEvent: // this branch active too when sdl.TextInputEvent @@ -513,7 +540,7 @@ func (e *Engine) Loop() { // TODO 4 -> SPACE_IN_ONE_TAB e.InsertChar('\t', DEBUG_CUR_ID) } - e.renderText(DEBUG_CUR_ID) + e.RenderText(DEBUG_CUR_ID) break } } @@ -551,7 +578,7 @@ func (e *Engine) EraseChar(key sdl.Scancode, cursorId int64) { switch key { case sdl.SCANCODE_BACKSPACE: err = e.text.RemoveCharBefore(cursorId) - //print("res: ", e.text.GetScreenString(0)) + //print("res: ", e.text.GetScreenString(0)) case sdl.SCANCODE_DELETE: err = e.text.RemoveCharAfter(cursorId) } @@ -583,86 +610,86 @@ func (e *Engine) InsertChar(value rune, cursorId int64) { } } - func Contains(s []rune, e rune) bool { - for _, a := range s { - if a == e { - return true - } - } - return false + for _, a := range s { + if a == e { + return true + } + } + return false } + // возвращает массив длины текста // на i-ой позиции цвет i-го символа строки -func HighlightTokensInString(s string) []uint32 { - result := make([]uint32, len(s)) - separators := []rune{' ','\n','(','{','}',')',';','/', '"'} - curStr := "" - lineCommentFlag := 0 - stringStartFlag := 0 - for ind, char := range s { - if stringStartFlag == 1 { - if char == '"' { - stringStartFlag = 0 - } - // гарантируется что существует предыдущий символ, т.к. в данной - // ветке рассматривается случай, когда до текущего символа встретился '"' - result[ind - 1] = textmanager.GREEN - result[ind] = textmanager.GREEN - continue - } - - if char == '/' { - lineCommentFlag++ - } else if lineCommentFlag < 2 { - lineCommentFlag = 0 - } - - if lineCommentFlag >= 2 { - // гарантируется что существует предыдущий символ, т.к. в данной - // ветке рассматривается случай, когда идёт два символа '\' подряд - result[ind - 1] = textmanager.GREY - result[ind] = textmanager.GREY - if char == '\n' { - lineCommentFlag = 0 - curStr = "" - } - continue - } - - if char == '"' { - stringStartFlag = 1 - } - - result[ind] = textmanager.FNTCLR - if Contains(separators, char) { - if color, ok := textmanager.TokensColor[curStr]; ok { - // start coloring - for i:= ind - len(curStr); i < ind; i+=1 { - result[i] = color - } - } - curStr = "" - } else { - curStr += string(char) - } - } - if color, ok := textmanager.TokensColor[curStr]; ok { - for i:= len(s) - len(curStr); i < len(s); i+=1 { - result[i] = color - } - } - // assert(len(s) == len(result)) - return result -} +// func HighlightTokensInString(s string) []uint32 { +// result := make([]uint32, len(s)) +// separators := []rune{' ', '\n', '(', '{', '}', ')', ';', '/', '"'} +// curStr := "" +// lineCommentFlag := 0 +// stringStartFlag := 0 +// for ind, char := range s { +// if stringStartFlag == 1 { +// if char == '"' { +// stringStartFlag = 0 +// } +// // гарантируется что существует предыдущий символ, т.к. в данной +// // ветке рассматривается случай, когда до текущего символа встретился '"' +// result[ind-1] = textmanager.GREEN +// result[ind] = textmanager.GREEN +// continue +// } + +// if char == '/' { +// lineCommentFlag++ +// } else if lineCommentFlag < 2 { +// lineCommentFlag = 0 +// } + +// if lineCommentFlag >= 2 { +// // гарантируется что существует предыдущий символ, т.к. в данной +// // ветке рассматривается случай, когда идёт два символа '\' подряд +// result[ind-1] = textmanager.GREY +// result[ind] = textmanager.GREY +// if char == '\n' { +// lineCommentFlag = 0 +// curStr = "" +// } +// continue +// } + +// if char == '"' { +// stringStartFlag = 1 +// } + +// result[ind] = textmanager.FNTCLR +// if Contains(separators, char) { +// if color, ok := textmanager.TokensColor[curStr]; ok { +// // start coloring +// for i := ind - len(curStr); i < ind; i += 1 { +// result[i] = color +// } +// } +// curStr = "" +// } else { +// curStr += string(char) +// } +// } +// if color, ok := textmanager.TokensColor[curStr]; ok { +// for i := len(s) - len(curStr); i < len(s); i += 1 { +// result[i] = color +// } +// } +// // assert(len(s) == len(result)) +// return result +// } // TODO переписать))) -func (e *Engine) renderText(cursorId int64) { +func (e *Engine) RenderText(cursorId int64) { e.renderer.Clear() var ( // e.font.GetSpaceBetween равен 0, поэтому он сейчас ни на что не влияет || тут +7 px это просто отступ от первой цифры - col int32 = e.CharCountInLineNumber - paddingLeft int32 = (e.font.GetSpaceBetween()+e.cache.PreRenderredCharTextures[rune('1')][textmanager.FNTCLR].Width)*col + 7 + col int32 = e.CharCountInLineNumber + paddingLeft int32 = (e.font.GetSpaceBetween()+e.cache.PreRenderredCharTextures[rune('1')][Colors[textmanager.Normal]].Width)*col + 7 X int32 = paddingLeft Y int32 = 0 row int32 = 0 @@ -673,89 +700,90 @@ func (e *Engine) renderText(cursorId int64) { ) e.renderBackground(paddingLeft) - var currentColor uint32 = textmanager.FNTCLR - for _, c := range e.text.GetScreenString(0) { - if c == '\n' { - Y += e.font.GetSize() - X = paddingLeft + e.font.GetSpaceBetween() - row++ - col = e.CharCountInLineNumber - continue - } - if col >= e.cache.RectangleMatrix.Columns { - continue // это из-за лишних чимволов которые появляются из-за отсптупа для номеров строк - } - // TODO write setter for this -> + screenString, screenTerms := e.text.GetScreenStringWithTerms(0) + for i, c := range screenString { + t := screenTerms[i] + if c == '\n' { + Y += e.font.GetSize() + X = paddingLeft + e.font.GetSpaceBetween() + row++ + col = e.CharCountInLineNumber + continue + } + if col >= e.cache.RectangleMatrix.Columns { + continue // это из-за лишних чимволов которые появляются из-за отсптупа для номеров строк + } + // TODO write setter for this -> e.GetRectFromMatrix(row, col).H = e.font.GetSize() - e.GetRectFromMatrix(row, col).W = e.cache.PreRenderredCharTextures[rune(c)][currentColor].Width + e.GetRectFromMatrix(row, col).W = e.cache.PreRenderredCharTextures[rune(c)][Colors[t]].Width e.GetRectFromMatrix(row, col).X = X e.GetRectFromMatrix(row, col).Y = Y - e.renderer.Copy(e.cache.PreRenderredCharTextures[rune(c)][currentColor].Texture, nil, e.GetRectFromMatrix(row, col)) - X += e.cache.PreRenderredCharTextures[rune(c)][currentColor].Width + e.font.GetSpaceBetween() - col++ + e.renderer.Copy(e.cache.PreRenderredCharTextures[rune(c)][Colors[t]].Texture, nil, e.GetRectFromMatrix(row, col)) + X += e.cache.PreRenderredCharTextures[rune(c)][Colors[t]].Width + e.font.GetSpaceBetween() + col++ } //println("delta:", delta) - /* - //leftBorder := e.text.Cursors[cursorId].ScreenLeft - //println("LeftBorderText: ", leftBorder) - if e.text.Cursors[cursorId].Col < leftBorder { - e.text.Cursors[cursorId].ScreenLeft = e.text.Cursors[cursorId].Col + 1 - delta = e.text.Cursors[cursorId].ScreenLeft - } else if delta >= leftBorder { - e.text.Cursors[cursorId].ScreenLeft = delta - } else { - delta = leftBorder - } - - if delta < 0 { - delta = 0 - } - - // for tokens - var currentColor uint32 = textmanager.FNTCLR - - tokens := HighlightTokensInString(e.text.GetScreenString(0)) - for ind, c := range e.text.GetScreenString(0) { - currentColor = tokens[ind] - if col-4 < delta { - if c == '\n' { - Y += e.font.GetSize() - X = paddingLeft + e.font.GetSpaceBetween() - row++ - col = 4 + /* + //leftBorder := e.text.Cursors[cursorId].ScreenLeft + //println("LeftBorderText: ", leftBorder) + if e.text.Cursors[cursorId].Col < leftBorder { + e.text.Cursors[cursorId].ScreenLeft = e.text.Cursors[cursorId].Col + 1 + delta = e.text.Cursors[cursorId].ScreenLeft + } else if delta >= leftBorder { + e.text.Cursors[cursorId].ScreenLeft = delta } else { - col++ + delta = leftBorder } - continue - } - if col-delta+1 >= e.cache.RectangleMatrix.Columns { - if c == '\n' { - Y += e.font.GetSize() - X = paddingLeft + e.font.GetSpaceBetween() - row++ - col = 4 - } else { + + if delta < 0 { + delta = 0 + } + + // for tokens + var currentColor uint32 = textmanager.FNTCLR + + tokens := HighlightTokensInString(e.text.GetScreenString(0)) + for ind, c := range e.text.GetScreenString(0) { + currentColor = tokens[ind] + if col-4 < delta { + if c == '\n' { + Y += e.font.GetSize() + X = paddingLeft + e.font.GetSpaceBetween() + row++ + col = 4 + } else { + col++ + } + continue + } + if col-delta+1 >= e.cache.RectangleMatrix.Columns { + if c == '\n' { + Y += e.font.GetSize() + X = paddingLeft + e.font.GetSpaceBetween() + row++ + col = 4 + } else { + col++ + } + continue + } + //println("col - del: ", col - delta, "c:", rune(c)) + e.GetRectFromMatrix(row, col-delta).H = e.font.GetSize() + e.GetRectFromMatrix(row, col-delta).W = e.cache.PreRenderredCharTextures[rune(c)][currentColor].Width + e.GetRectFromMatrix(row, col-delta).X = X + e.GetRectFromMatrix(row, col-delta).Y = Y + e.renderer.Copy(e.cache.PreRenderredCharTextures[rune(c)][currentColor].Texture, nil, e.GetRectFromMatrix(row, col-delta)) + X += e.cache.PreRenderredCharTextures[rune(c)][currentColor].Width + e.font.GetSpaceBetween() col++ + if c == '\n' { + Y += e.font.GetSize() + X = paddingLeft + e.font.GetSpaceBetween() + row++ + col = 4 + } } - continue - } - //println("col - del: ", col - delta, "c:", rune(c)) - e.GetRectFromMatrix(row, col-delta).H = e.font.GetSize() - e.GetRectFromMatrix(row, col-delta).W = e.cache.PreRenderredCharTextures[rune(c)][currentColor].Width - e.GetRectFromMatrix(row, col-delta).X = X - e.GetRectFromMatrix(row, col-delta).Y = Y - e.renderer.Copy(e.cache.PreRenderredCharTextures[rune(c)][currentColor].Texture, nil, e.GetRectFromMatrix(row, col-delta)) - X += e.cache.PreRenderredCharTextures[rune(c)][currentColor].Width + e.font.GetSpaceBetween() - col++ - if c == '\n' { - Y += e.font.GetSize() - X = paddingLeft + e.font.GetSpaceBetween() - row++ - col = 4 - } - } - */ + */ cur := e.text.Cursors[cursorId] row = 0 col = 3 @@ -806,10 +834,10 @@ func (e *Engine) renderBackground(paddingLeft int32) { it would be more efficient to do this directly using the function SDL_RenderFillRect." */ e.renderLineNumbersBackground(paddingLeft) - e.renderTextBackground(paddingLeft) + e.RenderTextBackground(paddingLeft) } -func (e *Engine) renderTextBackground(paddingLeft int32) { +func (e *Engine) RenderTextBackground(paddingLeft int32) { w, h := e.window.GetSize() e.renderer.SetDrawColor(hexToRBGA(e.TextBackgroundColor)) @@ -848,8 +876,8 @@ func main() { FontSize int32 = 30 // in px! SpaceBetween int32 = 0 FontFilename string = "MonoNL-Regular.ttf" - FontColor uint32 = textmanager.FNTCLR - LineNumbersColor uint32 = textmanager.LNNMBC + FontColor uint32 = Colors[textmanager.Normal] + LineNumbersColor uint32 = LNNMBC LineNumbersBackgroundColor uint32 = 0x44475aFF TextBackgroundColor uint32 = 0x282a36FF CursorColor uint32 = 0xDAD2D8FF diff --git a/textmanager/textmanager.go b/textmanager/textmanager.go index 103999b..b2dd7f5 100644 --- a/textmanager/textmanager.go +++ b/textmanager/textmanager.go @@ -3,45 +3,42 @@ package textmanager import ( "Type2gether/list" "errors" + "unicode" ) +type Term = byte + const ( - endl = '\n' - PURPLE = 0xDC42DDFF - GOLD = 0xD4AF37FF - RED = 0x51D718FF - RED2 = 0xFF8300FF - BLUE = 0x8A6CD5FF - CIAN = 0xF5A58DFF - PINK = 0x0893FCFF - GREY = 0xC7D7CFFF - GREEN = 0x51D733FF - FNTCLR = 0xFFFFFFFF - LNNMBC = 0xbd93f9FF + Normal Term = iota + Loop + Condition + Type + Bool + Digit + Return + Special ) -var COLORS = []uint32{GREEN, GREY, GOLD, PURPLE, BLUE, CIAN, PINK, FNTCLR, LNNMBC, RED2} - var ( - TokensColor = map[string]uint32{ - "for": PURPLE, - "while": PURPLE, - "if": BLUE, - "else": BLUE, - "return": RED2, - "int": CIAN, - "long": CIAN, - "bool": GOLD, - "true": PINK, - "false": PINK, - "aboba": PINK, - } - MaxTokenLength int + TokensTerm = map[string]Term{ + "for": Loop, + "while": Loop, + "if": Condition, + "else": Condition, + "return": Return, + "int": Type, + "long": Type, + "bool": Type, + "true": Bool, + "false": Bool, + "aboba": Special, + } + // MaxTokenLength int TODO: подумать над использованием ) type Char struct { - Value rune - Color uint32 + Value rune + TermType Term } type Cursor struct { @@ -54,10 +51,10 @@ type Cursor struct { ScreenLeft int32 - ScreenHead *Border - ScreenTail *Border - ScreenRowsCount int32 - ScreenColsCount int32 + ScreenHead *Border + ScreenTail *Border + ScreenRowsCount int32 + ScreenColsCount int32 } //Эта структура нужна для скрола @@ -108,14 +105,14 @@ func (cur *Cursor) ScrollDown() { } func (cur *Cursor) FixLeftScreen() { - if cur.ScreenLeft - 1 > cur.Col { - cur.ScreenLeft = cur.Col + 1 - } else if cur.Col - cur.ScreenLeft > cur.ScreenColsCount { - cur.ScreenLeft = cur.Col - cur.ScreenColsCount - } - if cur.ScreenLeft < 0 { - cur.ScreenLeft = 0 - } + if cur.ScreenLeft-1 > cur.Col { + cur.ScreenLeft = cur.Col + 1 + } else if cur.Col-cur.ScreenLeft > cur.ScreenColsCount { + cur.ScreenLeft = cur.Col - cur.ScreenColsCount + } + if cur.ScreenLeft < 0 { + cur.ScreenLeft = 0 + } } /* @@ -190,7 +187,7 @@ func (t *Text) InsertCharAfter(cursorId int64, value rune) error { cur := t.Cursors[cursorId] if cur.CharIter == nil { - err := cur.LineIter.GetValue().PushFront(Char{Value: value, Color: 0x000000FF}) + err := cur.LineIter.GetValue().PushFront(Char{Value: value, TermType: Normal}) if err != nil { //printtln(err) @@ -199,12 +196,13 @@ func (t *Text) InsertCharAfter(cursorId int64, value rune) error { cur.CharIter = cur.LineIter.GetValue().GetHead() cur.Col = 0 - // пересчитываем screen left - cur.FixLeftScreen() + t.DetectTerms(cursorId) + // пересчитываем screen left + cur.FixLeftScreen() return nil } - err := cur.LineIter.GetValue().InsertAfter(Char{Value: value, Color: 0x000000FF}, cur.CharIter) + err := cur.LineIter.GetValue().InsertAfter(Char{Value: value, TermType: Normal}, cur.CharIter) if err != nil { return err @@ -212,8 +210,88 @@ func (t *Text) InsertCharAfter(cursorId int64, value rune) error { cur.CharIter = cur.CharIter.GetNext() cur.Col++ - // пересчитываем screen left - cur.FixLeftScreen() + t.DetectTerms(cursorId) + // пересчитываем screen left + cur.FixLeftScreen() + return nil +} + +func (t *Text) DetectTerms(cursorId int64) error { + if t.Cursors[cursorId].CharIter == nil { + return errors.New("CharIter is nil") + } + + var ( + ptr = t.Cursors[cursorId].CharIter.GetPrev() + left = t.Cursors[cursorId].CharIter + right = left + ) + + if ptr != nil { + for ptr.GetPrev() != nil && ptr.GetPrev().GetValue().Value != ' ' { + ptr = ptr.GetPrev() + } + left = ptr + } + + ptr = t.Cursors[cursorId].CharIter.GetNext() + if ptr != nil { + for ptr.GetNext() != nil && ptr.GetNext().GetValue().Value != ' ' { + ptr = ptr.GetNext() + } + right = ptr + } + + ptr = left + curToken := "" + onlyDigits := true + for ptr != right.GetNext() { + if !unicode.IsDigit(ptr.GetValue().Value) && ptr.GetValue().Value != ' ' { + onlyDigits = false + } + if ptr.GetValue().Value == ' ' { + var termType Term + if onlyDigits { + termType = Digit + } else { + var ok bool + termType, ok = TokensTerm[curToken] + if !ok { + termType = Normal + } + } + for left != ptr { + val := left.GetValue() + val.TermType = termType + left.SetValue(val) + left = left.GetNext() + } + left = ptr.GetNext() + println("token found: ", curToken) + curToken = "" + onlyDigits = true + } else { + curToken += string(ptr.GetValue().Value) + } + ptr = ptr.GetNext() + } + var termType Term + if onlyDigits { + termType = Digit + } else { + var ok bool + termType, ok = TokensTerm[curToken] + if !ok { + termType = Normal + } + } + for left != ptr { + val := left.GetValue() + val.TermType = termType + left.SetValue(val) + left = left.GetNext() + } + return nil } @@ -278,8 +356,8 @@ func (t *Text) InsertLineAfter(cursorId int64) error { cur.Row++ cur.Col = -1 - // пересчитываем screen left - cur.FixLeftScreen() + // пересчитываем screen left + cur.FixLeftScreen() return nil } // line is empty @@ -311,8 +389,8 @@ func (t *Text) InsertLineAfter(cursorId int64) error { cur.Row++ cur.Col = -1 - // пересчитываем screen left - cur.FixLeftScreen() + // пересчитываем screen left + cur.FixLeftScreen() return nil } @@ -357,8 +435,8 @@ func (t *Text) InsertLineAfter(cursorId int64) error { cur.Row++ cur.Col = -1 - // пересчитываем screen left - cur.FixLeftScreen() + // пересчитываем screen left + cur.FixLeftScreen() return nil } @@ -420,8 +498,9 @@ func (t *Text) RemoveCharBefore(cursorId int64) error { cur.Row-- cur.Col = oldLen - 1 - // пересчитываем screen left - cur.FixLeftScreen() + t.DetectTerms(cursorId) + // пересчитываем screen left + cur.FixLeftScreen() return nil } @@ -434,8 +513,10 @@ func (t *Text) RemoveCharBefore(cursorId int64) error { cur.CharIter = newCharIter cur.Col-- - // пересчитываем screen left - cur.FixLeftScreen() + + t.DetectTerms(cursorId) + // пересчитываем screen left + cur.FixLeftScreen() return nil } @@ -492,27 +573,62 @@ func (t *Text) GetScreenString(cursorId int32) string { ptr1 := cur.ScreenHead.LineIter //printtln(cur.ScreenHead, cur.ScreenTail) res := "" - // итерируемся по каждой строчке + // итерируемся по каждой строчке for ptr1 != nil && ptr1 != cur.ScreenTail.LineIter.GetNext() { ptr2 := ptr1.GetValue().GetHead() - // смотрим, если строка не пустая и в ней достаточно символов - // чтобы их было видно на экране в данный момент - if ptr2 != nil && ptr1.GetValue().Length() >= cur.ScreenLeft { - // начинаем брать строчку с первого символа, который попадает на экран - ptr2 = ptr1.GetValue().GetNodeByIndex(cur.ScreenLeft) - currentLen := int32(0) - // выдаём либо все символы строки, которые помещаются на экран - for ptr2 != nil && currentLen <= cur.ScreenColsCount { - currentLen++ - res += string(ptr2.GetValue().Value) - ptr2 = ptr2.GetNext() - } - } - res += "\n" + // смотрим, если строка не пустая и в ней достаточно символов + // чтобы их было видно на экране в данный момент + if ptr2 != nil && ptr1.GetValue().Length() >= cur.ScreenLeft { + // начинаем брать строчку с первого символа, который попадает на экран + ptr2 = ptr1.GetValue().GetNodeByIndex(cur.ScreenLeft) + currentLen := int32(0) + // выдаём либо все символы строки, которые помещаются на экран + for ptr2 != nil && currentLen <= cur.ScreenColsCount { + currentLen++ + res += string(ptr2.GetValue().Value) + ptr2 = ptr2.GetNext() + } + } + res += "\n" ptr1 = ptr1.GetNext() } return res } + +func (t *Text) GetScreenStringWithTerms(cursorId int32) (string, []Term) { + cur := t.Cursors[cursorId] + if cur.ScreenHead.LineIter == nil || cur.ScreenTail.LineIter == nil { + //printtln("ScreenHead is nil") + return "", []Term{} + } + ptr1 := cur.ScreenHead.LineIter + //printtln(cur.ScreenHead, cur.ScreenTail) + res := "" + terms := []Term{} + // итерируемся по каждой строчке + for ptr1 != nil && ptr1 != cur.ScreenTail.LineIter.GetNext() { + ptr2 := ptr1.GetValue().GetHead() + // смотрим, если строка не пустая и в ней достаточно символов + // чтобы их было видно на экране в данный момент + if ptr2 != nil && ptr1.GetValue().Length() >= cur.ScreenLeft { + // начинаем брать строчку с первого символа, который попадает на экран + ptr2 = ptr1.GetValue().GetNodeByIndex(cur.ScreenLeft) + currentLen := int32(0) + // выдаём либо все символы строки, которые помещаются на экран + for ptr2 != nil && currentLen <= cur.ScreenColsCount { + currentLen++ + res += string(ptr2.GetValue().Value) + terms = append(terms, ptr2.GetValue().TermType) + ptr2 = ptr2.GetNext() + } + } + res += "\n" + terms = append(terms, Normal) + ptr1 = ptr1.GetNext() + } + return res, terms +} + /* // TODO think about width func (t *Text) GetScreenString(cursorId int32) string { @@ -558,16 +674,16 @@ func (cur *Cursor) MoveLeft() { cur.Col = cur.LineIter.GetValue().Length() - 1 - // пересчитываем screen left - cur.FixLeftScreen() + // пересчитываем screen left + cur.FixLeftScreen() return } cur.CharIter = cur.CharIter.GetPrev() cur.Col-- - // пересчитываем screen left - cur.FixLeftScreen() + // пересчитываем screen left + cur.FixLeftScreen() } func (cur *Cursor) MoveRight() { @@ -588,15 +704,15 @@ func (cur *Cursor) MoveRight() { cur.Row++ cur.Col = -1 - // пересчитываем screen left - cur.FixLeftScreen() + // пересчитываем screen left + cur.FixLeftScreen() return } cur.CharIter = cur.LineIter.GetValue().GetHead() cur.Col = 0 - // пересчитываем screen left - cur.FixLeftScreen() + // пересчитываем screen left + cur.FixLeftScreen() return } @@ -615,15 +731,15 @@ func (cur *Cursor) MoveRight() { cur.CharIter = nil cur.Row++ cur.Col = -1 - // пересчитываем screen left - cur.FixLeftScreen() + // пересчитываем screen left + cur.FixLeftScreen() return } cur.CharIter = cur.CharIter.GetNext() cur.Col++ - // пересчитываем screen left - cur.FixLeftScreen() + // пересчитываем screen left + cur.FixLeftScreen() } func (cur *Cursor) MoveUp() { @@ -644,8 +760,8 @@ func (cur *Cursor) MoveUp() { cur.LineIter = cur.LineIter.GetPrev() cur.Row-- cur.Col = cur.LineIter.GetValue().Index(cur.CharIter) - // пересчитываем screen left - cur.FixLeftScreen() + // пересчитываем screen left + cur.FixLeftScreen() } func (cur *Cursor) MoveDown() { @@ -664,20 +780,20 @@ func (cur *Cursor) MoveDown() { cur.LineIter = cur.LineIter.GetNext() cur.Row++ cur.Col = cur.LineIter.GetValue().Index(cur.CharIter) - // пересчитываем screen left - cur.FixLeftScreen() + // пересчитываем screen left + cur.FixLeftScreen() } func (cur *Cursor) MoveHome() { cur.CharIter = nil cur.Col = -1 - // пересчитываем screen left - cur.FixLeftScreen() + // пересчитываем screen left + cur.FixLeftScreen() } func (cur *Cursor) MoveEnd() { cur.CharIter = cur.LineIter.GetValue().GetTail() cur.Col = cur.LineIter.GetValue().Length() - 1 - // пересчитываем screen left - cur.FixLeftScreen() + // пересчитываем screen left + cur.FixLeftScreen() } From 2dad3877ccd16529142494bd8458285bba837b9a Mon Sep 17 00:00:00 2001 From: Glushin Nikita Date: Tue, 20 Jun 2023 17:23:09 +0300 Subject: [PATCH 7/7] added string and comments to highlighting --- main.go | 2 + textmanager/textmanager.go | 134 ++++++++++++++++++++++--------------- 2 files changed, 81 insertions(+), 55 deletions(-) diff --git a/main.go b/main.go index bfafdff..f3e593c 100644 --- a/main.go +++ b/main.go @@ -33,6 +33,8 @@ var Colors = map[textmanager.Term]uint32{ textmanager.Bool: BEIGE, textmanager.Digit: GREY, textmanager.Return: ORANGE, + textmanager.String: GREEN, + textmanager.Comment: GOLD, textmanager.Special: GOLD, } diff --git a/textmanager/textmanager.go b/textmanager/textmanager.go index b2dd7f5..34abcfd 100644 --- a/textmanager/textmanager.go +++ b/textmanager/textmanager.go @@ -3,7 +3,6 @@ package textmanager import ( "Type2gether/list" "errors" - "unicode" ) type Term = byte @@ -16,6 +15,8 @@ const ( Bool Digit Return + Comment + String Special ) @@ -216,85 +217,108 @@ func (t *Text) InsertCharAfter(cursorId int64, value rune) error { return nil } +func Contains(s []rune, e rune) bool { + for _, a := range s { + if a == e { + return true + } + } + return false +} + func (t *Text) DetectTerms(cursorId int64) error { if t.Cursors[cursorId].CharIter == nil { return errors.New("CharIter is nil") } var ( - ptr = t.Cursors[cursorId].CharIter.GetPrev() - left = t.Cursors[cursorId].CharIter - right = left + ptr = t.Cursors[cursorId].LineIter.GetValue().GetHead() + prev *list.Node[Char] = nil + separators = []rune{' ', '\n', '(', '{', '}', ')', ';', '/', '"'} + curStr = "" + lineCommentFlag = 0 + stringStartFlag = 0 ) - if ptr != nil { - for ptr.GetPrev() != nil && ptr.GetPrev().GetValue().Value != ' ' { - ptr = ptr.GetPrev() + for ptr != nil { + char := ptr.GetValue().Value + if stringStartFlag == 1 { + if char == '"' { + stringStartFlag = 0 + } + // гарантируется что существует предыдущий символ, т.к. в данной + // ветке рассматривается случай, когда до текущего символа встретился '"' + + SetTermType(ptr, String) + SetTermType(ptr.GetPrev(), String) + prev = ptr + ptr = ptr.GetNext() + continue + } + + if char == '/' { + lineCommentFlag++ + } else if lineCommentFlag < 2 { + lineCommentFlag = 0 } - left = ptr - } - ptr = t.Cursors[cursorId].CharIter.GetNext() - if ptr != nil { - for ptr.GetNext() != nil && ptr.GetNext().GetValue().Value != ' ' { + if lineCommentFlag >= 2 { + // гарантируется что существует предыдущий символ, т.к. в данной + // ветке рассматривается случай, когда идёт два символа '\' подряд + SetTermType(ptr, Comment) + SetTermType(ptr.GetPrev(), Comment) + + if char == '\n' { + lineCommentFlag = 0 + curStr = "" + } + prev = ptr ptr = ptr.GetNext() + continue } - right = ptr - } - ptr = left - curToken := "" - onlyDigits := true - for ptr != right.GetNext() { - if !unicode.IsDigit(ptr.GetValue().Value) && ptr.GetValue().Value != ' ' { - onlyDigits = false + if char == '"' { + stringStartFlag = 1 } - if ptr.GetValue().Value == ' ' { - var termType Term - if onlyDigits { - termType = Digit - } else { - var ok bool - termType, ok = TokensTerm[curToken] - if !ok { - termType = Normal + + SetTermType(ptr, Normal) + + if Contains(separators, char) { + if term, ok := TokensTerm[curStr]; ok { + backPtr := ptr.GetPrev() + for i := 0; i < len(curStr); i++ { + SetTermType(backPtr, term) + backPtr = backPtr.GetPrev() } } - for left != ptr { - val := left.GetValue() - val.TermType = termType - left.SetValue(val) - left = left.GetNext() - } - left = ptr.GetNext() - println("token found: ", curToken) - curToken = "" - onlyDigits = true + curStr = "" } else { - curToken += string(ptr.GetValue().Value) + curStr += string(char) } + prev = ptr ptr = ptr.GetNext() } - var termType Term - if onlyDigits { - termType = Digit - } else { - var ok bool - termType, ok = TokensTerm[curToken] - if !ok { - termType = Normal - } - } - for left != ptr { - val := left.GetValue() - val.TermType = termType - left.SetValue(val) - left = left.GetNext() + + if prev == nil { + return nil } + if term, ok := TokensTerm[curStr]; ok { + backPtr := prev + for i := 0; i < len(curStr); i++ { + SetTermType(backPtr, term) + backPtr = backPtr.GetPrev() + } + } return nil } +func SetTermType(ptr *list.Node[Char], term Term) { + cur := ptr.GetValue() + cur.TermType = term + ptr.SetValue(cur) +} + // TODO validation func (t *Text) Paste(data string, cursorId int64) error { //cur := t.Cursors[cursorId]