mirror of
https://github.com/chipsenkbeil/distant.git
synced 2024-11-05 12:00:36 +00:00
Add support for --lsp [scheme]
This commit is contained in:
parent
398aff2f12
commit
f2bd2f15f5
@ -10,6 +10,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
### Changed
|
||||
|
||||
- Renamed `distant_core::data` to `distant_core::protocol`
|
||||
- CLI `--lsp` now accepts an optional `scheme` to be used instead of
|
||||
`distant://`, which is the default
|
||||
- `RemoteLspProcess` now takes a second argument, `scheme`, which dictates
|
||||
whether to translate `distant://` or something else
|
||||
|
||||
## [0.20.0-alpha.5]
|
||||
|
||||
|
@ -22,6 +22,7 @@ pub struct RemoteLspCommand {
|
||||
pty: Option<PtySize>,
|
||||
environment: Environment,
|
||||
current_dir: Option<PathBuf>,
|
||||
scheme: Option<String>,
|
||||
}
|
||||
|
||||
impl Default for RemoteLspCommand {
|
||||
@ -37,6 +38,7 @@ impl RemoteLspCommand {
|
||||
pty: None,
|
||||
environment: Environment::new(),
|
||||
current_dir: None,
|
||||
scheme: None,
|
||||
}
|
||||
}
|
||||
|
||||
@ -58,6 +60,12 @@ impl RemoteLspCommand {
|
||||
self
|
||||
}
|
||||
|
||||
/// Configures the process with a specific scheme to convert rather than `distant://`
|
||||
pub fn scheme(&mut self, scheme: Option<String>) -> &mut Self {
|
||||
self.scheme = scheme;
|
||||
self
|
||||
}
|
||||
|
||||
/// Spawns the specified process on the remote machine using the given session, treating
|
||||
/// the process like an LSP server
|
||||
pub async fn spawn(
|
||||
@ -71,9 +79,18 @@ impl RemoteLspCommand {
|
||||
command.pty(self.pty);
|
||||
|
||||
let mut inner = command.spawn(channel, cmd).await?;
|
||||
let stdin = inner.stdin.take().map(RemoteLspStdin::new);
|
||||
let stdout = inner.stdout.take().map(RemoteLspStdout::new);
|
||||
let stderr = inner.stderr.take().map(RemoteLspStderr::new);
|
||||
let stdin = inner
|
||||
.stdin
|
||||
.take()
|
||||
.map(|x| RemoteLspStdin::new(x, self.scheme.clone()));
|
||||
let stdout = inner
|
||||
.stdout
|
||||
.take()
|
||||
.map(|x| RemoteLspStdout::new(x, self.scheme.clone()));
|
||||
let stderr = inner
|
||||
.stderr
|
||||
.take()
|
||||
.map(|x| RemoteLspStderr::new(x, self.scheme.clone()));
|
||||
|
||||
Ok(RemoteLspProcess {
|
||||
inner,
|
||||
@ -119,11 +136,16 @@ impl DerefMut for RemoteLspProcess {
|
||||
pub struct RemoteLspStdin {
|
||||
inner: RemoteStdin,
|
||||
buf: Option<Vec<u8>>,
|
||||
scheme: Option<String>,
|
||||
}
|
||||
|
||||
impl RemoteLspStdin {
|
||||
pub fn new(inner: RemoteStdin) -> Self {
|
||||
Self { inner, buf: None }
|
||||
pub fn new(inner: RemoteStdin, scheme: impl Into<Option<String>>) -> Self {
|
||||
Self {
|
||||
inner,
|
||||
buf: None,
|
||||
scheme: scheme.into(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Tries to write data to the stdin of a specific remote process
|
||||
@ -133,7 +155,10 @@ impl RemoteLspStdin {
|
||||
// Process and then send out each LSP message in our queue
|
||||
for mut data in queue {
|
||||
// Convert distant:// to file://
|
||||
data.mut_content().convert_distant_scheme_to_local();
|
||||
match self.scheme.as_mut() {
|
||||
Some(scheme) => data.mut_content().convert_scheme_to_local(scheme),
|
||||
None => data.mut_content().convert_distant_scheme_to_local(),
|
||||
}
|
||||
data.refresh_content_length();
|
||||
self.inner.try_write_str(data.to_string())?;
|
||||
}
|
||||
@ -152,7 +177,10 @@ impl RemoteLspStdin {
|
||||
// Process and then send out each LSP message in our queue
|
||||
for mut data in queue {
|
||||
// Convert distant:// to file://
|
||||
data.mut_content().convert_distant_scheme_to_local();
|
||||
match self.scheme.as_mut() {
|
||||
Some(scheme) => data.mut_content().convert_scheme_to_local(scheme),
|
||||
None => data.mut_content().convert_distant_scheme_to_local(),
|
||||
}
|
||||
data.refresh_content_length();
|
||||
self.inner.write_str(data.to_string()).await?;
|
||||
}
|
||||
@ -197,16 +225,16 @@ pub struct RemoteLspStdout {
|
||||
}
|
||||
|
||||
impl RemoteLspStdout {
|
||||
pub fn new(inner: RemoteStdout) -> Self {
|
||||
let (read_task, rx) = spawn_read_task(Box::pin(futures::stream::unfold(
|
||||
inner,
|
||||
|mut inner| async move {
|
||||
pub fn new(inner: RemoteStdout, scheme: impl Into<Option<String>>) -> Self {
|
||||
let (read_task, rx) = spawn_read_task(
|
||||
Box::pin(futures::stream::unfold(inner, |mut inner| async move {
|
||||
match inner.read().await {
|
||||
Ok(res) => Some((res, inner)),
|
||||
Err(_) => None,
|
||||
}
|
||||
},
|
||||
)));
|
||||
})),
|
||||
scheme,
|
||||
);
|
||||
|
||||
Self { read_task, rx }
|
||||
}
|
||||
@ -263,16 +291,16 @@ pub struct RemoteLspStderr {
|
||||
}
|
||||
|
||||
impl RemoteLspStderr {
|
||||
pub fn new(inner: RemoteStderr) -> Self {
|
||||
let (read_task, rx) = spawn_read_task(Box::pin(futures::stream::unfold(
|
||||
inner,
|
||||
|mut inner| async move {
|
||||
pub fn new(inner: RemoteStderr, scheme: impl Into<Option<String>>) -> Self {
|
||||
let (read_task, rx) = spawn_read_task(
|
||||
Box::pin(futures::stream::unfold(inner, |mut inner| async move {
|
||||
match inner.read().await {
|
||||
Ok(res) => Some((res, inner)),
|
||||
Err(_) => None,
|
||||
}
|
||||
},
|
||||
)));
|
||||
})),
|
||||
scheme,
|
||||
);
|
||||
|
||||
Self { read_task, rx }
|
||||
}
|
||||
@ -321,10 +349,14 @@ impl Drop for RemoteLspStderr {
|
||||
}
|
||||
}
|
||||
|
||||
fn spawn_read_task<S>(mut stream: S) -> (JoinHandle<()>, mpsc::Receiver<io::Result<Vec<u8>>>)
|
||||
fn spawn_read_task<S>(
|
||||
mut stream: S,
|
||||
scheme: impl Into<Option<String>>,
|
||||
) -> (JoinHandle<()>, mpsc::Receiver<io::Result<Vec<u8>>>)
|
||||
where
|
||||
S: Stream<Item = Vec<u8>> + Send + Unpin + 'static,
|
||||
{
|
||||
let mut scheme = scheme.into();
|
||||
let (tx, rx) = mpsc::channel::<io::Result<Vec<u8>>>(1);
|
||||
let read_task = tokio::spawn(async move {
|
||||
let mut task_buf: Option<Vec<u8>> = None;
|
||||
@ -352,7 +384,10 @@ where
|
||||
let mut out = Vec::new();
|
||||
for mut data in queue {
|
||||
// Convert file:// to distant://
|
||||
data.mut_content().convert_local_scheme_to_distant();
|
||||
match scheme.as_mut() {
|
||||
Some(scheme) => data.mut_content().convert_local_scheme_to(scheme),
|
||||
None => data.mut_content().convert_local_scheme_to_distant(),
|
||||
}
|
||||
data.refresh_content_length();
|
||||
out.extend(data.to_bytes());
|
||||
}
|
||||
|
@ -335,12 +335,22 @@ fn swap_prefix(obj: &mut Map<String, Value>, old: &str, new: &str) {
|
||||
impl LspContent {
|
||||
/// Converts all URIs with `file://` as the scheme to `distant://` instead
|
||||
pub fn convert_local_scheme_to_distant(&mut self) {
|
||||
swap_prefix(&mut self.0, "file:", "distant:");
|
||||
self.convert_local_scheme_to("distant://")
|
||||
}
|
||||
|
||||
/// Converts all URIs with `file://` as the scheme to `scheme` instead
|
||||
pub fn convert_local_scheme_to(&mut self, scheme: &str) {
|
||||
swap_prefix(&mut self.0, "file://", scheme);
|
||||
}
|
||||
|
||||
/// Converts all URIs with `distant://` as the scheme to `file://` instead
|
||||
pub fn convert_distant_scheme_to_local(&mut self) {
|
||||
swap_prefix(&mut self.0, "distant:", "file:");
|
||||
self.convert_scheme_to_local("distant://")
|
||||
}
|
||||
|
||||
/// Converts all URIs with `scheme` as the scheme to `file://` instead
|
||||
pub fn convert_scheme_to_local(&mut self, scheme: &str) {
|
||||
swap_prefix(&mut self.0, scheme, "file://");
|
||||
}
|
||||
}
|
||||
|
||||
@ -688,6 +698,51 @@ mod tests {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn content_convert_local_scheme_to_should_convert_keys_and_values() {
|
||||
let mut content = LspContent(make_obj!({
|
||||
"distant://key1": "file://value1",
|
||||
"file://key2": "distant://value2",
|
||||
"key3": ["file://value3", "distant://value4"],
|
||||
"key4": {
|
||||
"distant://key5": "file://value5",
|
||||
"file://key6": "distant://value6",
|
||||
"key7": [
|
||||
{
|
||||
"distant://key8": "file://value8",
|
||||
"file://key9": "distant://value9",
|
||||
}
|
||||
]
|
||||
},
|
||||
"key10": null,
|
||||
"key11": 123,
|
||||
"key12": true,
|
||||
}));
|
||||
|
||||
content.convert_local_scheme_to("custom://");
|
||||
assert_eq!(
|
||||
content.0,
|
||||
make_obj!({
|
||||
"distant://key1": "custom://value1",
|
||||
"custom://key2": "distant://value2",
|
||||
"key3": ["custom://value3", "distant://value4"],
|
||||
"key4": {
|
||||
"distant://key5": "custom://value5",
|
||||
"custom://key6": "distant://value6",
|
||||
"key7": [
|
||||
{
|
||||
"distant://key8": "custom://value8",
|
||||
"custom://key9": "distant://value9",
|
||||
}
|
||||
]
|
||||
},
|
||||
"key10": null,
|
||||
"key11": 123,
|
||||
"key12": true,
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn content_convert_distant_scheme_to_local_should_convert_keys_and_values() {
|
||||
let mut content = LspContent(make_obj!({
|
||||
@ -732,4 +787,49 @@ mod tests {
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn content_convert_scheme_to_local_should_convert_keys_and_values() {
|
||||
let mut content = LspContent(make_obj!({
|
||||
"custom://key1": "file://value1",
|
||||
"file://key2": "custom://value2",
|
||||
"key3": ["file://value3", "custom://value4"],
|
||||
"key4": {
|
||||
"custom://key5": "file://value5",
|
||||
"file://key6": "custom://value6",
|
||||
"key7": [
|
||||
{
|
||||
"custom://key8": "file://value8",
|
||||
"file://key9": "custom://value9",
|
||||
}
|
||||
]
|
||||
},
|
||||
"key10": null,
|
||||
"key11": 123,
|
||||
"key12": true,
|
||||
}));
|
||||
|
||||
content.convert_scheme_to_local("custom://");
|
||||
assert_eq!(
|
||||
content.0,
|
||||
make_obj!({
|
||||
"file://key1": "file://value1",
|
||||
"file://key2": "file://value2",
|
||||
"key3": ["file://value3", "file://value4"],
|
||||
"key4": {
|
||||
"file://key5": "file://value5",
|
||||
"file://key6": "file://value6",
|
||||
"key7": [
|
||||
{
|
||||
"file://key8": "file://value8",
|
||||
"file://key9": "file://value9",
|
||||
}
|
||||
]
|
||||
},
|
||||
"key10": null,
|
||||
"key11": 123,
|
||||
"key12": true,
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -433,13 +433,13 @@ async fn async_run(cmd: ClientSubcommand) -> CliResult {
|
||||
// Convert cmd into string
|
||||
let cmd = cmd.join(" ");
|
||||
|
||||
if lsp {
|
||||
if let Some(scheme) = lsp {
|
||||
debug!(
|
||||
"Spawning LSP server (pty = {}, cwd = {:?}): {}",
|
||||
pty, current_dir, cmd
|
||||
);
|
||||
Lsp::new(channel.into_client().into_channel())
|
||||
.spawn(cmd, current_dir, pty, MAX_PIPE_CHUNK_SIZE)
|
||||
.spawn(cmd, current_dir, scheme, pty, MAX_PIPE_CHUNK_SIZE)
|
||||
.await?;
|
||||
} else if pty {
|
||||
debug!(
|
||||
|
@ -20,6 +20,7 @@ impl Lsp {
|
||||
self,
|
||||
cmd: impl Into<String>,
|
||||
current_dir: Option<PathBuf>,
|
||||
scheme: Option<String>,
|
||||
pty: bool,
|
||||
max_chunk_size: usize,
|
||||
) -> CliResult {
|
||||
@ -33,6 +34,7 @@ impl Lsp {
|
||||
None
|
||||
})
|
||||
.current_dir(current_dir)
|
||||
.scheme(scheme)
|
||||
.spawn(self.0, &cmd)
|
||||
.await
|
||||
.with_context(|| format!("Failed to spawn {cmd}"))?;
|
||||
|
@ -417,9 +417,12 @@ pub enum ClientSubcommand {
|
||||
network: NetworkSettings,
|
||||
|
||||
/// If specified, will assume the remote process is a LSP server
|
||||
/// and will translate paths that are local into distant:// and vice versa
|
||||
/// and will translate paths that are local into distant:// and vice versa.
|
||||
///
|
||||
/// If a scheme is provided, will translate local paths into that scheme!
|
||||
/// Note that the scheme must be the exact prefix like `distant://`.
|
||||
#[clap(long)]
|
||||
lsp: bool,
|
||||
lsp: Option<Option<String>>,
|
||||
|
||||
/// If specified, will spawn process using a pseudo tty
|
||||
#[clap(long)]
|
||||
@ -1746,7 +1749,7 @@ mod tests {
|
||||
},
|
||||
current_dir: None,
|
||||
environment: map!(),
|
||||
lsp: true,
|
||||
lsp: Some(None),
|
||||
pty: true,
|
||||
cmd: vec![String::from("cmd")],
|
||||
}),
|
||||
@ -1784,7 +1787,7 @@ mod tests {
|
||||
},
|
||||
current_dir: None,
|
||||
environment: map!(),
|
||||
lsp: true,
|
||||
lsp: Some(None),
|
||||
pty: true,
|
||||
cmd: vec![String::from("cmd")],
|
||||
}),
|
||||
@ -1809,7 +1812,7 @@ mod tests {
|
||||
},
|
||||
current_dir: None,
|
||||
environment: map!(),
|
||||
lsp: true,
|
||||
lsp: Some(None),
|
||||
pty: true,
|
||||
cmd: vec![String::from("cmd")],
|
||||
}),
|
||||
@ -1847,7 +1850,7 @@ mod tests {
|
||||
},
|
||||
current_dir: None,
|
||||
environment: map!(),
|
||||
lsp: true,
|
||||
lsp: Some(None),
|
||||
pty: true,
|
||||
cmd: vec![String::from("cmd")],
|
||||
}),
|
||||
|
Loading…
Reference in New Issue
Block a user