Patch 9.0.0303
Problem:    It is not easy to get information about a script.
Solution:   Make getscriptinf() return the version.  When selecting a specific
            script return functions and variables. (Yegappan Lakshmanan,
            closes #10991)
Files:      runtime/doc/builtin.txt, src/scriptfile.c, src/userfunc.c,
            src/testdir/test_scriptnames.vim,
            src/testdir/test_vim9_builtin.vim,
            src/testdir/test_vim9_import.vim


*** ../vim-9.0.0302/runtime/doc/builtin.txt     2022-08-27 12:22:19.975008573 
+0100
--- runtime/doc/builtin.txt     2022-08-28 18:40:05.034457308 +0100
***************
*** 4093,4116 ****
                scripts in the order they were sourced, like what
                `:scriptnames` shows.
  
                Each item in the returned List is a |Dict| with the following
                items:
!                   autoload    set to TRUE for a script that was used with
                                `import autoload` but was not actually sourced
                                yet (see |import-autoload|).
!                   name        vim script file name.
!                   sid         script ID |<SID>|.
!                   sourced     script ID of the actually sourced script that
                                this script name links to, if any, otherwise
                                zero
!                   version     vimscript version (|scriptversion|)
! 
!               The optional Dict argument {opts} supports the following
!               items:
!                   name        script name match pattern. If specified,
!                               information about scripts with name
!                               that match the pattern "name" are returned.
  
  gettabinfo([{tabnr}])                                 *gettabinfo()*
                If {tabnr} is not specified, then information about all the
                tab pages is returned as a |List|. Each List item is a
--- 4099,4140 ----
                scripts in the order they were sourced, like what
                `:scriptnames` shows.
  
+               The optional Dict argument {opts} supports the following
+               optional items:
+                   name        Script name match pattern. If specified,
+                               and "sid" is not specified, information about
+                               scripts with name that match the pattern
+                               "name" are returned.
+                   sid         Script ID |<SID>|.  If specified, only
+                               information about the script with ID "sid" is
+                               returned and "name" is ignored.
+ 
                Each item in the returned List is a |Dict| with the following
                items:
!                   autoload    Set to TRUE for a script that was used with
                                `import autoload` but was not actually sourced
                                yet (see |import-autoload|).
!                   functions   List of script-local function names defined in
!                               the script.  Present only when a particular
!                               script is specified using the "sid" item in
!                               {opts}.
!                   name        Vim script file name.
!                   sid         Script ID |<SID>|.
!                   sourced     Script ID of the actually sourced script that
                                this script name links to, if any, otherwise
                                zero
!                   variables   A dictionary with the script-local variables.
!                               Present only when the a particular script is
!                               specified using the "sid" item in {opts}.
!                               Note that this is a copy, the value of
!                               script-local variables cannot be changed using
!                               this dictionary.
!                   version     Vimscript version (|scriptversion|)
  
+               Examples: >
+                       :echo getscriptinfo({'name': 'myscript'})
+                       :echo getscriptinfo({'sid': 15}).variables
+ <
  gettabinfo([{tabnr}])                                 *gettabinfo()*
                If {tabnr} is not specified, then information about all the
                tab pages is returned as a |List|. Each List item is a
*** ../vim-9.0.0302/src/scriptfile.c    2022-08-25 17:39:26.805017714 +0100
--- src/scriptfile.c    2022-08-28 18:44:32.757458421 +0100
***************
*** 1947,1952 ****
--- 1947,1999 ----
  }
  
  /*
+  * Return a List of script-local functions defined in the script with id
+  * 'sid'.
+  */
+     static list_T *
+ get_script_local_funcs(scid_T sid)
+ {
+     hashtab_T *functbl;
+     hashitem_T        *hi;
+     long_u    todo;
+     list_T    *l;
+ 
+     l = list_alloc();
+     if (l == NULL)
+       return NULL;
+ 
+     // Iterate through all the functions in the global function hash table
+     // looking for functions with script ID 'sid'.
+     functbl = func_tbl_get();
+     todo = functbl->ht_used;
+     for (hi = functbl->ht_array; todo > 0; ++hi)
+     {
+       ufunc_T *fp;
+ 
+       if (HASHITEM_EMPTY(hi))
+           continue;
+ 
+       --todo;
+       fp = HI2UF(hi);
+ 
+       // Add active functions with script id == 'sid'
+       if (!(fp->uf_flags & FC_DEAD) && (fp->uf_script_ctx.sc_sid == sid))
+       {
+           char_u      *name;
+ 
+           if (fp->uf_name_exp != NULL)
+               name = fp->uf_name_exp;
+           else
+               name = fp->uf_name;
+ 
+           list_append_string(l, name, -1);
+       }
+     }
+ 
+     return l;
+ }
+ 
+ /*
   * getscriptinfo() function
   */
      void
***************
*** 1956,1961 ****
--- 2003,2010 ----
      list_T    *l;
      char_u    *pat = NULL;
      regmatch_T        regmatch;
+     int               filterpat = FALSE;
+     scid_T    sid = -1;
  
      if (rettv_list_alloc(rettv) == FAIL)
        return;
***************
*** 1970,1978 ****
  
      if (argvars[0].v_type == VAR_DICT)
      {
!       pat = dict_get_string(argvars[0].vval.v_dict, "name", TRUE);
!       if (pat != NULL)
!           regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
      }
  
      for (i = 1; i <= script_items.ga_len; ++i)
--- 2019,2033 ----
  
      if (argvars[0].v_type == VAR_DICT)
      {
!       sid = dict_get_number_def(argvars[0].vval.v_dict, "sid", -1);
!       if (sid == -1)
!       {
!           pat = dict_get_string(argvars[0].vval.v_dict, "name", TRUE);
!           if (pat != NULL)
!               regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
!           if (regmatch.regprog != NULL)
!               filterpat = TRUE;
!       }
      }
  
      for (i = 1; i <= script_items.ga_len; ++i)
***************
*** 1983,1990 ****
        if (si->sn_name == NULL)
            continue;
  
!       if (pat != NULL && regmatch.regprog != NULL
!               && !vim_regexec(&regmatch, si->sn_name, (colnr_T)0))
            continue;
  
        if ((d = dict_alloc()) == NULL
--- 2038,2047 ----
        if (si->sn_name == NULL)
            continue;
  
!       if (filterpat && !vim_regexec(&regmatch, si->sn_name, (colnr_T)0))
!           continue;
! 
!       if (sid != -1 && sid != i)
            continue;
  
        if ((d = dict_alloc()) == NULL
***************
*** 1996,2001 ****
--- 2053,2074 ----
                || dict_add_bool(d, "autoload",
                                si->sn_state == SN_STATE_NOT_LOADED) == FAIL)
            return;
+ 
+       // When a filter pattern is specified to return information about only
+       // specific script(s), also add the script-local variables and
+       // functions.
+       if (sid != -1)
+       {
+           dict_T      *var_dict;
+ 
+           var_dict = dict_copy(&si->sn_vars->sv_dict, TRUE, TRUE,
+                                                               get_copyID());
+           if (var_dict == NULL
+                   || dict_add_dict(d, "variables", var_dict) == FAIL
+                   || dict_add_list(d, "functions",
+                                       get_script_local_funcs(sid)) == FAIL)
+               return;
+       }
      }
  
      vim_regfree(regmatch.regprog);
*** ../vim-9.0.0302/src/userfunc.c      2022-08-18 13:28:27.720128098 +0100
--- src/userfunc.c      2022-08-28 18:29:33.637347610 +0100
***************
*** 40,46 ****
      hash_init(&func_hashtab);
  }
  
- #if defined(FEAT_PROFILE) || defined(PROTO)
  /*
   * Return the function hash table
   */
--- 40,45 ----
***************
*** 49,55 ****
  {
      return &func_hashtab;
  }
- #endif
  
  /*
   * Get one function argument.
--- 48,53 ----
*** ../vim-9.0.0302/src/testdir/test_scriptnames.vim    2022-08-25 
17:39:26.805017714 +0100
--- src/testdir/test_scriptnames.vim    2022-08-28 18:29:33.633347632 +0100
***************
*** 32,51 ****
  " Test for the getscriptinfo() function
  func Test_getscriptinfo()
    let lines =<< trim END
      let g:loaded_script_id = expand("<SID>")
      let s:XscriptVar = [1, #{v: 2}]
!     func s:XscriptFunc()
      endfunc
    END
    call writefile(lines, 'X22script91')
    source X22script91
    let l = getscriptinfo()
    call assert_match('X22script91$', l[-1].name)
    call assert_equal(g:loaded_script_id, $"<SNR>{l[-1].sid}_")
  
!   let l = getscriptinfo({'name': '22script91'})
    call assert_equal(1, len(l))
    call assert_match('22script91$', l[0].name)
  
    let l = getscriptinfo({'name': 'foobar'})
    call assert_equal(0, len(l))
--- 32,84 ----
  " Test for the getscriptinfo() function
  func Test_getscriptinfo()
    let lines =<< trim END
+     scriptversion 3
      let g:loaded_script_id = expand("<SID>")
      let s:XscriptVar = [1, #{v: 2}]
!     func s:XgetScriptVar()
!       return s:XscriptVar
      endfunc
+     func s:Xscript_legacy_func1()
+     endfunc
+     def s:Xscript_def_func1()
+     enddef
+     func Xscript_legacy_func2()
+     endfunc
+     def Xscript_def_func2()
+     enddef
    END
    call writefile(lines, 'X22script91')
    source X22script91
    let l = getscriptinfo()
    call assert_match('X22script91$', l[-1].name)
    call assert_equal(g:loaded_script_id, $"<SNR>{l[-1].sid}_")
+   call assert_equal(3, l[-1].version)
+   call assert_equal(0, has_key(l[-1], 'variables'))
+   call assert_equal(0, has_key(l[-1], 'functions'))
  
!   " Get script information using script name
!   let l = getscriptinfo(#{name: '22script91'})
    call assert_equal(1, len(l))
    call assert_match('22script91$', l[0].name)
+   let sid = l[0].sid
+ 
+   " Get script information using script-ID
+   let l = getscriptinfo({'sid': sid})
+   call assert_equal(#{XscriptVar: [1, {'v': 2}]}, l[0].variables)
+   let funcs = ['Xscript_legacy_func2',
+         \ $"<SNR>{sid}_Xscript_legacy_func1",
+         \ $"<SNR>{sid}_Xscript_def_func1",
+         \ 'Xscript_def_func2',
+         \ $"<SNR>{sid}_XgetScriptVar"]
+   for f in funcs
+     call assert_true(index(l[0].functions, f) != -1)
+   endfor
+ 
+   " Verify that a script-local variable cannot be modified using the dict
+   " returned by getscriptinfo()
+   let l[0].variables.XscriptVar = ['n']
+   let funcname = $"<SNR>{sid}_XgetScriptVar"
+   call assert_equal([1, {'v': 2}], call(funcname, []))
  
    let l = getscriptinfo({'name': 'foobar'})
    call assert_equal(0, len(l))
***************
*** 58,63 ****
--- 91,98 ----
    call assert_true(len(l) > 1)
    call assert_fails("echo getscriptinfo('foobar')", 'E1206:')
  
+   call assert_fails("echo getscriptinfo({'sid': []})", 'E745:')
+ 
    call delete('X22script91')
  endfunc
  
*** ../vim-9.0.0302/src/testdir/test_vim9_builtin.vim   2022-08-28 
17:24:59.775549192 +0100
--- src/testdir/test_vim9_builtin.vim   2022-08-28 18:49:06.220500042 +0100
***************
*** 1898,1903 ****
--- 1898,1943 ----
  
  def Test_getscriptinfo()
    v9.CheckDefAndScriptFailure(['getscriptinfo("x")'], ['E1013: Argument 1: 
type mismatch, expected dict<any> but got string', 'E1206: Dictionary required 
for argument 1'])
+ 
+   var lines1 =<< trim END
+     vim9script
+     g:loaded_script_id = expand("<SID>")
+     var XscriptVar = [1, {v: 2}]
+     func XgetScriptVar()
+       return XscriptVar
+     endfunc
+     func Xscript_legacy_func1()
+     endfunc
+     def Xscript_def_func1()
+     enddef
+     func g:Xscript_legacy_func2()
+     endfunc
+     def g:Xscript_def_func2()
+     enddef
+   END
+   writefile(lines1, 'X22script92')
+ 
+   var lines2 =<< trim END
+     source X22script92
+     var sid = matchstr(g:loaded_script_id, '<SNR>\zs\d\+\ze_')->str2nr()
+ 
+     var l = getscriptinfo({sid: sid, name: 'ignored'})
+     assert_match('X22script92$', l[0].name)
+     assert_equal(g:loaded_script_id, $"<SNR>{l[0].sid}_")
+     assert_equal(999999, l[0].version)
+     assert_equal(0, l[0].sourced)
+     assert_equal({XscriptVar: [1, {v: 2}]}, l[0].variables)
+     var funcs = ['Xscript_legacy_func2',
+           $"<SNR>{sid}_Xscript_legacy_func1",
+           $"<SNR>{sid}_Xscript_def_func1",
+           'Xscript_def_func2',
+           $"<SNR>{sid}_XgetScriptVar"]
+     for f in funcs
+       assert_true(index(l[0].functions, f) != -1)
+     endfor
+   END
+   v9.CheckDefAndScriptSuccess(lines2)
+   delete('X22script92')
  enddef
  
  def Test_gettabinfo()
*** ../vim-9.0.0302/src/testdir/test_vim9_import.vim    2022-08-25 
17:39:26.805017714 +0100
--- src/testdir/test_vim9_import.vim    2022-08-28 18:29:33.633347632 +0100
***************
*** 741,746 ****
--- 741,747 ----
    assert_true(len(l) == 1)
    assert_match('XrelautoloadExport.vim$', l[0].name)
    assert_false(l[0].autoload)
+   assert_equal(999999, l[0].version)
  
    unlet g:result
    delete('XrelautoloadExport.vim')
*** ../vim-9.0.0302/src/version.c       2022-08-28 17:59:02.544645487 +0100
--- src/version.c       2022-08-28 18:31:19.952775900 +0100
***************
*** 709,710 ****
--- 709,712 ----
  {   /* Add new patch number below this line */
+ /**/
+     303,
  /**/

-- 
-- 
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php

--- 
You received this message because you are subscribed to the Google Groups 
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/vim_dev/20220828175506.C2F2C1C08A0%40moolenaar.net.

Raspunde prin e-mail lui