First stab at builtin set_color. Moved set_color.cpp to builtin_set_color.cpp and taught fish about it.

This commit is contained in:
ridiculousfish 2013-02-14 15:50:24 -08:00
parent db5eebd372
commit 8d95d0834d
11 changed files with 249 additions and 431 deletions

View File

@ -167,7 +167,7 @@ static const io_chain_t *real_io;
static int builtin_count_args(wchar_t **argv)
{
int argc = 1;
while (argv[argc] != 0)
while (argv[argc] != NULL)
{
argc++;
}
@ -390,6 +390,7 @@ static void builtin_missing_argument(parser_t &parser, const wchar_t *cmd, const
#include "builtin_complete.cpp"
#include "builtin_ulimit.cpp"
#include "builtin_jobs.cpp"
#include "builtin_set_color.cpp"
/* builtin_test lives in builtin_test.cpp */
int builtin_test(parser_t &parser, wchar_t **argv);
@ -4030,6 +4031,7 @@ static const builtin_data_t builtin_datas[]=
{ L"read", &builtin_read, N_(L"Read a line of input into variables") },
{ L"return", &builtin_return, N_(L"Stop the currently evaluated function") },
{ L"set", &builtin_set, N_(L"Handle environment variables") },
{ L"set_color", &builtin_set_color, N_(L"Set the terminal color") },
{ L"status", &builtin_status, N_(L"Return status information about fish") },
{ L"switch", &builtin_switch, N_(L"Conditionally execute a block of commands") },
{ L"test", &builtin_test, N_(L"Test a condition") },

195
builtin_set_color.cpp Normal file
View File

@ -0,0 +1,195 @@
/** \file builtin_set_color.cpp Functions defining the set_color builtin
Functions used for implementing the set_color builtin.
*/
#include "config.h"
#include "builtin.h"
#include "color.h"
#include "output.h"
#if HAVE_TERM_H
#include <term.h>
#elif HAVE_NCURSES_TERM_H
#include <ncurses/term.h>
#endif
/* We know about these buffers */
extern wcstring stdout_buffer, stderr_buffer;
/**
Error message for invalid path operations
*/
#define BUILTIN_SET_PATH_ERROR L"%ls: Warning: path component %ls may not be valid in %ls.\n"
/**
Hint for invalid path operation with a colon
*/
#define BUILTIN_SET_PATH_HINT L"%ls: Did you mean 'set %ls $%ls %ls'?\n"
/**
Error for mismatch between index count and elements
*/
#define BUILTIN_SET_ARG_COUNT L"%ls: The number of variable indexes does not match the number of values\n"
static void print_colors(void)
{
const wcstring_list_t result = rgb_color_t::named_color_names();
size_t i;
for (i=0; i < result.size(); i++)
{
stdout_buffer.append(result.at(i));
stdout_buffer.push_back(L'\n');
}
}
/**
set_color builtin
*/
static int builtin_set_color(parser_t &parser, wchar_t **argv)
{
/** Variables used for parsing the argument list */
const struct woption long_options[] =
{
{ L"background", required_argument, 0, 'b'},
{ L"help", no_argument, 0, 'h' },
{ L"bold", no_argument, 0, 'o' },
{ L"underline", no_argument, 0, 'u' },
{ L"version", no_argument, 0, 'v' },
{ L"print-colors", no_argument, 0, 'c' },
{ 0, 0, 0, 0 }
};
const wchar_t *short_options = L"b:hvocu";
int argc = builtin_count_args(argv);
const wchar_t *bgcolor = NULL;
bool bold = false, underline=false;
/* Parse options to obtain the requested operation and the modifiers */
woptind = 0;
while (1)
{
int c = wgetopt_long(argc, argv, short_options, long_options, 0);
if (c == -1)
{
break;
}
switch (c)
{
case 0:
break;
case 'b':
bgcolor = woptarg;
break;
case 'h':
builtin_print_help(parser, argv[0], stdout_buffer);
return STATUS_BUILTIN_OK;
case 'o':
bold = true;
break;
case 'u':
underline = true;
break;
case 'c':
print_colors();
return STATUS_BUILTIN_OK;
case '?':
return STATUS_BUILTIN_ERROR;
}
}
/* Remaining argument is foreground color */
const wchar_t *fgcolor = NULL;
if (woptind < argc)
{
if (woptind + 1 == argc)
{
fgcolor = argv[woptind];
}
else
{
append_format(stderr_buffer,
_(L"%ls: Too many arguments\n"),
argv[0]);
return STATUS_BUILTIN_ERROR;
}
}
if (fgcolor == NULL && bgcolor == NULL && !bold && !underline)
{
append_format(stderr_buffer,
_(L"%ls: Expected an argument\n"),
argv[0]);
return STATUS_BUILTIN_ERROR;
}
const rgb_color_t fg = rgb_color_t(fgcolor ? fgcolor : L"");
if (fgcolor && fg.is_none())
{
append_format(stderr_buffer, _("%s: Unknown color '%s'\n"), argv[0], fgcolor);
return STATUS_BUILTIN_ERROR;
}
const rgb_color_t bg = rgb_color_t(bgcolor ? bgcolor : L"");
if (bgcolor && bg.is_none())
{
append_format(stderr_buffer, _("%s: Unknown color '%s'\n"), argv[0], bgcolor);
return STATUS_BUILTIN_ERROR;
}
if (bold)
{
if (enter_bold_mode)
putp(enter_bold_mode);
}
if (underline)
{
if (enter_underline_mode)
putp(enter_underline_mode);
}
if (bgcolor != NULL)
{
if (bg.is_normal())
{
write_background_color(0);
putp(tparm(exit_attribute_mode));
}
}
if (fgcolor != NULL)
{
if (fg.is_normal())
{
write_foreground_color(0);
putp(tparm(exit_attribute_mode));
}
else
{
write_foreground_color(index_for_color(fg));
}
}
if (bgcolor != NULL)
{
if (! bg.is_normal())
{
write_background_color(index_for_color(bg));
}
}
return STATUS_BUILTIN_OK;
}

View File

@ -170,6 +170,18 @@ static const named_color_t named_colors[11] =
{L"normal", 8, {0xFF, 0xFF, 0XFF}}
};
wcstring_list_t rgb_color_t::named_color_names(void)
{
size_t count = sizeof named_colors / sizeof *named_colors;
wcstring_list_t result;
result.reserve(count);
for (size_t i=0; i < count; i++)
{
result.push_back(named_colors[i].name);
}
return result;
}
bool rgb_color_t::try_parse_named(const wcstring &str)
{
bzero(&data, sizeof data);

View File

@ -169,6 +169,9 @@ public:
{
return !(*this == other);
}
/** Returns the names of all named colors */
static wcstring_list_t named_color_names(void);
};
#endif

View File

@ -18,7 +18,6 @@ as A0FF33 or f2f. fish will choose the closest supported color.
- \c -h, \c --help Display help message and exit
- \c -o, \c --bold Set bold or extra bright mode
- \c -u, \c --underline Set underlined mode
- \c -v, \c --version Display version and exit
Calling <tt>set_color normal</tt> will set the terminal color to

View File

@ -469,6 +469,7 @@
D0C4FD9415A7D7EE00212EF1 /* config.fish */ = {isa = PBXFileReference; lastKnownFileType = text; name = config.fish; path = etc/config.fish; sourceTree = "<group>"; };
D0C6FCC914CFA4B0004CE8AD /* autoload.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = autoload.cpp; sourceTree = "<group>"; };
D0C6FCCB14CFA4B7004CE8AD /* autoload.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = autoload.h; sourceTree = "<group>"; };
D0C861EA16CC7054003B5A04 /* builtin_set_color.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = builtin_set_color.cpp; sourceTree = "<group>"; };
D0CBD580159EE48F0024809C /* config.fish */ = {isa = PBXFileReference; lastKnownFileType = text; name = config.fish; path = share/config.fish; sourceTree = "<group>"; };
D0CBD583159EEE010024809C /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
D0CBD586159EF0E10024809C /* launch_fish.scpt */ = {isa = PBXFileReference; lastKnownFileType = file; name = launch_fish.scpt; path = osx/launch_fish.scpt; sourceTree = "<group>"; };
@ -592,6 +593,7 @@
D0A0853113B3ACEE0099B651 /* builtin_complete.cpp */,
D0A0853213B3ACEE0099B651 /* builtin_jobs.cpp */,
D0A0853313B3ACEE0099B651 /* builtin_set.cpp */,
D0C861EA16CC7054003B5A04 /* builtin_set_color.cpp */,
D0A0853413B3ACEE0099B651 /* builtin_ulimit.cpp */,
D0F3373A1506DE3C00ECEFC0 /* builtin_test.cpp */,
D0A0853513B3ACEE0099B651 /* builtin.cpp */,

View File

@ -146,7 +146,7 @@ void output_set_supports_term256(bool val)
support_term256 = val;
}
static unsigned char index_for_color(rgb_color_t c)
unsigned char index_for_color(rgb_color_t c)
{
if (c.is_named() || ! output_get_supports_term256())
{
@ -192,7 +192,7 @@ static bool write_color(char *todo, unsigned char idx, bool is_fg)
return result;
}
static bool write_foreground_color(unsigned char idx)
bool write_foreground_color(unsigned char idx)
{
if (set_a_foreground && set_a_foreground[0])
{
@ -208,7 +208,7 @@ static bool write_foreground_color(unsigned char idx)
}
}
static bool write_background_color(unsigned char idx)
bool write_background_color(unsigned char idx)
{
if (set_a_background && set_a_background[0])
{

View File

@ -163,4 +163,9 @@ const wchar_t *output_get_term();
bool output_get_supports_term256();
void output_set_supports_term256(bool val);
/* Exported for builtin_set_color's usage only */
bool write_foreground_color(unsigned char idx);
bool write_background_color(unsigned char idx);
unsigned char index_for_color(rgb_color_t c);
#endif

View File

@ -1,400 +0,0 @@
#include "config.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <termios.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <locale.h>
#if HAVE_NCURSES_H
#include <ncurses.h>
#else
#include <curses.h>
#endif
#if HAVE_TERMIO_H
#include <termio.h>
#endif
#if HAVE_TERM_H
#include <term.h>
#elif HAVE_NCURSES_TERM_H
#include <ncurses/term.h>
#endif
#include <errno.h>
#ifdef HAVE_GETOPT_H
#include <getopt.h>
#endif
#if HAVE_LIBINTL_H
#include <libintl.h>
#endif
#include "fallback.h"
#include "print_help.h"
#include "color.h"
/*
Small utility for setting the color.
Usage: set_color COLOR
where COLOR is either an integer from 0 to seven or one of the strings in the col array.
*/
#define COLORS (sizeof(col)/sizeof(char *))
/**
Program name
*/
#define SET_COLOR "set_color"
/**
Getopt short switches for set_color
*/
#define GETOPT_STRING "b:hvocu"
#ifdef _
#undef _
#endif
#ifdef USE_GETTEXT
#define _(string) gettext(string)
#else
#define _(string) (string)
#endif
const char *col[]=
{
"black",
"red",
"green",
"brown",
"yellow",
"blue",
"magenta",
"purple",
"cyan",
"white",
"normal"
};
const int col_idx[]=
{
0,
1,
2,
3,
3,
4,
5,
5,
6,
7,
8
};
void print_colors()
{
size_t i;
for (i=0; i<COLORS; i++)
{
printf("%s\n", col[i]);
}
}
static void check_locale_init()
{
static int is_init = 0;
if (is_init)
return;
is_init = 1;
setlocale(LC_ALL, "");
bindtextdomain(PACKAGE_NAME, LOCALEDIR);
textdomain(PACKAGE_NAME);
}
/* A lot of this code is taken straight from output.cpp; it sure would be nice to factor these together. */
static bool support_term256;
static bool output_get_supports_term256(void)
{
return support_term256;
}
static bool term256_support_is_native(void)
{
/* Return YES if we think the term256 support is "native" as opposed to forced. */
return max_colors == 256;
}
static bool write_color(char *todo, unsigned char idx, bool is_fg)
{
bool result = false;
if (idx < 16 || term256_support_is_native())
{
/* Use tparm */
putp(tparm(todo, idx));
result = true;
}
else
{
/* We are attempting to bypass the term here. Generate the ANSI escape sequence ourself. */
char stridx[128];
format_long_safe(stridx, (long)idx);
char buff[128] = "\x1b[";
strcat(buff, is_fg ? "38;5;" : "48;5;");
strcat(buff, stridx);
strcat(buff, "m");
write_loop(STDOUT_FILENO, buff, strlen(buff));
result = true;
}
return result;
}
static bool write_foreground_color(unsigned char idx)
{
if (set_a_foreground && set_a_foreground[0])
{
return write_color(set_a_foreground, idx, true);
}
else if (set_foreground && set_foreground[0])
{
return write_color(set_foreground, idx, true);
}
else
{
return false;
}
}
static bool write_background_color(unsigned char idx)
{
if (set_a_background && set_a_background[0])
{
return write_color(set_a_background, idx, false);
}
else if (set_background && set_background[0])
{
return write_color(set_background, idx, false);
}
else
{
return false;
}
}
static unsigned char index_for_color(rgb_color_t c)
{
if (c.is_named() || ! output_get_supports_term256())
{
return c.to_name_index();
}
else
{
return c.to_term256_index();
}
}
int main(int argc, char **argv)
{
/* Some code passes variables to set_color that don't exist, like $fish_user_whatever. As a hack, quietly return failure. */
if (argc <= 1)
return EXIT_FAILURE;
char *bgcolor=0;
char *fgcolor=0;
bool bold=false;
bool underline=false;
while (1)
{
static struct option
long_options[] =
{
{
"background", required_argument, 0, 'b'
}
,
{
"help", no_argument, 0, 'h'
}
,
{
"bold", no_argument, 0, 'o'
}
,
{
"underline", no_argument, 0, 'u'
}
,
{
"version", no_argument, 0, 'v'
}
,
{
"print-colors", no_argument, 0, 'c'
}
,
{
0, 0, 0, 0
}
}
;
int opt_index = 0;
int opt = getopt_long(argc,
argv,
GETOPT_STRING,
long_options,
&opt_index);
if (opt == -1)
break;
switch (opt)
{
case 0:
break;
case 'b':
bgcolor = optarg;
break;
case 'h':
print_help(argv[0], 1);
exit(0);
case 'o':
bold=true;
break;
case 'u':
underline=true;
break;
case 'v':
check_locale_init();
fprintf(stderr, _("%s, version %s\n"), SET_COLOR, PACKAGE_VERSION);
exit(0);
case 'c':
print_colors();
exit(0);
case '?':
return 1;
}
}
switch (argc-optind)
{
case 0:
// printf( "no fg\n" );
break;
case 1:
fgcolor=argv[optind];
// printf( "fg %s\n", fgcolor );
break;
default:
check_locale_init();
printf(_("%s: Too many arguments\n"), SET_COLOR);
return 1;
}
/* Infer term256 support */
char *fish_term256 = getenv("fish_term256");
if (fish_term256)
{
support_term256 = from_string<bool>(fish_term256);
}
else
{
const char *term = getenv("TERM");
support_term256 = term && strstr(term, "256color");
}
if (!fgcolor && !bgcolor && !bold && !underline)
{
check_locale_init();
fprintf(stderr, _("%s: Expected an argument\n"), SET_COLOR);
print_help(argv[0], 2);
return 1;
}
rgb_color_t fg = rgb_color_t(fgcolor ? fgcolor : "");
if (fgcolor && fg.is_none())
{
check_locale_init();
fprintf(stderr, _("%s: Unknown color '%s'\n"), SET_COLOR, fgcolor);
return 1;
}
rgb_color_t bg = rgb_color_t(bgcolor ? bgcolor : "");
if (bgcolor && bg.is_none())
{
check_locale_init();
fprintf(stderr, _("%s: Unknown color '%s'\n"), SET_COLOR, bgcolor);
return 1;
}
setupterm(0, STDOUT_FILENO, 0);
if (bold)
{
if (enter_bold_mode)
putp(enter_bold_mode);
}
if (underline)
{
if (enter_underline_mode)
putp(enter_underline_mode);
}
if (bgcolor)
{
if (bg.is_normal())
{
write_background_color(0);
putp(tparm(exit_attribute_mode));
}
}
if (fgcolor)
{
if (fg.is_normal())
{
write_foreground_color(0);
putp(tparm(exit_attribute_mode));
}
else
{
write_foreground_color(index_for_color(fg));
}
}
if (bgcolor)
{
if (! bg.is_normal())
{
write_background_color(index_for_color(bg));
}
}
if (del_curterm(cur_term) == ERR)
{
fprintf(stderr, "%s", _("Error while closing terminfo"));
}
}