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);
}
--
2.47.2
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
--
2.47.2
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) {
--
2.47.2
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]
--
2.47.2
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(); }
--
2.47.2