Detailed changes
@@ -3158,6 +3158,7 @@ dependencies = [
"go_to_line",
"gpui",
"language",
+ "log",
"menu",
"picker",
"postage",
@@ -3208,6 +3209,7 @@ dependencies = [
"db",
"gpui",
"languages",
+ "log",
"notifications",
"project",
"serde",
@@ -7100,6 +7102,7 @@ dependencies = [
"editor",
"file_icons",
"gpui",
+ "log",
"project",
"schemars",
"serde",
@@ -20,6 +20,7 @@ command_palette_hooks.workspace = true
db.workspace = true
fuzzy.workspace = true
gpui.workspace = true
+log.workspace = true
picker.workspace = true
postage.workspace = true
serde.workspace = true
@@ -67,7 +67,12 @@ impl CommandPaletteDB {
command_name: impl Into<String>,
user_query: impl Into<String>,
) -> Result<()> {
- self.write_command_invocation_internal(command_name.into(), user_query.into())
+ let command_name = command_name.into();
+ let user_query = user_query.into();
+ log::debug!(
+ "Writing command invocation: command_name={command_name}, user_query={user_query}"
+ );
+ self.write_command_invocation_internal(command_name, user_query)
.await
}
@@ -21,6 +21,7 @@ component.workspace = true
gpui.workspace = true
languages.workspace = true
notifications.workspace = true
+log.workspace = true
project.workspace = true
ui.workspace = true
ui_input.workspace = true
@@ -23,6 +23,9 @@ impl ComponentPreviewDb {
workspace_id: WorkspaceId,
active_page_id: String,
) -> Result<()> {
+ log::debug!(
+ "Saving active page: item_id={item_id:?}, workspace_id={workspace_id:?}, active_page_id={active_page_id}"
+ );
let query = "INSERT INTO component_previews(item_id, workspace_id, active_page_id)
VALUES (?1, ?2, ?3)
ON CONFLICT DO UPDATE SET
@@ -18,8 +18,13 @@ impl KeyValueStore {
}
}
+ pub async fn write_kvp(&self, key: String, value: String) -> anyhow::Result<()> {
+ log::debug!("Writing key-value pair for key {key}");
+ self.write_kvp_inner(key, value).await
+ }
+
query! {
- pub async fn write_kvp(key: String, value: String) -> Result<()> {
+ async fn write_kvp_inner(key: String, value: String) -> Result<()> {
INSERT OR REPLACE INTO kv_store(key, value) VALUES ((?), (?))
}
}
@@ -78,8 +83,13 @@ impl GlobalKeyValueStore {
}
}
+ pub async fn write_kvp(&self, key: String, value: String) -> anyhow::Result<()> {
+ log::debug!("Writing global key-value pair for key {key}");
+ self.write_kvp_inner(key, value).await
+ }
+
query! {
- pub async fn write_kvp(key: String, value: String) -> Result<()> {
+ async fn write_kvp_inner(key: String, value: String) -> Result<()> {
INSERT OR REPLACE INTO kv_store(key, value) VALUES ((?), (?))
}
}
@@ -1251,6 +1251,7 @@ impl SerializableItem for Editor {
language,
mtime,
};
+ log::debug!("Serializing editor {item_id:?} in workspace {workspace_id:?}");
DB.save_serialized_editor(item_id, workspace_id, editor)
.await
.context("failed to save serialized editor")
@@ -276,6 +276,7 @@ impl EditorDb {
workspace_id: WorkspaceId,
selections: Vec<(usize, usize)>,
) -> Result<()> {
+ log::debug!("Saving selections for editor {editor_id} in workspace {workspace_id:?}");
let mut first_selection;
let mut last_selection = 0_usize;
for (count, placeholders) in std::iter::once("(?1, ?2, ?, ?)")
@@ -327,6 +328,7 @@ VALUES {placeholders};
workspace_id: WorkspaceId,
folds: Vec<(usize, usize)>,
) -> Result<()> {
+ log::debug!("Saving folds for editor {editor_id} in workspace {workspace_id:?}");
let mut first_fold;
let mut last_fold = 0_usize;
for (count, placeholders) in std::iter::once("(?1, ?2, ?, ?)")
@@ -270,6 +270,9 @@ impl ScrollManager {
cx.foreground_executor()
.spawn(async move {
+ log::debug!(
+ "Saving scroll position for item {item_id:?} in workspace {workspace_id:?}"
+ );
DB.save_scroll_position(
item_id,
workspace_id,
@@ -21,6 +21,7 @@ db.workspace = true
editor.workspace = true
file_icons.workspace = true
gpui.workspace = true
+log.workspace = true
project.workspace = true
schemars.workspace = true
serde.workspace = true
@@ -261,6 +261,7 @@ impl SerializableItem for ImageView {
Some(cx.background_spawn({
async move {
+ log::debug!("Saving image at path {image_path:?}");
IMAGE_VIEWER
.save_image_path(item_id, workspace_id, image_path)
.await
@@ -399,18 +400,6 @@ mod persistence {
}
impl ImageViewerDb {
- query! {
- pub async fn update_workspace_id(
- new_id: WorkspaceId,
- old_id: WorkspaceId,
- item_id: ItemId
- ) -> Result<()> {
- UPDATE image_viewers
- SET workspace_id = ?
- WHERE workspace_id = ? AND item_id = ?
- }
- }
-
query! {
pub async fn save_image_path(
item_id: ItemId,
@@ -1,7 +1,7 @@
use std::time::Duration;
use db::kvp::KEY_VALUE_STORE;
-use gpui::{AnyWindowHandle, AppContext as _, Context, Subscription, Task, WindowId};
+use gpui::{App, AppContext as _, Context, Subscription, Task, WindowId};
use util::ResultExt;
use uuid::Uuid;
@@ -59,7 +59,7 @@ impl Session {
pub struct AppSession {
session: Session,
- _serialization_task: Option<Task<()>>,
+ _serialization_task: Task<()>,
_subscriptions: Vec<Subscription>,
}
@@ -67,17 +67,21 @@ impl AppSession {
pub fn new(session: Session, cx: &Context<Self>) -> Self {
let _subscriptions = vec![cx.on_app_quit(Self::app_will_quit)];
- let _serialization_task = Some(cx.spawn(async move |_, cx| {
+ let _serialization_task = cx.spawn(async move |_, cx| {
+ let mut current_window_stack = Vec::new();
loop {
- if let Some(windows) = cx.update(|cx| cx.window_stack()).ok().flatten() {
- store_window_stack(windows).await;
+ if let Some(windows) = cx.update(|cx| window_stack(cx)).ok().flatten() {
+ if windows != current_window_stack {
+ store_window_stack(&windows).await;
+ current_window_stack = windows;
+ }
}
cx.background_executor()
- .timer(Duration::from_millis(100))
+ .timer(Duration::from_millis(500))
.await;
}
- }));
+ });
Self {
session,
@@ -87,8 +91,8 @@ impl AppSession {
}
fn app_will_quit(&mut self, cx: &mut Context<Self>) -> Task<()> {
- if let Some(windows) = cx.window_stack() {
- cx.background_spawn(store_window_stack(windows))
+ if let Some(window_stack) = window_stack(cx) {
+ cx.background_spawn(async move { store_window_stack(&window_stack).await })
} else {
Task::ready(())
}
@@ -107,13 +111,17 @@ impl AppSession {
}
}
-async fn store_window_stack(windows: Vec<AnyWindowHandle>) {
- let window_ids = windows
- .into_iter()
- .map(|window| window.window_id().as_u64())
- .collect::<Vec<_>>();
+fn window_stack(cx: &App) -> Option<Vec<u64>> {
+ Some(
+ cx.window_stack()?
+ .into_iter()
+ .map(|window| window.window_id().as_u64())
+ .collect(),
+ )
+}
- if let Ok(window_ids_json) = serde_json::to_string(&window_ids) {
+async fn store_window_stack(windows: &[u64]) {
+ if let Ok(window_ids_json) = serde_json::to_string(windows) {
KEY_VALUE_STORE
.write_kvp(SESSION_WINDOW_STACK_KEY.to_string(), window_ids_json)
.await
@@ -429,6 +429,9 @@ impl TerminalDb {
workspace_id: WorkspaceId,
working_directory: PathBuf,
) -> Result<()> {
+ log::debug!(
+ "Saving working directory {working_directory:?} for item {item_id} in workspace {workspace_id:?}"
+ );
let query =
"INSERT INTO terminals(item_id, workspace_id, working_directory, working_directory_path)
VALUES (?1, ?2, ?3, ?4)
@@ -112,6 +112,7 @@ pub struct TerminalView {
cursor_shape: CursorShape,
blink_state: bool,
blinking_terminal_enabled: bool,
+ cwd_serialized: bool,
blinking_paused: bool,
blink_epoch: usize,
hover_target_tooltip: Option<String>,
@@ -207,6 +208,7 @@ impl TerminalView {
scroll_handle,
show_scrollbar: !Self::should_autohide_scrollbar(cx),
hide_scrollbar_task: None,
+ cwd_serialized: false,
_subscriptions: vec![
focus_in,
focus_out,
@@ -843,167 +845,176 @@ fn subscribe_for_terminal_events(
cx: &mut Context<TerminalView>,
) -> Vec<Subscription> {
let terminal_subscription = cx.observe(terminal, |_, _, cx| cx.notify());
+ let mut previous_cwd = None;
let terminal_events_subscription = cx.subscribe_in(
terminal,
window,
- move |terminal_view, _, event, window, cx| match event {
- Event::Wakeup => {
- cx.notify();
- cx.emit(Event::Wakeup);
- cx.emit(ItemEvent::UpdateTab);
- cx.emit(SearchEvent::MatchesInvalidated);
- }
-
- Event::Bell => {
- terminal_view.has_bell = true;
- cx.emit(Event::Wakeup);
+ move |terminal_view, terminal, event, window, cx| {
+ let current_cwd = terminal.read(cx).working_directory();
+ if current_cwd != previous_cwd {
+ previous_cwd = current_cwd;
+ terminal_view.cwd_serialized = false;
}
- Event::BlinkChanged(blinking) => {
- if matches!(
- TerminalSettings::get_global(cx).blinking,
- TerminalBlink::TerminalControlled
- ) {
- terminal_view.blinking_terminal_enabled = *blinking;
+ match event {
+ Event::Wakeup => {
+ cx.notify();
+ cx.emit(Event::Wakeup);
+ cx.emit(ItemEvent::UpdateTab);
+ cx.emit(SearchEvent::MatchesInvalidated);
}
- }
- Event::TitleChanged => {
- cx.emit(ItemEvent::UpdateTab);
- }
+ Event::Bell => {
+ terminal_view.has_bell = true;
+ cx.emit(Event::Wakeup);
+ }
- Event::NewNavigationTarget(maybe_navigation_target) => {
- match maybe_navigation_target.as_ref() {
- None => {
- terminal_view.hover_target_tooltip = None;
- terminal_view.hover_tooltip_update = Task::ready(());
- }
- Some(MaybeNavigationTarget::Url(url)) => {
- terminal_view.hover_target_tooltip = Some(url.clone());
- terminal_view.hover_tooltip_update = Task::ready(());
- }
- Some(MaybeNavigationTarget::PathLike(path_like_target)) => {
- let valid_files_to_open_task = possible_open_target(
- &workspace,
- &path_like_target.terminal_dir,
- &path_like_target.maybe_path,
- cx,
- );
-
- terminal_view.hover_tooltip_update =
- cx.spawn(async move |terminal_view, cx| {
- let file_to_open = valid_files_to_open_task.await;
- terminal_view
- .update(cx, |terminal_view, _| match file_to_open {
- Some(
- OpenTarget::File(path, _)
- | OpenTarget::Worktree(path, _),
- ) => {
- terminal_view.hover_target_tooltip =
- Some(path.to_string(|path| {
- path.to_string_lossy().to_string()
- }));
- }
- None => {
- terminal_view.hover_target_tooltip = None;
- }
- })
- .ok();
- });
+ Event::BlinkChanged(blinking) => {
+ if matches!(
+ TerminalSettings::get_global(cx).blinking,
+ TerminalBlink::TerminalControlled
+ ) {
+ terminal_view.blinking_terminal_enabled = *blinking;
}
}
- cx.notify()
- }
-
- Event::Open(maybe_navigation_target) => match maybe_navigation_target {
- MaybeNavigationTarget::Url(url) => cx.open_url(url),
+ Event::TitleChanged => {
+ cx.emit(ItemEvent::UpdateTab);
+ }
- MaybeNavigationTarget::PathLike(path_like_target) => {
- if terminal_view.hover_target_tooltip.is_none() {
- return;
+ Event::NewNavigationTarget(maybe_navigation_target) => {
+ match maybe_navigation_target.as_ref() {
+ None => {
+ terminal_view.hover_target_tooltip = None;
+ terminal_view.hover_tooltip_update = Task::ready(());
+ }
+ Some(MaybeNavigationTarget::Url(url)) => {
+ terminal_view.hover_target_tooltip = Some(url.clone());
+ terminal_view.hover_tooltip_update = Task::ready(());
+ }
+ Some(MaybeNavigationTarget::PathLike(path_like_target)) => {
+ let valid_files_to_open_task = possible_open_target(
+ &workspace,
+ &path_like_target.terminal_dir,
+ &path_like_target.maybe_path,
+ cx,
+ );
+
+ terminal_view.hover_tooltip_update =
+ cx.spawn(async move |terminal_view, cx| {
+ let file_to_open = valid_files_to_open_task.await;
+ terminal_view
+ .update(cx, |terminal_view, _| match file_to_open {
+ Some(
+ OpenTarget::File(path, _)
+ | OpenTarget::Worktree(path, _),
+ ) => {
+ terminal_view.hover_target_tooltip =
+ Some(path.to_string(|path| {
+ path.to_string_lossy().to_string()
+ }));
+ }
+ None => {
+ terminal_view.hover_target_tooltip = None;
+ }
+ })
+ .ok();
+ });
+ }
}
- let task_workspace = workspace.clone();
- let path_like_target = path_like_target.clone();
- cx.spawn_in(window, async move |terminal_view, cx| {
- let open_target = terminal_view
- .update(cx, |_, cx| {
- possible_open_target(
- &task_workspace,
- &path_like_target.terminal_dir,
- &path_like_target.maybe_path,
- cx,
- )
- })?
- .await;
- if let Some(open_target) = open_target {
- let path_to_open = open_target.path();
- let opened_items = task_workspace
- .update_in(cx, |workspace, window, cx| {
- workspace.open_paths(
- vec![path_to_open.path.clone()],
- OpenOptions {
- visible: Some(OpenVisible::OnlyDirectories),
- ..Default::default()
- },
- None,
- window,
+
+ cx.notify()
+ }
+
+ Event::Open(maybe_navigation_target) => match maybe_navigation_target {
+ MaybeNavigationTarget::Url(url) => cx.open_url(url),
+
+ MaybeNavigationTarget::PathLike(path_like_target) => {
+ if terminal_view.hover_target_tooltip.is_none() {
+ return;
+ }
+ let task_workspace = workspace.clone();
+ let path_like_target = path_like_target.clone();
+ cx.spawn_in(window, async move |terminal_view, cx| {
+ let open_target = terminal_view
+ .update(cx, |_, cx| {
+ possible_open_target(
+ &task_workspace,
+ &path_like_target.terminal_dir,
+ &path_like_target.maybe_path,
cx,
)
- })
- .context("workspace update")?
+ })?
.await;
- if opened_items.len() != 1 {
- debug_panic!(
- "Received {} items for one path {path_to_open:?}",
- opened_items.len(),
- );
- }
+ if let Some(open_target) = open_target {
+ let path_to_open = open_target.path();
+ let opened_items = task_workspace
+ .update_in(cx, |workspace, window, cx| {
+ workspace.open_paths(
+ vec![path_to_open.path.clone()],
+ OpenOptions {
+ visible: Some(OpenVisible::OnlyDirectories),
+ ..Default::default()
+ },
+ None,
+ window,
+ cx,
+ )
+ })
+ .context("workspace update")?
+ .await;
+ if opened_items.len() != 1 {
+ debug_panic!(
+ "Received {} items for one path {path_to_open:?}",
+ opened_items.len(),
+ );
+ }
- if let Some(opened_item) = opened_items.first() {
- if open_target.is_file() {
- if let Some(Ok(opened_item)) = opened_item {
- if let Some(row) = path_to_open.row {
- let col = path_to_open.column.unwrap_or(0);
- if let Some(active_editor) =
- opened_item.downcast::<Editor>()
- {
- active_editor
- .downgrade()
- .update_in(cx, |editor, window, cx| {
- editor.go_to_singleton_buffer_point(
- language::Point::new(
- row.saturating_sub(1),
- col.saturating_sub(1),
- ),
- window,
- cx,
- )
- })
- .log_err();
+ if let Some(opened_item) = opened_items.first() {
+ if open_target.is_file() {
+ if let Some(Ok(opened_item)) = opened_item {
+ if let Some(row) = path_to_open.row {
+ let col = path_to_open.column.unwrap_or(0);
+ if let Some(active_editor) =
+ opened_item.downcast::<Editor>()
+ {
+ active_editor
+ .downgrade()
+ .update_in(cx, |editor, window, cx| {
+ editor.go_to_singleton_buffer_point(
+ language::Point::new(
+ row.saturating_sub(1),
+ col.saturating_sub(1),
+ ),
+ window,
+ cx,
+ )
+ })
+ .log_err();
+ }
}
}
+ } else if open_target.is_dir() {
+ task_workspace.update(cx, |workspace, cx| {
+ workspace.project().update(cx, |_, cx| {
+ cx.emit(project::Event::ActivateProjectPanel);
+ })
+ })?;
}
- } else if open_target.is_dir() {
- task_workspace.update(cx, |workspace, cx| {
- workspace.project().update(cx, |_, cx| {
- cx.emit(project::Event::ActivateProjectPanel);
- })
- })?;
}
}
- }
- anyhow::Ok(())
- })
- .detach_and_log_err(cx)
+ anyhow::Ok(())
+ })
+ .detach_and_log_err(cx)
+ }
+ },
+ Event::BreadcrumbsChanged => cx.emit(ItemEvent::UpdateBreadcrumbs),
+ Event::CloseTerminal => cx.emit(ItemEvent::CloseItem),
+ Event::SelectionsChanged => {
+ window.invalidate_character_coordinates();
+ cx.emit(SearchEvent::ActiveMatchChanged)
}
- },
- Event::BreadcrumbsChanged => cx.emit(ItemEvent::UpdateBreadcrumbs),
- Event::CloseTerminal => cx.emit(ItemEvent::CloseItem),
- Event::SelectionsChanged => {
- window.invalidate_character_coordinates();
- cx.emit(SearchEvent::ActiveMatchChanged)
}
},
);
@@ -1539,6 +1550,9 @@ impl Item for TerminalView {
) {
if self.terminal().read(cx).task().is_none() {
if let Some((new_id, old_id)) = workspace.database_id().zip(self.workspace_id) {
+ log::debug!(
+ "Updating workspace id for the terminal, old: {old_id:?}, new: {new_id:?}",
+ );
cx.background_spawn(TERMINAL_DB.update_workspace_id(
new_id,
old_id,
@@ -1587,6 +1601,7 @@ impl SerializableItem for TerminalView {
}
if let Some((cwd, workspace_id)) = terminal.working_directory().zip(self.workspace_id) {
+ self.cwd_serialized = true;
Some(cx.background_spawn(async move {
TERMINAL_DB
.save_working_directory(item_id, workspace_id, cwd)
@@ -1597,8 +1612,8 @@ impl SerializableItem for TerminalView {
}
}
- fn should_serialize(&self, event: &Self::Event) -> bool {
- matches!(event, ItemEvent::UpdateTab)
+ fn should_serialize(&self, _: &Self::Event) -> bool {
+ !self.cwd_serialized
}
fn deserialize(
@@ -1644,6 +1644,7 @@ impl VimDb {
path: Arc<Path>,
marks: HashMap<String, Vec<Point>>,
) -> Result<()> {
+ log::debug!("Setting path {path:?} for {} marks", marks.len());
let result = self
.write(move |conn| {
let mut query = conn.exec_bound(sql!(
@@ -1694,6 +1695,7 @@ impl VimDb {
mark_name: String,
path: Arc<Path>,
) -> Result<()> {
+ log::debug!("Setting global mark path {path:?} for {mark_name}");
self.write(move |conn| {
conn.exec_bound(sql!(
INSERT OR REPLACE INTO vim_global_marks_paths
@@ -739,6 +739,7 @@ impl WorkspaceDb {
/// Saves a workspace using the worktree roots. Will garbage collect any workspaces
/// that used this workspace previously
pub(crate) async fn save_workspace(&self, workspace: SerializedWorkspace) {
+ log::debug!("Saving workspace at location: {:?}", workspace.location);
self.write(move |conn| {
conn.with_savepoint("update_worktrees", || {
// Clear out panes and pane_groups
@@ -909,6 +910,7 @@ impl WorkspaceDb {
{
Ok(project)
} else {
+ log::debug!("Inserting SSH project at host {host}");
self.insert_ssh_project(host, port, paths, user)
.await?
.ok_or_else(|| anyhow!("failed to insert ssh project"))
@@ -1209,6 +1211,9 @@ impl WorkspaceDb {
pane_group: &SerializedPaneGroup,
parent: Option<(GroupId, usize)>,
) -> Result<()> {
+ if parent.is_none() {
+ log::debug!("Saving a pane group for workspace {workspace_id:?}");
+ }
match pane_group {
SerializedPaneGroup::Group {
axis,
@@ -1387,6 +1392,10 @@ impl WorkspaceDb {
relative_worktree_path: String,
toolchain: Toolchain,
) -> Result<()> {
+ log::debug!(
+ "Setting toolchain for workspace, worktree: {worktree_id:?}, relative path: {relative_worktree_path:?}, toolchain: {}",
+ toolchain.name
+ );
self.write(move |conn| {
let mut insert = conn
.exec_bound(sql!(