aboutsummaryrefslogtreecommitdiff
path: root/src/plugins/HotExamples.cpp
blob: 043ddfd3026501211fc1b472250bb55a9e4a0c26 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
#include "../../plugins/HotExamples.hpp"
#include "../../include/Theme.hpp"
#include "../../include/StringUtils.hpp"
#include <quickmedia/HtmlSearch.h>

namespace QuickMedia {
    static std::shared_ptr<BodyItem> create_body_item_with_url(const std::string &title, const std::string &url) {
        auto body_item = BodyItem::create(title);
        body_item->url = url;
        return body_item;
    }

    void hot_examples_front_page_fill(BodyItems &body_items) {
        body_items.push_back(create_body_item_with_url("C++", "cpp"));
        body_items.push_back(create_body_item_with_url("C#", "csharp"));
        body_items.push_back(create_body_item_with_url("Go", "go"));
        body_items.push_back(create_body_item_with_url("Java", "java"));
        body_items.push_back(create_body_item_with_url("JavaScript", "javascript"));
        body_items.push_back(create_body_item_with_url("PHP", "php"));
        body_items.push_back(create_body_item_with_url("Python", "python"));
        body_items.push_back(create_body_item_with_url("TypeScript", "typescript"));
    }

    PluginResult HotExamplesLanguageSelectPage::submit(const std::string&, const std::string &url, std::vector<Tab> &result_tabs) {
        result_tabs.push_back({ create_body(), std::make_unique<HotExamplesSearchPage>(program, url), create_search_bar("Search...", 500) });
        return PluginResult::OK;
    }

    SearchResult HotExamplesSearchPage::search(const std::string &str, BodyItems &result_items) {
        std::vector<CommandArg> additional_args = {
            { "-H", "content-type: application/x-www-form-urlencoded" },
            { "--data-raw", "SearchForm[lang]=" + language + "&SearchForm[search]=" + url_param_encode(str) }
        };
        
        std::string website_data;
        DownloadResult download_result = download_to_string("https://hotexamples.com/search", website_data, additional_args, true);
        if(download_result != DownloadResult::OK) return download_result_to_search_result(download_result);

        QuickMediaHtmlSearch html_search;
        int result = quickmedia_html_search_init(&html_search, website_data.c_str(), website_data.size());
        if(result != 0)
            return SearchResult::ERR;

        quickmedia_html_find_nodes_xpath(&html_search, "//div[class='search-result row']//div[class='header']//a",
            [](QuickMediaMatchNode *node, void *userdata) {
                auto *item_data = (BodyItems*)userdata;
                QuickMediaStringView href = quickmedia_html_node_get_attribute_value(node, "href");
                if(href.data && memmem(href.data, href.size, "/examples/", 10)) {
                    QuickMediaStringView text = quickmedia_html_node_get_text(node);
                    if(text.data) {
                        std::string title(text.data, text.size);
                        html_unescape_sequences(title);

                        auto item = BodyItem::create(std::move(title));
                        item->url.assign(href.data, href.size);
                        item_data->push_back(std::move(item));
                    }
                }
                return 0;
            }, &result_items);

        BodyItemContext body_item_context;
        body_item_context.body_items = &result_items;
        body_item_context.index = 0;

        quickmedia_html_find_nodes_xpath(&html_search, "//div[class='search-result row']//span[class='count']",
            [](QuickMediaMatchNode *node, void *userdata) {
                auto *item_data = (BodyItemContext*)userdata;
                QuickMediaStringView text = quickmedia_html_node_get_text(node);
                if(text.data && item_data->index < item_data->body_items->size()) {
                    std::string desc(text.data, text.size);
                    html_unescape_sequences(desc);

                    (*item_data->body_items)[item_data->index]->set_description(std::move(desc));
                    (*item_data->body_items)[item_data->index]->set_description_color(get_theme().faded_text_color);
                    item_data->index++;
                }
                return 0;
            }, &body_item_context);

        quickmedia_html_search_deinit(&html_search);
        return SearchResult::OK;
    }

    PluginResult HotExamplesSearchPage::submit(const std::string &title, const std::string &url, std::vector<Tab> &result_tabs) {
        BodyItems result_items;
        std::string website_data;
        DownloadResult download_result = download_to_string(url, website_data, {}, true);
        if(download_result != DownloadResult::OK) return download_result_to_plugin_result(download_result);

        QuickMediaHtmlSearch html_search;
        int result = quickmedia_html_search_init(&html_search, website_data.c_str(), website_data.size());
        if(result != 0)
            return PluginResult::ERR;

        quickmedia_html_find_nodes_xpath(&html_search, "//div[class='example-item']//div[class='example-project-info']",
            [](QuickMediaMatchNode *node, void *userdata) {
                auto *item_data = (BodyItems*)userdata;
                QuickMediaStringView text = quickmedia_html_node_get_text(node);
                if(text.data) {
                    std::string title(text.data, text.size);
                    html_unescape_sequences(title);
                    string_replace_all(title, "File:", "File: ");
                    string_replace_all(title, "Project:", " Project: ");

                    auto item = BodyItem::create(std::move(title));
                    //item->url.assign(href.data, href.size);
                    item_data->push_back(std::move(item));
                }
                return 0;
            }, &result_items);

        BodyItemContext body_item_context;
        body_item_context.body_items = &result_items;
        body_item_context.index = 0;

        quickmedia_html_find_nodes_xpath(&html_search, "//div[class='example-item']//div[class='example']",
            [](QuickMediaMatchNode *node, void *userdata) {
                auto *item_data = (BodyItemContext*)userdata;
                QuickMediaStringView text = quickmedia_html_node_get_text(node);
                if(text.data && item_data->index < item_data->body_items->size()) {
                    std::string desc(text.data, text.size);
                    html_unescape_sequences(desc);

                    (*item_data->body_items)[item_data->index]->set_description(std::move(desc));
                    (*item_data->body_items)[item_data->index]->set_description_color(get_theme().text_color);
                    // TODO: Use monospace
                    item_data->index++;
                }
                return 0;
            }, &body_item_context);

        quickmedia_html_search_deinit(&html_search);
        
        auto body = create_body();
        body->set_items(std::move(result_items));
        result_tabs.push_back({ std::move(body), std::make_unique<HotExamplesCodeExamplesPage>(program, title + " code examples"), create_search_bar("Search...", SEARCH_DELAY_FILTER) });
        return PluginResult::OK;
    }
}