1
1
mirror of https://github.com/wez/wezterm.git synced 2024-12-23 13:21:38 +03:00

track the full current dir URL for OSC 7

Matching against the current dir when it includes a host and a
path seems like a handy way to automate selecting appropriate
theme/color/profile settings, so I'd like to make sure that
we have the full URL content available for that.

Refs: https://github.com/wez/wezterm/issues/115
Refs: https://github.com/wez/wezterm/issues/117
This commit is contained in:
Wez Furlong 2020-01-14 22:06:13 -08:00
parent 18bbd2ac6f
commit 4b455288dd
11 changed files with 106 additions and 41 deletions

1
Cargo.lock generated
View File

@ -2875,6 +2875,7 @@ dependencies = [
"unicode-normalization 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-segmentation 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-width 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
"url 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"varbincode 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"vergen 3.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
"walkdir 2.2.9 (registry+https://github.com/rust-lang/crates.io-index)",

View File

@ -56,6 +56,7 @@ toml = "0.4"
unicode-normalization = "0.1"
unicode-segmentation = "1.5"
unicode-width = "0.1"
url = "2"
varbincode = "0.1"
walkdir = "2"
window = { path = "window", features=["opengl", "wayland"]}

View File

@ -1065,6 +1065,10 @@ impl TermWindow {
None,
),
};
let cwd = match cwd {
Some(url) if url.scheme() == "file" => Some(url.path().to_string()),
Some(_) | None => None,
};
let tab = domain.spawn(size, None, cwd, self.mux_window_id)?;
let tab_id = tab.tab_id();

View File

@ -7,6 +7,7 @@ use std::cell::{RefCell, RefMut};
use std::sync::Arc;
use term::color::ColorPalette;
use term::{Clipboard, KeyCode, KeyModifiers, MouseEvent, Terminal, TerminalHost};
use url::Url;
pub struct LocalTab {
tab_id: TabId,
@ -94,8 +95,8 @@ impl Tab for LocalTab {
self.terminal.borrow().is_mouse_grabbed()
}
fn get_current_working_dir(&self) -> Option<String> {
self.terminal.borrow().get_current_dir().map(String::from)
fn get_current_working_dir(&self) -> Option<Url> {
self.terminal.borrow().get_current_dir().cloned()
}
}

View File

@ -8,6 +8,7 @@ use std::cell::RefMut;
use std::sync::{Arc, Mutex};
use term::color::ColorPalette;
use term::{Clipboard, KeyCode, KeyModifiers, MouseEvent, TerminalHost};
use url::Url;
static TAB_ID: ::std::sync::atomic::AtomicUsize = ::std::sync::atomic::AtomicUsize::new(0);
pub type TabId = usize;
@ -69,7 +70,7 @@ pub trait Tab: Downcast {
fn set_clipboard(&self, _clipboard: &Arc<dyn Clipboard>) {}
fn get_current_working_dir(&self) -> Option<String>;
fn get_current_working_dir(&self) -> Option<Url>;
fn trickle_paste(&self, text: String) -> anyhow::Result<()> {
if text.len() <= PASTE_CHUNK_SIZE {

View File

@ -117,6 +117,7 @@ fn client_thread(
let mut next_serial = 1u64;
let mut promises = HashMap::new();
let mut read_buffer = Vec::with_capacity(1024);
loop {
loop {
match rx.try_recv() {
@ -131,7 +132,13 @@ fn client_thread(
}
},
Err(TryRecvError::Empty) => break,
Err(TryRecvError::Disconnected) => bail!("Client was destroyed"),
Err(TryRecvError::Disconnected) => {
for (_, mut promise) in promises.into_iter() {
promise.result(Err(anyhow!("Client was destroyed")));
}
log::error!("Client Disconnected");
bail!("Client was destroyed");
}
};
}
@ -149,20 +156,33 @@ fn client_thread(
reconnectable.stream().set_non_blocking(true)?;
let res = Pdu::try_read_and_decode(reconnectable.stream(), &mut read_buffer);
reconnectable.stream().set_non_blocking(false)?;
if let Some(decoded) = res? {
log::trace!("decoded serial {}", decoded.serial);
if decoded.serial == 0 {
process_unilateral(local_domain_id, decoded)?;
} else if let Some(mut promise) = promises.remove(&decoded.serial) {
promise.result(Ok(decoded.pdu));
} else {
log::error!(
"got serial {} without a corresponding promise",
decoded.serial
);
match res {
Ok(None) => {
/* no data available right now; try again later! */
break;
}
Ok(Some(decoded)) => {
log::trace!("decoded serial {}", decoded.serial);
if decoded.serial == 0 {
process_unilateral(local_domain_id, decoded)?;
} else if let Some(mut promise) = promises.remove(&decoded.serial) {
promise.result(Ok(decoded.pdu));
} else {
log::error!(
"got serial {} without a corresponding promise",
decoded.serial
);
}
break;
}
Err(err) => {
let reason = format!("Error while decoding response pdu: {}", err);
log::error!("{}", reason);
for (_, mut promise) in promises.into_iter() {
promise.result(Err(anyhow!("{}", reason)));
}
bail!(reason);
}
} else {
break;
}
}
}
@ -547,6 +567,9 @@ impl Client {
}
}
}
} else {
log::error!("client_thread returned without any error condition");
break;
}
}
Future::with_executor(executor(), move || {

View File

@ -27,6 +27,7 @@ use std::sync::Arc;
use term::StableRowIndex;
use termwiz::hyperlink::Hyperlink;
use termwiz::surface::Line;
use url::Url;
use varbincode;
/// Returns the encoded length of the leb128 representation of value
@ -237,7 +238,7 @@ macro_rules! pdu {
/// The overall version of the codec.
/// This must be bumped when backwards incompatible changes
/// are made to the types and protocol.
pub const CODEC_VERSION: usize = 1;
pub const CODEC_VERSION: usize = 2;
// Defines the Pdu enum.
// Each struct has an explicit identifying number.
@ -365,13 +366,45 @@ pub struct Pong {}
#[derive(Deserialize, Serialize, PartialEq, Debug)]
pub struct ListTabs {}
#[derive(Deserialize, Clone, Serialize, PartialEq, Debug)]
#[serde(try_from = "String", into = "String")]
pub struct SerdeUrl {
pub url: Url,
}
impl std::convert::TryFrom<String> for SerdeUrl {
type Error = url::ParseError;
fn try_from(s: String) -> Result<SerdeUrl, url::ParseError> {
let url = Url::parse(&s)?;
Ok(SerdeUrl { url })
}
}
impl From<Url> for SerdeUrl {
fn from(url: Url) -> SerdeUrl {
SerdeUrl { url }
}
}
impl Into<Url> for SerdeUrl {
fn into(self) -> Url {
self.url
}
}
impl Into<String> for SerdeUrl {
fn into(self) -> String {
self.url.as_str().into()
}
}
#[derive(Deserialize, Serialize, PartialEq, Debug)]
pub struct WindowAndTabEntry {
pub window_id: WindowId,
pub tab_id: TabId,
pub title: String,
pub size: PtySize,
pub working_dir: Option<String>,
pub working_dir: Option<SerdeUrl>,
}
#[derive(Deserialize, Serialize, PartialEq, Debug)]
@ -444,7 +477,7 @@ pub struct GetTabRenderChangesResponse {
pub dimensions: RenderableDimensions,
pub dirty_lines: Vec<Range<StableRowIndex>>,
pub title: String,
pub working_dir: Option<String>,
pub working_dir: Option<SerdeUrl>,
/// Lines that the server thought we'd almost certainly
/// want to fetch as soon as we received this response
pub bonus_lines: SerializedLines,

View File

@ -28,6 +28,7 @@ use std::thread;
use std::time::Instant;
use term::terminal::Clipboard;
use term::StableRowIndex;
use url::Url;
struct LocalListener {
listener: UnixListener,
@ -386,7 +387,7 @@ pub struct ClientSession<S: ReadAndWrite> {
struct PerTab {
cursor_position: StableCursorPosition,
title: String,
working_dir: Option<String>,
working_dir: Option<Url>,
dimensions: RenderableDimensions,
dirty_lines: RangeSet<StableRowIndex>,
mouse_grabbed: bool,
@ -471,7 +472,7 @@ impl PerTab {
cursor_position,
title,
bonus_lines,
working_dir,
working_dir: working_dir.map(Into::into),
})
}
@ -620,17 +621,20 @@ impl<S: ReadAndWrite> ClientSession<S> {
self.stream.set_non_blocking(true)?;
let res = Pdu::try_read_and_decode(&mut self.stream, &mut read_buffer);
self.stream.set_non_blocking(false)?;
if let Some(decoded) = res? {
self.process_one(decoded)?;
} else {
break;
match res {
Ok(Some(decoded)) => self.process_one(decoded),
Ok(None) => break,
Err(err) => {
log::error!("Error decoding: {}", err);
return Err(err);
}
}
}
}
}
}
fn process_one(&mut self, decoded: DecodedPdu) -> anyhow::Result<()> {
fn process_one(&mut self, decoded: DecodedPdu) {
let start = Instant::now();
let sender = self.to_write_tx.clone();
let serial = decoded.serial;
@ -644,7 +648,6 @@ impl<S: ReadAndWrite> ClientSession<S> {
log::trace!("{} processing time {:?}", serial, start.elapsed());
sender.send(DecodedPdu { pdu, serial })
});
Ok(())
}
fn process_pdu(&mut self, pdu: Pdu) -> Future<Pdu> {
@ -668,7 +671,7 @@ impl<S: ReadAndWrite> ClientSession<S> {
pixel_height: 0,
pixel_width: 0,
},
working_dir,
working_dir: working_dir.map(Into::into),
});
}
}

View File

@ -28,6 +28,7 @@ use term::{
StableRowIndex, TerminalHost,
};
use termwiz::input::KeyEvent;
use url::Url;
struct MouseState {
future: Option<Future<()>>,
@ -319,7 +320,7 @@ impl Tab for ClientTab {
*self.mouse_grabbed.borrow()
}
fn get_current_working_dir(&self) -> Option<String> {
fn get_current_working_dir(&self) -> Option<Url> {
self.renderable.borrow().inner.borrow().working_dir.clone()
}
}
@ -367,7 +368,7 @@ struct RenderableInner {
lines: LruCache<StableRowIndex, LineEntry>,
title: String,
working_dir: Option<String>,
working_dir: Option<Url>,
fetch_limiter: RateLimiter,
}
@ -397,7 +398,7 @@ impl RenderableInner {
self.cursor_position = delta.cursor_position;
self.dimensions = delta.dimensions;
self.title = delta.title;
self.working_dir = delta.working_dir;
self.working_dir = delta.working_dir.map(Into::into);
let config = configuration();
for (stable_row, line) in delta.bonus_lines.lines() {

View File

@ -31,6 +31,7 @@ use termwiz::input::{InputEvent, KeyEvent};
use termwiz::lineedit::*;
use termwiz::surface::{Change, SequenceNo, Surface};
use termwiz::terminal::{ScreenSize, Terminal, TerminalWaker};
use url::Url;
struct RenderableInner {
surface: Surface,
@ -286,7 +287,7 @@ impl Tab for TermWizTerminalTab {
true
}
fn get_current_working_dir(&self) -> Option<String> {
fn get_current_working_dir(&self) -> Option<Url> {
None
}
}

View File

@ -219,7 +219,7 @@ pub struct TerminalState {
clipboard: Option<Arc<dyn Clipboard>>,
current_dir: Option<String>,
current_dir: Option<Url>,
}
fn encode_modifiers(mods: KeyModifiers) -> u8 {
@ -300,8 +300,8 @@ impl TerminalState {
&self.title
}
pub fn get_current_dir(&self) -> Option<&str> {
self.current_dir.as_ref().map(String::as_str)
pub fn get_current_dir(&self) -> Option<&Url> {
self.current_dir.as_ref()
}
/// Returns a copy of the palette.
@ -1724,11 +1724,7 @@ impl<'a> Performer<'a> {
error!("Application sends SystemNotification: {}", message);
}
OperatingSystemCommand::CurrentWorkingDirectory(url) => {
let dir = match Url::parse(&url) {
Ok(url) if url.scheme() == "file" => Some(url.path().to_string()),
Ok(_) | Err(_) => None,
};
self.current_dir = dir;
self.current_dir = Url::parse(&url).ok();
}
OperatingSystemCommand::ChangeColorNumber(specs) => {
error!("ChangeColorNumber: {:?}", specs);