Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Some cheatsheet improvements #129

Merged
merged 5 commits into from
Dec 14, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
214 changes: 58 additions & 156 deletions src/cheat_sheet.py → src/cheatsheet/cheat_sheet.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
from .conventions import get_cursorless_list_name
from talon import Module, ui, registry, skia, actions, cron
from talon import Module, ui, skia, actions, cron
from talon.canvas import Canvas
import re
import webbrowser
import math
from .actions.actions import ACTION_LIST_NAMES

from .sections.actions import get_actions
from .sections.scopes import get_scopes
from .sections.compound_targets import get_compound_targets

from .get_list import get_list, get_lists

mod = Module()
mod.mode("cursorless_cheat_sheet", "Mode for showing cursorless cheat sheet gui")
Expand Down Expand Up @@ -95,141 +98,50 @@ def draw(self, canvas):
self.y = get_y(canvas)
self.w = 0

all_actions = {}
for name in ACTION_LIST_NAMES:
all_actions.update(get_raw_list(name))

multiple_target_action_names = [
"replaceWithTarget",
"moveToTarget",
"swapTargets",
"applyFormatter",
]
simple_actions = {
key: value
for key, value in all_actions.items()
if value not in multiple_target_action_names
}
complex_actions = {
value: key
for key, value in all_actions.items()
if value in multiple_target_action_names
}

swap_connective = list(get_raw_list("swap_connective").keys())[0]
source_destination_connective = list(
get_raw_list("source_destination_connective").keys()
)[0]

make_dict_readable(
simple_actions,
{
"callAsFunction": "Call T on S",
"wrapWithPairedDelimiter": '"round" wrap T',
},
)
all_actions = {
**simple_actions,
f"{complex_actions['replaceWithTarget']} T1 {source_destination_connective} T2": "Replace T2 with T1",
f"{complex_actions['replaceWithTarget']} T": "Replace S with T",
f"{complex_actions['moveToTarget']} T1 {source_destination_connective} T2": "Move T1 to T2",
f"{complex_actions['moveToTarget']} T": "Move T to S",
f"{complex_actions['swapTargets']} T1 {swap_connective} T2": "Swap T1 with T2",
f"{complex_actions['swapTargets']} T": "Swap S with T",
f"{complex_actions['applyFormatter']} * at T": "Reformat T as *",
}

actions_limit = round(len(all_actions) / 2)
actions_1 = slice_dict(all_actions, 0, actions_limit)
actions_2 = slice_dict(all_actions, actions_limit)

self.draw_header(canvas, "Actions")
self.draw_items(canvas, actions_1)
self.next_column(canvas)

self.draw_header(canvas, "More actions")
self.draw_items(canvas, actions_2)
self.next_column(canvas)

all_scopes = get_list("scope_type", {"argumentOrParameter": "Argument"})
scopes_limit = len(all_scopes) - 3
scopes_1 = slice_dict(all_scopes, 0, scopes_limit)
scopes_2 = slice_dict(all_scopes, scopes_limit)
self.is_first_row_in_column = True

self.draw_header(canvas, "Scopes")
self.draw_items(canvas, scopes_1)
self.draw_multicolumn_section(
canvas, get_actions(), ["Actions", "More actions"]
)

self.next_column(canvas)

self.draw_header(canvas, "More scopes")
self.draw_items(canvas, scopes_2)

self.next_row()
self.draw_header(canvas, "Selection types")
self.draw_items(canvas, get_list("selection_type"))

self.next_row()
self.draw_header(canvas, "Subtokens")
self.draw_items(canvas, get_list("subtoken_scope_type"))
self.draw_multicolumn_section(canvas, get_scopes(), ["Scopes", "More scopes"])

self.next_row()
self.draw_header(canvas, "Positions")
self.draw_items(canvas, get_list("position"))
self.draw_section(
canvas,
"Paired delimiters",
get_lists(
[
"wrapper_only_paired_delimiter",
"wrapper_selectable_paired_delimiter",
"selectable_only_paired_delimiter",
]
),
)

self.next_row()
self.draw_header(canvas, "Special marks")
self.draw_items(canvas, get_list("special_mark"))
self.draw_section(canvas, "Special marks", get_list("special_mark"))

self.next_column(canvas)

include_both_term = next(
spoken_form
for spoken_form, value in get_raw_list("range_connective").items()
if value == "rangeInclusive"
)
list_connective_term = next(
spoken_form
for spoken_form, value in get_raw_list("list_connective").items()
if value == "listConnective"
)
self.draw_section(canvas, "Positions", get_list("position"))

self.draw_header(canvas, "Compound targets")
self.draw_items(
self.draw_section(
canvas,
{
f"T1 {list_connective_term} T2": "T1 and T2",
f"T1 {include_both_term} T2": "T1 through T2",
f"{include_both_term} T": "S through T",
},
"Compound targets",
get_compound_targets(),
)

hat_colors = get_list("hat_color")
if hat_colors:
self.next_row()
self.draw_header(canvas, "Colors")
self.draw_items(canvas, hat_colors)
self.draw_section(canvas, "Colors", hat_colors)

hat_shapes = get_list("hat_shape")
if hat_shapes:
self.next_row()
self.draw_header(canvas, "Shapes")
self.draw_items(canvas, hat_shapes)
self.draw_section(canvas, "Shapes", hat_shapes)

self.next_row()
self.draw_header(canvas, "Examples")
self.draw_items(
canvas,
[
"Post blue air",
"Take funk green bat",
"Chuck air past cap",
"Clear first word drum",
"Bring line each to fine",
"Take gust and harp",
"Copy that",
"Center funk",
],
)
# Needs to update this for the last column
self.max_y = max(self.max_y, self.y)

# Resize to fit content
# NB: We debounce because for some reason draw gets called multiple
Expand All @@ -239,6 +151,27 @@ def draw(self, canvas):
math.ceil(self.max_y - canvas.y + outer_padding),
)

def draw_section(self, canvas, header_text, items):
if not self.is_first_row_in_column:
self.y += line_height / 2

self.is_first_row_in_column = False

self.draw_header(canvas, header_text)
self.draw_items(canvas, items)

def draw_multicolumn_section(
self, canvas, items, column_names: str, scopes_limit=24
):
items_0 = slice_dict(items, 0, scopes_limit)
items_1 = slice_dict(items, scopes_limit)

self.draw_section(canvas, column_names[0], items_0)

self.next_column(canvas)

self.draw_section(canvas, column_names[1], items_1)

def draw_background(self, canvas):
radius = 10
rrect = skia.RoundRect.from_rect(canvas.rect, x=radius, y=radius)
Expand All @@ -255,7 +188,10 @@ def draw_legend(self, canvas):
canvas.paint.textsize = text_size
canvas.paint.color = text_color
self.y = canvas.y + canvas.height - line_height
self.draw_value(canvas, "S = Current selection T = Target")
self.draw_value(
canvas,
"S = Current selection, T = Target, P = Paired delimiter, F = Formatter",
)

def draw_close(self, canvas):
canvas.paint.textsize = close_size
Expand All @@ -279,9 +215,7 @@ def next_column(self, canvas):
self.x = self.x + self.w + 1.5 * line_height
self.y = get_y(canvas)
self.w = 0

def next_row(self):
self.y += line_height
self.is_first_row_in_column = True

def draw_header(self, canvas, text):
canvas.paint.typeface = text_font
Expand Down Expand Up @@ -372,21 +306,6 @@ def cursorless_open_instructions():
webbrowser.open(instructions_url)


def get_list(name, descriptions=None):
if descriptions is None:
descriptions = {}

items = get_raw_list(name)
if isinstance(items, dict):
make_dict_readable(items, descriptions)
return items


def get_raw_list(name):
cursorless_list_name = get_cursorless_list_name(name)
return registry.lists[cursorless_list_name][0].copy()


def get_y(canvas):
return canvas.y + outer_padding

Expand All @@ -395,23 +314,6 @@ def draw_text(canvas, text, x, y):
canvas.draw_text(text, x, y + text_size + padding / 2)


def make_dict_readable(dict, descriptions=None):
if descriptions is None:
descriptions = {}

for k in dict:
desc = dict[k]
if desc in descriptions:
desc = descriptions[desc]
else:
desc = make_readable(desc)
dict[k] = desc


def make_readable(text):
return re.sub(r"(?<=[a-z])(?=[A-Z])", " ", text).lower().capitalize()


def get_close_rect(canvas):
wh = 1.5 * close_size
cr = canvas.rect
Expand Down
File renamed without changes.
42 changes: 42 additions & 0 deletions src/cheatsheet/get_list.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
from ..conventions import get_cursorless_list_name
from talon import registry
import re


def get_list(name, descriptions=None):
if descriptions is None:
descriptions = {}

items = get_raw_list(name)
if isinstance(items, dict):
make_dict_readable(items, descriptions)
return items


def get_lists(names: list[str], descriptions=None):
items = sorted(
item for name in names for item in get_list(name, descriptions).items()
)
return {key: value for key, value in items}


def get_raw_list(name):
cursorless_list_name = get_cursorless_list_name(name)
return registry.lists[cursorless_list_name][0].copy()


def make_dict_readable(dict, descriptions=None):
if descriptions is None:
descriptions = {}

for k in dict:
desc = dict[k]
if desc in descriptions:
desc = descriptions[desc]
else:
desc = make_readable(desc)
dict[k] = desc


def make_readable(text):
return re.sub(r"(?<=[a-z])(?=[A-Z])", " ", text).lower().capitalize()
49 changes: 49 additions & 0 deletions src/cheatsheet/sections/actions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
from ..get_list import get_raw_list, make_dict_readable
from ...actions.actions import ACTION_LIST_NAMES


def get_actions():
all_actions = {}
for name in ACTION_LIST_NAMES:
all_actions.update(get_raw_list(name))

multiple_target_action_names = [
"replaceWithTarget",
"moveToTarget",
"swapTargets",
"applyFormatter",
"wrapWithPairedDelimiter",
]
simple_actions = {
key: value
for key, value in all_actions.items()
if value not in multiple_target_action_names
}
complex_actions = {
value: key
for key, value in all_actions.items()
if value in multiple_target_action_names
}

swap_connective = list(get_raw_list("swap_connective").keys())[0]
source_destination_connective = list(
get_raw_list("source_destination_connective").keys()
)[0]

make_dict_readable(
simple_actions,
{
"callAsFunction": "Call T on S",
},
)
return {
**simple_actions,
f"{complex_actions['replaceWithTarget']} <T1> {source_destination_connective} <T2>": "Replace T2 with T1",
f"{complex_actions['replaceWithTarget']} <T>": "Replace S with T",
f"{complex_actions['moveToTarget']} <T1> {source_destination_connective} <T2>": "Move T1 to T2",
f"{complex_actions['moveToTarget']} <T>": "Move T to S",
f"{complex_actions['swapTargets']} <T1> {swap_connective} <T2>": "Swap T1 with T2",
f"{complex_actions['swapTargets']} <T>": "Swap S with T",
f"{complex_actions['applyFormatter']} <F> at <T>": "Reformat T as F",
f"<P> {complex_actions['wrapWithPairedDelimiter']} <T>": "Wrap T with P",
}
21 changes: 21 additions & 0 deletions src/cheatsheet/sections/compound_targets.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
from ..get_list import get_raw_list


def get_compound_targets():
include_both_term = next(
spoken_form
for spoken_form, value in get_raw_list("range_connective").items()
if value == "rangeInclusive"
)
list_connective_term = next(
spoken_form
for spoken_form, value in get_raw_list("list_connective").items()
if value == "listConnective"
)
compound_targets = {
f"<T1> {list_connective_term} <T2>": "T1 and T2",
f"<T1> {include_both_term} <T2>": "T1 through T2",
f"{include_both_term} <T>": "S through T",
}

return compound_targets
Loading