virtual at 0
editor_data:
	.hPlugin	dd	?
	.hFile		dd	?
if (.hPlugin <> viewer_data.hPlugin) | (.hFile <> viewer_data.hFile)
error in viewer_IsHandleUsed/editor_IsHandleUsed
end if
	.memsize	dd	?
	.encoding	db	?
	.flags		db	?	; & 0x80: modified
					; & 0x40: file is locked
					; & 0x20: next key as a symbol
					; & 0x10: replace mode (vs insert)
	.eol		db	?
			rb	1
	.first_block	dd	?
	.last_block	dd	?
	.numfree	dd	?
	.freeblocks	dd	?
	.numlines	dd	?
	.curline	dd	?
	.curcol		dd	?
	;.curpos_block	dd	?
	;.curpos_offs	dd	?
	.cur_block	dd	?
	.cur_offs	dd	?
	.cur_delta	dd	?
	.cursor_x	dd	?
	.cursor_y	dd	?
	align 200h
	.filename	rb	1024
	.hostname	rb	1024
if (.filename <> viewer_data.filename) | (.hostname <> viewer_data.hostname)
error in viewer_getname/editor_getname
end if
	.buf		rb	16384	; all I/O operations use this buffer
	.basesize = $
	.linedata_start:
end virtual

virtual at 0
editor_line:
	.block		dd	?
	.offs		dw	?
	;.length		dd	?
	.plugdata:
end virtual

; when a file is loaded into the editor, this file is fragmented to blocks
; each block has RESERVE_IN_BLOCK empty bytes to allow quick inserting
; must be dword-aligned!
edit.RESERVE_IN_BLOCK = 16
edit.eol_dos = 1	; DOS/Win EOLn style (0D 0A)
edit.eol_unix = 2	; Unix EOLn style (0A)
edit.eol_mac = 3	; MacOS EOLn style (0D)

virtual at 0
edit_block_header:
	.next		dd	?
	.prev		dd	?
	.limit		dd	?
	.size = $	; must be dword-aligned
end virtual

edit_file:
	mov	eax, [ebp + panel1_files - panel1_data]
	mov	ecx, [eax+ecx*4]
	test	byte [ecx], 10h
	jz	.file
	ret
.file:
; calculate required memory size
	cmp	dword [ecx+36], 0
	jnz	.nomemory
; block size = 4096
; block header: edit_block_header.size bytes
; some plugin-specific data can follow
; reserve RESERVE_IN_BLOCK free bytes in the end of block
	mov	ebx, 4096
	mov	eax, [EditPlugInfo]
	add	eax, edit_block_header.size
	mov	[EditBlockStart], eax
	sub	ebx, eax
	sub	ebx, edit.RESERVE_IN_BLOCK
	mov	[EditBlockSize], ebx
; now ebx = size of file data in each block
	mov	eax, [ecx+32]
; if eax == 0, set eax = 1
	sub	eax, 1
	adc	eax, 1
	xor	edx, edx
	div	ebx
	sub	edx, 1
	sbb	eax, -1
	add	eax, [EditDataSize]
; eax = number of blocks + memory for editor_data structure
	cmp	eax, 0x80000000 shr 12
	jb	.memok
.nomemory:
	push	aEditNoMemory
	mov	eax, esp
	push	ContinueBtn
	push	1
	push	eax
	push	1
	call	SayErr
	pop	eax
	ret
.memok:
	lea	esi, [ebp + panel1_dir - panel1_data]
	push	eax
	push	ecx
	mov	ecx, eax
	shl	ecx, 12
	mov	edx, editor_vtable
	call	new_screen
	pop	ecx
	pop	ebx
	test	eax, eax
	jnz	@f
	ret
@@:
	mov	[ebp + editor_data.memsize], ebx
	mov	al, [EditEOLStyle]
	mov	[ebp + editor_data.eol], al
	mov	eax, dword [esi + panel1_hPlugin - panel1_dir]
	mov	[ebp + editor_data.hPlugin], eax
	test	eax, eax
	jz	.nocopyhostname
	lea	edi, [ebp + editor_data.hostname]
	push	esi
	mov	eax, dword [esi + panel1_parents - panel1_dir]
	mov	esi, dword [esi + panel1_parents_sz - panel1_dir]
	add	esi, eax
@@:
	dec	esi
	cmp	byte [esi-1], 0
	jz	@f
	cmp	byte [esi-1], '/'
	jnz	@b
@@:
	lodsb
	stosb
	test	al, al
	jnz	@b
	pop	esi
.nocopyhostname:
	mov	eax, dword [esi + panel1_hFile - panel1_dir]
	mov	[ebp + editor_data.hFile], eax
	mov	[ebp + editor_data.encoding], encodings.cp866
	xor	eax, eax
	mov	[ebp + editor_data.flags], al
	inc	eax
	mov	[ebp + editor_data.numlines], eax
	lea	edi, [ebp + editor_data.filename]
	mov	ebx, readinfo
	mov	[ebx+21], edi
@@:
	lodsb
	test	al, al
	jz	@f
	stosb
	jmp	@b
@@:
	lea	esi, [ecx+40]
	mov	al, '/'
	cmp	byte [edi-1], al
	jz	@f
	stosb
@@:
	lodsb
	stosb
	test	al, al
	jnz	@b
; load file into memory
	mov	esi, [ebp + editor_data.memsize]
	mov	edi, [EditDataSize]
	sub	esi, edi	; esi = number of blocks
	shl	edi, 12
	;mov	[ebp + editor_data.curpos_block], edi
	mov	[ebp + editor_data.first_block], edi
	mov	[ebp + editor_data.cur_block], edi
	add	edi, ebp	; edi -> first block
	mov	[ebp + editor_data.linedata_start + editor_line.block], edi
	xor	eax, eax
	mov	[ebx+4], eax
	mov	[ebx+8], eax
	mov	dword [ebx+12], 16384
	lea	eax, [ebp + editor_data.buf]
	mov	[ebx+16], eax
	mov	edx, [ebp + editor_data.hPlugin]
	test	edx, edx
	jz	@f
	pushad
	push	O_READ
	push	dword [ebx+21]
	push	[ebp + editor_data.hFile]
	call	[edx + PluginInfo.open]
	mov	[esp+1Ch], eax
	popad
	test	eax, eax
	jz	..openerr_in_screen
	mov	ebx, eax
@@:
	mov	ecx, [EditBlockSize]	; bytes rest in the current block
	add	edi, [EditBlockStart]
.readloop:
	mov	edx, [ebp + editor_data.hPlugin]
	test	edx, edx
	jz	.readnative
	pushad
	push	16384
	push	[readinfo.data]
	push	ebx
	call	[edx + PluginInfo.read]
	mov	[esp+1Ch], eax
	popad
	cmp	eax, -1
	jnz	.readok
; let us hope that plugin says error itself
	push	ebp
	push	ebx
	call	[edx + PluginInfo.close]
	pop	ebp
	jmp	.readfailed
.readnative:
	push	ebx
	push	70
	pop	eax
	int	40h
	mov	edx, ebx
	xchg	eax, edx
	pop	ebx
	add	dword [ebx+4], eax
	adc	dword [ebx+8], 0
	test	edx, edx
	jz	.readok
	cmp	edx, 6
	jz	.readok
	push	dword [ebx+21]
	push	aCannotReadFile
	xchg	eax, edx
	call	get_error_msg
	push	eax
	mov	eax, esp
	push	RetryOrCancelBtn
	push	2
	push	eax
	push	3
	call	SayErr
	add	esp, 3*4
	test	eax, eax
	jz	.readnative
.readfailed:
	jmp	delete_active_screen
.readok:
; eax = number of bytes read
	test	eax, eax
	jnz	@f
	push	edi
	sub	edi, ebp
	cmp	edi, [ebp + editor_data.first_block]
	pop	edi
	jnz	.readdone
@@:
	push	eax ebx
	mov	ebx, [readinfo.data]
.loadloop:
	test	ecx, ecx
	jnz	.hasplace
	push	eax
	dec	esi
	jns	.hasblock
	add	[ebp + editor_data.memsize], 8
	add	esi, 8
	mov	ecx, [ebp + editor_data.memsize]
	cmp	ecx, 80000000h shr 12
	jb	@f
.nomemory2:
	pop	eax ebx eax
	call	.nomemory
	jmp	.readfailed
@@:
	sub	edi, ebp
	shl	ecx, 12
	mov	edx, ebp
	call	xpgrealloc
	test	eax, eax
	jz	.nomemory2
	add	edi, eax
	xchg	ebp, eax
.hasblock:
	push	edi
	and	edi, not 0xFFF
	lea	eax, [edi + 0x1000]
	sub	eax, ebp
	stosd	; edit_block_header.next
	sub	eax, 0x2000
	stosd	; edit_block_header.prev
	pop	eax
	sub	eax, edi
	add	eax, 8
	stosd	; edit_block_header.limit
	mov	ecx, [EditPlugInfo]
	inc	ecx
	jz	@f
	dec	ecx
@@:
	xor	eax, eax
	rep	stosb	; info for plugins: zeroed
	add	edi, 0x1000
	mov	ecx, [EditBlockSize]
	pop	eax
.hasplace:
	push	ecx
	cmp	eax, ecx
	ja	@f
	mov	ecx, eax
@@:
	push	ecx
	push	eax
	push	esi edi
	mov	esi, ebx
	mov	edx, ecx
	shr	ecx, 2
	rep	movsd
	mov	ecx, edx
	and	ecx, 3
	rep	movsb
	mov	ebx, esi
	mov	ecx, edx
	pop	esi
; calculate number of lines in this block
	test	ecx, ecx
	jz	.4
	mov	al, [esi - 1]
	mov	edx, esi
	sub	edx, [EditBlockStart]
	test	edx, 0xFFF
	jnz	.0
	mov	al, 0
	sub	edx, ebp
	cmp	edx, [ebp + editor_data.first_block]
	jz	.0
	sub	edx, 1000h
	add	edx, ebp
	add	edx, [edx + edit_block_header.limit]
	mov	al, [edx - 1]
.0:
	xor	edx, edx
	cmp	al, 13
	jnz	.1
	mov	dl, 10
.1:
	mov	al, [esi]
	add	esi, 1
	cmp	al, 13
	jz	@f
	cmp	al, 10
	jz	@f
	mov	dl, 0
	sub	ecx, 1
	jnz	.1
	jmp	.4
@@:
	cmp	al, dl
	mov	dl, 0
	jz	.3
	add	[ebp + editor_data.numlines], 1
	cmp	al, 10
	jz	.3
	mov	dl, 10
.3:
	sub	ecx, 1
	jnz	.1
.4:
	pop	esi
	pop	eax
	pop	ecx
	sub	[esp], ecx
	sub	eax, ecx
	pop	ecx
	jnz	.loadloop
	pop	ebx eax
	cmp	eax, 16384
	jz	.readloop
.readdone:
	push	edi
	and	edi, not 0xFFF
	xor	eax, eax
	stosd	; editor_block_header.next
	lea	eax, [edi - 4 - 0x1000]
	sub	eax, ebp
	stosd	; editor_block_header.prev
	pop	eax
	sub	eax, edi
	add	eax, 8
	stosd	; editor_block_header.limit
	mov	ecx, [EditPlugInfo]
	inc	ecx
	jz	@f
	dec	ecx
@@:
	xor	eax, eax
	rep	stosb
	and	edi, not 0xFFF
	lea	ecx, [edi + 0x1000]
	sub	ecx, ebp
	mov	edx, ecx
	shr	ecx, 12
	sub	ecx, [ebp + editor_data.memsize]
	neg	ecx
	mov	[ebp + editor_data.numfree], ecx
	jz	.nofree
	mov	[ebp + editor_data.freeblocks], edx
	push	edi
.addfree:
	add	edi, 1000h
	add	edx, 1000h
	mov	[edi], edx
	loop	.addfree
	mov	[edi], eax
	pop	edi
.nofree:
	sub	edi, ebp
	mov	[ebp + editor_data.last_block], edi
	mov	ecx, [EditDataSize]
	shl	ecx, 12
	mov	[ecx + ebp + edit_block_header.prev], eax
	mov	[ebp + editor_data.curline], eax
	mov	[ebp + editor_data.curcol], eax
	mov	[ebp + editor_data.cursor_x], eax
	inc	eax
	mov	[ebp + editor_data.cursor_y], eax
	mov	eax, [EditBlockStart]
	;mov	[ebp + editor_data.curpos_offs], eax
	mov	[ebp + editor_data.linedata_start + editor_line.offs], ax
	mov	[ebp + editor_data.cur_offs], eax
	mov	ecx, [ebp + editor_data.first_block]
	cmp	[ecx + edit_block_header.limit], eax
	setz	cl
	movzx	ecx, cl
	dec	ecx
	mov	[ebp + editor_data.cur_delta], ecx
	call	editor_init_lines
editor_OnRedraw:
	mov	eax, [ebp + editor_data.cursor_x]
	mov	[cursor_x], eax
	mov	eax, [ebp + editor_data.cursor_y]
	mov	[cursor_y], eax
	test	[ebp + editor_data.flags], 10h
	jz	@f
	mov	[cursor_size], cursor_big_size
@@:
	call	editor_test_cursor_x
	call	editor_test_cursor_y
	call	editor_set_keybar
	call	editor_draw_text
	ret

editor_save:
	cmp	[ebp + editor_data.hPlugin], 0
	jz	.native
	push	aCannotSaveToPlugin
	mov	eax, esp
	push	ContinueBtn
	push	1
	push	eax
	push	1
	call	SayErr
	pop	eax
	ret
.native:
	call	editor_calc_filesize
	mov	ebx, writeinfo
	mov	[ebx+4], eax
	xor	eax, eax
	mov	[ebx+8], eax
	mov	[ebx+12], eax
	mov	[ebx+16], eax
	lea	eax, [ebp + editor_data.filename]
	mov	[ebx+21], eax
.setsize_retry:
	mov	byte [ebx], 4
	push	70
	pop	eax
	push	ebx
	int	0x40
	pop	ebx
	mov	byte [ebx], 3
	test	eax, eax
	jz	.sizeok
	push	dword [ebx+21]
	push	aCannotWriteFile
	call	get_error_msg
	push	eax
	mov	eax, esp
	push	RetryOrCancelBtn
	push	2
	push	eax
	push	3
	call	SayErr
	add	esp, 12
	test	eax, eax
	jz	.setsize_retry
.ret:
	ret
.sizeok:
	and	dword [ebx+4], 0
	mov	esi, [ebp + editor_data.first_block]
	add	esi, ebp
	mov	ebx, [EditBlockStart]
	call	editor_normalize_offs
	jnc	.writeok
	lea	edi, [ebp + editor_data.buf]
.loop:
	mov	ecx, 16384
	call	editor_get_data
	test	eax, eax
	jz	.done
	push	ebx
	mov	ebx, writeinfo
	mov	[ebx+12], eax
	mov	[ebx+16], edi
.write_retry:
	push	70
	pop	eax
	push	ebx
	int	0x40
	pop	ebx
	test	eax, eax
	jz	.writeok
	push	dword [ebx+21]
	push	aCannotWriteFile
	call	get_error_msg
	push	eax
	mov	eax, esp
	push	RetryOrCancelBtn
	push	2
	push	eax
	push	3
	call	SayErr
	add	esp, 12
	test	eax, eax
	jz	.write_retry
	ret
.writeok:
	mov	eax, [ebx+12]
	add	[ebx+4], eax
	adc	dword [ebx+8], 0
	pop	ebx
	jmp	.loop
.done:
	and	[ebp + editor_data.flags], not 0x80
	ret

editor_calc_filesize:
	xor	eax, eax
	push	esi
	mov	esi, [ebp + editor_data.first_block]
@@:
	add	esi, ebp
	add	eax, [esi + edit_block_header.limit]
	sub	eax, [EditBlockStart]
	mov	esi, [esi + edit_block_header.next]
	test	esi, esi
	jnz	@b
	pop	ebx
	ret

editor_get_data:
	push	edi
	test	esi, esi
	jz	.ret
.loop:
	mov	edx, [esi + edit_block_header.limit]
	sub	edx, ebx
	push	ecx
	cmp	ecx, edx
	jb	@f
	mov	ecx, edx
@@:
	push	esi
	add	esi, ebx
	add	ebx, ecx
	add	eax, ecx
	rep	movsb
	pop	esi
	pop	ecx
	sub	ecx, edx
	jb	.ret
	mov	esi, [esi + edit_block_header.next]
	mov	ebx, [EditBlockStart]
	test	esi, esi
	jz	.ret
	add	esi, ebp
	jmp	.loop
.ret:
	mov	eax, edi
	pop	edi
	sub	eax, edi
	ret

editor_get_pos:
	;mov	esi, [ebp + editor_data.curpos_block]
	;mov	ebx, [ebp + editor_data.curpos_offs]
	mov	esi, [ebp + editor_data.linedata_start + editor_line.block]
	sub	esi, ebp
	movzx	ebx, [ebp + editor_data.linedata_start + editor_line.offs]
@@:
	test	esi, esi
	jz	@f
	add	esi, ebp
	cmp	ebx, [esi + edit_block_header.limit]
	jb	@f
	mov	esi, [esi + edit_block_header.next]
	mov	ebx, [EditBlockStart]
	jmp	@b
@@:
	ret

editor_curline_start:
	mov	edx, [EditPlugInfo]
	add	edx, editor_line.plugdata
	mov	eax, [ebp + editor_data.cursor_y]
	dec	eax
	imul	eax, edx
	lea	edi, [ebp + eax + editor_data.linedata_start]
	mov	esi, [edi + editor_line.block]
	movzx	ebx, [edi + editor_line.offs]
	ret

editor_step_forward:
; in: esi = block (must be nonzero), ebx = offset in block
; out: esi = block (zero iff EOF reached), ebx = offset in block
; out: CF=1 iff EOF NOT reached
	inc	ebx
editor_normalize_offs:
	cmp	ebx, [esi + edit_block_header.limit]
	jb	@f
	mov	esi, [esi + edit_block_header.next]
	mov	ebx, [EditBlockStart]
	test	esi, esi
	jz	@f
	add	esi, ebp
	stc
@@:
	ret

editor_step_backward:
; in: esi = block (must be nonzero), ebx = offset in block
; out: esi = block (zero iff input was at the beginning), ebx = offset in block
; out: CF=1 iff start of file reached
	dec	ebx
	cmp	ebx, [EditBlockStart]
	jae	@f
	mov	esi, [esi + edit_block_header.prev]
	test	esi, esi
	stc
	jz	@f
	add	esi, ebp
	mov	ebx, [esi + edit_block_header.limit]
	dec	ebx
@@:
	ret

editor_get_string:
; read string up to the end of line
; in: esi = block, ebx = offset in block
; in: edi = destination, ecx = maximum number of bytes to copy, edx = number of bytes to skip
; out: esi = block, ebx = offset in block
; out: ecx = number of rest bytes (ecx_in - ecx_out = number of copied characters)
	mov	ah, [edit_normal_color]
	cmp	ebx, [esi + edit_block_header.limit]
	jz	.retnp
	push	0	; current position in line
.loop:
	test	ecx, ecx
	jz	.ret
	mov	al, [esi + ebx]
	cmp	al, 13
	jz	.ret
	cmp	al, 10
	jz	.ret
	cmp	al, 9
	jz	.tab
	inc	dword [esp]
	dec	edx
	jns	.4
	xor	edx, edx
	stosw
	dec	ecx
.4:
	call	editor_step_forward
	jc	.loop
.ret:
	pop	edx
.retnp:
	ret
.tab:
	push	eax edx
	mov	eax, [esp+8]
	xor	edx, edx
	div	[editor_tabsize]
	sub	edx, [editor_tabsize]
	neg	edx
	add	[esp+8], edx
	sub	[esp], edx
	pop	edx eax
	jns	.4
	mov	al, ' '
@@:
	stosw
	dec	ecx
	jz	.ret
	inc	edx
	jnz	@b
	jmp	.4

editor_find_newline:
; in: esi = block, ebx = offset in block
; out: esi = block, ebx = offset in block, ecx = line length
	xor	ecx, ecx
	test	esi, esi
	jz	.ret0
	cmp	ebx, [esi + edit_block_header.limit]
	jb	.1
	xor	esi, esi
.ret0:
	ret
.1:
	mov	al, [esi + ebx]
	inc	ecx
	call	editor_step_forward
	cmp	al, 13
	jz	.2
	cmp	al, 10
	jz	.2
	test	esi, esi
	jnz	.1
.ret1:
	mov	esi, [ebp + editor_data.last_block]
	add	esi, ebp
	mov	ebx, [esi + edit_block_header.limit]
	ret
.2:
	dec	ecx
	test	esi, esi
	jz	.ret1
	cmp	al, 13
	jnz	.ret
	cmp	byte [esi + ebx], 10
	jnz	.ret
	call	editor_step_forward
	jnc	.ret1
.ret:
	ret

editor_prev_newline:
	xor	ecx, ecx
	test	esi, esi
	jnz	@f
	mov	esi, [ebp + editor_data.last_block]
	add	esi, ebp
	mov	ebx, [esi + edit_block_header.limit]
@@:
	call	editor_step_backward
	jc	.ret
	mov	al, [esi + ebx]
	call	editor_step_backward
	jc	.ret
	cmp	al, 10
	jnz	.1
	cmp	byte [esi + ebx], 13
	jnz	.1
@@:
	call	editor_step_backward
	jc	.ret
.1:
	inc	ecx
	mov	al, [esi + ebx]
	cmp	al, 13
	jz	@f
	cmp	al, 10
	jnz	@b
@@:
	dec	ecx
	inc	ebx
	cmp	ebx, [esi + edit_block_header.limit]
	jb	.ret
	mov	esi, [esi + edit_block_header.next]
	mov	ebx, [EditBlockStart]
	test	esi, esi
	jz	.ret
	add	esi, ebp
.ret:
	test	esi, esi
	jnz	@f
	mov	esi, [ebp + editor_data.first_block]
	mov	ebx, [EditBlockStart]
	add	esi, ebp
@@:
	ret

editor_init_lines:
	call	editor_get_pos
	test	esi, esi
	jnz	@f
	mov	esi, [ebp + editor_data.last_block]
	add	esi, ebp
	mov	ebx, [esi + edit_block_header.limit]
@@:
	mov	ecx, max_height
	lea	edi, [ebp + editor_data.linedata_start]
.1:
	mov	eax, esi
	stosd	; editor_line.block
	mov	eax, ebx
	stosw	; editor_line.offs
	push	ecx
	call	editor_find_newline
	;mov	eax, ecx
	;stosd	; editor_line.length
	xor	eax, eax
	mov	ecx, [EditPlugInfo]
	rep	stosb
	pop	ecx
	loop	.1
	ret

editor_draw_status:
	lea	edi, [ebp + editor_data.buf]
	mov	ah, [edit_status_color]
	mov	ecx, [cur_width]
	sub	ecx, 56
	cmp	ecx, 25
	jge	@f
	push	25
	pop	ecx
@@:
	call	viewedit_draw_filename
	inc	ecx
	rep	stosw
	test	[ebp + editor_data.flags], 80h
	jz	@f
	mov	al, '*'
@@:
	stosw
	mov	al, ' '
	test	[ebp + editor_data.flags], 40h
	jz	@f
	mov	al, '-'
@@:
	stosw
	mov	al, ' '
	test	[ebp + editor_data.flags], 20h
	jz	@f
	mov	al, '"'
@@:
	stosw
	mov	al, ' '
	mov	cl, 10
        rep     stosw
        movzx   esi, [ebp+editor_data.encoding]
        lea     esi, [encodings.names+esi*8]
        push    edi esi
        dec     edi
        dec     edi
        std
        add     esi, 8
@@:
        dec     esi
        cmp     byte [esi], ' '
        jz      @b
@@:
        lodsb
        stosw
        cmp     esi, [esp]
        jae     @b
        cld
        pop     esi edi
	mov	esi, aLine
	mov	cl, 8
@@:
	lodsb
	stosw
	loop	@b
	mov	cl, 13
	mov	al, ' '
	rep	stosw
	std
	push	edi
	dec	edi
	dec	edi
	push	eax
	mov	eax, [ebp + editor_data.numlines]
	mov	cl, 10
@@:
	xor	edx, edx
	div	ecx
	xchg	eax, edx
	add	al, '0'
	mov	ah, [edit_status_color]
	stosw
	xchg	eax, edx
	test	eax, eax
	jnz	@b
	mov	al, '/'
	mov	ah, [edit_status_color]
	stosw
	mov	eax, [ebp + editor_data.curline]
	add	eax, [ebp + editor_data.cursor_y]
@@:
	xor	edx, edx
	div	ecx
	xchg	eax, edx
	add	al, '0'
	mov	ah, [edit_status_color]
	stosw
	xchg	eax, edx
	test	eax, eax
	jnz	@b
	pop	eax
	stosw
	cld
	pop	edi
	mov	ah, [edit_status_color]
	mov	esi, aCol
	mov	cl, 7
@@:
	lodsb
	stosw
	loop	@b
	mov	eax, [ebp + editor_data.curcol]
	add	eax, [ebp + editor_data.cursor_x]
	inc	eax
	mov	cl, 10
	push	-'0'
@@:
	xor	edx, edx
	div	ecx
	push	edx
	test	eax, eax
	jnz	@b
@@:
	pop	eax
	mov	ah, [edit_status_color]
	add	al, '0'
	jz	@f
	stosw
	jmp	@b
@@:
	mov	al, ' '
	mov	cl, 13
	rep	stosw
	xor	eax, eax
	xor	edx, edx
	call	get_console_ptr
	lea	esi, [ebp + editor_data.buf]
	mov	ecx, [cur_width]
	shr	ecx, 1
	rep	movsd
	adc	ecx, ecx
	rep	movsw
	cmp	[ebp + editor_data.cur_delta], -1
	jnz	.a
	mov	al, ' '
	mov	byte [edi-4*2], al
	mov	byte [edi-3*2], al
	mov	byte [edi-2*2], al
	mov	byte [edi-1*2], al
	mov	eax, [ebp + editor_data.cur_block]
	add	eax, ebp
	add	eax, [ebp + editor_data.cur_offs]
	movzx	eax, byte [eax]
	mov	cl, 100
	;xor	edx, edx	; edx=0 already
	div	ecx
	test	al, al
	jz	@f
	add	al, '0'
	mov	[edi-3*2], al
@@:
	xchg	eax, edx
	aam
	test	ah, ah
	jnz	.b
	cmp	byte [edi-3*2], ' '
	jz	@f
.b:
	add	ah, '0'
	mov	[edi-2*2], ah
@@:
	add	al, '0'
	mov	[edi-1*2], al
.a:
	ret

editor_draw_line:
	push	ecx
	mov	ecx, [cur_width]
	test	esi, esi
	jz	.2
	lea	edi, [ebp + editor_data.buf]
	push	edx edi
	mov	edx, [ebp + editor_data.curcol]
	call	editor_get_string
	mov	al, ' '
	rep	stosw
	pop	esi edx
	xor	eax, eax
	call	get_console_ptr
	mov	ecx, [cur_width]
	shr	ecx, 1
	rep	movsd
	adc	ecx, ecx
	rep	movsw
	pop	ecx
	ret
.2:
	xor	eax, eax
	call	get_console_ptr
	mov	al, ' '
	mov	ah, [edit_normal_color]
	rep	stosw
	pop	ecx
	ret

editor_draw_text:
	call	editor_draw_status
	push	1
	pop	edx
	lea	ecx, [ebp + editor_data.linedata_start]
.1:
	mov	esi, [ecx + editor_line.block]
	movzx	ebx, [ecx + editor_line.offs]
	add	ecx, editor_line.plugdata
	add	ecx, [EditPlugInfo]
	call	editor_draw_line
	inc	edx
	mov	eax, [cur_height]
	dec	eax
	cmp	edx, eax
	jb	.1
	jmp	draw_image

editor_set_keybar:
	mov	eax, keybar_editor
	movzx	esi, [ebp+editor_data.encoding]
	dec	esi
	jz	@f
	push	1
	pop	esi
@@:
	lea	esi, [encodings.names+esi*8]
	lea	edi, [eax+keybar_cp2-keybar_editor]
	movsd
	movsw
	jmp	draw_keybar

editor_up_scroll:
	push	ecx
	sub	[ebp + editor_data.curline], ecx
	mov	edx, [EditPlugInfo]
	add	edx, editor_line.plugdata
	imul	eax, edx, max_height
	imul	ecx, edx
	sub	ecx, eax
	neg	ecx
	lea	esi, [ebp + ecx + editor_data.linedata_start - 4]
	lea	edi, [ebp + eax + editor_data.linedata_start - 4]
	shr	ecx, 2
	std
	rep	movsd
	cld
	jnc	@f
	mov	cx, [esi+2]
	mov	[edi+2], cx
	sub	edi, 2
@@:
	pop	ecx
	add	edi, 4
	movzx	ebx, [edi + editor_line.offs]
	mov	esi, [edi + editor_line.block]
@@:
	push	ecx
	call	editor_prev_newline
	sub	edi, edx
	push	edi
	mov	eax, esi
	stosd	; editor_line.offs
	mov	eax, ebx
	stosw	; editor_line.block
	;mov	eax, ecx
	;stosd	; editor_line.length
	mov	ecx, [EditPlugInfo]
	xor	eax, eax
	rep	stosb
	pop	edi
	pop	ecx
	loop	@b
; fall through to editor_update_cur

editor_update_cur:
	mov	ecx, [ebp + editor_data.cursor_x]
	add	ecx, [ebp + editor_data.curcol]
	call	editor_curline_start
	xor	edx, edx	; current position in the line
	cmp	ebx, [esi + edit_block_header.limit]
	jz	.notfound
.scan:
	mov	al, [esi+ebx]
	cmp	al, 13
	jz	.notfound
	cmp	al, 10
	jz	.notfound
	test	ecx, ecx
	jz	.found
	cmp	al, 9
	jz	.tab
	inc	edx
	dec	ecx
	call	editor_step_forward
	jc	.scan
.notfound:
	test	esi, esi
	jnz	@f
	mov	esi, [ebp + editor_data.last_block]
	add	esi, ebp
	mov	ebx, [esi + edit_block_header.limit]
@@:
	mov	[ebp + editor_data.cur_delta], ecx
	xor	eax, eax
	jmp	.reta
.found:
	xor	eax, eax
.founda:
	or	[ebp + editor_data.cur_delta], -1
.reta:
	sub	esi, ebp
	mov	[ebp + editor_data.cur_block], esi
	mov	[ebp + editor_data.cur_offs], ebx
	ret
.tab:
	push	edx
	mov	eax, edx
	xor	edx, edx
	div	[editor_tabsize]
	sub	edx, [editor_tabsize]
	neg	edx
	add	[esp], edx
	cmp	ecx, edx
	jb	.curintab
	sub	ecx, edx
	pop	edx
	call	editor_step_forward
	jnc	.notfound
	test	ecx, ecx
	jz	.found
	jmp	.scan
.curintab:
	sub	[esp], edx
	pop	edx
	cmp	edx, [ebp + editor_data.curcol]
	setc	al
	jae	@f
	mov	[ebp + editor_data.curcol], edx
@@:
	sub	edx, [ebp + editor_data.curcol]
	mov	[ebp + editor_data.cursor_x], edx
	mov	[cursor_x], edx
	jmp	.founda

editor_down_scroll:
	push	ecx
	lea	edi, [ebp + editor_data.linedata_start]
	mov	edx, [EditPlugInfo]
	add	edx, editor_line.plugdata
	imul	ecx, edx
	lea	esi, [edi + ecx]
	imul	eax, edx, max_height
	sub	eax, ecx
	mov	ecx, eax
	shr	ecx, 2
	rep	movsd
	adc	ecx, ecx
	rep	movsw
@@:
	mov	esi, edi
	sub	esi, edx
	movzx	ebx, [esi + editor_line.offs]
	mov	esi, [esi + editor_line.block]
	pop	ecx
	jecxz	.ret
@@:
	push	ecx
	call	editor_find_newline
	mov	eax, esi
	stosd	; editor_line.block
	mov	eax, ebx
	stosw	; editor_line.offs
	;mov	eax, ecx
	;stosd	; editor_line.length
	mov	ecx, [EditPlugInfo]
	xor	eax, eax
	rep	stosb
	pop	ecx
	loop	@b
.ret:
	ret

editor_end_scroll:
	call	editor_curline_start
; calculate visible length of the line (it differs from the real length if tabulations are present)
	xor	ecx, ecx
	cmp	ebx, [esi + edit_block_header.limit]
	jz	.calcdone
.calcloop:
	mov	al, [esi+ebx]
	cmp	al, 10
	jz	.calcdone
	cmp	al, 13
	jz	.calcdone
	cmp	al, 9
	jz	.calctab
	inc	ecx
.calcnext:
	call	editor_step_forward
	jc	.calcloop
	jmp	.calcdone
.calctab:
	mov	eax, ecx
	xor	edx, edx
	div	[editor_tabsize]
	sub	edx, [editor_tabsize]
	sub	ecx, edx
	jmp	.calcnext
.calcdone:
	test	esi, esi
	jnz	@f
	mov	esi, [ebp + editor_data.last_block]
	add	esi, ebp
	mov	ebx, [esi + edit_block_header.limit]
@@:
	sub	esi, ebp
	mov	[ebp + editor_data.cur_block], esi
	mov	[ebp + editor_data.cur_offs], ebx
	and	[ebp + editor_data.cur_delta], 0
; ecx = number of symbols in the line
; calculate new position of view range
	mov	eax, [ebp + editor_data.curcol]
	cmp	ecx, eax
	jb	.toleft
	add	eax, [cur_width]
	cmp	ecx, eax
	jae	.toright
	sub	ecx, [ebp + editor_data.curcol]
	mov	[ebp + editor_data.cursor_x], ecx
	mov	[cursor_x], ecx
	ret
.toleft:
	mov	[ebp + editor_data.curcol], ecx
	and	[ebp + editor_data.cursor_x], 0
	and	[cursor_x], 0
	stc
	ret
.toright:
	mov	eax, [cur_width]
	dec	eax
	sub	ecx, eax
	mov	[ebp + editor_data.curcol], ecx
	mov	[ebp + editor_data.cursor_x], eax
	mov	[cursor_x], eax
	stc
	ret

editor_move_linestart:
; in: esi = block, ebx = start offset, ecx = delta
	lea	edi, [ebp + editor_data.linedata_start]
	mov	edx, max_height
.0:
	cmp	[edi + editor_line.block], esi
	jnz	.1
	movzx	eax, [edi + editor_line.offs]
	cmp	eax, ebx
	ja	.2
;	push	eax
;	add	eax, [edi + editor_line.length]
;	cmp	eax, ebx
;	jb	@f
;	add	[edi + editor_line.length], ecx
;@@:
;	pop	eax
	cmp	eax, [esi + edit_block_header.limit]
	jb	.1
	push	esi ebx
	mov	ebx, eax
	jmp	.3
.2:
	push	esi ebx
	mov	ebx, eax
	add	ebx, ecx
.3:
	cmp	ebx, [esi + edit_block_header.limit]
	jb	.4
	cmp	[esi + edit_block_header.next], 0
	jz	.4
	sub	ebx, [esi + edit_block_header.limit]
	mov	esi, [esi + edit_block_header.next]
	add	esi, ebp
	add	ebx, [EditBlockStart]
	jmp	.3
.4:
	mov	[edi + editor_line.block], esi
	mov	[edi + editor_line.offs], bx
	pop	ebx esi
.1:
	add	edi, editor_line.plugdata
	add	edi, [EditPlugInfo]
	dec	edx
	jnz	.0
	;lea	edx, [ebp + editor_data.curpos_block]
	;call	.5
	;add	edx, editor_data.cur_block - editor_data.curpos_block
	lea	edx, [ebp + editor_data.cur_block]
;	call	.5
;	ret
.5:
	mov	eax, [edx]
	add	eax, ebp
	cmp	eax, esi
	jnz	.6
	cmp	[edx+4], ebx
	jbe	@f
	add	[edx+4], ecx
@@:
	mov	eax, [edx+4]
	sub	eax, [esi + edit_block_header.limit]
	jb	.6
	push	ecx
	mov	ecx, [esi + edit_block_header.next]
	add	ecx, ebp
	add	eax, [EditBlockStart]
	mov	[edx], ecx
	mov	[edx+4], eax
	pop	ecx
.6:
	ret

editor_reserve_symbol:
	push	1
	pop	ecx

editor_reserve_space:
; Вставляет пустое место внутрь цепочки блоков
; in: ecx = number of symbols to add, esi = block, ebx = offset
	mov	eax, [esi + edit_block_header.limit]
	add	eax, ecx
	cmp	eax, 4096
	ja	.add
	mov	[esi + edit_block_header.limit], eax
	push	esi ecx
	sub	eax, ecx
	lea	esi, [esi + eax - 1]
	lea	edi, [esi + ecx]
	sub	eax, ebx
	mov	ecx, eax
	std
	rep	movsb
	cld
	pop	ecx esi
	call	editor_move_linestart
	clc
	ret
.add:
	push	ecx
	mov	eax, [esi + edit_block_header.limit]
	sub	eax, [EditBlockStart]
	add	eax, ecx
	push	eax
	xor	edx, edx
	div	[EditBlockSize]
	push	eax
	sub	eax, [ebp + editor_data.numfree]
	jbe	.norealloc
	mov	edx, [ebp + editor_data.memsize]
	push	eax edx
	add	eax, edx
	mov	ecx, eax
	shl	ecx, 12
	mov	edx, ebp
	call	xpgrealloc
	pop	edx ecx
	test	eax, eax
	jz	.nomem
	sub	eax, ebp
	add	ebp, eax
	add	esi, eax
	add	[ebp + editor_data.memsize], ecx
	push	ecx
	mov	ecx, max_height
	lea	edi, [ebp + editor_data.linedata_start]
@@:
	add	[edi + editor_line.block], eax
	add	edi, editor_line.plugdata
	add	edi, [EditPlugInfo]
	loop	@b
	pop	ecx
	shl	edx, 12
	add	[ebp + editor_data.numfree], ecx
	lea	edi, [edx + ebp]
	mov	eax, [ebp + editor_data.freeblocks]
	mov	[ebp + editor_data.freeblocks], edx
@@:
	add	edx, 1000h
	mov	[edi], edx
	add	edi, 1000h
	loop	@b
	mov	[edi-1000h], eax
.norealloc:
	pop	edx
	push	[esi + edit_block_header.next]
	push	esi
	sub	[ebp + editor_data.numfree], edx
	mov	edi, [ebp + editor_data.freeblocks]
@@:
	mov	[esi + edit_block_header.next], edi
	add	edi, ebp
	push	edi
	push	dword [edi]
	stosd	; edit_block_header.next - will be filled later
	mov	eax, esi
	sub	eax, ebp
	stosd	; edit_block_header.prev
	mov	eax, 4096 - edit.RESERVE_IN_BLOCK
	stosd	; edit_block_header.limit
	mov	eax, [EditBlockSize]
	sub	[esp+16], eax
	xor	eax, eax
	mov	ecx, [EditPlugInfo]
	rep	stosb
	pop	edi
	pop	esi
	dec	edx
	jnz	@b
	mov	[ebp + editor_data.freeblocks], edi
	mov	edi, esi
	pop	esi
	pop	[edi + edit_block_header.next]
	pop	ecx
	add	ecx, [EditBlockSize]
	mov	edx, ecx
	shr	edx, 1;2
	mov	eax, ecx
	sub	eax, edx
	cmp	eax, [EditBlockSize]
	jb	@f
	mov	eax, [EditBlockSize]
	mov	edx, ecx
	sub	edx, eax
@@:
	add	eax, [EditBlockStart]
	add	edx, [EditBlockStart]
	mov	ecx, [esi + edit_block_header.limit]
	mov	[esi + edit_block_header.limit], eax
	mov	[edi + edit_block_header.limit], edx
	sub	ecx, ebx
	push	ecx
	push	esi edi ecx
	add	esi, ecx
	add	esi, ebx
	push	edx
	sub	edx, [EditBlockStart]
	cmp	ecx, edx
	jb	@f
	mov	ecx, edx
@@:
	pop	edx
	sub	[esp], ecx
	add	edi, edx
	sub	esi, ecx
	sub	edi, ecx
	rep	movsb
	pop	ecx edi esi
	push	esi edi
	lea	edi, [esi + eax - 1]
	add	esi, ebx
	lea	esi, [esi + ecx - 1]
	std
	rep	movsb
	cld
	pop	edi esi
	pop	ecx
	mov	ecx, ebx
	sub	ecx, eax
	jb	@f
	push	esi edi
	add	esi, eax
	add	edi, [EditBlockStart]
	rep	movsb
	pop	edi esi
@@:
	push	esi edi
	sub	esi, ebp
	sub	edi, ebp
	cmp	[ebp + editor_data.last_block], esi
	jnz	@f
	mov	[ebp + editor_data.last_block], edi
@@:
	pop	edi esi
	pop	ecx
	call	editor_move_linestart
	cmp	ebx, [esi + edit_block_header.limit]
	jb	@f
	sub	ebx, [esi + edit_block_header.limit]
	mov	esi, [esi + edit_block_header.next]
	add	esi, ebp
	add	ebx, [EditBlockStart]
@@:
	clc
	ret
.nomem:
	pop	eax
	pop	ecx
	pop	ecx
	add	esi, ebp
	stc
	ret

editor_delete_symbol:
	push	1
	pop	ecx

editor_delete_space:
; Удаляет ecx байт из текста, начиная с esi:ebx
; ecx, esi, ebx разрушаются
	mov	eax, [esi + edit_block_header.limit]
	sub	eax, ebx
	cmp	eax, ecx
	jb	.more1
	push	esi
	sub	[esi + edit_block_header.limit], ecx
	sub	eax, ecx
	lea	edi, [esi+ebx]
	lea	esi, [edi+ecx]
	mov	ecx, eax
	rep	movsb
	pop	esi
.done:
	call	.collapse_prev
	call	.collapse_next
	call	editor_init_lines
	jmp	editor_update_cur
.more1:
	mov	[esi + edit_block_header.limit], ebx
	sub	ecx, eax
@@:
	mov	esi, [esi + edit_block_header.next]
	add	esi, ebp
	mov	eax, [esi + edit_block_header.limit]
	sub	eax, [EditBlockStart]
	sub	ecx, eax
	jb	@f
	call	.delete_block
	jmp	@b
@@:
	add	ecx, eax
	push	esi
	mov	eax, [esi + edit_block_header.limit]
	sub	[esi + edit_block_header.limit], ecx
	add	eax, esi
	add	esi, [EditBlockStart]
	mov	edi, esi
	add	esi, ecx
	sub	eax, esi
	mov	ecx, esi
	rep	movsb
	pop	esi
	call	.collapse_next
	mov	esi, [esi + edit_block_header.prev]
	add	esi, ebp
	jmp	.done

.delete_block:
	mov	eax, [esi + edit_block_header.next]
	mov	edx, [esi + edit_block_header.prev]
	test	eax, eax
	jz	.dbfirst
	mov	[eax + ebp + edit_block_header.prev], edx
	jmp	@f
.dbfirst:
	mov	[ebp + editor_data.first_block], edx
@@:
	test	edx, edx
	jz	.dblast
	mov	[edx + ebp + edit_block_header.next], eax
	jmp	@f
.dblast:
	mov	[ebp + editor_data.last_block], eax
@@:
	mov	eax, [ebp + editor_data.freeblocks]
	mov	[esi], eax
	sub	esi, ebp
	mov	[ebp + editor_data.freeblocks], esi
	inc	[ebp + editor_data.numfree]
	ret

.collapse_prev:
	mov	eax, [esi + edit_block_header.prev]
	test	eax, eax
	jz	.cpno
	add	eax, ebp
	mov	edx, [esi + edit_block_header.limit]
	sub	edx, [EditBlockStart]
	add	edx, [eax + edit_block_header.limit]
	cmp	edx, 4096 - edit.RESERVE_IN_BLOCK
	ja	.cpno
	mov	edi, eax
.collapse:	; (edi) + (esi) -> (edi)
	push	edi
	push	esi
	mov	ecx, [esi + edit_block_header.limit]
	sub	ecx, [EditBlockStart]
	add	esi, [EditBlockStart]
	mov	eax, [edi + edit_block_header.limit]
	add	[edi + edit_block_header.limit], ecx
	add	edi, eax
	rep	movsb
	pop	esi
	call	.delete_block
	pop	esi
.cpno:
	ret
.collapse_next:
	mov	eax, [esi + edit_block_header.next]
	test	eax, eax
	jz	.cpno
	add	eax, ebp
	mov	edx, [esi + edit_block_header.limit]
	sub	edx, [EditBlockStart]
	add	edx, [eax + edit_block_header.limit]
	cmp	edx, 4096 - edit.RESERVE_IN_BLOCK
	ja	.cpno
	mov	edi, esi
	mov	esi, eax
	jmp	.collapse

editor_OnKey:
	test	al, 80h
	jnz	.ret
	test	[ebp + editor_data.flags], 20h
	jnz	.symbol
	mov	esi, editor_ctrlkeys
	call	process_ctrl_keys
	jnc	.ret
.symbol:
	and	[ebp + editor_data.flags], not 20h
	test	[ebp + editor_data.flags], 40h
	jnz	.ret
	or	[ebp + editor_data.flags], 80h
	movzx	eax, al
	call	get_ascii_char
	mov	esi, [ebp + editor_data.cur_block]
	add	esi, ebp
	mov	ebx, [ebp + editor_data.cur_offs]
	cmp	al, 10
	jz	.insert_newline
	cmp	al, 13
	jz	.insert_newline
	cmp	[ebp + editor_data.cur_delta], -1
	jnz	.insert_after_eol
	test	[ebp + editor_data.flags], 10h
	jnz	.replace_symbol
	push	eax
	call	editor_reserve_symbol
	pop	eax
	jc	.ret
.replace_symbol:
	cmp	ebx, [esi + edit_block_header.limit]
	jnz	@f
	mov	esi, [esi + edit_block_header.next]
	add	esi, ebp
	mov	ebx, [EditBlockStart]
@@:
	mov	[esi + ebx], al
.symb_inserted:
	call	.redraw_curline
	jmp	.right
.redraw_curline:
	call	editor_curline_start
	mov	edx, [cursor_y]
	call	editor_draw_line
.ret:
	ret
.insert_after_eol:
	mov	ecx, [ebp + editor_data.cur_delta]
	inc	ecx
	push	eax
	call	editor_reserve_space
	pop	eax
	jc	.ret
	push	eax
	mov	edx, ecx
.2:
	mov	ecx, [esi + edit_block_header.limit]
	sub	ecx, ebx
	lea	edi, [esi + ebx]
	cmp	ecx, edx
	jb	@f
	mov	ecx, edx
@@:
	add	ebx, ecx
	sub	edx, ecx
	mov	al, ' '
	rep	stosb
	jz	@f
	mov	esi, [esi + edit_block_header.next]
	add	esi, ebp
	mov	ebx, [EditBlockStart]
	jmp	.2
@@:
	pop	eax
	mov	[edi-1], al
	dec	ebx
	sub	esi, ebp
	mov	[ebp + editor_data.cur_block], esi
	mov	[ebp + editor_data.cur_offs], ebx
	or	[ebp + editor_data.cur_delta], -1
	jmp	.symb_inserted
.insert_newline:
	push	1
	pop	ecx
	cmp	[ebp + editor_data.eol], 2
	adc	ecx, 0
	call	editor_reserve_space
	jc	.ret
; Просто так вставлять символ новой строки чревато - из-за существования двухбайтовых комбинаций перевода строки
; старый символ может слиться с новым. В таком случае придётся заниматься корректировкой.
; Проблема бывает в двух случаях:
; если редактор настроен на Unix-стиль и новый перевод строки вставляется непосредственно после
;	перевода строки в Mac-стиле;
; если редактор настроен на Mac-стиль и новый перевод строки вставляется непосредственно перед
;	переводом строки в Unix-стиле.
; В этих случаях форсируем перевод строки в текущем стиле файла.
	mov	al, [ebp + editor_data.eol]
	cmp	al, edit.eol_dos
	jz	.insert_eol_dos
	cmp	al, edit.eol_mac
	jz	.insert_eol_mac
	mov	al, 10	; Unix-style for end-of-line
	push	esi ebx
	call	editor_step_backward
	jc	@f
	cmp	byte [esi+ebx], 13
	jnz	@f
	mov	al, 13	; force Mac-style to avoid collapse
@@:
	pop	ebx esi
	mov	[esi+ebx], al
	jmp	.eol_correct
.insert_eol_mac:
	mov	al, 13	; Mac-style for end-of-line
	push	esi ebx
	call	editor_step_forward
	jnc	@f
	cmp	byte [esi+ebx], 10
	jnz	@f
	mov	al, 10	; force Unix-style to avoid collapse
@@:
	pop	ebx esi
	mov	[esi+ebx], al
	jmp	.eol_correct
.insert_eol_dos:
	mov	byte [esi+ebx], 13
	call	editor_step_forward
	mov	byte [esi+ebx], 10
.eol_correct:
	call	editor_step_forward
	test	esi, esi
	jnz	@f
	mov	esi, [ebp + editor_data.last_block]
	add	esi, ebp
	mov	ebx, [esi + edit_block_header.limit]
@@:
	and	[ebp + editor_data.cur_delta], 0
	cmp	ebx, [esi + edit_block_header.limit]
	jz	@f
	mov	al, [esi+ebx]
	cmp	al, 10
	jz	@f
	cmp	al, 13
	jz	@f
	dec	[ebp + editor_data.cur_delta]
@@:
; ну что же, в текст нужные символы вставили, теперь надо скорректировать информацию о начале строк на экране
	mov	edi, [ebp + editor_data.cursor_y]
	mov	ecx, max_height-1
	sub	ecx, edi
	dec	edi
	mov	eax, [EditPlugInfo]
	add	eax, editor_line.plugdata
	imul	edi, eax, max_height
	imul	ecx, eax
	lea	edi, [ebp + edi + editor_data.linedata_start - 2]
	push	esi
	mov	esi, edi
	sub	esi, eax
	shr	ecx, 1
	std
	rep	movsw
	cld
	pop	esi
	add	edi, 2
	sub	edi, eax
	push	esi
	mov	esi, edi
	sub	esi, eax
	pop	eax
	stosd	; editor_line.block
	sub	eax, ebp
	mov	[ebp + editor_data.cur_block], eax
	mov	eax, ebx
	stosw	; editor_line.offs
	mov	[ebp + editor_data.cur_offs], eax
	;mov	eax, ecx
	;stosd	; editor_line.length
	mov	ecx, [EditPlugInfo]
	xor	eax, eax
	rep	stosb
; на одну строку стало больше
	inc	[ebp + editor_data.numlines]
; курсор окажется в начале строки
	mov	[ebp + editor_data.cursor_x], eax
	mov	[ebp + editor_data.curcol], eax
	mov	[cursor_x], eax
; и передвинется на строку ниже
	mov	eax, [ebp + editor_data.cursor_y]
	inc	eax
	mov	edx, [cur_height]
	dec	edx
	cmp	eax, edx
	jae	.down_scroll
	mov	[ebp + editor_data.cursor_y], eax
	mov	[cursor_y], eax
	jmp	editor_draw_text

.exit_confirm:
	test	[ebp + editor_data.flags], 80h
	jz	.exit
	push	aFileModified
	mov	eax, esp
	push	EditorExitBtn
	push	3
	push	eax
	push	1
	push	aEditorTitle
	call	SayErrTitle
	pop	ecx
	test	eax, eax
	jz	.save
	dec	eax
	jz	.exit
	ret
.exit_save:
	test	[ebp + editor_data.flags], 80h
	jz	.exit
.save:
	call	editor_save
.exit:
	call	editor_OnExit
	jmp	delete_active_screen
.f2:
	call	editor_save
	jmp	.redraw_status

.up_scroll:
	cmp	[ebp + editor_data.curline], 0
	jz	.ret
	push	1
	pop	ecx
	call	editor_up_scroll
	jmp	editor_draw_text
.up:
	mov	eax, [ebp + editor_data.cursor_y]
	dec	eax
	jz	.up_scroll
.set_cursor_y:
	mov	[ebp + editor_data.cursor_y], eax
	mov	[cursor_y], eax
	call	editor_update_cur
	test	al, al
	jnz	editor_draw_text
.redraw_status:
	call	editor_draw_status
	jmp	draw_image
.down:
	mov	eax, [ebp + editor_data.cursor_y]
	inc	eax
	push	eax
	add	eax, [ebp + editor_data.curline]
	cmp	eax, [ebp + editor_data.numlines]
	pop	eax
	ja	.ret
	mov	edx, [cur_height]
	dec	edx
	cmp	eax, edx
	jnz	.set_cursor_y
.down_scroll:
	inc	[ebp + editor_data.curline]
	lea	edi, [ebp + editor_data.linedata_start]
	mov	eax, [EditPlugInfo]
	add	eax, editor_line.plugdata
	lea	esi, [edi + eax]
	imul	ecx, eax, max_height-1
	shr	ecx, 2
	rep	movsd
	adc	ecx, ecx
	rep	movsw
	sub	esi, eax
	sub	esi, eax
	movzx	ebx, [esi + editor_line.offs]
	mov	esi, [esi + editor_line.block]
	call	editor_find_newline
	mov	eax, esi
	stosd	; editor_line.block
	mov	eax, ebx
	stosw	; editor_line.offs
	;mov	eax, ecx
	;stosd	; editor_line.length
	mov	ecx, [EditPlugInfo]
	xor	eax, eax
	rep	stosb
	jmp	.ret2

.pgup:
	mov	ecx, [cur_height]
	sub	ecx, 3
	mov	edx, [ebp + editor_data.curline]
	mov	eax, edx
	push	edx
	sub	edx, ecx
	jnc	@f
	xor	edx, edx
@@:
	mov	[ebp + editor_data.curline], edx
	add	eax, [ebp + editor_data.cursor_y]
	dec	eax
	sub	eax, ecx
	jnc	@f
	xor	eax, eax
@@:
	sub	eax, edx
	inc	eax
	mov	[ebp + editor_data.cursor_y], eax
	mov	[cursor_y], eax
	pop	ecx
	sub	ecx, edx
	push	ecx
	mov	edx, [EditPlugInfo]
	add	edx, editor_line.plugdata
	imul	ecx, edx
	imul	eax, edx, max_height
	lea	edi, [ebp + editor_data.linedata_start + eax - 2]
	mov	esi, edi
	sub	esi, ecx
	sub	eax, ecx
	mov	ecx, eax
	shr	ecx, 1
	std
	rep	movsw
	cld
	pop	ecx
	jecxz	.ret2
	inc	edi
	inc	edi
	mov	esi, [edi + editor_line.block]
	movzx	ebx, [edi + editor_line.offs]
@@:
	push	ecx
	call	editor_prev_newline
	sub	edi, edx
	push	edi
	mov	eax, esi
	stosd	; editor_line.block
	mov	eax, ebx
	stosw	; editor_line.offs
	;mov	eax, ecx
	;stosd	; editor_line.length
	mov	ecx, [EditPlugInfo]
	xor	eax, eax
	rep	stosb
	pop	edi
	pop	ecx
	loop	@b
.ret2:
	call	editor_update_cur
	jmp	editor_draw_text
.pgdn:
	mov	edx, [cur_height]
	sub	edx, 2
	mov	ecx, [ebp + editor_data.curline]
	push	ecx
	lea	ecx, [edx + ecx - 1]
	mov	eax, [ebp + editor_data.numlines]
	sub	eax, edx
	jnc	@f
	xor	eax, eax
@@:
	cmp	ecx, eax
	jb	@f
	mov	ecx, eax
@@:
	mov	[ebp + editor_data.curline], ecx
	pop	eax
	push	eax
	add	eax, [ebp + editor_data.cursor_y]
	lea	eax, [eax + edx - 1]
	cmp	eax, [ebp + editor_data.numlines]
	jb	@f
	mov	eax, [ebp + editor_data.numlines]
@@:
	sub	eax, ecx
	mov	[ebp + editor_data.cursor_y], eax
	mov	[cursor_y], eax
	pop	edx
	sub	ecx, edx
	call	editor_down_scroll
	jmp	.ret2

.left:
	call	editor_cursor_left
	jnc	.redraw_status
	jmp	editor_draw_text
.ret3:
	ret

.right:
	cmp	[ebp + editor_data.cur_delta], -1
	jz	.right_in_text
	cmp	[ebp + editor_data.curcol], 0x80000000 - 0x1000
	jae	.ret3
	inc	[ebp + editor_data.cur_delta]
	push	1
	pop	edx
	jmp	.right_char
.right_in_text:
	mov	esi, [ebp + editor_data.cur_block]
	add	esi, ebp
	mov	ebx, [ebp + editor_data.cur_offs]
	mov	al, [esi + ebx]
	push	eax
	call	editor_step_forward
	test	esi, esi
	jz	.right_eol0
	mov	al, [esi + ebx]
	cmp	al, 10
	jz	.right_eol
	cmp	al, 13
	jz	.right_eol
	jmp	.right_ok
.right_eol0:
	mov	esi, [ebp + editor_data.last_block]
	add	esi, ebp
	mov	ebx, [esi + edit_block_header.limit]
.right_eol:
	inc	[ebp + editor_data.cur_delta]
.right_ok:
	sub	esi, ebp
	mov	[ebp + editor_data.cur_block], esi
	mov	[ebp + editor_data.cur_offs], ebx
	pop	eax
	push	1
	pop	edx
	cmp	al, 9
	jnz	.right_char
	mov	eax, [ebp + editor_data.curcol]
	add	eax, [ebp + editor_data.cursor_x]
	xor	edx, edx
	div	[editor_tabsize]
	sub	edx, [editor_tabsize]
	neg	edx
.right_char:
	mov	eax, [ebp + editor_data.cursor_x]
	add	eax, edx
	cmp	eax, [cur_width]
	jb	.set_cursor_x
	add	eax, [ebp + editor_data.curcol]
	mov	edx, [cur_width]
	dec	edx
	sub	eax, edx
	mov	[ebp + editor_data.cursor_x], edx
	mov	[cursor_x], edx
	mov	[ebp + editor_data.curcol], eax
	jmp	editor_draw_text
.set_cursor_x:
	mov	[ebp + editor_data.cursor_x], eax
	mov	[cursor_x], eax
	jmp	.redraw_status

.home:
	call	editor_curline_start
	and	[ebp + editor_data.cur_delta], 0
	cmp	ebx, [esi + edit_block_header.limit]
	jz	@f
	mov	al, [esi+ebx]
	cmp	al, 10
	jz	@f
	cmp	al, 13
	jz	@f
	dec	[ebp + editor_data.cur_delta]
@@:
	sub	esi, ebp
	mov	[ebp + editor_data.cur_block], esi
	mov	[ebp + editor_data.cur_offs], ebx
	xor	eax, eax
	mov	[ebp + editor_data.cursor_x], eax
	mov	[cursor_x], eax
	xchg	eax, [ebp + editor_data.curcol]
	test	eax, eax
	jnz	editor_draw_text
	jmp	.redraw_status

.end:
	call	editor_end_scroll
	jc	editor_draw_text
	jmp	.redraw_status

.ins:
	xor	[ebp + editor_data.flags], 10h
	mov	eax, cursor_normal_size
	test	[ebp + editor_data.flags], 10h
	jz	@f
	mov	eax, cursor_big_size
@@:
	mov	[cursor_size], eax
	jmp	draw_image

.backspace:
	cmp	[ebp + editor_data.cur_delta], -1
	jz	@f
	cmp	[ebp + editor_data.cur_delta], 0
	jnz	.left
@@:
	test	[ebp + editor_data.flags], 40h
	jnz	.ret3
	mov	esi, [ebp + editor_data.cur_block]
	add	esi, ebp
	mov	ebx, [ebp + editor_data.cur_offs]
	call	editor_step_backward
	jc	.ret3
	push	esi ebx
	call	editor_cursor_left
	pop	ebx esi
	setc	al
	push	eax
	push	esi ebx
	cmp	byte [esi+ebx], 10
	jnz	@f
	call	editor_step_backward
	jc	@f
	cmp	byte [esi+ebx], 13
	jnz	@f
	pop	eax eax
	jmp	.del_char
@@:
	pop	ebx esi
	jmp	.del_char
.del:
	test	[ebp + editor_data.flags], 40h
	jnz	.ret3
	mov	esi, [ebp + editor_data.cur_block]
	add	esi, ebp
	mov	ebx, [ebp + editor_data.cur_offs]
	call	editor_normalize_offs
	jnc	.ret3
	push	0
.del_char:
	or	[ebp + editor_data.flags], 80h
	mov	al, [esi+ebx]
	push	1
	pop	ecx
	push	eax
	push	esi ebx
	cmp	al, 13
	jnz	@f
	call	editor_step_forward
	jnc	@f
	cmp	byte [esi+ebx], 10
	jnz	@f
	inc	ecx
@@:
	pop	ebx esi
	call	editor_delete_space
	pop	eax
	cmp	al, 13
	jz	@f
	cmp	al, 10
	jz	@f
	pop	eax
	test	al, al
	jnz	.del1
	call	.redraw_curline
	jmp	.redraw_status
@@:
	pop	eax
	dec	[ebp + editor_data.numlines]
	call	editor_test_cursor_y
.del1:
	jmp	editor_draw_text

.f7:
	call	find_in_file_dlg
	jz	.shift_f7
.f7.ret:
	ret
.shift_f7:
; search string SearchString in file starting from current cursor position
	mov	ebx, SearchString
	xor	eax, eax
	cmp	byte [ebx], al
	jz	.f7.ret
	mov	esi, tolower_table
	test	[find_in_file_dlgdata.flags_case], 10h
	jz	@f
	mov	esi, identical_table
@@:
	test	[find_in_file_dlgdata.flags_whole], 10h
	setnz	al
	push	eax
	push	dword [ebp+editor_data.encoding]; always cp866 for now
				; needs to be revisited after Unicode support in editor
	call	search_string_pre
	mov	esi, [ebp + editor_data.cur_block]
	add	esi, ebp
	mov	ebx, [ebp + editor_data.cur_offs]
	call	editor_normalize_offs
	jnc	.f7.notfound
	xor	edi, edi
	push	ebx esi
	push	edi
	push	edi
	test	[find_in_file_dlgdata.flags_whole], 10h
	jnz	@f
	movzx	eax, byte [esi+ebx]
	jmp	.search_loop_next
@@:
	mov	edi, edx
.search_loop:
; edx -> FSM, ecx = last state, esi:ebx -> current data,
; edi = current state
; [esp] = row, [esp+4] = delta in lines
; get current symbol
	movzx	eax, byte [esi+ebx]
; calculate next state
	movzx	edi, byte [edi+eax]
; done?
	cmp	edi, ecx
	jz	.f7.found
.search_loop_next:
; no; proceed to next symbol
	add	ebx, 1
	shl	edi, 8
	add	dword [esp], 1
	add	edi, edx
	cmp	ebx, [esi + edit_block_header.limit]
	jae	.f7.nextblock
.f7.nonextblock:
	cmp	al, 10
	jz	.f7.newline
	cmp	al, 13
	jnz	.search_loop
	cmp	byte [esi+ebx], 10
	jnz	.f7.newline
	call	editor_step_forward
	jnc	.f7.notfound_pop
.f7.newline:
	mov	dword [esp], 0
	add	dword [esp+4], 1
	mov	dword [esp+8], esi
	mov	dword [esp+12], ebx
	jmp	.search_loop
.f7.nextblock:
	call	editor_normalize_offs
	jc	.f7.nonextblock
.f7.notfound_pop:
; last chance - if we are looking for a whole word, EOF is ok for last symbol
	test	[find_in_file_dlgdata.flags_whole], 10h
	jz	@f
	mov	esi, [ebp + editor_data.last_block]
	add	esi, ebp
	mov	ebx, [esi + edit_block_header.limit]
	movzx	edi, byte [edi+' ']
	cmp	edi, ecx
	jz	.f7.found
@@:
	add	esp, 10h
.f7.notfound:
	jmp	search_failed
.f7.found:
	or	[ebp + editor_data.cur_delta], -1
	sub	ebx, ecx
	inc	ebx
	test	[find_in_file_dlgdata.flags_whole], 10h
	jz	@f
	inc	ebx
@@:
	cmp	ebx, [EditBlockStart]
	jge	@f
	sub	ebx, [EditBlockStart]
	mov	esi, [esi + edit_block_header.prev]
	add	esi, ebp
	add	ebx, [esi + edit_block_header.limit]
	jmp	@b
@@:
	sub	esi, ebp
	mov	[ebp + editor_data.cur_block], esi
	add	esi, ebp
	mov	[ebp + editor_data.cur_offs], ebx
	push	ecx
	mov	ecx, edx
	call	pgfree
	pop	ecx
	pop	eax
	pop	edi
; esi:ebx -> last symbol of match, eax = row, edi = delta in lines
	pop	esi ebx
	test	[find_in_file_dlgdata.flags_whole], 10h
	jz	@f
	dec	ecx
@@:
	push	ebx esi
	sub	eax, ecx
	lea	edx, [eax+1]
	mov	eax, [ebp + editor_data.curcol]
	add	eax, [ebp + editor_data.cursor_x]
	test	edi, edi
	jz	@f
	xor	eax, eax
@@:
	test	edx, edx
	jz	.f7.foundpos1
.f7.findpos1:
	cmp	byte [ebx+esi], 9
	jz	.f7.findpos1.tab
	inc	eax
	call	editor_step_forward
	dec	edx
	jnz	.f7.findpos1
	jmp	.f7.foundpos1
.f7.findpos1.tab:
	push	edx eax
	xor	edx, edx
	div	[editor_tabsize]
	pop	eax
	sub	edx, [editor_tabsize]
	sub	eax, edx
	call	editor_step_forward
	pop	edx
	dec	edx
	jnz	.f7.findpos1
.f7.foundpos1:
	pop	esi ebx
	push	eax
	cmp	eax, [ebp + editor_data.curcol]
	jb	.f7.scrollleft
	sub	eax, [ebp + editor_data.curcol]
	sub	eax, [cur_width]
	jb	.f7.xset
	inc	eax
	inc	edx
	add	[ebp + editor_data.curcol], eax
	jmp	.f7.xset
.f7.scrollleft:
	inc	edx
	mov	[ebp + editor_data.curcol], eax
.f7.xset:
	pop	eax
	push	edx
	sub	eax, [ebp + editor_data.curcol]
	mov	[ebp + editor_data.cursor_x], eax
	mov	[cursor_x], eax
	add	edi, [ebp + editor_data.cursor_y]
	push	edi
	inc	edi
	cmp	edi, [cur_height]
	pop	edi
	jae	.f7.newview
	mov	[ebp + editor_data.cursor_y], edi
	mov	[cursor_y], edi
	jmp	.f7.yset
.f7.newview:
	dec	edi
	mov	[ebp + editor_data.linedata_start + editor_line.block], esi
	mov	[ebp + editor_data.linedata_start + editor_line.offs], bx
	add	[ebp + editor_data.curline], edi
	xor	eax, eax
	inc	eax
	mov	[ebp + editor_data.cursor_y], eax
	mov	[cursor_y], eax
	call	editor_init_lines
	call	editor_test_cursor_y
	inc	dword [esp]
.f7.yset:
	pop	eax
	test	eax, eax
	jz	.redraw_status
	jmp	editor_draw_text

editor_cursor_left:
	cmp	[ebp + editor_data.cur_delta], -1
	jz	.in_text
	dec	[ebp + editor_data.cur_delta]
	cmp	[ebp + editor_data.cur_delta], -1
	jnz	.left_cursor
.in_text:
	mov	esi, [ebp + editor_data.cur_block]
	add	esi, ebp
	mov	ebx, [ebp + editor_data.cur_offs]
	call	editor_step_backward
	jc	.ret_clc
	mov	al, [esi + ebx]
	cmp	al, 13
	jz	.eol
	cmp	al, 10
	jz	.eol2
	cmp	al, 9
	jz	.tab
	sub	esi, ebp
	mov	[ebp + editor_data.cur_block], esi
	mov	[ebp + editor_data.cur_offs], ebx
.left_cursor:
	mov	eax, [ebp + editor_data.cursor_x]
	test	eax, eax
	jz	@f
	dec	eax
.set_cursor_x:
	mov	[ebp + editor_data.cursor_x], eax
	mov	[cursor_x], eax
.ret_clc:
	clc
	ret
@@:
	dec	[ebp + editor_data.curcol]
	jmp	.ret_stc
.tab:
	mov	eax, [ebp + editor_data.cursor_x]
	test	eax, eax
	jz	@f
	dec	eax
	mov	[ebp + editor_data.cursor_x], eax
	mov	[cursor_x], eax
	call	editor_update_cur
	test	al, al
	jz	.ret_clc
.ret_stc:
	stc
	ret
@@:
	dec	[ebp + editor_data.curcol]
	call	editor_update_cur
	jmp	.ret_stc
.eol2:
	push	esi ebx
	call	editor_step_backward
	jc	@f
	cmp	byte [esi + ebx], 13
	jnz	@f
	pop	eax eax
	push	esi ebx
@@:
	pop	ebx esi
.eol:
	mov	eax, [ebp + editor_data.cursor_y]
	dec	eax
	jz	.scroll_left_toup
	push	0	; no full redraw
	mov	[ebp + editor_data.cursor_y], eax
	mov	[cursor_y], eax
	jmp	.scroll_left_toend
.scroll_left_toup:
	push	1
	pop	ecx
	call	editor_up_scroll
	push	1	; full redraw required
.scroll_left_toend:
	call	editor_end_scroll
	pop	eax
	adc	al, 0
	jnz	.ret_stc
	jmp	.ret_clc

editor_test_cursor_x:
	mov	ecx, [cur_width]
	dec	ecx
	mov	eax, [ebp + editor_data.cursor_x]
	sub	eax, ecx
	jbe	@f
	add	[ebp + editor_data.curcol], eax
	mov	[ebp + editor_data.cursor_x], ecx
	mov	[cursor_x], ecx
@@:
	ret

editor_test_cursor_y:
	mov	ecx, [ebp + editor_data.cursor_y]
	mov	edx, [cur_height]
	dec	edx
	dec	edx
	sub	ecx, edx
	ja	.scroll_down
	mov	ecx, [ebp + editor_data.curline]
	add	ecx, edx
	sub	ecx, [ebp + editor_data.numlines]
	ja	.scroll_up
.clc_ret:
	clc
	ret
.scroll_down:
	add	[ebp + editor_data.curline], ecx
	sub	[ebp + editor_data.cursor_y], ecx
	sub	[cursor_y], ecx
	call	editor_down_scroll
	stc
	ret
.scroll_up:
	cmp	ecx, [ebp + editor_data.curline]
	jb	@f
	mov	ecx, [ebp + editor_data.curline]
@@:
	jecxz	.clc_ret
	add	[ebp + editor_data.cursor_y], ecx
	add	[cursor_y], ecx
	call	editor_up_scroll
	stc
	ret

editor_OnExit:
	mov	edx, [ebp+editor_data.hPlugin]
	test	edx, edx
	jz	@f
	mov	ebx, [ebp+editor_data.hFile]
	call	close_handle_if_unused
@@:
	ret

find_in_file_dlg:
        mov     ebx, find_in_file_dlgdata
        mov     eax, [cur_width]
        sub     eax, 12
        mov     [ebx + dlgtemplate.width], eax
        dec     eax
        dec     eax
        mov     [ebx - find_in_file_dlgdata + find_in_file_dlgdata.width2], eax
        shr     eax, 1
        dec     eax
        dec     eax
        mov     [ebx - find_in_file_dlgdata + find_in_file_dlgdata.search_x2], eax
        sub     eax, aSearchBLength-1
        mov     [ebx - find_in_file_dlgdata + find_in_file_dlgdata.search_x1], eax
        add     eax, aSearchBLength+3
        mov     [ebx - find_in_file_dlgdata + find_in_file_dlgdata.cnl_x1], eax
        add     eax, aCancelBLength - 1
        mov     [ebx - find_in_file_dlgdata + find_in_file_dlgdata.cnl_x2], eax
        mov     byte [ebx - find_in_file_dlgdata + find_in_file_dlgdata.flags0], 0xC
        and     byte [ebx - find_in_file_dlgdata + find_in_file_dlgdata.flags1], not 4
        and     byte [ebx - find_in_file_dlgdata + find_in_file_dlgdata.flags2], not 4
	and	byte [ebx - find_in_file_dlgdata + find_in_file_dlgdata.flags_case], not 4
	and	byte [ebx - find_in_file_dlgdata + find_in_file_dlgdata.flags_whole], not 4
        push    ebx
        call    DialogBox
	cmp	eax, find_in_file_dlgdata.search_btn
	ret
