Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package vit for openSUSE:Factory checked in at 2022-05-25 20:34:30 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/vit (Old) and /work/SRC/openSUSE:Factory/.vit.new.2254 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "vit" Wed May 25 20:34:30 2022 rev:7 rq:979057 version:2.2.0 Changes: -------- --- /work/SRC/openSUSE:Factory/vit/vit.changes 2021-06-24 18:22:51.288934894 +0200 +++ /work/SRC/openSUSE:Factory/.vit.new.2254/vit.changes 2022-05-25 20:34:46.436245368 +0200 @@ -1,0 +2,9 @@ +Tue May 24 20:40:11 UTC 2022 - Mia Herkt <[email protected]> + +- Update to 2.2.0 + * Require Python >= 3.7 + * Simplify timezone handling + * Replace pytz and tzlocal by zoneinfo + * Make vit respect taskrc in config.ini + +------------------------------------------------------------------- Old: ---- vit-2.1.0.tar.gz New: ---- vit-2.2.0.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ vit.spec ++++++ --- /var/tmp/diff_new_pack.zqSsgn/_old 2022-05-25 20:34:46.948246082 +0200 +++ /var/tmp/diff_new_pack.zqSsgn/_new 2022-05-25 20:34:46.948246082 +0200 @@ -1,7 +1,7 @@ # # spec file for package vit # -# Copyright (c) 2021 SUSE LLC +# Copyright (c) 2022 SUSE LLC # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -17,7 +17,7 @@ Name: vit -Version: 2.1.0 +Version: 2.2.0 Release: 0 Summary: Visual Interactive Taskwarrior full-screen terminal interface License: MIT @@ -27,12 +27,12 @@ BuildRequires: bash-completion BuildRequires: fdupes BuildRequires: python-rpm-macros +BuildRequires: python3-base >= 3.7 BuildRequires: python3-setuptools BuildRequires: python3-tasklib -BuildRequires: python3-tzlocal BuildRequires: python3-urwid +Requires: python3-base >= 3.7 Requires: python3-tasklib -Requires: python3-tzlocal Requires: python3-urwid Requires: taskwarrior BuildArch: noarch ++++++ vit-2.1.0.tar.gz -> vit-2.2.0.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/vit-2.1.0/AUTHORS.md new/vit-2.2.0/AUTHORS.md --- old/vit-2.1.0/AUTHORS.md 1970-01-01 01:00:00.000000000 +0100 +++ new/vit-2.2.0/AUTHORS.md 2020-12-24 04:52:45.000000000 +0100 @@ -0,0 +1,36 @@ +The development of VIT was made possible by the significant +contributions of the following people: + + * Chad Phillips (Maintainer and Original Author >= 2.x) + * Scott Kostyshak (Maintainer and Contributing Author) + * Steve Rader (Original Author) + * Paul Beckingham (Advisor) + * David J Patrick (Designer) + +The following submitted code or analysis, and deserve special thanks: + + * Bryce Harrington + * Nemo Inis + * Devendra Ghate + * Ankur Sinha + * Benjamin Weber + * Jochen Sprickerhof + * Peter Novak + * Terran Air + * Rowan Thorpe + * Richard Gay + * Bas Zoetekouw + * Dhananjay Balan + +Thanks to the following, who submitted detailed bug reports and excellent +suggestions: + + * Ben Boeckel + * Michael Ahern + * Peter Lewis + * Jean-Philippe Rutault + * Jason Woofenden + * Benedikt Morbach + * Alick Zhao + * Bernhard M. Wiedemann + * Thomas Rebele diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/vit-2.1.0/CUSTOMIZE.md new/vit-2.2.0/CUSTOMIZE.md --- old/vit-2.1.0/CUSTOMIZE.md 2020-12-24 04:52:45.000000000 +0100 +++ new/vit-2.2.0/CUSTOMIZE.md 2021-11-04 14:51:45.000000000 +0100 @@ -2,11 +2,17 @@ ### Configuration +#### VIT's configuration + VIT provides a user directory that allows for configuring basic settings *(via ```config.ini```)*, as well as custom themes, formatters, and keybindings. -By default, the directory is located at ```~/.vit``` +VIT searches for the user directory in this order of priority: + +1. The ```VIT_DIR``` environment variable +2. ```~/.vit``` (the default location) +3. A ```vit``` directory in any valid [XDG base directory](https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html) -To customize the location of the user directory, you can set the ```VIT_DIR``` environment variable. +#### Taskwarrior configuration By default, VIT uses the default location of the Taskwarrior configuration file to read configuration from Taskwarrior. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/vit-2.1.0/PKG-INFO new/vit-2.2.0/PKG-INFO --- old/vit-2.1.0/PKG-INFO 2021-02-28 22:12:36.000000000 +0100 +++ new/vit-2.2.0/PKG-INFO 2022-04-18 01:07:49.000000000 +0200 @@ -1,78 +1,11 @@ Metadata-Version: 2.1 Name: vit -Version: 2.1.0 +Version: 2.2.0 Summary: Visual Interactive Taskwarrior full-screen terminal interface Home-page: https://github.com/vit-project/vit Author: Chad Phillips Author-email: [email protected] License: UNKNOWN -Description: # VIT - - <img src="images/great-tit-square-small.png" alt="Logo" width="150" height="150" align="right" /> - - Visual Interactive Taskwarrior full-screen terminal interface. - - *For VIT 1.3, [visit here](https://github.com/vit-project/vit/tree/1.3)* - - - ## Features - - * Fully-customizable key bindings *(default Vim-like)* - * Uncluttered display - * No mouse - * Speed - * Per-column colorization - * Advanced tab completion - * Multiple/customizable themes - * Override/customize column formatters - * Intelligent sub-project indenting - - ## Requirements - - * [Taskwarrior](https://taskwarrior.org) - * [Python](https://www.python.org) 3.5+ - * [pip](https://pypi.org/project/pip) - - ## Installation - - Follow the directions in [INSTALL.md](INSTALL.md) - - ## Quick start - - Run ```vit --help``` from the command line for basic usage instructions. - - Run ```vit``` from the command line to start VIT with default config, report, and filters. - - While VIT is running, type ```:help``` followed by enter to review basic command/navigation actions. - - #### Recommendations: - - * VIT will suggest to install a default user config file if none exists -- it's fully commented with all configuration options, check it out. - * Do ```vit --help``` *(know the vit command line arguments)* - * Do ```:help``` in vit *(look over the "commands")* - * Use an xterm terminal *(for full color support)* - * For suggestions on further tweaks, see [CUSTOMIZE.md](CUSTOMIZE.md) - * VIT handles task coloring differently than Taskwarrior, see [COLOR.md](COLOR.md) for more details - - #### Troubleshooting: - - See [FAQ.md](FAQ.md) - - #### Upgrading - - Follow the directions in [UPGRADE.md](UPGRADE.md) - - #### Development: - - Interested in the architecture, or in helping out with development? See [DEVELOPMENT.md](DEVELOPMENT.md) - - ##### In tribute - - Our friend and collaborator Steve Rader passed away in May 2013. We owe a lot to Steve for his excellent work, and so vit is preserved, maintained and continued. - - Taskwarrior Team - [email protected] - Keywords: taskwarrior,console,tui,text-user-interface Platform: UNKNOWN Classifier: Development Status :: 5 - Production/Stable @@ -81,5 +14,76 @@ Classifier: Programming Language :: Python Classifier: Natural Language :: English Classifier: Topic :: Text Processing :: General -Requires-Python: >=3.5 +Requires-Python: >=3.7 Description-Content-Type: text/markdown +License-File: LICENSE +License-File: AUTHORS.md + +# VIT + +<img src="images/great-tit-square-small.png" alt="Logo" width="150" height="150" align="right" /> + +Visual Interactive Taskwarrior full-screen terminal interface. + +*For VIT 1.3, [visit here](https://github.com/vit-project/vit/tree/1.3)* + + +## Features + + * Fully-customizable key bindings *(default Vim-like)* + * Uncluttered display + * No mouse + * Speed + * Per-column colorization + * Advanced tab completion + * Multiple/customizable themes + * Override/customize column formatters + * Intelligent sub-project indenting + +## Requirements + + * [Taskwarrior](https://taskwarrior.org) + * [Python](https://www.python.org) 3.5+ + * [pip](https://pypi.org/project/pip) + +## Installation + +Follow the directions in [INSTALL.md](https://github.com/vit-project/vit/blob/2.x/INSTALL.md) + +## Quick start + +Run ```vit --help``` from the command line for basic usage instructions. + +Run ```vit``` from the command line to start VIT with default config, report, and filters. + +While VIT is running, type ```:help``` followed by enter to review basic command/navigation actions. + +#### Recommendations: + + * VIT will suggest to install a default user config file if none exists -- it's fully commented with all configuration options, check it out. + * Do ```vit --help``` *(know the vit command line arguments)* + * Do ```:help``` in vit *(look over the "commands")* + * Use an xterm terminal *(for full color support)* + * For suggestions on further tweaks, see [CUSTOMIZE.md](https://github.com/vit-project/vit/blob/2.x/CUSTOMIZE.md) + * VIT handles task coloring differently than Taskwarrior, see [COLOR.md](https://github.com/vit-project/vit/blob/2.x/COLOR.md) for more details + +#### Troubleshooting: + +See [FAQ.md](https://github.com/vit-project/vit/blob/2.x/FAQ.md) + +#### Upgrading + +Follow the directions in [UPGRADE.md](https://github.com/vit-project/vit/blob/2.x/UPGRADE.md) + +#### Development: + +Interested in the architecture, or in helping out with development? See [DEVELOPMENT.md](https://github.com/vit-project/vit/blob/2.x/DEVELOPMENT.md) + +##### In tribute + + Our friend and collaborator Steve Rader passed away in May 2013. We owe a lot to Steve for his excellent work, and so vit is preserved, maintained and continued. + + Taskwarrior Team + [email protected] + + diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/vit-2.1.0/requirements.txt new/vit-2.2.0/requirements.txt --- old/vit-2.1.0/requirements.txt 2020-12-24 04:52:45.000000000 +0100 +++ new/vit-2.2.0/requirements.txt 2022-04-18 00:57:32.000000000 +0200 @@ -1,4 +1,3 @@ -pytz>=2019.3 -tasklib>=1.3.0 -tzlocal>=2.0.0 -urwid>=2.1.0 +tasklib>=2.4.3 +urwid>=2.1.2 +backports.zoneinfo;python_version<"3.9" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/vit-2.1.0/setup.py new/vit-2.2.0/setup.py --- old/vit-2.1.0/setup.py 2020-12-24 04:52:45.000000000 +0100 +++ new/vit-2.2.0/setup.py 2022-04-18 00:54:13.000000000 +0200 @@ -2,10 +2,16 @@ from setuptools import setup from os import path +DEFAULT_BRANCH = "2.x" +BASE_GITHUB_URL = "https://github.com/vit-project/vit/blob" + +MARKUP_LINK_REGEX = "\[([^]]+)\]\(([\w]+\.md)\)" FILE_DIR = path.dirname(path.abspath(path.realpath(__file__))) with open(path.join(FILE_DIR, 'README.md')) as f: - README = f.read() + readme_contents = f.read() + markup_link_substitution = '[\\1](%s/%s/\\2)' % (BASE_GITHUB_URL, DEFAULT_BRANCH) + README = re.sub(MARKUP_LINK_REGEX, markup_link_substitution, readme_contents, flags=re.MULTILINE) with open(path.join(FILE_DIR, 'requirements.txt')) as f: INSTALL_PACKAGES = f.read().splitlines() @@ -46,6 +52,6 @@ ], }, include_package_data=True, - python_requires='>=3.5', + python_requires='>=3.7', zip_safe=False ) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/vit-2.1.0/test/test_list_batcher.py new/vit-2.2.0/test/test_list_batcher.py --- old/vit-2.1.0/test/test_list_batcher.py 2020-12-24 04:52:45.000000000 +0100 +++ new/vit-2.2.0/test/test_list_batcher.py 2021-11-04 14:51:45.000000000 +0100 @@ -12,67 +12,67 @@ class TestListBatcher(unittest.TestCase): def test_batch_default_batch(self): - batcher, batch_to = default_batcher() - complete = batcher.add() - self.assertEqual(complete, True) - self.assertEqual(batcher.get_last_position(), len(DEFAULT_BATCH_FROM)) - self.assertEqual(batch_to, DEFAULT_BATCH_FROM) + batcher, batch_to = default_batcher() + complete = batcher.add() + self.assertEqual(complete, True) + self.assertEqual(batcher.get_last_position(), len(DEFAULT_BATCH_FROM)) + self.assertEqual(batch_to, DEFAULT_BATCH_FROM) def test_batch_1(self): - batcher, batch_to = default_batcher() - complete = batcher.add(1) - self.assertEqual(complete, False) - self.assertEqual(batcher.get_last_position(), 1) - self.assertEqual(batch_to, ['a']) + batcher, batch_to = default_batcher() + complete = batcher.add(1) + self.assertEqual(complete, False) + self.assertEqual(batcher.get_last_position(), 1) + self.assertEqual(batch_to, ['a']) def test_batch_5(self): - batcher, batch_to = default_batcher() - complete = batcher.add(5) - self.assertEqual(complete, False) - self.assertEqual(batcher.get_last_position(), 5) - self.assertEqual(batch_to, ['a', 'b', 'c', 'd', 'e']) + batcher, batch_to = default_batcher() + complete = batcher.add(5) + self.assertEqual(complete, False) + self.assertEqual(batcher.get_last_position(), 5) + self.assertEqual(batch_to, ['a', 'b', 'c', 'd', 'e']) def test_batch_1_and_1(self): - batcher, batch_to = default_batcher() - batcher.add(1) - complete = batcher.add(1) - self.assertEqual(complete, False) - self.assertEqual(batcher.get_last_position(), 2) - self.assertEqual(batch_to, ['a', 'b']) + batcher, batch_to = default_batcher() + batcher.add(1) + complete = batcher.add(1) + self.assertEqual(complete, False) + self.assertEqual(batcher.get_last_position(), 2) + self.assertEqual(batch_to, ['a', 'b']) def test_batch_1_and_rest(self): - batcher, batch_to = default_batcher() - batcher.add(1) - complete = batcher.add(0) - self.assertEqual(complete, True) - self.assertEqual(batcher.get_last_position(), len(DEFAULT_BATCH_FROM)) - self.assertEqual(batch_to, DEFAULT_BATCH_FROM) + batcher, batch_to = default_batcher() + batcher.add(1) + complete = batcher.add(0) + self.assertEqual(complete, True) + self.assertEqual(batcher.get_last_position(), len(DEFAULT_BATCH_FROM)) + self.assertEqual(batch_to, DEFAULT_BATCH_FROM) def test_batch_batch_size_greater_than_default(self): - batcher, batch_to = default_batcher() - complete = batcher.add(100000) - self.assertEqual(complete, True) - self.assertEqual(batcher.get_last_position(), len(DEFAULT_BATCH_FROM)) - self.assertEqual(batch_to, DEFAULT_BATCH_FROM) + batcher, batch_to = default_batcher() + complete = batcher.add(100000) + self.assertEqual(complete, True) + self.assertEqual(batcher.get_last_position(), len(DEFAULT_BATCH_FROM)) + self.assertEqual(batch_to, DEFAULT_BATCH_FROM) def test_batch_add_on_completed(self): - batcher, batch_to = default_batcher() - complete = batcher.add() - self.assertEqual(complete, True) - complete = batcher.add() - self.assertEqual(complete, True) - self.assertEqual(batcher.get_last_position(), len(DEFAULT_BATCH_FROM)) - self.assertEqual(batch_to, DEFAULT_BATCH_FROM) + batcher, batch_to = default_batcher() + complete = batcher.add() + self.assertEqual(complete, True) + complete = batcher.add() + self.assertEqual(complete, True) + self.assertEqual(batcher.get_last_position(), len(DEFAULT_BATCH_FROM)) + self.assertEqual(batch_to, DEFAULT_BATCH_FROM) def test_batch_5_with_formatter(self): - def formatter(partial, start_idx): - return ['before'] + [row * 2 for row in partial] + ['after'] - batch_to = [] - batcher = ListBatcher(DEFAULT_BATCH_FROM, batch_to, batch_to_formatter=formatter) - complete = batcher.add(5) - self.assertEqual(complete, False) - self.assertEqual(batcher.get_last_position(), 5) - self.assertEqual(batch_to, ['before', 'aa', 'bb', 'cc', 'dd', 'ee', 'after']) + def formatter(partial, start_idx): + return ['before'] + [row * 2 for row in partial] + ['after'] + batch_to = [] + batcher = ListBatcher(DEFAULT_BATCH_FROM, batch_to, batch_to_formatter=formatter) + complete = batcher.add(5) + self.assertEqual(complete, False) + self.assertEqual(batcher.get_last_position(), 5) + self.assertEqual(batch_to, ['before', 'aa', 'bb', 'cc', 'dd', 'ee', 'after']) if __name__ == '__main__': unittest.main() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/vit-2.1.0/vit/application.py new/vit-2.2.0/vit/application.py --- old/vit-2.1.0/vit/application.py 2020-12-28 18:26:46.000000000 +0100 +++ new/vit-2.2.0/vit/application.py 2021-11-22 15:12:28.000000000 +0100 @@ -19,7 +19,7 @@ from vit import event from vit.loader import Loader from vit.config_parser import ConfigParser, TaskParser -from vit.util import clear_screen, string_to_args, is_mouse_event +from vit.util import clear_screen, string_to_args, is_mouse_event, task_id_or_uuid_short from vit.process import Command from vit.task import TaskListModel from vit.autocomplete import AutoComplete @@ -53,9 +53,12 @@ self.action_manager_registrar = self.action_manager.get_registrar() self.action_manager_registrar.register('REFRESH', self.refresh) + def is_default_refresh_key(self, keys): + return keys == 'ctrl l' + def keypress(self, size, key): keys = self.key_cache.get(key) - if self.action_manager_registrar.handled_action(keys): + if self.action_manager_registrar.handled_action(keys) and self.is_default_refresh_key(keys): # NOTE: Calling refresh directly here to avoid the # action-manager:action-executed event, which clobbers the load # time currently. @@ -146,6 +149,10 @@ self.action_manager_registrar = self.action_manager.get_registrar() self.action_manager_registrar.register('QUIT', self.quit) self.action_manager_registrar.register('QUIT_WITH_CONFIRM', self.activate_command_bar_quit_with_confirm) + # NOTE: This is a no-op for the default refresh keybinding, which is + # handled by the MainFrame() class. It's included here in case the user + # assigns a non-default key to the REFRESH action. + self.action_manager_registrar.register('REFRESH', self.refresh) self.action_manager_registrar.register('TASK_ADD', self.activate_command_bar_add) self.action_manager_registrar.register('REPORT_FILTER', self.activate_command_bar_filter) self.action_manager_registrar.register('TASK_UNDO', self.task_undo) @@ -354,7 +361,9 @@ elif len(args) > 0: if op == 'add': if self.execute_command(['task', 'add'] + args, wait=self.wait): - self.activate_message_bar('Task added') + task = self.task_get_latest() + self.activate_message_bar('Task %s added' % task_id_or_uuid_short(task)) + self.focus_new_task(task) elif op == 'modify': # TODO: Will this break if user clicks another list item # before hitting enter? @@ -380,6 +389,10 @@ if 'uuid' in metadata: self.task_list.focus_by_task_uuid(metadata['uuid'], self.previous_focus_position) + def focus_new_task(self, task): + if self.config.get('vit', 'focus_on_add'): + self.task_list.focus_by_task_uuid(task['uuid'], self.previous_focus_position) + def key_pressed(self, key): if is_mouse_event(key): return None @@ -438,6 +451,12 @@ kwargs['wait'] = False else: kwargs['wait'] = True + uuid, _ = self.get_focused_task() + if not uuid: + uuid = "" + kwargs['custom_env'] = { + "VIT_TASK_UUID": uuid, + } self.execute_command(args, **kwargs) elif command.isdigit(): self.task_list.focus_by_task_id(int(command)) @@ -485,7 +504,8 @@ self.task_list.focus_position = new_focus def search_rows(self, term, start_index=0, reverse=False): - search_regex = re.compile(term, re.MULTILINE) + escaped_term = re.escape(term) + search_regex = re.compile(escaped_term, re.MULTILINE) rows = self.table.rows current_index = start_index last_index = len(rows) - 1 @@ -536,13 +556,12 @@ return False def get_focused_task(self): - if self.widget.focus_position == 'body': - try: - uuid = self.task_list.focus.uuid - task = self.model.get_task(uuid) - return uuid, task - except: - pass + try: + uuid = self.task_list.focus.uuid + task = self.model.get_task(uuid) + return uuid, task + except: + pass return False, False def quit(self): @@ -637,8 +656,6 @@ self.command_bar.activate(caption, metadata, edit_text) self.widget.focus_position = 'footer' - def activate_command_bar_add(self): - self.activate_command_bar('add', 'Add: ') def activate_command_bar_filter(self): self.activate_command_bar('filter', 'Filter: ') @@ -649,6 +666,13 @@ def task_sync(self): self.execute_command(['task', 'sync']) + def task_get_latest(self): + returncode, stdout, stderr = self.command.run(['task', '+LATEST', 'uuids'], capture_output=True) + if returncode == 0: + return self.model.get_task(stdout) + else: + raise RuntimeError("Error retrieving latest task UUID: %s" % stderr) + def activate_command_bar_quit_with_confirm(self): if self.confirm: self.activate_command_bar('quit', 'Quit?', {'choices': {'y': True}}) @@ -683,6 +707,8 @@ def global_escape(self): self.denotation_pop_up.close_pop_up() + def activate_command_bar_add(self): + self.activate_command_bar('add', 'Add: ') def task_done(self, uuid): success, task = self.model.task_done(uuid) @@ -732,7 +758,7 @@ def task_action_denotate(self): uuid, task = self.get_focused_task() if task and task['annotations']: - self.denotation_pop_up.open(task) + self.denotation_pop_up.open(task) def task_action_modify(self): uuid, _ = self.get_focused_task() @@ -909,7 +935,7 @@ self.task_config.get_projects() self.refresh_blocking_task_uuids() self.formatter.recalculate_due_datetimes() - context_filters = self.contexts[self.context]['filter'] if self.context else [] + context_filters = self.contexts[self.context]['filter'] if self.context and self.reports[self.report].get('context', 1) else [] try: self.model.update_report(self.report, context_filters=context_filters, extra_filters=self.extra_filters) except VitException as err: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/vit-2.1.0/vit/autocomplete.py new/vit-2.2.0/vit/autocomplete.py --- old/vit-2.1.0/vit/autocomplete.py 2020-12-24 04:52:45.000000000 +0100 +++ new/vit-2.2.0/vit/autocomplete.py 2021-11-04 14:51:45.000000000 +0100 @@ -125,6 +125,8 @@ self.teardown() def activate(self, text, edit_pos, reverse=False): + if not self.is_setup: + return if self.activated: self.send_tabbed_text(text, edit_pos, reverse) return @@ -180,7 +182,11 @@ def add_space_escaping(self, text): if self.space_escape_regex.match(text): - return text.replace(' ', '\ ') + parts = text.split(':', 1) + if len(parts) > 1: + return "%s:'%s'" % (parts[0], parts[1]) + else: + return "'%s'" % text else: return text @@ -189,7 +195,7 @@ def parse_text(self, text, edit_pos): full_prefix = text[:edit_pos] - self.prefix_parts = list(map(self.add_space_escaping, util.string_to_args(full_prefix))) + self.prefix_parts = list(map(self.add_space_escaping, util.string_to_args_on_whitespace(full_prefix))) if not self.prefix_parts: self.search_fragment = self.prefix = full_prefix self.suffix = text[(edit_pos + 1):] diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/vit-2.1.0/vit/config/config.sample.ini new/vit-2.2.0/vit/config/config.sample.ini --- old/vit-2.1.0/vit/config/config.sample.ini 2020-12-30 20:32:42.000000000 +0100 +++ new/vit-2.2.0/vit/config/config.sample.ini 2021-11-04 14:51:57.000000000 +0100 @@ -53,6 +53,10 @@ # Boolean. If true, hitting backspace against an empty prompt aborts the prompt. #abort_backspace = False +# Boolean. If true, VIT will focus on the newly added task. Note: the new task must be +#included in the active filter for this setting to have effect. +#focus_on_add = False + [report] # The default Taskwarrior report to load when VIT first starts, if no report diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/vit-2.1.0/vit/config_parser.py new/vit-2.2.0/vit/config_parser.py --- old/vit-2.1.0/vit/config_parser.py 2020-12-28 18:26:46.000000000 +0100 +++ new/vit-2.2.0/vit/config_parser.py 2022-03-06 02:27:52.000000000 +0100 @@ -12,7 +12,7 @@ except ImportError: import ConfigParser as configparser -from vit import env +from vit import env, xdg from vit.process import Command SORT_ORDER_CHARACTERS = ['+', '-'] @@ -45,6 +45,7 @@ 'wait': True, 'mouse': False, 'abort_backspace': False, + 'focus_on_add': False, }, 'report': { 'default_report': 'next', @@ -97,14 +98,14 @@ def __init__(self, loader): self.loader = loader self.config = configparser.SafeConfigParser() - self.config.optionxform=str + self.config.optionxform = str self.user_config_dir = self.loader.user_config_dir self.user_config_filepath = '%s/%s' % (self.user_config_dir, VIT_CONFIG_FILE) if not self.config_file_exists(self.user_config_filepath): self.optional_create_config_file(self.user_config_filepath) + self.config.read(self.user_config_filepath) self.taskrc_path = self.get_taskrc_path() self.validate_taskrc() - self.config.read(self.user_config_filepath) self.defaults = DEFAULTS self.set_config_data() @@ -186,7 +187,14 @@ return True if CONFIG_BOOLEAN_TRUE_REGEX.match(value) else False def get_taskrc_path(self): - return os.path.expanduser('TASKRC' in env.user and env.user['TASKRC'] or self.get('taskwarrior', 'taskrc')) + taskrc_path = os.path.expanduser('TASKRC' in env.user and env.user['TASKRC'] or self.get('taskwarrior', 'taskrc')) + + if not os.path.exists(taskrc_path): + xdg_dir = xdg.get_xdg_config_dir(taskrc_path, "task") + if xdg_dir: + taskrc_path = os.path.join(xdg_dir, "taskrc") + + return taskrc_path def is_subproject_indentable(self): return self.get('report', 'indent_subprojects') @@ -265,38 +273,38 @@ return list(filter(lambda config_pair: re.match(matcher_regex, config_pair[0]), self.task_config)) def subtree(self, matcher, walk_subtree=True): - matcher_regex = matcher - if walk_subtree: - matcher_regex = r'%s' % (('^%s' % matcher).replace('.', '\.')) - full_tree = {} - lines = self.filter(matcher_regex) - for (hierarchy, value) in lines: - # NOTE: This is necessary in order to convert Taskwarrior's dotted - # config syntax into a full tree, as some leaves are both branches - # and leaves. - hierarchy = self.transform_string_leaves(hierarchy) - parts = hierarchy.split('.') - tree_location = full_tree - while True: - if len(parts): - part = parts.pop(0) - if part not in tree_location: - tree_location[part] = {} if len(parts) else value - tree_location = tree_location[part] - else: - break - if walk_subtree: - parts = matcher.split('.') - subtree = full_tree - while True: - if len(parts): - part = parts.pop(0) - if part in subtree: - subtree = subtree[part] - else: - return subtree - else: - return full_tree + matcher_regex = matcher + if walk_subtree: + matcher_regex = r'%s' % (('^%s' % matcher).replace('.', '\.')) + full_tree = {} + lines = self.filter(matcher_regex) + for (hierarchy, value) in lines: + # NOTE: This is necessary in order to convert Taskwarrior's dotted + # config syntax into a full tree, as some leaves are both branches + # and leaves. + hierarchy = self.transform_string_leaves(hierarchy) + parts = hierarchy.split('.') + tree_location = full_tree + while True: + if len(parts): + part = parts.pop(0) + if part not in tree_location: + tree_location[part] = {} if len(parts) else value + tree_location = tree_location[part] + else: + break + if walk_subtree: + parts = matcher.split('.') + subtree = full_tree + while True: + if len(parts): + part = parts.pop(0) + if part in subtree: + subtree = subtree[part] + else: + return subtree + else: + return full_tree def parse_sort_column(self, column_string): order = collate = None @@ -324,47 +332,61 @@ self.get_task_config() subtree = self.subtree('context.') for context, filters in list(subtree.items()): - filters = shlex.split(re.sub(FILTER_PARENS_REGEX, r' \1 ', filters)) contexts[context] = { - 'filter': [f for f in filters if not FILTER_EXCLUSION_REGEX.match(f)], + 'filter': self.parse_context_filters(context, filters), } self.contexts = contexts return self.contexts + def parse_context_filters(self, context, filters): + # Filters can be a string (pre-2.6.0 definition, context.work=+work) + # or a dict (2.6.0 and newer, context.work.read=+work and + # context.work.write=+work). + if type(filters) is dict: + if 'read' in filters: + filters = filters['read'] + else: + return [] # Only contexts with read component defined should be considered. + filters = shlex.split(re.sub(FILTER_PARENS_REGEX, r' \1 ', filters)) + final_filters = [f for f in filters if not FILTER_EXCLUSION_REGEX.match(f)] + return final_filters + def get_reports(self): - reports = {} - subtree = self.subtree('report.') - for report, attrs in list(subtree.items()): - if report in self.disallowed_reports: - continue - reports[report] = { - 'name': report, - 'subproject_indentable': False, - } - if 'columns' in attrs: - reports[report]['columns'] = attrs['columns'].split(',') - if 'description' in attrs: - reports[report]['description'] = attrs['description'] - if 'filter' in attrs: - # Allows quoted strings. - # Adjust for missing spaces around parentheses. - filters = shlex.split(re.sub(FILTER_PARENS_REGEX, r' \1 ', attrs['filter'])) - reports[report]['filter'] = [f for f in filters if not FILTER_EXCLUSION_REGEX.match(f)] - if 'labels' in attrs: - reports[report]['labels'] = attrs['labels'].split(',') - else: - reports[report]['labels'] = [ column.title() for column in attrs['columns'].split(',') ] - if 'sort' in attrs: - columns = attrs['sort'].split(',') - reports[report]['sort'] = [self.parse_sort_column(c) for c in columns] - if 'dateformat' in attrs: - reports[report]['dateformat'] = self.translate_date_markers(attrs['dateformat']) - - self.reports = reports - # Another pass is needed after all report data has been parsed. - for report_name, report in self.reports.items(): - self.reports[report_name] = self.rectify_report(report_name, report) - return self.reports + reports = {} + subtree = self.subtree('report.') + for report, attrs in list(subtree.items()): + if report in self.disallowed_reports: + continue + reports[report] = { + 'name': report, + 'subproject_indentable': False, + } + if 'columns' in attrs: + reports[report]['columns'] = attrs['columns'].split(',') + if 'context' in attrs: + reports[report]['context'] = int(attrs['context']) + if 'description' in attrs: + reports[report]['description'] = attrs['description'] + if 'filter' in attrs: + # Allows quoted strings. + # Adjust for missing spaces around parentheses. + filters = shlex.split(re.sub(FILTER_PARENS_REGEX, r' \1 ', attrs['filter'])) + reports[report]['filter'] = [f for f in filters if not FILTER_EXCLUSION_REGEX.match(f)] + if 'labels' in attrs: + reports[report]['labels'] = attrs['labels'].split(',') + else: + reports[report]['labels'] = [column.title() for column in attrs['columns'].split(',')] + if 'sort' in attrs: + columns = attrs['sort'].split(',') + reports[report]['sort'] = [self.parse_sort_column(c) for c in columns] + if 'dateformat' in attrs: + reports[report]['dateformat'] = self.translate_date_markers(attrs['dateformat']) + + self.reports = reports + # Another pass is needed after all report data has been parsed. + for report_name, report in self.reports.items(): + self.reports[report_name] = self.rectify_report(report_name, report) + return self.reports def rectify_report(self, report_name, report): report['subproject_indentable'] = self.has_project_column(report_name) and self.has_primary_project_ascending_sort(report) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/vit-2.1.0/vit/formatter/__init__.py new/vit-2.2.0/vit/formatter/__init__.py --- old/vit-2.1.0/vit/formatter/__init__.py 2021-02-02 04:25:28.000000000 +0100 +++ new/vit-2.2.0/vit/formatter/__init__.py 2022-03-23 00:27:36.000000000 +0100 @@ -1,6 +1,9 @@ import math from datetime import datetime -from pytz import timezone +try: + from zoneinfo import ZoneInfo +except ImportError: + from backports.zoneinfo import ZoneInfo TIME_UNIT_MAP = { 'seconds': { @@ -150,14 +153,14 @@ def age(self, dt): if dt == None: return '' - now = datetime.now(self.formatter.zone) + now = datetime.now().astimezone() seconds = (now - dt).total_seconds() return self.format_duration_vague(seconds) def countdown(self, dt): if dt == None: return '' - now = datetime.now(self.formatter.zone) + now = datetime.now().astimezone() if dt < now: return '' seconds = (dt - now).total_seconds() @@ -166,14 +169,14 @@ def relative(self, dt): if dt == None: return '' - now = datetime.now(self.formatter.zone) + now = datetime.now().astimezone() seconds = (dt - now).total_seconds() return self.format_duration_vague(seconds) def remaining(self, dt): if dt == None: return '' - now = datetime.now(self.formatter.zone) + now = datetime.now().astimezone() if dt < now: return '' seconds = (dt - now).total_seconds() @@ -198,7 +201,7 @@ def iso(self, dt): if dt == None: return '' - dt = dt.replace(tzinfo=timezone('UTC')) + dt = dt.replace(tzinfo=ZoneInfo('UTC')) return dt.isoformat() class List(Formatter): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/vit-2.1.0/vit/formatter/markers.py new/vit-2.2.0/vit/formatter/markers.py --- old/vit-2.1.0/vit/formatter/markers.py 2021-02-02 04:42:09.000000000 +0100 +++ new/vit-2.2.0/vit/formatter/markers.py 2021-10-19 15:36:03.000000000 +0200 @@ -1,3 +1,4 @@ +import unicodedata from vit.formatter import Marker class Markers(Marker): @@ -35,7 +36,7 @@ def add_label(self, color, label, width, text_markup): if self.color_required(color) or not label: return width, text_markup - width += len(label) + width += len(label) + len([c for c in label if unicodedata.east_asian_width(c) == 'W']) text_markup += [(color, label)] return width, text_markup diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/vit-2.1.0/vit/formatter_base.py new/vit-2.2.0/vit/formatter_base.py --- old/vit-2.1.0/vit/formatter_base.py 2020-12-24 04:52:45.000000000 +0100 +++ new/vit-2.2.0/vit/formatter_base.py 2022-03-23 00:27:36.000000000 +0100 @@ -1,7 +1,9 @@ from importlib import import_module from datetime import datetime, timedelta -from tzlocal import get_localzone -from pytz import timezone +try: + from zoneinfo import ZoneInfo +except ImportError: + from backports.zoneinfo import ZoneInfo from vit import util from vit import uda @@ -27,8 +29,7 @@ self.report = self.task_config.translate_date_markers(self.task_config.subtree('dateformat.report')) or self.date_default self.annotation = self.task_config.translate_date_markers(self.task_config.subtree('dateformat.annotation')) or self.date_default self.description_truncate_len = DEFAULT_DESCRIPTION_TRUNCATE_LEN - self.zone = get_localzone() - self.epoch_datetime = datetime(1970, 1, 1, tzinfo=timezone('UTC')) + self.epoch_datetime = datetime(1970, 1, 1, tzinfo=ZoneInfo('UTC')) self.due_days = int(self.task_config.subtree('due')) self.none_label = config.get('color', 'none_label') self.build_indicators() @@ -97,7 +98,7 @@ return (width, ' ' * space_padding , indicator, subproject) def recalculate_due_datetimes(self): - self.now = datetime.now(self.zone) + self.now = datetime.now().astimezone() # NOTE: For some reason using self.zone for the tzinfo below results # in the tzinfo object having a zone of 'LMT', which is wrong. Using # the tzinfo associated with self.now returns the correct value, no diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/vit-2.1.0/vit/loader.py new/vit-2.2.0/vit/loader.py --- old/vit-2.1.0/vit/loader.py 2020-12-24 04:52:45.000000000 +0100 +++ new/vit-2.2.0/vit/loader.py 2021-11-04 14:51:45.000000000 +0100 @@ -4,7 +4,7 @@ except: import imp -from vit import env +from vit import env, xdg DEFAULT_VIT_DIR = '~/.vit' @@ -12,6 +12,11 @@ def __init__(self): self.user_config_dir = os.path.expanduser('VIT_DIR' in env.user and env.user['VIT_DIR'] or DEFAULT_VIT_DIR) + if not os.path.exists(self.user_config_dir): + xdg_dir = xdg.get_xdg_config_dir(self.user_config_dir, "vit") + if xdg_dir: + self.user_config_dir = xdg_dir + def load_user_class(self, module_type, module_name, class_name): module = '%s.%s' % (module_type, module_name) filepath = '%s/%s/%s.py' % (self.user_config_dir, module_type, module_name) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/vit-2.1.0/vit/process.py new/vit-2.2.0/vit/process.py --- old/vit-2.1.0/vit/process.py 2020-12-24 04:52:45.000000000 +0100 +++ new/vit-2.2.0/vit/process.py 2021-11-04 14:51:45.000000000 +0100 @@ -1,6 +1,7 @@ import os import re import subprocess +import copy from vit import env from vit.util import clear_screen, string_to_args @@ -14,11 +15,13 @@ self.env = env.user.copy() self.env['TASKRC'] = self.config.taskrc_path - def run(self, command, capture_output=False): + def run(self, command, capture_output=False, custom_env={}): if isinstance(command, str): command = string_to_args(command) + env = copy.copy(self.env) + env.update(custom_env) kwargs = { - 'env': self.env, + 'env': env, } if capture_output: kwargs.update({ @@ -36,10 +39,10 @@ returncode = 1 return returncode, stdout, self.filter_errors(returncode, stderr) - def result(self, command, confirm=DEFAULT_CONFIRM, capture_output=False, print_output=False, clear=True): + def result(self, command, confirm=DEFAULT_CONFIRM, capture_output=False, print_output=False, clear=True, custom_env={}): if clear: clear_screen() - returncode, stdout, stderr = self.run(command, capture_output) + returncode, stdout, stderr = self.run(command, capture_output, custom_env) output = returncode == 0 and stdout or stderr if print_output: print(output) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/vit-2.1.0/vit/readline.py new/vit-2.2.0/vit/readline.py --- old/vit-2.1.0/vit/readline.py 2020-12-24 04:52:45.000000000 +0100 +++ new/vit-2.2.0/vit/readline.py 2021-11-04 14:51:45.000000000 +0100 @@ -73,10 +73,10 @@ edit_text = self.edit_obj.get_edit_text() self.edit_obj.set_edit_text( - edit_text[: new_edit_pos - 2] + - edit_text[new_edit_pos - 1] + - edit_text[new_edit_pos - 2] + - edit_text[new_edit_pos :]) + edit_text[: new_edit_pos - 2] + + edit_text[new_edit_pos - 1] + + edit_text[new_edit_pos - 2] + + edit_text[new_edit_pos :]) self.edit_obj.set_edit_pos(new_edit_pos) return None # Delete backwards to the beginning of the line. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/vit-2.1.0/vit/util.py new/vit-2.2.0/vit/util.py --- old/vit-2.1.0/vit/util.py 2020-12-24 04:52:45.000000000 +0100 +++ new/vit-2.2.0/vit/util.py 2021-11-04 14:51:45.000000000 +0100 @@ -13,9 +13,17 @@ def string_to_args(string): try: - return shlex.split(string) + return shlex.split(string) except ValueError: - return [] + return [] + +def string_to_args_on_whitespace(string): + try: + lex = shlex.shlex(string) + lex.whitespace_split = True + return list(lex) + except ValueError: + return [] def is_mouse_event(key): return not isinstance(key, str) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/vit-2.1.0/vit/version.py new/vit-2.2.0/vit/version.py --- old/vit-2.1.0/vit/version.py 2021-02-28 20:20:14.000000000 +0100 +++ new/vit-2.2.0/vit/version.py 2022-04-18 00:51:26.000000000 +0200 @@ -1 +1 @@ -VIT = '2.1.0' +VIT = '2.2.0' diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/vit-2.1.0/vit/xdg.py new/vit-2.2.0/vit/xdg.py --- old/vit-2.1.0/vit/xdg.py 1970-01-01 01:00:00.000000000 +0100 +++ new/vit-2.2.0/vit/xdg.py 2021-11-04 14:51:45.000000000 +0100 @@ -0,0 +1,19 @@ +import os + +from vit import env + + +def get_xdg_config_dir(user_config_dir, resource): + xdg_config_home = env.user.get("XDG_CONFIG_HOME") or os.path.join( + os.path.expanduser("~"), ".config" + ) + + xdg_config_dirs = [xdg_config_home] + ( + env.user.get("XDG_CONFIG_DIRS") or "/etc/xdg" + ).split(":") + + for config_dir in xdg_config_dirs: + path = os.path.join(config_dir, resource) + if os.path.exists(path): + return path + return None diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/vit-2.1.0/vit.egg-info/PKG-INFO new/vit-2.2.0/vit.egg-info/PKG-INFO --- old/vit-2.1.0/vit.egg-info/PKG-INFO 2021-02-28 22:12:36.000000000 +0100 +++ new/vit-2.2.0/vit.egg-info/PKG-INFO 2022-04-18 01:07:49.000000000 +0200 @@ -1,78 +1,11 @@ Metadata-Version: 2.1 Name: vit -Version: 2.1.0 +Version: 2.2.0 Summary: Visual Interactive Taskwarrior full-screen terminal interface Home-page: https://github.com/vit-project/vit Author: Chad Phillips Author-email: [email protected] License: UNKNOWN -Description: # VIT - - <img src="images/great-tit-square-small.png" alt="Logo" width="150" height="150" align="right" /> - - Visual Interactive Taskwarrior full-screen terminal interface. - - *For VIT 1.3, [visit here](https://github.com/vit-project/vit/tree/1.3)* - - - ## Features - - * Fully-customizable key bindings *(default Vim-like)* - * Uncluttered display - * No mouse - * Speed - * Per-column colorization - * Advanced tab completion - * Multiple/customizable themes - * Override/customize column formatters - * Intelligent sub-project indenting - - ## Requirements - - * [Taskwarrior](https://taskwarrior.org) - * [Python](https://www.python.org) 3.5+ - * [pip](https://pypi.org/project/pip) - - ## Installation - - Follow the directions in [INSTALL.md](INSTALL.md) - - ## Quick start - - Run ```vit --help``` from the command line for basic usage instructions. - - Run ```vit``` from the command line to start VIT with default config, report, and filters. - - While VIT is running, type ```:help``` followed by enter to review basic command/navigation actions. - - #### Recommendations: - - * VIT will suggest to install a default user config file if none exists -- it's fully commented with all configuration options, check it out. - * Do ```vit --help``` *(know the vit command line arguments)* - * Do ```:help``` in vit *(look over the "commands")* - * Use an xterm terminal *(for full color support)* - * For suggestions on further tweaks, see [CUSTOMIZE.md](CUSTOMIZE.md) - * VIT handles task coloring differently than Taskwarrior, see [COLOR.md](COLOR.md) for more details - - #### Troubleshooting: - - See [FAQ.md](FAQ.md) - - #### Upgrading - - Follow the directions in [UPGRADE.md](UPGRADE.md) - - #### Development: - - Interested in the architecture, or in helping out with development? See [DEVELOPMENT.md](DEVELOPMENT.md) - - ##### In tribute - - Our friend and collaborator Steve Rader passed away in May 2013. We owe a lot to Steve for his excellent work, and so vit is preserved, maintained and continued. - - Taskwarrior Team - [email protected] - Keywords: taskwarrior,console,tui,text-user-interface Platform: UNKNOWN Classifier: Development Status :: 5 - Production/Stable @@ -81,5 +14,76 @@ Classifier: Programming Language :: Python Classifier: Natural Language :: English Classifier: Topic :: Text Processing :: General -Requires-Python: >=3.5 +Requires-Python: >=3.7 Description-Content-Type: text/markdown +License-File: LICENSE +License-File: AUTHORS.md + +# VIT + +<img src="images/great-tit-square-small.png" alt="Logo" width="150" height="150" align="right" /> + +Visual Interactive Taskwarrior full-screen terminal interface. + +*For VIT 1.3, [visit here](https://github.com/vit-project/vit/tree/1.3)* + + +## Features + + * Fully-customizable key bindings *(default Vim-like)* + * Uncluttered display + * No mouse + * Speed + * Per-column colorization + * Advanced tab completion + * Multiple/customizable themes + * Override/customize column formatters + * Intelligent sub-project indenting + +## Requirements + + * [Taskwarrior](https://taskwarrior.org) + * [Python](https://www.python.org) 3.5+ + * [pip](https://pypi.org/project/pip) + +## Installation + +Follow the directions in [INSTALL.md](https://github.com/vit-project/vit/blob/2.x/INSTALL.md) + +## Quick start + +Run ```vit --help``` from the command line for basic usage instructions. + +Run ```vit``` from the command line to start VIT with default config, report, and filters. + +While VIT is running, type ```:help``` followed by enter to review basic command/navigation actions. + +#### Recommendations: + + * VIT will suggest to install a default user config file if none exists -- it's fully commented with all configuration options, check it out. + * Do ```vit --help``` *(know the vit command line arguments)* + * Do ```:help``` in vit *(look over the "commands")* + * Use an xterm terminal *(for full color support)* + * For suggestions on further tweaks, see [CUSTOMIZE.md](https://github.com/vit-project/vit/blob/2.x/CUSTOMIZE.md) + * VIT handles task coloring differently than Taskwarrior, see [COLOR.md](https://github.com/vit-project/vit/blob/2.x/COLOR.md) for more details + +#### Troubleshooting: + +See [FAQ.md](https://github.com/vit-project/vit/blob/2.x/FAQ.md) + +#### Upgrading + +Follow the directions in [UPGRADE.md](https://github.com/vit-project/vit/blob/2.x/UPGRADE.md) + +#### Development: + +Interested in the architecture, or in helping out with development? See [DEVELOPMENT.md](https://github.com/vit-project/vit/blob/2.x/DEVELOPMENT.md) + +##### In tribute + + Our friend and collaborator Steve Rader passed away in May 2013. We owe a lot to Steve for his excellent work, and so vit is preserved, maintained and continued. + + Taskwarrior Team + [email protected] + + diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/vit-2.1.0/vit.egg-info/SOURCES.txt new/vit-2.2.0/vit.egg-info/SOURCES.txt --- old/vit-2.1.0/vit.egg-info/SOURCES.txt 2021-02-28 22:12:36.000000000 +0100 +++ new/vit-2.2.0/vit.egg-info/SOURCES.txt 2022-04-18 01:07:49.000000000 +0200 @@ -1,3 +1,4 @@ +AUTHORS.md COLOR.md CUSTOMIZE.md DEVELOPMENT.md @@ -44,6 +45,7 @@ vit/uda.py vit/util.py vit/version.py +vit/xdg.py vit.egg-info/PKG-INFO vit.egg-info/SOURCES.txt vit.egg-info/dependency_links.txt diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/vit-2.1.0/vit.egg-info/entry_points.txt new/vit-2.2.0/vit.egg-info/entry_points.txt --- old/vit-2.1.0/vit.egg-info/entry_points.txt 2021-02-28 22:12:36.000000000 +0100 +++ new/vit-2.2.0/vit.egg-info/entry_points.txt 2022-04-18 01:07:49.000000000 +0200 @@ -1,3 +1,2 @@ [console_scripts] vit = vit.command_line:main - diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/vit-2.1.0/vit.egg-info/requires.txt new/vit-2.2.0/vit.egg-info/requires.txt --- old/vit-2.1.0/vit.egg-info/requires.txt 2021-02-28 22:12:36.000000000 +0100 +++ new/vit-2.2.0/vit.egg-info/requires.txt 2022-04-18 01:07:49.000000000 +0200 @@ -1,4 +1,5 @@ -pytz>=2019.3 -tasklib>=1.3.0 -tzlocal>=2.0.0 -urwid>=2.1.0 +tasklib>=2.4.3 +urwid>=2.1.2 + +[:python_version < "3.9"] +backports.zoneinfo
