diff --git a/uppsrc/Core/String.cpp b/uppsrc/Core/String.cpp index 3de87e92b..f0359447f 100644 --- a/uppsrc/Core/String.cpp +++ b/uppsrc/Core/String.cpp @@ -441,6 +441,11 @@ String TrimRight(const String& str) return String(~str, s + 1); } +String TrimBoth(const String& str) +{ + return TrimLeft(TrimRight(str)); +} + struct StringICompare__ { int encoding; diff --git a/uppsrc/Core/String.h b/uppsrc/Core/String.h index acce37fa1..242a47882 100644 --- a/uppsrc/Core/String.h +++ b/uppsrc/Core/String.h @@ -487,6 +487,7 @@ int CompareNoCase(const char *a, const String& b, byte encoding = 0) { String TrimLeft(const String& s); String TrimRight(const String& s); +String TrimBoth(const String& s); inline StringBuffer& operator<<(StringBuffer& s, const char *x) { diff --git a/uppsrc/CtrlLib/init b/uppsrc/CtrlLib/init index 88a0929e9..edf5d1c39 100644 --- a/uppsrc/CtrlLib/init +++ b/uppsrc/CtrlLib/init @@ -3,7 +3,7 @@ #include "CtrlCore/init" #include "RichText/init" #include "PdfDraw/init" -#define BLITZ_INDEX__ F9E4BBC13A1F4208D11AB0446CDBF7C80 +#define BLITZ_INDEX__ F946C11C704A7351383B578758395F350 #include "CtrlLib.icpp" #undef BLITZ_INDEX__ #endif diff --git a/uppsrc/TextDiffCtrl/DiffCtrl.cpp b/uppsrc/TextDiffCtrl/DiffCtrl.cpp new file mode 100644 index 000000000..a6f083709 --- /dev/null +++ b/uppsrc/TextDiffCtrl/DiffCtrl.cpp @@ -0,0 +1,80 @@ +#include "TextDiffCtrl.h" + +namespace Upp { + +TextDiffCtrl::TextDiffCtrl() +{ + left.Gutter(30); + right.NoGutter(); + Horz(left, right); + left.WhenScroll = right.ScrollWhen(left); + right.HideSb(); + right.WhenScroll = left.ScrollWhen(right); +// compright.NumberBgColor(HistoryBg()); +} + +static bool SmallDiff(const char *s1, const char *s2) +{ + for(;;) { + while(*s1 && (byte)*s1 <= ' ') + s1++; + while(*s2 && (byte)*s2 <= ' ') + s2++; + if(!*s1 || !*s2) + return !*s1 && !*s2; + if(*s1 != *s2) + return false; + while(*s1 && *s1 == *s2) + s1++, s2++; + if((byte)s1[-1] <= ' ') + continue; + if((byte)*s1 > ' ' || (byte)*s2 > ' ') + return false; + } +} + +void TextDiffCtrl::Set(Stream& l, Stream& r) +{ + Vector ll = GetLineMap(l); + Vector rl = GetLineMap(r); + Array sections = CompareLineMaps(ll, rl); + + Point left_pos = left.GetPos(); + Point right_pos = right.GetPos(); + int sb_pos = left.GetSb(); + + int outln = 0; + left.SetCount(0); + right.SetCount(0); + for(int i = 0; i < sections.GetCount(); i++) { + const TextSection& sec = sections[i]; + bool diff = !sec.same; + Color c1 = (diff ? LtBlue() : SBlack()), c2 = (diff ? LtBlue() : SBlack()); + int maxcount = max(sec.count1, sec.count2); + left.AddCount(maxcount); + int l; + for(l = 0; l < sec.count1; l++) { + int level = (diff ? l < sec.count2 && SmallDiff(ll[sec.start1 + l], rl[sec.start2 + l]) ? 1 : 2 : 0); + left.Set(outln + l, ll[sec.start1 + l], c1, sec.start1 + l + 1, level); + } + for(; l < maxcount; l++) + left.Set(outln + l, Null, c1, Null, 2); + right.AddCount(maxcount); + for(l = 0; l < sec.count2; l++) { + int level = (diff ? l < sec.count1 && SmallDiff(rl[sec.start2 + l], ll[sec.start1 + l]) ? 1 : 2 : 0); + right.Set(outln + l, rl[sec.start2 + l], c2, sec.start2 + l + 1, level); + } + for(; l < maxcount; l++) + right.Set(outln + l, Null, c2, Null, 2); + outln += maxcount; + } +} + +void TextDiffCtrl::Set(const String& l, const String& r) +{ + StringStream sl(l); + StringStream sr(r); + Set(sl, sr); +} + +}; diff --git a/uppsrc/TextDiffCtrl/TextCtrl.cpp b/uppsrc/TextDiffCtrl/TextCtrl.cpp new file mode 100644 index 000000000..05b3ba20c --- /dev/null +++ b/uppsrc/TextDiffCtrl/TextCtrl.cpp @@ -0,0 +1,314 @@ +#include "TextDiffCtrl.h" + +namespace Upp { + + +inline Color HistoryBg() { return Color(255, 255, 0); } +/* +struct GapDisplay : public Display { + virtual void Paint(Draw& draw, const Rect& rc, const Value& v, Color ink, Color paper, dword style) const + { + draw.DrawRect(rc, paper); + Rect clip = rc.Deflated(3, 0); + draw.Clip(clip); + WString txt = IsString(v) ? v : StdConvert().Format(v); + Font fnt = StdFont(); + int tcy = GetTLTextHeight(txt, fnt); + DrawTLText(draw, rc.left + 5, rc.top + max((rc.Height() - tcy) / 2, 0), rc.Width(), txt, fnt, ink); + draw.End(); + } +}; + +struct HistoryRowDisplay : public GapDisplay { + virtual void Paint(Draw& draw, const Rect& rc, const Value& v, Color ink, Color paper, dword style) const + { + GapDisplay::Paint(draw, rc, v, ink, style & CURSOR ? paper : HistoryBg(), style); + } +}; +*/ +TextCompareCtrl::TextCompareCtrl() +{ + letter = Size(1, 1); + number_width = 0; + number_yshift = 0; + number_bg = WhiteGray(); + SetFrame(FieldFrame()); + AddFrame(scroll); + SetFont(Courier(14), Courier(10)); + scroll.NoAutoHide(); + scroll.WhenScroll = THISBACK(SelfScroll); + maxwidth = 0; + tabsize = 4; + gutter_width = 0; + gutter_bg = Color(151, 190, 239); + gutter_fg = SGreen; +} + +void TextCompareCtrl::LeftDown(Point pt, dword keyflags) +{ + if(pt.x < gutter_width || HasCapture()) + { + if(!HasCapture()) + SetCapture(); + Size sz = GetSize(); + int line = (pt.y * lines.GetCount()) / sz.cy; + int page_lines = sz.cy / letter.cy; + scroll.SetY(line - page_lines / 2); + } + SetWantFocus(); +} + +void TextCompareCtrl::LeftUp(Point pt, dword keyflags) +{ + ReleaseCapture(); +} + +void TextCompareCtrl::MouseMove(Point pt, dword keyflags) +{ + if(HasCapture()) + { + LeftDown(pt, keyflags); + } +} + + +bool TextCompareCtrl::Key(dword key, int repcnt) +{ + Point pos = scroll, newpos = pos, page = scroll.GetPage(); + switch(key) { + case K_LEFT: newpos.x--; break; + case K_RIGHT: newpos.x++; break; + case K_CTRL_LEFT: newpos.x -= page.x >> 1; break; + case K_CTRL_RIGHT: newpos.x += page.x >> 1; break; + case K_UP: newpos.y--; break; + case K_DOWN: newpos.y++; break; + case K_PAGEUP: newpos.y -= page.y; break; + case K_PAGEDOWN: newpos.y += page.y; break; + case K_HOME: newpos.x = 0; break; + case K_END: newpos.x = maxwidth - page.x; break; + case K_CTRL_HOME: newpos.y = 0; break; + case K_CTRL_END: newpos.y = lines.GetCount() - page.y; break; + case K_F3: { + bool found = false; + int i = max(pos.y + 2, 0); + while(i < lines.GetCount() && lines[i].level) + i++; + while(i < lines.GetCount()) + if(lines[i++].level) { + newpos.y = i - 2; + found = true; + break; + } + if(!found) { + BeepExclamation(); + return true; + } + break; + } + case K_SHIFT_F3: { + bool found = false; + int i = min(pos.y, lines.GetCount() - 1); + while(i > 0 && lines[i].level) + i--; + while(i >= 0) + if(lines[i--].level) { + newpos.y = i; + found = true; + break; + } + if(!found) { + BeepExclamation(); + return true; + } + break; + } + default: return false; + } + if(newpos != pos) + scroll.Set(newpos); + return true; +} + +void TextCompareCtrl::Paint(Draw& draw) +{ + Point sc = scroll.Get(); + Size offset = (Size)sc * letter; + Size sz = GetSize(); + + int lcnt = lines.GetCount(); + int first_line = offset.cy / letter.cy; + int last_line = min(idivceil(sz.cy + offset.cy, letter.cy), lines.GetCount() - 1); + + if(gutter_width > 0) + { + int t = 0, b = 0; + for(int i = 0; i < lcnt; i++) + if(lines[i].level > 1) { + b = idivceil(sz.cy * i, lcnt); + if(b >= t) { + draw.DrawRect(0, t, gutter_width, b - t, gutter_bg); + draw.DrawRect(0, b, gutter_width, 1, gutter_fg); + t = b + 1; + } + } + + draw.DrawRect(0, t, gutter_width, sz.cy - t, gutter_bg); + + int total = letter.cy * lcnt; + if(total <= 0) + total = 1; + int page_height = (sz.cy * sz.cy) / total; + int ty = max(0, (sz.cy * offset.cy) / total); + int by = min(sz.cy, ty + page_height); + draw.DrawRect(0, ty, gutter_width, 2, Black); + draw.DrawRect(0, by - 2, gutter_width, 2, Black); + draw.DrawRect(0, ty, 2, by - ty, Black); + draw.DrawRect(gutter_width - 2, ty, 2, by - ty, Black); + } + + Font ifont = Font(font).Italic(); + for(int i = first_line; i <= last_line; i++) { + const Line& l = lines[i]; + int y = i * letter.cy - offset.cy; + draw.DrawRect(gutter_width, y, number_width, letter.cy, number_bg); + if(!IsNull(l.number)) + draw.DrawText(gutter_width, y + number_yshift, FormatInt(l.number), number_font, l.color); + } + draw.Clip(gutter_width + number_width, 0, sz.cx - gutter_width - number_width, sz.cy); + for(int i = first_line; i <= last_line; i++) { + const Line& l = lines[i]; + int y = i * letter.cy - offset.cy; + draw.DrawRect(0, y, sz.cx, letter.cy, SWhite()); + draw.DrawText(gutter_width + number_width - offset.cx, y, ExpandTabs(l.text), l.level == 1 ? ifont : font, l.color); + } + draw.End(); + int lcy = lcnt * letter.cy - offset.cy; + draw.DrawRect(gutter_width, lcy, sz.cx, sz.cy - lcy, SGray()); +} + +void TextCompareCtrl::TabSize(int t) +{ + tabsize = t; + UpdateWidth(); + Layout(); +} + +void TextCompareCtrl::SetFont(Font f, Font nf) +{ + font = f; + number_font = nf; + FontInfo fi = f.Info(); + FontInfo ni = nf.Info(); + letter.cy = fi.GetHeight(); + letter.cx = fi.GetAveWidth(); + number_width = 5 * ni.GetAveWidth(); + number_yshift = (fi.GetHeight() - ni.GetHeight() + 2) >> 1; + Layout(); +} + +void TextCompareCtrl::Layout() +{ + scroll.Set(scroll, (scroll.GetReducedViewSize() - Size(number_width + gutter_width, 0)) / letter, Size(maxwidth, lines.GetCount())); + Refresh(); +} + +void TextCompareCtrl::MouseWheel(Point pt, int zdelta, dword keyflags) +{ + scroll.WheelY(zdelta); +} + +void TextCompareCtrl::SetCount(int c) +{ + bool rl = (c < lines.GetCount()); + lines.SetCount(c); + if(rl) + UpdateWidth(); + Layout(); +} + +void TextCompareCtrl::AddCount(int c) +{ + lines.InsertN(lines.GetCount(), c); + Layout(); +} + +void TextCompareCtrl::Set(int line, String text, Color color, int number, int level) +{ + Line& l = lines.At(line); + int tl = MeasureLength(text); + int lt = MeasureLength(l.text); + bool rl = (tl < lt && lt == maxwidth); + l.number = number; + l.text = text; + l.color = color; + l.level = level; + if(rl) + UpdateWidth(); + else if(tl > maxwidth) { + maxwidth = tl; + Layout(); + } +} + +void TextCompareCtrl::SelfScroll() +{ + Refresh(); + WhenScroll(); +} + +void TextCompareCtrl::PairScroll(TextCompareCtrl *ctrl) +{ + scroll.Set(ctrl->scroll.Get()); +} + +void TextCompareCtrl::UpdateWidth() +{ + maxwidth = 0; + for(int i = 0; i < lines.GetCount(); i++) + maxwidth = max(maxwidth, MeasureLength(lines[i].text)); +} + +int TextCompareCtrl::MeasureLength(const char *text) const +{ + int pos = 0; + while(*text) + if(*text++ == '\t') + pos += tabsize - pos % tabsize; + else + pos++; + return pos; +} + +String TextCompareCtrl::ExpandTabs(const char *text) const +{ + String out; + for(char c; c = *text++;) + if(c == '\t') + out.Cat(' ', tabsize - out.GetLength() % tabsize); + else + out.Cat(c); + return out; +} + +Point TextCompareCtrl::GetPos() const +{ + Point pos(0, 0); + int ltop = minmax(scroll.Get().y, 0, lines.GetCount() - 1); + while(ltop >= 0 && IsNull(lines[ltop].number)) { + ltop--; + pos.y++; + } + if(ltop >= 0) + pos.x = lines[ltop].number; + return pos; +} + +void TextCompareCtrl::SetPos(Point pos) +{ + int l = FindFieldIndex(lines, &Line::number,pos.x); + if(l < 0) + l = 0; + SetSb(l + pos.y); +} + +}; diff --git a/uppsrc/TextDiffCtrl/TextDiff.cpp b/uppsrc/TextDiffCtrl/TextDiff.cpp new file mode 100644 index 000000000..fb2e831a1 --- /dev/null +++ b/uppsrc/TextDiffCtrl/TextDiff.cpp @@ -0,0 +1,213 @@ +#include "TextDiffCtrl.h" + +namespace Upp { + +template +static int CompareGetCount(I a, I b, int max_count) +{ + if(max_count <= 0 || *a != *b) + return 0; + int left; + for(left = max_count; --left > 0;) + if(*++a != *++b) + return max_count - left; + return max_count; +} + +Vector GetLineMap(Stream& stream) +{ + Vector out; + int emp = 0; + if(stream.IsOpen()) + while(!stream.IsEof()) { + String s = stream.GetLine(); + const char *p = s, *e = s.End(), *f = e; + while(e > p && (byte)e[-1] <= ' ') + e--; + if(e == p) + emp++; + else + { + while(emp-- > 0) + out.Add(Null); + if(e != f) + s.Trim(e - p); + out.Add(s); + emp = 0; + } + } + return out; +} + +Vector GetFileLineMap(const String& path) +{ + FileIn fi(path); + return GetLineMap(fi); +} + +Vector GetStringLineMap(const String& s) +{ + StringStream ss(s); + return GetLineMap(ss); +} + +class TextComparator +{ +public: + TextComparator(const Vector& f1, const Vector& f2); + + Array GetSections() const; + +private: + bool Find(int start1, int end1, int start2, int end2, int& best_match, int& best_count) const; + void Split(Array& dest, int start1, int end1, int start2, int end2) const; + +private: + Vector hash1; + Vector hash2; + const Vector& file1; + const Vector& file2; +}; + +Array CompareLineMaps(const Vector& s1, const Vector& s2) +{ + return TextComparator(s1, s2).GetSections(); +} + +static void CalcHash(Vector& hash, const Vector& file, int limit) +{ + { // 1st row + HashBase& first = hash.Add(); + for(int i = 0; i < file.GetCount(); i++) + first.Add(GetHashValue(file[i])); + } + static const int prime[] = + { + 3, 5, 7, 11, 13, 17, 19, 21, + 23, 29, 31, 37, 41, 43, 47, 51, + 53, 61, 67, 71, 73, 79, 83, 87, + 89, 97, 101, 103, 107, 109, 113, 117, + }; + const int *pp = prime; + for(int l = 1; l < limit; l <<= 1) { + HashBase& nhash = hash.Add(); + const HashBase& ohash = hash[hash.GetCount() - 2]; + int pri = *pp++; + int t; + for(t = l; t < ohash.GetCount(); t++) + nhash.Add(ohash[t - l] + pri * ohash[t]); + for(t -= l; t < ohash.GetCount(); t++) + nhash.Add(ohash[t]); + } +} + +TextComparator::TextComparator(const Vector& f1, const Vector& f2) +: file1(f1), file2(f2) +{ + int limit = min(f1.GetCount(), f2.GetCount()); + CalcHash(hash1, f1, limit); + CalcHash(hash2, f2, limit); +} + +static bool CompareSection(const TextSection& ta, const TextSection& tb) +{ + return ta.start1 < tb.start1 || ta.start1 == tb.start1 && ta.start2 < tb.start2; +} + +Array TextComparator::GetSections() const +{ + Array output; + Split(output, 0, file1.GetCount(), 0, file2.GetCount()); + Sort(output, &CompareSection); + return output; +} + +static int GetHashLevel(int min_count, int hash_count) +{ + int l = 0; + hash_count--; + while(min_count > 1 && l < hash_count) + { + min_count >>= 1; + l++; + } + return l; +} + +bool TextComparator::Find(int start1, int end1, int start2, int end2, int& best_match, int& best_count) const +{ + ASSERT(end1 > start1 && end2 > start2); + bool done = false; + const String *f1 = file1.Begin() + start1; + int len1 = end1 - start1; + int lvl = GetHashLevel(best_count + 1, hash1.GetCount()); + int chunk = 1 << lvl; + int last = max(best_count - chunk + 1, 0); + const HashBase *hp1 = &hash1[lvl]; + const HashBase *hp2 = &hash2[lvl]; + const unsigned *h1 = hp1->Begin() + start1; + + int i = hp2->Find(*h1); + while(i >= 0) + if(i + best_count >= end2) + return done; + else { + if(i >= start2 && h1[last] == (*hp2)[i + last]) { + int top = min(len1, end2 - i); + int hc = CompareGetCount(h1, hp2->Begin() + i, top) + chunk - 1; + int cnt = CompareGetCount(f1, file2.Begin() + i, min(hc, top)); + if(cnt > best_count) { + best_count = cnt; + best_match = i; + done = true; + last = best_count - chunk + 1; + if(best_count + 1 >= 2 * chunk) + { + lvl = GetHashLevel(best_count + 1, hash1.GetCount()); + chunk = 1 << lvl; + last = best_count - chunk + 1; + hp1 = &hash1[lvl]; + hp2 = &hash2[lvl]; + h1 = hp1->Begin() + start1; + int oi = i; + for(i = hp2->Find(*h1); i >= 0 && i <= oi; i = hp2->FindNext(i)) + ; + continue; + } + } + } + i = hp2->FindNext(i); + } + return done; +} + +void TextComparator::Split(Array& dest, int start1, int end1, int start2, int end2) const +{ + ASSERT(start1 <= end1 && start2 <= end2); + while(start1 < end1 && start2 < end2) { + int new1 = -1, new2 = -1, count = 0; + for(int i = start1; i + count < end1; i++) + if(Find(i, end1, start2, end2, new2, count)) + new1 = i; + if(count == 0) + break; // no match at all + ASSERT(new1 >= start1 && new1 + count <= end1); + ASSERT(new2 >= start2 && new2 + count <= end2); + dest.Add(TextSection(new1, count, new2, count, true)); + if(new1 - start1 >= end1 - new1 - count) { // head is longer - recurse for tail + Split(dest, new1 + count, end1, new2 + count, end2); + end1 = new1; + end2 = new2; + } + else { // tail is longer - recurse for head + Split(dest, start1, new1, start2, new2); + start1 = new1 + count; + start2 = new2 + count; + } + ASSERT(start1 <= end1 && start2 <= end2); + } + if(start1 < end1 || start2 < end2) + dest.Add(TextSection(start1, end1 - start1, start2, end2 - start2, false)); +} + +}; diff --git a/uppsrc/TextDiffCtrl/TextDiffCtrl.h b/uppsrc/TextDiffCtrl/TextDiffCtrl.h new file mode 100644 index 000000000..413eb579a --- /dev/null +++ b/uppsrc/TextDiffCtrl/TextDiffCtrl.h @@ -0,0 +1,122 @@ +#ifndef _TextDiffCtrl_TextDiffCtrl_h +#define _TextDiffCtrl_TextDiffCtrl_h + +#include + +namespace Upp { + +class TextSection +{ +public: + TextSection(int start1, int count1, int start2, int count2, bool same) + : start1(start1), count1(count1), start2(start2), count2(count2), same(same) {} + +public: + int start1; + int count1; + int start2; + int count2 : 31; + unsigned same : 1; +}; + +Array CompareLineMaps(const Vector& l1, const Vector& l2); +Vector GetLineMap(Stream& stream); +Vector GetFileLineMap(const String& path); +Vector GetStringLineMap(const String &s); + +class TextCompareCtrl : public Ctrl { +public: + virtual void Paint(Draw& draw); + virtual void Layout(); + virtual void MouseWheel(Point pt, int zdelta, dword keyflags); + virtual void MouseMove(Point pt, dword keyflags); + virtual void LeftDown(Point pt, dword keyflags); + virtual void LeftUp(Point pt, dword keyflags); + virtual bool Key(dword key, int repcnt); + +private: + void SelfScroll(); + void PairScroll(TextCompareCtrl *ctrl); + void UpdateWidth(); + String ExpandTabs(const char *line) const; + int MeasureLength(const char *line) const; + +private: + struct Line { + Line() : number(Null), level(0) {} + int number; + Color color; + String text; + int level; + }; + Array lines; + int maxwidth; + ScrollBars scroll; + Font font; + Font number_font; + Color number_bg; + Color gutter_fg; + Color gutter_bg; + Size letter; + int tabsize; + int number_width; + int number_yshift; + int gutter_width; + + typedef TextCompareCtrl CLASSNAME; + +public: + Callback WhenScroll; + + void SetCount(int c); + void AddCount(int c); + int GetCount() const { return lines.GetCount(); } + + void SetFont(Font f, Font nf); + Font GetFont() const { return font; } + Font GetNumberFont() const { return number_font; } + + void NumberBgColor(Color bg) { number_bg = bg; Refresh(); } + Color GetNumberBgColor() const { return number_bg; } + + void ShowSb(bool ssb) { scroll.ShowY(ssb); } + void HideSb() { ShowSb(false); } + + void Gutter(int size) { gutter_width = size; Refresh(); } + void NoGutter() { gutter_width = 0; Refresh(); } + + void TabSize(int t); + int GetTabSize() const { return tabsize; } + + void Set(int line, String text, Color color, int number, int level); + String GetText(int line) const { return lines[line].text; } + Color GetColor(int line) const { return lines[line].color; } + int GetNumber(int line) const { return lines[line].number; } + + Point GetPos() const; + void SetPos(Point pos); + + int GetSb() const { return scroll.Get().y; } + void SetSb(int y) { scroll.Set(0, y); } + + Callback ScrollWhen(TextCompareCtrl& pair) { return THISBACK1(PairScroll, &pair); } + + TextCompareCtrl(); +}; + +class TextDiffCtrl : public Splitter { + TextCompareCtrl left; + TextCompareCtrl right; + +public: + void Set(Stream& l, Stream& r); + void Set(const String& l, const String& r); + void AddFrameLeft(CtrlFrame& f) { left.AddFrame(f); } + void AddFrameRight(CtrlFrame& f) { right.AddFrame(f); } + + TextDiffCtrl(); +}; + +}; + +#endif diff --git a/uppsrc/TextDiffCtrl/TextDiffCtrl.upp b/uppsrc/TextDiffCtrl/TextDiffCtrl.upp new file mode 100644 index 000000000..610b91095 --- /dev/null +++ b/uppsrc/TextDiffCtrl/TextDiffCtrl.upp @@ -0,0 +1,6 @@ +file + TextDiffCtrl.h, + TextDiff.cpp, + TextCtrl.cpp, + DiffCtrl.cpp; + diff --git a/uppsrc/TextDiffCtrl/init b/uppsrc/TextDiffCtrl/init new file mode 100644 index 000000000..b05e82eed --- /dev/null +++ b/uppsrc/TextDiffCtrl/init @@ -0,0 +1,3 @@ +#ifndef _TextDiffCtrl_icpp_init_stub +#define _TextDiffCtrl_icpp_init_stub +#endif diff --git a/uppsrc/ide/Diff.cpp b/uppsrc/ide/Diff.cpp new file mode 100644 index 000000000..26c154c6b --- /dev/null +++ b/uppsrc/ide/Diff.cpp @@ -0,0 +1,178 @@ +#include "ide.h" + +struct DiffDlg : public TopWindow { + TextDiffCtrl diff; + FrameTop p; + DataPusher l; + Button write; + String editfile; + String extfile; + + typedef DiffDlg CLASSNAME; + + void Write(); + void Execute(const String& f); + + DiffDlg(); +}; + +INITBLOCK { + RegisterGlobalConfig("diff"); +} + +void DiffDlg::Execute(const String& f) +{ + editfile = f; + l <<= editfile; + Title(editfile); + String h; + { + LoadFromGlobal(h, "diff"); + StringStream ss(h); + SerializePlacement(ss); + } + TopWindow::Execute(); + { + StringStream ss; + SerializePlacement(ss); + h = ss; + StoreToGlobal(h, "diff"); + } +} + +void DiffDlg::Write() +{ + if(PromptYesNo("Do you want to overwrite&[* " + DeQtf(editfile) + "] ?")) { + SaveFile(editfile, extfile); + Break(IDOK); + } +} + +DiffDlg::DiffDlg() +{ + Add(diff.SizePos()); + Sizeable().Zoomable(); + diff.AddFrameLeft(p); + int cy = EditField::GetStdHeight(); + p.Height(cy); + p.Add(l.VSizePos().HSizePos(0, 6 * cy)); + p.Add(write.VSizePos().RightPos(0, 6 * cy)); + write <<= THISBACK(Write); + write.SetLabel("Overwrite <-"); + l.SetReadOnly(); +} + +struct FileDiff : DiffDlg { + FrameTop r; + + void Open(); + void Execute(const String& f); + + typedef FileDiff CLASSNAME; + + FileDiff(); +}; + +void FileDiff::Open() +{ + if(!AnySourceFs().ExecuteOpen()) + return; + String f = ~AnySourceFs(); + r <<= f; + diff.Set(LoadFile(editfile), extfile = LoadFile(f)); +} + +void FileDiff::Execute(const String& f) +{ + Open(); + if(IsNull(r)) + return; + DiffDlg::Execute(f); +} + +FileDiff::FileDiff() +{ + r.Height(EditField::GetStdHeight()); + Icon(IdeImg::Diff()); + diff.AddFrameRight(r); + r <<= THISBACK(Open); +} + +void Ide::Diff() +{ + if(IsNull(editfile)) + return; + FileDiff dlg; + dlg.Execute(editfile); +} + +struct SvnDiff : DiffDlg { + FrameTop r; + + void Load(); + void Execute(const String& f); + + typedef SvnDiff CLASSNAME; + + SvnDiff(); +}; + +void SvnDiff::Execute(const String& f) +{ + editfile = f; + String log = Sys("svn log " + f); + if(log.IsVoid()) { + Exclamation("Error executing 'svn log'"); + return; + } + StringStream ss(log); + while(!ss.IsEof()) { + String l = ss.GetLine(); + if(l[0] == 'r') { + Vector h = Split(l, '|'); + if(h.GetCount() > 2) { + String rev = TrimBoth(h[0]); + String usr = TrimBoth(h[1]); + String msg; + while(!ss.IsEof()) { + l = ss.GetLine(); + if(l.GetCount()) { + if(l[0] != '-') + msg = l; + break; + } + } + r.Add(rev, rev + ' ' + usr + ": " + msg); + } + } + } + if(r.GetCount() == 0) { + Exclamation("No parsable history for the file"); + return; + } + r.SetIndex(0); + Load(); + DiffDlg::Execute(f); +} + +void SvnDiff::Load() +{ + diff.Set(LoadFile(editfile), extfile = Sys("svn cat " + editfile + '@' + AsString(~r))); +} + +SvnDiff::SvnDiff() +{ + r.Height(EditField::GetStdHeight()); + r.SetDropLines(32); + Icon(IdeImg::Diff()); + diff.AddFrameRight(r); + r <<= THISBACK(Load); +} + +void Ide::SvnHistory() +{ + if(IsNull(editfile)) + return; + SvnDiff dlg; + dlg.Execute(editfile); +} diff --git a/uppsrc/ide/Setup.cpp b/uppsrc/ide/Setup.cpp index 35857021e..8d719a8fb 100644 --- a/uppsrc/ide/Setup.cpp +++ b/uppsrc/ide/Setup.cpp @@ -36,33 +36,6 @@ public: }; void FontSelectManager::FaceSelect() { - height->Clear(); -#ifdef PLATFORM_WIN32 - int f = face->GetData(); - int h = -1; - int lh = height->GetData(); - int lhh = -1; - - int i; - for(i = 1; i < 32; i++) { - FontInfo fi = Font(f, i).Info(); - int hh = fi.GetHeight(); - if(hh != h) { - height->Add(hh); - if(hh >= lh && lhh < 0) - lhh = hh; - h = hh; - } - } - if(lhh >= 0) - height->SetData(lhh); - else - if(height->GetCount()) - height->SetIndex(0); -#else - for(int i = 6; i < 32; i++) - height->Add(i); -#endif Select(); } @@ -89,6 +62,9 @@ void FontSelectManager::Set(DropList& _face, DropList& _height, LLOG("Face: " << Font::GetFaceName(i)); } face->SetIndex(0); + height->ClearList(); + for(int i = 6; i < 32; i++) + height->Add(i); FaceSelect(); } diff --git a/uppsrc/ide/icon.ico b/uppsrc/ide/icon.ico index ed674dab4..6d3033f25 100644 Binary files a/uppsrc/ide/icon.ico and b/uppsrc/ide/icon.ico differ diff --git a/uppsrc/ide/ide.h b/uppsrc/ide/ide.h index 4fcefa033..b09cf4cde 100644 --- a/uppsrc/ide/ide.h +++ b/uppsrc/ide/ide.h @@ -12,6 +12,7 @@ #include #include #include +#include #define LAYOUTFILE #include @@ -859,7 +860,8 @@ public: String GetOpposite(); void GoOpposite(); void Print(); - + void Diff(); + void SvnHistory(); void Edit(Bar& menu); void EditAsText(); diff --git a/uppsrc/ide/ide.iml b/uppsrc/ide/ide.iml index 02eae369d..65cbbe568 100644 --- a/uppsrc/ide/ide.iml +++ b/uppsrc/ide/ide.iml @@ -69,6 +69,7 @@ IMAGE_ID(tpp_pen) IMAGE_ID(tpp_doc) IMAGE_ID(svn) IMAGE_ID(svn_dir) +IMAGE_ID(Diff) IMAGE_BEGIN_DATA IMAGE_DATA(120,156,237,152,77,210,155,48,12,134,125,129,206,124,187,206,116,213,235,244,84,229,68,61,67,206,145,35,116,217,46,187) @@ -3860,28 +3861,31 @@ IMAGE_DATA(25,114,248,31,15,161,22,99,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, IMAGE_END_DATA(5568, 20) IMAGE_BEGIN_DATA -IMAGE_DATA(120,156,237,152,191,75,91,81,20,199,191,77,72,107,76,83,18,3,133,22,107,237,162,212,150,20,26,135,218,14,26,90) -IMAGE_DATA(42,165,73,183,66,69,40,180,38,26,197,70,116,176,138,216,4,139,18,161,129,110,141,16,193,165,41,100,237,63,32,212) -IMAGE_DATA(237,14,130,157,178,37,89,28,218,173,14,113,122,189,247,189,228,229,189,228,253,126,210,31,226,9,223,225,29,190,159,115) -IMAGE_DATA(238,189,47,231,18,133,15,62,156,100,204,111,22,56,43,146,242,28,7,153,138,197,34,167,21,138,252,33,85,134,106,190) -IMAGE_DATA(201,167,82,41,81,141,103,69,158,177,99,84,3,114,222,84,127,214,59,220,206,43,173,65,177,63,235,189,99,113,255,153) -IMAGE_DATA(58,207,214,177,111,97,255,3,104,106,199,66,255,176,208,151,231,15,219,249,214,117,180,241,251,146,243,179,250,254,195,245) -IMAGE_DATA(26,156,197,247,63,80,223,131,149,254,59,146,243,87,232,223,122,14,173,188,157,249,177,21,39,125,25,208,224,44,74,228) -IMAGE_DATA(205,134,18,143,250,135,69,40,20,82,149,17,222,110,127,193,147,22,101,132,183,187,255,70,104,237,251,79,244,183,194,219) -IMAGE_DATA(252,254,180,134,90,125,163,97,135,87,243,26,173,97,151,55,23,23,79,254,50,248,219,241,84,67,202,254,193,193,166,66) -IMAGE_DATA(33,65,90,254,134,71,170,211,236,55,119,158,14,149,252,191,31,167,112,24,138,80,190,57,139,42,126,46,184,186,74,98) -IMAGE_DATA(185,28,25,94,95,39,190,100,146,56,167,166,8,212,111,30,142,121,191,238,238,146,55,219,219,228,54,101,59,102,102,52) -IMAGE_DATA(253,35,27,27,188,55,146,205,146,254,229,101,226,214,241,251,233,26,238,208,186,55,87,86,200,149,133,5,114,126,122,90) -IMAGE_DATA(211,239,74,36,8,99,186,230,230,136,103,118,86,119,253,152,156,228,61,76,14,230,165,207,26,126,179,231,249,255,134,15) -IMAGE_DATA(151,20,243,215,129,159,49,246,226,169,162,194,230,95,1,177,152,160,96,80,175,238,51,202,115,236,39,3,213,55,145,63) -IMAGE_DATA(56,0,74,37,160,82,1,114,57,192,235,53,199,179,240,251,129,100,18,56,58,2,10,5,53,222,9,108,117,2,159,153) -IMAGE_DATA(58,168,104,106,88,238,24,26,2,170,85,96,109,77,150,118,192,133,0,110,224,156,145,27,46,159,7,202,101,160,187,91) -IMAGE_DATA(76,61,194,50,62,210,245,14,33,174,207,7,2,194,22,251,250,248,199,40,54,145,197,49,207,127,64,13,15,177,168,206) -IMAGE_DATA(142,142,2,227,227,2,159,72,80,56,138,91,136,224,1,18,60,127,23,99,232,199,99,117,126,145,214,174,213,4,254,248) -IMAGE_DATA(24,200,100,248,244,101,74,49,190,19,93,250,235,143,199,5,126,105,73,76,249,112,13,239,80,198,11,228,245,121,7,61) -IMAGE_DATA(227,222,94,192,229,146,165,159,224,61,210,168,162,23,247,91,128,17,184,221,5,120,60,130,156,206,45,213,210,47,241,133) -IMAGE_DATA(158,230,47,250,214,231,224,22,111,252,215,216,219,107,254,55,34,26,253,161,202,95,128,23,207,241,9,41,84,176,130,18) -IMAGE_DATA(222,226,187,41,190,17,87,17,196,61,76,240,98,124,36,194,97,98,66,80,79,143,156,63,27,70,253,97,76,167,193,49) -IMAGE_DATA(181,119,209,31,70,198,53,254,144,111,212,105,214,210,31,70,41,35,173,99,116,24,165,156,156,55,54,140,234,60,11,99) -IMAGE_DATA(195,40,221,131,252,28,207,134,81,106,253,13,101,168,134,251,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0) -IMAGE_END_DATA(768, 6) +IMAGE_DATA(120,156,237,152,77,72,84,81,20,199,255,205,48,229,104,198,168,16,20,102,182,81,178,152,160,113,145,181,80,41,146,104) +IMAGE_DATA(166,93,144,8,65,57,234,40,54,162,11,83,196,102,52,148,17,26,112,215,8,10,130,52,193,108,163,69,139,72,200,221) +IMAGE_DATA(91,8,182,114,167,110,92,20,68,228,66,87,175,123,223,155,247,53,243,238,251,28,179,196,51,252,97,222,225,252,206,185) +IMAGE_DATA(247,188,119,46,243,6,1,4,80,74,27,158,203,242,78,164,230,121,30,26,229,114,57,222,200,116,249,93,162,20,209,176) +IMAGE_DATA(194,39,18,9,89,210,181,46,79,217,78,162,38,45,111,171,62,173,221,94,204,235,173,65,183,62,173,189,236,112,255,169) +IMAGE_DATA(60,79,215,177,238,96,255,77,80,180,236,160,126,187,88,87,224,119,139,249,194,117,20,241,235,170,254,57,189,255,237,249) +IMAGE_DATA(28,188,195,251,223,148,223,131,147,250,203,170,254,235,212,47,236,67,33,239,102,126,92,89,169,15,3,98,188,67,201,188) +IMAGE_DATA(93,211,227,145,255,80,11,133,66,76,89,225,221,214,23,99,146,178,172,240,110,247,47,153,209,190,255,70,125,39,188,203) +IMAGE_DATA(231,167,208,88,249,173,154,27,158,21,107,53,135,91,222,158,157,45,253,97,112,212,246,208,64,250,241,205,205,138,66,33) +IMAGE_DATA(81,70,241,82,140,90,199,57,222,94,63,61,12,255,191,111,199,112,24,114,208,63,57,115,140,120,62,56,57,201,69,51) +IMAGE_DATA(25,174,117,102,134,11,196,227,156,183,175,143,3,251,228,225,105,236,135,213,85,238,197,210,18,119,157,176,101,3,3,134) +IMAGE_DATA(241,109,179,179,66,108,56,157,230,26,199,199,57,191,73,124,21,89,195,13,146,247,234,196,4,119,97,100,132,59,221,223) +IMAGE_DATA(111,24,239,139,197,56,202,84,15,13,113,21,131,131,166,235,71,111,175,16,67,229,161,177,228,218,32,222,110,63,255,95) +IMAGE_DATA(11,224,156,174,255,50,240,35,74,111,60,81,68,220,252,51,32,26,21,21,12,154,229,125,68,120,158,254,100,32,250,42) +IMAGE_DATA(243,27,27,192,230,38,176,189,13,100,50,64,101,165,61,158,90,85,21,16,143,3,123,123,64,54,203,226,189,192,66,57) +IMAGE_DATA(240,142,170,140,136,184,90,181,17,45,45,192,206,14,48,61,173,113,123,224,67,13,174,224,148,149,19,110,113,17,216,218) +IMAGE_DATA(2,106,107,101,215,61,140,99,158,172,183,5,61,230,124,77,141,184,197,134,6,225,50,130,57,164,113,32,240,111,176,143) +IMAGE_DATA(187,24,101,179,29,29,64,87,151,200,199,98,4,142,224,26,194,184,131,152,192,223,68,39,26,113,159,205,143,146,220,251) +IMAGE_DATA(251,34,127,112,0,164,82,130,251,60,161,40,95,142,106,243,245,247,244,136,252,216,152,236,10,224,18,94,97,11,79,176) +IMAGE_DATA(104,206,123,72,143,235,235,1,159,79,227,126,128,215,72,98,7,245,184,93,0,180,193,239,207,162,162,66,148,215,187,192) +IMAGE_DATA(76,253,20,239,73,55,127,147,187,62,4,191,124,226,63,199,218,154,242,111,68,36,242,157,201,159,65,37,30,227,45,18) +IMAGE_DATA(216,198,4,54,241,18,223,108,241,146,93,68,16,183,208,45,136,242,225,48,143,238,110,81,117,117,90,254,100,24,205,135) +IMAGE_DATA(49,153,4,79,85,92,197,124,24,41,39,189,200,75,121,148,92,230,195,168,102,212,121,172,14,163,154,211,242,214,134,145) +IMAGE_DATA(205,83,179,54,140,234,61,104,251,120,50,140,154,216,67,248,3,197,141,153,188,36,39,77,4,254,243,212,148,174,36,62) +IMAGE_DATA(61,255,69,87,135,193,171,175,213,60,253,110,198,235,229,82,215,47,204,161,230,205,251,168,232,48,234,151,98,255,197,181) +IMAGE_DATA(217,253,87,158,141,98,158,250,126,174,172,48,121,234,255,248,233,23,115,253,148,101,241,18,171,230,93,62,191,71,106,127) +IMAGE_DATA(0,14,214,9,208,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0) +IMAGE_END_DATA(864, 7) diff --git a/uppsrc/ide/ide.key b/uppsrc/ide/ide.key index 9d643c0b9..74df4dac5 100644 --- a/uppsrc/ide/ide.key +++ b/uppsrc/ide/ide.key @@ -96,3 +96,6 @@ KEY(TOUPPER, "To uppercase", 0) KEY(TOLOWER, "To lowercase", 0) KEY(INITCAPS, "Capitalize the first character of words", 0) KEY(SWAPCASE, "Swap case", 0) + +KEY(DIFF, "Compare with file..", 0) +KEY(SVNDIFF, "Show svn history of file..", 0) diff --git a/uppsrc/ide/ide.upp b/uppsrc/ide/ide.upp index 77aeb9dae..64c5454fb 100644 --- a/uppsrc/ide/ide.upp +++ b/uppsrc/ide/ide.upp @@ -15,7 +15,8 @@ uses HexView, art\BlueBar, plugin/astyle, - usvn; + usvn, + TextDiffCtrl; link(WIN32 MSC) /MAP; @@ -59,6 +60,7 @@ file Calc.cpp, FormatCode.cpp, Abbr.cpp, + Diff.cpp, Compile readonly separator, Methods.cpp, AutoSetup.cpp, diff --git a/uppsrc/ide/idebar.cpp b/uppsrc/ide/idebar.cpp index fa76f16a3..388892786 100644 --- a/uppsrc/ide/idebar.cpp +++ b/uppsrc/ide/idebar.cpp @@ -342,6 +342,11 @@ void Ide::FilePropertiesMenu(Bar& menu) .Help("File properties stored in package"); menu.Add(IsActiveFile(), AK_SAVEENCODING, THISBACK(ChangeCharset)) .Help("Convert actual file to different encoding"); + menu.Add(IsActiveFile(), AK_DIFF, IdeImg::Diff(), THISBACK(Diff)) + .Help("Show differences between the project and arbitrary files"); + if(IsSvnDir(GetFileFolder(editfile))) + menu.Add(IsActiveFile(), AK_SVNDIFF, IdeImg::Diff(), THISBACK(SvnHistory)) + .Help("Show svn history of file"); } void Ide::BuildFileMenu(Bar& menu) diff --git a/uppsrc/ide/init b/uppsrc/ide/init index 8d58c3c02..9bc471689 100644 --- a/uppsrc/ide/init +++ b/uppsrc/ide/init @@ -15,4 +15,5 @@ #include "art\BlueBar/init" #include "plugin/astyle/init" #include "usvn/init" +#include "TextDiffCtrl/init" #endif