Merge branch 'master' into ast_templates

Conflicts:
	fish_tests.cpp
This commit is contained in:
ridiculousfish 2013-07-21 14:04:06 -07:00
commit 551d2dfebd
22 changed files with 756 additions and 460 deletions

View file

@ -1660,7 +1660,7 @@ static int builtin_echo(parser_t &parser, wchar_t **argv)
wc = L'\b';
break;
case L'e':
wc = L'\e';
wc = L'\x1B';
break;
case L'f':
wc = L'\f';
@ -2372,8 +2372,9 @@ static int builtin_read(parser_t &parser, wchar_t **argv)
reader_set_highlight_function(&highlight_shell);
reader_set_test_function(&reader_shell_test);
}
/* No autosuggestions in builtin_read */
/* No autosuggestions or abbreviations in builtin_read */
reader_set_allow_autosuggesting(false);
reader_set_expand_abbreviations(false);
reader_set_exit_on_interrupt(true);
reader_set_buffer(commandline, wcslen(commandline));

View file

@ -26,6 +26,7 @@
\a = alert (bell)
\b = backspace
\c = produce no further output
\e = escape
\f = form feed
\n = new line
\r = carriage return
@ -319,6 +320,9 @@ void builtin_printf_state_t::print_esc_char(wchar_t c)
case L'c': /* Cancel the rest of the output. */
this->early_exit = true;
break;
case L'e': /* Escape */
this->append_output(L'\x1B');
break;
case L'f': /* Form feed. */
this->append_output(L'\f');
break;
@ -358,7 +362,7 @@ long builtin_printf_state_t::print_esc(const wchar_t *escstart, bool octal_0)
esc_value = esc_value * 16 + hex_to_bin(*p);
if (esc_length == 0)
this->fatal_error(_(L"missing hexadecimal number in escape"));
this->append_format_output(L"%lc", esc_value);
this->append_output(esc_value);
}
else if (is_octal_digit(*p))
{
@ -367,10 +371,12 @@ long builtin_printf_state_t::print_esc(const wchar_t *escstart, bool octal_0)
extension to POSIX that is compatible with Bash 2.05b. */
for (esc_length = 0, p += octal_0 && *p == L'0'; esc_length < 3 && is_octal_digit(*p); ++esc_length, ++p)
esc_value = esc_value * 8 + octal_to_bin(*p);
this->append_format_output(L"%c", esc_value);
this->append_output(esc_value);
}
else if (*p && wcschr(L"\"\\abcfnrtv", *p))
else if (*p && wcschr(L"\"\\abcefnrtv", *p))
{
print_esc_char(*p++);
}
else if (*p == L'u' || *p == L'U')
{
wchar_t esc_char = *p;
@ -575,6 +581,16 @@ void builtin_printf_state_t::print_direc(const wchar_t *start, size_t length, wc
}
}
/* For each character in str, set the corresponding boolean in the array to the given flag */
static inline void modify_allowed_format_specifiers(bool ok[UCHAR_MAX + 1], const char *str, bool flag)
{
for (const char *c = str; *c != '\0'; c++)
{
unsigned char idx = static_cast<unsigned char>(*c);
ok[idx] = flag;
}
}
/* Print the text in FORMAT, using ARGV (with ARGC elements) for
arguments to any `%' directives.
Return the number of elements of ARGV used. */
@ -617,9 +633,7 @@ int builtin_printf_state_t::print_formatted(const wchar_t *format, int argc, wch
break;
}
ok['a'] = ok['A'] = ok['c'] = ok['d'] = ok['e'] = ok['E'] =
ok['f'] = ok['F'] = ok['g'] = ok['G'] = ok['i'] = ok['o'] =
ok['s'] = ok['u'] = ok['x'] = ok['X'] = true;
modify_allowed_format_specifiers(ok, "aAcdeEfFgGiosuxX", true);
for (;; f++, direc_length++)
{
@ -627,18 +641,17 @@ int builtin_printf_state_t::print_formatted(const wchar_t *format, int argc, wch
{
case L'I':
case L'\'':
ok['a'] = ok['A'] = ok['c'] = ok['e'] = ok['E'] =
ok['o'] = ok['s'] = ok['x'] = ok['X'] = false;
modify_allowed_format_specifiers(ok, "aAceEosxX", false);
break;
case '-':
case '+':
case ' ':
break;
case L'#':
ok['c'] = ok['d'] = ok['i'] = ok['s'] = ok['u'] = false;
modify_allowed_format_specifiers(ok, "cdisu", false);
break;
case '0':
ok['c'] = ok['s'] = false;
modify_allowed_format_specifiers(ok, "cs", false);
break;
default:
goto no_more_flag_characters;
@ -679,7 +692,7 @@ no_more_flag_characters:
{
++f;
++direc_length;
ok['c'] = false;
modify_allowed_format_specifiers(ok, "c", false);
if (*f == L'*')
{
++f;

View file

@ -137,7 +137,6 @@ struct env_node_t
class variable_entry_t
{
bool exportv; /**< Whether the variable should be exported */
wcstring value; /**< Value of the variable */
};

View file

@ -1336,10 +1336,7 @@ static int expand_cmdsubst(parser_t &parser, const wcstring &input, std::vector<
const wchar_t * const in = input.c_str();
int parse_ret;
switch (parse_ret = parse_util_locate_cmdsubst(in,
&paran_begin,
&paran_end,
0))
switch (parse_ret = parse_util_locate_cmdsubst(in, &paran_begin, &paran_end, false))
{
case -1:
parser.error(SYNTAX_ERROR,
@ -1628,10 +1625,7 @@ int expand_string(const wcstring &input, std::vector<completion_t> &output, expa
{
wchar_t *begin, *end;
if (parse_util_locate_cmdsubst(input.c_str(),
&begin,
&end,
1) != 0)
if (parse_util_locate_cmdsubst(input.c_str(), &begin, &end, true) != 0)
{
parser.error(CMDSUBST_ERROR, -1, L"Command substitutions not allowed");
return EXPAND_ERROR;
@ -1939,3 +1933,42 @@ bool fish_openSUSE_dbus_hack_hack_hack_hack(std::vector<completion_t> *args)
}
return result;
}
bool expand_abbreviation(const wcstring &src, wcstring *output)
{
if (src.empty())
return false;
/* Get the abbreviations. Return false if we have none */
env_var_t var = env_get_string(USER_ABBREVIATIONS_VARIABLE_NAME);
if (var.missing_or_empty())
return false;
bool result = false;
wcstring line;
wcstokenizer tokenizer(var, ARRAY_SEP_STR);
while (tokenizer.next(line))
{
/* Line is expected to be of the form 'foo=bar'. Parse out the first =. Be forgiving about spaces, but silently skip on failure (no equals, or equals at the end or beginning). Try to avoid copying any strings until we are sure this is a match. */
size_t equals = line.find(L'=');
if (equals == wcstring::npos || equals == 0 || equals + 1 == line.size())
continue;
/* Find the character just past the end of the command. Walk backwards, skipping spaces. */
size_t cmd_end = equals;
while (cmd_end > 0 && iswspace(line.at(cmd_end - 1)))
cmd_end--;
/* See if this command matches */
if (line.compare(0, cmd_end, src) == 0)
{
/* Success. Set output to everythign past the end of the string. */
if (output != NULL)
output->assign(line, equals + 1, wcstring::npos);
result = true;
break;
}
}
return result;
}

View file

@ -206,6 +206,10 @@ void expand_variable_error(parser_t &parser, const wchar_t *token, size_t token_
*/
std::vector<wcstring> expand_get_all_process_names(void);
/** Abbreviation support. Expand src as an abbreviation, returning true if one was found, false if not. If result is not-null, returns the abbreviation by reference. */
#define USER_ABBREVIATIONS_VARIABLE_NAME L"fish_user_abbreviations"
bool expand_abbreviation(const wcstring &src, wcstring *output);
/* Terrible hacks */
bool fish_xdm_login_hack_hack_hack_hack(std::vector<std::string> *cmds, int argc, const char * const *argv);
bool fish_openSUSE_dbus_hack_hack_hack_hack(std::vector<completion_t> *args);

View file

@ -382,36 +382,6 @@ static int fish_parse_opt(int argc, char **argv, std::vector<std::string> *out_c
return my_optind;
}
/**
Calls a bunch of init functions, parses the init files and then
parses commands from stdin or files, depending on arguments
*/
static wcstring full_escape(const wchar_t *in)
{
wcstring out;
for (; *in; in++)
{
if (*in < 32)
{
append_format(out, L"\\x%.2x", *in);
}
else if (*in < 128)
{
out.push_back(*in);
}
else if (*in < 65536)
{
append_format(out, L"\\u%.4x", *in);
}
else
{
append_format(out, L"\\U%.8x", *in);
}
}
return out;
}
extern int g_fork_count;
int main(int argc, char **argv)
{

View file

@ -1209,6 +1209,7 @@
MACOSX_DEPLOYMENT_TARGET = 10.7;
SDKROOT = macosx;
USER_HEADER_SEARCH_PATHS = "$(SRCROOT)/osx/**";
WARNING_CFLAGS = "-Wall";
};
name = "Release_C++11";
};
@ -1361,6 +1362,7 @@
ONLY_ACTIVE_ARCH = YES;
SDKROOT = macosx;
USER_HEADER_SEARCH_PATHS = "$(SRCROOT)/osx/**";
WARNING_CFLAGS = "-Wall";
};
name = Debug;
};
@ -1385,6 +1387,7 @@
MACOSX_DEPLOYMENT_TARGET = 10.6;
SDKROOT = macosx;
USER_HEADER_SEARCH_PATHS = "$(SRCROOT)/osx/**";
WARNING_CFLAGS = "-Wall";
};
name = Release;
};

View file

@ -62,6 +62,7 @@
#include "highlight.h"
#include "parse_tree.h"
#include "parse_exec.h"
#include "parse_util.h"
/**
The number of tests to run
@ -529,6 +530,28 @@ static void test_parser()
}
}
static void test_utils()
{
say(L"Testing utils");
const wchar_t *a = L"echo (echo (echo hi";
const wchar_t *begin = NULL, *end = NULL;
parse_util_cmdsubst_extent(a, 0, &begin, &end);
if (begin != a || end != begin + wcslen(begin)) err(L"parse_util_cmdsubst_extent failed on line %ld", (long)__LINE__);
parse_util_cmdsubst_extent(a, 1, &begin, &end);
if (begin != a || end != begin + wcslen(begin)) err(L"parse_util_cmdsubst_extent failed on line %ld", (long)__LINE__);
parse_util_cmdsubst_extent(a, 2, &begin, &end);
if (begin != a || end != begin + wcslen(begin)) err(L"parse_util_cmdsubst_extent failed on line %ld", (long)__LINE__);
parse_util_cmdsubst_extent(a, 3, &begin, &end);
if (begin != a || end != begin + wcslen(begin)) err(L"parse_util_cmdsubst_extent failed on line %ld", (long)__LINE__);
parse_util_cmdsubst_extent(a, 8, &begin, &end);
if (begin != a + wcslen(L"echo (")) err(L"parse_util_cmdsubst_extent failed on line %ld", (long)__LINE__);
parse_util_cmdsubst_extent(a, 17, &begin, &end);
if (begin != a + wcslen(L"echo (echo (")) err(L"parse_util_cmdsubst_extent failed on line %ld", (long)__LINE__);
}
class lru_node_test_t : public lru_node_t
{
public:
@ -680,6 +703,65 @@ static void test_fuzzy_match(void)
if (string_fuzzy_match_string(L"BB", L"ALPHA!").type != fuzzy_match_none) err(L"test_fuzzy_match failed on line %ld", __LINE__);
}
static void test_abbreviations(void)
{
say(L"Testing abbreviations");
const wchar_t *abbreviations =
L"gc=git checkout" ARRAY_SEP_STR
L"foo=" ARRAY_SEP_STR
L"gc=something else" ARRAY_SEP_STR
L"=" ARRAY_SEP_STR
L"=foo" ARRAY_SEP_STR
L"foo" ARRAY_SEP_STR
L"foo=bar";
env_push(true);
int ret = env_set(USER_ABBREVIATIONS_VARIABLE_NAME, abbreviations, ENV_LOCAL);
if (ret != 0) err(L"Unable to set abbreviation variable");
wcstring result;
if (expand_abbreviation(L"", &result)) err(L"Unexpected success with empty abbreviation");
if (expand_abbreviation(L"nothing", &result)) err(L"Unexpected success with missing abbreviation");
if (! expand_abbreviation(L"gc", &result)) err(L"Unexpected failure with gc abbreviation");
if (result != L"git checkout") err(L"Wrong abbreviation result for gc");
result.clear();
if (! expand_abbreviation(L"foo", &result)) err(L"Unexpected failure with foo abbreviation");
if (result != L"bar") err(L"Wrong abbreviation result for foo");
bool expanded;
expanded = reader_expand_abbreviation_in_command(L"just a command", 3, &result);
if (expanded) err(L"Command wrongly expanded on line %ld", (long)__LINE__);
expanded = reader_expand_abbreviation_in_command(L"gc somebranch", 0, &result);
if (! expanded) err(L"Command not expanded on line %ld", (long)__LINE__);
expanded = reader_expand_abbreviation_in_command(L"gc somebranch", wcslen(L"gc"), &result);
if (! expanded) err(L"gc not expanded");
if (result != L"git checkout somebranch") err(L"gc incorrectly expanded on line %ld to '%ls'", (long)__LINE__, result.c_str());
expanded = reader_expand_abbreviation_in_command(L"echo hi ; gc somebranch", wcslen(L"echo hi ; g"), &result);
if (! expanded) err(L"gc not expanded on line %ld", (long)__LINE__);
if (result != L"echo hi ; git checkout somebranch") err(L"gc incorrectly expanded on line %ld", (long)__LINE__);
expanded = reader_expand_abbreviation_in_command(L"echo (echo (echo (echo (gc ", wcslen(L"echo (echo (echo (echo (gc"), &result);
if (! expanded) err(L"gc not expanded on line %ld", (long)__LINE__);
if (result != L"echo (echo (echo (echo (git checkout ") err(L"gc incorrectly expanded on line %ld to '%ls'", (long)__LINE__, result.c_str());
/* if commands should be expanded */
expanded = reader_expand_abbreviation_in_command(L"if gc", wcslen(L"if gc"), &result);
if (! expanded) err(L"gc not expanded on line %ld", (long)__LINE__);
if (result != L"if git checkout") err(L"gc incorrectly expanded on line %ld to '%ls'", (long)__LINE__, result.c_str());
/* others should not be */
expanded = reader_expand_abbreviation_in_command(L"of gc", wcslen(L"of gc"), &result);
if (expanded) err(L"gc incorrectly expanded on line %ld", (long)__LINE__);
env_pop();
}
/** Test path functions */
static void test_path()
{
@ -1771,9 +1853,11 @@ int main(int argc, char **argv)
test_tok();
test_fork();
test_parser();
test_utils();
test_lru();
test_expand();
test_fuzzy_match();
test_abbreviations();
test_test();
test_path();
test_word_motion();

View file

@ -1106,6 +1106,9 @@ static void tokenize(const wchar_t * const buff, std::vector<int> &color, const
if (! is_cmd && use_function)
is_cmd = function_exists_no_autoload(cmd, vars);
if (! is_cmd)
is_cmd = expand_abbreviation(cmd, NULL);
/*
Moving on to expensive tests
*/
@ -1319,7 +1322,7 @@ void highlight_shell(const wcstring &buff, std::vector<int> &color, size_t pos,
std::fill(color.begin(), color.end(), -1);
/* Do something sucky and get the current working directory on this background thread. This should really be passed in. Note that we also need this as a vector (of one directory). */
/* Do something sucky and get the current working directory on this background thread. This should really be passed in. */
const wcstring working_directory = env_get_pwd_slash();
/* Tokenize the string */
@ -1335,7 +1338,7 @@ void highlight_shell(const wcstring &buff, std::vector<int> &color, size_t pos,
{
wchar_t *begin, *end;
if (parse_util_locate_cmdsubst(subpos, &begin, &end, 1) <= 0)
if (parse_util_locate_cmdsubst(subpos, &begin, &end, true) <= 0)
{
break;
}

View file

@ -153,10 +153,7 @@ size_t parse_util_get_offset(const wcstring &str, int line, long line_offset)
}
int parse_util_locate_cmdsubst(const wchar_t *in,
wchar_t **begin,
wchar_t **end,
int allow_incomplete)
int parse_util_locate_cmdsubst(const wchar_t *in, wchar_t **begin, wchar_t **end, bool allow_incomplete)
{
wchar_t *pos;
wchar_t prev=0;
@ -243,73 +240,57 @@ int parse_util_locate_cmdsubst(const wchar_t *in,
return 1;
}
void parse_util_cmdsubst_extent(const wchar_t *buff,
size_t cursor_pos,
const wchar_t **a,
const wchar_t **b)
void parse_util_cmdsubst_extent(const wchar_t *buff, size_t cursor_pos, const wchar_t **a, const wchar_t **b)
{
wchar_t *begin, *end;
wchar_t *pos;
const wchar_t *cursor = buff + cursor_pos;
const wchar_t * const cursor = buff + cursor_pos;
CHECK(buff,);
if (a)
{
*a = (wchar_t *)buff;
}
const size_t bufflen = wcslen(buff);
assert(cursor_pos <= bufflen);
if (b)
/* ap and bp are the beginning and end of the tightest command substitition found so far */
const wchar_t *ap = buff, *bp = buff + bufflen;
const wchar_t *pos = buff;
for (;;)
{
*b = (wchar_t *)buff+wcslen(buff);
}
pos = (wchar_t *)buff;
while (1)
{
if (parse_util_locate_cmdsubst(pos,
&begin,
&end,
1) <= 0)
wchar_t *begin = NULL, *end = NULL;
if (parse_util_locate_cmdsubst(pos, &begin, &end, true) <= 0)
{
/*
No subshell found
*/
/* No subshell found, all done */
break;
}
if (!end)
/* Intrepret NULL to mean the end */
if (end == NULL)
{
end = (wchar_t *)buff + wcslen(buff);
end = const_cast<wchar_t *>(buff) + bufflen;
}
if ((begin < cursor) && (end >= cursor))
if (begin < cursor && end >= cursor)
{
/* This command substitution surrounds the cursor, so it's a tighter fit */
begin++;
if (a)
{
*a = begin;
}
if (b)
{
*b = end;
}
break;
ap = begin;
bp = end;
pos = begin + 1;
}
if (!*end)
else if (begin >= cursor)
{
/* This command substitution starts at or after the cursor. Since it was the first command substitution in the string, we're done. */
break;
}
pos = end+1;
else
{
/* This command substitution ends before the cursor. Skip it. */
assert(end < cursor);
pos = end + 1;
assert(pos <= buff + bufflen);
}
}
if (a != NULL) *a = ap;
if (b != NULL) *b = bp;
}
/**
@ -432,7 +413,6 @@ void parse_util_token_extent(const wchar_t *buff,
{
const wchar_t *begin, *end;
long pos;
wchar_t *buffcpy;
const wchar_t *a = NULL, *b = NULL, *pa = NULL, *pb = NULL;
@ -459,14 +439,9 @@ void parse_util_token_extent(const wchar_t *buff,
assert(end >= begin);
assert(end <= (buff+wcslen(buff)));
buffcpy = wcsndup(begin, end-begin);
const wcstring buffcpy = wcstring(begin, end-begin);
if (!buffcpy)
{
DIE_MEM();
}
tokenizer_t tok(buffcpy, TOK_ACCEPT_UNFINISHED | TOK_SQUASH_ERRORS);
tokenizer_t tok(buffcpy.c_str(), TOK_ACCEPT_UNFINISHED | TOK_SQUASH_ERRORS);
for (; tok_has_next(&tok); tok_next(&tok))
{
size_t tok_begin = tok_get_pos(&tok);
@ -512,8 +487,6 @@ void parse_util_token_extent(const wchar_t *buff,
}
}
free(buffcpy);
if (tok_begin)
{
*tok_begin = a;
@ -568,7 +541,6 @@ void parse_util_set_argv(const wchar_t * const *argv, const wcstring_list_t &nam
{
const wchar_t * const *arg;
size_t i;
for (i=0, arg=argv; i < named_arguments.size(); i++)
{
env_set(named_arguments.at(i).c_str(), *arg, ENV_LOCAL);
@ -576,10 +548,7 @@ void parse_util_set_argv(const wchar_t * const *argv, const wcstring_list_t &nam
if (*arg)
arg++;
}
}
}
wchar_t *parse_util_unescape_wildcards(const wchar_t *str)
@ -679,7 +648,7 @@ static wchar_t get_quote(const wchar_t *cmd, size_t len)
{
const wchar_t *end = quote_end(&cmd[i]);
//fwprintf( stderr, L"Jump %d\n", end-cmd );
if ((end == 0) || (!*end) || (end-cmd > len))
if ((end == 0) || (!*end) || (end > cmd + len))
{
res = cmd[i];
break;

View file

@ -18,14 +18,14 @@
\param in the string to search for subshells
\param begin the starting paranthesis of the subshell
\param end the ending paranthesis of the subshell
\param flags set this variable to ACCEPT_INCOMPLETE if in tab_completion mode
\param accept_incomplete whether to permit missing closing parenthesis
\return -1 on syntax error, 0 if no subshells exist and 1 on sucess
*/
int parse_util_locate_cmdsubst(const wchar_t *in,
wchar_t **begin,
wchar_t **end,
int flags);
bool accept_incomplete);
/**
Find the beginning and end of the command substitution under the

View file

@ -2025,6 +2025,7 @@ int parser_t::parse_job(process_t *p,
for this, used by other shells like bash
and zsh).
*/
if (wcschr(cmd, L'='))
{
wchar_t *cpy = wcsdup(cmd);
@ -2074,9 +2075,15 @@ int parser_t::parse_job(process_t *p,
}
else
{
debug(0,
_(L"Unknown command '%ls'"),
cmd?cmd:L"UNKNOWN");
/*
Handle unrecognized commands with standard
command not found handler that can make better
error messages
*/
wcstring_list_t event_args;
event_args.push_back(args.at(0).completion);
event_fire_generic(L"fish_command_not_found", &event_args);
}
tmp = current_tokenizer_pos;
@ -2088,9 +2095,6 @@ int parser_t::parse_job(process_t *p,
job_set_flag(j, JOB_SKIP, 1);
wcstring_list_t event_args;
event_args.push_back(args.at(0).completion);
event_fire_generic(L"fish_command_not_found", &event_args);
proc_set_last_status(err==ENOENT?STATUS_UNKNOWN_COMMAND:STATUS_NOT_EXECUTABLE);
}
}
@ -2714,7 +2718,7 @@ int parser_t::parser_test_argument(const wchar_t *arg, wcstring *out, const wcha
switch (parse_util_locate_cmdsubst(arg_cpy,
&paran_begin,
&paran_end,
0))
false))
{
case -1:
err=1;

View file

@ -97,8 +97,8 @@ commence.
#include "iothread.h"
#include "intern.h"
#include "path.h"
#include "parse_util.h"
#include "parser_keywords.h"
/**
Maximum length of prefix string when printing completion
@ -182,6 +182,8 @@ static pthread_key_t generation_count_key;
/* A color is an int */
typedef int color_t;
static void set_command_line_and_position(const wcstring &new_str, size_t pos);
/**
A struct describing the state of the interactive reader. These
states can be stacked, in case reader_readline() calls are
@ -203,6 +205,9 @@ public:
/** When backspacing, we temporarily suppress autosuggestions */
bool suppress_autosuggestion;
/** Whether abbreviations are expanded */
bool expand_abbreviations;
/** The representation of the current screen contents */
screen_t screen;
@ -244,6 +249,9 @@ public:
/** Do what we need to do whenever our command line changes */
void command_line_changed(void);
/** Expand abbreviations at the current cursor position. */
bool expand_abbreviation_as_necessary();
/** The current position of the cursor in buff. */
size_t buff_pos;
@ -326,6 +334,7 @@ public:
reader_data_t() :
allow_autosuggestion(0),
suppress_autosuggestion(0),
expand_abbreviations(0),
history(0),
token_history_pos(0),
search_pos(0),
@ -635,6 +644,159 @@ void reader_data_t::command_line_changed()
s_generation_count++;
}
/* Expand abbreviations at the given cursor position. Does NOT inspect 'data'. */
bool reader_expand_abbreviation_in_command(const wcstring &cmdline, size_t cursor_pos, wcstring *output)
{
/* See if we are at "command position". Get the surrounding command substitution, and get the extent of the first token. */
const wchar_t * const buff = cmdline.c_str();
const wchar_t *cmdsub_begin = NULL, *cmdsub_end = NULL;
parse_util_cmdsubst_extent(buff, cursor_pos, &cmdsub_begin, &cmdsub_end);
assert(cmdsub_begin != NULL && cmdsub_begin >= buff);
assert(cmdsub_end != NULL && cmdsub_end >= cmdsub_begin);
/* Determine the offset of this command substitution */
const size_t subcmd_offset = cmdsub_begin - buff;
const wcstring subcmd = wcstring(cmdsub_begin, cmdsub_end - cmdsub_begin);
const wchar_t *subcmd_cstr = subcmd.c_str();
/* Get the token before the cursor */
const wchar_t *subcmd_tok_begin = NULL, *subcmd_tok_end = NULL;
assert(cursor_pos >= subcmd_offset);
size_t subcmd_cursor_pos = cursor_pos - subcmd_offset;
parse_util_token_extent(subcmd_cstr, subcmd_cursor_pos, &subcmd_tok_begin, &subcmd_tok_end, NULL, NULL);
/* Compute the offset of the token before the cursor within the subcmd */
assert(subcmd_tok_begin >= subcmd_cstr);
assert(subcmd_tok_end >= subcmd_tok_begin);
const size_t subcmd_tok_begin_offset = subcmd_tok_begin - subcmd_cstr;
const size_t subcmd_tok_length = subcmd_tok_end - subcmd_tok_begin;
/* Now parse the subcmd, looking for commands */
bool had_cmd = false, previous_token_is_cmd = false;
tokenizer_t tok(subcmd_cstr, TOK_ACCEPT_UNFINISHED | TOK_SQUASH_ERRORS);
for (; tok_has_next(&tok); tok_next(&tok))
{
size_t tok_pos = static_cast<size_t>(tok_get_pos(&tok));
if (tok_pos > subcmd_tok_begin_offset)
{
/* We've passed the token we're interested in */
break;
}
int last_type = tok_last_type(&tok);
switch (last_type)
{
case TOK_STRING:
{
if (had_cmd)
{
/* Parameter to the command. */
}
else
{
const wcstring potential_cmd = tok_last(&tok);
if (parser_keywords_is_subcommand(potential_cmd))
{
if (potential_cmd == L"command" || potential_cmd == L"builtin")
{
/* 'command' and 'builtin' defeat abbreviation expansion. Skip this command. */
had_cmd = true;
}
else
{
/* Other subcommand. Pretend it doesn't exist so that we can expand the following command */
had_cmd = false;
}
}
else
{
/* It's a normal command */
had_cmd = true;
if (tok_pos == subcmd_tok_begin_offset)
{
/* This is the token we care about! */
previous_token_is_cmd = true;
}
}
}
break;
}
case TOK_REDIRECT_NOCLOB:
case TOK_REDIRECT_OUT:
case TOK_REDIRECT_IN:
case TOK_REDIRECT_APPEND:
case TOK_REDIRECT_FD:
{
if (!had_cmd)
{
break;
}
tok_next(&tok);
break;
}
case TOK_PIPE:
case TOK_BACKGROUND:
case TOK_END:
{
had_cmd = false;
break;
}
case TOK_COMMENT:
case TOK_ERROR:
default:
{
break;
}
}
}
bool result = false;
if (previous_token_is_cmd)
{
/* The token is a command. Try expanding it as an abbreviation. */
const wcstring token = wcstring(subcmd, subcmd_tok_begin_offset, subcmd_tok_length);
wcstring abbreviation;
if (expand_abbreviation(token, &abbreviation))
{
/* There was an abbreviation! Replace the token in the full command. Maintain the relative position of the cursor. */
if (output != NULL)
{
size_t cmd_tok_begin_offset = subcmd_tok_begin_offset + subcmd_offset;
output->assign(cmdline);
output->replace(cmd_tok_begin_offset, subcmd_tok_length, abbreviation);
}
result = true;
}
}
return result;
}
/* Expand abbreviations. This may change the command line but does NOT repaint it. This is to allow the caller to coalesce repaints. */
bool reader_data_t::expand_abbreviation_as_necessary()
{
bool result = false;
if (this->expand_abbreviations)
{
/* Try expanding abbreviations */
wcstring new_cmdline;
if (reader_expand_abbreviation_in_command(this->command_line, this->buff_pos, &new_cmdline))
{
/* We expanded an abbreviation! The cursor moves by the difference in the command line lengths. */
size_t new_buff_pos = this->buff_pos + new_cmdline.size() - this->command_line.size();
this->command_line.swap(new_cmdline);
data->buff_pos = new_buff_pos;
data->command_line_changed();
result = true;
}
}
return result;
}
/** Sorts and remove any duplicate completions in the list. */
static void sort_and_make_unique(std::vector<completion_t> &l)
@ -1980,8 +2142,7 @@ void reader_sanity_check()
}
/**
Set the specified string from the history as the current buffer. Do
not modify prefix_width.
Set the specified string as the current buffer.
*/
static void set_command_line_and_position(const wcstring &new_str, size_t pos)
{
@ -2462,6 +2623,11 @@ void reader_set_allow_autosuggesting(bool flag)
data->allow_autosuggestion = flag;
}
void reader_set_expand_abbreviations(bool flag)
{
data->expand_abbreviations = flag;
}
void reader_set_complete_function(complete_function_t f)
{
data->complete_func = f;
@ -2712,6 +2878,7 @@ static int read_i(void)
reader_set_highlight_function(&highlight_shell);
reader_set_test_function(&reader_shell_test);
reader_set_allow_autosuggesting(true);
reader_set_expand_abbreviations(true);
reader_import_history_if_necessary();
parser_t &parser = parser_t::principal_parser();
@ -2851,7 +3018,6 @@ const wchar_t *reader_readline(void)
data->search_buff.clear();
data->search_mode = NO_SEARCH;
exec_prompt();
reader_super_highlight_me_plenty(data->buff_pos);
@ -3261,7 +3427,21 @@ const wchar_t *reader_readline(void)
}
}
switch (data->test_func(data->command_line.c_str()))
/* See if this command is valid */
int command_test_result = data->test_func(data->command_line.c_str());
if (command_test_result == 0 || command_test_result == PARSER_TEST_INCOMPLETE)
{
/* This command is valid, but an abbreviation may make it invalid. If so, we will have to test again. */
bool abbreviation_expanded = data->expand_abbreviation_as_necessary();
if (abbreviation_expanded)
{
/* It's our reponsibility to rehighlight and repaint. But everything we do below triggers a repaint. */
reader_super_highlight_me_plenty(data->buff_pos);
command_test_result = data->test_func(data->command_line.c_str());
}
}
switch (command_test_result)
{
case 0:
@ -3597,9 +3777,14 @@ const wchar_t *reader_readline(void)
/* Other, if a normal character, we add it to the command */
default:
{
if ((!wchar_private(c)) && (((c>31) || (c==L'\n'))&& (c != 127)))
{
/* Expand abbreviations on space */
if (c == L' ')
{
data->expand_abbreviation_as_necessary();
}
/* Regular character */
insert_char(c);
}
@ -3633,10 +3818,7 @@ const wchar_t *reader_readline(void)
}
writestr(L"\n");
/*
if( comp )
halloc_free( comp );
*/
if (!reader_exit_forced())
{
if (tcsetattr(0,TCSANOW,&old_modes)) /* return to previous mode */

View file

@ -204,6 +204,10 @@ void reader_set_right_prompt(const wcstring &prompt);
/** Sets whether autosuggesting is allowed. */
void reader_set_allow_autosuggesting(bool flag);
/** Sets whether abbreviation expansion is performed. */
void reader_set_expand_abbreviations(bool flag);
/** Sets whether the reader should exit on ^C. */
void reader_set_exit_on_interrupt(bool flag);
@ -243,6 +247,9 @@ int reader_search_mode();
/* Given a command line and an autosuggestion, return the string that gets shown to the user. Exposed for testing purposes only. */
wcstring combine_command_and_autosuggestion(const wcstring &cmdline, const wcstring &autosuggestion);
/* Expand abbreviations at the given cursor position. Exposed for testing purposes only. */
bool reader_expand_abbreviation_in_command(const wcstring &cmdline, size_t cursor_pos, wcstring *output);
/* Apply a completion string. Exposed for testing only. */
wcstring completion_apply_to_command_line(const wcstring &val_str, complete_flags_t flags, const wcstring &command_line, size_t *inout_cursor_pos, bool append_only);

View file

@ -0,0 +1,35 @@
function __fish_canto_using_command
set cmd (commandline -opc)
if [ (count $cmd) -gt 1 ]
if [ $argv[1] = $cmd[2] ]
return 0
end
if [ count $argv -gt 2 ]
if [ $argv[2] = $cmd[2] ]
return 0
end
end
end
return 1
end
complete -f -c canto -s h -l help -d 'Show Help'
complete -f -c canto -s v -l version -d 'Show version'
complete -f -c canto -s u -l update -d 'Update before running'
complete -f -c canto -s l -l list -d 'List feeds'
complete -f -c canto -s a -l checkall -d 'Show number of new items'
complete -f -c canto -s n -l checknew -d 'Show number of new items for feed'
complete -f -c canto -n '__fish_canto_using_command -l --checknew' -d 'Feed' -a '(command canto -l)'
complete -c canto -s o -l opml -d 'Print conf as OPML'
complete -c cnato -s i -l import -d 'Import from OPML'
complete -f -c canto -s r -l url -d 'Add feed'
complete -c canto -s D -l dir -d 'Set configuration directory'
complete -c canto -s C -l conf -d 'Set configuration file'
complete -c canto -s L -l log -d 'Set client log file'
complete -c canto -s F -l fdir -d 'Set feed directory'
complete -c canto -s S -l sdir -d 'Set script directory'

View file

@ -41,7 +41,7 @@ complete -c darcs -n '__fish_use_subcommand' -x -a obliterate --description 'Del
complete -c darcs -n '__fish_use_subcommand' -x -a rollback --description 'Record a new patch reversing some recorded changes'
complete -c darcs -n '__fish_use_subcommand' -x -a push --description 'Copy and apply patches from this repository to another one'
complete -c darcs -n '__fish_use_subcommand' -x -a send --description 'Send by email a bundle of one or more patches'
complete -c darcs -n '__fish_use_subcommand' -x -a apply --description 'Apply a patch bundle created by `darcs send''
complete -c darcs -n '__fish_use_subcommand' -x -a apply --description 'Apply a patch bundle created by `darcs send\''
complete -c darcs -n '__fish_use_subcommand' -x -a get --description 'Create a local copy of a repository'
complete -c darcs -n '__fish_use_subcommand' -x -a put --description 'Makes a copy of the repository'
complete -c darcs -n '__fish_use_subcommand' -x -a initialize --description 'Make the current directory a repository'

View file

@ -1,22 +1,14 @@
function __fish_complete_ftp -d 'Complete ftp, pftp' --argument-names ftp
complete -c $ftp -xa "(__fish_print_hostnames)" -d 'Hostname'
tname'
complete -c $ftp -s 4 -d 'Use only IPv4 to contact any host'
host'
complete -c $ftp -s 6 -d 'Use IPv6 only'
only'
complete -c $ftp -s p -d 'Use passive mode for data transfers'
sfers'
complete -c $ftp -s A -d 'Use active mode for data transfers'
sfers'
complete -c $ftp -s i -d 'Turn off interactive prompting during multiple file transfers'
complete -c $ftp -s 4 -d 'Use only IPv4 to contact any host'
complete -c $ftp -s 6 -d 'Use IPv6 only'
complete -c $ftp -s p -d 'Use passive mode for data transfers'
complete -c $ftp -s A -d 'Use active mode for data transfers'
complete -c $ftp -s i -d 'Turn off interactive prompting during multiple file transfers.'
complete -c $ftp -s n -d 'Restrain ftp from attempting "auto-login" upon initial connection'
complete -c $ftp -s e -d 'Disable command editing and history support'
complete -c $ftp -s g -d 'Disable file name globbing'
Disable file name globbing'
m -d 'Do not explicitly bind data and control channels to same interface'
channels to same interface'
v -d 'Verbose. Show all server responses and data transfer stats'
es and data transfer stats'
d -d 'Enable debugging'
complete -c $ftp -s m -d 'Do not explicitly bind data and control channels to same interface'
complete -c $ftp -s v -d 'Verbose. Show all server responses and data transfer stats'
complete -c $ftp -s d -d 'Enable debugging'
end

View file

@ -224,15 +224,17 @@ function __fish_config_interactive -d "Initializations that should be performed
function fish_command_not_found_handler --on-event fish_command_not_found
/usr/lib/command-not-found $argv
end
fish_command_not_found_handler $argv
# Ubuntu Feisty places this command in the regular path instead
else if type -p command-not-found > /dev/null 2> /dev/null
function fish_command_not_found_handler --on-event fish_command_not_found
command-not-found $argv
end
# Use standard fish command not found handler otherwise
else
# Ubuntu Feisty places this command in the regular path instead
if type -p command-not-found > /dev/null 2> /dev/null
function fish_command_not_found_handler --on-event fish_command_not_found
command-not-found $argv
end
fish_command_not_found_handler $argv
function fish_command_not_found_handler --on-event fish_command_not_found
echo fish: Unknown command "'$argv'" >&2
end
end
fish_command_not_found_handler $argv
end
end

View file

@ -75,6 +75,8 @@
# 'upstream_equal', 'upstream_behind', 'upstream_ahead', and
# 'upstream_diverged'.
set -g ___fish_git_prompt_status_order stagedstate invalidstate dirtystate untrackedfiles
function __fish_git_prompt_show_upstream --description "Helper function for __fish_git_prompt"
# Ask git-config for some config options
set -l svn_remote
@ -82,6 +84,7 @@ function __fish_git_prompt_show_upstream --description "Helper function for __fi
set -l upstream git
set -l legacy
set -l verbose
set -l informative
set -l svn_url_pattern
set -l show_upstream $__fish_git_prompt_showupstream
git config -z --get-regexp '^(svn-remote\..*\.url|bash\.showUpstream)$' ^/dev/null | tr '\0\n' '\n ' | while read -l key value
@ -109,6 +112,8 @@ function __fish_git_prompt_show_upstream --description "Helper function for __fi
set upstream $option
case verbose
set verbose 1
case informative
set informative 1
case legacy
set legacy 1
end
@ -176,30 +181,42 @@ function __fish_git_prompt_show_upstream --description "Helper function for __fi
end
# calculate the result
if test -z "$verbose"
switch "$count"
case '' # no upstream
case "0 0" # equal to upstream
echo $___fish_git_prompt_char_upstream_equal
case "0 *" # ahead of upstream
echo $___fish_git_prompt_char_upstream_ahead
case "* 0" # behind upstream
echo $___fish_git_prompt_char_upstream_behind
case '*' # diverged from upstream
echo $___fish_git_prompt_char_upstream_diverged
end
else
if test -n "$verbose"
echo $count | read -l behind ahead
switch "$count"
case '' # no upstream
case "0 0" # equal to upstream
echo " $___fish_git_prompt_char_upstream_equal"
echo "$___fish_git_prompt_char_upstream_prefix$___fish_git_prompt_char_upstream_equal"
case "0 *" # ahead of upstream
echo " $___fish_git_prompt_char_upstream_ahead$ahead"
echo "$___fish_git_prompt_char_upstream_prefix$___fish_git_prompt_char_upstream_ahead$ahead"
case "* 0" # behind upstream
echo " $___fish_git_prompt_char_upstream_behind$behind"
echo "$___fish_git_prompt_char_upstream_prefix$___fish_git_prompt_char_upstream_behind$behind"
case '*' # diverged from upstream
echo " $__fish_git_prompt_char_upstream_diverged$ahead-$behind"
echo "$___fish_git_prompt_char_upstream_prefix$___fish_git_prompt_char_upstream_diverged$ahead-$behind"
end
else if test -n informative
echo $count | read -l behind ahead
switch "$count"
case '' # no upstream
case "0 0" # equal to upstream
case "0 *" # ahead of upstream
echo "$___fish_git_prompt_char_upstream_prefix$___fish_git_prompt_char_upstream_ahead$ahead"
case "* 0" # behind upstream
echo "$___fish_git_prompt_char_upstream_prefix$___fish_git_prompt_char_upstream_behind$behind"
case '*' # diverged from upstream
echo "$___fish_git_prompt_char_upstream_prefix$___fish_git_prompt_char_upstream_ahead$ahead$___fish_git_prompt_char_upstream_behind$behind"
end
else
switch "$count"
case '' # no upstream
case "0 0" # equal to upstream
echo "$___fish_git_prompt_char_upstream_prefix$___fish_git_prompt_char_upstream_equal"
case "0 *" # ahead of upstream
echo "$___fish_git_prompt_char_upstream_prefix$___fish_git_prompt_char_upstream_ahead$ahead"
case "* 0" # behind upstream
echo "$___fish_git_prompt_char_upstream_prefix$___fish_git_prompt_char_upstream_behind$behind"
case '*' # diverged from upstream
echo "$___fish_git_prompt_char_upstream_prefix$___fish_git_prompt_char_upstream_diverged$ahead-$behind"
end
end
end
@ -216,32 +233,39 @@ function __fish_git_prompt --description "Prompt function for Git"
set -l u #untracked
set -l c (__fish_git_prompt_current_branch_bare)
set -l p #upstream
set -l informative_status
__fish_git_prompt_validate_chars
if test "true" = (git rev-parse --is-inside-work-tree ^/dev/null)
if test -n "$__fish_git_prompt_showdirtystate"
set -l config (git config --bool bash.showDirtyState)
if test "$config" != "false"
set w (__fish_git_prompt_dirty)
set i (__fish_git_prompt_staged)
if test -n "$__fish_git_prompt_show_informative_status"
set informative_status "|"(__fish_git_prompt_informative_status)
else
if test -n "$__fish_git_prompt_showdirtystate"
set -l config (git config --bool bash.showDirtyState)
if test "$config" != "false"
set w (__fish_git_prompt_dirty)
set i (__fish_git_prompt_staged)
end
end
end
if test -n "$__fish_git_prompt_showstashstate"
git rev-parse --verify refs/stash >/dev/null ^&1; and set s $___fish_git_prompt_char_stashstate
end
if test -n "$__fish_git_prompt_showstashstate"
git rev-parse --verify refs/stash >/dev/null ^&1; and set s $___fish_git_prompt_char_stashstate
end
if test -n "$__fish_git_prompt_showuntrackedfiles"
set -l files (git ls-files --others --exclude-standard)
if test -n "$files"
set u $___fish_git_prompt_char_untrackedfiles
if test -n "$__fish_git_prompt_showuntrackedfiles"
set -l files (git ls-files --others --exclude-standard)
if test -n "$files"
set u $___fish_git_prompt_char_untrackedfiles
end
end
end
if test -n "$__fish_git_prompt_showupstream"
set p (__fish_git_prompt_show_upstream)
end
end
__fish_git_prompt_validate_colors
@ -282,7 +306,7 @@ function __fish_git_prompt --description "Prompt function for Git"
set format " (%s)"
end
printf "%s$format%s" "$___fish_git_prompt_color_prefix" "$___fish_git_prompt_color_prefix_done$c$b$f$r$p$___fish_git_prompt_color_suffix" "$___git_ps_color_suffix_done"
printf "%s$format%s" "$___fish_git_prompt_color_prefix" "$___fish_git_prompt_color_prefix_done$c$b$f$r$p$informative_status$___fish_git_prompt_color_suffix" "$___git_ps_color_suffix_done"
end
### helper functions
@ -310,6 +334,46 @@ function __fish_git_prompt_dirty --description "__fish_git_prompt helper, tells
echo $dirty
end
function __fish_git_prompt_informative_status
set -l changedFiles (git diff --name-status | cut -c 1-2)
set -l stagedFiles (git diff --staged --name-status | cut -c 1-2)
set -l dirtystate (math (count $changedFiles) - (count (echo $changedFiles | grep "U")))
set -l invalidstate (count (echo $stagedFiles | grep "U"))
set -l stagedstate (math (count $stagedFiles) - $invalidstate)
set -l untrackedfiles (count (git ls-files --others --exclude-standard))
set -l info
if [ (math $dirtystate + $invalidstate + $stagedstate + $untrackedfiles) = 0 ]
set info $___fish_git_prompt_color_cleanstate$___fish_git_prompt_char_cleanstate$___fish_git_prompt_color_cleanstate_done
else
for i in $___fish_git_prompt_status_order
if [ $$i != "0" ]
set -l color_var ___fish_git_prompt_color_$i
set -l color_done_var ___fish_git_prompt_color_$i
set -l symbol_var ___fish_git_prompt_char_$i
set -l color $$color_var
set -l color_done $$color_done_var
set -l symbol $$symbol_var
set -l count
if not set -q __fish_git_prompt_hide_$i
set count $$i
end
set info "$info$color$symbol$count$color_done"
end
end
end
echo $info
end
function __fish_git_prompt_current_branch_bare --description "__fish_git_prompt helper, tells wheter or not the current branch is bare"
set -l bare
@ -388,145 +452,81 @@ function __fish_git_prompt_git_dir --description "__fish_git_prompt helper, retu
echo (git rev-parse --git-dir ^/dev/null)
end
function __fish_git_prompt_set_char
set -l user_variable_name "$argv[1]"
set -l char $argv[2]
set -l user_variable $$user_variable_name
set -l variable _$user_variable_name
set -l variable_done "$variable"_done
if not set -q $variable
set -g $variable (set -q $user_variable_name; and echo $user_variable; or echo $char)
end
end
function __fish_git_prompt_validate_chars --description "__fish_git_prompt helper, checks char variables"
if not set -q ___fish_git_prompt_char_dirtystate
set -g ___fish_git_prompt_char_dirtystate (set -q __fish_git_prompt_char_dirtystate; and echo $__fish_git_prompt_char_dirtystate; or echo '*')
__fish_git_prompt_set_char __fish_git_prompt_char_cleanstate '.'
__fish_git_prompt_set_char __fish_git_prompt_char_dirtystate '*'
__fish_git_prompt_set_char __fish_git_prompt_char_stagedstate '+'
__fish_git_prompt_set_char __fish_git_prompt_char_invalidstate '#'
__fish_git_prompt_set_char __fish_git_prompt_char_stashstate '$'
__fish_git_prompt_set_char __fish_git_prompt_char_untrackedfiles '%'
__fish_git_prompt_set_char __fish_git_prompt_char_upstream_equal '='
__fish_git_prompt_set_char __fish_git_prompt_char_upstream_behind '<'
__fish_git_prompt_set_char __fish_git_prompt_char_upstream_ahead '>'
__fish_git_prompt_set_char __fish_git_prompt_char_upstream_diverged '<>'
__fish_git_prompt_set_char __fish_git_prompt_char_upstream_prefix ' '
end
function __fish_git_prompt_set_color
set -l user_variable_name "$argv[1]"
set -l user_variable $$user_variable_name
set -l user_variable_bright
if test (count $user_variable) -eq 2
set user_variable_bright $user_variable[2]
set user_variable $user_variable[1]
end
if not set -q ___fish_git_prompt_char_stagedstate
set -g ___fish_git_prompt_char_stagedstate (set -q __fish_git_prompt_char_stagedstate; and echo $__fish_git_prompt_char_stagedstate; or echo '+')
end
if not set -q ___fish_git_prompt_char_invalidstate
set -g ___fish_git_prompt_char_invalidstate (set -q __fish_git_prompt_char_invalidstate; and echo $__fish_git_prompt_char_invalidstate; or echo '#')
end
if not set -q ___fish_git_prompt_char_stashstate
set -g ___fish_git_prompt_char_stashstate (set -q __fish_git_prompt_char_stashstate; and echo $__fish_git_prompt_char_stashstate; or echo '$')
end
if not set -q ___fish_git_prompt_char_untrackedfiles
set -g ___fish_git_prompt_char_untrackedfiles (set -q __fish_git_prompt_char_untrackedfiles; and echo $__fish_git_prompt_char_untrackedfiles; or echo '%')
end
if not set -q ___fish_git_prompt_char_upstream_equal
set -g ___fish_git_prompt_char_upstream_equal (set -q __fish_git_prompt_char_upstream_equal; and echo $__fish_git_prompt_char_upstream_equal; or echo '=')
end
if not set -q ___fish_git_prompt_char_upstream_behind
set -g ___fish_git_prompt_char_upstream_behind (set -q __fish_git_prompt_char_upstream_behind; and echo $__fish_git_prompt_char_upstream_behind; or echo '<')
end
if not set -q ___fish_git_prompt_char_upstream_ahead
set -g ___fish_git_prompt_char_upstream_ahead (set -q __fish_git_prompt_char_upstream_ahead; and echo $__fish_git_prompt_char_upstream_ahead; or echo '>')
end
if not set -q ___fish_git_prompt_char_upstream_diverged
set -g ___fish_git_prompt_char_upstream_diverged (set -q __fish_git_prompt_char_upstream_diverged; and echo $__fish_git_prompt_char_upstream_diverged; or echo '<>')
set -l variable _$user_variable_name
set -l variable_done "$variable"_done
if not set -q $variable
if test -n "$user_variable"
if test -n "$user_variable_bright"
set -g $variable (set_color -o $user_variable)
else
set -g $variable (set_color $user_variable)
end
set -g $variable_done (set_color normal)
else
set -g $variable ''
set -g $variable_done ''
end
end
end
function __fish_git_prompt_validate_colors --description "__fish_git_prompt helper, checks color variables"
if not set -q ___fish_git_prompt_color
if test -n "$__fish_git_prompt_color"
set -g ___fish_git_prompt_color (set_color $__fish_git_prompt_color)
set -g ___fish_git_prompt_color_done (set_color normal)
else
set -g ___fish_git_prompt_color ''
set -g ___fish_git_prompt_color_done ''
end
end
if not set -q ___fish_git_prompt_color_prefix
if test -n "$__fish_git_prompt_color_prefix"
set -g ___fish_git_prompt_color_prefix (set_color $__fish_git_prompt_color_prefix)
set -g ___fish_git_prompt_color_prefix_done (set_color normal)
else
set -g ___fish_git_prompt_color_prefix $___fish_git_prompt_color
set -g ___fish_git_prompt_color_prefix_done $___fish_git_prompt_color_done
end
end
if not set -q ___fish_git_prompt_color_suffix
if test -n "$__fish_git_prompt_color_suffix"
set -g ___fish_git_prompt_color_suffix (set_color $__fish_git_prompt_color_suffix)
set -g ___fish_git_prompt_color_suffix_done (set_color normal)
else
set -g ___fish_git_prompt_color_suffix $___fish_git_prompt_color
set -g ___fish_git_prompt_color_suffix_done $___fish_git_prompt_color_done
end
end
if not set -q ___fish_git_prompt_color_bare
if test -n "$__fish_git_prompt_color_bare"
set -g ___fish_git_prompt_color_bare (set_color $__fish_git_prompt_color_bare)
set -g ___fish_git_prompt_color_bare_done (set_color normal)
else
set -g ___fish_git_prompt_color_bare $___fish_git_prompt_color
set -g ___fish_git_prompt_color_bare_done $___fish_git_prompt_color_done
end
end
if not set -q ___fish_git_prompt_color_merging
if test -n "$__fish_git_prompt_color_merging"
set -g ___fish_git_prompt_color_merging (set_color $__fish_git_prompt_color_merging)
set -g ___fish_git_prompt_color_merging_done (set_color normal)
else
set -g ___fish_git_prompt_color_merging $___fish_git_prompt_color
set -g ___fish_git_prompt_color_merging_done $___fish_git_prompt_color_done
end
end
if not set -q ___fish_git_prompt_color_branch
if test -n "$__fish_git_prompt_color_branch"
set -g ___fish_git_prompt_color_branch (set_color $__fish_git_prompt_color_branch)
set -g ___fish_git_prompt_color_branch_done (set_color normal)
else
set -g ___fish_git_prompt_color_branch $___fish_git_prompt_color
set -g ___fish_git_prompt_color_branch_done $___fish_git_prompt_color_done
end
end
if not set -q ___fish_git_prompt_color_dirtystate
if test -n "$__fish_git_prompt_color_dirtystate"
set -g ___fish_git_prompt_color_dirtystate (set_color $__fish_git_prompt_color_dirtystate)
set -g ___fish_git_prompt_color_dirtystate_done (set_color normal)
else
set -g ___fish_git_prompt_color_dirtystate $___fish_git_prompt_color
set -g ___fish_git_prompt_color_dirtystate_done $___fish_git_prompt_color_done
end
end
if not set -q ___fish_git_prompt_color_stagedstate
if test -n "$__fish_git_prompt_color_stagedstate"
set -g ___fish_git_prompt_color_stagedstate (set_color $__fish_git_prompt_color_stagedstate)
set -g ___fish_git_prompt_color_stagedstate_done (set_color normal)
else
set -g ___fish_git_prompt_color_stagedstate $___fish_git_prompt_color
set -g ___fish_git_prompt_color_stagedstate_done $___fish_git_prompt_color_done
end
end
if not set -q ___fish_git_prompt_color_invalidstate
if test -n "$__fish_git_prompt_color_invalidstate"
set -g ___fish_git_prompt_color_invalidstate (set_color $__fish_git_prompt_color_invalidstate)
set -g ___fish_git_prompt_color_invalidstate_done (set_color normal)
else
set -g ___fish_git_prompt_color_invalidstate $___fish_git_prompt_color
set -g ___fish_git_prompt_color_invalidstate_done $___fish_git_prompt_color_done
end
end
if not set -q ___fish_git_prompt_color_stashstate
if test -n "$__fish_git_prompt_color_stashstate"
set -g ___fish_git_prompt_color_stashstate (set_color $__fish_git_prompt_color_stashstate)
set -g ___fish_git_prompt_color_stashstate_done (set_color normal)
else
set -g ___fish_git_prompt_color_stashstate $___fish_git_prompt_color
set -g ___fish_git_prompt_color_stashstate_done $___fish_git_prompt_color_done
end
end
if not set -q ___fish_git_prompt_color_untrackedfiles
if test -n "$__fish_git_prompt_color_untrackedfiles"
set -g ___fish_git_prompt_color_untrackedfiles (set_color $__fish_git_prompt_color_untrackedfiles)
set -g ___fish_git_prompt_color_untrackedfiles_done (set_color normal)
else
set -g ___fish_git_prompt_color_untrackedfiles $___fish_git_prompt_color
set -g ___fish_git_prompt_color_untrackedfiles_done $___fish_git_prompt_color_done
end
end
if not set -q ___fish_git_prompt_color_upstream
if test -n "$__fish_git_prompt_color_upstream"
set -g ___fish_git_prompt_color_upstream (set_color $__fish_git_prompt_color_upstream)
set -g ___fish_git_prompt_color_upstream_done (set_color normal)
else
set -g ___fish_git_prompt_color_upstream $___fish_git_prompt_color
set -g ___fish_git_prompt_color_upstream_done $___fish_git_prompt_color_done
end
end
__fish_git_prompt_set_color __fish_git_prompt_color
__fish_git_prompt_set_color __fish_git_prompt_color_prefix
__fish_git_prompt_set_color __fish_git_prompt_color_suffix
__fish_git_prompt_set_color __fish_git_prompt_color_bare
__fish_git_prompt_set_color __fish_git_prompt_color_merging
__fish_git_prompt_set_color __fish_git_prompt_color_branch
__fish_git_prompt_set_color __fish_git_prompt_color_cleanstate
__fish_git_prompt_set_color __fish_git_prompt_color_dirtystate
__fish_git_prompt_set_color __fish_git_prompt_color_stagedstate
__fish_git_prompt_set_color __fish_git_prompt_color_invalidstate
__fish_git_prompt_set_color __fish_git_prompt_color_stashstate
__fish_git_prompt_set_color __fish_git_prompt_color_untrackedfiles
__fish_git_prompt_set_color __fish_git_prompt_color_upstream
end
set -l varargs

View file

@ -59,19 +59,19 @@ def flush_diagnostics(where):
# This maps commands to lists of completions
already_output_completions = {}
def compileAndSearch(regex, input):
def compile_and_search(regex, input):
options_section_regex = re.compile(regex , re.DOTALL)
options_section_matched = re.search( options_section_regex, input)
return options_section_matched
def unquoteDoubleQuotes(data):
def unquote_double_quotes(data):
if (len(data) < 2):
return data
if data[0] == '"' and data[len(data)-1] == '"':
data = data[1:len(data)-1]
return data
def unquoteSingleQuotes(data):
def unquote_single_quotes(data):
if (len(data) < 2):
return data
if data[0] == '`' and data[len(data)-1] == '\'':
@ -188,11 +188,7 @@ def built_command(options, description):
output_complete_command(escaped_cmd, fish_options, truncated_description, built_command_output)
def removeGroffFormatting(data):
# data = data.replace("\fI","")
# data = data.replace("\fP","")
def remove_groff_formatting(data):
data = data.replace("\\fI","")
data = data.replace("\\fP","")
data = data.replace("\\f1","")
@ -217,26 +213,26 @@ def removeGroffFormatting(data):
return data
class ManParser:
def isMyType(self, manpage):
def is_my_type(self, manpage):
return False
def parseManPage(self, manpage):
def parse_man_page(self, manpage):
return False
def name(self):
return "no-name"
class Type1ManParser(ManParser):
def isMyType(self, manpage):
def is_my_type(self, manpage):
# print manpage
options_section_matched = compileAndSearch("\.SH \"OPTIONS\"(.*?)", manpage)
options_section_matched = compile_and_search("\.SH \"OPTIONS\"(.*?)", manpage)
if options_section_matched == None:
return False
else:
return True
def parseManPage(self, manpage):
def parse_man_page(self, manpage):
options_section_regex = re.compile( "\.SH \"OPTIONS\"(.*?)(\.SH|\Z)", re.DOTALL)
options_section_matched = re.search( options_section_regex, manpage)
@ -256,27 +252,22 @@ class Type1ManParser(ManParser):
return False
while (options_matched != None):
# print len(options_matched.groups())
# print options_matched.group()
data = options_matched.group(1)
last_dotpp_index = data.rfind(".PP")
if (last_dotpp_index != -1):
data = data[last_dotpp_index+3:]
data = removeGroffFormatting(data)
data = remove_groff_formatting(data)
data = data.split(".RS 4")
# print data
if (len (data) > 1): #and len(data[1]) <= 300):
optionName = data[0].strip()
if ( optionName.find("-") == -1):
add_diagnostic(optionName + " doesn't contain - ")
# return False
else:
optionName = unquoteDoubleQuotes(optionName)
optionName = unquoteSingleQuotes(optionName)
optionName = unquote_double_quotes(optionName)
optionName = unquote_single_quotes(optionName)
optionDescription = data[1].strip().replace("\n"," ")
# print >> sys.stderr, "Option: ", optionName," Description: ", optionDescription , '\n'
built_command(optionName, optionDescription)
else:
@ -295,7 +286,7 @@ class Type1ManParser(ManParser):
return False
while options_matched != None:
data = options_matched.group(2)
data = removeGroffFormatting(data)
data = remove_groff_formatting(data)
data = data.strip()
data = data.split("\n",1)
if (len(data)>1 and len(data[1].strip())>0): # and len(data[1])<400):
@ -303,10 +294,9 @@ class Type1ManParser(ManParser):
if ( optionName.find("-") == -1):
add_diagnostic(optionName + "doesn't contains -")
else:
optionName = unquoteDoubleQuotes(optionName)
optionName = unquoteSingleQuotes(optionName)
optionName = unquote_double_quotes(optionName)
optionName = unquote_single_quotes(optionName)
optionDescription = data[1].strip().replace("\n"," ")
# print "Option: ", optionName," Description: ", optionDescription , '\n'
built_command(optionName, optionDescription)
else:
add_diagnostic('Unable to split option from description')
@ -330,27 +320,21 @@ class Type1ManParser(ManParser):
while options_matched != None:
data = options_matched.group(1)
# print "Data is : ", data
data = removeGroffFormatting(data)
data = remove_groff_formatting(data)
data = data.strip()
data = data.split("\n",1)
if (len(data)>1 and len(data[1].strip())>0): # and len(data[1])<400):
# print "Data[0] is: ", data[0]
# data = re.sub(trailing_num_regex, "", data)
optionName = re.sub(trailing_num_regex, "", data[0].strip())
if ('-' not in optionName):
add_diagnostic(optionName + " doesn't contain -")
else:
optionName = optionName.strip()
optionName = unquoteDoubleQuotes(optionName)
optionName = unquoteSingleQuotes(optionName)
optionName = unquote_double_quotes(optionName)
optionName = unquote_single_quotes(optionName)
optionDescription = data[1].strip().replace("\n"," ")
# print "Option: ", optionName," Description: ", optionDescription , '\n'
built_command(optionName, optionDescription)
else:
# print data
add_diagnostic('Unable to split option from description')
return False
@ -363,31 +347,21 @@ class Type1ManParser(ManParser):
class Type2ManParser(ManParser):
def isMyType(self, manpage):
options_section_matched = compileAndSearch("\.SH OPTIONS(.*?)", manpage)
def is_my_type(self, manpage):
options_section_matched = compile_and_search("\.SH OPTIONS(.*?)", manpage)
if options_section_matched == None:
return False
else:
return True
def parseManPage(self, manpage):
def parse_man_page(self, manpage):
options_section_regex = re.compile( "\.SH OPTIONS(.*?)(\.SH|\Z)", re.DOTALL)
options_section_matched = re.search( options_section_regex, manpage)
# if (options_section_matched == None):
# print "Falling Back"
# options_section_regex = re.compile( "\.SH OPTIONS(.*?)$", re.DOTALL)
# options_section_matched = re.search( options_section_regex, manpage)
# print manpage
options_section = options_section_matched.group(1)
# print options_section
# print options_section
# sys.exit(1)
# options_parts_regex = re.compile("\.TP(.*?)\.TP", re.DOTALL)
options_parts_regex = re.compile("\.[I|T]P( \d+(\.\d)?i?)?(.*?)\.[I|T]P", re.DOTALL)
# options_parts_regex = re.compile("\.TP(.*?)[(\.TP)|(\.SH)]", re.DOTALL)
options_matched = re.search(options_parts_regex, options_section)
add_diagnostic('Command is ' + CMDNAME)
@ -396,56 +370,46 @@ class Type2ManParser(ManParser):
return False
while (options_matched != None):
# print len(options_matched.groups())
data = options_matched.group(3)
data = removeGroffFormatting(data)
data = remove_groff_formatting(data)
data = data.strip()
data = data.split("\n",1)
# print >> sys.stderr, data
if (len(data)>1 and len(data[1].strip())>0): # and len(data[1])<400):
optionName = data[0].strip()
if '-' not in optionName:
add_diagnostic(optionName + " doesn't contain -")
else:
optionName = unquoteDoubleQuotes(optionName)
optionName = unquoteSingleQuotes(optionName)
optionName = unquote_double_quotes(optionName)
optionName = unquote_single_quotes(optionName)
optionDescription = data[1].strip().replace("\n"," ")
# print "Option: ", optionName," Description: ", optionDescription , '\n'
built_command(optionName, optionDescription)
else:
# print >> sys.stderr, data
add_diagnostic('Unable to split option from description')
# return False
options_section = options_section[options_matched.end()-3:]
options_matched = re.search(options_parts_regex, options_section)
def name(self):
return "Type2"
class Type3ManParser(ManParser):
def isMyType(self, manpage):
options_section_matched = compileAndSearch("\.SH DESCRIPTION(.*?)", manpage)
def is_my_type(self, manpage):
options_section_matched = compile_and_search("\.SH DESCRIPTION(.*?)", manpage)
if options_section_matched == None:
return False
else:
return True
def parseManPage(self, manpage):
def parse_man_page(self, manpage):
options_section_regex = re.compile( "\.SH DESCRIPTION(.*?)(\.SH|\Z)", re.DOTALL)
options_section_matched = re.search( options_section_regex, manpage)
options_section = options_section_matched.group(1)
# print options_section
# sys.exit(1)
options_parts_regex = re.compile("\.TP(.*?)\.TP", re.DOTALL)
options_matched = re.search(options_parts_regex, options_section)
add_diagnostic('Command is ' + CMDNAME)
@ -455,10 +419,9 @@ class Type3ManParser(ManParser):
return False
while (options_matched != None):
# print len(options_matched.groups())
data = options_matched.group(1)
data = removeGroffFormatting(data)
data = remove_groff_formatting(data)
data = data.strip()
data = data.split("\n",1)
@ -467,10 +430,9 @@ class Type3ManParser(ManParser):
if ( optionName.find("-") == -1):
add_diagnostic(optionName + "doesn't contain -")
else:
optionName = unquoteDoubleQuotes(optionName)
optionName = unquoteSingleQuotes(optionName)
optionName = unquote_double_quotes(optionName)
optionName = unquote_single_quotes(optionName)
optionDescription = data[1].strip().replace("\n"," ")
# print >> sys.stderr, "Option: ", optionName," Description: ", optionDescription , '\n'
built_command(optionName, optionDescription)
else:
@ -481,27 +443,24 @@ class Type3ManParser(ManParser):
options_matched = re.search(options_parts_regex, options_section)
def name(self):
return "Type3"
class Type4ManParser(ManParser):
def isMyType(self, manpage):
options_section_matched = compileAndSearch("\.SH FUNCTION LETTERS(.*?)", manpage)
def is_my_type(self, manpage):
options_section_matched = compile_and_search("\.SH FUNCTION LETTERS(.*?)", manpage)
if options_section_matched == None:
return False
else:
return True
def parseManPage(self, manpage):
def parse_man_page(self, manpage):
options_section_regex = re.compile( "\.SH FUNCTION LETTERS(.*?)(\.SH|\Z)", re.DOTALL)
options_section_matched = re.search( options_section_regex, manpage)
options_section = options_section_matched.group(1)
# print options_section
# sys.exit(1)
options_parts_regex = re.compile("\.TP(.*?)\.TP", re.DOTALL)
options_matched = re.search(options_parts_regex, options_section)
add_diagnostic('Command is ' + CMDNAME)
@ -511,10 +470,9 @@ class Type4ManParser(ManParser):
return False
while (options_matched != None):
# print len(options_matched.groups())
data = options_matched.group(1)
data = removeGroffFormatting(data)
data = remove_groff_formatting(data)
data = data.strip()
data = data.split("\n",1)
@ -523,10 +481,9 @@ class Type4ManParser(ManParser):
if ( optionName.find("-") == -1):
add_diagnostic(optionName + " doesn't contain - ")
else:
optionName = unquoteDoubleQuotes(optionName)
optionName = unquoteSingleQuotes(optionName)
optionName = unquote_double_quotes(optionName)
optionName = unquote_single_quotes(optionName)
optionDescription = data[1].strip().replace("\n"," ")
# print "Option: ", optionName," Description: ", optionDescription , '\n'
built_command(optionName, optionDescription)
else:
@ -542,8 +499,8 @@ class Type4ManParser(ManParser):
return "Type4"
class TypeDarwinManParser(ManParser):
def isMyType(self, manpage):
options_section_matched = compileAndSearch("\.S[hH] DESCRIPTION", manpage)
def is_my_type(self, manpage):
options_section_matched = compile_and_search("\.S[hH] DESCRIPTION", manpage)
return options_section_matched != None
def trim_groff(self, line):
@ -572,9 +529,6 @@ class TypeDarwinManParser(ManParser):
line = line[3:]
return result
# Replace some groff escapes. There's a lot we don't bother to handle.
def groff_replace_escapes(self, line):
line = line.replace('.Nm', CMDNAME)
@ -586,7 +540,7 @@ class TypeDarwinManParser(ManParser):
def is_option(self, line):
return line.startswith('.It Fl')
def parseManPage(self, manpage):
def parse_man_page(self, manpage):
got_something = False
lines = manpage.splitlines()
# Discard lines until we get to ".sh Description"
@ -626,9 +580,6 @@ class TypeDarwinManParser(ManParser):
desc_lines.append(line)
desc = ' '.join(desc_lines)
# print "name: ", name
# print "desc: ", desc
if name == '-':
# Skip double -- arguments
continue
@ -647,7 +598,7 @@ class TypeDarwinManParser(ManParser):
class TypeDeroffManParser(ManParser):
def isMyType(self, manpage):
def is_my_type(self, manpage):
return True # We're optimists
def is_option(self, line):
@ -656,7 +607,7 @@ class TypeDeroffManParser(ManParser):
def could_be_description(self, line):
return len(line) > 0 and not line.startswith('-')
def parseManPage(self, manpage):
def parse_man_page(self, manpage):
d = Deroffer()
d.deroff(manpage)
output = d.get_output()
@ -697,7 +648,6 @@ class TypeDeroffManParser(ManParser):
return got_something
def name(self):
return "Deroffing man parser"
@ -800,7 +750,7 @@ def parse_manpage_at_path(manpage_path, output_directory):
parsers = [TypeDeroffManParser()]
else:
parsers = [Type1ManParser(), Type2ManParser(), Type4ManParser(), Type3ManParser(), TypeDarwinManParser(), TypeDeroffManParser()]
parsersToTry = [p for p in parsers if p.isMyType(manpage)]
parsersToTry = [p for p in parsers if p.is_my_type(manpage)]
success = False
if not parsersToTry:
@ -810,7 +760,7 @@ def parse_manpage_at_path(manpage_path, output_directory):
parser_name = parser.name()
add_diagnostic('Trying parser ' + parser_name)
diagnostic_indent += 1
success = parser.parseManPage(manpage)
success = parser.parse_man_page(manpage)
diagnostic_indent -= 1
# Make sure empty files aren't reported as success
if not built_command_output:

View file

@ -0,0 +1,47 @@
# name: Informative Git Prompt
# author: Mariusz Smykula <mariuszs at gmail.com>
set -g __fish_git_prompt_show_informative_status 1
set -g __fish_git_prompt_hide_untrackedfiles 1
set -g __fish_git_prompt_color_branch magenta bold
set -g __fish_git_prompt_showupstream "informative"
set -g __fish_git_prompt_char_upstream_ahead "↑"
set -g __fish_git_prompt_char_upstream_behind "↓"
set -g __fish_git_prompt_char_upstream_prefix ""
set -g __fish_git_prompt_char_stagedstate "●"
set -g __fish_git_prompt_char_dirtystate "✚"
set -g __fish_git_prompt_char_untrackedfiles "…"
set -g __fish_git_prompt_char_conflictedstate "✖"
set -g __fish_git_prompt_char_cleanstate "✔"
set -g __fish_git_prompt_color_dirtystate blue
set -g __fish_git_prompt_color_stagedstate yellow
set -g __fish_git_prompt_color_invalidstate red
set -g __fish_git_prompt_color_untrackedfiles $fish_color_normal
set -g __fish_git_prompt_color_cleanstate green bold
function fish_prompt --description 'Write out the prompt'
set -l last_status $status
if not set -q __fish_prompt_normal
set -g __fish_prompt_normal (set_color normal)
end
# PWD
set_color $fish_color_cwd
echo -n (prompt_pwd)
set_color normal
printf '%s ' (__fish_git_prompt)
if not test $last_status -eq 0
set_color $fish_color_error
end
echo -n '$ '
end

View file

@ -75,7 +75,6 @@ def better_color(c1, c2):
if c1 in named_colors: return c2
return c1
def parse_color(color_str):
""" A basic function to parse a color string, for example, 'red' '--bold' """
comps = color_str.split(' ')
@ -98,7 +97,6 @@ def parse_color(color_str):
return [color, background_color, bold, underline]
def parse_bool(val):
val = val.lower()
if val.startswith('f') or val.startswith('0'): return False
@ -229,11 +227,11 @@ def ansi_to_html(val):
# Clean up empty spans, the nasty way
idx = len(result) - 1
while idx >= 1:
if result[idx] == '</span>' and result[idx-1].startswith('<span'):
# Empty span, delete these two
result[idx-1:idx+1] = []
idx = idx - 1
idx = idx - 1
if result[idx] == '</span>' and result[idx-1].startswith('<span'):
# Empty span, delete these two
result[idx-1:idx+1] = []
idx = idx - 1
idx = idx - 1
return ''.join(result)
@ -579,26 +577,26 @@ class FishConfigHTTPRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
fish_bin_dir = os.environ.get('__fish_bin_dir')
fish_bin_path = None
if not fish_bin_dir:
print('The __fish_bin_dir environment variable is not set. Looking in $PATH...')
# distutils.spawn is terribly broken, because it looks in wd before PATH,
# and doesn't actually validate that the file is even executabl
for p in os.environ['PATH'].split(os.pathsep):
proposed_path = os.path.join(p, 'fish')
if os.access(proposed_path, os.X_OK):
fish_bin_path = proposed_path
break
if not fish_bin_path:
print("fish could not be found. Is fish installed correctly?")
sys.exit(-1)
else:
print("fish found at '%s'" % fish_bin_path)
print('The __fish_bin_dir environment variable is not set. Looking in $PATH...')
# distutils.spawn is terribly broken, because it looks in wd before PATH,
# and doesn't actually validate that the file is even executabl
for p in os.environ['PATH'].split(os.pathsep):
proposed_path = os.path.join(p, 'fish')
if os.access(proposed_path, os.X_OK):
fish_bin_path = proposed_path
break
if not fish_bin_path:
print("fish could not be found. Is fish installed correctly?")
sys.exit(-1)
else:
print("fish found at '%s'" % fish_bin_path)
else:
fish_bin_path = os.path.join(fish_bin_dir, 'fish')
fish_bin_path = os.path.join(fish_bin_dir, 'fish')
if not os.access(fish_bin_path, os.X_OK):
print("fish could not be executed at path '%s'. Is fish installed correctly?" % fish_bin_path)
sys.exit(-1)
print("fish could not be executed at path '%s'. Is fish installed correctly?" % fish_bin_path)
sys.exit(-1)
FISH_BIN_PATH = fish_bin_path
# We want to show the demo prompts in the directory from which this was invoked,
@ -646,15 +644,15 @@ webbrowser.open(url)
# Select on stdin and httpd
stdin_no = sys.stdin.fileno()
try:
while True:
ready_read = select.select([sys.stdin.fileno(), httpd.fileno()], [], [])
if ready_read[0][0] < 1:
print("Shutting down.")
# Consume the newline so it doesn't get printed by the caller
sys.stdin.readline()
break
else:
httpd.handle_request()
while True:
ready_read = select.select([sys.stdin.fileno(), httpd.fileno()], [], [])
if ready_read[0][0] < 1:
print("Shutting down.")
# Consume the newline so it doesn't get printed by the caller
sys.stdin.readline()
break
else:
httpd.handle_request()
except KeyboardInterrupt:
print("\nShutting down.")
print("\nShutting down.")