amun 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 6430d19551a385610563d0305e205315fb57afd3
4
+ data.tar.gz: d17d801b580e7cb7207713e43f7b635167aa159d
5
+ SHA512:
6
+ metadata.gz: 33457f2a5eb0d21f8aefee6277673e9473661c78e8c471ff4627a2c3b36676a822a1af8e1d53f70918ff94ee8346c659d65baaaef8d958742a14e83e9ba11585
7
+ data.tar.gz: b7f75bb84a7875b23be10d43a3513158c1da27dccd82944a620f1ebd5b715ce852b7712b5024ca8509ad84532049ea52d652cef473498c5d924ef6f90f3b6ee9
@@ -0,0 +1,10 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ .DS_Store
@@ -0,0 +1 @@
1
+ 2.4.0
@@ -0,0 +1,5 @@
1
+ sudo: false
2
+ language: ruby
3
+ rvm:
4
+ - 2.4.0
5
+ before_install: gem install bundler -v 1.14.4
data/Gemfile ADDED
@@ -0,0 +1,2 @@
1
+ source 'https://rubygems.org'
2
+ gemspec
@@ -0,0 +1,7 @@
1
+ directories ['lib', 'test']
2
+ guard :minitest do
3
+ # with Minitest::Unit
4
+ watch(%r{^test/(.*)\/?(.*)_test\.rb$})
5
+ watch(%r{^lib/(.*/)?([^/]+)\.rb$}) { |m| "test/#{m[1]}#{m[2]}_test.rb" }
6
+ watch(%r{^test/test_helper\.rb$}) { 'test' }
7
+ end
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2017 Emad Elsaid
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
@@ -0,0 +1,31 @@
1
+ # Amun (Work in progress)
2
+
3
+ A minimal CLI text editor, built on Ruby, looking for Emacs as it's father and idol.
4
+
5
+ As developing packages for Emacs with Elisp wasn't always a fun or easy task, Starting a project that leverage ruby ability for fast development will be a good move towards
6
+ an open, easy to extend editor.
7
+
8
+ When I started this project I had 2 options, taking the VIM way or emacs way, looking in the current state of the two editors, It's obvious that emacs abbroach has a better
9
+ extensibility over VIM, emacs customizability is far superior to VIM, so building this project as a minimal and emacs-like would open the door for vim users to have their own
10
+ bindings as a package like emacs Evil mode, but doing the other way around won't help emacs users.
11
+
12
+ ## Installation
13
+
14
+ $ gem install amun
15
+
16
+ ## Usage
17
+
18
+ amun install an executable to your path, so executing `amun` from your commandline should launch amun
19
+
20
+ ## Development
21
+
22
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
23
+
24
+ ## Contributing
25
+
26
+ Bug reports and pull requests are welcome on GitHub at https://github.com/blazeeboy/amun.
27
+
28
+
29
+ ## License
30
+
31
+ The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
@@ -0,0 +1,10 @@
1
+ require "bundler/gem_tasks"
2
+ require "rake/testtask"
3
+
4
+ Rake::TestTask.new(:test) do |t|
5
+ t.libs << "test"
6
+ t.libs << "lib"
7
+ t.test_files = FileList['test/**/*_test.rb']
8
+ end
9
+
10
+ task :default => :test
@@ -0,0 +1,31 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'amun/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "amun"
8
+ spec.version = Amun::VERSION
9
+ spec.authors = ["Emad Elsaid"]
10
+ spec.email = ["blazeeboy@gmail.com"]
11
+
12
+ spec.summary = "Emacs like editor, with Ruby core instead of ELisp"
13
+ spec.description = "A CLI editor built to have an Emacs similar development environment, with ruby in the heart of it instead of Elisp, that will make developing plugins and extensions faster and more enjoyable, this editor is kept to the minimum, anything that could be written as an pluging will be found as a plugin."
14
+ spec.homepage = "http://www.github.com/blazeeboy/amun"
15
+ spec.license = "MIT"
16
+
17
+ spec.files = `git ls-files -z`.split("\x0").reject do |f|
18
+ f.match(%r{^(test|spec|features)/})
19
+ end
20
+ spec.bindir = "exe"
21
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
22
+ spec.require_paths = ["lib"]
23
+
24
+ spec.add_dependency "curses", "~> 1.2"
25
+ spec.add_development_dependency "bundler", "~> 1.14"
26
+ spec.add_development_dependency "rake", "~> 10.0"
27
+ spec.add_development_dependency "minitest", "~> 5.0"
28
+ spec.add_development_dependency "pry"
29
+ spec.add_development_dependency "guard"
30
+ spec.add_development_dependency "guard-minitest"
31
+ end
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "amun"
5
+ require "pry"
6
+
7
+ Pry.start
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $LOAD_PATH.unshift(File.dirname(File.realpath(__FILE__)) + '/../lib')
4
+
5
+ require 'amun'
6
+
7
+ Amun::Application.instance.run
@@ -0,0 +1,65 @@
1
+ require 'amun/version'
2
+ require 'amun/event_manager'
3
+ require 'amun/ui/echo_area'
4
+ require 'curses'
5
+
6
+ module Amun
7
+ module_function
8
+
9
+ class Application
10
+ attr_accessor :keyboard, :events, :echo_area
11
+
12
+ def self.instance
13
+ @instance ||= new
14
+ end
15
+
16
+ def quit(_event)
17
+ exit 0
18
+ end
19
+
20
+ def write_char(char)
21
+ screen.addstr(char.to_s)
22
+ end
23
+
24
+ def run
25
+ init_curses
26
+ init_ui
27
+
28
+ echo_area.echo 'Press ESC to exit.'
29
+
30
+ Thread.new do
31
+ while ch = screen.get_char
32
+ keyboard.trigger(ch)
33
+ echo_area.refresh
34
+ end
35
+ end.join
36
+ end
37
+
38
+ def screen
39
+ @screen ||= Curses.stdscr
40
+ end
41
+
42
+ private
43
+
44
+ def initialize(keyboard = EventManager.new, events: EventManager.new)
45
+ self.keyboard = keyboard
46
+ self.events = events
47
+
48
+ keyboard.bind "\e", self, :quit
49
+ keyboard.bind_all self, :write_char
50
+ end
51
+
52
+ def init_curses
53
+ Curses.init_screen
54
+ Curses.raw
55
+ Curses.noecho
56
+ Curses.start_color
57
+ Curses.stdscr.keypad(true)
58
+ Curses.ESCDELAY = 0
59
+ end
60
+
61
+ def init_ui
62
+ self.echo_area = Amun::UI::EchoArea.new
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,81 @@
1
+ module Amun
2
+ # = Event manager
3
+ # Stores a stack of methods to call for each event,
4
+ # when an event is triggered it executes methods in Last-In-First-Out
5
+ # if a method returned true it continue execution of the next item in stack,
6
+ # if the method returned false it will stop executing the rest of stack.
7
+ #
8
+ # == Usage
9
+ # could be used to register keyboard events, registering a set of actions to
10
+ # be executed when a key combination is pressed, the stack implementation will
11
+ # help stop execution at certain action if it needs to hijack that key.
12
+ #
13
+ # Also could be used to as instrumentation tool between modules, some modules
14
+ # register for event, and others fire it when happens, e.g *Window*
15
+ # module needs to update it's title when a file is saved, so it
16
+ # register *update_title* method to *after_file_save* event,
17
+ # when the *Buffer* module saves a file it should trigger
18
+ # that event, which executed the *update_title*.
19
+ class EventManager
20
+ def initialize
21
+ @bindings = Hash.new { |h, k| h[k] = [] }
22
+ end
23
+
24
+ # register an *objects*' *method* to be executed when the *event* is triggered
25
+ #
26
+ # event(String):: and event to bind the method to
27
+ # object(Object):: an object or class, that respond to +method+
28
+ # method(Symbol):: a method name that should be executed when the event is triggered
29
+ def bind(event, object, method)
30
+ unless object.respond_to? method
31
+ raise ArgumentError, "#{method} : is not a method for #{object}"
32
+ end
33
+
34
+ @bindings[event].unshift(object: object, method: method)
35
+ end
36
+
37
+ # remove all occurence of *method* from the *event* stack
38
+ #
39
+ # event(String):: the event name
40
+ # object(Object):: object that we #bind it's method before
41
+ # method(Symbol):: method name we #bind before
42
+ def unbind(event, object, method)
43
+ @bindings[event].delete_if do |binding|
44
+ binding[:object] == object && binding[:method] == method
45
+ end
46
+ end
47
+
48
+ # bind an object method to be executed when any event is triggered
49
+ # it uses a stack called *all* to register this method, this stack will
50
+ # be executed after the event specific stack is executed and didn't
51
+ # stop execution
52
+ def bind_all(object, method)
53
+ bind :all, object, method
54
+ end
55
+
56
+ # remove the *method* from executing after every event,
57
+ # only if you registered this method with #bind_all,
58
+ #
59
+ # this won't remove the method if it was registered with #bind
60
+ def unbind_all(object, method)
61
+ unbind :all, object, method
62
+ end
63
+
64
+ # execute *event* stack of methods in Last-In-First-Out,
65
+ # then execute methods registered
66
+ # to be executed after all events with #bind_all method
67
+ # if any method in this chain returned false, it will stop the rest
68
+ # of the stack.
69
+ def trigger(event)
70
+ trigger_for_event(event, event) && trigger_for_event(:all, event)
71
+ end
72
+
73
+ private
74
+
75
+ def trigger_for_event(stack, event)
76
+ @bindings[stack].all? do |binding|
77
+ binding[:object].send binding[:method], event
78
+ end
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,65 @@
1
+ require 'curses'
2
+
3
+ module Amun
4
+ module Helpers
5
+ ##
6
+ # Colors is responsible for registering new colors pairs (foreground and background)
7
+ # associate the pair with a name, then #use that pair for the next text printed
8
+ # on screen, also contains styles constants could be passed to #use to print bold
9
+ # or underline text for example
10
+ #
11
+ # it's important to understand that the number of pairs that coul'd be registered
12
+ # is limited to a number the current terminal specify, so registering, more color
13
+ # pairs than allowed will result in a RuntimeError.
14
+ #
15
+ # color values could be taken from the xterm-256 color schema from here:
16
+ # https://upload.wikimedia.org/wikipedia/commons/1/15/Xterm_256color_chart.svg
17
+ module Colors
18
+ module_function
19
+
20
+ ALTCHARSET = Curses::A_ALTCHARSET
21
+ COLOR = Curses::A_COLOR
22
+ LOW = Curses::A_LOW
23
+ STANDOUT = Curses::A_STANDOUT
24
+ DIM = Curses::A_DIM
25
+ NORMAL = Curses::A_NORMAL
26
+ TOP = Curses::A_TOP
27
+ BLINK = Curses::A_BLINK
28
+ HORIZONTAL = Curses::A_HORIZONTAL
29
+ PROTECT = Curses::A_PROTECT
30
+ UNDERLINE = Curses::A_UNDERLINE
31
+ BOLD = Curses::A_BOLD
32
+ INVIS = Curses::A_INVIS
33
+ REVERSE = Curses::A_REVERSE
34
+ VERTICAL = Curses::A_VERTICAL
35
+ CHARTEXT = Curses::A_CHARTEXT
36
+ LEFT = Curses::A_LEFT
37
+ RIGHT = Curses::A_RIGHT
38
+
39
+ COLORS = Hash.new { |h, k| h[k] = h.length + 1 }
40
+ private_constant :COLORS
41
+
42
+ # register or update a color pair with *foreground* and *background*
43
+ # colors, this method will raise RuntimeError if we exceeded the limit
44
+ # of color pairs allowed by the terminal
45
+ # name(Symbol):: name of pair, could be used with the #use method
46
+ # foreground(Number):: foreground color in current terminal color schema
47
+ # background(Number):: background color in current terminal color schema
48
+ def register(name, foreground, background)
49
+ if COLORS.size >= Curses.color_pairs - 1
50
+ raise "Can't register color #{name} as the colors exceeded the limit #{Curses.color_pairs}"
51
+ end
52
+
53
+ Curses.init_pair(COLORS[name], foreground, background)
54
+ end
55
+
56
+ # use color pair for the next printed text
57
+ # name(Symbol):: a color pair name registered before with #register
58
+ # type(Colors::Constant):: a text style constant defined in Colors, that manipulate the text style (Bold, Underline, Invert colors)
59
+ def use(name, type = NORMAL)
60
+ index = COLORS.key?(name) ? COLORS[name] : 0
61
+ Curses.attron(Curses.color_pair(index)| type)
62
+ end
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,26 @@
1
+ require 'curses'
2
+
3
+ module Amun
4
+ module UI
5
+ # a line that is rendered by default at the end on the screen
6
+ # takes one line height and extends to take the whole width of screen
7
+ # should be linked to \*messages\* memory buffer and each time the #log
8
+ # is called it will display the message next time #render is called
9
+ class EchoArea
10
+ def initialize
11
+ @window = Curses::Window.new(1, Curses.cols, Curses.lines - 1, 0)
12
+ end
13
+
14
+ # display a *message* in the echo area
15
+ def echo(message)
16
+ @window << message
17
+ end
18
+
19
+ # render the echo area window
20
+ def refresh
21
+ @window.noutrefresh
22
+ @window.clear
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,3 @@
1
+ module Amun
2
+ VERSION = "0.1.2"
3
+ end
metadata ADDED
@@ -0,0 +1,163 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: amun
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.2
5
+ platform: ruby
6
+ authors:
7
+ - Emad Elsaid
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2017-03-12 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: curses
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.2'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.2'
27
+ - !ruby/object:Gem::Dependency
28
+ name: bundler
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.14'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.14'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '10.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '10.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: minitest
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '5.0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '5.0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: pry
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: guard
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: guard-minitest
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ description: A CLI editor built to have an Emacs similar development environment,
112
+ with ruby in the heart of it instead of Elisp, that will make developing plugins
113
+ and extensions faster and more enjoyable, this editor is kept to the minimum, anything
114
+ that could be written as an pluging will be found as a plugin.
115
+ email:
116
+ - blazeeboy@gmail.com
117
+ executables:
118
+ - amun
119
+ extensions: []
120
+ extra_rdoc_files: []
121
+ files:
122
+ - ".gitignore"
123
+ - ".ruby-version"
124
+ - ".travis.yml"
125
+ - Gemfile
126
+ - Guardfile
127
+ - LICENSE.txt
128
+ - README.md
129
+ - Rakefile
130
+ - amun.gemspec
131
+ - bin/console
132
+ - bin/setup
133
+ - exe/amun
134
+ - lib/amun.rb
135
+ - lib/amun/event_manager.rb
136
+ - lib/amun/helpers/colors.rb
137
+ - lib/amun/ui/echo_area.rb
138
+ - lib/amun/version.rb
139
+ homepage: http://www.github.com/blazeeboy/amun
140
+ licenses:
141
+ - MIT
142
+ metadata: {}
143
+ post_install_message:
144
+ rdoc_options: []
145
+ require_paths:
146
+ - lib
147
+ required_ruby_version: !ruby/object:Gem::Requirement
148
+ requirements:
149
+ - - ">="
150
+ - !ruby/object:Gem::Version
151
+ version: '0'
152
+ required_rubygems_version: !ruby/object:Gem::Requirement
153
+ requirements:
154
+ - - ">="
155
+ - !ruby/object:Gem::Version
156
+ version: '0'
157
+ requirements: []
158
+ rubyforge_project:
159
+ rubygems_version: 2.6.10
160
+ signing_key:
161
+ specification_version: 4
162
+ summary: Emacs like editor, with Ruby core instead of ELisp
163
+ test_files: []