;-------------------------------------------
; Assembly Editor for Win32
; Copyright (c) 2001-2002, Tomasz Grysztar.
; All rights reserved.
;-------------------------------------------

iglobal
  cAsmEditClassName   du  'ASMEDIT'
  .length = ($ - cAsmEditClassName)/2     ; the length in chars.
                      du  0

  wheel_scroll_lines  dd    3             ; this is the number of lines to scroll with mouse wheel.
endg


;uglobal
;  case_table   rb 100h
;endg



;-------------------------------------------
; Registers AsmEdit control class.
; Call only once in application.
;-------------------------------------------
initialize RegisterAsmEditClass

.ae WNDCLASS

begin
        mov     [.ae.style], CS_GLOBALCLASS or CS_DBLCLKS
        mov     [.ae.lpfnWndProc], AsmEdit
        mov     eax,[hInstance]
        mov     [.ae.hInstance],eax
        mov     [.ae.hbrBackground],0
        xor     eax,eax
        mov     [.ae.cbClsExtra],eax
        mov     [.ae.cbWndExtra], $10
        mov     [.ae.lpszMenuName],eax
        mov     [.ae.lpszClassName], cAsmEditClassName
        mov     [.ae.hIcon], eax
        mov     [.ae.hCursor],0         ; If Window procedure handles WM_SETCURSOR, this should be NULL
        lea     eax, [.ae]
        invoke  RegisterClassW, eax
        or      eax,eax
        jz      .failed

        push    ebx esi edi

;        mov     edi,case_table
;        xor     ebx,ebx
;        mov     esi,100h
;
;    .make_case_table:
;        invoke  CharLowerA,ebx
;        stosb
;        inc     bl
;        dec     esi
;        jnz     .make_case_table

        pop     edi esi ebx

        xor     eax,eax
        jmp     .finish

.failed:
        mov     eax,1
.finish:
        return
endp


;----------------------------------------------
; AsmEdit window proc
;----------------------------------------------
proc AsmEdit, .hwnd, .wmsg, .wparam, .lparam

  .editor_memory dd ?
  .editor_style dd ?

  .editor_data:

  .first_line dd ?
  .lines_count dd ?
  .caret_line dd ?
  .caret_position dd ?
  .caret_line_number dd ?
  .window_line dd ?
  .window_position dd ?
  .window_line_number dd ?
  .sel_line dd ?
  .sel_position dd ?
  .sel_line_number dd ?
  .editor_mode dd ?
  .line_to_draw dd ?
  .Modified  dd ?

  .editor_status_size = $ - .editor_data

  .editor_font dd ?
  .font_width dd ?
  .font_height dd ?
  .page_size dd ?
  .editor_screen dd ?
  .screen_width_bytes dd ?
  .screen_width dd ?
  .screen_height dd ?
  .background_color dd ?
  .text_color dd ?
  .selection_background dd ?
  .selection_text dd ?
  .margin_background dd ?
  .margin_border dd ?
  .margin_width dd ?
  .margin_gap dd ?
  .focus_fg dd ?
  .focus_bg dd ?
  .read_only_bg dd ?
  .read_only_fg dd ?
  .syntax_proc dd ?
  .syntax_colors dd ?
  .unallocated_lines dd ?
  .unallocated_lines_end dd ?
  .memory_search_block dd ?
  .memory_search_line dd ?
  .undo_data dd ?
  .search_text dd ?
  .caret_x dd ?
  .caret_y dd ?
  .caret_changed dd ?
  .PopupMenu dd ?
  .read_only dd ?
  .focus_line dd ?

  .bookmark_count = 10
  .bookmarks rd .bookmark_count
  .bookmark_icon dd ?

  .current_operation db ?
  .last_operation db ?
  .mouse_select db ?
  .focus db ?

  .editor_data_size = $ - .editor_data

  .current_line dd ?
  .return_value dd ?
  .background_brush dd ?
  .focus_brush dd ?

  .selection_brush dd ?
  .margin_brush dd ?
  .marginb_brush dd ?
  .bookmark_brush dd ?
  .was_selection db ?
  .line_selection db ?
  .redraw_now db ?
  .notification db ?

; moved from global to local - 12.08.2003 johnfound
  .sc   SCROLLINFO
  .ps   PAINTSTRUCT
  .tm   TEXTMETRIC
  .rect RECT
  .rc   RECT
  .pt   POINT

  .sz   SIZE
  rb 16

  .char         rw 4
  .kbstate      rb 100h

  .line_colors  rb aeLineDataLen
  .line_buffer  rb aeLineDataLen
  .text_buffer  rb aeLineDataLen
;  .param_buffer rd 10h

begin
        push    ebx esi edi

        invoke  GetWindowLongW, [.hwnd], GWL_STYLE
        mov     [.editor_style],eax
        cmp     [.wmsg], WM_CREATE
        je      .wmcreate
        cmp     [.wmsg], WM_GETDLGCODE
        je      .wmgetdlgcode
        invoke  GetWindowLongW, [.hwnd], ofsAsmEditMemory
        or      eax,eax
        jz      .defwndproc
        mov     [.editor_memory],eax
        lea     esi,[eax+8]
        lea     edi,[.editor_data]
        mov     ecx,.editor_data_size shr 2
        rep     movsd
        mov     [.return_value],0
        mov     [.notification],0
        mov     [.redraw_now],0
        cmp     [.wmsg],WM_DESTROY
        je      .wmdestroy
        cmp     [.wmsg],WM_PAINT
        je      .wmpaint

        cmp     [.wmsg],WM_HSCROLL
        je      .wmhscroll
        cmp     [.wmsg],WM_VSCROLL
        je      .wmvscroll
        cmp     [.wmsg],WM_SIZE
        je      .wmsize
        cmp     [.sel_line],0
        setnz   al
        mov     [.was_selection],al
        xor     al,al
        xchg    [.current_operation],al
        mov     [.last_operation],al
        mov     eax,[.wmsg]
        cmp     eax,WM_SETFOCUS
        je      .wmsetfocus
        cmp     eax,WM_KILLFOCUS
        je      .wmkillfocus
        cmp     eax,WM_LBUTTONDOWN
        je      .wmlbuttondown
        cmp     eax,WM_LBUTTONUP
        je      .wmlbuttonup
        cmp     eax,WM_RBUTTONDOWN
        je      .wmrbuttondown
        cmp     eax,WM_RBUTTONUP
        je      .wmrbuttonup
        cmp     eax,WM_MOUSEMOVE
        je      .wmmousemove
        cmp     eax,WM_LBUTTONDBLCLK
        je      .wmlbuttondblclk
        cmp     eax,WM_MOUSEWHEEL
        je      .wmmousewheel
        cmp     eax,WM_COPY
        je      .wmcopy

        cmp     eax,WM_SYSKEYDOWN
        je      .wmsyskeydown
        cmp     eax,WM_KEYDOWN
        je      .wmkeydown

        mov     ecx, [.caret_line_number]
        cmp     ecx, [.read_only]
        jbe     .dont_process               ; Added Tommy Lillehagen 31.01.2004

        cmp     eax,WM_CHAR
        je      .wmchar
        cmp     eax,WM_CUT
        je      .wmcut
        cmp     eax,WM_PASTE
        je      .wmpaste
        cmp     eax,WM_CLEAR
        je      .wmclear
        cmp     eax,WM_SETTEXT
        je      .wmsettext
        cmp     eax,WM_UNDO
        je      .wmundo
        cmp     eax,EM_UNDO
        je      .wmundo
        cmp     eax,EM_REPLACESEL
        je      .emreplacesel
        cmp     eax,AEM_COMMENT
        je      .aemcomment
        cmp     eax,AEM_INDENT
        je      .aemindent
    .dont_process:

        cmp     eax,WM_GETTEXTLENGTH
        je      .wmgettextlength
        cmp     eax,WM_GETTEXT
        je      .wmgettext
        cmp     eax,WM_SETFONT
        je      .wmsetfont
        cmp     eax,WM_GETFONT
        je      .wmgetfont
        cmp     eax,WM_CONTEXTMENU
        je      .wmrbuttonup
        cmp     eax,EM_CANUNDO
        je      .emcanundo
        cmp     eax,EM_EMPTYUNDOBUFFER
        je      .ememptyundobuffer
        cmp     eax,AEM_SETMODE
        je      .aemsetmode
        cmp     eax,AEM_GETMODE
        je      .aemgetmode
        cmp     eax, AEM_GETMODIFIED            ; John Found 25.11.2003
        je      .aemgetmodified
        cmp     eax, AEM_SETMODIFIED
        je      .aemsetmodified
        cmp     eax,AEM_SETSYNTAXHIGHLIGHT
        je      .aemsetsyntaxhighlight
        cmp     eax, AEM_GETLINEPTR
        je      .aemgetlineptr
        cmp     eax,AEM_GETLINEDATA
        je      .aemgetlinedata
        cmp     eax, AEM_SETLINEDATA
        je      .aemsetlinedata
        cmp     eax,AEM_SETPOS
        je      .aemsetpos
        cmp     eax,AEM_GETPOS
        je      .aemgetpos
        cmp     eax, AEM_GETCARETXY     ; Added john found 06.01.2004
        je      .amgetcaretxy
        cmp     eax,AEM_FINDFIRST
        je      .aemfindfirst
        cmp     eax,AEM_FINDNEXT
        je      .aemfindnext
        cmp     eax,AEM_CANFINDNEXT
        je      .aemcanfindnext
        cmp     eax,AEM_GETWORDATCARET
        je      .aemgetwordatcaret
        cmp     eax,AEM_SETTEXTCOLOR
        je      .aemsettextcolor
        cmp     eax,AEM_SETSELCOLOR
        je      .aemsetselcolor
        cmp     eax,AEM_SETPOPUPMENU
        je      .aemsetpopupmenu
        cmp     eax,AEM_SETMARGINCOLOR
        je      .aemsetmargincolor
        cmp     eax,AEM_SETMARGINWIDTH
        je      .aemsetmarginwidth
        cmp     eax,AEM_SETTHEME
        je      .aemsettheme
        cmp     eax,AEM_TOGGLEBOOKMARK
        je      .aemtogglebookmark
        cmp     eax,AEM_GOTOBOOKMARK
        je      .aemgotobookmark
        cmp     eax,AEM_CLEARBOOKMARKS
        je      .aemclearbookmarks
        cmp     eax,AEM_SETBOOKMARKICON
        je      .aemsetbookmarkicon
        cmp     eax,AEM_READONLY                ; Added Tommy Lillehagen 30.01.2004
        je      .aemreadonly
        cmp     eax,AEM_SETFOCUSLINE            ; Added Tommy Lillehagen 30.01.2004
        je      .aemsetfocusline


.defwndproc:
        invoke  DefWindowProcW,[.hwnd],[.wmsg],[.wparam],[.lparam]
        jmp     .finish

.wmcreate:
        call    .init_editor_memory
        jc      .create_failed
        call    .init_editor_data
        invoke  SetWindowLongW, [.hwnd], ofsAsmEditMemory, [.editor_memory]

        invoke  GetSysColor,COLOR_WINDOW
        mov     [.background_color],eax
        mov     [.margin_background],eax
        mov     [.margin_border],eax
        mov     [.read_only_bg], eax

        invoke  GetSysColor,COLOR_WINDOWTEXT
        mov     [.text_color],eax
        mov     [.read_only_fg], eax

        invoke  GetSysColor,COLOR_HIGHLIGHT
        mov     [.selection_background],eax
        mov     [.focus_bg],eax

        invoke  GetSysColor,COLOR_HIGHLIGHTTEXT
        mov     [.selection_text], eax
        mov     [.focus_fg], eax

        invoke  GetStockObject, SYSTEM_FIXED_FONT
        mov     [.editor_font], eax

        invoke  GetDC,[.hwnd]
        mov     ebx,eax
        invoke  SelectObject,ebx,[.editor_font]

        lea     eax, [.tm]
        invoke  GetTextMetricsW, ebx, eax

        mov     eax,[.tm.tmHeight]
        test    eax, eax
        jnz     @f
        inc     eax
@@:
        mov     [.font_height],eax

; This is dirty hack!!!
        lea     eax, [.sz]
        invoke  GetTextExtentPoint32W, ebx, cProbeText8, 8, eax
        mov     eax, [.sz.cx]
        sar     eax, 3

;        mov     eax,[.tm.tmAveCharWidth]
        test    eax, eax
        jnz     @f
        inc     eax
@@:
        mov     [.font_width],eax
        invoke  ReleaseDC,[.hwnd],ebx
        call    .update_positions
        call    .update_screen

        mov     [.PopupMenu], NULL
        mov     [.Modified], FALSE
        mov     [.bookmark_icon], NULL

        call    .clear_marks

        mov     [.margin_width],1
        mov     [.margin_gap],0
        mov     [.return_value],0
        mov     [.read_only], 0
        mov     [.focus_line],0
        jmp     .done

    .create_failed:
        or      eax,-1
        jmp     .finish


;----------- WM_DESTROY --------------------

.wmdestroy:
        stdcall FreeMem, [.editor_screen]

        call    .release_editor_memory

        invoke  SetWindowLongW,[.hwnd], ofsAsmEditMemory, 0
        xor     eax,eax
        jmp     .finish

.wmgetdlgcode:
        mov     eax, DLGC_WANTCHARS or DLGC_WANTARROWS or DLGC_WANTTAB
        mov     ecx, [.lparam]
        test    ecx, ecx
        jz      .finish

        cmp     [ecx+MSG.message], WM_KEYDOWN
        jne     .finish

        cmp     [ecx+MSG.wParam], VK_RETURN
        jne     .finish

        or      eax, DLGC_WANTMESSAGE
        jmp     .finish


;----------- WM_PAINT ----------------------
.wmpaint:
        lea     eax,[.rect]
        invoke  GetUpdateRect,[.hwnd],eax,FALSE
        or      eax,eax
        jz      .finish

        cmp     [.editor_screen],0
        je      .finish

        lea     eax, [.ps]
        invoke  BeginPaint,[.hwnd],eax
        mov     ebx,eax

        invoke  CreateSolidBrush, [.background_color]
        mov     [.background_brush],eax

        invoke  CreateSolidBrush, [.selection_background]
        mov     [.selection_brush], eax

        invoke  CreateSolidBrush,[.focus_bg]
        mov     [.focus_brush],eax

        push    [.rect.right]
        call    .paint_marks
        pop     eax

        cmp     eax, [.margin_width]
        jbe     .end_paint_free

        invoke  SelectObject,ebx,[.editor_font]

        mov     esi, [.editor_screen]                    ; characters
        mov     eax, [.screen_width]
        mul     [.screen_height]

        lea     edi, [esi + aeCharSize*eax]              ; colors

        mov     [.rect.top],0
        mov     eax,[.font_height]
        mov     [.rect.bottom],eax
        mov     ecx,[.screen_height]
        mov     eax,[.window_line_number]
        dec     eax
        mov     [.line_to_draw], eax

    .paint_screen:

        push    ecx
        inc     [.line_to_draw]

        mov     eax, [.margin_width]
        mov     [.rect.left], eax
        mov     ecx, [.screen_width]

    .paint_line:

        cmp     word [esi], 0
        je      .paint_empty_block

        mov     edx, 1
        mov     ax, [edi]   ; color word

    .get_characters_block:
        cmp     edx, ecx
        je      .get_color

        cmp     ax, [edi + aeCharSize * edx]    ; color
        jne     .get_color

        cmp     word [esi + aeCharSize * edx], 0 ; text at line ends here
        je      .get_color

        inc     edx
        jmp     .get_characters_block

    .paint_empty_block:
        mov     edx, 1
        test    word [edi], 80h
        jnz     .get_empty_selection

    .get_empty_block:
        cmp     edx, ecx
        je      .fill_empty_block

        cmp     word [esi+ aeCharSize * edx], 0
        jne     .fill_empty_block

        test    word [edi+ aeCharSize * edx], 80h
        jnz     .fill_empty_block

        inc     edx
        jmp     .get_empty_block

    .fill_empty_block:

        push    ecx edx
        mov     eax,[.font_width]
        mul     edx
        add     eax,[.rect.left]
        mov     [.rect.right],eax

        mov     eax, [.focus_line]

        mov     ecx, [.background_brush]
        cmp     eax, [.line_to_draw]
        jne     .brush_ok
        mov     ecx, [.focus_brush]

.brush_ok:
        lea     eax, [.rect]
        invoke  FillRect, ebx, eax, ecx
        jmp     .paint_next_block

    .get_empty_selection:

        cmp     edx, ecx
        je      .fill_empty_selection

        cmp     word [esi + aeCharSize * edx], 0
        jne     .fill_empty_selection

        test    word [edi + aeCharSize * edx], 80h
        jz      .fill_empty_selection

        inc     edx
        jmp     .get_empty_selection

    .fill_empty_selection:

        push    ecx edx

        mov     eax, [.font_width]
        mul     edx                     ;
        add     eax, [.rect.left]       ;
        mov     [.rect.right], eax      ; rect.right = EndSelX * font_width + rect.left

        lea     eax, [.rect]
        invoke  FillRect, ebx, eax, [.selection_brush]
        jmp     .paint_next_block

    .get_color:
        push    ecx edx

        mov     eax, [.line_to_draw]
        cmp     eax, [.focus_line]
        je      .focusline_color

        cmp     eax, [.read_only]
        jbe     .read_only_color

        test    word [edi], 80h
        jnz     .highlight_color

        invoke  SetBkColor, ebx, [.background_color]

        mov     ax, [edi]
        or      ax, ax
        jnz     .syntax_color

    .default_color:
        invoke  SetTextColor, ebx, [.text_color]
        jmp     .color_ok

    .syntax_color:
        movzx   eax, ax
        mov     edx, [.syntax_colors]
        or      edx, edx
        jz      .default_color

        mov     eax, [edx + (eax-1)*4]

        invoke  SetTextColor, ebx, eax
        jmp     .color_ok

    .highlight_color:

        invoke  SetBkColor, ebx, [.selection_background]
        invoke  SetTextColor, ebx, [.selection_text]
        jmp     .color_ok

    .read_only_color:

        invoke  SetBkColor, ebx, [.read_only_bg]
        invoke  SetTextColor, ebx, [.read_only_fg]
        jmp     .color_ok

    .focusline_color:
        invoke  SetBkColor, ebx, [.focus_bg]
        invoke  SetTextColor, ebx, [.focus_fg]

    .color_ok:
        mov     ecx, [esp]              ; current X position.
        mov     eax, [.font_width]
        mul     ecx
        add     eax, [.rect.left]
        mov     [.rect.right], eax

        lea     eax, [.rect]
        invoke  DrawTextW, ebx, esi, ecx, eax, DT_LEFT or DT_NOPREFIX or DT_SINGLELINE or DT_NOCLIP

    .paint_next_block:
        pop     edx ecx

        sub     ecx, edx

        lea     esi, [esi + aeCharSize * edx]
        lea     edi, [edi + aeCharSize * edx]

        mov     eax, [.rect.right]
        mov     [.rect.left], eax

        or      ecx, ecx
        jnz     .paint_line

        mov     eax, [.font_height]
        add     [.rect.top],eax
        add     [.rect.bottom],eax
        pop     ecx
        dec     ecx
        jnz     .paint_screen

.end_paint_free:
        invoke  DeleteObject,[.background_brush]
        invoke  DeleteObject,[.selection_brush]
        invoke  DeleteObject,[.focus_brush]

.end_paint:
        lea     eax, [.ps]
        invoke  EndPaint,[.hwnd],eax

        xor     eax,eax
        jmp     .finish


; paints the bookmarks and the left margin. Call it only from WM_PAINT message.

.paint_marks:
        xor     eax, eax
        mov     [.rect.left], eax

        lea     eax, [.rect]
        invoke  GetClientRect, [.hwnd], eax

        mov     eax,[.margin_width]
        sub     eax,[.margin_gap]
        mov     [.rect.right], eax

        cmp     [.margin_gap],0
        je      .fill_margin

        invoke  CreateSolidBrush,[.margin_background]
        mov     [.margin_brush],eax

        lea     eax,[.rect]
        invoke  FillRect,ebx,eax,[.margin_brush]

        invoke  DeleteObject,[.margin_brush]

        mov     eax,[.rect.right]
        mov     [.rect.left],eax
        inc     [.rect.right]

        invoke  CreateSolidBrush, [.margin_border]
        mov     [.marginb_brush],eax

        lea     eax,[.rect]
        invoke  FillRect,ebx,eax,[.marginb_brush]

        invoke  DeleteObject,[.marginb_brush]

  .fill_margin:
        mov     eax,[.rect.right]
        mov     [.rect.left],eax
        mov     eax,[.margin_gap]
        dec     eax
        add     [.rect.right],eax

        lea     eax,[.rect]
        invoke  FillRect, ebx, eax, [.background_brush]

        xor     eax,eax
        mov     [.rc.left],eax
        mov     eax,[.margin_width]
        sub     eax,[.margin_gap]
        mov     [.rc.right],eax
        cmp     [.margin_width], 1
        jle     .no_marks
        mov     ecx,.bookmark_count

      .paint_next_mark:
        push    ecx
        mov     eax,4
        mul     ecx
        lea     edx,[.bookmarks-4]
        add     eax,edx
        cmp     dword [eax],0
        je      .paint_next_item

        mov     edx,dword [eax]
        mov     eax,edx
        sub     eax,[.window_line_number]
        inc     eax
        call    .mark_line

      .paint_next_item:
        pop     ecx
        loop    .paint_next_mark

      .no_marks:
        ret

      .mark_line:
        mov     ecx,[.font_height]
        mul     ecx
        sub     eax,[.font_height]
        mov     [.rc.top],eax
        mov     [.rc.left],1
        cmp     [.bookmark_icon],0
        je      .no_marks
        invoke  DrawIconEx, ebx, [.rc.left], [.rc.top], [.bookmark_icon], 14, 14, 0, 0, DI_NORMAL

        retn



.wmsetfocus:

;        DebugMsg "AsmEdit WM_SETFOCUS"

        or      [.focus], -1
        call    .create_caret
        mov     [.notification], AEN_SETFOCUS and $ff
        cmp     [.was_selection],0
        je      .done
        jmp     .moved_window



.wmkillfocus:

;        DebugMsg "AsmEdit WM_KILLFOCUS"

        and     [.focus],0
        invoke  DestroyCaret
        mov     [.notification], AEN_KILLFOCUS and $ff
        cmp     [.was_selection],0
        je      .done
        jmp     .moved_window

.wmhscroll:
        mov     [.sc.cbSize],sizeof.SCROLLINFO
        mov     [.sc.fMask],SIF_PAGE
        lea     eax, [.sc]
        invoke  GetScrollInfo,[.hwnd],SB_HORZ,eax
        movzx   eax,word [.wparam]
        cmp     eax,SB_LINEUP
        je      .hscroll_left
        cmp     eax,SB_LINEDOWN
        je      .hscroll_right
        cmp     eax,SB_THUMBTRACK
        je      .hscroll_pos
        cmp     eax,SB_PAGEUP
        je      .hscroll_wleft
        cmp     eax,SB_PAGEDOWN
        je      .hscroll_wright
    .hscroll_ignore:
        jmp     .done
    .hscroll_left:
        cmp     [.window_position],0
        je      .hscroll_ignore
        dec     [.window_position]
        jmp     .moved_window
    .hscroll_right:
        mov     eax, aeLineCharLen
        sub     eax,[.sc.nPage]
        cmp     [.window_position],eax
        jge     .hscroll_ignore
        inc     [.window_position]
        jmp     .moved_window
    .hscroll_pos:
        movzx   eax,word [.wparam+2]
        mov     [.window_position],eax
        jmp     .moved_window
    .hscroll_wleft:
        mov     eax,[.sc.nPage]
        sub     [.window_position],eax
        jnc     .moved_window
        mov     [.window_position],0
        jmp     .moved_window
    .hscroll_wright:
        mov     eax,[.sc.nPage]
        mov     ecx, aeLineCharLen
        sub     ecx,eax
        add     [.window_position],eax
        cmp     [.window_position],ecx
        jbe     .moved_window
        mov     [.window_position],ecx
        jmp     .moved_window


.wmvscroll:
        mov     [.sc.cbSize],sizeof.SCROLLINFO
        mov     [.sc.fMask],SIF_ALL
        lea     eax, [.sc]
        invoke  GetScrollInfo,[.hwnd],SB_VERT,eax
        movzx   eax,word [.wparam]
        cmp     eax,SB_LINEUP
        je      .vscroll_up
        cmp     eax,SB_LINEDOWN
        je      .vscroll_down
        cmp     eax,SB_THUMBTRACK
        je      .vscroll_pos
        cmp     eax,SB_PAGEUP
        je      .vscroll_pageup
        cmp     eax,SB_PAGEDOWN
        je      .vscroll_pagedown
    .vscroll_ignore:
        jmp     .done
    .vscroll_up:
        mov     esi,[.window_line]
        mov     esi,[esi+4]
        or      esi,esi
        jz      .vscroll_ignore
        dec     [.window_line_number]
        mov     [.window_line],esi
        jmp     .moved_window
    .vscroll_down:
        mov     eax,[.sc.nPos]
        add     eax,[.sc.nPage]
        cmp     eax,[.sc.nMax]
        ja      .vscroll_ignore
        mov     esi,[.window_line]
        mov     esi,[esi]
        or      esi,esi
        jz      .vscroll_ignore
        inc     [.window_line_number]
        mov     [.window_line],esi
        jmp     .moved_window
    .vscroll_pos:
        mov     eax,[.sc.nTrackPos]
        call    .find_line
        or      esi,esi
        jz      .vscroll_ignore
        mov     [.window_line],esi
        mov     [.window_line_number],ecx
        jmp     .moved_window
    .vscroll_pageup:
        mov     esi,[.window_line]
        mov     ecx,[.sc.nPage]
    .scroll_up:
        mov     eax,[esi+4]
        or      eax,eax
        jz      .scroll_ok
        dec     [.window_line_number]
        mov     esi,eax
        loop    .scroll_up
        jmp     .scroll_ok
    .vscroll_pagedown:
        mov     esi,[.window_line]
        mov     eax,[.sc.nPos]
        add     eax,[.sc.nPage]
        mov     ecx,[.sc.nMax]
        sub     ecx,eax
        inc     ecx
        cmp     ecx,[.sc.nPage]
        jbe     .scroll_down
        mov     ecx,[.sc.nPage]
    .scroll_down:
        mov     eax,[esi]
        or      eax,eax
        jz      .scroll_ok
        inc     [.window_line_number]
        mov     esi,eax
        loop    .scroll_down


    .scroll_ok:
        mov     [.window_line],esi
        jmp     .moved_window

.wmmousewheel:
        mov     esi,[.window_line]
        mov     eax,[.wparam]
        sar     eax,16
        cdq
        mov     ecx,120
        idiv    ecx
        imul    eax,[wheel_scroll_lines]
        mov     ecx,eax
        cmp     ecx,0
        jg      .scroll_up
        neg     ecx
        jnz     .scroll_down
        jmp     .done


;---------- WM_SIZE -------------------------------

.wmsize:
        cmp     [.editor_screen], 0
        je      @f

        stdcall FreeMem, [.editor_screen]

@@:
        call    .update_positions
        call    .update_screen
        lea     esi, [.rect]
        invoke  GetClientRect,[.hwnd],esi
        invoke  InvalidateRect,[.hwnd],esi,FALSE
        jmp     .done

;----------- WM_KEYDOWN ---------------------------

.wmkeydown:
        lea     eax, [.kbstate]
        invoke  GetKeyboardState, eax
        cmp     [.was_selection],0
        jne     .process_key

        mov     eax,[.caret_line]
        mov     [.sel_line],eax
        mov     eax,[.caret_position]
        mov     [.sel_position],eax
        mov     eax,[.caret_line_number]
        mov     [.sel_line_number],eax

    .process_key:
        mov     eax,[.wparam]
        cmp     eax,VK_LEFT
        je      .left
        cmp     eax,VK_RIGHT
        je      .right
        cmp     eax,VK_UP
        je      .up
        cmp     eax,VK_DOWN
        je      .down
        cmp     eax,VK_HOME
        je      .line_home
        cmp     eax,VK_END
        je      .line_end
        cmp     eax,VK_PGUP
        je      .pgup
        cmp     eax,VK_PGDN
        je      .pgdn

        mov     ecx, [.caret_line_number]
        cmp     ecx, [.read_only]       ; read only => only navigation keys
        jbe     .ignore

        cmp     eax,VK_BACK
        je      .back
        cmp     eax,VK_DELETE
        je      .del
        cmp     eax,VK_INSERT
        je      .insert
        cmp     eax,VK_F6
        je      .duplicate_line
        test    [.kbstate+VK_CONTROL], 80h
        jz      .convert_to_unicode
        cmp     eax,'Y'
        je      .remove_line

    .convert_to_unicode:

        mov     ax,word [.lparam+2]
        and     eax,7Fh

        lea     ecx, [.kbstate]
        lea     edx, [.char]
        invoke  ToUnicode, [.wparam], eax, ecx, edx, 4, 0

        or      eax,eax
        jz      .ignore
        mov     ax, [.char]
        cmp     ax, 20h
        jae     .put_char
        cmp     ax, 0Dh
        je      .put_char
        cmp     ax, 9
        je      .put_char
        jmp     .ignore

  .left:
        test    [.kbstate+VK_CONTROL],80h
        jnz     .word_left
        cmp     [.caret_position],0
        je      .ignore
        dec     [.caret_position]
        jmp     .moved_caret

  .right:
        test    [.kbstate+VK_CONTROL],80h
        jnz     .word_right
        cmp     [.caret_position], aeLineCharLen
        je      .ignore
        inc     [.caret_position]
        jmp     .moved_caret

  .up:
        mov     esi,[.caret_line]
        mov     eax,[esi+4]
        or      eax,eax
        jz      .ignore
        mov     [.caret_line],eax
        dec     [.caret_line_number]
        jmp     .moved_caret

  .down:
        mov     esi,[.caret_line]
        mov     eax,[esi]
        or      eax,eax
        jz      .ignore
        mov     [.caret_line],eax
        inc     [.caret_line_number]
        jmp     .moved_caret
  .line_home:
        test    [.kbstate+VK_CONTROL],80h
        jnz     .screen_home
        mov     [.caret_position],0
        jmp     .moved_caret
  .line_end:
        test    [.kbstate+VK_CONTROL],80h
        jnz     .screen_end
    .find_line_end:
        mov     edi,[.caret_line]
        add     edi, sizeof.AELINE - aeCharSize
        mov     ax,20h
        mov     ecx, aeLineCharLen
        std
        repe    scasw
        setne   al
        movzx   eax,al
        add     ecx,eax
        cld
        mov     [.caret_position],ecx
        jmp     .moved_caret
  .screen_home:
        mov     eax,[.window_line]
        mov     [.caret_line],eax
        mov     eax,[.window_line_number]
        mov     [.caret_line_number],eax
        jmp     .moved_caret
  .screen_end:
        mov     eax,[.window_line_number]
        add     eax,[.page_size]
        dec     eax
        call    .find_line
        mov     [.caret_line],esi
        mov     [.caret_line_number],ecx
        jmp     .moved_caret
  .pgup:
        test    [.kbstate+VK_CONTROL],80h
        jnz     .text_home
        mov     eax,[.caret_line_number]
        mov     eax,[.caret_line_number]
        sub     eax,[.page_size]
        ja      .pgup_caret_ok
        mov     eax,1
    .pgup_caret_ok:
        call    .find_line
        mov     [.caret_line],esi
        mov     [.caret_line_number],ecx
        mov     eax,[.window_line_number]
        sub     eax,[.page_size]
        ja      .pgup_window_ok
        mov     eax,1
        cmp     [.window_line_number],eax
        je      .moved_caret
    .pgup_window_ok:
        call    .find_line
        mov     [.window_line],esi
        mov     [.window_line_number],ecx
        jmp     .moved_caret
  .pgdn:
        test    [.kbstate+VK_CONTROL],80h
        jnz     .text_end
        mov     eax,[.caret_line_number]
        mov     eax,[.caret_line_number]
        add     eax,[.page_size]
        call    .find_line
        mov     [.caret_line],esi
        mov     [.caret_line_number],ecx
        mov     eax,[.window_line_number]
        mov     ecx,[.page_size]
        add     eax,ecx
        mov     ebx,[.lines_count]
        sub     ebx,ecx
        jbe     .moved_caret
        inc     ebx
        cmp     eax,ebx
        jb      .pgdn_window_ok
        mov     eax,ebx
        cmp     [.window_line_number],eax
        je      .moved_caret

    .pgdn_window_ok:
        call    .find_line
        mov     [.window_line],esi
        mov     [.window_line_number],ecx
        jmp     .moved_caret

  .text_home:
        mov     eax,[.first_line]
        mov     [.caret_line],eax
        mov     [.caret_line_number],1
        jmp     .moved_caret

  .text_end:
        or      eax,-1
        call    .find_line
        mov     [.caret_line],esi
        mov     [.caret_line_number],ecx
        jmp     .moved_caret

  .word_left:
        mov     ecx, [.caret_position]
        mov     esi, [.caret_line]
        lea     esi, [esi + AELINE.text]

    .find_left_word:
        sub     ecx, 1
        jc      .word_line_up

        mov     ax, [esi + aeCharSize * ecx]
        call    .recognize_character
        jnc     .find_word_start
        jmp     .find_left_word

    .word_line_up:
        lea     esi, [esi - AELINE.text]        ; the pointer to the start of the line.
        mov     eax, [esi + AELINE.prev]
        or      eax, eax
        jz      .word_left_ok

        mov     [.caret_line],eax
        dec     [.caret_line_number]
        lea     esi,[eax + AELINE.text]
        mov     ecx, aeLineCharLen
        jmp     .find_left_word

    .find_word_start:
        sub     ecx,1
        jc      .word_left_ok

        mov     ax, [esi + aeCharSize * ecx]
        call    .recognize_character
        jc      .word_left_ok
        jmp     .find_word_start

    .word_left_ok:
        inc     ecx
        mov     [.caret_position], ecx
        jmp     .moved_caret

  .word_right:
        mov     ecx, [.caret_position]
        mov     esi, [.caret_line]
        lea     esi, [esi+AELINE.text]
        cmp     ecx, aeLineCharLen
        je      .word_line_down

    .find_word_end:
        add     ecx, 1
        cmp     ecx, aeLineCharLen
        je      .word_line_down

        mov     ax, [esi + aeCharSize * ecx]
        call    .recognize_character
        jc      .find_right_word
        jmp     .find_word_end

    .find_right_word:
        add     ecx, 1
        cmp     ecx, aeLineCharLen
        je      .word_line_down

    .check_right_word:
        mov     ax, [esi + aeCharSize * ecx]
        call    .recognize_character
        jnc     .word_right_ok
        jmp     .find_right_word

    .word_line_down:

        mov     eax, dword [esi - AELINE.text + AELINE.next]
        or      eax,eax
        jz      .find_line_end

        mov     [.caret_line],eax
        inc     [.caret_line_number]

        lea     esi, [eax + AELINE.text]
        xor     ecx,ecx
        jmp     .check_right_word

    .word_right_ok:
        mov     [.caret_position], ecx
        jmp     .moved_caret

  .insert:
        test    [.kbstate+VK_MENU],80h
        jnz     .switch_blocks
        test    [.kbstate+VK_CONTROL],80h
        jnz     .wmcopy
        test    [.kbstate+VK_SHIFT],80h
        jnz     .wmpaste
        xor     [.editor_mode],AEMODE_OVERWRITE
        mov     [.notification],AEN_MODECHANGE and $ff
        call    .create_caret
        cmp     [.was_selection],1
        je      .done
        mov     [.sel_line],0
        jmp     .done

  .del:
        test    [.kbstate+VK_CONTROL], 80h
        jnz     .wmclear
        test    [.kbstate+VK_SHIFT], 80h
        jnz     .wmcut

        cmp     [.was_selection],0
        je      .no_selection

        test    [.editor_style], AES_SECURESEL
        jz      .wmclear

    .no_selection:
        mov     edi,[.caret_line]
        mov     [.current_line],edi
        test    [.editor_mode],AEMODE_OVERWRITE
        jnz     .delete_char
        add     edi, sizeof.AELINE - aeCharSize
        mov     ax, 20h
        mov     ecx, aeLineCharLen

        std                     ; search the end of the line.
        repe scasw
        setne   al
        movzx   eax, al
        add     ecx, eax
        cld

        mov     edx, [.caret_position]
        cmp     edx, ecx
        jb      .delete_char

        mov     ecx, aeLineCharLen
        sub     ecx,edx
        mov     edi, [.caret_line]
        mov     esi, [edi+AELINE.next]
        or      esi,esi
        jz      .ignore

        call    .store_status_for_undo
        call    .store_line_for_undo

        mov     [.current_line], esi
        call    .store_line_for_undo

        mov     ebx, [esi+AELINE.next]
        mov     [edi+AELINE.next], ebx
        or      ebx,ebx
        jz      .append_line

        mov     [.current_line], ebx
        call    .store_line_for_undo

        mov     [ebx+AELINE.prev], edi

    .append_line:
        or      dword [esi+AELINE.next], -1     ; free the line
        dec     [.lines_count]
        lea     edi,[edi+AELINE.text + aeCharSize * edx]
        lea     esi, [esi+AELINE.text]

        rep movsw

        mov     [.sel_line], 0
        jmp     .text_modified

    .delete_char:
        mov     [.current_operation], VK_DELETE
        cmp     [.last_operation], VK_DELETE            ; group delete operations
        je      .undo_delete_ok

        call    .store_status_for_undo
        call    .store_line_for_undo

    .undo_delete_ok:
        call    .delete_character
        mov     [.sel_line], 0
        jmp     .text_modified

; handling of the BACKSPACE button
  .back:
        cmp     [.was_selection], 0
        je      .no_selection_to_clear

        test    [.editor_style], AES_SECURESEL
        jz      .wmclear

    .no_selection_to_clear:

        mov     eax,[.caret_line]
        mov     [.current_line],eax

        cmp     [.caret_position], 0
        je      .line_back

        test    [.kbstate+VK_CONTROL],80h
        jnz     .word_back

        mov     [.current_operation], VK_BACK
        cmp     [.last_operation],VK_BACK        ; group BACKSPACE operations for undo.
        je      .undo_back_ok

        call    .store_status_for_undo
        call    .store_line_for_undo

    .undo_back_ok:

        dec     [.caret_position]
        call    .delete_character
        mov     [.sel_line], 0
        jmp     .text_modified

    .word_back:

        call    .store_status_for_undo
        call    .store_line_for_undo

        mov     ecx, [.caret_position]
        mov     esi, [.caret_line]
        lea     esi, [esi+AELINE.text]

    .skip_spaces:

        sub     ecx, 1
        jc      .delete_word

        mov     ax, [esi + aeCharSize*ecx]
        cmp     ax, 20h
        je      .skip_spaces

        call    .recognize_character
        jnc     .find_word_to_delete_start

    .find_word_to_delete_end:

        sub     ecx, 1
        jc      .delete_word
        mov     ax, [esi + aeCharSize * ecx]
        call    .recognize_character
        jnc     .delete_word
        jmp     .find_word_to_delete_end

    .find_word_to_delete_start:

        sub     ecx, 1
        jc      .delete_word
        mov     ax, [esi + aeCharSize * ecx]
        call    .recognize_character
        jc      .delete_word
        jmp     .find_word_to_delete_start

    .delete_word:

        inc     ecx
        mov     eax, ecx
        lea     edi, [esi + aeCharSize * eax]
        xchg    eax, [.caret_position]

        lea     esi, [esi + aeCharSize * eax]
        mov     ecx, aeLineCharLen
        sub     ecx, eax
        rep movsw
        mov     ecx, [.caret_line]
        add     ecx, sizeof.AELINE
        sub     ecx, edi
        mov     ax, 20h
        shr     ecx, 1
        rep     stosw
        jmp     .text_modified

    .line_back:
        test    [.editor_mode], AEMODE_OVERWRITE
        jnz     .ignore

        mov     esi, [.caret_line]      ; current line
        mov     edi, [esi+AELINE.prev]  ; previous line
        or      edi,edi
        jz      .ignore

        call    .store_status_for_undo
        call    .store_line_for_undo

        mov     [.caret_line], edi
        dec     [.caret_line_number]
        mov     [.current_line], edi

        call    .store_line_for_undo

        mov     eax, [esi+AELINE.next]
        mov     [edi+AELINE.next], eax
        or      dword [esi+AELINE.next], -1     ; free this line block.
        dec     [.lines_count]
        or      eax,eax
        jz      .line_removed

        mov     [.current_line], eax
        call    .store_line_for_undo
        mov     [eax+AELINE.prev], edi

    .line_removed:
        add     edi, sizeof.AELINE - aeCharSize
        mov     ax, 20h
        mov     ecx, aeLineCharLen
        std
        repe scasw
        setne   al
        movzx   eax, al
        add     ecx, eax
        lea     edi, [edi + aeCharSize * eax + aeCharSize]
        cld

        mov     [.caret_position], ecx
        sub     ecx, aeLineCharLen
        neg     ecx
        lea     esi, [esi+AELINE.text]
        rep movsw
        mov     [.sel_line], 0
        jmp     .text_modified

  .put_char:
        mov     ebx, [.caret_line]
        mov     [.current_line], ebx
        cmp     ax, 0Dh
        je      .new_line

        cmp     ax,9
        je      .tab

        cmp     [.was_selection],0
        je      .no_selection_to_replace

        call    .store_status_for_undo
        test    [.editor_style], AES_SECURESEL
        jnz     .put_new_char

        push    eax
        call    .delete_block
        pop     eax

        call    .insert_character
        jmp     .text_modified

    .no_selection_to_replace:
        mov     [.current_operation],VK_SPACE
        cmp     [.last_operation],VK_SPACE
        je      .undo_put_ok
        call    .store_status_for_undo

    .put_new_char:
        call    .store_line_for_undo

    .undo_put_ok:
        call    .insert_character
        mov     [.sel_line], 0
        jmp     .text_modified

; inserting TAB, or indent/outdent selection if AES_INDENTSEL is set.

  .tab:
        call    .store_status_for_undo
        cmp     [.was_selection],0
        je      .tab_securesel
        test    [.editor_style],AES_SECURESEL
        jnz     .tab_securesel
        test    [.editor_style],AES_INDENTSEL
        jnz     .indent_text

        call    .delete_block
        call    .make_tab
        jmp     .text_modified

    .tab_securesel:
        call    .store_line_for_undo
        call    .make_tab
        mov     [.sel_line], 0
        jmp     .text_modified

    .make_tab:
        test    [.editor_style], AES_SMARTTABS
        jz      .standard_tab

        mov     esi, [.current_line]
        mov     esi, [esi+AELINE.prev]
        or      esi, esi
        jz      .standard_tab

        mov     edx, [.caret_position]
        lea     edi, [esi + AELINE.text + aeCharSize*edx]
        mov     ecx, aeLineCharLen
        sub     ecx, edx
        jecxz   .standard_tab

        mov     ax, 20h
        repne   scasw
        jne     .standard_tab   ; searches the first <> space

        repe    scasw           ; searches then the first == space
        je      .standard_tab

        add     ecx, edx
        sub     ecx, aeLineCharLen - 1
        neg     ecx
        jmp     .tab_spaces

    .standard_tab:
        mov     ecx, [.caret_position]
        and     ecx, not 111b
        sub     ecx, [.caret_position]
        add     ecx, 8

    .tab_spaces:
        push    ecx
        mov     ax, 20h
        call    .insert_character
        pop     ecx
        loop    .tab_spaces
        ret

    .indent_text:
        pushad

        cmp     [.was_selection], 0
        je      .done

        mov     ecx, [.sel_line_number]
        sub     ecx, [.caret_line_number]
        jge     .count_lines_ok

        neg     ecx
        push    ecx

        mov     eax, [.caret_line]
        mov     [.sel_line], eax

  .goto_first_line:
        mov     esi, [.caret_line]
        test    esi, esi
        jz      @f

        mov     edi, [esi + AELINE.prev]
        mov     [.caret_line], edi
        loop    .goto_first_line

@@:
        mov     ebx, [.caret_position]          ; the caret goes up and the selection down.
        mov     eax, [.sel_position]
        mov     [.sel_position], ebx
        mov     [.caret_position], eax

        mov     ebx, [.caret_line_number]
        mov     eax, [.sel_line_number]
        mov     [.caret_line_number], eax
        mov     [.sel_line_number], ebx

        pop     ecx

   .count_lines_ok:

        cmp     [.sel_position], 0
        je      @f

        mov     eax, [.sel_line]
        mov     eax, [eax+AELINE.next]
        mov     [.sel_line], eax

        inc     [.sel_line_number]

@@:

        mov     [.caret_position], 0
        mov     [.sel_position], 0

        push    [.caret_line_number] [.caret_line] [.caret_position]

   .indent_loop:

        push    ecx
        xor     eax,eax
        mov     [.caret_position], 0
        test    [.kbstate+VK_SHIFT], 80h
        jz      .do_indent

        mov     esi, [.caret_line]

        mov     [.current_line], esi
        call    .store_line_for_undo

        lea     esi, [esi+AELINE.text]

        cmp     word [esi], 20h
        jne     .ok_next

        add     esi, aeCharSize
        cmp     word [esi], 20h
        jne     .ok_next

        call    .delete_character
        call    .delete_character

        jmp     .ok_next

      .do_indent:

        mov     esi, [.caret_line]
        mov     [.current_line], esi
        call    .store_line_for_undo

        mov     ax,' '
        call    .insert_character

        mov     al,' '
        call    .insert_character

      .ok_next:

        inc     [.caret_line_number]
        mov     esi, [.caret_line]
        mov     edi, [esi + AELINE.next]
        mov     [.caret_line], edi

        pop     ecx
        loop    .indent_loop

        pop     [.caret_position] [.caret_line] [.caret_line_number]
        popad
        jmp     .text_modified

  .new_line:

        call    .store_status_for_undo
        cmp     [.was_selection],0
        je      .new_line_securesel
        test    [.editor_style], AES_SECURESEL
        jnz     .new_line_securesel

        call    .delete_block

    .new_line_securesel:

        test    [.editor_mode], AEMODE_OVERWRITE
        jnz     .next_line
        call    .store_line_for_undo
        call    .allocate_line
        jc      .out_of_memory
        mov     edi, eax
        mov     [.current_line], eax
        call    .store_line_for_undo
        mov     esi, [.caret_line]
        mov     ebx, [esi+AELINE.next]
        mov     [.current_line], ebx
        call    .store_line_for_undo
        mov     [edi+AELINE.next], ebx
        mov     [edi+AELINE.prev], esi
        mov     [esi+AELINE.next], edi
        or      ebx,ebx
        jz      .line_prepared
        mov     [ebx+AELINE.prev], edi

    .line_prepared:

        mov     [.caret_line], edi
        inc     [.caret_line_number]
        lea     edi, [edi+AELINE.text]          ; edi is the new line
        lea     esi, [esi+AELINE.text]          ; esi is the old line
        mov     edx, [.caret_position]
        mov     [.caret_position], 0
        test    [.editor_style], AES_AUTOINDENT
        jz      .indent_ok

        push    edi
        mov     ax, 20h
        lea     edi, [esi+aeCharSize*edx]      ; edi = old line at the caret position.
        mov     ecx, aeLineCharLen
        sub     ecx, edx                       ; ecx - remaining of the line
        repe    scasw                          ; searches forward for spaces that have to be deleted.
        je      .line_ok

        mov     edx, aeLineCharLen - 1
        sub     edx, ecx

    .line_ok:
        mov     edi, esi                       ; edi = the old line  beginning.
        mov     ecx, aeLineCharLen
        repe    scasw                          ; searches the indentation of the old line.
        setne   al
        neg     ecx
        add     ecx, aeLineCharLen - 1         ; how many spaces to insert at the beginning?
        movzx   eax, al
        imul    ecx, eax

        pop     edi                     ; the new line data
        cmp     ecx, edx
        ja      .indent_ok

        mov     [.caret_position], ecx

    .indent_ok:

        mov     eax, $00200020
        mov     ecx, aeLineDataLen shr 2
        rep     stosd
        inc     [.lines_count]
        cmp     edx, aeLineCharLen
        je      .new_line_ok

        sub     edi, aeLineDataLen      ; back to the beginning of the new line.
        add     edi, [.caret_position]
        add     edi, [.caret_position]  ; edi = edi + 2*[.caret_position]

        lea     esi, [esi + aeCharSize*edx]
        cmp     edx, [.caret_position]
        jae     .position_ok

        mov     edx, [.caret_position]

    .position_ok:
        mov     ecx, aeLineCharLen
        sub     ecx, edx

    .move_data:
        movsw
        mov     word [esi - aeCharSize], 20h
        loop    .move_data

        jmp     .new_line_ok

    .next_line:
        mov     esi, [.caret_line]
        mov     ebx, [esi]
        or      ebx, ebx
        jnz     .next_line_ok

        call    .store_line_for_undo
        call    .allocate_line
        jc      .out_of_memory

        mov     esi, [.caret_line]
        mov     ebx, eax
        mov     [.current_line],eax

        call    .store_line_for_undo
        mov     [esi + AELINE.next], ebx
        mov     [ebx + AELINE.next], dword 0
        mov     [ebx + AELINE.prev], esi
        lea     edi, [ebx + AELINE.text]
        mov     eax, $00200020
        mov     ecx, aeLineDataLen shr 2
        rep     stosd
        inc     [.lines_count]

    .next_line_ok:
        mov     [.caret_line], ebx
        inc     [.caret_line_number]
        mov     [.caret_position], 0

    .new_line_ok:
        mov     eax,[.caret_line]
        mov     [.current_line], eax
        call    .store_line_for_undo
        mov     [.sel_line],0
        jmp     .text_modified

  .remove_line:
        mov     esi,[.caret_line]
        mov     [.current_line],esi
        mov     ebx,[esi]
        or      ebx,ebx
        jz      .clear_line
        mov     [.caret_position], 0
        call    .store_status_for_undo
        call    .store_line_for_undo
        cmp     esi,[.window_line]
        jne     .window_ok
        mov     [.window_line],ebx

    .window_ok:
        mov     edi,[esi+ AELINE.prev]
        mov     [.caret_line],ebx
        mov     [.current_line],ebx
        call    .store_line_for_undo
        mov     [ebx + AELINE.prev], edi
        or      dword [esi + AELINE.next], -1   ; free the line block.
        dec     [.lines_count]
        or      edi, edi
        jz      .removed_first

        mov     [.current_line], edi
        call    .store_line_for_undo
        mov     [edi + AELINE.next],ebx
        mov     [.sel_line], 0
        jmp     .text_modified

    .removed_first:
        mov     [.first_line],ebx
        mov     [.sel_line],0
        jmp     .text_modified

    .clear_line:
        lea     edi,[esi + AELINE.text]
        mov     ecx, aeLineCharLen
        mov     ax, 20h
        repe scasw
        je      .ignore

        mov     [.caret_position], 0
        call    .store_status_for_undo
        call    .store_line_for_undo
        lea     edi, [esi + AELINE.text]
        mov     eax, $00200020
        mov     ecx, aeLineDataLen shr 2
        rep stosd
        mov     [.sel_line],0
        jmp     .text_modified

  .duplicate_line:
        mov     esi, [.caret_line]
        mov     [.current_line], esi
        call    .store_status_for_undo
        call    .store_line_for_undo
        call    .allocate_line
        jc      .out_of_memory
        mov     edi, eax
        mov     [.current_line], eax
        call    .store_line_for_undo
        mov     esi, [.caret_line]
        mov     ebx, [esi + AELINE.next]
        mov     [.current_line],ebx
        call    .store_line_for_undo

        mov     [edi + AELINE.next], ebx
        mov     [edi + AELINE.prev], esi
        mov     [esi + AELINE.next], edi
        or      ebx,ebx
        jz      .line_ready

        mov     [ebx + AELINE.prev], edi

    .line_ready:
        lea     esi, [esi+AELINE.text]
        lea     edi, [edi+AELINE.text]
        mov     ecx, aeLineDataLen shr 2
        rep     movsd
        inc     [.lines_count]
        jmp     .text_modified

.wmsyskeydown:
        mov     eax,[.wparam]

        cmp     eax,VK_INSERT
        je      .switch_blocks

        mov     ecx, [.caret_line_number]
        cmp     ecx, [.read_only]
        jbe     .ignore

        cmp     eax,VK_BACK
        je      .wmundo

        mov     al,[.last_operation]
        mov     [.current_operation],al

;        invoke  ShowCaret,[.hwnd]
        jmp     .defwndproc

  .switch_blocks:
        xor     [.editor_mode],AEMODE_VERTICALSEL
        mov     [.notification],AEN_MODECHANGE and $ff
        cmp     [.was_selection],0
        je      .ignore
        jmp     .moved_window

.wmchar:
        test    [.lparam],1 shl 31
        jz      .ignore

        mov     eax,[.wparam]
        jmp     .put_char


;-------- WM_LBUTTONDOWN -------------------

.wmlbuttondown:
        call    .update_mouse_cursor
        cmp     [.focus],0
        jne     .focus_ok

        invoke  SetFocus,[.hwnd]

        mov     esi, [.editor_memory]
        add     esi, 8
        lea     edi, [.editor_data]
        mov     ecx, .editor_data_size shr 2
        rep     movsd

    .focus_ok:
        lea     eax, [.kbstate]
        invoke  GetKeyboardState,eax

        cmp     [.was_selection],0
        jne     .sel_ok

        mov     eax, [.caret_line]
        mov     [.sel_line], eax
        mov     eax, [.caret_position]
        mov     [.sel_position], eax
        mov     eax, [.caret_line_number]
        mov     [.sel_line_number], eax

    .sel_ok:
        call    .get_mouse_position
        invoke  SetCapture,[.hwnd]
        or      [.mouse_select],-1
        jmp     .moved_caret

    .get_mouse_position:
        mov     ax,word [.lparam]
        cwde
        sub     eax,[.margin_width]
        cdq
        idiv    [.font_width]
        add     eax,[.window_position]
        cmp     eax,0
        jl      .lowest_position
        cmp     eax, aeLineCharLen
        jg      .highest_position
        jmp     .click_position_ok

    .lowest_position:
        xor     eax,eax
        jmp     .click_position_ok

    .highest_position:
        mov     eax, aeLineCharLen

    .click_position_ok:
        mov     [.caret_position],eax
        mov     ax,word [.lparam+2]
        cwde
        cdq
        idiv    [.font_height]
        add     eax,[.window_line_number]
        cmp     eax,0
        jg      .click_line_ok
        mov     eax,1

    .click_line_ok:
        call    .find_line
        mov     [.caret_line],esi
        mov     [.caret_line_number],ecx
        ret

.wmlbuttonup:
        mov     [.mouse_select],0
        invoke  ReleaseCapture
        test    [.kbstate+VK_CONTROL],80h
        jz      .done
        mov     eax,[.lparam]
        and     eax,0FFFFh
        cmp     eax,[.margin_width]
        jge     .done
        mov     [.sel_position], aeLineCharLen
        mov     [.caret_position],0
        mov     eax,[.caret_line]
        mov     ebx,[.caret_line_number]
        mov     [.sel_line],eax
        mov     [.sel_line_number],ebx
        jmp     .moved_selection

.wmrbuttondown:
        cmp     [.was_selection],0
        jne     .ignore

        call    .get_mouse_position
        jmp    .moved_selection

.wmrbuttonup:
        cmp     [.PopupMenu],0
        je      .wmlbuttonup
        lea     eax,[.pt]
        invoke  GetCursorPos,eax
        invoke  GetParent,[.hwnd]
        invoke  TrackPopupMenu,[.PopupMenu],TPM_LEFTALIGN or TPM_RIGHTBUTTON ,[.pt.x],[.pt.y],0,eax,0
        jmp     .wmlbuttonup

.wmmousemove:
        call    .update_mouse_cursor
        cmp     [.mouse_select],0
        je      .ignore
        cmp     [.was_selection],0
        jne     .select
        mov     eax,[.caret_line]
        mov     ebx,[.caret_line_number]
        mov     [.sel_line],eax
        mov     [.sel_line_number],ebx
        mov     eax,[.caret_position]
        mov     [.sel_position],eax
    .select:
        call    .get_mouse_position
        jmp     .moved_selection

.update_mouse_cursor:
        mov     eax,[.lparam]
        and     eax,0FFFFh
        cmp     eax,[.margin_width]
        jge     .cursor_normal
        invoke  LoadCursorW,0,IDC_ARROW
        invoke  SetCursor,eax
        jmp     .cursor_ok
      .cursor_normal:
        invoke  LoadCursorW,0,IDC_IBEAM
        invoke  SetCursor,eax
      .cursor_ok:
        ret

.wmlbuttondblclk:
        mov     [.mouse_select],0
        call    .get_mouse_position
        call    .get_word_edges
        mov     [.sel_position],edx
        mov     [.caret_position],ecx
        mov     eax,[.caret_line]
        mov     ebx,[.caret_line_number]
        mov     [.sel_line],eax
        mov     [.sel_line_number],ebx
        jmp     .moved_selection
.wmcopy:
        cmp     [.was_selection],0
        je      .ignore
        call    .copy_to_clipboard
        jmp     .ignore


    .copy_to_clipboard:
        call    .get_block_size
        shl     ecx, 1

        invoke  GlobalAlloc,GMEM_MOVEABLE+GMEM_DDESHARE, ecx
        mov     ebx,eax

        invoke  GlobalLock, ebx
        mov     edi,eax

        push    ebx
        call    .copy_block
        pop     ebx

        invoke  GlobalUnlock, ebx
        invoke  OpenClipboard, [.hwnd]
        invoke  EmptyClipboard
        invoke  SetClipboardData, CF_UNICODETEXT, ebx
        or      eax,eax
        jz      .copy_failed
        invoke  CloseClipboard
        ret

    .copy_failed:
        invoke  GlobalFree,ebx
        ret

.wmcut:
        cmp     [.was_selection], 0
        je      .ignore
        call    .copy_to_clipboard

.wmclear:
        cmp     [.was_selection], 0
        je      .ignore

        call    .store_status_for_undo
        call    .delete_block
        mov     [.sel_line], 0
        jmp     .text_modified

;------- WM_PASTE -------------------------

.wmpaste:
        invoke  OpenClipboard, NULL
        invoke  GetClipboardData, CF_UNICODETEXT
        or      eax,eax
        jz      .close_clipboard

        mov     ebx,eax
        invoke  GlobalLock,ebx
        mov     esi,eax

        push    ebx
        call    .store_status_for_undo
        call    .get_selection_start_position

        cmp     [.was_selection], 0
        je      .do_paste

        test    [.editor_style], AES_SECURESEL
        jnz     .do_paste

        push    esi
        call    .delete_block
        pop     esi

    .do_paste:

        call    .insert_block
        pop     ebx
        jc      .close_clipboard
        invoke  GlobalUnlock,ebx
        invoke  CloseClipboard
        test    [.editor_style],AES_SECURESEL
        jnz     .text_modified
        mov     eax,[.sel_line]
        mov     ebx,[.sel_position]
        mov     ecx,[.sel_line_number]
        mov     [.caret_line],eax
        mov     [.caret_position],ebx
        mov     [.caret_line_number],ecx
        mov     [.sel_line],0
        jmp     .text_modified

    .close_clipboard:

        invoke  CloseClipboard
        jmp     .ignore

    .get_selection_start_position:

        mov     eax, [.sel_line_number]
        mov     ebx, [.sel_position]
        cmp     [.was_selection], 0
        je      .new_position_ok
        cmp     eax, [.caret_line_number]
        ja      .new_position_ok
        jb      .update_position
        cmp     ebx, [.caret_position]
        ja      .new_position_ok

    .update_position:

        xchg    eax, [.caret_line_number]
        xchg    ebx, [.caret_position]
        push    eax ebx
        call    .update_positions
        pop     [.caret_position] [.caret_line_number]

    .new_position_ok:
        ret

;------- WM_SETTEXT -----------------------

.wmsettext:
        call    .reset_editor_memory
        call    .allocate_line
        mov     [.first_line],eax
        mov     [.lines_count],1
        mov     [.caret_line],eax
        mov     [.caret_line_number],1
        mov     [.window_line],eax
        mov     [.window_line_number],1
        mov     edi,eax
        xor     eax,eax
        stosd
        stosd
        mov     eax, $00200020
        mov     ecx, aeLineDataLen shr 2
        rep     stosd
        mov     [.caret_position],0
        mov     [.window_position],0
        mov     [.sel_line],0
        mov     esi,[.lparam]
        or      esi,esi
        jz      .text_modified
        mov     ebx, [.first_line]
        lea     edi, [ebx+AELINE.text]
        mov     ecx, aeLineCharLen

    .copy_line:
        lodsw
        or      ax, ax
        jz      .text_modified

        cmp     ax, 0Ah
        je      .copy_lf

        cmp     ax, 0Dh
        je      .copy_cr

        cmp     ax,9
        je      .copy_tab

        stosw
        loop    .copy_line

        jmp     .copy_new_line

    .skip_overlap:
        lodsw
        or      ax,ax
        jz      .text_modified
        cmp     ax,0Ah
        je      .copy_lf
        cmp     ax,0Dh
        je      .copy_cr
        jmp     .skip_overlap

    .copy_tab:
        mov     edx,ecx
        and     ecx, 111b
        setz    al
        shl     al,3
        or      cl,al
        sub     edx,ecx
        jc      .skip_overlap
        mov     ax, 20h
        rep stosw
        mov     ecx,edx
        jmp     .copy_line

    .copy_lf:
        cmp     word [esi], 0Dh
        jne     .copy_new_line
        lea     esi, [esi+2]
        jmp     .copy_new_line

    .copy_cr:
        cmp     word [esi],0Ah
        jne     .copy_new_line
        lea     esi, [esi+2]

    .copy_new_line:
        push    ebx esi
        call    .allocate_line
        jc      .out_of_memory
        pop     esi ebx
        mov     edi, eax
        mov     edx, [ebx + AELINE.next]
        mov     [edi + AELINE.next], edx
        mov     [edi + AELINE.prev], ebx
        mov     [ebx + AELINE.next], edi
        mov     ebx, edi
        lea     edi, [edi+AELINE.text]
        mov     eax, $00200020
        mov     ecx, aeLineDataLen shr 2
        rep     stosd
        inc     [.lines_count]
        or      edx, edx
        jz      .do_copy

        mov     [edx + AELINE.prev], ebx

    .do_copy:
        mov     ecx, aeLineCharLen
        lea     edi, [ebx+AELINE.text]
        jmp     .copy_line


.wmgettextlength:

        mov     esi,[.first_line]
        xor     edx,edx

    .get_line_length:
        lea     edi,[esi+AELINE.text + aeLineDataLen - aeCharSize]
        mov     ecx, aeLineCharLen
        mov     ax, 20h
        std
        repe    scasw
        cld
        setne   al
        movzx   eax,al
        add     edx, ecx
        add     edx, eax
        add     edx, 2
        mov     esi, [esi]
        or      esi, esi
        jnz     .get_line_length

        sub     edx, 2
        mov     [.return_value],edx
        jmp     .ignore


;---------- WM_GETTEXT ------------------------

.wmgettext:
        mov     edi,[.lparam]
        mov     ebx,[.first_line]
        mov     edx,[.wparam]
        sub     edx,1
        jc      .ignore

    .get_line:
        push    edi
        lea     edi,[ebx+AELINE.text + aeLineDataLen - aeCharSize]
        mov     ecx, aeLineCharLen
        mov     ax,20h
        std
        repe    scasw
        cld
        setne   al
        movzx   eax,al
        add     ecx,eax
        pop     edi
        lea     esi,[ebx+8]
        test    [.editor_style], AES_OPTIMALFILL
        jz      .copy_data

        push    ecx edx edi
        lea     edi,[.line_colors]
        mov     ecx, aeLineDataLen shr 2
        xor     eax,eax
        rep     stosd
        lea     edi, [.line_colors]
        invoke  .syntax_proc, esi, edi
        pop     edi edx ecx

    .optimal_fill:
        cmp     ecx, 8
        jbe     .copy_data
        push    ecx edi
        lea     edi,[esi+7]
        lea     eax,[.line_colors+edi-8]
        sub     eax,ebx
        mov     ecx,8

    .count_spaces:
        cmp     word [edi], 20h
        jne     .spaces_counted
        cmp     word [eax], 0
        jne     .spaces_counted

        sub     edi, aeCharSize
        sub     eax, aeCharSize
        loop    .count_spaces

    .spaces_counted:
        pop     edi eax
        cmp     ecx, 7
        jb      .put_tab
        mov     ecx, 8
        sub     edx,ecx
        jc      .cut_overlap
        rep movsw
        mov     ecx,eax
        sub     ecx, 8
        jmp     .optimal_fill

    .put_tab:
        sub     edx,ecx
        jc      .cut_overlap
        push    esi
        rep     movsw
        pop     esi
        add     esi,8
        or      edx,edx
        jz      .end_text
        dec     edx
        mov     ecx,eax
        sub     ecx,8
        mov     ax,9
        stosw
        jmp     .optimal_fill


    .copy_data:
        sub     edx,ecx
        jc      .cut_overlap

        rep     movsw

.end_copy_char:
        mov     ebx,[ebx]
        or      ebx,ebx
        jz      .end_text
        sub     edx,2
        jc      .end_text
        mov     eax,000A000Dh
        stosd
        jmp     .get_line

    .cut_overlap:
        neg     edx
        sub     ecx,edx
        rep movsw

    .end_text:
        xor     ax,ax
        stosw
        mov     eax,edi
        dec     eax
        sub     eax,[.lparam]
        mov     [.return_value],eax
        jmp     .ignore

;--------- WM_SETFONT ---------------------
iglobal
  cProbeText8 du 'ASDFGHJK'
endg

.wmsetfont:
        mov     esi,[.wparam]
        or      esi,esi
        jnz     .get_metrics

        invoke  GetStockObject, SYSTEM_FIXED_FONT
        mov     esi, eax

    .get_metrics:
        invoke  GetDC,[.hwnd]
        mov     ebx,eax
        invoke  SelectObject,ebx,esi

        lea     eax, [.tm]
        invoke  GetTextMetricsW, ebx, eax

        lea     eax, [.sz]
        invoke  GetTextExtentPoint32W, ebx, cProbeText8, 8, eax

        invoke  ReleaseDC,[.hwnd], ebx

;        test    [.tm.tmPitchAndFamily],TMPF_FIXED_PITCH
;        jnz     .ignore

        mov     [.return_value],esi
        mov     [.editor_font],esi
        mov     eax,[.tm.tmHeight]
        test    eax, eax
        jnz     @f
        inc     eax
@@:
        mov     [.font_height],eax

        mov     eax, [.sz.cx]
        sar     eax, 3
        test    eax, eax
        jnz     @f
        inc     eax
@@:
        mov     [.font_width],eax
        call    .create_caret
        mov     eax,[.lparam]
        mov     [.redraw_now],al
        jmp     .wmsize


;----------- WM_GETFONT ----------------------

.wmgetfont:
        mov     eax,[.editor_font]
        mov     [.return_value],eax
        jmp     .ignore


;------------ WM_UNDO ------------------------
.wmundo:
        cmp     [.undo_data],0
        je      .ignore
        call    .undo
        mov     [.last_operation],0
        call    .create_caret
        jmp     .text_modified

.emcanundo:
        mov     eax,[.undo_data]
        or      eax,eax
        jz      .ignore
        mov     [.return_value],TRUE
        jmp     .ignore

.ememptyundobuffer:
        call    .clear_undo_data
        jmp     .ignore

.emreplacesel:
        test    [.editor_mode], AEMODE_VERTICALSEL
        jnz     .ignore

        push    [.editor_mode]
        and     [.editor_mode], not (AEMODE_OVERWRITE or AEMODE_NOUNDO)
        push    [.caret_line] [.caret_position]

        cmp     [.wparam], 0            ; .wpara = 0 means to not save for undo.
        jne     .replace_undo_ok

        or      [.editor_mode], AEMODE_NOUNDO

    .replace_undo_ok:

        call    .store_status_for_undo
        call    .get_selection_start_position
        cmp     [.was_selection],0
        je      .ready_for_replace

        call    .delete_block
        mov     [.sel_line], 0

    .ready_for_replace:

        mov     esi, [.lparam]
        test    esi, esi
        jz      .insert_ok
        call    .insert_block

    .insert_ok:

        mov     [.notification], AEN_TEXTCHANGE and $ff
        pop     eax esi
        pop     [.editor_mode]

        sub     esi,[.caret_line]
        sub     eax,[.caret_position]
        or      eax, esi
        jz      .text_modified

        mov     eax,[.sel_line]
        xchg    eax,[.caret_line]
        mov     [.sel_line],eax
        mov     eax,[.sel_line_number]
        xchg    eax,[.caret_line_number]
        mov     [.sel_line_number],eax
        mov     eax,[.sel_position]
        xchg    eax,[.caret_position]
        mov     [.sel_position],eax
        jmp     .text_modified

.aemsetmode:
        mov     eax,[.wparam]
        xchg    [.editor_mode],eax
        cmp     eax,[.editor_mode]
        je      .ignore
        mov     [.notification], AEN_MODECHANGE and $ff
        call    .create_caret
        cmp     [.was_selection],0
        jne     .moved_window
        jmp     .done

.aemgetmode:
        mov     eax,[.editor_mode]
        mov     [.return_value],eax
        jmp     .ignore

; John Found - 25.11.2003
.aemgetmodified:
        mov     eax, [.Modified]
        mov     [.return_value], eax
        jmp     .ignore

.aemsetmodified:
        mov     eax, [.wparam]
        xchg    eax, [.Modified]
        mov     [.return_value], eax
        mov     [.notification],AEN_TEXTCHANGE and $ff
        jmp     .ignore

.aemsetsyntaxhighlight:
        mov     eax,[.wparam]
        mov     ebx,[.lparam]
        cmp     eax,0
        je      .no_new_colors
        mov     [.syntax_colors],eax
      .no_new_colors:
        mov     [.syntax_proc], ebx
      .syntax_proc_ok:
        or      ebx,ebx
        jnz     .wmsize
        mov     [.syntax_proc],SyntaxProc
        jmp     .wmsize


.aemsettextcolor:
        mov     eax,[.wparam]
        mov     ebx,[.lparam]
        mov     [.text_color],eax
        mov     [.background_color],ebx
        jmp     .wmsize


.aemsetselcolor:
        mov     eax,[.wparam]
        mov     ebx,[.lparam]
        mov     [.selection_text],eax
        mov     [.selection_background],ebx
        jmp     .wmsize


.aemsetmargincolor:
        mov     eax,[.wparam]
        mov     ebx,[.lparam]
        mov     [.margin_background],eax
        mov     [.margin_border],ebx
        jmp     .wmsize


.aemsetmarginwidth:
        mov     eax,[.wparam]
        mov     ebx,[.lparam]
        mov     [.margin_gap],eax
        mov     [.margin_width],ebx
        jmp     .wmsize


.aemsetpopupmenu:
        mov     eax, [.lparam]
        mov     [.PopupMenu],eax
        jmp     .ignore


.aemsettheme:
        mov     ebx,[.lparam]

        mov     eax,[ebx]
        mov     [.syntax_proc],eax
        or      eax,eax
        jnz     @f
        mov     [.syntax_proc], SyntaxProc
@@:

        add     ebx,4
        mov     eax,[ebx]
        mov     [.text_color],eax

        add     ebx,4
        mov     eax,[ebx]
        mov     [.background_color],eax

        add     ebx,4
        mov     eax,[ebx]
        mov     [.selection_text],eax

        add     ebx,4
        mov     eax,[ebx]
        mov     [.selection_background],eax

        add     ebx,4
        mov     eax,[ebx]
        mov     [.margin_background],eax

        add     ebx,4
        mov     eax,[ebx]
        mov     [.margin_border],eax

        add     ebx,4
        mov     eax,[ebx]
        mov     [.margin_width],eax

        add     ebx,4
        mov     eax,[ebx]
        mov     [.margin_gap],eax

        add     ebx,4
        mov     eax,[ebx]
        mov     [.focus_fg],eax

        add     ebx,4
        mov     eax,[ebx]
        mov     [.focus_bg],eax

        add     ebx,4
        mov     eax,[ebx]
        mov     [.read_only_fg],eax

        add     ebx,4
        mov     eax,[ebx]
        mov     [.read_only_bg],eax

        add     ebx,4
        mov     [.syntax_colors], ebx
        jmp     .wmsize


;----------------------------------------------------

.aemtogglebookmark:
       mov     ecx, .bookmark_count
       mov     edx,[.caret_line_number]
       xor     eax,eax

  .loop_exists:
       cmp     [.bookmarks + 4*ecx - 4],edx
       je      .done_toggle
       loop    .loop_exists

       mov     ecx,.bookmark_count
       xchg    edx,eax

  .check_next_mark:
        cmp     dword [.bookmarks + 4*ecx - 4], edx
        je      .done_toggle
        loop    .check_next_mark

        jmp     .wmsize

  .done_toggle:
        mov     dword [.bookmarks + 4*ecx - 4], eax
        mov     [.return_value],ecx
        jmp     .wmsize


;--------------------------------------------------

.aemgotobookmark:
        mov     eax,[.lparam]
        cmp     eax,AEBM_NEXT
        je      .aemnextbookmark
        cmp     eax,AEBM_PREV
        je      .aemprevbookmark
        mov     eax,[.wparam]
        mov     ecx,4
        mul     ecx
        lea     edx,[.bookmarks-4]
        add     eax,edx
        mov     ecx,dword [eax]
        mov     [.return_value],ecx
        jmp     .ignore
.aemnextbookmark:
        mov     ecx,.bookmark_count
      .loop_next:
        push    ecx
        mov     eax,4
        mul     ecx
        lea     edx,[.bookmarks-4]
        add     eax,edx
        mov     ecx,[.caret_line_number]
        cmp     dword [eax],ecx
        jle     .loop_check_next
        mov     ecx,[.return_value]
        cmp     ecx,0
        je      .set_next_value
        cmp     ecx,dword [eax]
        jl      .loop_check_next
      .set_next_value:
        mov     ecx,dword [eax]
        mov     [.return_value],ecx
      .loop_check_next:
        pop     ecx
        loop    .loop_next
        jmp     .ignore
.aemprevbookmark:
        mov     ecx,.bookmark_count
      .loop_prev:
        push    ecx
        mov     eax,4
        mul     ecx
        lea     edx,[.bookmarks-4]
        add     eax,edx
        mov     ecx,[.caret_line_number]
        cmp     dword [eax],ecx
        jge     .loop_check_prev
        mov     ecx,[.return_value]
        cmp     ecx,0
        je      .set_prev_value
        cmp     ecx,dword [eax]
        jg      .loop_check_prev
      .set_prev_value:
        mov     ecx,dword [eax]
        mov     [.return_value],ecx
      .loop_check_prev:
        pop     ecx
        loop    .loop_prev
        jmp     .ignore
.aemclearbookmarks:
        call    .clear_marks
        jmp     .wmsize
      .clear_marks:
        mov     ecx,.bookmark_count
      .clear_next_mark:
        push    ecx
        mov     eax,4
        mul     ecx
        lea     edx, [.bookmarks-4]
        add     eax, edx
        mov     dword [eax],0
        pop     ecx
        loop    .clear_next_mark
        ret
.aemsetbookmarkicon:
        mov     eax,[.wparam]
        mov     [.bookmark_icon],eax
        jmp     .wmsize

.aemcomment:
        cmp     [.was_selection], 0
        je      .done

        call    .store_status_for_undo

        mov     ecx,[.sel_line_number]
        sub     ecx,[.caret_line_number]
        cmp     ecx,0
        jge     .count_lines

        neg     ecx
        push    ecx

        mov     eax, [.caret_line]
        mov     [.sel_line], eax

   .goto_first:
        mov     esi, [.caret_line]
        mov     edi, [esi + AELINE.prev]
        mov     [.caret_line],edi
        loop    .goto_first

        mov     ebx,[.caret_position]
        mov     eax,[.sel_position]
        mov     [.sel_position],ebx
        mov     [.caret_position],eax

        mov     ebx,[.caret_line_number]
        mov     eax,[.sel_line_number]
        mov     [.sel_line_number],ebx
        mov     [.caret_line_number],eax

        pop     ecx

   .count_lines:

        cmp     [.sel_position], 0
        je      @f

        mov     eax, [.sel_line]
        mov     eax, [eax + AELINE.next]
        mov     [.sel_line], eax

        inc     [.sel_line_number]

@@:
        mov     [.caret_position],0
        mov     [.sel_position], 0

        push    [.caret_line_number] [.caret_line] [.caret_position]

      .comment_loop:

        push    ecx

        xor     eax,eax
        mov     [.caret_position], eax

        mov     esi, [.caret_line]
        mov     [.current_line], esi

        cmp     [.lparam], 1            ; 0 = uncomment; 1 = comment;
        je      .do_comment

        lea     esi, [esi+AELINE.text]

      .check_for_blank:

        cmp     [.caret_position], aeLineCharLen
        jae     .next_line_comment

        cmp     word [esi], ' '
        je      .inc_pos

        cmp     word [esi],';'
        jne     .next_line_comment

        call    .store_line_for_undo
        call    .delete_character
        jmp     .next_line_comment

      .inc_pos:

        add     esi, aeCharSize
        inc     [.caret_position]
        jmp     .check_for_blank

      .do_comment:

        call    .store_line_for_undo
        mov     ax, ';'
        call    .insert_character

      .next_line_comment:

        inc     [.caret_line_number]
        mov     esi, [.caret_line]
        mov     edi, [esi + AELINE.next]
        mov     [.caret_line],edi

        pop     ecx
        loop    .comment_loop

        pop     [.caret_position] [.caret_line] [.caret_line_number]
        jmp     .text_modified

.aemindent:
        cmp     [.lparam],1
        je      .not_outdent

        mov     [.kbstate+VK_SHIFT], 80h
        jmp     .do_aemindent

      .not_outdent:
        mov     [.kbstate+VK_SHIFT], 0

      .do_aemindent:
        jmp     .indent_text

.aemreadonly: ; Added Tommy Lillehagen 30.01.2004
        mov     eax,[.wparam]
        xchg    [.read_only], eax
        mov     [.return_value], eax
        jmp     .ignore

.aemsetfocusline: ; Added Tommy Lillehagen 30.01.2004
        mov     eax,[.wparam]
        cmp     eax, [.focus_line]
        je      .ignore

        mov     [.focus_line], eax
        test    eax,eax
        jz      .wmsize

        sub     eax,[.window_line_number]
        inc     eax
        jz      .setfocusline_updatepos
        js      .setfocusline_updatepos
        cmp     eax, [.screen_height]
        jl      .refresh

    .setfocusline_updatepos:
        mov     eax,[.wparam]
        mov     ecx,[.screen_height]
        shr     ecx,1
        sub     eax,ecx
        jz      .setfocusline_notok
        jns     .setfocusline_ok

    .setfocusline_notok:
        xor     eax,eax
        inc     eax

    .setfocusline_ok:
        call    .find_line
        mov     [.window_line],esi
        mov     [.window_line_number],ecx
        jmp     .moved_window


.aemgetlineptr:
        mov     esi, [.caret_line]
        mov     eax, [.wparam]
        or      eax, eax
        jz      .line_ptr_ok
        call    .find_line
        cmp     ecx, [.wparam]
        jne     .ignore

    .line_ptr_ok:
        mov     [.return_value],esi
        jmp     .ignore


.aemgetlinedata:
        mov     esi,[.caret_line]
        mov     eax,[.wparam]
        or      eax,eax
        jz      .line_data_ok

        call    .find_line
        cmp     ecx, [.wparam]
        jne     .ignore

    .line_data_ok:
        lea     esi, [esi + AELINE.text]
        mov     edi, [.lparam]
        mov     ecx, aeLineDataLen shr 2
        rep     movsd
        mov     [.return_value], aeLineDataLen
        jmp     .ignore

.aemsetlinedata:        ; Sets only the text of the line, not the pointers.
        mov     esi,[.caret_line]
        mov     eax,[.wparam]
        or      eax,eax
        jz      .setline_data_ok
        call    .find_line
        cmp     ecx,[.wparam]
        jne     .ignore

    .setline_data_ok:
        lea     esi, [esi+AELINE.text]
        mov     edi, [.lparam]
        xchg    esi, edi
        mov     ecx, aeLineDataLen shr 2
        rep     movsd
        mov     [.return_value], aeLineDataLen
        jmp     .ignore

.aemsetpos:

        mov     edi,[.wparam]

virtual at edi
  .aepos  AEPOS
end     virtual

        cmp     [.sel_line], 0
        jne     .sel_start_ok
        mov     eax,[.caret_line]
        mov     [.sel_line],eax
        mov     eax,[.caret_line_number]
        mov     [.sel_line_number],eax
        mov     eax,[.caret_position]
        mov     [.sel_position],eax
    .sel_start_ok:
        mov     eax,[.aepos.selectionLine]
        or      eax,eax
        jz      .sel_line_ok
        call    .find_line
        mov     [.sel_line],esi
        mov     [.sel_line_number],ecx

    .sel_line_ok:
        mov     eax,[.aepos.selectionPosition]
        or      eax,eax
        jz      .sel_position_ok
        dec     eax
        mov     [.sel_position],eax
        cmp     eax, aeLineCharLen
        jbe     .sel_position_ok
        mov     [.sel_position], aeLineCharLen

    .sel_position_ok:
        mov     eax,[.aepos.caretLine]
        or      eax,eax
        jz      .caret_line_ok
        call    .find_line
        mov     [.caret_line],esi
        mov     [.caret_line_number],ecx

    .caret_line_ok:
        mov     eax,[.aepos.caretPosition]
        or      eax,eax
        jz      .caret_position_ok
        dec     eax
        cmp     eax, aeLineCharLen
        jbe     .caret_position_ok
        mov     eax, aeLineCharLen
    .caret_position_ok:
        mov     [.caret_position],eax
        cmp     esi,[.sel_line]
        jne     .moved_selection
        cmp     eax,[.sel_position]
        jne     .moved_selection
        mov     [.sel_line],0
        jmp     .moved_selection

.aemgetpos:
        mov     edi,[.wparam]
        mov     eax,[.caret_line_number]
        mov     [.aepos.selectionLine],eax
        mov     [.aepos.caretLine],eax
        mov     eax,[.caret_position]
        inc     eax
        mov     [.aepos.selectionPosition],eax
        mov     [.aepos.caretPosition],eax
        cmp     [.sel_line],0
        je      .ignore
        mov     eax,[.sel_line_number]
        mov     [.aepos.selectionLine],eax
        mov     eax,[.sel_position]
        inc     eax
        mov     [.aepos.selectionPosition],eax
        jmp     .ignore

.amgetcaretxy:
        mov     ecx, [.wparam]

        mov     eax,[.caret_y]
        mov     ebx,[.caret_x]
        add     ebx,[.margin_width]

        mov     [ecx+AECARETXY.x0], ebx
        mov     [ecx+AECARETXY.x1], ebx
        mov     [ecx+AECARETXY.y0], eax

        add     eax, [.font_height]
        mov     [ecx+AECARETXY.y1], eax
        jmp     .ignore

.aemfindfirst:
        mov     eax,[.search_text]
        or      eax,eax
        jnz     .buffer_ok
        call    .allocate_line
        jc      .out_of_memory

    .buffer_ok:
        mov     esi,[.lparam]
        mov     edi,eax
        mov     eax,[.wparam]
        push    edi
        stosd
        stosd
        mov     edx, eax

        mov     ecx, aeLineCharLen
        lodsw

    .copy_text:
        test    edx,AEFIND_CASESENSITIVE
        jnz     .text_case_ok

        push    ecx edx
        movzx   eax, ax
        invoke  CharLowerW, eax
        pop     edx ecx

    .text_case_ok:

        stosw
        lodsw
        or      ax, ax
        loopnz  .copy_text

        pop     edi
        jnz     .ignore

        neg     ecx
        add     ecx, aeLineCharLen
        mov     [edi+4],ecx
        mov     [.search_text],edi

.aemfindnext:
        mov     esi, [.search_text]
        or      esi, esi
        jz      .ignore

        cmp     dword [esi + 4], 0
        je      .ignore

        mov     edi, [.caret_line]
        mov     ecx, [.caret_line_number]
        mov     edx, [.caret_position]
        test    byte [esi],AEFIND_BACKWARD
        jnz     .search_backward

    .do_search:
        push    ecx
        call    .find_text
        pop     ecx
        jnc     .text_found

        inc     ecx
        xor     edx, edx
        mov     edi, [edi+AELINE.next]
        or      edi, edi
        jnz     .do_search

        jmp     .search_done

    .text_found:

        mov     [.caret_line],edi
        mov     [.sel_line],edi
        mov     [.caret_line_number],ecx
        mov     [.sel_line_number],ecx
        mov     [.caret_position],eax
        mov     esi,[.search_text]
        add     eax,[esi+4]
        mov     [.sel_position],eax
        call    .update_positions
        call    .let_caret_appear
        mov     eax,[.caret_position]
        xchg    eax,[.sel_position]
        mov     [.caret_position],eax
        mov     [.return_value],TRUE
        jmp     .moved_selection
    .backward_found:
        mov     [.caret_line],edi
        mov     [.sel_line],edi
        mov     [.caret_line_number],ecx
        mov     [.sel_line_number],ecx
        mov     [.sel_position],eax
        mov     esi,[.search_text]
        add     eax,[esi+4]
        mov     [.caret_position],eax
        call    .update_positions
        call    .let_caret_appear
        mov     eax,[.caret_position]
        xchg    eax,[.sel_position]
        mov     [.caret_position],eax
        mov     [.return_value],TRUE
        jmp     .moved_selection
    .search_backward:
        push    ecx
        call    .find_text
        pop     ecx
        jnc     .backward_found
        dec     ecx
        mov     edx,100h
        mov     edi,[edi+4]
        or      edi,edi
        jnz     .search_backward
    .search_done:
        xor     eax,eax
        mov     esi,[.search_text]
        mov     [esi],eax
        mov     [.search_text],eax
        jmp     .done


.aemcanfindnext:
        cmp     [.search_text],0
        je      .ignore
        mov     [.return_value],TRUE
        jmp     .ignore


.aemgetwordatcaret:
        call    .get_word_edges

        mov     word [.return_value], dx
        mov     word [.return_value+2], cx

        mov     edi, [.lparam]
        lea     esi, [esi + AELINE.text + aeCharSize * edx]

        sub     ecx, edx

        inc     ecx
        movzx   eax, word [.wparam]
        cmp     ecx, eax
        cmova   ecx, eax
        dec     ecx

        rep movsw

        xor     ax, ax
        stosw

        jmp     .ignore

.get_word_edges:
        mov     esi,[.caret_line]
        mov     edx,[.caret_position]

    .find_left_edge:
        or      edx,edx
        jz      .left_edge_ok

        mov     ax, [esi+AELINE.text + aeCharSize * edx - aeCharSize]
        cmp     byte [.wparam+2], 0
        jne     .pointok

        cmp     al, '.'
        je      .inword

        cmp     al, ':'
        je      .inword

.pointok:
        call    .recognize_character
        jc      .left_edge_ok

.inword:
        dec     edx
        jmp     .find_left_edge
    .left_edge_ok:
        mov     ecx, [.caret_position]
    .find_right_edge:
        cmp     ecx,100h
        je      .right_edge_ok

        mov     ax, [esi + AELINE.text + aeCharSize * ecx]
        call    .recognize_character
        jc      .right_edge_ok
        inc     ecx
        jmp     .find_right_edge
    .right_edge_ok:
        ret


.moved_caret:
        test    [.kbstate+VK_SHIFT], 80h
        jnz     .moved_selection
        mov     [.sel_line],0


.moved_selection:
        mov     [.notification],AEN_POSCHANGE and $ff
        jmp     .update


.moved_window:
        call    .update_positions
        jmp     .refresh


.text_modified:
        mov     [.notification],AEN_TEXTCHANGE and $ff


    .update:
        call    .update_positions
        call    .let_caret_appear

    .refresh:

        mov     eax,[.editor_screen]
        or      eax,eax
        jz      .wmsize

        push    eax                     ; the old [.editor_screen]

        call    .update_screen
        mov     esi,[esp]
        mov     edi,[.editor_screen]
        or      edi,edi
        jz      .refresh_failed

        mov     [.rect.top],0
        mov     edx,[.font_height]
        mov     [.rect.bottom],edx
        mov     ecx,[.screen_height]

    .refresh_screen:
        push    ecx
        mov     ecx,[.screen_width]
        mov     ebx,[.screen_height]
        imul    ebx, ecx

        mov     edx,[.font_width]
        imul    edx, ecx

        mov     eax, [.margin_width]
        add     edx, eax
        mov     [.rect.left], eax
        mov     [.rect.right], edx

    .refresh_line:
        mov     ax, [esi]                        ; the old text
        cmp     ax, [edi]                        ; the new text
        jne     .invalidate

        mov     ax, [esi + aeCharSize * ebx]     ; the old color
        cmp     ax, [edi + aeCharSize * ebx]     ; the new color
        jne     .invalidate

        add     esi, aeCharSize
        add     edi, aeCharSize
        loop    .refresh_line

        jmp     .refresh_next_line


    .invalidate:
; refresh the whole line:

        lea     esi, [esi + aeCharSize * ecx]
        lea     edi, [edi + aeCharSize * ecx]

        lea     eax, [.rect]
        invoke  InvalidateRect, [.hwnd], eax, FALSE

    .refresh_next_line:

; repaint the left margin.
        mov     [.rect.left], 0
        mov     eax, [.margin_width]
        mov     [.rect.right], eax

        lea     eax, [.rect]
        invoke  InvalidateRect, [.hwnd], eax, FALSE

        mov     eax,[.font_height]
        add     [.rect.top],eax
        add     [.rect.bottom],eax
        pop      ecx
        dec     ecx
        jnz     .refresh_screen


.refresh_free:
        stdcall FreeMem         ; address from the stack.
        jmp     .done

    .refresh_failed:
        pop     [.editor_screen]
        jmp     .wmsize


.ignore:
        mov     dl,[.last_operation]
        mov     [.current_operation],dl
        cmp     [.was_selection],0
        jne     .done
        mov     [.sel_line],0
.done:
        cmp     [.focus],0
        je      .caret_ok

        call    .update_caret_position

  .caret_ok:

        lea     esi,[.editor_data]
        mov     edi,[.editor_memory]
        add     edi,8
        mov     ecx,.editor_data_size shr 2
        rep     movsd                           ; updates editor memory.

        cmp     [.notification],0
        je      .notification_ok
        invoke  GetWindowLongW, [.hwnd], GWL_HWNDPARENT
        mov     edi,eax
        invoke  GetWindowLongW, [.hwnd], GWL_ID

        movzx   ebx, [.notification]
        or      ebx, AEN_NOTIFICATION0
        shl     ebx,16
        or      eax, ebx
        invoke  SendMessageW, edi, WM_COMMAND, eax, [.hwnd]

    .notification_ok:
        cmp     [.redraw_now],0
        je      .redraw_ok
        invoke  UpdateWindow,[.hwnd]

    .redraw_ok:
        mov     eax,[.return_value]

.finish:
        pop     edi esi ebx
        return

.out_of_memory:
        call    .undo

.not_enough_memory:
        lea     esp,[.editor_memory-10h]
        mov     [.notification],AEN_OUTOFMEMORY and $ff
        or      [.return_value],-1
        jmp     .ignore

.update_positions:
        lea     eax, [.rect]
        invoke  GetClientRect,[.hwnd],eax
        mov     eax,[.rect.left]
        add     eax,[.margin_width]
        mov     [.rect.left],eax
        cmp     eax,[.rect.right]
        jbe     .margin_ok
        mov     [.rect.right],eax
    .margin_ok:
        mov     eax,[.rect.right]
        sub     eax,[.rect.left]
        cdq
        div     [.font_width]
        add     edx, -1
        adc     eax, 0
        mov     [.screen_width], eax

if aeCharSize > 1
        lea     eax, [aeCharSize*eax]
end if
        mov     [.screen_width_bytes], eax


        mov     eax, [.rect.bottom]
        sub     eax, [.rect.top]
        cdq
        div     [.font_height]
        add     edx, -1
        adc     eax, 0
        mov     [.screen_height],eax

    .setup_vscroll:
        mov     ecx,[.lines_count]
        mov     [.sc.cbSize],sizeof.SCROLLINFO
        mov     [.sc.fMask],SIF_DISABLENOSCROLL+SIF_RANGE+SIF_PAGE+SIF_POS
        mov     [.sc.nMin],1
        mov     [.sc.nMax],ecx
        mov     eax,[.rect.bottom]
        sub     eax,[.rect.top]
        xor     edx,edx
        div     [.font_height]
        mov     [.page_size],eax
        mov     [.sc.nPage],eax
        mov     edx,[.window_line_number]
        mov     [.sc.nPos],edx
        cmp     edx,1
        je      .vscroll_ok
        add     edx,eax
        dec     edx
        cmp     edx,ecx
        jle     .vscroll_ok
        sub     edx,ecx

    .vscroll_correction:
        mov     esi,[.window_line]
        mov     esi,[esi+4]
        or      esi,esi
        jz      .setup_vscroll
        mov     [.window_line],esi
        dec     [.window_line_number]
        dec     edx
        jnz     .vscroll_correction
        jmp     .setup_vscroll

    .vscroll_ok:
        test    [.editor_style], WS_VSCROLL
        jz      .setup_hscroll

        lea     eax, [.sc]
        invoke  SetScrollInfo,[.hwnd],SB_VERT,eax,TRUE

    .setup_hscroll:
        mov     [.sc.nMin],0
        mov     [.sc.nMax], aeLineCharLen
        mov     eax,[.rect.right]
        sub     eax,[.rect.left]
        xor     edx,edx
        div     [.font_width]
        mov     [.sc.nPage],eax
        mov     edx,[.window_position]
        mov     [.sc.nPos],edx
        or      edx,edx
        jz      .hscroll_ok
        add     edx,eax
        cmp     edx,101h
        jbe     .hscroll_ok
        sub     edx,101h
        sub     [.window_position],edx
        jnc     .setup_hscroll
        mov     [.window_position],0
        jmp     .setup_hscroll

    .hscroll_ok:
        test    [.editor_style],WS_HSCROLL
        jz      .setup_caret
        lea     eax, [.sc]
        invoke  SetScrollInfo,[.hwnd],SB_HORZ,eax,TRUE

    .setup_caret:
        mov     [.caret_changed], 0

        mov     eax,[.font_width]
        mov     edx,[.caret_position]
        sub     edx,[.window_position]
        imul    eax,edx

        xchg    [.caret_x],eax
        sub     eax, [.caret_x]
        add     [.caret_changed], eax

        mov     eax,[.font_height]
        mov     edx,[.caret_line_number]
        sub     edx,[.window_line_number]
        imul    eax,edx

        xchg    [.caret_y], eax
        sub     eax, [.caret_y]
        add     [.caret_changed], eax

        ret

.let_caret_appear:
        mov     eax,[.caret_position]
        cmp     eax,[.window_position]
        jl      .horizontal_correction
        mov     eax,[.rect.right]
        sub     eax,[.rect.left]
        xor     edx,edx
        div     [.font_width]
        or      eax,eax
        jz      .horizontal_check
        dec     eax

    .horizontal_check:
        neg     eax
        add     eax,[.caret_position]
        cmp     [.window_position],eax
        jge     .horizontal_ok

    .horizontal_correction:
        mov     [.window_position],eax
        call    .update_positions

    .horizontal_ok:
        mov     esi,[.caret_line]
        mov     ecx,[.caret_line_number]
        cmp     ecx,[.window_line_number]
        jl      .vertical_correction
        mov     eax,[.rect.bottom]
        sub     eax,[.rect.top]
        xor     edx,edx
        div     [.font_height]
        or      eax,eax
        jz      .vertical_check
        dec     eax

    .vertical_check:
        neg     eax
        add     eax,[.caret_line_number]
        cmp     [.window_line_number],eax
        jge     .vertical_ok
        mov     esi,[.window_line]
        mov     ecx,[.window_line_number]

    .vertical_find:
        mov     esi,[esi]
        inc     ecx
        cmp     ecx,eax
        jl      .vertical_find

    .vertical_correction:
        mov     [.window_line],esi
        mov     [.window_line_number],ecx
        call    .update_positions

    .vertical_ok:
        ret


.create_caret:
        cmp     [.focus], 0
        jne     .do_create_caret
        retn

.do_create_caret:

;        DebugMsg "DestroyCaret"

        invoke  DestroyCaret

        test    [.editor_mode], AEMODE_OVERWRITE
        jnz     .block_caret

        test    [.editor_style],AES_CONSOLECARET
        jnz     .console_caret

;        DebugMsg "Create vertical caret"
        invoke  CreateCaret, [.hwnd], NULL, 0, [.font_height]
        jmp     .update_caret_position_show

    .block_caret:
;        DebugMsg "Create block caret"
        invoke  CreateCaret, [.hwnd], NULL, [.font_width], [.font_height]
        jmp     .update_caret_position_show

    .console_caret:
;        DebugMsg "Create console caret"
        invoke  CreateCaret, [.hwnd], NULL, [.font_width], 2

.update_caret_position_show:

;        DebugMsg "Show the caret."

        invoke  ShowCaret, [.hwnd]
        mov     [.caret_changed], 1

.update_caret_position:
        cmp     [.caret_changed], 0
        jne     .do_update_caret_pos

        retn

.do_update_caret_pos:
        mov     eax, [.caret_y]
        mov     ebx, [.caret_x]
        add     ebx, [.margin_width]

        test    [.editor_mode],AEMODE_OVERWRITE
        jnz     .set_position

        test    [.editor_style],AES_CONSOLECARET
        jz      .set_position

        add     eax, [.font_height]
        sub     eax, 2

    .set_position:

        push    eax
        invoke  HideCaret, [.hwnd]
        pop     eax

        cmp     ebx,[.margin_width]
        jge     .caret_margin_ok

        xor     ebx, ebx
        sub     ebx, [.font_width]

    .caret_margin_ok:

;        OutputValue "Caret X = ", ebx, 10, -1
;        OutputValue "Caret Y = ", eax, 10, -1

        invoke  SetCaretPos, ebx, eax

;        OutputValue "SetCaretPos return: ", eax, 10, -1

        invoke  ShowCaret, [.hwnd]
        mov     [.caret_changed], 0
        retn


.update_screen:
        mov     eax,[.screen_width]
        mul     [.screen_height]
        mov     ebx, eax
        shl     eax, 2                  ; 4 bytes per character.
        or      eax, eax
        jz      .screen_allocated

        stdcall GetMem, eax

.screen_allocated:

        mov     [.editor_screen], eax
        or      eax,eax
        jz      .screen_prepared

        mov     edi, eax                        ; the characters screen
        lea     ebx, [edi + aeCharSize * ebx]   ; the colors screen? Originally was:  "add     ebx, edi"

        push    ebx
        mov     ecx, [.screen_height]
        mov     esi, [.window_line]

.prepare_screen:
        push    ecx

        push    esi
        push    edi

        lea     edi, [.line_colors]
        mov     ecx, aeLineDataLen shr 2        ; fill colors with 0
        xor     eax,eax
        rep     stosd

        lea     eax, [esi + AELINE.text]
        lea     edi, [.line_colors]

        invoke  .syntax_proc, eax, edi          ; syntax proc

        mov     edx, [.window_position]
        lea     esi, [esi + AELINE.text + aeCharSize*edx]
        mov     eax, aeLineCharLen
        sub     eax, edx

        cmp     eax, [.screen_width]
        jbe     .prepare_line

        mov     eax, [.screen_width]

.prepare_line:
        mov     ecx, eax
        push    eax

        mov     ax, $20
        lea     edi, [esi+aeCharSize*ecx-aeCharSize]

        std
        repe scasw      ; search for the first non-space char.
        cld

        je      .end_of_line            ; empty line found

        add     ecx, 1

        mov     edi, [esp+4]      ; saved EDI
        rep movsw                 ; copy non-empty line.

.end_of_line:
        pop     eax

        lea     esi, [.line_colors + aeCharSize * edx]
        mov     ecx, eax
        mov     edi, ebx
        rep movsw
        mov     ebx, edi        ; next colors line

        pop     edi
        add     edi, [.screen_width_bytes]

        pop     esi

.prepare_next_line:
        pop     ecx

        mov     esi, [esi+AELINE.next]
        dec     ecx
        jz      .prepare_selection

        test    esi,esi
        jnz     .prepare_screen

; EOF: fill the remaning lines with 0

        imul    ecx, [.screen_width]
        xor     eax, eax
        mov     edx, ecx

        rep     stosw

        xchg    edi, ebx
        mov     ecx, edx
        rep     stosw

.prepare_selection:

        pop     ebx

        test    [.editor_style], ES_NOHIDESEL
        jnz     .hidesel_ok

        cmp     [.focus],0
        je      .screen_prepared

    .hidesel_ok:

        cmp     [.sel_line], 0
        je      .screen_prepared

        mov     eax, [.window_line_number]      ; the top line number of the window
        mov     esi, [.sel_line_number]
        mov     edi, [.caret_line_number]

        sub     esi, eax                        ; esi = selection Y, relative to the screen
        sub     edi, eax                        ; edi = caret Y, relative to the screen

        mov     ecx, [.window_position]
        mov     eax, [.sel_position]
        mov     edx, [.caret_position]

        sub     eax, ecx                        ; eax = selection X, relative to the screen
        sub     edx, ecx                        ; edx = caret X, relative to the screen

        cmp     esi, edi
        jle     .sel_boundaries_ok

        xchg    esi, edi                        ; esi = start Y of the selection;
        xchg    eax, edx                        ; edi = end Y of the selection

    .sel_boundaries_ok:

        mov     ecx, [.screen_height]
        cmp     edi, 0
        jl      .screen_prepared                ; the selection is above the top of the screen.

        cmp     esi, ecx                        ; the selection is below the end of the screen.
        jge     .screen_prepared

        cmp     esi, edi
        je      .prepare_vsel                   ; if the start and the end of the selection is on the same line.

        test    [.editor_mode], AEMODE_VERTICALSEL
        jz      .prepare_hsel

; vertical selection.

    .prepare_vsel:

        cmp     eax, edx                        ; sort the X coordinates as well. eax = left; edx = right
        jle     .vsel_boundaries_ok
        xchg    eax, edx
    .vsel_boundaries_ok:

        cmp     esi, 0                          ; if the start Y is negative - start from 0
        jge     .vsel_start_ok
        xor     esi, esi
    .vsel_start_ok:

        inc     edi                             ; if the end Y is greater than the end of the screen, stop there.
        cmp     edi, ecx
        cmovg   edi, ecx

        mov     ecx, [.screen_width]            ; if the right side is to the left of the screen, draw nothing.
        cmp     edx, 0
        jl      .screen_prepared

        cmp     eax, ecx                        ; if the left side is to the right of the screen, draw nothing.
        jge     .screen_prepared

        cmp     eax, 0                          ; if left is negative, draw from 0
        jge     .vsel_line_start_ok
        xor     eax, eax
    .vsel_line_start_ok:

        cmp     edx, ecx                        ; if the right is greater than screen width, draw to the screen width.
        cmovg   edx, ecx

        mov     ecx, edi
        sub     ecx, esi                        ; ecx = (EndY - StartY)
        imul    esi, [.screen_width]            ; esi = start of the first line in characters

        lea     ebx, [ebx+aeCharSize*esi]       ; ebx is the start of the color part of the buffer.
                                                ; here, address of the beginning of the line where selection starts.

    .prepare_vsel_line:

        push    eax ecx         ; eax = left coordinate, ecx = EndY-StartY = vertical lines count.

;???        mov     edi, ebx        ; address of the start of the line
        mov     ecx, edx
        sub     ecx, eax        ; ecx = EndX - StartX

        lea     edi, [ebx + aeCharSize * eax]  ; address of the StartX

        mov     ax, 80h
        rep stosw

        add     ebx, [.screen_width_bytes]

        pop     ecx eax

        loop    .prepare_vsel_line
        jmp     .screen_prepared


; normal selection: ecx = screen height

    .prepare_hsel:

        cmp     esi, 0                  ; if StartY < 0 start from 0,0
        jge     .hsel_start_ok

        xor     esi, esi
        xor     eax, eax

    .hsel_start_ok:

        cmp     edi, ecx                ; if EndY > screen height, end there.
        jl      .hsel_end_ok

        mov     edi, ecx
        xor     edx, edx

    .hsel_end_ok:

        inc     esi                     ; esi = StartY+1
        mov     ecx, edi
        sub     ecx, esi                ; ecx = EndY - StartY - 1

        imul    ecx, [.screen_width]    ; the count of characters to select in the whole lines.
        imul    esi, [.screen_width]    ; the start Y of the selection in chars.

        lea     edi, [ebx + aeCharSize * esi]  ; edi = pointer to the second line of the selection.

        neg     eax
        add     eax, [.screen_width]    ; eax = (screen_width - startX) how many chars are to be selected from the first line.
        cmp     eax, 0
        jle     .hsel_start_line_ok

        sub     edi, eax        ; edi = edi - 2*eax (because in bytes).
        sub     edi, eax

        add     ecx, eax        ; the total count of characters to select.

        sub     eax, [.screen_width]    ; eax = - StartX
        jle     .hsel_start_line_ok

        add     edi, eax
        add     edi, eax
        sub     ecx, eax

    .hsel_start_line_ok:

        cmp     edx, 0
        jle     .hsel_end_line_ok       ; the endX of the selection is to the left of the screen.

        add     ecx, edx                ; edx more characters to select.

        sub     edx, [.screen_width]
        jle     .hsel_end_line_ok

        sub     ecx, edx                ; ???

    .hsel_end_line_ok:

        mov     ax, 80h
        rep stosw

    .screen_prepared:

        retn




.init_editor_memory:

        invoke  VirtualAlloc, 0, aeBigBlockLen, MEM_COMMIT, PAGE_READWRITE
        or      eax,eax
        jz      .memory_error
        mov     [.editor_memory],eax
        mov     dword [eax],0
        mov     dword [eax+4],0
        lea     ebx,[eax+sizeof.AELINE]
        mov     [.unallocated_lines],ebx
        mov     [.memory_search_line],ebx
        add     eax, aeBigBlockLen
        mov     [.unallocated_lines_end],eax
        mov     [.memory_search_block],eax
        clc
        ret
    .memory_error:
        stc
        ret

.reset_editor_memory:
        mov     esi,[.editor_memory]
        lea     eax,[esi+sizeof.AELINE]
        mov     [.unallocated_lines],eax
        mov     [.memory_search_line],eax
        lea     eax,[esi+aeBigBlockLen]
        mov     [.unallocated_lines_end],eax
        mov     [.memory_search_block],eax
        pushd   [esi]
    .decommit:
        pop     ebx
        test    ebx, ebx
        jz      .decommit_done
        pushd   [ebx]
        invoke  VirtualFree, ebx, 0, MEM_RELEASE
        jmp     .decommit

    .decommit_done:
        mov     eax,[.editor_memory]
        mov     [eax],dword 0
        mov     [.undo_data],0
        mov     [.search_text],0
        mov     [.current_operation],0
        ret

.release_editor_memory:
        mov     esi,[.editor_memory]
    .release:
        mov     ebx,[esi]
        invoke  VirtualFree,esi,0,MEM_RELEASE
        mov     esi,ebx
        or      esi,esi
        jnz     .release
        mov     [.editor_memory],0
        ret

.allocate_line:
        mov     eax,[.unallocated_lines]
        mov     ebx,[.memory_search_block]
        mov     esi,[.memory_search_line]
        cmp     eax,[.unallocated_lines_end]
        je      .find_free_line
        add     [.unallocated_lines], sizeof.AELINE
        clc
        ret

    .find_free_line:
        cmp     esi,ebx
        je      .find_in_next_block
        cmp     dword [esi],-1
        je      .reuse_line
        add     esi, sizeof.AELINE
        cmp     esi,[.memory_search_line]
        jne     .find_free_line
        sub     ebx, aeBigBlockLen

    .find_last_memory_block:
        cmp     dword [ebx],0
        je      .allocate_more_memory
        mov     ebx,[ebx]
        jmp     .find_last_memory_block

    .allocate_more_memory:
        invoke  VirtualAlloc, 0, aeBigBlockLen, MEM_COMMIT, PAGE_READWRITE
        or      eax,eax
        jz      .failed
        mov     [ebx],eax
        mov     [eax],dword 0
        mov     [eax+4],ebx
        lea     ebx,[eax+aeBigBlockLen]
        mov     [.unallocated_lines_end],ebx
        add     eax, sizeof.AELINE
        lea     ebx,[eax+sizeof.AELINE]
        mov     [.unallocated_lines],ebx
        clc
        ret
    .failed:
        stc
        ret
    .reuse_line:
        mov     eax,esi
        mov     [.memory_search_block],ebx
        add     esi,sizeof.AELINE
        mov     [.memory_search_line],esi
        clc
        ret

    .find_in_next_block:
        sub     ebx, aeBigBlockLen
        mov     esi,[ebx]
        lea     ebx,[esi+aeBigBlockLen]
        or      esi,esi
        jnz     .find_free_line
        mov     ebx,[.editor_memory]
        mov     esi,ebx
        add     ebx, aeBigBlockLen
        jmp     .find_free_line


.init_editor_data:
        call    .allocate_line
        mov     [.first_line],eax
        mov     [.lines_count],1
        mov     [.caret_line],eax
        mov     [.caret_line_number],1
        mov     [.window_line],eax
        mov     [.window_line_number],1
        mov     edi,eax
        xor     eax,eax
        stosd
        stosd
        mov     eax, $00200020
        mov     ecx, aeLineDataLen shr 2
        rep     stosd
        mov     [.caret_position],0
        mov     [.sel_position], 0
        mov     [.window_position],0
        mov     [.sel_line],0
        mov     [.sel_line_number], 1   ; 11.12.2003 John Found Added, bug fix for
                                        ; some functions immediately after creation
                                        ; of AsmEdit.
        mov     [.undo_data],0
        mov     [.search_text],0
        mov     [.current_operation],0
        mov     [.editor_mode],0
        mov     [.syntax_proc], SyntaxProc
        mov     [.syntax_colors],0
        mov     [.focus],0
        mov     [.mouse_select],0

        ret


.insert_character:
        mov     edx, [.caret_position]
        cmp     edx, aeLineCharLen
        je      .insert_done

        mov     esi, [.caret_line]
        lea     esi, [esi + AELINE.text + aeCharSize*edx]

        test    [.editor_mode], AEMODE_OVERWRITE
        jnz     .overwrite

        mov     ecx, aeLineCharLen
        sub     ecx, edx
        inc     edx
        mov     [.caret_position], edx

        mov     ebx, esi
        mov     edx, ecx

    .shift_data_right_push:

        push    eax

    .shift_data_right:
        xchg    ax, [esi]
        add     esi, aeCharSize
        loop    .shift_data_right

        pop     eax

        test    [.editor_style],AES_AUTOBRACKETS
        jz      .insert_done

        cmp     ax,'('
        je      .round
        cmp     ax,'['
        je      .square
        cmp     ax,'{'
        je      .brace

    .insert_done:
        ret

    .round:
        mov     ax,')'
        jmp     .auto_bracket

    .square:
        mov     ax,']'
        jmp     .auto_bracket

    .brace:
        mov     ax,'}'

    .auto_bracket:
        xor     ah,ah
        mov     ecx, edx
        dec     ecx
        jz      .insert_done

        lea     esi, [ebx+aeCharSize]
        xchg    ax, [esi]
        call    .recognize_character
        jnc     .cancel_bracket

        add     esi, aeCharSize
        dec     ecx
        jnz     .shift_data_right_push

        ret

    .cancel_bracket:
        mov     [esi], ax
        ret

    .overwrite:
        mov     [esi], ax
        inc     [.caret_position]
        ret

; deletes one character on the current caret position and depending on the editor mode.

.delete_character:
        mov     edx, [.caret_position]
        cmp     edx, aeLineCharLen
        je      .delete_done

        mov     esi, [.caret_line]
        mov     ax, 20h

        test    [.editor_mode], AEMODE_OVERWRITE
        jnz     .delete

        add     esi, sizeof.AELINE
        mov     ecx, aeLineCharLen
        sub     ecx, [.caret_position]

    .shift_data_left:
        sub     esi, aeCharSize
        xchg    ax, [esi]
        loop    .shift_data_left

    .delete_done:
        ret

; overwrites the character in position edx, line pointed by esi with the character in ax

    .delete:
        mov     [esi + AELINE.text + aeCharSize*edx], ax
        ret


.recognize_character:
        cmp     ax,20h
        jb      .neutral_character
        cmp     ax,30h
        jb      .separator_character
        cmp     ax,3Ah
        jb      .neutral_character
        cmp     ax,40h
        jb      .separator_character
        cmp     ax,5Bh
        jb      .neutral_character
        cmp     ax,5Fh
        jb      .separator_character
        cmp     ax,7Bh
        jb      .neutral_character
        cmp     ax,7Fh
        jb      .separator_character
    .neutral_character:
        clc
        ret
    .separator_character:
        stc
        ret


.find_line:
        mov     esi,[.first_line]
        mov     ecx,1
        mov     edx,[.window_line_number]
        cmp     eax,edx
        jae     .forward_from_window
        sub     edx,eax
        cmp     edx,eax
        jb      .backward_from_window
        jmp     .find_forward
    .forward_from_window:
        mov     esi,[.window_line]
        mov     ecx,edx
    .find_forward:
        cmp     ecx,eax
        je      .line_found
        cmp     [esi + AELINE.next], 0
        je      .line_found
        inc     ecx
        mov     esi,[esi + AELINE.next]
        jmp     .find_forward
    .backward_from_window:
        mov     esi,[.window_line]
        mov     ecx,[.window_line_number]
    .find_backward:
        cmp     ecx,eax
        je      .line_found
        cmp     [esi+4],dword 0
        je      .line_found
        dec     ecx
        mov     esi,[esi+4]
        jmp     .find_backward
    .line_found:
        ret


.insert_block:
        test    [.editor_mode], AEMODE_VERTICALSEL
        jz      .do_insert_block

; insert vertical block

        push    esi

        or      edx, -1
        xor     ecx, ecx

    .count:
        lodsw
        cmp     ax, 9
        je      .cannot_insert

        cmp     ax, 0Dh
        je      .count_next_line

        or      ax, ax
        jz      .check_count

        inc     ecx
        jmp     .count

    .count_next_line:

        lodsw         ; LF

    .check_count:

        cmp     edx, 0
        jl      .line_to_insert_ok
        je      .cannot_insert

        cmp     edx, ecx
        jne     .cannot_insert

    .line_to_insert_ok:

        mov     edx, ecx
        xor     ecx, ecx

        or      ax, ax
        jz      .do_ins_block ; .cannot_insert

        cmp     word [esi], 0
        jne     .count

.do_ins_block:

        pop     esi

    .do_insert_block:

        mov     eax, [.caret_line]
        mov     [.current_line], eax
        call    .store_line_for_undo

        mov     edx, [eax + AELINE.next]
        mov     [.current_line], edx
        call    .store_line_for_undo

        mov     ebx, eax
        mov     [.sel_line], ebx
        mov     edx, [.caret_position]
        mov     eax, [.caret_line_number]
        mov     [.sel_line_number], eax
        lea     edi, [ebx + AELINE.text + aeCharSize * edx]

        test    [.editor_mode], AEMODE_OVERWRITE
        jnz     .begin_insert

        test    [.editor_mode], AEMODE_VERTICALSEL
        jnz     .begin_insert

        push    esi edi
        mov     esi, edi

        lea     edi, [.line_buffer]
        mov     ecx, aeLineCharLen
        sub     ecx, [.caret_position]
        rep movsw

        mov     ecx, [.caret_position]
        mov     ax, 20h
        rep stosw
        mov     edi, [esp]
        mov     ecx, aeLineCharLen
        sub     ecx, [.caret_position]
        mov     ax, 20h
        rep stosw
        pop     edi esi

    .begin_insert:

        mov     edx, esi        ; esi = the block that have to be inserted.
        xor     ecx, ecx

    .count_characters:

        lodsw

        cmp     ax, 0Dh
        je      .put_string

        cmp     ax, 9
        je      .convert_string

        or      ax, ax
        jz      .put_string

        inc     ecx
        jmp     .count_characters

    .convert_string:

        mov     esi, edx
        push    edi
        lea     edi, [.text_buffer]
        xor     ecx,ecx

    .convert_tabs:

        lodsw
        cmp     ax, 0Dh
        je      .convert_done
        cmp     ax, 9
        je      .insert_tab
        or      ax, ax
        jz      .convert_done
        cmp     ecx, aeLineCharLen
        jae     .convert_tabs
        inc     ecx
        stosw
        jmp     .convert_tabs

    .insert_tab:

        mov     edx, ecx
        and     ecx, not 111b
        sub     ecx, edx
        add     ecx, 8
        add     edx, ecx
        mov     ax, 20h
        rep stosw
        mov     ecx, edx
        jmp     .convert_tabs

    .convert_done:
        lea     edx, [.text_buffer]
        pop     edi

    .put_string:

        xchg    esi, edx
        lea     eax, [ebx + sizeof.AELINE]
        sub     eax, edi
        shr     eax, 1          ; bytes to chars
        cmp     eax, ecx
        jbe     .larger_string

        test    [.editor_mode], AEMODE_VERTICALSEL
        jz      .simple_put

        test    [.editor_mode], AEMODE_OVERWRITE
        jnz     .simple_put

        sub     eax, ecx
        xchg    eax, ecx

        push    esi edi

        lea     esi, [edi + aeCharSize * ecx - aeCharSize]
        lea     edi, [ebx + sizeof.AELINE - aeCharSize]

        std
        rep movsw
        cld

        pop     edi esi

        xchg    eax,ecx

    .simple_put:

        rep movsw
        jmp     .put_ok

    .larger_string:
        xchg    ecx, eax
        sub     eax, ecx
        rep movsw

    .put_ok:
        mov     esi, edx

        cmp     word [esi - aeCharSize], 0
        je      .last_line

        lodsw
        or      ax, ax
        jz      .last_line

;        cmp     byte [esi],0
;        je      .last_line

        test    [.editor_mode], AEMODE_VERTICALSEL
        jnz     .insert_next_line

        test    [.editor_mode], AEMODE_OVERWRITE
        jnz     .overwrite_line

    .insert_new_line:
        push    ebx esi
        call    .allocate_line
        jc      .out_of_memory
        pop     esi ebx
        mov     [.sel_line], eax
        inc     [.sel_line_number]
        mov     [.current_line], eax
        call    .store_line_for_undo

        mov     edi, eax
        mov     edx, [ebx + AELINE.next]
        mov     [edi + AELINE.next], edx
        mov     [edi + AELINE.prev], ebx
        mov     [ebx + AELINE.next], edi
        mov     ebx, edi

        lea     edi, [edi + AELINE.text]
        mov     eax, $00200020
        mov     ecx, aeLineDataLen shr 2
        rep stosd
        inc     [.lines_count]
        or      edx, edx
        jz      .insert_into_line

        mov     [edx + AELINE.prev], ebx
        jmp     .insert_into_line

    .overwrite_line:

        lea     ecx, [ebx+sizeof.AELINE]
        sub     ecx, edi
        shr     ecx, 1          ; bytes to characters

        mov     ax, 20h
        rep stosw

    .insert_next_line:

        mov     eax, [ebx + AELINE.next]
        or      eax, eax
        jz      .insert_new_line

        mov     ebx, eax
        mov     [.sel_line], ebx
        inc     [.sel_line_number]
        mov     [.current_line], eax
        call    .store_line_for_undo

    .insert_into_line:

        mov     edx, esi
        xor     ecx, ecx
        lea     edi, [ebx + AELINE.text]
        test    [.editor_mode], AEMODE_VERTICALSEL
        jz      .count_characters

        add     edi, [.caret_position]
        add     edi, [.caret_position]
        jmp     .count_characters

    .last_line:

        test    [.editor_mode], AEMODE_OVERWRITE
        jnz     .block_inserted

        test    [.editor_mode], AEMODE_VERTICALSEL
        jnz     .block_inserted

        lea     eax, [ebx+sizeof.AELINE]
        cmp     edi, eax
        jae     .block_inserted

        push    edi
        mov     ecx, eax
        sub     ecx, edi
        shr     ecx, 1                  ; bytes to characters
        lea     esi, [.line_buffer]

        rep movsw
        pop     edi

    .block_inserted:

        lea     ebx, [ebx + AELINE.text]
        mov     eax, edi
        sub     eax, ebx
        shr     eax, 1          ; bytes to char position
        mov     [.sel_position], eax
        clc
        ret

    .cannot_insert:
        pop     esi
        stc
        ret


.delete_block:

        mov     eax, [.sel_line]
        mov     ebx, [.sel_position]
        mov     ecx, [.caret_line]
        mov     edx, [.caret_position]
        mov     esi, [.sel_line_number]

        test    [.editor_mode], AEMODE_VERTICALSEL
        jnz     .delete_vertical

; delete normal selection

        cmp     esi, [.caret_line_number]
        jb      .boundaries_for_delete_ok
        ja      .exchange_boundaries_for_delete
        cmp     ebx, edx
        jb      .boundaries_for_delete_ok

    .exchange_boundaries_for_delete:             ; sort selection coordinates.

        xchg    eax, ecx                         ; eax = StartY; ecx = EndY
        xchg    ebx, edx                         ; ebx = StartX; edx = EndX
        mov     esi, [.caret_line_number]        ; esi = Line number of StartY

    .boundaries_for_delete_ok:

        mov     [.caret_line], eax
        mov     [.caret_line_number], esi
        mov     esi, eax
        mov     [.sel_line], 0
        test    [.editor_mode], AEMODE_OVERWRITE
        jnz     .overwrite_delete

        mov     [.caret_position], ebx
        mov     [.current_line], eax
        call    .store_line_for_undo

        mov     edi, eax
        cmp     eax, ecx
        je      .delete_from_line
        mov     eax, [eax + AELINE.next]

    .delete_line:
        mov     [.current_line], eax
        call    .store_line_for_undo
        mov     esi, eax
        cmp     eax, [.window_line]
        jne     .release_line
        mov     eax, [.caret_line]
        mov     [.window_line], eax
        mov     eax, [.caret_line_number]
        mov     [.window_line_number], eax

    .release_line:
        cmp     esi, ecx
        je      .lines_deleted

        or      eax, -1
        xchg    [esi + AELINE.next], eax  ; free the line block
        dec     [.lines_count]
        jmp     .delete_line

    .lines_deleted:
        mov     eax, [esi+AELINE.next]
        mov     [edi+AELINE.next], eax

        or      eax,eax
        jz      .delete_last_line

        mov     [.current_line], eax
        call    .store_line_for_undo
        mov     eax, [.current_line]
        mov     [eax+AELINE.prev], edi

    .delete_last_line:
        or      dword [esi], -1

    .delete_from_line:
        lea     edi,[edi + AELINE.text + aeCharSize * ebx]
        lea     esi,[esi + AELINE.text + aeCharSize * edx]
        mov     ecx, aeLineCharLen
        sub     ecx, ebx
        xor     eax, eax
        cmp     ebx, edx
        jae     .move_remaining_data

        mov     ecx, aeLineCharLen
        sub     ecx, edx
        mov     eax, edx
        sub     eax, ebx

    .move_remaining_data:
        rep movsw
        mov     ecx, eax
        mov     ax, 20h
        rep stosw

    .block_deleted:
        ret

    .overwrite_delete:
        push    ecx
        mov     ecx, aeLineCharLen
        sub     ecx, ebx
        lea     edi, [esi + AELINE.text + aeCharSize * ebx]
        pop     ebx

    .fill_with_spaces:
        cmp     esi, ebx
        jne     .end_fill_ok

        sub     ecx, aeLineCharLen
        add     ecx, edx

    .end_fill_ok:
        mov     ax,20h
        rep stosw
        cmp     esi, ebx
        je      .block_deleted

        mov     esi, [esi + AELINE.next]
        mov     [.current_line],esi
        call    .store_line_for_undo

        mov     ecx, aeLineCharLen
        lea     edi, [esi+AELINE.text]
        jmp     .fill_with_spaces

    .delete_vertical:

        cmp     esi, [.caret_line_number]
        jbe     .vboundaries_for_delete_ok

        xchg    eax,ecx

    .vboundaries_for_delete_ok:

        cmp     ebx, edx
        jbe     .hboundaries_for_delete_ok
        xchg    ebx, edx

    .hboundaries_for_delete_ok:

        mov     [.sel_line], 0
        mov     esi, eax
        mov     edi, ecx
        mov     [.current_line], esi
        call    .store_line_for_undo

        test    [.editor_mode],AEMODE_OVERWRITE
        jnz     .vertical_fill

        mov     [.caret_position], ebx

    .cut_from_line:

        push    esi edi
        lea     edi, [esi + AELINE.text + aeCharSize * ebx]
        lea     esi, [esi + AELINE.text + aeCharSize * edx]
        mov     ecx, aeLineCharLen
        sub     ecx, edx
        rep movsw
        mov     ecx, edx
        sub     ecx, ebx
        mov     ax, 20h
        rep stosw
        pop     edi esi
        cmp     esi,edi
        je      .block_deleted

        mov     esi, [esi+AELINE.next]
        mov     [.current_line], esi
        call    .store_line_for_undo
        jmp     .cut_from_line

    .vertical_fill:
        push    edi
        lea     edi,[esi + AELINE.text + aeCharSize * ebx]
        mov     ecx, edx
        sub     ecx, ebx
        mov     ax, 20h
        rep stosw
        pop     edi
        cmp     esi, edi
        je      .block_deleted
        mov     esi, [esi + AELINE.next]
        mov     [.current_line], esi
        call    .store_line_for_undo
        jmp     .vertical_fill


.copy_block:

        mov     esi, [.sel_line]
        mov     eax, [.caret_line]
        mov     ebx, [.sel_position]
        mov     edx, [.caret_position]
        mov     ecx, [.sel_line_number]
        test    [.editor_mode], AEMODE_VERTICALSEL
        jnz     .copy_vertical_block

        cmp     ecx,[.caret_line_number]
        jb      .boundaries_for_copy_ok
        ja      .exchange_boundaries_for_copy
        cmp     ebx,edx
        jb      .boundaries_for_copy_ok

    .exchange_boundaries_for_copy:

        xchg    esi,eax
        xchg    ebx,edx

    .boundaries_for_copy_ok:

        cmp     esi, eax
        je      .hboundaries_for_copy_ok

        push    esi edi
        lea     edi, [esi+sizeof.AELINE-aeCharSize]
        lea     esi, [esi+AELINE.text+ aeCharSize * ebx]
        mov     ecx, aeLineCharLen
        sub     ecx,ebx
        mov     ebx,eax
        jmp     .get_line_size

    .copy_whole_line:

        mov     esi, [esi+AELINE.next]
        cmp     esi, ebx
        je      .copy_last_line

        push    esi edi
        lea     esi, [esi + AELINE.text]
        lea     edi, [esi + aeLineDataLen - aeCharSize]
        mov     ecx, aeLineCharLen

    .get_line_size:

        mov     ax,20h
        std
        repe scasw
        setne   al
        movzx   eax,al
        add     ecx,eax
        cld
        pop     edi
        rep movsw
        mov     dword [edi], $000A000D
        add     edi, 4
        pop     esi
        jmp     .copy_whole_line

    .copy_last_line:

        lea     esi, [esi+AELINE.text]
        mov     ecx, edx
        rep movsw

        test    ecx, ecx
        jz      .eol_ok

        mov     eax, $000A000D
        stosd

    .eol_ok:
        xor     ax,ax
        stosw
        ret

    .copy_vertical_block:

        cmp     ecx,[.caret_line_number]
        jb      .vboundaries_for_copy_ok
        xchg    esi,eax

    .vboundaries_for_copy_ok:

        cmp     ebx,edx
        jb      .hboundaries_for_copy_ok
        xchg    ebx,edx

    .hboundaries_for_copy_ok:

        push    esi
        lea     esi,[esi+AELINE.text + aeCharSize * ebx]
        mov     ecx, edx
        sub     ecx, ebx
        rep movsw
        pop     esi
        cmp     esi,eax
        je      .block_copied

        mov     dword [edi], $000A000D
        add     edi, 4

        mov     esi, [esi + AELINE.next]
        jmp     .hboundaries_for_copy_ok

    .block_copied:

        xor     ax,ax
        stosw
        ret

.get_block_size:

        xor     ecx,ecx
        mov     esi,[.sel_line]
        mov     eax,[.caret_line]
        mov     ebx,[.sel_position]
        mov     edx,[.caret_position]
        mov     edi,[.sel_line_number]
        test    [.editor_mode],AEMODE_VERTICALSEL
        jnz     .vertical_block

        cmp     edi, [.caret_line_number]
        jb      .boundaries_ok
        ja      .exchange_boundaries
        cmp     ebx,edx
        jb      .boundaries_ok

    .exchange_boundaries:
        xchg    esi, eax
        xchg    ebx, edx

    .boundaries_ok:
        xor     ecx, ecx
        cmp     esi, eax
        je      .hboundaries_ok

        add     edx, ecx
        mov     ecx, aeLineCharLen
        sub     ecx, ebx
        mov     ebx, eax
        lea     edi, [esi + AELINE.text + aeLineDataLen - aeCharSize]
        jmp     .count_line_bytes

    .whole_line:
        mov     esi, [esi]
        cmp     esi, ebx
        je      .block_size_ok

        lea     edi, [esi + AELINE.text + aeLineDataLen - aeCharSize]
        mov     ecx, aeLineCharLen

    .count_line_bytes:
        mov     ax, 20h
        std
        repe    scasw
        setne   al
        movzx   eax, al
        add     ecx, eax
        cld
        add     edx, ecx
        add     edx, 2
        jmp     .whole_line

    .block_size_ok:
        mov     ecx,edx
        add     ecx,3
        ret
    .vertical_block:
        cmp     edi,[.caret_line_number]
        jb      .vboundaries_ok
        xchg    esi,eax
    .vboundaries_ok:
        cmp     ebx,edx
        jb      .hboundaries_ok
        xchg    ebx,edx
    .hboundaries_ok:
        add     ecx,edx
        sub     ecx,ebx
        add     ecx,2
        cmp     esi,eax
        je      .vertical_block_size_ok
        mov     esi,[esi]
        jmp     .hboundaries_ok
    .vertical_block_size_ok:
        inc     ecx
        ret

.find_text:
        push    edi edx                         ; edi is the caret line.
        lea     edi, [edi+AELINE.text]
        mov     esi, [.search_text]
        test    byte [esi],AEFIND_BACKWARD
        jnz     .backward

        mov     ecx, aeLineCharLen
        sub     ecx,edx
        jz      .not_found

        lea     edi, [edi + aeCharSize * edx]
        test    byte [esi], AEFIND_CASESENSITIVE
        jnz     .case_ok

        mov     esi, edi
        lea     edi, [.text_buffer]

        push    ecx

    .convert_case:
        movzx   eax, word [esi]
        lea     esi, [esi+2]

        push    ecx edx
        invoke  CharLowerW, eax
        pop     edx ecx

        stosw
        loop    .convert_case

        pop     ecx
        lea     edi, [.text_buffer]
        mov     esi, [.search_text]

    .case_ok:
        mov     edx, ecx
        cmp     ecx, [esi+4]
        jb      .not_found

    .search:
        mov     ax, [esi+8]
        repne scasw
        jne     .not_found

        mov     eax, [esi+4]
        dec     eax
        jz      .found
        cmp     ecx, eax
        jb      .not_found

        push    ecx esi edi
        mov     ecx,eax
        lea     esi, [esi+ AELINE.text + aeCharSize]
        repe cmpsw
        pop     edi esi ecx

        jne     .search

    .found:
        mov     eax, edx
        sub     eax, ecx
        dec     eax
        add     eax, [esp]
        test    byte [esi], AEFIND_WHOLEWORDS
        jz      .found_ok

        or      eax, eax
        jz      .left_bound_ok
        mov     ebx, [esp+4]       ; the caret line.

        push    eax
        mov     ax, [ebx + AELINE.text + aeCharSize * eax - aeCharSize]
        call    .recognize_character
        pop     eax

        jnc     .search

    .left_bound_ok:
        mov     ebx, [esi+4]
        add     ebx, eax
        cmp     ebx, aeLineCharLen
        je      .found_ok

        add     ebx, ebx                ; in bytes.
        add     ebx, [esp+4]
        push    eax

        mov     ax, [ebx+8]
        call    .recognize_character
        pop     eax
        jnc     .search

    .found_ok:
        pop     edx edi
        cld
        clc
        ret

    .backward:
        std
        or      edx,edx
        jz      .not_found

        mov     ecx, edx
        lea     edi, [edi + aeCharSize * edx - aeCharSize]
        mov     esi, [.search_text]

        test    byte [esi], AEFIND_CASESENSITIVE
        jnz     .backward_case_ok

        mov     esi, edi
        lea     edi, [.text_buffer + aeCharSize * ecx - aeCharSize]
        push    ecx

    .convert_case_backward:
        movzx   eax, word [esi]
        lea     esi, [esi-aeCharSize]

        push    ecx edx
        invoke  CharLowerW, eax
        pop     edx ecx

        stosw
        loop    .convert_case_backward

        pop     ecx
        lea     edi, [.text_buffer + aeCharSize * ecx - aeCharSize]
        mov     esi, [.search_text]

    .backward_case_ok:
        cmp     ecx, [esi + 4]
        jb      .not_found

    .backward_search:
        mov     eax, [esi + 4]
        mov     ax, [esi + AELINE.text + aeCharSize*eax - aeCharSize]
        repne scasw
        jne     .not_found

        mov     eax, [esi+4]
        dec     eax
        jz      .found_in_backward

        cmp     ecx, eax
        jb      .not_found

        push    ecx esi edi
        mov     ecx,eax
        lea     esi,[esi + AELINE.text + aeCharSize*eax - aeCharSize]
        repe cmpsw
        pop     edi esi ecx

        jne     .backward_search

    .found_in_backward:

        mov     eax, ecx
        inc     eax
        mov     ebx, eax
        sub     eax, [esi+4]
        test    byte [esi], AEFIND_WHOLEWORDS
        jz      .found_ok

        cmp     ebx, aeLineCharLen
        je      .right_bound_ok

        add     ebx, ebx                ; in bytes.
        add     ebx, [esp+4]

        push    eax
        mov     ax, [ebx + AELINE.text]
        call    .recognize_character
        pop     eax
        jnc     .backward_search

    .right_bound_ok:

        or      eax,eax
        jz      .found_ok

        mov     ebx, [esp+4]

        push    eax
        mov     ax, [ebx + AELINE.text + aeCharSize * eax - aeCharSize]
        call    .recognize_character
        pop     eax

        jnc     .backward_search
        jmp     .found_ok

    .not_found:
        pop     edx edi
        cld
        stc
        ret


.store_status_for_undo:
        test    [.editor_mode], AEMODE_NOUNDO
        jnz     .end_ststundo

        pusha
        cmp     [.was_selection],0
        jne     .selection_ok
        mov     [.sel_line],0

    .selection_ok:
        call    .allocate_line
        jc      .not_enough_memory
        mov     [eax],dword 0
        mov     edi,eax
        xchg    eax,[.undo_data]
        push    eax
        call    .allocate_line
        jnc     .store_editor_status
        or      eax,-1
        stosd
        jmp     .not_enough_memory

    .store_editor_status:
        mov     [eax],dword 0
        mov     [eax+4],dword 0
        stosd
        pop     eax
        stosd
        lea     esi,[.editor_data]
        mov     ecx,.editor_status_size shr 2
        rep     movsd
        popa

.end_ststundo:
        clc
        ret


.store_line_for_undo:
        test    [.editor_mode], AEMODE_NOUNDO
        jnz     .end_stlnundo

        pusha
        cmp     [.current_line], 0
        je      .line_for_undo_ok

        mov     [.Modified], TRUE       ; John Found 25.11.2003

        mov     esi, [.undo_data]
        or      esi,esi
        jz      .line_for_undo_ok

        mov     esi, [esi]
        mov     ecx, [esi+4]
        lea     edi, [esi+8+ecx*8]
        inc     ecx
        cmp     ecx, 20h
        jbe     .slot_ok

        push    esi
        call    .allocate_line
        jc      .out_of_memory
        mov     esi,eax
        mov     ebx,[.undo_data]
        mov     [ebx],esi
        pop     dword [esi]
        mov     ecx,1
        lea     edi,[esi+8]

    .slot_ok:
        mov     [esi+4],ecx
        mov     esi,[.current_line]
        mov     eax,[esi]
        cmp     eax,-1
        jne     .store_line
        stosd
        mov     eax,esi
        stosd
        jmp     .line_for_undo_ok

    .store_line:
        call    .allocate_line
        jc      .out_of_memory
        mov     ebx,eax
        stosd
        mov     eax,[.current_line]
        stosd
        mov     esi,eax
        mov     edi,ebx
        mov     ecx,sizeof.AELINE shr 2
        rep     movsd

    .line_for_undo_ok:
        popa

.end_stlnundo:
        ret


.undo:
        mov     esi,[.undo_data]
        or      esi,esi
        jz      .undo_ok
        or      ebx,-1
        xchg    ebx,[esi]
        add     esi,4
        lodsd
        mov     [.undo_data],eax
        lea     edi,[.editor_data]
        mov     ecx,.editor_status_size shr 2
        rep     movsd
    .lines_block:
        or      ebx,ebx
        jz      .undo_ok
        mov     esi,ebx
        or      ebx,-1
        xchg    ebx,[esi]
        add     esi,4
        lodsd
        mov     ecx,eax
        jecxz   .undo_ok
        lea     esi,[esi+ecx*8]
    .restore_lines:
        sub     esi,8
        push    esi ecx
        mov     edi,[esi+4]
        mov     esi,[esi]
        or      esi,esi
        jz      .restore_next
        cmp     esi,-1
        jne     .restore_data
        mov     eax,esi
        stosd
        jmp     .restore_next
    .restore_data:
        mov     ecx,sizeof.AELINE shr 2
        rep     movsd
        or      dword [esi-sizeof.AELINE],-1
    .restore_next:
        pop     ecx esi
        loop    .restore_lines
        jmp     .lines_block
    .undo_ok:
        ret


.clear_undo_data:
        mov     esi,[.undo_data]
        or      esi,esi
        jz      .undo_data_ok
        or      ebx,-1
        xchg    ebx,[esi]
        add     esi,4
        lodsd
        mov     [.undo_data],eax
    .release_lines_block:
        or      ebx,ebx
        jz      .clear_undo_data
        mov     esi,ebx
        or      ebx,-1
        xchg    ebx,[esi]
        add     esi,4
        lodsd
        mov     ecx,eax
        jecxz   .clear_undo_data
        lea     esi,[esi+ecx*8]
    .release_lines:
        sub     esi,8
        mov     eax,[esi]
        cmp     eax,-1
        je      .release_next
        or      dword [eax],-1
    .release_next:
        loop    .release_lines
        jmp     .release_lines_block
    .undo_data_ok:
        mov     [.last_operation],0
        ret

endp

proc SyntaxProc, .lpLine, .lpColors
begin
        return
endp
