class GtkApp::TextBuffer
Constants
- DEFAULT_LANG
- DEFAULT_TAGS
Attributes
!@attribute [r] redo_stack
Collection of actions undone @return [Array]
!@attribute [r] spell_check
Aspell object @return [FFI::Aspell::Speller]
!@attribute [r] text_marks
Collection of named text marks used to track user input @return [Hash]
!@attribute [r] undo_stack
Collection of actions performed @return [Array]
Public Class Methods
Gtk::TextBuffer::new
# File lib/gtk_app/text_buffer.rb, line 29 def initialize(tag_table=nil, options={}) super(tag_table) @undo_stack, @redo_stack = [], [] options[:lang] ||= DEFAULT_LANG @spell_check = FFI::Aspell::Speller.new(options[:lang]) setup_default_tags setup_text_marks setup_signals end
Public Instance Methods
@param [Gtk::TextIter] s_iter @param [Gtk::TextIter] e_iter
# File lib/gtk_app/text_buffer.rb, line 110 def check_range(s_iter, e_iter) e_iter.forward_word_end if e_iter.inside_word? unless s_iter.starts_word? if s_iter.inside_word? || s_iter.ends_word? s_iter.backward_word_start elsif s_iter.forward_word_end s_iter.backward_word_start end end # Get the iter at the current cursor position and the pre cursor. c_iter = get_iter_at_offset(cursor_position) pc_iter = c_iter.clone pc_iter.backward_char spell_error = tag_table.lookup('spell_error') has_error = (c_iter.has_tag?(spell_error) || pc_iter.has_tag?(spell_error)) clear(:spell_error, s_iter, e_iter) # NOTE: From GtkSpell, catch rare cases when the replacement occurs at the # beginning of the buffer. An iter at offset 0 seems to always be inside a # word even if it's not. if get_iter_at_offset(0) == s_iter s_iter.forward_word_end s_iter.backward_word_start end ws_iter = s_iter.clone # => Word start iter while (ws_iter <=> e_iter) < 0 do we_iter = ws_iter.clone # => Word end iter we_iter.forward_word_end if ((ws_iter <=> c_iter) < 0) && ((c_iter <=> we_iter) <= 0) # The current word is being actively edited. Only check it if it's # already been identified as incorrect. Else, check later. check_word(ws_iter, we_iter) if has_error else check_word(ws_iter, we_iter) end # Move the word end iter the the beginning of the next word. we_iter.forward_word_end we_iter.backward_word_start break if we_iter == ws_iter ws_iter = we_iter.clone end end
Helper method to check the spelling of every word in the buffer.
# File lib/gtk_app/text_buffer.rb, line 104 def check_spelling check_range(*bounds) end
@param [Gtk::TextIter] s_iter @param [Gtk::TextIter] e_iter
# File lib/gtk_app/text_buffer.rb, line 159 def check_word(s_iter, e_iter) word = get_text(s_iter, e_iter) unless @spell_check.correct?(word) format(:spell_error, s_iter, e_iter) end end
Remove all tags of a given name from from one Gtk::TextIter to another. @param [] tag_name @param [Gtk::TextIter] s_iter @param [Gtk::TextIter] e_iter
# File lib/gtk_app/text_buffer.rb, line 234 def clear(tag_name, s_iter, e_iter) remove_tag(tag_name.to_s, s_iter, e_iter) end
Remove all Gtk::TextTag’s from one Gtk::TextIter to another. @param [Gtk::TextIter] s_iter @param [Gtk::TextIter] e_iter
# File lib/gtk_app/text_buffer.rb, line 243 def clear_all(s_iter, e_iter) remove_all_tags(s_iter, e_iter) end
Remove all occurrences of a Gtk::TextTag in the given selection range.
# File lib/gtk_app/text_buffer.rb, line 217 def clear_selection(*tag_names) s_iter, e_iter, text_selected = selection_bounds if text_selected if tag_names.empty? clear_all(s_iter, e_iter) else tag_names.each { |tag_name| clear(tag_name, s_iter, e_iter) } end end end
Locate text in selection or the entire buffer. If found, a Gtk::TextMark is returned. Else, nil. @param [String] string Text to search.
# File lib/gtk_app/text_buffer.rb, line 177 def find(string) s_iter, e_iter, text_selected = selection_bounds s_iter = start_iter unless text_selected s_iter, e_iter = s_iter.forward_search(string, Gtk::TextIter::SEARCH_TEXT_ONLY, e_iter) s_iter ? create_mark(nil, s_iter, false) : nil end
This is a small wrapper around the Gtk::TextBuffer#apply_tag method. It allows the Gtk::TextTag name to be passed as a symbol. @param [] tag_name @param [Gtk::TextIter] s_iter @param [Gtk::TextIter] e_iter
# File lib/gtk_app/text_buffer.rb, line 210 def format(tag_name, s_iter, e_iter) apply_tag(tag_name.to_s, s_iter, e_iter) end
Format text in the current selection range with a Gtk::TextTag identified by the given name. @param [String] tag_name
# File lib/gtk_app/text_buffer.rb, line 199 def format_selection(tag_name) s_iter, e_iter, text_selected = selection_bounds format(tag_name, s_iter, e_iter) if text_selected end
Pop the last action off the redo stack and apply the changes. If and action was performed, the cursor is placed at the actions starting Gtk::TextIter.
# File lib/gtk_app/text_buffer.rb, line 70 def redo if @redo_stack.empty? Gdk.beep else action = @redo_stack.pop s_iter = get_iter_at_offset(action[1]) e_iter = get_iter_at_offset(action[2]) case action[0] when :insert then insert(s_iter, action[3]) when :delete then delete(s_iter, e_iter) end @undo_stack.push(action) place_cursor(s_iter) end end
@param [String] string Text to replace the selection with. @param [Gtk::TextIter] s_iter @param [Gtk::TextIter] e_iter
# File lib/gtk_app/text_buffer.rb, line 187 def replace(string, s_iter, e_iter) begin_user_action delete(s_iter, e_iter) insert(s_iter, string) end_user_action place_cursor(s_iter) end
Does the Gtk::TextTagTable contain any ‘spell_error’ tags?
# File lib/gtk_app/text_buffer.rb, line 169 def spelling_errors? !tag_table.lookup('spell_error').nil? end
Pop the last action off the undo stack and rewind changes. If an action was performed, the cursor is placed at the actions starting Gtk::TextIter.
# File lib/gtk_app/text_buffer.rb, line 52 def undo if @undo_stack.empty? Gdk.beep else action = @undo_stack.pop s_iter = get_iter_at_offset(action[1]) case action[0] when :insert then delete(s_iter, get_iter_at_offset(action[2])) when :delete then insert(s_iter, action[3]) end @redo_stack.push(action) place_cursor(s_iter) end end
@param [Gtk::TextView]
# File lib/gtk_app/text_buffer.rb, line 42 def view=(text_view) text_view.instance_eval do signal_connect('button-press-event', &:__button_press_event) signal_connect('populate-popup', &:__populate_popup) end end
Retrieve the word at the current cursor position @return [String] The word.
# File lib/gtk_app/text_buffer.rb, line 88 def word_at_cursor get_text(*word_bounds).strip end
Determine the boudaries of the word at the current cursor position. @return [Array] The start and end iter.
# File lib/gtk_app/text_buffer.rb, line 94 def word_bounds iter = get_iter_at_offset(cursor_position) s_iter, e_iter = iter.clone, iter.clone s_iter.backward_word_start unless s_iter.starts_word? e_iter.forward_word_end unless e_iter.ends_word? [s_iter, e_iter] end
Private Instance Methods
Establish base signal handlers. Here we track user actions and…
# File lib/gtk_app/text_buffer.rb, line 273 def setup_signals signal_connect('begin-user-action') { |me| @user_action = true } signal_connect('end-user-action') { |me| @user_action = false } signal_connect('insert-text') do |me, iter, text, len| if user_action? @undo_stack << [:insert, iter.offset, (iter.offset + text.scan(/./).size), text] @redo_stack.clear end move_mark(me.text_marks[:insert_start], iter) end signal_connect_after('insert-text') do |me, iter, text, len| s_iter = get_iter_at_mark(me.text_marks[:insert_start]) check_range(s_iter, iter) move_mark(me.text_marks[:insert_end], iter) end signal_connect('delete-range') do |me, s_iter, e_iter| if user_action? text = get_text(s_iter, e_iter) @undo_stack << [:delete, s_iter.offset, e_iter.offset, text] end end signal_connect_after('delete-range') do |me, s_iter, e_iter| check_range(s_iter, e_iter) end end
# File lib/gtk_app/text_buffer.rb, line 264 def setup_text_marks @text_marks = { insert_start: create_mark('insert_start', start_iter, true), insert_end: create_mark('insert_end', start_iter, true), click: create_mark('click', start_iter, true) } end
# File lib/gtk_app/text_buffer.rb, line 304 def user_action? @user_action end