#include "stdafx.h" #include "common.h" /////////////////////////// // コード補完機能 /////////////////////////// BOOL GetComplementClass(char *pBuf,char *ClassName,char *nest,BOOL bInherits){ extern HANDLE hHeap; extern COMPLEMENT_WINDOW_INFO ComplementWndInfo; extern char *pHeaderBuf; extern char *pUserSource; int i,i2; char temporary[8192]; DWORD dwClassType; BOOL bRet; ///////////////////////////////////////// // ソースコードからクラス定義位置を取得 ///////////////////////////////////////// i=GetClassPos(pBuf,ClassName,&dwClassType); if(pBuf[i]=='\0') return 0; if(nest[0]){ //////////////////// // 入れ子構造の場合 //////////////////// //クラス、配列の構成要素を解析する char VarName[VN_SIZE]; //変数名 char array[VN_SIZE]; //第1次配列 char lpPtrOffset[VN_SIZE]; //第2次配列 char NestMember[VN_SIZE]; //入れ子メンバ int RefType; //"."参照のときは0、"->"参照のときは1 lstrcpy(VarName,nest); if(!GetVarFormatString(VarName,array,lpPtrOffset,NestMember,&RefType)) return 0; //メンバ変数の型であるクラスの名前を取得 char ClassName[VN_SIZE]; BOOL bArray; if(!GetClassNameFromClassMember(pBuf,i,VarName,ClassName,&bArray)) return 0; //TypeDef宣言を考慮してオリジナルなクラス名を取得 GetOriginalClassName(ClassName); if(!CheckReferType(ClassName,bArray,array,RefType)) return 0; //ユーザーのソースコードをサーチ bRet=GetComplementClass(pUserSource,ClassName,NestMember,0); if(!bRet){ //失敗したときはbasic.sbpをサーチ bRet=GetComplementClass(pHeaderBuf,ClassName,NestMember,0); } return bRet; } //////////////////////// // メンバ情報を取得 //////////////////////// DWORD dwAccess; DWORD dwProc; //アクセス制限の初期値をセット if(dwClassType==ESC_CLASS) dwAccess=ACCESS_PRIVATE; else dwAccess=ACCESS_PUBLIC; if(memicmp(pBuf+i,"Inherits",8)==0&&(pBuf[i+8]==' '||pBuf[i+8]=='\t')){ i+=9; while(pBuf[i]==' '||pBuf[i]=='\t') i++; //継承を行う場合 for(i2=0;;i++,i2++){ if(!IsVariableChar(pBuf[i])){ temporary[i2]=0; break; } temporary[i2]=pBuf[i]; } //ユーザーのソースコードをサーチ bRet=GetComplementClass(pUserSource,temporary,"",1); if(!bRet){ //失敗したときはbasic.sbpをサーチ bRet=GetComplementClass(pHeaderBuf,temporary,"",1); } for(;;i++){ if(pBuf[i]=='\0') break; i2=IsCommandDelimitation(pBuf,i); if(i2){ i+=i2; break; } } JumpBlank(pBuf,&i); } //メンバ変数、関数を取得 while(1){ if(pBuf[i]=='\0') break; if(memicmp(pBuf+i,"End",3)==0){ /* End Class End Type の検出 */ i2=i+3; while(pBuf[i2]==' '||pBuf[i2]=='\t') i2++; if(memicmp(pBuf+i2,"Class",5)==0&&(!IsVariableChar(pBuf[i2+5]))|| memicmp(pBuf+i2,"Interface",9)==0&&(!IsVariableChar(pBuf[i2+9]))|| memicmp(pBuf+i2,"Type",4)==0&&(!IsVariableChar(pBuf[i2+4]))) break; } if(memicmp(pBuf+i,"Abstract",8)==0&&(pBuf[i+8]==' '||pBuf[i+8]=='\t')|| memicmp(pBuf+i,"Virtual",7)==0&&(pBuf[i+7]==' '||pBuf[i+7]=='\t')|| memicmp(pBuf+i,"Override",8)==0&&(pBuf[i+8]==' '||pBuf[i+8]=='\t')|| memicmp(pBuf+i,"Function",8)==0&&(pBuf[i+8]==' '||pBuf[i+8]=='\t')|| memicmp(pBuf+i,"Sub",3)==0&&(pBuf[i+3]==' '||pBuf[i+3]=='\t')){ //メンバ関数のとき if(pBuf[i]=='a'||pBuf[i]=='A'){ i+=9; dwProc=ESC_ABSTRACT; while(pBuf[i]==' '||pBuf[i]=='\t') i++; if(memicmp(pBuf+i,"Function",8)==0&&(pBuf[i+8]==' '||pBuf[i+8]=='\t')) i+=9; else if(memicmp(pBuf+i,"Sub",3)==0&&(pBuf[i+3]==' '||pBuf[i+3]=='\t')) i+=4; } else if(pBuf[i]=='v'||pBuf[i]=='V'){ i+=8; dwProc=ESC_VIRTUAL; while(pBuf[i]==' '||pBuf[i]=='\t') i++; if(memicmp(pBuf+i,"Function",8)==0&&(pBuf[i+8]==' '||pBuf[i+8]=='\t')) i+=9; else if(memicmp(pBuf+i,"Sub",3)==0&&(pBuf[i+3]==' '||pBuf[i+3]=='\t')) i+=4; } else if(pBuf[i]=='o'||pBuf[i]=='O'){ i+=9; dwProc=ESC_OVERRIDE; while(pBuf[i]==' '||pBuf[i]=='\t') i++; if(memicmp(pBuf+i,"Function",8)==0&&(pBuf[i+8]==' '||pBuf[i+8]=='\t')) i+=9; else if(memicmp(pBuf+i,"Sub",3)==0&&(pBuf[i+3]==' '||pBuf[i+3]=='\t')) i+=4; } else if(pBuf[i]=='f'||pBuf[i]=='F'){ i+=9; dwProc=ESC_FUNCTION; } else if(pBuf[i]=='s'||pBuf[i]=='S'){ i+=4; dwProc=ESC_SUB; } while(pBuf[i]==' '||pBuf[i]=='\t') i++; } else{ //メンバ変数のとき dwProc=0; } //変数名または関数名を取得 if(pBuf[i]=='~'){ temporary[0]='~'; i2=1; i++; } else i2=0; for(;;i++,i2++){ if(!IsVariableChar(pBuf[i])){ temporary[i2]=0; break; } temporary[i2]=pBuf[i]; } if(bInherits){ //継承元の場合はコンストラクタ、デストラクタを除去 if(temporary[0]=='~') goto next; if(lstrcmp(temporary,ClassName)==0) goto next; } //次の行をサーチ for(;;i++){ if(pBuf[i]=='\0') break; if(pBuf[i]=='\''||(pBuf[i]=='/'&&pBuf[i+1]=='*')){ //コメント中 JumpBlank(pBuf,&i); break; } i2=IsCommandDelimitation(pBuf,i); if(i2){ i+=i2; break; } } JumpBlank(pBuf,&i); //重複チェック(オーバーライド関数の除去) for(i2=0;i2"参照のときは1 lstrcpy(VarName,variable); if(!GetVarFormatString(VarName,array,lpPtrOffset,NestMember,&RefType)){ HeapDefaultFree(pUserSource); pUserSource=0; return 0; } //////////////////////////////// // オブジェクトのクラス名を取得 //////////////////////////////// char ClassName[VN_SIZE]; BOOL bArray; if(!GetVariableClassName(pEditBuf,iPos,VarName,ClassName,&bArray)){ HeapDefaultFree(pUserSource); pUserSource=0; return 0; } //TypeDef宣言を考慮してオリジナルなクラス名を取得 GetOriginalClassName(ClassName); if(!CheckReferType(ClassName,bArray,array,RefType)){ HeapDefaultFree(pUserSource); pUserSource=0; return 0; } //////////////////// // クラス情報を取得 //////////////////// extern COMPLEMENT_WINDOW_INFO ComplementWndInfo; ComplementWndInfo.pMemberInfo=(MEMBERINFO *)HeapAlloc(hHeap,0,1); ComplementWndInfo.MemberNum=0; //ユーザーのソースコードをサーチ BOOL bRet; bRet=GetComplementClass(pUserSource,ClassName,NestMember,0); if(!bRet){ //失敗したときはbasic.sbpをサーチ extern char *pHeaderBuf; bRet=GetComplementClass(pHeaderBuf,ClassName,NestMember,0); } HeapDefaultFree(pUserSource); pUserSource=0; if(!bRet||ComplementWndInfo.MemberNum==0){ //見つからなかったとき DeleteComplementInfo(); return 0; } return 1; } void CodeComplement(int WndNum,int iPos){ int i,i2; //エディタ画面左端のコントロールタブ int iControlTabSpace; iControlTabSpace=MdiInfo[WndNum]->pMdiTextEdit->iWidth_ControlTabSpace; extern int font_width,font_height; POINT pos; pos=MdiInfo[WndNum]->pMdiTextEdit->StartCaretPos; GetScrollBaseCaretPos(MdiInfo[WndNum],(int *)&pos.x,(int *)&pos.y); pos.x=(pos.x-1)*font_width +iControlTabSpace; pos.y=(pos.y+1)*font_height; ClientToScreen(MdiInfo[WndNum]->pMdiTextEdit->hEdit,&pos); extern HINSTANCE hInst; extern COMPLEMENT_WINDOW_INFO ComplementWndInfo; ComplementWndInfo.hWnd=CreateWindowEx(WS_EX_DLGMODALFRAME, "ComplementWindow",NULL, WS_POPUP|WS_CLIPCHILDREN, pos.x,pos.y,100,100, hOwner,NULL,hInst,0); /////////////////////////// // リストビューの初期化 /////////////////////////// extern METHODCHECKINFO MethodCheckInfo; int height,max_width,listitem_height; max_width=0; // リストアイテムを追加 LV_ITEM lvItem; lvItem.mask = LVIF_TEXT|LVIF_IMAGE; for(i=0;ilistitem_height*MAX_COMPLEMENT_LISTNUM+dy){ size.cy=listitem_height*MAX_COMPLEMENT_LISTNUM+dy; //垂直スクロールバーの幅を考慮する size.cx+=GetSystemMetrics(SM_CXVSCROLL); } else{ //スクロールバーを使用しないようにする i=GetWindowLongPtr(ComplementWndInfo.hList,GWL_STYLE); i|=LVS_NOSCROLL; i&=~(WS_VSCROLL|WS_HSCROLL); SetWindowLongPtr(ComplementWndInfo.hList,GWL_STYLE,i); } if(pos.x+size.cx>ScreenX){ pos.x=ScreenX-size.cx; } if(pos.y+size.cy>ScreenY-30){ pos.y-=size.cy+font_height; } //サイズ変更 MoveWindow(ComplementWndInfo.hWnd, pos.x,pos.y, size.cx,size.cy,0); //チラツキを抑えながら、補完リストを表示する ShowWindow(ComplementWndInfo.hWnd,SW_SHOWNOACTIVATE); ComplementWndInfo.iPos=iPos; } //////////////////////////////// // コード補完ウィンドウ //////////////////////////////// void DrawComplementListView(HWND hListView,HDC hdc){ //コード補完リストビューの独自描画 int i; RECT rc; char temporary[1024]; RECT rcClient; GetClientRect(hListView,&rcClient); HFONT hFont; hFont=(HFONT)SendMessage(hListView,WM_GETFONT,0,0); HFONT hOldFont; hOldFont=(HFONT)SelectObject(hdc,hFont); SetBkMode(hdc,OPAQUE); for(i=0;ipMdiTextEdit->hEdit); return 0; case WM_KEYDOWN: if(LOWORD(wParam)==VK_RETURN) goto DblClk; else if(LOWORD(wParam)==VK_ESCAPE){ DestroyWindow(ComplementWndInfo.hWnd); ComplementWndInfo.hWnd=0; } break; case WM_LBUTTONDOWN: //フォーカスをエディタに戻す WndNum=GetWndNum(GetWindow(hClient,GW_CHILD)); SetFocus(MdiInfo[WndNum]->pMdiTextEdit->hEdit); LVHITTESTINFO lvHitTest; lvHitTest.pt.x=0; lvHitTest.pt.y=HIWORD(lParam); ListView_HitTest(hwnd,&lvHitTest); //アイテムを選択 ListView_SetItemState(hwnd,lvHitTest.iItem,LVIS_SELECTED|LVIS_FOCUSED,LVIS_SELECTED|LVIS_FOCUSED); return 0; case WM_LBUTTONDBLCLK: DblClk: //選択されたアイテムを取得 for(i=0;ipMdiTextEdit->buffer[i]!='\t'){ i++; break; } } GetCaretPosFromBufferIndex(MdiInfo[WndNum]->pMdiTextEdit->buffer, i, &MdiInfo[WndNum]->pMdiTextEdit->StartCaretPos); //インデント lstrcpy(temp2,ComplementWndInfo.szIndent); if(IsNeedNewIndentCommand(temporary)) lstrcat(temp2,"\t"); lstrcat(temp2,temporary); //リプレース前に補完機能を破棄する DestroyWindow(ComplementWndInfo.hWnd); ComplementWndInfo.hWnd=0; TextEdit_ReplaceUpdateUndoData(WndNum,temp2,0,1); } else{ //クラスメンバ補完 GetCaretPosFromBufferIndex(MdiInfo[WndNum]->pMdiTextEdit->buffer, ComplementWndInfo.iPos, &MdiInfo[WndNum]->pMdiTextEdit->StartCaretPos); //リプレース前に補完機能を破棄する DestroyWindow(ComplementWndInfo.hWnd); ComplementWndInfo.hWnd=0; TextEdit_ReplaceUpdateUndoData(WndNum,temporary,0,1); } } return 0; case WM_PAINT: HDC hdc; PAINTSTRUCT ps; hdc=BeginPaint(hwnd,&ps); DrawComplementListView(hwnd,hdc); EndPaint(hwnd,&ps); return 0; } return CallWindowProc(OldComplementListViewProc,hwnd,message,wParam,lParam); } LRESULT CALLBACK ComplementWindow(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam){ extern COMPLEMENT_WINDOW_INFO ComplementWndInfo; static HWND hListView; static HIMAGELIST hImageList; switch(message){ case WM_CREATE: //////////////////////// // リストビューを作成 //////////////////////// hListView=CreateWindow(WC_LISTVIEW,0, WS_CHILD|WS_VISIBLE|WS_VSCROLL| LVS_SMALLICON|LVS_SINGLESEL|LVS_SORTASCENDING|LVS_SHOWSELALWAYS, 0,0,0,0, hwnd,NULL,hInst,0); OldComplementListViewProc=(WNDPROC)GetWindowLongPtr(hListView,GWLP_WNDPROC); SetWindowLongPtr(hListView,GWLP_WNDPROC,(long)ComplementListViewProc); //フォントをセット extern METHODCHECKINFO MethodCheckInfo; SendMessage(hListView,WM_SETFONT,(long)MethodCheckInfo.hFont,0); ComplementWndInfo.hList=hListView; //背景色をセット COLORREF rgb; if(ComplementWndInfo.pMemberInfo[0].dwAccess==ACCESS_PAIRCOMMAND){ //ペアステートメント補完 rgb=RGB(245,245,255); } else{ //クラスメンバ補完 rgb=RGB(255,245,240); } ListView_SetBkColor(hListView,rgb); ListView_SetTextBkColor(hListView,rgb); //////////////////////// // イメージリストを作成 //////////////////////// hImageList=ImageList_Create(16, 16, ILC_COLOR24, 7, 0); ListView_SetImageList(hListView, hImageList, LVSIL_SMALL); ImageList_AddIcon(hImageList, ActiveBasic::Resource::LoadIconAlt(hResInst, IDI_MEMBER_PRIVATE_VARIABLE)); ImageList_AddIcon(hImageList, ActiveBasic::Resource::LoadIconAlt(hResInst, IDI_MEMBER_PUBLIC_VARIABLE)); ImageList_AddIcon(hImageList, ActiveBasic::Resource::LoadIconAlt(hResInst, IDI_MEMBER_PRIVATE_FUNCTION)); ImageList_AddIcon(hImageList, ActiveBasic::Resource::LoadIconAlt(hResInst, IDI_MEMBER_PUBLIC_FUNCTION)); ImageList_AddIcon(hImageList, ActiveBasic::Resource::LoadIconAlt(hResInst, IDI_PAIRSTATEMENT)); ImageList_AddIcon(hImageList, ActiveBasic::Resource::LoadIconAlt(hResInst, IDI_HTML_GENERAL_PARAMETER)); ImageList_AddIcon(hImageList, ActiveBasic::Resource::LoadIconAlt(hResInst, IDI_HTML_PARAMETER)); return 0; case WM_SIZE: MoveWindow(hListView,0,0,LOWORD(lParam),HIWORD(lParam),0); return 0; case WM_DESTROY: DeleteComplementInfo(); ImageList_Destroy(hImageList); return 0; case WM_NOTIFY: NMLISTVIEW *nmListView; nmListView=(NMLISTVIEW *)lParam; if(nmListView->hdr.hwndFrom==hListView){ if(nmListView->hdr.code==LVN_ITEMCHANGED){ InvalidateRect(hListView,NULL,0); return 1; } } break; } return DefWindowProc(hwnd,message,wParam,lParam); }