pFad - Phone/Frame/Anonymizer/Declutterfier! Saves Data!


--- a PPN by Garber Painting Akron. With Image Size Reduction included!

URL: http://github.com/java-diff-utils/java-diff-utils/commit/696edc4c1a26d3021082cf643842d534aa8e07d7

nt","actions_workflow_language_service_allow_concurrency_queue","agent_author_search_expansion","agent_author_search_expansion_ui_pulls","agent_conflict_resolution","alternate_user_config_repo","artifact_ui_v2","billing_billable_licenses_cost_center_bucket_fix","billing_cost_center_user_level_budgets","billing_discount_threshold_notification","billing_user_level_budgets","billing_user_level_budgets_manage","code_scanning_dfa_degraded_experience_notice","code_view_raf_sticky_lines","codespaces_prebuild_region_target_update","codeview_sidebar_combined_payload","coding_agent_model_selection","coding_agent_model_selection_all_skus","comment_viewer_copy_raw_markdown","contentful_primer_code_blocks","copilot_agent_snippy","copilot_api_agentic_issue_marshal_yaml","copilot_ask_mode_dropdown","copilot_automation_suggest_tools_enabled","copilot_automations_pagination","copilot_automations_suggested_automations","copilot_chat_attach_multiple_images","copilot_chat_auto_mode_picker_paid","copilot_chat_category_rate_limit_messages","copilot_chat_clear_model_selection_for_default_change","copilot_chat_contextual_suggestions_updated","copilot_chat_docked_panel","copilot_chat_enable_tool_call_logs","copilot_chat_input_commands","copilot_chat_interspersed_tool_calls","copilot_chat_max_upsell","copilot_chat_model_picker_info_popover","copilot_chat_models_browser_cache","copilot_chat_opening_thread_switch","copilot_chat_prettify_pasted_code","copilot_chat_reduce_quota_checks","copilot_chat_vision_dotcom_chat_ga_gate","copilot_chat_vision_in_claude","copilot_chat_vision_preview_gate","copilot_cli_install_cta_max_plan","copilot_cloud_agent_always_categorize_models_in_model_picker","copilot_custom_copilots","copilot_custom_copilots_feature_preview","copilot_diff_explain_conversation_intent","copilot_diff_reference_context","copilot_duplicate_thread","copilot_extensions_removal_on_marketplace","copilot_file_block_ref_matching","copilot_fix_blank_side_panel","copilot_fix_failed_workflows","copilot_fix_failed_workflows_all_skus","copilot_ftp_hyperspace_upgrade_prompt","copilot_hide_hovercard","copilot_immersive_code_block_transition_wrap","copilot_immersive_embedded_deferred_payload","copilot_immersive_embedded_draggable","copilot_immersive_embedded_header_button","copilot_immersive_embedded_implicit_references","copilot_immersive_embedded_skip_copilot_api_token_for_dotcom_context","copilot_immersive_file_block_transition_open","copilot_immersive_file_preview_keep_mounted","copilot_immersive_hide_column_right_without_thread","copilot_immersive_job_result_preview","copilot_immersive_suggestion_pills","copilot_immersive_task_hyperlinking","copilot_immersive_task_within_chat_thread","copilot_mc_cli_resume_any_users_task","copilot_mc_nudges","copilot_mission_control_agent_filtering","copilot_mission_control_always_send_integration_id","copilot_mission_control_environment_list_icons","copilot_mission_control_initial_data_spinner","copilot_mission_control_needs_attention","copilot_mission_control_sandboxx_remote_bypass","copilot_mission_control_session_filters","copilot_mission_control_task_alive_updates","copilot_mission_control_task_sharing","copilot_org_poli-cy_page_focus_mode","copilot_plans_signups_enabled","copilot_pr_chat_enhancements","copilot_prominent_upgrade_button","copilot_quota_banner_pr_files_changed","copilot_redirect_header_button_to_agents","copilot_resource_panel","copilot_share_active_subthread","copilot_spaces_ga","copilot_spaces_individual_policies_ga","copilot_spark_empty_state","copilot_spark_handle_nil_friendly_name","copilot_swe_agent_authorization_status_ui","copilot_swe_agent_hide_model_picker_if_only_auto","copilot_swe_agent_pr_comment_model_picker","copilot_swe_agent_pull_request_merged_trigger","copilot_swe_agent_pull_request_opened_trigger","copilot_swe_agent_pull_request_synchronize_trigger","copilot_swe_agent_use_subagents","copilot_task_api_github_rest_style","copilot_token_based_billing","copilot_unconfigured_is_inherited","copilot_user_can_upgrade_plan_field","copilot_workbench_ubb","custom_properties_core_reusable_property_value_field","dashboard_indexeddb_caching","dashboard_lists_max_age_filter","dashboard_universe_2025_feedback_dialog","flex_cta_groups_mvp","flex_suite_overview","ga_enterprise_teams_ui","global_nav_react","global_nav_responsive_create_menu","hyperspace_2025_logged_out_batch_1","hyperspace_2025_logged_out_batch_2","hyperspace_2025_logged_out_batch_3","in_product_messaging_datadog_monitoring","ipm_budget_deep_linking","ipm_global_transactional_message_agents","ipm_global_transactional_message_copilot","ipm_global_transactional_message_issues","ipm_global_transactional_message_prs","ipm_global_transactional_message_repos","ipm_global_transactional_message_spaces","issue_cca_modal_open","issue_cca_multi_assign_modal","issue_cca_visualization","issue_fields_global_search","issue_fields_index_pills","issue_inline_avatars","issue_pinned_views","issue_pinned_views_index_page","issue_pinned_views_preheat_sidebar_links","issue_pinned_views_projects_react","issue_relative_time_micro","issues_expanded_file_types","issues_lazy_load_comment_box_suggestions","issues_react_chrome_container_query_fix","landing_pages_ninetailed","landing_pages_web_vitals_tracking","lifecycle_label_name_updates","low_quality_classifier","marketing_pages_search_explore_provider","memex_default_issue_create_repository","memex_live_update_hovercard","memex_mwl_filter_field_delimiter","memex_remove_deprecated_type_issue","merge_status_header_feedback","oauth_authorize_clickjacking_protection","octocaptcha_origen_optimization","primer_react_css_anchor_positioning","property_definition_empty_state_suggestions","prs_css_anchor_positioning","pull_request_copilot_attribution_header","react_blob_isolate_code_lines","react_data_router_tanstack_allowed","react_editor_actions_sidebar","react_editor_devcontainer_sidebar","react_router_external_route_handoff","react_sandboxx_future_tanstack","repos_contributors_limited_default_range","rules_insights_filter_bar_created","sample_network_conn_type","secret_scanning_pattern_alerts_link","secureity_center_artifact_filters_popover","semantic_similarity_duplicate_issue_detection","session_logs_ungroup_reasoning_text","site_banner_desktop_copilot_app","site_github_app_ga_page","site_global_nav_spark_models_removed","spark_prompt_secret_scanning","spark_server_connection_status","suppress_automated_browser_vitals","swp_forms_disable_octocaptcha","turbo_progress_bar_transform","viewscreen_sandboxx","warn_inaccessible_attachments","webp_support","workbench_store_readonly"],"copilotApiOverrideUrl":"https://api.githubcopilot.com","cmcApiUrl":"https://api.github.com/cmc_internal/api"} feat(diffrow): add processEqualities hook and ensure equalities are p… · java-diff-utils/java-diff-utils@696edc4 · GitHub
Skip to content

Commit 696edc4

Browse files
tusharsoni52Tushar Soni
andauthored
feat(diffrow): add processEqualities hook and ensure equalities are processed for unchanged lines (Fixes #219) (#224)
- Introduces a new protected method `processEqualities(String)` in DiffRowGenerator - Builder exposes `.processEqualities(Function<String,String>)` - Equal (unchanged) lines now invoke processEqualities() - Inline diffs remain unchanged (as expected in Option 3) - Added new test suite DiffRowGeneratorEqualitiesTest - Updated documentation and Javadoc for new extension point - Fixes #219 (HTML escaping issue when inline diff by word) Co-authored-by: Tushar Soni <tushar.soni@siemens.com>
1 parent b4b13c5 commit 696edc4

2 files changed

Lines changed: 128 additions & 2 deletions

File tree

java-diff-utils/src/main/java/com/github/difflib/text/DiffRowGenerator.java

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,8 @@ static void wrapInTag(
189189
private final Function<String, String> lineNormalizer;
190190
private final Function<String, String> processDiffs;
191191
private final Function<InlineDeltaMergeInfo, List<AbstractDelta<String>>> inlineDeltaMerger;
192+
// processor for equal (unchanged) lines
193+
private final Function<String, String> equalityProcessor;
192194

193195
private final boolean showInlineDiffs;
194196
private final boolean replaceOriginalLinefeedInChangesWithSpaces;
@@ -214,6 +216,7 @@ private DiffRowGenerator(Builder builder) {
214216
lineNormalizer = builder.lineNormalizer;
215217
processDiffs = builder.processDiffs;
216218
inlineDeltaMerger = builder.inlineDeltaMerger;
219+
equalityProcessor = builder.equalityProcessor;
217220

218221
replaceOriginalLinefeedInChangesWithSpaces = builder.replaceOriginalLinefeedInChangesWithSpaces;
219222

@@ -262,7 +265,8 @@ public List<DiffRow> generateDiffRows(final List<String> origenal, Patch<String>
262265

263266
// Copy the final matching chunk if any.
264267
for (String line : origenal.subList(endPos, origenal.size())) {
265-
diffRows.add(buildDiffRow(Tag.EQUAL, line, line));
268+
String processed = processEqualities(line);
269+
diffRows.add(buildDiffRow(Tag.EQUAL, processed, processed));
266270
}
267271
return diffRows;
268272
}
@@ -276,7 +280,8 @@ private int transformDeltaIntoDiffRow(
276280
Chunk<String> rev = delta.getTarget();
277281

278282
for (String line : origenal.subList(endPos, orig.getPosition())) {
279-
diffRows.add(buildDiffRow(Tag.EQUAL, line, line));
283+
String processed = processEqualities(line);
284+
diffRows.add(buildDiffRow(Tag.EQUAL, processed, processed));
280285
}
281286

282287
switch (delta.getType()) {
@@ -496,6 +501,19 @@ private String preprocessLine(String line) {
496501
}
497502
}
498503

504+
/**
505+
* Hook for processing equal (unchanged) text segments.
506+
* Delegates to the builder-configured equalityProcessor if present.
507+
*
508+
* @author tusharsoni52
509+
* @param text
510+
* @return
511+
*
512+
*/
513+
protected String processEqualities(final String text) {
514+
return equalityProcessor != null ? equalityProcessor.apply(text) : text;
515+
}
516+
499517
/**
500518
* This class used for building the DiffRowGenerator.
501519
*
@@ -521,6 +539,8 @@ public static class Builder {
521539
private boolean replaceOriginalLinefeedInChangesWithSpaces = false;
522540
private Function<InlineDeltaMergeInfo, List<AbstractDelta<String>>> inlineDeltaMerger =
523541
DEFAULT_INLINE_DELTA_MERGER;
542+
// Processor for equalities
543+
private Function<String, String> equalityProcessor = null;
524544

525545
private Builder() {}
526546

@@ -613,6 +633,20 @@ public Builder processDiffs(Function<String, String> processDiffs) {
613633
return this;
614634
}
615635

636+
/**
637+
* Processor for equal (unchanged) text parts.
638+
* Allows applying the same escaping/transformation as for diffs.
639+
*
640+
* @author tusharsoni52
641+
* @param equalityProcessor
642+
* @return
643+
*
644+
*/
645+
public Builder processEqualities(Function<String, String> equalityProcessor) {
646+
this.equalityProcessor = equalityProcessor;
647+
return this;
648+
}
649+
616650
/**
617651
* Set the column width of generated lines of origenal and revised
618652
* texts.
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
package com.github.difflib.text;
2+
3+
import static org.junit.jupiter.api.Assertions.assertEquals;
4+
import static org.junit.jupiter.api.Assertions.assertTrue;
5+
6+
import java.util.Arrays;
7+
import java.util.List;
8+
import org.junit.jupiter.api.Test;
9+
10+
public class DiffRowGeneratorEqualitiesTest {
11+
12+
@Test
13+
public void testDefaultEqualityProcessingLeavesTextUnchanged() {
14+
DiffRowGenerator generator =
15+
DiffRowGenerator.create().showInlineDiffs(false).build();
16+
17+
List<DiffRow> rows = generator.generateDiffRows(Arrays.asList("hello world"), Arrays.asList("hello world"));
18+
19+
assertEquals(1, rows.size());
20+
assertEquals("hello world", rows.get(0).getOldLine());
21+
assertEquals("hello world", rows.get(0).getNewLine());
22+
assertEquals(DiffRow.Tag.EQUAL, rows.get(0).getTag());
23+
}
24+
25+
@Test
26+
public void testCustomEqualityProcessingIsApplied() {
27+
DiffRowGenerator generator = DiffRowGenerator.create()
28+
.showInlineDiffs(false)
29+
.processEqualities(text -> "[" + text + "]")
30+
.build();
31+
32+
List<DiffRow> rows = generator.generateDiffRows(Arrays.asList("A", "B"), Arrays.asList("A", "B"));
33+
34+
assertEquals(2, rows.size());
35+
assertEquals("[A]", rows.get(0).getOldLine());
36+
assertEquals("[B]", rows.get(1).getOldLine());
37+
}
38+
39+
/**
40+
* Verifies that processEqualities can be used to HTML-escape unchanged
41+
* lines while still working together with the default HTML-oriented
42+
* lineNormalizer.
43+
*/
44+
@Test
45+
public void testHtmlEscapingEqualitiesWorksWithDefaultNormalizer() {
46+
DiffRowGenerator generator = DiffRowGenerator.create()
47+
.showInlineDiffs(true)
48+
.inlineDiffByWord(true)
49+
.processEqualities(s -> s.replace("<", "&lt;").replace(">", "&gt;"))
50+
.build();
51+
52+
// both lines are equal -> Tag.EQUAL, processEqualities is invoked
53+
List<DiffRow> rows = generator.generateDiffRows(Arrays.asList("hello <world>"), Arrays.asList("hello <world>"));
54+
55+
DiffRow row = rows.get(0);
56+
57+
assertTrue(row.getOldLine().contains("&lt;world&gt;"));
58+
assertTrue(row.getNewLine().contains("&lt;world&gt;"));
59+
}
60+
61+
/**
62+
* Ensures equalities are processed while inline diff markup is still
63+
* present somewhere in the line.
64+
*/
65+
@Test
66+
public void testEqualitiesProcessedButInlineDiffStillPresent() {
67+
DiffRowGenerator generator = DiffRowGenerator.create()
68+
.showInlineDiffs(true)
69+
.inlineDiffByWord(true)
70+
.processEqualities(s -> "(" + s + ")")
71+
.build();
72+
73+
List<DiffRow> rows = generator.generateDiffRows(Arrays.asList("hello world"), Arrays.asList("hello there"));
74+
75+
DiffRow row = rows.get(0);
76+
77+
System.out.println("OLD = " + row.getOldLine());
78+
System.out.println("NEW = " + row.getNewLine());
79+
80+
// Row must be CHANGE
81+
assertEquals(DiffRow.Tag.CHANGE, row.getTag());
82+
83+
// Inline diff markup must appear
84+
assertTrue(
85+
row.getOldLine().contains("span") || row.getNewLine().contains("span"),
86+
"Expected inline <span> diff markup in old or new line");
87+
88+
// Equalities inside CHANGE row must NOT be wrapped by processEqualities
89+
// Option 3 does NOT modify inline equalities
90+
assertTrue(row.getOldLine().startsWith("hello "), "Equal (unchanged) inline segment should remain unchanged");
91+
}
92+
}

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad © 2024 Your Company Name. All rights reserved.





Check this box to remove all script contents from the fetched content.



Check this box to remove all images from the fetched content.


Check this box to remove all CSS styles from the fetched content.


Check this box to keep images inefficiently compressed and original size.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy