<commit_before>#    This file is part of Metasm, the Ruby assembly manipulation suite
#    Copyright (C) 2006-2009 <NAME>
#
#    Licence is LGPL, see LICENCE in the top-level directory

module Metasm
module Gui
class AsmListingWidget < DrawableWidget
	attr_accessor :dasm, :arrow_zone_w

	def initialize_widget(dasm, parent_widget)
		@dasm = dasm
		@parent_widget = parent_widget

		@arrows = []	# array of [linefrom, lineto] (may be :up or :down for offscreen)
		@line_address = []
		@line_text = []
		@line_text_color = []
		@want_update_line_text = @want_update_caret = true
		@wantaddr = nil
		@arrow_zone_w = 40

		addrs = @dasm.sections.keys.grep(Integer)
		@minaddr = addrs.min.to_i
		@maxaddr = (addrs.max + @dasm.sections[addrs.max].length rescue (1 << @dasm.cpu.size))
		@startaddr = @dasm.prog_binding['entrypoint'] || @minaddr

		@default_color_association = { :comment => :darkblue, :label => :darkgreen, :text => :black,
			  :instruction => :black, :address => :blue, :caret => :black,
			  :background => :white, :cursorline_bg => :paleyellow, :hl_word => :palered,
			  :arrows_bg => :palegrey, :arrow_up => :darkblue, :arrow_dn => :darkyellow, :arrow_hl => :red }
	end

	def resized(w, h)
		col = w/@font_width
		lin = h/@font_height
		@caret_x = col-1 if @caret_x >= col
		@caret_y = lin-1 if @caret_y >= lin and lin > 0
		gui_update
	end

	def adjust_startaddr(off=0, update = true)
		@startaddr += off
		@startaddr = @maxaddr - 1 if @startaddr.kind_of? Integer and @startaddr >= @maxaddr
		if off = (0..16).find { |off_| di = @dasm.decoded[@startaddr-off_] and di.respond_to? :bin_length and di.bin_length > off_ } and off != 0
			# align on @decoded boundary
			@startaddr -= off
		end
		@startaddr = @minaddr if @startaddr.kind_of? Integer and @startaddr < @minaddr
		gui_update if update
	end

	def click(x, y)
		set_caret_from_click(x - @arrow_zone_w, y)
	end

	def rightclick(x, y)
		click(x, y)
		@parent_widget.clone_window(@hl_word, :listing)
	end

	def doubleclick(x, y)
		click(x, y)
		@parent_widget.focus_addr(@hl_word)
	end

	def mouse_wheel(dir, x, y)
		case dir
		when :up
			# TODO handle block start (multiline) / data aggregation (db 100h dup(?), strings..)
			@wantaddr = @line_address[@caret_y]
			adjust_startaddr(-1, false)
			adjust_startaddr(-1, false)
			adjust_startaddr(-1, false)
			adjust_startaddr(-1)
		when :down
			# scroll down 4 lines, or more if all the 4 1st lines have the same addr (eg block start)
			@wantaddr = @line_address[@caret_y]
			a = @line_address[4..-1].find { |v| v != @line_address[0] } if @line_address[4]
			@startaddr = a || (@startaddr + 4)
			adjust_startaddr
		end
	end

	# renders the disassembler from @startaddr
	def paint
		w_w = width
		w_h = height

		# arrow bg
		draw_rectangle_color(:arrows_bg, 0, 0, @arrow_zone_w, w_h)

		# TODO scroll line-by-line when an addr is displayed on multiple lines (eg labels/comments)
		# TODO selection

		update_line_text if @want_update_line_text
		update_caret if @want_update_caret

		if @parent_widget.bg_color_callback
			ly = 0
			@line_address.each { |a|
				if c = @parent_widget.bg_color_callback[a]
					draw_rectangle_color(c, 0, ly*@font_height, w_w, @font_height)
				end
				ly += 1
			}
		end

		# current window position
		x = @arrow_zone_w + 1
		y = 0

		# renders a string at current cursor position with a color
		# must not include newline
		render = lambda { |str, color|
			# function ends when we write under the bottom of the listing
			next if not str or y >= w_h or x >= w_w
			if @hl_word and @hl_word != ''
				stmp = str
				pre_x = 0
				while stmp =~ /^(.*?)(\b#{Regexp.escape @hl_word}\b)/
					s1, s2 = $1, $2
					pre_x += s1.length * @font_width
					hl_x = s2.length * @font_width
					draw_rectangle_color(:hl_word, x+pre_x, y, hl_x, @font_height)
					pre_x += hl_x
					stmp = stmp[s1.length+s2.length..-1]
				end
			end
			draw_string_color(color, x, y, str)
			x += str.length * @font_width
		}<commit_msg>dasmgui: do not draw bg_color_callback in listings array zone<commit_after>#    This file is part of Metasm, the Ruby assembly manipulation suite
#    Copyright (C) 2006-2009 <NAME>
#
#    Licence is LGPL, see LICENCE in the top-level directory

module Metasm
module Gui
class AsmListingWidget < DrawableWidget
	attr_accessor :dasm, :arrow_zone_w

	def initialize_widget(dasm, parent_widget)
		@dasm = dasm
		@parent_widget = parent_widget

		@arrows = []	# array of [linefrom, lineto] (may be :up or :down for offscreen)
		@line_address = []
		@line_text = []
		@line_text_color = []
		@want_update_line_text = @want_update_caret = true
		@wantaddr = nil
		@arrow_zone_w = 40

		addrs = @dasm.sections.keys.grep(Integer)
		@minaddr = addrs.min.to_i
		@maxaddr = (addrs.max + @dasm.sections[addrs.max].length rescue (1 << @dasm.cpu.size))
		@startaddr = @dasm.prog_binding['entrypoint'] || @minaddr

		@default_color_association = { :comment => :darkblue, :label => :darkgreen, :text => :black,
			  :instruction => :black, :address => :blue, :caret => :black,
			  :background => :white, :cursorline_bg => :paleyellow, :hl_word => :palered,
			  :arrows_bg => :palegrey, :arrow_up => :darkblue, :arrow_dn => :darkyellow, :arrow_hl => :red }
	end

	def resized(w, h)
		col = w/@font_width
		lin = h/@font_height
		@caret_x = col-1 if @caret_x >= col
		@caret_y = lin-1 if @caret_y >= lin and lin > 0
		gui_update
	end

	def adjust_startaddr(off=0, update = true)
		@startaddr += off
		@startaddr = @maxaddr - 1 if @startaddr.kind_of? Integer and @startaddr >= @maxaddr
		if off = (0..16).find { |off_| di = @dasm.decoded[@startaddr-off_] and di.respond_to? :bin_length and di.bin_length > off_ } and off != 0
			# align on @decoded boundary
			@startaddr -= off
		end
		@startaddr = @minaddr if @startaddr.kind_of? Integer and @startaddr < @minaddr
		gui_update if update
	end

	def click(x, y)
		set_caret_from_click(x - @arrow_zone_w, y)
	end

	def rightclick(x, y)
		click(x, y)
		@parent_widget.clone_window(@hl_word, :listing)
	end

	def doubleclick(x, y)
		click(x, y)
		@parent_widget.focus_addr(@hl_word)
	end

	def mouse_wheel(dir, x, y)
		case dir
		when :up
			# TODO handle block start (multiline) / data aggregation (db 100h dup(?), strings..)
			@wantaddr = @line_address[@caret_y]
			adjust_startaddr(-1, false)
			adjust_startaddr(-1, false)
			adjust_startaddr(-1, false)
			adjust_startaddr(-1)
		when :down
			# scroll down 4 lines, or more if all the 4 1st lines have the same addr (eg block start)
			@wantaddr = @line_address[@caret_y]
			a = @line_address[4..-1].find { |v| v != @line_address[0] } if @line_address[4]
			@startaddr = a || (@startaddr + 4)
			adjust_startaddr
		end
	end

	# renders the disassembler from @startaddr
	def paint
		w_w = width
		w_h = height

		# arrow bg
		draw_rectangle_color(:arrows_bg, 0, 0, @arrow_zone_w, w_h)

		# TODO scroll line-by-line when an addr is displayed on multiple lines (eg labels/comments)
		# TODO selection

		update_line_text if @want_update_line_text
		update_caret if @want_update_caret

		if @parent_widget.bg_color_callback
			ly = 0
			@line_address.each { |a|
				if c = @parent_widget.bg_color_callback[a]
					draw_rectangle_color(c, @arrow_zone_w, ly*@font_height, w_w, @font_height)
				end
				ly += 1
			}
		end

		# current window position
		x = @arrow_zone_w + 1
		y = 0

		# renders a string at current cursor position with a color
		# must not include newline
		render = lambda { |str, color|
			# function ends when we write under the bottom of the listing
			next if not str or y >= w_h or x >= w_w
			if @hl_word and @hl_word != ''
				stmp = str
				pre_x = 0
				while stmp =~ /^(.*?)(\b#{Regexp.escape @hl_word}\b)/
					s1, s2 = $1, $2
					pre_x += s1.length * @font_width
					hl_x = s2.length * @font_width
					draw_rectangle_color(:hl_word, x+pre_x, y, hl_x, @font_height)
					pre_x += hl_x
					stmp = stmp[s1.length+s2.length..-1]
				end
			end
			draw_string_color(color, x, y, str)
			x += str.length * @font_width
		}
{'fraction_non_alphanumeric': 0.123, 'fraction_numerical': 0.012875, 'mean_word_length': 3.5589743589743588, 'pattern_counts': {'":': 0, '<': 13, '<?xml version=': 0, '>': 45, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '784330', 'n_tokens_mistral': 3423, 'n_tokens_neox': 2999, 'n_words': 822}