hiiro 0.1.279 → 0.1.280
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +1 -1
- data/bin/h-buffer +6 -25
- data/bin/h-jumplist +36 -9
- data/bin/h-pane +5 -10
- data/bin/h-project +56 -83
- data/bin/h-session +7 -26
- data/bin/h-window +5 -12
- data/lib/hiiro/options.rb +23 -6
- data/lib/hiiro/projects.rb +54 -0
- data/lib/hiiro/queue.rb +56 -10
- data/lib/hiiro/tasks.rb +22 -0
- data/lib/hiiro/tmux.rb +26 -0
- data/lib/hiiro/version.rb +1 -1
- data/lib/hiiro.rb +1 -0
- data/plugins/project.rb +9 -49
- metadata +2 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: c86b1990635355b7028465d785137a29092594900b220e679107138cdedf5821
|
|
4
|
+
data.tar.gz: fdd08045ed76b8ca7d288fa1f49358eb65649c35f043ce35745114c63af920f0
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: e4a7443498c3902dc536b39df7d128782f5cd3ad8be6b3acb75b50a93b431e27aff7b68e87b3531d860b7cf7bf82c0f658fad17663a5d2f42098bb7cbf605f2b
|
|
7
|
+
data.tar.gz: 1acd39aadcadd0dca8abdccfbe3e91d286cffbeb9e40cc5a2d3a139022c9c324de6c030573848ca0571d5d6dcb3a67785e19c0b2d677fd10d01d1e9c733ca25d
|
data/CHANGELOG.md
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
Done. CHANGELOG.md has been updated with v0.1.
|
|
1
|
+
Done. CHANGELOG.md has been updated with v0.1.280 for 2026-03-25. The new section documents all the features, changes, and refactorings from the recent commits, organized by Added and Changed categories.
|
data/bin/h-buffer
CHANGED
|
@@ -4,20 +4,7 @@ require "hiiro"
|
|
|
4
4
|
|
|
5
5
|
Hiiro.run(*ARGV, plugins: [Pins]) do
|
|
6
6
|
tmux = tmux_client
|
|
7
|
-
|
|
8
|
-
select_buffer_proc = ->(partial = nil) {
|
|
9
|
-
buffers = tmux.buffers
|
|
10
|
-
return nil if buffers.empty?
|
|
11
|
-
|
|
12
|
-
if partial
|
|
13
|
-
buffers = buffers.matching(partial)
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
return nil if buffers.empty?
|
|
17
|
-
return buffers.first.name if buffers.size == 1
|
|
18
|
-
|
|
19
|
-
fuzzyfind_from_map(buffers.name_map)
|
|
20
|
-
}
|
|
7
|
+
Hiiro::Tmux.add_resolvers(self)
|
|
21
8
|
|
|
22
9
|
add_subcmd(:ls) { |*args|
|
|
23
10
|
if args.empty?
|
|
@@ -28,7 +15,7 @@ Hiiro.run(*ARGV, plugins: [Pins]) do
|
|
|
28
15
|
}
|
|
29
16
|
|
|
30
17
|
add_subcmd(:show) { |name = nil, *args|
|
|
31
|
-
buffer_name =
|
|
18
|
+
buffer_name = resolve(:buffer, name)
|
|
32
19
|
|
|
33
20
|
unless buffer_name
|
|
34
21
|
puts "No buffer selected or found"
|
|
@@ -44,7 +31,7 @@ Hiiro.run(*ARGV, plugins: [Pins]) do
|
|
|
44
31
|
}
|
|
45
32
|
|
|
46
33
|
add_subcmd(:copy) { |name = nil|
|
|
47
|
-
buffer_name =
|
|
34
|
+
buffer_name = resolve(:buffer, name)
|
|
48
35
|
unless buffer_name
|
|
49
36
|
puts "No buffer selected or found"
|
|
50
37
|
next
|
|
@@ -66,7 +53,7 @@ Hiiro.run(*ARGV, plugins: [Pins]) do
|
|
|
66
53
|
if name
|
|
67
54
|
tmux.save_buffer(path, name: name)
|
|
68
55
|
elsif args.empty?
|
|
69
|
-
buffer_name =
|
|
56
|
+
buffer_name = resolve(:buffer, nil)
|
|
70
57
|
if buffer_name
|
|
71
58
|
tmux.save_buffer(path, name: buffer_name)
|
|
72
59
|
end
|
|
@@ -104,7 +91,7 @@ Hiiro.run(*ARGV, plugins: [Pins]) do
|
|
|
104
91
|
|
|
105
92
|
add_subcmd(:delete) { |name = nil, *args|
|
|
106
93
|
if name.nil?
|
|
107
|
-
name =
|
|
94
|
+
name = resolve(:buffer, nil)
|
|
108
95
|
end
|
|
109
96
|
|
|
110
97
|
if name && args.empty?
|
|
@@ -130,13 +117,7 @@ Hiiro.run(*ARGV, plugins: [Pins]) do
|
|
|
130
117
|
}
|
|
131
118
|
|
|
132
119
|
add_subcmd(:select) do
|
|
133
|
-
|
|
134
|
-
if buffers.empty?
|
|
135
|
-
STDERR.puts "No buffers found"
|
|
136
|
-
next
|
|
137
|
-
end
|
|
138
|
-
|
|
139
|
-
selected = fuzzyfind_from_map(buffers.name_map)
|
|
120
|
+
selected = resolve(:buffer)
|
|
140
121
|
print selected if selected
|
|
141
122
|
end
|
|
142
123
|
end
|
data/bin/h-jumplist
CHANGED
|
@@ -174,14 +174,6 @@ Hiiro.run(*ARGV) do
|
|
|
174
174
|
entries = read_entries
|
|
175
175
|
pos = get_pos
|
|
176
176
|
|
|
177
|
-
# Deduplicate: skip if current position entry matches pane/window/session
|
|
178
|
-
current_entry = entries[pos]
|
|
179
|
-
if current_entry
|
|
180
|
-
current_parts = current_entry.split('|')
|
|
181
|
-
current_key = current_parts[0..2]
|
|
182
|
-
next if current_key == [pane_id, window_id, session_name]
|
|
183
|
-
end
|
|
184
|
-
|
|
185
177
|
# If position is not at head, truncate forward history
|
|
186
178
|
if pos > 0 && entries.any?
|
|
187
179
|
entries = entries[pos..]
|
|
@@ -190,13 +182,48 @@ Hiiro.run(*ARGV) do
|
|
|
190
182
|
set_pos(0)
|
|
191
183
|
end
|
|
192
184
|
|
|
193
|
-
# Prepend new entry (newest first)
|
|
194
185
|
new_entry = [pane_id, window_id, session_name, timestamp, pane_cmd].join('|')
|
|
186
|
+
|
|
187
|
+
# Skip if the head already matches this pane (no-op navigation)
|
|
188
|
+
head_pane = entries.first&.split('|', 2)&.first
|
|
189
|
+
next if head_pane == pane_id
|
|
190
|
+
|
|
191
|
+
# Remove all earlier occurrences of this pane so it appears only once
|
|
192
|
+
entries.reject! { |e| e.split('|', 2).first == pane_id }
|
|
193
|
+
|
|
194
|
+
# Prepend new entry (newest first)
|
|
195
195
|
entries.unshift(new_entry)
|
|
196
196
|
entries = entries.first(MAX_SIZE)
|
|
197
197
|
write_entries(entries)
|
|
198
198
|
end
|
|
199
199
|
|
|
200
|
+
add_subcmd(:to) do |index = nil|
|
|
201
|
+
if index.nil?
|
|
202
|
+
puts "Usage: h jumplist to <index>"
|
|
203
|
+
next
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
entries, pos = prune_dead_entries(read_entries, get_pos)
|
|
207
|
+
|
|
208
|
+
if entries.empty?
|
|
209
|
+
system('tmux', 'display-message', 'Jumplist: empty')
|
|
210
|
+
next
|
|
211
|
+
end
|
|
212
|
+
|
|
213
|
+
idx = index.to_i
|
|
214
|
+
unless (0...entries.length).include?(idx)
|
|
215
|
+
system('tmux', 'display-message', "Jumplist: no entry at index #{idx}")
|
|
216
|
+
next
|
|
217
|
+
end
|
|
218
|
+
|
|
219
|
+
parts = entries[idx].split('|')
|
|
220
|
+
system('tmux', 'set-environment', 'TMUX_JUMPLIST_SUPPRESS', '1')
|
|
221
|
+
system('tmux', 'switch-client', '-t', parts[2])
|
|
222
|
+
system('tmux', 'select-window', '-t', parts[1])
|
|
223
|
+
system('tmux', 'select-pane', '-t', parts[0])
|
|
224
|
+
set_pos(idx)
|
|
225
|
+
end
|
|
226
|
+
|
|
200
227
|
add_subcmd(:back) do
|
|
201
228
|
entries, pos = prune_dead_entries(read_entries, get_pos)
|
|
202
229
|
|
data/bin/h-pane
CHANGED
|
@@ -5,6 +5,7 @@ require 'yaml'
|
|
|
5
5
|
|
|
6
6
|
Hiiro.run(*ARGV, plugins: [Pins]) do
|
|
7
7
|
tmux = tmux_client
|
|
8
|
+
Hiiro::Tmux.add_resolvers(self)
|
|
8
9
|
|
|
9
10
|
home_config_path = Hiiro::Config.path('pane_homes.yml')
|
|
10
11
|
|
|
@@ -54,9 +55,7 @@ Hiiro.run(*ARGV, plugins: [Pins]) do
|
|
|
54
55
|
}
|
|
55
56
|
|
|
56
57
|
add_subcmd(:kill) { |target = nil, *args|
|
|
57
|
-
|
|
58
|
-
target = fuzzyfind_from_map(tmux.panes(all: true).name_map)
|
|
59
|
-
end
|
|
58
|
+
target = resolve(:pane, target)
|
|
60
59
|
|
|
61
60
|
if target && args.empty?
|
|
62
61
|
tmux.kill_pane(target)
|
|
@@ -87,9 +86,7 @@ Hiiro.run(*ARGV, plugins: [Pins]) do
|
|
|
87
86
|
}
|
|
88
87
|
|
|
89
88
|
add_subcmd(:select) { |target = nil, *args|
|
|
90
|
-
|
|
91
|
-
target = fuzzyfind_from_map(tmux.panes(all: true).name_map)
|
|
92
|
-
end
|
|
89
|
+
target = resolve(:pane, target)
|
|
93
90
|
|
|
94
91
|
if target
|
|
95
92
|
print target
|
|
@@ -97,9 +94,7 @@ Hiiro.run(*ARGV, plugins: [Pins]) do
|
|
|
97
94
|
}
|
|
98
95
|
|
|
99
96
|
add_subcmd(:copy) { |target = nil, *args|
|
|
100
|
-
|
|
101
|
-
target = fuzzyfind_from_map(tmux.panes(all: true).name_map)
|
|
102
|
-
end
|
|
97
|
+
target = resolve(:pane, target)
|
|
103
98
|
|
|
104
99
|
if target
|
|
105
100
|
Hiiro::Shell.pipe(target, 'pbcopy')
|
|
@@ -108,7 +103,7 @@ Hiiro.run(*ARGV, plugins: [Pins]) do
|
|
|
108
103
|
}
|
|
109
104
|
|
|
110
105
|
add_subcmd(:sw, :switch) { |target = nil, *args|
|
|
111
|
-
target
|
|
106
|
+
target = resolve(:pane, target)
|
|
112
107
|
tmux.open_session(target) if target
|
|
113
108
|
}
|
|
114
109
|
|
data/bin/h-project
CHANGED
|
@@ -19,30 +19,16 @@ def start_tmux_session(session_name)
|
|
|
19
19
|
end
|
|
20
20
|
end
|
|
21
21
|
|
|
22
|
-
# Get project directories from ~/proj/
|
|
23
|
-
def project_dirs
|
|
24
|
-
Dir.glob(File.join(Dir.home, 'proj', '*/')).map { |path|
|
|
25
|
-
[File.basename(path), path]
|
|
26
|
-
}.to_h
|
|
27
|
-
end
|
|
28
|
-
|
|
29
|
-
# Get projects from config file
|
|
30
|
-
def projects_from_config
|
|
31
|
-
projects_file = File.join(Dir.home, '.config/hiiro', 'projects.yml')
|
|
32
|
-
|
|
33
|
-
return {} unless File.exist?(projects_file)
|
|
34
|
-
|
|
35
|
-
require 'yaml'
|
|
36
|
-
YAML.safe_load_file(projects_file)
|
|
37
|
-
end
|
|
38
|
-
|
|
39
22
|
Hiiro.run(*ARGV) do
|
|
23
|
+
projects = Hiiro::Projects.new
|
|
24
|
+
Hiiro::Projects.add_resolvers(self)
|
|
25
|
+
|
|
40
26
|
# === OPEN PROJECT (default) ===
|
|
41
27
|
add_subcmd(:open) { |project_name|
|
|
42
28
|
re = /#{project_name}/i
|
|
43
29
|
|
|
44
|
-
conf_matches =
|
|
45
|
-
dir_matches
|
|
30
|
+
conf_matches = projects.from_config.select { |k, v| k.match?(re) }
|
|
31
|
+
dir_matches = projects.dirs.select { |proj, path| proj.match?(re) }
|
|
46
32
|
|
|
47
33
|
matches = dir_matches.merge(conf_matches)
|
|
48
34
|
if matches.count > 1
|
|
@@ -82,15 +68,14 @@ Hiiro.run(*ARGV) do
|
|
|
82
68
|
|
|
83
69
|
# === LIST PROJECTS ===
|
|
84
70
|
add_subcmd(:list) { |*list_args|
|
|
85
|
-
|
|
86
|
-
conf =
|
|
87
|
-
|
|
88
|
-
all_projects = dirs.merge(conf)
|
|
71
|
+
all = projects.all
|
|
72
|
+
conf = projects.from_config
|
|
89
73
|
|
|
90
74
|
puts "Projects:"
|
|
91
75
|
puts
|
|
92
|
-
|
|
93
|
-
|
|
76
|
+
|
|
77
|
+
all.keys.sort.each do |name|
|
|
78
|
+
path = all[name]
|
|
94
79
|
source = conf.key?(name) ? '[config]' : '[dir]'
|
|
95
80
|
puts format(" %-12s %-8s %s", name, source, path)
|
|
96
81
|
end
|
|
@@ -102,12 +87,10 @@ Hiiro.run(*ARGV) do
|
|
|
102
87
|
|
|
103
88
|
# === SHOW CONFIG FILE ===
|
|
104
89
|
add_subcmd(:config) { |*config_args|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
if File.exist?(projects_file)
|
|
108
|
-
puts File.read(projects_file)
|
|
90
|
+
if File.exist?(Hiiro::Projects::CONFIG_FILE)
|
|
91
|
+
puts File.read(Hiiro::Projects::CONFIG_FILE)
|
|
109
92
|
else
|
|
110
|
-
puts "No config file found at: #{
|
|
93
|
+
puts "No config file found at: #{Hiiro::Projects::CONFIG_FILE}"
|
|
111
94
|
puts
|
|
112
95
|
puts "Create it with YAML format:"
|
|
113
96
|
puts " project_name: /path/to/project"
|
|
@@ -116,70 +99,88 @@ Hiiro.run(*ARGV) do
|
|
|
116
99
|
|
|
117
100
|
# === EDIT CONFIG FILE ===
|
|
118
101
|
add_subcmd(:edit) { |*edit_args|
|
|
119
|
-
|
|
120
|
-
# Create config dir if needed
|
|
121
|
-
config_dir = File.dirname(projects_file)
|
|
102
|
+
config_dir = File.dirname(Hiiro::Projects::CONFIG_FILE)
|
|
122
103
|
Dir.mkdir(config_dir) unless Dir.exist?(config_dir)
|
|
123
104
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
File.write(projects_file, "# Project aliases\n# project_name: /path/to/project\n")
|
|
105
|
+
unless File.exist?(Hiiro::Projects::CONFIG_FILE)
|
|
106
|
+
File.write(Hiiro::Projects::CONFIG_FILE, "# Project aliases\n# project_name: /path/to/project\n")
|
|
127
107
|
end
|
|
128
108
|
|
|
129
|
-
edit_files(
|
|
109
|
+
edit_files(Hiiro::Projects::CONFIG_FILE)
|
|
130
110
|
}
|
|
131
111
|
|
|
132
112
|
# === SELECT PROJECT ===
|
|
133
113
|
add_subcmd(:select) { |*select_args|
|
|
134
|
-
|
|
135
|
-
conf = projects_from_config
|
|
136
|
-
|
|
137
|
-
all_projects = dirs.merge(conf)
|
|
114
|
+
all = projects.all
|
|
138
115
|
|
|
139
|
-
if
|
|
116
|
+
if all.empty?
|
|
140
117
|
STDERR.puts "No projects found"
|
|
141
118
|
next
|
|
142
119
|
end
|
|
143
120
|
|
|
144
|
-
|
|
121
|
+
conf = projects.from_config
|
|
122
|
+
lines = all.each_with_object({}) do |(name, path), h|
|
|
145
123
|
source = conf.key?(name) ? '[config]' : '[dir]'
|
|
146
124
|
display = format("%-15s %s %s", name, source, path)
|
|
147
125
|
h[display] = path
|
|
148
126
|
end
|
|
149
127
|
|
|
150
128
|
selected = fuzzyfind_from_map(lines)
|
|
151
|
-
|
|
152
|
-
if selected
|
|
153
|
-
print selected
|
|
154
|
-
end
|
|
129
|
+
print selected if selected
|
|
155
130
|
}
|
|
156
131
|
|
|
157
132
|
# === COPY PROJECT PATH ===
|
|
158
133
|
add_subcmd(:copy) { |*copy_args|
|
|
159
|
-
|
|
160
|
-
conf = projects_from_config
|
|
161
|
-
|
|
162
|
-
all_projects = dirs.merge(conf)
|
|
134
|
+
all = projects.all
|
|
163
135
|
|
|
164
|
-
if
|
|
136
|
+
if all.empty?
|
|
165
137
|
STDERR.puts "No projects found"
|
|
166
138
|
next
|
|
167
139
|
end
|
|
168
140
|
|
|
169
|
-
|
|
141
|
+
conf = projects.from_config
|
|
142
|
+
lines = all.each_with_object({}) do |(name, path), h|
|
|
170
143
|
source = conf.key?(name) ? '[config]' : '[dir]'
|
|
171
144
|
display = format("%-15s %s %s", name, source, path)
|
|
172
145
|
h[display] = path
|
|
173
146
|
end
|
|
174
147
|
|
|
175
148
|
selected = fuzzyfind_from_map(lines)
|
|
176
|
-
|
|
177
149
|
if selected
|
|
178
150
|
Hiiro::Shell.pipe(selected, 'pbcopy')
|
|
179
151
|
puts "Copied project path '#{selected}' to clipboard"
|
|
180
152
|
end
|
|
181
153
|
}
|
|
182
154
|
|
|
155
|
+
# === SHELL IN PROJECT ===
|
|
156
|
+
add_subcmd(:sh) { |project_name=nil, *args|
|
|
157
|
+
if project_name.nil? || project_name.empty?
|
|
158
|
+
puts "Usage: h project sh <project_name> [command...]"
|
|
159
|
+
next
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
re = /#{project_name}/i
|
|
163
|
+
conf_matches = projects.from_config.select { |k, v| k.match?(re) }
|
|
164
|
+
dir_matches = projects.dirs.select { |proj, path| proj.match?(re) }
|
|
165
|
+
matches = dir_matches.merge(conf_matches)
|
|
166
|
+
matches = matches.select { |name, path| name == project_name } if matches.count > 1
|
|
167
|
+
|
|
168
|
+
case matches.count
|
|
169
|
+
when 0
|
|
170
|
+
puts "Project '#{project_name}' not found"
|
|
171
|
+
puts
|
|
172
|
+
puts "Available projects:"
|
|
173
|
+
projects.all.keys.sort.each { |k| puts " #{k}" }
|
|
174
|
+
when 1
|
|
175
|
+
_, path = matches.first
|
|
176
|
+
Dir.chdir(path)
|
|
177
|
+
args.empty? ? exec(ENV['SHELL'] || 'zsh') : exec(*args)
|
|
178
|
+
else
|
|
179
|
+
puts "Ambiguous project '#{project_name}' — multiple matches:"
|
|
180
|
+
matches.each { |name, path| puts format(" %-15s %s", name, path) }
|
|
181
|
+
end
|
|
182
|
+
}
|
|
183
|
+
|
|
183
184
|
# === HELP ===
|
|
184
185
|
add_subcmd(:help) { |*help_args|
|
|
185
186
|
puts <<~HELP
|
|
@@ -192,6 +193,7 @@ Hiiro.run(*ARGV) do
|
|
|
192
193
|
h-project ls Alias for list
|
|
193
194
|
h-project config Show config file contents
|
|
194
195
|
h-project edit Edit config file
|
|
196
|
+
h-project sh <project_name> Open shell in project directory
|
|
195
197
|
|
|
196
198
|
SOURCES:
|
|
197
199
|
Projects are discovered from two sources:
|
|
@@ -209,35 +211,6 @@ Hiiro.run(*ARGV) do
|
|
|
209
211
|
HELP
|
|
210
212
|
}
|
|
211
213
|
|
|
212
|
-
# === SHELL IN PROJECT ===
|
|
213
|
-
add_subcmd(:sh) { |project_name=nil, *args|
|
|
214
|
-
if project_name.nil? || project_name.empty?
|
|
215
|
-
puts "Usage: h project sh <project_name> [command...]"
|
|
216
|
-
next
|
|
217
|
-
end
|
|
218
|
-
|
|
219
|
-
re = /#{project_name}/i
|
|
220
|
-
conf_matches = (projects_from_config || {}).select { |k, v| k.match?(re) }
|
|
221
|
-
dir_matches = (project_dirs || {}).select { |proj, path| proj.match?(re) }
|
|
222
|
-
matches = dir_matches.merge(conf_matches)
|
|
223
|
-
matches = matches.select { |name, path| name == project_name } if matches.count > 1
|
|
224
|
-
|
|
225
|
-
case matches.count
|
|
226
|
-
when 0
|
|
227
|
-
puts "Project '#{project_name}' not found"
|
|
228
|
-
puts
|
|
229
|
-
puts "Available projects:"
|
|
230
|
-
project_dirs.merge(projects_from_config).keys.sort.each { |k| puts " #{k}" }
|
|
231
|
-
when 1
|
|
232
|
-
_, path = matches.first
|
|
233
|
-
Dir.chdir(path)
|
|
234
|
-
args.empty? ? exec(ENV['SHELL'] || 'zsh') : exec(*args)
|
|
235
|
-
else
|
|
236
|
-
puts "Ambiguous project '#{project_name}' — multiple matches:"
|
|
237
|
-
matches.each { |name, path| puts format(" %-15s %s", name, path) }
|
|
238
|
-
end
|
|
239
|
-
}
|
|
240
|
-
|
|
241
214
|
add_default {
|
|
242
215
|
run_subcmd(:help)
|
|
243
216
|
}
|
data/bin/h-session
CHANGED
|
@@ -6,6 +6,7 @@ require 'yaml'
|
|
|
6
6
|
|
|
7
7
|
Hiiro.run(*ARGV, tasks: true, plugins: [Pins]) do
|
|
8
8
|
tmux = tmux_client
|
|
9
|
+
Hiiro::Tmux.add_resolvers(self)
|
|
9
10
|
|
|
10
11
|
add_subcmd(:ls, :list) { |*args|
|
|
11
12
|
if args.empty?
|
|
@@ -24,9 +25,7 @@ Hiiro.run(*ARGV, tasks: true, plugins: [Pins]) do
|
|
|
24
25
|
}
|
|
25
26
|
|
|
26
27
|
add_subcmd(:kill) { |name = nil, *args|
|
|
27
|
-
|
|
28
|
-
name = fuzzyfind_from_map(tmux.sessions.name_map)
|
|
29
|
-
end
|
|
28
|
+
name = resolve(:session, name)
|
|
30
29
|
|
|
31
30
|
if name && args.empty?
|
|
32
31
|
tmux.kill_session(name)
|
|
@@ -36,9 +35,7 @@ Hiiro.run(*ARGV, tasks: true, plugins: [Pins]) do
|
|
|
36
35
|
}
|
|
37
36
|
|
|
38
37
|
add_subcmd(:attach) { |name = nil, *args|
|
|
39
|
-
|
|
40
|
-
name = fuzzyfind_from_map(tmux.sessions.name_map)
|
|
41
|
-
end
|
|
38
|
+
name = resolve(:session, name)
|
|
42
39
|
|
|
43
40
|
if name && args.empty?
|
|
44
41
|
tmux.attach_session(name)
|
|
@@ -48,9 +45,7 @@ Hiiro.run(*ARGV, tasks: true, plugins: [Pins]) do
|
|
|
48
45
|
}
|
|
49
46
|
|
|
50
47
|
add_subcmd(:rename) { |old_name = nil, new_name = nil, *args|
|
|
51
|
-
|
|
52
|
-
old_name = fuzzyfind_from_map(tmux.sessions.name_map)
|
|
53
|
-
end
|
|
48
|
+
old_name = resolve(:session, old_name)
|
|
54
49
|
|
|
55
50
|
if old_name && new_name && args.empty?
|
|
56
51
|
tmux.rename_session(old_name, new_name)
|
|
@@ -60,9 +55,7 @@ Hiiro.run(*ARGV, tasks: true, plugins: [Pins]) do
|
|
|
60
55
|
}
|
|
61
56
|
|
|
62
57
|
add_subcmd(:switch) { |name = nil, *args|
|
|
63
|
-
|
|
64
|
-
name = fuzzyfind_from_map(tmux.sessions.name_map)
|
|
65
|
-
end
|
|
58
|
+
name = resolve(:session, name)
|
|
66
59
|
|
|
67
60
|
if name
|
|
68
61
|
tmux.open_session(name)
|
|
@@ -105,24 +98,12 @@ Hiiro.run(*ARGV, tasks: true, plugins: [Pins]) do
|
|
|
105
98
|
}
|
|
106
99
|
|
|
107
100
|
add_subcmd(:select) do
|
|
108
|
-
|
|
109
|
-
if sessions.empty?
|
|
110
|
-
STDERR.puts "No sessions found"
|
|
111
|
-
next
|
|
112
|
-
end
|
|
113
|
-
|
|
114
|
-
selected = fuzzyfind_from_map(sessions.name_map)
|
|
101
|
+
selected = resolve(:session)
|
|
115
102
|
print selected if selected
|
|
116
103
|
end
|
|
117
104
|
|
|
118
105
|
add_subcmd(:copy) do
|
|
119
|
-
|
|
120
|
-
if sessions.empty?
|
|
121
|
-
STDERR.puts "No sessions found"
|
|
122
|
-
next
|
|
123
|
-
end
|
|
124
|
-
|
|
125
|
-
selected = fuzzyfind_from_map(sessions.name_map)
|
|
106
|
+
selected = resolve(:session)
|
|
126
107
|
if selected
|
|
127
108
|
Hiiro::Shell.pipe(selected, 'pbcopy')
|
|
128
109
|
puts "Copied session '#{selected}' to clipboard"
|
data/bin/h-window
CHANGED
|
@@ -4,6 +4,7 @@ require 'hiiro'
|
|
|
4
4
|
|
|
5
5
|
Hiiro.run(*ARGV, plugins: [Pins]) do
|
|
6
6
|
tmux = tmux_client
|
|
7
|
+
Hiiro::Tmux.add_resolvers(self)
|
|
7
8
|
|
|
8
9
|
add_subcmd(:ls) { |*args|
|
|
9
10
|
if args.empty?
|
|
@@ -30,9 +31,7 @@ Hiiro.run(*ARGV, plugins: [Pins]) do
|
|
|
30
31
|
}
|
|
31
32
|
|
|
32
33
|
add_subcmd(:kill) { |target = nil, *args|
|
|
33
|
-
|
|
34
|
-
target = fuzzyfind_from_map(tmux.windows(all: true).name_map)
|
|
35
|
-
end
|
|
34
|
+
target = resolve(:window, target)
|
|
36
35
|
|
|
37
36
|
if target && args.empty?
|
|
38
37
|
tmux.kill_window(target)
|
|
@@ -54,9 +53,7 @@ Hiiro.run(*ARGV, plugins: [Pins]) do
|
|
|
54
53
|
}
|
|
55
54
|
|
|
56
55
|
add_subcmd(:select) { |target = nil, *args|
|
|
57
|
-
|
|
58
|
-
target = fuzzyfind_from_map(tmux.windows(all: true).name_map)
|
|
59
|
-
end
|
|
56
|
+
target = resolve(:window, target)
|
|
60
57
|
|
|
61
58
|
if target
|
|
62
59
|
print target
|
|
@@ -64,9 +61,7 @@ Hiiro.run(*ARGV, plugins: [Pins]) do
|
|
|
64
61
|
}
|
|
65
62
|
|
|
66
63
|
add_subcmd(:copy) { |target = nil, *args|
|
|
67
|
-
|
|
68
|
-
target = fuzzyfind_from_map(tmux.windows(all: true).name_map)
|
|
69
|
-
end
|
|
64
|
+
target = resolve(:window, target)
|
|
70
65
|
|
|
71
66
|
if target
|
|
72
67
|
Hiiro::Shell.pipe(target, 'pbcopy')
|
|
@@ -75,9 +70,7 @@ Hiiro.run(*ARGV, plugins: [Pins]) do
|
|
|
75
70
|
}
|
|
76
71
|
|
|
77
72
|
add_subcmd(:sw, :switch) { |target = nil, *args|
|
|
78
|
-
|
|
79
|
-
target = fuzzyfind_from_map(tmux.windows(all: true).name_map)
|
|
80
|
-
end
|
|
73
|
+
target = resolve(:window, target)
|
|
81
74
|
|
|
82
75
|
if target
|
|
83
76
|
tmux.open_session(target)
|
data/lib/hiiro/options.rb
CHANGED
|
@@ -51,16 +51,27 @@ class Hiiro
|
|
|
51
51
|
|
|
52
52
|
def flag(name, long: nil, short: nil, default: false, desc: nil)
|
|
53
53
|
defn = Definition.new(name, long: long, short: short, type: :flag, default: default, desc: desc)
|
|
54
|
+
deconflict_short(short) if short
|
|
54
55
|
@definitions[name.to_sym] = defn
|
|
55
56
|
self
|
|
56
57
|
end
|
|
57
58
|
|
|
58
|
-
def option(name, long: nil, short: nil, type: :string, default: nil, desc: nil, multi: false)
|
|
59
|
-
defn = Definition.new(name, long: long, short: short, type: type, default: default, desc: desc, multi: multi)
|
|
59
|
+
def option(name, long: nil, short: nil, type: :string, default: nil, desc: nil, multi: false, flag_ifs: [])
|
|
60
|
+
defn = Definition.new(name, long: long, short: short, type: type, default: default, desc: desc, multi: multi, flag_ifs: Array(flag_ifs))
|
|
61
|
+
deconflict_short(short) if short
|
|
60
62
|
@definitions[name.to_sym] = defn
|
|
61
63
|
self
|
|
62
64
|
end
|
|
63
65
|
|
|
66
|
+
private
|
|
67
|
+
|
|
68
|
+
def deconflict_short(short)
|
|
69
|
+
short_s = short.to_s
|
|
70
|
+
@definitions.each_value { |d| d.short = nil if d.short == short_s }
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
public
|
|
74
|
+
|
|
64
75
|
def select(names)
|
|
65
76
|
subset = self.class.setup {}
|
|
66
77
|
names.each do |name|
|
|
@@ -170,7 +181,7 @@ class Hiiro
|
|
|
170
181
|
defn = @definitions.values.find { |d| d.long_form == flag_part }
|
|
171
182
|
return unless defn
|
|
172
183
|
|
|
173
|
-
if defn.flag?
|
|
184
|
+
if defn.flag? || defn.flag_active?(@values)
|
|
174
185
|
@values[defn.name] = !defn.default
|
|
175
186
|
else
|
|
176
187
|
value ||= args.shift
|
|
@@ -185,7 +196,7 @@ class Hiiro
|
|
|
185
196
|
defn = @definitions.values.find { |d| d.short == char }
|
|
186
197
|
next unless defn
|
|
187
198
|
|
|
188
|
-
if defn.flag?
|
|
199
|
+
if defn.flag? || defn.flag_active?(@values)
|
|
189
200
|
@values[defn.name] = !defn.default
|
|
190
201
|
elsif idx == chars.length - 1
|
|
191
202
|
store_value(defn, args.shift)
|
|
@@ -207,9 +218,10 @@ class Hiiro
|
|
|
207
218
|
end
|
|
208
219
|
|
|
209
220
|
class Definition
|
|
210
|
-
attr_reader :name, :
|
|
221
|
+
attr_reader :name, :long, :type, :default, :desc, :multi, :flag_ifs
|
|
222
|
+
attr_accessor :short
|
|
211
223
|
|
|
212
|
-
def initialize(name, short: nil, long: nil, type: :string, default: nil, desc: nil, multi: false)
|
|
224
|
+
def initialize(name, short: nil, long: nil, type: :string, default: nil, desc: nil, multi: false, flag_ifs: [])
|
|
213
225
|
@name = name.to_sym
|
|
214
226
|
@short = short&.to_s
|
|
215
227
|
@long = long&.to_sym
|
|
@@ -217,6 +229,11 @@ class Hiiro
|
|
|
217
229
|
@default = default
|
|
218
230
|
@desc = desc
|
|
219
231
|
@multi = multi
|
|
232
|
+
@flag_ifs = flag_ifs.map(&:to_sym)
|
|
233
|
+
end
|
|
234
|
+
|
|
235
|
+
def flag_active?(values)
|
|
236
|
+
@flag_ifs.any? { |f| values[f] }
|
|
220
237
|
end
|
|
221
238
|
|
|
222
239
|
def flag?
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
require 'yaml'
|
|
2
|
+
|
|
3
|
+
class Hiiro
|
|
4
|
+
class Projects
|
|
5
|
+
CONFIG_FILE = File.join(Dir.home, '.config', 'hiiro', 'projects.yml')
|
|
6
|
+
|
|
7
|
+
def self.add_resolvers(hiiro)
|
|
8
|
+
pm = new
|
|
9
|
+
hiiro.add_resolver(:project,
|
|
10
|
+
-> {
|
|
11
|
+
all = pm.all
|
|
12
|
+
return nil if all.empty?
|
|
13
|
+
conf = pm.from_config
|
|
14
|
+
lines = all.each_with_object({}) do |(name, path), h|
|
|
15
|
+
source = conf.key?(name) ? '[config]' : '[dir]'
|
|
16
|
+
h[format("%-15s %-8s %s", name, source, path)] = path
|
|
17
|
+
end
|
|
18
|
+
hiiro.fuzzyfind_from_map(lines)
|
|
19
|
+
}
|
|
20
|
+
) do |name|
|
|
21
|
+
pm.find(name)
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def dirs
|
|
26
|
+
Dir.glob(File.join(Dir.home, 'proj', '*/')).map { |path|
|
|
27
|
+
[File.basename(path), path]
|
|
28
|
+
}.to_h
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def from_config
|
|
32
|
+
return {} unless File.exist?(CONFIG_FILE)
|
|
33
|
+
YAML.safe_load_file(CONFIG_FILE) || {}
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def from_config?(name)
|
|
37
|
+
from_config.key?(name)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def all
|
|
41
|
+
dirs.merge(from_config)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
# Find a project path by name (regex match, exact-match tiebreak).
|
|
45
|
+
# Returns the path string, or nil if 0 or >1 matches.
|
|
46
|
+
def find(name)
|
|
47
|
+
re = /#{name}/i
|
|
48
|
+
conf = from_config
|
|
49
|
+
matches = dirs.select { |k, _| k.match?(re) }.merge(conf.select { |k, _| k.match?(re) })
|
|
50
|
+
matches = matches.select { |k, _| k == name } if matches.count > 1
|
|
51
|
+
matches.count == 1 ? matches.values.first : nil
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
data/lib/hiiro/queue.rb
CHANGED
|
@@ -304,7 +304,7 @@ class Hiiro
|
|
|
304
304
|
end
|
|
305
305
|
|
|
306
306
|
def resolve_task_info(opts, hiiro, default_task_info)
|
|
307
|
-
if opts.
|
|
307
|
+
if opts.find
|
|
308
308
|
selection = select_task_or_session(hiiro)
|
|
309
309
|
if selection
|
|
310
310
|
case selection[:type]
|
|
@@ -314,7 +314,7 @@ class Hiiro
|
|
|
314
314
|
else
|
|
315
315
|
default_task_info
|
|
316
316
|
end
|
|
317
|
-
elsif opts.task
|
|
317
|
+
elsif opts.task.is_a?(String)
|
|
318
318
|
task_info_for(opts.task)
|
|
319
319
|
else
|
|
320
320
|
default_task_info
|
|
@@ -523,11 +523,13 @@ class Hiiro
|
|
|
523
523
|
do_add = lambda do |args, split: nil|
|
|
524
524
|
q.queue_dirs
|
|
525
525
|
opts = Hiiro::Options.parse(args) do
|
|
526
|
-
option(:task,
|
|
527
|
-
option(:name,
|
|
528
|
-
flag(:
|
|
529
|
-
flag(:
|
|
530
|
-
flag(:
|
|
526
|
+
option(:task, short: :t, desc: 'Task name', flag_ifs: [:find])
|
|
527
|
+
option(:name, short: :n, desc: 'Base filename for the queue task')
|
|
528
|
+
flag(:find, short: :f, desc: 'Choose task/session interactively (fuzzyfind)')
|
|
529
|
+
flag(:horizontal, short: :h, desc: 'Split horizontally in the current tmux window')
|
|
530
|
+
flag(:vertical, short: :v, desc: 'Split vertically in the current tmux window')
|
|
531
|
+
flag(:session, short: :s, desc: 'Use current tmux session')
|
|
532
|
+
flag(:ignore, short: :i, desc: 'Background task — close window when done, no shell')
|
|
531
533
|
end
|
|
532
534
|
|
|
533
535
|
if opts.help?
|
|
@@ -535,6 +537,9 @@ class Hiiro
|
|
|
535
537
|
exit 1
|
|
536
538
|
end
|
|
537
539
|
|
|
540
|
+
split ||= :hsplit if opts.horizontal
|
|
541
|
+
split ||= :vsplit if opts.vertical
|
|
542
|
+
|
|
538
543
|
args = opts.args
|
|
539
544
|
ti = q.resolve_task_info(opts, h, task_info)
|
|
540
545
|
|
|
@@ -543,6 +548,47 @@ class Hiiro
|
|
|
543
548
|
ti = (ti || {}).merge(session_name: session_name) if session_name
|
|
544
549
|
end
|
|
545
550
|
|
|
551
|
+
# Split+interactive: open editor AND run claude in a new tmux pane
|
|
552
|
+
if split && args.empty? && $stdin.tty?
|
|
553
|
+
fm_lines = ["---"]
|
|
554
|
+
fm_lines << "task_name: #{ti[:task_name]}" if ti&.dig(:task_name)
|
|
555
|
+
fm_lines << "tree_name: #{ti[:tree_name]}" if ti&.dig(:tree_name)
|
|
556
|
+
fm_lines << "session_name: #{ti[:session_name]}" if ti&.dig(:session_name)
|
|
557
|
+
fm_lines << "ignore: true" if opts.ignore
|
|
558
|
+
fm_lines << "# app: <partial-app-name> (run claude from this app's directory)"
|
|
559
|
+
fm_lines << "# dir: <relative-path> (subdir within app or tree root)"
|
|
560
|
+
fm_lines << "---"
|
|
561
|
+
fm_lines << ""
|
|
562
|
+
|
|
563
|
+
tmp_dir = File.join(Dir.home, '.config/hiiro/tmp')
|
|
564
|
+
FileUtils.mkdir_p(tmp_dir)
|
|
565
|
+
base = File.join(tmp_dir, "hq-#{Time.now.strftime('%Y%m%d%H%M%S%L')}")
|
|
566
|
+
prompt_path = "#{base}.md"
|
|
567
|
+
script_path = "#{base}.sh"
|
|
568
|
+
File.write(prompt_path, fm_lines.join("\n"))
|
|
569
|
+
|
|
570
|
+
orig_pane = `tmux display-message -p '\#{pane_id}'`.strip
|
|
571
|
+
split_flag = split == :hsplit ? '-v' : '-h'
|
|
572
|
+
claude_cmd = opts.ignore ? 'claude -p' : 'claude'
|
|
573
|
+
shell_line = opts.ignore ? '' : "exec ${SHELL:-zsh}"
|
|
574
|
+
|
|
575
|
+
File.write(script_path, <<~SH)
|
|
576
|
+
#!/usr/bin/env bash
|
|
577
|
+
${EDITOR:-vim} #{Shellwords.shellescape(prompt_path)}
|
|
578
|
+
tmux select-pane -t #{Shellwords.shellescape(orig_pane)}
|
|
579
|
+
if [ -s #{Shellwords.shellescape(prompt_path)} ]; then
|
|
580
|
+
cat #{Shellwords.shellescape(prompt_path)} | #{claude_cmd}
|
|
581
|
+
fi
|
|
582
|
+
rm -f #{Shellwords.shellescape(prompt_path)} #{Shellwords.shellescape(script_path)}
|
|
583
|
+
#{shell_line}
|
|
584
|
+
SH
|
|
585
|
+
FileUtils.chmod(0755, script_path)
|
|
586
|
+
|
|
587
|
+
new_pane = `tmux split-window #{split_flag} -P -F '\#{pane_id}' #{Shellwords.shellescape(script_path)} 2>/dev/null`.strip
|
|
588
|
+
system('tmux', 'select-pane', '-t', new_pane) unless new_pane.empty?
|
|
589
|
+
next
|
|
590
|
+
end
|
|
591
|
+
|
|
546
592
|
if args.empty? && !$stdin.tty?
|
|
547
593
|
content = $stdin.read.strip
|
|
548
594
|
elsif args.any?
|
|
@@ -590,9 +636,9 @@ class Hiiro
|
|
|
590
636
|
h.add_subcmd(:wip) { |*args|
|
|
591
637
|
q.queue_dirs
|
|
592
638
|
opts = Hiiro::Options.parse(args) do
|
|
593
|
-
option(:task,
|
|
594
|
-
flag(:
|
|
595
|
-
flag(:session,
|
|
639
|
+
option(:task, short: :t, desc: 'Task name', flag_ifs: [:find])
|
|
640
|
+
flag(:find, short: :f, desc: 'Choose task/session interactively (fuzzyfind)')
|
|
641
|
+
flag(:session, short: :s, desc: 'Use current tmux session')
|
|
596
642
|
end
|
|
597
643
|
args = opts.args
|
|
598
644
|
ti = q.resolve_task_info(opts, h, task_info)
|
data/lib/hiiro/tasks.rb
CHANGED
|
@@ -6,6 +6,16 @@ class Hiiro
|
|
|
6
6
|
TASKS_DIR = File.join(Dir.home, '.config', 'hiiro', 'tasks')
|
|
7
7
|
APPS_FILE = File.join(Dir.home, '.config', 'hiiro', 'apps.yml')
|
|
8
8
|
|
|
9
|
+
def self.add_resolvers(hiiro, scope: :task)
|
|
10
|
+
tm = new(hiiro, scope: scope)
|
|
11
|
+
hiiro.add_resolver(:task,
|
|
12
|
+
-> { tm.select_task_interactive }
|
|
13
|
+
) { |name|
|
|
14
|
+
task = tm.task_by_name(name)
|
|
15
|
+
task&.name || name
|
|
16
|
+
}
|
|
17
|
+
end
|
|
18
|
+
|
|
9
19
|
attr_reader :hiiro, :scope, :environment
|
|
10
20
|
|
|
11
21
|
def initialize(hiiro, scope: :task, environment: nil)
|
|
@@ -937,6 +947,18 @@ class Hiiro
|
|
|
937
947
|
print task.session_name if task.session_name
|
|
938
948
|
end
|
|
939
949
|
|
|
950
|
+
h.add_subcmd(:sh) do |task_name=nil, *args|
|
|
951
|
+
task = task_name ? tm.task_by_name(task_name) : tm.current_task
|
|
952
|
+
unless task
|
|
953
|
+
puts task_name ? "Task '#{task_name}' not found" : "Not in a task session"
|
|
954
|
+
next
|
|
955
|
+
end
|
|
956
|
+
tree = tm.environment.find_tree(task.tree_name)
|
|
957
|
+
path = tree ? tree.path : File.join(Hiiro::WORK_DIR, task.tree_name)
|
|
958
|
+
Dir.chdir(path)
|
|
959
|
+
args.empty? ? exec(ENV['SHELL'] || 'zsh') : exec(*args)
|
|
960
|
+
end
|
|
961
|
+
|
|
940
962
|
h.add_subcmd(:status) { tm.status }
|
|
941
963
|
h.add_subcmd(:st) { tm.status }
|
|
942
964
|
|
data/lib/hiiro/tmux.rb
CHANGED
|
@@ -27,6 +27,32 @@ class Hiiro
|
|
|
27
27
|
client.open_session(name, **opts)
|
|
28
28
|
end
|
|
29
29
|
|
|
30
|
+
def self.add_resolvers(hiiro)
|
|
31
|
+
hiiro.add_resolver(:pane,
|
|
32
|
+
-> { hiiro.fuzzyfind_from_map(hiiro.tmux_client.panes(all: true).name_map) }
|
|
33
|
+
) { |ref| ref }
|
|
34
|
+
|
|
35
|
+
hiiro.add_resolver(:window,
|
|
36
|
+
-> { hiiro.fuzzyfind_from_map(hiiro.tmux_client.windows(all: true).name_map) }
|
|
37
|
+
) { |ref| ref }
|
|
38
|
+
|
|
39
|
+
hiiro.add_resolver(:session,
|
|
40
|
+
-> { hiiro.fuzzyfind_from_map(hiiro.tmux_client.sessions.name_map) }
|
|
41
|
+
) { |ref| ref }
|
|
42
|
+
|
|
43
|
+
hiiro.add_resolver(:buffer,
|
|
44
|
+
-> {
|
|
45
|
+
buffers = hiiro.tmux_client.buffers
|
|
46
|
+
return nil if buffers.empty?
|
|
47
|
+
hiiro.fuzzyfind_from_map(buffers.name_map)
|
|
48
|
+
}
|
|
49
|
+
) { |ref|
|
|
50
|
+
buffers = hiiro.tmux_client.buffers
|
|
51
|
+
matching = buffers.matching(ref)
|
|
52
|
+
matching.size == 1 ? matching.first.name : ref
|
|
53
|
+
}
|
|
54
|
+
end
|
|
55
|
+
|
|
30
56
|
attr_reader :hiiro
|
|
31
57
|
|
|
32
58
|
def initialize(hiiro = nil)
|
data/lib/hiiro/version.rb
CHANGED
data/lib/hiiro.rb
CHANGED
data/plugins/project.rb
CHANGED
|
@@ -2,72 +2,32 @@
|
|
|
2
2
|
|
|
3
3
|
module Project
|
|
4
4
|
def self.load(hiiro)
|
|
5
|
-
# hiiro.load_plugin(Tmux)
|
|
6
|
-
attach_methods(hiiro)
|
|
7
5
|
add_subcommands(hiiro)
|
|
8
6
|
end
|
|
9
7
|
|
|
10
8
|
def self.add_subcommands(hiiro)
|
|
11
9
|
hiiro.add_subcmd(:project) do |project_name|
|
|
12
|
-
|
|
10
|
+
projects = Hiiro::Projects.new
|
|
11
|
+
path = projects.find(project_name.to_s)
|
|
13
12
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
puts(conf_matches:,dir_matches:)
|
|
18
|
-
matches = dir_matches.merge(conf_matches)
|
|
19
|
-
if matches.count > 1
|
|
20
|
-
matches = matches.select{|name, path| name == project_name }
|
|
21
|
-
end
|
|
22
|
-
|
|
23
|
-
puts matches_two: matches
|
|
24
|
-
case matches.count
|
|
25
|
-
when 0
|
|
13
|
+
if path.nil?
|
|
14
|
+
# Fall back to ~/proj root
|
|
26
15
|
name = 'proj'
|
|
27
16
|
path = File.join(Dir.home, 'proj')
|
|
28
|
-
|
|
29
17
|
unless Dir.exist?(path)
|
|
30
18
|
puts "Error: #{path.inspect} does not exist"
|
|
31
19
|
exit 1
|
|
32
20
|
end
|
|
33
|
-
|
|
34
|
-
puts "changing dir: #{path}"
|
|
35
|
-
Dir.chdir(path)
|
|
36
|
-
|
|
37
|
-
hiiro.start_tmux_session(name)
|
|
38
|
-
when 1
|
|
39
|
-
name, path = matches.first
|
|
40
|
-
|
|
41
21
|
puts "changing dir: #{path}"
|
|
42
22
|
Dir.chdir(path)
|
|
43
|
-
|
|
44
23
|
hiiro.start_tmux_session(name)
|
|
45
|
-
|
|
46
|
-
puts "ERROR: Multiple matches found"
|
|
47
|
-
puts
|
|
48
|
-
puts "Matches:"
|
|
49
|
-
matches.each { |name, path|
|
|
50
|
-
puts format(" %s: %s", name, path)
|
|
51
|
-
}
|
|
24
|
+
next
|
|
52
25
|
end
|
|
53
|
-
end
|
|
54
|
-
end
|
|
55
26
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
[File.basename(path), path]
|
|
61
|
-
}.to_h
|
|
62
|
-
end
|
|
63
|
-
|
|
64
|
-
def projects_from_config
|
|
65
|
-
projects_file = File.join(Dir.home, '.config/hiiro', 'projects.yml')
|
|
66
|
-
|
|
67
|
-
return {} unless File.exist?(projects_file)
|
|
68
|
-
|
|
69
|
-
YAML.safe_load_file(projects_file)
|
|
70
|
-
end
|
|
27
|
+
name = project_name.to_s
|
|
28
|
+
puts "changing dir: #{path}"
|
|
29
|
+
Dir.chdir(path)
|
|
30
|
+
hiiro.start_tmux_session(name)
|
|
71
31
|
end
|
|
72
32
|
end
|
|
73
33
|
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: hiiro
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.280
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Joshua Toyota
|
|
@@ -271,6 +271,7 @@ files:
|
|
|
271
271
|
- lib/hiiro/options.rb
|
|
272
272
|
- lib/hiiro/paths.rb
|
|
273
273
|
- lib/hiiro/pinned_pr_manager.rb
|
|
274
|
+
- lib/hiiro/projects.rb
|
|
274
275
|
- lib/hiiro/queue.rb
|
|
275
276
|
- lib/hiiro/rbenv.rb
|
|
276
277
|
- lib/hiiro/runner_tool.rb
|