Author Topic: list_tags  (Read 2527 times)

chandlerzhang

  • Junior Community Member
  • Posts: 4
  • Hero Points: 0
list_tags
« on: June 25, 2013, 01:30:56 AM »
// Copyright 2010 SlickEdit Inc.
// You may modify, copy, and distribute the Slick-C Code (modified or unmodified)
// only if all of the following conditions are met:
//   (1) You do not include the Slick-C Code in any product or application
//       designed to run independently of SlickEdit software programs;
//   (2) You do not use the SlickEdit name, logos or other SlickEdit
//       trademarks to market Your application;
//   (3) You provide a copy of this license with the Slick-C Code; and
//   (4) You agree to indemnify, hold harmless and defend SlickEdit from and
//       against any loss, damage, claims or lawsuits, including attorney's fees,
//       that arise or result from the use or distribution of Your application.
////////////////////////////////////////////////////////////////////////////////////
#pragma option(pedantic,on)
#region Imports
#include "slick.sh"
#include "tagsdb.sh"
#import "context.e"
#import "main.e"
#import "pushtag.e"
#import "recmacro.e"
#import "seek.e"
#import "seltree.e"
#import "stdprocs.e"
#import "tags.e"
#import "treeview.e"
#import "util.e"
#import "se/tags/TaggingGuard.e"
#endregion

//#define ANOTHER


boolean _istagging_supported(_str lang=null)
{
   return (_QTaggingSupported(p_window_id,lang) != 0);
}

boolean _are_locals_supported(_str lang=null)
{
   if (lang==null) {
      if (!_isEditorCtl()) {
         return(true);
      }
      lang=p_LangId;
   }
   if (lang=='') return(0);
   static _str last_lang;
   if (last_lang:==lang) {
      return(true);
   }
   status := _FindLanguageCallbackIndex('%s-list-locals',lang);
   if (status) {
      last_lang = lang;
      return(status!=0);
   }
   status = _FindLanguageCallbackIndex('%s-lvar-search',lang);
   if (status) {
      last_lang = lang;
      return(status!=0);
   }
   return(false);
}

boolean _is_background_tagging_supported(_str lang=null)
{
   if (def_background_tagging_threads == 0) return false;
   index := _FindLanguageCallbackIndex("%s_is_asynchronous_supported", lang);
   return (index > 0);
}

boolean _is_background_tagging_enabled(int option=0)
{
   if (def_background_tagging_threads == 0) return false;
   if ((def_autotag_flags2 & option) == option) return false;
   return true;
}

int find_ext_callback(_str callback_name, _str lang=null)
{
   if (lang==null) {
      if (!_isEditorCtl()) {
         return(0);
      }
      lang=p_LangId;
   }
   // use fast iterative 'C' callback instead of slick-C code
   return _FindLanguageCallbackIndex(callback_name,lang);
}

boolean ext_inherits_from(_str parent, _str lang=null)
{
   return _LanguageInheritsFrom(parent, lang)? true:false;
}
static int select_index = 0;
static   int start_line_number[];
static   int start_seekpos_number[];
static void _tagtree_callback(int reason, typeless user_data, typeless info = null)
{
   switch (reason) {
   case SL_ONINITFIRST:
      // if we have columns, then restore the widths, please
      if (ctl_tree._TreeGetNumColButtons() > 1) {
         ctl_tree._TreeRetrieveColButtonWidths(false, SELECT_TREE_RETRIEVE);
      }
      break;
   case SL_ONCLOSE:
      // save our column widths - we'll be glad we did
      if (ctl_tree._TreeGetNumColButtons() > 1) {
         ctl_tree._TreeAppendColButtonWidths(false, SELECT_TREE_RETRIEVE);
      }
#ifdef ANOTHER
      wid := p_window_id;
       p_window_id=_mdi.p_child;
       p_window_id._set_focus();
      select_index = (int)info;
      start_line_no := start_line_number[select_index];
      start_seekpos := start_seekpos_number[select_index];

      //p_RLine     = start_line_no;
      //if (start_seekpos >= 0) _GoToROffset (start_seekpos); // seekpos == -1 on 'goto line'
      goto_line(start_line_no);
      //_nrseek(start_seekpos);
      p_window_id = wid;
      p_window_id._set_focus();
#endif /* ANOTHER */
      break;
   }
}

static _str _taglist_callback(int reason,var result,typeless key)
{
   if (reason==SL_ONDEFAULT) {  // Enter key
      result=_sellist.p_line-1;
      return(1);
   }
   return("");
}

static void _TaglistGetIndexList(_str (&IndexList)[],_str (&list)[], typeless (&picList)[] = null)
{
   int i;
   for (i=0;i<list._length();++i) {
      parse list with list " - " IndexList;
      if (picList != null) {
         parse IndexList with IndexList " - " picList;
      }
   }
}

//Takes off types and appends the index to the end of the line
//Also switches function names like MYCLASS::MemberFunction() to
//MemberFunction() - MYCLASS
static void _TaglistGetNoTypeList(_str (&list)[], int (&picList)[] = null)
{
   int i;
   for (i=0;i<list._length();++i) {
      list=strip(list);
#if 0
      int paren_pos=pos('(',list);
      if (paren_pos) {
         for (;;) {
            _str ch=substr(list,paren_pos-1,1);
            if (ch!=" "&&ch!="\t") break;
            list=substr(list,1,paren_pos-2):+substr(list,paren_pos);
            paren_pos=pos('(',list);
         }
      }
      int p=pos(' ',list);
      if (p) {
         while (p < pos('(',list) && p < pos('<',list)) {
            parse list with . list;
            p=pos(' ',list);
            if (!p) break;
         }
      }
      while (substr(list,1,1)=='*') {
         list=substr(list,2);
      }
      if (pos('::',list)) {
         _str ClassName,MemberFunctionName;
         parse list with ClassName '::' MemberFunctionName;
         list=MemberFunctionName"\t"ClassName;
      }
#endif
      list=list' - 'i;
      if (picList != null) {
         list = list' - 'picList;
      }
   }
}


_command listtags() name_info(','VSARG2_READ_ONLY|VSARG2_REQUIRES_EDITORCTL|VSARG2_REQUIRES_TAGGING)
{
   int was_recording=_macro();
   int wid = p_window_id;
   if ( !_istagging_supported() ) {
      _message_box(nls("No tagging support function for '%s'",p_mode_name));
      return(1);
   }

   message(nls('Searching for procedures...'));
   _UpdateContext(true,true,VS_UPDATEFLAG_context|VS_UPDATEFLAG_statement|VS_UPDATEFLAG_list_all);

   // make sure that the context doesn't get modified by a background thread.
   se.tags.TaggingGuard sentry;
   sentry.lockContext(false);

   // need lots of lists
   _str tagnameList[];
   int  idList[];
   _str indexList[];
   int picList[];

   _str type_name;
   _str tag_name;
   _str file_name;
   _str class_name;
   _str signature;
   _str return_type;
   int start_line_no;
   int start_seekpos;
   int scope_line_no;
   int scope_seekpos;
   int end_line_no;
   int end_seekpos;
   int tag_flags;

   //
   showAllTags := true;
   int i,n=tag_get_num_of_context();
   columns := false;
   for (i=0; i<=n; i++)
   {
      // is this a function, procedure, or prototype?
      tag_get_detail2(VS_TAGDETAIL_context_type,i,type_name);
      name := tag_tree_make_caption_fast(VS_TAGMATCH_context,i,true,true,false);
      if (!((name == "{}")
            #if 1
            ||(name == "break")||(name == "else")||(name == "return")
             ||(name == "continue")||(name == "default:")
             #endif
             ))
       {
         tagnameList[tagnameList._length()]=name;
         idList[idList._length()]=i;
         tag_get_context(i,tag_name,type_name,file_name,
                         start_line_no,start_seekpos,scope_line_no,
                         scope_seekpos,end_line_no,end_seekpos,
                         class_name,tag_flags,signature,return_type);
         start_line_number= start_line_no;
         start_seekpos_number= start_seekpos;

         tag_get_detail2(VS_TAGDETAIL_context_flags,i,tag_flags);
         tag_tree_get_bitmap(0,0,type_name,'',tag_flags,auto leaf_flag,auto pic);
         picList[picList._length()] = pic;

         columns = columns || (pos("::", tagnameList[tagnameList._length() - 1]) > 0);
      }
   }

  // say(tagnameList._length());
   clear_message();
   _TaglistGetNoTypeList(tagnameList);  // Add original indexes to end of list
   //tagnameList._sort('i');
   _TaglistGetIndexList(indexList,tagnameList);
   if ( tagnameList._length() > 0 ) {
      colFlags := '';
      colNames := '';
      if (0)
      {
         colNames = ',';
         colFlags = (TREE_BUTTON_PUSHBUTTON) :+ ',' :+  (TREE_BUTTON_PUSHBUTTON);
      }
      i = (int)select_tree_zxg(tagnameList,                       // caption array
                            indexList,                         // key array
                            picList,                           // picture index array
                            picList,                           //
                            null,                              // select array
                            _tagtree_callback,                 // callback
                            null,                              // user data
                            nls("All %s tags in %s",tagnameList._length(),_strip_filename(p_buf_name,'P')),       // caption
                            SL_INVERT|SL_DELETEBUTTON|SL_MUSTEXIST|SL_COMBO |SL_SELECTCLINE | SL_XY_WIDTH_HEIGHT|SL_SELECTALL|SL_ALLOWMULTISELECT,// sl flags
                            colNames,                          // column names
                            colFlags,                          // column flags
#ifdef ANOTHER
                            false,                              // modal
#else
                            true,
#endif
                            '',                                // help item
                            'listtags');                      // retrieve name
#ifndef ANOTHER
      if (i!="" && i >= 0 && i < idList._length())
      {
         i = idList;
         #if 0
         //tag_lock_context(false);
         int result=tag_get_context(i,tag_name,type_name,file_name,
                         start_line_no,start_seekpos,scope_line_no,
                         scope_seekpos,end_line_no,end_seekpos,
                         class_name,tag_flags,signature,return_type);
         //tag_unlock_context();
         if(result < 0)
         {
            _message_box(__FILE__":"__LINE__";"i";result:"result":"tag_name";gotoline:"start_line_no":"idList._length());
         }
         #else

         start_line_no = start_line_number;
         start_seekpos = start_seekpos_number;
         //_message_box(__FILE__":"__LINE__";i:"i"start_line_no:"start_line_no);
         #endif
         
        // _str proc_name=tag_tree_compose_tag(tag_name,class_name,type_name,0,signature);
         // Need macro which does push tag in current file.
         //_macro('m',was_recording);
         //_macro_delete_line();
         //_macro_call("push_bookmark");
         //_macro_call("goto_context_tag",proc_name);
         //This made macro recording wrong
         //push_bookmark();
         goto_line(start_line_no);
         _nrseek(start_seekpos);
      }
      else
      {
         //_message_box(nls('Selet num fail'));
      }
#endif
   }
   else
   {
      _message_box(nls('No tags found'));
   }
   
   if(wid != p_window_id)
   {
#ifndef ANOTHER
      p_window_id = wid;
      p_window_id._set_focus();
#endif
   }
   
   return(1);
}

_command list_locals() name_info(','VSARG2_READ_ONLY|VSARG2_REQUIRES_EDITORCTL)
{
   int was_recording=_macro();
   if (! _are_locals_supported())
   {
      _message_box(nls("No local variable tagging support function for '%s'",p_mode_name));
      return(1);
   }

   message(nls('Searching for local variables...'));
   _UpdateContext(true,true);
   _UpdateLocals(true,true);

   // make sure that the context doesn't get modified by a background thread.
   se.tags.TaggingGuard sentry;
   sentry.lockContext(false);

   // need lots of lists
   _str tagnameList[];
   int  idList[];
   _str indexList[];
   int i, n=tag_get_num_of_locals();
   for (i=1; i<=n; i++)
   {
      // is this a function, procedure, or prototype?
      tagnameList[tagnameList._length()]=tag_tree_make_caption_fast(VS_TAGMATCH_local,i,true,true,false);
      idList[idList._length()]=i;
   }

   clear_message();
   _TaglistGetNoTypeList(tagnameList);  // Add original indexes to end of list
   tagnameList._sort('i');
   _TaglistGetIndexList(indexList,tagnameList);
   if ( tagnameList._length() > 0 )
   {
      i=show("_sellist_form -mdi -modal -reinit",
                  nls("Local Variables in Current Proc"),
                  SL_DEFAULTCALLBACK|SL_SELECTCLINE,
                  tagnameList,
                  "",
                  "",  // help item name
                  "",  // font
                  _taglist_callback  // Call back function
                 );
      if (i!="")
      {
         i = idList[(int)indexList];
         VS_TAG_BROWSE_INFO cm;
         tag_get_local_info(i, cm);
         _str proc_name=tag_tree_compose_tag(cm.member_name,
                                             cm.class_name,
                                             cm.type_name,0,
                                             cm.arguments,cm.return_type);
         // Need macro which does push tag in current file.
         _macro('m',was_recording);
         _macro_delete_line();
         _macro_call("push_bookmark");
         _macro_call("goto_context_tag",proc_name);
         //This made macro recording wrong
         push_bookmark();
         goto_line(cm.line_no);
         _nrseek(cm.seekpos);
      }
   }
   else
   {
      _message_box(nls('No local variables found'));
   }
   _UpdateLocals(true);
   return(1);
}

/**
 * Is language-specific statement tagging supported for
 * the given language?  If no language ID is passed (lang==null),
 * and the current object is an editor control, use the p_LangId
 * property.
 * <p>
 * Since list-statements is done as a part of list-tags, the
 * way to indicate that list-statements is supported for a
 * language is to implement a '[lang]-are-statements-supported'
 * function which returns 'true'.
 *
 * @param lang   (optional) language to check
 *
 * @return true if list statements is supported, false otherwise.
 */
int _are_statements_supported(_str lang=null)
{
   if (lang==null) {
      if (!_isEditorCtl()) {
         return(0);
      }
      lang=p_LangId;
   }
   if (lang=='') return(0);
   static _str last_lang;
   if (last_lang:==lang) {
      return(1);
   }
   status := _FindLanguageCallbackIndex("%s-are-statements-supported",lang);
   if (status) {
      last_lang = lang;
      return(status);
   }
   return(0);
}

_command list_statements() name_info(','VSARG2_READ_ONLY|VSARG2_REQUIRES_EDITORCTL)
{
   int was_recording=_macro();
   if (! _are_statements_supported()) {
      _message_box(nls("No statement tagging support function for '%s'",p_mode_name));
      return(1);
   }

   message(nls('Searching for statements...'));
   _UpdateContext(true,true, VS_UPDATEFLAG_context|VS_UPDATEFLAG_statement);

   // make sure that the context doesn't get modified by a background thread.
   se.tags.TaggingGuard sentry;
   sentry.lockContext(false);

   _str type_name;
   _str tag_name;
   _str file_name;
   _str class_name;
   _str signature;
   _str return_type;
   int start_line_no;
   int start_seekpos;
   int scope_line_no;
   int scope_seekpos;
   int end_line_no;
   int end_seekpos;
   int tag_flags;

   // need lots of lists
   _str tagnameList[];
   int  idList[];
   _str indexList[];

   int i, n=tag_get_num_of_context();
   // Filter out contexts
   for (i=1; i<=n; i++) {
      tag_get_detail2(VS_TAGDETAIL_context_type,i,type_name);
      if ( tag_tree_type_is_statement(type_name) ) {
         tagnameList[tagnameList._length()]=tag_tree_make_caption_fast(VS_TAGMATCH_context,i,true,true,false);
         idList[idList._length()]=i;
      }
   }

   clear_message();
   _TaglistGetNoTypeList(tagnameList);  // Add original indexes to end of list
   tagnameList._sort('i');
   _TaglistGetIndexList(indexList,tagnameList);
   if ( tagnameList._length() > 0 ) {

      i=show("_sellist_form -mdi -modal -reinit",
                  nls("Statements in Current File"),
                  SL_DEFAULTCALLBACK|SL_SELECTCLINE,
                  tagnameList,
                  "",
                  "",  // help item name
                  "",  // font
                  _taglist_callback  // Call back function
                 );
      if (i!="") {
         i = idList[(int)indexList];
         tag_get_context(i,tag_name,type_name,file_name,
                         start_line_no,start_seekpos,scope_line_no,
                         scope_seekpos,end_line_no,end_seekpos,
                         class_name,tag_flags,signature,return_type);

         _str proc_name=tag_tree_compose_tag(tag_name,"","",0,signature);
         // Need macro which does push tag in current file.
         _macro('m',was_recording);
         _macro_delete_line();
         _macro_call("push_bookmark");
         _macro_call("goto_context_tag",proc_name);
         //This made macro recording wrong
         push_bookmark();
         goto_line(start_line_no);
         _nrseek(start_seekpos);
      }
   } else {
      _message_box(nls('No statements found'));
   }

   _UpdateContext(true,true, VS_UPDATEFLAG_context|VS_UPDATEFLAG_statement);
   return(1);
}



i put all those codes above into a file ,name it listtags.e, and load it a module. then bind listtags to a shortkey. it works fine.

but i think it would be better if :
(1)make listtags dockable;
(2)when input some search string in combox and enter, listtags do not be destroyed. still there.
(3)when i switch from current buffer to other buffer, update the content of the listtags.

Any ideas?

« Last Edit: June 25, 2013, 01:33:24 AM by chandlerzhang »

Dennis

  • Senior Community Member
  • Posts: 3996
  • Hero Points: 521
Re: list_tags
« Reply #1 on: June 25, 2013, 12:47:20 PM »
If you want a dockable tool, maybe you should check out the Find Symbol tool window.