#include "stdafx.h" #include "blitzide.h" #include "editor.h" static bool locked; #ifdef DEMO static const int TEXTLIMIT=16384; #else static const int TEXTLIMIT=1024*1024-1; #endif static const UINT wm_Find=RegisterWindowMessage( FINDMSGSTRING ); IMPLEMENT_DYNAMIC( Editor,CWnd ) BEGIN_MESSAGE_MAP( Editor,CWnd ) ON_WM_CREATE() ON_WM_SIZE() ON_WM_SETFOCUS() ON_WM_KILLFOCUS() ON_WM_PAINT() ON_WM_MOUSEMOVE() ON_WM_LBUTTONDOWN() ON_WM_LBUTTONUP() ON_CONTROL( EN_CHANGE,1,en_change ) ON_CONTROL( EN_UPDATE,1,en_update ) ON_NOTIFY( EN_SELCHANGE,1,en_selchange ) ON_NOTIFY( EN_PROTECTED,1,en_protected ) ON_NOTIFY( EN_MSGFILTER,1,en_msgfilter ) ON_REGISTERED_MESSAGE( wm_Find,onFind ) END_MESSAGE_MAP() static int blink; static set keyWordSet; static map keyWordMap; static bool isid( int c ){ return isalnum(c)||c=='_'; } static bool isfmt( int ch,int nxt ){ return ch==';' || ch=='\"' || isalpha(ch) || isdigit(ch) || (ch=='$' && isxdigit(nxt)); } static string rtfbgr( int bgr ){ return "\\red"+itoa(bgr&0xff)+"\\green"+itoa((bgr>>8)&0xff)+"\\blue"+itoa((bgr>>16)&0xff)+';'; } DWORD Editor::streamIn( LPBYTE buff,LONG cnt,LONG *done ){ int n=0; while( npeek()==EOF ) break; is_curs=0;is_line="";int c=0; for(;;){ c=is_stream->get(); if( c=='\r' || c=='\n' || c==EOF ) break; if( c=='\\' || c=='{' || c=='}' ) is_line+='\\'; is_line+=(char)c; } formatStreamLine();++is_linenum; if( c=='\r' && is_stream->peek()=='\n' ) is_stream->get(); if( is_stream->peek()==EOF ) is_line+='}'; } int sz=is_line.size()-is_curs; if( n+sz>cnt ) sz=cnt-n; memcpy( buff+n,is_line.data()+is_curs,sz ); is_curs+=sz;n+=sz; } *done=n; return 0; } DWORD CALLBACK Editor::streamIn( DWORD cookie,LPBYTE buff,LONG cnt,LONG *done ){ Editor *e=(Editor*)cookie; return e->streamIn( buff,cnt,done ); } DWORD CALLBACK Editor::streamOut( DWORD cookie,LPBYTE buff,LONG cnt,LONG *done ){ ostream *out=(ostream*)cookie; out->write( (char*)buff,cnt ); *done=cnt;return 0; } Editor::Editor( EditorListener *l ): listener(l),sizing(false),tabber_width(170), fmtBusy(false),findOnly(false),found(false), finder(0),selStart(0),selEnd(0), findFlags(0),lineToFmt(-1){ findBuff[0]=replaceBuff[0]=0; if( !blink ) blink=GetCaretBlinkTime(); funcList.setListener( this ); typeList.setListener( this ); labsList.setListener( this ); } Editor::~Editor(){ } void Editor::resized(){ CRect r; GetClientRect( &r ); int x=0,y=0,w=r.Width(),h=r.Height(); if( w ){ if( tabber_width<4 ) tabber_width=4; else if( w-64>0 && tabber_width>w-64 ) tabber_width=w-64; } editCtrl.MoveWindow( x,y,w-tabber_width-4,y+h ); tabber.MoveWindow( w-tabber_width+4,y,tabber_width-4,y+h ); } void Editor::OnPaint(){ CPaintDC dc( this ); CRect r; GetClientRect( &r ); int x=0,y=0,w=r.Width(),h=r.Height(); x=w-tabber_width-4; w=8; CBrush br( GetSysColor( COLOR_3DFACE ) ); CRect tr( x,y,x+w,y+h ); dc.FillRect( &tr,&br ); // CRect ar( x,y,x+w,y+w ); // dc.DrawFrameControl( &ar,DFC_SCROLL,DFCS_SCROLLRIGHT ); // y+=w;h-=w; CRect dr( x+2,y+2,x+w-2,y+h-2 ); dc.DrawEdge( &dr,EDGE_RAISED,BF_RECT ); } void Editor::OnMouseMove( UINT flags,CPoint p ){ CWnd::OnMouseMove( flags,p ); CRect r; GetClientRect( &r ); if( sizing ){ int dx=p.x-point.x,dy=p.y-point.y; tabber_width-=dx; resized();Invalidate(); point=p; }else if( abs(p.x-(r.Width()-tabber_width))<4 ){ SetCursor( AfxGetApp()->LoadStandardCursor( IDC_SIZEWE ) ); }else{ SetCursor( AfxGetApp()->LoadStandardCursor( IDC_ARROW ) ); } } void Editor::OnSize( UINT type,int sw,int sh ){ CWnd::OnSize( type,sw,sh ); resized(); } void Editor::OnLButtonDown( UINT flags,CPoint p ){ CRect r; GetClientRect( &r ); if( abs(p.x-(r.Width()-tabber_width))<4 ){ point=p; SetCapture(); SetCursor( AfxGetApp()->LoadStandardCursor( IDC_SIZEWE ) ); sizing=true; } } void Editor::OnLButtonUp( UINT flags,CPoint p ){ if( sizing ){ SetCursor( AfxGetApp()->LoadStandardCursor( IDC_ARROW ) ); ReleaseCapture(); sizing=false; } SetFocus(); } int Editor::OnCreate( LPCREATESTRUCT cs ){ CWnd::OnCreate( cs ); CHARFORMAT fmt;fmt.cbSize=sizeof( fmt ); fmt.dwMask=CFM_COLOR|CFM_PROTECTED; fmt.dwEffects=CFE_PROTECTED; fmt.crTextColor=prefs.rgb_default; PARAFORMAT pf; memset( &pf,0,sizeof( pf ) ); pf.cbSize=sizeof( pf ); pf.dwMask=PFM_TABSTOPS; pf.cTabCount=MAX_TAB_STOPS; int tabTwips=1440*8/GetDeviceCaps( ::GetDC(0),LOGPIXELSX ) * prefs.edit_tabs; for( int k=0;k>16)&0xffff,col=n&0xffff; int pos=editCtrl.LineIndex( row )+col; editCtrl.SetSel( pos,pos ); } string Editor::getName()const{ return name; } bool Editor::getText( ostream &out ){ fixFmt(true); EDITSTREAM es; es.dwCookie=(DWORD)&out; es.dwError=0; es.pfnCallback=streamOut; editCtrl.StreamOut( SF_TEXT,es ); return es.dwError==0; } void Editor::cut(){ editCtrl.Cut(); } void Editor::copy(){ editCtrl.Copy(); } void Editor::paste(){ editCtrl.PasteSpecial( CF_TEXT,0 ); } bool Editor::canCutCopy(){ getSel();return selStart!=selEnd; } bool Editor::canPaste(){ return editCtrl.CanPaste() ? true : false; } void Editor::print(){ static const int MARG=720; //1440=1 inch CPrintDialog dlg(false); int e=dlg.DoModal();if( e==IDCANCEL ) return; HDC hdc=dlg.GetPrinterDC(); if( !hdc ){ MessageBox( "Error printing" ); return; } int hr=GetDeviceCaps(hdc,HORZRES),vr=GetDeviceCaps(hdc,VERTRES); int px=GetDeviceCaps(hdc,LOGPIXELSX),py=GetDeviceCaps(hdc,LOGPIXELSY); SetMapMode(hdc,MM_TEXT); FORMATRANGE fr={0}; fr.hdc=fr.hdcTarget=hdc; fr.rcPage.left=fr.rcPage.top=0; fr.rcPage.right=(hr/px)*1440; fr.rcPage.bottom=(vr/py)*1440; //margins fr.rc.left=fr.rcPage.left+MARG; fr.rc.top=fr.rcPage.top+MARG; fr.rc.right=fr.rcPage.right-MARG; fr.rc.bottom=fr.rcPage.bottom-MARG; char buff[MAX_PATH]; strcpy( buff,name.c_str() ); DOCINFO di={sizeof(di)}; di.lpszDocName=buff; getSel(); int start=selStart,end=selEnd; if( start==end ){ start=0;end=editCtrl.GetTextLength(); } StartDoc(hdc,&di); while( startm_fr.lpstrFindWhat=findBuff; finder->m_fr.wFindWhatLen=256; finder->m_fr.lpstrReplaceWith=replaceBuff; finder->m_fr.wReplaceWithLen=256; finder->Create( findOnly=true,0,0,FR_HIDEUPDOWN,this ); found=false; } void Editor::replace(){ if( finder ) return; finder=new CFindReplaceDialog(); finder->m_fr.lpstrFindWhat=findBuff; finder->m_fr.wFindWhatLen=256; finder->m_fr.lpstrReplaceWith=replaceBuff; finder->m_fr.wReplaceWithLen=256; finder->Create( findOnly=false,0,0,FR_HIDEUPDOWN,this ); found=false; } bool Editor::canFind(){ return finder==0; } bool Editor::findNext( bool wrap ){ long start,end; editCtrl.GetSel( start,end ); FINDTEXTEX t; memset( &t,0,sizeof( t ) ); t.chrg.cpMin=end; t.chrg.cpMax=-1; t.lpstrText=findBuff; if( editCtrl.FindText( findFlags,&t )>=0 ){ editCtrl.SetSel( t.chrgText.cpMin,t.chrgText.cpMax ); return true; } if( !wrap ) return false; t.chrg.cpMin=0; t.chrg.cpMax=end; if( editCtrl.FindText( findFlags,&t )>=0 ){ editCtrl.SetSel( t.chrgText.cpMin,t.chrgText.cpMax ); return true; } string s( "Can't find \"" );s+=findBuff;s+='\"'; MessageBox( s.c_str(),"Text not found" ); if( finder ) finder->SetFocus(); return false; } void Editor::hilight( int pos ){ int row=(pos>>16)&0xffff,col=pos&0xffff; pos=editCtrl.LineIndex( row )+col; editCtrl.HideSelection( true,false ); getSel(); bool quote=false; int end=pos,len=editCtrl.GetTextLength(); while( endline.size() ) return ""; //ok, scan back until we have an isapha char preceded by a nonalnum/non '_' char for(;;){ while( pos>0 && ( !isalpha(line[pos]) || isid(line[pos-1]) ) ) --pos; if( !isalpha(line[pos]) ) return ""; int end=pos;while( endDestroyWindow(); finder=0; } LRESULT Editor::onFind( WPARAM w,LPARAM l ){ if( !finder ) return 0; findFlags=0; if( finder->MatchCase() ) findFlags|=FR_MATCHCASE; if( finder->MatchWholeWord() ) findFlags|=FR_WHOLEWORD; strcpy( findBuff,finder->GetFindString() ); strcpy( replaceBuff,finder->GetReplaceString() ); if( finder->FindNext() ){ found=findNext( true ); if( found && findOnly ) endFind(); }else if( finder->ReplaceCurrent() ){ if( found ) editCtrl.ReplaceSel( replaceBuff,true ); found=findNext( true ); }else if( finder->ReplaceAll() ){ int cnt=0; editCtrl.HideSelection( true,false ); editCtrl.SetSel( 0,0 ); while( findNext( false ) ){ editCtrl.ReplaceSel( replaceBuff,true ); ++cnt; } endFind(); char buff[32];itoa( cnt,buff,10 ); string s( buff );s+=" occurances replaced"; MessageBox( s.c_str(),"Replace All Done" ); editCtrl.HideSelection( false,false ); } if( finder && finder->IsTerminating() ) endFind(); return 0; } void Editor::caret(){ if( !prefs.edit_blkcursor ) return; long start,end; editCtrl.GetSel( start,end ); if( start==end ){ editCtrl.CreateSolidCaret( 8,13 ); editCtrl.ShowCaret(); }else editCtrl.HideCaret(); } void Editor::OnSetFocus( CWnd *wnd ){ if( prefs.edit_blkcursor ) SetCaretBlinkTime( 200 ); editCtrl.SetFocus(); caret(); } void Editor::OnKillFocus( CWnd *wnd ){ CWnd::OnKillFocus( wnd ); fixFmt(true); } string Editor::getLine( int line ){ int idx1=editCtrl.LineIndex( line ); int idx2=editCtrl.LineIndex( line+1 );if( idx2==-1 ) idx2=editCtrl.GetTextLength(); int len=idx2-idx1; char *buff=new char[ len>3 ? len+1 : 4 ]; *(int*)buff=len; int out=editCtrl.GetLine( line,buff ); buff[len]=0; string t=string( buff ); delete [] buff; return t; } void Editor::funcSelected( int line ){ int pos=editCtrl.LineIndex( line ); editCtrl.SetSel( editCtrl.GetTextLength()-1,editCtrl.GetTextLength()-1 ); editCtrl.SetSel( pos,pos ); SetFocus(); } void Editor::currentSet( Tabber *tabber,int index ){ SetFocus(); } void Editor::cursorMoved(){ listener->cursorMoved( this ); } void Editor::en_update(){ caret(); } void Editor::en_msgfilter( NMHDR *nmhdr,LRESULT *result ){ if( locked || fmtBusy ){ *result=1;return; } *result=0; getSel(); MSGFILTER *msg=(MSGFILTER*)nmhdr; if( msg->msg==WM_RBUTTONDOWN ){ CPoint p( LOWORD(msg->lParam),HIWORD(msg->lParam) ); ClientToScreen( &p ); CMenu *menu=blitzIDE.mainFrame->GetMenu(); CMenu *edit=menu->GetSubMenu(1); edit->TrackPopupMenu( TPM_LEFTALIGN,p.x,p.y,blitzIDE.mainFrame ); }else if( msg->msg==WM_CHAR ){ if( msg->wParam=='\t' ){ int lineStart=editCtrl.LineFromChar( selStart ); int lineEnd=editCtrl.LineFromChar( selEnd ); if( lineEnd<=lineStart ) return; editCtrl.HideSelection( true,false ); if( GetAsyncKeyState( VK_SHIFT )&0x80000000 ){ char buff[4]; for( int line=lineStart;linewParam==13 ){ if( selStart!=selEnd ) return; int k; int ln=editCtrl.LineFromChar( selStart ); int pos=selStart-editCtrl.LineIndex( ln ); string line=getLine( ln );if( pos>line.size() ) return; for( k=0;k0 ){ begin-=delta; funcList.relocate( begin,delta ); typeList.relocate( begin,delta ); labsList.relocate( begin,delta ); funcList.remove( begin,end ); typeList.remove( begin,end ); labsList.remove( begin,end ); }else if( delta<0 ){ int t=end-delta; funcList.remove( begin,t ); typeList.remove( begin,t ); labsList.remove( begin,t ); funcList.relocate( t,delta ); typeList.relocate( t,delta ); labsList.relocate( t,delta ); }else{ funcList.remove( begin,end ); typeList.remove( begin,end ); labsList.remove( begin,end ); } for( int n=begin;n=editCtrl.GetLineCount() ) return; lineToFmt=-1; int pos=editCtrl.LineIndex( ln ); string tline=getLine( ln ); string line=tolower( tline ); int *cf=0; string rep; for( int k=0;kpos+k ){ map::iterator it=keyWordMap.find( line.substr( from,k-from ) ); if( it!=keyWordMap.end() ){ rep=it->second;cf=&prefs.rgb_keyword; } }else lineToFmt=ln; }else if( c=='$' && k+1