Advertisement
Guest User

Espanso Dynamic Forms

a guest
Apr 1st, 2025
24
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 9.97 KB | Source Code | 0 0
  1. I had an idea and had Gemini flesh it out. The idea was to basically chain together forms and pass their outputs to each other to get the desired effect, and it's working exactly as intended:
  2.  
  3. ## Match File `/match/eventargs.yml`
  4.  
  5. ```yaml
  6. matches:
  7. - trigger: ":eventargs"
  8. # The final output comes from the last script variable
  9. replace: "{{code_generator}}"
  10. label: "Generate C# EventArgs class (Dynamic Args)"
  11. vars:
  12. # --- Step 1: Get Event Name and Number of Arguments ---
  13. - name: form1
  14. type: form
  15. params:
  16. layout: |
  17. EventArgs Class Generator
  18.  
  19. Event Name (e.g., FindStation):
  20. [[EventName]]
  21.  
  22. Number of arguments/variables:
  23. [[NumArgs]]
  24. fields:
  25. EventName:
  26. NumArgs:
  27. default: "1" # Default to 1 argument
  28.  
  29. # --- Step 2: Generate Layout for the Second Form ---
  30. - name: layout_generator
  31. type: script
  32. params:
  33. args:
  34. - env
  35. - ESPANSO_NUM_ARGS={{form1.NumArgs}}
  36. - ESPANSO_EVENT_NAME={{form1.EventName}}
  37. - python
  38. - "%CONFIG%/scripts/generate_eventargs_form_layout.py"
  39.  
  40. # --- Step 3: Show the Dynamically Generated Form ---
  41. - name: form2
  42. type: form
  43. params:
  44. # Use the layout string generated by the previous script
  45. layout: "{{layout_generator}}" # Espanso substitutes the stdout here
  46.  
  47. # --- Step 4: Generate C# Code using Form 1 & Form 2 Inputs ---
  48. - name: code_generator
  49. type: script
  50. params:
  51. args:
  52. - env
  53. - ESPANSO_EVENT_NAME={{form1.EventName}}
  54. - ESPANSO_NUM_ARGS={{form1.NumArgs}}
  55. - python
  56. - "%CONFIG%/scripts/generate_eventargs_code_dynamic.py"matches:
  57. - trigger: ":eventargs"
  58. # The final output comes from the last script variable
  59. replace: "{{code_generator}}"
  60. label: "Generate C# EventArgs class (Dynamic Args)"
  61. vars:
  62. # --- Step 1: Get Event Name and Number of Arguments ---
  63. - name: form1
  64. type: form
  65. params:
  66. layout: |
  67. EventArgs Class Generator
  68.  
  69.  
  70. Event Name (e.g., FindStation):
  71. [[EventName]]
  72.  
  73.  
  74. Number of arguments/variables:
  75. [[NumArgs]]
  76. fields:
  77. EventName:
  78. NumArgs:
  79. default: "1" # Default to 1 argument
  80.  
  81.  
  82. # --- Step 2: Generate Layout for the Second Form ---
  83. - name: layout_generator
  84. type: script
  85. params:
  86. args:
  87. - env
  88. - ESPANSO_NUM_ARGS={{form1.NumArgs}}
  89. - ESPANSO_EVENT_NAME={{form1.EventName}}
  90. - python
  91. - "%CONFIG%/scripts/generate_eventargs_form_layout.py"
  92.  
  93.  
  94. # --- Step 3: Show the Dynamically Generated Form ---
  95. - name: form2
  96. type: form
  97. params:
  98. # Use the layout string generated by the previous script
  99. layout: "{{layout_generator}}" # Espanso substitutes the stdout here
  100.  
  101.  
  102. # --- Step 4: Generate C# Code using Form 1 & Form 2 Inputs ---
  103. - name: code_generator
  104. type: script
  105. params:
  106. args:
  107. - env
  108. - ESPANSO_EVENT_NAME={{form1.EventName}}
  109. - ESPANSO_NUM_ARGS={{form1.NumArgs}}
  110. - python
  111. - "%CONFIG%/scripts/generate_eventargs_code_dynamic.py"
  112. ```
  113.  
  114. ## Python Scripts
  115.  
  116. ### Form Layout Generator `/scripts/generate_eventargs_form_layout.py`
  117.  
  118. ```python
  119. #!/usr/bin/env python
  120. # scripts/generate_eventargs_form_layout.py
  121. """
  122. Generates the layout string for the second Espanso form based on the
  123. number of arguments specified in the first form.
  124. Reads ESPANSO_NUM_ARGS and ESPANSO_EVENT_NAME.
  125. Prints the layout string to stdout.
  126. """
  127. import os
  128. import sys
  129. import logging
  130.  
  131. # Configure logging
  132. logging.basicConfig(stream=sys.stderr, level=logging.WARNING, format='%(levelname)s:%(name)s:%(message)s')
  133. log = logging.getLogger('layout_generator')
  134.  
  135. if __name__ == "__main__":
  136. layout_lines = []
  137. try:
  138. num_args_str = os.environ.get("ESPANSO_NUM_ARGS", "0")
  139. event_name = os.environ.get("ESPANSO_EVENT_NAME", "MyEvent") # Get name for title
  140.  
  141. try:
  142. num_args = int(num_args_str)
  143. if num_args < 0:
  144. num_args = 0
  145. # Optional: Set a reasonable upper limit?
  146. # max_args = 10
  147. # if num_args > max_args:
  148. # log.warning(f"Number of args {num_args} exceeds maximum {max_args}, capping.")
  149. # num_args = max_args
  150. except ValueError:
  151. log.error(f"Invalid number of arguments received: '{num_args_str}'. Defaulting to 0.")
  152. num_args = 0
  153.  
  154. # Start layout string - Use event name in title
  155. layout_lines.append(f"Define Arguments for {event_name}EventArgs")
  156. layout_lines.append("-" * (len(layout_lines[0]))) # Add underline
  157.  
  158. if num_args == 0:
  159. layout_lines.append("\n(No arguments specified)")
  160. else:
  161. # Add fields dynamically
  162. for i in range(1, num_args + 1):
  163. layout_lines.append(f"\nArgument #{i}")
  164. layout_lines.append(f"Type [[type{i}]]")
  165. layout_lines.append(f"Name [[var{i}]]")
  166.  
  167. # Join lines and print the final layout string
  168. print("\n".join(layout_lines), end='')
  169.  
  170. except Exception as e:
  171. log.critical(f"Error generating form layout: {e}", exc_info=True)
  172. # Output a fallback layout in case of error
  173. print("Error generating layout\nError Message: [[error]]", end='')
  174. sys.exit(1)
  175. ```
  176.  
  177. ### Code Builder `/scripts/generate_eventargs_code_dynamic.py`
  178.  
  179. ```python
  180. #!/usr/bin/env python
  181. # scripts/generate_eventargs_code_dynamic.py
  182. """
  183. Generates the C# EventArgs class code based on the EventName and
  184. the arguments provided in the dynamically generated second form.
  185. Reads ESPANSO_EVENT_NAME, ESPANSO_NUM_ARGS, and ESPANSO_FORM2_TYPE/VAR pairs.
  186. Prints the generated C# code to stdout.
  187. """
  188. import os
  189. import sys
  190. import logging
  191. from typing import List, Tuple
  192.  
  193. # Configure logging
  194. logging.basicConfig(stream=sys.stderr, level=logging.WARNING, format='%(levelname)s:%(name)s:%(message)s')
  195. log = logging.getLogger('code_generator')
  196.  
  197. def generate_csharp_code(event_name: str, valid_args: List[Tuple[str, str]]) -> str:
  198. """Generates the C# EventArgs class code string."""
  199. if not event_name:
  200. event_name = "MyEvent" # Fallback name
  201.  
  202. class_name = f"{event_name}EventArgs"
  203. indent = " " # 4 spaces for indentation
  204.  
  205. # --- Build Code Parts ---
  206. field_lines = []
  207. param_list = []
  208. assignment_lines = []
  209.  
  210. for arg_type, arg_name in valid_args:
  211. field_lines.append(f"{indent}public readonly {arg_type} {arg_name};")
  212. param_list.append(f"{arg_type} {arg_name}")
  213. assignment_lines.append(f"{indent}{indent}this.{arg_name} = {arg_name};")
  214.  
  215. # Join parts
  216. fields_str = "\n".join(field_lines) if field_lines else ""
  217. params_str = ", ".join(param_list) if param_list else ""
  218. assignments_str = "\n".join(assignment_lines) if assignment_lines else ""
  219.  
  220. # Handle constructor body indentation/newlines correctly
  221. constructor_body = f"\n{assignments_str}\n{indent}" if assignments_str else ""
  222.  
  223. # Assemble final code
  224. code = f"""\
  225. public class {class_name} : EventArgs
  226. {{
  227. {fields_str}{"" if not fields_str else "\n"}
  228. {indent}public {class_name}({params_str})
  229. {indent}{{
  230. {constructor_body}}}
  231. }}""" # Using triple quotes for multi-line string
  232.  
  233. return code
  234.  
  235.  
  236. if __name__ == "__main__":
  237. try:
  238. event_name = os.environ.get("ESPANSO_EVENT_NAME")
  239. num_args_str = os.environ.get("ESPANSO_NUM_ARGS", "0")
  240.  
  241. if not event_name:
  242. log.error("EventName not received from environment.")
  243. print("// Error: EventName not provided.", file=sys.stderr)
  244. sys.exit(1)
  245.  
  246. try:
  247. num_args = int(num_args_str)
  248. if num_args < 0: num_args = 0
  249. except ValueError:
  250. log.error(f"Invalid number of arguments received: {num_args_str}")
  251. print(f"// Error: Invalid NumArgs '{num_args_str}'", file=sys.stderr)
  252. sys.exit(1)
  253.  
  254. # --- Collect valid arguments from form2 ---
  255. valid_args_list: List[Tuple[str, str]] = []
  256. log.debug(f"Expecting {num_args} argument pairs.")
  257.  
  258. for i in range(1, num_args + 1):
  259. arg_type = os.environ.get(f"ESPANSO_FORM2_TYPE{i}", "").strip()
  260. arg_name = os.environ.get(f"ESPANSO_FORM2_VAR{i}", "").strip()
  261. log.debug(f"Read Arg {i}: Type='{arg_type}', Name='{arg_name}'")
  262.  
  263. # Only include if BOTH type and name are non-empty
  264. if arg_type and arg_name:
  265. valid_args_list.append((arg_type, arg_name))
  266. log.debug(f"Added valid arg pair {i}: ({arg_type}, {arg_name})")
  267. else:
  268. log.debug(f"Skipping arg pair {i} because type or name was empty.")
  269.  
  270. log.info(f"Collected {len(valid_args_list)} valid argument pairs.")
  271.  
  272. # Generate the C# code
  273. csharp_code = generate_csharp_code(event_name, valid_args_list)
  274.  
  275. # Print final code to stdout for Espanso
  276. print(csharp_code, end='')
  277.  
  278. except Exception as e:
  279. log.critical(f"Error generating C# code: {e}", exc_info=True)
  280. print(f"// Error generating EventArgs code: {e}", file=sys.stderr)
  281. sys.exit(1)
  282. ```
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement