def format_posting(posting: Posting, indent: str = ' ') -> str: printer = beancount.parser.printer.EntryPrinter() flag_account, position_str, weight_str = printer.render_posting_strings( posting) oss = io.StringIO() oss.write(('%s%s %s' % (indent, flag_account, position_str)).rstrip() + '\n') if posting.meta: printer.write_metadata(posting.meta, oss, ' ' + indent) return oss.getvalue()
def get_diff(self): if self._cached_diff is not None: return self._cached_diff change_sets = [] new_entries = [] old_entries = [] printer = beancount.parser.printer.EntryPrinter() for filename, changed_entries in self.changed_entries.items(): changed_entries.sort(key=lambda x: float('inf') if x[0] is None else x[0].meta['lineno']) _, lines = self.journal_editor.get_journal_lines(filename) change_sets_builder = FileChangeSetsBuilder(filename=filename, lines=lines) for old_entry, new_entry in changed_entries: if new_entry is None: # Remove entry _, _, line_range = self.journal_editor.get_entry_line_range( old_entry) start_line = line_range[0] # Move start line up until non-whitespace line while start_line > 0 and not lines[start_line - 1].strip(): start_line -= 1 builder = change_sets_builder.add_builder( (start_line, line_range[1])) builder.delete_until(line_range[1]) old_entries.append(old_entry) elif old_entry is None: # Add new entry _, _, line_range = self.journal_editor.get_append_line_range( filename) builder = change_sets_builder.add_builder(line_range) builder.ensure_blank_line() new_entry = builder.set_metadata(new_entry) if isinstance(new_entry, Transaction): new_postings = [] cur_lineno = new_entry.meta['lineno'] + 1 + len( new_entry.meta.keys() - META_IGNORE) new_postings = [] for posting in new_entry.postings: posting = builder.set_metadata(posting, cur_lineno) cur_lineno += 1 + len(posting.meta.keys() - META_IGNORE) new_postings.append(posting) new_entry = new_entry._replace(postings=new_postings) new_entries.append(new_entry) added_lines = printer(new_entry).strip('\n').split('\n') added_lines = [x.rstrip() for x in added_lines] builder.add_lines(added_lines) else: # Change entry _, _, line_range = self.journal_editor.get_entry_line_range( old_entry) builder = change_sets_builder.add_builder(line_range) old_print_result = printer(old_entry).split('\n') new_print_result = printer(new_entry).split('\n') new_entry = builder.set_metadata(new_entry) if old_print_result[0] == new_print_result[0]: # First line is the same builder.keep_line() else: builder.replace_line(new_print_result[0].rstrip()) compute_metadata_changes(builder=builder, old_meta=old_entry.meta, new_meta=new_entry.meta, indent=2) assert isinstance(old_entry, Transaction) == isinstance( new_entry, Transaction) if isinstance(old_entry, Transaction): # handle postings next_old_posting_i = 0 new_postings = [] for new_posting in new_entry.postings: new_posting = builder.set_metadata(new_posting) new_postings.append(new_posting) if next_old_posting_i < len(old_entry.postings): old_posting = old_entry.postings[ next_old_posting_i] # posting replaces old_posting compute_posting_changes( builder=builder, old_posting=old_posting, new_posting=new_posting) next_old_posting_i += 1 else: new_posting_lines = [] new_posting_lines.append( get_posting_line(new_posting)) oss = io.StringIO() printer.write_metadata(new_posting.meta, oss, prefix=' ') metadata_text = oss.getvalue().strip('\n') if metadata_text: new_posting_lines.extend( metadata_text.split('\n')) builder.add_lines(new_posting_lines) # Delete all remaining old postings builder.delete_until(builder.line_range[1]) # Replace list of postings with postings containing updated filename and lineno # information. new_entry = new_entry._replace(postings=new_postings) old_entries.append(old_entry) new_entries.append(new_entry) change_sets.append(change_sets_builder.change_sets) self._cached_diff = change_sets, old_entries, new_entries return self._cached_diff
def format_metadata_line(key): oss = io.StringIO() printer.write_metadata({key: new_meta[key]}, oss, prefix=' ' * indent) return oss.getvalue().rstrip()