Skip to content

Commit

Permalink
fix line number clipping issue, fix line hightlight issue
Browse files Browse the repository at this point in the history
  • Loading branch information
oligo committed Jul 31, 2024
1 parent 117d313 commit 67f1e43
Show file tree
Hide file tree
Showing 4 changed files with 203 additions and 118 deletions.
60 changes: 11 additions & 49 deletions editor/editor.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
package editor

import (
"errors"
"image"
"io"
"math"
Expand Down Expand Up @@ -615,7 +614,7 @@ func (e *Editor) Update(gtx layout.Context) (EditorEvent, bool) {
// Layout lays out the editor using the provided textMaterial as the paint material
// for the text glyphs+caret and the selectMaterial as the paint material for the
// selection rectangle.
func (e *Editor) Layout(gtx layout.Context, lt *text.Shaper, font font.Font, size unit.Sp, textMaterial, selectMaterial op.CallOp) layout.Dimensions {
func (e *Editor) Layout(gtx layout.Context, lt *text.Shaper, font font.Font, size unit.Sp, textMaterial, selectMaterial op.CallOp, lineMaterial op.CallOp) layout.Dimensions {
for {
_, ok := e.Update(gtx)
if !ok {
Expand All @@ -624,7 +623,7 @@ func (e *Editor) Layout(gtx layout.Context, lt *text.Shaper, font font.Font, siz
}

e.text.Layout(gtx, lt, font, size)
return e.layout(gtx, textMaterial, selectMaterial)
return e.layout(gtx, textMaterial, selectMaterial, lineMaterial)
}

// updateSnippet queues a key.SnippetCmd if the snippet content or position
Expand Down Expand Up @@ -670,7 +669,7 @@ func (e *Editor) updateSnippet(gtx layout.Context, start, end int) {
gtx.Execute(key.SnippetCmd{Tag: e, Snippet: newSnip})
}

func (e *Editor) layout(gtx layout.Context, textMaterial, selectMaterial op.CallOp) layout.Dimensions {
func (e *Editor) layout(gtx layout.Context, textMaterial, selectMaterial op.CallOp, lineMaterial op.CallOp) layout.Dimensions {
// Adjust scrolling for new viewport and layout.
e.text.ScrollRel(0, 0)

Expand Down Expand Up @@ -705,6 +704,7 @@ func (e *Editor) layout(gtx layout.Context, textMaterial, selectMaterial op.Call
if e.Len() > 0 {
e.paintSelection(gtx, selectMaterial)
e.paintText(gtx, textMaterial)
e.paintLineHighlight(gtx, lineMaterial)
}
if gtx.Enabled() {
e.paintCaret(gtx, textMaterial)
Expand Down Expand Up @@ -740,6 +740,11 @@ func (e *Editor) paintCaret(gtx layout.Context, material op.CallOp) {
e.text.PaintCaret(gtx, material)
}

func (e *Editor) paintLineHighlight(gtx layout.Context, material op.CallOp) {
e.initBuffer()
e.text.paintLineHighlight(gtx, material)
}

// Len is the length of the editor contents, in runes.
func (e *Editor) Len() int {
e.initBuffer()
Expand Down Expand Up @@ -1086,51 +1091,8 @@ func (e *Editor) UpdateTextStyles(styles []*TextStyle) {
}

func (e *Editor) VisibleLines() ([]*LineInfo, error) {
linePos, err := e.text.getVisibleLines()
if err != nil {
return nil, err
}

if len(linePos) <= 0 {
return nil, errors.New("no lines found")
}

lines := make([]*LineInfo, 0)
for idx, line := range linePos {
if idx == 0 {
if line.lineCol.line == 0 {
lines = append(lines, &LineInfo{
LineNum: 1,
YOffset: line.y - line.ascent.Ceil(),
Start: line.runes,
})
} else {
startLine := e.buffer.countLinesBeforeOffset(int64(e.text.runeOffset(line.runes)))
lines = append(lines, &LineInfo{
LineNum: startLine + 1,
YOffset: line.y - e.text.ScrollOff().Y - line.ascent.Ceil(),
Start: line.runes,
})
}

continue
}

// update the end position of the last line.
lines[idx-1].End = line.runes

lines = append(lines, &LineInfo{
LineNum: lines[idx-1].LineNum + 1,
YOffset: line.y - e.text.ScrollOff().Y - line.ascent.Ceil(),
Start: line.runes,
})

if idx == len(linePos)-1 {
lines[idx].End = e.text.lastVisibleLineEndPos().runes
}
}

return lines, nil
e.initBuffer()
return e.text.VisibleLines()
}

func max(a, b int) int {
Expand Down
91 changes: 56 additions & 35 deletions editor/editor_style.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"gioui.org/font"
"gioui.org/layout"
"gioui.org/op"
"gioui.org/op/clip"
"gioui.org/op/paint"
"gioui.org/text"
"gioui.org/unit"
Expand All @@ -34,28 +35,35 @@ type EditorStyle struct {
HintColor color.NRGBA
// SelectionColor is the color of the background for selected text.
SelectionColor color.NRGBA
Editor *Editor
ShowLineNum bool
//LineHighlightColor is the color used to highlight the clicked logical line.
// If not set, line will not be highlighted.
LineHighlightColor color.NRGBA

shaper *text.Shaper
Editor *Editor
ShowLineNum bool

shaper *text.Shaper
lineBar *lineNumberBar
}

type lineNumberBar struct {
shaper *text.Shaper
lineHeight unit.Sp
lineHeightScale float32
// Color is the text color.
color color.NRGBA
typeFace font.Typeface
textSize unit.Sp
positions []*LineInfo
color color.NRGBA
typeFace font.Typeface
textSize unit.Sp
// padding between line number and the editor content.
padding unit.Dp
}

type EditorConf struct {
Shaper *text.Shaper
TextColor color.NRGBA
Bg color.NRGBA
SelectionColor color.NRGBA
Shaper *text.Shaper
TextColor color.NRGBA
Bg color.NRGBA
SelectionColor color.NRGBA
LineHighlightColor color.NRGBA
// typeface for editing
TypeFace font.Typeface
TextSize unit.Sp
Expand All @@ -65,23 +73,39 @@ type EditorConf struct {
//May be helpful for code syntax highlighting.
ColorScheme string
ShowLineNum bool
// padding between line number and the editor content.
LineNumPadding unit.Dp
}

func NewEditor(editor *Editor, conf *EditorConf, hint string) EditorStyle {
if conf.LineNumPadding <= 0 {
conf.LineNumPadding = unit.Dp(32)
}

return EditorStyle{
Editor: editor,
Font: font.Font{
Typeface: conf.TypeFace,
Weight: conf.Weight,
},
LineHeightScale: conf.LineHeightScale,
TextSize: conf.TextSize,
Color: conf.TextColor,
shaper: conf.Shaper,
Hint: hint,
HintColor: MulAlpha(conf.TextColor, 0xbb),
SelectionColor: MulAlpha(conf.SelectionColor, 0x60),
ShowLineNum: conf.ShowLineNum,
LineHeightScale: conf.LineHeightScale,
TextSize: conf.TextSize,
Color: conf.TextColor,
shaper: conf.Shaper,
Hint: hint,
HintColor: MulAlpha(conf.TextColor, 0xbb),
SelectionColor: MulAlpha(conf.SelectionColor, 0x60),
LineHighlightColor: MulAlpha(conf.LineHighlightColor, 0x25),
ShowLineNum: conf.ShowLineNum,
lineBar: &lineNumberBar{
shaper: conf.Shaper,
lineHeight: conf.LineHeight,
lineHeightScale: conf.LineHeightScale,
color: misc.WithAlpha(conf.TextColor, 0xb6),
typeFace: conf.TypeFace,
textSize: conf.TextSize,
padding: conf.LineNumPadding,
},
}
}

Expand All @@ -96,6 +120,9 @@ func (e EditorStyle) Layout(gtx layout.Context) layout.Dimensions {
selectionColorMacro := op.Record(gtx.Ops)
paint.ColorOp{Color: blendDisabledColor(!gtx.Enabled(), e.SelectionColor)}.Add(gtx.Ops)
selectionColor := selectionColorMacro.Stop()
lineColorMacro := op.Record(gtx.Ops)
paint.ColorOp{Color: e.LineHighlightColor}.Add(gtx.Ops)
lineColor := lineColorMacro.Stop()

macro := op.Record(gtx.Ops)
tl := widget.Label{
Expand All @@ -117,33 +144,26 @@ func (e EditorStyle) Layout(gtx layout.Context) layout.Dimensions {
e.Editor.LineHeightScale = e.LineHeightScale

if !e.ShowLineNum {
d := e.Editor.Layout(gtx, e.shaper, e.Font, e.TextSize, textColor, selectionColor)
d := e.Editor.Layout(gtx, e.shaper, e.Font, e.TextSize, textColor, selectionColor, lineColor)
if e.Editor.Len() == 0 {
call.Add(gtx.Ops)
}
return d
}

// clip line number bar.
defer clip.Rect(image.Rectangle{Max: gtx.Constraints.Max}).Push(gtx.Ops).Pop()
dims = layout.Flex{
Axis: layout.Horizontal,
}.Layout(gtx,
layout.Rigid(func(gtx layout.Context) layout.Dimensions {
lines, _ := e.Editor.VisibleLines()
return lineNumberBar{
shaper: e.shaper,
lineHeight: e.LineHeight,
lineHeightScale: e.LineHeightScale,
color: misc.WithAlpha(e.Color, 0xb6),
typeFace: e.Font.Typeface,
textSize: e.TextSize,
positions: lines,
}.Layout(gtx)
return e.lineBar.Layout(gtx, e.Editor)
}),

layout.Rigid(layout.Spacer{Width: unit.Dp(20)}.Layout),
layout.Rigid(layout.Spacer{Width: e.lineBar.padding}.Layout),

layout.Rigid(func(gtx layout.Context) layout.Dimensions {
d := e.Editor.Layout(gtx, e.shaper, e.Font, e.TextSize, textColor, selectionColor)
d := e.Editor.Layout(gtx, e.shaper, e.Font, e.TextSize, textColor, selectionColor, lineColor)
if e.Editor.Len() == 0 {
call.Add(gtx.Ops)
}
Expand Down Expand Up @@ -173,7 +193,7 @@ func (bar lineNumberBar) layoutLine(gtx layout.Context, pos *LineInfo, textColor
return d
}

func (bar lineNumberBar) Layout(gtx layout.Context) layout.Dimensions {
func (bar lineNumberBar) Layout(gtx layout.Context, e *Editor) layout.Dimensions {
dims := layout.Dimensions{Size: image.Point{X: gtx.Constraints.Min.X}}

textColorMacro := op.Record(gtx.Ops)
Expand All @@ -183,9 +203,10 @@ func (bar lineNumberBar) Layout(gtx layout.Context) layout.Dimensions {
fake := gtx
fake.Ops = &op.Ops{}

positions, _ := e.VisibleLines()
maxWidth := 0
{
for _, pos := range bar.positions {
for _, pos := range positions {
d := bar.layoutLine(fake, pos, textColor)
maxWidth = max(maxWidth, d.Size.X)
}
Expand All @@ -194,7 +215,7 @@ func (bar lineNumberBar) Layout(gtx layout.Context) layout.Dimensions {

gtx.Constraints.Max.X = maxWidth
gtx.Constraints.Min.X = gtx.Constraints.Max.X
for _, pos := range bar.positions {
for _, pos := range positions {
d := bar.layoutLine(gtx, pos, textColor)
dims.Size = image.Point{X: maxWidth, Y: dims.Size.Y + d.Size.Y}
}
Expand Down
Loading

0 comments on commit 67f1e43

Please sign in to comment.