• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

akrennmair / newsbeuter / 970

pending completion
970

Pull #593

travis-ci

web-flow
improved code quality according to Minoru's advice

added warn_unused_result macros to methods open_in_browser(), open_in_pager()
and run_interactively()
Pull Request #593: intercept browser's/pager's failure (issue #449)

54 of 54 new or added lines in 10 files covered. (100.0%)

4909 of 13390 relevant lines covered (36.66%)

1024.1 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

20.33
/src/view.cpp
1
#include <itemlist.h>
2
#include <itemview.h>
3
#include <help.h>
4
#include <filebrowser.h>
5
#include <urlview.h>
6
#include <selecttag.h>
7
#include <feedlist.h>
8
#include <dialogs.h>
9
#include <formatstring.h>
10

11
#include <formaction.h>
12
#include <feedlist_formaction.h>
13
#include <itemlist_formaction.h>
14
#include <itemview_formaction.h>
15
#include <help_formaction.h>
16
#include <urlview_formaction.h>
17
#include <select_formaction.h>
18
#include <dialogs_formaction.h>
19

20
#include <logger.h>
21
#include <reloadthread.h>
22
#include <exception.h>
23
#include <exceptions.h>
24
#include <keymap.h>
25
#include <utils.h>
26
#include <strprintf.h>
27
#include <regexmanager.h>
28

29
#include <iostream>
30
#include <iomanip>
31
#include <fstream>
32
#include <cerrno>
33

34
#include <assert.h>
35
#include <libgen.h>
36
#include <sys/types.h>
37
#include <dirent.h>
38
#include <grp.h>
39
#include <pwd.h>
40
#include <unistd.h>
41
#include <config.h>
42
#include <sys/param.h>
43
#include <string.h>
44
#include <ncurses.h>
45
#include <curses.h>
46
#include <time.h>
47

48

49
extern "C" {
50
#include <stfl.h>
51
}
52

53
#include <view.h>
54
#include <rss.h>
55
#include <htmlrenderer.h>
56
#include <cstring>
57
#include <cstdio>
58

59
namespace newsbeuter {
60

61
view::view(controller * c) : ctrl(c), cfg(0), keys(0), current_formaction(0), is_inside_qna(false), is_inside_cmdline(false), tab_count(0) {
729✔
62
        if (getenv("ESCDELAY") == nullptr) {
297✔
63
                set_escdelay(25);
243✔
64
        }
162 all except COMPILER=g++-4.9 GCOV=/usr/bin/gcov-4.9, COMPILER=g++-5 GCOV=/usr/bin/gcov-5, and COMPILER=g++-6 GCOV=/usr/bin/gcov-6 ✔
65
}
297✔
66

67
view::~view() {
216 all except COMPILER=clang++-3.6 GCOV=/usr/bin/gcov, COMPILER=clang++-3.7 GCOV=/usr/bin/gcov, COMPILER=clang++-3.8 GCOV=/usr/bin/gcov, and COMPILER=clang++-4.0 GCOV=/usr/bin/gcov ✔
68
        stfl::reset();
243✔
69
}
297✔
70

71
void view::set_config_container(configcontainer * cfgcontainer) {
81 only COMPILER=g++-4.9 GCOV=/usr/bin/gcov-4.9, COMPILER=g++-5 GCOV=/usr/bin/gcov-5, and COMPILER=g++-6 GCOV=/usr/bin/gcov-6 ✔
72
        cfg = cfgcontainer;
243✔
73
}
243✔
74

75
void view::set_keymap(keymap * k) {
15 only COMPILER=g++-4.9 GCOV=/usr/bin/gcov-4.9, COMPILER=g++-5 GCOV=/usr/bin/gcov-5, and COMPILER=g++-6 GCOV=/usr/bin/gcov-6 ✔
76
        keys = k;
45✔
77
}
45✔
78

79

80
void view::update_bindings() {
×
81
        for (auto& form : formaction_stack) {
×
82
                if (form) {
×
83
                        set_bindings(form);
×
84
                }
×
85
        }
86
}
×
87

88
void view::set_bindings(std::shared_ptr<formaction> fa) {
15 only COMPILER=g++-4.9 GCOV=/usr/bin/gcov-4.9, COMPILER=g++-5 GCOV=/usr/bin/gcov-5, and COMPILER=g++-6 GCOV=/usr/bin/gcov-6 ✔
89
        std::string upkey("** ");
75✔
90
        upkey.append(keys->getkey(OP_SK_UP, fa->id()));
135✔
91
        std::string downkey("** ");
80✔
92
        downkey.append(keys->getkey(OP_SK_DOWN, fa->id()));
135✔
93
        fa->get_form()->set("bind_up", upkey);
135✔
94
        fa->get_form()->set("bind_down", downkey);
135✔
95

96
        std::string pgupkey;
60✔
97
        std::string pgdownkey;
60✔
98
        if (fa->id() == "article" || fa->id() == "help") {
265✔
99
                pgupkey.append("** b ");
9✔
100
                pgdownkey.append("** SPACE ");
9✔
101
        } else {
6 all except COMPILER=g++-4.9 GCOV=/usr/bin/gcov-4.9, COMPILER=g++-5 GCOV=/usr/bin/gcov-5, and COMPILER=g++-6 GCOV=/usr/bin/gcov-6 ✔
102
                pgupkey.append("** ");
36✔
103
                pgdownkey.append("** ");
36✔
104
        }
105

106
        pgupkey.append(keys->getkey(OP_SK_PGUP, fa->id()));
135✔
107
        pgdownkey.append(keys->getkey(OP_SK_PGDOWN, fa->id()));
135✔
108

109
        fa->get_form()->set("bind_page_up", pgupkey);
135✔
110
        fa->get_form()->set("bind_page_down", pgdownkey);
135✔
111

112
        std::string homekey("** ");
80✔
113
        homekey.append(keys->getkey(OP_SK_HOME, fa->id()));
135✔
114
        std::string endkey("** ");
80✔
115
        endkey.append(keys->getkey(OP_SK_END, fa->id()));
135✔
116
        fa->get_form()->set("bind_home", homekey);
135✔
117
        fa->get_form()->set("bind_end", endkey);
140✔
118
}
45✔
119

120
std::shared_ptr<formaction> view::get_current_formaction() {
99 only COMPILER=g++-4.9 GCOV=/usr/bin/gcov-4.9, COMPILER=g++-5 GCOV=/usr/bin/gcov-5, and COMPILER=g++-6 GCOV=/usr/bin/gcov-6 ✔
121
        if (formaction_stack.size() > 0 && current_formaction < formaction_stack_size()) {
471✔
122
                return formaction_stack[current_formaction];
261✔
123
        }
124
        return std::shared_ptr<formaction>();
36✔
125
}
198 all except COMPILER=g++-4.9 GCOV=/usr/bin/gcov-4.9, COMPILER=g++-5 GCOV=/usr/bin/gcov-5, and COMPILER=g++-6 GCOV=/usr/bin/gcov-6 ✔
126

127
void view::set_status_unlocked(const std::string& msg) {
39 only COMPILER=g++-4.9 GCOV=/usr/bin/gcov-4.9, COMPILER=g++-5 GCOV=/usr/bin/gcov-5, and COMPILER=g++-6 GCOV=/usr/bin/gcov-6 ✔
128
        if (formaction_stack.size() > 0 && get_current_formaction() != nullptr) {
273✔
129
                std::shared_ptr<stfl::form> form = get_current_formaction()->get_form();
×
130
                if (form != nullptr) {
×
131
                        form->set("msg",msg);
×
132
                        form->run(-1);
×
133
                } else {
×
134
                        LOG(level::ERROR, "view::set_status_unlocked: form for formaction of type %s is nullptr!", get_current_formaction()->id());
×
135
                }
×
136
        }
×
137
}
117✔
138

139
void view::set_status(const std::string& msg) {
39 only COMPILER=g++-4.9 GCOV=/usr/bin/gcov-4.9, COMPILER=g++-5 GCOV=/usr/bin/gcov-5, and COMPILER=g++-6 GCOV=/usr/bin/gcov-6 ✔
140
        std::lock_guard<std::mutex> lock(mtx);
143✔
141
        set_status_unlocked(msg);
117✔
142
}
117✔
143

144
void view::show_error(const std::string& msg) {
12 only COMPILER=g++-4.9 GCOV=/usr/bin/gcov-4.9, COMPILER=g++-5 GCOV=/usr/bin/gcov-5, and COMPILER=g++-6 GCOV=/usr/bin/gcov-6 ✔
145
        set_status(msg);
36✔
146
}
36✔
147

148
void view::run() {
×
149
        bool have_macroprefix = false;
×
150
        std::vector<macrocmd> macrocmds;
×
151

152
        // create feedlist
153
        auto feedlist = std::make_shared<feedlist_formaction>(this, feedlist_str);
×
154
        set_bindings(feedlist);
×
155
        feedlist->set_regexmanager(rxman);
×
156
        feedlist->set_tags(tags);
×
157
        apply_colors(feedlist);
×
158
        formaction_stack.push_back(feedlist);
×
159
        current_formaction = formaction_stack_size() - 1;
×
160

161
        get_current_formaction()->init();
×
162

163
        stfl::reset();
×
164

165
        curs_set(0);
×
166

167
        /*
168
         * This is the main "event" loop of newsbeuter.
169
         */
170

171
        while (formaction_stack_size() > 0) {
×
172
                // first, we take the current formaction.
173
                std::shared_ptr<formaction> fa = get_current_formaction();
×
174

175
                // we signal "oh, you will receive an operation soon"
176
                fa->prepare();
×
177

178
                if (!macrocmds.empty()) {
×
179
                        // if there is any macro command left to process, we do so
180

181
                        fa->get_form()->run(-1);
×
182
                        fa->process_op(macrocmds[0].op, true, &macrocmds[0].args);
×
183

184
                        macrocmds.erase(macrocmds.begin()); // remove first macro command, since it has already been processed
×
185

186
                } else {
×
187

188
                        // we then receive the event and ignore timeouts.
189
                        const char * event = fa->get_form()->run(60000);
×
190

191
                        if (ctrl_c_hit) {
×
192
                                ctrl_c_hit = 0;
×
193
                                cancel_input(fa);
×
194
                                if (!get_cfg()->get_configvalue_as_bool("confirm-exit") || confirm(_("Do you really want to quit (y:Yes n:No)? "), _("yn")) == *_("y")) {
×
195
                                        stfl::reset();
×
196
                                        utils::remove_fs_lock(lock_file);
×
197
                                        ::exit(EXIT_FAILURE);
×
198
                                }
199
                        }
×
200

201
                        if (!event || strcmp(event,"TIMEOUT")==0) {
×
202
                                if (fa->id() == "article")
×
203
                                        std::dynamic_pointer_cast<itemview_formaction, formaction>(fa)->update_percent();
×
204
                                continue;
×
205
                        }
206

207
                        if (is_inside_qna) {
×
208
                                LOG(level::DEBUG, "view::run: we're inside QNA input");
×
209
                                if (is_inside_cmdline && strcmp(event, "TAB")==0) {
×
210
                                        handle_cmdline_completion(fa);
×
211
                                        continue;
×
212
                                }
213
                                if (strcmp(event, "^U")==0) {
×
214
                                        clear_line(fa);
×
215
                                        continue;
×
216
                                } else if (strcmp(event, "^K")==0) {
×
217
                                        clear_eol(fa);
×
218
                                        continue;
×
219
                                } else if (strcmp(event, "^G")==0) {
×
220
                                        cancel_input(fa);
×
221
                                        continue;
×
222
                                } else if (strcmp(event, "^W")==0) {
×
223
                                        delete_word(fa);
×
224
                                        continue;
×
225
                                }
226
                        }
×
227

228
                        LOG(level::DEBUG, "view::run: event = %s", event);
×
229

230
                        // retrieve operation code through the keymap
231
                        operation op;
232

233
                        if (have_macroprefix) {
×
234
                                have_macroprefix = false;
×
235
                                LOG(level::DEBUG, "view::run: running macro `%s'", event);
×
236
                                macrocmds = keys->get_macro(event);
×
237
                                set_status("");
×
238
                        } else {
×
239
                                op = keys->get_operation(event, fa->id());
×
240

241
                                LOG(level::DEBUG, "view::run: event = %s op = %u", event, op);
×
242

243
                                if (OP_MACROPREFIX == op) {
×
244
                                        have_macroprefix = true;
×
245
                                        set_status("macro-");
×
246
                                }
×
247

248
                                // now we handle the operation to the formaction.
249
                                fa->process_op(op);
×
250
                        }
251
                }
252
        }
×
253

254
        stfl::reset();
×
255
}
×
256

257
std::string view::run_modal(std::shared_ptr<formaction> f, const std::string& value) {
×
258
        f->init();
×
259
        unsigned int stacksize = formaction_stack.size();
×
260

261
        formaction_stack.push_back(f);
×
262
        current_formaction = formaction_stack_size() - 1;
×
263

264
        while (formaction_stack.size() > stacksize) {
×
265
                std::shared_ptr<formaction> fa = get_current_formaction();
×
266

267
                fa->prepare();
×
268

269
                const char * event = fa->get_form()->run(1000);
×
270
                LOG(level::DEBUG, "view::run: event = %s", event);
×
271
                if (!event || strcmp(event,"TIMEOUT")==0) continue;
×
272

273
                operation op = keys->get_operation(event, fa->id());
×
274

275
                if (OP_REDRAW == op) {
×
276
                        stfl::reset();
×
277
                        continue;
×
278
                }
279

280
                fa->process_op(op);
×
281
        }
×
282

283
        if (value == "")
×
284
                return "";
×
285
        else
286
                return f->get_value(value);
×
287
}
×
288

289
std::string view::get_filename_suggestion(const std::string& s) {
×
290
        /*
291
         * With this function, we generate normalized filenames for saving
292
         * articles to files.
293
         */
294
        std::string retval;
×
295
        for (unsigned int i=0; i<s.length(); ++i) {
×
296
                if (isalnum(s[i]))
×
297
                        retval.append(1,s[i]);
×
298
                else if (s[i] == '/' || s[i] == ' ' || s[i] == '\r' || s[i] == '\n')
×
299
                        retval.append(1,'_');
×
300
        }
×
301
        if (retval.length() == 0)
×
302
                retval = "article.txt";
×
303
        else
304
                retval.append(".txt");
×
305
        LOG(level::DEBUG,"view::get_filename_suggestion: %s -> %s", s, retval);
×
306
        return retval;
×
307
}
×
308

309
void view::push_empty_formaction() {
12 only COMPILER=g++-4.9 GCOV=/usr/bin/gcov-4.9, COMPILER=g++-5 GCOV=/usr/bin/gcov-5, and COMPILER=g++-6 GCOV=/usr/bin/gcov-6 ✔
310
        formaction_stack.push_back(std::shared_ptr<formaction>());
60✔
311
        current_formaction = formaction_stack_size() - 1;
36✔
312
}
36✔
313

314
bool view::open_in_pager(const std::string& filename) {
3 only COMPILER=g++-4.9 GCOV=/usr/bin/gcov-4.9, COMPILER=g++-5 GCOV=/usr/bin/gcov-5, and COMPILER=g++-6 GCOV=/usr/bin/gcov-6 ✔
315
        formaction_stack.push_back(std::shared_ptr<formaction>());
15✔
316
        current_formaction = formaction_stack_size() - 1;
9✔
317
        std::string cmdline;
11✔
318
        std::string pager = cfg->get_configvalue("pager");
24✔
319
        if (pager.find("%f") != std::string::npos) {
13✔
320
                fmtstr_formatter fmt;
11✔
321
                fmt.register_fmt('f', filename);
9✔
322
                cmdline = fmt.do_format(pager, 0);
19✔
323
        } else {
6 all except COMPILER=g++-4.9 GCOV=/usr/bin/gcov-4.9, COMPILER=g++-5 GCOV=/usr/bin/gcov-5, and COMPILER=g++-6 GCOV=/usr/bin/gcov-6 ✔
324
                const char * env_pager = nullptr;
×
325
                if (pager != "")
×
326
                        cmdline.append(pager);
×
327
                else if ((env_pager = getenv("PAGER")) != nullptr)
×
328
                        cmdline.append(env_pager);
×
329
                else
330
                        cmdline.append("more");
×
331
                cmdline.append(" ");
×
332
                cmdline.append(filename);
×
333
        }
334
        stfl::reset();
9✔
335
        int pager_exit_code = utils::run_interactively(cmdline, "view::open_in_pager");
21✔
336
        pop_current_formaction();
9✔
337
        return pager_exit_code == 0;
12✔
338
}
6 all except COMPILER=g++-4.9 GCOV=/usr/bin/gcov-4.9, COMPILER=g++-5 GCOV=/usr/bin/gcov-5, and COMPILER=g++-6 GCOV=/usr/bin/gcov-6 ✔
339

340
bool view::open_in_browser(const std::string& url) {
66 only COMPILER=g++-4.9 GCOV=/usr/bin/gcov-4.9, COMPILER=g++-5 GCOV=/usr/bin/gcov-5, and COMPILER=g++-6 GCOV=/usr/bin/gcov-6 ✔
341
        formaction_stack.push_back(std::shared_ptr<formaction>());
330✔
342
        current_formaction = formaction_stack_size() - 1;
198✔
343
        std::string cmdline;
242✔
344
        std::string browser = cfg->get_configvalue("browser");
528✔
345
        if (browser.find("%u") != std::string::npos) {
286✔
346
                fmtstr_formatter fmt;
242✔
347
                std::string newurl;
264✔
348
                newurl = utils::replace_all(url, "'", "%27");
814✔
349
                newurl.insert(0, "'");
198✔
350
                newurl.append("'");
198✔
351
                fmt.register_fmt('u', newurl);
198✔
352
                cmdline = fmt.do_format(browser, 0);
440✔
353
        } else {
132 all except COMPILER=g++-4.9 GCOV=/usr/bin/gcov-4.9, COMPILER=g++-5 GCOV=/usr/bin/gcov-5, and COMPILER=g++-6 GCOV=/usr/bin/gcov-6 ✔
354
                if (browser != "")
×
355
                        cmdline.append(browser);
×
356
                else
357
                        cmdline.append("lynx");
×
358
                cmdline.append(" '");
×
359
                cmdline.append(utils::replace_all(url,"'", "%27"));
×
360
                cmdline.append("'");
×
361
        }
362
        stfl::reset();
198✔
363
        int browser_exit_code = utils::run_interactively(cmdline, "view::open_in_browser");
462✔
364
        pop_current_formaction();
198✔
365

366
        return browser_exit_code == 0;
264✔
367
}
132 all except COMPILER=g++-4.9 GCOV=/usr/bin/gcov-4.9, COMPILER=g++-5 GCOV=/usr/bin/gcov-5, and COMPILER=g++-6 GCOV=/usr/bin/gcov-6 ✔
368

369
void view::update_visible_feeds(std::vector<std::shared_ptr<rss_feed>> feeds) {
×
370
        try {
371
                if (formaction_stack_size() > 0) {
×
372
                        std::lock_guard<std::mutex> lock(mtx);
×
373
                        std::shared_ptr<feedlist_formaction> feedlist = std::dynamic_pointer_cast<feedlist_formaction, formaction>(formaction_stack[0]);
×
374
                        feedlist->update_visible_feeds(feeds);
×
375
                }
×
376
        } catch (const matcherexception& e) {
×
377
                set_status(strprintf::fmt(_("Error: applying the filter failed: %s"), e.what()));
×
378
                LOG(level::DEBUG, "view::update_visible_feeds: inside catch: %s", e.what());
×
379
        }
×
380
}
×
381

382
void view::set_feedlist(std::vector<std::shared_ptr<rss_feed>> feeds) {
×
383
        try {
384
                std::lock_guard<std::mutex> lock(mtx);
×
385

386
                for (auto feed : feeds) {
×
387
                        if (feed->rssurl().substr(0,6) != "query:") {
×
388
                                feed->set_feedptrs(feed);
×
389
                        }
×
390
                }
×
391

392
                if (formaction_stack_size() > 0) {
×
393
                        std::shared_ptr<feedlist_formaction> feedlist = std::dynamic_pointer_cast<feedlist_formaction, formaction>(formaction_stack[0]);
×
394
                        feedlist->set_feedlist(feeds);
×
395
                }
×
396
        } catch (const matcherexception& e) {
×
397
                set_status(strprintf::fmt(_("Error: applying the filter failed: %s"), e.what()));
×
398
        }
×
399
}
×
400

401

402
void view::set_tags(const std::vector<std::string>& t) {
×
403
        tags = t;
×
404
}
×
405

406
void view::push_searchresult(std::shared_ptr<rss_feed> feed, const std::string& phrase) {
×
407
        assert(feed != nullptr);
×
408
        LOG(level::DEBUG, "view::push_searchresult: pushing search result");
×
409

410
        if (feed->total_item_count() > 0) {
×
411
                std::shared_ptr<itemlist_formaction> searchresult(new itemlist_formaction(this, itemlist_str));
×
412
                set_bindings(searchresult);
×
413
                searchresult->set_regexmanager(rxman);
×
414
                searchresult->set_feed(feed);
×
415
                searchresult->set_show_searchresult(true);
×
416
                searchresult->set_searchphrase(phrase);
×
417
                apply_colors(searchresult);
×
418
                searchresult->set_parent_formaction(get_current_formaction());
×
419
                searchresult->init();
×
420
                formaction_stack.push_back(searchresult);
×
421
                current_formaction = formaction_stack_size() - 1;
×
422
        } else {
×
423
                show_error(_("Error: feed contains no items!"));
×
424
        }
425

426
}
×
427

428
void view::push_itemlist(std::shared_ptr<rss_feed> feed) {
15 only COMPILER=g++-4.9 GCOV=/usr/bin/gcov-4.9, COMPILER=g++-5 GCOV=/usr/bin/gcov-5, and COMPILER=g++-6 GCOV=/usr/bin/gcov-6 ✔
429
        assert(feed != nullptr);
75✔
430

431
        feed->purge_deleted_items();
45✔
432

433
        prepare_query_feed(feed);
75✔
434

435
        if (feed->total_item_count() > 0) {
45✔
436
                std::shared_ptr<itemlist_formaction> itemlist(new itemlist_formaction(this, itemlist_str));
116✔
437
                set_bindings(itemlist);
60✔
438
                itemlist->set_regexmanager(rxman);
36✔
439
                itemlist->set_feed(feed);
60✔
440
                itemlist->set_show_searchresult(false);
36✔
441
                apply_colors(itemlist);
60✔
442
                itemlist->set_parent_formaction(get_current_formaction());
84✔
443
                itemlist->init();
36✔
444
                formaction_stack.push_back(itemlist);
60✔
445
                current_formaction = formaction_stack_size() - 1;
60✔
446
        } else {
24 all except COMPILER=g++-4.9 GCOV=/usr/bin/gcov-4.9, COMPILER=g++-5 GCOV=/usr/bin/gcov-5, and COMPILER=g++-6 GCOV=/usr/bin/gcov-6 ✔
447
                show_error(_("Error: feed contains no items!"));
19✔
448
        }
449
}
45✔
450

451
void view::push_itemlist(unsigned int pos) {
×
452
        std::shared_ptr<rss_feed> feed = ctrl->get_feed(pos);
×
453
        LOG(level::DEBUG, "view::push_itemlist: retrieved feed at position %d", pos);
×
454
        push_itemlist(feed);
×
455
        if (feed->total_item_count() > 0) {
×
456
                std::shared_ptr<itemlist_formaction> itemlist = std::dynamic_pointer_cast<itemlist_formaction, formaction>(get_current_formaction());
×
457
                itemlist->set_pos(pos);
×
458
        }
×
459
}
×
460

461
void view::push_itemview(std::shared_ptr<rss_feed> f, const std::string& guid, const std::string& searchphrase) {
3 only COMPILER=g++-4.9 GCOV=/usr/bin/gcov-4.9, COMPILER=g++-5 GCOV=/usr/bin/gcov-5, and COMPILER=g++-6 GCOV=/usr/bin/gcov-6 ✔
462
        if (cfg->get_configvalue("pager") == "internal") {
23✔
463
                std::shared_ptr<itemlist_formaction> itemlist = std::dynamic_pointer_cast<itemlist_formaction, formaction>(get_current_formaction());
×
464
                assert(itemlist != nullptr);
×
465
                std::shared_ptr<itemview_formaction> itemview(new itemview_formaction(this, itemlist, itemview_str));
×
466
                set_bindings(itemview);
×
467
                itemview->set_regexmanager(rxman);
×
468
                itemview->set_feed(f);
×
469
                itemview->set_guid(guid);
×
470
                itemview->set_parent_formaction(get_current_formaction());
×
471
                if (searchphrase.length() > 0)
×
472
                        itemview->set_highlightphrase(searchphrase);
×
473
                apply_colors(itemview);
×
474
                itemview->init();
×
475
                formaction_stack.push_back(itemview);
×
476
                current_formaction = formaction_stack_size() - 1;
×
477
        } else {
×
478
                std::shared_ptr<rss_item> item = f->get_item_by_guid(guid);
11✔
479
                std::string filename = get_ctrl()->write_temporary_item(item);
23✔
480
                if (!open_in_pager(filename)) {
15✔
481
                        show_error(_("Pager failed to show the item!"));
×
482
                        return;
1 only COMPILER=g++-4.9 GCOV=/usr/bin/gcov-4.9 ✔
483
                }
484
                try {
485
                        bool old_unread = item->unread();
15✔
486
                        item->set_unread(false);
9✔
487
                        if (old_unread) {
9✔
488
                                get_ctrl()->mark_article_read(item->guid(), true);
21✔
489
                        }
6 all except COMPILER=g++-4.9 GCOV=/usr/bin/gcov-4.9, COMPILER=g++-5 GCOV=/usr/bin/gcov-5, and COMPILER=g++-6 GCOV=/usr/bin/gcov-6 ✔
490
                } catch (const dbexception& e) {
6 all except COMPILER=g++-4.9 GCOV=/usr/bin/gcov-4.9, COMPILER=g++-5 GCOV=/usr/bin/gcov-5, and COMPILER=g++-6 GCOV=/usr/bin/gcov-6 ✔
491
                        show_error(strprintf::fmt(_("Error while marking article as read: %s"), e.what()));
×
492
                }
×
493
                ::unlink(filename.c_str());
10✔
494
        }
18 all except COMPILER=g++-4.9 GCOV=/usr/bin/gcov-4.9, COMPILER=g++-5 GCOV=/usr/bin/gcov-5, and COMPILER=g++-6 GCOV=/usr/bin/gcov-6 ✔
495
}
7 all except COMPILER=g++-4.9 GCOV=/usr/bin/gcov-4.9, COMPILER=g++-5 GCOV=/usr/bin/gcov-5, and COMPILER=g++-6 GCOV=/usr/bin/gcov-6 ✔
496

497
void view::view_dialogs() {
×
498
        if (get_current_formaction() != nullptr && get_current_formaction()->id() != "dialogs") {
×
499
                std::shared_ptr<dialogs_formaction> dialogs(new dialogs_formaction(this, dialogs_str));
×
500
                dialogs->set_parent_formaction(get_current_formaction());
×
501
                apply_colors(dialogs);
×
502
                dialogs->init();
×
503
                formaction_stack.push_back(dialogs);
×
504
                current_formaction = formaction_stack_size() - 1;
×
505
        }
×
506
}
×
507

508
void view::push_help() {
3 only COMPILER=g++-4.9 GCOV=/usr/bin/gcov-4.9, COMPILER=g++-5 GCOV=/usr/bin/gcov-5, and COMPILER=g++-6 GCOV=/usr/bin/gcov-6 ✔
509
        std::shared_ptr<help_formaction> helpview(new help_formaction(this, help_str));
29✔
510
        set_bindings(helpview);
15✔
511
        apply_colors(helpview);
15✔
512
        helpview->set_context(get_current_formaction()->id());
27✔
513
        helpview->set_parent_formaction(get_current_formaction());
21✔
514
        helpview->init();
9✔
515
        formaction_stack.push_back(helpview);
15✔
516
        current_formaction = formaction_stack_size() - 1;
15✔
517
}
9✔
518

519
void view::push_urlview(const std::vector<linkpair>& links, std::shared_ptr<rss_feed>& feed) {
×
520
        std::shared_ptr<urlview_formaction> urlview(new urlview_formaction(this, feed, urlview_str));
×
521
        set_bindings(urlview);
×
522
        apply_colors(urlview);
×
523
        urlview->set_parent_formaction(get_current_formaction());
×
524
        urlview->init();
×
525
        urlview->set_links(links);
×
526
        formaction_stack.push_back(urlview);
×
527
        current_formaction = formaction_stack_size() - 1;
×
528
}
×
529

530
std::string view::run_filebrowser(const std::string& default_filename, const std::string& dir) {
×
531
        std::shared_ptr<filebrowser_formaction> filebrowser(new filebrowser_formaction(this, filebrowser_str));
×
532
        set_bindings(filebrowser);
×
533
        apply_colors(filebrowser);
×
534
        filebrowser->set_dir(dir);
×
535
        filebrowser->set_default_filename(default_filename);
×
536
        filebrowser->set_parent_formaction(get_current_formaction());
×
537
        return run_modal(filebrowser, "filenametext");
×
538
}
×
539

540

541
std::string view::select_tag() {
×
542
        if (tags.size() == 0) {
×
543
                show_error(_("No tags defined."));
×
544
                return "";
×
545
        }
546
        std::shared_ptr<select_formaction> selecttag(new select_formaction(this, selecttag_str));
×
547
        selecttag->set_type(select_formaction::selection_type::TAG);
×
548
        set_bindings(selecttag);
×
549
        apply_colors(selecttag);
×
550
        selecttag->set_parent_formaction(get_current_formaction());
×
551
        selecttag->set_tags(tags);
×
552
        run_modal(selecttag, "");
×
553
        return selecttag->get_selected_value();
×
554
}
×
555

556
std::string view::select_filter(const std::vector<filter_name_expr_pair>& filters) {
×
557
        std::shared_ptr<select_formaction> selecttag(new select_formaction(this, selecttag_str));
×
558
        selecttag->set_type(select_formaction::selection_type::FILTER);
×
559
        set_bindings(selecttag);
×
560
        apply_colors(selecttag);
×
561
        selecttag->set_parent_formaction(get_current_formaction());
×
562
        selecttag->set_filters(filters);
×
563
        run_modal(selecttag, "");
×
564
        return selecttag->get_selected_value();
×
565
}
×
566

567
char view::confirm(const std::string& prompt, const std::string& charset) {
×
568
        LOG(level::DEBUG, "view::confirm: charset = %s", charset);
×
569

570
        std::shared_ptr<formaction> f = get_current_formaction();
×
571
        formaction_stack.push_back(std::shared_ptr<formaction>());
×
572
        current_formaction = formaction_stack_size() - 1;
×
573
        f->get_form()->set("msg", prompt);
×
574

575
        char result = 0;
×
576

577
        do {
×
578
                const char * event = f->get_form()->run(0);
×
579
                LOG(level::DEBUG,"view::confirm: event = %s", event);
×
580
                if (!event) continue;
×
581
                if (strcmp(event, "ESC")==0 || strcmp(event, "ENTER")==0) {
×
582
                        result = 0;
×
583
                        LOG(level::DEBUG, "view::confirm: user pressed ESC or ENTER, we cancel confirmation dialog");
×
584
                        break;
×
585
                }
586
                result = keys->get_key(event);
×
587
                LOG(level::DEBUG, "view::confirm: key = %c (%u)", result, result);
×
588
        } while (!result || strchr(charset.c_str(), result)==nullptr);
×
589

590
        f->get_form()->set("msg", "");
×
591
        f->get_form()->run(-1);
×
592

593
        pop_current_formaction();
×
594

595
        return result;
×
596
}
×
597

598
void view::notify_itemlist_change(std::shared_ptr<rss_feed> feed) {
×
599
        for (auto& form : formaction_stack) {
×
600
                if (form != nullptr && form->id() == "articlelist") {
×
601
                        std::shared_ptr<itemlist_formaction> itemlist = std::dynamic_pointer_cast<itemlist_formaction, formaction>(form);
×
602
                        if (itemlist != nullptr) {
×
603
                                std::shared_ptr<rss_feed> f = itemlist->get_feed();
×
604
                                if (f != nullptr && f->rssurl() == feed->rssurl()) {
×
605
                                        itemlist->set_feed(feed);
×
606
                                        itemlist->set_redraw(true);
×
607
                                }
×
608
                        }
×
609
                }
×
610
        }
611
}
×
612

613
bool view::get_random_unread(itemlist_formaction * itemlist, itemview_formaction * itemview) {
×
614
        unsigned int feedpos;
615
        std::shared_ptr<feedlist_formaction> feedlist = std::dynamic_pointer_cast<feedlist_formaction, formaction>(formaction_stack[0]);
×
616
        if (!cfg->get_configvalue_as_bool("goto-next-feed")) {
×
617
                return false;
×
618
        }
619
        if (feedlist->jump_to_random_unread_feed(feedpos)) {
×
620
                LOG(level::DEBUG, "view::get_previous_unread: found feed with unread articles");
×
621
                prepare_query_feed(feedlist->get_feed());
×
622
                itemlist->set_feed(feedlist->get_feed());
×
623
                itemlist->set_pos(feedpos);
×
624
                itemlist->init();
×
625
                if (itemlist->jump_to_random_unread_item()) {
×
626
                        if (itemview) {
×
627
                                itemview->init();
×
628
                                itemview->set_feed(itemlist->get_feed());
×
629
                                itemview->set_guid(itemlist->get_guid());
×
630
                        }
×
631
                        return true;
×
632
                }
633
        }
×
634
        return false;
×
635
}
×
636

637
bool view::get_previous_unread(itemlist_formaction * itemlist, itemview_formaction * itemview) {
×
638
        unsigned int feedpos;
639
        LOG(level::DEBUG, "view::get_previous_unread: trying to find previous unread");
×
640
        std::shared_ptr<feedlist_formaction> feedlist = std::dynamic_pointer_cast<feedlist_formaction, formaction>(formaction_stack[0]);
×
641
        if (itemlist->jump_to_previous_unread_item(false)) {
×
642
                LOG(level::DEBUG, "view::get_previous_unread: found unread article in same feed");
×
643
                if (itemview) {
×
644
                        itemview->init();
×
645
                        itemview->set_feed(itemlist->get_feed());
×
646
                        itemview->set_guid(itemlist->get_guid());
×
647
                }
×
648
                return true;
×
649
        } else if (cfg->get_configvalue_as_bool("goto-next-feed")==false) {
×
650
                LOG(level::DEBUG, "view::get_previous_unread: goto-next-feed = false");
×
651
                show_error(_("No unread items."));
×
652
        } else if (feedlist->jump_to_previous_unread_feed(feedpos)) {
×
653
                LOG(level::DEBUG, "view::get_previous_unread: found feed with unread articles");
×
654
                prepare_query_feed(feedlist->get_feed());
×
655
                itemlist->set_feed(feedlist->get_feed());
×
656
                itemlist->set_pos(feedpos);
×
657
                itemlist->init();
×
658
                if (itemlist->jump_to_previous_unread_item(true)) {
×
659
                        if (itemview) {
×
660
                                itemview->init();
×
661
                                itemview->set_feed(itemlist->get_feed());
×
662
                                itemview->set_guid(itemlist->get_guid());
×
663
                        }
×
664
                        return true;
×
665
                }
666
        }
×
667
        return false;
×
668
}
×
669

670
bool view::get_next_unread_feed(itemlist_formaction * itemlist) {
×
671
        std::shared_ptr<feedlist_formaction> feedlist = std::dynamic_pointer_cast<feedlist_formaction, formaction>(formaction_stack[0]);
×
672
        unsigned int feedpos;
673
        assert(feedlist != nullptr);
×
674
        if (feedlist->jump_to_next_unread_feed(feedpos)) {
×
675
                prepare_query_feed(feedlist->get_feed());
×
676
                itemlist->set_feed(feedlist->get_feed());
×
677
                itemlist->set_pos(feedpos);
×
678
                itemlist->init();
×
679
                return true;
×
680
        }
681
        return false;
×
682
}
×
683

684
bool view::get_prev_unread_feed(itemlist_formaction * itemlist) {
×
685
        std::shared_ptr<feedlist_formaction> feedlist = std::dynamic_pointer_cast<feedlist_formaction, formaction>(formaction_stack[0]);
×
686
        unsigned int feedpos;
687
        assert(feedlist != nullptr);
×
688
        if (feedlist->jump_to_previous_unread_feed(feedpos)) {
×
689
                prepare_query_feed(feedlist->get_feed());
×
690
                itemlist->set_feed(feedlist->get_feed());
×
691
                itemlist->set_pos(feedpos);
×
692
                itemlist->init();
×
693
                return true;
×
694
        }
695
        return false;
×
696
}
×
697

698
bool view::get_next_unread(itemlist_formaction * itemlist, itemview_formaction * itemview) {
×
699
        unsigned int feedpos;
700
        std::shared_ptr<feedlist_formaction> feedlist = std::dynamic_pointer_cast<feedlist_formaction, formaction>(formaction_stack[0]);
×
701
        LOG(level::DEBUG, "view::get_next_unread: trying to find next unread");
×
702
        if (itemlist->jump_to_next_unread_item(false)) {
×
703
                LOG(level::DEBUG, "view::get_next_unread: found unread article in same feed");
×
704
                if (itemview) {
×
705
                        itemview->init();
×
706
                        itemview->set_feed(itemlist->get_feed());
×
707
                        itemview->set_guid(itemlist->get_guid());
×
708
                }
×
709
                return true;
×
710
        } else if (cfg->get_configvalue_as_bool("goto-next-feed")==false) {
×
711
                LOG(level::DEBUG, "view::get_next_unread: goto-next-feed = false");
×
712
                show_error(_("No unread items."));
×
713
        } else if (feedlist->jump_to_next_unread_feed(feedpos)) {
×
714
                LOG(level::DEBUG, "view::get_next_unread: found feed with unread articles");
×
715
                prepare_query_feed(feedlist->get_feed());
×
716
                itemlist->set_feed(feedlist->get_feed());
×
717
                itemlist->set_pos(feedpos);
×
718
                itemlist->init();
×
719
                if (itemlist->jump_to_next_unread_item(true)) {
×
720
                        if (itemview) {
×
721
                                itemview->init();
×
722
                                itemview->set_feed(itemlist->get_feed());
×
723
                                itemview->set_guid(itemlist->get_guid());
×
724
                        }
×
725
                        return true;
×
726
                }
727
        }
×
728
        return false;
×
729
}
×
730

731
bool view::get_previous(itemlist_formaction * itemlist, itemview_formaction * itemview) {
×
732
        unsigned int feedpos;
733
        std::shared_ptr<feedlist_formaction> feedlist = std::dynamic_pointer_cast<feedlist_formaction, formaction>(formaction_stack[0]);
×
734
        if (itemlist->jump_to_previous_item(false)) {
×
735
                LOG(level::DEBUG, "view::get_previous: article in same feed");
×
736
                if (itemview) {
×
737
                        itemview->init();
×
738
                        itemview->set_feed(itemlist->get_feed());
×
739
                        itemview->set_guid(itemlist->get_guid());
×
740
                }
×
741
                return true;
×
742
        } else if (cfg->get_configvalue_as_bool("goto-next-feed")==false) {
×
743
                LOG(level::DEBUG, "view::get_previous: goto-next-feed = false");
×
744
                show_error(_("Already on first item."));
×
745
        } else if (feedlist->jump_to_previous_feed(feedpos)) {
×
746
                LOG(level::DEBUG, "view::get_previous: previous feed");
×
747
                prepare_query_feed(feedlist->get_feed());
×
748
                itemlist->set_feed(feedlist->get_feed());
×
749
                itemlist->set_pos(feedpos);
×
750
                itemlist->init();
×
751
                if (itemlist->jump_to_previous_item(true)) {
×
752
                        if (itemview) {
×
753
                                itemview->init();
×
754
                                itemview->set_feed(itemlist->get_feed());
×
755
                                itemview->set_guid(itemlist->get_guid());
×
756
                        }
×
757
                        return true;
×
758
                }
759
        }
×
760
        return false;
×
761
}
×
762

763
bool view::get_next(itemlist_formaction * itemlist, itemview_formaction * itemview) {
×
764
        unsigned int feedpos;
765
        std::shared_ptr<feedlist_formaction> feedlist = std::dynamic_pointer_cast<feedlist_formaction, formaction>(formaction_stack[0]);
×
766
        if (itemlist->jump_to_next_item(false)) {
×
767
                LOG(level::DEBUG, "view::get_next: article in same feed");
×
768
                if (itemview) {
×
769
                        itemview->init();
×
770
                        itemview->set_feed(itemlist->get_feed());
×
771
                        itemview->set_guid(itemlist->get_guid());
×
772
                }
×
773
                return true;
×
774
        } else if (cfg->get_configvalue_as_bool("goto-next-feed")==false) {
×
775
                LOG(level::DEBUG, "view::get_next: goto-next-feed = false");
×
776
                show_error(_("Already on last item."));
×
777
        } else if (feedlist->jump_to_next_feed(feedpos)) {
×
778
                LOG(level::DEBUG, "view::get_next: next feed");
×
779
                prepare_query_feed(feedlist->get_feed());
×
780
                itemlist->set_feed(feedlist->get_feed());
×
781
                itemlist->set_pos(feedpos);
×
782
                itemlist->init();
×
783
                if (itemlist->jump_to_next_item(true)) {
×
784
                        if (itemview) {
×
785
                                itemview->init();
×
786
                                itemview->set_feed(itemlist->get_feed());
×
787
                                itemview->set_guid(itemlist->get_guid());
×
788
                        }
×
789
                        return true;
×
790
                }
791
        }
×
792
        return false;
×
793
}
×
794

795
bool view::get_next_feed(itemlist_formaction * itemlist) {
×
796
        std::shared_ptr<feedlist_formaction> feedlist = std::dynamic_pointer_cast<feedlist_formaction, formaction>(formaction_stack[0]);
×
797
        unsigned int feedpos;
798
        assert(feedlist != nullptr);
×
799
        if (feedlist->jump_to_next_feed(feedpos)) {
×
800
                prepare_query_feed(feedlist->get_feed());
×
801
                itemlist->set_feed(feedlist->get_feed());
×
802
                itemlist->set_pos(feedpos);
×
803
                itemlist->init();
×
804
                return true;
×
805
        }
806
        return false;
×
807
}
×
808

809
bool view::get_prev_feed(itemlist_formaction * itemlist) {
×
810
        std::shared_ptr<feedlist_formaction> feedlist = std::dynamic_pointer_cast<feedlist_formaction, formaction>(formaction_stack[0]);
×
811
        unsigned int feedpos;
812
        assert(feedlist != nullptr);
×
813
        if (feedlist->jump_to_previous_feed(feedpos)) {
×
814
                prepare_query_feed(feedlist->get_feed());
×
815
                itemlist->set_feed(feedlist->get_feed());
×
816
                itemlist->set_pos(feedpos);
×
817
                itemlist->init();
×
818
                return true;
×
819
        }
820
        return false;
×
821
}
×
822

823
void view::prepare_query_feed(std::shared_ptr<rss_feed> feed) {
15 only COMPILER=g++-4.9 GCOV=/usr/bin/gcov-4.9, COMPILER=g++-5 GCOV=/usr/bin/gcov-5, and COMPILER=g++-6 GCOV=/usr/bin/gcov-6 ✔
824
        if (feed->rssurl().substr(0,6) == "query:") {
65✔
825
                LOG(level::DEBUG, "view::prepare_query_feed: %s", feed->rssurl());
×
826

827
                set_status(_("Updating query feed..."));
×
828
                feed->update_items(ctrl->get_all_feeds());
×
829
                feed->sort(cfg->get_configvalue("article-sort-order"));
×
830
                notify_itemlist_change(feed);
×
831
                set_status("");
×
832
        }
×
833
}
45✔
834

835
void view::force_redraw() {
×
836
        std::shared_ptr<formaction> fa = get_current_formaction();
×
837
        if (fa != nullptr) {
×
838
                fa->set_redraw(true);
×
839
                fa->prepare();
×
840
                fa->get_form()->run(-1);
×
841
        }
×
842
}
×
843

844
void view::pop_current_formaction() {
81 only COMPILER=g++-4.9 GCOV=/usr/bin/gcov-4.9, COMPILER=g++-5 GCOV=/usr/bin/gcov-5, and COMPILER=g++-6 GCOV=/usr/bin/gcov-6 ✔
845
        std::shared_ptr<formaction> f = get_current_formaction();
297✔
846
        auto it=formaction_stack.begin();
243✔
847
        for (unsigned int i=0; i<current_formaction; i++)
435✔
848
                ++it;
18✔
849
        formaction_stack.erase(it);
405✔
850
        if (f == nullptr) {
243✔
851
                current_formaction = formaction_stack_size() - 1; // XXX TODO this is not correct... we'd need to return to the previous one, but nullptr formactions have no parent
405✔
852
        } else if (formaction_stack.size() > 0) {
162 all except COMPILER=g++-4.9 GCOV=/usr/bin/gcov-4.9, COMPILER=g++-5 GCOV=/usr/bin/gcov-5, and COMPILER=g++-6 GCOV=/usr/bin/gcov-6 ✔
853
                // first, we set back the parent formactions of those who reference the formaction we just removed
854
                for (auto& form : formaction_stack) {
×
855
                        if (form->get_parent_formaction() == f) {
×
856
                                form->set_parent_formaction(formaction_stack[0]);
×
857
                        }
×
858
                }
859
                // we set the new formaction based on the removed formaction's parent.
860
                unsigned int i=0;
×
861
                for (auto& form : formaction_stack) {
×
862
                        if (form == f->get_parent_formaction()) {
×
863
                                current_formaction = i;
×
864
                                break;
×
865
                        }
866
                        i++;
×
867
                }
868
                std::shared_ptr<formaction> f = get_current_formaction();
×
869
                if (f) {
×
870
                        f->set_redraw(true);
×
871
                        f->get_form()->set("msg","");
×
872
                        f->recalculate_form();
×
873
                }
×
874
        }
27 only COMPILER=g++-4.9 GCOV=/usr/bin/gcov-4.9 ✔
875
}
243✔
876

877
void view::set_current_formaction(unsigned int pos) {
×
878
        remove_formaction(current_formaction);
×
879
        current_formaction = pos;
×
880
}
×
881

882
void view::remove_formaction(unsigned int pos) {
×
883
        std::shared_ptr<formaction> f = formaction_stack[pos];
×
884
        auto it = formaction_stack.begin();
×
885
        for (unsigned int i=0; i<pos; i++)
×
886
                ++it;
×
887
        formaction_stack.erase(it);
×
888
        current_formaction--;
×
889
        if (f != nullptr && formaction_stack.size() > 0) {
×
890
                // we set back the parent formactions of those who reference the formaction we just removed
891
                for (auto& form : formaction_stack) {
×
892
                        if (form->get_parent_formaction() == f) {
×
893
                                form->set_parent_formaction(formaction_stack[0]);
×
894
                        }
×
895
                }
896
        }
×
897
}
×
898

899
void view::set_colors(std::map<std::string,std::string>& fgc, std::map<std::string,std::string>& bgc, std::map<std::string,std::vector<std::string>>& attribs) {
×
900
        fg_colors = fgc;
×
901
        bg_colors = bgc;
×
902
        attributes = attribs;
×
903
}
×
904

905
void view::apply_colors_to_all_formactions() {
×
906
        for (auto& form : formaction_stack) {
×
907
                apply_colors(form);
×
908
        }
909
        if (formaction_stack.size() > 0 && formaction_stack[current_formaction]) {
×
910
                formaction_stack[current_formaction]->set_redraw(true);
×
911
        }
×
912
}
×
913

914
void view::apply_colors(std::shared_ptr<formaction> fa) {
15 only COMPILER=g++-4.9 GCOV=/usr/bin/gcov-4.9, COMPILER=g++-5 GCOV=/usr/bin/gcov-5, and COMPILER=g++-6 GCOV=/usr/bin/gcov-6 ✔
915
        auto fgcit = fg_colors.begin();
45✔
916
        auto bgcit = bg_colors.begin();
45✔
917
        auto attit = attributes.begin();
45✔
918

919
        LOG(level::DEBUG, "view::apply_colors: fa = %s", fa->id());
155✔
920

921
        std::string article_colorstr;
55✔
922

923
        for (; fgcit != fg_colors.end(); ++fgcit, ++bgcit, ++attit) {
85✔
924
                std::string colorattr;
×
925
                if (fgcit->second != "default") {
×
926
                        colorattr.append("fg=");
×
927
                        colorattr.append(fgcit->second);
×
928
                }
×
929
                if (bgcit->second != "default") {
×
930
                        if (colorattr.length() > 0)
×
931
                                colorattr.append(",");
×
932
                        colorattr.append("bg=");
×
933
                        colorattr.append(bgcit->second);
×
934
                }
×
935
                for (auto attr : attit->second) {
×
936
                        if (colorattr.length() > 0)
×
937
                                colorattr.append(",");
×
938
                        colorattr.append("attr=");
×
939
                        colorattr.append(attr);
×
940
                }
×
941

942
                if (fgcit->first == "article") {
×
943
                        article_colorstr = colorattr;
×
944
                        if (fa->id() == "article") {
×
945
                                std::string bold = article_colorstr;
×
946
                                std::string ul = article_colorstr;
×
947
                                if (bold.length() > 0)
×
948
                                        bold.append(",");
×
949
                                if (ul.length() > 0)
×
950
                                        ul.append(",");
×
951
                                bold.append("attr=bold");
×
952
                                ul.append("attr=underline");
×
953
                                fa->get_form()->set("color_bold", bold.c_str());
×
954
                                fa->get_form()->set("color_underline", ul.c_str());
×
955
                        }
×
956
                }
×
957

958
                LOG(level::DEBUG,"view::apply_colors: %s %s %s\n", fa->id(), fgcit->first, colorattr);
×
959

960
                fa->get_form()->set(fgcit->first, colorattr);
×
961

962
                if (fgcit->first == "article") {
×
963
                        if (fa->id() == "article" || fa->id() == "help") {
×
964
                                std::string styleend_str;
×
965
                                if (bgcit->second != "default") {
×
966
                                        styleend_str.append("bg=");
×
967
                                        styleend_str.append(bgcit->second);
×
968
                                }
×
969
                                if (styleend_str.length() > 0)
×
970
                                        styleend_str.append(",");
×
971
                                styleend_str.append("attr=bold");
×
972

973
                                fa->get_form()->set("styleend", styleend_str.c_str());
×
974
                        }
×
975
                }
×
976
        }
5 only COMPILER=g++-4.9 GCOV=/usr/bin/gcov-4.9 ✔
977
}
45✔
978

979
void view::feedlist_mark_pos_if_visible(unsigned int pos) {
3 only COMPILER=g++-4.9 GCOV=/usr/bin/gcov-4.9, COMPILER=g++-5 GCOV=/usr/bin/gcov-5, and COMPILER=g++-6 GCOV=/usr/bin/gcov-6 ✔
980
        if (formaction_stack_size() > 0) {
9✔
981
                std::dynamic_pointer_cast<feedlist_formaction, formaction>(formaction_stack[0])->mark_pos_if_visible(pos);
×
982
        }
×
983
}
9✔
984

985
void view::set_regexmanager(regexmanager * r) {
15 only COMPILER=g++-4.9 GCOV=/usr/bin/gcov-4.9, COMPILER=g++-5 GCOV=/usr/bin/gcov-5, and COMPILER=g++-6 GCOV=/usr/bin/gcov-6 ✔
986
        rxman = r;
45✔
987
}
45✔
988

989

990
std::vector<std::pair<unsigned int, std::string>> view::get_formaction_names() {
×
991
        std::vector<std::pair<unsigned int, std::string>> formaction_names;
×
992
        unsigned int i=0;
×
993
        for (auto& form : formaction_stack) {
×
994
                if (form && form->id() != "dialogs") {
×
995
                        formaction_names.push_back(std::pair<unsigned int, std::string>(i, form->title()));
×
996
                }
×
997
                i++;
×
998
        }
999
        return formaction_names;
×
1000
}
×
1001

1002
void view::goto_next_dialog() {
×
1003
        current_formaction++;
×
1004
        if (current_formaction >= formaction_stack.size())
×
1005
                current_formaction = 0;
×
1006
}
×
1007

1008
void view::goto_prev_dialog() {
×
1009
        if (current_formaction > 0) {
×
1010
                current_formaction--;
×
1011
        } else {
×
1012
                current_formaction = formaction_stack.size() - 1;
×
1013
        }
1014
}
×
1015

1016
void view::inside_qna(bool f) {
36 only COMPILER=g++-4.9 GCOV=/usr/bin/gcov-4.9, COMPILER=g++-5 GCOV=/usr/bin/gcov-5, and COMPILER=g++-6 GCOV=/usr/bin/gcov-6 ✔
1017
        curs_set(f ? 1 : 0);
108✔
1018
        is_inside_qna = f;
108✔
1019
}
108✔
1020

1021
void view::inside_cmdline(bool f) {
36 only COMPILER=g++-4.9 GCOV=/usr/bin/gcov-4.9, COMPILER=g++-5 GCOV=/usr/bin/gcov-5, and COMPILER=g++-6 GCOV=/usr/bin/gcov-6 ✔
1022
        is_inside_cmdline = f;
108✔
1023
}
108✔
1024

1025
void view::clear_line(std::shared_ptr<formaction> fa) {
×
1026
        fa->get_form()->set("qna_value", "");
×
1027
        fa->get_form()->set("qna_value_pos", "0");
×
1028
        LOG(level::DEBUG, "view::clear_line: cleared line");
×
1029
}
×
1030

1031
void view::clear_eol(std::shared_ptr<formaction> fa) {
×
1032
        unsigned int pos = utils::to_u(fa->get_form()->get("qna_value_pos"), 0);
×
1033
        std::string val = fa->get_form()->get("qna_value");
×
1034
        val.erase(pos, val.length());
×
1035
        fa->get_form()->set("qna_value", val);
×
1036
        fa->get_form()->set("qna_value_pos", std::to_string(val.length()));
×
1037
        LOG(level::DEBUG, "view::clear_eol: cleared to end of line");
×
1038
}
×
1039

1040
void view::cancel_input(std::shared_ptr<formaction> fa) {
×
1041
        fa->process_op(OP_INT_CANCEL_QNA);
×
1042
        LOG(level::DEBUG, "view::cancel_input: cancelled input");
×
1043
}
×
1044

1045
void view::delete_word(std::shared_ptr<formaction> fa) {
×
1046
        std::string::size_type curpos = utils::to_u(fa->get_form()->get("qna_value_pos"), 0);
×
1047
        std::string val = fa->get_form()->get("qna_value");
×
1048
        std::string::size_type firstpos = curpos;
×
1049
        LOG(level::DEBUG, "view::delete_word: before val = %s", val);
×
1050
        if (firstpos >= val.length() || ::isspace(val[firstpos])) {
×
1051
                if (firstpos != 0 && firstpos >= val.length())
×
1052
                        firstpos = val.length() - 1;
×
1053
                while (firstpos > 0 && ::isspace(val[firstpos])) {
×
1054
                        --firstpos;
×
1055
                }
1056
        }
×
1057
        while (firstpos > 0 && !::isspace(val[firstpos])) {
×
1058
                --firstpos;
×
1059
        }
1060
        if (firstpos != 0)
×
1061
                firstpos++;
×
1062
        val.erase(firstpos, curpos - firstpos);
×
1063
        LOG(level::DEBUG, "view::delete_word: after val = %s", val);
×
1064
        fa->get_form()->set("qna_value", val);
×
1065
        fa->get_form()->set("qna_value_pos", std::to_string(firstpos));
×
1066
}
×
1067

1068
void view::handle_cmdline_completion(std::shared_ptr<formaction> fa) {
×
1069
        std::string fragment = fa->get_form()->get("qna_value");
×
1070
        if (fragment != last_fragment || fragment == "") {
×
1071
                last_fragment = fragment;
×
1072
                suggestions = fa->get_suggestions(fragment);
×
1073
                tab_count = 0;
×
1074
        }
×
1075
        tab_count++;
×
1076
        std::string suggestion;
×
1077
        switch (suggestions.size()) {
×
1078
        case 0:
1079
                LOG(level::DEBUG, "view::handle_cmdline_completion: found no suggestion for `%s'", fragment);
×
1080
                ::beep(); // direct call to ncurses - we beep to signal that there is no suggestion available, just like vim
×
1081
                return;
×
1082
        case 1:
1083
                suggestion = suggestions[0];
×
1084
                break;
×
1085
        default:
1086
                suggestion = suggestions[(tab_count-1) % suggestions.size()];
×
1087
                break;
×
1088
        }
1089
        fa->get_form()->set("qna_value", suggestion);
×
1090
        fa->get_form()->set("qna_value_pos", std::to_string(suggestion.length()));
×
1091
        last_fragment = suggestion;
×
1092
}
×
1093

1094
void view::dump_current_form() {
×
1095
        std::string formtext = formaction_stack[current_formaction]->get_form()->dump("", "", 0);
×
1096
        char fnbuf[128];
1097
        time_t t = time(nullptr);
×
1098
        struct tm * stm = localtime(&t);
×
1099
        strftime(fnbuf, sizeof(fnbuf), "dumpform-%Y%m%d-%H%M%S.stfl", stm);
×
1100
        std::fstream f(fnbuf, std::ios_base::out);
×
1101
        if (!f.is_open()) {
×
1102
                show_error(strprintf::fmt("Error: couldn't open file %s: %s", fnbuf, strerror(errno)));
×
1103
                return;
×
1104
        }
1105
        f << formtext;
×
1106
        f.close();
×
1107
        set_status(strprintf::fmt("Dumped current form to file %s", fnbuf));
×
1108
}
×
1109

1110
}
9 only COMPILER=g++-4.9 GCOV=/usr/bin/gcov-4.9, COMPILER=g++-5 GCOV=/usr/bin/gcov-5, and COMPILER=g++-6 GCOV=/usr/bin/gcov-6 ✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc