Class: Redwood::BufferManager
- Includes:
- Singleton
- Defined in:
- lib/sup/buffer.rb
Constant Summary collapse
- CONTINUE_IN_BUFFER_SEARCH_KEY =
we have to define the key used to continue in-buffer search here, because it has special semantics that BufferManager deals with—current searches are canceled by any keypress except this one.
"n"
Instance Attribute Summary collapse
-
#focus_buf ⇒ Object
readonly
Returns the value of attribute focus_buf.
Instance Method Summary collapse
- #[](n) ⇒ Object
- #[]=(n, b) ⇒ Object
-
#ask(domain, question, default = nil, &block) ⇒ Object
for simplicitly, we always place the question at the very bottom of the screen.
- #ask_for_account(domain, question) ⇒ Object
- #ask_for_contacts(domain, question, default_contacts = []) ⇒ Object
- #ask_for_filename(domain, question, default = nil, allow_directory = false) ⇒ Object
-
#ask_for_labels(domain, question, default_labels, forbidden_labels = []) ⇒ Object
returns an array of labels.
- #ask_getch(question, accept = nil) ⇒ Object
- #ask_many_emails_with_completions(domain, question, completions, default = nil) ⇒ Object
- #ask_many_with_completions(domain, question, completions, default = nil) ⇒ Object
-
#ask_with_completions(domain, question, completions, default = nil) ⇒ Object
ask* functions.
-
#ask_yes_or_no(question) ⇒ Object
returns true (y), false (n), or nil (ctrl-g / cancel).
- #buffers ⇒ Object
-
#clear(id) ⇒ Object
a little tricky because we can’t just delete_at id because ids are relative (they’re positions into the array).
- #completely_redraw_screen ⇒ Object
- #draw_minibuf(opts = {}) ⇒ Object
- #draw_screen(opts = {}) ⇒ Object
- #erase_flash ⇒ Object
- #exists?(n) ⇒ Boolean
- #flash(s) ⇒ Object
- #focus_on(buf) ⇒ Object
- #handle_input(c) ⇒ Object
-
#initialize ⇒ BufferManager
constructor
A new instance of BufferManager.
- #kill_all_buffers ⇒ Object
- #kill_all_buffers_safely ⇒ Object
- #kill_buffer(buf) ⇒ Object
- #kill_buffer_safely(buf) ⇒ Object
- #minibuf_lines ⇒ Object
- #raise_to_front(buf) ⇒ Object
-
#resolve_input_with_keymap(c, keymap) ⇒ Object
turns an input keystroke into an action symbol.
-
#roll_buffers ⇒ Object
we reset force_to_top when rolling buffers.
- #roll_buffers_backwards ⇒ Object
- #rollable_buffers ⇒ Object
- #say(s, id = nil) ⇒ Object
- #shell_out(command) ⇒ Object
- #shelled? ⇒ Boolean
- #sigwinch_happened! ⇒ Object
- #sigwinch_happened? ⇒ Boolean
- #spawn(title, mode, opts = {}) ⇒ Object
-
#spawn_modal(title, mode, opts = {}) ⇒ Object
requires the mode to have #done? and #value methods.
-
#spawn_unless_exists(title, opts = {}) ⇒ Object
if the named buffer already exists, pops it to the front without calling the block.
Methods included from Singleton
Constructor Details
#initialize ⇒ BufferManager
Returns a new instance of BufferManager.
144 145 146 147 148 149 150 151 152 153 154 155 156 157 |
# File 'lib/sup/buffer.rb', line 144 def initialize @name_map = {} @buffers = [] @focus_buf = nil @dirty = true @minibuf_stack = [] @minibuf_mutex = Mutex.new @textfields = {} @flash = nil @shelled = @asking = false @in_x = ENV["TERM"] =~ /(xterm|rxvt|screen)/ @sigwinch_happened = false @sigwinch_mutex = Mutex.new end |
Instance Attribute Details
#focus_buf ⇒ Object (readonly)
Returns the value of attribute focus_buf.
104 105 106 |
# File 'lib/sup/buffer.rb', line 104 def focus_buf @focus_buf end |
Instance Method Details
#[](n) ⇒ Object
227 |
# File 'lib/sup/buffer.rb', line 227 def [] n; @name_map[n]; end |
#[]=(n, b) ⇒ Object
228 229 230 231 232 |
# File 'lib/sup/buffer.rb', line 228 def []= n, b raise ArgumentError, "duplicate buffer name" if b && @name_map.member?(n) raise ArgumentError, "title must be a string" unless n.is_a? String @name_map[n] = b end |
#ask(domain, question, default = nil, &block) ⇒ Object
for simplicitly, we always place the question at the very bottom of the screen
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 |
# File 'lib/sup/buffer.rb', line 535 def ask domain, question, default=nil, &block raise "impossible!" if @asking raise "Question too long" if Ncurses.cols <= question.length @asking = true @textfields[domain] ||= TextField.new tf = @textfields[domain] completion_buf = nil status, title = get_status_and_title @focus_buf Ncurses.sync do tf.activate Ncurses.stdscr, Ncurses.rows - 1, 0, Ncurses.cols, question, default, &block @dirty = true # for some reason that blanks the whole fucking screen draw_screen :sync => false, :status => status, :title => title tf.position_cursor Ncurses.refresh end while true c = Ncurses::CharCode.get next unless c.present? # getch timeout break unless tf.handle_input c # process keystroke if tf.new_completions? kill_buffer completion_buf if completion_buf shorts = tf.completions.map { |full, short| short } prefix_len = shorts.shared_prefix(caseless=true).length mode = CompletionMode.new shorts, :header => "Possible completions for \"#{tf.value}\": ", :prefix_len => prefix_len completion_buf = spawn "<completions>", mode, :height => 10 draw_screen :skip_minibuf => true tf.position_cursor elsif tf.roll_completions? completion_buf.mode.roll draw_screen :skip_minibuf => true tf.position_cursor end Ncurses.sync { Ncurses.refresh } end kill_buffer completion_buf if completion_buf @dirty = true @asking = false Ncurses.sync do tf.deactivate draw_screen :sync => false, :status => status, :title => title end tf.value.tap { |x| x } end |
#ask_for_account(domain, question) ⇒ Object
526 527 528 529 530 531 |
# File 'lib/sup/buffer.rb', line 526 def ask_for_account domain, question completions = AccountManager.user_emails answer = BufferManager.ask_many_emails_with_completions domain, question, completions, "" answer = AccountManager.default_account.email if answer == "" AccountManager.account_for Person.from_address(answer).email if answer end |
#ask_for_contacts(domain, question, default_contacts = []) ⇒ Object
509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 |
# File 'lib/sup/buffer.rb', line 509 def ask_for_contacts domain, question, default_contacts=[] default = default_contacts.is_a?(String) ? default_contacts : default_contacts.map { |s| s.to_s }.join(", ") default += " " unless default.empty? recent = Index.load_contacts(AccountManager.user_emails, :num => 10).map { |c| [c.full_address, c.email] } contacts = ContactManager.contacts.map { |c| [ContactManager.alias_for(c), c.full_address, c.email] } completions = (recent + contacts).flatten.uniq completions += HookManager.run("extra-contact-addresses") || [] answer = BufferManager.ask_many_emails_with_completions domain, question, completions, default if answer answer.split_on_commas.map { |x| ContactManager.contact_for(x) || Person.from_address(x) } end end |
#ask_for_filename(domain, question, default = nil, allow_directory = false) ⇒ Object
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 |
# File 'lib/sup/buffer.rb', line 450 def ask_for_filename domain, question, default=nil, allow_directory=false answer = ask domain, question, default do |s| if s =~ /(~([^\s\/]*))/ # twiddle directory expansion full = $1 name = $2.empty? ? Etc.getlogin : $2 dir = Etc.getpwnam(name).dir rescue nil if dir [[s.sub(full, dir), "~#{name}"]] else users.select { |u| u =~ /^#{Regexp::escape name}/u }.map do |u| [s.sub("~#{name}", "~#{u}"), "~#{u}"] end end else # regular filename completion Dir["#{s}*"].sort.map do |fn| suffix = File.directory?(fn) ? "/" : "" [fn + suffix, File.basename(fn) + suffix] end end end if answer answer = if answer.empty? spawn_modal "file browser", FileBrowserMode.new elsif File.directory?(answer) && !allow_directory spawn_modal "file browser", FileBrowserMode.new(answer) else File. answer end end answer end |
#ask_for_labels(domain, question, default_labels, forbidden_labels = []) ⇒ Object
returns an array of labels
486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 |
# File 'lib/sup/buffer.rb', line 486 def ask_for_labels domain, question, default_labels, forbidden_labels=[] default_labels = default_labels - forbidden_labels - LabelManager::RESERVED_LABELS default = default_labels.to_a.join(" ") default += " " unless default.empty? # here I would prefer to give more control and allow all_labels instead of # user_defined_labels only applyable_labels = (LabelManager.user_defined_labels - forbidden_labels).map { |l| LabelManager.string_for l }.sort_by { |s| s.downcase } answer = ask_many_with_completions domain, question, applyable_labels, default return unless answer user_labels = answer.to_set_of_symbols user_labels.each do |l| if forbidden_labels.include?(l) || LabelManager::RESERVED_LABELS.include?(l) BufferManager.flash "'#{l}' is a reserved label!" return end end user_labels end |
#ask_getch(question, accept = nil) ⇒ Object
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 |
# File 'lib/sup/buffer.rb', line 590 def ask_getch question, accept=nil raise "impossible!" if @asking accept = accept.split(//).map { |x| x.ord } if accept status, title = get_status_and_title @focus_buf Ncurses.sync do draw_screen :sync => false, :status => status, :title => title Ncurses.mvaddstr Ncurses.rows - 1, 0, question Ncurses.move Ncurses.rows - 1, question.length + 1 Ncurses.curs_set 1 Ncurses.refresh end @asking = true ret = nil done = false until done key = Ncurses::CharCode.get next if key.empty? if key.is_keycode? Ncurses::KEY_CANCEL done = true elsif accept.nil? || accept.empty? || accept.member?(key.code) ret = key done = true end end @asking = false Ncurses.sync do Ncurses.curs_set 0 draw_screen :sync => false, :status => status, :title => title end ret end |
#ask_many_emails_with_completions(domain, question, completions, default = nil) ⇒ Object
437 438 439 440 441 442 443 444 445 446 447 448 |
# File 'lib/sup/buffer.rb', line 437 def ask_many_emails_with_completions domain, question, completions, default=nil ask domain, question, default do |partial| prefix, target = partial.split_on_commas_with_remainder target ||= prefix.pop || "" target.fix_encoding! prefix = prefix.join(", ") + (prefix.empty? ? "" : ", ") prefix.fix_encoding! completions.select { |x| x =~ /^#{Regexp::escape target}/iu }.sort_by { |c| [ContactManager.contact_for(c) ? 0 : 1, c] }.map { |x| [prefix + x, x] } end end |
#ask_many_with_completions(domain, question, completions, default = nil) ⇒ Object
419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 |
# File 'lib/sup/buffer.rb', line 419 def ask_many_with_completions domain, question, completions, default=nil ask domain, question, default do |partial| prefix, target = case partial when /^\s*$/ ["", ""] when /^(.*\s+)?(.*?)$/ [$1 || "", $2] else raise "william screwed up completion: #{partial.inspect}" end prefix.fix_encoding! target.fix_encoding! completions.select { |x| x =~ /^#{Regexp::escape target}/iu }.map { |x| [prefix + x, x] } end end |
#ask_with_completions(domain, question, completions, default = nil) ⇒ Object
ask* functions. these functions display a one-line text field with a prompt at the bottom of the screen. answers typed or choosen by tab-completion
common arguments are:
domain: token used as key for @textfields, which seems to be a
dictionary of input field objects
question: string used as prompt completions: array of possible answers, that can be completed by using
the tab key
default: default value to return
412 413 414 415 416 417 |
# File 'lib/sup/buffer.rb', line 412 def ask_with_completions domain, question, completions, default=nil ask domain, question, default do |s| s.fix_encoding! completions.select { |x| x =~ /^#{Regexp::escape s}/iu }.map { |x| [x, x] } end end |
#ask_yes_or_no(question) ⇒ Object
returns true (y), false (n), or nil (ctrl-g / cancel)
628 629 630 631 632 633 634 635 636 637 |
# File 'lib/sup/buffer.rb', line 628 def ask_yes_or_no question case(r = ask_getch question, "ynYN") when ?y, ?Y true when nil nil else false end end |
#buffers ⇒ Object
169 |
# File 'lib/sup/buffer.rb', line 169 def buffers; @name_map.to_a; end |
#clear(id) ⇒ Object
a little tricky because we can’t just delete_at id because ids are relative (they’re positions into the array).
718 719 720 721 722 723 724 725 726 727 728 729 730 |
# File 'lib/sup/buffer.rb', line 718 def clear id @minibuf_mutex.synchronize do @minibuf_stack[id] = nil if id == @minibuf_stack.length - 1 id.downto(0) do |i| break if @minibuf_stack[i] @minibuf_stack.delete_at i end end end draw_screen :refresh => true end |
#completely_redraw_screen ⇒ Object
234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 |
# File 'lib/sup/buffer.rb', line 234 def completely_redraw_screen return if @shelled ## this magic makes Ncurses get the new size of the screen Ncurses.endwin Ncurses.stdscr.keypad 1 Ncurses.curs_set 0 Ncurses.refresh @sigwinch_mutex.synchronize { @sigwinch_happened = false } debug "new screen size is #{Ncurses.rows} x #{Ncurses.cols}" status, title = get_status_and_title(@focus_buf) # must be called outside of the ncurses lock Ncurses.sync do @dirty = true Ncurses.clear draw_screen :sync => false, :status => status, :title => title end end |
#draw_minibuf(opts = {}) ⇒ Object
666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 |
# File 'lib/sup/buffer.rb', line 666 def draw_minibuf opts={} m = nil @minibuf_mutex.synchronize do m = @minibuf_stack.compact m << @flash if @flash m << "" if m.empty? unless @asking # to clear it end Ncurses.mutex.lock unless opts[:sync] == false Ncurses.attrset Colormap.color_for(:text_color) adj = @asking ? 2 : 1 m.each_with_index do |s, i| Ncurses.mvaddstr Ncurses.rows - i - adj, 0, s + (" " * [Ncurses.cols - s.length, 0].max) end Ncurses.refresh if opts[:refresh] Ncurses.mutex.unlock unless opts[:sync] == false end |
#draw_screen(opts = {}) ⇒ Object
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 |
# File 'lib/sup/buffer.rb', line 254 def draw_screen opts={} return if @shelled status, title = if opts.member? :status [opts[:status], opts[:title]] else raise "status must be supplied if draw_screen is called within a sync" if opts[:sync] == false get_status_and_title @focus_buf # must be called outside of the ncurses lock end ## http://rtfm.etla.org/xterm/ctlseq.html (see Operating System Controls) print "\033]0;#{title}\07" if title && @in_x Ncurses.mutex.lock unless opts[:sync] == false ## disabling this for the time being, to help with debugging ## (currently we only have one buffer visible at a time). ## TODO: reenable this if we allow multiple buffers false && @buffers.inject(@dirty) do |dirty, buf| buf.resize Ncurses.rows - minibuf_lines, Ncurses.cols #dirty ? buf.draw : buf.redraw buf.draw status dirty end ## quick hack if true buf = @buffers.last buf.resize Ncurses.rows - minibuf_lines, Ncurses.cols @dirty ? buf.draw(status) : buf.redraw(status) end draw_minibuf :sync => false unless opts[:skip_minibuf] @dirty = false Ncurses.doupdate Ncurses.refresh if opts[:refresh] Ncurses.mutex.unlock unless opts[:sync] == false end |
#erase_flash ⇒ Object
709 |
# File 'lib/sup/buffer.rb', line 709 def erase_flash; @flash = nil; end |
#exists?(n) ⇒ Boolean
226 |
# File 'lib/sup/buffer.rb', line 226 def exists? n; @name_map.member? n; end |
#flash(s) ⇒ Object
711 712 713 714 |
# File 'lib/sup/buffer.rb', line 711 def flash s @flash = s draw_screen :refresh => true end |
#focus_on(buf) ⇒ Object
172 173 174 175 176 177 178 |
# File 'lib/sup/buffer.rb', line 172 def focus_on buf return unless @buffers.member? buf return if buf == @focus_buf @focus_buf.blur if @focus_buf @focus_buf = buf @focus_buf.focus end |
#handle_input(c) ⇒ Object
216 217 218 219 220 221 222 223 224 |
# File 'lib/sup/buffer.rb', line 216 def handle_input c if @focus_buf if @focus_buf.mode.in_search? && c != CONTINUE_IN_BUFFER_SEARCH_KEY @focus_buf.mode.cancel_search! @focus_buf.mark_dirty end @focus_buf.mode.handle_input c end end |
#kill_all_buffers ⇒ Object
381 382 383 |
# File 'lib/sup/buffer.rb', line 381 def kill_all_buffers kill_buffer @buffers.first until @buffers.empty? end |
#kill_all_buffers_safely ⇒ Object
366 367 368 369 370 371 372 373 |
# File 'lib/sup/buffer.rb', line 366 def kill_all_buffers_safely until @buffers.empty? ## inbox mode always claims it's unkillable. we'll ignore it. return false unless @buffers.last.mode.is_a?(InboxMode) || @buffers.last.mode.killable? kill_buffer @buffers.last end true end |
#kill_buffer(buf) ⇒ Object
385 386 387 388 389 390 391 392 393 394 395 396 397 398 |
# File 'lib/sup/buffer.rb', line 385 def kill_buffer buf raise ArgumentError, "buffer not on stack: #{buf}: #{buf.title.inspect}" unless @buffers.member? buf buf.mode.cleanup @buffers.delete buf @name_map.delete buf.title @focus_buf = nil if @focus_buf == buf if @buffers.empty? ## TODO: something intelligent here ## for now I will simply prohibit killing the inbox buffer. else raise_to_front @buffers.last end end |
#kill_buffer_safely(buf) ⇒ Object
375 376 377 378 379 |
# File 'lib/sup/buffer.rb', line 375 def kill_buffer_safely buf return false unless buf.mode.killable? kill_buffer buf true end |
#minibuf_lines ⇒ Object
658 659 660 661 662 663 664 |
# File 'lib/sup/buffer.rb', line 658 def minibuf_lines @minibuf_mutex.synchronize do [(@flash ? 1 : 0) + (@asking ? 1 : 0) + @minibuf_stack.compact.size, 1].max end end |
#raise_to_front(buf) ⇒ Object
180 181 182 183 184 185 186 187 188 189 |
# File 'lib/sup/buffer.rb', line 180 def raise_to_front buf @buffers.delete(buf) or return if @buffers.length > 0 && @buffers.last.force_to_top? @buffers.insert(-2, buf) else @buffers.push buf end focus_on @buffers.last @dirty = true end |
#resolve_input_with_keymap(c, keymap) ⇒ Object
turns an input keystroke into an action symbol. returns the action if found, nil if not found, and throws InputSequenceAborted if the user aborted a multi-key sequence. (Because each of those cases should be handled differently.)
this is in BufferManager because multi-key sequences require prompting.
645 646 647 648 649 650 651 652 653 654 655 656 |
# File 'lib/sup/buffer.rb', line 645 def resolve_input_with_keymap c, keymap action, text = keymap.action_for c while action.is_a? Keymap # multi-key commands, prompt key = BufferManager.ask_getch text unless key # user canceled, abort erase_flash raise InputSequenceAborted end action, text = action.action_for(key) if action.has_key?(key) end action end |
#roll_buffers ⇒ Object
we reset force_to_top when rolling buffers. this is so that the human can actually still move buffers around, while still programmatically being able to pop stuff up in the middle of drawing a window without worrying about covering it up.
if we ever start calling roll_buffers programmatically, we will have to change this. but it’s not clear that we will ever actually do that.
199 200 201 202 203 |
# File 'lib/sup/buffer.rb', line 199 def roll_buffers bufs = rollable_buffers bufs.last.force_to_top = false raise_to_front bufs.first end |
#roll_buffers_backwards ⇒ Object
205 206 207 208 209 210 |
# File 'lib/sup/buffer.rb', line 205 def roll_buffers_backwards bufs = rollable_buffers return unless bufs.length > 1 bufs.last.force_to_top = false raise_to_front bufs[bufs.length - 2] end |
#rollable_buffers ⇒ Object
212 213 214 |
# File 'lib/sup/buffer.rb', line 212 def rollable_buffers @buffers.select { |b| !(b.system? || b.hidden?) || @buffers.last == b } end |
#say(s, id = nil) ⇒ Object
684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 |
# File 'lib/sup/buffer.rb', line 684 def say s, id=nil new_id = nil @minibuf_mutex.synchronize do new_id = id.nil? id ||= @minibuf_stack.length @minibuf_stack[id] = s end if new_id draw_screen :refresh => true else draw_minibuf :refresh => true end if block_given? begin yield id ensure clear id end end id end |
#shell_out(command) ⇒ Object
732 733 734 735 736 737 738 739 740 741 742 |
# File 'lib/sup/buffer.rb', line 732 def shell_out command @shelled = true Ncurses.sync do Ncurses.endwin system command Ncurses.stdscr.keypad 1 Ncurses.refresh Ncurses.curs_set 0 end @shelled = false end |
#shelled? ⇒ Boolean
170 |
# File 'lib/sup/buffer.rb', line 170 def shelled?; @shelled; end |
#sigwinch_happened! ⇒ Object
159 160 161 162 163 164 165 |
# File 'lib/sup/buffer.rb', line 159 def sigwinch_happened! @sigwinch_mutex.synchronize do return if @sigwinch_happened @sigwinch_happened = true Ncurses.ungetch ?\C-l.ord end end |
#sigwinch_happened? ⇒ Boolean
167 |
# File 'lib/sup/buffer.rb', line 167 def sigwinch_happened?; @sigwinch_mutex.synchronize { @sigwinch_happened } end |
#spawn(title, mode, opts = {}) ⇒ Object
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 |
# File 'lib/sup/buffer.rb', line 312 def spawn title, mode, opts={} raise ArgumentError, "title must be a string" unless title.is_a? String realtitle = title num = 2 while @name_map.member? realtitle realtitle = "#{title} <#{num}>" num += 1 end width = opts[:width] || Ncurses.cols height = opts[:height] || Ncurses.rows - 1 ## since we are currently only doing multiple full-screen modes, ## use stdscr for each window. once we become more sophisticated, ## we may need to use a new Ncurses::WINDOW ## ## w = Ncurses::WINDOW.new(height, width, (opts[:top] || 0), ## (opts[:left] || 0)) w = Ncurses.stdscr b = Buffer.new w, mode, width, height, :title => realtitle, :force_to_top => opts[:force_to_top], :system => opts[:system] mode.buffer = b mode.spawned @name_map[realtitle] = b @buffers.unshift b if opts[:hidden] focus_on b unless @focus_buf else raise_to_front b end b end |
#spawn_modal(title, mode, opts = {}) ⇒ Object
requires the mode to have #done? and #value methods
346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 |
# File 'lib/sup/buffer.rb', line 346 def spawn_modal title, mode, opts={} b = spawn title, mode, opts draw_screen until mode.done? c = Ncurses::CharCode.get next unless c.present? # getch timeout break if c.is_keycode? Ncurses::KEY_CANCEL begin mode.handle_input c rescue InputSequenceAborted # do nothing end draw_screen erase_flash end kill_buffer b mode.value end |
#spawn_unless_exists(title, opts = {}) ⇒ Object
if the named buffer already exists, pops it to the front without calling the block. otherwise, gets the mode from the block and creates a new buffer. returns two things: the buffer, and a boolean indicating whether it’s a new buffer or not.
299 300 301 302 303 304 305 306 307 308 309 310 |
# File 'lib/sup/buffer.rb', line 299 def spawn_unless_exists title, opts={} new = if @name_map.member? title raise_to_front @name_map[title] unless opts[:hidden] false else mode = yield spawn title, mode, opts true end [@name_map[title], new] end |