diff options
-rw-r--r-- | .SRCINFO | 8 | ||||
-rw-r--r-- | PKGBUILD | 10 | ||||
-rw-r--r-- | ps-dl-ui-find_all.patch | 43 | ||||
-rw-r--r-- | ui_pyroscope.cc | 111 | ||||
-rw-r--r-- | ui_pyroscope.h | 1 |
5 files changed, 142 insertions, 31 deletions
@@ -1,6 +1,6 @@ pkgbase = rtorrent-ps pkgdesc = Extended rTorrent distribution with UI enhancements, colorization, and some added features - pkgver = 1.1.r15.g56057fc + pkgver = 1.1.r29.g78a68a0 pkgrel = 1 url = https://github.com/pyroscope/rtorrent-ps arch = any @@ -14,6 +14,7 @@ pkgbase = rtorrent-ps source = https://github.com/rakshasa/rtorrent/archive/0.9.6.tar.gz source = backport_0.9.6_algorithm_median.patch source = command_pyroscope.cc + source = ps-dl-ui-find_all.patch source = ps-event-view_all.patch source = ps-fix-double-slash-319_all.patch source = ps-fix-log-xmlrpc-close_all.patch @@ -40,6 +41,7 @@ pkgbase = rtorrent-ps md5sums = b8b4009f95f8543244ae1d23b1810d7c md5sums = b49903d3fa25a66c72db69570dfe8b47 md5sums = e7f737e4b2c4db9659faf2609a17732e + md5sums = 27e2b4099fa2b943812d80d9306dab79 md5sums = fbe511a1dfe89fe0510a077e61ae6ec7 md5sums = 22fae392c6e281dc438b39a5019e7e1b md5sums = 1b4f82e6123c5baa0cd07056e368064e @@ -60,8 +62,8 @@ pkgbase = rtorrent-ps md5sums = 26faff00b306b6ef276a7d9e6d964994 md5sums = bd04a0699b80c8042e1cf63a7e0e4222 md5sums = d0a956f0eb4b53b66d83df2a8a4d16dc - md5sums = 88c3520c6ba51a31ea29903b5ee6c484 - md5sums = a572a0fd087c89d8f50f16544bb1ec69 + md5sums = d6eb433a0516d987ac1054e8b14e8129 + md5sums = a4528366d1839ee400e51abc793446f5 md5sums = 0a2bbaf74c7160ba33876dcc2f050f14 pkgname = rtorrent-ps @@ -3,7 +3,7 @@ _pkgname=rtorrent pkgname=rtorrent-ps _pkgver=0.9.6 -pkgver=1.1.r15.g56057fc +pkgver=1.1.r29.g78a68a0 pkgrel=1 pkgdesc='Extended rTorrent distribution with UI enhancements, colorization, and some added features' url='https://github.com/pyroscope/rtorrent-ps' @@ -15,6 +15,7 @@ conflicts=('rtorrent') source=("https://github.com/rakshasa/$_pkgname/archive/$_pkgver.tar.gz" 'backport_0.9.6_algorithm_median.patch' 'command_pyroscope.cc' + 'ps-dl-ui-find_all.patch' 'ps-event-view_all.patch' 'ps-fix-double-slash-319_all.patch' 'ps-fix-log-xmlrpc-close_all.patch' @@ -41,6 +42,7 @@ source=("https://github.com/rakshasa/$_pkgname/archive/$_pkgver.tar.gz" md5sums=('b8b4009f95f8543244ae1d23b1810d7c' 'b49903d3fa25a66c72db69570dfe8b47' 'e7f737e4b2c4db9659faf2609a17732e' + '27e2b4099fa2b943812d80d9306dab79' 'fbe511a1dfe89fe0510a077e61ae6ec7' '22fae392c6e281dc438b39a5019e7e1b' '1b4f82e6123c5baa0cd07056e368064e' @@ -61,8 +63,8 @@ md5sums=('b8b4009f95f8543244ae1d23b1810d7c' '26faff00b306b6ef276a7d9e6d964994' 'bd04a0699b80c8042e1cf63a7e0e4222' 'd0a956f0eb4b53b66d83df2a8a4d16dc' - '88c3520c6ba51a31ea29903b5ee6c484' - 'a572a0fd087c89d8f50f16544bb1ec69' + 'd6eb433a0516d987ac1054e8b14e8129' + 'a4528366d1839ee400e51abc793446f5' '0a2bbaf74c7160ba33876dcc2f050f14') prepare() { @@ -115,7 +117,7 @@ package() { make DESTDIR="$pkgdir" install - install -Dm644 "doc/faq.xml" "$pkgdir/usr/share/doc/$_pkgname/faq.xml" + install -Dm644 "doc/faq.xml" "$pkgdir/usr/share/doc/$_pkgname/faq.xml" install -Dm644 "doc/old/rtorrent.1" "$pkgdir/usr/share/man/man1/$_pkgname.1" install -Dm644 "doc/rtorrent.rc" "$pkgdir/usr/share/doc/$_pkgname/rtorrent.rc" install -Dm644 "doc/rtorrent_fast_resume.pl" "$pkgdir/usr/share/doc/$_pkgname/rtorrent_fast_resume.pl" diff --git a/ps-dl-ui-find_all.patch b/ps-dl-ui-find_all.patch new file mode 100644 index 000000000000..8392ce212593 --- /dev/null +++ b/ps-dl-ui-find_all.patch @@ -0,0 +1,43 @@ +--- a/src/ui/download_list.cc ++++ b/src/ui/download_list.cc +@@ -259,6 +259,10 @@ DownloadList::receive_view_input(Input type) { + title = "command"; + break; + ++ case INPUT_FIND: ++ title = "find"; ++ break; ++ + default: + throw torrent::internal_error("DownloadList::receive_view_input(...) Invalid input type."); + } +@@ -322,6 +326,11 @@ DownloadList::receive_exit_input(Input type) { + input->str()); + break; + ++ case INPUT_FIND: ++ rpc::call_command("ui.find.term.set", rak::trim(input->str()), rpc::make_target()); ++ rpc::call_command("ui.find.next", torrent::Object(), rpc::make_target()); ++ break; ++ + default: + throw torrent::internal_error("DownloadList::receive_exit_input(...) Invalid input type."); + } +@@ -353,2 +362,5 @@ DownloadList::setup_keys() { + m_uiArray[DISPLAY_DOWNLOAD_LIST]->bindings()['l'] = std::bind(&DownloadList::activate_display, this, DISPLAY_LOG); ++ ++ // Replace Ctrl-F binding for setting 'ui.find.term' ++ m_uiArray[DISPLAY_DOWNLOAD_LIST]->bindings()['F' - '@'] = std::bind(&DownloadList::receive_view_input, this, INPUT_FIND); + } +--- a/src/ui/download_list.h ++++ b/src/ui/download_list.h +@@ -86,7 +86,8 @@ public: + INPUT_LOAD_DEFAULT, + INPUT_LOAD_MODIFIED, + INPUT_CHANGE_DIRECTORY, +- INPUT_COMMAND ++ INPUT_COMMAND, ++ INPUT_FIND + } Input; + + DownloadList(); diff --git a/ui_pyroscope.cc b/ui_pyroscope.cc index 06db8c6725c7..d9dd1edd00a8 100644 --- a/ui_pyroscope.cc +++ b/ui_pyroscope.cc @@ -385,35 +385,38 @@ torrent::Object ui_canvas_color_set(const torrent::Object::string_type& arg) { int64_t cmd_d_message_alert(core::Download* d) { int64_t alert = ps::ALERT_NORMAL; + const std::string& msg = d->message(); - if (!d->message().empty()) { + if (!msg.empty()) { alert = ps::ALERT_GENERIC; - if (d->message().find("Tried all trackers") != std::string::npos) + if (msg.find("Tried all trackers") != std::string::npos) alert = ps::ALERT_NORMAL_CYCLING; - else if (d->message().find("Timeout was reached") != std::string::npos - || d->message().find("Timed out") != std::string::npos) + else if (msg.find("no data") != std::string::npos) + alert = ps::ALERT_NORMAL_GHOST; + else if (msg.find("Timeout was reached") != std::string::npos + || msg.find("Timed out") != std::string::npos) alert = ps::ALERT_TIMEOUT; - else if (d->message().find("Connecting to") != std::string::npos) + else if (msg.find("Connecting to") != std::string::npos) alert = ps::ALERT_CONNECT; - else if (d->message().find("Could not parse bencoded data") != std::string::npos - || d->message().find("Failed sending data") != std::string::npos - || d->message().find("Server returned nothing") != std::string::npos - || d->message().find("Couldn't connect to server") != std::string::npos) + else if (msg.find("Could not parse bencoded data") != std::string::npos + || msg.find("Failed sending data") != std::string::npos + || msg.find("Server returned nothing") != std::string::npos + || msg.find("Couldn't connect to server") != std::string::npos) alert = ps::ALERT_REQUEST; - else if (d->message().find("not registered") != std::string::npos - || d->message().find("torrent cannot be found") != std::string::npos - || d->message().find("nregistered") != std::string::npos) + else if (msg.find("not registered") != std::string::npos + || msg.find("torrent cannot be found") != std::string::npos + || msg.find("nregistered") != std::string::npos) alert = ps::ALERT_GONE; - else if (d->message().find("not authorized") != std::string::npos - || d->message().find("blocked from") != std::string::npos - || d->message().find("denied") != std::string::npos - || d->message().find("limit exceeded") != std::string::npos - || d->message().find("active torrents are enough") != std::string::npos) + else if (msg.find("not authorized") != std::string::npos + || msg.find("blocked from") != std::string::npos + || msg.find("denied") != std::string::npos + || msg.find("limit exceeded") != std::string::npos + || msg.find("active torrents are enough") != std::string::npos) alert = ps::ALERT_PERMS; - else if (d->message().find("tracker is down") != std::string::npos) + else if (msg.find("tracker is down") != std::string::npos) alert = ps::ALERT_DOWN; - else if (d->message().find("n't resolve host name") != std::string::npos) + else if (msg.find("n't resolve host name") != std::string::npos) alert = ps::ALERT_DNS; } @@ -438,7 +441,7 @@ torrent::Object cmd_d_tracker_alias(core::Download* download) { static void decorate_download_title(Window* window, display::Canvas* canvas, core::View* view, - int pos, Range& range, int x_title) { + int pos, Range& range, int x_title, size_t hilite, size_t hilen) { int offset = row_offset(view, range); core::Download* item = *range.first; bool active = item->is_open() && item->is_active(); @@ -455,6 +458,10 @@ static void decorate_download_title(Window* window, display::Canvas* canvas, cor title_col = (active ? D_INFO(item)->down_rate()->rate() ? ps::COL_LEECHING : ps::COL_INCOMPLETE : ps::COL_QUEUED) + offset; canvas->set_attr(x_title, pos, -1, attr_map[title_col] | focus_attr, title_col); + if (hilen && hilite != std::string::npos && x_title + hilite < int(canvas->width())) { + canvas->set_attr(x_title + hilite, pos, std::min(hilen, int(canvas->width()) - x_title - hilite), + (attr_map[title_col] | focus_attr | A_REVERSE) ^ A_BOLD, title_col); + } // show label for active tracker (a/k/a in focus tracker) if (int(canvas->width()) <= x_title + NAME_RESERVED_WIDTH + 3) return; @@ -505,7 +512,7 @@ void ui_pyroscope_download_list_redraw_item(Window* window, display::Canvas* can } } - decorate_download_title(window, canvas, view, pos, range, 2); + decorate_download_title(window, canvas, view, pos, range, 2, -1, 0); // better handling for trail of line 2 (ratio etc.) int status_pos = 91; @@ -763,7 +770,8 @@ int render_columns(bool headers, bool narrow, rpc::target_type target, core::Dow case ps::COL_ALERT: // COL_ALARM is the actual color, this is the dynamic one bool has_alert = !item->message().empty() && item->message().find("Tried all trackers") == std::string::npos; - attr_idx = has_alert ? ps::COL_ALARM : ps::COL_INFO; + bool no_data = item->message().find("no data") != std::string::npos; + attr_idx = no_data ? ps::COL_PROGRESS0 : has_alert ? ps::COL_ALARM : ps::COL_INFO; break; } } @@ -810,6 +818,8 @@ bool ui_pyroscope_download_list_redraw(Window* window, display::Canvas* canvas, const torrent::Object::map_type& column_defs = control->object_storage()->get_str("ui.column.render").as_map(); int pos = 1, x_base = 2, column = x_base; bool narrow = false; + std::string find_term = rpc::call_command_string("ui.find.term"); + std::transform(find_term.begin(), find_term.end(), find_term.begin(), ::tolower); // Render header line canvas->print(0, pos, "⇳ "); @@ -864,7 +874,13 @@ bool ui_pyroscope_download_list_redraw(Window* window, display::Canvas* canvas, canvas->print(column, pos, " %s", u8_chop(displayname.empty() ? d->info()->name() : displayname.c_str(), canvas->width() - column - 1).c_str()); - decorate_download_title(window, canvas, view, pos, range, column + 1); + size_t hilite = std::string::npos; + if (!find_term.empty()) { + if (displayname.empty()) displayname = d->info()->name(); + std::transform(displayname.begin(), displayname.end(), displayname.begin(), ::tolower); + hilite = displayname.find(find_term); + } + decorate_download_title(window, canvas, view, pos, range, column + 1, hilite, find_term.length()); } // Colorize focus marker @@ -1054,6 +1070,46 @@ torrent::Object apply_magnitude(const torrent::Object::list_type& args) { } +torrent::Object ui_find_next() { + std::string term = rpc::call_command_string("ui.find.term"); + if (term.empty()) + return torrent::Object(); // no current search term set + std::transform(term.begin(), term.end(), term.begin(), ::tolower); + + ui::DownloadList* dl_list = control->ui()->download_list(); + core::View* dl_view = dl_list->current_view(); + + if (dl_view->empty_visible()) { + control->core()->push_log("This view is empty, nothing to find!"); + } else { + core::View::iterator itr = dl_view->focus() == dl_view->end_visible() ? + dl_view->begin_visible() : dl_view->focus(); + bool found = false; + + do { + if (++itr == dl_view->end_visible()) + itr = dl_view->begin_visible(); + + // In C++11, this can be done more efficiently using std::search; + // we only use this interactively, so meh. + std::string name = get_custom_string(*itr, "displayname"); + if (name.empty()) name = (*itr)->info()->name(); + std::transform(name.begin(), name.end(), name.begin(), ::tolower); + found = name.find(term) != std::string::npos; + } while (!found && itr != dl_view->focus()); + + if (!found) { + control->core()->push_log(("Cannot find anything matching '" + term + "'").c_str()); + } else if (itr != dl_view->focus()) { + dl_view->set_focus(itr); + dl_view->set_last_changed(); + } + } + + return torrent::Object(); +} + + // register our commands void initialize_command_ui_pyroscope() { #define PS_VARIABLE_COLOR(key, value) \ @@ -1091,6 +1147,9 @@ void initialize_command_ui_pyroscope() { CMD2_ANY("ui.column.sacrificial.list", _cxxstd_::bind(&display::ui_column_sacrificial_list)); CMD2_VAR_VALUE("ui.column.sacrificed", 0); + CMD2_ANY ("ui.find.next", _cxxstd_::bind(&ui_find_next)); + CMD2_VAR_STRING("ui.find.term", ""); + PS_VARIABLE_COLOR("ui.color.progress0", "red"); PS_VARIABLE_COLOR("ui.color.progress20", "bold bright red"); PS_VARIABLE_COLOR("ui.color.progress40", "bold bright magenta"); @@ -1162,6 +1221,10 @@ void initialize_command_ui_pyroscope() { "schedule2 = collapsed_view_toggle, 0, 0, ((ui.bind_key, download_list, *, \"" "view.collapsed.toggle= ; ui.current_view.set = (ui.current_view)\"))\n" + // Bind 'F' / F3 to find the next item for 'ui.find.term' + "schedule2 = ui_find_next_f, 0, 0, ((ui.bind_key, download_list, F, \"ui.find.next=\"))\n" + "schedule2 = ui_find_next_f3, 0, 0, ((ui.bind_key, download_list, 0413, \"ui.find.next=\"))\n" + // Collapse built-in views "view.collapsed.toggle = main\n" "view.collapsed.toggle = name\n" @@ -1213,7 +1276,7 @@ void initialize_command_ui_pyroscope() { // Status flags (❢ ☢ ☍ ⌘) "method.set_key = ui.column.render, \"100:3C95/2:❢ \"," - " ((array.at, {\" \", \"♺ \", \"⚠ \", \"◔ \", \"⚡ \", \"↯ \", \"¿?\"," + " ((array.at, {\" \", \"♺ \", \"ʘ \", \"⚠ \", \"◔ \", \"⚡ \", \"↯ \", \"¿?\"," " \"⨂ \", \"⋫ \", \"☡ \"}, ((d.message.alert)) ))\n" "method.set_key = ui.column.render, \"110:2C92/2:☢ \"," " ((string.map, ((cat, ((d.is_open)), ((d.is_active)))), {00, \"▪ \"}, {01, \"▪ \"}, {10, \"╍ \"}, {11, \"▹ \"}))\n" diff --git a/ui_pyroscope.h b/ui_pyroscope.h index aee5ada5afde..042d73c44366 100644 --- a/ui_pyroscope.h +++ b/ui_pyroscope.h @@ -11,6 +11,7 @@ namespace ps { enum AlertKind { ALERT_NORMAL, ALERT_NORMAL_CYCLING, // Tried all trackers + ALERT_NORMAL_GHOST, // no data ALERT_GENERIC, ALERT_TIMEOUT, ALERT_CONNECT, |