Bladeren bron

Help: Add support for launching with a section and page, like man

I found it strange that `man` and `Help` did not accept the same command
line arguments since they are so similar. So... now they do. :^)

This means you can now open for example the `tar` man page in Help with
`Help tar`, or `Help 1 tar` if you want to disambiguate between pages in
different sections.

If the result is not found, it falls back to the previous behavior,
treating the input as a search query.

Initially I had this written as two optional positional arguments, but
when told to parse `[optional int] [optional string]`, and then given a
string input, ArgsParser forwards it to the [optional int], which then
fails to parse. Ideally it would pass it to the second, [optional
string] arg instead, but that looks like a fairly big change to make to
ArgsParser's internals, and risk breaking things. Maybe this ugly hack
will be an incentive to fix it. :^)
Sam Atkins 3 jaren geleden
bovenliggende
commit
8461f8c1cd
1 gewijzigde bestanden met toevoegingen van 71 en 8 verwijderingen
  1. 71 8
      Userland/Applications/Help/main.cpp

+ 71 - 8
Userland/Applications/Help/main.cpp

@@ -1,6 +1,7 @@
 /*
  * Copyright (c) 2019-2020, Sergey Bugaev <bugaevc@serenityos.org>
  * Copyright (c) 2021, Andreas Kling <kling@serenityos.org>
+ * Copyright (c) 2021, Sam Atkins <atkinssj@serenityos.org>
  *
  * SPDX-License-Identifier: BSD-2-Clause
  */
@@ -45,9 +46,40 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
     TRY(Core::System::unveil(nullptr, nullptr));
 
     char const* start_page = nullptr;
+    unsigned section = 0;
 
     Core::ArgsParser args_parser;
-    args_parser.add_positional_argument(start_page, "Page to open at launch", "page", Core::ArgsParser::Required::No);
+    // FIXME: These custom Args are a hack. What we want to do is have an optional int arg, then an optional string.
+    // However, when only a string is provided, it gets forwarded to the int argument since that is first, and
+    // parsing fails. This hack instead forwards it to the start_page in that case.
+    args_parser.add_positional_argument(Core::ArgsParser::Arg {
+        .help_string = "Section of the man page",
+        .name = "section",
+        .min_values = 0,
+        .max_values = 1,
+        .accept_value = [&](char const* input) {
+            // If it's a number, use it as the section
+            if (auto number = StringView(input).to_int(); number.has_value()) {
+                section = number.value();
+                return true;
+            }
+
+            // Otherwise, use it as the start_page
+            start_page = input;
+            return true;
+        } });
+    args_parser.add_positional_argument(Core::ArgsParser::Arg {
+        .help_string = "Help page to open. Either an absolute path to the markdown file, or a search query",
+        .name = "page",
+        .min_values = 0,
+        .max_values = 1,
+        .accept_value = [&](char const* input) {
+            // If start_page was already set by our section arg, then it can't be set again
+            if (start_page)
+                return false;
+            start_page = input;
+            return true;
+        } });
     args_parser.parse(arguments);
 
     auto app_icon = GUI::Icon::default_icon("app-help");
@@ -268,17 +300,48 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
 
     bool set_start_page = false;
     if (start_page) {
-        URL url = URL::create_with_url_or_path(start_page);
-        if (url.is_valid() && url.path().ends_with(".md")) {
+        if (section != 0) {
+            // > Help [section] [name]
+            String path = String::formatted("/usr/share/man/man{}/{}.md", section, start_page);
+            history.push(path);
+            open_page(path);
+            set_start_page = true;
+        } else if (URL url = URL::create_with_url_or_path(start_page); url.is_valid() && url.path().ends_with(".md")) {
+            // > Help [/path/to/documentation/file.md]
             history.push(url.path());
             open_page(url.path());
             set_start_page = true;
         } else {
-            left_tab_bar->set_active_widget(search_view);
-            search_box->set_text(start_page);
-            if (auto* model = search_list_view->model()) {
-                auto& search_model = *static_cast<GUI::FilteringProxyModel*>(model);
-                search_model.set_filter_term(search_box->text());
+            // > Help [query]
+
+            // First, see if we can find the page by name
+            char const* sections[] = {
+                "1",
+                "2",
+                "3",
+                "4",
+                "5",
+                "6",
+                "7",
+                "8"
+            };
+            for (auto s : sections) {
+                String path = String::formatted("/usr/share/man/man{}/{}.md", s, start_page);
+                if (Core::File::exists(path)) {
+                    history.push(path);
+                    open_page(path);
+                    set_start_page = true;
+                }
+            }
+
+            // No match, so treat the input as a search query
+            if (!set_start_page) {
+                left_tab_bar->set_active_widget(search_view);
+                search_box->set_text(start_page);
+                if (auto* model = search_list_view->model()) {
+                    auto& search_model = *static_cast<GUI::FilteringProxyModel*>(model);
+                    search_model.set_filter_term(search_box->text());
+                }
             }
         }
     }