12 luar "layeh.com/gopher-luar"
14 runewidth "github.com/mattn/go-runewidth"
15 lua "github.com/yuin/gopher-lua"
16 "github.com/zyedidia/micro/internal/buffer"
17 "github.com/zyedidia/micro/internal/config"
18 ulua "github.com/zyedidia/micro/internal/lua"
19 "github.com/zyedidia/micro/internal/screen"
20 "github.com/zyedidia/micro/internal/util"
23 // StatusLine represents the information line at the bottom
25 // It gives information such as filename, whether the file has been
26 // modified, filetype, cursor location
27 type StatusLine struct {
28 Info map[string]func(*buffer.Buffer) string
33 var statusInfo = map[string]func(*buffer.Buffer) string{
34 "filename": func(b *buffer.Buffer) string {
35 if b.Settings["basename"].(bool) {
36 return path.Base(b.GetName())
40 "line": func(b *buffer.Buffer) string {
41 return strconv.Itoa(b.GetActiveCursor().Y + 1)
43 "col": func(b *buffer.Buffer) string {
44 return strconv.Itoa(b.GetActiveCursor().X + 1)
46 "modified": func(b *buffer.Buffer) string {
57 func SetStatusInfoFnLua(fn string) {
58 luaFn := strings.Split(fn, ".")
62 plName, plFn := luaFn[0], luaFn[1]
63 pl := config.FindPlugin(plName)
67 statusInfo[fn] = func(b *buffer.Buffer) string {
68 if pl == nil || !pl.IsEnabled() {
71 val, err := pl.Call(plFn, luar.New(ulua.L, b))
73 if v, ok := val.(lua.LString); !ok {
74 screen.TermMessage(plFn, "should return a string")
84 // NewStatusLine returns a statusline bound to a window
85 func NewStatusLine(win *BufWindow) *StatusLine {
91 // FindOpt finds a given option in the current buffer's settings
92 func (s *StatusLine) FindOpt(opt string) interface{} {
93 if val, ok := s.win.Buf.Settings[opt]; ok {
99 var formatParser = regexp.MustCompile(`\$\(.+?\)`)
101 // Display draws the statusline to the screen
102 func (s *StatusLine) Display() {
103 // We'll draw the line at the lowest line in the window
104 y := s.win.Height + s.win.Y - 1
107 // autocomplete suggestions (for the buffer, not for the infowindow)
108 if b.HasSuggestions && len(b.Suggestions) > 1 {
109 statusLineStyle := config.DefStyle.Reverse(true)
110 if style, ok := config.Colorscheme["statusline"]; ok {
111 statusLineStyle = style
114 if config.GetGlobalOption("keymenu").(bool) {
115 keymenuOffset = len(keydisplay)
118 for j, sug := range b.Suggestions {
119 style := statusLineStyle
120 if b.CurSuggestion == j {
121 style = style.Reverse(true)
123 for _, r := range sug {
124 screen.SetContent(x, y-keymenuOffset, r, nil, style)
126 if x >= s.win.Width {
130 screen.SetContent(x, y-keymenuOffset, ' ', nil, statusLineStyle)
132 if x >= s.win.Width {
137 for x < s.win.Width {
138 screen.SetContent(x, y-keymenuOffset, ' ', nil, statusLineStyle)
144 formatter := func(match []byte) []byte {
145 name := match[2 : len(match)-1]
146 if bytes.HasPrefix(name, []byte("opt")) {
148 return []byte(fmt.Sprint(s.FindOpt(string(option))))
149 } else if bytes.HasPrefix(name, []byte("bind")) {
150 binding := string(name[5:])
151 for k, v := range config.Bindings {
156 return []byte("null")
158 if fn, ok := statusInfo[string(name)]; ok {
159 return []byte(fn(s.win.Buf))
165 leftText := []byte(s.win.Buf.Settings["statusformatl"].(string))
166 leftText = formatParser.ReplaceAllFunc(leftText, formatter)
167 rightText := []byte(s.win.Buf.Settings["statusformatr"].(string))
168 rightText = formatParser.ReplaceAllFunc(rightText, formatter)
170 statusLineStyle := config.DefStyle.Reverse(true)
171 if style, ok := config.Colorscheme["statusline"]; ok {
172 statusLineStyle = style
175 leftLen := util.StringWidth(leftText, utf8.RuneCount(leftText), 1)
176 rightLen := util.StringWidth(rightText, utf8.RuneCount(rightText), 1)
179 for x := 0; x < s.win.Width; x++ {
181 r, size := utf8.DecodeRune(leftText)
182 leftText = leftText[size:]
183 rw := runewidth.RuneWidth(r)
184 for j := 0; j < rw; j++ {
190 screen.SetContent(winX+x, y, c, nil, statusLineStyle)
192 } else if x >= s.win.Width-rightLen && x < rightLen+s.win.Width-rightLen {
193 r, size := utf8.DecodeRune(rightText)
194 rightText = rightText[size:]
195 rw := runewidth.RuneWidth(r)
196 for j := 0; j < rw; j++ {
202 screen.SetContent(winX+x, y, c, nil, statusLineStyle)
205 screen.SetContent(winX+x, y, ' ', nil, statusLineStyle)