start panel

This commit is contained in:
Dongdong Zhou 2020-12-17 18:16:37 +00:00
parent c1113c1866
commit ec0e5e4821
15 changed files with 262 additions and 107 deletions

49
Cargo.lock generated
View File

@ -406,7 +406,7 @@ dependencies = [
"block",
"cocoa-foundation",
"core-foundation 0.9.1",
"core-graphics 0.22.1",
"core-graphics 0.22.2",
"foreign-types",
"libc",
"objc",
@ -506,9 +506,9 @@ dependencies = [
[[package]]
name = "core-graphics"
version = "0.22.1"
version = "0.22.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fc239bba52bab96649441699533a68de294a101533b0270b2d65aa402b29a7f9"
checksum = "269f35f69b542b80e736a20a89a05215c0ce80c2c03c514abb2e318b78379d86"
dependencies = [
"bitflags",
"core-foundation 0.9.1",
@ -548,7 +548,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d2c7f46e8b820fd5f4b28528104b28b0a91cbe9e9c5bde8017087fb44bc93a60"
dependencies = [
"core-foundation 0.9.1",
"core-graphics 0.22.1",
"core-graphics 0.22.2",
"foreign-types",
"libc",
]
@ -747,7 +747,7 @@ dependencies = [
"cairo-rs",
"cfg-if 0.1.10",
"cocoa",
"core-graphics 0.22.1",
"core-graphics 0.22.2",
"foreign-types",
"gdk",
"gdk-pixbuf",
@ -1630,27 +1630,10 @@ dependencies = [
name = "lapce"
version = "0.0.1"
dependencies = [
"anyhow",
"cc",
"druid",
"fzyr",
"include_dir",
"lapce-core",
"lazy_static 1.4.0",
"lsp-types 0.61.0",
"parking_lot 0.11.0",
"serde",
"serde_json",
"strum 0.19.2",
"strum_macros 0.19.2",
"syntect",
"toml",
"tree-sitter",
"tree-sitter-highlight",
"uuid 0.7.4",
"xi-core-lib",
"xi-rope",
"xi-rpc",
]
[[package]]
@ -1667,7 +1650,7 @@ dependencies = [
"jsonrpc-lite",
"lapce-proxy",
"lazy_static 1.4.0",
"lsp-types 0.82.0",
"lsp-types",
"openssh",
"parking_lot 0.11.0",
"regex",
@ -1713,11 +1696,12 @@ dependencies = [
"home",
"jsonrpc-lite",
"lapce-rpc",
"lsp-types 0.82.0",
"lsp-types",
"parking_lot 0.11.0",
"serde",
"serde_json",
"toml",
"xi-core-lib",
"xi-rope",
"xi-rpc",
]
@ -1850,19 +1834,6 @@ dependencies = [
"cfg-if 0.1.10",
]
[[package]]
name = "lsp-types"
version = "0.61.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fa3268fbe8beb2795c2fb327bf44f4f3d24f5fe9ebc18d7e2980afd444d72bcf"
dependencies = [
"bitflags",
"serde",
"serde_json",
"serde_repr",
"url 2.1.1",
]
[[package]]
name = "lsp-types"
version = "0.82.0"
@ -2380,7 +2351,7 @@ dependencies = [
"cairo-rs",
"cairo-sys-rs",
"cfg-if 1.0.0",
"core-graphics 0.22.1",
"core-graphics 0.22.2",
"piet",
"piet-cairo",
"piet-coregraphics",
@ -2396,7 +2367,7 @@ version = "0.2.0-pre6"
dependencies = [
"core-foundation 0.9.1",
"core-foundation-sys 0.8.1",
"core-graphics 0.22.1",
"core-graphics 0.22.2",
"core-text 19.1.0",
"foreign-types",
"piet",

View File

@ -7,23 +7,23 @@ edition = "2018"
[dependencies]
lapce-core = { path = "./core" }
parking_lot = { version = "0.11.0", features = ["deadlock_detection"] }
include_dir = "0.6.0"
tree-sitter-highlight = "0.3.0"
tree-sitter = "0.17.0"
toml = "0.5.6"
anyhow = "1.0.32"
strum = "0.19"
strum_macros = "0.19"
lazy_static = "1.4.0"
serde = "1.0"
serde_json = "1.0"
syntect = "3.2"
xi-core-lib = { path = "../xi-editor/rust/core-lib/" }
xi-rope = { path = "../xi-editor/rust/rope/" }
xi-rpc = { path = "../xi-editor/rust/rpc/" }
fzyr = "0.1.2"
uuid = { version = "0.7.4", features = ["v4"] }
lsp-types = "0.61.0"
# include_dir = "0.6.0"
# tree-sitter-highlight = "0.3.0"
# tree-sitter = "0.17.0"
# toml = "0.5.6"
# anyhow = "1.0.32"
# strum = "0.19"
# strum_macros = "0.19"
# lazy_static = "1.4.0"
# serde = "1.0"
# serde_json = "1.0"
# syntect = "3.2"
# xi-core-lib = { path = "../xi-editor/rust/core-lib/" }
# xi-rope = { path = "../xi-editor/rust/rope/" }
# xi-rpc = { path = "../xi-editor/rust/rpc/" }
# fzyr = "0.1.2"
# uuid = { version = "0.7.4", features = ["v4"] }
# lsp-types = "0.61.0"
druid = { path = "../druid/druid", features = ["svg"] }
[build-dependencies]

View File

@ -676,6 +676,8 @@ pub fn indent_on_line(&self, line: usize) -> String {
}
pub fn line_of_offset(&self, offset: usize) -> usize {
let max = self.len();
let offset = if offset > max { max } else { offset };
self.rope.line_of_offset(offset)
}
@ -684,10 +686,14 @@ pub fn offset_of_line(&self, line: usize) -> usize {
}
pub fn offset_to_line_col(&self, offset: usize) -> (usize, usize) {
let max = self.len();
let offset = if offset > max { max } else { offset };
LogicalLines.offset_to_line_col(&self.rope, offset)
}
pub fn offset_to_position(&self, offset: usize) -> Position {
let max = self.len();
let offset = if offset > max { max } else { offset };
let (line, col) = LogicalLines.offset_to_line_col(&self.rope, offset);
Position {
line: line as u64,

View File

@ -135,6 +135,8 @@ pub enum LapceCommand {
Yank,
#[strum(serialize = "paste")]
Paste,
#[strum(serialize = "clipboard_paste")]
ClipboardPaste,
#[strum(serialize = "undo")]
Undo,
#[strum(serialize = "redo")]

View File

@ -32,7 +32,6 @@
};
use anyhow::{anyhow, Result};
use bit_vec::BitVec;
use druid::FileDialogOptions;
use druid::{
kurbo::Line, piet::PietText, theme, widget::IdentityWrapper, widget::Padding,
widget::SvgData, Affine, BoxConstraints, Color, Command, Data, Env, Event,
@ -44,6 +43,7 @@
piet::{PietTextLayout, Text, TextAttribute, TextLayoutBuilder},
FontWeight,
};
use druid::{Application, FileDialogOptions};
use fzyr::{has_match, locate};
use lsp_types::{
CodeActionOrCommand, CodeActionResponse, CompletionItem, CompletionResponse,
@ -104,6 +104,7 @@ pub struct EditorState {
pub saved_buffer_id: BufferId,
pub saved_selection: Selection,
pub saved_scroll_offset: Vec2,
last_movement: Movement,
}
#[derive(Clone, Debug)]
@ -138,6 +139,7 @@ pub fn new(
current_location: 0,
saved_buffer_id: BufferId(0),
saved_selection: Selection::new_simple(),
last_movement: Movement::Left,
saved_scroll_offset: Vec2::ZERO,
}
}
@ -320,9 +322,10 @@ pub fn do_move(
env: &Env,
count: Option<usize>,
) {
if movement.is_jump() {
if movement.is_jump() && movement != &self.last_movement {
self.save_jump_location(buffer);
}
self.last_movement = movement.clone();
self.selection = buffer.do_move(
ctx,
ui_state,
@ -2361,6 +2364,33 @@ pub fn run_command(
LapceCommand::DeleteOperator => {
self.operator = Some(EditorOperator::Delete(EditorCount(count)));
}
LapceCommand::ClipboardPaste => {
if let Some(s) = Application::global().clipboard().get_string() {
let editor = self.editors.get_mut(&self.active)?;
let buffer_id = editor.buffer_id.as_ref()?;
let buffer = self.buffers.get_mut(buffer_id)?;
let buffer_ui_state = ui_state.get_buffer_mut(buffer_id);
let mut selection = match &self.mode {
Mode::Visual => editor.get_selection(
buffer,
&self.mode,
&self.visual_mode,
false,
),
Mode::Normal => Selection::caret(
editor.selection.get_cursor_offset() + 1,
),
Mode::Insert => editor.selection.clone(),
};
let delta =
buffer.edit(ctx, buffer_ui_state, &s, &selection, true);
selection =
selection.apply_delta(&delta, true, InsertDrift::Default);
editor.selection =
Selection::caret(selection.get_cursor_offset() - 1);
self.mode = Mode::Normal;
}
}
LapceCommand::Paste => {
let editor = self.editors.get_mut(&self.active)?;
let buffer_id = editor.buffer_id.as_ref()?;
@ -2526,47 +2556,53 @@ pub fn run_command(
buffer.id,
buffer.offset_to_position(offset),
Box::new(move |result| {
let state =
LAPCE_APP_STATE.get_tab_state(&window_id, &tab_id);
let editor_split = state.editor_split.lock();
let editor =
editor_split.editors.get(&editor_split.active).unwrap();
if offset != editor.selection.get_cursor_offset() {
println!("not the previous offset ,quit");
return;
}
if let Ok(value) = result {
let resp: Result<
GotoDefinitionResponse,
serde_json::Error,
> = serde_json::from_value(value);
if let Ok(resp) = resp {
if let Some(location) = match resp {
GotoDefinitionResponse::Scalar(location) => {
Some(location)
}
GotoDefinitionResponse::Array(locations) => {
if locations.len() > 0 {
Some(locations[0].clone())
} else {
None
thread::spawn(move || {
let state =
LAPCE_APP_STATE.get_tab_state(&window_id, &tab_id);
let editor_split = state.editor_split.lock();
let editor = editor_split
.editors
.get(&editor_split.active)
.unwrap();
if offset != editor.selection.get_cursor_offset() {
println!("not the previous offset ,quit");
return;
}
if let Ok(value) = result {
let resp: Result<
GotoDefinitionResponse,
serde_json::Error,
> = serde_json::from_value(value);
if let Ok(resp) = resp {
if let Some(location) = match resp {
GotoDefinitionResponse::Scalar(location) => {
Some(location)
}
GotoDefinitionResponse::Array(locations) => {
if locations.len() > 0 {
Some(locations[0].clone())
} else {
None
}
}
GotoDefinitionResponse::Link(
location_links,
) => None,
} {
if location.range.start == prev_position {
editor_split.get_references();
} else {
LAPCE_APP_STATE.submit_ui_command(
LapceUICommand::GotoLocation(
location,
),
editor_split.widget_id,
);
}
}
GotoDefinitionResponse::Link(location_links) => {
None
}
} {
if location.range.start == prev_position {
editor_split.get_references();
} else {
LAPCE_APP_STATE.submit_ui_command(
LapceUICommand::GotoLocation(location),
editor_split.widget_id,
);
}
}
}
}
});
}),
);
// LAPCE_APP_STATE
@ -3530,11 +3566,17 @@ fn paint(&mut self, ctx: &mut PaintCtx, data: &LapceUIState, env: &Env) {
let buffer = editor_split.buffers.get(buffer_id.unwrap()).unwrap();
let last_line = buffer.last_line();
let max_offset = buffer.len() - 1;
let rects = ctx.region().rects().to_vec();
let active = editor_split.active;
let editor = editor_split.editors.get(&self.view_id).unwrap();
let (current_line, _) =
buffer.offset_to_line_col(editor.selection.get_cursor_offset());
let offset = editor.selection.get_cursor_offset();
let offset = if offset > max_offset {
max_offset
} else {
offset
};
let (current_line, _) = buffer.offset_to_line_col(offset);
for rect in rects {
let start_line = (rect.y0 / line_height).floor() as usize;
let num_lines = (rect.height() / line_height).floor() as usize;

View File

@ -10,6 +10,7 @@
pub mod lsp;
pub mod movement;
pub mod palette;
pub mod panel;
pub mod plugin;
pub mod proxy;
pub mod scroll;

View File

@ -311,12 +311,14 @@ pub fn apply_delta(
}
}
#[derive(Clone)]
pub enum LinePosition {
First,
Last,
Line(usize),
}
#[derive(Clone)]
pub enum Movement {
Left,
Right,
@ -334,6 +336,12 @@ pub enum Movement {
MatchPairs,
}
impl PartialEq for Movement {
fn eq(&self, other: &Self) -> bool {
std::mem::discriminant(self) == std::mem::discriminant(other)
}
}
impl Movement {
pub fn is_vertical(&self) -> bool {
match self {

75
core/src/panel.rs Normal file
View File

@ -0,0 +1,75 @@
use std::{collections::HashMap, sync::Arc};
use parking_lot::Mutex;
#[derive(Eq, PartialEq, Hash, Clone)]
pub enum PanelPosition {
LeftTop,
LeftBottom,
BottomLeft,
BottomRight,
RightTop,
RightBottom,
}
pub trait PanelProperty {
fn position(&self) -> &PanelPosition;
fn active(&self) -> usize;
fn size(&self) -> (usize, f64);
}
pub struct PanelState {
pub panels: Vec<Arc<Mutex<dyn PanelProperty>>>,
pub shown: HashMap<PanelPosition, bool>,
}
impl PanelState {
pub fn is_shown(&self, position: &PanelPosition) -> bool {
*self.shown.get(position).unwrap_or(&false)
}
pub fn size(&self, position: &PanelPosition) -> Option<(usize, f64)> {
let mut active_panel = None;
let mut active = 0;
for panel in self.panels.iter() {
let local_panel = panel.clone();
let panel = panel.lock();
if panel.position() == position {
let panel_active = panel.active();
if panel_active > active {
active_panel = Some(local_panel);
active = panel_active;
}
}
}
active_panel.map(|p| p.lock().size())
}
pub fn shown_panels(
&self,
) -> HashMap<PanelPosition, Option<(usize, Arc<Mutex<dyn PanelProperty>>)>> {
let mut shown_panels = HashMap::new();
for (postion, shown) in self.shown.iter() {
if *shown {
shown_panels.insert(postion.clone(), None);
}
}
for panel in self.panels.iter() {
let local_panel = panel.clone();
let panel = panel.lock();
let position = panel.position();
let active = panel.active();
if let Some(p) = shown_panels.get_mut(&position) {
if p.is_none() {
*p = Some((active, local_panel));
} else {
if active > p.as_ref().unwrap().0 {
*p = Some((active, local_panel))
}
}
}
}
shown_panels
}
}

View File

@ -18,7 +18,7 @@
LifeCycleCtx, PaintCtx, Point, Rect, RenderContext, Size, TextLayout, UpdateCtx,
Widget, WidgetId, WidgetPod, WindowId,
};
use std::sync::Arc;
use std::{collections::HashMap, sync::Arc};
pub struct LapceTab {
window_id: WindowId,
@ -146,6 +146,7 @@ fn layout(
) -> druid::Size {
let self_size = bc.max();
let status_size = self.status.layout(ctx, bc, data, env);
let main_split_size =
Size::new(self_size.width, self_size.height - status_size.height);
let main_split_bc = BoxConstraints::new(Size::ZERO, main_split_size);

View File

@ -61,8 +61,10 @@ fn initialize(&mut self, core: CoreProxy) {
"rust-analyzer-mac",
"rust",
Some(json!({
"diagnostics.enable": false,
"diagnostics.enableExperimental": false,
"diagnostics": {
"enable": false,
"enableExperimental": false,
},
})),
);
}

View File

@ -6,6 +6,7 @@ edition = "2018"
[dependencies]
lapce-rpc = { path = "../rpc" }
xi-core-lib = { path = "../../xi-editor/rust/core-lib/" }
xi-rpc = { path = "../../xi-editor/rust/rpc/" }
xi-rope = { path = "../../xi-editor/rust/rope/", features = ["serde"] }
serde = { version = "1.0", features = ["derive"] }

View File

@ -1,11 +1,11 @@
use anyhow::{anyhow, Result};
use crossbeam_channel::Sender;
use std::borrow::Cow;
use std::ffi::OsString;
use std::fs::File;
use std::io::Read;
use std::io::Write;
use std::path::PathBuf;
use std::{borrow::Cow, path::Path, time::SystemTime};
use std::{fs, str::FromStr};
use lsp_types::*;
@ -25,6 +25,7 @@ pub struct Buffer {
pub path: PathBuf,
pub rev: u64,
sender: Sender<(BufferId, u64)>,
pub mod_time: Option<SystemTime>,
}
impl Buffer {
@ -39,6 +40,7 @@ pub fn new(
Rope::from("")
};
let language_id = language_id_from_path(&path).unwrap_or("").to_string();
let mod_time = get_mod_time(&path);
Buffer {
id,
rope,
@ -46,6 +48,7 @@ pub fn new(
language_id,
rev: 0,
sender,
mod_time,
}
}
@ -184,3 +187,12 @@ fn get_document_content_changes(
None
}
/// Returns the modification timestamp for the file at a given path,
/// if present.
fn get_mod_time<P: AsRef<Path>>(path: P) -> Option<SystemTime> {
File::open(path)
.and_then(|f| f.metadata())
.and_then(|meta| meta.modified())
.ok()
}

View File

@ -18,10 +18,13 @@
use std::thread;
use std::{cmp, fs};
use std::{collections::HashMap, io};
use xi_core_lib::watcher::{FileWatcher, Notify, WatchToken};
use xi_rope::{RopeDelta, RopeInfo};
use xi_rpc::RpcPeer;
use xi_rpc::{Handler, RpcCtx};
pub const OPEN_FILE_EVENT_TOKEN: WatchToken = WatchToken(2);
#[derive(Clone)]
pub struct Dispatcher {
pub sender: Arc<Sender<Value>>,
@ -30,6 +33,24 @@ pub struct Dispatcher {
pub buffers: Arc<Mutex<HashMap<BufferId, Buffer>>>,
plugins: Arc<Mutex<PluginCatalog>>,
pub lsp: Arc<Mutex<LspCatalog>>,
pub watcher: Arc<Mutex<Option<FileWatcher>>>,
}
impl Notify for Dispatcher {
fn notify(&self) {
let dispatcher = self.clone();
thread::spawn(move || {
for (token, event) in
{ dispatcher.watcher.lock().as_mut().unwrap().take_events() }
.drain(..)
{
match token {
OPEN_FILE_EVENT_TOKEN => {}
_ => (),
}
}
});
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
@ -142,7 +163,9 @@ pub fn new(sender: Sender<Value>) -> Dispatcher {
buffers: Arc::new(Mutex::new(HashMap::new())),
plugins: Arc::new(Mutex::new(plugins)),
lsp: Arc::new(Mutex::new(LspCatalog::new())),
watcher: Arc::new(Mutex::new(None)),
};
*dispatcher.watcher.lock() = Some(FileWatcher::new(dispatcher.clone()));
dispatcher.lsp.lock().dispatcher = Some(dispatcher.clone());
dispatcher.plugins.lock().reload();
dispatcher.plugins.lock().start_all(dispatcher.clone());
@ -270,6 +293,11 @@ fn handle_notification(&self, rpc: Notification) {
}
}
}
self.watcher.lock().as_mut().unwrap().watch(
workspace.as_path(),
true,
OPEN_FILE_EVENT_TOKEN,
);
self.send_notification(
"list_dir",
json!({
@ -431,6 +459,11 @@ fn handle_request(&self, id: RequestId, rpc: Request) {
}
}
fn get_git_changes(workspace_path: &PathBuf) -> Option<()> {
let repo = Repository::open(workspace_path.to_str()?).ok()?;
None
}
#[derive(Clone, Debug)]
pub struct DiffHunk {
pub old_start: u32,

Binary file not shown.

View File

@ -7,8 +7,8 @@
use lapce_core::{editor::Editor, window::LapceTab, window::LapceWindow};
use druid::{
piet::Color, theme, FontDescriptor, FontFamily, FontWeight, Key, Size, Target,
WidgetId,
piet::Color, theme, FontDescriptor, FontFamily, FontWeight, Key, MenuDesc, Size,
Target, WidgetId,
};
use druid::{
widget::IdentityWrapper,
@ -22,11 +22,11 @@
use lapce_core::state::{
LapceTabState, LapceUIState, LapceWindowState, LAPCE_APP_STATE,
};
use tree_sitter::{Language, Parser};
// use tree_sitter::{Language, Parser};
extern "C" {
fn tree_sitter_rust() -> Language;
}
// extern "C" {
// fn tree_sitter_rust() -> Language;
// }
struct Delegate {
windows: Vec<WindowId>,
@ -143,6 +143,7 @@ pub fn main() {
.insert(window_id.clone(), window_state);
let mut window = WindowDesc::new(move || build_app(window_id.clone()))
.title(LocalizedString::new("lapce").with_placeholder("Lapce"))
.menu(MenuDesc::empty())
.window_size(Size::new(800.0, 600.0))
.with_min_size(Size::new(800.0, 600.0));
window.id = window_id;