Files
BlitzNext/BlitzBasicIDE/editor.cpp
T

887 lines
22 KiB
C++

#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<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 = &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;
}
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;
}
}
}
}