Class: Ruvi::EditorApp
- Inherits:
-
Object
- Object
- Ruvi::EditorApp
- Defined in:
- lib/debug.rb,
lib/front.rb,
lib/search.rb,
lib/shikaku.rb,
lib/widgets.rb,
lib/bindings.rb,
lib/commands.rb,
lib/movement.rb,
lib/curses-ui.rb,
lib/selections.rb,
lib/timemachine.rb,
lib/virtualbuffers.rb
Defined Under Namespace
Modules: BaseFakeBufferModule, BufferListExtension, DiffLogger, HierarchyListExtension Classes: BufferIdAllocator, CommandContext, SearchContext, Settings
Constant Summary collapse
- ASCII_UPPER =
TODO we should replace all this bullshit - by translating all the possible curses keys
255
- CR_KEY =
13
- BACKSPACE_KEYS =
[8, 127, 263]
- ESC_KEY =
27
- KEYPRESS_COUNT_INTERVAL =
0.2 - the higher this is the higher LAST_INTERVAL_KEYPRESS_COUNT is relatively
0.1
- FORCE_REDRAW_TIMEOUT =
0.1
0.005
- LAST_INTERVAL_KEYPRESS_COUNT =
heavily related to KEYPRESS_COUNT_INTERVAL
2
- SELECT_POLL_INTERVAL =
0.02
- SUSPEND_KEYS =
[26, 407]
Instance Attribute Summary collapse
-
#buffers ⇒ Object
readonly
Returns the value of attribute buffers.
-
#change_listeners ⇒ Object
readonly
Returns the value of attribute change_listeners.
-
#current_buffer ⇒ Object
readonly
too many attributes!!!!!.
-
#current_docview ⇒ Object
readonly
Returns the value of attribute current_docview.
-
#debug_buffer ⇒ Object
readonly
Returns the value of attribute debug_buffer.
-
#docview2 ⇒ Object
Returns the value of attribute docview2.
-
#docview_to_ruler ⇒ Object
Returns the value of attribute docview_to_ruler.
-
#end_char_mode ⇒ Object
Returns the value of attribute end_char_mode.
-
#history_buffer ⇒ Object
readonly
Returns the value of attribute history_buffer.
-
#hl_selection ⇒ Object
readonly
Returns the value of attribute hl_selection.
-
#main_paste_buffer ⇒ Object
readonly
Returns the value of attribute main_paste_buffer.
-
#mutex ⇒ Object
Returns the value of attribute mutex.
-
#selection ⇒ Object
readonly
Returns the value of attribute selection.
-
#settings ⇒ Object
Returns the value of attribute settings.
-
#status_bar ⇒ Object
readonly
Returns the value of attribute status_bar.
-
#widgets ⇒ Object
readonly
Returns the value of attribute widgets.
Class Method Summary collapse
- .alloc_new_buffer ⇒ Object
- .app_instance ⇒ Object
-
.each_lineslice_in_selection(buffer, selc) ⇒ Object
REQUIRES RIGHT WAY UP SELECTION.
- .file_to_buffer_lines(fname) ⇒ Object
- .invalidate_buffer_line(buffer, y) ⇒ Object
- .join_next_line_onto_this(buffer, myy) ⇒ Object
-
.lineslice_for_selection_intersect_with_y(selc, currenty, line_len) ⇒ Object
REQUIRES RIGHT WAY UP SELECTION - though it may not appear that is does :).
- .load_file_as_buffer(app, fname) ⇒ Object
-
.manip_selection(buffer, selc, manipulation, paste_buffer) ⇒ Object
USES right_way_up.
- .new_buffer(app, *options) ⇒ Object
-
.perform_layout ⇒ Object
each status bar uses up 1 line height wise the remaining main window hbox gets the remaining space.
Instance Method Summary collapse
- #add_binding(initial_options, *keys_a, &block) ⇒ Object
- #add_command_binding(*keys, &block) ⇒ Object
- #add_curses_key_translators(*params) ⇒ Object
- #add_insert_binding(*keys, &block) ⇒ Object
- #begin_insert_mode(buffer) ⇒ Object
- #begin_normal_mode(buffer) ⇒ Object
-
#blah(maxx, maxy) ⇒ Object
TODO.
-
#blub ⇒ Object
TODO.
- #buffer_changed_to(buffer) ⇒ Object
- #buffers_to_save ⇒ Object
- #calculate_autoindent(buffer, line, my_y, deindent_block) ⇒ Object
- #clear_buffers_with_extension(extension) ⇒ Object
- #cmd_execute(buffer, cmd_line) ⇒ Object
-
#config_get_nu ⇒ Object
TODO these config routines are ugly…
- #config_get_split ⇒ Object
- #config_get_sw ⇒ Object
- #config_get_tab_size ⇒ Object
- #config_get_tw ⇒ Object
- #create_selection(buffer, type, *options, &block) ⇒ Object
- #curs_x ⇒ Object
- #curs_y ⇒ Object
- #dbg_selc(buffer, selc) ⇒ Object
- #delete_binding(initial_options, key) ⇒ Object
- #delete_command_binding(key) ⇒ Object
- #delete_insert_binding(key) ⇒ Object
- #display_cursor(buffer, docview) ⇒ Object
- #do_action(buffer, selc) ⇒ Object
- #do_cmd_mode(c, current_string, &block) ⇒ Object
- #do_command(buffer, c) ⇒ Object
- #do_letter(buffer, c) ⇒ Object
- #do_movement_key(buffer, c, *options) ⇒ Object
- #do_search(buffer, c, word = nil) ⇒ Object
- #each_real_buffer ⇒ Object
- #end_selection(buffer) ⇒ Object
- #ensure_buffer_highlighted(buffer, pass = false) ⇒ Object
- #exec_into_buffer_lines(cmd) ⇒ Object
- #final_widget_position(widget) ⇒ Object
- #final_widget_size(widget) ⇒ Object
- #find_match_in_line(re, line, myx, go_backwards, forced_next) ⇒ Object
- #find_prefix(completions) ⇒ Object
- #finish ⇒ Object
- #flush_finish_redraw(buffer) ⇒ Object
- #get_binding_hash_key_pair(initial_options, keys) ⇒ Object
- #get_cmd_line ⇒ Object
- #get_indent_level(line) ⇒ Object
- #get_user_input(question = "") ⇒ Object
- #get_word_under_cursor(buffer, *options) ⇒ Object
- #handle_generic_command(buffer, c) ⇒ Object
-
#initialize ⇒ EditorApp
constructor
A new instance of EditorApp.
- #input_loop ⇒ Object
- #invalidate_screen_line(buffer, y) ⇒ Object
- #itr_backwards(buffer, tok, y) ⇒ Object
- #itr_forewards(buffer, tok, y) ⇒ Object
- #line_displayed?(buffer, y) ⇒ Boolean
- #load_script_file(scriptfname) ⇒ Object
-
#make_selection_exclusive_given_current_position(buffer, selc) ⇒ Object
SELECTION RELATED STUFF #.
-
#move_x(buffer, x_diff, allow_y_change = true) ⇒ Object
WRAPPING MOVEMENT #.
- #move_y(buffer, y_diff) ⇒ Object
- #new_status_bar(buf) ⇒ Object
-
#next_word(buffer, *options) ⇒ Object
CLEVER WORD SKIP STUFF #.
- #normalize_cursor_key(c) ⇒ Object
- #notify_of_change(the_change, direction) ⇒ Object
- #perform_search(buffer, forced_next) ⇒ Object
- #pop_paste_buffer ⇒ Object
- #position_cursor(buffer, docview) ⇒ Object
- #real_buffers ⇒ Object
- #redraw(buffer) ⇒ Object
- #redraw_from_and_including(buffer, y) ⇒ Object
- #refresh_widgets ⇒ Object
- #remove_unneeded_statusbars ⇒ Object
-
#reset_state ⇒ Object
TODO this is hecka big, can’t we seperate out more stuff?.
- #save_buffer_as_file(buffer, fname = nil) ⇒ Object
- #screen_height ⇒ Object
-
#scroll_down(buffer) ⇒ Object
test - scroll up and down in large buffer, needs visual test really.
- #scroll_to_bottom(buffer) ⇒ Object
- #scroll_to_top(buffer) ⇒ Object
-
#scroll_up(buffer) ⇒ Object
test - scroll up and down in large buffer, needs visual test really.
- #send_key(c) ⇒ Object
- #setup_bindings ⇒ Object
- #setup_cmd(cmd_string, re, &block) ⇒ Object
- #setup_cmd_override(re, &block) ⇒ Object
- #setup_default_command_set ⇒ Object
- #setup_extensions ⇒ Object
- #show_line_with_marker(buffer, point, line = nil) ⇒ Object
- #start_background_highlighter ⇒ Object
- #status_bar_edit_line(status, pos = -1) ⇒ Object
- #switch_to_buffer(buf = @last_buffer) ⇒ Object
- #token_itr(buffer, tok, y, forwards, &block) ⇒ Object
- #update_focus ⇒ Object
- #update_ruler_state ⇒ Object
-
#update_selection(buffer) ⇒ Object
USES right_way_up.
- #update_split_state ⇒ Object
Constructor Details
#initialize ⇒ EditorApp
Returns a new instance of EditorApp.
118 119 120 |
# File 'lib/shikaku.rb', line 118 def initialize reset_state end |
Instance Attribute Details
#buffers ⇒ Object (readonly)
Returns the value of attribute buffers.
69 70 71 |
# File 'lib/shikaku.rb', line 69 def buffers @buffers end |
#change_listeners ⇒ Object (readonly)
Returns the value of attribute change_listeners.
73 74 75 |
# File 'lib/shikaku.rb', line 73 def change_listeners @change_listeners end |
#current_buffer ⇒ Object (readonly)
too many attributes!!!!!
67 68 69 |
# File 'lib/shikaku.rb', line 67 def current_buffer @current_buffer end |
#current_docview ⇒ Object (readonly)
Returns the value of attribute current_docview.
411 412 413 |
# File 'lib/shikaku.rb', line 411 def current_docview @current_docview end |
#debug_buffer ⇒ Object (readonly)
Returns the value of attribute debug_buffer.
68 69 70 |
# File 'lib/shikaku.rb', line 68 def debug_buffer @debug_buffer end |
#docview2 ⇒ Object
Returns the value of attribute docview2.
74 75 76 |
# File 'lib/shikaku.rb', line 74 def docview2 @docview2 end |
#docview_to_ruler ⇒ Object
Returns the value of attribute docview_to_ruler.
74 75 76 |
# File 'lib/shikaku.rb', line 74 def docview_to_ruler @docview_to_ruler end |
#end_char_mode ⇒ Object
Returns the value of attribute end_char_mode.
74 75 76 |
# File 'lib/shikaku.rb', line 74 def end_char_mode @end_char_mode end |
#history_buffer ⇒ Object (readonly)
Returns the value of attribute history_buffer.
68 69 70 |
# File 'lib/shikaku.rb', line 68 def history_buffer @history_buffer end |
#hl_selection ⇒ Object (readonly)
Returns the value of attribute hl_selection.
70 71 72 |
# File 'lib/shikaku.rb', line 70 def hl_selection @hl_selection end |
#main_paste_buffer ⇒ Object (readonly)
Returns the value of attribute main_paste_buffer.
68 69 70 |
# File 'lib/shikaku.rb', line 68 def main_paste_buffer @main_paste_buffer end |
#mutex ⇒ Object
Returns the value of attribute mutex.
75 76 77 |
# File 'lib/shikaku.rb', line 75 def mutex @mutex end |
#selection ⇒ Object (readonly)
Returns the value of attribute selection.
70 71 72 |
# File 'lib/shikaku.rb', line 70 def selection @selection end |
#settings ⇒ Object
Returns the value of attribute settings.
74 75 76 |
# File 'lib/shikaku.rb', line 74 def settings @settings end |
#status_bar ⇒ Object (readonly)
Returns the value of attribute status_bar.
71 72 73 |
# File 'lib/shikaku.rb', line 71 def @status_bar end |
#widgets ⇒ Object (readonly)
Returns the value of attribute widgets.
72 73 74 |
# File 'lib/shikaku.rb', line 72 def @widgets end |
Class Method Details
.alloc_new_buffer ⇒ Object
301 302 303 304 |
# File 'lib/shikaku.rb', line 301 def self.alloc_new_buffer BufferIdAllocator::instance.max_buffer_idx += 1 (BufferIdAllocator::instance.max_buffer_idx - 1) end |
.app_instance ⇒ Object
122 123 124 |
# File 'lib/shikaku.rb', line 122 def EditorApp.app_instance @@app end |
.each_lineslice_in_selection(buffer, selc) ⇒ Object
REQUIRES RIGHT WAY UP SELECTION
121 122 123 124 125 126 127 128 |
# File 'lib/selections.rb', line 121 def EditorApp.each_lineslice_in_selection buffer, selc ((selc.s.y)..(selc.e.y)).each { |currenty| line = buffer.lines[currenty] break if currenty >= buffer.lines.length yield EditorApp.lineslice_for_selection_intersect_with_y(selc, currenty, line.length) } end |
.file_to_buffer_lines(fname) ⇒ Object
343 344 345 346 347 348 349 350 351 352 353 |
# File 'lib/shikaku.rb', line 343 def self.file_to_buffer_lines fname buffer_lines = [] File.open(fname, "r") { |fp| fp.each_line { |l| buffer_lines << BufferLine.new(l.chomp) } } buffer_lines end |
.invalidate_buffer_line(buffer, y) ⇒ Object
399 400 401 |
# File 'lib/shikaku.rb', line 399 def EditorApp.invalidate_buffer_line buffer, y buffer.redraw_list << y end |
.join_next_line_onto_this(buffer, myy) ⇒ Object
773 774 775 776 777 778 779 780 781 782 783 784 785 |
# File 'lib/shikaku.rb', line 773 def EditorApp.join_next_line_onto_this buffer, myy # join current line onto previous line - move to old end of last line line_to_join = nil DiffLogger::RemoveLineChange.new(buffer, myy+1) { line_to_join = buffer.lines.delete_at(myy+1) } DiffLogger::ModifyLineChange.new(buffer, myy) { join_to = buffer.lines[myy] buffer.move_to_x join_to.length join_to << line_to_join EditorApp::app_instance.redraw buffer # should actually just redraw from this point on } end |
.lineslice_for_selection_intersect_with_y(selc, currenty, line_len) ⇒ Object
REQUIRES RIGHT WAY UP SELECTION - though it may not appear that is does :)
53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 |
# File 'lib/selections.rb', line 53 def EditorApp.lineslice_for_selection_intersect_with_y selc, currenty, line_len selc = selc.dup hlls = LineSlice.new hlls.newline_at_start, hlls.newline_at_end = false, false hlls.y = currenty lined = (selc.mode == :selc_lined) box = (selc.mode == :selc_boxed) multiline = (selc.e.y != selc.s.y) end_char_mode = (EditorApp::app_instance.end_char_mode and selc.s != selc.e) sorted_x_1, sorted_x_2 = *([selc.s.x, selc.e.x].sort) if not (((selc.s.y)..(selc.e.y)) === currenty) return nil elsif multiline and currenty == selc.s.y and !box # first line in selection hlls.x1 = lined ? 0 : sorted_x_1 hlls.x2 = line_len hlls.newline_at_start = lined hlls.newline_at_end = true elsif multiline and currenty == selc.e.y and !box # end line of selection, if in end_char_mode we wish to join with next line # to indicate a join, we want start + !end - app.end_char_mode # TODO - clean up the boolean logic!!! if lined hlls.newline_at_end = lined hlls.newline_at_start = true elsif end_char_mode hlls.newline_at_end = false hlls.newline_at_start = true else hlls.newline_at_end = false hlls.newline_at_start = false end hlls.x1 = 0 hlls.x2 = lined ? line_len : sorted_x_2 elsif !multiline and currenty == selc.s.y and !box # implicit: and currenty == selc.e.y # "!=" surely??? # single line selection - if its end_char_mode we wish to join to next line hlls.newline_at_end = (lined || end_char_mode) hlls.newline_at_start = lined hlls.x1 = lined ? 0 : sorted_x_1 hlls.x2 = lined ? line_len : sorted_x_2 else hlls.newline_at_end = !box hlls.newline_at_start = !box hlls.x1 = box ? sorted_x_1 : 0 hlls.x2 = box ? sorted_x_2 : line_len end hlls.x2 += 1 return hlls end |
.load_file_as_buffer(app, fname) ⇒ Object
355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 |
# File 'lib/shikaku.rb', line 355 def self.load_file_as_buffer app, fname buf = self.new_buffer app, fname, :no_blank_line, :need_bnum, :delay_edlog_load if $replaying buf.lines = $action_replay_log.buffers_loaded[fname] else begin buf.lines += self.file_to_buffer_lines(fname) rescue => e # wait for user to :w rather than failing now "file not found: creating empty buffer" unless @status_bar.nil? end $action_replay_log.buffers_loaded[fname] = buf.lines end buf.lines << "" if buf.lines.empty? buf.dlog.load_or_create_difflog buf.update_highlighter buf end |
.manip_selection(buffer, selc, manipulation, paste_buffer) ⇒ Object
USES right_way_up
131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 |
# File 'lib/selections.rb', line 131 def EditorApp.manip_selection buffer, selc, manipulation, paste_buffer raise "manip_selection called for invalid selection object" if selc.invalid? paste_lines = BufferLineArray.new removed_lines = 0 selc = selc.right_way_up lineslices = [] EditorApp.each_lineslice_in_selection(buffer, selc) { |hlls| next if hlls.nil? lineslices << hlls } join_list = [] lineslices.each_with_index { |hlls, index| # NB - !newline_at_start + newline_at_end == join previous line with this (only at start of a selection) # - newline_at_start + newline_at_end == delete entire line # - !newline_at_start + !newline_at_end == just copy/modify entire line # - newline_at_start + !newline_at_end == join next line with this (only at end of a selection) lbuffer = nil case manipulation when :manip_cut updated_y = hlls.y - removed_lines if hlls.newline_at_start and hlls.newline_at_end DiffLogger::RemoveLineChange.new(buffer, updated_y) { lbuffer = BufferLine.new buffer.lines.delete_at(updated_y) removed_lines += 1 } else DiffLogger::ModifyLineChange.new(buffer, updated_y) { line = buffer.lines[updated_y] lbuffer = BufferLine.new line.slice!((hlls.x1)...(hlls.x2)).dup } end if !hlls.newline_at_start and hlls.newline_at_end and index == 0 join_list << updated_y end if hlls.newline_at_start and !hlls.newline_at_end and index == (lineslices.length - 1) join_list << updated_y - 1 if updated_y != buffer.lines.length - 1 end EditorApp.invalidate_buffer_line buffer, updated_y when :manip_copy # test - Vjjy lbuffer = BufferLine.new buffer.lines[hlls.y].slice((hlls.x1)...(hlls.x2)).dup end lbuffer.newline_at_start, lbuffer.newline_at_end = hlls.newline_at_start, hlls.newline_at_end paste_lines << lbuffer } # now we apply the joins post cut in order to prevent utter confusion join_list.each { |to_join| next if to_join == buffer.lines.length EditorApp.join_next_line_onto_this buffer, to_join } if manipulation == :manip_cut if buffer.lines.empty? DiffLogger::InsertLineAfterChange.new(buffer, -1) { buffer.lines << (BufferLine.new "") } end DiffLogger::CursorPositionChange.new(buffer, buffer.y) { y = (selc.s.y).clamp_to 0, buffer.last_line_num x = (selc.s.x).clamp_to 0, buffer.last_char_on_line(y) buffer.move_to x, y } end paste_buffer.lines = paste_lines end |
.new_buffer(app, *options) ⇒ Object
323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 |
# File 'lib/shikaku.rb', line 323 def self.new_buffer app, * fname = .detect { |opt| opt.is_a? String } no_blank_line = .include? :no_blank_line fake_buffer = .include? :fake_buffer needs_bnum = .include? :need_bnum delay_edlog_load = .include? :delay_edlog_load bnum = needs_bnum ? alloc_new_buffer : nil buf = DocumentBuffer.new app app.buffers << buf # TODO - sucky caller should do @buffers << ? buf.lines << BufferLine.new("") unless no_blank_line buf.fake_buffer = true if fake_buffer app. buf if needs_bnum fail "are you sure you want to have #{buf.fname} set and delay_edlog_load == #{delay_edlog_load}" \ if !buf.fname.nil? and delay_edlog_load buf.dlog.load_or_create_difflog unless delay_edlog_load buf.fname = fname unless fname.nil? buf.bnum = bnum buf end |
Instance Method Details
#add_binding(initial_options, *keys_a, &block) ⇒ Object
20 21 22 23 24 25 26 |
# File 'lib/front.rb', line 20 def add_binding , *keys_a, &block keys_a.each { |keys| hash, key = get_binding_hash_key_pair , keys hash[key] = block } end |
#add_command_binding(*keys, &block) ⇒ Object
35 |
# File 'lib/front.rb', line 35 def add_command_binding *keys, █ add_binding @stored_command_bindings, *keys, █ end |
#add_curses_key_translators(*params) ⇒ Object
206 207 208 209 |
# File 'lib/front.rb', line 206 def add_curses_key_translators *params hash = *params @curses_key_translators = @curses_key_translators.merge hash end |
#add_insert_binding(*keys, &block) ⇒ Object
36 |
# File 'lib/front.rb', line 36 def add_insert_binding *keys, █ add_binding @stored_insert_bindings, *keys, █ end |
#begin_insert_mode(buffer) ⇒ Object
81 82 83 84 85 |
# File 'lib/front.rb', line 81 def begin_insert_mode buffer buffer.dlog.partial_flush_mode = true @mode_stack = [:insert] @da_command = "" end |
#begin_normal_mode(buffer) ⇒ Object
87 88 89 90 91 92 |
# File 'lib/front.rb', line 87 def begin_normal_mode buffer @last_command = @da_command buffer.dlog.partial_flush_mode = false buffer.dlog.flush @mode_stack = [:normal] end |
#blah(maxx, maxy) ⇒ Object
TODO
84 85 86 87 88 89 90 91 |
# File 'lib/widgets.rb', line 84 def blah maxx, maxy # TODO @widgets.each { |w| next if w.kind_of? Box desc = WinDesc.new(*((w) + (w))) WinDescs::instance.descs[w] = desc } end |
#blub ⇒ Object
TODO
93 94 95 96 97 98 |
# File 'lib/widgets.rb', line 93 def blub # TODO return if @root.nil? stdscr = WinDescs::instance.stdscr blah stdscr.maxx, stdscr.maxy @needs_full_redraw = true end |
#buffer_changed_to(buffer) ⇒ Object
413 414 415 416 |
# File 'lib/shikaku.rb', line 413 def buffer_changed_to buffer current_docview.buffer = buffer @docview_to_ruler[current_docview].buffer = buffer end |
#buffers_to_save ⇒ Object
691 692 693 694 695 696 697 698 |
# File 'lib/shikaku.rb', line 691 def buffers_to_save buffers = [] each_real_buffer { |buffer| buffers << buffer if buffer.dlog.invalidated? } buffers end |
#calculate_autoindent(buffer, line, my_y, deindent_block) ⇒ Object
633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 |
# File 'lib/shikaku.rb', line 633 def calculate_autoindent buffer, line, my_y, deindent_block current_line = line current_line =~ /^(\s*)/ indent_level = $1 ? $1.length : 0 buffer.ensure_line_highlight my_y # ummm does current_line need to be used? # list of indenting keywords last_hlstack = (my_y == 0) ? [] : buffer.hlstacks[my_y - 1] hlstack = buffer.hlstacks[my_y] last_hlstack = [] if last_hlstack.nil? hlstack = [] if hlstack.nil? # if hlstack is bigger than previous hlstack then an indent is required if hlstack.length > last_hlstack.length bras = hlstack.reject { |k| k.str != "(" } kets = hlstack.reject { |k| k.str != ")" } if bras.length > kets.length indent_level = current_line.rindex("(") + 1 else indent_level += config_get_sw end elsif hlstack.length < last_hlstack.length diff = -config_get_sw was_bra = (last_hlstack[-1].str == "(") if was_bra da_y = my_y ridx = nil while true ridx = buffer.lines[da_y].rindex "(" break if !ridx.nil? da_y -= 1 end indent_level = get_indent_level(buffer.lines[da_y]) elsif deindent_block y = my_y DiffLogger::ModifyLineChange.new(buffer, y) { line = buffer.lines[y] line.slice! 0, indent_level indent_level = [(indent_level + diff), 0].max ecm = @end_char_mode buffer.move_to_x [(buffer.x + diff), 0].max @end_char_mode = ecm line[0, 0] = (" " * indent_level) } end end (" " * indent_level) end |
#clear_buffers_with_extension(extension) ⇒ Object
547 548 549 550 551 552 |
# File 'lib/shikaku.rb', line 547 def clear_buffers_with_extension extension @buffers.delete_if { |b| b.kind_of? extension } end |
#cmd_execute(buffer, cmd_line) ⇒ Object
330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 |
# File 'lib/front.rb', line 330 def cmd_execute buffer, cmd_line @cmd_overrides.each_pair { |re, block| if cmd_line =~ re ctx = CommandContext.new cmd_line, re, buffer block.call ctx return end } @cmds.each_pair { |re, block| if cmd_line =~ re ctx = CommandContext.new cmd_line, re, buffer block.call ctx return end } "Unknown command: #{cmd_line}" end |
#config_get_nu ⇒ Object
TODO these config routines are ugly… make them generic somehow!
82 83 84 |
# File 'lib/shikaku.rb', line 82 def config_get_nu @settings[:nu] == "true" end |
#config_get_split ⇒ Object
86 87 88 |
# File 'lib/shikaku.rb', line 86 def config_get_split @settings[:split] == "true" end |
#config_get_sw ⇒ Object
94 95 96 |
# File 'lib/shikaku.rb', line 94 def config_get_sw @settings[:sw].to_i end |
#config_get_tab_size ⇒ Object
98 99 100 |
# File 'lib/shikaku.rb', line 98 def config_get_tab_size @settings[:ts].to_i end |
#config_get_tw ⇒ Object
90 91 92 |
# File 'lib/shikaku.rb', line 90 def config_get_tw @settings[:tw].to_i end |
#create_selection(buffer, type, *options, &block) ⇒ Object
94 95 96 97 98 99 100 101 102 103 104 |
# File 'lib/front.rb', line 94 def create_selection buffer, type, *, &block selc = Selection.new selc.mode = type selc.s = Point.new(type == :selc_lined ? 0 : buffer.x, buffer.y) block.call selc.e = Point.new(type == :selc_lined ? buffer.lines[buffer.y].length : buffer.x, buffer.y) if .include? :restore buffer.move_to selc.s.x, selc.s.y end selc end |
#curs_x ⇒ Object
403 404 405 |
# File 'lib/shikaku.rb', line 403 def curs_x current_docview.cursor.x end |
#curs_y ⇒ Object
407 408 409 |
# File 'lib/shikaku.rb', line 407 def curs_y current_docview.cursor.y end |
#dbg_selc(buffer, selc) ⇒ Object
24 25 26 27 28 |
# File 'lib/debug.rb', line 24 def dbg_selc buffer, selc dbg(:selc) { selc} dbg(:selc) { show_line_with_marker buffer, selc.s } dbg(:selc) { show_line_with_marker buffer, selc.e } end |
#delete_binding(initial_options, key) ⇒ Object
28 29 30 31 |
# File 'lib/front.rb', line 28 def delete_binding , key hash, key = get_binding_hash_key_pair , key hash.delete key # returns also end |
#delete_command_binding(key) ⇒ Object
33 |
# File 'lib/front.rb', line 33 def delete_command_binding key; delete_binding @stored_command_bindings, key; end |
#delete_insert_binding(key) ⇒ Object
34 |
# File 'lib/front.rb', line 34 def delete_insert_binding key; delete_binding @stored_insert_bindings, key; end |
#display_cursor(buffer, docview) ⇒ Object
520 521 522 523 |
# File 'lib/shikaku.rb', line 520 def display_cursor buffer, docview @focus.canvas.setpos docview.cursor.y, docview.cursor.x # y, x @focus.canvas.refresh end |
#do_action(buffer, selc) ⇒ Object
106 107 108 109 110 111 112 113 114 115 116 117 118 |
# File 'lib/front.rb', line 106 def do_action buffer, selc case @command when "c", "d", "y" is_y = (@command == "y") is_c = (@command == "c") EditorApp.manip_selection buffer, selc, is_y ? :manip_copy : :manip_cut, pop_paste_buffer redraw buffer # - optimize!!! # EditorApp.invalidate_buffer_line buffer, buffer.y unless is_y @end_char_mode = true if selc.s.x == buffer.lines[buffer.y].length begin_insert_mode(buffer) if is_c @command = "" end end |
#do_cmd_mode(c, current_string, &block) ⇒ Object
373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 |
# File 'lib/front.rb', line 373 def do_cmd_mode c, current_string, &block possible_completions_string = "" had_completions = (@status_bar.text =~ /:.*\(.*\)/) case c when CR_KEY, ESC_KEY if c == CR_KEY block.call true else "Command mode cancelled." block.call false end return when 9 completions, to_cut, total_set, to_complete, = nil, nil, nil, nil, nil if (current_string =~ /\s([^ \t]*)$/) # attempt filename completion to_complete = $1 dir = File.dirname(to_complete) completions = Dir[to_complete + "*"] to_cut = to_complete.length parent_dir = (to_complete =~ %r{/$}) ? to_complete : (File.dirname(to_complete) + "/") total_set = Dir[parent_dir + "*"] = parent_dir.length else # do command completion completions = [] @commands.each_key { |key| completions << key if key.index(current_string) == 0 or current_string.empty? } to_cut = current_string.length total_set = @commands.keys to_complete = current_string = 0 end completions = completions.sort_by { |b| b.length } if completions.length > 0 prefix = find_prefix completions cmd_prefix = current_string[0, current_string.length - to_cut] if !prefix.empty? and (cmd_prefix + prefix) != current_string possible_completions_string = " (#{completions.sort.join ","})" current_string.replace cmd_prefix + prefix else new_string = completions.sort.first.dup if new_string == to_complete and had_completions idx = total_set.sort.index(new_string) || 0 # default to the first item to_complete = total_set.sort[(idx + 1) % total_set.length] current_string.replace cmd_prefix + to_complete else current_string.replace cmd_prefix + new_string to_complete = new_string end sorted_total_set = total_set.sort selected = to_complete current_idx = sorted_total_set.index selected if current_idx.nil? selected = completions.first current_idx = sorted_total_set.index selected end my_subset = nil unless current_idx.nil? top = limit_to_positive(sorted_total_set.length - 1) start_idx = (current_idx - 2).clamp_to(0, top) end_idx = (current_idx + 2).clamp_to(0, top) my_subset = sorted_total_set.slice(start_idx..end_idx) my_subset.unshift nil if (start_idx != 0) my_subset.push nil if (end_idx != top) else my_subset = sorted_total_set end = my_subset.map { |s| t = s.slice(..-1) rescue "" (s == nil) ? "..." : ( (s == selected) ? "[#{t}]" : t ) }.join(",") possible_completions_string = " (#{})" end if !had_completions and completions.length == 1 possible_completions_string = "" end end when *BACKSPACE_KEYS if current_string.length > 0 current_string.slice!(-1) else "Command mode cancelled." block.call false return end else if c > ASCII_UPPER "unhandled non ascii entry in do_cmd_mode: #{c}" else current_string << c.chr end end ":#{current_string}#{possible_completions_string}", current_string.length + 1 end |
#do_command(buffer, c) ⇒ Object
138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 |
# File 'lib/front.rb', line 138 def do_command buffer, c number_char = nil char_string = (c > 256) ? @curses_key_translators[c] : c.chr @current_command_binding_state = @stored_command_bindings if @current_command_binding_state.nil? if (c > 256) or !@current_command_binding_state[c].nil? if @command_context.nil? @command_context = Struct.new(:input).new @command_context.input = "" end char_string.each_byte { |c| = @current_command_binding_state[c] if .is_a? Hash @current_command_binding_state = @command_context.input << c.chr else @command_context.input << c.chr case .arity when 2 .call c, @command_context else .call c end @current_command_binding_state = nil @command_context = nil end } else @command_context = nil @current_command_binding_state = nil case c when ?0..?9 number_char = c else raise "[unknown key `#{Curses.keyname(c)}'=#{c}]" if $test_case "[unknown key `#{Curses.keyname(c)}'=#{c}] " end # what a freaking haccckk :( if number_char.nil? unless @number.nil? or !@command.nil? @number = nil "number ended..." end else if @number.nil? and number_char == ?0 buffer.move_to_x 0 else @number = "" if @number.nil? @number << number_char.chr end end end if !@selection.nil? and (@selection.mode == :selc_normal || @selection.mode == :selc_boxed) @selection.e = Point.new(buffer.x, buffer.y) elsif !@selection.nil? and @selection.mode == :selc_lined @selection.e = Point.new(buffer.lines[buffer.y].length, buffer.y) end @da_command << c.chr unless @mode_stack.last == :command or !@changed or c > 255 if @command.empty? and @mode_stack.last == :normal and !@da_command.empty? and @changed @changed = false @last_command = @da_command @da_command = "" end buffer.dlog.flush update_selection buffer @status_bar.invalidate end |
#do_letter(buffer, c) ⇒ Object
211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 |
# File 'lib/front.rb', line 211 def do_letter buffer, c @current_insert_binding_state = @stored_insert_bindings if @current_insert_binding_state.nil? c = 8 if BACKSPACE_KEYS.include? c char_string = (c > 256) ? @curses_key_translators[c] : c.chr if (c > 256) or !@current_insert_binding_state[c].nil? char_string.each_byte { |c| = @current_insert_binding_state[c] if .is_a? Hash @current_insert_binding_state = else .call c @current_insert_binding_state = nil end } else @current_insert_binding_state = nil if c > ASCII_UPPER "unhandled non ascii entry in do_letter: #{c}" else if !@settings[:tw].nil? and buffer.x > config_get_tw current_line = buffer.lines[buffer.y] x_was = buffer.x ecm = @end_char_mode next_word(buffer, :skip_space, :letter_after, :reverse, :greedy) if buffer.x > 0 if buffer.x == 0 buffer.x = x_was else indent_string = calculate_autoindent buffer, current_line, buffer.y, true line = nil DiffLogger::ModifyLineChange.new(buffer, buffer.y) { line = BufferLine.new(indent_string + current_line.slice!(buffer.x..-1)).dup current_line.gsub!(/\s*$/, '') } DiffLogger::InsertLineAfterChange.new(buffer, buffer.y+1) { buffer.lines.insert_after buffer.y+1, line } buffer.y += 1 buffer.move_to_x line.length @end_char_mode = ecm end end line = buffer.lines[buffer.y] ch = (c == 9) ? (" " * config_get_sw) : c.chr if !@end_char_mode and buffer.out_of_bounds buffer.y, buffer.x raise "Out of bounds while inserting character in do_letter!" if $test_case "Can't insert character, cursor at invalid position on line!!!" return end DiffLogger::ModifyLineChange.new(buffer, buffer.y) { if @end_char_mode # how to prevent replace_mode in this code path? line << ch buffer.move_to_x limit_to_positive(line.length - 1) @end_char_mode = true else line[buffer.x, @replace_mode ? 1 : 0] = ch buffer.move_to_x(buffer.x + ch.length) end } if @settings[:autopair] == "true" catch(:done) { end_pair = nil case c when ?\ end_pair = " " if @last_inserted_char == ?{ when ?{ end_pair = "}" end if !end_pair.nil? DiffLogger::ModifyLineChange.new(buffer, buffer.y) { if @end_char_mode line << end_pair buffer.x += 1 @end_char_mode = false else line[buffer.x, 0] = end_pair end } end } end EditorApp.invalidate_buffer_line buffer, buffer.y end if @replace_single_letter buffer.dlog.flush begin_normal_mode buffer @replace_mode = false @replace_single_letter = false buffer.x -= 1 end end @last_inserted_char = c @da_command << c.chr unless @mode_stack.last == :normal or c > 255 buffer.dlog.flush @status_bar.invalidate end |
#do_movement_key(buffer, c, *options) ⇒ Object
51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 |
# File 'lib/front.rb', line 51 def do_movement_key buffer, c, * c = normalize_cursor_key c insert_mode = .include? :insert_mode raise "ummm a @command number when in insert_mode are u insane???" if insert_mode and !@command.empty? if insert_mode and [?h, ?l].include? c eol_x = buffer.last_char_on_line(buffer.y) if buffer.x == eol_x and ( (@end_char_mode and c == ?h) or (!@end_char_mode and c == ?l) ) @end_char_mode = !@end_char_mode return elsif buffer.x == 0 and c == ?h move_x buffer, -1 @end_char_mode = !@end_char_mode return end end (@number || "1").to_i.times { case c when ?k move_y buffer, -1 when ?j move_y buffer, +1 when ?h move_x buffer, -1 when ?l move_x buffer, +1 end @number = nil } end |
#do_search(buffer, c, word = nil) ⇒ Object
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 |
# File 'lib/search.rb', line 5 def do_search buffer, c, word = nil forced_next = (c == Curses::KEY_CTRL_N || c == Curses::KEY_CTRL_P) @search.reverse = (c == Curses::KEY_CTRL_P) if forced_next if !@search.already_performed @case_sensitive = false @search.history_pos = @search_history.length if !word.nil? @search_history << word.dup elsif forced_next @search.history_pos -= 1 else @search_history << "" end @search.string = @search_history.last # rename end case c when Curses::KEY_CTRL_I @case_sensitive = !@case_sensitive when Curses::KEY_UP @search.history_pos -= 1 if @search.history_pos > 0 @search.string = @search_history[@search.history_pos].dup when Curses::KEY_DOWN @search.history_pos += 1 if @search.history_pos < (@search_history.length - 1) @search.string = @search_history[@search.history_pos].dup when ESC_KEY, CR_KEY if c == CR_KEY and !@hl_selection.nil? buffer.move_to @hl_selection.s.x, @hl_selection.s.y end @hl_selection = nil @search.history_pos = @search_history.length - 1 @search.already_performed = false if @search.got_no_key @search.history_pos = @search_history.length - 2 @search.string = @search_history[@search.history_pos] @search_history.pop perform_search buffer, true buffer.move_to @hl_selection.s.x, @hl_selection.s.y end @mode_stack.pop @search = nil return when *BACKSPACE_KEYS @search.string.slice!(-1) when Curses::KEY_CTRL_N, Curses::KEY_CTRL_P ; else if c > ASCII_UPPER "unhandled non ascii entry in do_search: #{c}" else @search.string << c.chr @search.got_no_key = false end end perform_search buffer, forced_next end |
#each_real_buffer ⇒ Object
280 281 282 283 284 285 286 |
# File 'lib/shikaku.rb', line 280 def each_real_buffer @buffers.each { |buffer| next if buffer.fake_buffer yield buffer } end |
#end_selection(buffer) ⇒ Object
199 200 201 202 203 204 |
# File 'lib/selections.rb', line 199 def end_selection buffer # test - Vjjy from above should cover this @selection_for_last_command = @selection @selection = nil redraw buffer end |
#ensure_buffer_highlighted(buffer, pass = false) ⇒ Object
732 733 734 735 736 737 738 739 740 741 742 743 744 |
# File 'lib/shikaku.rb', line 732 def ensure_buffer_highlighted buffer, pass = false while true @mutex.synchronize { line_num = buffer.first_non_highlighted_line if line_num.nil? or line_num > buffer.lines.length @status_bar.highlight_progress = nil return end buffer.ensure_line_highlight line_num } Thread.pass if pass end end |
#exec_into_buffer_lines(cmd) ⇒ Object
680 681 682 683 684 685 686 687 688 689 |
# File 'lib/shikaku.rb', line 680 def exec_into_buffer_lines cmd buffer_lines = [] IO.popen(cmd) { |io| while not io.eof? buffer_lines << BufferLine.new(io.gets) end } buffer_lines end |
#final_widget_position(widget) ⇒ Object
63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 |
# File 'lib/widgets.rb', line 63 def last_parent = current_box = .parent offset_x, offset_y = 0, 0 while !current_box.nil? idx = @widgets.index last_parent raise "blub?" if !current_box.is_a? VBox and !current_box.is_a? HBox children = @widgets.slice(0...idx).find_all { |w| w.parent == current_box } if current_box.is_a? HBox size = children.inject(0) { |sum, w| sum += (w)[0] } offset_x += size else size = children.inject(0) { |sum, w| sum += (w)[1] } offset_y += size end last_parent = current_box current_box = current_box.parent end [offset_x, offset_y] end |
#final_widget_size(widget) ⇒ Object
28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 |
# File 'lib/widgets.rb', line 28 def # !FIXME! - this is crap and hardcoded - !FIXME! docviews = @widgets.find_all { |w| w.is_a? DocView } number_of_horiz_splits = docviews.length = @widgets.find_all { |w| w.is_a? StatusBar } = .inject(0) { |sum, item| sum += item.height } rulers = @widgets.find_all { |w| w.is_a? Ruler } first_size_ruler = rulers.empty? ? 0 : rulers.first.width sx, sy = WinDescs::instance.stdscr.maxx, WinDescs::instance.stdscr.maxy case when @doc_with_ruler, @doc_with_ruler2 children = @widgets.find_all { |w| w.parent == } dx, dy = nil, nil if .is_a? HBox dx = children.inject(0) { |sum, w| sum += (w)[0] } # we assume that all the widths will be the same... maybe we should assert? dy = (children.first)[1] else # we assume that all the heights will be the same... maybe we should assert? dx = (children.first)[0] dy = children.inject(0) { |sum, w| sum += (w)[1] } end return [dx, dy] when Ruler return [first_size_ruler, (sy - ) / number_of_horiz_splits] when DocView return [sx - first_size_ruler, (sy - ) / number_of_horiz_splits] when StatusBar # we no parent and we are width.is_nil therefore we use the entire width # we have .height.is_not_nil so we take this height return [sx, .height] end raise "oops" end |
#find_match_in_line(re, line, myx, go_backwards, forced_next) ⇒ Object
61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 |
# File 'lib/search.rb', line 61 def find_match_in_line re, line, myx, go_backwards, forced_next line_to_compare = line.dup start_pos, end_pos = nil, nil if !go_backwards skiplen = myx skiplen += 1 if forced_next line_to_compare.slice! 0, skiplen matches = (line_to_compare =~ re) matches = false if $1.nil? or $2.nil? start_pos, end_pos = ($1.length) + skiplen, ($1.length + $2.length - 1) + skiplen if matches else # chop off end - the bit after myx skiplen = myx line_to_compare.slice! skiplen...line_to_compare.length x = 0 # scan all matches until the last match of the leftover string line_to_compare.scan(re) { matches = true start_pos = x + $1.length end_pos = start_pos + $2.length - 1 x += ($1.length + $2.length) } end return matches, start_pos, end_pos end |
#find_prefix(completions) ⇒ Object
356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 |
# File 'lib/front.rb', line 356 def find_prefix completions prefix = completions.first.dup completions.slice(1..-1).each { |str| idx = 0 prefix.each_byte { |byte| if str.length < idx or str[idx] != byte prefix = str.slice(0,idx) break end idx += 1 } } prefix end |
#finish ⇒ Object
276 277 278 |
# File 'lib/shikaku.rb', line 276 def finish Curses.int_finish # ext end |
#flush_finish_redraw(buffer) ⇒ Object
418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 |
# File 'lib/shikaku.rb', line 418 def flush_finish_redraw buffer buffer = nil # we *totally* ignore buffer now!, so lets remove it from the method prototype soon! position_cursor current_docview.buffer, current_docview watched_buffers = [] @widgets.each { |w| next unless w.is_a? DocView watched_buffers << w.watch_buffer unless watched_buffers.include? w.watch_buffer } nts = nil redraw_was_needed = false unwatching_buffers = @widgets.dup watched_buffers.each { |buffer| watching_buffer = @widgets.find_all { |w| w.watch_buffer == buffer } watching_buffer.each { || unwatching_buffers.delete } if buffer.needs_redraw or @needs_full_redraw redraw_was_needed = true redraw buffer elsif buffer.redraw_list = buffer.redraw_list.sort.uniq if buffer.got_a_scroll_already watching_buffer.each { || .canvas.scrl buffer.need_to_scroll } nts = buffer.need_to_scroll buffer.need_to_scroll = 0 end end buffer.needs_redraw = false buffer.got_a_scroll_already = false } @needs_full_redraw = false unwatching_buffers.each { || next if .kind_of? Box (0....height).each { |y| .render y } } watched_buffers.each { |buffer| buffer.redraw_list.delete_if { |y| (y < buffer.top) or (y > buffer.top + screen_height) } last_dirty_list = buffer.dirty_list || [] new_y = buffer.y buffer.dirty_list = [new_y, new_y - (nts || 0)] buffer.redraw_list += last_dirty_list buffer.redraw_list += buffer.dirty_list buffer.redraw_list = buffer.redraw_list.sort.uniq watching_buffer = @widgets.find_all { |w| w.watch_buffer == buffer } buffer.redraw_list.each { |y| watching_buffer.each { || dbg(:dbg_highlight) { "rendering #{y} for widget type #{.type}" } .render y - buffer.top } } buffer.redraw_list = [] } if !nts.nil? or redraw_was_needed # we clear the bottom line of the buffer # as the text scrolling appears to draw # outside its draw area descs = [WinDescs::instance.descs[@docview]] descs << WinDescs::instance.descs[@docview2] if @widgets.include? @docview2 descs.each { |desc| scr = WinDescs::instance.stdscr scr.set_attr false, Curses::COLOR_WHITE, Curses::COLOR_BLACK scr.setpos(desc.y + desc.sy - 1, 0) # y, x scr.addstr " " * (scr.maxx - 1) scr.refresh } end display_cursor current_docview.buffer, current_docview end |
#get_binding_hash_key_pair(initial_options, keys) ⇒ Object
5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
# File 'lib/front.rb', line 5 def get_binding_hash_key_pair , keys if keys.is_a? String last_char = keys.slice!(-1) = keys.each_byte { |b| [b] ||= {} = [b] } return , last_char else return , keys end end |
#get_cmd_line ⇒ Object
351 352 353 354 |
# File 'lib/front.rb', line 351 def get_cmd_line # used by testcases.rb @cmd_line end |
#get_indent_level(line) ⇒ Object
542 543 544 545 |
# File 'lib/shikaku.rb', line 542 def get_indent_level line line =~ /^(\s*)/ return $1 ? $1.length : 0 end |
#get_user_input(question = "") ⇒ Object
121 122 123 124 125 126 127 128 129 130 131 132 133 134 |
# File 'lib/curses-ui.rb', line 121 def get_user_input question = "" current_string = "" "#{question}:" flush_finish_redraw current_buffer while true c = Curses.getch do_cmd_mode(c, current_string) { |ok| return ok ? current_string : nil } flush_finish_redraw current_buffer end fail "impossible" end |
#get_word_under_cursor(buffer, *options) ⇒ Object
554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 |
# File 'lib/shikaku.rb', line 554 def get_word_under_cursor buffer, * ruby_vars = (.include? :look_for_ruby_variables) x_was = buffer.x next_word(buffer, :letter_after, :reverse) # begin x_pos_test_1 = buffer.x next_word(buffer, :letter_after) # test to see if we were start of string if buffer.x == x_was # we were already at the start, so we went too far # pass as we are back where we should be now anyway else # we are now at the start of a word buffer.x = x_pos_test_1 end # end x_pos1 = buffer.x next_word(buffer, :letter_after) x_pos2 = buffer.x buffer.x = x_was if ruby_vars prev_char = (buffer.lines[buffer.y][x_pos1-1] rescue 0) x_pos1 -= 1 if [?$, ?@].include? prev_char if prev_char == ?@ \ and (buffer.lines[buffer.y][x_pos1-1] rescue 0) \ == ?@ x_pos1 -= 1 end end return x_pos1...x_pos2 end |
#handle_generic_command(buffer, c) ⇒ Object
120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 |
# File 'lib/front.rb', line 120 def handle_generic_command buffer, c got_selection = !@selection.nil? if got_selection @command = c.chr do_action buffer, @selection @command = "" end_selection buffer else @command << c.chr if @command == (c.chr * 2) selc = Selection.new Point.new(0, buffer.y), Point.new(buffer.lines[buffer.y].length, buffer.y), :selc_lined @command = c.chr do_action buffer, selc @command = "" end end end |
#input_loop ⇒ Object
136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 |
# File 'lib/curses-ui.rb', line 136 def input_loop pagedown_count = 0 last_draw = Time.now flush_finish_redraw current_buffer last_count_end = Time.now last_count = 0 count = 0 timeout = nil # main loop while true read_fds = IO.select([$stdin], nil, nil, timeout) # got input? if so. lets read unless read_fds.nil? c = Curses.getch if SUSPEND_KEYS.include? c Curses.close_screen Process.kill "SIGTSTP", $$ Curses.init_screen redraw current_buffer flush_finish_redraw current_buffer next end if Time.now > last_count_end + KEYPRESS_COUNT_INTERVAL last_count = count last_count_end = Time.now count = 0 else count += 1 end send_key(c) end if last_count > LAST_INTERVAL_KEYPRESS_COUNT if (Time.now - last_draw) > FORCE_REDRAW_TIMEOUT flush_finish_redraw current_buffer last_draw = Time.now end timeout = SELECT_POLL_INTERVAL else flush_finish_redraw current_buffer last_draw = Time.now timeout = nil end end end |
#invalidate_screen_line(buffer, y) ⇒ Object
395 396 397 |
# File 'lib/shikaku.rb', line 395 def invalidate_screen_line buffer, y buffer.redraw_list << y + buffer.top end |
#itr_backwards(buffer, tok, y) ⇒ Object
597 598 599 600 601 602 603 604 605 606 607 |
# File 'lib/shikaku.rb', line 597 def itr_backwards buffer, tok, y buffer.ensure_line_highlight y idx = buffer.tokens[y].index tok buffer.tokens[y].slice(0...idx).reverse_each { |tok| yield y, tok } return if y == 0 (y-1).downto(0) { |ny| buffer.ensure_line_highlight ny buffer.tokens[ny].reverse_each { |tok| yield ny, tok } } end |
#itr_forewards(buffer, tok, y) ⇒ Object
585 586 587 588 589 590 591 592 593 594 595 |
# File 'lib/shikaku.rb', line 585 def itr_forewards buffer, tok, y buffer.ensure_line_highlight y idx = buffer.tokens[y].index tok buffer.tokens[y].slice(idx..-1).each { |tok| yield y, tok } return if buffer.lines.length == y (y+1).upto(buffer.last_line_num) { |ny| buffer.ensure_line_highlight ny buffer.tokens[ny].each { |tok| yield ny, tok } } end |
#line_displayed?(buffer, y) ⇒ Boolean
538 539 540 |
# File 'lib/shikaku.rb', line 538 def line_displayed? buffer, y (((buffer.top)..(buffer.top + screen_height - 1)) === y) end |
#load_script_file(scriptfname) ⇒ Object
746 747 748 749 750 751 752 |
# File 'lib/shikaku.rb', line 746 def load_script_file scriptfname File.open(scriptfname) { |file| content = file.gets nil eval content } end |
#make_selection_exclusive_given_current_position(buffer, selc) ⇒ Object
SELECTION RELATED STUFF #
43 44 45 46 47 48 49 50 |
# File 'lib/selections.rb', line 43 def make_selection_exclusive_given_current_position buffer, selc pos = Point.new(buffer.x, buffer.y) if selc.e == pos selc.e.x = limit_to_positive(selc.e.x - 1) elsif selc.s == pos selc.s.x = (selc.s.x + 1).clamp_to 0, buffer.last_char_on_line(selc.s.y) end end |
#move_x(buffer, x_diff, allow_y_change = true) ⇒ Object
WRAPPING MOVEMENT #
94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 |
# File 'lib/movement.rb', line 94 def move_x buffer, x_diff, allow_y_change = true return if buffer.lines.empty? # need to limit max buffer.y change to 1 return if x_diff == 0 if x_diff > 0 left_on_this_line = buffer.lines[buffer.y].length - buffer.x # we don't want to wrap, so capability states that we decrease the possible by one wanted_and_capable_on_this_line = (left_on_this_line - 1).clamp_to(0, x_diff) if left_on_this_line == 1 # the wrap == 1 return unless allow_y_change x_diff -= 1 move_y buffer, 1 buffer.x = 0 move_x buffer, x_diff else x_diff -= wanted_and_capable_on_this_line buffer.x += wanted_and_capable_on_this_line # we always move to end, and then wrap if needed end else left_on_this_line = buffer.x # in this case left_on_this_line == 0 when we can wrap so no need to adjust wanted_and_capable_on_this_line = [x_diff.abs, left_on_this_line].min if left_on_this_line == 0 # the wrap is at position 0 return unless allow_y_change x_diff += 1 # its a negative move_y buffer, -1 buffer.x = buffer.last_char_on_line(buffer.y) move_x buffer, x_diff else x_diff += wanted_and_capable_on_this_line # its negative buffer.x -= wanted_and_capable_on_this_line # we always move to the start, and then wrap if needed end end end |
#move_y(buffer, y_diff) ⇒ Object
143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 |
# File 'lib/movement.rb', line 143 def move_y buffer, y_diff return if buffer.lines.empty? new_doc_y = buffer.y + y_diff if new_doc_y < 0 scroll_to_bottom buffer elsif new_doc_y > buffer.lines.length - 1 scroll_to_top buffer elsif new_doc_y < buffer.top diff = buffer.y - new_doc_y diff.times { scroll_up(buffer) } elsif new_doc_y > (buffer.top + screen_height - 1) diff = new_doc_y - buffer.y diff.times { scroll_down(buffer) } else buffer.y = new_doc_y end if @end_char_mode # in insert mode in vim, last char is indicated visually... buffer.x = buffer.last_char_on_line(buffer.y) # buffer.x accessor resets the end_char_mod, so lets restore :) @end_char_mode = true else buffer.x = buffer.x.clamp_to 0, buffer.last_char_on_line(buffer.y) end end |
#new_status_bar(buf) ⇒ Object
315 316 317 318 319 320 321 |
# File 'lib/shikaku.rb', line 315 def buf = StatusBar.new self, buf .parent = @root @widgets << EditorApp.perform_layout end |
#next_word(buffer, *options) ⇒ Object
CLEVER WORD SKIP STUFF #
41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 |
# File 'lib/movement.rb', line 41 def next_word buffer, * letter_after = .include? :letter_after rev = .include? :reverse space_flag = .include? :skip_space greedy = .include? :greedy sub_identifier = .include? :sub_identifier line = buffer.lines[buffer.y].dup pos = rev ? (line.length-buffer.x+1) : buffer.x space = space_flag ? '\s*' : '' jump_over_re = nil if !rev jump_over_re = (greedy ? '[^\s]*\s*' \ : '( (\s+)' \ + (sub_identifier ? '| ([A-Z][a-z]+)' \ '| ([a-zA-Z]+_?)' \ '| ([A-Z]+)' \ '| ([\d]+)' \ : '| (\w+)' ) + '| ([^\s\w])' \ '| (.)' \ ')' \ + space ) # test - b else jump_over_re = (greedy ? '\s*[^\s]*' \ : space \ + '( (\s+)' \ + (sub_identifier ? '| ([a-z]+[A-Z])' \ '| (_?[a-zA-Z]+)' \ '| ([A-Z]+)' \ '| ([\d]+)' \ : '| (\w+)' ) + '| ([^\s\w])' \ '| (.)' \ ')' ) end sub = rev ? line[0..(buffer.x-1)].reverse : line[buffer.x..(line.length-1)] sub =~ /^(#{jump_over_re})/x return if $1.nil? len = $1.length len += (!rev ? -1 : 1) unless letter_after or rev x_diff = rev ? (-len) : len move_x buffer, x_diff, (buffer.x == (line.length - 1) || buffer.x == 0) ? true : false end |
#normalize_cursor_key(c) ⇒ Object
37 38 39 40 41 42 43 44 45 46 47 48 49 |
# File 'lib/front.rb', line 37 def normalize_cursor_key c case c when Curses::KEY_RIGHT return ?l when Curses::KEY_UP return ?k when Curses::KEY_DOWN return ?j when Curses::KEY_LEFT return ?h end return c end |
#notify_of_change(the_change, direction) ⇒ Object
629 630 631 |
# File 'lib/shikaku.rb', line 629 def notify_of_change the_change, direction @changed = true end |
#perform_search(buffer, forced_next) ⇒ Object
92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 |
# File 'lib/search.rb', line 92 def perform_search buffer, forced_next @search.already_performed = true re = nil begin re = @case_sensitive ? /(.*?)(#{@search.string})/ : /(.*?)(#{@search.string})/i rescue RegexpError ":( - #{@search.string}" return end cur_x, cur_y = buffer.x, buffer.y last_match_y = buffer.y moved, matches, search_wrapped = false, false, false dbg(:search) { "started! with search == #{@search.string}" } while true matches, start_pos, end_pos = find_match_in_line re, buffer.lines[cur_y], cur_x, @search.reverse, (forced_next and cur_y == buffer.y) last_match_y = cur_y if matches dbg(:search) { "B: #{start_pos.inspect} - #{end_pos.inspect}" } if matches && !moved && ( (!@search.reverse && start_pos > cur_x) \ || (@search.reverse && cur_x > start_pos) ) moved = true cur_x = start_pos end if search_wrapped and moved and !matches && (cur_y == last_match_y) "sorry, unable to find #{@search.string}" break end forced_next_but_unmoved = forced_next && !moved if matches and !forced_next_but_unmoved ":) - #{@search.string}" break end cur_y += (@search.reverse ? -1 : +1) cur_x = @search.reverse ? buffer.lines[cur_y].length : 0 if cur_y > (buffer.lines.length-1) or cur_y < 0 "wrapped!" search_wrapped = true end cur_y = cur_y % buffer.lines.length moved = true end @hl_selection = matches ? Selection.new(Point.new(start_pos, cur_y), Point.new(end_pos, cur_y), :selc_normal) \ : nil redraw buffer end |
#pop_paste_buffer ⇒ Object
617 618 619 620 621 622 623 624 625 626 627 |
# File 'lib/shikaku.rb', line 617 def pop_paste_buffer choice = @current_paste_buffer @current_paste_buffer = nil buf = choice.nil? ? @main_paste_buffer : @paste_buffers[choice] if buf.nil? buf = EditorApp.new_buffer self, :no_blank_line, :fake_buffer buf.is_paste_buffer = true @paste_buffers[choice] = buf end buf end |
#position_cursor(buffer, docview) ⇒ Object
511 512 513 514 515 516 517 518 |
# File 'lib/shikaku.rb', line 511 def position_cursor buffer, docview current_line = buffer.lines[buffer.y] string_upto_now = current_line.slice(0...buffer.x) x = string_upto_now.unpack("c*").inject(0) { |width, char| width += (char == ?\t ? config_get_tab_size : 1) } ecm_diff = (@end_char_mode and @mode_stack.last == :insert and !current_line.empty?) ? 1 : 0 docview.absolute_cursor.x, docview.absolute_cursor.y = buffer.x + ecm_diff, buffer.y - buffer.top docview.cursor.x, docview.cursor.y = x + ecm_diff, buffer.y - buffer.top end |
#real_buffers ⇒ Object
288 289 290 291 292 293 294 |
# File 'lib/shikaku.rb', line 288 def real_buffers buffs = [] each_real_buffer { |b| buffs << b } buffs end |
#redraw(buffer) ⇒ Object
532 533 534 535 536 |
# File 'lib/shikaku.rb', line 532 def redraw buffer @widgets.each { |sb| sb.invalidate if sb.is_a? StatusBar } buffer.redraw_list = [] # no point invalidating everything twice so lets clear the list! redraw_from_and_including buffer, 0 end |
#redraw_from_and_including(buffer, y) ⇒ Object
525 526 527 528 529 530 |
# File 'lib/shikaku.rb', line 525 def redraw_from_and_including buffer, y buffer.invalidate_line_highlight y (y...screen_height).each { |y| invalidate_screen_line buffer, y } end |
#refresh_widgets ⇒ Object
503 504 505 506 507 508 509 |
# File 'lib/shikaku.rb', line 503 def @widgets.each { || next if .kind_of? Box .canvas.refresh } end |
#remove_unneeded_statusbars ⇒ Object
306 307 308 309 310 311 312 313 |
# File 'lib/shikaku.rb', line 306 def count_was = @widgets.length @widgets.delete_if { |sb| (sb.is_a? StatusBar) and !(@buffers.include? sb.buffer) } EditorApp.perform_layout if count_was != @widgets.length end |
#reset_state ⇒ Object
TODO this is hecka big, can’t we seperate out more stuff?
127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 |
# File 'lib/shikaku.rb', line 127 def reset_state @@app = self @needs_full_redraw = false BufferIdAllocator::instance.max_buffer_idx = 1 BufferListing::instance.clear @mutex = Mutex.new @current_paste_buffer = nil @doing_macro = nil @macros = [] @change_listeners = [] @change_listeners << self.method(:notify_of_change) @changed = false @mode_stack = [:normal] Curses.int_init @curses_key_translators = {} @current_command_binding_state = nil @current_insert_binding_state = nil @stored_command_bindings = {} @stored_insert_bindings = {} setup_bindings @search_history = [] @buffers = [] @current_buffer = nil @number = nil @end_char_mode = false @replace_mode = false @replace_single_letter = false @search = nil @da_command = "" @status_bar = nil @selection = nil @hl_selection = nil @command, @cmd_line = "", "" @paste_buffers = {} @main_paste_buffer = EditorApp.new_buffer self, :no_blank_line, :fake_buffer @main_paste_buffer.is_paste_buffer = true @history_buffer = EditorApp.new_buffer self, :no_blank_line, :fake_buffer @debug_buffer = EditorApp.new_buffer self, :no_blank_line, :fake_buffer Debug::instance.register_debug_buffer @debug_buffer dbg(nil) { "--- beginning debug output #{Time.now.to_s} ---" } unless $test_case # root @root = VBox.new self, nil # window 1 @doc_with_ruler = HBox.new self, @root @docview = DocView.new self, nil @docview.parent = @doc_with_ruler @ruler = Ruler.new self, nil @ruler.parent = @doc_with_ruler # window 2 @doc_with_ruler2 = HBox.new self, @root @docview2 = DocView.new self, nil @docview2.parent = @doc_with_ruler2 @ruler2 = Ruler.new self, nil @ruler2.parent = @doc_with_ruler2 @docview_to_ruler = { @docview => @ruler, @docview2 => @ruler2, } @current_docview = @docview @focus = @docview @widgets = [@root, @doc_with_ruler, @docview] # DEFAULTS @settings = Settings.new # maybe arguments should be registered with types?????, or use a callback system to verify typing??? @settings[:sw] = "4" @settings[:ts] = "8" @settings[:tw] = nil @settings[:nu] = "false" @settings[:split] = "false" @settings[:autopair] = "false" @settings.procs[:nu] = proc { update_split_state update_ruler_state } update_split_state update_ruler_state @settings.procs[:split] = proc { update_split_state update_ruler_state } setup_default_command_set end |
#save_buffer_as_file(buffer, fname = nil) ⇒ Object
386 387 388 389 390 391 392 393 |
# File 'lib/shikaku.rb', line 386 def save_buffer_as_file buffer, fname = nil fname = buffer.fname if fname.nil? raise "save_buffer_as_file called for buffer without a valid fname" if fname.nil? File.open(fname, "w") { |fp| buffer.dlog.saved buffer.lines.each { |line| fp.puts line } } end |
#screen_height ⇒ Object
726 727 728 729 730 |
# File 'lib/shikaku.rb', line 726 def screen_height # when using the actual screen height the last char drawn on the last line # appears to scroll the screen up one thus completely messing up the rendering WinDescs::instance.descs[@docview].sy - 1 end |
#scroll_down(buffer) ⇒ Object
test - scroll up and down in large buffer, needs visual test really
24 25 26 27 28 29 30 31 32 33 34 35 |
# File 'lib/movement.rb', line 24 def scroll_down buffer b = (buffer.top + screen_height <= buffer.lines.length) if b buffer.need_to_scroll = 1 unless buffer.needs_redraw invalidate_screen_line buffer, screen_height - 1 unless buffer.needs_redraw buffer.y += 1 buffer.top += 1 buffer.needs_redraw = true if buffer.got_a_scroll_already buffer.got_a_scroll_already = true end return b end |
#scroll_to_bottom(buffer) ⇒ Object
131 132 133 134 135 |
# File 'lib/movement.rb', line 131 def scroll_to_bottom buffer while scroll_down(buffer); end buffer.y = buffer.last_line_num redraw buffer end |
#scroll_to_top(buffer) ⇒ Object
137 138 139 140 141 |
# File 'lib/movement.rb', line 137 def scroll_to_top buffer while scroll_up(buffer); end buffer.y = 0 redraw buffer end |
#scroll_up(buffer) ⇒ Object
test - scroll up and down in large buffer, needs visual test really
10 11 12 13 14 15 16 17 18 19 20 21 |
# File 'lib/movement.rb', line 10 def scroll_up buffer b = (buffer.top > 0) if b buffer.need_to_scroll = -1 unless buffer.needs_redraw invalidate_screen_line buffer, 0 unless buffer.needs_redraw buffer.y -= 1 buffer.top -= 1 buffer.needs_redraw = true if buffer.got_a_scroll_already buffer.got_a_scroll_already = true end return b end |
#send_key(c) ⇒ Object
472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 |
# File 'lib/front.rb', line 472 def send_key c dbg(nil) { "key press: #{(c == 27) ? "<esc>" : (c > 256 ? Curses.keyname(c) : c.chr)}" } $action_replay_log.keys_pressed << c unless $replaying update_focus @doing_macro << c.chr unless @doing_macro.nil? case @mode_stack.last when :search do_search @current_buffer, c when :normal do_command @current_buffer, c when :get_letter @mode_stack.pop @get_letter_pop_proc.call c when :command do_cmd_mode(c, @cmd_line) { |ok| cmd_execute @current_buffer, @cmd_line if ok @mode_stack = [:normal] @cmd_line = "" } when :insert do_letter @current_buffer, c end update_focus end |
#setup_bindings ⇒ Object
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 |
# File 'lib/bindings.rb', line 5 def setup_bindings look_for_letter_block = proc { |c| buffer = self.current_buffer @mode_stack.push :get_letter @get_letter_pop_proc = proc { |to_find| has_action = !@command.empty? = [] << :restore if has_action selc = create_selection(buffer, :selc_normal, *) { upcase = (c.chr == c.chr.upcase) letter_before = (c.chr.downcase == "t") diff = letter_before ? 1 : 0 line = buffer.lines[buffer.y] if upcase # backwards search... if buffer.x != 0 index = line.rindex(to_find, buffer.x-1) buffer.move_to_x(index + diff) unless index.nil? end else # forwards search if buffer.x != line.length - 1 index = line.index(to_find, buffer.x+1) buffer.move_to_x(index - diff) unless index.nil? end end } do_action buffer, selc } } goto_first_real_letter_on_line_block = proc { |c| buffer = self.current_buffer buffer.move_to_x get_indent_level(buffer.lines[buffer.y]) } skip_block_block = proc { |c| buffer = self.current_buffer backwards = (c == ?{) oy = buffer.y while true move_y buffer, backwards ? -1 : +1 break if buffer.lines[buffer.y] =~ /^\s*$/ \ or (buffer.y != oy \ and ([buffer.last_line_num, 0].include? buffer.y)) end if buffer.y == buffer.last_line_num and !backwards buffer.move_to_x buffer.last_char_on_line(buffer.last_line_num) else # used in the { at start of file case, and the default case buffer.move_to_x 0 end } =begin :: attribution - vim help - motion.txt Special case: "cw" and "cW" are treated like "ce" and "cE" if the cursor is on a non-blank. This is because "cw" is interpreted as change-word, and a word does not include the following white space. {Vi: "cw" when on a blank followed by other blanks changes only the first blank; this is probably a bug, because "dw" deletes all the blanks} =end word_movement_block = proc { |c, context| = [ ] case context.input when "zh" << :sub_identifier c = ?b when "zl" << :sub_identifier c = ?w end buffer = self.current_buffer cmd = c.chr.downcase if_e = (cmd == "e") if_b = (cmd == "b") is_upcase = (c.chr.upcase == c.chr) has_action = !@command.empty? on_blank = (buffer.lines[buffer.y][buffer.x] =~ /\s/) letterafter = (cmd == "w") letterafter = false if (cmd == "w" and @command == "c" and !on_blank) << :letter_after if letterafter << :skip_space if letterafter or (if_b and !has_action) << :reverse if if_b << :greedy if is_upcase ox, oy = buffer.x, buffer.y selc = create_selection(buffer, :selc_normal) { next_word(buffer, *) } if has_action selc = selc.right_way_up make_selection_exclusive_given_current_position(buffer, selc) if (letterafter or (@command == "c" and context.input == "zl")) end buffer.x, buffer.y = ox, oy if has_action should_make_exclusive = (if_b and has_action) make_selection_exclusive_given_current_position(buffer, selc) if should_make_exclusive do_action buffer, selc } goto_top_of_screen_block = proc { |c| buffer = self.current_buffer buffer.move_to_y buffer.top } goto_end_of_screen_block = proc { |c| buffer = self.current_buffer y = buffer.top + screen_height - 1 y = [y, buffer.lines.length - 1].min buffer.move_to_y y } goto_mid_screen_line_block = proc { |c| buffer = self.current_buffer y = buffer.top + ([screen_height, buffer.last_line_num].min / 2) buffer.move_to_y y } vi_g_block = proc { |c| buffer = self.current_buffer @command << c.chr if @command == "gg" if @number =~ /[0-9]+/ buffer.move_to_y(@number.to_i - 1) redraw buffer @number = nil else scroll_to_top buffer end @command = "" end } vi_cap_g_block = proc { |c| buffer = self.current_buffer if @number =~ /[0-9]+/ buffer.move_to_y(@number.to_i - 1) redraw buffer @number = nil else selc = create_selection(buffer, :selc_lined) { scroll_to_bottom buffer } do_action buffer, selc end } next_prev_search_block = proc { |c| buffer = self.current_buffer @search = SearchContext.new @search.history_pos = 0 @search.reverse = (c.chr.upcase == c.chr) do_search(buffer, @search.reverse ? Curses::KEY_CTRL_P : Curses::KEY_CTRL_N) if !hl_selection.nil? buffer.move_to @hl_selection.s.x, @hl_selection.s.y end @search = nil } find_next_word_block = proc { |c| buffer = self.current_buffer @search = SearchContext.new @search.history_pos = 0 @search.reverse = (c == ?#) word_range = get_word_under_cursor buffer word = buffer.lines[buffer.y].slice(word_range) "* matched: #{word}" @search.already_performed = false do_search(buffer, Curses::KEY_CTRL_N, word) # see above buffer.move_to @hl_selection.s.x, @hl_selection.s.y @search = nil } match_paren_block = proc { |c| buffer = self.current_buffer # make movements work, e.g d% -> delete between ()s buffer.ensure_line_highlight buffer.y row = buffer.tokens[buffer.y] token = row.find { |tok| (tok == row.last) || (row[row.index(tok) + 1].x > buffer.x) } matches_hash = buffer.highlighter.matches_hash inv_matches_hash = {} matches_hash.values.sort.uniq.each { |val| inv_matches_hash[val] = matches_hash.collect { |dom, rng| rng == val ? dom : nil }.compact } looking_backwards = matches_hash.values.include? token.str matches_hash_values, matches_hash_keys = matches_hash.values, matches_hash.keys we_want_a = looking_backwards ? inv_matches_hash[token.str] : [matches_hash[token.str]] level = 0 val = looking_backwards ? -1 : 1 token_itr(buffer, token, buffer.y, !looking_backwards) { |y, tok| level += val if matches_hash_values.include? tok.str if we_want_a.include?(tok.str) and level == 0 buffer.move_to tok.x, y break end level -= val if matches_hash_keys.include? tok.str } } insert_mode_cursor_block = proc { |c| buffer = self.current_buffer by_line = [?j, ?k].include?(c) selc = create_selection(buffer, by_line ? :selc_lined : :selc_normal) { do_movement_key buffer, c } make_selection_exclusive_given_current_position(buffer, selc) unless by_line do_action buffer, selc } end_block = proc { |c| buffer = self.current_buffer has_action = !@command.empty? selc = create_selection(buffer, :selc_normal) { buffer.move_to_x buffer.last_char_on_line(buffer.y) @end_char_mode = true unless has_action } make_selection_exclusive_given_current_position(buffer, selc) unless has_action do_action buffer, selc } home_block = proc { |c| buffer = self.current_buffer buffer.move_to_x 0 } selection_block = proc { |c| buffer = self.current_buffer if !@selection.nil? @selection = nil else @selection = Selection.new @selection.mode = (c == ?\C-v) ? :selc_boxed : ((c == ?v) ? :selc_normal : :selc_lined) if @selection.mode == :selc_normal || @selection.mode == :selc_boxed @selection.s = Point.new(buffer.x, buffer.y) elsif @selection.mode == :selc_lined @selection.s = Point.new(0, buffer.y) end end } search_block = proc { |c| buffer = self.current_buffer @mode_stack.push :search @search = SearchContext.new @search.history_pos = 0 @search.already_performed = false @search.reverse = (c == ??) @search.got_no_key = true "enter search term: " } join_line_block = proc { |c| buffer = self.current_buffer if buffer.y == buffer.last_line_num # beep :) # fixme - needs test else get_indent_level(buffer.lines[buffer.y]) DiffLogger::ModifyLineChange.new(buffer, buffer.y + 1) { line = buffer.lines[buffer.y + 1] line.slice! 0, get_indent_level(line) line[0,0] = " " } EditorApp.join_next_line_onto_this buffer, buffer.y end } macro_block = proc { |c| buffer = self.current_buffer if @doing_macro.nil? @mode_stack.push :get_letter @get_letter_pop_proc = proc { |c| @doing_macro = "" @macro_letter = c } else raise "er. how the fuck else did u exit macro mode thingy???" if @doing_macro[-1] != ?q @doing_macro.slice!(-1) @macros[@macro_letter] = @doing_macro @doing_macro = nil end } play_macro_block = proc { |c| buffer = self.current_buffer @mode_stack.push :get_letter @get_letter_pop_proc = proc { |c| @macros[c].each_byte { |c| send_key c } } } repeat_previous_command_block = proc { |c| buffer = self.current_buffer if !@last_command.nil? "executing #{@last_command}" was_nil_selection = @selection.nil? @selection = @selection_for_last_command if was_nil_selection cmd = @last_command cmd.each_byte { |key| send_key key } @last_command = cmd @selection = nil if was_nil_selection end } select_paste_buffer_block = proc { @mode_stack.push :get_letter @get_letter_pop_proc = proc { |c| @current_paste_buffer = c.chr } } undo_block = proc { |c| buffer = self.current_buffer buffer.dlog.undo redraw buffer } insert_block = proc { |c| buffer = self.current_buffer line = buffer.lines[buffer.y] buffer.move_to_x get_indent_level(line) if (c.chr == c.chr.upcase) @end_char_mode = true if line.empty? begin_insert_mode buffer } replace_block = proc { |c| buffer = self.current_buffer begin_insert_mode buffer @replace_mode = true } replace_letter_block = proc { |c| buffer = self.current_buffer begin_insert_mode buffer @replace_mode = true @replace_single_letter = true } enter_command_mode_block = proc { |c| buffer = self.current_buffer begin_insert_mode buffer @mode_stack = [:command] ":" } vi_y_block = proc { |c| buffer = self.current_buffer handle_generic_command buffer, c } debug_buffer_block = proc { |c| buffer = self.current_buffer switch_to_buffer @debug_buffer } goto_classstack_or_buffer_block = proc { |c| buffer = self.current_buffer # buffer specific... some kind of subclass or so? line = buffer.lines[buffer.y] idx_s = nil if line =~ /^\[:b([0-9]+?)\]/ idx = $1.to_i # due to to_i sucking we need to never have 1 numbered buffers switch_to_buffer @buffers.detect { |b| b.bnum == idx } BufferListExtension.clear_extension_buffers self elsif line =~ /^\[:([0-9]+?)\]/ line_no = $1.to_i tbuffer = buffer.old_buf tbuffer.x = 0 tbuffer.y = line_no unclamped_top = line_no - (screen_height / 2) tbuffer.top = unclamped_top.clamp_to 0, tbuffer.last_line_num switch_to_buffer buffer.old_buf HierarchyListExtension.clear_extension_buffers self end } show_classstack_block = proc { |c| buffer = self.current_buffer ensure_buffer_highlighted buffer class_list = [] done = [] buffer.classstacks.each_with_index { |stack, idx| next if stack.empty? str = stack.join "::" unless done.include? str done << str class_list << Struct.new(:y, :s).new(idx, str) end } cur_class_y = 0 b = HierarchyListExtension.create_buffer self class_list.each_with_index { |c, idx| b.lines << BufferLine.new("[:#{c.y}] #{c.s}") next_one = class_list.at(idx + 1) if (cur_class_y == 0) and (next_one.nil? \ || next_one.y > buffer.y) cur_class_y = idx end } b.y = cur_class_y b.top = b.y switch_to_buffer b } show_buffer_list_block = proc { |c| buffer = self.current_buffer b = BufferListExtension.create_buffer self @buffers.each { |buffer| visible_idx = buffer.fake_buffer ? " " : buffer.bnum b.lines << BufferLine.new("[:b#{visible_idx}] - #{buffer.fname} (length: #{buffer.lines.length}) (x:#{buffer.x}, y:#{buffer.y})") } switch_to_buffer b } previous_buffer_block = proc { |c| buffer = self.current_buffer switch_to_buffer } other_buffer_block = proc { |c| @current_docview = @docview2 } redraw_block = proc { |c| buffer = self.current_buffer redraw buffer } redo_block = proc { |c| buffer = self.current_buffer buffer.dlog.redo redraw buffer } paste_buffer_block = proc { |c| buffer = self.current_buffer myy = buffer.y after = !(c.chr.upcase == c.chr) done_something = false diff = 0 paste_buffer = pop_paste_buffer paste_buffer.lines.each_with_index { |lbuffer, idx| if after and !done_something if lbuffer.newline_at_start myy += 1 diff = +1 else # !newline_at_start buffer.x += 1 if buffer.x < buffer.lines[myy].length end end if lbuffer.newline_at_start and lbuffer.newline_at_end # add totally new line DiffLogger::InsertLineAfterChange.new(buffer, myy) { buffer.lines.insert_after myy, lbuffer.dup } elsif !lbuffer.newline_at_start and !lbuffer.newline_at_end # add in place DiffLogger::ModifyLineChange.new(buffer, myy) { buffer.lines[myy][buffer.x, 0] = lbuffer.dup } elsif lbuffer.newline_at_start and !lbuffer.newline_at_end # append to the start of the next line - equiv to new line, then join DiffLogger::ModifyLineChange.new(buffer, myy+1) { buffer.lines[myy+1][0, 0] = lbuffer.dup } elsif !lbuffer.newline_at_start and lbuffer.newline_at_end # add in place and split rest of line onto next line rest_of_line = nil DiffLogger::ModifyLineChange.new(buffer, myy) { rest_of_line = buffer.lines[myy].slice!(buffer.x..-1) } DiffLogger::ModifyLineChange.new(buffer, myy) { buffer.lines[myy][buffer.x, 0] = lbuffer.dup } DiffLogger::InsertLineAfterChange.new(buffer, myy) { buffer.lines.insert_after myy, rest_of_line } end done_something = true myy += 1 } buffer.y += diff redraw buffer } generic_vi_c_d_block = proc { |c| buffer = self.current_buffer handle_generic_command buffer, c } modify_indent_block = proc { |c| buffer = self.current_buffer @command << c.chr got_selection = !@selection.nil? selc = nil if got_selection selc = @selection.right_way_up elsif @command == c.chr*2 selc = Selection.new Point.new(0, buffer.y), Point.new(buffer.lines[buffer.y].length, buffer.y), :selc_lined @command = "" elsif @command.length > 2 @command = "" end if !selc.nil? tab = (" " * config_get_sw) backwards = (c == ?<) EditorApp.each_lineslice_in_selection(buffer, selc) { |hlls| DiffLogger::ModifyLineChange.new(buffer, hlls.y) { line = buffer.lines[hlls.y] if backwards line.slice! 0, [get_indent_level(line), config_get_sw].min else line[0, 0] = tab end } EditorApp.invalidate_buffer_line buffer, hlls.y } end } reindent_block = proc { |c| buffer = self.current_buffer @command << c.chr got_selection = !@selection.nil? selc = nil if got_selection @command = "" selc = @selection.right_way_up elsif @command == c.chr*2 selc = Selection.new Point.new(0, buffer.y), Point.new(buffer.lines[buffer.y].length, buffer.y), :selc_lined @command = "" end EditorApp.each_lineslice_in_selection(buffer, selc) { |hlls| y = hlls.y next if y == 0 current_line = buffer.lines[y-1] indent_string = calculate_autoindent buffer, current_line, y-1, true DiffLogger::ModifyLineChange.new(buffer, y) { line = buffer.lines[y] line.slice! 0, get_indent_level(buffer.lines[y]) line[0, 0] = indent_string } EditorApp.invalidate_buffer_line buffer, y } } vi_insert_after_block = proc { |c| buffer = self.current_buffer upcase = (c.chr.upcase == c.chr) cur_line_len = buffer.lines[buffer.y].length buffer.move_to_x(upcase ? buffer.last_char_on_line(buffer.y) : [buffer.x + 1, cur_line_len].min) @end_char_mode = true if buffer.x == buffer.last_char_on_line(buffer.y) begin_insert_mode buffer } vi_insert_new_line_block = proc { |c| buffer = self.current_buffer upcase = (c.chr.upcase == c.chr) insert_line = upcase ? buffer.y : buffer.y + 1 indent_string = calculate_autoindent buffer, "", insert_line - 1, false line = BufferLine.new(indent_string) DiffLogger::InsertLineAfterChange.new(buffer, insert_line) { buffer.lines.insert_after insert_line, line } buffer.move_to(indent_string.length, insert_line) @end_char_mode = true begin_insert_mode buffer redraw buffer } vi_escape_mode_block = proc { |c| buffer = self.current_buffer @selection = nil @command = "" } change_line_block = proc { |c| buffer = self.current_buffer buffer.move_to_x 0 DiffLogger::ModifyLineChange.new(buffer, buffer.y) { buffer.lines[buffer.y].replace BufferLine.new("") } EditorApp.invalidate_buffer_line buffer, buffer.y @end_char_mode = true begin_insert_mode buffer } edit_or_delete_till_end_block = proc { |c| buffer = self.current_buffer cmd = c.chr.downcase is_c = (cmd == "c") selc = Selection.new Point.new(buffer.x, buffer.y), Point.new(buffer.last_char_on_line(buffer.y), buffer.y), :selc_normal EditorApp.manip_selection buffer, selc, :manip_cut, pop_paste_buffer @end_char_mode = true EditorApp.invalidate_buffer_line buffer, buffer.y begin_insert_mode(buffer) if is_c } change_letter_block = proc { |c| buffer = self.current_buffer selc = Selection.new Point.new(buffer.x, buffer.y), Point.new(buffer.x, buffer.y), :selc_normal EditorApp.manip_selection buffer, selc, :manip_cut, pop_paste_buffer if buffer.lines[buffer.y].empty? @end_char_mode = true else buffer.x -= 1 if buffer.x >= buffer.lines[buffer.y].length end EditorApp.invalidate_buffer_line buffer, buffer.y begin_insert_mode buffer } vi_delete_char_block = proc { |c| buffer = self.current_buffer got_selection = !@selection.nil? if got_selection EditorApp.manip_selection buffer, @selection, :manip_cut, pop_paste_buffer end_selection buffer elsif buffer.lines[buffer.y].length > 0 upcase = (c.chr.upcase == c.chr) buffer.x -= 1 if upcase selc = Selection.new Point.new(buffer.x, buffer.y), Point.new(buffer.x, buffer.y), :selc_normal EditorApp.manip_selection buffer, selc, :manip_cut, pop_paste_buffer buffer.x -= 1 if buffer.x >= buffer.lines[buffer.y].length EditorApp.invalidate_buffer_line buffer, buffer.y end } scroll_up_line_no_cursor_move_block = proc { |c| buffer = self.current_buffer scroll_up(buffer) } scroll_down_line_no_cursor_move_block = proc { |c| buffer = self.current_buffer scroll_down(buffer) } page_down_move_cursor_half_page_block = proc { |c| buffer = self.current_buffer (screen_height / 2).times { break if not scroll_down(buffer) } redraw buffer } page_down_move_cursor_block = proc { |c| buffer = self.current_buffer screen_height.times { break if not scroll_down(buffer) } redraw buffer } page_up_move_cursor_half_page_block = proc { |c| buffer = self.current_buffer (screen_height / 2).times { break if not scroll_up(buffer) } redraw buffer } page_up_move_down_cursor_block = proc { |c| buffer = self.current_buffer screen_height.times { break if not scroll_up(buffer) } redraw buffer } insert_escape_block = proc { buffer = self.current_buffer begin_normal_mode buffer buffer.dlog.flush @end_char_mode = false @replace_mode = false @replace_single_letter = false } insert_backspace_block = proc { buffer = self.current_buffer if buffer.x == 0 and buffer.y == 0 # ignore backspace on first char in buffer elsif buffer.x == 0 and (!@end_char_mode or \ (@end_char_mode and buffer.lines[buffer.y].empty?)) # join current line onto previous line and move to old end of last line line_to_join = nil DiffLogger::RemoveLineChange.new(buffer, buffer.y) { line_to_join = buffer.lines.delete_at(buffer.y) } buffer.y -= 1 DiffLogger::ModifyLineChange.new(buffer, buffer.y) { join_to = buffer.lines[buffer.y] if line_to_join.length == 0 buffer.move_to_x join_to.length - 1 @end_char_mode = true else buffer.move_to_x join_to.length end join_to << line_to_join redraw_from_and_including buffer, buffer.y } else raise "out_of_bounds error!" if buffer.out_of_bounds buffer.y, buffer.x current_line = buffer.lines[buffer.y] current_indent = get_indent_level current_line bx = buffer.ax len = (current_indent == bx ? config_get_sw : 1) len = len.clamp_to 0, bx DiffLogger::ModifyLineChange.new(buffer, buffer.y) { buffer.lines[buffer.y].slice! bx - len, len } ecm = @end_char_mode buffer.move_to_x(limit_to_positive(buffer.x - len)) @end_char_mode = ecm EditorApp.invalidate_buffer_line buffer, buffer.y end } insert_cr_key_block = proc { buffer = self.current_buffer current_line = buffer.lines[buffer.y] indent_string = calculate_autoindent buffer, current_line, buffer.y, true should_fixup_end_pair = (current_line[buffer.x - 1,2] == "{}") and (@settings[:autopair] == "true") if buffer.ax == current_line.length line = BufferLine.new(indent_string) else # split the rest of the current line onto the next line DiffLogger::ModifyLineChange.new(buffer, buffer.y) { line = BufferLine.new(indent_string + current_line.slice!(buffer.x, current_line.length)).dup } end DiffLogger::InsertLineAfterChange.new(buffer, buffer.y+1) { buffer.lines.insert_after buffer.y+1, line } if should_fixup_end_pair indent_string = calculate_autoindent buffer, buffer.lines[buffer.y], buffer.y, false DiffLogger::InsertLineAfterChange.new(buffer, buffer.y+1) { buffer.lines.insert_after buffer.y+1, indent_string } end buffer.y += 1 if indent_string.length > buffer.last_char_on_line(buffer.y) buffer.move_to_x indent_string.length - 1 @end_char_mode = true else buffer.move_to_x indent_string.length end if buffer.lines[buffer.y].empty? buffer.move_to_x 0 @end_char_mode = true end redraw buffer } insert_end_key_block = proc { buffer = self.current_buffer buffer.move_to_x buffer.last_char_on_line(buffer.y) @end_char_mode = true } insert_home_key_block = proc { buffer = self.current_buffer buffer.move_to_x 0 } insert_movement_block = proc { |c| buffer = self.current_buffer do_movement_key buffer, c, :insert_mode } # INSERT BINDINGS add_insert_binding("\e", &insert_escape_block) add_insert_binding("\b", &insert_backspace_block) add_insert_binding("\r", &insert_cr_key_block) add_curses_key_translators(Curses::KEY_END => "\C-x\C-h$", Curses::KEY_HOME => "\C-x\C-h0") add_insert_binding("\C-x\C-h$", &insert_end_key_block) add_insert_binding("\C-x\C-h0", &insert_home_key_block) add_curses_key_translators(Curses::KEY_UP => "\C-x\C-hk", Curses::KEY_DOWN => "\C-x\C-hj", Curses::KEY_LEFT => "\C-x\C-hh", Curses::KEY_RIGHT => "\C-x\C-hl") add_insert_binding("\C-x\C-hh", "\C-x\C-hj", "\C-x\C-hk", "\C-x\C-hl", &insert_movement_block) # COMMAND BINDINGS add_command_binding("t", "T", "f", "F", &look_for_letter_block) add_command_binding("^", &goto_first_real_letter_on_line_block) add_command_binding("}", "{", &skip_block_block) add_command_binding("w", "W", "e", "E", "b", "B", "zh", "zl", &word_movement_block) add_command_binding("H", &goto_top_of_screen_block) add_command_binding("L", &goto_end_of_screen_block) add_command_binding("M", &goto_mid_screen_line_block) add_command_binding("g", &vi_g_block) add_command_binding("G", &vi_cap_g_block) add_command_binding("n", "N", &next_prev_search_block) add_command_binding("*", "#", &find_next_word_block) add_command_binding("%", &match_paren_block) add_command_binding("k", "j", "h", "l", "\C-x\C-hh", "\C-x\C-hj", "\C-x\C-hk", "\C-x\C-hl", &insert_mode_cursor_block) add_command_binding("$", "\C-x\C-h$", &end_block) add_command_binding("\C-x\C-h0", &home_block) add_command_binding("v", "V", "\C-V", &selection_block) add_command_binding("/", "?", &search_block) add_command_binding("J", &join_line_block ) add_command_binding("q", ¯o_block) add_command_binding("@", &play_macro_block) add_command_binding(".", &repeat_previous_command_block) add_command_binding("i", "I", &insert_block) add_command_binding("u", &undo_block) add_command_binding("\"", &select_paste_buffer_block) add_curses_key_translators(Curses::KEY_PPAGE => "\C-b", Curses::KEY_NPAGE => "\C-f") add_command_binding("\C-b", &page_up_move_down_cursor_block) add_command_binding("\C-f", &page_down_move_cursor_block) add_command_binding("\C-e", &scroll_down_line_no_cursor_move_block) add_command_binding("s", &change_letter_block) add_command_binding("D", "C", &edit_or_delete_till_end_block) add_command_binding("S", &change_line_block) add_command_binding("\e", &vi_escape_mode_block) add_command_binding("o", "O", &vi_insert_new_line_block) add_command_binding("a", "A", &vi_insert_after_block) add_command_binding("=", &reindent_block) add_command_binding("<", ">", &modify_indent_block) add_command_binding("c", "d", &generic_vi_c_d_block) add_command_binding("\C-r", &redo_block) add_command_binding("\C-l", &redraw_block) add_command_binding("\C-w\C-o", &previous_buffer_block) add_command_binding("\C-w\C-w", &other_buffer_block) add_command_binding("\C-s", &show_buffer_list_block) add_command_binding("\C-x\C-c", &show_classstack_block) # TODO - following is a "bit" of a hack... add_command_binding("\r", &goto_classstack_or_buffer_block) add_command_binding("\C-x\C-d", &debug_buffer_block) add_command_binding("\C-d", &page_up_move_cursor_half_page_block) add_command_binding("\C-u", &page_down_move_cursor_half_page_block) add_command_binding("y", &vi_y_block) add_command_binding("R", &replace_block) add_command_binding("r", &replace_letter_block) add_command_binding(":", &enter_command_mode_block) add_command_binding("p", "P", &paste_buffer_block) add_command_binding("x", "X", &vi_delete_char_block) add_command_binding("\C-y", &scroll_up_line_no_cursor_move_block) end |
#setup_cmd(cmd_string, re, &block) ⇒ Object
309 310 311 312 313 314 315 316 317 318 319 320 321 322 |
# File 'lib/front.rb', line 309 def setup_cmd cmd_string, re, &block possibles = [] cmd_string.split(",").each { |word| word << "'" if word.index('').nil? possibles += [word.sub(/'.*$/,""), word.sub(/'/, "")] } # @commands should be used in a shortest first fashion ... TODO possibles.sort.uniq.each { |possible| @commands[possible] = block } @cmds[re] = block end |
#setup_cmd_override(re, &block) ⇒ Object
324 325 326 |
# File 'lib/front.rb', line 324 def setup_cmd_override re, &block @cmd_overrides[re] = block end |
#setup_default_command_set ⇒ Object
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 |
# File 'lib/commands.rb', line 5 def setup_default_command_set @cmd_overrides = {} @commands = {} @cmds = {} setup_cmd("set", /^set\s+(.*?)=(.*)/) { |ctx| ctx.cmd_line =~ ctx.re key, val = $1, $2 @settings[key.to_sym] = val } setup_cmd("sp'lit", /^sp(lit)?/) { |ctx| buffer_copy = ctx.buffer.make_copy @docview_to_ruler[@docview2].buffer = buffer_copy @docview2.buffer = buffer_copy @current_docview = @docview @settings[:split] = "true" "you have to be insane to use this. split is totally messed up atm" } setup_cmd("q!", /^q!$/) { |ctx| bufs = buffers_to_save buffer = ctx.buffer if bufs.length > 1 dbg(:quit) { "u11" } if !buffer.dlog.invalidated? dbg(:quit) { "u12" } "closing reverted buffer!" @buffers.delete buffer switch_to_buffer redraw buffer else dbg(:quit) { "u13" } "more than one file unsaved! use :qa! to revert all!" end elsif bufs.length == 1 and bufs.first == buffer dbg(:quit) { "u14" } bufs.first.dlog.revert_to_save_point # there can be only one!!! :P Curses.end_it_all elsif !buffer.dlog.invalidated? dbg(:quit) { "u15" } @buffers.delete buffer Curses.end_it_all if buffers_to_save.length == 0 switch_to_buffer redraw buffer end } setup_cmd("qk", /^qk$/) { |ctx| Curses.end_it_all } setup_cmd("q'uit", /^q$/) { |ctx| buffer = ctx.buffer num_real_bufs = real_buffers.length if num_real_bufs > 0 and buffer.dlog.invalidated? dbg(:quit) { "u01" } "file unsaved!" elsif num_real_bufs > 0 dbg(:quit) { "u02" } @buffers.delete buffer switch_to_buffer nil end unless real_buffers.length > 0 dbg(:quit) { "u03" } Curses.end_it_all else dbg(:quit) { "u04" } redraw buffer end } setup_cmd("new", /^new$/) { |ctx| ctx.cmd_line =~ ctx.re buf = EditorApp.new_buffer self, :need_bnum switch_to_buffer buf redraw buf } setup_cmd("e,ed,edit", /^e(?:d(?:it)?)?\s+(.+)$/) { |ctx| ctx.cmd_line =~ ctx.re fname = $1 fname.sub! "~", ENV["HOME"] switch_to_buffer EditorApp.load_file_as_buffer(self, fname) } setup_cmd("r,r!", /r(!\s*(.*$)|\s+(.*$))/) { |ctx| # TODO - test ctx.cmd_line =~ ctx.re lines = nil is_cmd = !$2.nil? lines = is_cmd ? exec_into_buffer_lines($2) : EditorApp.file_to_buffer_lines($3) ctx.buffer.lines[ctx.buffer.y, 0] = lines redraw ctx.buffer } setup_cmd("b'uffer", /^b(.+)$/) { |ctx| ctx.cmd_line =~ ctx.re buf = @buffers.detect { |b| b.bnum == $1.to_i } if buf.nil? "No such buffer" else switch_to_buffer buf end } setup_cmd("w,wa,wq", /^w(q|a|\s+(.+))?$/) { # TODO - add in waq? |ctx| ctx.cmd_line =~ ctx.re buffer = ctx.buffer case $1 when "a" error = false each_real_buffer { |buffer| next if !buffer.dlog.invalidated? # don't save out untouched files if buffer.fname.nil? "ERROR - unnamed file on buffer #{buffer.bnum}" error = true break end save_buffer_as_file buffer } "saved all files" unless error when "q" if !buffer.fname.nil? # TODO - notify when other files are unsaved!!! save_buffer_as_file buffer Curses.end_it_all else "ERROR - unnamed file on buffer #{buffer.bnum}" end when nil # TODO - add a test case for this.. if !buffer.fname.nil? save_buffer_as_file buffer "saved" else "ERROR - unnamed file on buffer #{buffer.bnum}" end else fname = $2 fname.sub! "~", ENV["HOME"] unless fname.nil? if fname.nil? "ERROR - unnamed file on buffer #{buffer.bnum}" else save_buffer_as_file buffer, fname # write it to a file with a suffix "written out to: #{fname}" end end } # NOTE - this one just doesn't fit in with any completion plan i can come up with!!! - *has* to be a override setup_cmd_override(/^([0-9]+)$/) { |ctx| ctx.cmd_line =~ ctx.re buffer = ctx.buffer x = get_indent_level buffer.lines[buffer.y] buffer.move_to(x, $1.to_i - 1) buffer.top = buffer.y redraw buffer } end |
#setup_extensions ⇒ Object
700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 |
# File 'lib/shikaku.rb', line 700 def setup_extensions setup_cmd("sc", /^sc$/) { |ctx| ctx.cmd_line =~ ctx.re fname = ctx.buffer.fname buf = EditorApp.new_buffer self, :no_blank_line buf.lines += exec_into_buffer_lines "ruby -wc #{fname} 2>&1" switch_to_buffer buf } setup_cmd("tlaci,diff", /^((tlaci)|(diff))$/) { |ctx| ctx.cmd_line =~ ctx.re diff_only = $2.nil? cmd = "tla changes --diffs 2>&1" buf = nil if diff_only buf = EditorApp.new_buffer self, :no_blank_line else log_file_fname = `tla make-log`.chomp buf = EditorApp.load_file_as_buffer self, log_file_fname end buf.lines += exec_into_buffer_lines cmd switch_to_buffer buf } end |
#show_line_with_marker(buffer, point, line = nil) ⇒ Object
13 14 15 16 17 18 19 20 21 22 |
# File 'lib/debug.rb', line 13 def show_line_with_marker buffer, point, line = nil line = buffer.lines[point.y] if line.nil? n = 0 line.unpack("c*").collect { |c| t = (n == point.x) ? "[#{c.chr}]" \ : "#{c.chr}" n += 1; t }.join end |
#start_background_highlighter ⇒ Object
754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 |
# File 'lib/shikaku.rb', line 754 def start_background_highlighter # TODO enable the background highlighter return Thread.new { while true # FIXME - # maybe we should include some of the buffers listed by # a call to BufferListing::instance.open_buffers once we # are finished with the current_buffer? [current_buffer].each { |buffer| next if buffer != current_buffer ensure_buffer_highlighted buffer } sleep 5 end } end |
#status_bar_edit_line(status, pos = -1) ⇒ Object
87 88 89 90 |
# File 'lib/search.rb', line 87 def status, pos = -1 @status_bar.text = status @status_bar.cursor.x, @status_bar.cursor.y = ((pos == -1) ? status.length : pos), 0 end |
#switch_to_buffer(buf = @last_buffer) ⇒ Object
374 375 376 377 378 379 380 381 382 383 384 |
# File 'lib/shikaku.rb', line 374 def switch_to_buffer buf = @last_buffer @last_buffer = @current_buffer buf = real_buffers.first if (!@buffers.include? buf) or buf.nil? @current_buffer = buf buffer_changed_to buf return if buf.nil? # TODO need to fully clear screen here in case of short buffers? redraw buf @status_bar = @widgets.detect { |sb| (sb.is_a? StatusBar) and (sb.buffer == buf) } @status_bar = (buf) if @status_bar.nil? end |
#token_itr(buffer, tok, y, forwards, &block) ⇒ Object
609 610 611 612 613 614 615 |
# File 'lib/shikaku.rb', line 609 def token_itr buffer, tok, y, forwards, &block if forwards itr_forewards buffer, tok, y, &block else itr_backwards buffer, tok, y, &block end end |
#update_focus ⇒ Object
498 499 500 501 502 503 504 505 506 507 508 509 |
# File 'lib/front.rb', line 498 def update_focus case @mode_stack.last when :search @focus = @status_bar when :normal, :insert, :get_letter @focus = current_docview when :command @focus = @status_bar when @focus = current_docview end end |
#update_ruler_state ⇒ Object
265 266 267 268 269 270 271 272 273 274 |
# File 'lib/shikaku.rb', line 265 def update_ruler_state @widgets.delete @ruler @widgets.insert_after @widgets.index(@doc_with_ruler), @ruler if config_get_nu idx = @widgets.index(@doc_with_ruler2) if !idx.nil? @widgets.delete @ruler2 @widgets.insert_after idx, @ruler2 if config_get_nu end EditorApp.perform_layout end |
#update_selection(buffer) ⇒ Object
USES right_way_up
104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 |
# File 'lib/selections.rb', line 104 def update_selection buffer EditorApp.each_lineslice_in_selection(buffer, @last_selection) { |hlls| EditorApp.invalidate_buffer_line buffer, hlls.y } unless @last_selection.nil? no_selection = @selection.nil? || @selection.invalid? EditorApp.each_lineslice_in_selection(buffer, @selection.right_way_up) { |hlls| EditorApp.invalidate_buffer_line buffer, hlls.y } unless no_selection @last_selection = no_selection ? nil : @selection.dup.right_way_up end |
#update_split_state ⇒ Object
250 251 252 253 254 255 256 257 258 259 260 261 262 263 |
# File 'lib/shikaku.rb', line 250 def update_split_state [@doc_with_ruler2, @docview2].each { |w| @widgets.delete w } = @widgets.find_all { |sb| sb.is_a? StatusBar } = @widgets.index .first if config_get_split if .nil? @widgets += [@doc_with_ruler2, @docview2] if config_get_split else @widgets.insert_after( - 1, @docview2) @widgets.insert_after( - 1, @doc_with_ruler2) end end EditorApp.perform_layout end |