lib/scryglass/session.rb in scryglass-2.0.2 vs lib/scryglass/session.rb in scryglass-2.1.0

- old
+ new

@@ -7,37 +7,38 @@ attr_accessor :all_ros, :current_ro, :special_command_targets attr_accessor :current_view_coords, :current_lens, :current_subject_type, :view_panels, :current_panel_type, - :progress_bar, :current_warning_messages + :progress_bar, :current_warning_messages, + :content_shape_changed, + :previous_screen_dimensions attr_accessor :user_signals, :last_search, :number_to_move attr_accessor :session_manager, :signal_to_manager, :session_is_current, :tab_icon, :session_view_start_time CURSOR_CHARACTER = '–' # These are en dashes (alt+dash), not hyphens or em dashes. - SEARCH_PROMPT = "\e[7mSearch for (regex, case-sensitive): /\e[00m" - VARNAME_PROMPT = "\e[7mName your object(s): @\e[00m" - + METHOD_NAME_PROMPT = "\e[7mMethod(s) to call on object(s): object\e[00m" SUBJECT_TYPES = [ :value, :key ].freeze - CSI = "\e[" # "(C)ontrol (S)equence (I)ntroducer" for ANSI sequences KEY_MAP = { escape: 'esc', # Not a normal keystroke, see: genuine_escape_key_press ctrl_c: "\u0003", quit_session: 'q', delete_session_tab: 'Q', change_session_right: "\t", # Tab change_session_left: 'Z', # Shift+Tab (well, one of its signals, after "\e" and "[") + start_new_session_from_target: 't', + restart_session_from_target: 'T', digit_1: '1', digit_2: '2', digit_3: '3', digit_4: '4', digit_5: '5', @@ -48,16 +49,16 @@ digit_0: '0', move_cursor_up: 'A', # Up arrow (well, one of its signals, after "\e" and "[") move_cursor_down: 'B', # Down arrow (well, one of its signals, after "\e" and "[") open_bucket: 'C', # Right arrow (well, one of its signals, after "\e" and "[") close_bucket: 'D', # Left arrow (well, one of its signals, after "\e" and "[") - homerow_move_cursor_up: 'k', # To be like VIM arrow keys + homerow_move_cursor_up: 'k', # To be like VIM arrow keys homerow_move_cursor_up_fast: 'K', # To be like VIM arrow keys - homerow_move_cursor_down: 'j', # To be like VIM arrow keys + homerow_move_cursor_down: 'j', # To be like VIM arrow keys homerow_move_cursor_down_fast: 'J', # To be like VIM arrow keys - homerow_open_bucket: 'l', # To be like VIM arrow keys - homerow_close_bucket: 'h', # To be like VIM arrow keys + homerow_open_bucket: 'l', # To be like VIM arrow keys + homerow_close_bucket: 'h', # To be like VIM arrow keys # Note, shift-UP and shift-DOWN are not here, as those work very # differently: by virtue of the type-a-number-first functionality. toggle_view_panel: ' ', switch_lens: '>', switch_subject_type: '<', @@ -72,10 +73,11 @@ control_screen: '?', build_instance_variables: '@', build_ar_relations: '.', build_enum_children: '(', smart_open: 'o', + build_method_results: 'c', select_siblings: '|', select_all: '*', select_current: '-', start_search: '/', continue_search: 'n', @@ -102,10 +104,12 @@ self.session_manager = nil self.signal_to_manager = nil self.tab_icon = nil self.session_is_current = false self.session_view_start_time = nil + self.content_shape_changed = true + self.previous_screen_dimensions = $stdout.winsize top_ro = roify(seed, parent_ro: nil, depth: 1) top_ro.has_cursor = true self.current_ro = top_ro @@ -126,11 +130,11 @@ last_two_signals.last || last_two_signals.first end def run_scry_ui redraw = true - signal_to_manager = nil + self.signal_to_manager = nil self.session_view_start_time = Time.now # For this particular tab/session ## On hold: Record/Playback Functionality: # case actions # when :record @@ -278,20 +282,28 @@ when KEY_MAP[:move_view_right_fast] current_view_panel.move_view_right(50) when KEY_MAP[:build_instance_variables] build_instance_variables_for_target_ros + self.content_shape_changed = true tree_view.slide_view_to_cursor # Just a nice-to-have when KEY_MAP[:build_ar_relations] build_activerecord_relations_for_target_ros + self.content_shape_changed = true tree_view.slide_view_to_cursor # Just a nice-to-have when KEY_MAP[:build_enum_children] build_enum_children_for_target_ros + self.content_shape_changed = true tree_view.slide_view_to_cursor # Just a nice-to-have when KEY_MAP[:smart_open] smart_open_target_ros + self.content_shape_changed = true tree_view.slide_view_to_cursor # Just a nice-to-have + when KEY_MAP[:build_method_results] + build_method_result_ros + self.content_shape_changed = true + tree_view.slide_view_to_cursor # Just a nice-to-have when KEY_MAP[:select_siblings] sibling_ros = if current_ro.top_ro? [top_ro] else @@ -321,30 +333,34 @@ end when KEY_MAP[:start_search] initiate_search when KEY_MAP[:continue_search] + # TODO: extract in separate commit if last_search go_to_next_search_result else message = { text: 'No Search has been entered', end_time: Time.now + 2 } self.current_warning_messages << message end - + when KEY_MAP[:start_new_session_from_target] + self.signal_to_manager = :start_new_session_from_target + return subjects_of_target_ros + when KEY_MAP[:restart_session_from_target] + self.signal_to_manager = :restart_session_from_target + return subjects_of_target_ros when KEY_MAP[:change_session_right] self.signal_to_manager = :change_session_right return when KEY_MAP[:change_session_left] self.signal_to_manager = :change_session_left return when KEY_MAP[:name_objects] name_subjects_of_target_ros when KEY_MAP[:return_objects] self.signal_to_manager = :return - subjects = subjects_of_target_ros - self.special_command_targets = [] - return subjects + return subjects_of_target_ros end beep_if_user_had_to_wait(wait_start_time) end end @@ -412,18 +428,22 @@ action_count ||= !number_to_move.empty? ? number_to_move.to_i : 1 navigate_up_multiple(action_count) self.number_to_move = '' tree_view.slide_view_to_cursor + + self.content_shape_changed = true if current_panel_type == :lens end def move_cursor_down_action(action_count = nil) action_count ||= !number_to_move.empty? ? number_to_move.to_i : 1 navigate_down_multiple(action_count) self.number_to_move = '' tree_view.slide_view_to_cursor + + self.content_shape_changed = true if current_panel_type == :lens end def clear_tracked_values self.special_command_targets = [] self.last_search = nil @@ -505,12 +525,11 @@ while scanning_ro.parent_ro expand!(scanning_ro.parent_ro) scanning_ro = scanning_ro.parent_ro end - tree_view.recalculate_boundaries # Yes, necessary :) - lens_view.recalculate_boundaries # Yes, necessary :) + self.content_shape_changed = true # Needed here even if ros weren't expanded. tree_view.current_view_coords = { y: 0, x: 0 } tree_view.slide_view_to_cursor else message = { text: 'No Match Found', end_time: Time.now + 2 } self.current_warning_messages << message @@ -591,10 +610,11 @@ elsif current_ro.parent_ro collapse!(current_ro.parent_ro) end move_cursor_to(current_ro.parent_ro) until current_ro.visible? + self.content_shape_changed = true tree_view.slide_view_to_cursor end def expand_targets if special_command_targets.any? @@ -604,10 +624,12 @@ target_ros.each { |target_ro| expand!(target_ro) } self.special_command_targets = [] else expand!(current_ro) end + + self.content_shape_changed = true end def reset_the_view_or_cursor if current_view_panel.current_view_coords != { x: 0, y: 0 } current_view_panel.current_view_coords = { x: 0, y: 0 } @@ -615,12 +637,21 @@ move_cursor_to(top_ro) end end def draw_screen - current_view_panel.recalculate_boundaries # This now happens at every screen - # draw to account for the user changing the screen size. Otherwise glitch. + current_screen_dimensions = $stdout.winsize + screen_size_changed = current_screen_dimensions != previous_screen_dimensions + self.previous_screen_dimensions = current_screen_dimensions + + if content_shape_changed || screen_size_changed + current_view_panel.recalculate_boundaries + # ^This no longer happens at every screen draw, but only when + # determined necessary. + self.content_shape_changed = false + end + current_view_panel.ensure_correct_view_coords screen_string = current_view_panel.screen_string Hexes.overwrite_screen(screen_string) $stdout.write "#{CSI}1;1H" # Moves terminal cursor to top left corner, @@ -638,10 +669,45 @@ $stdout.write "#{CSI}1;#{VARNAME_PROMPT.ansiless_length + 1}H" # (Moves # console cursor to just after the varname prompt, before user types) $stdin.gets.chomp end + def get_method_text_from_user + _screen_height, screen_width = $stdout.winsize + $stdout.write "#{CSI}1;1H" # (Moves console cursor to top left corner) + $stdout.print ' ' * screen_width + $stdout.write "#{CSI}1;1H" # (Moves console cursor to top left corner) + $stdout.print METHOD_NAME_PROMPT + $stdout.write "#{CSI}1;#{METHOD_NAME_PROMPT.ansiless_length + 1}H" # (Moves + # console cursor to just after the search prompt, before user types) + $stdin.gets.chomp + end + + def build_method_result_ros + method_text = get_method_text_from_user + + if method_text.empty? + message = { text: 'Call text cannot be blank', + end_time: Time.now + 2 } + self.current_warning_messages << message + print "\a" # (Audio 'beep') + return + end + + if method_text[0] =~ /[a-z]|[A-Z]/ + message = { text: 'Call text must start with \'.\' or other symbol', + end_time: Time.now + 3 } + self.current_warning_messages << message + print "\a" # (Audio 'beep') + return + end + + build_method_results_for_target_ros(method_text) + + self.special_command_targets = [] + end + def name_subjects_of_target_ros typed_name = get_subject_name_from_user typed_name = typed_name.tr(' ', '') if typed_name.empty? @@ -720,23 +786,28 @@ when :tree :lens when :lens :tree end + + self.content_shape_changed = true end def toggle_current_subject_type self.current_subject_type = case current_subject_type when :value :key when :key :value end + + self.content_shape_changed = true end def scroll_lens_type self.current_lens += 1 + self.content_shape_changed = true end def move_cursor_to(new_ro) current_ro.has_cursor = false new_ro.has_cursor = true