diff options
author | Campbell Barton <campbell@blender.org> | 2022-03-28 09:04:19 +0300 |
---|---|---|
committer | Campbell Barton <campbell@blender.org> | 2022-03-28 09:06:38 +0300 |
commit | 1466f480c4ea894c2f0b23663fcdba644cceb3f8 (patch) | |
tree | d50be1db2281f9f8655b21e67b75b8b80219ee49 | |
parent | 0ce6ed47533f715a72b139cb47a4f2dfb5a0bb39 (diff) |
Python: select the start-end range of syntax errors
Python 3.10's syntax errors can specify a range.
Use this for text editor error selection.
-rw-r--r-- | source/blender/python/intern/bpy_interface_run.c | 12 | ||||
-rw-r--r-- | source/blender/python/intern/bpy_traceback.c | 72 | ||||
-rw-r--r-- | source/blender/python/intern/bpy_traceback.h | 3 |
3 files changed, 74 insertions, 13 deletions
diff --git a/source/blender/python/intern/bpy_interface_run.c b/source/blender/python/intern/bpy_interface_run.c index 14d03bf7e2b..8f7437ac1da 100644 --- a/source/blender/python/intern/bpy_interface_run.c +++ b/source/blender/python/intern/bpy_interface_run.c @@ -37,12 +37,14 @@ static void python_script_error_jump_text(Text *text, const char *filepath) { - int lineno; - int offset; - python_script_error_jump(filepath, &lineno, &offset); + int lineno, lineno_end; + int offset, offset_end; + python_script_error_jump(filepath, &lineno, &offset, &lineno_end, &offset_end); if (lineno != -1) { - /* select the line with the error */ - txt_move_to(text, lineno - 1, INT_MAX, false); + /* Start at the end so cursor motion that looses the selection, + * leaves the cursor from the most useful place. + * Also, the end can't always be set, so don't give it priority. */ + txt_move_to(text, lineno_end - 1, offset_end, false); txt_move_to(text, lineno - 1, offset, true); } } diff --git a/source/blender/python/intern/bpy_traceback.c b/source/blender/python/intern/bpy_traceback.c index 87e6375c7d1..6813496be83 100644 --- a/source/blender/python/intern/bpy_traceback.c +++ b/source/blender/python/intern/bpy_traceback.c @@ -24,7 +24,7 @@ static const char *traceback_filepath(PyTracebackObject *tb, PyObject **coerce) return PyBytes_AS_STRING(*coerce); } -/* copied from pythonrun.c, 3.4.0 */ +/* copied from pythonrun.c, 3.10.0 */ _Py_static_string(PyId_string, "<string>"); static int parse_syntax_error(PyObject *err, @@ -32,14 +32,18 @@ static int parse_syntax_error(PyObject *err, PyObject **filename, int *lineno, int *offset, + int *end_lineno, + int *end_offset, PyObject **text) { - long hold; + Py_ssize_t hold; PyObject *v; _Py_IDENTIFIER(msg); _Py_IDENTIFIER(filename); _Py_IDENTIFIER(lineno); _Py_IDENTIFIER(offset); + _Py_IDENTIFIER(end_lineno); + _Py_IDENTIFIER(end_offset); _Py_IDENTIFIER(text); *message = NULL; @@ -71,7 +75,7 @@ static int parse_syntax_error(PyObject *err, if (!v) { goto finally; } - hold = PyLong_AsLong(v); + hold = PyLong_AsSsize_t(v); Py_DECREF(v); if (hold < 0 && PyErr_Occurred()) { goto finally; @@ -87,7 +91,7 @@ static int parse_syntax_error(PyObject *err, Py_DECREF(v); } else { - hold = PyLong_AsLong(v); + hold = PyLong_AsSsize_t(v); Py_DECREF(v); if (hold < 0 && PyErr_Occurred()) { goto finally; @@ -95,6 +99,49 @@ static int parse_syntax_error(PyObject *err, *offset = (int)hold; } + if (Py_TYPE(err) == (PyTypeObject *)PyExc_SyntaxError) { + v = _PyObject_GetAttrId(err, &PyId_end_lineno); + if (!v) { + PyErr_Clear(); + *end_lineno = *lineno; + } + else if (v == Py_None) { + *end_lineno = *lineno; + Py_DECREF(v); + } + else { + hold = PyLong_AsSsize_t(v); + Py_DECREF(v); + if (hold < 0 && PyErr_Occurred()) { + goto finally; + } + *end_lineno = hold; + } + + v = _PyObject_GetAttrId(err, &PyId_end_offset); + if (!v) { + PyErr_Clear(); + *end_offset = -1; + } + else if (v == Py_None) { + *end_offset = -1; + Py_DECREF(v); + } + else { + hold = PyLong_AsSsize_t(v); + Py_DECREF(v); + if (hold < 0 && PyErr_Occurred()) { + goto finally; + } + *end_offset = hold; + } + } + else { + /* `SyntaxError` subclasses. */ + *end_lineno = *lineno; + *end_offset = -1; + } + v = _PyObject_GetAttrId(err, &PyId_text); if (!v) { goto finally; @@ -115,7 +162,8 @@ finally: } /* end copied function! */ -void python_script_error_jump(const char *filepath, int *r_lineno, int *r_offset) +void python_script_error_jump( + const char *filepath, int *r_lineno, int *r_offset, int *r_lineno_end, int *r_offset_end) { PyObject *exception, *value; PyTracebackObject *tb; @@ -123,6 +171,9 @@ void python_script_error_jump(const char *filepath, int *r_lineno, int *r_offset *r_lineno = -1; *r_offset = 0; + *r_lineno_end = -1; + *r_offset_end = 0; + PyErr_Fetch(&exception, &value, (PyObject **)&tb); if (exception == NULL) { return; @@ -137,7 +188,14 @@ void python_script_error_jump(const char *filepath, int *r_lineno, int *r_offset PyObject *message; PyObject *filepath_exc_py, *text_py; - if (parse_syntax_error(value, &message, &filepath_exc_py, r_lineno, r_offset, &text_py)) { + if (parse_syntax_error(value, + &message, + &filepath_exc_py, + r_lineno, + r_offset, + r_lineno_end, + r_offset_end, + &text_py)) { const char *filepath_exc = PyUnicode_AsUTF8(filepath_exc_py); /* python adds a '/', prefix, so check for both */ if ((BLI_path_cmp(filepath_exc, filepath) == 0) || @@ -170,7 +228,7 @@ void python_script_error_jump(const char *filepath, int *r_lineno, int *r_offset Py_DECREF(coerce); if (match) { - *r_lineno = tb->tb_lineno; + *r_lineno = *r_lineno_end = tb->tb_lineno; /* used to break here, but better find the inner most line */ } } diff --git a/source/blender/python/intern/bpy_traceback.h b/source/blender/python/intern/bpy_traceback.h index c96f8751989..2ebdab527e8 100644 --- a/source/blender/python/intern/bpy_traceback.h +++ b/source/blender/python/intern/bpy_traceback.h @@ -10,7 +10,8 @@ extern "C" { #endif -void python_script_error_jump(const char *filepath, int *r_lineno, int *r_offset); +void python_script_error_jump( + const char *filepath, int *r_lineno, int *r_offset, int *r_lineno_end, int *r_offset_end); #ifdef __cplusplus } |