]> git.lizzy.rs Git - micro.git/blob - cmd/micro/display/infowindow.go
Begin tab implementation
[micro.git] / cmd / micro / display / infowindow.go
1 package display
2
3 import (
4         "unicode/utf8"
5
6         runewidth "github.com/mattn/go-runewidth"
7         "github.com/zyedidia/micro/cmd/micro/buffer"
8         "github.com/zyedidia/micro/cmd/micro/config"
9         "github.com/zyedidia/micro/cmd/micro/info"
10         "github.com/zyedidia/micro/cmd/micro/screen"
11         "github.com/zyedidia/micro/cmd/micro/util"
12         "github.com/zyedidia/tcell"
13 )
14
15 type InfoWindow struct {
16         *info.InfoBuf
17         *View
18
19         defStyle tcell.Style
20         errStyle tcell.Style
21
22         width int
23         y     int
24 }
25
26 func NewInfoWindow(b *info.InfoBuf) *InfoWindow {
27         iw := new(InfoWindow)
28         iw.InfoBuf = b
29         iw.View = new(View)
30
31         iw.defStyle = config.DefStyle
32
33         if _, ok := config.Colorscheme["message"]; ok {
34                 iw.defStyle = config.Colorscheme["message"]
35         }
36
37         iw.errStyle = config.DefStyle.
38                 Foreground(tcell.ColorBlack).
39                 Background(tcell.ColorMaroon)
40
41         if _, ok := config.Colorscheme["error-message"]; ok {
42                 iw.errStyle = config.Colorscheme["error-message"]
43         }
44
45         iw.width, iw.y = screen.Screen.Size()
46         iw.y--
47
48         return iw
49 }
50
51 func (i *InfoWindow) Resize(w, h int) {
52         i.width = w
53         i.y = h
54 }
55
56 // func (i *InfoWindow) YesNoPrompt() (bool, bool) {
57 //      for {
58 //              i.Clear()
59 //              i.Display()
60 //              screen.Screen.ShowCursor(utf8.RuneCountInString(i.Msg), i.y)
61 //              screen.Show()
62 //              event := <-events
63 //
64 //              switch e := event.(type) {
65 //              case *tcell.EventKey:
66 //                      switch e.Key() {
67 //                      case tcell.KeyRune:
68 //                              if e.Rune() == 'y' || e.Rune() == 'Y' {
69 //                                      i.HasPrompt = false
70 //                                      return true, false
71 //                              } else if e.Rune() == 'n' || e.Rune() == 'N' {
72 //                                      i.HasPrompt = false
73 //                                      return false, false
74 //                              }
75 //                      case tcell.KeyCtrlC, tcell.KeyCtrlQ, tcell.KeyEscape:
76 //                              i.Clear()
77 //                              i.Reset()
78 //                              i.HasPrompt = false
79 //                              return false, true
80 //                      }
81 //              }
82 //      }
83 // }
84
85 func (i *InfoWindow) Relocate() bool   { return false }
86 func (i *InfoWindow) GetView() *View   { return i.View }
87 func (i *InfoWindow) SetView(v *View)  {}
88 func (i *InfoWindow) SetActive(b bool) {}
89
90 func (i *InfoWindow) GetMouseLoc(vloc buffer.Loc) buffer.Loc {
91         c := i.Buffer.GetActiveCursor()
92         l := i.Buffer.LineBytes(0)
93         n := utf8.RuneCountInString(i.Msg)
94         return buffer.Loc{c.GetCharPosInLine(l, vloc.X-n), 0}
95 }
96
97 func (i *InfoWindow) Clear() {
98         for x := 0; x < i.width; x++ {
99                 screen.Screen.SetContent(x, i.y, ' ', nil, config.DefStyle)
100         }
101 }
102
103 func (i *InfoWindow) displayBuffer() {
104         b := i.Buffer
105         line := b.LineBytes(0)
106         activeC := b.GetActiveCursor()
107
108         blocX := 0
109         vlocX := utf8.RuneCountInString(i.Msg)
110
111         tabsize := 4
112         line, nColsBeforeStart, bslice := util.SliceVisualEnd(line, blocX, tabsize)
113         blocX = bslice
114
115         draw := func(r rune, style tcell.Style) {
116                 if nColsBeforeStart <= 0 {
117                         bloc := buffer.Loc{X: blocX, Y: 0}
118                         if activeC.HasSelection() &&
119                                 (bloc.GreaterEqual(activeC.CurSelection[0]) && bloc.LessThan(activeC.CurSelection[1]) ||
120                                         bloc.LessThan(activeC.CurSelection[0]) && bloc.GreaterEqual(activeC.CurSelection[1])) {
121                                 // The current character is selected
122                                 style = config.DefStyle.Reverse(true)
123
124                                 if s, ok := config.Colorscheme["selection"]; ok {
125                                         style = s
126                                 }
127
128                         }
129
130                         screen.Screen.SetContent(vlocX, i.y, r, nil, style)
131                         vlocX++
132                 }
133                 nColsBeforeStart--
134         }
135
136         totalwidth := blocX - nColsBeforeStart
137         for len(line) > 0 {
138                 if activeC.X == blocX {
139                         screen.Screen.ShowCursor(vlocX, i.y)
140                 }
141
142                 r, size := utf8.DecodeRune(line)
143
144                 draw(r, i.defStyle)
145
146                 width := 0
147
148                 char := ' '
149                 switch r {
150                 case '\t':
151                         ts := tabsize - (totalwidth % tabsize)
152                         width = ts
153                 default:
154                         width = runewidth.RuneWidth(r)
155                         char = '@'
156                 }
157
158                 blocX++
159                 line = line[size:]
160
161                 // Draw any extra characters either spaces for tabs or @ for incomplete wide runes
162                 if width > 1 {
163                         for j := 1; j < width; j++ {
164                                 draw(char, i.defStyle)
165                         }
166                 }
167                 totalwidth += width
168                 if vlocX >= i.width {
169                         break
170                 }
171         }
172         if activeC.X == blocX {
173                 screen.Screen.ShowCursor(vlocX, i.y)
174         }
175 }
176
177 func (i *InfoWindow) Display() {
178         x := 0
179         if i.HasPrompt || config.GlobalSettings["infobar"].(bool) {
180                 if !i.HasPrompt && !i.HasMessage && !i.HasError {
181                         return
182                 }
183                 style := i.defStyle
184
185                 if i.HasError {
186                         style = i.errStyle
187                 }
188
189                 display := i.Msg
190                 for _, c := range display {
191                         screen.Screen.SetContent(x, i.y, c, nil, style)
192                         x += runewidth.RuneWidth(c)
193                 }
194
195                 if i.HasPrompt {
196                         i.displayBuffer()
197                 }
198         }
199 }