├── src ├── widgets.rs ├── results.rs ├── editor.rs ├── clipboard.rs ├── app.rs ├── input.rs ├── search.rs ├── snapshots │ ├── jiq__syntax_highlight__snapshot_tests__snapshot_empty_input.snap │ ├── jiq__syntax_highlight__snapshot_tests__snapshot_identity_filter.snap │ ├── jiq__syntax_highlight__snapshot_tests__snapshot_simple_field.snap │ ├── jiq__json__json_tests__snapshot_schema_extraction_nested_arrays.snap │ ├── jiq__syntax_highlight__snapshot_tests__snapshot_nested_field.snap │ ├── jiq__syntax_highlight__snapshot_tests__snapshot_unterminated_string.snap │ ├── jiq__syntax_highlight__snapshot_tests__snapshot_keywords_inside_string.snap │ ├── jiq__json__json_tests__snapshot_schema_extraction_complex.snap │ ├── jiq__syntax_highlight__snapshot_tests__snapshot_whitespace_handling.snap │ ├── jiq__syntax_highlight__snapshot_tests__snapshot_number_literals.snap │ ├── jiq__syntax_highlight__snapshot_tests__snapshot_array_iteration.snap │ ├── jiq__syntax_highlight__snapshot_tests__snapshot_string_literals.snap │ ├── jiq__syntax_highlight__snapshot_tests__snapshot_pipe_chain.snap │ ├── jiq__syntax_highlight__snapshot_tests__snapshot_if_then_else.snap │ ├── jiq__syntax_highlight__snapshot_tests__snapshot_reduce.snap │ ├── jiq__syntax_highlight__snapshot_tests__snapshot_object_construction.snap │ ├── jiq__syntax_highlight__snapshot_tests__snapshot_common_functions.snap │ ├── jiq__syntax_highlight__snapshot_tests__snapshot_keywords.snap │ └── jiq__syntax_highlight__snapshot_tests__snapshot_operators.snap ├── ai │ ├── provider │ │ └── snapshots │ │ │ ├── jiq__ai__provider__sse__sse_tests__anthropic_malformed.snap │ │ │ ├── jiq__ai__provider__sse__sse_tests__snapshot_parsed_anthropic_sse_stream.snap │ │ │ ├── jiq__ai__provider__sse__sse_tests__snapshot_parsed_gemini_sse_stream.snap │ │ │ ├── jiq__ai__provider__sse__sse_tests__snapshot_parsed_openai_sse_stream.snap │ │ │ ├── jiq__ai__provider__sse__sse_tests__openai_malformed.snap │ │ │ ├── jiq__ai__provider__sse__sse_tests__snapshot_mixed_valid_invalid_events.snap │ │ │ ├── jiq__ai__provider__async_openai__async_openai_tests__snapshot_request_body_format.snap │ │ │ └── jiq__ai__provider__async_gemini__async_gemini_tests__snapshot_request_body_format.snap │ ├── render.rs │ ├── suggestion.rs │ ├── provider_tests │ │ └── snapshots │ │ │ ├── jiq__ai__provider__provider_tests__openai_tests__openai_error_snapshots__snapshot_openai_network_error.snap │ │ │ ├── jiq__ai__provider__provider_tests__openai_tests__openai_error_snapshots__snapshot_openai_api_error.snap │ │ │ ├── jiq__ai__provider__provider_tests__openai_tests__openai_error_snapshots__snapshot_openai_parse_error.snap │ │ │ ├── jiq__ai__provider__provider_tests__openai_tests__openai_error_snapshots__snapshot_openai_api_error_rate_limit.snap │ │ │ ├── jiq__ai__provider__provider_tests__openai_tests__openai_error_snapshots__snapshot_openai_network_error_dns.snap │ │ │ ├── jiq__ai__provider__provider_tests__openai_tests__openai_error_snapshots__snapshot_openai_parse_error_request.snap │ │ │ ├── jiq__ai__provider__provider_tests__openai_tests__openai_error_snapshots__snapshot_openai_missing_model_error.snap │ │ │ ├── jiq__ai__provider__provider_tests__openai_tests__openai_error_snapshots__snapshot_openai_whitespace_model_error.snap │ │ │ ├── jiq__ai__provider__provider_tests__openai_tests__openai_error_snapshots__snapshot_openai_missing_api_key_error.snap │ │ │ └── jiq__ai__provider__provider_tests__openai_tests__openai_error_snapshots__snapshot_openai_whitespace_api_key_error.snap │ ├── ai_state │ │ └── suggestions.rs │ ├── ai_events_tests │ │ ├── debounce_tests.rs │ │ ├── application_tests.rs │ │ └── selection_tests.rs │ ├── selection.rs │ ├── cache.rs │ ├── provider_tests.rs │ ├── ai_render_tests.rs │ ├── render │ │ └── text.rs │ └── ai_events_tests.rs ├── notification.rs ├── history.rs ├── help.rs ├── syntax_highlight_tests │ └── snapshots │ │ ├── jiq__syntax_highlight__syntax_highlight_tests__snapshot_tests__snapshot_empty_input.snap │ │ ├── jiq__syntax_highlight__syntax_highlight_tests__snapshot_tests__snapshot_identity_filter.snap │ │ ├── jiq__syntax_highlight__syntax_highlight_tests__snapshot_tests__snapshot_simple_field.snap │ │ ├── jiq__syntax_highlight__syntax_highlight_tests__snapshot_tests__snapshot_nested_field.snap │ │ ├── jiq__syntax_highlight__syntax_highlight_tests__snapshot_tests__snapshot_unterminated_string.snap │ │ ├── jiq__syntax_highlight__syntax_highlight_tests__snapshot_tests__snapshot_keywords_inside_string.snap │ │ ├── jiq__syntax_highlight__syntax_highlight_tests__snapshot_tests__snapshot_whitespace_handling.snap │ │ ├── jiq__syntax_highlight__syntax_highlight_tests__snapshot_tests__snapshot_number_literals.snap │ │ ├── jiq__syntax_highlight__syntax_highlight_tests__snapshot_tests__snapshot_array_iteration.snap │ │ ├── jiq__syntax_highlight__syntax_highlight_tests__snapshot_tests__snapshot_string_literals.snap │ │ ├── jiq__syntax_highlight__syntax_highlight_tests__snapshot_tests__snapshot_pipe_chain.snap │ │ ├── jiq__syntax_highlight__syntax_highlight_tests__snapshot_tests__snapshot_if_then_else.snap │ │ ├── jiq__syntax_highlight__syntax_highlight_tests__snapshot_tests__snapshot_reduce.snap │ │ ├── jiq__syntax_highlight__syntax_highlight_tests__snapshot_tests__snapshot_object_construction.snap │ │ ├── jiq__syntax_highlight__syntax_highlight_tests__snapshot_tests__snapshot_common_functions.snap │ │ ├── jiq__syntax_highlight__syntax_highlight_tests__snapshot_tests__snapshot_keywords.snap │ │ └── jiq__syntax_highlight__syntax_highlight_tests__snapshot_tests__snapshot_operators.snap ├── syntax_highlight │ ├── snapshots │ │ ├── jiq__syntax_highlight__overlay__snapshot_tests__snapshot_extract_visible_beyond_text.snap │ │ ├── jiq__syntax_highlight__overlay__snapshot_tests__snapshot_extract_visible_unicode.snap │ │ ├── jiq__syntax_highlight__overlay__snapshot_tests__snapshot_cursor_empty_spans.snap │ │ ├── jiq__syntax_highlight__overlay__snapshot_tests__snapshot_extract_visible_with_scroll.snap │ │ ├── jiq__syntax_highlight__overlay__snapshot_tests__snapshot_cursor_at_end.snap │ │ ├── jiq__syntax_highlight__overlay__snapshot_tests__snapshot_cursor_at_start.snap │ │ ├── jiq__syntax_highlight__overlay__snapshot_tests__snapshot_extract_visible_no_scroll.snap │ │ ├── jiq__syntax_highlight__overlay__snapshot_tests__snapshot_cursor_in_middle.snap │ │ └── jiq__syntax_highlight__overlay__snapshot_tests__snapshot_cursor_across_spans.snap │ ├── overlay_tests │ │ └── snapshots │ │ │ ├── jiq__syntax_highlight__overlay__overlay_tests__snapshot_tests__snapshot_extract_visible_beyond_text.snap │ │ │ ├── jiq__syntax_highlight__overlay__overlay_tests__snapshot_tests__snapshot_extract_visible_unicode.snap │ │ │ ├── jiq__syntax_highlight__overlay__overlay_tests__snapshot_tests__snapshot_cursor_empty_spans.snap │ │ │ ├── jiq__syntax_highlight__overlay__overlay_tests__snapshot_tests__snapshot_extract_visible_with_scroll.snap │ │ │ ├── jiq__syntax_highlight__overlay__overlay_tests__snapshot_tests__snapshot_cursor_at_end.snap │ │ │ ├── jiq__syntax_highlight__overlay__overlay_tests__snapshot_tests__snapshot_extract_visible_no_scroll.snap │ │ │ ├── jiq__syntax_highlight__overlay__overlay_tests__snapshot_tests__snapshot_cursor_at_start.snap │ │ │ ├── jiq__syntax_highlight__overlay__overlay_tests__snapshot_tests__snapshot_cursor_in_middle.snap │ │ │ └── jiq__syntax_highlight__overlay__overlay_tests__snapshot_tests__snapshot_cursor_across_spans.snap │ └── overlay_tests.rs ├── query.rs ├── help │ ├── help_state_tests.rs │ ├── help_state.rs │ └── help_line_render.rs ├── search │ ├── search_events_tests.rs │ ├── matcher.rs │ ├── search_render.rs │ └── search_events_tests │ │ └── lifecycle_tests.rs ├── clipboard │ ├── system_tests.rs │ ├── system.rs │ ├── backend.rs │ ├── osc52.rs │ ├── backend_tests.rs │ └── osc52_tests.rs ├── tooltip │ ├── tooltip_events.rs │ └── tooltip_events_tests.rs ├── stats.rs ├── autocomplete │ ├── insertion_tests │ │ ├── query_execution_tests.rs │ │ └── cursor_positioning_tests.rs │ ├── insertion │ │ └── cursor.rs │ ├── scan_state.rs │ ├── insertion_tests.rs │ └── scan_state_tests.rs ├── tooltip.rs ├── editor │ ├── mode_tests.rs │ └── mode.rs ├── error.rs ├── app │ ├── snapshots │ │ ├── jiq__app__render__snapshot_tests__snapshot_ui_small_terminal.snap │ │ ├── jiq__app__app_render__snapshot_tests__snapshot_ui_small_terminal.snap │ │ ├── jiq__app__render__snapshot_tests__snapshot_help_popup.snap │ │ ├── jiq__app__render__snapshot_tests__snapshot_error_overlay.snap │ │ ├── jiq__app__render__snapshot_tests__snapshot_history_popup.snap │ │ ├── jiq__app__render__snapshot_tests__snapshot_ui_input_focused.snap │ │ ├── jiq__app__render__snapshot_tests__snapshot_ui_insert_mode.snap │ │ ├── jiq__app__render__snapshot_tests__snapshot_ui_normal_mode.snap │ │ ├── jiq__app__render__snapshot_tests__snapshot_ui_operator_mode.snap │ │ ├── jiq__app__render__snapshot_tests__snapshot_ui_with_error.snap │ │ ├── jiq__app__render__snapshot_tests__snapshot_ui_with_query.snap │ │ ├── jiq__app__app_render__snapshot_tests__snapshot_error_overlay.snap │ │ ├── jiq__app__app_render__snapshot_tests__snapshot_help_popup.snap │ │ ├── jiq__app__app_render__snapshot_tests__snapshot_history_popup.snap │ │ ├── jiq__app__app_render__snapshot_tests__snapshot_ui_with_error.snap │ │ ├── jiq__app__app_render__snapshot_tests__snapshot_ui_with_query.snap │ │ ├── jiq__app__render__snapshot_tests__snapshot_search_bar_no_matches.snap │ │ ├── jiq__app__render__snapshot_tests__snapshot_search_bar_visible.snap │ │ ├── jiq__app__render__snapshot_tests__snapshot_ui_results_focused.snap │ │ ├── jiq__app__render__snapshot_tests__snapshot_ui_with_array_data.snap │ │ ├── jiq__app__app_render__snapshot_tests__snapshot_search_bar_visible.snap │ │ ├── jiq__app__app_render__snapshot_tests__snapshot_ui_input_focused.snap │ │ ├── jiq__app__app_render__snapshot_tests__snapshot_ui_insert_mode.snap │ │ ├── jiq__app__app_render__snapshot_tests__snapshot_ui_normal_mode.snap │ │ ├── jiq__app__app_render__snapshot_tests__snapshot_ui_operator_mode.snap │ │ ├── jiq__app__app_render__snapshot_tests__snapshot_ui_results_focused.snap │ │ ├── jiq__app__app_render__snapshot_tests__snapshot_ui_with_array_data.snap │ │ ├── jiq__app__render__snapshot_tests__snapshot_history_popup_no_matches.snap │ │ ├── jiq__app__render__snapshot_tests__snapshot_history_popup_with_search.snap │ │ ├── jiq__app__render__snapshot_tests__snapshot_initial_ui_empty_query.snap │ │ ├── jiq__app__render__snapshot_tests__snapshot_stats_bar_array_focused.snap │ │ ├── jiq__app__render__snapshot_tests__snapshot_stats_bar_object_unfocused.snap │ │ ├── jiq__app__render__snapshot_tests__snapshot_ui_error_overlay_visible.snap │ │ ├── jiq__app__app_render__snapshot_tests__snapshot_initial_ui_empty_query.snap │ │ ├── jiq__app__app_render__snapshot_tests__snapshot_search_bar_no_matches.snap │ │ ├── jiq__app__app_render__snapshot_tests__snapshot_stats_bar_array_focused.snap │ │ ├── jiq__app__render__snapshot_tests__snapshot_autocomplete_popup_mixed_types.snap │ │ ├── jiq__app__render__snapshot_tests__snapshot_search_bar_with_match_count.snap │ │ ├── jiq__app__render__snapshot_tests__snapshot_search_with_highlighted_matches.snap │ │ ├── jiq__app__render__snapshot_tests__snapshot_search_with_horizontal_scroll.snap │ │ ├── jiq__app__app_render__snapshot_tests__snapshot_history_popup_no_matches.snap │ │ ├── jiq__app__app_render__snapshot_tests__snapshot_history_popup_with_search.snap │ │ ├── jiq__app__app_render__snapshot_tests__snapshot_input_border_with_ai_hint.snap │ │ ├── jiq__app__app_render__snapshot_tests__snapshot_processing_with_syntax_error.snap │ │ ├── jiq__app__app_render__snapshot_tests__snapshot_search_bar_with_match_count.snap │ │ ├── jiq__app__app_render__snapshot_tests__snapshot_stats_bar_object_unfocused.snap │ │ ├── jiq__app__app_render__snapshot_tests__snapshot_ui_error_overlay_visible.snap │ │ ├── jiq__app__render__snapshot_tests__snapshot_results_pane_with_success_focused.snap │ │ ├── jiq__app__render__snapshot_tests__snapshot_results_pane_with_success_unfocused.snap │ │ ├── jiq__app__render__snapshot_tests__snapshot_stats_bar_error_shows_last_stats.snap │ │ ├── jiq__app__app_render__snapshot_tests__snapshot_autocomplete_popup_mixed_types.snap │ │ └── jiq__app__app_render__snapshot_tests__snapshot_help_popup_with_ai_keybindings.snap │ └── app_events │ │ └── global_tests.rs ├── history │ ├── storage_tests.rs │ ├── history_events.rs │ └── matcher.rs ├── lib.rs ├── ai.rs ├── stats │ └── stats_state.rs ├── autocomplete.rs ├── widgets │ └── popup.rs ├── config │ └── types.rs ├── query │ ├── debouncer.rs │ └── worker.rs └── notification │ ├── notification_render_tests.rs │ └── notification_render.rs ├── tests └── fixtures │ ├── simple.json │ ├── invalid.json │ ├── array.json │ └── nested.json ├── .gitignore ├── proptest-regressions ├── app │ ├── state.txt │ ├── app_events_tests.txt │ ├── app_render.txt │ └── app_events │ │ └── global_tests │ │ ├── autocomplete_tests.txt │ │ └── ai_suggestion_tests.txt ├── ai │ ├── ai_state_tests.txt │ ├── provider_tests.txt │ ├── ai_state.txt │ └── ai_render_tests │ │ ├── content_tests.txt │ │ └── model_name_tests.txt ├── clipboard │ ├── clipboard_events_tests.txt │ └── events.txt ├── search │ ├── events.txt │ └── search_events_tests │ │ └── navigation_tests.txt └── tooltip │ └── detector.txt ├── dist-workspace.toml └── LICENSE-MIT /src/widgets.rs: -------------------------------------------------------------------------------- 1 | pub mod popup; 2 | -------------------------------------------------------------------------------- /src/results.rs: -------------------------------------------------------------------------------- 1 | pub mod results_events; 2 | pub mod results_render; 3 | -------------------------------------------------------------------------------- /src/editor.rs: -------------------------------------------------------------------------------- 1 | pub mod editor_events; 2 | pub mod mode; 3 | 4 | pub use mode::EditorMode; 5 | -------------------------------------------------------------------------------- /src/clipboard.rs: -------------------------------------------------------------------------------- 1 | mod backend; 2 | pub mod clipboard_events; 3 | mod osc52; 4 | mod system; 5 | -------------------------------------------------------------------------------- /tests/fixtures/simple.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Alice", 3 | "age": 30, 4 | "city": "Seattle" 5 | } 6 | -------------------------------------------------------------------------------- /tests/fixtures/invalid.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Invalid", 3 | "missing_quote: "value", 4 | "trailing_comma": true, 5 | } 6 | -------------------------------------------------------------------------------- /src/app.rs: -------------------------------------------------------------------------------- 1 | mod app_events; 2 | mod app_render; 3 | mod app_state; 4 | 5 | // Re-export public types 6 | pub use app_state::{App, Focus, OutputMode}; 7 | -------------------------------------------------------------------------------- /src/input.rs: -------------------------------------------------------------------------------- 1 | pub mod input_render; 2 | mod input_state; 3 | pub mod loader; 4 | 5 | pub use input_state::InputState; 6 | pub use loader::FileLoader; 7 | -------------------------------------------------------------------------------- /src/search.rs: -------------------------------------------------------------------------------- 1 | mod matcher; 2 | pub mod search_events; 3 | pub mod search_render; 4 | mod search_state; 5 | 6 | pub use search_state::{Match, SearchState}; 7 | -------------------------------------------------------------------------------- /src/snapshots/jiq__syntax_highlight__snapshot_tests__snapshot_empty_input.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/syntax/mod.rs 3 | expression: serialize_spans(&spans) 4 | --- 5 | [] 6 | -------------------------------------------------------------------------------- /src/ai/provider/snapshots/jiq__ai__provider__sse__sse_tests__anthropic_malformed.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/ai/provider/sse_tests.rs 3 | expression: anthropic_results 4 | --- 5 | [] 6 | -------------------------------------------------------------------------------- /src/ai/render.rs: -------------------------------------------------------------------------------- 1 | //! AI rendering module 2 | //! 3 | //! Contains rendering logic for the AI assistant popup. 4 | 5 | pub mod layout; 6 | pub mod suggestions; 7 | pub mod text; 8 | -------------------------------------------------------------------------------- /src/notification.rs: -------------------------------------------------------------------------------- 1 | mod notification_render; 2 | mod notification_state; 3 | 4 | pub use notification_render::render_notification; 5 | pub use notification_state::NotificationState; 6 | -------------------------------------------------------------------------------- /src/snapshots/jiq__syntax_highlight__snapshot_tests__snapshot_identity_filter.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/syntax/mod.rs 3 | expression: serialize_spans(&spans) 4 | --- 5 | - content: "." 6 | -------------------------------------------------------------------------------- /src/snapshots/jiq__syntax_highlight__snapshot_tests__snapshot_simple_field.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/syntax/mod.rs 3 | expression: serialize_spans(&spans) 4 | --- 5 | - content: ".name" 6 | -------------------------------------------------------------------------------- /src/history.rs: -------------------------------------------------------------------------------- 1 | pub mod history_events; 2 | pub mod history_render; 3 | mod history_state; 4 | mod matcher; 5 | pub mod storage; 6 | 7 | pub use history_state::{HistoryState, MAX_VISIBLE_HISTORY}; 8 | -------------------------------------------------------------------------------- /src/snapshots/jiq__json__json_tests__snapshot_schema_extraction_nested_arrays.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/json_tests.rs 3 | expression: schema 4 | --- 5 | {"labels":["string"],"matrix":[["number"]]} 6 | -------------------------------------------------------------------------------- /src/snapshots/jiq__syntax_highlight__snapshot_tests__snapshot_nested_field.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/syntax/mod.rs 3 | expression: serialize_spans(&spans) 4 | --- 5 | - content: ".user.address.city" 6 | -------------------------------------------------------------------------------- /src/help.rs: -------------------------------------------------------------------------------- 1 | mod help_content; 2 | pub mod help_line_render; 3 | pub mod help_popup_render; 4 | mod help_state; 5 | 6 | pub use help_content::{HELP_ENTRIES, HELP_FOOTER}; 7 | pub use help_state::HelpPopupState; 8 | -------------------------------------------------------------------------------- /src/syntax_highlight_tests/snapshots/jiq__syntax_highlight__syntax_highlight_tests__snapshot_tests__snapshot_empty_input.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/syntax/mod.rs 3 | expression: serialize_spans(&spans) 4 | --- 5 | [] 6 | -------------------------------------------------------------------------------- /src/snapshots/jiq__syntax_highlight__snapshot_tests__snapshot_unterminated_string.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/syntax/mod.rs 3 | expression: serialize_spans(&spans) 4 | --- 5 | - content: "\"unterminated" 6 | fg: green 7 | -------------------------------------------------------------------------------- /src/syntax_highlight/snapshots/jiq__syntax_highlight__overlay__snapshot_tests__snapshot_extract_visible_beyond_text.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/app/syntax_overlay.rs 3 | expression: serialize_spans(&visible) 4 | --- 5 | [] 6 | -------------------------------------------------------------------------------- /src/query.rs: -------------------------------------------------------------------------------- 1 | pub mod debouncer; 2 | pub mod executor; 3 | pub mod query_state; 4 | pub mod worker; 5 | 6 | // Re-export public types 7 | pub use debouncer::Debouncer; 8 | pub use query_state::{CharType, QueryState, ResultType}; 9 | -------------------------------------------------------------------------------- /src/snapshots/jiq__syntax_highlight__snapshot_tests__snapshot_keywords_inside_string.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/syntax/mod.rs 3 | expression: serialize_spans(&spans) 4 | --- 5 | - content: "\"if then else are keywords\"" 6 | fg: green 7 | -------------------------------------------------------------------------------- /src/syntax_highlight/snapshots/jiq__syntax_highlight__overlay__snapshot_tests__snapshot_extract_visible_unicode.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/app/syntax_overlay.rs 3 | expression: serialize_spans(&visible) 4 | --- 5 | - content: lo👋Wo 6 | -------------------------------------------------------------------------------- /src/syntax_highlight_tests/snapshots/jiq__syntax_highlight__syntax_highlight_tests__snapshot_tests__snapshot_identity_filter.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/syntax/mod.rs 3 | expression: serialize_spans(&spans) 4 | --- 5 | - content: "." 6 | -------------------------------------------------------------------------------- /src/syntax_highlight_tests/snapshots/jiq__syntax_highlight__syntax_highlight_tests__snapshot_tests__snapshot_simple_field.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/syntax/mod.rs 3 | expression: serialize_spans(&spans) 4 | --- 5 | - content: ".name" 6 | -------------------------------------------------------------------------------- /src/syntax_highlight_tests/snapshots/jiq__syntax_highlight__syntax_highlight_tests__snapshot_tests__snapshot_nested_field.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/syntax/mod.rs 3 | expression: serialize_spans(&spans) 4 | --- 5 | - content: ".user.address.city" 6 | -------------------------------------------------------------------------------- /src/ai/provider/snapshots/jiq__ai__provider__sse__sse_tests__snapshot_parsed_anthropic_sse_stream.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/ai/provider/sse_tests.rs 3 | expression: results 4 | --- 5 | [ 6 | "Hello", 7 | " world", 8 | "!", 9 | ] 10 | -------------------------------------------------------------------------------- /src/ai/provider/snapshots/jiq__ai__provider__sse__sse_tests__snapshot_parsed_gemini_sse_stream.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/ai/provider/sse_tests.rs 3 | expression: results 4 | --- 5 | [ 6 | "Hello", 7 | " world", 8 | "!", 9 | ] 10 | -------------------------------------------------------------------------------- /src/ai/provider/snapshots/jiq__ai__provider__sse__sse_tests__snapshot_parsed_openai_sse_stream.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/ai/provider/sse_tests.rs 3 | expression: results 4 | --- 5 | [ 6 | "Hello", 7 | " world", 8 | "!", 9 | ] 10 | -------------------------------------------------------------------------------- /src/syntax_highlight/overlay_tests/snapshots/jiq__syntax_highlight__overlay__overlay_tests__snapshot_tests__snapshot_extract_visible_beyond_text.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/app/syntax_overlay.rs 3 | expression: serialize_spans(&visible) 4 | --- 5 | [] 6 | -------------------------------------------------------------------------------- /src/ai/provider/snapshots/jiq__ai__provider__sse__sse_tests__openai_malformed.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/ai/provider/sse_tests.rs 3 | expression: openai_results 4 | --- 5 | [ 6 | "Valid", 7 | "Also valid", 8 | "Still works", 9 | ] 10 | -------------------------------------------------------------------------------- /src/ai/provider/snapshots/jiq__ai__provider__sse__sse_tests__snapshot_mixed_valid_invalid_events.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/ai/provider/sse_tests.rs 3 | expression: results 4 | --- 5 | [ 6 | "First", 7 | "Second", 8 | "Third", 9 | ] 10 | -------------------------------------------------------------------------------- /src/snapshots/jiq__json__json_tests__snapshot_schema_extraction_complex.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/json_tests.rs 3 | expression: schema 4 | --- 5 | {"count":"number","users":[{"address":{"city":"string","zip":"string"},"age":"number","name":"string"}]} 6 | -------------------------------------------------------------------------------- /src/syntax_highlight/overlay_tests/snapshots/jiq__syntax_highlight__overlay__overlay_tests__snapshot_tests__snapshot_extract_visible_unicode.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/app/syntax_overlay.rs 3 | expression: serialize_spans(&visible) 4 | --- 5 | - content: lo👋Wo 6 | -------------------------------------------------------------------------------- /src/syntax_highlight/snapshots/jiq__syntax_highlight__overlay__snapshot_tests__snapshot_cursor_empty_spans.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/app/syntax_overlay.rs 3 | expression: serialize_spans(&result) 4 | --- 5 | - content: " " 6 | modifiers: 7 | - reversed 8 | -------------------------------------------------------------------------------- /src/help/help_state_tests.rs: -------------------------------------------------------------------------------- 1 | //! Tests for help_state 2 | 3 | use super::*; 4 | 5 | #[test] 6 | fn test_new_help_state() { 7 | let state = HelpPopupState::new(); 8 | assert!(!state.visible); 9 | assert_eq!(state.scroll.offset, 0); 10 | } 11 | -------------------------------------------------------------------------------- /src/syntax_highlight_tests/snapshots/jiq__syntax_highlight__syntax_highlight_tests__snapshot_tests__snapshot_unterminated_string.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/syntax/mod.rs 3 | expression: serialize_spans(&spans) 4 | --- 5 | - content: "\"unterminated" 6 | fg: green 7 | -------------------------------------------------------------------------------- /src/ai/suggestion.rs: -------------------------------------------------------------------------------- 1 | //! Suggestion module for AI assistant 2 | //! 3 | //! This module provides types and parsing logic for AI suggestions. 4 | 5 | pub mod parser; 6 | 7 | // Re-export main types 8 | pub use parser::{Suggestion, SuggestionType, parse_suggestions}; 9 | -------------------------------------------------------------------------------- /src/search/search_events_tests.rs: -------------------------------------------------------------------------------- 1 | #[path = "search_events_tests/lifecycle_tests.rs"] 2 | mod lifecycle_tests; 3 | #[path = "search_events_tests/navigation_tests.rs"] 4 | mod navigation_tests; 5 | #[path = "search_events_tests/scroll_tests.rs"] 6 | mod scroll_tests; 7 | -------------------------------------------------------------------------------- /src/ai/provider_tests/snapshots/jiq__ai__provider__provider_tests__openai_tests__openai_error_snapshots__snapshot_openai_network_error.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/ai/provider_tests/openai_tests.rs 3 | expression: error_message 4 | --- 5 | [OpenAI] Network error: Connection timeout 6 | -------------------------------------------------------------------------------- /src/ai/ai_state/suggestions.rs: -------------------------------------------------------------------------------- 1 | //! AI suggestion management 2 | //! 3 | //! Handles suggestion selection, navigation, and state updates. 4 | //! Currently minimal as most suggestion logic is in lifecycle methods. 5 | 6 | use crate::ai::ai_state::AiState; 7 | 8 | impl AiState {} 9 | -------------------------------------------------------------------------------- /src/ai/provider_tests/snapshots/jiq__ai__provider__provider_tests__openai_tests__openai_error_snapshots__snapshot_openai_api_error.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/ai/provider_tests/openai_tests.rs 3 | expression: error_message 4 | --- 5 | [OpenAI] API error (401): Invalid API key provided 6 | -------------------------------------------------------------------------------- /src/ai/provider_tests/snapshots/jiq__ai__provider__provider_tests__openai_tests__openai_error_snapshots__snapshot_openai_parse_error.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/ai/provider_tests/openai_tests.rs 3 | expression: error_message 4 | --- 5 | [OpenAI] Parse error: Invalid JSON in SSE event 6 | -------------------------------------------------------------------------------- /src/clipboard/system_tests.rs: -------------------------------------------------------------------------------- 1 | //! Tests for clipboard/system 2 | 3 | use super::*; 4 | 5 | #[test] 6 | fn test_copy_returns_result() { 7 | let result = copy("test"); 8 | assert!(result.is_ok() || matches!(result, Err(ClipboardError::SystemUnavailable))); 9 | } 10 | -------------------------------------------------------------------------------- /src/syntax_highlight_tests/snapshots/jiq__syntax_highlight__syntax_highlight_tests__snapshot_tests__snapshot_keywords_inside_string.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/syntax/mod.rs 3 | expression: serialize_spans(&spans) 4 | --- 5 | - content: "\"if then else are keywords\"" 6 | fg: green 7 | -------------------------------------------------------------------------------- /src/ai/provider_tests/snapshots/jiq__ai__provider__provider_tests__openai_tests__openai_error_snapshots__snapshot_openai_api_error_rate_limit.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/ai/provider_tests/openai_tests.rs 3 | expression: error_message 4 | --- 5 | [OpenAI] API error (429): Rate limit exceeded 6 | -------------------------------------------------------------------------------- /src/ai/provider_tests/snapshots/jiq__ai__provider__provider_tests__openai_tests__openai_error_snapshots__snapshot_openai_network_error_dns.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/ai/provider_tests/openai_tests.rs 3 | expression: error_message 4 | --- 5 | [OpenAI] Network error: DNS resolution failed 6 | -------------------------------------------------------------------------------- /src/syntax_highlight/overlay_tests/snapshots/jiq__syntax_highlight__overlay__overlay_tests__snapshot_tests__snapshot_cursor_empty_spans.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/app/syntax_overlay.rs 3 | expression: serialize_spans(&result) 4 | --- 5 | - content: " " 6 | modifiers: 7 | - reversed 8 | -------------------------------------------------------------------------------- /src/syntax_highlight/snapshots/jiq__syntax_highlight__overlay__snapshot_tests__snapshot_extract_visible_with_scroll.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/app/syntax_overlay.rs 3 | expression: serialize_spans(&visible) 4 | --- 5 | - content: "56789" 6 | fg: red 7 | - content: ABCDE 8 | fg: blue 9 | -------------------------------------------------------------------------------- /src/tooltip/tooltip_events.rs: -------------------------------------------------------------------------------- 1 | use super::tooltip_state::TooltipState; 2 | 3 | pub fn handle_tooltip_toggle(state: &mut TooltipState) -> bool { 4 | state.toggle(); 5 | true 6 | } 7 | 8 | #[cfg(test)] 9 | #[path = "tooltip_events_tests.rs"] 10 | mod tooltip_events_tests; 11 | -------------------------------------------------------------------------------- /src/syntax_highlight/snapshots/jiq__syntax_highlight__overlay__snapshot_tests__snapshot_cursor_at_end.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/app/syntax_overlay.rs 3 | expression: serialize_spans(&result) 4 | --- 5 | - content: Hi 6 | fg: red 7 | - content: " " 8 | modifiers: 9 | - reversed 10 | -------------------------------------------------------------------------------- /src/ai/provider_tests/snapshots/jiq__ai__provider__provider_tests__openai_tests__openai_error_snapshots__snapshot_openai_parse_error_request.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/ai/provider_tests/openai_tests.rs 3 | expression: error_message 4 | --- 5 | [OpenAI] Parse error: Failed to serialize request body 6 | -------------------------------------------------------------------------------- /tests/fixtures/array.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "id": 1, 4 | "name": "Alice", 5 | "active": true 6 | }, 7 | { 8 | "id": 2, 9 | "name": "Bob", 10 | "active": false 11 | }, 12 | { 13 | "id": 3, 14 | "name": "Charlie", 15 | "active": true 16 | } 17 | ] 18 | -------------------------------------------------------------------------------- /src/syntax_highlight/overlay_tests/snapshots/jiq__syntax_highlight__overlay__overlay_tests__snapshot_tests__snapshot_extract_visible_with_scroll.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/app/syntax_overlay.rs 3 | expression: serialize_spans(&visible) 4 | --- 5 | - content: "56789" 6 | fg: red 7 | - content: ABCDE 8 | fg: blue 9 | -------------------------------------------------------------------------------- /src/syntax_highlight/snapshots/jiq__syntax_highlight__overlay__snapshot_tests__snapshot_cursor_at_start.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/app/syntax_overlay.rs 3 | expression: serialize_spans(&result) 4 | --- 5 | - content: H 6 | fg: red 7 | modifiers: 8 | - reversed 9 | - content: ello 10 | fg: red 11 | -------------------------------------------------------------------------------- /src/syntax_highlight/snapshots/jiq__syntax_highlight__overlay__snapshot_tests__snapshot_extract_visible_no_scroll.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/app/syntax_overlay.rs 3 | expression: serialize_spans(&visible) 4 | --- 5 | - content: Hello 6 | fg: red 7 | - content: " " 8 | - content: World 9 | fg: blue 10 | -------------------------------------------------------------------------------- /src/ai/provider_tests/snapshots/jiq__ai__provider__provider_tests__openai_tests__openai_error_snapshots__snapshot_openai_missing_model_error.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/ai/provider_tests/openai_tests.rs 3 | expression: error_message 4 | --- 5 | [OpenAI] AI not configured: Missing model. Add 'model' in [ai.openai] section. 6 | -------------------------------------------------------------------------------- /src/ai/provider_tests/snapshots/jiq__ai__provider__provider_tests__openai_tests__openai_error_snapshots__snapshot_openai_whitespace_model_error.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/ai/provider_tests/openai_tests.rs 3 | expression: error_message 4 | --- 5 | [OpenAI] AI not configured: Missing model. Add 'model' in [ai.openai] section. 6 | -------------------------------------------------------------------------------- /src/syntax_highlight/overlay_tests/snapshots/jiq__syntax_highlight__overlay__overlay_tests__snapshot_tests__snapshot_cursor_at_end.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/app/syntax_overlay.rs 3 | expression: serialize_spans(&result) 4 | --- 5 | - content: Hi 6 | fg: red 7 | - content: " " 8 | modifiers: 9 | - reversed 10 | -------------------------------------------------------------------------------- /src/ai/provider_tests/snapshots/jiq__ai__provider__provider_tests__openai_tests__openai_error_snapshots__snapshot_openai_missing_api_key_error.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/ai/provider_tests/openai_tests.rs 3 | expression: error_message 4 | --- 5 | [OpenAI] AI not configured: Missing API key. Add 'api_key' in [ai.openai] section. 6 | -------------------------------------------------------------------------------- /src/ai/provider_tests/snapshots/jiq__ai__provider__provider_tests__openai_tests__openai_error_snapshots__snapshot_openai_whitespace_api_key_error.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/ai/provider_tests/openai_tests.rs 3 | expression: error_message 4 | --- 5 | [OpenAI] AI not configured: Missing API key. Add 'api_key' in [ai.openai] section. 6 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Rust build artifacts 2 | /target/ 3 | Cargo.lock 4 | 5 | # Rust backup files 6 | **/*.rs.bk 7 | 8 | # macOS 9 | .DS_Store 10 | 11 | # Vim swap files 12 | *.swp 13 | *.swo 14 | *~ 15 | 16 | # Editor directories 17 | .vscode/ 18 | .idea/ 19 | .kiro/ 20 | 21 | # Test artifacts 22 | *.profraw 23 | *.profdata 24 | -------------------------------------------------------------------------------- /src/syntax_highlight/overlay_tests/snapshots/jiq__syntax_highlight__overlay__overlay_tests__snapshot_tests__snapshot_extract_visible_no_scroll.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/app/syntax_overlay.rs 3 | expression: serialize_spans(&visible) 4 | --- 5 | - content: Hello 6 | fg: red 7 | - content: " " 8 | - content: World 9 | fg: blue 10 | -------------------------------------------------------------------------------- /src/ai/ai_events_tests/debounce_tests.rs: -------------------------------------------------------------------------------- 1 | //! Tests for debouncing-related functionality 2 | //! 3 | //! Note: The original ai_events_tests.rs file did not contain explicit debouncing tests. 4 | //! This file is created as a placeholder for future debouncing-related tests. 5 | 6 | // Placeholder - no debouncing tests found in original file 7 | -------------------------------------------------------------------------------- /src/snapshots/jiq__syntax_highlight__snapshot_tests__snapshot_whitespace_handling.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/syntax/mod.rs 3 | expression: serialize_spans(&spans) 4 | --- 5 | - content: " " 6 | - content: ".name" 7 | - content: " " 8 | - content: "|" 9 | fg: magenta 10 | - content: " " 11 | - content: ".age" 12 | - content: " " 13 | -------------------------------------------------------------------------------- /src/syntax_highlight/overlay_tests/snapshots/jiq__syntax_highlight__overlay__overlay_tests__snapshot_tests__snapshot_cursor_at_start.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/app/syntax_overlay.rs 3 | expression: serialize_spans(&result) 4 | --- 5 | - content: H 6 | fg: red 7 | modifiers: 8 | - reversed 9 | - content: ello 10 | fg: red 11 | -------------------------------------------------------------------------------- /src/syntax_highlight/snapshots/jiq__syntax_highlight__overlay__snapshot_tests__snapshot_cursor_in_middle.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/app/syntax_overlay.rs 3 | expression: serialize_spans(&result) 4 | --- 5 | - content: He 6 | fg: red 7 | - content: l 8 | fg: red 9 | modifiers: 10 | - reversed 11 | - content: lo 12 | fg: red 13 | -------------------------------------------------------------------------------- /src/syntax_highlight/snapshots/jiq__syntax_highlight__overlay__snapshot_tests__snapshot_cursor_across_spans.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/app/syntax_overlay.rs 3 | expression: serialize_spans(&result) 4 | --- 5 | - content: Hello 6 | fg: red 7 | - content: W 8 | fg: blue 9 | modifiers: 10 | - reversed 11 | - content: orld 12 | fg: blue 13 | -------------------------------------------------------------------------------- /src/ai/ai_events_tests/application_tests.rs: -------------------------------------------------------------------------------- 1 | //! Tests for suggestion application 2 | //! 3 | //! Note: The original ai_events_tests.rs file did not contain explicit suggestion application tests. 4 | //! This file is created as a placeholder for future application-related tests. 5 | 6 | // Placeholder - no suggestion application tests found in original file 7 | -------------------------------------------------------------------------------- /src/ai/ai_events_tests/selection_tests.rs: -------------------------------------------------------------------------------- 1 | //! Tests for selection key handling (number keys, up/down navigation) 2 | //! 3 | //! Note: The original ai_events_tests.rs file did not contain explicit selection tests. 4 | //! This file is created as a placeholder for future selection-related tests. 5 | 6 | // Placeholder - no selection tests found in original file 7 | -------------------------------------------------------------------------------- /src/syntax_highlight/overlay_tests/snapshots/jiq__syntax_highlight__overlay__overlay_tests__snapshot_tests__snapshot_cursor_in_middle.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/app/syntax_overlay.rs 3 | expression: serialize_spans(&result) 4 | --- 5 | - content: He 6 | fg: red 7 | - content: l 8 | fg: red 9 | modifiers: 10 | - reversed 11 | - content: lo 12 | fg: red 13 | -------------------------------------------------------------------------------- /src/syntax_highlight/overlay_tests/snapshots/jiq__syntax_highlight__overlay__overlay_tests__snapshot_tests__snapshot_cursor_across_spans.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/app/syntax_overlay.rs 3 | expression: serialize_spans(&result) 4 | --- 5 | - content: Hello 6 | fg: red 7 | - content: W 8 | fg: blue 9 | modifiers: 10 | - reversed 11 | - content: orld 12 | fg: blue 13 | -------------------------------------------------------------------------------- /src/syntax_highlight_tests/snapshots/jiq__syntax_highlight__syntax_highlight_tests__snapshot_tests__snapshot_whitespace_handling.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/syntax/mod.rs 3 | expression: serialize_spans(&spans) 4 | --- 5 | - content: " " 6 | - content: ".name" 7 | - content: " " 8 | - content: "|" 9 | fg: magenta 10 | - content: " " 11 | - content: ".age" 12 | - content: " " 13 | -------------------------------------------------------------------------------- /src/ai/provider/snapshots/jiq__ai__provider__async_openai__async_openai_tests__snapshot_request_body_format.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/ai/provider/async_openai_tests.rs 3 | expression: pretty_json 4 | --- 5 | { 6 | "messages": [ 7 | { 8 | "content": "suggest jq filters for: extract user names", 9 | "role": "user" 10 | } 11 | ], 12 | "model": "gpt-4o-mini", 13 | "stream": true 14 | } 15 | -------------------------------------------------------------------------------- /src/stats.rs: -------------------------------------------------------------------------------- 1 | //! Stats module for computing and displaying result statistics 2 | //! 3 | //! This module provides fast, character-based parsing to compute statistics 4 | //! about jq query results without full JSON parsing. 5 | 6 | pub mod parser; 7 | mod stats_state; 8 | pub mod types; 9 | 10 | // Re-export public types 11 | pub use stats_state::StatsState; 12 | pub use stats_state::update_stats_from_app; 13 | -------------------------------------------------------------------------------- /src/ai/selection.rs: -------------------------------------------------------------------------------- 1 | //! Selection state module for AI suggestion navigation and application 2 | //! 3 | //! This module provides functionality for selecting and applying AI suggestions 4 | //! via keyboard shortcuts (Alt+1-5 for direct selection, Alt+Up/Down/j/k for navigation). 5 | 6 | pub mod apply; 7 | pub mod keybindings; 8 | pub mod state; 9 | 10 | // Re-export main types 11 | pub use state::SelectionState; 12 | -------------------------------------------------------------------------------- /src/ai/provider/snapshots/jiq__ai__provider__async_gemini__async_gemini_tests__snapshot_request_body_format.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/ai/provider/async_gemini_tests.rs 3 | expression: pretty_json 4 | --- 5 | { 6 | "contents": [ 7 | { 8 | "parts": [ 9 | { 10 | "text": "suggest jq filters for: extract user names" 11 | } 12 | ], 13 | "role": "user" 14 | } 15 | ] 16 | } 17 | -------------------------------------------------------------------------------- /src/autocomplete/insertion_tests/query_execution_tests.rs: -------------------------------------------------------------------------------- 1 | //! Query execution tests 2 | //! 3 | //! Note: Query execution is tested implicitly in other test files 4 | //! as part of the insertion behavior. This file is a placeholder for 5 | //! any future explicit query execution tests. 6 | 7 | // Query execution is tested as part of the field context tests and integration tests 8 | // No standalone query execution tests at this time 9 | -------------------------------------------------------------------------------- /src/ai/cache.rs: -------------------------------------------------------------------------------- 1 | //! Suggestion cache (stub for Phase 1) 2 | //! 3 | //! Placeholder for future caching of AI suggestions. 4 | 5 | /// Suggestion cache (stub implementation) 6 | #[allow(dead_code)] 7 | #[derive(Debug, Default)] 8 | pub struct SuggestionCache {} 9 | 10 | #[allow(dead_code)] 11 | impl SuggestionCache { 12 | /// Create a new empty cache 13 | pub fn new() -> Self { 14 | Self::default() 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /proptest-regressions/app/state.txt: -------------------------------------------------------------------------------- 1 | # Seeds for failure cases proptest has generated in the past. It is 2 | # automatically read and these particular cases re-run before any 3 | # novel cases are generated. 4 | # 5 | # It is recommended to check this file in to source control so that 6 | # everyone who runs the test benefits from these saved cases. 7 | cc a01390e11049bb1e3e6d3a51a2b931d1ecd33bd7f2fec4faeaf321af663c9ea1 # shrinks to field_name = "env" 8 | -------------------------------------------------------------------------------- /src/autocomplete/insertion_tests/cursor_positioning_tests.rs: -------------------------------------------------------------------------------- 1 | //! Cursor positioning tests 2 | //! 3 | //! Note: Cursor positioning is tested implicitly in other test files 4 | //! as part of the insertion behavior. This file is a placeholder for 5 | //! any future explicit cursor positioning tests. 6 | 7 | // Cursor positioning is tested as part of the property tests and integration tests 8 | // No standalone cursor positioning tests at this time 9 | -------------------------------------------------------------------------------- /proptest-regressions/ai/ai_state_tests.txt: -------------------------------------------------------------------------------- 1 | # Seeds for failure cases proptest has generated in the past. It is 2 | # automatically read and these particular cases re-run before any 3 | # novel cases are generated. 4 | # 5 | # It is recommended to check this file in to source control so that 6 | # everyone who runs the test benefits from these saved cases. 7 | cc a669f33fe65e9e894fbac43ca915a4abd61e5d452e5218679a5d61b99cd296cf # shrinks to enabled = false 8 | -------------------------------------------------------------------------------- /proptest-regressions/app/app_events_tests.txt: -------------------------------------------------------------------------------- 1 | # Seeds for failure cases proptest has generated in the past. It is 2 | # automatically read and these particular cases re-run before any 3 | # novel cases are generated. 4 | # 5 | # It is recommended to check this file in to source control so that 6 | # everyone who runs the test benefits from these saved cases. 7 | cc 35a4e20c7fc5295c277ff0d8ab9d656a018004d25403670b34d1ab4c8e0b5eba # shrinks to query = ".a" 8 | -------------------------------------------------------------------------------- /src/snapshots/jiq__syntax_highlight__snapshot_tests__snapshot_number_literals.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/syntax/mod.rs 3 | expression: results 4 | --- 5 | - - "0" 6 | - - content: "0" 7 | fg: cyan 8 | - - "42" 9 | - - content: "42" 10 | fg: cyan 11 | - - "-123" 12 | - - content: "-123" 13 | fg: cyan 14 | - - "3.14" 15 | - - content: "3.14" 16 | fg: cyan 17 | - - "-0.5" 18 | - - content: "-0.5" 19 | fg: cyan 20 | -------------------------------------------------------------------------------- /src/clipboard/system.rs: -------------------------------------------------------------------------------- 1 | use arboard::Clipboard; 2 | 3 | use super::backend::{ClipboardError, ClipboardResult}; 4 | 5 | pub fn copy(text: &str) -> ClipboardResult { 6 | let mut clipboard = Clipboard::new().map_err(|_| ClipboardError::SystemUnavailable)?; 7 | 8 | clipboard 9 | .set_text(text) 10 | .map_err(|_| ClipboardError::WriteError) 11 | } 12 | 13 | #[cfg(test)] 14 | #[path = "system_tests.rs"] 15 | mod system_tests; 16 | -------------------------------------------------------------------------------- /src/tooltip.rs: -------------------------------------------------------------------------------- 1 | mod detector; 2 | mod operator_content; 3 | mod tooltip_content; 4 | pub mod tooltip_events; 5 | pub mod tooltip_render; 6 | mod tooltip_state; 7 | 8 | pub use detector::detect_function_at_cursor; 9 | pub use detector::detect_operator_at_cursor; 10 | pub use operator_content::get_operator_content; 11 | pub use tooltip_content::get_tooltip_content; 12 | pub use tooltip_state::TooltipState; 13 | pub use tooltip_state::update_tooltip_from_app; 14 | -------------------------------------------------------------------------------- /proptest-regressions/ai/provider_tests.txt: -------------------------------------------------------------------------------- 1 | # Seeds for failure cases proptest has generated in the past. It is 2 | # automatically read and these particular cases re-run before any 3 | # novel cases are generated. 4 | # 5 | # It is recommended to check this file in to source control so that 6 | # everyone who runs the test benefits from these saved cases. 7 | cc 3d08126d429b902ac0437d0ad5352659aaefbf1afdb6f5155474df64e252173d # shrinks to model = "-a-00", max_tokens = 256 8 | -------------------------------------------------------------------------------- /proptest-regressions/ai/ai_state.txt: -------------------------------------------------------------------------------- 1 | # Seeds for failure cases proptest has generated in the past. It is 2 | # automatically read and these particular cases re-run before any 3 | # novel cases are generated. 4 | # 5 | # It is recommended to check this file in to source control so that 6 | # everyone who runs the test benefits from these saved cases. 7 | cc 7368d9a5456e8e23c95b1a544e3603dbe864fbd48b4f40ffdb385604afd5f8aa # shrinks to query = " ", desc = "A", suggestion_type = "Fix" 8 | -------------------------------------------------------------------------------- /proptest-regressions/app/app_render.txt: -------------------------------------------------------------------------------- 1 | # Seeds for failure cases proptest has generated in the past. It is 2 | # automatically read and these particular cases re-run before any 3 | # novel cases are generated. 4 | # 5 | # It is recommended to check this file in to source control so that 6 | # everyone who runs the test benefits from these saved cases. 7 | cc 9f544744e4fbd935c831ff5f43242d82e0bc2becdf78d361646cb2f9516f9709 # shrinks to tooltip_enabled = false, has_function = false 8 | -------------------------------------------------------------------------------- /proptest-regressions/clipboard/clipboard_events_tests.txt: -------------------------------------------------------------------------------- 1 | # Seeds for failure cases proptest has generated in the past. It is 2 | # automatically read and these particular cases re-run before any 3 | # novel cases are generated. 4 | # 5 | # It is recommended to check this file in to source control so that 6 | # everyone who runs the test benefits from these saved cases. 7 | cc cbf7a887619257992e63750f856778f1c9a7423c730d640957d9abd7d7a1e4ff # shrinks to ansi_params = "", ansi_letter = "a" 8 | -------------------------------------------------------------------------------- /src/snapshots/jiq__syntax_highlight__snapshot_tests__snapshot_array_iteration.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/syntax/mod.rs 3 | expression: serialize_spans(&spans) 4 | --- 5 | - content: ".items" 6 | - content: "[" 7 | fg: magenta 8 | - content: "]" 9 | fg: magenta 10 | - content: " " 11 | - content: "|" 12 | fg: magenta 13 | - content: " " 14 | - content: select 15 | fg: blue 16 | - content: ( 17 | fg: magenta 18 | - content: ".active" 19 | - content: ) 20 | fg: magenta 21 | -------------------------------------------------------------------------------- /proptest-regressions/app/app_events/global_tests/autocomplete_tests.txt: -------------------------------------------------------------------------------- 1 | # Seeds for failure cases proptest has generated in the past. It is 2 | # automatically read and these particular cases re-run before any 3 | # novel cases are generated. 4 | # 5 | # It is recommended to check this file in to source control so that 6 | # everyone who runs the test benefits from these saved cases. 7 | cc 7c7db1a2fa47e0480366bc14906f8e9b5e2550fb1cbc849cd3d4442c3dbf412c # shrinks to suggestion_text = "name" 8 | -------------------------------------------------------------------------------- /src/syntax_highlight_tests/snapshots/jiq__syntax_highlight__syntax_highlight_tests__snapshot_tests__snapshot_number_literals.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/syntax/mod.rs 3 | expression: results 4 | --- 5 | - - "0" 6 | - - content: "0" 7 | fg: cyan 8 | - - "42" 9 | - - content: "42" 10 | fg: cyan 11 | - - "-123" 12 | - - content: "-123" 13 | fg: cyan 14 | - - "3.14" 15 | - - content: "3.14" 16 | fg: cyan 17 | - - "-0.5" 18 | - - content: "-0.5" 19 | fg: cyan 20 | -------------------------------------------------------------------------------- /proptest-regressions/clipboard/events.txt: -------------------------------------------------------------------------------- 1 | # Seeds for failure cases proptest has generated in the past. It is 2 | # automatically read and these particular cases re-run before any 3 | # novel cases are generated. 4 | # 5 | # It is recommended to check this file in to source control so that 6 | # everyone who runs the test benefits from these saved cases. 7 | cc a39dc2a8e79d1d59aaf6d8f6d4e26edc0028d6a5bea9af32e034fa2a8cb92dad # shrinks to base_text = "\00\0\0¡ ¡\0¡¡ࠀ0ࠀ\0", ansi_params = "", ansi_letter = "a" 8 | -------------------------------------------------------------------------------- /proptest-regressions/search/events.txt: -------------------------------------------------------------------------------- 1 | # Seeds for failure cases proptest has generated in the past. It is 2 | # automatically read and these particular cases re-run before any 3 | # novel cases are generated. 4 | # 5 | # It is recommended to check this file in to source control so that 6 | # everyone who runs the test benefits from these saved cases. 7 | cc 4dc3025e0b0052d36aa8f33f8c92a1086f9e14beda0287c6e3793b7e48e94081 # shrinks to viewport_height = 11, max_offset = 71, initial_offset = 0, target_line = 82 8 | -------------------------------------------------------------------------------- /src/snapshots/jiq__syntax_highlight__snapshot_tests__snapshot_string_literals.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/syntax/mod.rs 3 | expression: results 4 | --- 5 | - - "\"hello\"" 6 | - - content: "\"hello\"" 7 | fg: green 8 | - - "\"hello world\"" 9 | - - content: "\"hello world\"" 10 | fg: green 11 | - - "\"hello \\\"escaped\\\" world\"" 12 | - - content: "\"hello \\\"escaped\\\" world\"" 13 | fg: green 14 | - - "\"unicode: 世界\"" 15 | - - content: "\"unicode: 世界\"" 16 | fg: green 17 | -------------------------------------------------------------------------------- /src/editor/mode_tests.rs: -------------------------------------------------------------------------------- 1 | //! Tests for editor/mode 2 | 3 | use super::*; 4 | 5 | #[test] 6 | fn test_default_mode() { 7 | assert_eq!(EditorMode::default(), EditorMode::Insert); 8 | } 9 | 10 | #[test] 11 | fn test_mode_display() { 12 | assert_eq!(EditorMode::Insert.display(), "INSERT"); 13 | assert_eq!(EditorMode::Normal.display(), "NORMAL"); 14 | assert_eq!(EditorMode::Operator('d').display(), "OPERATOR(d)"); 15 | assert_eq!(EditorMode::Operator('c').display(), "OPERATOR(c)"); 16 | } 17 | -------------------------------------------------------------------------------- /proptest-regressions/app/app_events/global_tests/ai_suggestion_tests.txt: -------------------------------------------------------------------------------- 1 | # Seeds for failure cases proptest has generated in the past. It is 2 | # automatically read and these particular cases re-run before any 3 | # novel cases are generated. 4 | # 5 | # It is recommended to check this file in to source control so that 6 | # everyone who runs the test benefits from these saved cases. 7 | cc 8896657cc70e8ea5f77943d0d78f633b6b4199c597e38ed9aa2cd289ecf35370 # shrinks to mode_idx = 0, nav_steps = 1, suggestion_query = ".name" 8 | -------------------------------------------------------------------------------- /src/syntax_highlight_tests/snapshots/jiq__syntax_highlight__syntax_highlight_tests__snapshot_tests__snapshot_array_iteration.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/syntax/mod.rs 3 | expression: serialize_spans(&spans) 4 | --- 5 | - content: ".items" 6 | - content: "[" 7 | fg: magenta 8 | - content: "]" 9 | fg: magenta 10 | - content: " " 11 | - content: "|" 12 | fg: magenta 13 | - content: " " 14 | - content: select 15 | fg: blue 16 | - content: ( 17 | fg: magenta 18 | - content: ".active" 19 | - content: ) 20 | fg: magenta 21 | -------------------------------------------------------------------------------- /src/error.rs: -------------------------------------------------------------------------------- 1 | use thiserror::Error; 2 | 3 | #[derive(Debug, Error, Clone, PartialEq)] 4 | pub enum JiqError { 5 | #[error("jq binary not found in PATH.\n\nInstall jq from: https://jqlang.org/download/")] 6 | JqNotFound, 7 | 8 | #[error("Invalid JSON input: {0}")] 9 | InvalidJson(String), 10 | 11 | #[error("IO error: {0}")] 12 | Io(String), 13 | } 14 | 15 | impl From for JiqError { 16 | fn from(err: std::io::Error) -> Self { 17 | JiqError::Io(err.to_string()) 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/syntax_highlight/overlay_tests.rs: -------------------------------------------------------------------------------- 1 | //! Tests for syntax_highlight/overlay 2 | 3 | #[path = "overlay_tests/unit_tests.rs"] 4 | mod unit_tests; 5 | 6 | #[path = "overlay_tests/snapshot_tests.rs"] 7 | mod snapshot_tests; 8 | 9 | // Re-export common test utilities 10 | pub(crate) use super::*; 11 | pub(crate) use ratatui::style::{Color, Modifier, Style}; 12 | pub(crate) use ratatui::text::Span; 13 | 14 | // Re-export snapshot helpers from parent module 15 | pub(crate) use crate::syntax_highlight::snapshot_helpers::serialize_spans; 16 | -------------------------------------------------------------------------------- /proptest-regressions/search/search_events_tests/navigation_tests.txt: -------------------------------------------------------------------------------- 1 | # Seeds for failure cases proptest has generated in the past. It is 2 | # automatically read and these particular cases re-run before any 3 | # novel cases are generated. 4 | # 5 | # It is recommended to check this file in to source control so that 6 | # everyone who runs the test benefits from these saved cases. 7 | cc 9e57d7828d099dac8879b389696628f45022dfdd05670e84c7408a11daf82104 # shrinks to viewport_width = 20, max_h_offset = 20, initial_h_offset_factor = 0.0, key_type = 0 8 | -------------------------------------------------------------------------------- /src/syntax_highlight_tests/snapshots/jiq__syntax_highlight__syntax_highlight_tests__snapshot_tests__snapshot_string_literals.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/syntax/mod.rs 3 | expression: results 4 | --- 5 | - - "\"hello\"" 6 | - - content: "\"hello\"" 7 | fg: green 8 | - - "\"hello world\"" 9 | - - content: "\"hello world\"" 10 | fg: green 11 | - - "\"hello \\\"escaped\\\" world\"" 12 | - - content: "\"hello \\\"escaped\\\" world\"" 13 | fg: green 14 | - - "\"unicode: 世界\"" 15 | - - content: "\"unicode: 世界\"" 16 | fg: green 17 | -------------------------------------------------------------------------------- /src/help/help_state.rs: -------------------------------------------------------------------------------- 1 | use crate::scroll::ScrollState; 2 | 3 | pub struct HelpPopupState { 4 | pub visible: bool, 5 | pub scroll: ScrollState, 6 | } 7 | 8 | impl HelpPopupState { 9 | pub fn new() -> Self { 10 | Self { 11 | visible: false, 12 | scroll: ScrollState::new(), 13 | } 14 | } 15 | } 16 | 17 | impl Default for HelpPopupState { 18 | fn default() -> Self { 19 | Self::new() 20 | } 21 | } 22 | 23 | #[cfg(test)] 24 | #[path = "help_state_tests.rs"] 25 | mod help_state_tests; 26 | -------------------------------------------------------------------------------- /src/app/snapshots/jiq__app__render__snapshot_tests__snapshot_ui_small_terminal.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/app/render.rs 3 | expression: output 4 | --- 5 | "┌ Object ──────────────────────────────┐" 6 | "│{ │" 7 | "│ "name": "Alice" │" 8 | "│} │" 9 | "│ │" 10 | "└──────────────────────────────────────┘" 11 | "┌ Query [INSERT] ──────────────────────┐" 12 | "│ │" 13 | "└──────────────────────────────────────┘" 14 | " F1: Help | Shift+Tab: Switch Pane | Ctr" 15 | -------------------------------------------------------------------------------- /src/snapshots/jiq__syntax_highlight__snapshot_tests__snapshot_pipe_chain.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/syntax/mod.rs 3 | expression: serialize_spans(&spans) 4 | --- 5 | - content: ".users" 6 | - content: " " 7 | - content: "|" 8 | fg: magenta 9 | - content: " " 10 | - content: map 11 | fg: blue 12 | - content: ( 13 | fg: magenta 14 | - content: ".name" 15 | - content: ) 16 | fg: magenta 17 | - content: " " 18 | - content: "|" 19 | fg: magenta 20 | - content: " " 21 | - content: sort 22 | fg: blue 23 | - content: " " 24 | - content: "|" 25 | fg: magenta 26 | - content: " " 27 | - content: unique 28 | fg: blue 29 | -------------------------------------------------------------------------------- /src/app/snapshots/jiq__app__app_render__snapshot_tests__snapshot_ui_small_terminal.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/app/app_render.rs 3 | expression: output 4 | --- 5 | "┌ Object ──────────────────────────────┐" 6 | "│{ │" 7 | "│ "name": "Alice" │" 8 | "│} │" 9 | "│ │" 10 | "└──────────────────────────────────────┘" 11 | "┌ Query [INSERT] rl+A for AI Assistant ┐" 12 | "│ │" 13 | "└──────────────────────────────────────┘" 14 | " F1: Help | Shift+Tab: Switch Pane | Ctr" 15 | -------------------------------------------------------------------------------- /proptest-regressions/tooltip/detector.txt: -------------------------------------------------------------------------------- 1 | # Seeds for failure cases proptest has generated in the past. It is 2 | # automatically read and these particular cases re-run before any 3 | # novel cases are generated. 4 | # 5 | # It is recommended to check this file in to source control so that 6 | # everyone who runs the test benefits from these saved cases. 7 | cc 9767abc038e24f3bbde8b235dc694b3c11e401807e718f355fe693295ce1ae64 # shrinks to func_index = 0, prefix = "", suffix = "a", cursor_offset = 0 8 | cc 2aad7530fd9591fb1cdf26232c4cc408c2b2f821015235f96bedd957e5b186f8 # shrinks to op_index = 3, prefix = ".", suffix = "", cursor_offset = 0 9 | -------------------------------------------------------------------------------- /tests/fixtures/nested.json: -------------------------------------------------------------------------------- 1 | { 2 | "company": "TechCorp", 3 | "departments": { 4 | "engineering": { 5 | "employees": [ 6 | { 7 | "name": "Alice", 8 | "role": "Engineer", 9 | "projects": ["Project A", "Project B"] 10 | }, 11 | { 12 | "name": "Bob", 13 | "role": "Manager", 14 | "projects": ["Project C"] 15 | } 16 | ] 17 | }, 18 | "sales": { 19 | "employees": [ 20 | { 21 | "name": "Charlie", 22 | "role": "Sales Rep", 23 | "projects": [] 24 | } 25 | ] 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/snapshots/jiq__syntax_highlight__snapshot_tests__snapshot_if_then_else.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/syntax/mod.rs 3 | expression: serialize_spans(&spans) 4 | --- 5 | - content: if 6 | fg: yellow 7 | - content: " " 8 | - content: ".value" 9 | - content: " " 10 | - content: ">" 11 | fg: magenta 12 | - content: " " 13 | - content: "10" 14 | fg: cyan 15 | - content: " " 16 | - content: then 17 | fg: yellow 18 | - content: " " 19 | - content: "\"high\"" 20 | fg: green 21 | - content: " " 22 | - content: else 23 | fg: yellow 24 | - content: " " 25 | - content: "\"low\"" 26 | fg: green 27 | - content: " " 28 | - content: end 29 | fg: yellow 30 | -------------------------------------------------------------------------------- /src/syntax_highlight_tests/snapshots/jiq__syntax_highlight__syntax_highlight_tests__snapshot_tests__snapshot_pipe_chain.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/syntax/mod.rs 3 | expression: serialize_spans(&spans) 4 | --- 5 | - content: ".users" 6 | - content: " " 7 | - content: "|" 8 | fg: magenta 9 | - content: " " 10 | - content: map 11 | fg: blue 12 | - content: ( 13 | fg: magenta 14 | - content: ".name" 15 | - content: ) 16 | fg: magenta 17 | - content: " " 18 | - content: "|" 19 | fg: magenta 20 | - content: " " 21 | - content: sort 22 | fg: blue 23 | - content: " " 24 | - content: "|" 25 | fg: magenta 26 | - content: " " 27 | - content: unique 28 | fg: blue 29 | -------------------------------------------------------------------------------- /src/clipboard/backend.rs: -------------------------------------------------------------------------------- 1 | use crate::config::ClipboardBackend; 2 | 3 | use super::{osc52, system}; 4 | 5 | pub type ClipboardResult = Result<(), ClipboardError>; 6 | 7 | #[derive(Debug)] 8 | pub enum ClipboardError { 9 | SystemUnavailable, 10 | WriteError, 11 | } 12 | 13 | pub fn copy_to_clipboard(text: &str, backend: ClipboardBackend) -> ClipboardResult { 14 | match backend { 15 | ClipboardBackend::System => system::copy(text), 16 | ClipboardBackend::Osc52 => osc52::copy(text), 17 | ClipboardBackend::Auto => system::copy(text).or_else(|_| osc52::copy(text)), 18 | } 19 | } 20 | 21 | #[cfg(test)] 22 | #[path = "backend_tests.rs"] 23 | mod backend_tests; 24 | -------------------------------------------------------------------------------- /src/syntax_highlight_tests/snapshots/jiq__syntax_highlight__syntax_highlight_tests__snapshot_tests__snapshot_if_then_else.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/syntax/mod.rs 3 | expression: serialize_spans(&spans) 4 | --- 5 | - content: if 6 | fg: yellow 7 | - content: " " 8 | - content: ".value" 9 | - content: " " 10 | - content: ">" 11 | fg: magenta 12 | - content: " " 13 | - content: "10" 14 | fg: cyan 15 | - content: " " 16 | - content: then 17 | fg: yellow 18 | - content: " " 19 | - content: "\"high\"" 20 | fg: green 21 | - content: " " 22 | - content: else 23 | fg: yellow 24 | - content: " " 25 | - content: "\"low\"" 26 | fg: green 27 | - content: " " 28 | - content: end 29 | fg: yellow 30 | -------------------------------------------------------------------------------- /src/snapshots/jiq__syntax_highlight__snapshot_tests__snapshot_reduce.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/syntax/mod.rs 3 | expression: serialize_spans(&spans) 4 | --- 5 | - content: reduce 6 | fg: yellow 7 | - content: " " 8 | - content: "." 9 | - content: "[" 10 | fg: magenta 11 | - content: "]" 12 | fg: magenta 13 | - content: " " 14 | - content: as 15 | fg: yellow 16 | - content: " " 17 | - content: $x 18 | - content: " " 19 | - content: ( 20 | fg: magenta 21 | - content: "0" 22 | fg: cyan 23 | - content: ; 24 | fg: magenta 25 | - content: " " 26 | - content: "." 27 | - content: " " 28 | - content: + 29 | fg: magenta 30 | - content: " " 31 | - content: $x 32 | - content: ) 33 | fg: magenta 34 | -------------------------------------------------------------------------------- /src/history/storage_tests.rs: -------------------------------------------------------------------------------- 1 | //! Tests for history/storage 2 | 3 | use super::*; 4 | 5 | #[test] 6 | fn test_deduplicate_keeps_first_occurrence() { 7 | let entries = vec![ 8 | "a".to_string(), 9 | "b".to_string(), 10 | "a".to_string(), 11 | "c".to_string(), 12 | "b".to_string(), 13 | ]; 14 | let result = deduplicate(&entries); 15 | assert_eq!(result, vec!["a", "b", "c"]); 16 | } 17 | 18 | #[test] 19 | fn test_trim_to_max() { 20 | let entries: Vec = (0..1500).map(|i| format!("entry{}", i)).collect(); 21 | let trimmed = trim_to_max(&entries); 22 | assert_eq!(trimmed.len(), MAX_HISTORY_ENTRIES); 23 | assert_eq!(trimmed[0], "entry0"); 24 | } 25 | -------------------------------------------------------------------------------- /src/snapshots/jiq__syntax_highlight__snapshot_tests__snapshot_object_construction.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/syntax/mod.rs 3 | expression: serialize_spans(&spans) 4 | --- 5 | - content: "{" 6 | fg: magenta 7 | - content: name 8 | fg: cyan 9 | - content: ":" 10 | fg: magenta 11 | - content: " " 12 | - content: ".name" 13 | - content: "," 14 | fg: magenta 15 | - content: " " 16 | - content: age 17 | fg: cyan 18 | - content: ":" 19 | fg: magenta 20 | - content: " " 21 | - content: ".age" 22 | - content: "," 23 | fg: magenta 24 | - content: " " 25 | - content: active 26 | fg: cyan 27 | - content: ":" 28 | fg: magenta 29 | - content: " " 30 | - content: "true" 31 | fg: yellow 32 | - content: "}" 33 | fg: magenta 34 | -------------------------------------------------------------------------------- /proptest-regressions/ai/ai_render_tests/content_tests.txt: -------------------------------------------------------------------------------- 1 | # Seeds for failure cases proptest has generated in the past. It is 2 | # automatically read and these particular cases re-run before any 3 | # novel cases are generated. 4 | # 5 | # It is recommended to check this file in to source control so that 6 | # everyone who runs the test benefits from these saved cases. 7 | cc 07da8fa5d74e0a766c9395eacc99792a0c8ebc72ec91f9bb0027c036b9e8cd93 # shrinks to suggestion_count = 2, selected_index = 0 8 | cc 7c38b483080456eeb35180ecf9e50fbd5736600ce7010fabfc8f0b468fcae4af # shrinks to suggestion_count = 5, selected_index = 2 9 | cc a7cb30aa910a0b0df03ea831365e8804326499152d7d2c7eecb2bd1df22a60a0 # shrinks to suggestion_count = 9, selected_index = 4 10 | -------------------------------------------------------------------------------- /src/clipboard/osc52.rs: -------------------------------------------------------------------------------- 1 | use base64::{Engine as _, engine::general_purpose::STANDARD}; 2 | use std::io::{self, Write}; 3 | 4 | use super::backend::{ClipboardError, ClipboardResult}; 5 | 6 | pub fn copy(text: &str) -> ClipboardResult { 7 | let sequence = encode_osc52(text); 8 | 9 | // Write directly to stdout 10 | io::stdout() 11 | .write_all(sequence.as_bytes()) 12 | .map_err(|_| ClipboardError::WriteError)?; 13 | 14 | io::stdout().flush().map_err(|_| ClipboardError::WriteError) 15 | } 16 | 17 | pub fn encode_osc52(text: &str) -> String { 18 | let encoded = STANDARD.encode(text); 19 | format!("\x1b]52;c;{}\x07", encoded) 20 | } 21 | 22 | #[cfg(test)] 23 | #[path = "osc52_tests.rs"] 24 | mod osc52_tests; 25 | -------------------------------------------------------------------------------- /src/syntax_highlight_tests/snapshots/jiq__syntax_highlight__syntax_highlight_tests__snapshot_tests__snapshot_reduce.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/syntax/mod.rs 3 | expression: serialize_spans(&spans) 4 | --- 5 | - content: reduce 6 | fg: yellow 7 | - content: " " 8 | - content: "." 9 | - content: "[" 10 | fg: magenta 11 | - content: "]" 12 | fg: magenta 13 | - content: " " 14 | - content: as 15 | fg: yellow 16 | - content: " " 17 | - content: $x 18 | - content: " " 19 | - content: ( 20 | fg: magenta 21 | - content: "0" 22 | fg: cyan 23 | - content: ; 24 | fg: magenta 25 | - content: " " 26 | - content: "." 27 | - content: " " 28 | - content: + 29 | fg: magenta 30 | - content: " " 31 | - content: $x 32 | - content: ) 33 | fg: magenta 34 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | //! jiq library - Interactive JSON query tool 2 | //! 3 | //! This library exposes the core functionality of jiq for testing purposes. 4 | 5 | pub mod ai; 6 | pub mod app; 7 | pub mod autocomplete; 8 | pub mod clipboard; 9 | pub mod config; 10 | pub mod editor; 11 | pub mod error; 12 | pub mod help; 13 | pub mod history; 14 | pub mod input; 15 | pub mod json; 16 | pub mod notification; 17 | pub mod query; 18 | pub mod results; 19 | pub mod scroll; 20 | pub mod search; 21 | pub mod stats; 22 | pub mod syntax_highlight; 23 | 24 | #[cfg(test)] 25 | pub mod test_utils; 26 | pub mod tooltip; 27 | pub mod widgets; 28 | 29 | // Re-export commonly used types for convenience 30 | pub use app::{App, Focus, OutputMode}; 31 | pub use config::Config; 32 | -------------------------------------------------------------------------------- /src/syntax_highlight_tests/snapshots/jiq__syntax_highlight__syntax_highlight_tests__snapshot_tests__snapshot_object_construction.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/syntax/mod.rs 3 | expression: serialize_spans(&spans) 4 | --- 5 | - content: "{" 6 | fg: magenta 7 | - content: name 8 | fg: cyan 9 | - content: ":" 10 | fg: magenta 11 | - content: " " 12 | - content: ".name" 13 | - content: "," 14 | fg: magenta 15 | - content: " " 16 | - content: age 17 | fg: cyan 18 | - content: ":" 19 | fg: magenta 20 | - content: " " 21 | - content: ".age" 22 | - content: "," 23 | fg: magenta 24 | - content: " " 25 | - content: active 26 | fg: cyan 27 | - content: ":" 28 | fg: magenta 29 | - content: " " 30 | - content: "true" 31 | fg: yellow 32 | - content: "}" 33 | fg: magenta 34 | -------------------------------------------------------------------------------- /proptest-regressions/ai/ai_render_tests/model_name_tests.txt: -------------------------------------------------------------------------------- 1 | # Seeds for failure cases proptest has generated in the past. It is 2 | # automatically read and these particular cases re-run before any 3 | # novel cases are generated. 4 | # 5 | # It is recommended to check this file in to source control so that 6 | # everyone who runs the test benefits from these saved cases. 7 | cc fb2493bc123007df467f25fef0fae1419be073b6d410d2c5cdd25358382f2807 # shrinks to model_name = "0a A0྾🌀Σ0೦ꟕ®𐺰A\u{11c92} ¡𐺀", popup_width = 54 8 | cc e020cea4ff8c769fe237a1d17cce4686bbb24b77e08ec16bd0765a24387c1304 # shrinks to model_name = "aA 𑣿ਫ਼ A ড়🌀A 0𐖳0 aAAA𐬀Aぁ\u{8e3}𐤿", popup_width = 80 9 | cc a25ffef9bc13cd55a4b4fe9cb5c6e2486e71a66d0b178588254d6eef232fecee # shrinks to model_name = "...", popup_width = 40 10 | -------------------------------------------------------------------------------- /src/editor/mode.rs: -------------------------------------------------------------------------------- 1 | /// VIM editing modes for the input field 2 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] 3 | pub enum EditorMode { 4 | /// Insert mode - typing inserts characters 5 | #[default] 6 | Insert, 7 | /// Normal mode - VIM navigation and commands 8 | Normal, 9 | /// Operator mode - waiting for motion after operator (d or c) 10 | Operator(char), 11 | } 12 | 13 | impl EditorMode { 14 | /// Get the display string for the mode indicator 15 | pub fn display(&self) -> String { 16 | match self { 17 | EditorMode::Insert => "INSERT".to_string(), 18 | EditorMode::Normal => "NORMAL".to_string(), 19 | EditorMode::Operator(op) => format!("OPERATOR({})", op), 20 | } 21 | } 22 | } 23 | 24 | #[cfg(test)] 25 | #[path = "mode_tests.rs"] 26 | mod mode_tests; 27 | -------------------------------------------------------------------------------- /dist-workspace.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = ["cargo:."] 3 | 4 | # Config for 'dist' 5 | [dist] 6 | # The preferred dist version to use in CI (Cargo.toml SemVer syntax) 7 | cargo-dist-version = "0.30.2" 8 | # CI backends to support 9 | ci = "github" 10 | # The installers to generate for each app 11 | installers = ["shell", "homebrew"] 12 | # A GitHub repo to push Homebrew formulas to 13 | tap = "bellicose100xp/homebrew-tap" 14 | # Target platforms to build apps for (Rust target-triple syntax) 15 | targets = ["aarch64-apple-darwin", "aarch64-unknown-linux-gnu", "x86_64-apple-darwin", "x86_64-unknown-linux-gnu", "x86_64-unknown-linux-musl", "x86_64-pc-windows-msvc"] 16 | # Path that installers should place binaries in 17 | install-path = "CARGO_HOME" 18 | # Publish jobs to run in CI 19 | publish-jobs = ["homebrew"] 20 | # Whether to install an updater program 21 | install-updater = false 22 | -------------------------------------------------------------------------------- /src/ai/provider_tests.rs: -------------------------------------------------------------------------------- 1 | //! Tests for AI provider abstraction 2 | //! 3 | //! This module contains tests for provider configuration validation, error handling, 4 | //! and factory methods. Tests are organized into submodules by provider. 5 | 6 | // Re-export test modules 7 | #[path = "provider_tests/anthropic_tests.rs"] 8 | mod anthropic_tests; 9 | #[path = "provider_tests/bedrock_tests.rs"] 10 | mod bedrock_tests; 11 | #[path = "provider_tests/error_tests.rs"] 12 | mod error_tests; 13 | #[path = "provider_tests/gemini_tests.rs"] 14 | mod gemini_tests; 15 | #[path = "provider_tests/openai_tests.rs"] 16 | mod openai_tests; 17 | 18 | // Re-export common imports for use in submodules 19 | pub(crate) use super::*; 20 | pub(crate) use crate::config::ai_types::{ 21 | AiConfig, AiProviderType, AnthropicConfig, BedrockConfig, GeminiConfig, OpenAiConfig, 22 | }; 23 | pub(crate) use proptest::prelude::*; 24 | -------------------------------------------------------------------------------- /src/autocomplete/insertion/cursor.rs: -------------------------------------------------------------------------------- 1 | //! Cursor positioning utilities for autocomplete insertion 2 | 3 | use tui_textarea::{CursorMove, TextArea}; 4 | 5 | /// Move cursor to a specific column position 6 | pub fn move_cursor_to_column(textarea: &mut TextArea<'_>, target_col: usize) { 7 | let current_col = textarea.cursor().1; 8 | 9 | match target_col.cmp(¤t_col) { 10 | std::cmp::Ordering::Less => { 11 | // Move backward 12 | for _ in 0..(current_col - target_col) { 13 | textarea.move_cursor(CursorMove::Back); 14 | } 15 | } 16 | std::cmp::Ordering::Greater => { 17 | // Move forward 18 | for _ in 0..(target_col - current_col) { 19 | textarea.move_cursor(CursorMove::Forward); 20 | } 21 | } 22 | std::cmp::Ordering::Equal => { 23 | // Already at target position 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/snapshots/jiq__syntax_highlight__snapshot_tests__snapshot_common_functions.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/syntax/mod.rs 3 | expression: results 4 | --- 5 | - - map 6 | - - content: map 7 | fg: blue 8 | - - select 9 | - - content: select 10 | fg: blue 11 | - - sort 12 | - - content: sort 13 | fg: blue 14 | - - keys 15 | - - content: keys 16 | fg: blue 17 | - - values 18 | - - content: values 19 | fg: blue 20 | - - length 21 | - - content: length 22 | fg: blue 23 | - - type 24 | - - content: type 25 | fg: blue 26 | - - add 27 | - - content: add 28 | fg: blue 29 | - - first 30 | - - content: first 31 | fg: blue 32 | - - last 33 | - - content: last 34 | fg: blue 35 | - - has 36 | - - content: has 37 | fg: blue 38 | - - contains 39 | - - content: contains 40 | fg: blue 41 | - - split 42 | - - content: split 43 | fg: blue 44 | - - join 45 | - - content: join 46 | fg: blue 47 | -------------------------------------------------------------------------------- /src/ai/ai_render_tests.rs: -------------------------------------------------------------------------------- 1 | //! Tests for AI render module 2 | //! 3 | //! This module organizes tests for the AI rendering functionality. 4 | 5 | // Module declarations using #[path] attributes 6 | #[path = "ai_render_tests/content_tests.rs"] 7 | mod content_tests; 8 | #[path = "ai_render_tests/height_persistence_tests.rs"] 9 | mod height_persistence_tests; 10 | #[path = "ai_render_tests/layout_tests.rs"] 11 | mod layout_tests; 12 | #[path = "ai_render_tests/model_name_tests.rs"] 13 | mod model_name_tests; 14 | #[path = "ai_render_tests/snapshot_tests.rs"] 15 | mod snapshot_tests; 16 | #[path = "ai_render_tests/spacing_tests.rs"] 17 | mod spacing_tests; 18 | #[path = "ai_render_tests/widget_background_unit_tests.rs"] 19 | mod widget_background_unit_tests; 20 | #[path = "ai_render_tests/widget_selection_tests.rs"] 21 | mod widget_selection_tests; 22 | 23 | // Re-export items from parent module for test use 24 | pub(crate) use super::ai_render::*; 25 | pub(crate) use super::ai_state::AiState; 26 | -------------------------------------------------------------------------------- /src/autocomplete/scan_state.rs: -------------------------------------------------------------------------------- 1 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] 2 | pub enum ScanState { 3 | #[default] 4 | Normal, 5 | InString, 6 | InStringEscape, 7 | } 8 | 9 | impl ScanState { 10 | pub fn advance(self, ch: char) -> Self { 11 | match self { 12 | ScanState::Normal => match ch { 13 | '"' => ScanState::InString, 14 | _ => ScanState::Normal, 15 | }, 16 | ScanState::InString => match ch { 17 | '\\' => ScanState::InStringEscape, 18 | '"' => ScanState::Normal, 19 | _ => ScanState::InString, 20 | }, 21 | ScanState::InStringEscape => ScanState::InString, 22 | } 23 | } 24 | 25 | pub fn is_in_string(self) -> bool { 26 | matches!(self, ScanState::InString | ScanState::InStringEscape) 27 | } 28 | } 29 | 30 | #[cfg(test)] 31 | #[path = "scan_state_tests.rs"] 32 | mod scan_state_tests; 33 | -------------------------------------------------------------------------------- /src/tooltip/tooltip_events_tests.rs: -------------------------------------------------------------------------------- 1 | //! Tests for tooltip/tooltip_events 2 | 3 | use super::*; 4 | 5 | #[test] 6 | fn test_handle_tooltip_toggle_from_enabled() { 7 | let mut state = TooltipState::new(true); 8 | assert!(state.enabled); 9 | 10 | let handled = handle_tooltip_toggle(&mut state); 11 | 12 | assert!(handled); 13 | assert!(!state.enabled); 14 | } 15 | 16 | #[test] 17 | fn test_handle_tooltip_toggle_from_disabled() { 18 | let mut state = TooltipState::new(false); 19 | assert!(!state.enabled); 20 | 21 | let handled = handle_tooltip_toggle(&mut state); 22 | 23 | assert!(handled); 24 | assert!(state.enabled); 25 | } 26 | 27 | #[test] 28 | fn test_handle_tooltip_toggle_preserves_current_function() { 29 | let mut state = TooltipState::new(true); 30 | state.set_current_function(Some("select".to_string())); 31 | 32 | handle_tooltip_toggle(&mut state); 33 | 34 | assert_eq!(state.current_function, Some("select".to_string())); 35 | } 36 | -------------------------------------------------------------------------------- /src/syntax_highlight_tests/snapshots/jiq__syntax_highlight__syntax_highlight_tests__snapshot_tests__snapshot_common_functions.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/syntax/mod.rs 3 | expression: results 4 | --- 5 | - - map 6 | - - content: map 7 | fg: blue 8 | - - select 9 | - - content: select 10 | fg: blue 11 | - - sort 12 | - - content: sort 13 | fg: blue 14 | - - keys 15 | - - content: keys 16 | fg: blue 17 | - - values 18 | - - content: values 19 | fg: blue 20 | - - length 21 | - - content: length 22 | fg: blue 23 | - - type 24 | - - content: type 25 | fg: blue 26 | - - add 27 | - - content: add 28 | fg: blue 29 | - - first 30 | - - content: first 31 | fg: blue 32 | - - last 33 | - - content: last 34 | fg: blue 35 | - - has 36 | - - content: has 37 | fg: blue 38 | - - contains 39 | - - content: contains 40 | fg: blue 41 | - - split 42 | - - content: split 43 | fg: blue 44 | - - join 45 | - - content: join 46 | fg: blue 47 | -------------------------------------------------------------------------------- /src/help/help_line_render.rs: -------------------------------------------------------------------------------- 1 | use ratatui::{ 2 | Frame, 3 | layout::Rect, 4 | style::{Color, Style}, 5 | widgets::Paragraph, 6 | }; 7 | 8 | use crate::app::{App, Focus}; 9 | use crate::editor::EditorMode; 10 | 11 | pub fn render_line(app: &App, frame: &mut Frame, area: Rect) { 12 | let help_text = if app.focus == Focus::InputField && app.input.editor_mode == EditorMode::Insert 13 | { 14 | let query_empty = app.query().is_empty(); 15 | if query_empty { 16 | " F1: Help | Shift+Tab: Switch Pane | Ctrl+P/N: Cycle History | ↑/Ctrl+R: History" 17 | } else { 18 | " F1: Help | Shift+Tab: Switch Pane | ↑/Ctrl+R: History | Enter: Output Result | Ctrl+Q: Output Query" 19 | } 20 | } else { 21 | " F1/?: Help | Shift+Tab: Switch Pane | Enter: Output Result | Ctrl+Q: Output Query | q: Quit" 22 | }; 23 | 24 | let help = Paragraph::new(help_text).style(Style::default().fg(Color::DarkGray)); 25 | 26 | frame.render_widget(help, area); 27 | } 28 | -------------------------------------------------------------------------------- /src/clipboard/backend_tests.rs: -------------------------------------------------------------------------------- 1 | //! Tests for clipboard/backend 2 | 3 | use super::*; 4 | 5 | #[test] 6 | fn test_copy_to_clipboard_osc52_backend() { 7 | let result = copy_to_clipboard("test", ClipboardBackend::Osc52); 8 | assert!(result.is_ok()); 9 | } 10 | 11 | #[test] 12 | fn test_copy_to_clipboard_system_backend() { 13 | let result = copy_to_clipboard("test", ClipboardBackend::System); 14 | assert!(result.is_ok() || matches!(result, Err(ClipboardError::SystemUnavailable))); 15 | } 16 | 17 | #[test] 18 | fn test_copy_to_clipboard_auto_backend() { 19 | let result = copy_to_clipboard("test", ClipboardBackend::Auto); 20 | assert!(result.is_ok()); 21 | } 22 | 23 | #[test] 24 | fn test_copy_to_clipboard_empty_string() { 25 | let result = copy_to_clipboard("", ClipboardBackend::Osc52); 26 | assert!(result.is_ok()); 27 | } 28 | 29 | #[test] 30 | fn test_copy_to_clipboard_unicode() { 31 | let result = copy_to_clipboard("日本語 🎉", ClipboardBackend::Osc52); 32 | assert!(result.is_ok()); 33 | } 34 | -------------------------------------------------------------------------------- /src/ai.rs: -------------------------------------------------------------------------------- 1 | //! AI Assistant module for jiq 2 | //! 3 | //! Provides AI-powered contextual help for jq queries, including error troubleshooting, 4 | //! function explanations, and query optimization suggestions. 5 | 6 | pub mod ai_events; 7 | pub mod ai_render; 8 | pub mod ai_state; // Made public for integration tests 9 | mod cache; 10 | pub mod context; 11 | pub mod prompt; 12 | mod provider; 13 | pub mod render; 14 | pub mod selection; 15 | pub mod suggestion; 16 | pub mod worker; 17 | 18 | #[cfg(test)] 19 | mod ai_events_tests; 20 | 21 | #[cfg(test)] 22 | mod ai_render_tests; 23 | 24 | // Note: ai_state_tests is declared in ai_state.rs to avoid duplicate module loading 25 | 26 | // Re-export main types (others are internal for Phase 1) 27 | pub use ai_state::AiState; 28 | // TODO: Remove #[allow(unused_imports)] when AiRequest/AiResponse are used externally 29 | #[allow(unused_imports)] 30 | pub use ai_state::{AiRequest, AiResponse}; 31 | // Re-export suggestion types 32 | #[allow(unused_imports)] 33 | pub use suggestion::{Suggestion, SuggestionType}; 34 | -------------------------------------------------------------------------------- /LICENSE-MIT: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2025 jiq contributors 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/stats/stats_state.rs: -------------------------------------------------------------------------------- 1 | use crate::app::App; 2 | use crate::stats::parser::StatsParser; 3 | use crate::stats::types::ResultStats; 4 | 5 | pub fn update_stats_from_app(app: &mut App) { 6 | // Only update if query state is available 7 | let query_state = match &app.query { 8 | Some(q) => q, 9 | None => return, 10 | }; 11 | 12 | if let Some(result) = &query_state.last_successful_result_unformatted { 13 | app.stats.compute(result); 14 | } 15 | } 16 | 17 | #[derive(Debug, Clone, Default)] 18 | pub struct StatsState { 19 | stats: Option, 20 | } 21 | 22 | impl StatsState { 23 | pub fn compute(&mut self, result: &str) { 24 | let trimmed = result.trim(); 25 | if trimmed.is_empty() { 26 | return; 27 | } 28 | self.stats = Some(StatsParser::parse(result)); 29 | } 30 | 31 | pub fn display(&self) -> Option { 32 | self.stats.as_ref().map(|s| s.to_string()) 33 | } 34 | 35 | #[cfg(test)] 36 | pub fn stats(&self) -> Option<&ResultStats> { 37 | self.stats.as_ref() 38 | } 39 | } 40 | 41 | #[cfg(test)] 42 | #[path = "stats_state_tests.rs"] 43 | mod stats_state_tests; 44 | -------------------------------------------------------------------------------- /src/snapshots/jiq__syntax_highlight__snapshot_tests__snapshot_keywords.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/syntax/mod.rs 3 | expression: results 4 | --- 5 | - - if 6 | - - content: if 7 | fg: yellow 8 | - - then 9 | - - content: then 10 | fg: yellow 11 | - - else 12 | - - content: else 13 | fg: yellow 14 | - - elif 15 | - - content: elif 16 | fg: yellow 17 | - - end 18 | - - content: end 19 | fg: yellow 20 | - - and 21 | - - content: and 22 | fg: yellow 23 | - - or 24 | - - content: or 25 | fg: yellow 26 | - - not 27 | - - content: not 28 | fg: yellow 29 | - - as 30 | - - content: as 31 | fg: yellow 32 | - - def 33 | - - content: def 34 | fg: yellow 35 | - - reduce 36 | - - content: reduce 37 | fg: yellow 38 | - - foreach 39 | - - content: foreach 40 | fg: yellow 41 | - - try 42 | - - content: try 43 | fg: yellow 44 | - - catch 45 | - - content: catch 46 | fg: yellow 47 | - - empty 48 | - - content: empty 49 | fg: yellow 50 | - - "null" 51 | - - content: "null" 52 | fg: yellow 53 | - - "true" 54 | - - content: "true" 55 | fg: yellow 56 | - - "false" 57 | - - content: "false" 58 | fg: yellow 59 | -------------------------------------------------------------------------------- /src/syntax_highlight_tests/snapshots/jiq__syntax_highlight__syntax_highlight_tests__snapshot_tests__snapshot_keywords.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/syntax/mod.rs 3 | expression: results 4 | --- 5 | - - if 6 | - - content: if 7 | fg: yellow 8 | - - then 9 | - - content: then 10 | fg: yellow 11 | - - else 12 | - - content: else 13 | fg: yellow 14 | - - elif 15 | - - content: elif 16 | fg: yellow 17 | - - end 18 | - - content: end 19 | fg: yellow 20 | - - and 21 | - - content: and 22 | fg: yellow 23 | - - or 24 | - - content: or 25 | fg: yellow 26 | - - not 27 | - - content: not 28 | fg: yellow 29 | - - as 30 | - - content: as 31 | fg: yellow 32 | - - def 33 | - - content: def 34 | fg: yellow 35 | - - reduce 36 | - - content: reduce 37 | fg: yellow 38 | - - foreach 39 | - - content: foreach 40 | fg: yellow 41 | - - try 42 | - - content: try 43 | fg: yellow 44 | - - catch 45 | - - content: catch 46 | fg: yellow 47 | - - empty 48 | - - content: empty 49 | fg: yellow 50 | - - "null" 51 | - - content: "null" 52 | fg: yellow 53 | - - "true" 54 | - - content: "true" 55 | fg: yellow 56 | - - "false" 57 | - - content: "false" 58 | fg: yellow 59 | -------------------------------------------------------------------------------- /src/ai/render/text.rs: -------------------------------------------------------------------------------- 1 | //! Text utilities for AI popup rendering 2 | //! 3 | //! Handles text wrapping and formatting. 4 | 5 | #![allow(dead_code)] 6 | 7 | /// Wrap text to fit within a given width, breaking at word boundaries 8 | pub fn wrap_text(text: &str, max_width: usize) -> Vec { 9 | if max_width == 0 { 10 | return vec![text.to_string()]; 11 | } 12 | 13 | let mut lines = Vec::new(); 14 | 15 | for paragraph in text.lines() { 16 | if paragraph.is_empty() { 17 | lines.push(String::new()); 18 | continue; 19 | } 20 | 21 | let mut current_line = String::new(); 22 | 23 | for word in paragraph.split_whitespace() { 24 | if current_line.is_empty() { 25 | current_line = word.to_string(); 26 | } else if current_line.len() + 1 + word.len() <= max_width { 27 | current_line.push(' '); 28 | current_line.push_str(word); 29 | } else { 30 | lines.push(current_line); 31 | current_line = word.to_string(); 32 | } 33 | } 34 | 35 | if !current_line.is_empty() { 36 | lines.push(current_line); 37 | } 38 | } 39 | 40 | if lines.is_empty() { 41 | lines.push(String::new()); 42 | } 43 | 44 | lines 45 | } 46 | -------------------------------------------------------------------------------- /src/snapshots/jiq__syntax_highlight__snapshot_tests__snapshot_operators.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/syntax/mod.rs 3 | expression: results 4 | --- 5 | - - "|" 6 | - - content: "|" 7 | fg: magenta 8 | - - "==" 9 | - - content: "==" 10 | fg: magenta 11 | - - "!=" 12 | - - content: "!=" 13 | fg: magenta 14 | - - "<=" 15 | - - content: "<=" 16 | fg: magenta 17 | - - ">=" 18 | - - content: ">=" 19 | fg: magenta 20 | - - // 21 | - - content: // 22 | fg: magenta 23 | - - + 24 | - - content: + 25 | fg: magenta 26 | - - "-" 27 | - - content: "-" 28 | fg: magenta 29 | - - "*" 30 | - - content: "*" 31 | fg: magenta 32 | - - / 33 | - - content: / 34 | fg: magenta 35 | - - "%" 36 | - - content: "%" 37 | fg: magenta 38 | - - ( 39 | - - content: ( 40 | fg: magenta 41 | - - ) 42 | - - content: ) 43 | fg: magenta 44 | - - "[" 45 | - - content: "[" 46 | fg: magenta 47 | - - "]" 48 | - - content: "]" 49 | fg: magenta 50 | - - "{" 51 | - - content: "{" 52 | fg: magenta 53 | - - "}" 54 | - - content: "}" 55 | fg: magenta 56 | - - "," 57 | - - content: "," 58 | fg: magenta 59 | - - ; 60 | - - content: ; 61 | fg: magenta 62 | - - ":" 63 | - - content: ":" 64 | fg: magenta 65 | - - "?" 66 | - - content: "?" 67 | fg: magenta 68 | -------------------------------------------------------------------------------- /src/search/matcher.rs: -------------------------------------------------------------------------------- 1 | use super::search_state::Match; 2 | 3 | pub struct SearchMatcher; 4 | 5 | impl SearchMatcher { 6 | pub fn find_all(content: &str, query: &str) -> Vec { 7 | if query.is_empty() { 8 | return Vec::new(); 9 | } 10 | 11 | let query_lower = query.to_lowercase(); 12 | let mut matches = Vec::new(); 13 | 14 | for (line_num, line) in content.lines().enumerate() { 15 | let line_lower = line.to_lowercase(); 16 | let mut search_start = 0; 17 | 18 | while let Some(byte_pos) = line_lower[search_start..].find(&query_lower) { 19 | let absolute_byte_pos = search_start + byte_pos; 20 | // Convert byte position to character position 21 | let col = line[..absolute_byte_pos].chars().count() as u16; 22 | let len = query.chars().count() as u16; 23 | 24 | matches.push(Match { 25 | line: line_num as u32, 26 | col, 27 | len, 28 | }); 29 | 30 | // Move past this match to find overlapping matches 31 | search_start = absolute_byte_pos + query_lower.len(); 32 | } 33 | } 34 | 35 | matches 36 | } 37 | } 38 | 39 | #[cfg(test)] 40 | #[path = "matcher_tests.rs"] 41 | mod matcher_tests; 42 | -------------------------------------------------------------------------------- /src/syntax_highlight_tests/snapshots/jiq__syntax_highlight__syntax_highlight_tests__snapshot_tests__snapshot_operators.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/syntax/mod.rs 3 | expression: results 4 | --- 5 | - - "|" 6 | - - content: "|" 7 | fg: magenta 8 | - - "==" 9 | - - content: "==" 10 | fg: magenta 11 | - - "!=" 12 | - - content: "!=" 13 | fg: magenta 14 | - - "<=" 15 | - - content: "<=" 16 | fg: magenta 17 | - - ">=" 18 | - - content: ">=" 19 | fg: magenta 20 | - - // 21 | - - content: // 22 | fg: magenta 23 | - - + 24 | - - content: + 25 | fg: magenta 26 | - - "-" 27 | - - content: "-" 28 | fg: magenta 29 | - - "*" 30 | - - content: "*" 31 | fg: magenta 32 | - - / 33 | - - content: / 34 | fg: magenta 35 | - - "%" 36 | - - content: "%" 37 | fg: magenta 38 | - - ( 39 | - - content: ( 40 | fg: magenta 41 | - - ) 42 | - - content: ) 43 | fg: magenta 44 | - - "[" 45 | - - content: "[" 46 | fg: magenta 47 | - - "]" 48 | - - content: "]" 49 | fg: magenta 50 | - - "{" 51 | - - content: "{" 52 | fg: magenta 53 | - - "}" 54 | - - content: "}" 55 | fg: magenta 56 | - - "," 57 | - - content: "," 58 | fg: magenta 59 | - - ; 60 | - - content: ; 61 | fg: magenta 62 | - - ":" 63 | - - content: ":" 64 | fg: magenta 65 | - - "?" 66 | - - content: "?" 67 | fg: magenta 68 | -------------------------------------------------------------------------------- /src/autocomplete.rs: -------------------------------------------------------------------------------- 1 | pub mod autocomplete_render; 2 | pub mod autocomplete_state; 3 | mod brace_tracker; 4 | mod context; 5 | pub mod insertion; 6 | pub mod jq_functions; 7 | mod result_analyzer; 8 | mod scan_state; 9 | 10 | #[cfg(test)] 11 | #[path = "autocomplete/insertion_tests.rs"] 12 | mod insertion_tests; 13 | 14 | pub use brace_tracker::BraceTracker; 15 | 16 | #[allow(unused_imports)] 17 | pub use autocomplete_state::{ 18 | AutocompleteState, JsonFieldType, Suggestion, SuggestionType, update_suggestions_from_app, 19 | }; 20 | pub use context::{ 21 | SuggestionContext, analyze_context, find_char_before_field_access, get_suggestions, 22 | }; 23 | pub use insertion::insert_suggestion_from_app; 24 | 25 | use crate::query::ResultType; 26 | use serde_json::Value; 27 | use std::sync::Arc; 28 | 29 | pub const MIN_CHARS_FOR_AUTOCOMPLETE: usize = 1; 30 | 31 | pub fn update_suggestions( 32 | autocomplete: &mut AutocompleteState, 33 | query: &str, 34 | cursor_pos: usize, 35 | result_parsed: Option>, 36 | result_type: Option, 37 | brace_tracker: &BraceTracker, 38 | ) { 39 | if query.trim().len() < MIN_CHARS_FOR_AUTOCOMPLETE { 40 | autocomplete.hide(); 41 | return; 42 | } 43 | 44 | let suggestions = get_suggestions(query, cursor_pos, result_parsed, result_type, brace_tracker); 45 | autocomplete.update_suggestions(suggestions); 46 | } 47 | -------------------------------------------------------------------------------- /src/ai/ai_events_tests.rs: -------------------------------------------------------------------------------- 1 | //! Tests for AI event handling 2 | //! 3 | //! This module contains unit tests and property-based tests for the AI event handlers. 4 | //! Tests are organized into separate submodules for better organization. 5 | 6 | // Re-export test modules 7 | #[path = "ai_events_tests/application_tests.rs"] 8 | mod application_tests; 9 | #[path = "ai_events_tests/debounce_tests.rs"] 10 | mod debounce_tests; 11 | #[path = "ai_events_tests/integration_tests.rs"] 12 | mod integration_tests; 13 | #[path = "ai_events_tests/property_tests.rs"] 14 | mod property_tests; 15 | #[path = "ai_events_tests/query_result_tests.rs"] 16 | mod query_result_tests; 17 | #[path = "ai_events_tests/selection_tests.rs"] 18 | mod selection_tests; 19 | #[path = "ai_events_tests/toggle_tests.rs"] 20 | mod toggle_tests; 21 | 22 | // Re-export common test utilities for use in submodules 23 | pub(crate) use super::ai_events::*; 24 | pub(crate) use super::ai_state::{AiRequest, AiResponse, AiState}; 25 | pub(crate) use proptest::prelude::*; 26 | pub(crate) use ratatui::crossterm::event::{KeyCode, KeyEvent, KeyModifiers}; 27 | pub(crate) use std::sync::mpsc; 28 | 29 | // Helper to create key events 30 | pub(crate) fn key(code: KeyCode) -> KeyEvent { 31 | KeyEvent::new(code, KeyModifiers::NONE) 32 | } 33 | 34 | pub(crate) fn key_with_mods(code: KeyCode, modifiers: KeyModifiers) -> KeyEvent { 35 | KeyEvent::new(code, modifiers) 36 | } 37 | -------------------------------------------------------------------------------- /src/search/search_render.rs: -------------------------------------------------------------------------------- 1 | use ratatui::{ 2 | Frame, 3 | layout::{Alignment, Rect}, 4 | style::{Color, Style}, 5 | text::{Line, Span}, 6 | widgets::{Block, Borders}, 7 | }; 8 | 9 | use crate::app::App; 10 | 11 | pub const SEARCH_BAR_HEIGHT: u16 = 3; 12 | 13 | pub fn render_bar(app: &mut App, frame: &mut Frame, area: Rect) { 14 | let match_count = app.search.match_count_display(); 15 | let match_count_style = if app.search.matches().is_empty() && !app.search.query().is_empty() { 16 | Style::default().fg(Color::Red) 17 | } else { 18 | Style::default().fg(Color::Gray) 19 | }; 20 | 21 | let block = Block::default() 22 | .borders(Borders::ALL) 23 | .title(" Search: ") 24 | .title_top( 25 | Line::from(Span::styled( 26 | format!(" {} ", match_count), 27 | match_count_style, 28 | )) 29 | .alignment(Alignment::Right), 30 | ) 31 | .border_style(Style::default().fg(Color::Cyan)) 32 | .style(Style::default().bg(Color::Black)); 33 | 34 | let inner_area = block.inner(area); 35 | frame.render_widget(block, area); 36 | 37 | let search_textarea = app.search.search_textarea_mut(); 38 | search_textarea.set_style(Style::default().fg(Color::White).bg(Color::Black)); 39 | search_textarea.set_cursor_line_style(Style::default()); 40 | frame.render_widget(&*search_textarea, inner_area); 41 | } 42 | -------------------------------------------------------------------------------- /src/widgets/popup.rs: -------------------------------------------------------------------------------- 1 | use ratatui::{Frame, layout::Rect, widgets::Clear}; 2 | 3 | pub fn centered_popup(frame_area: Rect, width: u16, height: u16) -> Rect { 4 | let popup_width = width.min(frame_area.width); 5 | let popup_height = height.min(frame_area.height); 6 | 7 | let popup_x = (frame_area.width.saturating_sub(popup_width)) / 2; 8 | let popup_y = (frame_area.height.saturating_sub(popup_height)) / 2; 9 | 10 | Rect { 11 | x: popup_x, 12 | y: popup_y, 13 | width: popup_width, 14 | height: popup_height, 15 | } 16 | } 17 | 18 | pub fn popup_above_anchor(anchor: Rect, width: u16, height: u16, x_offset: u16) -> Rect { 19 | let popup_x = anchor.x + x_offset; 20 | let popup_y = anchor.y.saturating_sub(height); 21 | 22 | Rect { 23 | x: popup_x, 24 | y: popup_y, 25 | width: width.min(anchor.width.saturating_sub(x_offset * 2)), 26 | height: height.min(anchor.y), 27 | } 28 | } 29 | 30 | pub fn inset_rect(area: Rect, horizontal_margin: u16, vertical_margin: u16) -> Rect { 31 | Rect { 32 | x: area.x + horizontal_margin, 33 | y: area.y + vertical_margin, 34 | width: area.width.saturating_sub(horizontal_margin * 2), 35 | height: area.height.saturating_sub(vertical_margin * 2), 36 | } 37 | } 38 | 39 | pub fn clear_area(frame: &mut Frame, area: Rect) { 40 | frame.render_widget(Clear, area); 41 | } 42 | 43 | #[cfg(test)] 44 | #[path = "popup_tests.rs"] 45 | mod popup_tests; 46 | -------------------------------------------------------------------------------- /src/autocomplete/insertion_tests.rs: -------------------------------------------------------------------------------- 1 | //! Tests for autocomplete insertion functionality 2 | 3 | // Test submodules 4 | #[path = "insertion_tests/cursor_positioning_tests.rs"] 5 | mod cursor_positioning_tests; 6 | #[path = "insertion_tests/field_context_tests.rs"] 7 | mod field_context_tests; 8 | #[path = "insertion_tests/function_context_tests.rs"] 9 | mod function_context_tests; 10 | #[path = "insertion_tests/property_tests.rs"] 11 | mod property_tests; 12 | #[path = "insertion_tests/query_execution_tests.rs"] 13 | mod query_execution_tests; 14 | 15 | // Common test utilities 16 | pub(crate) use super::insertion::*; 17 | pub(crate) use crate::autocomplete::autocomplete_state::{Suggestion, SuggestionType}; 18 | pub(crate) use crate::query::ResultType; 19 | pub(crate) use crate::test_utils::test_helpers::{execute_query_and_wait, test_app}; 20 | pub(crate) use tui_textarea::TextArea; 21 | 22 | /// Helper to create a test environment for insertion 23 | pub(crate) fn setup_insertion_test( 24 | initial_query: &str, 25 | ) -> (TextArea<'static>, crate::query::QueryState) { 26 | let mut textarea = TextArea::default(); 27 | textarea.insert_str(initial_query); 28 | let query_state = crate::query::QueryState::new(r#"{"test": true}"#.to_string()); 29 | (textarea, query_state) 30 | } 31 | 32 | /// Helper to create a test suggestion from text (for backward compatibility with existing tests) 33 | pub(crate) fn test_suggestion(text: &str) -> Suggestion { 34 | Suggestion::new(text, SuggestionType::Field) 35 | } 36 | -------------------------------------------------------------------------------- /src/config/types.rs: -------------------------------------------------------------------------------- 1 | // Configuration type definitions 2 | 3 | use serde::Deserialize; 4 | 5 | use super::ai_types::AiConfig; 6 | 7 | /// Clipboard backend selection 8 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize, Default)] 9 | #[serde(rename_all = "lowercase")] 10 | pub enum ClipboardBackend { 11 | #[default] 12 | Auto, 13 | System, 14 | Osc52, 15 | } 16 | 17 | /// Clipboard configuration section 18 | #[derive(Debug, Clone, Deserialize)] 19 | pub struct ClipboardConfig { 20 | #[serde(default)] 21 | pub backend: ClipboardBackend, 22 | } 23 | 24 | impl Default for ClipboardConfig { 25 | fn default() -> Self { 26 | ClipboardConfig { 27 | backend: ClipboardBackend::Auto, 28 | } 29 | } 30 | } 31 | 32 | /// Tooltip configuration section 33 | #[derive(Debug, Clone, Deserialize)] 34 | pub struct TooltipConfig { 35 | #[serde(default = "default_auto_show")] 36 | pub auto_show: bool, 37 | } 38 | 39 | fn default_auto_show() -> bool { 40 | true 41 | } 42 | 43 | impl Default for TooltipConfig { 44 | fn default() -> Self { 45 | TooltipConfig { auto_show: true } 46 | } 47 | } 48 | 49 | /// Root configuration structure 50 | #[derive(Debug, Clone, Deserialize, Default)] 51 | pub struct Config { 52 | #[serde(default)] 53 | pub clipboard: ClipboardConfig, 54 | #[serde(default)] 55 | pub tooltip: TooltipConfig, 56 | #[serde(default)] 57 | pub ai: AiConfig, 58 | } 59 | 60 | #[cfg(test)] 61 | #[path = "types_tests.rs"] 62 | mod types_tests; 63 | -------------------------------------------------------------------------------- /src/query/debouncer.rs: -------------------------------------------------------------------------------- 1 | use std::time::{Duration, Instant}; 2 | 3 | const DEBOUNCE_MS: u64 = 150; 4 | #[derive(Debug)] 5 | pub struct Debouncer { 6 | /// Timestamp of the last input that triggered a debounce 7 | last_input_time: Option, 8 | /// Whether there's a pending query execution waiting for debounce to expire 9 | pending_execution: bool, 10 | } 11 | 12 | impl Default for Debouncer { 13 | fn default() -> Self { 14 | Self::new() 15 | } 16 | } 17 | 18 | impl Debouncer { 19 | pub fn new() -> Self { 20 | Self { 21 | last_input_time: None, 22 | pending_execution: false, 23 | } 24 | } 25 | 26 | pub fn schedule_execution(&mut self) { 27 | self.last_input_time = Some(Instant::now()); 28 | self.pending_execution = true; 29 | } 30 | 31 | pub fn should_execute(&self) -> bool { 32 | if !self.pending_execution { 33 | return false; 34 | } 35 | 36 | match self.last_input_time { 37 | Some(last_time) => { 38 | let elapsed = last_time.elapsed(); 39 | elapsed >= Duration::from_millis(DEBOUNCE_MS) 40 | } 41 | None => false, 42 | } 43 | } 44 | 45 | pub fn mark_executed(&mut self) { 46 | self.pending_execution = false; 47 | self.last_input_time = None; 48 | } 49 | 50 | pub fn has_pending(&self) -> bool { 51 | self.pending_execution 52 | } 53 | } 54 | 55 | #[cfg(test)] 56 | #[path = "debouncer_tests.rs"] 57 | mod debouncer_tests; 58 | -------------------------------------------------------------------------------- /src/history/history_events.rs: -------------------------------------------------------------------------------- 1 | use ratatui::crossterm::event::{KeyCode, KeyEvent}; 2 | use tui_textarea::Input; 3 | 4 | use crate::app::App; 5 | 6 | pub fn handle_history_popup_key(app: &mut App, key: KeyEvent) { 7 | match key.code { 8 | KeyCode::Up => { 9 | app.history.select_next(); 10 | } 11 | KeyCode::Down => { 12 | app.history.select_previous(); 13 | } 14 | 15 | KeyCode::Enter | KeyCode::Tab => { 16 | if let Some(entry) = app.history.selected_entry() { 17 | let entry = entry.to_string(); 18 | replace_query_with(app, &entry); 19 | } 20 | app.history.close(); 21 | } 22 | 23 | KeyCode::Esc => { 24 | app.history.close(); 25 | } 26 | 27 | _ => { 28 | let input = Input::from(key); 29 | if app.history.search_textarea_mut().input(input) { 30 | app.history.on_search_input_changed(); 31 | } 32 | } 33 | } 34 | } 35 | 36 | fn replace_query_with(app: &mut App, text: &str) { 37 | app.input.textarea.delete_line_by_head(); 38 | app.input.textarea.delete_line_by_end(); 39 | app.input.textarea.insert_str(text); 40 | 41 | let query = app.input.textarea.lines()[0].as_ref(); 42 | if let Some(query_state) = &mut app.query { 43 | query_state.execute(query); 44 | } 45 | 46 | app.results_scroll.reset(); 47 | app.error_overlay_visible = false; 48 | } 49 | 50 | #[cfg(test)] 51 | #[path = "history_events_tests.rs"] 52 | mod history_events_tests; 53 | -------------------------------------------------------------------------------- /src/app/app_events/global_tests.rs: -------------------------------------------------------------------------------- 1 | //! Tests for global key handlers 2 | //! 3 | //! This module contains all tests for the global key handler functionality. 4 | //! Tests are organized into separate submodules for better organization. 5 | 6 | // Re-export test modules 7 | #[path = "global_tests/ai_suggestion_tests.rs"] 8 | mod ai_suggestion_tests; 9 | #[path = "global_tests/autocomplete_tests.rs"] 10 | mod autocomplete_tests; 11 | #[path = "global_tests/error_overlay_tests.rs"] 12 | mod error_overlay_tests; 13 | #[path = "global_tests/global_key_tests.rs"] 14 | mod global_key_tests; 15 | #[path = "global_tests/help_popup_tests.rs"] 16 | mod help_popup_tests; 17 | 18 | // Re-export common test utilities for use in submodules 19 | pub(crate) use crate::app::app_state::{App, Focus, OutputMode}; 20 | pub(crate) use crate::editor::EditorMode; 21 | pub(crate) use crate::test_utils::test_helpers::{ 22 | TEST_JSON, app_with_query, key, key_with_mods, test_app, wait_for_query_completion, 23 | }; 24 | pub(crate) use ratatui::crossterm::event::{KeyCode, KeyModifiers}; 25 | 26 | // Helper to execute any pending debounced query and wait for completion 27 | // In tests, we need to manually trigger execution and poll for results 28 | pub(crate) fn flush_debounced_query(app: &mut App) { 29 | if app.debouncer.has_pending() { 30 | crate::editor::editor_events::execute_query(app); 31 | app.debouncer.mark_executed(); 32 | 33 | // Wait for async query to complete 34 | assert!( 35 | wait_for_query_completion(app, 2000), 36 | "Query did not complete within timeout" 37 | ); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/query/worker.rs: -------------------------------------------------------------------------------- 1 | //! Query Worker Module 2 | //! 3 | //! Handles jq query execution in a background thread to avoid blocking the UI. 4 | //! Receives requests via channel, executes jq with cancellation support, 5 | //! and sends responses back to the main thread. 6 | //! 7 | //! ## Architecture 8 | //! 9 | //! The worker follows the same pattern as the AI worker: 10 | //! - Single background thread with std::sync::mpsc channels 11 | //! - Blocking recv() in dedicated thread (not async) 12 | //! - Panic hook to prevent TUI corruption 13 | //! - Request/Response pattern with cancellation tokens 14 | //! 15 | //! ## Usage 16 | //! 17 | //! ```ignore 18 | //! use std::sync::mpsc::channel; 19 | //! use query::worker::{spawn_worker, QueryRequest, QueryResponse}; 20 | //! use tokio_util::sync::CancellationToken; 21 | //! 22 | //! // Create channels 23 | //! let (request_tx, request_rx) = channel(); 24 | //! let (response_tx, response_rx) = channel(); 25 | //! 26 | //! // Spawn worker 27 | //! spawn_worker(json_input, request_rx, response_tx); 28 | //! 29 | //! // Send request 30 | //! let cancel_token = CancellationToken::new(); 31 | //! request_tx.send(QueryRequest { 32 | //! query: ".foo".to_string(), 33 | //! request_id: 1, 34 | //! cancel_token, 35 | //! }).unwrap(); 36 | //! 37 | //! // Receive response 38 | //! match response_rx.recv().unwrap() { 39 | //! QueryResponse::Success { output, .. } => println!("{}", output), 40 | //! QueryResponse::Error { message, .. } => eprintln!("{}", message), 41 | //! QueryResponse::Cancelled { .. } => println!("Cancelled"), 42 | //! } 43 | //! ``` 44 | 45 | pub mod thread; 46 | pub mod types; 47 | 48 | // Re-exports for convenience 49 | pub use thread::spawn_worker; 50 | pub use types::{QueryRequest, QueryResponse}; 51 | -------------------------------------------------------------------------------- /src/search/search_events_tests/lifecycle_tests.rs: -------------------------------------------------------------------------------- 1 | use super::super::*; 2 | use crate::app::Focus; 3 | use crate::test_utils::test_helpers::{key, test_app}; 4 | 5 | #[test] 6 | fn test_open_search_sets_visible_and_focus() { 7 | let mut app = test_app(r#"{"name": "test"}"#); 8 | app.focus = Focus::InputField; 9 | 10 | open_search(&mut app); 11 | 12 | assert!(app.search.is_visible()); 13 | assert_eq!(app.focus, Focus::ResultsPane); 14 | } 15 | 16 | #[test] 17 | fn test_close_search_clears_state() { 18 | let mut app = test_app(r#"{"name": "test"}"#); 19 | open_search(&mut app); 20 | app.search.search_textarea_mut().insert_str("test"); 21 | 22 | close_search(&mut app); 23 | 24 | assert!(!app.search.is_visible()); 25 | assert!(app.search.query().is_empty()); 26 | } 27 | 28 | #[test] 29 | fn test_handle_search_key_returns_false_when_not_visible() { 30 | let mut app = test_app(r#"{"name": "test"}"#); 31 | assert!(!app.search.is_visible()); 32 | 33 | let handled = handle_search_key(&mut app, key(KeyCode::Char('n'))); 34 | 35 | assert!(!handled); 36 | } 37 | 38 | #[test] 39 | fn test_escape_closes_search() { 40 | let mut app = test_app(r#"{"name": "test"}"#); 41 | open_search(&mut app); 42 | 43 | let handled = handle_search_key(&mut app, key(KeyCode::Esc)); 44 | 45 | assert!(handled); 46 | assert!(!app.search.is_visible()); 47 | } 48 | 49 | #[test] 50 | fn test_text_input_updates_query() { 51 | let mut app = test_app(r#"{"name": "test"}"#); 52 | open_search(&mut app); 53 | 54 | handle_search_key(&mut app, key(KeyCode::Char('t'))); 55 | handle_search_key(&mut app, key(KeyCode::Char('e'))); 56 | handle_search_key(&mut app, key(KeyCode::Char('s'))); 57 | handle_search_key(&mut app, key(KeyCode::Char('t'))); 58 | 59 | assert_eq!(app.search.query(), "test"); 60 | } 61 | -------------------------------------------------------------------------------- /src/history/matcher.rs: -------------------------------------------------------------------------------- 1 | use std::fmt; 2 | 3 | use fuzzy_matcher::FuzzyMatcher; 4 | use fuzzy_matcher::skim::SkimMatcherV2; 5 | 6 | pub struct HistoryMatcher { 7 | matcher: SkimMatcherV2, 8 | } 9 | 10 | impl fmt::Debug for HistoryMatcher { 11 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 12 | f.debug_struct("HistoryMatcher").finish_non_exhaustive() 13 | } 14 | } 15 | 16 | impl Default for HistoryMatcher { 17 | fn default() -> Self { 18 | Self::new() 19 | } 20 | } 21 | 22 | impl HistoryMatcher { 23 | pub fn new() -> Self { 24 | Self { 25 | matcher: SkimMatcherV2::default(), 26 | } 27 | } 28 | 29 | pub fn filter(&self, query: &str, entries: &[String]) -> Vec { 30 | if query.is_empty() { 31 | return (0..entries.len()).collect(); 32 | } 33 | 34 | // Split query into terms (space-separated, like fzf) 35 | let terms: Vec<&str> = query.split_whitespace().collect(); 36 | if terms.is_empty() { 37 | return (0..entries.len()).collect(); 38 | } 39 | 40 | let mut scored: Vec<(usize, i64)> = entries 41 | .iter() 42 | .enumerate() 43 | .filter_map(|(idx, entry)| { 44 | // All terms must match (AND logic) 45 | let mut total_score: i64 = 0; 46 | for term in &terms { 47 | match self.matcher.fuzzy_match(entry, term) { 48 | Some(score) => total_score += score, 49 | None => return None, // Term didn't match, exclude entry 50 | } 51 | } 52 | Some((idx, total_score)) 53 | }) 54 | .collect(); 55 | 56 | scored.sort_by(|a, b| b.1.cmp(&a.1)); 57 | 58 | scored.into_iter().map(|(idx, _)| idx).collect() 59 | } 60 | } 61 | 62 | #[cfg(test)] 63 | #[path = "matcher_tests.rs"] 64 | mod matcher_tests; 65 | -------------------------------------------------------------------------------- /src/autocomplete/scan_state_tests.rs: -------------------------------------------------------------------------------- 1 | //! Tests for scan state tracking 2 | 3 | use super::*; 4 | 5 | #[test] 6 | fn test_default_is_normal() { 7 | assert_eq!(ScanState::default(), ScanState::Normal); 8 | } 9 | 10 | #[test] 11 | fn test_enter_string() { 12 | let state = ScanState::Normal.advance('"'); 13 | assert_eq!(state, ScanState::InString); 14 | assert!(state.is_in_string()); 15 | } 16 | 17 | #[test] 18 | fn test_exit_string() { 19 | let state = ScanState::InString.advance('"'); 20 | assert_eq!(state, ScanState::Normal); 21 | assert!(!state.is_in_string()); 22 | } 23 | 24 | #[test] 25 | fn test_escape_in_string() { 26 | let state = ScanState::InString.advance('\\'); 27 | assert_eq!(state, ScanState::InStringEscape); 28 | assert!(state.is_in_string()); 29 | } 30 | 31 | #[test] 32 | fn test_escaped_quote() { 33 | let state = ScanState::InStringEscape.advance('"'); 34 | assert_eq!(state, ScanState::InString); 35 | assert!(state.is_in_string()); 36 | } 37 | 38 | #[test] 39 | fn test_escaped_backslash() { 40 | let state = ScanState::InStringEscape.advance('\\'); 41 | assert_eq!(state, ScanState::InString); 42 | } 43 | 44 | #[test] 45 | fn test_normal_chars_stay_normal() { 46 | let state = ScanState::Normal.advance('a'); 47 | assert_eq!(state, ScanState::Normal); 48 | } 49 | 50 | #[test] 51 | fn test_string_chars_stay_in_string() { 52 | let state = ScanState::InString.advance('a'); 53 | assert_eq!(state, ScanState::InString); 54 | } 55 | 56 | #[test] 57 | fn test_full_string_scan() { 58 | let mut state = ScanState::Normal; 59 | for ch in "\"hello\"".chars() { 60 | state = state.advance(ch); 61 | } 62 | assert_eq!(state, ScanState::Normal); 63 | } 64 | 65 | #[test] 66 | fn test_escaped_quote_in_string() { 67 | let mut state = ScanState::Normal; 68 | for ch in "\"say \\\"hi\\\"\"".chars() { 69 | state = state.advance(ch); 70 | } 71 | assert_eq!(state, ScanState::Normal); 72 | } 73 | -------------------------------------------------------------------------------- /src/notification/notification_render_tests.rs: -------------------------------------------------------------------------------- 1 | //! Tests for notification_render 2 | 3 | use super::*; 4 | use insta::assert_snapshot; 5 | use ratatui::Terminal; 6 | use ratatui::backend::TestBackend; 7 | 8 | fn create_test_terminal(width: u16, height: u16) -> Terminal { 9 | let backend = TestBackend::new(width, height); 10 | Terminal::new(backend).unwrap() 11 | } 12 | 13 | fn render_notification_to_string( 14 | notification: &mut NotificationState, 15 | width: u16, 16 | height: u16, 17 | ) -> String { 18 | let mut terminal = create_test_terminal(width, height); 19 | terminal 20 | .draw(|f| render_notification(f, notification)) 21 | .unwrap(); 22 | terminal.backend().to_string() 23 | } 24 | 25 | #[test] 26 | fn snapshot_notification_overlay() { 27 | let mut notification = NotificationState::new(); 28 | notification.show("Copied query!"); 29 | 30 | let output = render_notification_to_string(&mut notification, 80, 24); 31 | assert_snapshot!(output); 32 | } 33 | 34 | #[test] 35 | fn snapshot_notification_top_right_position() { 36 | let mut notification = NotificationState::new(); 37 | notification.show("Copied result!"); 38 | 39 | // Use a wider terminal to verify top-right positioning 40 | let output = render_notification_to_string(&mut notification, 100, 30); 41 | assert_snapshot!(output); 42 | } 43 | 44 | #[test] 45 | fn snapshot_notification_no_active() { 46 | let mut notification = NotificationState::new(); 47 | // No notification shown 48 | 49 | let output = render_notification_to_string(&mut notification, 80, 24); 50 | assert_snapshot!(output); 51 | } 52 | 53 | #[test] 54 | fn snapshot_notification_styled() { 55 | let mut notification = NotificationState::new(); 56 | // Use warning duration to test different notification types 57 | notification.show_warning("Custom warning!"); 58 | 59 | let output = render_notification_to_string(&mut notification, 80, 24); 60 | assert_snapshot!(output); 61 | } 62 | -------------------------------------------------------------------------------- /src/clipboard/osc52_tests.rs: -------------------------------------------------------------------------------- 1 | //! Tests for clipboard/osc52 2 | 3 | use super::*; 4 | use proptest::prelude::*; 5 | 6 | // Feature: clipboard, Property 1: OSC 52 encoding round-trip 7 | // *For any* input text string, encoding it with OSC 52 format and then 8 | // decoding the base64 portion should produce the original text. 9 | proptest! { 10 | #![proptest_config(ProptestConfig::with_cases(100))] 11 | 12 | #[test] 13 | fn prop_osc52_encoding_roundtrip(text in ".*") { 14 | let encoded = encode_osc52(&text); 15 | 16 | // Verify the format: \x1b]52;c;{base64}\x07 17 | assert!(encoded.starts_with("\x1b]52;c;"), "Should start with OSC 52 prefix"); 18 | assert!(encoded.ends_with("\x07"), "Should end with BEL terminator"); 19 | 20 | // Extract the base64 portion 21 | let prefix = "\x1b]52;c;"; 22 | let suffix = "\x07"; 23 | let base64_part = &encoded[prefix.len()..encoded.len() - suffix.len()]; 24 | 25 | // Decode and verify round-trip 26 | let decoded_bytes = STANDARD.decode(base64_part) 27 | .expect("Base64 decoding should succeed"); 28 | let decoded_text = String::from_utf8(decoded_bytes) 29 | .expect("Decoded bytes should be valid UTF-8"); 30 | 31 | assert_eq!(decoded_text, text, "Round-trip should preserve original text"); 32 | } 33 | } 34 | 35 | #[test] 36 | fn test_encode_osc52_simple() { 37 | let result = encode_osc52("hello"); 38 | assert_eq!(result, "\x1b]52;c;aGVsbG8=\x07"); 39 | } 40 | 41 | #[test] 42 | fn test_encode_osc52_empty() { 43 | let result = encode_osc52(""); 44 | assert_eq!(result, "\x1b]52;c;\x07"); 45 | } 46 | 47 | #[test] 48 | fn test_encode_osc52_unicode() { 49 | let result = encode_osc52("日本語"); 50 | assert!(result.starts_with("\x1b]52;c;")); 51 | assert!(result.ends_with("\x07")); 52 | 53 | let base64_part = &result[7..result.len() - 1]; 54 | let decoded = STANDARD.decode(base64_part).unwrap(); 55 | assert_eq!(String::from_utf8(decoded).unwrap(), "日本語"); 56 | } 57 | -------------------------------------------------------------------------------- /src/notification/notification_render.rs: -------------------------------------------------------------------------------- 1 | use ratatui::{ 2 | Frame, 3 | layout::Rect, 4 | style::Style, 5 | text::{Line, Span}, 6 | widgets::{Block, Borders, Paragraph}, 7 | }; 8 | 9 | use super::notification_state::NotificationState; 10 | use crate::widgets::popup; 11 | 12 | pub fn render_notification(frame: &mut Frame, notification: &mut NotificationState) { 13 | notification.clear_if_expired(); 14 | 15 | let notif = match notification.current() { 16 | Some(n) => n, 17 | None => return, 18 | }; 19 | 20 | let message = ¬if.message; 21 | let style = ¬if.style; 22 | 23 | let content_width = message.len() as u16; 24 | let notification_width = content_width + 4; 25 | let notification_height = 3; 26 | 27 | let frame_area = frame.area(); 28 | let margin = 2; 29 | let notification_x = frame_area.width.saturating_sub(notification_width + margin); 30 | let notification_y = margin; 31 | 32 | let notification_area = Rect { 33 | x: notification_x, 34 | y: notification_y, 35 | width: notification_width.min(frame_area.width.saturating_sub(margin * 2)), 36 | height: notification_height.min(frame_area.height.saturating_sub(margin * 2)), 37 | }; 38 | 39 | // Don't render if area is too small 40 | if notification_area.width < 5 || notification_area.height < 3 { 41 | return; 42 | } 43 | 44 | popup::clear_area(frame, notification_area); 45 | 46 | let block = Block::default() 47 | .borders(Borders::ALL) 48 | .border_style(Style::default().fg(style.border).bg(style.bg)) 49 | .style(Style::default().bg(style.bg)); 50 | 51 | let text = Line::from(Span::styled( 52 | format!(" {} ", message), 53 | Style::default().fg(style.fg).bg(style.bg), 54 | )); 55 | 56 | let paragraph = Paragraph::new(text).block(block); 57 | 58 | frame.render_widget(paragraph, notification_area); 59 | } 60 | 61 | #[cfg(test)] 62 | #[path = "notification_render_tests.rs"] 63 | mod notification_render_tests; 64 | -------------------------------------------------------------------------------- /src/app/snapshots/jiq__app__render__snapshot_tests__snapshot_help_popup.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/app/render.rs 3 | expression: output 4 | --- 5 | "┌ Obj┌ Keyboard Shortcuts ────────────────────────────────────────────────┐────┐" 6 | "│{ │ │ │" 7 | "│ "t│ ── GLOBAL ── │ │" 8 | "│} │ F1 or ? Toggle this help │ │" 9 | "│ │ Ctrl+C Quit without output │ │" 10 | "│ │ Enter Output filtered JSON and exit │ │" 11 | "│ │ Ctrl+Q Output query string only and exit │ │" 12 | "│ │ Shift+Tab Switch focus (Input / Results) │ │" 13 | "│ │ q Quit (in Normal mode or Results pane) │ │" 14 | "│ │ │ │" 15 | "│ │ ── INPUT: INSERT MODE ── │ │" 16 | "│ │ Esc Switch to Normal mode │ │" 17 | "│ │ ↑/Ctrl+R Open history popup │ │" 18 | "│ │ Ctrl+P/N Previous/Next query in history │ │" 19 | "│ │ │ │" 20 | "│ │ ── INPUT: NORMAL MODE ── │ │" 21 | "│ │ i/a/I/A Enter Insert mode │ │" 22 | "│ │ h/l Move cursor left/right │ │" 23 | "│ │ 0/^/$ Jump to start/end of line │ │" 24 | "└────│ w/b/e Word navigation │────┘" 25 | "┌ Que│ x/X Delete character │────┐" 26 | "│ │ dd/D Delete line/to end │ │" 27 | "└────│ u Undo │────┘" 28 | " F1: └────────────────────────────────────────────────────────────────────┘story" 29 | -------------------------------------------------------------------------------- /src/app/snapshots/jiq__app__render__snapshot_tests__snapshot_error_overlay.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/app/render.rs 3 | expression: output 4 | --- 5 | "┌ ⚠ Syntax Error (Object - last successful query result) ──────────────────────┐" 6 | "│{ │" 7 | "│ "test": true │" 8 | "│} │" 9 | "│ │" 10 | "│ │" 11 | "│ │" 12 | "│ │" 13 | "│ │" 14 | "│ │" 15 | "│ │" 16 | "│ │" 17 | "│ │" 18 | "│ │" 19 | "│ │" 20 | "│ │" 21 | "│ ┌ Syntax Error (Ctrl+E to close) ──────────────────────────────────────────┐ │" 22 | "│ │jq: compile error: syntax error at line 1 │ │" 23 | "│ └──────────────────────────────────────────────────────────────────────────┘ │" 24 | "└──────────────────────────────────────────────────────────────────────────────┘" 25 | "┌ Query [INSERT] ⚠ Syntax Error (Ctrl+E to view)───────────────────────────────┐" 26 | "│ │" 27 | "└──────────────────────────────────────────────────────────────────────────────┘" 28 | " F1: Help | Shift+Tab: Switch Pane | Ctrl+P/N: Cycle History | ↑/Ctrl+R: History" 29 | -------------------------------------------------------------------------------- /src/app/snapshots/jiq__app__render__snapshot_tests__snapshot_history_popup.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/app/render.rs 3 | expression: output 4 | --- 5 | "┌ Object ──────────────────────────────────────────────────────────────────────┐" 6 | "│{ │" 7 | "│ "test": true │" 8 | "│} │" 9 | "│ │" 10 | "│ │" 11 | "│ │" 12 | "│ │" 13 | "│ │" 14 | "│ │" 15 | "│ │" 16 | "│ │" 17 | "┌ History (3/3) ───────────────────────────────────────────────────────────────┐" 18 | "│ .name │" 19 | "│ .age │" 20 | "│ ► .users[] │" 21 | "└──────────────────────────────────────────────────────────────────────────────┘" 22 | "┌ Search ──────────────────────────────────────────────────────────────────────┐" 23 | "│ │" 24 | "└──────────────────────────────────────────────────────────────────────────────┘" 25 | "┌ Query [INSERT] ──────────────────────────────────────────────────────────────┐" 26 | "│ │" 27 | "└──────────────────────────────────────────────────────────────────────────────┘" 28 | " F1: Help | Shift+Tab: Switch Pane | Ctrl+P/N: Cycle History | ↑/Ctrl+R: History" 29 | -------------------------------------------------------------------------------- /src/app/snapshots/jiq__app__render__snapshot_tests__snapshot_ui_input_focused.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/app/render.rs 3 | expression: output 4 | --- 5 | "┌ Object ──────────────────────────────────────────────────────────────────────┐" 6 | "│{ │" 7 | "│ "test": true │" 8 | "│} │" 9 | "│ │" 10 | "│ │" 11 | "│ │" 12 | "│ │" 13 | "│ │" 14 | "│ │" 15 | "│ │" 16 | "│ │" 17 | "│ │" 18 | "│ │" 19 | "│ │" 20 | "│ │" 21 | "│ │" 22 | "│ │" 23 | "│ │" 24 | "└──────────────────────────────────────────────────────────────────────────────┘" 25 | "┌ Query [INSERT] ──────────────────────────────────────────────────────────────┐" 26 | "│ │" 27 | "└──────────────────────────────────────────────────────────────────────────────┘" 28 | " F1: Help | Shift+Tab: Switch Pane | Ctrl+P/N: Cycle History | ↑/Ctrl+R: History" 29 | -------------------------------------------------------------------------------- /src/app/snapshots/jiq__app__render__snapshot_tests__snapshot_ui_insert_mode.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/app/render.rs 3 | expression: output 4 | --- 5 | "┌ Object ──────────────────────────────────────────────────────────────────────┐" 6 | "│{ │" 7 | "│ "test": true │" 8 | "│} │" 9 | "│ │" 10 | "│ │" 11 | "│ │" 12 | "│ │" 13 | "│ │" 14 | "│ │" 15 | "│ │" 16 | "│ │" 17 | "│ │" 18 | "│ │" 19 | "│ │" 20 | "│ │" 21 | "│ │" 22 | "│ │" 23 | "│ │" 24 | "└──────────────────────────────────────────────────────────────────────────────┘" 25 | "┌ Query [INSERT] ──────────────────────────────────────────────────────────────┐" 26 | "│ │" 27 | "└──────────────────────────────────────────────────────────────────────────────┘" 28 | " F1: Help | Shift+Tab: Switch Pane | Ctrl+P/N: Cycle History | ↑/Ctrl+R: History" 29 | -------------------------------------------------------------------------------- /src/app/snapshots/jiq__app__render__snapshot_tests__snapshot_ui_normal_mode.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/app/render.rs 3 | expression: output 4 | --- 5 | "┌ Object ──────────────────────────────────────────────────────────────────────┐" 6 | "│{ │" 7 | "│ "test": true │" 8 | "│} │" 9 | "│ │" 10 | "│ │" 11 | "│ │" 12 | "│ │" 13 | "│ │" 14 | "│ │" 15 | "│ │" 16 | "│ │" 17 | "│ │" 18 | "│ │" 19 | "│ │" 20 | "│ │" 21 | "│ │" 22 | "│ │" 23 | "│ │" 24 | "└──────────────────────────────────────────────────────────────────────────────┘" 25 | "┌ Query [NORMAL] (press 'i' to edit) ──────────────────────────────────────────┐" 26 | "│ │" 27 | "└──────────────────────────────────────────────────────────────────────────────┘" 28 | " F1/?: Help | Shift+Tab: Switch Pane | Enter: Output Result | Ctrl+Q: Output Que" 29 | -------------------------------------------------------------------------------- /src/app/snapshots/jiq__app__render__snapshot_tests__snapshot_ui_operator_mode.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/app/render.rs 3 | expression: output 4 | --- 5 | "┌ Object ──────────────────────────────────────────────────────────────────────┐" 6 | "│{ │" 7 | "│ "test": true │" 8 | "│} │" 9 | "│ │" 10 | "│ │" 11 | "│ │" 12 | "│ │" 13 | "│ │" 14 | "│ │" 15 | "│ │" 16 | "│ │" 17 | "│ │" 18 | "│ │" 19 | "│ │" 20 | "│ │" 21 | "│ │" 22 | "│ │" 23 | "│ │" 24 | "└──────────────────────────────────────────────────────────────────────────────┘" 25 | "┌ Query [OPERATOR(d)] ─────────────────────────────────────────────────────────┐" 26 | "│ │" 27 | "└──────────────────────────────────────────────────────────────────────────────┘" 28 | " F1/?: Help | Shift+Tab: Switch Pane | Enter: Output Result | Ctrl+Q: Output Que" 29 | -------------------------------------------------------------------------------- /src/app/snapshots/jiq__app__render__snapshot_tests__snapshot_ui_with_error.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/app/render.rs 3 | expression: output 4 | --- 5 | "┌ ⚠ Syntax Error (Object - last successful query result) ──────────────────────┐" 6 | "│{ │" 7 | "│ "test": true │" 8 | "│} │" 9 | "│ │" 10 | "│ │" 11 | "│ │" 12 | "│ │" 13 | "│ │" 14 | "│ │" 15 | "│ │" 16 | "│ │" 17 | "│ │" 18 | "│ │" 19 | "│ │" 20 | "│ │" 21 | "│ │" 22 | "│ │" 23 | "│ │" 24 | "└──────────────────────────────────────────────────────────────────────────────┘" 25 | "┌ Query [INSERT] ⚠ Syntax Error (Ctrl+E to view)───────────────────────────────┐" 26 | "│.invalid[ │" 27 | "└──────────────────────────────────────────────────────────────────────────────┘" 28 | " F1: Help | Shift+Tab: Switch Pane | ↑/Ctrl+R: History | Enter: Output Result | " 29 | -------------------------------------------------------------------------------- /src/app/snapshots/jiq__app__render__snapshot_tests__snapshot_ui_with_query.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/app/render.rs 3 | expression: output 4 | --- 5 | "┌ String ──────────────────────────────────────────────────────────────────────┐" 6 | "│"Alice" │" 7 | "│ │" 8 | "│ │" 9 | "│ │" 10 | "│ │" 11 | "│ │" 12 | "│ │" 13 | "│ │" 14 | "│ │" 15 | "│ │" 16 | "│ │" 17 | "│ │" 18 | "│ │" 19 | "│ │" 20 | "│ │" 21 | "│ │" 22 | "│ │" 23 | "│ │" 24 | "└──────────────────────────────────────────────────────────────────────────────┘" 25 | "┌ Query [INSERT] ──────────────────────────────────────────────────────────────┐" 26 | "│.name │" 27 | "└──────────────────────────────────────────────────────────────────────────────┘" 28 | " F1: Help | Shift+Tab: Switch Pane | ↑/Ctrl+R: History | Enter: Output Result | " 29 | -------------------------------------------------------------------------------- /src/app/snapshots/jiq__app__app_render__snapshot_tests__snapshot_error_overlay.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/app/app_render.rs 3 | expression: output 4 | --- 5 | "┌ ⚠ Syntax Error (Object - last successful query result) ──────────────────────┐" 6 | "│{ │" 7 | "│ "test": true │" 8 | "│} │" 9 | "│ │" 10 | "│ │" 11 | "│ │" 12 | "│ │" 13 | "│ │" 14 | "│ │" 15 | "│ │" 16 | "│ │" 17 | "│ │" 18 | "│ │" 19 | "│ │" 20 | "│ │" 21 | "│ ┌ Syntax Error (Ctrl+E to close) ──────────────────────────────────────────┐ │" 22 | "│ │jq: compile error: syntax error at line 1 │ │" 23 | "│ └──────────────────────────────────────────────────────────────────────────┘ │" 24 | "└──────────────────────────────────────────────────────────────────────────────┘" 25 | "┌ Query [INSERT] ⚠ Syntax Error (Ctrl+E to view) Press Ctrl+A for AI Assistant ┐" 26 | "│ │" 27 | "└──────────────────────────────────────────────────────────────────────────────┘" 28 | " F1: Help | Shift+Tab: Switch Pane | Ctrl+P/N: Cycle History | ↑/Ctrl+R: History" 29 | -------------------------------------------------------------------------------- /src/app/snapshots/jiq__app__app_render__snapshot_tests__snapshot_help_popup.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/app/app_render.rs 3 | expression: output 4 | --- 5 | "┌ Obj┌ Keyboard Shortcuts ────────────────────────────────────────────────┐────┐" 6 | "│{ │ │ │" 7 | "│ "t│ ── GLOBAL ── │ │" 8 | "│} │ F1 or ? Toggle this help │ │" 9 | "│ │ Ctrl+A Toggle AI assistant │ │" 10 | "│ │ Ctrl+C Quit without output │ │" 11 | "│ │ Enter Output filtered JSON and exit │ │" 12 | "│ │ Ctrl+Q Output query string only and exit │ │" 13 | "│ │ Shift+Tab Switch focus (Input / Results) │ │" 14 | "│ │ q Quit (in Normal mode or Results pane) │ │" 15 | "│ │ │ │" 16 | "│ │ ── INPUT: INSERT MODE ── │ │" 17 | "│ │ Esc Switch to Normal mode │ │" 18 | "│ │ ↑/Ctrl+R Open history popup │ │" 19 | "│ │ Ctrl+P/N Previous/Next query in history │ │" 20 | "│ │ │ │" 21 | "│ │ ── INPUT: NORMAL MODE ── │ │" 22 | "│ │ i/a/I/A Enter Insert mode │ │" 23 | "│ │ h/l Move cursor left/right │ │" 24 | "└────│ 0/^/$ Jump to start/end of line │────┘" 25 | "┌ Que│ w/b/e Word navigation │ant ┐" 26 | "│ │ x/X Delete character │ │" 27 | "└────│ dd/D Delete line/to end │────┘" 28 | " F1: └────────────────────────────────────────────────────────────────────┘story" 29 | -------------------------------------------------------------------------------- /src/app/snapshots/jiq__app__app_render__snapshot_tests__snapshot_history_popup.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/app/app_render.rs 3 | expression: output 4 | --- 5 | "┌ Object ──────────────────────────────────────────────────────────────────────┐" 6 | "│{ │" 7 | "│ "test": true │" 8 | "│} │" 9 | "│ │" 10 | "│ │" 11 | "│ │" 12 | "│ │" 13 | "│ │" 14 | "│ │" 15 | "│ │" 16 | "│ │" 17 | "┌ History (3/3) ───────────────────────────────────────────────────────────────┐" 18 | "│ .name │" 19 | "│ .age │" 20 | "│ ► .users[] │" 21 | "└──────────────────────────────────────────────────────────────────────────────┘" 22 | "┌ Search ──────────────────────────────────────────────────────────────────────┐" 23 | "│ │" 24 | "└──────────────────────────────────────────────────────────────────────────────┘" 25 | "┌ Query [INSERT] ─────────────────────────────── Press Ctrl+A for AI Assistant ┐" 26 | "│ │" 27 | "└──────────────────────────────────────────────────────────────────────────────┘" 28 | " F1: Help | Shift+Tab: Switch Pane | Ctrl+P/N: Cycle History | ↑/Ctrl+R: History" 29 | -------------------------------------------------------------------------------- /src/app/snapshots/jiq__app__app_render__snapshot_tests__snapshot_ui_with_error.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/app/app_render.rs 3 | expression: output 4 | --- 5 | "┌ ⚠ Syntax Error (Object - last successful query result) ──────────────────────┐" 6 | "│{ │" 7 | "│ "test": true │" 8 | "│} │" 9 | "│ │" 10 | "│ │" 11 | "│ │" 12 | "│ │" 13 | "│ │" 14 | "│ │" 15 | "│ │" 16 | "│ │" 17 | "│ │" 18 | "│ │" 19 | "│ │" 20 | "│ │" 21 | "│ │" 22 | "│ │" 23 | "│ │" 24 | "└──────────────────────────────────────────────────────────────────────────────┘" 25 | "┌ Query [INSERT] ⚠ Syntax Error (Ctrl+E to view) Press Ctrl+A for AI Assistant ┐" 26 | "│.invalid[ │" 27 | "└──────────────────────────────────────────────────────────────────────────────┘" 28 | " F1: Help | Shift+Tab: Switch Pane | ↑/Ctrl+R: History | Enter: Output Result | " 29 | -------------------------------------------------------------------------------- /src/app/snapshots/jiq__app__app_render__snapshot_tests__snapshot_ui_with_query.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/app/app_render.rs 3 | expression: output 4 | --- 5 | "┌ String ──────────────────────────────────────────────────────────────────────┐" 6 | "│"Alice" │" 7 | "│ │" 8 | "│ │" 9 | "│ │" 10 | "│ │" 11 | "│ │" 12 | "│ │" 13 | "│ │" 14 | "│ │" 15 | "│ │" 16 | "│ │" 17 | "│ │" 18 | "│ │" 19 | "│ │" 20 | "│ │" 21 | "│ │" 22 | "│ │" 23 | "│ │" 24 | "└──────────────────────────────────────────────────────────────────────────────┘" 25 | "┌ Query [INSERT] ─────────────────────────────── Press Ctrl+A for AI Assistant ┐" 26 | "│.name │" 27 | "└──────────────────────────────────────────────────────────────────────────────┘" 28 | " F1: Help | Shift+Tab: Switch Pane | ↑/Ctrl+R: History | Enter: Output Result | " 29 | -------------------------------------------------------------------------------- /src/app/snapshots/jiq__app__render__snapshot_tests__snapshot_search_bar_no_matches.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/app/render.rs 3 | expression: output 4 | --- 5 | "┌ Object ──────────────────────────────────────────────────────────────────────┐" 6 | "│{ │" 7 | "│ "name": "Alice", │" 8 | "│ "age": 30 │" 9 | "│} │" 10 | "│ │" 11 | "│ │" 12 | "│ │" 13 | "│ │" 14 | "│ │" 15 | "│ │" 16 | "│ │" 17 | "│ │" 18 | "│ │" 19 | "│ │" 20 | "│ │" 21 | "└──────────────────────────────────────────────────────────────────────────────┘" 22 | "┌ Search: ────────────────────────────────────────────────────────────── (0/0) ┐" 23 | "│xyz │" 24 | "└──────────────────────────────────────────────────────────────────────────────┘" 25 | "┌ Query [INSERT] ──────────────────────────────────────────────────────────────┐" 26 | "│ │" 27 | "└──────────────────────────────────────────────────────────────────────────────┘" 28 | " F1/?: Help | Shift+Tab: Switch Pane | Enter: Output Result | Ctrl+Q: Output Que" 29 | -------------------------------------------------------------------------------- /src/app/snapshots/jiq__app__render__snapshot_tests__snapshot_search_bar_visible.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/app/render.rs 3 | expression: output 4 | --- 5 | "┌ Object ──────────────────────────────────────────────────────────────────────┐" 6 | "│{ │" 7 | "│ "name": "Alice", │" 8 | "│ "email": "alice@example.com", │" 9 | "│ "role": "admin" │" 10 | "│} │" 11 | "│ │" 12 | "│ │" 13 | "│ │" 14 | "│ │" 15 | "│ │" 16 | "│ │" 17 | "│ │" 18 | "│ │" 19 | "│ │" 20 | "│ │" 21 | "└──────────────────────────────────────────────────────────────────────────────┘" 22 | "┌ Search: ────────────────────────────────────────────────────────────── (1/2) ┐" 23 | "│alice │" 24 | "└──────────────────────────────────────────────────────────────────────────────┘" 25 | "┌ Query [INSERT] ──────────────────────────────────────────────────────────────┐" 26 | "│ │" 27 | "└──────────────────────────────────────────────────────────────────────────────┘" 28 | " F1/?: Help | Shift+Tab: Switch Pane | Enter: Output Result | Ctrl+Q: Output Que" 29 | -------------------------------------------------------------------------------- /src/app/snapshots/jiq__app__render__snapshot_tests__snapshot_ui_results_focused.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/app/render.rs 3 | expression: output 4 | --- 5 | "┌ Object ──────────────────────────────────────────────────────────────────────┐" 6 | "│{ │" 7 | "│ "test": true │" 8 | "│} │" 9 | "│ │" 10 | "│ │" 11 | "│ │" 12 | "│ │" 13 | "│ │" 14 | "│ │" 15 | "│ │" 16 | "│ │" 17 | "│ │" 18 | "│ │" 19 | "│ │" 20 | "│ │" 21 | "│ │" 22 | "│ │" 23 | "│ │" 24 | "└──────────────────────────────────────────────────────────────────────────────┘" 25 | "┌ Query [INSERT] ──────────────────────────────────────────────────────────────┐" 26 | "│ │" 27 | "└──────────────────────────────────────────────────────────────────────────────┘" 28 | " F1/?: Help | Shift+Tab: Switch Pane | Enter: Output Result | Ctrl+Q: Output Que" 29 | -------------------------------------------------------------------------------- /src/app/snapshots/jiq__app__render__snapshot_tests__snapshot_ui_with_array_data.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/app/render.rs 3 | expression: output 4 | --- 5 | "┌ Stream [3] ──────────────────────────────────────────────────────────────────┐" 6 | "│"Alice" │" 7 | "│"Bob" │" 8 | "│"Charlie" │" 9 | "│ │" 10 | "│ │" 11 | "│ │" 12 | "│ │" 13 | "│ │" 14 | "│ │" 15 | "│ │" 16 | "│ │" 17 | "│ │" 18 | "│ │" 19 | "│ │" 20 | "│ │" 21 | "│ │" 22 | "│ │" 23 | "│ │" 24 | "└──────────────────────────────────────────────────────────────────────────────┘" 25 | "┌ Query [INSERT] ──────────────────────────────────────────────────────────────┐" 26 | "│.[].name │" 27 | "└──────────────────────────────────────────────────────────────────────────────┘" 28 | " F1: Help | Shift+Tab: Switch Pane | ↑/Ctrl+R: History | Enter: Output Result | " 29 | -------------------------------------------------------------------------------- /src/app/snapshots/jiq__app__app_render__snapshot_tests__snapshot_search_bar_visible.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/app/app_render.rs 3 | expression: output 4 | --- 5 | "┌ Object ──────────────────────────────────────────────────────────────────────┐" 6 | "│{ │" 7 | "│ "name": "Alice", │" 8 | "│ "email": "alice@example.com", │" 9 | "│ "role": "admin" │" 10 | "│} │" 11 | "│ │" 12 | "│ │" 13 | "│ │" 14 | "│ │" 15 | "│ │" 16 | "│ │" 17 | "│ │" 18 | "│ │" 19 | "│ │" 20 | "│ │" 21 | "└──────────────────────────────────────────────────────────────────────────────┘" 22 | "┌ Search: ────────────────────────────────────────────────────────────── (1/2) ┐" 23 | "│alice │" 24 | "└──────────────────────────────────────────────────────────────────────────────┘" 25 | "┌ Query [INSERT] ─────────────────────────────── Press Ctrl+A for AI Assistant ┐" 26 | "│ │" 27 | "└──────────────────────────────────────────────────────────────────────────────┘" 28 | " F1/?: Help | Shift+Tab: Switch Pane | Enter: Output Result | Ctrl+Q: Output Que" 29 | -------------------------------------------------------------------------------- /src/app/snapshots/jiq__app__app_render__snapshot_tests__snapshot_ui_input_focused.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/app/app_render.rs 3 | expression: output 4 | --- 5 | "┌ Object ──────────────────────────────────────────────────────────────────────┐" 6 | "│{ │" 7 | "│ "test": true │" 8 | "│} │" 9 | "│ │" 10 | "│ │" 11 | "│ │" 12 | "│ │" 13 | "│ │" 14 | "│ │" 15 | "│ │" 16 | "│ │" 17 | "│ │" 18 | "│ │" 19 | "│ │" 20 | "│ │" 21 | "│ │" 22 | "│ │" 23 | "│ │" 24 | "└──────────────────────────────────────────────────────────────────────────────┘" 25 | "┌ Query [INSERT] ─────────────────────────────── Press Ctrl+A for AI Assistant ┐" 26 | "│ │" 27 | "└──────────────────────────────────────────────────────────────────────────────┘" 28 | " F1: Help | Shift+Tab: Switch Pane | Ctrl+P/N: Cycle History | ↑/Ctrl+R: History" 29 | -------------------------------------------------------------------------------- /src/app/snapshots/jiq__app__app_render__snapshot_tests__snapshot_ui_insert_mode.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/app/app_render.rs 3 | expression: output 4 | --- 5 | "┌ Object ──────────────────────────────────────────────────────────────────────┐" 6 | "│{ │" 7 | "│ "test": true │" 8 | "│} │" 9 | "│ │" 10 | "│ │" 11 | "│ │" 12 | "│ │" 13 | "│ │" 14 | "│ │" 15 | "│ │" 16 | "│ │" 17 | "│ │" 18 | "│ │" 19 | "│ │" 20 | "│ │" 21 | "│ │" 22 | "│ │" 23 | "│ │" 24 | "└──────────────────────────────────────────────────────────────────────────────┘" 25 | "┌ Query [INSERT] ─────────────────────────────── Press Ctrl+A for AI Assistant ┐" 26 | "│ │" 27 | "└──────────────────────────────────────────────────────────────────────────────┘" 28 | " F1: Help | Shift+Tab: Switch Pane | Ctrl+P/N: Cycle History | ↑/Ctrl+R: History" 29 | -------------------------------------------------------------------------------- /src/app/snapshots/jiq__app__app_render__snapshot_tests__snapshot_ui_normal_mode.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/app/app_render.rs 3 | expression: output 4 | --- 5 | "┌ Object ──────────────────────────────────────────────────────────────────────┐" 6 | "│{ │" 7 | "│ "test": true │" 8 | "│} │" 9 | "│ │" 10 | "│ │" 11 | "│ │" 12 | "│ │" 13 | "│ │" 14 | "│ │" 15 | "│ │" 16 | "│ │" 17 | "│ │" 18 | "│ │" 19 | "│ │" 20 | "│ │" 21 | "│ │" 22 | "│ │" 23 | "│ │" 24 | "└──────────────────────────────────────────────────────────────────────────────┘" 25 | "┌ Query [NORMAL] (press 'i' to edit) ─────────── Press Ctrl+A for AI Assistant ┐" 26 | "│ │" 27 | "└──────────────────────────────────────────────────────────────────────────────┘" 28 | " F1/?: Help | Shift+Tab: Switch Pane | Enter: Output Result | Ctrl+Q: Output Que" 29 | -------------------------------------------------------------------------------- /src/app/snapshots/jiq__app__app_render__snapshot_tests__snapshot_ui_operator_mode.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/app/app_render.rs 3 | expression: output 4 | --- 5 | "┌ Object ──────────────────────────────────────────────────────────────────────┐" 6 | "│{ │" 7 | "│ "test": true │" 8 | "│} │" 9 | "│ │" 10 | "│ │" 11 | "│ │" 12 | "│ │" 13 | "│ │" 14 | "│ │" 15 | "│ │" 16 | "│ │" 17 | "│ │" 18 | "│ │" 19 | "│ │" 20 | "│ │" 21 | "│ │" 22 | "│ │" 23 | "│ │" 24 | "└──────────────────────────────────────────────────────────────────────────────┘" 25 | "┌ Query [OPERATOR(d)] ────────────────────────── Press Ctrl+A for AI Assistant ┐" 26 | "│ │" 27 | "└──────────────────────────────────────────────────────────────────────────────┘" 28 | " F1/?: Help | Shift+Tab: Switch Pane | Enter: Output Result | Ctrl+Q: Output Que" 29 | -------------------------------------------------------------------------------- /src/app/snapshots/jiq__app__app_render__snapshot_tests__snapshot_ui_results_focused.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/app/app_render.rs 3 | expression: output 4 | --- 5 | "┌ Object ──────────────────────────────────────────────────────────────────────┐" 6 | "│{ │" 7 | "│ "test": true │" 8 | "│} │" 9 | "│ │" 10 | "│ │" 11 | "│ │" 12 | "│ │" 13 | "│ │" 14 | "│ │" 15 | "│ │" 16 | "│ │" 17 | "│ │" 18 | "│ │" 19 | "│ │" 20 | "│ │" 21 | "│ │" 22 | "│ │" 23 | "│ │" 24 | "└──────────────────────────────────────────────────────────────────────────────┘" 25 | "┌ Query [INSERT] ─────────────────────────────── Press Ctrl+A for AI Assistant ┐" 26 | "│ │" 27 | "└──────────────────────────────────────────────────────────────────────────────┘" 28 | " F1/?: Help | Shift+Tab: Switch Pane | Enter: Output Result | Ctrl+Q: Output Que" 29 | -------------------------------------------------------------------------------- /src/app/snapshots/jiq__app__app_render__snapshot_tests__snapshot_ui_with_array_data.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/app/app_render.rs 3 | expression: output 4 | --- 5 | "┌ Stream [3] ──────────────────────────────────────────────────────────────────┐" 6 | "│"Alice" │" 7 | "│"Bob" │" 8 | "│"Charlie" │" 9 | "│ │" 10 | "│ │" 11 | "│ │" 12 | "│ │" 13 | "│ │" 14 | "│ │" 15 | "│ │" 16 | "│ │" 17 | "│ │" 18 | "│ │" 19 | "│ │" 20 | "│ │" 21 | "│ │" 22 | "│ │" 23 | "│ │" 24 | "└──────────────────────────────────────────────────────────────────────────────┘" 25 | "┌ Query [INSERT] ─────────────────────────────── Press Ctrl+A for AI Assistant ┐" 26 | "│.[].name │" 27 | "└──────────────────────────────────────────────────────────────────────────────┘" 28 | " F1: Help | Shift+Tab: Switch Pane | ↑/Ctrl+R: History | Enter: Output Result | " 29 | -------------------------------------------------------------------------------- /src/app/snapshots/jiq__app__render__snapshot_tests__snapshot_history_popup_no_matches.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/app/render.rs 3 | expression: output 4 | --- 5 | "┌ Object ──────────────────────────────────────────────────────────────────────┐" 6 | "│{ │" 7 | "│ "test": true │" 8 | "│} │" 9 | "│ │" 10 | "│ │" 11 | "│ │" 12 | "│ │" 13 | "│ │" 14 | "│ │" 15 | "│ │" 16 | "│ │" 17 | "│ │" 18 | "│ │" 19 | "┌ History (0/1) ───────────────────────────────────────────────────────────────┐" 20 | "│ No matches │" 21 | "└──────────────────────────────────────────────────────────────────────────────┘" 22 | "┌ Search ──────────────────────────────────────────────────────────────────────┐" 23 | "│xyz │" 24 | "└──────────────────────────────────────────────────────────────────────────────┘" 25 | "┌ Query [INSERT] ──────────────────────────────────────────────────────────────┐" 26 | "│ │" 27 | "└──────────────────────────────────────────────────────────────────────────────┘" 28 | " F1: Help | Shift+Tab: Switch Pane | Ctrl+P/N: Cycle History | ↑/Ctrl+R: History" 29 | -------------------------------------------------------------------------------- /src/app/snapshots/jiq__app__render__snapshot_tests__snapshot_history_popup_with_search.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/app/render.rs 3 | expression: output 4 | --- 5 | "┌ Object ──────────────────────────────────────────────────────────────────────┐" 6 | "│{ │" 7 | "│ "test": true │" 8 | "│} │" 9 | "│ │" 10 | "│ │" 11 | "│ │" 12 | "│ │" 13 | "│ │" 14 | "│ │" 15 | "│ │" 16 | "│ │" 17 | "│ │" 18 | "│ │" 19 | "┌ History (1/3) ───────────────────────────────────────────────────────────────┐" 20 | "│ ► .name │" 21 | "└──────────────────────────────────────────────────────────────────────────────┘" 22 | "┌ Search ──────────────────────────────────────────────────────────────────────┐" 23 | "│na │" 24 | "└──────────────────────────────────────────────────────────────────────────────┘" 25 | "┌ Query [INSERT] ──────────────────────────────────────────────────────────────┐" 26 | "│ │" 27 | "└──────────────────────────────────────────────────────────────────────────────┘" 28 | " F1: Help | Shift+Tab: Switch Pane | Ctrl+P/N: Cycle History | ↑/Ctrl+R: History" 29 | -------------------------------------------------------------------------------- /src/app/snapshots/jiq__app__render__snapshot_tests__snapshot_initial_ui_empty_query.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/app/render.rs 3 | expression: output 4 | --- 5 | "┌ Object ──────────────────────────────────────────────────────────────────────┐" 6 | "│{ │" 7 | "│ "name": "Alice", │" 8 | "│ "age": 30 │" 9 | "│} │" 10 | "│ │" 11 | "│ │" 12 | "│ │" 13 | "│ │" 14 | "│ │" 15 | "│ │" 16 | "│ │" 17 | "│ │" 18 | "│ │" 19 | "│ │" 20 | "│ │" 21 | "│ │" 22 | "│ │" 23 | "│ │" 24 | "└──────────────────────────────────────────────────────────────────────────────┘" 25 | "┌ Query [INSERT] ──────────────────────────────────────────────────────────────┐" 26 | "│ │" 27 | "└──────────────────────────────────────────────────────────────────────────────┘" 28 | " F1: Help | Shift+Tab: Switch Pane | Ctrl+P/N: Cycle History | ↑/Ctrl+R: History" 29 | -------------------------------------------------------------------------------- /src/app/snapshots/jiq__app__render__snapshot_tests__snapshot_stats_bar_array_focused.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/app/render.rs 3 | expression: output 4 | --- 5 | "┌ Array [3 objects] ───────────────────────────────────────────────────────────┐" 6 | "│[ │" 7 | "│ { │" 8 | "│ "id": 1 │" 9 | "│ }, │" 10 | "│ { │" 11 | "│ "id": 2 │" 12 | "│ }, │" 13 | "│ { │" 14 | "│ "id": 3 │" 15 | "│ } │" 16 | "│] │" 17 | "│ │" 18 | "│ │" 19 | "│ │" 20 | "│ │" 21 | "│ │" 22 | "│ │" 23 | "│ │" 24 | "└──────────────────────────────────────────────────────────────────────────────┘" 25 | "┌ Query [INSERT] ──────────────────────────────────────────────────────────────┐" 26 | "│ │" 27 | "└──────────────────────────────────────────────────────────────────────────────┘" 28 | " F1/?: Help | Shift+Tab: Switch Pane | Enter: Output Result | Ctrl+Q: Output Que" 29 | -------------------------------------------------------------------------------- /src/app/snapshots/jiq__app__render__snapshot_tests__snapshot_stats_bar_object_unfocused.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/app/render.rs 3 | expression: output 4 | --- 5 | "┌ Object ──────────────────────────────────────────────────────────────────────┐" 6 | "│{ │" 7 | "│ "name": "Alice", │" 8 | "│ "age": 30 │" 9 | "│} │" 10 | "│ │" 11 | "│ │" 12 | "│ │" 13 | "│ │" 14 | "│ │" 15 | "│ │" 16 | "│ │" 17 | "│ │" 18 | "│ │" 19 | "│ │" 20 | "│ │" 21 | "│ │" 22 | "│ │" 23 | "│ │" 24 | "└──────────────────────────────────────────────────────────────────────────────┘" 25 | "┌ Query [INSERT] ──────────────────────────────────────────────────────────────┐" 26 | "│ │" 27 | "└──────────────────────────────────────────────────────────────────────────────┘" 28 | " F1: Help | Shift+Tab: Switch Pane | Ctrl+P/N: Cycle History | ↑/Ctrl+R: History" 29 | -------------------------------------------------------------------------------- /src/app/snapshots/jiq__app__render__snapshot_tests__snapshot_ui_error_overlay_visible.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/app/render.rs 3 | expression: output 4 | --- 5 | "┌ ⚠ Syntax Error (Object - last successful query result) ──────────────────────┐" 6 | "│{ │" 7 | "│ "test": true │" 8 | "│} │" 9 | "│ │" 10 | "│ │" 11 | "│ │" 12 | "│ │" 13 | "│ │" 14 | "│ │" 15 | "│ │" 16 | "│ │" 17 | "│ │" 18 | "│ ┌ Syntax Error (Ctrl+E to close) ──────────────────────────────────────────┐ │" 19 | "│ │jq: error: syntax error, unexpected end of file at , line 1, co│ │" 20 | "│ │ .invalid[ │ │" 21 | "│ │ ^ │ │" 22 | "│ │jq: 1 compile error │ │" 23 | "│ └──────────────────────────────────────────────────────────────────────────┘ │" 24 | "└──────────────────────────────────────────────────────────────────────────────┘" 25 | "┌ Query [INSERT] ⚠ Syntax Error (Ctrl+E to view)───────────────────────────────┐" 26 | "│.invalid[ │" 27 | "└──────────────────────────────────────────────────────────────────────────────┘" 28 | " F1: Help | Shift+Tab: Switch Pane | ↑/Ctrl+R: History | Enter: Output Result | " 29 | -------------------------------------------------------------------------------- /src/app/snapshots/jiq__app__app_render__snapshot_tests__snapshot_initial_ui_empty_query.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/app/app_render.rs 3 | expression: output 4 | --- 5 | "┌ Object ──────────────────────────────────────────────────────────────────────┐" 6 | "│{ │" 7 | "│ "name": "Alice", │" 8 | "│ "age": 30 │" 9 | "│} │" 10 | "│ │" 11 | "│ │" 12 | "│ │" 13 | "│ │" 14 | "│ │" 15 | "│ │" 16 | "│ │" 17 | "│ │" 18 | "│ │" 19 | "│ │" 20 | "│ │" 21 | "│ │" 22 | "│ │" 23 | "│ │" 24 | "└──────────────────────────────────────────────────────────────────────────────┘" 25 | "┌ Query [INSERT] ─────────────────────────────── Press Ctrl+A for AI Assistant ┐" 26 | "│ │" 27 | "└──────────────────────────────────────────────────────────────────────────────┘" 28 | " F1: Help | Shift+Tab: Switch Pane | Ctrl+P/N: Cycle History | ↑/Ctrl+R: History" 29 | -------------------------------------------------------------------------------- /src/app/snapshots/jiq__app__app_render__snapshot_tests__snapshot_search_bar_no_matches.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/app/app_render.rs 3 | expression: output 4 | --- 5 | "┌ Object ──────────────────────────────────────────────────────────────────────┐" 6 | "│{ │" 7 | "│ "name": "Alice", │" 8 | "│ "age": 30 │" 9 | "│} │" 10 | "│ │" 11 | "│ │" 12 | "│ │" 13 | "│ │" 14 | "│ │" 15 | "│ │" 16 | "│ │" 17 | "│ │" 18 | "│ │" 19 | "│ │" 20 | "│ │" 21 | "└──────────────────────────────────────────────────────────────────────────────┘" 22 | "┌ Search: ────────────────────────────────────────────────────────────── (0/0) ┐" 23 | "│xyz │" 24 | "└──────────────────────────────────────────────────────────────────────────────┘" 25 | "┌ Query [INSERT] ─────────────────────────────── Press Ctrl+A for AI Assistant ┐" 26 | "│ │" 27 | "└──────────────────────────────────────────────────────────────────────────────┘" 28 | " F1/?: Help | Shift+Tab: Switch Pane | Enter: Output Result | Ctrl+Q: Output Que" 29 | -------------------------------------------------------------------------------- /src/app/snapshots/jiq__app__app_render__snapshot_tests__snapshot_stats_bar_array_focused.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/app/app_render.rs 3 | expression: output 4 | --- 5 | "┌ Array [3 objects] ───────────────────────────────────────────────────────────┐" 6 | "│[ │" 7 | "│ { │" 8 | "│ "id": 1 │" 9 | "│ }, │" 10 | "│ { │" 11 | "│ "id": 2 │" 12 | "│ }, │" 13 | "│ { │" 14 | "│ "id": 3 │" 15 | "│ } │" 16 | "│] │" 17 | "│ │" 18 | "│ │" 19 | "│ │" 20 | "│ │" 21 | "│ │" 22 | "│ │" 23 | "│ │" 24 | "└──────────────────────────────────────────────────────────────────────────────┘" 25 | "┌ Query [INSERT] ─────────────────────────────── Press Ctrl+A for AI Assistant ┐" 26 | "│ │" 27 | "└──────────────────────────────────────────────────────────────────────────────┘" 28 | " F1/?: Help | Shift+Tab: Switch Pane | Enter: Output Result | Ctrl+Q: Output Que" 29 | -------------------------------------------------------------------------------- /src/app/snapshots/jiq__app__render__snapshot_tests__snapshot_autocomplete_popup_mixed_types.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/app/render.rs 3 | expression: output 4 | --- 5 | "┌ Object ──────────────────────────────────────────────────────────────────────┐" 6 | "│{ │" 7 | "│ "name": "Alice", │" 8 | "│ "age": 30 │" 9 | "│} │" 10 | "│ │" 11 | "│ │" 12 | "│ │" 13 | "│ │" 14 | "│ │" 15 | "│ │" 16 | "│ │" 17 | "│ │" 18 | "│ │" 19 | "│ │" 20 | "│ ┌ Suggestions ───────────┐ │" 21 | "│ │► keys [function] │ │" 22 | "│ │ name [field: String] │ │" 23 | "│ │ .[] [iterator] │ │" 24 | "└─└────────────────────────┘───────────────────────────────────────────────────┘" 25 | "┌ Query [INSERT] ──────────────────────────────────────────────────────────────┐" 26 | "│ │" 27 | "└──────────────────────────────────────────────────────────────────────────────┘" 28 | " F1: Help | Shift+Tab: Switch Pane | Ctrl+P/N: Cycle History | ↑/Ctrl+R: History" 29 | -------------------------------------------------------------------------------- /src/app/snapshots/jiq__app__render__snapshot_tests__snapshot_search_bar_with_match_count.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/app/render.rs 3 | expression: output 4 | --- 5 | "┌ Array [3 objects] ───────────────────────────────────────────────────────────┐" 6 | "│[ │" 7 | "│ { │" 8 | "│ "name": "alice" │" 9 | "│ }, │" 10 | "│ { │" 11 | "│ "name": "bob" │" 12 | "│ }, │" 13 | "│ { │" 14 | "│ "name": "alice" │" 15 | "│ } │" 16 | "│] │" 17 | "│ │" 18 | "│ │" 19 | "│ │" 20 | "│ │" 21 | "└──────────────────────────────────────────────────────────────────────────────┘" 22 | "┌ Search: ────────────────────────────────────────────────────────────── (1/2) ┐" 23 | "│alice │" 24 | "└──────────────────────────────────────────────────────────────────────────────┘" 25 | "┌ Query [INSERT] ──────────────────────────────────────────────────────────────┐" 26 | "│ │" 27 | "└──────────────────────────────────────────────────────────────────────────────┘" 28 | " F1/?: Help | Shift+Tab: Switch Pane | Enter: Output Result | Ctrl+Q: Output Que" 29 | -------------------------------------------------------------------------------- /src/app/snapshots/jiq__app__render__snapshot_tests__snapshot_search_with_highlighted_matches.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/app/render.rs 3 | expression: output 4 | --- 5 | "┌ Array [3 objects] ───────────────────────────────────────────────────────────┐" 6 | "│[ │" 7 | "│ { │" 8 | "│ "name": "alice", │" 9 | "│ "email": "alice@test.com" │" 10 | "│ }, │" 11 | "│ { │" 12 | "│ "name": "bob" │" 13 | "│ }, │" 14 | "│ { │" 15 | "│ "name": "alice" │" 16 | "│ } │" 17 | "│] │" 18 | "│ │" 19 | "│ │" 20 | "│ │" 21 | "└──────────────────────────────────────────────────────────────────────────────┘" 22 | "┌ Search: ────────────────────────────────────────────────────────────── (2/3) ┐" 23 | "│alice │" 24 | "└──────────────────────────────────────────────────────────────────────────────┘" 25 | "┌ Query [INSERT] ──────────────────────────────────────────────────────────────┐" 26 | "│ │" 27 | "└──────────────────────────────────────────────────────────────────────────────┘" 28 | " F1/?: Help | Shift+Tab: Switch Pane | Enter: Output Result | Ctrl+Q: Output Que" 29 | -------------------------------------------------------------------------------- /src/app/snapshots/jiq__app__render__snapshot_tests__snapshot_search_with_horizontal_scroll.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/app/render.rs 3 | expression: output 4 | --- 5 | "┌ Object ──────────────────────────────────────────────────────────────────────┐" 6 | "│ │" 7 | "│ │" 8 | "│ match_her│" 9 | "│ │" 10 | "│ │" 11 | "│ │" 12 | "│ │" 13 | "│ │" 14 | "│ │" 15 | "│ │" 16 | "│ │" 17 | "│ │" 18 | "│ │" 19 | "│ │" 20 | "│ │" 21 | "└──────────────────────────────────────────────────────────────────────────────┘" 22 | "┌ Search: ────────────────────────────────────────────────────────────── (1/1) ┐" 23 | "│match_here │" 24 | "└──────────────────────────────────────────────────────────────────────────────┘" 25 | "┌ Query [INSERT] ──────────────────────────────────────────────────────────────┐" 26 | "│ │" 27 | "└──────────────────────────────────────────────────────────────────────────────┘" 28 | " F1/?: Help | Shift+Tab: Switch Pane | Enter: Output Result | Ctrl+Q: Output Que" 29 | -------------------------------------------------------------------------------- /src/app/snapshots/jiq__app__app_render__snapshot_tests__snapshot_history_popup_no_matches.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/app/app_render.rs 3 | expression: output 4 | --- 5 | "┌ Object ──────────────────────────────────────────────────────────────────────┐" 6 | "│{ │" 7 | "│ "test": true │" 8 | "│} │" 9 | "│ │" 10 | "│ │" 11 | "│ │" 12 | "│ │" 13 | "│ │" 14 | "│ │" 15 | "│ │" 16 | "│ │" 17 | "│ │" 18 | "│ │" 19 | "┌ History (0/1) ───────────────────────────────────────────────────────────────┐" 20 | "│ No matches │" 21 | "└──────────────────────────────────────────────────────────────────────────────┘" 22 | "┌ Search ──────────────────────────────────────────────────────────────────────┐" 23 | "│xyz │" 24 | "└──────────────────────────────────────────────────────────────────────────────┘" 25 | "┌ Query [INSERT] ─────────────────────────────── Press Ctrl+A for AI Assistant ┐" 26 | "│ │" 27 | "└──────────────────────────────────────────────────────────────────────────────┘" 28 | " F1: Help | Shift+Tab: Switch Pane | Ctrl+P/N: Cycle History | ↑/Ctrl+R: History" 29 | -------------------------------------------------------------------------------- /src/app/snapshots/jiq__app__app_render__snapshot_tests__snapshot_history_popup_with_search.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/app/app_render.rs 3 | expression: output 4 | --- 5 | "┌ Object ──────────────────────────────────────────────────────────────────────┐" 6 | "│{ │" 7 | "│ "test": true │" 8 | "│} │" 9 | "│ │" 10 | "│ │" 11 | "│ │" 12 | "│ │" 13 | "│ │" 14 | "│ │" 15 | "│ │" 16 | "│ │" 17 | "│ │" 18 | "│ │" 19 | "┌ History (1/3) ───────────────────────────────────────────────────────────────┐" 20 | "│ ► .name │" 21 | "└──────────────────────────────────────────────────────────────────────────────┘" 22 | "┌ Search ──────────────────────────────────────────────────────────────────────┐" 23 | "│na │" 24 | "└──────────────────────────────────────────────────────────────────────────────┘" 25 | "┌ Query [INSERT] ─────────────────────────────── Press Ctrl+A for AI Assistant ┐" 26 | "│ │" 27 | "└──────────────────────────────────────────────────────────────────────────────┘" 28 | " F1: Help | Shift+Tab: Switch Pane | Ctrl+P/N: Cycle History | ↑/Ctrl+R: History" 29 | -------------------------------------------------------------------------------- /src/app/snapshots/jiq__app__app_render__snapshot_tests__snapshot_input_border_with_ai_hint.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/app/app_render.rs 3 | expression: output 4 | --- 5 | "┌ Object ──────────────────────────────────────────────────────────────────────┐" 6 | "│{ │" 7 | "│ "name": "Alice", │" 8 | "│ "age": 30 │" 9 | "│} │" 10 | "│ │" 11 | "│ │" 12 | "│ │" 13 | "│ │" 14 | "│ │" 15 | "│ │" 16 | "│ │" 17 | "│ │" 18 | "│ │" 19 | "│ │" 20 | "│ │" 21 | "│ │" 22 | "│ │" 23 | "│ │" 24 | "└──────────────────────────────────────────────────────────────────────────────┘" 25 | "┌ Query [INSERT] ─────────────────────────────── Press Ctrl+A for AI Assistant ┐" 26 | "│ │" 27 | "└──────────────────────────────────────────────────────────────────────────────┘" 28 | " F1: Help | Shift+Tab: Switch Pane | Ctrl+P/N: Cycle History | ↑/Ctrl+R: History" 29 | -------------------------------------------------------------------------------- /src/app/snapshots/jiq__app__app_render__snapshot_tests__snapshot_processing_with_syntax_error.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/app/app_render.rs 3 | expression: output 4 | --- 5 | "┌⠸ ⚠ Syntax Error (String - last successful query result) ────────────────────┐" 6 | "│"Alice" │" 7 | "│ │" 8 | "│ │" 9 | "│ │" 10 | "│ │" 11 | "│ │" 12 | "│ │" 13 | "│ │" 14 | "│ │" 15 | "│ │" 16 | "│ │" 17 | "│ │" 18 | "│ │" 19 | "│ │" 20 | "│ │" 21 | "│ │" 22 | "│ │" 23 | "│ │" 24 | "└──────────────────────────────────────────────────────────────────────────────┘" 25 | "┌ Query [INSERT] ⚠ Syntax Error (Ctrl+E to view) Press Ctrl+A for AI Assistant ┐" 26 | "│.invalid[ │" 27 | "└──────────────────────────────────────────────────────────────────────────────┘" 28 | " F1: Help | Shift+Tab: Switch Pane | ↑/Ctrl+R: History | Enter: Output Result | " 29 | -------------------------------------------------------------------------------- /src/app/snapshots/jiq__app__app_render__snapshot_tests__snapshot_search_bar_with_match_count.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/app/app_render.rs 3 | expression: output 4 | --- 5 | "┌ Array [3 objects] ───────────────────────────────────────────────────────────┐" 6 | "│[ │" 7 | "│ { │" 8 | "│ "name": "alice" │" 9 | "│ }, │" 10 | "│ { │" 11 | "│ "name": "bob" │" 12 | "│ }, │" 13 | "│ { │" 14 | "│ "name": "alice" │" 15 | "│ } │" 16 | "│] │" 17 | "│ │" 18 | "│ │" 19 | "│ │" 20 | "│ │" 21 | "└──────────────────────────────────────────────────────────────────────────────┘" 22 | "┌ Search: ────────────────────────────────────────────────────────────── (1/2) ┐" 23 | "│alice │" 24 | "└──────────────────────────────────────────────────────────────────────────────┘" 25 | "┌ Query [INSERT] ─────────────────────────────── Press Ctrl+A for AI Assistant ┐" 26 | "│ │" 27 | "└──────────────────────────────────────────────────────────────────────────────┘" 28 | " F1/?: Help | Shift+Tab: Switch Pane | Enter: Output Result | Ctrl+Q: Output Que" 29 | -------------------------------------------------------------------------------- /src/app/snapshots/jiq__app__app_render__snapshot_tests__snapshot_stats_bar_object_unfocused.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/app/app_render.rs 3 | expression: output 4 | --- 5 | "┌ Object ──────────────────────────────────────────────────────────────────────┐" 6 | "│{ │" 7 | "│ "name": "Alice", │" 8 | "│ "age": 30 │" 9 | "│} │" 10 | "│ │" 11 | "│ │" 12 | "│ │" 13 | "│ │" 14 | "│ │" 15 | "│ │" 16 | "│ │" 17 | "│ │" 18 | "│ │" 19 | "│ │" 20 | "│ │" 21 | "│ │" 22 | "│ │" 23 | "│ │" 24 | "└──────────────────────────────────────────────────────────────────────────────┘" 25 | "┌ Query [INSERT] ─────────────────────────────── Press Ctrl+A for AI Assistant ┐" 26 | "│ │" 27 | "└──────────────────────────────────────────────────────────────────────────────┘" 28 | " F1: Help | Shift+Tab: Switch Pane | Ctrl+P/N: Cycle History | ↑/Ctrl+R: History" 29 | -------------------------------------------------------------------------------- /src/app/snapshots/jiq__app__app_render__snapshot_tests__snapshot_ui_error_overlay_visible.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/app/app_render.rs 3 | expression: output 4 | --- 5 | "┌ ⚠ Syntax Error (Object - last successful query result) ──────────────────────┐" 6 | "│{ │" 7 | "│ "test": true │" 8 | "│} │" 9 | "│ │" 10 | "│ │" 11 | "│ │" 12 | "│ │" 13 | "│ │" 14 | "│ │" 15 | "│ │" 16 | "│ │" 17 | "│ │" 18 | "│ ┌ Syntax Error (Ctrl+E to close) ──────────────────────────────────────────┐ │" 19 | "│ │jq: error: syntax error, unexpected end of file at , line 1, co│ │" 20 | "│ │ .invalid[ │ │" 21 | "│ │ ^ │ │" 22 | "│ │jq: 1 compile error │ │" 23 | "│ └──────────────────────────────────────────────────────────────────────────┘ │" 24 | "└──────────────────────────────────────────────────────────────────────────────┘" 25 | "┌ Query [INSERT] ⚠ Syntax Error (Ctrl+E to view) Press Ctrl+A for AI Assistant ┐" 26 | "│.invalid[ │" 27 | "└──────────────────────────────────────────────────────────────────────────────┘" 28 | " F1: Help | Shift+Tab: Switch Pane | ↑/Ctrl+R: History | Enter: Output Result | " 29 | -------------------------------------------------------------------------------- /src/app/snapshots/jiq__app__render__snapshot_tests__snapshot_results_pane_with_success_focused.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/app/render.rs 3 | expression: output 4 | --- 5 | "┌ String ──────────────────────────────────────────────────────────────────────┐" 6 | "│"Alice" │" 7 | "│ │" 8 | "│ │" 9 | "│ │" 10 | "│ │" 11 | "│ │" 12 | "│ │" 13 | "│ │" 14 | "│ │" 15 | "│ │" 16 | "│ │" 17 | "│ │" 18 | "│ │" 19 | "│ │" 20 | "│ │" 21 | "│ │" 22 | "│ │" 23 | "│ │" 24 | "└──────────────────────────────────────────────────────────────────────────────┘" 25 | "┌ Query [INSERT] ──────────────────────────────────────────────────────────────┐" 26 | "│.name │" 27 | "└──────────────────────────────────────────────────────────────────────────────┘" 28 | " F1/?: Help | Shift+Tab: Switch Pane | Enter: Output Result | Ctrl+Q: Output Que" 29 | -------------------------------------------------------------------------------- /src/app/snapshots/jiq__app__render__snapshot_tests__snapshot_results_pane_with_success_unfocused.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/app/render.rs 3 | expression: output 4 | --- 5 | "┌ String ──────────────────────────────────────────────────────────────────────┐" 6 | "│"Alice" │" 7 | "│ │" 8 | "│ │" 9 | "│ │" 10 | "│ │" 11 | "│ │" 12 | "│ │" 13 | "│ │" 14 | "│ │" 15 | "│ │" 16 | "│ │" 17 | "│ │" 18 | "│ │" 19 | "│ │" 20 | "│ │" 21 | "│ │" 22 | "│ │" 23 | "│ │" 24 | "└──────────────────────────────────────────────────────────────────────────────┘" 25 | "┌ Query [INSERT] ──────────────────────────────────────────────────────────────┐" 26 | "│.name │" 27 | "└──────────────────────────────────────────────────────────────────────────────┘" 28 | " F1: Help | Shift+Tab: Switch Pane | ↑/Ctrl+R: History | Enter: Output Result | " 29 | -------------------------------------------------------------------------------- /src/app/snapshots/jiq__app__render__snapshot_tests__snapshot_stats_bar_error_shows_last_stats.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/app/render.rs 3 | expression: output 4 | --- 5 | "┌ ⚠ Syntax Error (Array [5 numbers] - last successful query result) ───────────┐" 6 | "│[ │" 7 | "│ 1, │" 8 | "│ 2, │" 9 | "│ 3, │" 10 | "│ 4, │" 11 | "│ 5 │" 12 | "│] │" 13 | "│ │" 14 | "│ │" 15 | "│ │" 16 | "│ │" 17 | "│ │" 18 | "│ │" 19 | "│ │" 20 | "│ │" 21 | "│ │" 22 | "│ │" 23 | "│ │" 24 | "└──────────────────────────────────────────────────────────────────────────────┘" 25 | "┌ Query [INSERT] ⚠ Syntax Error (Ctrl+E to view)───────────────────────────────┐" 26 | "│.invalid[ │" 27 | "└──────────────────────────────────────────────────────────────────────────────┘" 28 | " F1: Help | Shift+Tab: Switch Pane | ↑/Ctrl+R: History | Enter: Output Result | " 29 | -------------------------------------------------------------------------------- /src/app/snapshots/jiq__app__app_render__snapshot_tests__snapshot_autocomplete_popup_mixed_types.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/app/app_render.rs 3 | expression: output 4 | --- 5 | "┌ Object ──────────────────────────────────────────────────────────────────────┐" 6 | "│{ │" 7 | "│ "name": "Alice", │" 8 | "│ "age": 30 │" 9 | "│} │" 10 | "│ │" 11 | "│ │" 12 | "│ │" 13 | "│ │" 14 | "│ │" 15 | "│ │" 16 | "│ │" 17 | "│ │" 18 | "│ │" 19 | "│ │" 20 | "│ ┌ Suggestions ───────────┐ │" 21 | "│ │► keys [function] │ │" 22 | "│ │ name [field: String] │ │" 23 | "│ │ .[] [iterator] │ │" 24 | "└─└────────────────────────┘───────────────────────────────────────────────────┘" 25 | "┌ Query [INSERT] ─────────────────────────────── Press Ctrl+A for AI Assistant ┐" 26 | "│ │" 27 | "└──────────────────────────────────────────────────────────────────────────────┘" 28 | " F1: Help | Shift+Tab: Switch Pane | Ctrl+P/N: Cycle History | ↑/Ctrl+R: History" 29 | -------------------------------------------------------------------------------- /src/app/snapshots/jiq__app__app_render__snapshot_tests__snapshot_help_popup_with_ai_keybindings.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/app/app_render.rs 3 | expression: output 4 | --- 5 | "┌ Obj┌ Keyboard Shortcuts ────────────────────────────────────────────────┐────┐" 6 | "│{ │ Enter Confirm search │ │" 7 | "│ "t│ n/Enter Next match │ │" 8 | "│} │ N/Shift+Enter Previous match │ │" 9 | "│ │ Ctrl+F or / Re-enter edit mode │ │" 10 | "│ │ Esc Close search │ │" 11 | "│ │ │ │" 12 | "│ │ ── HISTORY POPUP ── │ │" 13 | "│ │ Up/Down Navigate entries │ │" 14 | "│ │ Type Fuzzy search filter │ │" 15 | "│ │ Enter/Tab Select entry and close │ │" 16 | "│ │ Esc Close without selecting │ │" 17 | "│ │ │ │" 18 | "│ │ ── ERROR OVERLAY ── │ │" 19 | "│ │ Ctrl+E Toggle error details │ │" 20 | "│ │ │ │" 21 | "│ │ ── AI ASSISTANT ── │ │" 22 | "│ │ Ctrl+A Toggle AI assistant │ │" 23 | "│ │ Alt+1-5 Apply AI suggestion (direct) │ │" 24 | "└────│ Alt+↑↓/j/k Navigate suggestions │────┘" 25 | "┌ Que│ Enter Apply selected suggestion │ant ┐" 26 | "│ │ │ │" 27 | "└────│ j/k: scroll | g/G: top/bottom | F1/q/?: close │────┘" 28 | " F1: └────────────────────────────────────────────────────────────────────┘story" 29 | --------------------------------------------------------------------------------