diff --git a/src/ui/package.devc.xml b/src/ui/package.devc.xml
new file mode 100644
index 000000000..03346b167
--- /dev/null
+++ b/src/ui/package.devc.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+ UI
+
+
+
+
diff --git a/src/ui/zcl_abapgit_html.clas.abap b/src/ui/zcl_abapgit_html.clas.abap
new file mode 100644
index 000000000..898c45976
--- /dev/null
+++ b/src/ui/zcl_abapgit_html.clas.abap
@@ -0,0 +1,368 @@
+CLASS zcl_abapgit_html DEFINITION
+ PUBLIC
+ CREATE PUBLIC .
+
+ PUBLIC SECTION.
+
+ CONSTANTS c_indent_size TYPE i VALUE 2 ##NO_TEXT.
+
+ CLASS-METHODS class_constructor .
+ METHODS reset .
+ METHODS add
+ IMPORTING
+ !iv_chunk TYPE any .
+ METHODS render
+ IMPORTING
+ !iv_no_indent_jscss TYPE abap_bool OPTIONAL
+ RETURNING
+ VALUE(rv_html) TYPE string .
+ METHODS is_empty
+ RETURNING
+ VALUE(rv_yes) TYPE abap_bool .
+ METHODS add_a
+ IMPORTING
+ !iv_txt TYPE string
+ !iv_act TYPE string
+ !iv_typ TYPE char1 DEFAULT zif_abapgit_definitions=>gc_action_type-sapevent
+ !iv_opt TYPE clike OPTIONAL
+ !iv_class TYPE string OPTIONAL
+ !iv_id TYPE string OPTIONAL
+ !iv_style TYPE string OPTIONAL .
+ METHODS add_icon
+ IMPORTING
+ !iv_name TYPE string
+ !iv_hint TYPE string OPTIONAL
+ !iv_class TYPE string OPTIONAL .
+ CLASS-METHODS a
+ IMPORTING
+ !iv_txt TYPE string
+ !iv_act TYPE string
+ !iv_typ TYPE char1 DEFAULT zif_abapgit_definitions=>gc_action_type-sapevent
+ !iv_opt TYPE clike OPTIONAL
+ !iv_class TYPE string OPTIONAL
+ !iv_id TYPE string OPTIONAL
+ !iv_style TYPE string OPTIONAL
+ RETURNING
+ VALUE(rv_str) TYPE string .
+ CLASS-METHODS icon
+ IMPORTING
+ !iv_name TYPE string
+ !iv_hint TYPE string OPTIONAL
+ !iv_class TYPE string OPTIONAL
+ RETURNING
+ VALUE(rv_str) TYPE string .
+ PRIVATE SECTION.
+ CLASS-DATA: go_single_tags_re TYPE REF TO cl_abap_regex.
+
+ DATA: mt_buffer TYPE string_table.
+
+ TYPES:
+ BEGIN OF ty_indent_context,
+ no_indent_jscss TYPE abap_bool,
+ within_style TYPE abap_bool,
+ within_js TYPE abap_bool,
+ indent TYPE i,
+ indent_str TYPE string,
+ END OF ty_indent_context,
+
+ BEGIN OF ty_study_result,
+ style_open TYPE abap_bool,
+ style_close TYPE abap_bool,
+ script_open TYPE abap_bool,
+ script_close TYPE abap_bool,
+ tag_close TYPE abap_bool,
+ curly_close TYPE abap_bool,
+ openings TYPE i,
+ closings TYPE i,
+ singles TYPE i,
+ END OF ty_study_result.
+
+ METHODS indent_line
+ CHANGING
+ cs_context TYPE ty_indent_context
+ cv_line TYPE string.
+
+ METHODS study_line
+ IMPORTING iv_line TYPE string
+ is_context TYPE ty_indent_context
+ RETURNING VALUE(rs_result) TYPE ty_study_result.
+
+ENDCLASS.
+
+
+
+CLASS ZCL_ABAPGIT_HTML IMPLEMENTATION.
+
+
+ METHOD a.
+
+ DATA: lv_class TYPE string,
+ lv_href TYPE string,
+ lv_click TYPE string,
+ lv_id TYPE string,
+ lv_style TYPE string.
+
+ lv_class = iv_class.
+
+ IF iv_opt CA zif_abapgit_definitions=>gc_html_opt-strong.
+ lv_class = lv_class && ' emphasis' ##NO_TEXT.
+ ENDIF.
+ IF iv_opt CA zif_abapgit_definitions=>gc_html_opt-cancel.
+ lv_class = lv_class && ' attention' ##NO_TEXT.
+ ENDIF.
+ IF iv_opt CA zif_abapgit_definitions=>gc_html_opt-crossout.
+ lv_class = lv_class && ' crossout grey' ##NO_TEXT.
+ ENDIF.
+ IF lv_class IS NOT INITIAL.
+ SHIFT lv_class LEFT DELETING LEADING space.
+ lv_class = | class="{ lv_class }"|.
+ ENDIF.
+
+ lv_href = ' href="#"'. " Default, dummy
+ IF iv_act IS NOT INITIAL OR iv_typ = zif_abapgit_definitions=>gc_action_type-dummy.
+ CASE iv_typ.
+ WHEN zif_abapgit_definitions=>gc_action_type-url.
+ lv_href = | href="{ iv_act }"|.
+ WHEN zif_abapgit_definitions=>gc_action_type-sapevent.
+ lv_href = | href="sapevent:{ iv_act }"|.
+ WHEN zif_abapgit_definitions=>gc_action_type-onclick.
+ lv_href = ' href="#"'.
+ lv_click = | onclick="{ iv_act }"|.
+ WHEN zif_abapgit_definitions=>gc_action_type-dummy.
+ lv_href = ' href="#"'.
+ ENDCASE.
+ ENDIF.
+
+ IF iv_id IS NOT INITIAL.
+ lv_id = | id="{ iv_id }"|.
+ ENDIF.
+
+ IF iv_style IS NOT INITIAL.
+ lv_style = | style="{ iv_style }"|.
+ ENDIF.
+
+ rv_str = |{ iv_txt }|.
+
+ ENDMETHOD. "a
+
+
+ METHOD add.
+
+ DATA: lv_type TYPE c,
+ lo_html TYPE REF TO zcl_abapgit_html.
+
+ FIELD-SYMBOLS: TYPE string_table.
+
+ DESCRIBE FIELD iv_chunk TYPE lv_type. " Describe is faster than RTTI classes
+
+ CASE lv_type.
+ WHEN 'C' OR 'g'. " Char or string
+ APPEND iv_chunk TO mt_buffer.
+ WHEN 'h'. " Table
+ ASSIGN iv_chunk TO . " Assuming table of strings ! Will dump otherwise
+ APPEND LINES OF TO mt_buffer.
+ WHEN 'r'. " Object ref
+ ASSERT iv_chunk IS BOUND. " Dev mistake
+ TRY.
+ lo_html ?= iv_chunk.
+ CATCH cx_sy_move_cast_error.
+ ASSERT 1 = 0. " Dev mistake
+ ENDTRY.
+ APPEND LINES OF lo_html->mt_buffer TO mt_buffer.
+ WHEN OTHERS.
+ ASSERT 1 = 0. " Dev mistake
+ ENDCASE.
+
+ ENDMETHOD. " add
+
+
+ METHOD add_a.
+
+ add( a( iv_txt = iv_txt
+ iv_act = iv_act
+ iv_typ = iv_typ
+ iv_opt = iv_opt
+ iv_class = iv_class
+ iv_id = iv_id
+ iv_style = iv_style ) ).
+
+ ENDMETHOD. "add_a
+
+
+ METHOD add_icon.
+
+ add( icon( iv_name = iv_name
+ iv_class = iv_class
+ iv_hint = iv_hint ) ).
+
+ ENDMETHOD. "add_icon
+
+
+ METHOD class_constructor.
+ CREATE OBJECT go_single_tags_re
+ EXPORTING
+ pattern = '<(AREA|BASE|BR|COL|COMMAND|EMBED|HR|IMG|INPUT|LINK|META|PARAM|SOURCE|!)'
+ ignore_case = abap_false.
+ ENDMETHOD. "class_constructor
+
+
+ METHOD icon.
+
+ DATA: lv_hint TYPE string,
+ lv_name TYPE string,
+ lv_color TYPE string,
+ lv_class TYPE string.
+
+ SPLIT iv_name AT '/' INTO lv_name lv_color.
+
+ IF iv_hint IS NOT INITIAL.
+ lv_hint = | title="{ iv_hint }"|.
+ ENDIF.
+ IF iv_class IS NOT INITIAL.
+ lv_class = | { iv_class }|.
+ ENDIF.
+ IF lv_color IS NOT INITIAL.
+ lv_color = | { lv_color }|.
+ ENDIF.
+
+ rv_str = ||.
+
+ ENDMETHOD. "icon
+
+
+ METHOD indent_line.
+
+ DATA: ls_study TYPE ty_study_result,
+ lv_x_str TYPE string.
+
+ ls_study = study_line(
+ is_context = cs_context
+ iv_line = cv_line ).
+
+ " First closing tag - shift back exceptionally
+ IF ( ls_study-script_close = abap_true
+ OR ls_study-style_close = abap_true
+ OR ls_study-curly_close = abap_true
+ OR ls_study-tag_close = abap_true )
+ AND cs_context-indent > 0.
+ lv_x_str = repeat( val = ` ` occ = ( cs_context-indent - 1 ) * c_indent_size ).
+ cv_line = lv_x_str && cv_line.
+ ELSE.
+ cv_line = cs_context-indent_str && cv_line.
+ ENDIF.
+
+ " Context status update
+ CASE abap_true.
+ WHEN ls_study-script_open.
+ cs_context-within_js = abap_true.
+ cs_context-within_style = abap_false.
+ WHEN ls_study-style_open.
+ cs_context-within_js = abap_false.
+ cs_context-within_style = abap_true.
+ WHEN ls_study-script_close OR ls_study-style_close.
+ cs_context-within_js = abap_false.
+ cs_context-within_style = abap_false.
+ ls_study-closings = ls_study-closings + 1.
+ ENDCASE.
+
+ " More-less logic chosen due to possible double tags in a line ''
+ IF ls_study-openings <> ls_study-closings.
+ IF ls_study-openings > ls_study-closings.
+ cs_context-indent = cs_context-indent + 1.
+ ELSEIF cs_context-indent > 0. " AND ls_study-openings < ls_study-closings
+ cs_context-indent = cs_context-indent - 1.
+ ENDIF.
+ cs_context-indent_str = repeat( val = ` ` occ = cs_context-indent * c_indent_size ).
+ ENDIF.
+
+ ENDMETHOD. "indent_line
+
+
+ METHOD is_empty.
+ rv_yes = boolc( lines( mt_buffer ) = 0 ).
+ ENDMETHOD. "is_empty
+
+
+ METHOD render.
+
+ DATA: ls_context TYPE ty_indent_context,
+ lt_temp TYPE string_table.
+
+ FIELD-SYMBOLS: LIKE LINE OF lt_temp,
+ LIKE LINE OF lt_temp.
+
+ ls_context-no_indent_jscss = iv_no_indent_jscss.
+
+ LOOP AT mt_buffer ASSIGNING .
+ APPEND TO lt_temp ASSIGNING .
+ indent_line( CHANGING cs_context = ls_context cv_line = ).
+ ENDLOOP.
+
+ CONCATENATE LINES OF lt_temp INTO rv_html SEPARATED BY zif_abapgit_definitions=>gc_newline.
+
+ ENDMETHOD. "render
+
+
+ METHOD reset.
+ CLEAR me->mt_buffer.
+ ENDMETHOD. "reset
+
+
+ METHOD study_line.
+
+ DATA: lv_line TYPE string,
+ lv_len TYPE i.
+
+ lv_line = to_upper( shift_left( val = iv_line sub = ` ` ) ).
+ lv_len = strlen( lv_line ).
+
+ " Some assumptions for simplification and speed
+ " - style & scripts tag should be opened/closed in a separate line
+ " - style & scripts opening and closing in one line is possible but only once
+
+ " TODO & Issues
+ " - What if the string IS a well formed html already not just single line ?
+
+ IF is_context-within_js = abap_true OR is_context-within_style = abap_true.
+
+ IF is_context-within_js = abap_true AND lv_len >= 8 AND lv_line(8) = '= 7 AND lv_line(7) = '= 1 AND lv_line(1) = '}'.
+ rs_result-curly_close = abap_true.
+ ENDIF.
+
+ FIND ALL OCCURRENCES OF '{' IN lv_line MATCH COUNT rs_result-openings.
+ FIND ALL OCCURRENCES OF '}' IN lv_line MATCH COUNT rs_result-closings.
+ ENDIF.
+
+ ELSE.
+ IF lv_len >= 7 AND lv_line(7) = '= 7 AND lv_line(7) = '= 1 AND lv_line(1) = '}'.
- rs_result-curly_close = abap_true.
- ENDIF.
-
- FIND ALL OCCURRENCES OF '{' IN lv_line MATCH COUNT rs_result-openings.
- FIND ALL OCCURRENCES OF '}' IN lv_line MATCH COUNT rs_result-closings.
- ENDIF.
-
- ELSE.
- IF lv_len >= 7 AND lv_line(7) = '