Просмотр исходного кода

feat(ui): add tab completion for files

Implemented file system tab completion in the minibuffer for FindFile mode. It supports directory navigation and prefix matching.
Bernardo Magri 1 месяц назад
Родитель
Сommit
fbd83939dd
1 измененных файлов с 75 добавлено и 0 удалено
  1. 75 0
      src/gtk_editor.cpp

+ 75 - 0
src/gtk_editor.cpp

@@ -3,6 +3,9 @@
 #include "lumacs/lua_api.hpp"
 #include "lumacs/keybinding.hpp"
 #include <iostream>
+#include <filesystem>
+#include <vector>
+#include <algorithm>
 
 // Check if GTK is enabled in build
 #ifdef LUMACS_WITH_GTK
@@ -867,6 +870,78 @@ protected:
                     return true;
                 }
                 // TODO: File completion for FindFile
+                if (mode_ == Mode::FindFile) {
+                    std::string input = command_buffer_;
+                    namespace fs = std::filesystem;
+                    
+                    fs::path search_path;
+                    std::string prefix;
+                    
+                    // Determine directory and prefix
+                    if (input.empty()) {
+                        search_path = fs::current_path();
+                    } else {
+                        fs::path input_path(input);
+                        if (fs::is_directory(input_path) && input.back() == '/') {
+                            search_path = input_path;
+                            prefix = "";
+                        } else {
+                            if (input_path.has_parent_path()) {
+                                search_path = input_path.parent_path();
+                                if (search_path.string().empty()) search_path = fs::current_path();
+                            } else {
+                                search_path = fs::current_path();
+                            }
+                            prefix = input_path.filename().string();
+                        }
+                    }
+
+                    std::vector<std::string> matches;
+                    try {
+                        if (fs::exists(search_path) && fs::is_directory(search_path)) {
+                            for (const auto& entry : fs::directory_iterator(search_path)) {
+                                std::string filename = entry.path().filename().string();
+                                if (filename.find(prefix) == 0) {
+                                    if (fs::is_directory(entry.path())) {
+                                        matches.push_back(filename + "/");
+                                    } else {
+                                        matches.push_back(filename);
+                                    }
+                                }
+                            }
+                        }
+                    } catch (...) {
+                        // Ignore permission errors etc
+                    }
+
+                    if (matches.size() == 1) {
+                        // Append the difference
+                        std::string completion = matches[0].substr(prefix.length());
+                        command_buffer_ += completion;
+                    } else if (matches.size() > 1) {
+                         // Find common prefix of MATCHES (not including full path)
+                        std::string common = matches[0];
+                        for (size_t i = 1; i < matches.size(); ++i) {
+                            const std::string& s = matches[i];
+                            size_t j = 0;
+                            while (j < common.size() && j < s.size() && common[j] == s[j]) {
+                                j++;
+                            }
+                            common = common.substr(0, j);
+                        }
+                        // Append difference between common prefix and current input prefix
+                        if (common.length() > prefix.length()) {
+                             command_buffer_ += common.substr(prefix.length());
+                        } else {
+                            message_line_ = "Multiple matches";
+                        }
+                    } else {
+                        message_line_ = "No match";
+                    }
+                    
+                    if (content_widget_) queue_redraw_all_windows(content_widget_);
+                    return true;
+                }
             }
             
             if (key_name == "Return") {