Răsfoiți Sursa

starting the plan for a GUI

Bernardo Magri 1 lună în urmă
părinte
comite
f50c65e891

+ 47 - 0
include/lumacs/config.hpp

@@ -0,0 +1,47 @@
+#pragma once
+
+#include <string>
+#include <unordered_map>
+#include <variant>
+#include <vector>
+
+namespace lumacs {
+
+/// Configuration value type
+using ConfigValue = std::variant<bool, int, std::string>;
+
+/// Global configuration manager
+class Config {
+public:
+    Config();
+
+    /// Set a configuration value
+    void set(const std::string& key, const ConfigValue& value);
+
+    /// Get a configuration value
+    template<typename T>
+    T get(const std::string& key, const T& default_value = T{}) const {
+        auto it = values_.find(key);
+        if (it == values_.end()) {
+            return default_value;
+        }
+
+        try {
+            return std::get<T>(it->second);
+        } catch (const std::bad_variant_access&) {
+            return default_value;
+        }
+    }
+
+    /// Check if a key exists
+    bool has(const std::string& key) const;
+
+    /// Get all keys
+    std::vector<std::string> keys() const;
+
+private:
+    std::unordered_map<std::string, ConfigValue> values_;
+    void set_defaults();
+};
+
+} // namespace lumacs

+ 18 - 11
include/lumacs/editor_core.hpp

@@ -14,6 +14,8 @@
 
 namespace lumacs {
 
+class LuaApi; // Forward declaration
+
 /// Editor state change events
 enum class EditorEvent {
     BufferModified,
@@ -266,12 +268,15 @@ public:
     [[nodiscard]] Config& config() noexcept { return config_; }
     [[nodiscard]] const Config& config() const noexcept { return config_; }
 
-    // === Key Binding System ===
-    [[nodiscard]] KeyBindingManager& keybinding_manager() noexcept { return keybinding_manager_; }
-    [[nodiscard]] const KeyBindingManager& keybinding_manager() const noexcept { return keybinding_manager_; }
-
-private:
-    // All open buffers
+        // === Key Binding System ===                                                                                                                                 
+        [[nodiscard]] KeyBindingManager& keybinding_manager() noexcept { return keybinding_manager_; }                                                                
+        [[nodiscard]] const KeyBindingManager& keybinding_manager() const noexcept { return keybinding_manager_; }                                                    
+                                                                                                                                                                      
+        // === Lua API ===                                                                                                                                            
+        [[nodiscard]] LuaApi* lua_api() const { return lua_api_.get(); }                                                                                              
+                                                                                                                                                                      
+    private:                                                                                                                                                          
+        // All open buffers
     std::list<std::shared_ptr<Buffer>> buffers_;
 
     // Word movement helpers
@@ -310,11 +315,13 @@ private:
     // Configuration
     Config config_;
 
-    // Key binding system
-    KeyBindingManager keybinding_manager_;
-
-    void emit_event(EditorEvent event);
-    
+        // Key binding system                                                                                                                                         
+        KeyBindingManager keybinding_manager_;                                                                                                                        
+                                                                                                                                                                      
+        // Lua API                                                                                                                                                    
+        std::unique_ptr<LuaApi> lua_api_;
+                                                                                                                                                                      
+        void emit_event(EditorEvent event);    
     // Helper to find a node containing the active window
     LayoutNode* find_parent_node(LayoutNode* root, std::shared_ptr<Window> target);
     

+ 162 - 0
include/lumacs/keybinding.hpp

@@ -0,0 +1,162 @@
+#pragma once
+
+#include <string>
+#include <vector>
+#include <map>
+#include <memory>
+#include <functional>
+#include <chrono>
+#include <optional>
+
+namespace lumacs {
+
+/// Represents a single key in a key sequence
+struct Key {
+    std::string name;           // Key name like "C-x", "M-f", "a", "Return"
+    bool ctrl = false;          // Ctrl modifier
+    bool meta = false;          // Meta/Alt modifier
+    bool shift = false;         // Shift modifier
+    
+    Key() = default;
+    explicit Key(const std::string& key_name);
+    
+    /// Parse a key string like "C-x" into Key structure
+    static Key parse(const std::string& key_str);
+    
+    /// Convert Key back to string representation
+    std::string to_string() const;
+    
+    bool operator==(const Key& other) const;
+    bool operator<(const Key& other) const;
+};
+
+/// Represents a sequence of keys like ["C-x", "2"] for "C-x 2"
+class KeySequence {
+public:
+    KeySequence() = default;
+    explicit KeySequence(const std::vector<Key>& keys);
+    explicit KeySequence(const std::string& key_sequence_str);
+    
+    /// Add a key to the sequence
+    void add_key(const Key& key);
+    void add_key(const std::string& key_str);
+    
+    /// Get the keys in this sequence
+    const std::vector<Key>& keys() const { return keys_; }
+    
+    /// Check if this sequence is empty
+    bool empty() const { return keys_.empty(); }
+    
+    /// Get the length of the sequence
+    size_t length() const { return keys_.size(); }
+    
+    /// Check if this sequence is a prefix of another sequence
+    bool is_prefix_of(const KeySequence& other) const;
+    
+    /// Check if this sequence has the given sequence as a prefix
+    bool has_prefix(const KeySequence& prefix) const;
+    
+    /// Get string representation like "C-x 2"
+    std::string to_string() const;
+    
+    /// Clear the sequence
+    void clear();
+    
+    /// Get a subsequence starting from index
+    KeySequence subsequence(size_t start_index) const;
+    
+    bool operator==(const KeySequence& other) const;
+    bool operator<(const KeySequence& other) const;
+
+private:
+    std::vector<Key> keys_;
+};
+
+/// Function type for key binding callbacks
+using KeyBindingFunction = std::function<bool()>;
+
+/// Represents a key binding with its associated function
+struct KeyBinding {
+    KeySequence sequence;
+    KeyBindingFunction function;
+    std::string description;    // Human-readable description
+    
+    KeyBinding() = default;
+    KeyBinding(const KeySequence& seq, KeyBindingFunction func, std::string desc = "");
+    KeyBinding(const std::string& key_str, KeyBindingFunction func, std::string desc = "");
+};
+
+/// Result of processing a key in the binding manager
+enum class KeyResult {
+    Unbound,        // No binding found, key not handled
+    Executed,       // Binding found and executed successfully
+    Failed,         // Binding found but execution failed
+    Partial,        // Key is part of a multi-key sequence, waiting for more keys
+    Timeout         // Partial sequence timed out
+};
+
+/// Central manager for all key bindings
+class KeyBindingManager {
+public:
+    KeyBindingManager();
+    ~KeyBindingManager() = default;
+    
+    /// Bind a key sequence to a function
+    void bind(const KeySequence& sequence, KeyBindingFunction function, const std::string& description = "");
+    void bind(const std::string& key_str, KeyBindingFunction function, const std::string& description = "");
+    
+    /// Unbind a key sequence
+    void unbind(const KeySequence& sequence);
+    void unbind(const std::string& key_str);
+    
+    /// Process a single key press
+    KeyResult process_key(const Key& key);
+    KeyResult process_key(const std::string& key_str);
+    
+    /// Check if a sequence has any bindings (exact or partial)
+    bool has_binding(const KeySequence& sequence) const;
+    bool has_exact_binding(const KeySequence& sequence) const;
+    bool has_prefix_bindings(const KeySequence& sequence) const;
+    
+    /// Clear current partial sequence (e.g., on timeout or escape)
+    void clear_partial_sequence();
+    
+    /// Get current partial sequence for display purposes
+    const KeySequence& current_partial_sequence() const { return current_sequence_; }
+    
+    /// Check if we're currently building a multi-key sequence
+    bool is_building_sequence() const;
+    
+    /// Get string representation of current sequence for display
+    std::string current_sequence_display() const;
+    
+    /// Get all registered bindings (for debugging/help)
+    std::vector<KeyBinding> get_all_bindings() const;
+    
+    /// Set timeout for multi-key sequences (in milliseconds)
+    void set_sequence_timeout(std::chrono::milliseconds timeout);
+    
+    /// Check if current partial sequence has timed out
+    bool has_sequence_timed_out() const;
+
+private:
+    /// Map from key sequences to their bindings
+    std::map<KeySequence, KeyBinding> bindings_;
+    
+    /// Current partial key sequence being built
+    KeySequence current_sequence_;
+    
+    /// Timestamp of when current sequence started
+    std::chrono::steady_clock::time_point sequence_start_time_;
+    
+    /// Timeout for partial sequences
+    std::chrono::milliseconds sequence_timeout_;
+    
+    /// Find exact binding for a sequence
+    std::optional<KeyBinding> find_exact_binding(const KeySequence& sequence) const;
+    
+    /// Check if sequence has any prefix bindings
+    bool has_prefix_bindings_impl(const KeySequence& sequence) const;
+};
+
+} // namespace lumacs

+ 56 - 0
include/lumacs/kill_ring.hpp

@@ -0,0 +1,56 @@
+#pragma once
+
+#include <string>
+#include <deque>
+#include <cstddef>
+
+namespace lumacs {
+
+/// Emacs-style kill ring for cut/copy/paste operations
+/// Maintains a circular buffer of killed/copied text
+class KillRing {
+public:
+    /// Constructor with optional maximum size
+    /// @param max_size Maximum number of entries to keep (default: 60)
+    explicit KillRing(size_t max_size = 60);
+
+    /// Push new text to the kill ring
+    /// @param text Text to add to the ring
+    void push(std::string text);
+
+    /// Get the current entry in the kill ring
+    /// @return Current text, or empty string if ring is empty
+    std::string current() const;
+
+    /// Move to previous entry and return it
+    /// @return Previous text in the ring
+    std::string previous();
+
+    /// Move to next entry and return it
+    /// @return Next text in the ring
+    std::string next();
+
+    /// Check if the kill ring is empty
+    /// @return true if the ring contains no entries
+    bool empty() const noexcept;
+
+    /// Get the number of entries in the ring
+    /// @return Number of entries currently stored
+    size_t size() const noexcept;
+
+    /// Clear all entries from the ring
+    void clear();
+
+    /// Enable append mode for the next push operation
+    /// When append mode is active, the next push will append to the current entry
+    /// instead of creating a new one
+    void set_append_next(bool append = true) { append_next_ = append; }
+
+private:
+    std::deque<std::string> ring_;       ///< The circular buffer of text entries
+    size_t max_size_;                    ///< Maximum number of entries to keep
+    size_t current_index_ = 0;           ///< Current position in the ring
+    bool append_next_ = false;           ///< Whether to append to current entry on next push
+};
+
+} // namespace lumacs

+ 7 - 2
include/lumacs/lua_api.hpp

@@ -10,12 +10,17 @@
 
 namespace lumacs {
 
+class EditorCore; // Forward declaration
+
 /// Lua scripting API for Lumacs
 class LuaApi {
 public:
-    explicit LuaApi(EditorCore& core);
+    explicit LuaApi(); // Default constructor
     ~LuaApi() = default;
 
+    /// Set the EditorCore instance after construction
+    void set_core(EditorCore& core);
+
     /// Get the Lua state
     [[nodiscard]] sol::state& state() { return lua_; }
 
@@ -45,7 +50,7 @@ public:
 
 private:
     sol::state lua_;
-    EditorCore& core_;
+    EditorCore* core_ = nullptr; // Changed to pointer
     std::map<std::string, sol::function> legacy_key_bindings_;  // For backward compatibility
 
     void setup_api();

+ 32 - 0
include/lumacs/ui_interface.hpp

@@ -0,0 +1,32 @@
+#pragma once
+
+#include "lumacs/editor_core.hpp" // For EditorEvent and other core types
+
+namespace lumacs {
+
+// Forward declaration to avoid circular dependency
+class EditorCore; 
+
+/// Abstract interface for a Lumacs editor UI frontend.
+/// All editor UIs (ncurses, GTK, etc.) must implement this interface.
+class IEditorView {
+public:
+    virtual ~IEditorView() = default;
+
+    /// Initialize the UI system (e.g., ncurses init, GTK window setup).
+    /// This should be called before run().
+    virtual void init() = 0;
+
+    /// Run the main UI loop. This method should block until the UI exits.
+    virtual void run() = 0;
+
+    /// Handle events emitted by the EditorCore.
+    /// The EditorCore will register this view as a callback listener.
+    virtual void handle_editor_event(EditorEvent event) = 0;
+
+    /// Set the EditorCore instance for the view to interact with.
+    /// This is typically called once during setup.
+    virtual void set_core(EditorCore* core) = 0;
+};
+
+} // namespace lumacs

+ 2 - 0
shell.nix

@@ -14,6 +14,8 @@ pkgs.mkShell {
     # Dependencies
     lua5_4
     ncurses
+    pkg-config # For locating libraries
+    gtkmm4     # GTK4 C++ bindings
 
     # Development tools
     clang-tools  # clangd, clang-format, clang-tidy

+ 26 - 1
src/editor_core.cpp

@@ -1,10 +1,32 @@
 #include "lumacs/editor_core.hpp"
+#include "lumacs/lua_api.hpp" // Include LuaApi header
 #include <algorithm>
 #include <iostream>
 
 namespace lumacs {
 
-EditorCore::EditorCore() {
+EditorCore::EditorCore() :
+    buffers_(), // 1. std::list
+    root_node_(), // 2. std::shared_ptr
+    active_window_(), // 3. std::shared_ptr
+    last_message_(), // 4. std::string
+    event_callbacks_(), // 5. std::vector
+    kill_ring_(), // 6. KillRing
+    last_yank_start_(), // 7. std::optional
+    last_yank_end_(), // 8. std::optional
+    registers_(), // 9. std::unordered_map
+    current_macro_(), // 10. std::vector
+    last_macro_(), // 11. std::vector
+    recording_macro_(false), // 12. bool
+    rectangle_kill_ring_(), // 13. std::vector
+    theme_manager_(), // 14. ThemeManager
+    config_(), // 15. Config
+    keybinding_manager_(), // 16. KeyBindingManager
+    lua_api_(std::make_unique<LuaApi>()) // 17. std::unique_ptr
+{
+    // LuaApi needs core_ pointer to be valid, so set it after constructor body starts
+    lua_api_->set_core(*this);
+
     // Create initial buffer
     auto buffer = std::make_shared<Buffer>();
     buffers_.push_back(buffer);
@@ -16,6 +38,9 @@ EditorCore::EditorCore() {
     // Initialize themes
     theme_manager_.create_default_themes();
     theme_manager_.set_active_theme("everforest-dark");
+
+    // LuaApi will load init.lua, which relies on `editor` global being set via set_core().
+    lua_api_->load_init_file();
 }
 
 // === Buffer Management ===

+ 11 - 6
src/lua_api.cpp

@@ -4,7 +4,7 @@
 
 namespace lumacs {
 
-LuaApi::LuaApi(EditorCore& core) : core_(core) {
+LuaApi::LuaApi() {
     lua_.open_libraries(
         sol::lib::base,
         sol::lib::package,
@@ -13,10 +13,15 @@ LuaApi::LuaApi(EditorCore& core) : core_(core) {
         sol::lib::table,
         sol::lib::io
     );
+    // setup_api() cannot be called here as core_ is not yet set
+}
 
+void LuaApi::set_core(EditorCore& core) {
+    core_ = &core;
     setup_api();
 }
 
+
 bool LuaApi::load_file(const std::filesystem::path& path) {
     try {
         std::cerr << "[DEBUG] Loading Lua file: " << path << std::endl;
@@ -73,7 +78,7 @@ void LuaApi::bind_key(std::string key, sol::function callback, std::string descr
     legacy_key_bindings_[key] = callback;
     
     // Register with new keybinding system
-    core_.keybinding_manager().bind(key, [callback]() -> bool {
+    core_->keybinding_manager().bind(key, [callback]() -> bool {
         try {
             callback();
             return true;  // Assume success if no exception is thrown
@@ -85,13 +90,13 @@ void LuaApi::bind_key(std::string key, sol::function callback, std::string descr
 }
 
 KeyResult LuaApi::process_key(const std::string& key) {
-    return core_.keybinding_manager().process_key(key);
+    return core_->keybinding_manager().process_key(key);
 }
 
 // Legacy methods for backward compatibility
 bool LuaApi::has_key_binding(const std::string& key) const {
     return legacy_key_bindings_.find(key) != legacy_key_bindings_.end() ||
-           core_.keybinding_manager().has_exact_binding(KeySequence(key));
+           core_->keybinding_manager().has_exact_binding(KeySequence(key));
 }
 
 bool LuaApi::execute_key_binding(const std::string& key) {
@@ -421,7 +426,7 @@ void LuaApi::register_types() {
 
 void LuaApi::register_functions() {
     // Global editor instance
-    lua_["editor"] = std::ref(core_);
+    lua_["editor"] = std::ref(*core_);
 
     // Key binding function
     lua_["bind_key"] = [this](std::string key, sol::function callback, sol::optional<std::string> description) {
@@ -438,7 +443,7 @@ void LuaApi::register_functions() {
 
     // Message function for user feedback
     lua_["message"] = [this](std::string msg) {
-        core_.set_message(std::move(msg));
+        core_->set_message(std::move(msg));
     };
 }
 

Fișier diff suprimat deoarece este prea mare
+ 1000 - 1006
src/main_ncurses.cpp


Unele fișiere nu au fost afișate deoarece prea multe fișiere au fost modificate în acest diff