t-rex 1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (3) hide show
  1. checksums.yaml +7 -0
  2. data/bin/t-rex.rb +880 -0
  3. metadata +46 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 143864da2a29ae4092854380494bda71487b16dc863c2a27fda2195c2ec9ca87
4
+ data.tar.gz: 13669428e6255bde5c076069156b275d313b71d3814f8f6d2c6b714b7fbd57c3
5
+ SHA512:
6
+ metadata.gz: 5126c19c705d819912dab5b5805c075f4ebb95824c912ea70d3296dbc4d2de7ac8876f441f266987eb55f2a5241b7ed1a66e417f9b73220505033e5aef6c2499
7
+ data.tar.gz: 4893863c9a2d9ebc4d6fcd989e67706f67951815758681e4b4597bd7f10370f51ee5f916dac10aa47eadcb9dd07401388b40e370c636fbc26ff335bb8b726ade
data/bin/t-rex.rb ADDED
@@ -0,0 +1,880 @@
1
+ #!/usr/bin/env ruby
2
+ # encoding: utf-8
3
+
4
+ require 'io/console'
5
+ require 'curses'
6
+ include Curses
7
+
8
+ # CLASSES
9
+ class Curses::Window # CLASS EXTENSION
10
+ # General extensions (see https://github.com/isene/Ruby-Curses-Class-Extension)
11
+ attr_accessor :color, :fg, :bg, :attr
12
+ # Set self.color for an already defined color pair such as: init_pair(1, 255, 3)
13
+ # The color pair is defined like this: init_pair(index, foreground, background)
14
+ # self.fg is set for the foreground color (and is used if self.color is not set)
15
+ # self.bg is set for the background color (and is used if self.color is not set)
16
+ # self.attr is set for text attributes like Curses::A_BOLD
17
+ def clr # Clears the whole window
18
+ self.setpos(0, 0)
19
+ self.maxy.times {self.deleteln()}
20
+ self.refresh
21
+ self.setpos(0, 0)
22
+ end
23
+ def fill # Fill window with color as set by self.color (or self.bg if not set)
24
+ self.setpos(0, 0)
25
+ self.fill_from_cur_pos
26
+ end
27
+ def fill_from_cur_pos # Fills the rest of the window from current line
28
+ x = curx
29
+ y = cury
30
+ self.setpos(y, 0)
31
+ blank = " " * self.maxx
32
+ if self.color == nil
33
+ self.bg = 0 if self.bg == nil
34
+ self.fg = 255 if self.fg == nil
35
+ init_pair(self.fg, self.fg, self.bg)
36
+ self.maxy.times {self.attron(color_pair(self.fg)) {self << blank}}
37
+ else
38
+ self.maxy.times {self.attron(color_pair(self.color)) {self << blank}}
39
+ end
40
+ self.refresh
41
+ self.setpos(y, x)
42
+ end
43
+ def fill_to_cur_pos # Fills the window up to current line
44
+ x = curx
45
+ y = cury
46
+ self.setpos(0, 0)
47
+ blank = " " * self.maxx
48
+ if self.color == nil
49
+ self.bg = 0 if self.bg == nil
50
+ self.fg = 255 if self.fg == nil
51
+ init_pair(self.fg, self.fg, self.bg)
52
+ y.times {self.attron(color_pair(self.fg)) {self << blank}}
53
+ else
54
+ y.times {self.attron(color_pair(self.color)) {self << blank}}
55
+ end
56
+ self.refresh
57
+ self.setpos(y, x)
58
+ end
59
+ def p(text) # Puts text to window
60
+ self.attr = 0 if self.attr == nil
61
+ if self.color == nil
62
+ self.bg = 0 if self.bg == nil
63
+ self.fg = 255 if self.fg == nil
64
+ init_pair(self.fg, self.fg, self.bg)
65
+ self.attron(color_pair(self.fg) | self.attr) { self << text }
66
+ else
67
+ self.attron(color_pair(self.color) | self.attr) { self << text }
68
+ end
69
+ self.refresh
70
+ end
71
+ end
72
+ class Stack
73
+ attr_accessor :x, :y, :z, :t, :l, :deg
74
+
75
+ def initialize(x, y, z, t, l)
76
+ self.x = x.to_f
77
+ self.y = y.to_f
78
+ self.z = z.to_f
79
+ self.t = t.to_f
80
+ self.l = l.to_f
81
+ end
82
+ def lift
83
+ self.y, self.z, self.t = self.x, self.y, self.z
84
+ end
85
+ def drop
86
+ self.y, self.z = self.z, self.t
87
+ end
88
+ def rdn
89
+ self.x, self.y, self.z, self.t = self.y, self.z, self.t, self.x
90
+ end
91
+ def rup
92
+ self.x, self.y, self.z, self.t = self.t, self.x, self.y, self.z
93
+ end
94
+ def xy
95
+ self.x, self.y = self.y, self.x
96
+ end
97
+ def add
98
+ self.l = self.x
99
+ self.x = self.y + self.x
100
+ self.drop
101
+ end
102
+ def subtract
103
+ self.l = self.x
104
+ self.x = self.y - self.x
105
+ self.drop
106
+ end
107
+ def multiply
108
+ self.l = self.x
109
+ self.x = self.y * self.x
110
+ self.drop
111
+ end
112
+ def divide
113
+ begin
114
+ throw if self.x == 0
115
+ self.l = self.x
116
+ self.x = self.y / self.x
117
+ self.drop
118
+ rescue
119
+ return "Error"
120
+ end
121
+ end
122
+ def mod
123
+ begin
124
+ throw if self.x == 0
125
+ self.l = self.x
126
+ self.x = self.y % self.x
127
+ self.drop
128
+ rescue
129
+ return "Error"
130
+ end
131
+ end
132
+ def percent
133
+ begin
134
+ throw if self.y == 0
135
+ self.l = self.x
136
+ self.x = 100*(self.x / self.y)
137
+ self.drop
138
+ rescue
139
+ return "Error"
140
+ end
141
+ end
142
+ def chs
143
+ self.x = -self.x
144
+ end
145
+ def pi
146
+ self.l = self.x
147
+ self.lift
148
+ self.x = Math::PI
149
+ end
150
+ def pow
151
+ self.l = self.x
152
+ self.x = self.y ** self.x
153
+ self.drop
154
+ end
155
+ def root
156
+ begin
157
+ self.l = self.x
158
+ self.x = self.y ** (1 / self.x)
159
+ self.drop
160
+ rescue
161
+ return "Error"
162
+ end
163
+ end
164
+ def recip
165
+ begin
166
+ throw if self.x == 0
167
+ self.l = self.x
168
+ self.x = 1 / self.x
169
+ rescue
170
+ return "Error"
171
+ end
172
+ end
173
+ def sqr
174
+ self.l = self.x
175
+ self.x = self.x ** 2
176
+ end
177
+ def sqrt
178
+ self.l = self.x
179
+ begin
180
+ self.x = Math::sqrt(self.x)
181
+ rescue
182
+ return "Error"
183
+ end
184
+ end
185
+ def cube
186
+ self.l = self.x
187
+ self.x = self.x ** 3
188
+ end
189
+ def ln
190
+ self.l = self.x
191
+ begin
192
+ self.x = Math::log(self.x)
193
+ rescue
194
+ return "Error"
195
+ end
196
+ end
197
+ def ex
198
+ self.l = self.x
199
+ self.x = Math::exp(self.x)
200
+ end
201
+ def log
202
+ self.l = self.x
203
+ begin
204
+ self.x = Math::log10(self.x)
205
+ rescue
206
+ return "Error"
207
+ end
208
+ end
209
+ def tenx
210
+ self.l = self.x
211
+ self.x = 10 ** self.x
212
+ end
213
+ def sin
214
+ self.l = self.x
215
+ self.x = self.x * Math::PI / 180 if self.deg
216
+ self.x = Math::sin(self.x)
217
+ end
218
+ def cos
219
+ self.l = self.x
220
+ self.x = self.x * Math::PI / 180 if self.deg
221
+ self.x = Math::cos(self.x)
222
+ end
223
+ def tan
224
+ self.l = self.x
225
+ self.x = self.x * Math::PI / 180 if self.deg
226
+ self.x = Math::tan(self.x)
227
+ end
228
+ def asin
229
+ self.l = self.x
230
+ self.x = Math::asin(self.x)
231
+ self.x = self.x * 180 / Math::PI if self.deg
232
+ end
233
+ def acos
234
+ self.l = self.x
235
+ self.x = Math::acos(self.x)
236
+ self.x = self.x * 180 / Math::PI if self.deg
237
+ end
238
+ def atan
239
+ self.l = self.x
240
+ self.x = Math::atan(self.x)
241
+ self.x = self.x * 180 / Math::PI if self.deg
242
+ end
243
+ def rp
244
+ begin
245
+ throw if self.x == 0
246
+ self.l = self.x
247
+ x = self.x
248
+ y = self.y
249
+ self.x = Math::sqrt(x*x + y*y)
250
+ self.y = Math::atan(y/x)
251
+ if x < 0 # Q2 & Q3
252
+ self.y += Math::PI
253
+ elsif x >= 0 and y < 0 # Q4
254
+ self.y += 2 * Math::PI
255
+ end
256
+ self.y = self.y * 180 / Math::PI if self.deg
257
+ rescue
258
+ return "Error"
259
+ end
260
+ end
261
+ def pr
262
+ self.l = self.x
263
+ r = self.x
264
+ t = self.y
265
+ t = t * Math::PI / 180 if self.deg
266
+ self.x = r * Math::cos(t)
267
+ self.y = r * Math::sin(t)
268
+ end
269
+ end
270
+
271
+ begin # BASIC SETUP
272
+ @stk = Stack.new(0, 0, 0, 0, 0)
273
+ @reg = %w[0 0 0 0 0 0 0 0 0 0]
274
+ @fix = 4
275
+ @sci = 6
276
+ @dot = true
277
+ @mod = "Deg"
278
+ @hlp = true
279
+
280
+ load(Dir.home+'/.t-rex.conf') if File.exist?(Dir.home+'/.t-rex.conf')
281
+ @mod == "Deg" ? @stk.deg = true : @stk.deg = false
282
+
283
+ @history = [""]
284
+
285
+ Curses.init_screen
286
+ Curses.start_color
287
+ Curses.curs_set(0)
288
+ Curses.noecho
289
+ Curses.cbreak
290
+ Curses.stdscr.keypad = true
291
+ end
292
+
293
+ # FUNCTIONS
294
+ def getchr # PROCESS KEY PRESSES
295
+ c = STDIN.getch
296
+ case c
297
+ when "\e" # ANSI escape sequences
298
+ case $stdin.getc
299
+ when '[' # CSI
300
+ case $stdin.getc
301
+ when 'A' then chr = "UP"
302
+ when 'B' then chr = "DOWN"
303
+ when 'C' then chr = "RIGHT"
304
+ when 'D' then chr = "LEFT"
305
+ when 'Z' then chr = "S-TAB"
306
+ when '2' then chr = "INS" ; STDIN.getc
307
+ when '3' then chr = "DEL" ; STDIN.getc
308
+ when '5' then chr = "PgUP" ; STDIN.getc
309
+ when '6' then chr = "PgDOWN" ; STDIN.getc
310
+ when '7' then chr = "HOME" ; STDIN.getc
311
+ when '8' then chr = "END" ; STDIN.getc
312
+ end
313
+ end
314
+ when "", "" then chr = "BACK"
315
+ when "" then chr = "WBACK"
316
+ when "" then chr = "LDEL"
317
+ when "" then chr = "C-X"
318
+ when "" then chr = "C-Q"
319
+ when "" then chr = "C-N"
320
+ when "" then chr = "C-G"
321
+ when " " then chr = "C-L"
322
+ when " " then chr = "C-I"
323
+ when "" then chr = "C-O"
324
+ when "" then chr = "C-A"
325
+ when "" then chr = "C-R"
326
+ when "" then chr = "C-D"
327
+ when "" then chr = "C-C"
328
+ when "" then chr = "C-T"
329
+ when "" then chr = "C-^"
330
+ when "\r" then chr = "ENTER"
331
+ when "\t" then chr = "TAB"
332
+ when /./ then chr = c
333
+ end
334
+ return chr
335
+ end
336
+ def main_getkey(c) # GET KEY FROM USER
337
+ c == "" ? chr = getchr : chr = c
338
+ case chr
339
+ when 'ENTER'
340
+ @stk.l = @stk.x
341
+ @stk.y, @stk.z, @stk.t = @stk.x, @stk.y, @stk.z
342
+ when "'"
343
+ @dot = !@dot
344
+ when 'UP' # Roll stack up
345
+ @stk.rup
346
+ when 'DOWN' # Roll stack down
347
+ @stk.rdn
348
+ when '<', 'LEFT', 'RIGHT' # x<>y
349
+ @stk.xy
350
+ when '+'
351
+ @stk.add
352
+ when '-'
353
+ @stk.subtract
354
+ when '*'
355
+ @stk.multiply
356
+ when '/'
357
+ e = @stk.divide
358
+ error ("Error: Divide by zero") if e == "Error"
359
+ when '\\' # \ (modulo)
360
+ @stk.mod
361
+ when '%' # 100*x/y
362
+ e = @stk.percent
363
+ error ("Error: Divide by zero") if e == "Error"
364
+ when 'h' # Change sign
365
+ @stk.chs
366
+ when 'p' # pi
367
+ @stk.l = @stk.x
368
+ @stk.pi
369
+ when '^' # y^x
370
+ @stk.pow
371
+ when 'C-^' # y^(1/x)
372
+ e = @stk.root
373
+ error ("Error: Divide by zero") if e == "Error"
374
+ when 'x' # 1/x
375
+ e = @stk.recip
376
+ error ("Error: Divide by zero") if e == "Error"
377
+ when 'C-X' # x^2
378
+ @stk.sqr
379
+ when 'q' # Square root
380
+ e = @stk.sqrt
381
+ error ("Error: Imaginary number") if e == "Error"
382
+ when 'C-Q' # x^3
383
+ @stk.cube
384
+ when 'n' # ln(x)
385
+ e = @stk.ln
386
+ error ("Error: Negative x") if e == "Error"
387
+ when 'C-N' # e^x
388
+ @stk.ex
389
+ when 'g' # log(x)
390
+ e = @stk.log
391
+ error ("Error: Negative x") if e == "Error"
392
+ when 'C-G' # 10^x
393
+ @stk.tenx
394
+ when 'l' # Recall Lastx (l) to x
395
+ @stk.lift
396
+ @stk.x = @stk.l
397
+ when 'C-L' # Break/redraw
398
+ @break = true
399
+ when 'i'
400
+ @stk.sin
401
+ when 'C-I'
402
+ @stk.asin
403
+ when 'o'
404
+ @stk.cos
405
+ when 'C-O'
406
+ @stk.acos
407
+ when 'a'
408
+ @stk.tan
409
+ when 'C-A'
410
+ @stk.atan
411
+ when 'r' # Rad mode
412
+ @mod = "Rad"
413
+ @stk.deg = false
414
+ when 'C-R' # R->P
415
+ e = @stk.rp
416
+ error ("Error: Divide by zero") if e == "Error"
417
+ when 'd' # Deg mode
418
+ @mod = "Deg"
419
+ @stk.deg = true
420
+ when 'C-D' # P->R
421
+ @stk.pr
422
+ when 'c', 'BACK'
423
+ @stk.x = 0
424
+ when 'C-C' # Clear stack
425
+ @stk.x = 0
426
+ @stk.y = 0
427
+ @stk.z = 0
428
+ @stk.t = 0
429
+ @stk.l = 0
430
+ when 'M'
431
+ @reg = %w[0 0 0 0 0 0 0 0 0 0]
432
+ when 'S' # Store to Reg
433
+ @w_x.clr
434
+ @w_x.p(" Store x in Reg #(0-9)")
435
+ r = getchr
436
+ if r =~ /[0-9]/
437
+ @reg[r.to_i] = @stk.x
438
+ end
439
+ when 'R' # Recall from Reg
440
+ @w_x.clr
441
+ @w_x.p(" Recall from Reg #(0-9)")
442
+ r = getchr
443
+ if r =~ /[0-9]/
444
+ @stk.lift
445
+ @stk.x = @reg[r.to_i].to_f
446
+ end
447
+ when 's' # Set Sci size/limit
448
+ @w_x.clr
449
+ @w_x.p(" Sci notation limit (2-9)")
450
+ r = getchr
451
+ if r =~ /[2-9]/
452
+ @sci = r.to_i
453
+ end
454
+ when 'f' # Set Fix size
455
+ @w_x.clr
456
+ @w_x.p(" Fixed decimals (0-9)")
457
+ r = getchr
458
+ if r =~ /[0-9]/
459
+ @fix = r.to_i
460
+ end
461
+ when 'u' # Undo
462
+ unless @u.empty?
463
+ @stk = @u.last.dup
464
+ @u.pop
465
+ @undo = true
466
+ end
467
+ when 'y'
468
+ begin
469
+ @w_x.color = 7
470
+ @w_x.fill
471
+ system("echo '#{@stk.x}' | xclip")
472
+ sleep(0.1)
473
+ @w_x.color = 6
474
+ rescue
475
+ @w_x.clr
476
+ @w_x.p(" Install xclip to yank")
477
+ getchr
478
+ end
479
+ when 'Y'
480
+ begin
481
+ @w_x.color = 5
482
+ @w_x.fill
483
+ mem = ""
484
+ 10.times do |i|
485
+ reg = @reg[i]
486
+ mem += "#{reg}\n"
487
+ end
488
+ system("echo '#{mem}' | xclip")
489
+ sleep(0.1)
490
+ @w_x.color = 6
491
+ rescue
492
+ @w_x.clr
493
+ @w_x.p(" Install xclip to yank")
494
+ getchr
495
+ end
496
+ when 'H'
497
+ @hlp = !@hlp
498
+ @w_hlp.fill
499
+ help if @hlp
500
+ when '@' # Ruby console
501
+ @w_hlp.fill
502
+ console(" Ruby: ")
503
+ @w_hlp.fill
504
+ help if @hlp
505
+ when 'Q' # Exit
506
+ exit 0
507
+ when /[0-9.,-]/ # Go to entry mode for x
508
+ number, c = entry(chr)
509
+ if number != ""
510
+ @stk.l = @stk.x
511
+ @stk.lift unless @stk.x == 0
512
+ @stk.x = number
513
+ end
514
+ main_getkey(c) if %w[< + - * / \ % ^ x C-X q C-Q n C-N g C-G i C-I o C-O a C-A c C-C].include?(c)
515
+ end
516
+ end
517
+ def console(pretext) # A SIMPLE READLINE-LIKE ROUTINE
518
+ Curses.curs_set(1)
519
+ Curses.echo
520
+ @w_hlp.color = 9
521
+ stk = 0
522
+ pos = @history[stk].length
523
+ @w_hlp.setpos(0,0)
524
+ chr = ""
525
+ while chr != "C-C"
526
+ @w_hlp.setpos(@w_hlp.cury,0)
527
+ text = pretext + @history[stk]
528
+ text += " " * (@w_hlp.maxx - text.length) if text.length < @w_hlp.maxx
529
+ @w_hlp.p(text)
530
+ @w_hlp.setpos(0,pretext.length + pos)
531
+ @w_hlp.refresh
532
+ chr = getchr
533
+ case chr
534
+ when 'UP'
535
+ unless stk == @history.length - 1
536
+ stk += 1
537
+ pos = @history[stk].length
538
+ end
539
+ when 'DOWN'
540
+ unless stk == 0
541
+ stk -= 1
542
+ pos = @history[stk].length
543
+ end
544
+ when 'RIGHT'
545
+ pos += 1 unless pos > @history[stk].length
546
+ when 'LEFT'
547
+ pos -= 1 unless pos == 0
548
+ when 'HOME'
549
+ pos = 0
550
+ when 'END'
551
+ pos = @history[stk].length
552
+ when 'DEL'
553
+ @history[stk][pos] = ""
554
+ when 'BACK'
555
+ unless pos == 0
556
+ pos -= 1
557
+ @history[stk][pos] = ""
558
+ end
559
+ when 'WBACK'
560
+ unless pos == 0
561
+ until @history[stk][pos - 1] == " " or pos == 0
562
+ pos -= 1
563
+ @history[stk][pos] = ""
564
+ end
565
+ if @history[stk][pos - 1] == " "
566
+ pos -= 1
567
+ @history[stk][pos] = ""
568
+ end
569
+ end
570
+ when 'LDEL'
571
+ @history[stk] = ""
572
+ pos = 0
573
+ when /^.$/
574
+ @history[stk].insert(pos,chr)
575
+ pos += 1
576
+ when 'ENTER'
577
+ @w_hlp.fill
578
+ @w_hlp.p(text)
579
+ @w_hlp.setpos(0,pretext.length + pos)
580
+ @w_hlp.refresh
581
+ @w_hlp.p("\n ")
582
+ curstr = @history[stk]
583
+ @history.uniq!
584
+ @history.compact!
585
+ @history.delete("")
586
+ begin
587
+ x = @stk.x
588
+ y = @stk.y
589
+ z = @stk.z
590
+ t = @stk.t
591
+ l = @stk.l
592
+ eval(curstr)
593
+ @stk.x = x
594
+ @stk.y = y
595
+ @stk.z = z
596
+ @stk.t = t
597
+ @stk.l = l
598
+ @w_hlp.p("\n\n")
599
+ pstack
600
+ rescue StandardError => e
601
+ @w_hlp.p("\n Error: #{e.inspect}\n")
602
+ end
603
+ @history.unshift("")
604
+ stk = 0
605
+ pos = @history[stk].length
606
+ chr = ""
607
+ @w_hlp.setpos(0,0)
608
+ end
609
+ end
610
+ @w_hlp.color = 11
611
+ Curses.curs_set(0)
612
+ Curses.noecho
613
+ end
614
+ def entry(chr)
615
+ Curses.curs_set(1)
616
+ Curses.echo
617
+ num = chr
618
+ pos = 1
619
+ @w_x.color = 7
620
+ while %w[0 1 2 3 4 5 6 7 8 9 . , h RIGHT LEFT HOME END DEL BACK WBACK LDEL].include?(chr)
621
+ @w_x.clr
622
+ @w_x.setpos(0,0)
623
+ @w_x.p(num)
624
+ @w_x.setpos(0,pos)
625
+ @w_x.refresh
626
+ chr = getchr
627
+ case chr
628
+ when 'RIGHT'
629
+ pos += 1 unless pos >= num.length
630
+ when 'LEFT'
631
+ pos -= 1 unless pos == 0
632
+ when 'HOME'
633
+ pos = 0
634
+ when 'END'
635
+ pos = num.length
636
+ when 'DEL'
637
+ num[pos] = ""
638
+ when 'BACK'
639
+ unless pos == 0
640
+ pos -= 1
641
+ num[pos] = ""
642
+ end
643
+ when 'WBACK'
644
+ unless pos == 0
645
+ until num[pos - 1] == " " or pos == 0
646
+ pos -= 1
647
+ num[pos] = ""
648
+ end
649
+ if num[pos - 1] == " "
650
+ pos -= 1
651
+ num[pos] = ""
652
+ end
653
+ end
654
+ when 'LDEL'
655
+ num = ""
656
+ pos = 0
657
+ when 'h'
658
+ if num[0] == "-"
659
+ num[0] = ""
660
+ pos -= 1
661
+ else
662
+ num.insert(0, "-")
663
+ pos += 1
664
+ end
665
+ when /[0-9.,]/
666
+ num.insert(pos,chr)
667
+ pos += 1
668
+ end
669
+ end
670
+ num = "" if %w[DOWN UP].include?(chr)
671
+ num.gsub!(/,/, '.')
672
+ num != "" ? number = num.to_f : number = ""
673
+ Curses.curs_set(0)
674
+ Curses.noecho
675
+ @w_x.color = 6
676
+ return number, chr
677
+ end
678
+ def num_format(n)
679
+ if n.abs >= 10 ** @sci.to_i
680
+ n = "%.#{@sci}g" % n
681
+ elsif n.abs <= 10 ** (1 / @sci.to_i) and n > 10
682
+ n = "%.#{@sci}g" % n
683
+ else
684
+ n = n.round(@fix)
685
+ n = "%.#{@fix}f" % n
686
+ m = n[/^-/]
687
+ m = "" if m == nil
688
+ n.sub!(/-/, '')
689
+ i = n[/\d*/]
690
+ i.gsub!(/(\d)(?=(\d\d\d)+(?!\d))/, "\\1,")
691
+ f = n.sub(/\d*\.(\d*)/, '\1')
692
+ n = m + i + "." + f
693
+ if not @dot
694
+ n.gsub!(/,/, ' ')
695
+ n.sub!(/\./, ',')
696
+ end
697
+ end
698
+ return n
699
+ end
700
+ def pstack
701
+ x = num_format(@stk.x)
702
+ y = num_format(@stk.y)
703
+ z = num_format(@stk.z)
704
+ t = num_format(@stk.t)
705
+ l = num_format(@stk.l)
706
+ @w_l.setpos(0,0)
707
+ @w_l.p(l.rjust(30))
708
+ @w_yzt.setpos(0,0)
709
+ @w_yzt.p(t.rjust(30) + z.rjust(30) + y.rjust(30))
710
+ @w_x.setpos(0,0)
711
+ @w_x.p(x.rjust(30))
712
+ end
713
+ def pregs
714
+ @w_reg.setpos(1,0)
715
+ 10.times do |i|
716
+ r = num_format(@reg[i].to_f)
717
+ @w_reg.p(" R##{i}" + "#{r}".rjust(27) + " ")
718
+ end
719
+ end
720
+ def error(err)
721
+ @w_x.clr
722
+ @w_x.p(err.rjust(30))
723
+ getchr
724
+ end
725
+ def cmd
726
+ text = <<CMDTEXT
727
+
728
+ r|↓| r|↑| x|<|>y |+| |-| |*| |/| |\\| |%| c|h|s |p|i
729
+ y√x x^2 x^3 e^x 10^x redrw
730
+ y|^|x 1/|x| s|q|rt l|n| lo|g| |l|astx
731
+ asin acos atan R→P P→R cstk
732
+ s|i|n c|o|s t|a|n |r|ad |d|eg |c|lx
733
+
734
+ |S|to |R|cl |s|ci |f|ix |u|ndo |H|lp |Q|uit
735
+ CMDTEXT
736
+ text = text.split("\n")
737
+ text.each_with_index do |t,i|
738
+ if i.even?
739
+ @w_cmd.color = 8
740
+ @w_cmd.p(t)
741
+ else
742
+ t = t.split("|")
743
+ t.each_with_index do |c,j|
744
+ if j.even?
745
+ @w_cmd.color = 9
746
+ @w_cmd.p(c)
747
+ else
748
+ @w_cmd.color = 10
749
+ @w_cmd.p(c)
750
+ end
751
+ end
752
+ @w_cmd.p("\n")
753
+ end
754
+ @w_cmd.p("\n")
755
+ end
756
+ end
757
+ def help
758
+ help = <<HELPTEXT
759
+
760
+ T-REX - Terminal Rpn calculator EXperiment. GitHub: https://github.com/isene/T-REX
761
+
762
+ This is a Reverse Polish Notation calculator similar to the traditional Hewlett
763
+ Packard calculators. See https://www.hpmuseum.org/rpn.htm for info on RPN.
764
+
765
+ The stack is shown to the top left. The X, Y, Z and T registers comprise the
766
+ operating stack. L is the "Last X" register showing the previous value in X.
767
+ Toggle US and European number formats by pressing '.
768
+
769
+ Functions available are shown under the stack registers. The orange symbol
770
+ corresponds to the key to be pressed. For functions above each label (grey
771
+ functions), press the Control key (Ctrl) and the orange key (asin = Ctrl+i).
772
+
773
+ For Rectangular to Polar conversions:
774
+ R-P: X value in x, Y in y - yields "θ" in y and "r" in x.
775
+ P-R: "θ" in y and "r" in x - yeilds X in x and Y in y.
776
+
777
+ Use the "f" key to set the fixed number of decimal places. Use the "s" key to set
778
+ the limit for viewing numbers in the "scientific" notation (e.g. 5e+06 for 5000000).
779
+
780
+ Content of registers #0-#9 are shown below the functions.
781
+ Store/recall using capital "S"/"R". "M" clears the regs.
782
+
783
+ Copy/yank the X register to clipboard with "y". Use "Y" to yank all the memory regs.
784
+
785
+ You can undo all the way to the beginning of the session.
786
+
787
+ The 'H' key toggles the help text in the right pane.
788
+
789
+ The stack, register contents, modes and help text settings are saved on Quit.
790
+
791
+ Additionally, for a world of possibilities, you can access the "Ruby mode" via '@'.
792
+ Here you can address the stack directly, e.g. x = y + (z / t). Quit Ruby mode with Ctrl-C.
793
+
794
+ HELPTEXT
795
+ @w_hlp.p(help)
796
+ end
797
+ def conf_write # WRITE TO .t-rex.conf
798
+ conf = "@fix = #{@fix}\n"
799
+ conf += "@sci = #{@sci}\n"
800
+ @dot ? d = "true" : d = "false"
801
+ conf += "@dot = #{d}\n"
802
+ conf += "@mod = \"#{@mod}\"\n"
803
+ conf += "@stk = Stack.new(#{@stk.x}, #{@stk.y}, #{@stk.z}, #{@stk.t}, #{@stk.l})\n"
804
+ conf += "@reg = %w[#{@reg[0]} #{@reg[1]} #{@reg[2]} #{@reg[3]} #{@reg[4]} #{@reg[5]} #{@reg[6]} #{@reg[7]} #{@reg[8]} #{@reg[9]}]\n"
805
+ @hlp ? h = "true" : h = "false"
806
+ conf += "@hlp = #{h}\n"
807
+ File.write(Dir.home+'/.t-rex.conf', conf)
808
+ end
809
+
810
+ # MAIN PROGRAM
811
+ loop do # OUTER LOOP - (catching refreshes via 'b')
812
+ @break = false # Initialize @break variable (set if user hits 'b')
813
+ begin # Create the windows/panels
814
+ maxx = Curses.cols
815
+ maxy = Curses.lines
816
+ init_pair( 1, 235, 235) # stdscr
817
+ Curses.stdscr.color = 1
818
+ Curses.stdscr.fill
819
+ # Curses::Window.new(h,w,y,x)
820
+ @w_inf = Curses::Window.new( 1, 32, 1, 1)
821
+ @w_lbl = Curses::Window.new( 5, 2, 2, 1)
822
+ @w_l = Curses::Window.new( 1, 30, 2, 3)
823
+ @w_yzt = Curses::Window.new( 3, 30, 3, 3)
824
+ @w_x = Curses::Window.new( 1, 30, 6, 3)
825
+ @w_cmd = Curses::Window.new(12, 32, 8, 1)
826
+ @w_reg = Curses::Window.new(maxy - 22, 32, 21, 1)
827
+ @w_hlp = Curses::Window.new(maxy - 2, maxx - 35, 1, 34)
828
+
829
+ init_pair( 2, 88, 238) # @w_inf
830
+ init_pair( 3, 60, 238) # @w_lbl
831
+ init_pair( 4, 246, 236) # @w_l
832
+ init_pair( 5, 250, 234) # @w_yzt
833
+ init_pair( 6, 7, 0) # @w_x
834
+ init_pair( 7, 0, 250) # @w_xi
835
+ init_pair( 8, 242, 0) # @w_cmd ctrl- & @w_reg
836
+ init_pair( 9, 111, 0) # @w_cmd
837
+ init_pair(10, 214, 0) # @w_cmd key
838
+ init_pair(11, 238, 0) # @w_hlp
839
+
840
+ @w_inf.color = 2
841
+ @w_lbl.color = 3
842
+ @w_l.color = 4
843
+ @w_yzt.color = 5
844
+ @w_x.color = 6
845
+ @w_x.attr = Curses::A_BOLD
846
+ @w_cmd.color = 8
847
+ @w_cmd.attr = Curses::A_BOLD
848
+ @w_reg.color = 8
849
+ @w_hlp.color = 11
850
+
851
+ @w_lbl.p(" L T Z Y X")
852
+ @w_cmd.fill; cmd
853
+ @w_reg.fill
854
+ @w_hlp.fill
855
+ help if @hlp
856
+
857
+ @u = []
858
+ @undo = false
859
+
860
+ loop do # INNER, CORE LOOP
861
+
862
+ @w_inf.clr
863
+ @w_inf.p(" #{@mod} Sci=#{@sci} Fix=#{@fix}".ljust(32))
864
+ pstack
865
+ pregs
866
+ @t = @stk.dup
867
+ main_getkey("") # Get key from user
868
+ @u.push(@t.dup) if @t != @stk and @undo == false
869
+ @undo = false
870
+
871
+ break if @break # Break to outer loop, redrawing windows, if user hit 'r'
872
+ break if Curses.cols != maxx or Curses.lines != maxy # break on terminal resize
873
+ end
874
+ ensure # On exit: close curses, clear terminal
875
+ conf_write
876
+ close_screen
877
+ end
878
+ end
879
+
880
+ # vim: set sw=2 sts=2 et fdm=syntax fdn=2 fcs=fold\:\ :
metadata ADDED
@@ -0,0 +1,46 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: t-rex
3
+ version: !ruby/object:Gem::Version
4
+ version: '1.0'
5
+ platform: ruby
6
+ authors:
7
+ - Geir Isene
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2021-09-23 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: This is a Reverse Polish Notation calculator similar to the traditional
14
+ calculators from Hewlett Packard. See https://www.hpmuseum.org/rpn.htm for info
15
+ on RPN.
16
+ email: g@isene.com
17
+ executables: []
18
+ extensions: []
19
+ extra_rdoc_files: []
20
+ files:
21
+ - bin/t-rex.rb
22
+ homepage: https://isene.com/
23
+ licenses:
24
+ - Unlicense
25
+ metadata:
26
+ source_code_uri: https://github.com/isene/t-rex
27
+ post_install_message:
28
+ rdoc_options: []
29
+ require_paths:
30
+ - lib
31
+ required_ruby_version: !ruby/object:Gem::Requirement
32
+ requirements:
33
+ - - ">="
34
+ - !ruby/object:Gem::Version
35
+ version: '0'
36
+ required_rubygems_version: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ requirements: []
42
+ rubygems_version: 3.1.2
43
+ signing_key:
44
+ specification_version: 4
45
+ summary: T-REX - Terminal Rpn calculator EXperiment
46
+ test_files: []