diff options
author | Johannes Schlüter <johannes@php.net> | 2010-05-20 20:55:33 +0000 |
---|---|---|
committer | Johannes Schlüter <johannes@php.net> | 2010-05-20 20:55:33 +0000 |
commit | 61db5cf98a91916c23ae4adf3754b2ef94a4fbb2 (patch) | |
tree | 1e0527691b9773d5edf32340d653810dd1d276a4 /sapi/cli/php_cli_readline.c | |
parent | 31f62dbc72f5d2c2670a1e3646a4bf2e62f0321d (diff) | |
download | php-git-61db5cf98a91916c23ae4adf3754b2ef94a4fbb2.tar.gz |
- Improved CLI Interactive readline shell (Johannes)
. Added cli.pager ini setting to set a pager for output.
. Added cli.prompt ini settingto configure the shell prompt.
. Added shortcut #inisetting=value to change ini settings at run-time.
. Don't terminate shell on fatal errors.
A pager can be a an shell command which will receive the command output on its
STDIN channel
php > #cli.pager=less
php > phpinfo();
(output will appear in the pager)
php > #cli.pager=grep -i readline
php > phpcredits();
Readline => Thies C. Arntzen
php > #cli.pager=
(output appears again direct on the terminal)
A prompt can contain a few escape sequences like
php > #cli.prompt=\e[032m\v \e[031m\b \e[34m\> \e[0m
5.3.99-dev php > //Colorful prompt with version number
A prompt can also contaian PHP code in backticks
php > #cli.prompt=`echo gethostname();` \b \>
guybrush php >
Diffstat (limited to 'sapi/cli/php_cli_readline.c')
-rw-r--r-- | sapi/cli/php_cli_readline.c | 152 |
1 files changed, 144 insertions, 8 deletions
diff --git a/sapi/cli/php_cli_readline.c b/sapi/cli/php_cli_readline.c index 49699c16da..cba710023d 100644 --- a/sapi/cli/php_cli_readline.c +++ b/sapi/cli/php_cli_readline.c @@ -44,6 +44,7 @@ #include "php_main.h" #include "fopen_wrappers.h" #include "ext/standard/php_standard.h" +#include "ext/standard/php_smart_str.h" #ifdef __riscos__ #include <unixlib/local.h> @@ -61,6 +62,55 @@ #include "zend_highlight.h" #include "zend_indent.h" +#include "php_cli_readline.h" + +#define DEFAULT_PROMPT "\\b \\> " + +ZEND_DECLARE_MODULE_GLOBALS(cli_readline); + +static void cli_readline_init_globals(zend_cli_readline_globals *rg TSRMLS_DC) +{ + rg->pager = NULL; + rg->prompt = NULL; + rg->prompt_str = NULL; +} + +PHP_INI_BEGIN() + STD_PHP_INI_ENTRY("cli.pager", "", PHP_INI_ALL, OnUpdateString, pager, zend_cli_readline_globals, cli_readline_globals) + STD_PHP_INI_ENTRY("cli.prompt", DEFAULT_PROMPT, PHP_INI_ALL, OnUpdateString, prompt, zend_cli_readline_globals, cli_readline_globals) +PHP_INI_END() + +static PHP_MINIT_FUNCTION(cli_readline) +{ + ZEND_INIT_MODULE_GLOBALS(cli_readline, cli_readline_init_globals, NULL); + REGISTER_INI_ENTRIES(); + return SUCCESS; +} + +static PHP_MSHUTDOWN_FUNCTION(cli_readline) +{ + UNREGISTER_INI_ENTRIES(); + return SUCCESS; +} + +static PHP_MINFO_FUNCTION(cli_readline) +{ + DISPLAY_INI_ENTRIES(); +} + +zend_module_entry cli_readline_module_entry = { + STANDARD_MODULE_HEADER, + "cli-readline", + NULL, + PHP_MINIT(cli_readline), + PHP_MSHUTDOWN(cli_readline), + NULL, + NULL, + PHP_MINFO(cli_readline), + PHP_VERSION, + STANDARD_MODULE_PROPERTIES +}; + typedef enum { body, sstring, @@ -74,6 +124,75 @@ typedef enum { outside, } php_code_type; +char *cli_get_prompt(char *block, char prompt TSRMLS_DC) /* {{{ */ +{ + smart_str retval = {0}; + char *prompt_spec = CLIR_G(prompt) ? CLIR_G(prompt) : DEFAULT_PROMPT; + + do { + if (*prompt_spec == '\\') { + switch (prompt_spec[1]) { + case '\\': + smart_str_appendc(&retval, '\\'); + prompt_spec++; + break; + case 'n': + smart_str_appendc(&retval, '\n'); + prompt_spec++; + break; + case 't': + smart_str_appendc(&retval, '\t'); + prompt_spec++; + break; + case 'e': + smart_str_appendc(&retval, '\033'); + prompt_spec++; + break; + + + case 'v': + smart_str_appends(&retval, PHP_VERSION); + prompt_spec++; + break; + case 'b': + smart_str_appends(&retval, block); + prompt_spec++; + break; + case '>': + smart_str_appendc(&retval, prompt); + prompt_spec++; + break; + case '`': + smart_str_appendc(&retval, '`'); + prompt_spec++; + break; + default: + smart_str_appendc(&retval, '\\'); + break; + } + } else if (*prompt_spec == '`') { + char *prompt_end = strstr(prompt_spec + 1, "`"); + char *code; + + if (prompt_end) { + code = estrndup(prompt_spec + 1, prompt_end - prompt_spec - 1); + + CLIR_G(prompt_str) = &retval; + zend_try { + zend_eval_stringl(code, prompt_end - prompt_spec - 1, NULL, "php prompt code" TSRMLS_CC); + } zend_end_try(); + CLIR_G(prompt_str) = NULL; + efree(code); + prompt_spec = prompt_end; + } + } else { + smart_str_appendc(&retval, *prompt_spec); + } + } while (++prompt_spec && *prompt_spec); + smart_str_0(&retval); + return retval.c; +} + int cli_is_valid_code(char *code, int len, char **prompt TSRMLS_DC) /* {{{ */ { int valid_end = 1, last_valid_end; @@ -206,6 +325,7 @@ int cli_is_valid_code(char *code, int len, char **prompt TSRMLS_DC) /* {{{ */ switch(code[i]) { case ' ': case '\t': + case '\'': break; case '\r': case '\n': @@ -241,29 +361,29 @@ int cli_is_valid_code(char *code, int len, char **prompt TSRMLS_DC) /* {{{ */ switch (code_type) { default: if (brace_count) { - *prompt = "php ( "; + *prompt = cli_get_prompt("php", '(' TSRMLS_CC); } else if (brackets_count) { - *prompt = "php { "; + *prompt = cli_get_prompt("php", '{' TSRMLS_CC); } else { - *prompt = "php > "; + *prompt = cli_get_prompt("php", '>' TSRMLS_CC); } break; case sstring: case sstring_esc: - *prompt = "php ' "; + *prompt = cli_get_prompt("php", '\'' TSRMLS_CC); break; case dstring: case dstring_esc: - *prompt = "php \" "; + *prompt = cli_get_prompt("php", '"' TSRMLS_CC); break; case comment_block: - *prompt = "/* > "; + *prompt = cli_get_prompt("/* ", '>' TSRMLS_CC); break; case heredoc: - *prompt = "<<< > "; + *prompt = cli_get_prompt("<<<", '>' TSRMLS_CC); break; case outside: - *prompt = " > "; + *prompt = cli_get_prompt(" ", '>' TSRMLS_CC); break; } @@ -315,6 +435,20 @@ static char *cli_completion_generator_var(const char *text, int textlen, int *st return retval; } /* }}} */ +static char *cli_completion_generator_ini(const char *text, int textlen, int *state TSRMLS_DC) /* {{{ */ +{ + char *retval, *tmp; + + tmp = retval = cli_completion_generator_ht(text + 1, textlen - 1, state, EG(ini_directives), NULL TSRMLS_CC); + if (retval) { + retval = malloc(strlen(tmp) + 2); + retval[0] = '#'; + strcpy(&retval[1], tmp); + rl_completion_append_character = '='; + } + return retval; +} /* }}} */ + static char *cli_completion_generator_func(const char *text, int textlen, int *state, HashTable *ht TSRMLS_DC) /* {{{ */ { zend_function *func; @@ -373,6 +507,8 @@ TODO: } if (text[0] == '$') { retval = cli_completion_generator_var(text, textlen, &cli_completion_state TSRMLS_CC); + } else if (text[0] == '#') { + retval = cli_completion_generator_ini(text, textlen, &cli_completion_state TSRMLS_CC); } else { char *lc_text, *class_name, *class_name_end; int class_name_len; |