; flat editor core ; Copyright (c) 1999-2015, Tomasz Grysztar. ; All rights reserved. set_text: push esi call reset_editor_memory pop esi mov ebx,[first_line] or esi,esi jz new_text_ok set_text_line: call set_line jc new_text_ok call allocate_segment mov [ebx],eax jc not_enough_memory mov ebx,eax mov eax,[caret_line] mov [ebx+4],eax mov [caret_line],ebx inc [lines_count] inc [caret_line_number] jmp set_text_line new_text_ok: xor eax,eax mov dword [ebx],eax inc eax mov [caret_line_number],eax mov eax,[first_line] mov [caret_line],eax mov [caret_position],0 retn put_character: call get_caret_segment inc [caret_position] put_here: cmp edx,SEGMENT_DATA_LENGTH jae put_after_line_end call store_segment_for_undo test [editor_mode],FEMODE_OVERWRITE jnz overwrite mov ah,[esi+SEGMENT_HEADER_LENGTH+edx] shl eax,8 mov al,ah insert_in_segment: lea ebx,[esi+SEGMENT_HEADER_LENGTH+edx] mov ecx,SEGMENT_DATA_LENGTH sub ecx,edx shift_data_right: xchg al,[ebx] inc ebx loop shift_data_right test byte [esi],1 jnz shift_next_segment_right cmp al,20h je put_ok add_segment: push eax call allocate_segment jc memory_shortage call store_allocated_segment_for_undo mov edi,eax or eax,1 xchg eax,[esi] stosd mov eax,esi or eax,1 stosd add edi,SEGMENT_HEADER_LENGTH - 8 pop eax stosb mov ecx,SEGMENT_DATA_LENGTH - 1 mov al,20h rep stosb jmp put_ok shift_next_segment_right: mov esi,[esi] dec esi call store_segment_for_undo xor edx,edx jmp insert_in_segment put_after_line_end: push eax call attach_empty_segments pop eax mov [esi+SEGMENT_HEADER_LENGTH+edx],al mov ah,20h shl eax,8 put_ok: test [editor_style],FES_AUTOBRACKETS jz insert_done shr eax,8 xchg ah,al call recognize_character jnc insert_done cmp ah,'(' je round cmp ah,'[' je square cmp ah,'{' je brace insert_done: retn round: mov al,')' jmp auto_bracket square: mov al,']' jmp auto_bracket brace: mov al,'}' auto_bracket: mov edx,[caret_position] mov esi,[caret_line] call find_segment jmp put_here overwrite: mov [esi+SEGMENT_HEADER_LENGTH+edx],al retn attach_empty_segments: call store_segment_for_undo attach_segment: push edx call allocate_segment jc memory_shortage call store_allocated_segment_for_undo pop edx mov ebx,esi mov esi,eax mov edi,eax or eax,1 xchg eax,[ebx] stosd mov eax,ebx or eax,1 stosd add edi,SEGMENT_HEADER_LENGTH - 8 mov ecx,SEGMENT_DATA_LENGTH shr 2 mov eax,20202020h rep stosd sub edx,SEGMENT_DATA_LENGTH cmp edx,SEGMENT_DATA_LENGTH jae attach_segment retn recognize_character: cmp al,20h jb neutral_character cmp al,30h jb separator_character cmp al,3Ah jb neutral_character cmp al,40h jb separator_character cmp al,5Bh jb neutral_character cmp al,5Fh jb separator_character cmp al,7Bh jb neutral_character cmp al,7Fh jb separator_character neutral_character: clc retn separator_character: stc retn delete_character: call get_caret_segment delete_here: cmp edx,SEGMENT_DATA_LENGTH jae delete_done call store_segment_for_undo test [editor_mode],FEMODE_OVERWRITE jnz blank lea ebx,[esi+SEGMENT_LENGTH] mov ecx,SEGMENT_DATA_LENGTH sub ecx,edx mov al,20h mov edi,[esi] test edi,1 jz shift_data_left mov al,[edi-1+SEGMENT_HEADER_LENGTH] shift_data_left: dec ebx xchg al,[ebx] loop shift_data_left lea esi,[edi-1] xor edx,edx test edi,1 jnz delete_here delete_done: retn blank: mov byte [esi+SEGMENT_HEADER_LENGTH+edx],20h retn tabulate: test [editor_style],FES_SMARTTABS jz standard_tab mov esi,[caret_line] mov esi,[esi+4] or esi,esi jz standard_tab mov edx,[caret_position] call find_segment cmp edx,SEGMENT_DATA_LENGTH jae standard_tab push 0 find_space: lea edi,[esi+SEGMENT_HEADER_LENGTH+edx] mov ecx,SEGMENT_DATA_LENGTH sub ecx,edx mov ebx,ecx mov al,20h repne scasb jne no_space_in_this_segment sub ebx,ecx dec ebx add edx,ebx add [esp],ebx call get_indent pop ecx or ebx,ebx jz standard_tab add ecx,ebx jmp insert_tab_spaces no_space_in_this_segment: pop ecx mov esi,[esi] btr esi,0 jnc standard_tab add ecx,SEGMENT_DATA_LENGTH sub ecx,edx xor edx,edx push ecx jmp find_space standard_tab: mov ecx,[caret_position] and ecx,not 111b sub ecx,[caret_position] add ecx,8 insert_tab_spaces: xor esi,esi push ecx call insert_into_line pop ecx add [caret_position],ecx retn carriage_return: xor ebx,ebx test [editor_style],FES_AUTOINDENT jz auto_indent_ok test [editor_mode],FEMODE_OVERWRITE jnz auto_indent_ok call get_caret_segment call get_indent add [caret_position],ebx mov esi,[caret_line] xor edx,edx call get_indent auto_indent_ok: call break_line retn get_indent: xor ebx,ebx find_indent_origin: cmp edx,SEGMENT_DATA_LENGTH jb find_indent mov esi,[esi] btr esi,0 jnc no_indent sub edx,SEGMENT_DATA_LENGTH jmp find_indent_origin find_indent: lea edi,[esi+SEGMENT_HEADER_LENGTH+edx] mov ecx,SEGMENT_DATA_LENGTH sub ecx,edx add ebx,ecx mov al,20h repe scasb je segment_indent sub ebx,ecx dec ebx retn segment_indent: xor edx,edx mov esi,[esi] btr esi,0 jc find_indent no_indent: xor ebx,ebx retn break_line: test [editor_mode],FEMODE_OVERWRITE jnz go_to_next_line push ebx call allocate_segment jc memory_shortage call store_allocated_segment_for_undo mov edi,eax mov eax,[caret_line] mov [edi+4],eax mov ebx,[esp] push edi add edi,SEGMENT_HEADER_LENGTH mov ecx,SEGMENT_DATA_LENGTH shr 2 mov eax,20202020h rep stosd call get_caret_segment call store_segment_for_undo mov edi,[esp] cmp edx,SEGMENT_DATA_LENGTH jae empty_new_line push esi edx new_line_segment: cmp ebx,SEGMENT_DATA_LENGTH jb new_line_segments_ok push edi ebx call allocate_segment jc memory_shortage call store_allocated_segment_for_undo mov esi,eax lea edi,[esi+SEGMENT_HEADER_LENGTH] mov ecx,SEGMENT_DATA_LENGTH shr 2 mov eax,20202020h rep stosd pop ebx edi sub ebx,SEGMENT_DATA_LENGTH mov eax,esi or eax,1 mov [edi],eax or edi,1 mov [esi+4],edi mov edi,esi jmp new_line_segment new_line_segments_ok: pop edx esi split_data: cmp ebx,edx jbe indent_data push esi edi mov ecx,SEGMENT_DATA_LENGTH sub ecx,ebx lea esi,[esi+SEGMENT_HEADER_LENGTH+edx] lea edi,[edi+SEGMENT_HEADER_LENGTH+ebx] add edx,ecx mov eax,ecx rep movsb mov edi,esi sub edi,eax mov ecx,eax mov al,20h rep stosb push edx call allocate_segment jc memory_shortage call store_allocated_segment_for_undo pop edx edi esi mov ebx,eax or eax,1 mov [edi],eax or edi,1 mov [ebx+4],edi mov edi,ebx xor ebx,ebx jmp split_data indent_data: push edi mov ecx,SEGMENT_DATA_LENGTH sub ecx,edx mov eax,ecx lea esi,[esi+SEGMENT_HEADER_LENGTH+edx] lea edi,[edi+SEGMENT_HEADER_LENGTH+ebx] rep movsb add ebx,eax mov edi,esi sub edi,eax mov ecx,eax mov al,20h rep stosb pop edi mov eax,[esp] xchg eax,[esi-SEGMENT_LENGTH] btr eax,0 jnc finish_new_line shift_splitted_data: mov esi,eax or eax,1 mov [edi],eax call store_segment_for_undo mov eax,edi or eax,1 mov [esi+4],eax mov ecx,SEGMENT_DATA_LENGTH sub ecx,ebx lea edi,[edi+SEGMENT_HEADER_LENGTH+ebx] add esi,SEGMENT_HEADER_LENGTH mov eax,esi rep movsb mov edi,eax mov ecx,ebx rep movsb sub edi,ebx sub edi,SEGMENT_HEADER_LENGTH mov eax,[edi] btr eax,0 jc shift_splitted_data finish_new_line: mov esi,edi call store_segment_for_undo mov [edi],eax pop esi or eax,eax jz new_line_pointers_ok xchg esi,eax call store_segment_for_undo xchg esi,eax mov [eax+4],esi new_line_pointers_ok: mov ecx,SEGMENT_DATA_LENGTH sub ecx,ebx lea edi,[edi+SEGMENT_HEADER_LENGTH+ebx] mov al,20h rep stosb xchg [caret_line],esi call check_line_length mov esi,[caret_line] mov dword [esi+8],0 call check_line_length inc [caret_line_number] inc [lines_count] pop [caret_position] retn empty_new_line: pop edi mov eax,[esi] mov [esi],edi mov [edi],eax or eax,eax jz empty_line_pointers_ok mov [eax+4],edi empty_line_pointers_ok: mov dword [edi+8],0 mov [caret_line],edi inc [caret_line_number] inc [lines_count] pop [caret_position] retn go_to_next_line: mov [caret_position],ebx mov esi,[caret_line] skip_line_segments: mov eax,[esi] btr eax,0 jnc line_segments_skipped mov esi,eax jmp skip_line_segments line_segments_skipped: or eax,eax jz no_next_line mov [caret_line],eax next_line_ok: inc [caret_line_number] retn no_next_line: call store_segment_for_undo call allocate_segment jc memory_shortage call store_allocated_segment_for_undo mov [esi],eax mov edi,eax xchg eax,[caret_line] mov [edi+4],eax xor eax,eax stosd add edi,4 stosd add edi,SEGMENT_HEADER_LENGTH - 12 mov ecx,SEGMENT_DATA_LENGTH shr 2 mov eax,20202020h rep stosd inc [lines_count] jmp next_line_ok cut_line_break: test [editor_mode],FEMODE_OVERWRITE jnz do_nothing call get_caret_segment cmp edx,SEGMENT_DATA_LENGTH jbe segment_for_deleting_ok call store_segment_for_undo add_empty_segment: push edx esi call allocate_segment jc memory_shortage call store_allocated_segment_for_undo pop ebx edx mov esi,eax mov edi,eax or eax,1 xchg eax,[ebx] stosd mov eax,ebx or eax,1 stosd add edi,SEGMENT_HEADER_LENGTH - 8 mov ecx,SEGMENT_DATA_LENGTH shr 2 mov eax,20202020h rep stosd sub edx,SEGMENT_DATA_LENGTH cmp edx,SEGMENT_DATA_LENGTH ja add_empty_segment segment_for_deleting_ok: call store_segment_for_undo mov edi,esi mov esi,[esi] btr esi,0 jc append_segment call cancel_line append_segment: or esi,esi jz fill_rest_with_spaces call store_segment_for_undo or byte [edi],1 lea eax,[edi+1] mov [esi+4],eax mov ecx,SEGMENT_DATA_LENGTH sub ecx,edx mov eax,ecx add esi,SEGMENT_HEADER_LENGTH lea edi,[edi+SEGMENT_HEADER_LENGTH+edx] rep movsb mov edi,esi sub edi,eax mov ecx,edx rep movsb sub esi,SEGMENT_LENGTH mov edi,esi mov esi,[esi] btr esi,0 jc append_segment fill_rest_with_spaces: lea edi,[edi+SEGMENT_HEADER_LENGTH+edx] mov ecx,SEGMENT_DATA_LENGTH sub ecx,edx mov al,20h rep stosb or esi,esi jz delete_done call store_segment_for_undo mov eax,[caret_line] mov [esi+4],eax do_nothing: retn cancel_line: dec [lines_count] mov eax,[esi+8] call unregister_length cmp esi,[window_line] jne window_line_ok mov eax,[caret_line] mov [window_line],eax mov eax,[caret_line_number] mov [window_line_number],eax window_line_ok: cmp esi,[first_line] jne first_line_ok mov eax,[caret_line] mov [first_line],eax first_line_ok: retn insert_into_line: or ecx,ecx jz void_insert push ecx esi call get_caret_segment test [editor_mode],FEMODE_OVERWRITE jnz overwrite_in_line cmp edx,SEGMENT_DATA_LENGTH jae attach_after_line_end mov eax,[esp+4] push edx xor edx,edx mov ecx,SEGMENT_DATA_LENGTH div ecx mov ebx,esi push esi or edx,edx jnz find_last_segment_to_shift call store_segment_for_undo mov esi,[esi] btr esi,0 jnc following_segments_shifted call store_segment_for_undo jmp following_segments_shifted find_last_segment_to_shift: test byte [ebx],1 jz shift_following_segments mov ebx,[ebx] dec ebx jmp find_last_segment_to_shift shift_following_segments: push edx call allocate_segment jc memory_shortage call store_allocated_segment_for_undo pop edx mov edi,eax mov esi,[ebx] mov [edi],esi mov eax,ebx or eax,1 mov [edi+4],eax lea edi,[edi+SEGMENT_HEADER_LENGTH+edx] mov ecx,SEGMENT_DATA_LENGTH sub ecx,edx mov al,20h rep stosb sub edi,SEGMENT_LENGTH carry_to_next_segment: mov esi,ebx call store_segment_for_undo mov eax,edi or eax,1 mov [esi],eax add esi,SEGMENT_LENGTH sub esi,edx mov ecx,edx add edi,SEGMENT_HEADER_LENGTH rep movsb cmp ebx,[esp] je following_segments_shifted mov edi,ebx mov ebx,[edi+4] btr ebx,0 push edi add edi,SEGMENT_LENGTH-1 mov esi,edi sub esi,edx mov ecx,SEGMENT_DATA_LENGTH sub ecx,edx std rep movsb cld pop edi jmp carry_to_next_segment following_segments_shifted: pop esi edx insert_more_segments: mov edi,esi mov ecx,[esp+4] make_inserted_segment: sub ecx,SEGMENT_DATA_LENGTH jb fill_inserted_segments push ecx edx call allocate_segment jc memory_shortage call store_allocated_segment_for_undo pop edx ecx mov ebx,[edi] btr ebx,0 jnc make_attached_segment or eax,1 mov [edi],eax mov [ebx+4],eax and eax,not 1 or ebx,1 mov [eax],ebx or edi,1 mov [eax+4],edi mov edi,eax jmp make_inserted_segment make_attached_segment: or eax,1 mov [edi],eax and eax,not 1 mov [eax],ebx or edi,1 mov [eax+4],edi mov edi,eax jmp make_inserted_segment fill_inserted_segments: mov eax,SEGMENT_DATA_LENGTH add ecx,eax sub eax,edx sub eax,ecx jbe all_shifts_done mov ecx,eax lea edi,[edi+SEGMENT_LENGTH-1] push esi lea esi,[esi+SEGMENT_HEADER_LENGTH+ecx-1] add esi,edx std rep movsb cld pop esi all_shifts_done: mov edi,esi pop esi ebx fill_new_segment: mov ecx,SEGMENT_DATA_LENGTH sub ecx,edx cmp ecx,ebx jbe length_for_inserting_ok mov ecx,ebx length_for_inserting_ok: sub ebx,ecx push edi lea edi,[edi+SEGMENT_HEADER_LENGTH+edx] or esi,esi jz insert_blank_string rep movsb jmp string_inserted insert_blank_string: mov al,20h rep stosb string_inserted: pop edi mov edi,[edi] and edi,not 1 xor edx,edx or ebx,ebx jnz fill_new_segment retn attach_after_line_end: call attach_empty_segments mov ebx,esi pop esi or esi,esi jnz attach_string pop ecx retn attach_string: mov ecx,[esp] mov eax,SEGMENT_DATA_LENGTH sub eax,edx cmp eax,ecx jae length_to_attach_ok mov ecx,eax length_to_attach_ok: sub [esp],ecx lea edi,[ebx+SEGMENT_HEADER_LENGTH+edx] rep movsb mov ecx,[esp] jecxz attach_ok call allocate_segment jc memory_shortage call store_allocated_segment_for_undo mov edi,eax or eax,1 xchg eax,[ebx] mov [edi],eax or ebx,1 mov [edi+4],ebx mov ebx,edi xor edx,edx jmp attach_string attach_ok: pop eax lea ecx,[ebx+SEGMENT_LENGTH] sub ecx,edi mov al,20h rep stosb void_insert: retn overwrite_in_line: cmp edx,SEGMENT_DATA_LENGTH jb position_for_overwrite_ok call attach_empty_segments position_for_overwrite_ok: mov edi,esi pop esi ebx overwrite_segment: xchg esi,edi call store_segment_for_undo xchg esi,edi mov ecx,SEGMENT_DATA_LENGTH sub ecx,edx cmp ecx,ebx jbe length_to_overwrite_ok mov ecx,ebx length_to_overwrite_ok: sub ebx,ecx push edi lea edi,[edi+SEGMENT_HEADER_LENGTH+edx] or esi,esi jz overwrite_with_blank rep movsb jmp overwritten_ok overwrite_with_blank: mov al,20h rep stosb overwritten_ok: pop edi or ebx,ebx jz overwrite_done push esi mov esi,[edi] btr esi,0 jc overwrite_existing_segment call allocate_segment jc memory_shortage call store_allocated_segment_for_undo mov edx,eax or edx,1 mov [edi],edx mov [eax],esi or edi,1 mov [eax+4],edi mov edi,eax pop esi xor edx,edx cmp ebx,SEGMENT_DATA_LENGTH jae overwrite_segment mov ecx,SEGMENT_DATA_LENGTH sub ecx,ebx lea edi,[edi+SEGMENT_HEADER_LENGTH+ebx] mov al,20h rep stosb sub edi,SEGMENT_LENGTH jmp overwrite_segment overwrite_existing_segment: call store_segment_for_undo mov edi,esi xor edx,edx pop esi jmp overwrite_segment overwrite_done: retn delete_from_line: or ecx,ecx jz nothing_to_delete test [editor_mode],FEMODE_OVERWRITE jnz clear_in_line push ecx add [caret_position],ecx call get_caret_segment pop ecx sub [caret_position],ecx cmp edx,SEGMENT_DATA_LENGTH jae clear_rest_of_line push esi edx call get_caret_segment call store_segment_for_undo mov edi,esi mov ebx,edx pop edx esi shift_over_deleted: mov ecx,SEGMENT_DATA_LENGTH mov eax,ecx sub ecx,ebx sub eax,edx cmp eax,ecx jae size_to_shift_ok mov ecx,eax size_to_shift_ok: push esi edi lea esi,[esi+SEGMENT_HEADER_LENGTH+edx] lea edi,[edi+SEGMENT_HEADER_LENGTH+ebx] add edx,ecx add ebx,ecx rep movsb pop edi cmp ebx,SEGMENT_DATA_LENGTH je next_destination_segment pop esi cmp edx,SEGMENT_DATA_LENGTH jne shift_over_deleted mov esi,[esi] btr esi,0 jnc cut_line xor edx,edx jmp shift_over_deleted next_destination_segment: mov esi,[edi] btr esi,0 call store_segment_for_undo mov edi,esi pop esi xor ebx,ebx jmp shift_over_deleted cut_line: mov esi,edi mov edx,ebx jmp clear_from_here clear_in_line: xor esi,esi jmp insert_into_line clear_rest_of_line: call get_caret_segment cmp edx,SEGMENT_DATA_LENGTH jae no_line_tail_to_clear call store_segment_for_undo clear_from_here: lea edi,[esi+SEGMENT_HEADER_LENGTH+edx] mov ecx,SEGMENT_DATA_LENGTH sub ecx,edx mov al,20h rep stosb mov ebx,esi mov esi,[ebx] remove_following_segments: btr esi,0 jnc rest_of_line_cleared call store_freed_segment_for_undo mov esi,[esi] jmp remove_following_segments rest_of_line_cleared: mov [ebx],esi nothing_to_delete: retn no_line_tail_to_clear: mov esi,[esi] retn remove_line: mov esi,[caret_line] mov esi,[esi] or esi,esi jnz cut_extra_segments mov edi,[caret_line] add edi,SEGMENT_HEADER_LENGTH mov ecx,SEGMENT_DATA_LENGTH mov al,20h repe scasb je line_removed cut_extra_segments: btr esi,0 jnc replace_with_next_line call store_freed_segment_for_undo mov esi,[esi] jmp cut_extra_segments replace_with_next_line: or esi,esi jz clear_current_line call store_segment_for_undo mov ebx,esi xchg esi,[caret_line] mov eax,[esi+4] mov [ebx+4],eax call store_freed_segment_for_undo call cancel_line mov esi,[esi+4] or esi,esi jz line_removed find_last_segment_of_previous_line: mov eax,[esi] btr eax,0 jnc link_to_new_next_line mov esi,eax jmp find_last_segment_of_previous_line link_to_new_next_line: call store_segment_for_undo mov [esi],ebx line_removed: mov [caret_position],0 mov [selection_line],0 retn clear_current_line: mov esi,[caret_line] call store_segment_for_undo mov dword [esi],0 lea edi,[esi+SEGMENT_HEADER_LENGTH] mov ecx,SEGMENT_DATA_LENGTH mov al,20h rep stosb jmp line_removed duplicate_line: call allocate_segment jc memory_shortage call store_allocated_segment_for_undo mov esi,[caret_line] mov edi,eax mov [edi+4],esi mov eax,[esi+8] mov [edi+8],eax call register_length push edi duplicate_segment: mov ebx,edi add edi,SEGMENT_HEADER_LENGTH add esi,SEGMENT_HEADER_LENGTH mov ecx,SEGMENT_DATA_LENGTH rep movsb sub esi,SEGMENT_LENGTH mov eax,[esi] btr eax,0 jnc all_segments_duplicated mov esi,eax call allocate_segment jc memory_shortage call store_allocated_segment_for_undo mov edi,eax or eax,1 mov [ebx],eax or ebx,1 mov [edi+4],ebx jmp duplicate_segment all_segments_duplicated: inc [lines_count] call store_segment_for_undo mov [ebx],eax pop ebx mov [esi],ebx mov esi,eax or esi,esi jz duplicate_done call store_segment_for_undo mov [esi+4],ebx duplicate_done: retn finish_edit: mov esi,[caret_line] call check_line_length retn