from ....code.terms import SELECT, TELEPORT, DELETE, FIND from enum import Enum from dataclasses import dataclass from ....code.keys import symbol_key_words import json from talon import Context, actions, ui, Module, app, clip ctx = Context() mod = Module() ctx.matches = r""" app: vscode """ mod.list("symbol_color", desc="Supported symbol colors for token jumping") ctx.lists["self.symbol_color"] = { "gray": "default", "blue": "blue", "green": "green", "rose": "red", "squash": "yellow", "plum": "mauve", } CONNECTIVES = {"at", "of", "in", "containing"} BASE_TARGET = {"type": "primitive"} @mod.capture( rule=( "[{user.cursorless_position}] " "[{user.cursorless_pair_surround_type}] " "[{user.cursorless_selection_type} [of | in | containing]] " "[] " "[ [at]]" "( | {user.cursorless_mark} | {user.unmarked_core} | | | )" "[ | {user.cursorless_matching}]" ) ) def cursorless_target(m) -> str: """Supported extents for cursorless navigation""" object = BASE_TARGET.copy() for capture in m: if capture in CONNECTIVES: continue for key, value in json.loads(capture).items(): if ( key in object and key == SELECTION_TYPE_KEY and ranked_selection_types[value] < ranked_selection_types[object[key]] ): continue object[key] = value return json.dumps(object) @dataclass class ModifierTerm: term: str info: dict @property def value(self): return json.dumps(self.info) def make_simple_transformation(type: str): return {"transformation": {"type": type}} matching_transformation = ModifierTerm( "matching", make_simple_transformation("matchingPairSymbol") ) mod.list("cursorless_matching", desc="Supported symbol extent types") ctx.lists["self.cursorless_matching"] = { matching_transformation.term: matching_transformation.value } containing_scope_type_map = { "arg": "argumentOrParameter", "arrow": "arrowFunction", "class": "class", "funk": "namedFunction", "if": "ifStatement", "lambda": "arrowFunction", "map": "dictionary", "pair": "pair", "value": "pairValue", "key": "pairKey", } containing_scope_types = { term: { "transformation": { "type": "containingScope", "scopeType": containing_scope_type, } } for term, containing_scope_type in containing_scope_type_map.items() } mod.list("containing_scope_type", desc="Supported symbol extent types") ctx.lists["self.containing_scope_type"] = { key: json.dumps(value) for key, value in containing_scope_types.items() } SELECTION_TYPE_KEY = "selectionType" @dataclass class SelectionType: singular: str plural: str json_name: str rank: int @property def json_repr(self): return {SELECTION_TYPE_KEY: self.json_name} TOKEN = SelectionType("token", "tokens", "token", 0) LINE = SelectionType("line", "lines", "line", 1) BLOCK = SelectionType("block", "blocks", "block", 2) SELECTION_TYPES = [ TOKEN, LINE, BLOCK, ] ranked_selection_types = { selection_type.json_name: selection_type.rank for selection_type in SELECTION_TYPES } cursor_mark = {"mark": {"type": "cursor"}} marks = { "here": cursor_mark, "this": cursor_mark, **{ f"this {selection_type.singular}": {**selection_type.json_repr, **cursor_mark} for selection_type in SELECTION_TYPES }, **{ f"these {selection_type.plural}": {**selection_type.json_repr, **cursor_mark} for selection_type in SELECTION_TYPES }, "change": {"mark": {"type": "lastEditRange"}}, "last cursor": {"mark": {"type": "lastCursorPosition"}}, **{ f"this {containing_scope_type}": {**cursor_mark, **value} for containing_scope_type, value in containing_scope_types.items() }, } mod.list("cursorless_mark", desc="Types of marks") ctx.lists["self.cursorless_mark"] = { key: json.dumps(value) for key, value in marks.items() } unmarked_cores = { **containing_scope_types, **{ selection_type.singular: selection_type.json_repr for selection_type in SELECTION_TYPES }, matching_transformation.term: matching_transformation.info, } mod.list("unmarked_core", desc="Core terms whose mark must be inferred") ctx.lists["self.unmarked_core"] = { key: json.dumps(value) for key, value in unmarked_cores.items() } positions = { "after": {"position": "after"}, "before": {"position": "before"}, "start of": {"position": "before", "insideOutsideType": "inside"}, "end of": {"position": "after", "insideOutsideType": "inside"}, "above": {"position": "before", **LINE.json_repr}, "below": {"position": "after", **LINE.json_repr}, } mod.list("cursorless_position", desc="Types of positions") ctx.lists["self.cursorless_position"] = { key: json.dumps(value) for key, value in positions.items() } selection_type_map = {} for selection_type in SELECTION_TYPES: selection_type_map[selection_type.singular] = selection_type.json_repr selection_type_map[selection_type.plural] = selection_type.json_repr mod.list("cursorless_selection_type", desc="Types of selection_types") ctx.lists["self.cursorless_selection_type"] = { key: json.dumps(value) for key, value in selection_type_map.items() } @mod.capture(rule="[at] [{user.symbol_color}] ") def decorated_symbol(m) -> str: """A decorated symbol""" try: symbol_color = m.symbol_color except AttributeError: symbol_color = "default" character = m.any_alphanumeric_key return json.dumps( { "mark": { "type": "decoratedSymbol", "symbolColor": symbol_color, "character": character, } } ) mod.list("cursorless_sub_component_type", desc="Supported subcomponent types") ctx.lists["self.cursorless_sub_component_type"] = { "small": "subtoken", "subtoken": "subtoken", "subtokens": "subtoken", "subword": "subtoken", "subwords": "subtoken", "car": "character", "cars": "character", "character": "character", "characters": "character", "letter": "character", "letters": "character", } @mod.capture( rule=( " [through ] {user.cursorless_sub_component_type}" ) ) def cursorless_indexer(m) -> str: """Supported extents for cursorless navigation""" return json.dumps( { "transformation": { "type": "subpiece", "pieceType": m.cursorless_sub_component_type, "startIndex": m.ordinals_list[0], "endIndex": m.ordinals_list[-1] + 1, } } ) pair_symbols = { "[": "squareBrackets", "]": "squareBrackets", "{": "curlyBrackets", "}": "curlyBrackets", "<": "angleBrackets", ">": "angleBrackets", "(": "parentheses", ")": "parentheses", '"': "doubleQuotes", "'": "singleQuotes", } mod.list("pair_symbol", desc="A pair symbol") ctx.lists["self.pair_symbol"] = { phrase: pair_symbols[character] for phrase, character in symbol_key_words.items() if character in pair_symbols } cursorless_pair_surround_types = { "out": {"insideOutsideType": "outside"}, "outer": {"insideOutsideType": "outside"}, "outside": {"insideOutsideType": "outside"}, "in": {"insideOutsideType": "inside"}, "inner": {"insideOutsideType": "inside"}, "inside": {"insideOutsideType": "inside"}, } mod.list("cursorless_pair_surround_type", desc="Supported pair surround types") ctx.lists["self.cursorless_pair_surround_type"] = { key: json.dumps(value) for key, value in cursorless_pair_surround_types.items() } @mod.capture(rule=("{user.cursorless_pair_surround_type} {user.pair_symbol}")) def cursorless_surrounding_pair(m) -> str: """Supported extents for cursorless navigation""" return json.dumps( { "transformation": { "type": "surroundingPair", "delimiter": m.pair_symbol, } ** json.loads(m.cursorless_pair_surround_type), } ) simple_transformations = [ matching_transformation, ] mod.list("cursorless_simple_transformations", desc="simple transformations") ctx.lists["self.cursorless_simple_transformations"] = { transformation.term: transformation.value for transformation in simple_transformations } @mod.capture(rule=("[every] {user.containing_scope_type} [containing]")) def cursorless_containing_scope(m) -> str: """Supported extents for cursorless navigation""" if m[0] in ["every"]: current_target = json.loads(m.containing_scope_type) current_target["transformation"]["includeSiblings"] = True return json.dumps(current_target) return m.containing_scope_type @mod.capture( rule=( " |" "{user.cursorless_simple_transformations} |" "" ) ) def cursorless_range_transformation(m) -> str: """Supported positions for cursorless navigation""" return str(m)