Compare commits

..

20 Commits

Author SHA1 Message Date
syedm 8c437d2639 Make it work with flake.nix 2026-07-08 14:52:12 +01:00
syedm 10287e1750 Fix file permissions 2026-07-01 18:53:49 +01:00
syedm 013bffcad9 Cleanup 2026-04-13 19:45:58 +01:00
syedm 037f884050 Move folder 2026-04-13 10:32:46 +01:00
syedm c683754d49 Cleanup / optimizations 2026-02-12 01:01:52 +00:00
syedm e9d164d769 Rewrite diagnostics popup with new api 2026-02-11 19:51:45 +00:00
syedm 5b66f503e4 Improve highlighting structure
- switched to a sparse delta based map
- true lazy-loading to avoid any unneccessary allocations
- fixed windows management api
2026-02-11 18:18:28 +00:00
syedm d79ea4e75a Fix parser bug on newlines 2026-02-05 14:23:52 +00:00
syedm dd474cc38d Fix deadlock 2026-02-05 13:03:41 +00:00
syedm a62d4a18a8 Switch to OOP style code 2026-02-04 00:38:11 +00:00
syedm e3fc5323df Cleanup 2026-02-02 10:45:22 +00:00
syedm 15cef855d6 Update installer 2026-02-01 20:49:38 +00:00
syedm 59fe554259 Fix bar dead code 2026-02-01 20:47:41 +00:00
syedm 8b93b955e8 Fix parsing bugs and add better indentation support 2026-02-01 20:40:52 +00:00
syedm f77caf604f Post release cleanup 2026-02-01 17:06:27 +00:00
syedm 8b49ab6085 Update mruby api. 2026-02-01 17:01:57 +00:00
syedm 154e557339 Fix memory leaks 2026-01-31 23:23:08 +00:00
syedm 04cce4224e Embed mruby and better clipboard support 2026-01-31 17:19:08 +00:00
syedm 410222b82a Fix minor bugs 2026-01-31 10:54:03 +00:00
syedm f93afc0d14 Make binary portable and other fixes 2026-01-31 10:25:39 +00:00
83 changed files with 5001 additions and 3663 deletions
+1
View File
@@ -2,6 +2,7 @@ CompileFlags:
Add: [
-I/home/syed/main/crib/include,
-I/home/syed/main/crib/libs,
-I/home/syed/main/crib/libs/mruby/include,
-std=c++23
]
Remove: []
+4
View File
@@ -17,4 +17,8 @@ bin
Gemfile*
.ruby-lsp/
include/scripting/ruby_compiled.h
__old__
.nix-bin/
+11 -3
View File
@@ -1,4 +1,12 @@
[submodule "libs/libgrapheme"]
path = libs/libgrapheme
url = git://git.suckless.org/libgrapheme
ignore = dirty
path = libs/libgrapheme
url = git://git.suckless.org/libgrapheme
ignore = dirty
[submodule "libs/mruby"]
path = libs/mruby
url = https://github.com/mruby/mruby.git
ignore = dirty
[submodule "libs/json"]
path = libs/json
url = https://github.com/nlohmann/json
ignore = dirty
+29 -19
View File
@@ -12,27 +12,35 @@ PCH_RELEASE := $(OBJ_DIR)/release/pch.h.gch
GENERATED_HEADER := $(INCLUDE_DIR)/scripting/ruby_compiled.h
CCACHE := ccache
CXX := $(CCACHE) clang++
CC := $(CCACHE) clang
CXX ?= x86_64-unknown-linux-musl-g++
CC ?= x86_64-unknown-linux-musl-gcc
CXX := $(CCACHE) $(CXX)
CC := $(CCACHE) $(CC)
CFLAGS_DEBUG :=\
-std=c++20 -Wall -Wextra \
-O0 -fno-inline -gsplit-dwarf\
-g -fno-omit-frame-pointer\
-Wno-unused-command-line-argument \
-I./include -I./libs
-std=c++20 -Wall -Wextra -static \
-O0 -fno-inline -gsplit-dwarf \
-g -fno-omit-frame-pointer \
-I./include -I./libs -I./libs/mruby/include -I./libs/json/include -I./libs/mruby/build/host/include
# C_SANITIZER := -fsanitize=address
CFLAGS_RELEASE :=\
-static \
-std=c++20 -O3 -march=native \
-fno-rtti -fstrict-aliasing \
-std=c++20 -O3 -march=x86-64 -mtune=generic -fno-rtti \
-ffast-math -flto=thin \
-fvisibility=hidden \
-fomit-frame-pointer -DNDEBUG -s \
-mllvm -vectorize-loops \
-fno-unwind-tables -fno-asynchronous-unwind-tables\
-Wno-unused-command-line-argument \
-I./include -I./libs
-I./include -I./libs -I./libs/mruby/include -I./libs/json/include -I./libs/mruby/build/host/include
PCRE_CFLAGS := $(shell pkg-config --cflags libpcre2-8)
PCRE_LIBS := $(shell pkg-config --static --libs libpcre2-8)
CFLAGS_DEBUG += $(PCRE_CFLAGS)
CFLAGS_RELEASE += $(PCRE_CFLAGS)
PCH_CFLAGS_DEBUG := $(CFLAGS_DEBUG) -x c++-header
PCH_CFLAGS_RELEASE := $(CFLAGS_RELEASE) -x c++-header
@@ -42,13 +50,15 @@ 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_RELEASE := $(patsubst libs/unicode_width/%.c,$(OBJ_DIR)/release/unicode_width/%.o,$(UNICODE_SRC))
LIBS_RELEASE := \
libs/libgrapheme/libgrapheme.a \
-Wl,-Bstatic,--gc-sections -lpcre2-8 -lmruby
LIBS_DEBUG := \
libs/libgrapheme/libgrapheme.a \
-Wl,-Bdynamic -lpcre2-8 -lmruby
./libs/mruby/build/host/lib/libmruby.a \
$(PCRE_LIBS)
LIBS_RELEASE := \
libs/libgrapheme/libgrapheme.a \
./libs/mruby/build/host/lib/libmruby.a \
$(PCRE_LIBS)
SRC := $(wildcard $(SRC_DIR)/**/*.cc) $(wildcard $(SRC_DIR)/*.cc)
OBJ_DEBUG := $(patsubst $(SRC_DIR)/%.cc,$(OBJ_DIR)/debug/%.o,$(SRC))
@@ -65,7 +75,7 @@ test: $(TARGET_DEBUG)
release: $(TARGET_RELEASE)
$(GENERATED_HEADER): $(INCLUDE_DIR)/syntax/tokens.def $(INCLUDE_DIR)/scripting/libcrib.rb src/ruby_compile.sh
$(GENERATED_HEADER): $(INCLUDE_DIR)/syntax/tokens.def $(INCLUDE_DIR)/ruby/libcrib.rb src/ruby_compile.sh
src/ruby_compile.sh
$(PCH_DEBUG): $(INCLUDE_DIR)/pch.h
@@ -78,7 +88,7 @@ $(PCH_RELEASE): $(INCLUDE_DIR)/pch.h
$(TARGET_DEBUG): $(PCH_DEBUG) $(OBJ_DEBUG) $(UNICODE_OBJ_DEBUG)
mkdir -p $(BIN_DIR)
$(CXX) $(CFLAGS_DEBUG) -o $@ $(OBJ_DEBUG) $(UNICODE_OBJ_DEBUG) $(LIBS_DEBUG)
$(CXX) $(CFLAGS_DEBUG) $(C_SANITIZER) -o $@ $(OBJ_DEBUG) $(UNICODE_OBJ_DEBUG) $(LIBS_DEBUG)
$(TARGET_RELEASE): $(PCH_RELEASE) $(OBJ_RELEASE) $(UNICODE_OBJ_RELEASE)
mkdir -p $(BIN_DIR)
+27 -11
View File
@@ -20,9 +20,8 @@ Binary can be installed with the following command:
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>
*Tested with arch linux, ubuntu and void*<br>
## Building
@@ -52,12 +51,6 @@ Make sure you have the following dependencies installed (apart from the standard
#include <pcre2.h>
```
* **[mruby](https://github.com/mruby/mruby)**
Install it via your package manager. Once installed, the header should be available as:
```cpp
#include <mruby.h>
```
It also uses `xclip` at runtime for copying/pasting *(TODO: make it os portable)*.
And any modern terminal should work fine - preferably `kitty` or `wezterm`.<br>
@@ -66,10 +59,32 @@ And any modern terminal should work fine - preferably `kitty` or `wezterm`.<br>
Some other dependancies are added as submodules or copied.<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>
- `mruby` needs to be compiled using `rake` in it's folder (needs ruby).<br>
- Need to add the following lines to the `build_config/default.rb` file (in the `MRuby::Build.new` block)
```ruby
conf.gem :mgem => 'pure-regexp'
conf.gem :mgem => 'env'
conf.gem :mgem => 'process'
conf.gem :mgem => 'marshal-c'
```
#### config file
The config file is a ruby file placed in one of these places (in order, first one found will be used):
- `$CRIB_CONFIG`
- `$CRIB_CONFIG_DIR/crib.rb`
- `$CRIB_CONFIG_DIR/main.rb`
- `./crib.rb`
- `$XDG_CONFIG_HOME/crib/crib.rb`
- `$XDG_CONFIG_HOME/crib/main.rb`
- `$XDG_CONFIG_HOME/crib.rb`
- `$HOME/.config/crib/crib.rb`
- `$HOME/.config/crib/main.rb`
- `$HOME/.config/crib.rb`
#### LSPs
Lsp's are defined in the `libcrib.rb` file and you can use your `config/main.rb` file to add more.<br>
Lsp's are defined in the `libcrib.rb` file and you can use your config file to add more.<br>
The following lsp's are added by default and can be installed anywhere in your `$PATH`<br>
@@ -99,7 +114,7 @@ The following lsp's are added by default and can be installed anywhere in your `
#### Compiler
`clang++` should work fine but `c++23+` is required.<br>
`g++` or `clang++` should work fine but `c++20+` is required.<br>
Can remove `ccache` if you want from the makefile.<br>
#### Compliling
@@ -119,10 +134,11 @@ crib ./filename.ext
```
*If `filename.ext` does not exist, it will be created*<br>
*memory usage is average case 10MB + 2x size of file*<br>
## Keybindings
TODO: add keybind information on how to set in `config/main.rb`
TODO: add keybind information on how to set in config file
and default / unchangeable keybinds
## Features Implemented
+191 -78
View File
@@ -2,122 +2,235 @@ Copyright 2025 Syed Daanish
# TODO
##### BTW Check each lsp with each of the features implemented
- Fix bug where scroll up at top of screen first line jumps to bottom
- Make completions work with new system
- And factorize renderer into its own class
- which is just managed by the renderer
- and adjusment.cc will call it
- which is reused by scrollers/ensurers too (for knowing screen wrapped end)
- this will then allow inlay hints to be possible
- and also make VAI easier to implement (probably as inlay hints)
- and also allow code lens to work too
- and an api to allow line skipping / virtual text which allows for folding logic as extention
- Also time extentions and disable if they take too long / for larger files with options to force
* Allow keybinds to be set in ruby
* ruby file for project specific runs alongside any system wide ones
- Seperate system functions into a class that branches to support local / ssh / server modes.
- Even lsp shouldnt be directly controlled because it can branch on local and server modes
- check libssh2 or child process stuff for remote editing (remote mode)
- Thick and thin mode (server mode) (through ssh or port) (for website only port + webhook)
- thin mode only shares screen diffing over the network - uses server settings / themes / shell
- only one user connects at a time
- provides data as a websocket with tui or gui/online modes where tui shares diffing as is (can be connected to by gui or website)
- and gui/online modes try to (if not then render onto a canvas) forward window.render_gui() and dedicated windowing system (i.e windowing is html divs)
- and window.render_gui() returns a markup code (custom markup)
- and for events i could either leave tui as-is and for markup have special event handling or i
- implement the widget system in both and have the same event handling then
- actually for true cross platform i need to make a ui lib with widgets etc. so it is workable on all platforms (so they all need only a single ui lib)
- thick only shared fileio and lsp data with local used for all else - uses local settings / themes
- multiple users connect at once but maybe either make them not be allowed to open same file or make vscode like multiediting (unsure how exactly)
- they all share same lsp instances
- they all have the same shell access
- allow having an instance that forwards thick mode to thin mode (to connect online mode to a thick server for code collaboration)
* Then allow ruby code to create and handle windows as extentions
* Then 3 inbuilt extentions being file manager, theme picker, tab selector
* make another tile type called tile tabbed that has a tab switcher and shows only one of its children at once
* it takes focus and takes some keybinds for switching and forwards the rest (it also forwards the info and adds one for itself - the selected/total tabs)
* also implement info strings for all the stuff that take focus
* Mode is a feild on a editor and there is no global "mode system" except in editors (enxtentions do their own thing)
- make mode normal and not atomic if it is truly unused across threads
- this means keybinds can be set to use the editor as insert mode only and so behave like vscode
* split lsp stuff into multiple files (not a monolithic class as it is now)
* Extentions can also be used as file openers (for like databases . diffing . images . audio etc)
* Local cache for state management (like undo history, cursor positions etc) (location can be set in config)
* make sure to write inbuilt extentions in cpp and not ruby
* also move default bar and clipboard back into cpp
* all lsp popups are no longer their own classes but instead windows (extention like) in popup mode
* also **fix click handling to send mouse unclick to the same focus window as the click And also for drag to be same as the starter**
* skip opening binary files
* apply themeing in bg log bar lsp popus etc. to keep visual consistency
* searching/replace/Multi-Cursor (for just one lsp command for all) with pcre2 with regex (started by a slash) (disabled for large files)
* add links support in xterm (kitty like clickable links)
* And preprocess markdown in popups to be more like styled than just highlighted
* In the ruby libcrib populate toplevel binding and file and dir and rubybuild stuff and other similar constants
* in require_relative allow requiring without appending .rb if possible.
* Possibly in the future limit memory usage by parser for larger files
* Add a file picker suggestion while typing a path (including stuff like ~ and .. and $HOME etc)
* allow opening directory after filemanger is sorted out.
* commands to:
change pwd
load a rb file
run a ruby command
close a window etc.
* [ ] Add mgems for most common things and a ruby library to allow combining true ruby with mruby
* add command to set and use a file type at runtime
* [ ] color alpha in ini files
* [ ] Make warning before ctrl+q for saving
* [ ] **LSP Bug:** Check why `fish-lsp` is behaving so off with completions filtering.
* [ ] **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.
* [ ] **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.
* [ ] 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.
* [ ] Add block indentation support.
* [ ] Ignore comments/strings from parser when auto-indenting.
* [ ] These will dedent when the block immediately after them is dedented
* [ ] Dont dedent if ending is valid starting is invalid but also empty
* [ ] Just leave asis if starting is empty
* [ ] **Readme:** Update readme to show ruby based config.
- [ ] Ignore comments/strings from parser when auto-indenting.
- [ ] Support for stuff like bash \ and math operators in other languages and comma and line starting with a dot (like in ruby)
etc.
* [ ] **Readme:** Update readme to show ruby based config in detail.
* [ ] **UI Refinement:**
* [ ] 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.
* [ ] Redo hooks as a struct.
* [ ] breakdown the render function into smaller functions.
* Cap line_tree data limit for large files and just store about a thousand previous lines maybe? (lazily loaded)
* Try to make all functions better now that folds have been purged
* Cleanup syntax and renderer files
* add `:j<n>` command to jump to line \<n> in the current file
* and give warning for invalid commands
* and upon escape clear the current command
* allow multiline logging which captures the input entirely and y will copy the log and anything else will exit
* it will then collapse to being the first line from the log only
* 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
* [ ] **LSP:**
support snippets in completion properly
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
* Allow ruby to config lsp capabilities
move lsp configs to json and also allow configs for windows-style vs unix-style line endings and utf-8 vs utf-16
* also try to fix why solargraph is the only one breaking on edits near emojis
* ruby-lsp also supports erb so thats a plus
* the ruby should have an api to be able to draw windows and add mappings to them
* **Syntax highlighting**
* ruby done!!
* finish bash then do all the directive-like ones like jsonc (first to help with theme files) / toml / yaml / ini / nginx
* then [ch](++)? then gdscript and python then erb then php
* then markdown / html
* then gitignore / gitattributes
* then fish then sql then css and [jt]sx? then python then lua (make with type annotations for lsp results)
* then [ch](++)? then gdscript then erb then php
* then fish then sql then css and [jt]sx? then lua (make with type annotations for lsp results)
* then haskell then gomod then go then rust
* [ ] **Undo/Redo:** Add support for undo/redo history.
* [ ] **Auto brace selection:** Add support for auto brace selection.
* [ ] **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).
* *Implementation:* Update `main.cc` to send drag events to the selected editor even if coordinates are out of bounds.
### UX
* [ ] **Editor word highlighter:** Do not recompute word under cursor if not changed.
- [ ] **Completion Filtering:**
- [ ] Stop filtering case-sensitive.
- [ ] Normalize completion edits if local filtering is used.
* [ ] **Completion Filtering:**
* [ ] Stop filtering case-sensitive.
* [ ] Normalize completion edits if local filtering is used.
- [ ] **Basic Autocomplete:** Keep a list of words in the current buffer for non-LSP fallback.
* [ ] **LSP Features:**
* [ ] Add LSP jumping support (Go to Definition, Hover).
* [ ] Add LSP rename support.
* [ ] Handle snippets properly in autocomplete: use only the last word in signature when replacing and set cursor to the first one.
### Features
* [ ] **Basic Autocomplete:** Keep a list of words in the current buffer for non-LSP fallback.
- [ ] **Search & Replace:**
- [ ] Add Search/Replace UI.
- [ ] Support capture groups (`$1`, `$2`) or allow Perl regex directly.
- [ ] Ensure virtual cursors are included in search positions.
### Major Features
* [ ] **Search & Replace:**
* [ ] Add Search/Replace UI.
* [ ] Support capture groups (`$1`, `$2`) or allow Perl regex directly.
* [ ] Ensure virtual cursors are included in search positions.
* [ ] **Multi-Cursor:**
* [ ] Add virtual cursor support (edits apply to all locations).
* [ ] Add `Alt+Click` to set multiple cursors.
* [ ] Allow search and place cursor at all matches.
* [ ] **Block Selection:**
* [ ] Double-clicking a bracket selects the whole block (first time only) and sets mode to `WORD`.
- [ ] **Multi-Cursor:**
- [ ] Add virtual cursor support (edits apply to all locations).
- [ ] Add `Alt+Click` to set multiple cursors.
- [ ] Allow search and place cursor at all matches.
- [ ] **Block Selection:**
- [ ] Double-clicking a bracket selects the whole block and sets mode to `WORD`.
### Visuals, UI & Extensions?
* [ ] **Status Bar:** Complete status bar and command runner.
- [ ] Add color picker/palette (as a floating extention).
* [ ] Add color picker/palette.
- [ ] **Git:** Add Git integration (status, diffs).
- [ ] **AI/Snippets:**
- [ ] Add snippets support (LuaSnip/VSnip style).
- [ ] Add Codeium/Copilot support (using VAI virtual text) as a test phase.
* [ ] **Git:** Add Git integration (status, diffs).
* [ ] **AI/Snippets:**
* [ ] Add snippets support (LuaSnip/VSnip style).
* [ ] Add Codeium/Copilot support (using VAI virtual text) as a test phase.
- [ ] **SQL:** Add SQL support (Viewer and Basic Editor) (as ruby extension).
- [ ] **Prolly?:** Add Splash Screen / Minigame.
* [ ] **SQL:** Add SQL support (Viewer and Basic Editor).
* [ ] **Prolly?:** Add Splash Screen / Minigame.
### Unimportant optimizations
- [ ] **Performance:**
- [ ] Switch JSON parser to `RapidJSON` (or similar high-performance lib).
- [ ] Decrease usage of `std::string` in UI, LSP, warnings etc.
- [ ] Also for vectors into managed memory especially for completions/lsp-stuff.
### Optimizations & Fluff
<!-- The pits of hell: -->
<!-- * Replace perfectly working superfast rope with a structure that stores for small files everything -->
<!-- - but for large ones it stores only what the user viewed / edited (by line number) -->
<!-- - the rest is from the disk and not entirely loaded into memory (keep as option maybe they want everything in memory?) -->
<!-- - also for the line mode still go through entire file to get and store line offsets -->
<!-- - also it stores everything prolly still as rope tho (rope of lines) (or sparse map) -->
<!-- - it stores the line text as-is which is only unicode / crlf normalized during usage -->
* [ ] **Performance:**
* [ ] Switch JSON parser to `RapidJSON` (or similar high-performance lib).
* [ ] Decrease usage of `std::string` in UI, LSP, and warnings.
* [ ] Also for vectors into managed memory especially for completions/lsp-stuff.
whyy is visible returnint x1,y2 and x2, 2y2 instead of x1,y1 and x2,y2
Render H: 1, Cursor: 0,0, Visible: 0,26 - 0,52
Render H: 2, Cursor: 0,0, Visible: 1,0 - 1,0
Render H: 3, Cursor: 0,0, Visible: 2,30 - 2,60
Render H: 4, Cursor: 0,0, Visible: 3,36 - 3,72
Render H: 5, Cursor: 0,0, Visible: 4,32 - 4,64
Render H: 6, Cursor: 0,0, Visible: 5,40 - 5,80
Render H: 7, Cursor: 0,0, Visible: 6,11 - 6,22
Render H: 8, Cursor: 0,0, Visible: 7,3 - 7,6
Render H: 9, Cursor: 0,0, Visible: 8,19 - 8,38
Render H: 10, Cursor: 0,0, Visible: 9,76 - 9,152
Render H: 11, Cursor: 0,0, Visible: 10,50 - 10,100
Render H: 12, Cursor: 0,0, Visible: 11,29 - 11,58
Render H: 13, Cursor: 0,0, Visible: 12,49 - 12,98
Render H: 14, Cursor: 0,0, Visible: 13,32 - 13,64
Render H: 15, Cursor: 0,0, Visible: 14,30 - 14,60
Render H: 16, Cursor: 0,0, Visible: 15,56 - 15,112
Render H: 17, Cursor: 0,0, Visible: 16,42 - 16,84
Render H: 18, Cursor: 0,0, Visible: 17,20 - 17,40
Render H: 19, Cursor: 0,0, Visible: 18,31 - 18,62
Render H: 20, Cursor: 0,0, Visible: 19,77 - 19,154
Render H: 21, Cursor: 0,0, Visible: 20,77 - 20,154
Render H: 22, Cursor: 0,0, Visible: 21,44 - 21,88
Render H: 23, Cursor: 0,0, Visible: 22,56 - 22,112
Render H: 24, Cursor: 0,0, Visible: 23,13 - 23,26
Render H: 25, Cursor: 0,0, Visible: 24,3 - 24,6
Render H: 26, Cursor: 0,0, Visible: 25,24 - 25,48
Render H: 27, Cursor: 0,0, Visible: 26,32 - 26,64
Render H: 28, Cursor: 0,0, Visible: 27,38 - 27,76
Render H: 29, Cursor: 0,0, Visible: 28,1 - 28,2
Render H: 30, Cursor: 0,0, Visible: 29,0 - 29,0
Render H: 31, Cursor: 0,0, Visible: 30,30 - 30,60
Render H: 32, Cursor: 0,0, Visible: 31,19 - 31,38
Render H: 33, Cursor: 0,0, Visible: 32,76 - 32,152
Render H: 34, Cursor: 0,0, Visible: 33,50 - 33,100
Render H: 35, Cursor: 0,0, Visible: 34,36 - 34,72
Render H: 36, Cursor: 0,0, Visible: 35,66 - 35,132
Render H: 37, Cursor: 0,0, Visible: 36,12 - 36,24
Render H: 38, Cursor: 0,0, Visible: 37,13 - 37,26
Render H: 39, Cursor: 0,0, Visible: 38,17 - 38,34
Render H: 40, Cursor: 0,0, Visible: 39,37 - 39,74
Render H: 41, Cursor: 0,0, Visible: 40,16 - 40,32
Render H: 42, Cursor: 0,0, Visible: 41,23 - 41,46
Render H: 43, Cursor: 0,0, Visible: 42,15 - 42,30
Render H: 44, Cursor: 0,0, Visible: 43,13 - 43,26
Render H: 45, Cursor: 0,0, Visible: 44,5 - 44,10
Render H: 46, Cursor: 0,0, Visible: 45,41 - 45,82
Render H: 47, Cursor: 0,0, Visible: 46,12 - 46,24
Render H: 48, Cursor: 0,0, Visible: 47,22 - 47,44
Render H: 49, Cursor: 0,0, Visible: 48,24 - 48,48
Render H: 50, Cursor: 0,0, Visible: 49,28 - 49,56
Render H: 51, Cursor: 0,0, Visible: 50,26 - 50,52
Render H: 52, Cursor: 0,0, Visible: 51,20 - 51,40
Render H: 53, Cursor: 0,0, Visible: 52,74 - 52,148
+8 -38
View File
@@ -1,3 +1,10 @@
# Files can be insluded using Kernel#require_relative
# but it can be called with binding as the second argument
# skipping it will call it with global binding which is usually fine
# Kernel#load can also be used
require_relative "theme"
# basic configuration
# This can also be used to do speacail configs for different projects.
# its ruby guys script whatever you want.
@@ -12,43 +19,6 @@ C.shutdown do
puts "Exiting crib..."
end
# this can be modified by the user during runtime through keybindings
# But i need to know how to ever read this value only when needed.
# maybe i can write a function that notifies if theme maybe changed then reload
# It can also be scripted to load different theme formats into a hash usable by crib
C.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 },
# rubocop:disable Lint/BooleanSymbol
:true => { fg: 0x7AE93C },
:false => { fg: 0xEF5168 },
# rubocop:enable Lint/BooleanSymbol
: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 }
}
# 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
# only use a preset set of stuff to bind while teh windows are purely custom
@@ -99,7 +69,7 @@ C.extra_highlights do |_line, _idx|
end
# The highlighter will be aplied to the language as long as the langauge is defined in C.languages
C.highlighters[:ruby_n] = {
C.highlighters[:string] = {
parser: ->(line, state, line_idx) {
# the return value is a hash
# it contains the state and the highlights
+36
View File
@@ -0,0 +1,36 @@
# this can be modified by the user during runtime through keybindings
# But i need to know how to ever read this value only when needed.
# maybe i can write a function that notifies if theme maybe changed then reload
# It can also be scripted to load different theme formats into a hash usable by crib
C.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 },
# rubocop:disable Lint/BooleanSymbol
:true => { fg: 0x7AE93C },
:false => { fg: 0xEF5168 },
# rubocop:enable Lint/BooleanSymbol
: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 }
}
Generated
+27
View File
@@ -0,0 +1,27 @@
{
"nodes": {
"nixpkgs": {
"locked": {
"lastModified": 1783224372,
"narHash": "sha256-8i/87eeoqiGE4yOTjwSA3Eh/ziJRQEmd/unYU+K27sk=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "d407951447dcd00442e97087bf374aad70c04cea",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixos-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"root": {
"inputs": {
"nixpkgs": "nixpkgs"
}
}
},
"root": "root",
"version": 7
}
+45
View File
@@ -0,0 +1,45 @@
{
description = "crib development environment";
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
};
outputs = { self, nixpkgs }:
let
system = "x86_64-linux";
pkgs = import nixpkgs {
inherit system;
};
static = pkgs.pkgsStatic;
in {
devShells.${system}.default = static.mkShell {
packages = [
pkgs.ccache
pkgs.gnumake
pkgs.bear
pkgs.ruby
pkgs.pkg-config
pkgs.xxd
pkgs.gdb
pkgs.binutils
static.pcre2
];
shellHook = ''
export PKG_CONFIG_PATH="${static.pcre2.dev}/lib/pkgconfig:$PKG_CONFIG_PATH"
echo "crib static musl dev shell"
export CC=x86_64-unknown-linux-musl-gcc
export CXX=x86_64-unknown-linux-musl-g++
export AR=x86_64-unknown-linux-musl-ar
'';
};
};
}
-45
View File
@@ -1,45 +0,0 @@
#ifndef EDITOR_COMPLETIONS_H
#define EDITOR_COMPLETIONS_H
#include "pch.h"
#include "ui/completionbox.h"
#include "ui/hover.h"
#include "utils/utils.h"
struct CompletionItem {
std::string label;
uint8_t kind;
std::optional<std::string> detail;
std::optional<std::string> documentation;
bool is_markup = false;
bool deprecated = false;
bool asis = true;
std::string sort;
std::string filter;
bool snippet = false;
std::vector<TextEdit> edits;
json original;
std::vector<char> end_chars;
};
struct CompletionSession {
std::shared_mutex mtx;
bool active = false;
Coord hook;
std::optional<std::string> prefix;
uint8_t select = 0;
std::vector<CompletionItem> items;
std::vector<uint8_t> visible;
bool complete = true;
std::optional<char> trigger_char;
uint8_t trigger = 0;
CompletionBox box;
HoverBox hover;
uint32_t doc = UINT32_MAX;
std::atomic<bool> hover_dirty = false;
int version;
CompletionSession() : box(this) {}
};
#endif
+136 -132
View File
@@ -1,165 +1,169 @@
#ifndef EDITOR_H
#define EDITOR_H
#include "editor/completions.h"
#include "editor/decl.h"
#include "editor/hooks.h"
#include "editor/indents.h"
#include "editor/visual.h"
#include "extentions/diagnostics.h"
#include "extentions/hover.h"
#include "io/knot.h"
#include "io/sysio.h"
#include "syntax/extras.h"
#include "syntax/parser.h"
#include "ui/completionbox.h"
#include "ui/diagnostics.h"
#include "ui/hover.h"
#include "utils/utils.h"
#include <cstdint>
#include "windows/decl.h"
#define CHAR 0
#define WORD 1
#define LINE 2
#define EXTRA_META 4
#define EXTRA_META 2
#define INDENT_WIDTH 2
// autocomplete lua// Bracket closing / tab on enter
struct Editor {
std::string filename;
std::string uri;
Knot *root;
std::shared_mutex knot_mtx;
Coord cursor;
uint32_t cursor_preffered;
Coord selection;
bool selection_active;
bool unix_eol; // false for windows
int selection_type;
Coord position;
Coord size;
Coord scroll;
Language lang;
uint32_t hooks[94];
bool jumper_set;
std::shared_mutex v_mtx;
std::vector<VWarn> warnings;
bool warnings_dirty;
VAI ai;
struct Editor : Window {
std::string filename = "";
std::string uri = "";
Knot *root = nullptr;
Coord cursor = {0, 0};
uint32_t cursor_preffered = 0;
Coord selection = {0, 0};
bool selection_active = false;
bool unix_eol = true;
int selection_type = 0;
Coord size = {0, 0};
Coord scroll = {0, 0};
Language lang = {};
bool jumper_set = false;
std::vector<VWarn> warnings = {};
bool warnings_dirty = false;
VAI ai = {};
std::shared_mutex lsp_mtx;
std::shared_ptr<struct LSPInstance> lsp;
bool hover_active;
HoverBox hover;
bool diagnostics_active;
DiagnosticBox diagnostics;
std::atomic<struct LSPInstance *> lsp = nullptr;
HoverBox *hover_popup = init_hover();
DiagnosticBox *diagnostic_popup = init_diagnostic();
std::atomic<int> lsp_version = 1;
CompletionSession completion;
IndentationEngine indents;
Parser *parser;
ExtraHighlighter extra_hl;
bool is_css_color;
};
IndentationEngine indents = {};
HookEngine hooks = {};
Parser *parser = nullptr;
ExtraHighlighter extra_hl = {};
bool is_css_color = false;
Editor *new_editor(const char *filename_arg, Coord position, Coord size,
uint8_t eol);
void save_file(Editor *editor);
void free_editor(Editor *editor);
void render_editor(Editor *editor);
void cursor_up(Editor *editor, uint32_t number);
void cursor_down(Editor *editor, uint32_t number);
Coord move_left(Editor *editor, Coord cursor, uint32_t number);
Coord move_right(Editor *editor, Coord cursor, uint32_t number);
void cursor_left(Editor *editor, uint32_t number);
void cursor_right(Editor *editor, uint32_t number);
void scroll_up(Editor *editor, int32_t number);
void scroll_down(Editor *editor, uint32_t number);
void ensure_cursor(Editor *editor);
void ensure_scroll(Editor *editor);
void handle_editor_event(Editor *editor, KeyEvent event);
void edit_erase(Editor *editor, Coord pos, int64_t len);
void edit_insert(Editor *editor, Coord pos, char *data, uint32_t len);
void edit_replace(Editor *editor, Coord start, Coord end, const char *text,
uint32_t len);
Coord editor_hit_test(Editor *editor, uint32_t x, uint32_t y);
char *get_selection(Editor *editor, uint32_t *out_len, Coord *out_start);
void selection_bounds(Editor *editor, Coord *out_start, Coord *out_end);
void editor_worker(Editor *editor);
void move_line_down(Editor *editor);
void move_line_up(Editor *editor);
void word_boundaries(Editor *editor, Coord coord, uint32_t *prev_col,
uint32_t *next_col, uint32_t *prev_clusters,
uint32_t *next_clusters);
void word_boundaries_exclusive(Editor *editor, Coord coord, uint32_t *prev_col,
uint32_t *next_col);
void editor_lsp_handle(Editor *editor, json msg);
void apply_lsp_edits(Editor *editor, std::vector<TextEdit> edits, bool move);
void completion_resolve_doc(Editor *editor);
void complete_accept(Editor *editor);
void complete_next(Editor *editor);
void complete_prev(Editor *editor);
void complete_select(Editor *editor, uint8_t index);
void handle_completion(Editor *editor, KeyEvent event);
Editor(const char *filename_arg, uint8_t eol);
~Editor();
inline void apply_hook_insertion(Editor *editor, uint32_t line, uint32_t rows) {
for (auto &hook : editor->hooks)
if (hook > line)
hook += rows;
}
void render(std::vector<ScreenCell> &buffer, Coord size, Coord pos) override;
void handle_event(KeyEvent event) override;
void handle_click(KeyEvent event, Coord size) override;
void handle_command(std::string &command) override;
void work() override;
std::array<std::string, 5> bar_info() override { return {}; };
inline void apply_hook_deletion(Editor *editor, uint32_t removal_start,
uint32_t removal_end) {
for (auto &hook : editor->hooks)
if (hook > removal_start)
hook -= removal_end - removal_start + 1;
}
void save();
void cursor_up(uint32_t number);
void cursor_down(uint32_t number);
void cursor_left(uint32_t number);
void cursor_right(uint32_t number);
void move_line_down();
void move_line_up();
inline static void utf8_normalize_edit(Editor *editor, TextEdit *edit) {
std::shared_lock lock(editor->knot_mtx);
if (edit->start.row > editor->root->line_count) {
edit->start.row = editor->root->line_count;
edit->start.col = UINT32_MAX;
}
if (edit->end.row > editor->root->line_count) {
edit->end.row = editor->root->line_count;
edit->end.col = UINT32_MAX;
}
LineIterator *it = begin_l_iter(editor->root, edit->start.row);
if (!it)
return;
uint32_t len;
char *line = next_line(it, &len);
if (!line) {
void scroll_up(uint32_t number);
void scroll_down(uint32_t number);
void ensure_cursor();
void ensure_scroll();
void edit_erase(Coord pos, int64_t len);
void edit_insert(Coord pos, char *data, uint32_t len);
void edit_replace(Coord start, Coord end, const char *text, uint32_t len);
Coord click_coord(uint32_t x, uint32_t y);
char *get_selection(uint32_t *out_len, Coord *out_start);
void selection_bounds(Coord *out_start, Coord *out_end);
void insert_str(char *c, uint32_t len);
void insert_char(char c);
void normal_mode();
void backspace_edit();
void delete_prev_word();
void delete_next_word();
void cursor_prev_word();
void cursor_next_word();
void select_all();
void fetch_lsp_hover();
void indent_current_line();
void dedent_current_line();
void indent_selection();
void dedent_selection();
void paste();
void copy();
void cut();
void lsp_handle(json msg);
void apply_lsp_edits(std::vector<TextEdit> edits, bool move);
// Not used by core editor, but can be used by
// extentions (due to cursor movement complexity)
void format_full(int version);
Coord move_left(Coord cursor, uint32_t number);
Coord move_right(Coord cursor, uint32_t number);
void word_boundaries(Coord coord, uint32_t *prev_col, uint32_t *next_col,
uint32_t *prev_clusters, uint32_t *next_clusters);
void word_boundaries_exclusive(Coord coord, uint32_t *prev_col,
uint32_t *next_col);
void utf8_normalize_edit(TextEdit *edit) {
if (edit->start.row > this->root->line_count) {
edit->start.row = this->root->line_count;
edit->start.col = UINT32_MAX;
}
if (edit->end.row > this->root->line_count) {
edit->end.row = this->root->line_count;
edit->end.col = UINT32_MAX;
}
LineIterator *it = begin_l_iter(this->root, edit->start.row);
if (!it)
return;
uint32_t len;
char *line = next_line(it, &len);
if (!line) {
free(it->buffer);
free(it);
return;
}
if (edit->start.col < len)
edit->start.col = utf16_offset_to_utf8(line, len, edit->start.col);
else
edit->start.col = len;
if (edit->end.row == edit->start.row) {
if (edit->end.col < len)
edit->end.col = utf16_offset_to_utf8(line, len, edit->end.col);
else
edit->end.col = len;
free(it->buffer);
free(it);
return;
}
free(it->buffer);
free(it);
return;
}
if (edit->start.col < len)
edit->start.col = utf16_offset_to_utf8(line, len, edit->start.col);
else
edit->start.col = len;
if (edit->end.row == edit->start.row) {
it = begin_l_iter(this->root, edit->end.row);
if (!it)
return;
line = next_line(it, &len);
if (!line) {
free(it->buffer);
free(it);
return;
}
if (edit->end.col < len)
edit->end.col = utf16_offset_to_utf8(line, len, edit->end.col);
else
edit->end.col = len;
free(it->buffer);
free(it);
return;
}
free(it->buffer);
free(it);
it = begin_l_iter(editor->root, edit->end.row);
if (!it)
return;
line = next_line(it, &len);
if (!line) {
free(it->buffer);
free(it);
return;
}
if (edit->end.col < len)
edit->end.col = utf16_offset_to_utf8(line, len, edit->end.col);
else
edit->end.col = len;
free(it->buffer);
free(it);
}
};
#endif
-18
View File
@@ -3,22 +3,4 @@
#include "editor/editor.h"
void insert_str(Editor *editor, char *c, uint32_t len);
void insert_char(Editor *editor, char c);
void normal_mode(Editor *editor);
void backspace_edit(Editor *editor);
void delete_prev_word(Editor *editor);
void delete_next_word(Editor *editor);
void clear_hooks_at_line(Editor *editor, uint32_t line);
void cursor_prev_word(Editor *editor);
void cursor_next_word(Editor *editor);
void select_all(Editor *editor);
void fetch_lsp_hover(Editor *editor);
void handle_mouse(Editor *editor, KeyEvent event);
void indent_current_line(Editor *editor);
void dedent_current_line(Editor *editor);
void paste(Editor *editor);
void copy(Editor *editor);
void cut(Editor *editor);
#endif
+91
View File
@@ -0,0 +1,91 @@
#ifndef EDITOR_HOOKS_H
#define EDITOR_HOOKS_H
#include "utils/utils.h"
struct HookEngine {
uint32_t hooks[94];
std::vector<std::pair<uint32_t, char>> v;
std::vector<std::pair<uint32_t, char>>::iterator it;
HookEngine() {
for (int i = 0; i < 94; i++)
hooks[i] = UINT32_MAX;
v.reserve(94);
}
inline void edit(uint32_t line, uint32_t removed_rows,
uint32_t inserted_rows) {
int64_t delta = (int64_t)inserted_rows - (int64_t)removed_rows;
for (int i = 0; i < 94; i++) {
uint32_t &h = hooks[i];
if (h == UINT32_MAX)
continue;
if (h < line)
continue;
if (removed_rows > 0 && h < line + removed_rows) {
h = UINT32_MAX;
continue;
}
h = (uint32_t)((int64_t)h + delta);
}
}
inline void set(char c, uint32_t line) {
if (c < '!' || c > '~')
return;
int idx = c - '!';
for (int i = 0; i < 94; i++) {
if (hooks[i] == line) {
hooks[i] = UINT32_MAX;
break;
}
}
hooks[idx] = line;
}
inline bool get(char c, uint32_t *out_line) const {
if (c < '!' || c > '~')
return false;
uint32_t h = hooks[c - '!'];
if (h == UINT32_MAX)
return false;
*out_line = h;
return true;
}
inline void clear_line(uint32_t line) {
for (int i = 0; i < 94; i++)
if (hooks[i] == line)
hooks[i] = UINT32_MAX;
}
inline void clear(char c) {
if (c < '!' || c > '~')
return;
hooks[c - '!'] = UINT32_MAX;
}
void start_iter(uint32_t scroll_line) {
for (int i = 0; i < 94; i++)
if (hooks[i] != UINT32_MAX)
v.push_back({hooks[i], (char)('!' + i)});
std::sort(v.begin(), v.end(),
[](const auto &a, const auto &b) { return a.first < b.first; });
it = std::lower_bound(
v.begin(), v.end(), scroll_line,
[](const auto &p, uint32_t line) { return p.first < line; });
}
char next(uint32_t line_index) {
if (it != v.end() && it->first == line_index) {
char c = it->second;
it++;
return c;
}
return '\0';
}
};
#endif
+6
View File
@@ -112,12 +112,18 @@ struct IndentationEngine {
uint32_t set_indent(uint32_t row, int64_t indent_level);
uint32_t indent_line(uint32_t row);
uint32_t dedent_line(uint32_t row);
void indent_block(uint32_t start_row, uint32_t end_row, int delta);
void indent_block(uint32_t start, uint32_t end);
void dedent_block(uint32_t start, uint32_t end);
// fixes a autocomplete block's indentation
char *block_to_asis(Coord cursor, std::string source, uint32_t *out_len);
private:
const std::vector<std::string> *start_end = nullptr;
const std::vector<std::string> *start_start = nullptr;
const std::vector<std::string> *end_full = nullptr;
const std::vector<std::string> *end_start = nullptr;
// TODO: Ignore comments/strings too
// returns the indent level of the line itself or of the previous non-empty
uint32_t indent_expected(uint32_t row);
+113
View File
@@ -0,0 +1,113 @@
#include "editor/decl.h"
#include "io/knot.h"
#include "io/sysio.h"
#include "utils/utils.h"
struct GraphemeIterator {
char *line{nullptr};
uint32_t len{0};
GraphemeIterator(char *line, uint32_t len) : line(line), len(len) {}
char *next(uint32_t *o_len, uint32_t *o_width) {
if (!line || len == 0)
return nullptr;
char *cur = line;
uint32_t g = grapheme_next_character_break_utf8(cur, len);
if (o_width)
*o_width = display_width(cur, g);
if (o_len)
*o_len = g;
line += g;
len -= g;
return cur;
}
};
struct VisualIterator {
LineIterator *it{nullptr};
uint32_t line_index{UINT32_MAX};
uint32_t offset{0};
uint32_t len{0};
bool first{true};
char *line{nullptr};
uint32_t render_width{io::cols};
std::stack<std::pair<Coord, Coord>> prev_stack;
VisualIterator(Knot *root, Coord pos, uint32_t width)
: it(begin_l_iter(root, pos.row)), line_index(pos.row - 1),
offset(pos.col), render_width(width) {}
std::pair<Coord, Coord> prev() {
if (!it)
return {{UINT32_MAX, UINT32_MAX}, {UINT32_MAX, UINT32_MAX}};
if (prev_stack.empty())
return _prev();
auto ret = prev_stack.top();
offset = ret.first.col;
prev_stack.pop();
return ret;
}
std::pair<Coord, Coord> _prev() {
if (!it)
return {{UINT32_MAX, UINT32_MAX}, {UINT32_MAX, UINT32_MAX}};
line_index--;
line = prev_line(it, &len);
if (!line)
return {{UINT32_MAX, UINT32_MAX}, {UINT32_MAX, UINT32_MAX}};
if (len > 0 && line[len - 1] == '\n')
len--;
offset = first ? offset : 0;
first = false;
GraphemeIterator g(line + offset, len - offset);
uint32_t o_len, o_width, rendered = 0, advance = 0;
while (g.next(&o_len, &o_width)) {
if (rendered + o_width > render_width) {
prev_stack.push({{line_index, offset}, {line_index, offset + advance}});
offset += advance;
rendered = 0;
advance = 0;
}
advance += o_len;
rendered += o_width;
}
return {{line_index, offset}, {line_index, offset + advance}};
}
std::pair<Coord, Coord> next() {
if (!it)
return {{UINT32_MAX, UINT32_MAX}, {UINT32_MAX, UINT32_MAX}};
if (!line) {
line_index++;
line = next_line(it, &len);
if (!line)
return {{UINT32_MAX, UINT32_MAX}, {UINT32_MAX, UINT32_MAX}};
if (len > 0 && line[len - 1] == '\n')
len--;
offset = first ? offset : 0;
first = false;
}
GraphemeIterator g(line + offset, len - offset);
uint32_t o_len, o_width, rendered = 0, advance = 0;
while (g.next(&o_len, &o_width)) {
if (rendered + o_width > render_width) {
offset += advance;
return {{line_index, offset - advance}, {line_index, offset}};
}
advance += o_len;
rendered += o_width;
}
offset += advance;
if (offset >= len)
line = nullptr;
return {{line_index, offset}, {line_index, offset + advance}};
}
~VisualIterator() {
if (!it)
return;
free(it->buffer);
free(it);
}
};
+64
View File
@@ -0,0 +1,64 @@
#ifndef EXTENTION_COMPLETION_H
#define EXTENTION_COMPLETION_H
#include "editor/decl.h"
#include "io/sysio.h"
#include "pch.h"
#include "utils/utils.h"
#include "windows/decl.h"
struct CompletionItem {
std::string label;
uint8_t kind;
std::optional<std::string> detail;
std::optional<std::string> documentation;
bool is_markup = false;
bool deprecated = false;
bool asis = true;
std::string sort;
std::string filter;
bool snippet = false;
std::vector<TextEdit> edits;
json original;
std::vector<char> end_chars;
};
struct CompletionBox : Popup {
struct CompletionSession *session;
CompletionBox() { this->hidden = true; }
void render(std::vector<ScreenCell> &buffer, Coord size, Coord pos) override;
void handle_click(KeyEvent, Coord) override { this->hidden = true; }
~CompletionBox() {}
};
struct CompletionSession {
struct Editor *editor;
std::shared_mutex mtx;
bool active = false;
Coord hook;
uint32_t select = 0;
uint32_t scroll = 0;
std::vector<CompletionItem> items;
std::vector<uint32_t> visible;
bool complete = true;
std::optional<char> trigger_char;
uint8_t trigger = 0;
CompletionBox *box = nullptr;
uint32_t doc = UINT32_MAX;
std::atomic<bool> hover_dirty = false;
int version;
CompletionSession(Editor *editor) : editor(editor) {}
void resolve_doc();
void accept();
void next();
void prev();
void choose(uint8_t index);
void handle(KeyEvent event);
};
CompletionBox *init_completion_box(CompletionSession *session);
void completion_request(Editor *editor);
void completion_filter(Editor *editor);
#endif
+22
View File
@@ -0,0 +1,22 @@
#ifndef EXTENTION_DIAGNOSTICS_H
#define EXTENTION_DIAGNOSTICS_H
#include "editor/decl.h"
#include "io/sysio.h"
#include "pch.h"
#include "utils/utils.h"
#include "windows/decl.h"
struct DiagnosticBox : Popup {
std::vector<VWarn> warnings;
DiagnosticBox() { this->hidden = true; }
void clear() { this->warnings.clear(); }
void render(std::vector<ScreenCell> &buffer, Coord size, Coord pos) override;
void handle_click(KeyEvent, Coord) override { this->hidden = true; };
~DiagnosticBox() {};
};
DiagnosticBox *init_diagnostic();
#endif
+37
View File
@@ -0,0 +1,37 @@
#ifndef EXTENTION_HOVER_H
#define EXTENTION_HOVER_H
#include "io/sysio.h"
#include "pch.h"
#include "utils/utils.h"
#include "windows/decl.h"
struct HoverBox : Popup {
std::string text;
std::atomic<bool> is_markup;
uint32_t scroll_;
bool scroll_dirty;
HoverBox() : scroll_(0) { this->hidden = true; }
void clear() {
this->text = "";
this->hidden = true;
this->is_markup = false;
this->scroll_ = 0;
this->scroll_dirty = true;
}
void scroll(int32_t number);
void render(std::vector<ScreenCell> &buffer, Coord size, Coord pos) override;
void handle_click(KeyEvent ev, Coord) override {
if (ev.mouse_button == SCROLL_BTN && ev.mouse_state == SCROLL) {
this->scroll(ev.mouse_direction == SCROLL_UP ? -1 : 1);
return;
}
this->hidden = true;
};
~HoverBox() {};
};
HoverBox *init_hover();
#endif
+2 -2
View File
@@ -115,8 +115,8 @@ LineIterator *begin_l_iter(Knot *root, uint32_t start_line);
// Each subsequent call returns the next line as a null terminated string
// `it` is the iterator returned from begin_l_iter
// After getting the necessary lines free the iterator (no need to go upto
// the end) returns null if there are no more lines All return strings
// `must` be freed by the caller
// the end) returns null if there are no more lines
// The string must not be freed
char *next_line(LineIterator *it, uint32_t *out_len);
// Returns the previous line as a null terminated string
+9 -10
View File
@@ -96,20 +96,19 @@ inline bool is_empty_cell(const ScreenCell &c) {
return c.utf8.empty() || c.utf8 == " " || c.utf8 == "\x1b";
}
namespace io {
extern std::vector<ScreenCell> new_screen;
extern uint32_t rows, cols;
extern bool show_cursor;
extern std::vector<ScreenCell> old_screen;
extern termios orig_termios;
} // namespace io
Coord start_screen();
void end_screen();
void update(uint32_t row, uint32_t col, std::string utf8, uint32_t fg,
uint32_t bg, uint8_t flags);
void update(uint32_t row, uint32_t col, const char *utf8, uint32_t fg,
uint32_t bg, uint8_t flags);
void update(uint32_t row, uint32_t col, std::string utf8, uint32_t fg,
uint32_t bg, uint8_t flags, uint32_t ul_color);
void update(uint32_t row, uint32_t col, const char *utf8, uint32_t fg,
uint32_t bg, uint8_t flags, uint32_t ul_color);
void set_cursor(uint8_t row, uint8_t col, uint32_t type,
bool show_cursor_param);
void render();
Coord get_size();
void io_render();
KeyEvent read_key();
+416 -55
View File
@@ -2,54 +2,19 @@
#define LSP_H
#include "editor/editor.h"
#include "main.h"
#include "pch.h"
#include "utils/utils.h"
#include <cstdint>
#include <sys/types.h>
struct LSPPending {
std::string method;
Editor *editor = nullptr;
#define LSP_TIMEOUT_START 3000
#define LSP_TIMEOUT_QUIT_NORMAL 300
#define LSP_TIMEOUT_QUIT_FORCE 80
std::function<void(Editor *, std::string, json)> callback;
};
void lsp_worker();
struct LSPOpenRequest {
Language language;
Editor *editor;
};
struct LSPInstance {
std::shared_mutex mtx;
const LSP *lsp;
std::string root_dir;
int pid{-1};
int stdin_fd{-1};
int stdout_fd{-1};
std::atomic<bool> initialized = false;
std::atomic<bool> exited = false;
bool incremental_sync = false;
bool allow_hover = false;
bool allow_completion = false;
bool allow_resolve = false;
bool allow_formatting = false;
bool allow_formatting_on_type = false;
bool is_utf8 = false;
std::vector<char> format_chars;
std::vector<char> trigger_chars;
std::vector<char> end_chars;
uint32_t last_id = 0;
Queue<json> inbox;
Queue<json> outbox;
Queue<std::pair<Language, Editor *>> open_queue;
std::unordered_map<uint32_t, LSPPending *> pending;
std::vector<Editor *> editors;
};
extern std::shared_mutex active_lsps_mtx;
extern std::unordered_map<std::string, std::shared_ptr<LSPInstance>>
active_lsps;
extern Queue<LSPOpenRequest> lsp_open_queue;
static json client_capabilities = {
static const json client_capabilities = {
{"general", {{"positionEncodings", {"utf-16"}}}},
{"textDocument",
{{"publishDiagnostics", {{"relatedInformation", true}}},
@@ -73,19 +38,415 @@ static json client_capabilities = {
{"contextSupport", true},
{"insertTextMode", 1}}}}}};
void lsp_send(std::shared_ptr<LSPInstance> lsp, json message,
LSPPending *pending);
void lsp_worker();
struct LSPMessage {
Editor *editor = nullptr;
json message;
std::function<void(const LSPMessage &)> callback;
};
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 close_lsp(std::string lsp_id);
namespace lsp {
extern std::mutex lsp_mutex;
extern std::unordered_map<std::string, std::unique_ptr<LSPInstance>>
active_lsps;
extern Queue<std::string> need_opening;
extern std::unordered_set<std::string> opened;
extern std::vector<Editor *> new_editors;
extern Queue<std::unique_ptr<LSPMessage>> response_queue;
} // namespace lsp
void open_editor(std::shared_ptr<LSPInstance> lsp,
std::pair<Language, Editor *> entry);
void request_add_to_lsp(Language language, Editor *editor);
void add_to_lsp(Language language, Editor *editor);
void remove_from_lsp(Editor *editor);
void lsp_handle(std::shared_ptr<LSPInstance> lsp, json message);
struct LSPInstance {
const LSP *lsp_info;
std::string root_dir;
int pid{-1};
int stdin_fd{-1};
int stdout_fd{-1};
std::atomic<bool> initialized = false;
std::atomic<bool> exited = false;
bool incremental_sync = false;
bool allow_hover = false;
bool allow_completion = false;
bool allow_resolve = false;
bool allow_formatting = false;
bool allow_formatting_on_type = false;
bool is_utf8 = false;
std::vector<char> format_chars;
std::vector<char> trigger_chars;
std::vector<char> end_chars;
uint32_t last_id = 0;
Queue<json> inbox;
Queue<json> outbox;
std::unordered_map<uint32_t, std::unique_ptr<LSPMessage>> pending;
std::vector<Editor *> editors;
LSPInstance(std::string lsp_id) {
lsp_info = &lsps[lsp_id];
if (!init_process()) {
exited = true;
return;
}
json initialize_message = {
{"jsonrpc", "2.0"},
{"id", ++last_id},
{"method", "initialize"},
{"params",
{{"processId", getpid()},
{"rootUri", "file://" + percent_encode(path_abs("."))},
{"capabilities", client_capabilities}}}};
send_raw(initialize_message);
pollfd pfd{stdout_fd, POLLIN, 0};
uint32_t waited = 0;
while (waited < LSP_TIMEOUT_START) {
poll(&pfd, 1, 50);
if (pfd.revents & POLLIN)
break;
if (!running)
return;
waited += 50;
}
if (!(pfd.revents & POLLIN)) {
exited = true;
return;
}
json response = *read_lsp_message();
if (response.contains("result") &&
response["result"].contains("capabilities")) {
auto &caps = response["result"]["capabilities"];
// if (caps.contains("positionEncoding")) {
// std::string s = caps["positionEncoding"].get<std::string>();
// if (s == "utf-8")
// is_utf8 = true;
// log("Lsp name: %s, supports: %s", lsp->command.c_str(),
// s.c_str());
// }
if (caps.contains("textDocumentSync")) {
auto &sync = caps["textDocumentSync"];
if (sync.is_number()) {
int change_type = sync.get<int>();
incremental_sync = (change_type == 2);
} else if (sync.is_object() && sync.contains("change")) {
int change_type = sync["change"].get<int>();
incremental_sync = (change_type == 2);
}
}
allow_formatting = caps.value("documentFormattingProvider", false);
if (caps.contains("documentOnTypeFormattingProvider")) {
auto &fmt = caps["documentOnTypeFormattingProvider"];
if (fmt.is_object()) {
if (fmt.contains("firstTriggerCharacter")) {
std::string s = fmt["firstTriggerCharacter"].get<std::string>();
if (s.size() == 1)
format_chars.push_back(s[0]);
}
if (fmt.contains("moreTriggerCharacter")) {
for (auto &c : fmt["moreTriggerCharacter"]) {
std::string s = c.get<std::string>();
if (s.size() == 1)
format_chars.push_back(s[0]);
}
}
allow_formatting_on_type = true;
} else if (fmt.is_boolean()) {
allow_formatting_on_type = fmt.get<bool>();
}
}
if (caps.contains("hoverProvider")) {
auto &hover = caps["hoverProvider"];
allow_hover =
hover.is_boolean() ? hover.get<bool>() : hover.is_object();
} else {
allow_hover = false;
}
if (caps.contains("completionProvider")) {
allow_completion = true;
if (caps["completionProvider"].contains("resolveProvider"))
allow_resolve =
caps["completionProvider"]["resolveProvider"].get<bool>();
if (caps["completionProvider"].contains("triggerCharacters")) {
auto &chars = caps["completionProvider"]["triggerCharacters"];
if (chars.is_array()) {
for (auto &c : chars) {
std::string str = c.get<std::string>();
if (str.size() != 1)
continue;
trigger_chars.push_back(str[0]);
}
}
}
if (caps["completionProvider"].contains("allCommitCharacters")) {
auto &chars = caps["completionProvider"]["allCommitCharacters"];
if (chars.is_array()) {
for (auto &c : chars) {
std::string str = c.get<std::string>();
if (str.size() != 1)
continue;
end_chars.push_back(str[0]);
}
}
}
}
}
initialized = true;
json initialized_message = {{"jsonrpc", "2.0"},
{"method", "initialized"},
{"params", json::object()}};
send_raw(initialized_message);
}
~LSPInstance() {
uint32_t timeout =
running ? LSP_TIMEOUT_QUIT_NORMAL : LSP_TIMEOUT_QUIT_FORCE;
for (auto &ed : editors)
ed->lsp.store(nullptr);
initialized = false;
exited = true;
if (pid == -1)
return;
json shutdown = {
{"jsonrpc", "2.0"}, {"id", ++last_id}, {"method", "shutdown"}};
send_raw(shutdown);
pollfd pfd{stdout_fd, POLLIN, 0};
poll(&pfd, 1, timeout);
if (pfd.revents & POLLIN) {
json exit_msg = {{"jsonrpc", "2.0"}, {"method", "exit"}};
send_raw(exit_msg);
uint32_t waited = 0;
while (waited < timeout) {
int status;
pid_t res = waitpid(pid, &status, WNOHANG);
if (res == pid)
break;
std::this_thread::sleep_for(10ms);
waited += 10;
}
}
close(stdin_fd);
close(stdout_fd);
if (kill(pid, 0) == 0) {
kill(pid, SIGKILL);
waitpid(pid, nullptr, 0);
}
pid = -1;
}
bool init_process() {
int in_pipe[2];
int out_pipe[2];
if (pipe(in_pipe) == -1 || pipe(out_pipe) == -1) {
perror("pipe");
return false;
}
pid_t pid_tmp = fork();
if (pid_tmp == -1) {
perror("fork");
return false;
}
if (pid_tmp == 0) {
dup2(in_pipe[0], STDIN_FILENO);
dup2(out_pipe[1], STDOUT_FILENO);
int devnull = open("/dev/null", O_WRONLY);
if (devnull >= 0) {
dup2(devnull, STDERR_FILENO);
close(devnull);
}
close(in_pipe[0]);
close(in_pipe[1]);
close(out_pipe[0]);
close(out_pipe[1]);
std::vector<char *> argv;
argv.push_back(const_cast<char *>(lsp_info->command.c_str()));
for (auto &arg : lsp_info->args)
argv.push_back(const_cast<char *>(arg.c_str()));
argv.push_back(nullptr);
execvp(lsp_info->command.c_str(), argv.data());
perror("execvp");
_exit(127);
}
pid = pid_tmp;
stdin_fd = in_pipe[1];
stdout_fd = out_pipe[0];
close(in_pipe[0]);
close(out_pipe[1]);
return true;
}
void add(Editor *ed) {
editors.push_back(ed);
ed->lsp.store(this);
char *buf = read(ed->root, 0, ed->root->char_count);
std::string text(buf);
free(buf);
json message = {{"jsonrpc", "2.0"},
{"method", "textDocument/didOpen"},
{"params",
{{"textDocument",
{{"uri", ed->uri},
{"languageId", ed->lang.name},
{"version", 1},
{"text", text}}}}}};
send_raw(message);
}
void remove(Editor *ed) {
std::unique_lock lock(lsp::lsp_mutex);
editors.erase(std::remove(editors.begin(), editors.end(), ed),
editors.end());
lock.unlock();
auto message = std::make_unique<LSPMessage>();
message->message = {{"method", "textDocument/didClose"},
{"params", {{"textDocument", {{"uri", ed->uri}}}}}};
send(std::move(message));
}
void work() {
if (exited)
return;
int status;
pid_t res = waitpid(pid, &status, WNOHANG);
if (res == pid) {
exited = true;
pid = -1;
return;
}
while (!outbox.empty()) {
json message = outbox.front();
std::string m = message.value("method", "");
outbox.pop();
send_raw(message);
}
pollfd pfd{stdout_fd, POLLIN | POLLHUP | POLLERR, 0};
int r = poll(&pfd, 1, 0);
if (r > 0 && pfd.revents & (POLLHUP | POLLERR)) {
exited = true;
pid = -1;
return;
}
while ((r = poll(&pfd, 1, 0)) > 0) {
if (pfd.revents & (POLLHUP | POLLERR)) {
exited = true;
pid = -1;
return;
}
auto msg = read_lsp_message();
if (!msg)
break;
if (msg->contains("id")) {
uint32_t id = msg->at("id").get<uint32_t>();
auto it = pending.find(id);
if (it != pending.end()) {
if (it->second->editor) {
it->second->message = *msg;
lsp::response_queue.push(std::move(it->second));
} else {
auto message = *std::move(it->second);
message.message = *msg;
message.callback(message);
}
pending.erase(it);
}
} else if (msg->contains("method")) {
std::string uri;
if (msg->contains("params")) {
auto &p = (*msg)["params"];
if (p.contains("textDocument") && p["textDocument"].contains("uri"))
uri = p["textDocument"]["uri"].get<std::string>();
else if (p.contains("uri"))
uri = p["uri"].get<std::string>();
}
Editor *ed = resolve_uri(uri);
auto response = std::make_unique<LSPMessage>();
response->editor = ed;
response->message = *msg;
response->callback = editor_handle_wrapper;
if (ed)
lsp::response_queue.push(std::move(response));
else
lsp_handle(*msg);
}
}
}
inline static void editor_handle_wrapper(const LSPMessage &message) {
message.editor->lsp_handle(message.message);
}
inline void send_raw(const json &msg) {
std::string payload = msg.dump();
std::string header =
"Content-Length: " + std::to_string(payload.size()) + "\r\n\r\n";
std::string out = header + payload;
const char *ptr = out.data();
size_t remaining = out.size();
while (remaining > 0) {
ssize_t n = write(stdin_fd, ptr, remaining);
if (n <= 0) {
if (errno == EINTR)
continue;
break;
}
ptr += n;
remaining -= n;
}
};
inline std::optional<json> read_lsp_message() {
std::string header;
char c;
while (true) {
ssize_t n = read(stdout_fd, &c, 1);
if (n <= 0)
return std::nullopt;
header.push_back(c);
if (header.size() >= 4 && header.substr(header.size() - 4) == "\r\n\r\n")
break;
}
size_t pos = header.find("Content-Length:");
if (pos == std::string::npos)
return std::nullopt;
pos += strlen("Content-Length:");
while (pos < header.size() && std::isspace(header[pos]))
pos++;
size_t end = pos;
while (end < header.size() && std::isdigit(header[end]))
end++;
size_t len = std::stoul(header.substr(pos, end - pos));
std::string body(len, '\0');
size_t got = 0;
while (got < len) {
ssize_t n = read(stdout_fd, &body[got], len - got);
if (n <= 0)
return std::nullopt;
got += n;
}
return json::parse(body);
}
inline Editor *resolve_uri(std::string uri) {
if (uri.empty())
return nullptr;
for (auto &editor : editors)
if (editor->uri == uri)
return editor;
return nullptr;
}
inline void lsp_handle(json &message) {
std::string method = message.value("method", "");
if (method == "window/showMessage") {
if (message.contains("params")) {
auto &p = message["params"];
if (p.contains("message"))
log("%s\n", p["message"].get<std::string>().c_str());
}
} else if (method == "window/logMessage") {
if (message.contains("params")) {
auto &p = message["params"];
if (p.contains("message"))
log("%s\n", p["message"].get<std::string>().c_str());
}
}
}
void send(std::unique_ptr<LSPMessage> message) {
if (pid == -1)
return;
message->message["jsonrpc"] = "2.0";
if (message->callback)
message->message["id"] = ++last_id;
outbox.push(message->message);
if (!message->callback)
return;
std::lock_guard lock(lsp::lsp_mutex);
pending[last_id] = std::move(message);
}
};
#endif
+6 -2
View File
@@ -2,6 +2,7 @@
#define MAIN_H
#include "pch.h"
#include "ui/bar.h"
#define NORMAL 0
#define INSERT 1
@@ -11,7 +12,10 @@
extern std::atomic<bool> running;
extern std::atomic<uint8_t> mode;
extern std::vector<struct Editor *> editors;
extern uint8_t current_editor;
extern fs::path pwd;
namespace ui {
extern Bar bar;
} // namespace ui
#endif
+9 -7
View File
@@ -4,12 +4,12 @@
#define PCRE2_CODE_UNIT_WIDTH 8
#define PCRE_WORKSPACE_SIZE 512
#include <mruby.h>
#include <mruby/array.h>
#include <mruby/compile.h>
#include <mruby/hash.h>
#include <mruby/irep.h>
#include <mruby/string.h>
#include "mruby.h"
#include "mruby/array.h"
#include "mruby/compile.h"
#include "mruby/hash.h"
#include "mruby/irep.h"
#include "mruby/string.h"
#include <nlohmann/json.hpp>
#include <pcre2.h>
extern "C" {
@@ -31,10 +31,12 @@ extern "C" {
#include <filesystem>
#include <fstream>
#include <functional>
#include <immintrin.h>
#include <limits.h>
#include <map>
#include <mutex>
#include <optional>
#include <poll.h>
#include <queue>
#include <set>
#include <shared_mutex>
@@ -43,13 +45,13 @@ extern "C" {
#include <string.h>
#include <string>
#include <sys/ioctl.h>
#include <sys/poll.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <termios.h>
#include <thread>
#include <unistd.h>
#include <unordered_map>
#include <unordered_set>
#include <vector>
using json = nlohmann::json;
+52
View File
@@ -0,0 +1,52 @@
#ifndef SCRIPTING_DECL_H
#define SCRIPTING_DECL_H
#include "syntax/decl.h"
#include "utils/utils.h"
#include "windows/decl.h"
namespace fs = std::filesystem;
extern std::unordered_map<std::string, std::pair<mrb_value, mrb_value>>
custom_highlighters;
extern mrb_state *mrb;
extern fs::path ruby_config_path;
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_copy(const char *text, size_t len);
std::string ruby_paste();
std::string ruby_file_detect(std::string filename);
void load_theme();
void load_languages_info();
uint8_t read_line_endings();
void load_custom_highlighters();
bool custom_compare(mrb_value match_block, std::string state1,
std::string state2);
std::string parse_custom(std::vector<Token> *tokens, mrb_value parser_block,
const char *line, uint32_t len, std::string state,
uint32_t c_line);
BarLine bar_contents(uint8_t mode, uint32_t width, std::string foldername,
Window *window);
#endif
@@ -1,3 +1,66 @@
def command_exists?(cmd)
system("command -v #{cmd} > /dev/null 2>&1")
end
module Clipboard
@clip = ""
@os = :os_name_placed_here
class << self
def copy(text)
if @os == :windows
IO.popen("clip", "w") { |f| f.write(text) }
elsif @os == :mac
IO.popen("pbcopy", "w") { |f| f.write(text) }
elsif @os == :linux
if ENV["XDG_SESSION_TYPE"]&.downcase == "wayland" || ENV["WAYLAND_DISPLAY"]
if command_exists?("wl-copy")
IO.popen("wl-copy", "w") { |f| f.write(text) }
else
osc52_copy(text)
end
elsif ENV["XDG_SESSION_TYPE"]&.downcase == "x11" || ENV["DISPLAY"]
if command_exists?("xsel")
IO.popen("xsel --clipboard --input", "w") { |f| f.write(text) }
elsif command_exists?("xclip")
IO.popen("xclip -selection clipboard", "w") { |f| f.write(text) }
else
osc52_copy(text)
end
end
end
@clip = text
end
def paste
if @os == :windows
return `powershell -NoProfile -Command Get-Clipboard`
elsif @os == :mac
return `pbpaste`
elsif @os == :linux
if ENV["XDG_SESSION_TYPE"]&.downcase == "wayland" || ENV["WAYLAND_DISPLAY"]
if command_exists?("wl-copy")
return `wl-paste`
end
elsif ENV["XDG_SESSION_TYPE"]&.downcase == "x11" || ENV["DISPLAY"]
if command_exists?("xsel")
return `xsel --clipboard --output`
elsif command_exists?("xclip")
return `xclip -selection clipboard -o`
else
return @clip
end
end
end
return ""
end
def osc52_copy(text)
encoded = [text].pack("m0")
print "\e]52;c;#{encoded}\a"
text
end
end
end
module C
@lsp_config = {
"clangd" => [
@@ -114,7 +177,7 @@ module C
color: 0x6e1516,
symbol: "",
extensions: ["erb"],
lsp: "ruby-lsp"
lsp: "emmet-language-server"
},
lua: {
color: 0x36a3d9,
@@ -224,6 +287,11 @@ module C
extensions: ["sh"],
filenames: ["bash_profile", "bashrc"],
lsp: "bash-language-server"
},
default: {
color: 0x6d8086,
symbol: "󰈚 ",
extensions: []
}
}
@theme = {
@@ -262,11 +330,98 @@ module C
@highlighters = {}
@b_startup = nil
@b_shutdown = nil
@b_bar = proc do |info|
# mode, width, data[5] : strings (any data about the focused window)
# 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[:default]
filename = ""
if info[:data][0] == "editor"
lang_info = C.languages[info[:data][2]] if info[:data][2] != ""
if lang_info.nil?
lang_info = C.languages[:default]
end
filename = File.basename(info[:data][1]) if info[:data][1] != ""
end
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 + 1 }
highlights << { fg: 0x24272d, bg: 0x000000, start: 15 + filename.length + 1, length: 1 }
next {
text: starting,
highlights: highlights
}
end
@b_copy = proc do |text|
Clipboard.copy(text)
end
@b_paste = proc do
next Clipboard.paste
end
@b_file_detect = proc do |filename|
type = :default
next type unless File.exist?(filename)
first_line = File.open(filename, &:readline).chomp
if first_line.start_with?("#!")
shebang = first_line[2..].downcase
type = case shebang
when /bash/, /sh/ then :bash
when /fish/ then :fish
when /python/ then :python
when /ruby/ then :ruby
when /lua/ then :lua
else :default
end
next type
end
next type if :os_name_placed_here != :linux || :os_name_placed_here != :mac
next type if !command_exists?("file")
mimetype = `file --mime-type -b #{filename}`.chomp
type = case mimetype
when /shellscript/ then :bash
when /ruby/ then :ruby
when /diff/ then :diff
when /html/ then :html
when /python/ then :python
when /javascript/ then :javascript
when /makefile/ then :makefile
when /-c$/ then :c
else :default
end
next type
end
class << self
attr_accessor :theme, :lsp_config, :languages,
:line_endings, :highlighters
attr_reader :b_startup, :b_shutdown, :b_extra_highlights
attr_reader :b_startup, :b_shutdown, :b_extra_highlights,
:b_bar, :b_copy, :b_paste, :b_file_detect
def bar=(&block)
@b_bar = block
end
def startup(&block)
@b_startup = block
@@ -276,6 +431,18 @@ module C
@b_shutdown = block
end
def copy(&block)
@b_copy = block
end
def paste(&block)
@b_paste = block
end
def file_detect(&block)
@b_file_detect = block
end
def extra_highlights(&block)
@b_extra_highlights = block
end
@@ -311,3 +478,23 @@ module C
end
end
end
$LOADED ||= []
$BIND_TOP = binding
module Kernel
def require_relative(path, bind = nil)
path += ".rb" unless path.end_with?(".rb")
path = File.expand_path(path, File.dirname(C.config_file))
return if $LOADED.include?(path)
$LOADED << path
code = File.read(path)
eval(code, bind || $BIND_TOP, path)
end
def load(path, bind = nil)
path += ".rb" unless path.end_with?(".rb")
path = File.expand_path(path, File.dirname(C.config_file))
$LOADED.delete(path)
require_relative(path, bind)
end
end
+955
View File
@@ -0,0 +1,955 @@
#pragma once
constexpr unsigned char _tmp___crib_precompiled_mrb[] = {
0x52, 0x49, 0x54, 0x45, 0x30, 0x34, 0x30, 0x30, 0x00, 0x00, 0x2c, 0x93,
0x48, 0x53, 0x4d, 0x4b, 0x30, 0x30, 0x30, 0x30, 0x49, 0x52, 0x45, 0x50,
0x00, 0x00, 0x2a, 0xff, 0x30, 0x34, 0x30, 0x30, 0x00, 0x00, 0x00, 0xa2,
0x00, 0x01, 0x00, 0x04, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3a,
0x11, 0x01, 0x68, 0x01, 0x00, 0x69, 0x01, 0x00, 0x6b, 0x01, 0x01, 0x01,
0x11, 0x01, 0x68, 0x01, 0x02, 0x69, 0x01, 0x02, 0x11, 0x01, 0x68, 0x01,
0x03, 0x69, 0x01, 0x03, 0x15, 0x01, 0x04, 0x27, 0x01, 0x00, 0x06, 0x52,
0x01, 0x00, 0x16, 0x01, 0x04, 0x30, 0x02, 0x05, 0x16, 0x02, 0x06, 0x11,
0x02, 0x68, 0x02, 0x07, 0x69, 0x02, 0x04, 0x3d, 0x02, 0x76, 0x00, 0x00,
0x00, 0x08, 0x00, 0x06, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x00, 0x00,
0x0f, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x5f, 0x65, 0x78, 0x69,
0x73, 0x74, 0x73, 0x3f, 0x00, 0x00, 0x09, 0x43, 0x6c, 0x69, 0x70, 0x62,
0x6f, 0x61, 0x72, 0x64, 0x00, 0x00, 0x01, 0x43, 0x00, 0x00, 0x07, 0x24,
0x4c, 0x4f, 0x41, 0x44, 0x45, 0x44, 0x00, 0x00, 0x07, 0x62, 0x69, 0x6e,
0x64, 0x69, 0x6e, 0x67, 0x00, 0x00, 0x09, 0x24, 0x42, 0x49, 0x4e, 0x44,
0x5f, 0x54, 0x4f, 0x50, 0x00, 0x00, 0x06, 0x4b, 0x65, 0x72, 0x6e, 0x65,
0x6c, 0x00, 0x00, 0x00, 0x03, 0xfc, 0x00, 0x01, 0x00, 0x03, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x01, 0x3b, 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, 0x30, 0x01, 0x35, 0x3d, 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, 0x00, 0x58, 0x00, 0x03, 0x00, 0x06, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x39, 0x04, 0x00, 0x00, 0x5c, 0x04,
0x00, 0x01, 0x05, 0x01, 0x5d, 0x04, 0x5c, 0x05, 0x01, 0x5d, 0x04, 0x2f,
0x03, 0x00, 0x01, 0x3d, 0x03, 0x00, 0x02, 0x00, 0x00, 0x0b, 0x63, 0x6f,
0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x20, 0x2d, 0x76, 0x20, 0x00, 0x00, 0x00,
0x11, 0x20, 0x3e, 0x20, 0x2f, 0x64, 0x65, 0x76, 0x2f, 0x6e, 0x75, 0x6c,
0x6c, 0x20, 0x32, 0x3e, 0x26, 0x31, 0x00, 0x00, 0x01, 0x00, 0x06, 0x73,
0x79, 0x73, 0x74, 0x65, 0x6d, 0x00, 0x00, 0x00, 0x00, 0x43, 0x00, 0x01,
0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x5c, 0x01,
0x00, 0x1a, 0x01, 0x00, 0x10, 0x01, 0x01, 0x1a, 0x01, 0x02, 0x12, 0x01,
0x6f, 0x01, 0x69, 0x01, 0x00, 0x3d, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00,
0x00, 0x00, 0x03, 0x00, 0x05, 0x40, 0x63, 0x6c, 0x69, 0x70, 0x00, 0x00,
0x05, 0x6c, 0x69, 0x6e, 0x75, 0x78, 0x00, 0x00, 0x03, 0x40, 0x6f, 0x73,
0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 0x00,
0x00, 0x00, 0x00, 0x00, 0x0e, 0x6b, 0x01, 0x00, 0x00, 0x6b, 0x01, 0x01,
0x01, 0x6b, 0x01, 0x02, 0x02, 0x3d, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00,
0x04, 0x63, 0x6f, 0x70, 0x79, 0x00, 0x00, 0x05, 0x70, 0x61, 0x73, 0x74,
0x65, 0x00, 0x00, 0x0a, 0x6f, 0x73, 0x63, 0x35, 0x32, 0x5f, 0x63, 0x6f,
0x70, 0x79, 0x00, 0x00, 0x00, 0x02, 0x37, 0x00, 0x03, 0x00, 0x07, 0x00,
0x05, 0x00, 0x00, 0x00, 0x00, 0x01, 0x0f, 0x39, 0x04, 0x00, 0x00, 0x19,
0x03, 0x00, 0x10, 0x04, 0x01, 0x4d, 0x03, 0x28, 0x03, 0x00, 0x13, 0x1d,
0x03, 0x02, 0x5c, 0x04, 0x00, 0x5c, 0x05, 0x01, 0x62, 0x06, 0x00, 0x34,
0x03, 0x03, 0x02, 0x26, 0x00, 0xe4, 0x19, 0x03, 0x00, 0x10, 0x04, 0x04,
0x4d, 0x03, 0x28, 0x03, 0x00, 0x13, 0x1d, 0x03, 0x02, 0x5c, 0x04, 0x02,
0x5c, 0x05, 0x01, 0x62, 0x06, 0x01, 0x34, 0x03, 0x03, 0x02, 0x26, 0x00,
0xc5, 0x19, 0x03, 0x00, 0x10, 0x04, 0x05, 0x4d, 0x03, 0x28, 0x03, 0x00,
0xb9, 0x1d, 0x03, 0x06, 0x5c, 0x04, 0x03, 0x23, 0x03, 0x01, 0x04, 0x03,
0x29, 0x04, 0x00, 0x03, 0x33, 0x03, 0x07, 0x5c, 0x04, 0x04, 0x4d, 0x03,
0x27, 0x03, 0x00, 0x08, 0x1d, 0x03, 0x06, 0x5c, 0x04, 0x05, 0x23, 0x03,
0x28, 0x03, 0x00, 0x28, 0x5c, 0x04, 0x06, 0x2f, 0x03, 0x08, 0x01, 0x28,
0x03, 0x00, 0x13, 0x1d, 0x03, 0x02, 0x5c, 0x04, 0x06, 0x5c, 0x05, 0x01,
0x62, 0x06, 0x02, 0x34, 0x03, 0x03, 0x02, 0x26, 0x00, 0x07, 0x01, 0x04,
0x01, 0x2f, 0x03, 0x09, 0x01, 0x26, 0x00, 0x6a, 0x1d, 0x03, 0x06, 0x5c,
0x04, 0x03, 0x23, 0x03, 0x01, 0x04, 0x03, 0x29, 0x04, 0x00, 0x03, 0x33,
0x03, 0x07, 0x5c, 0x04, 0x07, 0x4d, 0x03, 0x27, 0x03, 0x00, 0x08, 0x1d,
0x03, 0x06, 0x5c, 0x04, 0x08, 0x23, 0x03, 0x28, 0x03, 0x00, 0x43, 0x5c,
0x04, 0x09, 0x2f, 0x03, 0x08, 0x01, 0x28, 0x03, 0x00, 0x13, 0x1d, 0x03,
0x02, 0x5c, 0x04, 0x0a, 0x5c, 0x05, 0x01, 0x62, 0x06, 0x03, 0x34, 0x03,
0x03, 0x02, 0x26, 0x00, 0x25, 0x5c, 0x04, 0x0b, 0x2f, 0x03, 0x08, 0x01,
0x28, 0x03, 0x00, 0x13, 0x1d, 0x03, 0x02, 0x5c, 0x04, 0x0c, 0x5c, 0x05,
0x01, 0x62, 0x06, 0x04, 0x34, 0x03, 0x03, 0x02, 0x26, 0x00, 0x07, 0x01,
0x04, 0x01, 0x2f, 0x03, 0x09, 0x01, 0x01, 0x03, 0x01, 0x1a, 0x03, 0x0a,
0x3d, 0x03, 0x00, 0x0d, 0x00, 0x00, 0x04, 0x63, 0x6c, 0x69, 0x70, 0x00,
0x00, 0x00, 0x01, 0x77, 0x00, 0x00, 0x00, 0x06, 0x70, 0x62, 0x63, 0x6f,
0x70, 0x79, 0x00, 0x00, 0x00, 0x10, 0x58, 0x44, 0x47, 0x5f, 0x53, 0x45,
0x53, 0x53, 0x49, 0x4f, 0x4e, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x00, 0x00,
0x00, 0x07, 0x77, 0x61, 0x79, 0x6c, 0x61, 0x6e, 0x64, 0x00, 0x00, 0x00,
0x0f, 0x57, 0x41, 0x59, 0x4c, 0x41, 0x4e, 0x44, 0x5f, 0x44, 0x49, 0x53,
0x50, 0x4c, 0x41, 0x59, 0x00, 0x00, 0x00, 0x07, 0x77, 0x6c, 0x2d, 0x63,
0x6f, 0x70, 0x79, 0x00, 0x00, 0x00, 0x03, 0x78, 0x31, 0x31, 0x00, 0x00,
0x00, 0x07, 0x44, 0x49, 0x53, 0x50, 0x4c, 0x41, 0x59, 0x00, 0x00, 0x00,
0x04, 0x78, 0x73, 0x65, 0x6c, 0x00, 0x00, 0x00, 0x18, 0x78, 0x73, 0x65,
0x6c, 0x20, 0x2d, 0x2d, 0x63, 0x6c, 0x69, 0x70, 0x62, 0x6f, 0x61, 0x72,
0x64, 0x20, 0x2d, 0x2d, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x00, 0x00, 0x00,
0x05, 0x78, 0x63, 0x6c, 0x69, 0x70, 0x00, 0x00, 0x00, 0x1a, 0x78, 0x63,
0x6c, 0x69, 0x70, 0x20, 0x2d, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x69,
0x6f, 0x6e, 0x20, 0x63, 0x6c, 0x69, 0x70, 0x62, 0x6f, 0x61, 0x72, 0x64,
0x00, 0x00, 0x0b, 0x00, 0x03, 0x40, 0x6f, 0x73, 0x00, 0x00, 0x07, 0x77,
0x69, 0x6e, 0x64, 0x6f, 0x77, 0x73, 0x00, 0x00, 0x02, 0x49, 0x4f, 0x00,
0x00, 0x05, 0x70, 0x6f, 0x70, 0x65, 0x6e, 0x00, 0x00, 0x03, 0x6d, 0x61,
0x63, 0x00, 0x00, 0x05, 0x6c, 0x69, 0x6e, 0x75, 0x78, 0x00, 0x00, 0x03,
0x45, 0x4e, 0x56, 0x00, 0x00, 0x08, 0x64, 0x6f, 0x77, 0x6e, 0x63, 0x61,
0x73, 0x65, 0x00, 0x00, 0x0f, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64,
0x5f, 0x65, 0x78, 0x69, 0x73, 0x74, 0x73, 0x3f, 0x00, 0x00, 0x0a, 0x6f,
0x73, 0x63, 0x35, 0x32, 0x5f, 0x63, 0x6f, 0x70, 0x79, 0x00, 0x00, 0x05,
0x40, 0x63, 0x6c, 0x69, 0x70, 0x00, 0x00, 0x00, 0x00, 0x2d, 0x00, 0x03,
0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x39, 0x04,
0x00, 0x00, 0x01, 0x03, 0x01, 0x21, 0x04, 0x01, 0x00, 0x32, 0x03, 0x00,
0x01, 0x3d, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x05, 0x77, 0x72, 0x69,
0x74, 0x65, 0x00, 0x00, 0x00, 0x00, 0x2d, 0x00, 0x03, 0x00, 0x06, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x39, 0x04, 0x00, 0x00, 0x01,
0x03, 0x01, 0x21, 0x04, 0x01, 0x00, 0x32, 0x03, 0x00, 0x01, 0x3d, 0x03,
0x00, 0x00, 0x00, 0x01, 0x00, 0x05, 0x77, 0x72, 0x69, 0x74, 0x65, 0x00,
0x00, 0x00, 0x00, 0x2d, 0x00, 0x03, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x11, 0x39, 0x04, 0x00, 0x00, 0x01, 0x03, 0x01, 0x21,
0x04, 0x01, 0x00, 0x32, 0x03, 0x00, 0x01, 0x3d, 0x03, 0x00, 0x00, 0x00,
0x01, 0x00, 0x05, 0x77, 0x72, 0x69, 0x74, 0x65, 0x00, 0x00, 0x00, 0x00,
0x2d, 0x00, 0x03, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x11, 0x39, 0x04, 0x00, 0x00, 0x01, 0x03, 0x01, 0x21, 0x04, 0x01, 0x00,
0x32, 0x03, 0x00, 0x01, 0x3d, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x05,
0x77, 0x72, 0x69, 0x74, 0x65, 0x00, 0x00, 0x00, 0x00, 0x2d, 0x00, 0x03,
0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x39, 0x04,
0x00, 0x00, 0x01, 0x03, 0x01, 0x21, 0x04, 0x01, 0x00, 0x32, 0x03, 0x00,
0x01, 0x3d, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x05, 0x77, 0x72, 0x69,
0x74, 0x65, 0x00, 0x00, 0x00, 0x02, 0x31, 0x00, 0x02, 0x00, 0x05, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe7, 0x39, 0x00, 0x00, 0x00, 0x19,
0x02, 0x00, 0x10, 0x03, 0x01, 0x4d, 0x02, 0x28, 0x02, 0x00, 0x0e, 0x12,
0x02, 0x5c, 0x03, 0x00, 0x2f, 0x02, 0x02, 0x01, 0x3d, 0x02, 0x26, 0x00,
0xc4, 0x19, 0x02, 0x00, 0x10, 0x03, 0x03, 0x4d, 0x02, 0x28, 0x02, 0x00,
0x0e, 0x12, 0x02, 0x5c, 0x03, 0x01, 0x2f, 0x02, 0x02, 0x01, 0x3d, 0x02,
0x26, 0x00, 0xaa, 0x19, 0x02, 0x00, 0x10, 0x03, 0x04, 0x4d, 0x02, 0x28,
0x02, 0x00, 0x9e, 0x1d, 0x02, 0x05, 0x5c, 0x03, 0x02, 0x23, 0x02, 0x01,
0x03, 0x02, 0x29, 0x03, 0x00, 0x03, 0x33, 0x02, 0x06, 0x5c, 0x03, 0x03,
0x4d, 0x02, 0x27, 0x02, 0x00, 0x08, 0x1d, 0x02, 0x05, 0x5c, 0x03, 0x04,
0x23, 0x02, 0x28, 0x02, 0x00, 0x19, 0x5c, 0x03, 0x05, 0x2f, 0x02, 0x07,
0x01, 0x28, 0x02, 0x00, 0x0b, 0x12, 0x02, 0x5c, 0x03, 0x06, 0x2f, 0x02,
0x02, 0x01, 0x3d, 0x02, 0x26, 0x00, 0x5e, 0x1d, 0x02, 0x05, 0x5c, 0x03,
0x02, 0x23, 0x02, 0x01, 0x03, 0x02, 0x29, 0x03, 0x00, 0x03, 0x33, 0x02,
0x06, 0x5c, 0x03, 0x07, 0x4d, 0x02, 0x27, 0x02, 0x00, 0x08, 0x1d, 0x02,
0x05, 0x5c, 0x03, 0x08, 0x23, 0x02, 0x28, 0x02, 0x00, 0x37, 0x5c, 0x03,
0x09, 0x2f, 0x02, 0x07, 0x01, 0x28, 0x02, 0x00, 0x0e, 0x12, 0x02, 0x5c,
0x03, 0x0a, 0x2f, 0x02, 0x02, 0x01, 0x3d, 0x02, 0x26, 0x00, 0x1e, 0x5c,
0x03, 0x0b, 0x2f, 0x02, 0x07, 0x01, 0x28, 0x02, 0x00, 0x0e, 0x12, 0x02,
0x5c, 0x03, 0x0c, 0x2f, 0x02, 0x02, 0x01, 0x3d, 0x02, 0x26, 0x00, 0x05,
0x19, 0x02, 0x08, 0x3d, 0x02, 0x5c, 0x02, 0x0d, 0x3d, 0x02, 0x00, 0x0e,
0x00, 0x00, 0x2c, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x73, 0x68, 0x65, 0x6c,
0x6c, 0x20, 0x2d, 0x4e, 0x6f, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65,
0x20, 0x2d, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x20, 0x47, 0x65,
0x74, 0x2d, 0x43, 0x6c, 0x69, 0x70, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x00,
0x00, 0x00, 0x07, 0x70, 0x62, 0x70, 0x61, 0x73, 0x74, 0x65, 0x00, 0x00,
0x00, 0x10, 0x58, 0x44, 0x47, 0x5f, 0x53, 0x45, 0x53, 0x53, 0x49, 0x4f,
0x4e, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x00, 0x00, 0x00, 0x07, 0x77, 0x61,
0x79, 0x6c, 0x61, 0x6e, 0x64, 0x00, 0x00, 0x00, 0x0f, 0x57, 0x41, 0x59,
0x4c, 0x41, 0x4e, 0x44, 0x5f, 0x44, 0x49, 0x53, 0x50, 0x4c, 0x41, 0x59,
0x00, 0x00, 0x00, 0x07, 0x77, 0x6c, 0x2d, 0x63, 0x6f, 0x70, 0x79, 0x00,
0x00, 0x00, 0x08, 0x77, 0x6c, 0x2d, 0x70, 0x61, 0x73, 0x74, 0x65, 0x00,
0x00, 0x00, 0x03, 0x78, 0x31, 0x31, 0x00, 0x00, 0x00, 0x07, 0x44, 0x49,
0x53, 0x50, 0x4c, 0x41, 0x59, 0x00, 0x00, 0x00, 0x04, 0x78, 0x73, 0x65,
0x6c, 0x00, 0x00, 0x00, 0x19, 0x78, 0x73, 0x65, 0x6c, 0x20, 0x2d, 0x2d,
0x63, 0x6c, 0x69, 0x70, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x20, 0x2d, 0x2d,
0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x00, 0x00, 0x00, 0x05, 0x78, 0x63,
0x6c, 0x69, 0x70, 0x00, 0x00, 0x00, 0x1d, 0x78, 0x63, 0x6c, 0x69, 0x70,
0x20, 0x2d, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20,
0x63, 0x6c, 0x69, 0x70, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x20, 0x2d, 0x6f,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x03, 0x40, 0x6f, 0x73,
0x00, 0x00, 0x07, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x73, 0x00, 0x00,
0x01, 0x60, 0x00, 0x00, 0x03, 0x6d, 0x61, 0x63, 0x00, 0x00, 0x05, 0x6c,
0x69, 0x6e, 0x75, 0x78, 0x00, 0x00, 0x03, 0x45, 0x4e, 0x56, 0x00, 0x00,
0x08, 0x64, 0x6f, 0x77, 0x6e, 0x63, 0x61, 0x73, 0x65, 0x00, 0x00, 0x0f,
0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x5f, 0x65, 0x78, 0x69, 0x73,
0x74, 0x73, 0x3f, 0x00, 0x00, 0x05, 0x40, 0x63, 0x6c, 0x69, 0x70, 0x00,
0x00, 0x00, 0x00, 0x60, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x27, 0x39, 0x04, 0x00, 0x00, 0x01, 0x04, 0x01, 0x52,
0x04, 0x01, 0x5c, 0x05, 0x00, 0x32, 0x04, 0x00, 0x01, 0x01, 0x03, 0x04,
0x5c, 0x05, 0x01, 0x01, 0x06, 0x03, 0x5d, 0x05, 0x5c, 0x06, 0x02, 0x5d,
0x05, 0x2f, 0x04, 0x01, 0x01, 0x3d, 0x01, 0x00, 0x03, 0x00, 0x00, 0x02,
0x6d, 0x30, 0x00, 0x00, 0x00, 0x07, 0x1b, 0x5d, 0x35, 0x32, 0x3b, 0x63,
0x3b, 0x00, 0x00, 0x00, 0x01, 0x07, 0x00, 0x00, 0x02, 0x00, 0x04, 0x70,
0x61, 0x63, 0x6b, 0x00, 0x00, 0x05, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x00,
0x00, 0x00, 0x0f, 0xc7, 0x00, 0x01, 0x00, 0x4c, 0x00, 0x05, 0x00, 0x00,
0x00, 0x00, 0x07, 0xa8, 0x5c, 0x01, 0x00, 0x5c, 0x02, 0x01, 0x5c, 0x03,
0x02, 0x5c, 0x04, 0x03, 0x5c, 0x05, 0x04, 0x5c, 0x06, 0x05, 0x5c, 0x07,
0x06, 0x5c, 0x08, 0x07, 0x52, 0x02, 0x07, 0x5c, 0x03, 0x08, 0x52, 0x04,
0x00, 0x5c, 0x05, 0x09, 0x5c, 0x06, 0x0a, 0x52, 0x06, 0x01, 0x5c, 0x07,
0x0b, 0x5c, 0x08, 0x0c, 0x52, 0x08, 0x01, 0x5c, 0x09, 0x0d, 0x5c, 0x0a,
0x0e, 0x52, 0x0a, 0x01, 0x5c, 0x0b, 0x0f, 0x5c, 0x0c, 0x0e, 0x52, 0x0c,
0x01, 0x5c, 0x0d, 0x10, 0x5c, 0x0e, 0x0c, 0x52, 0x0e, 0x01, 0x5c, 0x0f,
0x11, 0x5c, 0x10, 0x12, 0x52, 0x10, 0x01, 0x5c, 0x11, 0x13, 0x5c, 0x12,
0x14, 0x52, 0x12, 0x01, 0x5c, 0x13, 0x15, 0x5c, 0x14, 0x0e, 0x52, 0x14,
0x01, 0x5c, 0x15, 0x16, 0x5c, 0x16, 0x0e, 0x52, 0x16, 0x01, 0x5c, 0x17,
0x17, 0x52, 0x18, 0x00, 0x5c, 0x19, 0x18, 0x5c, 0x1a, 0x0e, 0x52, 0x1a,
0x01, 0x5c, 0x1b, 0x19, 0x52, 0x1c, 0x00, 0x5c, 0x1d, 0x1a, 0x5c, 0x1e,
0x0e, 0x52, 0x1e, 0x01, 0x5c, 0x1f, 0x1b, 0x5c, 0x20, 0x1c, 0x52, 0x20,
0x01, 0x5c, 0x21, 0x1d, 0x52, 0x22, 0x00, 0x5c, 0x23, 0x1e, 0x5c, 0x24,
0x14, 0x5c, 0x25, 0x0a, 0x52, 0x24, 0x02, 0x5c, 0x25, 0x1f, 0x5c, 0x26,
0x0e, 0x52, 0x26, 0x01, 0x5c, 0x27, 0x20, 0x5c, 0x28, 0x12, 0x52, 0x28,
0x01, 0x5c, 0x29, 0x21, 0x52, 0x2a, 0x00, 0x5c, 0x2b, 0x22, 0x5c, 0x2c,
0x23, 0x5c, 0x2d, 0x24, 0x5c, 0x2e, 0x0a, 0x52, 0x2c, 0x03, 0x5e, 0x01,
0x16, 0x1a, 0x01, 0x00, 0x10, 0x01, 0x01, 0x10, 0x02, 0x02, 0x0f, 0x03,
0x00, 0x55, 0x55, 0x55, 0x10, 0x04, 0x03, 0x5c, 0x05, 0x25, 0x10, 0x06,
0x04, 0x5c, 0x07, 0x26, 0x52, 0x07, 0x01, 0x10, 0x08, 0x05, 0x5c, 0x09,
0x00, 0x5e, 0x02, 0x04, 0x10, 0x03, 0x06, 0x10, 0x04, 0x02, 0x0e, 0x05,
0x59, 0x9c, 0x10, 0x06, 0x03, 0x5c, 0x07, 0x27, 0x10, 0x08, 0x04, 0x5c,
0x09, 0x28, 0x5c, 0x0a, 0x29, 0x5c, 0x0b, 0x2a, 0x52, 0x09, 0x03, 0x10,
0x0a, 0x05, 0x5c, 0x0b, 0x00, 0x5e, 0x04, 0x04, 0x10, 0x05, 0x07, 0x10,
0x06, 0x02, 0x0f, 0x07, 0x00, 0xa8, 0xb9, 0xcc, 0x10, 0x08, 0x03, 0x5c,
0x09, 0x2b, 0x10, 0x0a, 0x04, 0x5c, 0x0b, 0x2c, 0x5c, 0x0c, 0x2d, 0x52,
0x0b, 0x02, 0x10, 0x0c, 0x05, 0x5c, 0x0d, 0x00, 0x5e, 0x06, 0x04, 0x10,
0x07, 0x08, 0x10, 0x08, 0x02, 0x0f, 0x09, 0x00, 0x36, 0xa3, 0xd9, 0x10,
0x0a, 0x03, 0x5c, 0x0b, 0x2e, 0x10, 0x0c, 0x04, 0x5c, 0x0d, 0x2f, 0x52,
0x0d, 0x01, 0x10, 0x0e, 0x05, 0x5c, 0x0f, 0x0d, 0x5e, 0x08, 0x04, 0x10,
0x09, 0x09, 0x10, 0x0a, 0x02, 0x0f, 0x0b, 0x00, 0x4d, 0x5a, 0x5e, 0x10,
0x0c, 0x03, 0x5c, 0x0d, 0x30, 0x10, 0x0e, 0x04, 0x5c, 0x0f, 0x31, 0x52,
0x0f, 0x01, 0x10, 0x10, 0x05, 0x5c, 0x11, 0x10, 0x5e, 0x0a, 0x04, 0x10,
0x0b, 0x0a, 0x10, 0x0c, 0x02, 0x0f, 0x0d, 0x00, 0x00, 0xad, 0xd8, 0x10,
0x0e, 0x03, 0x5c, 0x0f, 0x32, 0x10, 0x10, 0x04, 0x5c, 0x11, 0x33, 0x52,
0x11, 0x01, 0x10, 0x12, 0x05, 0x5c, 0x13, 0x11, 0x5e, 0x0c, 0x04, 0x10,
0x0d, 0x0b, 0x10, 0x0e, 0x02, 0x0f, 0x0f, 0x00, 0x00, 0xad, 0xd8, 0x10,
0x10, 0x03, 0x5c, 0x11, 0x32, 0x10, 0x12, 0x04, 0x5c, 0x13, 0x34, 0x52,
0x13, 0x01, 0x10, 0x14, 0x05, 0x5c, 0x15, 0x11, 0x5e, 0x0e, 0x04, 0x10,
0x0f, 0x0c, 0x10, 0x10, 0x02, 0x0f, 0x11, 0x00, 0xa0, 0x74, 0xc4, 0x10,
0x12, 0x03, 0x5c, 0x13, 0x35, 0x10, 0x14, 0x04, 0x5c, 0x15, 0x36, 0x5c,
0x16, 0x37, 0x52, 0x15, 0x02, 0x10, 0x16, 0x05, 0x5c, 0x17, 0x13, 0x5e,
0x10, 0x04, 0x10, 0x11, 0x0d, 0x10, 0x12, 0x02, 0x0f, 0x13, 0x00, 0xef,
0x8a, 0x91, 0x10, 0x14, 0x03, 0x5c, 0x15, 0x38, 0x10, 0x16, 0x04, 0x5c,
0x17, 0x39, 0x5c, 0x18, 0x3a, 0x52, 0x17, 0x02, 0x10, 0x18, 0x05, 0x5c,
0x19, 0x15, 0x5e, 0x12, 0x04, 0x10, 0x13, 0x0e, 0x10, 0x14, 0x02, 0x0f,
0x15, 0x00, 0xf0, 0xdf, 0x8a, 0x10, 0x16, 0x03, 0x5c, 0x17, 0x3b, 0x10,
0x18, 0x04, 0x5c, 0x19, 0x3c, 0x52, 0x19, 0x01, 0x10, 0x1a, 0x05, 0x5c,
0x1b, 0x16, 0x5e, 0x14, 0x04, 0x10, 0x15, 0x0f, 0x10, 0x16, 0x02, 0x0f,
0x17, 0x00, 0x36, 0xa3, 0xd9, 0x10, 0x18, 0x03, 0x5c, 0x19, 0x3d, 0x10,
0x1a, 0x04, 0x5c, 0x1b, 0x3e, 0x52, 0x1b, 0x01, 0x10, 0x1c, 0x05, 0x5c,
0x1d, 0x16, 0x5e, 0x16, 0x04, 0x10, 0x17, 0x10, 0x10, 0x18, 0x02, 0x0f,
0x19, 0x00, 0xcb, 0xcb, 0x41, 0x10, 0x1a, 0x03, 0x5c, 0x1b, 0x3f, 0x10,
0x1c, 0x04, 0x5c, 0x1d, 0x40, 0x52, 0x1d, 0x01, 0x10, 0x1e, 0x05, 0x5c,
0x1f, 0x0f, 0x5e, 0x18, 0x04, 0x10, 0x19, 0x11, 0x10, 0x1a, 0x02, 0x0f,
0x1b, 0x00, 0xcb, 0xcb, 0x41, 0x10, 0x1c, 0x03, 0x5c, 0x1d, 0x3f, 0x10,
0x1e, 0x04, 0x5c, 0x1f, 0x41, 0x52, 0x1f, 0x01, 0x10, 0x20, 0x05, 0x5c,
0x21, 0x0f, 0x5e, 0x1a, 0x04, 0x10, 0x1b, 0x12, 0x10, 0x1c, 0x02, 0x0f,
0x1d, 0x00, 0x6e, 0x15, 0x16, 0x10, 0x1e, 0x03, 0x5c, 0x1f, 0x38, 0x10,
0x20, 0x04, 0x5c, 0x21, 0x42, 0x52, 0x21, 0x01, 0x10, 0x22, 0x05, 0x5c,
0x23, 0x15, 0x5e, 0x1c, 0x04, 0x10, 0x1d, 0x13, 0x10, 0x1e, 0x02, 0x0f,
0x1f, 0x00, 0x36, 0xa3, 0xd9, 0x10, 0x20, 0x03, 0x5c, 0x21, 0x43, 0x10,
0x22, 0x04, 0x5c, 0x23, 0x44, 0x52, 0x23, 0x01, 0x10, 0x24, 0x05, 0x5c,
0x25, 0x17, 0x5e, 0x1e, 0x04, 0x10, 0x1f, 0x14, 0x10, 0x20, 0x02, 0x0f,
0x21, 0x00, 0x95, 0xe6, 0xcb, 0x10, 0x22, 0x03, 0x5c, 0x23, 0x45, 0x10,
0x24, 0x04, 0x5c, 0x25, 0x46, 0x52, 0x25, 0x01, 0x10, 0x26, 0x05, 0x5c,
0x27, 0x47, 0x5e, 0x20, 0x04, 0x10, 0x21, 0x15, 0x10, 0x22, 0x02, 0x0f,
0x23, 0x00, 0xde, 0xa5, 0x84, 0x10, 0x24, 0x03, 0x5c, 0x25, 0x48, 0x10,
0x26, 0x04, 0x5c, 0x27, 0x49, 0x52, 0x27, 0x01, 0x10, 0x28, 0x05, 0x5c,
0x29, 0x19, 0x5e, 0x22, 0x04, 0x10, 0x23, 0x16, 0x10, 0x24, 0x02, 0x0f,
0x25, 0x00, 0xa0, 0x74, 0xc4, 0x10, 0x26, 0x03, 0x5c, 0x27, 0x4a, 0x10,
0x28, 0x04, 0x5c, 0x29, 0x4b, 0x52, 0x29, 0x01, 0x10, 0x2a, 0x05, 0x5c,
0x2b, 0x1a, 0x5e, 0x24, 0x04, 0x10, 0x25, 0x17, 0x10, 0x26, 0x02, 0x0f,
0x27, 0x00, 0x36, 0xa3, 0xd9, 0x10, 0x28, 0x03, 0x5c, 0x29, 0x4c, 0x10,
0x2a, 0x04, 0x5c, 0x2b, 0x4d, 0x5c, 0x2c, 0x4e, 0x52, 0x2b, 0x02, 0x10,
0x2c, 0x05, 0x5c, 0x2d, 0x1b, 0x5e, 0x26, 0x04, 0x10, 0x27, 0x18, 0x10,
0x28, 0x02, 0x0f, 0x29, 0x00, 0x6d, 0x80, 0x86, 0x10, 0x2a, 0x03, 0x5c,
0x2b, 0x4f, 0x10, 0x2c, 0x04, 0x5c, 0x2d, 0x50, 0x52, 0x2d, 0x01, 0x10,
0x2e, 0x05, 0x5c, 0x2f, 0x1d, 0x5e, 0x28, 0x04, 0x10, 0x29, 0x19, 0x10,
0x2a, 0x02, 0x0f, 0x2b, 0x00, 0x36, 0xa3, 0xd9, 0x10, 0x2c, 0x03, 0x5c,
0x2d, 0x51, 0x10, 0x2e, 0x04, 0x5c, 0x2f, 0x52, 0x52, 0x2f, 0x01, 0x10,
0x30, 0x05, 0x5c, 0x31, 0x1e, 0x5e, 0x2a, 0x04, 0x10, 0x2b, 0x1a, 0x10,
0x2c, 0x02, 0x0f, 0x2d, 0x00, 0x6d, 0x80, 0x86, 0x10, 0x2e, 0x03, 0x5c,
0x2f, 0x4f, 0x10, 0x30, 0x04, 0x5c, 0x31, 0x53, 0x5c, 0x32, 0x54, 0x52,
0x31, 0x02, 0x10, 0x32, 0x05, 0x5c, 0x33, 0x1f, 0x5e, 0x2c, 0x04, 0x10,
0x2d, 0x1b, 0x10, 0x2e, 0x02, 0x0f, 0x2f, 0x00, 0xda, 0xd8, 0xd8, 0x10,
0x30, 0x03, 0x5c, 0x31, 0x55, 0x10, 0x32, 0x04, 0x5c, 0x33, 0x56, 0x52,
0x33, 0x01, 0x10, 0x34, 0x05, 0x5c, 0x35, 0x20, 0x5e, 0x2e, 0x04, 0x10,
0x2f, 0x1c, 0x10, 0x30, 0x02, 0x0f, 0x31, 0x00, 0x4e, 0x5c, 0x61, 0x10,
0x32, 0x03, 0x5c, 0x33, 0x57, 0x10, 0x34, 0x04, 0x5c, 0x35, 0x58, 0x5c,
0x36, 0x59, 0x52, 0x35, 0x02, 0x10, 0x36, 0x05, 0x5c, 0x37, 0x21, 0x5e,
0x30, 0x04, 0x10, 0x31, 0x1d, 0x10, 0x32, 0x02, 0x0f, 0x33, 0x00, 0x6d,
0x80, 0x86, 0x10, 0x34, 0x03, 0x5c, 0x35, 0x5a, 0x10, 0x36, 0x04, 0x5c,
0x37, 0x5b, 0x52, 0x37, 0x01, 0x5e, 0x32, 0x03, 0x10, 0x33, 0x1e, 0x10,
0x34, 0x02, 0x0f, 0x35, 0x00, 0xda, 0xd8, 0xd8, 0x10, 0x36, 0x03, 0x5c,
0x37, 0x5c, 0x10, 0x38, 0x04, 0x5c, 0x39, 0x5d, 0x52, 0x39, 0x01, 0x5e,
0x34, 0x03, 0x10, 0x35, 0x1f, 0x10, 0x36, 0x02, 0x0f, 0x37, 0x00, 0xdd,
0x4c, 0x35, 0x10, 0x38, 0x03, 0x5c, 0x39, 0x5e, 0x10, 0x3a, 0x04, 0x5c,
0x3b, 0x5f, 0x5c, 0x3c, 0x60, 0x52, 0x3b, 0x02, 0x5e, 0x36, 0x03, 0x10,
0x37, 0x20, 0x10, 0x38, 0x02, 0x0f, 0x39, 0x00, 0xf0, 0x50, 0x32, 0x10,
0x3a, 0x03, 0x5c, 0x3b, 0x61, 0x10, 0x3c, 0x04, 0x5c, 0x3d, 0x62, 0x52,
0x3d, 0x01, 0x5e, 0x38, 0x03, 0x10, 0x39, 0x21, 0x10, 0x3a, 0x02, 0x0f,
0x3b, 0x00, 0xf0, 0x50, 0x32, 0x10, 0x3c, 0x03, 0x5c, 0x3d, 0x61, 0x10,
0x3e, 0x04, 0x5c, 0x3f, 0x63, 0x52, 0x3f, 0x01, 0x5e, 0x3a, 0x03, 0x10,
0x3b, 0x22, 0x10, 0x3c, 0x02, 0x0f, 0x3d, 0x00, 0x9e, 0x9e, 0x9e, 0x10,
0x3e, 0x03, 0x5c, 0x3f, 0x64, 0x10, 0x40, 0x04, 0x5c, 0x41, 0x65, 0x52,
0x41, 0x01, 0x5e, 0x3c, 0x03, 0x10, 0x3d, 0x23, 0x10, 0x3e, 0x02, 0x0f,
0x3f, 0x00, 0x6d, 0x80, 0x86, 0x10, 0x40, 0x03, 0x5c, 0x41, 0x4f, 0x10,
0x42, 0x04, 0x5c, 0x43, 0x66, 0x52, 0x43, 0x01, 0x5e, 0x3e, 0x03, 0x10,
0x3f, 0x24, 0x10, 0x40, 0x02, 0x0f, 0x41, 0x00, 0xff, 0x80, 0x87, 0x10,
0x42, 0x03, 0x5c, 0x43, 0x67, 0x10, 0x44, 0x04, 0x5c, 0x45, 0x68, 0x52,
0x45, 0x01, 0x10, 0x46, 0x25, 0x5c, 0x47, 0x69, 0x52, 0x47, 0x01, 0x10,
0x48, 0x05, 0x5c, 0x49, 0x09, 0x5e, 0x40, 0x05, 0x10, 0x41, 0x26, 0x10,
0x42, 0x02, 0x0f, 0x43, 0x00, 0x4d, 0x5a, 0x5e, 0x10, 0x44, 0x03, 0x5c,
0x45, 0x6a, 0x10, 0x46, 0x04, 0x5c, 0x47, 0x6b, 0x52, 0x47, 0x01, 0x10,
0x48, 0x25, 0x5c, 0x49, 0x6c, 0x5c, 0x4a, 0x6d, 0x52, 0x49, 0x02, 0x10,
0x4a, 0x05, 0x5c, 0x4b, 0x0b, 0x5e, 0x42, 0x05, 0x10, 0x43, 0x27, 0x10,
0x44, 0x02, 0x0f, 0x45, 0x00, 0x6d, 0x80, 0x86, 0x10, 0x46, 0x03, 0x5c,
0x47, 0x6e, 0x10, 0x48, 0x04, 0x52, 0x49, 0x00, 0x5e, 0x44, 0x03, 0x5e,
0x01, 0x22, 0x1a, 0x01, 0x28, 0x10, 0x01, 0x27, 0x10, 0x02, 0x29, 0x0f,
0x03, 0x00, 0xee, 0xee, 0xee, 0x5e, 0x02, 0x01, 0x10, 0x03, 0x2a, 0x10,
0x04, 0x29, 0x0f, 0x05, 0x00, 0x7d, 0xcf, 0xff, 0x5e, 0x04, 0x01, 0x10,
0x05, 0x2b, 0x10, 0x06, 0x29, 0x0f, 0x07, 0x00, 0xef, 0x51, 0x68, 0x5e,
0x06, 0x01, 0x10, 0x07, 0x2c, 0x10, 0x08, 0x29, 0x0f, 0x09, 0x00, 0xaa,
0xaa, 0xaa, 0x10, 0x0a, 0x2d, 0x13, 0x0b, 0x5e, 0x08, 0x02, 0x10, 0x09,
0x2e, 0x10, 0x0a, 0x29, 0x0f, 0x0b, 0x00, 0xaa, 0xd9, 0x4c, 0x5e, 0x0a,
0x01, 0x10, 0x0b, 0x2f, 0x10, 0x0c, 0x29, 0x0f, 0x0d, 0x00, 0x7d, 0xcf,
0xff, 0x5e, 0x0c, 0x01, 0x10, 0x0d, 0x30, 0x10, 0x0e, 0x29, 0x0f, 0x0f,
0x00, 0x7d, 0xcf, 0xff, 0x5e, 0x0e, 0x01, 0x10, 0x0f, 0x31, 0x10, 0x10,
0x29, 0x0f, 0x11, 0x00, 0xd2, 0xa6, 0xff, 0x5e, 0x10, 0x01, 0x10, 0x11,
0x32, 0x10, 0x12, 0x29, 0x0f, 0x13, 0x00, 0xe6, 0xc0, 0x8a, 0x5e, 0x12,
0x01, 0x10, 0x13, 0x33, 0x10, 0x14, 0x29, 0x0f, 0x15, 0x00, 0x7a, 0xe9,
0x3c, 0x5e, 0x14, 0x01, 0x10, 0x15, 0x34, 0x10, 0x16, 0x29, 0x0f, 0x17,
0x00, 0xef, 0x51, 0x68, 0x5e, 0x16, 0x01, 0x10, 0x17, 0x35, 0x10, 0x18,
0x29, 0x0f, 0x19, 0x00, 0xff, 0xaf, 0x70, 0x5e, 0x18, 0x01, 0x10, 0x19,
0x36, 0x10, 0x1a, 0x29, 0x0f, 0x1b, 0x00, 0xff, 0x8f, 0x40, 0x5e, 0x1a,
0x01, 0x10, 0x1b, 0x37, 0x10, 0x1c, 0x29, 0x0f, 0x1d, 0x00, 0xf0, 0x71,
0x78, 0x5e, 0x1c, 0x01, 0x10, 0x1d, 0x38, 0x10, 0x1e, 0x29, 0x0f, 0x1f,
0x00, 0xff, 0xff, 0xff, 0x10, 0x20, 0x2d, 0x13, 0x21, 0x5e, 0x1e, 0x02,
0x10, 0x1f, 0x39, 0x10, 0x20, 0x29, 0x0f, 0x21, 0x00, 0xff, 0xaf, 0x70,
0x5e, 0x20, 0x01, 0x10, 0x21, 0x3a, 0x10, 0x22, 0x29, 0x0f, 0x23, 0x00,
0xf0, 0x71, 0x78, 0x5e, 0x22, 0x01, 0x10, 0x23, 0x3b, 0x10, 0x24, 0x29,
0x0f, 0x25, 0x00, 0x7d, 0xcf, 0xff, 0x5e, 0x24, 0x01, 0x10, 0x25, 0x3c,
0x10, 0x26, 0x29, 0x0f, 0x27, 0x00, 0x95, 0xe6, 0xcb, 0x5e, 0x26, 0x01,
0x10, 0x27, 0x3d, 0x10, 0x28, 0x29, 0x0f, 0x29, 0x00, 0xf0, 0x71, 0x78,
0x5e, 0x28, 0x01, 0x10, 0x29, 0x3e, 0x10, 0x2a, 0x29, 0x0f, 0x2b, 0x00,
0x7d, 0xcf, 0xff, 0x5e, 0x2a, 0x01, 0x10, 0x2b, 0x3f, 0x10, 0x2c, 0x29,
0x0f, 0x2d, 0x00, 0xff, 0x8f, 0x40, 0x5e, 0x2c, 0x01, 0x10, 0x2d, 0x40,
0x10, 0x2e, 0x29, 0x0f, 0x2f, 0x00, 0xd2, 0xa6, 0xff, 0x5e, 0x2e, 0x01,
0x10, 0x2f, 0x41, 0x10, 0x30, 0x29, 0x0f, 0x31, 0x00, 0xd2, 0xa6, 0xff,
0x5e, 0x30, 0x01, 0x10, 0x31, 0x42, 0x10, 0x32, 0x29, 0x0f, 0x33, 0x00,
0xff, 0xaf, 0xaf, 0x5e, 0x32, 0x01, 0x10, 0x33, 0x43, 0x10, 0x34, 0x29,
0x0f, 0x35, 0x00, 0xff, 0xff, 0x00, 0x5e, 0x34, 0x01, 0x10, 0x35, 0x44,
0x10, 0x36, 0x29, 0x0f, 0x37, 0x00, 0x0f, 0xff, 0x0f, 0x5e, 0x36, 0x01,
0x10, 0x37, 0x45, 0x10, 0x38, 0x29, 0x0f, 0x39, 0x00, 0xff, 0x0f, 0x0f,
0x5e, 0x38, 0x01, 0x5e, 0x01, 0x1c, 0x1a, 0x01, 0x46, 0x10, 0x01, 0x47,
0x1a, 0x01, 0x48, 0x5e, 0x01, 0x00, 0x1a, 0x01, 0x49, 0x5e, 0x01, 0x00,
0x1a, 0x01, 0x4a, 0x5e, 0x01, 0x00, 0x1a, 0x01, 0x4b, 0x11, 0x01, 0x1a,
0x01, 0x4c, 0x11, 0x01, 0x1a, 0x01, 0x4d, 0x62, 0x02, 0x00, 0x31, 0x01,
0x4e, 0x00, 0x1a, 0x01, 0x4f, 0x62, 0x02, 0x01, 0x31, 0x01, 0x4e, 0x00,
0x1a, 0x01, 0x50, 0x62, 0x02, 0x02, 0x31, 0x01, 0x4e, 0x00, 0x1a, 0x01,
0x51, 0x62, 0x02, 0x03, 0x31, 0x01, 0x4e, 0x00, 0x1a, 0x01, 0x52, 0x12,
0x01, 0x6f, 0x01, 0x69, 0x01, 0x04, 0x3d, 0x01, 0x00, 0x6f, 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, 0x00, 0x05, 0xf3,
0xb0, 0x88, 0x9a, 0x20, 0x00, 0x00, 0x53, 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, 0x07, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74,
0x00, 0x00, 0x0a, 0x40, 0x6c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65,
0x73, 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, 0x04, 0x70, 0x72, 0x6f, 0x63, 0x00, 0x00, 0x06, 0x40, 0x62,
0x5f, 0x62, 0x61, 0x72, 0x00, 0x00, 0x07, 0x40, 0x62, 0x5f, 0x63, 0x6f,
0x70, 0x79, 0x00, 0x00, 0x08, 0x40, 0x62, 0x5f, 0x70, 0x61, 0x73, 0x74,
0x65, 0x00, 0x00, 0x0e, 0x40, 0x62, 0x5f, 0x66, 0x69, 0x6c, 0x65, 0x5f,
0x64, 0x65, 0x74, 0x65, 0x63, 0x74, 0x00, 0x00, 0x00, 0x03, 0xc6, 0x00,
0x09, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x8d, 0x39,
0x04, 0x00, 0x00, 0x0f, 0x03, 0x00, 0x82, 0xaa, 0xff, 0x5c, 0x04, 0x00,
0x01, 0x09, 0x01, 0x10, 0x0a, 0x00, 0x23, 0x09, 0x10, 0x0a, 0x01, 0x01,
0x0b, 0x09, 0x32, 0x0a, 0x02, 0x01, 0x27, 0x0a, 0x00, 0x03, 0x26, 0x00,
0x0c, 0x0f, 0x03, 0x00, 0x82, 0xaa, 0xff, 0x5c, 0x04, 0x01, 0x26, 0x00,
0x74, 0x10, 0x0a, 0x03, 0x01, 0x0b, 0x09, 0x32, 0x0a, 0x02, 0x01, 0x27,
0x0a, 0x00, 0x03, 0x26, 0x00, 0x0c, 0x0f, 0x03, 0x00, 0xff, 0x8f, 0x40,
0x5c, 0x04, 0x02, 0x26, 0x00, 0x57, 0x10, 0x0a, 0x04, 0x01, 0x0b, 0x09,
0x32, 0x0a, 0x02, 0x01, 0x27, 0x0a, 0x00, 0x03, 0x26, 0x00, 0x0c, 0x0f,
0x03, 0x00, 0x9a, 0xde, 0x7a, 0x5c, 0x04, 0x03, 0x26, 0x00, 0x3a, 0x10,
0x0a, 0x05, 0x01, 0x0b, 0x09, 0x32, 0x0a, 0x02, 0x01, 0x27, 0x0a, 0x00,
0x03, 0x26, 0x00, 0x0c, 0x0f, 0x03, 0x00, 0xff, 0xd7, 0x00, 0x5c, 0x04,
0x04, 0x26, 0x00, 0x1d, 0x10, 0x0a, 0x06, 0x01, 0x0b, 0x09, 0x32, 0x0a,
0x02, 0x01, 0x27, 0x0a, 0x00, 0x03, 0x26, 0x00, 0x0c, 0x0f, 0x03, 0x00,
0xf2, 0x9c, 0xc3, 0x5c, 0x04, 0x05, 0x26, 0x00, 0x00, 0x1d, 0x09, 0x07,
0x33, 0x09, 0x08, 0x10, 0x0a, 0x09, 0x23, 0x09, 0x01, 0x05, 0x09, 0x5c,
0x06, 0x06, 0x01, 0x09, 0x01, 0x10, 0x0a, 0x0a, 0x23, 0x09, 0x06, 0x0a,
0x23, 0x09, 0x5c, 0x0a, 0x07, 0x4d, 0x09, 0x28, 0x09, 0x00, 0x73, 0x01,
0x09, 0x01, 0x10, 0x0a, 0x0a, 0x23, 0x09, 0x08, 0x0a, 0x23, 0x09, 0x5c,
0x0a, 0x06, 0x32, 0x09, 0x0b, 0x01, 0x28, 0x09, 0x00, 0x17, 0x1d, 0x09,
0x07, 0x33, 0x09, 0x08, 0x01, 0x0a, 0x01, 0x10, 0x0b, 0x0a, 0x23, 0x0a,
0x08, 0x0b, 0x23, 0x0a, 0x23, 0x09, 0x01, 0x05, 0x09, 0x01, 0x09, 0x05,
0x29, 0x09, 0x00, 0x03, 0x26, 0x00, 0x0e, 0x1d, 0x09, 0x07, 0x33, 0x09,
0x08, 0x10, 0x0a, 0x09, 0x23, 0x09, 0x01, 0x05, 0x09, 0x01, 0x09, 0x01,
0x10, 0x0a, 0x0a, 0x23, 0x09, 0x07, 0x0a, 0x23, 0x09, 0x5c, 0x0a, 0x06,
0x32, 0x09, 0x0b, 0x01, 0x28, 0x09, 0x00, 0x16, 0x1d, 0x09, 0x0c, 0x01,
0x0a, 0x01, 0x10, 0x0b, 0x0a, 0x23, 0x0a, 0x07, 0x0b, 0x23, 0x0a, 0x32,
0x09, 0x0d, 0x01, 0x01, 0x06, 0x09, 0x5c, 0x09, 0x08, 0x01, 0x0a, 0x04,
0x5d, 0x09, 0x5c, 0x0a, 0x08, 0x5d, 0x09, 0x01, 0x0a, 0x01, 0x10, 0x0b,
0x00, 0x23, 0x0a, 0x33, 0x0a, 0x0e, 0x33, 0x0a, 0x0f, 0x5d, 0x09, 0x5c,
0x0a, 0x09, 0x5d, 0x09, 0x01, 0x0a, 0x05, 0x10, 0x0b, 0x10, 0x23, 0x0a,
0x5d, 0x09, 0x5c, 0x0a, 0x08, 0x5d, 0x09, 0x01, 0x0a, 0x06, 0x5d, 0x09,
0x5c, 0x0a, 0x0a, 0x5d, 0x09, 0x01, 0x07, 0x09, 0x52, 0x08, 0x00, 0x01,
0x09, 0x08, 0x10, 0x0a, 0x11, 0x0f, 0x0b, 0x00, 0x0b, 0x0e, 0x14, 0x10,
0x0c, 0x12, 0x01, 0x0d, 0x03, 0x10, 0x0e, 0x13, 0x08, 0x0f, 0x10, 0x10,
0x14, 0x06, 0x11, 0x10, 0x12, 0x15, 0x03, 0x13, 0x0a, 0x5e, 0x0a, 0x05,
0x32, 0x09, 0x16, 0x01, 0x01, 0x09, 0x08, 0x10, 0x0a, 0x11, 0x01, 0x0b,
0x03, 0x10, 0x0c, 0x12, 0x0f, 0x0d, 0x00, 0x33, 0x36, 0x3c, 0x10, 0x0e,
0x14, 0x03, 0x0f, 0x0a, 0x10, 0x10, 0x15, 0x07, 0x11, 0x5e, 0x0a, 0x04,
0x32, 0x09, 0x16, 0x01, 0x01, 0x09, 0x08, 0x10, 0x0a, 0x11, 0x0f, 0x0b,
0x00, 0x33, 0x36, 0x3c, 0x10, 0x0c, 0x12, 0x0f, 0x0d, 0x00, 0x24, 0x27,
0x2d, 0x10, 0x0e, 0x14, 0x03, 0x0f, 0x0b, 0x10, 0x10, 0x15, 0x07, 0x11,
0x5e, 0x0a, 0x04, 0x32, 0x09, 0x16, 0x01, 0x01, 0x09, 0x08, 0x10, 0x0a,
0x11, 0x01, 0x0b, 0x05, 0x10, 0x0c, 0x17, 0x23, 0x0b, 0x10, 0x0c, 0x12,
0x0f, 0x0d, 0x00, 0x24, 0x27, 0x2d, 0x10, 0x0e, 0x14, 0x03, 0x0f, 0x0d,
0x10, 0x10, 0x15, 0x08, 0x11, 0x5e, 0x0a, 0x04, 0x32, 0x09, 0x16, 0x01,
0x01, 0x09, 0x08, 0x10, 0x0a, 0x11, 0x0f, 0x0b, 0x00, 0xce, 0xd4, 0xdf,
0x10, 0x0c, 0x12, 0x0f, 0x0d, 0x00, 0x24, 0x27, 0x2d, 0x10, 0x0e, 0x14,
0x03, 0x0f, 0x0f, 0x10, 0x10, 0x15, 0x01, 0x11, 0x06, 0x33, 0x11, 0x15,
0x46, 0x11, 0x01, 0x5e, 0x0a, 0x04, 0x32, 0x09, 0x16, 0x01, 0x01, 0x09,
0x08, 0x10, 0x0a, 0x11, 0x0f, 0x0b, 0x00, 0x24, 0x27, 0x2d, 0x10, 0x0c,
0x12, 0x06, 0x0d, 0x10, 0x0e, 0x14, 0x03, 0x0f, 0x0f, 0x01, 0x10, 0x06,
0x33, 0x10, 0x15, 0x45, 0x0f, 0x46, 0x0f, 0x01, 0x10, 0x10, 0x15, 0x07,
0x11, 0x5e, 0x0a, 0x04, 0x32, 0x09, 0x16, 0x01, 0x10, 0x09, 0x18, 0x01,
0x0a, 0x07, 0x10, 0x0b, 0x19, 0x01, 0x0c, 0x08, 0x5e, 0x09, 0x02, 0x52,
0x09, 0x01, 0x3d, 0x09, 0x00, 0x0b, 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, 0x00, 0x00, 0x00, 0x00,
0x06, 0x65, 0x64, 0x69, 0x74, 0x6f, 0x72, 0x00, 0x00, 0x00, 0x01, 0x20,
0x00, 0x00, 0x00, 0x08, 0x20, 0xee, 0x82, 0xb4, 0xee, 0x82, 0xb4, 0x20,
0x00, 0x00, 0x00, 0x03, 0xee, 0x82, 0xb4, 0x00, 0x00, 0x1a, 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, 0x07, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x00, 0x00, 0x04,
0x64, 0x61, 0x74, 0x61, 0x00, 0x00, 0x02, 0x21, 0x3d, 0x00, 0x00, 0x04,
0x46, 0x69, 0x6c, 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, 0x00, 0x37, 0x00, 0x03, 0x00, 0x06, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x10, 0x39, 0x04, 0x00, 0x00, 0x1d, 0x03, 0x00,
0x01, 0x04, 0x01, 0x32, 0x03, 0x01, 0x01, 0x3d, 0x03, 0x00, 0x00, 0x00,
0x02, 0x00, 0x09, 0x43, 0x6c, 0x69, 0x70, 0x62, 0x6f, 0x61, 0x72, 0x64,
0x00, 0x00, 0x04, 0x63, 0x6f, 0x70, 0x79, 0x00, 0x00, 0x00, 0x00, 0x37,
0x00, 0x02, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f,
0x39, 0x00, 0x00, 0x00, 0x1d, 0x02, 0x00, 0x33, 0x02, 0x01, 0x52, 0x02,
0x01, 0x3d, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x09, 0x43, 0x6c, 0x69,
0x70, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x00, 0x00, 0x05, 0x70, 0x61, 0x73,
0x74, 0x65, 0x00, 0x00, 0x00, 0x04, 0x13, 0x00, 0x07, 0x00, 0x0b, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x80, 0x39, 0x04, 0x00, 0x00, 0x10,
0x03, 0x00, 0x1d, 0x07, 0x01, 0x01, 0x08, 0x01, 0x32, 0x07, 0x02, 0x01,
0x27, 0x07, 0x00, 0x08, 0x01, 0x07, 0x03, 0x52, 0x07, 0x01, 0x3d, 0x07,
0x1d, 0x07, 0x01, 0x01, 0x08, 0x01, 0x10, 0x09, 0x03, 0x34, 0x07, 0x04,
0x01, 0x33, 0x07, 0x05, 0x01, 0x04, 0x07, 0x01, 0x07, 0x04, 0x5c, 0x08,
0x00, 0x32, 0x07, 0x06, 0x01, 0x28, 0x07, 0x00, 0xde, 0x01, 0x07, 0x04,
0x08, 0x08, 0x11, 0x09, 0x64, 0x08, 0x23, 0x07, 0x33, 0x07, 0x07, 0x01,
0x05, 0x07, 0x01, 0x07, 0x05, 0x66, 0x08, 0x1f, 0x08, 0x08, 0x5c, 0x09,
0x01, 0x32, 0x08, 0x09, 0x01, 0x01, 0x09, 0x07, 0x32, 0x08, 0x0a, 0x01,
0x27, 0x08, 0x00, 0x1a, 0x66, 0x08, 0x1f, 0x08, 0x08, 0x5c, 0x09, 0x02,
0x32, 0x08, 0x09, 0x01, 0x01, 0x09, 0x07, 0x32, 0x08, 0x0a, 0x01, 0x27,
0x08, 0x00, 0x03, 0x26, 0x00, 0x06, 0x10, 0x08, 0x0b, 0x26, 0x00, 0x88,
0x66, 0x08, 0x1f, 0x08, 0x08, 0x5c, 0x09, 0x03, 0x32, 0x08, 0x09, 0x01,
0x01, 0x09, 0x07, 0x32, 0x08, 0x0a, 0x01, 0x27, 0x08, 0x00, 0x03, 0x26,
0x00, 0x06, 0x10, 0x08, 0x0c, 0x26, 0x00, 0x68, 0x66, 0x08, 0x1f, 0x08,
0x08, 0x5c, 0x09, 0x04, 0x32, 0x08, 0x09, 0x01, 0x01, 0x09, 0x07, 0x32,
0x08, 0x0a, 0x01, 0x27, 0x08, 0x00, 0x03, 0x26, 0x00, 0x06, 0x10, 0x08,
0x0d, 0x26, 0x00, 0x48, 0x66, 0x08, 0x1f, 0x08, 0x08, 0x5c, 0x09, 0x05,
0x32, 0x08, 0x09, 0x01, 0x01, 0x09, 0x07, 0x32, 0x08, 0x0a, 0x01, 0x27,
0x08, 0x00, 0x03, 0x26, 0x00, 0x06, 0x10, 0x08, 0x0e, 0x26, 0x00, 0x28,
0x66, 0x08, 0x1f, 0x08, 0x08, 0x5c, 0x09, 0x06, 0x32, 0x08, 0x09, 0x01,
0x01, 0x09, 0x07, 0x32, 0x08, 0x0a, 0x01, 0x27, 0x08, 0x00, 0x03, 0x26,
0x00, 0x06, 0x10, 0x08, 0x0f, 0x26, 0x00, 0x08, 0x10, 0x08, 0x00, 0x26,
0x00, 0x02, 0x11, 0x08, 0x01, 0x03, 0x08, 0x01, 0x07, 0x03, 0x52, 0x07,
0x01, 0x3d, 0x07, 0x10, 0x07, 0x10, 0x10, 0x08, 0x10, 0x32, 0x07, 0x11,
0x01, 0x27, 0x07, 0x00, 0x0a, 0x10, 0x07, 0x10, 0x10, 0x08, 0x12, 0x32,
0x07, 0x11, 0x01, 0x28, 0x07, 0x00, 0x08, 0x01, 0x07, 0x03, 0x52, 0x07,
0x01, 0x3d, 0x07, 0x5c, 0x08, 0x07, 0x2f, 0x07, 0x13, 0x01, 0x33, 0x07,
0x14, 0x28, 0x07, 0x00, 0x08, 0x01, 0x07, 0x03, 0x52, 0x07, 0x01, 0x3d,
0x07, 0x12, 0x07, 0x5c, 0x08, 0x08, 0x01, 0x09, 0x01, 0x5d, 0x08, 0x2f,
0x07, 0x16, 0x01, 0x33, 0x07, 0x05, 0x01, 0x06, 0x07, 0x01, 0x07, 0x06,
0x66, 0x08, 0x1f, 0x08, 0x08, 0x5c, 0x09, 0x09, 0x32, 0x08, 0x09, 0x01,
0x01, 0x09, 0x07, 0x32, 0x08, 0x0a, 0x01, 0x27, 0x08, 0x00, 0x03, 0x26,
0x00, 0x06, 0x10, 0x08, 0x0b, 0x26, 0x00, 0xe8, 0x66, 0x08, 0x1f, 0x08,
0x08, 0x5c, 0x09, 0x05, 0x32, 0x08, 0x09, 0x01, 0x01, 0x09, 0x07, 0x32,
0x08, 0x0a, 0x01, 0x27, 0x08, 0x00, 0x03, 0x26, 0x00, 0x06, 0x10, 0x08,
0x0e, 0x26, 0x00, 0xc8, 0x66, 0x08, 0x1f, 0x08, 0x08, 0x5c, 0x09, 0x0a,
0x32, 0x08, 0x09, 0x01, 0x01, 0x09, 0x07, 0x32, 0x08, 0x0a, 0x01, 0x27,
0x08, 0x00, 0x03, 0x26, 0x00, 0x06, 0x10, 0x08, 0x17, 0x26, 0x00, 0xa8,
0x66, 0x08, 0x1f, 0x08, 0x08, 0x5c, 0x09, 0x0b, 0x32, 0x08, 0x09, 0x01,
0x01, 0x09, 0x07, 0x32, 0x08, 0x0a, 0x01, 0x27, 0x08, 0x00, 0x03, 0x26,
0x00, 0x06, 0x10, 0x08, 0x18, 0x26, 0x00, 0x88, 0x66, 0x08, 0x1f, 0x08,
0x08, 0x5c, 0x09, 0x04, 0x32, 0x08, 0x09, 0x01, 0x01, 0x09, 0x07, 0x32,
0x08, 0x0a, 0x01, 0x27, 0x08, 0x00, 0x03, 0x26, 0x00, 0x06, 0x10, 0x08,
0x0d, 0x26, 0x00, 0x68, 0x66, 0x08, 0x1f, 0x08, 0x08, 0x5c, 0x09, 0x0c,
0x32, 0x08, 0x09, 0x01, 0x01, 0x09, 0x07, 0x32, 0x08, 0x0a, 0x01, 0x27,
0x08, 0x00, 0x03, 0x26, 0x00, 0x06, 0x10, 0x08, 0x19, 0x26, 0x00, 0x48,
0x66, 0x08, 0x1f, 0x08, 0x08, 0x5c, 0x09, 0x0d, 0x32, 0x08, 0x09, 0x01,
0x01, 0x09, 0x07, 0x32, 0x08, 0x0a, 0x01, 0x27, 0x08, 0x00, 0x03, 0x26,
0x00, 0x06, 0x10, 0x08, 0x1a, 0x26, 0x00, 0x28, 0x66, 0x08, 0x1f, 0x08,
0x08, 0x5c, 0x09, 0x0e, 0x32, 0x08, 0x09, 0x01, 0x01, 0x09, 0x07, 0x32,
0x08, 0x0a, 0x01, 0x27, 0x08, 0x00, 0x03, 0x26, 0x00, 0x06, 0x10, 0x08,
0x1b, 0x26, 0x00, 0x08, 0x10, 0x08, 0x00, 0x26, 0x00, 0x02, 0x11, 0x08,
0x01, 0x03, 0x08, 0x01, 0x07, 0x03, 0x52, 0x07, 0x01, 0x3d, 0x07, 0x00,
0x0f, 0x00, 0x00, 0x02, 0x23, 0x21, 0x00, 0x00, 0x00, 0x04, 0x62, 0x61,
0x73, 0x68, 0x00, 0x00, 0x00, 0x02, 0x73, 0x68, 0x00, 0x00, 0x00, 0x04,
0x66, 0x69, 0x73, 0x68, 0x00, 0x00, 0x00, 0x06, 0x70, 0x79, 0x74, 0x68,
0x6f, 0x6e, 0x00, 0x00, 0x00, 0x04, 0x72, 0x75, 0x62, 0x79, 0x00, 0x00,
0x00, 0x03, 0x6c, 0x75, 0x61, 0x00, 0x00, 0x00, 0x04, 0x66, 0x69, 0x6c,
0x65, 0x00, 0x00, 0x00, 0x14, 0x66, 0x69, 0x6c, 0x65, 0x20, 0x2d, 0x2d,
0x6d, 0x69, 0x6d, 0x65, 0x2d, 0x74, 0x79, 0x70, 0x65, 0x20, 0x2d, 0x62,
0x20, 0x00, 0x00, 0x00, 0x0b, 0x73, 0x68, 0x65, 0x6c, 0x6c, 0x73, 0x63,
0x72, 0x69, 0x70, 0x74, 0x00, 0x00, 0x00, 0x04, 0x64, 0x69, 0x66, 0x66,
0x00, 0x00, 0x00, 0x04, 0x68, 0x74, 0x6d, 0x6c, 0x00, 0x00, 0x00, 0x0a,
0x6a, 0x61, 0x76, 0x61, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x00, 0x00,
0x00, 0x08, 0x6d, 0x61, 0x6b, 0x65, 0x66, 0x69, 0x6c, 0x65, 0x00, 0x00,
0x00, 0x03, 0x2d, 0x63, 0x24, 0x00, 0x00, 0x1c, 0x00, 0x07, 0x64, 0x65,
0x66, 0x61, 0x75, 0x6c, 0x74, 0x00, 0x00, 0x04, 0x46, 0x69, 0x6c, 0x65,
0x00, 0x00, 0x06, 0x65, 0x78, 0x69, 0x73, 0x74, 0x3f, 0x00, 0x00, 0x08,
0x72, 0x65, 0x61, 0x64, 0x6c, 0x69, 0x6e, 0x65, 0x00, 0x00, 0x04, 0x6f,
0x70, 0x65, 0x6e, 0x00, 0x00, 0x05, 0x63, 0x68, 0x6f, 0x6d, 0x70, 0x00,
0x00, 0x0b, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x77, 0x69, 0x74, 0x68,
0x3f, 0x00, 0x00, 0x08, 0x64, 0x6f, 0x77, 0x6e, 0x63, 0x61, 0x73, 0x65,
0x00, 0x00, 0x06, 0x52, 0x65, 0x67, 0x65, 0x78, 0x70, 0x00, 0x00, 0x07,
0x63, 0x6f, 0x6d, 0x70, 0x69, 0x6c, 0x65, 0x00, 0x00, 0x03, 0x3d, 0x3d,
0x3d, 0x00, 0x00, 0x04, 0x62, 0x61, 0x73, 0x68, 0x00, 0x00, 0x04, 0x66,
0x69, 0x73, 0x68, 0x00, 0x00, 0x06, 0x70, 0x79, 0x74, 0x68, 0x6f, 0x6e,
0x00, 0x00, 0x04, 0x72, 0x75, 0x62, 0x79, 0x00, 0x00, 0x03, 0x6c, 0x75,
0x61, 0x00, 0x00, 0x05, 0x6c, 0x69, 0x6e, 0x75, 0x78, 0x00, 0x00, 0x02,
0x21, 0x3d, 0x00, 0x00, 0x03, 0x6d, 0x61, 0x63, 0x00, 0x00, 0x0f, 0x63,
0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x5f, 0x65, 0x78, 0x69, 0x73, 0x74,
0x73, 0x3f, 0x00, 0x00, 0x01, 0x21, 0x00, 0x00, 0x06, 0x4b, 0x65, 0x72,
0x6e, 0x65, 0x6c, 0x00, 0x00, 0x01, 0x60, 0x00, 0x00, 0x04, 0x64, 0x69,
0x66, 0x66, 0x00, 0x00, 0x04, 0x68, 0x74, 0x6d, 0x6c, 0x00, 0x00, 0x0a,
0x6a, 0x61, 0x76, 0x61, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x00, 0x00,
0x08, 0x6d, 0x61, 0x6b, 0x65, 0x66, 0x69, 0x6c, 0x65, 0x00, 0x00, 0x01,
0x63, 0x00, 0x00, 0x00, 0x01, 0x6b, 0x00, 0x01, 0x00, 0x0a, 0x00, 0x08,
0x00, 0x00, 0x00, 0x00, 0x00, 0x4e, 0x10, 0x02, 0x00, 0x10, 0x03, 0x01,
0x10, 0x04, 0x02, 0x10, 0x05, 0x03, 0x10, 0x06, 0x04, 0x2f, 0x01, 0x05,
0x05, 0x10, 0x02, 0x06, 0x10, 0x03, 0x07, 0x10, 0x04, 0x08, 0x10, 0x05,
0x09, 0x10, 0x06, 0x0a, 0x10, 0x07, 0x0b, 0x10, 0x08, 0x0c, 0x2f, 0x01,
0x0d, 0x07, 0x6b, 0x01, 0x0e, 0x00, 0x6b, 0x01, 0x0f, 0x01, 0x6b, 0x01,
0x10, 0x02, 0x6b, 0x01, 0x11, 0x03, 0x6b, 0x01, 0x12, 0x04, 0x6b, 0x01,
0x13, 0x05, 0x6b, 0x01, 0x14, 0x06, 0x6b, 0x01, 0x15, 0x07, 0x3d, 0x01,
0x00, 0x00, 0x00, 0x16, 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, 0x06, 0x62, 0x5f, 0x63, 0x6f, 0x70,
0x79, 0x00, 0x00, 0x07, 0x62, 0x5f, 0x70, 0x61, 0x73, 0x74, 0x65, 0x00,
0x00, 0x0d, 0x62, 0x5f, 0x66, 0x69, 0x6c, 0x65, 0x5f, 0x64, 0x65, 0x74,
0x65, 0x63, 0x74, 0x00, 0x00, 0x0b, 0x61, 0x74, 0x74, 0x72, 0x5f, 0x72,
0x65, 0x61, 0x64, 0x65, 0x72, 0x00, 0x00, 0x04, 0x62, 0x61, 0x72, 0x3d,
0x00, 0x00, 0x07, 0x73, 0x74, 0x61, 0x72, 0x74, 0x75, 0x70, 0x00, 0x00,
0x08, 0x73, 0x68, 0x75, 0x74, 0x64, 0x6f, 0x77, 0x6e, 0x00, 0x00, 0x04,
0x63, 0x6f, 0x70, 0x79, 0x00, 0x00, 0x05, 0x70, 0x61, 0x73, 0x74, 0x65,
0x00, 0x00, 0x0b, 0x66, 0x69, 0x6c, 0x65, 0x5f, 0x64, 0x65, 0x74, 0x65,
0x63, 0x74, 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, 0x2c, 0x00, 0x03, 0x00,
0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x39, 0x00, 0x00,
0x01, 0x01, 0x02, 0x01, 0x01, 0x03, 0x02, 0x1a, 0x03, 0x00, 0x3d, 0x03,
0x00, 0x00, 0x00, 0x01, 0x00, 0x06, 0x40, 0x62, 0x5f, 0x62, 0x61, 0x72,
0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x03, 0x00, 0x04, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x0f, 0x39, 0x00, 0x00, 0x01, 0x01, 0x02, 0x01,
0x01, 0x03, 0x02, 0x1a, 0x03, 0x00, 0x3d, 0x03, 0x00, 0x00, 0x00, 0x01,
0x00, 0x0a, 0x40, 0x62, 0x5f, 0x73, 0x74, 0x61, 0x72, 0x74, 0x75, 0x70,
0x00, 0x00, 0x00, 0x00, 0x31, 0x00, 0x03, 0x00, 0x04, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x0f, 0x39, 0x00, 0x00, 0x01, 0x01, 0x02, 0x01,
0x01, 0x03, 0x02, 0x1a, 0x03, 0x00, 0x3d, 0x03, 0x00, 0x00, 0x00, 0x01,
0x00, 0x0b, 0x40, 0x62, 0x5f, 0x73, 0x68, 0x75, 0x74, 0x64, 0x6f, 0x77,
0x6e, 0x00, 0x00, 0x00, 0x00, 0x2d, 0x00, 0x03, 0x00, 0x04, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x39, 0x00, 0x00, 0x01, 0x01, 0x02,
0x01, 0x01, 0x03, 0x02, 0x1a, 0x03, 0x00, 0x3d, 0x03, 0x00, 0x00, 0x00,
0x01, 0x00, 0x07, 0x40, 0x62, 0x5f, 0x63, 0x6f, 0x70, 0x79, 0x00, 0x00,
0x00, 0x00, 0x2e, 0x00, 0x03, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x0f, 0x39, 0x00, 0x00, 0x01, 0x01, 0x02, 0x01, 0x01, 0x03,
0x02, 0x1a, 0x03, 0x00, 0x3d, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x08,
0x40, 0x62, 0x5f, 0x70, 0x61, 0x73, 0x74, 0x65, 0x00, 0x00, 0x00, 0x00,
0x34, 0x00, 0x03, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x0f, 0x39, 0x00, 0x00, 0x01, 0x01, 0x02, 0x01, 0x01, 0x03, 0x02, 0x1a,
0x03, 0x00, 0x3d, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x0e, 0x40, 0x62,
0x5f, 0x66, 0x69, 0x6c, 0x65, 0x5f, 0x64, 0x65, 0x74, 0x65, 0x63, 0x74,
0x00, 0x00, 0x00, 0x00, 0x39, 0x00, 0x03, 0x00, 0x04, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x0f, 0x39, 0x00, 0x00, 0x01, 0x01, 0x02, 0x01,
0x01, 0x03, 0x02, 0x1a, 0x03, 0x00, 0x3d, 0x03, 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, 0x08, 0x00, 0x0b, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00,
0x00, 0xc1, 0x39, 0x04, 0x40, 0x01, 0x26, 0x00, 0x06, 0x26, 0x00, 0x05,
0x26, 0x00, 0x04, 0x11, 0x02, 0x11, 0x03, 0x01, 0x05, 0x04, 0x01, 0x08,
0x01, 0x1d, 0x09, 0x00, 0x32, 0x08, 0x01, 0x01, 0x27, 0x08, 0x00, 0x07,
0x01, 0x08, 0x01, 0x53, 0x01, 0x08, 0x01, 0x01, 0x08, 0x02, 0x29, 0x08,
0x00, 0x03, 0x26, 0x00, 0x31, 0x12, 0x06, 0x1d, 0x08, 0x02, 0x33, 0x08,
0x03, 0x01, 0x07, 0x08, 0x01, 0x08, 0x07, 0x10, 0x09, 0x04, 0x62, 0x0a,
0x00, 0x34, 0x08, 0x05, 0x01, 0x30, 0x08, 0x06, 0x28, 0x08, 0x00, 0x0d,
0x01, 0x08, 0x07, 0x01, 0x09, 0x05, 0x34, 0x08, 0x07, 0x00, 0x26, 0x00,
0x02, 0x11, 0x08, 0x26, 0x00, 0x5b, 0x30, 0x08, 0x06, 0x28, 0x08, 0x00,
0x22, 0x01, 0x08, 0x02, 0x1d, 0x09, 0x00, 0x32, 0x08, 0x01, 0x01, 0x27,
0x08, 0x00, 0x07, 0x01, 0x08, 0x02, 0x53, 0x02, 0x08, 0x01, 0x01, 0x08,
0x01, 0x62, 0x09, 0x01, 0x34, 0x08, 0x08, 0x00, 0x26, 0x00, 0x32, 0x01,
0x08, 0x03, 0x1d, 0x09, 0x09, 0x32, 0x08, 0x01, 0x01, 0x28, 0x08, 0x00,
0x22, 0x01, 0x08, 0x02, 0x1d, 0x09, 0x00, 0x32, 0x08, 0x01, 0x01, 0x27,
0x08, 0x00, 0x07, 0x01, 0x08, 0x02, 0x53, 0x02, 0x08, 0x01, 0x01, 0x08,
0x01, 0x62, 0x09, 0x02, 0x34, 0x08, 0x08, 0x00, 0x26, 0x00, 0x02, 0x11,
0x08, 0x3d, 0x08, 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,
0x41, 0x00, 0x05, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x26, 0x39, 0x04, 0x20, 0x01, 0x26, 0x00, 0x03, 0x26, 0x00, 0x02, 0x11,
0x02, 0x01, 0x04, 0x03, 0x21, 0x05, 0x06, 0x00, 0x21, 0x06, 0x01, 0x00,
0x01, 0x07, 0x01, 0x01, 0x08, 0x02, 0x01, 0x09, 0x04, 0x34, 0x05, 0x00,
0x03, 0x3d, 0x05, 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, 0x39, 0x04, 0x00, 0x00, 0x21, 0x03,
0x02, 0x00, 0x62, 0x04, 0x00, 0x34, 0x03, 0x00, 0x00, 0x3d, 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, 0x39, 0x04, 0x00, 0x00, 0x19, 0x03, 0x00, 0x21, 0x04, 0x01,
0x00, 0x01, 0x05, 0x03, 0x01, 0x06, 0x04, 0x32, 0x05, 0x01, 0x01, 0x27,
0x05, 0x00, 0x07, 0x5e, 0x05, 0x00, 0x32, 0x03, 0x02, 0x02, 0x19, 0x03,
0x00, 0x21, 0x04, 0x01, 0x00, 0x23, 0x03, 0x01, 0x04, 0x01, 0x01, 0x05,
0x03, 0x01, 0x06, 0x04, 0x32, 0x05, 0x01, 0x01, 0x27, 0x05, 0x00, 0x07,
0x52, 0x05, 0x00, 0x32, 0x03, 0x02, 0x02, 0x19, 0x03, 0x00, 0x21, 0x04,
0x01, 0x00, 0x23, 0x03, 0x01, 0x04, 0x01, 0x23, 0x03, 0x21, 0x04, 0x05,
0x01, 0x32, 0x03, 0x03, 0x01, 0x3d, 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, 0x39,
0x04, 0x00, 0x00, 0x21, 0x03, 0x02, 0x00, 0x62, 0x04, 0x00, 0x34, 0x03,
0x00, 0x00, 0x3d, 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, 0x39, 0x04, 0x00, 0x00, 0x19,
0x03, 0x00, 0x21, 0x04, 0x01, 0x00, 0x01, 0x05, 0x03, 0x01, 0x06, 0x04,
0x32, 0x05, 0x01, 0x01, 0x27, 0x05, 0x00, 0x07, 0x5e, 0x05, 0x00, 0x32,
0x03, 0x02, 0x02, 0x19, 0x03, 0x00, 0x21, 0x04, 0x01, 0x00, 0x23, 0x03,
0x01, 0x04, 0x01, 0x01, 0x05, 0x03, 0x01, 0x06, 0x04, 0x32, 0x05, 0x01,
0x01, 0x27, 0x05, 0x00, 0x07, 0x52, 0x05, 0x00, 0x32, 0x03, 0x02, 0x02,
0x19, 0x03, 0x00, 0x21, 0x04, 0x01, 0x00, 0x23, 0x03, 0x01, 0x04, 0x01,
0x23, 0x03, 0x21, 0x04, 0x03, 0x01, 0x32, 0x03, 0x03, 0x01, 0x3d, 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, 0x00, 0x00, 0x00,
0x38, 0x00, 0x01, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
0x0a, 0x6b, 0x01, 0x00, 0x00, 0x6b, 0x01, 0x01, 0x01, 0x3d, 0x01, 0x00,
0x00, 0x00, 0x02, 0x00, 0x10, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65,
0x5f, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x76, 0x65, 0x00, 0x00, 0x04,
0x6c, 0x6f, 0x61, 0x64, 0x00, 0x00, 0x00, 0x01, 0x07, 0x00, 0x05, 0x00,
0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7b, 0x39, 0x04, 0x20,
0x00, 0x26, 0x00, 0x03, 0x26, 0x00, 0x02, 0x11, 0x02, 0x01, 0x05, 0x01,
0x5c, 0x06, 0x00, 0x32, 0x05, 0x00, 0x01, 0x27, 0x05, 0x00, 0x0b, 0x01,
0x05, 0x01, 0x5c, 0x06, 0x00, 0x45, 0x05, 0x01, 0x01, 0x05, 0x1d, 0x05,
0x01, 0x01, 0x06, 0x01, 0x1d, 0x07, 0x01, 0x1d, 0x08, 0x02, 0x33, 0x08,
0x03, 0x32, 0x07, 0x04, 0x01, 0x32, 0x05, 0x05, 0x02, 0x01, 0x01, 0x05,
0x15, 0x05, 0x06, 0x01, 0x06, 0x01, 0x32, 0x05, 0x07, 0x01, 0x28, 0x05,
0x00, 0x01, 0x40, 0x15, 0x05, 0x06, 0x01, 0x06, 0x01, 0x32, 0x05, 0x08,
0x01, 0x1d, 0x05, 0x01, 0x01, 0x06, 0x01, 0x32, 0x05, 0x09, 0x01, 0x01,
0x04, 0x05, 0x01, 0x06, 0x04, 0x01, 0x07, 0x02, 0x27, 0x07, 0x00, 0x03,
0x15, 0x07, 0x0a, 0x01, 0x08, 0x01, 0x2f, 0x05, 0x0b, 0x03, 0x3d, 0x05,
0x00, 0x01, 0x00, 0x00, 0x03, 0x2e, 0x72, 0x62, 0x00, 0x00, 0x0c, 0x00,
0x09, 0x65, 0x6e, 0x64, 0x5f, 0x77, 0x69, 0x74, 0x68, 0x3f, 0x00, 0x00,
0x04, 0x46, 0x69, 0x6c, 0x65, 0x00, 0x00, 0x01, 0x43, 0x00, 0x00, 0x0b,
0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x66, 0x69, 0x6c, 0x65, 0x00,
0x00, 0x07, 0x64, 0x69, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x00, 0x00, 0x0b,
0x65, 0x78, 0x70, 0x61, 0x6e, 0x64, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x00,
0x00, 0x07, 0x24, 0x4c, 0x4f, 0x41, 0x44, 0x45, 0x44, 0x00, 0x00, 0x08,
0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x3f, 0x00, 0x00, 0x02, 0x3c,
0x3c, 0x00, 0x00, 0x04, 0x72, 0x65, 0x61, 0x64, 0x00, 0x00, 0x09, 0x24,
0x42, 0x49, 0x4e, 0x44, 0x5f, 0x54, 0x4f, 0x50, 0x00, 0x00, 0x04, 0x65,
0x76, 0x61, 0x6c, 0x00, 0x00, 0x00, 0x00, 0xd3, 0x00, 0x04, 0x00, 0x09,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x39, 0x04, 0x20, 0x00,
0x26, 0x00, 0x03, 0x26, 0x00, 0x02, 0x11, 0x02, 0x01, 0x04, 0x01, 0x5c,
0x05, 0x00, 0x32, 0x04, 0x00, 0x01, 0x27, 0x04, 0x00, 0x0b, 0x01, 0x04,
0x01, 0x5c, 0x05, 0x00, 0x45, 0x04, 0x01, 0x01, 0x04, 0x1d, 0x04, 0x01,
0x01, 0x05, 0x01, 0x1d, 0x06, 0x01, 0x1d, 0x07, 0x02, 0x33, 0x07, 0x03,
0x32, 0x06, 0x04, 0x01, 0x32, 0x04, 0x05, 0x02, 0x01, 0x01, 0x04, 0x15,
0x04, 0x06, 0x01, 0x05, 0x01, 0x32, 0x04, 0x07, 0x01, 0x01, 0x05, 0x01,
0x01, 0x06, 0x02, 0x2f, 0x04, 0x08, 0x02, 0x3d, 0x04, 0x00, 0x01, 0x00,
0x00, 0x03, 0x2e, 0x72, 0x62, 0x00, 0x00, 0x09, 0x00, 0x09, 0x65, 0x6e,
0x64, 0x5f, 0x77, 0x69, 0x74, 0x68, 0x3f, 0x00, 0x00, 0x04, 0x46, 0x69,
0x6c, 0x65, 0x00, 0x00, 0x01, 0x43, 0x00, 0x00, 0x0b, 0x63, 0x6f, 0x6e,
0x66, 0x69, 0x67, 0x5f, 0x66, 0x69, 0x6c, 0x65, 0x00, 0x00, 0x07, 0x64,
0x69, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x00, 0x00, 0x0b, 0x65, 0x78, 0x70,
0x61, 0x6e, 0x64, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x00, 0x00, 0x07, 0x24,
0x4c, 0x4f, 0x41, 0x44, 0x45, 0x44, 0x00, 0x00, 0x06, 0x64, 0x65, 0x6c,
0x65, 0x74, 0x65, 0x00, 0x00, 0x10, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72,
0x65, 0x5f, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x76, 0x65, 0x00, 0x4c,
0x56, 0x41, 0x52, 0x00, 0x00, 0x01, 0x78, 0x00, 0x00, 0x00, 0x1d, 0x00,
0x03, 0x63, 0x6d, 0x64, 0x00, 0x04, 0x74, 0x65, 0x78, 0x74, 0x00, 0x01,
0x66, 0x00, 0x07, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x64, 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, 0x04, 0x74, 0x79, 0x70, 0x65, 0x00, 0x0a, 0x66, 0x69, 0x72, 0x73,
0x74, 0x5f, 0x6c, 0x69, 0x6e, 0x65, 0x00, 0x07, 0x73, 0x68, 0x65, 0x62,
0x61, 0x6e, 0x67, 0x00, 0x08, 0x6d, 0x69, 0x6d, 0x65, 0x74, 0x79, 0x70,
0x65, 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, 0x04, 0x70, 0x61, 0x74, 0x68, 0x00, 0x04, 0x62,
0x69, 0x6e, 0x64, 0x00, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x00, 0x00, 0xff,
0xff, 0x00, 0x01, 0xff, 0xff, 0x00, 0x02, 0xff, 0xff, 0x00, 0x02, 0xff,
0xff, 0x00, 0x02, 0xff, 0xff, 0x00, 0x02, 0xff, 0xff, 0x00, 0x02, 0xff,
0xff, 0xff, 0xff, 0x00, 0x01, 0xff, 0xff, 0x00, 0x03, 0x00, 0x04, 0xff,
0xff, 0x00, 0x05, 0x00, 0x06, 0x00, 0x07, 0x00, 0x08, 0x00, 0x09, 0x00,
0x0a, 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0x00, 0x08, 0xff, 0xff, 0x00,
0x0b, 0x00, 0x0c, 0x00, 0x0d, 0x00, 0x0e, 0xff, 0xff, 0x00, 0x0f, 0xff,
0xff, 0x00, 0x0f, 0xff, 0xff, 0x00, 0x0f, 0xff, 0xff, 0x00, 0x0f, 0xff,
0xff, 0x00, 0x0f, 0xff, 0xff, 0x00, 0x0f, 0xff, 0xff, 0x00, 0x0f, 0x00,
0x10, 0x00, 0x11, 0x00, 0x12, 0xff, 0xff, 0x00, 0x0f, 0x00, 0x13, 0x00,
0x14, 0x00, 0x15, 0x00, 0x16, 0xff, 0xff, 0x00, 0x17, 0x00, 0x18, 0xff,
0xff, 0x00, 0x19, 0xff, 0xff, 0x00, 0x18, 0xff, 0xff, 0x00, 0x19, 0xff,
0xff, 0x00, 0x1a, 0x00, 0x1b, 0xff, 0xff, 0x00, 0x1c, 0x00, 0x1a, 0x00,
0x1b, 0xff, 0xff, 0x45, 0x4e, 0x44, 0x00, 0x00, 0x00, 0x00, 0x08
};
constexpr unsigned int _tmp___crib_precompiled_mrb_len = 11411;
-21
View File
@@ -1,21 +0,0 @@
#ifndef SCRIPTING_DECL_H
#define SCRIPTING_DECL_H
#include "syntax/decl.h"
#include "utils/utils.h"
extern std::unordered_map<std::string, std::pair<mrb_value, mrb_value>>
custom_highlighters;
void ruby_start();
void ruby_shutdown();
void load_theme();
void load_languages_info();
uint8_t read_line_endings();
void load_custom_highlighters();
mrb_value parse_custom(std::vector<Token> *tokens, mrb_value parser_block,
const char *line, uint32_t len, mrb_value state,
uint32_t c_line);
bool custom_compare(mrb_value match_block, mrb_value state1, mrb_value state2);
#endif
-530
View File
@@ -1,530 +0,0 @@
#pragma once
constexpr unsigned char _tmp___crib_precompiled_mrb[] = {
0x52, 0x49, 0x54, 0x45, 0x30, 0x33, 0x30, 0x30, 0x00, 0x00, 0x18, 0xa1,
0x4d, 0x41, 0x54, 0x5a, 0x30, 0x30, 0x30, 0x30, 0x49, 0x52, 0x45, 0x50,
0x00, 0x00, 0x18, 0x13, 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, 0x45, 0x00, 0x01, 0x00, 0x4c, 0x00, 0x01, 0x00,
0x00, 0x00, 0x00, 0x07, 0x65, 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, 0x12, 0x01, 0x62, 0x01, 0x5e, 0x01, 0x00,
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, 0x4e, 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, 0x00,
0x01, 0x10, 0x00, 0x01, 0x00, 0x08, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00,
0x00, 0x42, 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, 0x2d, 0x01, 0x09, 0x03, 0x63, 0x01,
0x58, 0x02, 0x00, 0x5f, 0x01, 0x0a, 0x63, 0x01, 0x58, 0x02, 0x01, 0x5f,
0x01, 0x0b, 0x63, 0x01, 0x58, 0x02, 0x02, 0x5f, 0x01, 0x0c, 0x63, 0x01,
0x58, 0x02, 0x03, 0x5f, 0x01, 0x0d, 0x38, 0x01, 0x00, 0x00, 0x00, 0x0e,
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, 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, 0x72, 0x00,
0x00, 0x00, 0x0b, 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, 0x00, 0x00, 0x00, 0x00, 0x00,
0x01, 0x00, 0x02, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x05, 0x00,
0x06, 0x00, 0x07, 0x00, 0x08, 0x00, 0x09, 0xff, 0xff, 0x00, 0x0a, 0xff,
0xff, 0x00, 0x09, 0xff, 0xff, 0x00, 0x0a, 0xff, 0xff, 0x45, 0x4e, 0x44,
0x00, 0x00, 0x00, 0x00, 0x08
};
constexpr unsigned int _tmp___crib_precompiled_mrb_len = 6305;
+18 -7
View File
@@ -3,8 +3,11 @@
#include "io/knot.h"
#include "io/sysio.h"
#include "pch.h"
#include "syntax/trie.h"
#define MAX_LINES_LOOKAROUND 512
struct Highlight {
uint32_t fg{0xFFFFFF};
uint32_t bg{0x000000};
@@ -34,15 +37,23 @@ struct Token {
TokenKind type;
};
struct LineData {
std::shared_ptr<void> in_state{nullptr};
std::vector<Token> tokens;
std::shared_ptr<void> out_state{nullptr};
struct StateBase {
virtual ~StateBase() = default;
virtual std::unique_ptr<StateBase> clone() const = 0;
};
struct CustomState {
mrb_value state;
CustomState(mrb_value s) : state(s) {}
struct CustomState : StateBase {
std::string value;
explicit CustomState(std::string v) : value(std::move(v)) {}
std::unique_ptr<StateBase> clone() const override {
return std::make_unique<CustomState>(value);
}
};
struct LineData {
std::unique_ptr<StateBase> out_state;
std::vector<Token> tokens;
std::unique_ptr<StateBase> in_state;
};
#endif
+10 -21
View File
@@ -4,29 +4,19 @@
#include "syntax/decl.h"
#define DEF_LANG(name) \
std::shared_ptr<void> name##_parse( \
std::vector<Token> *tokens, std::shared_ptr<void> in_state, \
const char *text, uint32_t len, uint32_t line_num); \
bool name##_state_match(std::shared_ptr<void> state_1, \
std::shared_ptr<void> state_2);
std::unique_ptr<StateBase> name##_parse( \
std::vector<Token> *tokens, StateBase *in_state, const char *text, \
uint32_t len, uint32_t line_num); \
bool name##_state_match(StateBase *state_1, StateBase *state_2);
#define LANG_A(name) \
{ \
#name, { name##_parse, name##_state_match } \
}
template <typename T>
inline std::shared_ptr<T> ensure_state(std::shared_ptr<T> state) {
using U = typename T::full_state_type;
if (!state)
state = std::make_shared<T>();
if (!state.unique())
state = std::make_shared<T>(*state);
if (!state->full_state)
state->full_state = std::make_shared<U>();
else if (!state->full_state.unique())
state->full_state = std::make_shared<U>(*state->full_state);
return state;
template <typename B, typename A>
std::unique_ptr<B> static_unique_ptr_cast(std::unique_ptr<A> &&p) {
return std::unique_ptr<B>(static_cast<B *>(p.release()));
}
DEF_LANG(ruby);
@@ -34,11 +24,10 @@ DEF_LANG(bash);
inline static const std::unordered_map<
std::string,
std::tuple<std::shared_ptr<void> (*)(
std::vector<Token> *tokens, std::shared_ptr<void> in_state,
std::tuple<std::unique_ptr<StateBase> (*)(
std::vector<Token> *tokens, StateBase *in_state,
const char *text, uint32_t len, uint32_t line_num),
bool (*)(std::shared_ptr<void> state_1,
std::shared_ptr<void> state_2)>>
bool (*)(StateBase *state_1, StateBase *state_2)>>
parsers = {
LANG_A(ruby),
LANG_A(bash),
+136
View File
@@ -0,0 +1,136 @@
#ifndef LINE_MAP_H
#define LINE_MAP_H
#include "syntax/decl.h"
struct LineKey {
uint32_t line;
uint32_t version;
bool operator==(const LineKey &other) const {
return line == other.line && version == other.version;
}
};
struct LineKeyHash {
size_t operator()(const LineKey &key) const {
uint64_t combined = (uint64_t(key.line) << 32) | key.version;
return std::hash<uint64_t>()(combined);
}
};
struct EditDelta {
uint32_t start_line;
int64_t delta;
};
struct LineMap {
LineMap() : current_version(0) { edit_log.push_back({0, 0}); }
LineData *at(uint32_t line) {
auto key_opt = resolve_line(line);
if (!key_opt)
return nullptr;
LineKey key = *key_opt;
if (key.version == current_version)
return lines[key].get();
auto data_ptr = std::move(lines[key]);
lines.erase(key);
key = {line, current_version};
lines[key] = std::move(data_ptr);
return lines[key].get();
}
LineData *create_at(uint32_t line) {
auto key_opt = resolve_line(line);
LineKey key;
std::unique_ptr<LineData> data_ptr;
if (key_opt) {
key = *key_opt;
if (key.version == current_version)
return lines[key].get();
data_ptr = std::move(lines[key]);
lines.erase(key);
} else {
data_ptr = std::make_unique<LineData>();
}
key = {line, current_version};
lines[key] = std::move(data_ptr);
return lines[key].get();
}
void apply_edit(uint32_t start, int64_t delta) {
if (delta < 0)
batch_remove(start, -delta);
current_version++;
edit_log.push_back({start, delta});
}
private:
std::unordered_map<LineKey, std::unique_ptr<LineData>, LineKeyHash> lines;
std::vector<EditDelta> edit_log;
uint32_t current_version;
void batch_remove(uint32_t line, uint32_t count) {
std::vector<uint32_t> lines_t;
lines_t.reserve(count);
for (uint32_t i = 0; i < count; i++)
lines_t.push_back(line + i);
for (int64_t v = current_version; v >= 0; v--) {
for (auto &l : lines_t) {
if (l == UINT32_MAX)
continue;
LineKey key = {l, (uint32_t)v};
if (lines.find(key) != lines.end()) {
lines.erase(key);
l = UINT32_MAX;
}
}
bool all_removed = true;
const auto &edit = edit_log[v];
for (auto &l : lines_t) {
if (l == UINT32_MAX)
continue;
all_removed = false;
if (edit.delta > 0) {
if (l >= edit.start_line) {
if (l < edit.start_line + edit.delta)
l = UINT32_MAX;
else
l -= edit.delta;
}
} else {
if (l >= edit.start_line)
l -= edit.delta;
}
}
if (all_removed)
break;
}
return;
}
std::optional<LineKey> resolve_line(uint32_t line) {
uint32_t current_line = line;
for (int64_t v = current_version; v >= 0; v--) {
LineKey key = {current_line, (uint32_t)v};
if (lines.find(key) != lines.end())
return key;
const auto &edit = edit_log[v];
if (edit.delta > 0) {
if (current_line >= edit.start_line) {
if (current_line < edit.start_line + edit.delta)
return std::nullopt;
current_line -= edit.delta;
}
} else {
if (current_line >= edit.start_line)
current_line -= edit.delta;
}
}
return std::nullopt;
}
};
#endif
-245
View File
@@ -1,245 +0,0 @@
#ifndef LINE_TREE_H
#define LINE_TREE_H
#include "syntax/decl.h"
struct LineTree {
void clear() {
std::unique_lock lock(mtx);
clear_node(root);
root = nullptr;
stack_size = 0;
}
void build(uint32_t x) {
std::unique_lock lock(mtx);
root = build_node(x);
}
LineData *at(uint32_t x) {
std::shared_lock lock(mtx);
LineNode *n = root;
while (n) {
uint32_t left_size = n->left ? n->left->size : 0;
if (x < left_size) {
n = n->left;
} else if (x < left_size + n->data.size()) {
return &n->data[x - left_size];
} else {
x -= left_size + n->data.size();
n = n->right;
}
}
return nullptr;
}
LineData *start_iter(uint32_t x) {
std::shared_lock lock(mtx);
stack_size = 0;
LineNode *n = root;
while (n) {
uint32_t left_size = n->left ? n->left->size : 0;
if (x < left_size) {
push(n, 0);
n = n->left;
} else if (x < left_size + n->data.size()) {
push(n, x - left_size + 1);
return &n->data[x - left_size];
} else {
x -= left_size + n->data.size();
push(n, UINT32_MAX);
n = n->right;
}
}
return nullptr;
}
void end_iter() { stack_size = 0; }
LineData *next() {
std::shared_lock lock(mtx);
while (stack_size) {
auto &f = stack[stack_size - 1];
LineNode *n = f.node;
if (f.index < n->data.size())
return &n->data[f.index++];
stack_size--;
if (n->right) {
n = n->right;
while (n) {
push(n, 0);
if (!n->left)
break;
n = n->left;
}
return &stack[stack_size - 1].node->data[0];
}
}
return nullptr;
}
void insert(uint32_t x, uint32_t y) {
std::unique_lock lock(mtx);
if (x > subtree_size(root))
x = subtree_size(root);
root = insert_node(root, x, y);
}
void erase(uint32_t x, uint32_t y) {
std::unique_lock lock(mtx);
if (x + y > subtree_size(root))
x = subtree_size(root) - y;
root = erase_node(root, x, y);
}
uint32_t count() {
std::shared_lock lock(mtx);
return subtree_size(root);
}
~LineTree() { clear(); }
private:
struct LineNode {
LineNode *left = nullptr;
LineNode *right = nullptr;
uint8_t depth = 1;
uint32_t size = 0;
std::vector<LineData> data;
};
struct Frame {
LineNode *node;
uint32_t index;
};
void push(LineNode *n, uint32_t x) {
stack[stack_size].node = n;
stack[stack_size].index = x;
stack_size++;
}
static void clear_node(LineNode *n) {
if (!n)
return;
clear_node(n->left);
clear_node(n->right);
delete n;
}
LineNode *root = nullptr;
Frame stack[32];
std::atomic<uint8_t> stack_size = 0;
std::shared_mutex mtx;
static constexpr uint32_t LEAF_TARGET = 256;
LineTree::LineNode *erase_node(LineNode *n, uint32_t x, uint32_t y) {
if (!n || y == 0)
return n;
uint32_t left_sz = subtree_size(n->left);
uint32_t mid_sz = n->data.size();
if (x < left_sz) {
uint32_t len = std::min(y, left_sz - x);
n->left = erase_node(n->left, x, len);
y -= len;
x = left_sz;
}
if (y > 0 && x < left_sz + mid_sz) {
uint32_t mid_x = x - left_sz;
uint32_t len = std::min(y, mid_sz - mid_x);
n->data.erase(n->data.begin() + mid_x, n->data.begin() + mid_x + len);
y -= len;
x += len;
}
if (y > 0) {
n->right = erase_node(n->right, x - left_sz - n->data.size(), y);
}
if (n->left && n->right &&
subtree_size(n->left) + subtree_size(n->right) < 256) {
return merge(n->left, n->right);
}
return rebalance(n);
}
LineTree::LineNode *insert_node(LineNode *n, uint32_t x, uint32_t y) {
if (!n) {
auto *leaf = new LineNode();
leaf->data.resize(y);
leaf->size = y;
return leaf;
}
if (!n->left && !n->right) {
n->data.insert(n->data.begin() + x, y, LineData());
fix(n);
if (n->data.size() > 512)
return split_leaf(n);
return n;
}
uint32_t left_size = subtree_size(n->left);
if (x <= left_size)
n->left = insert_node(n->left, x, y);
else
n->right = insert_node(n->right, x - left_size - n->data.size(), y);
return rebalance(n);
}
LineNode *build_node(uint32_t count) {
if (count <= LEAF_TARGET) {
auto *n = new LineNode();
n->data.resize(count);
n->size = count;
return n;
}
uint32_t left_count = count / 2;
uint32_t right_count = count - left_count;
auto *n = new LineNode();
n->left = build_node(left_count);
n->right = build_node(right_count);
fix(n);
return n;
}
static LineNode *split_leaf(LineNode *n) {
auto *right = new LineNode();
size_t mid = n->data.size() / 2;
right->data.assign(n->data.begin() + mid, n->data.end());
n->data.resize(mid);
fix(n);
fix(right);
auto *parent = new LineNode();
parent->left = n;
parent->right = right;
fix(parent);
return parent;
}
static LineNode *merge(LineNode *a, LineNode *b) {
a->data.insert(a->data.end(), b->data.begin(), b->data.end());
delete b;
fix(a);
return a;
}
static void fix(LineNode *n) {
n->depth = 1 + MAX(height(n->left), height(n->right));
n->size = subtree_size(n->left) + n->data.size() + subtree_size(n->right);
}
static LineNode *rotate_right(LineNode *y) {
LineNode *x = y->left;
LineNode *T2 = x->right;
x->right = y;
y->left = T2;
fix(y);
fix(x);
return x;
}
static LineNode *rotate_left(LineNode *x) {
LineNode *y = x->right;
LineNode *T2 = y->left;
y->left = x;
x->right = T2;
fix(x);
fix(y);
return y;
}
static LineNode *rebalance(LineNode *n) {
fix(n);
int balance = int(height(n->left)) - int(height(n->right));
if (balance > 1) {
if (height(n->left->left) < height(n->left->right))
n->left = rotate_left(n->left);
return rotate_right(n);
}
if (balance < -1) {
if (height(n->right->right) < height(n->right->left))
n->right = rotate_right(n->right);
return rotate_left(n);
}
return n;
}
static uint8_t height(LineNode *n) { return n ? n->depth : 0; }
static uint32_t subtree_size(LineNode *n) { return n ? n->size : 0; }
};
#endif
+10 -14
View File
@@ -1,31 +1,27 @@
#ifndef SYNTAX_PARSER_H
#define SYNTAX_PARSER_H
#include "scripting/decl.h"
#include "ruby/decl.h"
#include "syntax/decl.h"
#include "syntax/line_tree.h"
#include "syntax/line_map.h"
struct Parser {
struct Editor *editor = nullptr;
std::string lang;
std::shared_ptr<void> (*parse_func)(std::vector<Token> *tokens,
std::shared_ptr<void> in_state,
const char *text, uint32_t len,
uint32_t line_num);
bool (*state_match_func)(std::shared_ptr<void> state_1,
std::shared_ptr<void> state_2);
std::unique_ptr<StateBase> (*parse_func)(std::vector<Token> *tokens,
StateBase *in_state,
const char *text, uint32_t len,
uint32_t line_num);
bool (*state_match_func)(StateBase *state_1, StateBase *state_2);
mrb_value parser_block = mrb_nil_value();
mrb_value match_block = mrb_nil_value();
bool is_custom{false};
std::atomic<uint32_t> scroll_max{UINT32_MAX - 2048};
std::atomic<uint32_t> scroll_max{0};
std::atomic<bool> scroll_dirty{false};
std::mutex mutex;
std::mutex data_mutex;
LineTree line_tree;
UniqueQueue<uint32_t> dirty_lines;
LineMap line_map = LineMap();
Parser(Editor *editor, std::string n_lang, uint32_t n_scroll_max);
void edit(uint32_t start_line, uint32_t old_end_line, uint32_t inserted_rows);
void edit(uint32_t start_line, uint32_t removed_rows, uint32_t inserted_rows);
void work();
void scroll(uint32_t line);
};
+5 -3
View File
@@ -8,11 +8,13 @@
struct Bar {
Coord screen;
std::string command = "";
std::string log_line = "";
uint32_t cursor = 0;
Bar(Coord screen) : screen(screen) {}
void render();
void handle(KeyEvent event);
void init(Coord screen) { this->screen = screen; }
void render(std::vector<ScreenCell> &buffer);
void handle_event(KeyEvent event);
void handle_command(std::string &command);
void log(std::string message);
};
-21
View File
@@ -1,21 +0,0 @@
#ifndef UI_COMPLETIONBOX_H
#define UI_COMPLETIONBOX_H
#include "io/sysio.h"
#include "pch.h"
#include "utils/utils.h"
struct CompletionBox {
std::shared_mutex mtx;
struct CompletionSession *session;
bool hidden = true;
std::vector<ScreenCell> cells;
Coord size;
Coord position;
CompletionBox(CompletionSession *s) : session(s) {}
void render_update();
void render(Coord pos);
};
#endif
-19
View File
@@ -1,19 +0,0 @@
#ifndef UI_DIAGNOSTICS_H
#define UI_DIAGNOSTICS_H
#include "editor/decl.h"
#include "io/sysio.h"
#include "pch.h"
#include "utils/utils.h"
struct DiagnosticBox {
std::vector<VWarn> warnings;
std::vector<ScreenCell> cells;
Coord size;
void clear();
void render_first();
void render(Coord pos);
};
#endif
-22
View File
@@ -1,22 +0,0 @@
#ifndef UI_HOVER_H
#define UI_HOVER_H
#include "editor/decl.h"
#include "io/sysio.h"
#include "pch.h"
#include "utils/utils.h"
struct HoverBox {
std::string text;
std::atomic<bool> is_markup;
uint32_t scroll_;
std::vector<ScreenCell> cells;
Coord size;
void clear();
void scroll(int32_t number);
void render_first(bool scroll = false);
void render(Coord pos);
};
#endif
+11 -7
View File
@@ -6,18 +6,19 @@
template <typename T> struct Queue {
void push(T val) {
std::lock_guard<std::mutex> lock(m);
q.push(val);
q.push(std::move(val));
}
std::optional<T> front() {
std::lock_guard<std::mutex> lock(m);
if (q.empty())
return std::nullopt;
return q.front();
return std::move(q.front());
}
bool pop(T &val) {
std::lock_guard<std::mutex> lock(m);
if (q.empty())
return false;
val = q.front();
val = std::move(q.front());
q.pop();
return true;
}
@@ -92,6 +93,11 @@ struct Coord {
bool operator>=(const Coord &other) const { return !(*this < other); }
};
static inline bool inside(Coord c, Coord pos, Coord size) {
return c.row >= pos.row && c.col >= pos.col && c.row - pos.row < size.row &&
c.col - pos.col < size.col;
}
struct Match {
size_t start;
size_t end;
@@ -102,7 +108,6 @@ struct Language {
std::string name;
std::string lsp_name;
uint32_t color;
std::string symbol = "󱓧 ";
};
struct LSP {
@@ -119,6 +124,7 @@ extern std::unordered_map<std::string, LSP> lsps;
#define ABS(x) ((x) < 0 ? -(x) : (x))
#define UNUSED(x) (void)(x)
#define USING(x) UNUSED(sizeof(x))
#define CTRL(x) ((x) & 0x1f)
inline uint32_t HEX(const std::string &s) {
if (s.empty())
@@ -133,6 +139,7 @@ std::string percent_encode(const std::string &s);
std::string percent_decode(const std::string &s);
uint32_t count_clusters(const char *line, size_t len, size_t from, size_t to);
std::string trim(const std::string &s);
std::string strip_newlines(const std::string &s);
std::string substitute_fence(const std::string &documentation,
const std::string &lang);
@@ -156,9 +163,6 @@ std::string get_exe_dir();
char *load_file(const char *path, uint32_t *out_len, bool *out_eol);
Language language_for_file(const char *filename);
void copy_to_clipboard(const char *text, size_t len);
char *get_from_clipboard(uint32_t *out_len);
template <typename T>
inline T *safe_get(std::map<uint16_t, T> &m, uint16_t key) {
auto it = m.find(key);
+119
View File
@@ -0,0 +1,119 @@
#ifndef TILING_DECL_H
#define TILING_DECL_H
#include "io/sysio.h"
#include "utils/utils.h"
struct Tile {
bool hidden = false;
uint32_t weight = 100;
virtual void render(std::vector<ScreenCell> &buffer, Coord size,
Coord pos) = 0;
virtual void handle_click(KeyEvent event, Coord size) = 0;
virtual ~Tile() = default;
};
struct Window : Tile {
virtual ~Window() = default;
virtual void handle_event(KeyEvent){};
virtual void handle_command(std::string &) {};
virtual void work() {};
virtual std::array<std::string, 5> bar_info() { return {}; };
};
struct Popup : Window {
Coord pos;
Coord size;
virtual ~Popup() = default;
};
struct TileBlock : Tile {
bool vertical;
std::vector<std::unique_ptr<Tile>> tiles;
void render(std::vector<ScreenCell> &buffer, Coord size, Coord pos) override {
uint32_t total_weight = 0;
for (auto &t : tiles) {
if (!t->hidden)
total_weight += t->weight;
}
if (total_weight == 0)
return;
for (auto &t : tiles) {
if (t->hidden)
continue;
uint32_t proportion =
t->weight * (vertical ? size.row : size.col) / total_weight;
Coord tile_size = vertical ? Coord{.row = proportion, .col = size.col}
: Coord{.row = size.row, .col = proportion};
t->render(buffer, tile_size, pos);
if (vertical)
pos.row += tile_size.row;
else
pos.col += tile_size.col;
}
}
void handle_click(KeyEvent event, Coord size) override {
uint32_t total_weight = 0;
for (auto &t : tiles)
if (!t->hidden)
total_weight += t->weight;
if (total_weight == 0)
return;
uint32_t i = 0;
for (auto &t : tiles) {
if (t->hidden)
continue;
uint32_t proportion =
t->weight * (vertical ? size.row : size.col) / total_weight;
Coord tile_size = vertical ? Coord{.row = proportion, .col = size.col}
: Coord{.row = size.row, .col = proportion};
if (vertical) {
if (event.mouse_y < i + proportion) {
event.mouse_y -= i;
t->handle_click(event, tile_size);
return;
}
} else {
if (event.mouse_x < i + proportion) {
event.mouse_x -= i;
t->handle_click(event, tile_size);
return;
}
}
i += proportion;
}
}
};
struct TileBase {
std::unique_ptr<Tile> tile;
Coord pos;
Coord size;
inline bool hidden() { return this->tile->hidden; }
void render(std::vector<ScreenCell> &buffer) {
if (this->tile->hidden)
return;
this->tile->render(buffer, size, pos);
}
void handle_click(KeyEvent event) {
event.mouse_x -= this->pos.col;
event.mouse_y -= this->pos.row;
this->tile->handle_click(event, size);
}
};
namespace layout {
extern TileBase root_tile;
extern Window *focused_window;
extern std::vector<std::unique_ptr<Popup>> popups;
extern std::vector<std::unique_ptr<TileBase>> floating_tiles;
} // namespace layout
void render();
void handle_click(KeyEvent event);
#endif
Regular → Executable
+2 -14
View File
@@ -4,21 +4,9 @@ set -eu
install() {
BINARY_NAME="crib"
VERSION="v0.0.1-alpha"
BIN_URL="https://git.syedm.dev/SyedM-dev/crib/releases/download/$VERSION/crib"
BIN_URL="https://git.syedm.dev/SyedM/crib/releases/download/v0.0.5-alpha/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]"
echo "Install or update locally (~/.local/bin) or globally (/usr/bin)? [l/g]"
read -r choice </dev/tty
case "$choice" in
l | L)
Vendored Submodule
+1
Submodule libs/json added at 3b0dd69928
Vendored Submodule
+1
Submodule libs/mruby added at 88b93f66c4
+1 -3
View File
@@ -22,15 +22,13 @@ colorize() {
}
# Example of error handling
handle_error() {
log ERROR "An error occurred on line $1"
}
trap 'handle_error $LINENO' ERR
trap 'handle_error $LINENO' ERR
# Multiline string test
read -r -d '' MULTI <<'CPP'
int main() {
}
+1 -1
View File
@@ -89,6 +89,7 @@ BASH
puts multi
# Arrays mixing everything
mixed = [
'🐍 Ruby + Python? sacrilege! 🐍',
@@ -338,6 +339,5 @@ puts 'Ruby syntax highlighting test complete.'
__END__
Anything here should be ignored >><<
{{{}}}[[[]]](((000)))
+47 -91
View File
@@ -1,83 +1,39 @@
#include "editor/editor.h"
void ensure_cursor(Editor *editor) {
std::shared_lock knot_lock(editor->knot_mtx);
if (editor->cursor < editor->scroll) {
editor->cursor.row = editor->scroll.row;
editor->cursor.col = editor->scroll.col;
editor->cursor_preffered = UINT32_MAX;
void Editor::ensure_cursor() {
if (this->cursor < this->scroll) {
this->cursor = this->scroll;
this->cursor_preffered = UINT32_MAX;
return;
}
uint32_t numlen =
EXTRA_META + static_cast<int>(std::log10(editor->root->line_count + 1));
uint32_t render_width = editor->size.col - numlen;
uint32_t visual_rows = 0;
uint32_t line_index = editor->scroll.row;
bool first_visual_line = true;
LineIterator *it = begin_l_iter(editor->root, line_index);
if (!it)
return;
Coord last_visible = editor->scroll;
while (true) {
if (visual_rows >= editor->size.row)
break;
uint32_t line_len;
char *line = next_line(it, &line_len);
if (!line)
break;
if (line_len > 0 && line[line_len - 1] == '\n')
line_len--;
uint32_t offset = first_visual_line ? editor->scroll.col : 0;
first_visual_line = false;
while (offset < line_len || (line_len == 0 && offset == 0)) {
Coord current = {line_index, offset};
last_visible = current;
visual_rows++;
if (visual_rows >= editor->size.row)
break;
uint32_t col = 0;
uint32_t advance = 0;
uint32_t left = line_len - offset;
while (left > 0 && col < render_width) {
uint32_t g =
grapheme_next_character_break_utf8(line + offset + advance, left);
int w = display_width(line + offset + advance, g);
if (col + w > render_width)
break;
advance += g;
left -= g;
col += w;
}
if (line_index == editor->cursor.row) {
if (editor->cursor.col >= offset &&
editor->cursor.col <= offset + advance) {
free(it->buffer);
free(it);
return;
}
}
if (advance == 0)
break;
offset += advance;
if (line_len == 0)
break;
}
line_index++;
EXTRA_META + static_cast<int>(std::log10(this->root->line_count + 1));
uint32_t render_width = this->size.col - numlen;
uint32_t render_height = 0;
VisualIterator vis(root, scroll, render_width);
std::pair<Coord, Coord> vline;
Coord last_visible = scroll;
while ((vline = vis.next()).first.row != UINT32_MAX &&
render_height < this->size.row) {
render_height++;
last_visible = vline.first;
log("Render H: %d, Cursor: %d,%d, Visible: %d,%d - %d,%d", render_height,
this->cursor.row, this->cursor.col, vline.first.row, vline.first.col,
vline.second.row, vline.second.col);
if (cursor >= vline.first && cursor <= vline.second)
return;
}
editor->cursor.row = last_visible.row;
editor->cursor.col = last_visible.col;
editor->cursor_preffered = UINT32_MAX;
free(it->buffer);
free(it);
cursor = last_visible;
cursor_preffered = UINT32_MAX;
this->cursor_preffered = UINT32_MAX;
}
void ensure_scroll(Editor *editor) {
std::shared_lock knot_lock(editor->knot_mtx);
void Editor::ensure_scroll() {
uint32_t numlen =
EXTRA_META + static_cast<int>(std::log10(editor->root->line_count + 1));
uint32_t render_width = editor->size.col - numlen;
if (editor->cursor < editor->scroll) {
LineIterator *it = begin_l_iter(editor->root, editor->cursor.row);
EXTRA_META + static_cast<int>(std::log10(this->root->line_count + 1));
uint32_t render_width = this->size.col - numlen;
if (this->cursor < this->scroll) {
LineIterator *it = begin_l_iter(this->root, this->cursor.row);
if (!it)
return;
uint32_t len;
@@ -98,9 +54,9 @@ void ensure_scroll(Editor *editor) {
int width = display_width(line + offset, inc);
if (cols + width > render_width) {
cols = 0;
if (editor->cursor.col > old_offset && editor->cursor.col <= offset) {
editor->scroll.row = editor->cursor.row;
editor->scroll.col = old_offset;
if (this->cursor.col > old_offset && this->cursor.col <= offset) {
this->scroll.row = this->cursor.row;
this->scroll.col = old_offset;
free(it->buffer);
free(it);
return;
@@ -112,14 +68,14 @@ void ensure_scroll(Editor *editor) {
}
free(it->buffer);
free(it);
editor->scroll.row = editor->cursor.row;
editor->scroll.col = (editor->cursor.col == 0) ? 0 : old_offset;
} else if (editor->cursor.row - editor->scroll.row < editor->size.row * 2) {
uint32_t line_index = editor->scroll.row;
LineIterator *it = begin_l_iter(editor->root, line_index);
this->scroll.row = this->cursor.row;
this->scroll.col = (this->cursor.col == 0) ? 0 : old_offset;
} else if (this->cursor.row - this->scroll.row < this->size.row * 2) {
uint32_t line_index = this->scroll.row;
LineIterator *it = begin_l_iter(this->root, line_index);
if (!it)
return;
uint32_t max_visual_lines = editor->size.row;
uint32_t max_visual_lines = this->size.row;
Coord *scroll_queue = (Coord *)malloc(sizeof(Coord) * max_visual_lines);
uint32_t q_head = 0;
uint32_t q_size = 0;
@@ -133,7 +89,7 @@ void ensure_scroll(Editor *editor) {
line_len--;
uint32_t current_byte_offset = 0;
if (first_visual_line) {
current_byte_offset += editor->scroll.col;
current_byte_offset += this->scroll.col;
first_visual_line = false;
}
while (current_byte_offset < line_len ||
@@ -160,16 +116,16 @@ void ensure_scroll(Editor *editor) {
line_left -= cluster_len;
col += width;
}
if (line_index == editor->cursor.row) {
if (line_index == this->cursor.row) {
bool cursor_found = false;
if (editor->cursor.col >= current_byte_offset &&
editor->cursor.col < current_byte_offset + local_render_offset)
if (this->cursor.col >= current_byte_offset &&
this->cursor.col < current_byte_offset + local_render_offset)
cursor_found = true;
else if (editor->cursor.col == line_len &&
else if (this->cursor.col == line_len &&
current_byte_offset + local_render_offset == line_len)
cursor_found = true;
if (cursor_found) {
editor->scroll = scroll_queue[q_head];
this->scroll = scroll_queue[q_head];
free(scroll_queue);
free(it->buffer);
free(it);
@@ -186,10 +142,10 @@ void ensure_scroll(Editor *editor) {
free(it->buffer);
free(it);
} else {
editor->scroll.row = (editor->cursor.row > editor->size.row * 1.5)
? editor->cursor.row - editor->size.row * 1.5
: 0;
editor->scroll.col = 0;
ensure_scroll(editor);
this->scroll.row = (this->cursor.row > this->size.row * 1.5)
? this->cursor.row - this->size.row * 1.5
: 0;
this->scroll.col = 0;
this->ensure_scroll();
}
}
+7 -13
View File
@@ -32,12 +32,9 @@ uint32_t scan_right(const char *line, uint32_t len, uint32_t off) {
return i;
}
void word_boundaries_exclusive(Editor *editor, Coord coord, uint32_t *prev_col,
uint32_t *next_col) {
if (!editor)
return;
std::shared_lock lock(editor->knot_mtx);
LineIterator *it = begin_l_iter(editor->root, coord.row);
void Editor::word_boundaries_exclusive(Coord coord, uint32_t *prev_col,
uint32_t *next_col) {
LineIterator *it = begin_l_iter(this->root, coord.row);
if (!it)
return;
uint32_t line_len;
@@ -85,13 +82,10 @@ uint32_t word_jump_left(const char *line, size_t len, uint32_t col) {
return static_cast<uint32_t>(last);
}
void word_boundaries(Editor *editor, Coord coord, uint32_t *prev_col,
uint32_t *next_col, uint32_t *prev_clusters,
uint32_t *next_clusters) {
if (!editor)
return;
std::shared_lock lock(editor->knot_mtx);
LineIterator *it = begin_l_iter(editor->root, coord.row);
void Editor::word_boundaries(Coord coord, uint32_t *prev_col,
uint32_t *next_col, uint32_t *prev_clusters,
uint32_t *next_clusters) {
LineIterator *it = begin_l_iter(this->root, coord.row);
if (!it)
return;
uint32_t line_len;
+10 -14
View File
@@ -1,23 +1,19 @@
#include "editor/editor.h"
#include "main.h"
Coord editor_hit_test(Editor *editor, uint32_t x, uint32_t y) {
if (mode == INSERT)
x++;
Coord Editor::click_coord(uint32_t x, uint32_t y) {
uint32_t numlen =
EXTRA_META + static_cast<int>(std::log10(editor->root->line_count + 1));
uint32_t render_width = editor->size.col - numlen;
x = MAX(x, numlen) - numlen;
EXTRA_META + static_cast<int>(std::log10(this->root->line_count + 1));
uint32_t render_width = this->size.col - numlen;
x = MAX(x, numlen) - numlen - 1;
uint32_t target_visual_row = y;
uint32_t visual_row = 0;
uint32_t line_index = editor->scroll.row;
uint32_t last_line_index = editor->scroll.row;
uint32_t last_col = editor->scroll.col;
uint32_t line_index = this->scroll.row;
uint32_t last_line_index = this->scroll.row;
uint32_t last_col = this->scroll.col;
bool first_visual_line = true;
std::shared_lock knot_lock(editor->knot_mtx);
LineIterator *it = begin_l_iter(editor->root, line_index);
LineIterator *it = begin_l_iter(this->root, line_index);
if (!it)
return editor->scroll;
return this->scroll;
while (visual_row <= target_visual_row) {
uint32_t line_len;
char *line = next_line(it, &line_len);
@@ -27,7 +23,7 @@ Coord editor_hit_test(Editor *editor, uint32_t x, uint32_t y) {
line_len--;
last_line_index = line_index;
last_col = line_len;
uint32_t offset = first_visual_line ? editor->scroll.col : 0;
uint32_t offset = first_visual_line ? this->scroll.col : 0;
first_visual_line = false;
while (offset < line_len || (line_len == 0 && offset == 0)) {
uint32_t col = 0;
+13
View File
@@ -0,0 +1,13 @@
#include "editor/editor.h"
#include "main.h"
void Editor::handle_command(std::string &command) {
if (command == "w") {
this->save();
}
if (command == "wq") {
this->save();
command = "q";
ui::bar.handle_command(command);
}
}
+105 -89
View File
@@ -1,9 +1,8 @@
#include "editor/decl.h"
#include "editor/editor.h"
/* #include "editor/editor.h"
#include "io/knot.h"
#include "io/sysio.h"
#include "lsp/lsp.h"
#include "main.h"
#include "ui/completionbox.h"
#include "utils/utils.h"
inline static std::string completion_prefix(Editor *editor) {
@@ -25,6 +24,23 @@ inline static std::string completion_prefix(Editor *editor) {
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) {
auto &session = editor->completion;
std::string prefix = completion_prefix(editor);
@@ -44,23 +60,22 @@ void completion_filter(Editor *editor) {
session.select) == session.visible.end())
session.select = session.visible[0];
session.box.hidden = false;
session.scroll = 0;
completion_adjust_scroll(session);
session.box.render_update();
}
void completion_request(Editor *editor) {
Coord hook = editor->cursor;
word_boundaries(editor, editor->cursor, &hook.col, nullptr, nullptr, nullptr);
editor->completion.hook = hook;
editor->completion.complete = false;
editor->completion.active = false;
editor->completion.items.clear();
editor->word_boundaries(editor->cursor, &hook.col, nullptr, nullptr,
nullptr); editor->completion.hook = hook; editor->completion.complete =
false; editor->completion.active = false; editor->completion.items.clear();
editor->completion.visible.clear();
editor->completion.select = 0;
editor->completion.version = editor->lsp_version;
LSPPending *pending = new LSPPending();
pending->editor = editor;
pending->method = "textDocument/completion";
pending->callback = [](Editor *editor, std::string, json message) {
pending->callback = [](Editor *editor, const json &message) {
auto &session = editor->completion;
std::unique_lock lock(session.mtx);
std::vector<json> items_json;
@@ -82,7 +97,8 @@ void completion_request(Editor *editor) {
return;
editor->completion.active = true;
session.complete = !list.value("isIncomplete", false);
if (list.contains("itemDefaults") && list["itemDefaults"].is_object()) {
if (list.contains("itemDefaults") &&
list["itemDefaults"].is_object()) {
auto &defs = list["itemDefaults"];
if (defs.contains("insertTextFormat") &&
defs["insertTextFormat"].is_number())
@@ -180,7 +196,7 @@ void completion_request(Editor *editor) {
edit.start = session.hook;
edit.end = editor->cursor;
}
utf8_normalize_edit(editor, &edit);
editor->utf8_normalize_edit(&edit);
item.edits.push_back(edit);
if (item_json.contains("additionalTextEdits")) {
for (auto &te : item_json["additionalTextEdits"]) {
@@ -190,7 +206,7 @@ void completion_request(Editor *editor) {
edit.start.col = te["range"]["start"]["character"];
edit.end.row = te["range"]["end"]["line"];
edit.end.col = te["range"]["end"]["character"];
utf8_normalize_edit(editor, &edit);
editor->utf8_normalize_edit(&edit);
item.edits.push_back(edit);
}
}
@@ -209,7 +225,6 @@ void completion_request(Editor *editor) {
session.box.hidden = false;
session.box.render_update();
};
std::shared_lock lock(editor->knot_mtx);
LineIterator *it = begin_l_iter(editor->root, hook.row);
uint32_t length;
char *line = next_line(it, &length);
@@ -221,7 +236,6 @@ void completion_request(Editor *editor) {
uint32_t col = utf8_offset_to_utf16(line, length, editor->cursor.col);
free(it->buffer);
free(it);
lock.unlock();
json message = {
{"jsonrpc", "2.0"},
{"method", "textDocument/completion"},
@@ -238,110 +252,111 @@ void completion_request(Editor *editor) {
lsp_send(editor->lsp, message, pending);
}
void handle_completion(Editor *editor, KeyEvent event) {
Move this into the box and merge the box and this guy
void CompletionSession::handle(KeyEvent event) {
if (!editor->lsp || !editor->lsp->allow_completion)
return;
if (mode != INSERT) {
editor->completion.active = false;
this->active = false;
return;
}
std::unique_lock lock(editor->completion.mtx);
std::unique_lock lock(this->mtx);
if (event.key_type == KEY_PASTE) {
editor->completion.active = false;
this->active = false;
return;
} else if (event.key_type == KEY_CHAR) {
char ch = *event.c;
if (!editor->completion.active) {
if (!this->active) {
for (char c : editor->lsp->trigger_chars)
if (c == ch) {
editor->completion.trigger = 2;
editor->completion.trigger_char = c;
this->trigger = 2;
this->trigger_char = c;
completion_request(editor);
return;
}
} else {
if (!editor->completion.items.empty()) {
const auto &item = editor->completion.items[editor->completion.select];
const std::vector<char> &end_chars =
const auto &item =
editor->completion.items[editor->completion.select]; const
std::vector<char> &end_chars =
item.end_chars.empty() ? editor->lsp->end_chars : item.end_chars;
for (char c : end_chars)
if (c == ch) {
complete_accept(editor);
this->accept();
return;
}
}
}
if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') ||
(ch >= '0' && ch <= '9') || ch == '_') {
if (editor->completion.active) {
if (editor->completion.complete)
if (this->active) {
if (this->complete)
completion_filter(editor);
else
completion_request(editor);
} else {
editor->completion.trigger = 3;
this->trigger = 3;
completion_request(editor);
}
} else if (ch == CTRL('\\')) {
if (editor->completion.active && !editor->completion.visible.empty()) {
complete_accept(editor);
if (this->active && !this->visible.empty()) {
this->accept();
} else {
editor->completion.trigger = 1;
this->trigger = 1;
completion_request(editor);
}
} else if (ch == CTRL('p')) {
if (editor->completion.active)
complete_next(editor);
if (this->active)
this->next();
} else if (ch == CTRL('o')) {
if (editor->completion.active)
complete_prev(editor);
if (this->active)
this->prev();
} else if (ch == 0x7F || ch == 0x08 || ch == CTRL('W')) {
if (editor->completion.active) {
if (editor->completion.complete) {
if (editor->cursor <= editor->completion.hook)
editor->completion.active = false;
if (this->active) {
if (this->complete) {
if (editor->cursor <= this->hook)
this->active = false;
else
completion_filter(editor);
} else {
if (editor->cursor <= editor->completion.hook)
editor->completion.active = false;
if (editor->cursor <= this->hook)
this->active = false;
else
completion_request(editor);
}
}
} else {
editor->completion.active = false;
this->active = false;
}
} else if (event.key_type == KEY_MOUSE && event.mouse_modifier == 0) {
// Prolly remove mouse support here
// auto &box = editor->completion.box;
// if (event.mouse_y >= box.position.row &&
// event.mouse_x >= box.position.col) {
// uint32_t row = event.mouse_y - box.position.row;
// uint32_t col = event.mouse_x - box.position.col;
// if (row < box.size.row && col < box.size.col) {
// uint8_t idx = 0;
// /* TODO: fix index relative to scroll */
// complete_select(editor, idx);
// }
// }
// if it is being implemented then stop main event handler from processing
// when click inside the box
editor->completion.active = false;
Prolly add mouse support here
auto &box = this->box;
if (event.mouse_y >= box.position.row &&
event.mouse_x >= box.position.col) {
uint32_t row = event.mouse_y - box.position.row;
uint32_t col = event.mouse_x - box.position.col;
if (row < box.size.row && col < box.size.col) {
uint8_t idx = 0;
complete_select(editor, idx);
}
}
if it is being implemented then stop main event handler from
processing
when click inside the box
this->active = false;
} else {
editor->completion.active = false;
this->active = false;
}
}
void completion_resolve_doc(Editor *editor) {
auto &item = editor->completion.items[editor->completion.select];
void CompletionSession::resolve_doc() {
auto &item = this->items[this->select];
if (item.documentation)
return;
item.documentation = "";
LSPPending *pending = new LSPPending();
pending->editor = editor;
pending->method = "completionItem/resolve";
pending->callback = [](Editor *editor, std::string, json message) {
pending->callback = [](Editor *editor, const json &message) {
std::unique_lock lock(editor->completion.mtx);
auto &item = editor->completion.items[editor->completion.select];
if (message["result"].contains("documentation")) {
@@ -373,13 +388,13 @@ void completion_resolve_doc(Editor *editor) {
lsp_send(editor->lsp, message, pending);
}
void complete_accept(Editor *editor) {
if (!editor->completion.active || editor->completion.box.hidden)
void CompletionSession::accept() {
if (!this->active || this->box.hidden)
return;
auto &item = editor->completion.items[editor->completion.select];
// TODO: support snippets and asis here
// once indentation engine is implemented
if (editor->completion.version != editor->lsp_version) {
auto &item = this->items[this->select];
TODO: support snippets and asis here
once indentation engine is implemented
if (this->version != editor->lsp_version) {
int delta_col = 0;
TextEdit &e = item.edits[0];
if (e.end.row == editor->cursor.row) {
@@ -395,8 +410,8 @@ void complete_accept(Editor *editor) {
}
}
}
apply_lsp_edits(editor, item.edits, true);
editor->completion.active = false;
editor->apply_lsp_edits(item.edits, true);
this->active = false;
}
inline static int visible_index(const CompletionSession &s) {
@@ -406,35 +421,36 @@ inline static int visible_index(const CompletionSession &s) {
return -1;
}
void complete_next(Editor *editor) {
auto &s = editor->completion;
if (!s.active || s.box.hidden || s.visible.empty())
void CompletionSession::next() {
if (!this->active || this->box.hidden || this->visible.empty())
return;
int vi = visible_index(s);
int vi = visible_index(*this);
if (vi < 0)
vi = 0;
else
vi = (vi + 1) % s.visible.size();
s.select = s.visible[vi];
completion_resolve_doc(editor);
editor->completion.box.render_update();
vi = (vi + 1) % this->visible.size();
this->select = this->visible[vi];
this->resolve_doc();
completion_adjust_scroll(*this);
this->box.render_update();
}
void complete_prev(Editor *editor) {
auto &s = editor->completion;
if (!s.active || s.box.hidden || s.visible.empty())
void CompletionSession::prev() {
if (!this->active || this->box.hidden || this->visible.empty())
return;
int vi = visible_index(s);
int vi = visible_index(*this);
if (vi < 0)
vi = 0;
else
vi = (vi + s.visible.size() - 1) % s.visible.size();
s.select = s.visible[vi];
completion_resolve_doc(editor);
editor->completion.box.render_update();
vi = (vi + this->visible.size() - 1) % this->visible.size();
this->select = this->visible[vi];
this->resolve_doc();
completion_adjust_scroll(*this);
this->box.render_update();
}
void complete_select(Editor *editor, uint8_t index) {
editor->completion.select = index;
complete_accept(editor);
void CompletionSession::choose(uint8_t index) {
this->select = index;
this->accept();
}
*/
+40 -40
View File
@@ -1,14 +1,14 @@
#include "editor/editor.h"
#include "utils/utils.h"
Coord move_right(Editor *editor, Coord cursor, uint32_t number) {
Coord Editor::move_right(Coord cursor, uint32_t number) {
Coord result = cursor;
if (!editor || !editor->root || number == 0)
if (!this->root || number == 0)
return result;
uint32_t row = result.row;
uint32_t col = result.col;
uint32_t line_len = 0;
LineIterator *it = begin_l_iter(editor->root, row);
LineIterator *it = begin_l_iter(this->root, row);
if (!it)
return result;
char *line = next_line(it, &line_len);
@@ -22,7 +22,7 @@ Coord move_right(Editor *editor, Coord cursor, uint32_t number) {
while (number > 0) {
if (col >= line_len) {
uint32_t next_row = row + 1;
if (next_row >= editor->root->line_count) {
if (next_row >= this->root->line_count) {
col = line_len;
break;
}
@@ -49,14 +49,16 @@ Coord move_right(Editor *editor, Coord cursor, uint32_t number) {
return result;
}
Coord move_left(Editor *editor, Coord cursor, uint32_t number) {
Coord Editor::move_left(Coord cursor, uint32_t number) {
Coord result = cursor;
if (!editor || !editor->root || number == 0)
if (!this->root || number == 0)
return result;
uint32_t row = result.row;
uint32_t col = result.col;
uint32_t len = 0;
LineIterator *it = begin_l_iter(editor->root, row);
LineIterator *it = begin_l_iter(this->root, row);
if (!it)
return result;
char *line = next_line(it, &len);
if (!line) {
free(it->buffer);
@@ -102,29 +104,28 @@ Coord move_left(Editor *editor, Coord cursor, uint32_t number) {
return result;
}
void cursor_down(Editor *editor, uint32_t number) {
if (!editor || !editor->root || number == 0)
void Editor::cursor_down(uint32_t number) {
if (!this->root || number == 0)
return;
uint32_t visual_col = editor->cursor_preffered;
uint32_t visual_col = this->cursor_preffered;
if (visual_col == UINT32_MAX) {
uint32_t len;
LineIterator *it = begin_l_iter(editor->root, editor->cursor.row);
LineIterator *it = begin_l_iter(this->root, this->cursor.row);
char *line = next_line(it, &len);
if (!line) {
free(it->buffer);
free(it);
return;
}
editor->cursor_preffered =
get_visual_col_from_bytes(line, len, editor->cursor.col);
visual_col = editor->cursor_preffered;
this->cursor_preffered =
get_visual_col_from_bytes(line, len, this->cursor.col);
visual_col = this->cursor_preffered;
free(it->buffer);
free(it);
}
editor->cursor.row =
MIN(editor->cursor.row + number, editor->root->line_count - 1);
this->cursor.row = MIN(this->cursor.row + number, this->root->line_count - 1);
uint32_t len;
LineIterator *it = begin_l_iter(editor->root, editor->cursor.row);
LineIterator *it = begin_l_iter(this->root, this->cursor.row);
char *line = next_line(it, &len);
if (!line) {
free(it->buffer);
@@ -133,26 +134,26 @@ void cursor_down(Editor *editor, uint32_t number) {
}
if (len > 0 && line[len - 1] == '\n')
--len;
editor->cursor.col = get_bytes_from_visual_col(line, len, visual_col);
this->cursor.col = get_bytes_from_visual_col(line, len, visual_col);
free(it->buffer);
free(it);
}
void cursor_up(Editor *editor, uint32_t number) {
if (!editor || !editor->root || number == 0 || editor->cursor.row == 0)
void Editor::cursor_up(uint32_t number) {
if (!this->root || number == 0 || this->cursor.row == 0)
return;
uint32_t len;
LineIterator *it = begin_l_iter(editor->root, editor->cursor.row);
LineIterator *it = begin_l_iter(this->root, this->cursor.row);
char *line_content = next_line(it, &len);
if (!line_content)
return;
if (editor->cursor_preffered == UINT32_MAX)
editor->cursor_preffered =
get_visual_col_from_bytes(line_content, len, editor->cursor.col);
uint32_t visual_col = editor->cursor_preffered;
if (this->cursor_preffered == UINT32_MAX)
this->cursor_preffered =
get_visual_col_from_bytes(line_content, len, this->cursor.col);
uint32_t visual_col = this->cursor_preffered;
free(it->buffer);
free(it);
uint32_t target_row = editor->cursor.row;
uint32_t target_row = this->cursor.row;
while (number > 0 && target_row > 0) {
target_row--;
if (target_row == 0) {
@@ -161,32 +162,31 @@ void cursor_up(Editor *editor, uint32_t number) {
}
number--;
}
it = begin_l_iter(editor->root, target_row);
it = begin_l_iter(this->root, target_row);
line_content = next_line(it, &len);
if (line_content) {
if (len > 0 && line_content[len - 1] == '\n')
--len;
editor->cursor.row = target_row;
editor->cursor.col =
get_bytes_from_visual_col(line_content, len, visual_col);
this->cursor.row = target_row;
this->cursor.col = get_bytes_from_visual_col(line_content, len, visual_col);
} else {
editor->cursor.row = 0;
editor->cursor.col = 0;
this->cursor.row = 0;
this->cursor.col = 0;
}
free(it->buffer);
free(it);
}
void cursor_right(Editor *editor, uint32_t number) {
if (!editor || !editor->root || number == 0)
void Editor::cursor_right(uint32_t number) {
if (!this->root || number == 0)
return;
editor->cursor = move_right(editor, editor->cursor, number);
editor->cursor_preffered = UINT32_MAX;
this->cursor = this->move_right(this->cursor, number);
this->cursor_preffered = UINT32_MAX;
}
void cursor_left(Editor *editor, uint32_t number) {
if (!editor || !editor->root || number == 0)
void Editor::cursor_left(uint32_t number) {
if (!this->root || number == 0)
return;
editor->cursor = move_left(editor, editor->cursor, number);
editor->cursor_preffered = UINT32_MAX;
this->cursor = this->move_left(this->cursor, number);
this->cursor_preffered = UINT32_MAX;
}
+100 -111
View File
@@ -2,20 +2,18 @@
#include "lsp/lsp.h"
#include "utils/utils.h"
void edit_erase(Editor *editor, Coord pos, int64_t len) {
void Editor::edit_erase(Coord pos, int64_t len) {
if (len == 0)
return;
if (len < 0) {
std::shared_lock lock_1(editor->knot_mtx);
uint32_t cursor_original =
line_to_byte(editor->root, editor->cursor.row, nullptr) +
editor->cursor.col;
uint32_t byte_pos = line_to_byte(editor->root, pos.row, nullptr) + pos.col;
Coord point = move_left(editor, pos, -len);
line_to_byte(this->root, this->cursor.row, nullptr) + this->cursor.col;
uint32_t byte_pos = line_to_byte(this->root, pos.row, nullptr) + pos.col;
Coord point = this->move_left(pos, -len);
json lsp_range;
bool do_lsp = (editor->lsp != nullptr);
bool do_lsp = (this->lsp != nullptr);
if (do_lsp) {
LineIterator *it = begin_l_iter(editor->root, point.row);
LineIterator *it = begin_l_iter(this->root, point.row);
uint32_t len;
char *line = next_line(it, &len);
int utf16_start = 0;
@@ -23,7 +21,7 @@ void edit_erase(Editor *editor, Coord pos, int64_t len) {
utf16_start = utf8_offset_to_utf16(line, len, point.col);
free(it->buffer);
free(it);
it = begin_l_iter(editor->root, pos.row);
it = begin_l_iter(this->root, pos.row);
line = next_line(it, &len);
int utf16_end = 0;
if (line)
@@ -33,62 +31,58 @@ void edit_erase(Editor *editor, Coord pos, int64_t len) {
lsp_range = {{"start", {{"line", point.row}, {"character", utf16_start}}},
{"end", {{"line", pos.row}, {"character", utf16_end}}}};
}
uint32_t start = line_to_byte(editor->root, point.row, nullptr) + point.col;
uint32_t start = line_to_byte(this->root, point.row, nullptr) + point.col;
if (cursor_original > start && cursor_original <= byte_pos) {
editor->cursor = point;
editor->cursor_preffered = UINT32_MAX;
this->cursor = point;
this->cursor_preffered = UINT32_MAX;
} else if (cursor_original > byte_pos) {
uint32_t cursor_new = cursor_original - (byte_pos - start);
uint32_t new_col;
uint32_t new_row = byte_to_line(editor->root, cursor_new, &new_col);
editor->cursor = {new_row, new_col};
editor->cursor_preffered = UINT32_MAX;
uint32_t new_row = byte_to_line(this->root, cursor_new, &new_col);
this->cursor = {new_row, new_col};
this->cursor_preffered = UINT32_MAX;
}
lock_1.unlock();
uint32_t start_row = point.row;
uint32_t end_row = pos.row;
apply_hook_deletion(editor, start_row + 1, end_row);
std::unique_lock lock_2(editor->knot_mtx);
editor->root = erase(editor->root, start, byte_pos - start);
lock_2.unlock();
if (editor->parser)
editor->parser->edit(start_row, end_row, 0);
this->root = erase(this->root, start, byte_pos - start);
if (this->parser)
this->parser->edit(start_row, end_row - start_row, 0);
this->hooks.edit(start_row, end_row - start_row, 0);
if (do_lsp) {
if (editor->lsp->incremental_sync) {
json message = {
{"jsonrpc", "2.0"},
auto lsp = this->lsp.load();
if (lsp->incremental_sync) {
auto message = std::make_unique<LSPMessage>();
message->message = {
{"method", "textDocument/didChange"},
{"params",
{{"textDocument",
{{"uri", editor->uri}, {"version", ++editor->lsp_version}}},
{{"uri", this->uri}, {"version", ++this->lsp_version}}},
{"contentChanges",
json::array({{{"range", lsp_range}, {"text", ""}}})}}}};
lsp_send(editor->lsp, message, nullptr);
lsp->send(std::move(message));
} else {
char *buf = read(editor->root, 0, editor->root->char_count);
char *buf = read(this->root, 0, this->root->char_count);
std::string text(buf);
free(buf);
json message = {
{"jsonrpc", "2.0"},
auto message = std::make_unique<LSPMessage>();
message->message = {
{"method", "textDocument/didChange"},
{"params",
{{"textDocument",
{{"uri", editor->uri}, {"version", ++editor->lsp_version}}},
{{"uri", this->uri}, {"version", ++this->lsp_version}}},
{"contentChanges", json::array({{{"text", text}}})}}}};
lsp_send(editor->lsp, message, nullptr);
lsp->send(std::move(message));
}
}
} else {
std::shared_lock lock_1(editor->knot_mtx);
uint32_t cursor_original =
line_to_byte(editor->root, editor->cursor.row, nullptr) +
editor->cursor.col;
uint32_t byte_pos = line_to_byte(editor->root, pos.row, nullptr) + pos.col;
Coord point = move_right(editor, pos, len);
line_to_byte(this->root, this->cursor.row, nullptr) + this->cursor.col;
uint32_t byte_pos = line_to_byte(this->root, pos.row, nullptr) + pos.col;
Coord point = this->move_right(pos, len);
json lsp_range;
bool do_lsp = (editor->lsp != nullptr);
bool do_lsp = (this->lsp != nullptr);
if (do_lsp) {
LineIterator *it = begin_l_iter(editor->root, pos.row);
LineIterator *it = begin_l_iter(this->root, pos.row);
uint32_t line_len;
char *line = next_line(it, &line_len);
int utf16_start = 0;
@@ -96,7 +90,7 @@ void edit_erase(Editor *editor, Coord pos, int64_t len) {
utf16_start = utf8_offset_to_utf16(line, line_len, pos.col);
free(it->buffer);
free(it);
it = begin_l_iter(editor->root, point.row);
it = begin_l_iter(this->root, point.row);
line = next_line(it, &line_len);
int utf16_end = 0;
if (line)
@@ -106,67 +100,63 @@ void edit_erase(Editor *editor, Coord pos, int64_t len) {
lsp_range = {{"start", {{"line", pos.row}, {"character", utf16_start}}},
{"end", {{"line", point.row}, {"character", utf16_end}}}};
}
uint32_t end = line_to_byte(editor->root, point.row, nullptr) + point.col;
uint32_t end = line_to_byte(this->root, point.row, nullptr) + point.col;
if (cursor_original > byte_pos && cursor_original <= end) {
editor->cursor = pos;
editor->cursor_preffered = UINT32_MAX;
this->cursor = pos;
this->cursor_preffered = UINT32_MAX;
} else if (cursor_original > end) {
uint32_t cursor_new = cursor_original - (end - byte_pos);
uint32_t new_col;
uint32_t new_row = byte_to_line(editor->root, cursor_new, &new_col);
editor->cursor = {new_row, new_col};
editor->cursor_preffered = UINT32_MAX;
uint32_t new_row = byte_to_line(this->root, cursor_new, &new_col);
this->cursor = {new_row, new_col};
this->cursor_preffered = UINT32_MAX;
}
lock_1.unlock();
uint32_t start_row = pos.row;
uint32_t end_row = point.row;
apply_hook_deletion(editor, start_row + 1, end_row);
std::unique_lock lock_2(editor->knot_mtx);
editor->root = erase(editor->root, byte_pos, end - byte_pos);
lock_2.unlock();
if (editor->parser)
editor->parser->edit(start_row, end_row, 0);
this->root = erase(this->root, byte_pos, end - byte_pos);
if (this->parser)
this->parser->edit(start_row, end_row - start_row, 0);
this->hooks.edit(start_row, end_row - start_row, 0);
if (do_lsp) {
if (editor->lsp->incremental_sync) {
json message = {
{"jsonrpc", "2.0"},
auto lsp = this->lsp.load();
if (lsp->incremental_sync) {
auto message = std::make_unique<LSPMessage>();
message->message = {
{"method", "textDocument/didChange"},
{"params",
{{"textDocument",
{{"uri", editor->uri}, {"version", ++editor->lsp_version}}},
{{"uri", this->uri}, {"version", ++this->lsp_version}}},
{"contentChanges",
json::array({{{"range", lsp_range}, {"text", ""}}})}}}};
lsp_send(editor->lsp, message, nullptr);
lsp->send(std::move(message));
} else {
char *buf = read(editor->root, 0, editor->root->char_count);
char *buf = read(this->root, 0, this->root->char_count);
std::string text(buf);
free(buf);
json message = {
{"jsonrpc", "2.0"},
auto message = std::make_unique<LSPMessage>();
message->message = {
{"method", "textDocument/didChange"},
{"params",
{{"textDocument",
{{"uri", editor->uri}, {"version", ++editor->lsp_version}}},
{{"uri", this->uri}, {"version", ++this->lsp_version}}},
{"contentChanges", json::array({{{"text", text}}})}}}};
lsp_send(editor->lsp, message, nullptr);
lsp->send(std::move(message));
}
}
}
}
void edit_insert(Editor *editor, Coord pos, char *data, uint32_t len) {
std::shared_lock lock_1(editor->knot_mtx);
void Editor::edit_insert(Coord pos, char *data, uint32_t len) {
uint32_t cursor_original =
line_to_byte(editor->root, editor->cursor.row, nullptr) +
editor->cursor.col;
uint32_t byte_pos = line_to_byte(editor->root, pos.row, nullptr) + pos.col;
line_to_byte(this->root, this->cursor.row, nullptr) + this->cursor.col;
uint32_t byte_pos = line_to_byte(this->root, pos.row, nullptr) + pos.col;
if (cursor_original > byte_pos) {
uint32_t cursor_new = cursor_original + len;
uint32_t new_col;
uint32_t new_row = byte_to_line(editor->root, cursor_new, &new_col);
editor->cursor = {new_row, new_col};
uint32_t new_row = byte_to_line(this->root, cursor_new, &new_col);
this->cursor = {new_row, new_col};
}
LineIterator *it = begin_l_iter(editor->root, pos.row);
LineIterator *it = begin_l_iter(this->root, pos.row);
uint32_t line_len;
char *line = next_line(it, &line_len);
int utf16_col = 0;
@@ -174,55 +164,52 @@ void edit_insert(Editor *editor, Coord pos, char *data, uint32_t len) {
utf16_col = utf8_offset_to_utf16(line, line_len, pos.col);
free(it->buffer);
free(it);
lock_1.unlock();
std::unique_lock lock_2(editor->knot_mtx);
editor->root = insert(editor->root, byte_pos, data, len);
this->root = insert(this->root, byte_pos, data, len);
uint32_t rows = 0;
for (uint32_t i = 0; i < len; i++)
if (data[i] == '\n')
rows++;
apply_hook_insertion(editor, pos.row, rows);
lock_2.unlock();
if (editor->parser)
editor->parser->edit(pos.row, pos.row, rows);
if (editor->lsp) {
if (editor->lsp->incremental_sync) {
json message = {
{"jsonrpc", "2.0"},
if (this->parser)
this->parser->edit(pos.row, 0, rows);
this->hooks.edit(pos.row, 0, rows);
auto lsp = this->lsp.load();
if (lsp) {
if (lsp->incremental_sync) {
auto message = std::make_unique<LSPMessage>();
message->message = {
{"method", "textDocument/didChange"},
{"params",
{{"textDocument",
{{"uri", editor->uri}, {"version", ++editor->lsp_version}}},
{{"uri", this->uri}, {"version", ++this->lsp_version}}},
{"contentChanges",
json::array(
{{{"range",
{{"start", {{"line", pos.row}, {"character", utf16_col}}},
{"end", {{"line", pos.row}, {"character", utf16_col}}}}},
{"text", std::string(data, len)}}})}}}};
lsp_send(editor->lsp, message, nullptr);
lsp->send(std::move(message));
} else {
char *buf = read(editor->root, 0, editor->root->char_count);
char *buf = read(this->root, 0, this->root->char_count);
std::string text(buf);
free(buf);
json message = {
{"jsonrpc", "2.0"},
auto message = std::make_unique<LSPMessage>();
message->message = {
{"method", "textDocument/didChange"},
{"params",
{{"textDocument",
{{"uri", editor->uri}, {"version", ++editor->lsp_version}}},
{{"uri", this->uri}, {"version", ++this->lsp_version}}},
{"contentChanges", json::array({{{"text", text}}})}}}};
lsp_send(editor->lsp, message, nullptr);
lsp->send(std::move(message));
}
}
}
void edit_replace(Editor *editor, Coord start, Coord end, const char *text,
uint32_t len) {
std::unique_lock lock(editor->knot_mtx);
void Editor::edit_replace(Coord start, Coord end, const char *text,
uint32_t len) {
uint32_t start_byte =
line_to_byte(editor->root, start.row, nullptr) + start.col;
uint32_t end_byte = line_to_byte(editor->root, end.row, nullptr) + end.col;
LineIterator *it = begin_l_iter(editor->root, start.row);
line_to_byte(this->root, start.row, nullptr) + start.col;
uint32_t end_byte = line_to_byte(this->root, end.row, nullptr) + end.col;
LineIterator *it = begin_l_iter(this->root, start.row);
uint32_t line_len;
char *line = next_line(it, &line_len);
int utf16_start = 0;
@@ -230,7 +217,7 @@ void edit_replace(Editor *editor, Coord start, Coord end, const char *text,
utf16_start = utf8_offset_to_utf16(line, line_len, start.col);
free(it->buffer);
free(it);
it = begin_l_iter(editor->root, end.row);
it = begin_l_iter(this->root, end.row);
line = next_line(it, &line_len);
int utf16_end = 0;
if (line)
@@ -238,23 +225,25 @@ void edit_replace(Editor *editor, Coord start, Coord end, const char *text,
free(it->buffer);
free(it);
if (start_byte != end_byte)
editor->root = erase(editor->root, start_byte, end_byte - start_byte);
this->root = erase(this->root, start_byte, end_byte - start_byte);
if (len > 0)
editor->root = insert(editor->root, start_byte, (char *)text, len);
this->root = insert(this->root, start_byte, (char *)text, len);
uint32_t rows = 0;
for (uint32_t i = 0; i < len; i++)
if (text[i] == '\n')
rows++;
if (editor->parser)
editor->parser->edit(start.row, end.row - 1, rows);
if (editor->lsp) {
if (editor->lsp->incremental_sync) {
json message = {
{"jsonrpc", "2.0"},
if (this->parser)
this->parser->edit(start.row, end.row - start.row, rows);
this->hooks.edit(start.row, end.row - start.row, rows);
auto lsp = this->lsp.load();
if (lsp) {
if (lsp->incremental_sync) {
auto message = std::make_unique<LSPMessage>();
message->message = {
{"method", "textDocument/didChange"},
{"params",
{{"textDocument",
{{"uri", editor->uri}, {"version", ++editor->lsp_version}}},
{{"uri", this->uri}, {"version", ++this->lsp_version}}},
{"contentChanges",
json::array(
{{{"range",
@@ -262,19 +251,19 @@ void edit_replace(Editor *editor, Coord start, Coord end, const char *text,
{{"line", start.row}, {"character", utf16_start}}},
{"end", {{"line", end.row}, {"character", utf16_end}}}}},
{"text", std::string(text, len)}}})}}}};
lsp_send(editor->lsp, message, nullptr);
lsp->send(std::move(message));
} else {
char *buf = read(editor->root, 0, editor->root->char_count);
char *buf = read(this->root, 0, this->root->char_count);
std::string full_text(buf);
free(buf);
json message = {
{"jsonrpc", "2.0"},
auto message = std::make_unique<LSPMessage>();
message->message = {
{"method", "textDocument/didChange"},
{"params",
{{"textDocument",
{{"uri", editor->uri}, {"version", ++editor->lsp_version}}},
{{"uri", this->uri}, {"version", ++this->lsp_version}}},
{"contentChanges", json::array({{{"text", full_text}}})}}}};
lsp_send(editor->lsp, message, nullptr);
lsp->send(std::move(message));
}
}
}
+40 -104
View File
@@ -1,72 +1,68 @@
#include "editor/editor.h"
#include "editor/decl.h"
#include "lsp/lsp.h"
#include "main.h"
#include "syntax/langs.h"
#include "utils/utils.h"
Editor *new_editor(const char *filename_arg, Coord position, Coord size,
uint8_t eol) {
Editor *editor = new Editor();
if (!editor)
return nullptr;
Editor::Editor(const char *filename_arg, uint8_t eol) {
uint32_t len = 0;
std::string filename = path_abs(filename_arg);
editor->unix_eol = eol & 1;
char *str = load_file(filename.c_str(), &len, &editor->unix_eol);
this->unix_eol = eol & 1;
char *str = load_file(filename.c_str(), &len, &this->unix_eol);
if (!str) {
str = (char *)malloc(1);
*str = '\n';
len = 1;
}
if ((eol >> 1) & 1)
editor->unix_eol = eol & 1;
editor->filename = filename;
editor->uri = path_to_file_uri(filename);
editor->position = position;
editor->size = size;
editor->cursor_preffered = UINT32_MAX;
this->unix_eol = eol & 1;
this->filename = filename;
this->uri = path_to_file_uri(filename);
this->cursor_preffered = UINT32_MAX;
if (len == 0) {
free(str);
str = (char *)malloc(1);
*str = '\n';
len = 1;
}
editor->root = load(str, len, optimal_chunk_size(len));
this->scroll = {0, 0};
this->cursor = {0, 0};
this->size = {20, 20};
this->root = load(str, len, optimal_chunk_size(len));
free(str);
editor->lang = language_for_file(filename.c_str());
if (parsers.find(editor->lang.name) != parsers.end())
editor->parser = new Parser(editor, editor->lang.name, size.row + 5);
if (editor->lang.name == "css" || editor->lang.name == "html" ||
editor->lang.name == "javascript" || editor->lang.name == "markdown" ||
editor->lang.name == "typescript")
editor->is_css_color = true;
if (len <= (1024 * 28))
request_add_to_lsp(editor->lang, editor);
editor->indents.compute_indent(editor);
return editor;
this->lang = language_for_file(filename.c_str());
if (parsers.find(this->lang.name) != parsers.end())
this->parser = new Parser(this, this->lang.name, size.row + 5);
if (this->lang.name == "css" || this->lang.name == "html" ||
this->lang.name == "javascript" || this->lang.name == "markdown" ||
this->lang.name == "typescript")
this->is_css_color = true;
if (len <= (1024 * 28)) {
std::lock_guard lock(lsp::lsp_mutex);
lsp::new_editors.push_back(this);
}
this->indents.compute_indent(this);
}
void free_editor(Editor *editor) {
remove_from_lsp(editor);
if (editor->parser)
delete editor->parser;
editor->parser = nullptr;
free_rope(editor->root);
delete editor;
Editor::~Editor() {
auto lsp = this->lsp.load();
if (lsp)
lsp->remove(this);
if (this->parser)
delete this->parser;
this->parser = nullptr;
free_rope(this->root);
}
void save_file(Editor *editor) {
if (!editor || !editor->root)
void Editor::save() {
if (!this->root)
return;
std::shared_lock lock(editor->knot_mtx);
int version = editor->lsp_version;
uint32_t char_count = editor->root->char_count;
char *str = read(editor->root, 0, char_count);
uint32_t char_count = this->root->char_count;
char *str = read(this->root, 0, char_count);
if (!str)
return;
lock.unlock();
std::ofstream out(editor->filename);
if (!editor->unix_eol) {
std::ofstream out(this->filename);
if (!this->unix_eol) {
for (uint32_t i = 0; i < char_count; ++i) {
if (str[i] == '\n')
out.put('\r');
@@ -77,66 +73,6 @@ void save_file(Editor *editor) {
}
out.close();
free(str);
if (editor->lsp) {
json save_msg = {{"jsonrpc", "2.0"},
{"method", "textDocument/didSave"},
{"params", {{"textDocument", {{"uri", editor->uri}}}}}};
lsp_send(editor->lsp, save_msg, nullptr);
if (editor->lsp->allow_formatting) {
json msg = {{"jsonrpc", "2.0"},
{"method", "textDocument/formatting"},
{"params",
{{"textDocument", {{"uri", editor->uri}}},
{"options",
{{"tabSize", 2},
{"insertSpaces", true},
{"trimTrailingWhitespace", true},
{"trimFinalNewlines", true}}}}}};
LSPPending *pending = new LSPPending();
pending->editor = editor;
pending->method = "textDocument/formatting";
pending->callback = [save_msg, version](Editor *editor, std::string,
json message) {
if (version != editor->lsp_version)
return;
auto &edits = message["result"];
if (edits.is_array()) {
std::vector<TextEdit> t_edits;
t_edits.reserve(edits.size());
for (auto &edit : edits) {
TextEdit t_edit;
t_edit.text = edit.value("newText", "");
t_edit.start.row = edit["range"]["start"]["line"];
t_edit.start.col = edit["range"]["start"]["character"];
t_edit.end.row = edit["range"]["end"]["line"];
t_edit.end.col = edit["range"]["end"]["character"];
utf8_normalize_edit(editor, &t_edit);
t_edits.push_back(t_edit);
}
apply_lsp_edits(editor, t_edits, false);
ensure_scroll(editor);
std::shared_lock lock(editor->knot_mtx);
uint32_t char_count = editor->root->char_count;
char *str = read(editor->root, 0, char_count);
if (!str)
return;
lock.unlock();
std::ofstream out(editor->filename);
if (!editor->unix_eol) {
for (uint32_t i = 0; i < char_count; ++i) {
if (str[i] == '\n')
out.put('\r');
out.put(str[i]);
}
} else {
out.write(str, char_count);
}
out.close();
free(str);
lsp_send(editor->lsp, save_msg, nullptr);
}
};
lsp_send(editor->lsp, msg, pending);
}
}
ui::bar.log("Written " + std::to_string(char_count) + " bytes to " +
this->filename);
}
+75 -78
View File
@@ -1,60 +1,59 @@
#include "editor/editor.h"
#include "editor/helpers.h"
#include "extentions/hover.h"
#include "io/sysio.h"
#include "main.h"
#include "utils/utils.h"
void handle_editor_event(Editor *editor, KeyEvent event) {
void Editor::handle_event(KeyEvent event) {
uint8_t old_mode = mode;
if (editor->hover_active)
editor->hover_active = false;
handle_mouse(editor, event);
if (!this->hover_popup->hidden)
this->hover_popup->hidden = true;
if (event.key_type == KEY_SPECIAL) {
switch (event.special_modifier) {
case 0:
switch (event.special_key) {
case KEY_DOWN:
cursor_down(editor, 1);
this->cursor_down(1);
break;
case KEY_UP:
cursor_up(editor, 1);
this->cursor_up(1);
break;
case KEY_LEFT:
cursor_left(editor, 1);
this->cursor_left(1);
break;
case KEY_RIGHT:
cursor_right(editor, 1);
this->cursor_right(1);
break;
}
break;
case CNTRL:
switch (event.special_key) {
case KEY_DOWN:
cursor_down(editor, 5);
this->cursor_down(5);
break;
case KEY_UP:
cursor_up(editor, 5);
this->cursor_up(5);
break;
case KEY_LEFT:
cursor_prev_word(editor);
this->cursor_prev_word();
case KEY_RIGHT:
cursor_next_word(editor);
this->cursor_next_word();
break;
}
break;
case ALT:
switch (event.special_key) {
case KEY_DOWN:
move_line_down(editor);
this->move_line_down();
break;
case KEY_UP:
move_line_up(editor);
this->move_line_up();
break;
case KEY_LEFT:
cursor_left(editor, 8);
this->cursor_left(8);
break;
case KEY_RIGHT:
cursor_right(editor, 8);
this->cursor_right(8);
break;
}
break;
@@ -65,86 +64,86 @@ void handle_editor_event(Editor *editor, KeyEvent event) {
if (event.key_type == KEY_CHAR && event.len == 1) {
switch (event.c[0]) {
case 'u':
select_all(editor);
this->select_all();
break;
case CTRL('h'):
editor->hover.scroll(-1);
editor->hover_active = true;
this->hover_popup->scroll(-1);
this->hover_popup->hidden = false;
break;
case CTRL('l'):
editor->hover.scroll(1);
editor->hover_active = true;
this->hover_popup->scroll(1);
this->hover_popup->hidden = false;
break;
case 'h':
fetch_lsp_hover(editor);
this->fetch_lsp_hover();
break;
case 'a': {
mode = INSERT;
Coord start = editor->cursor;
cursor_right(editor, 1);
if (start.row != editor->cursor.row)
cursor_left(editor, 1);
Coord start = this->cursor;
this->cursor_right(1);
if (start.row != this->cursor.row)
this->cursor_left(1);
} break;
case 'i':
mode = INSERT;
break;
case 'n':
mode = JUMPER;
editor->jumper_set = true;
this->jumper_set = true;
break;
case 'm':
mode = JUMPER;
editor->jumper_set = false;
this->jumper_set = false;
break;
case 'N':
clear_hooks_at_line(editor, editor->cursor.row);
this->hooks.clear_line(this->cursor.row);
break;
case 's':
case 'v':
mode = SELECT;
editor->selection_active = true;
editor->selection = editor->cursor;
editor->selection_type = CHAR;
this->selection_active = true;
this->selection = this->cursor;
this->selection_type = CHAR;
break;
case ';':
case ':':
mode = RUNNER;
break;
case 0x7F:
cursor_left(editor, 1);
this->cursor_left(1);
break;
case ' ':
cursor_right(editor, 1);
this->cursor_right(1);
break;
case '\r':
case '\n':
cursor_down(editor, 1);
this->cursor_down(1);
break;
case '\\':
case '|':
cursor_up(editor, 1);
this->cursor_up(1);
break;
case CTRL('d'):
scroll_down(editor, 1);
ensure_cursor(editor);
this->scroll_down(1);
this->ensure_cursor();
break;
case CTRL('u'):
scroll_up(editor, 1);
ensure_cursor(editor);
this->scroll_up(1);
this->ensure_cursor();
break;
case '>':
case '.':
indent_current_line(editor);
this->indent_current_line();
break;
case '<':
case ',':
dedent_current_line(editor);
this->dedent_current_line();
break;
case CTRL('s'):
save_file(editor);
this->save();
break;
case 'p':
paste(editor);
this->paste();
break;
}
}
@@ -153,35 +152,34 @@ void handle_editor_event(Editor *editor, KeyEvent event) {
if (event.key_type == KEY_CHAR) {
if (event.len == 1) {
if (event.c[0] == '\t') {
edit_insert(editor, editor->cursor, (char *)" ", 2);
cursor_right(editor, 2);
this->indents.insert_tab(this->cursor);
} else if (event.c[0] == '\n' || event.c[0] == '\r') {
editor->indents.insert_new_line(editor->cursor);
this->indents.insert_new_line(this->cursor);
} else if (event.c[0] == CTRL('W')) {
delete_prev_word(editor);
this->delete_prev_word();
} else if (isprint((unsigned char)(event.c[0]))) {
insert_char(editor, event.c[0]);
this->insert_char(event.c[0]);
} else if (event.c[0] == 0x7F || event.c[0] == 0x08) {
backspace_edit(editor);
this->backspace_edit();
} else if (event.c[0] == 0x1B) {
normal_mode(editor);
this->normal_mode();
}
} else if (event.len > 1) {
edit_insert(editor, editor->cursor, event.c, event.len);
cursor_right(editor, 1);
this->edit_insert(this->cursor, event.c, event.len);
this->cursor_right(1);
}
} else if (event.key_type == KEY_SPECIAL &&
event.special_key == KEY_DELETE) {
switch (event.special_modifier) {
case 0:
edit_erase(editor, editor->cursor, 1);
this->edit_erase(this->cursor, 1);
break;
case CNTRL:
delete_next_word(editor);
this->delete_next_word();
break;
}
} else if (event.key_type == KEY_PASTE) {
insert_str(editor, event.c, event.len);
this->insert_str(event.c, event.len);
}
break;
case SELECT:
@@ -190,48 +188,47 @@ void handle_editor_event(Editor *editor, KeyEvent event) {
case 0x1B:
case 's':
case 'v':
editor->selection_active = false;
this->selection_active = false;
mode = NORMAL;
break;
case 'y':
copy(editor);
this->copy();
mode = NORMAL;
break;
case 'x':
cut(editor);
this->cut();
mode = NORMAL;
break;
case 'p':
paste(editor);
this->paste();
mode = NORMAL;
break;
case '<':
case ',':
this->dedent_selection();
break;
case '>':
case '.':
this->indent_selection();
break;
}
}
break;
case JUMPER:
if (event.key_type == KEY_CHAR && event.len == 1 &&
(event.c[0] >= '!' && event.c[0] <= '~')) {
if (editor->jumper_set) {
for (uint8_t i = 0; i < 94; i++)
if (editor->hooks[i] == editor->cursor.row + 1) {
editor->hooks[i] = 0;
break;
}
editor->hooks[event.c[0] - '!'] = editor->cursor.row + 1;
if (this->jumper_set) {
this->hooks.set(event.c[0], this->cursor.row);
} else {
uint32_t line = editor->hooks[event.c[0] - '!'] - 1;
if (line > 0) {
editor->cursor = {line, 0};
editor->cursor_preffered = UINT32_MAX;
}
uint32_t line;
if (this->hooks.get(event.c[0], &line))
this->cursor = {line, 0};
}
}
mode = NORMAL;
break;
}
if (old_mode == mode || mode != INSERT)
handle_completion(editor, event);
ensure_scroll(editor);
if ((event.key_type == KEY_CHAR || event.key_type == KEY_PASTE) && event.c)
free(event.c);
// if (old_mode == mode || mode != INSERT)
// this->completion.handle(event);
this->ensure_scroll();
}
+317 -191
View File
@@ -1,83 +1,135 @@
#include "editor/helpers.h"
#include "editor/editor.h"
#include "extentions/hover.h"
#include "io/sysio.h"
#include "lsp/lsp.h"
#include "main.h"
#include "utils/utils.h"
void cut(Editor *editor) {
void Editor::cut() {
if (ABS((int64_t)this->cursor.row - (int64_t)this->selection.row) > 1500) {
ui::bar.log("Selection too large!");
return;
}
if (mode != SELECT)
return;
Coord start;
uint32_t len;
char *text = get_selection(editor, &len, &start);
copy_to_clipboard(text, len);
char *text = this->get_selection(&len, &start);
ruby_copy(text, len);
len = count_clusters(text, len, 0, len);
edit_erase(editor, start, len);
this->edit_erase(start, len);
free(text);
editor->selection_active = false;
this->selection_active = false;
}
void copy(Editor *editor) {
void Editor::copy() {
if (ABS((int64_t)this->cursor.row - (int64_t)this->selection.row) > 1500) {
ui::bar.log("Selection too large!");
return;
}
if (mode != SELECT)
return;
uint32_t len;
char *text = get_selection(editor, &len, nullptr);
copy_to_clipboard(text, len);
char *text = this->get_selection(&len, nullptr);
ruby_copy(text, len);
free(text);
editor->selection_active = false;
this->selection_active = false;
}
void paste(Editor *editor) {
uint32_t len;
void Editor::paste() {
if (mode == NORMAL) {
char *text = get_from_clipboard(&len);
if (text) {
insert_str(editor, text, len);
free(text);
}
std::string text = ruby_paste();
if (text.empty())
return;
this->insert_str((char *)text.c_str(), text.length());
} else if (mode == SELECT) {
char *text = get_from_clipboard(&len);
if (text) {
std::string text = ruby_paste();
if (!text.empty()) {
Coord start, end;
selection_bounds(editor, &start, &end);
this->selection_bounds(&start, &end);
uint32_t start_byte =
line_to_byte(editor->root, start.row, nullptr) + start.col;
uint32_t end_byte =
line_to_byte(editor->root, end.row, nullptr) + end.col;
edit_erase(editor, start, end_byte - start_byte);
edit_insert(editor, editor->cursor, text, len);
free(text);
line_to_byte(this->root, start.row, nullptr) + start.col;
uint32_t end_byte = line_to_byte(this->root, end.row, nullptr) + end.col;
this->edit_erase(start, end_byte - start_byte);
this->edit_insert(this->cursor, (char *)text.c_str(), text.length());
}
editor->selection_active = false;
this->selection_active = false;
}
}
void insert_str(Editor *editor, char *c, uint32_t len) {
void Editor::insert_str(char *c, uint32_t len) {
if (c) {
edit_insert(editor, editor->cursor, c, len);
this->edit_insert(this->cursor, c, len);
uint32_t grapheme_len = count_clusters(c, len, 0, len);
cursor_right(editor, grapheme_len);
this->cursor_right(grapheme_len);
}
}
void indent_current_line(Editor *editor) {
Coord start = editor->cursor;
uint32_t delta = editor->indents.indent_line(editor->cursor.row);
editor->cursor.col = start.col + delta;
editor->cursor.row = start.row;
void Editor::indent_current_line() {
Coord start = this->cursor;
uint32_t delta = this->indents.indent_line(this->cursor.row);
this->cursor.col = start.col + delta;
this->cursor.row = start.row;
}
void dedent_current_line(Editor *editor) {
Coord start = editor->cursor;
uint32_t delta = editor->indents.dedent_line(editor->cursor.row);
editor->cursor.col = MAX((int64_t)start.col - delta, 0);
editor->cursor.row = start.row;
void Editor::dedent_current_line() {
Coord start = this->cursor;
uint32_t delta = this->indents.dedent_line(this->cursor.row);
this->cursor.col = MAX((int64_t)start.col - delta, 0);
this->cursor.row = start.row;
}
void insert_char(Editor *editor, char c) {
uint32_t col = editor->cursor.col;
LineIterator *it = begin_l_iter(editor->root, editor->cursor.row);
static void move_coord_by_delta(Coord &c, uint32_t row, int64_t delta) {
if (c.row == row) {
int64_t new_col = (int64_t)c.col + delta;
c.col = (uint32_t)MAX(new_col, 0);
}
}
void Editor::indent_selection() {
uint32_t top = MIN(this->cursor.row, this->selection.row);
uint32_t bot = MAX(this->cursor.row, this->selection.row);
if (bot - top > 1500) {
ui::bar.log("Can't indent more than 1500 lines at once!");
return;
}
if (bot - top >= 2)
this->indents.indent_block(top + 1, bot - 1);
uint32_t delta_top = this->indents.indent_line(top);
uint32_t delta_bot =
(bot == top) ? delta_top : this->indents.indent_line(bot);
move_coord_by_delta(this->cursor, top, delta_top);
move_coord_by_delta(this->selection, top, delta_top);
if (bot != top) {
move_coord_by_delta(this->cursor, bot, delta_bot);
move_coord_by_delta(this->selection, bot, delta_bot);
}
}
void Editor::dedent_selection() {
uint32_t top = MIN(this->cursor.row, this->selection.row);
uint32_t bot = MAX(this->cursor.row, this->selection.row);
if (bot - top > 1500) {
ui::bar.log("Can't dedent more than 1500 lines at once!");
return;
}
if (bot - top >= 2)
this->indents.dedent_block(top + 1, bot - 1);
uint32_t delta_top = this->indents.dedent_line(top);
uint32_t delta_bot =
(bot == top) ? delta_top : this->indents.dedent_line(bot);
move_coord_by_delta(this->cursor, top, -(int64_t)delta_top);
move_coord_by_delta(this->selection, top, -(int64_t)delta_top);
if (bot != top) {
move_coord_by_delta(this->cursor, bot, -(int64_t)delta_bot);
move_coord_by_delta(this->selection, bot, -(int64_t)delta_bot);
}
}
void Editor::insert_char(char c) {
uint32_t col = this->cursor.col;
LineIterator *it = begin_l_iter(this->root, this->cursor.row);
if (!it)
return;
uint32_t len;
@@ -93,7 +145,7 @@ void insert_char(Editor *editor, char c) {
if ((c == '}' && next == '}') || (c == ')' && next == ')') ||
(c == ']' && next == ']') || (c == '"' && next == '"') ||
(c == '\'' && next == '\'')) {
cursor_right(editor, 1);
this->cursor_right(1);
skip_insert = true;
}
}
@@ -120,16 +172,17 @@ void insert_char(Editor *editor, char c) {
}
if (closing) {
char pair[2] = {c, closing};
edit_insert(editor, editor->cursor, pair, 2);
cursor_right(editor, 1);
this->edit_insert(this->cursor, pair, 2);
this->cursor_right(1);
} else {
edit_insert(editor, editor->cursor, &c, 1);
cursor_right(editor, 1);
this->edit_insert(this->cursor, &c, 1);
this->cursor_right(1);
}
if (editor->lsp && editor->lsp->allow_formatting_on_type) {
for (char ch : editor->lsp->format_chars) {
auto lsp = this->lsp.load();
if (lsp && lsp->allow_formatting_on_type) {
for (char ch : lsp->format_chars) {
if (ch == c) {
LineIterator *it = begin_l_iter(editor->root, editor->cursor.row);
LineIterator *it = begin_l_iter(this->root, this->cursor.row);
if (!it)
return;
uint32_t len;
@@ -139,31 +192,27 @@ void insert_char(Editor *editor, char c) {
free(it);
return;
}
uint32_t col = utf8_offset_to_utf16(line, len, editor->cursor.col);
uint32_t col = utf8_offset_to_utf16(line, len, this->cursor.col);
free(it->buffer);
free(it);
int version = editor->lsp_version;
json message = {
{"jsonrpc", "2.0"},
int version = this->lsp_version;
auto message = std::make_unique<LSPMessage>();
message->message = {
{"method", "textDocument/onTypeFormatting"},
{"params",
{{"textDocument", {{"uri", editor->uri}}},
{"position",
{{"line", editor->cursor.row}, {"character", col}}},
{{"textDocument", {{"uri", this->uri}}},
{"position", {{"line", this->cursor.row}, {"character", col}}},
{"ch", std::string(1, c)},
{"options",
{{"tabSize", 2},
{"insertSpaces", true},
{"trimTrailingWhitespace", true},
{"trimFinalNewlines", true}}}}}};
LSPPending *pending = new LSPPending();
pending->editor = editor;
pending->method = "textDocument/onTypeFormatting";
pending->callback = [version](Editor *editor, std::string,
json message) {
if (version != editor->lsp_version)
message->editor = this;
message->callback = [version](const LSPMessage &message) {
if (version != message.editor->lsp_version)
return;
auto &edits = message["result"];
auto &edits = message.message["result"];
if (edits.is_array()) {
std::vector<TextEdit> t_edits;
t_edits.reserve(edits.size());
@@ -174,14 +223,14 @@ void insert_char(Editor *editor, char c) {
t_edit.start.col = edit["range"]["start"]["character"];
t_edit.end.row = edit["range"]["end"]["line"];
t_edit.end.col = edit["range"]["end"]["character"];
utf8_normalize_edit(editor, &t_edit);
message.editor->utf8_normalize_edit(&t_edit);
t_edits.push_back(t_edit);
}
apply_lsp_edits(editor, t_edits, false);
ensure_scroll(editor);
message.editor->apply_lsp_edits(t_edits, false);
message.editor->ensure_scroll();
}
};
lsp_send(editor->lsp, message, pending);
lsp->send(std::move(message));
break;
}
}
@@ -189,91 +238,171 @@ void insert_char(Editor *editor, char c) {
}
}
void normal_mode(Editor *editor) {
Coord prev_pos = editor->cursor;
mode = NORMAL;
cursor_left(editor, 1);
if (prev_pos.row != editor->cursor.row)
cursor_right(editor, 1);
void Editor::format_full(int version) {
auto lsp = this->lsp.load();
if (lsp) {
log("Saving %s", this->filename.c_str());
auto message = std::make_unique<LSPMessage>();
message->message = {{"method", "textDocument/didSave"},
{"params", {{"textDocument", {{"uri", this->uri}}}}}};
lsp->send(std::move(message));
if (lsp->allow_formatting) {
json s_msg = {{"method", "textDocument/formatting"},
{"params",
{{"textDocument", {{"uri", this->uri}}},
{"options",
{{"tabSize", 2},
{"insertSpaces", true},
{"trimTrailingWhitespace", true},
{"trimFinalNewlines", true}}}}}};
auto save_msg = std::make_unique<LSPMessage>();
save_msg->editor = this;
save_msg->message = s_msg;
save_msg->callback = [s_msg, version](const LSPMessage &msg) {
if (version != msg.editor->lsp_version)
return;
auto &edits = msg.message["result"];
if (edits.is_array()) {
std::vector<TextEdit> t_edits;
t_edits.reserve(edits.size());
for (auto &edit : edits) {
TextEdit t_edit;
t_edit.text = edit.value("newText", "");
t_edit.start.row = edit["range"]["start"]["line"];
t_edit.start.col = edit["range"]["start"]["character"];
t_edit.end.row = edit["range"]["end"]["line"];
t_edit.end.col = edit["range"]["end"]["character"];
msg.editor->utf8_normalize_edit(&t_edit);
t_edits.push_back(t_edit);
}
msg.editor->apply_lsp_edits(t_edits, false);
msg.editor->ensure_cursor();
uint32_t char_count = msg.editor->root->char_count;
char *str = read(msg.editor->root, 0, char_count);
if (!str)
return;
std::ofstream out(msg.editor->filename);
if (!msg.editor->unix_eol) {
for (uint32_t i = 0; i < char_count; ++i) {
if (str[i] == '\n')
out.put('\r');
out.put(str[i]);
}
} else {
out.write(str, char_count);
}
out.close();
free(str);
auto save_msg = std::make_unique<LSPMessage>();
save_msg->editor = msg.editor;
save_msg->message = s_msg;
save_msg->callback = [](const LSPMessage &) {};
msg.editor->lsp.load()->send(std::move(save_msg));
}
};
lsp->send(std::move(save_msg));
}
}
}
void backspace_edit(Editor *editor) {
Coord prev_pos = editor->cursor;
void Editor::normal_mode() {
Coord prev_pos = this->cursor;
mode = NORMAL;
this->cursor_left(1);
if (prev_pos.row != this->cursor.row)
this->cursor_right(1);
}
void Editor::backspace_edit() {
Coord prev_pos = this->cursor;
if (prev_pos.col > 0)
prev_pos.col--;
LineIterator *it = begin_l_iter(editor->root, editor->cursor.row);
LineIterator *it = begin_l_iter(this->root, this->cursor.row);
if (!it)
return;
char *line = next_line(it, nullptr);
char prev_char = line[prev_pos.col];
char next_char = line[editor->cursor.col];
uint32_t len;
char *line = next_line(it, &len);
if (!line) {
free(it->buffer);
free(it);
return;
}
if (len > 0 && line[len - 1] == '\n')
--len;
char prev_char = (prev_pos.col < len) ? line[prev_pos.col] : 0;
char next_char = (this->cursor.col < len) ? line[this->cursor.col] : 0;
bool before_content = false;
if (this->cursor.col > 0) {
before_content = true;
for (uint32_t i = 0; i < this->cursor.col; i++)
if (line[i] != ' ' && line[i] != '\t') {
before_content = false;
break;
}
}
free(it->buffer);
free(it);
if (before_content) {
this->dedent_current_line();
return;
}
bool is_pair = (prev_char == '{' && next_char == '}') ||
(prev_char == '(' && next_char == ')') ||
(prev_char == '[' && next_char == ']') ||
(prev_char == '"' && next_char == '"') ||
(prev_char == '\'' && next_char == '\'');
if (is_pair) {
edit_erase(editor, editor->cursor, 1);
edit_erase(editor, prev_pos, 1);
this->edit_erase(this->cursor, 1);
this->edit_erase(prev_pos, 1);
} else {
edit_erase(editor, editor->cursor, -1);
this->edit_erase(this->cursor, -1);
}
}
void delete_prev_word(Editor *editor) {
void Editor::delete_prev_word() {
uint32_t prev_col_byte, prev_col_cluster;
word_boundaries(editor, editor->cursor, &prev_col_byte, nullptr,
&prev_col_cluster, nullptr);
if (prev_col_byte == editor->cursor.col)
edit_erase(editor, editor->cursor, -1);
this->word_boundaries(this->cursor, &prev_col_byte, nullptr,
&prev_col_cluster, nullptr);
if (prev_col_byte == this->cursor.col)
this->edit_erase(this->cursor, -1);
else
edit_erase(editor, editor->cursor, -(int64_t)prev_col_cluster);
this->edit_erase(this->cursor, -(int64_t)prev_col_cluster);
}
void delete_next_word(Editor *editor) {
void Editor::delete_next_word() {
uint32_t next_col_byte, next_col_cluster;
word_boundaries(editor, editor->cursor, nullptr, &next_col_byte, nullptr,
&next_col_cluster);
if (next_col_byte == editor->cursor.col)
edit_erase(editor, editor->cursor, 1);
this->word_boundaries(this->cursor, nullptr, &next_col_byte, nullptr,
&next_col_cluster);
if (next_col_byte == this->cursor.col)
this->edit_erase(this->cursor, 1);
else
edit_erase(editor, editor->cursor, next_col_cluster);
this->edit_erase(this->cursor, next_col_cluster);
}
void clear_hooks_at_line(Editor *editor, uint32_t line) {
for (uint8_t i = 0; i < 94; i++)
if (editor->hooks[i] == line + 1) {
editor->hooks[i] = 0;
break;
}
}
void cursor_prev_word(Editor *editor) {
void Editor::cursor_prev_word() {
uint32_t prev_col;
word_boundaries(editor, editor->cursor, &prev_col, nullptr, nullptr, nullptr);
editor->cursor_preffered = UINT32_MAX;
if (prev_col == editor->cursor.col)
cursor_left(editor, 1);
word_boundaries(this->cursor, &prev_col, nullptr, nullptr, nullptr);
this->cursor_preffered = UINT32_MAX;
if (prev_col == this->cursor.col)
cursor_left(1);
else
editor->cursor = {editor->cursor.row, prev_col};
this->cursor = {this->cursor.row, prev_col};
}
void cursor_next_word(Editor *editor) {
void Editor::cursor_next_word() {
uint32_t next_col;
word_boundaries(editor, editor->cursor, nullptr, &next_col, nullptr, nullptr);
editor->cursor_preffered = UINT32_MAX;
if (next_col == editor->cursor.col)
cursor_right(editor, 1);
word_boundaries(this->cursor, nullptr, &next_col, nullptr, nullptr);
this->cursor_preffered = UINT32_MAX;
if (next_col == this->cursor.col)
this->cursor_right(1);
else
editor->cursor = {editor->cursor.row, next_col};
this->cursor = {this->cursor.row, next_col};
}
void select_all(Editor *editor) {
if (editor->root->line_count > 0) {
editor->cursor.row = editor->root->line_count - 1;
LineIterator *it = begin_l_iter(editor->root, editor->cursor.row);
void Editor::select_all() {
if (this->root->line_count > 0) {
this->cursor.row = this->root->line_count - 1;
LineIterator *it = begin_l_iter(this->root, this->cursor.row);
if (!it)
return;
uint32_t line_len;
@@ -285,18 +414,19 @@ void select_all(Editor *editor) {
line_len = count_clusters(line, line_len, 0, line_len);
free(it->buffer);
free(it);
editor->cursor.col = line_len;
editor->cursor_preffered = UINT32_MAX;
this->cursor.col = line_len;
this->cursor_preffered = UINT32_MAX;
mode = SELECT;
editor->selection_active = true;
editor->selection = {0, 0};
editor->selection_type = LINE;
this->selection_active = true;
this->selection = {0, 0};
this->selection_type = LINE;
}
}
void fetch_lsp_hover(Editor *editor) {
if (editor->lsp && editor->lsp->allow_hover) {
LineIterator *it = begin_l_iter(editor->root, editor->cursor.row);
void Editor::fetch_lsp_hover() {
auto lsp = this->lsp.load();
if (lsp && lsp->allow_hover) {
LineIterator *it = begin_l_iter(this->root, this->cursor.row);
uint32_t line_len;
char *line = next_line(it, &line_len);
if (!line) {
@@ -304,19 +434,18 @@ void fetch_lsp_hover(Editor *editor) {
free(it);
return;
}
uint32_t col = utf8_offset_to_utf16(line, line_len, editor->cursor.col);
uint32_t col = utf8_offset_to_utf16(line, line_len, this->cursor.col);
free(it->buffer);
free(it);
json hover_request = {
{"jsonrpc", "2.0"},
auto message = std::make_unique<LSPMessage>();
message->message = {
{"method", "textDocument/hover"},
{"params",
{{"textDocument", {{"uri", editor->uri}}},
{"position", {{"line", editor->cursor.row}, {"character", col}}}}}};
LSPPending *pending = new LSPPending();
pending->editor = editor;
pending->method = "textDocument/hover";
pending->callback = [](Editor *editor, std::string, json hover) {
{{"textDocument", {{"uri", this->uri}}},
{"position", {{"line", this->cursor.row}, {"character", col}}}}}};
message->editor = this;
message->callback = [](const LSPMessage &message) {
auto &hover = message.message;
if (hover.contains("result") && !hover["result"].is_null()) {
auto &contents = hover["result"]["contents"];
std::string hover_text = "";
@@ -340,23 +469,26 @@ void fetch_lsp_hover(Editor *editor) {
hover_text += contents.get<std::string>();
}
if (!hover_text.empty()) {
editor->hover.clear();
editor->hover.text = clean_text(hover_text);
editor->hover.is_markup = is_markup;
editor->hover.render_first();
editor->hover_active = true;
message.editor->hover_popup->clear();
message.editor->hover_popup->text = clean_text(hover_text);
message.editor->hover_popup->is_markup = is_markup;
message.editor->hover_popup->hidden = false;
}
}
};
lsp_send(editor->lsp, hover_request, pending);
lsp->send(std::move(message));
}
}
void handle_mouse(Editor *editor, KeyEvent event) {
void Editor::handle_click(KeyEvent event, Coord size) {
layout::focused_window = this;
this->size = size;
static std::chrono::steady_clock::time_point last_click_time =
std::chrono::steady_clock::now();
static uint32_t click_count = 0;
static Coord last_click_pos = {UINT32_MAX, UINT32_MAX};
if (!this->hover_popup->hidden)
this->hover_popup->hidden = true;
if (event.key_type == KEY_MOUSE) {
auto now = std::chrono::steady_clock::now();
auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(
@@ -366,18 +498,12 @@ void handle_mouse(Editor *editor, KeyEvent event) {
case SCROLL:
switch (event.mouse_direction) {
case SCROLL_UP:
scroll_up(editor, 4);
ensure_cursor(editor);
this->scroll_up(1);
this->ensure_cursor();
break;
case SCROLL_DOWN:
scroll_down(editor, 4);
ensure_cursor(editor);
break;
case SCROLL_LEFT:
cursor_left(editor, 10);
break;
case SCROLL_RIGHT:
cursor_right(editor, 10);
this->scroll_down(1);
this->ensure_cursor();
break;
}
break;
@@ -390,35 +516,35 @@ void handle_mouse(Editor *editor, KeyEvent event) {
click_count = 1;
last_click_time = now;
last_click_pos = cur_pos;
Coord p = editor_hit_test(editor, event.mouse_x, event.mouse_y);
Coord p = this->click_coord(event.mouse_x, event.mouse_y);
if (p.row == UINT32_MAX && p.col == UINT32_MAX)
return;
editor->cursor_preffered = UINT32_MAX;
this->cursor_preffered = UINT32_MAX;
if (click_count == 1) {
editor->cursor = p;
editor->selection = p;
this->cursor = p;
this->selection = p;
if (mode == SELECT) {
mode = NORMAL;
editor->selection_active = false;
this->selection_active = false;
}
} else if (click_count == 2) {
uint32_t prev_col, next_col;
word_boundaries(editor, editor->cursor, &prev_col, &next_col, nullptr,
nullptr);
if (editor->cursor < editor->selection)
editor->cursor = {editor->cursor.row, prev_col};
this->word_boundaries(this->cursor, &prev_col, &next_col, nullptr,
nullptr);
if (this->cursor < this->selection)
this->cursor = {this->cursor.row, prev_col};
else
editor->cursor = {editor->cursor.row, next_col};
editor->cursor_preffered = UINT32_MAX;
editor->selection_type = WORD;
this->cursor = {this->cursor.row, next_col};
this->cursor_preffered = UINT32_MAX;
this->selection_type = WORD;
mode = SELECT;
editor->selection_active = true;
this->selection_active = true;
} else if (click_count >= 3) {
if (editor->cursor < editor->selection) {
editor->cursor = {p.row, 0};
if (this->cursor < this->selection) {
this->cursor = {p.row, 0};
} else {
uint32_t line_len;
LineIterator *it = begin_l_iter(editor->root, p.row);
LineIterator *it = begin_l_iter(this->root, p.row);
char *line = next_line(it, &line_len);
if (!line)
return;
@@ -426,44 +552,44 @@ void handle_mouse(Editor *editor, KeyEvent event) {
line_len--;
free(it->buffer);
free(it);
editor->cursor = {p.row, line_len};
this->cursor = {p.row, line_len};
}
editor->cursor_preffered = UINT32_MAX;
editor->selection_type = LINE;
this->cursor_preffered = UINT32_MAX;
this->selection_type = LINE;
mode = SELECT;
editor->selection_active = true;
this->selection_active = true;
click_count = 3;
}
}
break;
case DRAG:
if (event.mouse_button == LEFT_BTN) {
Coord p = editor_hit_test(editor, event.mouse_x, event.mouse_y);
Coord p = this->click_coord(event.mouse_x, event.mouse_y);
if (p.row == UINT32_MAX && p.col == UINT32_MAX)
return;
editor->cursor_preffered = UINT32_MAX;
this->cursor_preffered = UINT32_MAX;
mode = SELECT;
if (!editor->selection_active) {
editor->selection_active = true;
editor->selection_type = CHAR;
if (!this->selection_active) {
this->selection_active = true;
this->selection_type = CHAR;
}
uint32_t prev_col, next_col, line_len;
switch (editor->selection_type) {
switch (this->selection_type) {
case CHAR:
editor->cursor = p;
this->cursor = p;
break;
case WORD:
word_boundaries(editor, p, &prev_col, &next_col, nullptr, nullptr);
if (editor->cursor < editor->selection)
editor->cursor = {p.row, prev_col};
this->word_boundaries(p, &prev_col, &next_col, nullptr, nullptr);
if (this->cursor < this->selection)
this->cursor = {p.row, prev_col};
else
editor->cursor = {p.row, next_col};
this->cursor = {p.row, next_col};
break;
case LINE:
if (editor->cursor < editor->selection) {
editor->cursor = {p.row, 0};
if (this->cursor < this->selection) {
this->cursor = {p.row, 0};
} else {
LineIterator *it = begin_l_iter(editor->root, p.row);
LineIterator *it = begin_l_iter(this->root, p.row);
char *line = next_line(it, &line_len);
if (!line)
return;
@@ -471,7 +597,7 @@ void handle_mouse(Editor *editor, KeyEvent event) {
line_len--;
free(it->buffer);
free(it);
editor->cursor = {p.row, line_len};
this->cursor = {p.row, line_len};
}
break;
}
@@ -479,10 +605,10 @@ void handle_mouse(Editor *editor, KeyEvent event) {
break;
case RELEASE:
if (event.mouse_button == LEFT_BTN)
if (editor->cursor.row == editor->selection.row &&
editor->cursor.col == editor->selection.col) {
if (this->cursor.row == this->selection.row &&
this->cursor.col == this->selection.col) {
mode = NORMAL;
editor->selection_active = false;
this->selection_active = false;
}
break;
}
+153 -69
View File
@@ -38,6 +38,18 @@ void IndentationEngine::compute_indent(Editor *n_editor) {
indent = 2;
free(it->buffer);
free(it);
auto x = kLangtoBlockStartsEnd.find(editor->lang.name);
if (x != kLangtoBlockStartsEnd.end())
start_end = &x->second;
x = kLangtoBlockStartsStart.find(editor->lang.name);
if (x != kLangtoBlockStartsStart.end())
start_start = &x->second;
x = kLangtoBlockEndsFull.find(editor->lang.name);
if (x != kLangtoBlockEndsFull.end())
end_full = &x->second;
x = kLangtoBlockEndsStart.find(editor->lang.name);
if (x != kLangtoBlockEndsStart.end())
end_start = &x->second;
}
uint32_t IndentationEngine::indent_real(char *line, uint32_t len) {
@@ -56,7 +68,6 @@ uint32_t IndentationEngine::indent_real(char *line, uint32_t len) {
}
uint32_t IndentationEngine::indent_expected(uint32_t row) {
std::shared_lock lock(editor->knot_mtx);
uint32_t line_idx = row;
if (row == 0)
return 0;
@@ -75,18 +86,16 @@ uint32_t IndentationEngine::indent_expected(uint32_t row) {
if (len == 0)
continue;
c_indent = indent_real(line, len);
auto is_end_set = kLangtoBlockStartsEnd.find(editor->lang.name);
auto is_start_set = kLangtoBlockStartsStart.find(editor->lang.name);
bool is_end = false;
if (is_end_set != kLangtoBlockStartsEnd.end())
for (auto end : is_end_set->second)
if (start_end)
for (auto end : *start_end)
if (ends_with(line, end)) {
c_indent++;
is_end = true;
break;
}
if (!is_end && is_start_set != kLangtoBlockStartsStart.end())
for (auto end : is_start_set->second)
if (!is_end && start_start)
for (auto end : *start_start)
if (starts_with(line, end)) {
c_indent++;
break;
@@ -99,7 +108,6 @@ uint32_t IndentationEngine::indent_expected(uint32_t row) {
}
uint32_t IndentationEngine::set_indent(uint32_t row, int64_t new_indent) {
std::shared_lock lock(editor->knot_mtx);
LineIterator *it = begin_l_iter(editor->root, row);
if (!it)
return 0;
@@ -112,7 +120,6 @@ uint32_t IndentationEngine::set_indent(uint32_t row, int64_t new_indent) {
}
if (len > 0 && line[len - 1] == '\n')
--len;
lock.unlock();
if (new_indent <= 0)
new_indent = 0;
uint32_t ws_len = 0;
@@ -125,14 +132,13 @@ uint32_t IndentationEngine::set_indent(uint32_t row, int64_t new_indent) {
new_ws.assign(new_indent * indent, ' ');
Coord start = {row, 0};
Coord end = {row, ws_len};
edit_replace(editor, start, end, new_ws.c_str(), new_ws.length());
editor->edit_replace(start, end, new_ws.c_str(), new_ws.length());
free(it->buffer);
free(it);
return len - ws_len + (new_indent * indent);
}
uint32_t IndentationEngine::indent_line(uint32_t row) {
std::shared_lock lock(editor->knot_mtx);
LineIterator *it = begin_l_iter(editor->root, row);
if (!it)
return 0;
@@ -143,7 +149,6 @@ uint32_t IndentationEngine::indent_line(uint32_t row) {
free(it);
return 0;
}
lock.unlock();
if (len > 0 && line[len - 1] == '\n')
--len;
uint32_t new_indent = indent_real(line, len) + 1;
@@ -155,15 +160,14 @@ uint32_t IndentationEngine::indent_line(uint32_t row) {
new_ws.assign(new_indent, '\t');
else
new_ws.assign(new_indent * indent, ' ');
edit_replace(editor, {row, 0}, {row, ws_len}, new_ws.c_str(),
new_indent * indent);
editor->edit_replace({row, 0}, {row, ws_len}, new_ws.c_str(),
new_indent * indent);
free(it->buffer);
free(it);
return (uint32_t)ABS((int64_t)ws_len - (new_indent * indent));
}
uint32_t IndentationEngine::dedent_line(uint32_t row) {
std::shared_lock lock(editor->knot_mtx);
LineIterator *it = begin_l_iter(editor->root, row);
if (!it)
return 0;
@@ -174,7 +178,6 @@ uint32_t IndentationEngine::dedent_line(uint32_t row) {
free(it);
return 0;
}
lock.unlock();
if (len > 0 && line[len - 1] == '\n')
--len;
int64_t new_indent = (int64_t)indent_real(line, len) - 1;
@@ -188,16 +191,107 @@ uint32_t IndentationEngine::dedent_line(uint32_t row) {
new_ws.assign(new_indent, '\t');
else
new_ws.assign(new_indent * indent, ' ');
edit_replace(editor, {row, 0}, {row, ws_len}, new_ws.c_str(),
new_indent * indent);
editor->edit_replace({row, 0}, {row, ws_len}, new_ws.c_str(),
new_indent * indent);
free(it->buffer);
free(it);
return (uint32_t)ABS((int64_t)ws_len - (new_indent * indent));
}
void IndentationEngine::indent_block(uint32_t start_row, uint32_t end_row) {
indent_block(start_row, end_row, +1);
}
void IndentationEngine::dedent_block(uint32_t start_row, uint32_t end_row) {
indent_block(start_row, end_row, -1);
}
void IndentationEngine::indent_block(uint32_t start_row, uint32_t end_row,
int delta) {
if (start_row > end_row)
std::swap(start_row, end_row);
uint32_t start_len, end_len;
uint32_t start_off = line_to_byte(editor->root, start_row, &start_len);
uint32_t end_off = line_to_byte(editor->root, end_row, &end_len);
uint32_t total_len = (end_off - start_off) + end_len;
char *block = read(editor->root, start_off, total_len);
if (!block)
return;
uint32_t cap = total_len + 128;
char *out = (char *)malloc(cap);
uint32_t out_len = 0;
char *p = block;
char *end = block + total_len;
while (p < end) {
char *line_start = p;
while (p < end && *p != '\n')
p++;
uint32_t len = (uint32_t)(p - line_start);
uint32_t ws = 0;
while (ws < len && (line_start[ws] == ' ' || line_start[ws] == '\t'))
ws++;
uint32_t real_indent = indent_real(line_start, len);
int64_t new_indent = (int64_t)real_indent + delta;
if (new_indent < 0)
new_indent = 0;
uint32_t indent_chars = (indent == 1) ? new_indent : new_indent * indent;
uint32_t new_line_len = indent_chars + (len - ws);
if (out_len + new_line_len + 2 >= cap) {
cap = (cap * 2) + new_line_len + 32;
out = (char *)realloc(out, cap);
}
if (indent == 1) {
memset(out + out_len, '\t', indent_chars);
out_len += indent_chars;
} else {
memset(out + out_len, ' ', indent_chars);
out_len += indent_chars;
}
memcpy(out + out_len, line_start + ws, len - ws);
out_len += (len - ws);
if (p < end && *p == '\n') {
out[out_len++] = '\n';
p++;
}
}
free(block);
editor->edit_replace({start_row, 0}, {end_row, end_len}, out, out_len);
free(out);
}
void IndentationEngine::insert_tab(Coord cursor) {
LineIterator *it = begin_l_iter(editor->root, cursor.row);
if (!it)
return;
uint32_t len;
char *line = next_line(it, &len);
if (!line) {
free(it->buffer);
free(it);
return;
}
if (len > 0 && line[len - 1] == '\n')
--len;
uint32_t ws_len = 0;
while (ws_len < len && (line[ws_len] == ' ' || line[ws_len] == '\t'))
ws_len++;
std::string insert;
if (cursor.col <= ws_len) {
if (indent == 1)
insert = "\t";
else
insert.assign(indent - ((cursor.col) % indent), ' ');
} else {
insert = "\t";
}
free(it->buffer);
free(it);
editor->edit_insert(cursor, (char *)insert.c_str(), insert.size());
editor->cursor.col += insert.size();
}
void IndentationEngine::insert_new_line(Coord cursor) {
std::string formatted;
std::shared_lock lock(editor->knot_mtx);
LineIterator *it = begin_l_iter(editor->root, cursor.row);
if (!it)
return;
@@ -208,29 +302,25 @@ void IndentationEngine::insert_new_line(Coord cursor) {
free(it);
return;
}
lock.unlock();
if (len > 0 && line[len - 1] == '\n')
--len;
if (cursor.col >= len) {
auto is_end_full = kLangtoBlockEndsFull.find(editor->lang.name);
auto is_end_start = kLangtoBlockEndsStart.find(editor->lang.name);
bool end_matched = false;
if (is_end_full != kLangtoBlockEndsFull.end())
for (auto end : is_end_full->second)
if (end_full)
for (auto end : *end_full)
if (end == trim(line)) {
cursor.col =
set_indent(cursor.row, (int64_t)indent_expected(cursor.row) - 1);
cursor.col = set_indent(
cursor.row, (int64_t)indent_expected(cursor.row) - (int64_t)1);
end_matched = true;
break;
}
if (!end_matched && is_end_start != kLangtoBlockEndsStart.end())
for (auto end : is_end_start->second)
if (!end_matched && end_start)
for (auto end : *end_start)
if (starts_with(trim(line), end)) {
cursor.col =
set_indent(cursor.row, (int64_t)indent_expected(cursor.row) - 1);
cursor.col = set_indent(
cursor.row, (int64_t)indent_expected(cursor.row) - (int64_t)1);
break;
}
lock.lock();
free(it->buffer);
free(it);
it = begin_l_iter(editor->root, cursor.row);
@@ -244,41 +334,35 @@ void IndentationEngine::insert_new_line(Coord cursor) {
}
if (len > 0 && line[len - 1] == '\n')
--len;
lock.unlock();
}
std::string ending = trim(std::string(line + cursor.col, len - cursor.col));
std::string before = trim(std::string(line, cursor.col));
uint32_t c_indent = indent_real(line, len);
int64_t c_indent = indent_real(line, len);
if (!ending.empty()) {
bool ending_valid = false;
bool starting_valid = false;
auto is_end_full = kLangtoBlockEndsFull.find(editor->lang.name);
auto is_end_start = kLangtoBlockEndsStart.find(editor->lang.name);
auto is_end_set = kLangtoBlockStartsEnd.find(editor->lang.name);
auto is_start_set = kLangtoBlockStartsStart.find(editor->lang.name);
if (is_end_full != kLangtoBlockEndsFull.end())
for (auto end : is_end_full->second)
if (end_full)
for (auto end : *end_full)
if (ending == end) {
ending_valid = true;
break;
}
if (!ending_valid && is_end_start != kLangtoBlockEndsStart.end())
for (auto end : is_end_start->second)
if (!ending_valid && end_start)
for (auto end : *end_start)
if (starts_with(ending, end)) {
ending_valid = true;
break;
}
if (is_end_set != kLangtoBlockStartsEnd.end())
for (auto end : is_end_set->second)
if (start_end)
for (auto end : *start_end)
if (ends_with(before, end)) {
c_indent++;
starting_valid = true;
break;
}
if (!starting_valid && is_start_set != kLangtoBlockStartsStart.end())
for (auto end : is_start_set->second)
if (!starting_valid && start_start)
for (auto end : *start_start)
if (starts_with(before, end)) {
c_indent++;
starting_valid = true;
break;
}
if (ending_valid && starting_valid)
@@ -289,36 +373,37 @@ void IndentationEngine::insert_new_line(Coord cursor) {
else if (ending_valid)
c_indent--;
}
auto is_end_set = kLangtoBlockStartsEnd.find(editor->lang.name);
auto is_start_set = kLangtoBlockStartsStart.find(editor->lang.name);
bool is_end = false;
if (is_end_set != kLangtoBlockStartsEnd.end())
for (auto end : is_end_set->second)
if (start_end)
for (auto end : *start_end)
if (ends_with(before, end)) {
c_indent++;
is_end = true;
break;
}
if (!is_end && is_start_set != kLangtoBlockStartsStart.end())
for (auto end : is_start_set->second)
if (!is_end && start_start)
for (auto end : *start_start)
if (starts_with(before, end)) {
c_indent++;
break;
}
if (c_indent < 0)
c_indent = 0;
formatted = "\n" +
(indent == 1 ? std::string(c_indent, '\t')
: std::string(c_indent * indent, ' ')) +
ending;
Coord new_cursor = {cursor.row + 1, c_indent * indent};
edit_replace(editor, cursor, {cursor.row, len}, formatted.data(),
formatted.size());
Coord new_cursor = {cursor.row + 1, (uint32_t)c_indent * indent};
editor->edit_replace(cursor, {cursor.row, len}, formatted.data(),
formatted.size());
editor->cursor = new_cursor;
editor->cursor_preffered = UINT32_MAX;
free(it->buffer);
free(it);
if (!editor->lsp || !editor->lsp->allow_formatting_on_type)
auto lsp = editor->lsp.load();
if (!lsp || !lsp->allow_formatting_on_type)
return;
for (char ch : editor->lsp->format_chars) {
for (char ch : lsp->format_chars) {
if (ch == '\n') {
LineIterator *it = begin_l_iter(editor->root, editor->cursor.row);
if (!it)
@@ -334,7 +419,9 @@ void IndentationEngine::insert_new_line(Coord cursor) {
free(it->buffer);
free(it);
int version = editor->lsp_version;
json message = {
auto message = std::make_unique<LSPMessage>();
message->editor = editor;
message->message = {
{"jsonrpc", "2.0"},
{"method", "textDocument/onTypeFormatting"},
{"params",
@@ -346,13 +433,10 @@ void IndentationEngine::insert_new_line(Coord cursor) {
{"insertSpaces", true},
{"trimTrailingWhitespace", true},
{"trimFinalNewlines", true}}}}}};
LSPPending *pending = new LSPPending();
pending->editor = editor;
pending->method = "textDocument/onTypeFormatting";
pending->callback = [version](Editor *editor, std::string, json message) {
if (version != editor->lsp_version)
message->callback = [version](const LSPMessage &message) {
if (version != message.editor->lsp_version)
return;
auto &edits = message["result"];
auto &edits = message.message["result"];
if (edits.is_array()) {
std::vector<TextEdit> t_edits;
t_edits.reserve(edits.size());
@@ -363,14 +447,14 @@ void IndentationEngine::insert_new_line(Coord cursor) {
t_edit.start.col = edit["range"]["start"]["character"];
t_edit.end.row = edit["range"]["end"]["line"];
t_edit.end.col = edit["range"]["end"]["character"];
utf8_normalize_edit(editor, &t_edit);
message.editor->utf8_normalize_edit(&t_edit);
t_edits.push_back(t_edit);
}
apply_lsp_edits(editor, t_edits, false);
ensure_scroll(editor);
message.editor->apply_lsp_edits(t_edits, false);
message.editor->ensure_scroll();
}
};
lsp_send(editor->lsp, message, pending);
lsp->send(std::move(message));
break;
}
}
+20 -26
View File
@@ -2,52 +2,47 @@
#include "editor/editor.h"
#include "utils/utils.h"
void apply_lsp_edits(Editor *editor, std::vector<TextEdit> edits, bool move) {
void Editor::apply_lsp_edits(std::vector<TextEdit> edits, bool move) {
if (!edits.size())
return;
TextEdit first = edits[0];
Coord cursor = editor->cursor;
Coord cursor = this->cursor;
std::sort(
edits.begin(), edits.end(),
[](const TextEdit &a, const TextEdit &b) { return a.start > b.start; });
for (const auto &edit : edits)
edit_replace(editor, edit.start, edit.end, edit.text.c_str(),
edit.text.size());
this->edit_replace(edit.start, edit.end, edit.text.c_str(),
edit.text.size());
if (move) {
std::shared_lock lock(editor->knot_mtx);
editor->cursor = first.start;
editor->cursor =
move_right(editor, editor->cursor,
count_clusters(first.text.c_str(), first.text.size(), 0,
first.text.size()));
this->cursor = first.start;
this->cursor = this->move_right(
this->cursor, count_clusters(first.text.c_str(), first.text.size(), 0,
first.text.size()));
} else {
if (cursor.row >= editor->root->line_count) {
editor->cursor.row = editor->root->line_count - 1;
editor->cursor.col = 0;
if (cursor.row >= this->root->line_count) {
this->cursor.row = this->root->line_count - 1;
this->cursor.col = 0;
} else {
std::shared_lock lock(editor->knot_mtx);
uint32_t len;
line_to_byte(editor->root, cursor.row, &len);
line_to_byte(this->root, cursor.row, &len);
len--;
editor->cursor.row = cursor.row;
editor->cursor.col = cursor.col < len ? cursor.col : len;
this->cursor.row = cursor.row;
this->cursor.col = cursor.col < len ? cursor.col : len;
}
}
}
void editor_lsp_handle(Editor *editor, json msg) {
void Editor::lsp_handle(json msg) {
if (msg.contains("method") &&
msg["method"] == "textDocument/publishDiagnostics") {
std::unique_lock lock(editor->v_mtx);
editor->warnings.clear();
this->warnings.clear();
json diagnostics = msg["params"]["diagnostics"];
for (size_t i = 0; i < diagnostics.size(); i++) {
json d = diagnostics[i];
VWarn w;
w.line = d["range"]["start"]["line"];
w.start = d["range"]["start"]["character"];
std::shared_lock lock(editor->knot_mtx);
LineIterator *it = begin_l_iter(editor->root, w.line);
LineIterator *it = begin_l_iter(this->root, w.line);
if (!it)
continue;
uint32_t len;
@@ -59,7 +54,6 @@ void editor_lsp_handle(Editor *editor, json msg) {
}
if (len > 0 && line[len - 1] == '\n')
--len;
lock.unlock();
w.start = utf16_offset_to_utf8(line, len, w.start);
uint32_t end = d["range"]["end"]["character"];
if (d["range"]["end"]["line"] == w.line)
@@ -102,9 +96,9 @@ void editor_lsp_handle(Editor *editor, json msg) {
w.type = 1;
if (d.contains("severity"))
w.type = d["severity"].get<int>();
editor->warnings.push_back(w);
this->warnings.push_back(w);
}
std::sort(editor->warnings.begin(), editor->warnings.end());
editor->warnings_dirty = true;
std::sort(this->warnings.begin(), this->warnings.end());
this->warnings_dirty = true;
}
}
+54 -66
View File
@@ -1,120 +1,108 @@
#include "editor/editor.h"
#include "main.h"
void move_line_up(Editor *editor) {
if (!editor || !editor->root || editor->cursor.row == 0)
void Editor::move_line_up() {
if (!this->root || this->cursor.row == 0)
return;
if (mode == NORMAL || mode == INSERT) {
uint32_t line_len, line_cluster_len;
std::shared_lock lock(editor->knot_mtx);
LineIterator *it = begin_l_iter(editor->root, editor->cursor.row);
LineIterator *it = begin_l_iter(this->root, this->cursor.row);
char *line = next_line(it, &line_len);
if (!line) {
lock.unlock();
if (!line)
return;
}
if (line_len > 0 && line[line_len - 1] == '\n')
line_len--;
line_cluster_len = count_clusters(line, line_len, 0, line_len);
uint32_t target_row = editor->cursor.row - 1;
uint32_t up_by = editor->cursor.row - target_row;
uint32_t target_row = this->cursor.row - 1;
uint32_t up_by = this->cursor.row - target_row;
if (up_by > 1)
up_by--;
lock.unlock();
Coord cursor = editor->cursor;
edit_erase(editor, {cursor.row, 0}, line_cluster_len);
edit_erase(editor, {cursor.row, 0}, -1);
edit_insert(editor, {cursor.row - up_by, 0}, (char *)"\n", 1);
edit_insert(editor, {cursor.row - up_by, 0}, line, line_len);
Coord cursor = this->cursor;
edit_erase({cursor.row, 0}, line_cluster_len);
edit_erase({cursor.row, 0}, -1);
edit_insert({cursor.row - up_by, 0}, (char *)"\n", 1);
edit_insert({cursor.row - up_by, 0}, line, line_len);
free(it->buffer);
free(it);
editor->cursor = {cursor.row - up_by, cursor.col};
this->cursor = {cursor.row - up_by, cursor.col};
} else if (mode == SELECT) {
uint32_t start_row = MIN(editor->cursor.row, editor->selection.row);
uint32_t end_row = MAX(editor->cursor.row, editor->selection.row);
uint32_t start_byte = line_to_byte(editor->root, start_row, nullptr);
uint32_t end_byte = line_to_byte(editor->root, end_row + 1, nullptr);
char *selected_text = read(editor->root, start_byte, end_byte - start_byte);
uint32_t start_row = MIN(this->cursor.row, this->selection.row);
uint32_t end_row = MAX(this->cursor.row, this->selection.row);
uint32_t start_byte = line_to_byte(this->root, start_row, nullptr);
uint32_t end_byte = line_to_byte(this->root, end_row + 1, nullptr);
char *selected_text = read(this->root, start_byte, end_byte - start_byte);
if (!selected_text)
return;
uint32_t selected_len = count_clusters(selected_text, end_byte - start_byte,
0, end_byte - start_byte);
Coord cursor = editor->cursor;
Coord selection = editor->selection;
edit_erase(editor, {start_row, 0}, selected_len);
edit_insert(editor, {start_row - 1, 0}, selected_text,
end_byte - start_byte);
Coord cursor = this->cursor;
Coord selection = this->selection;
edit_erase({start_row, 0}, selected_len);
edit_insert({start_row - 1, 0}, selected_text, end_byte - start_byte);
free(selected_text);
editor->cursor = {cursor.row - 1, cursor.col};
editor->selection = {selection.row - 1, selection.col};
this->cursor = {cursor.row - 1, cursor.col};
this->selection = {selection.row - 1, selection.col};
}
}
void move_line_down(Editor *editor) {
if (!editor || !editor->root)
void Editor::move_line_down() {
if (!this->root)
return;
if (mode == NORMAL || mode == INSERT) {
if (editor->cursor.row >= editor->root->line_count - 1)
if (this->cursor.row >= this->root->line_count - 1)
return;
uint32_t line_len, line_cluster_len;
std::shared_lock lock(editor->knot_mtx);
LineIterator *it = begin_l_iter(editor->root, editor->cursor.row);
LineIterator *it = begin_l_iter(this->root, this->cursor.row);
char *line = next_line(it, &line_len);
if (!line) {
lock.unlock();
if (!line)
return;
}
if (line_len && line[line_len - 1] == '\n')
line_len--;
line_cluster_len = count_clusters(line, line_len, 0, line_len);
uint32_t target_row = editor->cursor.row + 1;
if (target_row >= editor->root->line_count) {
free(line);
lock.unlock();
uint32_t target_row = this->cursor.row + 1;
if (target_row >= this->root->line_count) {
free(it->buffer);
free(it);
return;
}
uint32_t down_by = target_row - editor->cursor.row;
uint32_t down_by = target_row - this->cursor.row;
if (down_by > 1)
down_by--;
uint32_t ln;
line_to_byte(editor->root, editor->cursor.row + down_by - 1, &ln);
lock.unlock();
Coord cursor = editor->cursor;
edit_erase(editor, {cursor.row, 0}, line_cluster_len);
edit_erase(editor, {cursor.row, 0}, -1);
edit_insert(editor, {cursor.row + down_by, 0}, (char *)"\n", 1);
edit_insert(editor, {cursor.row + down_by, 0}, line, line_len);
line_to_byte(this->root, this->cursor.row + down_by - 1, &ln);
Coord cursor = this->cursor;
edit_erase({cursor.row, 0}, line_cluster_len);
edit_erase({cursor.row, 0}, -1);
edit_insert({cursor.row + down_by, 0}, (char *)"\n", 1);
edit_insert({cursor.row + down_by, 0}, line, line_len);
free(it->buffer);
free(it);
editor->cursor = {cursor.row + down_by, cursor.col};
this->cursor = {cursor.row + down_by, cursor.col};
} else if (mode == SELECT) {
if (editor->cursor.row >= editor->root->line_count - 1 ||
editor->selection.row >= editor->root->line_count - 1)
if (this->cursor.row >= this->root->line_count - 1 ||
this->selection.row >= this->root->line_count - 1)
return;
std::shared_lock lock(editor->knot_mtx);
uint32_t start_row = MIN(editor->cursor.row, editor->selection.row);
uint32_t end_row = MAX(editor->cursor.row, editor->selection.row);
uint32_t start_row = MIN(this->cursor.row, this->selection.row);
uint32_t end_row = MAX(this->cursor.row, this->selection.row);
uint32_t target_row = end_row + 1;
if (target_row >= editor->root->line_count)
if (target_row >= this->root->line_count)
return;
uint32_t down_by = target_row - end_row;
if (down_by > 1)
down_by--;
uint32_t start_byte = line_to_byte(editor->root, start_row, nullptr);
uint32_t end_byte = line_to_byte(editor->root, end_row + 1, nullptr);
char *selected_text = read(editor->root, start_byte, end_byte - start_byte);
lock.unlock();
uint32_t start_byte = line_to_byte(this->root, start_row, nullptr);
uint32_t end_byte = line_to_byte(this->root, end_row + 1, nullptr);
char *selected_text = read(this->root, start_byte, end_byte - start_byte);
if (!selected_text)
return;
uint32_t selected_len = count_clusters(selected_text, end_byte - start_byte,
0, end_byte - start_byte);
Coord cursor = editor->cursor;
Coord selection = editor->selection;
edit_erase(editor, {start_row, 0}, selected_len);
edit_insert(editor, {start_row + down_by, 0}, selected_text,
end_byte - start_byte);
Coord cursor = this->cursor;
Coord selection = this->selection;
edit_erase({start_row, 0}, selected_len);
edit_insert({start_row + down_by, 0}, selected_text, end_byte - start_byte);
free(selected_text);
editor->cursor = {cursor.row + down_by, cursor.col};
editor->selection = {selection.row + down_by, selection.col};
this->cursor = {cursor.row + down_by, cursor.col};
this->selection = {selection.row + down_by, selection.col};
}
}
+134 -163
View File
@@ -3,31 +3,18 @@
#include "main.h"
#include "syntax/decl.h"
#include "syntax/parser.h"
#include <cstdint>
void render_editor(Editor *editor) {
void Editor::render(std::vector<ScreenCell> &buffer, Coord size, Coord pos) {
this->size = size;
uint32_t sel_start = 0, sel_end = 0;
std::shared_lock knot_lock(editor->knot_mtx);
uint32_t numlen =
EXTRA_META + static_cast<int>(std::log10(editor->root->line_count + 1));
uint32_t render_width = editor->size.col - numlen;
uint32_t render_x = editor->position.col + numlen;
std::vector<std::pair<uint32_t, char>> v;
for (size_t i = 0; i < 94; ++i)
if (editor->hooks[i] != 0)
v.push_back({editor->hooks[i], '!' + i});
std::sort(v.begin(), v.end());
auto hook_it = v.begin();
while (hook_it != v.end() && hook_it->first <= editor->scroll.row)
++hook_it;
std::unique_lock warn_lock(editor->v_mtx);
auto warn_it = editor->warnings.begin();
while (warn_it != editor->warnings.end() &&
warn_it->line < editor->scroll.row)
EXTRA_META + static_cast<int>(std::log10(this->root->line_count + 1));
uint32_t render_width = size.col - numlen - 1;
uint32_t render_x = pos.col + numlen + 1;
this->hooks.start_iter(this->scroll.row);
auto warn_it = this->warnings.begin();
while (warn_it != this->warnings.end() && warn_it->line < this->scroll.row)
++warn_it;
std::unique_lock<std::mutex> lock;
if (editor->parser)
lock = std::unique_lock<std::mutex>(editor->parser->mutex);
LineData *line_data = nullptr;
auto get_type = [&](uint32_t col) {
if (!line_data)
@@ -37,40 +24,54 @@ void render_editor(Editor *editor) {
return (int)token.type;
return 0;
};
if (editor->selection_active) {
Coord screen = {io::rows, io::cols};
auto update = [&](uint32_t row, uint32_t col, std::string text, uint32_t fg,
uint32_t bg, uint8_t flags, uint32_t u_color,
uint32_t width) {
if (row >= screen.row || col >= screen.col)
return;
ScreenCell &c = buffer[row * screen.col + col];
c.utf8 = text;
c.width = width;
c.fg = fg;
c.bg = bg;
c.flags = flags;
c.ul_color = u_color;
};
if (this->selection_active) {
Coord start, end;
if (editor->cursor >= editor->selection) {
if (this->cursor >= this->selection) {
uint32_t prev_col, next_col;
switch (editor->selection_type) {
switch (this->selection_type) {
case CHAR:
start = editor->selection;
end = move_right(editor, editor->cursor, 1);
start = this->selection;
end = this->move_right(this->cursor, 1);
break;
case WORD:
word_boundaries(editor, editor->selection, &prev_col, &next_col,
nullptr, nullptr);
start = {editor->selection.row, prev_col};
end = editor->cursor;
this->word_boundaries(this->selection, &prev_col, &next_col, nullptr,
nullptr);
start = {this->selection.row, prev_col};
end = this->cursor;
break;
case LINE:
start = {editor->selection.row, 0};
end = editor->cursor;
start = {this->selection.row, 0};
end = this->cursor;
break;
}
} else {
start = editor->cursor;
start = this->cursor;
uint32_t prev_col, next_col, line_len;
switch (editor->selection_type) {
switch (this->selection_type) {
case CHAR:
end = move_right(editor, editor->selection, 1);
end = this->move_right(this->selection, 1);
break;
case WORD:
word_boundaries(editor, editor->selection, &prev_col, &next_col,
nullptr, nullptr);
end = {editor->selection.row, next_col};
this->word_boundaries(this->selection, &prev_col, &next_col, nullptr,
nullptr);
end = {this->selection.row, next_col};
break;
case LINE:
LineIterator *it = begin_l_iter(editor->root, editor->selection.row);
LineIterator *it = begin_l_iter(this->root, this->selection.row);
char *line = next_line(it, &line_len);
if (!line)
return;
@@ -78,41 +79,37 @@ void render_editor(Editor *editor) {
line_len--;
free(it->buffer);
free(it);
end = {editor->selection.row, line_len};
end = {this->selection.row, line_len};
break;
}
}
sel_start = line_to_byte(editor->root, start.row, nullptr) + start.col;
sel_end = line_to_byte(editor->root, end.row, nullptr) + end.col;
sel_start = line_to_byte(this->root, start.row, nullptr) + start.col;
sel_end = line_to_byte(this->root, end.row, nullptr) + end.col;
}
Coord cursor = {UINT32_MAX, UINT32_MAX};
uint32_t line_index = editor->scroll.row;
LineIterator *it = begin_l_iter(editor->root, line_index);
uint32_t line_index = this->scroll.row;
LineIterator *it = begin_l_iter(this->root, line_index);
if (!it)
return;
uint32_t prev_col, next_col;
std::string word;
word_boundaries_exclusive(editor, editor->cursor, &prev_col, &next_col);
this->word_boundaries_exclusive(this->cursor, &prev_col, &next_col);
if (next_col - prev_col > 0 && next_col - prev_col < 256 - 4) {
uint32_t offset = line_to_byte(editor->root, editor->cursor.row, nullptr);
char *word_ptr = read(editor->root, offset + prev_col, next_col - prev_col);
uint32_t offset = line_to_byte(this->root, this->cursor.row, nullptr);
char *word_ptr = read(this->root, offset + prev_col, next_col - prev_col);
if (word_ptr) {
word = std::string(word_ptr, next_col - prev_col);
free(word_ptr);
}
}
editor->extra_hl.render(editor->root, line_index, word, editor->is_css_color);
this->extra_hl.render(this->root, line_index, word, this->is_css_color);
uint32_t rendered_rows = 0;
uint32_t global_byte_offset = line_to_byte(editor->root, line_index, nullptr);
while (rendered_rows < editor->size.row) {
uint32_t global_byte_offset = line_to_byte(this->root, line_index, nullptr);
while (rendered_rows < this->size.row) {
uint32_t line_len;
char *line = next_line(it, &line_len);
if (editor->parser) {
if (line_data)
line_data = editor->parser->line_tree.next();
else
line_data = editor->parser->line_tree.start_iter(line_index);
}
if (this->parser)
line_data = this->parser->line_map.at(line_index);
if (!line)
break;
if (line_len > 0 && line[line_len - 1] == '\n')
@@ -126,56 +123,46 @@ void render_editor(Editor *editor) {
(line[content_start] == ' ' || line[content_start] == '\t'))
content_start++;
std::vector<VWarn> line_warnings;
while (warn_it != editor->warnings.end() && warn_it->line == line_index) {
while (warn_it != this->warnings.end() && warn_it->line == line_index) {
line_warnings.push_back(*warn_it);
++warn_it;
}
uint32_t current_byte_offset = 0;
if (rendered_rows == 0)
current_byte_offset += editor->scroll.col;
while (current_byte_offset < line_len && rendered_rows < editor->size.row) {
uint32_t color = editor->cursor.row == line_index ? 0x222222 : 0;
current_byte_offset += this->scroll.col;
while (current_byte_offset < line_len && rendered_rows < this->size.row) {
uint32_t color = this->cursor.row == line_index ? 0x222222 : 0;
if (current_byte_offset == 0 || rendered_rows == 0) {
const char *hook = nullptr;
char h[2] = {0, 0};
if (hook_it != v.end() && hook_it->first == line_index + 1) {
h[0] = hook_it->second;
hook = h;
hook_it++;
}
update(editor->position.row + rendered_rows, editor->position.col, hook,
0xAAAAAA, 0, 0);
char hook = this->hooks.next(line_index);
update(pos.row + rendered_rows, pos.col, {hook, 0}, 0xAAAAAA, 0, 0, 0,
1);
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 =
editor->cursor.row == line_index ? 0xFFFFFF : 0x555555;
this->cursor.row == line_index ? 0xFFFFFF : 0x555555;
for (int i = 0; i < len; i++)
update(editor->position.row + rendered_rows,
editor->position.col + i + 2, (char[2]){buf[i], 0}, num_color,
0, 0);
update(pos.row + rendered_rows, pos.col + i, (char[2]){buf[i], 0},
num_color, 0, 0, 0, 1);
} else {
for (uint32_t i = 0; i < numlen; i++)
update(editor->position.row + rendered_rows, editor->position.col + i,
" ", 0, 0, 0);
for (uint32_t i = 0; i < numlen + 1; i++)
update(pos.row + rendered_rows, pos.col + i, " ", 0, 0, 0, 0, 1);
}
uint32_t col = 0;
uint32_t local_render_offset = 0;
uint32_t line_left = line_len - current_byte_offset;
while (line_left > 0 && col < render_width) {
if (line_index == editor->cursor.row &&
editor->cursor.col == (current_byte_offset + local_render_offset)) {
cursor.row = editor->position.row + rendered_rows;
if (line_index == this->cursor.row &&
this->cursor.col == (current_byte_offset + local_render_offset)) {
cursor.row = pos.row + rendered_rows;
cursor.col = render_x + col;
}
uint32_t absolute_byte_pos =
global_byte_offset + current_byte_offset + local_render_offset;
const Highlight *hl = nullptr;
if (editor->parser)
if (this->parser)
hl = &highlights[get_type(current_byte_offset + local_render_offset)];
std::optional<std::pair<uint32_t, uint32_t>> extra =
editor->extra_hl.get(
{line_index, current_byte_offset + local_render_offset});
std::optional<std::pair<uint32_t, uint32_t>> extra = this->extra_hl.get(
{line_index, current_byte_offset + local_render_offset});
uint32_t fg = extra && extra->second != UINT32_MAX
? extra->first
: (hl ? hl->fg : 0xFFFFFF);
@@ -186,7 +173,7 @@ void render_editor(Editor *editor) {
(hl ? hl->flags : 0) |
(extra ? (extra->second != UINT32_MAX ? CF_BOLD : CF_UNDERLINE)
: 0);
if (editor->selection_active && absolute_byte_pos >= sel_start &&
if (this->selection_active && absolute_byte_pos >= sel_start &&
absolute_byte_pos < sel_end)
bg = bg | 0x555555;
uint32_t u_color = 0;
@@ -222,40 +209,39 @@ void render_editor(Editor *editor) {
break;
if (current_byte_offset + local_render_offset >= content_start &&
current_byte_offset + local_render_offset < content_end) {
update(editor->position.row + rendered_rows, render_x + col,
cluster.c_str(), fg, bg | color, fl, u_color);
update(pos.row + rendered_rows, render_x + col, cluster.c_str(), fg,
bg | color, fl, u_color, width);
} else {
if (cluster[0] == ' ') {
update(editor->position.row + rendered_rows, render_x + col, "·",
0x282828, bg | color, fl, u_color);
update(pos.row + rendered_rows, render_x + col, "·", 0x282828,
bg | color, fl, u_color, 1);
} else {
update(editor->position.row + rendered_rows, render_x + col, "-> ",
0x282828, bg | color, (fl & ~CF_BOLD) | CF_ITALIC, u_color);
update(pos.row + rendered_rows, render_x + col, "-> ", 0x282828,
bg | color, (fl & ~CF_BOLD) | CF_ITALIC, u_color, 4);
}
}
local_render_offset += cluster_len;
line_left -= cluster_len;
col += width;
while (width-- > 1)
update(editor->position.row + rendered_rows, render_x + col - width,
"\x1b", fg, bg | color, fl);
update(pos.row + rendered_rows, render_x + col - width, "\x1b", fg,
bg | color, fl, u_color, 0);
}
if (line_index == editor->cursor.row &&
editor->cursor.col == (current_byte_offset + local_render_offset)) {
cursor.row = editor->position.row + rendered_rows;
if (line_index == this->cursor.row &&
this->cursor.col == (current_byte_offset + local_render_offset)) {
cursor.row = pos.row + rendered_rows;
cursor.col = render_x + col;
}
if (editor->selection_active &&
if (this->selection_active &&
global_byte_offset + line_len + 1 > sel_start &&
global_byte_offset + line_len + 1 <= sel_end && col < render_width) {
update(editor->position.row + rendered_rows, render_x + col, " ", 0,
0x555555 | color, 0);
update(pos.row + rendered_rows, render_x + col, " ", 0,
0x555555 | color, 0, 0, 1);
col++;
}
if (!line_warnings.empty() && line_left == 0) {
VWarn warn = line_warnings.front();
update(editor->position.row + rendered_rows, render_x + col, " ", 0,
color, 0);
update(pos.row + rendered_rows, render_x + col, " ", 0, color, 0, 0, 1);
col++;
for (size_t i = 0; i < line_warnings.size(); i++) {
if (line_warnings[i].type < warn.type)
@@ -281,18 +267,18 @@ void render_editor(Editor *editor) {
goto final;
final:
if (col < render_width) {
update(editor->position.row + rendered_rows, render_x + col,
err_sym, fg_color, color, 0);
update(pos.row + rendered_rows, render_x + col, err_sym, fg_color,
color, 0, 0, 1);
col++;
update(editor->position.row + rendered_rows, render_x + col, " ",
fg_color, color, 0);
update(pos.row + rendered_rows, render_x + col, " ", fg_color,
color, 0, 0, 1);
col++;
}
}
}
if (col < render_width) {
update(editor->position.row + rendered_rows, render_x + col, " ", 0,
0 | color, 0);
update(pos.row + rendered_rows, render_x + col, " ", 0, 0 | color, 0,
0, 1);
col++;
}
size_t warn_idx = 0;
@@ -318,19 +304,19 @@ void render_editor(Editor *editor) {
int width = display_width(cluster.c_str(), cluster_len);
if (col + width > render_width)
break;
update(editor->position.row + rendered_rows, render_x + col,
cluster.c_str(), fg_color, color, 0);
update(pos.row + rendered_rows, render_x + col, cluster.c_str(),
fg_color, color, 0, 0, width);
col += width;
warn_idx += cluster_len;
while (width-- > 1)
update(editor->position.row + rendered_rows, render_x + col - width,
"\x1b", fg_color, color, 0);
update(pos.row + rendered_rows, render_x + col - width, "\x1b",
fg_color, color, 0, 0, 0);
}
line_warnings.clear();
}
while (col < render_width) {
update(editor->position.row + rendered_rows, render_x + col, " ", 0,
0 | color, 0);
update(pos.row + rendered_rows, render_x + col, " ", 0, 0 | color, 0, 0,
1);
col++;
}
rendered_rows++;
@@ -338,40 +324,30 @@ void render_editor(Editor *editor) {
}
if (line_len == 0 ||
(current_byte_offset >= line_len && rendered_rows == 0)) {
uint32_t color = editor->cursor.row == line_index ? 0x222222 : 0;
const char *hook = nullptr;
char h[2] = {0, 0};
if (hook_it != v.end() && hook_it->first == line_index + 1) {
h[0] = hook_it->second;
hook = h;
hook_it++;
}
update(editor->position.row + rendered_rows, editor->position.col, hook,
0xAAAAAA, 0, 0);
uint32_t color = this->cursor.row == line_index ? 0x222222 : 0;
char hook = this->hooks.next(line_index);
update(pos.row + rendered_rows, pos.col, {hook, 0}, 0xAAAAAA, 0, 0, 0, 1);
char buf[16];
int len = snprintf(buf, sizeof(buf), "%*u ", numlen - 3, line_index + 1);
uint32_t num_color =
editor->cursor.row == line_index ? 0xFFFFFF : 0x555555;
int len = snprintf(buf, sizeof(buf), "%*u ", numlen, line_index + 1);
uint32_t num_color = this->cursor.row == line_index ? 0xFFFFFF : 0x555555;
for (int i = 0; i < len; i++)
update(editor->position.row + rendered_rows,
editor->position.col + i + 2, (char[2]){buf[i], 0}, num_color, 0,
0);
if (editor->cursor.row == line_index) {
cursor.row = editor->position.row + rendered_rows;
update(pos.row + rendered_rows, pos.col + i, (char[2]){buf[i], 0},
num_color, 0, 0, 0, 1);
if (this->cursor.row == line_index) {
cursor.row = pos.row + rendered_rows;
cursor.col = render_x;
}
uint32_t col = 0;
if (editor->selection_active &&
if (this->selection_active &&
global_byte_offset + line_len + 1 > sel_start &&
global_byte_offset + line_len + 1 <= sel_end) {
update(editor->position.row + rendered_rows, render_x + col, " ", 0,
0x555555 | color, 0);
update(pos.row + rendered_rows, render_x + col, " ", 0,
0x555555 | color, 0, 0, 1);
col++;
}
if (!line_warnings.empty()) {
VWarn warn = line_warnings.front();
update(editor->position.row + rendered_rows, render_x + col, " ", 0,
color, 0);
update(pos.row + rendered_rows, render_x + col, " ", 0, color, 0, 0, 1);
col++;
for (size_t i = 0; i < line_warnings.size(); i++) {
if (line_warnings[i].type < warn.type)
@@ -397,18 +373,18 @@ void render_editor(Editor *editor) {
goto final2;
final2:
if (col < render_width) {
update(editor->position.row + rendered_rows, render_x + col,
err_sym, fg_color, color, 0);
update(pos.row + rendered_rows, render_x + col, err_sym, fg_color,
color, 0, 0, 1);
col++;
update(editor->position.row + rendered_rows, render_x + col, " ",
fg_color, color, 0);
update(pos.row + rendered_rows, render_x + col, " ", fg_color,
color, 0, 0, 1);
col++;
}
}
}
if (col < render_width) {
update(editor->position.row + rendered_rows, render_x + col, " ", 0,
0 | color, 0);
update(pos.row + rendered_rows, render_x + col, " ", 0, 0 | color, 0,
0, 1);
col++;
}
size_t warn_idx = 0;
@@ -434,18 +410,18 @@ void render_editor(Editor *editor) {
int width = display_width(cluster.c_str(), cluster_len);
if (col + width > render_width)
break;
update(editor->position.row + rendered_rows, render_x + col,
cluster.c_str(), fg_color, color, 0);
update(pos.row + rendered_rows, render_x + col, cluster.c_str(),
fg_color, color, 0, 0, width);
col += width;
warn_idx += cluster_len;
while (width-- > 1)
update(editor->position.row + rendered_rows, render_x + col - width,
"\x1b", fg_color, color, 0);
update(pos.row + rendered_rows, render_x + col - width, "\x1b",
fg_color, color, 0, 0, 0);
}
}
while (col < render_width) {
update(editor->position.row + rendered_rows, render_x + col, " ", 0,
0 | color, 0);
update(pos.row + rendered_rows, render_x + col, " ", 0, 0 | color, 0, 0,
1);
col++;
}
rendered_rows++;
@@ -453,12 +429,9 @@ void render_editor(Editor *editor) {
global_byte_offset += line_len + 1;
line_index++;
}
if (lock.owns_lock())
lock.unlock();
while (rendered_rows < editor->size.row) {
for (uint32_t col = 0; col < editor->size.col; col++)
update(editor->position.row + rendered_rows, editor->position.col + col,
" ", 0xFFFFFF, 0, 0);
while (rendered_rows < this->size.row) {
for (uint32_t col = 0; col < this->size.col; col++)
update(pos.row + rendered_rows, pos.col + col, " ", 0xFFFFFF, 0, 0, 0, 1);
rendered_rows++;
}
if (cursor.row != UINT32_MAX && cursor.col != UINT32_MAX) {
@@ -476,15 +449,13 @@ void render_editor(Editor *editor) {
break;
}
set_cursor(cursor.row, cursor.col, type, true);
if (editor->completion.active && !editor->completion.box.hidden)
editor->completion.box.render(cursor);
else if (editor->hover_active)
editor->hover.render(cursor);
else if (editor->diagnostics_active)
editor->diagnostics.render(cursor);
if (!this->hover_popup->hidden)
this->hover_popup->pos = cursor;
if (!this->diagnostic_popup->hidden)
this->diagnostic_popup->pos = cursor;
}
free(it->buffer);
free(it);
if (editor->parser)
editor->parser->scroll(line_index + 5);
if (this->parser)
this->parser->scroll(line_index + 5);
}
+22 -23
View File
@@ -1,13 +1,13 @@
#include "editor/editor.h"
void scroll_up(Editor *editor, int32_t number) {
if (!editor || number == 0)
void Editor::scroll_up(uint32_t number) {
if (number == 0)
return;
uint32_t numlen =
EXTRA_META + static_cast<int>(std::log10(editor->root->line_count + 1));
uint32_t render_width = editor->size.col - numlen;
uint32_t line_index = editor->scroll.row;
LineIterator *it = begin_l_iter(editor->root, line_index);
EXTRA_META + static_cast<int>(std::log10(this->root->line_count + 1));
uint32_t render_width = this->size.col - numlen;
uint32_t line_index = this->scroll.row;
LineIterator *it = begin_l_iter(this->root, line_index);
if (!it)
return;
uint32_t len;
@@ -23,10 +23,9 @@ void scroll_up(Editor *editor, int32_t number) {
uint32_t col = 0;
std::vector<uint32_t> segment_starts;
segment_starts.reserve(16);
if (current_byte_offset < editor->scroll.col)
if (current_byte_offset < this->scroll.col)
segment_starts.push_back(0);
while (current_byte_offset < editor->scroll.col &&
current_byte_offset < len) {
while (current_byte_offset < this->scroll.col && current_byte_offset < len) {
uint32_t cluster_len = grapheme_next_character_break_utf8(
line + current_byte_offset, len - current_byte_offset);
int width = display_width(line + current_byte_offset, cluster_len);
@@ -40,7 +39,7 @@ void scroll_up(Editor *editor, int32_t number) {
for (auto it_seg = segment_starts.rbegin(); it_seg != segment_starts.rend();
++it_seg) {
if (--number == 0) {
editor->scroll = {line_index, *it_seg};
this->scroll = {line_index, *it_seg};
free(it->buffer);
free(it);
return;
@@ -48,7 +47,7 @@ void scroll_up(Editor *editor, int32_t number) {
}
line = prev_line(it, &len);
if (!line) {
editor->scroll = {0, 0};
this->scroll = {0, 0};
free(it->buffer);
free(it);
return;
@@ -57,7 +56,7 @@ void scroll_up(Editor *editor, int32_t number) {
line_index--;
line = prev_line(it, &len);
if (!line) {
editor->scroll = {0, 0};
this->scroll = {0, 0};
free(it->buffer);
free(it);
return;
@@ -83,7 +82,7 @@ void scroll_up(Editor *editor, int32_t number) {
for (auto it_seg = segment_starts.rbegin(); it_seg != segment_starts.rend();
++it_seg) {
if (--number == 0) {
editor->scroll = {line_index, *it_seg};
this->scroll = {line_index, *it_seg};
free(it->buffer);
free(it);
return;
@@ -94,17 +93,17 @@ void scroll_up(Editor *editor, int32_t number) {
free(it);
}
void scroll_down(Editor *editor, uint32_t number) {
if (!editor || number == 0)
void Editor::scroll_down(uint32_t number) {
if (number == 0)
return;
uint32_t numlen =
EXTRA_META + static_cast<int>(std::log10(editor->root->line_count + 1));
uint32_t render_width = editor->size.col - numlen;
uint32_t line_index = editor->scroll.row;
LineIterator *it = begin_l_iter(editor->root, line_index);
EXTRA_META + static_cast<int>(std::log10(this->root->line_count + 1));
uint32_t render_width = this->size.col - numlen;
uint32_t line_index = this->scroll.row;
LineIterator *it = begin_l_iter(this->root, line_index);
if (!it)
return;
const uint32_t max_visual_lines = editor->size.row;
const uint32_t max_visual_lines = this->size.row;
Coord *scroll_queue = (Coord *)malloc(sizeof(Coord) * max_visual_lines);
uint32_t q_head = 0;
uint32_t q_size = 0;
@@ -119,7 +118,7 @@ void scroll_down(Editor *editor, uint32_t number) {
line_len--;
uint32_t current_byte_offset = 0;
if (first_visual_line) {
current_byte_offset += editor->scroll.col;
current_byte_offset += this->scroll.col;
first_visual_line = false;
}
while (current_byte_offset < line_len ||
@@ -134,7 +133,7 @@ void scroll_down(Editor *editor, uint32_t number) {
}
visual_seen++;
if (visual_seen >= number + max_visual_lines) {
editor->scroll = scroll_queue[q_head];
this->scroll = scroll_queue[q_head];
free(scroll_queue);
free(it->buffer);
free(it);
@@ -162,7 +161,7 @@ void scroll_down(Editor *editor, uint32_t number) {
}
if (q_size > 0) {
uint32_t advance = (q_size > number) ? number : (q_size - 1);
editor->scroll = scroll_queue[(q_head + advance) % max_visual_lines];
this->scroll = scroll_queue[(q_head + advance) % max_visual_lines];
}
free(it->buffer);
free(it);
+41 -43
View File
@@ -1,47 +1,46 @@
#include "editor/editor.h"
#include "utils/utils.h"
void selection_bounds(Editor *editor, Coord *out_start, Coord *out_end) {
std::shared_lock lock(editor->knot_mtx);
void Editor::selection_bounds(Coord *out_start, Coord *out_end) {
Coord start, end;
if (editor->cursor >= editor->selection) {
if (this->cursor >= this->selection) {
uint32_t prev_col;
switch (editor->selection_type) {
switch (this->selection_type) {
case CHAR:
start = editor->selection;
end = move_right(editor, editor->cursor, 1);
start = this->selection;
end = this->move_right(this->cursor, 1);
break;
case WORD:
word_boundaries(editor, editor->selection, &prev_col, nullptr, nullptr,
nullptr);
start = {editor->selection.row, prev_col};
end = editor->cursor;
this->word_boundaries(this->selection, &prev_col, nullptr, nullptr,
nullptr);
start = {this->selection.row, prev_col};
end = this->cursor;
break;
case LINE:
start = {editor->selection.row, 0};
end = editor->cursor;
start = {this->selection.row, 0};
end = this->cursor;
break;
}
} else {
start = editor->cursor;
start = this->cursor;
uint32_t next_col, line_len;
switch (editor->selection_type) {
switch (this->selection_type) {
case CHAR:
end = move_right(editor, editor->selection, 1);
end = this->move_right(this->selection, 1);
break;
case WORD:
word_boundaries(editor, editor->selection, nullptr, &next_col, nullptr,
nullptr);
end = {editor->selection.row, next_col};
this->word_boundaries(this->selection, nullptr, &next_col, nullptr,
nullptr);
end = {this->selection.row, next_col};
break;
case LINE:
LineIterator *it = begin_l_iter(editor->root, editor->selection.row);
LineIterator *it = begin_l_iter(this->root, this->selection.row);
char *line = next_line(it, &line_len);
if (!line)
return;
if (line_len > 0 && line[line_len - 1] == '\n')
line_len--;
end = {editor->selection.row, line_len};
end = {this->selection.row, line_len};
free(it->buffer);
free(it);
break;
@@ -53,47 +52,46 @@ void selection_bounds(Editor *editor, Coord *out_start, Coord *out_end) {
*out_end = end;
}
char *get_selection(Editor *editor, uint32_t *out_len, Coord *out_start) {
std::shared_lock lock(editor->knot_mtx);
char *Editor::get_selection(uint32_t *out_len, Coord *out_start) {
Coord start, end;
if (editor->cursor >= editor->selection) {
if (this->cursor >= this->selection) {
uint32_t prev_col;
switch (editor->selection_type) {
switch (this->selection_type) {
case CHAR:
start = editor->selection;
end = move_right(editor, editor->cursor, 1);
start = this->selection;
end = this->move_right(this->cursor, 1);
break;
case WORD:
word_boundaries(editor, editor->selection, &prev_col, nullptr, nullptr,
nullptr);
start = {editor->selection.row, prev_col};
end = editor->cursor;
this->word_boundaries(this->selection, &prev_col, nullptr, nullptr,
nullptr);
start = {this->selection.row, prev_col};
end = this->cursor;
break;
case LINE:
start = {editor->selection.row, 0};
end = editor->cursor;
start = {this->selection.row, 0};
end = this->cursor;
break;
}
} else {
start = editor->cursor;
start = this->cursor;
uint32_t next_col, line_len;
switch (editor->selection_type) {
switch (this->selection_type) {
case CHAR:
end = move_right(editor, editor->selection, 1);
end = this->move_right(this->selection, 1);
break;
case WORD:
word_boundaries(editor, editor->selection, nullptr, &next_col, nullptr,
nullptr);
end = {editor->selection.row, next_col};
this->word_boundaries(this->selection, nullptr, &next_col, nullptr,
nullptr);
end = {this->selection.row, next_col};
break;
case LINE:
LineIterator *it = begin_l_iter(editor->root, editor->selection.row);
LineIterator *it = begin_l_iter(this->root, this->selection.row);
char *line = next_line(it, &line_len);
if (!line)
return nullptr;
if (line_len > 0 && line[line_len - 1] == '\n')
line_len--;
end = {editor->selection.row, line_len};
end = {this->selection.row, line_len};
free(it->buffer);
free(it);
break;
@@ -102,9 +100,9 @@ char *get_selection(Editor *editor, uint32_t *out_len, Coord *out_start) {
if (out_start)
*out_start = start;
uint32_t start_byte =
line_to_byte(editor->root, start.row, nullptr) + start.col;
uint32_t end_byte = line_to_byte(editor->root, end.row, nullptr) + end.col;
char *text = read(editor->root, start_byte, end_byte - start_byte);
line_to_byte(this->root, start.row, nullptr) + start.col;
uint32_t end_byte = line_to_byte(this->root, end.row, nullptr) + end.col;
char *text = read(this->root, start_byte, end_byte - start_byte);
if (out_len)
*out_len = end_byte - start_byte;
return text;
+13 -15
View File
@@ -1,7 +1,6 @@
#include "editor/editor.h"
void hover_diagnostic(Editor *editor) {
std::shared_lock lock(editor->v_mtx);
static uint32_t last_line = UINT32_MAX;
if (last_line == editor->cursor.row && !editor->warnings_dirty)
return;
@@ -15,23 +14,22 @@ void hover_diagnostic(Editor *editor) {
std::upper_bound(editor->warnings.begin(), editor->warnings.end(), dummy);
std::vector<VWarn> warnings_at_line(first, last);
if (warnings_at_line.size() == 0) {
editor->diagnostics_active = false;
editor->diagnostic_popup->hidden = true;
return;
}
editor->diagnostics.clear();
editor->diagnostics.warnings.swap(warnings_at_line);
editor->diagnostics.render_first();
editor->diagnostics_active = true;
editor->diagnostic_popup->clear();
editor->diagnostic_popup->warnings.swap(warnings_at_line);
editor->diagnostic_popup->hidden = false;
}
void editor_worker(Editor *editor) {
if (!editor || !editor->root)
void Editor::work() {
if (!this->root)
return;
if (editor->parser)
editor->parser->work();
hover_diagnostic(editor);
if (editor->completion.active && editor->completion.hover_dirty) {
editor->completion.hover.render_first();
editor->completion.hover_dirty = false;
}
if (this->parser)
this->parser->work();
hover_diagnostic(this);
// if (this->completion.active && this->completion.hover_dirty) {
// this->completion.hover.render_first();
// this->completion.hover_dirty = false;
// }
}
@@ -1,12 +1,33 @@
#include "ui/diagnostics.h"
#include "extentions/diagnostics.h"
void DiagnosticBox::clear() {
warnings.clear();
cells.clear();
size = {0, 0};
};
DiagnosticBox *init_diagnostic() {
auto diagnostic = std::make_unique<DiagnosticBox>();
diagnostic->pos = {0, 0};
diagnostic->size = {1, 1};
diagnostic->hidden = true;
DiagnosticBox *ptr = diagnostic.get();
layout::popups.push_back(std::move(diagnostic));
return ptr;
}
void DiagnosticBox::render_first() {
// TODO: Make this code more readable, It works fine tho.
void DiagnosticBox::render(std::vector<ScreenCell> &buffer, Coord n_size,
Coord n_pos) {
pos = n_pos;
size = n_size;
int32_t start_row = (int32_t)pos.row - (int32_t)size.row;
if (start_row < 0)
start_row = pos.row + 1;
int32_t start_col = pos.col;
Coord screen_size = {io::rows, io::cols};
if (start_col + size.col > screen_size.col) {
start_col = screen_size.col - size.col;
if (start_col < 0)
start_col = 0;
}
pos.col = start_col;
pos.row = start_row;
if (warnings.empty())
return;
uint32_t longest_line = 8 + warnings[0].source.length();
@@ -30,22 +51,35 @@ void DiagnosticBox::render_first() {
}
uint32_t content_width = MIN(longest_line, 150u);
size.col = content_width + 2;
cells.assign(size.col * 25, {" ", 0, 0, 0, 0, 0});
auto set = [&](uint32_t r, uint32_t c, const char *text, uint32_t fg,
uint32_t bg, uint8_t flags) {
cells[r * size.col + c] = {std::string(text), 0, fg, bg, flags, 0};
auto set = [&](uint32_t r, uint32_t c, std::string text, uint32_t fg,
uint32_t bg, uint8_t flags, uint32_t width) {
if (r < 0 || r >= size.row || c < 0 || c >= size.col)
return;
r += pos.row;
c += pos.col;
if (r < 0 || r >= screen_size.row || c < 0 || c >= screen_size.col)
return;
ScreenCell &cell = buffer[r * screen_size.col + c];
cell.utf8 = std::move(text);
cell.width = width;
cell.fg = fg;
cell.bg = bg;
cell.flags = flags;
cell.ul_color = 0;
};
uint32_t base_bg = 0;
uint32_t border_fg = 0x82AAFF;
uint32_t r = 0;
if (warnings[0].source != "") {
std::string src_txt = "Source: ";
for (uint32_t i = 0; i < src_txt.length() && i < content_width; i++)
set(1, i + 1, (char[2]){src_txt[i], 0}, 0x3EAAFF, base_bg, 0);
for (uint32_t i = 0; i < warnings[0].source.length() && i < content_width;
i++)
set(1, i + 1 + src_txt.length(), (char[2]){warnings[0].source[i], 0},
0xffffff, base_bg, 0);
uint32_t i = 0;
for (; i < 8 && i < content_width; i++)
set(1, i + 1, (char[2]){src_txt[i], 0}, 0x3EAAFF, base_bg, 0, 1);
for (; i < 8 + warnings[0].source.length() && i < content_width; i++)
set(1, i + 1, (char[2]){warnings[0].source[i - 8], 0}, 0xffffff, base_bg,
0, 1);
while (i < content_width)
set(1, ++i, " ", 0xffffff, base_bg, 0, 1);
r++;
}
int idx = 1;
@@ -54,7 +88,7 @@ void DiagnosticBox::render_first() {
std::snprintf(buf, sizeof(buf), "%2d", idx % 100);
std::string line_txt = std::string(buf) + ". ";
for (uint32_t i = 0; i < line_txt.length(); i++)
set(r + 1, i + 1, (char[2]){line_txt[i], 0}, 0xffffff, base_bg, 0);
set(r + 1, i + 1, (char[2]){line_txt[i], 0}, 0xffffff, base_bg, 0, 1);
if (r >= 23)
break;
const char *err_sym = "";
@@ -93,19 +127,26 @@ void DiagnosticBox::render_first() {
int width = display_width(cluster.c_str(), cluster_len);
if (c + width > content_width)
break;
set(r + 1, c + 1, cluster.c_str(), c_sym, base_bg, 0);
set(r + 1, c + 1, cluster.c_str(), c_sym, base_bg, 0, width);
c += width;
i += cluster_len;
for (int w = 1; w < width; w++)
set(r + 1, c - w + 1, "\x1b", c_sym, base_bg, 0);
set(r + 1, c - w + 1, "\x1b", c_sym, base_bg, 0, 0);
}
while (c < content_width)
set(r + 1, ++c, " ", 0xffffff, base_bg, 0, 1);
r++;
}
if (r >= 23)
break;
if (warn.code != "") {
for (uint32_t i = 0; i < warn.code.length() && i + 5 < content_width; i++)
set(r + 1, i + 5, (char[2]){warn.code[i], 0}, 0x81cdc6, base_bg, 0);
uint32_t i = 0;
for (; i < 5 && i < content_width; i++)
set(r + 1, i, " ", 0x81cdc6, base_bg, 0, 1);
for (; i < warn.code.length() + 5 && i < content_width; i++)
set(r + 1, i, (char[2]){warn.code[i - 5], 0}, 0x81cdc6, base_bg, 0, 1);
while (i <= content_width)
set(r + 1, i++, " ", 0x81cdc6, base_bg, 0, 1);
r++;
}
if (r >= 23)
@@ -113,14 +154,18 @@ void DiagnosticBox::render_first() {
for (std::string &see_also : warn.see_also) {
uint32_t fg = 0xB55EFF;
uint8_t colon_count = 0;
for (uint32_t i = 0; i < see_also.length() && i + 5 < content_width;
i++) {
set(r + 1, i + 5, (char[2]){see_also[i], 0}, fg, base_bg, 0);
if (see_also[i] == ':')
uint32_t i = 0;
for (; i < 5 && i < content_width; i++)
set(r + 1, i, " ", 0x81cdc6, base_bg, 0, 1);
for (; i < see_also.length() + 5 && i < content_width; i++) {
set(r + 1, i, (char[2]){see_also[i - 5], 0}, fg, base_bg, 0, 1);
if (see_also[i - 5] == ':')
colon_count++;
if (colon_count == 2)
fg = 0xFFFFFF;
}
while (i <= content_width)
set(r + 1, i++, " ", fg, base_bg, 0, 1);
r++;
if (r >= 23)
break;
@@ -128,35 +173,16 @@ void DiagnosticBox::render_first() {
idx++;
}
size.row = 2 + r;
set(0, 0, "", border_fg, base_bg, 0);
set(0, 0, "", border_fg, base_bg, 0, 1);
for (uint32_t i = 1; i < size.col - 1; i++)
set(0, i, "", border_fg, base_bg, 0);
set(0, size.col - 1, "", border_fg, base_bg, 0);
set(0, i, "", border_fg, base_bg, 0, 1);
set(0, size.col - 1, "", border_fg, base_bg, 0, 1);
for (uint32_t r = 1; r < size.row - 1; r++) {
set(r, 0, "", border_fg, base_bg, 0);
set(r, size.col - 1, "", border_fg, base_bg, 0);
set(r, 0, "", border_fg, base_bg, 0, 1);
set(r, size.col - 1, "", border_fg, base_bg, 0, 1);
}
set(size.row - 1, 0, "", border_fg, base_bg, 0);
set(size.row - 1, 0, "", border_fg, base_bg, 0, 1);
for (uint32_t i = 1; i < size.col - 1; i++)
set(size.row - 1, i, "", border_fg, base_bg, 0);
set(size.row - 1, size.col - 1, "", border_fg, base_bg, 0);
cells.resize(size.col * size.row);
}
void DiagnosticBox::render(Coord pos) {
int32_t start_row = (int32_t)pos.row - (int32_t)size.row;
if (start_row < 0)
start_row = pos.row + 1;
int32_t start_col = pos.col;
Coord screen_size = get_size();
if (start_col + size.col > screen_size.col) {
start_col = screen_size.col - size.col;
if (start_col < 0)
start_col = 0;
}
for (uint32_t r = 0; r < size.row; r++)
for (uint32_t c = 0; c < size.col; c++)
update(start_row + r, start_col + c, cells[r * size.col + c].utf8,
cells[r * size.col + c].fg, cells[r * size.col + c].bg,
cells[r * size.col + c].flags);
set(size.row - 1, i, "", border_fg, base_bg, 0, 1);
set(size.row - 1, size.col - 1, "", border_fg, base_bg, 0, 1);
}
+58 -44
View File
@@ -1,12 +1,16 @@
#include "ui/hover.h"
#include "extentions/hover.h"
#include "io/sysio.h"
#include "syntax/decl.h"
#include "windows/decl.h"
void HoverBox::clear() {
text = "";
scroll_ = 0;
is_markup = false;
size = {0, 0};
cells.clear();
HoverBox *init_hover() {
auto hover = std::make_unique<HoverBox>();
hover->pos = {0, 0};
hover->size = {1, 1};
hover->hidden = true;
HoverBox *ptr = hover.get();
layout::popups.push_back(std::move(hover));
return ptr;
}
void HoverBox::scroll(int32_t number) {
@@ -19,13 +23,28 @@ void HoverBox::scroll(int32_t number) {
scroll_ = MAX((int32_t)scroll_ + number, 0);
if (scroll_ > line_count)
scroll_ = line_count;
render_first(true);
scroll_dirty = true;
}
void HoverBox::render_first(bool scroll) {
if (!scroll) {
void HoverBox::render(std::vector<ScreenCell> &buffer, Coord n_size,
Coord n_pos) {
pos = n_pos;
size = n_size;
if (scroll_dirty) {
// TODO: call syntax highlighter here
}
int32_t start_row = (int32_t)pos.row - (int32_t)size.row;
if (start_row < 0)
start_row = pos.row + 1;
int32_t start_col = pos.col;
Coord screen_size = {io::rows, io::cols};
if (start_col + size.col > screen_size.col) {
start_col = screen_size.col - size.col;
if (start_col < 0)
start_col = 0;
}
pos.col = start_col;
pos.row = start_row;
uint32_t longest_line = 0;
uint32_t current_width = 0;
for (size_t j = 0; j < text.length(); j++) {
@@ -36,7 +55,7 @@ void HoverBox::render_first(bool scroll) {
current_width += 1;
}
}
// HACK: the 1 is added so the longest line doesnt wrap which should be fixed
// HACK: the 1 is added so the longest line doesnt wrap which should befixed
// in the loop instead as it was never meant to wrap in the first place
longest_line = MAX(longest_line, current_width) + 1;
uint32_t content_width = MIN(longest_line, 130u);
@@ -50,10 +69,21 @@ void HoverBox::render_first(bool scroll) {
}
uint32_t border_fg = 0x82AAFF;
uint32_t base_bg = 0;
cells.assign(size.col * 26, ScreenCell{" ", 0, 0, 0, 0, 0});
auto set = [&](uint32_t r, uint32_t c, const char *text, uint32_t fg,
uint32_t bg, uint8_t flags) {
cells[r * size.col + c] = {std::string(text), 0, fg, bg, flags, 0};
uint32_t bg, uint8_t flags, uint32_t width) {
if (r < 0 || r >= size.row || c < 0 || c >= size.col)
return;
r += pos.row;
c += pos.col;
if (r < 0 || r >= screen_size.row || c < 0 || c >= screen_size.col)
return;
ScreenCell &cell = buffer[r * screen_size.col + c];
cell.utf8 = text;
cell.width = width;
cell.fg = fg;
cell.bg = bg;
cell.flags = flags;
cell.ul_color = 0;
};
uint32_t r = 0;
while (i < text.length() && r < 24) {
@@ -75,45 +105,29 @@ void HoverBox::render_first(bool scroll) {
uint32_t fg = hl ? hl->fg : 0xFFFFFF;
uint32_t bg = hl ? hl->bg : 0;
uint32_t flags = hl ? hl->flags : 0;
set(r + 1, c + 1, cluster.c_str(), fg, bg | base_bg, flags);
set(r + 1, c + 1, cluster.c_str(), fg, bg | base_bg, flags, width);
c += width;
i += cluster_len;
for (int w = 1; w < width; w++)
set(r + 1, c - w + 1, "\x1b", 0xFFFFFF, base_bg, 0);
set(r + 1, c - w + 1, "\x1b", 0xFFFFFF, base_bg, 0, 0);
}
while (c < content_width)
set(r + 1, ++c, " ", 0xFFFFFF, base_bg, 0, 0);
r++;
}
if (!scroll)
if (scroll_dirty)
size.row = r + 2;
set(0, 0, "", border_fg, base_bg, 0);
set(0, 0, "", border_fg, base_bg, 0, 1);
for (uint32_t i = 1; i < size.col - 1; i++)
set(0, i, "", border_fg, base_bg, 0);
set(0, size.col - 1, "", border_fg, base_bg, 0);
set(0, i, "", border_fg, base_bg, 0, 1);
set(0, size.col - 1, "", border_fg, base_bg, 0, 1);
for (uint32_t r = 1; r < size.row - 1; r++) {
set(r, 0, "", border_fg, base_bg, 0);
set(r, size.col - 1, "", border_fg, base_bg, 0);
set(r, 0, "", border_fg, base_bg, 0, 1);
set(r, size.col - 1, "", border_fg, base_bg, 0, 1);
}
set(size.row - 1, 0, "", border_fg, base_bg, 0);
set(size.row - 1, 0, "", border_fg, base_bg, 0, 1);
for (uint32_t i = 1; i < size.col - 1; i++)
set(size.row - 1, i, "", border_fg, base_bg, 0);
set(size.row - 1, size.col - 1, "", border_fg, base_bg, 0);
cells.resize(size.col * size.row);
}
void HoverBox::render(Coord pos) {
int32_t start_row = (int32_t)pos.row - (int32_t)size.row;
if (start_row < 0)
start_row = pos.row + 1;
int32_t start_col = pos.col;
Coord screen_size = get_size();
if (start_col + size.col > screen_size.col) {
start_col = screen_size.col - size.col;
if (start_col < 0)
start_col = 0;
}
for (uint32_t r = 0; r < size.row; r++)
for (uint32_t c = 0; c < size.col; c++)
update(start_row + r, start_col + c, cells[r * size.col + c].utf8,
cells[r * size.col + c].fg, cells[r * size.col + c].bg,
cells[r * size.col + c].flags);
set(size.row - 1, i, "", border_fg, base_bg, 0, 1);
set(size.row - 1, size.col - 1, "", border_fg, base_bg, 0, 1);
scroll_dirty = false;
}
+19 -83
View File
@@ -1,16 +1,19 @@
#include "io/sysio.h"
static uint32_t rows, cols;
static bool show_cursor = 0;
static std::vector<ScreenCell> screen;
static std::vector<ScreenCell> old_screen;
static std::mutex screen_mutex;
static termios orig_termios;
namespace io {
std::vector<ScreenCell> new_screen;
uint32_t rows, cols;
bool show_cursor = 0;
std::vector<ScreenCell> old_screen;
termios orig_termios;
} // namespace io
using namespace io;
void disable_raw_mode() {
std::string os = "\x1b[?1049l\x1b[2 q\x1b[?1002l\x1b[?25h\x1b[?2004l";
write(STDOUT_FILENO, os.c_str(), os.size());
if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &orig_termios) == -1) {
if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &io::orig_termios) == -1) {
perror("tcsetattr");
exit(EXIT_FAILURE);
}
@@ -24,7 +27,7 @@ void enable_raw_mode() {
raw.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON);
raw.c_oflag &= ~(OPOST);
raw.c_cflag |= (CS8);
raw.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG);
raw.c_lflag &= ~(ECHO | ICANON | IEXTEN); // | ISIG);
raw.c_cc[VMIN] = 0;
raw.c_cc[VTIME] = 0;
if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &raw) == -1)
@@ -39,80 +42,14 @@ Coord start_screen() {
ioctl(0, TIOCGWINSZ, &w);
rows = w.ws_row;
cols = w.ws_col;
screen.assign(rows * cols, {});
new_screen.assign(rows * cols, {});
old_screen.assign(rows * cols, {});
return {rows, cols};
}
void end_screen() { disable_raw_mode(); }
Coord get_size() { return {rows, cols}; }
void update(uint32_t row, uint32_t col, std::string utf8, uint32_t fg,
uint32_t bg, uint8_t flags) {
if (row >= rows || col >= cols)
return;
uint32_t idx = row * cols + col;
std::lock_guard<std::mutex> lock(screen_mutex);
screen[idx].utf8 = utf8 != "" ? utf8 : "";
if (utf8 == "")
return;
screen[idx].width = display_width(utf8.c_str(), utf8.size());
screen[idx].fg = fg;
screen[idx].bg = bg;
screen[idx].flags = flags;
screen[idx].ul_color = 0;
}
void update(uint32_t row, uint32_t col, const char *utf8, uint32_t fg,
uint32_t bg, uint8_t flags) {
if (row >= rows || col >= cols)
return;
uint32_t idx = row * cols + col;
std::lock_guard<std::mutex> lock(screen_mutex);
screen[idx].utf8 = utf8 ? utf8 : "";
if (utf8 == nullptr)
return;
screen[idx].width = display_width(utf8, strlen(utf8));
screen[idx].fg = fg;
screen[idx].bg = bg;
screen[idx].flags = flags;
screen[idx].ul_color = 0;
}
void update(uint32_t row, uint32_t col, std::string utf8, uint32_t fg,
uint32_t bg, uint8_t flags, uint32_t ul_color) {
if (row >= rows || col >= cols)
return;
uint32_t idx = row * cols + col;
std::lock_guard<std::mutex> lock(screen_mutex);
screen[idx].utf8 = utf8 != "" ? utf8 : "";
if (utf8 == "")
return;
screen[idx].width = display_width(utf8.c_str(), utf8.size());
screen[idx].fg = fg;
screen[idx].bg = bg;
screen[idx].flags = flags;
screen[idx].ul_color = ul_color;
}
void update(uint32_t row, uint32_t col, const char *utf8, uint32_t fg,
uint32_t bg, uint8_t flags, uint32_t ul_color) {
if (row >= rows || col >= cols)
return;
uint32_t idx = row * cols + col;
std::lock_guard<std::mutex> lock(screen_mutex);
screen[idx].utf8 = utf8 ? utf8 : "";
if (utf8 == nullptr)
return;
screen[idx].width = display_width(utf8, strlen(utf8));
screen[idx].fg = fg;
screen[idx].bg = bg;
screen[idx].flags = flags;
screen[idx].ul_color = ul_color;
}
void render() {
void io_render() {
static bool first_render = true;
uint32_t current_fg = 0;
uint32_t current_bg = 0;
@@ -121,7 +58,6 @@ void render() {
bool current_bold = false;
bool current_strikethrough = false;
bool current_underline = false;
std::lock_guard<std::mutex> lock(screen_mutex);
std::string out;
out.reserve(static_cast<size_t>(rows) * static_cast<size_t>(cols) * 4 + 256);
out += "\x1b[s\x1b[?25l";
@@ -135,7 +71,7 @@ void render() {
for (uint32_t col = 0; col < cols; ++col) {
uint32_t idx = row * cols + col;
ScreenCell &old_cell = old_screen[idx];
ScreenCell &new_cell = screen[idx];
ScreenCell &new_cell = new_screen[idx];
bool content_changed =
old_cell.utf8 != new_cell.utf8 || old_cell.fg != new_cell.fg ||
old_cell.bg != new_cell.bg || old_cell.flags != new_cell.flags ||
@@ -147,7 +83,7 @@ void render() {
for (int64_t back = 1; back <= 4 && first_change_col - back >= 0;
++back) {
ScreenCell &prev_cell =
screen[row * cols + (first_change_col - back)];
new_screen[row * cols + (first_change_col - back)];
if (prev_cell.width > 1) {
first_change_col -= back;
break;
@@ -165,7 +101,7 @@ void render() {
for (uint32_t col = first_change_col; col <= last_change_col; ++col) {
uint32_t idx = row * cols + col;
ScreenCell &old_cell = old_screen[idx];
ScreenCell &new_cell = screen[idx];
ScreenCell &new_cell = new_screen[idx];
uint32_t width = new_cell.width > 0 ? new_cell.width : 1;
bool overlap = false;
if (width > 1) {
@@ -173,7 +109,7 @@ void render() {
uint32_t next_col = col + i;
if (next_col >= cols)
break;
const ScreenCell &next = screen[row * cols + next_col];
const ScreenCell &next = new_screen[row * cols + next_col];
if (!is_empty_cell(next)) {
overlap = true;
break;
@@ -244,7 +180,7 @@ void render() {
uint32_t next_col = col + i;
if (next_col >= cols)
break;
const ScreenCell &next = screen[row * cols + next_col];
const ScreenCell &next = new_screen[row * cols + next_col];
if (!is_empty_cell(next))
break;
out.push_back(' ');
@@ -260,7 +196,7 @@ void render() {
ScreenCell *cell = &new_cell;
int back = 0;
while ((int)col - back >= 0 && cell->utf8[0] == '\x1b')
cell = &screen[row * cols + col - ++back];
cell = &new_screen[row * cols + col - ++back];
if (width >= cell->width)
out.append(" ");
}
-87
View File
@@ -1,87 +0,0 @@
#include "lsp/lsp.h"
Queue<LSPOpenRequest> lsp_open_queue;
void request_add_to_lsp(Language language, Editor *editor) {
lsp_open_queue.push({language, editor});
}
void add_to_lsp(Language language, Editor *editor) {
std::shared_ptr<LSPInstance> lsp = get_or_init_lsp(language.lsp_name);
if (!lsp)
return;
std::unique_lock lock(lsp->mtx);
if (editor->lsp == lsp)
return;
lsp->editors.push_back(editor);
lsp->open_queue.push({language, editor});
lock.unlock();
}
void open_editor(std::shared_ptr<LSPInstance> lsp,
std::pair<Language, Editor *> entry) {
Language language = entry.first;
Editor *editor = entry.second;
if (editor->lsp == lsp)
return;
editor->lsp = lsp;
std::unique_lock lock3(editor->knot_mtx);
char *buf = read(editor->root, 0, editor->root->char_count);
std::string text(buf);
free(buf);
json message = {{"jsonrpc", "2.0"},
{"method", "textDocument/didOpen"},
{"params",
{{"textDocument",
{{"uri", editor->uri},
{"languageId", language.name},
{"version", 1},
{"text", text}}}}}};
lock3.unlock();
lsp_send(lsp, message, nullptr);
}
static std::string find_lsp_id(std::shared_ptr<LSPInstance> needle) {
for (const auto &[id, lsp] : active_lsps)
if (lsp == needle)
return id;
return "";
}
void remove_from_lsp(Editor *editor) {
auto lsp = editor->lsp;
if (!lsp)
return;
std::unique_lock lock1(lsp->mtx);
lsp->editors.erase(
std::remove(lsp->editors.begin(), lsp->editors.end(), editor),
lsp->editors.end());
lock1.unlock();
std::unique_lock lock2(editor->lsp_mtx);
editor->lsp = nullptr;
lock2.unlock();
json message = {{"jsonrpc", "2.0"},
{"method", "textDocument/didClose"},
{"params", {{"textDocument", {{"uri", editor->uri}}}}}};
lsp_send(lsp, message, nullptr);
std::string lsp_id = find_lsp_id(lsp);
if (!lsp_id.empty() && lsp->editors.empty())
close_lsp(lsp_id);
}
void lsp_handle(std::shared_ptr<LSPInstance>, json message) {
std::string method = message.value("method", "");
if (method == "window/showMessage") {
if (message.contains("params")) {
auto &p = message["params"];
if (p.contains("message"))
log("%s\n", p["message"].get<std::string>().c_str());
}
} else if (method == "window/logMessage") {
if (message.contains("params")) {
auto &p = message["params"];
if (p.contains("message"))
log("%s\n", p["message"].get<std::string>().c_str());
}
}
}
-205
View File
@@ -1,205 +0,0 @@
#include "lsp/lsp.h"
static bool init_lsp(std::shared_ptr<LSPInstance> lsp) {
int in_pipe[2];
int out_pipe[2];
if (pipe(in_pipe) == -1 || pipe(out_pipe) == -1) {
perror("pipe");
return false;
}
pid_t pid = fork();
if (pid == -1) {
perror("fork");
return false;
}
if (pid == 0) {
dup2(in_pipe[0], STDIN_FILENO);
dup2(out_pipe[1], STDOUT_FILENO);
int devnull = open("/dev/null", O_WRONLY);
if (devnull >= 0) {
dup2(devnull, STDERR_FILENO);
close(devnull);
}
close(in_pipe[0]);
close(in_pipe[1]);
close(out_pipe[0]);
close(out_pipe[1]);
std::vector<char *> argv;
argv.push_back(const_cast<char *>(lsp->lsp->command.c_str()));
for (auto &arg : lsp->lsp->args)
argv.push_back(const_cast<char *>(arg.c_str()));
argv.push_back(nullptr);
execvp(lsp->lsp->command.c_str(), argv.data());
perror("execvp");
_exit(127);
}
lsp->pid = pid;
lsp->stdin_fd = in_pipe[1];
lsp->stdout_fd = out_pipe[0];
close(in_pipe[0]);
close(out_pipe[1]);
return true;
}
std::shared_ptr<LSPInstance> get_or_init_lsp(std::string lsp_id) {
std::unique_lock lock(active_lsps_mtx);
auto it = active_lsps.find(lsp_id);
if (it == active_lsps.end()) {
auto map_it = lsps.find(lsp_id);
if (map_it == lsps.end())
return nullptr;
std::shared_ptr<LSPInstance> lsp = std::make_shared<LSPInstance>();
lsp->lsp = &map_it->second;
if (!init_lsp(lsp))
return nullptr;
LSPPending *pending = new LSPPending();
pending->method = "initialize";
pending->editor = nullptr;
pending->callback = [lsp, lsp_id](Editor *, std::string, json msg) {
if (msg.contains("result") && msg["result"].contains("capabilities")) {
auto &caps = msg["result"]["capabilities"];
// if (caps.contains("positionEncoding")) {
// std::string s = caps["positionEncoding"].get<std::string>();
// if (s == "utf-8")
// lsp->is_utf8 = true;
// log("Lsp name: %s, supports: %s", lsp->lsp->command.c_str(),
// s.c_str());
// }
if (caps.contains("textDocumentSync")) {
auto &sync = caps["textDocumentSync"];
if (sync.is_number()) {
int change_type = sync.get<int>();
lsp->incremental_sync = (change_type == 2);
} else if (sync.is_object() && sync.contains("change")) {
int change_type = sync["change"].get<int>();
lsp->incremental_sync = (change_type == 2);
}
}
lsp->allow_formatting = caps.value("documentFormattingProvider", false);
if (lsp_id != "lua-language-server" /* Lua ls gives terrible ontype
formatting so disable */
&& caps.contains("documentOnTypeFormattingProvider")) {
auto &fmt = caps["documentOnTypeFormattingProvider"];
if (fmt.is_object()) {
if (fmt.contains("firstTriggerCharacter")) {
std::string s = fmt["firstTriggerCharacter"].get<std::string>();
if (s.size() == 1)
lsp->format_chars.push_back(s[0]);
}
if (fmt.contains("moreTriggerCharacter")) {
for (auto &c : fmt["moreTriggerCharacter"]) {
std::string s = c.get<std::string>();
if (s.size() == 1)
lsp->format_chars.push_back(s[0]);
}
}
lsp->allow_formatting_on_type = true;
} else if (fmt.is_boolean()) {
lsp->allow_formatting_on_type = fmt.get<bool>();
}
}
if (caps.contains("hoverProvider")) {
auto &hover = caps["hoverProvider"];
lsp->allow_hover =
hover.is_boolean() ? hover.get<bool>() : hover.is_object();
} else {
lsp->allow_hover = false;
}
if (caps.contains("completionProvider")) {
lsp->allow_completion = true;
if (caps["completionProvider"].contains("resolveProvider"))
lsp->allow_resolve =
caps["completionProvider"]["resolveProvider"].get<bool>();
if (caps["completionProvider"].contains("triggerCharacters")) {
auto &chars = caps["completionProvider"]["triggerCharacters"];
if (chars.is_array()) {
for (auto &c : chars) {
std::string str = c.get<std::string>();
if (str.size() != 1)
continue;
lsp->trigger_chars.push_back(str[0]);
}
}
}
if (caps["completionProvider"].contains("allCommitCharacters")) {
auto &chars = caps["completionProvider"]["allCommitCharacters"];
if (chars.is_array()) {
for (auto &c : chars) {
std::string str = c.get<std::string>();
if (str.size() != 1)
continue;
lsp->end_chars.push_back(str[0]);
}
}
}
}
}
lsp->initialized = true;
json initialized = {{"jsonrpc", "2.0"},
{"method", "initialized"},
{"params", json::object()}};
lsp_send(lsp, initialized, nullptr);
};
json init_message = {
{"jsonrpc", "2.0"},
{"method", "initialize"},
{"params",
{{"processId", getpid()},
{"rootUri", "file://" + percent_encode(path_abs("."))},
{"capabilities", client_capabilities}}}};
lsp_send(lsp, init_message, pending);
active_lsps[lsp_id] = lsp;
return lsp;
}
return it->second;
}
void close_lsp(std::string lsp_id) {
std::shared_lock active_lsps_lock(active_lsps_mtx);
auto it = active_lsps.find(lsp_id);
if (it == active_lsps.end())
return;
std::shared_ptr<LSPInstance> lsp = it->second;
active_lsps_lock.unlock();
lsp->exited = true;
lsp->initialized = false;
LSPPending *shutdown_pending = new LSPPending();
shutdown_pending->method = "shutdown";
shutdown_pending->callback = [lsp](Editor *, std::string, json) {
json exit = {{"jsonrpc", "2.0"}, {"method", "exit"}};
lsp_send(lsp, exit, nullptr);
};
json shutdown = {{"jsonrpc", "2.0"}, {"method", "shutdown"}};
lsp_send(lsp, shutdown, shutdown_pending);
std::thread t([lsp, lsp_id] {
std::this_thread::sleep_for(100ms);
std::unique_lock active_lsps_lock(active_lsps_mtx);
std::unique_lock lock(lsp->mtx);
if (lsp->pid != -1 && kill(lsp->pid, 0) == 0)
kill(lsp->pid, SIGKILL);
waitpid(lsp->pid, nullptr, 0);
close(lsp->stdin_fd);
close(lsp->stdout_fd);
for (auto &kv : lsp->pending)
delete kv.second;
for (auto &editor : lsp->editors) {
std::unique_lock editor_lock(editor->lsp_mtx);
editor->lsp = nullptr;
}
active_lsps.erase(lsp_id);
});
t.detach();
}
void clean_lsp(std::shared_ptr<LSPInstance> lsp, std::string lsp_id) {
for (auto &kv : lsp->pending)
delete kv.second;
lsp->pid = -1;
close(lsp->stdin_fd);
close(lsp->stdout_fd);
for (auto &editor : lsp->editors) {
std::unique_lock editor_lock(editor->lsp_mtx);
editor->lsp = nullptr;
}
active_lsps.erase(lsp_id);
}
+49
View File
@@ -0,0 +1,49 @@
#include "lsp/lsp.h"
namespace lsp {
std::mutex lsp_mutex;
std::unordered_map<std::string, std::unique_ptr<LSPInstance>> active_lsps;
std::unordered_set<std::string> opened;
Queue<std::string> need_opening;
std::vector<Editor *> new_editors;
Queue<std::unique_ptr<LSPMessage>> response_queue;
}
void lsp_worker() {
std::lock_guard lock(lsp::lsp_mutex);
while (!lsp::need_opening.empty()) {
auto lsp_id = *lsp::need_opening.front();
if (!lsp::opened.contains(lsp_id)) {
lsp::active_lsps[lsp_id] = std::make_unique<LSPInstance>(lsp_id);
lsp::opened.insert(lsp_id);
}
lsp::need_opening.pop();
}
for (auto it = lsp::new_editors.begin(); it != lsp::new_editors.end();) {
auto ed = *it;
auto lsp_id = ed->lang.lsp_name;
if (lsp_id.empty()) {
it = lsp::new_editors.erase(it);
continue;
}
if (lsp::opened.contains(lsp_id)) {
auto a_it = lsp::active_lsps.find(lsp_id);
if (a_it != lsp::active_lsps.end())
a_it->second->add(ed);
it = lsp::new_editors.erase(it);
} else {
lsp::need_opening.push(lsp_id);
it++;
}
}
for (auto it = lsp::active_lsps.begin(); it != lsp::active_lsps.end();) {
auto &lsp_inst = it->second;
if (!lsp_inst || lsp_inst->pid == -1 || lsp_inst->editors.empty() ||
lsp_inst->exited) {
it = lsp::active_lsps.erase(it);
continue;
}
lsp_inst->work();
++it;
}
}
-170
View File
@@ -1,170 +0,0 @@
#include "lsp/lsp.h"
std::shared_mutex active_lsps_mtx;
std::unordered_map<std::string, std::shared_ptr<LSPInstance>> active_lsps;
void lsp_send(std::shared_ptr<LSPInstance> lsp, json message,
LSPPending *pending) {
if (!lsp || lsp->stdin_fd == -1)
return;
std::unique_lock lock(lsp->mtx);
if (pending) {
message["id"] = lsp->last_id++;
uint32_t id = message["id"].get<uint32_t>();
lsp->pending[id] = pending;
}
lsp->outbox.push(message);
}
static std::optional<json> read_lsp_message(int fd) {
std::string header;
char c;
while (true) {
ssize_t n = read(fd, &c, 1);
if (n <= 0)
return std::nullopt;
header.push_back(c);
if (header.size() >= 4 && header.substr(header.size() - 4) == "\r\n\r\n")
break;
}
size_t pos = header.find("Content-Length:");
if (pos == std::string::npos)
return std::nullopt;
pos += strlen("Content-Length:");
while (pos < header.size() && std::isspace(header[pos]))
pos++;
size_t end = pos;
while (end < header.size() && std::isdigit(header[end]))
end++;
size_t len = std::stoul(header.substr(pos, end - pos));
std::string body(len, '\0');
size_t got = 0;
while (got < len) {
ssize_t n = read(fd, &body[got], len - got);
if (n <= 0)
return std::nullopt;
got += n;
}
return json::parse(body);
}
static Editor *editor_for_uri(std::shared_ptr<LSPInstance> lsp,
std::string uri) {
if (uri.empty())
return nullptr;
for (auto &editor : lsp->editors)
if (editor->uri == uri)
return editor;
return nullptr;
}
void lsp_worker() {
LSPOpenRequest request;
while (lsp_open_queue.pop(request))
add_to_lsp(request.language, request.editor);
std::unique_lock active_lsps_lock(active_lsps_mtx);
for (auto &kv : active_lsps) {
std::shared_ptr<LSPInstance> lsp = kv.second;
std::unique_lock lock(lsp->mtx);
int status;
pid_t res = waitpid(lsp->pid, &status, WNOHANG);
if (res == lsp->pid) {
clean_lsp(lsp, kv.first);
return;
}
if (lsp->initialized) {
std::pair<Language, Editor *> request;
while (lsp->open_queue.pop(request)) {
lock.unlock();
open_editor(lsp, request);
lock.lock();
}
}
while (!lsp->outbox.empty()) {
json message = lsp->outbox.front();
std::string m = message.value("method", "");
if (lsp->exited) {
if (m != "exit" && m != "shutdown") {
lsp->outbox.pop(message);
continue;
}
}
if (!lsp->initialized) {
if (m != "initialize" && m != "exit" && m != "shutdown")
break;
}
lsp->outbox.pop(message);
std::string payload = message.dump();
std::string header =
"Content-Length: " + std::to_string(payload.size()) + "\r\n\r\n";
std::string out = header + payload;
const char *ptr = out.data();
size_t remaining = out.size();
while (remaining > 0) {
int status;
pid_t res = waitpid(lsp->pid, &status, WNOHANG);
if (res == lsp->pid) {
clean_lsp(lsp, kv.first);
return;
}
ssize_t written = write(lsp->stdin_fd, ptr, remaining);
if (written == 0)
break;
else if (written == -1) {
if (errno == EINTR)
continue;
perror("write");
clean_lsp(lsp, kv.first);
return;
} else {
ptr += written;
remaining -= written;
}
}
}
pollfd pfd{lsp->stdout_fd, POLLIN | POLLHUP | POLLERR, 0};
int r = poll(&pfd, 1, 0);
if (r > 0 && pfd.revents & (POLLHUP | POLLERR)) {
clean_lsp(lsp, kv.first);
return;
}
while ((r = poll(&pfd, 1, 0) > 0)) {
if (r > 0 && pfd.revents & (POLLHUP | POLLERR)) {
clean_lsp(lsp, kv.first);
return;
}
auto msg = read_lsp_message(lsp->stdout_fd);
if (!msg)
break;
if (msg->contains("id")) {
uint32_t id = msg->at("id").get<uint32_t>();
auto it = lsp->pending.find(id);
if (it != lsp->pending.end()) {
LSPPending *pend = it->second;
lock.unlock();
if (pend->callback)
pend->callback(pend->editor, pend->method, *msg);
delete pend;
lock.lock();
lsp->pending.erase(it);
}
} else if (msg->contains("method")) {
std::string uri;
if (msg->contains("params")) {
auto &p = (*msg)["params"];
if (p.contains("textDocument") && p["textDocument"].contains("uri"))
uri = p["textDocument"]["uri"].get<std::string>();
else if (p.contains("uri"))
uri = p["uri"].get<std::string>();
}
Editor *ed = editor_for_uri(lsp, uri);
lock.unlock();
if (ed)
editor_lsp_handle(ed, *msg);
else
lsp_handle(lsp, *msg);
lock.lock();
}
}
}
}
+53 -87
View File
@@ -2,73 +2,22 @@
#include "editor/editor.h"
#include "io/sysio.h"
#include "lsp/lsp.h"
#include "scripting/decl.h"
#include "ruby/decl.h"
#include "ui/bar.h"
#include "utils/utils.h"
#include "windows/decl.h"
std::atomic<bool> running{true};
Queue<KeyEvent> event_queue;
std::vector<Editor *> editors;
uint8_t current_editor = 0;
std::atomic<uint8_t> mode = NORMAL;
fs::path pwd;
namespace ui {
Bar bar;
} // namespace ui
void background_lsp() {
while (running)
throttle(8ms, lsp_worker);
}
inline Editor *editor_at(uint8_t x, uint8_t y) {
for (Editor *ed : editors) {
Coord pos = ed->position;
Coord size = ed->size;
if (x >= pos.col && x < pos.col + size.col && y >= pos.row &&
y < pos.row + size.row)
return ed;
}
return nullptr;
}
inline uint8_t index_of(Editor *ed) {
for (uint8_t i = 0; i < editors.size(); i++)
if (editors[i] == ed)
return i;
return 0;
}
void input_listener(Bar bar) {
while (running) {
KeyEvent event = throttle(1ms, read_key);
if (event.key_type == KEY_NONE)
goto render;
if (event.key_type == KEY_CHAR && event.len == 1 &&
event.c[0] == CTRL('q')) {
free(event.c);
running = false;
break;
}
if (mode != RUNNER) {
if (event.key_type == KEY_MOUSE) {
Editor *target = editor_at(event.mouse_x, event.mouse_y);
if (target) {
if (event.mouse_state == PRESS)
current_editor = index_of(target);
event.mouse_x -= target->position.col;
event.mouse_y -= target->position.row;
handle_editor_event(target, event);
}
} else {
handle_editor_event(editors[current_editor], event);
}
} else {
bar.handle(event);
}
render:
render_editor(editors[current_editor]);
bar.render();
throttle(4ms, render);
}
throttle(16ms, lsp_worker);
}
int main(int argc, char *argv[]) {
@@ -80,46 +29,63 @@ int main(int argc, char *argv[]) {
Coord screen = start_screen();
const char *filename = (argc > 1) ? argv[1] : "";
uint8_t eol = read_line_endings();
Editor *editor =
new_editor(filename, {0, 0}, {screen.row - 2, screen.col}, eol);
Bar bar(screen);
if (!editor) {
end_screen();
fprintf(stderr, "Failed to load editor\n");
return 1;
}
layout::root_tile.pos = {0, 0};
layout::root_tile.size = {screen.row - 2, screen.col - 1};
auto editor = std::make_unique<Editor>(filename, eol);
layout::focused_window = editor.get();
auto block = std::make_unique<TileBlock>();
block->tiles.push_back(std::move(editor));
layout::root_tile.tile = std::move(block);
editors.push_back(editor);
current_editor = editors.size() - 1;
ui::bar.init(screen);
std::thread input_thread(input_listener, bar);
std::thread lsp_thread(background_lsp);
while (running)
throttle(16ms, editor_worker, editors[current_editor]);
while (running) {
layout::focused_window->work();
render();
throttle(16ms, io_render);
KeyEvent event;
while (running && lsp::response_queue.empty() &&
(event = read_key()).key_type == KEY_NONE)
std::this_thread::sleep_for(1ms);
uint8_t consumed = 0;
do {
if (event.key_type != KEY_NONE) {
if (event.key_type == KEY_CHAR && event.len == 1 &&
event.c[0] == CTRL('q')) {
free(event.c);
running = false;
goto quit;
}
if (mode != RUNNER) {
if (event.key_type == KEY_MOUSE) {
handle_click(event);
} else {
layout::focused_window->handle_event(event);
}
} else {
ui::bar.handle_event(event);
}
if ((event.key_type == KEY_CHAR || event.key_type == KEY_PASTE) &&
event.c)
free(event.c);
}
} while (++consumed < 32 && (event = read_key()).key_type != KEY_NONE);
std::unique_ptr<LSPMessage> msg;
while (lsp::response_queue.pop(msg)) {
msg->callback(*msg);
};
}
if (input_thread.joinable())
input_thread.join();
quit:
if (lsp_thread.joinable())
lsp_thread.join();
end_screen();
for (auto editor : editors)
free_editor(editor);
std::unique_lock lk(active_lsps_mtx);
lk.unlock();
while (true) {
lk.lock();
if (active_lsps.empty())
break;
lk.unlock();
throttle(16ms, lsp_worker);
}
ruby_shutdown();
return 0;
+11
View File
@@ -0,0 +1,11 @@
#include "ruby/decl.h"
mrb_value get_config_file(mrb_state *mrb, mrb_value self) {
UNUSED(self);
return mrb_str_new_cstr(mrb, ruby_config_path.string().c_str());
}
void setup_ruby_bindings(mrb_state *mrb, RClass *C_module) {
mrb_define_module_function(mrb, C_module, "config_file", get_config_file,
MRB_ARGS_NONE());
}
+313 -34
View File
@@ -1,5 +1,8 @@
#include "scripting/decl.h"
#include "scripting/ruby_compiled.h"
#include "io/sysio.h"
#include "main.h"
#include "pch.h"
#include "ruby/decl.h"
#include "ruby/ruby_compiled.h"
#include "utils/utils.h"
std::unordered_map<std::string, std::pair<mrb_value, mrb_value>>
@@ -18,7 +21,6 @@ struct R_ThemeEntry {
struct R_Language {
std::string name;
uint32_t color = 0xFFFFFF;
std::string symbol;
std::vector<std::string> extensions;
std::vector<std::string> filenames;
std::string lsp_command; // link to LSP by name
@@ -26,12 +28,9 @@ struct R_Language {
mrb_state *mrb = nullptr;
RClass *C_module;
std::mutex ruby_mutex;
namespace fs = std::filesystem;
fs::path ruby_config_path;
void ruby_start() {
std::lock_guard lock(ruby_mutex);
mrb = mrb_open();
if (!mrb) {
fprintf(stderr, "Failed to init mruby\n");
@@ -39,6 +38,14 @@ void ruby_start() {
}
fs::path exe_dir = get_exe_dir();
std::vector<fs::path> candidates;
const char *crib_config = std::getenv("CRIB_CONFIG");
if (crib_config)
candidates.emplace_back(fs::path(crib_config));
const char *crib_config_dir = std::getenv("CRIB_CONFIG_DIR");
if (crib_config_dir) {
candidates.emplace_back(fs::path(crib_config_dir) / "crib.rb");
candidates.emplace_back(fs::path(crib_config_dir) / "main.rb");
}
candidates.emplace_back("./crib.rb");
const char *xdg = std::getenv("XDG_CONFIG_HOME");
const char *home = std::getenv("HOME");
@@ -46,19 +53,21 @@ void ruby_start() {
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) {
}
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) {
ruby_config_path = p;
mrb_load_file(mrb, f);
if (mrb->exc)
exit(1);
@@ -67,19 +76,280 @@ void ruby_start() {
break;
}
}
C_module = mrb_module_get(mrb, "C");
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);
if (!mrb_nil_p(block))
mrb_funcall(mrb, block, "call", 0);
mrb_garbage_collect(mrb);
}
static mrb_value sym_fg;
static mrb_value sym_bg;
static mrb_value sym_flags;
static mrb_value sym_start;
static mrb_value sym_length;
static mrb_value sym_mode;
static mrb_value sym_data;
static mrb_value sym_foldername;
static mrb_value sym_width;
static mrb_value sym_normal;
static mrb_value sym_insert;
static mrb_value sym_select;
static mrb_value sym_runner;
static mrb_value sym_jumper;
inline void initialize_symbols() {
sym_fg = mrb_symbol_value(mrb_intern_cstr(mrb, "fg"));
sym_bg = mrb_symbol_value(mrb_intern_cstr(mrb, "bg"));
sym_flags = mrb_symbol_value(mrb_intern_cstr(mrb, "flags"));
sym_start = mrb_symbol_value(mrb_intern_cstr(mrb, "start"));
sym_length = mrb_symbol_value(mrb_intern_cstr(mrb, "length"));
sym_mode = mrb_symbol_value(mrb_intern_cstr(mrb, "mode"));
sym_data = mrb_symbol_value(mrb_intern_cstr(mrb, "data"));
sym_foldername = mrb_symbol_value(mrb_intern_cstr(mrb, "foldername"));
sym_width = mrb_symbol_value(mrb_intern_cstr(mrb, "width"));
sym_normal = mrb_symbol_value(mrb_intern_cstr(mrb, "normal"));
sym_insert = mrb_symbol_value(mrb_intern_cstr(mrb, "insert"));
sym_select = mrb_symbol_value(mrb_intern_cstr(mrb, "select"));
sym_runner = mrb_symbol_value(mrb_intern_cstr(mrb, "runner"));
sym_jumper = mrb_symbol_value(mrb_intern_cstr(mrb, "jumper"));
}
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;
mrb_value fg_v = mrb_hash_get(mrb, item, sym_fg);
mrb_value bg_v = mrb_hash_get(mrb, item, sym_bg);
mrb_value flags_v = mrb_hash_get(mrb, item, sym_flags);
mrb_value start_v = mrb_hash_get(mrb, item, sym_start);
mrb_value length_v = mrb_hash_get(mrb, item, 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, uint32_t width, std::string foldername,
Window *window) {
BarLine bar_line;
static bool initialed = false;
if (!initialed) {
initialize_symbols();
initialed = true;
}
int ai = mrb_gc_arena_save(mrb);
mrb_value info = mrb_hash_new(mrb);
mrb_value val_mode;
switch (mode) {
case NORMAL:
val_mode = sym_normal;
break;
case INSERT:
val_mode = sym_insert;
break;
case SELECT:
val_mode = sym_select;
break;
case RUNNER:
val_mode = sym_runner;
break;
case JUMPER:
val_mode = sym_jumper;
break;
}
mrb_hash_set(mrb, info, sym_mode, val_mode);
mrb_value val_foldername =
mrb_str_new(mrb, foldername.c_str(), foldername.length());
mrb_hash_set(mrb, info, sym_foldername, val_foldername);
std::array<std::string, 5> arr = window->bar_info();
mrb_value ary = mrb_ary_new(mrb);
mrb_ary_push(mrb, ary, mrb_str_new(mrb, arr[0].c_str(), arr[0].length()));
mrb_ary_push(mrb, ary, mrb_str_new(mrb, arr[1].c_str(), arr[1].length()));
mrb_ary_push(mrb, ary, mrb_str_new(mrb, arr[2].c_str(), arr[2].length()));
mrb_ary_push(mrb, ary, mrb_str_new(mrb, arr[3].c_str(), arr[3].length()));
mrb_ary_push(mrb, ary, mrb_str_new(mrb, arr[4].c_str(), arr[4].length()));
mrb_hash_set(mrb, info, sym_data, ary);
mrb_value val_width = mrb_fixnum_value(width);
mrb_hash_set(mrb, info, sym_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_array_p(val_line) && RARRAY_LEN(val_line) == 1) {
val_line = mrb_ary_ref(mrb, val_line, 0);
}
if (!mrb_hash_p(val_line)) {
mrb_value inspected = mrb_funcall(mrb, val_line, "inspect", 0);
printf("bar returned: %s\n", RSTRING_PTR(inspected));
fprintf(stderr, "bar returned: %s\n", mrb_obj_classname(mrb, val_line));
abort();
}
if (mrb->exc) {
end_screen();
fputs("Error when executing Ruby code:\n", stderr);
mrb_print_error(mrb);
mrb_close(mrb);
exit(1);
}
mrb_value text_val = mrb_hash_get(
mrb, val_line, mrb_symbol_value(mrb_intern_cstr(mrb, "text")));
if (!mrb_string_p(text_val)) {
fprintf(stderr, "text is not a string: %s\n",
mrb_obj_classname(mrb, text_val));
abort();
}
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);
mrb_gc_arena_restore(mrb, ai);
return bar_line;
}
std::string serialize_value(mrb_state *mrb, mrb_value val) {
int ai = mrb_gc_arena_save(mrb);
mrb_value marshal_module = mrb_obj_value(mrb_module_get(mrb, "Marshal"));
mrb_value dumped = mrb_funcall(mrb, marshal_module, "dump", 1, val);
if (mrb->exc) {
end_screen();
fputs("Error when executing Ruby code:\n", stderr);
mrb_print_error(mrb);
mrb_close(mrb);
exit(1);
}
std::string bytes(RSTRING_PTR(dumped), RSTRING_LEN(dumped));
mrb_gc_arena_restore(mrb, ai);
return bytes;
}
mrb_value deserialize_value(mrb_state *mrb, std::string bytes) {
if (bytes.empty())
return mrb_nil_value();
mrb_value marshal_module = mrb_obj_value(mrb_module_get(mrb, "Marshal"));
mrb_value val = mrb_funcall(mrb, marshal_module, "load", 1,
mrb_str_new(mrb, bytes.c_str(), bytes.length()));
if (mrb->exc) {
end_screen();
fputs("Error when executing Ruby code:\n", stderr);
mrb_print_error(mrb);
mrb_close(mrb);
exit(1);
}
return val;
}
void ruby_copy(const char *text, size_t len) {
int ai = mrb_gc_arena_save(mrb);
if (C_module == nullptr)
return;
mrb_value mod_val = mrb_obj_value(C_module);
mrb_value block = mrb_funcall(mrb, mod_val, "b_copy", 0);
if (!mrb_nil_p(block))
mrb_funcall(mrb, block, "call", 1, mrb_str_new(mrb, text, len));
if (mrb->exc) {
end_screen();
fputs("Error when executing Ruby code:\n", stderr);
mrb_print_error(mrb);
mrb_close(mrb);
exit(1);
}
mrb_gc_arena_restore(mrb, ai);
}
std::string ruby_file_detect(std::string filename) {
int ai = mrb_gc_arena_save(mrb);
if (C_module == nullptr)
return "";
mrb_value mod_val = mrb_obj_value(C_module);
mrb_value block = mrb_funcall(mrb, mod_val, "b_file_detect", 0);
if (mrb->exc) {
end_screen();
fputs("Error when executing Ruby code:\n", stderr);
mrb_print_error(mrb);
mrb_close(mrb);
exit(1);
}
if (!mrb_nil_p(block)) {
mrb_value val =
mrb_funcall(mrb, block, "call", 1,
mrb_str_new(mrb, filename.c_str(), filename.length()));
if (mrb->exc) {
end_screen();
fputs("Error when executing Ruby code:\n", stderr);
mrb_print_error(mrb);
mrb_close(mrb);
exit(1);
}
mrb_value s_val = mrb_funcall(mrb, val, "to_s", 0);
if (mrb->exc) {
end_screen();
fputs("Error when executing Ruby code:\n", stderr);
mrb_print_error(mrb);
mrb_close(mrb);
exit(1);
}
if (mrb_string_p(s_val)) {
std::string result = std::string(RSTRING_PTR(s_val), RSTRING_LEN(s_val));
mrb_gc_arena_restore(mrb, ai);
return result;
}
}
mrb_gc_arena_restore(mrb, ai);
return "";
}
std::string ruby_paste() {
int ai = mrb_gc_arena_save(mrb);
if (C_module == nullptr)
return "";
mrb_value mod_val = mrb_obj_value(C_module);
mrb_value block = mrb_funcall(mrb, mod_val, "b_paste", 0);
if (!mrb_nil_p(block)) {
mrb_value val = mrb_funcall(mrb, block, "call", 0);
if (mrb->exc) {
end_screen();
fputs("Error when executing Ruby code:\n", stderr);
mrb_print_error(mrb);
mrb_close(mrb);
exit(1);
}
if (mrb_string_p(val)) {
std::string result = std::string(RSTRING_PTR(val), RSTRING_LEN(val));
mrb_gc_arena_restore(mrb, ai);
return result;
}
mrb_gc_arena_restore(mrb, ai);
return "";
}
mrb_gc_arena_restore(mrb, ai);
return "";
}
void ruby_shutdown() {
std::lock_guard lock(ruby_mutex);
if (C_module == nullptr)
return;
mrb_value mod_val = mrb_obj_value(C_module);
mrb_value block = mrb_funcall(mrb, mod_val, "b_shutdown", 0);
mrb_funcall(mrb, block, "call", 0);
if (!mrb_nil_p(block))
mrb_funcall(mrb, block, "call", 0);
mrb_close(mrb);
mrb = nullptr;
C_module = nullptr;
@@ -99,7 +369,6 @@ std::vector<std::string> array_to_vector(mrb_value ary) {
}
void load_custom_highlighters() {
std::lock_guard<std::mutex> lock(ruby_mutex);
if (!C_module)
return;
mrb_value mod_val = mrb_obj_value((struct RObject *)C_module);
@@ -124,27 +393,36 @@ void load_custom_highlighters() {
mrb_hash_get(mrb, val_hash, mrb_symbol_value(matcher_sym));
custom_highlighters[key] = {parse_block, match_block};
}
mrb_garbage_collect(mrb);
}
bool custom_compare(mrb_value match_block, mrb_value state1, mrb_value state2) {
std::lock_guard<std::mutex> lock(ruby_mutex);
bool custom_compare(mrb_value match_block, std::string state1,
std::string state2) {
if (state1.empty() || state2.empty())
return false;
int ai = mrb_gc_arena_save(mrb);
if (mrb_type(match_block) != MRB_TT_PROC)
return false;
mrb_value ret = mrb_funcall(mrb, match_block, "call", 2, state1, state2);
return mrb_test(ret);
mrb_value ret =
mrb_funcall(mrb, match_block, "call", 2, deserialize_value(mrb, state1),
deserialize_value(mrb, state2));
bool result = mrb_test(ret);
mrb_gc_arena_restore(mrb, ai);
return result;
}
mrb_value parse_custom(std::vector<Token> *tokens, mrb_value parser_block,
const char *line, uint32_t len, mrb_value state,
uint32_t c_line) {
std::lock_guard<std::mutex> lock(ruby_mutex);
std::string parse_custom(std::vector<Token> *tokens, mrb_value parser_block,
const char *line, uint32_t len, std::string state,
uint32_t c_line) {
int ai = mrb_gc_arena_save(mrb);
tokens->clear();
if (mrb_nil_p(parser_block))
return mrb_nil_value();
return "";
mrb_value ruby_line = mrb_str_new(mrb, line, len);
mrb_value line_idx = mrb_fixnum_value(c_line);
mrb_value tokens_and_state_hash =
mrb_funcall(mrb, parser_block, "call", 3, ruby_line, state, line_idx);
mrb_funcall(mrb, parser_block, "call", 3, ruby_line,
deserialize_value(mrb, state), line_idx);
mrb_sym tokens_sym = mrb_intern_lit(mrb, "tokens");
mrb_value tokens_rb =
mrb_hash_get(mrb, tokens_and_state_hash, mrb_symbol_value(tokens_sym));
@@ -164,11 +442,16 @@ mrb_value parse_custom(std::vector<Token> *tokens, mrb_value parser_block,
}
}
mrb_sym state_sym = mrb_intern_lit(mrb, "state");
return mrb_hash_get(mrb, tokens_and_state_hash, mrb_symbol_value(state_sym));
mrb_value state_rb =
mrb_hash_get(mrb, tokens_and_state_hash, mrb_symbol_value(state_sym));
std::string result;
if (mrb_type(state_rb) == MRB_TT_STRING)
result = std::string(RSTRING_PTR(state_rb), RSTRING_LEN(state_rb));
mrb_gc_arena_restore(mrb, ai);
return result;
}
static std::vector<R_ThemeEntry> read_theme() {
std::lock_guard<std::mutex> lock(ruby_mutex);
std::vector<R_ThemeEntry> result;
if (!C_module)
return result;
@@ -214,6 +497,7 @@ static std::vector<R_ThemeEntry> read_theme() {
entry.strikethrough = mrb_test(strikethrough);
result.push_back(entry);
}
mrb_garbage_collect(mrb);
return result;
}
@@ -282,6 +566,7 @@ std::vector<LSP> read_lsps() {
std::vector<std::string> args = array_to_vector(args_array);
result.push_back({cmd, args});
}
mrb_garbage_collect(mrb);
return result;
}
@@ -307,8 +592,6 @@ std::vector<R_Language> read_languages() {
lang.name = std::string(RSTRING_PTR(key), RSTRING_LEN(key));
mrb_value fg = mrb_hash_get(mrb, val_hash,
mrb_symbol_value(mrb_intern_lit(mrb, "color")));
mrb_value symbol = mrb_hash_get(
mrb, val_hash, mrb_symbol_value(mrb_intern_lit(mrb, "symbol")));
mrb_value extensions = mrb_hash_get(
mrb, val_hash, mrb_symbol_value(mrb_intern_lit(mrb, "extensions")));
mrb_value filenames = mrb_hash_get(
@@ -317,8 +600,6 @@ std::vector<R_Language> read_languages() {
mrb_symbol_value(mrb_intern_lit(mrb, "lsp")));
if (!mrb_nil_p(fg))
lang.color = (uint32_t)mrb_fixnum(fg);
if (!mrb_nil_p(symbol))
lang.symbol = std::string(RSTRING_PTR(symbol), RSTRING_LEN(symbol));
lang.extensions = array_to_vector(extensions);
if (!mrb_nil_p(filenames))
lang.filenames = array_to_vector(filenames);
@@ -326,11 +607,11 @@ std::vector<R_Language> read_languages() {
lang.lsp_command = std::string(RSTRING_PTR(lsp), RSTRING_LEN(lsp));
result.push_back(lang);
}
mrb_garbage_collect(mrb);
return result;
}
void load_languages_info() {
std::lock_guard lock(ruby_mutex);
auto langs = read_languages();
auto lsps_t = read_lsps();
languages.clear();
@@ -339,7 +620,6 @@ void load_languages_info() {
l.name = lang.name;
l.color = lang.color;
l.lsp_name = lang.lsp_command;
l.symbol = lang.symbol;
languages[lang.name] = l;
for (auto &ext : lang.extensions)
language_extensions[ext] = lang.name;
@@ -352,7 +632,6 @@ void load_languages_info() {
}
uint8_t read_line_endings() {
std::lock_guard<std::mutex> lock(ruby_mutex);
if (!C_module)
return 1;
mrb_value mod_val = mrb_obj_value((struct RObject *)C_module);
+18 -3
View File
@@ -19,20 +19,35 @@ while read -r line; do
fi
done <"$INPUT"
OS="$(uname -s)"
OS_TYPE="unknown"
case "$OS" in
Linux*)
OS_TYPE="linux"
;;
Darwin*)
OS_TYPE="mac"
;;
CYGWIN* | MINGW* | MSYS*)
OS_TYPE="windows"
;;
esac
{
echo " freeze"
echo "end"
echo
cat "$SCRIPT_DIR/../include/scripting/libcrib.rb"
cat "$SCRIPT_DIR/../include/ruby/libcrib.rb" | sed "s/os_name_placed_here/$OS_TYPE/g"
} >>"$TMP"
mrbc -o$OUTPUT $TMP
"$SCRIPT_DIR/../libs/mruby/bin/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"
} >"$SCRIPT_DIR/../include/ruby/ruby_compiled.h"
rm $TMP
rm $OUTPUT
+17 -11
View File
@@ -10,7 +10,7 @@ struct BashFullState {
bool line_cont = false;
struct Lit {
std::string delim = ""; // Only 1 wide for strings
std::string delim = "";
bool allow_interp = false;
bool operator==(const BashFullState::Lit &other) const {
@@ -24,7 +24,7 @@ struct BashFullState {
}
};
struct BashState {
struct BashState : StateBase {
using full_state_type = BashFullState;
int interp_level = 0;
@@ -37,26 +37,32 @@ struct BashState {
((full_state && other.full_state &&
*full_state == *other.full_state));
}
std::unique_ptr<StateBase> clone() const override {
return std::make_unique<BashState>(*this);
}
};
bool bash_state_match(std::shared_ptr<void> state_1,
std::shared_ptr<void> state_2) {
bool bash_state_match(StateBase *state_1, StateBase *state_2) {
if (!state_1 || !state_2)
return false;
return *std::static_pointer_cast<BashState>(state_1) ==
*std::static_pointer_cast<BashState>(state_2);
return *static_cast<BashState *>(state_1) ==
*static_cast<BashState *>(state_2);
}
std::shared_ptr<void> bash_parse(std::vector<Token> *tokens,
std::shared_ptr<void> in_state,
const char *text, uint32_t len,
uint32_t line_num) {
std::unique_ptr<StateBase> bash_parse(std::vector<Token> *tokens,
StateBase *in_state, const char *text,
uint32_t len, uint32_t line_num) {
static bool keywords_trie_init = false;
if (!keywords_trie_init) {
keywords_trie_init = true;
}
tokens->clear();
auto state = ensure_state(std::static_pointer_cast<BashState>(in_state));
std::unique_ptr<BashState> state;
if (in_state)
state = static_unique_ptr_cast<BashState>(in_state->clone());
else
state = std::make_unique<BashState>();
uint32_t i = 0;
while (len > 0 && (text[len - 1] == '\n' || text[len - 1] == '\r' ||
text[len - 1] == '\t' || text[len - 1] == ' '))
+100 -152
View File
@@ -26,176 +26,124 @@ Parser::Parser(Editor *n_editor, std::string n_lang, uint32_t n_scroll_max) {
assert("unknown lang should be checked by caller" && 0);
}
}
edit(0, 0, editor->root->line_count);
line_map.apply_edit(0, editor->root->line_count + 1);
}
void Parser::edit(uint32_t start_line, uint32_t old_end_line,
void Parser::edit(uint32_t start_line, uint32_t removed_rows,
uint32_t inserted_rows) {
std::lock_guard lock(data_mutex);
if (((int64_t)old_end_line - (int64_t)start_line) > 0)
line_tree.erase(start_line, old_end_line - start_line);
if (inserted_rows > 0)
line_tree.insert(start_line, inserted_rows);
if (start_line > 0)
dirty_lines.push(start_line - 1);
dirty_lines.push(start_line);
dirty_lines.push(start_line + 1);
int64_t delta = (int64_t)inserted_rows - (int64_t)removed_rows;
line_map.apply_edit(start_line, delta);
uint32_t span = MAX(removed_rows, inserted_rows);
uint32_t begin = (start_line > 0) ? start_line - 1 : 0;
uint32_t end = start_line + span;
for (uint32_t line = begin; line <= end + 1; ++line)
if (LineData *ld = line_map.at(line))
ld->out_state = nullptr;
}
void Parser::work() {
if (!editor || !editor->root)
return;
std::shared_lock k_lock(editor->knot_mtx);
k_lock.unlock();
uint32_t capacity = 256;
char *text = (char *)calloc((capacity + 1), sizeof(char));
std::unique_lock lock_data(data_mutex);
lock_data.unlock();
std::unique_lock lock(mutex);
lock.unlock();
uint32_t c_line;
while (dirty_lines.pop(c_line)) {
if (!running.load(std::memory_order_relaxed)) {
free(text);
return;
}
if (c_line > scroll_max + 40) {
dirty_lines.push(c_line);
std::vector<uint32_t> batch;
uint32_t line_count = editor->root->line_count + 1;
uint32_t min_line =
scroll_max > MAX_LINES_LOOKAROUND ? scroll_max - MAX_LINES_LOOKAROUND : 0;
uint32_t max_line = MIN(scroll_max + MAX_LINES_LOOKAROUND, line_count - 1);
bool sequential = false;
for (uint32_t i = min_line; i <= max_line; ++i) {
LineData *ld = line_map.at(i);
if ((!ld || !ld->in_state || !ld->out_state) && !sequential) {
batch.push_back(i);
sequential = true;
continue;
}
if (scroll_max > 50 && c_line < scroll_max - 50) {
dirty_lines.push(c_line);
sequential = false;
}
for (uint32_t c_line : batch) {
if (!running.load(std::memory_order_relaxed))
break;
uint32_t min_line = scroll_max > MAX_LINES_LOOKAROUND
? scroll_max - MAX_LINES_LOOKAROUND
: 0;
uint32_t max_line = scroll_max + MAX_LINES_LOOKAROUND;
if (c_line < min_line || c_line > max_line)
continue;
uint32_t scroll_snapshot = scroll_max;
std::unique_ptr<StateBase> prev_state = nullptr;
if (c_line > 0 && c_line < line_count) {
auto lm = line_map.at(c_line - 1);
if (lm && lm->out_state)
prev_state = lm->out_state ? lm->out_state->clone() : nullptr;
}
uint32_t line_count = line_tree.count();
lock_data.lock();
std::shared_ptr<void> prev_state =
(c_line > 0) && c_line < line_tree.count()
? line_tree.at(c_line - 1)->out_state
: nullptr;
lock_data.unlock();
while (c_line < line_count) {
if (!running.load(std::memory_order_relaxed)) {
free(text);
return;
}
if (scroll_dirty.exchange(false, std::memory_order_acq_rel)) {
dirty_lines.push(c_line);
c_line = scroll_max < 50 ? 0 : scroll_max - 50;
}
k_lock.lock();
if (c_line > editor->root->line_count) {
k_lock.unlock();
continue;
}
uint32_t r_offset, r_len;
r_offset = line_to_byte(editor->root, c_line, &r_len);
if (r_len > capacity) {
capacity = r_len;
text = (char *)realloc(text, capacity + 1);
memset(text, 0, capacity + 1);
}
read_into(editor->root, r_offset, r_len, text);
k_lock.unlock();
if (c_line < scroll_max &&
((scroll_max > 100 && c_line > scroll_max - 100) || c_line < 100))
lock.lock();
if (line_tree.count() < c_line) {
if (lock.owns_lock())
lock.unlock();
continue;
}
lock_data.lock();
LineData *line_data = line_tree.at(c_line);
if (!line_data) {
lock_data.unlock();
if (lock.owns_lock())
lock.unlock();
continue;
}
std::shared_ptr<void> new_state{nullptr};
if (is_custom) {
mrb_value state = mrb_nil_value();
if (prev_state) {
std::shared_ptr<CustomState> state_ptr =
std::static_pointer_cast<CustomState>(prev_state);
state = state_ptr->state;
}
mrb_value out_state = parse_custom(&line_data->tokens, parser_block,
text, r_len, state, c_line);
std::shared_ptr<CustomState> out_state_ptr =
std::make_shared<CustomState>(out_state);
new_state = out_state_ptr;
} else {
new_state =
parse_func(&line_data->tokens, prev_state, text, r_len, c_line);
}
line_data->in_state = prev_state;
line_data->out_state = new_state;
if (!running.load(std::memory_order_relaxed)) {
free(text);
return;
}
prev_state = new_state;
c_line++;
if (c_line < line_count && c_line > scroll_max + 50 && scroll_max < 50 &&
c_line < scroll_max + 50) {
lock_data.unlock();
if (lock.owns_lock())
lock.unlock();
if (c_line > 0)
dirty_lines.push(c_line - 1);
dirty_lines.push(c_line);
LineIterator *it = begin_l_iter(editor->root, c_line);
if (!it)
continue;
uint32_t cur_line = c_line;
while (cur_line < line_count) {
if (!running.load(std::memory_order_relaxed))
break;
if (scroll_snapshot != scroll_max)
break;
if (cur_line < min_line || cur_line > max_line) {
LineData *line_data = line_map.at(cur_line);
if (line_data)
line_data->out_state = nullptr;
break;
}
if (c_line < line_count && (line_data = line_tree.at(c_line))) {
bool done = false;
if (is_custom) {
mrb_value in_state_v = mrb_nil_value();
if (prev_state)
in_state_v =
std::static_pointer_cast<CustomState>(prev_state)->state;
mrb_value out_state_v = mrb_nil_value();
if (line_data->in_state)
out_state_v =
std::static_pointer_cast<CustomState>(line_data->in_state)
->state;
done = custom_compare(match_block, in_state_v, out_state_v);
} else {
done = state_match_func(prev_state, line_data->in_state);
uint32_t len;
char *line = next_line(it, &len);
if (!line)
break;
LineData *line_data = line_map.create_at(cur_line);
std::unique_ptr<StateBase> new_state;
if (is_custom) {
std::string prev_value = "";
if (prev_state) {
CustomState *prev_custom =
static_cast<CustomState *>(prev_state.get());
prev_value = prev_custom->value;
}
if (done) {
lock_data.unlock();
if (lock.owns_lock())
lock.unlock();
break;
std::string out_value = parse_custom(&line_data->tokens, parser_block,
line, len, prev_value, cur_line);
new_state = std::make_unique<CustomState>(out_value);
} else {
new_state = parse_func(&line_data->tokens, prev_state.get(), line, len,
cur_line);
}
line_data->in_state = std::move(prev_state);
line_data->out_state = std::move(new_state);
bool done = false;
if (cur_line + 1 < line_count) {
LineData *next_line_data = line_map.at(cur_line + 1);
if (next_line_data) {
if (is_custom) {
std::string a = "";
if (new_state) {
CustomState *cs = static_cast<CustomState *>(new_state.get());
a = cs->value;
}
std::string b = "";
if (next_line_data->in_state) {
CustomState *cs =
static_cast<CustomState *>(next_line_data->in_state.get());
b = cs->value;
}
done = custom_compare(match_block, a, b);
} else {
done = state_match_func(new_state.get(),
next_line_data->in_state.get());
}
}
}
lock_data.unlock();
if (lock.owns_lock())
lock.unlock();
}
if (!running.load(std::memory_order_relaxed)) {
free(text);
return;
prev_state =
line_data->out_state ? line_data->out_state->clone() : nullptr;
cur_line++;
if (done)
break;
}
free(it->buffer);
free(it);
}
free(text);
lock_data.lock();
}
void Parser::scroll(uint32_t line) {
if (line != scroll_max) {
scroll_max = line;
uint32_t c_line = line > 50 ? line - 50 : 0;
if (c_line >= line_tree.count())
return;
std::unique_lock lock_data(data_mutex);
if (line_tree.at(c_line)->in_state || line_tree.at(c_line)->out_state)
return;
scroll_dirty = true;
dirty_lines.push(c_line);
} else {
scroll_max = line;
}
}
void Parser::scroll(uint32_t line) { scroll_max = line; }
+122 -118
View File
@@ -241,20 +241,22 @@ struct RubyFullState {
}
};
struct RubyState {
struct RubyState : StateBase {
using full_state_type = RubyFullState;
int interp_level = 0;
std::stack<std::shared_ptr<RubyFullState>> interp_stack;
std::shared_ptr<RubyFullState> full_state;
std::stack<RubyFullState> interp_stack;
RubyFullState full_state;
std::deque<HeredocInfo> heredocs;
bool operator==(const RubyState &other) const {
return interp_level == other.interp_level &&
interp_stack == other.interp_stack &&
((full_state && other.full_state &&
*full_state == *other.full_state)) &&
heredocs == other.heredocs;
full_state == other.full_state && heredocs == other.heredocs;
}
std::unique_ptr<StateBase> clone() const override {
return std::make_unique<RubyState>(*this);
}
};
@@ -278,18 +280,16 @@ inline static uint32_t get_next_word(const char *text, uint32_t i,
return width;
}
bool ruby_state_match(std::shared_ptr<void> state_1,
std::shared_ptr<void> state_2) {
bool ruby_state_match(StateBase *state_1, StateBase *state_2) {
if (!state_1 || !state_2)
return false;
return *std::static_pointer_cast<RubyState>(state_1) ==
*std::static_pointer_cast<RubyState>(state_2);
return *static_cast<RubyState *>(state_1) ==
*static_cast<RubyState *>(state_2);
}
std::shared_ptr<void> ruby_parse(std::vector<Token> *tokens,
std::shared_ptr<void> in_state,
const char *text, uint32_t len,
uint32_t line_num) {
std::unique_ptr<StateBase> ruby_parse(std::vector<Token> *tokens,
StateBase *in_state, const char *text,
uint32_t len, uint32_t line_num) {
static bool keywords_trie_init = false;
static Trie<void> base_keywords_trie;
static Trie<void> expecting_keywords_trie;
@@ -313,7 +313,11 @@ std::shared_ptr<void> ruby_parse(std::vector<Token> *tokens,
keywords_trie_init = true;
}
tokens->clear();
auto state = ensure_state(std::static_pointer_cast<RubyState>(in_state));
std::unique_ptr<RubyState> state;
if (in_state)
state = static_unique_ptr_cast<RubyState>(in_state->clone());
else
state = std::make_unique<RubyState>();
uint32_t i = 0;
while (len > 0 && (text[len - 1] == '\n' || text[len - 1] == '\r' ||
text[len - 1] == '\t' || text[len - 1] == ' '))
@@ -322,18 +326,18 @@ std::shared_ptr<void> ruby_parse(std::vector<Token> *tokens,
return state;
bool heredoc_first = false;
while (i < len) {
if (state->full_state->in_state == RubyFullState::END)
if (state->full_state.in_state == RubyFullState::END)
return state;
if (state->full_state->in_state == RubyFullState::COMMENT) {
if (state->full_state.in_state == RubyFullState::COMMENT) {
tokens->push_back({i, len, TokenKind::K_COMMENT});
if (i == 0 && len == 4 && text[i] == '=' && text[i + 1] == 'e' &&
text[i + 2] == 'n' && text[i + 3] == 'd') {
state->full_state->in_state = RubyFullState::NONE;
state->full_state.in_state = RubyFullState::NONE;
}
return state;
}
if (!heredoc_first &&
state->full_state->in_state == RubyFullState::HEREDOC) {
state->full_state.in_state == RubyFullState::HEREDOC) {
if (i == 0) {
uint32_t start = 0;
if (state->heredocs.front().allow_indentation)
@@ -344,7 +348,7 @@ std::shared_ptr<void> ruby_parse(std::vector<Token> *tokens,
state->heredocs.front().delim.length())) {
state->heredocs.pop_front();
if (state->heredocs.empty())
state->full_state->in_state = RubyFullState::NONE;
state->full_state.in_state = RubyFullState::NONE;
tokens->push_back({i, len, TokenKind::K_ANNOTATION});
return state;
}
@@ -421,7 +425,7 @@ std::shared_ptr<void> ruby_parse(std::vector<Token> *tokens,
tokens->push_back({i, i + 2, TokenKind::K_INTERPOLATION});
i += 2;
state->interp_stack.push(state->full_state);
state->full_state = std::make_shared<RubyFullState>();
state->full_state = RubyFullState();
state->interp_level = 1;
break;
}
@@ -432,7 +436,7 @@ std::shared_ptr<void> ruby_parse(std::vector<Token> *tokens,
continue;
}
}
if (state->full_state->in_state == RubyFullState::STRING) {
if (state->full_state.in_state == RubyFullState::STRING) {
uint32_t start = i;
while (i < len) {
if (text[i] == '\\') {
@@ -496,36 +500,36 @@ std::shared_ptr<void> ruby_parse(std::vector<Token> *tokens,
tokens->push_back({start, i, TokenKind::K_ESCAPE});
continue;
}
if (state->full_state->lit.allow_interp && text[i] == '#' &&
if (state->full_state.lit.allow_interp && text[i] == '#' &&
i + 1 < len && text[i + 1] == '{') {
tokens->push_back({start, i, TokenKind::K_STRING});
tokens->push_back({i, i + 2, TokenKind::K_INTERPOLATION});
i += 2;
state->interp_stack.push(state->full_state);
state->full_state = std::make_shared<RubyFullState>();
state->full_state = RubyFullState();
state->interp_level = 1;
break;
}
if (text[i] == state->full_state->lit.delim_start &&
state->full_state->lit.delim_start !=
state->full_state->lit.delim_end) {
state->full_state->lit.brace_level++;
if (text[i] == state->full_state.lit.delim_start &&
state->full_state.lit.delim_start !=
state->full_state.lit.delim_end) {
state->full_state.lit.brace_level++;
}
if (text[i] == state->full_state->lit.delim_end) {
if (state->full_state->lit.delim_start ==
state->full_state->lit.delim_end) {
if (text[i] == state->full_state.lit.delim_end) {
if (state->full_state.lit.delim_start ==
state->full_state.lit.delim_end) {
i++;
tokens->push_back({start, i, TokenKind::K_STRING});
state->full_state->in_state = RubyFullState::NONE;
state->full_state->expecting_expr = false;
state->full_state.in_state = RubyFullState::NONE;
state->full_state.expecting_expr = false;
break;
} else {
state->full_state->lit.brace_level--;
if (state->full_state->lit.brace_level == 0) {
state->full_state.lit.brace_level--;
if (state->full_state.lit.brace_level == 0) {
i++;
tokens->push_back({start, i, TokenKind::K_STRING});
state->full_state->in_state = RubyFullState::NONE;
state->full_state->expecting_expr = false;
state->full_state.in_state = RubyFullState::NONE;
state->full_state.expecting_expr = false;
break;
}
}
@@ -536,7 +540,7 @@ std::shared_ptr<void> ruby_parse(std::vector<Token> *tokens,
tokens->push_back({start, len, TokenKind::K_STRING});
continue;
}
if (state->full_state->in_state == RubyFullState::REGEXP) {
if (state->full_state.in_state == RubyFullState::REGEXP) {
uint32_t start = i;
while (i < len) {
if (text[i] == '\\') {
@@ -605,30 +609,30 @@ std::shared_ptr<void> ruby_parse(std::vector<Token> *tokens,
tokens->push_back({i, i + 2, TokenKind::K_INTERPOLATION});
i += 2;
state->interp_stack.push(state->full_state);
state->full_state = std::make_shared<RubyFullState>();
state->full_state = RubyFullState();
state->interp_level = 1;
break;
}
if (text[i] == state->full_state->lit.delim_start &&
state->full_state->lit.delim_start !=
state->full_state->lit.delim_end) {
state->full_state->lit.brace_level++;
if (text[i] == state->full_state.lit.delim_start &&
state->full_state.lit.delim_start !=
state->full_state.lit.delim_end) {
state->full_state.lit.brace_level++;
}
if (text[i] == state->full_state->lit.delim_end) {
if (state->full_state->lit.delim_start ==
state->full_state->lit.delim_end) {
if (text[i] == state->full_state.lit.delim_end) {
if (state->full_state.lit.delim_start ==
state->full_state.lit.delim_end) {
i += 1;
tokens->push_back({start, i, TokenKind::K_REGEXP});
state->full_state->in_state = RubyFullState::NONE;
state->full_state->expecting_expr = false;
state->full_state.in_state = RubyFullState::NONE;
state->full_state.expecting_expr = false;
break;
} else {
state->full_state->lit.brace_level--;
if (state->full_state->lit.brace_level == 0) {
state->full_state.lit.brace_level--;
if (state->full_state.lit.brace_level == 0) {
i += 1;
tokens->push_back({start, i, TokenKind::K_REGEXP});
state->full_state->in_state = RubyFullState::NONE;
state->full_state->expecting_expr = false;
state->full_state.in_state = RubyFullState::NONE;
state->full_state.expecting_expr = false;
break;
}
}
@@ -642,8 +646,8 @@ std::shared_ptr<void> ruby_parse(std::vector<Token> *tokens,
if (i == 0 && len == 6) {
if (text[i] == '=' && text[i + 1] == 'b' && text[i + 2] == 'e' &&
text[i + 3] == 'g' && text[i + 4] == 'i' && text[i + 5] == 'n') {
state->full_state->in_state = RubyFullState::COMMENT;
state->full_state->expecting_expr = false;
state->full_state.in_state = RubyFullState::COMMENT;
state->full_state.expecting_expr = false;
tokens->push_back({0, len, TokenKind::K_COMMENT});
return state;
}
@@ -653,8 +657,8 @@ std::shared_ptr<void> ruby_parse(std::vector<Token> *tokens,
text[i + 3] == 'N' && text[i + 4] == 'D' && text[i + 5] == '_' &&
text[i + 6] == '_') {
tokens->clear();
state->full_state->in_state = RubyFullState::END;
state->full_state->expecting_expr = false;
state->full_state.in_state = RubyFullState::END;
state->full_state.expecting_expr = false;
return state;
}
}
@@ -684,33 +688,33 @@ std::shared_ptr<void> ruby_parse(std::vector<Token> *tokens,
delim += text[j++];
}
}
state->full_state->expecting_expr = false;
state->full_state.expecting_expr = false;
if (!delim.empty()) {
tokens->push_back({s, j, TokenKind::K_ANNOTATION});
state->heredocs.push_back({delim, interpolation, indented});
state->full_state->in_state = RubyFullState::HEREDOC;
state->full_state.in_state = RubyFullState::HEREDOC;
heredoc_first = true;
}
i = j;
continue;
}
if (text[i] == '/' && state->full_state->expecting_expr) {
if (text[i] == '/' && state->full_state.expecting_expr) {
tokens->push_back({i, i + 1, TokenKind::K_REGEXP});
state->full_state->in_state = RubyFullState::REGEXP;
state->full_state->expecting_expr = false;
state->full_state->lit.delim_start = '/';
state->full_state->lit.delim_end = '/';
state->full_state->lit.allow_interp = true;
state->full_state.in_state = RubyFullState::REGEXP;
state->full_state.expecting_expr = false;
state->full_state.lit.delim_start = '/';
state->full_state.lit.delim_end = '/';
state->full_state.lit.allow_interp = true;
i++;
continue;
} else if (text[i] == '#') {
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});
return state;
}
tokens->push_back({i, len, TokenKind::K_COMMENT});
state->full_state->expecting_expr = false;
state->full_state.expecting_expr = false;
return state;
} else if (text[i] == '.') {
uint32_t start = i;
@@ -722,15 +726,15 @@ std::shared_ptr<void> ruby_parse(std::vector<Token> *tokens,
}
}
tokens->push_back({start, i, TokenKind::K_OPERATOR});
state->full_state->expecting_expr = false;
state->full_state.expecting_expr = false;
continue;
} else if (text[i] == ':') {
state->full_state->expecting_expr = false;
state->full_state.expecting_expr = false;
uint32_t start = i;
i++;
if (i >= len) {
tokens->push_back({start, i, TokenKind::K_OPERATOR});
state->full_state->expecting_expr = true;
state->full_state.expecting_expr = true;
continue;
}
if (text[i] == ':') {
@@ -739,7 +743,7 @@ std::shared_ptr<void> ruby_parse(std::vector<Token> *tokens,
}
if (text[i] == '\'' || text[i] == '"') {
tokens->push_back({start, i, TokenKind::K_LABEL});
state->full_state->expecting_expr = true;
state->full_state.expecting_expr = true;
continue;
}
if (text[i] == '$' || text[i] == '@') {
@@ -767,7 +771,7 @@ std::shared_ptr<void> ruby_parse(std::vector<Token> *tokens,
tokens->push_back({start, i, TokenKind::K_OPERATOR});
continue;
} else if (text[i] == '@') {
state->full_state->expecting_expr = false;
state->full_state.expecting_expr = false;
uint32_t start = i;
i++;
if (i >= len)
@@ -783,7 +787,7 @@ std::shared_ptr<void> ruby_parse(std::vector<Token> *tokens,
tokens->push_back({start, i, TokenKind::K_VARIABLEINSTANCE});
continue;
} else if (text[i] == '$') {
state->full_state->expecting_expr = false;
state->full_state.expecting_expr = false;
uint32_t start = i;
i++;
if (i >= len)
@@ -806,7 +810,7 @@ std::shared_ptr<void> ruby_parse(std::vector<Token> *tokens,
tokens->push_back({start, i, TokenKind::K_VARIABLEGLOBAL});
continue;
} else if (text[i] == '?') {
state->full_state->expecting_expr = false;
state->full_state.expecting_expr = false;
uint32_t start = i;
i++;
if (i < len && text[i] == '\\') {
@@ -851,95 +855,95 @@ std::shared_ptr<void> ruby_parse(std::vector<Token> *tokens,
tokens->push_back({start, i, TokenKind::K_CHAR});
continue;
} else {
state->full_state->expecting_expr = true;
state->full_state.expecting_expr = true;
tokens->push_back({start, i, TokenKind::K_OPERATOR});
continue;
}
} else if (text[i] == '{') {
state->full_state->expecting_expr = true;
state->full_state.expecting_expr = true;
uint8_t brace_color =
(uint8_t)TokenKind::K_BRACE1 + (state->full_state->brace_level % 5);
(uint8_t)TokenKind::K_BRACE1 + (state->full_state.brace_level % 5);
tokens->push_back({i, i + 1, (TokenKind)brace_color});
state->interp_level++;
state->full_state->brace_level++;
state->full_state.brace_level++;
i++;
continue;
} else if (text[i] == '}') {
state->full_state->expecting_expr = false;
state->full_state.expecting_expr = false;
state->interp_level--;
if (state->interp_level == 0 && !state->interp_stack.empty()) {
state->full_state = state->interp_stack.top();
state->interp_stack.pop();
tokens->push_back({i, i + 1, TokenKind::K_INTERPOLATION});
} else {
state->full_state->brace_level--;
state->full_state.brace_level--;
uint8_t brace_color =
(uint8_t)TokenKind::K_BRACE1 + (state->full_state->brace_level % 5);
(uint8_t)TokenKind::K_BRACE1 + (state->full_state.brace_level % 5);
tokens->push_back({i, i + 1, (TokenKind)brace_color});
}
i++;
continue;
} else if (text[i] == '(') {
state->full_state->expecting_expr = true;
state->full_state.expecting_expr = true;
uint8_t brace_color =
(uint8_t)TokenKind::K_BRACE1 + (state->full_state->brace_level % 5);
(uint8_t)TokenKind::K_BRACE1 + (state->full_state.brace_level % 5);
tokens->push_back({i, i + 1, (TokenKind)brace_color});
state->full_state->brace_level++;
state->full_state.brace_level++;
i++;
continue;
} else if (text[i] == ')') {
state->full_state->expecting_expr = false;
state->full_state->brace_level--;
state->full_state.expecting_expr = false;
state->full_state.brace_level--;
uint8_t brace_color =
(uint8_t)TokenKind::K_BRACE1 + (state->full_state->brace_level % 5);
(uint8_t)TokenKind::K_BRACE1 + (state->full_state.brace_level % 5);
tokens->push_back({i, i + 1, (TokenKind)brace_color});
i++;
continue;
} else if (text[i] == '[') {
state->full_state->expecting_expr = true;
state->full_state.expecting_expr = true;
uint8_t brace_color =
(uint8_t)TokenKind::K_BRACE1 + (state->full_state->brace_level % 5);
(uint8_t)TokenKind::K_BRACE1 + (state->full_state.brace_level % 5);
tokens->push_back({i, i + 1, (TokenKind)brace_color});
state->full_state->brace_level++;
state->full_state.brace_level++;
i++;
continue;
} else if (text[i] == ']') {
state->full_state->expecting_expr = false;
state->full_state->brace_level--;
state->full_state.expecting_expr = false;
state->full_state.brace_level--;
uint8_t brace_color =
(uint8_t)TokenKind::K_BRACE1 + (state->full_state->brace_level % 5);
(uint8_t)TokenKind::K_BRACE1 + (state->full_state.brace_level % 5);
tokens->push_back({i, i + 1, (TokenKind)brace_color});
i++;
continue;
} else if (text[i] == '\'') {
state->full_state->expecting_expr = false;
state->full_state.expecting_expr = false;
tokens->push_back({i, i + 1, TokenKind::K_STRING});
state->full_state->in_state = RubyFullState::STRING;
state->full_state->lit.delim_start = '\'';
state->full_state->lit.delim_end = '\'';
state->full_state->lit.allow_interp = false;
state->full_state.in_state = RubyFullState::STRING;
state->full_state.lit.delim_start = '\'';
state->full_state.lit.delim_end = '\'';
state->full_state.lit.allow_interp = false;
i++;
continue;
} else if (text[i] == '"') {
state->full_state->expecting_expr = false;
state->full_state.expecting_expr = false;
tokens->push_back({i, i + 1, TokenKind::K_STRING});
state->full_state->in_state = RubyFullState::STRING;
state->full_state->lit.delim_start = '"';
state->full_state->lit.delim_end = '"';
state->full_state->lit.allow_interp = true;
state->full_state.in_state = RubyFullState::STRING;
state->full_state.lit.delim_start = '"';
state->full_state.lit.delim_end = '"';
state->full_state.lit.allow_interp = true;
i++;
continue;
} else if (text[i] == '`') {
state->full_state->expecting_expr = false;
state->full_state.expecting_expr = false;
tokens->push_back({i, i + 1, TokenKind::K_STRING});
state->full_state->in_state = RubyFullState::STRING;
state->full_state->lit.delim_start = '`';
state->full_state->lit.delim_end = '`';
state->full_state->lit.allow_interp = true;
state->full_state.in_state = RubyFullState::STRING;
state->full_state.lit.delim_start = '`';
state->full_state.lit.delim_end = '`';
state->full_state.lit.allow_interp = true;
i++;
continue;
} else if (text[i] == '%') {
state->full_state->expecting_expr = false;
state->full_state.expecting_expr = false;
if (i + 1 >= len) {
i++;
continue;
@@ -1005,16 +1009,16 @@ std::shared_ptr<void> ruby_parse(std::vector<Token> *tokens,
tokens->push_back(
{i, i + prefix_len + 1,
(is_regexp ? TokenKind::K_REGEXP : TokenKind::K_STRING)});
state->full_state->in_state =
state->full_state.in_state =
is_regexp ? RubyFullState::REGEXP : RubyFullState::STRING;
state->full_state->lit.delim_start = delim_start;
state->full_state->lit.delim_end = delim_end;
state->full_state->lit.allow_interp = allow_interp;
state->full_state->lit.brace_level = 1;
state->full_state.lit.delim_start = delim_start;
state->full_state.lit.delim_end = delim_end;
state->full_state.lit.allow_interp = allow_interp;
state->full_state.lit.brace_level = 1;
i += prefix_len + 1;
continue;
} else if (isdigit(text[i])) {
state->full_state->expecting_expr = false;
state->full_state.expecting_expr = false;
uint32_t start = i;
if (text[i] == '0') {
i++;
@@ -1115,7 +1119,7 @@ std::shared_ptr<void> ruby_parse(std::vector<Token> *tokens,
tokens->push_back({start, i, TokenKind::K_NUMBER});
continue;
} else if (identifier_start_char(text[i])) {
state->full_state->expecting_expr = false;
state->full_state.expecting_expr = false;
uint32_t length;
if ((length = base_keywords_trie.match(text, i, len, identifier_char))) {
tokens->push_back({i, i + length, TokenKind::K_KEYWORD});
@@ -1123,7 +1127,7 @@ std::shared_ptr<void> ruby_parse(std::vector<Token> *tokens,
continue;
} else if ((length = expecting_keywords_trie.match(text, i, len,
identifier_char))) {
state->full_state->expecting_expr = true;
state->full_state.expecting_expr = true;
tokens->push_back({i, i + length, TokenKind::K_KEYWORD});
i += length;
continue;
@@ -1134,7 +1138,7 @@ std::shared_ptr<void> ruby_parse(std::vector<Token> *tokens,
continue;
} else if ((length = expecting_operators_trie.match(
text, i, len, identifier_char)) > 0) {
state->full_state->expecting_expr = true;
state->full_state.expecting_expr = true;
tokens->push_back({i, i + length, TokenKind::K_KEYWORDOPERATOR});
i += length;
continue;
@@ -1256,7 +1260,7 @@ std::shared_ptr<void> ruby_parse(std::vector<Token> *tokens,
operator_trie.match(text, i, len, [](char) { return false; }))) {
tokens->push_back({i, i + op_len, TokenKind::K_OPERATOR});
i += op_len;
state->full_state->expecting_expr = true;
state->full_state.expecting_expr = true;
continue;
} else {
i += utf8_codepoint_width(text[i]);
+71 -59
View File
@@ -1,78 +1,90 @@
#include "ui/bar.h"
#include "io/sysio.h"
#include "lsp/lsp.h"
#include "main.h"
#include "syntax/decl.h"
#include "windows/decl.h"
void Bar::render() {
Editor *editor = editors[current_editor];
void Bar::log(std::string message) { log_line = strip_newlines(message); }
void Bar::render(std::vector<ScreenCell> &buffer) {
USING(LSPInstance);
BarLine bar_line;
bar_line =
bar_contents(mode, screen.col, pwd.string(), layout::focused_window);
auto update = [&](uint32_t row, uint32_t col, std::string text, uint32_t fg,
uint32_t bg, uint8_t flags, uint32_t width) {
ScreenCell &c = buffer[row * screen.col + col];
c.utf8 = text;
c.width = width;
c.fg = fg;
c.bg = bg;
c.flags = flags;
c.ul_color = 0;
};
uint32_t row = screen.row - 2;
uint32_t col = 0;
uint32_t width = screen.col;
UNUSED(width);
uint32_t color = 0;
uint32_t black = 0x0b0e14;
uint32_t grey = 0x33363c;
uint32_t dark_grey = 0x24272d;
uint32_t name_color = 0xced4df;
uint32_t lang_color = editor->lang.color;
const char *symbol = "󱓧 ";
const char *name = "EDITOR";
switch (mode) {
case NORMAL:
color = 0x82AAFF;
symbol = "";
name = "NORMAL";
break;
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;
std::string &line = bar_line.line;
uint32_t i = 0;
uint32_t col = 0;
while (i < line.length()) {
uint32_t cluster_len =
grapheme_next_character_break_utf8(line.c_str() + i, line.length() - i);
std::string cluster = line.substr(i, cluster_len);
int width = display_width(cluster.c_str(), cluster_len);
Highlight highlight = bar_line.get_highlight(col);
update(row, col, cluster.c_str(), highlight.fg, highlight.bg,
highlight.flags, width);
col += width;
i += cluster_len;
for (int w = 1; w < width; w++)
update(row, col - w, "\x1b", highlight.fg, highlight.bg, highlight.flags,
0);
}
update(row, col, " ", black, color, CF_BOLD);
update(row, ++col, symbol, black, color, CF_BOLD);
update(row, ++col, "\x1b", black, color, CF_BOLD);
update(row, ++col, " ", black, color, CF_BOLD);
for (uint32_t i = 0; i < 6; i++)
update(row, ++col, {name[i], 0}, black, color, CF_BOLD);
update(row, ++col, " ", black, color, CF_BOLD);
update(row, ++col, "", color, grey, CF_BOLD);
update(row, ++col, "", grey, dark_grey, CF_BOLD);
update(row, ++col, " ", name_color, dark_grey, CF_BOLD);
update(row, ++col, editor->lang.symbol, lang_color, dark_grey, 0);
update(row, ++col, "\x1b", lang_color, dark_grey, 0);
update(row, ++col, " ", name_color, dark_grey, CF_BOLD);
std::string filename = filename_from_path(editor->filename);
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);
while (col < width)
update(row, col++, " ", 0, 0, 0, 1);
col = 0;
row++;
if (mode == RUNNER) {
update(row, col++, ":", 0xFFFFFF, 0, 0, 1);
for (char c : command)
update(row, col++, (char[2]){c, 0}, 0xFFFFFF, 0, 0, 1);
} else {
for (char c : log_line)
update(row, col++, (char[2]){c, 0}, 0xFFFFFF, 0, 0, 1);
}
while (col < width)
update(row, col++, " ", 0, 0, 0, 1);
}
void Bar::handle(KeyEvent event) {
void Bar::handle_command(std::string &command) {
if (command == "q") {
running = false;
return;
}
if (layout::focused_window)
layout::focused_window->handle_command(command);
}
void Bar::handle_event(KeyEvent event) {
if (event.key_type == KEY_CHAR && event.len == 1) {
if (event.c[0] == 0x1B) {
command = "";
mode = NORMAL;
} else if (event.c[0] == '\n' || event.c[0] == '\r') {
// execute command while stripping starting `[:;]`
command = trim(command);
handle_command(command);
mode = NORMAL;
command = "";
} 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) {
switch (event.special_key) {
+33 -21
View File
@@ -1,4 +1,4 @@
#include "ui/completionbox.h"
/* #include "ui/completionbox.h"
#include "editor/completions.h"
#include "io/sysio.h"
#include "utils/utils.h"
@@ -71,7 +71,9 @@ void CompletionBox::render_update() {
uint32_t max_label_len = 0;
uint32_t max_detail_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())
continue;
auto &item = session->items[i];
@@ -81,10 +83,12 @@ void CompletionBox::render_update() {
max_kind_len =
MAX(max_kind_len, (uint32_t)item_kind_name(item.kind).size());
}
size.row = session->visible.size() + 2;
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});
auto set = [&](uint32_t r, uint32_t c, const char *text, uint32_t fg,
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; 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,
uint32_t bg, uint8_t flags) {
if (r < size.row && c < size.col)
cells[r * size.col + c] = {std::string(text), 0, fg, bg, flags, 0};
@@ -95,17 +99,16 @@ void CompletionBox::render_update() {
for (uint32_t c = 1; c < size.col - 1; c++)
set(0, c, "─", 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 r = row_idx + 1;
uint32_t start = session->scroll;
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]];
uint32_t bg = (session->visible[row_idx] == session->select) ? sel_bg : 1;
uint32_t fg = 0xFFFFFF;
set(r, 0, "", border_fg, 0, 0);
uint32_t c = 1;
const char *sym = item_symbol(item.kind);
set(r, c++, sym, kind_color(item.kind), bg, 0);
set(r, c++, " ", fg, bg, 0);
for (size_t i = 0; i < item.label.size(); i++)
uint32_t bg = (session->visible[row_idx] == session->select) ? sel_bg :
1; uint32_t fg = 0xFFFFFF; set(r, 0, "│", border_fg, 0, 0); uint32_t c =
1; const char *sym = item_symbol(item.kind); set(r, c++, sym,
kind_color(item.kind), bg, 0); set(r, c++, " ", fg, bg, 0); for (size_t i
= 0; i < item.label.size(); i++)
set(r, c + i, (char[2]){item.label[i], 0}, fg, bg,
item.deprecated ? CF_STRIKETHROUGH : 0);
c += item.label.size();
@@ -122,7 +125,8 @@ void CompletionBox::render_update() {
c += pad;
std::string kind_name = item_kind_name(item.kind);
for (size_t i = 0; i < kind_name.size(); i++)
set(r, c + i, (char[2]){kind_name[i], 0}, kind_color(item.kind), bg, 0);
set(r, c + i, (char[2]){kind_name[i], 0}, kind_color(item.kind), bg,
0);
set(r, size.col - 1, "│", border_fg, 0, 0);
}
uint32_t bottom = size.row - 1;
@@ -130,6 +134,13 @@ void CompletionBox::render_update() {
for (uint32_t c = 1; c < size.col - 1; c++)
set(bottom, c, "─", 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) {
@@ -140,9 +151,8 @@ void CompletionBox::render(Coord pos) {
if (start_row < 0)
start_row = pos.row + 1;
int32_t start_col = pos.col;
Coord screen_size = get_size();
if (start_col + size.col > screen_size.col) {
start_col = screen_size.col - size.col;
if (start_col + size.col > io::cols) {
start_col = io::cols - size.col;
if (start_col < 0)
start_col = 0;
}
@@ -168,8 +178,10 @@ void CompletionBox::render(Coord pos) {
position.col - session->hover.size.col});
} else {
session->hover.render(
{position.row + session->hover.size.row, position.col + size.col});
{position.row + session->hover.size.row, position.col +
size.col});
}
}
}
}
*/
+8 -50
View File
@@ -1,3 +1,4 @@
#include "ruby/decl.h"
#include "utils/utils.h"
std::unordered_map<std::string, Language> languages;
@@ -58,6 +59,7 @@ char *load_file(const char *path, uint32_t *out_len, bool *out_eol) {
bool has_utf8_bom = (bom[0] == 0xEF && bom[1] == 0xBB && bom[2] == 0xBF);
uint32_t skip = has_utf8_bom ? 3 : 0;
uint32_t data_len = static_cast<uint32_t>(len) - skip;
file.clear();
file.seekg(skip, std::ios::beg);
char *buf = (char *)malloc(data_len + 1);
if (!buf)
@@ -107,60 +109,16 @@ static std::string file_extension(const char *filename) {
Language language_for_file(const char *filename) {
std::string ext = file_extension(filename);
std::string lang_name;
if (!ext.empty()) {
auto it = language_extensions.find(ext);
if (it != language_extensions.end())
return languages.find(it->second)->second;
}
std::string lang_name = ruby_file_detect(filename);
if (!lang_name.empty()) {
auto it = languages.find(lang_name);
if (it != languages.end())
return it->second;
}
return Language{};
}
char *get_from_clipboard(uint32_t *out_len) {
FILE *pipe = popen("xclip -selection clipboard -o", "r");
if (!pipe) {
*out_len = 0;
return nullptr;
}
size_t capacity = 4096;
size_t length = 0;
char *buffer = (char *)malloc(capacity);
if (!buffer) {
pclose(pipe);
*out_len = 0;
return nullptr;
}
size_t n;
while ((n = fread(buffer + length, 1, capacity - length, pipe)) > 0) {
length += n;
if (length == capacity) {
capacity *= 2;
char *tmp = (char *)realloc(buffer, capacity);
if (!tmp) {
free(buffer);
pclose(pipe);
*out_len = 0;
return nullptr;
}
buffer = tmp;
}
}
pclose(pipe);
char *result = (char *)realloc(buffer, length + 1);
if (result) {
result[length] = '\0';
buffer = result;
} else {
buffer[length] = '\0';
}
*out_len = length;
return buffer;
}
void copy_to_clipboard(const char *text, size_t len) {
FILE *pipe = popen("xclip -selection clipboard", "w");
if (!pipe)
return;
fwrite(text, sizeof(char), len, pipe);
pclose(pipe);
}
+9
View File
@@ -91,6 +91,15 @@ std::string trim(const std::string &s) {
return s.substr(start, end - start + 1);
}
std::string strip_newlines(const std::string &s) {
std::string out;
out.reserve(s.size());
for (char c : s)
if (c != '\n' && c != '\r')
out.push_back(c);
return out;
}
std::string clean_text(const std::string &input) {
std::string result = input;
static const std::unordered_map<std::string, std::string> entities = {
+49
View File
@@ -0,0 +1,49 @@
#include "io/sysio.h"
#include "main.h"
#include "windows/decl.h"
namespace layout {
TileBase root_tile;
Window *focused_window;
std::vector<std::unique_ptr<Popup>> popups;
std::vector<std::unique_ptr<TileBase>> floating_tiles;
} // namespace layout
void render() {
ui::bar.render(io::new_screen);
layout::root_tile.render(io::new_screen);
for (auto &tile : layout::floating_tiles) {
if (tile->hidden())
continue;
tile->render(io::new_screen);
}
for (auto &popup : layout::popups) {
if (popup->hidden)
continue;
popup->render(io::new_screen, popup->size, popup->pos);
}
}
void handle_click(KeyEvent event) {
for (auto &popup : layout::popups) {
if (!popup->hidden &&
inside({event.mouse_y, event.mouse_x}, popup->pos, popup->size)) {
event.mouse_x -= popup->pos.col;
event.mouse_y -= popup->pos.row;
popup->handle_click(event, popup->size);
return;
}
}
for (auto &tile : layout::floating_tiles) {
if (!tile->hidden() &&
inside({event.mouse_y, event.mouse_x}, tile->pos, tile->size)) {
event.mouse_x -= tile->pos.col;
event.mouse_y -= tile->pos.row;
tile->handle_click(event);
return;
}
}
if (inside({event.mouse_y, event.mouse_x}, layout::root_tile.pos,
layout::root_tile.size))
layout::root_tile.handle_click(event);
}