1
#include "simodo/lsp/client/LanguageClient.h"
2
#include "simodo/inout/log/Logger.h"
3
#include "simodo/inout/token/FileStream.h"
4
#include "simodo/inout/token/LexicalParameters.h"
5
#include "simodo/inout/token/Tokenizer.h"
6
#include "simodo/inout/convert/functions.h"
10
using namespace simodo;
11
using namespace simodo::inout;
13
void performOpenCommand(lsp::LanguageClient & client, std::vector<Token> command)
15
// format: o uri [grammar]
17
if (command.size() < 2) {
18
std::cout << "Wrong structure of Open command" << std::endl;
22
std::ifstream in(toU8(command[1].lexeme()));
24
std::cout << "*** Unable to open file '" << toU8(command[1].lexeme()) << "'" << std::endl;
28
InputStream in_stream(in);
29
std::u16string string_buffer;
32
char16_t ch = in_stream.get();
33
if (ch == std::char_traits<char16_t>::eof())
38
client.exec("textDocument/didOpen", variable::Object {{
39
{u"textDocument", variable::Object {{
40
{u"uri", command[1].lexeme()},
41
{u"languageId", command.size() > 2 ? command[2].lexeme() : u"simodo-script"},
43
{u"text", encodeSpecialChars(string_buffer)},
48
void performCloseCommand(lsp::LanguageClient & client, std::vector<Token> command)
52
if (command.size() != 2) {
53
std::cout << "*** Wrong structure of Close command" << std::endl;
57
client.exec("textDocument/didClose", variable::Object {{
58
{u"textDocument", variable::Object {{
59
{u"uri", command[1].lexeme()},
64
void performChangeCommand(lsp::LanguageClient & client, std::vector<Token> command)
66
// format: u uri version text
68
if (command.size() != 4) {
69
std::cout << "*** Wrong structure of Change command" << std::endl;
70
// for(const Token & t : command)
71
// std::cout << "'" << toU8(t.lexeme()) << "': " << toU8(getLexemeTypeName(t.type())) << std::endl;
75
client.exec("textDocument/didChange", variable::Object {{
76
{u"textDocument", variable::Object {{
77
{u"uri", command[1].lexeme()},
78
{u"version", int64_t(std::stol(toU8(command[2].lexeme())))},
80
{u"contentChanges", variable::Array {{
81
variable::Object {{{u"text", command[3].lexeme()}}},
86
void performHoverCommand(lsp::LanguageClient & client, std::vector<Token> command)
88
// format: h uri line character
90
if (command.size() < 4) {
91
std::cout << "*** Wrong structure of Hover command" << std::endl;
95
client.exec("textDocument/hover",
97
{u"textDocument", variable::Object {{
98
{u"uri", command[1].lexeme()},
100
{u"position", variable::Object {{
101
{u"line", int64_t(std::stol(toU8(command[2].lexeme())))},
102
{u"character", int64_t(std::stol(toU8(command[3].lexeme())))},
105
[](const variable::JsonRpc & rpc, const void *){
106
std::cout << "= textDocument/hover => " << variable::toJson(rpc.value()) << std::endl;
110
void performDefinitionCommand(lsp::LanguageClient & client, std::vector<Token> command)
112
// format: h uri line character
114
if (command.size() < 4) {
115
std::cout << "*** Wrong structure of Definition command" << std::endl;
119
client.exec("textDocument/definition",
121
{u"textDocument", variable::Object {{
122
{u"uri", command[1].lexeme()},
124
{u"position", variable::Object {{
125
{u"line", int64_t(std::stol(toU8(command[2].lexeme())))},
126
{u"character", int64_t(std::stol(toU8(command[3].lexeme())))},
129
[](const variable::JsonRpc & rpc, const void *){
130
std::cout << "= textDocument/definition => " << variable::toJson(rpc.value()) << std::endl;
134
void performDocSymbolsCommand(lsp::LanguageClient & client, std::vector<Token> command)
138
if (command.size() != 2) {
139
std::cout << "*** Wrong structure of 'documentSymbol' command" << std::endl;
143
client.exec("textDocument/documentSymbol",
145
{u"textDocument", variable::Object {{
146
{u"uri", command[1].lexeme()},
149
[](const variable::JsonRpc & rpc, const void *){
150
std::cout << "= textDocument/documentSymbol => " << variable::toJson(rpc.value()) << std::endl;
154
void performSemTokensCommand(lsp::LanguageClient & client, std::vector<Token> command)
158
if (command.size() != 2) {
159
std::cout << "*** Wrong structure of 'semanticTokens' command" << std::endl;
163
client.exec("textDocument/semanticTokens/full",
165
{u"textDocument", variable::Object {{
166
{u"uri", command[1].lexeme()},
169
[](const variable::JsonRpc & rpc, const void *){
170
std::cout << "= textDocument/semanticTokens => " << variable::toJson(rpc.value()) << std::endl;
174
void performSegmentationFaultCommand(lsp::LanguageClient & client, std::vector<Token> command)
178
if (command.size() != 2) {
179
std::cout << "*** Wrong structure of 'SegmentationFault' command" << std::endl;
183
client.exec("SegmentationFault",
185
{u"textDocument", variable::Object {{
186
{u"uri", command[1].lexeme()},
189
[](const variable::JsonRpc & rpc, const void *){
190
std::cout << "= SegmentationFault => " << variable::toJson(rpc.value()) << std::endl;
194
void performWaitCommand(lsp::LanguageClient & , std::vector<Token> command)
198
if (command.size() < 2 || command[1].type() != LexemeType::Number) {
199
std::cout << "*** Wrong structure of Wait command" << std::endl;
203
int wait_mills = std::stol(toU8(command[1].lexeme()));
204
std::this_thread::sleep_for(std::chrono::milliseconds(wait_mills));
207
int main(int argc, char * argv[])
210
std::cout << "Usage: language-client <command file> <path to language server> {<language server args...>}" << std::endl;
214
std::ifstream in(argv[1]);
217
std::cout << "*** Unable to open file '" << argv[1] << "'" << std::endl;
221
Logger log(std::cout, "LSP-client", Logger::SeverityLevel::Warning);
223
std::vector<std::string> args(argv+3,argv+argc);
225
lsp::LanguageClient client(argv[2], args, {}, log);
227
if (!client.running()) {
228
std::cout << "*** Server don't running" << std::endl;
232
client.registerListener("textDocument/publishDiagnostics",
233
[&] (variable::JsonRpc rpc, const void *) {
234
std::cout << "= textDocument/publishDiagnostics => " << variable::toJson(rpc.value()) << std::endl;
236
if (rpc.params().isObject()) {
237
const variable::Value & uri_value = rpc.params().getObject()->find(u"uri");
238
if (uri_value.isString()) {
239
const std::u16string uri = uri_value.getString();
240
const inout::Token uri_token {inout::LexemeType::Id, uri, inout::null_token_location};
242
performDocSymbolsCommand(client, {inout::null_token, uri_token});
243
performSemTokensCommand(client, {inout::null_token, uri_token});
246
std::cout << "*** uri not found" << std::endl;
249
std::cout << "*** params not found" << std::endl;
253
while(std::getline(in,line) && !line.empty()) {
254
std::vector<Token> command;
255
std::istringstream str_in(line);
256
InputStream in(str_in);
257
LexicalParameters lex;
258
lex.masks.push_back({ BUILDING_NUMBER, LexemeType::Number, 10 });
259
lex.markups.push_back({u"\"", u"\"", u"\\", LexemeType::Annotation});
261
Tokenizer tokenizer(0, in, lex);
262
Token t = tokenizer.getToken();
264
while(t.type() != LexemeType::Empty) {
265
command.push_back(t);
266
t = tokenizer.getToken();
269
if (command.empty() || command[0].type() != LexemeType::Id) {
270
std::cout << "*** Wrong command" << std::endl;
274
if (command[0].lexeme() == u"o")
275
performOpenCommand(client, command);
276
else if (command[0].lexeme() == u"c")
277
performCloseCommand(client, command);
278
else if (command[0].lexeme() == u"u")
279
performChangeCommand(client, command);
280
else if (command[0].lexeme() == u"h")
281
performHoverCommand(client, command);
282
else if (command[0].lexeme() == u"go")
283
performDefinitionCommand(client, command);
284
else if (command[0].lexeme() == u"w")
285
performWaitCommand(client, command);
286
// Запускается автоматически при получении диагностики
287
// else if (command[0].lexeme() == u"s")
288
// performDocSymbolsCommand(client, command);
289
// else if (command[0].lexeme() == u"t")
290
// performSemTokensCommand(client, command);
291
else if (command[0].lexeme() == u"sf")
292
performSegmentationFaultCommand(client, command);
294
std::cout << "*** Command don't recognized" << std::endl;
298
if (!client.running()) {
299
std::cout << "*** Server don't running" << std::endl;
304
// std::this_thread::sleep_for(std::chrono::milliseconds(1000));
305
// client.done(1000);
306
std::this_thread::sleep_for(std::chrono::milliseconds(5000));
309
std::cout << "Done" << std::endl;
313
std::cout << "Something is wrong" << std::endl;