fir-repl 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/LICENSE +25 -0
- data/README.md +64 -0
- data/bin/fir +6 -0
- data/lib/fir.rb +59 -0
- data/lib/fir/cursor.rb +46 -0
- data/lib/fir/eraser.rb +23 -0
- data/lib/fir/evaluater.rb +52 -0
- data/lib/fir/history.rb +53 -0
- data/lib/fir/indent.rb +228 -0
- data/lib/fir/key.rb +24 -0
- data/lib/fir/key_command/backspace_command.rb +28 -0
- data/lib/fir/key_command/ctrl_a_command.rb +21 -0
- data/lib/fir/key_command/ctrl_c_command.rb +17 -0
- data/lib/fir/key_command/ctrl_d_command.rb +16 -0
- data/lib/fir/key_command/ctrl_e_command.rb +19 -0
- data/lib/fir/key_command/ctrl_v_command.rb +23 -0
- data/lib/fir/key_command/ctrl_z_command.rb +17 -0
- data/lib/fir/key_command/down_arrow_command.rb +17 -0
- data/lib/fir/key_command/enter_command.rb +20 -0
- data/lib/fir/key_command/key_command.rb +67 -0
- data/lib/fir/key_command/left_arrow_command.rb +19 -0
- data/lib/fir/key_command/right_arrow_command.rb +21 -0
- data/lib/fir/key_command/single_key_command.rb +23 -0
- data/lib/fir/key_command/tab_command.rb +22 -0
- data/lib/fir/key_command/up_arrow_command.rb +17 -0
- data/lib/fir/lines.rb +57 -0
- data/lib/fir/renderer.rb +65 -0
- data/lib/fir/repl_state.rb +102 -0
- data/lib/fir/screen.rb +26 -0
- data/lib/fir/screen_helper.rb +30 -0
- data/lib/fir/suggestion.rb +31 -0
- data/lib/fir/version.rb +6 -0
- metadata +76 -0
data/lib/fir/renderer.rb
ADDED
@@ -0,0 +1,65 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
# encoding: UTF-8
|
3
|
+
|
4
|
+
require_relative 'screen_helper'
|
5
|
+
|
6
|
+
class Fir
|
7
|
+
class Renderer
|
8
|
+
include ScreenHelper
|
9
|
+
attr_reader :output
|
10
|
+
|
11
|
+
def initialize(output)
|
12
|
+
@output = output
|
13
|
+
output.syswrite(line_prompt)
|
14
|
+
end
|
15
|
+
|
16
|
+
def perform(state)
|
17
|
+
output.syswrite(rendered_lines(state))
|
18
|
+
output.syswrite(rendered_cursor(state))
|
19
|
+
output.syswrite(rendered_suggestion(state)) if state.suggestion
|
20
|
+
end
|
21
|
+
|
22
|
+
def rendered_suggestion(state)
|
23
|
+
return unless state.suggestion.length.positive?
|
24
|
+
"#{state.suggestion}#{cursor_back(state.suggestion.length)}"
|
25
|
+
end
|
26
|
+
|
27
|
+
def rendered_cursor(state)
|
28
|
+
cursor = ''
|
29
|
+
if state.cursor.x != state.current_line.length
|
30
|
+
cursor = "#{cursor}#{cursor_back(state.current_line.length - state.cursor.x)}"
|
31
|
+
end
|
32
|
+
cursor
|
33
|
+
end
|
34
|
+
|
35
|
+
def rendered_lines(state)
|
36
|
+
lines_with_prompt(state)
|
37
|
+
.map(&:join)
|
38
|
+
.join("\n#{horizontal_absolute(1)}")
|
39
|
+
.concat(result_prompt(state))
|
40
|
+
end
|
41
|
+
|
42
|
+
def lines_with_prompt(state)
|
43
|
+
lines_to_render(state).map.with_index do |line, i|
|
44
|
+
prompt = state.indents[i].zero? ? '>' : '*'
|
45
|
+
[line_prompt(prompt), (' ' * state.indents[i]), line.join]
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def lines_to_render(state)
|
50
|
+
if state.executable?
|
51
|
+
state.lines[0...-1]
|
52
|
+
else
|
53
|
+
state.lines
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def result_prompt(state)
|
58
|
+
if state.executable?
|
59
|
+
"\n=> "
|
60
|
+
else
|
61
|
+
''
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,102 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
# encoding: UTF-8
|
3
|
+
|
4
|
+
require_relative 'lines'
|
5
|
+
require_relative 'cursor'
|
6
|
+
require_relative 'indent'
|
7
|
+
require_relative 'history'
|
8
|
+
require_relative 'suggestion'
|
9
|
+
|
10
|
+
class Fir
|
11
|
+
class ReplState
|
12
|
+
attr_accessor :lines, :cursor
|
13
|
+
attr_reader :indent, :repl_binding, :history
|
14
|
+
|
15
|
+
def self.blank
|
16
|
+
new(Lines.blank, Cursor.blank)
|
17
|
+
end
|
18
|
+
|
19
|
+
def initialize(
|
20
|
+
lines,
|
21
|
+
cursor,
|
22
|
+
repl_binding = TOPLEVEL_BINDING,
|
23
|
+
history = Fir::History.new
|
24
|
+
)
|
25
|
+
@lines = lines
|
26
|
+
@cursor = cursor
|
27
|
+
@repl_binding = repl_binding
|
28
|
+
@history = history
|
29
|
+
set_indent
|
30
|
+
end
|
31
|
+
|
32
|
+
def transition(command)
|
33
|
+
new_state = command.execute
|
34
|
+
new_state.set_indent
|
35
|
+
yield new_state if block_given?
|
36
|
+
return blank if new_state.executable?
|
37
|
+
new_state
|
38
|
+
end
|
39
|
+
|
40
|
+
def clone
|
41
|
+
self.class.new(
|
42
|
+
lines.clone,
|
43
|
+
cursor.clone,
|
44
|
+
repl_binding,
|
45
|
+
history
|
46
|
+
)
|
47
|
+
end
|
48
|
+
|
49
|
+
def blank
|
50
|
+
self.class.new(
|
51
|
+
Lines.blank,
|
52
|
+
Cursor.blank,
|
53
|
+
repl_binding,
|
54
|
+
history
|
55
|
+
)
|
56
|
+
end
|
57
|
+
|
58
|
+
def blank?
|
59
|
+
lines.blank? && cursor.blank?
|
60
|
+
end
|
61
|
+
|
62
|
+
def ==(other)
|
63
|
+
lines == other.lines && cursor == other.cursor
|
64
|
+
end
|
65
|
+
|
66
|
+
def current_line=(new_line)
|
67
|
+
lines[cursor.y] = new_line
|
68
|
+
end
|
69
|
+
|
70
|
+
def current_line
|
71
|
+
lines[cursor.y]
|
72
|
+
end
|
73
|
+
|
74
|
+
def indents
|
75
|
+
indent.indents
|
76
|
+
end
|
77
|
+
|
78
|
+
def executable?
|
79
|
+
indent.executable?
|
80
|
+
end
|
81
|
+
|
82
|
+
def suggestion
|
83
|
+
history.suggestion(current_line.join)
|
84
|
+
end
|
85
|
+
|
86
|
+
def commit_current_line_to_history
|
87
|
+
Fir::History.add_line_to_history_file(
|
88
|
+
current_line.join
|
89
|
+
)
|
90
|
+
end
|
91
|
+
|
92
|
+
protected
|
93
|
+
|
94
|
+
def set_indent
|
95
|
+
@indent = indent!
|
96
|
+
end
|
97
|
+
|
98
|
+
def indent!
|
99
|
+
Fir::Indent.new(lines.map(&:join)).generate
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
data/lib/fir/screen.rb
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
# encoding: UTF-8
|
3
|
+
|
4
|
+
require_relative 'eraser'
|
5
|
+
require_relative 'evaluater'
|
6
|
+
require_relative 'renderer'
|
7
|
+
|
8
|
+
class Fir
|
9
|
+
class Screen
|
10
|
+
attr_reader :eraser
|
11
|
+
attr_reader :renderer
|
12
|
+
attr_reader :evaluater
|
13
|
+
|
14
|
+
def initialize(output, error)
|
15
|
+
@eraser = Eraser.new(output)
|
16
|
+
@renderer = Renderer.new(output)
|
17
|
+
@evaluater = Evaluater.new(output, error)
|
18
|
+
end
|
19
|
+
|
20
|
+
def update(state, new_state)
|
21
|
+
eraser.perform(state)
|
22
|
+
renderer.perform(new_state)
|
23
|
+
evaluater.perform(new_state)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
# encoding: UTF-8
|
3
|
+
|
4
|
+
class Fir
|
5
|
+
module ScreenHelper
|
6
|
+
def previous_line(n)
|
7
|
+
"\e[#{n}F"
|
8
|
+
end
|
9
|
+
|
10
|
+
def next_line(n)
|
11
|
+
"\e[#{n}E"
|
12
|
+
end
|
13
|
+
|
14
|
+
def horizontal_absolute(n)
|
15
|
+
"\e[#{n}G"
|
16
|
+
end
|
17
|
+
|
18
|
+
def clear(n)
|
19
|
+
"\e[#{n}K"
|
20
|
+
end
|
21
|
+
|
22
|
+
def cursor_back(n)
|
23
|
+
"\e[#{n}D"
|
24
|
+
end
|
25
|
+
|
26
|
+
def line_prompt(prompt = '>')
|
27
|
+
"(fir)#{prompt} "
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
# encoding: UTF-8
|
3
|
+
|
4
|
+
class Fir
|
5
|
+
class Suggestion
|
6
|
+
attr_reader :line, :history
|
7
|
+
|
8
|
+
def initialize(line, history)
|
9
|
+
@line = line
|
10
|
+
@history = history
|
11
|
+
end
|
12
|
+
|
13
|
+
def generate(i)
|
14
|
+
word = suggestion(line, i)
|
15
|
+
return unless word
|
16
|
+
word[(line.length)..(word.length)]
|
17
|
+
end
|
18
|
+
|
19
|
+
def suggestion(str, i)
|
20
|
+
if str == '' && i.positive?
|
21
|
+
history[-i]
|
22
|
+
elsif str != ''
|
23
|
+
filtered_history(str)[-i]
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def filtered_history(str)
|
28
|
+
history.grep(/^#{Regexp.escape(str)}/).reverse
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
data/lib/fir/version.rb
ADDED
metadata
ADDED
@@ -0,0 +1,76 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: fir-repl
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Nassredean Nasseri
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2017-07-18 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
13
|
+
description: A Ruby REPL inspired by the Fish shell
|
14
|
+
email: dean@nasseri.io
|
15
|
+
executables:
|
16
|
+
- fir
|
17
|
+
extensions: []
|
18
|
+
extra_rdoc_files: []
|
19
|
+
files:
|
20
|
+
- LICENSE
|
21
|
+
- README.md
|
22
|
+
- bin/fir
|
23
|
+
- lib/fir.rb
|
24
|
+
- lib/fir/cursor.rb
|
25
|
+
- lib/fir/eraser.rb
|
26
|
+
- lib/fir/evaluater.rb
|
27
|
+
- lib/fir/history.rb
|
28
|
+
- lib/fir/indent.rb
|
29
|
+
- lib/fir/key.rb
|
30
|
+
- lib/fir/key_command/backspace_command.rb
|
31
|
+
- lib/fir/key_command/ctrl_a_command.rb
|
32
|
+
- lib/fir/key_command/ctrl_c_command.rb
|
33
|
+
- lib/fir/key_command/ctrl_d_command.rb
|
34
|
+
- lib/fir/key_command/ctrl_e_command.rb
|
35
|
+
- lib/fir/key_command/ctrl_v_command.rb
|
36
|
+
- lib/fir/key_command/ctrl_z_command.rb
|
37
|
+
- lib/fir/key_command/down_arrow_command.rb
|
38
|
+
- lib/fir/key_command/enter_command.rb
|
39
|
+
- lib/fir/key_command/key_command.rb
|
40
|
+
- lib/fir/key_command/left_arrow_command.rb
|
41
|
+
- lib/fir/key_command/right_arrow_command.rb
|
42
|
+
- lib/fir/key_command/single_key_command.rb
|
43
|
+
- lib/fir/key_command/tab_command.rb
|
44
|
+
- lib/fir/key_command/up_arrow_command.rb
|
45
|
+
- lib/fir/lines.rb
|
46
|
+
- lib/fir/renderer.rb
|
47
|
+
- lib/fir/repl_state.rb
|
48
|
+
- lib/fir/screen.rb
|
49
|
+
- lib/fir/screen_helper.rb
|
50
|
+
- lib/fir/suggestion.rb
|
51
|
+
- lib/fir/version.rb
|
52
|
+
homepage:
|
53
|
+
licenses:
|
54
|
+
- MIT
|
55
|
+
metadata: {}
|
56
|
+
post_install_message:
|
57
|
+
rdoc_options: []
|
58
|
+
require_paths:
|
59
|
+
- lib
|
60
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
61
|
+
requirements:
|
62
|
+
- - ">="
|
63
|
+
- !ruby/object:Gem::Version
|
64
|
+
version: '0'
|
65
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
66
|
+
requirements:
|
67
|
+
- - ">="
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '0'
|
70
|
+
requirements: []
|
71
|
+
rubyforge_project:
|
72
|
+
rubygems_version: 2.6.14
|
73
|
+
signing_key:
|
74
|
+
specification_version: 4
|
75
|
+
summary: A Ruby REPL inspired by the Fish shell
|
76
|
+
test_files: []
|