add support for scratch buffer

This commit is contained in:
Dongdong Zhou 2022-05-11 21:12:12 +01:00
parent c404f7194f
commit 3b772bfe2d
16 changed files with 427 additions and 88 deletions

View File

@ -234,11 +234,17 @@ pub fn init_content(&mut self, content: Rope) {
self.set_pristine();
}
pub fn reload(&mut self, content: Rope) -> (RopeDelta, InvalLines) {
pub fn reload(
&mut self,
content: Rope,
set_prisitine: bool,
) -> (RopeDelta, InvalLines) {
let delta = LineHashDiff::compute_delta(&self.text, &content);
self.this_edit_type = EditType::Other;
let (delta, inval_lines) = self.add_delta(delta);
self.set_pristine();
if set_prisitine {
self.set_pristine();
}
(delta, inval_lines)
}

View File

@ -23,6 +23,7 @@
use crate::alert::AlertContentData;
use crate::data::LapceWorkspace;
use crate::document::BufferContent;
use crate::rich_text::RichText;
use crate::{
data::{EditorTabChild, SplitContent},
@ -240,6 +241,10 @@ pub enum LapceWorkbenchCommand {
#[strum(serialize = "new_window")]
NewWindow,
#[strum(message = "New File")]
#[strum(serialize = "new_file")]
NewFile,
#[strum(serialize = "connect_ssh_host")]
#[strum(message = "Connect to SSH Host")]
ConnectSshHost,
@ -469,6 +474,8 @@ pub enum LapceUICommand {
Scroll((f64, f64)),
ScrollTo((f64, f64)),
ForceScrollTo(f64, f64),
SaveAs(BufferContent, PathBuf, WidgetId, bool),
SaveAsSuccess(BufferContent, u64, PathBuf, WidgetId, bool),
HomeDir(PathBuf),
FileChange(notify::Event),
ProxyUpdateStatus(ProxyStatus),

View File

@ -10,8 +10,7 @@
use anyhow::Result;
use crossbeam_channel::{unbounded, Receiver, Sender};
use druid::{
piet::{PietText, PietTextLayout, Text, TextLayout, TextLayoutBuilder},
theme, Command, Data, Env, EventCtx, ExtEventSink, FontFamily, Lens, Point,
piet::PietText, theme, Command, Data, Env, EventCtx, ExtEventSink, Lens, Point,
Rect, Size, Target, Vec2, WidgetId, WindowId,
};
@ -25,11 +24,10 @@
selection::Selection,
};
use lapce_rpc::{
plugin::PluginDescription, source_control::FileDiff, terminal::TermId,
};
use lsp_types::{
CodeActionOrCommand, Diagnostic, Position, ProgressToken, TextEdit,
buffer::BufferId, plugin::PluginDescription, source_control::FileDiff,
terminal::TermId,
};
use lsp_types::{Diagnostic, Position, ProgressToken, TextEdit};
use notify::Watcher;
use serde::{Deserialize, Serialize};
use serde_json::Value;
@ -707,6 +705,9 @@ pub fn editor_view_content(
BufferContent::File(path) => {
self.main_split.open_docs.get(path).unwrap().clone()
}
BufferContent::Scratch(id) => {
self.main_split.scratch_docs.get(id).unwrap().clone()
}
BufferContent::Local(kind) => {
self.main_split.local_docs.get(kind).unwrap().clone()
}
@ -742,39 +743,12 @@ pub fn code_action_size(&self, text: &mut PietText, _env: &Env) -> Size {
BufferContent::File(path) => {
let doc = self.main_split.open_docs.get(path).unwrap();
let offset = editor.new_cursor.offset();
let prev_offset = doc.buffer().prev_code_boundary(offset);
let empty_vec = Vec::new();
let code_actions =
doc.code_actions.get(&prev_offset).unwrap_or(&empty_vec);
let action_text_layouts: Vec<PietTextLayout> = code_actions
.iter()
.map(|code_action| {
let title = match code_action {
CodeActionOrCommand::Command(cmd) => {
cmd.title.to_string()
}
CodeActionOrCommand::CodeAction(action) => {
action.title.to_string()
}
};
text.new_text_layout(title)
.font(FontFamily::SYSTEM_UI, 14.0)
.build()
.unwrap()
})
.collect();
let mut width = 0.0;
for text_layout in &action_text_layouts {
let line_width = text_layout.size().width + 10.0;
if line_width > width {
width = line_width;
}
}
let line_height = self.config.editor.line_height as f64;
Size::new(width, code_actions.len() as f64 * line_height)
doc.code_action_size(text, offset, &self.config)
}
BufferContent::Scratch(id) => {
let doc = self.main_split.scratch_docs.get(id).unwrap();
let offset = editor.new_cursor.offset();
doc.code_action_size(text, offset, &self.config)
}
}
}
@ -810,6 +784,11 @@ pub fn update_from_editor_buffer_data(
.open_docs
.insert(path.clone(), editor_buffer_data.doc);
}
BufferContent::Scratch(id) => {
self.main_split
.scratch_docs
.insert(*id, editor_buffer_data.doc);
}
BufferContent::Local(kind) => {
self.main_split
.local_docs
@ -846,8 +825,8 @@ pub fn code_action_origin(
*editor.window_origin.borrow()
- self.window_origin.borrow().to_vec2()
}
BufferContent::File(path) => {
let doc = self.main_split.open_docs.get(path).unwrap();
BufferContent::File(_) | BufferContent::Scratch(_) => {
let doc = self.main_split.editor_doc(editor.view_id);
let offset = editor.new_cursor.offset();
let (line, col) = doc.buffer().offset_to_line_col(offset);
let width = config.editor_char_width(text);
@ -884,8 +863,8 @@ pub fn completion_origin(
*editor.window_origin.borrow()
- self.window_origin.borrow().to_vec2()
}
BufferContent::File(path) => {
let doc = self.main_split.open_docs.get(path).unwrap();
BufferContent::File(_) | BufferContent::Scratch(_) => {
let doc = self.main_split.editor_doc(editor.view_id);
let offset = self.completion.offset;
let (line, col) = doc.buffer().offset_to_line_col(offset);
let width = config.editor_char_width(text);
@ -940,8 +919,8 @@ pub fn hover_origin(
*editor.window_origin.borrow()
- self.window_origin.borrow().to_vec2()
}
BufferContent::File(path) => {
let doc = self.main_split.open_docs.get(path).unwrap();
BufferContent::File(_) | BufferContent::Scratch(_) => {
let doc = self.main_split.editor_doc(editor.view_id);
let offset = self.hover.offset;
let (line, col) = doc.buffer().offset_to_line_col(offset);
let point = doc.point_of_line_col(
@ -1117,6 +1096,9 @@ pub fn run_workbench_command(
Target::Widget(self.palette.widget_id),
));
}
LapceWorkbenchCommand::NewFile => {
self.main_split.new_file(ctx, &self.config);
}
LapceWorkbenchCommand::OpenLogFile => {
if let Some(path) = Config::log_file() {
let editor_view_id = self.main_split.active.clone();
@ -1391,7 +1373,7 @@ pub fn run_workbench_command(
return;
}
self.proxy.git_commit(message, diffs);
Arc::make_mut(doc).reload(Rope::from(""));
Arc::make_mut(doc).reload(Rope::from(""), true);
let editor = self
.main_split
.editors
@ -1635,7 +1617,7 @@ pub fn set_picker_pwd(&mut self, pwd: PathBuf) {
.get_mut(&LocalBufferKind::FilePicker)
.unwrap();
let doc = Arc::make_mut(doc);
doc.reload(Rope::from(s));
doc.reload(Rope::from(s), true);
let editor = self
.main_split
.editors
@ -1860,6 +1842,7 @@ pub struct LapceMainSplitData {
pub open_docs: im::HashMap<PathBuf, Arc<Document>>,
pub local_docs: im::HashMap<LocalBufferKind, Arc<Document>>,
pub value_docs: im::HashMap<String, Arc<Document>>,
pub scratch_docs: im::HashMap<BufferId, Arc<Document>>,
pub register: Arc<Register>,
pub proxy: Arc<LapceProxy>,
pub palette_preview_editor: Arc<WidgetId>,
@ -1884,6 +1867,7 @@ pub fn editor_doc(&self, editor_view_id: WidgetId) -> Arc<Document> {
BufferContent::File(path) => self.open_docs.get(path).unwrap().clone(),
BufferContent::Local(kind) => self.local_docs.get(kind).unwrap().clone(),
BufferContent::Value(name) => self.value_docs.get(name).unwrap().clone(),
BufferContent::Scratch(id) => self.scratch_docs.get(id).unwrap().clone(),
};
doc
}
@ -2082,6 +2066,7 @@ fn get_editor_or_new(
ctx: &mut EventCtx,
editor_view_id: Option<WidgetId>,
path: Option<PathBuf>,
scratch: bool,
config: &Config,
) -> &mut LapceEditorData {
match editor_view_id {
@ -2093,7 +2078,7 @@ fn get_editor_or_new(
match &editor_tab.children[editor_tab.active] {
EditorTabChild::Editor(id, _) => {
if config.editor.show_tab {
if let Some(path) = path {
if path.is_some() || scratch {
let mut editor_size = Size::ZERO;
for (i, child) in
editor_tab.children.iter().enumerate()
@ -2107,24 +2092,26 @@ fn get_editor_or_new(
if current_size.height > 0.0 {
editor_size = current_size;
}
if editor.content
== BufferContent::File(
path.clone(),
)
{
editor_tab.active = i;
ctx.submit_command(
if let Some(path) = path.as_ref() {
if editor.content
== BufferContent::File(
path.clone(),
)
{
editor_tab.active = i;
ctx.submit_command(
Command::new(
LAPCE_UI_COMMAND,
LapceUICommand::Focus,
Target::Widget(*id),
),
);
return Arc::make_mut(
self.editors
.get_mut(id)
.unwrap(),
);
return Arc::make_mut(
self.editors
.get_mut(id)
.unwrap(),
);
}
}
}
}
@ -2245,7 +2232,8 @@ pub fn jump_to_position(
position: Position,
config: &Config,
) {
let editor = self.get_editor_or_new(ctx, editor_view_id, None, config);
let editor =
self.get_editor_or_new(ctx, editor_view_id, None, false, config);
if let BufferContent::File(path) = &editor.content {
let location = EditorLocationNew {
path: path.clone(),
@ -2269,6 +2257,7 @@ pub fn jump_to_location(
ctx,
editor_view_id,
Some(location.path.clone()),
false,
config,
)
.view_id;
@ -2277,6 +2266,7 @@ pub fn jump_to_location(
ctx,
Some(editor_view_id),
Some(location.path.clone()),
false,
config,
);
editor.save_jump_location(&doc);
@ -2284,6 +2274,24 @@ pub fn jump_to_location(
editor_view_id
}
pub fn new_file(&mut self, ctx: &mut EventCtx, config: &Config) {
let tab_id = *self.tab_id;
let proxy = self.proxy.clone();
let buffer_id = BufferId::next();
let content = BufferContent::Scratch(buffer_id);
let doc =
Document::new(content.clone(), tab_id, ctx.get_external_handle(), proxy);
self.scratch_docs.insert(buffer_id, Arc::new(doc));
let editor = self.get_editor_or_new(ctx, None, None, true, config);
editor.content = content;
editor.new_cursor = if config.lapce.modal {
Cursor::new(CursorMode::Normal(0), None, None)
} else {
Cursor::new(CursorMode::Insert(Selection::caret(0)), None, None)
};
}
pub fn go_to_location(
&mut self,
ctx: &mut EventCtx,
@ -2296,6 +2304,7 @@ pub fn go_to_location(
ctx,
editor_view_id,
Some(location.path.clone()),
false,
config,
)
.view_id;
@ -2304,6 +2313,7 @@ pub fn go_to_location(
BufferContent::File(path) => path != &location.path,
BufferContent::Local(_) => true,
BufferContent::Value(_) => true,
BufferContent::Scratch(_) => true,
};
if new_buffer {
self.db.save_doc_position(&self.workspace, &doc);
@ -2356,6 +2366,7 @@ pub fn go_to_location(
ctx,
Some(editor_view_id),
Some(location.path.clone()),
false,
config,
);
if let Some(version) = location.history.as_ref() {
@ -2401,7 +2412,7 @@ pub fn jump_to_line(
config: &Config,
) {
let editor_view_id = self
.get_editor_or_new(ctx, editor_view_id, None, config)
.get_editor_or_new(ctx, editor_view_id, None, false, config)
.view_id;
let doc = self.editor_doc(editor_view_id);
let offset = doc.buffer().first_non_blank_character_on_line(if line > 0 {
@ -2444,6 +2455,7 @@ pub fn new(
)),
);
let value_docs = im::HashMap::new();
let scratch_docs = im::HashMap::new();
let editor = LapceEditorData::new(
Some(palette_preview_editor),
@ -2462,6 +2474,7 @@ pub fn new(
open_docs,
local_docs,
value_docs,
scratch_docs,
active: Arc::new(None),
active_tab: Arc::new(None),
register: Arc::new(Register::default()),
@ -2590,6 +2603,86 @@ pub fn update_split_layout_rect(&self, split_id: WidgetId, rect: Rect) {
*split.layout_rect.borrow_mut() = rect;
}
pub fn save_as_success(
&mut self,
ctx: &mut EventCtx,
content: &BufferContent,
rev: u64,
path: &Path,
view_id: WidgetId,
exit: bool,
) {
match content {
BufferContent::Scratch(id) => {
let doc = self.scratch_docs.get(id).unwrap();
if doc.rev() == rev {
let new_content = BufferContent::File(path.to_path_buf());
for (_, editor) in self.editors.iter_mut() {
if editor.content == BufferContent::Scratch(*id) {
Arc::make_mut(editor).content = new_content.clone();
}
}
let mut doc = self.scratch_docs.remove(id).unwrap();
let mut_doc = Arc::make_mut(&mut doc);
mut_doc.buffer_mut().set_pristine();
mut_doc.set_content(new_content);
self.open_docs.insert(path.to_path_buf(), doc);
if exit {
ctx.submit_command(Command::new(
LAPCE_COMMAND,
LapceCommand {
kind: CommandKind::Focus(FocusCommand::SplitClose),
data: None,
},
Target::Widget(view_id),
));
}
}
}
BufferContent::File(_) => {}
_ => {}
}
}
pub fn save_as(
&mut self,
ctx: &mut EventCtx,
content: &BufferContent,
path: &Path,
view_id: WidgetId,
exit: bool,
) {
match content {
BufferContent::Scratch(id) => {
let event_sink = ctx.get_external_handle();
let doc = self.scratch_docs.get(id).unwrap();
let rev = doc.rev();
let path = path.to_path_buf();
let content = content.clone();
self.proxy.save_buffer_as(
doc.id(),
path.to_path_buf(),
doc.rev(),
doc.buffer().text().to_string(),
Box::new(move |result| {
if let Ok(_r) = result {
let _ = event_sink.submit_command(
LAPCE_UI_COMMAND,
LapceUICommand::SaveAsSuccess(
content, rev, path, view_id, exit,
),
Target::Auto,
);
}
}),
);
}
BufferContent::File(_) => {}
_ => {}
}
}
pub fn editor_close(
&mut self,
ctx: &mut EventCtx,
@ -2597,12 +2690,11 @@ pub fn editor_close(
force: bool,
) {
let editor = self.editors.get(&view_id).unwrap();
if let BufferContent::File(path) = &editor.content {
let doc = self.open_docs.get(path).unwrap();
if let BufferContent::File(_) | BufferContent::Scratch(_) = &editor.content {
let doc = self.editor_doc(view_id);
if !force && !doc.buffer().is_pristine() {
let exits = self.editors.iter().any(|(_, e)| {
e.content == BufferContent::File(path.to_path_buf())
&& e.view_id != view_id
&e.content == doc.content() && e.view_id != view_id
});
if !exits {
ctx.submit_command(Command::new(
@ -2610,9 +2702,7 @@ pub fn editor_close(
LapceUICommand::ShowAlert(AlertContentData {
title: format!(
"Do you want to save the changes you made to {}?",
path.file_name()
.and_then(|f| f.to_str())
.unwrap_or("")
doc.content().file_name()
),
msg: "Your changes will be lost if you don't save them."
.to_string(),
@ -2644,7 +2734,7 @@ pub fn editor_close(
return;
}
}
self.db.save_doc_position(&self.workspace, doc);
self.db.save_doc_position(&self.workspace, &doc);
}
if let Some(tab_id) = editor.tab_id {
let editor_tab = self.editor_tabs.get(&tab_id).unwrap();
@ -3080,8 +3170,15 @@ pub fn save_jump_location(&mut self, doc: &Document) {
}
pub fn editor_info(&self, data: &LapceTabData) -> EditorInfo {
let unsaved = if let BufferContent::Scratch(id) = &self.content {
let doc = data.main_split.scratch_docs.get(id).unwrap();
Some(doc.buffer().text().to_string())
} else {
None
};
let info = EditorInfo {
content: self.content.clone(),
unsaved,
scroll_offset: (self.scroll_offset.x, self.scroll_offset.y),
position: if let BufferContent::File(path) = &self.content {
let doc = data.main_split.open_docs.get(path).unwrap().clone();

View File

@ -12,6 +12,7 @@
use druid::{ExtEventSink, Point, Rect, Size, Vec2, WidgetId};
use lsp_types::Position;
use serde::{Deserialize, Serialize};
use xi_rope::Rope;
use crate::{
config::Config,
@ -233,6 +234,7 @@ pub struct BufferInfo {
#[derive(Clone, Serialize, Deserialize)]
pub struct EditorInfo {
pub content: BufferContent,
pub unsaved: Option<String>,
pub scroll_offset: (f64, f64),
pub position: Option<Position>,
}
@ -285,6 +287,19 @@ pub fn to_data(
));
data.open_docs.insert(path.clone(), doc);
}
} else if let BufferContent::Scratch(id) = &self.content {
if !data.scratch_docs.contains_key(id) {
let mut doc = Document::new(
self.content.clone(),
tab_id,
event_sink,
data.proxy.clone(),
);
if let Some(text) = &self.unsaved {
doc.reload(Rope::from(text), false);
}
data.scratch_docs.insert(*id, Arc::new(doc));
}
}
data.insert_editor(Arc::new(editor_data.clone()), config);
editor_data

View File

@ -13,7 +13,7 @@
piet::{
PietText, PietTextLayout, Text, TextAttribute, TextLayout, TextLayoutBuilder,
},
ExtEventSink, FontFamily, Point, Target, Vec2, WidgetId,
ExtEventSink, FontFamily, Point, Size, Target, Vec2, WidgetId,
};
use lapce_core::{
buffer::{Buffer, DiffLines, InvalLines},
@ -32,7 +32,7 @@
buffer::{BufferId, NewBufferResponse},
style::{LineStyle, LineStyles, Style},
};
use lsp_types::CodeActionResponse;
use lsp_types::{CodeActionOrCommand, CodeActionResponse};
use serde::{Deserialize, Serialize};
use xi_rope::{spans::Spans, Rope, RopeDelta};
@ -99,6 +99,7 @@ pub enum BufferContent {
File(PathBuf),
Local(LocalBufferKind),
Value(String),
Scratch(BufferId),
}
impl BufferContent {
@ -119,6 +120,7 @@ pub fn is_special(&self) -> bool {
LocalBufferKind::Empty => false,
},
BufferContent::Value(_) => true,
BufferContent::Scratch(_) => false,
}
}
@ -134,6 +136,7 @@ pub fn is_input(&self) -> bool {
LocalBufferKind::Empty | LocalBufferKind::SourceControl => false,
},
BufferContent::Value(_) => true,
BufferContent::Scratch(_) => false,
}
}
@ -141,6 +144,7 @@ pub fn is_search(&self) -> bool {
match &self {
BufferContent::File(_) => false,
BufferContent::Value(_) => false,
BufferContent::Scratch(_) => false,
BufferContent::Local(local) => matches!(local, LocalBufferKind::Search),
}
}
@ -150,6 +154,17 @@ pub fn is_settings(&self) -> bool {
BufferContent::File(_) => false,
BufferContent::Value(_) => true,
BufferContent::Local(_) => false,
BufferContent::Scratch(_) => false,
}
}
pub fn file_name(&self) -> &str {
match self {
BufferContent::File(p) => {
p.file_name().and_then(|f| f.to_str()).unwrap_or("")
}
BufferContent::Scratch(_) => "[Untitled]",
_ => "",
}
}
}
@ -187,10 +202,15 @@ pub fn new(
BufferContent::File(path) => Syntax::init(path),
BufferContent::Local(_) => None,
BufferContent::Value(_) => None,
BufferContent::Scratch(_) => None,
};
let id = match &content {
BufferContent::Scratch(id) => *id,
_ => BufferId::next(),
};
Self {
id: BufferId::next(),
id,
tab_id,
buffer: Buffer::new(""),
content,
@ -219,6 +239,17 @@ pub fn loaded(&self) -> bool {
self.loaded
}
pub fn set_content(&mut self, content: BufferContent) {
self.content = content;
self.syntax = match &self.content {
BufferContent::File(path) => Syntax::init(path),
BufferContent::Local(_) => None,
BufferContent::Value(_) => None,
BufferContent::Scratch(_) => None,
};
self.on_update(None);
}
pub fn content(&self) -> &BufferContent {
&self.content
}
@ -234,15 +265,15 @@ pub fn init_content(&mut self, content: Rope) {
self.on_update(None);
}
pub fn reload(&mut self, content: Rope) {
pub fn reload(&mut self, content: Rope, set_pristine: bool) {
self.code_actions.clear();
let delta = self.buffer.reload(content);
let delta = self.buffer.reload(content, set_pristine);
self.apply_deltas(&[delta]);
}
pub fn handle_file_changed(&mut self, content: Rope) {
if self.buffer.is_pristine() {
self.reload(content);
self.reload(content, true);
}
}
@ -442,6 +473,7 @@ fn on_update(&mut self, delta: Option<&RopeDelta>) {
fn notify_special(&self) {
match &self.content {
BufferContent::File(_) => {}
BufferContent::Scratch(_) => {}
BufferContent::Local(local) => {
let s = self.buffer.text().to_string();
match local {
@ -1384,6 +1416,44 @@ pub fn move_offset(
}
}
pub fn code_action_size(
&self,
text: &mut PietText,
offset: usize,
config: &Config,
) -> Size {
let prev_offset = self.buffer.prev_code_boundary(offset);
let empty_vec = Vec::new();
let code_actions = self.code_actions.get(&prev_offset).unwrap_or(&empty_vec);
let action_text_layouts: Vec<PietTextLayout> = code_actions
.iter()
.map(|code_action| {
let title = match code_action {
CodeActionOrCommand::Command(cmd) => cmd.title.to_string(),
CodeActionOrCommand::CodeAction(action) => {
action.title.to_string()
}
};
text.new_text_layout(title)
.font(FontFamily::SYSTEM_UI, 14.0)
.build()
.unwrap()
})
.collect();
let mut width = 0.0;
for text_layout in &action_text_layouts {
let line_width = text_layout.size().width + 10.0;
if line_width > width {
width = line_width;
}
}
let line_height = config.editor.line_height as f64;
Size::new(width, code_actions.len() as f64 * line_height)
}
pub fn reset_find(&self, current_find: &Find) {
{
let find = self.find.borrow();

View File

@ -1111,6 +1111,36 @@ fn save(&mut self, ctx: &mut EventCtx, exit: bool) {
Target::Auto,
);
});
} else if let BufferContent::Scratch(_) = self.doc.content() {
let workspace = self.main_split.workspace.clone();
let event_sink = ctx.get_external_handle();
let tab_id = *self.main_split.tab_id;
let content = self.doc.content().clone();
let view_id = self.editor.view_id;
thread::spawn(move || {
let dirs = directories::UserDirs::new();
let dir = workspace
.path
.as_deref()
.or_else(|| dirs.as_ref().map(|u| u.home_dir()))
.map(|u| u.join("Untitled"));
let dir = dir
.as_ref()
.and_then(|u| u.to_str())
.unwrap_or("./Untitled");
if let Some(path) =
tinyfiledialogs::save_file_dialog("Save File", dir)
{
let path = PathBuf::from(path);
let _ = event_sink.submit_command(
LAPCE_UI_COMMAND,
LapceUICommand::SaveAs(content, path, view_id, exit),
Target::Widget(tab_id),
);
}
});
}
}
@ -1851,6 +1881,7 @@ fn check_condition(&self, condition: &str) -> bool {
"input_focus" => self.editor.content.is_input(),
"editor_focus" => match self.editor.content {
BufferContent::File(_) => true,
BufferContent::Scratch(_) => true,
BufferContent::Local(_) => false,
BufferContent::Value(_) => false,
},

View File

@ -16,6 +16,7 @@
use lapce_rpc::buffer::BufferId;
use lapce_rpc::core::{CoreNotification, CoreRequest};
use lapce_rpc::plugin::PluginDescription;
use lapce_rpc::proxy::ProxyRequest;
use lapce_rpc::source_control::FileDiff;
use lapce_rpc::terminal::TermId;
use lapce_rpc::RpcHandler;
@ -434,6 +435,23 @@ pub fn new_buffer(
);
}
pub fn save_buffer_as(
&self,
buffer_id: BufferId,
path: PathBuf,
rev: u64,
content: String,
f: Box<dyn Callback>,
) {
let request = ProxyRequest::SaveBufferAs {
buffer_id,
path,
rev,
content,
};
self.rpc.send_rpc_request_value_async(request, f);
}
pub fn update(&self, buffer_id: BufferId, delta: &RopeDelta, rev: u64) {
self.rpc.send_rpc_notification(
"update",

View File

@ -29,6 +29,7 @@
use std::sync::Arc;
use std::thread;
use std::{collections::HashSet, io::BufRead};
use xi_rope::Rope;
const OPEN_FILE_EVENT_TOKEN: WatchToken = WatchToken(1);
const WORKSPACE_EVENT_TOKEN: WatchToken = WatchToken(2);
@ -566,6 +567,26 @@ fn handle_request(&self, id: RequestId, rpc: ProxyRequest) {
self.lsp.lock().save_buffer(buffer);
self.respond(id, resp);
}
SaveBufferAs {
buffer_id,
path,
rev,
content,
} => {
let mut buffer =
Buffer::new(buffer_id, path.clone(), self.git_sender.clone());
buffer.rope = Rope::from(content);
buffer.rev = rev;
let resp = buffer.save(rev).map(|_r| json!({}));
if resp.is_ok() {
self.buffers.lock().insert(buffer_id, buffer);
self.open_files
.lock()
.insert(path.to_str().unwrap().to_string(), buffer_id);
let _ = self.git_sender.send((buffer_id, 0));
}
self.respond(id, resp);
}
GlobalSearch { pattern } => {
if let Some(workspace) = self.workspace.lock().clone() {
let local_dispatcher = self.clone();

View File

@ -160,6 +160,47 @@ fn send_rpc_request_common(
}
}
fn send_rpc_request_value_common<T: serde::Serialize>(
&self,
request: T,
rh: ResponseHandler,
) {
let id = self.id.fetch_add(1, Ordering::Relaxed);
{
let mut pending = self.pending.lock();
pending.insert(id, rh);
}
let mut request = serde_json::to_value(request).unwrap();
request
.as_object_mut()
.unwrap()
.insert("id".to_string(), json!(id));
if let Err(_e) = self.sender.send(request) {
let mut pending = self.pending.lock();
if let Some(rh) = pending.remove(&id) {
rh.invoke(Err(json!("io error")));
}
}
}
pub fn send_rpc_request_value<T: serde::Serialize>(
&self,
request: T,
) -> Result<Value, Value> {
let (tx, rx) = crossbeam_channel::bounded(1);
self.send_rpc_request_value_common(request, ResponseHandler::Chan(tx));
rx.recv().unwrap_or_else(|_| Err(json!("io error")))
}
pub fn send_rpc_request_value_async<T: serde::Serialize>(
&self,
request: T,
f: Box<dyn Callback>,
) {
self.send_rpc_request_value_common(request, ResponseHandler::Callback(f));
}
pub fn send_rpc_request(
&self,
method: &str,

View File

@ -110,6 +110,12 @@ pub enum ProxyRequest {
rev: u64,
buffer_id: BufferId,
},
SaveBufferAs {
buffer_id: BufferId,
path: PathBuf,
rev: u64,
content: String,
},
}
#[derive(Debug, Clone, Serialize, Deserialize)]

View File

@ -285,7 +285,7 @@ pub fn get_size(
let line_height = data.config.editor.line_height as f64;
let width = data.config.editor_char_width(text);
match &data.editor.content {
BufferContent::File(_) => {
BufferContent::File(_) | BufferContent::Scratch(_) => {
if data.editor.code_lens {
if let Some(syntax) = data.doc.syntax() {
let height =

View File

@ -1,4 +1,4 @@
use std::iter::Iterator;
use std::{iter::Iterator, path::PathBuf};
use druid::{
piet::{Text, TextLayout as TextLayoutTrait, TextLayoutBuilder},
@ -135,10 +135,19 @@ pub fn paint_buffer(
clip_rect.x1 = icon.rect.x0;
}
}
if let BufferContent::File(path) = data.doc.content() {
if let BufferContent::File(_) | BufferContent::Scratch(_) =
data.doc.content()
{
let mut path = match data.doc.content() {
BufferContent::File(path) => path.to_path_buf(),
BufferContent::Scratch(_) => {
PathBuf::from(data.doc.content().file_name())
}
_ => PathBuf::from(""),
};
ctx.with_save(|ctx| {
ctx.clip(clip_rect);
let mut path = path.clone();
let svg = file_svg_new(&path);
let width = 13.0;

View File

@ -359,6 +359,8 @@ fn layout(
text = s.to_string();
}
}
} else if let BufferContent::Scratch(_) = &editor.content {
text = editor.content.file_name().to_string();
}
}
}

View File

@ -112,7 +112,7 @@ pub fn request_focus(
));
}
match &editor.content {
BufferContent::File(_) => {
BufferContent::File(_) | BufferContent::Scratch(_) => {
data.focus_area = FocusArea::Editor;
data.main_split.active = Arc::new(Some(self.view_id));
data.main_split.active_tab = Arc::new(editor.tab_id);

View File

@ -668,7 +668,7 @@ pub fn new(
event_sink,
data.proxy.clone(),
);
doc.reload(Rope::from(&input));
doc.reload(Rope::from(&input), true);
data.main_split.value_docs.insert(name, Arc::new(doc));
let editor = LapceEditorData::new(None, None, content, &data.config);
let view_id = editor.view_id;

View File

@ -330,7 +330,7 @@ fn handle_event(
.local_docs
.get_mut(&LocalBufferKind::Palette)
.unwrap();
Arc::make_mut(doc).reload(Rope::from(pattern));
Arc::make_mut(doc).reload(Rope::from(pattern), true);
let editor = data
.main_split
.editors
@ -354,7 +354,7 @@ fn handle_event(
.get_mut(&LocalBufferKind::Search)
.unwrap();
if &doc.buffer().text().to_string() != pattern {
Arc::make_mut(doc).reload(Rope::from(pattern));
Arc::make_mut(doc).reload(Rope::from(pattern), true);
}
if pattern.is_empty() {
Arc::make_mut(&mut data.find).unset();
@ -624,7 +624,7 @@ fn handle_event(
location,
} => {
let doc = data.main_split.open_docs.get_mut(path).unwrap();
Arc::make_mut(doc).reload(Rope::from(content));
Arc::make_mut(doc).reload(Rope::from(content), true);
data.main_split.go_to_location(
ctx,
Some(*editor_view_id),
@ -819,6 +819,22 @@ fn handle_event(
}
ctx.set_handled();
}
LapceUICommand::SaveAs(content, path, view_id, exit) => {
data.main_split.save_as(ctx, content, path, *view_id, *exit);
ctx.set_handled();
}
LapceUICommand::SaveAsSuccess(
content,
rev,
path,
view_id,
exit,
) => {
data.main_split.save_as_success(
ctx, content, *rev, path, *view_id, *exit,
);
ctx.set_handled();
}
LapceUICommand::OpenFileChanged { path, content } => {
let doc = data.main_split.open_docs.get_mut(path).unwrap();
let doc = Arc::make_mut(doc);
@ -828,7 +844,7 @@ fn handle_event(
let doc = data.main_split.open_docs.get_mut(path).unwrap();
if doc.rev() + 1 == *rev {
let doc = Arc::make_mut(doc);
doc.reload(content.to_owned());
doc.reload(content.to_owned(), true);
for (_, editor) in data.main_split.editors.iter_mut() {
if &editor.content == doc.content()