package display
import (
- "unicode/utf8"
-
runewidth "github.com/mattn/go-runewidth"
- "github.com/zyedidia/micro/internal/buffer"
- "github.com/zyedidia/micro/internal/config"
- "github.com/zyedidia/micro/internal/info"
- "github.com/zyedidia/micro/internal/screen"
- "github.com/zyedidia/micro/internal/util"
- "github.com/zyedidia/tcell"
+ "github.com/zyedidia/micro/v2/internal/buffer"
+ "github.com/zyedidia/micro/v2/internal/config"
+ "github.com/zyedidia/micro/v2/internal/info"
+ "github.com/zyedidia/micro/v2/internal/screen"
+ "github.com/zyedidia/micro/v2/internal/util"
+ "github.com/zyedidia/tcell/v2"
)
type InfoWindow struct {
*info.InfoBuf
*View
+
+ hscroll int
}
func (i *InfoWindow) errStyle() tcell.Style {
func (i *InfoWindow) LocFromVisual(vloc buffer.Loc) buffer.Loc {
c := i.Buffer.GetActiveCursor()
l := i.Buffer.LineBytes(0)
- n := utf8.RuneCountInString(i.Msg)
+ n := util.CharacterCountInString(i.Msg)
return buffer.Loc{c.GetCharPosInLine(l, vloc.X-n), 0}
}
+func (i *InfoWindow) BufWidth() int { return i.Width }
+func (i *InfoWindow) BufHeight() int { return 1 }
+
+func (i *InfoWindow) Scroll(s SLoc, n int) SLoc { return s }
+func (i *InfoWindow) Diff(s1, s2 SLoc) int { return 0 }
+func (i *InfoWindow) SLocFromLoc(loc buffer.Loc) SLoc { return SLoc{0, 0} }
+func (i *InfoWindow) VLocFromLoc(loc buffer.Loc) VLoc { return VLoc{SLoc{0, 0}, loc.X} }
+func (i *InfoWindow) LocFromVLoc(vloc VLoc) buffer.Loc { return buffer.Loc{vloc.VisualX, 0} }
+
func (i *InfoWindow) Clear() {
for x := 0; x < i.Width; x++ {
- screen.Screen.SetContent(x, i.Y, ' ', nil, i.defStyle())
+ screen.SetContent(x, i.Y, ' ', nil, i.defStyle())
}
}
activeC := b.GetActiveCursor()
blocX := 0
- vlocX := utf8.RuneCountInString(i.Msg)
+ vlocX := util.CharacterCountInString(i.Msg)
tabsize := 4
line, nColsBeforeStart, bslice := util.SliceVisualEnd(line, blocX, tabsize)
blocX = bslice
- draw := func(r rune, style tcell.Style) {
+ draw := func(r rune, combc []rune, style tcell.Style) {
if nColsBeforeStart <= 0 {
bloc := buffer.Loc{X: blocX, Y: 0}
if activeC.HasSelection() &&
c := r
if j > 0 {
c = ' '
+ combc = nil
}
- screen.Screen.SetContent(vlocX, i.Y, c, nil, style)
+ screen.SetContent(vlocX, i.Y, c, combc, style)
}
vlocX++
}
totalwidth := blocX - nColsBeforeStart
for len(line) > 0 {
- if activeC.X == blocX {
- screen.Screen.ShowCursor(vlocX, i.Y)
- }
-
- r, size := utf8.DecodeRune(line)
+ curVX := vlocX
+ curBX := blocX
+ r, combc, size := util.DecodeCharacter(line)
- draw(r, i.defStyle())
+ draw(r, combc, i.defStyle())
width := 0
// Draw any extra characters either spaces for tabs or @ for incomplete wide runes
if width > 1 {
for j := 1; j < width; j++ {
- draw(char, i.defStyle())
+ draw(char, nil, i.defStyle())
}
}
+ if activeC.X == curBX {
+ screen.ShowCursor(curVX, i.Y)
+ }
totalwidth += width
if vlocX >= i.Width {
break
}
}
if activeC.X == blocX {
- screen.Screen.ShowCursor(vlocX, i.Y)
+ screen.ShowCursor(vlocX, i.Y)
}
}
for y := 0; y < len(keydisplay); y++ {
for x := 0; x < i.Width; x++ {
if x < len(keydisplay[y]) {
- screen.Screen.SetContent(x, i.Y-len(keydisplay)+y, rune(keydisplay[y][x]), nil, i.defStyle())
+ screen.SetContent(x, i.Y-len(keydisplay)+y, rune(keydisplay[y][x]), nil, i.defStyle())
} else {
- screen.Screen.SetContent(x, i.Y-len(keydisplay)+y, ' ', nil, i.defStyle())
+ screen.SetContent(x, i.Y-len(keydisplay)+y, ' ', nil, i.defStyle())
}
}
}
}
-func (i *InfoWindow) Display() {
+func (i *InfoWindow) totalSize() int {
+ sum := 0
+ for _, n := range i.Suggestions {
+ sum += runewidth.StringWidth(n) + 1
+ }
+ return sum
+}
+
+func (i *InfoWindow) scrollToSuggestion() {
x := 0
- if config.GetGlobalOption("keymenu").(bool) {
- i.displayKeyMenu()
+ s := i.totalSize()
+
+ for j, n := range i.Suggestions {
+ c := util.CharacterCountInString(n)
+ if j == i.CurSuggestion {
+ if x+c >= i.hscroll+i.Width {
+ i.hscroll = util.Clamp(x+c+1-i.Width, 0, s-i.Width)
+ } else if x < i.hscroll {
+ i.hscroll = util.Clamp(x-1, 0, s-i.Width)
+ }
+ break
+ }
+ x += c + 1
+ }
+
+ if s-i.Width <= 0 {
+ i.hscroll = 0
}
+}
+func (i *InfoWindow) Display() {
if i.HasPrompt || config.GlobalSettings["infobar"].(bool) {
+ i.Clear()
+ x := 0
+ if config.GetGlobalOption("keymenu").(bool) {
+ i.displayKeyMenu()
+ }
+
if !i.HasPrompt && !i.HasMessage && !i.HasError {
return
}
display := i.Msg
for _, c := range display {
- screen.Screen.SetContent(x, i.Y, c, nil, style)
+ screen.SetContent(x, i.Y, c, nil, style)
x += runewidth.RuneWidth(c)
}
}
if i.HasSuggestions && len(i.Suggestions) > 1 {
+ i.scrollToSuggestion()
+
+ x := -i.hscroll
+ done := false
+
statusLineStyle := config.DefStyle.Reverse(true)
if style, ok := config.Colorscheme["statusline"]; ok {
statusLineStyle = style
if config.GetGlobalOption("keymenu").(bool) {
keymenuOffset = len(keydisplay)
}
- x := 0
+
+ draw := func(r rune, s tcell.Style) {
+ y := i.Y - keymenuOffset - 1
+ rw := runewidth.RuneWidth(r)
+ for j := 0; j < rw; j++ {
+ c := r
+ if j > 0 {
+ c = ' '
+ }
+
+ if x == i.Width-1 && !done {
+ screen.SetContent(i.Width-1, y, '>', nil, s)
+ x++
+ break
+ } else if x == 0 && i.hscroll > 0 {
+ screen.SetContent(0, y, '<', nil, s)
+ } else if x >= 0 && x < i.Width {
+ screen.SetContent(x, y, c, nil, s)
+ }
+ x++
+ }
+ }
+
for j, s := range i.Suggestions {
style := statusLineStyle
if i.CurSuggestion == j {
style = style.Reverse(true)
}
for _, r := range s {
- screen.Screen.SetContent(x, i.Y-keymenuOffset-1, r, nil, style)
- x++
- if x >= i.Width {
- return
- }
- }
- screen.Screen.SetContent(x, i.Y-keymenuOffset-1, ' ', nil, statusLineStyle)
- x++
- if x >= i.Width {
- return
+ draw(r, style)
+ // screen.SetContent(x, i.Y-keymenuOffset-1, r, nil, style)
}
+ draw(' ', statusLineStyle)
}
for x < i.Width {
- screen.Screen.SetContent(x, i.Y-keymenuOffset-1, ' ', nil, statusLineStyle)
- x++
+ draw(' ', statusLineStyle)
}
}
}