Midetor

Midetor

A terminal-based vim like Markdown editor with Obsidian-like features

midetor

Description

midetor (MY-EDITOR) is a terminal-based Vim-like Markdown editor designed to provide a highly customizable, Obsidian-like experience right in your terminal. It integrates tightly with markdown-scanner to provide lightning-fast SQLite-backed metadata management.

Powered by Ratatui and Crossterm, midetor now features embedded Lua scripting, allowing you to completely customize keybindings, write custom search providers, and build your own autocomplete snippets.

Trying it out

Go to this repo and run it inside Docker. You can pass -v to volume your folder if you want.

Why?

  • Do you want an nvim-like experience that doesn't break a few times a week? This editor is heavily self-contained.
  • You can just copy it on any device with a terminal and it will work out of the box.
  • You can use this website to render your data in a user-friendly interface.
  • It is fully extensible via Lua without needing to recompile the Rust source.
  • This editor serves as an advanced example of how you can work with markdown-scanner.

images/main.jpg

It can now render images (using backlinks) directly in the terminal! images/images-render-example.png

Features

  • Extensible Configuration: Write an init.lua file to define keymaps, macros, and UI behaviors.
  • Media Playback: Render local images in the terminal and play linked .mp3 audio files via VLC.
  • Advanced Editing: Vim-like Normal, Insert, Visual, and Command modes.
  • Virtual Text & UI: Inject custom text overlays into the editor buffer via Lua.
  • Knowledge Graph Support: Manage tags (#) and backlinks ([[) via a fast SQLite database.
  • Custom Search & Autocomplete: Program your own fuzzy finders and snippet expanders using Lua (@ trigger).

Requirements

  • Rust: Version 1.87.0 or higher.
  • Cargo: The Rust package manager.
  • markdown-scanner: Must be available in your system PATH to populate the database.
  • VLC (Optional): Required if you want to play audio backlinks from the editor.

Installation

  1. Install midetor: Copy the compiled binary to a directory in your PATH:

    cargo install --git https://github.com/andrenaP/midetor.git
    
  2. Install markdown-scanner: The editor requires this binary to process Markdown files and generate the database.

    cargo install --git https://github.com/andrenaP/markdown-scanner.git
    

Usage

Run the editor with the following command:

midetor <file_path> [base_dir] [music_folder]
  • <file_path>: Path to the Markdown file to edit (required).
  • [base_dir]: Base directory of the Obsidian vault (optional). Defaults to the Obsidian_valt_main_path env variable or the current working directory.
  • [music_folder]: Directory where .mp3 files are stored (optional). Defaults to the musik_folder env variable or the current working directory.

Examples

  • Edit a file using the default vault path:

    midetor notes.md
    
  • Edit a file with a specific vault directory and music folder:

    midetor notes.md /path/to/vault /path/to/music
    

Configuration & Lua Scripting

midetor reads an init.lua file from your current working directory on startup or from ~/,config/midetor/. This is where you configure all keybindings, custom macros, search logic, and snippet expansions.

The editor exposes a global editor object to Lua.

Mapping Keys

You can map keys for Normal (n) and Visual (v) modes. Use standard characters or angle brackets for special keys (e.g., <C-s>, <Esc>, <A-Up>).

-- Save file
editor:map("n", "<C-s>", function() editor:save() end)

-- Toggle File Tree
editor:map("n", "\\t", function() editor:toggle_file_tree() end)

-- Create a custom macro (Jump to end of line, add newline, enter insert mode)
editor:map("n", "o", function()
    editor:move("end")        
    editor:insert_text("\n")  
    editor:set_mode("insert") 
end)

Custom Autocomplete Snippets (@)

You can define dynamic snippets in Lua that trigger when you type @ in Insert mode. You must define two global functions: on_autocomplete and expand_autocomplete.

local snippets = {
    ["date"] = function() return os.date("%Y-%m-%d") end,
    ["file-name"] = function() return editor:get_current_file():match("^.+/(.+)$") end
}

function on_autocomplete(trigger, query)
    local results = {}
    if trigger == "@" then
        for key, _ in pairs(snippets) do
            if string.sub(key, 1, string.len(query)) == query then
                table.insert(results, key)
            end
        end
    end
    return results
end

function expand_autocomplete(trigger, suggestion)
    if trigger == "@" then
        local action = snippets[suggestion]
        if type(action) == "function" then return action() end
        if type(action) == "string" then return action end
    end
    return suggestion 
end

Custom Search Providers

You can build custom search interfaces directly in Lua by providing a search function and a selection callback.

_G.my_search_provider = function(query)
    -- Return a table of strings based on the query
    return {"apple", "banana", "cherry"}
end

_G.my_search_action = function(selected_item)
    editor:insert_text("Selected: " .. selected_item)
end

-- Bind it to a key
editor:map("n", "\\fs", function()
    editor:start_custom_search("my_search_provider", "my_search_action")
end)

Default Key Bindings (Provided via init.lua)

If you use the example init.lua, the following default bindings are active:

KeybindingModeAction
i / aNormalEnter Insert mode
v / <C-v>NormalEnter Visual / Visual Block mode
:NormalEnter Command mode (:w, :q, :wq)
<C-s> / <C-q>NormalSave file / Quit
u / <C-r>NormalUndo / Redo
\tNormalToggle File Tree
\ob / \otNormalSearch Backlinks / Search Tags
\fNormalSearch Files
\osNormalSearch via Custom SQL query
\if / \icNormalToggle Image Fullscreen / Clear Image
\sNormalStop audio playback
\wNormalToggle Read Mode (Line wrapping)
\ntNormalOpen Template picker
\ootNormalOpen Today's Daily Note

Note: The File Tree has its own bindings once opened (oc to sort by time, on to sort by name, y to copy, x to cut, p to paste, d to delete).

Database

The editor creates a SQLite database (markdown_data.db) in the base_dir to store metadata. The schema includes:

  • files: File paths and names.
  • tags: Unique tags.
  • file_tags: Mapping files to tags.
  • backlinks: Tracks [[backlinks]] between files.

The markdown-scanner tool runs automatically in the background to keep this database populated.

Environment Variables

  • OBSIDIAN_VAULT_PATH: Default base directory for the vault.
  • MUSIC_FOLDER: Default directory for audio/music playback.

License

This project is licensed under the GNU GENERAL PUBLIC LICENSE. See the LICENSE file for details.

Contact

For issues or questions, please open an issue on the repository.

Related

How to Install

  1. Download the ZIP or clone the repository
  2. Open the folder as a vault in Obsidian (File → Open Vault)
  3. Obsidian will prompt you to install required plugins

Stats

Stars

7

Forks

1

License

GPL-3.0

Last updated 1mo ago

Categories

Tags

markdown-editorrusttui