Metadata-Version: 2.4
Name: denary
Version: 0.0.5
Summary: A curses-based text editor with syntax highlighting
License: MIT
License-File: LICENSE
Keywords: editor,tui,curses,syntax-highlighting,terminal
Author: Jordaly Suriel
Requires-Python: >=3.12,<3.15
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Requires-Dist: Pygments (>=2.20)
Requires-Dist: pathspec (>=1.0.4)
Requires-Dist: platformdirs (>=4.9.6)
Requires-Dist: windows-curses (>=2.4.2) ; sys_platform == "win32"
Project-URL: Homepage, https://gitlab.com/jordaly/editor
Project-URL: Repository, https://gitlab.com/jordaly/editor
Description-Content-Type: text/markdown


## Editor Documentation
```
 ,gggggggggggg,
dP"""88""""""Y8b,
Yb,  88       `8b,
 `"  88        `8b
     88         Y8
     88         d8  ,ggg,    ,ggg,,ggg,     ,gggg,gg   ,gggggg,  gg     gg
     88        ,8P i8" "8i  ,8" "8P" "8,   dP"  "Y8I   dP""""8I  I8     8I
     88       ,8P' I8, ,8I  I8   8I   8I  i8'    ,8I  ,8'    8I  I8,   ,8I
     88______,dP'  `YbadP' ,dP   8I   Yb,,d8,   ,d8b,,dP     Y8,,d8b, ,d8I
    888888888P"   888P"Y8888P'   8I   `Y8P"Y8888P"`Y88P      `Y8P""Y88P"888
                                                                      ,d8I'
                                                                    ,dP'8I
                                                                   ,8"  8I
                                                                   I8   8I
                                                                   `8, ,8I
                                                                    `Y8P"
```

A modal terminal editor built on curses with a command-driven,
event-based architecture and chunked text storage.

Includes syntax highlighting, multi-buffer management,
registers and markers, undo/redo history, Git integration,
async LSP support, subprocess execution, and HTTP requests.


## Installation

### Install via pip (Recommended)

If your package is published:

```bash
pip install denary
```

Then run:

```bash
denary
```

Or open a file directly:

```bash
denary main.py
```

---

### Install from Source

Clone the repository:

```bash
git clone https://gitlab.com/jordaly/editor.git denary
cd denary
```

Using **Poetry**:

```bash
poetry install
poetry run python -m denary
```

Or using plain pip:

```bash
pip install -e .
denary
```

### Recommended (Better): Alias That Runs Denary Directly

Instead of activating the venv every time, just point the alias to the venv’s binary.

Assume your venv is here:

```bash
~/venvs/denary_venv
```

Edit your `~/.bashrc`:

```bash
nano ~/.bashrc
```

Add this line:

```bash
alias denary="~/venvs/denary_venv/bin/denary"
```

Then reload:

```bash
source ~/.bashrc
```

Now you can run:

```bash
denary
denary myfile.py
```

## Quick Start

### Open a File

```bash
denary myfile.py
```

If the file does not exist, it will be created.

## Key Bindings

## Arrow & Basic Movement

| Shortcut       | Action                              |
| -------------- | ----------------------------------- |
| **Right**      | Move cursor right                   |
| **Left**       | Move cursor left                    |
| **Up**         | Move cursor up                      |
| **Down**       | Move cursor down                    |
| **PageUp**     | Page up                             |
| **PageDown**   | Page down                           |
| **Ctrl+Right** | Jump right (word/semantic move)     |
| **Ctrl+Left**  | Jump left (word/semantic move)      |
| **Ctrl+Up**    | Scroll / move up (mode dependent)   |
| **Ctrl+Down**  | Scroll / move down (mode dependent) |

---

## Vim-Style Normal Mode Navigation

| Shortcut  | Action                           |
| --------- | -------------------------------- |
| **h**     | Move left                        |
| **j**     | Move down                        |
| **k**     | Move up                          |
| **l**     | Move right                       |
| **0**     | Jump to start of line            |
| **$**     | Jump to end of line              |
| **w / W** | Move forward by word             |
| **b / B** | Move backward by word            |
| **e / E** | Move to end of word              |
| **f / F** | Find character forward/backward  |
| **g**     | Go command prefix                |
| **G**     | Go to bottom                     |
| **H**     | Jump to top of visible window    |
| **L**     | Jump to bottom of visible window |
| **%**     | Jump to matching bracket         |

---

## Insert & Editing (Normal Mode)

| Shortcut | Action                    |
| -------- | ------------------------- |
| **i**    | Enter insert mode         |
| **a**    | Append after cursor       |
| **A**    | Append at end of line     |
| **o**    | Insert new line below     |
| **O**    | Insert new line above     |
| **x**    | Delete character          |
| **d**    | Delete (operator)         |
| **c**    | Change (operator)         |
| **y**    | Yank (copy)               |
| **p**    | Paste after               |
| **P**    | Paste before              |
| **u**    | Undo                      |
| **U**    | Undo line / extended undo |
| **J**    | Join lines                |
| **>**    | Indent right              |
| **<**    | Indent left               |

---

## Search & Repeat

| Shortcut | Action                   |
| -------- | ------------------------ |
| **/**    | Search forward           |
| **n**    | Next match               |
| **N**    | Previous match           |
| *****    | Search word under cursor |

---

## Marks & Registers

| Shortcut | Action                          |
| -------- | ------------------------------- |
| **m**    | Set marker                      |
| **'**    | Jump to marker (linewise)       |
| **`**    | Jump to marker (exact position) |
| **@**    | Execute macro                   |
| **q**    | Start/stop macro recording      |

---

## LSP / Diagnostics (Normal Mode)

| Shortcut   | Action                      |
| ---------- | --------------------------- |
| **K**      | Show LSP hover / definition |
| **;**      | LSP-related navigation      |
| **Ctrl+D** | Diagnostics-related action  |

(Exact behavior depends on your handler implementations.)

---

## Alt-Based Commands

| Shortcut              | Action                      |
| --------------------- | --------------------------- |
| **Alt+;**             | Toggle selection mode       |
| **Alt+Right / Alt+.** | Indent right                |
| **Alt+Left / Alt+,**  | Indent left                 |
| **Alt+/**             | Alternative slash action    |
| **Alt+h / Alt+l**     | Alternative horizontal move |
| **Alt+j / Alt+k**     | Move lines or cursor        |
| **Alt+Up / Alt+Down** | Scroll view                 |
| **Alt+9 / Alt+0**     | Jump line start/end         |
| **Alt+w**             | File search                 |
| **Alt+r**             | Custom action               |
| **Alt+i / Alt+o**     | Punctuation jump            |
| **Alt+[**             | Bracket-related action      |
| **Alt+'**             | Quote-related action        |

---

## Shift Selection

| Shortcut             | Action                   |
| -------------------- | ------------------------ |
| **Shift+Right**      | Expand selection right   |
| **Shift+Left**       | Expand selection left    |
| **Shift+Up**         | Expand selection up      |
| **Shift+Down**       | Expand selection down    |
| **Ctrl+Shift+Right** | Expand selection by word |
| **Ctrl+Shift+Left**  | Expand selection by word |

---

## Misc

| Shortcut              | Action                    |
| --------------------- | ------------------------- |
| **Ctrl+A**            | Select all                |
| **Ctrl+P**            | Previous buffer           |
| **Ctrl+X**            | Cut / special action      |
| **Ctrl+O**            | Open file                 |
| **Ctrl+I**            | Jump forward in jump list |
| **Q**                 | Quit variant              |
| **PageUp / PageDown** | Scroll                    |

## Commands

### Buffer Actions

| Command                           | Description         |
| --------------------------------- | ------------------- |
| `h` / `help`                      | Show help           |
| `q`                               | Exit editor         |
| `w`                               | Save current buffer |
| `ls`                              | List open buffers   |
| `open`                            | Open a file         |
| `bufnew`                          | Create new buffer   |
| `nbuf` / `nextbuf` / `next` / `n` | Next buffer         |
| `pbuf` / `prevbuf` / `prev` / `p` | Previous buffer     |
| `delbuf` / `d`                    | Delete buffer       |
| `ff`                              | File search         |
| `ffr`                             | New file search     |
| `fb`                              | Buffer picker       |
| `ex`                              | File explorer       |

---

### UI & Behavior

| Command         | Description          |
| --------------- | -------------------- |
| `themes`        | Change editor theme  |
| `ln`            | Toggle line numbers  |
| `gch`           | Toggle Git highlight |
| `scrolloff <n>` | Set scroll offset    |

---

### Markers

| Command        | Description                   |
| -------------- | ----------------------------- |
| `m` / `marker` | Add local/global marker       |
| `pm`           | Pick marker                   |
| `dm`           | Delete markers in this buffer |
| `dgm`          | Delete global markers         |
| `dpm`          | Delete specific marker        |
| `dam`          | Delete all markers            |

---

### Text Utilities

| Command                          | Description        |
| -------------------------------- | ------------------ |
| `clear_registers`                | Reset registers    |
| `reset_h_matches`                | Reset highlighting |
| `replace`                        | Replace text       |
| `comment`                        | Toggle comment     |
| `upper` / `lower` / `capitalize` | Change case        |
| `filetype <type>`                | Set syntax mode    |

---

## Utilities

| Command                          | Description                                                       |
|----------------------------------|-------------------------------------------------------------------|
| `align`                          | Align text by a delimiter (e.g. `=`, `:`, `,`, `|`)               |
| `column_edit`                    | Insert, replace, or delete text within column ranges per line     |
| `date`                           | Copy date                                                         |
| `datetime`                       | Copy current date & time                                          |
| `file_path`                      | Copy current file path                                            |
| `json_format`                    | Format JSON in selection or entire file                           |
| `number_lines`                   | Add line numbers to each line                                     |
| `rejoin`                         | Split and rejoin selection or entire file using a delimiter       |
| `remove_empty_lines`             | Remove blank or whitespace-only lines                             |
| `reverse_lines`                  | Reverse the order of lines                                        |
| `shuffle_lines`                  | Randomly shuffle lines                                            |
| `slugify`                        | Convert text to URL-friendly slug format                          |
| `sort` / `sort_r`                | Sort selection or entire file by lines (normal or reverse)        |
| `trim` / `trim_l` / `trim_r`     | Trim whitespace (both, left, or right) per line                   |
| `unique_lines` / `dedup`         | Remove duplicate lines (keep first occurrence)                    |
| `uuid`                           | Copy random UUID                                                  |
| `wrap`                           | Wrap text to a specified width                                    |
| `json_format`                    | formats json with indentation                                     |

---

## Git Commands

| Command          | Description                           |
| ---------------- | ------------------------------------- |
| `git_status`     | Show Git status                       |
| `git_diff`       | Show diff                             |
| `git_commit_all` | Commit all                            |
| `git_blame`      | Show blame                            |
| `git_log`        | Show history                          |
| `git_refresh`    | Refresh state                         |
| `git_hunk`       | Show previous version of changed code |

---

## LSP Commands

| Command                         | Description                        |
| ------------------------------- | ---------------------------------- |
| `lsp_diagnostics`               | Show buffer diagnostics            |
| `lsp_hover`                     | Show hover info                    |
| `lsp_definition`                | Go to definition                   |
| `lsp_refresh`                   | Restart LSP for buffer             |
| `lsp_references`                | References picker                  |
| `lsp_line_diagnostics`          | Show diagnostics for current line  |
| `lsp_clear_diagnostics`         | Clear diagnostics                  |
| `lsp_clear_line_diag` / `clrld` | Clear diagnostics for current line |

---

## AI Commands

| Command             | Description                               |
| ------------------- | ----------------------------------------- |
| `ai`                | Send a custom instruction to the AI       |
| `ai_gen`            | Generate code at the cursor               |
| `ai_review`         | Review Git diff for issues                |
| `ai_commit_message` | Generate a commit message from Git diff   |
| `ai_get`            | Retrieve AI result at the cursor          |
| `ai_show`           | Show AI completion picker                 |
| `ai_remove`         | Cancel/remove AI completion at the cursor |
| `change_ai_model`   | Change the active AI model                |

---

## HTTP Request Execution

Select a block and run:

| Command                     | Description                        |
| --------------------------- | ---------------------------------- |
| `req`                       | Make http request                  |

### Request Format

```
<HTTP_METHOD> <URL>
<Header>: <Value>
<Header>: <Value>

<Optional Body>
```

### Examples

#### GET:

```
GET https://jsonplaceholder.typicode.com/todos/1
Accept: application/json
```

#### POST:

```
POST https://jsonplaceholder.typicode.com/posts
Content-Type: application/json

{
    "title": "Hello world",
    "body": "Testing request from editor",
    "userId": 1
}
```


## Regex Replacement

Perform regex-based find and replace in the current buffer.

| Command   | Description                    |
| --------- | ------------------------------ |
| `replace` | Run a regex search and replace |

---

## Capture Groups

Parentheses create **capture groups** that can be reused in the replacement.

| Syntax | Meaning      |
| ------ | ------------ |
| `\0`   | Entire match |
| `\1`   | First group  |
| `\2`   | Second group |
| `\3`   | Third group  |

Example

Find

```
(\w+)\s+(\w+)
```

Replace

```
\2 \1
```

Result

```
hello world → world hello
```

---

## Named Capture Groups

Groups can also be named.

```
(?P<name>pattern)
```

Named groups are referenced in the replacement using:

```
\g<name>
```

Example

Find

```
(?P<first>\w+)\s+(?P<last>\w+)
```

Replace

```
\g<last> \g<first>
```

Result

```
john doe → doe john
```

---

## Case Transformations

The replacement string supports case modifiers.

| Syntax | Effect                   |
| ------ | ------------------------ |
| `\U`   | Uppercase until `\E`     |
| `\L`   | Lowercase until `\E`     |
| `\u`   | Uppercase next character |
| `\l`   | Lowercase next character |
| `\E`   | End transformation       |

Example

Find

```
select
```

Replace

```
\U\0\E
```

Result

```
select → SELECT
```

---

## Word Boundaries

`\b` matches the boundary between a word and a non-word character.

Example

Find

```
\bselect\b
```

Matches

```
select
```

Does not match

```
selected
```

---

## Example: SQL Keyword Formatting

Find

```
\b(select|from|where|join|group\s+by|order\s+by)\b
```

Replace

```
\U\0\E
```

Result

```
select name from users where id = 1
↓
SELECT name FROM users WHERE id = 1
```

## Configuration

Denary loads its configuration from a platform-specific directory.

### Config Location

#### Linux

```
~/.config/denary/init.py
```

#### macOS

```
~/Library/Application Support/denary/init.py
```

#### Windows (WSL recommended)

```
~/.config/denary/init.py
```

If the file does not exist, create it manually.

Example:

```bash
mkdir -p ~/.config/denary
nano ~/.config/denary/init.py
```

---

### LSP Configuration

The `init.py` file allows you to:

* Configure Language Servers (LSPs)
* Map file extensions to language identifiers
* Provide custom initialization settings

Denary expects two dictionaries:

```python
LSP_CONFIG = {}
EXT_TO_LANG = {}
```

---

### Example Configuration

#### LSP_CONFIG

```python
LSP_CONFIG = {
    "python": {
        "cmd": [
            "/home/user/.config/denary/pylsp_venv/bin/python",
            "-m",
            "pylsp",
        ],
        "settings": {
            "pylsp": {
                "plugins": {
                    "flake8": {"enabled": True, "maxLineLength": 100},
                    "pyflakes": {"enabled": False},
                    "pycodestyle": {"enabled": False},
                }
            },
        },
    },

    "javascript": {
        "cmd": [
            "/home/user/.config/denary/ts_server/node_modules/.bin/typescript-language-server",
            "--stdio",
        ],
    },

    "c": {
        "cmd": [
            "/home/user/.config/denary/clangd_venv/bin/clangd",
            "--all-scopes-completion",
            "--clang-tidy",
            "--offset-encoding=utf-8",
        ],
    },

    "csharp": {
        "cmd": [
            "mono",
            "/home/user/.config/denary/omnisharp/OmniSharp.exe",
            "--languageserver",
        ],
    },

    "sql": {
        "cmd": [
            "/home/user/go/bin/sqls",
        ],
    },
}
```

---

### EXT_TO_LANG

This maps file extensions to language keys defined in `LSP_CONFIG`.

```python
EXT_TO_LANG = {
    ".py": "python",
    ".c": "c",
    ".h": "c",
    ".cpp": "c",
    ".js": "javascript",
    ".ts": "javascript",
    ".jsx": "javascript",
    ".tsx": "javascript",
    ".cs": "csharp",
    ".sql": "sql",
}
```

---

## How It Works

1. You open a file:

   ```
   denary main.py
   ```

2. Denary checks the file extension (`.py`)

3. It maps it using `EXT_TO_LANG`

4. It loads the corresponding LSP from `LSP_CONFIG`

5. The language server is started using the `cmd` array

---

## Recommended Structure for LSP Tools

It is recommended to keep all LSP-related tools inside:

```
~/.config/denary/
```

Example layout:

```
~/.config/denary/
├── init.py
├── pylsp_venv/
├── clangd_venv/
├── ts_server/
└── omnisharp/
```

This keeps your setup portable and isolated.

---

## Important Notes

* `cmd` must be a list (not a string)
* Paths must be absolute
* The language key in `EXT_TO_LANG` must exist in `LSP_CONFIG`
* If an extension is not mapped, no LSP will be started

