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