mirror of
https://github.com/ModOrganizer2/modorganizer.git
synced 2026-07-27 13:58:24 -07:00
* Extended MODL / direct download handling - name, modname, version, and source options added to download command - nxmhandler init adds schemas and MODL entry with default launch args - Add MODL register button to general tab - On window display, call meta function to trigger both registrations
379 lines
10 KiB
C++
379 lines
10 KiB
C++
#ifndef MODORGANIZER_COMMANDLINE_INCLUDED
|
|
#define MODORGANIZER_COMMANDLINE_INCLUDED
|
|
#include "moshortcut.h"
|
|
#include <memory>
|
|
#include <vector>
|
|
|
|
class OrganizerCore;
|
|
class MOApplication;
|
|
class MOMultiProcess;
|
|
|
|
namespace cl
|
|
{
|
|
|
|
namespace po = boost::program_options;
|
|
|
|
// base class for all commands
|
|
//
|
|
class Command
|
|
{
|
|
public:
|
|
virtual ~Command() = default;
|
|
|
|
// command name, used on the command line to invoke it; this is meta().name
|
|
//
|
|
std::string name() const;
|
|
|
|
// command short description, shown in general help; this is
|
|
// meta().description
|
|
//
|
|
std::string description() const;
|
|
|
|
// usage line, puts together the name and whatever meta().usage is
|
|
//
|
|
std::string usageLine() const;
|
|
|
|
// shown after the usage line; this is meta().more
|
|
//
|
|
std::string moreInfo() const;
|
|
|
|
// returns all options for this command, including hidden ones; used to parse
|
|
// the command line
|
|
//
|
|
po::options_description allOptions() const;
|
|
|
|
// returns visible options, used to display usage
|
|
//
|
|
po::options_description visibleOptions() const;
|
|
|
|
// returns positional arguments
|
|
//
|
|
po::positional_options_description positional() const;
|
|
|
|
// when this returns true, the command line is not parsed at all and doRun()
|
|
// is expected to use untouched()
|
|
//
|
|
virtual bool legacy() const;
|
|
|
|
// remembers the given values
|
|
//
|
|
void set(const std::wstring& originalLine, po::variables_map vm,
|
|
std::vector<std::wstring> untouched);
|
|
|
|
// called as soon as the command line has been parsed; return something to
|
|
// exit immediately
|
|
//
|
|
virtual std::optional<int> runEarly();
|
|
|
|
// called as soon as the MOApplication has been created, which is also the
|
|
// first time where Qt stuff is available
|
|
//
|
|
virtual std::optional<int> runPostApplication(MOApplication& a);
|
|
|
|
// called as soon as the multi process checks have confirmed that this is
|
|
// a primary instance; return something to exit immediately
|
|
//
|
|
virtual std::optional<int> runPostMultiProcess(MOMultiProcess& mp);
|
|
|
|
// called after the OrganizerCore has been initialized; return something to
|
|
// exit immediatley
|
|
//
|
|
virtual std::optional<int> runPostOrganizer(OrganizerCore& core);
|
|
|
|
// whether this command can be forwarded to the primary instance if one is
|
|
// already running
|
|
//
|
|
// if an instance is already running and this returns true, the whole command
|
|
// line is sent as a message to the primary instance, which will construct a
|
|
// new CommandLine and call runPostOrganizer() with it
|
|
//
|
|
// if an instance is already running and this returns false, the "an instance
|
|
// is already running" error dialog will be shown
|
|
//
|
|
// if this is the primary instance, this function is not called
|
|
//
|
|
virtual bool canForwardToPrimary() const;
|
|
|
|
protected:
|
|
// meta information about this command, returned by derived classes
|
|
//
|
|
struct Meta
|
|
{
|
|
std::string name, description, usage, more;
|
|
|
|
Meta(std::string name, std::string description, std::string usage,
|
|
std::string more);
|
|
};
|
|
|
|
// meta
|
|
//
|
|
virtual Meta meta() const = 0;
|
|
|
|
// returns visible options specific to this command
|
|
//
|
|
virtual po::options_description getVisibleOptions() const;
|
|
|
|
// returns hidden options specific to this command
|
|
//
|
|
virtual po::options_description getInternalOptions() const;
|
|
|
|
// returns positional arguments specific to this command
|
|
//
|
|
virtual po::positional_options_description getPositional() const;
|
|
|
|
// returns the original command line
|
|
//
|
|
const std::wstring& originalCmd() const;
|
|
|
|
// variables
|
|
//
|
|
const po::variables_map& vm() const;
|
|
|
|
// returns unparsed options, only used by launch
|
|
//
|
|
const std::vector<std::wstring>& untouched() const;
|
|
|
|
private:
|
|
std::wstring m_original;
|
|
po::variables_map m_vm;
|
|
std::vector<std::wstring> m_untouched;
|
|
};
|
|
|
|
// generates a crash dump for another MO process
|
|
//
|
|
class CrashDumpCommand : public Command
|
|
{
|
|
protected:
|
|
po::options_description getVisibleOptions() const override;
|
|
Meta meta() const override;
|
|
std::optional<int> runEarly() override;
|
|
};
|
|
|
|
// this is the `launch` command used when starting a process from within the
|
|
// virtualized directory, see processrunner.cpp
|
|
//
|
|
// it has its own parsing of the command line to extract the argument after
|
|
// `launch` and use it as the cwd of the process, but pass the remaining
|
|
// arguments verbatim
|
|
//
|
|
// this is very old code that should probably never be changed
|
|
//
|
|
// note that it's actually buggy; in particular, it doesn't handle multiple
|
|
// whitespace between arguments
|
|
//
|
|
class LaunchCommand : public Command
|
|
{
|
|
public:
|
|
bool legacy() const override;
|
|
|
|
protected:
|
|
Meta meta() const override;
|
|
std::optional<int> runEarly() override;
|
|
|
|
int SpawnWaitProcess(LPCWSTR workingDirectory, LPCWSTR commandLine);
|
|
|
|
LPCWSTR UntouchedCommandLineArguments(int parseArgCount,
|
|
std::vector<std::wstring>& parsedArgs);
|
|
};
|
|
|
|
// runs a program or an executable
|
|
//
|
|
class RunCommand : public Command
|
|
{
|
|
protected:
|
|
Meta meta() const override;
|
|
|
|
po::options_description getVisibleOptions() const override;
|
|
po::options_description getInternalOptions() const override;
|
|
po::positional_options_description getPositional() const override;
|
|
|
|
bool canForwardToPrimary() const override;
|
|
std::optional<int> runPostOrganizer(OrganizerCore& core) override;
|
|
};
|
|
|
|
// reloads the given plugin
|
|
//
|
|
class ReloadPluginCommand : public Command
|
|
{
|
|
protected:
|
|
Meta meta() const override;
|
|
|
|
po::options_description getInternalOptions() const override;
|
|
po::positional_options_description getPositional() const override;
|
|
|
|
bool canForwardToPrimary() const override;
|
|
std::optional<int> runPostOrganizer(OrganizerCore& core) override;
|
|
};
|
|
|
|
// downloads a file
|
|
//
|
|
class DownloadFileCommand : public Command
|
|
{
|
|
protected:
|
|
Meta meta() const override;
|
|
|
|
po::options_description getVisibleOptions() const override;
|
|
po::options_description getInternalOptions() const override;
|
|
po::positional_options_description getPositional() const override;
|
|
|
|
bool canForwardToPrimary() const override;
|
|
std::optional<int> runPostOrganizer(OrganizerCore& core) override;
|
|
};
|
|
|
|
// refreshes mo
|
|
//
|
|
class RefreshCommand : public Command
|
|
{
|
|
protected:
|
|
Meta meta() const override;
|
|
bool canForwardToPrimary() const override;
|
|
std::optional<int> runPostOrganizer(OrganizerCore& core) override;
|
|
};
|
|
|
|
// parses the command line and runs any given command
|
|
//
|
|
// the command line used to support a few commands but with no real conventions;
|
|
// those are mostly preserved for backwards compatibility, but deprecated:
|
|
//
|
|
// - moshortcut:// for desktop/taskbar shortcuts, may contain an instance name
|
|
// and a configured executable or arbitrary binary (still used in MO for
|
|
// shortcuts)
|
|
//
|
|
// - nxm:// links
|
|
//
|
|
// - the name of a configured executable or path to binary, followed by
|
|
// arbitrary parameters, forwarded to the program
|
|
//
|
|
// any command added CommandLine will unfortunately break any executable with
|
|
// the same name: `ModOrganizer.exe run` used to launch a program named "run"
|
|
// but will now execute the command "run"
|
|
//
|
|
// if moshortcut:// is detected and has an instance, it will override -i if both
|
|
// are given
|
|
//
|
|
//
|
|
// the command is used in two phases:
|
|
//
|
|
// 1) run() is called in main() shortly after startup; it parses the command
|
|
// line and runs the given command, if any
|
|
//
|
|
// 2) if the command did not request to exit, the instance is loaded
|
|
// in main() et al. and setupCore() is called; it handles moshortcut,
|
|
// nxm links and starting executables/binaries
|
|
//
|
|
// either can return an exit code, which will make MO exit immediately
|
|
//
|
|
class CommandLine
|
|
{
|
|
public:
|
|
CommandLine();
|
|
|
|
// parses the given command line and calls runEarly() on the appropriate
|
|
// command, if any
|
|
//
|
|
// returns an empty optional if execution should continue, or a return code
|
|
// if MO must quit
|
|
//
|
|
std::optional<int> process(const std::wstring& line);
|
|
|
|
// called as soon as the MOApplication has been created; this handles a few
|
|
// global actions and forwards to the command, if any
|
|
//
|
|
std::optional<int> runPostApplication(MOApplication& a);
|
|
|
|
// calls Command::runPostMultiProcess() on the command, if any
|
|
//
|
|
std::optional<int> runPostMultiProcess(MOMultiProcess& mp);
|
|
|
|
// calls Command::runPostOrganizer() on the command, if any
|
|
//
|
|
// if MO wasn't invoked with a valid command, this also handles moshortcut,
|
|
// nxm links and starting processes
|
|
//
|
|
std::optional<int> runPostOrganizer(OrganizerCore& core);
|
|
|
|
// called when this instance is not the primary one
|
|
//
|
|
// if a command was executed and the command returns true for
|
|
// canForwardToPrimary(), this forwards the command line as an external
|
|
// message and returns true
|
|
//
|
|
// if the command returns false for canForwardToPrimary(), returns false
|
|
//
|
|
// if there was no valid command on the command line, this also forwards
|
|
// moshortcut and nxm links
|
|
//
|
|
// if there was no command, moshortcut or nxm links, this returns false, which
|
|
// will end up displaying an error message about an instance already running
|
|
//
|
|
bool forwardToPrimary(MOMultiProcess& multiProcess);
|
|
|
|
// clears parsed options, used when MO is "restarted" so the options aren't
|
|
// processed again
|
|
//
|
|
void clear();
|
|
|
|
// global usage string plus usage for the given command, if any
|
|
//
|
|
std::string usage(const Command* c = nullptr) const;
|
|
|
|
// whether --pick was given
|
|
//
|
|
bool pick() const;
|
|
|
|
// whether --multiple was given
|
|
//
|
|
bool multiple() const;
|
|
|
|
// profile override (-p)
|
|
//
|
|
std::optional<QString> profile() const;
|
|
|
|
// instance override (-i)
|
|
//
|
|
std::optional<QString> instance() const;
|
|
|
|
// returns the data parsed from an moshortcut:// option, if any
|
|
//
|
|
const MOShortcut& shortcut() const;
|
|
|
|
// returns the nxm:// link, if any
|
|
//
|
|
std::optional<QString> nxmLink() const;
|
|
|
|
// returns the executable/binary, if any
|
|
//
|
|
std::optional<QString> executable() const;
|
|
|
|
// returns the list of arguments, excluding moshortcut or executable name;
|
|
// deprecated, only use with executable()
|
|
//
|
|
const QStringList& untouched() const;
|
|
|
|
private:
|
|
po::options_description m_visibleOptions, m_allOptions;
|
|
po::positional_options_description m_positional;
|
|
std::vector<std::unique_ptr<Command>> m_commands;
|
|
po::variables_map m_vm;
|
|
MOShortcut m_shortcut;
|
|
std::optional<QString> m_nxmLink;
|
|
std::optional<QString> m_executable;
|
|
QStringList m_untouched;
|
|
Command* m_command;
|
|
|
|
void createOptions();
|
|
std::string more() const;
|
|
|
|
template <class... Ts>
|
|
void add()
|
|
{
|
|
(m_commands.push_back(std::make_unique<Ts>()), ...);
|
|
}
|
|
|
|
std::optional<int> runEarly();
|
|
};
|
|
|
|
} // namespace cl
|
|
|
|
#endif // MODORGANIZER_COMMANDLINE_INCLUDED
|