/
dinruspro
/
DinrusIDE
Обзор
Документация
Войти
/
dinruspro
/
DinrusIDE
Код
Запросы
0
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
main
t.cpp
724 строки
18 KB
dinruspro
Очередные доработки
21 апр 2024, 12:35
21 апр 2024, 12:35
be87ef0
Код
Авторство
О чём код?
#include "DinrusIDE.h" struct FileLine : Moveable<FileLine> { String file; int line; }; struct LngEntry : Moveable<LngEntry, DeepCopyOption<LngEntry> > { bool added; VectorMap<int, String> text; Vector<FileLine> fileline; LngEntry(const LngEntry& e, int) { added = e.added; text <<= e.text; fileline <<= e.fileline; } LngEntry() {} void AddFileLine(CParser& p) { FileLine& fl = fileline.Add(); fl.file = p.GetFileName(); fl.line = p.GetLine(); } }; struct TFile : Moveable<TFile> { bool dirty; bool java; String package, file; VectorMap<String, LngEntry> map; Vector<int> ls; void MakeLS() { Index<int> lngset; lngset.Add(LNG_ruRU); for(int i = 0; i < map.GetCount(); i++) for(int j = 0; j < map[i].text.GetCount(); j++) lngset.FindAdd(map[i].text.GetKey(j)); ls = lngset.PickKeys(); Sort(ls); } rval_default(TFile); TFile() { dirty = false; } }; void t_error(CParser& p) { PutConsole(p.GetFileName() + Format("(%d): t_/tt_ работает только с простыми текстовыми литералами", p.GetLine())); } void LngParseCFile(const String& fn, VectorMap<String, LngEntry>& lng) { String data = LoadFile(fn); CParser p(data, fn); try { while(!p.IsEof()) { if((p.Id("t_") || p.Id("tt_")) && p.Char('(')) if(p.IsString()) { String tid = p.ReadString(); LngEntry& le = lng.GetAdd(tid); le.text.GetAdd(LNG_ruRU) = GetENUS(tid); le.AddFileLine(p); le.added = true; if(!p.Char(')')) t_error(p); } else t_error(p); else p.SkipTerm(); } } catch(CParser::Error e) { PutConsole(e); ShowConsole(); } } const Index<int>& LngIndex() { static Index<int> l; if(l.GetCount() == 0) { const int *x = GetAllLanguages(); while(*x) l.Add(*x++); } return l; } bool LngParseTFile(const String& fn, VectorMap<String, LngEntry>& lng) { String data = LoadFile(fn); CParser p(data, fn); try { if(p.Char('#')) while(!p.IsEof()) { if(p.IsChar2('T', '_')) break; else p.SkipTerm(); } String id; while(!p.IsEof()) { if(p.Id("T_")) { p.PassChar('('); id = Null; do id.Cat(p.ReadString()); while(p.Char('+')); p.PassChar(')'); lng.GetAdd(id).added = false; } else { if(IsNull(id)) p.ThrowError("отсутствует T_"); String lngs = p.ReadId(); p.PassChar('('); if(lngs.GetLength() == 4) { int lang = LNG_(ToUpper(lngs[0]), ToUpper(lngs[1]), ToUpper(lngs[2]), ToUpper(lngs[3])); if(LngIndex().Find(lang) >= 0) { String lt; do lt.Cat(p.ReadString()); while(p.Char('+')); lng.GetAdd(id).text.GetAdd(lang) = lt; p.PassChar(')'); continue; } } p.ThrowError("неверный язык"); } } } catch(CParser::Error e) { PutConsole(e); ShowConsole(); return false; } return true; } String CreateTFile(const VectorMap<String, LngEntry>& map, const Vector<int>& lngset, bool rep, bool obsolete, bool java) { const char *linepfx = (java ? " + " : " "); int ascflags = (java ? 0 : ASCSTRING_OCTALHI) | ASCSTRING_SMART; String out; String cfile; out << "#ifdef _MSC_VER\r\n#pragma setlocale(\"C\")\r\n#endif"; for(int i = 0; i < map.GetCount(); i++) { if(i) out << "\r\n"; const LngEntry& e = map[i]; String nc; if(e.fileline.GetCount()) nc = e.fileline[0].file; if(nc != cfile) { cfile = nc; if(!IsNull(cfile) && !rep) out << "\r\n// " << GetFileName(cfile) << "\r\n\r\n"; if(IsNull(cfile) && obsolete) out << "\r\n// Obsolete\r\n\r\n"; } if(!IsNull(cfile) || rep || obsolete) { String id = map.GetKey(i); out << "T_(" << AsCString(id, 70, linepfx, ascflags) << ")\r\n"; for(int j = 0; j < lngset.GetCount(); j++) { int lang = lngset[j]; if(rep || lang != LNG_ruRU) { int q = e.text.Find(lang); if(!rep || q >= 0 && !IsNull(e.text[q])) { int c = (lang >> 15) & 31; if(c) { out.Cat(c + 'a' - 1); c = (lang >> 10) & 31; if(c) { out.Cat(c + 'a' - 1); c = (lang >> 5) & 31; if(c) { out.Cat(c + 'A' - 1); c = lang & 31; if(c) out.Cat(c + 'A' - 1); } } } out << '(' << AsCString(q >= 0 ? e.text[q] : String(), 70, linepfx, ascflags) << ")\r\n"; } } } } } return out; } struct LangDlg : WithLangLayout<TopWindow> { void Serialize(Stream& s); Vector<TFile>& tfile; void AddLang(); void RemoveLang(); void AddLangAll(); void RemoveLangAll(); void EnterFile(); void EnterText(); void ToggleWork(); void LangMenu(Bar& bar); bool ShouldWrite(int i) { return file.Get(i, 1); } LangDlg(Vector<TFile>& map); }; void LangDlg::Serialize(Stream& s) { SerializePlacement(s); String f = file.GetKey(); int l = lang.GetKey(); String t = text.GetKey(); s % f % l % t; file.FindSetCursor(f); lang.FindSetCursor(l); text.FindSetCursor(t); } void LangDlg::AddLang() { if(!file.IsCursor()) return; WithAddLangLayout<TopWindow> dlg; CtrlLayoutOKCancel(dlg, "Добавить язык"); dlg.lang <<= dlg.Breaker(999); TFile& tf = tfile[file.GetCursor()]; Vector<int>& ls = tf.ls; for(;;) { int l = ~dlg.lang; dlg.ok.Enable((l & 31) && FindIndex(ls, l) < 0); switch(dlg.Run()) { case IDOK: l = ~dlg.lang; if(FindIndex(ls, l) < 0) { ls.Add(l); tf.dirty = true; Sort(ls); EnterFile(); lang.FindSetCursor(l); return; } break; case IDCANCEL: return; } } } void LangDlg::AddLangAll() { WithAddLangLayout<TopWindow> dlg; CtrlLayoutOKCancel(dlg, "Добавить ко всем"); if(dlg.Run() != IDOK) return; int l = ~dlg.lang; for(int i = 0; i < tfile.GetCount(); i++) { TFile& tf = tfile[i]; Vector<int>& ls = tf.ls; if(FindIndex(ls, l) < 0) { ls.Add(l); tf.dirty = true; Sort(ls); } } EnterFile(); lang.FindSetCursor(l); } void LangDlg::RemoveLang() { if(file.IsCursor() && lang.IsCursor() && (int)lang.GetKey() != LNG_ruRU && PromptOKCancel("Удалить выбранную версию языка?")) { TFile& tf = tfile[file.GetCursor()]; tf.ls.Remove(lang.GetCursor()); tf.dirty = true; EnterFile(); } } void LangDlg::RemoveLangAll() { WithAddLangLayout<TopWindow> dlg; CtrlLayoutOKCancel(dlg, "Удалить из всех"); if(file.IsCursor() && lang.IsCursor()) dlg.lang <<= tfile[file.GetCursor()].ls[lang.GetCursor()]; if(dlg.Run() != IDOK) return; int l = ~dlg.lang; for(int i = 0; i < tfile.GetCount(); i++) { TFile& tf = tfile[i]; Vector<int>& ls = tf.ls; int q = FindIndex(ls, l); if(q >= 0) { ls.Remove(q); tf.dirty = true; Sort(ls); } } EnterFile(); lang.FindSetCursor(l); } void LangDlg::LangMenu(Bar& bar) { bar.Add(file.IsCursor(), "Добавить..", [=, this] { AddLang(); }); bar.Add(lang.IsCursor(), "Удалить", [=, this] { RemoveLang(); }); bar.Separator(); bar.Add(file.IsCursor(), "Добавить ко всем..", [=, this] { AddLangAll(); }); bar.Add(lang.IsCursor(), "Удалить из всех..", [=, this] { RemoveLangAll(); }); } struct FontAndColorDisplay : Display { Font font; Color color; void Paint(Draw& w, const Rect& r, const Value& q, Color ink, Color paper, dword s) const { w.DrawRect(r, paper); String vt = q; const char *txt = GetENUS(vt); int x = r.left; if(txt != ~vt) { String id(~vt, txt - 1); w.DrawText(x, r.top, id, font, txt[-1] == '\a' ? LtRed : Magenta); x += GetTextSize(id, font).cx + 6; } w.DrawText(x, r.top, AsCString(txt), font, ink); } FontAndColorDisplay(Font f, Color c) : font(f), color(c) {} }; void LangDlg::EnterFile() { TFile& tf = tfile[file.GetCursor()]; Sort(tf.ls); lang.Clear(); for(int i = 0; i < tf.ls.GetCount(); i++) lang.Add(tf.ls[i], LNGAsText(tf.ls[i])); lang.GoBegin(); static FontAndColorDisplay normal(ArialZ(11)(), Null); static FontAndColorDisplay added(ArialZ(11)().Bold(), Null); static FontAndColorDisplay obsolete(ArialZ(11)().Italic(), Null); text.Clear(); for(int i = 0; i < tf.map.GetCount(); i++) { text.Add(tf.map.GetKey(i)); LngEntry& e = tf.map[i]; Display *d; if(e.fileline.GetCount() == 0) d = &obsolete; else if(e.added) d = &added; else d = &normal; text.SetDisplay(text.GetCount() - 1, 0, *d); } text.GoBegin(); } void LangDlg::EnterText() { source.Clear(); VectorMap<String, LngEntry>& map = tfile[file.GetCursor()].map; int q = text.GetCursor(); if(q < 0 || q >= map.GetCount()) return; LngEntry& e = map[q]; for(int i = 0; i < e.fileline.GetCount(); i++) { FileLine& f = e.fileline[i]; source.Add(f.file, f.line, GetFileName(f.file) + " (" + AsString(f.line) + ")"); } } void LangDlg::ToggleWork() { if(file.GetCount()) { bool q = !(int)file.Get(0, 1); for(int i = 0; i < file.GetCount(); i++) file.Set(i, 1, q); } } LangDlg::LangDlg(Vector<TFile>& tfile) : tfile(tfile) { CtrlLayoutOKCancel(*this, "Файлы переводов"); file.AddColumn("Файл"); HeaderCtrl::Column& m = file.AddColumn().Ctrls<Option>().HeaderTab(); m.SetImage(IdeImg::work()); m.WhenAction = [=, this] { ToggleWork(); }; file.WhenEnterRow = [=, this] { EnterFile(); }; file.ColumnWidths("144 27"); lang.AddIndex(); lang.AddColumn("Версии"); lang.WhenBar = [=, this] (Bar& bar) { LangMenu(bar); }; text.AddColumn("Текст"); text.WhenEnterRow = [=, this] { EnterText(); }; help << [=] { LaunchWebBrowser("https://www.ultimatepp.org/srcdoc$Core$i18n_en-us.html"); }; source.AddIndex(); source.AddIndex(); source.AddColumn("Исходник"); source.WhenLeftDouble = Breaker(IDYES); for(int i = 0; i < tfile.GetCount(); i++) file.Add(tfile[i].package + '/' + tfile[i].file, 1); file.GoBegin(); Icon(IdeImg::Language()); Sizeable().Zoomable(); } class ExportTrDlg : public WithExportTrLayout<TopWindow> { SelectDirButton of; typedef ExportTrDlg CLASSNAME; public: ExportTrDlg(); }; ExportTrDlg::ExportTrDlg() { CtrlLayoutOKCancel(*this, "Экспортировать в файл .tr"); DlCharsetD(charset); of.Attach(folder); charset <<= CHARSET_UTF8; lang <<= LNG_RUSSIAN; } String ExportTr(const Vector<TFile>& tfile, int& cs) { ExportTrDlg dlg; LoadFromGlobal(dlg, "tr-export"); int c = dlg.Run(); StoreToGlobal(dlg, "tr-export"); if(c != IDOK) return Null; int lng = ~dlg.lang; cs = ~dlg.charset; String fn = AppendFileName(~dlg.folder, LNGAsText(lng) + "." + CharsetName(cs) + ".tr"); FileOut out(fn); if(!out) { Exclamation("Не удаётся открыть файл вывода:&[* \1" + fn); return Null; } out << "LANGUAGE " << AsCString(LNGAsText(SetLNGCharset(lng, cs))) << ";\r\n"; for(int i = 0; i < tfile.GetCount(); i++) { const TFile& m = tfile[i]; out << "// " << m.package << "/" << m.file << "\r\n"; for(int j = 0; j < m.map.GetCount(); j++) out << AsCString(m.map.GetKey(j), 70) << ",\r\n" << "\t" << AsCString(ToCharset(cs, m.map[j].text.Get(lng, ""), CHARSET_UTF8), 60, "\t", ASCSTRING_SMART) << ";\r\n\r\n"; } return fn; } void Ide::SyncT(int kind) { console.Clear(); String filepath = GetActiveFilePath(); SaveFile(); TFile repository; LngParseTFile(ConfigFile("repository.t"), repository.map); if(kind == 1) { FileSel fs; fs.ActiveDir(AnySourceFs().GetActiveDir()); fs.Type("Файл перевода рантаймный (*.tr)", "*.tr"); fs.AllFilesType(); LoadFromGlobal(fs, "fs-tr"); bool b = fs.ExecuteOpen("Импортировать файл перевода"); StoreToGlobal(fs, "fs-tr"); if(!b) return; String tr = LoadFile(~fs); CParser p(tr); try { while(!p.IsEof()) { p.PassId("LANGUAGE"); int lang = LNGFromText(p.ReadString()); if(!lang) p.ThrowError("Неверный Язык"); p.PassChar(';'); byte cs = GetLNGCharset(lang); lang &= LNGC_(255, 255, 255, 255, 0); while(p.IsString()) { String id = p.ReadString(); p.PassChar(','); repository.map.GetAdd(id).text.GetAdd(lang) = ToCharset(CHARSET_UTF8, p.ReadString(), cs); p.PassChar(';'); } } } catch(CParser::Error& e) { PutConsole(e); Exclamation("Неудача: \1" + e); return; } } Vector<TFile> tfile; Vector<int> mainsT; Progress pi; const Workspace& wspc = IdeWorkspace(); pi.SetTotal(wspc.GetCount()); for(int iPackage = 0; iPackage < wspc.GetCount(); iPackage++) { const Package& pk = wspc.GetPackage(iPackage); String n = wspc[iPackage]; pi.SetText("Сканируется " + n); if(pi.StepCanceled()) return; VectorMap<String, LngEntry> pmap; for(int iFile = 0; iFile < pk.file.GetCount(); iFile++) { String file = SourcePath(n, pk.file[iFile]); LngParseCFile(SourcePath(GetActivePackage(), file), pmap); } bool localT = false; for(int iFile = 0; iFile < pk.file.GetCount(); iFile++) { String file = SourcePath(n, pk.file[iFile]); String ext = GetFileExt(file); if(ext == ".t" || ext == ".jt") { VectorMap<String, LngEntry> tmap(pmap, 0); if(LngParseTFile(file, tmap)) { TFile& tf = tfile.Add(); tf.java = (ext == ".jt"); tf.package = n; tf.file = pk.file[iFile]; tf.map = pick(tmap); tf.MakeLS(); // mark that we've found a local translation file localT = true; // store index of main package translation(s) file(s) if(iPackage == 0) mainsT.Add(tfile.GetCount() - 1); } } } // if no local translation file(s), we append translation to // main package one(s), if any if(!localT && iPackage > 0) { for(int i = 0; i < mainsT.GetCount(); i++) { VectorMap<String, LngEntry> &map = tfile[mainsT[i]].map; for(int iEntry = 0; iEntry < pmap.GetCount(); iEntry++) { int idx = map.Find(pmap.GetKey(iEntry)); if(idx < 0) { map.Add(pmap.GetKey(iEntry), clone(pmap[iEntry])); idx = map.GetCount() - 1; } LngEntry &entry = map[idx]; if(!entry.fileline.GetCount()) { LngEntry &pEntry = pmap[iEntry]; for(int iLc = 0; iLc < pEntry.fileline.GetCount(); iLc++) { FileLine &fl = entry.fileline.Add(); String file = GetFileName(pEntry.fileline[iLc].file); file = "PACKAGE '" + GetFileName(n) + "' FILE '" + file + "'"; fl.file = file; fl.line = pEntry.fileline[iLc].line; } } } } } } if(kind == 2) { for(int i = 0; i < tfile.GetCount(); i++) { TFile& tf = tfile[i]; for(int ii = 0; ii < tf.map.GetCount(); ii++) { LngEntry& tle = tf.map[ii]; LngEntry& rle = repository.map.GetAdd(tf.map.GetKey(ii)); for(int l = 0; l < tle.text.GetCount(); l++) if(!IsNull(tle.text[l])) rle.text.GetAdd(tle.text.GetKey(l)) = tle.text[l]; } } int cs; String fn = ExportTr(tfile, cs); if(!IsNull(fn)) { EditFile(fn); int c = filelist.GetCursor(); FlushFile(); ActiveFile().charset = (byte)cs; SavePackage(); PackageCursor(); if(c >= 0) filelist.SetCursor(c); editor.ClearUndo(); } return; } LangDlg dlg(tfile); LoadFromWorkspace(dlg, "Tdlg"); switch(dlg.Execute()) { case IDCANCEL: return; case IDYES: if(dlg.source.IsCursor()) { EditFile(dlg.source.Get(0)); editor.SetCursor(editor.GetPos64(editor.GetLineNo((int)dlg.source.Get(1) - 1))); editor.CenterCursor(); editor.SetFocus(); StoreToWorkspace(dlg, "Tdlg"); return; } } StoreToWorkspace(dlg, "Tdlg"); FlushFile(); for(int i = 0; i < tfile.GetCount(); i++) { TFile& tf = tfile[i]; for(int ii = 0; ii < tf.map.GetCount(); ii++) { int q = repository.map.Find(tf.map.GetKey(ii)); if(q >= 0) { LngEntry& tle = tf.map[ii]; LngEntry& rle = repository.map[q]; for(int l = 0; l < tf.ls.GetCount(); l++) { q = rle.text.Find(tf.ls[l]); if(q >= 0) tle.text.GetAdd(tf.ls[l]) = rle.text[q]; } } } } pi.SetTotal(tfile.GetCount()); for(int i = 0; i < tfile.GetCount(); i++) { TFile& tf = tfile[i]; String td = CreateTFile(tf.map, tf.ls, false, !dlg.remove, tf.java); String fp = SourcePath(tf.package, tf.file); pi.SetText("Сохранение " + tf.package + '/' + tf.file); if(pi.StepCanceled()) break; if(dlg.ShouldWrite(i) && LoadFile(fp) != td) ::SaveFile(fp, td); } repository.MakeLS(); ::SaveFile(ConfigFile("repository.t"), CreateTFile(repository.map, repository.ls, true, false, false)); FileCursor(); } void Ide::ConvertST() { if(!PromptYesNo("Преобразовать проект в переводы t_?")) return; FlushFile(); TFile repository; LngParseTFile(ConfigFile("repository.t"), repository.map); Progress pi; const Workspace& wspc = IdeWorkspace(); pi.SetTotal(wspc.GetCount()); for(int i = 0; i < wspc.GetCount(); i++) { const Package& pk = wspc.GetPackage(i); String n = wspc[i]; pi.SetText("Преобразуется " + n); if(pi.StepCanceled()) return; VectorMap<String, LngEntry> pmap; for(int i = 0; i < pk.file.GetCount(); i++) { String file = SourcePath(n, pk.file[i]); String data = LoadFile(file); CParser p(data); String r; const char *b = data; while(!p.IsEof()) { p.Spaces(); const char *w = p.GetPtr(); if(p.Id("s_") && p.Char('(') && p.IsId()) { String id = p.ReadId(); int q = repository.map.Find(id); if(q >= 0) { LngEntry& e = repository.map[q]; q = e.text.Find(LNG_ruRU); if(q >= 0) { r.Cat(b, w); r.Cat("t_("); r.Cat(AsCString(e.text[q])); b = p.GetPtr(); } } } else p.SkipTerm(); } r.Cat(b); if(r != data) ::SaveFile(file, r); } } FileCursor(); }