Skip to content
GitLab
Explore
Sign in
Register
Primary navigation
Search or go to…
Project
F
fzf
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Wiki
Requirements
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Locked files
Build
Pipelines
Jobs
Pipeline schedules
Test cases
Artifacts
Deploy
Releases
Package Registry
Container Registry
Model registry
Operate
Environments
Terraform modules
Monitor
Incidents
Service Desk
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Code review analytics
Issue analytics
Insights
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to JiHu GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
KMSCAKKSCFKA AKFACAMADCAS
fzf
Commits
e3e7b336
Unverified
Commit
e3e7b336
authored
7 years ago
by
Junegunn Choi
Browse files
Options
Downloads
Patches
Plain Diff
Delete ncurses implementation
parent
655dfb83
No related branches found
Branches containing commit
No related tags found
Tags containing commit
No related merge requests found
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
src/tui/ncurses.go
+0
-505
0 additions, 505 deletions
src/tui/ncurses.go
with
0 additions
and
505 deletions
src/tui/ncurses.go
deleted
100644 → 0
+
0
−
505
View file @
655dfb83
// +build ncurses
// +build !windows
// +build !tcell
package
tui
/*
#include <ncurses.h>
#include <locale.h>
#cgo !static LDFLAGS: -lncurses
#cgo static LDFLAGS: -l:libncursesw.a -l:libtinfo.a -l:libgpm.a -ldl
#cgo android static LDFLAGS: -l:libncurses.a -fPIE -march=armv7-a -mfpu=neon -mhard-float -Wl,--no-warn-mismatch
FILE* c_tty() {
return fopen("/dev/tty", "r");
}
SCREEN* c_newterm(FILE* tty) {
return newterm(NULL, stderr, tty);
}
int c_getcurx(WINDOW* win) {
return getcurx(win);
}
*/
import
"C"
import
(
"os"
"strconv"
"strings"
"time"
"unicode/utf8"
)
func
HasFullscreenRenderer
()
bool
{
return
true
}
type
Attr
C
.
uint
type
CursesWindow
struct
{
impl
*
C
.
WINDOW
top
int
left
int
width
int
height
int
}
func
(
w
*
CursesWindow
)
Top
()
int
{
return
w
.
top
}
func
(
w
*
CursesWindow
)
Left
()
int
{
return
w
.
left
}
func
(
w
*
CursesWindow
)
Width
()
int
{
return
w
.
width
}
func
(
w
*
CursesWindow
)
Height
()
int
{
return
w
.
height
}
func
(
w
*
CursesWindow
)
Refresh
()
{
C
.
wnoutrefresh
(
w
.
impl
)
}
func
(
w
*
CursesWindow
)
FinishFill
()
{
// NO-OP
}
const
(
Bold
Attr
=
C
.
A_BOLD
Dim
=
C
.
A_DIM
Blink
=
C
.
A_BLINK
Reverse
=
C
.
A_REVERSE
Underline
=
C
.
A_UNDERLINE
)
var
Italic
Attr
=
C
.
A_VERTICAL
<<
1
// FIXME
const
(
AttrRegular
Attr
=
0
)
var
(
_screen
*
C
.
SCREEN
_colorMap
map
[
int
]
int16
_colorFn
func
(
ColorPair
,
Attr
)
(
C
.
short
,
C
.
int
)
)
func
init
()
{
_colorMap
=
make
(
map
[
int
]
int16
)
if
strings
.
HasPrefix
(
C
.
GoString
(
C
.
curses_version
()),
"ncurses 5"
)
{
Italic
=
C
.
A_NORMAL
}
}
func
(
a
Attr
)
Merge
(
b
Attr
)
Attr
{
return
a
|
b
}
func
(
r
*
FullscreenRenderer
)
defaultTheme
()
*
ColorTheme
{
if
C
.
tigetnum
(
C
.
CString
(
"colors"
))
>=
256
{
return
Dark256
}
return
Default16
}
func
(
r
*
FullscreenRenderer
)
Init
()
{
C
.
setlocale
(
C
.
LC_ALL
,
C
.
CString
(
""
))
tty
:=
C
.
c_tty
()
if
tty
==
nil
{
errorExit
(
"Failed to open /dev/tty"
)
}
_screen
=
C
.
c_newterm
(
tty
)
if
_screen
==
nil
{
errorExit
(
"Invalid $TERM: "
+
os
.
Getenv
(
"TERM"
))
}
C
.
set_term
(
_screen
)
if
r
.
mouse
{
C
.
mousemask
(
C
.
ALL_MOUSE_EVENTS
,
nil
)
C
.
mouseinterval
(
0
)
}
C
.
noecho
()
C
.
raw
()
// stty dsusp undef
C
.
nonl
()
C
.
keypad
(
C
.
stdscr
,
true
)
delay
:=
50
delayEnv
:=
os
.
Getenv
(
"ESCDELAY"
)
if
len
(
delayEnv
)
>
0
{
num
,
err
:=
strconv
.
Atoi
(
delayEnv
)
if
err
==
nil
&&
num
>=
0
{
delay
=
num
}
}
C
.
set_escdelay
(
C
.
int
(
delay
))
if
r
.
theme
!=
nil
{
C
.
start_color
()
initTheme
(
r
.
theme
,
r
.
defaultTheme
(),
r
.
forceBlack
)
initPairs
(
r
.
theme
)
C
.
bkgd
(
C
.
chtype
(
C
.
COLOR_PAIR
(
C
.
int
(
ColNormal
.
index
()))))
_colorFn
=
attrColored
}
else
{
initTheme
(
r
.
theme
,
nil
,
r
.
forceBlack
)
_colorFn
=
attrMono
}
C
.
nodelay
(
C
.
stdscr
,
true
)
ch
:=
C
.
getch
()
if
ch
!=
C
.
ERR
{
C
.
ungetch
(
ch
)
}
C
.
nodelay
(
C
.
stdscr
,
false
)
}
func
initPairs
(
theme
*
ColorTheme
)
{
C
.
assume_default_colors
(
C
.
int
(
theme
.
Fg
),
C
.
int
(
theme
.
Bg
))
for
_
,
pair
:=
range
[]
ColorPair
{
ColNormal
,
ColPrompt
,
ColMatch
,
ColCurrent
,
ColCurrentMatch
,
ColSpinner
,
ColInfo
,
ColCursor
,
ColSelected
,
ColHeader
,
ColBorder
}
{
C
.
init_pair
(
C
.
short
(
pair
.
index
()),
C
.
short
(
pair
.
Fg
()),
C
.
short
(
pair
.
Bg
()))
}
}
func
(
r
*
FullscreenRenderer
)
Pause
(
bool
)
{
C
.
endwin
()
}
func
(
r
*
FullscreenRenderer
)
Resume
(
bool
)
{
}
func
(
r
*
FullscreenRenderer
)
Close
()
{
C
.
endwin
()
C
.
delscreen
(
_screen
)
}
func
(
r
*
FullscreenRenderer
)
NewWindow
(
top
int
,
left
int
,
width
int
,
height
int
,
borderStyle
BorderStyle
)
Window
{
win
:=
C
.
newwin
(
C
.
int
(
height
),
C
.
int
(
width
),
C
.
int
(
top
),
C
.
int
(
left
))
if
r
.
theme
!=
nil
{
C
.
wbkgd
(
win
,
C
.
chtype
(
C
.
COLOR_PAIR
(
C
.
int
(
ColNormal
.
index
()))))
}
// FIXME Does not implement BorderHorizontal
if
borderStyle
!=
BorderNone
{
pair
,
attr
:=
_colorFn
(
ColBorder
,
0
)
C
.
wcolor_set
(
win
,
pair
,
nil
)
C
.
wattron
(
win
,
attr
)
C
.
box
(
win
,
0
,
0
)
C
.
wattroff
(
win
,
attr
)
C
.
wcolor_set
(
win
,
0
,
nil
)
}
return
&
CursesWindow
{
impl
:
win
,
top
:
top
,
left
:
left
,
width
:
width
,
height
:
height
,
}
}
func
attrColored
(
color
ColorPair
,
a
Attr
)
(
C
.
short
,
C
.
int
)
{
return
C
.
short
(
color
.
index
()),
C
.
int
(
a
)
}
func
attrMono
(
color
ColorPair
,
a
Attr
)
(
C
.
short
,
C
.
int
)
{
return
0
,
C
.
int
(
attrFor
(
color
,
a
))
}
func
(
r
*
FullscreenRenderer
)
MaxX
()
int
{
return
int
(
C
.
COLS
)
}
func
(
r
*
FullscreenRenderer
)
MaxY
()
int
{
return
int
(
C
.
LINES
)
}
func
(
w
*
CursesWindow
)
Close
()
{
C
.
delwin
(
w
.
impl
)
}
func
(
w
*
CursesWindow
)
Enclose
(
y
int
,
x
int
)
bool
{
return
bool
(
C
.
wenclose
(
w
.
impl
,
C
.
int
(
y
),
C
.
int
(
x
)))
}
func
(
w
*
CursesWindow
)
Move
(
y
int
,
x
int
)
{
C
.
wmove
(
w
.
impl
,
C
.
int
(
y
),
C
.
int
(
x
))
}
func
(
w
*
CursesWindow
)
MoveAndClear
(
y
int
,
x
int
)
{
w
.
Move
(
y
,
x
)
C
.
wclrtoeol
(
w
.
impl
)
}
func
(
w
*
CursesWindow
)
Print
(
text
string
)
{
C
.
waddstr
(
w
.
impl
,
C
.
CString
(
strings
.
Map
(
func
(
r
rune
)
rune
{
if
r
<
32
{
return
-
1
}
return
r
},
text
)))
}
func
(
w
*
CursesWindow
)
CPrint
(
color
ColorPair
,
attr
Attr
,
text
string
)
{
p
,
a
:=
_colorFn
(
color
,
attr
)
C
.
wcolor_set
(
w
.
impl
,
p
,
nil
)
C
.
wattron
(
w
.
impl
,
a
)
w
.
Print
(
text
)
C
.
wattroff
(
w
.
impl
,
a
)
C
.
wcolor_set
(
w
.
impl
,
0
,
nil
)
}
func
(
r
*
FullscreenRenderer
)
Clear
()
{
C
.
clear
()
C
.
endwin
()
}
func
(
r
*
FullscreenRenderer
)
Refresh
()
{
C
.
refresh
()
}
func
(
w
*
CursesWindow
)
Erase
()
{
C
.
werase
(
w
.
impl
)
}
func
(
w
*
CursesWindow
)
X
()
int
{
return
int
(
C
.
c_getcurx
(
w
.
impl
))
}
func
(
r
*
FullscreenRenderer
)
DoesAutoWrap
()
bool
{
return
true
}
func
(
r
*
FullscreenRenderer
)
IsOptimized
()
bool
{
return
true
}
func
(
w
*
CursesWindow
)
Fill
(
str
string
)
FillReturn
{
if
C
.
waddstr
(
w
.
impl
,
C
.
CString
(
str
))
==
C
.
OK
{
return
FillContinue
}
return
FillSuspend
}
func
(
w
*
CursesWindow
)
CFill
(
fg
Color
,
bg
Color
,
attr
Attr
,
str
string
)
FillReturn
{
index
:=
ColorPair
{
fg
,
bg
,
-
1
}
.
index
()
C
.
wcolor_set
(
w
.
impl
,
C
.
short
(
index
),
nil
)
C
.
wattron
(
w
.
impl
,
C
.
int
(
attr
))
ret
:=
w
.
Fill
(
str
)
C
.
wattroff
(
w
.
impl
,
C
.
int
(
attr
))
C
.
wcolor_set
(
w
.
impl
,
0
,
nil
)
return
ret
}
func
(
r
*
FullscreenRenderer
)
RefreshWindows
(
windows
[]
Window
)
{
for
_
,
w
:=
range
windows
{
w
.
Refresh
()
}
C
.
doupdate
()
}
func
(
p
ColorPair
)
index
()
int16
{
if
p
.
id
>=
0
{
return
p
.
id
}
// ncurses does not support 24-bit colors
if
p
.
is24
()
{
return
ColDefault
.
index
()
}
key
:=
p
.
key
()
if
found
,
prs
:=
_colorMap
[
key
];
prs
{
return
found
}
id
:=
int16
(
len
(
_colorMap
))
+
ColUser
.
id
C
.
init_pair
(
C
.
short
(
id
),
C
.
short
(
p
.
Fg
()),
C
.
short
(
p
.
Bg
()))
_colorMap
[
key
]
=
id
return
id
}
func
consume
(
expects
...
rune
)
bool
{
for
_
,
r
:=
range
expects
{
if
int
(
C
.
getch
())
!=
int
(
r
)
{
return
false
}
}
return
true
}
func
escSequence
()
Event
{
C
.
nodelay
(
C
.
stdscr
,
true
)
defer
func
()
{
C
.
nodelay
(
C
.
stdscr
,
false
)
}()
c
:=
C
.
getch
()
switch
c
{
case
C
.
ERR
:
return
Event
{
ESC
,
0
,
nil
}
case
CtrlM
:
return
Event
{
CtrlAltM
,
0
,
nil
}
case
'/'
:
return
Event
{
AltSlash
,
0
,
nil
}
case
' '
:
return
Event
{
AltSpace
,
0
,
nil
}
case
127
,
C
.
KEY_BACKSPACE
:
return
Event
{
AltBS
,
0
,
nil
}
case
'['
:
// Bracketed paste mode (printf "\e[?2004h")
// \e[200~ TEXT \e[201~
if
consume
(
'2'
,
'0'
,
'0'
,
'~'
)
{
return
Event
{
Invalid
,
0
,
nil
}
}
}
if
c
>=
'a'
&&
c
<=
'z'
{
return
Event
{
AltA
+
int
(
c
)
-
'a'
,
0
,
nil
}
}
if
c
>=
'0'
&&
c
<=
'9'
{
return
Event
{
Alt0
+
int
(
c
)
-
'0'
,
0
,
nil
}
}
// Don't care. Ignore the rest.
for
;
c
!=
C
.
ERR
;
c
=
C
.
getch
()
{
}
return
Event
{
Invalid
,
0
,
nil
}
}
func
(
r
*
FullscreenRenderer
)
GetChar
()
Event
{
c
:=
C
.
getch
()
switch
c
{
case
C
.
ERR
:
// Unexpected error from blocking read
r
.
Close
()
errorExit
(
"Failed to read /dev/tty"
)
case
C
.
KEY_UP
:
return
Event
{
Up
,
0
,
nil
}
case
C
.
KEY_DOWN
:
return
Event
{
Down
,
0
,
nil
}
case
C
.
KEY_LEFT
:
return
Event
{
Left
,
0
,
nil
}
case
C
.
KEY_RIGHT
:
return
Event
{
Right
,
0
,
nil
}
case
C
.
KEY_HOME
:
return
Event
{
Home
,
0
,
nil
}
case
C
.
KEY_END
:
return
Event
{
End
,
0
,
nil
}
case
C
.
KEY_BACKSPACE
:
return
Event
{
BSpace
,
0
,
nil
}
case
C
.
KEY_F0
+
1
:
return
Event
{
F1
,
0
,
nil
}
case
C
.
KEY_F0
+
2
:
return
Event
{
F2
,
0
,
nil
}
case
C
.
KEY_F0
+
3
:
return
Event
{
F3
,
0
,
nil
}
case
C
.
KEY_F0
+
4
:
return
Event
{
F4
,
0
,
nil
}
case
C
.
KEY_F0
+
5
:
return
Event
{
F5
,
0
,
nil
}
case
C
.
KEY_F0
+
6
:
return
Event
{
F6
,
0
,
nil
}
case
C
.
KEY_F0
+
7
:
return
Event
{
F7
,
0
,
nil
}
case
C
.
KEY_F0
+
8
:
return
Event
{
F8
,
0
,
nil
}
case
C
.
KEY_F0
+
9
:
return
Event
{
F9
,
0
,
nil
}
case
C
.
KEY_F0
+
10
:
return
Event
{
F10
,
0
,
nil
}
case
C
.
KEY_F0
+
11
:
return
Event
{
F11
,
0
,
nil
}
case
C
.
KEY_F0
+
12
:
return
Event
{
F12
,
0
,
nil
}
case
C
.
KEY_DC
:
return
Event
{
Del
,
0
,
nil
}
case
C
.
KEY_PPAGE
:
return
Event
{
PgUp
,
0
,
nil
}
case
C
.
KEY_NPAGE
:
return
Event
{
PgDn
,
0
,
nil
}
case
C
.
KEY_BTAB
:
return
Event
{
BTab
,
0
,
nil
}
case
C
.
KEY_ENTER
:
return
Event
{
CtrlM
,
0
,
nil
}
case
C
.
KEY_SLEFT
:
return
Event
{
SLeft
,
0
,
nil
}
case
C
.
KEY_SRIGHT
:
return
Event
{
SRight
,
0
,
nil
}
case
C
.
KEY_MOUSE
:
var
me
C
.
MEVENT
if
C
.
getmouse
(
&
me
)
!=
C
.
ERR
{
mod
:=
((
me
.
bstate
&
C
.
BUTTON_SHIFT
)
|
(
me
.
bstate
&
C
.
BUTTON_CTRL
)
|
(
me
.
bstate
&
C
.
BUTTON_ALT
))
>
0
x
:=
int
(
me
.
x
)
y
:=
int
(
me
.
y
)
/* Cannot use BUTTON1_DOUBLE_CLICKED due to mouseinterval(0) */
if
(
me
.
bstate
&
C
.
BUTTON1_PRESSED
)
>
0
{
now
:=
time
.
Now
()
if
now
.
Sub
(
r
.
prevDownTime
)
<
doubleClickDuration
{
r
.
clickY
=
append
(
r
.
clickY
,
y
)
}
else
{
r
.
clickY
=
[]
int
{
y
}
r
.
prevDownTime
=
now
}
return
Event
{
Mouse
,
0
,
&
MouseEvent
{
y
,
x
,
0
,
true
,
false
,
mod
}}
}
else
if
(
me
.
bstate
&
C
.
BUTTON1_RELEASED
)
>
0
{
double
:=
false
if
len
(
r
.
clickY
)
>
1
&&
r
.
clickY
[
0
]
==
r
.
clickY
[
1
]
&&
time
.
Now
()
.
Sub
(
r
.
prevDownTime
)
<
doubleClickDuration
{
double
=
true
}
return
Event
{
Mouse
,
0
,
&
MouseEvent
{
y
,
x
,
0
,
false
,
double
,
mod
}}
}
else
if
(
me
.
bstate
&
0x8000000
)
>
0
||
(
me
.
bstate
&
0x80
)
>
0
{
return
Event
{
Mouse
,
0
,
&
MouseEvent
{
y
,
x
,
-
1
,
false
,
false
,
mod
}}
}
else
if
(
me
.
bstate
&
C
.
BUTTON4_PRESSED
)
>
0
{
return
Event
{
Mouse
,
0
,
&
MouseEvent
{
y
,
x
,
1
,
false
,
false
,
mod
}}
}
}
return
Event
{
Invalid
,
0
,
nil
}
case
C
.
KEY_RESIZE
:
return
Event
{
Resize
,
0
,
nil
}
case
ESC
:
return
escSequence
()
case
127
:
return
Event
{
BSpace
,
0
,
nil
}
case
0
:
return
Event
{
CtrlSpace
,
0
,
nil
}
}
// CTRL-A ~ CTRL-Z
if
c
>=
CtrlA
&&
c
<=
CtrlZ
{
return
Event
{
int
(
c
),
0
,
nil
}
}
// Multi-byte character
buffer
:=
[]
byte
{
byte
(
c
)}
for
{
r
,
_
:=
utf8
.
DecodeRune
(
buffer
)
if
r
!=
utf8
.
RuneError
{
return
Event
{
Rune
,
r
,
nil
}
}
c
:=
C
.
getch
()
if
c
==
C
.
ERR
{
break
}
if
c
>=
C
.
KEY_CODE_YES
{
C
.
ungetch
(
c
)
break
}
buffer
=
append
(
buffer
,
byte
(
c
))
}
return
Event
{
Invalid
,
0
,
nil
}
}
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment