<commit_before>#include <itemlistformaction.h>

#include <cassert>
#include <cinttypes>
#include <cstdio>
#include <langinfo.h>
#include <sstream>
#include <string>
#include <sys/stat.h>

#include "config.h"
#include "controller.h"
#include "dbexception.h"
#include "fmtstrformatter.h"
#include "logger.h"
#include "matcherexception.h"
#include "rssfeed.h"
#include "scopemeasure.h"
#include "strprintf.h"
#include "utils.h"
#include "view.h"

namespace newsboat {

ItemListFormAction::ItemListFormAction(View* vv,
	std::string formstr,
	Cache* cc,
	FilterContainer& f,
	ConfigContainer* cfg,
	RegexManager& r)
	: ListFormAction(vv, formstr, "items", cfg)
	, pos(0)
	, apply_filter(false)
	, show_searchresult(false)
	, search_dummy_feed(new RssFeed(cc))
	, set_filterpos(false)
	, filterpos(0)
	, rxman(r)
	, old_width(0)
	, old_itempos(-1)
	, invalidation_mode(InvalidationMode::NONE)
	, listfmt(&rxman, "articlelist")
	, rsscache(cc)
	, filters(f)
{
	search_dummy_feed->set_search_feed(true);
	register_format_styles();
}

ItemListFormAction::~ItemListFormAction() {}

bool ItemListFormAction::process_operation(Operation op,
	bool automatic,
	std::vector<std::string>* args)
{
	bool quit = false;
	bool hardquit = false;

	/*
	 * most of the operations go like this:
	 *   - extract the current position
	 *   - if an item was selected, then fetch it and do something with it
	 */

	const unsigned int itempos = list.get_position();

	switch (op) {
	case OP_OPEN: {
		LOG(Level::INFO, "ItemListFormAction: opening item at pos `%u'", itempos);
		if (!visible_items.empty()) {
			// no need to mark item as read, the itemview already do
			// that
			old_itempos = itempos;
			v->push_itemview(feed,
				visible_items[itempos].first->guid(),
				show_searchresult ? searchphrase : "");
			invalidate(itempos);
		} else {
			v->show_error(
				_("No item selected!")); // should not happen
		}
	}
	break;
	case OP_DELETE: {
		ScopeMeasure m1("OP_DELETE");
		if (!visible_items.empty()) {
			// mark as read
			v->get_ctrl()->mark_article_read(
				visible_items[itempos].first->guid(), true);
			visible_items[itempos].first->set_unread(false);
			// mark as deleted
			visible_items[itempos].first->set_deleted(
				!visible_items[itempos].first->deleted());
			rsscache->mark_item_deleted(
				visible_items[itempos].first->guid(),
				visible_items[itempos].first->deleted());
			if (itempos < visible_items.size() - 1) {
				list.set_position(itempos + 1);
			}
			invalidate(itempos);
		} else {
			v->show_error(
				_("No item selected!")); // should not happen
		}
	}
	break;
	case OP_DELETE_ALL: {
		ScopeMeasure m1("OP_DELETE_ALL");
		if (visible_items.size() > 0) {
			v->get_ctrl()->mark_all_read(pos);
			for (const auto& pair : visible_items) {
				pair.first->set_deleted(true);
			}
			if (feed->is_query_feed()) {
				for (const auto& pair : visible_items) {
					rsscache->mark_item_deleted(pair.first->guid(), true);
				}
			} else {
				rsscache->mark_feed_items_deleted(feed->rssurl());
			}
			invalidate_everything();
		}
	}
	break;
	case OP_PURGE_DELETED: {
		ScopeMeasure m1("OP_PURGE_DELETED");
		feed->purge_deleted_items();
		invalidate_everything();
	}
	break;
	case OP_OPENBROWSER_AND_MARK: {<commit_msg>Don't mark first feed read when deleting all items in search itemlist<commit_after>#include <itemlistformaction.h>

#include <cassert>
#include <cinttypes>
#include <cstdio>
#include <langinfo.h>
#include <sstream>
#include <string>
#include <sys/stat.h>

#include "config.h"
#include "controller.h"
#include "dbexception.h"
#include "fmtstrformatter.h"
#include "logger.h"
#include "matcherexception.h"
#include "rssfeed.h"
#include "scopemeasure.h"
#include "strprintf.h"
#include "utils.h"
#include "view.h"

namespace newsboat {

ItemListFormAction::ItemListFormAction(View* vv,
	std::string formstr,
	Cache* cc,
	FilterContainer& f,
	ConfigContainer* cfg,
	RegexManager& r)
	: ListFormAction(vv, formstr, "items", cfg)
	, pos(0)
	, apply_filter(false)
	, show_searchresult(false)
	, search_dummy_feed(new RssFeed(cc))
	, set_filterpos(false)
	, filterpos(0)
	, rxman(r)
	, old_width(0)
	, old_itempos(-1)
	, invalidation_mode(InvalidationMode::NONE)
	, listfmt(&rxman, "articlelist")
	, rsscache(cc)
	, filters(f)
{
	search_dummy_feed->set_search_feed(true);
	register_format_styles();
}

ItemListFormAction::~ItemListFormAction() {}

bool ItemListFormAction::process_operation(Operation op,
	bool automatic,
	std::vector<std::string>* args)
{
	bool quit = false;
	bool hardquit = false;

	/*
	 * most of the operations go like this:
	 *   - extract the current position
	 *   - if an item was selected, then fetch it and do something with it
	 */

	const unsigned int itempos = list.get_position();

	switch (op) {
	case OP_OPEN: {
		LOG(Level::INFO, "ItemListFormAction: opening item at pos `%u'", itempos);
		if (!visible_items.empty()) {
			// no need to mark item as read, the itemview already do
			// that
			old_itempos = itempos;
			v->push_itemview(feed,
				visible_items[itempos].first->guid(),
				show_searchresult ? searchphrase : "");
			invalidate(itempos);
		} else {
			v->show_error(
				_("No item selected!")); // should not happen
		}
	}
	break;
	case OP_DELETE: {
		ScopeMeasure m1("OP_DELETE");
		if (!visible_items.empty()) {
			// mark as read
			v->get_ctrl()->mark_article_read(
				visible_items[itempos].first->guid(), true);
			visible_items[itempos].first->set_unread(false);
			// mark as deleted
			visible_items[itempos].first->set_deleted(
				!visible_items[itempos].first->deleted());
			rsscache->mark_item_deleted(
				visible_items[itempos].first->guid(),
				visible_items[itempos].first->deleted());
			if (itempos < visible_items.size() - 1) {
				list.set_position(itempos + 1);
			}
			invalidate(itempos);
		} else {
			v->show_error(
				_("No item selected!")); // should not happen
		}
	}
	break;
	case OP_DELETE_ALL: {
		ScopeMeasure m1("OP_DELETE_ALL");
		if (visible_items.size() > 0) {
			if (!feed->is_search_feed()) {
				v->get_ctrl()->mark_all_read(pos);
			} else {
				v->get_ctrl()->mark_all_read(feed);
			}
			for (const auto& pair : visible_items) {
				pair.first->set_deleted(true);
			}
			if (feed->is_query_feed()) {
				for (const auto& pair : visible_items) {
					rsscache->mark_item_deleted(pair.first->guid(), true);
				}
			} else {
				rsscache->mark_feed_items_deleted(feed->rssurl());
			}
			invalidate_everything();
		}
	}
	break;
	case OP_PURGE_DELETED: {
		ScopeMeasure m1("OP_PURGE_DELETED");
		feed->purge_deleted_items();
		invalidate_everything();
	}
	break;
	case OP_OPENBROWSER_AND_MARK: {
{'fraction_non_alphanumeric': 0.14758308157099698, 'fraction_numerical': 0.0030211480362537764, 'mean_word_length': 4.422604422604422, 'pattern_counts': {'":': 0, '<': 23, '<?xml version=': 0, '>': 72, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3713901', 'n_tokens_mistral': 2623, 'n_tokens_neox': 2396, 'n_words': 477}