summaryrefslogtreecommitdiff
path: root/xmake/core/ui/curses.lua
blob: 62b63c04011a50d46d8c6a09a6fd80308a9b30e5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
--!A cross-platform build utility based on Lua
--
-- Licensed under the Apache License, Version 2.0 (the "License");
-- you may not use this file except in compliance with the License.
-- You may obtain a copy of the License at
--
--     http://www.apache.org/licenses/LICENSE-2.0
--
-- Unless required by applicable law or agreed to in writing, software
-- distributed under the License is distributed on an "AS IS" BASIS,
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-- See the License for the specific language governing permissions and
-- limitations under the License.
--
-- Copyright (C) 2015-present, Xmake Open Source Community.
--
-- @author      ruki
-- @file        curses.lua
--

-- define module: curses
local curses = curses or {}

-- load modules
local os  = require("base/os")
local log = require("ui/log")

-- get color from the given name
function curses.color(name)
        if name == 'black' then     return curses.COLOR_BLACK
    elseif name == 'red' then       return curses.COLOR_RED
    elseif name == 'green' then     return curses.COLOR_GREEN
    elseif name == 'yellow' then    return curses.COLOR_YELLOW
    elseif name == 'blue' then      return curses.COLOR_BLUE
    elseif name == 'magenta' then   return curses.COLOR_MAGENTA
    elseif name == 'cyan' then      return curses.COLOR_CYAN
    elseif name == 'white' then     return curses.COLOR_WHITE
    else                            return curses.COLOR_BLACK
    end
end

-- is color?
local colors = {black = true, red = true, green = true, yellow = true, blue = true, magenta = true, cyan = true, white = true}
function curses.iscolor(name)
    return colors[name] or colors[name:sub(3) or ""]
end

-- get attr from the given name
function curses.attr(name)
        if name == 'normal' then    return curses.A_NORMAL
    elseif name == 'standout' then  return curses.A_STANDOUT
    elseif name == 'underline' then return curses.A_UNDERLINE
    elseif name == 'reverse' then   return curses.A_REVERSE
    elseif name == 'blink' then     return curses.A_BLINK
    elseif name == 'dim' then       return curses.A_DIM
    elseif name == 'bold' then      return curses.A_BOLD
    elseif name == 'protect' then   return curses.A_PROTECT
    elseif name == 'invis' then     return curses.A_INVIS
    elseif name == 'alt' then       return curses.A_ALTCHARSET
    else                            return curses.A_NORMAL
    end
end

-- get acs character from the given name
function curses.acs(name)
        if name == 'block' then     return curses.ACS_BLOCK
    elseif name == 'board' then     return curses.ACS_BOARD
    elseif name == 'btee' then      return curses.ACS_BTEE
    elseif name == 'bullet' then    return curses.ACS_BULLET
    elseif name == 'ckboard' then   return curses.ACS_CKBOARD
    elseif name == 'darrow' then    return curses.ACS_DARROW
    elseif name == 'degree' then    return curses.ACS_DEGREE
    elseif name == 'diamond' then   return curses.ACS_DIAMOND
    elseif name == 'gequal' then    return curses.ACS_GEQUAL
    elseif name == 'hline' then     return curses.ACS_HLINE
    elseif name == 'lantern' then   return curses.ACS_LANTERN
    elseif name == 'larrow' then    return curses.ACS_LARROW
    elseif name == 'lequal' then    return curses.ACS_LEQUAL
    elseif name == 'llcorner' then  return curses.ACS_LLCORNER
    elseif name == 'lrcorner' then  return curses.ACS_LRCORNER
    elseif name == 'ltee' then      return curses.ACS_LTEE
    elseif name == 'nequal' then    return curses.ACS_NEQUAL
    elseif name == 'pi' then        return curses.ACS_PI
    elseif name == 'plminus' then   return curses.ACS_PLMINUS
    elseif name == 'plus' then      return curses.ACS_PLUS
    elseif name == 'rarrow' then    return curses.ACS_RARROW
    elseif name == 'rtee' then      return curses.ACS_RTEE
    elseif name == 's1' then        return curses.ACS_S1
    elseif name == 's3' then        return curses.ACS_S3
    elseif name == 's7' then        return curses.ACS_S7
    elseif name == 's9' then        return curses.ACS_S9
    elseif name == 'sterling' then  return curses.ACS_STERLING
    elseif name == 'ttee' then      return curses.ACS_TTEE
    elseif name == 'uarrow' then    return curses.ACS_UARROW
    elseif name == 'ulcorner' then  return curses.ACS_ULCORNER
    elseif name == 'urcorner' then  return curses.ACS_URCORNER
    elseif name == 'vline' then     return curses.ACS_VLINE
    elseif type(name) == 'string' and #name == 1 then
        return name
    else
        return ' '
    end
end

-- calculate attr from the attributes list
--
-- local attr = curses.calc_attr("bold")
-- local attr = curses.calc_attr("yellow")
-- local attr = curses.calc_attr{ "yellow", "ongreen" }
-- local attr = curses.calc_attr{ "yellow", "ongreen", "bold" }
-- local attr = curses.calc_attr{ curses.color_pair("yellow", "green"), "bold" }
--
function curses.calc_attr(attrs)

    -- curses.calc_attr(curses.A_BOLD)
    -- curses.calc_attr(curses.color_pair("yellow", "green"))
    local atype = type(attrs)
    if atype == "number" then
        return attrs
    -- curses.calc_attr("bold")
    -- curses.calc_attr("yellow")
    elseif atype == "string" then
        if curses.iscolor(attrs) then
            local color = attrs
            if color:startswith("on") then
                color = color:sub(3)
            end
            return curses.color_pair(color, color)
        end
        return curses.attr(attrs)
    -- curses.calc_attr{ "yellow", "ongreen", "bold" }
    -- curses.calc_attr{ curses.color_pair("yellow", "green"), "bold" }
    elseif atype == "table" then
        local v = 0
        local set = {}
        local fg = nil
        local bg = nil
        for _, a in ipairs(attrs) do
            if not set[a] and a then
                set[a] = true
                if type(a) == "number" then
                    v = v + a
                elseif curses.iscolor(a) then
                    if a:startswith("on") then
                        bg = a:sub(3)
                    else
                        fg = a
                    end
                else
                    v = v + curses.attr(a)
                end
            end
        end
        if fg or bg then
            v = v + curses.color_pair(fg or bg, bg or fg)
        end
        return v
    else
        return 0
    end
end

-- get attr from the color pair
curses._color_pair = curses._color_pair or curses.color_pair
function curses.color_pair(fg, bg)

    -- get foreground and backround color
    fg = curses.color(fg)
    bg = curses.color(bg)

    -- attempt to get color from the cache first
    local key = fg .. ':' .. bg
    local colors = curses._COLORS or {}
    if colors[key] then
        return colors[key]
    end

    -- no colors?
    if not curses.has_colors() then
        return 0
    end

    -- update the colors count
    curses._NCOLORS = (curses._NCOLORS or 0) + 1

    -- init the color pair
    if not curses.init_pair(curses._NCOLORS, fg, bg) then
        os.raise("failed to initialize color pair (%d, %s, %s)", curses._NCOLORS, fg, bg)
    end

    -- get the color attr
    local attr = curses._color_pair(curses._NCOLORS)

    -- save to cache
    colors[key] = attr
    curses._COLORS = colors

    -- ok
    return attr
end

-- set cursor state
curses._cursor_set = curses._cursor_set or curses.cursor_set
function curses.cursor_set(state)
    if curses._CURSOR_STATE ~= state then
        curses._CURSOR_STATE = state
        curses._cursor_set(state)
    end
end

-- has mouse?
function curses.has_mouse()
    return curses.KEY_MOUSE and true or false
end

-- return module: curses
return curses