Add --color=[dark|light|16|bw] option

- dark:  the current default for 256-color terminal
- light: color scheme for 256-color terminal with light background
- 16:    the default color scheme for 16-color terminal (`+2`)
- bw:    no colors (`+c`)
This commit is contained in:
Junegunn Choi 2015-04-18 02:52:30 +09:00
parent 2fe1e28220
commit f66d94c6b0
7 changed files with 124 additions and 47 deletions

View File

@ -9,6 +9,10 @@ CHANGELOG
- Performance optimization
- Less aggressive memoization to limit memory usage
### New features
- Added color scheme for light background: `--color=light`
0.9.9
-----

4
fzf
View File

@ -206,10 +206,10 @@ class FZF
@expect = true
when /^--expect=(.*)$/
@expect = true
when '--toggle-sort', '--tiebreak'
when '--toggle-sort', '--tiebreak', '--color'
argv.shift
when '--tac', '--no-tac', '--sync', '--no-sync', '--hscroll', '--no-hscroll',
/^--toggle-sort=(.*)$/, /^--tiebreak=(.*)$/
/^--color=(.*)$/, /^--toggle-sort=(.*)$/, /^--tiebreak=(.*)$/
# XXX
else
usage 1, "illegal option: #{o}"

View File

@ -91,11 +91,21 @@ Enable processing of ANSI color codes
.B "--no-mouse"
Disable mouse
.TP
.B "+c, --no-color"
Disable colors
.TP
.B "+2, --no-256"
Disable 256-color
.B "--color=COL"
Color scheme: [dark|light|16|bw]
.br
(default: dark on 256-color terminal, otherwise 16)
.br
.R ""
.br
.BR dark " Dark color scheme for 256-color terminal"
.br
.BR light " Light color scheme for 256-color terminal"
.br
.BR 16 " Default color scheme for 16-color terminal"
.br
.BR bw " No colors"
.br
.TP
.B "--black"
Use black background

View File

@ -68,7 +68,7 @@ func Run(options *Options) {
return data, nil
}
if opts.Ansi {
if opts.Color {
if opts.Theme != nil {
ansiProcessor = func(data *string) (*string, []ansiOffset) {
return extractColor(data)
}

View File

@ -95,6 +95,18 @@ const (
doubleClickDuration = 500 * time.Millisecond
)
type ColorTheme struct {
darkBg C.short
prompt C.short
match C.short
current C.short
currentMatch C.short
spinner C.short
info C.short
cursor C.short
selected C.short
}
type Event struct {
Type int
Char rune
@ -117,6 +129,9 @@ var (
_colorMap map[int]int
_prevDownTime time.Time
_clickY []int
Default16 *ColorTheme
Dark256 *ColorTheme
Light256 *ColorTheme
DarkBG C.short
)
@ -124,6 +139,36 @@ func init() {
_prevDownTime = time.Unix(0, 0)
_clickY = []int{}
_colorMap = make(map[int]int)
Default16 = &ColorTheme{
darkBg: C.COLOR_BLACK,
prompt: C.COLOR_BLUE,
match: C.COLOR_GREEN,
current: C.COLOR_YELLOW,
currentMatch: C.COLOR_GREEN,
spinner: C.COLOR_GREEN,
info: C.COLOR_WHITE,
cursor: C.COLOR_RED,
selected: C.COLOR_MAGENTA}
Dark256 = &ColorTheme{
darkBg: 236,
prompt: 110,
match: 108,
current: 254,
currentMatch: 151,
spinner: 148,
info: 144,
cursor: 161,
selected: 168}
Light256 = &ColorTheme{
darkBg: 251,
prompt: 25,
match: 66,
current: 237,
currentMatch: 23,
spinner: 65,
info: 101,
cursor: 161,
selected: 168}
}
func attrColored(pair int, bold bool) C.int {
@ -173,7 +218,7 @@ func getch(nonblock bool) int {
return int(b[0])
}
func Init(color bool, color256 bool, black bool, mouse bool) {
func Init(theme *ColorTheme, black bool, mouse bool) {
{
in, err := os.OpenFile("/dev/tty", syscall.O_RDONLY, 0)
if err != nil {
@ -203,42 +248,35 @@ func Init(color bool, color256 bool, black bool, mouse bool) {
os.Exit(1)
}()
if color {
if theme != nil {
C.start_color()
var bg C.short
if black {
bg = C.COLOR_BLACK
} else {
C.use_default_colors()
bg = -1
}
if color256 {
DarkBG = 236
C.init_pair(ColPrompt, 110, bg)
C.init_pair(ColMatch, 108, bg)
C.init_pair(ColCurrent, 254, DarkBG)
C.init_pair(ColCurrentMatch, 151, DarkBG)
C.init_pair(ColSpinner, 148, bg)
C.init_pair(ColInfo, 144, bg)
C.init_pair(ColCursor, 161, DarkBG)
C.init_pair(ColSelected, 168, DarkBG)
} else {
DarkBG = C.COLOR_BLACK
C.init_pair(ColPrompt, C.COLOR_BLUE, bg)
C.init_pair(ColMatch, C.COLOR_GREEN, bg)
C.init_pair(ColCurrent, C.COLOR_YELLOW, DarkBG)
C.init_pair(ColCurrentMatch, C.COLOR_GREEN, DarkBG)
C.init_pair(ColSpinner, C.COLOR_GREEN, bg)
C.init_pair(ColInfo, C.COLOR_WHITE, bg)
C.init_pair(ColCursor, C.COLOR_RED, DarkBG)
C.init_pair(ColSelected, C.COLOR_MAGENTA, DarkBG)
}
initPairs(theme, black)
_color = attrColored
} else {
_color = attrMono
}
}
func initPairs(theme *ColorTheme, black bool) {
var bg C.short
if black {
bg = C.COLOR_BLACK
} else {
C.use_default_colors()
bg = -1
}
DarkBG = theme.darkBg
C.init_pair(ColPrompt, theme.prompt, bg)
C.init_pair(ColMatch, theme.match, bg)
C.init_pair(ColCurrent, theme.current, DarkBG)
C.init_pair(ColCurrentMatch, theme.currentMatch, DarkBG)
C.init_pair(ColSpinner, theme.spinner, bg)
C.init_pair(ColInfo, theme.info, bg)
C.init_pair(ColCursor, theme.cursor, DarkBG)
C.init_pair(ColSelected, theme.selected, DarkBG)
}
func Close() {
C.endwin()
C.swapOutput()

View File

@ -35,8 +35,8 @@ const usage = `usage: fzf [options]
-m, --multi Enable multi-select with tab/shift-tab
--ansi Enable processing of ANSI color codes
--no-mouse Disable mouse
+c, --no-color Disable colors
+2, --no-256 Disable 256-color
--color=COL Color scheme [dark|light|16|bw]
(default: dark on 256-color terminal, otherwise 16)
--black Use black background
--reverse Reverse orientation
--no-hscroll Disable horizontal scroll
@ -101,8 +101,7 @@ type Options struct {
Multi bool
Ansi bool
Mouse bool
Color bool
Color256 bool
Theme *curses.ColorTheme
Black bool
Reverse bool
Hscroll bool
@ -119,6 +118,13 @@ type Options struct {
}
func defaultOptions() *Options {
var defaultTheme *curses.ColorTheme
if strings.Contains(os.Getenv("TERM"), "256") {
defaultTheme = curses.Dark256
} else {
defaultTheme = curses.Default16
}
return &Options{
Mode: ModeFuzzy,
Case: CaseSmart,
@ -131,8 +137,7 @@ func defaultOptions() *Options {
Multi: false,
Ansi: false,
Mouse: true,
Color: true,
Color256: strings.Contains(os.Getenv("TERM"), "256"),
Theme: defaultTheme,
Black: false,
Reverse: false,
Hscroll: true,
@ -266,6 +271,22 @@ func parseTiebreak(str string) tiebreak {
return byLength
}
func parseTheme(str string) *curses.ColorTheme {
switch strings.ToLower(str) {
case "dark":
return curses.Dark256
case "light":
return curses.Light256
case "16":
return curses.Default16
case "bw", "off", "no", "none":
return nil
default:
errorExit("invalid color scheme: " + str)
}
return nil
}
func checkToggleSort(str string) int {
keys := parseKeyChords(str, "key name required")
if len(keys) != 1 {
@ -295,6 +316,8 @@ func parseOptions(opts *Options, allArgs []string) {
opts.Expect = parseKeyChords(nextString(allArgs, &i, "key names required"), "key names required")
case "--tiebreak":
opts.Tiebreak = parseTiebreak(nextString(allArgs, &i, "sort criterion required"))
case "--color":
opts.Theme = parseTheme(nextString(allArgs, &i, "color scheme name required"))
case "--toggle-sort":
opts.ToggleSort = checkToggleSort(nextString(allArgs, &i, "key name required"))
case "-d", "--delimiter":
@ -326,9 +349,9 @@ func parseOptions(opts *Options, allArgs []string) {
case "--no-mouse":
opts.Mouse = false
case "+c", "--no-color":
opts.Color = false
opts.Theme = nil
case "+2", "--no-256":
opts.Color256 = false
opts.Theme = curses.Default16
case "--black":
opts.Black = true
case "--no-black":
@ -384,6 +407,8 @@ func parseOptions(opts *Options, allArgs []string) {
opts.Expect = parseKeyChords(value, "key names required")
} else if match, value := optString(arg, "--tiebreak="); match {
opts.Tiebreak = parseTiebreak(value)
} else if match, value := optString(arg, "--color="); match {
opts.Theme = parseTheme(value)
} else {
errorExit("unknown option: " + arg)
}

View File

@ -105,7 +105,7 @@ func NewTerminal(opts *Options, eventBox *util.EventBox) *Terminal {
suppress: true,
startChan: make(chan bool, 1),
initFunc: func() {
C.Init(opts.Color, opts.Color256, opts.Black, opts.Mouse)
C.Init(opts.Theme, opts.Black, opts.Mouse)
}}
}