diff --git a/documentation/manpages/man.1 b/documentation/manpages/man.1
index 220b8095c..06c5c5038 100644
--- a/documentation/manpages/man.1
+++ b/documentation/manpages/man.1
@@ -151,4 +151,4 @@ Report all bugs to \f[B]https://github.com/Slackadays/Clipboard\f[R] or
\f[B]https://discord.gg/J6asnc3pEG\f[R].
.SS COPYRIGHT
.PP
-Copyright (c) 2023 Jackson Huff.
+Copyright (c) 2022-2024 Jackson Huff.
diff --git a/documentation/manpages/man.md b/documentation/manpages/man.md
index 01ccebdfe..9d940475d 100644
--- a/documentation/manpages/man.md
+++ b/documentation/manpages/man.md
@@ -153,4 +153,4 @@ Report all bugs to __https://github.com/Slackadays/Clipboard__ or __https://disc
## COPYRIGHT
-Copyright (c) 2023 Jackson Huff.
\ No newline at end of file
+Copyright (c) 2022-2024 Jackson Huff.
\ No newline at end of file
diff --git a/src/cb/CMakeLists.txt b/src/cb/CMakeLists.txt
index 102392e50..e97548872 100644
--- a/src/cb/CMakeLists.txt
+++ b/src/cb/CMakeLists.txt
@@ -40,6 +40,7 @@ add_executable(cb
src/utils/files.cpp
src/utils/distance.cpp
src/utils/directorysize.cpp
+ src/utils/cowcopy.cpp
)
enable_lto(cb)
diff --git a/src/cb/src/actions/info.cpp b/src/cb/src/actions/info.cpp
index 029feb1b7..3878071bc 100644
--- a/src/cb/src/actions/info.cpp
+++ b/src/cb/src/actions/info.cpp
@@ -39,13 +39,16 @@ void info() {
fprintf(stderr, "━");
fprintf(stderr, "%s", formatColors("┓[blank]\n").data());
+ auto endbarStr = generatedEndbar();
+ auto endbar = endbarStr.data();
+
// creation date
#if defined(UNIX_OR_UNIX_LIKE)
struct stat info;
stat(path.string().data(), &info);
std::string time(std::ctime(&info.st_ctime));
std::erase(time, '\n');
- fprintf(stderr, formatColors("[info]%s┃ Created [help]%s[blank]\n").data(), generatedEndbar().data(), time.data());
+ fprintf(stderr, formatColors("[info]%s┃ Created [help]%s[blank]\n").data(), endbar, time.data());
#elif defined(_WIN32) || defined(_WIN64)
fprintf(stderr, formatColors("[info]┃ Created [help]n/a[blank]\n").data());
#endif
@@ -59,67 +62,67 @@ void info() {
}
time = std::ctime(&latest);
std::erase(time, '\n');
- fprintf(stderr, formatColors("[info]%s┃ Content last changed [help]%s[blank]\n").data(), generatedEndbar().data(), time.data());
+ fprintf(stderr, formatColors("[info]%s┃ Content last changed [help]%s[blank]\n").data(), endbar, time.data());
#elif defined(_WIN32) || defined(_WIN64)
fprintf(stderr, formatColors("[info]┃ Content last changed [help]%s[blank]\n").data(), std::format("{}", fs::last_write_time(path)).data());
#endif
- fprintf(stderr, formatColors("[info]%s┃ Stored in [help]%s[blank]\n").data(), generatedEndbar().data(), path.string().data());
+ fprintf(stderr, formatColors("[info]%s┃ Stored in [help]%s[blank]\n").data(), endbar, path.string().data());
#if defined(UNIX_OR_UNIX_LIKE)
struct passwd* pw = getpwuid(info.st_uid);
- fprintf(stderr, formatColors("[info]%s┃ Owned by [help]%s[blank]\n").data(), generatedEndbar().data(), pw->pw_name);
+ fprintf(stderr, formatColors("[info]%s┃ Owned by [help]%s[blank]\n").data(), endbar, pw->pw_name);
#elif defined(_WIN32) || defined(_WIN64)
fprintf(stderr, formatColors("[info]┃ Owned by [help]n/a[blank]\n").data());
#endif
- fprintf(stderr, formatColors("[info]%s┃ Persistent? [help]%s[blank]\n").data(), generatedEndbar().data(), path.is_persistent ? "Yes" : "No");
+ fprintf(stderr, formatColors("[info]%s┃ Persistent? [help]%s[blank]\n").data(), endbar, path.is_persistent ? "Yes" : "No");
auto totalEntries = path.totalEntries();
auto totalSize = totalDirectorySize(path);
auto spaceAvailable = fs::space(path).available;
- fprintf(stderr, formatColors("[info]%s┃ Total entries: [help]%zu[blank]\n").data(), generatedEndbar().data(), totalEntries);
- fprintf(stderr, formatColors("[info]%s┃ Total clipboard size: [help]%s[blank]\n").data(), generatedEndbar().data(), formatBytes(totalSize).data());
- fprintf(stderr, formatColors("[info]%s┃ Total space remaining: [help]%s[blank]\n").data(), generatedEndbar().data(), formatBytes(spaceAvailable).data());
- fprintf(stderr, formatColors("[info]%s┃ Approx. entries remaining: [help]%s[blank]\n").data(), generatedEndbar().data(), formatNumbers(spaceAvailable / (totalSize / totalEntries)).data());
+ fprintf(stderr, formatColors("[info]%s┃ Total entries: [help]%zu[blank]\n").data(), endbar, totalEntries);
+ fprintf(stderr, formatColors("[info]%s┃ Total clipboard size: [help]%s[blank]\n").data(), endbar, formatBytes(totalSize).data());
+ fprintf(stderr, formatColors("[info]%s┃ Total space remaining: [help]%s[blank]\n").data(), endbar, formatBytes(spaceAvailable).data());
+ fprintf(stderr, formatColors("[info]%s┃ Approx. entries remaining: [help]%s[blank]\n").data(), endbar, formatNumbers(spaceAvailable / (totalSize / totalEntries)).data());
if (path.holdsRawDataInCurrentEntry()) {
- fprintf(stderr, formatColors("[info]%s┃ Content size: [help]%s[blank]\n").data(), generatedEndbar().data(), formatBytes(fs::file_size(path.data.raw)).data());
- fprintf(stderr, formatColors("[info]%s┃ Content type: [help]%s[blank]\n").data(), generatedEndbar().data(), inferMIMEType(fileContents(path.data.raw).value()).value_or("text/plain").data());
+ fprintf(stderr, formatColors("[info]%s┃ Content size: [help]%s[blank]\n").data(), endbar, formatBytes(fs::file_size(path.data.raw)).data());
+ fprintf(stderr, formatColors("[info]%s┃ Content type: [help]%s[blank]\n").data(), endbar, inferMIMEType(fileContents(path.data.raw).value()).value_or("text/plain").data());
} else {
size_t files = 0;
size_t directories = 0;
- fprintf(stderr, formatColors("[info]%s┃ Content size: [help]%s[blank]\n").data(), generatedEndbar().data(), formatBytes(totalDirectorySize(path.data)).data());
+ fprintf(stderr, formatColors("[info]%s┃ Content size: [help]%s[blank]\n").data(), endbar, formatBytes(totalDirectorySize(path.data)).data());
for (const auto& entry : fs::directory_iterator(path.data))
entry.is_directory() ? directories++ : files++;
- fprintf(stderr, formatColors("[info]%s┃ Files: [help]%zu[blank]\n").data(), generatedEndbar().data(), files);
- fprintf(stderr, formatColors("[info]%s┃ Directories: [help]%zu[blank]\n").data(), generatedEndbar().data(), directories);
+ fprintf(stderr, formatColors("[info]%s┃ Files: [help]%zu[blank]\n").data(), endbar, files);
+ fprintf(stderr, formatColors("[info]%s┃ Directories: [help]%zu[blank]\n").data(), endbar, directories);
}
if (!available_mimes.empty()) {
- fprintf(stderr, formatColors("[info]%s┃ Available types from GUI: [help]").data(), generatedEndbar().data());
+ fprintf(stderr, formatColors("[info]%s┃ Available types from GUI: [help]").data(), endbar);
for (const auto& mime : available_mimes) {
fprintf(stderr, "%s", mime.data());
if (mime != available_mimes.back()) fprintf(stderr, ", ");
}
fprintf(stderr, "%s", formatColors("[blank]\n").data());
}
- fprintf(stderr, formatColors("[info]%s┃ Content cut? [help]%s[blank]\n").data(), generatedEndbar().data(), fs::exists(path.metadata.originals) ? "Yes" : "No");
+ fprintf(stderr, formatColors("[info]%s┃ Content cut? [help]%s[blank]\n").data(), endbar, fs::exists(path.metadata.originals) ? "Yes" : "No");
- fprintf(stderr, formatColors("[info]%s┃ Locked by another process? [help]%s[blank]\n").data(), generatedEndbar().data(), path.isLocked() ? "Yes" : "No");
+ fprintf(stderr, formatColors("[info]%s┃ Locked by another process? [help]%s[blank]\n").data(), endbar, path.isLocked() ? "Yes" : "No");
if (path.isLocked()) {
- fprintf(stderr, formatColors("[info]%s┃ Locked by process with pid [help]%s[blank]\n").data(), generatedEndbar().data(), fileContents(path.metadata.lock).value().data());
+ fprintf(stderr, formatColors("[info]%s┃ Locked by process with pid [help]%s[blank]\n").data(), endbar, fileContents(path.metadata.lock).value().data());
}
if (fs::exists(path.metadata.notes))
- fprintf(stderr, formatColors("[info]%s┃ Note: [help]%s[blank]\n").data(), generatedEndbar().data(), fileContents(path.metadata.notes).value().data());
+ fprintf(stderr, formatColors("[info]%s┃ Note: [help]%s[blank]\n").data(), endbar, fileContents(path.metadata.notes).value().data());
else
- fprintf(stderr, formatColors("[info]%s┃ There is no note for this clipboard.[blank]\n").data(), generatedEndbar().data());
+ fprintf(stderr, formatColors("[info]%s┃ There is no note for this clipboard.[blank]\n").data(), endbar);
if (path.holdsIgnoreRegexes()) {
- fprintf(stderr, formatColors("[info]%s┃ Ignore regexes: [help]").data(), generatedEndbar().data());
+ fprintf(stderr, formatColors("[info]%s┃ Ignore regexes: [help]").data(), endbar);
auto regexes = fileLines(path.metadata.ignore);
for (const auto& regex : regexes) {
fprintf(stderr, "%s", regex.data());
@@ -127,7 +130,26 @@ void info() {
}
fprintf(stderr, "%s", formatColors("[blank]\n").data());
} else
- fprintf(stderr, formatColors("[info]%s┃ There are no ignore regexes for this clipboard.[blank]\n").data(), generatedEndbar().data());
+ fprintf(stderr, formatColors("[info]%s┃ There are no ignore regexes for this clipboard.[blank]\n").data(), endbar);
+
+ if (fs::exists(path.metadata.ignore_secret)) {
+ // list only how many ignore secrets there are
+ auto secrets = fileLines(path.metadata.ignore_secret);
+ fprintf(stderr, formatColors("[info]%s┃ There are %zu ignore secrets for this clipboard.[blank]\n").data(), endbar, secrets.size());
+ } else {
+ fprintf(stderr, formatColors("[info]%s┃ There are no ignore secrets for this clipboard.[blank]\n").data(), endbar);
+ }
+
+ if (fs::exists(path.metadata.script)) {
+ auto script = fileContents(path.metadata.script).value();
+ if (script.size() > 50) {
+ fprintf(stderr, formatColors("[info]%s┃ Script: [help]%s...[blank]\n").data(), endbar, makeControlCharactersVisible(removeExcessWhitespace(script.substr(0, 50))).data());
+ } else {
+ fprintf(stderr, formatColors("[info]%s┃ Script: [help]%s[blank]\n").data(), endbar, makeControlCharactersVisible(removeExcessWhitespace(script)).data());
+ }
+ } else {
+ fprintf(stderr, formatColors("[info]%s┃ There is no script for this clipboard.[blank]\n").data(), endbar);
+ }
fprintf(stderr, "%s", formatColors("[info]┗").data());
int cols = thisTerminalSize().columns;
diff --git a/src/cb/src/locales/en_us.cpp b/src/cb/src/locales/en_us.cpp
index 9504c5c72..d40c5468b 100644
--- a/src/cb/src/locales/en_us.cpp
+++ b/src/cb/src/locales/en_us.cpp
@@ -72,7 +72,7 @@ Message help_message = "[info]┃ This is the Clipboard Project %s (commit %s),
"[info]┃ You can also get more help in our Discord server at [bold]https://discord.gg/J6asnc3pEG[blank]\n"
"[info][bold]┃ All Actions Available[blank]\n"
"%s"
- "[info]┃ Copyright (C) 2023 Jackson Huff. Licensed under the GPLv3.[blank]\n"
+ "[info]┃ Copyright (C) 2022-2024 Jackson Huff. Licensed under the GPLv3.[blank]\n"
"[info]┃ This program comes with ABSOLUTELY NO WARRANTY. This is free software, and you are welcome to "
"redistribute it under certain conditions.[blank]\n";
Message check_clipboard_status_message = "[info][bold]All your clipboards with content[nobold]";
diff --git a/src/cb/src/locales/es_co.cpp b/src/cb/src/locales/es_co.cpp
index 60c741819..c15506c99 100644
--- a/src/cb/src/locales/es_co.cpp
+++ b/src/cb/src/locales/es_co.cpp
@@ -127,7 +127,7 @@ void setLanguageES_CO() {
"-h[nobold], [bold]cb --help[nobold] o[bold] cb help[nobold].\n"
"[info][bold]┃ All Actions Available[blank]\n"
"%s"
- "[info]┃ Copyright (C) 2023 Jackson Huff. Licensed under the GPLv3.[blank]\n"
+ "[info]┃ Copyright (C) 2022-2024 Jackson Huff. Licensed under the GPLv3.[blank]\n"
"[info]┃ This program comes with ABSOLUTELY NO WARRANTY. This is free software, and you are welcome "
"to redistribute it under certain conditions.[blank]\n";
no_valid_action_message = "[error][inverse] ✘ [noinverse] No especificaste ninguna acción válida o se te olvidó. [help]⬤ Inténta usar o añadir [bold]cortar, "
diff --git a/src/cb/src/locales/es_do.cpp b/src/cb/src/locales/es_do.cpp
index 2efd5b281..f51e229e9 100644
--- a/src/cb/src/locales/es_do.cpp
+++ b/src/cb/src/locales/es_do.cpp
@@ -127,7 +127,7 @@ void setLanguageES_DO() {
"-h[nobold], [bold]cb --help[nobold] o[bold] cb help[nobold].\n"
"[info][bold]┃ All Actions Available[blank]\n"
"%s"
- "[info]┃ Copyright (C) 2023 Jackson Huff. Licensed under the GPLv3.[blank]\n"
+ "[info]┃ Copyright (C) 2022-2024 Jackson Huff. Licensed under the GPLv3.[blank]\n"
"[info]┃ This program comes with ABSOLUTELY NO WARRANTY. This is free software, and you are welcome "
"to redistribute it under certain conditions.[blank]\n";
no_valid_action_message = "[error][inverse] ✘ [noinverse] No especificaste ninguna acción válida o se te olvidó. [help]⬤ Inténta usar o añadir [bold]cortar, "
diff --git a/src/cb/src/locales/pt_br.cpp b/src/cb/src/locales/pt_br.cpp
index 31d132c61..d9d7f2837 100644
--- a/src/cb/src/locales/pt_br.cpp
+++ b/src/cb/src/locales/pt_br.cpp
@@ -108,7 +108,7 @@ void setLanguagePT() {
"-h[nobold], [bold]cb --help[nobold] ou[bold] cb help[nobold].\n"
"[info][bold]┃ All Actions Available[blank]\n"
"%s"
- "[info]┃ Copyright (C) 2023 Jackson Huff. Licensed under the GPLv3.[blank]\n"
+ "[info]┃ Copyright (C) 2022-2024 Jackson Huff. Licensed under the GPLv3.[blank]\n"
"[info]┃ Este programa vem com ABSOLUTAMENTE NENHUMA GARANTIA. Este é um software livre, e você é "
"bem-vindo a redistribuí-lo sob certas condições.[blank]\n";
no_valid_action_message = "[error][inverse] ✘ [noinverse] Você não especificou uma ação válida (\"%s\"), ou esqueceu de incluí-la. [help]⬤ Tente utilizar "
diff --git a/src/cb/src/locales/tr_tr.cpp b/src/cb/src/locales/tr_tr.cpp
index e2ac2a8e7..d018c3aed 100644
--- a/src/cb/src/locales/tr_tr.cpp
+++ b/src/cb/src/locales/tr_tr.cpp
@@ -135,7 +135,7 @@ void setLanguageTR() {
"[info][bold]┃ All Actions Available[blank]\n"
"%s"
"[info]┃ Discord sunucumuzdan daha fazla yardım alabilirsiniz: [bold]https://discord.gg/J6asnc3pEG[blank]\n"
- "[info]┃ Copyright (C) 2023 Jackson Huff. Licensed under the GPLv3.[blank]\n"
+ "[info]┃ Copyright (C) 2022-2024 Jackson Huff. Licensed under the GPLv3.[blank]\n"
"[info]┃ GPLv3 altında lisanslanmıştır.[blank]\n"
"[info]┃ Bu program KESİNLİKLE HİÇBİR GARANTİ ile birlikte gelir. Bu ücretsiz bir yazılımdır ve belirli "
"koşullar altında yeniden dağıtabilirsiniz.[blank]\n";
diff --git a/src/cb/src/utils/cowcopy.cpp b/src/cb/src/utils/cowcopy.cpp
new file mode 100644
index 000000000..cb1d103b7
--- /dev/null
+++ b/src/cb/src/utils/cowcopy.cpp
@@ -0,0 +1,21 @@
+/* The Clipboard Project - Cut, copy, and paste anything, anytime, anywhere, all from the terminal.
+ Copyright (C) 2024 Jackson Huff and other contributors on GitHub.com
+ SPDX-License-Identifier: GPL-3.0-or-later
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see .*/
+#include "../clipboard.hpp"
+#if defined(__linux__)
+#include
+#include
+#endif
+
diff --git a/src/cb/src/utils/formatting.cpp b/src/cb/src/utils/formatting.cpp
index 168820eb9..60f80622b 100644
--- a/src/cb/src/utils/formatting.cpp
+++ b/src/cb/src/utils/formatting.cpp
@@ -91,6 +91,8 @@ std::string removeExcessWhitespace(const std::string_view& oldStr, size_t len) {
std::string newStr;
newStr.reserve(oldStr.size());
+ if (len == 0) len = oldStr.size();
+
// Remove all whitespace that isn't a single space (2+ spaces, and tabs)
for (size_t i = 0; i < len && i < oldStr.size(); i++) {
if (oldStr[i] == ' ') {