Skip to content

Commit

Permalink
Support fully compositional modifiers
Browse files Browse the repository at this point in the history
Fixes #69
  • Loading branch information
pokey committed May 12, 2022
1 parent 39f91b7 commit f98806d
Show file tree
Hide file tree
Showing 11 changed files with 77 additions and 66 deletions.
15 changes: 7 additions & 8 deletions cursorless-talon/src/marks/lines_number.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from dataclasses import dataclass
from typing import Any, Callable

from talon import Context, Module

Expand All @@ -13,7 +14,7 @@ class CustomizableTerm:
defaultSpokenForm: str
cursorlessIdentifier: str
type: str
formatter: callable
formatter: Callable


# NOTE: Please do not change these dicts. Use the CSVs for customization.
Expand All @@ -33,18 +34,16 @@ class CustomizableTerm:


@mod.capture(rule="{user.cursorless_line_direction} <number_small>")
def cursorless_line_number(m) -> str:
def cursorless_line_number(m) -> dict[str, Any]:
direction = directions_map[m.cursorless_line_direction]
line_number = m.number_small
line = {
"lineNumber": direction.formatter(line_number),
"type": direction.type,
}
# TODO: Make sure to spit out a line in the case of a line number mark
return {
"selectionType": "line",
"mark": {
"type": "lineNumber",
"anchor": line,
"active": line,
},
"type": "lineNumber",
"anchor": line,
"active": line,
}
20 changes: 9 additions & 11 deletions cursorless-talon/src/marks/mark.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,19 +43,17 @@
@mod.capture(
rule="[{user.cursorless_hat_color}] [{user.cursorless_hat_shape}] <user.any_alphanumeric_key>"
)
def cursorless_decorated_symbol(m) -> dict[str, dict[str, Any]]:
def cursorless_decorated_symbol(m) -> dict[str, Any]:
"""A decorated symbol"""
hat_color = getattr(m, "cursorless_hat_color", "default")
try:
hat_style_name = f"{hat_color}-{m.cursorless_hat_shape}"
except AttributeError:
hat_style_name = hat_color
return {
"mark": {
"type": "decoratedSymbol",
"symbolColor": hat_style_name,
"character": m.any_alphanumeric_key,
}
"type": "decoratedSymbol",
"symbolColor": hat_style_name,
"character": m.any_alphanumeric_key,
}


Expand All @@ -69,10 +67,10 @@ class CustomizableTerm:
# NOTE: Please do not change these dicts. Use the CSVs for customization.
# See https://www.cursorless.org/docs/user/customization/
special_marks = [
CustomizableTerm("this", "currentSelection", {"mark": {"type": "cursor"}}),
CustomizableTerm("that", "previousTarget", {"mark": {"type": "that"}}),
CustomizableTerm("source", "previousSource", {"mark": {"type": "source"}}),
CustomizableTerm("nothing", "nothing", {"mark": {"type": "nothing"}}),
CustomizableTerm("this", "currentSelection", {"type": "cursor"}),
CustomizableTerm("that", "previousTarget", {"type": "that"}),
CustomizableTerm("source", "previousSource", {"type": "source"}),
CustomizableTerm("nothing", "nothing", {"type": "nothing"}),
# "last cursor": {"mark": {"type": "lastCursorPosition"}} # Not implemented
]

Expand All @@ -93,7 +91,7 @@ class CustomizableTerm:
"<user.cursorless_line_number>" # row (ie absolute mod 100), up, down
)
)
def cursorless_mark(m) -> str:
def cursorless_mark(m) -> dict[str, Any]:
try:
return m.cursorless_decorated_symbol
except AttributeError:
Expand Down
10 changes: 4 additions & 6 deletions cursorless-talon/src/modifiers/containing_scope.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,14 +50,12 @@


@mod.capture(rule="[every] {user.cursorless_scope_type}")
def cursorless_containing_scope(m) -> dict[str, dict[str, Any]]:
def cursorless_containing_scope(m) -> dict[str, Any]:
"""Expand to containing scope"""
return {
"modifier": {
"type": "containingScope",
"scopeType": m.cursorless_scope_type,
"includeSiblings": m[0] == "every",
}
"type": "containingScope",
"scopeType": m.cursorless_scope_type,
"includeSiblings": m[0] == "every",
}


Expand Down
7 changes: 3 additions & 4 deletions cursorless-talon/src/modifiers/head_tail.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from dataclasses import dataclass
from typing import Any

from talon import Module

Expand All @@ -22,9 +23,7 @@ class HeadTail:


@mod.capture(rule="{user.cursorless_head_tail}")
def cursorless_head_tail(m) -> dict:
def cursorless_head_tail(m) -> dict[str, Any]:
return {
"modifier": {
"type": head_tail_map[m.cursorless_head_tail],
}
"type": head_tail_map[m.cursorless_head_tail],
}
6 changes: 4 additions & 2 deletions cursorless-talon/src/modifiers/position.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from typing import Any

from talon import Context, Module

mod = Module()
Expand All @@ -19,5 +21,5 @@


@mod.capture(rule="{user.cursorless_position}")
def cursorless_position(m) -> str:
return positions[m.cursorless_position]
def cursorless_position(m) -> dict[str, Any]:
return {"type": "position", **positions[m.cursorless_position]}
7 changes: 5 additions & 2 deletions cursorless-talon/src/modifiers/selection_type.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from typing import Any

from talon import Module

mod = Module()
Expand All @@ -7,5 +9,6 @@


@mod.capture(rule="{user.cursorless_selection_type}")
def cursorless_selection_type(m) -> str:
return {"selectionType": m.cursorless_selection_type}
def cursorless_selection_type(m) -> dict[str, Any]:
# TODO: Change this to containing scope next
return {"type": "selectionType", "selectionType": m.cursorless_selection_type}
13 changes: 6 additions & 7 deletions cursorless-talon/src/modifiers/sub_token.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from typing import Any

from talon import Module

from ..compound_targets import is_active_included, is_anchor_included
Expand Down Expand Up @@ -51,17 +53,14 @@ def cursorless_first_last_range(m) -> str:
"{user.cursorless_subtoken_scope_type}"
)
)
def cursorless_subtoken_scope(m) -> str:
def cursorless_subtoken_scope(m) -> dict[str, Any]:
"""Subtoken ranges such as subwords or characters"""
try:
range = m.cursorless_ordinal_range
except AttributeError:
range = m.cursorless_first_last_range
return {
"selectionType": "token",
"modifier": {
"type": "subpiece",
"pieceType": m.cursorless_subtoken_scope_type,
**range,
},
"type": "subpiece",
"pieceType": m.cursorless_subtoken_scope_type,
**range,
}
40 changes: 20 additions & 20 deletions cursorless-talon/src/modifiers/surrounding_pair.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from typing import Any

from talon import Context, Module

from ..paired_delimiter import paired_delimiters_map
Expand Down Expand Up @@ -28,13 +30,29 @@
)


@mod.capture(
rule=(
"<user.cursorless_selectable_paired_delimiter> |"
"{user.cursorless_surrounding_pair_scope_type}"
)
)
def cursorless_surrounding_pair_scope_type(m) -> str:
"""Surrounding pair scope type"""
try:
return m.cursorless_surrounding_pair_scope_type
except AttributeError:
return paired_delimiters_map[
m.cursorless_selectable_paired_delimiter
].cursorlessIdentifier


@mod.capture(
rule=(
"[{user.cursorless_delimiter_inclusion}] [{user.cursorless_delimiter_force_direction}] <user.cursorless_surrounding_pair_scope_type> | "
"{user.cursorless_delimiter_inclusion} [{user.cursorless_delimiter_force_direction}]"
)
)
def cursorless_surrounding_pair(m) -> str:
def cursorless_surrounding_pair(m) -> dict[str, Any]:
"""Surrounding pair modifier"""
try:
surrounding_pair_scope_type = m.cursorless_surrounding_pair_scope_type
Expand All @@ -56,22 +74,4 @@ def cursorless_surrounding_pair(m) -> str:
except AttributeError:
pass

return {
"modifier": modifier,
}


@mod.capture(
rule=(
"<user.cursorless_selectable_paired_delimiter> |"
"{user.cursorless_surrounding_pair_scope_type}"
)
)
def cursorless_surrounding_pair_scope_type(m) -> str:
"""Surrounding pair scope type"""
try:
return m.cursorless_surrounding_pair_scope_type
except AttributeError:
return paired_delimiters_map[
m.cursorless_selectable_paired_delimiter
].cursorlessIdentifier
return modifier
6 changes: 4 additions & 2 deletions cursorless-talon/src/modifiers/to_raw_selection.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from typing import Any

from talon import Module

mod = Module()
Expand All @@ -10,5 +12,5 @@


@mod.capture(rule="{user.cursorless_to_raw_selection}")
def cursorless_to_raw_selection(m) -> dict:
return {"modifier": {"type": "toRawSelection"}}
def cursorless_to_raw_selection(m) -> dict[str, Any]:
return {"type": "toRawSelection"}
11 changes: 7 additions & 4 deletions cursorless-talon/src/primitive_target.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
from typing import Any

from talon import Module

mod = Module()

BASE_TARGET = {"type": "primitive"}
BASE_TARGET: dict[str, Any] = {"type": "primitive"}
IMPLICIT_TARGET = {"type": "primitive", "isImplicit": True}


Expand All @@ -27,9 +29,10 @@ def cursorless_modifier(m) -> str:
@mod.capture(
rule="<user.cursorless_modifier>+ [<user.cursorless_mark>] | <user.cursorless_mark>"
)
def cursorless_primitive_target(m) -> str:
def cursorless_primitive_target(m) -> dict[str, Any]:
"""Supported extents for cursorless navigation"""
result = BASE_TARGET.copy()
for capture in m:
result.update(capture)

result["stages"] = list(m)

return result
8 changes: 8 additions & 0 deletions src/typings/Types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,7 @@ export type InsideOutsideType = "inside" | "outside" | null;

export interface PartialPrimitiveTarget {
type: "primitive";
stages: PipelineDescriptor[];
mark?: Mark;
modifier?: Modifier;
selectionType?: SelectionType;
Expand All @@ -222,6 +223,13 @@ export interface PartialPrimitiveTarget {
isImplicit?: boolean;
}

type PipelineDescriptor =
| Mark
| Modifier
| SelectionType
| Position
| InsideOutsideType;

export interface PartialRangeTarget {
type: "range";
start: PartialPrimitiveTarget;
Expand Down

0 comments on commit f98806d

Please sign in to comment.