use super::*;use crate::{ display_map::{DisplayMap, FoldMap, InlayMap}, test::editor_test_context::EditorTestContext,};use gpui::{Context, TestAppContext};use language::{Language, LanguageConfig, LanguageMatcher, LanguageRegistry};use multi_buffer::MultiBuffer;use project::Project;use std::sync::Arc; #[gpui::test]async fn test_markdown_link_folding(cx: &mut TestAppContext) { init_test(cx); let mut cx = EditorTestContext::new(cx).await; // Set up markdown language with folding query cx.update_buffer(|buffer, cx| { let registry = LanguageRegistry::test(cx.background_executor().clone()); let markdown = Arc::new(Language::new( LanguageConfig { name: "Markdown".into(), matcher: LanguageMatcher { path_suffixes: vec!["md".to_string()], ..Default::default() }, ..Default::default() }, None, )); registry.add(markdown.clone()); buffer.set_language_registry(registry); buffer.set_language(Some(markdown), cx); }); // Add markdown content with links cx.set_state(indoc! {" # Channel Notes Check out [our website](https://example.com) for more info. Here's a [link to docs](https://docs.example.com/guide) that you should read. And another [reference](https://reference.example.com). "}); cx.update_editor(|editor, cx| { // Enable syntax folding let display_map = editor.display_map.update(cx, |map, cx| { map.syntax_fold_config = SyntaxFoldConfig { enabled: true, auto_fold_on_open: true, proximity_expand_distance: 2, }; map.detect_syntax_folds(cx); }); // Verify folds were created for each link let snapshot = editor.snapshot(cx); let fold_count = snapshot.fold_count(); assert_eq!(fold_count, 3, "Should have 3 folds for 3 links"); });} #[gpui::test]async fn test_link_proximity_expansion(cx: &mut TestAppContext) { init_test(cx); let mut cx = EditorTestContext::new(cx).await; // Set up markdown with a single link cx.set_state(indoc! {" Check out [this link](https://example.com) for details. "}); cx.update_editor(|editor, cx| { // Enable syntax folding with proximity expansion editor.display_map.update(cx, |map, cx| { map.syntax_fold_config = SyntaxFoldConfig { enabled: true, auto_fold_on_open: true, proximity_expand_distance: 3, }; map.detect_syntax_folds(cx); }); }); // Move cursor near the link cx.set_selections_state(indoc! {" Check out |[this link](https://example.com) for details. "}); cx.update_editor(|editor, cx| { let display_map = editor.display_map.update(cx, |map, cx| { // Simulate cursor movement handling let cursor_offset = editor.selections.newest::<usize>(cx).head(); map.handle_cursor_movement(cursor_offset, cx); }); // Verify link is expanded due to proximity let snapshot = editor.snapshot(cx); let expanded_count = snapshot.expanded_fold_count(); assert_eq!( expanded_count, 1, "Link should be expanded when cursor is near" ); }); // Move cursor away from the link cx.set_selections_state(indoc! {" Check out [this link](https://example.com) for details.| "}); cx.update_editor(|editor, cx| { let display_map = editor.display_map.update(cx, |map, cx| { let cursor_offset = editor.selections.newest::<usize>(cx).head(); map.handle_cursor_movement(cursor_offset, cx); }); // Verify link is folded again let snapshot = editor.snapshot(cx); let expanded_count = snapshot.expanded_fold_count(); assert_eq!( expanded_count, 0, "Link should be folded when cursor moves away" ); });} #[gpui::test]async fn test_link_click_action(cx: &mut TestAppContext) { init_test(cx); let mut cx = EditorTestContext::new(cx).await; cx.set_state(indoc! {" Visit [GitHub](https://github.com) for code. "}); cx.update_editor(|editor, cx| { editor.display_map.update(cx, |map, cx| { map.syntax_fold_config = SyntaxFoldConfig { enabled: true, auto_fold_on_open: true, proximity_expand_distance: 2, }; map.detect_syntax_folds(cx); }); }); // Simulate clicking on the folded link cx.update_editor(|editor, cx| { let point = editor.pixel_position_of_cursor(cx); // Find fold at click position let display_map = editor.display_map.read(cx); let snapshot = display_map.snapshot(cx); let click_offset = snapshot.display_point_to_offset(point, cx); if let Some(fold) = display_map.syntax_fold_at_offset(click_offset) { // Verify the fold has the correct URL action assert!(matches!( fold.action_data, Some(FoldAction::OpenUrl(ref url)) if url == "https://github.com" )); // Execute the action (in tests, this would be mocked) display_map.execute_fold_action(&fold, cx); } else { panic!("No fold found at click position"); } });} #[gpui::test]async fn test_nested_markdown_structures(cx: &mut TestAppContext) { init_test(cx); let mut cx = EditorTestContext::new(cx).await; // Test with nested brackets and complex markdown cx.set_state(indoc! {" # Documentation See [the [nested] guide](https://example.com/guide) for details.  Code: `[not a link](just code)` > Quote with [link in quote](https://quoted.com) "}); cx.update_editor(|editor, cx| { editor.display_map.update(cx, |map, cx| { map.syntax_fold_config = SyntaxFoldConfig { enabled: true, auto_fold_on_open: true, proximity_expand_distance: 2, }; map.detect_syntax_folds(cx); }); // Verify correct number of folds (should not fold code block content) let snapshot = editor.snapshot(cx); let fold_count = snapshot.fold_count(); assert_eq!( fold_count, 3, "Should have 3 folds: nested link, image, and quote link" ); });} #[gpui::test]async fn test_fold_persistence_across_edits(cx: &mut TestAppContext) { init_test(cx); let mut cx = EditorTestContext::new(cx).await; cx.set_state(indoc! {" First [link one](https://one.com) here. Second [link two](https://two.com) here. "}); cx.update_editor(|editor, cx| { editor.display_map.update(cx, |map, cx| { map.syntax_fold_config = SyntaxFoldConfig { enabled: true, auto_fold_on_open: true, proximity_expand_distance: 2, }; map.detect_syntax_folds(cx); }); }); // Edit text between links cx.set_selections_state(indoc! {" First [link one](https://one.com) here|. Second [link two](https://two.com) here. "}); cx.simulate_keystroke(" and more text"); cx.update_editor(|editor, cx| { // Verify folds are maintained after edit let snapshot = editor.snapshot(cx); let fold_count = snapshot.fold_count(); assert_eq!(fold_count, 2, "Both folds should persist after edit"); }); // Add a new link cx.simulate_keystroke("\nThird [link three](https://three.com) added."); cx.update_editor(|editor, cx| { // Verify new fold is detected let snapshot = editor.snapshot(cx); let fold_count = snapshot.fold_count(); assert_eq!(fold_count, 3, "New fold should be detected for added link"); });} #[gpui::test]async fn test_channel_notes_integration(cx: &mut TestAppContext) { init_test(cx); let mut cx = EditorTestContext::new(cx).await; // Simulate channel notes content with many links cx.set_state(indoc! {" # Project Resources ## Documentation - [API Reference](https://api.example.com/docs) - [User Guide](https://guide.example.com) - [Developer Handbook](https://dev.example.com/handbook) ## Tools - [Build Status](https://ci.example.com/status) - [Issue Tracker](https://issues.example.com) - [Code Review](https://review.example.com) ## External Links - [Blog Post](https://blog.example.com/announcement) - [Video Tutorial](https://youtube.com/watch?v=demo) - [Community Forum](https://forum.example.com) "}); cx.update_editor(|editor, cx| { editor.display_map.update(cx, |map, cx| { map.syntax_fold_config = SyntaxFoldConfig { enabled: true, auto_fold_on_open: true, proximity_expand_distance: 2, }; map.detect_syntax_folds(cx); }); // Verify all links are folded let snapshot = editor.snapshot(cx); let fold_count = snapshot.fold_count(); assert_eq!(fold_count, 9, "All 9 links should be folded"); // Verify visual appearance (folded links show only text) let display_text = snapshot.display_text(); assert!(display_text.contains("API Reference")); assert!(!display_text.contains("https://api.example.com/docs")); });} fn init_test(cx: &mut TestAppContext) { cx.update(|cx| { let settings = crate::test::test_settings(cx); cx.set_global(settings); theme::init(theme::LoadThemes::JustBase, cx); language::init(cx); crate::init(cx); });}
use super::*;
use crate::{
display_map::{DisplayMap, FoldMap, InlayMap},
test::editor_test_context::EditorTestContext,
};
use gpui::{Context, TestAppContext};
use language::{Language, LanguageConfig, LanguageMatcher, LanguageRegistry};
use multi_buffer::MultiBuffer;
use project::Project;
use std::sync::Arc;
#[gpui::test]
async fn test_markdown_link_folding(cx: &mut TestAppContext) {
init_test(cx);
let mut cx = EditorTestContext::new(cx).await;
// Set up markdown language with folding query
cx.update_buffer(|buffer, cx| {
let registry = LanguageRegistry::test(cx.background_executor().clone());
let markdown = Arc::new(Language::new(
LanguageConfig {
name: "Markdown".into(),
matcher: LanguageMatcher {
path_suffixes: vec!["md".to_string()],
..Default::default()
},
..Default::default()
},
None,
));
registry.add(markdown.clone());
buffer.set_language_registry(registry);
buffer.set_language(Some(markdown), cx);
});
// Add markdown content with links
cx.set_state(indoc! {"
# Channel Notes
Check out [our website](https://example.com) for more info.
Here's a [link to docs](https://docs.example.com/guide) that you should read.
And another [reference](https://reference.example.com).
"});
cx.update_editor(|editor, cx| {
// Enable syntax folding
let display_map = editor.display_map.update(cx, |map, cx| {
map.syntax_fold_config = SyntaxFoldConfig {
enabled: true,
auto_fold_on_open: true,
proximity_expand_distance: 2,
};
map.detect_syntax_folds(cx);
});
// Verify folds were created for each link
let snapshot = editor.snapshot(cx);
let fold_count = snapshot.fold_count();
assert_eq!(fold_count, 3, "Should have 3 folds for 3 links");
});
}
#[gpui::test]
async fn test_link_proximity_expansion(cx: &mut TestAppContext) {
init_test(cx);
let mut cx = EditorTestContext::new(cx).await;
// Set up markdown with a single link
cx.set_state(indoc! {"
Check out [this link](https://example.com) for details.
"});
cx.update_editor(|editor, cx| {
// Enable syntax folding with proximity expansion
editor.display_map.update(cx, |map, cx| {
map.syntax_fold_config = SyntaxFoldConfig {
enabled: true,
auto_fold_on_open: true,
proximity_expand_distance: 3,
};
map.detect_syntax_folds(cx);
});
});
// Move cursor near the link
cx.set_selections_state(indoc! {"
Check out |[this link](https://example.com) for details.
"});
cx.update_editor(|editor, cx| {
let display_map = editor.display_map.update(cx, |map, cx| {
// Simulate cursor movement handling
let cursor_offset = editor.selections.newest::<usize>(cx).head();
map.handle_cursor_movement(cursor_offset, cx);
});
// Verify link is expanded due to proximity
let snapshot = editor.snapshot(cx);
let expanded_count = snapshot.expanded_fold_count();
assert_eq!(
expanded_count, 1,
"Link should be expanded when cursor is near"
);
});
// Move cursor away from the link
cx.set_selections_state(indoc! {"
Check out [this link](https://example.com) for details.|
"});
cx.update_editor(|editor, cx| {
let display_map = editor.display_map.update(cx, |map, cx| {
let cursor_offset = editor.selections.newest::<usize>(cx).head();
map.handle_cursor_movement(cursor_offset, cx);
});
// Verify link is folded again
let snapshot = editor.snapshot(cx);
let expanded_count = snapshot.expanded_fold_count();
assert_eq!(
expanded_count, 0,
"Link should be folded when cursor moves away"
);
});
}
#[gpui::test]
async fn test_link_click_action(cx: &mut TestAppContext) {
init_test(cx);
let mut cx = EditorTestContext::new(cx).await;
cx.set_state(indoc! {"
Visit [GitHub](https://github.com) for code.
"});
cx.update_editor(|editor, cx| {
editor.display_map.update(cx, |map, cx| {
map.syntax_fold_config = SyntaxFoldConfig {
enabled: true,
auto_fold_on_open: true,
proximity_expand_distance: 2,
};
map.detect_syntax_folds(cx);
});
});
// Simulate clicking on the folded link
cx.update_editor(|editor, cx| {
let point = editor.pixel_position_of_cursor(cx);
// Find fold at click position
let display_map = editor.display_map.read(cx);
let snapshot = display_map.snapshot(cx);
let click_offset = snapshot.display_point_to_offset(point, cx);
if let Some(fold) = display_map.syntax_fold_at_offset(click_offset) {
// Verify the fold has the correct URL action
assert!(matches!(
fold.action_data,
Some(FoldAction::OpenUrl(ref url)) if url == "https://github.com"
));
// Execute the action (in tests, this would be mocked)
display_map.execute_fold_action(&fold, cx);
} else {
panic!("No fold found at click position");
}
});
}
#[gpui::test]
async fn test_nested_markdown_structures(cx: &mut TestAppContext) {
init_test(cx);
let mut cx = EditorTestContext::new(cx).await;
// Test with nested brackets and complex markdown
cx.set_state(indoc! {"
# Documentation
See [the [nested] guide](https://example.com/guide) for details.

Code: `[not a link](just code)`
> Quote with [link in quote](https://quoted.com)
"});
cx.update_editor(|editor, cx| {
editor.display_map.update(cx, |map, cx| {
map.syntax_fold_config = SyntaxFoldConfig {
enabled: true,
auto_fold_on_open: true,
proximity_expand_distance: 2,
};
map.detect_syntax_folds(cx);
});
// Verify correct number of folds (should not fold code block content)
let snapshot = editor.snapshot(cx);
let fold_count = snapshot.fold_count();
assert_eq!(
fold_count, 3,
"Should have 3 folds: nested link, image, and quote link"
);
});
}
#[gpui::test]
async fn test_fold_persistence_across_edits(cx: &mut TestAppContext) {
init_test(cx);
let mut cx = EditorTestContext::new(cx).await;
cx.set_state(indoc! {"
First [link one](https://one.com) here.
Second [link two](https://two.com) here.
"});
cx.update_editor(|editor, cx| {
editor.display_map.update(cx, |map, cx| {
map.syntax_fold_config = SyntaxFoldConfig {
enabled: true,
auto_fold_on_open: true,
proximity_expand_distance: 2,
};
map.detect_syntax_folds(cx);
});
});
// Edit text between links
cx.set_selections_state(indoc! {"
First [link one](https://one.com) here|.
Second [link two](https://two.com) here.
"});
cx.simulate_keystroke(" and more text");
cx.update_editor(|editor, cx| {
// Verify folds are maintained after edit
let snapshot = editor.snapshot(cx);
let fold_count = snapshot.fold_count();
assert_eq!(fold_count, 2, "Both folds should persist after edit");
});
// Add a new link
cx.simulate_keystroke("\nThird [link three](https://three.com) added.");
cx.update_editor(|editor, cx| {
// Verify new fold is detected
let snapshot = editor.snapshot(cx);
let fold_count = snapshot.fold_count();
assert_eq!(fold_count, 3, "New fold should be detected for added link");
});
}
#[gpui::test]
async fn test_channel_notes_integration(cx: &mut TestAppContext) {
init_test(cx);
let mut cx = EditorTestContext::new(cx).await;
// Simulate channel notes content with many links
cx.set_state(indoc! {"
# Project Resources
## Documentation
- [API Reference](https://api.example.com/docs)
- [User Guide](https://guide.example.com)
- [Developer Handbook](https://dev.example.com/handbook)
## Tools
- [Build Status](https://ci.example.com/status)
- [Issue Tracker](https://issues.example.com)
- [Code Review](https://review.example.com)
## External Links
- [Blog Post](https://blog.example.com/announcement)
- [Video Tutorial](https://youtube.com/watch?v=demo)
- [Community Forum](https://forum.example.com)
"});
cx.update_editor(|editor, cx| {
editor.display_map.update(cx, |map, cx| {
map.syntax_fold_config = SyntaxFoldConfig {
enabled: true,
auto_fold_on_open: true,
proximity_expand_distance: 2,
};
map.detect_syntax_folds(cx);
});
// Verify all links are folded
let snapshot = editor.snapshot(cx);
let fold_count = snapshot.fold_count();
assert_eq!(fold_count, 9, "All 9 links should be folded");
// Verify visual appearance (folded links show only text)
let display_text = snapshot.display_text();
assert!(display_text.contains("API Reference"));
assert!(!display_text.contains("https://api.example.com/docs"));
});
}
fn init_test(cx: &mut TestAppContext) {
cx.update(|cx| {
let settings = crate::test::test_settings(cx);
cx.set_global(settings);
theme::init(theme::LoadThemes::JustBase, cx);
language::init(cx);
crate::init(cx);
});
}