mui 0.2.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.rubocop_todo.yml +18 -10
- data/CHANGELOG.md +162 -0
- data/README.md +309 -6
- data/docs/_config.yml +56 -0
- data/docs/configuration.md +314 -0
- data/docs/getting-started.md +140 -0
- data/docs/index.md +55 -0
- data/docs/jobs.md +297 -0
- data/docs/keybindings.md +229 -0
- data/docs/plugins.md +285 -0
- data/docs/syntax-highlighting.md +155 -0
- data/lib/mui/color_manager.rb +140 -6
- data/lib/mui/color_scheme.rb +1 -0
- data/lib/mui/command_completer.rb +11 -2
- data/lib/mui/command_history.rb +89 -0
- data/lib/mui/command_line.rb +32 -2
- data/lib/mui/command_registry.rb +21 -2
- data/lib/mui/config.rb +3 -1
- data/lib/mui/editor.rb +90 -2
- data/lib/mui/floating_window.rb +53 -1
- data/lib/mui/handler_result.rb +13 -7
- data/lib/mui/highlighters/search_highlighter.rb +2 -1
- data/lib/mui/highlighters/syntax_highlighter.rb +4 -1
- data/lib/mui/insert_completion_state.rb +15 -2
- data/lib/mui/key_handler/base.rb +87 -0
- data/lib/mui/key_handler/command_mode.rb +68 -0
- data/lib/mui/key_handler/insert_mode.rb +10 -41
- data/lib/mui/key_handler/normal_mode.rb +24 -51
- data/lib/mui/key_handler/operators/paste_operator.rb +9 -3
- data/lib/mui/key_handler/search_mode.rb +10 -7
- data/lib/mui/key_handler/visual_mode.rb +15 -10
- data/lib/mui/key_notation_parser.rb +159 -0
- data/lib/mui/key_sequence.rb +67 -0
- data/lib/mui/key_sequence_buffer.rb +85 -0
- data/lib/mui/key_sequence_handler.rb +163 -0
- data/lib/mui/key_sequence_matcher.rb +79 -0
- data/lib/mui/line_renderer.rb +52 -1
- data/lib/mui/mode_manager.rb +3 -2
- data/lib/mui/screen.rb +30 -6
- data/lib/mui/search_state.rb +74 -27
- data/lib/mui/syntax/language_detector.rb +33 -1
- data/lib/mui/syntax/lexers/c_lexer.rb +2 -0
- data/lib/mui/syntax/lexers/css_lexer.rb +121 -0
- data/lib/mui/syntax/lexers/go_lexer.rb +207 -0
- data/lib/mui/syntax/lexers/html_lexer.rb +118 -0
- data/lib/mui/syntax/lexers/javascript_lexer.rb +219 -0
- data/lib/mui/syntax/lexers/markdown_lexer.rb +210 -0
- data/lib/mui/syntax/lexers/ruby_lexer.rb +3 -0
- data/lib/mui/syntax/lexers/rust_lexer.rb +150 -0
- data/lib/mui/syntax/lexers/typescript_lexer.rb +225 -0
- data/lib/mui/terminal_adapter/base.rb +21 -0
- data/lib/mui/terminal_adapter/curses.rb +37 -11
- data/lib/mui/themes/default.rb +263 -132
- data/lib/mui/version.rb +1 -1
- data/lib/mui/window.rb +105 -39
- data/lib/mui/window_manager.rb +7 -0
- data/lib/mui/wrap_cache.rb +40 -0
- data/lib/mui/wrap_helper.rb +84 -0
- data/lib/mui.rb +15 -0
- metadata +26 -3
data/docs/plugins.md
ADDED
|
@@ -0,0 +1,285 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Plugins
|
|
3
|
+
layout: default
|
|
4
|
+
nav_order: 5
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Plugins
|
|
8
|
+
{: .no_toc }
|
|
9
|
+
|
|
10
|
+
## Table of contents
|
|
11
|
+
{: .no_toc .text-delta }
|
|
12
|
+
|
|
13
|
+
1. TOC
|
|
14
|
+
{:toc}
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
## Overview
|
|
19
|
+
|
|
20
|
+
Mui's plugin system allows you to extend the editor's functionality using Ruby gems. Plugins can:
|
|
21
|
+
|
|
22
|
+
- Add custom commands
|
|
23
|
+
- Define key mappings
|
|
24
|
+
- React to events (autocmd)
|
|
25
|
+
- Integrate with external tools
|
|
26
|
+
- Add syntax highlighting
|
|
27
|
+
|
|
28
|
+
## Official Plugins
|
|
29
|
+
|
|
30
|
+
| Plugin | Description | Install |
|
|
31
|
+
|--------|-------------|---------|
|
|
32
|
+
| [mui-lsp](https://github.com/S-H-GAMELINKS/mui-lsp) | LSP support | `gem install mui-lsp` |
|
|
33
|
+
| [mui-git](https://github.com/S-H-GAMELINKS/mui-git) | Git integration | `gem install mui-git` |
|
|
34
|
+
| [mui-fzf](https://github.com/S-H-GAMELINKS/mui-fzf) | fzf integration | `gem install mui-fzf` |
|
|
35
|
+
|
|
36
|
+
## Using Plugins
|
|
37
|
+
|
|
38
|
+
### Loading Plugins
|
|
39
|
+
|
|
40
|
+
Add plugins to your `~/.muirc`:
|
|
41
|
+
|
|
42
|
+
```ruby
|
|
43
|
+
Mui.use "mui-lsp"
|
|
44
|
+
Mui.use "mui-git"
|
|
45
|
+
Mui.use "mui-fzf"
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Plugins are automatically installed via `bundler/inline` on first startup.
|
|
49
|
+
|
|
50
|
+
### LSP Configuration
|
|
51
|
+
|
|
52
|
+
Configure LSP servers with `Mui.lsp`:
|
|
53
|
+
|
|
54
|
+
```ruby
|
|
55
|
+
Mui.use "mui-lsp"
|
|
56
|
+
|
|
57
|
+
Mui.lsp do
|
|
58
|
+
# Use preset configuration
|
|
59
|
+
use :ruby
|
|
60
|
+
|
|
61
|
+
# Custom server configuration
|
|
62
|
+
server :typescript,
|
|
63
|
+
command: ["typescript-language-server", "--stdio"],
|
|
64
|
+
filetypes: ["typescript", "typescriptreact"]
|
|
65
|
+
end
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
---
|
|
69
|
+
|
|
70
|
+
## Creating Plugins
|
|
71
|
+
|
|
72
|
+
### Class-based Plugin
|
|
73
|
+
|
|
74
|
+
```ruby
|
|
75
|
+
class MyPlugin < Mui::Plugin
|
|
76
|
+
name :my_plugin
|
|
77
|
+
version "1.0.0"
|
|
78
|
+
description "My awesome plugin"
|
|
79
|
+
|
|
80
|
+
# Optional: declare dependencies
|
|
81
|
+
depends_on :other_plugin
|
|
82
|
+
|
|
83
|
+
def setup
|
|
84
|
+
# Define commands, keymaps, autocmds here
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### DSL-based Plugin
|
|
90
|
+
|
|
91
|
+
```ruby
|
|
92
|
+
Mui.define_plugin(:my_plugin) do
|
|
93
|
+
# Define commands, keymaps, autocmds here
|
|
94
|
+
end
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
---
|
|
98
|
+
|
|
99
|
+
## Plugin API
|
|
100
|
+
|
|
101
|
+
### Commands
|
|
102
|
+
|
|
103
|
+
```ruby
|
|
104
|
+
def setup
|
|
105
|
+
command :greet do |ctx|
|
|
106
|
+
ctx.set_message("Hello!")
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
command :greet_name do |ctx, name|
|
|
110
|
+
ctx.set_message("Hello, #{name}!")
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
### Key Mappings
|
|
116
|
+
|
|
117
|
+
```ruby
|
|
118
|
+
def setup
|
|
119
|
+
# Normal mode mapping
|
|
120
|
+
keymap :normal, "<Leader>g" do |ctx|
|
|
121
|
+
ctx.editor.execute_command("greet")
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
# Insert mode mapping
|
|
125
|
+
keymap :insert, "<C-g>" do |ctx|
|
|
126
|
+
ctx.insert_text("Generated text")
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
# Multi-key sequence
|
|
130
|
+
keymap :normal, "<Leader>gg" do |ctx|
|
|
131
|
+
ctx.set_message("Leader g g pressed!")
|
|
132
|
+
end
|
|
133
|
+
end
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
### Autocmd Events
|
|
137
|
+
|
|
138
|
+
```ruby
|
|
139
|
+
def setup
|
|
140
|
+
autocmd :BufEnter, pattern: "*.rb" do |ctx|
|
|
141
|
+
ctx.set_message("Opened Ruby file: #{ctx.buffer.file_path}")
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
autocmd :BufWritePre do |ctx|
|
|
145
|
+
# Run before every file save
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
autocmd :InsertLeave do |ctx|
|
|
149
|
+
# Run when leaving insert mode
|
|
150
|
+
end
|
|
151
|
+
end
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
---
|
|
155
|
+
|
|
156
|
+
## CommandContext API
|
|
157
|
+
|
|
158
|
+
The `ctx` object passed to handlers provides access to editor internals:
|
|
159
|
+
|
|
160
|
+
### Messages
|
|
161
|
+
|
|
162
|
+
```ruby
|
|
163
|
+
ctx.set_message("Info message")
|
|
164
|
+
ctx.set_error("Error message")
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
### Editor Access
|
|
168
|
+
|
|
169
|
+
```ruby
|
|
170
|
+
ctx.editor # Editor instance
|
|
171
|
+
ctx.buffer # Current buffer
|
|
172
|
+
ctx.window # Current window
|
|
173
|
+
ctx.mode # Current mode (:normal, :insert, etc.)
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
### Mode Control
|
|
177
|
+
|
|
178
|
+
```ruby
|
|
179
|
+
ctx.change_mode(:normal)
|
|
180
|
+
ctx.change_mode(:insert)
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
### Text Manipulation
|
|
184
|
+
|
|
185
|
+
```ruby
|
|
186
|
+
ctx.insert_text("text") # Insert at cursor
|
|
187
|
+
ctx.buffer.lines # Get all lines
|
|
188
|
+
ctx.buffer.line(n) # Get line n
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
### Cursor
|
|
192
|
+
|
|
193
|
+
```ruby
|
|
194
|
+
ctx.cursor_row # Current row (0-indexed)
|
|
195
|
+
ctx.cursor_col # Current column (0-indexed)
|
|
196
|
+
ctx.move_cursor(row, col) # Move cursor
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
### File Operations
|
|
200
|
+
|
|
201
|
+
```ruby
|
|
202
|
+
ctx.buffer.file_path # Current file path
|
|
203
|
+
ctx.buffer.modified? # Has unsaved changes?
|
|
204
|
+
ctx.editor.execute_command("w") # Save file
|
|
205
|
+
ctx.editor.execute_command("e filename") # Open file
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
### Scratch Buffers
|
|
209
|
+
|
|
210
|
+
```ruby
|
|
211
|
+
ctx.open_scratch_buffer("[Results]", "Content here")
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
### Jobs
|
|
215
|
+
|
|
216
|
+
See [Jobs]({{ site.baseurl }}/jobs) for async job execution.
|
|
217
|
+
|
|
218
|
+
### Interactive Commands
|
|
219
|
+
|
|
220
|
+
```ruby
|
|
221
|
+
if ctx.command_exists?("fzf")
|
|
222
|
+
result = ctx.run_interactive_command("fzf")
|
|
223
|
+
ctx.editor.execute_command("e #{result}") if result
|
|
224
|
+
end
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
---
|
|
228
|
+
|
|
229
|
+
## Publishing Plugins
|
|
230
|
+
|
|
231
|
+
### Gem Structure
|
|
232
|
+
|
|
233
|
+
```
|
|
234
|
+
mui-myplugin/
|
|
235
|
+
├── lib/
|
|
236
|
+
│ └── mui_myplugin.rb
|
|
237
|
+
├── mui-myplugin.gemspec
|
|
238
|
+
└── README.md
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
### Gemspec
|
|
242
|
+
|
|
243
|
+
```ruby
|
|
244
|
+
Gem::Specification.new do |spec|
|
|
245
|
+
spec.name = "mui-myplugin"
|
|
246
|
+
spec.version = "1.0.0"
|
|
247
|
+
spec.summary = "My Mui plugin"
|
|
248
|
+
spec.files = Dir["lib/**/*.rb"]
|
|
249
|
+
spec.require_paths = ["lib"]
|
|
250
|
+
|
|
251
|
+
spec.add_dependency "mui", ">= 0.2.0"
|
|
252
|
+
end
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
### Plugin File
|
|
256
|
+
|
|
257
|
+
```ruby
|
|
258
|
+
# lib/mui_myplugin.rb
|
|
259
|
+
require "mui"
|
|
260
|
+
|
|
261
|
+
class MuiMyplugin < Mui::Plugin
|
|
262
|
+
name :myplugin
|
|
263
|
+
version "1.0.0"
|
|
264
|
+
|
|
265
|
+
def setup
|
|
266
|
+
command :my_command do |ctx|
|
|
267
|
+
ctx.set_message("Hello from myplugin!")
|
|
268
|
+
end
|
|
269
|
+
end
|
|
270
|
+
end
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
### Publishing
|
|
274
|
+
|
|
275
|
+
```bash
|
|
276
|
+
gem build mui-myplugin.gemspec
|
|
277
|
+
gem push mui-myplugin-1.0.0.gem
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
Users can then install with:
|
|
281
|
+
|
|
282
|
+
```ruby
|
|
283
|
+
# ~/.muirc
|
|
284
|
+
Mui.use "mui-myplugin"
|
|
285
|
+
```
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Syntax Highlighting
|
|
3
|
+
layout: default
|
|
4
|
+
nav_order: 7
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Syntax Highlighting
|
|
8
|
+
{: .no_toc }
|
|
9
|
+
|
|
10
|
+
## Table of contents
|
|
11
|
+
{: .no_toc .text-delta }
|
|
12
|
+
|
|
13
|
+
1. TOC
|
|
14
|
+
{:toc}
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
## Overview
|
|
19
|
+
|
|
20
|
+
Mui includes built-in syntax highlighting for 9 programming languages. Highlighting is automatic based on file extension.
|
|
21
|
+
|
|
22
|
+
## Supported Languages
|
|
23
|
+
|
|
24
|
+
| Language | Extensions |
|
|
25
|
+
|----------|------------|
|
|
26
|
+
| Ruby | `.rb`, `.rake`, `.gemspec` |
|
|
27
|
+
| C | `.c`, `.h`, `.y` |
|
|
28
|
+
| Go | `.go` |
|
|
29
|
+
| Rust | `.rs` |
|
|
30
|
+
| JavaScript | `.js`, `.mjs`, `.cjs`, `.jsx` |
|
|
31
|
+
| TypeScript | `.ts`, `.tsx`, `.mts`, `.cts` |
|
|
32
|
+
| Markdown | `.md`, `.markdown` |
|
|
33
|
+
| HTML | `.html`, `.htm`, `.xhtml` |
|
|
34
|
+
| CSS | `.css`, `.scss`, `.sass` |
|
|
35
|
+
|
|
36
|
+
## Configuration
|
|
37
|
+
|
|
38
|
+
### Enable/Disable
|
|
39
|
+
|
|
40
|
+
```ruby
|
|
41
|
+
# ~/.muirc
|
|
42
|
+
Mui.set :syntax, true # Enable (default)
|
|
43
|
+
Mui.set :syntax, false # Disable
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## Language Features
|
|
47
|
+
|
|
48
|
+
### Ruby
|
|
49
|
+
|
|
50
|
+
- Keywords (`def`, `class`, `module`, `if`, `end`, etc.)
|
|
51
|
+
- Strings (single, double, heredoc)
|
|
52
|
+
- Comments (`#`, `=begin`/`=end`)
|
|
53
|
+
- Numbers
|
|
54
|
+
- Symbols (`:symbol`)
|
|
55
|
+
- Constants (`CONSTANT`, `ClassName`)
|
|
56
|
+
- Instance variables (`@foo`, `@@bar`)
|
|
57
|
+
- Global variables (`$stdout`)
|
|
58
|
+
- Method calls (`.to_s`, `.each`)
|
|
59
|
+
|
|
60
|
+
### C
|
|
61
|
+
|
|
62
|
+
- Keywords (`int`, `char`, `struct`, `if`, `for`, etc.)
|
|
63
|
+
- Strings and character literals
|
|
64
|
+
- Comments (`//`, `/* */`)
|
|
65
|
+
- Numbers
|
|
66
|
+
- Preprocessor directives (`#include`, `#define`)
|
|
67
|
+
|
|
68
|
+
### Go
|
|
69
|
+
|
|
70
|
+
- Keywords (`func`, `package`, `import`, `go`, `defer`, etc.)
|
|
71
|
+
- Types (`int`, `string`, `bool`, etc.)
|
|
72
|
+
- Constants (`true`, `false`, `nil`, `iota`)
|
|
73
|
+
- Strings (regular and raw backtick strings)
|
|
74
|
+
- Comments (`//`, `/* */`)
|
|
75
|
+
|
|
76
|
+
### Rust
|
|
77
|
+
|
|
78
|
+
- Keywords (`fn`, `let`, `mut`, `impl`, `trait`, etc.)
|
|
79
|
+
- Macros (`println!`, `vec!`)
|
|
80
|
+
- Lifetimes (`'a`, `'static`)
|
|
81
|
+
- Attributes (`#[derive]`, `#[cfg]`)
|
|
82
|
+
- Doc comments (`///`, `//!`)
|
|
83
|
+
- Raw strings (`r#"..."#`)
|
|
84
|
+
|
|
85
|
+
### JavaScript
|
|
86
|
+
|
|
87
|
+
- ES6+ keywords (`const`, `let`, `async`, `await`, `class`)
|
|
88
|
+
- Template literals (`` `template ${expr}` ``)
|
|
89
|
+
- Regex literals (`/pattern/flags`)
|
|
90
|
+
- BigInt (`123n`)
|
|
91
|
+
- Strings and comments
|
|
92
|
+
|
|
93
|
+
### TypeScript
|
|
94
|
+
|
|
95
|
+
All JavaScript features plus:
|
|
96
|
+
- Type keywords (`interface`, `type`, `enum`, `declare`, `abstract`)
|
|
97
|
+
- Type annotations
|
|
98
|
+
|
|
99
|
+
### Markdown
|
|
100
|
+
|
|
101
|
+
- Headings (`#`, `##`, etc.)
|
|
102
|
+
- Emphasis (`*italic*`, `**bold**`)
|
|
103
|
+
- Code blocks (fenced and indented)
|
|
104
|
+
- Links (`[text](url)`)
|
|
105
|
+
- Lists (ordered and unordered)
|
|
106
|
+
- Blockquotes (`>`)
|
|
107
|
+
|
|
108
|
+
### HTML
|
|
109
|
+
|
|
110
|
+
- Tags (`<div>`, `</div>`, `<br/>`)
|
|
111
|
+
- Attributes (`class="..."`, `id="..."`)
|
|
112
|
+
- Comments (`<!-- -->`)
|
|
113
|
+
- DOCTYPE
|
|
114
|
+
- Entities (`&`, `<`)
|
|
115
|
+
|
|
116
|
+
### CSS
|
|
117
|
+
|
|
118
|
+
- Selectors (`.class`, `#id`, `:pseudo`, `::pseudo-element`)
|
|
119
|
+
- Properties and values
|
|
120
|
+
- Hex colors (`#fff`, `#ffffff`)
|
|
121
|
+
- At-rules (`@media`, `@import`, `@keyframes`)
|
|
122
|
+
- Functions (`calc()`, `rgb()`, `var()`)
|
|
123
|
+
|
|
124
|
+
## Theme Colors
|
|
125
|
+
|
|
126
|
+
Syntax colors are defined per theme. All 8 built-in themes include syntax highlighting colors:
|
|
127
|
+
|
|
128
|
+
- `mui` (default)
|
|
129
|
+
- `solarized_dark`
|
|
130
|
+
- `solarized_light`
|
|
131
|
+
- `monokai`
|
|
132
|
+
- `nord`
|
|
133
|
+
- `gruvbox_dark`
|
|
134
|
+
- `dracula`
|
|
135
|
+
- `tokyo_night`
|
|
136
|
+
|
|
137
|
+
Each theme defines colors for:
|
|
138
|
+
|
|
139
|
+
| Element | Description |
|
|
140
|
+
|---------|-------------|
|
|
141
|
+
| `syntax_keyword` | Language keywords |
|
|
142
|
+
| `syntax_string` | String literals |
|
|
143
|
+
| `syntax_comment` | Comments |
|
|
144
|
+
| `syntax_number` | Numeric literals |
|
|
145
|
+
| `syntax_type` | Types and classes |
|
|
146
|
+
| `syntax_function` | Function names |
|
|
147
|
+
| `syntax_function_definition` | Function definition names |
|
|
148
|
+
| `syntax_variable` | Variables |
|
|
149
|
+
| `syntax_constant` | Constants |
|
|
150
|
+
| `syntax_operator` | Operators |
|
|
151
|
+
| `diagnostic_error` | LSP diagnostic errors |
|
|
152
|
+
| `diagnostic_warning` | LSP diagnostic warnings |
|
|
153
|
+
| `diagnostic_info` | LSP diagnostic information |
|
|
154
|
+
| `diagnostic_hint` | LSP diagnostic hints |
|
|
155
|
+
| `floating_window` | Floating window background |
|
data/lib/mui/color_manager.rb
CHANGED
|
@@ -17,8 +17,27 @@ module Mui
|
|
|
17
17
|
# 256-color palette extended colors
|
|
18
18
|
# Use https://www.ditig.com/256-colors-cheat-sheet for reference
|
|
19
19
|
EXTENDED_COLOR_MAP = {
|
|
20
|
-
# mui theme
|
|
21
|
-
|
|
20
|
+
# mui theme - Eye-friendly gray-based theme
|
|
21
|
+
mui_bg: 236, # #303030 - Calm dark gray background
|
|
22
|
+
mui_fg: 253, # #dadada - Soft white (easy on the eyes)
|
|
23
|
+
mui_comment: 102, # #878787 - Subtle gray (for comments)
|
|
24
|
+
mui_constant: 110, # #87afd7 - Calm blue (constants/strings/numbers)
|
|
25
|
+
mui_identifier: 174, # #d78787 - Soft salmon pink
|
|
26
|
+
mui_statement: 186, # #d7d787 - Subtle yellow (keywords)
|
|
27
|
+
mui_preproc: 173, # #d7875f - Orange/brown (preprocessor)
|
|
28
|
+
mui_type: 109, # #87afaf - Calm cyan (types)
|
|
29
|
+
mui_special: 180, # #d7af87 - Soft beige (symbols)
|
|
30
|
+
mui_function: 216, # #ffaf87 - Peach/orange (functions)
|
|
31
|
+
# UI colors
|
|
32
|
+
mui_line_number: 243, # #767676 - Subtle gray
|
|
33
|
+
mui_status_bg: 238, # #444444 - Status bar background
|
|
34
|
+
mui_visual: 239, # #4e4e4e - Selection background
|
|
35
|
+
mui_search: 222, # #ffd787 - Search highlight (prominent yellow)
|
|
36
|
+
mui_tab_bg: 237, # #3a3a3a - Tab bar background
|
|
37
|
+
mui_tab_active: 110, # #87afd7 - Active tab
|
|
38
|
+
mui_error: 167, # #d75f5f - Error messages
|
|
39
|
+
mui_info: 109, # #87afaf - Info messages
|
|
40
|
+
darkgray: 235, # #262626 (~#2b2b2b) - Kept for backward compatibility
|
|
22
41
|
|
|
23
42
|
# solarized
|
|
24
43
|
solarized_base03: 234, # #1c1c1c (~#002b36)
|
|
@@ -41,6 +60,7 @@ module Mui
|
|
|
41
60
|
# monokai
|
|
42
61
|
monokai_bg: 235, # #262626 (~#272822)
|
|
43
62
|
monokai_fg: 231, # #ffffff (~#f8f8f2)
|
|
63
|
+
monokai_comment: 101, # #87875f (~#75715e) - Olive gray for comments
|
|
44
64
|
monokai_pink: 197, # #ff005f (~#f92672)
|
|
45
65
|
monokai_green: 148, # #afd700 (~#a6e22e)
|
|
46
66
|
monokai_orange: 208, # #ff8700 (~#fd971f)
|
|
@@ -104,18 +124,95 @@ module Mui
|
|
|
104
124
|
tokyo_yellow: 223 # #ffd7af (~#e0af68)
|
|
105
125
|
}.freeze
|
|
106
126
|
|
|
107
|
-
|
|
127
|
+
# Fallback map: 256-color to 8-color
|
|
128
|
+
FALLBACK_MAP = {
|
|
129
|
+
# mui theme
|
|
130
|
+
mui_bg: :black,
|
|
131
|
+
mui_fg: :white,
|
|
132
|
+
mui_comment: :white,
|
|
133
|
+
mui_constant: :cyan,
|
|
134
|
+
mui_identifier: :red,
|
|
135
|
+
mui_statement: :yellow,
|
|
136
|
+
mui_preproc: :yellow,
|
|
137
|
+
mui_type: :cyan,
|
|
138
|
+
mui_special: :yellow,
|
|
139
|
+
mui_function: :yellow,
|
|
140
|
+
mui_line_number: :white,
|
|
141
|
+
mui_status_bg: :blue,
|
|
142
|
+
mui_visual: :magenta,
|
|
143
|
+
mui_search: :yellow,
|
|
144
|
+
mui_tab_bg: :blue,
|
|
145
|
+
mui_tab_active: :cyan,
|
|
146
|
+
mui_error: :red,
|
|
147
|
+
mui_info: :cyan,
|
|
148
|
+
darkgray: :black,
|
|
149
|
+
# solarized
|
|
150
|
+
solarized_base03: :black, solarized_base02: :black,
|
|
151
|
+
solarized_base01: :white, solarized_base00: :white,
|
|
152
|
+
solarized_base0: :white, solarized_base1: :white,
|
|
153
|
+
solarized_base2: :white, solarized_base3: :white,
|
|
154
|
+
solarized_yellow: :yellow, solarized_orange: :red,
|
|
155
|
+
solarized_red: :red, solarized_magenta: :magenta,
|
|
156
|
+
solarized_violet: :blue, solarized_blue: :blue,
|
|
157
|
+
solarized_cyan: :cyan, solarized_green: :green,
|
|
158
|
+
# monokai
|
|
159
|
+
monokai_bg: :black, monokai_fg: :white, monokai_comment: :white,
|
|
160
|
+
monokai_pink: :magenta, monokai_green: :green,
|
|
161
|
+
monokai_orange: :yellow, monokai_purple: :magenta,
|
|
162
|
+
monokai_cyan: :cyan, monokai_yellow: :yellow,
|
|
163
|
+
# nord
|
|
164
|
+
nord_polar0: :black, nord_polar1: :black,
|
|
165
|
+
nord_polar2: :black, nord_polar3: :white,
|
|
166
|
+
nord_snow0: :white, nord_snow1: :white, nord_snow2: :white,
|
|
167
|
+
nord_frost0: :cyan, nord_frost1: :cyan,
|
|
168
|
+
nord_frost2: :blue, nord_frost3: :blue,
|
|
169
|
+
nord_aurora_red: :red, nord_aurora_orange: :yellow,
|
|
170
|
+
nord_aurora_yellow: :yellow, nord_aurora_green: :green,
|
|
171
|
+
nord_aurora_purple: :magenta,
|
|
172
|
+
# gruvbox
|
|
173
|
+
gruvbox_bg: :black, gruvbox_fg: :white,
|
|
174
|
+
gruvbox_red: :red, gruvbox_green: :green,
|
|
175
|
+
gruvbox_yellow: :yellow, gruvbox_blue: :blue,
|
|
176
|
+
gruvbox_purple: :magenta, gruvbox_aqua: :cyan,
|
|
177
|
+
gruvbox_orange: :yellow, gruvbox_gray: :white,
|
|
178
|
+
# dracula
|
|
179
|
+
dracula_bg: :black, dracula_fg: :white,
|
|
180
|
+
dracula_selection: :black, dracula_comment: :blue,
|
|
181
|
+
dracula_cyan: :cyan, dracula_green: :green,
|
|
182
|
+
dracula_orange: :yellow, dracula_pink: :magenta,
|
|
183
|
+
dracula_purple: :magenta, dracula_red: :red,
|
|
184
|
+
dracula_yellow: :yellow,
|
|
185
|
+
# tokyo night
|
|
186
|
+
tokyo_bg: :black, tokyo_fg: :white,
|
|
187
|
+
tokyo_comment: :blue, tokyo_cyan: :cyan,
|
|
188
|
+
tokyo_blue: :blue, tokyo_purple: :magenta,
|
|
189
|
+
tokyo_green: :green, tokyo_orange: :yellow,
|
|
190
|
+
tokyo_red: :red, tokyo_yellow: :yellow
|
|
191
|
+
}.freeze
|
|
108
192
|
|
|
109
|
-
|
|
193
|
+
attr_reader :pairs, :supports_256_colors
|
|
194
|
+
|
|
195
|
+
def initialize(adapter: nil)
|
|
110
196
|
@pair_index = 1
|
|
111
197
|
@pairs = {}
|
|
198
|
+
@pair_order = []
|
|
199
|
+
@adapter = adapter
|
|
200
|
+
configure_color_capability
|
|
112
201
|
end
|
|
113
202
|
|
|
114
203
|
def register_pair(fg, bg)
|
|
115
204
|
key = [fg, bg]
|
|
116
|
-
|
|
205
|
+
|
|
206
|
+
if @pairs[key]
|
|
207
|
+
touch_pair(key)
|
|
208
|
+
return @pairs[key]
|
|
209
|
+
end
|
|
210
|
+
|
|
211
|
+
# Check pair limit and evict oldest if needed
|
|
212
|
+
evict_oldest_pair if @max_pairs.positive? && @pair_index >= @max_pairs
|
|
117
213
|
|
|
118
214
|
@pairs[key] = @pair_index
|
|
215
|
+
@pair_order << key
|
|
119
216
|
@pair_index += 1
|
|
120
217
|
@pairs[key]
|
|
121
218
|
end
|
|
@@ -128,9 +225,46 @@ module Mui
|
|
|
128
225
|
return -1 if color.nil?
|
|
129
226
|
return color if color.is_a?(Integer)
|
|
130
227
|
|
|
131
|
-
|
|
228
|
+
resolved_color = resolve_with_fallback(color)
|
|
229
|
+
COLOR_MAP[resolved_color] || EXTENDED_COLOR_MAP[resolved_color] || -1
|
|
132
230
|
end
|
|
133
231
|
|
|
134
232
|
alias resolve color_code
|
|
233
|
+
|
|
234
|
+
private
|
|
235
|
+
|
|
236
|
+
def configure_color_capability
|
|
237
|
+
if @adapter.nil?
|
|
238
|
+
# Backward compatibility: assume 256 colors when adapter is not specified
|
|
239
|
+
@available_colors = 256
|
|
240
|
+
@max_pairs = 256
|
|
241
|
+
@supports_256_colors = true
|
|
242
|
+
elsif @adapter.has_colors?
|
|
243
|
+
@available_colors = @adapter.colors
|
|
244
|
+
@max_pairs = [@adapter.color_pairs, 256].min
|
|
245
|
+
@supports_256_colors = @available_colors >= 256
|
|
246
|
+
else
|
|
247
|
+
@available_colors = 0
|
|
248
|
+
@max_pairs = 0
|
|
249
|
+
@supports_256_colors = false
|
|
250
|
+
end
|
|
251
|
+
end
|
|
252
|
+
|
|
253
|
+
def resolve_with_fallback(color)
|
|
254
|
+
return color if @supports_256_colors
|
|
255
|
+
return color if COLOR_MAP.key?(color)
|
|
256
|
+
|
|
257
|
+
FALLBACK_MAP[color] || :white
|
|
258
|
+
end
|
|
259
|
+
|
|
260
|
+
def touch_pair(key)
|
|
261
|
+
@pair_order.delete(key)
|
|
262
|
+
@pair_order << key
|
|
263
|
+
end
|
|
264
|
+
|
|
265
|
+
def evict_oldest_pair
|
|
266
|
+
oldest_key = @pair_order.shift
|
|
267
|
+
@pairs.delete(oldest_key) if oldest_key
|
|
268
|
+
end
|
|
135
269
|
end
|
|
136
270
|
end
|
data/lib/mui/color_scheme.rb
CHANGED
|
@@ -13,9 +13,18 @@ module Mui
|
|
|
13
13
|
].freeze
|
|
14
14
|
|
|
15
15
|
def complete(prefix)
|
|
16
|
-
|
|
16
|
+
all_commands = COMMANDS + plugin_command_names
|
|
17
17
|
|
|
18
|
-
|
|
18
|
+
return all_commands.uniq.sort if prefix.empty?
|
|
19
|
+
|
|
20
|
+
prefix_downcase = prefix.downcase
|
|
21
|
+
all_commands.select { |cmd| cmd.downcase.start_with?(prefix_downcase) }.uniq.sort
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
private
|
|
25
|
+
|
|
26
|
+
def plugin_command_names
|
|
27
|
+
Mui.config.commands.keys.map(&:to_s)
|
|
19
28
|
end
|
|
20
29
|
end
|
|
21
30
|
end
|