Mirror of the Vim source from https://github.com/vim/vim
リビジョン | a10936038ec94f4ce9fec5d7fae57468f5b66c35 (tree) |
---|---|
日時 | 2022-01-18 05:15:02 |
作者 | Bram Moolenaar <Bram@vim....> |
コミッター | Bram Moolenaar |
patch 8.2.4123: complete function cannot be import.Name
Commit: https://github.com/vim/vim/commit/15d1635e50896002fbd4ebbc896b78a155b2487d
Author: Bram Moolenaar <Bram@vim.org>
Date: Mon Jan 17 20:09:08 2022 +0000
@@ -626,6 +626,63 @@ | ||
626 | 626 | } |
627 | 627 | |
628 | 628 | /* |
629 | + * "*arg" points to what can be a function name in the form of "import.Name" or | |
630 | + * "Funcref". Return the name of the function. Set "tofree" to something that | |
631 | + * was allocated. | |
632 | + * If "verbose" is FALSE no errors are given. | |
633 | + * Return NULL for any failure. | |
634 | + */ | |
635 | + static char_u * | |
636 | +deref_function_name( | |
637 | + char_u **arg, | |
638 | + char_u **tofree, | |
639 | + evalarg_T *evalarg, | |
640 | + int verbose) | |
641 | +{ | |
642 | + typval_T ref; | |
643 | + char_u *name = *arg; | |
644 | + | |
645 | + ref.v_type = VAR_UNKNOWN; | |
646 | + if (eval7(arg, &ref, evalarg, FALSE) == FAIL) | |
647 | + return NULL; | |
648 | + if (*skipwhite(*arg) != NUL) | |
649 | + { | |
650 | + if (verbose) | |
651 | + semsg(_(e_trailing_characters_str), *arg); | |
652 | + name = NULL; | |
653 | + } | |
654 | + else if (ref.v_type == VAR_FUNC && ref.vval.v_string != NULL) | |
655 | + { | |
656 | + name = ref.vval.v_string; | |
657 | + ref.vval.v_string = NULL; | |
658 | + *tofree = name; | |
659 | + } | |
660 | + else if (ref.v_type == VAR_PARTIAL && ref.vval.v_partial != NULL) | |
661 | + { | |
662 | + if (ref.vval.v_partial->pt_argc > 0 | |
663 | + || ref.vval.v_partial->pt_dict != NULL) | |
664 | + { | |
665 | + if (verbose) | |
666 | + emsg(_(e_cannot_use_partial_here)); | |
667 | + name = NULL; | |
668 | + } | |
669 | + else | |
670 | + { | |
671 | + name = vim_strsave(partial_name(ref.vval.v_partial)); | |
672 | + *tofree = name; | |
673 | + } | |
674 | + } | |
675 | + else | |
676 | + { | |
677 | + if (verbose) | |
678 | + semsg(_(e_not_callable_type_str), name); | |
679 | + name = NULL; | |
680 | + } | |
681 | + clear_tv(&ref); | |
682 | + return name; | |
683 | +} | |
684 | + | |
685 | +/* | |
629 | 686 | * Call some Vim script function and return the result in "*rettv". |
630 | 687 | * Uses argv[0] to argv[argc - 1] for the function arguments. argv[argc] |
631 | 688 | * should have type VAR_UNKNOWN. |
@@ -640,15 +697,27 @@ | ||
640 | 697 | { |
641 | 698 | int ret; |
642 | 699 | funcexe_T funcexe; |
700 | + char_u *arg; | |
701 | + char_u *name; | |
702 | + char_u *tofree = NULL; | |
643 | 703 | |
644 | 704 | rettv->v_type = VAR_UNKNOWN; // clear_tv() uses this |
645 | 705 | CLEAR_FIELD(funcexe); |
646 | 706 | funcexe.fe_firstline = curwin->w_cursor.lnum; |
647 | 707 | funcexe.fe_lastline = curwin->w_cursor.lnum; |
648 | 708 | funcexe.fe_evaluate = TRUE; |
649 | - ret = call_func(func, -1, rettv, argc, argv, &funcexe); | |
709 | + | |
710 | + // The name might be "import.Func" or "Funcref". | |
711 | + arg = func; | |
712 | + name = deref_function_name(&arg, &tofree, &EVALARG_EVALUATE, FALSE); | |
713 | + if (name == NULL) | |
714 | + name = func; | |
715 | + | |
716 | + ret = call_func(name, -1, rettv, argc, argv, &funcexe); | |
717 | + | |
650 | 718 | if (ret == FAIL) |
651 | 719 | clear_tv(rettv); |
720 | + vim_free(tofree); | |
652 | 721 | |
653 | 722 | return ret; |
654 | 723 | } |
@@ -3979,57 +4048,16 @@ | ||
3979 | 4048 | if (**arg != '(' && alias == NULL |
3980 | 4049 | && (paren = vim_strchr(*arg, '(')) != NULL) |
3981 | 4050 | { |
3982 | - typval_T ref; | |
3983 | - | |
3984 | 4051 | *arg = name; |
3985 | 4052 | *paren = NUL; |
3986 | - ref.v_type = VAR_UNKNOWN; | |
3987 | - if (eval7(arg, &ref, evalarg, FALSE) == FAIL) | |
4053 | + name = deref_function_name(arg, &tofree, evalarg, verbose); | |
4054 | + if (name == NULL) | |
3988 | 4055 | { |
3989 | 4056 | *arg = name + len; |
3990 | 4057 | ret = FAIL; |
3991 | 4058 | } |
3992 | - else if (*skipwhite(*arg) != NUL) | |
3993 | - { | |
3994 | - if (verbose) | |
3995 | - semsg(_(e_trailing_characters_str), *arg); | |
3996 | - ret = FAIL; | |
3997 | - } | |
3998 | - else if (ref.v_type == VAR_FUNC && ref.vval.v_string != NULL) | |
3999 | - { | |
4000 | - name = ref.vval.v_string; | |
4001 | - ref.vval.v_string = NULL; | |
4002 | - tofree = name; | |
4059 | + else | |
4003 | 4060 | len = STRLEN(name); |
4004 | - } | |
4005 | - else if (ref.v_type == VAR_PARTIAL && ref.vval.v_partial != NULL) | |
4006 | - { | |
4007 | - if (ref.vval.v_partial->pt_argc > 0 | |
4008 | - || ref.vval.v_partial->pt_dict != NULL) | |
4009 | - { | |
4010 | - emsg(_(e_cannot_use_partial_here)); | |
4011 | - ret = FAIL; | |
4012 | - } | |
4013 | - else | |
4014 | - { | |
4015 | - name = vim_strsave(partial_name(ref.vval.v_partial)); | |
4016 | - tofree = name; | |
4017 | - if (name == NULL) | |
4018 | - { | |
4019 | - ret = FAIL; | |
4020 | - name = *arg; | |
4021 | - } | |
4022 | - else | |
4023 | - len = STRLEN(name); | |
4024 | - } | |
4025 | - } | |
4026 | - else | |
4027 | - { | |
4028 | - if (verbose) | |
4029 | - semsg(_(e_not_callable_type_str), name); | |
4030 | - ret = FAIL; | |
4031 | - } | |
4032 | - clear_tv(&ref); | |
4033 | 4061 | *paren = '('; |
4034 | 4062 | } |
4035 | 4063 |
@@ -580,6 +580,29 @@ | ||
580 | 580 | nunmap <F3> |
581 | 581 | enddef |
582 | 582 | |
583 | +def Test_use_import_in_completion() | |
584 | + var lines =<< trim END | |
585 | + vim9script | |
586 | + export def Complete(..._): list<string> | |
587 | + return ['abcd'] | |
588 | + enddef | |
589 | + END | |
590 | + writefile(lines, 'Xscript.vim') | |
591 | + | |
592 | + lines =<< trim END | |
593 | + vim9script | |
594 | + import './Xscript.vim' | |
595 | + | |
596 | + command -nargs=1 -complete=customlist,Xscript.Complete Cmd echo 'ok' | |
597 | + feedkeys(":Cmd ab\<Tab>\<C-B>#\<CR>", 'xnt') | |
598 | + assert_equal('#Cmd abcd', @:) | |
599 | + END | |
600 | + CheckScriptSuccess(lines) | |
601 | + | |
602 | + delcommand Cmd | |
603 | + delete('Xscript.vim') | |
604 | +enddef | |
605 | + | |
583 | 606 | def Test_export_fails() |
584 | 607 | CheckScriptFailure(['export var some = 123'], 'E1042:') |
585 | 608 | CheckScriptFailure(['vim9script', 'export var g:some'], 'E1022:') |
@@ -3119,18 +3119,30 @@ | ||
3119 | 3119 | |
3120 | 3120 | /* |
3121 | 3121 | * Return TRUE if "name" looks like a builtin function name: starts with a |
3122 | - * lower case letter and doesn't contain AUTOLOAD_CHAR or ':'. | |
3122 | + * lower case letter, doesn't contain AUTOLOAD_CHAR or ':', no "." after the | |
3123 | + * name. | |
3123 | 3124 | * "len" is the length of "name", or -1 for NUL terminated. |
3124 | 3125 | */ |
3125 | 3126 | int |
3126 | 3127 | builtin_function(char_u *name, int len) |
3127 | 3128 | { |
3128 | - char_u *p; | |
3129 | + int i; | |
3129 | 3130 | |
3130 | 3131 | if (!ASCII_ISLOWER(name[0]) || name[1] == ':') |
3131 | 3132 | return FALSE; |
3132 | - p = vim_strchr(name, AUTOLOAD_CHAR); | |
3133 | - return p == NULL || (len > 0 && p > name + len); | |
3133 | + for (i = 0; name[i] != NUL && (len < 0 || i < len); ++i) | |
3134 | + { | |
3135 | + if (name[i] == AUTOLOAD_CHAR) | |
3136 | + return FALSE; | |
3137 | + if (!eval_isnamec(name[i])) | |
3138 | + { | |
3139 | + // "name.something" is not a builtin function | |
3140 | + if (name[i] == '.') | |
3141 | + return FALSE; | |
3142 | + break; | |
3143 | + } | |
3144 | + } | |
3145 | + return TRUE; | |
3134 | 3146 | } |
3135 | 3147 | |
3136 | 3148 | int |
@@ -751,6 +751,8 @@ | ||
751 | 751 | static int included_patches[] = |
752 | 752 | { /* Add new patch number below this line */ |
753 | 753 | /**/ |
754 | + 4123, | |
755 | +/**/ | |
754 | 756 | 4122, |
755 | 757 | /**/ |
756 | 758 | 4121, |