first pass of merging in warp (doesn't build)
This commit is contained in:
@@ -1,38 +1,34 @@
|
||||
mod queries;
|
||||
use languages::Language;
|
||||
pub use queries::highlight_query::{ColorMap, TextSlice};
|
||||
|
||||
use std::{
|
||||
cell::{Ref, RefCell},
|
||||
collections::{HashMap, HashSet},
|
||||
sync::Arc,
|
||||
};
|
||||
|
||||
use parking_lot::Mutex;
|
||||
use std::cell::{Ref, RefCell};
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::sync::Arc;
|
||||
|
||||
use arborium::tree_sitter::{InputEdit, Parser, Tree};
|
||||
use futures::stream::AbortHandle;
|
||||
use galaxyui::{color::ColorU, AppContext, Entity, ModelContext, WeakModelHandle};
|
||||
use queries::{
|
||||
highlight_query::HighlightQuery,
|
||||
indent_query::{indentation_delta, IndentDelta},
|
||||
};
|
||||
use languages::Language;
|
||||
use parking_lot::Mutex;
|
||||
use queries::highlight_query::HighlightQuery;
|
||||
pub use queries::highlight_query::{ColorMap, TextSlice};
|
||||
use queries::indent_query::{indentation_delta, IndentDelta};
|
||||
use rangemap::{RangeMap, RangeSet};
|
||||
use string_offset::{ByteOffset, CharOffset};
|
||||
|
||||
use galaxy_editor::{
|
||||
content::{
|
||||
buffer::{Buffer, BufferSnapshot},
|
||||
edit::PreciseDelta,
|
||||
text::IndentUnit,
|
||||
version::BufferVersion,
|
||||
},
|
||||
decoration::DecorationLayer,
|
||||
};
|
||||
use galaxyui::text::point::Point;
|
||||
use galaxy_editor::content::buffer::{Buffer, BufferSnapshot};
|
||||
use galaxy_editor::content::edit::PreciseDelta;
|
||||
use galaxy_editor::content::text::IndentUnit;
|
||||
use galaxy_editor::content::version::BufferVersion;
|
||||
use galaxy_editor::decoration::DecorationLayer;
|
||||
use galaxyui_core::color::ColorU;
|
||||
use galaxyui_core::text::point::Point;
|
||||
use galaxyui_core::{AppContext, Entity, ModelContext, WeakModelHandle};
|
||||
|
||||
const MAX_SYNTAX_TREES: usize = 3;
|
||||
|
||||
/// Maximum buffer size in bytes for which we attempt to parse a syntax tree.
|
||||
/// Files larger than this are skipped to avoid tree-sitter's super-linear
|
||||
/// memory growth on large inputs. See this tree-sitter issue:
|
||||
/// https://github.com/tree-sitter/tree-sitter/issues/222#issuecomment-435987441
|
||||
const MAX_PARSE_BYTES: usize = 2 * 1024 * 1024; // 2 MB
|
||||
|
||||
thread_local! {
|
||||
static PARSER: RefCell<Parser> = RefCell::new(Parser::new());
|
||||
}
|
||||
@@ -225,12 +221,17 @@ impl SyntaxTreeState {
|
||||
}
|
||||
|
||||
/// Re-parse the tree based on the updated tree and source content.
|
||||
///
|
||||
/// Returns `None` if the buffer exceeds [`MAX_PARSE_BYTES`].
|
||||
async fn parse_text(
|
||||
content: BufferSnapshot,
|
||||
old_tree: Option<Tree>,
|
||||
language: &Language,
|
||||
) -> Tree {
|
||||
PARSER.with(|parser| {
|
||||
) -> Option<Tree> {
|
||||
if content.byte_len() > MAX_PARSE_BYTES {
|
||||
return None;
|
||||
}
|
||||
Some(PARSER.with(|parser| {
|
||||
let mut parser = parser.borrow_mut();
|
||||
parser
|
||||
.set_language(&language.grammar)
|
||||
@@ -244,7 +245,7 @@ impl SyntaxTreeState {
|
||||
parser
|
||||
.parse_with_options(&mut callback, old_tree.as_ref(), None)
|
||||
.expect("Should succeed")
|
||||
})
|
||||
}))
|
||||
}
|
||||
|
||||
/// Translate an incoming edit delta into an InputEdit for incrementally updating the syntax
|
||||
@@ -355,6 +356,17 @@ impl DecorationLayer for SyntaxTreeState {
|
||||
new_tree
|
||||
},
|
||||
move |model, new_tree, ctx| {
|
||||
let Some(new_tree) = new_tree else {
|
||||
// Buffer exceeded MAX_PARSE_BYTES; skip updating the syntax tree, but
|
||||
// still emit DecorationUpdated so any delayed rendering is flushed
|
||||
let mut syntax_tree_lock = model.syntax_tree.lock();
|
||||
syntax_tree_lock.remove(&version);
|
||||
drop(syntax_tree_lock);
|
||||
model.invalidate_highlight_cache_for_version(version);
|
||||
// (the editor delays showing content until this event fires).
|
||||
ctx.emit(DecorationStateEvent::DecorationUpdated { version });
|
||||
return;
|
||||
};
|
||||
let mut syntax_tree_lock = model.syntax_tree.lock();
|
||||
model.invalidate_highlight_cache_for_version(version);
|
||||
if let Some(old_tree) = syntax_tree_lock.get_mut(&version) {
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
use std::{iter, ops::Range};
|
||||
use std::iter;
|
||||
use std::ops::Range;
|
||||
|
||||
use arborium::tree_sitter::{Node, Query, QueryCursor, TextProvider, Tree};
|
||||
use galaxy_editor::content::{
|
||||
buffer::{Buffer, ToBufferByteOffset, ToBufferCharOffset},
|
||||
text::Bytes,
|
||||
};
|
||||
use galaxyui::color::ColorU;
|
||||
use rangemap::RangeMap;
|
||||
use streaming_iterator::StreamingIterator;
|
||||
use string_offset::{ByteOffset, CharOffset};
|
||||
use galaxy_editor::content::buffer::{Buffer, ToBufferByteOffset, ToBufferCharOffset};
|
||||
use galaxy_editor::content::text::Bytes;
|
||||
use galaxyui_core::color::ColorU;
|
||||
|
||||
/// Color mapping from parsed syntax token name to its corresponding highlighting color.
|
||||
#[derive(Clone, Copy)]
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
use std::{collections::HashMap, ops::Range};
|
||||
use std::collections::HashMap;
|
||||
use std::ops::Range;
|
||||
|
||||
use arborium::tree_sitter::{Node, Query, QueryCursor, Tree};
|
||||
use galaxy_editor::content::buffer::Buffer;
|
||||
use galaxyui::text::point::Point;
|
||||
use streaming_iterator::StreamingIterator;
|
||||
use galaxyui_core::text::point::Point;
|
||||
|
||||
use super::highlight_query::TextBuffer;
|
||||
|
||||
|
||||
@@ -6,28 +6,34 @@ use galaxy_editor::content::selection_model::BufferSelectionModel;
|
||||
use galaxy_editor::content::text::IndentBehavior;
|
||||
use galaxyui::App;
|
||||
use languages::{language_by_filename, Language};
|
||||
|
||||
use crate::SyntaxTreeState;
|
||||
use galaxy_util::standardized_path::StandardizedPath;
|
||||
use galaxyui_core::App;
|
||||
|
||||
use super::*;
|
||||
use crate::SyntaxTreeState;
|
||||
|
||||
// Simple stub function to allow compilation - can be improved later
|
||||
fn mock_buffer_and_tree(text_content: &str, language: Arc<Language>) -> (Buffer, Tree) {
|
||||
// Create a tree by parsing the text
|
||||
let snapshot = BufferSnapshot::from_plain_text(text_content);
|
||||
let tree = galaxyui::r#async::block_on(async {
|
||||
let tree = galaxyui_core::r#async::block_on(async {
|
||||
SyntaxTreeState::parse_text(snapshot, None, &language).await
|
||||
});
|
||||
})
|
||||
.expect("test buffer is small and should parse");
|
||||
|
||||
// Create a minimal buffer
|
||||
let buffer = Buffer::new(Box::new(|_, _| IndentBehavior::Ignore));
|
||||
(buffer, tree)
|
||||
}
|
||||
|
||||
fn test_path(filename: &str) -> StandardizedPath {
|
||||
StandardizedPath::try_new(&format!("/{filename}")).expect("test path should be absolute")
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_indent_query() {
|
||||
App::test((), |mut app| async move {
|
||||
let language = language_by_filename(std::path::Path::new("test.rs"))
|
||||
let language = language_by_filename(&test_path("test.rs"))
|
||||
.expect("Should contain language rule for rust");
|
||||
let text_content = r#"impl Test {
|
||||
fn first_func() {
|
||||
@@ -55,9 +61,10 @@ fn test_indent_query() {
|
||||
});
|
||||
|
||||
let buffer_snapshot = buffer_handle.read(&app, |buffer, _| buffer.buffer_snapshot());
|
||||
let tree = galaxyui::r#async::block_on(async {
|
||||
let tree = galaxyui_core::r#async::block_on(async {
|
||||
SyntaxTreeState::parse_text(buffer_snapshot, None, &language).await
|
||||
});
|
||||
})
|
||||
.expect("test buffer is small and should parse");
|
||||
|
||||
let query = language.as_ref().indents_query.as_ref().unwrap();
|
||||
|
||||
@@ -116,7 +123,7 @@ fn test_indent_query() {
|
||||
#[test]
|
||||
fn test_indent_query_on_go() {
|
||||
App::test((), |mut app| async move {
|
||||
let language = language_by_filename(std::path::Path::new("test.go"))
|
||||
let language = language_by_filename(&test_path("test.go"))
|
||||
.expect("Should contain language rule for go");
|
||||
let text_content = r#"package logic
|
||||
import (
|
||||
@@ -151,9 +158,10 @@ fn test_indent_query_on_go() {
|
||||
});
|
||||
|
||||
let buffer_snapshot = buffer_handle.read(&app, |buffer, _| buffer.buffer_snapshot());
|
||||
let tree = galaxyui::r#async::block_on(async {
|
||||
let tree = galaxyui_core::r#async::block_on(async {
|
||||
SyntaxTreeState::parse_text(buffer_snapshot, None, &language).await
|
||||
});
|
||||
})
|
||||
.expect("test buffer is small and should parse");
|
||||
|
||||
let query = &language.as_ref().indents_query.as_ref().unwrap();
|
||||
|
||||
@@ -210,8 +218,8 @@ fn test_indent_query_on_go() {
|
||||
|
||||
#[test]
|
||||
fn test_indent_query_on_go_bracket_expansion() {
|
||||
let language = language_by_filename(std::path::Path::new("test.go"))
|
||||
.expect("Should contain language rule for go");
|
||||
let language =
|
||||
language_by_filename(&test_path("test.go")).expect("Should contain language rule for go");
|
||||
let (buffer, tree) = mock_buffer_and_tree(
|
||||
r#"func test(){}
|
||||
func test() {
|
||||
@@ -250,7 +258,7 @@ fn test_indent_query_on_go_bracket_expansion() {
|
||||
// source: https://peps.python.org/pep-0008/#indentation
|
||||
#[test]
|
||||
fn test_indent_query_on_python() {
|
||||
let language = language_by_filename(std::path::Path::new("test.py"))
|
||||
let language = language_by_filename(&test_path("test.py"))
|
||||
.expect("Should contain language rule for python");
|
||||
let (buffer, tree) = mock_buffer_and_tree(
|
||||
r#"# Aligned with opening delimiter.
|
||||
@@ -300,7 +308,7 @@ fn test_indent_query_on_python() {
|
||||
|
||||
#[test]
|
||||
fn test_indent_query_on_python_colon() {
|
||||
let language = language_by_filename(std::path::Path::new("test.py"))
|
||||
let language = language_by_filename(&test_path("test.py"))
|
||||
.expect("Should contain language rule for python");
|
||||
let (if_buffer, if_tree) = mock_buffer_and_tree(r#"if x:"#, language.clone());
|
||||
let query = &language.as_ref().indents_query.as_ref().unwrap();
|
||||
@@ -601,7 +609,7 @@ def foo():
|
||||
|
||||
#[test]
|
||||
fn test_indent_query_on_javascript() {
|
||||
let language = language_by_filename(std::path::Path::new("test.js"))
|
||||
let language = language_by_filename(&test_path("test.js"))
|
||||
.expect("Should contain language rule for javascript");
|
||||
let (buffer, tree) = mock_buffer_and_tree(
|
||||
r#"// Import the 'fs' module, commonly used for file operations
|
||||
@@ -661,7 +669,7 @@ fn test_indent_query_on_javascript() {
|
||||
|
||||
#[test]
|
||||
fn test_indent_query_on_typescript() {
|
||||
let language = language_by_filename(std::path::Path::new("test.ts"))
|
||||
let language = language_by_filename(&test_path("test.ts"))
|
||||
.expect("Should contain language rule for typescript");
|
||||
let (buffer, tree) = mock_buffer_and_tree(
|
||||
r#"import { User } from './types';
|
||||
|
||||
Reference in New Issue
Block a user