giga 0.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/LICENSE +21 -0
- data/README.md +1 -0
- data/bin/giga +5 -0
- data/lib/giga/version.rb +3 -0
- data/lib/giga.rb +181 -0
- metadata +62 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 206803871e1829a4cbfe9cedf95d4ecd4c799bc5c5c47e9eda33289d2eade515
|
4
|
+
data.tar.gz: '03829d2857eeed92b9bbafcc6cc39d0a935e23f33abc9beb020d006d534e8eb4'
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 96efc65d1868d5739618738d4e10e6822e1c9890025d3b793a68f49ff7bf0702927f5d88f503e02aa0152ddef708c4b1a4a1d7f79d408984a6483c152290e724
|
7
|
+
data.tar.gz: e15600e66dbc3aa2cf2f5f9eaa5370a68de626b387adaaeb99e885fc87c8e42da866f1cec1cd9a0dcefe0a01bed498a21fe71a760b8297b35fb0818188fc6b66
|
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
MIT License
|
2
|
+
|
3
|
+
Copyright (c) 2020 Pierre Jambet
|
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 all
|
13
|
+
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 THE
|
21
|
+
SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
# Giga the text editor
|
data/bin/giga
ADDED
data/lib/giga/version.rb
ADDED
data/lib/giga.rb
ADDED
@@ -0,0 +1,181 @@
|
|
1
|
+
require 'termios'
|
2
|
+
|
3
|
+
module Giga
|
4
|
+
class Editor
|
5
|
+
def initialize
|
6
|
+
end
|
7
|
+
|
8
|
+
def refresh
|
9
|
+
append_buffer = ""
|
10
|
+
append_buffer << "\x1b[?25l" # Hide cursor
|
11
|
+
append_buffer << "\x1b[H"
|
12
|
+
# stderr_log @text_content
|
13
|
+
@height.times do |row_index|
|
14
|
+
|
15
|
+
if row_index >= @text_content.count
|
16
|
+
append_buffer << "~\x1b[0K\r\n"
|
17
|
+
# stderr_log("Row index: #{row_index}")
|
18
|
+
# stderr_log("Line count: #{@text_content.count}")
|
19
|
+
next
|
20
|
+
end
|
21
|
+
|
22
|
+
row = @text_content[row_index] || ""
|
23
|
+
# stderr_log "'#{row}'"
|
24
|
+
append_buffer << row
|
25
|
+
# https://notes.burke.libbey.me/ansi-escape-codes/
|
26
|
+
# https://en.wikipedia.org/wiki/ANSI_escape_code
|
27
|
+
append_buffer << "\x1b[39m" # Default foregroung color
|
28
|
+
append_buffer << "\x1b[0K" # Erase the rest of the line
|
29
|
+
append_buffer << "\r\n"
|
30
|
+
end
|
31
|
+
append_buffer.strip!
|
32
|
+
append_buffer << "\x1b[H"
|
33
|
+
x, y = @cursor_position
|
34
|
+
# x += 1 if x > 0
|
35
|
+
append_buffer << "\x1b[#{y};#{x}H"
|
36
|
+
# append_buffer << "\x1b[;1H"
|
37
|
+
append_buffer << "\x1b[?25h" # Show cursor
|
38
|
+
stderr_log("'#{append_buffer}'".inspect)
|
39
|
+
stderr_log("Cursor postition: x: #{@cursor_position[0]}, y: #{@cursor_position[1]}: #{y};#{x}H")
|
40
|
+
STDOUT.write(append_buffer)
|
41
|
+
end
|
42
|
+
|
43
|
+
def current_row
|
44
|
+
@text_content[@cursor_position[1] - 1]
|
45
|
+
end
|
46
|
+
|
47
|
+
def stderr_log(message)
|
48
|
+
unless STDERR.tty? # true when not redirecting to a file, a little janky but works for what I want
|
49
|
+
STDERR.puts(message)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def start
|
54
|
+
s = [0, 0, 0, 0].pack("S_S_S_S_")
|
55
|
+
STDOUT.ioctl(Termios::TIOCGWINSZ, s)
|
56
|
+
|
57
|
+
@height, @WIDTH, _, _ = s.unpack("S_S_S_S_")
|
58
|
+
|
59
|
+
# Raw mode
|
60
|
+
current = Termios.tcgetattr(STDIN)
|
61
|
+
t = current.dup
|
62
|
+
t.c_iflag &= ~(Termios::BRKINT | Termios::ICRNL | Termios::INPCK | Termios::ISTRIP | Termios::IXON)
|
63
|
+
t.c_oflag &= ~(Termios::OPOST)
|
64
|
+
t.c_cflag |= (Termios::CS8)
|
65
|
+
t.c_lflag &= ~(Termios::ECHO | Termios::ICANON | Termios::IEXTEN | Termios::ISIG)
|
66
|
+
t.c_cc[Termios::VMIN] = 1 # Setting 0 as in Kilo raises EOF errors
|
67
|
+
Termios.tcsetattr(STDIN, Termios::TCSANOW, t)
|
68
|
+
|
69
|
+
trap("INT") {
|
70
|
+
Termios.tcsetattr(STDIN, Termios::TCSANOW, current)
|
71
|
+
exit(0)
|
72
|
+
}
|
73
|
+
|
74
|
+
@text_content = [""]
|
75
|
+
@cursor_position = [1, 1]
|
76
|
+
|
77
|
+
loop do
|
78
|
+
refresh
|
79
|
+
c = STDIN.readpartial(1)
|
80
|
+
if c == "q"
|
81
|
+
Process.kill("INT", Process.pid)
|
82
|
+
end
|
83
|
+
# stderr_log("ord: #{c.ord}")
|
84
|
+
if c.ord == 13 # enter
|
85
|
+
if current_row && current_row.length > (@cursor_position[0] - 1)
|
86
|
+
carry = current_row[(@cursor_position[0] - 1)..-1]
|
87
|
+
current_row.slice!((@cursor_position[0] - 1)..-1)
|
88
|
+
else
|
89
|
+
carry = ""
|
90
|
+
end
|
91
|
+
if @cursor_position[1] - 1 == @text_content.length # We're on a new line at the end
|
92
|
+
new_line_index = @cursor_position[1] - 1
|
93
|
+
else
|
94
|
+
new_line_index = @cursor_position[1]
|
95
|
+
end
|
96
|
+
@text_content.insert(new_line_index, carry)
|
97
|
+
@cursor_position[0] = 1
|
98
|
+
@cursor_position[1] += 1
|
99
|
+
elsif c.ord == 127 # backspace
|
100
|
+
next if @cursor_position[0] == 1 && @cursor_position[1] == 1
|
101
|
+
|
102
|
+
if @cursor_position[0] == 1
|
103
|
+
if current_row.nil?
|
104
|
+
@text_content.delete_at(@cursor_position[1] - 1)
|
105
|
+
@cursor_position[1] -= 1
|
106
|
+
@cursor_position[0] = current_row.length + 1
|
107
|
+
elsif current_row.empty?
|
108
|
+
@text_content.delete_at(@cursor_position[1] - 1)
|
109
|
+
@cursor_position[1] -= 1
|
110
|
+
@cursor_position[0] = current_row.length + 1
|
111
|
+
else
|
112
|
+
previous_row = @text_content[@cursor_position[1] - 2]
|
113
|
+
@cursor_position[0] = previous_row.length + 1
|
114
|
+
@text_content[@cursor_position[1] - 2] = previous_row + current_row
|
115
|
+
@text_content.delete_at(@cursor_position[1] - 1)
|
116
|
+
@cursor_position[1] -= 1
|
117
|
+
end
|
118
|
+
else
|
119
|
+
deletion_index = @cursor_position[0] - 2
|
120
|
+
current_row.slice!(deletion_index)
|
121
|
+
@cursor_position[0] -= 1
|
122
|
+
end
|
123
|
+
elsif c.ord == 27 # ESC
|
124
|
+
second_char = STDIN.read_nonblock(1, exception: false)
|
125
|
+
next if second_char == :wait_readable
|
126
|
+
|
127
|
+
third_char = STDIN.read_nonblock(1, exception: false)
|
128
|
+
next if third_char == :wait_readable
|
129
|
+
|
130
|
+
if second_char == "["
|
131
|
+
case third_char
|
132
|
+
when "A" # Up
|
133
|
+
@cursor_position[1] -= 1 unless @cursor_position[1] == 1
|
134
|
+
if current_row && @cursor_position[0] > current_row.length + 1
|
135
|
+
@cursor_position[0] = current_row.length + 1
|
136
|
+
end
|
137
|
+
when "B" # Down
|
138
|
+
if @cursor_position[1] == @text_content.length
|
139
|
+
@cursor_position[0] = 1
|
140
|
+
end
|
141
|
+
@cursor_position[1] += 1 unless @cursor_position[1] == @text_content.length + 1
|
142
|
+
if current_row && @cursor_position[0] > current_row.length + 1
|
143
|
+
@cursor_position[0] = current_row.length + 1
|
144
|
+
end
|
145
|
+
when "C" # Right
|
146
|
+
# stderr_log("Current row: #{current_row}\n")
|
147
|
+
if current_row && @cursor_position[0] > current_row.length
|
148
|
+
if @cursor_position[1] <= @text_content.length + 1
|
149
|
+
@cursor_position[0] = 1
|
150
|
+
@cursor_position[1] += 1
|
151
|
+
end
|
152
|
+
elsif current_row
|
153
|
+
@cursor_position[0] += 1
|
154
|
+
end
|
155
|
+
when "D" # Left
|
156
|
+
if @cursor_position[0] == 1
|
157
|
+
if @cursor_position[1] > 1
|
158
|
+
@cursor_position[1] -= 1
|
159
|
+
@cursor_position[0] = current_row.length + 1
|
160
|
+
end
|
161
|
+
else
|
162
|
+
@cursor_position[0] -= 1
|
163
|
+
end
|
164
|
+
when "H" then "H" # Home
|
165
|
+
when "F" then "F" # End
|
166
|
+
end
|
167
|
+
end
|
168
|
+
# @text_content.last << third_char
|
169
|
+
elsif c.ord >= 32 && c.ord <= 126
|
170
|
+
if current_row.nil?
|
171
|
+
@text_content << ""
|
172
|
+
end
|
173
|
+
current_row.insert(@cursor_position[0] - 1, c)
|
174
|
+
@cursor_position[0] += 1
|
175
|
+
else
|
176
|
+
stderr_log("Ignored char: #{c.ord}")
|
177
|
+
end
|
178
|
+
end
|
179
|
+
end
|
180
|
+
end
|
181
|
+
end
|
metadata
ADDED
@@ -0,0 +1,62 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: giga
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Pierre Jambet
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2022-08-25 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: ruby-termios
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 1.1.0
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 1.1.0
|
27
|
+
description: A console text editor, built pretty much from scratch
|
28
|
+
email: hello@pjam.me
|
29
|
+
executables:
|
30
|
+
- giga
|
31
|
+
extensions: []
|
32
|
+
extra_rdoc_files: []
|
33
|
+
files:
|
34
|
+
- LICENSE
|
35
|
+
- README.md
|
36
|
+
- bin/giga
|
37
|
+
- lib/giga.rb
|
38
|
+
- lib/giga/version.rb
|
39
|
+
homepage: https://rubygems.org/gems/giga
|
40
|
+
licenses:
|
41
|
+
- MIT
|
42
|
+
metadata: {}
|
43
|
+
post_install_message:
|
44
|
+
rdoc_options: []
|
45
|
+
require_paths:
|
46
|
+
- lib
|
47
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
48
|
+
requirements:
|
49
|
+
- - ">="
|
50
|
+
- !ruby/object:Gem::Version
|
51
|
+
version: '0'
|
52
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
53
|
+
requirements:
|
54
|
+
- - ">="
|
55
|
+
- !ruby/object:Gem::Version
|
56
|
+
version: '0'
|
57
|
+
requirements: []
|
58
|
+
rubygems_version: 3.3.7
|
59
|
+
signing_key:
|
60
|
+
specification_version: 4
|
61
|
+
summary: A console text editor, pretty much copied from antirez/kilo
|
62
|
+
test_files: []
|