fir-repl 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+ # encoding: UTF-8
3
+
4
+ class Fir
5
+ class Key
6
+ attr_reader :input
7
+
8
+ def initialize(input)
9
+ @input = input
10
+ end
11
+
12
+ def get
13
+ input.raw do |raw_input|
14
+ key = raw_input.sysread(1).chr
15
+ if key == "\e"
16
+ skt = Thread.new { 2.times { key += raw_input.sysread(1).chr } }
17
+ skt.join(0.0001)
18
+ skt.kill
19
+ end
20
+ key
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+ # encoding: UTF-8
3
+
4
+ require_relative './key_command'
5
+
6
+ class Fir
7
+ class BackspaceCommand < KeyCommand
8
+ def self.character_regex
9
+ /^\177$/
10
+ end
11
+
12
+ def execute_hook(new_state)
13
+ unless state.blank?
14
+ if state.cursor.x.positive?
15
+ new_state.cursor = state.cursor.left(1)
16
+ new_line = state.current_line.clone
17
+ new_line.delete_at(state.cursor.x - 1)
18
+ new_state.current_line = new_line
19
+ elsif state.cursor.x.zero? && state.cursor.y.positive?
20
+ new_state.cursor =
21
+ state.cursor.up.right(state.lines[state.cursor.y - 1].length)
22
+ new_state.lines = state.lines.remove
23
+ end
24
+ end
25
+ new_state
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+ # encoding: UTF-8
3
+
4
+ require_relative './key_command'
5
+
6
+ class Fir
7
+ class CtrlACommand < KeyCommand
8
+ def self.character_regex
9
+ /^\x01$/
10
+ end
11
+
12
+ def execute_hook(new_state)
13
+ unless state.blank?
14
+ if state.cursor.x.positive?
15
+ new_state.cursor = state.cursor.left(state.cursor.x)
16
+ end
17
+ end
18
+ new_state
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+ # encoding: UTF-8
3
+
4
+ require_relative './key_command'
5
+
6
+ class Fir
7
+ class CtrlCCommand < KeyCommand
8
+ def self.character_regex
9
+ /^\u0003$/
10
+ end
11
+
12
+ def execute_hook(new_state)
13
+ new_state.history.reset
14
+ new_state.blank
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+ # encoding: UTF-8
3
+
4
+ require_relative './key_command'
5
+
6
+ class Fir
7
+ class CtrlDCommand < KeyCommand
8
+ def self.character_regex
9
+ /^\u0004$/
10
+ end
11
+
12
+ def execute_hook(_)
13
+ exit(0)
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+ # encoding: UTF-8
3
+
4
+ require_relative './key_command'
5
+
6
+ class Fir
7
+ class CtrlECommand < KeyCommand
8
+ def self.character_regex
9
+ /^\x05$/
10
+ end
11
+
12
+ def execute_hook(new_state)
13
+ unless state.blank?
14
+ new_state.cursor = state.cursor.right(state.current_line.length - state.cursor.x)
15
+ end
16
+ new_state
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+ # encoding: UTF-8
3
+
4
+ require_relative './key_command'
5
+
6
+ class Fir
7
+ class CtrlVCommand < KeyCommand
8
+ def self.character_regex
9
+ /^\u0016$/
10
+ end
11
+
12
+ def execute_hook(new_state)
13
+ paste_buffer = `pbpaste`
14
+ new_state.current_line = state.current_line.clone.insert(
15
+ state.cursor.x,
16
+ *paste_buffer.split('')
17
+ ).flatten
18
+ new_state.cursor = state.cursor.right(paste_buffer.length)
19
+ new_state.history.reset
20
+ new_state
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+ # encoding: UTF-8
3
+
4
+ require_relative './key_command'
5
+
6
+ class Fir
7
+ class CtrlZCommand < KeyCommand
8
+ def self.character_regex
9
+ /^\u001A$/
10
+ end
11
+
12
+ def execute_hook(new_state)
13
+ `kill -TSTP #{Process.pid}`
14
+ new_state
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+ # encoding: UTF-8
3
+
4
+ require_relative './key_command'
5
+
6
+ class Fir
7
+ class DownArrowCommand < KeyCommand
8
+ def self.character_regex
9
+ [/^\e\[B$/, /\x0E/]
10
+ end
11
+
12
+ def execute_hook(new_state)
13
+ new_state.history.down
14
+ new_state
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+ # encoding: UTF-8
3
+
4
+ require_relative './key_command'
5
+
6
+ class Fir
7
+ class EnterCommand < KeyCommand
8
+ def self.character_regex
9
+ /^\r$/
10
+ end
11
+
12
+ def execute_hook(new_state)
13
+ new_state.commit_current_line_to_history
14
+ new_state.lines = state.lines.add([])
15
+ new_state.cursor = state.cursor.down.left(state.cursor.x)
16
+ new_state.history.reset
17
+ new_state
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,67 @@
1
+ # frozen_string_literal: true
2
+ # encoding: UTF-8
3
+
4
+ class Fir
5
+ class KeyCommand
6
+ attr_reader :character
7
+ attr_reader :state
8
+
9
+ def self.build(character, state)
10
+ find(character).new(character, state)
11
+ end
12
+
13
+ def self.for(character, state)
14
+ registry.find do |candidate|
15
+ candidate.handles?(character)
16
+ end.new(character, state)
17
+ end
18
+
19
+ def self.registry
20
+ @registry ||= [KeyCommand]
21
+ end
22
+
23
+ def self.register(candidate)
24
+ registry.unshift(candidate)
25
+ end
26
+
27
+ def self.inherited(candidate)
28
+ register(candidate)
29
+ end
30
+
31
+ def self.handles?(character)
32
+ Array(character_regex).any? { |re| re.match(character) }
33
+ end
34
+
35
+ def self.character_regex
36
+ /.*/
37
+ end
38
+
39
+ def initialize(character, state)
40
+ @character = character
41
+ @state = state
42
+ end
43
+
44
+ def execute
45
+ execute_hook(state.clone)
46
+ end
47
+
48
+ def execute_hook(new_state)
49
+ new_state
50
+ end
51
+ end
52
+ end
53
+
54
+ require_relative './single_key_command'
55
+ require_relative './enter_command'
56
+ require_relative './tab_command'
57
+ require_relative './backspace_command'
58
+ require_relative './ctrl_c_command'
59
+ require_relative './ctrl_d_command'
60
+ require_relative './ctrl_z_command'
61
+ require_relative './ctrl_v_command'
62
+ require_relative './ctrl_a_command'
63
+ require_relative './ctrl_e_command'
64
+ require_relative './left_arrow_command'
65
+ require_relative './right_arrow_command'
66
+ require_relative './up_arrow_command'
67
+ require_relative './down_arrow_command'
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+ # encoding: UTF-8
3
+
4
+ require_relative './key_command'
5
+
6
+ class Fir
7
+ class LeftArrowCommand < KeyCommand
8
+ def self.character_regex
9
+ [/^\e\[D$/, /^\x02$/]
10
+ end
11
+
12
+ def execute_hook(new_state)
13
+ unless state.blank?
14
+ new_state.cursor = state.cursor.left(1) if state.cursor.x.positive?
15
+ end
16
+ new_state
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+ # encoding: UTF-8
3
+
4
+ require_relative './key_command'
5
+
6
+ class Fir
7
+ class RightArrowCommand < KeyCommand
8
+ def self.character_regex
9
+ [/^\e\[C$/, /^\x06$/]
10
+ end
11
+
12
+ def execute_hook(new_state)
13
+ unless state.blank?
14
+ if state.cursor.x < state.current_line.length
15
+ new_state.cursor = state.cursor.right(1)
16
+ end
17
+ end
18
+ new_state
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+ # encoding: UTF-8
3
+
4
+ require_relative './key_command'
5
+
6
+ class Fir
7
+ class SingleKeyCommand < KeyCommand
8
+ def self.character_regex
9
+ # Matches all printable ASCII characters
10
+ /[ -~]/
11
+ end
12
+
13
+ def execute_hook(new_state)
14
+ new_state.current_line = state.lines[-1].clone.insert(
15
+ state.cursor.x,
16
+ character
17
+ )
18
+ new_state.cursor = state.cursor.right(1)
19
+ new_state.history.reset
20
+ new_state
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+ # encoding: UTF-8
3
+
4
+ require_relative './key_command'
5
+
6
+ class Fir
7
+ class TabCommand < KeyCommand
8
+ def self.character_regex
9
+ /^\t$/
10
+ end
11
+
12
+ def execute_hook(new_state)
13
+ new_state.current_line = state.current_line.clone.insert(
14
+ state.cursor.x,
15
+ *state.suggestion.split('')
16
+ ).flatten
17
+ new_state.cursor = state.cursor.right(state.suggestion.length)
18
+ new_state.history.reset
19
+ new_state
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+ # encoding: UTF-8
3
+
4
+ require_relative './key_command'
5
+
6
+ class Fir
7
+ class UpArrowCommand < KeyCommand
8
+ def self.character_regex
9
+ [/^\e\[A$/, /\x10/]
10
+ end
11
+
12
+ def execute_hook(new_state)
13
+ new_state.history.up
14
+ new_state
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,57 @@
1
+ # frozen_string_literal: true
2
+ # encoding: UTF-8
3
+
4
+ class Fir
5
+ class Lines
6
+ include Enumerable
7
+ attr_reader :members
8
+
9
+ def initialize(*members)
10
+ @members = members
11
+ end
12
+
13
+ def self.blank
14
+ new([])
15
+ end
16
+
17
+ def blank?
18
+ @members == [[]]
19
+ end
20
+
21
+ def clone
22
+ self.class.new(*@members.clone.map(&:clone))
23
+ end
24
+
25
+ def each(&block)
26
+ @members.each(&block)
27
+ end
28
+
29
+ def [](key)
30
+ @members[key].clone
31
+ end
32
+
33
+ def []=(key, value)
34
+ @members[key] = value
35
+ end
36
+
37
+ def length
38
+ @members.length
39
+ end
40
+
41
+ def join(chr = nil)
42
+ map(&:join).join(chr)
43
+ end
44
+
45
+ def ==(other)
46
+ other.members == members
47
+ end
48
+
49
+ def add(n)
50
+ self.class.new(*(@members + [n]))
51
+ end
52
+
53
+ def remove
54
+ self.class.new(*(@members[0...-1]))
55
+ end
56
+ end
57
+ end