Uh oh!
There was an error while loading.Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork33.7k
gh-103997: Automatically dedent the argument to "-c"#103998
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.
Already on GitHub?Sign in to your account
Changes from1 commit
16be08fe88216bbcb7c77fb8985a26f27a8417eff8924e0a69f956723f4a78b97f207904435eb4c4eca9f9c969b674f1e005d41699d53c4e689a13af0ac7ea71cad014549de80c3b90b1f5b746ca405891f17e232de2e1ec84616ca19b6757ce411fdea4301e06d40ca40d02895696551735d0fd3681b73b4a7bcf355760b1e89c9d1b4cd1e556bbf136c8b08e5cc7fcd14a0007d2273ed6e17bd1edb1b4c78c5738d2a4e42b633098c17e5File filter
Filter by extension
Conversations
Uh oh!
There was an error while loading.Please reload this page.
Jump to
Uh oh!
There was an error while loading.Please reload this page.
Diff view
Diff view
- Loading branch information
Uh oh!
There was an error while loading.Please reload this page.
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -122,6 +122,31 @@ PyAPI_FUNC(void*) _PyBytesWriter_WriteBytes(_PyBytesWriter *writer, | ||
| const void *bytes, | ||
| Py_ssize_t size); | ||
| /** Dedent a UTF-8 encoded string. | ||
| * behavior is expected to match `textwrap.dedent` | ||
| * | ||
| * return value: | ||
| * 0, no need to dedent, writer untouched | ||
| * 1, success | ||
| * -1, failure | ||
| * | ||
| * str is the beginning of the string to dedent. | ||
| * expecting (str != NULL) | ||
| * | ||
| * len is the length of the string to dedent. | ||
| * expecting (len >= 0) | ||
| * | ||
sunmy2019 marked this conversation as resolved. OutdatedShow resolvedHide resolvedUh oh!There was an error while loading.Please reload this page. | ||
| * writer is a _PyBytesWriter object to write the dedented string. | ||
| * expecting (writer != NULL) | ||
| * | ||
| * p points to a char* indicating the current position in the _PyBytesWriter. | ||
| * It is updated to the new position after writing the dedented string on exit. | ||
| * expecting (p != NULL && *p != NULL) | ||
| */ | ||
| PyAPI_FUNC(int) | ||
| _PyBytes_Dedent(const char *str, Py_ssize_t len, _PyBytesWriter *writer, | ||
| char **p); | ||
| #ifdef __cplusplus | ||
| } | ||
| #endif | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1 +1,7 @@ | ||
| String arguments passed to "-c" are now automatically dedented as if by | ||
| :func:`textwrap.dedent`. This allows "python -c" invocations to be indented | ||
| in shell scripts without causing indentation errors. | ||
sunmy2019 marked this conversation as resolved. OutdatedShow resolvedHide resolvedUh oh!There was an error while loading.Please reload this page. | ||
| Add a private API :c:func:`_PyBytes_Dedent`. | ||
sunmy2019 marked this conversation as resolved. OutdatedShow resolvedHide resolvedUh oh!There was an error while loading.Please reload this page. | ||
| (Patch by Jon Crall and Steven Sun) | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -7,6 +7,7 @@ | ||
| #include "pycore_pathconfig.h" // _PyPathConfig_ComputeSysPath0() | ||
| #include "pycore_pylifecycle.h" // _Py_PreInitializeFromPyArgv() | ||
| #include "pycore_pystate.h" // _PyInterpreterState_GET() | ||
| #include "pycore_bytesobject.h" // _PyBytesWriter, _PyBytes_Dedent() | ||
sunmy2019 marked this conversation as resolved. OutdatedShow resolvedHide resolvedUh oh!There was an error while loading.Please reload this page. | ||
| /* Includes for exit_sigint() */ | ||
| #include <stdio.h> // perror() | ||
| @@ -229,150 +230,35 @@ pymain_import_readline(const PyConfig *config) | ||
| } | ||
| /* Strip common leading whitespace, just as textwrap.dedent. | ||
| Itreturns a new reference. */ | ||
| static PyObject * | ||
| dedent_utf8_bytes(PyObject *bytes) | ||
| { | ||
| assert(bytes == NULL || !PyBytes_CheckExact(bytes->ob_type)); | ||
| Py_ssize_t nchars; | ||
| char *start; | ||
| if (PyBytes_AsStringAndSize(bytes, &start, &nchars) != 0) { | ||
| return NULL; | ||
| } | ||
| _PyBytesWriter writer; | ||
| _PyBytesWriter_Init(&writer); | ||
| char *p = _PyBytesWriter_Alloc(&writer, nchars); | ||
| if (p == NULL) { | ||
| return NULL; | ||
| } | ||
| int ret = _PyBytes_Dedent(start, nchars, &writer, &p); | ||
| if (ret < 0) { | ||
| return NULL; | ||
| } | ||
| if (ret == 0) { | ||
| Py_INCREF(bytes); | ||
| _PyBytesWriter_Dealloc(&writer); | ||
| return bytes; | ||
| } | ||
| return _PyBytesWriter_Finish(&writer, p); | ||
| } | ||
| static int | ||
| @@ -396,10 +282,12 @@ pymain_run_command(wchar_t *command) | ||
| goto error; | ||
| } | ||
| PyObject *new_bytes = dedent_utf8_bytes(bytes); | ||
| if (new_bytes == NULL) { | ||
| Py_DECREF(bytes); | ||
| goto error; | ||
| } | ||
| Py_SETREF(bytes, new_bytes); | ||
| PyCompilerFlags cf = _PyCompilerFlags_INIT; | ||
| cf.cf_flags |= PyCF_IGNORE_COOKIE; | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -3535,6 +3535,8 @@ _PyBytesWriter_WriteBytes(_PyBytesWriter *writer, void *ptr, | ||
| } | ||
| /* Algorithms on bytes */ | ||
sunmy2019 marked this conversation as resolved. OutdatedShow resolvedHide resolvedUh oh!There was an error while loading.Please reload this page. | ||
| void | ||
| _PyBytes_Repeat(char* dest, Py_ssize_t len_dest, | ||
| const char* src, Py_ssize_t len_src) | ||
| @@ -3558,3 +3560,148 @@ _PyBytes_Repeat(char* dest, Py_ssize_t len_dest, | ||
| } | ||
| } | ||
sunmy2019 marked this conversation as resolved. Show resolvedHide resolvedUh oh!There was an error while loading.Please reload this page. | ||
| /** Dedent a UTF-8 encoded string. | ||
methane marked this conversation as resolved. OutdatedShow resolvedHide resolvedUh oh!There was an error while loading.Please reload this page. | ||
| * behavior is expected to match `textwrap.dedent` | ||
| * | ||
| * return value: | ||
| * 0, no need to dedent, writer untouched | ||
| * 1, success | ||
| * -1, failure | ||
| * | ||
| * str is the beginning of the string to dedent. | ||
| * expecting (str != NULL) | ||
| * | ||
| * len is the length of the string to dedent. | ||
| * expecting (len >= 0) | ||
| * | ||
sunmy2019 marked this conversation as resolved. OutdatedShow resolvedHide resolvedUh oh!There was an error while loading.Please reload this page. | ||
| * writer is a _PyBytesWriter object to write the dedented string. | ||
| * expecting (writer != NULL) | ||
| * | ||
| * p points to a char* indicating the current position in the _PyBytesWriter. | ||
| * It is updated to the new position after writing the dedented string on exit. | ||
| * expecting (p != NULL && *p != NULL) | ||
| */ | ||
| int | ||
| _PyBytes_Dedent(const char *str, Py_ssize_t len, _PyBytesWriter *writer, | ||
| char **p) | ||
sunmy2019 marked this conversation as resolved. OutdatedShow resolvedHide resolvedUh oh!There was an error while loading.Please reload this page. | ||
| { | ||
sunmy2019 marked this conversation as resolved. OutdatedShow resolvedHide resolvedUh oh!There was an error while loading.Please reload this page. | ||
| assert(str); | ||
| assert(p != NULL && *p != NULL); | ||
| assert(writer); | ||
| if (len <= 0) | ||
| return 0; | ||
| const char *end = str + len; | ||
| assert(str < end); // prevent overflow when len is too large | ||
| const char *candidate_start = NULL; | ||
| Py_ssize_t candidate_len = 0; | ||
| for (const char *iter = str; iter < end; ++iter) { | ||
| const char *line_start = iter; | ||
| const char *leading_whitespace_end = NULL; | ||
| // scan the whole line | ||
| while (iter < end && *iter != '\n') { | ||
| if (!leading_whitespace_end && *iter != ' ' && *iter != '\t') { | ||
| if (iter == line_start) { | ||
| // some line has no indent, fast exit! | ||
| return 0; | ||
| } | ||
| leading_whitespace_end = iter; | ||
| } | ||
| ++iter; | ||
| } | ||
| // if this line has all white space, skip it | ||
| if (!leading_whitespace_end) { | ||
| continue; | ||
| } | ||
| if (!candidate_start) { | ||
| candidate_start = line_start; | ||
| candidate_len = leading_whitespace_end - line_start; | ||
| assert(candidate_len > 0); | ||
| } else { | ||
| /* We then compare with the current longest leading whitespace. | ||
| [line_start, leading_whitespace_end) is the leading whitespace of | ||
| this line, | ||
| [candidate_start, candidate_start + candidate_len) | ||
| is the leading whitespace of the current longest leading | ||
| whitespace. */ | ||
| Py_ssize_t new_candidate_len = 0; | ||
| for (const char *candidate_iter = candidate_start, | ||
| *line_iter = line_start; | ||
| candidate_iter < candidate_start + candidate_len && | ||
| line_iter < leading_whitespace_end; | ||
| ++candidate_iter, ++line_iter) { | ||
| if (*candidate_iter != *line_iter) { | ||
| break; | ||
| } | ||
| ++new_candidate_len; | ||
| } | ||
| candidate_len = new_candidate_len; | ||
| if (candidate_len == 0) { | ||
| return 0; | ||
| } | ||
| } | ||
| } | ||
| assert(candidate_len >= 0); | ||
| if (candidate_len == 0) { | ||
| return 0; | ||
| } | ||
| // trigger a dedent | ||
| // prepare the writer | ||
| char *p_ = _PyBytesWriter_Prepare(writer, *p, len); | ||
| if (p_ == NULL) { | ||
| *p = NULL; | ||
| return -1; | ||
| } | ||
| for (const char *iter = str; iter < end; ++iter) { | ||
| const char *line_start = iter; | ||
| bool in_leading_space = true; | ||
| // iterate over a line to find the end of a line | ||
| while (iter < end && *iter != '\n') { | ||
| if (in_leading_space && *iter != ' ' && *iter != '\t') { | ||
| in_leading_space = false; | ||
| } | ||
| ++iter; | ||
| } | ||
| // invariant: *iter == '\n' or iter == end | ||
| bool append_newline = iter < end; | ||
| // if this line has all white space, write '\n' | ||
| if (in_leading_space && append_newline) { | ||
| *p_++ = '\n'; | ||
| continue; | ||
| } | ||
| /* copy [new_line_start + candidate_len, iter) to buffer, then | ||
| conditionally append '\n' */ | ||
| Py_ssize_t new_line_len = iter - line_start - candidate_len; | ||
| assert(new_line_len >= 0); | ||
| memcpy(p_, line_start + candidate_len, new_line_len); | ||
| p_ += new_line_len; | ||
| if (append_newline) { | ||
| *p_++ = '\n'; | ||
| } | ||
| } | ||
| *p = p_; | ||
| return 1; | ||
| } | ||