Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
11 changes: 8 additions & 3 deletions cursorless-talon/src/cheatsheet/get_list.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,18 +41,23 @@ def get_raw_list(name: str) -> Mapping[str, str]:
return typing.cast(dict[str, str], registry.lists[cursorless_list_name][0]).copy()


def get_spoken_form_from_list(list_name: str, value: str) -> str:
def get_spoken_form_from_list(list_name: str, value: str) -> str | None:
"""Get the spoken form of a value from a list.

Args:
list_name (str): The name of the list.
value (str): The value to look up.

Returns:
str: The spoken form of the value.
str: The spoken form of the value if found, otherwise None.
"""
return next(
spoken_form for spoken_form, v in get_raw_list(list_name).items() if v == value
(
spoken_form
for spoken_form, v in get_raw_list(list_name).items()
if v == value
),
None,
)


Expand Down
247 changes: 140 additions & 107 deletions cursorless-talon/src/cheatsheet/sections/actions.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
from ...actions.actions import ACTION_LIST_NAMES
from ..get_list import get_raw_list, make_dict_readable
from ..get_list import ListItemDescriptor, get_raw_list, make_dict_readable


def get_actions():
def get_actions() -> list[ListItemDescriptor]:
all_actions = {}
for name in ACTION_LIST_NAMES:
all_actions.update(get_raw_list(name))
Expand All @@ -28,111 +28,144 @@ def get_actions():
if value in multiple_target_action_names
}

swap_connective = list(get_raw_list("swap_connective").keys())[0]
swap_connectives = list(get_raw_list("swap_connective").keys())
swap_connective = swap_connectives[0] if swap_connectives else None

return [
*make_dict_readable(
"action",
simple_actions,
{
"editNewLineAfter": "Edit new line/scope after",
"editNewLineBefore": "Edit new line/scope before",
},
),
{
"id": "replaceWithTarget",
"type": "action",
"variations": [
{
"spokenForm": f"{complex_actions['replaceWithTarget']} <target> <destination>",
"description": "Copy <target> to <destination>",
},
{
"spokenForm": f"{complex_actions['replaceWithTarget']} <target>",
"description": "Insert copy of <target> at cursor",
},
],
},
{
"id": "pasteFromClipboard",
"type": "action",
"variations": [
{
"spokenForm": f"{complex_actions['pasteFromClipboard']} <destination>",
"description": "Paste from clipboard at <destination>",
}
],
},
{
"id": "moveToTarget",
"type": "action",
"variations": [
{
"spokenForm": f"{complex_actions['moveToTarget']} <target> <destination>",
"description": "Move <target> to <destination>",
},
{
"spokenForm": f"{complex_actions['moveToTarget']} <target>",
"description": "Move <target> to cursor position",
},
],
},
{
"id": "swapTargets",
"type": "action",
"variations": [
{
"spokenForm": f"{complex_actions['swapTargets']} <target 1> {swap_connective} <target 2>",
"description": "Swap <target 1> with <target 2>",
},
{
"spokenForm": f"{complex_actions['swapTargets']} {swap_connective} <target>",
"description": "Swap selection with <target>",
},
],
},
items = make_dict_readable(
"action",
simple_actions,
{
"id": "applyFormatter",
"type": "action",
"variations": [
{
"spokenForm": f"{complex_actions['applyFormatter']} <formatter> at <target>",
"description": "Reformat <target> as <formatter>",
}
],
"editNewLineAfter": "Edit new line/scope after",
"editNewLineBefore": "Edit new line/scope before",
},
{
"id": "callAsFunction",
"type": "action",
"variations": [
{
"spokenForm": f"{complex_actions['callAsFunction']} <target>",
"description": "Call <target> on selection",
},
{
"spokenForm": f"{complex_actions['callAsFunction']} <target 1> on <target 2>",
"description": "Call <target 1> on <target 2>",
},
],
},
{
"id": "wrapWithPairedDelimiter",
"type": "action",
"variations": [
{
"spokenForm": f"<pair> {complex_actions['wrapWithPairedDelimiter']} <target>",
"description": "Wrap <target> with <pair>",
}
],
},
{
"id": "rewrap",
"type": "action",
"variations": [
{
"spokenForm": f"<pair> {complex_actions['rewrap']} <target>",
"description": "Rewrap <target> with <pair>",
}
],
},
]
)

if "replaceWithTarget" in complex_actions:
items.append(
{
"id": "replaceWithTarget",
"type": "action",
"variations": [
{
"spokenForm": f"{complex_actions['replaceWithTarget']} <target> <destination>",
"description": "Copy <target> to <destination>",
},
{
"spokenForm": f"{complex_actions['replaceWithTarget']} <target>",
"description": "Insert copy of <target> at cursor",
},
],
}
)

Copy link
Member

@phillco phillco Jan 25, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's a bit of duplication here and this switches from defining a data structure to a fair bit of imperative code, but I think we could reduce it.

Why not something like a dictionary of tuples (one description and one lambda that generates the spoken form?):

{
    "replaceWithTarget": ("Copy <target> to <destination>", lambda value: f"{value} <target> <destination>"),
}

Then we could just use a loop to generate all of these and remove some the duplication.

Not sure if you could refer to stuff outside of the scope like swap_connective but I think it's helpful either way, if not that means the more complicated ones will stay as imperative code, which I think itself helps with readability.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Better like this?

if "pasteFromClipboard" in complex_actions:
items.append(
{
"id": "pasteFromClipboard",
"type": "action",
"variations": [
{
"spokenForm": f"{complex_actions['pasteFromClipboard']} <destination>",
"description": "Paste from clipboard at <destination>",
}
],
}
)

if "moveToTarget" in complex_actions:
items.append(
{
"id": "moveToTarget",
"type": "action",
"variations": [
{
"spokenForm": f"{complex_actions['moveToTarget']} <target> <destination>",
"description": "Move <target> to <destination>",
},
{
"spokenForm": f"{complex_actions['moveToTarget']} <target>",
"description": "Move <target> to cursor position",
},
],
}
)

if "swapTargets" in complex_actions and swap_connective:
items.append(
{
"id": "swapTargets",
"type": "action",
"variations": [
{
"spokenForm": f"{complex_actions['swapTargets']} <target 1> {swap_connective} <target 2>",
"description": "Swap <target 1> with <target 2>",
},
{
"spokenForm": f"{complex_actions['swapTargets']} {swap_connective} <target>",
"description": "Swap selection with <target>",
},
],
}
)

if "applyFormatter" in complex_actions:
items.append(
{
"id": "applyFormatter",
"type": "action",
"variations": [
{
"spokenForm": f"{complex_actions.get('applyFormatter')} <formatter> at <target>",
"description": "Reformat <target> as <formatter>",
}
],
}
)

if "callAsFunction" in complex_actions:
items.append(
{
"id": "callAsFunction",
"type": "action",
"variations": [
{
"spokenForm": f"{complex_actions['callAsFunction']} <target>",
"description": "Call <target> on selection",
},
{
"spokenForm": f"{complex_actions['callAsFunction']} <target 1> on <target 2>",
"description": "Call <target 1> on <target 2>",
},
],
}
)

if "wrapWithPairedDelimiter" in complex_actions:
items.append(
{
"id": "wrapWithPairedDelimiter",
"type": "action",
"variations": [
{
"spokenForm": f"<pair> {complex_actions['wrapWithPairedDelimiter']} <target>",
"description": "Wrap <target> with <pair>",
}
],
}
)

if "rewrap" in complex_actions:
items.append(
{
"id": "rewrap",
"type": "action",
"variations": [
{
"spokenForm": f"<pair> {complex_actions['rewrap']} <target>",
"description": "Rewrap <target> with <pair>",
}
],
}
)

return items
46 changes: 28 additions & 18 deletions cursorless-talon/src/cheatsheet/sections/compound_targets.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from ..get_list import get_raw_list, get_spoken_form_from_list
from ..get_list import ListItemDescriptor, get_raw_list, get_spoken_form_from_list

FORMATTERS = {
"rangeExclusive": lambda start, end: f"between {start} and {end}",
Expand All @@ -9,32 +9,42 @@
}


def get_compound_targets():
def get_compound_targets() -> list[ListItemDescriptor]:
list_connective_term = get_spoken_form_from_list(
"list_connective", "listConnective"
)
vertical_range_term = get_spoken_form_from_list("range_type", "verticalRange")

return [
{
"id": "listConnective",
"type": "compoundTargetConnective",
"variations": [
{
"spokenForm": f"<target 1> {list_connective_term} <target 2>",
"description": "<target 1> and <target 2>",
},
],
},
*[
items: list[ListItemDescriptor] = []

if list_connective_term:
items.append(
{
"id": "listConnective",
"type": "compoundTargetConnective",
"variations": [
{
"spokenForm": f"<target 1> {list_connective_term} <target 2>",
"description": "<target 1> and <target 2>",
},
],
}
)

items.extend(
[
get_entry(spoken_form, id)
for spoken_form, id in get_raw_list("range_connective").items()
],
get_entry(vertical_range_term, "verticalRange"),
]
]
)

if vertical_range_term:
items.append(get_entry(vertical_range_term, "verticalRange"))

return items


def get_entry(spoken_form, id):
def get_entry(spoken_form, id) -> ListItemDescriptor:
formatter = FORMATTERS[id]

return {
Expand Down
4 changes: 2 additions & 2 deletions cursorless-talon/src/cheatsheet/sections/destinations.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from ..get_list import get_raw_list
from ..get_list import ListItemDescriptor, get_raw_list


def get_destinations():
def get_destinations() -> list[ListItemDescriptor]:
insertion_modes = {
**{p: "to" for p in get_raw_list("insertion_mode_to")},
**get_raw_list("insertion_mode_before_after"),
Expand Down
Loading
Loading