mirror of
https://github.com/tomasriveral/NoteWrapper.git
synced 2026-08-11 18:18:36 +02:00
Merge (#9) from tomasriveral/multiple-vault-directories add multiple vault directory
add the code for multiple vault directory. each directory can be backed up to a different dir. added documentation about it. added documentation about changing default config fixed multiple bugs i introduced myself.
This commit is contained in:
+10
-1
@@ -37,7 +37,7 @@ Format:
|
||||
Examples:
|
||||
|
||||
* `Editor (#1): add support for Microsoft Word`
|
||||
* `README.md: fix typos`
|
||||
* `docs: fix typos in README.md`
|
||||
* `Journal: improve entry parsing logic`
|
||||
|
||||
Keep commit messages short and descriptive.
|
||||
@@ -67,6 +67,15 @@ To add support for a new editor, you must update both documentation and source c
|
||||
|
||||
---
|
||||
|
||||
## Changing default configuration
|
||||
|
||||
If you want to change the default configuration or add a new option:
|
||||
1. Update [README's documentation](./README.md#configuration)
|
||||
2. In `./src/utils.c`, update the function `initAppFilesAndDirs()` which creates a default configuration if `~/.config/notewrapper/config.json` or if neither `-c` nor `--config` is set.
|
||||
3. In `./src/main.c` where the JSON is parsed, add the parsing logic. Do not forget the debugging information, errors when wrong type or when an important field is missing and add a default value if a less important field is missing.
|
||||
|
||||
---
|
||||
|
||||
## Before opening a pull request
|
||||
|
||||
Before submitting a pull request, ensure that:
|
||||
|
||||
@@ -102,7 +102,6 @@ As a NixOS user, I will likely package it for **nixpkgs** in the future if the p
|
||||
Usage: notewrapper [options]
|
||||
Options:
|
||||
-c, --config <path/to/config> Specify the config file.
|
||||
-d, --directory <path/to/directory> Specify the vaults' directory.
|
||||
-h, --help Display this message.
|
||||
-e, --editor Specify the editor to open.
|
||||
-j, --jump Jump to the end of the file on opening.
|
||||
@@ -163,7 +162,7 @@ Edit `~/.config/notewrapper/config.json`. If it does not exist, it will be creat
|
||||
|
||||
```json
|
||||
{
|
||||
"directory": "~/Documents/Notes/",
|
||||
"directory": ["~/Documents/Notes/", "/other/paths/"],
|
||||
"render": true,
|
||||
"jumpToEndOfFileOnLaunch": true,
|
||||
"editor": "neovim",
|
||||
@@ -181,7 +180,7 @@ Edit `~/.config/notewrapper/config.json`. If it does not exist, it will be creat
|
||||
|
||||
### Fields
|
||||
|
||||
* `directory`: root directory containing all vaults
|
||||
* `directory`: Array of directories containing the vaults.
|
||||
* `render`: enable/disable Vivify rendering
|
||||
* `jumpToEndOfFileOnLaunch`: move cursor to end of file on open
|
||||
* `editor`: selected editor (must be supported). If not set, it defaults to `$EDITOR`.
|
||||
@@ -207,6 +206,6 @@ It is recommended to use a browser different from your main one for rendering.
|
||||
## Planned features
|
||||
|
||||
* [ ] A converter between journal types
|
||||
* [ ] Support multiple vault directories
|
||||
* [x] Support multiple vault directories
|
||||
* [ ] Port NoteWrapper to other editors (non-exhaustive list of planned ports: `emacs -nw`, `jed`, `ad`, flow-control, `ee`, `amp`, `dte`, `cano`, `mle`, `zee`, `ptext`, `kibi`, `ox`, `ne`, `dit`, `zile`, `moe`, `joe`, `pico`, `vis`)
|
||||
* [x] Default to $EDITOR
|
||||
|
||||
-14
@@ -1,14 +0,0 @@
|
||||
{
|
||||
"directory": "~/Documents/Notes/",
|
||||
"render": true,
|
||||
"jumpToEndOfFileOnLaunch": true,
|
||||
"editor": "neovim",
|
||||
"journalRegex": ".*journal.*",
|
||||
"dateEntry": "# %Y %m %d %a",
|
||||
"newLineOnOpening": true,
|
||||
"backup": {
|
||||
"enable": false,
|
||||
"directory": "/path/to/backup",
|
||||
"interval": "weekly"
|
||||
}
|
||||
}
|
||||
+53
-43
@@ -1,6 +1,8 @@
|
||||
#include "cjson/cJSON.h"
|
||||
#include "ui.h"
|
||||
#include "utils.h"
|
||||
#include "notes.h"
|
||||
#include <stdio.h>
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
int shouldDebug = 0;
|
||||
@@ -100,20 +102,33 @@ arg_next:
|
||||
if (!json) {free(data);}
|
||||
error(!json, "program", "JSON parse error");
|
||||
|
||||
// Parse all of the directories which will( or do) contain the vaults
|
||||
cJSON *dirJson = cJSON_GetObjectItem(json, "directory");
|
||||
char *notesDirectoryString = malloc(PATH_MAX);
|
||||
if (dirJson && cJSON_IsString(dirJson) && cJSON_GetStringValue(dirJson) != NULL) { // we replaced all the ->valuestr and ->valueint to cJSON_GetStringValue() and cJSON_GetNumberValue()
|
||||
char *rawPath = cJSON_GetStringValue(dirJson);
|
||||
if (rawPath[0] == '~') { // expands ~ in the path
|
||||
snprintf(notesDirectoryString, PATH_MAX, "%s/%s", homedir, rawPath+1);
|
||||
error(dirJson && !cJSON_IsArray(dirJson), "user", "In %s, \"directory\" is missing or isn't an array", configPath);
|
||||
int numDirectories = cJSON_GetArraySize(dirJson);
|
||||
debug("In %s, detected %d paths in \"directory\"", configPath, numDirectories);
|
||||
error(numDirectories == 0, "user", "In %s, \"directory\" is an empty array.", configPath);
|
||||
|
||||
char **directoriesArray = malloc(numDirectories * sizeof(char*));
|
||||
debug("Directories:");
|
||||
cJSON *tempEntry = NULL;
|
||||
int i = 0;
|
||||
cJSON_ArrayForEach(tempEntry, dirJson) { // iterate over all the elements of the array _i. e._ over all the dirs
|
||||
if (tempEntry && cJSON_IsString(tempEntry)) {
|
||||
if (cJSON_GetStringValue(tempEntry)[0] == '~') { // we must expand ~
|
||||
char *tempUnFixedName = cJSON_GetStringValue(tempEntry);
|
||||
tempUnFixedName++; // shifts and removes the ~
|
||||
directoriesArray[i] = malloc(PATH_MAX);
|
||||
debug("~ in %s was expanded to %s", tempUnFixedName, homedir);
|
||||
snprintf(directoriesArray[i], PATH_MAX, "%s%s", homedir, tempUnFixedName);
|
||||
} else {
|
||||
directoriesArray[i] = strdup(cJSON_GetStringValue(tempEntry));
|
||||
altDebug("%s\n",directoriesArray[i]);
|
||||
}
|
||||
} else {
|
||||
notesDirectoryString = rawPath;
|
||||
error(1, "user", "In %s, in \"directory\", invalid type of one of the entries.", configPath);
|
||||
}
|
||||
debug("In %s, \"directory\" was set to %s.", configPath, notesDirectoryString);
|
||||
} else {
|
||||
// default vault path if it is not set in the config
|
||||
snprintf(notesDirectoryString, PATH_MAX, "%s/Documents/Notes/", homedir);
|
||||
debug("In %s, \"directory\" wasn't set or we encountered a abnormal type. Defaulting to %s.", configPath, notesDirectoryString);
|
||||
i++;
|
||||
}
|
||||
|
||||
// fetch the render and jumpToEnfOfFileOnLaunch bools
|
||||
@@ -178,7 +193,8 @@ arg_next:
|
||||
|
||||
int doesBackup = 0;
|
||||
int interval = 0; // this is an int. But some times it will be inputed a string. We must translate it.
|
||||
char *pathToBackup = malloc(PATH_MAX);
|
||||
// to handle linking each directory to its backup path. We create an array of char*. If we want to backup the ith directory, the ith pointer will point to the path. Else, we set the ith pointer to NULL.
|
||||
char **backupDirectoriesArray = malloc(numDirectories*sizeof(char*));
|
||||
char **rsyncArgs = NULL;
|
||||
int rsyncArgsNumber = 0;
|
||||
cJSON *backupJSON = cJSON_GetObjectItem(json, "backup");
|
||||
@@ -187,19 +203,22 @@ arg_next:
|
||||
if (doesBackupJSON && cJSON_IsBool(doesBackupJSON)) {
|
||||
doesBackup = cJSON_IsTrue(doesBackupJSON) ? 1 : 0;
|
||||
debug("doesBackup is set to %d", doesBackup);
|
||||
// handles the path to the backup
|
||||
if (!doesBackup) {
|
||||
goto backup_config_end; // easier to just go to rather than do a big if statement
|
||||
}
|
||||
|
||||
// handles the path to the backup for each directory
|
||||
cJSON *pathToBackupJSON = cJSON_GetObjectItem(backupJSON, "directory");
|
||||
if (pathToBackupJSON && cJSON_IsString(pathToBackupJSON)) {
|
||||
char *temp = cJSON_GetStringValue(pathToBackupJSON); // we name it temp. As we can't directly set pathToBackup because snprintf doesn't like when a pointer is both an arg and the destination // temp should be freed when free(json), because cJSON_GetStringValue returns a pointer.
|
||||
if (temp[0] == '~') { // expands ~
|
||||
temp++; // we shift by one to remove ~
|
||||
snprintf(pathToBackup, PATH_MAX, "%s/%s", homedir, temp);
|
||||
debug("~ was expanded to %s\nThe backup path is %s", homedir, pathToBackup);
|
||||
} else {
|
||||
pathToBackup = strndup(temp, PATH_MAX); // temp will be freed later so strndup
|
||||
debug("Directory for backup is set to %s in %s", pathToBackup, configPath);
|
||||
error(cJSON_IsObject(pathToBackupJSON), "user", "In %s, incorrect type for \"backup\". It must be a JSON object.");
|
||||
for (int i = 0; i < numDirectories; i++) { // we iterate over every
|
||||
cJSON *pathToBackupForIthDirectoryJSON = cJSON_GetObjectItem(pathToBackupJSON, directoriesArray[i]);
|
||||
if (pathToBackupForIthDirectoryJSON) {
|
||||
backupDirectoriesArray[i] = strdup(cJSON_GetStringValue(pathToBackupForIthDirectoryJSON));
|
||||
} else { // else no path is set. So we won't backup it.
|
||||
backupDirectoriesArray[i] = NULL;
|
||||
}
|
||||
} else {error(1, "user", "%s did not contained a directory inside the backup section or the value is from an unexpected type", configPath);}
|
||||
}
|
||||
|
||||
// handles the interval of backup
|
||||
cJSON *intervalJSON = cJSON_GetObjectItem(backupJSON, "interval");
|
||||
if (intervalJSON && cJSON_IsString(intervalJSON)) {
|
||||
@@ -237,7 +256,7 @@ arg_next:
|
||||
} else {
|
||||
debug("In %s, \"backup\" wasn't set or we encountered a abnormal type. Defaulting to {\"enable\": false}.", configPath);
|
||||
}
|
||||
|
||||
backup_config_end:
|
||||
|
||||
|
||||
//cleans up
|
||||
@@ -268,11 +287,6 @@ for (int i = 1; i < argc; i++) {
|
||||
overwriteConfigPath = ++i;
|
||||
debug("--config set to %s", argv[i]);
|
||||
|
||||
} else if (strcmp(arg, "--directory") == 0) {
|
||||
error(i + 1 == argc, "user", "Missing argument for --directory");
|
||||
notesDirectoryString = argv[++i];
|
||||
debug("--directory set to %s", notesDirectoryString);
|
||||
|
||||
} else if (strcmp(arg, "--editor") == 0) {
|
||||
error(i + 1 == argc, "user", "Missing argument for --editor");
|
||||
editorToOpen = argv[++i];
|
||||
@@ -311,7 +325,6 @@ for (int i = 1; i < argc; i++) {
|
||||
printf("Usage: notewrapper [options]\n");
|
||||
printf("Options:\n");
|
||||
printf(" -c, --config <path/to/config> Specify the config file.\n");
|
||||
printf(" -d, --directory <path/to/directory> Specify the vaults' directory.\n");
|
||||
printf(" -h, --help Display this message.\n");
|
||||
printf(" -e, --editor Specify the editor to open.\n");
|
||||
printf(" -j, --jump Jumps to the end of the file on opening.\n");
|
||||
@@ -369,7 +382,6 @@ for (int i = 1; i < argc; i++) {
|
||||
printf("Usage: notewrapper [options]\n");
|
||||
printf("Options:\n");
|
||||
printf(" -c, --config <path/to/config> Specify the config file.\n");
|
||||
printf(" -d, --directory <path/to/directory> Specify the vaults' directory.\n");
|
||||
printf(" -h, --help Display this message.\n");
|
||||
printf(" -e, --editor Specify the editor to open.\n");
|
||||
printf(" -j, --jump Jumps to the end of the file on opening.\n");
|
||||
@@ -383,7 +395,6 @@ for (int i = 1; i < argc; i++) {
|
||||
return 0;
|
||||
|
||||
// -------- flags with arguments (MUST be last in group) --------
|
||||
case 'd':
|
||||
case 'e':
|
||||
case 'n':
|
||||
case 'v':
|
||||
@@ -400,11 +411,6 @@ for (int i = 1; i < argc; i++) {
|
||||
char *value = argv[++i];
|
||||
|
||||
switch (opt) {
|
||||
case 'd':
|
||||
notesDirectoryString = value;
|
||||
debug("-d set directory to %s", value);
|
||||
break;
|
||||
|
||||
case 'e':
|
||||
editorToOpen = value;
|
||||
defaultEditor = 0;
|
||||
@@ -451,7 +457,7 @@ next_arg:
|
||||
isEditorValid(editorToOpen, defaultEditor, shouldDebug); // check if editor is supported and if it is installed. If not, it will throw an error.
|
||||
|
||||
if (doesBackup) {
|
||||
handleBackups(notesDirectoryString, pathToBackup, homedir, interval, (const char**)rsyncArgs, rsyncArgsNumber, shouldDebug);
|
||||
handleBackups(directoriesArray, numDirectories, backupDirectoriesArray, homedir, interval, (const char**)rsyncArgs, rsyncArgsNumber, shouldDebug);
|
||||
}
|
||||
|
||||
initscr(); //initialize ncurses
|
||||
@@ -463,7 +469,8 @@ next_arg:
|
||||
char *vaultSelected = NULL;
|
||||
|
||||
int vaultsCount = 0;
|
||||
char **vaultsArray = getVaultsFromDirectory(notesDirectoryString, &vaultsCount, shouldDebug);
|
||||
int *vaultsCountForEachDirectory = malloc(numDirectories*sizeof(int));
|
||||
char **vaultsArray = getVaultsFromDirectories(directoriesArray, numDirectories, vaultsCountForEachDirectory, &vaultsCount, shouldDebug); // when selecting each vault won't show the directory from which they come. We will find this later.
|
||||
|
||||
// bypass if -v or --vault is set
|
||||
if (bypassSelectionVault) {
|
||||
@@ -480,7 +487,6 @@ next_arg:
|
||||
}
|
||||
}
|
||||
|
||||
qsort(vaultsArray, vaultsCount, sizeof(const char *), compareString); // sorts the vaults alphabetically
|
||||
debug("┌--------------------------------\nAvailable vaults:");
|
||||
if (shouldDebug) {
|
||||
for (int i = 0; i < vaultsCount; i++) {
|
||||
@@ -505,13 +511,14 @@ next_arg:
|
||||
free(vaultsArray[i]); // we must only free the vaults options and not the extraOptions to avoid segfault
|
||||
}
|
||||
}
|
||||
free(vaultsArray);
|
||||
|
||||
debug("Selected vault: %s", vaultSelected);
|
||||
if (strcmp(vaultSelected,"Create a new vault") != 0 && strcmp(vaultSelected,"Settings") != 0 && strcmp(vaultSelected,"Quit (Ctrl+C)") != 0) {
|
||||
note_selection:
|
||||
bypassSelectionVault = 0; // we must reset bypassSelectionVault to not get stuck in a infinite loop of bypassing
|
||||
int shouldChangeVault = 0;
|
||||
// we must find the directory from which the vault comes again.
|
||||
char *notesDirectoryString = getDirectoryFromVault(vaultSelected, vaultsArray, vaultsCount, vaultsCountForEachDirectory, directoriesArray, numDirectories, shouldDebug);
|
||||
while (!shouldExit && !shouldChangeVault) {
|
||||
// this loop is the note selector
|
||||
int filesCount = 0;
|
||||
@@ -598,6 +605,8 @@ note_creation:
|
||||
} else if (strcmp(noteSelected,"Back to vault selection") == 0) {
|
||||
shouldChangeVault = 1;
|
||||
} else if (strcmp(noteSelected, "Delete vault") == 0) {
|
||||
// we must find where does the vault comes from.
|
||||
char *notesDirectoryString = getDirectoryFromVault(vaultSelected, vaultsArray, vaultsCount, vaultsCountForEachDirectory, directoriesArray, numDirectories, shouldDebug);
|
||||
const char *yesNo[] = {"No, go back to note selection.", "Yes."};
|
||||
char *answer = ncursesSelect((char **)yesNo, "Are you sure you want to delete the entire vault? This can not be undone (Use arrows or WASD, Enter to select):", 1, 1, " ", "", "", shouldDebug); debug("You answered: %s for deleting the vault %s", answer, vaultSelected);
|
||||
if (strcmp(answer, "Yes.") == 0) {
|
||||
@@ -613,10 +622,10 @@ note_creation:
|
||||
shouldExit = 1;
|
||||
}
|
||||
}
|
||||
|
||||
free(vaultsArray);
|
||||
} else if (strcmp(vaultSelected,"Create a new vault") == 0) {
|
||||
vault_creation:
|
||||
createNewVault(notesDirectoryString, bypassSelectionVault, bypassSelectionVaultValue, shouldDebug);
|
||||
createNewVault(directoriesArray, numDirectories, vaultsArray, vaultsCount, bypassSelectionVault, bypassSelectionVaultValue, shouldDebug);
|
||||
bypassSelectionVault = 0; // we need to reset bypassSelectionVault to avoid getting into an infinite loop of bypassing
|
||||
} else if (strcmp(vaultSelected,"Settings") == 0) {
|
||||
openEditor(configPath, editorToOpen, 0, 0, shouldDebug); // as this is not a md file we set render and jumptoEnfOfFile to 0
|
||||
@@ -626,5 +635,6 @@ vault_creation:
|
||||
}
|
||||
}
|
||||
free(configPath);
|
||||
free(directoriesArray);
|
||||
return 0;
|
||||
}
|
||||
|
||||
+69
-26
@@ -1,5 +1,30 @@
|
||||
#include "notes.h"
|
||||
#include "ui.h"
|
||||
#include "utils.h"
|
||||
|
||||
char *getDirectoryFromVault(char *targetVault, char **vaultsArray, int vaultTotalNumber, int *vaultNumberPerDirectory, char **directoryArray, int directoryNumber, int shouldDebug) {
|
||||
debug("Searching the vault %s inside all the directories...", targetVault);
|
||||
debug("Here are how many vaults there is per directory:");
|
||||
for (int i = 0; i < directoryNumber; i++) {
|
||||
altDebug("%d for %s\n", vaultNumberPerDirectory[i], directoryArray[i]);
|
||||
}
|
||||
debug("Here are all the vaults in the order they will be searched:");
|
||||
for (int i = 0; i < vaultTotalNumber; i++) {
|
||||
altDebug("%s\n", vaultsArray[i]);
|
||||
}
|
||||
int index = 0;
|
||||
|
||||
for (int i = 0; i < directoryNumber; i++) {
|
||||
for (int j = 0; j < vaultNumberPerDirectory[i]; j++) {
|
||||
if (strcmp(vaultsArray[index], targetVault) == 0) {
|
||||
debug("%s found in %s. (index %d)", targetVault, directoryArray[i], index);
|
||||
return directoryArray[i];
|
||||
}
|
||||
index++;
|
||||
}
|
||||
}
|
||||
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.";
|
||||
}
|
||||
|
||||
char **getJournalsFromVault(char *pathToVault, char *vault, char *journalRegex, int *count, int shouldDebug) {
|
||||
debug("Searching %s for journals", vault);
|
||||
@@ -90,38 +115,56 @@ char** getNotesFromVault(char *pathToVault, char *vault, char *journalRegex, int
|
||||
return notesArray;
|
||||
}
|
||||
|
||||
char **getVaultsFromDirectory(char *dirString, int *count, int shouldDebug) {
|
||||
// this function is inputed a path to a directory (which comes usually from the config file) and outpus all the suitable directories (so not the hidden ones) which will serve as separate vaults for notes
|
||||
debug("Opening %s ", dirString);
|
||||
char **getVaultsFromDirectories(char **directoryStringArray, int directoryNumber, int *vaultsPerDirectoryNumber, int *count, int shouldDebug) {
|
||||
// to avoid having to work with a tree-dimensional array. We will use a 2d and vaultsPerDirectoryNumber will indicate the width of the directories.
|
||||
char **vaultsArray = NULL;
|
||||
int nthVault = 0; // this is only used internally to set the string into the right place in directoryStringArray.
|
||||
int previousStartIndex = 0;
|
||||
for (int i = 0; i < directoryNumber; i++) {
|
||||
debug("Opening %s", directoryStringArray[i]);
|
||||
// originally from https://www.geeksforgeeks.org/c/c-program-list-files-sub-directories-directory/
|
||||
struct dirent *vaultsDirectoryEntry;
|
||||
DIR *vaultsDirectory = opendir(dirString);
|
||||
error(vaultsDirectory==NULL, "program", "Could not open directory %s", dirString);
|
||||
char **dirsArray = NULL; // will contain all the dirs/vaults
|
||||
int dirsCount = 0; // we need to count how many dirs there is to always readjust how many memory we alloc
|
||||
DIR *vaultsDirectory = opendir(directoryStringArray[i]);
|
||||
error(!vaultsDirectory, "program", "Could not open directory %s", directoryStringArray[i]);
|
||||
vaultsPerDirectoryNumber[i] = 0;
|
||||
debug("┌------------------------------\n Detected files and dirs %s:", directoryStringArray[i]);
|
||||
// Refer https://pubs.opengroup.org/onlinepubs/7990989775/xsh/readdir.html
|
||||
// for readdir()
|
||||
debug("┌------------------------------\n Detected files and dirs from the directory:");
|
||||
while ((vaultsDirectoryEntry = readdir(vaultsDirectory)) != NULL) {
|
||||
altDebug("%s\n", vaultsDirectoryEntry->d_name);
|
||||
if (vaultsDirectoryEntry->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", dirString, vaultsDirectoryEntry->d_name); // sets the full absolute path to fullPathEntry
|
||||
|
||||
struct stat metadataPathEntry;
|
||||
if (stat(fullPathEntry, &metadataPathEntry) == 0 && S_ISDIR(metadataPathEntry.st_mode)) { // if this entry is a directory
|
||||
dirsArray = realloc(dirsArray, (dirsCount + 1)*sizeof(char*)); // resize dirsArray so that
|
||||
dirsArray[dirsCount] = strdup(vaultsDirectoryEntry->d_name); // copy the dir name into dirsArray
|
||||
dirsCount++;
|
||||
while((vaultsDirectoryEntry = readdir(vaultsDirectory)) != NULL) {
|
||||
char *entryName = vaultsDirectoryEntry->d_name; // gets the entry as a string value
|
||||
altDebug("%s", entryName);
|
||||
if (entryName[0] != '.') { // if not hidden file/dir
|
||||
char tempFullEntryPath[PATH_MAX]; // we recreate the full path to check it's proprieties
|
||||
snprintf(tempFullEntryPath, PATH_MAX, "%s%s", directoryStringArray[i], entryName);
|
||||
altDebug(" (%s)", tempFullEntryPath);
|
||||
//checking the metadata to see if it is a dir
|
||||
struct stat metadataEntry;
|
||||
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.
|
||||
altDebug(" is a vault\n");
|
||||
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.)\n");
|
||||
}
|
||||
} else {
|
||||
altDebug(" is not a vault (hidden file/dir)\n");
|
||||
}
|
||||
}
|
||||
altDebug("└------------------------------\n");
|
||||
|
||||
// free's some used memory
|
||||
// we sort entries for the same vault. We can't sort them all. This would break the order.
|
||||
qsort(vaultsArray + previousStartIndex, nthVault - previousStartIndex, sizeof(const char *), compareString); // sorts the vaults alphabetically
|
||||
closedir(vaultsDirectory);
|
||||
*count = dirsCount;
|
||||
return dirsArray;
|
||||
previousStartIndex = nthVault;
|
||||
}
|
||||
// we calculate once the total number of vaults to avoid recalculation every time we use it
|
||||
*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) {
|
||||
@@ -135,7 +178,7 @@ char *updateJournal(char *path, char *journal, char *timeFormat, int *journalWas
|
||||
sanitize(dateWithExtension);
|
||||
debug("Sanitized date: %s\n(it might be used later for a file name if the journal is divided)", dateWithExtension);
|
||||
struct stat metadata;
|
||||
error(stat(path, &metadata), "program", "stat() failed to get information about %s", path);
|
||||
stat(path, &metadata);
|
||||
if (S_ISREG(metadata.st_mode)) {
|
||||
debug("%s is a unified journal.", path);
|
||||
if (!isStringInFile(path, date, shouldDebug)) { // if there is no entry for current date
|
||||
|
||||
+9
-2
@@ -2,6 +2,8 @@
|
||||
#define NOTES_H
|
||||
#include "utils.h"
|
||||
#include "ui.h"
|
||||
// find which directory contains targetVault
|
||||
char *getDirectoryFromVault(char *targetVault, char **vaultsArray, int vaultTotalNumber, int *vaultNumberPerDirectory, char **directoryArray, int directoryNumber, int shouldDebug);
|
||||
// gets the journals from the vault.
|
||||
//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.
|
||||
@@ -9,8 +11,13 @@ char **getJournalsFromVault(char *pathToVault, char *vault, char *journalRegex,
|
||||
// this function is inputed a path to a vault (which was selected before) and outpus all the suitable notes (so not the hidden ones).
|
||||
// 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.
|
||||
char **getNotesFromVault(char *pathToVault, char *vault, char *journalRegex, int *count, int shouldDebug);
|
||||
// this function is inputed a path to a directory (which comes usually from the config file) and outpus all the suitable directories (so not the hidden ones) which will serve as separate vaults for notes.
|
||||
char **getVaultsFromDirectory(char *dirString, int *count, int shouldDebug);
|
||||
// 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.
|
||||
char **getVaultsFromDirectories(char **directoryStringArray, int directoryNumber, int *vaultsPerDirectoryNumber, int *count, int shouldDebug);
|
||||
// path is the path to the file.
|
||||
// journal is the name of the file.
|
||||
// journalWasUpdated will be set to 1 if a new entry was created
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
#include "ui.h"
|
||||
#include "utils.h"
|
||||
|
||||
void createNewVault(char *dirToVault, int bypass, char *bypassvalue, int shouldDebug) {
|
||||
void createNewVault(char **directoriesArray, int directoryCount, char **vaultsArray, int vaultCount, int bypass, char *bypassvalue, int shouldDebug) {
|
||||
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:
|
||||
// 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 *vaultName = malloc(PATH_MAX);
|
||||
if (!bypass) { // if won't bypass (if -v or --vault weren't set)
|
||||
echo();
|
||||
@@ -48,13 +51,13 @@ input_screen:
|
||||
sanitize(vaultName);
|
||||
debug("Sanitized vaultName=%s", vaultName);
|
||||
|
||||
struct stat st = {0}; // https://stackoverflow.com/a/7430262
|
||||
char vaultFullPath[PATH_MAX];
|
||||
sprintf(vaultFullPath, "%s/%s/", dirToVault, vaultName);
|
||||
if (stat(vaultFullPath, &st) == -1) {
|
||||
|
||||
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.
|
||||
char vaultFullPath[PATH_MAX]; // recreating the full path
|
||||
sprintf(vaultFullPath, "%s/%s/", dirToVault, vaultName);
|
||||
|
||||
mkdir(vaultFullPath, 0744);
|
||||
} else {
|
||||
// if stat(...) != -1 it means the vault already exist. We will go back to the input screen with a new message.
|
||||
duplicateWarning = 1;
|
||||
goto input_screen;
|
||||
}
|
||||
@@ -109,7 +112,7 @@ char *createNewNote(char dirToVault[PATH_MAX], char *vaultFromDir, int bypass, c
|
||||
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");
|
||||
error(mkdir(fileFullPath, 0744), "program", "mkdir failed");
|
||||
} else {
|
||||
error(1, "program", "%s could not be created", fileFullPath);
|
||||
}
|
||||
@@ -260,7 +263,7 @@ char* fzfSelect(char *pathToFiles, char *selectText, int shouldDebug) {
|
||||
return result;
|
||||
}
|
||||
|
||||
char* ncursesSelect(char **options, char *optionsText, int optionsNumber, int extraOptionsNumber, char *bottomText, char *middleText, char *topText, int shouldDebug) {
|
||||
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)
|
||||
int highlight = 0; //curently highlighted option
|
||||
int key;
|
||||
|
||||
|
||||
@@ -22,11 +22,13 @@ returns the path to the note.
|
||||
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);
|
||||
/*Uses ncurses to get an input from the user.
|
||||
/*
|
||||
Chooses in which directory it want to create the vault.
|
||||
Uses ncurses to get an input from the user.
|
||||
Creates a new vault with this input.
|
||||
If vault already exists, prints a warning.
|
||||
returns nothing. */
|
||||
void createNewVault(char *dirToVault, 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.
|
||||
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.
|
||||
|
||||
+8
-4
@@ -136,9 +136,9 @@ void initAppFilesAndDirs(const char *home, const int shouldDebug) {
|
||||
debug("Creating default config file.");
|
||||
FILE *w = fopen(config_file, "w");
|
||||
error(!w, "program", "fopen failed opening %s");
|
||||
fprintf(w,
|
||||
fprintf(w, //TODO CHANGE default json
|
||||
"{\n"
|
||||
" \"directory\": \"~/Documents/Notes/\",\n"
|
||||
" \"directory\": [\"~/Documents/Notes/\"],\n"
|
||||
" \"render\": true,\n"
|
||||
" \"jumpToEndOfFileOnLaunch\": true,\n"
|
||||
" \"editor\": \"neovim\",\n"
|
||||
@@ -156,7 +156,7 @@ void initAppFilesAndDirs(const char *home, const int shouldDebug) {
|
||||
fclose(w);
|
||||
}
|
||||
|
||||
void handleBackups(const char *pathOfVaults, const char *pathOfBackup, 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;
|
||||
time_t now = time(NULL);
|
||||
debug("Time since epoch is %ld", (long)now);
|
||||
@@ -202,7 +202,11 @@ void handleBackups(const char *pathOfVaults, const char *pathOfBackup, const cha
|
||||
}
|
||||
|
||||
if (shouldBackup) {
|
||||
copyDir(pathOfVaults, pathOfBackup, rsyncArguments, rsyncArgumentsNumber, shouldDebug);
|
||||
for (int i = 0; i < sourceNumber; i++) {
|
||||
if (destinationDirectoryArray[i]) { // if we don't want to backup it, it was set to NULL
|
||||
copyDir(sourceDirectoryArray[i], destinationDirectoryArray[i], rsyncArguments, rsyncArgumentsNumber, shouldDebug);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+3
-1
@@ -82,6 +82,8 @@ int openEditor(char *path, char *editor, int render, int shouldJumpToEndOfFile,
|
||||
char *getFormatedTime(char *format, int shouldDebug);
|
||||
/* Caclulates if we need to do another backup (by reading ~/.cache/NoteWrapper/backupTime.txt.
|
||||
If need launches in the background rsync to do the backuping.
|
||||
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.
|
||||
rsyncArgs is the array of arguments to be passed to rsync. Do not inclue destination or source. It will be added in the function.*/
|
||||
void handleBackups(const char *pathOfVaults, const char *pathOfBackup, const char *homeDir, const int interval, const char **rsyncArgs, const int rsyncArgsNumber, const int shouldDebug);
|
||||
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
|
||||
|
||||
Reference in New Issue
Block a user