micro/internal/display/statusline.go

121 lines
3.3 KiB
Go
Raw Normal View History

2018-08-29 01:44:52 +03:00
package display
2016-03-18 01:20:07 +03:00
import (
2018-08-26 06:06:44 +03:00
"bytes"
"fmt"
2018-01-03 06:25:55 +03:00
"path"
2018-08-26 06:06:44 +03:00
"regexp"
2016-03-18 01:20:07 +03:00
"strconv"
2018-08-26 06:06:44 +03:00
"unicode/utf8"
2018-08-27 22:53:10 +03:00
2019-02-04 07:17:24 +03:00
"github.com/zyedidia/micro/internal/buffer"
"github.com/zyedidia/micro/internal/config"
"github.com/zyedidia/micro/internal/screen"
2016-03-18 01:20:07 +03:00
)
2018-08-26 06:06:44 +03:00
// StatusLine represents the information line at the bottom
// of each window
2016-03-25 19:14:22 +03:00
// It gives information such as filename, whether the file has been
// modified, filetype, cursor location
2018-08-26 06:06:44 +03:00
type StatusLine struct {
FormatLeft string
FormatRight string
2018-08-27 22:53:10 +03:00
Info map[string]func(*buffer.Buffer) string
2016-03-18 01:20:07 +03:00
2018-08-29 01:44:52 +03:00
win *BufWindow
2018-08-26 06:06:44 +03:00
}
2018-08-26 06:06:44 +03:00
// TODO: plugin modify status line formatter
2016-03-18 01:20:07 +03:00
2018-08-26 06:06:44 +03:00
// NewStatusLine returns a statusline bound to a window
2018-08-29 01:44:52 +03:00
func NewStatusLine(win *BufWindow) *StatusLine {
2018-08-26 06:06:44 +03:00
s := new(StatusLine)
s.FormatLeft = "$(filename) $(modified)($(line),$(col)) $(opt:filetype) $(opt:fileformat) $(opt:encoding)"
2018-08-28 00:55:28 +03:00
// s.FormatLeft = "$(filename) $(modified)(line,col) $(opt:filetype) $(opt:fileformat)"
2019-01-16 01:10:13 +03:00
s.FormatRight = "$(bind:ToggleKeyMenu): show bindings, $(bind:ToggleHelp): toggle help"
2018-08-27 22:53:10 +03:00
s.Info = map[string]func(*buffer.Buffer) string{
"filename": func(b *buffer.Buffer) string {
2018-08-26 06:06:44 +03:00
if b.Settings["basename"].(bool) {
return path.Base(b.GetName())
}
return b.GetName()
},
2018-08-27 22:53:10 +03:00
"line": func(b *buffer.Buffer) string {
2018-08-28 00:55:28 +03:00
return strconv.Itoa(b.GetActiveCursor().Y + 1)
2018-08-26 06:06:44 +03:00
},
2018-08-27 22:53:10 +03:00
"col": func(b *buffer.Buffer) string {
2018-08-28 00:55:28 +03:00
return strconv.Itoa(b.GetActiveCursor().X + 1)
2018-08-26 06:06:44 +03:00
},
2018-08-27 22:53:10 +03:00
"modified": func(b *buffer.Buffer) string {
2018-08-26 06:06:44 +03:00
if b.Modified() {
return "+ "
}
return ""
},
2018-01-03 06:25:55 +03:00
}
2018-08-26 06:06:44 +03:00
s.win = win
return s
}
2016-03-25 19:14:22 +03:00
2018-08-26 06:06:44 +03:00
// FindOpt finds a given option in the current buffer's settings
func (s *StatusLine) FindOpt(opt string) interface{} {
if val, ok := s.win.Buf.Settings[opt]; ok {
return val
2016-03-18 01:20:07 +03:00
}
2018-08-26 06:06:44 +03:00
return "null"
}
2016-03-25 19:14:22 +03:00
2018-08-26 06:06:44 +03:00
var formatParser = regexp.MustCompile(`\$\(.+?\)`)
2016-03-25 19:14:22 +03:00
2018-08-26 06:06:44 +03:00
// Display draws the statusline to the screen
func (s *StatusLine) Display() {
// We'll draw the line at the lowest line in the window
2018-08-27 22:53:10 +03:00
y := s.win.Height + s.win.Y - 1
2018-08-26 06:06:44 +03:00
formatter := func(match []byte) []byte {
name := match[2 : len(match)-1]
if bytes.HasPrefix(name, []byte("opt")) {
option := name[4:]
return []byte(fmt.Sprint(s.FindOpt(string(option))))
} else if bytes.HasPrefix(name, []byte("bind")) {
2019-01-11 23:33:16 +03:00
binding := string(name[5:])
for k, v := range config.Bindings {
if v == binding {
return []byte(k)
}
}
2018-08-27 22:53:10 +03:00
return []byte("null")
2018-08-26 06:06:44 +03:00
} else {
return []byte(s.Info[string(name)](s.win.Buf))
}
2016-04-19 20:58:02 +03:00
}
2016-03-28 00:53:00 +03:00
2018-08-26 06:06:44 +03:00
leftText := []byte(s.FormatLeft)
leftText = formatParser.ReplaceAllFunc([]byte(s.FormatLeft), formatter)
rightText := []byte(s.FormatRight)
rightText = formatParser.ReplaceAllFunc([]byte(s.FormatRight), formatter)
2018-08-27 22:53:10 +03:00
statusLineStyle := config.DefStyle.Reverse(true)
if style, ok := config.Colorscheme["statusline"]; ok {
statusLineStyle = style
}
2016-03-18 01:20:07 +03:00
2018-08-26 06:06:44 +03:00
leftLen := utf8.RuneCount(leftText)
rightLen := utf8.RuneCount(rightText)
2018-08-26 06:06:44 +03:00
winX := s.win.X
for x := 0; x < s.win.Width; x++ {
if x < leftLen {
r, size := utf8.DecodeRune(leftText)
leftText = leftText[size:]
2018-08-27 22:53:10 +03:00
screen.Screen.SetContent(winX+x, y, r, nil, statusLineStyle)
2018-08-26 06:06:44 +03:00
} else if x >= s.win.Width-rightLen && x < rightLen+s.win.Width-rightLen {
r, size := utf8.DecodeRune(rightText)
rightText = rightText[size:]
2018-08-27 22:53:10 +03:00
screen.Screen.SetContent(winX+x, y, r, nil, statusLineStyle)
2016-03-18 01:20:07 +03:00
} else {
2018-08-27 22:53:10 +03:00
screen.Screen.SetContent(winX+x, y, ' ', nil, statusLineStyle)
2016-03-18 01:20:07 +03:00
}
}
}