10 luar "layeh.com/gopher-luar"
12 runewidth "github.com/mattn/go-runewidth"
13 lua "github.com/yuin/gopher-lua"
14 "github.com/zyedidia/micro/v2/internal/buffer"
15 "github.com/zyedidia/micro/v2/internal/config"
16 ulua "github.com/zyedidia/micro/v2/internal/lua"
17 "github.com/zyedidia/micro/v2/internal/screen"
18 "github.com/zyedidia/micro/v2/internal/util"
21 // StatusLine represents the information line at the bottom
23 // It gives information such as filename, whether the file has been
24 // modified, filetype, cursor location
25 type StatusLine struct {
26 Info map[string]func(*buffer.Buffer) string
31 var statusInfo = map[string]func(*buffer.Buffer) string{
32 "filename": func(b *buffer.Buffer) string {
35 "line": func(b *buffer.Buffer) string {
36 return strconv.Itoa(b.GetActiveCursor().Y + 1)
38 "col": func(b *buffer.Buffer) string {
39 return strconv.Itoa(b.GetActiveCursor().X + 1)
41 "modified": func(b *buffer.Buffer) string {
50 "lines": func(b *buffer.Buffer) string {
51 return strconv.Itoa(b.LinesNum())
53 "percentage": func(b *buffer.Buffer) string {
54 return strconv.Itoa((b.GetActiveCursor().Y + 1) * 100 / b.LinesNum())
58 func SetStatusInfoFnLua(fn string) {
59 luaFn := strings.Split(fn, ".")
63 plName, plFn := luaFn[0], luaFn[1]
64 pl := config.FindPlugin(plName)
68 statusInfo[fn] = func(b *buffer.Buffer) string {
69 if pl == nil || !pl.IsEnabled() {
72 val, err := pl.Call(plFn, luar.New(ulua.L, b))
74 if v, ok := val.(lua.LString); !ok {
75 screen.TermMessage(plFn, "should return a string")
85 // NewStatusLine returns a statusline bound to a window
86 func NewStatusLine(win *BufWindow) *StatusLine {
92 // FindOpt finds a given option in the current buffer's settings
93 func (s *StatusLine) FindOpt(opt string) interface{} {
94 if val, ok := s.win.Buf.Settings[opt]; ok {
100 var formatParser = regexp.MustCompile(`\$\(.+?\)`)
102 // Display draws the statusline to the screen
103 func (s *StatusLine) Display() {
104 // We'll draw the line at the lowest line in the window
105 y := s.win.Height + s.win.Y - 1
110 // autocomplete suggestions (for the buffer, not for the infowindow)
111 if b.HasSuggestions && len(b.Suggestions) > 1 {
112 statusLineStyle := config.DefStyle.Reverse(true)
113 if style, ok := config.Colorscheme["statusline"]; ok {
114 statusLineStyle = style
117 for j, sug := range b.Suggestions {
118 style := statusLineStyle
119 if b.CurSuggestion == j {
120 style = style.Reverse(true)
122 for _, r := range sug {
123 screen.SetContent(winX+x, y, r, nil, style)
125 if x >= s.win.Width {
129 screen.SetContent(winX+x, y, ' ', nil, statusLineStyle)
131 if x >= s.win.Width {
136 for x < s.win.Width {
137 screen.SetContent(winX+x, y, ' ', nil, statusLineStyle)
143 formatter := func(match []byte) []byte {
144 name := match[2 : len(match)-1]
145 if bytes.HasPrefix(name, []byte("opt")) {
147 return []byte(fmt.Sprint(s.FindOpt(string(option))))
148 } else if bytes.HasPrefix(name, []byte("bind")) {
149 binding := string(name[5:])
150 for k, v := range config.Bindings["buffer"] {
155 return []byte("null")
157 if fn, ok := statusInfo[string(name)]; ok {
158 return []byte(fn(s.win.Buf))
164 leftText := []byte(s.win.Buf.Settings["statusformatl"].(string))
165 leftText = formatParser.ReplaceAllFunc(leftText, formatter)
166 rightText := []byte(s.win.Buf.Settings["statusformatr"].(string))
167 rightText = formatParser.ReplaceAllFunc(rightText, formatter)
169 statusLineStyle := config.DefStyle.Reverse(true)
170 if style, ok := config.Colorscheme["statusline"]; ok {
171 statusLineStyle = style
174 leftLen := util.StringWidth(leftText, util.CharacterCount(leftText), 1)
175 rightLen := util.StringWidth(rightText, util.CharacterCount(rightText), 1)
177 for x := 0; x < s.win.Width; x++ {
179 r, combc, size := util.DecodeCharacter(leftText)
180 leftText = leftText[size:]
181 rw := runewidth.RuneWidth(r)
182 for j := 0; j < rw; j++ {
189 screen.SetContent(winX+x, y, c, combc, statusLineStyle)
191 } else if x >= s.win.Width-rightLen && x < rightLen+s.win.Width-rightLen {
192 r, combc, size := util.DecodeCharacter(rightText)
193 rightText = rightText[size:]
194 rw := runewidth.RuneWidth(r)
195 for j := 0; j < rw; j++ {
202 screen.SetContent(winX+x, y, c, combc, statusLineStyle)
205 screen.SetContent(winX+x, y, ' ', nil, statusLineStyle)