diff --git a/lib/IUtils.rakumod b/lib/IUtils.rakumod index fd1aa1e..7a74f0d 100644 --- a/lib/IUtils.rakumod +++ b/lib/IUtils.rakumod @@ -1,3 +1,4 @@ +#| Utilities for interacting with idris and associated tooling unit module IUtils; need IUtils::IDEMode; diff --git a/lib/IUtils/IDEMode.rakumod b/lib/IUtils/IDEMode.rakumod index 8985e11..4c8d765 100644 --- a/lib/IUtils/IDEMode.rakumod +++ b/lib/IUtils/IDEMode.rakumod @@ -1,10 +1,16 @@ +#| Interaction wtih Idris 2's IDE Mode unit class IUtils::IDEMode; +#| The underlying idris process has $!process; +#| The port number we are connected via has $!port; +#| The socket we are connected via has $!socket; +#| The next request id has $!request-id = 0; +#| Grammar for S-Expressions grammar SExp { rule TOP { } @@ -22,6 +28,7 @@ grammar SExp { } } +#| Convert a parsed S-Expression into a list of lists class SExp::Actions { method TOP($/) { make $.made } @@ -74,6 +81,7 @@ submethod TWEAK { say "IDE Protocol Version: $major.$minor"; } +#| Capture and parse the initial protocol version message method process-protocol-version() { my @resp = self.read-sexp(); if @resp[0] eq ':protocol-version' { @@ -82,6 +90,7 @@ method process-protocol-version() { die "Expected protocol version, got: ", @resp; } +#| Read one sexp from the IDE server method read-sexp() { my $len = $!socket.read(6).decode('utf8'); my $msg = $!socket.read(:bin, $len.parse-base(16)).decode('utf8'); @@ -89,6 +98,11 @@ method read-sexp() { SExp.parse($msg, actions => SExp::Actions).made } +#| Send a command to the IDE server, and collect all the responses to that +#| command +#| +#| For convinence, automatically symbolizes the first argument, and will wrap +#| the command in parens if there is more than one argument method send-command(*@cmd) { my $id = ++$!request-id; my $cmd-str; @@ -98,7 +112,6 @@ method send-command(*@cmd) { $cmd-str = "(" ~ (":" ~ @cmd[0]) ~ " $id)"; } my $len = sprintf("%06x", $cmd-str.chars); - # say "Sending: ", $len, $cmd-str; $!socket.print($len ~ $cmd-str); my @responses; @@ -106,12 +119,14 @@ method send-command(*@cmd) { my $resp = self.read-sexp(); @responses.push($resp); + # TODO: Die on error if $resp[0] eq ':return' && $resp[2] == $id { return @responses; } } } +#| Wrapper for :load-file command method load-file($filename, $line-number?){ if $line-number { self.send-command('load-file', "\"$filename\"", $line-number.Str) @@ -120,28 +135,35 @@ method load-file($filename, $line-number?){ } } +#| Wrapper for :cd command method cd($filepath) { self.send-command('cd', "\"$filepath\"") } +#| Wrapper for :interpret command method interpret($cmd) { self.send-command('interpret', "\"$cmd\"") } +#| Wrapper for :type-of command method type-of($item) { self.send-command('type-of', "\"$item\"") } +#| Wrapper for :docs-for command method docs-for($item) { self.send-command('docs-for', "\"$item\"") } +#| Wrapper for :browse-namespace command +#| +#| Will import $namespace before browsing it to ensure we get results method browse-namespace($namespace) { - # Import the namespace first to make sure this works properly self.interpret: ":import $namespace"; self.send-command('browse-namespace', "\"$namespace\"") } +#| Wrapper for :version command method version() { self.send-command('version') }