// 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?