package main import "core:fmt" import "core:net" import "core:os" import "core:strconv" main :: proc() { args := os.args if len(args) < 2 { fmt.println("usage: odin run client/odin -- [workspace]") fmt.println(" or: odin run client/odin -- --sdl [workspace] [port] [file]") return } if args[1] == "--sdl" { workspace := "." if len(args) >= 3 { workspace = args[2] } port := 0 file := "" if len(args) >= 4 { parsed_port, parsed_ok := strconv.parse_int(args[3]) if parsed_ok { port = int(parsed_port) } else { file = args[3] } } if len(args) >= 5 { file = args[4] } run_sdl_editor(workspace, port, file) return } port, ok := strconv.parse_int(args[1]) if !ok { fmt.println("invalid port") return } workspace := "." if len(args) >= 3 { workspace = args[2] } run_buffer_smoke() editor := run_editor_smoke(workspace) defer editor_destroy(&editor) socket, err := net.dial_tcp("127.0.0.1", int(port)) if err != nil { fmt.println("connect failed:", err) return } defer net.close(socket) send_line(socket, "{\"id\":1,\"method\":\"ping\",\"params\":{}}\n") read_messages(socket, 1) open_workspace := fmt.tprintf("{{\"id\":2,\"method\":\"workspace/open\",\"params\":{{\"root\":%s}}}}\n", json_quote(workspace)) send_line(socket, open_workspace) read_messages(socket, 3) send_line(socket, "{\"id\":3,\"method\":\"gradle/tasks\",\"params\":{}}\n") read_messages(socket, 1) active := editor_active_buffer(&editor) diagnostics_path := active.path active_text := editor_active_text(&editor) defer delete(active_text) text_change_request := fmt.tprintf("{{\"id\":4,\"method\":\"text/change\",\"params\":{{\"path\":%s,\"version\":1,\"text\":%s}}}}\n", json_quote(diagnostics_path), json_quote(string(active_text[:]))) send_line(socket, text_change_request) read_messages(socket, 2) diagnostics_request := fmt.tprintf("{{\"id\":5,\"method\":\"kotlin/diagnostics\",\"params\":{{\"path\":%s}}}}\n", json_quote(diagnostics_path)) send_line(socket, diagnostics_request) read_messages(socket, 1) completion_request := fmt.tprintf("{{\"id\":6,\"method\":\"kotlin/completion\",\"params\":{{\"path\":%s,\"line\":1,\"column\":1}}}}\n", json_quote(diagnostics_path)) send_line(socket, completion_request) read_messages(socket, 1) hover_request := fmt.tprintf("{{\"id\":7,\"method\":\"kotlin/hover\",\"params\":{{\"path\":%s,\"line\":1,\"column\":1}}}}\n", json_quote(diagnostics_path)) send_line(socket, hover_request) read_messages(socket, 1) definition_request := fmt.tprintf("{{\"id\":8,\"method\":\"kotlin/definition\",\"params\":{{\"path\":%s,\"line\":1,\"column\":5}}}}\n", json_quote(diagnostics_path)) send_line(socket, definition_request) read_messages(socket, 1) references_request := fmt.tprintf("{{\"id\":9,\"method\":\"kotlin/references\",\"params\":{{\"path\":%s,\"line\":1,\"column\":5}}}}\n", json_quote(diagnostics_path)) send_line(socket, references_request) read_messages(socket, 1) rename_request := fmt.tprintf("{{\"id\":10,\"method\":\"kotlin/rename\",\"params\":{{\"path\":%s,\"line\":1,\"column\":5,\"newName\":\"renamedBroken\"}}}}\n", json_quote(diagnostics_path)) send_line(socket, rename_request) read_messages(socket, 1) } run_editor_smoke :: proc(workspace: string) -> Editor { editor := Editor{} path := fmt.tprintf("%s/src/main/kotlin/dev/nativeeditor/daemon/Main.kt", workspace) if !editor_open_file(&editor, path) { return editor } fmt.println("editor-visible-before:") editor_print_visible(&editor, 0, 2) editor_replace_active_text(&editor, "fun broken( {") fmt.println("editor-visible-after:") editor_print_visible(&editor, 0, 2) return editor } run_buffer_smoke :: proc() { buffer := buffer_make("hello world\nsecond line\n") defer buffer_destroy(&buffer) buffer_insert(&buffer, 6, "native ") buffer_delete_range(&buffer, 0, 6) cursor := Cursor{} cursor_move_to_line_col(&buffer, &cursor, 1, 6) cursor_insert(&buffer, &cursor, " edited") cursor_backspace(&buffer, &cursor) _ = buffer_undo(&buffer, &cursor) _ = buffer_redo(&buffer, &cursor) cursor_move_vertical(&buffer, &cursor, -1) line, col := buffer_offset_to_line_col(&buffer, cursor.offset) second_line := buffer_line_bytes(&buffer, 1) defer delete(second_line) text := buffer_bytes(&buffer) defer delete(text) fmt.printf("buffer-smoke: %s", string(text[:])) fmt.printf("buffer-lines: %d\n", buffer_line_count(&buffer)) fmt.printf("buffer-line-1: %s\n", string(second_line[:])) fmt.printf("buffer-cursor: %d:%d\n", line, col) } send_line :: proc(socket: net.TCP_Socket, line: string) { bytes := transmute([]byte)line _, err := net.send_tcp(socket, bytes) if err != nil { fmt.println("send failed:", err) } } read_messages :: proc(socket: net.TCP_Socket, expected: int) { seen := 0 for seen < expected { seen += read_some(socket) } } read_some :: proc(socket: net.TCP_Socket) -> int { buf: [4096]byte n, err := net.recv_tcp(socket, buf[:]) if err != nil { fmt.println("recv failed:", err) return 0 } if n == 0 { fmt.println("connection closed") return 0 } lines := 0 for b in buf[:n] { if b == '\n' { lines += 1 } } fmt.print(string(buf[:n])) return lines }