12 Commits

Author SHA1 Message Date
f93afc0d14 Make binary portable and other fixes 2026-01-31 10:25:39 +00:00
86d5b7a021 Fix dependancies and precompile ruby module 2026-01-29 23:21:47 +00:00
78949bc770 Remove unneccesary dependancy
Signed-off-by: Syed Daanish <me@syedm.dev>
2026-01-29 15:00:57 +00:00
17a04bdddc Fix url 2026-01-29 13:59:55 +00:00
eafed64bea Use embedded mruby for portablity 2026-01-29 13:52:46 +00:00
9757a8db31 Fix installation stuff 2026-01-28 23:16:59 +00:00
cef357ffdc Fixes 2026-01-28 22:19:32 +00:00
515d5559a7 Allow ruby versions 3.2 and 3.4 for installation 2026-01-28 22:12:37 +00:00
1312c09501 Fix bug 2026-01-28 19:01:45 +00:00
b018877c03 Cleanup 2026-01-28 19:00:34 +00:00
e6f51d69b6 Add installer script 2026-01-28 18:57:23 +00:00
6abdefa808 Cleanup and minor Fixes 2026-01-28 18:46:44 +00:00
45 changed files with 1693 additions and 892 deletions

View File

@@ -1,7 +1,8 @@
CompileFlags: CompileFlags:
Add: [-I/home/syed/main/crib/include, -I/home/syed/main/crib/libs, -I/usr/include/ruby-3.4.0, -I/usr/include/ruby-3.4.0/x86_64-linux, c++20] Add: [
-I/home/syed/main/crib/include,
-I/home/syed/main/crib/libs,
-std=c++23
]
Remove: [] Remove: []
Compiler: clang++ Compiler: clang++
HeaderInsertion:
Policy: Never

2
.gitattributes vendored
View File

@@ -1 +1 @@
/libs/unicode_width/** linguist-vendored /libs/** linguist-vendored

3
.gitignore vendored
View File

@@ -3,6 +3,7 @@
*.a *.a
*.o *.o
*.so *.so
!libs/libruby/libruby.so
*.yml *.yml
.vscode .vscode
@@ -13,5 +14,7 @@ build
bin bin
.thinlto-cache/ .thinlto-cache/
Gemfile*
.ruby-lsp/
__old__ __old__

4
.gitmodules vendored
View File

@@ -2,7 +2,3 @@
path = libs/libgrapheme path = libs/libgrapheme
url = git://git.suckless.org/libgrapheme url = git://git.suckless.org/libgrapheme
ignore = dirty ignore = dirty
[submodule "libs/utfcpp"]
path = libs/utfcpp
url = https://github.com/nemtrif/utfcpp.git
ignore = dirty

View File

@@ -9,27 +9,30 @@ TARGET_RELEASE := $(BIN_DIR)/crib
PCH_DEBUG := $(OBJ_DIR)/debug/pch.h.gch PCH_DEBUG := $(OBJ_DIR)/debug/pch.h.gch
PCH_RELEASE := $(OBJ_DIR)/release/pch.h.gch PCH_RELEASE := $(OBJ_DIR)/release/pch.h.gch
GENERATED_HEADER := $(INCLUDE_DIR)/scripting/ruby_compiled.h
CCACHE := ccache CCACHE := ccache
CXX := $(CCACHE) clang++ CXX := $(CCACHE) clang++
CC := $(CCACHE) musl-clang
CFLAGS_DEBUG :=\ CFLAGS_DEBUG :=\
-std=c++20 -Wall -Wextra \ -std=c++20 -Wall -Wextra \
-O0 -fno-inline -gsplit-dwarf \ -O0 -fno-inline -gsplit-dwarf \
-g -fno-omit-frame-pointer \ -g -fno-omit-frame-pointer \
-Wno-unused-command-line-argument \ -Wno-unused-command-line-argument \
-I./include -I./libs \ -fsanitize=address \
-I/usr/include/ruby-3.4.0 -I/usr/include/ruby-3.4.0/x86_64-linux -I./include -I./libs
CFLAGS_RELEASE :=\ CFLAGS_RELEASE :=\
-std=c++20 -O3 -march=native \ -static --target=x86_64-linux-musl \
-fno-rtti -fstrict-aliasing \ -std=c++20 -O3 -march=x86-64 -mtune=generic \
-fno-rtti \
-ffast-math -flto=thin \ -ffast-math -flto=thin \
-fvisibility=hidden -fuse-ld=lld \ -fvisibility=hidden \
-fomit-frame-pointer -DNDEBUG -s \ -fomit-frame-pointer -DNDEBUG -s \
-mllvm -vectorize-loops \ -mllvm -vectorize-loops \
-fno-unwind-tables -fno-asynchronous-unwind-tables\
-Wno-unused-command-line-argument \ -Wno-unused-command-line-argument \
-I./include -I./libs \ -I./include -I./libs
-I/usr/include/ruby-3.4.0 -I/usr/include/ruby-3.4.0/x86_64-linux
PCH_CFLAGS_DEBUG := $(CFLAGS_DEBUG) -x c++-header PCH_CFLAGS_DEBUG := $(CFLAGS_DEBUG) -x c++-header
PCH_CFLAGS_RELEASE := $(CFLAGS_RELEASE) -x c++-header PCH_CFLAGS_RELEASE := $(CFLAGS_RELEASE) -x c++-header
@@ -39,9 +42,13 @@ UNICODE_SRC := $(wildcard libs/unicode_width/*.c)
UNICODE_OBJ_DEBUG := $(patsubst libs/unicode_width/%.c,$(OBJ_DIR)/debug/unicode_width/%.o,$(UNICODE_SRC)) UNICODE_OBJ_DEBUG := $(patsubst libs/unicode_width/%.c,$(OBJ_DIR)/debug/unicode_width/%.o,$(UNICODE_SRC))
UNICODE_OBJ_RELEASE := $(patsubst libs/unicode_width/%.c,$(OBJ_DIR)/release/unicode_width/%.o,$(UNICODE_SRC)) UNICODE_OBJ_RELEASE := $(patsubst libs/unicode_width/%.c,$(OBJ_DIR)/release/unicode_width/%.o,$(UNICODE_SRC))
LIBS := \ LIBS_RELEASE := \
libs/libgrapheme/libgrapheme.a \ libs/libgrapheme/libgrapheme.a \
-lpcre2-8 -lmagic -lruby -Wl,-Bstatic,--gc-sections -lpcre2-8 -lmruby
LIBS_DEBUG := \
libs/libgrapheme/libgrapheme.a \
-Wl,-Bdynamic -lpcre2-8 -lmruby
SRC := $(wildcard $(SRC_DIR)/**/*.cc) $(wildcard $(SRC_DIR)/*.cc) SRC := $(wildcard $(SRC_DIR)/**/*.cc) $(wildcard $(SRC_DIR)/*.cc)
OBJ_DEBUG := $(patsubst $(SRC_DIR)/%.cc,$(OBJ_DIR)/debug/%.o,$(SRC)) OBJ_DEBUG := $(patsubst $(SRC_DIR)/%.cc,$(OBJ_DIR)/debug/%.o,$(SRC))
@@ -58,6 +65,9 @@ test: $(TARGET_DEBUG)
release: $(TARGET_RELEASE) release: $(TARGET_RELEASE)
$(GENERATED_HEADER): $(INCLUDE_DIR)/syntax/tokens.def $(INCLUDE_DIR)/scripting/libcrib.rb src/ruby_compile.sh
src/ruby_compile.sh
$(PCH_DEBUG): $(INCLUDE_DIR)/pch.h $(PCH_DEBUG): $(INCLUDE_DIR)/pch.h
mkdir -p $(dir $@) mkdir -p $(dir $@)
$(CXX) $(PCH_CFLAGS_DEBUG) -o $@ $< $(CXX) $(PCH_CFLAGS_DEBUG) -o $@ $<
@@ -68,27 +78,27 @@ $(PCH_RELEASE): $(INCLUDE_DIR)/pch.h
$(TARGET_DEBUG): $(PCH_DEBUG) $(OBJ_DEBUG) $(UNICODE_OBJ_DEBUG) $(TARGET_DEBUG): $(PCH_DEBUG) $(OBJ_DEBUG) $(UNICODE_OBJ_DEBUG)
mkdir -p $(BIN_DIR) mkdir -p $(BIN_DIR)
$(CXX) $(CFLAGS_DEBUG) -o $@ $(OBJ_DEBUG) $(UNICODE_OBJ_DEBUG) $(LIBS) $(CXX) $(CFLAGS_DEBUG) -o $@ $(OBJ_DEBUG) $(UNICODE_OBJ_DEBUG) $(LIBS_DEBUG)
$(TARGET_RELEASE): $(PCH_RELEASE) $(OBJ_RELEASE) $(UNICODE_OBJ_RELEASE) $(TARGET_RELEASE): $(PCH_RELEASE) $(OBJ_RELEASE) $(UNICODE_OBJ_RELEASE)
mkdir -p $(BIN_DIR) mkdir -p $(BIN_DIR)
$(CXX) $(CFLAGS_RELEASE) -o $@ $(OBJ_RELEASE) $(UNICODE_OBJ_RELEASE) $(LIBS) $(CXX) $(CFLAGS_RELEASE) -o $@ $(OBJ_RELEASE) $(UNICODE_OBJ_RELEASE) $(LIBS_RELEASE)
$(OBJ_DIR)/debug/%.o: $(SRC_DIR)/%.cc $(PCH_DEBUG) $(OBJ_DIR)/debug/%.o: $(SRC_DIR)/%.cc $(PCH_DEBUG) $(GENERATED_HEADER)
mkdir -p $(dir $@) mkdir -p $(dir $@)
$(CXX) $(CFLAGS_DEBUG) -include $(INCLUDE_DIR)/pch.h -MMD -MP -c $< -o $@ $(CXX) $(CFLAGS_DEBUG) -include $(INCLUDE_DIR)/pch.h -MMD -MP -c $< -o $@
$(OBJ_DIR)/release/%.o: $(SRC_DIR)/%.cc $(PCH_RELEASE) $(OBJ_DIR)/release/%.o: $(SRC_DIR)/%.cc $(PCH_RELEASE) $(GENERATED_HEADER)
mkdir -p $(dir $@) mkdir -p $(dir $@)
$(CXX) $(CFLAGS_RELEASE) -include $(INCLUDE_DIR)/pch.h -MMD -MP -c $< -o $@ $(CXX) $(CFLAGS_RELEASE) -include $(INCLUDE_DIR)/pch.h -MMD -MP -c $< -o $@
$(OBJ_DIR)/debug/unicode_width/%.o: libs/unicode_width/%.c $(OBJ_DIR)/debug/unicode_width/%.o: libs/unicode_width/%.c
mkdir -p $(dir $@) mkdir -p $(dir $@)
$(CXX) $(CFLAGS_DEBUG) -MMD -MP -c $< -o $@ $(CC) -MMD -MP -c $< -o $@
$(OBJ_DIR)/release/unicode_width/%.o: libs/unicode_width/%.c $(OBJ_DIR)/release/unicode_width/%.o: libs/unicode_width/%.c
mkdir -p $(dir $@) mkdir -p $(dir $@)
$(CXX) $(CFLAGS_RELEASE) -MMD -MP -c $< -o $@ $(CC) -MMD -MP -c $< -o $@
DEP_DEBUG += $(UNICODE_OBJ_DEBUG:.o=.d) DEP_DEBUG += $(UNICODE_OBJ_DEBUG:.o=.d)
DEP_RELEASE += $(UNICODE_OBJ_RELEASE:.o=.d) DEP_RELEASE += $(UNICODE_OBJ_RELEASE:.o=.d)

169
README.md
View File

@@ -12,6 +12,18 @@ It aims to be complete general purpose IDE.<br>
(It is still very much a work in progress so a lot of things may seem incomplete)<br> (It is still very much a work in progress so a lot of things may seem incomplete)<br>
For now it is just a single file editor. I plan to add a multi-file support with file pickers and tabs soon.<br> For now it is just a single file editor. I plan to add a multi-file support with file pickers and tabs soon.<br>
## Installation
Binary can be installed with the following command:
```bash
curl https://syedm.dev/crib | sh
```
It requires `libmagic` to be installed (most systems have it preinstalled).<br>
Currently only for Linux.<br>
*Tested with arch linux and ubuntu*<br>
## Building ## Building
### Get started ### Get started
@@ -40,10 +52,10 @@ Make sure you have the following dependencies installed (apart from the standard
#include <pcre2.h> #include <pcre2.h>
``` ```
* **libmagic** * **[mruby](https://github.com/mruby/mruby)**
Install it so that you can include it in your code (most *nix systems have it installed): Install it via your package manager. Once installed, the header should be available as:
```cpp ```cpp
#include <magic.h> #include <mruby.h>
``` ```
It also uses `xclip` at runtime for copying/pasting *(TODO: make it os portable)*. It also uses `xclip` at runtime for copying/pasting *(TODO: make it os portable)*.
@@ -51,16 +63,18 @@ And any modern terminal should work fine - preferably `kitty` or `wezterm`.<br>
#### `./libs` folder #### `./libs` folder
Some other dependancies like `libgrapheme` and `unicode_width` are added as submodules or copied.<br> Some other dependancies are added as submodules or copied.<br>
`unicode_width` is compiled by the makefile so nothing to do there.<br> - `unicode_width` is compiled by the makefile so nothing to do there.<br>
`libgrapheme` needs to be compiled using `make` in it's folder.<br> - `libgrapheme` needs to be compiled using `make` in it's folder.<br>
#### LSPs #### LSPs
The following lsp's are supported and can be installed anywhere in your `$PATH`<br> Lsp's are defined in the `libcrib.rb` file and you can use your `config/main.rb` file to add more.<br>
The following lsp's are added by default and can be installed anywhere in your `$PATH`<br>
* [clangd](https://clangd.llvm.org/) * [clangd](https://clangd.llvm.org/)
* [solargraph](https://solargraph.org/) * [ruby-lsp](https://shopify.github.io/ruby-lsp/)
* [bash-language-server](https://github.com/bash-lsp/bash-language-server) * [bash-language-server](https://github.com/bash-lsp/bash-language-server)
* [vscode-css-language-server](https://github.com/hrsh7th/vscode-langservers-extracted) * [vscode-css-language-server](https://github.com/hrsh7th/vscode-langservers-extracted)
* [vscode-json-language-server](https://github.com/hrsh7th/vscode-langservers-extracted) * [vscode-json-language-server](https://github.com/hrsh7th/vscode-langservers-extracted)
@@ -81,14 +95,11 @@ The following lsp's are supported and can be installed anywhere in your `$PATH`<
* [make-language-server](https://github.com/Freed-Wu/autotools-language-server) * [make-language-server](https://github.com/Freed-Wu/autotools-language-server)
> As it is still in development, some of these may not work as expected or that well.<br> > As it is still in development, some of these may not work as expected or that well.<br>
> But for c/ruby/lua/python it should work fine (I test more with these).<br>
> It should work even if the lsp is not installed but lsp features will not work.<br> > It should work even if the lsp is not installed but lsp features will not work.<br>
> See `include/config.h` & `include/ts/decl.h` if you want to add your own lsp and/or tree-sitter grammar.<br>
#### Compiler #### Compiler
`g++` and `clang++` should both work fine but `c++20+` is required. `clang++` should work fine but `c++23+` is required.<br>
The makefile uses `clang++` by default.<br>
Can remove `ccache` if you want from the makefile.<br> Can remove `ccache` if you want from the makefile.<br>
#### Compliling #### Compliling
@@ -100,9 +111,6 @@ make release
### Running ### Running
Preferably add the `bin` folder to PATH or move `bin/crib` to somewhere in PATH.<br> Preferably add the `bin` folder to PATH or move `bin/crib` to somewhere in PATH.<br>
But make sure that `scripts/` are at `../` relative to the binary or it will crash.<br>
`scripts/init.sh` and `scripts/exit.sh` can be used to add hooks to the editor on startup and exit
(Make sure to remove my `kitty` hooks from them if you want).<br>
For some LSP's to work properly `crib` needs to be run from the root folder of the project. *To be fixed*<br> For some LSP's to work properly `crib` needs to be run from the root folder of the project. *To be fixed*<br>
then do -<br> then do -<br>
@@ -110,127 +118,12 @@ then do -<br>
crib ./filename.ext crib ./filename.ext
``` ```
*If `filename.ext` does not exist, it will fail to load the editor - use `touch filename.ext` to create it - to be fixed*<br> *If `filename.ext` does not exist, it will be created*<br>
*Try out with files in `samples/`*<br>
## Keybindings ## Keybindings
### Mouse Interactions TODO: add keybind information on how to set in `config/main.rb`
and default / unchangeable keybinds
These interactions work globally or generally across the editor canvas.
| Action | Function |
| --- | --- |
| **Scroll Up/Down** | Scrolls the view. |
| **Scroll Left/Right** | Moves the cursor left or right. |
| **Left Click (Press)** | Moves cursor to position; resets selection. |
| **Left Click (Double)** | Selects the **word** under the cursor (enters SELECT mode). |
| **Left Click (Triple)** | Selects the **line** under the cursor (enters SELECT mode). |
| **Left Click (Drag)** | Selects text (Character, Word, or Line based on initial click type). |
| **Left Click (Release)** | If cursor and selection start are the same, returns to NORMAL mode. |
### Navigation (Global / Special Keys)
These keys work primarily in Normal mode but handle movement logic.
| Key | Modifier | Function |
| --- | --- | --- |
| **Arrows** (Up/Down/Left/Right) | None | Move cursor 1 step in that direction. |
| **Arrows** (Up/Down) | `CTRL` | Move cursor **5 steps** in that direction. |
| **Arrows** (Left/Right) | `CTRL` | Jump to the previous/next **word boundary**. |
| **Arrows** (Up/Down) | `ALT` | **Move the current line** Up or Down. |
| **Arrows** (Left/Right) | `ALT` | Move cursor **8 steps** in that direction. |
### NORMAL Mode
This is the default navigation and command mode.
| Key | Function |
| --- | --- |
| **i** | Enter **INSERT** mode (at current position). |
| **a** | Enter **INSERT** mode (append: moves cursor right by 1 first). |
| **s** or **v** | Enter **SELECT** mode (start character selection). |
| **:** or **;** | Enter **RUNNER** mode (Command Bar). |
| **u** | Select the **last line** of the file (Jumps to bottom). |
| **h** | Trigger **LSP Hover** information for the symbol under cursor. |
| **Ctrl + h** | Scroll the hover window **Up**. |
| **Ctrl + l** | Scroll the hover window **Down**. |
| **Ctrl + s** | **Save** the file. |
| **Ctrl + d** | Scroll Page **Down** (1 unit). |
| **Ctrl + u** | Scroll Page **Up** (1 unit). |
| **p** | **Paste** from clipboard at cursor position (moves cursor to end of paste). |
| **>** or **.** | **Indent** the current line. |
| **<** or **,** | **Dedent** (un-indent) the current line. |
| **Space** | Move cursor Right. |
| **Backspace** (`0x7F`) | Move cursor Left. |
| **Enter** (`\n`, `\r`) | Move cursor Down. |
| **\| or \\** | Move cursor Up. |
| **n** | Enter **JUMPER** mode (Set Bookmark). |
| **m** | Enter **JUMPER** mode (Jump to Bookmark). |
| **N** | Clear specific Jumper hook (logic attempts to clear hook at current line). |
### INSERT Mode
Used for typing text.
| Key | Function |
| --- | --- |
| **Esc** (`0x1B`) | Return to **NORMAL** mode. |
| **Tab** (`\t`) | Inserts 2 spaces. |
| **Enter** | Inserts newline + **Auto-indents** based on previous line/context. |
| **Backspace** | Deletes previous character or auto-collapses empty pairs (e.g., `{` -> `}`). |
| **Ctrl + w** | **Delete Previous Word**. |
| **Del** | Delete character under cursor. |
| **Ctrl + Del** | Delete **Next Word**. |
| **Typing** | Inserts characters. |
| **Ctrl + Shift + v or as configured in your terminal** | System pasting. |
| **{ ( [ " '** | Auto-inserts closing pair (e.g., typing `{` inserts `{}`). |
| **} ) ] " '** | If the next char matches the typed char, skip insertion (overwrite), otherwise insert. |
#### Autocompletion (Inside Insert Mode)
These function only if LSP and completion are active.
| Key | Function |
| --- | --- |
| **Ctrl + p** | Select **Next** completion item. |
| **Ctrl + o** | Select **Previous** completion item. |
| **Ctrl + \\** | **Accept** selected completion OR trigger new completion request. |
| **Trigger Chars** | (e.g., `.`, `>`) Automatically triggers completion popup. |
### SELECT Mode
Used for highlighting text.
| Key | Function |
| --- | --- |
| **Esc**, **s**, **v** | Cancel selection and return to **NORMAL** mode. |
| **y** | **Yank (Copy)** selection to clipboard → Return to Normal. |
| **x** | **Cut** selection to clipboard → Return to Normal. |
| **p** | **Paste** over selection (Replace text) → Return to Normal. |
| **f** | **Fold** the selected range (collapses code) → Return to Normal. |
### JUMPER Mode
This mode uses a bookmarking system mapped to keyboard characters.
* **Entered via `n` (Set Mode):**
* Pressing any key `!` through `~` assigns the current line number to that key.
* **Entered via `m` (Jump Mode):**
* Pressing any key `!` through `~` jumps the cursor to the line previously assigned to that key.
### RUNNER Mode (Command Bar)
Activated by `:` or `;`.
| Key | Function |
| --- | --- |
| **Esc** | Cancel and return to **NORMAL** mode. |
| **Enter** | Execute the typed command. |
| **Left / Right** | Move cursor within the command bar. |
| **Up / Down** | Intended for command history. (Not implemented) |
| **Typing** | Insert characters into the command bar. (Not implemented) |
## Features Implemented ## Features Implemented
@@ -250,9 +143,9 @@ Activated by `:` or `;`.
- hooks jumping (bookmarking) - hooks jumping (bookmarking)
- color hex code highlighting - color hex code highlighting
- current line highlighting - current line highlighting
<!-- - TODO: current word under cursor highlighting --> - all instances of current word under cursor highlighting
#### syntax highlighting and filetype detection (using extention or libmagic) for: #### syntax highlighting and filetype detection for:
- ruby - ruby
<!-- TODO: --> <!-- TODO: -->
<!-- - bash --> <!-- - bash -->
@@ -286,11 +179,13 @@ Activated by `:` or `;`.
#### LSP-powered features: #### LSP-powered features:
- diagnostics - diagnostics
- autocompletion - autocompletion
- hover docs (with markdown support) - hover docs
- formatting support - formatting support
- Full file formatting on save - Full file formatting on save
- Ontype formatting when inserting special characters defined by the language server - Ontype formatting when inserting special characters defined by the language server
- *(few lsp's actually support this - try to configure a few more which can but need configuration and for others need to add support for external formatters)* - *(few lsp's actually support this - try to configure a few more which can but need configuration and for others need to add support for external formatters)*
- A list of all supported lsp's can be found [here](#lsps). - A list of some lsp's can be found [here](#lsps).
- Any lsp can be added to the `config/main.rb` file.
- Though not all might work well. Open an issue if you find a lsp that doesn't work well.
**A lot lot more to come** **A lot lot more to come**

71
TODO.md
View File

@@ -2,16 +2,15 @@ Copyright 2025 Syed Daanish
# TODO # TODO
### Critical Fixes ##### BTW Check each lsp with each of the features implemented
##### Check each lsp with each of the features implemented
* [ ] Make a proper qeued system for bar contents from ruby
* [ ] Allow clipbaord setting & alpha in ini files
* [ ] Make warning before ctrl+q for saving
* [ ] **LSP Bug:** Check why `fish-lsp` is behaving so off with completions filtering. * [ ] **LSP Bug:** Check why `fish-lsp` is behaving so off with completions filtering.
* [ ] **File IO:** Normalize/validate unicode on file open (enforce UTF-8, handle other types gracefully).
* [ ] **Critical Crash:** Fix bug where closing immediately while LSP is still loading hangs and then segfaults (especially on slow ones like fish-lsp where quick edits and exit can hang).
* [ ] **Line move:** fix the move line functions to work without the calculations from folds as folds are removed. * [ ] **Line move:** fix the move line functions to work without the calculations from folds as folds are removed.
* [ ] **Modularize handle_events and renderer functions:** The function is over 700 lines with a lot of repeating blocks. Split into smaller functions.
* [ ] **Editor Indentation Fix:** - Main : merger indentation with the parser for more accurate results. * [ ] **Editor Indentation Fix:** - Main : merger indentation with the parser for more accurate results.
* [ ] Fix bug where enter at start of line with ending type crashes
* [ ] Keep cache of language maps in engine to reduce lookup time. * [ ] Keep cache of language maps in engine to reduce lookup time.
* [ ] In indents add function to support tab which indents if before any content and inserts a pure \t otherwise. * [ ] In indents add function to support tab which indents if before any content and inserts a pure \t otherwise.
* [ ] And backspace which undents if before any content. * [ ] And backspace which undents if before any content.
@@ -20,22 +19,35 @@ Copyright 2025 Syed Daanish
* [ ] These will dedent when the block immediately after them is dedented * [ ] These will dedent when the block immediately after them is dedented
* [ ] Dont dedent if ending is valid starting is invalid but also empty * [ ] Dont dedent if ending is valid starting is invalid but also empty
* [ ] Just leave asis if starting is empty * [ ] Just leave asis if starting is empty
* [ ] **Readme:** Update readme to show indetation mechanics. * [ ] **Readme:** Update readme to show ruby based config.
* [ ] **LSP Bug:** Try to find out why emojis are breaking lsp edits. (check the ruby sample)
* [ ] **UI Refinement:** * [ ] **UI Refinement:**
* [ ] Allow completion list to be scrolled; show only `x` max items. * [ ] Allow completion list to be scrolled; show only `x` max items.
* [ ] Finish autocomplete box style functions. * [ ] Finish autocomplete box style functions.
* [ ] **Documentation UI:** Capture `Ctrl+h` / `Ctrl+l` for scrolling documentation windows. * [ ] **Documentation UI:** Capture `Ctrl+h` / `Ctrl+l` for scrolling documentation windows.
* [ ] **Redo hooks and folding as proper engines**: With functions to checkstate/cursor like function and edits application. * [ ] Redo hooks as a struct.
* [ ] Do trextmate like regex grammar parsing with lsp symbols for semantic highlighting. * [ ] breakdown the render function into smaller functions.
* Probably remove tre--sitter or just keep it for context tree.
* Making bracket matching andignoring strings/comments easier.
* remove tree-sitter mention from everywhere especially submodules
* make it faster for line inserts/deletes too (treeify the vector)
* Try to make all functions better now that folds have been purged * Try to make all functions better now that folds have been purged
* Cleanup syntax and renderer files * Cleanup syntax and renderer files
probably remove solargraph support and use ruby-lsp (or sorbet?) instead * Add a thing called view which is a rect with speacial type editor . but otherwise a ruby or c++ view
* can be used for stuff like file manager/git manager/theme picker.
* allow flushing functions in ruby to tell c++ to refresh keybinds/themes etc.
* allow keybinds to be set in ruby
check::
pull diagnostics for ruby-lsp
lsp selection range - use to highlight start / end of range maybe?
goto definiton
signature help
document symbol for the top bar maybe? (or workspace symbol)
also setup workspaces
Semantic highlighting
Quick fixes
Rename symbols
probably remove solargraph support and use ruby-lsp (or sorbet?) instead because it is a pain for utf stuff
ruby-lsp also supports erb so thats a plus
move lsp configs to json and also allow configs for windows-style vs unix-style line endings and utf-8 vs utf-16 move lsp configs to json and also allow configs for windows-style vs unix-style line endings and utf-8 vs utf-16
@@ -55,7 +67,7 @@ move lsp configs to json and also allow configs for windows-style vs unix-style
* [ ] **Tree-sitter Indent:** Attempt to allow Tree-sitter to handle indentation if possible. * [ ] **Tree-sitter Indent:** Attempt to allow Tree-sitter to handle indentation if possible.
* [ ] **Scrolling:** Add logic where selecting at the end of the screen scrolls down (and vice versa). * [ ] **Scrolling:** Add logic where selecting at the end of the screen scrolls down (and vice versa).
* *Implementation:* Update `main.cc` to send drag events to the selected editor. * *Implementation:* Update `main.cc` to send drag events to the selected editor even if coordinates are out of bounds.
### UX ### UX
@@ -72,11 +84,6 @@ move lsp configs to json and also allow configs for windows-style vs unix-style
* [ ] Handle snippets properly in autocomplete: use only the last word in signature when replacing and set cursor to the first one. * [ ] Handle snippets properly in autocomplete: use only the last word in signature when replacing and set cursor to the first one.
* [ ] **Basic Autocomplete:** Keep a list of words in the current buffer for non-LSP fallback. * [ ] **Basic Autocomplete:** Keep a list of words in the current buffer for non-LSP fallback.
* [ ] **Language Support:**
* [ ] Add ECMA to JS and make TSX support.
* [ ] Add formatting for files where LSP doesn't provide it.
* [ ] Redo grammar files properly (especially cpp).
### Major Features ### Major Features
@@ -93,20 +100,11 @@ move lsp configs to json and also allow configs for windows-style vs unix-style
* [ ] **Block Selection:** * [ ] **Block Selection:**
* [ ] Double-clicking a bracket selects the whole block (first time only) and sets mode to `WORD`. * [ ] Double-clicking a bracket selects the whole block (first time only) and sets mode to `WORD`.
* [ ] **Tree-sitter Context:**
* [ ] Get code context from Tree-sitter.
* [ ] Get node path of current cursor and add indicator bar (breadcrumbs).
* [ ] Highlight block edges when cursor is on/in a bracket.
### Visuals, UI & Extensions? ### Visuals, UI & Extensions?
*Focus: Aesthetics and external integrations.*
* [ ] **Status Bar:** Complete status bar and command runner. * [ ] **Status Bar:** Complete status bar and command runner.
* [ ] **Visual Aids:**
* [ ] Expand color regex to match CSS colors in CSS files.
* [ ] Add color picker/palette. * [ ] Add color picker/palette.
* [ ] **Git:** Add Git integration (status, diffs). * [ ] **Git:** Add Git integration (status, diffs).
@@ -120,21 +118,8 @@ move lsp configs to json and also allow configs for windows-style vs unix-style
### Optimizations & Fluff ### Optimizations & Fluff
* [ ] **Event Loop:**
* [ ] Make the whole engine event-driven rather than clock-driven.
* [ ] Mybe keep background thread with dirty flag.
* [ ] But merge input and render into a single loop that only renders when input affects render or background thread needs refresh and try to couple multiple renders.
* [ ] LSP and inputs should be blocking (lsp on its fd) and inputs in io/input.cc
* [ ] **Performance:** * [ ] **Performance:**
* [ ] Switch JSON parser to `RapidJSON` (or similar high-performance lib). * [ ] Switch JSON parser to `RapidJSON` (or similar high-performance lib).
* [ ] Decrease usage of `std::string` in UI, LSP, and warnings. * [ ] Decrease usage of `std::string` in UI, LSP, and warnings.
* [ ] Also for vectors into managed memory especially for completions/lsp-stuff. * [ ] Also for vectors into managed memory especially for completions/lsp-stuff.
* [ ] **Folding:** Redo folding system and its relation to `move_line_*` functions.
* [ ] **Grammars:**
* [ ] Manually add redo SCM files (especially cpp/c/h).
* [ ] Create `lua-typed` and `man pages` Tree-sitter grammars.
* [ ] **Repo Maintenance:** Once renderer is proven check commit `43f443e`.

View File

@@ -1,6 +1,8 @@
require_relative "libcrib"
# basic configuration # basic configuration
# This can also be used to do speacail configs for different projects.
# its ruby guys script whatever you want.
# puts "Loading main config..."
C.startup do C.startup do
puts "Starting crib..." puts "Starting crib..."
@@ -47,30 +49,30 @@ C.theme = {
:brace5 => { fg: 0xFF0F0F } :brace5 => { fg: 0xFF0F0F }
} }
# # TODO: to be done once a proper api for binding and window drawing is made # TODO: to be done once a proper api for binding and window drawing is made
# # The binds will be connected to either `editor` or windows where editor can # The binds will be connected to either `editor` or windows where editor can
# # only use a preset set of stuff to bind while teh windows are purely custom # only use a preset set of stuff to bind while teh windows are purely custom
# # # this part uses dsl bindings to define the bind function # # this part uses dsl bindings to define the bind function
# # # Hopefully extend to give more context/power to bindings # # Hopefully extend to give more context/power to bindings
# # # but try to keep simple for performance # # but try to keep simple for performance
# # # for default keybindings # # for default keybindings
# # C.bind [:normal, :select], :a => "insert_mode" # C.bind [:normal, :select], :a => "insert_mode"
# # # for custom keybindings # # for custom keybindings
# # C.bind :select, [:x, :c] do # C.bind :select, [:x, :c] do
# # puts "cut" # puts "cut"
# # end # end
# # C.bind :jumper do # C.bind :jumper do
# # set [:x, :c] do # set [:x, :c] do
# # puts "jump to first bookmark" # puts "jump to first bookmark"
# # end # end
# # end # end
# # # they can also be defined conditionally # # they can also be defined conditionally
# # # This code is just an example and doesnt actually work # # This code is just an example and doesnt actually work
# # if using_tmux? # if using_tmux?
# # bind :C-p do # bind :C-p do
# # system("tmux select-pane -U") # system("tmux select-pane -U")
# # end # end
# # end # end
# This can, for example, be modified by user bindings during runtime # This can, for example, be modified by user bindings during runtime
# TODO: dynamic registration to actually be implemented once keybinds and extentions are implemented # TODO: dynamic registration to actually be implemented once keybinds and extentions are implemented
@@ -82,24 +84,23 @@ C.theme = {
# symbol: "󰴭 ", # symbol: "󰴭 ",
# extensions: ["rb"], # extensions: ["rb"],
# filenames: ["Gemfile"], # filenames: ["Gemfile"],
# mimetypes: ["text/x-ruby"],
# lsp: "solargraph" # lsp: "solargraph"
# } # }
C.line_endings = :unix # or :windows C.line_endings = :auto_unix # or :unix or :windows or :auto_windows
# C.extra_highlights do |_line, _idx| C.extra_highlights do |_line, _idx|
# # the return can be an array of # the return can be an array of
# # [fg, bg. flags, start, end] # [fg, bg. flags, start, end]
# # where fg and bg are integers (using 24 bit color) # where fg and bg are integers (using 24 bit color)
# # and flags is a bitmask of bold/underline/italic etc # and flags is a bitmask of bold/underline/italic etc
# # and start and end are integers strictly inside the line # and start and end are integers strictly inside the line
# return [] return []
# end end
# The highlighter will be aplied to the language as long as the langauge is defined in C.languages # The highlighter will be aplied to the language as long as the langauge is defined in C.languages
C.highlighters[:ruby_n] = { C.highlighters[:ruby_n] = {
parser: ->(line, state) { parser: ->(line, state, line_idx) {
# the return value is a hash # the return value is a hash
# it contains the state and the highlights # it contains the state and the highlights
# state can be of any type but will be consistent between calls # state can be of any type but will be consistent between calls
@@ -108,14 +109,14 @@ C.highlighters[:ruby_n] = {
# the highlights can be an array of # the highlights can be an array of
# [K_type, start, end] # [K_type, start, end]
# K_type is a constant from the constants defined in libcrib.rb # K_type is a constant from the constants defined in libcrib.rb
# for ex: for strings it would be C::K_STRING or for numbers C::K_NUMBER etc. # for ex: for strings it would be Tokens::K_STRING or for numbers Tokens::K_NUMBER etc.
# and start and end are integers strictly inside the line # and start and end are integers strictly inside the line
return { return {
state: "", state: "",
tokens: [ tokens: [
# This will highlight the entire line as a string # This will highlight the entire line as a string
# Any wrong format will not be handled and lead to crashes # Any wrong format will not be handled and lead to crashes
{ type: C::K_STRING, start: 0, end: line.length } { type: Tokens::K_STRING, start: 0, end: line.length }
] ]
} }
}, },

View File

@@ -27,9 +27,10 @@ struct CompletionSession {
bool active = false; bool active = false;
Coord hook; Coord hook;
std::optional<std::string> prefix; std::optional<std::string> prefix;
uint8_t select = 0; uint32_t select = 0;
uint32_t scroll = 0;
std::vector<CompletionItem> items; std::vector<CompletionItem> items;
std::vector<uint8_t> visible; std::vector<uint32_t> visible;
bool complete = true; bool complete = true;
std::optional<char> trigger_char; std::optional<char> trigger_char;
uint8_t trigger = 0; uint8_t trigger = 0;

View File

@@ -11,16 +11,15 @@
#include "ui/diagnostics.h" #include "ui/diagnostics.h"
#include "ui/hover.h" #include "ui/hover.h"
#include "utils/utils.h" #include "utils/utils.h"
#include <cstdint>
#define CHAR 0 #define CHAR 0
#define WORD 1 #define WORD 1
#define LINE 2 #define LINE 2
#define EXTRA_META 4 #define EXTRA_META 2
#define INDENT_WIDTH 2 #define INDENT_WIDTH 2
// autocomplete lua// Bracket closing / tab on enter
struct Editor { struct Editor {
std::string filename; std::string filename;
std::string uri; std::string uri;
@@ -30,7 +29,7 @@ struct Editor {
uint32_t cursor_preffered; uint32_t cursor_preffered;
Coord selection; Coord selection;
bool selection_active; bool selection_active;
bool unix_eol; // false for windows bool unix_eol;
int selection_type; int selection_type;
Coord position; Coord position;
Coord size; Coord size;
@@ -57,7 +56,7 @@ struct Editor {
}; };
Editor *new_editor(const char *filename_arg, Coord position, Coord size, Editor *new_editor(const char *filename_arg, Coord position, Coord size,
bool unix_eol); uint8_t eol);
void save_file(Editor *editor); void save_file(Editor *editor);
void free_editor(Editor *editor); void free_editor(Editor *editor);
void render_editor(Editor *editor); void render_editor(Editor *editor);

View File

@@ -80,6 +80,7 @@ void lsp_worker();
std::shared_ptr<LSPInstance> get_or_init_lsp(std::string lsp_id); std::shared_ptr<LSPInstance> get_or_init_lsp(std::string lsp_id);
void clean_lsp(std::shared_ptr<LSPInstance> lsp, std::string lsp_id); void clean_lsp(std::shared_ptr<LSPInstance> lsp, std::string lsp_id);
void close_lsp(std::string lsp_id); void close_lsp(std::string lsp_id);
std::optional<json> read_lsp_message(int fd);
void open_editor(std::shared_ptr<LSPInstance> lsp, void open_editor(std::shared_ptr<LSPInstance> lsp,
std::pair<Language, Editor *> entry); std::pair<Language, Editor *> entry);

View File

@@ -2,6 +2,7 @@
#define MAIN_H #define MAIN_H
#include "pch.h" #include "pch.h"
#include "ui/bar.h"
#define NORMAL 0 #define NORMAL 0
#define INSERT 1 #define INSERT 1
@@ -13,5 +14,6 @@ extern std::atomic<bool> running;
extern std::atomic<uint8_t> mode; extern std::atomic<uint8_t> mode;
extern std::vector<struct Editor *> editors; extern std::vector<struct Editor *> editors;
extern uint8_t current_editor; extern uint8_t current_editor;
extern Bar bar;
#endif #endif

View File

@@ -4,11 +4,12 @@
#define PCRE2_CODE_UNIT_WIDTH 8 #define PCRE2_CODE_UNIT_WIDTH 8
#define PCRE_WORKSPACE_SIZE 512 #define PCRE_WORKSPACE_SIZE 512
#pragma clang diagnostic push #include <mruby.h>
#pragma clang diagnostic ignored "-Wunused-parameter" #include <mruby/array.h>
#include <ruby.h> #include <mruby/compile.h>
#pragma clang diagnostic pop #include <mruby/hash.h>
#include <magic.h> #include <mruby/irep.h>
#include <mruby/string.h>
#include <nlohmann/json.hpp> #include <nlohmann/json.hpp>
#include <pcre2.h> #include <pcre2.h>
extern "C" { extern "C" {

View File

@@ -4,18 +4,42 @@
#include "syntax/decl.h" #include "syntax/decl.h"
#include "utils/utils.h" #include "utils/utils.h"
extern std::unordered_map<std::string, std::pair<VALUE, VALUE>> extern std::unordered_map<std::string, std::pair<mrb_value, mrb_value>>
custom_highlighters; custom_highlighters;
void ruby_start(const char *main_file); struct BarLight {
uint32_t start;
uint32_t end;
Highlight highlight;
};
struct BarLine {
std::string line;
std::vector<BarLight> highlights;
Highlight get_highlight(uint32_t x) {
for (auto &hl : highlights) {
if (hl.start <= x && x <= hl.end)
return hl.highlight;
}
return {0xFFFFFF, 0, 0};
}
};
void setup_ruby_bindings(mrb_state *mrb, RClass *C_module);
void ruby_start();
void ruby_shutdown(); void ruby_shutdown();
void ruby_log(std::string msg);
void load_theme(); void load_theme();
void load_languages_info(); void load_languages_info();
bool read_line_endings(); uint8_t read_line_endings();
void load_custom_highlighters(); void load_custom_highlighters();
VALUE parse_custom(std::vector<Token> *tokens, VALUE parser_block, mrb_value parse_custom(std::vector<Token> *tokens, mrb_value parser_block,
const char *line, uint32_t len, VALUE state); const char *line, uint32_t len, mrb_value state,
bool custom_compare(VALUE match_block, VALUE state1, VALUE state2); uint32_t c_line);
bool custom_compare(mrb_value match_block, mrb_value state1, mrb_value state2);
BarLine bar_contents(uint8_t mode, std::string lang_name, uint32_t warnings,
std::string lsp_name, std::string filename,
std::string foldername, uint32_t line, uint32_t max_line,
uint32_t width);
#endif #endif

View File

@@ -1,57 +1,4 @@
module C module C
K_DATA = 0
K_SHEBANG = 1
K_COMMENT = 2
K_ERROR = 3
K_STRING = 4
K_ESCAPE = 5
K_INTERPOLATION = 6
K_REGEXP = 7
K_NUMBER = 8
K_TRUE = 9
K_FALSE = 10
K_CHAR = 11
K_KEYWORD = 12
K_KEYWORDOPERATOR = 13
K_OPERATOR = 14
K_FUNCTION = 15
K_TYPE = 16
K_CONSTANT = 17
K_VARIABLEINSTANCE = 18
K_VARIABLEGLOBAL = 19
K_ANNOTATION = 20
K_DIRECTIVE = 21
K_LABEL = 22
K_BRACE1 = 23
K_BRACE2 = 24
K_BRACE3 = 25
K_BRACE4 = 26
K_BRACE5 = 27
K_HEADING1 = 28
K_HEADING2 = 29
K_HEADING3 = 30
K_HEADING4 = 31
K_HEADING5 = 32
K_HEADING6 = 33
K_BLOCKQUOTE = 34
K_LIST = 35
K_LISTITEM = 36
K_CODE = 37
K_LANGUAGENAME = 38
K_LINKLABEL = 39
K_IMAGELABEL = 40
K_LINK = 41
K_TABLE = 42
K_TABLEHEADER = 43
K_ITALIC = 44
K_BOLD = 45
K_UNDERLINE = 46
K_STRIKETHROUGH = 47
K_HORIXONTALRULE = 48
K_TAG = 49
K_ATTRIBUTE = 50
K_CHECKDONE = 51
K_CHECKNOTDONE = 52
@lsp_config = { @lsp_config = {
"clangd" => [ "clangd" => [
"--background-index", "--background-index",
@@ -89,256 +36,186 @@ module C
color: 0x555555, color: 0x555555,
symbol: "", symbol: "",
extensions: ["c"], extensions: ["c"],
filenames: [],
mimetypes: ["text/x-c"],
lsp: "clangd" lsp: "clangd"
}, },
cpp: { cpp: {
color: 0x00599C, color: 0x00599C,
symbol: "", symbol: "",
extensions: ["cpp", "cc", "cxx"], extensions: ["cpp", "cc", "cxx"],
filenames: [],
mimetypes: ["text/x-cpp"],
lsp: "clangd" lsp: "clangd"
}, },
h: { h: {
color: 0xA8B9CC, color: 0xA8B9CC,
symbol: "", symbol: "",
extensions: ["h", "hpp"], extensions: ["h", "hpp"],
filenames: [],
mimetypes: ["text/x-c-header"],
lsp: "clangd" lsp: "clangd"
}, },
css: { css: {
color: 0x36a3d9, color: 0x36a3d9,
symbol: "", symbol: "",
extensions: ["css"], extensions: ["css"],
filenames: [],
mimetypes: ["text/css"],
lsp: "vscode-css-language-server" lsp: "vscode-css-language-server"
}, },
fish: { fish: {
color: 0x4d5a5e, color: 0x4d5a5e,
symbol: "", symbol: "",
extensions: ["fish"], extensions: ["fish"],
filenames: [],
mimetypes: ["application/x-fish"],
lsp: "fish-lsp" lsp: "fish-lsp"
}, },
go: { go: {
color: 0x00add8, color: 0x00add8,
symbol: "", symbol: "",
extensions: ["go"], extensions: ["go"],
filenames: [],
mimetypes: ["text/x-go"],
lsp: "gopls" lsp: "gopls"
}, },
gomod: { gomod: {
color: 0x00add8, color: 0x00add8,
symbol: "", symbol: "",
extensions: ["mod"], extensions: ["mod"],
filenames: [],
mimetypes: ["text/x-go-mod"],
lsp: "gopls" lsp: "gopls"
}, },
haskell: { haskell: {
color: 0xa074c4, color: 0xa074c4,
symbol: "", symbol: "",
extensions: ["hs", "lhs"], extensions: ["hs", "lhs"],
filenames: [],
mimetypes: ["text/x-haskell"],
lsp: "haskell-language-server" lsp: "haskell-language-server"
}, },
html: { html: {
color: 0xef8a91, color: 0xef8a91,
symbol: "", symbol: "",
extensions: ["html", "htm"], extensions: ["html", "htm"],
filenames: [],
mimetypes: ["text/html"],
lsp: "emmet-language-server" lsp: "emmet-language-server"
}, },
javascript: { javascript: {
color: 0xf0df8a, color: 0xf0df8a,
symbol: "", symbol: "",
extensions: ["js"], extensions: ["js"],
filenames: [],
mimetypes: ["application/javascript"],
lsp: "typescript-language-server" lsp: "typescript-language-server"
}, },
typescript: { typescript: {
color: 0x36a3d9, color: 0x36a3d9,
symbol: "", symbol: "",
extensions: ["ts"], extensions: ["ts"],
filenames: [],
mimetypes: ["application/typescript"],
lsp: "typescript-language-server" lsp: "typescript-language-server"
}, },
json: { json: {
color: 0xcbcb41, color: 0xcbcb41,
symbol: "{}", symbol: "{}",
extensions: ["json"], extensions: ["json"],
filenames: [],
mimetypes: ["application/json"],
lsp: "vscode-json-language-server" lsp: "vscode-json-language-server"
}, },
jsonc: { jsonc: {
color: 0xcbcb41, color: 0xcbcb41,
symbol: "{}", symbol: "{}",
extensions: ["jsonc"], extensions: ["jsonc"],
filenames: [],
mimetypes: ["application/json"],
lsp: "vscode-json-language-server" lsp: "vscode-json-language-server"
}, },
erb: { erb: {
color: 0x6e1516, color: 0x6e1516,
symbol: "", symbol: "",
extensions: ["erb"], extensions: ["erb"],
filenames: [], lsp: "ruby-lsp"
mimetypes: ["text/x-erb"],
lsp: "emmet-language-server"
}, },
lua: { lua: {
color: 0x36a3d9, color: 0x36a3d9,
symbol: "󰢱 ", symbol: "󰢱 ",
extensions: ["lua"], extensions: ["lua"],
filenames: [],
mimetypes: ["text/x-lua"],
lsp: "lua-language-server" lsp: "lua-language-server"
}, },
python: { python: {
color: 0x95e6cb, color: 0x95e6cb,
symbol: "󰌠 ", symbol: "󰌠 ",
extensions: ["py"], extensions: ["py"],
filenames: [],
mimetypes: ["text/x-python"],
lsp: "pyright" lsp: "pyright"
}, },
rust: { rust: {
color: 0xdea584, color: 0xdea584,
symbol: "󱘗 ", symbol: "󱘗 ",
extensions: ["rs"], extensions: ["rs"],
filenames: [],
mimetypes: ["text/x-rust"],
lsp: "rust-analyzer" lsp: "rust-analyzer"
}, },
php: { php: {
color: 0xa074c4, color: 0xa074c4,
symbol: "󰌟 ", symbol: "󰌟 ",
extensions: ["php"], extensions: ["php"],
filenames: [],
mimetypes: ["application/x-php"],
lsp: "intelephense" lsp: "intelephense"
}, },
markdown: { markdown: {
color: 0x36a3d9, color: 0x36a3d9,
symbol: "", symbol: "",
extensions: ["md", "markdown"], extensions: ["md", "markdown"],
filenames: [],
mimetypes: ["text/markdown"],
lsp: "marksman" lsp: "marksman"
}, },
nginx: { nginx: {
color: 0x6d8086, color: 0x6d8086,
symbol: "", symbol: "",
extensions: ["conf"], extensions: ["conf"],
filenames: [],
mimetypes: ["text/nginx"],
lsp: "nginx-language-server" lsp: "nginx-language-server"
}, },
toml: { toml: {
color: 0x36a3d9, color: 0x36a3d9,
symbol: "", symbol: "",
extensions: ["toml"], extensions: ["toml"],
filenames: [],
mimetypes: ["application/toml"],
lsp: "taplo" lsp: "taplo"
}, },
yaml: { yaml: {
color: 0x6d8086, color: 0x6d8086,
symbol: "", symbol: "",
extensions: ["yml", "yaml"], extensions: ["yml", "yaml"],
filenames: [],
mimetypes: ["text/yaml"],
lsp: "yaml-language-server" lsp: "yaml-language-server"
}, },
sql: { sql: {
color: 0xdad8d8, color: 0xdad8d8,
symbol: "", symbol: "",
extensions: ["sql"], extensions: ["sql"],
filenames: [],
mimetypes: ["text/x-sql"],
lsp: "sqls" lsp: "sqls"
}, },
make: { make: {
color: 0x4e5c61, color: 0x4e5c61,
symbol: "", symbol: "",
extensions: ["Makefile", "makefile"], extensions: ["Makefile", "makefile"],
filenames: [],
mimetypes: ["text/x-makefile"],
lsp: "make-language-server" lsp: "make-language-server"
}, },
gdscript: { gdscript: {
color: 0x6d8086, color: 0x6d8086,
symbol: "", symbol: "",
extensions: ["gd"], extensions: ["gd"]
filenames: [],
mimetypes: ["text/x-gdscript"],
lsp: nil
}, },
man: { man: {
color: 0xdad8d8, color: 0xdad8d8,
symbol: "", symbol: "",
extensions: ["man"], extensions: ["man"]
filenames: [],
mimetypes: ["application/x-troff-man"],
lsp: nil
}, },
diff: { diff: {
color: 0xDD4C35, color: 0xDD4C35,
symbol: "", symbol: "",
extensions: ["diff", "patch"], extensions: ["diff", "patch"]
filenames: [],
mimetypes: ["text/x-diff"],
lsp: nil
}, },
gitattributes: { gitattributes: {
color: 0xF05032, color: 0xF05032,
symbol: "", symbol: "",
extensions: ["gitattributes"], extensions: ["gitattributes"]
filenames: [],
mimetypes: [],
lsp: nil
}, },
gitignore: { gitignore: {
color: 0xF05032, color: 0xF05032,
symbol: "", symbol: "",
extensions: ["gitignore"], extensions: ["gitignore"]
filenames: [],
mimetypes: [],
lsp: nil
}, },
regex: { regex: {
color: 0x9E9E9E, color: 0x9E9E9E,
symbol: ".*", symbol: ".*",
extensions: ["regex"], extensions: ["regex"]
filenames: [],
mimetypes: [],
lsp: nil
}, },
ini: { ini: {
color: 0x6d8086, color: 0x6d8086,
symbol: "", symbol: "",
extensions: ["ini"], extensions: ["ini"]
filenames: [],
mimetypes: [],
lsp: nil
}, },
ruby: { ruby: {
color: 0xff8087, color: 0xff8087,
symbol: "󰴭 ", symbol: "󰴭 ",
extensions: ["rb"], extensions: ["rb"],
filenames: ["Gemfile"], filenames: ["Gemfile"],
mimetypes: ["text/x-ruby"],
lsp: "solargraph" lsp: "solargraph"
}, },
bash: { bash: {
@@ -346,20 +223,91 @@ module C
symbol: "", symbol: "",
extensions: ["sh"], extensions: ["sh"],
filenames: ["bash_profile", "bashrc"], filenames: ["bash_profile", "bashrc"],
mimetypes: ["text/x-sh"],
lsp: "bash-language-server" lsp: "bash-language-server"
} }
} }
@theme = {
:default => { fg: 0xEEEEEE },
:shebang => { fg: 0x7DCFFF },
:error => { fg: 0xEF5168 },
:comment => { fg: 0xAAAAAA, italic: true },
:string => { fg: 0xAAD94C },
:escape => { fg: 0x7DCFFF },
:interpolation => { fg: 0x7DCFFF },
:regexp => { fg: 0xD2A6FF },
:number => { fg: 0xE6C08A },
:true => { fg: 0x7AE93C },
:false => { fg: 0xEF5168 },
:char => { fg: 0xFFAF70 },
:keyword => { fg: 0xFF8F40 },
:keywordoperator => { fg: 0xF07178 },
:operator => { fg: 0xFFFFFF, italic: true },
:function => { fg: 0xFFAF70 },
:type => { fg: 0xF07178 },
:constant => { fg: 0x7DCFFF },
:variableinstance => { fg: 0x95E6CB },
:variableglobal => { fg: 0xF07178 },
:annotation => { fg: 0x7DCFFF },
:directive => { fg: 0xFF8F40 },
:label => { fg: 0xD2A6FF },
:brace1 => { fg: 0xD2A6FF },
:brace2 => { fg: 0xFFAFAF },
:brace3 => { fg: 0xFFFF00 },
:brace4 => { fg: 0x0FFF0F },
:brace5 => { fg: 0xFF0F0F }
}
@line_endings = :auto_unix
@key_handlers = {} @key_handlers = {}
@key_binds = {} @key_binds = {}
@highlighters = {} @highlighters = {}
@log_queue = [] @b_startup = nil
@line_endings = :unix @b_shutdown = nil
@b_bar = lambda do |info|
# mode, lang_name, warnings, lsp_name, filename, foldername, line, max_line, width
# puts info.inspect
mode_color = 0x82AAFF
mode_symbol = " "
case info[:mode]
when :normal
mode_color = 0x82AAFF
mode_symbol = ""
when :insert
mode_color = 0xFF8F40
mode_symbol = "󱓧 "
when :select
mode_color = 0x9ADE7A
mode_symbol = "󱩧 "
when :runner
mode_color = 0xFFD700
mode_symbol = ""
when :jumper
mode_color = 0xF29CC3
mode_symbol = ""
end
lang_info = C.languages[info[:lang_name]]
filename = File.basename(info[:filename])
starting = " #{mode_symbol} #{info[:mode].to_s.upcase}  #{lang_info[:symbol]}#{filename}"
highlights = []
highlights << { fg: 0x0b0e14, bg: mode_color, flags: 1 << 1, start: 0, length: 10 }
highlights << { fg: mode_color, bg: 0x33363c, start: 10, length: 1 }
highlights << { fg: 0x33363c, bg: 0x24272d, start: 11, length: 1 }
highlights << { fg: lang_info[:color], bg: 0x24272d, start: 13, length: 2 }
highlights << { fg: 0xced4df, bg: 0x24272d, start: 15, length: filename.length }
highlights << { fg: 0x24272d, bg: 0x000000, start: 15 + filename.length, length: 1 }
return {
text: starting,
highlights: highlights
}
end
class << self class << self
attr_accessor :theme, :lsp_config, :languages, attr_accessor :theme, :lsp_config, :languages,
:line_endings, :highlighters :line_endings, :highlighters
attr_reader :b_startup, :b_shutdown, :b_extra_highlights attr_reader :b_startup, :b_shutdown, :b_extra_highlights, :b_bar
# def bar=(block)
# @b_bar = block
# end
def startup(&block) def startup(&block)
@b_startup = block @b_startup = block
@@ -369,17 +317,6 @@ module C
@b_shutdown = block @b_shutdown = block
end end
def queue_log(msg)
@log_queue << msg
end
def log_all
@log_queue.each do |msg|
puts msg
end
@log_queue = []
end
def extra_highlights(&block) def extra_highlights(&block)
@b_extra_highlights = block @b_extra_highlights = block
end end
@@ -415,5 +352,3 @@ module C
end end
end end
end end
at_exit { C.log_all }

View File

@@ -0,0 +1,611 @@
#pragma once
constexpr unsigned char _tmp___crib_precompiled_mrb[] = {
0x52, 0x49, 0x54, 0x45, 0x30, 0x33, 0x30, 0x30, 0x00, 0x00, 0x1c, 0x69,
0x4d, 0x41, 0x54, 0x5a, 0x30, 0x30, 0x30, 0x30, 0x49, 0x52, 0x45, 0x50,
0x00, 0x00, 0x1b, 0x81, 0x30, 0x33, 0x30, 0x30, 0x00, 0x00, 0x00, 0x34,
0x00, 0x01, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13,
0x11, 0x01, 0x5d, 0x01, 0x00, 0x5e, 0x01, 0x00, 0x11, 0x01, 0x5d, 0x01,
0x01, 0x5e, 0x01, 0x01, 0x38, 0x01, 0x69, 0x00, 0x00, 0x00, 0x02, 0x00,
0x06, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x00, 0x00, 0x01, 0x43, 0x00,
0x00, 0x00, 0x03, 0xfd, 0x00, 0x01, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x01, 0x3c, 0x06, 0x01, 0x1e, 0x01, 0x00, 0x07, 0x01, 0x1e,
0x01, 0x01, 0x08, 0x01, 0x1e, 0x01, 0x02, 0x09, 0x01, 0x1e, 0x01, 0x03,
0x0a, 0x01, 0x1e, 0x01, 0x04, 0x0b, 0x01, 0x1e, 0x01, 0x05, 0x0c, 0x01,
0x1e, 0x01, 0x06, 0x0d, 0x01, 0x1e, 0x01, 0x07, 0x03, 0x01, 0x08, 0x1e,
0x01, 0x08, 0x03, 0x01, 0x09, 0x1e, 0x01, 0x09, 0x03, 0x01, 0x0a, 0x1e,
0x01, 0x0a, 0x03, 0x01, 0x0b, 0x1e, 0x01, 0x0b, 0x03, 0x01, 0x0c, 0x1e,
0x01, 0x0c, 0x03, 0x01, 0x0d, 0x1e, 0x01, 0x0d, 0x03, 0x01, 0x0e, 0x1e,
0x01, 0x0e, 0x03, 0x01, 0x0f, 0x1e, 0x01, 0x0f, 0x03, 0x01, 0x10, 0x1e,
0x01, 0x10, 0x03, 0x01, 0x11, 0x1e, 0x01, 0x11, 0x03, 0x01, 0x12, 0x1e,
0x01, 0x12, 0x03, 0x01, 0x13, 0x1e, 0x01, 0x13, 0x03, 0x01, 0x14, 0x1e,
0x01, 0x14, 0x03, 0x01, 0x15, 0x1e, 0x01, 0x15, 0x03, 0x01, 0x16, 0x1e,
0x01, 0x16, 0x03, 0x01, 0x17, 0x1e, 0x01, 0x17, 0x03, 0x01, 0x18, 0x1e,
0x01, 0x18, 0x03, 0x01, 0x19, 0x1e, 0x01, 0x19, 0x03, 0x01, 0x1a, 0x1e,
0x01, 0x1a, 0x03, 0x01, 0x1b, 0x1e, 0x01, 0x1b, 0x03, 0x01, 0x1c, 0x1e,
0x01, 0x1c, 0x03, 0x01, 0x1d, 0x1e, 0x01, 0x1d, 0x03, 0x01, 0x1e, 0x1e,
0x01, 0x1e, 0x03, 0x01, 0x1f, 0x1e, 0x01, 0x1f, 0x03, 0x01, 0x20, 0x1e,
0x01, 0x20, 0x03, 0x01, 0x21, 0x1e, 0x01, 0x21, 0x03, 0x01, 0x22, 0x1e,
0x01, 0x22, 0x03, 0x01, 0x23, 0x1e, 0x01, 0x23, 0x03, 0x01, 0x24, 0x1e,
0x01, 0x24, 0x03, 0x01, 0x25, 0x1e, 0x01, 0x25, 0x03, 0x01, 0x26, 0x1e,
0x01, 0x26, 0x03, 0x01, 0x27, 0x1e, 0x01, 0x27, 0x03, 0x01, 0x28, 0x1e,
0x01, 0x28, 0x03, 0x01, 0x29, 0x1e, 0x01, 0x29, 0x03, 0x01, 0x2a, 0x1e,
0x01, 0x2a, 0x03, 0x01, 0x2b, 0x1e, 0x01, 0x2b, 0x03, 0x01, 0x2c, 0x1e,
0x01, 0x2c, 0x03, 0x01, 0x2d, 0x1e, 0x01, 0x2d, 0x03, 0x01, 0x2e, 0x1e,
0x01, 0x2e, 0x03, 0x01, 0x2f, 0x1e, 0x01, 0x2f, 0x03, 0x01, 0x30, 0x1e,
0x01, 0x30, 0x03, 0x01, 0x31, 0x1e, 0x01, 0x31, 0x03, 0x01, 0x32, 0x1e,
0x01, 0x32, 0x03, 0x01, 0x33, 0x1e, 0x01, 0x33, 0x03, 0x01, 0x34, 0x1e,
0x01, 0x34, 0x2d, 0x01, 0x35, 0x00, 0x38, 0x01, 0x00, 0x00, 0x00, 0x36,
0x00, 0x06, 0x4b, 0x5f, 0x44, 0x41, 0x54, 0x41, 0x00, 0x00, 0x09, 0x4b,
0x5f, 0x53, 0x48, 0x45, 0x42, 0x41, 0x4e, 0x47, 0x00, 0x00, 0x09, 0x4b,
0x5f, 0x43, 0x4f, 0x4d, 0x4d, 0x45, 0x4e, 0x54, 0x00, 0x00, 0x07, 0x4b,
0x5f, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x00, 0x00, 0x08, 0x4b, 0x5f, 0x53,
0x54, 0x52, 0x49, 0x4e, 0x47, 0x00, 0x00, 0x08, 0x4b, 0x5f, 0x45, 0x53,
0x43, 0x41, 0x50, 0x45, 0x00, 0x00, 0x0f, 0x4b, 0x5f, 0x49, 0x4e, 0x54,
0x45, 0x52, 0x50, 0x4f, 0x4c, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x00, 0x00,
0x08, 0x4b, 0x5f, 0x52, 0x45, 0x47, 0x45, 0x58, 0x50, 0x00, 0x00, 0x08,
0x4b, 0x5f, 0x4e, 0x55, 0x4d, 0x42, 0x45, 0x52, 0x00, 0x00, 0x06, 0x4b,
0x5f, 0x54, 0x52, 0x55, 0x45, 0x00, 0x00, 0x07, 0x4b, 0x5f, 0x46, 0x41,
0x4c, 0x53, 0x45, 0x00, 0x00, 0x06, 0x4b, 0x5f, 0x43, 0x48, 0x41, 0x52,
0x00, 0x00, 0x09, 0x4b, 0x5f, 0x4b, 0x45, 0x59, 0x57, 0x4f, 0x52, 0x44,
0x00, 0x00, 0x11, 0x4b, 0x5f, 0x4b, 0x45, 0x59, 0x57, 0x4f, 0x52, 0x44,
0x4f, 0x50, 0x45, 0x52, 0x41, 0x54, 0x4f, 0x52, 0x00, 0x00, 0x0a, 0x4b,
0x5f, 0x4f, 0x50, 0x45, 0x52, 0x41, 0x54, 0x4f, 0x52, 0x00, 0x00, 0x0a,
0x4b, 0x5f, 0x46, 0x55, 0x4e, 0x43, 0x54, 0x49, 0x4f, 0x4e, 0x00, 0x00,
0x06, 0x4b, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x00, 0x00, 0x0a, 0x4b, 0x5f,
0x43, 0x4f, 0x4e, 0x53, 0x54, 0x41, 0x4e, 0x54, 0x00, 0x00, 0x12, 0x4b,
0x5f, 0x56, 0x41, 0x52, 0x49, 0x41, 0x42, 0x4c, 0x45, 0x49, 0x4e, 0x53,
0x54, 0x41, 0x4e, 0x43, 0x45, 0x00, 0x00, 0x10, 0x4b, 0x5f, 0x56, 0x41,
0x52, 0x49, 0x41, 0x42, 0x4c, 0x45, 0x47, 0x4c, 0x4f, 0x42, 0x41, 0x4c,
0x00, 0x00, 0x0c, 0x4b, 0x5f, 0x41, 0x4e, 0x4e, 0x4f, 0x54, 0x41, 0x54,
0x49, 0x4f, 0x4e, 0x00, 0x00, 0x0b, 0x4b, 0x5f, 0x44, 0x49, 0x52, 0x45,
0x43, 0x54, 0x49, 0x56, 0x45, 0x00, 0x00, 0x07, 0x4b, 0x5f, 0x4c, 0x41,
0x42, 0x45, 0x4c, 0x00, 0x00, 0x08, 0x4b, 0x5f, 0x42, 0x52, 0x41, 0x43,
0x45, 0x31, 0x00, 0x00, 0x08, 0x4b, 0x5f, 0x42, 0x52, 0x41, 0x43, 0x45,
0x32, 0x00, 0x00, 0x08, 0x4b, 0x5f, 0x42, 0x52, 0x41, 0x43, 0x45, 0x33,
0x00, 0x00, 0x08, 0x4b, 0x5f, 0x42, 0x52, 0x41, 0x43, 0x45, 0x34, 0x00,
0x00, 0x08, 0x4b, 0x5f, 0x42, 0x52, 0x41, 0x43, 0x45, 0x35, 0x00, 0x00,
0x0a, 0x4b, 0x5f, 0x48, 0x45, 0x41, 0x44, 0x49, 0x4e, 0x47, 0x31, 0x00,
0x00, 0x0a, 0x4b, 0x5f, 0x48, 0x45, 0x41, 0x44, 0x49, 0x4e, 0x47, 0x32,
0x00, 0x00, 0x0a, 0x4b, 0x5f, 0x48, 0x45, 0x41, 0x44, 0x49, 0x4e, 0x47,
0x33, 0x00, 0x00, 0x0a, 0x4b, 0x5f, 0x48, 0x45, 0x41, 0x44, 0x49, 0x4e,
0x47, 0x34, 0x00, 0x00, 0x0a, 0x4b, 0x5f, 0x48, 0x45, 0x41, 0x44, 0x49,
0x4e, 0x47, 0x35, 0x00, 0x00, 0x0a, 0x4b, 0x5f, 0x48, 0x45, 0x41, 0x44,
0x49, 0x4e, 0x47, 0x36, 0x00, 0x00, 0x0c, 0x4b, 0x5f, 0x42, 0x4c, 0x4f,
0x43, 0x4b, 0x51, 0x55, 0x4f, 0x54, 0x45, 0x00, 0x00, 0x06, 0x4b, 0x5f,
0x4c, 0x49, 0x53, 0x54, 0x00, 0x00, 0x0a, 0x4b, 0x5f, 0x4c, 0x49, 0x53,
0x54, 0x49, 0x54, 0x45, 0x4d, 0x00, 0x00, 0x06, 0x4b, 0x5f, 0x43, 0x4f,
0x44, 0x45, 0x00, 0x00, 0x0e, 0x4b, 0x5f, 0x4c, 0x41, 0x4e, 0x47, 0x55,
0x41, 0x47, 0x45, 0x4e, 0x41, 0x4d, 0x45, 0x00, 0x00, 0x0b, 0x4b, 0x5f,
0x4c, 0x49, 0x4e, 0x4b, 0x4c, 0x41, 0x42, 0x45, 0x4c, 0x00, 0x00, 0x0c,
0x4b, 0x5f, 0x49, 0x4d, 0x41, 0x47, 0x45, 0x4c, 0x41, 0x42, 0x45, 0x4c,
0x00, 0x00, 0x06, 0x4b, 0x5f, 0x4c, 0x49, 0x4e, 0x4b, 0x00, 0x00, 0x07,
0x4b, 0x5f, 0x54, 0x41, 0x42, 0x4c, 0x45, 0x00, 0x00, 0x0d, 0x4b, 0x5f,
0x54, 0x41, 0x42, 0x4c, 0x45, 0x48, 0x45, 0x41, 0x44, 0x45, 0x52, 0x00,
0x00, 0x08, 0x4b, 0x5f, 0x49, 0x54, 0x41, 0x4c, 0x49, 0x43, 0x00, 0x00,
0x06, 0x4b, 0x5f, 0x42, 0x4f, 0x4c, 0x44, 0x00, 0x00, 0x0b, 0x4b, 0x5f,
0x55, 0x4e, 0x44, 0x45, 0x52, 0x4c, 0x49, 0x4e, 0x45, 0x00, 0x00, 0x0f,
0x4b, 0x5f, 0x53, 0x54, 0x52, 0x49, 0x4b, 0x45, 0x54, 0x48, 0x52, 0x4f,
0x55, 0x47, 0x48, 0x00, 0x00, 0x10, 0x4b, 0x5f, 0x48, 0x4f, 0x52, 0x49,
0x58, 0x4f, 0x4e, 0x54, 0x41, 0x4c, 0x52, 0x55, 0x4c, 0x45, 0x00, 0x00,
0x05, 0x4b, 0x5f, 0x54, 0x41, 0x47, 0x00, 0x00, 0x0b, 0x4b, 0x5f, 0x41,
0x54, 0x54, 0x52, 0x49, 0x42, 0x55, 0x54, 0x45, 0x00, 0x00, 0x0b, 0x4b,
0x5f, 0x43, 0x48, 0x45, 0x43, 0x4b, 0x44, 0x4f, 0x4e, 0x45, 0x00, 0x00,
0x0e, 0x4b, 0x5f, 0x43, 0x48, 0x45, 0x43, 0x4b, 0x4e, 0x4f, 0x54, 0x44,
0x4f, 0x4e, 0x45, 0x00, 0x00, 0x06, 0x66, 0x72, 0x65, 0x65, 0x7a, 0x65,
0x00, 0x00, 0x00, 0x0f, 0x61, 0x00, 0x01, 0x00, 0x4c, 0x00, 0x02, 0x00,
0x00, 0x00, 0x00, 0x07, 0x6f, 0x51, 0x01, 0x00, 0x51, 0x02, 0x01, 0x51,
0x03, 0x02, 0x51, 0x04, 0x03, 0x51, 0x05, 0x04, 0x51, 0x06, 0x05, 0x51,
0x07, 0x06, 0x51, 0x08, 0x07, 0x47, 0x02, 0x07, 0x51, 0x03, 0x08, 0x47,
0x04, 0x00, 0x51, 0x05, 0x09, 0x51, 0x06, 0x0a, 0x47, 0x06, 0x01, 0x51,
0x07, 0x0b, 0x51, 0x08, 0x0c, 0x47, 0x08, 0x01, 0x51, 0x09, 0x0d, 0x51,
0x0a, 0x0e, 0x47, 0x0a, 0x01, 0x51, 0x0b, 0x0f, 0x51, 0x0c, 0x0e, 0x47,
0x0c, 0x01, 0x51, 0x0d, 0x10, 0x51, 0x0e, 0x0c, 0x47, 0x0e, 0x01, 0x51,
0x0f, 0x11, 0x51, 0x10, 0x12, 0x47, 0x10, 0x01, 0x51, 0x11, 0x13, 0x51,
0x12, 0x14, 0x47, 0x12, 0x01, 0x51, 0x13, 0x15, 0x51, 0x14, 0x0e, 0x47,
0x14, 0x01, 0x51, 0x15, 0x16, 0x51, 0x16, 0x0e, 0x47, 0x16, 0x01, 0x51,
0x17, 0x17, 0x47, 0x18, 0x00, 0x51, 0x19, 0x18, 0x51, 0x1a, 0x0e, 0x47,
0x1a, 0x01, 0x51, 0x1b, 0x19, 0x47, 0x1c, 0x00, 0x51, 0x1d, 0x1a, 0x51,
0x1e, 0x0e, 0x47, 0x1e, 0x01, 0x51, 0x1f, 0x1b, 0x51, 0x20, 0x1c, 0x47,
0x20, 0x01, 0x51, 0x21, 0x1d, 0x47, 0x22, 0x00, 0x51, 0x23, 0x1e, 0x51,
0x24, 0x14, 0x51, 0x25, 0x0a, 0x47, 0x24, 0x02, 0x51, 0x25, 0x1f, 0x51,
0x26, 0x0e, 0x47, 0x26, 0x01, 0x51, 0x27, 0x20, 0x51, 0x28, 0x12, 0x47,
0x28, 0x01, 0x51, 0x29, 0x21, 0x47, 0x2a, 0x00, 0x51, 0x2b, 0x22, 0x51,
0x2c, 0x23, 0x51, 0x2d, 0x24, 0x51, 0x2e, 0x0a, 0x47, 0x2c, 0x03, 0x53,
0x01, 0x16, 0x1a, 0x01, 0x00, 0x10, 0x01, 0x01, 0x10, 0x02, 0x02, 0x0f,
0x03, 0x00, 0x55, 0x55, 0x55, 0x10, 0x04, 0x03, 0x51, 0x05, 0x25, 0x10,
0x06, 0x04, 0x51, 0x07, 0x26, 0x47, 0x07, 0x01, 0x10, 0x08, 0x05, 0x51,
0x09, 0x00, 0x53, 0x02, 0x04, 0x10, 0x03, 0x06, 0x10, 0x04, 0x02, 0x0e,
0x05, 0x59, 0x9c, 0x10, 0x06, 0x03, 0x51, 0x07, 0x27, 0x10, 0x08, 0x04,
0x51, 0x09, 0x28, 0x51, 0x0a, 0x29, 0x51, 0x0b, 0x2a, 0x47, 0x09, 0x03,
0x10, 0x0a, 0x05, 0x51, 0x0b, 0x00, 0x53, 0x04, 0x04, 0x10, 0x05, 0x07,
0x10, 0x06, 0x02, 0x0f, 0x07, 0x00, 0xa8, 0xb9, 0xcc, 0x10, 0x08, 0x03,
0x51, 0x09, 0x2b, 0x10, 0x0a, 0x04, 0x51, 0x0b, 0x2c, 0x51, 0x0c, 0x2d,
0x47, 0x0b, 0x02, 0x10, 0x0c, 0x05, 0x51, 0x0d, 0x00, 0x53, 0x06, 0x04,
0x10, 0x07, 0x08, 0x10, 0x08, 0x02, 0x0f, 0x09, 0x00, 0x36, 0xa3, 0xd9,
0x10, 0x0a, 0x03, 0x51, 0x0b, 0x2e, 0x10, 0x0c, 0x04, 0x51, 0x0d, 0x2f,
0x47, 0x0d, 0x01, 0x10, 0x0e, 0x05, 0x51, 0x0f, 0x0d, 0x53, 0x08, 0x04,
0x10, 0x09, 0x09, 0x10, 0x0a, 0x02, 0x0f, 0x0b, 0x00, 0x4d, 0x5a, 0x5e,
0x10, 0x0c, 0x03, 0x51, 0x0d, 0x30, 0x10, 0x0e, 0x04, 0x51, 0x0f, 0x31,
0x47, 0x0f, 0x01, 0x10, 0x10, 0x05, 0x51, 0x11, 0x10, 0x53, 0x0a, 0x04,
0x10, 0x0b, 0x0a, 0x10, 0x0c, 0x02, 0x0f, 0x0d, 0x00, 0x00, 0xad, 0xd8,
0x10, 0x0e, 0x03, 0x51, 0x0f, 0x32, 0x10, 0x10, 0x04, 0x51, 0x11, 0x33,
0x47, 0x11, 0x01, 0x10, 0x12, 0x05, 0x51, 0x13, 0x11, 0x53, 0x0c, 0x04,
0x10, 0x0d, 0x0b, 0x10, 0x0e, 0x02, 0x0f, 0x0f, 0x00, 0x00, 0xad, 0xd8,
0x10, 0x10, 0x03, 0x51, 0x11, 0x32, 0x10, 0x12, 0x04, 0x51, 0x13, 0x34,
0x47, 0x13, 0x01, 0x10, 0x14, 0x05, 0x51, 0x15, 0x11, 0x53, 0x0e, 0x04,
0x10, 0x0f, 0x0c, 0x10, 0x10, 0x02, 0x0f, 0x11, 0x00, 0xa0, 0x74, 0xc4,
0x10, 0x12, 0x03, 0x51, 0x13, 0x35, 0x10, 0x14, 0x04, 0x51, 0x15, 0x36,
0x51, 0x16, 0x37, 0x47, 0x15, 0x02, 0x10, 0x16, 0x05, 0x51, 0x17, 0x13,
0x53, 0x10, 0x04, 0x10, 0x11, 0x0d, 0x10, 0x12, 0x02, 0x0f, 0x13, 0x00,
0xef, 0x8a, 0x91, 0x10, 0x14, 0x03, 0x51, 0x15, 0x38, 0x10, 0x16, 0x04,
0x51, 0x17, 0x39, 0x51, 0x18, 0x3a, 0x47, 0x17, 0x02, 0x10, 0x18, 0x05,
0x51, 0x19, 0x15, 0x53, 0x12, 0x04, 0x10, 0x13, 0x0e, 0x10, 0x14, 0x02,
0x0f, 0x15, 0x00, 0xf0, 0xdf, 0x8a, 0x10, 0x16, 0x03, 0x51, 0x17, 0x3b,
0x10, 0x18, 0x04, 0x51, 0x19, 0x3c, 0x47, 0x19, 0x01, 0x10, 0x1a, 0x05,
0x51, 0x1b, 0x16, 0x53, 0x14, 0x04, 0x10, 0x15, 0x0f, 0x10, 0x16, 0x02,
0x0f, 0x17, 0x00, 0x36, 0xa3, 0xd9, 0x10, 0x18, 0x03, 0x51, 0x19, 0x3d,
0x10, 0x1a, 0x04, 0x51, 0x1b, 0x3e, 0x47, 0x1b, 0x01, 0x10, 0x1c, 0x05,
0x51, 0x1d, 0x16, 0x53, 0x16, 0x04, 0x10, 0x17, 0x10, 0x10, 0x18, 0x02,
0x0f, 0x19, 0x00, 0xcb, 0xcb, 0x41, 0x10, 0x1a, 0x03, 0x51, 0x1b, 0x3f,
0x10, 0x1c, 0x04, 0x51, 0x1d, 0x40, 0x47, 0x1d, 0x01, 0x10, 0x1e, 0x05,
0x51, 0x1f, 0x0f, 0x53, 0x18, 0x04, 0x10, 0x19, 0x11, 0x10, 0x1a, 0x02,
0x0f, 0x1b, 0x00, 0xcb, 0xcb, 0x41, 0x10, 0x1c, 0x03, 0x51, 0x1d, 0x3f,
0x10, 0x1e, 0x04, 0x51, 0x1f, 0x41, 0x47, 0x1f, 0x01, 0x10, 0x20, 0x05,
0x51, 0x21, 0x0f, 0x53, 0x1a, 0x04, 0x10, 0x1b, 0x12, 0x10, 0x1c, 0x02,
0x0f, 0x1d, 0x00, 0x6e, 0x15, 0x16, 0x10, 0x1e, 0x03, 0x51, 0x1f, 0x38,
0x10, 0x20, 0x04, 0x51, 0x21, 0x42, 0x47, 0x21, 0x01, 0x10, 0x22, 0x05,
0x51, 0x23, 0x08, 0x53, 0x1c, 0x04, 0x10, 0x1d, 0x13, 0x10, 0x1e, 0x02,
0x0f, 0x1f, 0x00, 0x36, 0xa3, 0xd9, 0x10, 0x20, 0x03, 0x51, 0x21, 0x43,
0x10, 0x22, 0x04, 0x51, 0x23, 0x44, 0x47, 0x23, 0x01, 0x10, 0x24, 0x05,
0x51, 0x25, 0x17, 0x53, 0x1e, 0x04, 0x10, 0x1f, 0x14, 0x10, 0x20, 0x02,
0x0f, 0x21, 0x00, 0x95, 0xe6, 0xcb, 0x10, 0x22, 0x03, 0x51, 0x23, 0x45,
0x10, 0x24, 0x04, 0x51, 0x25, 0x46, 0x47, 0x25, 0x01, 0x10, 0x26, 0x05,
0x51, 0x27, 0x47, 0x53, 0x20, 0x04, 0x10, 0x21, 0x15, 0x10, 0x22, 0x02,
0x0f, 0x23, 0x00, 0xde, 0xa5, 0x84, 0x10, 0x24, 0x03, 0x51, 0x25, 0x48,
0x10, 0x26, 0x04, 0x51, 0x27, 0x49, 0x47, 0x27, 0x01, 0x10, 0x28, 0x05,
0x51, 0x29, 0x19, 0x53, 0x22, 0x04, 0x10, 0x23, 0x16, 0x10, 0x24, 0x02,
0x0f, 0x25, 0x00, 0xa0, 0x74, 0xc4, 0x10, 0x26, 0x03, 0x51, 0x27, 0x4a,
0x10, 0x28, 0x04, 0x51, 0x29, 0x4b, 0x47, 0x29, 0x01, 0x10, 0x2a, 0x05,
0x51, 0x2b, 0x1a, 0x53, 0x24, 0x04, 0x10, 0x25, 0x17, 0x10, 0x26, 0x02,
0x0f, 0x27, 0x00, 0x36, 0xa3, 0xd9, 0x10, 0x28, 0x03, 0x51, 0x29, 0x4c,
0x10, 0x2a, 0x04, 0x51, 0x2b, 0x4d, 0x51, 0x2c, 0x4e, 0x47, 0x2b, 0x02,
0x10, 0x2c, 0x05, 0x51, 0x2d, 0x1b, 0x53, 0x26, 0x04, 0x10, 0x27, 0x18,
0x10, 0x28, 0x02, 0x0f, 0x29, 0x00, 0x6d, 0x80, 0x86, 0x10, 0x2a, 0x03,
0x51, 0x2b, 0x4f, 0x10, 0x2c, 0x04, 0x51, 0x2d, 0x50, 0x47, 0x2d, 0x01,
0x10, 0x2e, 0x05, 0x51, 0x2f, 0x1d, 0x53, 0x28, 0x04, 0x10, 0x29, 0x19,
0x10, 0x2a, 0x02, 0x0f, 0x2b, 0x00, 0x36, 0xa3, 0xd9, 0x10, 0x2c, 0x03,
0x51, 0x2d, 0x51, 0x10, 0x2e, 0x04, 0x51, 0x2f, 0x52, 0x47, 0x2f, 0x01,
0x10, 0x30, 0x05, 0x51, 0x31, 0x1e, 0x53, 0x2a, 0x04, 0x10, 0x2b, 0x1a,
0x10, 0x2c, 0x02, 0x0f, 0x2d, 0x00, 0x6d, 0x80, 0x86, 0x10, 0x2e, 0x03,
0x51, 0x2f, 0x4f, 0x10, 0x30, 0x04, 0x51, 0x31, 0x53, 0x51, 0x32, 0x54,
0x47, 0x31, 0x02, 0x10, 0x32, 0x05, 0x51, 0x33, 0x1f, 0x53, 0x2c, 0x04,
0x10, 0x2d, 0x1b, 0x10, 0x2e, 0x02, 0x0f, 0x2f, 0x00, 0xda, 0xd8, 0xd8,
0x10, 0x30, 0x03, 0x51, 0x31, 0x55, 0x10, 0x32, 0x04, 0x51, 0x33, 0x56,
0x47, 0x33, 0x01, 0x10, 0x34, 0x05, 0x51, 0x35, 0x20, 0x53, 0x2e, 0x04,
0x10, 0x2f, 0x1c, 0x10, 0x30, 0x02, 0x0f, 0x31, 0x00, 0x4e, 0x5c, 0x61,
0x10, 0x32, 0x03, 0x51, 0x33, 0x57, 0x10, 0x34, 0x04, 0x51, 0x35, 0x58,
0x51, 0x36, 0x59, 0x47, 0x35, 0x02, 0x10, 0x36, 0x05, 0x51, 0x37, 0x21,
0x53, 0x30, 0x04, 0x10, 0x31, 0x1d, 0x10, 0x32, 0x02, 0x0f, 0x33, 0x00,
0x6d, 0x80, 0x86, 0x10, 0x34, 0x03, 0x51, 0x35, 0x5a, 0x10, 0x36, 0x04,
0x51, 0x37, 0x5b, 0x47, 0x37, 0x01, 0x53, 0x32, 0x03, 0x10, 0x33, 0x1e,
0x10, 0x34, 0x02, 0x0f, 0x35, 0x00, 0xda, 0xd8, 0xd8, 0x10, 0x36, 0x03,
0x51, 0x37, 0x5c, 0x10, 0x38, 0x04, 0x51, 0x39, 0x5d, 0x47, 0x39, 0x01,
0x53, 0x34, 0x03, 0x10, 0x35, 0x1f, 0x10, 0x36, 0x02, 0x0f, 0x37, 0x00,
0xdd, 0x4c, 0x35, 0x10, 0x38, 0x03, 0x51, 0x39, 0x5e, 0x10, 0x3a, 0x04,
0x51, 0x3b, 0x5f, 0x51, 0x3c, 0x60, 0x47, 0x3b, 0x02, 0x53, 0x36, 0x03,
0x10, 0x37, 0x20, 0x10, 0x38, 0x02, 0x0f, 0x39, 0x00, 0xf0, 0x50, 0x32,
0x10, 0x3a, 0x03, 0x51, 0x3b, 0x61, 0x10, 0x3c, 0x04, 0x51, 0x3d, 0x62,
0x47, 0x3d, 0x01, 0x53, 0x38, 0x03, 0x10, 0x39, 0x21, 0x10, 0x3a, 0x02,
0x0f, 0x3b, 0x00, 0xf0, 0x50, 0x32, 0x10, 0x3c, 0x03, 0x51, 0x3d, 0x61,
0x10, 0x3e, 0x04, 0x51, 0x3f, 0x63, 0x47, 0x3f, 0x01, 0x53, 0x3a, 0x03,
0x10, 0x3b, 0x22, 0x10, 0x3c, 0x02, 0x0f, 0x3d, 0x00, 0x9e, 0x9e, 0x9e,
0x10, 0x3e, 0x03, 0x51, 0x3f, 0x64, 0x10, 0x40, 0x04, 0x51, 0x41, 0x65,
0x47, 0x41, 0x01, 0x53, 0x3c, 0x03, 0x10, 0x3d, 0x23, 0x10, 0x3e, 0x02,
0x0f, 0x3f, 0x00, 0x6d, 0x80, 0x86, 0x10, 0x40, 0x03, 0x51, 0x41, 0x4f,
0x10, 0x42, 0x04, 0x51, 0x43, 0x66, 0x47, 0x43, 0x01, 0x53, 0x3e, 0x03,
0x10, 0x3f, 0x24, 0x10, 0x40, 0x02, 0x0f, 0x41, 0x00, 0xff, 0x80, 0x87,
0x10, 0x42, 0x03, 0x51, 0x43, 0x67, 0x10, 0x44, 0x04, 0x51, 0x45, 0x68,
0x47, 0x45, 0x01, 0x10, 0x46, 0x25, 0x51, 0x47, 0x69, 0x47, 0x47, 0x01,
0x10, 0x48, 0x05, 0x51, 0x49, 0x09, 0x53, 0x40, 0x05, 0x10, 0x41, 0x26,
0x10, 0x42, 0x02, 0x0f, 0x43, 0x00, 0x4d, 0x5a, 0x5e, 0x10, 0x44, 0x03,
0x51, 0x45, 0x6a, 0x10, 0x46, 0x04, 0x51, 0x47, 0x6b, 0x47, 0x47, 0x01,
0x10, 0x48, 0x25, 0x51, 0x49, 0x6c, 0x51, 0x4a, 0x6d, 0x47, 0x49, 0x02,
0x10, 0x4a, 0x05, 0x51, 0x4b, 0x0b, 0x53, 0x42, 0x05, 0x53, 0x01, 0x21,
0x1a, 0x01, 0x27, 0x10, 0x01, 0x28, 0x10, 0x02, 0x29, 0x0f, 0x03, 0x00,
0xee, 0xee, 0xee, 0x53, 0x02, 0x01, 0x10, 0x03, 0x2a, 0x10, 0x04, 0x29,
0x0f, 0x05, 0x00, 0x7d, 0xcf, 0xff, 0x53, 0x04, 0x01, 0x10, 0x05, 0x2b,
0x10, 0x06, 0x29, 0x0f, 0x07, 0x00, 0xef, 0x51, 0x68, 0x53, 0x06, 0x01,
0x10, 0x07, 0x2c, 0x10, 0x08, 0x29, 0x0f, 0x09, 0x00, 0xaa, 0xaa, 0xaa,
0x10, 0x0a, 0x2d, 0x13, 0x0b, 0x53, 0x08, 0x02, 0x10, 0x09, 0x2e, 0x10,
0x0a, 0x29, 0x0f, 0x0b, 0x00, 0xaa, 0xd9, 0x4c, 0x53, 0x0a, 0x01, 0x10,
0x0b, 0x2f, 0x10, 0x0c, 0x29, 0x0f, 0x0d, 0x00, 0x7d, 0xcf, 0xff, 0x53,
0x0c, 0x01, 0x10, 0x0d, 0x30, 0x10, 0x0e, 0x29, 0x0f, 0x0f, 0x00, 0x7d,
0xcf, 0xff, 0x53, 0x0e, 0x01, 0x10, 0x0f, 0x31, 0x10, 0x10, 0x29, 0x0f,
0x11, 0x00, 0xd2, 0xa6, 0xff, 0x53, 0x10, 0x01, 0x10, 0x11, 0x32, 0x10,
0x12, 0x29, 0x0f, 0x13, 0x00, 0xe6, 0xc0, 0x8a, 0x53, 0x12, 0x01, 0x10,
0x13, 0x33, 0x10, 0x14, 0x29, 0x0f, 0x15, 0x00, 0x7a, 0xe9, 0x3c, 0x53,
0x14, 0x01, 0x10, 0x15, 0x34, 0x10, 0x16, 0x29, 0x0f, 0x17, 0x00, 0xef,
0x51, 0x68, 0x53, 0x16, 0x01, 0x10, 0x17, 0x35, 0x10, 0x18, 0x29, 0x0f,
0x19, 0x00, 0xff, 0xaf, 0x70, 0x53, 0x18, 0x01, 0x10, 0x19, 0x36, 0x10,
0x1a, 0x29, 0x0f, 0x1b, 0x00, 0xff, 0x8f, 0x40, 0x53, 0x1a, 0x01, 0x10,
0x1b, 0x37, 0x10, 0x1c, 0x29, 0x0f, 0x1d, 0x00, 0xf0, 0x71, 0x78, 0x53,
0x1c, 0x01, 0x10, 0x1d, 0x38, 0x10, 0x1e, 0x29, 0x0f, 0x1f, 0x00, 0xff,
0xff, 0xff, 0x10, 0x20, 0x2d, 0x13, 0x21, 0x53, 0x1e, 0x02, 0x10, 0x1f,
0x39, 0x10, 0x20, 0x29, 0x0f, 0x21, 0x00, 0xff, 0xaf, 0x70, 0x53, 0x20,
0x01, 0x10, 0x21, 0x3a, 0x10, 0x22, 0x29, 0x0f, 0x23, 0x00, 0xf0, 0x71,
0x78, 0x53, 0x22, 0x01, 0x10, 0x23, 0x3b, 0x10, 0x24, 0x29, 0x0f, 0x25,
0x00, 0x7d, 0xcf, 0xff, 0x53, 0x24, 0x01, 0x10, 0x25, 0x3c, 0x10, 0x26,
0x29, 0x0f, 0x27, 0x00, 0x95, 0xe6, 0xcb, 0x53, 0x26, 0x01, 0x10, 0x27,
0x3d, 0x10, 0x28, 0x29, 0x0f, 0x29, 0x00, 0xf0, 0x71, 0x78, 0x53, 0x28,
0x01, 0x10, 0x29, 0x3e, 0x10, 0x2a, 0x29, 0x0f, 0x2b, 0x00, 0x7d, 0xcf,
0xff, 0x53, 0x2a, 0x01, 0x10, 0x2b, 0x3f, 0x10, 0x2c, 0x29, 0x0f, 0x2d,
0x00, 0xff, 0x8f, 0x40, 0x53, 0x2c, 0x01, 0x10, 0x2d, 0x40, 0x10, 0x2e,
0x29, 0x0f, 0x2f, 0x00, 0xd2, 0xa6, 0xff, 0x53, 0x2e, 0x01, 0x10, 0x2f,
0x41, 0x10, 0x30, 0x29, 0x0f, 0x31, 0x00, 0xd2, 0xa6, 0xff, 0x53, 0x30,
0x01, 0x10, 0x31, 0x42, 0x10, 0x32, 0x29, 0x0f, 0x33, 0x00, 0xff, 0xaf,
0xaf, 0x53, 0x32, 0x01, 0x10, 0x33, 0x43, 0x10, 0x34, 0x29, 0x0f, 0x35,
0x00, 0xff, 0xff, 0x00, 0x53, 0x34, 0x01, 0x10, 0x35, 0x44, 0x10, 0x36,
0x29, 0x0f, 0x37, 0x00, 0x0f, 0xff, 0x0f, 0x53, 0x36, 0x01, 0x10, 0x37,
0x45, 0x10, 0x38, 0x29, 0x0f, 0x39, 0x00, 0xff, 0x0f, 0x0f, 0x53, 0x38,
0x01, 0x53, 0x01, 0x1c, 0x1a, 0x01, 0x46, 0x10, 0x01, 0x47, 0x1a, 0x01,
0x48, 0x53, 0x01, 0x00, 0x1a, 0x01, 0x49, 0x53, 0x01, 0x00, 0x1a, 0x01,
0x4a, 0x53, 0x01, 0x00, 0x1a, 0x01, 0x4b, 0x11, 0x01, 0x1a, 0x01, 0x4c,
0x11, 0x01, 0x1a, 0x01, 0x4d, 0x57, 0x02, 0x00, 0x2e, 0x01, 0x4e, 0x00,
0x1a, 0x01, 0x4f, 0x12, 0x01, 0x62, 0x01, 0x5e, 0x01, 0x01, 0x38, 0x01,
0x00, 0x6e, 0x00, 0x00, 0x06, 0x63, 0x6c, 0x61, 0x6e, 0x67, 0x64, 0x00,
0x00, 0x00, 0x12, 0x2d, 0x2d, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f,
0x75, 0x6e, 0x64, 0x2d, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x00, 0x00, 0x00,
0x0c, 0x2d, 0x2d, 0x63, 0x6c, 0x61, 0x6e, 0x67, 0x2d, 0x74, 0x69, 0x64,
0x79, 0x00, 0x00, 0x00, 0x1b, 0x2d, 0x2d, 0x63, 0x6f, 0x6d, 0x70, 0x6c,
0x65, 0x74, 0x69, 0x6f, 0x6e, 0x2d, 0x73, 0x74, 0x79, 0x6c, 0x65, 0x3d,
0x64, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x65, 0x64, 0x00, 0x00, 0x00, 0x18,
0x2d, 0x2d, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x2d, 0x69, 0x6e, 0x73,
0x65, 0x72, 0x74, 0x69, 0x6f, 0x6e, 0x3d, 0x6e, 0x65, 0x76, 0x65, 0x72,
0x00, 0x00, 0x00, 0x14, 0x2d, 0x2d, 0x70, 0x63, 0x68, 0x2d, 0x73, 0x74,
0x6f, 0x72, 0x61, 0x67, 0x65, 0x3d, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79,
0x00, 0x00, 0x00, 0x12, 0x2d, 0x2d, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x2d,
0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x3d, 0x35, 0x30, 0x00, 0x00,
0x00, 0x0b, 0x2d, 0x2d, 0x6c, 0x6f, 0x67, 0x3d, 0x65, 0x72, 0x72, 0x6f,
0x72, 0x00, 0x00, 0x00, 0x08, 0x72, 0x75, 0x62, 0x79, 0x2d, 0x6c, 0x73,
0x70, 0x00, 0x00, 0x00, 0x0a, 0x73, 0x6f, 0x6c, 0x61, 0x72, 0x67, 0x72,
0x61, 0x70, 0x68, 0x00, 0x00, 0x00, 0x05, 0x73, 0x74, 0x64, 0x69, 0x6f,
0x00, 0x00, 0x00, 0x14, 0x62, 0x61, 0x73, 0x68, 0x2d, 0x6c, 0x61, 0x6e,
0x67, 0x75, 0x61, 0x67, 0x65, 0x2d, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72,
0x00, 0x00, 0x00, 0x05, 0x73, 0x74, 0x61, 0x72, 0x74, 0x00, 0x00, 0x00,
0x1a, 0x76, 0x73, 0x63, 0x6f, 0x64, 0x65, 0x2d, 0x63, 0x73, 0x73, 0x2d,
0x6c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x2d, 0x73, 0x65, 0x72,
0x76, 0x65, 0x72, 0x00, 0x00, 0x00, 0x07, 0x2d, 0x2d, 0x73, 0x74, 0x64,
0x69, 0x6f, 0x00, 0x00, 0x00, 0x1b, 0x76, 0x73, 0x63, 0x6f, 0x64, 0x65,
0x2d, 0x6a, 0x73, 0x6f, 0x6e, 0x2d, 0x6c, 0x61, 0x6e, 0x67, 0x75, 0x61,
0x67, 0x65, 0x2d, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x00, 0x00, 0x00,
0x08, 0x66, 0x69, 0x73, 0x68, 0x2d, 0x6c, 0x73, 0x70, 0x00, 0x00, 0x00,
0x05, 0x67, 0x6f, 0x70, 0x6c, 0x73, 0x00, 0x00, 0x00, 0x05, 0x73, 0x65,
0x72, 0x76, 0x65, 0x00, 0x00, 0x00, 0x17, 0x68, 0x61, 0x73, 0x6b, 0x65,
0x6c, 0x6c, 0x2d, 0x6c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x2d,
0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x00, 0x00, 0x00, 0x03, 0x6c, 0x73,
0x70, 0x00, 0x00, 0x00, 0x15, 0x65, 0x6d, 0x6d, 0x65, 0x74, 0x2d, 0x6c,
0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x2d, 0x73, 0x65, 0x72, 0x76,
0x65, 0x72, 0x00, 0x00, 0x00, 0x1a, 0x74, 0x79, 0x70, 0x65, 0x73, 0x63,
0x72, 0x69, 0x70, 0x74, 0x2d, 0x6c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67,
0x65, 0x2d, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x00, 0x00, 0x00, 0x13,
0x6c, 0x75, 0x61, 0x2d, 0x6c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65,
0x2d, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x00, 0x00, 0x00, 0x12, 0x70,
0x79, 0x72, 0x69, 0x67, 0x68, 0x74, 0x2d, 0x6c, 0x61, 0x6e, 0x67, 0x73,
0x65, 0x72, 0x76, 0x65, 0x72, 0x00, 0x00, 0x00, 0x0d, 0x72, 0x75, 0x73,
0x74, 0x2d, 0x61, 0x6e, 0x61, 0x6c, 0x79, 0x7a, 0x65, 0x72, 0x00, 0x00,
0x00, 0x0c, 0x69, 0x6e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x68, 0x65, 0x6e,
0x73, 0x65, 0x00, 0x00, 0x00, 0x08, 0x6d, 0x61, 0x72, 0x6b, 0x73, 0x6d,
0x61, 0x6e, 0x00, 0x00, 0x00, 0x06, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72,
0x00, 0x00, 0x00, 0x15, 0x6e, 0x67, 0x69, 0x6e, 0x78, 0x2d, 0x6c, 0x61,
0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x2d, 0x73, 0x65, 0x72, 0x76, 0x65,
0x72, 0x00, 0x00, 0x00, 0x05, 0x74, 0x61, 0x70, 0x6c, 0x6f, 0x00, 0x00,
0x00, 0x14, 0x79, 0x61, 0x6d, 0x6c, 0x2d, 0x6c, 0x61, 0x6e, 0x67, 0x75,
0x61, 0x67, 0x65, 0x2d, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x00, 0x00,
0x00, 0x04, 0x73, 0x71, 0x6c, 0x73, 0x00, 0x00, 0x00, 0x14, 0x6d, 0x61,
0x6b, 0x65, 0x2d, 0x6c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x2d,
0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x00, 0x00, 0x00, 0x13, 0x73, 0x71,
0x6c, 0x2d, 0x6c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x2d, 0x73,
0x65, 0x72, 0x76, 0x65, 0x72, 0x00, 0x00, 0x00, 0x02, 0x75, 0x70, 0x00,
0x00, 0x00, 0x08, 0x2d, 0x2d, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x00,
0x00, 0x00, 0x04, 0xee, 0x98, 0x9e, 0x20, 0x00, 0x00, 0x00, 0x01, 0x63,
0x00, 0x00, 0x00, 0x04, 0xee, 0x98, 0x9d, 0x20, 0x00, 0x00, 0x00, 0x03,
0x63, 0x70, 0x70, 0x00, 0x00, 0x00, 0x02, 0x63, 0x63, 0x00, 0x00, 0x00,
0x03, 0x63, 0x78, 0x78, 0x00, 0x00, 0x00, 0x04, 0xef, 0x83, 0xbd, 0x20,
0x00, 0x00, 0x00, 0x01, 0x68, 0x00, 0x00, 0x00, 0x03, 0x68, 0x70, 0x70,
0x00, 0x00, 0x00, 0x04, 0xee, 0x9a, 0xb8, 0x20, 0x00, 0x00, 0x00, 0x03,
0x63, 0x73, 0x73, 0x00, 0x00, 0x00, 0x04, 0xee, 0xb9, 0x81, 0x20, 0x00,
0x00, 0x00, 0x04, 0x66, 0x69, 0x73, 0x68, 0x00, 0x00, 0x00, 0x04, 0xee,
0x98, 0xa7, 0x20, 0x00, 0x00, 0x00, 0x02, 0x67, 0x6f, 0x00, 0x00, 0x00,
0x03, 0x6d, 0x6f, 0x64, 0x00, 0x00, 0x00, 0x04, 0xee, 0x9d, 0xb7, 0x20,
0x00, 0x00, 0x00, 0x02, 0x68, 0x73, 0x00, 0x00, 0x00, 0x03, 0x6c, 0x68,
0x73, 0x00, 0x00, 0x00, 0x04, 0xef, 0x84, 0xa1, 0x20, 0x00, 0x00, 0x00,
0x04, 0x68, 0x74, 0x6d, 0x6c, 0x00, 0x00, 0x00, 0x03, 0x68, 0x74, 0x6d,
0x00, 0x00, 0x00, 0x04, 0xef, 0x8b, 0xaf, 0x20, 0x00, 0x00, 0x00, 0x02,
0x6a, 0x73, 0x00, 0x00, 0x00, 0x04, 0xee, 0x9a, 0x9d, 0x20, 0x00, 0x00,
0x00, 0x02, 0x74, 0x73, 0x00, 0x00, 0x00, 0x02, 0x7b, 0x7d, 0x00, 0x00,
0x00, 0x04, 0x6a, 0x73, 0x6f, 0x6e, 0x00, 0x00, 0x00, 0x05, 0x6a, 0x73,
0x6f, 0x6e, 0x63, 0x00, 0x00, 0x00, 0x03, 0x65, 0x72, 0x62, 0x00, 0x00,
0x00, 0x05, 0xf3, 0xb0, 0xa2, 0xb1, 0x20, 0x00, 0x00, 0x00, 0x03, 0x6c,
0x75, 0x61, 0x00, 0x00, 0x00, 0x05, 0xf3, 0xb0, 0x8c, 0xa0, 0x20, 0x00,
0x00, 0x00, 0x02, 0x70, 0x79, 0x00, 0x00, 0x00, 0x07, 0x70, 0x79, 0x72,
0x69, 0x67, 0x68, 0x74, 0x00, 0x00, 0x00, 0x05, 0xf3, 0xb1, 0x98, 0x97,
0x20, 0x00, 0x00, 0x00, 0x02, 0x72, 0x73, 0x00, 0x00, 0x00, 0x05, 0xf3,
0xb0, 0x8c, 0x9f, 0x20, 0x00, 0x00, 0x00, 0x03, 0x70, 0x68, 0x70, 0x00,
0x00, 0x00, 0x04, 0xee, 0xba, 0xab, 0x20, 0x00, 0x00, 0x00, 0x02, 0x6d,
0x64, 0x00, 0x00, 0x00, 0x08, 0x6d, 0x61, 0x72, 0x6b, 0x64, 0x6f, 0x77,
0x6e, 0x00, 0x00, 0x00, 0x04, 0xee, 0x98, 0x95, 0x20, 0x00, 0x00, 0x00,
0x04, 0x63, 0x6f, 0x6e, 0x66, 0x00, 0x00, 0x00, 0x04, 0xee, 0x9a, 0xb2,
0x20, 0x00, 0x00, 0x00, 0x04, 0x74, 0x6f, 0x6d, 0x6c, 0x00, 0x00, 0x00,
0x03, 0x79, 0x6d, 0x6c, 0x00, 0x00, 0x00, 0x04, 0x79, 0x61, 0x6d, 0x6c,
0x00, 0x00, 0x00, 0x04, 0xee, 0x99, 0x8d, 0x20, 0x00, 0x00, 0x00, 0x03,
0x73, 0x71, 0x6c, 0x00, 0x00, 0x00, 0x04, 0xee, 0x99, 0xb3, 0x20, 0x00,
0x00, 0x00, 0x08, 0x4d, 0x61, 0x6b, 0x65, 0x66, 0x69, 0x6c, 0x65, 0x00,
0x00, 0x00, 0x08, 0x6d, 0x61, 0x6b, 0x65, 0x66, 0x69, 0x6c, 0x65, 0x00,
0x00, 0x00, 0x04, 0xee, 0x99, 0x9f, 0x20, 0x00, 0x00, 0x00, 0x02, 0x67,
0x64, 0x00, 0x00, 0x00, 0x04, 0xef, 0x80, 0xad, 0x20, 0x00, 0x00, 0x00,
0x03, 0x6d, 0x61, 0x6e, 0x00, 0x00, 0x00, 0x04, 0xee, 0x9c, 0xa8, 0x20,
0x00, 0x00, 0x00, 0x04, 0x64, 0x69, 0x66, 0x66, 0x00, 0x00, 0x00, 0x05,
0x70, 0x61, 0x74, 0x63, 0x68, 0x00, 0x00, 0x00, 0x04, 0xee, 0x99, 0x9d,
0x20, 0x00, 0x00, 0x00, 0x0d, 0x67, 0x69, 0x74, 0x61, 0x74, 0x74, 0x72,
0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x00, 0x00, 0x00, 0x09, 0x67, 0x69,
0x74, 0x69, 0x67, 0x6e, 0x6f, 0x72, 0x65, 0x00, 0x00, 0x00, 0x02, 0x2e,
0x2a, 0x00, 0x00, 0x00, 0x05, 0x72, 0x65, 0x67, 0x65, 0x78, 0x00, 0x00,
0x00, 0x03, 0x69, 0x6e, 0x69, 0x00, 0x00, 0x00, 0x05, 0xf3, 0xb0, 0xb4,
0xad, 0x20, 0x00, 0x00, 0x00, 0x02, 0x72, 0x62, 0x00, 0x00, 0x00, 0x07,
0x47, 0x65, 0x6d, 0x66, 0x69, 0x6c, 0x65, 0x00, 0x00, 0x00, 0x04, 0xee,
0xaf, 0x8a, 0x20, 0x00, 0x00, 0x00, 0x02, 0x73, 0x68, 0x00, 0x00, 0x00,
0x0c, 0x62, 0x61, 0x73, 0x68, 0x5f, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c,
0x65, 0x00, 0x00, 0x00, 0x06, 0x62, 0x61, 0x73, 0x68, 0x72, 0x63, 0x00,
0x00, 0x50, 0x00, 0x0b, 0x40, 0x6c, 0x73, 0x70, 0x5f, 0x63, 0x6f, 0x6e,
0x66, 0x69, 0x67, 0x00, 0x00, 0x01, 0x63, 0x00, 0x00, 0x05, 0x63, 0x6f,
0x6c, 0x6f, 0x72, 0x00, 0x00, 0x06, 0x73, 0x79, 0x6d, 0x62, 0x6f, 0x6c,
0x00, 0x00, 0x0a, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e,
0x73, 0x00, 0x00, 0x03, 0x6c, 0x73, 0x70, 0x00, 0x00, 0x03, 0x63, 0x70,
0x70, 0x00, 0x00, 0x01, 0x68, 0x00, 0x00, 0x03, 0x63, 0x73, 0x73, 0x00,
0x00, 0x04, 0x66, 0x69, 0x73, 0x68, 0x00, 0x00, 0x02, 0x67, 0x6f, 0x00,
0x00, 0x05, 0x67, 0x6f, 0x6d, 0x6f, 0x64, 0x00, 0x00, 0x07, 0x68, 0x61,
0x73, 0x6b, 0x65, 0x6c, 0x6c, 0x00, 0x00, 0x04, 0x68, 0x74, 0x6d, 0x6c,
0x00, 0x00, 0x0a, 0x6a, 0x61, 0x76, 0x61, 0x73, 0x63, 0x72, 0x69, 0x70,
0x74, 0x00, 0x00, 0x0a, 0x74, 0x79, 0x70, 0x65, 0x73, 0x63, 0x72, 0x69,
0x70, 0x74, 0x00, 0x00, 0x04, 0x6a, 0x73, 0x6f, 0x6e, 0x00, 0x00, 0x05,
0x6a, 0x73, 0x6f, 0x6e, 0x63, 0x00, 0x00, 0x03, 0x65, 0x72, 0x62, 0x00,
0x00, 0x03, 0x6c, 0x75, 0x61, 0x00, 0x00, 0x06, 0x70, 0x79, 0x74, 0x68,
0x6f, 0x6e, 0x00, 0x00, 0x04, 0x72, 0x75, 0x73, 0x74, 0x00, 0x00, 0x03,
0x70, 0x68, 0x70, 0x00, 0x00, 0x08, 0x6d, 0x61, 0x72, 0x6b, 0x64, 0x6f,
0x77, 0x6e, 0x00, 0x00, 0x05, 0x6e, 0x67, 0x69, 0x6e, 0x78, 0x00, 0x00,
0x04, 0x74, 0x6f, 0x6d, 0x6c, 0x00, 0x00, 0x04, 0x79, 0x61, 0x6d, 0x6c,
0x00, 0x00, 0x03, 0x73, 0x71, 0x6c, 0x00, 0x00, 0x04, 0x6d, 0x61, 0x6b,
0x65, 0x00, 0x00, 0x08, 0x67, 0x64, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74,
0x00, 0x00, 0x03, 0x6d, 0x61, 0x6e, 0x00, 0x00, 0x04, 0x64, 0x69, 0x66,
0x66, 0x00, 0x00, 0x0d, 0x67, 0x69, 0x74, 0x61, 0x74, 0x74, 0x72, 0x69,
0x62, 0x75, 0x74, 0x65, 0x73, 0x00, 0x00, 0x09, 0x67, 0x69, 0x74, 0x69,
0x67, 0x6e, 0x6f, 0x72, 0x65, 0x00, 0x00, 0x05, 0x72, 0x65, 0x67, 0x65,
0x78, 0x00, 0x00, 0x03, 0x69, 0x6e, 0x69, 0x00, 0x00, 0x04, 0x72, 0x75,
0x62, 0x79, 0x00, 0x00, 0x09, 0x66, 0x69, 0x6c, 0x65, 0x6e, 0x61, 0x6d,
0x65, 0x73, 0x00, 0x00, 0x04, 0x62, 0x61, 0x73, 0x68, 0x00, 0x00, 0x0a,
0x40, 0x6c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x73, 0x00, 0x00,
0x07, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x00, 0x00, 0x02, 0x66,
0x67, 0x00, 0x00, 0x07, 0x73, 0x68, 0x65, 0x62, 0x61, 0x6e, 0x67, 0x00,
0x00, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x00, 0x00, 0x07, 0x63, 0x6f,
0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x00, 0x00, 0x06, 0x69, 0x74, 0x61, 0x6c,
0x69, 0x63, 0x00, 0x00, 0x06, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x00,
0x00, 0x06, 0x65, 0x73, 0x63, 0x61, 0x70, 0x65, 0x00, 0x00, 0x0d, 0x69,
0x6e, 0x74, 0x65, 0x72, 0x70, 0x6f, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e,
0x00, 0x00, 0x06, 0x72, 0x65, 0x67, 0x65, 0x78, 0x70, 0x00, 0x00, 0x06,
0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x00, 0x00, 0x04, 0x74, 0x72, 0x75,
0x65, 0x00, 0x00, 0x05, 0x66, 0x61, 0x6c, 0x73, 0x65, 0x00, 0x00, 0x04,
0x63, 0x68, 0x61, 0x72, 0x00, 0x00, 0x07, 0x6b, 0x65, 0x79, 0x77, 0x6f,
0x72, 0x64, 0x00, 0x00, 0x0f, 0x6b, 0x65, 0x79, 0x77, 0x6f, 0x72, 0x64,
0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x00, 0x00, 0x08, 0x6f,
0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x00, 0x00, 0x08, 0x66, 0x75,
0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x00, 0x00, 0x04, 0x74, 0x79, 0x70,
0x65, 0x00, 0x00, 0x08, 0x63, 0x6f, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x74,
0x00, 0x00, 0x10, 0x76, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x69,
0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x00, 0x00, 0x0e, 0x76, 0x61,
0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c,
0x00, 0x00, 0x0a, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f,
0x6e, 0x00, 0x00, 0x09, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x76,
0x65, 0x00, 0x00, 0x05, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x00, 0x00, 0x06,
0x62, 0x72, 0x61, 0x63, 0x65, 0x31, 0x00, 0x00, 0x06, 0x62, 0x72, 0x61,
0x63, 0x65, 0x32, 0x00, 0x00, 0x06, 0x62, 0x72, 0x61, 0x63, 0x65, 0x33,
0x00, 0x00, 0x06, 0x62, 0x72, 0x61, 0x63, 0x65, 0x34, 0x00, 0x00, 0x06,
0x62, 0x72, 0x61, 0x63, 0x65, 0x35, 0x00, 0x00, 0x06, 0x40, 0x74, 0x68,
0x65, 0x6d, 0x65, 0x00, 0x00, 0x09, 0x61, 0x75, 0x74, 0x6f, 0x5f, 0x75,
0x6e, 0x69, 0x78, 0x00, 0x00, 0x0d, 0x40, 0x6c, 0x69, 0x6e, 0x65, 0x5f,
0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x73, 0x00, 0x00, 0x0d, 0x40, 0x6b,
0x65, 0x79, 0x5f, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x72, 0x73, 0x00,
0x00, 0x0a, 0x40, 0x6b, 0x65, 0x79, 0x5f, 0x62, 0x69, 0x6e, 0x64, 0x73,
0x00, 0x00, 0x0d, 0x40, 0x68, 0x69, 0x67, 0x68, 0x6c, 0x69, 0x67, 0x68,
0x74, 0x65, 0x72, 0x73, 0x00, 0x00, 0x0a, 0x40, 0x62, 0x5f, 0x73, 0x74,
0x61, 0x72, 0x74, 0x75, 0x70, 0x00, 0x00, 0x0b, 0x40, 0x62, 0x5f, 0x73,
0x68, 0x75, 0x74, 0x64, 0x6f, 0x77, 0x6e, 0x00, 0x00, 0x06, 0x6c, 0x61,
0x6d, 0x62, 0x64, 0x61, 0x00, 0x00, 0x06, 0x40, 0x62, 0x5f, 0x62, 0x61,
0x72, 0x00, 0x00, 0x00, 0x03, 0x47, 0x00, 0x09, 0x00, 0x14, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x02, 0x17, 0x34, 0x04, 0x00, 0x00, 0x0f, 0x03,
0x00, 0x82, 0xaa, 0xff, 0x51, 0x04, 0x00, 0x01, 0x09, 0x01, 0x10, 0x0a,
0x00, 0x23, 0x09, 0x10, 0x0a, 0x01, 0x01, 0x0b, 0x09, 0x2f, 0x0a, 0x02,
0x01, 0x26, 0x0a, 0x00, 0x03, 0x25, 0x00, 0x0c, 0x0f, 0x03, 0x00, 0x82,
0xaa, 0xff, 0x51, 0x04, 0x01, 0x25, 0x00, 0x74, 0x10, 0x0a, 0x03, 0x01,
0x0b, 0x09, 0x2f, 0x0a, 0x02, 0x01, 0x26, 0x0a, 0x00, 0x03, 0x25, 0x00,
0x0c, 0x0f, 0x03, 0x00, 0xff, 0x8f, 0x40, 0x51, 0x04, 0x02, 0x25, 0x00,
0x57, 0x10, 0x0a, 0x04, 0x01, 0x0b, 0x09, 0x2f, 0x0a, 0x02, 0x01, 0x26,
0x0a, 0x00, 0x03, 0x25, 0x00, 0x0c, 0x0f, 0x03, 0x00, 0x9a, 0xde, 0x7a,
0x51, 0x04, 0x03, 0x25, 0x00, 0x3a, 0x10, 0x0a, 0x05, 0x01, 0x0b, 0x09,
0x2f, 0x0a, 0x02, 0x01, 0x26, 0x0a, 0x00, 0x03, 0x25, 0x00, 0x0c, 0x0f,
0x03, 0x00, 0xff, 0xd7, 0x00, 0x51, 0x04, 0x04, 0x25, 0x00, 0x1d, 0x10,
0x0a, 0x06, 0x01, 0x0b, 0x09, 0x2f, 0x0a, 0x02, 0x01, 0x26, 0x0a, 0x00,
0x03, 0x25, 0x00, 0x0c, 0x0f, 0x03, 0x00, 0xf2, 0x9c, 0xc3, 0x51, 0x04,
0x05, 0x25, 0x00, 0x00, 0x1d, 0x09, 0x07, 0x2f, 0x09, 0x08, 0x00, 0x01,
0x0a, 0x01, 0x10, 0x0b, 0x09, 0x23, 0x0a, 0x23, 0x09, 0x01, 0x05, 0x09,
0x1d, 0x09, 0x0a, 0x01, 0x0a, 0x01, 0x10, 0x0b, 0x0b, 0x23, 0x0a, 0x2f,
0x09, 0x0c, 0x01, 0x01, 0x06, 0x09, 0x51, 0x09, 0x06, 0x01, 0x0a, 0x04,
0x52, 0x09, 0x51, 0x0a, 0x06, 0x52, 0x09, 0x01, 0x0a, 0x01, 0x10, 0x0b,
0x00, 0x23, 0x0a, 0x2f, 0x0a, 0x0d, 0x00, 0x2f, 0x0a, 0x0e, 0x00, 0x52,
0x09, 0x51, 0x0a, 0x07, 0x52, 0x09, 0x01, 0x0a, 0x05, 0x10, 0x0b, 0x0f,
0x23, 0x0a, 0x52, 0x09, 0x51, 0x0a, 0x08, 0x52, 0x09, 0x01, 0x0a, 0x06,
0x52, 0x09, 0x51, 0x0a, 0x09, 0x52, 0x09, 0x01, 0x07, 0x09, 0x47, 0x08,
0x00, 0x01, 0x09, 0x08, 0x10, 0x0a, 0x10, 0x0f, 0x0b, 0x00, 0x0b, 0x0e,
0x14, 0x10, 0x0c, 0x11, 0x01, 0x0d, 0x03, 0x10, 0x0e, 0x12, 0x08, 0x0f,
0x10, 0x10, 0x13, 0x06, 0x11, 0x10, 0x12, 0x14, 0x03, 0x13, 0x0a, 0x53,
0x0a, 0x05, 0x2f, 0x09, 0x15, 0x01, 0x01, 0x09, 0x08, 0x10, 0x0a, 0x10,
0x01, 0x0b, 0x03, 0x10, 0x0c, 0x11, 0x0f, 0x0d, 0x00, 0x33, 0x36, 0x3c,
0x10, 0x0e, 0x13, 0x03, 0x0f, 0x0a, 0x10, 0x10, 0x14, 0x07, 0x11, 0x53,
0x0a, 0x04, 0x2f, 0x09, 0x15, 0x01, 0x01, 0x09, 0x08, 0x10, 0x0a, 0x10,
0x0f, 0x0b, 0x00, 0x33, 0x36, 0x3c, 0x10, 0x0c, 0x11, 0x0f, 0x0d, 0x00,
0x24, 0x27, 0x2d, 0x10, 0x0e, 0x13, 0x03, 0x0f, 0x0b, 0x10, 0x10, 0x14,
0x07, 0x11, 0x53, 0x0a, 0x04, 0x2f, 0x09, 0x15, 0x01, 0x01, 0x09, 0x08,
0x10, 0x0a, 0x10, 0x01, 0x0b, 0x05, 0x10, 0x0c, 0x16, 0x23, 0x0b, 0x10,
0x0c, 0x11, 0x0f, 0x0d, 0x00, 0x24, 0x27, 0x2d, 0x10, 0x0e, 0x13, 0x03,
0x0f, 0x0d, 0x10, 0x10, 0x14, 0x08, 0x11, 0x53, 0x0a, 0x04, 0x2f, 0x09,
0x15, 0x01, 0x01, 0x09, 0x08, 0x10, 0x0a, 0x10, 0x0f, 0x0b, 0x00, 0xce,
0xd4, 0xdf, 0x10, 0x0c, 0x11, 0x0f, 0x0d, 0x00, 0x24, 0x27, 0x2d, 0x10,
0x0e, 0x13, 0x03, 0x0f, 0x0f, 0x10, 0x10, 0x14, 0x01, 0x11, 0x06, 0x2f,
0x11, 0x14, 0x00, 0x53, 0x0a, 0x04, 0x2f, 0x09, 0x15, 0x01, 0x01, 0x09,
0x08, 0x10, 0x0a, 0x10, 0x0f, 0x0b, 0x00, 0x24, 0x27, 0x2d, 0x10, 0x0c,
0x11, 0x06, 0x0d, 0x10, 0x0e, 0x13, 0x03, 0x0f, 0x0f, 0x01, 0x10, 0x06,
0x2f, 0x10, 0x14, 0x00, 0x3c, 0x0f, 0x10, 0x10, 0x14, 0x07, 0x11, 0x53,
0x0a, 0x04, 0x2f, 0x09, 0x15, 0x01, 0x10, 0x09, 0x17, 0x01, 0x0a, 0x07,
0x10, 0x0b, 0x18, 0x01, 0x0c, 0x08, 0x53, 0x09, 0x02, 0x39, 0x09, 0x38,
0x09, 0x00, 0x0a, 0x00, 0x00, 0x02, 0x20, 0x20, 0x00, 0x00, 0x00, 0x04,
0xee, 0x99, 0x8e, 0x20, 0x00, 0x00, 0x00, 0x05, 0xf3, 0xb1, 0x93, 0xa7,
0x20, 0x00, 0x00, 0x00, 0x05, 0xf3, 0xb1, 0xa9, 0xa7, 0x20, 0x00, 0x00,
0x00, 0x04, 0xef, 0x84, 0xa0, 0x20, 0x00, 0x00, 0x00, 0x04, 0xee, 0xba,
0xa2, 0x20, 0x00, 0x00, 0x00, 0x01, 0x20, 0x00, 0x00, 0x00, 0x08, 0x20,
0xee, 0x82, 0xb4, 0xee, 0x82, 0xb4, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x03, 0xee, 0x82, 0xb4, 0x00, 0x00, 0x19, 0x00, 0x04, 0x6d,
0x6f, 0x64, 0x65, 0x00, 0x00, 0x06, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c,
0x00, 0x00, 0x03, 0x3d, 0x3d, 0x3d, 0x00, 0x00, 0x06, 0x69, 0x6e, 0x73,
0x65, 0x72, 0x74, 0x00, 0x00, 0x06, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74,
0x00, 0x00, 0x06, 0x72, 0x75, 0x6e, 0x6e, 0x65, 0x72, 0x00, 0x00, 0x06,
0x6a, 0x75, 0x6d, 0x70, 0x65, 0x72, 0x00, 0x00, 0x01, 0x43, 0x00, 0x00,
0x09, 0x6c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x73, 0x00, 0x00,
0x09, 0x6c, 0x61, 0x6e, 0x67, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x00, 0x00,
0x04, 0x46, 0x69, 0x6c, 0x65, 0x00, 0x00, 0x08, 0x66, 0x69, 0x6c, 0x65,
0x6e, 0x61, 0x6d, 0x65, 0x00, 0x00, 0x08, 0x62, 0x61, 0x73, 0x65, 0x6e,
0x61, 0x6d, 0x65, 0x00, 0x00, 0x04, 0x74, 0x6f, 0x5f, 0x73, 0x00, 0x00,
0x06, 0x75, 0x70, 0x63, 0x61, 0x73, 0x65, 0x00, 0x00, 0x06, 0x73, 0x79,
0x6d, 0x62, 0x6f, 0x6c, 0x00, 0x00, 0x02, 0x66, 0x67, 0x00, 0x00, 0x02,
0x62, 0x67, 0x00, 0x00, 0x05, 0x66, 0x6c, 0x61, 0x67, 0x73, 0x00, 0x00,
0x05, 0x73, 0x74, 0x61, 0x72, 0x74, 0x00, 0x00, 0x06, 0x6c, 0x65, 0x6e,
0x67, 0x74, 0x68, 0x00, 0x00, 0x02, 0x3c, 0x3c, 0x00, 0x00, 0x05, 0x63,
0x6f, 0x6c, 0x6f, 0x72, 0x00, 0x00, 0x04, 0x74, 0x65, 0x78, 0x74, 0x00,
0x00, 0x0a, 0x68, 0x69, 0x67, 0x68, 0x6c, 0x69, 0x67, 0x68, 0x74, 0x73,
0x00, 0x00, 0x00, 0x01, 0x1b, 0x00, 0x01, 0x00, 0x08, 0x00, 0x04, 0x00,
0x00, 0x00, 0x00, 0x00, 0x45, 0x10, 0x02, 0x00, 0x10, 0x03, 0x01, 0x10,
0x04, 0x02, 0x10, 0x05, 0x03, 0x10, 0x06, 0x04, 0x2d, 0x01, 0x05, 0x05,
0x10, 0x02, 0x06, 0x10, 0x03, 0x07, 0x10, 0x04, 0x08, 0x10, 0x05, 0x09,
0x2d, 0x01, 0x0a, 0x04, 0x63, 0x01, 0x58, 0x02, 0x00, 0x5f, 0x01, 0x0b,
0x63, 0x01, 0x58, 0x02, 0x01, 0x5f, 0x01, 0x0c, 0x63, 0x01, 0x58, 0x02,
0x02, 0x5f, 0x01, 0x0d, 0x63, 0x01, 0x58, 0x02, 0x03, 0x5f, 0x01, 0x0e,
0x38, 0x01, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x05, 0x74, 0x68, 0x65, 0x6d,
0x65, 0x00, 0x00, 0x0a, 0x6c, 0x73, 0x70, 0x5f, 0x63, 0x6f, 0x6e, 0x66,
0x69, 0x67, 0x00, 0x00, 0x09, 0x6c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67,
0x65, 0x73, 0x00, 0x00, 0x0c, 0x6c, 0x69, 0x6e, 0x65, 0x5f, 0x65, 0x6e,
0x64, 0x69, 0x6e, 0x67, 0x73, 0x00, 0x00, 0x0c, 0x68, 0x69, 0x67, 0x68,
0x6c, 0x69, 0x67, 0x68, 0x74, 0x65, 0x72, 0x73, 0x00, 0x00, 0x0d, 0x61,
0x74, 0x74, 0x72, 0x5f, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x6f, 0x72,
0x00, 0x00, 0x09, 0x62, 0x5f, 0x73, 0x74, 0x61, 0x72, 0x74, 0x75, 0x70,
0x00, 0x00, 0x0a, 0x62, 0x5f, 0x73, 0x68, 0x75, 0x74, 0x64, 0x6f, 0x77,
0x6e, 0x00, 0x00, 0x12, 0x62, 0x5f, 0x65, 0x78, 0x74, 0x72, 0x61, 0x5f,
0x68, 0x69, 0x67, 0x68, 0x6c, 0x69, 0x67, 0x68, 0x74, 0x73, 0x00, 0x00,
0x05, 0x62, 0x5f, 0x62, 0x61, 0x72, 0x00, 0x00, 0x0b, 0x61, 0x74, 0x74,
0x72, 0x5f, 0x72, 0x65, 0x61, 0x64, 0x65, 0x72, 0x00, 0x00, 0x07, 0x73,
0x74, 0x61, 0x72, 0x74, 0x75, 0x70, 0x00, 0x00, 0x08, 0x73, 0x68, 0x75,
0x74, 0x64, 0x6f, 0x77, 0x6e, 0x00, 0x00, 0x10, 0x65, 0x78, 0x74, 0x72,
0x61, 0x5f, 0x68, 0x69, 0x67, 0x68, 0x6c, 0x69, 0x67, 0x68, 0x74, 0x73,
0x00, 0x00, 0x04, 0x62, 0x69, 0x6e, 0x64, 0x00, 0x00, 0x00, 0x00, 0x2d,
0x00, 0x02, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c,
0x34, 0x00, 0x00, 0x01, 0x01, 0x02, 0x01, 0x1a, 0x02, 0x00, 0x38, 0x02,
0x00, 0x00, 0x00, 0x01, 0x00, 0x0a, 0x40, 0x62, 0x5f, 0x73, 0x74, 0x61,
0x72, 0x74, 0x75, 0x70, 0x00, 0x00, 0x00, 0x00, 0x2e, 0x00, 0x02, 0x00,
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x34, 0x00, 0x00,
0x01, 0x01, 0x02, 0x01, 0x1a, 0x02, 0x00, 0x38, 0x02, 0x00, 0x00, 0x00,
0x01, 0x00, 0x0b, 0x40, 0x62, 0x5f, 0x73, 0x68, 0x75, 0x74, 0x64, 0x6f,
0x77, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x36, 0x00, 0x02, 0x00, 0x03, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x34, 0x00, 0x00, 0x01, 0x01,
0x02, 0x01, 0x1a, 0x02, 0x00, 0x38, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00,
0x13, 0x40, 0x62, 0x5f, 0x65, 0x78, 0x74, 0x72, 0x61, 0x5f, 0x68, 0x69,
0x67, 0x68, 0x6c, 0x69, 0x67, 0x68, 0x74, 0x73, 0x00, 0x00, 0x00, 0x01,
0x43, 0x00, 0x07, 0x00, 0x0a, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
0xc1, 0x34, 0x04, 0x40, 0x01, 0x25, 0x00, 0x06, 0x25, 0x00, 0x05, 0x25,
0x00, 0x04, 0x11, 0x02, 0x11, 0x03, 0x01, 0x07, 0x01, 0x1d, 0x08, 0x00,
0x2f, 0x07, 0x01, 0x01, 0x26, 0x07, 0x00, 0x07, 0x01, 0x07, 0x01, 0x48,
0x01, 0x07, 0x01, 0x01, 0x07, 0x02, 0x28, 0x07, 0x00, 0x03, 0x25, 0x00,
0x33, 0x12, 0x05, 0x1d, 0x07, 0x02, 0x2f, 0x07, 0x03, 0x00, 0x01, 0x06,
0x07, 0x01, 0x07, 0x06, 0x10, 0x08, 0x04, 0x57, 0x09, 0x00, 0x30, 0x07,
0x05, 0x01, 0x2d, 0x07, 0x06, 0x00, 0x27, 0x07, 0x00, 0x0d, 0x01, 0x07,
0x06, 0x01, 0x08, 0x04, 0x30, 0x07, 0x07, 0x00, 0x25, 0x00, 0x02, 0x11,
0x07, 0x25, 0x00, 0x5c, 0x2d, 0x07, 0x06, 0x00, 0x27, 0x07, 0x00, 0x22,
0x01, 0x07, 0x02, 0x1d, 0x08, 0x00, 0x2f, 0x07, 0x01, 0x01, 0x26, 0x07,
0x00, 0x07, 0x01, 0x07, 0x02, 0x48, 0x02, 0x07, 0x01, 0x01, 0x07, 0x01,
0x57, 0x08, 0x01, 0x30, 0x07, 0x08, 0x00, 0x25, 0x00, 0x32, 0x01, 0x07,
0x03, 0x1d, 0x08, 0x09, 0x2f, 0x07, 0x01, 0x01, 0x27, 0x07, 0x00, 0x22,
0x01, 0x07, 0x02, 0x1d, 0x08, 0x00, 0x2f, 0x07, 0x01, 0x01, 0x26, 0x07,
0x00, 0x07, 0x01, 0x07, 0x02, 0x48, 0x02, 0x07, 0x01, 0x01, 0x07, 0x01,
0x57, 0x08, 0x02, 0x30, 0x07, 0x08, 0x00, 0x25, 0x00, 0x02, 0x11, 0x07,
0x38, 0x07, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x05, 0x41, 0x72, 0x72, 0x61,
0x79, 0x00, 0x00, 0x05, 0x69, 0x73, 0x5f, 0x61, 0x3f, 0x00, 0x00, 0x06,
0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x00, 0x00, 0x03, 0x6e, 0x65, 0x77,
0x00, 0x00, 0x03, 0x73, 0x65, 0x74, 0x00, 0x00, 0x17, 0x64, 0x65, 0x66,
0x69, 0x6e, 0x65, 0x5f, 0x73, 0x69, 0x6e, 0x67, 0x6c, 0x65, 0x74, 0x6f,
0x6e, 0x5f, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x00, 0x00, 0x0c, 0x62,
0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x67, 0x69, 0x76, 0x65, 0x6e, 0x3f, 0x00,
0x00, 0x0d, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x65,
0x78, 0x65, 0x63, 0x00, 0x00, 0x04, 0x65, 0x61, 0x63, 0x68, 0x00, 0x00,
0x06, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x00, 0x00, 0x00, 0x00, 0x3e,
0x00, 0x04, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x23,
0x34, 0x04, 0x20, 0x01, 0x25, 0x00, 0x03, 0x25, 0x00, 0x02, 0x11, 0x02,
0x21, 0x04, 0x05, 0x00, 0x21, 0x05, 0x01, 0x00, 0x01, 0x06, 0x01, 0x01,
0x07, 0x02, 0x01, 0x08, 0x03, 0x30, 0x04, 0x00, 0x03, 0x38, 0x04, 0x00,
0x00, 0x00, 0x01, 0x00, 0x04, 0x62, 0x69, 0x6e, 0x64, 0x00, 0x00, 0x00,
0x00, 0x2c, 0x00, 0x03, 0x00, 0x05, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
0x00, 0x11, 0x34, 0x04, 0x00, 0x00, 0x21, 0x03, 0x02, 0x00, 0x57, 0x04,
0x00, 0x30, 0x03, 0x00, 0x00, 0x38, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00,
0x04, 0x65, 0x61, 0x63, 0x68, 0x00, 0x00, 0x00, 0x00, 0x8d, 0x00, 0x03,
0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x59, 0x34, 0x04,
0x00, 0x00, 0x19, 0x03, 0x00, 0x21, 0x04, 0x01, 0x00, 0x01, 0x05, 0x03,
0x01, 0x06, 0x04, 0x2f, 0x05, 0x01, 0x01, 0x26, 0x05, 0x00, 0x07, 0x53,
0x05, 0x00, 0x2f, 0x03, 0x02, 0x02, 0x19, 0x03, 0x00, 0x21, 0x04, 0x01,
0x00, 0x23, 0x03, 0x01, 0x04, 0x01, 0x01, 0x05, 0x03, 0x01, 0x06, 0x04,
0x2f, 0x05, 0x01, 0x01, 0x26, 0x05, 0x00, 0x07, 0x47, 0x05, 0x00, 0x2f,
0x03, 0x02, 0x02, 0x19, 0x03, 0x00, 0x21, 0x04, 0x01, 0x00, 0x23, 0x03,
0x01, 0x04, 0x01, 0x23, 0x03, 0x21, 0x04, 0x04, 0x01, 0x2f, 0x03, 0x03,
0x01, 0x38, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x0d, 0x40, 0x6b, 0x65,
0x79, 0x5f, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x72, 0x73, 0x00, 0x00,
0x02, 0x5b, 0x5d, 0x00, 0x00, 0x03, 0x5b, 0x5d, 0x3d, 0x00, 0x00, 0x02,
0x3c, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x03, 0x00, 0x05, 0x00,
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x34, 0x04, 0x00, 0x00, 0x21,
0x03, 0x02, 0x00, 0x57, 0x04, 0x00, 0x30, 0x03, 0x00, 0x00, 0x38, 0x03,
0x00, 0x00, 0x00, 0x01, 0x00, 0x04, 0x65, 0x61, 0x63, 0x68, 0x00, 0x00,
0x00, 0x00, 0x8a, 0x00, 0x03, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x59, 0x34, 0x04, 0x00, 0x00, 0x19, 0x03, 0x00, 0x21, 0x04,
0x01, 0x00, 0x01, 0x05, 0x03, 0x01, 0x06, 0x04, 0x2f, 0x05, 0x01, 0x01,
0x26, 0x05, 0x00, 0x07, 0x53, 0x05, 0x00, 0x2f, 0x03, 0x02, 0x02, 0x19,
0x03, 0x00, 0x21, 0x04, 0x01, 0x00, 0x23, 0x03, 0x01, 0x04, 0x01, 0x01,
0x05, 0x03, 0x01, 0x06, 0x04, 0x2f, 0x05, 0x01, 0x01, 0x26, 0x05, 0x00,
0x07, 0x47, 0x05, 0x00, 0x2f, 0x03, 0x02, 0x02, 0x19, 0x03, 0x00, 0x21,
0x04, 0x01, 0x00, 0x23, 0x03, 0x01, 0x04, 0x01, 0x23, 0x03, 0x21, 0x04,
0x03, 0x01, 0x2f, 0x03, 0x03, 0x01, 0x38, 0x03, 0x00, 0x00, 0x00, 0x04,
0x00, 0x0a, 0x40, 0x6b, 0x65, 0x79, 0x5f, 0x62, 0x69, 0x6e, 0x64, 0x73,
0x00, 0x00, 0x02, 0x5b, 0x5d, 0x00, 0x00, 0x03, 0x5b, 0x5d, 0x3d, 0x00,
0x00, 0x02, 0x3c, 0x3c, 0x00, 0x4c, 0x56, 0x41, 0x52, 0x00, 0x00, 0x00,
0xcc, 0x00, 0x00, 0x00, 0x12, 0x00, 0x04, 0x69, 0x6e, 0x66, 0x6f, 0x00,
0x0a, 0x6d, 0x6f, 0x64, 0x65, 0x5f, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x00,
0x0b, 0x6d, 0x6f, 0x64, 0x65, 0x5f, 0x73, 0x79, 0x6d, 0x62, 0x6f, 0x6c,
0x00, 0x09, 0x6c, 0x61, 0x6e, 0x67, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x00,
0x08, 0x66, 0x69, 0x6c, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x00, 0x08, 0x73,
0x74, 0x61, 0x72, 0x74, 0x69, 0x6e, 0x67, 0x00, 0x0a, 0x68, 0x69, 0x67,
0x68, 0x6c, 0x69, 0x67, 0x68, 0x74, 0x73, 0x00, 0x05, 0x62, 0x6c, 0x6f,
0x63, 0x6b, 0x00, 0x05, 0x6d, 0x6f, 0x64, 0x65, 0x73, 0x00, 0x04, 0x6b,
0x65, 0x79, 0x73, 0x00, 0x06, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x00,
0x03, 0x61, 0x70, 0x70, 0x00, 0x03, 0x64, 0x73, 0x6c, 0x00, 0x01, 0x6b,
0x00, 0x03, 0x61, 0x63, 0x74, 0x00, 0x03, 0x62, 0x6c, 0x6b, 0x00, 0x04,
0x6d, 0x6f, 0x64, 0x65, 0x00, 0x03, 0x6b, 0x65, 0x79, 0x00, 0x00, 0xff,
0xff, 0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 0x00, 0x04, 0x00, 0x05, 0x00,
0x06, 0x00, 0x07, 0x00, 0x07, 0x00, 0x07, 0x00, 0x08, 0x00, 0x09, 0x00,
0x0a, 0x00, 0x07, 0x00, 0x0b, 0x00, 0x0c, 0x00, 0x0d, 0x00, 0x0e, 0x00,
0x0f, 0x00, 0x10, 0xff, 0xff, 0x00, 0x11, 0xff, 0xff, 0x00, 0x10, 0xff,
0xff, 0x00, 0x11, 0xff, 0xff, 0x45, 0x4e, 0x44, 0x00, 0x00, 0x00, 0x00,
0x08
};
constexpr unsigned int _tmp___crib_precompiled_mrb_len = 7273;

View File

@@ -41,9 +41,8 @@ struct LineData {
}; };
struct CustomState { struct CustomState {
VALUE state; mrb_value state;
CustomState(VALUE s) : state(s) { rb_gc_register_address(&state); } CustomState(mrb_value s) : state(s) {}
~CustomState() { rb_gc_unregister_address(&state); }
}; };
#endif #endif

View File

@@ -4,9 +4,9 @@
#include "syntax/decl.h" #include "syntax/decl.h"
#define DEF_LANG(name) \ #define DEF_LANG(name) \
std::shared_ptr<void> name##_parse(std::vector<Token> *tokens, \ std::shared_ptr<void> name##_parse( \
std::shared_ptr<void> in_state, \ std::vector<Token> *tokens, std::shared_ptr<void> in_state, \
const char *text, uint32_t len); \ const char *text, uint32_t len, uint32_t line_num); \
bool name##_state_match(std::shared_ptr<void> state_1, \ bool name##_state_match(std::shared_ptr<void> state_1, \
std::shared_ptr<void> state_2); std::shared_ptr<void> state_2);
@@ -34,9 +34,9 @@ DEF_LANG(bash);
inline static const std::unordered_map< inline static const std::unordered_map<
std::string, std::string,
std::tuple<std::shared_ptr<void> (*)(std::vector<Token> *tokens, std::tuple<std::shared_ptr<void> (*)(
std::shared_ptr<void> in_state, std::vector<Token> *tokens, std::shared_ptr<void> in_state,
const char *text, uint32_t len), const char *text, uint32_t len, uint32_t line_num),
bool (*)(std::shared_ptr<void> state_1, bool (*)(std::shared_ptr<void> state_1,
std::shared_ptr<void> state_2)>> std::shared_ptr<void> state_2)>>
parsers = { parsers = {

View File

@@ -10,11 +10,12 @@ struct Parser {
std::string lang; std::string lang;
std::shared_ptr<void> (*parse_func)(std::vector<Token> *tokens, std::shared_ptr<void> (*parse_func)(std::vector<Token> *tokens,
std::shared_ptr<void> in_state, std::shared_ptr<void> in_state,
const char *text, uint32_t len); const char *text, uint32_t len,
uint32_t line_num);
bool (*state_match_func)(std::shared_ptr<void> state_1, bool (*state_match_func)(std::shared_ptr<void> state_1,
std::shared_ptr<void> state_2); std::shared_ptr<void> state_2);
VALUE parser_block = Qnil; mrb_value parser_block = mrb_nil_value();
VALUE match_block = Qnil; mrb_value match_block = mrb_nil_value();
bool is_custom{false}; bool is_custom{false};
std::atomic<uint32_t> scroll_max{UINT32_MAX - 2048}; std::atomic<uint32_t> scroll_max{UINT32_MAX - 2048};
std::atomic<bool> scroll_dirty{false}; std::atomic<bool> scroll_dirty{false};

View File

@@ -1,4 +1,3 @@
// When updating this file with new types do not forget to update libcrib.rb to parallel changes
ADD(K_DATA) ADD(K_DATA)
ADD(K_SHEBANG) ADD(K_SHEBANG)
ADD(K_COMMENT) ADD(K_COMMENT)

View File

@@ -8,9 +8,13 @@
struct Bar { struct Bar {
Coord screen; Coord screen;
std::string command = ""; std::string command = "";
std::string log_line = "";
uint32_t cursor = 0; uint32_t cursor = 0;
BarLine bar_line;
std::mutex mtx;
Bar(Coord screen) : screen(screen) {} void init(Coord screen) { this->screen = screen; }
void work();
void render(); void render();
void handle(KeyEvent event); void handle(KeyEvent event);
void log(std::string message); void log(std::string message);

View File

@@ -102,7 +102,6 @@ struct Language {
std::string name; std::string name;
std::string lsp_name; std::string lsp_name;
uint32_t color; uint32_t color;
std::string symbol;
}; };
struct LSP { struct LSP {
@@ -112,7 +111,6 @@ struct LSP {
extern std::unordered_map<std::string, Language> languages; extern std::unordered_map<std::string, Language> languages;
extern std::unordered_map<std::string, std::string> language_extensions; extern std::unordered_map<std::string, std::string> language_extensions;
extern std::unordered_map<std::string, std::string> language_mimetypes;
extern std::unordered_map<std::string, LSP> lsps; extern std::unordered_map<std::string, LSP> lsps;
#define MAX(a, b) ((a) > (b) ? (a) : (b)) #define MAX(a, b) ((a) > (b) ? (a) : (b))
@@ -154,8 +152,7 @@ std::string path_abs(const std::string &path_str);
std::string path_to_file_uri(const std::string &path_str); std::string path_to_file_uri(const std::string &path_str);
std::string filename_from_path(const std::string &path); std::string filename_from_path(const std::string &path);
std::string get_exe_dir(); std::string get_exe_dir();
char *load_file(const char *path, uint32_t *out_len); char *load_file(const char *path, uint32_t *out_len, bool *out_eol);
char *detect_file_type(const char *filename);
Language language_for_file(const char *filename); Language language_for_file(const char *filename);
void copy_to_clipboard(const char *text, size_t len); void copy_to_clipboard(const char *text, size_t len);

51
installer.sh Normal file
View File

@@ -0,0 +1,51 @@
#!/usr/bin/env sh
set -eu
install() {
BINARY_NAME="crib"
VERSION="v0.0.1-alpha"
BIN_URL="https://git.syedm.dev/SyedM-dev/crib/releases/download/$VERSION/crib"
ldconfig -p | grep libmagic >/dev/null 2>&1
if ! ldconfig -p | grep libmagic >/dev/null 2>&1; then
echo "Missing dependency: libmagic (part of \`file\` package)"
echo "Install them using your package manager:"
echo "Ubuntu/Debian: sudo apt install ruby libmagic1"
echo "Arch: sudo pacman -S file"
echo "Void: sudo xbps-install -Sy file"
exit 1
fi
echo "Install locally (~/.local/bin) or globally (/usr/bin)? [l/g]"
read -r choice </dev/tty
case "$choice" in
l | L)
INSTALL_DIR="$HOME/.local/bin"
SUDO=""
;;
g | G)
INSTALL_DIR="/usr/bin"
SUDO="sudo"
;;
*)
echo "Invalid choice"
exit 1
;;
esac
$SUDO mkdir -p "$INSTALL_DIR"
echo "Downloading binary..."
curl -L "$BIN_URL" -o /tmp/"$BINARY_NAME"
$SUDO install -m 755 /tmp/"$BINARY_NAME" "$INSTALL_DIR/$BINARY_NAME"
rm -f /tmp/"$BINARY_NAME"
echo
echo "✔ Crib installed to $INSTALL_DIR"
echo "Run with: $BINARY_NAME"
echo "Add $INSTALL_DIR to PATH if needed."
}
install "$@"

1
libs/utfcpp vendored

Submodule libs/utfcpp deleted from cfc9112cee

View File

@@ -47,7 +47,7 @@ while ((counter < 5)); do
done done
# Subshelled loops and alternating quoting # Subshelled loops and alternating quoting
for item in "${ITEMS[@]}"; do for item in "${ITEMS[@]}}"; do
( (
msg="Processing $item" msg="Processing $item"
echo "$(colorize blue "$msg")" echo "$(colorize blue "$msg")"

View File

@@ -4,13 +4,12 @@
# Purpose: Test syntax highlighting + width calculation in your editor # Purpose: Test syntax highlighting + width calculation in your editor
# --------------------------------------------------------------- # ---------------------------------------------------------------
# Mixed-width CJKssssssssssssssss LoadErssssssssssssssssssssssss # Mixed-width CJKssssssssssssssss LoadErssssssssssssssssssssssss
cjk_samples = [ cjk_samples = [
"漢字テスト", '漢字テスト',
"測試中文字串", '測試中文字串',
"한국어 테스트", '한국어 테스트',
"ひらがなカタカナ混合", 'ひらがなカタカナ混合'
] ]
# a hex color: #FFFFFF shouldn't hl here: hsl(147rad, 50%, 47%) as it is not css-style file # a hex color: #FFFFFF shouldn't hl here: hsl(147rad, 50%, 47%) as it is not css-style file
@@ -18,34 +17,33 @@ cjk_samples = [
0x603010 # another hex color 0x603010 # another hex color
# Ruby regex with unicode # Ruby regex with unicode
$unicode_regex_multiline = /[一-龯ぁ-ん#{0x3000} $unicode_regex_multiline = /[一-龯ぁ-ん12288
\-ヶー \-ヶー
s wow s wow
々〆〤]/ 々〆〤]/
UNICORE = %r{ UNICORE = /
[s] s
{#{ss}} {#{ss}}
\C-s\u{10} \C-s\u{10}
} /
UNINITCORE = %{ UNINITCORE = %(
{{#{}}} {{#{}}}
test = "A:\x41 B:\101 C:\u0043 D:\u{44 45} NUL:\0 DEL:\c? CTRL_A:\cA META_X:\M-x CTRL_META_X:\C-\M-x MIX:\C-\M-z N:\N{UNICODE NAME}" test = "A:\x41 B:\101 C:\u0043 D:\u{44 45} NUL:\0 DEL:\c? CTRL_A:\cA META_X:\M-x CTRL_META_X:\C-\M-x MIX:\C-\M-z N:\N{UNICODE NAME}"
} )
# Unicode identifiers (valid in Ruby) # Unicode identifiers (valid in Ruby)
= 0x5_4eddaee = 0x5_4eddaee
π = 3.14_159e+2, ?\u0234, ?\,, ?\x0A, ?s, true, false, 0 π = 0.314_159e+2, ?\u0234, "\,", ?\x0A, 's', true, false, 0
= -> { "こんに \n ちは" } = -> { "こんに \n ちは" }
arr = Array.new() arr = []
not_arr = NotABuiltin.new() not_arr = NotABuiltin.new
raise NameError or SystemExit or CustomError or Errno or ErrorNotAtAll raise NameError or SystemExit or CustomError or Errno or ErrorNotAtAll
@@ -56,7 +54,7 @@ end
# Iterate through CJK samples # Iterate through CJK samples
cjk_samples.each_with_index do |str, idx:| cjk_samples.each_with_index do |str, idx:|
puts %Q! CJK[#{idx}] => #{str} (len=#{str.length})\! ! puts %! CJK[#{idx}] => #{str} (len=#{str.length})\! !
symbol = :" symbol = :"
a a
" "
@@ -67,7 +65,7 @@ end
puts "Emoji count: #{emojis.length}" puts "Emoji count: #{emojis.length}"
# Multi-line string with unicode # Multi-line string with unicode
multi = <<BASH multi = <<~BASH
# Function recursion demo # Function recursion demo
factorial() { factorial() {
local n="$1" local n="$1"
@@ -78,10 +76,10 @@ multi = <<BASH
prev=$(factorial $((n - 1))) prev=$(factorial $((n - 1)))
echo $((n * prev)) echo $((n * prev))
before #{ interpol before #{ interpol
# {' '}
# comment should be fine heres s # comment should be fine heres s
$a / $-s + 0xFF $a / $-s + 0xFF
}s }s#{' '}
x x
a after a after
fi fi
@@ -91,22 +89,20 @@ BASH
puts multi puts multi
# Arrays mixing everything # Arrays mixing everything
mixed = [ mixed = [
"🐍 Ruby + Python? sacrilege! 🐍", '🐍 Ruby + Python? sacrilege! 🐍',
"日本語とEnglishと🔧mix", '日本語とEnglishと🔧mix',
"Spacing test →→→→→→→", 'Spacing test →→→→→→→',
"Zero-width joiner test: 👨‍👩‍👧‍👦 family emoji", 'Zero-width joiner test: 👨‍👩‍👧‍👦 family emoji'
] ]
two_docs = <<DOC1 , <<DOC2 two_docs = <<~DOC1, <<~DOC2
stuff for doc2 stuff for doc2
rdvajehvbaejbfh rdvajehvbaejbfh
DOC1 DOC1
stuff for doc 2 with #{not interpolation} and more stuff for doc 2 with #{!interpolation} and more
DOC2 DOC2
p = 0 << 22 # not a heredoc p = 0 << 22 # not a heredoc
@@ -129,7 +125,7 @@ puts escaped
p = 0 << 2 p = 0 << 2
# Frozen string literal test # Frozen string literal test
# frozen_string_literal: true # frozen_string_literal: true
const_str = "定数文字列🔒".freeze const_str = '定数文字列🔒'.freeze
puts const_str puts const_str
# End marker # End marker
@@ -137,14 +133,12 @@ puts '--- END OF UNICODE TEST FILE ---'
# Ruby syntax highlighting test # Ruby syntax highlighting test
=begin # This is a multi-line comment.
This is a multi-line comment. # It spans multiple lines.
It spans multiple lines. # Good for testing highlighting.
Good for testing highlighting. #
# This is a wrapped line test, This is a wrapped line test, This is a wrapped line test, This is a wrapped line test, This is a wrapped line test, This is a wrapped line test, This is a wrapped line test, This is a wrapped line test, This is a wrapped line test, This is a wrapped line test, This is a wrapped line test, This is a wrapped line test, This is a wrapped line test, This is a wrapped line test, This is a wrapped line test, This is a wrapped line test, This is a wrapped line test, This is a wrapped line test, This is a wrapped line test, This is a wrapped line test, This is a wrapped line test, This is a wrapped line test, This is a wrapped line test, This is a wrapped line test, This is a wrapped line test, This is a wrapped line test, This is a wrapped line test, This is a wrapped line test, This is a wrapped line test, This is a wrapped line test, This is a wrapped line test, This is a wrapped line test, This is a wrapped line test, This is a wrapped line test, This is a wrapped line test, This is a wrapped line test, This is a wrapped line test, This is a wrapped line test, This is a wrapped line test, This is a wrapped line test, This is a wrapped line test, This is a wrapped line test, This is a wrapped line test, This is a wrapped line test, This is a wrapped line test, This is a wrapped line test, This is a wrapped line test, This is a wrapped line test, This is a wrapped line test, This is a wrapped line test, This is a wrapped line test, This is a wrapped line test, This is a wrapped line test, This is a wrapped linetest,
This is a wrapped line test, This is a wrapped line test, This is a wrapped line test, This is a wrapped line test, This is a wrapped line test, This is a wrapped line test, This is a wrapped line test, This is a wrapped line test, This is a wrapped line test, This is a wrapped line test, This is a wrapped line test, This is a wrapped line test, This is a wrapped line test, This is a wrapped line test, This is a wrapped line test, This is a wrapped line test, This is a wrapped line test, This is a wrapped line test, This is a wrapped line test, This is a wrapped line test, This is a wrapped line test, This is a wrapped line test, This is a wrapped line test, This is a wrapped line test, This is a wrapped line test, This is a wrapped line test, This is a wrapped line test, This is a wrapped line test, This is a wrapped line test, This is a wrapped line test, This is a wrapped line test, This is a wrapped line test, This is a wrapped line test, This is a wrapped line test, This is a wrapped line test, This is a wrapped line test, This is a wrapped line test, This is a wrapped line test, This is a wrapped line test, This is a wrapped line test, This is a wrapped line test, This is a wrapped line test, This is a wrapped line test, This is a wrapped line test, This is a wrapped line test, This is a wrapped line test, This is a wrapped line test, This is a wrapped line test, This is a wrapped line test, This is a wrapped line test, This is a wrapped line test, This is a wrapped line test, This is a wrapped line test, This is a wrapped linetest, #
=end
# Constants # Constants
@@ -153,11 +147,12 @@ MAX_ITER = 5
# Module # Module
module Utilities module Utilities
def self.random_greeting def self.random_greeting
["Hello", "Hi", "Hey", "Hola", "Bonjour", "Merhaba"].sample %w[Hello Hi Hey Hola Bonjour Merhaba].sample
end end
def self.factorial(n) def self.factorial(n)
return 1 if n <= 1 return 1 if n <= 1
n * factorial(n - 1) n * factorial(n - 1)
end end
end end
@@ -218,18 +213,16 @@ end
# Method definition # Method definition
def greet_person(name) def greet_person(name)
puts "#{Utilities.random_greeting}, #{name}!" puts "#{Utilities.random_greeting}, #{name}!"
if (name == "harry") return true if name == 'harry'
return true
else 's'
return "s"
end
end end
h = a / a h = a / a
# Calling methods # Calling methods
greet_person("Alice") greet_person('Alice')
greet_person("Bob") greet_person('Bob')
# Loops # Loops
i = 0 i = 0
@@ -249,7 +242,7 @@ begin
rescue ZeroDivisionError => e rescue ZeroDivisionError => e
puts "Caught an error: #{e}" puts "Caught an error: #{e}"
ensure ensure
puts "This runs no matter what" puts 'This runs no matter what'
end end
# Arrays of objects # Arrays of objects
@@ -285,7 +278,7 @@ end
end end
# Special objects # Special objects
so = SpecialObject.new("Special", 10) so = SpecialObject.new('Special', 10)
puts "Double: #{so.double_value}, Triple: #{so.triple_value}" puts "Double: #{so.double_value}, Triple: #{so.triple_value}"
# String interpolation and formatting # String interpolation and formatting
@@ -296,8 +289,8 @@ multi_line = <<~TEXT
k kmW ; k kmW ;
This is a multi-line string. This is a multi-line string.
It spans multiple lines. It spans multiple lines.
Gossn m Gossn sssmss
dd ddsss
od for testing highlighting. od for testing highlighting.
TEXT TEXT
@@ -305,7 +298,7 @@ puts multi_line
# Symbols and strings # Symbols and strings
sym = :my_symbol == __dir__ sym = :my_symbol == __dir__
str = "my string" str = 'my string'
puts "Symbol: #{sym}, String: #{str}" puts "Symbol: #{sym}, String: #{str}"
# Random numbers # Random numbers
@@ -324,25 +317,25 @@ end
# Block with yield # Block with yield
def wrapper def wrapper
puts "Before block" puts 'Before block'
yield if block_given? yield if block_given?
puts "After block" puts 'After block'
end end
# ss # ss
wrapper { puts "Inside block" } wrapper { puts 'Inside block' }
# Sorting # Sorting
sorted = rand_nums.sort sorted = rand_nums.sort
puts "Sorted: #{sorted.join(', ')}" puts "Sorted: #{sorted.join(', ')}"
# Regex # Regex
sample_text = "The quick brown fox jumps over the lazy dog" sample_text = 'The quick brown fox jumps over the lazy dog'
puts "Match 'fox'?" if sample_text =~ /fox/ puts "Match 'fox'?" if sample_text =~ /fox/
# End of test script # End of test script
puts "Ruby syntax highlighting test complete." puts 'Ruby syntax highlighting test complete.'
__END__ __END__

View File

@@ -25,6 +25,23 @@ inline static std::string completion_prefix(Editor *editor) {
return prefix; return prefix;
} }
inline static void completion_adjust_scroll(CompletionSession &s) {
if (s.visible.empty())
return;
int vi = -1;
for (size_t i = 0; i < s.visible.size(); i++)
if (s.visible[i] == s.select) {
vi = (int)i;
break;
}
if (vi < 0)
return;
if ((uint32_t)vi < s.scroll)
s.scroll = vi;
else if ((uint32_t)vi >= s.scroll + 8)
s.scroll = vi - 7;
}
void completion_filter(Editor *editor) { void completion_filter(Editor *editor) {
auto &session = editor->completion; auto &session = editor->completion;
std::string prefix = completion_prefix(editor); std::string prefix = completion_prefix(editor);
@@ -44,6 +61,8 @@ void completion_filter(Editor *editor) {
session.select) == session.visible.end()) session.select) == session.visible.end())
session.select = session.visible[0]; session.select = session.visible[0];
session.box.hidden = false; session.box.hidden = false;
session.scroll = 0;
completion_adjust_scroll(session);
session.box.render_update(); session.box.render_update();
} }
@@ -417,6 +436,7 @@ void complete_next(Editor *editor) {
vi = (vi + 1) % s.visible.size(); vi = (vi + 1) % s.visible.size();
s.select = s.visible[vi]; s.select = s.visible[vi];
completion_resolve_doc(editor); completion_resolve_doc(editor);
completion_adjust_scroll(editor->completion);
editor->completion.box.render_update(); editor->completion.box.render_update();
} }
@@ -431,6 +451,7 @@ void complete_prev(Editor *editor) {
vi = (vi + s.visible.size() - 1) % s.visible.size(); vi = (vi + s.visible.size() - 1) % s.visible.size();
s.select = s.visible[vi]; s.select = s.visible[vi];
completion_resolve_doc(editor); completion_resolve_doc(editor);
completion_adjust_scroll(editor->completion);
editor->completion.box.render_update(); editor->completion.box.render_update();
} }

View File

@@ -1,22 +1,26 @@
#include "editor/editor.h" #include "editor/editor.h"
#include "editor/decl.h" #include "editor/decl.h"
#include "lsp/lsp.h" #include "lsp/lsp.h"
#include "main.h"
#include "syntax/langs.h" #include "syntax/langs.h"
#include "utils/utils.h" #include "utils/utils.h"
Editor *new_editor(const char *filename_arg, Coord position, Coord size, Editor *new_editor(const char *filename_arg, Coord position, Coord size,
bool unix_eol) { uint8_t eol) {
Editor *editor = new Editor(); Editor *editor = new Editor();
if (!editor) if (!editor)
return nullptr; return nullptr;
uint32_t len = 0; uint32_t len = 0;
std::string filename = path_abs(filename_arg); std::string filename = path_abs(filename_arg);
char *str = load_file(filename.c_str(), &len); editor->unix_eol = eol & 1;
char *str = load_file(filename.c_str(), &len, &editor->unix_eol);
if (!str) { if (!str) {
free_editor(editor); str = (char *)malloc(1);
return nullptr; *str = '\n';
len = 1;
} }
editor->unix_eol = unix_eol; if ((eol >> 1) & 1)
editor->unix_eol = eol & 1;
editor->filename = filename; editor->filename = filename;
editor->uri = path_to_file_uri(filename); editor->uri = path_to_file_uri(filename);
editor->position = position; editor->position = position;
@@ -74,6 +78,8 @@ void save_file(Editor *editor) {
} }
out.close(); out.close();
free(str); free(str);
bar.log("Written " + std::to_string(char_count) + " bytes to " +
editor->filename);
if (editor->lsp) { if (editor->lsp) {
json save_msg = {{"jsonrpc", "2.0"}, json save_msg = {{"jsonrpc", "2.0"},
{"method", "textDocument/didSave"}, {"method", "textDocument/didSave"},

View File

@@ -232,6 +232,4 @@ void handle_editor_event(Editor *editor, KeyEvent event) {
if (old_mode == mode || mode != INSERT) if (old_mode == mode || mode != INSERT)
handle_completion(editor, event); handle_completion(editor, event);
ensure_scroll(editor); ensure_scroll(editor);
if ((event.key_type == KEY_CHAR || event.key_type == KEY_PASTE) && event.c)
free(event.c);
} }

View File

@@ -218,8 +218,8 @@ void IndentationEngine::insert_new_line(Coord cursor) {
if (is_end_full != kLangtoBlockEndsFull.end()) if (is_end_full != kLangtoBlockEndsFull.end())
for (auto end : is_end_full->second) for (auto end : is_end_full->second)
if (end == trim(line)) { if (end == trim(line)) {
cursor.col = cursor.col = set_indent(
set_indent(cursor.row, (int64_t)indent_expected(cursor.row) - 1); cursor.row, (int64_t)indent_expected(cursor.row) - (int64_t)1);
end_matched = true; end_matched = true;
break; break;
} }
@@ -286,7 +286,7 @@ void IndentationEngine::insert_new_line(Coord cursor) {
(indent == 1 ? std::string(c_indent, '\t') (indent == 1 ? std::string(c_indent, '\t')
: std::string(c_indent * indent, ' ')) + : std::string(c_indent * indent, ' ')) +
ending; ending;
else if (ending_valid) else if (ending_valid && c_indent)
c_indent--; c_indent--;
} }
auto is_end_set = kLangtoBlockStartsEnd.find(editor->lang.name); auto is_end_set = kLangtoBlockStartsEnd.find(editor->lang.name);

View File

@@ -11,7 +11,7 @@ void render_editor(Editor *editor) {
uint32_t numlen = uint32_t numlen =
EXTRA_META + static_cast<int>(std::log10(editor->root->line_count + 1)); EXTRA_META + static_cast<int>(std::log10(editor->root->line_count + 1));
uint32_t render_width = editor->size.col - numlen; uint32_t render_width = editor->size.col - numlen;
uint32_t render_x = editor->position.col + numlen; uint32_t render_x = editor->position.col + numlen + 1;
std::vector<std::pair<uint32_t, char>> v; std::vector<std::pair<uint32_t, char>> v;
for (size_t i = 0; i < 94; ++i) for (size_t i = 0; i < 94; ++i)
if (editor->hooks[i] != 0) if (editor->hooks[i] != 0)
@@ -146,16 +146,14 @@ void render_editor(Editor *editor) {
update(editor->position.row + rendered_rows, editor->position.col, hook, update(editor->position.row + rendered_rows, editor->position.col, hook,
0xAAAAAA, 0, 0); 0xAAAAAA, 0, 0);
char buf[16]; char buf[16];
int len = int len = snprintf(buf, sizeof(buf), "%*u ", numlen, line_index + 1);
snprintf(buf, sizeof(buf), "%*u ", numlen - 3, line_index + 1);
uint32_t num_color = uint32_t num_color =
editor->cursor.row == line_index ? 0xFFFFFF : 0x555555; editor->cursor.row == line_index ? 0xFFFFFF : 0x555555;
for (int i = 0; i < len; i++) for (int i = 0; i < len; i++)
update(editor->position.row + rendered_rows, update(editor->position.row + rendered_rows, editor->position.col + i,
editor->position.col + i + 2, (char[2]){buf[i], 0}, num_color, (char[2]){buf[i], 0}, num_color, 0, 0);
0, 0);
} else { } else {
for (uint32_t i = 0; i < numlen; i++) for (uint32_t i = 0; i < numlen + 1; i++)
update(editor->position.row + rendered_rows, editor->position.col + i, update(editor->position.row + rendered_rows, editor->position.col + i,
" ", 0, 0, 0); " ", 0, 0, 0);
} }
@@ -349,13 +347,12 @@ void render_editor(Editor *editor) {
update(editor->position.row + rendered_rows, editor->position.col, hook, update(editor->position.row + rendered_rows, editor->position.col, hook,
0xAAAAAA, 0, 0); 0xAAAAAA, 0, 0);
char buf[16]; char buf[16];
int len = snprintf(buf, sizeof(buf), "%*u ", numlen - 3, line_index + 1); int len = snprintf(buf, sizeof(buf), "%*u ", numlen, line_index + 1);
uint32_t num_color = uint32_t num_color =
editor->cursor.row == line_index ? 0xFFFFFF : 0x555555; editor->cursor.row == line_index ? 0xFFFFFF : 0x555555;
for (int i = 0; i < len; i++) for (int i = 0; i < len; i++)
update(editor->position.row + rendered_rows, update(editor->position.row + rendered_rows, editor->position.col + i,
editor->position.col + i + 2, (char[2]){buf[i], 0}, num_color, 0, (char[2]){buf[i], 0}, num_color, 0, 0);
0);
if (editor->cursor.row == line_index) { if (editor->cursor.row == line_index) {
cursor.row = editor->position.row + rendered_rows; cursor.row = editor->position.row + rendered_rows;
cursor.col = render_x; cursor.col = render_x;

View File

@@ -1,4 +1,5 @@
#include "lsp/lsp.h" #include "lsp/lsp.h"
#include "main.h"
Queue<LSPOpenRequest> lsp_open_queue; Queue<LSPOpenRequest> lsp_open_queue;

View File

@@ -155,40 +155,78 @@ std::shared_ptr<LSPInstance> get_or_init_lsp(std::string lsp_id) {
} }
void close_lsp(std::string lsp_id) { void close_lsp(std::string lsp_id) {
std::shared_lock active_lsps_lock(active_lsps_mtx); std::shared_ptr<LSPInstance> lsp;
{
std::shared_lock lock(active_lsps_mtx);
auto it = active_lsps.find(lsp_id); auto it = active_lsps.find(lsp_id);
if (it == active_lsps.end()) if (it == active_lsps.end())
return; return;
std::shared_ptr<LSPInstance> lsp = it->second; lsp = it->second;
active_lsps_lock.unlock(); }
if (!lsp || lsp->pid == -1 || lsp->exited)
return;
lsp->exited = true; lsp->exited = true;
lsp->initialized = false; lsp->initialized = false;
LSPPending *shutdown_pending = new LSPPending(); auto send_raw = [&](const json &msg) {
shutdown_pending->method = "shutdown"; std::string payload = msg.dump();
shutdown_pending->callback = [lsp](Editor *, std::string, json) { std::string header =
json exit = {{"jsonrpc", "2.0"}, {"method", "exit"}}; "Content-Length: " + std::to_string(payload.size()) + "\r\n\r\n";
lsp_send(lsp, exit, nullptr); std::string out = header + payload;
const char *ptr = out.data();
size_t remaining = out.size();
while (remaining > 0) {
ssize_t n = write(lsp->stdin_fd, ptr, remaining);
if (n <= 0) {
if (errno == EINTR)
continue;
break;
}
ptr += n;
remaining -= n;
}
}; };
json shutdown = {{"jsonrpc", "2.0"}, {"method", "shutdown"}}; json shutdown = {{"jsonrpc", "2.0"}, {"id", 1}, {"method", "shutdown"}};
lsp_send(lsp, shutdown, shutdown_pending); send_raw(shutdown);
std::thread t([lsp, lsp_id] { {
std::this_thread::sleep_for(100ms); pollfd pfd{lsp->stdout_fd, POLLIN, 0};
std::unique_lock active_lsps_lock(active_lsps_mtx); int timeout_ms = 300;
std::unique_lock lock(lsp->mtx); if (poll(&pfd, 1, timeout_ms) > 0) {
if (lsp->pid != -1 && kill(lsp->pid, 0) == 0) auto msg = read_lsp_message(lsp->stdout_fd);
(void)msg;
}
}
json exit_msg = {{"jsonrpc", "2.0"}, {"method", "exit"}};
send_raw(exit_msg);
const int max_wait_ms = 500;
int waited = 0;
while (waited < max_wait_ms) {
int status;
pid_t res = waitpid(lsp->pid, &status, WNOHANG);
if (res == lsp->pid)
break;
std::this_thread::sleep_for(std::chrono::milliseconds(10));
waited += 10;
}
if (kill(lsp->pid, 0) == 0) {
kill(lsp->pid, SIGKILL); kill(lsp->pid, SIGKILL);
waitpid(lsp->pid, nullptr, 0); waitpid(lsp->pid, nullptr, 0);
}
close(lsp->stdin_fd); close(lsp->stdin_fd);
close(lsp->stdout_fd); close(lsp->stdout_fd);
{
std::unique_lock lock(lsp->mtx);
for (auto &kv : lsp->pending) for (auto &kv : lsp->pending)
delete kv.second; delete kv.second;
lsp->pending.clear();
}
for (auto &editor : lsp->editors) { for (auto &editor : lsp->editors) {
std::unique_lock editor_lock(editor->lsp_mtx); std::unique_lock editor_lock(editor->lsp_mtx);
editor->lsp = nullptr; editor->lsp = nullptr;
} }
{
std::unique_lock lock(active_lsps_mtx);
active_lsps.erase(lsp_id); active_lsps.erase(lsp_id);
}); }
t.detach();
} }
void clean_lsp(std::shared_ptr<LSPInstance> lsp, std::string lsp_id) { void clean_lsp(std::shared_ptr<LSPInstance> lsp, std::string lsp_id) {

View File

@@ -16,7 +16,7 @@ void lsp_send(std::shared_ptr<LSPInstance> lsp, json message,
lsp->outbox.push(message); lsp->outbox.push(message);
} }
static std::optional<json> read_lsp_message(int fd) { std::optional<json> read_lsp_message(int fd) {
std::string header; std::string header;
char c; char c;
while (true) { while (true) {

View File

@@ -9,6 +9,7 @@
std::atomic<bool> running{true}; std::atomic<bool> running{true};
Queue<KeyEvent> event_queue; Queue<KeyEvent> event_queue;
std::vector<Editor *> editors; std::vector<Editor *> editors;
Bar bar;
uint8_t current_editor = 0; uint8_t current_editor = 0;
std::atomic<uint8_t> mode = NORMAL; std::atomic<uint8_t> mode = NORMAL;
@@ -36,7 +37,7 @@ inline uint8_t index_of(Editor *ed) {
return 0; return 0;
} }
void input_listener(Bar bar) { void input_listener() {
while (running) { while (running) {
KeyEvent event = throttle(1ms, read_key); KeyEvent event = throttle(1ms, read_key);
if (event.key_type == KEY_NONE) if (event.key_type == KEY_NONE)
@@ -53,7 +54,6 @@ void input_listener(Bar bar) {
if (target) { if (target) {
if (event.mouse_state == PRESS) if (event.mouse_state == PRESS)
current_editor = index_of(target); current_editor = index_of(target);
event.mouse_x -= target->position.col; event.mouse_x -= target->position.col;
event.mouse_y -= target->position.row; event.mouse_y -= target->position.row;
handle_editor_event(target, event); handle_editor_event(target, event);
@@ -64,37 +64,27 @@ void input_listener(Bar bar) {
} else { } else {
bar.handle(event); bar.handle(event);
} }
if ((event.key_type == KEY_CHAR || event.key_type == KEY_PASTE) && event.c)
free(event.c);
render: render:
render_editor(editors[current_editor]);
bar.render(); bar.render();
render_editor(editors[current_editor]);
throttle(4ms, render); throttle(4ms, render);
} }
} }
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
auto start = std::chrono::high_resolution_clock::now(); ruby_start();
ruby_init();
ruby_start((get_exe_dir() + "/../config/main.rb").c_str());
load_theme(); load_theme();
load_languages_info(); load_languages_info();
load_custom_highlighters(); load_custom_highlighters();
Coord screen = start_screen(); Coord screen = start_screen();
const char *filename = (argc > 1) ? argv[1] : ""; const char *filename = (argc > 1) ? argv[1] : "";
uint8_t eol = read_line_endings();
bool unix_eol = read_line_endings();
Editor *editor = Editor *editor =
new_editor(filename, {0, 0}, {screen.row - 2, screen.col}, unix_eol); new_editor(filename, {0, 0}, {screen.row - 2, screen.col}, eol);
Bar bar(screen); bar.init(screen);
auto end = std::chrono::high_resolution_clock::now();
auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(end - start)
.count();
ruby_log("[LOG] STARTUP_TIME: " + std::to_string(static_cast<long long>(ms)) +
"ms");
if (!editor) { if (!editor) {
end_screen(); end_screen();
@@ -105,11 +95,13 @@ int main(int argc, char *argv[]) {
editors.push_back(editor); editors.push_back(editor);
current_editor = editors.size() - 1; current_editor = editors.size() - 1;
std::thread input_thread(input_listener, bar); std::thread input_thread(input_listener);
std::thread lsp_thread(background_lsp); std::thread lsp_thread(background_lsp);
while (running) while (running) {
throttle(16ms, editor_worker, editors[current_editor]); throttle(16ms, editor_worker, editors[current_editor]);
bar.work();
}
if (input_thread.joinable()) if (input_thread.joinable())
input_thread.join(); input_thread.join();
@@ -119,22 +111,10 @@ int main(int argc, char *argv[]) {
end_screen(); end_screen();
ruby_shutdown();
for (auto editor : editors) for (auto editor : editors)
free_editor(editor); free_editor(editor);
std::unique_lock lk(active_lsps_mtx); ruby_shutdown();
lk.unlock();
while (true) {
lk.lock();
if (active_lsps.empty())
break;
lk.unlock();
throttle(16ms, lsp_worker);
}
rb_gc_start(); return 0;
return ruby_cleanup(0);
} }

38
src/ruby_compile.sh Executable file
View File

@@ -0,0 +1,38 @@
#!/usr/bin/env bash
set -e
SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"
INPUT="$SCRIPT_DIR/../include/syntax/tokens.def"
TMP="/tmp/__crib_precompiled.rb"
OUTPUT="/tmp/__crib_precompiled.mrb"
echo "module Tokens" >"$TMP"
counter=0
while read -r line; do
if [[ $line =~ ADD\(([^\)]+)\) ]]; then
name="${BASH_REMATCH[1]}"
echo " $name = $counter" >>"$TMP"
counter=$((counter + 1))
fi
done <"$INPUT"
{
echo " freeze"
echo "end"
echo
cat "$SCRIPT_DIR/../include/scripting/libcrib.rb"
} >>"$TMP"
mrbc -o$OUTPUT $TMP
{
echo "#pragma once"
xxd -i $OUTPUT | sed 's/^unsigned char /constexpr unsigned char /' |
sed 's/^unsigned int /constexpr unsigned int /'
} >"$SCRIPT_DIR/../include/scripting/ruby_compiled.h"
rm $TMP
rm $OUTPUT

View File

@@ -0,0 +1,10 @@
#include "main.h"
#include "scripting/decl.h"
mrb_value get_mode(mrb_state *mrb, mrb_value self) {
return mrb_fixnum_value(mode);
}
void setup_ruby_bindings(mrb_state *mrb, RClass *C_module) {
mrb_define_module_function(mrb, C_module, "mode", get_mode, MRB_ARGS_NONE());
}

View File

@@ -1,9 +1,11 @@
#include "ruby/internal/gc.h" #include "main.h"
#include "ruby/internal/value.h"
#include "scripting/decl.h" #include "scripting/decl.h"
#include "scripting/ruby_compiled.h"
#include "utils/utils.h" #include "utils/utils.h"
#include <mruby/boxing_word.h>
std::unordered_map<std::string, std::pair<VALUE, VALUE>> custom_highlighters; std::unordered_map<std::string, std::pair<mrb_value, mrb_value>>
custom_highlighters;
struct R_ThemeEntry { struct R_ThemeEntry {
std::string key; std::string key;
@@ -18,149 +20,280 @@ struct R_ThemeEntry {
struct R_Language { struct R_Language {
std::string name; std::string name;
uint32_t color = 0xFFFFFF; uint32_t color = 0xFFFFFF;
std::string symbol;
std::vector<std::string> extensions; std::vector<std::string> extensions;
std::vector<std::string> filenames; std::vector<std::string> filenames;
std::vector<std::string> mimetypes;
std::string lsp_command; // link to LSP by name std::string lsp_command; // link to LSP by name
}; };
VALUE C_module = Qnil; mrb_state *mrb = nullptr;
std::mutex ruby_mutex; RClass *C_module;
void ruby_start(const char *main_file) { namespace fs = std::filesystem;
std::lock_guard lock(ruby_mutex);
ruby_init_loadpath(); void ruby_start() {
int state = 0; mrb = mrb_open();
rb_load_protect(rb_str_new_cstr(main_file), 0, &state); if (!mrb) {
if (state) { fprintf(stderr, "Failed to init mruby\n");
rb_errinfo();
rb_set_errinfo(Qnil);
fprintf(stderr, "%d: Failed to load Ruby file\n", state);
return; return;
} }
C_module = rb_const_get(rb_cObject, rb_intern("C")); fs::path exe_dir = get_exe_dir();
if (C_module == Qnil) std::vector<fs::path> candidates;
return; candidates.emplace_back("./crib.rb");
VALUE block = rb_funcall(C_module, rb_intern("b_startup"), 0); const char *xdg = std::getenv("XDG_CONFIG_HOME");
if (block != Qnil) const char *home = std::getenv("HOME");
rb_funcall(block, rb_intern("call"), 0); if (xdg) {
candidates.emplace_back(fs::path(xdg) / "crib/crib.rb");
candidates.emplace_back(fs::path(xdg) / "crib/main.rb");
candidates.emplace_back(fs::path(xdg) / "crib.rb");
} else if (home) {
fs::path base = fs::path(home) / ".config";
candidates.emplace_back(base / "crib/crib.rb");
candidates.emplace_back(base / "crib/main.rb");
candidates.emplace_back(base / "crib.rb");
}
candidates.emplace_back(exe_dir / "../config/main.rb");
candidates.emplace_back(exe_dir / "../config/crib.rb");
mrb_load_irep(mrb, _tmp___crib_precompiled_mrb);
C_module = mrb_module_get(mrb, "C");
setup_ruby_bindings(mrb, C_module);
for (const auto &p : candidates) {
if (fs::exists(p)) {
FILE *f = fopen(p.string().c_str(), "r");
if (f) {
mrb_load_file(mrb, f);
if (mrb->exc)
exit(1);
fclose(f);
}
break;
}
}
mrb_value mod_val = mrb_obj_value(C_module);
mrb_value block = mrb_funcall(mrb, mod_val, "b_startup", 0);
mrb_funcall(mrb, block, "call", 0);
}
inline static std::vector<BarLight>
convert_highlights(mrb_state *mrb, mrb_value highlights_val) {
std::vector<BarLight> result;
if (!mrb_array_p(highlights_val))
return result;
mrb_int len = RARRAY_LEN(highlights_val);
for (mrb_int i = 0; i < len; i++) {
mrb_value item = mrb_ary_ref(mrb, highlights_val, i);
if (!mrb_hash_p(item))
continue;
auto get_sym = [&](const char *name) {
return mrb_symbol_value(mrb_intern_cstr(mrb, name));
};
mrb_value fg_v = mrb_hash_get(mrb, item, get_sym("fg"));
mrb_value bg_v = mrb_hash_get(mrb, item, get_sym("bg"));
mrb_value flags_v = mrb_hash_get(mrb, item, get_sym("flags"));
mrb_value start_v = mrb_hash_get(mrb, item, get_sym("start"));
mrb_value length_v = mrb_hash_get(mrb, item, get_sym("length"));
BarLight bl{};
if (!mrb_nil_p(fg_v))
bl.highlight.fg = (uint32_t)mrb_fixnum(fg_v);
if (!mrb_nil_p(bg_v))
bl.highlight.bg = (uint32_t)mrb_fixnum(bg_v);
if (!mrb_nil_p(flags_v))
bl.highlight.flags = (uint32_t)mrb_fixnum(flags_v);
uint32_t start = !mrb_nil_p(start_v) ? (uint32_t)mrb_fixnum(start_v) : 0;
uint32_t length = !mrb_nil_p(length_v) ? (uint32_t)mrb_fixnum(length_v) : 0;
bl.start = start;
bl.end = start + length;
result.push_back(bl);
}
return result;
}
BarLine bar_contents(uint8_t mode, std::string lang_name, uint32_t warnings,
std::string lsp_name, std::string filename,
std::string foldername, uint32_t line, uint32_t max_line,
uint32_t width) {
BarLine bar_line;
mrb_value info = mrb_hash_new(mrb);
mrb_value key_mode = mrb_symbol_value(mrb_intern_cstr(mrb, "mode"));
mrb_value val_mode;
switch (mode) {
case NORMAL:
val_mode = mrb_symbol_value(mrb_intern_cstr(mrb, "normal"));
break;
case INSERT:
val_mode = mrb_symbol_value(mrb_intern_cstr(mrb, "insert"));
break;
case SELECT:
val_mode = mrb_symbol_value(mrb_intern_cstr(mrb, "select"));
break;
case RUNNER:
val_mode = mrb_symbol_value(mrb_intern_cstr(mrb, "runner"));
break;
case JUMPER:
val_mode = mrb_symbol_value(mrb_intern_cstr(mrb, "jumper"));
break;
}
mrb_hash_set(mrb, info, key_mode, val_mode);
mrb_value key_lang_name = mrb_symbol_value(mrb_intern_cstr(mrb, "lang_name"));
mrb_value val_lang_name =
mrb_symbol_value(mrb_intern_cstr(mrb, lang_name.c_str()));
mrb_hash_set(mrb, info, key_lang_name, val_lang_name);
mrb_value key_filename = mrb_symbol_value(mrb_intern_cstr(mrb, "filename"));
mrb_value val_filename =
mrb_str_new(mrb, filename.c_str(), filename.length());
mrb_hash_set(mrb, info, key_filename, val_filename);
mrb_value key_width = mrb_symbol_value(mrb_intern_cstr(mrb, "width"));
mrb_value val_width = mrb_fixnum_value(width);
mrb_hash_set(mrb, info, key_width, val_width);
mrb_value mod_val = mrb_obj_value(C_module);
mrb_value block = mrb_funcall(mrb, mod_val, "b_bar", 0);
mrb_value val_line = mrb_funcall(mrb, block, "call", 1, info);
if (mrb->exc)
exit(1);
mrb_value text_val = mrb_hash_get(
mrb, val_line, mrb_symbol_value(mrb_intern_cstr(mrb, "text")));
const char *ptr = RSTRING_PTR(text_val);
mrb_int len = RSTRING_LEN(text_val);
bar_line.line = std::string(ptr, len);
mrb_value highlights_val = mrb_hash_get(
mrb, val_line, mrb_symbol_value(mrb_intern_cstr(mrb, "highlights")));
bar_line.highlights = convert_highlights(mrb, highlights_val);
return bar_line;
} }
void ruby_shutdown() { void ruby_shutdown() {
std::lock_guard lock(ruby_mutex); if (C_module == nullptr)
if (C_module == Qnil)
return; return;
VALUE block = rb_funcall(C_module, rb_intern("b_shutdown"), 0); mrb_value mod_val = mrb_obj_value(C_module);
if (block != Qnil) mrb_value block = mrb_funcall(mrb, mod_val, "b_shutdown", 0);
rb_funcall(block, rb_intern("call"), 0); mrb_funcall(mrb, block, "call", 0);
mrb_close(mrb);
mrb = nullptr;
C_module = nullptr;
} }
inline std::vector<std::string> ruby_array_to_vector(VALUE rb_array) { std::vector<std::string> array_to_vector(mrb_value ary) {
std::vector<std::string> result; std::vector<std::string> result;
if (NIL_P(rb_array) || !RB_TYPE_P(rb_array, T_ARRAY)) if (mrb_nil_p(ary) || mrb_type(ary) != MRB_TT_ARRAY)
return result; return result;
for (long i = 0; i < RARRAY_LEN(rb_array); ++i) { mrb_int len = RARRAY_LEN(ary);
VALUE item = rb_ary_entry(rb_array, i); for (mrb_int i = 0; i < len; i++) {
if (RB_TYPE_P(item, T_STRING)) mrb_value item = mrb_ary_ref(mrb, ary, i);
result.push_back(StringValueCStr(item)); if (mrb_string_p(item))
result.push_back(std::string(RSTRING_PTR(item), RSTRING_LEN(item)));
} }
return result; return result;
} }
void ruby_log(std::string msg) {
std::lock_guard lock(ruby_mutex);
VALUE str = rb_str_new(msg.c_str(), msg.size());
rb_funcall(C_module, rb_intern("queue_log"), 1, str);
}
void load_custom_highlighters() { void load_custom_highlighters() {
std::lock_guard lock(ruby_mutex); if (!C_module)
if (C_module == Qnil)
return; return;
VALUE hashmap = rb_funcall(C_module, rb_intern("highlighters"), 0); mrb_value mod_val = mrb_obj_value((struct RObject *)C_module);
if (NIL_P(hashmap)) mrb_value hashmap = mrb_funcall(mrb, mod_val, "highlighters", 0);
if (mrb_nil_p(hashmap) || mrb_type(hashmap) != MRB_TT_HASH)
return; return;
VALUE keys = rb_funcall(hashmap, rb_intern("keys"), 0); mrb_value keys = mrb_funcall(mrb, hashmap, "keys", 0);
for (long i = 0; i < RARRAY_LEN(keys); ++i) { mrb_int len = RARRAY_LEN(keys);
VALUE key_sym = rb_ary_entry(keys, i); for (mrb_int i = 0; i < len; i++) {
std::string key = rb_id2name(SYM2ID(key_sym)); mrb_value key_sym = mrb_ary_ref(mrb, keys, i);
VALUE val_hash = rb_hash_aref(hashmap, key_sym); mrb_sym sym_id = mrb_symbol(key_sym);
if (NIL_P(val_hash)) const char *key_cstr = mrb_sym_dump(mrb, sym_id);
std::string key(key_cstr);
mrb_value val_hash = mrb_hash_get(mrb, hashmap, key_sym);
if (mrb_nil_p(val_hash) || mrb_type(val_hash) != MRB_TT_HASH)
continue; continue;
VALUE parse_block = rb_hash_aref(val_hash, ID2SYM(rb_intern("parser"))); mrb_sym parser_sym = mrb_intern_lit(mrb, "parser");
VALUE match_block = rb_hash_aref(val_hash, ID2SYM(rb_intern("matcher"))); mrb_sym matcher_sym = mrb_intern_lit(mrb, "matcher");
rb_gc_register_address(&match_block); mrb_value parse_block =
rb_gc_register_address(&parse_block); mrb_hash_get(mrb, val_hash, mrb_symbol_value(parser_sym));
mrb_value match_block =
mrb_hash_get(mrb, val_hash, mrb_symbol_value(matcher_sym));
custom_highlighters[key] = {parse_block, match_block}; custom_highlighters[key] = {parse_block, match_block};
} }
} }
bool custom_compare(VALUE match_block, VALUE state1, VALUE state2) { bool custom_compare(mrb_value match_block, mrb_value state1, mrb_value state2) {
std::lock_guard lock(ruby_mutex); if (mrb_type(match_block) != MRB_TT_PROC)
return RTEST(rb_funcall(match_block, rb_intern("call"), 2, state1, state2)); return false;
mrb_value ret = mrb_funcall(mrb, match_block, "call", 2, state1, state2);
return mrb_test(ret);
} }
VALUE parse_custom(std::vector<Token> *tokens, VALUE parser_block, mrb_value parse_custom(std::vector<Token> *tokens, mrb_value parser_block,
const char *line, uint32_t len, VALUE state) { const char *line, uint32_t len, mrb_value state,
std::lock_guard lock(ruby_mutex); uint32_t c_line) {
tokens->clear(); tokens->clear();
if (NIL_P(parser_block)) if (mrb_nil_p(parser_block))
return {}; return mrb_nil_value();
VALUE ruby_line = rb_str_new(line, len); mrb_value ruby_line = mrb_str_new(mrb, line, len);
VALUE tokens_and_state_hash = mrb_value line_idx = mrb_fixnum_value(c_line);
rb_funcall(parser_block, rb_intern("call"), 2, ruby_line, state); mrb_value tokens_and_state_hash =
VALUE tokens_rb = mrb_funcall(mrb, parser_block, "call", 3, ruby_line, state, line_idx);
rb_hash_aref(tokens_and_state_hash, ID2SYM(rb_intern("tokens"))); mrb_sym tokens_sym = mrb_intern_lit(mrb, "tokens");
for (long i = 0; i < RARRAY_LEN(tokens_rb); ++i) { mrb_value tokens_rb =
VALUE token = rb_ary_entry(tokens_rb, i); mrb_hash_get(mrb, tokens_and_state_hash, mrb_symbol_value(tokens_sym));
if (mrb_type(tokens_rb) == MRB_TT_ARRAY) {
mrb_int len_tokens = RARRAY_LEN(tokens_rb);
for (mrb_int i = 0; i < len_tokens; i++) {
mrb_value token = mrb_ary_ref(mrb, tokens_rb, i);
Token tok; Token tok;
tok.type = tok.type = (TokenKind)mrb_fixnum(mrb_hash_get(
(TokenKind)NUM2INT(rb_hash_aref(token, ID2SYM(rb_intern("type")))); mrb, token, mrb_symbol_value(mrb_intern_lit(mrb, "type"))));
tok.start = NUM2UINT(rb_hash_aref(token, ID2SYM(rb_intern("start")))); tok.start = (uint32_t)mrb_fixnum(mrb_hash_get(
tok.end = NUM2UINT(rb_hash_aref(token, ID2SYM(rb_intern("end")))); mrb, token, mrb_symbol_value(mrb_intern_lit(mrb, "start"))));
tok.end = (uint32_t)mrb_fixnum(mrb_hash_get(
mrb, token, mrb_symbol_value(mrb_intern_lit(mrb, "end"))));
if (tok.type < TokenKind::Count && tok.end > tok.start && tok.end <= len) if (tok.type < TokenKind::Count && tok.end > tok.start && tok.end <= len)
tokens->push_back(tok); tokens->push_back(tok);
} }
return rb_hash_aref(tokens_and_state_hash, ID2SYM(rb_intern("state"))); }
mrb_sym state_sym = mrb_intern_lit(mrb, "state");
return mrb_hash_get(mrb, tokens_and_state_hash, mrb_symbol_value(state_sym));
} }
static std::vector<R_ThemeEntry> read_theme() { static std::vector<R_ThemeEntry> read_theme() {
std::lock_guard lock(ruby_mutex);
std::vector<R_ThemeEntry> result; std::vector<R_ThemeEntry> result;
if (C_module == Qnil) if (!C_module)
return result; return result;
VALUE theme_hash = rb_funcall(C_module, rb_intern("theme"), 0); mrb_value mod_val = mrb_obj_value((struct RObject *)C_module);
if (NIL_P(theme_hash)) mrb_value theme_hash = mrb_funcall(mrb, mod_val, "theme", 0);
if (mrb_nil_p(theme_hash) || mrb_type(theme_hash) != MRB_TT_HASH)
return result; return result;
VALUE keys = rb_funcall(theme_hash, rb_intern("keys"), 0); mrb_value keys = mrb_funcall(mrb, theme_hash, "keys", 0);
for (long i = 0; i < RARRAY_LEN(keys); ++i) { mrb_int len_keys = RARRAY_LEN(keys);
VALUE key_sym = rb_ary_entry(keys, i); for (mrb_int i = 0; i < len_keys; i++) {
std::string key = rb_id2name(SYM2ID(key_sym)); mrb_value key_sym = mrb_ary_ref(mrb, keys, i);
VALUE val_hash = rb_hash_aref(theme_hash, key_sym); mrb_sym sym_id = mrb_symbol(key_sym);
if (NIL_P(val_hash)) const char *key_cstr = mrb_sym_dump(mrb, sym_id);
std::string key(key_cstr);
mrb_value val_hash = mrb_hash_get(mrb, theme_hash, key_sym);
if (mrb_nil_p(val_hash) || mrb_type(val_hash) != MRB_TT_HASH)
continue; continue;
R_ThemeEntry entry; R_ThemeEntry entry;
entry.key = key; entry.key = key;
VALUE fg = rb_hash_aref(val_hash, ID2SYM(rb_intern("fg"))); mrb_value fg = mrb_hash_get(mrb, val_hash,
VALUE bg = rb_hash_aref(val_hash, ID2SYM(rb_intern("bg"))); mrb_symbol_value(mrb_intern_lit(mrb, "fg")));
VALUE italic = rb_hash_aref(val_hash, ID2SYM(rb_intern("italic"))); mrb_value bg = mrb_hash_get(mrb, val_hash,
VALUE bold = rb_hash_aref(val_hash, ID2SYM(rb_intern("bold"))); mrb_symbol_value(mrb_intern_lit(mrb, "bg")));
VALUE underline = rb_hash_aref(val_hash, ID2SYM(rb_intern("underline"))); mrb_value italic = mrb_hash_get(
VALUE strikethrough = mrb, val_hash, mrb_symbol_value(mrb_intern_lit(mrb, "italic")));
rb_hash_aref(val_hash, ID2SYM(rb_intern("strikethrough"))); mrb_value bold = mrb_hash_get(
if (!NIL_P(fg)) mrb, val_hash, mrb_symbol_value(mrb_intern_lit(mrb, "bold")));
entry.fg = NUM2UINT(fg); mrb_value underline = mrb_hash_get(
if (!NIL_P(bg)) mrb, val_hash, mrb_symbol_value(mrb_intern_lit(mrb, "underline")));
entry.bg = NUM2UINT(bg); mrb_value strikethrough = mrb_hash_get(
if (!NIL_P(italic)) mrb, val_hash, mrb_symbol_value(mrb_intern_lit(mrb, "strikethrough")));
entry.italic = RTEST(italic); if (!mrb_nil_p(fg))
if (!NIL_P(bold)) entry.fg = (uint32_t)mrb_fixnum(fg);
entry.bold = RTEST(bold); if (!mrb_nil_p(bg))
if (!NIL_P(underline)) entry.bg = (uint32_t)mrb_fixnum(bg);
entry.underline = RTEST(underline); if (!mrb_nil_p(italic))
if (!NIL_P(strikethrough)) entry.italic = mrb_test(italic);
entry.strikethrough = RTEST(strikethrough); if (!mrb_nil_p(bold))
entry.bold = mrb_test(bold);
if (!mrb_nil_p(underline))
entry.underline = mrb_test(underline);
if (!mrb_nil_p(strikethrough))
entry.strikethrough = mrb_test(strikethrough);
result.push_back(entry); result.push_back(entry);
} }
return result; return result;
@@ -212,17 +345,23 @@ void load_theme() {
std::vector<LSP> read_lsps() { std::vector<LSP> read_lsps() {
std::vector<LSP> result; std::vector<LSP> result;
if (C_module == Qnil) if (!C_module)
return result; return result;
VALUE lsp_hash = rb_funcall(C_module, rb_intern("lsp_config"), 0); mrb_value mod_val = mrb_obj_value((struct RObject *)C_module);
if (NIL_P(lsp_hash)) mrb_value lsp_hash = mrb_funcall(mrb, mod_val, "lsp_config", 0);
if (mrb_nil_p(lsp_hash) || mrb_type(lsp_hash) != MRB_TT_HASH)
return result; return result;
VALUE keys = rb_funcall(lsp_hash, rb_intern("keys"), 0); mrb_value keys = mrb_funcall(mrb, lsp_hash, "keys", 0);
for (long i = 0; i < RARRAY_LEN(keys); ++i) { mrb_int len_keys = RARRAY_LEN(keys);
VALUE key = rb_ary_entry(keys, i); for (mrb_int i = 0; i < len_keys; i++) {
std::string cmd = StringValueCStr(key); mrb_value key = mrb_ary_ref(mrb, keys, i);
VALUE args_array = rb_hash_aref(lsp_hash, key); std::string cmd;
std::vector<std::string> args = ruby_array_to_vector(args_array); if (mrb_string_p(key))
cmd = std::string(RSTRING_PTR(key), RSTRING_LEN(key));
else if (mrb_symbol_p(key))
cmd = std::string(mrb_sym_dump(mrb, mrb_symbol(key)));
mrb_value args_array = mrb_hash_get(mrb, lsp_hash, key);
std::vector<std::string> args = array_to_vector(args_array);
result.push_back({cmd, args}); result.push_back({cmd, args});
} }
return result; return result;
@@ -230,41 +369,45 @@ std::vector<LSP> read_lsps() {
std::vector<R_Language> read_languages() { std::vector<R_Language> read_languages() {
std::vector<R_Language> result; std::vector<R_Language> result;
if (C_module == Qnil) if (!C_module)
return result; return result;
VALUE lang_hash = rb_funcall(C_module, rb_intern("languages"), 0); mrb_value mod_val = mrb_obj_value((struct RObject *)C_module);
if (NIL_P(lang_hash)) mrb_value lang_hash = mrb_funcall(mrb, mod_val, "languages", 0);
if (mrb_nil_p(lang_hash) || mrb_type(lang_hash) != MRB_TT_HASH)
return result; return result;
VALUE keys = rb_funcall(lang_hash, rb_intern("keys"), 0); mrb_value keys = mrb_funcall(mrb, lang_hash, "keys", 0);
for (long i = 0; i < RARRAY_LEN(keys); ++i) { mrb_int len_keys = RARRAY_LEN(keys);
VALUE key = rb_ary_entry(keys, i); for (mrb_int i = 0; i < len_keys; i++) {
VALUE val_hash = rb_hash_aref(lang_hash, key); mrb_value key = mrb_ary_ref(mrb, keys, i);
if (NIL_P(val_hash)) mrb_value val_hash = mrb_hash_get(mrb, lang_hash, key);
if (mrb_nil_p(val_hash) || mrb_type(val_hash) != MRB_TT_HASH)
continue; continue;
R_Language lang; R_Language lang;
lang.name = rb_id2name(SYM2ID(key)); if (mrb_symbol_p(key))
VALUE fg = rb_hash_aref(val_hash, ID2SYM(rb_intern("color"))); lang.name = std::string(mrb_sym_dump(mrb, mrb_symbol(key)));
VALUE symbol = rb_hash_aref(val_hash, ID2SYM(rb_intern("symbol"))); else if (mrb_string_p(key))
VALUE extensions = rb_hash_aref(val_hash, ID2SYM(rb_intern("extensions"))); lang.name = std::string(RSTRING_PTR(key), RSTRING_LEN(key));
VALUE filenames = rb_hash_aref(val_hash, ID2SYM(rb_intern("filenames"))); mrb_value fg = mrb_hash_get(mrb, val_hash,
VALUE mimetypes = rb_hash_aref(val_hash, ID2SYM(rb_intern("mimetypes"))); mrb_symbol_value(mrb_intern_lit(mrb, "color")));
VALUE lsp = rb_hash_aref(val_hash, ID2SYM(rb_intern("lsp"))); mrb_value extensions = mrb_hash_get(
if (!NIL_P(fg)) mrb, val_hash, mrb_symbol_value(mrb_intern_lit(mrb, "extensions")));
lang.color = NUM2UINT(fg); mrb_value filenames = mrb_hash_get(
if (!NIL_P(symbol)) mrb, val_hash, mrb_symbol_value(mrb_intern_lit(mrb, "filenames")));
lang.symbol = StringValueCStr(symbol); mrb_value lsp = mrb_hash_get(mrb, val_hash,
lang.extensions = ruby_array_to_vector(extensions); mrb_symbol_value(mrb_intern_lit(mrb, "lsp")));
lang.filenames = ruby_array_to_vector(filenames); if (!mrb_nil_p(fg))
lang.mimetypes = ruby_array_to_vector(mimetypes); lang.color = (uint32_t)mrb_fixnum(fg);
if (!NIL_P(lsp)) lang.extensions = array_to_vector(extensions);
lang.lsp_command = StringValueCStr(lsp); if (!mrb_nil_p(filenames))
lang.filenames = array_to_vector(filenames);
if (!mrb_nil_p(lsp))
lang.lsp_command = std::string(RSTRING_PTR(lsp), RSTRING_LEN(lsp));
result.push_back(lang); result.push_back(lang);
} }
return result; return result;
} }
void load_languages_info() { void load_languages_info() {
std::lock_guard lock(ruby_mutex);
auto langs = read_languages(); auto langs = read_languages();
auto lsps_t = read_lsps(); auto lsps_t = read_lsps();
languages.clear(); languages.clear();
@@ -273,26 +416,33 @@ void load_languages_info() {
l.name = lang.name; l.name = lang.name;
l.color = lang.color; l.color = lang.color;
l.lsp_name = lang.lsp_command; l.lsp_name = lang.lsp_command;
l.symbol = lang.symbol;
languages[lang.name] = l; languages[lang.name] = l;
for (auto &ext : lang.extensions) for (auto &ext : lang.extensions)
language_extensions[ext] = lang.name; language_extensions[ext] = lang.name;
// TODO: seperate extensions and filenames // TODO: seperate extensions and filenames
for (auto &filename : lang.filenames) for (auto &filename : lang.filenames)
language_extensions[filename] = lang.name; language_extensions[filename] = lang.name;
for (auto &mimetype : lang.mimetypes)
language_mimetypes[mimetype] = lang.name;
} }
for (auto &lsp : lsps_t) for (auto &lsp : lsps_t)
lsps[lsp.command] = lsp; lsps[lsp.command] = lsp;
} }
bool read_line_endings() { uint8_t read_line_endings() {
std::lock_guard lock(ruby_mutex); if (!C_module)
if (C_module == Qnil) return 1;
return true; mrb_value mod_val = mrb_obj_value((struct RObject *)C_module);
VALUE le = rb_funcall(C_module, rb_intern("line_endings"), 0); mrb_value le = mrb_funcall(mrb, mod_val, "line_endings", 0);
if (SYMBOL_P(le)) if (!mrb_symbol_p(le))
return std::string(rb_id2name(SYM2ID(le))) == "unix"; return 1;
return true; uint8_t flags = 1;
const char *name = mrb_sym_dump(mrb, mrb_symbol(le));
if (std::strcmp(name, "unix") == 0)
flags = 0b01;
else if (std::strcmp(name, "windows") == 0)
flags = 0b00;
else if (std::strcmp(name, "auto_unix") == 0)
flags = 0b11;
else if (std::strcmp(name, "auto_windows") == 0)
flags = 0b10;
return flags;
} }

View File

@@ -1,11 +1,10 @@
#include "syntax/decl.h" #include "syntax/decl.h"
#include "syntax/langs.h" #include "syntax/langs.h"
#include <cstdint>
struct BashFullState { struct BashFullState {
int brace_level = 0; int brace_level = 0;
enum : uint8_t { NONE, STRING, HEREDOC }; enum : uint8_t { NONE, STRING, HEREDOC, PARAMETER };
uint8_t in_state = BashFullState::NONE; uint8_t in_state = BashFullState::NONE;
bool line_cont = false; bool line_cont = false;
@@ -50,7 +49,8 @@ bool bash_state_match(std::shared_ptr<void> state_1,
std::shared_ptr<void> bash_parse(std::vector<Token> *tokens, std::shared_ptr<void> bash_parse(std::vector<Token> *tokens,
std::shared_ptr<void> in_state, std::shared_ptr<void> in_state,
const char *text, uint32_t len) { const char *text, uint32_t len,
uint32_t line_num) {
static bool keywords_trie_init = false; static bool keywords_trie_init = false;
if (!keywords_trie_init) { if (!keywords_trie_init) {
keywords_trie_init = true; keywords_trie_init = true;
@@ -64,10 +64,44 @@ std::shared_ptr<void> bash_parse(std::vector<Token> *tokens,
if (len == 0) if (len == 0)
return state; return state;
while (i < len) { while (i < len) {
if (state->full_state->in_state == BashFullState::PARAMETER) {
uint32_t start = i;
while (i < len) {
if (text[i] == '{') {
i++;
state->full_state->brace_level++;
continue;
}
if (text[i] == '}') {
if (--state->full_state->brace_level == 0 &&
!state->interp_stack.empty()) {
tokens->push_back({i - 1, i, TokenKind::K_INTERPOLATION});
state->full_state = state->interp_stack.top();
state->interp_stack.pop();
i++;
break;
}
}
i++;
}
continue;
}
if (state->full_state->in_state == BashFullState::STRING) { if (state->full_state->in_state == BashFullState::STRING) {
uint32_t start = i; uint32_t start = i;
while (i < len) { while (i < len) {
if (state->full_state->lit.allow_interp && text[i] == '$') {
if (++i < len && text[i] == '{') {
tokens->push_back({start, i - 1, TokenKind::K_STRING});
tokens->push_back({i - 1, i, TokenKind::K_INTERPOLATION});
state->interp_stack.push(state->full_state);
state->full_state = std::make_shared<BashFullState>();
state->full_state->in_state = BashFullState::PARAMETER;
state->full_state->brace_level = 1;
break;
}
}
if (text[i] == state->full_state->lit.delim[0]) { if (text[i] == state->full_state->lit.delim[0]) {
i++;
tokens->push_back({start, i, TokenKind::K_STRING}); tokens->push_back({start, i, TokenKind::K_STRING});
state->full_state->in_state = BashFullState::NONE; state->full_state->in_state = BashFullState::NONE;
break; break;
@@ -79,7 +113,7 @@ std::shared_ptr<void> bash_parse(std::vector<Token> *tokens,
continue; continue;
} }
if (text[i] == '#') { if (text[i] == '#') {
if (i == 0 && len > 4 && text[i + 1] == '!') { if (line_num == 0 && i == 0 && len > 4 && text[i + 1] == '!') {
tokens->push_back({0, len, TokenKind::K_SHEBANG}); tokens->push_back({0, len, TokenKind::K_SHEBANG});
return state; return state;
} }
@@ -91,6 +125,12 @@ std::shared_ptr<void> bash_parse(std::vector<Token> *tokens,
state->full_state->lit.allow_interp = false; state->full_state->lit.allow_interp = false;
tokens->push_back({i, ++i, TokenKind::K_STRING}); tokens->push_back({i, ++i, TokenKind::K_STRING});
continue; continue;
} else if (text[i] == '"') {
state->full_state->in_state = BashFullState::STRING;
state->full_state->lit.delim = "\"";
state->full_state->lit.allow_interp = true;
tokens->push_back({i, ++i, TokenKind::K_STRING});
continue;
} }
i++; i++;
} }

View File

@@ -2,7 +2,6 @@
#include "editor/editor.h" #include "editor/editor.h"
#include "io/knot.h" #include "io/knot.h"
#include "main.h" #include "main.h"
#include "ruby/internal/special_consts.h"
#include "syntax/decl.h" #include "syntax/decl.h"
#include "syntax/langs.h" #include "syntax/langs.h"
@@ -64,6 +63,10 @@ void Parser::work() {
dirty_lines.push(c_line); dirty_lines.push(c_line);
continue; continue;
} }
if (scroll_max > 50 && c_line < scroll_max - 50) {
dirty_lines.push(c_line);
continue;
}
uint32_t line_count = line_tree.count(); uint32_t line_count = line_tree.count();
lock_data.lock(); lock_data.lock();
std::shared_ptr<void> prev_state = std::shared_ptr<void> prev_state =
@@ -112,19 +115,20 @@ void Parser::work() {
} }
std::shared_ptr<void> new_state{nullptr}; std::shared_ptr<void> new_state{nullptr};
if (is_custom) { if (is_custom) {
VALUE state = Qnil; mrb_value state = mrb_nil_value();
if (prev_state) { if (prev_state) {
std::shared_ptr<CustomState> state_ptr = std::shared_ptr<CustomState> state_ptr =
std::static_pointer_cast<CustomState>(prev_state); std::static_pointer_cast<CustomState>(prev_state);
state = state_ptr->state; state = state_ptr->state;
} }
VALUE out_state = mrb_value out_state = parse_custom(&line_data->tokens, parser_block,
parse_custom(&line_data->tokens, parser_block, text, r_len, state); text, r_len, state, c_line);
std::shared_ptr<CustomState> out_state_ptr = std::shared_ptr<CustomState> out_state_ptr =
std::make_shared<CustomState>(out_state); std::make_shared<CustomState>(out_state);
new_state = out_state_ptr; new_state = out_state_ptr;
} else { } else {
new_state = parse_func(&line_data->tokens, prev_state, text, r_len); new_state =
parse_func(&line_data->tokens, prev_state, text, r_len, c_line);
} }
line_data->in_state = prev_state; line_data->in_state = prev_state;
line_data->out_state = new_state; line_data->out_state = new_state;
@@ -134,7 +138,8 @@ void Parser::work() {
} }
prev_state = new_state; prev_state = new_state;
c_line++; c_line++;
if (c_line < line_count && c_line > scroll_max + 50) { if (c_line < line_count && c_line > scroll_max + 50 && scroll_max < 50 &&
c_line < scroll_max + 50) {
lock_data.unlock(); lock_data.unlock();
if (lock.owns_lock()) if (lock.owns_lock())
lock.unlock(); lock.unlock();
@@ -146,11 +151,11 @@ void Parser::work() {
if (c_line < line_count && (line_data = line_tree.at(c_line))) { if (c_line < line_count && (line_data = line_tree.at(c_line))) {
bool done = false; bool done = false;
if (is_custom) { if (is_custom) {
VALUE in_state_v = Qnil; mrb_value in_state_v = mrb_nil_value();
if (prev_state) if (prev_state)
in_state_v = in_state_v =
std::static_pointer_cast<CustomState>(prev_state)->state; std::static_pointer_cast<CustomState>(prev_state)->state;
VALUE out_state_v = Qnil; mrb_value out_state_v = mrb_nil_value();
if (line_data->in_state) if (line_data->in_state)
out_state_v = out_state_v =
std::static_pointer_cast<CustomState>(line_data->in_state) std::static_pointer_cast<CustomState>(line_data->in_state)

View File

@@ -288,7 +288,8 @@ bool ruby_state_match(std::shared_ptr<void> state_1,
std::shared_ptr<void> ruby_parse(std::vector<Token> *tokens, std::shared_ptr<void> ruby_parse(std::vector<Token> *tokens,
std::shared_ptr<void> in_state, std::shared_ptr<void> in_state,
const char *text, uint32_t len) { const char *text, uint32_t len,
uint32_t line_num) {
static bool keywords_trie_init = false; static bool keywords_trie_init = false;
static Trie<void> base_keywords_trie; static Trie<void> base_keywords_trie;
static Trie<void> expecting_keywords_trie; static Trie<void> expecting_keywords_trie;
@@ -703,7 +704,7 @@ std::shared_ptr<void> ruby_parse(std::vector<Token> *tokens,
i++; i++;
continue; continue;
} else if (text[i] == '#') { } else if (text[i] == '#') {
if (i == 0 && len > 4 && text[i + 1] == '!') { if (line_num == 0 && i == 0 && len > 4 && text[i + 1] == '!') {
state->full_state->expecting_expr = false; state->full_state->expecting_expr = false;
tokens->push_back({0, len, TokenKind::K_SHEBANG}); tokens->push_back({0, len, TokenKind::K_SHEBANG});
return state; return state;

View File

@@ -1,66 +1,59 @@
#include "ui/bar.h" #include "ui/bar.h"
#include "io/sysio.h" #include "io/sysio.h"
#include "lsp/lsp.h"
#include "main.h" #include "main.h"
#include "syntax/decl.h"
void Bar::work() {
std::lock_guard<std::mutex> lock(mtx);
Editor *editor = editors[current_editor];
bar_line =
bar_contents(mode, editor->lang.name, editor->warnings.size(),
editor->lsp ? editor->lsp->lsp->command : "",
editor->filename, editor->filename, editor->cursor.row + 1,
editor->root->line_count + 1, screen.col);
}
void Bar::log(std::string message) {
std::lock_guard<std::mutex> lock(mtx);
log_line = message;
}
void Bar::render() { void Bar::render() {
Editor *editor = editors[current_editor]; std::lock_guard<std::mutex> lock(mtx);
USING(LSPInstance);
uint32_t row = screen.row - 2; uint32_t row = screen.row - 2;
uint32_t col = 0;
uint32_t width = screen.col; uint32_t width = screen.col;
UNUSED(width); std::string &line = bar_line.line;
uint32_t color = 0; uint32_t i = 0;
uint32_t black = 0x0b0e14; uint32_t col = 0;
uint32_t grey = 0x33363c; while (i < line.length()) {
uint32_t dark_grey = 0x24272d; uint32_t cluster_len =
uint32_t name_color = 0xced4df; grapheme_next_character_break_utf8(line.c_str() + i, line.length() - i);
uint32_t lang_color = editor->lang.color; std::string cluster = line.substr(i, cluster_len);
const char *symbol = "󱓧 "; int width = display_width(cluster.c_str(), cluster_len);
const char *name = "EDITOR"; Highlight highlight = bar_line.get_highlight(col);
switch (mode) { update(row, col, cluster.c_str(), highlight.fg, highlight.bg,
case NORMAL: highlight.flags);
color = 0x82AAFF; col += width;
symbol = ""; i += cluster_len;
name = "NORMAL"; for (int w = 1; w < width; w++)
break; update(row, col - w, "\x1b", highlight.fg, highlight.bg, highlight.flags);
case INSERT:
color = 0xFF8F40;
symbol = "󱓧 ";
name = "INSERT";
break;
case SELECT:
color = 0x9ADE7A;
symbol = "󱩧 ";
name = "SELECT";
break;
case RUNNER:
color = 0xFFD700;
symbol = "";
name = "RUNNER";
break;
case JUMPER:
color = 0xF29CC3;
symbol = "";
name = "JUMPER";
break;
} }
update(row, col, " ", black, color, CF_BOLD); while (col < width)
update(row, ++col, symbol, black, color, CF_BOLD); update(row, col++, " ", 0, 0, 0);
update(row, ++col, "\x1b", black, color, CF_BOLD); col = 0;
update(row, ++col, " ", black, color, CF_BOLD); row++;
for (uint32_t i = 0; i < 6; i++) if (mode == RUNNER) {
update(row, ++col, {name[i], 0}, black, color, CF_BOLD); update(row, col++, ":", 0xFFFFFF, 0, 0);
update(row, ++col, " ", black, color, CF_BOLD); for (char c : command)
update(row, ++col, "", color, grey, CF_BOLD); update(row, col++, (char[2]){c, 0}, 0xFFFFFF, 0, 0);
update(row, ++col, "", grey, dark_grey, CF_BOLD); } else {
update(row, ++col, " ", name_color, dark_grey, CF_BOLD); for (char c : log_line)
update(row, ++col, editor->lang.symbol, lang_color, dark_grey, 0); update(row, col++, (char[2]){c, 0}, 0xFFFFFF, 0, 0);
update(row, ++col, "\x1b", lang_color, dark_grey, 0); }
update(row, ++col, " ", name_color, dark_grey, CF_BOLD); while (col < width)
std::string filename = filename_from_path(editor->filename); update(row, col++, " ", 0, 0, 0);
for (uint32_t i = 0; i < filename.length(); i++)
update(row, ++col, {filename[i], 0}, name_color, dark_grey, CF_BOLD);
update(row, ++col, " ", name_color, dark_grey, CF_BOLD);
update(row, ++col, "", dark_grey, 1, CF_BOLD);
} }
void Bar::handle(KeyEvent event) { void Bar::handle(KeyEvent event) {
@@ -68,11 +61,26 @@ void Bar::handle(KeyEvent event) {
if (event.c[0] == 0x1B) { if (event.c[0] == 0x1B) {
mode = NORMAL; mode = NORMAL;
} else if (event.c[0] == '\n' || event.c[0] == '\r') { } else if (event.c[0] == '\n' || event.c[0] == '\r') {
// execute command while stripping starting `[:;]` command = trim(command);
if (command == "w") {
save_file(editors[current_editor]);
} else if (command == "q") {
running = false;
} else if (command == "wq") {
save_file(editors[current_editor]);
running = false;
}
mode = NORMAL; mode = NORMAL;
command = ""; command = "";
} else if (isprint((unsigned char)(event.c[0]))) { } else if (isprint((unsigned char)(event.c[0]))) {
} else if (event.c[0] == 0x7F || event.c[0] == 0x08) { // backspace command += event.c[0];
} else if (event.c[0] == 0x7F || event.c[0] == 0x08) {
if (command.length() > 0) {
command = command.substr(0, command.length() - 1);
} else {
mode = NORMAL;
command = "";
}
} }
} else if (event.key_type == KEY_SPECIAL) { } else if (event.key_type == KEY_SPECIAL) {
switch (event.special_key) { switch (event.special_key) {

View File

@@ -71,7 +71,9 @@ void CompletionBox::render_update() {
uint32_t max_label_len = 0; uint32_t max_label_len = 0;
uint32_t max_detail_len = 0; uint32_t max_detail_len = 0;
uint32_t max_kind_len = 0; uint32_t max_kind_len = 0;
for (auto i : session->visible) { for (uint32_t x = session->scroll;
x < session->scroll + 8 && x < session->visible.size(); x++) {
uint32_t i = session->visible[x];
if (i >= session->items.size()) if (i >= session->items.size())
continue; continue;
auto &item = session->items[i]; auto &item = session->items[i];
@@ -81,7 +83,9 @@ void CompletionBox::render_update() {
max_kind_len = max_kind_len =
MAX(max_kind_len, (uint32_t)item_kind_name(item.kind).size()); MAX(max_kind_len, (uint32_t)item_kind_name(item.kind).size());
} }
size.row = session->visible.size() + 2; uint32_t total = session->visible.size();
uint32_t rows = MIN(total, 8);
size.row = rows + 2;
size.col = 2 + 2 + max_label_len + 1 + max_detail_len + 2 + max_kind_len + 1; size.col = 2 + 2 + max_label_len + 1 + max_detail_len + 2 + max_kind_len + 1;
cells.assign(size.row * size.col, {" ", 0, 0, 0, 0, 0}); cells.assign(size.row * size.col, {" ", 0, 0, 0, 0, 0});
auto set = [&](uint32_t r, uint32_t c, const char *text, uint32_t fg, auto set = [&](uint32_t r, uint32_t c, const char *text, uint32_t fg,
@@ -95,8 +99,10 @@ void CompletionBox::render_update() {
for (uint32_t c = 1; c < size.col - 1; c++) for (uint32_t c = 1; c < size.col - 1; c++)
set(0, c, "", border_fg, 0, 0); set(0, c, "", border_fg, 0, 0);
set(0, size.col - 1, "", border_fg, 0, 0); set(0, size.col - 1, "", border_fg, 0, 0);
for (uint32_t row_idx = 0; row_idx < session->visible.size(); row_idx++) { uint32_t start = session->scroll;
uint32_t r = row_idx + 1; uint32_t end = MIN(start + 8, session->visible.size());
for (uint32_t row_idx = start; row_idx < end; row_idx++) {
uint32_t r = (row_idx - start) + 1;
auto &item = session->items[session->visible[row_idx]]; auto &item = session->items[session->visible[row_idx]];
uint32_t bg = (session->visible[row_idx] == session->select) ? sel_bg : 1; uint32_t bg = (session->visible[row_idx] == session->select) ? sel_bg : 1;
uint32_t fg = 0xFFFFFF; uint32_t fg = 0xFFFFFF;
@@ -130,6 +136,12 @@ void CompletionBox::render_update() {
for (uint32_t c = 1; c < size.col - 1; c++) for (uint32_t c = 1; c < size.col - 1; c++)
set(bottom, c, "", border_fg, 0, 0); set(bottom, c, "", border_fg, 0, 0);
set(bottom, size.col - 1, "", border_fg, 0, 0); set(bottom, size.col - 1, "", border_fg, 0, 0);
if (session->visible.size() > 8) {
std::string info = std::to_string(start + 1) + "-" + std::to_string(end) +
"/" + std::to_string(session->visible.size());
for (size_t i = 0; i < info.size() && i < size.col - 2; i++)
set(bottom, 1 + i, (char[2]){info[i], 0}, border_fg, 0, 0);
}
} }
void CompletionBox::render(Coord pos) { void CompletionBox::render(Coord pos) {

View File

@@ -2,7 +2,6 @@
std::unordered_map<std::string, Language> languages; std::unordered_map<std::string, Language> languages;
std::unordered_map<std::string, std::string> language_extensions; std::unordered_map<std::string, std::string> language_extensions;
std::unordered_map<std::string, std::string> language_mimetypes;
std::unordered_map<std::string, LSP> lsps; std::unordered_map<std::string, LSP> lsps;
void log(const char *fmt, ...) { void log(const char *fmt, ...) {
@@ -44,7 +43,7 @@ std::string get_exe_dir() {
return path.substr(0, path.find_last_of('/')); return path.substr(0, path.find_last_of('/'));
} }
char *load_file(const char *path, uint32_t *out_len) { char *load_file(const char *path, uint32_t *out_len, bool *out_eol) {
std::ifstream file(path, std::ios::binary | std::ios::ate); std::ifstream file(path, std::ios::binary | std::ios::ate);
if (!file.is_open()) if (!file.is_open())
return nullptr; return nullptr;
@@ -64,18 +63,28 @@ char *load_file(const char *path, uint32_t *out_len) {
if (!buf) if (!buf)
return nullptr; return nullptr;
file.read(buf, data_len); file.read(buf, data_len);
if (memchr(buf, '\r', data_len) == nullptr) { bool has_cr = memchr(buf, '\r', data_len) != nullptr;
bool has_lf = memchr(buf, '\n', data_len) != nullptr;
if (!has_cr && !has_lf) {
uint32_t write = data_len; uint32_t write = data_len;
if (write == 0 || buf[write - 1] != '\n')
buf[write++] = '\n'; buf[write++] = '\n';
*out_len = write; *out_len = write;
return buf; return buf;
} }
if (!has_cr) {
*out_eol = true;
uint32_t write = data_len;
if (buf[write - 1] != '\n')
buf[write++] = '\n';
*out_len = write;
return buf;
}
*out_eol = false;
uint32_t write = 0; uint32_t write = 0;
for (uint32_t i = 0; i < data_len; ++i) for (uint32_t i = 0; i < data_len; ++i)
if (buf[i] != '\r') if (buf[i] != '\r')
buf[write++] = buf[i]; buf[write++] = buf[i];
if (write == 0 || buf[write - 1] != '\n') if (buf[write - 1] != '\n')
buf[write++] = '\n'; buf[write++] = '\n';
*out_len = write; *out_len = write;
return buf; return buf;
@@ -96,24 +105,6 @@ static std::string file_extension(const char *filename) {
return ext; return ext;
} }
char *detect_file_type(const char *filename) {
magic_t magic = magic_open(MAGIC_MIME_TYPE);
if (!magic)
return nullptr;
if (magic_load(magic, nullptr) != 0) {
magic_close(magic);
return nullptr;
}
const char *type = magic_file(magic, filename);
if (!type) {
magic_close(magic);
return nullptr;
}
char *result = strdup(type);
magic_close(magic);
return result;
}
Language language_for_file(const char *filename) { Language language_for_file(const char *filename) {
std::string ext = file_extension(filename); std::string ext = file_extension(filename);
std::string lang_name; std::string lang_name;
@@ -122,14 +113,6 @@ Language language_for_file(const char *filename) {
if (it != language_extensions.end()) if (it != language_extensions.end())
return languages.find(it->second)->second; return languages.find(it->second)->second;
} }
char *mime = detect_file_type(filename);
if (mime) {
std::string mime_type(mime);
free(mime);
auto it = language_mimetypes.find(mime_type);
if (it != language_mimetypes.end())
return languages.find(it->second)->second;
}
return Language{}; return Language{};
} }

View File

@@ -1,4 +1,3 @@
#include "utfcpp/source/utf8.h"
#include "utils/utils.h" #include "utils/utils.h"
int display_width(const char *str, size_t len) { int display_width(const char *str, size_t len) {
@@ -99,42 +98,48 @@ uint32_t count_clusters(const char *line, size_t len, size_t from, size_t to) {
return count; return count;
} }
size_t utf8_offset_to_utf16(const char *utf8, size_t utf8_len, size_t utf8_offset_to_utf16(const char *s, size_t utf8_len, size_t byte_pos) {
size_t byte_offset) { if (byte_pos > utf8_len)
if (byte_offset > utf8_len) return 0;
return byte_offset; size_t utf16_units = 0;
const char *start = utf8; size_t i = 0;
const char *mid = utf8 + byte_offset; while (i < byte_pos) {
if (!utf8::is_valid(start, mid)) unsigned char c = s[i];
assert(0 && "invalid utf8"); if ((c & 0x80) == 0x00) {
size_t utf16_offset = 0; i += 1;
for (auto it = start; it < mid;) { utf16_units += 1;
uint32_t codepoint = utf8::next(it, mid); } else if ((c & 0xE0) == 0xC0) {
if (codepoint <= 0xFFFF) i += 2;
utf16_offset += 1; utf16_units += 1;
else } else if ((c & 0xF0) == 0xE0) {
utf16_offset += 2; i += 3;
utf16_units += 1;
} else {
i += 4;
utf16_units += 2;
} }
return utf16_offset; }
return utf16_units;
} }
size_t utf16_offset_to_utf8(const char *utf8, size_t utf8_len, size_t utf16_offset_to_utf8(const char *s, size_t utf8_len, size_t utf16_pos) {
size_t utf16_offset) { size_t utf16_units = 0;
const char *start = utf8; size_t i = 0;
const char *end = utf8 + utf8_len; while (utf16_units < utf16_pos && i < utf8_len) {
const char *it = start; unsigned char c = s[i];
size_t utf16_count = 0; if ((c & 0x80) == 0x00) {
while (it < end) { i += 1;
if (utf16_count >= utf16_offset) utf16_units += 1;
break; } else if ((c & 0xE0) == 0xC0) {
const char *prev = it; i += 2;
uint32_t codepoint = utf8::next(it, end); utf16_units += 1;
if (codepoint <= 0xFFFF) } else if ((c & 0xF0) == 0xE0) {
utf16_count += 1; i += 3;
else utf16_units += 1;
utf16_count += 2; } else {
if (utf16_count > utf16_offset) i += 4;
return prev - start; utf16_units += 2;
} }
return it - start; }
return i;
} }