Parcourir la source

Shell: Implement a "cd history" (cdh) builtin

`cdh` with no arguments dumps the last 8 cd calls in history, and
`cdh [index]` can be used to cd to re-run a specific index from that
history. `cdh` itself it a thin wrapper of the `cd` builtin.

There's definitely some improvements that can be made for this command,
but this seems like a good starting point for getting a feel for it and
ideas for changing it in the future.

It's not entirely clear whether we should be storing the resolved path -
or simply just the last argument passed to cd. For now we just use the
last path passed into cd as this seemed like the better option for now.

This means:
 * invalid paths will still be stored in history (potentially useful)
 * cdh's can be repeated for duplicate directory names
 * the history looks a little nicer on the eyes

It might make sense to use resolved paths.

Closes #397
Shannon Booth il y a 5 ans
Parent
commit
d0fb816ac3
2 fichiers modifiés avec 41 ajouts et 0 suppressions
  1. 2 0
      Shell/GlobalState.h
  2. 39 0
      Shell/main.cpp

+ 2 - 0
Shell/GlobalState.h

@@ -28,6 +28,7 @@
 
 #include <AK/String.h>
 #include <AK/Vector.h>
+#include <AK/CircularQueue.h>
 #include <termios.h>
 
 struct GlobalState {
@@ -43,6 +44,7 @@ struct GlobalState {
     bool was_resized { false };
     int last_return_code { 0 };
     Vector<String> directory_stack;
+    CircularQueue<String, 8> cd_history; // FIXME: have a configurable cd history length
 };
 
 extern GlobalState g;

+ 39 - 0
Shell/main.cpp

@@ -191,7 +191,11 @@ static int sh_cd(int argc, const char** argv)
 
     if (argc == 1) {
         new_path = g.home;
+        if (g.cd_history.is_empty() || g.cd_history.last() != g.home)
+            g.cd_history.enqueue(g.home);
     } else {
+        if (g.cd_history.is_empty() || g.cd_history.last() != argv[1])
+            g.cd_history.enqueue(argv[1]);
         if (strcmp(argv[1], "-") == 0) {
             char* oldpwd = getenv("OLDPWD");
             if (oldpwd == nullptr)
@@ -241,6 +245,37 @@ static int sh_cd(int argc, const char** argv)
     return 0;
 }
 
+static int sh_cdh(int argc, const char** argv)
+{
+    if (argc > 2) {
+        fprintf(stderr, "usage: cdh [index]\n");
+        return 1;
+    }
+
+    if (argc == 1) {
+        if (g.cd_history.size() == 0) {
+            printf("cdh: no history available\n");
+            return 0;
+        }
+
+        for (int i = g.cd_history.size() - 1; i >= 0; --i)
+            printf("%lu: %s\n", g.cd_history.size() - i, g.cd_history.at(i).characters());
+        return 0;
+    }
+
+    bool ok;
+    size_t cd_history_index = String(argv[1]).to_uint(ok);
+
+    if (!ok || cd_history_index < 1 || cd_history_index > g.cd_history.size()) {
+        fprintf(stderr, "usage: cdh [index]\n");
+        return 1;
+    }
+
+    const char* path = g.cd_history.at(g.cd_history.size() - cd_history_index).characters();
+    const char* cd_args[] = { "cd", path };
+    return sh_cd(2, cd_args);
+}
+
 static int sh_history(int, const char**)
 {
     for (size_t i = 0; i < editor.history().size(); ++i) {
@@ -489,6 +524,10 @@ static bool handle_builtin(int argc, const char** argv, int& retval)
         retval = sh_cd(argc, argv);
         return true;
     }
+    if (!strcmp(argv[0], "cdh")) {
+        retval = sh_cdh(argc, argv);
+        return true;
+    }
     if (!strcmp(argv[0], "pwd")) {
         retval = sh_pwd(argc, argv);
         return true;