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 \
-g -fno-omit-frame-pointer \
-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
@@ -33,7 +33,7 @@ CFLAGS_RELEASE :=\
-fomit-frame-pointer -DNDEBUG -s \
-mllvm -vectorize-loops \
-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_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
- 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 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
- 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)
- 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
@@ -37,8 +46,8 @@ Copyright 2025 Syed Daanish
* 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
- 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)
@@ -59,10 +68,10 @@ Copyright 2025 Syed Daanish
* 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.
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
@@ -70,12 +79,12 @@ Copyright 2025 Syed Daanish
* [ ] **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.
* [ ] **Editor Indentation Fix:** - Main : merger indentation with the parser for more accurate results.
* [ ] 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.
- [ ] 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:**
* [ ] Finish autocomplete box style functions.
- [ ] Finish autocomplete box style functions.
* [ ] **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)
@@ -88,17 +97,17 @@ Copyright 2025 Syed Daanish
* allow flushing functions in ruby to tell c++ to refresh keybinds/themes etc.
* [ ] **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
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
* Allow ruby to config lsp capabilities
@@ -122,49 +131,45 @@ Copyright 2025 Syed Daanish
### UX
* [ ] **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.
- [ ] **Basic Autocomplete:** Keep a list of words in the current buffer for non-LSP fallback.
### 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.
- [ ] **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.
- [ ] **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`.
- [ ] **Block Selection:**
- [ ] Double-clicking a bracket selects the whole block and sets mode to `WORD`.
### 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).
* [ ] **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.
- [ ] **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.
### 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.
- [ ] **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.
<!-- The pits of hell: -->
<!-- * 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 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 -->
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
#define EDITOR_H
#include "editor/decl.h"
#include "editor/hooks.h"
#include "editor/indents.h"
#include "editor/visual.h"
@@ -101,6 +102,10 @@ struct Editor : Window {
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);
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
#define EDITOR_COMPLETIONS_H
#ifndef EXTENTION_COMPLETION_H
#define EXTENTION_COMPLETION_H
#include "editor/decl.h"
#include "io/sysio.h"
#include "pch.h"
#include "ui/completionbox.h"
#include "ui/hover.h"
#include "utils/utils.h"
#include "windows/decl.h"
struct CompletionItem {
std::string label;
@@ -22,12 +23,19 @@ struct CompletionItem {
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;
std::optional<std::string> prefix;
uint32_t select = 0;
uint32_t scroll = 0;
std::vector<CompletionItem> items;
@@ -35,14 +43,12 @@ struct CompletionSession {
bool complete = true;
std::optional<char> trigger_char;
uint8_t trigger = 0;
CompletionBox box;
HoverBox hover;
CompletionBox *box = nullptr;
uint32_t doc = UINT32_MAX;
std::atomic<bool> hover_dirty = false;
int version;
CompletionSession(Editor *editor) : editor(editor), box(this) {}
CompletionSession(Editor *editor) : editor(editor) {}
void resolve_doc();
void accept();
void next();
@@ -51,4 +57,8 @@ struct CompletionSession {
void handle(KeyEvent event);
};
CompletionBox *init_completion_box(CompletionSession *session);
void completion_request(Editor *editor);
void completion_filter(Editor *editor);
#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++;
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;
}
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 "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) {
// Coord hook = editor->completion.hook;
// Coord cur = editor->cursor;
// if (hook.row != cur.row || cur.col < hook.col)
// return "";
// LineIterator *it = begin_l_iter(editor->root, hook.row);
// uint32_t line_len;
// char *line = next_line(it, &line_len);
// if (!line) {
// free(it->buffer);
// free(it);
// return "";
// }
// std::string prefix(line + hook.col, cur.col - hook.col);
// free(it->buffer);
// free(it);
// 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);
// session.visible.clear();
// for (size_t i = 0; i < session.items.size(); ++i) {
// const auto &item = session.items[i];
// const std::string &key = item.filter;
// if (key.size() >= prefix.size() &&
// key.compare(0, prefix.size(), prefix) == 0)
// session.visible.push_back(i);
// }
// if (session.visible.empty()) {
// session.box.hidden = true;
// return;
// }
// if (std::find(session.visible.begin(), session.visible.end(),
// 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;
// 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->callback = [](Editor *editor, const json &message) {
// auto &session = editor->completion;
// std::unique_lock lock(session.mtx);
// std::vector<json> items_json;
// std::vector<char> end_chars_def;
// int insert_text_format = 1;
// int insert_text_mode = 1;
// if (message.contains("result")) {
// auto &result = message["result"];
// if (result.is_array()) {
// items_json = result.get<std::vector<json>>();
// session.complete = true;
// if (items_json.empty())
// return;
// editor->completion.active = true;
// } else if (result.is_object() && result.contains("items")) {
// auto &list = result;
// items_json = list["items"].get<std::vector<json>>();
// if (items_json.empty())
// return;
// editor->completion.active = true;
// session.complete = !list.value("isIncomplete", false);
// if (list.contains("itemDefaults") &&
// list["itemDefaults"].is_object()) {
// auto &defs = list["itemDefaults"];
// if (defs.contains("insertTextFormat") &&
// defs["insertTextFormat"].is_number())
// insert_text_format = defs["insertTextFormat"].get<int>();
// if (defs.contains("insertTextMode") &&
// defs["insertTextMode"].is_number())
// insert_text_mode = defs["insertTextMode"].get<int>();
// if (defs.contains("textEdit"))
// if (defs["textEdit"].is_array())
// for (auto &c : defs["textEdit"]) {
// if (!c.is_string())
// continue;
// std::string str = c.get<std::string>();
// if (str.size() != 1)
// continue;
// end_chars_def.push_back(str[0]);
// }
// }
// }
// }
// session.items.reserve(items_json.size() + 1);
// session.visible.reserve(items_json.size() + 1);
// for (auto &item_json : items_json) {
// CompletionItem item;
// item.original = item_json;
// item.label = item_json.value("label", "");
// item.kind = item_json.value("kind", 0);
// if (item_json.contains("detail") && item_json["detail"].is_string())
// item.detail = item_json["detail"].get<std::string>();
// if (item_json.contains("documentation")) {
// if (item_json["documentation"].is_string()) {
// item.documentation = item_json["documentation"].get<std::string>();
// } else if (item_json["documentation"].contains("value") &&
// item_json["documentation"]["value"].is_string()) {
// item.is_markup =
// item_json["documentation"]["kind"].get<std::string>() ==
// "markdown";
// std::string documentation =
// item_json["documentation"]["value"].get<std::string>();
// if (documentation.size() > 1024)
// item.is_markup = false;
// if (item.is_markup) {
// item.documentation =
// substitute_fence(documentation, editor->lang.name);
// } else {
// item.documentation = documentation;
// }
// }
// }
// if (item_json.contains("deprecated") &&
// item_json["deprecated"].is_boolean())
// item.deprecated = item_json["deprecated"].get<bool>();
// auto tags = item_json.value("tags", std::vector<int>());
// for (auto tag : tags)
// if (tag == 1)
// item.deprecated = true;
// item.sort = item_json.value("sortText", item.label);
// item.filter = item_json.value("filterText", item.label);
// if (item_json.contains("preselect") &&
// item_json["preselect"].is_boolean() &&
// item_json["preselect"].get<bool>())
// session.select = session.items.size() - 1;
// TextEdit edit;
// if (item_json.contains("textEdit")) {
// auto &te = item_json["textEdit"];
// if (te.contains("newText")) {
// edit.text = te.value("newText", "");
// if (te.contains("replace")) {
// edit.start.row = te["replace"]["start"]["line"];
// edit.start.col = te["replace"]["start"]["character"];
// edit.end.row = te["replace"]["end"]["line"];
// edit.end.col = te["replace"]["end"]["character"];
// } else if (te.contains("insert")) {
// edit.start.row = te["insert"]["start"]["line"];
// edit.start.col = te["insert"]["start"]["character"];
// edit.end.row = te["insert"]["end"]["line"];
// edit.end.col = te["insert"]["end"]["character"];
// } else if (te.contains("range")) {
// edit.start.row = te["range"]["start"]["line"];
// edit.start.col = te["range"]["start"]["character"];
// edit.end.row = te["range"]["end"]["line"];
// edit.end.col = te["range"]["end"]["character"];
// } else {
// edit.start = session.hook;
// edit.end = editor->cursor;
// }
// }
// } else if (item_json.contains("insertText") &&
// item_json["insertText"].is_string()) {
// edit.text = item_json["insertText"].get<std::string>();
// edit.start = session.hook;
// edit.end = editor->cursor;
// } else {
// edit.text = item.label;
// edit.start = session.hook;
// edit.end = editor->cursor;
// }
// editor->utf8_normalize_edit(&edit);
// item.edits.push_back(edit);
// if (item_json.contains("additionalTextEdits")) {
// for (auto &te : item_json["additionalTextEdits"]) {
// TextEdit edit;
// edit.text = te.value("newText", "");
// edit.start.row = te["range"]["start"]["line"];
// edit.start.col = te["range"]["start"]["character"];
// edit.end.row = te["range"]["end"]["line"];
// edit.end.col = te["range"]["end"]["character"];
// editor->utf8_normalize_edit(&edit);
// item.edits.push_back(edit);
// }
// }
// item.snippet = insert_text_format == 2;
// if (item_json.contains("insertTextFormat"))
// item.snippet = item_json["insertTextFormat"].get<int>() == 2;
// if (item_json.contains("insertTextMode"))
// item.asis = item_json["insertTextMode"].get<int>() == 1;
// if (item_json.contains("commitCharacters"))
// for (auto &c : item_json["commitCharacters"])
// if (c.is_string() && c.get<std::string>().size() == 1)
// item.end_chars.push_back(c.get<std::string>()[0]);
// session.items.push_back(std::move(item));
// session.visible.push_back(session.items.size() - 1);
// }
// session.box.hidden = false;
// session.box.render_update();
// };
// LineIterator *it = begin_l_iter(editor->root, hook.row);
// uint32_t length;
// char *line = next_line(it, &length);
// if (!line) {
// free(it->buffer);
// free(it);
// return;
// }
// uint32_t col = utf8_offset_to_utf16(line, length, editor->cursor.col);
// free(it->buffer);
// free(it);
// json message = {
// {"jsonrpc", "2.0"},
// {"method", "textDocument/completion"},
// {"params",
// {{"textDocument", {{"uri", editor->uri}}},
// {"position", {{"line", editor->cursor.row}, {"character", col}}}}}};
// if (editor->completion.trigger > 0) {
// json context = {{"triggerKind", editor->completion.trigger}};
// if (editor->completion.trigger == 2 && editor->completion.trigger_char)
// context["triggerCharacter"] =
// std::string(1, *editor->completion.trigger_char);
// message["params"]["context"] = context;
// }
// lsp_send(editor->lsp, message, pending);
// }
//
// // 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) {
// this->active = false;
// return;
// }
// std::unique_lock lock(this->mtx);
// if (event.key_type == KEY_PASTE) {
// this->active = false;
// return;
// } else if (event.key_type == KEY_CHAR) {
// char ch = *event.c;
// if (!this->active) {
// for (char c : editor->lsp->trigger_chars)
// if (c == ch) {
// 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 =
// item.end_chars.empty() ? editor->lsp->end_chars : item.end_chars;
// for (char c : end_chars)
// if (c == ch) {
// this->accept();
// return;
// }
// }
// }
// if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') ||
// (ch >= '0' && ch <= '9') || ch == '_') {
// if (this->active) {
// if (this->complete)
// completion_filter(editor);
// else
// completion_request(editor);
// } else {
// this->trigger = 3;
// completion_request(editor);
// }
// } else if (ch == CTRL('\\')) {
// if (this->active && !this->visible.empty()) {
// this->accept();
// } else {
// this->trigger = 1;
// completion_request(editor);
// }
// } else if (ch == CTRL('p')) {
// if (this->active)
// this->next();
// } else if (ch == CTRL('o')) {
// if (this->active)
// this->prev();
// } else if (ch == 0x7F || ch == 0x08 || ch == CTRL('W')) {
// if (this->active) {
// if (this->complete) {
// if (editor->cursor <= this->hook)
// this->active = false;
// else
// completion_filter(editor);
// } else {
// if (editor->cursor <= this->hook)
// this->active = false;
// else
// completion_request(editor);
// }
// }
// } else {
// this->active = false;
// }
// } else if (event.key_type == KEY_MOUSE && event.mouse_modifier == 0) {
// // 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;
// // /* 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
// this->active = false;
// } else {
// this->active = false;
// }
// }
//
// void CompletionSession::resolve_doc() {
// auto &item = this->items[this->select];
// if (item.documentation)
// return;
// item.documentation = "";
// LSPPending *pending = new LSPPending();
// pending->editor = editor;
// 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")) {
// if (message["result"]["documentation"].is_string()) {
// item.documentation =
// message["result"]["documentation"].get<std::string>();
// } else if (message["result"]["documentation"].contains("value") &&
// message["result"]["documentation"]["value"].is_string()) {
// item.is_markup =
// message["result"]["documentation"]["kind"].get<std::string>() ==
// "markdown";
// std::string documentation =
// message["result"]["documentation"]["value"].get<std::string>();
// if (documentation.size() > 1024)
// item.is_markup = false;
// if (item.is_markup) {
// item.documentation =
// substitute_fence(documentation, editor->lang.name);
// } else {
// item.documentation = documentation;
// }
// }
// }
// editor->completion.box.render_update();
// };
// json message = {{"jsonrpc", "2.0"},
// {"method", "completionItem/resolve"},
// {"params", item.original}};
// lsp_send(editor->lsp, message, pending);
// }
//
// void CompletionSession::accept() {
// if (!this->active || this->box.hidden)
// return;
// 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) {
// delta_col = editor->cursor.col - e.end.col;
// e.end.col = editor->cursor.col;
// for (size_t i = 1; i < item.edits.size(); ++i) {
// TextEdit &e = item.edits[i];
// if (e.start.row == editor->cursor.row) {
// 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;
// }
//
// inline static int visible_index(const CompletionSession &s) {
// for (size_t i = 0; i < s.visible.size(); ++i)
// if (s.visible[i] == s.select)
// return (int)i;
// return -1;
// }
//
// void CompletionSession::next() {
// if (!this->active || this->box.hidden || this->visible.empty())
// return;
// int vi = visible_index(*this);
// if (vi < 0)
// vi = 0;
// else
// vi = (vi + 1) % this->visible.size();
// this->select = this->visible[vi];
// this->resolve_doc();
// completion_adjust_scroll(*this);
// this->box.render_update();
// }
//
// void CompletionSession::prev() {
// if (!this->active || this->box.hidden || this->visible.empty())
// return;
// int vi = visible_index(*this);
// if (vi < 0)
// vi = 0;
// else
// 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 CompletionSession::choose(uint8_t index) {
// this->select = index;
// this->accept();
// }
/* #include "editor/editor.h"
#include "io/knot.h"
#include "io/sysio.h"
#include "main.h"
#include "ui/completionbox.h"
#include "utils/utils.h"
inline static std::string completion_prefix(Editor *editor) {
Coord hook = editor->completion.hook;
Coord cur = editor->cursor;
if (hook.row != cur.row || cur.col < hook.col)
return "";
LineIterator *it = begin_l_iter(editor->root, hook.row);
uint32_t line_len;
char *line = next_line(it, &line_len);
if (!line) {
free(it->buffer);
free(it);
return "";
}
std::string prefix(line + hook.col, cur.col - hook.col);
free(it->buffer);
free(it);
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);
session.visible.clear();
for (size_t i = 0; i < session.items.size(); ++i) {
const auto &item = session.items[i];
const std::string &key = item.filter;
if (key.size() >= prefix.size() &&
key.compare(0, prefix.size(), prefix) == 0)
session.visible.push_back(i);
}
if (session.visible.empty()) {
session.box.hidden = true;
return;
}
if (std::find(session.visible.begin(), session.visible.end(),
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;
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->callback = [](Editor *editor, const json &message) {
auto &session = editor->completion;
std::unique_lock lock(session.mtx);
std::vector<json> items_json;
std::vector<char> end_chars_def;
int insert_text_format = 1;
int insert_text_mode = 1;
if (message.contains("result")) {
auto &result = message["result"];
if (result.is_array()) {
items_json = result.get<std::vector<json>>();
session.complete = true;
if (items_json.empty())
return;
editor->completion.active = true;
} else if (result.is_object() && result.contains("items")) {
auto &list = result;
items_json = list["items"].get<std::vector<json>>();
if (items_json.empty())
return;
editor->completion.active = true;
session.complete = !list.value("isIncomplete", false);
if (list.contains("itemDefaults") &&
list["itemDefaults"].is_object()) {
auto &defs = list["itemDefaults"];
if (defs.contains("insertTextFormat") &&
defs["insertTextFormat"].is_number())
insert_text_format = defs["insertTextFormat"].get<int>();
if (defs.contains("insertTextMode") &&
defs["insertTextMode"].is_number())
insert_text_mode = defs["insertTextMode"].get<int>();
if (defs.contains("textEdit"))
if (defs["textEdit"].is_array())
for (auto &c : defs["textEdit"]) {
if (!c.is_string())
continue;
std::string str = c.get<std::string>();
if (str.size() != 1)
continue;
end_chars_def.push_back(str[0]);
}
}
}
}
session.items.reserve(items_json.size() + 1);
session.visible.reserve(items_json.size() + 1);
for (auto &item_json : items_json) {
CompletionItem item;
item.original = item_json;
item.label = item_json.value("label", "");
item.kind = item_json.value("kind", 0);
if (item_json.contains("detail") && item_json["detail"].is_string())
item.detail = item_json["detail"].get<std::string>();
if (item_json.contains("documentation")) {
if (item_json["documentation"].is_string()) {
item.documentation = item_json["documentation"].get<std::string>();
} else if (item_json["documentation"].contains("value") &&
item_json["documentation"]["value"].is_string()) {
item.is_markup =
item_json["documentation"]["kind"].get<std::string>() ==
"markdown";
std::string documentation =
item_json["documentation"]["value"].get<std::string>();
if (documentation.size() > 1024)
item.is_markup = false;
if (item.is_markup) {
item.documentation =
substitute_fence(documentation, editor->lang.name);
} else {
item.documentation = documentation;
}
}
}
if (item_json.contains("deprecated") &&
item_json["deprecated"].is_boolean())
item.deprecated = item_json["deprecated"].get<bool>();
auto tags = item_json.value("tags", std::vector<int>());
for (auto tag : tags)
if (tag == 1)
item.deprecated = true;
item.sort = item_json.value("sortText", item.label);
item.filter = item_json.value("filterText", item.label);
if (item_json.contains("preselect") &&
item_json["preselect"].is_boolean() &&
item_json["preselect"].get<bool>())
session.select = session.items.size() - 1;
TextEdit edit;
if (item_json.contains("textEdit")) {
auto &te = item_json["textEdit"];
if (te.contains("newText")) {
edit.text = te.value("newText", "");
if (te.contains("replace")) {
edit.start.row = te["replace"]["start"]["line"];
edit.start.col = te["replace"]["start"]["character"];
edit.end.row = te["replace"]["end"]["line"];
edit.end.col = te["replace"]["end"]["character"];
} else if (te.contains("insert")) {
edit.start.row = te["insert"]["start"]["line"];
edit.start.col = te["insert"]["start"]["character"];
edit.end.row = te["insert"]["end"]["line"];
edit.end.col = te["insert"]["end"]["character"];
} else if (te.contains("range")) {
edit.start.row = te["range"]["start"]["line"];
edit.start.col = te["range"]["start"]["character"];
edit.end.row = te["range"]["end"]["line"];
edit.end.col = te["range"]["end"]["character"];
} else {
edit.start = session.hook;
edit.end = editor->cursor;
}
}
} else if (item_json.contains("insertText") &&
item_json["insertText"].is_string()) {
edit.text = item_json["insertText"].get<std::string>();
edit.start = session.hook;
edit.end = editor->cursor;
} else {
edit.text = item.label;
edit.start = session.hook;
edit.end = editor->cursor;
}
editor->utf8_normalize_edit(&edit);
item.edits.push_back(edit);
if (item_json.contains("additionalTextEdits")) {
for (auto &te : item_json["additionalTextEdits"]) {
TextEdit edit;
edit.text = te.value("newText", "");
edit.start.row = te["range"]["start"]["line"];
edit.start.col = te["range"]["start"]["character"];
edit.end.row = te["range"]["end"]["line"];
edit.end.col = te["range"]["end"]["character"];
editor->utf8_normalize_edit(&edit);
item.edits.push_back(edit);
}
}
item.snippet = insert_text_format == 2;
if (item_json.contains("insertTextFormat"))
item.snippet = item_json["insertTextFormat"].get<int>() == 2;
if (item_json.contains("insertTextMode"))
item.asis = item_json["insertTextMode"].get<int>() == 1;
if (item_json.contains("commitCharacters"))
for (auto &c : item_json["commitCharacters"])
if (c.is_string() && c.get<std::string>().size() == 1)
item.end_chars.push_back(c.get<std::string>()[0]);
session.items.push_back(std::move(item));
session.visible.push_back(session.items.size() - 1);
}
session.box.hidden = false;
session.box.render_update();
};
LineIterator *it = begin_l_iter(editor->root, hook.row);
uint32_t length;
char *line = next_line(it, &length);
if (!line) {
free(it->buffer);
free(it);
return;
}
uint32_t col = utf8_offset_to_utf16(line, length, editor->cursor.col);
free(it->buffer);
free(it);
json message = {
{"jsonrpc", "2.0"},
{"method", "textDocument/completion"},
{"params",
{{"textDocument", {{"uri", editor->uri}}},
{"position", {{"line", editor->cursor.row}, {"character", col}}}}}};
if (editor->completion.trigger > 0) {
json context = {{"triggerKind", editor->completion.trigger}};
if (editor->completion.trigger == 2 && editor->completion.trigger_char)
context["triggerCharacter"] =
std::string(1, *editor->completion.trigger_char);
message["params"]["context"] = context;
}
lsp_send(editor->lsp, message, pending);
}
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) {
this->active = false;
return;
}
std::unique_lock lock(this->mtx);
if (event.key_type == KEY_PASTE) {
this->active = false;
return;
} else if (event.key_type == KEY_CHAR) {
char ch = *event.c;
if (!this->active) {
for (char c : editor->lsp->trigger_chars)
if (c == ch) {
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 =
item.end_chars.empty() ? editor->lsp->end_chars : item.end_chars;
for (char c : end_chars)
if (c == ch) {
this->accept();
return;
}
}
}
if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') ||
(ch >= '0' && ch <= '9') || ch == '_') {
if (this->active) {
if (this->complete)
completion_filter(editor);
else
completion_request(editor);
} else {
this->trigger = 3;
completion_request(editor);
}
} else if (ch == CTRL('\\')) {
if (this->active && !this->visible.empty()) {
this->accept();
} else {
this->trigger = 1;
completion_request(editor);
}
} else if (ch == CTRL('p')) {
if (this->active)
this->next();
} else if (ch == CTRL('o')) {
if (this->active)
this->prev();
} else if (ch == 0x7F || ch == 0x08 || ch == CTRL('W')) {
if (this->active) {
if (this->complete) {
if (editor->cursor <= this->hook)
this->active = false;
else
completion_filter(editor);
} else {
if (editor->cursor <= this->hook)
this->active = false;
else
completion_request(editor);
}
}
} else {
this->active = false;
}
} else if (event.key_type == KEY_MOUSE && event.mouse_modifier == 0) {
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 {
this->active = false;
}
}
void CompletionSession::resolve_doc() {
auto &item = this->items[this->select];
if (item.documentation)
return;
item.documentation = "";
LSPPending *pending = new LSPPending();
pending->editor = editor;
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")) {
if (message["result"]["documentation"].is_string()) {
item.documentation =
message["result"]["documentation"].get<std::string>();
} else if (message["result"]["documentation"].contains("value") &&
message["result"]["documentation"]["value"].is_string()) {
item.is_markup =
message["result"]["documentation"]["kind"].get<std::string>() ==
"markdown";
std::string documentation =
message["result"]["documentation"]["value"].get<std::string>();
if (documentation.size() > 1024)
item.is_markup = false;
if (item.is_markup) {
item.documentation =
substitute_fence(documentation, editor->lang.name);
} else {
item.documentation = documentation;
}
}
}
editor->completion.box.render_update();
};
json message = {{"jsonrpc", "2.0"},
{"method", "completionItem/resolve"},
{"params", item.original}};
lsp_send(editor->lsp, message, pending);
}
void CompletionSession::accept() {
if (!this->active || this->box.hidden)
return;
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) {
delta_col = editor->cursor.col - e.end.col;
e.end.col = editor->cursor.col;
for (size_t i = 1; i < item.edits.size(); ++i) {
TextEdit &e = item.edits[i];
if (e.start.row == editor->cursor.row) {
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;
}
inline static int visible_index(const CompletionSession &s) {
for (size_t i = 0; i < s.visible.size(); ++i)
if (s.visible[i] == s.select)
return (int)i;
return -1;
}
void CompletionSession::next() {
if (!this->active || this->box.hidden || this->visible.empty())
return;
int vi = visible_index(*this);
if (vi < 0)
vi = 0;
else
vi = (vi + 1) % this->visible.size();
this->select = this->visible[vi];
this->resolve_doc();
completion_adjust_scroll(*this);
this->box.render_update();
}
void CompletionSession::prev() {
if (!this->active || this->box.hidden || this->visible.empty())
return;
int vi = visible_index(*this);
if (vi < 0)
vi = 0;
else
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 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/decl.h"
#include "lsp/lsp.h"
#include "main.h"
#include "syntax/langs.h"
@@ -58,7 +57,6 @@ Editor::~Editor() {
void Editor::save() {
if (!this->root)
return;
int version = this->lsp_version;
uint32_t char_count = this->root->char_count;
char *str = read(this->root, 0, char_count);
if (!str)
@@ -77,70 +75,4 @@ void Editor::save() {
free(str);
ui::bar.log("Written " + std::to_string(char_count) + " bytes to " +
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() {
Coord prev_pos = this->cursor;
mode = NORMAL;
@@ -431,19 +498,13 @@ void Editor::handle_click(KeyEvent event, Coord size) {
case SCROLL:
switch (event.mouse_direction) {
case SCROLL_UP:
this->scroll_up(4);
this->scroll_up(1);
this->ensure_cursor();
break;
case SCROLL_DOWN:
this->scroll_down(4);
this->scroll_down(1);
this->ensure_cursor();
break;
case SCROLL_LEFT:
this->cursor_left(10);
break;
case SCROLL_RIGHT:
this->cursor_right(10);
break;
}
break;
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 numlen =
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;
this->hooks.start_iter(this->scroll.row);
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 <cstdint>
DiagnosticBox *init_diagnostic() {
auto diagnostic = std::make_unique<DiagnosticBox>();
@@ -11,6 +10,8 @@ DiagnosticBox *init_diagnostic() {
return ptr;
}
// 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;
@@ -158,7 +159,7 @@ void DiagnosticBox::render(std::vector<ScreenCell> &buffer, Coord n_size,
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] == ':')
if (see_also[i - 5] == ':')
colon_count++;
if (colon_count == 2)
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;
std::vector<Editor *> new_editors;
Queue<std::unique_ptr<LSPMessage>> response_queue;
} // namespace lsp
}
void lsp_worker() {
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();) {
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())
Executable → Regular
View File
Executable → Regular
+1
View File
@@ -1,6 +1,7 @@
#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());
}
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