mirror of
https://github.com/abapGit/abapGit.git
synced 2025-05-01 04:08:27 +08:00
Enhance diff class (#5044)
* Enhance diff class - Refactor `zcl_abapgit_diff` to use `RS_CMP_COMPUTE_DELTA` instead of `SVRS_COMPUTE_DELTA_REPS` (needs less code in abapGit) - Replace `abaptxt_255` with `rswsourcet` which removes 255 character per line limit. Now diffs on long lines are calculated properly. - Add "ignore indent", "ignore comments", and "ignore case" options. These correspond to the options for the Split Screen Editor in SAP GUI and work the same way. The options are *not* exposed to the UI yet. Same functionality, same performance. * Lint Co-authored-by: Lars Hvam <larshp@hotmail.com>
This commit is contained in:
parent
45806c5a95
commit
c15b58400a
|
@ -1,37 +1,39 @@
|
|||
CLASS zcl_abapgit_diff DEFINITION
|
||||
PUBLIC
|
||||
CREATE PUBLIC .
|
||||
CREATE PUBLIC.
|
||||
|
||||
PUBLIC SECTION.
|
||||
CONSTANTS co_starting_beacon TYPE i VALUE 1.
|
||||
|
||||
* assumes data is UTF8 based with newlines
|
||||
* only works with lines up to 255 characters
|
||||
METHODS constructor
|
||||
IMPORTING
|
||||
!iv_new TYPE xstring
|
||||
!iv_old TYPE xstring .
|
||||
!iv_new TYPE xstring
|
||||
!iv_old TYPE xstring
|
||||
!iv_ignore_indentation TYPE abap_bool DEFAULT abap_false
|
||||
!iv_ignore_comments TYPE abap_bool DEFAULT abap_false
|
||||
!iv_ignore_case TYPE abap_bool DEFAULT abap_false.
|
||||
METHODS get
|
||||
RETURNING
|
||||
VALUE(rt_diff) TYPE zif_abapgit_definitions=>ty_diffs_tt .
|
||||
VALUE(rt_diff) TYPE zif_abapgit_definitions=>ty_diffs_tt.
|
||||
METHODS stats
|
||||
RETURNING
|
||||
VALUE(rs_count) TYPE zif_abapgit_definitions=>ty_count .
|
||||
VALUE(rs_count) TYPE zif_abapgit_definitions=>ty_count.
|
||||
METHODS set_patch_new
|
||||
IMPORTING
|
||||
!iv_line_new TYPE i
|
||||
!iv_patch_flag TYPE abap_bool
|
||||
RAISING
|
||||
zcx_abapgit_exception .
|
||||
zcx_abapgit_exception.
|
||||
METHODS set_patch_old
|
||||
IMPORTING
|
||||
!iv_line_old TYPE i
|
||||
!iv_patch_flag TYPE abap_bool
|
||||
RAISING
|
||||
zcx_abapgit_exception .
|
||||
zcx_abapgit_exception.
|
||||
METHODS get_beacons
|
||||
RETURNING
|
||||
VALUE(rt_beacons) TYPE zif_abapgit_definitions=>ty_string_tt .
|
||||
VALUE(rt_beacons) TYPE zif_abapgit_definitions=>ty_string_tt.
|
||||
METHODS is_line_patched
|
||||
IMPORTING
|
||||
iv_index TYPE i
|
||||
|
@ -47,38 +49,35 @@ CLASS zcl_abapgit_diff DEFINITION
|
|||
PROTECTED SECTION.
|
||||
|
||||
PRIVATE SECTION.
|
||||
TYPES ty_regexset_tt TYPE STANDARD TABLE OF REF TO cl_abap_regex WITH KEY table_line.
|
||||
|
||||
DATA mt_beacons TYPE zif_abapgit_definitions=>ty_string_tt .
|
||||
DATA mt_diff TYPE zif_abapgit_definitions=>ty_diffs_tt .
|
||||
DATA ms_stats TYPE zif_abapgit_definitions=>ty_count .
|
||||
TYPES:
|
||||
ty_regexset_tt TYPE STANDARD TABLE OF REF TO cl_abap_regex WITH KEY table_line.
|
||||
|
||||
CLASS-METHODS unpack
|
||||
DATA mt_beacons TYPE zif_abapgit_definitions=>ty_string_tt.
|
||||
DATA mt_diff TYPE zif_abapgit_definitions=>ty_diffs_tt.
|
||||
DATA ms_stats TYPE zif_abapgit_definitions=>ty_count.
|
||||
DATA mv_compare_mode TYPE c LENGTH 1.
|
||||
DATA mv_ignore_case TYPE abap_bool.
|
||||
|
||||
METHODS unpack
|
||||
IMPORTING
|
||||
!iv_new TYPE xstring
|
||||
!iv_old TYPE xstring
|
||||
EXPORTING
|
||||
!et_new TYPE abaptxt255_tab
|
||||
!et_old TYPE abaptxt255_tab .
|
||||
CLASS-METHODS render
|
||||
IMPORTING
|
||||
!it_new TYPE abaptxt255_tab
|
||||
!it_old TYPE abaptxt255_tab
|
||||
!it_delta TYPE vxabapt255_tab
|
||||
RETURNING
|
||||
VALUE(rt_diff) TYPE zif_abapgit_definitions=>ty_diffs_tt .
|
||||
CLASS-METHODS compute
|
||||
IMPORTING
|
||||
!it_new TYPE abaptxt255_tab
|
||||
!it_old TYPE abaptxt255_tab
|
||||
RETURNING
|
||||
VALUE(rt_delta) TYPE vxabapt255_tab .
|
||||
METHODS calculate_line_num_and_stats .
|
||||
METHODS map_beacons .
|
||||
METHODS shortlist .
|
||||
!et_new TYPE rswsourcet
|
||||
!et_old TYPE rswsourcet.
|
||||
METHODS map_beacons.
|
||||
METHODS shortlist.
|
||||
METHODS create_regex_set
|
||||
RETURNING
|
||||
VALUE(rt_regex_set) TYPE ty_regexset_tt.
|
||||
METHODS compute_and_render
|
||||
IMPORTING
|
||||
!it_new TYPE rswsourcet
|
||||
!it_old TYPE rswsourcet
|
||||
RETURNING
|
||||
VALUE(rt_diff) TYPE zif_abapgit_definitions=>ty_diffs_tt.
|
||||
METHODS calculate_stats.
|
||||
ENDCLASS.
|
||||
|
||||
|
||||
|
@ -86,31 +85,12 @@ ENDCLASS.
|
|||
CLASS zcl_abapgit_diff IMPLEMENTATION.
|
||||
|
||||
|
||||
METHOD calculate_line_num_and_stats.
|
||||
|
||||
DATA: lv_new TYPE i VALUE 1,
|
||||
lv_old TYPE i VALUE 1.
|
||||
METHOD calculate_stats.
|
||||
|
||||
FIELD-SYMBOLS: <ls_diff> LIKE LINE OF mt_diff.
|
||||
|
||||
|
||||
LOOP AT mt_diff ASSIGNING <ls_diff>.
|
||||
<ls_diff>-new_num = lv_new.
|
||||
<ls_diff>-old_num = lv_old.
|
||||
|
||||
CASE <ls_diff>-result. " Line nums
|
||||
WHEN zif_abapgit_definitions=>c_diff-delete.
|
||||
lv_old = lv_old + 1.
|
||||
CLEAR <ls_diff>-new_num.
|
||||
WHEN zif_abapgit_definitions=>c_diff-insert.
|
||||
lv_new = lv_new + 1.
|
||||
CLEAR <ls_diff>-old_num.
|
||||
WHEN OTHERS.
|
||||
lv_new = lv_new + 1.
|
||||
lv_old = lv_old + 1.
|
||||
ENDCASE.
|
||||
|
||||
CASE <ls_diff>-result. " Stats
|
||||
CASE <ls_diff>-result.
|
||||
WHEN zif_abapgit_definitions=>c_diff-insert.
|
||||
ms_stats-insert = ms_stats-insert + 1.
|
||||
WHEN zif_abapgit_definitions=>c_diff-delete.
|
||||
|
@ -118,51 +98,103 @@ CLASS zcl_abapgit_diff IMPLEMENTATION.
|
|||
WHEN zif_abapgit_definitions=>c_diff-update.
|
||||
ms_stats-update = ms_stats-update + 1.
|
||||
ENDCASE.
|
||||
|
||||
ENDLOOP.
|
||||
|
||||
ENDMETHOD.
|
||||
|
||||
|
||||
METHOD compute.
|
||||
METHOD compute_and_render.
|
||||
|
||||
DATA: lt_trdirtab_old TYPE TABLE OF trdir,
|
||||
lt_trdirtab_new TYPE TABLE OF trdir,
|
||||
lt_trdir_delta TYPE TABLE OF xtrdir.
|
||||
DATA:
|
||||
lv_i TYPE i,
|
||||
ls_diff LIKE LINE OF rt_diff,
|
||||
lt_delta TYPE STANDARD TABLE OF rsedcresul WITH DEFAULT KEY.
|
||||
|
||||
FIELD-SYMBOLS:
|
||||
<ls_old> LIKE LINE OF it_old,
|
||||
<ls_new> LIKE LINE OF it_new,
|
||||
<ls_delta> LIKE LINE OF lt_delta.
|
||||
|
||||
CALL FUNCTION 'SVRS_COMPUTE_DELTA_REPS'
|
||||
CALL FUNCTION 'RS_CMP_COMPUTE_DELTA'
|
||||
EXPORTING
|
||||
compare_mode = mv_compare_mode
|
||||
ignore_case_differences = mv_ignore_case
|
||||
TABLES
|
||||
texttab_old = it_old
|
||||
texttab_new = it_new
|
||||
trdirtab_old = lt_trdirtab_old
|
||||
trdirtab_new = lt_trdirtab_new
|
||||
trdir_delta = lt_trdir_delta
|
||||
text_delta = rt_delta.
|
||||
text_tab1 = it_new
|
||||
text_tab2 = it_old
|
||||
text_tab_res = lt_delta
|
||||
EXCEPTIONS
|
||||
parameter_invalid = 1
|
||||
difference_not_found = 2
|
||||
OTHERS = 3.
|
||||
|
||||
IF sy-subrc = 0.
|
||||
" Process delta
|
||||
LOOP AT lt_delta ASSIGNING <ls_delta>.
|
||||
CLEAR ls_diff.
|
||||
IF <ls_delta>-line1 > 0.
|
||||
ls_diff-old_num = lv_i = <ls_delta>-line1.
|
||||
ls_diff-old = <ls_delta>-text1.
|
||||
ENDIF.
|
||||
IF <ls_delta>-line2 > 0.
|
||||
ls_diff-new_num = lv_i = <ls_delta>-line2.
|
||||
ls_diff-new = <ls_delta>-text2.
|
||||
ENDIF.
|
||||
IF <ls_delta>-flag1 = 'D'.
|
||||
ls_diff-result = zif_abapgit_definitions=>c_diff-delete.
|
||||
ELSEIF <ls_delta>-flag2 = 'I'.
|
||||
ls_diff-result = zif_abapgit_definitions=>c_diff-insert.
|
||||
ELSEIF <ls_delta>-flag1 = 'M' AND <ls_delta>-flag2 = 'M'.
|
||||
ls_diff-result = zif_abapgit_definitions=>c_diff-update.
|
||||
ELSEIF <ls_delta>-flag1 = '' AND <ls_delta>-flag2 = ''.
|
||||
ls_diff-result = ''.
|
||||
ELSE.
|
||||
ASSERT 0 = 1. " unknown comparison result
|
||||
ENDIF.
|
||||
APPEND ls_diff TO rt_diff.
|
||||
ENDLOOP.
|
||||
ELSEIF sy-subrc = 2.
|
||||
" Identical input
|
||||
LOOP AT it_old ASSIGNING <ls_old>.
|
||||
CLEAR ls_diff.
|
||||
ls_diff-old_num = sy-tabix.
|
||||
ls_diff-old = <ls_old>.
|
||||
READ TABLE it_new ASSIGNING <ls_new> INDEX sy-tabix.
|
||||
ASSERT sy-subrc = 0.
|
||||
ls_diff-new_num = sy-tabix.
|
||||
ls_diff-new = <ls_new>.
|
||||
APPEND ls_diff TO rt_diff.
|
||||
ENDLOOP.
|
||||
ELSE.
|
||||
ASSERT 0 = 1. " incorrect function call
|
||||
ENDIF.
|
||||
|
||||
ENDMETHOD.
|
||||
|
||||
|
||||
METHOD constructor.
|
||||
|
||||
DATA: lt_delta TYPE vxabapt255_tab,
|
||||
lt_new TYPE abaptxt255_tab,
|
||||
lt_old TYPE abaptxt255_tab.
|
||||
DATA: lt_new TYPE rswsourcet,
|
||||
lt_old TYPE rswsourcet.
|
||||
|
||||
mv_compare_mode = 1.
|
||||
IF iv_ignore_indentation = abap_true.
|
||||
mv_compare_mode = mv_compare_mode + 1.
|
||||
ENDIF.
|
||||
IF iv_ignore_comments = abap_true.
|
||||
mv_compare_mode = mv_compare_mode + 2.
|
||||
ENDIF.
|
||||
mv_ignore_case = iv_ignore_case.
|
||||
|
||||
unpack( EXPORTING iv_new = iv_new
|
||||
iv_old = iv_old
|
||||
IMPORTING et_new = lt_new
|
||||
et_old = lt_old ).
|
||||
|
||||
lt_delta = compute( it_new = lt_new
|
||||
it_old = lt_old ).
|
||||
mt_diff = compute_and_render( it_new = lt_new
|
||||
it_old = lt_old ).
|
||||
|
||||
mt_diff = render( it_new = lt_new
|
||||
it_old = lt_old
|
||||
it_delta = lt_delta ).
|
||||
|
||||
calculate_line_num_and_stats( ).
|
||||
calculate_stats( ).
|
||||
map_beacons( ).
|
||||
shortlist( ).
|
||||
|
||||
|
@ -272,75 +304,6 @@ CLASS zcl_abapgit_diff IMPLEMENTATION.
|
|||
ENDMETHOD.
|
||||
|
||||
|
||||
METHOD render.
|
||||
|
||||
DATA: lv_oindex TYPE i VALUE 1,
|
||||
lv_nindex TYPE i VALUE 1,
|
||||
ls_new LIKE LINE OF it_new,
|
||||
ls_old LIKE LINE OF it_old,
|
||||
ls_diff LIKE LINE OF rt_diff,
|
||||
lt_delta LIKE it_delta,
|
||||
ls_delta LIKE LINE OF it_delta.
|
||||
|
||||
|
||||
lt_delta = it_delta.
|
||||
|
||||
DO.
|
||||
READ TABLE lt_delta INTO ls_delta WITH KEY number = lv_oindex.
|
||||
IF sy-subrc = 0.
|
||||
DELETE lt_delta INDEX sy-tabix.
|
||||
|
||||
CASE ls_delta-vrsflag.
|
||||
WHEN zif_abapgit_definitions=>c_diff-delete.
|
||||
ls_diff-new = ''.
|
||||
ls_diff-result = zif_abapgit_definitions=>c_diff-delete.
|
||||
ls_diff-old = ls_delta-line.
|
||||
|
||||
lv_oindex = lv_oindex + 1.
|
||||
WHEN zif_abapgit_definitions=>c_diff-insert.
|
||||
ls_diff-new = ls_delta-line.
|
||||
ls_diff-result = zif_abapgit_definitions=>c_diff-insert.
|
||||
ls_diff-old = ''.
|
||||
|
||||
lv_nindex = lv_nindex + 1.
|
||||
WHEN zif_abapgit_definitions=>c_diff-update.
|
||||
CLEAR ls_new.
|
||||
READ TABLE it_new INTO ls_new INDEX lv_nindex.
|
||||
ASSERT sy-subrc = 0.
|
||||
|
||||
ls_diff-new = ls_new.
|
||||
ls_diff-result = zif_abapgit_definitions=>c_diff-update.
|
||||
ls_diff-old = ls_delta-line.
|
||||
|
||||
lv_nindex = lv_nindex + 1.
|
||||
lv_oindex = lv_oindex + 1.
|
||||
WHEN OTHERS.
|
||||
ASSERT 0 = 1.
|
||||
ENDCASE.
|
||||
ELSE.
|
||||
CLEAR ls_new.
|
||||
READ TABLE it_new INTO ls_new INDEX lv_nindex. "#EC CI_SUBRC
|
||||
lv_nindex = lv_nindex + 1.
|
||||
CLEAR ls_old.
|
||||
READ TABLE it_old INTO ls_old INDEX lv_oindex. "#EC CI_SUBRC
|
||||
lv_oindex = lv_oindex + 1.
|
||||
|
||||
ls_diff-new = ls_new.
|
||||
ls_diff-result = ''.
|
||||
ls_diff-old = ls_old.
|
||||
ENDIF.
|
||||
|
||||
APPEND ls_diff TO rt_diff.
|
||||
CLEAR ls_diff.
|
||||
|
||||
IF lv_nindex > lines( it_new ) AND lv_oindex > lines( it_old ).
|
||||
EXIT.
|
||||
ENDIF.
|
||||
ENDDO.
|
||||
|
||||
ENDMETHOD.
|
||||
|
||||
|
||||
METHOD set_patch_by_old_diff.
|
||||
|
||||
FIELD-SYMBOLS: <ls_diff> TYPE zif_abapgit_definitions=>ty_diff.
|
||||
|
|
|
@ -18,7 +18,11 @@ CLASS ltcl_diff DEFINITION FOR TESTING
|
|||
iv_old TYPE zif_abapgit_definitions=>ty_diff-old.
|
||||
|
||||
METHODS: setup.
|
||||
METHODS: test.
|
||||
METHODS: test
|
||||
IMPORTING
|
||||
!iv_ignore_indentation TYPE abap_bool DEFAULT abap_false
|
||||
!iv_ignore_comments TYPE abap_bool DEFAULT abap_false
|
||||
!iv_ignore_case TYPE abap_bool DEFAULT abap_false.
|
||||
|
||||
METHODS:
|
||||
diff01 FOR TESTING,
|
||||
|
@ -26,7 +30,10 @@ CLASS ltcl_diff DEFINITION FOR TESTING
|
|||
diff03 FOR TESTING,
|
||||
diff04 FOR TESTING,
|
||||
diff05 FOR TESTING,
|
||||
diff06 FOR TESTING.
|
||||
diff06 FOR TESTING,
|
||||
diff07 FOR TESTING,
|
||||
diff08 FOR TESTING,
|
||||
diff09 FOR TESTING.
|
||||
|
||||
ENDCLASS.
|
||||
|
||||
|
@ -85,8 +92,12 @@ CLASS ltcl_diff IMPLEMENTATION.
|
|||
|
||||
CREATE OBJECT lo_diff
|
||||
EXPORTING
|
||||
iv_new = lv_xnew
|
||||
iv_old = lv_xold.
|
||||
iv_new = lv_xnew
|
||||
iv_old = lv_xold
|
||||
iv_ignore_indentation = iv_ignore_indentation
|
||||
iv_ignore_comments = iv_ignore_comments
|
||||
iv_ignore_case = iv_ignore_case.
|
||||
|
||||
|
||||
lt_diff = lo_diff->get( ).
|
||||
|
||||
|
@ -183,7 +194,7 @@ CLASS ltcl_diff IMPLEMENTATION.
|
|||
|
||||
METHOD diff06.
|
||||
|
||||
|
||||
" mixed
|
||||
add_new( iv_new = 'A' ).
|
||||
add_new( iv_new = 'B' ).
|
||||
add_new( iv_new = 'inserted' ).
|
||||
|
@ -225,4 +236,118 @@ CLASS ltcl_diff IMPLEMENTATION.
|
|||
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD diff07.
|
||||
|
||||
" ignore indentation
|
||||
add_new( iv_new = 'A' ).
|
||||
add_new( iv_new = ' B' ). " changed indent
|
||||
add_new( iv_new = 'C' ).
|
||||
add_new( iv_new = ' D' ). " changed indent
|
||||
|
||||
add_old( iv_old = 'A' ).
|
||||
add_old( iv_old = 'B' ).
|
||||
add_old( iv_old = 'C' ).
|
||||
add_old( iv_old = 'D' ).
|
||||
|
||||
add_expected( iv_new_num = ' 1'
|
||||
iv_new = 'A'
|
||||
iv_result = ''
|
||||
iv_old_num = ' 1'
|
||||
iv_old = 'A' ).
|
||||
add_expected( iv_new_num = ' 2'
|
||||
iv_new = ' B'
|
||||
iv_result = '' " no diff!
|
||||
iv_old_num = ' 2'
|
||||
iv_old = 'B' ).
|
||||
add_expected( iv_new_num = ' 3'
|
||||
iv_new = 'C'
|
||||
iv_result = ''
|
||||
iv_old_num = ' 3'
|
||||
iv_old = 'C' ).
|
||||
add_expected( iv_new_num = ' 4'
|
||||
iv_new = ' D'
|
||||
iv_result = '' " no diff!
|
||||
iv_old_num = ' 4'
|
||||
iv_old = 'D' ).
|
||||
|
||||
test( iv_ignore_indentation = abap_true ).
|
||||
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD diff08.
|
||||
|
||||
" ignore comments
|
||||
add_new( iv_new = 'A' ).
|
||||
add_new( iv_new = '* X' ). " changed comment
|
||||
add_new( iv_new = 'C' ).
|
||||
add_new( iv_new = 'D " new' ). " changed comment
|
||||
|
||||
add_old( iv_old = 'A' ).
|
||||
add_old( iv_old = '* B' ).
|
||||
add_old( iv_old = 'C' ).
|
||||
add_old( iv_old = 'D " old' ).
|
||||
|
||||
add_expected( iv_new_num = ' 1'
|
||||
iv_new = 'A'
|
||||
iv_result = ''
|
||||
iv_old_num = ' 1'
|
||||
iv_old = 'A' ).
|
||||
add_expected( iv_new_num = ' 2'
|
||||
iv_new = '* X'
|
||||
iv_result = '' " no diff!
|
||||
iv_old_num = ' 2'
|
||||
iv_old = '* B' ).
|
||||
add_expected( iv_new_num = ' 3'
|
||||
iv_new = 'C'
|
||||
iv_result = ''
|
||||
iv_old_num = ' 3'
|
||||
iv_old = 'C' ).
|
||||
add_expected( iv_new_num = ' 4'
|
||||
iv_new = 'D " new'
|
||||
iv_result = '' " no diff!
|
||||
iv_old_num = ' 4'
|
||||
iv_old = 'D " old' ).
|
||||
|
||||
test( iv_ignore_comments = abap_true ).
|
||||
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD diff09.
|
||||
|
||||
" ignore case
|
||||
add_new( iv_new = 'A' ).
|
||||
add_new( iv_new = 'b' ). " changed case
|
||||
add_new( iv_new = 'c' ).
|
||||
add_new( iv_new = 'D' ). " changed case
|
||||
|
||||
add_old( iv_old = 'A' ).
|
||||
add_old( iv_old = 'B' ).
|
||||
add_old( iv_old = 'c' ).
|
||||
add_old( iv_old = 'd' ).
|
||||
|
||||
add_expected( iv_new_num = ' 1'
|
||||
iv_new = 'A'
|
||||
iv_result = ''
|
||||
iv_old_num = ' 1'
|
||||
iv_old = 'A' ).
|
||||
add_expected( iv_new_num = ' 2'
|
||||
iv_new = 'b'
|
||||
iv_result = '' " no diff!
|
||||
iv_old_num = ' 2'
|
||||
iv_old = 'B' ).
|
||||
add_expected( iv_new_num = ' 3'
|
||||
iv_new = 'c'
|
||||
iv_result = ''
|
||||
iv_old_num = ' 3'
|
||||
iv_old = 'c' ).
|
||||
add_expected( iv_new_num = ' 4'
|
||||
iv_new = 'D'
|
||||
iv_result = '' " no diff!
|
||||
iv_old_num = ' 4'
|
||||
iv_old = 'd' ).
|
||||
|
||||
test( iv_ignore_case = abap_true ).
|
||||
|
||||
ENDMETHOD.
|
||||
|
||||
ENDCLASS.
|
||||
|
|
Loading…
Reference in New Issue
Block a user