Fix file permissions

This commit is contained in:
2026-07-01 18:53:49 +01:00
parent 013bffcad9
commit 10287e1750
107 changed files with 882 additions and 827 deletions
Executable → Regular
View File
Executable → Regular
View File
Executable → Regular
View File
Executable → Regular
View File
Executable → Regular
View File
Executable → Regular
+2 -2
View File
@@ -20,7 +20,7 @@ CFLAGS_DEBUG :=\
-O0 -fno-inline -gsplit-dwarf \ -O0 -fno-inline -gsplit-dwarf \
-g -fno-omit-frame-pointer \ -g -fno-omit-frame-pointer \
-Wno-unused-command-line-argument \ -Wno-unused-command-line-argument \
-I./include -I./libs -I/home/syed/main/crib/libs/mruby/include -I./include -I./libs -I./libs/mruby/include
# C_SANITIZER := -fsanitize=address # C_SANITIZER := -fsanitize=address
@@ -33,7 +33,7 @@ CFLAGS_RELEASE :=\
-fomit-frame-pointer -DNDEBUG -s \ -fomit-frame-pointer -DNDEBUG -s \
-mllvm -vectorize-loops \ -mllvm -vectorize-loops \
-Wno-unused-command-line-argument \ -Wno-unused-command-line-argument \
-I./include -I./libs -I/home/syed/main/crib/libs/mruby/include -I./include -I./libs -I./libs/mruby/include
PCH_CFLAGS_DEBUG := $(CFLAGS_DEBUG) -x c++-header PCH_CFLAGS_DEBUG := $(CFLAGS_DEBUG) -x c++-header
PCH_CFLAGS_RELEASE := $(CFLAGS_RELEASE) -x c++-header PCH_CFLAGS_RELEASE := $(CFLAGS_RELEASE) -x c++-header
Executable → Regular
View File
Executable → Regular
+129 -68
View File
@@ -2,33 +2,42 @@ Copyright 2025 Syed Daanish
# TODO # TODO
- 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 - And factorize renderer into its own class
- which is just managed by the renderer - which is just managed by the renderer
- and adjusment.cc will call it - and adjusment.cc will call it
- which is reused by scrollers/ensurers too (for knowing screen wrapped end) - which is reused by scrollers/ensurers too (for knowing screen wrapped end)
- this will then allow inlay hints to be possible - this will then allow inlay hints to be possible
- and also make VAI easier to implement - 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 * Allow keybinds to be set in ruby
* ruby file for project specific runs alongside any system wide ones * 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. - 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 - 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) - 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) - 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 - thin mode only shares screen diffing over the network - uses server settings / themes / shell
- only one user connects at a time - 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) - 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 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 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 - 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 - 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) - 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 - 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) - 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 share same lsp instances
- they all have the same shell access - 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) - 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 allow ruby code to create and handle windows as extentions
* Then 3 inbuilt extentions being file manager, theme picker, tab selector * Then 3 inbuilt extentions being file manager, theme picker, tab selector
@@ -37,8 +46,8 @@ Copyright 2025 Syed Daanish
* also implement info strings for all the stuff that take focus * 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) * 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 - 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 - 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) * 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) * Extentions can also be used as file openers (for like databases . diffing . images . audio etc)
@@ -59,10 +68,10 @@ Copyright 2025 Syed Daanish
* Add a file picker suggestion while typing a path (including stuff like ~ and .. and $HOME etc) * Add a file picker suggestion while typing a path (including stuff like ~ and .. and $HOME etc)
* allow opening directory after filemanger is sorted out. * allow opening directory after filemanger is sorted out.
* commands to: * commands to:
change pwd change pwd
load a rb file load a rb file
run a ruby command run a ruby command
close a window etc. close a window etc.
* [ ] Add mgems for most common things and a ruby library to allow combining true ruby with mruby * [ ] 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 * add command to set and use a file type at runtime
* [ ] color alpha in ini files * [ ] color alpha in ini files
@@ -70,12 +79,12 @@ Copyright 2025 Syed Daanish
* [ ] **LSP Bug:** Check why `fish-lsp` is behaving so off with completions filtering. * [ ] **LSP Bug:** Check why `fish-lsp` is behaving so off with completions filtering.
* [ ] **Line move:** fix the move line functions to work without the calculations from folds as folds are removed. * [ ] **Line move:** fix the move line functions to work without the calculations from folds as folds are removed.
* [ ] **Editor Indentation Fix:** - Main : merger indentation with the parser for more accurate results. * [ ] **Editor Indentation Fix:** - Main : merger indentation with the parser for more accurate results.
* [ ] Ignore comments/strings from parser when auto-indenting. - [ ] 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) - [ ] Support for stuff like bash \ and math operators in other languages and comma and line starting with a dot (like in ruby)
etc. etc.
* [ ] **Readme:** Update readme to show ruby based config in detail. * [ ] **Readme:** Update readme to show ruby based config in detail.
* [ ] **UI Refinement:** * [ ] **UI Refinement:**
* [ ] Finish autocomplete box style functions. - [ ] Finish autocomplete box style functions.
* [ ] **Documentation UI:** Capture `Ctrl+h` / `Ctrl+l` for scrolling documentation windows. * [ ] **Documentation UI:** Capture `Ctrl+h` / `Ctrl+l` for scrolling documentation windows.
* Cap line_tree data limit for large files and just store about a thousand previous lines maybe? (lazily loaded) * Cap line_tree data limit for large files and just store about a thousand previous lines maybe? (lazily loaded)
@@ -88,17 +97,17 @@ Copyright 2025 Syed Daanish
* allow flushing functions in ruby to tell c++ to refresh keybinds/themes etc. * allow flushing functions in ruby to tell c++ to refresh keybinds/themes etc.
* [ ] **LSP:** * [ ] **LSP:**
support snippets in completion properly support snippets in completion properly
check:: check::
pull diagnostics for ruby-lsp pull diagnostics for ruby-lsp
lsp selection range - use to highlight start / end of range maybe? lsp selection range - use to highlight start / end of range maybe?
goto definiton goto definiton
signature help signature help
document symbol for the top bar maybe? (or workspace symbol) document symbol for the top bar maybe? (or workspace symbol)
also setup workspaces also setup workspaces
Semantic highlighting Semantic highlighting
Quick fixes Quick fixes
Rename symbols Rename symbols
* Allow ruby to config lsp capabilities * Allow ruby to config lsp capabilities
@@ -122,49 +131,45 @@ Copyright 2025 Syed Daanish
### UX ### UX
* [ ] **Completion Filtering:** - [ ] **Completion Filtering:**
* [ ] Stop filtering case-sensitive. - [ ] Stop filtering case-sensitive.
* [ ] Normalize completion edits if local filtering is used. - [ ] Normalize completion edits if local filtering is used.
* [ ] **Basic Autocomplete:** Keep a list of words in the current buffer for non-LSP fallback. - [ ] **Basic Autocomplete:** Keep a list of words in the current buffer for non-LSP fallback.
### Features ### Features
* [ ] **Search & Replace:** - [ ] **Search & Replace:**
* [ ] Add Search/Replace UI. - [ ] Add Search/Replace UI.
* [ ] Support capture groups (`$1`, `$2`) or allow Perl regex directly. - [ ] Support capture groups (`$1`, `$2`) or allow Perl regex directly.
* [ ] Ensure virtual cursors are included in search positions. - [ ] Ensure virtual cursors are included in search positions.
* [ ] **Multi-Cursor:** - [ ] **Multi-Cursor:**
* [ ] Add virtual cursor support (edits apply to all locations). - [ ] Add virtual cursor support (edits apply to all locations).
* [ ] Add `Alt+Click` to set multiple cursors. - [ ] Add `Alt+Click` to set multiple cursors.
* [ ] Allow search and place cursor at all matches. - [ ] Allow search and place cursor at all matches.
* [ ] **Block Selection:** - [ ] **Block Selection:**
* [ ] Double-clicking a bracket selects the whole block and sets mode to `WORD`. - [ ] Double-clicking a bracket selects the whole block and sets mode to `WORD`.
### Visuals, UI & Extensions? ### Visuals, UI & Extensions?
* [ ] Add color picker/palette (as a floating extention). - [ ] Add color picker/palette (as a floating extention).
* [ ] **Git:** Add Git integration (status, diffs). - [ ] **Git:** Add Git integration (status, diffs).
* [ ] **AI/Snippets:** - [ ] **AI/Snippets:**
* [ ] Add snippets support (LuaSnip/VSnip style). - [ ] Add snippets support (LuaSnip/VSnip style).
* [ ] Add Codeium/Copilot support (using VAI virtual text) as a test phase. - [ ] 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) (as ruby extension).
- [ ] **Prolly?:** Add Splash Screen / Minigame.
### Unimportant optimizations ### Unimportant optimizations
* [ ] **Performance:** - [ ] **Performance:**
* [ ] Switch JSON parser to `RapidJSON` (or similar high-performance lib). - [ ] Switch JSON parser to `RapidJSON` (or similar high-performance lib).
* [ ] Decrease usage of `std::string` in UI, LSP, warnings etc. - [ ] Decrease usage of `std::string` in UI, LSP, warnings etc.
* [ ] Also for vectors into managed memory especially for completions/lsp-stuff. - [ ] Also for vectors into managed memory especially for completions/lsp-stuff.
<!-- The pits of hell: --> <!-- The pits of hell: -->
<!-- * Replace perfectly working superfast rope with a structure that stores for small files everything --> <!-- * Replace perfectly working superfast rope with a structure that stores for small files everything -->
@@ -173,3 +178,59 @@ Copyright 2025 Syed Daanish
<!-- - also for the line mode still go through entire file to get and store line offsets --> <!-- - 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) --> <!-- - 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 --> <!-- - it stores the line text as-is which is only unicode / crlf normalized during usage -->
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
Executable → Regular
View File
Executable → Regular
View File
Executable → Regular
View File
Executable → Regular
+5
View File
@@ -1,6 +1,7 @@
#ifndef EDITOR_H #ifndef EDITOR_H
#define EDITOR_H #define EDITOR_H
#include "editor/decl.h"
#include "editor/hooks.h" #include "editor/hooks.h"
#include "editor/indents.h" #include "editor/indents.h"
#include "editor/visual.h" #include "editor/visual.h"
@@ -101,6 +102,10 @@ struct Editor : Window {
void lsp_handle(json msg); void lsp_handle(json msg);
void apply_lsp_edits(std::vector<TextEdit> edits, bool move); 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_left(Coord cursor, uint32_t number);
Coord move_right(Coord cursor, uint32_t number); Coord move_right(Coord cursor, uint32_t number);
Executable → Regular
View File
Executable → Regular
View File
Executable → Regular
View File
Executable → Regular
View File
+19 -9
View File
@@ -1,10 +1,11 @@
#ifndef EDITOR_COMPLETIONS_H #ifndef EXTENTION_COMPLETION_H
#define EDITOR_COMPLETIONS_H #define EXTENTION_COMPLETION_H
#include "editor/decl.h"
#include "io/sysio.h"
#include "pch.h" #include "pch.h"
#include "ui/completionbox.h"
#include "ui/hover.h"
#include "utils/utils.h" #include "utils/utils.h"
#include "windows/decl.h"
struct CompletionItem { struct CompletionItem {
std::string label; std::string label;
@@ -22,12 +23,19 @@ struct CompletionItem {
std::vector<char> end_chars; 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 CompletionSession {
struct Editor *editor; struct Editor *editor;
std::shared_mutex mtx; std::shared_mutex mtx;
bool active = false; bool active = false;
Coord hook; Coord hook;
std::optional<std::string> prefix;
uint32_t select = 0; uint32_t select = 0;
uint32_t scroll = 0; uint32_t scroll = 0;
std::vector<CompletionItem> items; std::vector<CompletionItem> items;
@@ -35,14 +43,12 @@ struct CompletionSession {
bool complete = true; bool complete = true;
std::optional<char> trigger_char; std::optional<char> trigger_char;
uint8_t trigger = 0; uint8_t trigger = 0;
CompletionBox box; CompletionBox *box = nullptr;
HoverBox hover;
uint32_t doc = UINT32_MAX; uint32_t doc = UINT32_MAX;
std::atomic<bool> hover_dirty = false; std::atomic<bool> hover_dirty = false;
int version; int version;
CompletionSession(Editor *editor) : editor(editor), box(this) {} CompletionSession(Editor *editor) : editor(editor) {}
void resolve_doc(); void resolve_doc();
void accept(); void accept();
void next(); void next();
@@ -51,4 +57,8 @@ struct CompletionSession {
void handle(KeyEvent event); void handle(KeyEvent event);
}; };
CompletionBox *init_completion_box(CompletionSession *session);
void completion_request(Editor *editor);
void completion_filter(Editor *editor);
#endif #endif
Executable → Regular
View File
Executable → Regular
View File
Executable → Regular
View File
Executable → Regular
View File
Executable → Regular
View File
Executable → Regular
View File
Executable → Regular
View File
Executable → Regular
View File
Executable → Regular
View File
Executable → Regular
View File
Executable → Regular
View File
Executable → Regular
View File
Executable → Regular
View File
Executable → Regular
View File
Executable → Regular
View File
Executable → Regular
View File
Executable → Regular
View File
Executable → Regular
View File
-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
Executable → Regular
View File
Executable → Regular
View File
Vendored Executable → Regular
View File
Vendored Executable → Regular
View File
Executable → Regular
View File
Executable → Regular
View File
Executable → Regular
View File
Executable → Regular
View File
Executable → Regular
View File
Executable → Regular
View File
Executable → Regular
View File
Executable → Regular
View File
Executable → Regular
View File
Executable → Regular
View File
Executable → Regular
View File
Executable → Regular
View File
Executable → Regular
View File
Executable → Regular
View File
Executable → Regular
View File
Executable → Regular
View File
Executable → Regular
View File
Executable → Regular
View File
Executable → Regular
View File
Executable → Regular
View File
Executable → Regular
View File
Executable → Regular
View File
Executable → Regular
View File
Executable → Regular
View File
Executable → Regular
View File
Executable → Regular
View File
Executable → Regular
View File
Executable → Regular
+4 -1
View File
@@ -17,7 +17,10 @@ void Editor::ensure_cursor() {
render_height < this->size.row) { render_height < this->size.row) {
render_height++; render_height++;
last_visible = vline.first; last_visible = vline.first;
if (cursor >= vline.first && cursor < vline.second) 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; return;
} }
cursor = last_visible; cursor = last_visible;
Executable → Regular
View File
Executable → Regular
View File
Executable → Regular
View File
Executable → Regular
+456 -458
View File
@@ -1,458 +1,456 @@
// #include "editor/decl.h" /* #include "editor/editor.h"
// #include "editor/editor.h" #include "io/knot.h"
// #include "io/knot.h" #include "io/sysio.h"
// #include "io/sysio.h" #include "main.h"
// #include "lsp/lsp.h" #include "ui/completionbox.h"
// #include "main.h" #include "utils/utils.h"
// #include "ui/completionbox.h"
// #include "utils/utils.h" inline static std::string completion_prefix(Editor *editor) {
// Coord hook = editor->completion.hook;
// inline static std::string completion_prefix(Editor *editor) { Coord cur = editor->cursor;
// Coord hook = editor->completion.hook; if (hook.row != cur.row || cur.col < hook.col)
// Coord cur = editor->cursor; return "";
// if (hook.row != cur.row || cur.col < hook.col) LineIterator *it = begin_l_iter(editor->root, hook.row);
// return ""; uint32_t line_len;
// LineIterator *it = begin_l_iter(editor->root, hook.row); char *line = next_line(it, &line_len);
// uint32_t line_len; if (!line) {
// char *line = next_line(it, &line_len); free(it->buffer);
// if (!line) { free(it);
// free(it->buffer); return "";
// free(it); }
// return ""; std::string prefix(line + hook.col, cur.col - hook.col);
// } free(it->buffer);
// std::string prefix(line + hook.col, cur.col - hook.col); free(it);
// free(it->buffer); return prefix;
// free(it); }
// return prefix;
// } inline static void completion_adjust_scroll(CompletionSession &s) {
// if (s.visible.empty())
// inline static void completion_adjust_scroll(CompletionSession &s) { return;
// if (s.visible.empty()) int vi = -1;
// return; for (size_t i = 0; i < s.visible.size(); i++)
// int vi = -1; if (s.visible[i] == s.select) {
// for (size_t i = 0; i < s.visible.size(); i++) vi = (int)i;
// if (s.visible[i] == s.select) { break;
// vi = (int)i; }
// break; if (vi < 0)
// } return;
// if (vi < 0) if ((uint32_t)vi < s.scroll)
// return; s.scroll = vi;
// if ((uint32_t)vi < s.scroll) else if ((uint32_t)vi >= s.scroll + 8)
// s.scroll = vi; s.scroll = vi - 7;
// else if ((uint32_t)vi >= s.scroll + 8) }
// s.scroll = vi - 7;
// } void completion_filter(Editor *editor) {
// auto &session = editor->completion;
// void completion_filter(Editor *editor) { std::string prefix = completion_prefix(editor);
// auto &session = editor->completion; session.visible.clear();
// std::string prefix = completion_prefix(editor); for (size_t i = 0; i < session.items.size(); ++i) {
// session.visible.clear(); const auto &item = session.items[i];
// for (size_t i = 0; i < session.items.size(); ++i) { const std::string &key = item.filter;
// const auto &item = session.items[i]; if (key.size() >= prefix.size() &&
// const std::string &key = item.filter; key.compare(0, prefix.size(), prefix) == 0)
// if (key.size() >= prefix.size() && session.visible.push_back(i);
// key.compare(0, prefix.size(), prefix) == 0) }
// session.visible.push_back(i); if (session.visible.empty()) {
// } session.box.hidden = true;
// if (session.visible.empty()) { return;
// session.box.hidden = true; }
// return; if (std::find(session.visible.begin(), session.visible.end(),
// } session.select) == session.visible.end())
// if (std::find(session.visible.begin(), session.visible.end(), session.select = session.visible[0];
// session.select) == session.visible.end()) session.box.hidden = false;
// session.select = session.visible[0]; session.scroll = 0;
// session.box.hidden = false; completion_adjust_scroll(session);
// session.scroll = 0; session.box.render_update();
// completion_adjust_scroll(session); }
// session.box.render_update();
// } void completion_request(Editor *editor) {
// Coord hook = editor->cursor;
// void completion_request(Editor *editor) { editor->word_boundaries(editor->cursor, &hook.col, nullptr, nullptr,
// Coord hook = editor->cursor; nullptr); editor->completion.hook = hook; editor->completion.complete =
// editor->word_boundaries(editor->cursor, &hook.col, nullptr, nullptr, false; editor->completion.active = false; editor->completion.items.clear();
// nullptr); editor->completion.hook = hook; editor->completion.complete = editor->completion.visible.clear();
// false; editor->completion.active = false; editor->completion.items.clear(); editor->completion.select = 0;
// editor->completion.visible.clear(); editor->completion.version = editor->lsp_version;
// editor->completion.select = 0; LSPPending *pending = new LSPPending();
// editor->completion.version = editor->lsp_version; pending->editor = editor;
// LSPPending *pending = new LSPPending(); pending->callback = [](Editor *editor, const json &message) {
// pending->editor = editor; auto &session = editor->completion;
// pending->callback = [](Editor *editor, const json &message) { std::unique_lock lock(session.mtx);
// auto &session = editor->completion; std::vector<json> items_json;
// std::unique_lock lock(session.mtx); std::vector<char> end_chars_def;
// std::vector<json> items_json; int insert_text_format = 1;
// std::vector<char> end_chars_def; int insert_text_mode = 1;
// int insert_text_format = 1; if (message.contains("result")) {
// int insert_text_mode = 1; auto &result = message["result"];
// if (message.contains("result")) { if (result.is_array()) {
// auto &result = message["result"]; items_json = result.get<std::vector<json>>();
// if (result.is_array()) { session.complete = true;
// items_json = result.get<std::vector<json>>(); if (items_json.empty())
// session.complete = true; return;
// if (items_json.empty()) editor->completion.active = true;
// return; } else if (result.is_object() && result.contains("items")) {
// editor->completion.active = true; auto &list = result;
// } else if (result.is_object() && result.contains("items")) { items_json = list["items"].get<std::vector<json>>();
// auto &list = result; if (items_json.empty())
// items_json = list["items"].get<std::vector<json>>(); return;
// if (items_json.empty()) editor->completion.active = true;
// return; session.complete = !list.value("isIncomplete", false);
// editor->completion.active = true; if (list.contains("itemDefaults") &&
// session.complete = !list.value("isIncomplete", false); list["itemDefaults"].is_object()) {
// if (list.contains("itemDefaults") && auto &defs = list["itemDefaults"];
// list["itemDefaults"].is_object()) { if (defs.contains("insertTextFormat") &&
// auto &defs = list["itemDefaults"]; defs["insertTextFormat"].is_number())
// if (defs.contains("insertTextFormat") && insert_text_format = defs["insertTextFormat"].get<int>();
// defs["insertTextFormat"].is_number()) if (defs.contains("insertTextMode") &&
// insert_text_format = defs["insertTextFormat"].get<int>(); defs["insertTextMode"].is_number())
// if (defs.contains("insertTextMode") && insert_text_mode = defs["insertTextMode"].get<int>();
// defs["insertTextMode"].is_number()) if (defs.contains("textEdit"))
// insert_text_mode = defs["insertTextMode"].get<int>(); if (defs["textEdit"].is_array())
// if (defs.contains("textEdit")) for (auto &c : defs["textEdit"]) {
// if (defs["textEdit"].is_array()) if (!c.is_string())
// for (auto &c : defs["textEdit"]) { continue;
// if (!c.is_string()) std::string str = c.get<std::string>();
// continue; if (str.size() != 1)
// std::string str = c.get<std::string>(); continue;
// if (str.size() != 1) end_chars_def.push_back(str[0]);
// continue; }
// end_chars_def.push_back(str[0]); }
// } }
// } }
// } session.items.reserve(items_json.size() + 1);
// } session.visible.reserve(items_json.size() + 1);
// session.items.reserve(items_json.size() + 1); for (auto &item_json : items_json) {
// session.visible.reserve(items_json.size() + 1); CompletionItem item;
// for (auto &item_json : items_json) { item.original = item_json;
// CompletionItem item; item.label = item_json.value("label", "");
// item.original = item_json; item.kind = item_json.value("kind", 0);
// item.label = item_json.value("label", ""); if (item_json.contains("detail") && item_json["detail"].is_string())
// item.kind = item_json.value("kind", 0); item.detail = item_json["detail"].get<std::string>();
// if (item_json.contains("detail") && item_json["detail"].is_string()) if (item_json.contains("documentation")) {
// item.detail = item_json["detail"].get<std::string>(); if (item_json["documentation"].is_string()) {
// if (item_json.contains("documentation")) { item.documentation = item_json["documentation"].get<std::string>();
// if (item_json["documentation"].is_string()) { } else if (item_json["documentation"].contains("value") &&
// item.documentation = item_json["documentation"].get<std::string>(); item_json["documentation"]["value"].is_string()) {
// } else if (item_json["documentation"].contains("value") && item.is_markup =
// item_json["documentation"]["value"].is_string()) { item_json["documentation"]["kind"].get<std::string>() ==
// item.is_markup = "markdown";
// item_json["documentation"]["kind"].get<std::string>() == std::string documentation =
// "markdown"; item_json["documentation"]["value"].get<std::string>();
// std::string documentation = if (documentation.size() > 1024)
// item_json["documentation"]["value"].get<std::string>(); item.is_markup = false;
// if (documentation.size() > 1024) if (item.is_markup) {
// item.is_markup = false; item.documentation =
// if (item.is_markup) { substitute_fence(documentation, editor->lang.name);
// item.documentation = } else {
// substitute_fence(documentation, editor->lang.name); item.documentation = documentation;
// } else { }
// item.documentation = documentation; }
// } }
// } if (item_json.contains("deprecated") &&
// } item_json["deprecated"].is_boolean())
// if (item_json.contains("deprecated") && item.deprecated = item_json["deprecated"].get<bool>();
// item_json["deprecated"].is_boolean()) auto tags = item_json.value("tags", std::vector<int>());
// item.deprecated = item_json["deprecated"].get<bool>(); for (auto tag : tags)
// auto tags = item_json.value("tags", std::vector<int>()); if (tag == 1)
// for (auto tag : tags) item.deprecated = true;
// if (tag == 1) item.sort = item_json.value("sortText", item.label);
// item.deprecated = true; item.filter = item_json.value("filterText", item.label);
// item.sort = item_json.value("sortText", item.label); if (item_json.contains("preselect") &&
// item.filter = item_json.value("filterText", item.label); item_json["preselect"].is_boolean() &&
// if (item_json.contains("preselect") && item_json["preselect"].get<bool>())
// item_json["preselect"].is_boolean() && session.select = session.items.size() - 1;
// item_json["preselect"].get<bool>()) TextEdit edit;
// session.select = session.items.size() - 1; if (item_json.contains("textEdit")) {
// TextEdit edit; auto &te = item_json["textEdit"];
// if (item_json.contains("textEdit")) { if (te.contains("newText")) {
// auto &te = item_json["textEdit"]; edit.text = te.value("newText", "");
// if (te.contains("newText")) { if (te.contains("replace")) {
// edit.text = te.value("newText", ""); edit.start.row = te["replace"]["start"]["line"];
// if (te.contains("replace")) { edit.start.col = te["replace"]["start"]["character"];
// edit.start.row = te["replace"]["start"]["line"]; edit.end.row = te["replace"]["end"]["line"];
// edit.start.col = te["replace"]["start"]["character"]; edit.end.col = te["replace"]["end"]["character"];
// edit.end.row = te["replace"]["end"]["line"]; } else if (te.contains("insert")) {
// edit.end.col = te["replace"]["end"]["character"]; edit.start.row = te["insert"]["start"]["line"];
// } else if (te.contains("insert")) { edit.start.col = te["insert"]["start"]["character"];
// edit.start.row = te["insert"]["start"]["line"]; edit.end.row = te["insert"]["end"]["line"];
// edit.start.col = te["insert"]["start"]["character"]; edit.end.col = te["insert"]["end"]["character"];
// edit.end.row = te["insert"]["end"]["line"]; } else if (te.contains("range")) {
// edit.end.col = te["insert"]["end"]["character"]; edit.start.row = te["range"]["start"]["line"];
// } else if (te.contains("range")) { edit.start.col = te["range"]["start"]["character"];
// edit.start.row = te["range"]["start"]["line"]; edit.end.row = te["range"]["end"]["line"];
// edit.start.col = te["range"]["start"]["character"]; edit.end.col = te["range"]["end"]["character"];
// edit.end.row = te["range"]["end"]["line"]; } else {
// edit.end.col = te["range"]["end"]["character"]; edit.start = session.hook;
// } else { edit.end = editor->cursor;
// edit.start = session.hook; }
// edit.end = editor->cursor; }
// } } else if (item_json.contains("insertText") &&
// } item_json["insertText"].is_string()) {
// } else if (item_json.contains("insertText") && edit.text = item_json["insertText"].get<std::string>();
// item_json["insertText"].is_string()) { edit.start = session.hook;
// edit.text = item_json["insertText"].get<std::string>(); edit.end = editor->cursor;
// edit.start = session.hook; } else {
// edit.end = editor->cursor; edit.text = item.label;
// } else { edit.start = session.hook;
// edit.text = item.label; edit.end = editor->cursor;
// edit.start = session.hook; }
// edit.end = editor->cursor; editor->utf8_normalize_edit(&edit);
// } item.edits.push_back(edit);
// editor->utf8_normalize_edit(&edit); if (item_json.contains("additionalTextEdits")) {
// item.edits.push_back(edit); for (auto &te : item_json["additionalTextEdits"]) {
// if (item_json.contains("additionalTextEdits")) { TextEdit edit;
// for (auto &te : item_json["additionalTextEdits"]) { edit.text = te.value("newText", "");
// TextEdit edit; edit.start.row = te["range"]["start"]["line"];
// edit.text = te.value("newText", ""); edit.start.col = te["range"]["start"]["character"];
// edit.start.row = te["range"]["start"]["line"]; edit.end.row = te["range"]["end"]["line"];
// edit.start.col = te["range"]["start"]["character"]; edit.end.col = te["range"]["end"]["character"];
// edit.end.row = te["range"]["end"]["line"]; editor->utf8_normalize_edit(&edit);
// edit.end.col = te["range"]["end"]["character"]; item.edits.push_back(edit);
// editor->utf8_normalize_edit(&edit); }
// item.edits.push_back(edit); }
// } item.snippet = insert_text_format == 2;
// } if (item_json.contains("insertTextFormat"))
// item.snippet = insert_text_format == 2; item.snippet = item_json["insertTextFormat"].get<int>() == 2;
// if (item_json.contains("insertTextFormat")) if (item_json.contains("insertTextMode"))
// item.snippet = item_json["insertTextFormat"].get<int>() == 2; item.asis = item_json["insertTextMode"].get<int>() == 1;
// if (item_json.contains("insertTextMode")) if (item_json.contains("commitCharacters"))
// item.asis = item_json["insertTextMode"].get<int>() == 1; for (auto &c : item_json["commitCharacters"])
// if (item_json.contains("commitCharacters")) if (c.is_string() && c.get<std::string>().size() == 1)
// for (auto &c : item_json["commitCharacters"]) item.end_chars.push_back(c.get<std::string>()[0]);
// if (c.is_string() && c.get<std::string>().size() == 1) session.items.push_back(std::move(item));
// item.end_chars.push_back(c.get<std::string>()[0]); session.visible.push_back(session.items.size() - 1);
// session.items.push_back(std::move(item)); }
// session.visible.push_back(session.items.size() - 1); session.box.hidden = false;
// } session.box.render_update();
// session.box.hidden = false; };
// session.box.render_update(); LineIterator *it = begin_l_iter(editor->root, hook.row);
// }; uint32_t length;
// LineIterator *it = begin_l_iter(editor->root, hook.row); char *line = next_line(it, &length);
// uint32_t length; if (!line) {
// char *line = next_line(it, &length); free(it->buffer);
// if (!line) { free(it);
// free(it->buffer); return;
// free(it); }
// return; uint32_t col = utf8_offset_to_utf16(line, length, editor->cursor.col);
// } free(it->buffer);
// uint32_t col = utf8_offset_to_utf16(line, length, editor->cursor.col); free(it);
// free(it->buffer); json message = {
// free(it); {"jsonrpc", "2.0"},
// json message = { {"method", "textDocument/completion"},
// {"jsonrpc", "2.0"}, {"params",
// {"method", "textDocument/completion"}, {{"textDocument", {{"uri", editor->uri}}},
// {"params", {"position", {{"line", editor->cursor.row}, {"character", col}}}}}};
// {{"textDocument", {{"uri", editor->uri}}}, if (editor->completion.trigger > 0) {
// {"position", {{"line", editor->cursor.row}, {"character", col}}}}}}; json context = {{"triggerKind", editor->completion.trigger}};
// if (editor->completion.trigger > 0) { if (editor->completion.trigger == 2 && editor->completion.trigger_char)
// json context = {{"triggerKind", editor->completion.trigger}}; context["triggerCharacter"] =
// if (editor->completion.trigger == 2 && editor->completion.trigger_char) std::string(1, *editor->completion.trigger_char);
// context["triggerCharacter"] = message["params"]["context"] = context;
// std::string(1, *editor->completion.trigger_char); }
// message["params"]["context"] = context; lsp_send(editor->lsp, message, pending);
// } }
// lsp_send(editor->lsp, message, pending);
// } Move this into the box and merge the box and this guy
// void CompletionSession::handle(KeyEvent event) {
// // Move this into the box and merge the box and this guy if (!editor->lsp || !editor->lsp->allow_completion)
// void CompletionSession::handle(KeyEvent event) { return;
// if (!editor->lsp || !editor->lsp->allow_completion) if (mode != INSERT) {
// return; this->active = false;
// if (mode != INSERT) { return;
// this->active = false; }
// return; std::unique_lock lock(this->mtx);
// } if (event.key_type == KEY_PASTE) {
// std::unique_lock lock(this->mtx); this->active = false;
// if (event.key_type == KEY_PASTE) { return;
// this->active = false; } else if (event.key_type == KEY_CHAR) {
// return; char ch = *event.c;
// } else if (event.key_type == KEY_CHAR) { if (!this->active) {
// char ch = *event.c; for (char c : editor->lsp->trigger_chars)
// if (!this->active) { if (c == ch) {
// for (char c : editor->lsp->trigger_chars) this->trigger = 2;
// if (c == ch) { this->trigger_char = c;
// this->trigger = 2; completion_request(editor);
// this->trigger_char = c; return;
// completion_request(editor); }
// return; } else {
// } if (!editor->completion.items.empty()) {
// } else { const auto &item =
// if (!editor->completion.items.empty()) { editor->completion.items[editor->completion.select]; const
// const auto &item = std::vector<char> &end_chars =
// editor->completion.items[editor->completion.select]; const item.end_chars.empty() ? editor->lsp->end_chars : item.end_chars;
// std::vector<char> &end_chars = for (char c : end_chars)
// item.end_chars.empty() ? editor->lsp->end_chars : item.end_chars; if (c == ch) {
// for (char c : end_chars) this->accept();
// if (c == ch) { return;
// this->accept(); }
// return; }
// } }
// } if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') ||
// } (ch >= '0' && ch <= '9') || ch == '_') {
// if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || if (this->active) {
// (ch >= '0' && ch <= '9') || ch == '_') { if (this->complete)
// if (this->active) { completion_filter(editor);
// if (this->complete) else
// completion_filter(editor); completion_request(editor);
// else } else {
// completion_request(editor); this->trigger = 3;
// } else { completion_request(editor);
// this->trigger = 3; }
// completion_request(editor); } else if (ch == CTRL('\\')) {
// } if (this->active && !this->visible.empty()) {
// } else if (ch == CTRL('\\')) { this->accept();
// if (this->active && !this->visible.empty()) { } else {
// this->accept(); this->trigger = 1;
// } else { completion_request(editor);
// this->trigger = 1; }
// completion_request(editor); } else if (ch == CTRL('p')) {
// } if (this->active)
// } else if (ch == CTRL('p')) { this->next();
// if (this->active) } else if (ch == CTRL('o')) {
// this->next(); if (this->active)
// } else if (ch == CTRL('o')) { this->prev();
// if (this->active) } else if (ch == 0x7F || ch == 0x08 || ch == CTRL('W')) {
// this->prev(); if (this->active) {
// } else if (ch == 0x7F || ch == 0x08 || ch == CTRL('W')) { if (this->complete) {
// if (this->active) { if (editor->cursor <= this->hook)
// if (this->complete) { this->active = false;
// if (editor->cursor <= this->hook) else
// this->active = false; completion_filter(editor);
// else } else {
// completion_filter(editor); if (editor->cursor <= this->hook)
// } else { this->active = false;
// if (editor->cursor <= this->hook) else
// this->active = false; completion_request(editor);
// else }
// completion_request(editor); }
// } } else {
// } this->active = false;
// } else { }
// this->active = false; } else if (event.key_type == KEY_MOUSE && event.mouse_modifier == 0) {
// } Prolly add mouse support here
// } else if (event.key_type == KEY_MOUSE && event.mouse_modifier == 0) { auto &box = this->box;
// // Prolly add mouse support here if (event.mouse_y >= box.position.row &&
// // auto &box = this->box; event.mouse_x >= box.position.col) {
// // if (event.mouse_y >= box.position.row && uint32_t row = event.mouse_y - box.position.row;
// // event.mouse_x >= box.position.col) { uint32_t col = event.mouse_x - box.position.col;
// // uint32_t row = event.mouse_y - box.position.row; if (row < box.size.row && col < box.size.col) {
// // uint32_t col = event.mouse_x - box.position.col; uint8_t idx = 0;
// // if (row < box.size.row && col < box.size.col) { complete_select(editor, idx);
// // 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
// // if it is being implemented then stop main event handler from this->active = false;
// processing } else {
// // when click inside the box this->active = false;
// this->active = false; }
// } else { }
// this->active = false;
// } void CompletionSession::resolve_doc() {
// } auto &item = this->items[this->select];
// if (item.documentation)
// void CompletionSession::resolve_doc() { return;
// auto &item = this->items[this->select]; item.documentation = "";
// if (item.documentation) LSPPending *pending = new LSPPending();
// return; pending->editor = editor;
// item.documentation = ""; pending->callback = [](Editor *editor, const json &message) {
// LSPPending *pending = new LSPPending(); std::unique_lock lock(editor->completion.mtx);
// pending->editor = editor; auto &item = editor->completion.items[editor->completion.select];
// pending->callback = [](Editor *editor, const json &message) { if (message["result"].contains("documentation")) {
// std::unique_lock lock(editor->completion.mtx); if (message["result"]["documentation"].is_string()) {
// auto &item = editor->completion.items[editor->completion.select]; item.documentation =
// if (message["result"].contains("documentation")) { message["result"]["documentation"].get<std::string>();
// if (message["result"]["documentation"].is_string()) { } else if (message["result"]["documentation"].contains("value") &&
// item.documentation = message["result"]["documentation"]["value"].is_string()) {
// message["result"]["documentation"].get<std::string>(); item.is_markup =
// } else if (message["result"]["documentation"].contains("value") && message["result"]["documentation"]["kind"].get<std::string>() ==
// message["result"]["documentation"]["value"].is_string()) { "markdown";
// item.is_markup = std::string documentation =
// message["result"]["documentation"]["kind"].get<std::string>() == message["result"]["documentation"]["value"].get<std::string>();
// "markdown"; if (documentation.size() > 1024)
// std::string documentation = item.is_markup = false;
// message["result"]["documentation"]["value"].get<std::string>(); if (item.is_markup) {
// if (documentation.size() > 1024) item.documentation =
// item.is_markup = false; substitute_fence(documentation, editor->lang.name);
// if (item.is_markup) { } else {
// item.documentation = item.documentation = documentation;
// substitute_fence(documentation, editor->lang.name); }
// } else { }
// item.documentation = documentation; }
// } editor->completion.box.render_update();
// } };
// } json message = {{"jsonrpc", "2.0"},
// editor->completion.box.render_update(); {"method", "completionItem/resolve"},
// }; {"params", item.original}};
// json message = {{"jsonrpc", "2.0"}, lsp_send(editor->lsp, message, pending);
// {"method", "completionItem/resolve"}, }
// {"params", item.original}};
// lsp_send(editor->lsp, message, pending); void CompletionSession::accept() {
// } if (!this->active || this->box.hidden)
// return;
// void CompletionSession::accept() { auto &item = this->items[this->select];
// if (!this->active || this->box.hidden) TODO: support snippets and asis here
// return; once indentation engine is implemented
// auto &item = this->items[this->select]; if (this->version != editor->lsp_version) {
// // TODO: support snippets and asis here int delta_col = 0;
// // once indentation engine is implemented TextEdit &e = item.edits[0];
// if (this->version != editor->lsp_version) { if (e.end.row == editor->cursor.row) {
// int delta_col = 0; delta_col = editor->cursor.col - e.end.col;
// TextEdit &e = item.edits[0]; e.end.col = editor->cursor.col;
// if (e.end.row == editor->cursor.row) { for (size_t i = 1; i < item.edits.size(); ++i) {
// delta_col = editor->cursor.col - e.end.col; TextEdit &e = item.edits[i];
// e.end.col = editor->cursor.col; if (e.start.row == editor->cursor.row) {
// for (size_t i = 1; i < item.edits.size(); ++i) { e.start.col += delta_col;
// TextEdit &e = item.edits[i]; if (e.end.row == editor->cursor.row)
// if (e.start.row == editor->cursor.row) { e.end.col += delta_col;
// e.start.col += delta_col; }
// if (e.end.row == editor->cursor.row) }
// e.end.col += delta_col; }
// } }
// } editor->apply_lsp_edits(item.edits, true);
// } this->active = false;
// } }
// editor->apply_lsp_edits(item.edits, true);
// this->active = false; inline static int visible_index(const CompletionSession &s) {
// } for (size_t i = 0; i < s.visible.size(); ++i)
// if (s.visible[i] == s.select)
// inline static int visible_index(const CompletionSession &s) { return (int)i;
// for (size_t i = 0; i < s.visible.size(); ++i) return -1;
// if (s.visible[i] == s.select) }
// return (int)i;
// return -1; void CompletionSession::next() {
// } if (!this->active || this->box.hidden || this->visible.empty())
// return;
// void CompletionSession::next() { int vi = visible_index(*this);
// if (!this->active || this->box.hidden || this->visible.empty()) if (vi < 0)
// return; vi = 0;
// int vi = visible_index(*this); else
// if (vi < 0) vi = (vi + 1) % this->visible.size();
// vi = 0; this->select = this->visible[vi];
// else this->resolve_doc();
// vi = (vi + 1) % this->visible.size(); completion_adjust_scroll(*this);
// this->select = this->visible[vi]; this->box.render_update();
// this->resolve_doc(); }
// completion_adjust_scroll(*this);
// this->box.render_update(); void CompletionSession::prev() {
// } if (!this->active || this->box.hidden || this->visible.empty())
// return;
// void CompletionSession::prev() { int vi = visible_index(*this);
// if (!this->active || this->box.hidden || this->visible.empty()) if (vi < 0)
// return; vi = 0;
// int vi = visible_index(*this); else
// if (vi < 0) vi = (vi + this->visible.size() - 1) % this->visible.size();
// vi = 0; this->select = this->visible[vi];
// else this->resolve_doc();
// vi = (vi + this->visible.size() - 1) % this->visible.size(); completion_adjust_scroll(*this);
// this->select = this->visible[vi]; this->box.render_update();
// this->resolve_doc(); }
// completion_adjust_scroll(*this);
// this->box.render_update(); void CompletionSession::choose(uint8_t index) {
// } this->select = index;
// this->accept();
// void CompletionSession::choose(uint8_t index) { }
// this->select = index; */
// this->accept();
// }
Executable → Regular
View File
Executable → Regular
View File
Executable → Regular
-68
View File
@@ -1,5 +1,4 @@
#include "editor/editor.h" #include "editor/editor.h"
#include "editor/decl.h"
#include "lsp/lsp.h" #include "lsp/lsp.h"
#include "main.h" #include "main.h"
#include "syntax/langs.h" #include "syntax/langs.h"
@@ -58,7 +57,6 @@ Editor::~Editor() {
void Editor::save() { void Editor::save() {
if (!this->root) if (!this->root)
return; return;
int version = this->lsp_version;
uint32_t char_count = this->root->char_count; uint32_t char_count = this->root->char_count;
char *str = read(this->root, 0, char_count); char *str = read(this->root, 0, char_count);
if (!str) if (!str)
@@ -77,70 +75,4 @@ void Editor::save() {
free(str); free(str);
ui::bar.log("Written " + std::to_string(char_count) + " bytes to " + ui::bar.log("Written " + std::to_string(char_count) + " bytes to " +
this->filename); this->filename);
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) {
log("Formatting %s", this->filename.c_str());
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) {
log("Formattin");
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));
}
}
} }
Executable → Regular
View File
Executable → Regular
View File
Executable → Regular
+69 -8
View File
@@ -238,6 +238,73 @@ void Editor::insert_char(char c) {
} }
} }
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 Editor::normal_mode() { void Editor::normal_mode() {
Coord prev_pos = this->cursor; Coord prev_pos = this->cursor;
mode = NORMAL; mode = NORMAL;
@@ -431,19 +498,13 @@ void Editor::handle_click(KeyEvent event, Coord size) {
case SCROLL: case SCROLL:
switch (event.mouse_direction) { switch (event.mouse_direction) {
case SCROLL_UP: case SCROLL_UP:
this->scroll_up(4); this->scroll_up(1);
this->ensure_cursor(); this->ensure_cursor();
break; break;
case SCROLL_DOWN: case SCROLL_DOWN:
this->scroll_down(4); this->scroll_down(1);
this->ensure_cursor(); this->ensure_cursor();
break; break;
case SCROLL_LEFT:
this->cursor_left(10);
break;
case SCROLL_RIGHT:
this->cursor_right(10);
break;
} }
break; break;
case PRESS: case PRESS:
Executable → Regular
View File
Executable → Regular
View File
Executable → Regular
View File
Executable → Regular
+1 -1
View File
@@ -9,7 +9,7 @@ void Editor::render(std::vector<ScreenCell> &buffer, Coord size, Coord pos) {
uint32_t sel_start = 0, sel_end = 0; uint32_t sel_start = 0, sel_end = 0;
uint32_t numlen = uint32_t numlen =
EXTRA_META + static_cast<int>(std::log10(this->root->line_count + 1)); EXTRA_META + static_cast<int>(std::log10(this->root->line_count + 1));
uint32_t render_width = size.col - numlen; uint32_t render_width = size.col - numlen - 1;
uint32_t render_x = pos.col + numlen + 1; uint32_t render_x = pos.col + numlen + 1;
this->hooks.start_iter(this->scroll.row); this->hooks.start_iter(this->scroll.row);
auto warn_it = this->warnings.begin(); auto warn_it = this->warnings.begin();
Executable → Regular
View File
Executable → Regular
View File
Executable → Regular
View File
Executable → Regular
View File
Executable → Regular
+3 -2
View File
@@ -1,5 +1,4 @@
#include "extentions/diagnostics.h" #include "extentions/diagnostics.h"
#include <cstdint>
DiagnosticBox *init_diagnostic() { DiagnosticBox *init_diagnostic() {
auto diagnostic = std::make_unique<DiagnosticBox>(); auto diagnostic = std::make_unique<DiagnosticBox>();
@@ -11,6 +10,8 @@ DiagnosticBox *init_diagnostic() {
return ptr; return ptr;
} }
// TODO: Make this code more readable, It works fine tho.
void DiagnosticBox::render(std::vector<ScreenCell> &buffer, Coord n_size, void DiagnosticBox::render(std::vector<ScreenCell> &buffer, Coord n_size,
Coord n_pos) { Coord n_pos) {
pos = n_pos; pos = n_pos;
@@ -158,7 +159,7 @@ void DiagnosticBox::render(std::vector<ScreenCell> &buffer, Coord n_size,
set(r + 1, i, " ", 0x81cdc6, base_bg, 0, 1); set(r + 1, i, " ", 0x81cdc6, base_bg, 0, 1);
for (; i < see_also.length() + 5 && i < content_width; i++) { 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); set(r + 1, i, (char[2]){see_also[i - 5], 0}, fg, base_bg, 0, 1);
if (see_also[i] == ':') if (see_also[i - 5] == ':')
colon_count++; colon_count++;
if (colon_count == 2) if (colon_count == 2)
fg = 0xFFFFFF; fg = 0xFFFFFF;
Executable → Regular
View File
Executable → Regular
View File
Executable → Regular
View File
Executable → Regular
View File
Executable → Regular
View File
Executable → Regular
View File
Executable → Regular
+5 -1
View File
@@ -7,7 +7,7 @@ std::unordered_set<std::string> opened;
Queue<std::string> need_opening; Queue<std::string> need_opening;
std::vector<Editor *> new_editors; std::vector<Editor *> new_editors;
Queue<std::unique_ptr<LSPMessage>> response_queue; Queue<std::unique_ptr<LSPMessage>> response_queue;
} // namespace lsp }
void lsp_worker() { void lsp_worker() {
std::lock_guard lock(lsp::lsp_mutex); std::lock_guard lock(lsp::lsp_mutex);
@@ -22,6 +22,10 @@ void lsp_worker() {
for (auto it = lsp::new_editors.begin(); it != lsp::new_editors.end();) { for (auto it = lsp::new_editors.begin(); it != lsp::new_editors.end();) {
auto ed = *it; auto ed = *it;
auto lsp_id = ed->lang.lsp_name; auto lsp_id = ed->lang.lsp_name;
if (lsp_id.empty()) {
it = lsp::new_editors.erase(it);
continue;
}
if (lsp::opened.contains(lsp_id)) { if (lsp::opened.contains(lsp_id)) {
auto a_it = lsp::active_lsps.find(lsp_id); auto a_it = lsp::active_lsps.find(lsp_id);
if (a_it != lsp::active_lsps.end()) if (a_it != lsp::active_lsps.end())
Executable → Regular
View File
Executable → Regular
+1
View File
@@ -1,6 +1,7 @@
#include "ruby/decl.h" #include "ruby/decl.h"
mrb_value get_config_file(mrb_state *mrb, mrb_value self) { 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()); return mrb_str_new_cstr(mrb, ruby_config_path.string().c_str());
} }
Executable → Regular
View File
Executable → Regular
View File
Executable → Regular
View File
Executable → Regular
View File

Some files were not shown because too many files have changed in this diff Show More