Merge branch 'develop' into main
continuous-integration/drone/push Build is passing Details

This commit is contained in:
tastytea 2019-11-28 09:52:21 +01:00
commit 8b95b43c45
Signed by: tastytea
GPG Key ID: CFC39497F1B26E07
13 changed files with 263 additions and 29 deletions

View File

@ -20,6 +20,7 @@
:uri-ff-addon: https://addons.mozilla.org/firefox/addon/remwharead
:uri-papirus: https://github.com/PapirusDevelopmentTeam/papirus-icon-theme
:uri-hunter: https://github.com/cpp-pm/hunter
:uri-rofi: https://github.com/davatorium/rofi
*remwharead* saves URIs of things you want to remember in a database along with
an URI to the archived version, the current date and time, title, description,
@ -45,6 +46,12 @@ image::{uri-images-base}/example_tags.png[]
See {uri-branch-main}/man/remwharead.1.adoc[manpage] and/or read
{uri-blogpost}[the blogpost].
=== With rofi
The link:{uri-rofi}[rofi] export makes integration with rofi simple. See
link:{uri-branch-main}/scripts/remwharead-rofi[scripts/remwharead-rofi] for an
example.
=== In your programs
The complete functionality is implemented in a C++ library, libremwharead. Take

39
include/export/rofi.hpp Normal file
View File

@ -0,0 +1,39 @@
/* This file is part of remwharead.
* Copyright © 2019 tastytea <tastytea@tastytea.de>
*
* 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, version 3.
*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef REMWHAREAD_EXPORT_ROFI_HPP
#define REMWHAREAD_EXPORT_ROFI_HPP
#include "export.hpp"
namespace remwharead::Export
{
/*!
* @brief Export title, tags and URL for consumption by rofi.
*
* @since 0.9.0
*
* @headerfile rofi.hpp remwharead/export/rofi.hpp
*/
class Rofi : protected ExportBase
{
public:
using ExportBase::ExportBase;
void print() const override;
};
} // namespace remwharead::Export
#endif // REMWHAREAD_EXPORT_ROFI_HPP

View File

@ -46,6 +46,8 @@
#include "export/json.hpp"
#include "export/rss.hpp"
#include "export/simple.hpp"
#include "export/list.hpp"
#include "export/rofi.hpp"
#include "search.hpp"
#include "sqlite.hpp"
#include "time.hpp"

View File

@ -118,6 +118,14 @@ public:
*/
size_t remove(const string &uri);
/*!
* @brief Returns tags as comma separated string.
*
* @since 0.9.0
*/
[[nodiscard]]
static string tags_to_string(const vector<string> &tags);
private:
fs::path _dbpath;
std::unique_ptr<Session> _session;

View File

@ -37,7 +37,8 @@ enum class export_format
simple,
json,
rss,
link
link,
rofi
};
} // namespace remwharead

View File

@ -26,7 +26,8 @@ remwharead - Saves URIs of things you want to remember in a database
the full text of the page and optional tags.
The database can be filtered by time, tags and full text and exported to CSV,
AsciiDoc, a bookmarks file, JSON, RSS or a list of hyperlinks.
AsciiDoc, a bookmarks file, JSON, RSS, a list of hyperlinks or a rofi-compatible
list.
Archiving is done using the Wayback machine from the
https://archive.org/[Internet Archive].
@ -38,7 +39,7 @@ Add tags to _URI_, delimited by commas.
*-e*=_format_, *--export*=_format_::
Export to _format_. Possible values are _csv_, _asciidoc_, _bookmarks_,
_simple_, _json_, _rss_ or _link_. See _FORMATS_.
_simple_, _json_, _rss_, _link_ or _rofi_. See _FORMATS_.
*-f*=_file_, *--file*=_file_::
Save output to _file_. Default is stdout.
@ -77,32 +78,65 @@ Print version, copyright and license.
.Save a thing into the database, with tags.
====
`remwharead -t=tag1,tag2 https://example.com/article.html`
[source,shell]
----
remwharead -t=tag1,tag2 https://example.com/article.html
----
====
.Export all things between and including 2019-04-01 and 2019-05-31 to a file.
====
`remwharead -e=asciidoc -f=out.adoc -T=2019-04-01,2019-05-31`
[source,shell]
----
remwharead -e=asciidoc -f=out.adoc -T=2019-04-01,2019-05-31
----
====
.Export all things to an HTML file.
====
`remwharead -e=asciidoc | asciidoctor --backend=html5 --out-file=out.html -`
[source,shell]
----
remwharead -e=asciidoc | asciidoctor --backend=html5 --out-file=out.html -
----
====
.Export all things about GRUB the boot-loader, but nothing about caterpillars.
====
`remwharead -e=csv -s="grub AND boot"`
[source,shell]
----
remwharead -e=csv -s="grub AND boot"
----
====
.Output all articles by Jan Müller, consider different spellings.
====
`remwharead -e=simple -S='Jan[\s]+M(ü|ue?)ller' -r`
[source,shell]
----
remwharead -e=simple -S='Jan[\s]+M(ü|ue?)ller' -r
----
====
.Export all things from the last week to an RSS feed.
====
`remwharead -e=rss -T=$(date -d "-1 week" -I),$(date -Iminutes) | sed 's|<link/>|<link>https://example.com/</link>|' > /var/www/feed.rss`
[source,shell]
----
remwharead -e=rss -T=$(date -d "-1 week" -I),$(date -Iminutes) | sed 's|<link/>|<link>https://example.com/</link>|' > /var/www/feed.rss
----
====
.Remove all entries that are tagged with mountain
====
[source,shell]
----
OLDIFS=${IFS}
IFS=$'\n'
for uri in $(remwharead -e link -s mountain); do
remwharead -d "${uri}"
done
IFS=${OLDIFS}
----
====
=== Display database
@ -158,6 +192,11 @@ specification (the element _link_ in _channel_ is empty).
Export as a plain list of links, separated by newlines.
=== rofi
Export title, tags and URL for consumption by rofi. See the `scripts/` directory
on https://schlomp.space/tastytea/remwharead for an example.
== SEARCH EXPRESSIONS
A search expression is either a single term, or several terms separated by _AND_

15
scripts/remwharead-rofi Executable file
View File

@ -0,0 +1,15 @@
#!/bin/sh
# Open the whole database in rofi. Searches in title, tags and URI.
# The selected entry will be opened with the default browser.
if [ -n "${2}" ]; then
uri=$(echo "${*}" | sed -E 's|^.+>([^><]+)</span>$|\1|')
xdg-open "${uri}"
exit 0
fi
if [ "${1}" = "runremwharead" ]; then
remwharead -e rofi
else
rofi -show remwharead -modi remwharead:"${0} runremwharead"
fi

View File

@ -20,6 +20,7 @@
#include "export/csv.hpp"
#include "export/json.hpp"
#include "export/link.hpp"
#include "export/rofi.hpp"
#include "export/rss.hpp"
#include "export/simple.hpp"
#include "search.hpp"
@ -228,6 +229,19 @@ int App::main(const std::vector<std::string> &args)
}
break;
}
case export_format::rofi:
{
if (file.is_open())
{
Export::Rofi(entries, file).print();
file.close();
}
else
{
Export::Rofi(entries).print();
}
break;
}
default:
{
break;

View File

@ -156,6 +156,10 @@ void App::handle_options(const std::string &name, const std::string &value)
{
_format = export_format::link;
}
else if (value == "rofi")
{
_format = export_format::rofi;
}
else
{
cerr << "Error: Unknown format.\n";

View File

@ -30,19 +30,10 @@ void Export::CSV::print() const
<< R"("Title","Description","Full text")" << "\r\n";
for (const Database::entry &entry : _entries)
{
string strtags;
for (const string &tag : entry.tags)
{
strtags += tag;
if (tag != *(entry.tags.rbegin()))
{
strtags += ",";
}
}
_out << '"' << quote(entry.uri) << "\",\""
<< quote(entry.archive_uri) << "\",\""
<< timepoint_to_string(entry.datetime) << "\",\""
<< quote(strtags) << "\",\""
<< quote(Database::tags_to_string(entry.tags)) << "\",\""
<< quote(entry.title) << "\",\""
<< quote(entry.description) << "\",\""
<< quote(entry.fulltext_oneline()) << '"'<< "\r\n";

39
src/lib/export/rofi.cpp Normal file
View File

@ -0,0 +1,39 @@
/* This file is part of remwharead.
* Copyright © 2019 tastytea <tastytea@tastytea.de>
*
* 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, version 3.
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "export/rofi.hpp"
#include "sqlite.hpp"
#include <string>
namespace remwharead
{
using std::string;
void Export::Rofi::print() const
{
_out << static_cast<char>(0x00) << "markup-rows"
<< static_cast<char>(0x1f) << "true\n";
for (const Database::entry & entry : _entries)
{
_out << entry.title
<< R"( <span size="small" weight="light" style="italic">()"
<< Database::tags_to_string(entry.tags) << ")</span> "
<< R"(<span size="xx-small" weight="ultralight">)"
<< entry.uri << "</span>\n";
}
}
} // namespace remwharead

View File

@ -84,18 +84,9 @@ void Database::store(const Database::entry &data) const
try
{
const string strdatetime = timepoint_to_string(data.datetime, true);
string strtags;
string strtags = tags_to_string(data.tags);
Statement insert(*_session);
for (const string &tag : data.tags)
{
strtags += tag;
if (tag != *(data.tags.rbegin()))
{
strtags += ",";
}
}
// useRef() uses the const reference.
insert << "INSERT INTO remwharead "
"VALUES(?, ?, ?, ?, ?, ?, ?);",
@ -175,6 +166,22 @@ size_t Database::remove(const string &uri)
return del.execute();
}
string Database::tags_to_string(const vector<string> &tags)
{
string strtags;
for (const string &tag : tags)
{
strtags += tag;
if (tag != *(tags.rbegin()))
{
strtags += ',';
}
}
return strtags;
}
fs::path Database::get_data_home() const
{
fs::path path;

68
tests/test_rofi.cpp Normal file
View File

@ -0,0 +1,68 @@
/* This file is part of remwharead.
* Copyright © 2019 tastytea <tastytea@tastytea.de>
*
* 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, version 3.
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include <exception>
#include <string>
#include <catch.hpp>
#include "sqlite.hpp"
#include "export/rofi.hpp"
using namespace remwharead;
using std::string;
SCENARIO ("The Rofi export works correctly")
{
bool exception = false;
bool rofi_ok = true;
GIVEN ("One database entry")
{
Database::entry entry;
entry.uri = "https://example.com/page.html";
entry.title = "Thoughtful title";
entry.tags = { "tag1", "tag2" };
const string expected = static_cast<char>(0x00) + string("markup-rows")
+ static_cast<char>(0x1f) + "true\n"
"Thoughtful title "
R"(<span size="small" weight="light" style="italic">(tag1,tag2))"
R"(</span> <span size="xx-small" weight="ultralight">)"
"https://example.com/page.html</span>\n";
try
{
std::ostringstream output;
Export::Rofi({ entry }, output).print();
const string rofi = output.str();
if (rofi != expected)
{
rofi_ok = false;
}
}
catch (const std::exception &e)
{
exception = true;
}
THEN ("No exception is thrown")
AND_THEN ("Output looks okay")
{
REQUIRE_FALSE(exception);
REQUIRE(rofi_ok);
}
}
}