Files
BlitzNext/ide/editor.cpp
T

1044 lines
23 KiB
C++
Raw Normal View History

#include "editor.h"
2019-01-19 18:31:46 +01:00
#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)
2019-01-19 18:31:46 +01:00
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()
2019-01-19 18:31:46 +01:00
static int blink;
static set<string> keyWordSet;
static map<string, string> keyWordMap;
2019-01-19 18:31:46 +01:00
static bool isid(int c)
{
return isalnum(c) || c == '_';
}
2019-01-19 18:31:46 +01:00
static bool isfmt(int ch, int nxt)
{
return ch == ';' || ch == '\"' || isalpha(ch) || isdigit(ch) || (ch == '$' && isxdigit(nxt));
}
2019-01-19 18:31:46 +01:00
static string rtfbgr(int bgr)
{
return "\\red" + itoa(bgr & 0xff) + "\\green" + itoa((bgr >> 8) & 0xff) + "\\blue" + itoa((bgr >> 16) & 0xff) + ';';
}
2019-01-19 18:31:46 +01:00
DWORD Editor::streamIn(LPBYTE buff, LONG cnt, LONG* done)
{
int n = 0;
while (n < cnt) {
if (is_curs == is_line.size()) {
2019-01-19 18:31:46 +01:00
if (is_stream->peek() == EOF)
break;
is_curs = 0;
is_line = "";
int c = 0;
for (;;) {
c = is_stream->get();
2019-01-19 18:31:46 +01:00
if (c == '\r' || c == '\n' || c == EOF)
break;
if (c == '\\' || c == '{' || c == '}')
is_line += '\\';
is_line += (char)c;
}
2019-01-19 18:31:46 +01:00
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;
2019-01-19 18:31:46 +01:00
if (n + sz > cnt)
sz = cnt - n;
memcpy(buff + n, is_line.data() + is_curs, sz);
2019-01-19 18:31:46 +01:00
is_curs += sz;
n += sz;
}
*done = n;
return 0;
}
2019-01-19 18:31:46 +01:00
DWORD CALLBACK Editor::streamIn(DWORD cookie, LPBYTE buff, LONG cnt, LONG* done)
{
Editor* e = (Editor*)cookie;
return e->streamIn(buff, cnt, done);
}
2019-01-19 18:31:46 +01:00
DWORD CALLBACK Editor::streamOut(DWORD cookie, LPBYTE buff, LONG cnt, LONG* done)
{
ostream* out = (ostream*)cookie;
out->write((char*)buff, cnt);
2019-01-19 18:31:46 +01:00
*done = cnt;
return 0;
}
2019-01-19 18:31:46 +01:00
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;
2019-01-19 18:31:46 +01:00
if (!blink)
blink = GetCaretBlinkTime();
funcList.setListener(this);
typeList.setListener(this);
labsList.setListener(this);
}
2019-01-19 18:31:46 +01:00
Editor::~Editor() {}
2019-01-19 18:31:46 +01:00
void Editor::resized()
{
CRect r;
GetClientRect(&r);
int x = 0, y = 0, w = r.Width(), h = r.Height();
if (w) {
2019-01-19 18:31:46 +01:00
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);
}
2019-01-19 18:31:46 +01:00
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));
2019-01-19 18:31:46 +01:00
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);
}
2019-01-19 18:31:46 +01:00
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;
2019-01-19 18:31:46 +01:00
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));
}
}
2019-01-19 18:31:46 +01:00
void Editor::OnSize(UINT type, int sw, int sh)
{
CWnd::OnSize(type, sw, sh);
resized();
}
2019-01-19 18:31:46 +01:00
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;
}
}
2019-01-19 18:31:46 +01:00
void Editor::OnLButtonUp(UINT flags, CPoint p)
{
if (sizing) {
SetCursor(AfxGetApp()->LoadStandardCursor(IDC_ARROW));
ReleaseCapture();
sizing = false;
}
SetFocus();
}
2019-01-19 18:31:46 +01:00
int Editor::OnCreate(LPCREATESTRUCT cs)
{
CWnd::OnCreate(cs);
2019-01-19 18:31:46 +01:00
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));
2019-01-19 18:31:46 +01:00
pf.cbSize = sizeof(pf);
pf.dwMask = PFM_TABSTOPS;
pf.cTabCount = MAX_TAB_STOPS;
int tabTwips = 1440 * 8 / GetDeviceCaps(::GetDC(0), LOGPIXELSX) * prefs.edit_tabs;
2019-01-19 18:31:46 +01:00
for (int k = 0; k < MAX_TAB_STOPS; ++k)
pf.rgxTabs[k] = k * tabTwips;
CRect r(0, 0, 0, 0);
2019-01-19 18:31:46 +01:00
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);
2019-01-19 18:31:46 +01:00
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 ***********************************************/
2019-01-19 18:31:46 +01:00
void Editor::setName(const string& n)
{
name = n;
}
2019-01-19 18:31:46 +01:00
bool Editor::setText(istream& in)
{
// editCtrl.HideCaret();
fmtBusy = true;
EDITSTREAM es;
2019-01-19 18:31:46 +01:00
es.dwCookie = (DWORD)this;
es.dwError = 0;
es.pfnCallback = streamIn;
2019-01-19 18:31:46 +01:00
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;
2019-01-19 18:31:46 +01:00
for (int k = 0; k < MAX_TAB_STOPS; ++k)
is_line += "\\tx" + itoa(k * tabTwips) + ' ';
is_stream = &in;
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;
}
2019-01-19 18:31:46 +01:00
void Editor::setModified(bool n)
{
editCtrl.SetModify(n);
}
2019-01-19 18:31:46 +01:00
void Editor::setCursor(int n)
{
int row = (n >> 16) & 0xffff, col = n & 0xffff;
int pos = editCtrl.LineIndex(row) + col;
editCtrl.SetSel(pos, pos);
}
2019-01-19 18:31:46 +01:00
string Editor::getName() const
{
return name;
}
2019-01-19 18:31:46 +01:00
bool Editor::getText(ostream& out)
{
fixFmt(true);
EDITSTREAM es;
2019-01-19 18:31:46 +01:00
es.dwCookie = (DWORD)&out;
es.dwError = 0;
es.pfnCallback = streamOut;
editCtrl.StreamOut(SF_TEXT, es);
return es.dwError == 0;
}
2019-01-19 18:31:46 +01:00
void Editor::cut()
{
editCtrl.Cut();
}
2019-01-19 18:31:46 +01:00
void Editor::copy()
{
editCtrl.Copy();
}
2019-01-19 18:31:46 +01:00
void Editor::paste()
{
editCtrl.PasteSpecial(CF_TEXT, 0);
}
2019-01-19 18:31:46 +01:00
bool Editor::canCutCopy()
{
getSel();
return selStart != selEnd;
}
2019-01-19 18:31:46 +01:00
bool Editor::canPaste()
{
return editCtrl.CanPaste() ? true : false;
}
2019-01-19 18:31:46 +01:00
void Editor::print()
{
static const int MARG = 720; //1440=1 inch
CPrintDialog dlg(false);
2019-01-19 18:31:46 +01:00
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);
2019-01-19 18:31:46 +01:00
FORMATRANGE fr = {0};
fr.hdc = fr.hdcTarget = hdc;
fr.rcPage.left = fr.rcPage.top = 0;
2019-01-19 18:31:46 +01:00
fr.rcPage.right = (hr / px) * 1440;
fr.rcPage.bottom = (vr / py) * 1440;
//margins
2019-01-19 18:31:46 +01:00
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());
2019-01-19 18:31:46 +01:00
DOCINFO di = {sizeof(di)};
di.lpszDocName = buff;
getSel();
int start = selStart, end = selEnd;
2019-01-19 18:31:46 +01:00
if (start == end) {
start = 0;
end = editCtrl.GetTextLength();
}
StartDoc(hdc, &di);
while (start < end) {
StartPage(hdc);
fr.chrg.cpMin = start;
fr.chrg.cpMax = end;
2019-01-19 18:31:46 +01:00
start = editCtrl.FormatRange(&fr, true);
EndPage(hdc);
}
EndDoc(hdc);
editCtrl.FormatRange(0, false);
DeleteDC(hdc);
}
2019-01-19 18:31:46 +01:00
void Editor::find()
{
if (finder)
return;
finder = new CFindReplaceDialog();
finder->m_fr.lpstrFindWhat = findBuff;
finder->m_fr.wFindWhatLen = 256;
finder->m_fr.lpstrReplaceWith = replaceBuff;
2019-01-19 18:31:46 +01:00
finder->m_fr.wReplaceWithLen = 256;
finder->Create(findOnly = true, 0, 0, FR_HIDEUPDOWN, this);
found = false;
}
2019-01-19 18:31:46 +01:00
void Editor::replace()
{
if (finder)
return;
finder = new CFindReplaceDialog();
finder->m_fr.lpstrFindWhat = findBuff;
finder->m_fr.wFindWhatLen = 256;
finder->m_fr.lpstrReplaceWith = replaceBuff;
2019-01-19 18:31:46 +01:00
finder->m_fr.wReplaceWithLen = 256;
finder->Create(findOnly = false, 0, 0, FR_HIDEUPDOWN, this);
found = false;
}
2019-01-19 18:31:46 +01:00
bool Editor::canFind()
{
return finder == 0;
}
2019-01-19 18:31:46 +01:00
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;
2019-01-19 18:31:46 +01:00
t.lpstrText = findBuff;
if (editCtrl.FindText(findFlags, &t) >= 0) {
editCtrl.SetSel(t.chrgText.cpMin, t.chrgText.cpMax);
return true;
}
2019-01-19 18:31:46 +01:00
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;
}
2019-01-19 18:31:46 +01:00
string s("Can't find \"");
s += findBuff;
s += '\"';
MessageBox(s.c_str(), "Text not found");
2019-01-19 18:31:46 +01:00
if (finder)
finder->SetFocus();
return false;
}
2019-01-19 18:31:46 +01:00
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;
2019-01-19 18:31:46 +01:00
int end = pos, len = editCtrl.GetTextLength();
while (end < len) {
char temp[8];
editCtrl.SetSel(end, end + 1);
auto txt = editCtrl.GetSelText();
2019-01-19 18:31:46 +01:00
if (txt[0] == '\"')
quote = !quote;
if (!quote && (txt[0] == ':' || !isprint(txt[0])))
break;
++end;
}
editCtrl.HideSelection(false, false);
editCtrl.SetSel(pos, end);
}
2019-01-19 18:31:46 +01:00
void Editor::selectAll()
{
editCtrl.SetSel(0, -1);
}
2019-01-19 18:31:46 +01:00
void Editor::lock()
{
locked = true;
}
2019-01-19 18:31:46 +01:00
void Editor::unlock()
{
locked = false;
}
2019-01-19 18:31:46 +01:00
string Editor::getKeyword()
{
fixFmt(true);
getSel();
2019-01-19 18:31:46 +01:00
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 (;;) {
2019-01-19 18:31:46 +01:00
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);
2019-01-19 18:31:46 +01:00
if (keyWordSet.find(t) != keyWordSet.end())
return t;
if (!pos)
return "";
--pos;
}
}
2019-01-19 18:31:46 +01:00
bool Editor::getModified()
{
return editCtrl.GetModify() ? true : false;
}
2019-01-19 18:31:46 +01:00
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);
}
2019-01-19 18:31:46 +01:00
void Editor::getCursor(int* row, int* col)
{
long start, end;
editCtrl.GetSel(start, end);
*row = editCtrl.LineFromChar(end);
*col = end - editCtrl.LineIndex(*row);
}
2019-01-19 18:31:46 +01:00
void Editor::addKeyword(const string& s)
{
keyWordSet.insert(s);
string t = s;
2019-01-19 18:31:46 +01:00
for (int k = 0; k < t.size(); ++k)
t[k] = tolower(t[k]);
keyWordMap[t] = s;
}
/************************************************* PRIVATE ***********************************************/
2019-01-19 18:31:46 +01:00
void Editor::endFind()
{
if (!finder)
return;
finder->DestroyWindow();
finder = 0;
}
2019-01-19 18:31:46 +01:00
LRESULT Editor::onFind(WPARAM w, LPARAM l)
{
if (!finder)
return 0;
findFlags = 0;
2019-01-19 18:31:46 +01:00
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);
2019-01-19 18:31:46 +01:00
if (found && findOnly)
endFind();
} else if (finder->ReplaceCurrent()) {
2019-01-19 18:31:46 +01:00
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();
2019-01-19 18:31:46 +01:00
char buff[32];
itoa(cnt, buff, 10);
string s(buff);
s += " occurances replaced";
MessageBox(s.c_str(), "Replace All Done");
editCtrl.HideSelection(false, false);
}
2019-01-19 18:31:46 +01:00
if (finder && finder->IsTerminating())
endFind();
return 0;
}
2019-01-19 18:31:46 +01:00
void Editor::caret()
{
if (!prefs.edit_blkcursor)
return;
long start, end;
editCtrl.GetSel(start, end);
if (start == end) {
editCtrl.CreateSolidCaret(8, 13);
editCtrl.ShowCaret();
2019-01-19 18:31:46 +01:00
} else
editCtrl.HideCaret();
}
2019-01-19 18:31:46 +01:00
void Editor::OnSetFocus(CWnd* wnd)
{
if (prefs.edit_blkcursor)
SetCaretBlinkTime(200);
editCtrl.SetFocus();
caret();
}
2019-01-19 18:31:46 +01:00
void Editor::OnKillFocus(CWnd* wnd)
{
CWnd::OnKillFocus(wnd);
fixFmt(true);
}
2019-01-19 18:31:46 +01:00
string Editor::getLine(int line)
{
int idx1 = editCtrl.LineIndex(line);
2019-01-19 18:31:46 +01:00
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;
2019-01-19 18:31:46 +01:00
int out = editCtrl.GetLine(line, buff);
buff[len] = 0;
string t = string(buff);
delete[] buff;
return t;
}
2019-01-19 18:31:46 +01:00
void Editor::funcSelected(int line)
{
int pos = editCtrl.LineIndex(line);
editCtrl.SetSel(editCtrl.GetTextLength() - 1, editCtrl.GetTextLength() - 1);
editCtrl.SetSel(pos, pos);
SetFocus();
}
2019-01-19 18:31:46 +01:00
void Editor::currentSet(Tabber* tabber, int index)
{
SetFocus();
}
2019-01-19 18:31:46 +01:00
void Editor::cursorMoved()
{
listener->cursorMoved(this);
}
2019-01-19 18:31:46 +01:00
void Editor::en_update()
{
caret();
}
2019-01-19 18:31:46 +01:00
void Editor::en_msgfilter(NMHDR* nmhdr, LRESULT* result)
{
if (locked || fmtBusy) {
*result = 1;
return;
}
*result = 0;
getSel();
2019-01-19 18:31:46 +01:00
MSGFILTER* msg = (MSGFILTER*)nmhdr;
if (msg->msg == WM_RBUTTONDOWN) {
CPoint p(LOWORD(msg->lParam), HIWORD(msg->lParam));
ClientToScreen(&p);
2019-01-19 18:31:46 +01:00
CMenu* menu = blitzIDE.mainFrame->GetMenu();
2019-01-19 18:31:46 +01:00
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);
2019-01-19 18:31:46 +01:00
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();
2019-01-19 18:31:46 +01:00
if (txt[0] == '\t')
editCtrl.ReplaceSel("", true);
}
} else {
for (int line = lineStart; line < lineEnd; ++line) {
int n = editCtrl.LineIndex(line);
2019-01-19 18:31:46 +01:00
editCtrl.SetSel(n, n);
editCtrl.ReplaceSel("\t", true);
}
}
selStart = editCtrl.LineIndex(lineStart);
2019-01-19 18:31:46 +01:00
selEnd = editCtrl.LineIndex(lineEnd);
setSel();
*result = 1;
editCtrl.HideSelection(false, false);
} else if (msg->wParam == 13) {
2019-01-19 18:31:46 +01:00
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();
}
2019-01-19 18:31:46 +01:00
void Editor::en_selchange(NMHDR* nmhdr, LRESULT* result)
{
if (!fmtBusy)
fixFmt(false);
cursorMoved();
caret();
}
2019-01-19 18:31:46 +01:00
void Editor::en_protected(NMHDR* nmhdr, LRESULT* result)
{
*result = 0;
if (fmtBusy)
return;
fmtLineCount = editCtrl.GetLineCount();
2019-01-19 18:31:46 +01:00
found = false;
}
2019-01-19 18:31:46 +01:00
void Editor::en_change()
{
if (fmtBusy)
return;
fmtBusy = true;
editCtrl.HideSelection(true, false);
getSel();
int begin = editCtrl.LineFromChar(selStart);
2019-01-19 18:31:46 +01:00
int end = begin + 1;
int lineCount = editCtrl.GetLineCount();
2019-01-19 18:31:46 +01:00
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);
}
2019-01-19 18:31:46 +01:00
for (int n = begin; n < end; ++n)
formatLine(n);
2019-01-19 18:31:46 +01:00
setSel();
editCtrl.HideSelection(false, false);
fmtBusy = false;
cursorMoved();
}
2019-01-19 18:31:46 +01:00
void Editor::setFormat(int from, int to, int color, const string& s)
{
editCtrl.SetSel(from, to);
if (s.size()) {
2019-01-19 18:31:46 +01:00
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);
2019-01-19 18:31:46 +01:00
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);
}
2019-01-19 18:31:46 +01:00
void Editor::formatStreamLine()
{
string out;
2019-01-19 18:31:46 +01:00
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)) {
2019-01-19 18:31:46 +01:00
for (++k; k < is_sz && !isgraph(is_line[k]); ++k) {
}
} else if (!isfmt(c, k + 1 < is_sz ? is_line[k + 1] : 0)) {
2019-01-19 18:31:46 +01:00
for (++k; k < is_sz && !isfmt(is_line[k], k + 1 < is_sz ? is_line[k + 1] : 0); ++k) {
}
cf = '6';
2019-01-19 18:31:46 +01:00
} else if (c == ';') { //comment?
k = is_sz;
cf = '4';
2019-01-19 18:31:46 +01:00
} else if (c == '\"') { //string const?
for (++k; k < is_sz && is_line[k] != '\"'; ++k) {
}
if (k < is_sz)
++k;
cf = '1';
2019-01-19 18:31:46 +01:00
} 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 == '$') {
2019-01-19 18:31:46 +01:00
for (++k; k < is_sz && isxdigit(is_line[k]); ++k) {
}
cf = '5';
2019-01-19 18:31:46 +01:00
} else if (isdigit(c)) { //numeric const?
for (++k; k < is_sz && isdigit(is_line[k]); ++k) {
}
cf = '5';
}
if (cf != pf) {
2019-01-19 18:31:46 +01:00
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;
2019-01-19 18:31:46 +01:00
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;
2019-01-19 18:31:46 +01:00
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;
2019-01-19 18:31:46 +01:00
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 ";
}
2019-01-19 18:31:46 +01:00
void Editor::fixFmt(bool fmt)
{
if (lineToFmt < 0 || fmtBusy)
return;
fmtBusy = true;
2019-01-19 18:31:46 +01:00
editCtrl.HideSelection(true, false);
getSel();
long start = selStart;
if (fmt)
selStart = -1;
formatLine(lineToFmt);
2019-01-19 18:31:46 +01:00
selStart = start;
setSel();
editCtrl.HideSelection(false, false);
fmtBusy = false;
}
2019-01-19 18:31:46 +01:00
void Editor::formatLine(int ln)
{
if (ln < 0 || ln >= editCtrl.GetLineCount())
return;
2019-01-19 18:31:46 +01:00
lineToFmt = -1;
int pos = editCtrl.LineIndex(ln);
string tline = getLine(ln);
2019-01-19 18:31:46 +01:00
string line = tolower(tline);
2019-01-19 18:31:46 +01:00
int* cf = 0;
string rep;
2019-01-19 18:31:46 +01:00
for (int k = 0; k < line.size();) {
rep.resize(0);
2019-01-19 18:31:46 +01:00
int* pf = cf;
int from = k, c = line[k], sz = line.size();
if (!isgraph(c)) {
2019-01-19 18:31:46 +01:00
for (++k; k < sz && !isgraph(line[k]); ++k) {
}
} else if (!isfmt(c, k + 1 < sz ? line[k + 1] : 0)) {
2019-01-19 18:31:46 +01:00
for (++k; k < sz && !isfmt(line[k], k + 1 < sz ? line[k + 1] : 0); ++k) {
}
cf = &prefs.rgb_default;
2019-01-19 18:31:46 +01:00
} else if (c == ';') { //comment?
k = sz;
cf = &prefs.rgb_comment;
2019-01-19 18:31:46 +01:00
} else if (c == '\"') { //string const?
for (++k; k < sz && line[k] != '\"'; ++k) {
}
if (k < sz)
++k;
cf = &prefs.rgb_string;
2019-01-19 18:31:46 +01:00
} 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()) {
2019-01-19 18:31:46 +01:00
rep = it->second;
cf = &prefs.rgb_keyword;
}
2019-01-19 18:31:46 +01:00
} else
lineToFmt = ln;
} else if (c == '$' && k + 1 < sz && isxdigit(line[k + 1])) {
2019-01-19 18:31:46 +01:00
for (++k; k < sz && isxdigit(line[k]); ++k) {
}
cf = &prefs.rgb_digit;
2019-01-19 18:31:46 +01:00
} else if (isdigit(c)) { //numeric const?
for (++k; k < sz && isdigit(line[k]); ++k) {
}
cf = &prefs.rgb_digit;
}
2019-01-19 18:31:46 +01:00
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;
2019-01-19 18:31:46 +01:00
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;
2019-01-19 18:31:46 +01:00
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;
2019-01-19 18:31:46 +01:00
for (++k; k < line.size() && isid(line[k]); ++k) {
}
labsList.insert(ln, tline.substr(start, k - start));
break;
}
}
}
}