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
+69 -43
View File
@@ -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
View File
@@ -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
View File
@@ -33,7 +33,7 @@ int main(int argc, char* argv[])
init_ncurses();
if( !tree.isEmpty() )
if( !tree.empty() )
displayTree(tree);
return 0;
+6 -1
View File
@@ -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
View File
@@ -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);
+1 -5
View File
@@ -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