aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorIgor Dreher <igor.dreher@gmail.com>2022-07-31 21:42:51 -0300
committerIgor Dreher <igor.dreher@gmail.com>2022-07-31 21:50:12 -0300
commit5c94e68ebb7c217be2d5dd74fc484a3b3ac9467a (patch)
treefd0c15ef5110077d327285a3acba3be1664ae854 /src
parent7da73a562eb017708ac89ec6658db982fc941689 (diff)
Implement platform independent `run_executable`
This should make diagnostics work on other platforms besides Windows.
Diffstat (limited to 'src')
-rw-r--r--src/common/util.odin35
-rw-r--r--src/server/check.odin285
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)
+ }
}
}