// assumes tabs aren't going to get reset yet
#define STRICT 
#include <windows.h>
#include <commctrl.h>
#include "header.h"
#include <richedit.h>

typedef struct {
   HWND tooltip ;
   RECT ttrect ;
   char ttident[256] ;
   int ttlineno ;
	int startpos ;
	int endpos ;
	int startline ;
	int endline ;
	char inserting ;
	char shifted ;
	char selecting ;
	char control ;
} EDITDATA ;
typedef struct {
	char *text;
	int len ;
	COLORREF *color ;
} KEYLIST ;
COLORREF keywordColor = 0xff0000 ;
COLORREF numberColor = 0x0000ff ;
COLORREF commentColor = 0x00c000 ;
COLORREF stringColor = 0xffff00 ;
COLORREF escapeColor = 0x0000ff ;
COLORREF backgroundColor = 0xffffff ;
COLORREF textColor = 0 ;

int tabs = 4 ;
int txtFontHeight ;

#define LEFTMARGIN 5

extern enum DebugState uState ;
extern HINSTANCE hInstance ;
extern CONTEXT StoppedRegs ;
extern PROJLIST *selectedProject ;

static WNDPROC oldproc ;
static int wndoffs ;
static HFONT hFont ;
static LOGFONT lf ;
static KEYLIST C_keywordList[] = { 
	{ "int", 3, &keywordColor },
	{ "char", 4, &keywordColor },
	{ "long", 4, &keywordColor },
	{ "float" , 5 , &keywordColor },
	{ "double", 6, &keywordColor } ,
	{ "return", 6, &keywordColor },
	{ "struct", 6, &keywordColor },
	{ "union", 5, &keywordColor },
	{ "typedef",7, &keywordColor },
	{ "enum" , 4, &keywordColor },
	{ "static",6,&keywordColor },
	{ "auto", 4, &keywordColor },
	{ "sizeof", 6, &keywordColor },
	{ "do",2,&keywordColor },
	{ "if",2,&keywordColor },
	{ "else",4,&keywordColor },
	{ "for",3,&keywordColor },
	{ "switch",6,&keywordColor },
	{ "while",5,&keywordColor },
	{ "short",5,&keywordColor },
	{ "extern",6,&keywordColor },
	{ "case",4,&keywordColor },
	{ "goto",4,&keywordColor },
	{ "default",7,&keywordColor },
	{ "register",8,&keywordColor },
	{ "unsigned",8,&keywordColor },
	{ "break",5,&keywordColor },
	{ "continue",8,&keywordColor } ,
	{ "void",4,&keywordColor },
	{ "volatile",8,&keywordColor },
	{ "const",5,&keywordColor },
	{ "virtual",7,&keywordColor },
	{ "public",6,&keywordColor },
	{ "private",7,&keywordColor },
	{ "protected",9,&keywordColor },
	{ "class",5,&keywordColor },
	{ "friend",6,&keywordColor },
	{ "this",4,&keywordColor },
	{ "operator",8,&keywordColor },
	{ "new",3,&keywordColor },
	{ "delete",6,&keywordColor },
	{ "inline",6,&keywordColor },
	{ "try",3,&keywordColor },
	{ "catch", 5, &keywordColor },
	{ "template",8,&keywordColor },
	{ "throw",5,&keywordColor } ,
	{ "namespace",9,&keywordColor },
	{ "bool", 4, &keywordColor },
	{ "true", 4, &numberColor } ,
	{ "false", 5, &numberColor },
	{ "#include",8,&escapeColor },
	{ "#define", 7,&escapeColor },
	{ "#if",3,&escapeColor },
	{ "#else",5,&escapeColor },
	{ "#elseif",7,&escapeColor },
	{ "#endif",6,&escapeColor },
	{ "#ifdef",6,&escapeColor },
	{ "#ifndef",7,&escapeColor },
	{ "defined",7,&keywordColor },
	{ 0, 0}
} ;
void saveColors(void)
{
   IntToProfile("KeywordColor",keywordColor) ;
   IntToProfile("NumberColor",numberColor) ;
   IntToProfile("CommentColor",commentColor) ;
   IntToProfile("StringColor",stringColor) ;
   IntToProfile("EscapeColor",escapeColor) ;
   IntToProfile("BackgroundColor",backgroundColor) ;
   IntToProfile("TextColor",textColor) ;
}
void restoreColors(void)
{
   keywordColor = ProfileToInt("KeywordColor", keywordColor) ;
   numberColor = ProfileToInt("NumberColor", numberColor) ;
   commentColor = ProfileToInt("CommentColor", commentColor) ;
   stringColor = ProfileToInt("StringColor", stringColor) ;
   escapeColor = ProfileToInt("EscapeColor", escapeColor) ;
   backgroundColor = ProfileToInt("BackgroundColor", backgroundColor) ;
   textColor = ProfileToInt("TextColor", textColor) ;
}
static void Colorize(HWND hwnd, int start, int len, int color, int italic)
{
	CHARFORMAT cf ;
	memset(&cf,0,sizeof(cf)) ;
	cf.cbSize = sizeof(cf) ;
	cf.dwMask = CFM_COLOR | CFM_ITALIC | CFM_BOLD;
	if (italic)
		cf.dwEffects |= CFE_ITALIC ;
	if (!color)
		cf.dwEffects |= CFE_AUTOCOLOR ;
	else {
		if (!italic)
			cf.dwEffects |= CFE_BOLD ;
		cf.crTextColor = color ;
	}
	SendMessage(hwnd,EM_SETSEL,start,start+len) ;
	SendMessage(hwnd, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM) &cf) ;
//   ExtendedMessageBox("hi",0,"%x %d %d",color, start, len) ;
}
static void SearchKeywords(HWND hwnd, char *buf, int chars, int start)
{
	KEYLIST *p = C_keywordList ;
	int i ;
	buf[chars] = 0 ;
	while (p->text) {
		char *t = buf ;
		while ((t = strstr(t,p->text)) && t < buf + start + chars) {
			if ((t == buf || !isalnum(t[-1])) && !isalnum(t[p->len]))
				Colorize(hwnd,start+t-buf,p->len,*p->color,FALSE) ;
			t += p->len ;
		}
		p++ ;
	}
	for (i=0; i < chars; i++)
		if (isdigit(buf[i])) {
			if (!i || !isalpha(buf[i-1])) {
				int j = i ;
				char c = buf[i++] ;
				if (isdigit(buf[i]) || buf[i] == 'x' && c == '0') {
					i++ ;
					while (isdigit(buf[i])) 
						i++ ;
				}
				Colorize(hwnd,start+j,i-j,numberColor,FALSE) ;
				i-- ;
			}
		}
	for (i=0; i < chars; i++) {
		if (buf[i] == '"' || buf[i] == '\'') {
			int ch = buf[i] ;
			int j = i++ ;
			while (buf[i] && buf[i] != ch)
				i++ ;
			Colorize(hwnd,start+j+1,i-j-1,stringColor,FALSE) ;
		}
	}
				
				
}
char *GetEditData(HWND hwnd) ;

static void FormatBuffer(HWND hwnd, char *buf,int start, int len)
{
	if (buf) {
      char *t=buf+start ;
      int type ;
		while (t < buf + len) {
			char *t1 = strstr(t,"/*") ;
         char *t2 = strstr(t,"//") ;
			if (!t1 || t1 > buf + len)
				t1 = buf + len;
         if (!t2 || t2 > buf + len)
            t2 = buf + len ;
         if (t2 < t1) {
            t1 = t2 ;
            type = 1 ;
         } else
            type = 0 ;
         if (t1 != t) 
            SearchKeywords(hwnd,t,t1-t,t-buf) ;
         if (t1 != buf + len) {
            if (type) {
               t = strstr(t1+2,"\n") ;
               if (!t || t > buf+len-1)
                  t = buf + len-1 ;
            } else {
               t = strstr(t1+2,"*/") ;
               if (!t || t > buf+len-2)
                  t = buf + len-2 ;
            }
				Colorize(hwnd,t1-buf,t-t1+2,commentColor,TRUE) ;
            if (type)
               t++ ;
            else
               t += 2 ;
			} else
				t = buf + len ;
		}
	}
}
static void FormatLine(HWND hwnd)
{
	char *buf = GetEditData(hwnd);
	char *s ;
	if (buf) {
		int start,end,xstart,xend,ystart,found = FALSE ;
		SendMessage(hwnd, EM_GETSEL, (WPARAM) &start,(LPARAM) &end) ;

		SendMessage(hwnd, EM_HIDESELECTION,1,0) ;
		xend = start ;
		xstart = start ;
		while (xstart && buf[xstart] != '\n')
			xstart -- ;
		while (buf[xend] && buf[xend] != '\r')
			xend++ ;
		ystart = xstart ;
		while (xstart) {
			while (xstart && buf[--xstart] != '*') ;
			if (!xstart)
				break ;
			if (buf[xstart+1] == '/')
				xstart = 0 ;
			else if (buf[xstart-1] == '/') {
				xstart-- ;
				found = TRUE ;
				break ;
			}
		}
		if (!found)
			xstart = ystart ;
		Colorize(hwnd,xstart,xend-xstart,textColor,FALSE) ;
		FormatBuffer(hwnd,buf,xstart,xend) ;
		SendMessage(hwnd, EM_HIDESELECTION,0,0) ;
		SendMessage(hwnd, EM_SETSEL, start, end) ;
	  free(buf) ;
	}
}
static int CuttingComment(HWND hwnd)
{
	char *buf = GetEditData(hwnd) ;
	if (buf) {
		int start,end ;
		char *x,*y;
		SendMessage(hwnd,EM_GETSEL,(WPARAM)&start,(LPARAM)&end) ;
	 	start--;
		x =strstr(buf+start,"/*") ;
		y =strstr(buf+start,"*/") ;
		free(buf) ;
		return x && x < buf+end || y && y < buf+ end ;
	}
	return TRUE ;
}
static void CutComment(HWND hwnd, int key, int iscomment)
{
	char *buf = GetEditData(hwnd) ;
	if (buf) {
		if (!iscomment)
			FormatLine(hwnd) ;
		else {
			int start,end ;
			int xstart,xend,ystart,yend ;
			SendMessage(hwnd,EM_GETSEL,(WPARAM)&start,(LPARAM)&end) ;

			SendMessage(hwnd, EM_HIDESELECTION,1,0) ;
			xstart = xend = start ;
			while (xstart && buf[xstart] != '\n') 
				xstart-- ;
			ystart = xstart ;
			while (TRUE) {
				while (xstart && buf[--xstart] != '*')  ;
				if (xstart == 0 || buf[xstart+1] == '/') {
					xstart = ystart ;
					break ;	
				} else if (xstart && buf[xstart-1] == '/') {
					xstart-- ;
					break ;
				}
			}
			while (buf[xend] && buf[xend] != '\r')
				xend++ ;
			yend = xend ;
			while (TRUE) {
				while (buf[xend] && buf[++xend] != '*') ;
				if (!buf[xend] || buf[xend+1] == '/') {
					xend++ ;
					break ;
				}
				if (buf[xend-1] == '/') {
					xend-- ;
					break ;
				}
			}
			Colorize(hwnd,xstart,xend-xstart,textColor,FALSE) ;
			FormatBuffer(hwnd,buf,xstart,xend) ;
			SendMessage(hwnd, EM_HIDESELECTION,0,0) ;
			SendMessage(hwnd, EM_SETSEL, start, end) ;
		}
		free(buf) ;
	}
}
static void PasteComment(HWND hwnd)
{
}
static int AddedComment(HWND hwnd, int key) 
{
	int starting = -1, ending = -1 ;
	char *buf = GetEditData(hwnd) ;
	if (buf) {
		int start,end ;
		SendMessage(hwnd,EM_GETSEL,(WPARAM)&start,(LPARAM)&end) ;
		if (buf[start-1] == '*') {
			if (buf[start-2] == '/')
				starting = start-2 ;
			else if (buf[start] == '/')
				ending = start-1 ;
		} else if (buf[start-1] == '/') {
			if (buf[start-2] == '*')
				ending = start - 2 ;
			else if (buf[start] == '*')
				starting = start-1 ;
		}
				
		SendMessage(hwnd, EM_HIDESELECTION,1,0) ;
		if (starting != -1) {
			char *t = strstr(buf+starting+2,"*/") ;
			if (!t)
				t = buf + strlen(buf) ;
			FormatBuffer(hwnd,buf, starting, t-buf+2) ;
		} else if (ending != -1) {
			char *t = strstr(buf+ending+2,"/*") ;
			if (!t)
				t = buf + strlen(buf) ;
			Colorize(hwnd,ending,t-buf-ending,textColor,FALSE) ;
			Colorize(hwnd,ending,2,commentColor,2) ;
			FormatBuffer(hwnd,buf, ending,t- buf+2) ;
		}
		SendMessage(hwnd, EM_HIDESELECTION,0,0) ;
		SendMessage(hwnd,EM_SETSEL,start,end) ;
	  free(buf) ;
	}
	return !(starting == ending) ;
	
}
static void NullTip(EDITDATA *p, HWND edwin) 
{
   TOOLINFO t ;
      t.rect.left = p->ttrect.left = 0 ;
      t.rect.right = p->ttrect.right = 0 ; 
      t.rect.top = p->ttrect.top = 0;
      t.rect.bottom = p->ttrect.bottom = 0 ;
      t.cbSize = sizeof(TOOLINFO) ;
      t.uFlags = 0 ;
      t.hwnd = edwin ;
      t.uId = 10000 ;
      t.hinst = hInstance ;
      t.lpszText = "" ;
      SendMessage(p->tooltip, TTM_SETTOOLINFO, 0 , (LPARAM)&t) ;
}
int GetWordFromPos(HWND hwnd, char *outputbuf, int charpos, int *linenum, int *startoffs, int *endoffs)
{
   int linepos ;
   int linecharpos ;
   int linecharindex ;
   char buf[1000] ;   
   struct {
      long min,max ;
   } charrange ;
   if (charpos == -1) {
      SendMessage(hwnd,EM_EXGETSEL,(WPARAM) 0, (LPARAM) &charrange) ;
      charpos = charrange.min ;
   }
   linepos = SendMessage(hwnd,EM_LINEFROMCHAR,(WPARAM)charpos,0) ;
   linecharindex = SendMessage(hwnd, EM_LINEINDEX,linepos,0) ;
   linecharpos = charpos - linecharindex;
   *(short *)buf = 1000 ;
   SendMessage(hwnd,EM_GETLINE,linepos,(LPARAM)buf) ;
   while (linecharpos && buf[linecharpos] == ' ' || buf[linecharpos] == '\n' || buf[linecharpos] == '\t' || buf[linecharpos] == 0) 
      linecharpos-- ;
   {
      char *start = buf + linecharpos, *end = start ;
      if (start > buf) {
         start -- ;

         if (start == buf) {
            if (!isalnum(*start) && *start != '_')
               start++ ;
         } else while (start > buf) {
            if (!isalnum(*start) && *start != '_') {
               start++ ;
               break ;
            }
            start--;
         }
         if (!isalnum(*start) && *start != '_')
            start++ ;
      }
      while (*end && (isalnum(*end) || *end == '_'))
         end++ ;
      *end = 0 ;
      if (linenum)
         *linenum = linepos ;
      if (startoffs)
         *startoffs = start - buf + linecharindex ;
      if (endoffs)
         *endoffs = end - buf + linecharindex ;
      strcpy(outputbuf,start) ;
      return TRUE ;
   }
}
static void DoHelp(HWND edwin)
{
   char buf[256] ;   
   if (!GetWordFromPos(edwin,buf,-1,0,0,0)) 
      return ;
   else
      ShowHelp(buf) ;
}
static void RunToolTip(EDITDATA *p, HWND edwin,int x, int y)
{
   static int semaphore ;
   int charpos ;
   int linepos ;
   int left, right ;
   int start, end ;
   TOOLINFO t ;
   POINT pt,lpt,rpt ;

   pt.x = x ;
   pt.y = y ;

   if (semaphore)
      return ;
   semaphore = TRUE ;
   if (uState == notDebugging || uState == Running) {
      NullTip(p,edwin) ;
      semaphore = FALSE ;
      return ;
   }
   if (p->ttrect.left <= x && p->ttrect.right > x && p->ttrect.top <= y &&
         p->ttrect.bottom > y) {
      semaphore = FALSE ;
      return ;
   }
   charpos = SendMessage(edwin,EM_CHARFROMPOS,0,(LPARAM)&pt) ;
   if (!GetWordFromPos(edwin,p->ttident,charpos,&linepos,&start,&end))
      NullTip(p,edwin) ;
   else {
      POINTL point1, point2 ;
      p->ttlineno = linepos + 1;
      SendMessage(edwin,EM_POSFROMCHAR,(WPARAM)&point1,(LPARAM)(start)) ;
      left = point1.x ;
      SendMessage(edwin,EM_POSFROMCHAR,(WPARAM)&point2,(LPARAM)(end)) ;
      right = point2.x ;
      t.rect.left = p->ttrect.left = left ;
      t.rect.right = p->ttrect.right = right;
      t.rect.top = p->ttrect.top = point1.y ;
      t.rect.bottom = p->ttrect.bottom = t.rect.top + txtFontHeight ;
      t.cbSize = sizeof(TOOLINFO) ;
      t.uFlags = 0 ;
      t.hwnd = edwin ;
      t.uId = 10000 ;
      t.hinst = hInstance ;
      t.lpszText = LPSTR_TEXTCALLBACK ;
      SendMessage(p->tooltip, TTM_SETTOOLINFO, 0 , (LPARAM)&t) ;
   }
   semaphore = FALSE ;
}
static void SendMessageToToolTip(HWND ttwin, HWND hwnd, UINT iMessage, 
               WPARAM wparam ,LPARAM lparam)
{
   MSG msg ;
   msg.hwnd = hwnd ;
   msg.message = iMessage ;
   msg.wParam = wparam ;
   msg.lParam = lparam ;
   msg.time = 0 ;
   msg.pt.x = LOWORD(lparam) ;
   msg.pt.y = HIWORD(lparam) ;
   SendMessage(ttwin,TTM_RELAYEVENT,0,(LPARAM)&msg) ;
}
LRESULT  CALLBACK exeditProc( HWND hwnd, UINT iMessage, WPARAM wParam,
																		LPARAM lParam)
{
   static char buffer[1024] ;
   TOOLINFO t ;
	EDITDATA * p ;
   DWINFO *x ;
	int stop ;
	char *data, *buf ;
	LRESULT rv ;
	int i,linecount,start,end,line,chars ;
   TOOLTIPTEXT *lpnhead ;
   char *types, *syms ;
   int offset ;
   DEBUG_INFO * dbg ;
   VARINFO *var ;
   NMHDR nm ;
   int charpos ;
	switch (iMessage) {                                 
		case EM_GETINSERTSTATUS:
			return ((EDITDATA *)GetWindowLong(hwnd,wndoffs))->inserting ;
      case WM_NOTIFY:
         lpnhead = (TOOLTIPTEXT *)lParam ;
         switch (lpnhead->hdr.code) {
            case TTN_NEEDTEXT :
               if (selectedProject->buildFlags & BF_DEBUGTOOLTIPS) {
                  p = (EDITDATA *)GetWindowLong(hwnd,wndoffs) ;
                  x = (DWINFO *)GetWindowLong(GetParent(hwnd),0) ;
                  offset = GetBreakpointAddress(x->dwName,&p->ttlineno, TRUE) ;
                  if (FindSymbol(&dbg, &types,&syms,&offset,
                              StoppedRegs.Eip, offset, p->ttident)) {
                     var = GetVarInfo(dbg,types,syms,offset,p->ttident) ;
                     if (var) {
                        sprintf(buffer,"%s: ",p->ttident) ;
                        HintValue(types,var,buffer+ strlen(buffer)) ;
                        lpnhead->lpszText = buffer ;
                        FreeVarInfo(var) ;
                     }
                  }
               }
               break ;
         }
         break ;
		case WM_KEYDOWN:
			switch(wParam) {
				case VK_INSERT:
					p = (EDITDATA *)GetWindowLong(hwnd,wndoffs) ;
					p->inserting = !p->inserting ;
					SendMessage(GetParent(hwnd),WM_SETCURSOR,0,0) ;
				  break ;
				case VK_BACK:
				case VK_DELETE:
					i = CuttingComment(hwnd) ;
					rv = CallWindowProc(oldproc,hwnd,iMessage,wParam,lParam) ;
					CutComment(hwnd,wParam,i) ;
					return rv ;
				case VK_DOWN:
					p = (EDITDATA *)GetWindowLong(hwnd,wndoffs) ;
					rv = CallWindowProc(oldproc,hwnd,iMessage,wParam,lParam) ;
					if (p->selecting) {
						if (p->endline == p->startline-1) {
							p->endline++ ;
							p->startpos = SendMessage(hwnd, EM_LINEINDEX, --p->startline,0) ;
						}
						p->endline++ ;
						p->endpos = SendMessage(hwnd, EM_LINEINDEX, p->endline,0) ;
						SendMessage(hwnd,EM_SETSEL,p->startpos,p->endpos) ;
					}
					SendMessage(GetParent(hwnd),WM_COMMAND,ID_REDRAWSTATUS,0) ;
					return rv ;
				case VK_UP:
					p = (EDITDATA *)GetWindowLong(hwnd,wndoffs) ;
					if (p->selecting) {
						rv = CallWindowProc(oldproc,hwnd,iMessage,wParam,lParam) ;
						if (p->endline) {
							if (p->endline == p->startline+1) {
								p->endline-- ;
								p->startpos = SendMessage(hwnd, EM_LINEINDEX, ++p->startline,0) ;
							}
							p->endline-- ;
							p->endpos = SendMessage(hwnd, EM_LINEINDEX, p->endline,0) ;
						}
						SendMessage(hwnd,EM_SETSEL,p->startpos,p->endpos) ;
						SendMessage(GetParent(hwnd),WM_COMMAND,ID_REDRAWSTATUS,0) ;
						return rv ;
					}
				case VK_PRIOR:
				case VK_NEXT:
				case VK_END:
				case VK_HOME:
				case VK_LEFT:
				case VK_RIGHT:
					rv = CallWindowProc(oldproc,hwnd,iMessage,wParam,lParam) ;
					SendMessage(GetParent(hwnd),WM_COMMAND,ID_REDRAWSTATUS,0) ;
					return rv ;
				case VK_F8:
					p = (EDITDATA *)GetWindowLong(hwnd,wndoffs) ;
					if (p->shifted) {
						SendMessage(hwnd,EM_GETSEL,(WPARAM)&start,(LPARAM)&end) ;
						*((short *)buffer) = 1024 ;
						line = SendMessage(hwnd, EM_LINEFROMCHAR, start, 0) ;
						chars = SendMessage(hwnd, EM_GETLINE, line, (LPARAM) &buffer) ;
						line = SendMessage(hwnd, EM_LINEINDEX, line,0) ;
						SendMessage(hwnd,EM_SETSEL,line,line+chars) ;
						SendMessage(hwnd,EM_REPLACESEL,TRUE,(LPARAM)"") ;
					}
					break ;
				case VK_F7:					
					p = (EDITDATA *)GetWindowLong(hwnd,wndoffs) ;
					p->selecting = !p->selecting ;
					SendMessage(hwnd,EM_GETSEL,(WPARAM)&start,0) ;
					if (p->selecting) {
						*((short *)buffer) = 1024 ;
						p->endline = p->startline = line = SendMessage(hwnd, EM_LINEFROMCHAR, start, 0) ;
						p->endline++ ;
						chars = SendMessage(hwnd, EM_GETLINE, line, (LPARAM) &buffer) ;
						p->endpos = SendMessage(hwnd, EM_LINEINDEX, line, 0) ;
						p->startpos = line = SendMessage(hwnd, EM_LINEINDEX, line,0) ;
						SendMessage(hwnd,EM_SETSEL,line,line+chars) ;
					} else {
						SendMessage(hwnd, EM_SETSEL, p->endpos,p->endpos) ;
					}
					break ;
				case 'X':
						p = (EDITDATA *)GetWindowLong(hwnd,wndoffs) ;
					  if (p->control) {
							i = CuttingComment(hwnd) ;
							rv = CallWindowProc(oldproc,hwnd,iMessage,wParam,lParam) ;
							CutComment(hwnd, wParam,i) ;
							p->selecting = FALSE ;
							return rv ;
						}
						break ;
				case 'C': 
						p = (EDITDATA *)GetWindowLong(hwnd,wndoffs) ;
					  if (p->control)
							p->selecting = FALSE ;
						break ;
				case 'V':
						p = (EDITDATA *)GetWindowLong(hwnd,wndoffs) ;
					  if (p->control) {
							PasteComment(hwnd) ;
							p->selecting = FALSE ;
						}
						break ;
				case VK_CONTROL:
						p = (EDITDATA *)GetWindowLong(hwnd,wndoffs) ;
					  p->control = TRUE  ;
						break ;
				case VK_SHIFT:
						p = (EDITDATA *)GetWindowLong(hwnd,wndoffs) ;
					  p->shifted = TRUE  ;
						break ;
			}
			break ;
      case WM_HELP:
         DoHelp(hwnd) ;
         break ;
		case WM_KEYUP:
			switch(wParam) {
				case VK_SHIFT:
						p = (EDITDATA *)GetWindowLong(hwnd,wndoffs) ;
					  p->shifted = FALSE ;
						break ;
				case VK_CONTROL:
						p = (EDITDATA *)GetWindowLong(hwnd,wndoffs) ;
					  p->control = FALSE ;
						break ;
			}
			break ;
		case WM_CHAR:
			if (wParam >= ' ' && wParam < 127) {
				p = (EDITDATA *)GetWindowLong(hwnd,wndoffs) ;
				p->selecting = FALSE ;
				rv = CallWindowProc(oldproc,hwnd,iMessage,wParam,lParam) ;
				if (!p->inserting)
					SendMessage(hwnd,WM_CLEAR,0,0) ;
				if (wParam == '*' || wParam == '/') {
					if (!AddedComment(hwnd,wParam))
						FormatLine(hwnd) ;
				} else	
					FormatLine(hwnd) ;
				SendMessage(GetParent(hwnd),WM_COMMAND,ID_REDRAWSTATUS,0) ;
				return rv ;
			}
			break ;
		case WM_SETTEXT:
         SendMessage(hwnd,EM_SETBKGNDCOLOR,0,backgroundColor) ;
         rv = CallWindowProc(oldproc,hwnd,iMessage,wParam,lParam) ;
			linecount = SendMessage(hwnd,EM_GETLINECOUNT,0,0) ;
			buf = GetEditData(hwnd) ;
			if (buf) {
				Colorize(hwnd,0,strlen(buf),textColor,FALSE) ;
				FormatBuffer(hwnd,buf,0,strlen(buf)) ;
				SendMessage(hwnd,EM_SETSEL,0,0) ;
				free(buf) ;
			}
         return rv ;
		case WM_CREATE:
			rv = CallWindowProc(oldproc,hwnd,iMessage,wParam,lParam) ;
         p = (EDITDATA *)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(EDITDATA)) ;
         SetWindowLong(hwnd,wndoffs, (int)p) ;
         p->inserting = TRUE ;
         p->tooltip = CreateWindowEx(0,TOOLTIPS_CLASS,"",
                  0,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,
                  hwnd,0,hInstance,0) ;
         SendMessage(p->tooltip,TTM_SETDELAYTIME,TTDT_AUTOPOP,30000) ;
         SendMessage(p->tooltip,TTM_SETDELAYTIME,TTDT_INITIAL,1000) ;
         SendMessage(p->tooltip,TTM_SETDELAYTIME,TTDT_RESHOW,1000) ;

         t.cbSize = sizeof(TOOLINFO) ;
         t.uFlags = 0 ;
         t.hwnd = hwnd ;
         t.uId = 10000 ;
         t.rect.left = 0 ;
         t.rect.right = 1 ;
         t.rect.top = 0 ;
         t.rect.bottom = 1 ;
         t.hinst = hInstance ;
         t.lpszText = "Empty Text";
         SendMessage(p->tooltip,TTM_ADDTOOL,0,(LPARAM)&t) ;

         SendMessage(hwnd,EM_SETBKGNDCOLOR,0,backgroundColor) ;
			stop = tabs * 4 ;
			SendMessage(hwnd,EM_SETTABSTOPS,1,(LPARAM)&stop) ;
			SendMessage(hwnd,EM_SETMARGINS,EC_LEFTMARGIN,LEFTMARGIN) ;
			SendMessage(hwnd,EM_SETEVENTMASK,0,ENM_UPDATE) ;
         SendMessage(hwnd,EM_SETLIMITTEXT,500000,0) ;
			if (!hFont) {
				HDC dc = GetDC(hwnd) ;
            HFONT xfont ;
            TEXTMETRIC t ;
				lf.lfHeight = -MulDiv(10,GetDeviceCaps(dc,LOGPIXELSY),72) ;
				hFont = CreateFontIndirect(&lf) ;
            xfont = SelectObject(dc,hFont) ;
            GetTextMetrics(dc,&t) ;
            SelectObject(dc,xfont) ;
				ReleaseDC(hwnd,dc) ;
            txtFontHeight = t.tmHeight ;
			}
			SendMessage(hwnd,WM_SETFONT,(WPARAM)hFont,0) ;
			return rv ;
		case WM_SETEDITORSETTINGS:
         SendMessage(hwnd,EM_SETBKGNDCOLOR,0,backgroundColor) ;
			stop = tabs * 4 ;
			SendMessage(hwnd,EM_SETTABSTOPS,1,(LPARAM)&stop) ;
			buf = GetEditData(hwnd) ;
			if (buf) {
				SendMessage(hwnd, EM_GETSEL, (WPARAM) &start,(LPARAM) &end) ;
				SendMessage(hwnd, EM_HIDESELECTION,1,0) ;
				Colorize(hwnd,0,strlen(buf),textColor,FALSE) ;
				FormatBuffer(hwnd,buf,0,strlen(buf)) ;
				SendMessage(hwnd, EM_HIDESELECTION,0,0) ;
				SendMessage(hwnd, EM_SETSEL, start, end) ;
				free(buf) ;
			}
         return 0 ;
		case WM_DESTROY:
         p = (EDITDATA *)GetWindowLong(hwnd,wndoffs) ;
         DestroyWindow(p->tooltip) ;
			HeapFree(GetProcessHeap(),0,(void *)GetWindowLong(hwnd,wndoffs)) ;
			break ;
      case WM_MOUSEMOVE:
         p = (EDITDATA *)GetWindowLong(hwnd,wndoffs) ;
         RunToolTip(p,hwnd,LOWORD(lParam),HIWORD(lParam)) ;
         SendMessageToToolTip(p->tooltip,hwnd,iMessage,wParam,lParam) ;
         break ;
      case WM_RBUTTONDOWN:
         p = (EDITDATA *)GetWindowLong(hwnd,wndoffs) ;
         SendMessageToToolTip(p->tooltip,hwnd,iMessage,wParam,lParam) ;
         nm.code = NM_RCLICK ;
         SendMessage(GetParent(hwnd),WM_NOTIFY,0,(LPARAM)&nm) ;
         return 0 ;
      case WM_RBUTTONUP:
      case WM_MBUTTONDOWN:
      case WM_MBUTTONUP:
         p = (EDITDATA *)GetWindowLong(hwnd,wndoffs) ;
         SendMessageToToolTip(p->tooltip,hwnd,iMessage,wParam,lParam) ;
         return 0 ;
      case WM_LBUTTONDOWN:
      case WM_LBUTTONUP:
         p = (EDITDATA *)GetWindowLong(hwnd,wndoffs) ;
         SendMessageToToolTip(p->tooltip,hwnd,iMessage,wParam,lParam) ;
         break ;
      case WM_WORDUNDERCURSOR:
         return GetWordFromPos(hwnd,(char *)lParam,-1,0,0,0) ;
	}
	return CallWindowProc(oldproc,hwnd,iMessage,wParam,lParam) ;
}
void unregxedit(void)
{
	if (hFont)
		DeleteObject(hFont) ;
}
void RegisterXeditWindow(void)
{
		WNDCLASS wc ;
      GetClassInfo(0,"richedit",&wc) ;
		oldproc = wc.lpfnWndProc ;
      wc.lpfnWndProc = &exeditProc ;
		wc.lpszClassName = "XEDIT" ;
		wc.hInstance = hInstance ;
		wc.cbWndExtra+= (4-wc.cbWndExtra % 4) ;
		wndoffs = wc.cbWndExtra ;
		wc.cbWndExtra += 4 ;
		RegisterClass(&wc) ;

		lf.lfHeight = 0 ;
		lf.lfWidth = 0 ;
		lf.lfEscapement = 0;
		lf.lfOrientation = 0 ;
		lf.lfWeight = FW_LIGHT ;
		lf.lfItalic = lf.lfUnderline = lf.lfStrikeOut = FALSE ;
		lf.lfCharSet = ANSI_CHARSET ;
		lf.lfOutPrecision = OUT_DEFAULT_PRECIS ;
		lf.lfClipPrecision = CLIP_DEFAULT_PRECIS ;
		lf.lfQuality = DRAFT_QUALITY ;
		lf.lfPitchAndFamily = FIXED_PITCH | FF_MODERN ;
		strcpy(lf.lfFaceName,"Courier New") ;

}