]> git.lizzy.rs Git - micro.git/blob - internal/screen/screen.go
Merge pull request #1324 from konsumer/master
[micro.git] / internal / screen / screen.go
1 package screen
2
3 import (
4         "fmt"
5         "os"
6         "sync"
7
8         "github.com/zyedidia/micro/internal/config"
9         "github.com/zyedidia/micro/internal/util"
10         "github.com/zyedidia/tcell"
11 )
12
13 // Screen is the tcell screen we use to draw to the terminal
14 // Synchronization is used because we poll the screen on a separate
15 // thread and sometimes the screen is shut down by the main thread
16 // (for example on TermMessage) so we don't want to poll a nil/shutdown
17 // screen. TODO: maybe we should worry about polling and drawing at the
18 // same time too.
19 var Screen tcell.Screen
20
21 // The lock is necessary since the screen is polled on a separate thread
22 var lock sync.Mutex
23
24 // DrawChan is a channel that will cause the screen to redraw when
25 // written to even if no event user event has occurred
26 var DrawChan chan bool
27
28 // Lock locks the screen lock
29 func Lock() {
30         lock.Lock()
31 }
32
33 // Unlock unlocks the screen lock
34 func Unlock() {
35         lock.Unlock()
36 }
37
38 // Redraw schedules a redraw with the draw channel
39 func Redraw() {
40         DrawChan <- true
41 }
42
43 type screenCell struct {
44         x, y  int
45         r     rune
46         combc []rune
47         style tcell.Style
48 }
49
50 var lastCursor screenCell
51
52 // ShowFakeCursor displays a cursor at the given position by modifying the
53 // style of the given column instead of actually using the terminal cursor
54 // This can be useful in certain terminals such as the windows console where
55 // modifying the cursor location is slow and frequent modifications cause flashing
56 // This keeps track of the most recent fake cursor location and resets it when
57 // a new fake cursor location is specified
58 func ShowFakeCursor(x, y int) {
59         r, combc, style, _ := Screen.GetContent(x, y)
60         Screen.SetContent(lastCursor.x, lastCursor.y, lastCursor.r, lastCursor.combc, lastCursor.style)
61         Screen.SetContent(x, y, r, combc, config.DefStyle.Reverse(true))
62
63         lastCursor.x, lastCursor.y = x, y
64         lastCursor.r = r
65         lastCursor.combc = combc
66         lastCursor.style = style
67 }
68
69 // ShowFakeCursorMulti is the same as ShowFakeCursor except it does not
70 // reset previous locations of the cursor
71 // Fake cursors are also necessary to display multiple cursors
72 func ShowFakeCursorMulti(x, y int) {
73         r, _, _, _ := Screen.GetContent(x, y)
74         Screen.SetContent(x, y, r, nil, config.DefStyle.Reverse(true))
75 }
76
77 // ShowCursor puts the cursor at the given location using a fake cursor
78 // if enabled or using the terminal cursor otherwise
79 // By default only the windows console will use a fake cursor
80 func ShowCursor(x, y int) {
81         if util.FakeCursor {
82                 ShowFakeCursor(x, y)
83         } else {
84                 Screen.ShowCursor(x, y)
85         }
86 }
87
88 // SetContent sets a cell at a point on the screen and makes sure that it is
89 // synced with the last cursor location
90 func SetContent(x, y int, mainc rune, combc []rune, style tcell.Style) {
91         Screen.SetContent(x, y, mainc, combc, style)
92         if util.FakeCursor && lastCursor.x == x && lastCursor.y == y {
93                 lastCursor.r = mainc
94                 lastCursor.style = style
95                 lastCursor.combc = combc
96         }
97 }
98
99 // TempFini shuts the screen down temporarily
100 func TempFini() bool {
101         screenWasNil := Screen == nil
102
103         if !screenWasNil {
104                 Screen.Fini()
105                 Lock()
106                 Screen = nil
107         }
108         return screenWasNil
109 }
110
111 // TempStart restarts the screen after it was temporarily disabled
112 func TempStart(screenWasNil bool) {
113         if !screenWasNil {
114                 Init()
115                 Unlock()
116         }
117 }
118
119 // Init creates and initializes the tcell screen
120 func Init() {
121         DrawChan = make(chan bool, 8)
122
123         // Should we enable true color?
124         truecolor := os.Getenv("MICRO_TRUECOLOR") == "1"
125
126         if !truecolor {
127                 os.Setenv("TCELL_TRUECOLOR", "disable")
128         }
129
130         // Initilize tcell
131         var err error
132         Screen, err = tcell.NewScreen()
133         if err != nil {
134                 fmt.Println(err)
135                 fmt.Println("Fatal: Micro could not initialize a Screen.")
136                 os.Exit(1)
137         }
138         if err = Screen.Init(); err != nil {
139                 fmt.Println(err)
140                 os.Exit(1)
141         }
142
143         if config.GetGlobalOption("mouse").(bool) {
144                 Screen.EnableMouse()
145         }
146 }