Przeglądaj źródła

Shell: highlight runnable commands

And display in red the command which will result in something like "no
command, or is directory" (inspired by the fish shell).
Mathieu PATUREL 5 lat temu
rodzic
commit
2b4b9d212e
3 zmienionych plików z 23 dodań i 1 usunięć
  1. 7 1
      Shell/AST.cpp
  2. 15 0
      Shell/Shell.cpp
  3. 1 0
      Shell/Shell.h

+ 7 - 1
Shell/AST.cpp

@@ -367,9 +367,15 @@ RefPtr<Value> BarewordLiteral::run(RefPtr<Shell>)
 void BarewordLiteral::highlight_in_editor(Line::Editor& editor, Shell& shell, HighlightMetadata metadata)
 {
     if (metadata.is_first_in_list) {
-        editor.stylize({ m_position.start_offset, m_position.end_offset }, { Line::Style::Bold });
+        if (shell.is_runnable(m_text))
+            editor.stylize({ m_position.start_offset, m_position.end_offset }, { Line::Style::Bold });
+        else {
+            editor.stylize({ m_position.start_offset, m_position.end_offset }, { Line::Style::Foreground(Line::Style::XtermColor::Red) });
+        }
+
         return;
     }
+
     if (m_text.starts_with('-')) {
         if (m_text == "--") {
             editor.stylize({ m_position.start_offset, m_position.end_offset }, { Line::Style::Foreground(Line::Style::XtermColor::Green) });

+ 15 - 0
Shell/Shell.cpp

@@ -386,6 +386,21 @@ String Shell::resolve_alias(const String& name) const
     return m_aliases.get(name).value_or({});
 }
 
+bool Shell::is_runnable(const StringView& name)
+{
+    // FIXME: for now, check aliases manually because cached path doesn't get
+    // updated with aliases. Should it?
+    if (!resolve_alias(name).is_null())
+        return true;
+
+    if (access(name.to_string().characters(), X_OK) == 0)
+        return true;
+
+    return !!binary_search(cached_path.span(), name.to_string(), [](const String& name, const String& program) -> int {
+        return strcmp(name.characters(), program.characters());
+    });
+}
+
 int Shell::run_command(const StringView& cmd)
 {
     if (cmd.is_empty())

+ 1 - 0
Shell/Shell.h

@@ -73,6 +73,7 @@ public:
     constexpr static auto global_init_file_path = "/etc/shellrc";
 
     int run_command(const StringView&);
+    bool is_runnable(const StringView&);
     RefPtr<Job> run_command(const AST::Command&);
     Vector<RefPtr<Job>> run_commands(Vector<AST::Command>&);
     bool run_file(const String&, bool explicitly_invoked = true);