]> granicus.if.org Git - php/commitdiff
Allow overriding completion in `auto_prepend_file`
authorTyson Andre <tysonandre775@hotmail.com>
Sat, 18 Jul 2020 21:54:59 +0000 (17:54 -0400)
committerTyson Andre <tysonandre775@hotmail.com>
Sat, 1 Aug 2020 15:39:08 +0000 (11:39 -0400)
Currently, it's possible to override `php -a`s completion
functionality to provide an alternative to the C implementation,
with `readline_completion_function()`.

However, that surprisingly gets overridden when called from
`auto_prepend_file`, because those scripts get run before the interactive shell
is started. I believe that not overriding it would be more consistent
with what happens when you override the completion function **after** the
interactive shell.

CLI is the only built-in API that uses this (See discussion in GH-5872).
I believe MINIT and RINIT will only run once when invoked with `php -a`.

Add documentation about the architecture of how php uses readline/libedit

Closes GH-5872

UPGRADING
ext/readline/README.md [new file with mode: 0644]
ext/readline/readline.c
ext/readline/readline_cli.c
ext/readline/readline_cli.h

index a71c8959c362e31673d901c3b5ac76029214e768..f38f149236c9c8070ebf7867b0deb3de8bdd1d8f 100644 (file)
--- a/UPGRADING
+++ b/UPGRADING
@@ -932,6 +932,12 @@ PHP 8.0 UPGRADE NOTES
 - PGSQL / PDO PGSQL:
   . The PGSQL and PDO PGSQL extensions now require at least libpq 9.1.
 
+- Readline:
+  . Calling readline_completion_function() before the interactive prompt starts
+    (e.g. in auto_prepend_file) will now override the default interactive prompt
+       completion function. Previously, readline_completion_function() only worked
+       when called after starting the interactive prompt.
+
 - SimpleXML:
   . SimpleXMLElement now implements RecursiveIterator and absorbed the
     functionality of SimpleXMLIterator. SimpleXMLIterator is an empty extension
diff --git a/ext/readline/README.md b/ext/readline/README.md
new file mode 100644 (file)
index 0000000..5dec48e
--- /dev/null
@@ -0,0 +1,20 @@
+readline
+========
+
+Provides generic line editing, history, and tokenization functions.
+See https://www.php.net/manual/en/book.readline.php
+
+Implementation Details
+----------------------
+
+C variables starting with `rl_*` are declared by the readline library
+(or are macros referring to variables from the libedit library).
+See http://web.mit.edu/gnu/doc/html/rlman_2.html
+
+This should only be used in the CLI SAPI.
+Historically, the code lived in sapi/cli,
+but many distributions build readline as a shared extension.
+Therefore, that code was split into ext/readline so that this can dynamically
+be loaded. With other SAPIs, readline is/should be disabled.
+
+`readline_cli.c` implements most of the interactive shell(`php -a`).
index d569efe820cadbb05cc8188d10420e3488b27f2d..ec1d1ff255076b333f1c4f9a4f2a8e639cc16885 100644 (file)
@@ -437,7 +437,7 @@ static void _readline_long_zval(zval *ret, long l)
        ZVAL_LONG(ret, l);
 }
 
-static char **_readline_completion_cb(const char *text, int start, int end)
+char **php_readline_completion_cb(const char *text, int start, int end)
 {
        zval params[3];
        char **matches = NULL;
@@ -479,7 +479,8 @@ PHP_FUNCTION(readline_completion_function)
        zval_ptr_dtor(&_readline_completion);
        ZVAL_COPY(&_readline_completion, &fci.function_name);
 
-       rl_attempted_completion_function = _readline_completion_cb;
+       /* NOTE: The rl_attempted_completion_function variable (and others) are part of the readline library, not php */
+       rl_attempted_completion_function = php_readline_completion_cb;
        if (rl_attempted_completion_function == NULL) {
                RETURN_FALSE;
        }
index c1ec134ffff0292f92fabd713e00950eaf5834b0..a463a89db49416144db6e2dda364f29b34181b36 100644 (file)
@@ -603,7 +603,14 @@ static int readline_shell_run(void) /* {{{ */
 #else
        spprintf(&history_file, MAX_PATH, "%s/.php_history", getenv("USERPROFILE"));
 #endif
-       rl_attempted_completion_function = cli_code_completion;
+       /* Install the default completion function for 'php -a'.
+        *
+        * But if readline_completion_function() was called by PHP code prior to the shell starting
+        * (e.g. with 'php -d auto_prepend_file=prepend.php -a'),
+        * then use that instead of PHP's default. */
+       if (rl_attempted_completion_function != php_readline_completion_cb) {
+               rl_attempted_completion_function = cli_code_completion;
+       }
 #ifndef PHP_WIN32
        rl_special_prefixes = "$";
 #endif
index 81e73d1e4dee471678ea8cbaad3dfa608b90fdfd..7afadded0708bd7ccb32fbba5aa650eeb97f0d46 100644 (file)
@@ -34,4 +34,6 @@ extern PHP_MINIT_FUNCTION(cli_readline);
 extern PHP_MSHUTDOWN_FUNCTION(cli_readline);
 extern PHP_MINFO_FUNCTION(cli_readline);
 
+char **php_readline_completion_cb(const char *text, int start, int end);
+
 ZEND_EXTERN_MODULE_GLOBALS(cli_readline)