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'; wc = L'\b';
break; break;
case L'e': case L'e':
wc = L'\e'; wc = L'\x1B';
break; break;
case L'f': case L'f':
wc = 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_highlight_function(&highlight_shell);
reader_set_test_function(&reader_shell_test); 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_allow_autosuggesting(false);
reader_set_expand_abbreviations(false);
reader_set_exit_on_interrupt(true); reader_set_exit_on_interrupt(true);
reader_set_buffer(commandline, wcslen(commandline)); reader_set_buffer(commandline, wcslen(commandline));

View file

@ -26,6 +26,7 @@
\a = alert (bell) \a = alert (bell)
\b = backspace \b = backspace
\c = produce no further output \c = produce no further output
\e = escape
\f = form feed \f = form feed
\n = new line \n = new line
\r = carriage return \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. */ case L'c': /* Cancel the rest of the output. */
this->early_exit = true; this->early_exit = true;
break; break;
case L'e': /* Escape */
this->append_output(L'\x1B');
break;
case L'f': /* Form feed. */ case L'f': /* Form feed. */
this->append_output(L'\f'); this->append_output(L'\f');
break; 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); esc_value = esc_value * 16 + hex_to_bin(*p);
if (esc_length == 0) if (esc_length == 0)
this->fatal_error(_(L"missing hexadecimal number in escape")); 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)) 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. */ 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) 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); 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++); print_esc_char(*p++);
}
else if (*p == L'u' || *p == L'U') else if (*p == L'u' || *p == L'U')
{ {
wchar_t esc_char = *p; 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 /* Print the text in FORMAT, using ARGV (with ARGC elements) for
arguments to any `%' directives. arguments to any `%' directives.
Return the number of elements of ARGV used. */ 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; break;
} }
ok['a'] = ok['A'] = ok['c'] = ok['d'] = ok['e'] = ok['E'] = modify_allowed_format_specifiers(ok, "aAcdeEfFgGiosuxX", true);
ok['f'] = ok['F'] = ok['g'] = ok['G'] = ok['i'] = ok['o'] =
ok['s'] = ok['u'] = ok['x'] = ok['X'] = true;
for (;; f++, direc_length++) 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'I':
case L'\'': case L'\'':
ok['a'] = ok['A'] = ok['c'] = ok['e'] = ok['E'] = modify_allowed_format_specifiers(ok, "aAceEosxX", false);
ok['o'] = ok['s'] = ok['x'] = ok['X'] = false;
break; break;
case '-': case '-':
case '+': case '+':
case ' ': case ' ':
break; break;
case L'#': case L'#':
ok['c'] = ok['d'] = ok['i'] = ok['s'] = ok['u'] = false; modify_allowed_format_specifiers(ok, "cdisu", false);
break; break;
case '0': case '0':
ok['c'] = ok['s'] = false; modify_allowed_format_specifiers(ok, "cs", false);
break; break;
default: default:
goto no_more_flag_characters; goto no_more_flag_characters;
@ -679,7 +692,7 @@ no_more_flag_characters:
{ {
++f; ++f;
++direc_length; ++direc_length;
ok['c'] = false; modify_allowed_format_specifiers(ok, "c", false);
if (*f == L'*') if (*f == L'*')
{ {
++f; ++f;

View file

@ -137,7 +137,6 @@ struct env_node_t
class variable_entry_t class variable_entry_t
{ {
bool exportv; /**< Whether the variable should be exported */
wcstring value; /**< Value of the variable */ 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(); const wchar_t * const in = input.c_str();
int parse_ret; int parse_ret;
switch (parse_ret = parse_util_locate_cmdsubst(in, switch (parse_ret = parse_util_locate_cmdsubst(in, &paran_begin, &paran_end, false))
&paran_begin,
&paran_end,
0))
{ {
case -1: case -1:
parser.error(SYNTAX_ERROR, parser.error(SYNTAX_ERROR,
@ -1628,10 +1625,7 @@ int expand_string(const wcstring &input, std::vector<completion_t> &output, expa
{ {
wchar_t *begin, *end; wchar_t *begin, *end;
if (parse_util_locate_cmdsubst(input.c_str(), if (parse_util_locate_cmdsubst(input.c_str(), &begin, &end, true) != 0)
&begin,
&end,
1) != 0)
{ {
parser.error(CMDSUBST_ERROR, -1, L"Command substitutions not allowed"); parser.error(CMDSUBST_ERROR, -1, L"Command substitutions not allowed");
return EXPAND_ERROR; return EXPAND_ERROR;
@ -1939,3 +1933,42 @@ bool fish_openSUSE_dbus_hack_hack_hack_hack(std::vector<completion_t> *args)
} }
return result; 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); 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 */ /* Terrible hacks */
bool fish_xdm_login_hack_hack_hack_hack(std::vector<std::string> *cmds, int argc, const char * const *argv); 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); 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; 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; extern int g_fork_count;
int main(int argc, char **argv) int main(int argc, char **argv)
{ {

View file

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

View file

@ -62,6 +62,7 @@
#include "highlight.h" #include "highlight.h"
#include "parse_tree.h" #include "parse_tree.h"
#include "parse_exec.h" #include "parse_exec.h"
#include "parse_util.h"
/** /**
The number of tests to run 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 class lru_node_test_t : public lru_node_t
{ {
public: 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__); 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 */ /** Test path functions */
static void test_path() static void test_path()
{ {
@ -1771,9 +1853,11 @@ int main(int argc, char **argv)
test_tok(); test_tok();
test_fork(); test_fork();
test_parser(); test_parser();
test_utils();
test_lru(); test_lru();
test_expand(); test_expand();
test_fuzzy_match(); test_fuzzy_match();
test_abbreviations();
test_test(); test_test();
test_path(); test_path();
test_word_motion(); 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) if (! is_cmd && use_function)
is_cmd = function_exists_no_autoload(cmd, vars); is_cmd = function_exists_no_autoload(cmd, vars);
if (! is_cmd)
is_cmd = expand_abbreviation(cmd, NULL);
/* /*
Moving on to expensive tests 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); 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(); const wcstring working_directory = env_get_pwd_slash();
/* Tokenize the string */ /* Tokenize the string */
@ -1335,7 +1338,7 @@ void highlight_shell(const wcstring &buff, std::vector<int> &color, size_t pos,
{ {
wchar_t *begin, *end; 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; 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, int parse_util_locate_cmdsubst(const wchar_t *in, wchar_t **begin, wchar_t **end, bool allow_incomplete)
wchar_t **begin,
wchar_t **end,
int allow_incomplete)
{ {
wchar_t *pos; wchar_t *pos;
wchar_t prev=0; wchar_t prev=0;
@ -243,73 +240,57 @@ int parse_util_locate_cmdsubst(const wchar_t *in,
return 1; 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; const wchar_t * const cursor = buff + cursor_pos;
wchar_t *pos;
const wchar_t *cursor = buff + cursor_pos;
CHECK(buff,); CHECK(buff,);
if (a) const size_t bufflen = wcslen(buff);
{ assert(cursor_pos <= bufflen);
*a = (wchar_t *)buff;
}
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); wchar_t *begin = NULL, *end = NULL;
} if (parse_util_locate_cmdsubst(pos, &begin, &end, true) <= 0)
pos = (wchar_t *)buff;
while (1)
{ {
if (parse_util_locate_cmdsubst(pos, /* No subshell found, all done */
&begin,
&end,
1) <= 0)
{
/*
No subshell found
*/
break; 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++; begin++;
ap = begin;
if (a) bp = end;
{ pos = begin + 1;
*a = begin;
} }
else if (begin >= cursor)
if (b)
{ {
*b = end; /* This command substitution starts at or after the cursor. Since it was the first command substitution in the string, we're done. */
}
break; break;
} }
else
if (!*end)
{ {
break; /* This command substitution ends before the cursor. Skip it. */
} assert(end < cursor);
pos = end + 1; 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; const wchar_t *begin, *end;
long pos; long pos;
wchar_t *buffcpy;
const wchar_t *a = NULL, *b = NULL, *pa = NULL, *pb = NULL; 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 >= begin);
assert(end <= (buff+wcslen(buff))); assert(end <= (buff+wcslen(buff)));
buffcpy = wcsndup(begin, end-begin); const wcstring buffcpy = wcstring(begin, end-begin);
if (!buffcpy) tokenizer_t tok(buffcpy.c_str(), TOK_ACCEPT_UNFINISHED | TOK_SQUASH_ERRORS);
{
DIE_MEM();
}
tokenizer_t tok(buffcpy, TOK_ACCEPT_UNFINISHED | TOK_SQUASH_ERRORS);
for (; tok_has_next(&tok); tok_next(&tok)) for (; tok_has_next(&tok); tok_next(&tok))
{ {
size_t tok_begin = tok_get_pos(&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) if (tok_begin)
{ {
*tok_begin = a; *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; const wchar_t * const *arg;
size_t i; size_t i;
for (i=0, arg=argv; i < named_arguments.size(); i++) for (i=0, arg=argv; i < named_arguments.size(); i++)
{ {
env_set(named_arguments.at(i).c_str(), *arg, ENV_LOCAL); 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) if (*arg)
arg++; arg++;
} }
} }
} }
wchar_t *parse_util_unescape_wildcards(const wchar_t *str) 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]); const wchar_t *end = quote_end(&cmd[i]);
//fwprintf( stderr, L"Jump %d\n", end-cmd ); //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]; res = cmd[i];
break; break;

View file

@ -18,14 +18,14 @@
\param in the string to search for subshells \param in the string to search for subshells
\param begin the starting paranthesis of the subshell \param begin the starting paranthesis of the subshell
\param end the ending 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 \return -1 on syntax error, 0 if no subshells exist and 1 on sucess
*/ */
int parse_util_locate_cmdsubst(const wchar_t *in, int parse_util_locate_cmdsubst(const wchar_t *in,
wchar_t **begin, wchar_t **begin,
wchar_t **end, wchar_t **end,
int flags); bool accept_incomplete);
/** /**
Find the beginning and end of the command substitution under the 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 for this, used by other shells like bash
and zsh). and zsh).
*/ */
if (wcschr(cmd, L'=')) if (wcschr(cmd, L'='))
{ {
wchar_t *cpy = wcsdup(cmd); wchar_t *cpy = wcsdup(cmd);
@ -2074,9 +2075,15 @@ int parser_t::parse_job(process_t *p,
} }
else else
{ {
debug(0, /*
_(L"Unknown command '%ls'"), Handle unrecognized commands with standard
cmd?cmd:L"UNKNOWN"); 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; tmp = current_tokenizer_pos;
@ -2088,9 +2095,6 @@ int parser_t::parse_job(process_t *p,
job_set_flag(j, JOB_SKIP, 1); 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); 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, switch (parse_util_locate_cmdsubst(arg_cpy,
&paran_begin, &paran_begin,
&paran_end, &paran_end,
0)) false))
{ {
case -1: case -1:
err=1; err=1;

View file

@ -97,8 +97,8 @@ commence.
#include "iothread.h" #include "iothread.h"
#include "intern.h" #include "intern.h"
#include "path.h" #include "path.h"
#include "parse_util.h" #include "parse_util.h"
#include "parser_keywords.h"
/** /**
Maximum length of prefix string when printing completion Maximum length of prefix string when printing completion
@ -182,6 +182,8 @@ static pthread_key_t generation_count_key;
/* A color is an int */ /* A color is an int */
typedef int color_t; 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 A struct describing the state of the interactive reader. These
states can be stacked, in case reader_readline() calls are states can be stacked, in case reader_readline() calls are
@ -203,6 +205,9 @@ public:
/** When backspacing, we temporarily suppress autosuggestions */ /** When backspacing, we temporarily suppress autosuggestions */
bool suppress_autosuggestion; bool suppress_autosuggestion;
/** Whether abbreviations are expanded */
bool expand_abbreviations;
/** The representation of the current screen contents */ /** The representation of the current screen contents */
screen_t screen; screen_t screen;
@ -244,6 +249,9 @@ public:
/** Do what we need to do whenever our command line changes */ /** Do what we need to do whenever our command line changes */
void command_line_changed(void); 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. */ /** The current position of the cursor in buff. */
size_t buff_pos; size_t buff_pos;
@ -326,6 +334,7 @@ public:
reader_data_t() : reader_data_t() :
allow_autosuggestion(0), allow_autosuggestion(0),
suppress_autosuggestion(0), suppress_autosuggestion(0),
expand_abbreviations(0),
history(0), history(0),
token_history_pos(0), token_history_pos(0),
search_pos(0), search_pos(0),
@ -635,6 +644,159 @@ void reader_data_t::command_line_changed()
s_generation_count++; 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. */ /** Sorts and remove any duplicate completions in the list. */
static void sort_and_make_unique(std::vector<completion_t> &l) 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 Set the specified string as the current buffer.
not modify prefix_width.
*/ */
static void set_command_line_and_position(const wcstring &new_str, size_t pos) 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; data->allow_autosuggestion = flag;
} }
void reader_set_expand_abbreviations(bool flag)
{
data->expand_abbreviations = flag;
}
void reader_set_complete_function(complete_function_t f) void reader_set_complete_function(complete_function_t f)
{ {
data->complete_func = f; data->complete_func = f;
@ -2712,6 +2878,7 @@ static int read_i(void)
reader_set_highlight_function(&highlight_shell); reader_set_highlight_function(&highlight_shell);
reader_set_test_function(&reader_shell_test); reader_set_test_function(&reader_shell_test);
reader_set_allow_autosuggesting(true); reader_set_allow_autosuggesting(true);
reader_set_expand_abbreviations(true);
reader_import_history_if_necessary(); reader_import_history_if_necessary();
parser_t &parser = parser_t::principal_parser(); parser_t &parser = parser_t::principal_parser();
@ -2851,7 +3018,6 @@ const wchar_t *reader_readline(void)
data->search_buff.clear(); data->search_buff.clear();
data->search_mode = NO_SEARCH; data->search_mode = NO_SEARCH;
exec_prompt(); exec_prompt();
reader_super_highlight_me_plenty(data->buff_pos); 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: case 0:
@ -3597,9 +3777,14 @@ const wchar_t *reader_readline(void)
/* Other, if a normal character, we add it to the command */ /* Other, if a normal character, we add it to the command */
default: default:
{ {
if ((!wchar_private(c)) && (((c>31) || (c==L'\n'))&& (c != 127))) 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 */ /* Regular character */
insert_char(c); insert_char(c);
} }
@ -3633,10 +3818,7 @@ const wchar_t *reader_readline(void)
} }
writestr(L"\n"); writestr(L"\n");
/*
if( comp )
halloc_free( comp );
*/
if (!reader_exit_forced()) if (!reader_exit_forced())
{ {
if (tcsetattr(0,TCSANOW,&old_modes)) /* return to previous mode */ 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. */ /** Sets whether autosuggesting is allowed. */
void reader_set_allow_autosuggesting(bool flag); 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. */ /** Sets whether the reader should exit on ^C. */
void reader_set_exit_on_interrupt(bool flag); 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. */ /* 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); 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. */ /* 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); 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 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 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 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 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 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' 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 function __fish_complete_ftp -d 'Complete ftp, pftp' --argument-names ftp
complete -c $ftp -xa "(__fish_print_hostnames)" -d 'Hostname' complete -c $ftp -xa "(__fish_print_hostnames)" -d 'Hostname'
tname'
complete -c $ftp -s 4 -d 'Use only IPv4 to contact any host' complete -c $ftp -s 4 -d 'Use only IPv4 to contact any host'
host'
complete -c $ftp -s 6 -d 'Use IPv6 only' complete -c $ftp -s 6 -d 'Use IPv6 only'
only'
complete -c $ftp -s p -d 'Use passive mode for data transfers' 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' 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 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 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 e -d 'Disable command editing and history support'
complete -c $ftp -s g -d 'Disable file name globbing' complete -c $ftp -s g -d 'Disable file name globbing'
Disable file name globbing' complete -c $ftp -s m -d 'Do not explicitly bind data and control channels to same interface'
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'
channels to same interface' complete -c $ftp -s d -d 'Enable debugging'
v -d 'Verbose. Show all server responses and data transfer stats'
es and data transfer stats'
d -d 'Enable debugging'
end 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 function fish_command_not_found_handler --on-event fish_command_not_found
/usr/lib/command-not-found $argv /usr/lib/command-not-found $argv
end end
fish_command_not_found_handler $argv
else
# Ubuntu Feisty places this command in the regular path instead # Ubuntu Feisty places this command in the regular path instead
if type -p command-not-found > /dev/null 2> /dev/null else if type -p command-not-found > /dev/null 2> /dev/null
function fish_command_not_found_handler --on-event fish_command_not_found function fish_command_not_found_handler --on-event fish_command_not_found
command-not-found $argv command-not-found $argv
end end
# Use standard fish command not found handler otherwise
else
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 fish_command_not_found_handler $argv
end end
end end
end
end

View file

@ -75,6 +75,8 @@
# 'upstream_equal', 'upstream_behind', 'upstream_ahead', and # 'upstream_equal', 'upstream_behind', 'upstream_ahead', and
# 'upstream_diverged'. # '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" function __fish_git_prompt_show_upstream --description "Helper function for __fish_git_prompt"
# Ask git-config for some config options # Ask git-config for some config options
set -l svn_remote 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 upstream git
set -l legacy set -l legacy
set -l verbose set -l verbose
set -l informative
set -l svn_url_pattern set -l svn_url_pattern
set -l show_upstream $__fish_git_prompt_showupstream 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 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 set upstream $option
case verbose case verbose
set verbose 1 set verbose 1
case informative
set informative 1
case legacy case legacy
set legacy 1 set legacy 1
end end
@ -176,30 +181,42 @@ function __fish_git_prompt_show_upstream --description "Helper function for __fi
end end
# calculate the result # calculate the result
if test -z "$verbose" if test -n "$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
echo $count | read -l behind ahead echo $count | read -l behind ahead
switch "$count" switch "$count"
case '' # no upstream case '' # no upstream
case "0 0" # equal to 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 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 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 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 end
end end
@ -216,10 +233,15 @@ function __fish_git_prompt --description "Prompt function for Git"
set -l u #untracked set -l u #untracked
set -l c (__fish_git_prompt_current_branch_bare) set -l c (__fish_git_prompt_current_branch_bare)
set -l p #upstream set -l p #upstream
set -l informative_status
__fish_git_prompt_validate_chars __fish_git_prompt_validate_chars
if test "true" = (git rev-parse --is-inside-work-tree ^/dev/null) if test "true" = (git rev-parse --is-inside-work-tree ^/dev/null)
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" if test -n "$__fish_git_prompt_showdirtystate"
set -l config (git config --bool bash.showDirtyState) set -l config (git config --bool bash.showDirtyState)
if test "$config" != "false" if test "$config" != "false"
@ -238,10 +260,12 @@ function __fish_git_prompt --description "Prompt function for Git"
set u $___fish_git_prompt_char_untrackedfiles set u $___fish_git_prompt_char_untrackedfiles
end end
end end
end
if test -n "$__fish_git_prompt_showupstream" if test -n "$__fish_git_prompt_showupstream"
set p (__fish_git_prompt_show_upstream) set p (__fish_git_prompt_show_upstream)
end end
end end
__fish_git_prompt_validate_colors __fish_git_prompt_validate_colors
@ -282,7 +306,7 @@ function __fish_git_prompt --description "Prompt function for Git"
set format " (%s)" set format " (%s)"
end 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 end
### helper functions ### helper functions
@ -310,6 +334,46 @@ function __fish_git_prompt_dirty --description "__fish_git_prompt helper, tells
echo $dirty echo $dirty
end 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" function __fish_git_prompt_current_branch_bare --description "__fish_git_prompt helper, tells wheter or not the current branch is bare"
set -l 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) echo (git rev-parse --git-dir ^/dev/null)
end 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" 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 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 '+') 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 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 '#') 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 end
if not set -q ___fish_git_prompt_char_stashstate set -g $variable_done (set_color normal)
set -g ___fish_git_prompt_char_stashstate (set -q __fish_git_prompt_char_stashstate; and echo $__fish_git_prompt_char_stashstate; or echo '$') else
end set -g $variable ''
if not set -q ___fish_git_prompt_char_untrackedfiles set -g $variable_done ''
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 '<>')
end end
end end
end
function __fish_git_prompt_validate_colors --description "__fish_git_prompt helper, checks color variables" 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" __fish_git_prompt_set_color __fish_git_prompt_color
set -g ___fish_git_prompt_color (set_color $__fish_git_prompt_color) __fish_git_prompt_set_color __fish_git_prompt_color_prefix
set -g ___fish_git_prompt_color_done (set_color normal) __fish_git_prompt_set_color __fish_git_prompt_color_suffix
else __fish_git_prompt_set_color __fish_git_prompt_color_bare
set -g ___fish_git_prompt_color '' __fish_git_prompt_set_color __fish_git_prompt_color_merging
set -g ___fish_git_prompt_color_done '' __fish_git_prompt_set_color __fish_git_prompt_color_branch
end __fish_git_prompt_set_color __fish_git_prompt_color_cleanstate
end __fish_git_prompt_set_color __fish_git_prompt_color_dirtystate
if not set -q ___fish_git_prompt_color_prefix __fish_git_prompt_set_color __fish_git_prompt_color_stagedstate
if test -n "$__fish_git_prompt_color_prefix" __fish_git_prompt_set_color __fish_git_prompt_color_invalidstate
set -g ___fish_git_prompt_color_prefix (set_color $__fish_git_prompt_color_prefix) __fish_git_prompt_set_color __fish_git_prompt_color_stashstate
set -g ___fish_git_prompt_color_prefix_done (set_color normal) __fish_git_prompt_set_color __fish_git_prompt_color_untrackedfiles
else __fish_git_prompt_set_color __fish_git_prompt_color_upstream
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
end end
set -l varargs set -l varargs

View file

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