import (
"bytes"
"fmt"
- "path"
"regexp"
"strconv"
- "unicode/utf8"
+ "strings"
+
+ luar "layeh.com/gopher-luar"
runewidth "github.com/mattn/go-runewidth"
- "github.com/zyedidia/micro/internal/buffer"
- "github.com/zyedidia/micro/internal/config"
- "github.com/zyedidia/micro/internal/screen"
- "github.com/zyedidia/micro/internal/util"
+ lua "github.com/yuin/gopher-lua"
+ "github.com/zyedidia/micro/v2/internal/buffer"
+ "github.com/zyedidia/micro/v2/internal/config"
+ ulua "github.com/zyedidia/micro/v2/internal/lua"
+ "github.com/zyedidia/micro/v2/internal/screen"
+ "github.com/zyedidia/micro/v2/internal/util"
)
// StatusLine represents the information line at the bottom
win *BufWindow
}
-// TODO: plugin modify status line formatter
+var statusInfo = map[string]func(*buffer.Buffer) string{
+ "filename": func(b *buffer.Buffer) string {
+ return b.GetName()
+ },
+ "line": func(b *buffer.Buffer) string {
+ return strconv.Itoa(b.GetActiveCursor().Y + 1)
+ },
+ "col": func(b *buffer.Buffer) string {
+ return strconv.Itoa(b.GetActiveCursor().X + 1)
+ },
+ "modified": func(b *buffer.Buffer) string {
+ if b.Modified() {
+ return "+ "
+ }
+ if b.Type.Readonly {
+ return "[ro] "
+ }
+ return ""
+ },
+}
+
+func SetStatusInfoFnLua(fn string) {
+ luaFn := strings.Split(fn, ".")
+ if len(luaFn) <= 1 {
+ return
+ }
+ plName, plFn := luaFn[0], luaFn[1]
+ pl := config.FindPlugin(plName)
+ if pl == nil {
+ return
+ }
+ statusInfo[fn] = func(b *buffer.Buffer) string {
+ if pl == nil || !pl.IsEnabled() {
+ return ""
+ }
+ val, err := pl.Call(plFn, luar.New(ulua.L, b))
+ if err == nil {
+ if v, ok := val.(lua.LString); !ok {
+ screen.TermMessage(plFn, "should return a string")
+ return ""
+ } else {
+ return string(v)
+ }
+ }
+ return ""
+ }
+}
// NewStatusLine returns a statusline bound to a window
func NewStatusLine(win *BufWindow) *StatusLine {
s := new(StatusLine)
- s.Info = map[string]func(*buffer.Buffer) string{
- "filename": func(b *buffer.Buffer) string {
- if b.Settings["basename"].(bool) {
- return path.Base(b.GetName())
- }
- return b.GetName()
- },
- "line": func(b *buffer.Buffer) string {
- return strconv.Itoa(b.GetActiveCursor().Y + 1)
- },
- "col": func(b *buffer.Buffer) string {
- return strconv.Itoa(b.GetActiveCursor().X + 1)
- },
- "modified": func(b *buffer.Buffer) string {
- if b.Modified() {
- return "+ "
- }
- return ""
- },
- }
s.win = win
return s
}
// We'll draw the line at the lowest line in the window
y := s.win.Height + s.win.Y - 1
+ winX := s.win.X
+
b := s.win.Buf
+ // autocomplete suggestions (for the buffer, not for the infowindow)
if b.HasSuggestions && len(b.Suggestions) > 1 {
statusLineStyle := config.DefStyle.Reverse(true)
if style, ok := config.Colorscheme["statusline"]; ok {
statusLineStyle = style
}
- keymenuOffset := 0
- if config.GetGlobalOption("keymenu").(bool) {
- keymenuOffset = len(keydisplay)
- }
x := 0
for j, sug := range b.Suggestions {
style := statusLineStyle
style = style.Reverse(true)
}
for _, r := range sug {
- screen.Screen.SetContent(x, y-keymenuOffset, r, nil, style)
+ screen.SetContent(winX+x, y, r, nil, style)
x++
if x >= s.win.Width {
return
}
}
- screen.Screen.SetContent(x, y-keymenuOffset, ' ', nil, statusLineStyle)
+ screen.SetContent(winX+x, y, ' ', nil, statusLineStyle)
x++
if x >= s.win.Width {
return
}
for x < s.win.Width {
- screen.Screen.SetContent(x, y-keymenuOffset, ' ', nil, statusLineStyle)
+ screen.SetContent(winX+x, y, ' ', nil, statusLineStyle)
x++
}
return
return []byte(fmt.Sprint(s.FindOpt(string(option))))
} else if bytes.HasPrefix(name, []byte("bind")) {
binding := string(name[5:])
- for k, v := range config.Bindings {
+ for k, v := range config.Bindings["buffer"] {
if v == binding {
return []byte(k)
}
}
return []byte("null")
} else {
- return []byte(s.Info[string(name)](s.win.Buf))
+ if fn, ok := statusInfo[string(name)]; ok {
+ return []byte(fn(s.win.Buf))
+ }
+ return []byte{}
}
}
- leftText := []byte(s.win.Buf.StatusFormatLeft)
+ leftText := []byte(s.win.Buf.Settings["statusformatl"].(string))
leftText = formatParser.ReplaceAllFunc(leftText, formatter)
- rightText := []byte(s.win.Buf.StatusFormatRight)
+ rightText := []byte(s.win.Buf.Settings["statusformatr"].(string))
rightText = formatParser.ReplaceAllFunc(rightText, formatter)
statusLineStyle := config.DefStyle.Reverse(true)
statusLineStyle = style
}
- leftLen := util.StringWidth(leftText, utf8.RuneCount(leftText), 1)
- rightLen := util.StringWidth(rightText, utf8.RuneCount(rightText), 1)
+ leftLen := util.StringWidth(leftText, util.CharacterCount(leftText), 1)
+ rightLen := util.StringWidth(rightText, util.CharacterCount(rightText), 1)
- winX := s.win.X
for x := 0; x < s.win.Width; x++ {
if x < leftLen {
- r, size := utf8.DecodeRune(leftText)
+ r, combc, size := util.DecodeCharacter(leftText)
leftText = leftText[size:]
rw := runewidth.RuneWidth(r)
for j := 0; j < rw; j++ {
c := r
if j > 0 {
c = ' '
+ combc = nil
x++
}
- screen.Screen.SetContent(winX+x, y, c, nil, statusLineStyle)
+ screen.SetContent(winX+x, y, c, combc, statusLineStyle)
}
} else if x >= s.win.Width-rightLen && x < rightLen+s.win.Width-rightLen {
- r, size := utf8.DecodeRune(rightText)
+ r, combc, size := util.DecodeCharacter(rightText)
rightText = rightText[size:]
rw := runewidth.RuneWidth(r)
for j := 0; j < rw; j++ {
c := r
if j > 0 {
c = ' '
+ combc = nil
x++
}
- screen.Screen.SetContent(winX+x, y, c, nil, statusLineStyle)
+ screen.SetContent(winX+x, y, c, combc, statusLineStyle)
}
} else {
- screen.Screen.SetContent(winX+x, y, ' ', nil, statusLineStyle)
+ screen.SetContent(winX+x, y, ' ', nil, statusLineStyle)
}
}
}