k.add :list_buffers, "List all buffers", 'B'
k.add :list_contacts, "List contacts", 'C'
k.add :redraw, "Redraw screen", :ctrl_l
- k.add :search, "Search messages", '/'
+ k.add :search, "Search all messages", '\\'
k.add :list_labels, "List labels", 'L'
k.add :poll, "Poll for new messages", 'P'
k.add :compose, "Compose new message", 'm'
+ k.add :nothing, "Do nothing", :ctrl_g
k.add :recall_draft, "Edit most recent draft message", 'R'
end
c.add :reply_mode_selected_color, Ncurses::COLOR_YELLOW, Ncurses::COLOR_BLACK, Ncurses::A_BOLD
c.add :reply_mode_unselected_color, Ncurses::COLOR_CYAN, Ncurses::COLOR_BLACK
c.add :reply_mode_label_color, Ncurses::COLOR_CYAN, Ncurses::COLOR_BLACK
+ c.add :search_highlight_color, Ncurses::COLOR_BLACK, Ncurses::COLOR_YELLOW, Ncurses::A_BOLD, :highlight => :search_highlight_color
end
log "initializing buffer manager"
when :redraw
bm.completely_redraw_screen
else
- bm.flash "Unknown key press '#{c.to_character}' for #{bm.focus_buf.mode.name}."
+ bm.flash "Unknown keypress '#{c.to_character}' for #{bm.focus_buf.mode.name}."
end
end
k.add :jump_to_start, "Jump to top", :home, '^', '1'
k.add :jump_to_end, "Jump to bottom", :end, '$', '0'
k.add :jump_to_left, "Jump to the left", '['
+ k.add :search_in_buffer, "Search in current buffer", '/'
+ k.add :continue_search_in_buffer, "Jump to next search occurrence in buffer", BufferManager::CONTINUE_IN_BUFFER_SEARCH_KEY
end
def initialize opts={}
@slip_rows = opts[:slip_rows] || 0 # when we pgup/pgdown,
# how many lines do we keep?
@twiddles = opts.member?(:twiddles) ? opts[:twiddles] : true
+ @search_query = nil
+ @search_line = nil
super()
end
@status = "lines #{@topline + 1}:#{@botline}/#{lines}"
end
+ def in_search?; @search_line end
+
+ def cancel_search!; @search_line = nil end
+
+ def continue_search_in_buffer
+ unless @search_query
+ BufferManager.flash "No current search!"
+ return
+ end
+
+ if(line = find_text(@search_query, @search_line || search_start_line))
+ @search_line = line + 1
+ search_goto_line line
+ buffer.mark_dirty
+ else
+ BufferManager.flash "Not found!"
+ end
+ end
+
+ def search_in_buffer
+ query = BufferManager.ask(:search, "query: ") or return
+ @search_query = Regexp.escape query
+ continue_search_in_buffer
+ end
+
+ ## subclasses can override these two!
+ def search_goto_line line; jump_to_line line end
+ def search_start_line; @topline end
+
def col_left
return unless @leftcol > 0
@leftcol -= COL_JUMP
protected
+ def find_text query, start_line
+ regex = /#{query}/i
+ (start_line ... lines).each do |i|
+ case(s = self[i])
+ when String
+ return i if s =~ regex
+ when Array
+ return i if s.any? { |color, string| string =~ regex }
+ end
+ end
+ nil
+ end
+
def draw_line ln, opts={}
+ regex = /(#{@search_query})/i
case(s = self[ln])
when String
- buffer.write ln - @topline, 0, s[@leftcol .. -1],
- :highlight => opts[:highlight]
+ if in_search?
+ draw_line_from_array ln, matching_text_array(s, regex), opts
+ else
+ draw_line_from_string ln, s, opts
+ end
when Array
- xpos = 0
+ if in_search?
+ ## seems like there ought to be a better way of doing this
+ array = []
+ s.each do |color, text|
+ if text =~ regex
+ array += matching_text_array text, regex, color
+ else
+ array << [color, text]
+ end
+ end
+ draw_line_from_array ln, array, opts
+ else
+ draw_line_from_array ln, s, opts
+ end
+ else
+ raise "unknown drawable object: #{s.inspect}" # good for debugging
+ end
## speed test
# str = s.map { |color, text| text }.join
# buffer.write ln - @topline, 0, str, :color => :none, :highlight => opts[:highlight]
# return
+ end
- s.each do |color, text|
- raise "nil text for color '#{color}'" if text.nil? # good for debugging
- if xpos + text.length < @leftcol
- buffer.write ln - @topline, 0, "", :color => color,
- :highlight => opts[:highlight]
- xpos += text.length
- elsif xpos < @leftcol
- ## partial
- buffer.write ln - @topline, 0, text[(@leftcol - xpos) .. -1],
- :color => color,
- :highlight => opts[:highlight]
- xpos += text.length
- else
- buffer.write ln - @topline, xpos - @leftcol, text,
- :color => color, :highlight => opts[:highlight]
- xpos += text.length
- end
+ def matching_text_array s, regex, oldcolor=:none
+ s.split(regex).map do |text|
+ next if text.empty?
+ if text =~ regex
+ [:search_highlight_color, text]
+ else
+ [oldcolor, text]
+ end
+ end.compact + [[oldcolor, ""]]
+ end
+ def draw_line_from_array ln, a, opts
+ xpos = 0
+ a.each do |color, text|
+ raise "nil text for color '#{color}'" if text.nil? # good for debugging
+
+ if xpos + text.length < @leftcol
+ buffer.write ln - @topline, 0, "", :color => color,
+ :highlight => opts[:highlight]
+ xpos += text.length
+ elsif xpos < @leftcol
+ ## partial
+ buffer.write ln - @topline, 0, text[(@leftcol - xpos) .. -1],
+ :color => color,
+ :highlight => opts[:highlight]
+ xpos += text.length
+ else
+ buffer.write ln - @topline, xpos - @leftcol, text,
+ :color => color, :highlight => opts[:highlight]
+ xpos += text.length
end
end
end
+
+ def draw_line_from_string ln, s, opts
+ buffer.write ln - @topline, 0, s[@leftcol .. -1], :highlight => opts[:highlight]
+ end
end
end
+