chitin 1.0.1
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.
- data/ANNOUNCEMENT +67 -0
- data/README +414 -0
- data/TODO +32 -0
- data/bin/chitin +26 -0
- data/chitin.gemspec +31 -0
- data/chitinrc +86 -0
- data/lib/chitin/commands/builtins.rb +224 -0
- data/lib/chitin/commands/executable.rb +139 -0
- data/lib/chitin/commands/pipe.rb +112 -0
- data/lib/chitin/commands/ruby.rb +152 -0
- data/lib/chitin/commands/runnable.rb +84 -0
- data/lib/chitin/core_ext/coolline.rb +104 -0
- data/lib/chitin/core_ext/io.rb +7 -0
- data/lib/chitin/core_ext/object.rb +21 -0
- data/lib/chitin/core_ext/string.rb +35 -0
- data/lib/chitin/core_ext/symbol.rb +6 -0
- data/lib/chitin/file.rb +163 -0
- data/lib/chitin/sandbox.rb +18 -0
- data/lib/chitin/session.rb +167 -0
- data/lib/chitin/support.rb +51 -0
- data/lib/chitin/tools/csv.rb +0 -0
- data/lib/chitin/tools/replay.rb +45 -0
- data/lib/chitin/tools/string_methods.rb +10 -0
- data/lib/chitin/version.rb +4 -0
- data/lib/chitin.rb +26 -0
- data/sample.txt +187 -0
- metadata +126 -0
data/ANNOUNCEMENT
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
chitin
|
2
|
+
========================
|
3
|
+
by Ari Brown
|
4
|
+
http://bitbucket.org/seydar/chitin
|
5
|
+
|
6
|
+
Hai everybahdy
|
7
|
+
|
8
|
+
Let's talk about the shell you're using real quick. It's most likely bash. Or
|
9
|
+
at least it's bash-esque. There are a few hipsters among us who are using fish
|
10
|
+
or zsh or whatever. A few of the older persuasion are into csh and tcsh.
|
11
|
+
But that's not the point. The point is you're on a Ruby mailing list but you're
|
12
|
+
not using a Ruby shell. It's time to upgrade. It's time to upgrade your shell
|
13
|
+
to Chitin. I hope you all get the joke. I made it myself. The joke and the shell.
|
14
|
+
|
15
|
+
== So what IS Chitin?
|
16
|
+
|
17
|
+
* Chitin is a Ruby interpreter
|
18
|
+
* Turned into a shell.
|
19
|
+
|
20
|
+
Everything you type is Ruby -- remember that. So let's look at it in action:
|
21
|
+
|
22
|
+
ari: ~/src/chitin % 4 + 5
|
23
|
+
=> 9
|
24
|
+
|
25
|
+
Boom. "Show me more!" Ok, but only because you asked so nicely:
|
26
|
+
|
27
|
+
ari: ~/src/chitin % ls
|
28
|
+
ANNOUNCEMENT README TODO bin chitin-1.0.gem chitin.gemspec
|
29
|
+
chitinrc lib sample.txt
|
30
|
+
ari: ~/src/chitin % hg.stat | wc | proc {|i| i.read.size } > '/tmp/test.out'
|
31
|
+
ari: ~/src/chitin %
|
32
|
+
|
33
|
+
Holy Batman! Yeah, waddap, git on mah level. I don't even know why you'd want
|
34
|
+
to run that last command, but thar ya go.
|
35
|
+
|
36
|
+
It's supposed to replace your current shell. Now OBVIOUSLY, you're not going
|
37
|
+
to replace the entirety of the bash infrastructure that exists in computing and
|
38
|
+
has existed for like 40 years since the dinosaurs first walked the Earth, but
|
39
|
+
it's a start. It's just supposed to be for personal use.
|
40
|
+
|
41
|
+
== Why use it?
|
42
|
+
|
43
|
+
Because it's written in Ruby and supadupes easy to modify. Also:
|
44
|
+
|
45
|
+
* No need to use closing quotes. If you need a final quote in a line, don't
|
46
|
+
sweat it. Chitin will take care of that.
|
47
|
+
* Syntax highlighting while you type (thanks to Coolline!)
|
48
|
+
* You can do simple arithmatic on the command line without having to switch
|
49
|
+
interfaces (this was the original itch I had to scratch).
|
50
|
+
* The power of Ruby in a shell
|
51
|
+
* The command utility of a shell in Ruby
|
52
|
+
* No underlying shell usage
|
53
|
+
* A much more programmatic shell
|
54
|
+
* Prevents against accidental `rm -rf /usr /local/bin` like that one thing
|
55
|
+
we all saw on Reddit.
|
56
|
+
* Makes for a great Christmas present
|
57
|
+
* Text processing is SO. MUCH. EASIER.
|
58
|
+
* Great library for calling executable files from your own program without
|
59
|
+
shelling your soul or shelling out.
|
60
|
+
|
61
|
+
Anyways, I really like it and find it useful. I much prefer it over Bash. I
|
62
|
+
encourage you all to take a quick look at the README and maybe try it out
|
63
|
+
yourselves.
|
64
|
+
|
65
|
+
- Ari/seydar
|
66
|
+
ari@aribrown.com
|
67
|
+
|
data/README
ADDED
@@ -0,0 +1,414 @@
|
|
1
|
+
== Quick Intro
|
2
|
+
|
3
|
+
Rules of the road:
|
4
|
+
|
5
|
+
* Everything you enter is pure Ruby. When you type, you are typing pure Ruby.
|
6
|
+
* When in doubt of what something is: use #inspect by doing command[:inspect]
|
7
|
+
* #[] allows you to run methods of Executables, Pipes, and StringMethods
|
8
|
+
without accidentally running them.
|
9
|
+
|
10
|
+
Sample commands and shizzle:
|
11
|
+
|
12
|
+
ari: ~/src/chitin % ls
|
13
|
+
ari: ~/src/chitin % 5 + 4
|
14
|
+
ari: ~/src/chitin % ll = ls -:al
|
15
|
+
ari: ~/src/chitin % hg.stat
|
16
|
+
ari: ~/src/chitin % hg.stat | wc | L {|i| i.size }
|
17
|
+
ari: ~/src/chitin % hg.stat | wc | L {|i| i.size } > '/tmp/test.out'
|
18
|
+
ari: ~/src/chitin % 44 - 2
|
19
|
+
ari: ~/src/chitin % _ + 5
|
20
|
+
ari: ~/src/chitin % wget "http://bigbad.evils.in
|
21
|
+
ari: ~/src/chitin % _ # run the same command again
|
22
|
+
|
23
|
+
Look! Thanks to Mon_Ouie, it even has syntax highlighting on the line as you
|
24
|
+
type! Hooray! Thank you, monsieur!
|
25
|
+
|
26
|
+
For the most part, you can just use chitin as you would bash or any other
|
27
|
+
shell.
|
28
|
+
|
29
|
+
Why should you use Chitin?
|
30
|
+
|
31
|
+
* You can do simple arithmatic on the command line without having to switch
|
32
|
+
interfaces.
|
33
|
+
* The power of Ruby in a shell
|
34
|
+
* The command utility of a shell in Ruby
|
35
|
+
* No underlying shell usage
|
36
|
+
* A much more programmatic shell
|
37
|
+
* Prevents against accidental `rm -rf /usr /local/bin` like that one thing
|
38
|
+
we all saw on Reddit.
|
39
|
+
* Syntax highlighting while you type
|
40
|
+
* Makes for a great Christmas present
|
41
|
+
* Text processing is SO. MUCH. EASIER.
|
42
|
+
* Great library for calling executable files from your own program without
|
43
|
+
shelling your soul or shelling out.
|
44
|
+
|
45
|
+
== The Library
|
46
|
+
|
47
|
+
Buckle up, kids:
|
48
|
+
|
49
|
+
include Chitin
|
50
|
+
|
51
|
+
Real simply, here's how you create a reference to a file with Chitin:
|
52
|
+
|
53
|
+
f = FileObject.new "/bin/ls"
|
54
|
+
f = F "/bin/ls"
|
55
|
+
|
56
|
+
and a directory:
|
57
|
+
|
58
|
+
d = Directory.new "/bin"
|
59
|
+
d = D "/bin"
|
60
|
+
|
61
|
+
Which is sweet and all, but you kinda need read and write priveleges in order
|
62
|
+
to read and write to it. And if you're writing to /bin/ls, you're a bad person.
|
63
|
+
|
64
|
+
So we can make it an executable really easily:
|
65
|
+
|
66
|
+
f = Executable.new "/bin/ls"
|
67
|
+
|
68
|
+
By default, it reads and writes from and to, respectively, empty pipes.
|
69
|
+
So to make it work in a standard manner, we need to set it up to use STDIN,
|
70
|
+
STDOUT, and STDERR.
|
71
|
+
|
72
|
+
f.in.reopen STDIN # f.in is the input to f
|
73
|
+
f.out.reopen STDOUT # f.out is the output of f
|
74
|
+
f.err.reopen STDERR # f.err is the error of f
|
75
|
+
|
76
|
+
We can easily run this:
|
77
|
+
|
78
|
+
f.run
|
79
|
+
|
80
|
+
SWEET!
|
81
|
+
|
82
|
+
A more complicated example of "cat /tmp/cool | wc -l":
|
83
|
+
|
84
|
+
f = Executable.new "/bin/cat", "/tmp/cool"
|
85
|
+
g = Executable.new "/bin/wc", "-l"
|
86
|
+
|
87
|
+
Now we link them together (something like f | g)
|
88
|
+
|
89
|
+
g.in.reopen f.out
|
90
|
+
|
91
|
+
And make the overall input and output visible to us
|
92
|
+
|
93
|
+
f.in.reopen STDIN
|
94
|
+
g.out.reopen STDOUT
|
95
|
+
|
96
|
+
and run them
|
97
|
+
|
98
|
+
f.run # since these are asynchronous
|
99
|
+
g.run # this seems like an ok thing to do
|
100
|
+
|
101
|
+
That's a lot of work, though. Luckily, we can simplify it all:
|
102
|
+
|
103
|
+
STDIN > f | g > STDOUT
|
104
|
+
|
105
|
+
What's that? You have another function called h?
|
106
|
+
|
107
|
+
h = Executable.new "/bin/cat"
|
108
|
+
pipe = STDIN > f | g | h > STDOUT
|
109
|
+
|
110
|
+
And then you can run the pipe simply:
|
111
|
+
|
112
|
+
pipe.run
|
113
|
+
|
114
|
+
Easy peasy, right? But what if you want to run the exact same command again?
|
115
|
+
No worries:
|
116
|
+
|
117
|
+
pipe.run
|
118
|
+
|
119
|
+
It automatically resets itself internally after being run.
|
120
|
+
|
121
|
+
You can even use ruby code:
|
122
|
+
|
123
|
+
STDIN > f | gsub(/asdf/, "LAWL") > STDOUT
|
124
|
+
|
125
|
+
And you can chain it simply:
|
126
|
+
|
127
|
+
STDIN > f | gsub(/asdf/, "LAWL").chomp > STDOUT
|
128
|
+
|
129
|
+
You can even set up a pipe to return a random ruby object of your choice:
|
130
|
+
|
131
|
+
STDIN > f | split.size > STDOUT
|
132
|
+
|
133
|
+
Although you have to run it with `pipe.raw_run`.
|
134
|
+
|
135
|
+
If you have your own method and you want to take the result of something as an
|
136
|
+
input, you can use a special proc to make it happen:
|
137
|
+
|
138
|
+
STDIN > f | L {|i| my_method(i) } > STDOUT
|
139
|
+
|
140
|
+
And let's say that you want it all into a file. No problemo, broski.
|
141
|
+
|
142
|
+
STDIN > f | L {|i| my_method(i) } > '/tmp/lolwut'
|
143
|
+
|
144
|
+
Dis ish goes both ways:
|
145
|
+
|
146
|
+
'/tmp/my_input' > f | L {|i| my_method(i) } > '/tmp/lolwut'
|
147
|
+
|
148
|
+
SILENCE ALLLLLLLLLLLLLLLLLLLL
|
149
|
+
|
150
|
+
NULLIN > f | L {|i| my_method(i) } > NULLOUT > NULLERR
|
151
|
+
|
152
|
+
Git on mah level, son.
|
153
|
+
|
154
|
+
== The Shell
|
155
|
+
|
156
|
+
Chitin is such named because it is the material that comprises the exoskeleton
|
157
|
+
shells of insects. Yes, I know insects suck, but chitin is a pretty cool word,
|
158
|
+
especially when you learn that it's pronounced chitin and not chitin.
|
159
|
+
|
160
|
+
By default, chitin gives you a funky prompt that's big like yo mamma. The
|
161
|
+
reason the default prompt is so AWESOME is so that it doesn't look identical
|
162
|
+
to my bash prompt (leading me to get confused) but still provides useful
|
163
|
+
information. Before we continue our tutorial, let's change that. Add the
|
164
|
+
following bit of code to ~/.chitinrc
|
165
|
+
|
166
|
+
def prompt
|
167
|
+
"#{ENV['USER']}: #{short_pwd} % "
|
168
|
+
end
|
169
|
+
|
170
|
+
1337. Well done! You've been promoted to tenderfoot. I'm proud of you.
|
171
|
+
|
172
|
+
So now let's get going with this thang. Try out some random math equation:
|
173
|
+
|
174
|
+
ari: ~/src/chitin % 4 + 5
|
175
|
+
=> 9
|
176
|
+
ari: ~/src/chitin % (1 + 3 + 4 +65 + 7 +345) / 23
|
177
|
+
=> 18.4782608695652
|
178
|
+
|
179
|
+
NB: integer division is off by default because it sucks and always has sucked.
|
180
|
+
If I'm cranking out some quick maths, I don't want to deal with the fact that
|
181
|
+
3/4 = 0. NIQUE LA POLICE WOOT WOOT!!!!!
|
182
|
+
|
183
|
+
So ladida, you're doing some math, this could be IRB with a few changes.
|
184
|
+
HOLY BATMAN! LOOK AT THAT SHIZNIZZLE YOU JUST DID!!! Oh, you mean this bit?
|
185
|
+
|
186
|
+
ari: ~/src/chitin % ls
|
187
|
+
NOTES README TODO bin lib
|
188
|
+
|
189
|
+
Yeah, that's right. We just ran a command. And guess what? We didn't have to
|
190
|
+
start a shell underneath to get it to work! We also didn't use any system
|
191
|
+
calls because that would be hell to get right for every system. Though it
|
192
|
+
might be neat for a future version. Note to self...
|
193
|
+
|
194
|
+
But that's not all! Let's make ruby do some heavy lifting for us:
|
195
|
+
|
196
|
+
ari: ~/src/chitin % ls | L {|s| s.split }
|
197
|
+
=> ["NOTES", "README", "TODO", "bin", "lib"]
|
198
|
+
|
199
|
+
Chyeah son, it even returned us a ruby object.
|
200
|
+
|
201
|
+
What Chitin as a shell does is it automatically does the STDIN > ... > STDOUT
|
202
|
+
boilerplate that you saw in the first section. It also automagically runs your
|
203
|
+
pipe, calling #run in the general case and #raw_run if it's supposed to return
|
204
|
+
ruby.
|
205
|
+
|
206
|
+
To earn your second class rank, you need to do a few things. First, you must
|
207
|
+
demonstrate proficiency with the bowline knot and clove hitch. These are just
|
208
|
+
good life skillz. Second, you must solve a problem for "your friend Jimmy".
|
209
|
+
|
210
|
+
Jimmmy has a pokemon folder on his computer that he doesn't want his dad to see.
|
211
|
+
Unfortunately, Jimmy doesn't know about cryptography and wants to give you
|
212
|
+
(hah, as if you and Jimmy aren't the same person) a task to solve with Chitin.
|
213
|
+
Help him hide his pokemon folder from his dad who likes to cd and ls around!
|
214
|
+
|
215
|
+
ari: ~/src/chitin % ls
|
216
|
+
NOTES POKEMON README TODO bin lib
|
217
|
+
ari: ~/src/chitin % ls | L {|s| a = s.gsub /pokemon/i, "digimon"} | cat
|
218
|
+
NOTES
|
219
|
+
digimon
|
220
|
+
README
|
221
|
+
TODO
|
222
|
+
bin
|
223
|
+
lib
|
224
|
+
ari: ~/src/chitin % def ls; raw_command('/bin/ls') | L {|s| s.gsub /pokemon/i, "digimon" } | cat; end
|
225
|
+
=> nil
|
226
|
+
ari: ~/src/chitin % ls
|
227
|
+
NOTES
|
228
|
+
digimon
|
229
|
+
README
|
230
|
+
TODO
|
231
|
+
bin
|
232
|
+
lib
|
233
|
+
|
234
|
+
Save that in you ~/.chitinrc and your dad won't find out about your pokemon
|
235
|
+
collection.
|
236
|
+
|
237
|
+
Congratulations! You are now a second class scout!
|
238
|
+
|
239
|
+
Alright, hotshot. Let's see if you've got what it takes to be first class.
|
240
|
+
Your boss rolls into your office and asks to speak with you. You know it
|
241
|
+
couldn't be about your porn collection because you fixed that in attaining
|
242
|
+
second class; now he just thinks you're a nerd for having a 40GB digimon
|
243
|
+
collection. So bossman rolls in and says "Yo dawg, delete every file and folder
|
244
|
+
in a directory." Naturally, he decides not to open up a GUI and do that himself
|
245
|
+
using the wonders of modern technology (the mouse). You look that cat dead in
|
246
|
+
the eye and say "YES SIR LET'S DO DIS THANG!"
|
247
|
+
|
248
|
+
ari: ~/src/chitin % Dir['pokemon/*'].each {|f| rm f }
|
249
|
+
|
250
|
+
But since I'm a sick bastard, I showed you code that DOES NOT WORK. Before I
|
251
|
+
get into why it doesn't work, lemme show you code that DOES work, first:
|
252
|
+
|
253
|
+
ari: ~/src/chitin % Dir['pokemon/*'].map {|f| rm f}
|
254
|
+
|
255
|
+
The difference here is that we used #map instead of #each. Why?
|
256
|
+
|
257
|
+
#each is a function that returns self after running the block. Since an
|
258
|
+
executable is just a Ruby object that is only run when told to, those blocks
|
259
|
+
will never run the code you want. In order to run the code, we use #map to
|
260
|
+
return the executables we want to run in an array. Chitin knows that whenever
|
261
|
+
it sees an array of executables, its job is to execute them.
|
262
|
+
|
263
|
+
But let's get back to the original problem, which was removing a buttload of
|
264
|
+
files:
|
265
|
+
|
266
|
+
ari: ~/src/chitin % rm *Dir['pokemon/*']
|
267
|
+
|
268
|
+
The built-in Ruby * (glob) operator enables us to do batch functions as an
|
269
|
+
afterthought. It is like `rm "file1", "file2", ...`.
|
270
|
+
|
271
|
+
Sweet deal brah, you're a second class scout. To become a first class scout,
|
272
|
+
you need to install something. Luckily, Rosy the Nosy Neighbor from down the
|
273
|
+
street (guess who just watch "Trapped in the Closet" -- all fucking 23 videos)
|
274
|
+
wants you to install this C program that she wrote so she can monitor your
|
275
|
+
keystrokes. Here comes you to the rescue! OH MAN that rhymed. Time to give
|
276
|
+
up 'gramming and move to lyrical wordsmithing.
|
277
|
+
|
278
|
+
First, you gotsta download the codez:
|
279
|
+
|
280
|
+
ari: ~/src/chitin % wget "http://supersecret.com/rosys_stuff.tar.gz
|
281
|
+
|
282
|
+
Simple enough, you're just running the `wget` command. Now, unzip it to remove
|
283
|
+
it from its archived format. Use tab completion to make your life simpler! Or
|
284
|
+
not...
|
285
|
+
|
286
|
+
ari: ~/src/chitin % tar.zxf "rosys_stuff.tar.gz"
|
287
|
+
|
288
|
+
Easy there, cowboy. You have no idea what Rosy the Asshole just sent you.
|
289
|
+
Let's try it again except THIS time, use the "v" flag for "tar".
|
290
|
+
|
291
|
+
ari: ~/src/chitin % rm -:rf, "rosys_stuff
|
292
|
+
ari: ~/src/chitin % tar.zxvf "rosys_stuff.tar.gz"
|
293
|
+
|
294
|
+
So here we learned a few things about Chitin and how it plays well with 40
|
295
|
+
fucking years of bash-style syntax and history. Most obviously, -:rf takes
|
296
|
+
a symbol and translates it into '-rf'. These three are all equal:
|
297
|
+
|
298
|
+
-:rf == -'rf' == '-rf'
|
299
|
+
|
300
|
+
You want two dashes? Sweet deal brah.
|
301
|
+
|
302
|
+
--:rf == --'rf == -'-rf' == '--rf'
|
303
|
+
|
304
|
+
Next in the commands, we use tar. But we don't just run tar. We run tar.zxvf.
|
305
|
+
tar refers to the command itself, and then calling any methods on it send the
|
306
|
+
method name directly to the executable. Thus, 'tar.zxvf' becomes 'tar zxvf'. We
|
307
|
+
do this here because tar does NOT want any dashes.
|
308
|
+
|
309
|
+
So back to the installation process:
|
310
|
+
|
311
|
+
ari: ~/src/chitin % here 'configure', :prefix => '/Users/ari/local'
|
312
|
+
ari: ~/src/chitin % make & make.install
|
313
|
+
|
314
|
+
`here` is the method we use to refer to an executable file relative to the
|
315
|
+
current directory. We're using hash notation in configure to automatically
|
316
|
+
prepend two dashes to 'prefix' ('--prefix'); the whole line is translated
|
317
|
+
as "./configure --prefix /Users/ari/local". We're also using the #& operator
|
318
|
+
to do each command only if the previous one succeeds.
|
319
|
+
|
320
|
+
In lieu of using `here`, which can understandably get a little tedious, we
|
321
|
+
can do two other things:
|
322
|
+
|
323
|
+
ari: ~/src/chitin % raw_exec 'configure', :prefix => '/Users/ari/local
|
324
|
+
|
325
|
+
And if you didn't want to include any arguments:
|
326
|
+
|
327
|
+
ari: ~/src/chitin % '.'/'configure'
|
328
|
+
|
329
|
+
For the second one using String#/, it can't take any arguments because
|
330
|
+
otherwise it wouldn't be valid Ruby. I'm still trying to figure out a better
|
331
|
+
way to make use of it.
|
332
|
+
|
333
|
+
So now that we have this all, let's try archiving it all up again.
|
334
|
+
|
335
|
+
ari: ~/src/chitin % tar.zcf 'compiled.tar.gz' => 'rosys_stuff'
|
336
|
+
|
337
|
+
Much better.
|
338
|
+
|
339
|
+
== Color Guard: Working with Flags
|
340
|
+
|
341
|
+
Here's a quick synopsis of flag equivalencies from bash-style flags to Chitin.
|
342
|
+
The first on the left is the bash, and everything else is Chitin:
|
343
|
+
|
344
|
+
-h == -:h == -'h' == '-h'
|
345
|
+
-f file == :f => file
|
346
|
+
-help == -:help == -'help' == '-help'
|
347
|
+
--d == --:h == --'h' == '--h'
|
348
|
+
--pref file == :pref => file
|
349
|
+
|
350
|
+
You should be able to get the idea after that. The important things to note
|
351
|
+
are how hashes are treated. If the key is one character long, it gets one dash.
|
352
|
+
If the key is two or more characters long, it gets two dashes. This makes
|
353
|
+
dealing with Java programs really fucking annoying.
|
354
|
+
|
355
|
+
== String Methods
|
356
|
+
|
357
|
+
One of the points of using Ruby in a shell is that you can use Ruby. For
|
358
|
+
instance:
|
359
|
+
|
360
|
+
ari: ~/src/chitin % ll | split("\n")
|
361
|
+
|
362
|
+
However, what if there's an executable on your path entitled "split"? Then
|
363
|
+
the executable would be the one to be run. However, I really, really, really
|
364
|
+
want to use a few String methods such as #gsub and #split regardless of whether
|
365
|
+
there is an executable named as such. So, there's the Kernel::string_method
|
366
|
+
function that takes a string method and makes it a PRIORITY method. This means
|
367
|
+
that the Ruby method will take precedence over any executables found.
|
368
|
+
|
369
|
+
The string methods which take precedence over executables are:
|
370
|
+
|
371
|
+
gsub
|
372
|
+
split
|
373
|
+
size
|
374
|
+
pack
|
375
|
+
unpack
|
376
|
+
|
377
|
+
== Globbing: Globins and Hobglobins
|
378
|
+
|
379
|
+
Globbing is simple in Chitin: there is none. However, that's ok because
|
380
|
+
globbing is a really really cheap hack. So here's what Chitin offers in its
|
381
|
+
stead:
|
382
|
+
|
383
|
+
ari: ~/src/chitin % D('.').map {|f| echo f } # D stands for Directory
|
384
|
+
ari: ~/src/chitin % all.map {|f| echo f } # all is an alias to D('.')
|
385
|
+
ari: ~/src/chitin % echo *all # Ruby's natural glob!
|
386
|
+
|
387
|
+
Now, all and D('.') will only get the files and directories in the current
|
388
|
+
directory. What if you wanted to see just how far the rabbit hole went?
|
389
|
+
|
390
|
+
ari: ~/src/chitin % all.down.map {|f| echo f }
|
391
|
+
ari: ~/src/chitin % echo *all.down
|
392
|
+
|
393
|
+
#down will go from the directory it's called on allllll the way down to
|
394
|
+
Davey Jones' locker.
|
395
|
+
|
396
|
+
== Kewl Features
|
397
|
+
|
398
|
+
Did you know?
|
399
|
+
|
400
|
+
* A FULL RUBY INTERPRETER!
|
401
|
+
* Tab completion that respects spaces in strings!
|
402
|
+
* Bashes' ESC-. to place the last argument!
|
403
|
+
* Syntax highlighting as you type!
|
404
|
+
* ^q quotes the word just behind your cursor
|
405
|
+
* I think this train might ACTUALLY get to Chicago on time!
|
406
|
+
|
407
|
+
== Bugs
|
408
|
+
|
409
|
+
Coolline deletes and reprints the line with every character you type. This is
|
410
|
+
great! We like this because it means we get syntax highlighting as we type.
|
411
|
+
We don't like this, however, because it means that if a program prints output
|
412
|
+
without a trailing newline, the last line of the output will be cut off by
|
413
|
+
chitin as soon as you start typing :(
|
414
|
+
|
data/TODO
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
FUTURE:
|
2
|
+
* add STDERR support
|
3
|
+
* fix it so that self.err isn't alone in the whole `if self.err` bit.
|
4
|
+
* set local variables in config, have them appear in shell
|
5
|
+
* getting the menu to NOT have leading quotes
|
6
|
+
* remove/edit history
|
7
|
+
-> important for removing passwords if accidentally typed
|
8
|
+
* improve library usage of executables
|
9
|
+
* output silencing
|
10
|
+
-> learn to fake being an IO
|
11
|
+
-> shit won't work until then
|
12
|
+
* get consistent on what methods needs #[] and what methods don't
|
13
|
+
|
14
|
+
FAILURES:
|
15
|
+
* cursor display issues with the menu
|
16
|
+
-> it places the cursor at the location of the cursor on the input line
|
17
|
+
except the cursor is actually placed on the final line of the menu
|
18
|
+
(the input line is several lines above it)
|
19
|
+
* get coolline to play well with missing newlines before it
|
20
|
+
-> right now it preserves junk on the line up until the first character is
|
21
|
+
typed. once the user types something, the line is made pristine.
|
22
|
+
-> see if you can replace reset_line with something like
|
23
|
+
reset_what_was_written, deleting the prompt and the visible portion of
|
24
|
+
the line
|
25
|
+
|
26
|
+
Questions:
|
27
|
+
* Why do you have to do @line = '' in Coolline in order to not affect the
|
28
|
+
history? History calls el.dup which creates a new object. It shouldn't
|
29
|
+
matter if I do @line.clear on the original.
|
30
|
+
* Are there any ANSI codes for deleting part of a line? Yes. Duh. But what
|
31
|
+
are they?
|
32
|
+
|
data/bin/chitin
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
# fuck, this isn't my method. i don't know where i got it. please don't hate me!
|
4
|
+
def follow_link(file)
|
5
|
+
file = File.expand_path(file)
|
6
|
+
while File.symlink?(file)
|
7
|
+
file = File.expand_path(File.readlink(file), File.dirname(file))
|
8
|
+
end
|
9
|
+
file
|
10
|
+
end
|
11
|
+
|
12
|
+
require File.join(File.dirname(follow_link(__FILE__)), "..", "lib", "chitin")
|
13
|
+
|
14
|
+
FileUtils
|
15
|
+
if ARGV[0]
|
16
|
+
rc = ARGV[0]
|
17
|
+
else
|
18
|
+
FileUtils.touch File.expand_path('~/.chitinrc')
|
19
|
+
rc = File.expand_path('~/.chitinrc')
|
20
|
+
end
|
21
|
+
|
22
|
+
Chitin::Builtins.class_eval File.read(rc)
|
23
|
+
|
24
|
+
SESSION = Chitin::Session.new Chitin::Builtins
|
25
|
+
SESSION.start
|
26
|
+
|
data/chitin.gemspec
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
$:.push File.expand_path("../lib", __FILE__)
|
2
|
+
require "chitin/version"
|
3
|
+
|
4
|
+
Gem::Specification.new do |s|
|
5
|
+
# Metadata
|
6
|
+
s.name = "chitin"
|
7
|
+
s.version = Chitin::VERSION
|
8
|
+
s.authors = ["Ari Brown"]
|
9
|
+
s.email = ["ari@aribrown.com"]
|
10
|
+
s.homepage = "http://bitbucket.org/seydar/chitin"
|
11
|
+
s.summary = %q{A shell! In Ruby!}
|
12
|
+
s.description = <<DESC
|
13
|
+
The point of Chitin is that you should be able to use Ruby in your shell. Bash
|
14
|
+
is too old. Time for the new wave of shell environments.
|
15
|
+
DESC
|
16
|
+
|
17
|
+
s.rubyforge_project = "chitin"
|
18
|
+
|
19
|
+
# Manifest
|
20
|
+
s.files = `hg manifest`.split("\n")
|
21
|
+
s.executables = ["chitin"]
|
22
|
+
s.require_paths = ["lib"]
|
23
|
+
|
24
|
+
# Dependencies
|
25
|
+
# specify any dependencies here; for example:
|
26
|
+
# s.add_development_dependency "rspec"
|
27
|
+
s.add_runtime_dependency "wirble"
|
28
|
+
s.add_runtime_dependency "coolline"
|
29
|
+
s.add_runtime_dependency "coderay"
|
30
|
+
end
|
31
|
+
|
data/chitinrc
ADDED
@@ -0,0 +1,86 @@
|
|
1
|
+
###########################
|
2
|
+
# Place this in ~/.chitinrc
|
3
|
+
# This is mine. Feel free to screw with this as you please.
|
4
|
+
# - Ari Brown
|
5
|
+
###########################
|
6
|
+
include Math
|
7
|
+
|
8
|
+
module Aliases
|
9
|
+
def src; cd "#{ENV['HOME']}/src"; end
|
10
|
+
def school; cd "/Users/ari/School/Fall '11/"; end
|
11
|
+
def idea; vim '/Users/ari/src/IDEAS'; end
|
12
|
+
def ideas; less '/Users/ari/src/IDEAS'; end
|
13
|
+
def vpython(*args)
|
14
|
+
Executable.new '/Library/Frameworks/Python.framework/Versions/2.7/bin/python', *args
|
15
|
+
end
|
16
|
+
def fixit; vim '/Users/ari/.chitinrc'; end
|
17
|
+
def ouvrez(*args)
|
18
|
+
Executable.new '/usr/bin/open', *args
|
19
|
+
end
|
20
|
+
end
|
21
|
+
include Aliases
|
22
|
+
|
23
|
+
def normal_prompt
|
24
|
+
"#{ENV['USER'].cyan}: #{short_pwd.yellow} (... "
|
25
|
+
end
|
26
|
+
|
27
|
+
def prompt
|
28
|
+
normal_prompt
|
29
|
+
end
|
30
|
+
|
31
|
+
def relax
|
32
|
+
def prompt
|
33
|
+
normal_prompt
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def focus(string)
|
38
|
+
@todo = string
|
39
|
+
def prompt
|
40
|
+
@todo = @todo.to_s
|
41
|
+
"[ #{@todo.red} #{'-' * (`tput cols`.to_i - 4 - @todo.red.size)}]\n" +
|
42
|
+
"[ #{short_pwd.light_cyan} ] "
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
pre_process do |val|
|
47
|
+
val = val.strip == '.' ? 'exit' : val
|
48
|
+
val = val.strip == '..' ? 'cd ".."' : val
|
49
|
+
end
|
50
|
+
|
51
|
+
# Sample usage of pre_process and post_process.
|
52
|
+
# This is taken from the lib/chitin/commands/builtins.rb
|
53
|
+
#
|
54
|
+
# pre_process do |val|
|
55
|
+
# # if there is an unclosed string, close it and run it again.
|
56
|
+
# # smart compilers are bad... but this ain't a compiler
|
57
|
+
# #
|
58
|
+
# # option: make it ask for confirmation first
|
59
|
+
# # settable in chitinrc, perjaps?
|
60
|
+
# if (e = syntax_error_for(val)) &&
|
61
|
+
# e.message =~ /unterminated string meets end of file/
|
62
|
+
#
|
63
|
+
# if syntax_error_for(val + '\'')
|
64
|
+
# unless syntax_error_for(val + '"')
|
65
|
+
# val << '"'
|
66
|
+
# end
|
67
|
+
# else
|
68
|
+
# val << '\''
|
69
|
+
# end
|
70
|
+
#
|
71
|
+
# end
|
72
|
+
#
|
73
|
+
# val
|
74
|
+
# end
|
75
|
+
#
|
76
|
+
# # You can use error classes as a name and if the error comes up,
|
77
|
+
# # block of code will be run.
|
78
|
+
# #
|
79
|
+
# # post_process SyntaxError do |e, val|
|
80
|
+
# # # sample
|
81
|
+
# # end
|
82
|
+
#
|
83
|
+
# post_process :color do |val|
|
84
|
+
# Wirble::Colorize.colorize val
|
85
|
+
# end
|
86
|
+
|