Module: SyntaxTree::CLI

Defined in:
lib/syntax_tree/cli.rb

Overview

Syntax Tree ships with the ‘stree` CLI, which can be used to inspect and manipulate Ruby code. This module is responsible for powering that CLI.

Defined Under Namespace

Classes: AST, Action, CTags, Check, Color, ConfigFile, Debug, Doc, Expr, FileItem, Format, Json, Match, Options, STDINItem, ScriptItem, Search, Write

Constant Summary collapse

HELP =

The help message displayed if the input arguments are not correctly ordered or formatted.

"\#{Color.bold(\"stree ast [--plugins=...] [--print-width=NUMBER] [-e SCRIPT] FILE\")}\n  Print out the AST corresponding to the given files\n\n\#{Color.bold(\"stree check [--plugins=...] [--print-width=NUMBER] [-e SCRIPT] FILE\")}\n  Check that the given files are formatted as syntax tree would format them\n\n\#{Color.bold(\"stree ctags [-e SCRIPT] FILE\")}\n  Print out a ctags-compatible index of the given files\n\n\#{Color.bold(\"stree debug [--plugins=...] [--print-width=NUMBER] [-e SCRIPT] FILE\")}\n  Check that the given files can be formatted idempotently\n\n\#{Color.bold(\"stree doc [--plugins=...] [-e SCRIPT] FILE\")}\n  Print out the doc tree that would be used to format the given files\n\n\#{Color.bold(\"stree expr [-e SCRIPT] FILE\")}\n  Print out a pattern-matching Ruby expression that would match the first\n  expression of the given files\n\n\#{Color.bold(\"stree format [--plugins=...] [--print-width=NUMBER] [-e SCRIPT] FILE\")}\n  Print out the formatted version of the given files\n\n\#{Color.bold(\"stree json [--plugins=...] [-e SCRIPT] FILE\")}\n  Print out the JSON representation of the given files\n\n\#{Color.bold(\"stree match [--plugins=...] [-e SCRIPT] FILE\")}\n  Print out a pattern-matching Ruby expression that would match the given files\n\n\#{Color.bold(\"stree help\")}\n  Display this help message\n\n\#{Color.bold(\"stree lsp [--plugins=...] [--print-width=NUMBER]\")}\n  Run syntax tree in language server mode\n\n\#{Color.bold(\"stree search PATTERN [-e SCRIPT] FILE\")}\n  Search for the given pattern in the given files\n\n\#{Color.bold(\"stree version\")}\n  Output the current version of syntax tree\n\n\#{Color.bold(\"stree write [--plugins=...] [--print-width=NUMBER] [-e SCRIPT] FILE\")}\n  Read, format, and write back the source of the given files\n\n--ignore-files=...\n  A glob pattern to ignore files when processing. This can be specified\n  multiple times to ignore multiple patterns.\n\n--plugins=...\n  A comma-separated list of plugins to load.\n\n--print-width=...\n  The maximum line width to use when formatting.\n\n-e ...\n  Parse an inline string.\n\n--extension=...\n  A file extension matching the content passed in via STDIN or -e.\n  Defaults to '.rb'.\n\n--config=...\n  Path to a configuration file. Defaults to .streerc in the current\n  working directory.\n"

Class Method Summary collapse

Class Method Details

.run(argv) ⇒ Object

Run the CLI over the given array of strings that make up the arguments passed to the invocation.



599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
# File 'lib/syntax_tree/cli.rb', line 599

def run(argv)
  name, *arguments = argv

  # First, we need to check if there's a --config option specified
  # so we can use the custom config file path.
  config_filepath = nil
  arguments.each_with_index do |arg, index|
    if arg.start_with?("--config=")
      config_filepath = arg.split("=", 2)[1]
      arguments.delete_at(index)
      break
    elsif arg == "--config" && arguments[index + 1]
      config_filepath = arguments[index + 1]
      arguments.delete_at(index + 1)
      arguments.delete_at(index)
      break
    end
  end

  config_file = ConfigFile.new(config_filepath)
  arguments = config_file.arguments.concat(arguments)

  options = Options.new
  options.parse(arguments)

  action =
    case name
    when "a", "ast"
      AST.new(options)
    when "c", "check"
      Check.new(options)
    when "ctags"
      CTags.new(options)
    when "debug"
      Debug.new(options)
    when "doc"
      Doc.new(options)
    when "e", "expr"
      Expr.new(options)
    when "f", "format"
      Format.new(options)
    when "help"
      puts HELP
      return 0
    when "j", "json"
      Json.new(options)
    when "lsp"
      LanguageServer.new(
        print_width: options.print_width,
        ignore_files: options.ignore_files
      ).run
      return 0
    when "m", "match"
      Match.new(options)
    when "s", "search"
      Search.new(arguments.shift)
    when "version"
      puts SyntaxTree::VERSION
      return 0
    when "w", "write"
      Write.new(options)
    else
      warn(HELP)
      return 1
    end

  # We're going to build up a queue of items to process.
  queue = Queue.new

  # If there are any arguments or scripts, then we'll add those to the
  # queue. Otherwise we'll read the content off STDIN.
  if arguments.any? || options.scripts.any?
    arguments.each do |pattern|
      Dir
        .glob(pattern)
        .each do |filepath|
          # Skip past invalid filepaths by default.
          next unless File.readable?(filepath)

          # Skip past any ignored filepaths.
          next if options.ignore_files.any? { File.fnmatch(_1, filepath) }

          # Otherwise, a new file item for the given filepath to the list.
          queue << FileItem.new(filepath)
        end
    end

    options.scripts.each do |script|
      queue << ScriptItem.new(script, options.extension)
    end
  else
    queue << STDINItem.new(options.extension)
  end

  # At the end, we're going to return whether or not this worker ever
  # encountered an error.
  if process_queue(queue, action)
    action.failure
    1
  else
    action.success
    0
  end
end