amun 0.1.3 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.rspec +1 -0
- data/.rubocop.yml +6 -1
- data/.ruby-version +1 -1
- data/Guardfile +26 -6
- data/README.md +1 -0
- data/Rakefile +4 -6
- data/_config.yml +1 -0
- data/amun.gemspec +6 -5
- data/exe/amun +1 -1
- data/lib/amun/application.rb +11 -5
- data/lib/amun/behaviours/emacs.rb +14 -122
- data/lib/amun/behaviours/erasing.rb +67 -0
- data/lib/amun/behaviours/insertion.rb +22 -0
- data/lib/amun/behaviours/movement.rb +83 -0
- data/lib/amun/buffer.rb +103 -0
- data/lib/amun/event_manager.rb +12 -3
- data/lib/amun/features/echo_event.rb +4 -1
- data/lib/amun/features/files.rb +26 -0
- data/lib/amun/helpers/colors.rb +8 -7
- data/lib/amun/helpers/keyboard.rb +25 -8
- data/lib/amun/major_modes/fundamental.rb +8 -40
- data/lib/amun/major_modes/irb.rb +40 -0
- data/lib/amun/mode_line_segments/buffer_name.rb +10 -0
- data/lib/amun/mode_line_segments/major_mode.rb +11 -0
- data/lib/amun/object.rb +21 -0
- data/lib/amun/primitives/rect.rb +15 -0
- data/lib/amun/version.rb +1 -1
- data/lib/amun/windows/base.rb +42 -0
- data/lib/amun/windows/buffer_window.rb +73 -0
- data/lib/amun/windows/echo_area.rb +34 -0
- data/lib/amun/windows/frame.rb +92 -0
- data/lib/amun/windows/mini_buffer_window.rb +126 -0
- data/lib/amun/windows/mode_line.rb +50 -0
- data/lib/amun/windows/text_renderer.rb +41 -0
- metadata +56 -31
- data/lib/amun/ui/buffer.rb +0 -90
- data/lib/amun/ui/echo_area.rb +0 -42
- data/lib/amun/ui/mode_line.rb +0 -44
- data/lib/amun/ui/mode_line_segments/buffer_name.rb +0 -16
- data/lib/amun/ui/mode_line_segments/major_mode.rb +0 -17
- data/lib/amun/ui/windows/buffer_window.rb +0 -40
- data/lib/amun/ui/windows/frame.rb +0 -75
data/lib/amun/buffer.rb
ADDED
@@ -0,0 +1,103 @@
|
|
1
|
+
require 'set'
|
2
|
+
require 'amun/object'
|
3
|
+
require 'amun/event_manager'
|
4
|
+
require 'amun/major_modes/fundamental'
|
5
|
+
require 'forwardable'
|
6
|
+
|
7
|
+
module Amun
|
8
|
+
# A buffer could present any kind of IO object (File, StringIO...etc)
|
9
|
+
# also it has a major mode responsible update lines and visual lines
|
10
|
+
class Buffer < Object
|
11
|
+
extend Forwardable
|
12
|
+
attr_accessor :name, :io, :major_mode, :minor_modes
|
13
|
+
|
14
|
+
def initialize(name, io = StringIO.new)
|
15
|
+
super()
|
16
|
+
self.io = io
|
17
|
+
self.name = name
|
18
|
+
self.point = 0
|
19
|
+
self.text = ''
|
20
|
+
self.major_mode = MajorModes::Fundamental.new(self)
|
21
|
+
self.minor_modes = Set.new
|
22
|
+
end
|
23
|
+
|
24
|
+
attr_writer :point
|
25
|
+
def point
|
26
|
+
return 0 if @point.negative?
|
27
|
+
return length if @point > length
|
28
|
+
@point
|
29
|
+
end
|
30
|
+
|
31
|
+
attr_writer :mark
|
32
|
+
def mark
|
33
|
+
return nil if @mark.nil?
|
34
|
+
return 0 if @mark.negative?
|
35
|
+
return length if @mark > length
|
36
|
+
@mark
|
37
|
+
end
|
38
|
+
|
39
|
+
def trigger(event)
|
40
|
+
EventManager.join(
|
41
|
+
event,
|
42
|
+
*([events] + minor_modes.to_a + [major_mode])
|
43
|
+
)
|
44
|
+
end
|
45
|
+
|
46
|
+
# buffer should wrap the inner @text
|
47
|
+
# and expose any reading method but
|
48
|
+
# control the writing methods
|
49
|
+
|
50
|
+
def_delegators :text,
|
51
|
+
:length, :size, :[],
|
52
|
+
:count, :index, :rindex,
|
53
|
+
:empty?
|
54
|
+
|
55
|
+
def insert(index, other_str)
|
56
|
+
text.insert(index, other_str)
|
57
|
+
end
|
58
|
+
|
59
|
+
def slice!(start, length = 1)
|
60
|
+
text.slice!(start, length)
|
61
|
+
end
|
62
|
+
|
63
|
+
def <<(p1)
|
64
|
+
insert(length, p1)
|
65
|
+
end
|
66
|
+
|
67
|
+
def clear
|
68
|
+
slice!(0, length)
|
69
|
+
end
|
70
|
+
|
71
|
+
def to_s
|
72
|
+
text.dup
|
73
|
+
end
|
74
|
+
|
75
|
+
class << self
|
76
|
+
attr_writer :current, :instances
|
77
|
+
|
78
|
+
def instances
|
79
|
+
@instances ||= Set.new
|
80
|
+
end
|
81
|
+
|
82
|
+
def current
|
83
|
+
@current ||= scratch
|
84
|
+
end
|
85
|
+
|
86
|
+
def scratch
|
87
|
+
@scratch ||= new('*Scratch*')
|
88
|
+
instances << @scratch
|
89
|
+
@scratch
|
90
|
+
end
|
91
|
+
|
92
|
+
def messages
|
93
|
+
@messages ||= new('*Messages*')
|
94
|
+
instances << @messages
|
95
|
+
@messages
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
private
|
100
|
+
|
101
|
+
attr_accessor :text
|
102
|
+
end
|
103
|
+
end
|
data/lib/amun/event_manager.rb
CHANGED
@@ -44,8 +44,8 @@ module Amun
|
|
44
44
|
raise ArgumentError, "#{method} : is not a method for #{object}"
|
45
45
|
end
|
46
46
|
|
47
|
-
add_chain(event)
|
48
|
-
@bindings[event].unshift(object: object, method: method)
|
47
|
+
add_chain(event.to_s)
|
48
|
+
@bindings[event.to_s].unshift(object: object, method: method)
|
49
49
|
end
|
50
50
|
|
51
51
|
# remove all occurence of *method* from the *event* stack
|
@@ -148,6 +148,15 @@ module Amun
|
|
148
148
|
end
|
149
149
|
end
|
150
150
|
|
151
|
+
# clear the globally bound events
|
152
|
+
# if you need to reset this class to
|
153
|
+
# its default state, this method
|
154
|
+
# should clear all events and its associated
|
155
|
+
# objects/methods
|
156
|
+
def clear
|
157
|
+
@instance = nil
|
158
|
+
end
|
159
|
+
|
151
160
|
private
|
152
161
|
|
153
162
|
def instance
|
@@ -172,7 +181,7 @@ module Amun
|
|
172
181
|
|
173
182
|
def add_chain(event)
|
174
183
|
return unless event.to_s.include?(' ')
|
175
|
-
event.to_s.split(" ").inject("") do |chain, evt|
|
184
|
+
event.to_s.split(" ")[0...-1].inject("") do |chain, evt|
|
176
185
|
new_chain = (chain + " " + evt).strip
|
177
186
|
@chains << new_chain
|
178
187
|
new_chain
|
@@ -1,6 +1,9 @@
|
|
1
1
|
require 'amun/event_manager'
|
2
|
+
require 'amun/buffer'
|
2
3
|
|
3
4
|
def log(event)
|
4
|
-
|
5
|
+
# log valid strings only no control characters
|
6
|
+
event = event.encode!('UTF-8', 'UTF-8', invalid: :replace)
|
7
|
+
Amun::Buffer.messages << "#{event}\n"
|
5
8
|
end
|
6
9
|
Amun::EventManager.bind_all nil, :log
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'amun/event_manager'
|
2
|
+
require 'amun/buffer'
|
3
|
+
require 'amun/windows/mini_buffer_window'
|
4
|
+
|
5
|
+
def find_file(*)
|
6
|
+
Amun::Windows::MiniBufferWindow.new('Open file: ', Dir.pwd) do |window|
|
7
|
+
file_path = window.buffer.to_s
|
8
|
+
|
9
|
+
file_buffer = Amun::Buffer.new(file_path, File.open(file_path, 'r+'))
|
10
|
+
Amun::Buffer.instances << file_buffer
|
11
|
+
Amun::Buffer.current = file_buffer
|
12
|
+
end.attach(Amun::Application.frame)
|
13
|
+
|
14
|
+
true
|
15
|
+
end
|
16
|
+
|
17
|
+
Amun::EventManager.bind "\C-x \C-f", nil, :find_file
|
18
|
+
|
19
|
+
unless ARGV.empty?
|
20
|
+
ARGV.each do |file|
|
21
|
+
file_buffer = Amun::Buffer.new(file, File.open(file, 'r+'))
|
22
|
+
Amun::Buffer.instances << file_buffer
|
23
|
+
Amun::Buffer.current = file_buffer
|
24
|
+
Amun::Application.frame.render
|
25
|
+
end
|
26
|
+
end
|
data/lib/amun/helpers/colors.rb
CHANGED
@@ -2,6 +2,7 @@ require 'curses'
|
|
2
2
|
|
3
3
|
module Amun
|
4
4
|
module Helpers
|
5
|
+
class ColorLimitExceeded < StandardError; end
|
5
6
|
##
|
6
7
|
# Colors is responsible for registering new colors
|
7
8
|
# pairs (foreground and background)
|
@@ -52,8 +53,8 @@ module Amun
|
|
52
53
|
# foreground(Number):: foreground color in current terminal color schema
|
53
54
|
# background(Number):: background color in current terminal color schema
|
54
55
|
def register(name, foreground, background)
|
55
|
-
if COLORS.size >= Curses.color_pairs - 1
|
56
|
-
raise "Can't register color: #{name}, max: #{Curses.color_pairs}"
|
56
|
+
if !COLORS.key?(name) && COLORS.size >= Curses.color_pairs - 1
|
57
|
+
raise ColorLimitExceeded, "Can't register color: #{name}, max: #{Curses.color_pairs}"
|
57
58
|
end
|
58
59
|
|
59
60
|
Curses.init_pair(COLORS[name], foreground, background)
|
@@ -79,16 +80,16 @@ module Amun
|
|
79
80
|
# type(Colors::Constant):: a text style constant
|
80
81
|
# defined in Colors, that manipulate the text style
|
81
82
|
# (Bold, Underline, Invert colors)
|
82
|
-
def use(
|
83
|
+
def use(curses_window, name, type = NORMAL)
|
83
84
|
index = COLORS.key?(name) ? COLORS[name] : 0
|
84
|
-
|
85
|
+
curses_window.attron(Curses.color_pair(index) | type)
|
85
86
|
end
|
86
87
|
|
87
88
|
# print string in Curses window in the choosen color and style
|
88
|
-
def print(
|
89
|
+
def print(curses_window, *strings)
|
89
90
|
strings.each do |string|
|
90
|
-
use(
|
91
|
-
|
91
|
+
use(curses_window, string.color || DEFAULT_COLOR, string.style || NORMAL)
|
92
|
+
curses_window << string
|
92
93
|
end
|
93
94
|
end
|
94
95
|
end
|
@@ -2,27 +2,44 @@ require 'curses'
|
|
2
2
|
|
3
3
|
module Amun
|
4
4
|
module Helpers
|
5
|
+
# a module to deal with the keyboard
|
6
|
+
# a complementary module to curses
|
7
|
+
# doesn't intend to replace it
|
8
|
+
# it was created to overcome the shorcoming
|
9
|
+
# of getting a character + meta from the keyboard
|
10
|
+
# in the first place.
|
5
11
|
module Keyboard
|
6
12
|
module_function
|
7
13
|
|
8
14
|
TIMEOUT = 100
|
9
15
|
|
16
|
+
# get a character from the keyboard
|
17
|
+
# and make sure you detect the meta combination
|
10
18
|
def char
|
11
19
|
ch = Curses.stdscr.get_char
|
12
|
-
|
13
|
-
modified_char = Curses.stdscr.get_char if ch == "\e"
|
14
|
-
Curses.stdscr.timeout = -1
|
20
|
+
modified_character = modified_char if ch == "\e"
|
15
21
|
|
16
|
-
return ch if
|
17
|
-
return "#{ch} #{
|
18
|
-
return "#{ch} #{
|
22
|
+
return ch.to_s if modified_character.nil?
|
23
|
+
return "#{ch} #{modified_character}" if modified_character.is_a? Numeric
|
24
|
+
return "#{ch} #{modified_character}" if modified_character.length > 1
|
19
25
|
|
20
26
|
begin
|
21
|
-
eval "?\\M-#{
|
27
|
+
eval "?\\M-#{modified_character}"
|
22
28
|
rescue SyntaxError
|
23
|
-
return "#{ch} #{
|
29
|
+
return "#{ch} #{modified_character}"
|
24
30
|
end
|
25
31
|
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
module_function
|
36
|
+
|
37
|
+
def modified_char
|
38
|
+
Curses.stdscr.timeout = TIMEOUT
|
39
|
+
char = Curses.stdscr.get_char
|
40
|
+
Curses.stdscr.timeout = -1
|
41
|
+
char
|
42
|
+
end
|
26
43
|
end
|
27
44
|
end
|
28
45
|
end
|
@@ -1,51 +1,19 @@
|
|
1
|
+
require 'amun/object'
|
1
2
|
require 'amun/helpers/colors'
|
2
3
|
require 'amun/behaviours/emacs'
|
3
4
|
|
4
5
|
module Amun
|
5
6
|
module MajorModes
|
6
|
-
# Basic mode
|
7
|
-
class Fundamental
|
7
|
+
# Basic mode with emacs defaults
|
8
|
+
class Fundamental < Object
|
8
9
|
include Behaviours::Emacs
|
9
10
|
|
10
11
|
def initialize(buffer)
|
11
|
-
|
12
|
+
super()
|
13
|
+
self.buffer = buffer
|
12
14
|
|
13
|
-
|
14
|
-
|
15
|
-
emacs_behaviour_initialize(@events)
|
16
|
-
|
17
|
-
read_io if buffer.text.nil?
|
18
|
-
end
|
19
|
-
|
20
|
-
def trigger(event)
|
21
|
-
EventManager.join(event, @events)
|
22
|
-
end
|
23
|
-
|
24
|
-
def render(window)
|
25
|
-
window.clear
|
26
|
-
point = buffer.point
|
27
|
-
|
28
|
-
window << buffer.text[0...point]
|
29
|
-
window.attron(Helpers::Colors::REVERSE)
|
30
|
-
|
31
|
-
at_point = buffer.text[point]
|
32
|
-
window << (at_point == "\n" || at_point.nil? ? " \n" : at_point)
|
33
|
-
window.attroff(Helpers::Colors::REVERSE)
|
34
|
-
window << buffer.text[(point + 1)..-1]
|
35
|
-
end
|
36
|
-
|
37
|
-
def event_handler(event)
|
38
|
-
return true unless event.is_a? String
|
39
|
-
return true unless event.length == 1
|
40
|
-
return true unless event.valid_encoding?
|
41
|
-
|
42
|
-
case event
|
43
|
-
when /[^[:print:]\n\t]/
|
44
|
-
true
|
45
|
-
else
|
46
|
-
buffer.text.insert(buffer.point, event)
|
47
|
-
buffer.point += 1
|
48
|
-
end
|
15
|
+
emacs_behaviour_initialize
|
16
|
+
read_io if buffer.empty?
|
49
17
|
end
|
50
18
|
|
51
19
|
private
|
@@ -53,7 +21,7 @@ module Amun
|
|
53
21
|
attr_accessor :buffer
|
54
22
|
|
55
23
|
def read_io
|
56
|
-
buffer
|
24
|
+
buffer << buffer.io.read
|
57
25
|
end
|
58
26
|
end
|
59
27
|
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'amun/object'
|
2
|
+
require 'amun/helpers/colors'
|
3
|
+
require 'amun/behaviours/emacs'
|
4
|
+
|
5
|
+
module Amun
|
6
|
+
module MajorModes
|
7
|
+
# mode that executes the last line in
|
8
|
+
# the current environment and print the output
|
9
|
+
class IRB < Object
|
10
|
+
include Behaviours::Emacs
|
11
|
+
|
12
|
+
def initialize(buffer)
|
13
|
+
super()
|
14
|
+
self.buffer = buffer
|
15
|
+
|
16
|
+
emacs_behaviour_initialize
|
17
|
+
bind "\n", self, :execute_last_line
|
18
|
+
read_io if buffer.empty?
|
19
|
+
end
|
20
|
+
|
21
|
+
def execute_last_line(*)
|
22
|
+
last_line = buffer.lines.last
|
23
|
+
result = eval(last_line)
|
24
|
+
buffer << "\n#{result}"
|
25
|
+
rescue StandardError, SyntaxError => error
|
26
|
+
buffer << "\n#{error.inspect}\n#{error.backtrace}"
|
27
|
+
ensure
|
28
|
+
buffer.point = buffer.length
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
attr_accessor :buffer
|
34
|
+
|
35
|
+
def read_io
|
36
|
+
buffer << buffer.io.read
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
data/lib/amun/object.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'amun/event_manager'
|
2
|
+
require 'forwardable'
|
3
|
+
|
4
|
+
module Amun
|
5
|
+
# an object wrapping event manager inside it
|
6
|
+
# and exposing every method to the public
|
7
|
+
# this way you can have this object and switch
|
8
|
+
# behavior and states by switching internal event manager
|
9
|
+
# instances, for example you can have a mode that switch between
|
10
|
+
# normal and insert mode (ahem ahmed VIM style)
|
11
|
+
class Object
|
12
|
+
extend Forwardable
|
13
|
+
|
14
|
+
attr_accessor :events
|
15
|
+
def_delegators :events, :bind, :bind_all, :unbind, :unbind_all, :trigger
|
16
|
+
|
17
|
+
def initialize
|
18
|
+
@events = EventManager.new
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# a primitive class that incapsulate
|
2
|
+
# a rectangle on screen, with position
|
3
|
+
# (top, left) and size (width, height)
|
4
|
+
class Rect
|
5
|
+
attr_reader :top, :left, :width, :height
|
6
|
+
|
7
|
+
# create a rectangle with top, left, width and height
|
8
|
+
# opts(Hash):: a hash with keys (top, left, width, height)
|
9
|
+
def initialize(opts = {})
|
10
|
+
@top = opts[:top]
|
11
|
+
@left = opts[:left]
|
12
|
+
@width = opts[:width]
|
13
|
+
@height = opts[:height]
|
14
|
+
end
|
15
|
+
end
|
data/lib/amun/version.rb
CHANGED