From d26dd1b5a2024280fee3631607abb0656d7e7252 Mon Sep 17 00:00:00 2001 From: Hayden Hargreaves Date: Tue, 28 Oct 2025 18:01:51 -0700 Subject: [PATCH 1/5] (FIX): Resolved the naming issues. When this was merged, it seemed to produce a miss matched result. The names were not migrated. But now they have been. --- lib/commandLineParser.cpp | 109 ++++++++++---------- lib/watchDog.cpp | 212 +++++++++++++++++++------------------- 2 files changed, 160 insertions(+), 161 deletions(-) diff --git a/lib/commandLineParser.cpp b/lib/commandLineParser.cpp index 779e90c..a2b6a14 100644 --- a/lib/commandLineParser.cpp +++ b/lib/commandLineParser.cpp @@ -2,66 +2,67 @@ #include #include // for std::invalid_argument -//implement hashmap for the code -CLI::CLI(int argc, char** argv){ - try{ - if (arc < 2) { - throw std::invalid_argument("Error: No input file provided.\n - Usage: "); - } - //sets program info - programName = argv[0]; - inputFile = argv[1] +// implement hashmap for the code +CLI::CLI(int argc, char **argv) { + try { + if (argc < 2) { + throw std::invalid_argument( + "Error: No input file provided.\nUsage: "); + } + // sets program info + programName = argv[0]; + inputFile = argv[1]; - //checks that file has correct file extension - if(!(CLI::IsMarkupFile(inputFile))) { - throw std::invalid_argument("Error: Invalid file extension. Expected a '.md' (Markdown) file."); - } - //stores remaining arguments - for (int i = 1; i < argc; i++){ - args.push_back(argv[i]); - } - } - catch (const std::invalid_argument& e) { - std::cerr << e.what() << "\n"; - PrintHelp(); - std::exit(EXIT_FAILURE); + // checks that file has correct file extension + if (!(CLI::IsMarkupFile(inputFile))) { + throw std::invalid_argument( + "Error: Invalid file extension. Expected a '.md' (Markdown) file."); } + // stores remaining arguments + for (int i = 1; i < argc; i++) { + args.push_back(argv[i]); } - -bool CLI::IsMarkupFile(const std::string& filename) { - //markdown file extension - const std::string requiredExtension = ".md"; - //checks to see if it can even include extension - if (filename.size() <= requiredExtension.size()) { - return false; - } - // Extracts the last N characters of the filename (where N is the length of the required extension) - // and checks if they match the required file extension (e.g., ".md"). - // - // Example: - // filename = "notes.md" - // requiredExtension = ".md" - // filename.substr(filename.size() - requiredExtension.size()) == ".md" → true - // - // Reference: https://en.cppreference.com/w/cpp/string/basic_string/substr - return filename.substr(filename.size() - requiredExtension.size()) == requiredExtension; + } catch (const std::invalid_argument &e) { + std::cerr << e.what() << "\n"; + PrintHelp(); + std::exit(EXIT_FAILURE); + } } - -//place to run commands but IDK IF WE SHOULD USE A HASMAP or how we are going to get each method to run -void CLI::RunCommands(){ - for (int i = 0; i < args.size(); i++){ - - } +bool CLI::IsMarkupFile(const std::string &filename) { + // markdown file extension + const std::string requiredExtension = ".md"; + // checks to see if it can even include extension + if (filename.size() <= requiredExtension.size()) { + return false; + } + // Extracts the last N characters of the filename (where N is the length of + // the required extension) and checks if they match the required file + // extension (e.g., ".md"). + // + // Example: + // filename = "notes.md" + // requiredExtension = ".md" + // filename.substr(filename.size() - requiredExtension.size()) == ".md" → + // true + // + // Reference: https://en.cppreference.com/w/cpp/string/basic_string/substr + return filename.substr(filename.size() - requiredExtension.size()) == + requiredExtension; } -void CLI::PrintHelp() const{ - std::cout << "Usage:\n" - << " " << programName << " REQUIRED\n" - << "Flags:\n" - << " --o, --output , optional output filename\n" - << " --w, --watch, enables watchdog\n" - << " --s, --stop, stops watchdog\n"; +// place to run commands but IDK IF WE SHOULD USE A HASMAP or how we are going +// to get each method to run +void CLI::RunCommands() { + for (int i = 0; i < args.size(); i++) { + } } +void CLI::PrintHelp() const { + std::cout << "Usage:\n" + << " " << programName << " REQUIRED\n" + << "Flags:\n" + << " --o, --output , optional output filename\n" + << " --w, --watch, enables watchdog\n" + << " --s, --stop, stops watchdog\n"; +} diff --git a/lib/watchDog.cpp b/lib/watchDog.cpp index 8f7d9f0..d73adaa 100644 --- a/lib/watchDog.cpp +++ b/lib/watchDog.cpp @@ -1,123 +1,121 @@ -#include "watchdog.h" +#include "watchDog.h" -namespace fs = std::filesystem; //makes it easier to read -void WatchDog::start() -{ - //checks if file exist - if(!fs::exists(path)) - { - //returns and sets parameters to false if file doesnt exist - watching = false; - hasInitialTime = false; - std::cout << "WatchDog: File does not exists: " << path << std::endl; - return; - } - //grabs intial write time - lastWriteTime = fs::last_write_time(path); - watching = true; - hasInitialTime = true; - std::cout << "WatchDog: Started" << std::endl; -} -void WatchDog::stop(){ - watching = false; -} -bool WatchDog::checkFile(){ - //If not watching returns false - if (!watching) return false; +namespace fs = std::filesystem; // makes it easier to read - //Checking if file was deleted - if(!fs::exists(path)) - { - if (hasInitialTime) { - std::cout << "WatchDog: File was delete: " << path << std::endl; - hasInitialTime = false; - return true; - } - return false; +void Watchdog::Start() { + // checks if file exist + if (!fs::exists(path)) { + // returns and sets parameters to false if file doesnt exist + this->watching = false; + this->has_initial_time = false; + std::cout << "Watchdog: File does not exists: " << path << std::endl; + return; + } + // grabs intial write time + this->last_write_time = fs::last_write_time(path); + this->watching = true; + this->has_initial_time = true; + std::cout << "Watchdog: Started" << std::endl; +} + +bool Watchdog::CheckFile() { + // If not watching returns false + if (!watching) + return false; + + try { + // Checking if file was deleted + if (!fs::exists(path)) { + if (this->has_initial_time) { + std::cout << "Watchdog: File was delete: " << path << std::endl; + this->has_initial_time = false; + return true; + } + return false; } - - //Built in function with file system to check last write tim + + // Built in function with file system to check last write tim fs::file_time_type currentWriteTime = fs::last_write_time(path); - //File was just created - if(!hasInitialTime) - { - lastWriteTime = currentWriteTime; - hasInitialTime = true; - std::cout << "WatchDog: File created: " << path << std::endl; - return true; + // File was just created + if (!this->has_initial_time) { + this->last_write_time = currentWriteTime; + this->has_initial_time = true; + std::cout << "Watchdog: File created: " << path << std::endl; + return true; } - //File modified - if (currentWriteTime != lastWriteTime) - { - lastWriteTime = currentWriteTime; - std::cout << "WatchDog: File modifed at " - << timePointToString(lastWriteTime) << std::endl; - return true; + // File modified + if (currentWriteTime != this->last_write_time) { + this->last_write_time = currentWriteTime; + std::cout << "Watchdog: File modifed at " + << TimePointToString(this->last_write_time) << std::endl; + return true; } - - } catch (const fs::filesystem_error& e) { - // File deleted, inaccessible, or path invalid - if (hasInitialTime) { - std::cout << "WatchDog: File deleted or inaccessible: " << path << std::endl; - hasInitialTime = false; - return true; - } - return false; - - } catch (const std::exception& e) { - std::cerr << "WatchDog: Unexpected error checking file: " << e.what() << std::endl; - return false; + } catch (const fs::filesystem_error &e) { + // File deleted, inaccessible, or path invalid + if (this->has_initial_time) { + std::cout << "Watchdog: File deleted or inaccessible: " << path + << std::endl; + this->has_initial_time = false; + return true; } - - // No change return false; + } catch (const std::exception &e) { + std::cerr << "Watchdog: Unexpected error checking file: " << e.what() + << std::endl; + return false; + } + + // No change + return false; } -std::string Watchdog::TimePointToString(const fs::file_time_type& timePoint){ - /** - * Step 1: timePoint - * - This is the last write time of the file, returned by std::filesystem. - * - Its clock is platform-dependent (filesystem clock). - * - * Step 2: fs::file_time_type::clock::now() - * - Current time according to the filesystem clock. - * - * Step 3: std::chrono::system_clock::now() - * - Current time according to the system clock (standard C++ clock). - * - * Conversion formula: - * timePoint - fs::file_time_type::clock::now() + std::chrono::system_clock::now() - * - * Explanation: - * a) timePoint - fs::file_time_type::clock::now() - * - Calculates the duration between the file's last write time and "now" - * according to the filesystem clock. - * b) + std::chrono::system_clock::now() - * - Shifts that duration to align with the system clock timeline. - * c) std::chrono::time_point_cast(...) - * - Ensures the resulting time_point uses the correct duration type - * for std::chrono::system_clock. - * - * Result: - * - systemTime is a std::chrono::system_clock::time_point representing - * the same instant as timePoint, but compatible with system_clock. - */ - std::chrono::system_clock::time_point systemTimePoint = - std::chrono::time_point_cast( - timePoint - fs::file_time_type::clock::now() + std::chrono::system_clock::now() - ); - - //Converts to seconds - std::time_t timeInSeconds = std::chrono::system_clock::to_time_t(systemTimePoint); +std::string Watchdog::TimePointToString(const fs::file_time_type &timePoint) { + /** + * Step 1: timePoint + * - This is the last write time of the file, returned by std::filesystem. + * - Its clock is platform-dependent (filesystem clock). + * + * Step 2: fs::file_time_type::clock::now() + * - Current time according to the filesystem clock. + * + * Step 3: std::chrono::system_clock::now() + * - Current time according to the system clock (standard C++ clock). + * + * Conversion formula: + * timePoint - fs::file_time_type::clock::now() + + * std::chrono::system_clock::now() + * + * Explanation: + * a) timePoint - fs::file_time_type::clock::now() + * - Calculates the duration between the file's last write time and "now" + * according to the filesystem clock. + * b) + std::chrono::system_clock::now() + * - Shifts that duration to align with the system clock timeline. + * c) std::chrono::time_point_cast(...) + * - Ensures the resulting time_point uses the correct duration type + * for std::chrono::system_clock. + * + * Result: + * - systemTime is a std::chrono::system_clock::time_point representing + * the same instant as timePoint, but compatible with system_clock. + */ + std::chrono::system_clock::time_point systemTimePoint = + std::chrono::time_point_cast( + timePoint - fs::file_time_type::clock::now() + + std::chrono::system_clock::now()); - //Converts to local time, built in function - std::tm localTime = *std::localtime(&timeInSeconds); + // Converts to seconds + std::time_t timeInSeconds = + std::chrono::system_clock::to_time_t(systemTimePoint); - // Format the time into a string using strftime - char buffer[20]; - std::strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", &localTime); + // Converts to local time, built in function + std::tm localTime = *std::localtime(&timeInSeconds); - return std::string(buffer); + // Format the time into a string using strftime + char buffer[20]; + std::strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", &localTime); + + return std::string(buffer); } From 3f76dafbc1ead544afdd917ac587029c2cf571df Mon Sep 17 00:00:00 2001 From: Hayden Hargreaves Date: Tue, 28 Oct 2025 18:02:45 -0700 Subject: [PATCH 2/5] (FIX): Renamed `watchDog` to `watchdog` --- lib/{watchDog.cpp => watchdog.cpp} | 2 +- lib/{watchDog.h => watchdog.h} | 0 src/main.cpp | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) rename lib/{watchDog.cpp => watchdog.cpp} (96%) rename lib/{watchDog.h => watchdog.h} (100%) diff --git a/lib/watchDog.cpp b/lib/watchdog.cpp similarity index 96% rename from lib/watchDog.cpp rename to lib/watchdog.cpp index d73adaa..85aa520 100644 --- a/lib/watchDog.cpp +++ b/lib/watchdog.cpp @@ -1,4 +1,4 @@ -#include "watchDog.h" +#include "watchdog.h" namespace fs = std::filesystem; // makes it easier to read diff --git a/lib/watchDog.h b/lib/watchdog.h similarity index 100% rename from lib/watchDog.h rename to lib/watchdog.h diff --git a/src/main.cpp b/src/main.cpp index ceeef67..c5e2626 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,7 +1,7 @@ #include "../lib/inlineNode.h" #include "../lib/parser.h" #include "../lib/structureNode.h" -#include "../lib/watchDog.h" +#include "../lib/watchdog.h" #include #include From 862c6e7c92f4d23567ec1580713b1b84e6e196c1 Mon Sep 17 00:00:00 2001 From: Hayden Hargreaves Date: Tue, 28 Oct 2025 18:45:18 -0700 Subject: [PATCH 3/5] (FIX): Simplified the watchdog. Now it runs the way its expected to, just needs to be wired up into the parser somehow. --- lib/watchdog.cpp | 148 ++++++++++++++++++----------------------------- lib/watchdog.h | 146 ++++++++++++++++++++++++---------------------- src/main.cpp | 12 ---- 3 files changed, 132 insertions(+), 174 deletions(-) diff --git a/lib/watchdog.cpp b/lib/watchdog.cpp index 85aa520..06f3eac 100644 --- a/lib/watchdog.cpp +++ b/lib/watchdog.cpp @@ -1,114 +1,76 @@ #include "watchdog.h" +#include +#include +#include -namespace fs = std::filesystem; // makes it easier to read +namespace fs = std::filesystem; +using namespace std::chrono; void Watchdog::Start() { // checks if file exist - if (!fs::exists(path)) { - // returns and sets parameters to false if file doesnt exist - this->watching = false; - this->has_initial_time = false; - std::cout << "Watchdog: File does not exists: " << path << std::endl; - return; + if (!fs::exists(this->path)) + throw std::runtime_error("File does not exist."); + + // Loop forever and check the file. + while (true) { + CheckFile(); + std::this_thread::sleep_for(this->POLLING_INTERVAL); } - // grabs intial write time - this->last_write_time = fs::last_write_time(path); - this->watching = true; - this->has_initial_time = true; - std::cout << "Watchdog: Started" << std::endl; } -bool Watchdog::CheckFile() { - // If not watching returns false - if (!watching) - return false; +void Watchdog::CheckFile() { + // LONG STORY SHORT: + // When a file is written to, it aquires an OS lock, which means our program + // cannot access it. So when we request, it fails. So we should basically just + // keep trying until we get access. + // + // After implementing some retry logic, I was unable to replicate the error. - try { - // Checking if file was deleted - if (!fs::exists(path)) { - if (this->has_initial_time) { - std::cout << "Watchdog: File was delete: " << path << std::endl; - this->has_initial_time = false; - return true; + for (int attempt = 0; attempt < this->MAX_RETRIES; ++attempt) { + try { + // Checking if file was deleted + if (!fs::exists(this->path)) + throw std::runtime_error( + "File could not be found. Maybe it was deleted?"); + + // Built in function with file system to check last write time + fs::file_time_type currentWriteTime = fs::last_write_time(path); + + // File modified + if (currentWriteTime != this->last_write_time) { + this->last_write_time = currentWriteTime; + + time_point before = high_resolution_clock::now(); + + // DO SOMETHING + std::this_thread::sleep_for(this->POLLING_INTERVAL); + + time_point after = high_resolution_clock::now(); + + duration dur = after - before; + long ms = std::chrono::duration_cast(dur).count(); + std::cout << std::endl + << "Recompiled in \033[36m" << ms << "ms\033[0m" << std::endl; } - return false; - } + } catch (const std::exception &ex) { + // On last attempt, bubble the error outward + if (attempt == this->MAX_RETRIES - 1) + throw std::runtime_error("Watchdog failed after multiple retries: " + + std::string(ex.what())); - // Built in function with file system to check last write tim - fs::file_time_type currentWriteTime = fs::last_write_time(path); - - // File was just created - if (!this->has_initial_time) { - this->last_write_time = currentWriteTime; - this->has_initial_time = true; - std::cout << "Watchdog: File created: " << path << std::endl; - return true; + // Wait and then try again + std::this_thread::sleep_for(this->RETRY_DELAY); } - - // File modified - if (currentWriteTime != this->last_write_time) { - this->last_write_time = currentWriteTime; - std::cout << "Watchdog: File modifed at " - << TimePointToString(this->last_write_time) << std::endl; - return true; - } - } catch (const fs::filesystem_error &e) { - // File deleted, inaccessible, or path invalid - if (this->has_initial_time) { - std::cout << "Watchdog: File deleted or inaccessible: " << path - << std::endl; - this->has_initial_time = false; - return true; - } - return false; - } catch (const std::exception &e) { - std::cerr << "Watchdog: Unexpected error checking file: " << e.what() - << std::endl; - return false; } - - // No change - return false; } std::string Watchdog::TimePointToString(const fs::file_time_type &timePoint) { - /** - * Step 1: timePoint - * - This is the last write time of the file, returned by std::filesystem. - * - Its clock is platform-dependent (filesystem clock). - * - * Step 2: fs::file_time_type::clock::now() - * - Current time according to the filesystem clock. - * - * Step 3: std::chrono::system_clock::now() - * - Current time according to the system clock (standard C++ clock). - * - * Conversion formula: - * timePoint - fs::file_time_type::clock::now() + - * std::chrono::system_clock::now() - * - * Explanation: - * a) timePoint - fs::file_time_type::clock::now() - * - Calculates the duration between the file's last write time and "now" - * according to the filesystem clock. - * b) + std::chrono::system_clock::now() - * - Shifts that duration to align with the system clock timeline. - * c) std::chrono::time_point_cast(...) - * - Ensures the resulting time_point uses the correct duration type - * for std::chrono::system_clock. - * - * Result: - * - systemTime is a std::chrono::system_clock::time_point representing - * the same instant as timePoint, but compatible with system_clock. - */ - std::chrono::system_clock::time_point systemTimePoint = - std::chrono::time_point_cast( - timePoint - fs::file_time_type::clock::now() + - std::chrono::system_clock::now()); + system_clock::time_point systemTimePoint = + time_point_cast( + timePoint - fs::file_time_type::clock::now() + system_clock::now()); // Converts to seconds - std::time_t timeInSeconds = - std::chrono::system_clock::to_time_t(systemTimePoint); + std::time_t timeInSeconds = system_clock::to_time_t(systemTimePoint); // Converts to local time, built in function std::tm localTime = *std::localtime(&timeInSeconds); diff --git a/lib/watchdog.h b/lib/watchdog.h index 3164ac1..32b0aef 100644 --- a/lib/watchdog.h +++ b/lib/watchdog.h @@ -1,24 +1,23 @@ -/** +/** * @file watchdog.h * @brief file watcher * @author Preston Shultz - * Sources: + * Sources: * https://en.cppreference.com/w/cpp/filesystem.html * https://en.cppreference.com/w/cpp/chrono.html * Format the time into a string using strftime - * https://en.cppreference.com/w/cpp/chrono/c/strftime.html + * https://en.cppreference.com/w/cpp/chrono/c/strftime.html */ #ifndef WATCHDOG_H #define WATCHDOG_H -#include -#include +#include //makes timestamps easier +#include //Convert time_t to std::tm for local time #include //allow access to files platform independent -#include //makes timestamps easier -#include //Convert time_t to std::tm for local time -#include //Formats std::tim into "YYYY-MM-DD HH-MM-SS" - +#include //Formats std::tim into "YYYY-MM-DD HH-MM-SS" +#include +#include /** * @brief watchdog class. @@ -27,70 +26,79 @@ * * @author Preston Shultz (shultzp1@my.erau.edu) */ -class Watchdog{ +class Watchdog { +protected: + /** + * @brief watchdog class. + * + * Checks if a file has been modified + * + * @author Preston Shultz (shultzp1@my.erau.edu) + * @author Hayden Hargreaves (hhargreaves2006@gmail.com) + */ + void CheckFile(); + public: - Watchdog(const std::string& path) : - path(path), watching(false), has_initial_time(false) {} + Watchdog(const std::string &path) : path(path) {} - /** - * @brief watchdog class. - * - * Starts the watchdog to check of a file is modified - * - * @author Preston Shultz (shultzp1@my.erau.edu) - */ - void Start(); - /** - * @brief watchdog class. - * - * Stops the watchdog - * - * @author Preston Shultz (shultzp1@my.erau.edu) - */ - void Stop() {watching = false;} //Disable + /** + * @brief watchdog class. + * + * Starts the watchdog to check of a file is modified + * + * @author Preston Shultz (shultzp1@my.erau.edu) + */ + void Start(); - /** - * @brief watchdog class. - * - * Checks if a file has been modified - * - * @author Preston Shultz (shultzp1@my.erau.edu) - */ - bool CheckFile(); - - /** - * @brief watchdog class. - * - * Returns files last modified date - * - * @author Preston Shultz (shultzp1@my.erau.edu) - */ - std::filesystem::file_time_type GetLastWriteTime() - const {return last_write_time;} - - /** - * @brief watchdog class. - * - * Converts time point into a string - * - * @author Preston Shultz (shultzp1@my.erau.edu) - */ - static std::string TimePointToString(const std::filesystem::file_time_type& timePoint); - - /** - * @brief watchdog class. - * - * Returns if the watchDog is on - * - * @author Preston Shultz (shultzp1@my.erau.edu) - */ - bool IsWatching() const{return watching;} + /** + * @brief watchdog class. + * + * Converts time point into a string + * + * Details below: + * + * Step 1: timePoint + * - This is the last write time of the file, returned by std::filesystem. + * - Its clock is platform-dependent (filesystem clock). + * + * Step 2: fs::file_time_type::clock::now() + * - Current time according to the filesystem clock. + * + * Step 3: std::chrono::system_clock::now() + * - Current time according to the system clock (standard C++ clock). + * + * Conversion formula: + * timePoint - fs::file_time_type::clock::now() + + * std::chrono::system_clock::now() + * + * Explanation: + * a) timePoint - fs::file_time_type::clock::now() + * - Calculates the duration between the file's last write time and "now" + * according to the filesystem clock. + * b) + std::chrono::system_clock::now() + * - Shifts that duration to align with the system clock timeline. + * c) std::chrono::time_point_cast(...) + * - Ensures the resulting time_point uses the correct duration type + * for std::chrono::system_clock. + * + * Result: + * - systemTime is a std::chrono::system_clock::time_point representing + * the same instant as timePoint, but compatible with system_clock. + * + * @author Preston Shultz (shultzp1@my.erau.edu) + */ + static std::string + TimePointToString(const std::filesystem::file_time_type &timePoint); private: - std::string path; //file path - bool watching; //Is watchdog on? - std::filesystem::file_time_type last_write_time; - bool has_initial_time; //checks if initial time is given + std::string path; + std::filesystem::file_time_type last_write_time; + + // Timing values for the watchdog + const std::chrono::milliseconds POLLING_INTERVAL = + std::chrono::milliseconds(100); + const int MAX_RETRIES = 20; + const std::chrono::milliseconds RETRY_DELAY = std::chrono::milliseconds(20); }; -#endif \ No newline at end of file +#endif diff --git a/src/main.cpp b/src/main.cpp index c5e2626..922ba50 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -41,18 +41,6 @@ void test_nodes() { void test_watchdog() { Watchdog wd("test/input.md"); wd.Start(); - - std::cout << "Initial check (should do nothing if file unchanged):\n"; - wd.CheckFile(); - - std::cout << "Now, modify or create the file 'example.txt' manually and " - "press Enter:\n"; - std::cin.get(); // Wait for user to press Enter - - // Check again after manual change - wd.CheckFile(); - - std::cout << "Done testing.\n"; } void test_input(int argc, char **argv) { From 408fd5fc2eb70d09d7772cb7114bff7a7905f36b Mon Sep 17 00:00:00 2001 From: Hayden Hargreaves Date: Wed, 29 Oct 2025 15:09:45 -0700 Subject: [PATCH 4/5] (FEAT): Completed watchdog v2 updates. This works the way expected, all thats left is the CLI and the command arg parser. --- input.md | 22 -------- lib/commandLineParser.cpp | 17 ++++--- lib/commandLineParser.h | 103 +++++++++++++++++++------------------- lib/documentConverter.h | 33 ++++++++++++ lib/fileSystem.cpp | 1 + lib/parser.cpp | 6 ++- lib/watchdog.cpp | 22 ++++---- lib/watchdog.h | 13 +++-- src/main.cpp | 10 +++- syntax.md | 45 ----------------- test/input.html | 25 +++++++++ test/input.md | 39 ++++++++++++--- 12 files changed, 188 insertions(+), 148 deletions(-) delete mode 100644 input.md create mode 100644 lib/documentConverter.h delete mode 100644 syntax.md create mode 100644 test/input.html diff --git a/input.md b/input.md deleted file mode 100644 index f66ff5f..0000000 --- a/input.md +++ /dev/null @@ -1,22 +0,0 @@ -hello `world` - - -This `is also a code block` - -hi `mom -hello` - -hi `mom - -this is too far` - - -*this is **words*** - -## **Hello world** - -### hello *world* - -# ***This is both!*** - -###### This is neither diff --git a/lib/commandLineParser.cpp b/lib/commandLineParser.cpp index a2b6a14..2a1c4fc 100644 --- a/lib/commandLineParser.cpp +++ b/lib/commandLineParser.cpp @@ -10,11 +10,11 @@ CLI::CLI(int argc, char **argv) { "Error: No input file provided.\nUsage: "); } // sets program info - programName = argv[0]; - inputFile = argv[1]; + program_name = argv[0]; + input_file = argv[1]; // checks that file has correct file extension - if (!(CLI::IsMarkupFile(inputFile))) { + if (!(CLI::IsMarkupFile(input_file))) { throw std::invalid_argument( "Error: Invalid file extension. Expected a '.md' (Markdown) file."); } @@ -54,15 +54,16 @@ bool CLI::IsMarkupFile(const std::string &filename) { // place to run commands but IDK IF WE SHOULD USE A HASMAP or how we are going // to get each method to run void CLI::RunCommands() { - for (int i = 0; i < args.size(); i++) { + for (size_t i = 0; i < args.size(); i++) { } } void CLI::PrintHelp() const { std::cout << "Usage:\n" - << " " << programName << " REQUIRED\n" + << "\t" << program_name << " \n" << "Flags:\n" - << " --o, --output , optional output filename\n" - << " --w, --watch, enables watchdog\n" - << " --s, --stop, stops watchdog\n"; + << "\t-o, --output , optional output filename\n" + << "\t-w, --watch, enables watchdog\n"; } + +// ./parser input_file -w dhuahdakhk -o output diff --git a/lib/commandLineParser.h b/lib/commandLineParser.h index 88c9a09..55ad1fd 100644 --- a/lib/commandLineParser.h +++ b/lib/commandLineParser.h @@ -1,9 +1,9 @@ -/** +/** * @file commandLineParser.h * @brief Parses command line * @author Preston Shultz - * Sources: - * + * Sources: + * */ #ifndef COMMAND_LINE_PARSER_H @@ -17,64 +17,63 @@ * * Parse input arguments, sets input and output files * Lets user use commands with program - * + * * @author Preston Shultz (shultzp1@my.erau.edu) */ -class CLI{ +class CLI { public: - /** - * @brief Takes in argc and argv and converts it to vector - * - * CLI constructor - * - * @author Preston Shultz (shultzp1@my.erau.edu) - */ - CLI(int argc, char **argv); + /** + * @brief Takes in argc and argv and converts it to vector + * + * CLI constructor + * + * @author Preston Shultz (shultzp1@my.erau.edu) + */ + CLI(int argc, char **argv); - /** - * @brief Runs Commands - * - * @author Preston Shultz (shultzp1@my.erau.edu) - */ - void RunCommands(); + /** + * @brief Runs Commands + * + * @author Preston Shultz (shultzp1@my.erau.edu) + */ + void RunCommands(); - /** - * @brief Prints a list of commands that can be used - * - * @author Preston Shultz (shultzp1@my.erau.edu) - */ - void PrintHelp() const; + /** + * @brief Prints a list of commands that can be used + * + * @author Preston Shultz (shultzp1@my.erau.edu) + */ + void PrintHelp() const; - /** - * @brief Returns input file - * - * @author Preston Shultz (shultzp1@my.erau.edu) - */ - std::string GetInputFile() const {return inputFile;} + /** + * @brief Returns input file + * + * @author Preston Shultz (shultzp1@my.erau.edu) + */ + std::string GetInputFile() const { return input_file; } - /** - * @brief Returns output file - * - * @author Preston Shultz (shultzp1@my.erau.edu) - */ - std::string GetOutputFile() const {return outputFile;} + /** + * @brief Returns output file + * + * @author Preston Shultz (shultzp1@my.erau.edu) + */ + std::string GetOutputFile() const { return output_file; } private: + /** + * @brief Ensures the provided filename has a .markup extension + * + * @param filename The file name to validate + * @return true if file ends with .markup + * @return false otherwise + * @author Preston Shultz (shultzp1@my.erau.edu) + */ + static bool IsMarkupFile(const std::string &filename); - /** - * @brief Ensures the provided filename has a .markup extension - * - * @param filename The file name to validate - * @return true if file ends with .markup - * @return false otherwise - * @author Preston Shultz (shultzp1@my.erau.edu) - */ - static bool IsMarkupFile(const std::string& filename); - - std::string programName; - std::vector args; - std::string inputFile; - std::string outputFile; + std::string program_name; + std::vector args; + std::string input_file; + std::string output_file; }; -#endif \ No newline at end of file +#endif diff --git a/lib/documentConverter.h b/lib/documentConverter.h new file mode 100644 index 0000000..29ce2f4 --- /dev/null +++ b/lib/documentConverter.h @@ -0,0 +1,33 @@ +#ifndef DOCUMENT_CONVERTER_H +#define DOCUMENT_CONVERTER_H + +#include "parser.h" +#include "watchdog.h" +#include + +class DocumentConverter { +private: + Parser parser; + Watchdog watchdog; + +public: + DocumentConverter(std::string input, std::string output = "") + : parser(input, output), watchdog(input) {}; + + void Convert() { + this->parser.ParseDocument(); + this->parser.WriteOutput(); + } + + void ConvertWatcher() { + // This is a lambda, which can be passed into the start function of + // watchdog. + std::function callback = [this]() { + this->parser.ParseDocument(); + this->parser.WriteOutput(); + }; + this->watchdog.Start(callback); + } +}; + +#endif diff --git a/lib/fileSystem.cpp b/lib/fileSystem.cpp index 3742b7a..87f2ebe 100644 --- a/lib/fileSystem.cpp +++ b/lib/fileSystem.cpp @@ -2,6 +2,7 @@ #include "util.h" #include +#include #include #include #include diff --git a/lib/parser.cpp b/lib/parser.cpp index 1d5a7e5..d1674d6 100644 --- a/lib/parser.cpp +++ b/lib/parser.cpp @@ -11,7 +11,8 @@ using std::string; using std::vector; void Parser::Inspect() { - std::cerr << "Parser::Inspect() is not yet implemented." << std::endl; + std::cout << this->position << std::endl; + std::cout << this->content.size() << std::endl; } void Parser::NormalizeInputStream() { @@ -40,6 +41,9 @@ void Parser::WriteOutput() { } void Parser::ParseDocument() { + // NOTE:This needs to be set so the parsing can continue + this->position = 0; + try { this->content = this->filesystem.ReadInputFile(); } catch (const std::runtime_error &e) { diff --git a/lib/watchdog.cpp b/lib/watchdog.cpp index 06f3eac..700edc5 100644 --- a/lib/watchdog.cpp +++ b/lib/watchdog.cpp @@ -6,19 +6,19 @@ namespace fs = std::filesystem; using namespace std::chrono; -void Watchdog::Start() { +void Watchdog::Start(std::function callback) { // checks if file exist if (!fs::exists(this->path)) throw std::runtime_error("File does not exist."); // Loop forever and check the file. while (true) { - CheckFile(); + CheckFile(callback); std::this_thread::sleep_for(this->POLLING_INTERVAL); } } -void Watchdog::CheckFile() { +void Watchdog::CheckFile(std::function callback) { // LONG STORY SHORT: // When a file is written to, it aquires an OS lock, which means our program // cannot access it. So when we request, it fails. So we should basically just @@ -41,16 +41,20 @@ void Watchdog::CheckFile() { this->last_write_time = currentWriteTime; time_point before = high_resolution_clock::now(); - - // DO SOMETHING - std::this_thread::sleep_for(this->POLLING_INTERVAL); - + callback(); time_point after = high_resolution_clock::now(); duration dur = after - before; long ms = std::chrono::duration_cast(dur).count(); - std::cout << std::endl - << "Recompiled in \033[36m" << ms << "ms\033[0m" << std::endl; + long us = std::chrono::duration_cast(dur).count(); + + if (ms > 0) { + std::cout << std::endl + << "Recompiled in \033[36m" << ms << "ms\033[0m" << std::endl; + } else { + std::cout << std::endl + << "Recompiled in \033[36m" << us << "μs\033[0m" << std::endl; + } } } catch (const std::exception &ex) { // On last attempt, bubble the error outward diff --git a/lib/watchdog.h b/lib/watchdog.h index 32b0aef..dd34483 100644 --- a/lib/watchdog.h +++ b/lib/watchdog.h @@ -15,7 +15,8 @@ #include //makes timestamps easier #include //Convert time_t to std::tm for local time #include //allow access to files platform independent -#include //Formats std::tim into "YYYY-MM-DD HH-MM-SS" +#include +#include //Formats std::tim into "YYYY-MM-DD HH-MM-SS" #include #include @@ -33,10 +34,13 @@ protected: * * Checks if a file has been modified * + * @param callback Callback function to execute when the watchdog notices a + * change. + * * @author Preston Shultz (shultzp1@my.erau.edu) * @author Hayden Hargreaves (hhargreaves2006@gmail.com) */ - void CheckFile(); + void CheckFile(std::function callback); public: Watchdog(const std::string &path) : path(path) {} @@ -46,9 +50,12 @@ public: * * Starts the watchdog to check of a file is modified * + * @param callback Callback function to execute when the watchdog notices a + * change. + * * @author Preston Shultz (shultzp1@my.erau.edu) */ - void Start(); + void Start(std::function callback); /** * @brief watchdog class. diff --git a/src/main.cpp b/src/main.cpp index 922ba50..3c8a116 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,3 +1,4 @@ +#include "../lib/documentConverter.h" #include "../lib/inlineNode.h" #include "../lib/parser.h" #include "../lib/structureNode.h" @@ -40,7 +41,7 @@ void test_nodes() { */ void test_watchdog() { Watchdog wd("test/input.md"); - wd.Start(); + wd.Start(nullptr); } void test_input(int argc, char **argv) { @@ -66,4 +67,9 @@ void test_input(int argc, char **argv) { std::cout << std::endl; } -int main(int argc, char **argv) { test_watchdog(); } +void test_document_converter() { + DocumentConverter dc("test/input.md"); + dc.Convert(); +} + +int main(int argc, char **argv) { test_document_converter(); } diff --git a/syntax.md b/syntax.md deleted file mode 100644 index bd80e12..0000000 --- a/syntax.md +++ /dev/null @@ -1,45 +0,0 @@ - -Reference [here](https://www.markdownguide.org/basic-syntax/) - -Headings, h# tags - - -# Header Level 1 ->

Content

-## Header Level 2 ->

Content

-### Header Level 3 ->

Content

-#### Header Level 4 ->

Content

-##### Header Level 5 ->
Content
-###### Header Level 6 ->
Content
- - -Alternate syntax (n number of =/-) - -Header Level 1 ->

Content

-================ - - -Header Level 2 ->

Content

----------------- - - -Paragraph tags - -Hello world ->

Hello world

- -This is also -a paragraph ->

this is also a paragraph regardless

-regardless - -However -this is a break, because it ends with two spaces ->

However
this is a break, because it ends with two spaces

- -Double returns also - -yields new paragraphs ->

Double returns also

yields new paragraphs

- - -*italic* -> italic -**bold** -> bold -***italic bold*** -> italic bold - -hello **world** -> [TextClass: hello, BoldClass: world] diff --git a/test/input.html b/test/input.html new file mode 100644 index 0000000..d5b4d49 --- /dev/null +++ b/test/input.html @@ -0,0 +1,25 @@ + + + + + + Document + + +

Reference [here](https://www.markdownguide.org/basic-syntax/)

+

Headings, h# tags

+

Header Level 1 ->

Content

## Header Level 2 ->

Content

### Header Level 3 ->

Content

#### Header Level 4 ->

Content

##### Header Level 5 ->
Content
###### Header Level 6 ->
Content
+

Alternate syntax (n number of =/-)

+

Header Level 1 ->

Content

================

+

Header Level 2 ->

Content

----------------

+

Paragraph tags

+

Hello world ->

Hello world

+

This is also a paragraph ->

this is also a paragraph regardless

regardless

+

However this is a break, because it ends with two spaces ->

However
this is a break, because it ends with two spaces

+

Double returns also

+

yields new paragraphs ->

Double returns also

yields new paragraphs

+

italic -> italic bold -> bold italic bold -> italic bold

+

hello world -> [TextClass: hello, BoldClass: world]

+ + + \ No newline at end of file diff --git a/test/input.md b/test/input.md index 54ed126..2ba0eb3 100644 --- a/test/input.md +++ b/test/input.md @@ -1,17 +1,44 @@ +Reference [here](https://www.markdownguide.org/basic-syntax/) + +Headings, h# tags -# Hello world in an h1 tag +# Header Level 1 ->

Content

+## Header Level 2 ->

Content

+### Header Level 3 ->

Content

+#### Header Level 4 ->

Content

+##### Header Level 5 ->
Content
+###### Header Level 6 ->
Content
-## This is a h2 tag +Alternate syntax (n number of =/-) + +Header Level 1 ->

Content

+================ -### h3 +Header Level 2 ->

Content

+---------------- -#### h4 +Paragraph tags -##### h5 +Hello world ->

Hello world

-###### h6 +This is also +a paragraph ->

this is also a paragraph regardless

+regardless +However +this is a break, because it ends with two spaces ->

However
this is a break, because it ends with two spaces

+ +Double returns also + +yields new paragraphs ->

Double returns also

yields new paragraphs

+ + +*italic* -> italic +**bold** -> bold +***italic bold*** -> italic bold + +hello **world** -> [TextClass: hello, BoldClass: world] From 9d58f08984e47171335da2e60d6410b8ffbd6fb7 Mon Sep 17 00:00:00 2001 From: Hayden Hargreaves Date: Wed, 29 Oct 2025 15:11:01 -0700 Subject: [PATCH 5/5] (FIX): Needed to include these for testing --- src/main.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 3c8a116..81ee88a 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -69,7 +69,8 @@ void test_input(int argc, char **argv) { void test_document_converter() { DocumentConverter dc("test/input.md"); - dc.Convert(); + dc.ConvertWatcher(); } -int main(int argc, char **argv) { test_document_converter(); } +int main(int argc, char **argv) { + test_document_converter(); }