Bash++
Bash++ compiler internal documentation
BashppServer.h
Go to the documentation of this file.
1/*
2 * Copyright (C) 2025 Andrew S. Rightenburg
3 * Bash++: Bash with classes
4 * SPDX-License-Identifier: GPL-3.0-or-later
5 */
6
7#pragma once
8
9#include <iostream>
10#include <thread>
11#include <mutex>
12#include <chrono>
13#include <atomic>
14#include <memory>
15#include <unordered_map>
16#include <fstream>
17#include <nlohmann/json.hpp>
18#include <unistd.h>
19
20#include "ThreadPool.h"
21#include "ProgramPool.h"
22
23#include "static/Message.h"
24
25#include "generated/CompletionList.h"
26#include "generated/CompletionParams.h"
27
29#include <include/BashVersion.h>
30
31namespace bpp {
32
33using json = nlohmann::json;
34
35template<typename T>
36void printValue(std::ostream& os, const T& value) {
37 os << value;
38}
39
40template<typename... Ts>
41void printValue(std::ostream& os, const std::variant<Ts...>& v) {
42 std::visit([&os](auto&& arg) { os << arg; }, v);
43}
44
45
55 public:
56 BashppServer() = default;
57 ~BashppServer() = default;
58 BashppServer(const BashppServer& other) = delete; // Non-copyable
59 BashppServer& operator=(const BashppServer& other) = delete;
60 BashppServer(BashppServer&& other) noexcept = delete; // Non-movable
61 BashppServer& operator=(BashppServer&& other) noexcept = delete;
62
63 void mainLoop();
64
65 void setLogFile(const std::string& path);
66 void setTargetBashVersion(const BashVersion& version);
67 void setThreadCount(size_t num_threads);
68
69 GenericResponseMessage shutdown(const GenericRequestMessage& request);
70 void exit(const GenericNotificationMessage& notification);
71 void cleanup();
72
73 void processMessage(const std::string& message);
74
75 // Request-Response handlers
76 GenericResponseMessage handleInitialize(const GenericRequestMessage& request);
77 GenericResponseMessage handleDefinition(const GenericRequestMessage& request);
78 GenericResponseMessage handleHover(const GenericRequestMessage& request);
79 GenericResponseMessage handleDocumentSymbol(const GenericRequestMessage& request);
80 GenericResponseMessage handleRename(const GenericRequestMessage& request);
81 GenericResponseMessage handleReferences(const GenericRequestMessage& request);
82 GenericResponseMessage handleCompletion(const GenericRequestMessage& request);
83
84 CompletionList handleATCompletion(const CompletionParams& params);
85 CompletionList handleDOTCompletion(const CompletionParams& params);
86
87 // Notification handlers
88 void handleDidOpen(const GenericNotificationMessage& request);
89 void handleDidChange(const GenericNotificationMessage& request);
90 void handleDidChangeWatchedFiles(const GenericNotificationMessage& request);
91 void handleDidClose(const GenericNotificationMessage& request);
92 void handleDidSave(const GenericNotificationMessage& request);
93
94 void sendResponse(const GenericResponseMessage& response);
95 void sendNotification(const GenericNotificationMessage& notification);
96
97 void publishDiagnostics(std::shared_ptr<bpp::bpp_program> program);
98
99 void add_include_path(const std::string& path);
100 void set_suppress_warnings(bool suppress);
101
102 template <typename... Args>
103 void log(Args&&... args) {
104 if (!log_file.is_open()) return; // Not logging
105
106 std::lock_guard<std::mutex> lock(log_mutex);
107 auto now = std::chrono::system_clock::now();
108 auto now_time_t = std::chrono::system_clock::to_time_t(now);
109 std::tm tm_buf{};
110 localtime_r(&now_time_t, &tm_buf);
111 log_file << "[" << std::put_time(&tm_buf, "%Y-%m-%d %H:%M:%S") << "] ";
112 log_file << "[" << std::to_string(pid) << "] ";
113 ((printValue(log_file, std::forward<Args>(args))), ...);
114 log_file << std::endl;
115 }
116
117 private:
118 pid_t pid = getpid();
119 std::atomic<bool> exiting = false;
120 std::atomic<bool> shutdown_requested = false;
121
122 // Resources
123 std::istream* input_stream = &std::cin; // Held as std::stream* for future extensions beyond stdio
124 std::ostream* output_stream = &std::cout;
125 std::unique_ptr<ThreadPool> thread_pool = std::make_unique<ThreadPool>(std::thread::hardware_concurrency());
126 ProgramPool program_pool = ProgramPool(10); // Maximum 10 programs in the pool
127 std::ofstream log_file;
128
129 // Debouncing didChange notifications
131 std::atomic<uint64_t> change_generation{0};
132 std::atomic<uint64_t> average_reparse_time_in_microseconds{50'000}; // 50ms initial guess
133 std::atomic<uint32_t> debounce_time_in_milliseconds{100}; // Start with 100ms
134 };
135
136 // Map: program main URI -> DebounceState
137 // Used for adaptive debouncing
139 private:
140 std::unordered_map<std::string, std::shared_ptr<DebounceState>> states;
142 std::mutex map_mutex;
143
144 void cleanup() {
145 for (auto it = states.begin(); it != states.end(); ) {
146 if (!pool->has_program(it->first)) {
147 it = states.erase(it);
148 } else {
149 it++;
150 }
151 }
152 }
153 public:
156 std::shared_ptr<DebounceState> get(const std::string& uri) {
157 std::lock_guard<std::mutex> lock(map_mutex);
158 cleanup(); // Clean up stale entries on every access
159 auto it = states.find(uri);
160 if (it != states.end()) return it->second;
161 auto new_state = std::make_shared<DebounceState>();
162 states[uri] = new_state;
163 return new_state;
164 }
165 };
167 std::atomic<bool> processing_didChange{false};
168
169 static std::string readHeaderLine(std::streambuf* buffer);
170
171 void _sendMessage(const std::string& message);
172
173 static std::mutex output_mutex; // Mutex for thread-safe output
174 static std::mutex log_mutex; // Mutex for thread-safe logging
175
176 static GenericResponseMessage invalidRequestHandler(const GenericRequestMessage& request);
177 static void invalidNotificationHandler(const GenericNotificationMessage& request);
178
179 void processRequest(const GenericRequestMessage& request);
180 void processNotification(const GenericNotificationMessage& notification);
181
183 .isIncomplete = false,
184 .items = {
185 CompletionItem{
186 .label = "class",
187 .kind = CompletionItemKind::Keyword,
188 .detail = "Define a new class"
189 },
190 CompletionItem{
191 .label = "public",
192 .kind = CompletionItemKind::Keyword,
193 .detail = "Public access specifier"
194 },
195 CompletionItem{
196 .label = "private",
197 .kind = CompletionItemKind::Keyword,
198 .detail = "Private access specifier"
199 },
200 CompletionItem{
201 .label = "protected",
202 .kind = CompletionItemKind::Keyword,
203 .detail = "Protected access specifier"
204 },
205 CompletionItem{
206 .label = "method",
207 .kind = CompletionItemKind::Keyword,
208 .detail = "Define a new method in a class"
209 },
210 CompletionItem{
211 .label = "constructor",
212 .kind = CompletionItemKind::Keyword,
213 .detail = "Define a constructor for a class"
214 },
215 CompletionItem{
216 .label = "destructor",
217 .kind = CompletionItemKind::Keyword,
218 .detail = "Define a destructor for a class"
219 },
220 CompletionItem{
221 .label = "virtual",
222 .kind = CompletionItemKind::Keyword,
223 .detail = "Declare a method to be virtual"
224 },
225 CompletionItem{
226 .label = "this",
227 .kind = CompletionItemKind::Keyword,
228 .detail = "Reference the current object"
229 },
230 CompletionItem{
231 .label = "super",
232 .kind = CompletionItemKind::Keyword,
233 .detail = "Reference the current object as an instance of its parent class"
234 },
235 CompletionItem{
236 .label = "include",
237 .kind = CompletionItemKind::Keyword,
238 .detail = "Include a file"
239 },
240 CompletionItem{
241 .label = "include_once",
242 .kind = CompletionItemKind::Keyword,
243 .detail = "Include a file only once"
244 },
245 CompletionItem{
246 .label = "dynamic_cast",
247 .kind = CompletionItemKind::Keyword,
248 .detail = "Perform a dynamic cast"
249 },
250 CompletionItem{
251 .label = "typeof",
252 .kind = CompletionItemKind::Keyword,
253 .detail = "Get the type of a pointer"
254 },
255 CompletionItem{
256 .label = "new",
257 .kind = CompletionItemKind::Keyword,
258 .detail = "Create a new object"
259 },
260 CompletionItem{
261 .label = "delete",
262 .kind = CompletionItemKind::Keyword,
263 .detail = "Delete an object"
264 },
265 CompletionItem{
266 .label = "nullptr",
267 .kind = CompletionItemKind::Keyword,
268 .detail = "Null pointer constant"
269 }
270 }
271 };
272
273 using RequestHandler = GenericResponseMessage (BashppServer::*)(const GenericRequestMessage&);
274 using NotificationHandler = void (BashppServer::*)(const GenericNotificationMessage&);
275
284
289 static constexpr std::array<RequestHandlerEntry, 8> request_handlers = {{
290 {"initialize", &BashppServer::handleInitialize},
291 {"textDocument/definition", &BashppServer::handleDefinition},
292 {"textDocument/completion", &BashppServer::handleCompletion},
293 {"textDocument/hover", &BashppServer::handleHover},
294 {"textDocument/documentSymbol", &BashppServer::handleDocumentSymbol},
295 {"textDocument/rename", &BashppServer::handleRename},
296 {"textDocument/references", &BashppServer::handleReferences},
297 {"shutdown", &BashppServer::shutdown}
298 }};
299
304 static constexpr std::array<NotificationHandlerEntry, 6> notification_handlers = {{
305 {"textDocument/didOpen", &BashppServer::handleDidOpen},
306 {"textDocument/didChange", &BashppServer::handleDidChange},
307 {"workspace/didChangeWatchedFiles", &BashppServer::handleDidChangeWatchedFiles},
308 {"textDocument/didSave", &BashppServer::handleDidSave},
309 {"textDocument/didClose", &BashppServer::handleDidClose},
310 {"exit", &BashppServer::exit}
311 }};
312};
313
314} // namespace bpp
Manages a pool of bpp_program objects for efficient reuse and access.
Definition ProgramPool.h:36
bool has_program(const std::string &file_path)
Check if a program for the given file path exists in the pool.
Definition ProgramPool.cpp:286
Definition BashppServer.h:138
ProgramPool * pool
Definition BashppServer.h:141
void cleanup()
Definition BashppServer.h:144
std::shared_ptr< DebounceState > get(const std::string &uri)
Definition BashppServer.h:156
DebounceStateMap(ProgramPool *program_pool)
Definition BashppServer.h:155
std::unordered_map< std::string, std::shared_ptr< DebounceState > > states
Definition BashppServer.h:140
std::mutex map_mutex
Definition BashppServer.h:142
The main server class for handling LSP requests and notifications.
Definition BashppServer.h:54
std::atomic< bool > exiting
Definition BashppServer.h:119
void publishDiagnostics(std::shared_ptr< bpp::bpp_program > program)
Definition BashppServer.cpp:245
GenericResponseMessage handleHover(const GenericRequestMessage &request)
Definition handleHover.cpp:18
void(BashppServer::*)(const GenericNotificationMessage &) NotificationHandler
Definition BashppServer.h:274
void processNotification(const GenericNotificationMessage &notification)
Definition BashppServer.cpp:170
static std::string readHeaderLine(std::streambuf *buffer)
Definition BashppServer.cpp:44
std::ostream * output_stream
Definition BashppServer.h:124
void mainLoop()
Definition BashppServer.cpp:59
static std::mutex log_mutex
Definition BashppServer.h:174
DebounceStateMap debounce_states
Definition BashppServer.h:166
GenericResponseMessage handleRename(const GenericRequestMessage &request)
Definition handleRename.cpp:19
pid_t pid
Definition BashppServer.h:118
void sendNotification(const GenericNotificationMessage &notification)
Definition BashppServer.cpp:133
void processRequest(const GenericRequestMessage &request)
Definition BashppServer.cpp:139
GenericResponseMessage handleDocumentSymbol(const GenericRequestMessage &request)
Definition handleDocumentSymbol.cpp:17
ProgramPool program_pool
Definition BashppServer.h:126
void handleDidClose(const GenericNotificationMessage &request)
Definition handledDidClose.cpp:11
GenericResponseMessage(BashppServer::*)(const GenericRequestMessage &) RequestHandler
Definition BashppServer.h:273
void sendResponse(const GenericResponseMessage &response)
Definition BashppServer.cpp:127
std::atomic< bool > processing_didChange
Definition BashppServer.h:167
static GenericResponseMessage invalidRequestHandler(const GenericRequestMessage &request)
Definition BashppServer.cpp:113
~BashppServer()=default
BashppServer & operator=(const BashppServer &other)=delete
BashppServer(const BashppServer &other)=delete
GenericResponseMessage shutdown(const GenericRequestMessage &request)
Definition BashppServer.cpp:225
GenericResponseMessage handleReferences(const GenericRequestMessage &request)
Definition handleReference.cpp:15
BashppServer & operator=(BashppServer &&other) noexcept=delete
void exit(const GenericNotificationMessage &notification)
Definition BashppServer.cpp:234
static void invalidNotificationHandler(const GenericNotificationMessage &request)
Definition BashppServer.cpp:117
std::istream * input_stream
Definition BashppServer.h:123
void handleDidChange(const GenericNotificationMessage &request)
Definition handleDidChange.cpp:13
void processMessage(const std::string &message)
Definition BashppServer.cpp:190
void handleDidOpen(const GenericNotificationMessage &request)
Definition handleDidOpen.cpp:11
std::atomic< bool > shutdown_requested
Definition BashppServer.h:120
void log(Args &&... args)
Definition BashppServer.h:103
GenericResponseMessage handleInitialize(const GenericRequestMessage &request)
Definition handleInitialize.cpp:12
static constexpr std::array< NotificationHandlerEntry, 6 > notification_handlers
Maps notification types to the functions that handle them.
Definition BashppServer.h:304
std::ofstream log_file
Definition BashppServer.h:127
GenericResponseMessage handleDefinition(const GenericRequestMessage &request)
Definition handleDefinition.cpp:15
CompletionList handleDOTCompletion(const CompletionParams &params)
Definition handleCompletion.cpp:129
void setThreadCount(size_t num_threads)
Definition BashppServer.cpp:28
void setLogFile(const std::string &path)
Definition BashppServer.cpp:19
CompletionList handleATCompletion(const CompletionParams &params)
Definition handleCompletion.cpp:83
void handleDidChangeWatchedFiles(const GenericNotificationMessage &request)
Definition handleDidChangeWatchedFiles.cpp:11
void add_include_path(const std::string &path)
Definition BashppServer.cpp:291
BashppServer(BashppServer &&other) noexcept=delete
BashppServer()=default
static constexpr std::array< RequestHandlerEntry, 8 > request_handlers
Maps request types to the functions that handle them.
Definition BashppServer.h:289
void cleanup()
Definition BashppServer.cpp:34
CompletionList default_completion_list
Definition BashppServer.h:182
std::unique_ptr< ThreadPool > thread_pool
Definition BashppServer.h:125
static std::mutex output_mutex
Definition BashppServer.h:173
void setTargetBashVersion(const BashVersion &version)
Definition BashppServer.cpp:24
void _sendMessage(const std::string &message)
Definition BashppServer.cpp:121
GenericResponseMessage handleCompletion(const GenericRequestMessage &request)
Definition handleCompletion.cpp:19
void set_suppress_warnings(bool suppress)
Definition BashppServer.cpp:295
void handleDidSave(const GenericNotificationMessage &request)
Definition handleDidSave.cpp:11
Definition bash_case.cpp:9
void printValue(std::ostream &os, const T &value)
Definition BashppServer.h:36
nlohmann::json json
Definition BashppServer.h:33
Represents a Bash version to target for code generation.
Definition BashVersion.h:23
Definition BashppServer.h:130
std::atomic< uint32_t > debounce_time_in_milliseconds
Definition BashppServer.h:133
std::atomic< uint64_t > change_generation
Definition BashppServer.h:131
std::atomic< uint64_t > average_reparse_time_in_microseconds
Definition BashppServer.h:132
Definition BashppServer.h:280
std::string_view method_name
Definition BashppServer.h:281
NotificationHandler handler
Definition BashppServer.h:282
Definition BashppServer.h:276
std::string_view method_name
Definition BashppServer.h:277
RequestHandler handler
Definition BashppServer.h:278