dotfiles/talon/community/community-cursorless-0.4.0/apps/mac/things3.py
2024-11-16 20:27:38 -07:00

143 lines
4 KiB
Python

from typing import Dict, Optional
import webbrowser
from talon import ctrl, ui, Module, Context, actions, clip, app
from dataclasses import dataclass
from things3.things3 import Things3
from ...code.create_spoken_forms import create_spoken_forms
import io
import csv
ctx = Context()
mod = Module()
apps = mod.apps
apps.things3 = """
app.name: Things
"""
ctx.matches = r"""
app: things3
"""
mod.list("things_tag", desc="Tags in Things")
mod.list("things_tag_with_shortcut", desc="Tags in Things within an assigned shortcut")
mod.list("things_project", desc="Areas and projects in Things")
things = Things3()
@dataclass
class Tag:
uuid: str
title: str
shortcut: Optional[str]
@dataclass
class Project:
uuid: str
title: str
raw_areas = things.get_areas()
raw_projects = things.get_projects()
sql_query = f"""
SELECT TAG.title, TAG.shortcut, TAG.uuid
FROM {things.TABLE_TAG} AS TAG
"""
tags = [Tag(**raw_tag) for raw_tag in things.execute_query(sql_query)]
projects = [
Project(uuid=raw_project["uuid"], title=raw_project["title"])
for raw_project in raw_areas + raw_projects
]
tag_map: Dict[str, Tag] = {tag.uuid: tag for tag in tags}
project_map = {project.uuid: project for project in projects}
ctx.lists["self.things_tag"] = {
spoken_form: tag.uuid
for tag in tags
for spoken_form in create_spoken_forms(tag.title)
}
ctx.lists["self.things_tag_with_shortcut"] = {
spoken_form: tag.uuid
for tag in tags
if tag.shortcut is not None
for spoken_form in create_spoken_forms(tag.title)
}
things_projects = {
spoken_form: project.uuid
for project in projects
for spoken_form in create_spoken_forms(project.title)
}
print(things_projects)
ctx.lists["self.things_project"] = things_projects
@mod.action_class
class Actions:
def tag_todo(things_tags: str):
"""Tag todo with a list of tags"""
tag_list = [tag_map[tag_uuid] for tag_uuid in things_tags.split(",")]
tags_with_shortcuts = [tag for tag in tag_list if tag.shortcut is not None]
tags_without_shortcuts = [tag for tag in tag_list if tag.shortcut is None]
for tag in tags_with_shortcuts:
actions.key(f"ctrl-{tag.shortcut}")
for tag in tags_without_shortcuts:
actions.key(f"cmd-shift-t")
actions.insert(tag.title)
actions.key("enter")
def filter_by_tag(things_tags: str):
"""Tag todo with a list of tags"""
tag_list = [tag_map[tag_uuid] for tag_uuid in things_tags.split(",")]
for tag in tag_list:
if tag.shortcut is None:
raise Exception("Can only filter by tags with assigned shortcuts")
actions.key(f"ctrl-alt-{tag.shortcut}")
def show_tag(things_tag: str):
"""Show a particular tag in things"""
tag = tag_map[things_tag]
webbrowser.open(f"things:///show?id={tag.uuid}")
def show_things_list(things_project: str):
"""Show a list in things"""
project = project_map[things_project]
webbrowser.open(f"things:///show?id={project.uuid}")
def move_todo(project: str):
"""Move todo to a particular list"""
try:
project = project_map[project].title
except KeyError:
pass
actions.key("cmd-shift-m")
actions.insert(project)
actions.key("enter")
@mod.capture(rule="{self.things_tag}+")
def things_tags(m) -> str:
"One or more Things tags"
return ",".join(m.things_tag_list)
@mod.capture(rule="{self.things_tag_with_shortcut}+")
def things_tags_with_shortcut(m) -> str:
"One or more Things tags"
return ",".join(m.things_tag_with_shortcut_list)
@mod.capture(rule="{self.things_project}+")
def things_projects(m) -> str:
"One or more Things projects"
return to_csv_row_string(m.things_project_list)
def to_csv_row_string(row_elements: str) -> str:
output = io.StringIO()
writer = csv.writer(output, quoting=csv.QUOTE_MINIMAL)
writer.writerow(row_elements)
return output.getvalue()