1044 lines
23 KiB
C++
1044 lines
23 KiB
C++
|
|
#include "editor.h"
|
|
#include "blitzide.h"
|
|
#include "stdafx.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<string> keyWordSet;
|
|
static map<string, string> 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 (n < cnt) {
|
|
if (is_curs == is_line.size()) {
|
|
if (is_stream->peek() == 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 < MAX_TAB_STOPS; ++k)
|
|
pf.rgxTabs[k] = k * tabTwips;
|
|
|
|
CRect r(0, 0, 0, 0);
|
|
|
|
editCtrl.Create(WS_CHILD | WS_VISIBLE | WS_HSCROLL | WS_VSCROLL | WS_BORDER | ES_MULTILINE | ES_AUTOHSCROLL
|
|
| ES_AUTOVSCROLL | ES_NOHIDESEL,
|
|
r, this, 1);
|
|
editCtrl.SetFont(&prefs.editFont);
|
|
editCtrl.SetBackgroundColor(false, prefs.rgb_bkgrnd);
|
|
editCtrl.SetDefaultCharFormat(fmt);
|
|
editCtrl.SetEventMask(ENM_CHANGE | ENM_PROTECTED | ENM_KEYEVENTS | ENM_MOUSEEVENTS | ENM_SELCHANGE);
|
|
editCtrl.SetParaFormat(pf);
|
|
editCtrl.LimitText(TEXTLIMIT);
|
|
if (editCtrl.GetLimitText() != TEXTLIMIT)
|
|
AfxMessageBox("Unable to set editor text Limit");
|
|
editCtrl.SetModify(false);
|
|
|
|
tabber.Create(WS_CHILD | WS_VISIBLE | TCS_BUTTONS | TCS_HOTTRACK, r, this, 2);
|
|
tabber.SetFont(&prefs.tabsFont);
|
|
tabber.SetPadding(CSize(3, 3));
|
|
|
|
tabber.setListener(this);
|
|
|
|
int bk = prefs.rgb_bkgrnd;
|
|
int fg = prefs.rgb_ident;
|
|
|
|
int ws = WS_CHILD | WS_BORDER;
|
|
|
|
funcList.Create(ws | LVS_LIST | LVS_SHOWSELALWAYS, r, &tabber, 1);
|
|
funcList.SetFont(&prefs.debugFont);
|
|
funcList.SetBkColor(bk);
|
|
funcList.SetTextColor(fg);
|
|
funcList.SetTextBkColor(bk);
|
|
|
|
typeList.Create(ws | LVS_LIST | LVS_SHOWSELALWAYS, r, &tabber, 2);
|
|
typeList.SetFont(&prefs.debugFont);
|
|
typeList.SetBkColor(bk);
|
|
typeList.SetTextColor(fg);
|
|
typeList.SetTextBkColor(bk);
|
|
|
|
labsList.Create(ws | LVS_LIST | LVS_SHOWSELALWAYS, r, &tabber, 3);
|
|
labsList.SetFont(&prefs.debugFont);
|
|
labsList.SetBkColor(bk);
|
|
labsList.SetTextColor(fg);
|
|
labsList.SetTextBkColor(bk);
|
|
|
|
tabber.insert(0, &funcList, "funcs");
|
|
tabber.insert(1, &typeList, "types");
|
|
tabber.insert(2, &labsList, "labels");
|
|
|
|
cursorMoved();
|
|
|
|
return 0;
|
|
}
|
|
|
|
/************************************************* PUBLIC ***********************************************/
|
|
|
|
void Editor::setName(const string& n)
|
|
{
|
|
name = n;
|
|
}
|
|
|
|
bool Editor::setText(istream& in)
|
|
{
|
|
// editCtrl.HideCaret();
|
|
fmtBusy = true;
|
|
EDITSTREAM es;
|
|
es.dwCookie = (DWORD)this;
|
|
es.dwError = 0;
|
|
es.pfnCallback = streamIn;
|
|
is_line = "{{\\colortbl;" + rtfbgr(prefs.rgb_string) + rtfbgr(prefs.rgb_ident) + rtfbgr(prefs.rgb_keyword)
|
|
+ rtfbgr(prefs.rgb_comment) + rtfbgr(prefs.rgb_digit) + rtfbgr(prefs.rgb_default) + "}";
|
|
int tabTwips = 1440 * 8 / GetDeviceCaps(::GetDC(0), LOGPIXELSX) * prefs.edit_tabs;
|
|
for (int k = 0; k < MAX_TAB_STOPS; ++k)
|
|
is_line += "\\tx" + itoa(k * tabTwips) + ' ';
|
|
is_stream = ∈
|
|
is_curs = is_linenum = 0;
|
|
funcList.clear();
|
|
typeList.clear();
|
|
labsList.clear();
|
|
editCtrl.StreamIn(SF_RTF, es);
|
|
fmtBusy = false;
|
|
// editCtrl.HideCaret();
|
|
caret();
|
|
return es.dwError == 0;
|
|
}
|
|
|
|
void Editor::setModified(bool n)
|
|
{
|
|
editCtrl.SetModify(n);
|
|
}
|
|
|
|
void Editor::setCursor(int n)
|
|
{
|
|
int row = (n >> 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 (start < end) {
|
|
StartPage(hdc);
|
|
fr.chrg.cpMin = start;
|
|
fr.chrg.cpMax = end;
|
|
start = editCtrl.FormatRange(&fr, true);
|
|
EndPage(hdc);
|
|
}
|
|
EndDoc(hdc);
|
|
|
|
editCtrl.FormatRange(0, false);
|
|
DeleteDC(hdc);
|
|
}
|
|
|
|
void Editor::find()
|
|
{
|
|
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 = 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 (end < len) {
|
|
char temp[8];
|
|
editCtrl.SetSel(end, end + 1);
|
|
auto txt = editCtrl.GetSelText();
|
|
if (txt[0] == '\"')
|
|
quote = !quote;
|
|
if (!quote && (txt[0] == ':' || !isprint(txt[0])))
|
|
break;
|
|
++end;
|
|
}
|
|
editCtrl.HideSelection(false, false);
|
|
editCtrl.SetSel(pos, end);
|
|
}
|
|
|
|
void Editor::selectAll()
|
|
{
|
|
editCtrl.SetSel(0, -1);
|
|
}
|
|
|
|
void Editor::lock()
|
|
{
|
|
locked = true;
|
|
}
|
|
|
|
void Editor::unlock()
|
|
{
|
|
locked = false;
|
|
}
|
|
|
|
string Editor::getKeyword()
|
|
{
|
|
fixFmt(true);
|
|
getSel();
|
|
int ln = editCtrl.LineFromChar(selStart);
|
|
int pos = selStart - editCtrl.LineIndex(ln);
|
|
string line = getLine(ln);
|
|
if (pos > line.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 (end < line.size() && isid(line[end]))
|
|
++end;
|
|
string t = line.substr(pos, end - pos);
|
|
if (keyWordSet.find(t) != keyWordSet.end())
|
|
return t;
|
|
if (!pos)
|
|
return "";
|
|
--pos;
|
|
}
|
|
}
|
|
|
|
bool Editor::getModified()
|
|
{
|
|
return editCtrl.GetModify() ? true : false;
|
|
}
|
|
|
|
int Editor::getCursor()
|
|
{
|
|
long start, end;
|
|
editCtrl.GetSel(start, end);
|
|
int row, col;
|
|
row = editCtrl.LineFromChar(start);
|
|
col = start - editCtrl.LineIndex(row);
|
|
return ((row) << 16) | (col);
|
|
}
|
|
|
|
void Editor::getCursor(int* row, int* col)
|
|
{
|
|
long start, end;
|
|
editCtrl.GetSel(start, end);
|
|
*row = editCtrl.LineFromChar(end);
|
|
*col = end - editCtrl.LineIndex(*row);
|
|
}
|
|
|
|
void Editor::addKeyword(const string& s)
|
|
{
|
|
keyWordSet.insert(s);
|
|
string t = s;
|
|
for (int k = 0; k < t.size(); ++k)
|
|
t[k] = tolower(t[k]);
|
|
keyWordMap[t] = s;
|
|
}
|
|
|
|
/************************************************* PRIVATE ***********************************************/
|
|
|
|
void Editor::endFind()
|
|
{
|
|
if (!finder)
|
|
return;
|
|
finder->DestroyWindow();
|
|
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; line < lineEnd; ++line) {
|
|
int n = editCtrl.LineIndex(line);
|
|
editCtrl.SetSel(n, n + 1);
|
|
auto txt = editCtrl.GetSelText();
|
|
if (txt[0] == '\t')
|
|
editCtrl.ReplaceSel("", true);
|
|
}
|
|
} else {
|
|
for (int line = lineStart; line < lineEnd; ++line) {
|
|
int n = editCtrl.LineIndex(line);
|
|
editCtrl.SetSel(n, n);
|
|
editCtrl.ReplaceSel("\t", true);
|
|
}
|
|
}
|
|
selStart = editCtrl.LineIndex(lineStart);
|
|
selEnd = editCtrl.LineIndex(lineEnd);
|
|
setSel();
|
|
*result = 1;
|
|
editCtrl.HideSelection(false, false);
|
|
} else if (msg->wParam == 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; k < pos && line[k] == '\t'; ++k) {
|
|
}
|
|
line = "\r\n" + line.substr(0, k) + '\0';
|
|
editCtrl.ReplaceSel(line.data(), true);
|
|
*result = 1;
|
|
}
|
|
}
|
|
caret();
|
|
}
|
|
|
|
void Editor::en_selchange(NMHDR* nmhdr, LRESULT* result)
|
|
{
|
|
if (!fmtBusy)
|
|
fixFmt(false);
|
|
cursorMoved();
|
|
caret();
|
|
}
|
|
|
|
void Editor::en_protected(NMHDR* nmhdr, LRESULT* result)
|
|
{
|
|
*result = 0;
|
|
if (fmtBusy)
|
|
return;
|
|
fmtLineCount = editCtrl.GetLineCount();
|
|
found = false;
|
|
}
|
|
|
|
void Editor::en_change()
|
|
{
|
|
if (fmtBusy)
|
|
return;
|
|
|
|
fmtBusy = true;
|
|
editCtrl.HideSelection(true, false);
|
|
getSel();
|
|
|
|
int begin = editCtrl.LineFromChar(selStart);
|
|
int end = begin + 1;
|
|
|
|
int lineCount = editCtrl.GetLineCount();
|
|
int delta = lineCount - fmtLineCount;
|
|
|
|
if (delta > 0) {
|
|
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 < end; ++n)
|
|
formatLine(n);
|
|
|
|
setSel();
|
|
editCtrl.HideSelection(false, false);
|
|
fmtBusy = false;
|
|
cursorMoved();
|
|
}
|
|
|
|
void Editor::setFormat(int from, int to, int color, const string& s)
|
|
{
|
|
editCtrl.SetSel(from, to);
|
|
if (s.size()) {
|
|
char buff[256];
|
|
CString txt = editCtrl.GetSelText();
|
|
txt[to - from] = 0;
|
|
if (string(buff) != s) {
|
|
editCtrl.ReplaceSel(s.c_str());
|
|
editCtrl.SetSel(from, to);
|
|
}
|
|
}
|
|
CHARFORMAT fmt;
|
|
fmt.cbSize = sizeof(fmt);
|
|
DWORD t = editCtrl.GetSelectionCharFormat(fmt);
|
|
if ((t & CFM_COLOR) && fmt.crTextColor == color)
|
|
return;
|
|
fmt.dwMask = CFM_COLOR | CFM_PROTECTED;
|
|
fmt.dwEffects = CFE_PROTECTED;
|
|
fmt.crTextColor = color;
|
|
editCtrl.SetSelectionCharFormat(fmt);
|
|
}
|
|
|
|
void Editor::formatStreamLine()
|
|
{
|
|
string out;
|
|
char cf = '0';
|
|
for (int k = 0; k < is_line.size();) {
|
|
int from = k;
|
|
char pf = cf;
|
|
int c = is_line[k], is_sz = is_line.size();
|
|
if (!isgraph(c)) {
|
|
for (++k; k < is_sz && !isgraph(is_line[k]); ++k) {
|
|
}
|
|
} else if (!isfmt(c, k + 1 < is_sz ? is_line[k + 1] : 0)) {
|
|
for (++k; k < is_sz && !isfmt(is_line[k], k + 1 < is_sz ? is_line[k + 1] : 0); ++k) {
|
|
}
|
|
cf = '6';
|
|
} else if (c == ';') { //comment?
|
|
k = is_sz;
|
|
cf = '4';
|
|
} else if (c == '\"') { //string const?
|
|
for (++k; k < is_sz && is_line[k] != '\"'; ++k) {
|
|
}
|
|
if (k < is_sz)
|
|
++k;
|
|
cf = '1';
|
|
} else if (isalpha(c)) { //ident?
|
|
for (++k; k < is_sz && isid(is_line[k]); ++k) {
|
|
}
|
|
if (keyWordSet.find(is_line.substr(from, k - from)) == keyWordSet.end())
|
|
cf = '2';
|
|
else
|
|
cf = '3';
|
|
} else if (c == '$') {
|
|
for (++k; k < is_sz && isxdigit(is_line[k]); ++k) {
|
|
}
|
|
cf = '5';
|
|
} else if (isdigit(c)) { //numeric const?
|
|
for (++k; k < is_sz && isdigit(is_line[k]); ++k) {
|
|
}
|
|
cf = '5';
|
|
}
|
|
if (cf != pf) {
|
|
out += "\\cf";
|
|
out += cf;
|
|
out += ' ';
|
|
}
|
|
out += is_line.substr(from, k - from);
|
|
}
|
|
if (is_line[0] == 'F' && is_line.find("Function") == 0) {
|
|
for (int k = 8; k < is_line.size(); ++k) {
|
|
if (isalpha(is_line[k])) {
|
|
int start = k;
|
|
for (++k; k < is_line.size() && isid(is_line[k]); ++k) {
|
|
}
|
|
funcList.insert(is_linenum, is_line.substr(start, k - start));
|
|
break;
|
|
}
|
|
}
|
|
} else if (is_line[0] == 'T' && is_line.find("Type") == 0) {
|
|
for (int k = 4; k < is_line.size(); ++k) {
|
|
if (isalpha(is_line[k])) {
|
|
int start = k;
|
|
for (++k; k < is_line.size() && isid(is_line[k]); ++k) {
|
|
}
|
|
typeList.insert(is_linenum, is_line.substr(start, k - start));
|
|
break;
|
|
}
|
|
}
|
|
} else if (is_line[0] == '.') {
|
|
for (int k = 1; k < is_line.size(); ++k) {
|
|
if (isalpha(is_line[k])) {
|
|
int start = k;
|
|
for (++k; k < is_line.size() && isid(is_line[k]); ++k) {
|
|
}
|
|
labsList.insert(is_linenum, is_line.substr(start, k - start));
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
is_line = out + "\\line ";
|
|
}
|
|
|
|
void Editor::fixFmt(bool fmt)
|
|
{
|
|
if (lineToFmt < 0 || fmtBusy)
|
|
return;
|
|
fmtBusy = true;
|
|
editCtrl.HideSelection(true, false);
|
|
getSel();
|
|
long start = selStart;
|
|
if (fmt)
|
|
selStart = -1;
|
|
formatLine(lineToFmt);
|
|
selStart = start;
|
|
setSel();
|
|
editCtrl.HideSelection(false, false);
|
|
fmtBusy = false;
|
|
}
|
|
|
|
void Editor::formatLine(int ln)
|
|
{
|
|
if (ln < 0 || ln >= 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; k < line.size();) {
|
|
rep.resize(0);
|
|
int* pf = cf;
|
|
int from = k, c = line[k], sz = line.size();
|
|
if (!isgraph(c)) {
|
|
for (++k; k < sz && !isgraph(line[k]); ++k) {
|
|
}
|
|
} else if (!isfmt(c, k + 1 < sz ? line[k + 1] : 0)) {
|
|
for (++k; k < sz && !isfmt(line[k], k + 1 < sz ? line[k + 1] : 0); ++k) {
|
|
}
|
|
cf = &prefs.rgb_default;
|
|
} else if (c == ';') { //comment?
|
|
k = sz;
|
|
cf = &prefs.rgb_comment;
|
|
} else if (c == '\"') { //string const?
|
|
for (++k; k < sz && line[k] != '\"'; ++k) {
|
|
}
|
|
if (k < sz)
|
|
++k;
|
|
cf = &prefs.rgb_string;
|
|
} else if (isalpha(c)) { //ident?
|
|
for (++k; k < sz && isid(line[k]); ++k) {
|
|
}
|
|
cf = &prefs.rgb_ident;
|
|
pf = 0;
|
|
if (selStart <= pos + from || selStart > pos + k) {
|
|
map<string, string>::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 < sz && isxdigit(line[k + 1])) {
|
|
for (++k; k < sz && isxdigit(line[k]); ++k) {
|
|
}
|
|
cf = &prefs.rgb_digit;
|
|
} else if (isdigit(c)) { //numeric const?
|
|
for (++k; k < sz && isdigit(line[k]); ++k) {
|
|
}
|
|
cf = &prefs.rgb_digit;
|
|
}
|
|
if (cf != pf)
|
|
setFormat(pos + from, pos + k, *cf, rep);
|
|
}
|
|
if (line[0] == 'f' && line.find("function") == 0) {
|
|
for (int k = 8; k < line.size(); ++k) {
|
|
if (isalpha(line[k])) {
|
|
int start = k;
|
|
for (++k; k < line.size() && isid(line[k]); ++k) {
|
|
}
|
|
funcList.insert(ln, tline.substr(start, k - start));
|
|
break;
|
|
}
|
|
}
|
|
} else if (line[0] == 't' && line.find("type") == 0) {
|
|
for (int k = 4; k < line.size(); ++k) {
|
|
if (isalpha(line[k])) {
|
|
int start = k;
|
|
for (++k; k < line.size() && isid(line[k]); ++k) {
|
|
}
|
|
typeList.insert(ln, tline.substr(start, k - start));
|
|
break;
|
|
}
|
|
}
|
|
} else if (line[0] == '.') {
|
|
for (int k = 1; k < line.size(); ++k) {
|
|
if (isalpha(line[k])) {
|
|
int start = k;
|
|
for (++k; k < line.size() && isid(line[k]); ++k) {
|
|
}
|
|
labsList.insert(ln, tline.substr(start, k - start));
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|