diff options
| author | DanielGavin <danielgavin5@hotmail.com> | 2022-08-01 14:14:40 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2022-08-01 14:14:40 +0200 |
| commit | bbc6dc4b64f3dc8c9cb9c4671be641f31e4cd327 (patch) | |
| tree | fd0c15ef5110077d327285a3acba3be1664ae854 | |
| parent | 7da73a562eb017708ac89ec6658db982fc941689 (diff) | |
| parent | 5c94e68ebb7c217be2d5dd74fc484a3b3ac9467a (diff) | |
Merge pull request #128 from igordreher/diagnostics
Implement platform independent `run_executable`
| -rw-r--r-- | src/common/util.odin | 35 | ||||
| -rw-r--r-- | src/server/check.odin | 285 |
2 files changed, 174 insertions, 146 deletions
diff --git a/src/common/util.odin b/src/common/util.odin index 6e31563..b28154e 100644 --- a/src/common/util.odin +++ b/src/common/util.odin @@ -4,6 +4,9 @@ import "core:fmt" import "core:os" import "core:strings" import "core:path/filepath" +foreign import libc "system:c" +import "core:mem" +import "core:bytes" when ODIN_OS == .Windows { delimiter :: ";" @@ -35,3 +38,35 @@ lookup_in_path :: proc(name: string) -> (string, bool) { return "", false } + +run_executable :: proc(command: string, stdout: ^[]byte) -> (u32, bool, []byte) { + fp := popen(strings.clone_to_cstring(command, context.temp_allocator), "r") + if fp == nil { + return 0, false, stdout[0:] + } + defer pclose(fp) + + read_buffer: [50]byte + index: int + + for fgets(&read_buffer[0], size_of(read_buffer), fp) != nil { + read := bytes.index_byte(read_buffer[:], 0) + defer index += cast(int)read + + if read > 0 && index + cast(int)read <= len(stdout) { + mem.copy(&stdout[index], &read_buffer[0], cast(int)read) + } + } + + return 0, true, stdout[0:index] +} + +foreign libc +{ + popen :: proc(command: cstring, type: cstring) -> ^FILE --- + pclose :: proc(stream: ^FILE) -> i32 --- + fgets :: proc "cdecl" (s: [^]byte, n: i32, stream: ^FILE) -> [^]u8 --- + fgetc :: proc "cdecl" (stream: ^FILE) -> i32 --- +} + +FILE :: struct {} diff --git a/src/server/check.odin b/src/server/check.odin index 1721cec..38a999f 100644 --- a/src/server/check.odin +++ b/src/server/check.odin @@ -18,200 +18,177 @@ import "core:text/scanner" import "shared:common" -when ODIN_OS == .Windows { - - is_package :: proc(file: string, pkg: string) { - - } +is_package :: proc(file: string, pkg: string) { + +} - check :: proc(uri: common.Uri, writer: ^Writer, config: ^common.Config) { - data := make([]byte, mem.Kilobyte*10, context.temp_allocator) +check :: proc(uri: common.Uri, writer: ^Writer, config: ^common.Config) { + data := make([]byte, mem.Kilobyte*10, context.temp_allocator) - buffer: []byte - code: u32 - ok: bool + buffer: []byte + code: u32 + ok: bool - collection_builder := strings.builder_make(context.temp_allocator) + collection_builder := strings.builder_make(context.temp_allocator) - for k, v in common.config.collections { - if k == "" || k == "core" || k == "vendor" { - continue - } - strings.write_string(&collection_builder, fmt.aprintf("-collection:%v=%v ", k, v)) + for k, v in common.config.collections { + if k == "" || k == "core" || k == "vendor" { + continue } + strings.write_string(&collection_builder, fmt.aprintf("-collection:%v=%v ", k, v)) + } - command: string - - if config.odin_command != "" { - command = config.odin_command - - } else { - command = "odin" - } - - if code, ok, buffer = common.run_executable(fmt.tprintf("%v check %s %s -no-entry-point %s", command, path.dir(uri.path, context.temp_allocator), strings.to_string(collection_builder), config.checker_args), &data); !ok { - log.errorf("Odin check failed with code %v for file %v", code, uri.path) - return - } - - s: scanner.Scanner + command: string - scanner.init(&s, string(buffer)) + if config.odin_command != "" { + command = config.odin_command + } else { + command = "odin" + } - s.whitespace = {'\t', ' '} + if code, ok, buffer = common.run_executable(fmt.tprintf("%v check %s %s -no-entry-point %s 2>&1", command, path.dir(uri.path, context.temp_allocator), strings.to_string(collection_builder), config.checker_args), &data); !ok { + log.errorf("Odin check failed with code %v for file %v", code, uri.path) + return + } - current: rune + s: scanner.Scanner - ErrorSeperator :: struct { - message: string, - line: int, - column: int, - uri: string, - } + scanner.init(&s, string(buffer)) - error_seperators := make([dynamic]ErrorSeperator, context.temp_allocator) + s.whitespace = {'\t', ' '} - //find all the signatures string(digit:digit) - loop: for scanner.peek(&s) != scanner.EOF { + current: rune - error: ErrorSeperator + ErrorSeperator :: struct { + message: string, + line: int, + column: int, + uri: string, + } - source_pos := s.src_pos + error_seperators := make([dynamic]ErrorSeperator, context.temp_allocator) - if source_pos == 1 { - source_pos = 0 - } + //find all the signatures string(digit:digit) + loop: for scanner.peek(&s) != scanner.EOF { - for scanner.peek(&s) != '(' { - n := scanner.scan(&s) + error: ErrorSeperator - if n == scanner.EOF { - break loop - } - } + source_pos := s.src_pos - error.uri = string(buffer[source_pos:s.src_pos-1]) + if source_pos == 1 { + source_pos = 0 + } - left_paren := scanner.scan(&s) + for scanner.peek(&s) != '(' { + n := scanner.scan(&s) - if left_paren != '(' { + if n == scanner.EOF { break loop - } + } + } - lhs_digit := scanner.scan(&s) + error.uri = string(buffer[source_pos:s.src_pos-1]) - if lhs_digit != scanner.Int { - break loop - } + left_paren := scanner.scan(&s) - line, column: int - ok: bool + if left_paren != '(' { + break loop + } - line, ok = strconv.parse_int(scanner.token_text(&s)) + lhs_digit := scanner.scan(&s) - if !ok { - break loop - } + if lhs_digit != scanner.Int { + break loop + } - seperator := scanner.scan(&s) + line, column: int + ok: bool - if seperator != ':' { - break loop - } + line, ok = strconv.parse_int(scanner.token_text(&s)) - rhs_digit := scanner.scan(&s) + if !ok { + break loop + } - if rhs_digit != scanner.Int { - break loop - } + seperator := scanner.scan(&s) - column, ok = strconv.parse_int(scanner.token_text(&s)) + if seperator != ':' { + break loop + } - if !ok { - break loop - } + rhs_digit := scanner.scan(&s) - right_paren := scanner.scan(&s) + if rhs_digit != scanner.Int { + break loop + } - if right_paren != ')' { - break loop - } + column, ok = strconv.parse_int(scanner.token_text(&s)) - source_pos = s.src_pos + if !ok { + break loop + } - for scanner.peek(&s) != '\n' { - n := scanner.scan(&s) + right_paren := scanner.scan(&s) - if n == scanner.EOF { - break - } - } + if right_paren != ')' { + break loop + } - if source_pos == s.src_pos { - continue - } + source_pos = s.src_pos - error.message = string(buffer[source_pos:s.src_pos-1]) - error.column = column - error.line = line + for scanner.peek(&s) != '\n' { + n := scanner.scan(&s) - append(&error_seperators, error) + if n == scanner.EOF { + break + } } - errors := make(map[string][dynamic]Diagnostic, 0, context.temp_allocator) + if source_pos == s.src_pos { + continue + } - for error in error_seperators { + error.message = string(buffer[source_pos:s.src_pos-1]) + error.column = column + error.line = line - if error.uri not_in errors { - errors[error.uri] = make([dynamic]Diagnostic, context.temp_allocator) - } + append(&error_seperators, error) + } - append(&errors[error.uri], Diagnostic { - code = "checker", - severity = .Error, - range = { - start = { - character = 0, - line = error.line - 1, - }, - end = { - character = 0, - line = error.line, - }, - }, - message = error.message, - }) - } - - matches, err := filepath.glob(fmt.tprintf("%v/*.odin", path.dir(uri.path, context.temp_allocator))) - - if err == .None { - for match in matches { - uri := common.create_uri(match, context.temp_allocator) - - params := NotificationPublishDiagnosticsParams { - uri = uri.uri, - diagnostics = {}, - } - - notifaction := Notification { - jsonrpc = "2.0", - method = "textDocument/publishDiagnostics", - params = params, - } - - if writer != nil { - send_notification(notifaction, writer) - } - } + errors := make(map[string][dynamic]Diagnostic, 0, context.temp_allocator) + + for error in error_seperators { + + if error.uri not_in errors { + errors[error.uri] = make([dynamic]Diagnostic, context.temp_allocator) } - for k, v in errors { - uri := common.create_uri(k, context.temp_allocator) + append(&errors[error.uri], Diagnostic { + code = "checker", + severity = .Error, + range = { + start = { + character = 0, + line = error.line - 1, + }, + end = { + character = 0, + line = error.line, + }, + }, + message = error.message, + }) + } + + matches, err := filepath.glob(fmt.tprintf("%v/*.odin", path.dir(uri.path, context.temp_allocator))) + if err == .None { + for match in matches { + uri := common.create_uri(match, context.temp_allocator) + params := NotificationPublishDiagnosticsParams { uri = uri.uri, - diagnostics = v[:], + diagnostics = {}, } notifaction := Notification { @@ -225,7 +202,23 @@ when ODIN_OS == .Windows { } } } -} else { - check :: proc(uri: common.Uri, writer: ^Writer, config: ^common.Config) { + + for k, v in errors { + uri := common.create_uri(k, context.temp_allocator) + + params := NotificationPublishDiagnosticsParams { + uri = uri.uri, + diagnostics = v[:], + } + + notifaction := Notification { + jsonrpc = "2.0", + method = "textDocument/publishDiagnostics", + params = params, + } + + if writer != nil { + send_notification(notifaction, writer) + } } } |