rufio 1.1.0 → 1.3.0
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 +34 -0
- data/README.md +74 -3
- data/README_ja.md +71 -2
- data/Rakefile +14 -1
- data/bin/rufio +31 -2
- data/docs/fast_zip_design_ja.md +167 -0
- data/info/help.md +2 -0
- data/info/keybindings.md +3 -1
- data/info/welcome.md +1 -1
- data/lib/rufio/application.rb +12 -1
- data/lib/rufio/archive_controller.rb +211 -0
- data/lib/rufio/background_command_executor.rb +9 -0
- data/lib/rufio/background_status.rb +49 -0
- data/lib/rufio/bookmark_controller.rb +38 -121
- data/lib/rufio/bookmark_manager.rb +77 -331
- data/lib/rufio/command_completion.rb +6 -1
- data/lib/rufio/command_history.rb +5 -2
- data/lib/rufio/command_mode.rb +40 -134
- data/lib/rufio/command_mode_ui.rb +4 -42
- data/lib/rufio/config.rb +88 -136
- data/lib/rufio/config_loader.rb +3 -11
- data/lib/rufio/dialog_renderer.rb +64 -152
- data/lib/rufio/dialog_support.rb +69 -0
- data/lib/rufio/document_text_extractor.rb +167 -0
- data/lib/rufio/file_operation_controller.rb +49 -222
- data/lib/rufio/file_preview.rb +46 -2
- data/lib/rufio/global_search.rb +121 -9
- data/lib/rufio/help_menu.rb +8 -2
- data/lib/rufio/interpreter_resolver.rb +6 -11
- data/lib/rufio/job_manager.rb +2 -5
- data/lib/rufio/key_input.rb +77 -0
- data/lib/rufio/keybind_handler.rb +81 -115
- data/lib/rufio/local_script_scanner.rb +6 -18
- data/lib/rufio/native/aarch64-linux-gnu/librufio_zig.so +0 -0
- data/lib/rufio/native/aarch64-linux-musl/librufio_zig.so +0 -0
- data/lib/rufio/native/aarch64-macos/librufio_zig.dylib +0 -0
- data/lib/rufio/native/aarch64-windows/rufio_zig.dll +0 -0
- data/lib/rufio/native/x86_64-linux-gnu/librufio_zig.so +0 -0
- data/lib/rufio/native/x86_64-linux-musl/librufio_zig.so +0 -0
- data/lib/rufio/native/x86_64-macos/librufio_zig.dylib +0 -0
- data/lib/rufio/native/x86_64-windows/rufio_zig.dll +0 -0
- data/lib/rufio/native_content_search.rb +153 -0
- data/lib/rufio/native_scanner.rb +13 -68
- data/lib/rufio/native_scanner_zig.rb +106 -56
- data/lib/rufio/native_zip.rb +121 -0
- data/lib/rufio/navigation_controller.rb +18 -20
- data/lib/rufio/screen.rb +2 -12
- data/lib/rufio/script_executor.rb +6 -73
- data/lib/rufio/script_file.rb +44 -0
- data/lib/rufio/script_path_manager.rb +9 -43
- data/lib/rufio/script_runner.rb +13 -50
- data/lib/rufio/search_controller.rb +1 -1
- data/lib/rufio/shell_command_completion.rb +1 -5
- data/lib/rufio/shell_init.rb +90 -0
- data/lib/rufio/task_status.rb +5 -1
- data/lib/rufio/terminal_ui.rb +55 -294
- data/lib/rufio/text_utils.rb +26 -3
- data/lib/rufio/ui_renderer.rb +63 -40
- data/lib/rufio/version.rb +1 -1
- data/lib/rufio/zip_archive.rb +314 -0
- data/lib/rufio/zip_extractor.rb +346 -0
- data/lib/rufio/zip_writer.rb +268 -0
- data/lib/rufio/zoxide_integration.rb +5 -43
- data/lib/rufio.rb +5 -0
- data/lib_zig/rufio_native/Makefile +54 -17
- data/lib_zig/rufio_native/bench.sh +36 -0
- data/lib_zig/rufio_native/build.zig +32 -35
- data/lib_zig/rufio_native/src/cli.zig +99 -0
- data/lib_zig/rufio_native/src/main.zig +187 -83
- data/lib_zig/rufio_native/src/os.zig +889 -0
- data/lib_zig/rufio_native/src/search.zig +919 -0
- data/lib_zig/rufio_native/src/search_test.zig +88 -0
- data/lib_zig/rufio_native/src/zip.zig +482 -0
- metadata +125 -3
- data/lib/rufio/native/rufio_zig.bundle +0 -0
data/lib/rufio/screen.rb
CHANGED
|
@@ -229,12 +229,7 @@ module Rufio
|
|
|
229
229
|
return if out_of_bounds?(x, y)
|
|
230
230
|
|
|
231
231
|
char_width = width || TextUtils.display_width(char)
|
|
232
|
-
@overlay_cells[y][x] =
|
|
233
|
-
char: char,
|
|
234
|
-
fg: fg,
|
|
235
|
-
bg: bg,
|
|
236
|
-
width: char_width
|
|
237
|
-
}
|
|
232
|
+
@overlay_cells[y][x] = Cell.new(char, fg, bg, char_width)
|
|
238
233
|
|
|
239
234
|
@dirty_rows.add(y)
|
|
240
235
|
|
|
@@ -243,12 +238,7 @@ module Rufio
|
|
|
243
238
|
(char_width - 1).times do |offset|
|
|
244
239
|
next_x = x + 1 + offset
|
|
245
240
|
break if next_x >= @width
|
|
246
|
-
@overlay_cells[y][next_x] =
|
|
247
|
-
char: '',
|
|
248
|
-
fg: nil,
|
|
249
|
-
bg: nil,
|
|
250
|
-
width: 0
|
|
251
|
-
}
|
|
241
|
+
@overlay_cells[y][next_x] = Cell.new('', nil, nil, 0)
|
|
252
242
|
end
|
|
253
243
|
end
|
|
254
244
|
end
|
|
@@ -83,11 +83,7 @@ module Rufio
|
|
|
83
83
|
options[:chdir] = chdir if chdir
|
|
84
84
|
spawn_env = env || {}
|
|
85
85
|
|
|
86
|
-
|
|
87
|
-
execute_shell_with_timeout(dsl_command.shell_command, spawn_env, options, timeout)
|
|
88
|
-
else
|
|
89
|
-
execute_shell_without_timeout(dsl_command.shell_command, spawn_env, options)
|
|
90
|
-
end
|
|
86
|
+
execute_with_options([dsl_command.shell_command], spawn_env, options, timeout)
|
|
91
87
|
rescue StandardError => e
|
|
92
88
|
build_error_result(e)
|
|
93
89
|
end
|
|
@@ -133,8 +129,11 @@ module Rufio
|
|
|
133
129
|
# プロセスを終了
|
|
134
130
|
if pid
|
|
135
131
|
begin
|
|
136
|
-
|
|
137
|
-
|
|
132
|
+
# Windows は TERM を送れない(Errno::EINVAL)ため KILL だけで終了させる
|
|
133
|
+
unless Gem.win_platform?
|
|
134
|
+
Process.kill("TERM", pid)
|
|
135
|
+
sleep 0.1
|
|
136
|
+
end
|
|
138
137
|
Process.kill("KILL", pid)
|
|
139
138
|
rescue Errno::ESRCH, Errno::EPERM
|
|
140
139
|
# プロセスが既に終了している、または権限がない
|
|
@@ -176,72 +175,6 @@ module Rufio
|
|
|
176
175
|
}
|
|
177
176
|
end
|
|
178
177
|
|
|
179
|
-
# シェルコマンドをタイムアウト付きで実行
|
|
180
|
-
def execute_shell_with_timeout(shell_command, env, options, timeout_sec)
|
|
181
|
-
stdout = ""
|
|
182
|
-
stderr = ""
|
|
183
|
-
status = nil
|
|
184
|
-
timed_out = false
|
|
185
|
-
pid = nil
|
|
186
|
-
|
|
187
|
-
begin
|
|
188
|
-
Timeout.timeout(timeout_sec) do
|
|
189
|
-
args = env.empty? ? [shell_command] : [env, shell_command]
|
|
190
|
-
stdin, stdout_io, stderr_io, wait_thread = Open3.popen3(*args, **options)
|
|
191
|
-
pid = wait_thread.pid
|
|
192
|
-
stdin.close
|
|
193
|
-
stdout = stdout_io.read
|
|
194
|
-
stderr = stderr_io.read
|
|
195
|
-
stdout_io.close
|
|
196
|
-
stderr_io.close
|
|
197
|
-
status = wait_thread.value
|
|
198
|
-
end
|
|
199
|
-
rescue Timeout::Error
|
|
200
|
-
timed_out = true
|
|
201
|
-
if pid
|
|
202
|
-
begin
|
|
203
|
-
Process.kill("TERM", pid)
|
|
204
|
-
sleep 0.1
|
|
205
|
-
Process.kill("KILL", pid)
|
|
206
|
-
rescue Errno::ESRCH, Errno::EPERM
|
|
207
|
-
# プロセスが既に終了している、または権限がない
|
|
208
|
-
end
|
|
209
|
-
end
|
|
210
|
-
end
|
|
211
|
-
|
|
212
|
-
if timed_out
|
|
213
|
-
{
|
|
214
|
-
success: false,
|
|
215
|
-
exit_code: nil,
|
|
216
|
-
stdout: stdout,
|
|
217
|
-
stderr: stderr,
|
|
218
|
-
timeout: true
|
|
219
|
-
}
|
|
220
|
-
else
|
|
221
|
-
{
|
|
222
|
-
success: status&.success? || false,
|
|
223
|
-
exit_code: status&.exitstatus || 1,
|
|
224
|
-
stdout: stdout,
|
|
225
|
-
stderr: stderr,
|
|
226
|
-
timeout: false
|
|
227
|
-
}
|
|
228
|
-
end
|
|
229
|
-
end
|
|
230
|
-
|
|
231
|
-
# シェルコマンドをタイムアウトなしで実行
|
|
232
|
-
def execute_shell_without_timeout(shell_command, env, options)
|
|
233
|
-
args = env.empty? ? [shell_command] : [env, shell_command]
|
|
234
|
-
stdout, stderr, status = Open3.capture3(*args, **options)
|
|
235
|
-
|
|
236
|
-
{
|
|
237
|
-
success: status.success?,
|
|
238
|
-
exit_code: status.exitstatus,
|
|
239
|
-
stdout: stdout,
|
|
240
|
-
stderr: stderr,
|
|
241
|
-
timeout: false
|
|
242
|
-
}
|
|
243
|
-
end
|
|
244
|
-
|
|
245
178
|
# エラー結果を構築
|
|
246
179
|
def build_error_result(error)
|
|
247
180
|
{
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'shellwords'
|
|
4
|
+
|
|
5
|
+
module Rufio
|
|
6
|
+
# 検出対象の拡張子・名前解決・ファイル実行方法を一か所で定義する。
|
|
7
|
+
module ScriptFile
|
|
8
|
+
# .sh は shebang を尊重して直接実行する。PowerShell は既存の pwsh を維持する。
|
|
9
|
+
INTERPRETERS = {
|
|
10
|
+
'.sh' => nil, '.rb' => 'ruby', '.py' => 'python3', '.pl' => 'perl',
|
|
11
|
+
'.js' => 'node', '.ts' => 'ts-node', '.ps1' => 'pwsh'
|
|
12
|
+
}.freeze
|
|
13
|
+
EXTENSIONS = INTERPRETERS.keys.freeze
|
|
14
|
+
|
|
15
|
+
def self.supported?(path)
|
|
16
|
+
INTERPRETERS.key?(File.extname(path).downcase)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def self.executable?(path)
|
|
20
|
+
supported?(path) || File.executable?(path)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def self.find(scripts, name)
|
|
24
|
+
exact = scripts.find { |script| script[:name] == name }
|
|
25
|
+
return exact if exact
|
|
26
|
+
|
|
27
|
+
EXTENSIONS.each do |extension|
|
|
28
|
+
match = scripts.find { |script| script[:name] == "#{name}#{extension}" }
|
|
29
|
+
return match if match
|
|
30
|
+
end
|
|
31
|
+
nil
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def self.complete(scripts, prefix)
|
|
35
|
+
scripts.map { |script| script[:name] }.select { |name| name.start_with?(prefix) }.uniq.sort
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def self.command(path, args: nil)
|
|
39
|
+
interpreter = INTERPRETERS[File.extname(path).downcase]
|
|
40
|
+
command = [interpreter, path.shellescape].compact.join(' ')
|
|
41
|
+
args && !args.empty? ? "#{command} #{args}" : command
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require_relative 'script_file'
|
|
4
|
+
|
|
3
5
|
require 'yaml'
|
|
6
|
+
require 'set'
|
|
4
7
|
require_relative 'config'
|
|
5
8
|
|
|
6
9
|
module Rufio
|
|
@@ -10,7 +13,7 @@ module Rufio
|
|
|
10
13
|
attr_reader :paths
|
|
11
14
|
|
|
12
15
|
# サポートするスクリプト拡張子
|
|
13
|
-
SUPPORTED_EXTENSIONS =
|
|
16
|
+
SUPPORTED_EXTENSIONS = ScriptFile::EXTENSIONS
|
|
14
17
|
|
|
15
18
|
# 履歴の最大サイズ
|
|
16
19
|
MAX_HISTORY_SIZE = 100
|
|
@@ -56,14 +59,7 @@ module Rufio
|
|
|
56
59
|
|
|
57
60
|
scripts = find_scripts(command_name)
|
|
58
61
|
|
|
59
|
-
|
|
60
|
-
when 0
|
|
61
|
-
nil
|
|
62
|
-
when 1
|
|
63
|
-
@cache[command_name] = scripts.first
|
|
64
|
-
else
|
|
65
|
-
@cache[command_name] = scripts.first
|
|
66
|
-
end
|
|
62
|
+
@cache[command_name] = scripts.first unless scripts.empty?
|
|
67
63
|
end
|
|
68
64
|
|
|
69
65
|
# 全スクリプト一覧を取得(タブ補完用)
|
|
@@ -121,7 +117,7 @@ module Rufio
|
|
|
121
117
|
|
|
122
118
|
# すべてのマッチを取得(複数マッチ対応)
|
|
123
119
|
def find_all_matches(command_name)
|
|
124
|
-
|
|
120
|
+
find_scripts(command_name, all_paths: true)
|
|
125
121
|
end
|
|
126
122
|
|
|
127
123
|
# スクリプト名を補完
|
|
@@ -232,7 +228,7 @@ module Rufio
|
|
|
232
228
|
paths.map { |p| File.expand_path(p) }
|
|
233
229
|
end
|
|
234
230
|
|
|
235
|
-
def find_scripts(command_name)
|
|
231
|
+
def find_scripts(command_name, all_paths: false)
|
|
236
232
|
scripts = []
|
|
237
233
|
basename_without_ext = command_name.sub(/\.[^.]+$/, '')
|
|
238
234
|
has_extension = command_name.include?('.')
|
|
@@ -255,44 +251,14 @@ module Rufio
|
|
|
255
251
|
end
|
|
256
252
|
end
|
|
257
253
|
|
|
258
|
-
return scripts
|
|
254
|
+
return scripts if !all_paths && !scripts.empty?
|
|
259
255
|
end
|
|
260
256
|
|
|
261
257
|
scripts
|
|
262
258
|
end
|
|
263
259
|
|
|
264
260
|
def executable_script?(path)
|
|
265
|
-
|
|
266
|
-
return true if SUPPORTED_EXTENSIONS.include?(ext)
|
|
267
|
-
|
|
268
|
-
File.executable?(path)
|
|
269
|
-
end
|
|
270
|
-
|
|
271
|
-
def find_scripts_all_paths(command_name)
|
|
272
|
-
scripts = []
|
|
273
|
-
basename_without_ext = command_name.sub(/\.[^.]+$/, '')
|
|
274
|
-
has_extension = command_name.include?('.')
|
|
275
|
-
|
|
276
|
-
@paths.each do |path|
|
|
277
|
-
next unless Dir.exist?(path)
|
|
278
|
-
|
|
279
|
-
Dir.glob(File.join(path, '**', '*')).each do |file|
|
|
280
|
-
next unless File.file?(file)
|
|
281
|
-
|
|
282
|
-
file_basename = File.basename(file)
|
|
283
|
-
next if file_basename.start_with?('.')
|
|
284
|
-
next unless executable_script?(file)
|
|
285
|
-
|
|
286
|
-
if has_extension
|
|
287
|
-
scripts << file if file_basename.downcase == command_name.downcase
|
|
288
|
-
else
|
|
289
|
-
file_name_without_ext = File.basename(file, '.*')
|
|
290
|
-
scripts << file if file_name_without_ext.downcase == basename_without_ext.downcase
|
|
291
|
-
end
|
|
292
|
-
end
|
|
293
|
-
end
|
|
294
|
-
|
|
295
|
-
scripts
|
|
261
|
+
ScriptFile.executable?(path)
|
|
296
262
|
end
|
|
297
263
|
|
|
298
264
|
def levenshtein_distance(s1, s2)
|
data/lib/rufio/script_runner.rb
CHANGED
|
@@ -1,13 +1,16 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require_relative 'script_file'
|
|
4
|
+
|
|
3
5
|
require 'open3'
|
|
6
|
+
require 'set'
|
|
4
7
|
|
|
5
8
|
module Rufio
|
|
6
9
|
# スクリプトパスからスクリプトを検索・実行するクラス
|
|
7
10
|
# ジョブマネージャーと連携してバックグラウンド実行を管理
|
|
8
11
|
class ScriptRunner
|
|
9
12
|
# サポートするスクリプト拡張子
|
|
10
|
-
SUPPORTED_EXTENSIONS =
|
|
13
|
+
SUPPORTED_EXTENSIONS = ScriptFile::EXTENSIONS
|
|
11
14
|
|
|
12
15
|
# @param script_paths [Array<String>] スクリプトを検索するディレクトリのリスト
|
|
13
16
|
# @param job_manager [JobManager, nil] ジョブマネージャー(nilの場合は同期実行)
|
|
@@ -29,28 +32,14 @@ module Rufio
|
|
|
29
32
|
# @param name [String] スクリプト名(拡張子あり/なし)
|
|
30
33
|
# @return [Hash, nil] スクリプト情報 { name:, path:, dir: } または nil
|
|
31
34
|
def find_script(name)
|
|
32
|
-
|
|
33
|
-
script = available_scripts.find { |s| s[:name] == name }
|
|
34
|
-
return script if script
|
|
35
|
-
|
|
36
|
-
# 拡張子なしで検索
|
|
37
|
-
SUPPORTED_EXTENSIONS.each do |ext|
|
|
38
|
-
script = available_scripts.find { |s| s[:name] == "#{name}#{ext}" }
|
|
39
|
-
return script if script
|
|
40
|
-
end
|
|
41
|
-
|
|
42
|
-
nil
|
|
35
|
+
ScriptFile.find(available_scripts, name)
|
|
43
36
|
end
|
|
44
37
|
|
|
45
38
|
# スクリプト名の補完候補を取得
|
|
46
39
|
# @param prefix [String] 入力中の文字列
|
|
47
40
|
# @return [Array<String>] 補完候補のスクリプト名
|
|
48
41
|
def complete(prefix)
|
|
49
|
-
available_scripts
|
|
50
|
-
.map { |s| s[:name] }
|
|
51
|
-
.select { |name| name.start_with?(prefix) }
|
|
52
|
-
.uniq
|
|
53
|
-
.sort
|
|
42
|
+
ScriptFile.complete(available_scripts, prefix)
|
|
54
43
|
end
|
|
55
44
|
|
|
56
45
|
# スクリプトをジョブとして実行
|
|
@@ -64,6 +53,11 @@ module Rufio
|
|
|
64
53
|
script = find_script(name)
|
|
65
54
|
return nil unless script
|
|
66
55
|
|
|
56
|
+
execute(script, working_dir: working_dir, args: args, selected_file: selected_file, selected_dir: selected_dir)
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# 検出済みスクリプトの実行。検索元によらず同じジョブ・ログ処理を使う。
|
|
60
|
+
def execute(script, working_dir:, args: nil, selected_file: nil, selected_dir: nil)
|
|
67
61
|
env = build_environment(working_dir, selected_file, selected_dir)
|
|
68
62
|
execute_script(script, working_dir, env, args)
|
|
69
63
|
end
|
|
@@ -108,11 +102,7 @@ module Rufio
|
|
|
108
102
|
# @param path [String] ファイルパス
|
|
109
103
|
# @return [Boolean]
|
|
110
104
|
def executable_script?(path)
|
|
111
|
-
|
|
112
|
-
return true if SUPPORTED_EXTENSIONS.include?(ext)
|
|
113
|
-
|
|
114
|
-
# 拡張子がなくても実行可能なら対象
|
|
115
|
-
File.executable?(path)
|
|
105
|
+
ScriptFile.executable?(path)
|
|
116
106
|
end
|
|
117
107
|
|
|
118
108
|
# 環境変数を構築
|
|
@@ -136,8 +126,7 @@ module Rufio
|
|
|
136
126
|
# @param args [String, nil] スクリプトに渡す引数
|
|
137
127
|
# @return [TaskStatus] 作成されたジョブ
|
|
138
128
|
def execute_script(script, working_dir, env = {}, args = nil)
|
|
139
|
-
command =
|
|
140
|
-
command = "#{command} #{args}" if args && !args.empty?
|
|
129
|
+
command = ScriptFile.command(script[:path], args: args)
|
|
141
130
|
|
|
142
131
|
if @job_manager
|
|
143
132
|
# ジョブマネージャーにジョブを追加
|
|
@@ -166,32 +155,6 @@ module Rufio
|
|
|
166
155
|
end
|
|
167
156
|
end
|
|
168
157
|
|
|
169
|
-
# スクリプトの実行コマンドを構築
|
|
170
|
-
# @param script [Hash] スクリプト情報
|
|
171
|
-
# @return [String] 実行コマンド
|
|
172
|
-
def build_command(script)
|
|
173
|
-
path = script[:path]
|
|
174
|
-
ext = File.extname(path).downcase
|
|
175
|
-
|
|
176
|
-
case ext
|
|
177
|
-
when '.rb'
|
|
178
|
-
"ruby #{path.shellescape}"
|
|
179
|
-
when '.py'
|
|
180
|
-
"python3 #{path.shellescape}"
|
|
181
|
-
when '.js'
|
|
182
|
-
"node #{path.shellescape}"
|
|
183
|
-
when '.ts'
|
|
184
|
-
"ts-node #{path.shellescape}"
|
|
185
|
-
when '.pl'
|
|
186
|
-
"perl #{path.shellescape}"
|
|
187
|
-
when '.ps1'
|
|
188
|
-
"pwsh #{path.shellescape}"
|
|
189
|
-
else
|
|
190
|
-
# shスクリプトまたは実行可能ファイル
|
|
191
|
-
path.shellescape
|
|
192
|
-
end
|
|
193
|
-
end
|
|
194
|
-
|
|
195
158
|
# バックグラウンドでスクリプトを実行
|
|
196
159
|
# @param job [TaskStatus] ジョブ
|
|
197
160
|
# @param command [String] 実行コマンド
|
|
@@ -108,12 +108,8 @@ module Rufio
|
|
|
108
108
|
# @param history [CommandHistory] 履歴オブジェクト
|
|
109
109
|
# @return [Array<String>] コマンドのリスト
|
|
110
110
|
def get_history_commands(history)
|
|
111
|
-
# CommandHistoryの内部データにアクセスするため、
|
|
112
|
-
# instance_variable_getを使用(本来はpublicメソッドを追加すべき)
|
|
113
|
-
history_array = history.instance_variable_get(:@history) || []
|
|
114
|
-
|
|
115
111
|
# ! を除去したコマンドを返す
|
|
116
|
-
|
|
112
|
+
history.entries.map do |cmd|
|
|
117
113
|
cmd.start_with?('!') ? cmd[1..-1] : cmd
|
|
118
114
|
end
|
|
119
115
|
end
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Rufio
|
|
4
|
+
# `rufio --shell-init` が出力するシェル関数。
|
|
5
|
+
# rufio は子プロセスなので親シェルの作業ディレクトリを変えられない。
|
|
6
|
+
# T キーで終了した時に rufio が --choosedir のファイルへ書いたディレクトリへ、関数側で cd する。
|
|
7
|
+
module ShellInit
|
|
8
|
+
FUNCTION_NAME = 'rf'
|
|
9
|
+
SHELLS = %w[bash zsh fish powershell].freeze
|
|
10
|
+
|
|
11
|
+
class << self
|
|
12
|
+
# OS とログインシェルから出力するシェルを決める。
|
|
13
|
+
# Windows は PowerShell。ただし Git Bash など SHELL が設定された環境ではそのシェルに合わせる。
|
|
14
|
+
def detect(platform: RUBY_PLATFORM, env: ENV)
|
|
15
|
+
shell = env['SHELL'].to_s.split(%r{[/\\]}).last.to_s.sub(/\.exe\z/i, '')
|
|
16
|
+
return shell if SHELLS.include?(shell)
|
|
17
|
+
|
|
18
|
+
platform =~ /mswin|mingw/ ? 'powershell' : 'bash'
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def script(shell)
|
|
22
|
+
case shell
|
|
23
|
+
when 'bash', 'zsh' then posix_script(shell)
|
|
24
|
+
when 'fish' then fish_script
|
|
25
|
+
when 'powershell', 'pwsh' then powershell_script
|
|
26
|
+
else
|
|
27
|
+
raise ArgumentError, "Unsupported shell: #{shell} (#{SHELLS.join(', ')})"
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
private
|
|
32
|
+
|
|
33
|
+
def posix_script(shell)
|
|
34
|
+
<<~SH
|
|
35
|
+
# rufio shell integration (#{shell})
|
|
36
|
+
# Add to ~/.#{shell}rc: eval "$(rufio --shell-init #{shell})"
|
|
37
|
+
# Run `#{FUNCTION_NAME}` and press T to quit rufio and cd to the last directory.
|
|
38
|
+
#{FUNCTION_NAME}() {
|
|
39
|
+
local tmp dir
|
|
40
|
+
tmp="$(mktemp -t rufio-cwd.XXXXXX)" || return
|
|
41
|
+
command rufio --choosedir "$tmp" "$@"
|
|
42
|
+
dir="$(cat -- "$tmp" 2>/dev/null)"
|
|
43
|
+
rm -f -- "$tmp"
|
|
44
|
+
if [ -n "$dir" ] && [ -d "$dir" ] && [ "$dir" != "$PWD" ]; then
|
|
45
|
+
cd -- "$dir"
|
|
46
|
+
fi
|
|
47
|
+
}
|
|
48
|
+
SH
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def fish_script
|
|
52
|
+
<<~FISH
|
|
53
|
+
# rufio shell integration (fish)
|
|
54
|
+
# Add to ~/.config/fish/config.fish: rufio --shell-init fish | source
|
|
55
|
+
# Run `#{FUNCTION_NAME}` and press T to quit rufio and cd to the last directory.
|
|
56
|
+
function #{FUNCTION_NAME}
|
|
57
|
+
set -l tmp (mktemp -t rufio-cwd.XXXXXX); or return
|
|
58
|
+
command rufio --choosedir $tmp $argv
|
|
59
|
+
set -l dir (cat -- $tmp 2>/dev/null)
|
|
60
|
+
rm -f -- $tmp
|
|
61
|
+
if test -n "$dir"; and test -d "$dir"; and test "$dir" != "$PWD"
|
|
62
|
+
cd -- $dir
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
FISH
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def powershell_script
|
|
69
|
+
<<~PS1
|
|
70
|
+
# rufio shell integration (PowerShell)
|
|
71
|
+
# Add to $PROFILE: Invoke-Expression (& rufio --shell-init powershell | Out-String)
|
|
72
|
+
# Run `#{FUNCTION_NAME}` and press T to quit rufio and cd to the last directory.
|
|
73
|
+
function #{FUNCTION_NAME} {
|
|
74
|
+
$tmp = New-TemporaryFile
|
|
75
|
+
try {
|
|
76
|
+
rufio --choosedir $tmp.FullName @args
|
|
77
|
+
$dir = Get-Content -LiteralPath $tmp.FullName -Raw -Encoding UTF8 -ErrorAction SilentlyContinue
|
|
78
|
+
if ($dir) { $dir = $dir.Trim() }
|
|
79
|
+
if ($dir -and (Test-Path -LiteralPath $dir -PathType Container)) {
|
|
80
|
+
Set-Location -LiteralPath $dir
|
|
81
|
+
}
|
|
82
|
+
} finally {
|
|
83
|
+
Remove-Item -LiteralPath $tmp.FullName -ErrorAction SilentlyContinue
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
PS1
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
end
|
data/lib/rufio/task_status.rb
CHANGED
|
@@ -6,14 +6,18 @@ module Rufio
|
|
|
6
6
|
class TaskStatus
|
|
7
7
|
attr_accessor :id, :name, :path, :status, :start_time, :end_time, :logs, :exit_code
|
|
8
8
|
|
|
9
|
+
attr_reader :command
|
|
10
|
+
|
|
9
11
|
# 初期化
|
|
10
12
|
# @param id [Integer] タスクID
|
|
11
13
|
# @param name [String] タスク名(スクリプト名)
|
|
12
14
|
# @param path [String] 実行ディレクトリ
|
|
13
|
-
|
|
15
|
+
# @param command [String, nil] 実行コマンド
|
|
16
|
+
def initialize(id:, name:, path:, command: nil)
|
|
14
17
|
@id = id
|
|
15
18
|
@name = name
|
|
16
19
|
@path = path
|
|
20
|
+
@command = command
|
|
17
21
|
@status = :waiting
|
|
18
22
|
@start_time = nil
|
|
19
23
|
@end_time = nil
|