/* Part of the TERMINAL MODULE Copyright (C) 2020 by Maxim Prokhorov */ #pragma once #include #include "terminal_parsing.h" #include #include #include namespace terminal { struct Terminal; // We need to be able to pass arbitrary Args structure into the command function // Like Embedis implementation, we only pass things that we actually use instead of complete obj instance struct CommandContext { std::vector argv; size_t argc; Print& output; }; class Terminal { public: enum class Result { Error, // Genric error condition Command, // We successfully parsed the line and executed the callback specified via addCommand CommandNotFound, // ... similar to the above, but command was never added via addCommand BufferOverflow, // Command line processing failed, no \r\n / \n before buffer was filled Pending, // We got something in the buffer, but can't yet do anything with it NoInput // We got nothing in the buffer and stream read() returns -1 }; using CommandFunc = void(*)(const CommandContext&); using ProcessFunc = bool(*)(Result); using Names = std::vector; using Command = std::pair; using Commands = std::forward_list; // stream - see `stream` description below // buffer_size - set internal limit for the total command line length Terminal(Stream& stream, size_t buffer_size = 128) : _stream(stream), _buffer_size(buffer_size) { _buffer.reserve(buffer_size); } static void addCommand(const __FlashStringHelper* name, CommandFunc func); static size_t commands(); static Names names(); // Try to process a single line (until either `\r\n` or just `\n`) Result processLine(); // Calls processLine() repeatedly. // Blocks until the stream no longer has any data available. // `process_f` will return each individual processLine() Result, // and we can either stop (false) or continue (true) the function. void process(ProcessFunc = defaultProcessFunc); private: static bool defaultProcessFunc(Result); // general input / output stream: // - stream.read() should return user input // - stream.write() can be called from the command callback // - stream.write() can be called by us to show error messages Stream& _stream; // input stream is buffered until it can be parsed // in case parsing did not happen and we filled the buffer up to it's size, // the error will be returned and the buffer parsing will start from the beginning std::vector _buffer; const size_t _buffer_size; static Commands _commands; }; } // namespace terminal