bin/hook in hookapp-0.0.7 vs bin/hook in hookapp-2.0.3

- old
+ new

@@ -7,21 +7,34 @@ # Main class for GLI app class App extend GLI::App program_desc 'CLI interface for Hook.app (macOS)' + program_long_desc 'Hook.app is a productivity tool for macOS <https://hookproductivity.com/>. This gem includes a `hook` binary that allows interaction with the features of Hook.app.' + default_command 'help' + autocomplete_commands = true + synopsis_format(:terminal) version Hook::VERSION subcommand_option_handling :normal arguments :strict hooker = nil desc 'List hooks on a file or url' + long_desc %{ +Output a list of all hooks attached to given url(s) or file(s) in the specified format (default "paths"). + +Run `hook list` with no file/url argument to list all bookmarks.} + arg_name 'FILE_OR_URL [FILE_OR_URL...]' command %i[list ls] do |c| + c.desc 'Generate a menu to select hook(s) for opening' + c.long_desc 'This option is a shortcut to `hook select` and overrides any other arguments.' + c.switch %i[s select] + c.desc 'Output only bookmarks with file paths (exclude e.g. emails)' c.switch %i[f files_only], { negatable: false, default_value: false } c.desc 'Separate results with NULL separator, only applies with "paths" output for single file argument' c.switch %i[null], { negatable: false, default_value: false } @@ -30,22 +43,98 @@ fmt_list = valid_formats.map { |fmt| fmt.sub(/^(.)(.*?)$/, '(\1)\2') }.join(', ') c.desc "Output format [#{fmt_list}]" c.flag %i[o output_format], { arg_name: 'format', default_value: 'paths' } c.action do |_global_options, options, args| + if options[:s] + return hooker.open_linked(args[0]) + end valid_format = hooker.validate_format(options[:o], valid_formats) - raise 'Invalid output format' unless valid_format + exit_now!("Invalid output format: \"#{options[:o]}\"", 6) unless valid_format result = hooker.linked_bookmarks(args, { files_only: options[:f], format: valid_format, null_separator: options[:null] }) puts result end end + # Shell completion scripts are located in lib/completion/ and named "hook_completion" with + # the full shell name as the extension, e.g. "hook_completion.bash". + desc 'Shell completion examples' + valid_shells = %w[bash zsh fish] + long_desc %{ +Output completion script example for the specified shell (#{valid_shells.join(', ')}) + } + arg_name 'SHELL' + command %i[scripts] do |c| + c.action do |_global_options, _options, args| + if args.length > 1 + exit_now!("Invalid number of arguments, (expected 1)", 5) + elsif args.nil? || args.empty? + exit_now!("Specify a shell (#{valid_shells.join(', ')})", 0) + else + if valid_shells.include?(args[0]) + base_dir = File.expand_path(File.join(File.dirname(__FILE__), '../lib/completion')) + completion = File.join(base_dir, "hook_completion.#{args[0]}") + script = IO.read(completion) + $stdout.puts script + else + exit_now!("Invalid shell name, must be one of #{valid_shells.join(', ')}", 1) + end + end + end + end + + + + desc 'Search bookmarks' + long_desc %{ +Search bookmark urls and names for a string and output in specified format (default "paths"). + +Run `hook find` with no search argument to list all bookmarks.} + arg_name 'SEARCH_STRING' + command %i[find search] do |c| + c.desc 'Output only bookmarks with file paths (exclude e.g. emails)' + c.switch %i[f files_only], { negatable: false, default_value: false } + + c.desc 'Separate results with NULL separator, only applies with "paths" output for single file argument' + c.switch %i[null], { negatable: false, default_value: false } + + valid_formats = %w[hooks paths markdown verbose] + fmt_list = valid_formats.map { |fmt| fmt.sub(/^(.)(.*?)$/, '(\1)\2') }.join(', ') + + c.desc "Output format [#{fmt_list}]" + c.flag %i[o output_format], { arg_name: 'format', default_value: 'paths' } + + c.desc "Search only bookmark names" + c.switch %i[n names_only], { negatable: false, default_value: false } + + c.action do |_global_options, options, args| + valid_format = hooker.validate_format(options[:o], valid_formats) + exit_now!("Invalid output format: \"#{options[:o]}\"", 6) unless valid_format + + result = hooker.search_bookmarks(args.join(" "), { files_only: options[:f], + format: valid_format, + null_separator: options[:null], + names_only: options[:n] }) + + puts result + end + end + desc 'Create bidirectional hooks between two or more files/urls' + long_desc %{ +If two files/urls are provided, links will be bi-directional. +If three or more are provided, `link` defaults to creating bi-directional +links between each file and the last file in the list. Use `-a` to create +bi-directional links between every file in the list. + +If using `--paste`, the URL/hook link in the clipboard will be used as one argument, +to be combined with one or more file/url arguments. + } arg_name 'SOURCE [SOURCE...] TARGET' command %i[link ln] do |c| c.desc 'Link every listed file or url to every other' c.switch %i[a all], { negatable: false, default_value: false } @@ -57,94 +146,122 @@ clipboard = `pbpaste`.strip clipboard.valid_hook! args.push(clipboard) if clipboard end if args.length < 2 - raise 'At least 2 files must be specified, or one file with --paste' + exit_now!('Wrong number of arguments. At least 2 files must be specified, or one file with --paste', 5) end if options[:a] puts hooker.link_all(args) else puts hooker.link_files(args) end end end desc 'Copy Hook URL for file/url to clipboard' + long_desc %{ +Creates a bookmark for the specified file or URL and copies its Hook URL to the clipboard. + +The copied Hook URL can be used to link to other files (use `hook link --paste FILE/URL), +or to paste into another app as a link. Use the -m flag to copy a full Markdown link. + } arg_name 'FILE_OR_URL' command %i[clip cp] do |c| c.desc 'Copy as Markdown' c.switch %i[m markdown], { negatable: false, default_value: false } c.desc 'Copy from application' c.flag %i[a app], { arg_name: 'APP_NAME' } c.action do |_global_options, options, args| - raise 'Wrong number of arguments. Requires a path/url or -a APP_NAME' if args.length != 1 && !options[:a] + exit_now!('Wrong number of arguments. Requires a path/url or -a APP_NAME', 5) if args.length != 1 && !options[:a] if options[:a] puts hooker.bookmark_from_app(options[:a], { copy: true, markdown: options[:m] }) else puts hooker.clip_bookmark(args[0], { markdown: options[:m] }) end end end desc 'Get a Hook URL for the frontmost window of an app' + long_desc %{ +Specify an application by name (without '.app') to bring that app to the foreground and create a bookmark +for the active document, note, task, etc., returning a Hook URL. + +Use -m to get the response as Markdown, and/or -c to copy the result directly to the clipboard. + } arg_name 'APPLICATION_NAME' command %i[from] do |c| c.desc 'Output as Markdown' c.switch %i[m markdown], { negatable: false, default_value: false } c.desc 'Copy to clipboard' c.switch %i[c copy], { negatable: false, default_value: false } c.action do |_global_options, options, args| - raise "Wrong number of arguments (1 expected, #{args.length} given)" if args.length != 1 + exit_now!("Wrong number of arguments (1 expected, #{args.length} given)", 5) if args.length != 1 puts hooker.bookmark_from_app(args[0], { copy: options[:c], markdown: options[:m] }) end end desc 'Remove a hook between two files/urls' + long_desc %{ +Remove a hook between two files or URLs. If you use --all, all hooks on a given file will be removed. + +If --all isn't specified, exactly two arguments (Files/URLs) are required. + } arg_name 'ITEM_1 ITEM_2' command %i[remove rm] do |c| c.desc 'Remove ALL links on files, requires confirmation' - c.switch %i[a all] + c.switch %i[a all], { negatable: false, default_value: false } c.action do |_global_options, options, args| - result = hooker.delete_hooks(args, { all: options[:r] }) + result = hooker.delete_hooks(args, { all: options[:a] }) puts result end end desc 'Clone all hooks from one file or url onto another' + long_desc %{ +Copy all the files and urls that the first file is hooked to onto another file. Exactly two arguments (SOURCE, TARGET) required. + } arg_name 'SOURCE TARGET' command %i[clone] do |c| c.action do |_global_options, _options, args| - raise "Wrong number of arguments. Two file paths or urls required (#{args.length} given)" if args.length != 2 + exit_now!("Wrong number of arguments. Two file paths or urls required (#{args.length} given)", 5) if args.length != 2 result = hooker.clone_hooks(args) puts result end end desc 'Select from hooks on a file/url and open in default application' + long_desc %{ +If the target file/URL has hooked items, a menu will be provided. Selecting one or more files +from this menu will open the item(s) using the default application assigned to the +filetype by macOS. Allows multiple selections with tab key, and type-ahead fuzzy filtering of results. +} arg_name 'FILE_OR_URL' command %i[select] do |c| c.action do |_global_options, _options, args| - raise "Wrong number of arguments. One file path or url required (#{args.length} given)" if args.length != 1 + exit_now!("Wrong number of arguments. One file path or url required (#{args.length} given)", 5) if args.length != 1 hooker.open_linked(args[0]) end end desc 'Open the specified file or url in Hook GUI' + long_desc %{ +Opens Hook.app on the specified file/URL for browsing and performing actions. Exactly one argument (File/URL) required. + } arg_name 'FILE_OR_URL' command %i[open gui] do |c| c.action do |_global_options, _options, args| - raise "Wrong number of arguments. One file path or url required (#{args.length} given)" if args.length != 1 + exit_now!("Wrong number of arguments. One file path or url required (#{args.length} given)", 5) if args.length != 1 hooker.open_gui(args[0]) end end @@ -152,10 +269,10 @@ # Pre logic here # Return true to proceed; false to abort and not call the # chosen command # Use skips_pre before a command to skip this block # on that command only - hooker = Hooker.new(global) + hooker = Hooker.new true end post do |_global, _command, _options, _args| # Post logic here