Commit 33619796 authored by Kirill Smelkov's avatar Kirill Smelkov

X search through implied contexts and projects

A user can setup associations in topydo config file and then search will
take those associations into account. For example with

	[implied]
	# X implies -> A B C ...
	+pygolang   = +work +python +go
	+wcfs       = +work
	@jp         = +work
	@jerome     = +work +zodbtools
	...

I can associate projects and people to "+work" label, and then use that
label to query for work-related todo and todos not related to work:

	$ t +work	# todo itmes related to work
	$ t -+work	# todo items related to not-work

this provides a bit of start for work/life balance without explictly
marking every todo with redundant +work label or using complex queries.
parent 1bc287fa
......@@ -57,6 +57,7 @@ class _Config:
'column_keymap',
'columns',
'dep',
'implied',
'ls',
'sort',
'tags',
......@@ -129,6 +130,9 @@ class _Config:
'listcontexts': 'lscon',
},
'implied': {
},
'columns': {
'column_width': '40',
},
......@@ -420,6 +424,19 @@ class _Config:
return alias_dict
def implied(self):
"""
implied returns {} with key -> [] of implied items
"""
implied = self.cp.items('implied')
implied_dict = {}
for key, implied_line in implied:
impliedv = implied_line.split()
implied_dict[key] = impliedv
return implied_dict
def list_format(self):
""" Returns the list format used by `ls` """
return self.cp.get('ls', 'list_format')
......
......@@ -82,7 +82,7 @@ class GrepFilter(Filter):
def match(self, p_todo):
expr = self.expression
string = p_todo.source()
string = p_todo.xsource()
if not self.case_sensitive:
expr = expr.lower()
string = string.lower()
......
# Implied - implience for Topydo - A todo.txt client written in Python.
# Copyright (C) 2020 Kirill Smelkov <kirr@navytux.spb.ru>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
"""Module Implied provides implied() function that returns associations for
provided items.
For example implied(['+pygolang']) -> ['+work', '+python', '+go']
The associations have to be set up in topydo configuration in [topydo.implied]
section e.g. as follows:
[implied]
# X implies -> A B C ...
+pygolang = +work +python +go
@jp = +work
@jerome = +work +zodbtools
...
"""
from topydo.lib.Config import config
def implied(items): # -> implied_items
db = _db()
I = set(items) # resulting implied set we build; will remove source items in the end
Inext = set(items) # items to scan as roots in the next round
while len(Inext) > 0:
Icur = Inext
Inext = set()
for item in Icur:
for i in db.get(item, []):
if i in I:
continue # we already have this item
# new item - add it to result set and schedule scan from it in
# the next round
I.add(i)
Inext.add(i)
# I now has complete closure of implience starting from items.
# return only what is new.
I = I.difference(items)
L = list(I)
L.sort()
#print('implied %s -> %s' % (items, L))
return L
# _db returns {} with implied words database:
# {} key -> [] of implied items
__db = None
def _db():
global __db
if __db is not None:
return __db
# load the database from config
__db = config().implied()
return __db
......@@ -23,6 +23,7 @@ from datetime import date
from topydo.lib.TodoParser import parse_line
from topydo.lib.Utils import is_valid_priority
from topydo.lib.Implied import implied
class TodoBase(object):
......@@ -40,6 +41,8 @@ class TodoBase(object):
def __init__(self, p_src):
self.src = ""
self.fields = {}
self._xsrc = "" # .src extended with implied contexts and labels
# (ex +pygolang -> +work, @jp -> +work, @удельная -> @город)
self.set_source_text(p_src)
......@@ -174,10 +177,24 @@ class TodoBase(object):
"""
return self.text(True)
def xsource(self):
"""xsource returns extended source of the todo.
That is original todo source appended with contexts and labels implied
from original todo source.
GrepFilter uses xsource to match query not only to original todo
source, but also to contexts and labels implied to the todo item. """
return self._xsrc
def set_source_text(self, p_text):
""" Sets the todo source text. The text will be parsed again. """
self.src = p_text.strip()
self.fields = parse_line(self.src)
xsrc = self.src
xsrc = ' '.join([xsrc] + implied(['+'+_ for _ in self.fields['projects']]))
xsrc = ' '.join([xsrc] + implied(['@'+_ for _ in self.fields['contexts']]))
self._xsrc = xsrc
def projects(self):
""" Returns a set of projects associated with this todo item. """
......
  • /cc @jerome (I wonder if ERP5 has something similar - to search with taking implied contexts into account and to topydo in general)

  • "Searches with implied contexts", maybe in some projects custom implementations. We have "portal_catalog" to search documents, it works by generating SQL, for example

    portal.portal_catalog(title="the title")

    will generate something like:

    SELECT path FROM catalog where title = "the title"

    and then documents are retrieved from zodb by their path. What we can do is write a "scriptable key" for title key, it would be a script which will receive "the title" and will return a query object (which is transformed to a SQL fragment). It can probably be used to achieve similar tricks. Ten years ago there was a project where this was used to "normalize" the searches (various spelling of people first names, for example to make "Jean-Paul" or "Jean Paul" equivalent ). It's different but seems bit similar in the idea.

    There's also ERP5 "path" ( one of the 5 base classes making the 5 of ERP5 - https://www.erp5.com/basic/developer ), where we can define that movements of resources "work" from Kirill to Nexedi are on project Wendelin, the definition of "implications" in this seem to be similar to ERP5 path. But this is more at theorical level.

    topydo, it looks interesting. I'll give it a try (I also wanted to try orgmode). In ERP5 we have the tasks and tasks reports from erp5 project, but it's not really small - productivity optimised tool to quickly record what you are doing and what you have to do, but more something so that everybody in an organisation record the times with different user level security and then make reports of what was planned vs what is the reality. In any case, it's interesting, thanks for letting me know.

  • @jerome, thanks for feedback; it was an interesting read.

    P.S. I'm contemplating whether to use openstreetmaps data or API so that geospatial (in-city) implication could be handled automatically instead of manual setup.

Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment