2 * Copyright (c) 2015, Facebook, Inc.
5 * This source code is licensed under the MIT license found in the
6 * LICENSE file in the "hack" directory of this source tree.
14 (** Arg specs shared across more than 1 arg parser. *)
15 module Common_argspecs
= struct
16 let config value_ref
=
19 (fun s
-> value_ref
:= String_utils.split2_exn '
=' s
:: !value_ref
),
20 " override arbitrary value from hh.conf and .hhconfig (format: <key>=<value>)"
23 let force_dormant_start value_ref
=
24 ( "--force-dormant-start",
25 Arg.Bool
(fun x
-> value_ref
:= x
),
26 " If server is dormant, force start a new one instead of waiting for"
27 ^
" the next one to start up automatically (default: false)" )
31 Arg.Set_string value_ref
,
32 " so we know who's calling hh_client - e.g. nuclide, vim, emacs, vscode"
35 let no_prechecked value_ref
=
37 Arg.Unit
(fun () -> value_ref
:= Some
false),
38 " override value of \"prechecked_files\" flag from hh.conf" )
40 let prechecked value_ref
=
42 Arg.Unit
(fun () -> value_ref
:= Some
true),
43 " override value of \"prechecked_files\" flag from hh.conf" )
45 let watchman_debug_logging value_ref
=
46 ( "--watchman-debug-logging",
48 " Enable debug logging on Watchman client. This is very noisy" )
50 let allow_non_opt_build value_ref
=
51 ( "--allow-non-opt-build",
53 " Override build mode check triggered by warn_on_non_opt_build .hhconfig option"
57 let parse_command () =
58 if Array.length
Sys.argv
< 2 then
61 match String.lowercase
Sys.argv
.(1) with
65 | "restart" -> CKRestart
68 | "download-saved-state" -> CKDownloadSavedState
72 let parse_without_command options usage command
=
74 Arg.parse
(Arg.align options
) (fun x
-> args := x
:: !args) usage
;
75 match List.rev
!args with
76 | x
:: rest
when String.(lowercase x
= lowercase command
) -> rest
79 (* *** *** NB *** *** ***
80 * Commonly-used options are documented in hphp/hack/man/hh_client.1 --
81 * if you are making significant changes you need to update the manpage as
82 * well. Experimental or otherwise volatile options need not be documented
83 * there, but keep what's there up to date please. *)
84 let parse_check_args cmd
=
85 (* arg parse output refs *)
86 let ai_mode = ref None
in
87 let autostart = ref true in
88 let config = ref [] in
89 let dynamic_view = ref false in
90 let error_format = ref Errors.Context
in
91 let force_dormant_start = ref false in
92 let format_from = ref 0 in
94 let hot_classes_threshold = ref 0 in
95 let gen_saved_ignore_type_errors = ref false in
96 let ignore_hh_version = ref false in
97 let saved_state_ignore_hhconfig = ref false in
98 let log_inference_constraints = ref false in
99 let max_errors = ref None
in
100 let mode = ref None
in
101 let logname = ref false in
102 let monitor_logname = ref false in
103 let client_logname = ref false in
104 let ide_logname = ref false in
105 let lsp_logname = ref false in
106 let no_load = ref false in
107 let output_json = ref false in
108 let prechecked = ref None
in
109 let profile_log = ref false in
110 let refactor_before = ref "" in
111 let refactor_mode = ref "" in
112 let remote = ref false in
113 let replace_state_after_saving = ref false in
114 let sort_results = ref false in
115 let timeout = ref None
in
116 let version = ref false in
117 let watchman_debug_logging = ref false in
118 let allow_non_opt_build = ref false in
119 (* custom behaviors *)
120 let set_from x
() = from := x
in
122 if Option.is_some
!mode then
123 raise
(Arg.Bad
"only a single mode should be specified")
132 "Usage: %s check [OPTION]... [WWW-ROOT]\n\nWWW-ROOT is assumed to be current directory if unspecified\n"
136 ( "Usage: %s [COMMAND] [OPTION]... [WWW-ROOT]\n\nValid values for COMMAND:\n"
137 ^^
"\tcheck\t\tShows current Hack errors\n"
138 ^^
"\tstart\t\tStarts a Hack server\n"
139 ^^
"\tstop\t\tStops a Hack server\n"
140 ^^
"\trestart\t\tRestarts a Hack server\n"
141 ^^
"\tlsp\t\tRuns a persistent language service\n"
142 ^^
"\tdebug\t\tDebug mode\n"
143 ^^
"\trage\t\tReport a bug\n"
144 ^^
"\nDefault values if unspecified:\n"
145 ^^
"\tCOMMAND\t\tcheck\n"
146 ^^
"\tWWW-ROOT\tCurrent directory\n\nCheck command options:\n" )
148 | _
-> failwith
"No other keywords should make it here"
152 (* Please keep these sorted in the alphabetical order *)
158 ( ignore
(Ai_options.prepare ~server
:true s
);
160 " run AI module with provided options" );
162 Arg.String
(fun x
-> set_mode (MODE_AI_QUERY x
) ()),
163 (* Send an AI query *) "" );
164 Common_argspecs.allow_non_opt_build allow_non_opt_build;
166 Arg.Unit
(set_mode MODE_AUTO_COMPLETE
),
167 " (mode) auto-completes the text on stdin" );
168 ( "--autostart-server",
169 Arg.Bool
(fun x
-> autostart := x
),
170 " automatically start hh_server if it's not running (default: true)" );
172 Arg.String
(fun filename
-> set_mode (MODE_BIGCODE filename
) ()),
173 " (mode) source code indexing functionalities for Big Code analysis" );
175 Arg.String
(fun x
-> set_mode (MODE_COLORING x
) ()),
176 " (mode) pretty prints the file content showing what is checked (give '-' for stdin)"
178 ("--colour", Arg.String
(fun x
-> set_mode (MODE_COLORING x
) ()), " ");
179 Common_argspecs.config config;
181 Arg.String
(fun x
-> set_mode (MODE_COVERAGE x
) ()),
182 " (mode) calculates the extent of typing of a given file or directory"
184 ( "--create-checkpoint",
185 Arg.String
(fun x
-> set_mode (MODE_CREATE_CHECKPOINT x
) ()),
186 (* Create a checkpoint which can be used to retrieve changed files later *)
189 Arg.Unit
(set_mode (MODE_CST_SEARCH None
)),
190 " (mode) Search the concrete syntax trees of files in the codebase"
191 ^
" for a given pattern" );
192 ( "--cst-search-files",
199 | Some
(MODE_CST_SEARCH None
) ->
200 Some
(MODE_CST_SEARCH
(Some
[fn
]))
201 | Some
(MODE_CST_SEARCH
(Some fnl
)) ->
202 Some
(MODE_CST_SEARCH
(Some
(fn
:: fnl
)))
203 | _
-> raise
(Arg.Bad
"only a single mode should be specified")
205 " Run CST search on this set of files,"
206 ^
" rather than all the files in the codebase." );
207 (* Delete an existing checkpoint.
208 * Exitcode will be non-zero if no checkpoint is found *)
209 ( "--delete-checkpoint",
210 Arg.String
(fun x
-> set_mode (MODE_DELETE_CHECKPOINT x
) ()),
212 ( "--dump-full-fidelity-parse",
213 Arg.String
(fun x
-> set_mode (MODE_FULL_FIDELITY_PARSE x
) ()),
215 ( "--dump-symbol-info",
216 Arg.String
(fun files
-> set_mode (MODE_DUMP_SYMBOL_INFO files
) ()),
218 * The file list can either be "-" which accepts the input from stdin
219 * separated by newline(for long list) or directly from command line
220 * separated by semicolon.
223 * "function_calls": list of fun_calls;
225 * Note: results list can be in any order *)
228 Arg.Set
dynamic_view,
229 " Replace occurrences of untyped code with dynamic" );
234 | "raw" -> error_format := Errors.Raw
235 | "context" -> error_format := Errors.Context
236 | _
-> print_string
"Warning: unrecognized error format.\n"),
237 "<raw|context> Error formatting style" );
238 ( "--extract-standalone",
239 Arg.String
(fun name
-> set_mode (MODE_EXTRACT_STANDALONE name
) ()),
240 " extract a given function / method together with its dependencies as a standalone file"
242 ( "--concatenate-all",
243 Arg.Unit
(fun () -> set_mode MODE_CONCATENATE_ALL
()),
244 "(mode) create a single file containing all Hack code in the specified prefix"
246 ( "--file-dependents",
249 let () = prechecked := Some
false in
250 set_mode MODE_FILE_DEPENDENTS
()),
251 " (mode) Given a list of filepaths, shows list of (possibly) dependent files"
253 ( "--find-class-refs",
254 Arg.String
(fun x
-> set_mode (MODE_FIND_CLASS_REFS x
) ()),
255 " (mode) finds references of the provided class name" );
257 Arg.String
(fun x
-> set_mode (MODE_FIND_REFS x
) ()),
258 " (mode) finds references of the provided method name" );
259 Common_argspecs.force_dormant_start force_dormant_start;
263 Arg.Int
(fun x
-> format_from := x
);
264 Arg.Int
(fun x
-> set_mode (MODE_FORMAT
(!format_from, x
)) ());
267 Common_argspecs.from from;
269 Arg.Unit
(set_from "arc_diff"),
270 " (deprecated) equivalent to --from arc_diff" );
272 Arg.Unit
(set_from "arc_land"),
273 " (deprecated) equivalent to --from arc_land" );
274 ( "--from-check-trunk",
275 Arg.Unit
(set_from "check_trunk"),
276 " (deprecated) equivalent to --from check_trunk" );
278 Arg.Unit
(set_from "emacs"),
279 " (deprecated) equivalent to --from emacs" );
281 Arg.Unit
(fun () -> from := "vim"),
282 " (deprecated) equivalent to --from vim" );
283 ( "--full-fidelity-schema",
284 Arg.Unit
(set_mode MODE_FULL_FIDELITY_SCHEMA
),
286 ( "--fun-deps-at-pos-batch",
292 | None
-> Some
(MODE_FUN_DEPS_AT_POS_BATCH
[position
])
293 | Some
(MODE_FUN_DEPS_AT_POS_BATCH positions
) ->
294 Some
(MODE_FUN_DEPS_AT_POS_BATCH
(position
:: positions
))
295 | _
-> raise
(Arg.Bad
"only a single mode should be specified")
297 " (mode) for each entry in input list get list of function dependencies [file:line:character list]"
299 ( "--fun-is-locallable-at-pos-batch",
305 | None
-> Some
(MODE_FUN_IS_LOCALLABLE_AT_POS_BATCH
[position
])
306 | Some
(MODE_FUN_IS_LOCALLABLE_AT_POS_BATCH positions
) ->
308 (MODE_FUN_IS_LOCALLABLE_AT_POS_BATCH
(position
:: positions
))
309 | _
-> raise
(Arg.Bad
"only a single mode should be specified")
311 " (mode) for each entry in input list checks if function at position can be made RxLocal [file:line:character list]"
313 ( "--gen-hot-classes-file",
316 Arg.Int
(fun x
-> hot_classes_threshold := x
);
319 set_mode (MODE_GEN_HOT_CLASSES
(!hot_classes_threshold, x
)) ());
321 " generate a JSON file listing all classes with more dependents than the"
322 ^
" given threshold. Usage: --gen-hot-classes-file 500 ~/hh_hot_classes.json"
324 ( "--gen-saved-ignore-type-errors",
325 Arg.Set
gen_saved_ignore_type_errors,
326 " generate a saved state even if there are type errors (default: false)."
328 ( "--get-method-name",
329 Arg.String
(fun x
-> set_mode (MODE_IDENTIFY_SYMBOL3 x
) ()),
330 (* alias for --identify-function *) "" );
331 ( "--go-to-impl-class",
332 Arg.String
(fun x
-> set_mode (MODE_GO_TO_IMPL_CLASS x
) ()),
333 " (mode) goes to implementation of the provided class/trait/interface/etc. with the given name"
335 ( "--go-to-impl-class-remote",
336 Arg.String
(fun x
-> set_mode (MODE_GO_TO_IMPL_CLASS_REMOTE x
) ()),
337 " (mode) similar to go-to-class-impl, but uses a glean database for faster but potentially out-of-date results"
339 ( "--go-to-impl-method",
340 Arg.String
(fun x
-> set_mode (MODE_GO_TO_IMPL_METHOD x
) ()),
341 " (mode) goes to implementation of the provided method name" );
343 Arg.String
(fun x
-> set_mode (MODE_IDE_FIND_REFS x
) ()),
345 ( "--ide-get-definition",
346 Arg.String
(fun x
-> set_mode (MODE_IDENTIFY_SYMBOL2 x
) ()),
347 (* alias for --identify-function *) "" );
348 ( "--ide-highlight-refs",
349 Arg.String
(fun x
-> set_mode (MODE_IDE_HIGHLIGHT_REFS x
) ()),
350 (* Similar to --ide-find-refs, but returns references in current file only,
351 * and is optimized to be faster in that case *)
353 ( "--global-inference",
362 - "merge" will gather all artifacts generated by typechecking with
363 global inference on and generate the global constraint graph
364 - "solve" will solve the global constraint graph and bind all
365 global type variable to a concrete type
366 - "export-json" will export the global constraint graph in a
369 | "merge" -> ServerGlobalInferenceTypes.MMerge
370 | "solve" -> ServerGlobalInferenceTypes.MSolve
371 | "export-json" -> ServerGlobalInferenceTypes.MExport
372 | "rewrite" -> ServerGlobalInferenceTypes.MRewrite
376 ("No " ^ fn ^
" submode supported for global inference"))
378 Some
(MODE_GLOBAL_INFERENCE
(submode, []))
379 | Some
(MODE_GLOBAL_INFERENCE
(submode, fnl
)) ->
380 Some
(MODE_GLOBAL_INFERENCE
(submode, fn
:: fnl
))
381 | _
-> raise
(Arg.Bad
"only a single mode should be specified")
383 " (mode) global inference operations, Usage: --global-inference "
384 ^
"[\"merge\", \"solve\", \"export-json\", \"rewrite\"] files..." );
385 ("--ide-outline", Arg.Unit
(set_mode MODE_OUTLINE2
), "");
387 Arg.String
(fun x
-> set_mode (MODE_IDE_REFACTOR x
) ()),
388 " (mode) rename a symbol, Usage: --ide-refactor "
389 ^
" <filename>:<line number>:<col number>:<new name>" );
390 ( "--identify-function",
391 Arg.String
(fun x
-> set_mode (MODE_IDENTIFY_SYMBOL1 x
) ()),
392 " (mode) print the full function name at the position "
393 ^
"[line:character] of the text on stdin" );
395 Arg.String
(fun x
-> set_mode (MODE_IDENTIFY_SYMBOL x
) ()),
396 " (mode) identify the named symbol" );
397 ( "--ignore-hh-version",
398 Arg.Set
ignore_hh_version,
399 " ignore hh_version check when loading saved states (default: false)" );
400 ( "--in-memory-dep-table-size",
401 Arg.Unit
(set_mode MODE_IN_MEMORY_DEP_TABLE_SIZE
),
402 " number of entries in the in-memory dependency table" );
403 ( "--inheritance-ancestor-classes",
405 (fun x
-> set_mode (MODE_METHOD_JUMP_ANCESTORS
(x
, "Class")) ()),
406 " (mode) prints a list of classes that this class extends" );
407 ( "--inheritance-ancestor-classes-batch",
414 Some
(MODE_METHOD_JUMP_ANCESTORS_BATCH
([class_
], "Class"))
415 | Some
(MODE_METHOD_JUMP_ANCESTORS_BATCH
(classes
, "Class")) ->
417 (MODE_METHOD_JUMP_ANCESTORS_BATCH
(class_
:: classes
, "Class"))
418 | _
-> raise
(Arg.Bad
"only a single mode should be specified")
420 " (mode) prints a list of classes that these classes extend" );
421 ( "--inheritance-ancestor-interfaces",
423 (fun x
-> set_mode (MODE_METHOD_JUMP_ANCESTORS
(x
, "Interface")) ()),
424 " (mode) prints a list of interfaces that this class implements" );
425 ( "--inheritance-ancestor-interfaces-batch",
432 Some
(MODE_METHOD_JUMP_ANCESTORS_BATCH
([class_
], "Interface"))
433 | Some
(MODE_METHOD_JUMP_ANCESTORS_BATCH
(classes
, "Interface"))
436 (MODE_METHOD_JUMP_ANCESTORS_BATCH
437 (class_
:: classes
, "Interface"))
438 | _
-> raise
(Arg.Bad
"only a single mode should be specified")
440 " (mode) prints a list of interfaces that these classes implement" );
441 ( "--inheritance-ancestor-traits",
443 (fun x
-> set_mode (MODE_METHOD_JUMP_ANCESTORS
(x
, "Trait")) ()),
444 " (mode) prints a list of traits that this class uses" );
445 ( "--inheritance-ancestor-traits-batch",
452 Some
(MODE_METHOD_JUMP_ANCESTORS_BATCH
([class_
], "Trait"))
453 | Some
(MODE_METHOD_JUMP_ANCESTORS_BATCH
(classes
, "Trait")) ->
455 (MODE_METHOD_JUMP_ANCESTORS_BATCH
(class_
:: classes
, "Trait"))
456 | _
-> raise
(Arg.Bad
"only a single mode should be specified")
458 " (mode) prints a list of traits that these classes use" );
459 ( "--inheritance-ancestors",
461 (fun x
-> set_mode (MODE_METHOD_JUMP_ANCESTORS
(x
, "No_filter")) ()),
462 " (mode) prints a list of all related classes or methods"
463 ^
" to the given class" );
464 ( "--inheritance-children",
465 Arg.String
(fun x
-> set_mode (MODE_METHOD_JUMP_CHILDREN x
) ()),
466 " (mode) prints a list of all related classes or methods"
467 ^
" to the given class" );
470 " output json for machine consumption. (default: false)" );
472 Arg.Unit
(set_mode MODE_LINT
),
473 " (mode) lint the given list of files" );
475 Arg.Int
(fun x
-> set_mode (MODE_LINT_ALL x
) ()),
476 " (mode) find all occurrences of lint with the given error code" );
478 Arg.String
(fun filename
-> set_mode (MODE_LINT_STDIN filename
) ()),
479 " (mode) lint a file given on stdin; the filename should be the"
480 ^
" argument to this option" );
481 ( "--lint-xcontroller",
483 (fun filename
-> set_mode (MODE_LINT_XCONTROLLER filename
) ()),
485 (* (mode) lint all xcontrollers in files listed in given file (i.e. the argument is
486 * a path to a file that contains a list of files) *);
488 Arg.Unit
(set_mode MODE_LIST_FILES
),
489 " (mode) list files with errors" );
490 ( "--log-inference-constraints",
491 Arg.Set
log_inference_constraints,
492 " (for hh debugging purpose only) log type"
493 ^
" inference constraints into external logger (e.g. Scuba)" );
495 Arg.Int
(fun num_errors
-> max_errors := Some num_errors
),
496 " Maximum number of errors to display" );
497 ("--logname", Arg.Set
logname, " (mode) show log filename and exit");
498 ( "--monitor-logname",
499 Arg.Set
monitor_logname,
500 " (mode) show monitor log filename and exit" );
501 ( "--client-logname",
502 Arg.Set
client_logname,
503 " (mode) show client log filename and exit" );
506 " (mode) show client ide log filename and exit" );
509 " (mode) show client lsp log filename and exit" );
510 ("--no-load", Arg.Set
no_load, " start from a fresh state");
512 Arg.Unit
(set_mode MODE_OUTLINE
),
513 " (mode) prints an outline of the text on stdin" );
514 Common_argspecs.prechecked prechecked;
515 Common_argspecs.no_prechecked prechecked;
517 Arg.Unit
(set_mode (MODE_PAUSE
true)),
518 " (mode) pause recheck-on-file-change [EXPERIMENTAL]" );
519 ("--profile-log", Arg.Set
profile_log, " enable profile logging");
524 (["Class"; "Function"; "Method"], (fun x
-> refactor_mode := x
));
525 Arg.String
(fun x
-> refactor_before := x
);
529 (MODE_REFACTOR
(!refactor_mode, !refactor_before, x
))
532 " (mode) rename a symbol, Usage: --refactor "
533 ^
"[\"Class\", \"Function\", \"Method\"] <Current Name> <New Name>" );
534 ("--remote", Arg.Set
remote, " force remote type checking");
535 ( "--remove-dead-fixme",
541 | None
-> Some
(MODE_REMOVE_DEAD_FIXMES
[code
])
542 | Some
(MODE_REMOVE_DEAD_FIXMES codel
) ->
543 Some
(MODE_REMOVE_DEAD_FIXMES
(code
:: codel
))
544 | _
-> raise
(Arg.Bad
"only a single mode should be specified")
546 " (mode) remove dead HH_FIXME for specified error code "
547 ^
"(first do hh_client restart --no-load)" );
548 ( "--remove-dead-fixmes",
549 Arg.Unit
(set_mode (MODE_REMOVE_DEAD_FIXMES
[])),
550 " (mode) remove dead HH_FIXME for any error code < 5000 "
551 ^
"(first do hh_client restart --no-load)" );
552 ( "--replace-state-after-saving",
553 Arg.Set
replace_state_after_saving,
554 " if combined with --save-mini, causes the saved state"
555 ^
" to replace the program state; otherwise, the state files are not"
556 ^
" used after being written to disk (default: false)" );
558 Arg.Unit
(set_mode (MODE_PAUSE
false)),
559 " (mode) resume recheck-on-file-change [EXPERIMENTAL]" );
561 Arg.Int
(fun n
-> timeout := Some
(float_of_int
(max
5 n
))),
562 " (deprecated) same as --timeout" );
563 (* Retrieve changed files since input checkpoint.
564 * Output is separated by newline.
565 * Exit code will be non-zero if no checkpoint is found *)
566 ( "--retrieve-checkpoint",
567 Arg.String
(fun x
-> set_mode (MODE_RETRIEVE_CHECKPOINT x
) ()),
569 ("--retry-if-init", Arg.Bool
(fun _
-> ()), " (deprecated and ignored)");
570 ( "--rewrite-lambda-parameters",
576 | None
-> Some
(MODE_REWRITE_LAMBDA_PARAMETERS
[fn
])
577 | Some
(MODE_REWRITE_LAMBDA_PARAMETERS fnl
) ->
578 Some
(MODE_REWRITE_LAMBDA_PARAMETERS
(fn
:: fnl
))
579 | _
-> raise
(Arg.Bad
"only a single mode should be specified")
581 " (mode) rewrite lambdas in the files from the given list"
582 ^
" with suggested parameter types" );
583 ( "--rewrite-partial-parameters-type-hints",
589 | None
-> Some
(MODE_REWRITE_TYPE_PARAMS_TYPE
[fn
])
590 | Some
(MODE_REWRITE_TYPE_PARAMS_TYPE fnl
) ->
591 Some
(MODE_REWRITE_TYPE_PARAMS_TYPE
(fn
:: fnl
))
592 | _
-> raise
(Arg.Bad
"only a single mode should be specified")
594 " (mode) add missing type parameters in the type hints for function"
595 ^
" parameters (e.g.: C $x -> C<int> $x) in the files from the given list"
598 Arg.String
(fun x
-> set_mode (MODE_SAVE_NAMING x
) ()),
599 " (mode) Save the naming table to the given file."
600 ^
" Returns the number of files and symbols written to disk." );
602 Arg.String
(fun x
-> set_mode (MODE_SAVE_STATE x
) ()),
603 " (mode) Save a saved state to the given file."
604 ^
" Returns number of edges dumped from memory to the database." );
605 ( "--saved-state-ignore-hhconfig",
606 Arg.Set
saved_state_ignore_hhconfig,
607 " ignore hhconfig hash when loading saved states (default: false)" );
609 Arg.String
(fun x
-> set_mode (MODE_SEARCH
(x
, "")) ()),
610 " (mode) fuzzy search symbol definitions" );
612 Arg.String
(fun x
-> set_mode (MODE_SEARCH
(x
, "class")) ()),
613 " (mode) fuzzy search class definitions" );
614 ( "--search-constant",
615 Arg.String
(fun x
-> set_mode (MODE_SEARCH
(x
, "constant")) ()),
616 " (mode) fuzzy search constant definitions" );
617 ( "--search-function",
618 Arg.String
(fun x
-> set_mode (MODE_SEARCH
(x
, "function")) ()),
619 " (mode) fuzzy search function definitions" );
620 ( "--search-typedef",
621 Arg.String
(fun x
-> set_mode (MODE_SEARCH
(x
, "typedef")) ()),
622 " (mode) fuzzy search typedef definitions" );
624 Arg.Unit
(set_mode MODE_SERVER_RAGE
),
625 " (mode) dumps internal state of hh_server" );
627 Arg.String
(fun x
-> set_mode (MODE_STATUS_SINGLE x
) ()),
628 "<path> Return errors in file with provided name (give '-' for stdin)"
630 ("--sort-results", Arg.Set
sort_results, " sort output for CST search.");
632 Arg.Unit
(set_mode MODE_STATS
),
633 " display some server statistics" );
635 Arg.Unit
(set_mode MODE_STATUS
),
636 " (mode) show a human readable list of errors (default)" );
638 Arg.Float
(fun x
-> timeout := Some
(Float.max
5. x
)),
639 " set the timeout in seconds (default: no timeout)" );
641 Arg.String
(fun x
-> set_mode (MODE_TYPE_AT_POS x
) ()),
642 " (mode) show type at a given position in file [line:character]" );
643 ( "--type-at-pos-batch",
649 | None
-> Some
(MODE_TYPE_AT_POS_BATCH
[position
])
650 | Some
(MODE_TYPE_AT_POS_BATCH positions
) ->
651 Some
(MODE_TYPE_AT_POS_BATCH
(position
:: positions
))
652 | _
-> raise
(Arg.Bad
"only a single mode should be specified")
654 " (mode) show types at multiple positions [file:line:character list]" );
656 Arg.Unit
(fun () -> set_mode (MODE_VERBOSE
true) ()),
657 " (mode) turn on verbose server log" );
659 Arg.Unit
(fun () -> set_mode (MODE_VERBOSE
false) ()),
660 " (mode) turn off verbose server log" );
661 ("--version", Arg.Set
version, " (mode) show version and exit");
662 Common_argspecs.watchman_debug_logging watchman_debug_logging;
663 (* Please keep these sorted in the alphabetical order *)
666 let args = parse_without_command options usage "check" in
669 ServerArgs.print_json_version
()
671 print_endline
Hh_version.version;
675 let mode = Option.value !mode ~default
:MODE_STATUS
in
678 match (mode, args) with
680 | (MODE_CONCATENATE_ALL
, _
)
681 | (MODE_FILE_DEPENDENTS
, _
) ->
682 (Wwwroot.get None
, args)
683 | (_
, []) -> (Wwwroot.get None
, [])
684 | (_
, [x
]) -> (Wwwroot.get
(Some x
), [])
688 "Error: please provide at most one www directory\n%!";
691 if !ide_logname then (
692 let ide_log_link = ServerFiles.client_ide_log root
in
693 Printf.printf
"%s\n%!" ide_log_link;
697 if !lsp_logname then (
698 let lsp_log_link = ServerFiles.client_lsp_log root
in
699 Printf.printf
"%s\n%!" lsp_log_link;
703 if !monitor_logname then (
704 let monitor_log_link = ServerFiles.monitor_log_link root
in
705 Printf.printf
"%s\n%!" monitor_log_link;
709 if !client_logname then (
710 let client_log_link = ServerFiles.client_log root
in
711 Printf.printf
"%s\n%!" client_log_link;
716 let log_link = ServerFiles.log_link root
in
717 Printf.printf
"%s\n%!" log_link;
722 if String.equal
!from "emacs" then
723 Printf.fprintf stdout
"-*- mode: compilation -*-\n%!"
728 autostart = !autostart;
730 dynamic_view = !dynamic_view;
731 error_format = !error_format;
732 force_dormant_start = !force_dormant_start;
734 gen_saved_ignore_type_errors = !gen_saved_ignore_type_errors;
735 ignore_hh_version = !ignore_hh_version;
736 saved_state_ignore_hhconfig = !saved_state_ignore_hhconfig;
738 log_inference_constraints = !log_inference_constraints;
739 max_errors = !max_errors;
745 | MODE_REMOVE_DEAD_FIXMES _
-> true
747 output_json = !output_json;
748 prechecked = !prechecked;
749 profile_log = !profile_log;
751 replace_state_after_saving = !replace_state_after_saving;
753 sort_results = !sort_results;
754 deadline
= Option.map ~f
:(fun t
-> Unix.time
() +. t
) !timeout;
755 watchman_debug_logging = !watchman_debug_logging;
756 allow_non_opt_build = !allow_non_opt_build;
759 let parse_start_env command
=
762 "Usage: %s %s [OPTION]... [WWW-ROOT]\n%s a Hack server\n\nWWW-ROOT is assumed to be current directory if unspecified\n"
765 (String.capitalize command
)
767 let log_inference_constraints = ref false in
768 let no_load = ref false in
769 let watchman_debug_logging = ref false in
770 let profile_log = ref false in
771 let ai_mode = ref None
in
772 let ignore_hh_version = ref false in
773 let saved_state_ignore_hhconfig = ref false in
774 let prechecked = ref None
in
776 let config = ref [] in
777 let allow_non_opt_build = ref false in
778 let wait_deprecation_msg () =
780 "WARNING: --wait is deprecated, does nothing, and will be going away soon!\n%!"
784 (* Please keep these sorted in the alphabetical order *)
785 ("--ai", Arg.String
(fun x
-> ai_mode := Some x
), " run ai with options ");
786 Common_argspecs.allow_non_opt_build allow_non_opt_build;
787 Common_argspecs.config config;
788 Common_argspecs.from from;
789 ( "--ignore-hh-version",
790 Arg.Set
ignore_hh_version,
791 " ignore hh_version check when loading saved states (default: false)" );
792 ( "--log-inference-constraints",
793 Arg.Set
log_inference_constraints,
794 " (for hh debugging purpose only) log type"
795 ^
" inference constraints into external logger (e.g. Scuba)" );
796 ("--no-load", Arg.Set
no_load, " start from a fresh state");
797 Common_argspecs.no_prechecked prechecked;
798 Common_argspecs.prechecked prechecked;
799 ("--profile-log", Arg.Set
profile_log, " enable profile logging");
800 ( "--saved-state-ignore-hhconfig",
801 Arg.Set
saved_state_ignore_hhconfig,
802 " ignore hhconfig hash when loading saved states (default: false)" );
804 Arg.Unit
wait_deprecation_msg,
805 " this flag is deprecated and does nothing!" );
806 Common_argspecs.watchman_debug_logging watchman_debug_logging;
807 (* Please keep these sorted in the alphabetical order *)
810 let args = parse_without_command options usage command
in
813 | [] -> Wwwroot.get None
814 | [x
] -> Wwwroot.get
(Some x
)
818 "Error: please provide at most one www directory\n%!";
822 ClientStart.ai_mode = !ai_mode;
825 dynamic_view = false;
826 exit_on_failure
= true;
828 ignore_hh_version = !ignore_hh_version;
829 saved_state_ignore_hhconfig = !saved_state_ignore_hhconfig;
830 log_inference_constraints = !log_inference_constraints;
832 prechecked = !prechecked;
833 profile_log = !profile_log;
836 watchman_debug_logging = !watchman_debug_logging;
837 allow_non_opt_build = !allow_non_opt_build;
840 let parse_start_args () = CStart
(parse_start_env "start")
842 let parse_restart_args () = CRestart
(parse_start_env "restart")
844 let parse_stop_args () =
847 "Usage: %s stop [OPTION]... [WWW-ROOT]\nStop a hack server\n\nWWW-ROOT is assumed to be current directory if unspecified\n"
851 let options = [Common_argspecs.from from] in
852 let args = parse_without_command options usage "stop" in
855 | [] -> Wwwroot.get None
856 | [x
] -> Wwwroot.get
(Some x
)
860 "Error: please provide at most one www directory\n%!";
863 CStop
{ ClientStop.root; from = !from }
865 let parse_lsp_args ~
(init_id
: string) =
868 "Usage: %s lsp [OPTION]...\nRuns a persistent language service\n"
872 let config = ref [] in
873 let use_ffp_autocomplete = ref false in
874 let use_ranked_autocomplete = ref false in
875 let use_serverless_ide = ref false in
876 let verbose = ref false in
879 (* Please keep these sorted in the alphabetical order *)
880 ("--enhanced-hover", Arg.Unit
(fun () -> ()), " [legacy] no-op");
881 ( "--ffp-autocomplete",
882 Arg.Set
use_ffp_autocomplete,
883 " [experimental] use the full-fidelity parser based autocomplete " );
884 Common_argspecs.from from;
885 Common_argspecs.config config;
886 ( "--ranked-autocomplete",
887 Arg.Set
use_ranked_autocomplete,
888 " [experimental] display ranked autocompletion results" );
889 ( "--serverless-ide",
890 Arg.Set
use_serverless_ide,
891 " [experimental] provide IDE services from hh_client instead of hh_server"
895 " verbose logs to stderr and `hh --ide-logname` and `--lsp-logname`" );
896 (* Please keep these sorted in the alphabetical order *)
899 let args = parse_without_command options usage "lsp" in
904 ClientLsp.from = !from;
906 use_ffp_autocomplete = !use_ffp_autocomplete;
907 use_ranked_autocomplete = !use_ranked_autocomplete;
908 use_serverless_ide = !use_serverless_ide;
913 Printf.printf
"%s\n" usage;
916 let parse_debug_args () =
918 Printf.sprintf
"Usage: %s debug [OPTION]... [WWW-ROOT]\n" Sys.argv
.(0)
921 let options = [Common_argspecs.from from] in
922 let args = parse_without_command options usage "debug" in
925 | [] -> Wwwroot.get None
926 | [x
] -> Wwwroot.get
(Some x
)
928 Printf.printf
"%s\n" usage;
931 CDebug
{ ClientDebug.root; from = !from }
933 let parse_rage_args () =
935 Printf.sprintf
"Usage: %s rage [OPTION]... [WWW-ROOT]\n" Sys.argv
.(0)
938 let desc = ref None
in
939 let rageid = ref None
in
942 Common_argspecs.from from;
943 ("--desc", Arg.String
(fun s
-> desc := Some s
), " description of problem");
945 Arg.String
(fun s
-> rageid := Some s
),
946 " (optional) use this id, and finish even if parent process dies" );
949 let args = parse_without_command options usage "rage" in
952 | [] -> Wwwroot.get None
953 | [x
] -> Wwwroot.get
(Some x
)
955 Printf.printf
"%s\n" usage;
958 (* hh_client normally handles Ctrl+C by printing an exception-stack.
959 But for us, in an interactive prompt, Ctrl+C is an unexceptional way to quit. *)
960 Sys_utils.set_signal
Sys.sigint
Sys.Signal_default
;
967 ( "Sorry that hh isn't working. What's wrong?\n"
968 ^^
"1. hh_server takes ages to initialize\n"
969 ^^
"2. hh is stuck in an infinite loop\n"
970 ^^
"3. hh gives some error message about the monitor\n"
971 ^^
"4. hack says it has an internal typecheck bug and asked me to report it\n"
972 ^^
"5. hack is reporting errors that are clearly incorrect [please elaborate]\n"
973 ^^
"6. I'm not sure how to write my code to avoid these hack errors\n"
974 ^^
"7. hh says something about unsaved changes from an editor even after I've quit my editor\n"
975 ^^
"8. something's wrong with hack VS Code or other editor\n"
976 ^^
"[other] Please type either one of the above numbers, or a freeform description\n"
978 let response = In_channel.input_line_exn
In_channel.stdin
in
979 let (response, info
) =
980 if String.equal
response "1" then
981 ("hh_server slow initialize", `Verbose_hh_start
)
982 else if String.equal
response "2" then
983 ("hh stuck in infinite loop", `Verbose_hh_start
)
984 else if String.equal
response "3" then
985 ("hh monitor problem", `Verbose_hh_start
)
986 else if String.equal
response "4" then
987 ("internal typecheck bug", `No_info
)
988 else if String.equal
response "5" then
991 "Please elaborate on which errors are incorrect...\nrage> %!"
993 (In_channel.input_line_exn
In_channel.stdin
, `No_info
)
994 else if String.equal
response "6" then
997 ( "Please ask in the appropriate support groups for advice on coding in Hack; "
998 ^^
"`hh rage` is solely for reporting bugs in the tooling, not for reporting typechecker or "
999 ^^
"language issues." )
1002 else if String.equal
response "7" then
1003 ("unsaved editor changes", `Unsaved
)
1004 else if String.equal
response "8" then
1007 ( "Please file the bug from within your editor to capture the right logs. "
1008 ^^
"Note: you can do Preferences > Settings > Hack > Verbose, then `pkill hh_client`, "
1009 ^^
"then reproduce the error, then file the bug. This way we'll get even richer logs.\n%!"
1014 (response, `Verbose_hh_start
)
1019 | `Verbose_hh_start
->
1021 ( "\nPOWER USERS ONLY: Sometimes the normal logging from hh_server isn't "
1022 ^^
"enough to diagnose an issue, and we'll ask you to switch hh_server to "
1023 ^^
"write verbose logs, then have you repro the issue, then use `hh rage` to "
1024 ^^
"gather up those now-verbose logs. To restart hh_server with verbose logs, "
1025 ^^
"do `hh stop && hh start --config min_log_level=debug`. "
1026 ^^
"Once done, then you can repro the issue, and then do rage again.\n\n%!"
1030 "\nNote: you can often work around this issue yourself by quitting your editor, then `pkill hh_client`.\n%!"
1034 CRage
{ ClientRage.root; from = !from; desc; rageid = !rageid }
1036 let parse_download_saved_state_args () =
1039 {|Usage
: %s download
-saved
-state
[OPTION
]... [WWW
-ROOT
]
1041 Download a saved
-state
to disk
for the given repository
, to make future
1042 invocations
of `hh` faster
.|}
1045 let valid_types_message =
1046 "Valid values are: naming-and-dep-table, naming-table"
1049 let from = ref "" in
1050 let saved_state_type = ref None
in
1054 Common_argspecs.from from;
1056 Arg.String
(fun arg
-> saved_state_type := Some arg
),
1058 "The type of saved-state to download. %s"
1059 valid_types_message );
1062 let args = parse_without_command options usage "download-saved-state" in
1065 | [x
] -> Wwwroot.get
(Some x
)
1067 print_endline
usage;
1073 print_endline
"The '--from' option is required.";
1077 let saved_state_type =
1078 match !saved_state_type with
1080 Printf.printf
"The '--type' option is required. %s\n" valid_types_message;
1082 | Some
"naming-and-dep-table" ->
1083 ClientDownloadSavedState.Naming_and_dep_table
1084 | Some
"naming-table" -> ClientDownloadSavedState.Naming_table
1085 | Some
saved_state_type ->
1087 "Unrecognized value '%s' for '--type'. %s\n"
1089 valid_types_message;
1092 CDownloadSavedState
{ ClientDownloadSavedState.root; from; saved_state_type }
1094 let parse_args ~
(init_id
: string) =
1095 match parse_command () with
1096 | (CKNone
| CKCheck
) as cmd
-> parse_check_args cmd
1097 | CKStart
-> parse_start_args ()
1098 | CKStop
-> parse_stop_args ()
1099 | CKRestart
-> parse_restart_args ()
1100 | CKDebug
-> parse_debug_args ()
1101 | CKLsp
-> parse_lsp_args ~init_id
1102 | CKRage
-> parse_rage_args ()
1103 | CKDownloadSavedState
-> parse_download_saved_state_args ()
1106 | CCheck
{ ClientEnv.root; _
}
1107 | CStart
{ ClientStart.root; _
}
1108 | CRestart
{ ClientStart.root; _
}
1109 | CStop
{ ClientStop.root; _
}
1110 | CDebug
{ ClientDebug.root; _
}
1111 | CRage
{ ClientRage.root; _
}
1112 | CDownloadSavedState
{ ClientDownloadSavedState.root; _
} ->