multiple ^s mean n-th previous
This commit is contained in:
+69
-43
@@ -49,7 +49,7 @@ namespace /* internal */
|
|||||||
LAST // ^
|
LAST // ^
|
||||||
};
|
};
|
||||||
|
|
||||||
struct token
|
struct token /* todo: string_view? */
|
||||||
{
|
{
|
||||||
token(const char* b, const char* e);
|
token(const char* b, const char* e);
|
||||||
explicit token(TokenType t)
|
explicit token(TokenType t)
|
||||||
@@ -69,6 +69,7 @@ namespace /* internal */
|
|||||||
using TokenIt = vector<token>::const_iterator;
|
using TokenIt = vector<token>::const_iterator;
|
||||||
|
|
||||||
/* internal data */
|
/* internal data */
|
||||||
|
const char* cur_file;
|
||||||
unsigned line = 1;
|
unsigned line = 1;
|
||||||
pair<person_id, person_id> prev_parents(Nobody, Nobody);
|
pair<person_id, person_id> prev_parents(Nobody, Nobody);
|
||||||
Tree* cur_tree;
|
Tree* cur_tree;
|
||||||
@@ -87,6 +88,7 @@ namespace /* internal */
|
|||||||
U32 sameNamedIndex(TokenIt& it);
|
U32 sameNamedIndex(TokenIt& it);
|
||||||
Sex parseSex(TokenIt& it, TokenIt end);
|
Sex parseSex(TokenIt& it, TokenIt end);
|
||||||
I32 processDatePart(const char*& it_date, const char* end_date);
|
I32 processDatePart(const char*& it_date, const char* end_date);
|
||||||
|
person_id parsePerson(TokenIt& it, TokenIt end);
|
||||||
pair<person_id, person_id> processParents(TokenIt& it, TokenIt end);
|
pair<person_id, person_id> processParents(TokenIt& it, TokenIt end);
|
||||||
vector<person_id> parseSpouses(TokenIt& it, TokenIt end); /* return the spouse IDs */
|
vector<person_id> parseSpouses(TokenIt& it, TokenIt end); /* return the spouse IDs */
|
||||||
|
|
||||||
@@ -97,6 +99,12 @@ namespace /* internal */
|
|||||||
|
|
||||||
|
|
||||||
/* errors */
|
/* errors */
|
||||||
|
void report_err()
|
||||||
|
{
|
||||||
|
endwin();
|
||||||
|
cerr << "In file " << cur_file << " Line " << line << ": ";
|
||||||
|
}
|
||||||
|
|
||||||
[[noreturn]]void err_unexpected_end()
|
[[noreturn]]void err_unexpected_end()
|
||||||
{
|
{
|
||||||
endwin();
|
endwin();
|
||||||
@@ -106,15 +114,15 @@ namespace /* internal */
|
|||||||
|
|
||||||
[[noreturn]]void err_unexpected_char(char c)
|
[[noreturn]]void err_unexpected_char(char c)
|
||||||
{
|
{
|
||||||
endwin();
|
report_err();
|
||||||
cerr << "Line " << line << ": Unexpected '" << c << "'\n";
|
cerr << "Unexpected '" << c << "'\n";
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
[[noreturn]]void err_expected(const char* what, token instead)
|
[[noreturn]]void err_expected(const char* what, token instead)
|
||||||
{
|
{
|
||||||
endwin();
|
report_err();
|
||||||
cerr << "Line " << line << ": Expected " << what << " got ";
|
cerr << "Expected " << what << " got ";
|
||||||
cerr.write(instead.begin, instead.size());
|
cerr.write(instead.begin, instead.size());
|
||||||
cerr << " instead\n";
|
cerr << " instead\n";
|
||||||
exit(1);
|
exit(1);
|
||||||
@@ -123,8 +131,8 @@ namespace /* internal */
|
|||||||
|
|
||||||
[[noreturn]]void err_unexpected_token(token t)
|
[[noreturn]]void err_unexpected_token(token t)
|
||||||
{
|
{
|
||||||
endwin();
|
report_err();
|
||||||
cerr << "Line " << line << ": Unexpected token '";
|
cerr << "Unexpected token '";
|
||||||
cerr.write(t.begin, t.size());
|
cerr.write(t.begin, t.size());
|
||||||
cerr << "'\n";
|
cerr << "'\n";
|
||||||
exit(1);
|
exit(1);
|
||||||
@@ -132,8 +140,8 @@ namespace /* internal */
|
|||||||
|
|
||||||
[[noreturn]]void err_illegal_attribute(token attr)
|
[[noreturn]]void err_illegal_attribute(token attr)
|
||||||
{
|
{
|
||||||
endwin();
|
report_err();
|
||||||
cerr << "Line " << line << ": Illegal attribute '";
|
cerr << "Illegal attribute '";
|
||||||
cerr.write(attr.begin, attr.size());
|
cerr.write(attr.begin, attr.size());
|
||||||
cerr << "'\n";
|
cerr << "'\n";
|
||||||
exit(1);
|
exit(1);
|
||||||
@@ -149,26 +157,34 @@ namespace /* internal */
|
|||||||
|
|
||||||
[[noreturn]]void err_personUndefined(const string& name)
|
[[noreturn]]void err_personUndefined(const string& name)
|
||||||
{
|
{
|
||||||
endwin();
|
report_err();
|
||||||
cerr << "Line " << line << ": '" << name << "' is undefined.\n"
|
cerr << "'" << name << "' is undefined.\n"
|
||||||
"Members need to be defined before they are used as relations\n";
|
"Members need to be defined before they are used as relations\n";
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
[[noreturn]]void err_indexExcedes(U32 index, U32 max)
|
[[noreturn]]void err_indexExcedes(U32 index, U32 max)
|
||||||
{
|
{
|
||||||
endwin();
|
report_err();
|
||||||
cerr << "Line " << line << ": '" << index << "' is too large.\n"
|
cerr << "'" << index << "' is too large.\n"
|
||||||
<< "At most the index after a name can be the number of people with the "
|
<< "At most the index after a name can be the number of people with the "
|
||||||
"same name already defined - 1, since the count starts from 0.\n"
|
"same name already defined - 1, since the count starts from 0.\n"
|
||||||
"In this case the max is " << max << '\n';
|
"In this case the max is " << max << '\n';
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[[noreturn]]void err_no_previous(token t, U32 requested, U32 actual)
|
||||||
|
{
|
||||||
|
report_err();
|
||||||
|
/* todo: print t */
|
||||||
|
cerr << requested << "th last person requested but only " << actual << " are defined so far\n";
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
[[noreturn]]void err_same_sex_spouse(const string& name, const Person& spouse)
|
[[noreturn]]void err_same_sex_spouse(const string& name, const Person& spouse)
|
||||||
{
|
{
|
||||||
endwin();
|
report_err();
|
||||||
cerr << "Line " << line << ": '" << name << "' and their spouse " << spouse.name
|
cerr << "'" << name << "' and their spouse " << spouse.name
|
||||||
<< " are both " << (spouse.sex == M ? "male" : "female") << '\n';
|
<< " are both " << (spouse.sex == M ? "male" : "female") << '\n';
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
@@ -199,9 +215,16 @@ namespace /* internal */
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(type == STRING)
|
if(type != NUMBER)
|
||||||
{
|
{
|
||||||
if(t.size() == 1)
|
if(t.begin[0] == '^')
|
||||||
|
{
|
||||||
|
type = LAST;
|
||||||
|
for(const char* p = t.begin; p < t.end; ++p)
|
||||||
|
if(*p != '^')
|
||||||
|
err_unexpected_char(*p);
|
||||||
|
}
|
||||||
|
else if(t.size() == 1)
|
||||||
{
|
{
|
||||||
switch(t.begin[0])
|
switch(t.begin[0])
|
||||||
{
|
{
|
||||||
@@ -211,9 +234,6 @@ namespace /* internal */
|
|||||||
case '-':
|
case '-':
|
||||||
type = REPEAT;
|
type = REPEAT;
|
||||||
break;
|
break;
|
||||||
case '^':
|
|
||||||
type = LAST;
|
|
||||||
break;
|
|
||||||
case '\n':
|
case '\n':
|
||||||
type = NEW_LINE;
|
type = NEW_LINE;
|
||||||
}
|
}
|
||||||
@@ -439,6 +459,27 @@ namespace /* internal */
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
person_id parsePerson(TokenIt& it, TokenIt end)
|
||||||
|
{
|
||||||
|
person_id person;
|
||||||
|
if(it->type == LAST)
|
||||||
|
{
|
||||||
|
if(it->size() > cur_tree->size())
|
||||||
|
err_no_previous(*it, it->size(), cur_tree->size());
|
||||||
|
|
||||||
|
person = cur_tree->last() - (it->size() - 1);
|
||||||
|
|
||||||
|
++it;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
string name = parseName(it, end);
|
||||||
|
U32 same_name_index = sameNamedIndex(it);
|
||||||
|
person = findPerson(name, same_name_index);
|
||||||
|
}
|
||||||
|
return person;
|
||||||
|
}
|
||||||
|
|
||||||
pair<person_id, person_id> processParents(TokenIt& it, TokenIt end)
|
pair<person_id, person_id> processParents(TokenIt& it, TokenIt end)
|
||||||
{
|
{
|
||||||
++it; /* skip attribute */
|
++it; /* skip attribute */
|
||||||
@@ -449,23 +490,13 @@ namespace /* internal */
|
|||||||
parents = prev_parents;
|
parents = prev_parents;
|
||||||
++it;
|
++it;
|
||||||
}
|
}
|
||||||
else if(it->type == LAST)
|
|
||||||
{
|
|
||||||
parents.first = cur_tree->last();
|
|
||||||
prev_parents = parents;
|
|
||||||
++it;
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
string name = parseName(it, end);
|
parents.first = parsePerson(it, end);
|
||||||
U32 same_name_index = sameNamedIndex(it);
|
|
||||||
parents.first = findPerson(name, same_name_index);
|
|
||||||
if(it->type == SEPARATOR)
|
if(it->type == SEPARATOR)
|
||||||
{
|
{
|
||||||
++it;
|
++it;
|
||||||
string name = parseName(it, end);
|
parents.second = parsePerson(it, end);
|
||||||
U32 same_name_index = sameNamedIndex(it);
|
|
||||||
parents.second = findPerson(name, same_name_index);
|
|
||||||
}
|
}
|
||||||
prev_parents = parents;
|
prev_parents = parents;
|
||||||
}
|
}
|
||||||
@@ -482,21 +513,13 @@ namespace /* internal */
|
|||||||
{
|
{
|
||||||
switch(it->type)
|
switch(it->type)
|
||||||
{
|
{
|
||||||
|
case LAST:
|
||||||
case STRING:
|
case STRING:
|
||||||
{
|
spouses.push_back(parsePerson(it, end));
|
||||||
string name = parseName(it, end); /* todo unify in 1 function */
|
|
||||||
U32 same_name_index = sameNamedIndex(it);
|
|
||||||
spouses.push_back(findPerson(name, same_name_index));
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case SEPARATOR:
|
case SEPARATOR:
|
||||||
++it;
|
++it;
|
||||||
break;
|
break;
|
||||||
case REPEAT:
|
|
||||||
case LAST:
|
|
||||||
++it;
|
|
||||||
spouses.push_back( cur_tree->last() );
|
|
||||||
break;
|
|
||||||
case NEW_LINE:
|
case NEW_LINE:
|
||||||
++line;
|
++line;
|
||||||
++it;
|
++it;
|
||||||
@@ -547,7 +570,7 @@ namespace /* internal */
|
|||||||
|
|
||||||
Sex sex = parseSex(it, end);
|
Sex sex = parseSex(it, end);
|
||||||
|
|
||||||
while(true)
|
while(true) /* Parse person attributes */
|
||||||
{
|
{
|
||||||
switch(it->type)
|
switch(it->type)
|
||||||
{
|
{
|
||||||
@@ -647,10 +670,13 @@ Tree parseTftFile(const char* path)
|
|||||||
|
|
||||||
Tree result(path);
|
Tree result(path);
|
||||||
cur_tree = &result;
|
cur_tree = &result;
|
||||||
|
cur_file = path;
|
||||||
|
|
||||||
MappedFile mapedfile = mapfile(file);
|
MappedFile mapedfile = mapfile(file);
|
||||||
|
|
||||||
vector<token> tokens = tokenize(mapedfile);
|
vector<token> tokens = tokenize(mapedfile);
|
||||||
|
|
||||||
|
// Parse the tokens
|
||||||
state_neutral(tokens);
|
state_neutral(tokens);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
|||||||
+1
-1
@@ -170,7 +170,7 @@ U16 person_box_height(ZoomLevel z)
|
|||||||
case ZoomLevel::ALL_NAMES:
|
case ZoomLevel::ALL_NAMES:
|
||||||
case ZoomLevel::FIRST_NAME:
|
case ZoomLevel::FIRST_NAME:
|
||||||
return 5;
|
return 5;
|
||||||
case NO_NAME:
|
case ZoomLevel::NO_NAME:
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -33,7 +33,7 @@ int main(int argc, char* argv[])
|
|||||||
|
|
||||||
init_ncurses();
|
init_ncurses();
|
||||||
|
|
||||||
if( !tree.isEmpty() )
|
if( !tree.empty() )
|
||||||
displayTree(tree);
|
displayTree(tree);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
+6
-1
@@ -98,7 +98,12 @@ Tree& Tree::operator-= (const Tree& other)
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Tree::isEmpty()
|
U32 Tree::size()
|
||||||
|
{
|
||||||
|
return people_.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Tree::empty()
|
||||||
{
|
{
|
||||||
return people_.empty();
|
return people_.empty();
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-2
@@ -40,7 +40,8 @@ public:
|
|||||||
Tree& operator+= (const Tree& other);
|
Tree& operator+= (const Tree& other);
|
||||||
Tree& operator-= (const Tree& other);
|
Tree& operator-= (const Tree& other);
|
||||||
|
|
||||||
bool isEmpty();
|
U32 size();
|
||||||
|
bool empty();
|
||||||
person_id last();
|
person_id last();
|
||||||
|
|
||||||
// Get person by id
|
// Get person by id
|
||||||
@@ -61,7 +62,8 @@ public:
|
|||||||
std::vector<person_id> findChildren(person_id person, person_id exclude) const; // exclude the child with the given ID
|
std::vector<person_id> findChildren(person_id person, person_id exclude) const; // exclude the child with the given ID
|
||||||
|
|
||||||
void addPerson(const char* name, Sex sex, person_id father=Nobody, person_id mother=Nobody, EventTime birth={}, EventTime death={});
|
void addPerson(const char* name, Sex sex, person_id father=Nobody, person_id mother=Nobody, EventTime birth={}, EventTime death={});
|
||||||
bool addRelation(person_id first, RelType, person_id second, bool update=true); //0 - failure 1 - success
|
// Return weather it succeeded or not
|
||||||
|
bool addRelation(person_id first, RelType, person_id second, bool update=true);
|
||||||
|
|
||||||
void removePerson(person_id id); //Removes a member and the last one takes his ID
|
void removePerson(person_id id); //Removes a member and the last one takes his ID
|
||||||
void removeRelation(person_id first, person_id second);
|
void removeRelation(person_id first, person_id second);
|
||||||
|
|||||||
@@ -11,28 +11,24 @@ man page
|
|||||||
types - screenCoord...
|
types - screenCoord...
|
||||||
|
|
||||||
tft descriton - multiple trees, why its better, features, ^
|
tft descriton - multiple trees, why its better, features, ^
|
||||||
tft ^ should expand to last person (for parents it doesnt)
|
|
||||||
tft merge trees relation
|
tft merge trees relation
|
||||||
|
|
||||||
Visualization:
|
Visualization:
|
||||||
- more granular zooming
|
- more granular zooming
|
||||||
- snap to selection/scroll with selection
|
- snap to selection/scroll with selection
|
||||||
|
- centralize when changing focus
|
||||||
- horizontal navigation between cousins
|
- horizontal navigation between cousins
|
||||||
- color on different consoles
|
- color on different consoles
|
||||||
- screen resize
|
- screen resize
|
||||||
- empty tree
|
- empty tree
|
||||||
- half children and main tree
|
- half children and main tree
|
||||||
- distinct tree regions
|
|
||||||
- aproximate birth day
|
- aproximate birth day
|
||||||
- indicator for people with their own tree
|
|
||||||
- centralize when changing focus
|
|
||||||
|
|
||||||
Compilation
|
Compilation
|
||||||
- static and dynamic ncurses
|
- static and dynamic ncurses
|
||||||
|
|
||||||
?
|
?
|
||||||
- info bar
|
- info bar
|
||||||
- tree visualizer component
|
|
||||||
- distinct regions of a tree
|
- distinct regions of a tree
|
||||||
- same person can be displayed twice
|
- same person can be displayed twice
|
||||||
- coordinate types for large trees
|
- coordinate types for large trees
|
||||||
|
|||||||
Reference in New Issue
Block a user