Skip to content
This repository has been archived by the owner on Oct 10, 2019. It is now read-only.

Commit

Permalink
Andreas Krennmair:
Browse files Browse the repository at this point in the history
	added "contains" and "contains not" operators
	implemented filter for item list
  • Loading branch information
akrennmair committed Jun 1, 2007
1 parent cfc5ea2 commit 3abe90e
Show file tree
Hide file tree
Showing 6 changed files with 114 additions and 30 deletions.
2 changes: 2 additions & 0 deletions doc/newsbeuter.txt
Original file line number Diff line number Diff line change
Expand Up @@ -383,6 +383,8 @@ Operator:Meaning
>:greater than
<=:less than or equal
>=:greater than or equal
#:contains; this operator matches if a word is contained in a list of space-separated words (useful for matching tags, see below)
!#:contains not; the negation of the # operator
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

.Available Attributes
Expand Down
2 changes: 1 addition & 1 deletion filter/FilterParser.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
#include <regex.h>


enum { LOGOP_AND = 1, LOGOP_OR, MATCHOP_EQ, MATCHOP_NE, MATCHOP_RXEQ, MATCHOP_RXNE, MATCHOP_LT, MATCHOP_GT, MATCHOP_LE, MATCHOP_GE };
enum { LOGOP_AND = 1, LOGOP_OR, MATCHOP_EQ, MATCHOP_NE, MATCHOP_RXEQ, MATCHOP_RXNE, MATCHOP_LT, MATCHOP_GT, MATCHOP_LE, MATCHOP_GE, MATCHOP_CONTAINS, MATCHOP_CONTAINSNOT };

struct expression {
expression(const std::string& n, const std::string& lit, int o);
Expand Down
2 changes: 2 additions & 0 deletions filter/filter.atg
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ PRODUCTIONS
| ">" (. op = MATCHOP_GT; .)
| "<=" (. op = MATCHOP_LE; .)
| ">=" (. op = MATCHOP_GE; .)
| "#" (. op = MATCHOP_CONTAINS; .)
| "!#" (. op = MATCHOP_CONTAINSNOT; .)
.

logop<int &lop>
Expand Down
5 changes: 5 additions & 0 deletions include/itemlist_formaction.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,15 @@ class itemlist_formaction : public formaction {
private:
virtual void process_operation(operation op, int raw_char);
void set_head(const std::string& s, unsigned int unread, unsigned int total, const std::string &url);
int get_pos(unsigned int idx);

rss_feed * feed;
unsigned int pos;
bool rebuild_list;
bool apply_filter;
matcher m;
std::vector<std::pair<rss_item *, unsigned int> > visible_items;
bool update_visible_items;
};

}
Expand Down
105 changes: 77 additions & 28 deletions src/itemlist_formaction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,28 @@
namespace newsbeuter {

itemlist_formaction::itemlist_formaction(view * vv, std::string formstr)
: formaction(vv,formstr), feed(0) {
: formaction(vv,formstr), feed(0), apply_filter(false), update_visible_items(false) {
}

itemlist_formaction::~itemlist_formaction() { }

void itemlist_formaction::process_operation(operation op, int /*raw_char*/) {
void itemlist_formaction::process_operation(operation op, int raw_char) {
if ((raw_char == '\n' || raw_char == '\r') && f->get_focus() == "filter") {
std::string filtertext = f->get("filtertext");
f->modify("lastline","replace","{hbox[lastline] .expand:0 {label[msglabel] .expand:h text[msg]:\"\"}}");
if (filtertext.length() > 0) {
if (!m.parse(filtertext)) {
v->show_error(_("Error: couldn't parse filter command!"));
} else {
apply_filter = true;
update_visible_items = true;
do_redraw = true;
}
}
return;
}

bool quit = false;
std::vector<rss_item>& items = feed->items();
switch (op) {
case OP_OPEN: {
std::string itemposname = f->get("itempos");
Expand All @@ -24,7 +38,7 @@ void itemlist_formaction::process_operation(operation op, int /*raw_char*/) {
std::istringstream posname(itemposname);
unsigned int pos = 0;
posname >> pos;
v->push_itemview(feed, items[pos].guid());
v->push_itemview(feed, visible_items[pos].first->guid());
do_redraw = true;
} else {
v->show_error(_("No item selected!")); // should not happen
Expand All @@ -38,8 +52,8 @@ void itemlist_formaction::process_operation(operation op, int /*raw_char*/) {
std::istringstream posname(itemposname);
unsigned int pos = 0;
posname >> pos;
if (pos < feed->items().size()) {
v->open_in_browser(feed->items()[pos].link());
if (pos < visible_items.size()) {
v->open_in_browser(visible_items[pos].first->link());
do_redraw = true;
}
} else {
Expand All @@ -57,12 +71,12 @@ void itemlist_formaction::process_operation(operation op, int /*raw_char*/) {
unsigned int pos = 0;
posname >> pos;

std::string filename = v->run_filebrowser(FBT_SAVE,v->get_filename_suggestion(items[pos].title()));
std::string filename = v->run_filebrowser(FBT_SAVE,v->get_filename_suggestion(visible_items[pos].first->title()));
if (filename == "") {
v->show_error(_("Aborted saving."));
} else {
try {
v->write_item(items[pos], filename);
v->write_item(*visible_items[pos].first, filename);
snprintf(buf, sizeof(buf), _("Saved article to %s"), filename.c_str());
v->show_error(buf);

Expand Down Expand Up @@ -113,12 +127,23 @@ void itemlist_formaction::process_operation(operation op, int /*raw_char*/) {
unsigned int pos = 0;
posname >> pos;
v->set_status(_("Toggling read flag for article..."));
items[pos].set_unread(!items[pos].unread());
visible_items[pos].first->set_unread(!visible_items[pos].first->unread());
v->set_status("");
do_redraw = true;
}
}
break;
case OP_SETFILTER: {
char buf[256];
snprintf(buf,sizeof(buf), "{hbox[lastline] .expand:0 {label .expand:0 text:\"%s\"}{input[filter] modal:1 .expand:h text[filtertext]:\"\"}}", _("Filter: "));
f->modify("lastline", "replace", buf);
f->set_focus("filter");
}
break;
case OP_CLEARFILTER:
apply_filter = false;
do_redraw = true;
break;
default:
break;
}
Expand All @@ -128,35 +153,48 @@ void itemlist_formaction::process_operation(operation op, int /*raw_char*/) {
}

void itemlist_formaction::prepare() {
if (do_redraw) {
if (update_visible_items) {
std::vector<rss_item>& items = feed->items();

std::string code = "{list";
if (visible_items.size() > 0)
visible_items.erase(visible_items.begin(), visible_items.end());

unsigned int i=0;
for (std::vector<rss_item>::iterator it = items.begin(); it != items.end(); ++it, ++i) {
if (!apply_filter || m.matches(&(*it))) {
visible_items.push_back(std::pair<rss_item *, unsigned int>(&(*it), i));
}
}

update_visible_items = false;
}

if (do_redraw) {
std::string code = "{list";

for (std::vector<std::pair<rss_item *, unsigned int> >::iterator it = visible_items.begin(); it != visible_items.end(); ++it) {
std::string line = "{listitem[";
std::ostringstream x;
x << i;
x << it->second;
line.append(x.str());
line.append("] text:");
std::string title;
char buf[20];
snprintf(buf,sizeof(buf),"%4u ",i+1);
snprintf(buf,sizeof(buf),"%4u ",it->second + 1);
title.append(buf);
if (it->unread()) {
if (it->first->unread()) {
title.append("N ");
} else {
title.append(" ");
}
char datebuf[64];
time_t t = it->pubDate_timestamp();
time_t t = it->first->pubDate_timestamp();
struct tm * stm = localtime(&t);
strftime(datebuf,sizeof(datebuf), "%b %d ", stm);
title.append(datebuf);
title.append(it->title());
GetLogger().log(LOG_DEBUG, "itemlist_formaction: XXXTITLE it->title = `%s' title = `%s' quoted title = `%s'",
it->title().c_str(), title.c_str(), stfl::quote(title).c_str());
title.append(it->first->title());
GetLogger().log(LOG_DEBUG, "itemlist_formaction: XXXTITLE it->first->title = `%s' title = `%s' quoted title = `%s'",
it->first->title().c_str(), title.c_str(), stfl::quote(title).c_str());
line.append(stfl::quote(title));
line.append("}");
code.append(line);
Expand Down Expand Up @@ -186,20 +224,19 @@ void itemlist_formaction::set_head(const std::string& s, unsigned int unread, un
}

bool itemlist_formaction::jump_to_next_unread_item(bool start_with_first) {
std::vector<rss_item>& items = feed->items();
unsigned int pos;
std::istringstream is(f->get("itempos"));
is >> pos;
for (unsigned int i=(start_with_first?pos:(pos+1));i<items.size();++i) {
if (items[i].unread()) {
for (unsigned int i=(start_with_first?pos:(pos+1));i<visible_items.size();++i) {
if (visible_items[i].first->unread()) {
std::ostringstream os;
os << i;
f->set("itempos", os.str());
return true;
}
}
for (unsigned int i=0;i<=pos;++i) {
if (items[i].unread()) {
if (visible_items[i].first->unread()) {
std::ostringstream os;
os << i;
f->set("itempos", os.str());
Expand All @@ -210,11 +247,10 @@ bool itemlist_formaction::jump_to_next_unread_item(bool start_with_first) {
}

std::string itemlist_formaction::get_guid() {
std::vector<rss_item>& items = feed->items();
unsigned int pos;
std::istringstream is(f->get("itempos"));
is >> pos;
return items[pos].guid();
return visible_items[pos].first->guid();
}

keymap_hint_entry * itemlist_formaction::get_keymap_hint() {
Expand All @@ -235,10 +271,15 @@ keymap_hint_entry * itemlist_formaction::get_keymap_hint() {
void itemlist_formaction::handle_cmdline(const std::string& cmd) {
unsigned int idx = 0;
if (1==sscanf(cmd.c_str(),"%u",&idx)) {
if (idx > 0 && idx <= feed->items().size()) {
std::ostringstream idxstr;
idxstr << (idx - 1);
f->set("itempos", idxstr.str());
if (idx > 0 && idx <= visible_items[visible_items.size()-1].second + 1) {
int i = get_pos(idx - 1);
if (i == -1) {
v->show_error(_("Position not visible!"));
} else {
std::ostringstream idxstr;
idxstr << i;
f->set("itempos", idxstr.str());
}
} else {
v->show_error(_("Invalid position!"));
}
Expand All @@ -248,5 +289,13 @@ void itemlist_formaction::handle_cmdline(const std::string& cmd) {
}
}

int itemlist_formaction::get_pos(unsigned int realidx) {
for (unsigned int i=0;i<visible_items.size();++i) {
if (visible_items[i].second == realidx)
return i;
}
return -1;
}


}
28 changes: 27 additions & 1 deletion src/matcher.cpp
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
#include <matcher.h>
#include <logger.h>
#include <cassert>
#include <utils.h>

#include <sys/time.h>
#include <ctime>
#include <cassert>
#include <sstream>
#include <vector>

namespace newsbeuter {

Expand Down Expand Up @@ -123,6 +125,30 @@ bool matcher::matches_r(expression * e, matchable * item) {
retval = true;
}
break;
case MATCHOP_CONTAINS: {
std::vector<std::string> elements = utils::tokenize(item->get_attribute(e->name), " ");
std::string literal = e->literal;
retval = false;
for (std::vector<std::string>::iterator it=elements.begin();it!=elements.end();++it) {
if (literal == *it) {
retval = true;
break;
}
}
}
break;
case MATCHOP_CONTAINSNOT: {
std::vector<std::string> elements = utils::tokenize(item->get_attribute(e->name), " ");
std::string literal = e->literal;
retval = true;
for (std::vector<std::string>::iterator it=elements.begin();it!=elements.end();++it) {
if (literal == *it) {
retval = false;
break;
}
}
}
break;
default:
GetLogger().log(LOG_ERROR, "matcher::matches_r: invalid operator %d", e->op);
assert(false); // that's an error condition
Expand Down

0 comments on commit 3abe90e

Please sign in to comment.