.ide Refactor MacroManager by extracting logic to UscFileParser.

git-svn-id: svn://ultimatepp.org/upp/trunk@11091 f0d560ea-af0d-0410-9eb7-867de7ffcac7
This commit is contained in:
klugier 2017-05-15 21:21:13 +00:00
parent decfea7cdc
commit 4bb4685dd6
7 changed files with 271 additions and 243 deletions

View file

@ -0,0 +1,21 @@
#include "ide.h"
MacroElement::MacroElement(Type type, const String& fileName, int line, const String& comment)
: type(type)
, comment(comment)
, fileName(fileName)
, line(line)
{}
Image MacroElement::GetImage(Type type)
{
switch(type)
{
case(Type::MACRO):
return IdeImg::Macro();
case(Type::FUNCTION):
return IdeImg::Fn();
case(Type::UNKNOWN):
return Image();
}
}

View file

@ -1,99 +1,7 @@
#include "ide.h"
class MacroElement {
public:
enum class Type {
MACRO,
FUNCTION,
UNKNOWN
};
public:
MacroElement(Type type, const String& fileName, int line, const String& comment);
static Image GetImage(Type type);
public:
Type type;
String comment;
String name;
String prototype;
String args;
String code;
String fileName;
int line;
};
MacroElement::MacroElement(Type type, const String& fileName, int line, const String& comment)
: type(type)
, comment(comment)
, fileName(fileName)
, line(line)
{}
Image MacroElement::GetImage(Type type)
{
switch(type)
{
case(Type::MACRO):
return IdeImg::Macro();
case(Type::FUNCTION):
return IdeImg::Fn();
case(Type::UNKNOWN):
return Image();
}
return Image();
}
#define METHOD_NAME "MacroManagerWindow " << UPP_FUNCTION_NAME << "(): "
using MacroList = Array<MacroElement>;
class MacroManagerWindow final : public WithMacroManagerLayout<TopWindow> {
using MacroStore = ArrayMap<String, Array<MacroElement>>;
public:
MacroManagerWindow(Ide& ide);
void Layout() override;
private:
void InitButtons();
MacroList LoadUscFile(const String& fileName);
void LoadUscDir(const String& dir, MacroList& store);
void LoadMacros();
void ReloadGlobalMacros();
void ReloadLocalMacros();
void OnMacroSel();
void OnImport();
void OnExport();
void OnEditFile();
void ExportFiles(Index<String>& files, const String& dir);
void FindNodeFiles(int id, Index<String>& list);
void ReadFunction(CParser& parser, const String& comment, const char* prototypeBegin, MacroList& list);
void ReadMacro(CParser& parser, const String& comment, const char* prototypeBegin, MacroList& list);
void FinishRead(CParser& parser, const char* prototypeBegin, MacroElement& element, MacroList& list);
private:
static String ReadArgs(CParser& parser);
static String ReadKeyDesc(CParser& parser);
static String GenFileOverrideMessage(const String& fileName);
private:
// TODO: MacroManager shold not depend upon Ide instance.
// The edit logic should be outside class the same as load macros.
Ide& ide;
TreeCtrl macrosTree;
SplitterFrame splitter;
CodeEditor editor;
};
MacroManagerWindow::MacroManagerWindow(Ide& ide)
: ide(ide)
{
@ -262,152 +170,6 @@ void MacroManagerWindow::OnEditFile()
Break();
}
static void FindNext(CParser& parser)
{
while(!parser.IsEof() && !parser.IsId("fn") && !parser.IsId("macro"))
parser.SkipTerm();
}
void MacroManagerWindow::ReadFunction(CParser& parser, const String& comment, const char* prototypeBegin, MacroList& list)
{
String fileName = parser.GetFileName();
MacroElement fn(MacroElement::Type::FUNCTION, fileName, parser.GetLine(), comment);
if(!parser.IsId()) {
FindNext(parser);
return;
}
fn.name = parser.ReadId();
if(!parser.Char('(')) {
FindNext(parser);
return;
}
fn.args = ReadArgs(parser);
FinishRead(parser, prototypeBegin, fn, list);
}
void MacroManagerWindow::ReadMacro(CParser& parser, const String& comment, const char* prototypeBegin, MacroList& list)
{
String fileName = parser.GetFileName();
MacroElement macro(MacroElement::Type::MACRO, fileName, parser.GetLine(), comment);
if(!parser.IsString()) {
FindNext(parser);
return;
}
macro.name = String() << (parser.IsString() ? parser.ReadString() : "");
if(parser.Char(':')) {
if(!parser.IsString()) {
FindNext(parser);
return;
}
macro.name << " : " << (parser.IsString() ? parser.ReadString() : "");
}
if (!parser.IsChar('{'))
ReadKeyDesc(parser);
FinishRead(parser, prototypeBegin, macro, list);
}
void MacroManagerWindow::FinishRead(CParser& parser, const char* prototypeBegin, MacroElement& element, MacroList& list)
{
const char* bodyBegin = parser.GetPtr();
element.prototype = String(prototypeBegin, bodyBegin);
if (!parser.Char('{')) {
FindNext(parser);
return;
}
Upp::SkipBlock(parser);
if(parser.GetSpacePtr() > bodyBegin)
element.code = String(bodyBegin, parser.GetSpacePtr());
list.Add(element);
}
MacroList MacroManagerWindow::LoadUscFile(const String& fileName)
{
MacroList ret;
String fileContent = LoadFile(fileName);
if(fileContent.IsEmpty()) {
Logw() << METHOD_NAME << "Following file \"" << fileName << "\" doesn't exist or is empty.";
return ret;
}
try {
CParser parser(fileContent, fileName);
while (!parser.IsEof()) {
String comment = TrimLeft(String(parser.GetSpacePtr(), parser.GetPtr()));
if (!parser.IsId())
return ret;
const char* prototypeBegin = parser.GetPtr();
String id = parser.ReadId();
if(id.IsEqual("fn"))
ReadFunction(parser, comment, prototypeBegin, ret);
else
if(id.IsEqual("macro"))
ReadMacro(parser, comment, prototypeBegin, ret);
else
return ret;
}
}
catch (const CParser::Error& error) {
Logw() << METHOD_NAME << "Parsing file \"" << fileName << "\" failed with error: " << error << ".";
}
return ret;
}
String MacroManagerWindow::ReadArgs(CParser& parser)
{
int level = 1;
parser.Char('(');
String ret = "(";
while(level > 0 && !parser.IsEof()) {
if (parser.Char('('))
level++;
else
if (parser.Char(')'))
level--;
else
ret << parser.GetChar();
}
ret << ")";
return ret;
}
String MacroManagerWindow::ReadKeyDesc(CParser& parser)
{
if(!parser.IsId())
return String();
String ret = parser.ReadId();
while(!parser.IsEof() && parser.Char('+')) {
if(parser.IsId())
ret << "+" << parser.ReadId();
else
if(parser.IsNumber())
ret << "+" << parser.ReadInt();
else
break;
}
return ret;
}
String MacroManagerWindow::GenFileOverrideMessage(const String& fileName)
{
return String(t_("Target file")) << " \"" << fileName << "\" " << t_("already exists! Do you want to overwrite it?");
@ -417,7 +179,7 @@ void MacroManagerWindow::LoadUscDir(const String& dir, MacroList& store)
{
for(FindFile ff(AppendFileName(dir, "*.usc")); ff; ff.Next())
{
MacroList list = LoadUscFile(AppendFileName(dir, ff.GetName()));
auto list = UscFileParser(AppendFileName(dir, ff.GetName())).Parse();
if(list.GetCount())
store.AppendRange(list);
}
@ -475,7 +237,7 @@ void MacroManagerWindow::ReloadLocalMacros()
if (ToLower(GetFileExt(filePath)) != ".usc")
continue;
MacroList list = LoadUscFile(filePath);
auto list = UscFileParser(filePath).Parse();
if (list.GetCount() == 0)
continue;
@ -491,8 +253,6 @@ void MacroManagerWindow::ReloadLocalMacros()
}
}
#undef METHOD_NAME
void Ide::DoMacroManager()
{
MacroManagerWindow(*this).Execute();

87
uppsrc/ide/MacroManager.h Normal file
View file

@ -0,0 +1,87 @@
// TODO: Move to separate package...
class MacroElement {
public:
enum class Type {
MACRO,
FUNCTION,
UNKNOWN
};
public:
MacroElement(Type type, const String& fileName, int line, const String& comment);
static Image GetImage(Type type);
public:
Type type;
String comment;
String name;
String prototype;
String args;
String code;
String fileName;
int line;
};
using MacroList = Array<MacroElement>;
class UscFileParser final {
public:
UscFileParser(const String& filePath);
MacroList Parse();
private:
void ReadFunction(CParser& parser, const String& comment, const char* prototypeBegin, MacroList& list);
void ReadMacro(CParser& parser, const String& comment, const char* prototypeBegin, MacroList& list);
void FinishRead(CParser& parser, const char* prototypeBegin, MacroElement& element, MacroList& list);
private:
static void FindNextElement(CParser& parser);
static String ReadArgs(CParser& parser);
static String ReadKeyDesc(CParser& parser);
private:
String filePath;
};
class MacroManagerWindow final : public WithMacroManagerLayout<TopWindow> {
public:
using MacroStore = ArrayMap<String, Array<MacroElement>>;
public:
MacroManagerWindow(Ide& ide);
void Layout() override;
private:
void InitButtons();
void LoadUscDir(const String& dir, MacroList& store);
void LoadMacros();
void ReloadGlobalMacros();
void ReloadLocalMacros();
void OnMacroSel();
void OnImport();
void OnExport();
void OnEditFile();
void ExportFiles(Index<String>& files, const String& dir);
void FindNodeFiles(int id, Index<String>& list);
private:
static String GenFileOverrideMessage(const String& fileName);
private:
// TODO: MacroManager shold not depend upon Ide instance.
// The edit logic should be outside class the same as load macros.
Ide& ide;
TreeCtrl macrosTree;
SplitterFrame splitter;
CodeEditor editor;
};

View file

@ -0,0 +1,154 @@
#include "ide.h"
#define METHOD_NAME "UscFileParser::" << UPP_FUNCTION_NAME << "(): "
UscFileParser::UscFileParser(const String& filePath)
: filePath(filePath)
{}
MacroList UscFileParser::Parse()
{
MacroList ret;
String fileContent = LoadFile(filePath);
if(fileContent.IsEmpty()) {
Logw() << METHOD_NAME << "Following file \"" << filePath << "\" doesn't exist or is empty.";
return ret;
}
try {
CParser parser(fileContent, filePath);
while (!parser.IsEof()) {
String comment = TrimLeft(String(parser.GetSpacePtr(), parser.GetPtr()));
if (!parser.IsId())
return ret;
const char* prototypeBegin = parser.GetPtr();
String id = parser.ReadId();
if(id.IsEqual("fn"))
ReadFunction(parser, comment, prototypeBegin, ret);
else
if(id.IsEqual("macro"))
ReadMacro(parser, comment, prototypeBegin, ret);
else
return ret;
}
}
catch (const CParser::Error& error) {
Logw() << METHOD_NAME << "Parsing file \"" << filePath << "\" failed with error: " << error << ".";
}
return ret;
}
void UscFileParser::ReadFunction(CParser& parser, const String& comment, const char* prototypeBegin, MacroList& list)
{
String fileName = parser.GetFileName();
MacroElement fn(MacroElement::Type::FUNCTION, fileName, parser.GetLine(), comment);
if(!parser.IsId()) {
FindNextElement(parser);
return;
}
fn.name = parser.ReadId();
if(!parser.Char('(')) {
FindNextElement(parser);
return;
}
fn.args = ReadArgs(parser);
FinishRead(parser, prototypeBegin, fn, list);
}
void UscFileParser::ReadMacro(CParser& parser, const String& comment, const char* prototypeBegin, MacroList& list)
{
String fileName = parser.GetFileName();
MacroElement macro(MacroElement::Type::MACRO, fileName, parser.GetLine(), comment);
if(!parser.IsString()) {
FindNextElement(parser);
return;
}
macro.name = String() << (parser.IsString() ? parser.ReadString() : "");
if(parser.Char(':')) {
if(!parser.IsString()) {
FindNextElement(parser);
return;
}
macro.name << " : " << (parser.IsString() ? parser.ReadString() : "");
}
if (!parser.IsChar('{'))
ReadKeyDesc(parser);
FinishRead(parser, prototypeBegin, macro, list);
}
void UscFileParser::FinishRead(CParser& parser, const char* prototypeBegin, MacroElement& element, MacroList& list)
{
const char* bodyBegin = parser.GetPtr();
element.prototype = String(prototypeBegin, bodyBegin);
if (!parser.Char('{')) {
FindNextElement(parser);
return;
}
Upp::SkipBlock(parser);
if(parser.GetSpacePtr() > bodyBegin)
element.code = String(bodyBegin, parser.GetSpacePtr());
list.Add(element);
}
void UscFileParser::FindNextElement(CParser& parser)
{
while(!parser.IsEof() && !parser.IsId("fn") && !parser.IsId("macro"))
parser.SkipTerm();
}
String UscFileParser::ReadArgs(CParser& parser)
{
int level = 1;
parser.Char('(');
String ret = "(";
while(level > 0 && !parser.IsEof()) {
if (parser.Char('('))
level++;
else
if (parser.Char(')'))
level--;
else
ret << parser.GetChar();
}
ret << ")";
return ret;
}
String UscFileParser::ReadKeyDesc(CParser& parser)
{
if(!parser.IsId())
return String();
String ret = parser.ReadId();
while(!parser.IsEof() && parser.Char('+')) {
if(parser.IsId())
ret << "+" << parser.ReadId();
else
if(parser.IsNumber())
ret << "+" << parser.ReadInt();
else
break;
}
return ret;
}

View file

@ -306,6 +306,7 @@ void InsertPath(EditString *es);
void DlSpellerLangs(DropList& dl);
#include "Assist.h"
#include "MacroManager.h"
void DirSel(EditField& f, FrameRight<Button>& b);
bool CopyFolder(const char *dst, const char *src, Progress *pi);

View file

@ -80,6 +80,10 @@ file
Xml.cpp,
Json.cpp,
Update.cpp,
MacroManager readonly separator,
MacroManager.h,
MacroElement.cpp,
UscFileParser.cpp,
MacroManager.cpp,
Compile readonly separator,
MethodsCtrls.h,

View file

@ -602,7 +602,8 @@ void Ide::BrowseMenu(Bar& menu)
.Check(editor.IsNavigator())
.Enable(!designer);
menu.Add(AK_GOTO, THISBACK(SearchCode))
.Enable(!designer);
.Enable(!designer)
.Help("Go to given line");
menu.Add(AK_GOTOGLOBAL, THISBACK(NavigatorDlg));
menu.Add(!designer, AK_JUMPS, THISBACK(ContextGoto));
menu.Add(!designer, AK_SWAPS, THISBACK(SwapS));