From 5592a6bcd0bd77d1833049a40a564fe720bc0b2a Mon Sep 17 00:00:00 2001 From: Dongdong Zhou Date: Fri, 21 Jan 2022 19:36:13 +0000 Subject: [PATCH] change tree sitter to use crates --- .gitmodules | 20 -- Cargo.lock | 40 +++ core/Cargo.toml | 4 + core/build.rs | 94 ------- core/languages/tree-sitter-go | 1 - core/languages/tree-sitter-javascript | 1 - core/languages/tree-sitter-rust | 1 - core/languages/tree-sitter-toml | 1 - core/languages/tree-sitter-yaml | 1 - core/src/buffer.rs | 48 +++- core/src/command.rs | 8 +- core/src/data.rs | 20 ++ core/src/editor.rs | 386 ++++++++++++++++++++++++-- core/src/language.rs | 79 +----- core/src/problem.rs | 2 + core/src/proxy.rs | 14 + core/src/scroll.rs | 1 - core/src/source_control.rs | 9 + core/src/tab.rs | 24 ++ proxy/src/dispatch.rs | 43 ++- 20 files changed, 568 insertions(+), 229 deletions(-) delete mode 100644 .gitmodules delete mode 100644 core/build.rs delete mode 160000 core/languages/tree-sitter-go delete mode 160000 core/languages/tree-sitter-javascript delete mode 160000 core/languages/tree-sitter-rust delete mode 160000 core/languages/tree-sitter-toml delete mode 160000 core/languages/tree-sitter-yaml diff --git a/.gitmodules b/.gitmodules deleted file mode 100644 index 409f67c6..00000000 --- a/.gitmodules +++ /dev/null @@ -1,20 +0,0 @@ -[submodule "core/languages/tree-sitter-rust"] - path = core/languages/tree-sitter-rust - url = https://github.com/tree-sitter/tree-sitter-rust - shallow = true -[submodule "core/languages/tree-sitter-toml"] - path = core/languages/tree-sitter-toml - url = https://github.com/ikatyang/tree-sitter-toml - shallow = true -[submodule "core/languages/tree-sitter-javascript"] - path = core/languages/tree-sitter-javascript - url = https://github.com/tree-sitter/tree-sitter-javascript - shallow = true -[submodule "core/languages/tree-sitter-yaml"] - path = core/languages/tree-sitter-yaml - url = https://github.com/ikatyang/tree-sitter-yaml - shallow = true -[submodule "core/languages/tree-sitter-go"] - path = core/languages/tree-sitter-go - url = https://github.com/tree-sitter/tree-sitter-go - shallow = true diff --git a/Cargo.lock b/Cargo.lock index eda981e3..e9680e66 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1027,6 +1027,12 @@ dependencies = [ "syn", ] +[[package]] +name = "diff" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e25ea47919b1560c4e3b7fe0aaab9becf5b84a10325ddf7db0f0ba5e1026499" + [[package]] name = "digest" version = "0.8.1" @@ -2157,6 +2163,7 @@ dependencies = [ "config", "crossbeam-channel 0.5.1", "crossbeam-utils 0.8.5", + "diff", "directories", "druid", "flate2", @@ -2184,7 +2191,10 @@ dependencies = [ "tinyfiledialogs", "toml", "tree-sitter", + "tree-sitter-go", "tree-sitter-highlight", + "tree-sitter-javascript", + "tree-sitter-rust", "unicode-segmentation", "unicode-width", "usvg", @@ -4739,6 +4749,16 @@ dependencies = [ "regex", ] +[[package]] +name = "tree-sitter-go" +version = "0.19.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71967701c8214be4aa77e0260e98361e6fd71ceec1d9d03abb37a22c9f60d0ff" +dependencies = [ + "cc", + "tree-sitter", +] + [[package]] name = "tree-sitter-highlight" version = "0.20.1" @@ -4750,6 +4770,26 @@ dependencies = [ "tree-sitter", ] +[[package]] +name = "tree-sitter-javascript" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2490fab08630b2c8943c320f7b63473cbf65511c8d83aec551beb9b4375906ed" +dependencies = [ + "cc", + "tree-sitter", +] + +[[package]] +name = "tree-sitter-rust" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3df540a493d754015d22eaf57c38f58804be3713a22f6062db983ec15f85c3c9" +dependencies = [ + "cc", + "tree-sitter", +] + [[package]] name = "try-lock" version = "0.2.3" diff --git a/core/Cargo.toml b/core/Cargo.toml index a670cb1e..d8dbde43 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -5,6 +5,7 @@ authors = ["Dongdong Zhou "] edition = "2021" [dependencies] +diff = "0.1.12" libloading = "0.7" flate2 = "1.0.22" reqwest = { version = "0.11", features = ["blocking", "json"] } @@ -30,6 +31,9 @@ parking_lot = { version = "0.11.0", features = ["deadlock_detection"] } include_dir = "0.6.0" tree-sitter = "0.20.2" tree-sitter-highlight = "0.20.1" +tree-sitter-rust = "0.20.0" +tree-sitter-go = "0.19.1" +tree-sitter-javascript = "0.20.0" anyhow = "1.0.32" strum = "0.19" strum_macros = "0.19" diff --git a/core/build.rs b/core/build.rs deleted file mode 100644 index 47cddd22..00000000 --- a/core/build.rs +++ /dev/null @@ -1,94 +0,0 @@ -use anyhow::{anyhow, Context, Result}; -use std::fs; -use std::path::{Path, PathBuf}; - -fn collect_tree_sitter_dirs(ignore: &[String]) -> Result> { - let mut dirs = Vec::new(); - let path = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("languages"); - - for entry in fs::read_dir(path)? { - let entry = entry?; - let path = entry.path(); - - if !entry.file_type()?.is_dir() { - continue; - } - - let dir = path.file_name().unwrap().to_str().unwrap().to_string(); - - // filter ignores - if ignore.contains(&dir) { - continue; - } - dirs.push(dir) - } - - Ok(dirs) -} - -fn build_library(src_dir: &Path, language: &str) -> Result<()> { - let mut config = cc::Build::new(); - config.include(&src_dir); - config - .flag_if_supported("-Wno-unused-parameter") - .flag_if_supported("-Wno-unused-but-set-variable") - .flag_if_supported("-Wno-trigraphs"); - - let parser_path = src_dir.join("parser.c"); - println!("cargo:rerun-if-changed={}", parser_path.to_str().unwrap()); - config.file(&parser_path); - - let scanner_path = src_dir.join("scanner.c"); - if scanner_path.exists() { - println!("cargo:rerun-if-changed={}", scanner_path.to_str().unwrap()); - config.file(&scanner_path); - } - - let scanner_path = src_dir.join("scanner.cc"); - if scanner_path.exists() { - println!("cargo:rerun-if-changed={}", scanner_path.to_str().unwrap()); - config.file(&scanner_path); - config.cpp(true); - } - - config.out_dir(src_dir); - config.compile(language); - Ok(()) -} - -fn build_dir(dir: &str, language: &str) { - println!("Build language {}", language); - if PathBuf::from("languages") - .join(dir) - .read_dir() - .unwrap() - .next() - .is_none() - { - eprintln!( - "The directory {} is empty, you probably need to use 'git submodule update --init --recursive'?", - dir - ); - std::process::exit(1); - } - - let path = PathBuf::from(env!("CARGO_MANIFEST_DIR")) - .join("languages") - .join(dir) - .join("src"); - - build_library(&path, language).unwrap(); -} - -fn main() { - let ignore = vec![ - "tree-sitter-typescript".to_string(), - "tree-sitter-ocaml".to_string(), - ]; - let dirs = collect_tree_sitter_dirs(&ignore).unwrap(); - - for dir in dirs { - let language = &dir.strip_prefix("tree-sitter-").unwrap(); - build_dir(&dir, language); - } -} diff --git a/core/languages/tree-sitter-go b/core/languages/tree-sitter-go deleted file mode 160000 index 0fa917a7..00000000 --- a/core/languages/tree-sitter-go +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 0fa917a7022d1cd2e9b779a6a8fc5dc7fad69c75 diff --git a/core/languages/tree-sitter-javascript b/core/languages/tree-sitter-javascript deleted file mode 160000 index fdeb68ac..00000000 --- a/core/languages/tree-sitter-javascript +++ /dev/null @@ -1 +0,0 @@ -Subproject commit fdeb68ac8d2bd5a78b943528bb68ceda3aade2eb diff --git a/core/languages/tree-sitter-rust b/core/languages/tree-sitter-rust deleted file mode 160000 index eeb0702e..00000000 --- a/core/languages/tree-sitter-rust +++ /dev/null @@ -1 +0,0 @@ -Subproject commit eeb0702ebdac504b97196577b1dac43c80913d7b diff --git a/core/languages/tree-sitter-toml b/core/languages/tree-sitter-toml deleted file mode 160000 index 8bd20568..00000000 --- a/core/languages/tree-sitter-toml +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 8bd2056818b21860e3d756b5a58c4f6e05fb744e diff --git a/core/languages/tree-sitter-yaml b/core/languages/tree-sitter-yaml deleted file mode 160000 index 0e36bed1..00000000 --- a/core/languages/tree-sitter-yaml +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 0e36bed171768908f331ff7dff9d956bae016efb diff --git a/core/src/buffer.rs b/core/src/buffer.rs index a03ee672..5bef74f4 100644 --- a/core/src/buffer.rs +++ b/core/src/buffer.rs @@ -10,7 +10,7 @@ }; use druid::{Env, FontFamily, PaintCtx, Point}; use language::{new_highlight_config, new_parser, LapceLanguage}; -use lapce_proxy::dispatch::NewBufferResponse; +use lapce_proxy::dispatch::{BufferHeadResponse, NewBufferResponse}; use lsp_types::SemanticTokensServerCapabilities; use lsp_types::{CallHierarchyOptions, SemanticTokensLegend}; use lsp_types::{ @@ -35,10 +35,6 @@ use std::{collections::HashMap, fs::File}; use std::{fs, str::FromStr}; use tree_sitter::{Node, Parser, Tree}; -use tree_sitter_highlight::{ - Highlight, HighlightConfiguration, HighlightEvent, Highlighter, -}; -use unicode_segmentation::UnicodeSegmentation; use unicode_width::{UnicodeWidthChar, UnicodeWidthStr}; use xi_core_lib::selection::InsertDrift; use xi_rope::{ @@ -58,8 +54,6 @@ use crate::{ command::LapceUICommand, command::LAPCE_UI_COMMAND, - data::LapceEditorViewData, - editor::EditorOperator, find::Find, language, movement::{ColPosition, LinePosition, Movement, SelRegion, Selection}, @@ -217,6 +211,7 @@ pub struct BufferNew { pub local: bool, update_sender: Arc>, pub line_changes: HashMap, + pub histories: im::HashMap, pub find: Rc>, pub find_progress: Rc>, @@ -270,6 +265,7 @@ pub fn new( update_sender, local: false, line_changes: HashMap::new(), + histories: im::HashMap::new(), revs: vec![Revision { max_undo_so_far: 0, @@ -362,6 +358,44 @@ pub fn notify_update(&self) { } } + pub fn retrieve_file_head( + &self, + tab_id: WidgetId, + proxy: Arc, + event_sink: ExtEventSink, + ) { + let id = self.id; + if let BufferContent::File(path) = &self.content { + let path = path.clone(); + thread::spawn(move || { + proxy.get_buffer_head( + id, + path.clone(), + Box::new(move |result| { + if let Ok(res) = result { + if let Ok(resp) = + serde_json::from_value::(res) + { + println!("load buffer head {}", resp.content); + event_sink.submit_command( + LAPCE_UI_COMMAND, + LapceUICommand::LoadBufferHead { + path, + content: Rope::from(resp.content), + id: resp.id, + }, + Target::Widget(tab_id), + ); + } + } + }), + ) + }); + } + } + + pub fn retrieve_file_history(&self) {} + pub fn retrieve_file( &self, tab_id: WidgetId, diff --git a/core/src/command.rs b/core/src/command.rs index 20c52c7e..3a9c3344 100644 --- a/core/src/command.rs +++ b/core/src/command.rs @@ -16,7 +16,7 @@ use strum_macros::{Display, EnumIter, EnumMessage, EnumProperty, EnumString}; use tree_sitter::Tree; use tree_sitter_highlight::Highlight; -use xi_rope::spans::Spans; +use xi_rope::{spans::Spans, Rope}; use crate::{ buffer::BufferId, @@ -411,6 +411,11 @@ pub enum LapceUICommand { content: String, locations: Vec<(WidgetId, EditorLocationNew)>, }, + LoadBufferHead { + path: PathBuf, + id: String, + content: Rope, + }, LoadBufferAndGoToPosition { path: PathBuf, content: String, @@ -420,6 +425,7 @@ pub enum LapceUICommand { SetWorkspace(LapceWorkspace), SetTheme(String, bool), OpenFile(PathBuf), + OpenFileDiff(PathBuf, String), CancelCompletion(usize), ResolveCompletion(BufferId, u64, usize, CompletionItem), UpdateCompletion(usize, String, CompletionResponse), diff --git a/core/src/data.rs b/core/src/data.rs index 443d6fde..e626f9b1 100644 --- a/core/src/data.rs +++ b/core/src/data.rs @@ -829,6 +829,7 @@ pub fn run_workbench_command( path: path.clone(), position: None, scroll_offset: None, + hisotry: None, }, &self.config, ); @@ -853,6 +854,7 @@ pub fn run_workbench_command( path: path.clone(), position: None, scroll_offset: None, + hisotry: None, }, &self.config, ); @@ -1592,6 +1594,7 @@ pub fn jump_to_position( path: path.clone(), position: Some(position), scroll_offset: None, + hisotry: None, }; self.jump_to_location(ctx, editor_view_id, location, config); } @@ -1653,8 +1656,19 @@ pub fn go_to_location( None => (buffer.cursor_offset, Some(&buffer.scroll_offset)), }; + if let Some(compare) = location.hisotry.as_ref() { + if !buffer.histories.contains_key(compare) { + buffer.retrieve_file_head( + *self.tab_id, + self.proxy.clone(), + ctx.get_external_handle(), + ); + } + } + let editor = self.get_editor_or_new(ctx, Some(editor_view_id), config); editor.content = BufferContent::File(path.clone()); + editor.compare = location.hisotry.clone(); editor.cursor = if config.lapce.modal { Cursor::new(CursorMode::Normal(offset), None) } else { @@ -1751,6 +1765,7 @@ pub fn new( e.scroll_offset.0, e.scroll_offset.1, )), + hisotry: None, }, )); @@ -1883,6 +1898,7 @@ pub struct LapceEditorData { pub split_id: Option, pub view_id: WidgetId, pub content: BufferContent, + pub compare: Option, pub scroll_offset: Vec2, pub cursor: Cursor, pub size: Rc>, @@ -1913,6 +1929,7 @@ pub fn new( Cursor::new(CursorMode::Insert(Selection::caret(0)), None) }, size: Rc::new(RefCell::new(Size::ZERO)), + compare: None, window_origin: Point::ZERO, snippet: None, locations: vec![], @@ -1956,6 +1973,7 @@ pub fn save_jump_location(&mut self, buffer: &BufferNew) { path: path.clone(), position: Some(buffer.offset_to_position(self.cursor.offset())), scroll_offset: Some(self.scroll_offset.clone()), + hisotry: None, }; self.locations.push(location); self.current_location = self.locations.len(); @@ -2302,6 +2320,7 @@ pub fn next_error(&mut self, ctx: &mut EventCtx, env: &Env) { path, position: Some(position), scroll_offset: None, + hisotry: None, }; ctx.submit_command(Command::new( LAPCE_UI_COMMAND, @@ -2775,6 +2794,7 @@ fn process_get_references( path: PathBuf::from(location.uri.path()), position: Some(location.range.start.clone()), scroll_offset: None, + hisotry: None, }, ), Target::Auto, diff --git a/core/src/editor.rs b/core/src/editor.rs index 98266642..fcaa6574 100644 --- a/core/src/editor.rs +++ b/core/src/editor.rs @@ -71,6 +71,8 @@ FontWeight, }; use fzyr::has_match; +use hashbrown::HashSet; +use indexmap::IndexMap; use itertools::Itertools; use lsp_types::CompletionTextEdit; use lsp_types::{ @@ -79,6 +81,7 @@ Location, Position, SignatureHelp, TextEdit, Url, WorkspaceEdit, }; use serde_json::Value; +use std::ops::Range; use std::thread; use std::{cmp::Ordering, iter::Iterator, path::PathBuf}; use std::{collections::HashMap, sync::Arc}; @@ -139,6 +142,7 @@ pub struct EditorLocationNew { pub path: PathBuf, pub position: Option, pub scroll_offset: Option, + pub hisotry: Option, } #[derive(Clone, Debug)] @@ -222,6 +226,19 @@ pub struct LapceEditorBufferData { pub config: Arc, } +pub enum DiffLines { + Left(Range), + Both(Range, Range), + Right(Range), +} + +#[derive(Hash, Eq, PartialEq, Clone)] +pub enum DiffCurrentLine { + Left(usize), + Both(usize, usize), + Right(usize), +} + impl LapceEditorBufferData { fn buffer_mut(&mut self) -> &mut BufferNew { Arc::make_mut(&mut self.buffer) @@ -994,6 +1011,7 @@ fn next_error(&mut self, ctx: &mut EventCtx, env: &Env) { path, position: Some(position), scroll_offset: None, + hisotry: None, }; ctx.submit_command(Command::new( LAPCE_UI_COMMAND, @@ -1325,7 +1343,9 @@ fn paint_content( let line_height = self.config.editor.line_height as f64; self.paint_cursor(ctx, is_focused, placeholder, config); self.paint_find(ctx); + let self_size = ctx.size(); let rect = ctx.region().bounding_box(); + let last_line = self.buffer.last_line(); let start_line = (rect.y0 / line_height).floor() as usize; let end_line = (rect.y1 / line_height).ceil() as usize; @@ -1340,6 +1360,340 @@ fn paint_content( .unwrap(); let y_shift = (line_height - text_layout.size().height) / 2.0; + if let Some(compare) = self.editor.compare.as_ref() { + if let Some(history) = self.buffer.histories.get(compare) { + let mut left_line = 0; + let mut right_line = 0; + let mut changes = IndexMap::new(); + let left_str = &history.slice_to_cow(0..history.len()); + let right_str = + &self.buffer.rope.slice_to_cow(0..self.buffer.rope.len()); + for diff in diff::lines(left_str, right_str) { + match diff { + diff::Result::Left(l) => { + let key = DiffCurrentLine::Right(right_line); + if !changes.contains_key(&key) { + changes.insert( + key.clone(), + DiffLines::Left(left_line..left_line), + ); + } + if let DiffLines::Left(range) = + changes.get_mut(&key).unwrap() + { + range.end = left_line; + } + left_line += 1; + } + diff::Result::Both(_, _) => { + if !changes + .last() + .map(|(key, value)| match key { + DiffCurrentLine::Both(_, _) => true, + _ => false, + }) + .unwrap_or(false) + { + changes.insert( + DiffCurrentLine::Both(left_line, right_line), + DiffLines::Both( + left_line..left_line, + right_line..right_line, + ), + ); + } + if let DiffLines::Both(left, right) = + changes.last_mut().unwrap().1 + { + left.end = left_line; + right.end = right_line; + } + + left_line += 1; + right_line += 1; + } + diff::Result::Right(_) => { + let key = DiffCurrentLine::Left(left_line); + if !changes.contains_key(&key) { + changes.insert( + key.clone(), + DiffLines::Right(right_line..right_line), + ); + } + if let DiffLines::Right(range) = + changes.get_mut(&key).unwrap() + { + range.end = right_line; + } + + right_line += 1; + } + } + } + + let mut line = 0; + for (key, change) in changes.iter() { + match change { + DiffLines::Left(range) => { + line += range.len(); + + if line < start_line { + continue; + } + ctx.fill( + Size::new( + self_size.width, + line_height * range.len() as f64, + ) + .to_rect() + .with_origin( + Point::new( + 0.0, + line_height * (line - range.len()) as f64, + ), + ), + &Color::RED, + ); + if line > end_line { + break; + } + } + DiffLines::Both(left, right) => { + line += right.len().min(6); + if line < start_line { + continue; + } + if line > end_line { + break; + } + } + DiffLines::Right(range) => { + line += range.len(); + + if line < start_line { + continue; + } + + ctx.fill( + Size::new( + self_size.width, + line_height * range.len() as f64, + ) + .to_rect() + .with_origin( + Point::new( + 0.0, + line_height * (line - range.len()) as f64, + ), + ), + &Color::GREEN, + ); + + if line > end_line { + break; + } + } + } + } + return; + + let mut line = 0; + let mut left_line = 0; + let mut changes = IndexMap::new(); + let mut deletes = IndexMap::new(); + let mut adds = HashSet::new(); + for diff in diff::lines( + &history.slice_to_cow(0..history.len()), + &self.buffer.rope.slice_to_cow(0..self.buffer.rope.len()), + ) { + match diff { + diff::Result::Left(l) => { + if !deletes.contains_key(&line) { + deletes.insert(line, vec![]); + } + deletes.get_mut(&line).unwrap().push(l.to_string()); + + if !changes.contains_key(&line) { + changes.insert(line, 0); + } + *changes.get_mut(&line).unwrap() -= 1; + } + diff::Result::Both(_, _) => { + line += 1; + } + diff::Result::Right(_) => { + adds.insert(line); + + let mut had_previous = false; + if let Some((last_line, last)) = changes.last_mut() { + if *last > 0 && *last_line + *last == line { + *last += 1; + had_previous = true; + } + } + if !had_previous { + changes.insert(line, 1); + } + + line += 1; + } + } + } + + let mut line = 0; + let mut deleted_lines = 0; + let mut skipped_lines = 0; + + for (changed_line, change) in changes.iter() {} + + for (delete_line, delete) in deletes.iter() { + if delete_line + deleted_lines + delete.len() < start_line { + deleted_lines += delete.len(); + continue; + } + if delete_line + deleted_lines < start_line { + for (i, deleted_str) in delete + [start_line - (delete_line + deleted_lines)..] + .iter() + .enumerate() + { + line = delete_line + deleted_lines + i; + if line > end_line { + break; + } + ctx.fill( + Size::new(self_size.width, line_height) + .to_rect() + .with_origin(Point::new( + 0.0, + line_height * line as f64, + )), + &Color::RED, + ); + let text_layout = ctx + .text() + .new_text_layout(deleted_str.to_string()) + .font( + config.editor.font_family(), + config.editor.font_size as f64, + ) + .build_with_bounds([rect.x0, rect.x1]); + ctx.draw_text( + &text_layout, + Point::new(0.0, line_height * line as f64 + y_shift), + ); + } + line += 1; + deleted_lines += delete.len(); + continue; + } + + if line < start_line { + line = start_line; + } + for i in line..delete_line + deleted_lines { + if line > end_line { + break; + } + let actual_line = line - deleted_lines; + if actual_line > last_line { + break; + } + if adds.contains(&actual_line) { + ctx.fill( + Size::new(self_size.width, line_height) + .to_rect() + .with_origin(Point::new( + 0.0, + line_height * line as f64, + )), + &Color::GREEN, + ); + } + let text_layout = self.buffer.new_text_layout( + ctx, + actual_line, + &self.buffer.line_content(actual_line), + None, + [rect.x0, rect.x1], + &self.config, + ); + ctx.draw_text( + &text_layout, + Point::new(0.0, line_height * line as f64 + y_shift), + ); + line += 1; + } + + for (i, deleted_str) in delete.iter().enumerate() { + line = delete_line + deleted_lines + i; + if line > end_line { + break; + } + + ctx.fill( + Size::new(self_size.width, line_height) + .to_rect() + .with_origin(Point::new( + 0.0, + line_height * line as f64, + )), + &Color::RED, + ); + let text_layout = ctx + .text() + .new_text_layout(deleted_str.to_string()) + .font( + config.editor.font_family(), + config.editor.font_size as f64, + ) + .build_with_bounds([rect.x0, rect.x1]); + ctx.draw_text( + &text_layout, + Point::new(0.0, line_height * line as f64 + y_shift), + ); + } + line += 1; + deleted_lines += delete.len(); + } + + if line < start_line { + line = start_line; + } + for i in line..end_line { + let actual_line = line - deleted_lines; + if actual_line > last_line { + break; + } + if adds.contains(&actual_line) { + ctx.fill( + Size::new(self_size.width, line_height) + .to_rect() + .with_origin(Point::new( + 0.0, + line_height * line as f64, + )), + &Color::GREEN, + ); + } + let text_layout = self.buffer.new_text_layout( + ctx, + actual_line, + &self.buffer.line_content(actual_line), + None, + [rect.x0, rect.x1], + &self.config, + ); + ctx.draw_text( + &text_layout, + Point::new(0.0, line_height * line as f64 + y_shift), + ); + line += 1; + } + return; + } + } + let cursor_offset = self.editor.cursor.offset(); let cursor_line = self.buffer.line_of_offset(cursor_offset); let start_offset = self.buffer.offset_of_line(start_line); @@ -2586,6 +2940,7 @@ fn run_command( location.range.start, ), scroll_offset: None, + hisotry: None, }, ), Target::Auto, @@ -4306,36 +4661,6 @@ fn paint(&mut self, ctx: &mut PaintCtx, data: &LapceTabData, env: &Env) { let is_focused = data.focus == self.view_id; let data = data.editor_view_content(self.view_id); data.paint_content(ctx, is_focused, self.placeholder.as_ref(), &data.config); - // LapceEditorViewContent::None => { - // let svg = logo_svg(); - // let size = ctx.size(); - // let svg_size = 100.0; - // let rect = Size::ZERO - // .to_rect() - // .with_origin( - // Point::new(size.width / 2.0, size.height / 2.0) - // + (0.0, -svg_size), - // ) - // .inflate(svg_size, svg_size); - // ctx.draw_svg( - // &svg, - // rect, - // Some( - // &data - // .config - // .get_color_unchecked(LapceTheme::EDITOR_DIM) - // .clone() - // .with_alpha(0.5), - // ), - // ); - // for (cmd, text, rect, keymap) in &self.commands { - // ctx.draw_text(text, rect.origin()); - // ctx.draw_text( - // keymap, - // rect.origin() + (20.0 + rect.width(), 0.0), - // ); - // } - // } } } @@ -4473,6 +4798,7 @@ fn process_get_references( path: PathBuf::from(location.uri.path()), position: Some(location.range.start.clone()), scroll_offset: None, + hisotry: None, }, ), Target::Auto, diff --git a/core/src/language.rs b/core/src/language.rs index 4631e864..edf01151 100644 --- a/core/src/language.rs +++ b/core/src/language.rs @@ -7,12 +7,6 @@ use tree_sitter::{Language, Parser}; use tree_sitter_highlight::HighlightConfiguration; -#[cfg(unix)] -const DYLIB_EXTENSION: &str = "so"; - -#[cfg(windows)] -const DYLIB_EXTENSION: &str = "dll"; - pub const QUERIES_DIR: Dir = include_dir!("../runtime/queries"); lazy_static! { pub static ref SCOPES: Vec = vec![ @@ -43,10 +37,8 @@ #[derive(Eq, PartialEq, Hash, Copy, Clone)] pub enum LapceLanguage { Rust, - Toml, Javascript, Go, - Yaml, } impl LapceLanguage { @@ -54,12 +46,12 @@ pub fn from_path(path: &PathBuf) -> Option { let extension = path.extension()?.to_str()?; Some(match extension { "rs" => LapceLanguage::Rust, - "toml" => LapceLanguage::Toml, "js" => LapceLanguage::Javascript, "jsx" => LapceLanguage::Javascript, "go" => LapceLanguage::Go, - "yaml" => LapceLanguage::Yaml, - "yml" => LapceLanguage::Yaml, + // "toml" => LapceLanguage::Toml, + // "yaml" => LapceLanguage::Yaml, + // "yml" => LapceLanguage::Yaml, _ => return None, }) } @@ -73,7 +65,7 @@ pub fn new_highlight_config(language: LapceLanguage) -> HighlightConfiguration { match language { LapceLanguage::Rust => { let mut configuration = HighlightConfiguration::new( - unsafe { tree_sitter_rust() }, + tree_sitter_rust::language(), QUERIES_DIR .get_file("rust/highlights.scm") .unwrap() @@ -86,24 +78,9 @@ pub fn new_highlight_config(language: LapceLanguage) -> HighlightConfiguration { configuration.configure(&SCOPES); configuration } - LapceLanguage::Toml => { - let mut configuration = HighlightConfiguration::new( - unsafe { tree_sitter_toml() }, - QUERIES_DIR - .get_file("toml/highlights.scm") - .unwrap() - .contents_utf8() - .unwrap(), - "", - "", - ) - .unwrap(); - configuration.configure(&SCOPES); - configuration - } LapceLanguage::Javascript => { let mut configuration = HighlightConfiguration::new( - unsafe { tree_sitter_javascript() }, + tree_sitter_javascript::language(), QUERIES_DIR .get_file("javascript/highlights.scm") .unwrap() @@ -116,24 +93,9 @@ pub fn new_highlight_config(language: LapceLanguage) -> HighlightConfiguration { configuration.configure(&SCOPES); configuration } - LapceLanguage::Yaml => { - let mut configuration = HighlightConfiguration::new( - unsafe { tree_sitter_yaml() }, - QUERIES_DIR - .get_file("yaml/highlights.scm") - .unwrap() - .contents_utf8() - .unwrap(), - "", - "", - ) - .unwrap(); - configuration.configure(&SCOPES); - configuration - } LapceLanguage::Go => { let mut configuration = HighlightConfiguration::new( - unsafe { tree_sitter_go() }, + tree_sitter_go::language(), QUERIES_DIR .get_file("go/highlights.scm") .unwrap() @@ -151,34 +113,11 @@ pub fn new_highlight_config(language: LapceLanguage) -> HighlightConfiguration { pub fn new_parser(language: LapceLanguage) -> Parser { let language = match language { - LapceLanguage::Rust => unsafe { tree_sitter_rust() }, - LapceLanguage::Toml => unsafe { tree_sitter_toml() }, - LapceLanguage::Javascript => unsafe { tree_sitter_javascript() }, - LapceLanguage::Go => unsafe { tree_sitter_go() }, - LapceLanguage::Yaml => unsafe { tree_sitter_yaml() }, + LapceLanguage::Rust => tree_sitter_rust::language(), + LapceLanguage::Javascript => tree_sitter_javascript::language(), + LapceLanguage::Go => tree_sitter_go::language(), }; let mut parser = Parser::new(); parser.set_language(language).unwrap(); parser } - -extern "C" { - fn tree_sitter_rust() -> Language; - fn tree_sitter_toml() -> Language; - fn tree_sitter_yaml() -> Language; - fn tree_sitter_go() -> Language; - fn tree_sitter_javascript() -> Language; -} - -// impl TreeSitter { -// pub fn new() -> TreeSitter { -// let mut parsers = HashMap::new(); -// -// let mut parser = Parser::new(); -// let language = tree_sitter_rust::language(); -// parser.set_language(language); -// parsers.insert(LapceLanguage::Rust, parser); -// -// TreeSitter { parsers } -// } -// } diff --git a/core/src/problem.rs b/core/src/problem.rs index 1459f0b7..fcc9f386 100644 --- a/core/src/problem.rs +++ b/core/src/problem.rs @@ -147,6 +147,7 @@ fn mouse_down( .unwrap_or(d.diagnositc.range.start.clone()), ), scroll_offset: None, + hisotry: None, }, ), Target::Widget(data.id), @@ -175,6 +176,7 @@ fn mouse_down( related.location.range.start.clone(), ), scroll_offset: None, + hisotry: None, }, ), Target::Widget(data.id), diff --git a/core/src/proxy.rs b/core/src/proxy.rs index 5b9c1d05..f7510ef1 100644 --- a/core/src/proxy.rs +++ b/core/src/proxy.rs @@ -277,6 +277,20 @@ pub fn install_plugin(&self, plugin: &PluginDescription) { .send_rpc_notification("install_plugin", &json!({ "plugin": plugin })); } + pub fn get_buffer_head( + &self, + buffer_id: BufferId, + path: PathBuf, + f: Box, + ) { + self.wait(); + self.peer.lock().as_ref().unwrap().send_rpc_request_async( + "buffer_head", + &json!({ "buffer_id": buffer_id, "path": path, }), + f, + ); + } + pub fn new_buffer( &self, buffer_id: BufferId, diff --git a/core/src/scroll.rs b/core/src/scroll.rs index badc299d..6c4cc625 100644 --- a/core/src/scroll.rs +++ b/core/src/scroll.rs @@ -1650,7 +1650,6 @@ pub fn handle_scroll( ) { if !ctx.is_handled() { if let Event::Wheel(mouse) = event { - println!("view port {} {}", port.rect, port.content_size); if port.pan_by(mouse.wheel_delta.round()) {} ctx.request_paint(); self.reset_scrollbar_fade(|d| ctx.request_timer(d), env); diff --git a/core/src/source_control.rs b/core/src/source_control.rs index aa7d3893..6d631f60 100644 --- a/core/src/source_control.rs +++ b/core/src/source_control.rs @@ -239,6 +239,15 @@ fn event( source_control.file_list_index = line; if mouse_event.pos.x < line_height { self.mouse_down = Some(line); + } else { + ctx.submit_command(Command::new( + LAPCE_UI_COMMAND, + LapceUICommand::OpenFileDiff( + source_control.diff_files[line].0.clone(), + "head".to_string(), + ), + Target::Widget(data.id), + )); } } } diff --git a/core/src/tab.rs b/core/src/tab.rs index 92e7131f..925ff83a 100644 --- a/core/src/tab.rs +++ b/core/src/tab.rs @@ -279,6 +279,13 @@ fn event( } ctx.set_handled(); } + LapceUICommand::LoadBufferHead { path, id, content } => { + let buffer = + data.main_split.open_files.get_mut(path).unwrap(); + let buffer = Arc::make_mut(buffer); + buffer.histories.insert(id.clone(), content.clone()); + ctx.set_handled(); + } LapceUICommand::UpdateTerminalTitle(term_id, title) => { let terminal_panel = Arc::make_mut(&mut data.terminal); if let Some(mut terminal) = @@ -427,6 +434,21 @@ fn event( ); ctx.set_handled(); } + LapceUICommand::OpenFileDiff(path, history) => { + let editor_view_id = data.main_split.active.clone(); + data.main_split.jump_to_location( + ctx, + *editor_view_id, + EditorLocationNew { + path: path.clone(), + position: None, + scroll_offset: None, + hisotry: Some(history.to_string()), + }, + &data.config, + ); + ctx.set_handled(); + } LapceUICommand::OpenFile(path) => { let editor_view_id = data.main_split.active.clone(); data.main_split.jump_to_location( @@ -436,6 +458,7 @@ fn event( path: path.clone(), position: None, scroll_offset: None, + hisotry: None, }, &data.config, ); @@ -555,6 +578,7 @@ fn event( path: PathBuf::from(l.uri.path()), position: Some(l.range.start.clone()), scroll_offset: None, + hisotry: None, }) .collect(); ctx.submit_command(Command::new( diff --git a/proxy/src/dispatch.rs b/proxy/src/dispatch.rs index eacf6320..9439ea61 100644 --- a/proxy/src/dispatch.rs +++ b/proxy/src/dispatch.rs @@ -5,7 +5,7 @@ use crate::terminal::{TermId, Terminal}; use alacritty_terminal::event_loop::Msg; use alacritty_terminal::term::SizeInfo; -use anyhow::{anyhow, Result}; +use anyhow::{anyhow, Context, Result}; use crossbeam_channel::{unbounded, Receiver, Sender}; use git2::{DiffOptions, Oid, Repository}; use jsonrpc_lite::{self, JsonRpc}; @@ -145,6 +145,10 @@ pub enum Request { buffer_id: BufferId, path: PathBuf, }, + BufferHead { + buffer_id: BufferId, + path: PathBuf, + }, GetCompletion { request_id: usize, buffer_id: BufferId, @@ -194,6 +198,12 @@ pub struct NewBufferResponse { pub content: String, } +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct BufferHeadResponse { + pub id: String, + pub content: String, +} + #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] pub struct FileNodeItem { pub path_buf: PathBuf, @@ -521,6 +531,20 @@ fn handle_request(&self, id: RequestId, rpc: Request) { "result": resp, })); } + Request::BufferHead { buffer_id, path } => { + let workspace = self.workspace.lock().clone(); + let result = file_get_head(&workspace, &path); + if let Ok((blob_id, content)) = result { + let resp = BufferHeadResponse { + id: "head".to_string(), + content, + }; + self.sender.send(json!({ + "id": id, + "result": resp, + })); + } + } Request::GetCompletion { buffer_id, position, @@ -706,6 +730,23 @@ fn git_diff(workspace_path: &PathBuf) -> Option> { Some(diff_files) } +fn file_get_head( + workspace_path: &PathBuf, + path: &PathBuf, +) -> Result<(String, String)> { + let repo = + Repository::open(workspace_path.to_str().ok_or(anyhow!("can't to str"))?)?; + let head = repo.head()?; + let tree = head.peel_to_tree()?; + let tree_entry = tree.get_path(path.strip_prefix(workspace_path)?)?; + let blob = repo.find_blob(tree_entry.id())?; + let id = blob.id().to_string(); + let content = std::str::from_utf8(blob.content()) + .with_context(|| "content bytes to string")? + .to_string(); + Ok((id, content)) +} + fn file_git_diff( workspace_path: &PathBuf, path: &PathBuf,