mirror of https://github.com/lapce/lapce.git
change tree sitter to use crates
This commit is contained in:
parent
07a85e4ac6
commit
5592a6bcd0
|
@ -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
|
|
@ -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"
|
||||
|
|
|
@ -5,6 +5,7 @@ authors = ["Dongdong Zhou <dzhou121@gmail.com>"]
|
|||
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"
|
||||
|
|
|
@ -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<Vec<String>> {
|
||||
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);
|
||||
}
|
||||
}
|
|
@ -1 +0,0 @@
|
|||
Subproject commit 0fa917a7022d1cd2e9b779a6a8fc5dc7fad69c75
|
|
@ -1 +0,0 @@
|
|||
Subproject commit fdeb68ac8d2bd5a78b943528bb68ceda3aade2eb
|
|
@ -1 +0,0 @@
|
|||
Subproject commit eeb0702ebdac504b97196577b1dac43c80913d7b
|
|
@ -1 +0,0 @@
|
|||
Subproject commit 8bd2056818b21860e3d756b5a58c4f6e05fb744e
|
|
@ -1 +0,0 @@
|
|||
Subproject commit 0e36bed171768908f331ff7dff9d956bae016efb
|
|
@ -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<Sender<UpdateEvent>>,
|
||||
pub line_changes: HashMap<usize, char>,
|
||||
pub histories: im::HashMap<String, Rope>,
|
||||
|
||||
pub find: Rc<RefCell<Find>>,
|
||||
pub find_progress: Rc<RefCell<FindProgress>>,
|
||||
|
@ -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<LapceProxy>,
|
||||
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::<BufferHeadResponse>(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,
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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<WidgetId>,
|
||||
pub view_id: WidgetId,
|
||||
pub content: BufferContent,
|
||||
pub compare: Option<String>,
|
||||
pub scroll_offset: Vec2,
|
||||
pub cursor: Cursor,
|
||||
pub size: Rc<RefCell<Size>>,
|
||||
|
@ -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,
|
||||
|
|
|
@ -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<Position>,
|
||||
pub scroll_offset: Option<Vec2>,
|
||||
pub hisotry: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
|
@ -222,6 +226,19 @@ pub struct LapceEditorBufferData {
|
|||
pub config: Arc<Config>,
|
||||
}
|
||||
|
||||
pub enum DiffLines {
|
||||
Left(Range<usize>),
|
||||
Both(Range<usize>, Range<usize>),
|
||||
Right(Range<usize>),
|
||||
}
|
||||
|
||||
#[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,
|
||||
|
|
|
@ -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<String> = 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<LapceLanguage> {
|
|||
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 }
|
||||
// }
|
||||
// }
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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<dyn Callback>,
|
||||
) {
|
||||
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,
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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),
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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<Vec<String>> {
|
|||
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,
|
||||
|
|
Loading…
Reference in New Issue