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.
@@ -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