rubish-gem 0.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.
Files changed (45) hide show
  1. checksums.yaml +7 -0
  2. data/.dockerignore +23 -0
  3. data/Dockerfile +54 -0
  4. data/LICENSE.txt +21 -0
  5. data/README.md +39 -0
  6. data/Rakefile +12 -0
  7. data/lib/rubish/arithmetic.rb +140 -0
  8. data/lib/rubish/ast.rb +168 -0
  9. data/lib/rubish/builtins/arithmetic.rb +129 -0
  10. data/lib/rubish/builtins/bind_readline.rb +834 -0
  11. data/lib/rubish/builtins/directory_stack.rb +182 -0
  12. data/lib/rubish/builtins/echo_printf.rb +510 -0
  13. data/lib/rubish/builtins/hash_directories.rb +260 -0
  14. data/lib/rubish/builtins/read.rb +299 -0
  15. data/lib/rubish/builtins/trap.rb +324 -0
  16. data/lib/rubish/codegen.rb +1273 -0
  17. data/lib/rubish/completion.rb +840 -0
  18. data/lib/rubish/completions/bash_helpers.rb +530 -0
  19. data/lib/rubish/completions/git.rb +431 -0
  20. data/lib/rubish/completions/help_parser.rb +453 -0
  21. data/lib/rubish/completions/ssh.rb +114 -0
  22. data/lib/rubish/config.rb +267 -0
  23. data/lib/rubish/data/builtin_help.rb +716 -0
  24. data/lib/rubish/data/completion_data.rb +53 -0
  25. data/lib/rubish/data/readline_config.rb +47 -0
  26. data/lib/rubish/data/shell_options.rb +251 -0
  27. data/lib/rubish/data_define.rb +65 -0
  28. data/lib/rubish/execution_context.rb +1124 -0
  29. data/lib/rubish/expansion.rb +988 -0
  30. data/lib/rubish/history.rb +663 -0
  31. data/lib/rubish/lazy_loader.rb +127 -0
  32. data/lib/rubish/lexer.rb +1194 -0
  33. data/lib/rubish/parser.rb +1167 -0
  34. data/lib/rubish/prompt.rb +766 -0
  35. data/lib/rubish/repl.rb +2267 -0
  36. data/lib/rubish/runtime/builtins.rb +7222 -0
  37. data/lib/rubish/runtime/command.rb +1153 -0
  38. data/lib/rubish/runtime/job.rb +153 -0
  39. data/lib/rubish/runtime.rb +1169 -0
  40. data/lib/rubish/shell_state.rb +241 -0
  41. data/lib/rubish/startup_profiler.rb +67 -0
  42. data/lib/rubish/version.rb +5 -0
  43. data/lib/rubish.rb +60 -0
  44. data/sig/rubish.rbs +4 -0
  45. metadata +85 -0
@@ -0,0 +1,127 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rubish
4
+ # Background lazy loader for slow shell initializations
5
+ #
6
+ # Usage in config:
7
+ # lazy_load {
8
+ # `rbenv init - --no-rehash bash`
9
+ # }
10
+ #
11
+ # The block runs in a background thread immediately.
12
+ # Its return value (a string of shell code) is eval'd in the main thread
13
+ # before the next prompt.
14
+ #
15
+ # Benefits:
16
+ # - Shell starts instantly
17
+ # - Slow inits run in parallel during startup
18
+ # - By the time you need the command, it's usually ready
19
+ #
20
+ module LazyLoader
21
+ @pending_tasks = []
22
+ @completed_results = Queue.new
23
+ @mutex = Mutex.new
24
+
25
+ class << self
26
+ # Register a lazy load task to run in background
27
+ def register(name, executor, &block)
28
+ task = {
29
+ name: name,
30
+ thread: nil,
31
+ executor: executor,
32
+ started_at: Process.clock_gettime(Process::CLOCK_MONOTONIC)
33
+ }
34
+
35
+ task[:thread] = Thread.new do
36
+ begin
37
+ # Run the block and capture its return value (shell code to eval)
38
+ result = block.call
39
+ # If result is a string, it's shell code to eval
40
+ if result.is_a?(String) && !result.strip.empty?
41
+ @completed_results << {name: name, code: result, error: nil, started_at: task[:started_at]}
42
+ else
43
+ @completed_results << {name: name, code: nil, error: nil, started_at: task[:started_at]}
44
+ end
45
+ rescue => e
46
+ @completed_results << {name: name, code: nil, error: e, started_at: task[:started_at]}
47
+ end
48
+ end
49
+
50
+ @mutex.synchronize { @pending_tasks << task }
51
+ end
52
+
53
+ # Check for completed background tasks and apply their results
54
+ # Called before each prompt
55
+ def apply_completed(executor)
56
+ applied = []
57
+
58
+ while !@completed_results.empty?
59
+ begin
60
+ item = @completed_results.pop(true) # non-blocking
61
+ rescue ThreadError
62
+ break
63
+ end
64
+
65
+ if item[:error]
66
+ $stderr.puts "lazy_load: #{item[:error].message}"
67
+ elsif item[:code]
68
+ begin
69
+ # Execute the shell code in main thread
70
+ executor.call(item[:code])
71
+ elapsed = Process.clock_gettime(Process::CLOCK_MONOTONIC) - item[:started_at]
72
+ applied << {name: item[:name], elapsed: elapsed}
73
+ rescue => e
74
+ $stderr.puts "lazy_load: #{e.message}"
75
+ end
76
+ end
77
+ end
78
+
79
+ # Report if profiling is enabled
80
+ if defined?(StartupProfiler) && StartupProfiler.enabled && applied.any?
81
+ applied.each do |info|
82
+ puts " [lazy] #{info[:name]}: loaded in background (#{(info[:elapsed] * 1000).round(1)}ms)"
83
+ end
84
+ end
85
+
86
+ applied.map { |a| a[:name] }
87
+ end
88
+
89
+ # Wait for all pending tasks to complete (useful for scripts)
90
+ def wait_all(executor, timeout: 30)
91
+ deadline = Time.now + timeout
92
+
93
+ @mutex.synchronize { @pending_tasks.dup }.each do |task|
94
+ remaining = deadline - Time.now
95
+ break if remaining <= 0
96
+ task[:thread]&.join(remaining)
97
+ end
98
+
99
+ apply_completed(executor)
100
+ end
101
+
102
+ # Check if any tasks are still running
103
+ def pending?
104
+ @mutex.synchronize { @pending_tasks.any? { |t| t[:thread]&.alive? } }
105
+ end
106
+
107
+ # Get status of all tasks
108
+ def status
109
+ @mutex.synchronize do
110
+ @pending_tasks.map do |task|
111
+ {
112
+ name: task[:name],
113
+ running: task[:thread]&.alive?,
114
+ elapsed: Process.clock_gettime(Process::CLOCK_MONOTONIC) - task[:started_at]
115
+ }
116
+ end
117
+ end
118
+ end
119
+
120
+ # Clear all tasks (for testing)
121
+ def clear!
122
+ @mutex.synchronize { @pending_tasks.clear }
123
+ @completed_results.clear rescue nil
124
+ end
125
+ end
126
+ end
127
+ end