mirror of
https://github.com/tomasriveral/NoteWrapper.git
synced 2026-08-11 18:18:36 +02:00
format: fix whole project
This commit is contained in:
+566
-428
File diff suppressed because it is too large
Load Diff
+301
-224
@@ -1,67 +1,81 @@
|
|||||||
#include "notes.h"
|
#include "notes.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
|
|
||||||
char *getDirectoryFromVault(char *targetVault, char **vaultsArray, int vaultTotalNumber, int *vaultNumberPerDirectory, char **directoryArray, int directoryNumber, int shouldDebug) {
|
char *getDirectoryFromVault(char *targetVault, char **vaultsArray, int vaultTotalNumber,
|
||||||
debug("Searching the vault %s inside all the directories...", targetVault);
|
int *vaultNumberPerDirectory, char **directoryArray,
|
||||||
debug("Here are how many vaults there is per directory:");
|
int directoryNumber, int shouldDebug) {
|
||||||
for (int i = 0; i < directoryNumber; i++) {
|
debug("Searching the vault %s inside all the directories...", targetVault);
|
||||||
altDebug("%d for %s\n", vaultNumberPerDirectory[i], directoryArray[i]);
|
debug("Here are how many vaults there is per directory:");
|
||||||
}
|
for (int i = 0; i < directoryNumber; i++) {
|
||||||
debug("Here are all the vaults in the order they will be searched:");
|
altDebug("%d for %s\n", vaultNumberPerDirectory[i], directoryArray[i]);
|
||||||
for (int i = 0; i < vaultTotalNumber; i++) {
|
}
|
||||||
altDebug("%s\n", vaultsArray[i]);
|
debug("Here are all the vaults in the order they will be searched:");
|
||||||
}
|
for (int i = 0; i < vaultTotalNumber; i++) {
|
||||||
int index = 0;
|
altDebug("%s\n", vaultsArray[i]);
|
||||||
|
}
|
||||||
|
int index = 0;
|
||||||
|
|
||||||
for (int i = 0; i < directoryNumber; i++) {
|
for (int i = 0; i < directoryNumber; i++) {
|
||||||
for (int j = 0; j < vaultNumberPerDirectory[i]; j++) {
|
for (int j = 0; j < vaultNumberPerDirectory[i]; j++) {
|
||||||
if (strcmp(vaultsArray[index], targetVault) == 0) {
|
if (strcmp(vaultsArray[index], targetVault) == 0) {
|
||||||
debug("%s found in %s. (index %d)", targetVault, directoryArray[i], index);
|
debug("%s found in %s. (index %d)", targetVault, directoryArray[i], index);
|
||||||
return directoryArray[i];
|
return directoryArray[i];
|
||||||
}
|
}
|
||||||
index++;
|
index++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
error(1, "program", "the vault %s was not found", targetVault);
|
error(1, "program", "the vault %s was not found", targetVault);
|
||||||
return "this makes the compiler and clangd happy. Who doesn't want GCC and clangd to be happy? Such person would be a terrible monster... One must imagine GCC and clangd happy.";
|
return "this makes the compiler and clangd happy. Who doesn't want GCC and clangd to be happy? "
|
||||||
|
"Such person would be a terrible monster... One must imagine GCC and clangd happy.";
|
||||||
}
|
}
|
||||||
|
|
||||||
char **getJournalsFromVault(char *pathToVault, char *vault, char *journalRegex, int *count, int shouldDebug) {
|
char **getJournalsFromVault(char *pathToVault, char *vault, char *journalRegex, int *count,
|
||||||
|
int shouldDebug) {
|
||||||
debug("Searching %s for journals", vault);
|
debug("Searching %s for journals", vault);
|
||||||
// originally from https://www.geeksforgeeks.org/c/c-program-list-files-sub-directories-directory/
|
// originally from
|
||||||
|
// https://www.geeksforgeeks.org/c/c-program-list-files-sub-directories-directory/
|
||||||
struct dirent *vaultEntry;
|
struct dirent *vaultEntry;
|
||||||
char tempPath[PATH_MAX];
|
char tempPath[PATH_MAX];
|
||||||
snprintf(tempPath, sizeof(tempPath), "%s/%s", pathToVault, vault); // sets the full absolute path to fullPathEntry
|
snprintf(tempPath, sizeof(tempPath), "%s/%s", pathToVault,
|
||||||
|
vault); // sets the full absolute path to fullPathEntry
|
||||||
DIR *vaultDirectory = opendir(tempPath);
|
DIR *vaultDirectory = opendir(tempPath);
|
||||||
error(vaultDirectory==NULL, "program", "Could not open directory %s", tempPath);
|
error(vaultDirectory == NULL, "program", "Could not open directory %s", tempPath);
|
||||||
char **journalsArray = NULL; // will contain all the notes
|
char **journalsArray = NULL; // will contain all the notes
|
||||||
int journalsCount = 0; // we need to count how many notes there is to always readjust how many memory we alloc
|
int journalsCount =
|
||||||
|
0; // we need to count how many notes there is to always readjust how many memory we alloc
|
||||||
|
|
||||||
// https://stackoverflow.com/a/1085120 for regex code
|
// https://stackoverflow.com/a/1085120 for regex code
|
||||||
regex_t regex;
|
regex_t regex;
|
||||||
int regexReturn;
|
int regexReturn;
|
||||||
// compiles the regex
|
// compiles the regex
|
||||||
regexReturn = regcomp(®ex, journalRegex, 0);
|
regexReturn = regcomp(®ex, journalRegex, 0);
|
||||||
error(regexReturn, "program", "Regex could not compile. Perhaps there is an error with the regex string");
|
error(regexReturn, "program",
|
||||||
|
"Regex could not compile. Perhaps there is an error with the regex string");
|
||||||
debug("Regex compiled succesfully");
|
debug("Regex compiled succesfully");
|
||||||
// Refer https://pubs.opengroup.org/onlinepubs/7990989775/xsh/readdir.html
|
// Refer https://pubs.opengroup.org/onlinepubs/7990989775/xsh/readdir.html
|
||||||
// for readdir()
|
// for readdir()
|
||||||
debug("┌------------------------------------------\nDetected files and dirs from the vault");
|
debug("┌------------------------------------------\nDetected files and dirs from the vault");
|
||||||
while ((vaultEntry = readdir(vaultDirectory)) != NULL) { // we iterate over every entry from the dir. So files and dirs (. and .. included)
|
while (
|
||||||
altDebug("%s ", vaultEntry->d_name);
|
(vaultEntry = readdir(vaultDirectory)) !=
|
||||||
if (vaultEntry->d_name[0] != '.') { // if the entry don't start with a dot (so hidden dirs and hidden files)
|
NULL) { // we iterate over every entry from the dir. So files and dirs (. and .. included)
|
||||||
regexReturn = regexec(®ex, vaultEntry->d_name, 0, NULL, 0);
|
altDebug("%s ", vaultEntry->d_name);
|
||||||
if (!regexReturn) { // if the regex matches
|
if (vaultEntry->d_name[0] !=
|
||||||
altDebug("matched with the regex. It is a journal.\n");
|
'.') { // if the entry don't start with a dot (so hidden dirs and hidden files)
|
||||||
journalsArray = realloc(journalsArray, (journalsCount + 1)*sizeof(char*)); // resize notesArray so that
|
regexReturn = regexec(®ex, vaultEntry->d_name, 0, NULL, 0);
|
||||||
journalsArray[journalsCount] = strdup(vaultEntry->d_name); // copy the dir name into notesArray
|
if (!regexReturn) { // if the regex matches
|
||||||
journalsCount++;
|
altDebug("matched with the regex. It is a journal.\n");
|
||||||
|
journalsArray =
|
||||||
|
realloc(journalsArray,
|
||||||
|
(journalsCount + 1) * sizeof(char *)); // resize notesArray so that
|
||||||
|
journalsArray[journalsCount] =
|
||||||
|
strdup(vaultEntry->d_name); // copy the dir name into notesArray
|
||||||
|
journalsCount++;
|
||||||
|
} else {
|
||||||
|
altDebug("did not matched with the regex. It is a note.\n");
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
altDebug("did not matched with the regex. It is a note.\n");
|
altDebug(" was ignored\n");
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
altDebug(" was ignored\n");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
altDebug("└ ------------------------------\n");
|
altDebug("└ ------------------------------\n");
|
||||||
// free's some used memory
|
// free's some used memory
|
||||||
@@ -70,42 +84,57 @@ char **getJournalsFromVault(char *pathToVault, char *vault, char *journalRegex,
|
|||||||
return journalsArray;
|
return journalsArray;
|
||||||
}
|
}
|
||||||
|
|
||||||
char** getNotesFromVault(char *pathToVault, char *vault, char *journalRegex, int *count, int shouldDebug) {
|
char **getNotesFromVault(char *pathToVault, char *vault, char *journalRegex, int *count,
|
||||||
// this function is inputed a path to a vault (which was selected before) and outpus all the suitable notes (so not the hidden ones)
|
int shouldDebug) {
|
||||||
// originally from https://www.geeksforgeeks.org/c/c-program-list-files-sub-directories-directory/
|
// this function is inputed a path to a vault (which was selected before) and outpus all the
|
||||||
|
// suitable notes (so not the hidden ones) originally from
|
||||||
|
// https://www.geeksforgeeks.org/c/c-program-list-files-sub-directories-directory/
|
||||||
debug("Searching %s for notes", vault);
|
debug("Searching %s for notes", vault);
|
||||||
struct dirent *vaultEntry;
|
struct dirent *vaultEntry;
|
||||||
char tempPath[PATH_MAX];
|
char tempPath[PATH_MAX];
|
||||||
snprintf(tempPath, sizeof(tempPath), "%s/%s", pathToVault, vault); // sets the full absolute path to fullPathEntry
|
snprintf(tempPath, sizeof(tempPath), "%s/%s", pathToVault,
|
||||||
|
vault); // sets the full absolute path to fullPathEntry
|
||||||
DIR *vaultDirectory = opendir(tempPath);
|
DIR *vaultDirectory = opendir(tempPath);
|
||||||
error(vaultDirectory==NULL, "program", "Could not open directory %s", tempPath);
|
error(vaultDirectory == NULL, "program", "Could not open directory %s", tempPath);
|
||||||
char **notesArray = NULL; // will contain all the notes
|
char **notesArray = NULL; // will contain all the notes
|
||||||
int notesCount = 0; // we need to count how many notes there is to always readjust how many memory we alloc
|
int notesCount =
|
||||||
|
0; // we need to count how many notes there is to always readjust how many memory we alloc
|
||||||
// Refer https://pubs.opengroup.org/onlinepubs/7990989775/xsh/readdir.html
|
// Refer https://pubs.opengroup.org/onlinepubs/7990989775/xsh/readdir.html
|
||||||
// for readdir()
|
// for readdir()
|
||||||
debug("┌------------------------------\nDetected Files and dirs from the vault:");
|
debug("┌------------------------------\nDetected Files and dirs from the vault:");
|
||||||
while ((vaultEntry = readdir(vaultDirectory)) != NULL) {
|
while ((vaultEntry = readdir(vaultDirectory)) != NULL) {
|
||||||
char *entryName = vaultEntry->d_name;
|
char *entryName = vaultEntry->d_name;
|
||||||
int entryLenght = strlen(entryName);
|
int entryLenght = strlen(entryName);
|
||||||
altDebug("%s ", entryName);
|
altDebug("%s ", entryName);
|
||||||
// for the regex code https://stackoverflow.com/a/1085120
|
// for the regex code https://stackoverflow.com/a/1085120
|
||||||
regex_t regex;
|
regex_t regex;
|
||||||
int regexReturn;
|
int regexReturn;
|
||||||
// compiles the regex
|
// compiles the regex
|
||||||
regexReturn = regcomp(®ex, journalRegex, 0);
|
regexReturn = regcomp(®ex, journalRegex, 0);
|
||||||
if (entryName[0] != '.') { // if the entry don't start with a dot (so hidden dirs and hidden files)
|
if (entryName[0] !=
|
||||||
char fullPathEntry[PATH_MAX]; // creates a string of size of the maximum path lenght
|
'.') { // if the entry don't start with a dot (so hidden dirs and hidden files)
|
||||||
snprintf(fullPathEntry, sizeof(fullPathEntry), "%s/%s/%s", pathToVault, vault, entryName); // sets the full absolute path to fullPathEntry
|
char fullPathEntry[PATH_MAX]; // creates a string of size of the maximum path lenght
|
||||||
// check if it matches the regex. If it does not match regexReturn != 0.
|
snprintf(fullPathEntry, sizeof(fullPathEntry), "%s/%s/%s", pathToVault, vault,
|
||||||
regexReturn = regexec(®ex, entryName, 0, NULL, 0);
|
entryName); // sets the full absolute path to fullPathEntry
|
||||||
struct stat metadataPathEntry;
|
// check if it matches the regex. If it does not match regexReturn != 0.
|
||||||
if (stat(fullPathEntry, &metadataPathEntry) == 0 && entryName[entryLenght - 3] == '.' && entryName[entryLenght - 2] == 'm' && entryName[entryLenght - 1] == 'd' && regexReturn && S_ISREG(metadataPathEntry.st_mode)) { // if this entry is a file ending in .md and that does no match the regex
|
regexReturn = regexec(®ex, entryName, 0, NULL, 0);
|
||||||
notesArray = realloc(notesArray, (notesCount + 1)*sizeof(char*)); // resize notesArray so that
|
struct stat metadataPathEntry;
|
||||||
notesArray[notesCount] = strdup(entryName); // copy the dir name into notesArray
|
if (stat(fullPathEntry, &metadataPathEntry) == 0 && entryName[entryLenght - 3] == '.' &&
|
||||||
notesCount++;
|
entryName[entryLenght - 2] == 'm' && entryName[entryLenght - 1] == 'd' &&
|
||||||
altDebug("did not match with the regex. It is a note.\n");
|
regexReturn &&
|
||||||
} else if (!regexReturn) {altDebug("matched with the regex. It is a journal.\n");}
|
S_ISREG(metadataPathEntry.st_mode)) { // if this entry is a file ending in .md and
|
||||||
} else {altDebug("was ignored\n");}
|
// that does no match the regex
|
||||||
|
notesArray = realloc(notesArray, (notesCount + 1) *
|
||||||
|
sizeof(char *)); // resize notesArray so that
|
||||||
|
notesArray[notesCount] = strdup(entryName); // copy the dir name into notesArray
|
||||||
|
notesCount++;
|
||||||
|
altDebug("did not match with the regex. It is a note.\n");
|
||||||
|
} else if (!regexReturn) {
|
||||||
|
altDebug("matched with the regex. It is a journal.\n");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
altDebug("was ignored\n");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
altDebug("└ ------------------------------\n");
|
altDebug("└ ------------------------------\n");
|
||||||
|
|
||||||
@@ -115,166 +144,214 @@ char** getNotesFromVault(char *pathToVault, char *vault, char *journalRegex, int
|
|||||||
return notesArray;
|
return notesArray;
|
||||||
}
|
}
|
||||||
|
|
||||||
char **getVaultsFromDirectories(char **directoryStringArray, int directoryNumber, int *vaultsPerDirectoryNumber, int *count, int shouldDebug) {
|
char **getVaultsFromDirectories(char **directoryStringArray, int directoryNumber,
|
||||||
// to avoid having to work with a tree-dimensional array. We will use a 2d and vaultsPerDirectoryNumber will indicate the width of the directories.
|
int *vaultsPerDirectoryNumber, int *count, int shouldDebug) {
|
||||||
char **vaultsArray = NULL;
|
// to avoid having to work with a tree-dimensional array. We will use a 2d and
|
||||||
int nthVault = 0; // this is only used internally to set the string into the right place in directoryStringArray.
|
// vaultsPerDirectoryNumber will indicate the width of the directories.
|
||||||
int previousStartIndex = 0;
|
char **vaultsArray = NULL;
|
||||||
for (int i = 0; i < directoryNumber; i++) {
|
int nthVault = 0; // this is only used internally to set the string into the right place in
|
||||||
debug("Opening %s", directoryStringArray[i]);
|
// directoryStringArray.
|
||||||
// originally from https://www.geeksforgeeks.org/c/c-program-list-files-sub-directories-directory/
|
int previousStartIndex = 0;
|
||||||
struct dirent *vaultsDirectoryEntry;
|
for (int i = 0; i < directoryNumber; i++) {
|
||||||
DIR *vaultsDirectory = opendir(directoryStringArray[i]);
|
debug("Opening %s", directoryStringArray[i]);
|
||||||
error(!vaultsDirectory, "program", "Could not open directory %s", directoryStringArray[i]);
|
// originally from
|
||||||
vaultsPerDirectoryNumber[i] = 0;
|
// https://www.geeksforgeeks.org/c/c-program-list-files-sub-directories-directory/
|
||||||
debug("┌------------------------------\n Detected files and dirs %s:", directoryStringArray[i]);
|
struct dirent *vaultsDirectoryEntry;
|
||||||
// Refer https://pubs.opengroup.org/onlinepubs/7990989775/xsh/readdir.html
|
DIR *vaultsDirectory = opendir(directoryStringArray[i]);
|
||||||
// for readdir()
|
error(!vaultsDirectory, "program", "Could not open directory %s", directoryStringArray[i]);
|
||||||
while((vaultsDirectoryEntry = readdir(vaultsDirectory)) != NULL) {
|
vaultsPerDirectoryNumber[i] = 0;
|
||||||
char *entryName = vaultsDirectoryEntry->d_name; // gets the entry as a string value
|
debug("┌------------------------------\n Detected files and dirs %s:",
|
||||||
altDebug("%s", entryName);
|
directoryStringArray[i]);
|
||||||
if (entryName[0] != '.') { // if not hidden file/dir
|
// Refer https://pubs.opengroup.org/onlinepubs/7990989775/xsh/readdir.html
|
||||||
char tempFullEntryPath[PATH_MAX]; // we recreate the full path to check it's proprieties
|
// for readdir()
|
||||||
snprintf(tempFullEntryPath, PATH_MAX, "%s%s", directoryStringArray[i], entryName);
|
while ((vaultsDirectoryEntry = readdir(vaultsDirectory)) != NULL) {
|
||||||
altDebug(" (%s)", tempFullEntryPath);
|
char *entryName = vaultsDirectoryEntry->d_name; // gets the entry as a string value
|
||||||
//checking the metadata to see if it is a dir
|
altDebug("%s", entryName);
|
||||||
struct stat metadataEntry;
|
if (entryName[0] != '.') { // if not hidden file/dir
|
||||||
if (stat(tempFullEntryPath, &metadataEntry) == 0 && S_ISDIR(metadataEntry.st_mode)) { // get's the metadata (stat should return 0 if fails) and sees if it is a dir.
|
char tempFullEntryPath[PATH_MAX]; // we recreate the full path to check it's
|
||||||
altDebug(" is a vault");
|
// proprieties
|
||||||
vaultsArray = realloc(vaultsArray, sizeof(char *)*(nthVault + 1)); // resize vaultsArray
|
snprintf(tempFullEntryPath, PATH_MAX, "%s%s", directoryStringArray[i], entryName);
|
||||||
error(vaultsArray == NULL, "program", "realloc failed");
|
altDebug(" (%s)", tempFullEntryPath);
|
||||||
vaultsPerDirectoryNumber[i]++; // it will be used later to know which vaults goes into which directory
|
// checking the metadata to see if it is a dir
|
||||||
vaultsArray[nthVault] = strdup(entryName); // we use strdup and not strcpy, because memory used with opendir and readdir will be closed.
|
struct stat metadataEntry;
|
||||||
error(vaultsArray[nthVault] == NULL, "program", "strdup failed");
|
if (stat(tempFullEntryPath, &metadataEntry) == 0 &&
|
||||||
nthVault++; // it is used immediatly to set the vault into directoryStringArray
|
S_ISDIR(metadataEntry.st_mode)) { // get's the metadata (stat should return 0 if
|
||||||
} else {
|
// fails) and sees if it is a dir.
|
||||||
altDebug(" is not a vault (not a dir.)");
|
altDebug(" is a vault");
|
||||||
|
vaultsArray =
|
||||||
|
realloc(vaultsArray, sizeof(char *) * (nthVault + 1)); // resize vaultsArray
|
||||||
|
error(vaultsArray == NULL, "program", "realloc failed");
|
||||||
|
vaultsPerDirectoryNumber[i]++; // it will be used later to know which vaults
|
||||||
|
// goes into which directory
|
||||||
|
vaultsArray[nthVault] =
|
||||||
|
strdup(entryName); // we use strdup and not strcpy, because memory used with
|
||||||
|
// opendir and readdir will be closed.
|
||||||
|
error(vaultsArray[nthVault] == NULL, "program", "strdup failed");
|
||||||
|
nthVault++; // it is used immediatly to set the vault into directoryStringArray
|
||||||
|
} else {
|
||||||
|
altDebug(" is not a vault (not a dir.)");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
altDebug(" is not a vault (hidden file/dir)");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
// we sort entries for the same vault. We can't sort them all. This would break the order.
|
||||||
altDebug(" is not a vault (hidden file/dir)");
|
qsort(vaultsArray + previousStartIndex, nthVault - previousStartIndex, sizeof(const char *),
|
||||||
}
|
compareString); // sorts the vaults alphabetically
|
||||||
|
closedir(vaultsDirectory);
|
||||||
|
previousStartIndex = nthVault;
|
||||||
}
|
}
|
||||||
// we sort entries for the same vault. We can't sort them all. This would break the order.
|
// we calculate once the total number of vaults to avoid recalculation every time we use it
|
||||||
qsort(vaultsArray + previousStartIndex, nthVault - previousStartIndex, sizeof(const char *), compareString); // sorts the vaults alphabetically
|
*count = 0;
|
||||||
closedir(vaultsDirectory);
|
for (int i = 0; i < directoryNumber; i++) {
|
||||||
previousStartIndex = nthVault;
|
*count += vaultsPerDirectoryNumber[i];
|
||||||
}
|
}
|
||||||
// we calculate once the total number of vaults to avoid recalculation every time we use it
|
return vaultsArray;
|
||||||
*count = 0;
|
|
||||||
for (int i = 0; i < directoryNumber; i++) {
|
|
||||||
*count += vaultsPerDirectoryNumber[i];
|
|
||||||
}
|
|
||||||
return vaultsArray;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
char *updateJournal(char *path, char *journal, char *timeFormat, int *journalWasUpdated, int shouldDebug) {
|
char *updateJournal(char *path, char *journal, char *timeFormat, int *journalWasUpdated,
|
||||||
path[PATH_MAX] = '\0'; // it assures it is a string (Most cases this does nothing). But rewriting at least one bytes make the compile happy. He doesn't want to return an unchanged input.
|
int shouldDebug) {
|
||||||
debug("Handling the journal %s", path);
|
path[PATH_MAX] =
|
||||||
|
'\0'; // it assures it is a string (Most cases this does nothing). But rewriting at least
|
||||||
|
// one bytes make the compile happy. He doesn't want to return an unchanged input.
|
||||||
|
debug("Handling the journal %s", path);
|
||||||
|
|
||||||
char *date = getFormatedTime(timeFormat, shouldDebug);
|
char *date = getFormatedTime(timeFormat, shouldDebug);
|
||||||
debug("Formated time for the journal's entry is %s", date);
|
debug("Formated time for the journal's entry is %s", date);
|
||||||
char dateWithExtension[PATH_MAX];
|
char dateWithExtension[PATH_MAX];
|
||||||
snprintf(dateWithExtension, PATH_MAX, "%s.md", date);
|
snprintf(dateWithExtension, PATH_MAX, "%s.md", date);
|
||||||
sanitize(dateWithExtension);
|
sanitize(dateWithExtension);
|
||||||
debug("Sanitized date: %s\n(it might be used later for a file name if the journal is divided)", dateWithExtension);
|
debug("Sanitized date: %s\n(it might be used later for a file name if the journal is divided)",
|
||||||
struct stat metadata;
|
dateWithExtension);
|
||||||
stat(path, &metadata);
|
struct stat metadata;
|
||||||
if (S_ISREG(metadata.st_mode)) {
|
stat(path, &metadata);
|
||||||
debug("%s is a unified journal.", path);
|
if (S_ISREG(metadata.st_mode)) {
|
||||||
if (!isStringInFile(path, date, shouldDebug)) { // if there is no entry for current date
|
debug("%s is a unified journal.", path);
|
||||||
appendToFile(path, date, shouldDebug);
|
if (!isStringInFile(path, date, shouldDebug)) { // if there is no entry for current date
|
||||||
*journalWasUpdated = 1;
|
appendToFile(path, date, shouldDebug);
|
||||||
} // if there is an entry do nothing
|
*journalWasUpdated = 1;
|
||||||
} else if (S_ISDIR(metadata.st_mode)) {
|
} // if there is an entry do nothing
|
||||||
debug("%s is a divided journal.", path);
|
} else if (S_ISDIR(metadata.st_mode)) {
|
||||||
struct dirent *dividedJournalEntry;
|
debug("%s is a divided journal.", path);
|
||||||
// snprintf does not like to have the same variable as input and output so we use a buffer
|
struct dirent *dividedJournalEntry;
|
||||||
char temp[PATH_MAX];
|
|
||||||
snprintf(temp, PATH_MAX, "%s/", path); // appends a /. For safety
|
|
||||||
strncpy(path, temp, PATH_MAX);
|
|
||||||
DIR *dividedJournalDirectory = opendir(path);
|
|
||||||
error(dividedJournalDirectory==NULL, "program", "Could not open directory %s", path);
|
|
||||||
/*char **entryArray = NULL; // will contain all the entries of the divided journal
|
|
||||||
// This time it will be different. We must add "invert" the extraOptions to the options so that the Create new entry in journal is on top
|
|
||||||
entryArray = realloc(entryArray, sizeof(char*));*/
|
|
||||||
// simpler to just malloc 2 and later realloc
|
|
||||||
const int extraOptions = 3;
|
|
||||||
char **entryArray = malloc(extraOptions*sizeof(char*));
|
|
||||||
char *createEntryMessage = malloc(PATH_MAX);
|
|
||||||
snprintf(createEntryMessage, PATH_MAX, "Create new entry for the journal %s", journal);
|
|
||||||
entryArray[0] = createEntryMessage;
|
|
||||||
entryArray[1] = "Open random entry";
|
|
||||||
entryArray[2] = "Search inside entries";
|
|
||||||
int entryCount = extraOptions; // we need to count how many dirs there is to always readjust how many memory we alloc
|
|
||||||
// Refer https://pubs.opengroup.org/onlinepubs/7990989775/xsh/readdir.html
|
|
||||||
// for readdir()
|
|
||||||
debug("┌------------------------------\n Detected files and dirs from %s:", path);
|
|
||||||
// iterates over all the entries from the dir
|
|
||||||
while ((dividedJournalEntry = readdir(dividedJournalDirectory)) != NULL) {
|
|
||||||
altDebug("%s\n", dividedJournalEntry->d_name);
|
|
||||||
if (dividedJournalEntry->d_name[0] != '.') { // if the entry don't start with a dot (so hidden dirs and hidden files)
|
|
||||||
char fullPathEntry[PATH_MAX]; // creates a string of size of the maximum path lenght
|
|
||||||
snprintf(fullPathEntry, sizeof(fullPathEntry), "%s/%s", path, dividedJournalEntry->d_name); // sets the full absolute path to fullPathEntry
|
|
||||||
|
|
||||||
struct stat metadataPathEntry;
|
|
||||||
if (stat(fullPathEntry, &metadataPathEntry) == 0 && S_ISREG(metadataPathEntry.st_mode)) { // if this entry is a directory
|
|
||||||
entryArray = realloc(entryArray, (entryCount + 1)*sizeof(char*));
|
|
||||||
entryArray[entryCount] = strdup(dividedJournalEntry->d_name); // copy the dir name into entryArray
|
|
||||||
entryCount++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
altDebug("└------------------------------\n");
|
|
||||||
// free's some used memory
|
|
||||||
closedir(dividedJournalDirectory);
|
|
||||||
qsort(entryArray + extraOptions, entryCount - extraOptions, sizeof(const char *), reverseCompareString); // sorts the journals entries alphabetically. // the + extraOptions - extraOptions is to not sort "Create new entry for the journal" or Open random entry which is the first element
|
|
||||||
|
|
||||||
// we must now select to create new entry or to enter in old one
|
|
||||||
char *selectedOption = ncursesSelect(entryArray, "Create new entry or acces old entry (Use arrows or WASD, Enter to select):", extraOptions, entryCount - extraOptions, " ", " ", "", shouldDebug); // the "Create new entry for the journal %s" will be the only options. All other will be extraOptions. This is made so that "Create [...] %s" will always be on top
|
|
||||||
debug("Selected option from journal entry selection: %s", selectedOption);
|
|
||||||
if (strcmp(selectedOption, createEntryMessage) == 0) { // create new entry
|
|
||||||
char temp[PATH_MAX];
|
|
||||||
error(strlen(path)+1+strlen(dateWithExtension)+1>PATH_MAX, "Error file path too long. %s/%s must not exceed PATH_MAX", path, dateWithExtension);
|
|
||||||
snprintf(temp, PATH_MAX, "%s/%s", path, dateWithExtension);
|
|
||||||
strncpy(path, temp, PATH_MAX);
|
|
||||||
if (!isStringInArray(dateWithExtension, (const char **)entryArray, entryCount)) { // it only creates it if it doesn't already exist
|
|
||||||
// if it does exist it will just pass the full path
|
|
||||||
debug("Creating entry %s inside %s", date, path);
|
|
||||||
FILE *file;
|
|
||||||
file = fopen(path, "w");
|
|
||||||
error(file == NULL, "program", "%s couldn't be created", path);
|
|
||||||
debug("Writing %s\\n to %s", date, path);
|
|
||||||
fprintf(file, "%s\n", date);
|
|
||||||
fclose(file);
|
|
||||||
free(createEntryMessage);
|
|
||||||
*journalWasUpdated = 1;
|
|
||||||
} else {
|
|
||||||
debug("Today's entry (%s) already exist. We won't create a new one.", dateWithExtension);
|
|
||||||
}
|
|
||||||
} else if (strcmp(selectedOption, entryArray[1]) == 0) { // if we choosed to open a random entry
|
|
||||||
// setting up the seed for rand()
|
|
||||||
srand(time(NULL)); // not totaly random, just pseudorandom
|
|
||||||
int randomEntry = extraOptions + (rand() % (entryCount - extraOptions)); // we get a random number between extraOptions and entryCount (so all journal entries and not extraOptions)
|
|
||||||
char temp[PATH_MAX];
|
|
||||||
snprintf(temp, PATH_MAX, "%s/%s", path, entryArray[randomEntry]); // reconstruct the path
|
|
||||||
strncpy(path, temp, PATH_MAX);
|
|
||||||
debug("Selected random entry %s. It's path is %s.", entryArray[randomEntry], path);
|
|
||||||
} else if (strcmp(selectedOption, entryArray[2]) == 0) { // if we choosed to search
|
|
||||||
char *temp = fzfSelect(path, "Input text to be searched", shouldDebug); // uses ripgrep and fzf to search inside the files
|
|
||||||
char *selectedOption = malloc(PATH_MAX); // we can't just use path as both input and output of snprintf
|
|
||||||
snprintf(selectedOption, PATH_MAX, "%s/%s", path, temp);
|
|
||||||
path = strdup(selectedOption);
|
|
||||||
free(selectedOption);
|
|
||||||
} else { // we just recreate the path to the selected entry
|
|
||||||
// snprintf does not like to have the same variable as input and output so we use a buffer
|
// snprintf does not like to have the same variable as input and output so we use a buffer
|
||||||
char temp[PATH_MAX];
|
char temp[PATH_MAX];
|
||||||
snprintf(temp, PATH_MAX, "%s/%s", path, selectedOption);
|
snprintf(temp, PATH_MAX, "%s/", path); // appends a /. For safety
|
||||||
strncpy(path, temp, PATH_MAX);
|
strncpy(path, temp, PATH_MAX);
|
||||||
debug("Returning path to the selected entry: %s", path);
|
DIR *dividedJournalDirectory = opendir(path);
|
||||||
}
|
error(dividedJournalDirectory == NULL, "program", "Could not open directory %s", path);
|
||||||
} else {
|
/*char **entryArray = NULL; // will contain all the entries of the divided journal
|
||||||
error(1, "program", "%s is not a file and not a directory.", path);
|
// This time it will be different. We must add "invert" the extraOptions to the options so
|
||||||
}
|
that the Create new entry in journal is on top entryArray = realloc(entryArray,
|
||||||
|
sizeof(char*));*/
|
||||||
return path;
|
// simpler to just malloc 2 and later realloc
|
||||||
|
const int extraOptions = 3;
|
||||||
|
char **entryArray = malloc(extraOptions * sizeof(char *));
|
||||||
|
char *createEntryMessage = malloc(PATH_MAX);
|
||||||
|
snprintf(createEntryMessage, PATH_MAX, "Create new entry for the journal %s", journal);
|
||||||
|
entryArray[0] = createEntryMessage;
|
||||||
|
entryArray[1] = "Open random entry";
|
||||||
|
entryArray[2] = "Search inside entries";
|
||||||
|
int entryCount = extraOptions; // we need to count how many dirs there is to always readjust
|
||||||
|
// how many memory we alloc
|
||||||
|
// Refer https://pubs.opengroup.org/onlinepubs/7990989775/xsh/readdir.html
|
||||||
|
// for readdir()
|
||||||
|
debug("┌------------------------------\n Detected files and dirs from %s:", path);
|
||||||
|
// iterates over all the entries from the dir
|
||||||
|
while ((dividedJournalEntry = readdir(dividedJournalDirectory)) != NULL) {
|
||||||
|
altDebug("%s\n", dividedJournalEntry->d_name);
|
||||||
|
if (dividedJournalEntry->d_name[0] !=
|
||||||
|
'.') { // if the entry don't start with a dot (so hidden dirs and hidden files)
|
||||||
|
char fullPathEntry[PATH_MAX]; // creates a string of size of the maximum path lenght
|
||||||
|
snprintf(
|
||||||
|
fullPathEntry, sizeof(fullPathEntry), "%s/%s", path,
|
||||||
|
dividedJournalEntry->d_name); // sets the full absolute path to fullPathEntry
|
||||||
|
|
||||||
|
struct stat metadataPathEntry;
|
||||||
|
if (stat(fullPathEntry, &metadataPathEntry) == 0 &&
|
||||||
|
S_ISREG(metadataPathEntry.st_mode)) { // if this entry is a directory
|
||||||
|
entryArray = realloc(entryArray, (entryCount + 1) * sizeof(char *));
|
||||||
|
entryArray[entryCount] =
|
||||||
|
strdup(dividedJournalEntry->d_name); // copy the dir name into entryArray
|
||||||
|
entryCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
altDebug("└------------------------------\n");
|
||||||
|
// free's some used memory
|
||||||
|
closedir(dividedJournalDirectory);
|
||||||
|
qsort(entryArray + extraOptions, entryCount - extraOptions, sizeof(const char *),
|
||||||
|
reverseCompareString); // sorts the journals entries alphabetically. // the +
|
||||||
|
// extraOptions - extraOptions is to not sort "Create new entry
|
||||||
|
// for the journal" or Open random entry which is the first
|
||||||
|
// element
|
||||||
|
|
||||||
|
// we must now select to create new entry or to enter in old one
|
||||||
|
char *selectedOption = ncursesSelect(
|
||||||
|
entryArray,
|
||||||
|
"Create new entry or acces old entry (Use arrows or WASD, Enter to select):",
|
||||||
|
extraOptions, entryCount - extraOptions, " ", " ", "",
|
||||||
|
shouldDebug); // the "Create new entry for the journal %s" will be the only options. All
|
||||||
|
// other will be extraOptions. This is made so that "Create [...] %s" will
|
||||||
|
// always be on top
|
||||||
|
debug("Selected option from journal entry selection: %s", selectedOption);
|
||||||
|
if (strcmp(selectedOption, createEntryMessage) == 0) { // create new entry
|
||||||
|
char temp[PATH_MAX];
|
||||||
|
error(strlen(path) + 1 + strlen(dateWithExtension) + 1 > PATH_MAX,
|
||||||
|
"Error file path too long. %s/%s must not exceed PATH_MAX", path,
|
||||||
|
dateWithExtension);
|
||||||
|
snprintf(temp, PATH_MAX, "%s/%s", path, dateWithExtension);
|
||||||
|
strncpy(path, temp, PATH_MAX);
|
||||||
|
if (!isStringInArray(dateWithExtension, (const char **)entryArray,
|
||||||
|
entryCount)) { // it only creates it if it doesn't already exist
|
||||||
|
// if it does exist it will just pass the full path
|
||||||
|
debug("Creating entry %s inside %s", date, path);
|
||||||
|
FILE *file;
|
||||||
|
file = fopen(path, "w");
|
||||||
|
error(file == NULL, "program", "%s couldn't be created", path);
|
||||||
|
debug("Writing %s\\n to %s", date, path);
|
||||||
|
fprintf(file, "%s\n", date);
|
||||||
|
fclose(file);
|
||||||
|
free(createEntryMessage);
|
||||||
|
*journalWasUpdated = 1;
|
||||||
|
} else {
|
||||||
|
debug("Today's entry (%s) already exist. We won't create a new one.",
|
||||||
|
dateWithExtension);
|
||||||
|
}
|
||||||
|
} else if (strcmp(selectedOption, entryArray[1]) ==
|
||||||
|
0) { // if we choosed to open a random entry
|
||||||
|
// setting up the seed for rand()
|
||||||
|
srand(time(NULL)); // not totaly random, just pseudorandom
|
||||||
|
int randomEntry =
|
||||||
|
extraOptions +
|
||||||
|
(rand() %
|
||||||
|
(entryCount -
|
||||||
|
extraOptions)); // we get a random number between extraOptions and entryCount (so
|
||||||
|
// all journal entries and not extraOptions)
|
||||||
|
char temp[PATH_MAX];
|
||||||
|
snprintf(temp, PATH_MAX, "%s/%s", path,
|
||||||
|
entryArray[randomEntry]); // reconstruct the path
|
||||||
|
strncpy(path, temp, PATH_MAX);
|
||||||
|
debug("Selected random entry %s. It's path is %s.", entryArray[randomEntry], path);
|
||||||
|
} else if (strcmp(selectedOption, entryArray[2]) == 0) { // if we choosed to search
|
||||||
|
char *temp = fzfSelect(path, "Input text to be searched",
|
||||||
|
shouldDebug); // uses ripgrep and fzf to search inside the files
|
||||||
|
char *selectedOption =
|
||||||
|
malloc(PATH_MAX); // we can't just use path as both input and output of snprintf
|
||||||
|
snprintf(selectedOption, PATH_MAX, "%s/%s", path, temp);
|
||||||
|
path = strdup(selectedOption);
|
||||||
|
free(selectedOption);
|
||||||
|
} else { // we just recreate the path to the selected entry
|
||||||
|
// snprintf does not like to have the same variable as input and output so we use a
|
||||||
|
// buffer
|
||||||
|
char temp[PATH_MAX];
|
||||||
|
snprintf(temp, PATH_MAX, "%s/%s", path, selectedOption);
|
||||||
|
strncpy(path, temp, PATH_MAX);
|
||||||
|
debug("Returning path to the selected entry: %s", path);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
error(1, "program", "%s is not a file and not a directory.", path);
|
||||||
|
}
|
||||||
|
|
||||||
|
return path;
|
||||||
}
|
}
|
||||||
|
|||||||
+22
-15
@@ -1,23 +1,29 @@
|
|||||||
#ifndef NOTES_H
|
#ifndef NOTES_H
|
||||||
#define NOTES_H
|
#define NOTES_H
|
||||||
#include "utils.h"
|
|
||||||
#include "ui.h"
|
#include "ui.h"
|
||||||
|
#include "utils.h"
|
||||||
// find which directory contains targetVault
|
// find which directory contains targetVault
|
||||||
char *getDirectoryFromVault(char *targetVault, char **vaultsArray, int vaultTotalNumber, int *vaultNumberPerDirectory, char **directoryArray, int directoryNumber, int shouldDebug);
|
char *getDirectoryFromVault(char *targetVault, char **vaultsArray, int vaultTotalNumber,
|
||||||
|
int *vaultNumberPerDirectory, char **directoryArray,
|
||||||
|
int directoryNumber, int shouldDebug);
|
||||||
// gets the journals from the vault.
|
// gets the journals from the vault.
|
||||||
//to distinguish journals from note we use regex.
|
// to distinguish journals from note we use regex.
|
||||||
//Note: we must handle them separatly as journals can either be a single file (which will treat specially) or a directory.
|
// Note: we must handle them separatly as journals can either be a single file (which will treat
|
||||||
char **getJournalsFromVault(char *pathToVault, char *vault, char *journalRegex, int *count, int shouldDebug);
|
// specially) or a directory.
|
||||||
// this function is inputed a path to a vault (which was selected before) and outpus all the suitable notes (so not the hidden ones).
|
char **getJournalsFromVault(char *pathToVault, char *vault, char *journalRegex, int *count,
|
||||||
// journalRegex is the regex code for the journals. If a note matches this code, it is treated as a journal and it is not outputed from this function.
|
int shouldDebug);
|
||||||
char **getNotesFromVault(char *pathToVault, char *vault, char *journalRegex, int *count, int shouldDebug);
|
// this function is inputed a path to a vault (which was selected before) and outpus all the
|
||||||
// function gets as input an array of directoryNumber strings. Which are the directories the function will search for vaults.
|
// suitable notes (so not the hidden ones). journalRegex is the regex code for the journals. If a
|
||||||
// it returns an array of vaults.
|
// note matches this code, it is treated as a journal and it is not outputed from this function.
|
||||||
// the vaults are organized in order per directory.
|
char **getNotesFromVault(char *pathToVault, char *vault, char *journalRegex, int *count,
|
||||||
// vaultsPerDirectoryNumber and count should be initiallized before calling the function and the address be inputed.
|
int shouldDebug);
|
||||||
// count is the total number of vaults.
|
// function gets as input an array of directoryNumber strings. Which are the directories the
|
||||||
|
// function will search for vaults. it returns an array of vaults. the vaults are organized in order
|
||||||
|
// per directory. vaultsPerDirectoryNumber and count should be initiallized before calling the
|
||||||
|
// function and the address be inputed. count is the total number of vaults.
|
||||||
// vaultsPerDirectoryNumber gives how many vaults each directory has.
|
// vaultsPerDirectoryNumber gives how many vaults each directory has.
|
||||||
char **getVaultsFromDirectories(char **directoryStringArray, int directoryNumber, int *vaultsPerDirectoryNumber, int *count, int shouldDebug);
|
char **getVaultsFromDirectories(char **directoryStringArray, int directoryNumber,
|
||||||
|
int *vaultsPerDirectoryNumber, int *count, int shouldDebug);
|
||||||
// path is the path to the file.
|
// path is the path to the file.
|
||||||
// journal is the name of the file.
|
// journal is the name of the file.
|
||||||
// journalWasUpdated will be set to 1 if a new entry was created
|
// journalWasUpdated will be set to 1 if a new entry was created
|
||||||
@@ -25,5 +31,6 @@ char **getVaultsFromDirectories(char **directoryStringArray, int directoryNumber
|
|||||||
// creates new entry with date.
|
// creates new entry with date.
|
||||||
// for divided select if we want to acces to a new entry or a old one.
|
// for divided select if we want to acces to a new entry or a old one.
|
||||||
// returns the path to the file that needs to be opened.
|
// returns the path to the file that needs to be opened.
|
||||||
char *updateJournal(char *path, char *journal, char *timeFormat, int *journalWasUpdated, int shouldDebug);
|
char *updateJournal(char *path, char *journal, char *timeFormat, int *journalWasUpdated,
|
||||||
|
int shouldDebug);
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -1,163 +1,187 @@
|
|||||||
#include "ui.h"
|
#include "ui.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
|
|
||||||
void createNewVault(char **directoriesArray, int directoryCount, char **vaultsArray, int vaultCount, int bypass, char *bypassvalue, int shouldDebug) {
|
void createNewVault(char **directoriesArray, int directoryCount, char **vaultsArray, int vaultCount,
|
||||||
int duplicateWarning = 0; // set to 1 later if the vault you tried to create already existed
|
int bypass, char *bypassvalue, int shouldDebug) {
|
||||||
int emptyWarning = 0; // set to 1 later if inpted empty name
|
int duplicateWarning = 0; // set to 1 later if the vault you tried to create already existed
|
||||||
|
int emptyWarning = 0; // set to 1 later if inpted empty name
|
||||||
input_screen:
|
input_screen:
|
||||||
// choose in which directory the vault will be created
|
// choose in which directory the vault will be created
|
||||||
char *dirToVault = ncursesSelect(directoriesArray, "Select a directory, in which the vault will remain (Use arrows or WASD, Enter to select)", directoryCount, 0, "", "", " ", shouldDebug);
|
char *dirToVault = ncursesSelect(
|
||||||
char *vaultName = malloc(PATH_MAX);
|
directoriesArray,
|
||||||
if (!bypass) { // if won't bypass (if -v or --vault weren't set)
|
"Select a directory, in which the vault will remain (Use arrows or WASD, Enter to select)",
|
||||||
echo();
|
directoryCount, 0, "", "", " ", shouldDebug);
|
||||||
keypad(stdscr, FALSE);
|
char *vaultName = malloc(PATH_MAX);
|
||||||
// color code from https://stackoverflow.com/a/73396575
|
if (!bypass) { // if won't bypass (if -v or --vault weren't set)
|
||||||
start_color();
|
echo();
|
||||||
clear();
|
keypad(stdscr, FALSE);
|
||||||
use_default_colors();
|
// color code from https://stackoverflow.com/a/73396575
|
||||||
init_pair(1, COLOR_WHITE, -1); // -1 is blank
|
start_color();
|
||||||
init_pair(2, COLOR_RED, -1);
|
clear();
|
||||||
attron(COLOR_PAIR(1));
|
use_default_colors();
|
||||||
printw("Enter the name of the new vault: ");
|
init_pair(1, COLOR_WHITE, -1); // -1 is blank
|
||||||
mvprintw(3, 0, "Unsafe characters such as \\ and / will be replaced by _");
|
init_pair(2, COLOR_RED, -1);
|
||||||
attroff(COLOR_PAIR(1));
|
attron(COLOR_PAIR(1));
|
||||||
if (duplicateWarning) {
|
printw("Enter the name of the new vault: ");
|
||||||
attron(COLOR_PAIR(2));
|
mvprintw(3, 0, "Unsafe characters such as \\ and / will be replaced by _");
|
||||||
mvprintw(4, 0, "A vault with this name already exists. Please input another name");
|
attroff(COLOR_PAIR(1));
|
||||||
attroff(COLOR_PAIR(2));
|
if (duplicateWarning) {
|
||||||
|
attron(COLOR_PAIR(2));
|
||||||
|
mvprintw(4, 0, "A vault with this name already exists. Please input another name");
|
||||||
|
attroff(COLOR_PAIR(2));
|
||||||
|
}
|
||||||
|
if (emptyWarning) {
|
||||||
|
attron(COLOR_PAIR(2));
|
||||||
|
mvprintw(5, 0, "The vault's name must not be empty. Please input another name");
|
||||||
|
attroff(COLOR_PAIR(2));
|
||||||
|
}
|
||||||
|
move(1, 1); // replace cursor
|
||||||
|
wgetnstr(stdscr, vaultName, PATH_MAX - 1);
|
||||||
|
refresh();
|
||||||
|
endwin();
|
||||||
|
reset_shell_mode();
|
||||||
|
fflush(stdout);
|
||||||
|
fflush(stderr);
|
||||||
|
} else {
|
||||||
|
strncpy(vaultName, bypassvalue, PATH_MAX - 2); // -2 (and later -1) because indexing
|
||||||
|
vaultName[PATH_MAX - 1] = '\0';
|
||||||
}
|
}
|
||||||
if (emptyWarning) {
|
// check if no empty string
|
||||||
attron(COLOR_PAIR(2));
|
if (strcmp(vaultName, "") == 0) {
|
||||||
mvprintw(5, 0, "The vault's name must not be empty. Please input another name");
|
emptyWarning = 1;
|
||||||
attroff(COLOR_PAIR(2));
|
goto input_screen;
|
||||||
}
|
}
|
||||||
move(1, 1); // replace cursor
|
debug("Inputed vaultName=%s", vaultName);
|
||||||
wgetnstr(stdscr, vaultName, PATH_MAX-1);
|
sanitize(vaultName);
|
||||||
refresh();
|
debug("Sanitized vaultName=%s", vaultName);
|
||||||
endwin();
|
|
||||||
reset_shell_mode();
|
|
||||||
fflush(stdout);
|
|
||||||
fflush(stderr);
|
|
||||||
} else {
|
|
||||||
strncpy(vaultName, bypassvalue, PATH_MAX -2); // -2 (and later -1) because indexing
|
|
||||||
vaultName[PATH_MAX-1] = '\0';
|
|
||||||
}
|
|
||||||
// check if no empty string
|
|
||||||
if (strcmp(vaultName, "") == 0) {
|
|
||||||
emptyWarning = 1;
|
|
||||||
goto input_screen;
|
|
||||||
}
|
|
||||||
debug("Inputed vaultName=%s", vaultName);
|
|
||||||
sanitize(vaultName);
|
|
||||||
debug("Sanitized vaultName=%s", vaultName);
|
|
||||||
|
|
||||||
|
if (!isStringInArray(vaultName, (const char **)vaultsArray,
|
||||||
if (!isStringInArray(vaultName, (const char**)vaultsArray, vaultCount)) { // if vault doesnt already exists. We avoid vaults with the same name even if they are from different directories.
|
vaultCount)) { // if vault doesnt already exists. We avoid vaults with the
|
||||||
char vaultFullPath[PATH_MAX]; // recreating the full path
|
// same name even if they are from different directories.
|
||||||
sprintf(vaultFullPath, "%s/%s/", dirToVault, vaultName);
|
char vaultFullPath[PATH_MAX]; // recreating the full path
|
||||||
|
sprintf(vaultFullPath, "%s/%s/", dirToVault, vaultName);
|
||||||
|
|
||||||
mkdir(vaultFullPath, 0744);
|
mkdir(vaultFullPath, 0744);
|
||||||
} else {
|
} else {
|
||||||
duplicateWarning = 1;
|
duplicateWarning = 1;
|
||||||
goto input_screen;
|
goto input_screen;
|
||||||
}
|
}
|
||||||
free(vaultName);
|
free(vaultName);
|
||||||
}
|
}
|
||||||
|
|
||||||
char *createNewNote(char dirToVault[PATH_MAX], char *vaultFromDir, int bypass, char *bypassvalue, char *journalRegex, int shouldDebug) {
|
char *createNewNote(char dirToVault[PATH_MAX], char *vaultFromDir, int bypass, char *bypassvalue,
|
||||||
// input from user for the name
|
char *journalRegex, int shouldDebug) {
|
||||||
char *fileName = malloc(BUFFER_SIZE);
|
// input from user for the name
|
||||||
if (!bypass) { // if we don't bypass. (if -n or --note weren't set.)
|
char *fileName = malloc(BUFFER_SIZE);
|
||||||
echo();
|
if (!bypass) { // if we don't bypass. (if -n or --note weren't set.)
|
||||||
keypad(stdscr, FALSE);
|
echo();
|
||||||
clear();
|
keypad(stdscr, FALSE);
|
||||||
printw("Enter the name of the new note: ");
|
clear();
|
||||||
mvprintw(3, 0, "Unsafe characters such as \\, and / will be replaced by _");
|
printw("Enter the name of the new note: ");
|
||||||
mvprintw(4, 0, "If the name matches with the regex for a journal (%s), it will create a journal instead of a note.", journalRegex);
|
mvprintw(3, 0, "Unsafe characters such as \\, and / will be replaced by _");
|
||||||
move(1,1);
|
mvprintw(4, 0,
|
||||||
wgetnstr(stdscr, fileName, BUFFER_SIZE-4); //limits the buffer to prevent overflow (-4 to account indexing and from ".md" in case we need to add it later)
|
"If the name matches with the regex for a journal (%s), it will create a journal "
|
||||||
refresh();
|
"instead of a note.",
|
||||||
endwin();
|
journalRegex);
|
||||||
reset_shell_mode();
|
move(1, 1);
|
||||||
fflush(stdout);
|
wgetnstr(stdscr, fileName,
|
||||||
fflush(stderr);
|
BUFFER_SIZE - 4); // limits the buffer to prevent overflow (-4 to account indexing
|
||||||
} else { // bypasses user input if we bypass is set to 1
|
// and from ".md" in case we need to add it later)
|
||||||
strncpy(fileName, bypassvalue, BUFFER_SIZE);
|
refresh();
|
||||||
fileName[BUFFER_SIZE-1] = '\0';
|
endwin();
|
||||||
}
|
reset_shell_mode();
|
||||||
error(strcmp(fileName, "") == 0, "user", "fileName is empty"); // replace this with a warning and add a warning if duplicate file and handle case where multiple warnings (if such case is possible)
|
fflush(stdout);
|
||||||
// check/sanitize the input
|
fflush(stderr);
|
||||||
debug("Inputed fileName=%s", fileName);
|
} else { // bypasses user input if we bypass is set to 1
|
||||||
sanitize(fileName);
|
strncpy(fileName, bypassvalue, BUFFER_SIZE);
|
||||||
debug("Sanitized fileName=%s (We might append .md later", fileName);
|
fileName[BUFFER_SIZE - 1] = '\0';
|
||||||
// we trow an error if the file already exists (previous behaviour was overwriting the file)
|
|
||||||
char path[PATH_MAX];
|
|
||||||
snprintf(path, PATH_MAX, "%s/%s/%s", dirToVault, vaultFromDir, fileName);
|
|
||||||
struct stat st;
|
|
||||||
error(stat(path, &st) == 0, "user", "%s already exists", fileName);
|
|
||||||
// if it matches with the journalRegex we treat it as a journal instead of a note
|
|
||||||
regex_t regex;
|
|
||||||
int regexReturn = regcomp(®ex, journalRegex, 0);
|
|
||||||
error(regexReturn, "program", "Regex compilation failed.");
|
|
||||||
regexReturn = regexec(®ex, fileName, 0, NULL, 0);
|
|
||||||
if (!regexReturn) {
|
|
||||||
debug("%s matches with %s treating it as a journal", fileName, journalRegex);
|
|
||||||
char **options = malloc(32); // the number of bytes is exactly what in the two strings
|
|
||||||
options[0] = "Divided journal";
|
|
||||||
options[1] = "Unified journal";
|
|
||||||
char *optionSelected = ncursesSelect(options, "Select which type of journal you want to create (Use arrows or WASD, Enter to select):", 2, 0, "", "", " ", shouldDebug);
|
|
||||||
debug("%s was selected to be a %s", fileName, optionSelected);
|
|
||||||
if (strcmp(optionSelected, options[0]) == 0) { // if it is a divided journal
|
|
||||||
char *fileFullPath = malloc(PATH_MAX);
|
|
||||||
snprintf(fileFullPath, PATH_MAX, "%s/%s/%s/", dirToVault, vaultFromDir, fileName);
|
|
||||||
struct stat st = {0};
|
|
||||||
if (stat(fileFullPath, &st) == -1) {
|
|
||||||
error(mkdir(fileFullPath, 0744), "program", "mkdir failed");
|
|
||||||
} else {
|
|
||||||
error(1, "program", "%s could not be created", fileFullPath);
|
|
||||||
}
|
|
||||||
free(fileFullPath);
|
|
||||||
} else { // if it is a unified journal
|
|
||||||
char *fileFullPath = malloc(PATH_MAX);
|
|
||||||
snprintf(fileFullPath, PATH_MAX, "%s/%s/%s", dirToVault, vaultFromDir, fileName);
|
|
||||||
int len = strlen(fileFullPath);
|
|
||||||
if (fileFullPath[len-3] != '.' || fileFullPath[len-2] != 'm' || fileFullPath[len-1] != 'd') { // there might be a cleaner way to do this
|
|
||||||
error(len > PATH_MAX - 3, "user", "%s is too big (greater than PATH_MAX-3) and we can't append .md", fileFullPath);
|
|
||||||
strncat(fileFullPath, ".md", PATH_MAX);
|
|
||||||
// we checked before if fileName didn't already exist.
|
|
||||||
// we must redo it as we add a .mode
|
|
||||||
struct stat st;
|
|
||||||
error(stat(fileFullPath, &st) == 0, "user", "%s already exists", fileFullPath);
|
|
||||||
}
|
|
||||||
FILE *filePointer;
|
|
||||||
filePointer = fopen(fileFullPath, "w"); // creates and opens the file
|
|
||||||
error(filePointer == NULL, "program", "The %s couldn't be created.", fileFullPath);
|
|
||||||
fprintf(filePointer, "### %s\n", fileName);
|
|
||||||
fclose(filePointer); // closes the file so that nvim could open it
|
|
||||||
free(fileFullPath);
|
|
||||||
}
|
}
|
||||||
free(options); // they are useless now
|
error(
|
||||||
} else { // normal process for a note
|
strcmp(fileName, "") == 0, "user",
|
||||||
debug("%s does not match with %s treating it as a note", fileName, journalRegex);
|
"fileName is empty"); // replace this with a warning and add a warning if duplicate file and
|
||||||
// if there is no .md add an .md
|
// handle case where multiple warnings (if such case is possible)
|
||||||
int len = strlen(fileName);
|
// check/sanitize the input
|
||||||
if (fileName[len-3] != '.' || fileName[len-2] != 'm' || fileName[len-1] != 'd') { // there might be a cleaner way to do this
|
debug("Inputed fileName=%s", fileName);
|
||||||
strcat(fileName, ".md"); // this should not cause an overflow issue as we get at most 252 chars (+'.'+'m'+'d'+'\0' makes it to 256) with wgetnstr
|
sanitize(fileName);
|
||||||
|
debug("Sanitized fileName=%s (We might append .md later", fileName);
|
||||||
|
// we trow an error if the file already exists (previous behaviour was overwriting the file)
|
||||||
|
char path[PATH_MAX];
|
||||||
|
snprintf(path, PATH_MAX, "%s/%s/%s", dirToVault, vaultFromDir, fileName);
|
||||||
|
struct stat st;
|
||||||
|
error(stat(path, &st) == 0, "user", "%s already exists", fileName);
|
||||||
|
// if it matches with the journalRegex we treat it as a journal instead of a note
|
||||||
|
regex_t regex;
|
||||||
|
int regexReturn = regcomp(®ex, journalRegex, 0);
|
||||||
|
error(regexReturn, "program", "Regex compilation failed.");
|
||||||
|
regexReturn = regexec(®ex, fileName, 0, NULL, 0);
|
||||||
|
if (!regexReturn) {
|
||||||
|
debug("%s matches with %s treating it as a journal", fileName, journalRegex);
|
||||||
|
char **options = malloc(32); // the number of bytes is exactly what in the two strings
|
||||||
|
options[0] = "Divided journal";
|
||||||
|
options[1] = "Unified journal";
|
||||||
|
char *optionSelected = ncursesSelect(options,
|
||||||
|
"Select which type of journal you want to create "
|
||||||
|
"(Use arrows or WASD, Enter to select):",
|
||||||
|
2, 0, "", "", " ", shouldDebug);
|
||||||
|
debug("%s was selected to be a %s", fileName, optionSelected);
|
||||||
|
if (strcmp(optionSelected, options[0]) == 0) { // if it is a divided journal
|
||||||
|
char *fileFullPath = malloc(PATH_MAX);
|
||||||
|
snprintf(fileFullPath, PATH_MAX, "%s/%s/%s/", dirToVault, vaultFromDir, fileName);
|
||||||
|
struct stat st = {0};
|
||||||
|
if (stat(fileFullPath, &st) == -1) {
|
||||||
|
error(mkdir(fileFullPath, 0744), "program", "mkdir failed");
|
||||||
|
} else {
|
||||||
|
error(1, "program", "%s could not be created", fileFullPath);
|
||||||
|
}
|
||||||
|
free(fileFullPath);
|
||||||
|
} else { // if it is a unified journal
|
||||||
|
char *fileFullPath = malloc(PATH_MAX);
|
||||||
|
snprintf(fileFullPath, PATH_MAX, "%s/%s/%s", dirToVault, vaultFromDir, fileName);
|
||||||
|
int len = strlen(fileFullPath);
|
||||||
|
if (fileFullPath[len - 3] != '.' || fileFullPath[len - 2] != 'm' ||
|
||||||
|
fileFullPath[len - 1] != 'd') { // there might be a cleaner way to do this
|
||||||
|
error(len > PATH_MAX - 3, "user",
|
||||||
|
"%s is too big (greater than PATH_MAX-3) and we can't append .md",
|
||||||
|
fileFullPath);
|
||||||
|
strncat(fileFullPath, ".md", PATH_MAX);
|
||||||
|
// we checked before if fileName didn't already exist.
|
||||||
|
// we must redo it as we add a .mode
|
||||||
|
struct stat st;
|
||||||
|
error(stat(fileFullPath, &st) == 0, "user", "%s already exists", fileFullPath);
|
||||||
|
}
|
||||||
|
FILE *filePointer;
|
||||||
|
filePointer = fopen(fileFullPath, "w"); // creates and opens the file
|
||||||
|
error(filePointer == NULL, "program", "The %s couldn't be created.", fileFullPath);
|
||||||
|
fprintf(filePointer, "### %s\n", fileName);
|
||||||
|
fclose(filePointer); // closes the file so that nvim could open it
|
||||||
|
free(fileFullPath);
|
||||||
|
}
|
||||||
|
free(options); // they are useless now
|
||||||
|
} else { // normal process for a note
|
||||||
|
debug("%s does not match with %s treating it as a note", fileName, journalRegex);
|
||||||
|
// if there is no .md add an .md
|
||||||
|
int len = strlen(fileName);
|
||||||
|
if (fileName[len - 3] != '.' || fileName[len - 2] != 'm' ||
|
||||||
|
fileName[len - 1] != 'd') { // there might be a cleaner way to do this
|
||||||
|
strcat(fileName, ".md"); // this should not cause an overflow issue as we get at most
|
||||||
|
// 252 chars (+'.'+'m'+'d'+'\0' makes it to 256) with wgetnstr
|
||||||
|
}
|
||||||
|
char *fileFullPath = malloc(PATH_MAX); // this dinamically allocated because we use it in
|
||||||
|
// the main function to call openEditor
|
||||||
|
sprintf(fileFullPath, "%s/%s/%s", dirToVault, vaultFromDir, fileName);
|
||||||
|
FILE *filePointer;
|
||||||
|
filePointer = fopen(fileFullPath, "w"); // creates and opens the file
|
||||||
|
error(filePointer == NULL, "program", "The %s couldn't be created.", fileFullPath);
|
||||||
|
fprintf(filePointer, "### %s\n", fileName);
|
||||||
|
fclose(filePointer); // closes the file so that nvim could open it
|
||||||
|
free(fileFullPath);
|
||||||
}
|
}
|
||||||
char *fileFullPath = malloc(PATH_MAX); // this dinamically allocated because we use it in the main function to call openEditor
|
return fileName;
|
||||||
sprintf(fileFullPath, "%s/%s/%s", dirToVault, vaultFromDir, fileName);
|
|
||||||
FILE *filePointer;
|
|
||||||
filePointer = fopen(fileFullPath, "w"); // creates and opens the file
|
|
||||||
error(filePointer == NULL, "program", "The %s couldn't be created.", fileFullPath);
|
|
||||||
fprintf(filePointer, "### %s\n", fileName);
|
|
||||||
fclose(filePointer); // closes the file so that nvim could open it
|
|
||||||
free(fileFullPath);
|
|
||||||
}
|
|
||||||
return fileName;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
char* fzfSelect(char *pathToFiles, char *selectText, int shouldDebug) {
|
char *fzfSelect(char *pathToFiles, char *selectText, int shouldDebug) {
|
||||||
// we are gonna write each line of each files (with the filename and the line number to an index)
|
// we are gonna write each line of each files (with the filename and the line number to an
|
||||||
|
// index)
|
||||||
char command[CMD_BUFFER];
|
char command[CMD_BUFFER];
|
||||||
char indexFile[] = "/tmp/notewrapper_index_XXXXXX";
|
char indexFile[] = "/tmp/notewrapper_index_XXXXXX";
|
||||||
|
|
||||||
@@ -170,12 +194,9 @@ char* fzfSelect(char *pathToFiles, char *selectText, int shouldDebug) {
|
|||||||
* Build index once into temp file
|
* Build index once into temp file
|
||||||
* format: file:line:content
|
* format: file:line:content
|
||||||
*/
|
*/
|
||||||
snprintf(command, sizeof(command),
|
snprintf(command, sizeof(command), "rg --line-number --no-heading --color=never . \"%s\" > %s",
|
||||||
"rg --line-number --no-heading --color=never . \"%s\" > %s",
|
pathToFiles, indexFile);
|
||||||
pathToFiles,
|
|
||||||
indexFile
|
|
||||||
);
|
|
||||||
|
|
||||||
debug("INDEX CMD: %s", command);
|
debug("INDEX CMD: %s", command);
|
||||||
|
|
||||||
if (system(command) != 0) {
|
if (system(command) != 0) {
|
||||||
@@ -189,47 +210,47 @@ char* fzfSelect(char *pathToFiles, char *selectText, int shouldDebug) {
|
|||||||
*/
|
*/
|
||||||
/*
|
/*
|
||||||
EXPLANATION:
|
EXPLANATION:
|
||||||
|
|
||||||
cat %s
|
cat %s
|
||||||
→ feeds prebuilt index file (format: file:line:content) into fzf
|
→ feeds prebuilt index file (format: file:line:content) into fzf
|
||||||
|
|
||||||
fzf --delimiter ':'
|
fzf --delimiter ':'
|
||||||
→ splits each line into fields:
|
→ splits each line into fields:
|
||||||
{1} = file path
|
{1} = file path
|
||||||
{2} = line number
|
{2} = line number
|
||||||
{3} = content
|
{3} = content
|
||||||
|
|
||||||
--prompt
|
--prompt
|
||||||
→ UI prompt text shown in fzf
|
→ UI prompt text shown in fzf
|
||||||
|
|
||||||
--preview
|
--preview
|
||||||
→ runs a shell command for selected item:
|
→ runs a shell command for selected item:
|
||||||
file={1} → current file
|
file={1} → current file
|
||||||
line={2} → line number of match
|
line={2} → line number of match
|
||||||
|
|
||||||
nl -ba "$file"
|
nl -ba "$file"
|
||||||
→ prints file with line numbers
|
→ prints file with line numbers
|
||||||
|
|
||||||
sed -n "$((line-5)),$((line+5))p"
|
sed -n "$((line-5)),$((line+5))p"
|
||||||
→ extracts a window of 5 lines above and below match
|
→ extracts a window of 5 lines above and below match
|
||||||
|
|
||||||
sed "... -> ..."
|
sed "... -> ..."
|
||||||
→ highlights the matched line (middle of window) with red arrow
|
→ highlights the matched line (middle of window) with red arrow
|
||||||
|
|
||||||
--preview-window=right:60%:hidden
|
--preview-window=right:60%:hidden
|
||||||
→ preview appears on right, 60% width, initially hidden
|
→ preview appears on right, 60% width, initially hidden
|
||||||
|
|
||||||
--bind 'change:show-preview'
|
--bind 'change:show-preview'
|
||||||
→ preview only appears after first selection change (not at startup)
|
→ preview only appears after first selection change (not at startup)
|
||||||
*/
|
*/
|
||||||
snprintf(command, sizeof(command),
|
snprintf(
|
||||||
"cat %s | fzf --delimiter ':' --prompt='%s' "
|
command, sizeof(command),
|
||||||
"--preview 'file={1}; line={2}; nl -ba \"$file\" | sed -n \"$((line-5)),$((line+5))p\" | sed \"$((line-$(($((line-5))))+1))s/^/\\x1b[31m-> \\x1b[0m/\"' "
|
"cat %s | fzf --delimiter ':' --prompt='%s' "
|
||||||
"--preview-window=right:60%%:hidden "
|
"--preview 'file={1}; line={2}; nl -ba \"$file\" | sed -n \"$((line-5)),$((line+5))p\" | "
|
||||||
"--bind 'change:show-preview'",
|
"sed \"$((line-$(($((line-5))))+1))s/^/\\x1b[31m-> \\x1b[0m/\"' "
|
||||||
indexFile,
|
"--preview-window=right:60%%:hidden "
|
||||||
selectText ? selectText : "> "
|
"--bind 'change:show-preview'",
|
||||||
);
|
indexFile, selectText ? selectText : "> ");
|
||||||
debug("FZF CMD: %s", command);
|
debug("FZF CMD: %s", command);
|
||||||
|
|
||||||
FILE *fzfPipe = popen(command, "r");
|
FILE *fzfPipe = popen(command, "r");
|
||||||
@@ -252,8 +273,8 @@ char* fzfSelect(char *pathToFiles, char *selectText, int shouldDebug) {
|
|||||||
char *token = strtok(result, "/");
|
char *token = strtok(result, "/");
|
||||||
result = NULL;
|
result = NULL;
|
||||||
while (token != NULL) {
|
while (token != NULL) {
|
||||||
result = token;
|
result = token;
|
||||||
token = strtok(NULL, "/"); //Passing NULL means “don’t start a new string, resume
|
token = strtok(NULL, "/"); // Passing NULL means “don’t start a new string, resume
|
||||||
}
|
}
|
||||||
|
|
||||||
// clean up
|
// clean up
|
||||||
@@ -263,81 +284,86 @@ char* fzfSelect(char *pathToFiles, char *selectText, int shouldDebug) {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
char* ncursesSelect(char **options, char *optionsText, int optionsNumber, int extraOptionsNumber, char *bottomText, char *middleText, char *topText, int shouldDebug) { // TODO we should see how it handles larges strings (like large directories)
|
char *ncursesSelect(
|
||||||
int highlight = 0; //curently highlighted option
|
char **options, char *optionsText, int optionsNumber, int extraOptionsNumber, char *bottomText,
|
||||||
|
char *middleText, char *topText,
|
||||||
|
int shouldDebug) { // TODO we should see how it handles larges strings (like large directories)
|
||||||
|
int highlight = 0; // curently highlighted option
|
||||||
int key;
|
int key;
|
||||||
|
|
||||||
cbreak(); // disable line buffering
|
cbreak(); // disable line buffering
|
||||||
noecho(); // don't echo key presses
|
noecho(); // don't echo key presses
|
||||||
keypad(stdscr, TRUE); // enable arrow keys
|
keypad(stdscr, TRUE); // enable arrow keys
|
||||||
start_color();
|
start_color();
|
||||||
curs_set(0); // sets the cursor to invisible. (We will emulate the cursor with a hightlight that go up and down).
|
curs_set(0); // sets the cursor to invisible. (We will emulate the cursor with a hightlight that
|
||||||
|
// go up and down).
|
||||||
use_default_colors();
|
use_default_colors();
|
||||||
init_pair(1, COLOR_WHITE, -1); // color for optionsNumber (so notes, vaults, etc.)
|
init_pair(1, COLOR_WHITE, -1); // color for optionsNumber (so notes, vaults, etc.)
|
||||||
init_pair(2, COLOR_BLUE, -1); // color for extraOptionsNumber (so settings, delete notes, create vault, etc.)
|
init_pair(2, COLOR_BLUE,
|
||||||
|
-1); // color for extraOptionsNumber (so settings, delete notes, create vault, etc.)
|
||||||
while (1) {
|
while (1) {
|
||||||
clear();
|
clear();
|
||||||
attron(COLOR_PAIR(1));
|
attron(COLOR_PAIR(1));
|
||||||
mvprintw(0,0, "%s", optionsText);
|
mvprintw(0, 0, "%s", optionsText);
|
||||||
int offset = 1;
|
int offset = 1;
|
||||||
if (strcmp(bottomText, "") != 0) {
|
if (strcmp(bottomText, "") != 0) {
|
||||||
mvprintw(offset, 1, "%s", bottomText);
|
mvprintw(offset, 1, "%s", bottomText);
|
||||||
offset++;
|
offset++;
|
||||||
}
|
|
||||||
// Print options with highlighting
|
|
||||||
for (int i = 0; i < optionsNumber; i++) {
|
|
||||||
if (i == highlight) {
|
|
||||||
attron(A_REVERSE);
|
|
||||||
} // highlight selected
|
|
||||||
mvprintw(i+offset, 2, "%s", options[i]);
|
|
||||||
if (i == highlight) {
|
|
||||||
attroff(A_REVERSE);
|
|
||||||
}
|
}
|
||||||
}
|
// Print options with highlighting
|
||||||
attroff(COLOR_PAIR(1));
|
for (int i = 0; i < optionsNumber; i++) {
|
||||||
if (strcmp(middleText, "") != 0) {
|
if (i == highlight) {
|
||||||
mvprintw(offset+optionsNumber, 1, "%s", middleText);
|
attron(A_REVERSE);
|
||||||
offset++;
|
} // highlight selected
|
||||||
}
|
mvprintw(i + offset, 2, "%s", options[i]);
|
||||||
// Printf extraOptions with highlighting
|
if (i == highlight) {
|
||||||
attron(COLOR_PAIR(2));
|
attroff(A_REVERSE);
|
||||||
for (int k = optionsNumber; k < optionsNumber + extraOptionsNumber; k++) {
|
}
|
||||||
if (k == highlight) {
|
|
||||||
attron(A_REVERSE);
|
|
||||||
}
|
}
|
||||||
mvprintw(k+offset, 2, "%s", options[k]);
|
attroff(COLOR_PAIR(1));
|
||||||
if (k == highlight) {
|
if (strcmp(middleText, "") != 0) {
|
||||||
attroff(A_REVERSE);
|
mvprintw(offset + optionsNumber, 1, "%s", middleText);
|
||||||
|
offset++;
|
||||||
}
|
}
|
||||||
}
|
// Printf extraOptions with highlighting
|
||||||
attroff(COLOR_PAIR(2));
|
attron(COLOR_PAIR(2));
|
||||||
attron(COLOR_PAIR(1));
|
for (int k = optionsNumber; k < optionsNumber + extraOptionsNumber; k++) {
|
||||||
mvprintw(offset+optionsNumber+extraOptionsNumber, 1, "%s", topText);
|
if (k == highlight) {
|
||||||
attroff(COLOR_PAIR(1));
|
attron(A_REVERSE);
|
||||||
key = getch(); //get some int which value correspond to some key being pressed
|
}
|
||||||
|
mvprintw(k + offset, 2, "%s", options[k]);
|
||||||
|
if (k == highlight) {
|
||||||
|
attroff(A_REVERSE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
attroff(COLOR_PAIR(2));
|
||||||
|
attron(COLOR_PAIR(1));
|
||||||
|
mvprintw(offset + optionsNumber + extraOptionsNumber, 1, "%s", topText);
|
||||||
|
attroff(COLOR_PAIR(1));
|
||||||
|
key = getch(); // get some int which value correspond to some key being pressed
|
||||||
|
|
||||||
switch(key) {
|
switch (key) {
|
||||||
case KEY_UP:
|
case KEY_UP:
|
||||||
case 'w':
|
case 'w':
|
||||||
case 'W':
|
case 'W':
|
||||||
highlight--;
|
highlight--;
|
||||||
if (highlight < 0) {
|
if (highlight < 0) {
|
||||||
highlight = optionsNumber + extraOptionsNumber - 1;// can't select the -1nth option
|
highlight = optionsNumber + extraOptionsNumber - 1; // can't select the -1nth option
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 's':
|
case 's':
|
||||||
case 'S':
|
case 'S':
|
||||||
case KEY_DOWN:
|
case KEY_DOWN:
|
||||||
highlight++;
|
highlight++;
|
||||||
if (highlight >= optionsNumber + extraOptionsNumber) {
|
if (highlight >= optionsNumber + extraOptionsNumber) {
|
||||||
highlight = 0;
|
highlight = 0;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 10: //\n
|
case 10: //\n
|
||||||
goto end_loop;
|
goto end_loop;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
end_loop:
|
end_loop:
|
||||||
endwin(); // end ncurses mode
|
endwin(); // end ncurses mode
|
||||||
fflush(stderr);
|
fflush(stderr);
|
||||||
debug("Selected option: %s", options[highlight]);
|
debug("Selected option: %s", options[highlight]);
|
||||||
|
|||||||
@@ -1,47 +1,47 @@
|
|||||||
#ifndef UI_H
|
#ifndef UI_H
|
||||||
#define UI_H
|
#define UI_H
|
||||||
|
|
||||||
|
#include "utils.h"
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#include <ncurses.h>
|
||||||
|
#include <pwd.h>
|
||||||
|
#include <regex.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <ncurses.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <pwd.h>
|
#include <unistd.h>
|
||||||
#include <ctype.h>
|
#define CMD_BUFFER 4096 // for fzfSelect
|
||||||
#include <limits.h>
|
|
||||||
#include <regex.h>
|
|
||||||
#include "utils.h"
|
|
||||||
#define CMD_BUFFER 4096 // for fzfSelect
|
|
||||||
#define RESULT_BUFFER 1024 // for fzfSelect
|
#define RESULT_BUFFER 1024 // for fzfSelect
|
||||||
|
|
||||||
/*Uses ncurses to get an input from the user.
|
/*Uses ncurses to get an input from the user.
|
||||||
Creates a new note with this input.
|
Creates a new note with this input.
|
||||||
also can create a journal if the name matches with journalRegex.
|
also can create a journal if the name matches with journalRegex.
|
||||||
returns the path to the note.
|
returns the path to the note.
|
||||||
If you want to bypass the input TUI set bypass to 1 and bypassvalue to the note name
|
If you want to bypass the input TUI set bypass to 1 and bypassvalue to the note name
|
||||||
*/
|
*/
|
||||||
char *createNewNote(char dirToVault[PATH_MAX], char *vaultFromDir, int bypass, char *bypassvalue, char *journalRegex, int debug);
|
char *createNewNote(char dirToVault[PATH_MAX], char *vaultFromDir, int bypass, char *bypassvalue,
|
||||||
|
char *journalRegex, int debug);
|
||||||
/*
|
/*
|
||||||
Chooses in which directory it want to create the vault.
|
Chooses in which directory it want to create the vault.
|
||||||
Uses ncurses to get an input from the user.
|
Uses ncurses to get an input from the user.
|
||||||
Creates a new vault with this input.
|
Creates a new vault with this input.
|
||||||
If vault already exists, prints a warning.
|
If vault already exists, prints a warning.
|
||||||
returns nothing. */
|
returns nothing. */
|
||||||
void createNewVault(char **directoriesArray, int directoryCount, char **vaultsArray, int vaultCount, int bypass, char *bypassvalue, int debug);
|
void createNewVault(char **directoriesArray, int directoryCount, char **vaultsArray, int vaultCount,
|
||||||
|
int bypass, char *bypassvalue, int debug);
|
||||||
// uses fzf and ripgrep to search inside the files to choose between all the options.
|
// uses fzf and ripgrep to search inside the files to choose between all the options.
|
||||||
char* fzfSelect(char *pathToFiles, char *selectText, int shouldDebug);
|
char *fzfSelect(char *pathToFiles, char *selectText, int shouldDebug);
|
||||||
/*this function is used multiple times let the user select one options from many with ncurses in a TUI.
|
/*this function is used multiple times let the user select one options from many with ncurses in a
|
||||||
options is the array of strings with all the options.
|
TUI. options is the array of strings with all the options. optionsText is the text that will be
|
||||||
optionsText is the text that will be printed at the top (For example: "Please select ...").
|
printed at the top (For example: "Please select ..."). we distinguish options from extraOptions.
|
||||||
we distinguish options from extraOptions.
|
|
||||||
options could be the list of all notes or all vaults.
|
options could be the list of all notes or all vaults.
|
||||||
extraOptions are options that are special and have a special color (for ex: "Delete vault", "Settings", etc.).
|
extraOptions are options that are special and have a special color (for ex: "Delete vault",
|
||||||
note: extraOptions should be at the end of options.
|
"Settings", etc.). note: extraOptions should be at the end of options. topText is printed between
|
||||||
topText is printed between options text and the start of options.
|
options text and the start of options. middleText (usally \n) is printed between options and
|
||||||
middleText (usally \n) is printed between options and extraOptions.
|
extraOptions. bottomText is printed bellow. topText and middle must be exactly one line. If you want
|
||||||
bottomText is printed bellow.
|
empty lines use " " and not "". returns the selected option. */
|
||||||
topText and middle must be exactly one line. If you want empty lines use " " and not "".
|
char *ncursesSelect(char **options, char *optionsText, int optionsNumber, int extraOptionsNumber,
|
||||||
returns the selected option. */
|
char *bottomText, char *middleText, char *topText, int debug);
|
||||||
char* ncursesSelect(char **options, char *optionsText, int optionsNumber, int extraOptionsNumber, char *bottomText, char *middleText, char *topText, int debug);
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
+423
-397
@@ -11,88 +11,95 @@ int compareString(const void *a, const void *b) {
|
|||||||
int reverseCompareString(const void *a, const void *b) {
|
int reverseCompareString(const void *a, const void *b) {
|
||||||
const char *str1 = *(const char **)a;
|
const char *str1 = *(const char **)a;
|
||||||
const char *str2 = *(const char **)b;
|
const char *str2 = *(const char **)b;
|
||||||
return -1*strcmp(str1, str2);
|
return -1 * strcmp(str1, str2);
|
||||||
}
|
}
|
||||||
|
|
||||||
void getCurrentTime(int *hour, int *minute, int *second) {
|
void getCurrentTime(int *hour, int *minute, int *second) {
|
||||||
time_t now = time(NULL); // Get current time in seconds since epoch
|
time_t now = time(NULL); // Get current time in seconds since epoch
|
||||||
struct tm *local = localtime(&now); // Convert to local time structure
|
struct tm *local = localtime(&now); // Convert to local time structure
|
||||||
|
|
||||||
*hour = local->tm_hour; // Extract hour
|
*hour = local->tm_hour; // Extract hour
|
||||||
*minute = local->tm_min; // Extract minutes
|
*minute = local->tm_min; // Extract minutes
|
||||||
*second = local->tm_sec; // Extract seconds
|
*second = local->tm_sec; // Extract seconds
|
||||||
}
|
}
|
||||||
|
|
||||||
void _debug(const int d, const char *file, const int line, const char *function, const char *message, ...) { // use for formatted debug
|
void _debug(const int d, const char *file, const int line, const char *function,
|
||||||
if (d) {
|
const char *message, ...) { // use for formatted debug
|
||||||
fflush(stdout);
|
if (d) {
|
||||||
fflush(stderr);
|
fflush(stdout);
|
||||||
va_list args; //variadic function stuff
|
fflush(stderr);
|
||||||
va_start(args, message);
|
va_list args; // variadic function stuff
|
||||||
int h, m, s;
|
va_start(args, message);
|
||||||
getCurrentTime(&h, &m, &s);
|
int h, m, s;
|
||||||
fprintf(stderr, "\e[0;32m[DEBUG -- %d:%d:%d] From file %s line %d function %s:\e[0m\n", h, m, s, file, line, function);
|
getCurrentTime(&h, &m, &s);
|
||||||
vfprintf(stderr, message, args);
|
fprintf(stderr, "\e[0;32m[DEBUG -- %d:%d:%d] From file %s line %d function %s:\e[0m\n", h,
|
||||||
fprintf(stderr, "\e[0m\n");
|
m, s, file, line, function);
|
||||||
va_end(args);
|
vfprintf(stderr, message, args);
|
||||||
}
|
fprintf(stderr, "\e[0m\n");
|
||||||
}
|
va_end(args);
|
||||||
void _altDebug(const int d, const char *message, ...) { // use for less formal debuggin. (usefull if enumerating or making a list
|
|
||||||
if (d) {
|
|
||||||
fflush(stdout);
|
|
||||||
fflush(stderr);
|
|
||||||
va_list args;
|
|
||||||
va_start(args, message);
|
|
||||||
vfprintf(stderr, message, args);
|
|
||||||
va_end(args);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void _error(const int shouldDebug, const int condition, const char *type, const char *file, const int line, const char *function, const char *message, ...) { // used for formatted errors
|
|
||||||
if (condition) {
|
|
||||||
int h, m, s;
|
|
||||||
getCurrentTime(&h, &m, &s);
|
|
||||||
fprintf(stderr, "\e[0;31m[%s ERROR -- %d:%d:%d] From file %s line %d function %s:\n", type, h, m, s, file, line, function);
|
|
||||||
if (errno != 0) {
|
|
||||||
fprintf(stderr, " (System-level error message: %s)\n", strerror(errno));
|
|
||||||
} else {
|
|
||||||
fprintf(stderr, " (No system-level error; issue is application-level)\n");
|
|
||||||
}
|
}
|
||||||
va_list args;
|
}
|
||||||
va_start(args, message);
|
void _altDebug(const int d, const char *message,
|
||||||
vfprintf(stderr, message, args);
|
...) { // use for less formal debuggin. (usefull if enumerating or making a list
|
||||||
va_end(args);
|
if (d) {
|
||||||
if (!shouldDebug) {
|
fflush(stdout);
|
||||||
fprintf(stderr, "\nRunning notewrapper -V might give you more information.");
|
fflush(stderr);
|
||||||
|
va_list args;
|
||||||
|
va_start(args, message);
|
||||||
|
vfprintf(stderr, message, args);
|
||||||
|
va_end(args);
|
||||||
}
|
}
|
||||||
fprintf(stderr, "\e[0m\n");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void copyDir(const char *source, const char *destination, const char **rsyncArgs, const int rsyncArgsNumber, const int shouldDebug) {
|
void _error(const int shouldDebug, const int condition, const char *type, const char *file,
|
||||||
|
const int line, const char *function, const char *message,
|
||||||
|
...) { // used for formatted errors
|
||||||
|
if (condition) {
|
||||||
|
int h, m, s;
|
||||||
|
getCurrentTime(&h, &m, &s);
|
||||||
|
fprintf(stderr, "\e[0;31m[%s ERROR -- %d:%d:%d] From file %s line %d function %s:\n", type,
|
||||||
|
h, m, s, file, line, function);
|
||||||
|
if (errno != 0) {
|
||||||
|
fprintf(stderr, " (System-level error message: %s)\n", strerror(errno));
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, " (No system-level error; issue is application-level)\n");
|
||||||
|
}
|
||||||
|
va_list args;
|
||||||
|
va_start(args, message);
|
||||||
|
vfprintf(stderr, message, args);
|
||||||
|
va_end(args);
|
||||||
|
if (!shouldDebug) {
|
||||||
|
fprintf(stderr, "\nRunning notewrapper -V might give you more information.");
|
||||||
|
}
|
||||||
|
fprintf(stderr, "\e[0m\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void copyDir(const char *source, const char *destination, const char **rsyncArgs,
|
||||||
|
const int rsyncArgsNumber, const int shouldDebug) {
|
||||||
debug("Backuping... source: %s and destination: %s", source, destination);
|
debug("Backuping... source: %s and destination: %s", source, destination);
|
||||||
debug("Rsync has %d extra arguments", rsyncArgsNumber);
|
debug("Rsync has %d extra arguments", rsyncArgsNumber);
|
||||||
pid_t pid = fork();
|
pid_t pid = fork();
|
||||||
|
|
||||||
error(pid < 0, "program", "fork() faild. pid = %d", pid);
|
error(pid < 0, "program", "fork() faild. pid = %d", pid);
|
||||||
|
|
||||||
if (pid == 0) {
|
if (pid == 0) {
|
||||||
// Child process: execute rsync
|
// Child process: execute rsync
|
||||||
char **args = malloc((4 + rsyncArgsNumber)*sizeof(char*));
|
char **args = malloc((4 + rsyncArgsNumber) * sizeof(char *));
|
||||||
args[0] = "rsync";
|
args[0] = "rsync";
|
||||||
for (int i = 0; i < rsyncArgsNumber; i++) {
|
for (int i = 0; i < rsyncArgsNumber; i++) {
|
||||||
args[i+1] = (char *)rsyncArgs[i];
|
args[i + 1] = (char *)rsyncArgs[i];
|
||||||
if (i == rsyncArgsNumber-1) { // last loop
|
if (i == rsyncArgsNumber - 1) { // last loop
|
||||||
args[i+2] = (char*)source;
|
args[i + 2] = (char *)source;
|
||||||
args[i+3] = (char*)destination;
|
args[i + 3] = (char *)destination;
|
||||||
args[i+4] = NULL; // execvp expect last arg to be NULL
|
args[i + 4] = NULL; // execvp expect last arg to be NULL
|
||||||
debug("rsync command:");
|
debug("rsync command:");
|
||||||
for (int k = 0; k <= i+4; k++) {
|
for (int k = 0; k <= i + 4; k++) {
|
||||||
altDebug("%s ", args[k]);
|
altDebug("%s ", args[k]);
|
||||||
|
}
|
||||||
|
altDebug("\n");
|
||||||
}
|
}
|
||||||
altDebug("\n");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
execvp("rsync", args);
|
execvp("rsync", args);
|
||||||
// If execvp returns, there was an error
|
// If execvp returns, there was an error
|
||||||
@@ -115,24 +122,21 @@ void initAppFilesAndDirs(const char *home, const int shouldDebug) {
|
|||||||
// sometimes .cache and .config doesn't exist. Such as with github actions machines
|
// sometimes .cache and .config doesn't exist. Such as with github actions machines
|
||||||
char config_dir[PATH_MAX];
|
char config_dir[PATH_MAX];
|
||||||
char cache_dir[PATH_MAX];
|
char cache_dir[PATH_MAX];
|
||||||
|
|
||||||
snprintf(config_dir, sizeof(config_dir),
|
|
||||||
"%s/.config/", home);
|
|
||||||
|
|
||||||
snprintf(cache_dir, sizeof(cache_dir),
|
snprintf(config_dir, sizeof(config_dir), "%s/.config/", home);
|
||||||
"%s/.cache/", home);
|
|
||||||
|
snprintf(cache_dir, sizeof(cache_dir), "%s/.cache/", home);
|
||||||
|
|
||||||
ensureDir(config_dir, shouldDebug);
|
ensureDir(config_dir, shouldDebug);
|
||||||
ensureDir(cache_dir, shouldDebug);
|
ensureDir(cache_dir, shouldDebug);
|
||||||
|
|
||||||
strncat(config_dir, "notewrapper/", PATH_MAX);
|
strncat(config_dir, "notewrapper/", PATH_MAX);
|
||||||
strncat(cache_dir, "notewrapper/", PATH_MAX);
|
strncat(cache_dir, "notewrapper/", PATH_MAX);
|
||||||
|
|
||||||
ensureDir(config_dir, shouldDebug);
|
ensureDir(config_dir, shouldDebug);
|
||||||
ensureDir(cache_dir, shouldDebug);
|
ensureDir(cache_dir, shouldDebug);
|
||||||
|
|
||||||
|
|
||||||
char config_file[PATH_MAX+12];
|
char config_file[PATH_MAX + 12];
|
||||||
snprintf(config_file, sizeof(config_file), "%s/config.json", config_dir);
|
snprintf(config_file, sizeof(config_file), "%s/config.json", config_dir);
|
||||||
|
|
||||||
FILE *f = fopen(config_file, "r");
|
FILE *f = fopen(config_file, "r");
|
||||||
@@ -143,29 +147,34 @@ void initAppFilesAndDirs(const char *home, const int shouldDebug) {
|
|||||||
debug("Creating default config file.");
|
debug("Creating default config file.");
|
||||||
FILE *w = fopen(config_file, "w");
|
FILE *w = fopen(config_file, "w");
|
||||||
error(!w, "program", "fopen failed opening %s");
|
error(!w, "program", "fopen failed opening %s");
|
||||||
fprintf(w, //TODO CHANGE default json
|
fprintf(w, // TODO CHANGE default json
|
||||||
"{\n"
|
"{\n"
|
||||||
" \"directory\": [\"~/Documents/\"],\n"// I personally use ~/Documents/Notes. But the dir doesn't exist most times. So for the default user it is better to put ~/Documents
|
" \"directory\": [\"~/Documents/\"],\n" // I personally use ~/Documents/Notes. But the
|
||||||
" \"render\": true,\n"
|
// dir doesn't exist most times. So for the
|
||||||
" \"jumpToEndOfFileOnLaunch\": true,\n"
|
// default user it is better to put ~/Documents
|
||||||
" \"editor\": \"neovim\",\n"
|
" \"render\": true,\n"
|
||||||
" \"journalRegex\": \".*journal.*\",\n"
|
" \"jumpToEndOfFileOnLaunch\": true,\n"
|
||||||
" \"dateEntry\": \"# %%Y %%m %%d %%a\",\n"
|
" \"editor\": \"neovim\",\n"
|
||||||
" \"newLineOnOpening\": true,\n"
|
" \"journalRegex\": \".*journal.*\",\n"
|
||||||
" \"backup\": {\n"
|
" \"dateEntry\": \"# %%Y %%m %%d %%a\",\n"
|
||||||
" \"enable\": false,\n"
|
" \"newLineOnOpening\": true,\n"
|
||||||
" \"directory\": {\n"
|
" \"backup\": {\n"
|
||||||
" \"~/Documents/\": \"path/to/backup/\"\n"
|
" \"enable\": false,\n"
|
||||||
" },\n"
|
" \"directory\": {\n"
|
||||||
" \"interval\": \"weekly\",\n"
|
" \"~/Documents/\": \"path/to/backup/\"\n"
|
||||||
" \"rsyncArgs\": [\"-Lqah\", \"--update\"]\n"
|
" },\n"
|
||||||
" }\n"
|
" \"interval\": \"weekly\",\n"
|
||||||
"}\n");
|
" \"rsyncArgs\": [\"-Lqah\", \"--update\"]\n"
|
||||||
|
" }\n"
|
||||||
|
"}\n");
|
||||||
|
|
||||||
fclose(w);
|
fclose(w);
|
||||||
}
|
}
|
||||||
|
|
||||||
void handleBackups(char **sourceDirectoryArray, const int sourceNumber, char **destinationDirectoryArray, const char *homeDir, const int interval, const char **rsyncArguments, const int rsyncArgumentsNumber, const int shouldDebug) {
|
void handleBackups(char **sourceDirectoryArray, const int sourceNumber,
|
||||||
|
char **destinationDirectoryArray, const char *homeDir, const int interval,
|
||||||
|
const char **rsyncArguments, const int rsyncArgumentsNumber,
|
||||||
|
const int shouldDebug) {
|
||||||
int shouldBackup = 0;
|
int shouldBackup = 0;
|
||||||
time_t now = time(NULL);
|
time_t now = time(NULL);
|
||||||
debug("Time since epoch is %ld", (long)now);
|
debug("Time since epoch is %ld", (long)now);
|
||||||
@@ -202,7 +211,8 @@ void handleBackups(char **sourceDirectoryArray, const int sourceNumber, char **d
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (difftime(now, lastBackupTime) > interval) {
|
if (difftime(now, lastBackupTime) > interval) {
|
||||||
debug("(difftime) %d is greater than (interval) %d -> backuping...", difftime(now, lastBackupTime), interval);
|
debug("(difftime) %d is greater than (interval) %d -> backuping...",
|
||||||
|
difftime(now, lastBackupTime), interval);
|
||||||
shouldBackup = 1;
|
shouldBackup = 1;
|
||||||
cacheFile = fopen(cacheFilePATH, "w");
|
cacheFile = fopen(cacheFilePATH, "w");
|
||||||
if (!cacheFile) {
|
if (!cacheFile) {
|
||||||
@@ -211,41 +221,57 @@ void handleBackups(char **sourceDirectoryArray, const int sourceNumber, char **d
|
|||||||
fprintf(cacheFile, "%ld\n", (long)now);
|
fprintf(cacheFile, "%ld\n", (long)now);
|
||||||
fclose(cacheFile);
|
fclose(cacheFile);
|
||||||
} else {
|
} else {
|
||||||
debug("(difftime) %d is smaller than (interval) %d -> no need to backup.", difftime(now, lastBackupTime), interval);
|
debug("(difftime) %d is smaller than (interval) %d -> no need to backup.",
|
||||||
|
difftime(now, lastBackupTime), interval);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (shouldBackup) {
|
if (shouldBackup) {
|
||||||
debug("A backup is needed");
|
debug("A backup is needed");
|
||||||
for (int i = 0; i < sourceNumber; i++) {
|
for (int i = 0; i < sourceNumber; i++) {
|
||||||
debug("%s", destinationDirectoryArray[i]);
|
debug("%s", destinationDirectoryArray[i]);
|
||||||
if (destinationDirectoryArray[i]) { // if we don't want to backup it, it was set to NULL
|
if (destinationDirectoryArray[i]) { // if we don't want to backup it, it was set to NULL
|
||||||
copyDir(sourceDirectoryArray[i], destinationDirectoryArray[i], rsyncArguments, rsyncArgumentsNumber, shouldDebug);
|
copyDir(sourceDirectoryArray[i], destinationDirectoryArray[i], rsyncArguments,
|
||||||
|
rsyncArgumentsNumber, shouldDebug);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int isEditorValid (char *editorToCheck, int useDefaultEditor, int shouldDebug) { // check if editor is supported and if it is installed
|
int isEditorValid(char *editorToCheck, int useDefaultEditor,
|
||||||
// check if supported
|
int shouldDebug) { // check if editor is supported and if it is installed
|
||||||
|
// check if supported
|
||||||
if (useDefaultEditor) { // we use a different error message if it defaulted to $EDITOR
|
if (useDefaultEditor) { // we use a different error message if it defaulted to $EDITOR
|
||||||
error(!isStringInArray(editorToCheck, supportedEditor, numEditors), "user", "%s is not a supported editor.\n(defaulted to $EDITOR as neither \"editor\" was set in the configuration file nor -e/--editor <editor> was set.)\n See https://github.com/tomasriveral/NoteWrapper#editor-support for a list of supported editors.", editorToCheck);
|
error(!isStringInArray(editorToCheck, supportedEditor, numEditors), "user",
|
||||||
|
"%s is not a supported editor.\n(defaulted to $EDITOR as neither \"editor\" was set "
|
||||||
|
"in the configuration file nor -e/--editor <editor> was set.)\n See "
|
||||||
|
"https://github.com/tomasriveral/NoteWrapper#editor-support for a list of supported "
|
||||||
|
"editors.",
|
||||||
|
editorToCheck);
|
||||||
} else {
|
} else {
|
||||||
error(!isStringInArray(editorToCheck, supportedEditor, numEditors), "user", "%s is not a supported editor.\n See https://github.com/tomasriveral/NoteWrapper#editor-support for a list of supported editors.", editorToCheck);
|
error(!isStringInArray(editorToCheck, supportedEditor, numEditors), "user",
|
||||||
|
"%s is not a supported editor.\n See "
|
||||||
|
"https://github.com/tomasriveral/NoteWrapper#editor-support for a list of supported "
|
||||||
|
"editors.",
|
||||||
|
editorToCheck);
|
||||||
}
|
}
|
||||||
// check if installed
|
// check if installed
|
||||||
char *editor;
|
char *editor;
|
||||||
if (strcmp(editorToCheck, "neovim") == 0) { // some executables are not name the same as the project
|
if (strcmp(editorToCheck, "neovim") ==
|
||||||
editor = strdup("nvim"); // we must use strdup and not just copy as we would have modified editorToOpen in main
|
0) { // some executables are not name the same as the project
|
||||||
|
editor = strdup("nvim"); // we must use strdup and not just copy as we would have modified
|
||||||
|
// editorToOpen in main
|
||||||
} else if (strcmp(editorToCheck, "helix") == 0) {
|
} else if (strcmp(editorToCheck, "helix") == 0) {
|
||||||
editor = strdup("hx");
|
editor = strdup("hx");
|
||||||
} else if (strcmp(editorToCheck, "kakoune") == 0) {
|
} else if (strcmp(editorToCheck, "kakoune") == 0) {
|
||||||
editor = strdup("kak");
|
editor = strdup("kak");
|
||||||
} else {
|
} else {
|
||||||
editor = strdup(editorToCheck);
|
editor = strdup(editorToCheck);
|
||||||
}
|
}
|
||||||
char *path_env = getenv("PATH");
|
char *path_env = getenv("PATH");
|
||||||
error(!path_env, "program", "getenv(\"PATH\") failed to get your path. NoteWrapper is unable to check if your desired editor is installed\n");
|
error(!path_env, "program",
|
||||||
|
"getenv(\"PATH\") failed to get your path. NoteWrapper is unable to check if your "
|
||||||
|
"desired editor is installed\n");
|
||||||
debug("Your PATH is %s", path_env);
|
debug("Your PATH is %s", path_env);
|
||||||
char *paths = strdup(path_env); // duplicate because strtok modifies the string
|
char *paths = strdup(path_env); // duplicate because strtok modifies the string
|
||||||
char *dir = strtok(paths, ":");
|
char *dir = strtok(paths, ":");
|
||||||
@@ -266,43 +292,47 @@ int isEditorValid (char *editorToCheck, int useDefaultEditor, int shouldDebug) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
char *getFormatedTime(char *format, int shouldDebug) {
|
char *getFormatedTime(char *format, int shouldDebug) {
|
||||||
debug("Inputed time format is %s", format);
|
debug("Inputed time format is %s", format);
|
||||||
time_t t = time(NULL);
|
time_t t = time(NULL);
|
||||||
struct tm *tm = localtime(&t);
|
struct tm *tm = localtime(&t);
|
||||||
char *buf = malloc(BUFFER_SIZE);
|
char *buf = malloc(BUFFER_SIZE);
|
||||||
strftime(buf, BUFFER_SIZE, format, tm);
|
strftime(buf, BUFFER_SIZE, format, tm);
|
||||||
debug("Formated time is %s", buf);
|
debug("Formated time is %s", buf);
|
||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
int isStringInArray(const char *string, const char **array, const int len) {
|
int isStringInArray(const char *string, const char **array, const int len) {
|
||||||
for (int i = 0; i < len; i++) {
|
for (int i = 0; i < len; i++) {
|
||||||
if (strcmp(string, array[i]) == 0) {
|
if (strcmp(string, array[i]) == 0) {
|
||||||
return 1;
|
return 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
return 0;
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int isStringInFile(const char *path, const char *string, const int shouldDebug) {
|
int isStringInFile(const char *path, const char *string, const int shouldDebug) {
|
||||||
FILE *file = fopen(path, "r");
|
FILE *file = fopen(path, "r");
|
||||||
error(file == NULL, "program", "While searching for \"%s\", we could not open file %s", string, path);
|
error(file == NULL, "program", "While searching for \"%s\", we could not open file %s", string,
|
||||||
char buf[BUFFER_SIZE];
|
path);
|
||||||
|
char buf[BUFFER_SIZE];
|
||||||
while (fgets(buf, BUFFER_SIZE, file) != NULL) {
|
|
||||||
if (strstr(buf, string) != NULL) {
|
while (fgets(buf, BUFFER_SIZE, file) != NULL) {
|
||||||
debug("%s contains the substring %s", buf, string);
|
if (strstr(buf, string) != NULL) {
|
||||||
return 1;
|
debug("%s contains the substring %s", buf, string);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
debug("The string %s is not inside %s", string, path);
|
||||||
debug("The string %s is not inside %s", string, path);
|
return 0;
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
void appendToFile(const char *path, const char *string, const int shouldDebug) {
|
void appendToFile(const char *path, const char *string, const int shouldDebug) {
|
||||||
FILE *file = fopen(path, "r");
|
FILE *file = fopen(path, "r");
|
||||||
char lastLine[1024] = {0};
|
char lastLine[1024] = {0};
|
||||||
error(file == NULL, "program", "could not open %s", path);
|
error(file == NULL, "program", "could not open %s", path);
|
||||||
char buffer[BUFFER_SIZE]; // it does not matter if we have a small buffer. string is relatively small (most time \n or the name of the file). So it is under BUFFER_SIZE. If the last line is more than BUFFER_SIZE. It can't be equal to string
|
char buffer[BUFFER_SIZE]; // it does not matter if we have a small buffer. string is relatively
|
||||||
|
// small (most time \n or the name of the file). So it is under
|
||||||
|
// BUFFER_SIZE. If the last line is more than BUFFER_SIZE. It can't be
|
||||||
|
// equal to string
|
||||||
|
|
||||||
// Read file line by line to get the last one
|
// Read file line by line to get the last one
|
||||||
while (fgets(buffer, sizeof(buffer), file) != NULL) {
|
while (fgets(buffer, sizeof(buffer), file) != NULL) {
|
||||||
@@ -329,17 +359,18 @@ void appendToFile(const char *path, const char *string, const int shouldDebug) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void sanitize(char *string) {
|
void sanitize(char *string) {
|
||||||
size_t stringLenght = strlen(string);
|
size_t stringLenght = strlen(string);
|
||||||
for (size_t i = 0; i < stringLenght; i++) {
|
for (size_t i = 0; i < stringLenght; i++) {
|
||||||
if ((!isalnum((unsigned char)string[i]) && strchr("~/\\:*?\"\'|!$[]{}<>\n\r\t", string[i]))) { // replace unwanted chars by '_'
|
if ((!isalnum((unsigned char)string[i]) &&
|
||||||
string[i] = '_';
|
strchr("~/\\:*?\"\'|!$[]{}<>\n\r\t", string[i]))) { // replace unwanted chars by '_'
|
||||||
|
string[i] = '_';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// removes any leading '.
|
||||||
|
size_t i = 0;
|
||||||
|
while (i < stringLenght && string[i] == '.') {
|
||||||
|
string[i++] = '_';
|
||||||
}
|
}
|
||||||
}
|
|
||||||
// removes any leading '.
|
|
||||||
size_t i = 0;
|
|
||||||
while (i < stringLenght && string[i] == '.') {
|
|
||||||
string[i++] = '_';
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// both functions are from https://stackoverflow.com/a/5467788
|
// both functions are from https://stackoverflow.com/a/5467788
|
||||||
@@ -347,301 +378,296 @@ void sanitize(char *string) {
|
|||||||
// remove() can't delete directories with files
|
// remove() can't delete directories with files
|
||||||
// so it walks the file tree and deletes it's content before removing the directory
|
// so it walks the file tree and deletes it's content before removing the directory
|
||||||
int unlink_cb(const char *filePath, const struct stat *sb, int typeflag, struct FTW *ftwbuf) {
|
int unlink_cb(const char *filePath, const struct stat *sb, int typeflag, struct FTW *ftwbuf) {
|
||||||
(void)sb;
|
(void)sb;
|
||||||
(void)typeflag;
|
(void)typeflag;
|
||||||
(void)ftwbuf;
|
(void)ftwbuf;
|
||||||
|
|
||||||
int shouldDebug = 1; //normally shouldDebug should be passed to the function. However, it's to difficult here and the best it to set it to 1.
|
int shouldDebug = 1; // normally shouldDebug should be passed to the function. However, it's to
|
||||||
|
// difficult here and the best it to set it to 1.
|
||||||
|
|
||||||
// some sanity checks to be sure that we don't delete something we shouldn't
|
// some sanity checks to be sure that we don't delete something we shouldn't
|
||||||
error(strcmp(filePath, "") == 0, "program", "filePath is empty. Refusing to delete directory");
|
error(strcmp(filePath, "") == 0, "program", "filePath is empty. Refusing to delete directory");
|
||||||
error(filePath[0] == '.', "program", "%s starts with \".\". For security reasons, use absolute path and not relative path.", filePath);
|
error(filePath[0] == '.', "program",
|
||||||
|
"%s starts with \".\". For security reasons, use absolute path and not relative path.",
|
||||||
|
filePath);
|
||||||
|
|
||||||
int rv = remove(filePath);
|
int rv = remove(filePath);
|
||||||
error(rv, "program", "remove() failed to delete %s", filePath);
|
error(rv, "program", "remove() failed to delete %s", filePath);
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
int rmrf(char *path, int shouldDebug) {
|
int rmrf(char *path, int shouldDebug) {
|
||||||
error(strcmp(path, "/") == 0, "program", "Refusing to delete root directory");
|
error(strcmp(path, "/") == 0, "program", "Refusing to delete root directory");
|
||||||
return nftw(path, unlink_cb, 64, FTW_DEPTH | FTW_PHYS);
|
return nftw(path, unlink_cb, 64, FTW_DEPTH | FTW_PHYS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int openEditor(char *path, char *editor, int render, int shouldJumpToEndOfFile, int shouldDebug) {
|
int openEditor(char *path, char *editor, int render, int shouldJumpToEndOfFile, int shouldDebug) {
|
||||||
|
|
||||||
// this ensures that ncurses won't affect the editor behaviour
|
// this ensures that ncurses won't affect the editor behaviour
|
||||||
pid_t editor_pid = fork();
|
pid_t editor_pid = fork();
|
||||||
error(editor_pid < 0, "program", "fork() failed.");
|
error(editor_pid < 0, "program", "fork() failed.");
|
||||||
|
|
||||||
// instead of reusing part of the codes, for any new editor copy an example and adapt it. This is in case we need a custom fix for an editor.
|
// instead of reusing part of the codes, for any new editor copy an example and adapt it. This
|
||||||
|
// is in case we need a custom fix for an editor.
|
||||||
|
|
||||||
if (editor_pid == 0) {
|
if (editor_pid == 0) {
|
||||||
// =========================
|
// =========================
|
||||||
// CHILD: launch editor
|
// CHILD: launch editor
|
||||||
// =========================
|
// =========================
|
||||||
|
|
||||||
// ---- NEOVIM / VIM ----
|
// ---- NEOVIM / VIM ----
|
||||||
if (strcmp(editor, "neovim") == 0 || strcmp(editor, "vim") == 0) {
|
if (strcmp(editor, "neovim") == 0 || strcmp(editor, "vim") == 0) {
|
||||||
const char *bin = (strcmp(editor, "neovim") == 0) ? "nvim" : "vim";
|
const char *bin = (strcmp(editor, "neovim") == 0) ? "nvim" : "vim";
|
||||||
|
|
||||||
if (render) {
|
if (render) {
|
||||||
if (shouldJumpToEndOfFile) {
|
if (shouldJumpToEndOfFile) {
|
||||||
debug("Running %s +:$ +:Vivify %s", bin, path);
|
debug("Running %s +:$ +:Vivify %s", bin, path);
|
||||||
execlp(bin, bin, "+:$", "+:Vivify", path, NULL);
|
execlp(bin, bin, "+:$", "+:Vivify", path, NULL);
|
||||||
} else {
|
} else {
|
||||||
debug("Running %s +:Vivify %s", bin, path);
|
debug("Running %s +:Vivify %s", bin, path);
|
||||||
execlp(bin, bin, "+:Vivify", path, NULL);
|
execlp(bin, bin, "+:Vivify", path, NULL);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (shouldJumpToEndOfFile) {
|
if (shouldJumpToEndOfFile) {
|
||||||
debug("Running %s +:$ %s", bin, path);
|
debug("Running %s +:$ %s", bin, path);
|
||||||
execlp(bin, bin, "+:$", path, NULL);
|
execlp(bin, bin, "+:$", path, NULL);
|
||||||
} else {
|
} else {
|
||||||
debug("Running %s %s", bin, path);
|
debug("Running %s %s", bin, path);
|
||||||
execlp(bin, bin, path, NULL);
|
execlp(bin, bin, path, NULL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
error(1, "program", "execlp() failed.");
|
error(1, "program", "execlp() failed.");
|
||||||
// ---- MICRO ----
|
// ---- MICRO ----
|
||||||
} else if (strcmp(editor, "micro") == 0) {
|
} else if (strcmp(editor, "micro") == 0) {
|
||||||
|
|
||||||
if (render) {
|
if (render) {
|
||||||
if (shouldJumpToEndOfFile) {
|
if (shouldJumpToEndOfFile) {
|
||||||
debug("Running MICRO_VIVIFY=1 micro %s +99999", path);
|
debug("Running MICRO_VIVIFY=1 micro %s +99999", path);
|
||||||
setenv("MICRO_VIVIFY", "1", 1);
|
setenv("MICRO_VIVIFY", "1", 1);
|
||||||
execlp("micro", "micro", path, "+999999", NULL);
|
execlp("micro", "micro", path, "+999999", NULL);
|
||||||
} else {
|
} else {
|
||||||
debug("Running MICRO_VIVIFY=1 micro %s", path);
|
debug("Running MICRO_VIVIFY=1 micro %s", path);
|
||||||
setenv("MICRO_VIVIFY", "1", 1);
|
setenv("MICRO_VIVIFY", "1", 1);
|
||||||
execlp("micro", "micro", path, NULL);
|
execlp("micro", "micro", path, NULL);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (shouldJumpToEndOfFile) {
|
if (shouldJumpToEndOfFile) {
|
||||||
debug("Running micro %s +999999", path);
|
debug("Running micro %s +999999", path);
|
||||||
execlp("micro", "micro", path, "+999999", NULL);
|
execlp("micro", "micro", path, "+999999", NULL);
|
||||||
} else {
|
} else {
|
||||||
debug("Running micro %s", path);
|
debug("Running micro %s", path);
|
||||||
execlp("micro", "micro", path, NULL);
|
execlp("micro", "micro", path, NULL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
error(1, "program", "execlp() failed.");
|
error(1, "program", "execlp() failed.");
|
||||||
}
|
|
||||||
|
|
||||||
// ---- NANO ----
|
|
||||||
else if (strcmp(editor, "nano") == 0) {
|
|
||||||
|
|
||||||
// If render enabled → spawn viv in parallel
|
|
||||||
if (render) {
|
|
||||||
debug("Running Vivify...");
|
|
||||||
pid_t viv_pid = fork();
|
|
||||||
error(viv_pid < 0, "program", "fork() failed.");
|
|
||||||
|
|
||||||
if (viv_pid == 0) {
|
|
||||||
// GRANDCHILD → viv
|
|
||||||
|
|
||||||
|
|
||||||
char viv_path[PATH_MAX];
|
|
||||||
strncpy(viv_path, path, PATH_MAX - 1);
|
|
||||||
viv_path[PATH_MAX - 1] = '\0';
|
|
||||||
|
|
||||||
if (shouldJumpToEndOfFile) {
|
|
||||||
strncat(viv_path, ":99999",
|
|
||||||
PATH_MAX - strlen(viv_path) - 1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
debug("Running viv %s", viv_path);
|
// ---- NANO ----
|
||||||
execlp("viv", "viv", viv_path, NULL);
|
else if (strcmp(editor, "nano") == 0) {
|
||||||
error(1, "program", "execlp() failed.");
|
|
||||||
}
|
|
||||||
// IMPORTANT: do NOT wait for viv
|
|
||||||
}
|
|
||||||
|
|
||||||
// Now run nano (this replaces the child process)
|
// If render enabled → spawn viv in parallel
|
||||||
if (shouldJumpToEndOfFile) {
|
if (render) {
|
||||||
debug("Running nano + %s", path);
|
debug("Running Vivify...");
|
||||||
execlp("nano", "nano", "+", path, NULL);
|
pid_t viv_pid = fork();
|
||||||
} else {
|
error(viv_pid < 0, "program", "fork() failed.");
|
||||||
debug("Running nano %s", path);
|
|
||||||
execlp("nano", "nano", path, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
error(1, "program", "execlp() failed.");
|
if (viv_pid == 0) {
|
||||||
// ---- HELIX ----
|
// GRANDCHILD → viv
|
||||||
} else if (strcmp(editor, "helix") == 0) {
|
|
||||||
|
|
||||||
// If render enabled → spawn viv in parallel
|
char viv_path[PATH_MAX];
|
||||||
if (render) {
|
strncpy(viv_path, path, PATH_MAX - 1);
|
||||||
debug("Running Vivify...");
|
viv_path[PATH_MAX - 1] = '\0';
|
||||||
pid_t viv_pid = fork();
|
|
||||||
error(viv_pid < 0, "program", "fork() failed.");
|
|
||||||
|
|
||||||
if (viv_pid == 0) {
|
if (shouldJumpToEndOfFile) {
|
||||||
// GRANDCHILD → viv
|
strncat(viv_path, ":99999", PATH_MAX - strlen(viv_path) - 1);
|
||||||
|
}
|
||||||
|
|
||||||
char viv_path[PATH_MAX];
|
debug("Running viv %s", viv_path);
|
||||||
strncpy(viv_path, path, PATH_MAX - 1);
|
execlp("viv", "viv", viv_path, NULL);
|
||||||
viv_path[PATH_MAX - 1] = '\0';
|
error(1, "program", "execlp() failed.");
|
||||||
|
}
|
||||||
|
// IMPORTANT: do NOT wait for viv
|
||||||
|
}
|
||||||
|
|
||||||
if (shouldJumpToEndOfFile) {
|
// Now run nano (this replaces the child process)
|
||||||
strncat(viv_path, ":99999",
|
if (shouldJumpToEndOfFile) {
|
||||||
PATH_MAX - strlen(viv_path) - 1);
|
debug("Running nano + %s", path);
|
||||||
|
execlp("nano", "nano", "+", path, NULL);
|
||||||
|
} else {
|
||||||
|
debug("Running nano %s", path);
|
||||||
|
execlp("nano", "nano", path, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
error(1, "program", "execlp() failed.");
|
||||||
|
// ---- HELIX ----
|
||||||
|
} else if (strcmp(editor, "helix") == 0) {
|
||||||
|
|
||||||
|
// If render enabled → spawn viv in parallel
|
||||||
|
if (render) {
|
||||||
|
debug("Running Vivify...");
|
||||||
|
pid_t viv_pid = fork();
|
||||||
|
error(viv_pid < 0, "program", "fork() failed.");
|
||||||
|
|
||||||
|
if (viv_pid == 0) {
|
||||||
|
// GRANDCHILD → viv
|
||||||
|
|
||||||
|
char viv_path[PATH_MAX];
|
||||||
|
strncpy(viv_path, path, PATH_MAX - 1);
|
||||||
|
viv_path[PATH_MAX - 1] = '\0';
|
||||||
|
|
||||||
|
if (shouldJumpToEndOfFile) {
|
||||||
|
strncat(viv_path, ":99999", PATH_MAX - strlen(viv_path) - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
debug("Running viv %s", viv_path);
|
||||||
|
execlp("viv", "viv", viv_path, NULL);
|
||||||
|
error(1, "program", "execlp() failed.");
|
||||||
|
}
|
||||||
|
// IMPORTANT: do NOT wait for viv
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now run helix (this replaces the child process)
|
||||||
|
if (shouldJumpToEndOfFile) {
|
||||||
|
strncat(path, ":99999", PATH_MAX);
|
||||||
|
debug("Running hx %s", path);
|
||||||
|
execlp("hx", "hx", path, NULL);
|
||||||
|
} else {
|
||||||
|
debug("Running hx %s", path);
|
||||||
|
execlp("hx", "hx", path, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
error(1, "program", "execlp() failed.");
|
||||||
}
|
}
|
||||||
|
// ---- kakoune ----
|
||||||
|
else if (strcmp(editor, "kakoune") == 0) {
|
||||||
|
|
||||||
debug("Running viv %s", viv_path);
|
// If render enabled → spawn viv in parallel
|
||||||
execlp("viv", "viv", viv_path, NULL);
|
if (render) {
|
||||||
error(1, "program", "execlp() failed.");
|
debug("Running Vivify...");
|
||||||
}
|
pid_t viv_pid = fork();
|
||||||
// IMPORTANT: do NOT wait for viv
|
error(viv_pid < 0, "program", "fork() failed.");
|
||||||
}
|
|
||||||
|
|
||||||
// Now run helix (this replaces the child process)
|
if (viv_pid == 0) {
|
||||||
if (shouldJumpToEndOfFile) {
|
// GRANDCHILD → viv
|
||||||
strncat(path, ":99999", PATH_MAX);
|
|
||||||
debug("Running hx %s", path);
|
|
||||||
execlp("hx", "hx", path, NULL);
|
|
||||||
} else {
|
|
||||||
debug("Running hx %s", path);
|
|
||||||
execlp("hx", "hx", path, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
error(1, "program", "execlp() failed.");
|
char viv_path[PATH_MAX];
|
||||||
}
|
strncpy(viv_path, path, PATH_MAX - 1);
|
||||||
// ---- kakoune ----
|
viv_path[PATH_MAX - 1] = '\0';
|
||||||
else if (strcmp(editor, "kakoune") == 0) {
|
|
||||||
|
|
||||||
// If render enabled → spawn viv in parallel
|
if (shouldJumpToEndOfFile) {
|
||||||
if (render) {
|
strncat(viv_path, ":99999", PATH_MAX - strlen(viv_path) - 1);
|
||||||
debug("Running Vivify...");
|
}
|
||||||
pid_t viv_pid = fork();
|
|
||||||
error(viv_pid < 0, "program", "fork() failed.");
|
|
||||||
|
|
||||||
if (viv_pid == 0) {
|
debug("Running viv %s", viv_path);
|
||||||
// GRANDCHILD → viv
|
execlp("viv", "viv", viv_path, NULL);
|
||||||
|
error(1, "program", "execlp() failed.");
|
||||||
|
}
|
||||||
|
// IMPORTANT: do NOT wait for viv
|
||||||
|
}
|
||||||
|
|
||||||
char viv_path[PATH_MAX];
|
// Now run nano (this replaces the child process)
|
||||||
strncpy(viv_path, path, PATH_MAX - 1);
|
if (shouldJumpToEndOfFile) {
|
||||||
viv_path[PATH_MAX - 1] = '\0';
|
debug("Running kak + %s", path);
|
||||||
|
execlp("kak", "kak", "+", path, NULL);
|
||||||
|
} else {
|
||||||
|
debug("Running kak %s", path);
|
||||||
|
execlp("kak", "kak", path, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
if (shouldJumpToEndOfFile) {
|
error(1, "program", "execlp() failed.");
|
||||||
strncat(viv_path, ":99999",
|
// ---- VI ----
|
||||||
PATH_MAX - strlen(viv_path) - 1);
|
} else if (strcmp(editor, "vi") == 0) {
|
||||||
|
|
||||||
|
// If render enabled → spawn viv in parallel
|
||||||
|
if (render) {
|
||||||
|
debug("Running Vivify...");
|
||||||
|
pid_t viv_pid = fork();
|
||||||
|
error(viv_pid < 0, "program", "fork() failed.");
|
||||||
|
|
||||||
|
if (viv_pid == 0) {
|
||||||
|
// GRANDCHILD → viv
|
||||||
|
|
||||||
|
char viv_path[PATH_MAX];
|
||||||
|
strncpy(viv_path, path, PATH_MAX - 1);
|
||||||
|
viv_path[PATH_MAX - 1] = '\0';
|
||||||
|
|
||||||
|
if (shouldJumpToEndOfFile) {
|
||||||
|
strncat(viv_path, ":99999", PATH_MAX - strlen(viv_path) - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
debug("Running viv %s", viv_path);
|
||||||
|
execlp("viv", "viv", viv_path, NULL);
|
||||||
|
error(1, "program", "execlp() failed.");
|
||||||
|
}
|
||||||
|
// IMPORTANT: do NOT wait for viv
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now run vi (this replaces the child process)
|
||||||
|
if (shouldJumpToEndOfFile) {
|
||||||
|
debug("Running vi +:$ %s", path);
|
||||||
|
execlp("vi", "vi", "+:$", path, NULL);
|
||||||
|
} else {
|
||||||
|
debug("Running vi %s", path);
|
||||||
|
execlp("vi", "vi", path, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
error(1, "program", "execlp() failed.");
|
||||||
|
// ---- Jed ----
|
||||||
|
} else if (strcmp(editor, "jed") == 0) {
|
||||||
|
|
||||||
|
// If render enabled → spawn viv in parallel
|
||||||
|
if (render) {
|
||||||
|
debug("Running Vivify...");
|
||||||
|
pid_t viv_pid = fork();
|
||||||
|
error(viv_pid < 0, "program", "fork() failed.");
|
||||||
|
|
||||||
|
if (viv_pid == 0) {
|
||||||
|
// GRANDCHILD → viv
|
||||||
|
|
||||||
|
char viv_path[PATH_MAX];
|
||||||
|
strncpy(viv_path, path, PATH_MAX - 1);
|
||||||
|
viv_path[PATH_MAX - 1] = '\0';
|
||||||
|
|
||||||
|
if (shouldJumpToEndOfFile) {
|
||||||
|
strncat(viv_path, ":99999", PATH_MAX - strlen(viv_path) - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
debug("Running viv %s", viv_path);
|
||||||
|
execlp("viv", "viv", viv_path, NULL);
|
||||||
|
error(1, "program", "execlp() failed.");
|
||||||
|
}
|
||||||
|
// IMPORTANT: do NOT wait for viv
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now run jed (this replaces the child process)
|
||||||
|
if (shouldJumpToEndOfFile) {
|
||||||
|
debug("Running jed %s -g 99999999", path);
|
||||||
|
execlp("jed", "jed", path, "-g", "99999999", NULL);
|
||||||
|
} else {
|
||||||
|
debug("Running jed %s", path);
|
||||||
|
execlp("jed", "jed", path, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
error(1, "program", "execlp() failed.");
|
||||||
|
// ---- UNKNOWN EDITOR ----
|
||||||
|
} else {
|
||||||
|
error(1, "program", "Unknown editor.");
|
||||||
}
|
}
|
||||||
|
|
||||||
debug("Running viv %s", viv_path);
|
|
||||||
execlp("viv", "viv", viv_path, NULL);
|
|
||||||
error(1, "program", "execlp() failed.");
|
|
||||||
}
|
|
||||||
// IMPORTANT: do NOT wait for viv
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now run nano (this replaces the child process)
|
|
||||||
if (shouldJumpToEndOfFile) {
|
|
||||||
debug("Running kak + %s", path);
|
|
||||||
execlp("kak", "kak", "+", path, NULL);
|
|
||||||
} else {
|
|
||||||
debug("Running kak %s", path);
|
|
||||||
execlp("kak", "kak", path, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
error(1, "program", "execlp() failed.");
|
|
||||||
// ---- VI ----
|
|
||||||
} else if (strcmp(editor, "vi") == 0) {
|
|
||||||
|
|
||||||
// If render enabled → spawn viv in parallel
|
|
||||||
if (render) {
|
|
||||||
debug("Running Vivify...");
|
|
||||||
pid_t viv_pid = fork();
|
|
||||||
error(viv_pid < 0, "program", "fork() failed.");
|
|
||||||
|
|
||||||
if (viv_pid == 0) {
|
|
||||||
// GRANDCHILD → viv
|
|
||||||
|
|
||||||
|
|
||||||
char viv_path[PATH_MAX];
|
|
||||||
strncpy(viv_path, path, PATH_MAX - 1);
|
|
||||||
viv_path[PATH_MAX - 1] = '\0';
|
|
||||||
|
|
||||||
if (shouldJumpToEndOfFile) {
|
|
||||||
strncat(viv_path, ":99999",
|
|
||||||
PATH_MAX - strlen(viv_path) - 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
debug("Running viv %s", viv_path);
|
|
||||||
execlp("viv", "viv", viv_path, NULL);
|
|
||||||
error(1, "program", "execlp() failed.");
|
|
||||||
}
|
|
||||||
// IMPORTANT: do NOT wait for viv
|
|
||||||
}
|
|
||||||
|
|
||||||
// Now run vi (this replaces the child process)
|
|
||||||
if (shouldJumpToEndOfFile) {
|
|
||||||
debug("Running vi +:$ %s", path);
|
|
||||||
execlp("vi", "vi", "+:$", path, NULL);
|
|
||||||
} else {
|
|
||||||
debug("Running vi %s", path);
|
|
||||||
execlp("vi", "vi", path, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
error(1, "program", "execlp() failed.");
|
|
||||||
// ---- Jed ----
|
|
||||||
} else if (strcmp(editor, "jed") == 0) {
|
|
||||||
|
|
||||||
// If render enabled → spawn viv in parallel
|
|
||||||
if (render) {
|
|
||||||
debug("Running Vivify...");
|
|
||||||
pid_t viv_pid = fork();
|
|
||||||
error(viv_pid < 0, "program", "fork() failed.");
|
|
||||||
|
|
||||||
if (viv_pid == 0) {
|
|
||||||
// GRANDCHILD → viv
|
|
||||||
|
|
||||||
|
|
||||||
char viv_path[PATH_MAX];
|
|
||||||
strncpy(viv_path, path, PATH_MAX - 1);
|
|
||||||
viv_path[PATH_MAX - 1] = '\0';
|
|
||||||
|
|
||||||
if (shouldJumpToEndOfFile) {
|
|
||||||
strncat(viv_path, ":99999",
|
|
||||||
PATH_MAX - strlen(viv_path) - 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
debug("Running viv %s", viv_path);
|
|
||||||
execlp("viv", "viv", viv_path, NULL);
|
|
||||||
error(1, "program", "execlp() failed.");
|
|
||||||
}
|
|
||||||
// IMPORTANT: do NOT wait for viv
|
|
||||||
}
|
|
||||||
|
|
||||||
// Now run jed (this replaces the child process)
|
|
||||||
if (shouldJumpToEndOfFile) {
|
|
||||||
debug("Running jed %s -g 99999999", path);
|
|
||||||
execlp("jed", "jed", path, "-g", "99999999", NULL);
|
|
||||||
} else {
|
|
||||||
debug("Running jed %s", path);
|
|
||||||
execlp("jed", "jed", path, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
error(1, "program", "execlp() failed.");
|
|
||||||
// ---- UNKNOWN EDITOR ----
|
|
||||||
} else {
|
|
||||||
error(1, "program", "Unknown editor.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// =========================
|
// =========================
|
||||||
// PARENT: wait ONLY editor
|
// PARENT: wait ONLY editor
|
||||||
// =========================
|
// =========================
|
||||||
int status;
|
int status;
|
||||||
while (waitpid(editor_pid, &status, 0) == -1) { // we can't just use waitpid(). Because when resizing the terminal, waitpid() is returned so we loop to see if there is not a problem
|
while (waitpid(editor_pid, &status, 0) ==
|
||||||
if (errno != EINTR) {
|
-1) { // we can't just use waitpid(). Because when resizing the terminal, waitpid() is
|
||||||
perror("waitpid");
|
// returned so we loop to see if there is not a problem
|
||||||
break;
|
if (errno != EINTR) {
|
||||||
}
|
perror("waitpid");
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
+35
-32
@@ -1,60 +1,60 @@
|
|||||||
#ifndef UTILS_H
|
#ifndef UTILS_H
|
||||||
#define UTILS_H
|
#define UTILS_H
|
||||||
|
|
||||||
|
#include <cjson/cJSON.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <dirent.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <ftw.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#include <ncurses.h>
|
||||||
|
#include <pwd.h>
|
||||||
|
#include <regex.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <dirent.h>
|
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <unistd.h>
|
|
||||||
#include <ftw.h>
|
|
||||||
#include <pwd.h>
|
|
||||||
#include <ncurses.h>
|
|
||||||
#include <ctype.h>
|
|
||||||
#include <sys/wait.h>
|
#include <sys/wait.h>
|
||||||
#include <limits.h>
|
|
||||||
#include <cjson/cJSON.h>
|
|
||||||
#include <regex.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <ftw.h>
|
#include <unistd.h>
|
||||||
#ifndef VERSION
|
#ifndef VERSION
|
||||||
#define VERSION "dev"
|
#define VERSION "dev"
|
||||||
#endif
|
#endif
|
||||||
#define BUFFER_SIZE 256 //standard buffer size.
|
#define BUFFER_SIZE 256 // standard buffer size.
|
||||||
// the three supported values are "daily" "weekly" and "monthly" (for months we use the avarage lenght of a month in a non leap year). All values were calculated on my loyal TI-30 ECO RS
|
// the three supported values are "daily" "weekly" and "monthly" (for months we use the avarage
|
||||||
|
// lenght of a month in a non leap year). All values were calculated on my loyal TI-30 ECO RS
|
||||||
#define DAILY 86400
|
#define DAILY 86400
|
||||||
#define WEEKLY 604800
|
#define WEEKLY 604800
|
||||||
#define MONTHLY 2628000 // calculated from the average lenght of a non leap year
|
#define MONTHLY 2628000 // calculated from the average lenght of a non leap year
|
||||||
#define debug(message, ...) \
|
#define debug(message, ...) \
|
||||||
_debug(shouldDebug, __FILE__, __LINE__, __func__, message, ##__VA_ARGS__)
|
_debug(shouldDebug, __FILE__, __LINE__, __func__, message, ##__VA_ARGS__)
|
||||||
#define altDebug(message, ...) \
|
#define altDebug(message, ...) _altDebug(shouldDebug, message, ##__VA_ARGS__)
|
||||||
_altDebug(shouldDebug, message, ##__VA_ARGS__)
|
#define error(condition, type, message, ...) \
|
||||||
#define error(condition, type, message, ...) \
|
_error(shouldDebug, condition, type, __FILE__, __LINE__, __func__, message, ##__VA_ARGS__)
|
||||||
_error(shouldDebug, condition, type, __FILE__, __LINE__, __func__, message, ##__VA_ARGS__)
|
|
||||||
// you must edit this two values if you want to add suport for an editor
|
// you must edit this two values if you want to add suport for an editor
|
||||||
extern const char *supportedEditor[]; // array of supported editors
|
extern const char *supportedEditor[]; // array of supported editors
|
||||||
extern const int numEditors; // number of supported editors
|
extern const int numEditors; // number of supported editors
|
||||||
|
|
||||||
|
// compares two strings alphabetically.
|
||||||
//compares two strings alphabetically.
|
// this function is used for qsort
|
||||||
//this function is used for qsort
|
|
||||||
int compareString(const void *a, const void *b);
|
int compareString(const void *a, const void *b);
|
||||||
// compares two strings in reversed alphabetical order
|
// compares two strings in reversed alphabetical order
|
||||||
// this function is used for qsort
|
// this function is used for qsort
|
||||||
int reverseCompareString(const void *a, const void *b);
|
int reverseCompareString(const void *a, const void *b);
|
||||||
// checks if editor is supported and if it installed.
|
// checks if editor is supported and if it installed.
|
||||||
// this basically checks all the dirs from your path for the editor. This is a safety check.
|
// this basically checks all the dirs from your path for the editor. This is a safety check.
|
||||||
// If the executable from an editor is not the editor name (for example neovim and nvim), you must handle at the start of the function.
|
// If the executable from an editor is not the editor name (for example neovim and nvim), you must
|
||||||
// This can return an error and stop the program.
|
// handle at the start of the function. This can return an error and stop the program.
|
||||||
int isEditorValid(char *editorToCheck, int useDefaultEditor, int debug);
|
int isEditorValid(char *editorToCheck, int useDefaultEditor, int debug);
|
||||||
// please use the macro debug instead of _debug.
|
// please use the macro debug instead of _debug.
|
||||||
//formated debugging.
|
// formated debugging.
|
||||||
void _debug(const int d, const char *file, const int line, const char *function, const char *message, ...);
|
void _debug(const int d, const char *file, const int line, const char *function,
|
||||||
//use for less formal debuggin. (usefull if enumerating or making a list).
|
const char *message, ...);
|
||||||
|
// use for less formal debuggin. (usefull if enumerating or making a list).
|
||||||
void _altDebug(const int d, const char *message, ...);
|
void _altDebug(const int d, const char *message, ...);
|
||||||
// formated error.
|
// formated error.
|
||||||
void _error(const int shouldDebug, const int condition, const char *type, const char *file, const int line, const char *function, const char *message, ...);
|
void _error(const int shouldDebug, const int condition, const char *type, const char *file,
|
||||||
|
const int line, const char *function, const char *message, ...);
|
||||||
// Returns 1 if the string is in the array.
|
// Returns 1 if the string is in the array.
|
||||||
// Returns 0 if the string is not in the array.
|
// Returns 0 if the string is not in the array.
|
||||||
// If you want to only check the first n elements of the array, pass n as len.
|
// If you want to only check the first n elements of the array, pass n as len.
|
||||||
@@ -68,8 +68,8 @@ void appendToFile(const char *path, const char *string, const int shouldDebug);
|
|||||||
// replace unwanted chars by '_'.
|
// replace unwanted chars by '_'.
|
||||||
// '.' is replaced if it is only the first two chars
|
// '.' is replaced if it is only the first two chars
|
||||||
void sanitize(char *string);
|
void sanitize(char *string);
|
||||||
//from https://stackoverflow.com/a/5467788.
|
// from https://stackoverflow.com/a/5467788.
|
||||||
//deletes an entire directory. Use with parsimony and carefullness.
|
// deletes an entire directory. Use with parsimony and carefullness.
|
||||||
int rmrf(char *path, int shouldDebug);
|
int rmrf(char *path, int shouldDebug);
|
||||||
// Inputs are the path to the file, the editor to open and some rendering option.
|
// Inputs are the path to the file, the editor to open and some rendering option.
|
||||||
// render: if we render the .md file with Vivify.
|
// render: if we render the .md file with Vivify.
|
||||||
@@ -84,6 +84,9 @@ char *getFormatedTime(char *format, int shouldDebug);
|
|||||||
If need launches in the background rsync to do the backuping.
|
If need launches in the background rsync to do the backuping.
|
||||||
Each pair of source/destination will launch one rsync process.
|
Each pair of source/destination will launch one rsync process.
|
||||||
If a pair don't need to be backed up, the destination should be set to NULL.
|
If a pair don't need to be backed up, the destination should be set to NULL.
|
||||||
rsyncArgs is the array of arguments to be passed to rsync. Do not inclue destination or source. It will be added in the function.*/
|
rsyncArgs is the array of arguments to be passed to rsync. Do not inclue destination or source. It
|
||||||
void handleBackups(char **sourceDirectoryArray, const int sourceDirectoryNumber, char **destinationDirectoryArray, const char *homeDir, const int interval, const char **rsyncArgs, const int rsyncArgsNumber, const int shouldDebug);
|
will be added in the function.*/
|
||||||
|
void handleBackups(char **sourceDirectoryArray, const int sourceDirectoryNumber,
|
||||||
|
char **destinationDirectoryArray, const char *homeDir, const int interval,
|
||||||
|
const char **rsyncArgs, const int rsyncArgsNumber, const int shouldDebug);
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
Reference in New Issue
Block a user