/// <summary> /// Parses the command line arguments. /// </summary> private void ParseCommandLineArguments() { Logger.Debug("Parsing command-line arguments."); CommandLineResult = null; var args = Environment.GetCommandLineArgs(); Debug.Assert(args != null, "The command-line arguments should never be null."); Debug.Assert(args.Length > 0, "The command-line arguments should at least contain the name of the executable."); // Skip the first parameter because in Main(string[] args) the first parameter is not the // program path, but in Environment.GetCommandLineArgs it is! args = args.Skip(1).ToArray(); try { Logger.Info("Command-line arguments: {0}", args); CommandLineResult = CommandLineParser.Parse(args); if (CommandLineResult.ParsedArguments[_helpArgument] != null) { // "help" is in the parsed arguments. Logger.Debug("Showing command-line usage information."); using (ConsoleHelper.AttachConsole()) { Console.WriteLine(CommandLineParser.GetHelp()); } Exit(); return; } CommandLineParser.ThrowIfMandatoryArgumentIsMissing(CommandLineResult); } catch (CommandLineParserException exception) { Logger.Warn(exception, "Error parsing command-line arguments: "); // Show error message and usage and exit application. using (ConsoleHelper.AttachConsole()) { Logger.Debug("Printing error message and showing command-line usage information."); Console.Error.WriteLine("ERROR"); Console.Error.WriteLineIndented(exception.Message, 4); Console.Error.WriteLine(); Console.Out.WriteLine("SYNTAX"); Console.Out.WriteLineIndented(CommandLineParser.GetSyntax(), 4); Console.Out.WriteLine(); Console.Out.WriteLine(Invariant($"Try '{EditorHelper.GetExecutableName()} --help' for more information.")); } Exit((int)Editor.ExitCode.ERROR_BAD_ARGUMENTS); } }
/// <summary> /// Opens the documents that were specified using command-line arguments. /// </summary> /// <param name="commandLineResult">The command line parse result.</param> /// <remarks> /// This method is called automatically when the applications starts. However, in a /// single-instance application it can be necessary to call this method manually: For /// example, when the single-instance application is started the method is called /// automatically to load all files specified on the command line. When a new instance of /// the same application is started the command-line arguments are redirected to the /// existing instance. The existing instance needs to parse the new command line arguments /// and then call <see cref="OpenFromCommandLineAsync"/> explicitly. /// </remarks> public async Task OpenFromCommandLineAsync(ParseResult commandLineResult) { var fileArgument = commandLineResult.ParsedArguments["file"]; if (fileArgument != null) { // The user has specified files on the command-line. var files = new List<string>(); foreach (string filePattern in fileArgument.Values) { Logger.Debug(CultureInfo.InvariantCulture, "Opening file \"{0}\" from command-line.", filePattern); try { bool anyFileFound = false; var searchFolder = "."; var searchPattern = filePattern; if (Path.IsPathRooted(filePattern)) { searchFolder = Path.GetDirectoryName(filePattern); searchPattern = Path.GetFileName(filePattern); } foreach (var file in Directory.EnumerateFiles(searchFolder, searchPattern)) { anyFileFound = true; files.Add(Path.GetFullPath(file)); } if (!anyFileFound) Logger.Error(CultureInfo.InvariantCulture, "Cannot open file \"{0}\" from command-line. File does not exist.", filePattern); } catch (Exception exception) { Logger.Error(exception, CultureInfo.InvariantCulture, "Cannot open file \"{0}\" from command-line.", filePattern); // Ignore the error. The user just gets an empty application window, but no error message. // TODO: Collect all invalid files and show a message box. } } await OpenAsync(files); } }
/// <summary> /// Throws a <see cref="MissingArgumentException"/> if a mandatory argument /// (<see cref="Argument.IsOptional"/> is <see langword="false"/>) is missing. /// </summary> /// <param name="parseResult">The parse result.</param> /// <remarks> /// <see cref="Parse"/> throws a <see cref="MissingArgumentException"/> only if no arguments /// where parsed at all. The reason for this is that if an argument, like "help", is found /// you do not want to check for missing arguments. Therefore, /// <see cref="ThrowIfMandatoryArgumentIsMissing"/> is a separate step which must be called /// manually. /// </remarks> public void ThrowIfMandatoryArgumentIsMissing(ParseResult parseResult) { if (parseResult == null) throw new ArgumentNullException(nameof(parseResult)); foreach (var argument in Arguments) if (!argument.IsOptional && parseResult.ParsedArguments[argument] == null) throw new MissingArgumentException(argument); }