Add lsp warnings and updates support (and other minor fixes)
This commit is contained in:
@@ -19,7 +19,7 @@ A TUI IDE.
|
||||
- `textDocument/foldingRange` - i will never use this for folding but it might be useful for other things.
|
||||
- `textDocument/rename` & `textDocument/prepareRename` - probably useful
|
||||
- And a lot more (just go through each for `clangd` and then expand to say `solargraph`).
|
||||
- Make incremental edits apply.
|
||||
- Make incremental edits apply. // make a bool field in LSP qhich says if it supports incremental and based on it apply edits
|
||||
- Make a universal plug for lsp. So focus more on making a general purpose solid communication interface. Instead of something specific.
|
||||
- With a 4ish pass system. (more like each returned value from the lsp is used in 4 ways)
|
||||
1. One for stuff like jump to x position. or rename symbol x to y. (stuff that explicitly requires user request to do something)
|
||||
|
||||
613
grammar/h.scm
Normal file
613
grammar/h.scm
Normal file
@@ -0,0 +1,613 @@
|
||||
;; #ffffff #000000 0 0 0 1
|
||||
((identifier) @variable
|
||||
(#set! priority 95))
|
||||
|
||||
(preproc_def
|
||||
(preproc_arg) @variable)
|
||||
|
||||
;; #fbb152 #000000 0 0 0 1
|
||||
[
|
||||
"default"
|
||||
"goto"
|
||||
"asm"
|
||||
"__asm__"
|
||||
] @keyword
|
||||
|
||||
[
|
||||
"enum"
|
||||
"struct"
|
||||
"union"
|
||||
"typedef"
|
||||
] @keyword.type
|
||||
|
||||
[
|
||||
"sizeof"
|
||||
"offsetof"
|
||||
] @keyword.operator
|
||||
|
||||
(alignof_expression
|
||||
.
|
||||
_ @keyword.operator)
|
||||
|
||||
;; #fbb152 #000000 0 0 0 1
|
||||
"return" @keyword.return
|
||||
|
||||
;; #fbb152 #000000 0 0 0 1
|
||||
[
|
||||
"while"
|
||||
"for"
|
||||
"do"
|
||||
"continue"
|
||||
"break"
|
||||
] @keyword.repeat
|
||||
|
||||
;; #fbb152 #000000 0 0 0 1
|
||||
[
|
||||
"if"
|
||||
"else"
|
||||
"case"
|
||||
"switch"
|
||||
] @keyword.conditional
|
||||
|
||||
;; #fbb152 #000000 0 0 0 1
|
||||
[
|
||||
"#if"
|
||||
"#ifdef"
|
||||
"#ifndef"
|
||||
"#else"
|
||||
"#elif"
|
||||
"#endif"
|
||||
"#elifdef"
|
||||
"#elifndef"
|
||||
(preproc_directive)
|
||||
] @keyword.directive
|
||||
|
||||
;; #fbb152 #000000 0 0 0 1
|
||||
"#define" @keyword.directive.define
|
||||
|
||||
;; #fbb152 #000000 0 0 0 1
|
||||
"#include" @keyword.import
|
||||
|
||||
;; #bd9ae6 #000000 0 0 0 1
|
||||
[
|
||||
";"
|
||||
":"
|
||||
","
|
||||
"."
|
||||
"::"
|
||||
] @punctuation.delimiter
|
||||
|
||||
;; #e6a24c #000000 0 0 0 2
|
||||
"..." @punctuation.special
|
||||
|
||||
;; #bd9ae6 #000000 0 0 0 1
|
||||
[
|
||||
"("
|
||||
")"
|
||||
"["
|
||||
"]"
|
||||
"{"
|
||||
"}"
|
||||
] @punctuation.bracket
|
||||
|
||||
;; #ffffff #000000 0 0 0 1
|
||||
[
|
||||
"="
|
||||
"-"
|
||||
"*"
|
||||
"/"
|
||||
"+"
|
||||
"%"
|
||||
"~"
|
||||
"|"
|
||||
"&"
|
||||
"^"
|
||||
"<<"
|
||||
">>"
|
||||
"->"
|
||||
"<"
|
||||
"<="
|
||||
">="
|
||||
">"
|
||||
"=="
|
||||
"!="
|
||||
"!"
|
||||
"&&"
|
||||
"||"
|
||||
"-="
|
||||
"+="
|
||||
"*="
|
||||
"/="
|
||||
"%="
|
||||
"|="
|
||||
"&="
|
||||
"^="
|
||||
">>="
|
||||
"<<="
|
||||
"--"
|
||||
"++"
|
||||
] @operator
|
||||
|
||||
;; #ffffff #000000 0 0 0 1
|
||||
(comma_expression
|
||||
"," @operator)
|
||||
|
||||
;; #51eeba #000000 0 0 0 1
|
||||
[
|
||||
(true)
|
||||
(false)
|
||||
] @boolean
|
||||
|
||||
;; #fbb152 #000000 0 0 0 1
|
||||
(conditional_expression
|
||||
[
|
||||
"?"
|
||||
":"
|
||||
] @keyword.conditional.ternary)
|
||||
|
||||
;; #aad84c #000000 0 0 0 1
|
||||
(string_literal) @string
|
||||
|
||||
(system_lib_string) @string
|
||||
|
||||
;; #e6a24c #000000 0 0 0 2
|
||||
(escape_sequence) @string.escape
|
||||
|
||||
;; #ebda8c #000000 0 0 0 1
|
||||
(null) @constant.builtin
|
||||
|
||||
;; #ebda8c #000000 0 0 0 1
|
||||
(number_literal) @number
|
||||
|
||||
;; #ebda8c #000000 0 0 0 1
|
||||
(char_literal) @character
|
||||
|
||||
;; #aad84c #000000 0 0 0 1
|
||||
(preproc_defined) @function.macro
|
||||
|
||||
;; #ffffff #000000 0 0 0 1
|
||||
((field_expression
|
||||
(field_identifier) @property) @_parent)
|
||||
|
||||
(field_designator) @property
|
||||
|
||||
((field_identifier) @property)
|
||||
|
||||
;; #fbb152 #000000 0 0 0 1
|
||||
(statement_identifier) @label
|
||||
|
||||
(declaration
|
||||
type: (type_identifier) @_type
|
||||
declarator: (identifier) @label
|
||||
(#match? @_type "^__label__$"))
|
||||
|
||||
;; #aad84c #000000 0 0 0 1
|
||||
[
|
||||
(type_identifier)
|
||||
(type_descriptor)
|
||||
] @type
|
||||
|
||||
;; #fbb152 #000000 0 0 0 1
|
||||
(storage_class_specifier) @keyword.modifier
|
||||
|
||||
[
|
||||
(type_qualifier)
|
||||
(gnu_asm_qualifier)
|
||||
"__extension__"
|
||||
] @keyword.modifier
|
||||
|
||||
;; #fbb152 #000000 0 0 0 1
|
||||
(linkage_specification
|
||||
"extern" @keyword.modifier)
|
||||
|
||||
;; #aad84c #000000 0 0 0 1
|
||||
(type_definition
|
||||
declarator: (type_identifier) @type.definition)
|
||||
|
||||
;; #aad84c #000000 0 0 0 1
|
||||
(primitive_type) @type.builtin
|
||||
|
||||
(sized_type_specifier
|
||||
_ @type.builtin
|
||||
type: _?)
|
||||
|
||||
;; #ebda8c #000000 0 0 0 1
|
||||
((identifier) @constant
|
||||
(#match? @constant "^[A-Z][A-Z0-9_]+$"))
|
||||
|
||||
(preproc_def
|
||||
(preproc_arg) @constant
|
||||
(#match? @constant "^[A-Z][A-Z0-9_]+$"))
|
||||
|
||||
(enumerator
|
||||
name: (identifier) @constant)
|
||||
|
||||
(case_statement
|
||||
value: (identifier) @constant)
|
||||
|
||||
;; #ebda8c #000000 0 0 0 1
|
||||
((identifier) @constant.builtin
|
||||
(#match? @constant.builtin "^(stderr|stdin|stdout|__FILE__|__LINE__|__DATE__|__TIME__|__STDC__|__STDC_VERSION__|__STDC_HOSTED__|__cplusplus|__OBJC__|__ASSEMBLER__|__BASE_FILE__|__FILE_NAME__|__INCLUDE_LEVEL__|__TIMESTAMP__|__clang__|__clang_major__|__clang_minor__|__clang_patchlevel__|__clang_version__|__clang_literal_encoding__|__clang_wide_literal_encoding__|__FUNCTION__|__func__|__PRETTY_FUNCTION__|__VA_ARGS__|__VA_OPT__)$"))
|
||||
|
||||
(preproc_def
|
||||
(preproc_arg) @constant.builtin
|
||||
(#match? @constant.builtin "^(stderr|stdin|stdout|__FILE__|__LINE__|__DATE__|__TIME__|__STDC__|__STDC_VERSION__|__STDC_HOSTED__|__cplusplus|__OBJC__|__ASSEMBLER__|__BASE_FILE__|__FILE_NAME__|__INCLUDE_LEVEL__|__TIMESTAMP__|__clang__|__clang_major__|__clang_minor__|__clang_patchlevel__|__clang_version__|__clang_literal_encoding__|__clang_wide_literal_encoding__|__FUNCTION__|__func__|__PRETTY_FUNCTION__|__VA_ARGS__|__VA_OPT__)$"))
|
||||
|
||||
;; #ffffff #000000 0 0 0 1
|
||||
(attribute_specifier
|
||||
(argument_list
|
||||
(identifier) @variable.builtin))
|
||||
|
||||
(attribute_specifier
|
||||
(argument_list
|
||||
(call_expression
|
||||
function: (identifier) @variable.builtin)))
|
||||
|
||||
;; #aad84c #000000 0 0 0 1
|
||||
((call_expression
|
||||
function: (identifier) @function.builtin)
|
||||
(#match? @function.builtin "^__builtin_"))
|
||||
|
||||
((call_expression
|
||||
function: (identifier) @function.builtin))
|
||||
|
||||
;; #ebda8c #000000 0 0 0 1
|
||||
(preproc_def
|
||||
name: (_) @constant.macro)
|
||||
|
||||
(preproc_call
|
||||
directive: (preproc_directive) @_u
|
||||
argument: (_) @constant.macro
|
||||
(#match? @_u "^#undef$"))
|
||||
|
||||
(preproc_ifdef
|
||||
name: (identifier) @constant.macro)
|
||||
|
||||
(preproc_elifdef
|
||||
name: (identifier) @constant.macro)
|
||||
|
||||
(preproc_defined
|
||||
(identifier) @constant.macro)
|
||||
|
||||
;; #aad84c #000000 0 0 0 3
|
||||
(call_expression
|
||||
function: (identifier) @function.call)
|
||||
|
||||
(call_expression
|
||||
function: (field_expression
|
||||
field: (field_identifier) @function.call))
|
||||
|
||||
;; #aad84c #000000 0 0 0 3
|
||||
(function_declarator
|
||||
declarator: (identifier) @function)
|
||||
|
||||
(function_declarator
|
||||
declarator: (parenthesized_declarator
|
||||
(pointer_declarator
|
||||
declarator: (field_identifier) @function)))
|
||||
|
||||
;; #aad84c #000000 0 0 0 3
|
||||
(preproc_function_def
|
||||
name: (identifier) @function.macro)
|
||||
|
||||
;; #AAAAAA #000000 0 1 0 1
|
||||
(comment) @comment @spell
|
||||
|
||||
;; #AAAAAA #000000 0 1 0 1
|
||||
((comment) @comment.documentation
|
||||
(#match? @comment.documentation "^/[*][*][^*].*[*]/$"))
|
||||
|
||||
;; #ffffff #000000 0 0 0 1
|
||||
(parameter_declaration
|
||||
declarator: (identifier) @variable.parameter)
|
||||
|
||||
(parameter_declaration
|
||||
declarator: (array_declarator) @variable.parameter)
|
||||
|
||||
(parameter_declaration
|
||||
declarator: (pointer_declarator) @variable.parameter)
|
||||
|
||||
(preproc_params
|
||||
(identifier) @variable.parameter)
|
||||
|
||||
;; #fbb152 #000000 0 0 0 1
|
||||
[
|
||||
"__attribute__"
|
||||
"__declspec"
|
||||
"__based"
|
||||
"__cdecl"
|
||||
"__clrcall"
|
||||
"__stdcall"
|
||||
"__fastcall"
|
||||
"__thiscall"
|
||||
"__vectorcall"
|
||||
(ms_pointer_modifier)
|
||||
(attribute_declaration)
|
||||
] @attribute
|
||||
|
||||
;; #ffffff #000000 0 0 0 1
|
||||
((identifier) @variable.member
|
||||
(#match? @variable.member "^m_.*$"))
|
||||
|
||||
(parameter_declaration
|
||||
declarator: (reference_declarator) @variable.parameter)
|
||||
|
||||
(variadic_parameter_declaration
|
||||
declarator: (variadic_declarator
|
||||
(_) @variable.parameter))
|
||||
|
||||
(optional_parameter_declaration
|
||||
declarator: (_) @variable.parameter)
|
||||
|
||||
;; #ffffff #000000 0 0 0 1
|
||||
((field_expression
|
||||
(field_identifier) @function.method) @_parent)
|
||||
|
||||
(field_declaration
|
||||
(field_identifier) @variable.member)
|
||||
|
||||
(field_initializer
|
||||
(field_identifier) @property)
|
||||
|
||||
(function_declarator
|
||||
declarator: (field_identifier) @function.method)
|
||||
|
||||
;; #aad84c #000000 0 0 0 3
|
||||
(concept_definition
|
||||
name: (identifier) @type.definition)
|
||||
|
||||
(alias_declaration
|
||||
name: (type_identifier) @type.definition)
|
||||
|
||||
;; #aad84c #000000 0 0 0 1
|
||||
(auto) @type.builtin
|
||||
|
||||
;; #aad84c #000000 0 0 0 1
|
||||
(namespace_identifier) @module
|
||||
|
||||
;; #aad84c #000000 0 0 0 1
|
||||
((namespace_identifier) @type
|
||||
(#match? @type "^[A-Z]"))
|
||||
|
||||
;; #ebda8c #000000 0 0 0 1
|
||||
(case_statement
|
||||
value: (qualified_identifier
|
||||
(identifier) @constant))
|
||||
|
||||
;; #fbb152 #000000 0 0 0 1
|
||||
(using_declaration
|
||||
.
|
||||
"using"
|
||||
.
|
||||
"namespace"
|
||||
.
|
||||
[
|
||||
(qualified_identifier)
|
||||
(identifier)
|
||||
] @module)
|
||||
|
||||
;; #aad84c #000000 0 0 0 3
|
||||
(destructor_name
|
||||
(identifier) @function.method)
|
||||
|
||||
;; #aad84c #000000 0 0 0 3
|
||||
(function_declarator
|
||||
(qualified_identifier
|
||||
(identifier) @function))
|
||||
|
||||
(function_declarator
|
||||
(qualified_identifier
|
||||
(qualified_identifier
|
||||
(identifier) @function)))
|
||||
|
||||
(function_declarator
|
||||
(qualified_identifier
|
||||
(qualified_identifier
|
||||
(qualified_identifier
|
||||
(identifier) @function))))
|
||||
|
||||
((qualified_identifier
|
||||
(qualified_identifier
|
||||
(qualified_identifier
|
||||
(qualified_identifier
|
||||
(identifier) @function)))) @_parent)
|
||||
|
||||
(function_declarator
|
||||
(template_function
|
||||
(identifier) @function))
|
||||
|
||||
(operator_name) @function
|
||||
|
||||
"operator" @function
|
||||
|
||||
;; #aad84c #000000 0 0 0 3
|
||||
"static_assert" @function.builtin
|
||||
|
||||
;; #aad84c #000000 0 0 0 3
|
||||
(call_expression
|
||||
(qualified_identifier
|
||||
(identifier) @function.call))
|
||||
|
||||
(call_expression
|
||||
(qualified_identifier
|
||||
(qualified_identifier
|
||||
(identifier) @function.call)))
|
||||
|
||||
(call_expression
|
||||
(qualified_identifier
|
||||
(qualified_identifier
|
||||
(qualified_identifier
|
||||
(identifier) @function.call))))
|
||||
|
||||
((qualified_identifier
|
||||
(qualified_identifier
|
||||
(qualified_identifier
|
||||
(qualified_identifier
|
||||
(identifier) @function.call)))) @_parent)
|
||||
|
||||
(call_expression
|
||||
(template_function
|
||||
(identifier) @function.call))
|
||||
|
||||
(call_expression
|
||||
(qualified_identifier
|
||||
(template_function
|
||||
(identifier) @function.call)))
|
||||
|
||||
(call_expression
|
||||
(qualified_identifier
|
||||
(qualified_identifier
|
||||
(template_function
|
||||
(identifier) @function.call))))
|
||||
|
||||
(call_expression
|
||||
(qualified_identifier
|
||||
(qualified_identifier
|
||||
(qualified_identifier
|
||||
(template_function
|
||||
(identifier) @function.call)))))
|
||||
|
||||
((qualified_identifier
|
||||
(qualified_identifier
|
||||
(qualified_identifier
|
||||
(qualified_identifier
|
||||
(template_function
|
||||
(identifier) @function.call))))) @_parent)
|
||||
|
||||
(function_declarator
|
||||
(template_method
|
||||
(field_identifier) @function.method))
|
||||
|
||||
;; #aad84c #000000 0 0 0 3
|
||||
(call_expression
|
||||
(field_expression
|
||||
(field_identifier) @function.method.call))
|
||||
|
||||
(call_expression
|
||||
(field_expression
|
||||
(template_method
|
||||
(field_identifier) @function.method.call)))
|
||||
|
||||
;; #aad84c #000000 0 0 0 3
|
||||
((function_declarator
|
||||
(qualified_identifier
|
||||
(identifier) @constructor))
|
||||
(#match? @constructor "^[A-Z]"))
|
||||
|
||||
((call_expression
|
||||
function: (identifier) @constructor)
|
||||
(#match? @constructor "^[A-Z]"))
|
||||
|
||||
((call_expression
|
||||
function: (qualified_identifier
|
||||
name: (identifier) @constructor))
|
||||
(#match? @constructor "^[A-Z]"))
|
||||
|
||||
((call_expression
|
||||
function: (field_expression
|
||||
field: (field_identifier) @constructor))
|
||||
(#match? @constructor "^[A-Z]"))
|
||||
|
||||
((field_initializer
|
||||
(field_identifier) @constructor
|
||||
(argument_list))
|
||||
(#match? @constructor "^[A-Z]"))
|
||||
|
||||
;; #ffffff #000000 0 0 0 1
|
||||
(this) @variable.builtin
|
||||
|
||||
;; #ebda8c #000000 0 0 0 1
|
||||
(null
|
||||
"nullptr" @constant.builtin)
|
||||
|
||||
;; #51eeba #000000 0 0 0 2
|
||||
(true) @boolean_true
|
||||
|
||||
;; #ee513a #000000 0 0 0 2
|
||||
(false) @boolean_false
|
||||
|
||||
;; #aad84c #000000 0 0 0 1
|
||||
(raw_string_literal) @string
|
||||
|
||||
;; #fbb152 #000000 0 0 0 1
|
||||
[
|
||||
"try"
|
||||
"catch"
|
||||
"noexcept"
|
||||
"throw"
|
||||
] @keyword.exception
|
||||
|
||||
;; #fbb152 #000000 0 0 0 1
|
||||
[
|
||||
"decltype"
|
||||
"explicit"
|
||||
"friend"
|
||||
"override"
|
||||
"using"
|
||||
"requires"
|
||||
"constexpr"
|
||||
] @keyword
|
||||
|
||||
;; #fbb152 #000000 0 0 0 1
|
||||
[
|
||||
"class"
|
||||
"namespace"
|
||||
"template"
|
||||
"typename"
|
||||
"concept"
|
||||
] @keyword.type
|
||||
|
||||
;; #fbb152 #000000 0 0 0 1
|
||||
[
|
||||
"co_await"
|
||||
"co_yield"
|
||||
"co_return"
|
||||
] @keyword.coroutine
|
||||
|
||||
;; #fbb152 #000000 0 0 0 1
|
||||
[
|
||||
"public"
|
||||
"private"
|
||||
"protected"
|
||||
"final"
|
||||
"virtual"
|
||||
] @keyword.modifier
|
||||
|
||||
;; #fbb152 #000000 0 0 0 1
|
||||
[
|
||||
"new"
|
||||
"delete"
|
||||
"xor"
|
||||
"bitand"
|
||||
"bitor"
|
||||
"compl"
|
||||
"not"
|
||||
"xor_eq"
|
||||
"and_eq"
|
||||
"or_eq"
|
||||
"not_eq"
|
||||
"and"
|
||||
"or"
|
||||
] @keyword.operator
|
||||
|
||||
;; #ffffff #000000 0 0 0 1
|
||||
"<=>" @operator
|
||||
|
||||
;; #bd9ae6 #000000 0 0 0 1
|
||||
"::" @punctuation.delimiter
|
||||
|
||||
;; #bd9ae6 #000000 0 0 0 1
|
||||
(template_argument_list
|
||||
[
|
||||
"<"
|
||||
">"
|
||||
] @punctuation.bracket)
|
||||
|
||||
(template_parameter_list
|
||||
[
|
||||
"<"
|
||||
">"
|
||||
] @punctuation.bracket)
|
||||
|
||||
;; #ffffff #000000 0 0 0 1
|
||||
(literal_suffix) @operator
|
||||
@@ -7,6 +7,7 @@
|
||||
#include "./utils.h"
|
||||
#include "ts_def.h"
|
||||
#include <cstdint>
|
||||
#include <shared_mutex>
|
||||
|
||||
#define CHAR 0
|
||||
#define WORD 1
|
||||
@@ -95,16 +96,14 @@ struct SpanCursor {
|
||||
|
||||
struct VHint {
|
||||
Coord pos;
|
||||
char *text; // Can only be a single line with ascii only
|
||||
uint32_t len;
|
||||
std::string hint;
|
||||
|
||||
bool operator<(const VHint &other) const { return pos < other.pos; }
|
||||
};
|
||||
|
||||
struct VWarn {
|
||||
uint32_t line;
|
||||
char *text; // Can only be a single line
|
||||
uint32_t len;
|
||||
std::string text;
|
||||
int8_t type; // For hl
|
||||
|
||||
bool operator<(const VWarn &other) const { return line < other.line; }
|
||||
@@ -158,11 +157,13 @@ struct Editor {
|
||||
Spans def_spans;
|
||||
uint32_t hooks[94];
|
||||
bool jumper_set;
|
||||
std::shared_mutex v_mtx;
|
||||
std::vector<VHint> hints;
|
||||
std::vector<VWarn> warnings;
|
||||
VAI ai;
|
||||
std::shared_mutex lsp_mtx;
|
||||
struct LSPInstance *lsp;
|
||||
int lsp_version = 1;
|
||||
};
|
||||
|
||||
inline const Fold *fold_for_line(const std::vector<Fold> &folds,
|
||||
@@ -262,6 +263,6 @@ void apply_line_deletion(Editor *editor, uint32_t removal_start,
|
||||
uint32_t leading_indent(const char *line, uint32_t len);
|
||||
uint32_t get_indent(Editor *editor, Coord cursor);
|
||||
bool closing_after_cursor(const char *line, uint32_t len, uint32_t col);
|
||||
// void editor_lsp_handle(Editor *editor, json msg);
|
||||
void editor_lsp_handle(Editor *editor, json msg);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -7,21 +7,21 @@
|
||||
#include <unordered_map>
|
||||
|
||||
static const std::unordered_map<std::string, Language> kLanguages = {
|
||||
{"bash", {"bash", tree_sitter_bash}},
|
||||
{"c", {"c", tree_sitter_c, 1}},
|
||||
{"cpp", {"cpp", tree_sitter_cpp, 1}},
|
||||
{"h", {"h", tree_sitter_cpp, 1}},
|
||||
{"css", {"css", tree_sitter_css}},
|
||||
{"fish", {"fish", tree_sitter_fish}},
|
||||
{"go", {"go", tree_sitter_go}},
|
||||
{"haskell", {"haskell", tree_sitter_haskell}},
|
||||
{"html", {"html", tree_sitter_html}},
|
||||
{"javascript", {"javascript", tree_sitter_javascript}},
|
||||
{"json", {"json", tree_sitter_json}},
|
||||
{"lua", {"lua", tree_sitter_lua}},
|
||||
{"make", {"make", tree_sitter_make}},
|
||||
{"python", {"python", tree_sitter_python}},
|
||||
{"ruby", {"ruby", tree_sitter_ruby}},
|
||||
{"bash", {"bash", LANG(bash)}},
|
||||
{"c", {"c", LANG(c), 1}},
|
||||
{"cpp", {"cpp", LANG(cpp), 1}},
|
||||
{"h", {"h", LANG(cpp), 1}},
|
||||
{"css", {"css", LANG(css)}},
|
||||
{"fish", {"fish", LANG(fish)}},
|
||||
{"go", {"go", LANG(go)}},
|
||||
{"haskell", {"haskell", LANG(haskell)}},
|
||||
{"html", {"html", LANG(html)}},
|
||||
{"javascript", {"javascript", LANG(javascript)}},
|
||||
{"json", {"json", LANG(json)}},
|
||||
{"lua", {"lua", LANG(lua)}},
|
||||
{"make", {"make", LANG(make)}},
|
||||
{"python", {"python", LANG(python)}},
|
||||
{"ruby", {"ruby", LANG(ruby)}},
|
||||
};
|
||||
|
||||
static const std::unordered_map<uint8_t, LSP> kLsps = {
|
||||
|
||||
@@ -3,34 +3,36 @@
|
||||
|
||||
#include "./pch.h"
|
||||
|
||||
#define LANG(name) tree_sitter_##name
|
||||
#define TS_DEF(name) extern "C" const TSLanguage *LANG(name)();
|
||||
|
||||
struct Language {
|
||||
std::string name;
|
||||
const TSLanguage *(*fn)();
|
||||
uint8_t lsp_id = 0;
|
||||
};
|
||||
|
||||
extern "C" {
|
||||
const TSLanguage *tree_sitter_bash();
|
||||
const TSLanguage *tree_sitter_c();
|
||||
const TSLanguage *tree_sitter_cpp();
|
||||
const TSLanguage *tree_sitter_css();
|
||||
const TSLanguage *tree_sitter_fish();
|
||||
const TSLanguage *tree_sitter_go();
|
||||
const TSLanguage *tree_sitter_haskell();
|
||||
const TSLanguage *tree_sitter_html();
|
||||
const TSLanguage *tree_sitter_javascript();
|
||||
const TSLanguage *tree_sitter_json();
|
||||
const TSLanguage *tree_sitter_lua();
|
||||
const TSLanguage *tree_sitter_make();
|
||||
const TSLanguage *tree_sitter_python();
|
||||
const TSLanguage *tree_sitter_ruby();
|
||||
const TSLanguage *tree_sitter_rust();
|
||||
TS_DEF(bash)
|
||||
TS_DEF(c)
|
||||
TS_DEF(cpp)
|
||||
TS_DEF(css)
|
||||
TS_DEF(fish)
|
||||
TS_DEF(go)
|
||||
TS_DEF(haskell)
|
||||
TS_DEF(html)
|
||||
TS_DEF(javascript)
|
||||
TS_DEF(json)
|
||||
TS_DEF(lua)
|
||||
TS_DEF(make)
|
||||
TS_DEF(python)
|
||||
TS_DEF(ruby)
|
||||
TS_DEF(rust)
|
||||
|
||||
// TO ADD
|
||||
// sql
|
||||
// wasm
|
||||
// conf
|
||||
// yaml, toml
|
||||
// godot
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -82,6 +82,8 @@ extern std::mutex screen_mutex;
|
||||
|
||||
Coord start_screen();
|
||||
void end_screen();
|
||||
void update(uint32_t row, uint32_t col, std::string utf8, uint32_t fg,
|
||||
uint32_t bg, uint8_t flags);
|
||||
void update(uint32_t row, uint32_t col, const char *utf8, uint32_t fg,
|
||||
uint32_t bg, uint8_t flags);
|
||||
void set_cursor(int row, int col, int type, bool show_cursor_param);
|
||||
|
||||
@@ -62,6 +62,7 @@ void log(const char *fmt, ...);
|
||||
std::string get_exe_dir();
|
||||
char *load_file(const char *path, uint32_t *out_len);
|
||||
char *detect_file_type(const char *filename);
|
||||
int utf8_byte_offset_to_utf16(const char *s, size_t byte_pos);
|
||||
Language language_for_file(const char *filename);
|
||||
void copy_to_clipboard(const char *text, size_t len);
|
||||
char *get_from_clipboard(uint32_t *out_len);
|
||||
|
||||
@@ -71,6 +71,10 @@ void render_editor(Editor *editor) {
|
||||
auto hook_it = v.begin();
|
||||
while (hook_it != v.end() && hook_it->first <= editor->scroll.row)
|
||||
++hook_it;
|
||||
auto warn_it = editor->warnings.begin();
|
||||
while (warn_it != editor->warnings.end() &&
|
||||
warn_it->line < editor->scroll.row)
|
||||
++warn_it;
|
||||
std::shared_lock knot_lock(editor->knot_mtx);
|
||||
if (editor->selection_active) {
|
||||
Coord start, end;
|
||||
@@ -131,6 +135,7 @@ void render_editor(Editor *editor) {
|
||||
uint32_t global_byte_offset = line_to_byte(editor->root, line_index, nullptr);
|
||||
span_cursor.sync(global_byte_offset);
|
||||
def_span_cursor.sync(global_byte_offset);
|
||||
std::shared_lock v_lock(editor->v_mtx);
|
||||
while (rendered_rows < editor->size.row) {
|
||||
const Fold *fold = fold_for_line(editor->folds, line_index);
|
||||
if (fold) {
|
||||
@@ -156,6 +161,8 @@ void render_editor(Editor *editor) {
|
||||
while (line_index <= skip_until) {
|
||||
if (hook_it != v.end() && hook_it->first == line_index + 1)
|
||||
hook_it++;
|
||||
while (warn_it != editor->warnings.end() && warn_it->line == line_index)
|
||||
++warn_it;
|
||||
uint32_t line_len;
|
||||
char *line = next_line(it, &line_len);
|
||||
if (!line)
|
||||
@@ -174,6 +181,11 @@ void render_editor(Editor *editor) {
|
||||
break;
|
||||
if (line_len > 0 && line[line_len - 1] == '\n')
|
||||
line_len--;
|
||||
std::vector<VWarn> line_warnings;
|
||||
while (warn_it != editor->warnings.end() && warn_it->line == line_index) {
|
||||
line_warnings.push_back(*warn_it);
|
||||
++warn_it;
|
||||
}
|
||||
uint32_t current_byte_offset = 0;
|
||||
if (rendered_rows == 0)
|
||||
current_byte_offset += editor->scroll.col;
|
||||
@@ -257,6 +269,78 @@ void render_editor(Editor *editor) {
|
||||
0x555555 | color, 0);
|
||||
col++;
|
||||
}
|
||||
if (!line_warnings.empty() && line_left == 0) {
|
||||
VWarn warn = line_warnings.front();
|
||||
update(editor->position.row + rendered_rows, render_x + col, " ", 0,
|
||||
color, 0);
|
||||
col++;
|
||||
for (size_t i = 0; i < line_warnings.size(); i++) {
|
||||
if (line_warnings[i].type < warn.type)
|
||||
warn = line_warnings[i];
|
||||
std::string err_sym = " ";
|
||||
uint32_t fg_color = 0;
|
||||
switch (line_warnings[i].type) {
|
||||
case 1:
|
||||
err_sym = "";
|
||||
fg_color = 0xFF0000;
|
||||
goto final;
|
||||
case 2:
|
||||
err_sym = "";
|
||||
fg_color = 0xFFFF00;
|
||||
goto final;
|
||||
case 3:
|
||||
err_sym = "";
|
||||
fg_color = 0xFF00FF;
|
||||
goto final;
|
||||
case 4:
|
||||
err_sym = "";
|
||||
fg_color = 0xAAAAAA;
|
||||
goto final;
|
||||
final:
|
||||
if (col < render_width) {
|
||||
update(editor->position.row + rendered_rows, render_x + col,
|
||||
err_sym, fg_color, color, 0);
|
||||
col++;
|
||||
update(editor->position.row + rendered_rows, render_x + col, " ",
|
||||
fg_color, color, 0);
|
||||
col++;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (col < render_width) {
|
||||
update(editor->position.row + rendered_rows, render_x + col, " ", 0,
|
||||
0 | color, 0);
|
||||
col++;
|
||||
}
|
||||
size_t warn_idx = 0;
|
||||
uint32_t fg_color = 0;
|
||||
switch (warn.type) {
|
||||
case 1:
|
||||
fg_color = 0xFF0000;
|
||||
break;
|
||||
case 2:
|
||||
fg_color = 0xFFFF00;
|
||||
break;
|
||||
case 3:
|
||||
fg_color = 0xFF00FF;
|
||||
break;
|
||||
case 4:
|
||||
fg_color = 0xAAAAAA;
|
||||
break;
|
||||
}
|
||||
while (col < render_width && warn_idx < warn.text.length()) {
|
||||
uint32_t cluster_len = grapheme_next_character_break_utf8(
|
||||
warn.text.c_str() + warn_idx, warn.text.length() - warn_idx);
|
||||
std::string cluster = warn.text.substr(warn_idx, cluster_len);
|
||||
int width = display_width(cluster.c_str(), cluster_len);
|
||||
if (col + width > render_width)
|
||||
break;
|
||||
update(editor->position.row + rendered_rows, render_x + col,
|
||||
cluster.c_str(), fg_color, color, 0);
|
||||
col += width;
|
||||
warn_idx += cluster_len;
|
||||
}
|
||||
}
|
||||
while (col < render_width) {
|
||||
update(editor->position.row + rendered_rows, render_x + col, " ", 0,
|
||||
0 | color, 0);
|
||||
|
||||
@@ -2,6 +2,7 @@ extern "C" {
|
||||
#include "../libs/libgrapheme/grapheme.h"
|
||||
}
|
||||
#include "../include/editor.h"
|
||||
#include "../include/lsp.h"
|
||||
#include "../include/main.h"
|
||||
#include "../include/utils.h"
|
||||
|
||||
@@ -342,6 +343,26 @@ void edit_erase(Editor *editor, Coord pos, int64_t len) {
|
||||
TSPoint old_point = {pos.row, pos.col};
|
||||
uint32_t byte_pos = line_to_byte(editor->root, pos.row, nullptr) + pos.col;
|
||||
Coord point = move_left_pure(editor, pos, -len);
|
||||
json lsp_range;
|
||||
bool do_lsp = (editor->lsp != nullptr);
|
||||
if (do_lsp) {
|
||||
LineIterator *it = begin_l_iter(editor->root, point.row);
|
||||
char *line = next_line(it, nullptr);
|
||||
int utf16_start = 0;
|
||||
if (line)
|
||||
utf16_start = utf8_byte_offset_to_utf16(line, point.col);
|
||||
free(it->buffer);
|
||||
free(it);
|
||||
it = begin_l_iter(editor->root, pos.row);
|
||||
line = next_line(it, nullptr);
|
||||
int utf16_end = 0;
|
||||
if (line)
|
||||
utf16_end = utf8_byte_offset_to_utf16(line, pos.col);
|
||||
free(it->buffer);
|
||||
free(it);
|
||||
lsp_range = {{"start", {{"line", point.row}, {"character", utf16_start}}},
|
||||
{"end", {{"line", pos.row}, {"character", utf16_end}}}};
|
||||
}
|
||||
uint32_t start = line_to_byte(editor->root, point.row, nullptr) + point.col;
|
||||
if (cursor_original > start && cursor_original <= byte_pos) {
|
||||
editor->cursor = point;
|
||||
@@ -372,6 +393,17 @@ void edit_erase(Editor *editor, Coord pos, int64_t len) {
|
||||
};
|
||||
editor->edit_queue.push(edit);
|
||||
}
|
||||
if (do_lsp) {
|
||||
json message = {
|
||||
{"jsonrpc", "2.0"},
|
||||
{"method", "textDocument/didChange"},
|
||||
{"params",
|
||||
{{"textDocument",
|
||||
{{"uri", editor->uri}, {"version", ++editor->lsp_version}}},
|
||||
{"contentChanges",
|
||||
json::array({{{"range", lsp_range}, {"text", ""}}})}}}};
|
||||
lsp_send(editor->lsp, message, nullptr);
|
||||
}
|
||||
std::unique_lock lock_3(editor->spans.mtx);
|
||||
apply_edit(editor->spans.spans, start, start - byte_pos);
|
||||
if (editor->spans.mid_parse)
|
||||
@@ -386,6 +418,26 @@ void edit_erase(Editor *editor, Coord pos, int64_t len) {
|
||||
TSPoint old_point = {pos.row, pos.col};
|
||||
uint32_t byte_pos = line_to_byte(editor->root, pos.row, nullptr) + pos.col;
|
||||
Coord point = move_right_pure(editor, pos, len);
|
||||
json lsp_range;
|
||||
bool do_lsp = (editor->lsp != nullptr);
|
||||
if (do_lsp) {
|
||||
LineIterator *it = begin_l_iter(editor->root, pos.row);
|
||||
char *line = next_line(it, nullptr);
|
||||
int utf16_start = 0;
|
||||
if (line)
|
||||
utf16_start = utf8_byte_offset_to_utf16(line, pos.col);
|
||||
free(it->buffer);
|
||||
free(it);
|
||||
it = begin_l_iter(editor->root, point.row);
|
||||
line = next_line(it, nullptr);
|
||||
int utf16_end = 0;
|
||||
if (line)
|
||||
utf16_end = utf8_byte_offset_to_utf16(line, point.col);
|
||||
free(it->buffer);
|
||||
free(it);
|
||||
lsp_range = {{"start", {{"line", pos.row}, {"character", utf16_start}}},
|
||||
{"end", {{"line", point.row}, {"character", utf16_end}}}};
|
||||
}
|
||||
uint32_t end = line_to_byte(editor->root, point.row, nullptr) + point.col;
|
||||
if (cursor_original > byte_pos && cursor_original <= end) {
|
||||
editor->cursor = pos;
|
||||
@@ -416,6 +468,17 @@ void edit_erase(Editor *editor, Coord pos, int64_t len) {
|
||||
};
|
||||
editor->edit_queue.push(edit);
|
||||
}
|
||||
if (do_lsp) {
|
||||
json message = {
|
||||
{"jsonrpc", "2.0"},
|
||||
{"method", "textDocument/didChange"},
|
||||
{"params",
|
||||
{{"textDocument",
|
||||
{{"uri", editor->uri}, {"version", ++editor->lsp_version}}},
|
||||
{"contentChanges",
|
||||
json::array({{{"range", lsp_range}, {"text", ""}}})}}}};
|
||||
lsp_send(editor->lsp, message, nullptr);
|
||||
}
|
||||
std::unique_lock lock_3(editor->spans.mtx);
|
||||
apply_edit(editor->spans.spans, byte_pos, byte_pos - end);
|
||||
if (editor->spans.mid_parse)
|
||||
@@ -466,6 +529,30 @@ void edit_insert(Editor *editor, Coord pos, char *data, uint32_t len) {
|
||||
};
|
||||
editor->edit_queue.push(edit);
|
||||
}
|
||||
if (editor->lsp) {
|
||||
lock_1.lock();
|
||||
LineIterator *it = begin_l_iter(editor->root, pos.row);
|
||||
char *line = next_line(it, nullptr);
|
||||
int utf16_col = 0;
|
||||
if (line)
|
||||
utf16_col = utf8_byte_offset_to_utf16(line, pos.col);
|
||||
free(it->buffer);
|
||||
free(it);
|
||||
lock_1.unlock();
|
||||
json message = {
|
||||
{"jsonrpc", "2.0"},
|
||||
{"method", "textDocument/didChange"},
|
||||
{"params",
|
||||
{{"textDocument",
|
||||
{{"uri", editor->uri}, {"version", ++editor->lsp_version}}},
|
||||
{"contentChanges",
|
||||
json::array(
|
||||
{{{"range",
|
||||
{{"start", {{"line", pos.row}, {"character", utf16_col}}},
|
||||
{"end", {{"line", pos.row}, {"character", utf16_col}}}}},
|
||||
{"text", std::string(data, len)}}})}}}};
|
||||
lsp_send(editor->lsp, message, nullptr);
|
||||
}
|
||||
std::unique_lock lock_3(editor->spans.mtx);
|
||||
apply_edit(editor->spans.spans, byte_pos, len);
|
||||
if (editor->spans.mid_parse)
|
||||
|
||||
@@ -351,24 +351,49 @@ void handle_editor_event(Editor *editor, KeyEvent event) {
|
||||
edit_erase(editor, editor->cursor, -(int64_t)prev_col_cluster);
|
||||
} else if (isprint((unsigned char)(event.c[0]))) {
|
||||
char c = event.c[0];
|
||||
char closing = 0;
|
||||
if (c == '{')
|
||||
closing = '}';
|
||||
else if (c == '(')
|
||||
closing = ')';
|
||||
else if (c == '[')
|
||||
closing = ']';
|
||||
else if (c == '"')
|
||||
closing = '"';
|
||||
else if (c == '\'')
|
||||
closing = '\'';
|
||||
if (closing) {
|
||||
char pair[2] = {c, closing};
|
||||
edit_insert(editor, editor->cursor, pair, 2);
|
||||
cursor_right(editor, 1);
|
||||
} else {
|
||||
edit_insert(editor, editor->cursor, event.c, 1);
|
||||
cursor_right(editor, 1);
|
||||
uint32_t col = editor->cursor.col;
|
||||
LineIterator *it = begin_l_iter(editor->root, editor->cursor.row);
|
||||
uint32_t len;
|
||||
char *line = next_line(it, &len);
|
||||
bool skip_insert = false;
|
||||
if (line && col < len) {
|
||||
char next = line[col];
|
||||
if ((c == '}' && next == '}') || (c == ')' && next == ')') ||
|
||||
(c == ']' && next == ']') || (c == '"' && next == '"') ||
|
||||
(c == '\'' && next == '\'')) {
|
||||
cursor_right(editor, 1);
|
||||
skip_insert = true;
|
||||
}
|
||||
}
|
||||
free(it->buffer);
|
||||
free(it);
|
||||
if (!skip_insert) {
|
||||
char closing = 0;
|
||||
switch (c) {
|
||||
case '{':
|
||||
closing = '}';
|
||||
break;
|
||||
case '(':
|
||||
closing = ')';
|
||||
break;
|
||||
case '[':
|
||||
closing = ']';
|
||||
break;
|
||||
case '"':
|
||||
closing = '"';
|
||||
break;
|
||||
case '\'':
|
||||
closing = '\'';
|
||||
break;
|
||||
}
|
||||
if (closing) {
|
||||
char pair[2] = {c, closing};
|
||||
edit_insert(editor, editor->cursor, pair, 2);
|
||||
cursor_right(editor, 1);
|
||||
} else {
|
||||
edit_insert(editor, editor->cursor, &c, 1);
|
||||
cursor_right(editor, 1);
|
||||
}
|
||||
}
|
||||
} else if (event.c[0] == 0x7F || event.c[0] == 0x08) {
|
||||
Coord prev_pos = editor->cursor;
|
||||
@@ -571,3 +596,23 @@ void editor_worker(Editor *editor) {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
void editor_lsp_handle(Editor *editor, json msg) {
|
||||
if (msg.contains("method") &&
|
||||
msg["method"] == "textDocument/publishDiagnostics") {
|
||||
std::unique_lock lock(editor->v_mtx);
|
||||
editor->warnings.clear();
|
||||
json diagnostics = msg["params"]["diagnostics"];
|
||||
for (size_t i = 0; i < diagnostics.size(); i++) {
|
||||
json d = diagnostics[i];
|
||||
VWarn w;
|
||||
w.line = d["range"]["start"]["line"];
|
||||
std::string text = d["message"].get<std::string>();
|
||||
auto pos = text.find('\n');
|
||||
w.text = (pos == std::string::npos) ? text : text.substr(0, pos);
|
||||
w.type = d["severity"].get<int>();
|
||||
editor->warnings.push_back(w);
|
||||
}
|
||||
std::sort(editor->warnings.begin(), editor->warnings.end());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ uint32_t get_indent(Editor *editor, Coord cursor) {
|
||||
if (!editor)
|
||||
return 0;
|
||||
LineIterator *it = begin_l_iter(editor->root, cursor.row);
|
||||
next_line(it, nullptr);
|
||||
uint32_t line_len;
|
||||
char *line;
|
||||
while ((line = prev_line(it, &line_len)) != nullptr) {
|
||||
|
||||
@@ -13,7 +13,6 @@ std::unordered_map<uint8_t, LSPInstance *> active_lsps;
|
||||
Queue<LSPOpenRequest> lsp_open_queue;
|
||||
|
||||
static bool init_lsp(LSPInstance *lsp) {
|
||||
log("starting %s\n", lsp->lsp->command);
|
||||
int in_pipe[2];
|
||||
int out_pipe[2];
|
||||
if (pipe(in_pipe) == -1 || pipe(out_pipe) == -1) {
|
||||
@@ -240,8 +239,7 @@ void lsp_worker() {
|
||||
Editor *ed = editor_for_uri(lsp, uri);
|
||||
lock.unlock();
|
||||
if (ed)
|
||||
// editor_lsp_handle(ed, *msg)
|
||||
;
|
||||
editor_lsp_handle(ed, *msg);
|
||||
else
|
||||
lsp_handle(lsp, *msg);
|
||||
lock.lock();
|
||||
|
||||
@@ -48,14 +48,24 @@ void end_screen() { disable_raw_mode(); }
|
||||
|
||||
Coord get_size() { return {rows, cols}; }
|
||||
|
||||
void update(uint32_t row, uint32_t col, std::string utf8, uint32_t fg,
|
||||
uint32_t bg, uint8_t flags) {
|
||||
if (row >= rows || col >= cols)
|
||||
return;
|
||||
uint32_t idx = row * cols + col;
|
||||
std::lock_guard<std::mutex> lock(screen_mutex);
|
||||
screen[idx].utf8 = utf8 != "" ? utf8 : "";
|
||||
screen[idx].fg = fg;
|
||||
screen[idx].bg = bg;
|
||||
screen[idx].flags = flags;
|
||||
}
|
||||
|
||||
void update(uint32_t row, uint32_t col, const char *utf8, uint32_t fg,
|
||||
uint32_t bg, uint8_t flags) {
|
||||
if (row >= rows || col >= cols)
|
||||
return;
|
||||
|
||||
uint32_t idx = row * cols + col;
|
||||
std::lock_guard<std::mutex> lock(screen_mutex);
|
||||
|
||||
screen[idx].utf8 = utf8 ? utf8 : "";
|
||||
screen[idx].fg = fg;
|
||||
screen[idx].bg = bg;
|
||||
|
||||
@@ -304,6 +304,7 @@ void ts_collect_spans(Editor *editor) {
|
||||
while (editor->spans.edits.pop(span_edit))
|
||||
apply_edit(new_spans, span_edit.first, span_edit.second);
|
||||
TSTree *inj_tree = ts_parser_parse(inj.parser, nullptr, tsinput);
|
||||
knot_mtx.unlock();
|
||||
TSQueryCursor *inj_cursor = ts_query_cursor_new();
|
||||
ts_query_cursor_exec(inj_cursor, inj.query, ts_tree_root_node(inj_tree));
|
||||
TSQueryMatch inj_match;
|
||||
|
||||
22
src/utils.cc
22
src/utils.cc
@@ -242,6 +242,28 @@ char *detect_file_type(const char *filename) {
|
||||
return result;
|
||||
}
|
||||
|
||||
int utf8_byte_offset_to_utf16(const char *s, size_t byte_pos) {
|
||||
int utf16_units = 0;
|
||||
size_t i = 0;
|
||||
while (i < byte_pos) {
|
||||
unsigned char c = s[i];
|
||||
if ((c & 0x80) == 0x00) {
|
||||
i += 1;
|
||||
utf16_units += 1;
|
||||
} else if ((c & 0xE0) == 0xC0) {
|
||||
i += 2;
|
||||
utf16_units += 1;
|
||||
} else if ((c & 0xF0) == 0xE0) {
|
||||
i += 3;
|
||||
utf16_units += 1;
|
||||
} else {
|
||||
i += 4;
|
||||
utf16_units += 2;
|
||||
}
|
||||
}
|
||||
return utf16_units;
|
||||
}
|
||||
|
||||
Language language_for_file(const char *filename) {
|
||||
std::string ext = file_extension(filename);
|
||||
std::string lang_name;
|
||||
|
||||
Reference in New Issue
Block a user