Module: OmnifocusMcp::Infrastructure::AppleScript
- Defined in:
- lib/omnifocus_mcp/infrastructure/apple_script.rb
Overview
Composable AppleScript fragments for write-side primitives. rubocop:disable Metrics/ModuleLength
Constant Summary collapse
- ITEM_TYPES =
%w[task project].freeze
- LOOKUP_KINDS =
%i[folder project].freeze
Class Method Summary collapse
-
.escape(value) ⇒ Object
Escape ‘“` and `` so `value` is safe inside an AppleScript double-quoted string.
-
.find_item(var:, item_type:, id:, name:) ⇒ Object
Find a task or project, setting ‘var` to the located object or `missing value` when not found.
-
.generate_folder_lookup_script(raw_folder_path:, var_name:, error_return_json:) ⇒ Object
Generate AppleScript that resolves a folder by path or simple name.
-
.generate_lookup_script(kind:, raw_path:, var_name:, error_return_json:) ⇒ Object
Unified entry point for folder/project lookup scripts.
-
.generate_project_lookup_script(raw_project_path:, var_name:, error_return_json:) ⇒ Object
Generate AppleScript that resolves a project by path or simple name.
-
.indent(text:, prefix:) ⇒ Object
Prefix every non-empty line of ‘text` with `prefix`.
-
.tag_assignment(item_var:, tag_name:) ⇒ Object
Add an existing tag to ‘item_var`, creating it if it does not exist.
-
.tell_document(body) ⇒ Object
Wrap a script ‘body` in the standard OmniFocus front document envelope used by write-side primitives.
Class Method Details
.escape(value) ⇒ Object
Escape ‘“` and `` so `value` is safe inside an AppleScript double-quoted string. CR/LF collapse to a single space.
23 24 25 26 27 |
# File 'lib/omnifocus_mcp/infrastructure/apple_script.rb', line 23 def escape(value) value.to_s .gsub(/["\\]/) { |m| "\\#{m}" } .gsub(/[\r\n]/, " ") end |
.find_item(var:, item_type:, id:, name:) ⇒ Object
Find a task or project, setting ‘var` to the located object or `missing value` when not found.
47 48 49 50 51 52 53 54 55 56 57 58 59 60 |
# File 'lib/omnifocus_mcp/infrastructure/apple_script.rb', line 47 def find_item(var:, item_type:, id:, name:) unless ITEM_TYPES.include?(item_type) raise ArgumentError, "item_type must be one of #{ITEM_TYPES.inspect}, got #{item_type.inspect}" end collection = "flattened #{item_type}" sections = [ ["set #{var} to missing value"], id_lookup_lines(var: var, collection: collection, item_type: item_type, id: id), name_lookup_lines(var: var, collection: collection, item_type: item_type, name: name, fallback: !id.empty?) ] "#{sections.flatten.join("\n")}\n" end |
.generate_folder_lookup_script(raw_folder_path:, var_name:, error_return_json:) ⇒ Object
Generate AppleScript that resolves a folder by path or simple name.
81 82 83 84 85 86 87 88 |
# File 'lib/omnifocus_mcp/infrastructure/apple_script.rb', line 81 def generate_folder_lookup_script(raw_folder_path:, var_name:, error_return_json:) generate_lookup_script( kind: :folder, raw_path: raw_folder_path, var_name: var_name, error_return_json: error_return_json ) end |
.generate_lookup_script(kind:, raw_path:, var_name:, error_return_json:) ⇒ Object
Unified entry point for folder/project lookup scripts.
101 102 103 104 105 106 107 108 109 110 111 112 113 |
# File 'lib/omnifocus_mcp/infrastructure/apple_script.rb', line 101 def generate_lookup_script(kind:, raw_path:, var_name:, error_return_json:) unless LOOKUP_KINDS.include?(kind) raise ArgumentError, "kind must be one of #{LOOKUP_KINDS.inspect}, got #{kind.inspect}" end components = raw_path.split("/") .reject(&:empty?) return "set #{var_name} to missing value" if components.empty? escaped_components = components.map { |c| escape(c) } builder = components.length == 1 ? :simple : :nested send(:"#{builder}_#{kind}_lookup", var_name:, escaped_components:, error_return_json:) end |
.generate_project_lookup_script(raw_project_path:, var_name:, error_return_json:) ⇒ Object
Generate AppleScript that resolves a project by path or simple name.
91 92 93 94 95 96 97 98 |
# File 'lib/omnifocus_mcp/infrastructure/apple_script.rb', line 91 def generate_project_lookup_script(raw_project_path:, var_name:, error_return_json:) generate_lookup_script( kind: :project, raw_path: raw_project_path, var_name: var_name, error_return_json: error_return_json ) end |
.indent(text:, prefix:) ⇒ Object
Prefix every non-empty line of ‘text` with `prefix`. Lines that are blank or only-whitespace are passed through unchanged so the result diffs cleanly.
15 16 17 18 19 |
# File 'lib/omnifocus_mcp/infrastructure/apple_script.rb', line 15 def indent(text:, prefix:) text.each_line .map { |line| line.strip.empty? ? line : "#{prefix}#{line}" } .join end |
.tag_assignment(item_var:, tag_name:) ⇒ Object
Add an existing tag to ‘item_var`, creating it if it does not exist.
63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 |
# File 'lib/omnifocus_mcp/infrastructure/apple_script.rb', line 63 def tag_assignment(item_var:, tag_name:) <<~APPLESCRIPT.chomp try set theTag to first flattened tag where name = "#{tag_name}" add theTag to tags of #{item_var} on error -- Tag might not exist, try to create it try set theTag to make new tag with properties {name:"#{tag_name}"} add theTag to tags of #{item_var} on error -- Could not create or add tag end try end try APPLESCRIPT end |
.tell_document(body) ⇒ Object
Wrap a script ‘body` in the standard OmniFocus front document envelope used by write-side primitives.
31 32 33 34 35 36 37 38 39 40 41 42 43 |
# File 'lib/omnifocus_mcp/infrastructure/apple_script.rb', line 31 def tell_document(body) <<~APPLESCRIPT try tell application "OmniFocus" tell front document #{indent(text: body.chomp, prefix: " ")} end tell end tell on error errorMessage return "{\\"success\\":false,\\"error\\":\\"" & errorMessage & "\\"}" end try APPLESCRIPT end |