1#!/usr/local/bin/python3.8 2# vim:fileencoding=utf-8 3# License: GPLv3 Copyright: 2021, Kovid Goyal <kovid at kovidgoyal.net> 4 5import inspect 6from typing import Dict, List, NamedTuple 7 8from .boss import Boss 9from .tabs import Tab 10from .types import run_once, ActionGroup, ActionSpec 11from .window import Window 12 13 14class Action(NamedTuple): 15 name: str 16 group: str 17 short_help: str 18 long_help: str 19 20 21groups: Dict[ActionGroup, str] = { 22 'cp': 'Copy/paste', 23 'sc': 'Scrolling', 24 'win': 'Window management', 25 'tab': 'Tab management', 26 'mouse': 'Mouse actions', 27 'mk': 'Marks', 28 'lay': 'Layouts', 29 'misc': 'Miscellaneous', 30} 31group_title = groups.__getitem__ 32 33 34@run_once 35def get_all_actions() -> Dict[str, List[Action]]: 36 ' test docstring ' 37 38 ans: Dict[str, List[Action]] = {} 39 40 def is_action(x: object) -> bool: 41 return isinstance(getattr(x, 'action_spec', None), ActionSpec) 42 43 def as_action(x: object) -> Action: 44 spec: ActionSpec = getattr(x, 'action_spec') 45 doc = inspect.cleandoc(spec.doc) 46 lines = doc.splitlines() 47 first = lines.pop(0) 48 short_help = first 49 long_help = '\n'.join(lines).strip() 50 return Action(getattr(x, '__name__'), spec.group, short_help, long_help) 51 52 seen = set() 53 for cls in (Window, Tab, Boss): 54 for (name, func) in inspect.getmembers(cls, is_action): 55 ac = as_action(func) 56 if ac.name not in seen: 57 ans.setdefault(ac.group, []).append(ac) 58 seen.add(ac.name) 59 for i, which in enumerate('first second third fourth fifth sixth seventh eighth ninth tenth'.split()): 60 name = f'{which}_window' 61 if name not in seen: 62 seen.add(name) 63 ans['win'].append(Action(name, 'win', f'Focus the {which} window', '')) 64 65 return ans 66 67 68def dump() -> None: 69 from pprint import pprint 70 pprint(get_all_actions()) 71 72 73def as_rst() -> str: 74 from .options.definition import definition 75 from .conf.types import Mapping 76 allg = get_all_actions() 77 lines: List[str] = [] 78 a = lines.append 79 maps: Dict[str, List[Mapping]] = {} 80 for m in definition.iter_all_maps(): 81 if m.documented: 82 func = m.action_def.split()[0] 83 maps.setdefault(func, []).append(m) 84 85 for group in sorted(allg, key=lambda x: group_title(x).lower()): 86 title = group_title(group) 87 a('') 88 a(f'.. _action-group-{group}:') 89 a('') 90 a(title) 91 a('-' * len(title)) 92 a('') 93 94 for action in allg[group]: 95 a('') 96 a(f'.. _action-{action.name}:') 97 a('') 98 a(action.name) 99 a('+' * len(action.name)) 100 a('') 101 a(action.short_help) 102 a('') 103 if action.long_help: 104 a(action.long_help) 105 if action.name in maps: 106 a('') 107 a('Default shortcuts using this action:') 108 scs = {f':sc:`kitty.{m.name}`' for m in maps[action.name]} 109 a(', '.join(sorted(scs))) 110 return '\n'.join(lines) 111