Skip to content

Commit

Permalink
implement infrastructure for R routine registration (#58)
Browse files Browse the repository at this point in the history
* [WIP]

* [WIP]

* [WIP]

* POC of routine registration

* wire up automagic routine registration

* fix up some imports
  • Loading branch information
kevinushey authored Nov 29, 2022
1 parent d3a7961 commit a9ce481
Show file tree
Hide file tree
Showing 18 changed files with 270 additions and 69 deletions.
26 changes: 25 additions & 1 deletion extensions/positron-r/amalthea/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ impl Kernel {
None,
self.connection.endpoint(self.connection.shell_port),
)?;

let shell_clone = shell_handler.clone();
let iopub_sender_clone = iopub_sender.clone();
thread::spawn(move || Self::shell_thread(shell_socket, iopub_sender_clone, shell_clone));
Expand Down
2 changes: 2 additions & 0 deletions extensions/positron-r/amalthea/crates/ark/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ amalthea = { path = "../amalthea" }
anyhow = { version = "^1.0", features = ["backtrace"] }
async-trait = "0.1.53"
chrono = "0.4.22"
ctor = "0.1.26"
dashmap = "5.3.3"
ego-tree = "0.6.2"
harp = { path = "../harp" }
Expand All @@ -19,6 +20,7 @@ lazy_static = "1.4.0"
libR-sys = { git = "https://github.com/kevinushey/libR-sys", branch = "feature/dynamic-lookup" }
libc = "0.2"
log = "0.4.14"
once_cell = "1.16.0"
nix = { version = "0.24.1", features = ["signal"] }
parking_lot = "0.12.1"
regex = "1.6.0"
Expand Down
14 changes: 10 additions & 4 deletions extensions/positron-r/amalthea/crates/ark/src/interface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
use amalthea::socket::iopub::IOPubMessage;
use harp::lock::R_RUNTIME_LOCK;
use harp::lock::R_RUNTIME_TASKS_PENDING;
use harp::routines::r_register_routines;
use harp::utils::r_get_option;
use libR_sys::*;
use libc::{c_char, c_int};
Expand All @@ -29,6 +30,7 @@ use crate::request::Request;

extern "C" {
fn R_ProcessEvents();
fn run_Rmainloop();
pub static mut R_PolledEvents: Option<unsafe extern "C" fn()>;
}

Expand Down Expand Up @@ -254,10 +256,14 @@ pub fn start_r(
// Listen for polled events
R_PolledEvents = Some(r_polled_events);

// Does not return
trace!("Entering R main loop");
Rf_mainloop();
trace!("Exiting R main loop");
// Set up main loop
setup_Rmainloop();

// Register embedded routines
r_register_routines();

// Run the main loop -- does not return
run_Rmainloop();
}
}

Expand Down
54 changes: 32 additions & 22 deletions extensions/positron-r/amalthea/crates/ark/src/lsp/backend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,14 @@

use std::collections::HashSet;
use std::path::Path;
use std::sync::mpsc::SyncSender;
use std::sync::Arc;
use std::sync::Mutex;
use std::sync::mpsc::SyncSender;

use dashmap::DashMap;
use harp::r_lock;
use log::*;
use once_cell::sync::OnceCell;
use parking_lot::Mutex;
use regex::Regex;
use serde_json::Value;
use stdext::*;
Expand Down Expand Up @@ -43,6 +44,8 @@ use crate::lsp::signature_help::signature_help;
use crate::lsp::symbols;
use crate::request::Request;

pub static CLIENT: OnceCell<Mutex<Client>> = OnceCell::new();

macro_rules! backend_trace {

($self: expr, $($rest: expr),*) => {{
Expand Down Expand Up @@ -113,26 +116,24 @@ impl LanguageServer for Backend {
r_lock! { modules::initialize() };

// initialize the set of known workspaces
if let Ok(mut workspace) = self.workspace.lock() {

// initialize the workspace folders
let mut folders: Vec<String> = Vec::new();
if let Some(workspace_folders) = params.workspace_folders {
for folder in workspace_folders.iter() {
workspace.folders.push(folder.uri.clone());
if let Ok(path) = folder.uri.to_file_path() {
if let Some(path) = path.to_str() {
folders.push(path.to_string());
}
let mut workspace = self.workspace.lock();

// initialize the workspace folders
let mut folders: Vec<String> = Vec::new();
if let Some(workspace_folders) = params.workspace_folders {
for folder in workspace_folders.iter() {
workspace.folders.push(folder.uri.clone());
if let Ok(path) = folder.uri.to_file_path() {
if let Some(path) = path.to_str() {
folders.push(path.to_string());
}
}
}

// start indexing
indexer::start(folders);

}

// start indexing
indexer::start(folders);

Ok(InitializeResult {
server_info: Some(ServerInfo {
name: "Amalthea R Kernel (ARK)".to_string(),
Expand Down Expand Up @@ -578,14 +579,23 @@ pub async fn start_lsp(address: String, channel: SyncSender<Request>) {
debug!("Connecting to LSP client at '{}'", address);
let stream = TcpStream::connect(address).await.unwrap();
let (read, write) = tokio::io::split(stream);

#[cfg(feature = "runtime-agnostic")]
let (read, write) = (read.compat(), write.compat_write());

let (service, socket) = LspService::new(|client| Backend {
client: client,
documents: DOCUMENT_INDEX.clone(),
workspace: Arc::new(Mutex::new(Workspace::default())),
channel: channel,
let (service, socket) = LspService::new(|client| {

// initialize global client (needs to be visible for R routines)
CLIENT.set(Mutex::new(client.clone())).unwrap();

// create backend
Backend {
client: client,
documents: DOCUMENT_INDEX.clone(),
workspace: Arc::new(Mutex::new(Workspace::default())),
channel: channel,
}

});

Server::new(read, write, socket).serve(service).await;
Expand Down
24 changes: 24 additions & 0 deletions extensions/positron-r/amalthea/crates/ark/src/lsp/browser.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
//
// browser.rs
//
// Copyright (C) 2022 by Posit, PBC
//
//

use libR_sys::*;
use tokio::runtime::Runtime;
use tower_lsp::lsp_types::MessageType;

use crate::lsp::backend::CLIENT;

#[harp::register]
pub unsafe extern "C" fn ps_browse_url(url: SEXP) -> SEXP {

let runtime = Runtime::new().unwrap();
runtime.block_on(async move {
let client = CLIENT.get().unwrap().lock();
client.log_message(MessageType::INFO, "This is a message from an R callback!").await;
});

R_NilValue
}
15 changes: 7 additions & 8 deletions extensions/positron-r/amalthea/crates/ark/src/lsp/completions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1185,14 +1185,13 @@ pub fn append_workspace_completions(backend: &Backend, context: &CompletionConte

// add some metadata about where the completion was found
let mut path = path.to_str().unwrap_or_default();
if let Ok(workspace) = backend.workspace.lock() {
for folder in &workspace.folders {
if let Ok(folder) = folder.to_file_path() {
if let Some(folder) = folder.to_str() {
if path.starts_with(folder) {
path = &path[folder.len() + 1..];
break;
}
let workspace = backend.workspace.lock();
for folder in &workspace.folders {
if let Ok(folder) = folder.to_file_path() {
if let Some(folder) = folder.to_str() {
if path.starts_with(folder) {
path = &path[folder.len() + 1..];
break;
}
}
}
Expand Down
1 change: 1 addition & 0 deletions extensions/positron-r/amalthea/crates/ark/src/lsp/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
//

pub mod backend;
pub mod browser;
pub mod comm;
pub mod completions;
pub mod definitions;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#
# options.R
#
# Copyright (C) 2022 by Posit, PBC
#
#

options(browser = function(url) {
.Call("ps_browse_url", as.character(url), PACKAGE = "(embedding)")
})
11 changes: 5 additions & 6 deletions extensions/positron-r/amalthea/crates/ark/src/lsp/references.rs
Original file line number Diff line number Diff line change
Expand Up @@ -224,12 +224,11 @@ impl Backend {
});

// Now, start searching through workspace folders for references to that identifier.
if let Ok(workspace) = self.workspace.lock() {
for folder in workspace.folders.iter() {
if let Ok(path) = folder.to_file_path() {
info!("searching references in folder {}", path.display());
self.find_references_in_folder(&context, &path, &mut locations);
}
let workspace = self.workspace.lock();
for folder in workspace.folders.iter() {
if let Ok(path) = folder.to_file_path() {
info!("searching references in folder {}", path.display());
self.find_references_in_folder(&context, &path, &mut locations);
}
}

Expand Down
5 changes: 4 additions & 1 deletion extensions/positron-r/amalthea/crates/ark/src/shell.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,10 @@ impl Shell {
let iopub_sender = iopub.clone();
let (req_sender, req_receiver) = sync_channel::<Request>(1);
let (init_sender, init_receiver) = channel::<KernelInfo>();
thread::spawn(move || Self::execution_thread(iopub_sender, req_receiver, init_sender));
thread::spawn(move || {
Self::execution_thread(iopub_sender, req_receiver, init_sender);
});

Self {
req_sender: req_sender.clone(),
init_receiver: Arc::new(Mutex::new(init_receiver)),
Expand Down
3 changes: 3 additions & 0 deletions extensions/positron-r/amalthea/crates/harp/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ Tools for integrating R and Rust.
"""

[dependencies]
ctor = "0.1.26"
harp-macros = { path = "./harp-macros" }
lazy_static = "1.4.0"
libR-sys = { git = "https://github.com/kevinushey/libR-sys", branch = "feature/dynamic-lookup" }
log = "0.4.17"
stdext = { path = "../stdext" }
15 changes: 15 additions & 0 deletions extensions/positron-r/amalthea/crates/harp/harp-macros/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
[package]
name = "harp-macros"
version = "0.1.0"
edition = "2021"

[lib]
proc-macro = true

[dependencies]
proc-macro2 = "*"
quote = "*"
syn = { version = "*", features = ["full"] }

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

Loading

0 comments on commit a9ce481

Please sign in to comment.