Skip to content

Commit 663d18d

Browse files
ichizokrbtnn
authored andcommitted
patch 9.1.0984: exception handling can be improved
Problem: exception handling can be improved Solution: add v:stacktrace and getstacktrace() closes: #16360 Co-authored-by: Naruhiko Nishino <naru123456789@gmail.com> Signed-off-by: ichizok <gclient.gaap@gmail.com> Signed-off-by: Christian Brabandt <cb@256bit.org>
1 parent fd77161 commit 663d18d

17 files changed

Lines changed: 285 additions & 21 deletions

runtime/doc/builtin.txt

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -279,6 +279,7 @@ getregionpos({pos1}, {pos2} [, {opts}])
279279
List get a list of positions for a region
280280
getregtype([{regname}]) String type of a register
281281
getscriptinfo([{opts}]) List list of sourced scripts
282+
getstacktrace() List get current stack trace of Vim scripts
282283
gettabinfo([{expr}]) List list of tab pages
283284
gettabvar({nr}, {varname} [, {def}])
284285
any variable {varname} in tab {nr} or {def}
@@ -4997,6 +4998,21 @@ getscriptinfo([{opts}]) *getscriptinfo()*
49974998
Return type: list<dict<any>>
49984999

49995000

5001+
getstacktrace() *getstacktrace()*
5002+
Returns the current stack trace of Vim scripts.
5003+
Stack trace is a |List|, of which each item is a |Dictionary|
5004+
with the following items:
5005+
funcref The funcref if the stack is at the function,
5006+
otherwise this item is not exist.
5007+
event The string of the event description if the
5008+
stack is at autocmd event, otherwise this item
5009+
is not exist.
5010+
lnum The line number of the script on the stack.
5011+
filepath The file path of the script on the stack.
5012+
5013+
Return type: list<dict<any>>
5014+
5015+
50005016
gettabinfo([{tabnr}]) *gettabinfo()*
50015017
If {tabnr} is not specified, then information about all the
50025018
tab pages is returned as a |List|. Each List item is a

runtime/doc/eval.txt

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
*eval.txt* For Vim version 9.1. Last change: 2024 Dec 23
1+
*eval.txt* For Vim version 9.1. Last change: 2025 Jan 02
22

33

44
VIM REFERENCE MANUAL by Bram Moolenaar
@@ -1953,7 +1953,8 @@ variables for each buffer. Use local buffer variables instead |b:var|.
19531953

19541954
PREDEFINED VIM VARIABLES *vim-variable* *v:var* *v:*
19551955
*E963* *E1063*
1956-
Some variables can be set by the user, but the type cannot be changed.
1956+
Most variables are read-only, when a variable can be set by the user, it will
1957+
be mentioned at the variable description below. The type cannot be changed.
19571958

19581959
*v:argv* *argv-variable*
19591960
v:argv The command line arguments Vim was invoked with. This is a
@@ -2172,7 +2173,8 @@ v:event Dictionary containing information about the current
21722173
<
21732174
*v:exception* *exception-variable*
21742175
v:exception The value of the exception most recently caught and not
2175-
finished. See also |v:throwpoint| and |throw-variables|.
2176+
finished. See also |v:stacktrace|, |v:throwpoint|, and
2177+
|throw-variables|.
21762178
Example: >
21772179
:try
21782180
: throw "oops"
@@ -2548,6 +2550,12 @@ v:sizeofpointer Number of bytes in a pointer. Depends on how Vim was compiled.
25482550
This is only useful for deciding whether a test will give the
25492551
expected result.
25502552

2553+
*v:stacktrace* *stacktrace-variable*
2554+
v:stacktrace The stack trace of the exception most recently caught and
2555+
not finished. Refer to |getstacktrace()| for the structure of
2556+
stack trace. See also |v:exception|, |v:throwpoint|, and
2557+
|throw-variables|.
2558+
25512559
*v:statusmsg* *statusmsg-variable*
25522560
v:statusmsg Last given status message. It's allowed to set this variable.
25532561

@@ -2676,7 +2684,7 @@ v:this_session Full filename of the last loaded or saved session file. See
26762684
*v:throwpoint* *throwpoint-variable*
26772685
v:throwpoint The point where the exception most recently caught and not
26782686
finished was thrown. Not set when commands are typed. See
2679-
also |v:exception| and |throw-variables|.
2687+
also |v:exception|, |v:stacktrace|, and |throw-variables|.
26802688
Example: >
26812689
:try
26822690
: throw "oops"
@@ -3856,7 +3864,8 @@ in the variable |v:exception|: >
38563864
: echo "Number thrown. Value is" v:exception
38573865
38583866
You may also be interested where an exception was thrown. This is stored in
3859-
|v:throwpoint|. Note that "v:exception" and "v:throwpoint" are valid for the
3867+
|v:throwpoint|. And you can obtain the stack trace from |v:stacktrace|.
3868+
Note that "v:exception", "v:stacktrace" and "v:throwpoint" are valid for the
38603869
exception most recently caught as long it is not finished.
38613870
Example: >
38623871

runtime/doc/tags

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7908,6 +7908,7 @@ getscript-history pi_getscript.txt /*getscript-history*
79087908
getscript-plugins pi_getscript.txt /*getscript-plugins*
79097909
getscript-start pi_getscript.txt /*getscript-start*
79107910
getscriptinfo() builtin.txt /*getscriptinfo()*
7911+
getstacktrace() builtin.txt /*getstacktrace()*
79117912
gettabinfo() builtin.txt /*gettabinfo()*
79127913
gettabvar() builtin.txt /*gettabvar()*
79137914
gettabwinvar() builtin.txt /*gettabwinvar()*
@@ -10218,6 +10219,7 @@ sqrt() builtin.txt /*sqrt()*
1021810219
squirrel.vim syntax.txt /*squirrel.vim*
1021910220
srand() builtin.txt /*srand()*
1022010221
sscanf eval.txt /*sscanf*
10222+
stacktrace-variable eval.txt /*stacktrace-variable*
1022110223
standard-plugin usr_05.txt /*standard-plugin*
1022210224
standard-plugin-list help.txt /*standard-plugin-list*
1022310225
standout syntax.txt /*standout*
@@ -11038,6 +11040,7 @@ v:shell_error eval.txt /*v:shell_error*
1103811040
v:sizeofint eval.txt /*v:sizeofint*
1103911041
v:sizeoflong eval.txt /*v:sizeoflong*
1104011042
v:sizeofpointer eval.txt /*v:sizeofpointer*
11043+
v:stacktrace eval.txt /*v:stacktrace*
1104111044
v:statusmsg eval.txt /*v:statusmsg*
1104211045
v:swapchoice eval.txt /*v:swapchoice*
1104311046
v:swapcommand eval.txt /*v:swapcommand*

runtime/doc/usr_41.txt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
*usr_41.txt* For Vim version 9.1. Last change: 2024 Dec 30
1+
*usr_41.txt* For Vim version 9.1. Last change: 2025 Jan 02
22

33
VIM USER MANUAL - by Bram Moolenaar
44

@@ -1399,7 +1399,8 @@ Various: *various-functions*
13991399
eventhandler() check if invoked by an event handler
14001400
getcellpixels() get List of cell pixel size
14011401
getpid() get process ID of Vim
1402-
getscriptinfo() get list of sourced vim scripts
1402+
getscriptinfo() get list of sourced Vim scripts
1403+
getstacktrace() get current stack trace of Vim scripts
14031404
getimstatus() check if IME status is active
14041405
interrupt() interrupt script execution
14051406
windowsversion() get MS-Windows version

runtime/doc/version9.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41623,6 +41623,8 @@ Changed~
4162341623
for the ghostty terminal emulator (using kitty protocol)
4162441624
- |complete_info()| returns the list of matches shown in the poppu menu via
4162541625
the "matches" key
41626+
- |v:stacktrace| The stack trace of the exception most recently caught and
41627+
not finished
4162641628

4162741629
*added-9.2*
4162841630
Added ~
@@ -41642,6 +41644,7 @@ Functions: ~
4164241644
|getcmdprompt()| get prompt for input()/confirm()
4164341645
|getregion()| get a region of text from a buffer
4164441646
|getregionpos()| get a list of positions for a region
41647+
|getstacktrace()| get current stack trace of Vim scripts
4164541648
|id()| get unique identifier for a Dict, List, Object,
4164641649
Channel or Blob variable
4164741650
|matchbufline()| all the matches of a pattern in a buffer

src/dict.c

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -531,6 +531,29 @@ dict_add_callback(dict_T *d, char *key, callback_T *cb)
531531
return OK;
532532
}
533533

534+
/*
535+
* Add a function entry to dictionary "d".
536+
* Returns FAIL when out of memory and when key already exists.
537+
*/
538+
int
539+
dict_add_func(dict_T *d, char *key, ufunc_T *fp)
540+
{
541+
dictitem_T *item;
542+
543+
item = dictitem_alloc((char_u *)key);
544+
if (item == NULL)
545+
return FAIL;
546+
item->di_tv.v_type = VAR_FUNC;
547+
item->di_tv.vval.v_string = vim_strsave(fp->uf_name);
548+
if (dict_add(d, item) == FAIL)
549+
{
550+
dictitem_free(item);
551+
return FAIL;
552+
}
553+
func_ref(item->di_tv.vval.v_string);
554+
return OK;
555+
}
556+
534557
/*
535558
* Initializes "iter" for iterating over dictionary items with
536559
* dict_iterate_next().

src/evalfunc.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2170,6 +2170,8 @@ static funcentry_T global_functions[] =
21702170
ret_string, f_getregtype},
21712171
{"getscriptinfo", 0, 1, 0, arg1_dict_any,
21722172
ret_list_dict_any, f_getscriptinfo},
2173+
{"getstacktrace", 0, 0, 0, NULL,
2174+
ret_list_dict_any, f_getstacktrace},
21732175
{"gettabinfo", 0, 1, FEARG_1, arg1_number,
21742176
ret_list_dict_any, f_gettabinfo},
21752177
{"gettabvar", 2, 3, FEARG_1, arg3_number_string_any,

src/evalvars.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,8 @@ static struct vimvar
160160
{VV_NAME("python3_version", VAR_NUMBER), NULL, VV_RO},
161161
{VV_NAME("t_typealias", VAR_NUMBER), NULL, VV_RO},
162162
{VV_NAME("t_enum", VAR_NUMBER), NULL, VV_RO},
163-
{VV_NAME("t_enumvalue", VAR_NUMBER), NULL, VV_RO}
163+
{VV_NAME("t_enumvalue", VAR_NUMBER), NULL, VV_RO},
164+
{VV_NAME("stacktrace", VAR_LIST), &t_list_string, VV_RO},
164165
};
165166

166167
// shorthand

src/ex_eval.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -562,6 +562,10 @@ throw_exception(void *value, except_type_T type, char_u *cmdname)
562562
excp->throw_lnum = SOURCING_LNUM;
563563
}
564564

565+
excp->stacktrace = stacktrace_create();
566+
if (excp->stacktrace != NULL)
567+
excp->stacktrace->lv_refcount = 1;
568+
565569
if (p_verbose >= 13 || debug_break_level > 0)
566570
{
567571
int save_msg_silent = msg_silent;
@@ -647,6 +651,7 @@ discard_exception(except_T *excp, int was_finished)
647651
if (excp->type == ET_ERROR)
648652
free_msglist(excp->messages);
649653
vim_free(excp->throw_name);
654+
list_unref(excp->stacktrace);
650655
vim_free(excp);
651656
}
652657

@@ -671,6 +676,7 @@ catch_exception(except_T *excp)
671676
excp->caught = caught_stack;
672677
caught_stack = excp;
673678
set_vim_var_string(VV_EXCEPTION, (char_u *)excp->value, -1);
679+
set_vim_var_list(VV_STACKTRACE, excp->stacktrace);
674680
if (*excp->throw_name != NUL)
675681
{
676682
if (excp->throw_lnum != 0)
@@ -721,6 +727,7 @@ finish_exception(except_T *excp)
721727
if (caught_stack != NULL)
722728
{
723729
set_vim_var_string(VV_EXCEPTION, (char_u *)caught_stack->value, -1);
730+
set_vim_var_list(VV_STACKTRACE, caught_stack->stacktrace);
724731
if (*caught_stack->throw_name != NUL)
725732
{
726733
if (caught_stack->throw_lnum != 0)
@@ -741,6 +748,7 @@ finish_exception(except_T *excp)
741748
{
742749
set_vim_var_string(VV_EXCEPTION, NULL, -1);
743750
set_vim_var_string(VV_THROWPOINT, NULL, -1);
751+
set_vim_var_list(VV_STACKTRACE, NULL);
744752
}
745753

746754
// Discard the exception, but use the finish message for 'verbose'.

src/proto/dict.pro

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ int dict_add_string_len(dict_T *d, char *key, char_u *str, int len);
2222
int dict_add_list(dict_T *d, char *key, list_T *list);
2323
int dict_add_tv(dict_T *d, char *key, typval_T *tv);
2424
int dict_add_callback(dict_T *d, char *key, callback_T *cb);
25+
int dict_add_func(dict_T *d, char *key, ufunc_T *fp);
2526
void dict_iterate_start(typval_T *var, dict_iterator_T *iter);
2627
char_u *dict_iterate_next(dict_iterator_T *iter, typval_T **tv_result);
2728
int dict_add_dict(dict_T *d, char *key, dict_T *dict);

0 commit comments

Comments
 (0)