Breaking instead of out-right exiting when `Nfoiled::read!` catches an interrupt.
[nfoiled.git] / lib / nfoiled.rb
blobf23afa78f708de54a0abca717817704e74451642
1 require 'ncurses'
3 require 'nfoiled/key'
4 require 'nfoiled/terminal'
5 require 'nfoiled/window'
7 ##
8 # See `README.markdown`.
9 module Nfoiled
10   Version = 0
11   
12   class <<self
13     attr_accessor :initialized; alias_method :initialized?, :initialized
14     
15     ##
16     # This module method is responsible for setting up the entirety of Nfoiled's
17     # overall environment. It will be called before any other Nfoiled
18     # functionality is allowed. In most cases, this will be called for you.
19     # 
20     # This method also schedules `Nfoiled::finalize` to be automatically run
21     # `at_exit`.
22     def initialize!
23       self.initialized = true
24       Terminal.default = Terminal.new unless Terminal.current
25       
26       ::Ncurses.noecho # Characters will not be printed to the terminal by Ncurses for us
27       ::Ncurses.cbreak # No character processing is done, each individual character will be returned to `#getch`
28       ::Ncurses.raw    # Interrupt etc signals are all directed to us instead of handled by Ncurses
29       
30       at_exit { Nfoiled.finalize }
31     end
32     
33     ##
34     # This module method ensures that Nfoiled is initialized. It simply calls
35     # `Nfoiled::initialize!` if Nfoiled hasn't already been initialized.
36     def initialize
37       initialize! unless initialized?
38     end
39     public :initialize
40     
41     ##
42     # Causes an cycling of the physical window with the virtual window.
43     # 
44     # Warning: You have to update the virtual window first!
45     def update!
46       # We need to ensure that the current input acceptor will have the cursor
47       # at all times, so we force a refresh on it (Ncurses leaves the cursor
48       # on the last window to be updated). See `doupdate(3X)`.
49       Terminal.current.acceptor.update
50       ::Ncurses.doupdate
51     end
52     
53     ##
54     # This method is responsible for tearing down any environment set up by the
55     # `Ncurses::initialize!` method. See `endwin(3X)`.
56     def finalize!
57       self.initialized = false
58       ::Ncurses.endwin
59       Terminal.terminals.each {|t| t.destroy! }
60       Terminal.current, Terminal.default = nil
61     end
62     
63     ##
64     # This module method ensures that Nfoiled is finalize. It simply calls
65     # `Nfoiled::finalize!` if Nfoiled hasn't already been finalized.
66     def finalize
67       # TODO: Ensure finalization on fatal errors or interrupts
68       finalize! if initialized?
69     end
70     
71     ##
72     # This handles the global "input loop". Each character is processed into a
73     # `Key`, and then passed to the current input acceptor's `on_key` block
74     # (if such a block has been defined). See `getch(3X)`.
75     def read!
76       while true
77         Terminal.current.acceptor.getk do |key|
78           # TODO: This should be handled more naturally by a Key handler or something
79           break if [Key.new(:etx), Key.new(:eot)].include? key # ^C, ^D
80           Terminal.current.acceptor.on_key[key]
81         end
82       end
83     end
84   end
85   
86 end