Compare commits

...

1 Commits

Author SHA1 Message Date
Conrad Irwin
d8d8f90893 vim-global 2025-01-31 12:59:24 -07:00
6 changed files with 119 additions and 9 deletions

1
Cargo.lock generated
View File

@@ -14538,6 +14538,7 @@ dependencies = [
"collections",
"command_palette",
"command_palette_hooks",
"db",
"editor",
"futures 0.3.31",
"git_ui",

View File

@@ -22,6 +22,7 @@ async-trait = { workspace = true, "optional" = true }
collections.workspace = true
command_palette.workspace = true
command_palette_hooks.workspace = true
db.workspace = true
editor.workspace = true
futures.workspace = true
gpui.workspace = true

View File

@@ -33,7 +33,7 @@ impl Vim {
}) else {
return;
};
self.marks.insert(text.to_string(), anchors);
self.set_mark(text.to_string(), anchors);
self.clear_operator(window, cx);
}
@@ -71,8 +71,8 @@ impl Vim {
}
});
self.marks.insert("<".to_string(), starts);
self.marks.insert(">".to_string(), ends);
self.set_mark("<".to_string(), starts);
self.set_mark(">".to_string(), ends);
self.stored_visual_mode.replace((mode, reversed));
}

View File

@@ -131,14 +131,14 @@ impl Vim {
let mut clipboard_selections = Vec::with_capacity(selections.len());
let mut ranges_to_highlight = Vec::new();
self.marks.insert(
self.set_mark(
"[".to_string(),
selections
.iter()
.map(|s| buffer.anchor_before(s.start))
.collect(),
);
self.marks.insert(
self.set_mark(
"]".to_string(),
selections
.iter()

View File

@@ -5,18 +5,25 @@ use crate::{motion::Motion, object::Object};
use crate::{UseSystemClipboard, Vim, VimSettings};
use collections::HashMap;
use command_palette_hooks::{CommandPaletteFilter, CommandPaletteInterceptor};
use db::sqlez_macros::sql;
use db::{define_connection, query};
use editor::{Anchor, ClipboardSelection, Editor};
use gpui::{
Action, App, BorrowAppContext, ClipboardEntry, ClipboardItem, Entity, Global, WeakEntity,
};
use language::Point;
use language::{BufferId, Point};
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use settings::{Settings, SettingsStore};
use std::borrow::BorrowMut;
use std::ffi::OsString;
use std::os::unix::ffi::OsStringExt;
use std::path::{Path, PathBuf};
use std::{fmt::Display, ops::Range, sync::Arc};
use ui::{Context, SharedString};
use util::ResultExt;
use workspace::searchable::Direction;
use workspace::{Workspace, WorkspaceDb, WorkspaceId};
#[derive(Clone, Copy, Debug, PartialEq, Eq, Deserialize, JsonSchema, Serialize)]
pub enum Mode {
@@ -172,7 +179,7 @@ impl From<String> for Register {
}
}
#[derive(Default, Clone)]
#[derive(Default)]
pub struct VimGlobals {
pub last_find: Option<Motion>,
@@ -201,6 +208,15 @@ pub struct VimGlobals {
pub recordings: HashMap<char, Vec<ReplayableAction>>,
pub focused_vim: Option<WeakEntity<Vim>>,
pub local_marks: HashMap<(WorkspaceId, Arc<Path>), HashMap<String, Vec<Point>>>,
}
// when you open a buffer, read from the local marks and convert to anchor
// when you create a mark, or edit a buffer such that an anchor's point changes, write that to the database
pub struct MarksCollection {
pub local_loaded: HashMap<BufferId, HashMap<String, Vec<Anchor>>>, // keep this type on non-global-vim
pub local: HashMap<Arc<Path>, HashMap<String, Vec<Point>>>,
}
impl Global for VimGlobals {}
@@ -235,6 +251,22 @@ impl VimGlobals {
}
})
.detach();
cx.observe_new(|workspace: &mut Workspace, _, cx| {
let Some(workspace_id) = workspace.database_id() else {
return;
};
cx.spawn(|this, mut cx| async move {
let marks = cx
.background_executor()
.spawn(async move { DB.get_local_marks(workspace_id) })
.await?;
cx.update_global(|g: &mut VimGlobals, cx: &mut App| {
g.load_local_marks(workspace_id, marks, cx)
})
})
.detach_and_log_err(cx)
})
.detach()
}
pub(crate) fn write_registers(
@@ -362,6 +394,29 @@ impl VimGlobals {
}
}
fn load_local_marks(
&mut self,
workspace_id: WorkspaceId,
marks: Vec<(Vec<u8>, String, String)>,
cx: &mut App,
) {
for (abs_path, name, values) in marks {
let Some(value) = serde_json::from_str::<Vec<(u32, u32)>>(&values).log_err() else {
continue;
};
let path = PathBuf::from(OsString::from_vec(abs_path));
let mut marks = self
.local_marks
.entry((workspace_id, Arc::from(path)))
.or_default();
let points = value
.into_iter()
.map(|(row, col)| Point::new(row, col))
.collect();
marks.insert(name, points);
}
}
fn system_clipboard_is_newer(&self, cx: &mut Context<Editor>) -> bool {
cx.read_from_clipboard().is_some_and(|item| {
if let Some(last_state) = &self.last_yank {
@@ -558,3 +613,45 @@ impl Operator {
}
}
}
define_connection! {
pub static ref DB: VimDb<WorkspaceDb> = &[
sql! (
CREATE TABLE vim_local_marks(
workspace_id INTEGER,
mark_name TEXT,
absolute_path BLOB,
value TEXT
);
CREATE UNIQUE INDEX idx_vim_local_marks
ON vim_local_marks (workspace_id, mark_name, absolute_path);
),
sql! (
CREATE TABLE vim_global_marks(
workspace_id INTEGER,
mark_name TEXT,
absolute_path BLOB,
value TEXT
);
CREATE UNIQUE INDEX idx_vim_global_marks
ON vim_global_marks (workspace_id, mark_name);
),
];
}
impl VimDb {
query! {
pub fn set_local_mark(workspace_id: WorkspaceId, mark_name: String, absolute_path: Vec<u8>, value: String) -> Result<Vec<(PathBuf, bool)>> {
INSERT OR REPLACE INTO vim_local_marks (workspace_id, mark_name, absolute_path, value)
VALUES (?, ?, ?, ?)
}
}
query! {
pub fn get_local_marks(workspace_id: WorkspaceId) -> Result<Vec<(Vec<u8>, String, String)>> {
SELECT absolute_path, mark_name, value FROM vim_local_marks
WHERE workspace_id = ?
}
}
}

View File

@@ -23,7 +23,7 @@ use anyhow::Result;
use collections::HashMap;
use editor::{
movement::{self, FindRange},
Anchor, Bias, Editor, EditorEvent, EditorMode, ToPoint,
Anchor, Bias, Editor, EditorEvent, EditorMode, MultiBuffer, ToPoint,
};
use gpui::{
actions, impl_actions, Action, App, AppContext as _, Axis, Context, Entity, EventEmitter,
@@ -38,7 +38,7 @@ use schemars::JsonSchema;
use serde::Deserialize;
use serde_derive::Serialize;
use settings::{update_settings_file, Settings, SettingsSources, SettingsStore};
use state::{Mode, Operator, RecordedSelection, SearchState, VimGlobals};
use state::{Mode, Operator, RecordedSelection, SearchState, VimDb, VimGlobals};
use std::{mem, ops::Range, sync::Arc};
use surrounds::SurroundsType;
use theme::ThemeSettings;
@@ -457,6 +457,17 @@ impl Vim {
}
}
fn set_mark(&mut self, name: String, positions: Vec<Anchor>) {
match name.to_string() {
m if m.starts_with(|c: char| c.is_uppercase()) => {
// VimGlobals::set_mark(m, positions);
} // global mark
m => {
let _ = self.marks.insert(m, positions);
} // local mark
};
}
fn handle_editor_event(
&mut self,
event: &EditorEvent,