multiple ^s mean n-th previous

This commit is contained in:
vrd
2024-12-31 18:04:52 +02:00
parent b459aaf65d
commit 9f4739a057
6 changed files with 83 additions and 54 deletions
+70 -44
View File
@@ -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 */ break;
U32 same_name_index = sameNamedIndex(it);
spouses.push_back(findPerson(name, same_name_index));
}
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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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);
+1 -5
View File
@@ -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