From 85ee81b8ae972d17f0e3dc78657077924c047ada Mon Sep 17 00:00:00 2001 From: pommicket Date: Tue, 27 Dec 2022 00:16:35 -0500 Subject: added workspaceFolders support but broke non-workspaceFolders support --- README.md | 5 ++++ json.c | 2 +- lsp-parse.c | 16 +++++++--- lsp-write.c | 78 ++++++++++++++++++++++++++++++++++-------------- lsp.c | 60 +++++++++++++++++++++++++++++++++---- lsp.h | 41 ++++++++++++++++++++----- main.c | 7 +++++ ted.c | 28 ++++++++++++----- ted.cfg | 2 +- test.cpp | 62 -------------------------------------- test.go | 18 ----------- test.java | 13 -------- test.js | 12 -------- test.rs | 30 ------------------- test/lsp/JavaA/.ted-root | 0 test/lsp/JavaA/Main.java | 8 +++++ test/lsp/JavaB/.ted-root | 0 test/lsp/JavaB/B.java | 13 ++++++++ test/test.cpp | 62 ++++++++++++++++++++++++++++++++++++++ test/test.go | 18 +++++++++++ test/test.java | 13 ++++++++ test/test.js | 12 ++++++++ test/test.rs | 30 +++++++++++++++++++ 23 files changed, 346 insertions(+), 184 deletions(-) delete mode 100644 test.cpp delete mode 100644 test.go delete mode 100644 test.java delete mode 100644 test.js delete mode 100644 test.rs create mode 100644 test/lsp/JavaA/.ted-root create mode 100644 test/lsp/JavaA/Main.java create mode 100644 test/lsp/JavaB/.ted-root create mode 100644 test/lsp/JavaB/B.java create mode 100644 test/test.cpp create mode 100644 test/test.go create mode 100644 test/test.java create mode 100644 test/test.js create mode 100644 test/test.rs diff --git a/README.md b/README.md index 3f00f1b..64718e3 100644 --- a/README.md +++ b/README.md @@ -234,3 +234,8 @@ ted is in the public domain (see `LICENSE.txt`). You can report a bug by sending an email to `pommicket at pommicket.com`. +If ted is crashing on startup try doing these things: + +- Delete `~/.local/share/ted/session.txt` or `C:\Users\\AppData\Local\ted\session.txt` +- Reset your ted configuration by moving `ted.cfg` somewhere else. + diff --git a/json.c b/json.c index 2dfb368..da52efa 100644 --- a/json.c +++ b/json.c @@ -2,7 +2,6 @@ // provides FAST(ish) parsing but SLOW lookup // this is especially fast for small objects // this actually supports "extended json", where objects can have arbitrary values as keys. - typedef struct { u32 pos; u32 len; @@ -57,6 +56,7 @@ typedef struct { JSONValue *values; } JSON; + #define SKIP_WHITESPACE while (json_is_space(text[index])) ++index; const char *json_type_to_str(JSONValueType type) { diff --git a/lsp-parse.c b/lsp-parse.c index 6d436d9..8797edf 100644 --- a/lsp-parse.c +++ b/lsp-parse.c @@ -79,9 +79,12 @@ static bool parse_range(LSP *lsp, const JSON *json, JSONValue range_value, LSPRa static void parse_capabilities(LSP *lsp, const JSON *json, JSONObject capabilities) { + LSPCapabilities *cap = &lsp->capabilities; + + // check CompletionOptions JSONValue completion_value = json_object_get(json, capabilities, "completionProvider"); if (completion_value.type == JSON_OBJECT) { - lsp->provides_completion = true; + cap->completion_support = true; JSONObject completion = completion_value.val.object; JSONArray trigger_chars = json_object_get_array(json, completion, "triggerCharacters"); @@ -104,6 +107,14 @@ static void parse_capabilities(LSP *lsp, const JSON *json, JSONObject capabiliti } } } + + + JSONObject workspace = json_object_get_object(json, capabilities, "workspace"); + // check WorkspaceFoldersServerCapabilities + JSONObject workspace_folders = json_object_get_object(json, workspace, "workspaceFolders"); + if (json_object_get_bool(json, workspace_folders, "supported", false)) { + cap->workspace_folders_support = true; + } } static bool parse_completion(LSP *lsp, const JSON *json, LSPResponse *response) { @@ -383,15 +394,12 @@ static void process_message(LSP *lsp, JSON *json) { break; case LSP_REQUEST_INITIALIZE: { // it's the response to our initialize request! - if (result.type == JSON_OBJECT) { // read server capabilities JSONObject capabilities = json_object_get_object(json, result.val.object, "capabilities"); parse_capabilities(lsp, json, capabilities); } - // let's send back an "initialized" request (notification) because apparently - // that's something we need to do. LSPRequest initialized = { .type = LSP_REQUEST_INITIALIZED, .data = {0}, diff --git a/lsp-write.c b/lsp-write.c index 5d402c4..93bdd26 100644 --- a/lsp-write.c +++ b/lsp-write.c @@ -32,6 +32,13 @@ static const char *lsp_language_id(Language lang) { return "text"; } +static const char *lsp_document_path(LSP *lsp, LSPDocumentID document) { + if (document >= arr_len(lsp->document_data)) { + assert(0); + return ""; + } + return lsp->document_data[document].path; +} typedef struct { LSP *lsp; @@ -174,13 +181,7 @@ static void write_file_uri_direct(JSONWriter *o, const char *path) { } static void write_file_uri(JSONWriter *o, LSPDocumentID document) { - if (document >= arr_len(o->lsp->document_data)) { - assert(0); - str_builder_append(&o->builder, "\"\""); - return; - } - const char *path = o->lsp->document_data[document].path; - write_file_uri_direct(o, path); + write_file_uri_direct(o, lsp_document_path(o->lsp, document)); } static void write_key_file_uri(JSONWriter *o, const char *key, LSPDocumentID document) { @@ -217,13 +218,18 @@ static void write_key_range(JSONWriter *o, const char *key, LSPRange range) { write_range(o, range); } -static void write_workspace_folders(JSONWriter *o, char **workspace_folders) { +static void write_workspace_folder(JSONWriter *o, LSPDocumentID folder) { + write_obj_start(o); + write_key_file_uri(o, "uri", folder); + write_key_string(o, "name", lsp_document_path(o->lsp, folder)); + write_obj_end(o); +} + +static void write_workspace_folders(JSONWriter *o, LSPDocumentID *workspace_folders) { write_arr_start(o); - arr_foreach_ptr(workspace_folders, char *, folder) { - write_arr_elem_obj_start(o); - write_key_file_uri_direct(o, "uri", *folder); - write_key_string(o, "name", *folder); - write_obj_end(o); + arr_foreach_ptr(workspace_folders, LSPDocumentID, folder) { + write_arr_elem(o); + write_workspace_folder(o, *folder); } write_arr_end(o); } @@ -231,14 +237,18 @@ static void write_workspace_folders(JSONWriter *o, char **workspace_folders) { static const char *lsp_request_method(LSPRequest *request) { switch (request->type) { case LSP_REQUEST_NONE: break; - case LSP_REQUEST_SHOW_MESSAGE: - return "window/showMessage"; - case LSP_REQUEST_LOG_MESSAGE: - return "window/logMessage"; case LSP_REQUEST_INITIALIZE: return "initialize"; case LSP_REQUEST_INITIALIZED: return "initialized"; + case LSP_REQUEST_SHUTDOWN: + return "shutdown"; + case LSP_REQUEST_EXIT: + return "exit"; + case LSP_REQUEST_SHOW_MESSAGE: + return "window/showMessage"; + case LSP_REQUEST_LOG_MESSAGE: + return "window/logMessage"; case LSP_REQUEST_DID_OPEN: return "textDocument/didOpen"; case LSP_REQUEST_DID_CLOSE: @@ -247,12 +257,10 @@ static const char *lsp_request_method(LSPRequest *request) { return "textDocument/didChange"; case LSP_REQUEST_COMPLETION: return "textDocument/completion"; - case LSP_REQUEST_SHUTDOWN: - return "shutdown"; - case LSP_REQUEST_EXIT: - return "exit"; case LSP_REQUEST_WORKSPACE_FOLDERS: return "workspace/workspaceFolders"; + case LSP_REQUEST_DID_CHANGE_WORKSPACE_FOLDERS: + return "workspace/didChangeWorkspaceFolders"; } assert(0); return "$/ignore"; @@ -266,6 +274,7 @@ static bool request_type_is_notification(LSPRequestType type) { case LSP_REQUEST_DID_OPEN: case LSP_REQUEST_DID_CLOSE: case LSP_REQUEST_DID_CHANGE: + case LSP_REQUEST_DID_CHANGE_WORKSPACE_FOLDERS: return true; case LSP_REQUEST_INITIALIZE: case LSP_REQUEST_SHUTDOWN: @@ -385,9 +394,11 @@ static void write_request(LSP *lsp, LSPRequest *request) { write_key_bool(o, "workspaceFolders", true); write_obj_end(o); write_obj_end(o); - write_key_file_uri_direct(o, "rootUri", lsp->workspace_folders[0]); + SDL_LockMutex(lsp->workspace_folders_mutex); + write_key_file_uri(o, "rootUri", lsp->workspace_folders[0]); write_key(o, "workspaceFolders"); write_workspace_folders(o, lsp->workspace_folders); + SDL_UnlockMutex(lsp->workspace_folders_mutex); write_key_obj_start(o, "clientInfo"); write_key_string(o, "name", "ted"); write_obj_end(o); @@ -454,6 +465,25 @@ static void write_request(LSP *lsp, LSPRequest *request) { } write_obj_end(o); } break; + case LSP_REQUEST_DID_CHANGE_WORKSPACE_FOLDERS: { + const LSPRequestDidChangeWorkspaceFolders *w = &request->data.change_workspace_folders; + write_key_obj_start(o, "params"); + write_key_obj_start(o, "event"); + write_key_arr_start(o, "added"); + arr_foreach_ptr(w->added, LSPDocumentID, added) { + write_arr_elem(o); + write_workspace_folder(o, *added); + } + write_arr_end(o); + write_key_arr_start(o, "removed"); + arr_foreach_ptr(w->removed, LSPDocumentID, removed) { + write_arr_elem(o); + write_workspace_folder(o, *removed); + } + write_arr_end(o); + write_obj_end(o); + write_obj_end(o); + } break; } write_obj_end(o); @@ -486,7 +516,9 @@ static void write_response(LSP *lsp, LSPResponse *response) { write_key(o, "result"); switch (response->request.type) { case LSP_REQUEST_WORKSPACE_FOLDERS: - write_workspace_folders(o, lsp->workspace_folders); + SDL_LockMutex(lsp->workspace_folders_mutex); + write_workspace_folders(o, lsp->workspace_folders); + SDL_UnlockMutex(lsp->workspace_folders_mutex); break; default: // this is not a valid client-to-server response. diff --git a/lsp.c b/lsp.c index 0c9aede..e5bec71 100644 --- a/lsp.c +++ b/lsp.c @@ -1,7 +1,7 @@ // print server-to-client communication #define LSP_SHOW_S2C 0 // print client-to-server communication -#define LSP_SHOW_C2S 0 +#define LSP_SHOW_C2S 1 #define write_bool lsp_write_bool @@ -60,6 +60,11 @@ static void lsp_request_free(LSPRequest *r) { lsp_document_change_event_free(event); arr_free(c->changes); } break; + case LSP_REQUEST_DID_CHANGE_WORKSPACE_FOLDERS: { + LSPRequestDidChangeWorkspaceFolders *w = &r->data.change_workspace_folders; + arr_free(w->added); + arr_free(w->removed); + } break; } memset(r, 0, sizeof *r); } @@ -108,6 +113,7 @@ static bool has_response(const char *data, size_t data_len, u64 *p_offset, u64 * } static bool lsp_supports_request(LSP *lsp, const LSPRequest *request) { + LSPCapabilities *cap = &lsp->capabilities; switch (request->type) { case LSP_REQUEST_NONE: // return false for server-to-client requests since we should never send them @@ -124,7 +130,9 @@ static bool lsp_supports_request(LSP *lsp, const LSPRequest *request) { case LSP_REQUEST_EXIT: return true; case LSP_REQUEST_COMPLETION: - return lsp->provides_completion; + return cap->completion_support; + case LSP_REQUEST_DID_CHANGE_WORKSPACE_FOLDERS: + return cap->workspace_folders_support; } assert(0); return false; @@ -323,10 +331,12 @@ LSP *lsp_create(const char *root_dir, Language language, const char *analyzer_co #endif str_hash_table_create(&lsp->document_ids, sizeof(u32)); - arr_add(lsp->workspace_folders, str_dup(root_dir)); lsp->language = language; lsp->quit_sem = SDL_CreateSemaphore(0); + lsp->error_mutex = SDL_CreateMutex(); lsp->messages_mutex = SDL_CreateMutex(); + arr_add(lsp->workspace_folders, lsp_document_id(lsp, root_dir)); + lsp->workspace_folders_mutex = SDL_CreateMutex(); ProcessSettings settings = { .stdin_blocking = true, @@ -346,6 +356,46 @@ LSP *lsp_create(const char *root_dir, Language language, const char *analyzer_co return lsp; } +bool lsp_try_add_root_dir(LSP *lsp, const char *new_root_dir) { + bool got_it = false; + SDL_LockMutex(lsp->workspace_folders_mutex); + if (!lsp->initialized) { + // pretend we have workspace folder support until we get initialize response + // (it's totally possible that this would be called with lsp->initialized = false, + // e.g. if the user starts up ted with multiple files in different projects) + // we'll fix things up when we get the initialize response if there's no actual support. + arr_add(lsp->workspace_folders, lsp_document_id(lsp, new_root_dir)); + got_it = true; + } else { + arr_foreach_ptr(lsp->workspace_folders, LSPDocumentID, folder) { + if (str_has_path_prefix(new_root_dir, lsp_document_path(lsp, *folder))) { + got_it = true; + break; + } + } + } + SDL_UnlockMutex(lsp->workspace_folders_mutex); + if (got_it) return true; + + if (!lsp->capabilities.workspace_folders_support) { + return false; + } + + // send workspace/didChangeWorkspaceFolders notification + LSPRequest req = {.type = LSP_REQUEST_DID_CHANGE_WORKSPACE_FOLDERS}; + LSPRequestDidChangeWorkspaceFolders *w = &req.data.change_workspace_folders; + LSPDocumentID document_id = lsp_document_id(lsp, new_root_dir); + arr_add(w->added, document_id); + lsp_send_request(lsp, &req); + // *technically* this is incorrect because if the server *just now sent* a + // workspace/workspaceFolders request, we'd give it back inconsistent information. + // i don't care. + SDL_LockMutex(lsp->workspace_folders_mutex); + arr_add(lsp->workspace_folders, document_id); + SDL_UnlockMutex(lsp->workspace_folders_mutex); + return true; +} + bool lsp_next_message(LSP *lsp, LSPMessage *message) { bool any = false; SDL_LockMutex(lsp->messages_mutex); @@ -362,6 +412,8 @@ void lsp_free(LSP *lsp) { SDL_SemPost(lsp->quit_sem); SDL_WaitThread(lsp->communication_thread, NULL); SDL_DestroyMutex(lsp->messages_mutex); + SDL_DestroyMutex(lsp->workspace_folders_mutex); + SDL_DestroyMutex(lsp->error_mutex); SDL_DestroySemaphore(lsp->quit_sem); process_kill(&lsp->process); @@ -384,8 +436,6 @@ void lsp_free(LSP *lsp) { lsp_request_free(r); arr_free(lsp->requests_sent); - arr_foreach_ptr(lsp->workspace_folders, char *, folder) - free(*folder); arr_free(lsp->workspace_folders); arr_free(lsp->trigger_chars); diff --git a/lsp.h b/lsp.h index 85993cb..b931b5c 100644 --- a/lsp.h +++ b/lsp.h @@ -26,12 +26,13 @@ typedef enum { // client-to-server LSP_REQUEST_INITIALIZE, LSP_REQUEST_INITIALIZED, + LSP_REQUEST_SHUTDOWN, + LSP_REQUEST_EXIT, LSP_REQUEST_DID_OPEN, LSP_REQUEST_DID_CLOSE, LSP_REQUEST_DID_CHANGE, LSP_REQUEST_COMPLETION, - LSP_REQUEST_SHUTDOWN, - LSP_REQUEST_EXIT, + LSP_REQUEST_DID_CHANGE_WORKSPACE_FOLDERS, // server-to-client LSP_REQUEST_SHOW_MESSAGE, @@ -97,18 +98,25 @@ typedef struct { LSPCompletionContext context; } LSPRequestCompletion; +typedef struct { + LSPDocumentID *removed; // dynamic array + LSPDocumentID *added; // dynamic array +} LSPRequestDidChangeWorkspaceFolders; + typedef struct { // id is set by lsp.c; you shouldn't set it. u32 id; LSPRequestType type; char *id_string; // if not NULL, this is the ID (only for server-to-client messages; we always use integer IDs) - union { + // one member of this union is set depending on `type`. + union { LSPRequestDidOpen open; LSPRequestDidClose close; LSPRequestDidChange change; LSPRequestCompletion completion; - // for LSP_SHOW_MESSAGE and LSP_LOG_MESSAGE + // LSP_REQUEST_SHOW_MESSAGE or LSP_REQUEST_LOG_MESSAGE LSPRequestMessage message; + LSPRequestDidChangeWorkspaceFolders change_workspace_folders; } data; } LSPRequest; @@ -227,6 +235,7 @@ typedef struct { LSPCompletionItem *items; } LSPResponseCompletion; + typedef LSPRequestType LSPResponseType; typedef struct { LSPRequest request; // the request which this is a response to @@ -252,9 +261,19 @@ typedef struct { u32 version_number; // for LSP } LSPDocumentData; +typedef struct { + bool completion_support; + // support for multiple root folders + // sadly, as of me writing this, clangd and rust-analyzer don't support this + // (but jdtls and gopls do) + bool workspace_folders_support; +} LSPCapabilities; + typedef struct LSP { Process process; u32 request_id; + // for our purposes, folders are "documents" + // the spec kinda does this too: WorkspaceFolder has a `uri: DocumentUri` member. StrHashTable document_ids; // values are u32. they are indices into document_data. // this is a dynamic array which just keeps growing. // but the user isn't gonna open millions of files so it's fine. @@ -266,15 +285,18 @@ typedef struct LSP { // so that we can process responses. // this also lets us re-send requests if that's ever necessary. LSPRequest *requests_sent; - bool initialized; // has the response to the initialize request been sent? + // has the response to the initialize request been sent? + // we access this both in the main thread and in the LSP communication thread. + _Atomic bool initialized; SDL_Thread *communication_thread; SDL_sem *quit_sem; char *received_data; // dynamic array - bool provides_completion; // can this LSP server handle completion requests? + LSPCapabilities capabilities; char32_t *trigger_chars; // dynamic array of "trigger characters" SDL_mutex *error_mutex; Language language; - char **workspace_folders; // dynamic array of root directories of LSP "workspaces" (meaningless garbage) + SDL_mutex *workspace_folders_mutex; + LSPDocumentID *workspace_folders; // dynamic array of root directories of LSP "workspaces" (meaningless garbage) char error[256]; } LSP; @@ -293,6 +315,11 @@ void lsp_send_request(LSP *lsp, LSPRequest *request); void lsp_send_response(LSP *lsp, LSPResponse *response); const char *lsp_response_string(const LSPResponse *response, LSPString string); LSP *lsp_create(const char *root_dir, Language language, const char *analyzer_command); +// try to add a new "workspace folder" to the lsp. +// returns true on success or if new_root_dir is already contained in a workspace folder for this LSP. +// if this fails (i.e. if the LSP does not have workspace support), create a new LSP +// with root directory `new_root_dir`. +bool lsp_try_add_root_dir(LSP *lsp, const char *new_root_dir); bool lsp_next_message(LSP *lsp, LSPMessage *message); void lsp_document_changed(LSP *lsp, const char *document, LSPDocumentChangeEvent change); void lsp_free(LSP *lsp); diff --git a/main.c b/main.c index 9339b95..d514132 100644 --- a/main.c +++ b/main.c @@ -1,6 +1,11 @@ /* @TODO: - ignore telemetry/event +- https://github.com/typescript-language-server/typescript-language-server + - NOTE: This supports javascript. + - We should also add a typescript language (but just use javascript syntax highlighting for now) + - (don't want to add .ts as a Javascript extension since that won't be forwards-compatible + if we ever do add real typescript highlighting support) - handle window/showMessageRequest - make sure "save as" works - what's wrong with gopls? @@ -8,6 +13,7 @@ - hover - go to definition using LSP - find usages + - that thing where it shows you the current function argument - workspaceFolders support (so we don't need to start up multiple instances of rust-analyzer) - document lsp.h and lsp.c. - maximum queue size for requests/responses just in case? @@ -39,6 +45,7 @@ FUTURE FEATURES: - keyboard macros - ctrl+9/0 to inc/dec number would be useful here - with macros we can really test performance of buffer_insert_text_at_pos, etc. (which should ideally be fast) +- real typescript highlighting (?) */ #include "base.h" diff --git a/ted.c b/ted.c index 34d67a2..8e2f669 100644 --- a/ted.c +++ b/ted.c @@ -48,15 +48,19 @@ static void *ted_realloc(Ted *ted, void *p, size_t new_size) { return ret; } +char *ted_get_root_dir_of(Ted *ted, const char *path) { + Settings *settings = ted_active_settings(ted); + return settings_get_root_dir(settings, path); +} + // get the project root directory (based on the active buffer or ted->cwd if there's no active buffer). // the return value should be freed char *ted_get_root_dir(Ted *ted) { - Settings *settings = ted_active_settings(ted); TextBuffer *buffer = ted->active_buffer; if (buffer) { - return settings_get_root_dir(settings, buffer->filename); + return ted_get_root_dir_of(ted, buffer->filename); } else { - return settings_get_root_dir(settings, ted->cwd); + return ted_get_root_dir_of(ted, ted->cwd); } } @@ -91,6 +95,14 @@ Settings *ted_get_settings(Ted *ted, const char *path, Language language) { return settings; } +// IMPORTANT NOTE ABOUT CACHING LSPs: +// - be careful if you want to cache LSPs, e.g. adding a LSP *lsp member to `buffer`. +// - right now we pretend that the server has workspace folder support until the initialize response is sent. +// - specifically, this means that: +// ted_get_lsp("/path1/a") => new LSP 0x12345 +// ted_get_lsp("/path2/b") => same LSP 0x12345 +// (receive initialize request, realize we don't have workspace folder support) +// ted_get_lsp("/path2/b") => new LSP 0x6789A LSP *ted_get_lsp(Ted *ted, const char *path, Language language) { Settings *settings = ted_get_settings(ted, path, language); if (!settings->lsp_enabled) @@ -102,11 +114,11 @@ LSP *ted_get_lsp(Ted *ted, const char *path, Language language) { if (!lsp) break; if (lsp->language != language) continue; - // check if root matches up - arr_foreach_ptr(lsp->workspace_folders, char *, lsp_root) { - if (str_has_path_prefix(path, *lsp_root)) - return lsp; - } + // check if root matches up or if we can add a workspace folder + char *root = ted_get_root_dir_of(ted, path); + bool success = lsp_try_add_root_dir(lsp, root); + free(root); + if (success) return lsp; } if (i == TED_LSP_MAX) return NULL; // why are there so many LSP open??? diff --git a/ted.cfg b/ted.cfg index e4a6b1b..53784f2 100644 --- a/ted.cfg +++ b/ted.cfg @@ -51,7 +51,7 @@ regenerate-tags-if-not-found = yes # So if /a/b/.git and /a/Makefile and /a/b/c/Cargo.toml exist, # ted will select /a/b as the root. # if no identifying files are found, the directory containing the current file is used. -root-identifiers = .ted-root.out, Cargo.toml, make.bat, CMakeLists.txt, Makefile, go.mod, .git +root-identifiers = .ted-root, .ted-root.out, Cargo.toml, make.bat, CMakeLists.txt, Makefile, go.mod, .git # you can make your own custom background for ted using a shader. # an example is provided here. you will have access to the following variables: diff --git a/test.cpp b/test.cpp deleted file mode 100644 index e373bff..0000000 --- a/test.cpp +++ /dev/null @@ -1,62 +0,0 @@ -#include -char const *s = R"( -Lorem ipsum dolor sit amet. -It was the age of reason. -It was the age of foolishness. -do { - class x; -} while (0.1238712e+12 != CHAR_MAX); -)"; -using std::cout; - -template -class Option { -public: - Option() { - exists = false; - } - Option(T const &t) { - set(t); - } - void set(T const &t) { - exists = true; - x = t; - } - void clear() { - exists = false; - } - T *get() { - if (exists) - return &x; - else - return nullptr; - } - T const *get() const { - if (exists) - return &x; - else - return nullptr; - } -private: - bool exists; - T x; -}; - -template -void print_option(Option const &o) { - T const *ptr = o.get(); - if (ptr) - cout << *ptr << "\n"; - else - cout << "None\n"; -} - -int main() { - Option o(7); - print_option(o); - o.clear(); - print_option(o); - o.set(133); - print_option(o); - return 0; -} diff --git a/test.go b/test.go deleted file mode 100644 index 98eea24..0000000 --- a/test.go +++ /dev/null @@ -1,18 +0,0 @@ -package main - -import "fmt" - -/* -what -a -wonderful -day -*///yes - -func main() { - var x []int = make([]int, 10) - fmt.Println(x != nil) - println(`hello - world\`) - println("yes\"\\") -} diff --git a/test.java b/test.java deleted file mode 100644 index 7183aed..0000000 --- a/test.java +++ /dev/null @@ -1,13 +0,0 @@ -class Test { - public static void main(String[] args) { - /* hello! - everyone - this - is - a test*/ - String x = "hello, world!\""; - System.out.println(x + - "yes\n\\"+ - x); - } -} diff --git a/test.js b/test.js deleted file mode 100644 index ad95614..0000000 --- a/test.js +++ /dev/null @@ -1,12 +0,0 @@ -const c = `template -strings -yay -`; -let y = 34 * parseInt('hello\\\'\\"') + "'\\"; -/* -comm -ent - -*/a//yes -/* -*//no diff --git a/test.rs b/test.rs deleted file mode 100644 index 40c2438..0000000 --- a/test.rs +++ /dev/null @@ -1,30 +0,0 @@ -/* -testing comments -/* /* /* /* /* hello */ */ */ */ */ -yay -*/ -use std::fs::File; -use std::io::{Result, BufRead, BufReader}; -fn main() -> Result<()> { - let file = File::open("test.rs")?; - let mut reader = BufReader::new(file); - let mut lines = vec![]; - - loop { - let mut line = String::new(); - if reader.read_line(&mut line)? == 0 { - // reached end of file - break; - } - line.pop(); - lines.push(line); - } -let x = lines. - for line in lines { - println!("{}", line); - } - print!(" - string - "); - Ok(()) -} diff --git a/test/lsp/JavaA/.ted-root b/test/lsp/JavaA/.ted-root new file mode 100644 index 0000000..e69de29 diff --git a/test/lsp/JavaA/Main.java b/test/lsp/JavaA/Main.java new file mode 100644 index 0000000..2792b7c --- /dev/null +++ b/test/lsp/JavaA/Main.java @@ -0,0 +1,8 @@ +public class Main { + public static void main(String[] args) { + int x = 0; + x++; + for (int i = 0; i < args.length; ++i) { + } + } +} diff --git a/test/lsp/JavaB/.ted-root b/test/lsp/JavaB/.ted-root new file mode 100644 index 0000000..e69de29 diff --git a/test/lsp/JavaB/B.java b/test/lsp/JavaB/B.java new file mode 100644 index 0000000..fde8107 --- /dev/null +++ b/test/lsp/JavaB/B.java @@ -0,0 +1,13 @@ +public class B { + private static class Something { + public int x = 0; + int f() { + return x; + } + } + + public static void main(String[] args) { + Something s = new Something(); + s.f(); + } +} diff --git a/test/test.cpp b/test/test.cpp new file mode 100644 index 0000000..e373bff --- /dev/null +++ b/test/test.cpp @@ -0,0 +1,62 @@ +#include +char const *s = R"( +Lorem ipsum dolor sit amet. +It was the age of reason. +It was the age of foolishness. +do { + class x; +} while (0.1238712e+12 != CHAR_MAX); +)"; +using std::cout; + +template +class Option { +public: + Option() { + exists = false; + } + Option(T const &t) { + set(t); + } + void set(T const &t) { + exists = true; + x = t; + } + void clear() { + exists = false; + } + T *get() { + if (exists) + return &x; + else + return nullptr; + } + T const *get() const { + if (exists) + return &x; + else + return nullptr; + } +private: + bool exists; + T x; +}; + +template +void print_option(Option const &o) { + T const *ptr = o.get(); + if (ptr) + cout << *ptr << "\n"; + else + cout << "None\n"; +} + +int main() { + Option o(7); + print_option(o); + o.clear(); + print_option(o); + o.set(133); + print_option(o); + return 0; +} diff --git a/test/test.go b/test/test.go new file mode 100644 index 0000000..98eea24 --- /dev/null +++ b/test/test.go @@ -0,0 +1,18 @@ +package main + +import "fmt" + +/* +what +a +wonderful +day +*///yes + +func main() { + var x []int = make([]int, 10) + fmt.Println(x != nil) + println(`hello + world\`) + println("yes\"\\") +} diff --git a/test/test.java b/test/test.java new file mode 100644 index 0000000..7183aed --- /dev/null +++ b/test/test.java @@ -0,0 +1,13 @@ +class Test { + public static void main(String[] args) { + /* hello! + everyone + this + is + a test*/ + String x = "hello, world!\""; + System.out.println(x + + "yes\n\\"+ + x); + } +} diff --git a/test/test.js b/test/test.js new file mode 100644 index 0000000..ad95614 --- /dev/null +++ b/test/test.js @@ -0,0 +1,12 @@ +const c = `template +strings +yay +`; +let y = 34 * parseInt('hello\\\'\\"') + "'\\"; +/* +comm +ent + +*/a//yes +/* +*//no diff --git a/test/test.rs b/test/test.rs new file mode 100644 index 0000000..40c2438 --- /dev/null +++ b/test/test.rs @@ -0,0 +1,30 @@ +/* +testing comments +/* /* /* /* /* hello */ */ */ */ */ +yay +*/ +use std::fs::File; +use std::io::{Result, BufRead, BufReader}; +fn main() -> Result<()> { + let file = File::open("test.rs")?; + let mut reader = BufReader::new(file); + let mut lines = vec![]; + + loop { + let mut line = String::new(); + if reader.read_line(&mut line)? == 0 { + // reached end of file + break; + } + line.pop(); + lines.push(line); + } +let x = lines. + for line in lines { + println!("{}", line); + } + print!(" + string + "); + Ok(()) +} -- cgit v1.2.3