-
Notifications
You must be signed in to change notification settings - Fork 15
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Some fixes to make edit()
and file.edit()
more robust
#68
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -8,6 +8,7 @@ | |
use harp::vector::CharacterVector; | ||
use harp::vector::Vector; | ||
use libR_sys::*; | ||
use stdext::unwrap; | ||
use tokio::runtime::Runtime; | ||
use tower_lsp::lsp_types::ShowDocumentParams; | ||
use tower_lsp::lsp_types::Url; | ||
|
@@ -19,13 +20,25 @@ unsafe extern "C" fn ps_editor(file: SEXP, _title: SEXP) -> SEXP { | |
let rt = Runtime::new().unwrap(); | ||
let globals = R_CALLBACK_GLOBALS.as_ref().unwrap(); | ||
let files = CharacterVector::new_unchecked(file); | ||
|
||
for file in files.iter() { | ||
if let Some(file) = file { | ||
rt.block_on(async move { | ||
let uri = Url::from_file_path(&file); | ||
|
||
let uri = unwrap!(uri, Err(_) => { | ||
// The R side of this handles most issues, but we don't want to panic | ||
// if some unknown file path slips through. | ||
// `from_file_path()` doesn't return `Display`able errors, so we | ||
// can't necessarily give a good reason. | ||
log::error!("Can't open file at '{}'.", file); | ||
return; | ||
}); | ||
Comment on lines
+27
to
+36
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As mentioned in the comment, it is fairly hard to get here now, but just in case we do we don't want to panic |
||
|
||
globals | ||
.lsp_client | ||
.show_document(ShowDocumentParams { | ||
uri: Url::from_file_path(file).unwrap(), | ||
uri, | ||
external: Some(false), | ||
take_focus: Some(true), | ||
selection: None, | ||
|
@@ -36,5 +49,5 @@ unsafe extern "C" fn ps_editor(file: SEXP, _title: SEXP) -> SEXP { | |
} | ||
} | ||
|
||
file | ||
R_NilValue | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
# | ||
# options.R | ||
# | ||
# Copyright (C) 2023 Posit Software, PBC. All rights reserved. | ||
# | ||
# | ||
|
||
handler_editor <- function(file, title, ..., name = NULL) { | ||
# `file.edit()` calls this as `editor(file = file, title = title)` | ||
# `edit()` calls this as `editor(name = name, file = file, title = title)` | ||
|
||
if (!is.null(name)) { | ||
stop("Editing objects is not currently supported.", call. = FALSE) | ||
} | ||
Comment on lines
+12
to
+14
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
|
||
if (identical(file, "")) { | ||
# i.e. `edit()` with no arguments. Also `file.edit("")`. | ||
# Opens a temporary file for editing. | ||
file <- tempfile(fileext = ".txt") | ||
} | ||
Comment on lines
+16
to
+20
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is documented behavior of |
||
|
||
file <- as.character(file) | ||
title <- as.character(title) | ||
|
||
# Get absolute path to file | ||
file <- normalizePath(file, mustWork = FALSE) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This was previously |
||
|
||
# Make sure the requested files exist, creating them if they don't | ||
ensure_file(file) | ||
|
||
# Edit those files. | ||
.ps.Call("ps_editor", file, title) | ||
|
||
invisible() | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -14,13 +14,69 @@ | |
} | ||
|
||
ensure_directory <- function(path) { | ||
dir.create(path, showWarnings = FALSE, recursive = TRUE) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I do think we want to error here, because we don't want to pass some invalid path to Rust |
||
exists <- dir.exists(path) | ||
|
||
if (all(exists)) { | ||
# Nothing to do if they all exist | ||
return(invisible()) | ||
} | ||
|
||
path <- path[!exists] | ||
|
||
# Try to create missing ones (`dir.create()` isn't vectorized) | ||
for (elt in path) { | ||
dir.create(elt, showWarnings = FALSE, recursive = TRUE) | ||
} | ||
Comment on lines
+26
to
+29
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. i.e. for posit-dev/positron#857 |
||
|
||
exists <- dir.exists(path) | ||
|
||
if (all(exists)) { | ||
# Nothing left to do if the missing ones were successfully created | ||
return(invisible()) | ||
} | ||
|
||
path <- path[!exists] | ||
path <- encodeString(path, quote = "\"") | ||
path <- paste0(path, collapse = ", ") | ||
|
||
stop("Can't create the directory at: ", path, call. = FALSE) | ||
} | ||
|
||
ensure_parent_directory <- function(path) { | ||
ensure_directory(dirname(path)) | ||
} | ||
|
||
ensure_file <- function(path) { | ||
exists <- file.exists(path) | ||
|
||
if (all(exists)) { | ||
# All files exist already, nothing to do | ||
return(invisible()) | ||
} | ||
|
||
path <- path[!exists] | ||
|
||
# Create parent directories as needed | ||
ensure_parent_directory(path) | ||
|
||
# Try to create the missing files | ||
file.create(path, showWarnings = FALSE) | ||
|
||
exists <- file.exists(path) | ||
Comment on lines
+63
to
+65
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I was scared to use the result of
So rather than using the creation result, we check for existence of that original path again |
||
|
||
if (all(exists)) { | ||
# We successfully created the new files and can detect | ||
# their existance | ||
return(invisible()) | ||
} | ||
|
||
path <- path[!exists] | ||
path <- encodeString(path, quote = "\"") | ||
path <- paste0(path, collapse = ", ") | ||
|
||
stop("Can't create the files at: ", path, call. = FALSE) | ||
} | ||
|
||
# Checks if a package is installed without loading it. | ||
# Could be slow on network drives. | ||
is_installed <- function(pkg, minimum_version = NULL) { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -12,16 +12,8 @@ options(max.print = 1000) | |
options(help_type = "html") | ||
|
||
# Use internal editor | ||
options(editor = function(file, title, ...) { | ||
|
||
# Make sure the requested files exist. | ||
file <- as.character(path.expand(file)) | ||
ensure_parent_directory(file) | ||
file.create(file[!file.exists(file)]) | ||
|
||
# Edit those files. | ||
.ps.Call("ps_editor", as.character(file), as.character(title)) | ||
|
||
options(editor = function(file, title, ..., name = NULL) { | ||
handler_editor(file = file, title = title, ..., name = name) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I have put this in its own private helper instead, as that makes it easier to debug by name, i.e. |
||
}) | ||
|
||
# Use custom browser implementation | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see that this is an
async
function, and we use.await
down below.I don't need to do anything special before returning here, right? In my testing this seemed okay