支持代码完成和函数提示

支持代码完成和函数提示

来自http://www.cppprog.com/2009/1111/176_4.html

VS的代码完成和函数提示功能是很值得称道的,它们可以极大地提高我们的编程效率(造成我现在写代码时往往只记住前四个字母,如果在对象后面点了小数点后不出现提示就会心慌意乱的说-_-),尽管有时也会失效。

做为IDE这个功能是绝对不能少D。即使你只打算做个编辑器,如果有这个功能那也是一大亮点啊~~(目前很多代码编辑器都没这个功能的说)。

关于函数提示的几个命令以SCI_CALLTIP作为前缀,这里只介绍我们即将使用的几个命令(更多命令见:http://scintilla.sourceforge.net/ScintillaDoc.html#CallTips

  • SCI_CALLTIPSHOW(int posStart, const char *definition) 显示提示。posStart表示显示位置,definition是显示的内容
  • SCI_CALLTIPCANCEL 取消提示
  • SCI_CALLTIPACTIVE 如果当前编辑器中有提示信息,返回1,否则返回0
  • SCI_CALLTIPSETHLT(int highlightStart, int highlightEnd) 设置提示中的高亮位置,在VS里我们输入函数实参时函数提示会高亮当前输入的参数名。

在我们程序中加入提示的最佳时机是SCN_CHARADDED(见上一节)事件。当用户输入左圆括号'('时,取得括号左边的函数名,然后显示出该函数的完整定义。

下面的代码实现了CreateWindow和MoveWindow两个API的函数提示

  1. //我们要高亮的两个函数
  2. const size_t FUNCSIZE=2;
  3. char* g_szFuncList[FUNCSIZE]={ //函数名
  4.     "CreateWindow(",
  5.     "MoveWindow("
  6. };
  7. char* g_szFuncDesc[FUNCSIZE]={ //函数信息
  8.     "HWND CreateWindow("
  9.     "LPCTSTR lpClassName,"
  10.     " LPCTSTR lpWindowName,"
  11.     " DWORD dwStyle, "
  12.     " int x,"
  13.     " int y,"
  14.     " int nWidth,"
  15.     " int nHeight, "
  16.     " HWND hWndParent,"
  17.     " HMENU hMenu,"
  18.     " HANDLE hInstance,"
  19.     " PVOID lpParam"
  20.     ")",
  21.     "BOOL MoveWindow("
  22.     "HWND hWnd,"
  23.     " int X,"
  24.     " int Y,"
  25.     " int nWidth,"
  26.     " int nHeight,"
  27.     " BOOL bRepaint"
  28.     ")"
  29. };
  30. void __fastcall TForm1::WndProc(Messages::TMessage &Message)
  31. {
  32.     TForm::WndProc(Message);
  33.     if(Message.Msg == WM_NOTIFY)
  34.     {
  35.         SCNotification* notify = (SCNotification*)Message.LParam;
  36.         ...
  37.         if(notify->nmhdr.code == SCN_CHARADDED)
  38.         {
  39.             ...
  40.             // 函数提示功能
  41.             static const char* pCallTipNextWord = NULL;//下一个高亮位置
  42.             static const char* pCallTipCurDesc = NULL;//当前提示的函数信息
  43.             if(notify->ch == '('//如果输入了左括号,显示函数提示
  44.             {
  45.                 char word[1000]; //保存当前光标下的单词(函数名)
  46.                 TextRange tr;    //用于SCI_GETTEXTRANGE命令
  47.                 int pos = SendEditor(SCI_GETCURRENTPOS); //取得当前位置(括号的位置)
  48.                 int startpos = SendEditor(SCI_WORDSTARTPOSITION,pos-1);//当前单词起始位置
  49.                 int endpos = SendEditor(SCI_WORDENDPOSITION,pos-1);//当前单词终止位置
  50.                 tr.chrg.cpMin = startpos;  //设定单词区间,取出单词
  51.                 tr.chrg.cpMax = endpos;
  52.                 tr.lpstrText = word;
  53.                 SendEditor(SCI_GETTEXTRANGE,0, sptr_t(&tr));
  54.                 
  55.                 for(size_t i=0; i<FUNCSIZE; i++) //找找有没有我们认识的函数?
  56.                 {
  57.                     if(memcmp(g_szFuncList[i],word,sizeof(g_szFuncList[i])) == 0)
  58.                     {     //找到啦,那么显示提示吧
  59.                         pCallTipCurDesc = g_szFuncDesc[i]; //当前提示的函数信息
  60.                         SendEditor(SCI_CALLTIPSHOW,pos,sptr_t(pCallTipCurDesc));//显示这个提示
  61.                         const char *pStart = strchr(pCallTipCurDesc,'(')+1; //高亮第一个参数
  62.                         const char *pEnd = strchr(pStart,',');//参数列表以逗号分隔
  63.                         if(pEnd == NULL) pEnd = strchr(pStart,')');//若是最后一个参数,后面是右括号
  64.                         SendEditor(SCI_CALLTIPSETHLT,
  65.                             pStart-pCallTipCurDesc, pEnd-pCallTipCurDesc);
  66.                         pCallTipNextWord = pEnd+1;//指向下一参数位置
  67.                         break;
  68.                     }
  69.                 }
  70.             }
  71.             else if(notify->ch == ')'//如果输入右括号,就关闭函数提示
  72.             {
  73.                 SendEditor(SCI_CALLTIPCANCEL);
  74.                 pCallTipCurDesc = NULL;
  75.                 pCallTipNextWord = NULL;                
  76.             }
  77.             else if(notify->ch == ',' && SendEditor(SCI_CALLTIPACTIVE) && pCallTipCurDesc)
  78.             {
  79.                 //输入的是逗号,高亮下一个参数
  80.                 const char *pStart = pCallTipNextWord;
  81.                 const char *pEnd = strchr(pStart,',');
  82.                 if(pEnd == NULL) pEnd = strchr(pStart,')');
  83.                 if(pEnd == NULL) //没有下一个参数啦,关闭提示
  84.                     SendEditor(SCI_CALLTIPCANCEL);
  85.                 else
  86.                 {
  87.                     SendEditor(SCI_CALLTIPSETHLT,pStart-pCallTipCurDesc, pEnd-pCallTipCurDesc);
  88.                     pCallTipNextWord = pEnd+1;
  89.                 }
  90.             }
  91.         }//if(notify->nmhdr.code == SCN_CHARADDED)
  92.         ...
  93.     }//if(Message.Msg == WM_NOTIFY)
  94. }

当然,这个提示功能相当山寨啦。比如函数名和括号之间有空格提示就不出来了,函数嵌套调用时只会提示最后一个函数的参数。关于如果改进,大家各显神通吧。

另外,还有一个提外话,在实际的使用中,我们的函数信息不可能象这里一样是写死的,而是依据用户的输入动态生成的函数名及信息列表。这就涉及到一个C++代码解析的问题(还好,只要解析函数声明就行了),对于这一点,牛X的同学可以自己写解析代码;次牛X的可以考虑用WAVE,Spirit,Regex等库帮助解析;象偶这种不牛的同学,则可以考虑利用CTAGS工具在后台线程中生成tag文件,我们从tag文件里取就可以了(当然,效率嘛~~可以参考C++Builder的函数提示效率-_-)。

代码完成和函数提示的用法类似,前缀是SCI_AUTOC,具体命令见:http://scintilla.sourceforge.net/ScintillaDoc.html#Autocompletion

直接上代码:

  1. void __fastcall TForm1::WndProc(Messages::TMessage &Message)
  2. {
  3.     TForm::WndProc(Message);
  4.     if(Message.Msg == WM_NOTIFY)
  5.     {
  6.         ...
  7.         if(notify->nmhdr.code == SCN_CHARADDED)
  8.         {
  9.             ...
  10.             if(notify->ch == '.')
  11.             {
  12.                 char word[1000]; //保存当前光标下的单词
  13.                 TextRange tr;    //用于SCI_GETTEXTRANGE命令
  14.                 int pos = SendEditor(SCI_GETCURRENTPOS); //取得当前位置
  15.                 int startpos = SendEditor(SCI_WORDSTARTPOSITION,pos-1);//当前单词起始位置
  16.                 int endpos = SendEditor(SCI_WORDENDPOSITION,pos-1);//当前单词终止位置
  17.                 tr.chrg.cpMin = startpos;  //设定单词区间,取出单词
  18.                 tr.chrg.cpMax = endpos;
  19.                 tr.lpstrText = word;
  20.                 SendEditor(SCI_GETTEXTRANGE,0, sptr_t(&tr));
  21.                 if(strcmp(word,"file.") == 0) //输入file.后提示file对象的几个方法
  22.                 {
  23.                     SendEditor(SCI_AUTOCSHOW,0,
  24.                         sptr_t(
  25.                             "close "
  26.                             "eof "
  27.                             "good "
  28.                             "open "
  29.                             "rdbuf "
  30.                             "size"
  31.                         ));
  32.                 }
  33.             }
  34.             ...

SCI_AUTOCSHOW命令的第一个参数表示已经输入了多少个字符。这对于代码自动完成是很有帮助的,比如我们可以用它帮助用户输入长串的单词,如:

  1. if(strcmp(word,"Create") == 0)
  2. {
  3.     SendEditor(SCI_AUTOCSHOW,6,//已经输入了6位字符
  4.         sptr_t(
  5.             "CreateBitmap "
  6.             "CreateDC "
  7.             "CreateHandle "
  8.             "CreateWindow "
  9.             "CreateWindowEx"
  10.         ));
  11. }

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值