Skip to main content

Overview

ZepMode_Search provides fast file searching and navigation capabilities within a project directory. It offers fuzzy matching and real-time search results, similar to tools like Ctrl+P in VS Code or telescope.nvim in Neovim.

Class Definition

class ZepMode_Search : public ZepMode
Inherits from ZepMode and implements interactive file search.

Constructor

ZepMode_Search(
    ZepEditor& editor,
    ZepWindow& previousWindow,
    ZepWindow& window,
    const fs::path& startPath
)
editor
ZepEditor&
required
Reference to the parent ZepEditor instance
previousWindow
ZepWindow&
required
The window that was active before entering search mode
window
ZepWindow&
required
The window to display search results in
startPath
const fs::path&
required
Root directory to start the file search from

Core Methods

AddKeyPress

virtual void AddKeyPress(uint32_t key, uint32_t modifiers = 0) override
Handles keyboard input for search queries and result navigation.
key
uint32_t
required
The key code
modifiers
uint32_t
default:"0"
Modifier keys (Ctrl, Alt, Shift)
As you type, the search results update in real-time with fuzzy matching.

Begin

virtual void Begin(ZepWindow* pWindow) override
Activates search mode and begins indexing files.
pWindow
ZepWindow*
required
The window to activate search mode in

Name

virtual const char* Name() const override
static const char* StaticName()
Returns the mode name “Search”. Returns: "Search"

DefaultMode

virtual EditorMode DefaultMode() const override
Returns the default editor mode for Search (Normal mode). Returns: EditorMode::Normal

GetCursorType

virtual CursorType GetCursorType() const override
Returns the cursor type for search mode. Returns: Appropriate CursorType for search input

Notify

virtual void Notify(std::shared_ptr<ZepMessage> message) override
Handles system messages and notifications.
message
std::shared_ptr<ZepMessage>
required
The message to process

Search Result Structure

SearchResult

struct SearchResult
{
    uint32_t index;     // Index in the file list
    uint32_t location;  // Character position of last match
}
Represents a single search result with its location in the file list.

IndexSet

struct IndexSet
{
    std::multimap<uint32_t, SearchResult> indices;
}
Maps search scores to results, ordered by relevance.

Opening Files

OpenType

enum class OpenType
{
    Replace,  // Replace current window content
    VSplit,   // Open in vertical split
    HSplit,   // Open in horizontal split
    Tab       // Open in new tab
}
Defines how to open selected files.
Different key combinations in search mode can open files in different ways (e.g., Enter for replace, Ctrl+V for vsplit).

Search Algorithm

The search mode uses a hierarchical fuzzy matching algorithm:
  1. File Indexing: Asynchronously indexes all files in the directory
  2. Incremental Search: Builds a search tree as you type
  3. Fuzzy Matching: Matches characters in sequence, not necessarily adjacent
  4. Scoring: Ranks results by match quality
  5. Real-time Update: Updates results on every keystroke

Usage Example

Basic Search Setup

#include <zep/mode_search.h>
#include <zep/editor.h>
#include <zep/window.h>

// Create editor and window
auto editor = std::make_unique<ZepEditor>(display);
auto mainWindow = editor->GetActiveWindow();

// Create a dedicated search window
auto searchWindow = editor->AddWindow();
searchWindow->SetWindowFlags(WindowFlags::Modal);

// Initialize search mode
fs::path projectRoot = "/home/user/myproject";
auto searchMode = std::make_shared<ZepMode_Search>(
    *editor,
    *mainWindow,      // Return to this window after selection
    *searchWindow,    // Display results here
    projectRoot       // Search in this directory
);

// Activate search mode
searchMode->Begin(searchWindow);

// User types search query
searchMode->AddKeyPress('m');  // m
searchMode->AddKeyPress('a');  // ma
searchMode->AddKeyPress('i');  // mai
// Results update: main.cpp, main.h, email.cpp, etc.

// Navigate results with arrow keys
searchMode->AddKeyPress(ExtKeys::DOWN);
searchMode->AddKeyPress(ExtKeys::DOWN);

// Open selected file with Enter
searchMode->AddKeyPress(ExtKeys::RETURN);
// File opens in mainWindow, search mode exits

Opening Files in Different Ways

// Open in vertical split: Ctrl+V
searchMode->AddKeyPress('v', ModifierKey::Ctrl);

// Open in horizontal split: Ctrl+H
searchMode->AddKeyPress('h', ModifierKey::Ctrl);

// Open in new tab: Ctrl+T
searchMode->AddKeyPress('t', ModifierKey::Ctrl);

Custom Search Configuration

class MySearchMode : public ZepMode_Search
{
public:
    MySearchMode(
        ZepEditor& editor,
        ZepWindow& prevWin,
        ZepWindow& win,
        const fs::path& path
    ) : ZepMode_Search(editor, prevWin, win, path)
    {
        // Configure search
        ConfigureIgnorePatterns();
    }
    
private:
    void ConfigureIgnorePatterns()
    {
        // Customize which files to ignore
        m_ignorePatterns = {
            "*.o",
            "*.obj",
            ".git/*",
            "build/*",
            "node_modules/*",
            ".DS_Store"
        };
    }
    
    std::vector<std::string> m_ignorePatterns;
};

Integration Example

class ProjectNavigator
{
public:
    ProjectNavigator(ZepEditor& editor, const fs::path& projectRoot)
        : m_editor(editor)
        , m_projectRoot(projectRoot)
    {
    }
    
    void ActivateSearch()
    {
        // Get current window
        auto currentWindow = m_editor.GetActiveWindow();
        
        // Create modal search window
        auto searchWindow = CreateSearchWindow();
        
        // Create and activate search mode
        m_searchMode = std::make_shared<ZepMode_Search>(
            m_editor,
            *currentWindow,
            *searchWindow,
            m_projectRoot
        );
        
        m_searchMode->Begin(searchWindow);
        
        // Store previous mode to restore later
        m_previousMode = m_editor.GetCurrentMode();
    }
    
    void CancelSearch()
    {
        // Restore previous mode
        if (m_previousMode) {
            m_editor.SetMode(m_previousMode->Name());
        }
    }
    
private:
    ZepWindow* CreateSearchWindow()
    {
        // Create a centered, modal window for search
        auto window = m_editor.AddWindow();
        
        // Position at screen center
        NVec2f screenSize = m_editor.GetDisplay().GetScreenSize();
        NVec2f windowSize(screenSize.x * 0.6f, screenSize.y * 0.4f);
        NVec2f windowPos(
            (screenSize.x - windowSize.x) / 2,
            (screenSize.y - windowSize.y) / 2
        );
        
        window->SetWindowRect(NRectf(windowPos, windowSize));
        window->SetWindowFlags(WindowFlags::Modal | WindowFlags::Floating);
        
        return window;
    }
    
    ZepEditor& m_editor;
    fs::path m_projectRoot;
    std::shared_ptr<ZepMode_Search> m_searchMode;
    std::shared_ptr<ZepMode> m_previousMode;
};

// Usage
ProjectNavigator navigator(editor, "/home/user/project");

// Bind to Ctrl+P
if (key == 'p' && modifiers & ModifierKey::Ctrl) {
    navigator.ActivateSearch();
}

// Bind Escape to cancel
if (key == ExtKeys::ESCAPE && editor.GetCurrentMode()->Name() == "Search") {
    navigator.CancelSearch();
}

Search Features

Fuzzy Matching

Search supports fuzzy matching where characters don’t need to be adjacent:
  • Query: mah matches:
    • main.h (exact character sequence)
    • my_app_header.h (characters present in order)
    • manager.h (characters present)

Case Sensitivity

Search can be configured for case-sensitive or case-insensitive matching:
// Case-insensitive by default
m_caseImportant = false;

// Enable case-sensitive search
m_caseImportant = true;

Asynchronous Indexing

File indexing happens asynchronously using std::future:
// Indexing doesn't block the UI
std::future<std::shared_ptr<FileIndexResult>> m_indexResult;
std::future<std::shared_ptr<IndexSet>> m_searchResult;
Large projects with thousands of files remain responsive during indexing thanks to asynchronous processing.

Performance Considerations

  • Initial Indexing: First search in a directory indexes all files
  • Incremental Updates: Subsequent searches reuse the index
  • Result Limiting: Only top N results are displayed for performance
  • Thread Safety: Indexing runs on background threads

See Also

Build docs developers (and LLMs) love