utils 0.68.0 → 0.69.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.
Files changed (56) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +251 -18
  3. data/bin/ascii7 +28 -0
  4. data/bin/blameline +17 -0
  5. data/bin/changes +69 -5
  6. data/bin/classify +128 -7
  7. data/bin/code_comment +102 -104
  8. data/bin/commit_message +26 -2
  9. data/bin/create_cstags +18 -0
  10. data/bin/create_tags +10 -0
  11. data/bin/discover +38 -1
  12. data/bin/edit +14 -1
  13. data/bin/edit_wait +14 -0
  14. data/bin/enum +139 -15
  15. data/bin/git-empty +50 -0
  16. data/bin/git-versions +20 -0
  17. data/bin/json_check +15 -1
  18. data/bin/long_lines +11 -2
  19. data/bin/myex +38 -0
  20. data/bin/on_change +22 -0
  21. data/bin/path +21 -0
  22. data/bin/print_method +29 -1
  23. data/bin/probe +52 -4
  24. data/bin/rainbow +52 -0
  25. data/bin/rd2md +15 -0
  26. data/bin/search +83 -1
  27. data/bin/sedit +6 -0
  28. data/bin/serve +18 -3
  29. data/bin/ssh-tunnel +14 -2
  30. data/bin/strip_spaces +17 -9
  31. data/bin/sync_dir +48 -1
  32. data/bin/untest +19 -1
  33. data/bin/utils-utilsrc +42 -6
  34. data/bin/vcf2alias +33 -0
  35. data/bin/yaml_check +24 -2
  36. data/lib/utils/config_dir.rb +127 -0
  37. data/lib/utils/config_file.rb +445 -1
  38. data/lib/utils/editor.rb +215 -3
  39. data/lib/utils/finder.rb +127 -16
  40. data/lib/utils/grepper.rb +90 -1
  41. data/lib/utils/irb.rb +387 -39
  42. data/lib/utils/line_blamer.rb +28 -0
  43. data/lib/utils/line_formatter.rb +198 -0
  44. data/lib/utils/md5.rb +14 -0
  45. data/lib/utils/patterns.rb +77 -3
  46. data/lib/utils/probe_server.rb +302 -23
  47. data/lib/utils/ssh_tunnel_specification.rb +58 -0
  48. data/lib/utils/version.rb +1 -1
  49. data/lib/utils/xt/source_location_extension.rb +18 -6
  50. data/lib/utils.rb +3 -1
  51. data/tests/utils_test.rb +7 -1
  52. data/utils.gemspec +5 -5
  53. metadata +4 -6
  54. data/bin/number_files +0 -26
  55. data/lib/utils/xdg_config.rb +0 -10
  56. /data/{COPYING → LICENSE} +0 -0
data/bin/code_comment CHANGED
@@ -1,15 +1,79 @@
1
1
  #!/usr/bin/env ruby
2
+ #
3
+ # Generate YARD comments for Ruby methods using LLM assistance
4
+ #
5
+ # Usage:
6
+ # code_comment path/to/file.rb:line_number # Generate comment for method at line
7
+ #
8
+ # This script analyzes Ruby source code and generates high-quality YARD comments
9
+ # for methods using an LLM (via Ollama). It examines the surrounding context to
10
+ # identify method definitions and provides comprehensive documentation including
11
+ # descriptions, parameters, return values, and exceptions.
12
+ #
13
+ # Requires:
14
+ # - Git repository with Ruby files in lib/, spec/, or test/ directories
15
+ # - Ollama server running locally or accessible via OLLAMA_URL / OLLAMA_HOST
16
+ # - Configuration files in ~/.config/code_comment/
17
+ # - system.txt: System prompt for LLM
18
+ # - prompt.txt: Template for comment generation
19
+ # - client.json: Ollama client settings
20
+ # - options.json: Generation options (temperature, etc.)
21
+ #
22
+ # Environment variables:
23
+ # OLLAMA_URL: Base URL of Ollama server
24
+ # OLLAMA_MODEL: Model to use (default: llama3.1)
25
+ # XDG_CONFIG_HOME: Custom config directory location
26
+ # DEBUG: Set to 1 for verbose output and debug.log creation
27
+ #
28
+ # Examples:
29
+ # code_comment app/models/user.rb:42 # Document method at line 42
30
+ # code_comment lib/api/client.rb:15 # Document method at line 15
2
31
 
3
32
  require 'ollama'
4
33
  include Ollama
5
34
  require 'utils'
6
- include Utils::XDGConfig
7
35
 
36
+ META_METHOD = /(
37
+ (class_)? # Optional "class_" prefix
38
+ attr( # "attr" keyword
39
+ _reader| # reader variant
40
+ _writer| # writer variant
41
+ _accessor # accessor variant
42
+ )? # Optional variant
43
+ | # OR
44
+ dsl_(accessor|reader) # DSL accessor patterns
45
+ | # OR
46
+ constant # Constant definitions
47
+ | # OR
48
+ config # config settings
49
+ | # OR
50
+ (instance_)? # Optional "instance_" prefix
51
+ thread( # "thread" keyword
52
+ _local| # local variant
53
+ _global # global variant
54
+ )? # Optional variant
55
+ )\s+:/x
56
+
57
+ # Fetches the method definition from a given filename and line number.
58
+ #
59
+ # This method retrieves the source code of a method by analyzing the file
60
+ # location and line number provided. It attempts to identify the method
61
+ # definition by examining the surrounding context, including handling
62
+ # private and protected method declarations.
63
+ #
64
+ # @param filename_linenumber [ Object ] an object that responds to #source_location
65
+ # and provides filename and line number information
66
+ #
67
+ # @return [ String ] the source code of the method definition, or an empty string
68
+ # if the method cannot be determined
8
69
  def fetch_method(filename_linenumber)
9
70
  result = ''
10
71
  source_location = filename_linenumber.source_location
11
72
  lf = Tins::LinesFile.for_filename(source_location.filename, source_location.linenumber)
12
- if spaces = lf.match_backward(/^(\s*|.*?(private|protected)\s+)def\s+(?:\S+?)(?:\(|\s*$)/)&.first
73
+ if lf.line =~ META_METHOD
74
+ return lf.line
75
+ end
76
+ if spaces = lf.match_backward(/^(\s*?)(\S.*?\s+)?def\s+/)&.first
13
77
  line_number_begin = lf.line_number
14
78
  lf.match_forward(/^#{spaces}end/)
15
79
  line_number_end = lf.line_number
@@ -21,134 +85,67 @@ def fetch_method(filename_linenumber)
21
85
  result
22
86
  end
23
87
 
24
- def fetch_file(filename_linenumber)
25
- source_location = filename_linenumber.source_location
26
- File.read(source_location.filename)
27
- end
28
-
29
88
  filename_linenumber = ARGV.shift or fail "require file_name as second argument"
89
+ config = Utils::ConfigDir.new('code_comment', env_var: 'XDG_CONFIG_HOME')
30
90
  method = fetch_method(filename_linenumber)
31
91
  method_indent = method[/\A( *)/, 1].size
32
- #file = fetch_file(filename_linenumber)
33
92
  files = Dir['{lib,spec,test}/**/*.rb']
34
93
  base_url = ENV['OLLAMA_URL'] || 'http://%s' % ENV.fetch('OLLAMA_HOST')
35
94
  model = ENV.fetch('OLLAMA_MODEL', 'llama3.1')
36
- #file = File.read(file_name)
37
95
  #call_sites = %x(cscope -L -3 "#{method_name}" $(find . -name '*.rb') | awk '{ print $1 ":" $3 }').lines.map(&:chomp).uniq
38
96
  #methods = call_sites.map { fetch_method(_1) } * ?\n
39
97
 
40
- cheatsheet = <<EOT
41
- Documenting Code with YARD
42
-
43
- By default, YARD is compatible with the same RDoc syntax most Ruby developers
44
- are already familiar with. However, one of the biggest advantages of YARD is
45
- the extended meta-data syntax, commonly known as "tags", that you can use to
46
- express small bits of information in a structured and formal manner. While RDoc
47
- syntax expects you to describe your method in a completely free-form manner,
48
- YARD recommends declaring your parameters, return types, etc. with the @tag
49
- syntax, which makes outputting the documentation more consistent and easier to
50
- read. Consider the RDoc documentation for a method to_format:
51
-
52
- # Converts the object into textual markup given a specific `format`
53
- # (defaults to `:html`)
54
- #
55
- # == Parameters:
56
- # format::
57
- # A Symbol declaring the format to convert the object to. This
58
- # can be `:text` or `:html`.
59
- #
60
- # == Returns:
61
- # A string representing the object in a specified
62
- # format.
63
- #
64
- def to_format(format = :html)
65
- # format the object
66
- end
67
-
68
- While this may seem easy enough to read and understand, it's hard for a machine
69
- to properly pull this data back out of our documentation. Also we've tied our
70
- markup to our content, and now our documentation becomes hard to maintain if we
71
- decide later to change our markup style (maybe we don't want the ":" suffix on
72
- our headers anymore).
73
-
74
- In YARD, we would simply define our method as:
75
-
76
- # Converts the object into textual markup given a specific format.
77
- #
78
- # @param format [Symbol] the format type, `:text` or `:html`
79
- # @return [String] the object converted into the expected format.
80
- # @raise [CannotFormatException] the object cannot be formatted
81
- def to_format(format = :html)
82
- # format the object
83
- end
84
-
85
- Using tags we can add semantic metadata to our code without worrying about
86
- presentation. YARD will handle presentation for us when we decide to generate
87
- documentation later.
88
- EOT
89
-
90
- system = <<EOT
98
+ default_system = <<EOT
91
99
  Provide high-quality YARD comments for the given Ruby method, including a brief
92
100
  description of its purpose, parameters, raised exceptions (and why), and
93
101
  return values, assuming an expert-level understanding of the programming
94
102
  concepts involved.
95
103
  EOT
96
- system = nil
104
+ system = config.read('system.txt', default: default_system)
97
105
 
98
- prompt = <<EOT
106
+ file_contents = files.map { _1 + ":\n" + File.read(_1) } * ?\n
107
+ default_prompt = <<EOT
99
108
  Look at this code to document it:
100
109
 
101
- #{files.map { File.read(_1) } * ?\n}
110
+ %{file_contents}
102
111
 
103
112
  Here's an example for how you should document a method.
104
113
 
105
- # The foo method computes the bar result by processing…
106
- # then it returns the result.
107
- #
108
- # @param first [ String ] the foo string
109
- # @param second [ Integer ] the number of bars lengthy detailed mutltiline
110
- # detailed explanation including a newline.
111
- # @param third [ TrueClass, FalseClass ]
112
- #
113
- # @yield [ a, b ]
114
- #
115
- # @raise [ ArgumentError ] if block argument wasn't provided
116
- # @raise [ ArgumentError ] if second parameter was too small.
117
- #
118
- # @example
119
- # bar.foo("blub", 4) { |a, b| … } #=> …
120
- #
121
- # @return [ ProcessResult ]
122
- def foo(first, second, third: false, &block)
123
- block or raise ArgumentError, 'no &block'
124
- a = first * 2
125
- if second < 0
126
- raise ArgumentError, 'too small'
127
- end
128
- b = "foo" * second
129
- if third
130
- a = a * b
131
- end
132
- block_result = block.(a, b)
133
- result = process block_result
134
- return result
135
- end
114
+ # The foo method computes the bar result by processing…
115
+ # then it returns the result.
116
+ #
117
+ # @param first [ String ] the foo string
118
+ # @param second [ Integer ] the number of bars lengthy detailed mutltiline
119
+ # detailed explanation including a newline.
120
+ # @param third [ TrueClass, FalseClass ]
121
+ #
122
+ # @yield [ a, b ]
123
+ #
124
+ # @raise [ ArgumentError ] if block argument wasn't provided
125
+ # @raise [ ArgumentError ] if second parameter was too small.
126
+ #
127
+ # @return [ ProcessResult ]
136
128
 
137
129
  And this is the method you should document:
138
130
 
139
- #{method}
131
+ %{method}
140
132
 
141
133
  Output a YARD comment for this method:
142
134
 
143
135
  Format requirements:
144
136
 
145
- 1. Focus on providing a description of the method's purpose, without including any code snippets.
146
- 2. Never use `, `ruby, ```, ```ruby in your response.
147
- 3. Never add any other remarks or explanation to your response.
148
- 4. Start each line of your comment with a single # character.
137
+ 1. Focus on providing a description of the method's purpose
138
+ without including any code snippets.
139
+ 2. You should ommit the @raise if you are not sure.
140
+ 3. Never use `, `ruby, ```, ```ruby in your response.
141
+ 4. Never add any other remarks or explanation to your response.
142
+ 5. Start each line of your comment with a single # character.
149
143
  EOT
144
+ prompt = config.read('prompt.txt', default: default_prompt) % {
145
+ method:, file_contents:,
146
+ }
150
147
 
151
- options = Ollama::Options.new(
148
+ default_options = JSON(
152
149
  #repeat_penalty: 1.8,
153
150
  num_ctx: 16384,
154
151
  num_predict: 512,
@@ -159,6 +156,11 @@ options = Ollama::Options.new(
159
156
  min_p: 0.1,
160
157
  )
161
158
 
159
+ client_config = Client::Config.load_from_json config + 'client.json'
160
+ client_config.base_url = base_url
161
+ ollama = Client.configure_with(client_config)
162
+ options = JSON.parse(config.read('options.json', default: default_options))
163
+
162
164
  if ENV['DEBUG'].to_i == 1
163
165
  File.open('debug.log', ?w) do |log|
164
166
  log.puts "system:\n#{system}"
@@ -168,9 +170,5 @@ if ENV['DEBUG'].to_i == 1
168
170
  end
169
171
  end
170
172
 
171
- config = xdg_config('code_comment')
172
- client_config = Client::Config.load_from_json "#{config}/client.json"
173
- client_config.base_url = base_url
174
- ollama = Client.configure_with(client_config)
175
173
  response = ollama.generate(model:, system:, prompt:, options:, stream: false, think: false).response
176
174
  puts response.gsub(/^/) { ' ' * method_indent }
data/bin/commit_message CHANGED
@@ -1,9 +1,33 @@
1
1
  #!/usr/bin/env ruby
2
+ #
3
+ # Git Commit Message Generator
4
+ #
5
+ # Generates AI-powered commit messages based on git changes using Ollama.
6
+ # Reads configuration from $XDG_CONFIG_HOME/commit_message/ directory.
7
+ #
8
+ # Usage:
9
+ # commit_message
10
+ #
11
+ # The script automatically:
12
+ # - Determines current git branch name
13
+ # - Loads configuration files (client.json, options.json, system.txt, prompt.txt)
14
+ # - Generates commit message using ollama_cli with the current diff as input
15
+ #
16
+ # Requirements:
17
+ # - Git repository in current directory
18
+ # - ollama_cli tool installed
19
+ # - Ollama server running
20
+ # - Configuration files in $XDG_CONFIG_HOME/commit_message/
21
+ #
22
+ # Configuration files:
23
+ # - client.json: Ollama API client configuration
24
+ # - options.json: Generation options
25
+ # - system.txt: System prompt for AI model
26
+ # - prompt.txt: Commit message template, contains %{branch} and %{stdin}
2
27
 
3
28
  require 'utils'
4
- include Utils::XDGConfig
5
29
 
6
- config = xdg_config('commit_message')
30
+ config = Utils::ConfigDir.new('commit_message', env_var: 'XDG_CONFIG_HOME')
7
31
 
8
32
  branch = `git rev-parse --abbrev-ref HEAD`.chomp
9
33
  exec 'ollama_cli', '-c', "#{config}/client.json",
data/bin/create_cstags CHANGED
@@ -1,4 +1,22 @@
1
1
  #!/usr/bin/env ruby
2
+ #
3
+ # Create cscope database for project files
4
+ #
5
+ # Usage:
6
+ # create_cstags # Generate cscope.out database in current directory
7
+ #
8
+ # This script generates a cscope database (cscope.out) by collecting all
9
+ # project files and building an index for efficient cross-reference searching.
10
+ # It uses bundle paths and project roots to determine which files to include.
11
+ #
12
+ # Requires:
13
+ # - cscope command-line tool
14
+ #
15
+ # The script will:
16
+ # 1. Collect all files from project roots (including bundle paths)
17
+ # 2. Generate cscope.out database with cross-references
18
+ # 3. Show progress using infobar visualization
19
+ # 4. Report the size of the created database
2
20
 
3
21
  require 'utils'
4
22
  require 'infobar'
data/bin/create_tags CHANGED
@@ -1,4 +1,14 @@
1
1
  #!/usr/bin/env ruby
2
+ #
3
+ # Creates ctags index for Ruby project including bundled gems
4
+ #
5
+ # This script generates a tags file that enables code navigation in editors
6
+ # like Vim. It automatically includes:
7
+ # - Current directory (.)
8
+ # - All gem paths from bundle list
9
+ # - Excludes pkg directory to avoid vendor code
10
+ #
11
+ # Usage: Run directly from project root
2
12
 
3
13
  require 'infobar'
4
14
 
data/bin/discover CHANGED
@@ -1,13 +1,43 @@
1
1
  #!/usr/bin/env ruby
2
+ #
3
+ # File Discovery and Search Tool
4
+ #
5
+ # Interactive file discovery and search utility with advanced filtering and
6
+ # editing capabilities. Combines file system traversal with intelligent pattern
7
+ # matching and Vim integration.
8
+ #
9
+ # Features:
10
+ # - Interactive pattern input with live search results
11
+ # - File system discovery with directory traversal
12
+ # - Vim integration for editing discovered files
13
+ # - Configurable search filters (regexp, fuzzy, case-insensitive)
14
+ # - Search index management and caching
15
+ # - Directory listing and leaf directory identification
16
+ # - Character set filtering for patterns
17
+ # - Interactive selection when multiple matches exist
18
+ #
19
+ # The tool creates a searchable index of your file system (which is also used
20
+ # by the search tool) and provides interactive discovery of files matching your
21
+ # criteria, with seamless Vim
22
+ # integration.
2
23
 
3
24
  require 'utils'
4
25
  include Utils
5
- require 'tins/xt'
6
26
  include Tins::GO
7
27
  require 'search_ui'
8
28
  include SearchUI
9
29
  require 'pathname'
10
30
 
31
+ # The edit_files method opens editor windows for specified file paths.
32
+ #
33
+ # This method allows users to edit one or more files using the configured
34
+ # editor. It provides options to pick a specific file from multiple paths or
35
+ # edit all files directly. The method supports waiting for the editor process
36
+ # to complete before returning control.
37
+ #
38
+ # @param paths [ Array<String> ] the file paths to be edited
39
+ # @param pick [ TrueClass, FalseClass ] whether to prompt for file selection
40
+ # @param wait [ TrueClass, FalseClass ] whether to wait for the editor to finish
11
41
  def edit_files(*paths, pick: false, wait: true)
12
42
  editor = Utils::Editor.new
13
43
  if pick
@@ -25,6 +55,13 @@ def edit_files(*paths, pick: false, wait: true)
25
55
  end
26
56
  end
27
57
 
58
+ # The usage method displays the help message and version information for the
59
+ # application.
60
+ #
61
+ # This method prints a formatted usage message to standard output, including
62
+ # the application name, available options, and version number. It also shows
63
+ # detailed descriptions of each command-line option and their expected
64
+ # arguments.
28
65
  def usage
29
66
  puts <<-EOT
30
67
  Usage: #{File.basename($0)} [OPTS] [PATTERN] [PATHS]
data/bin/edit CHANGED
@@ -1,4 +1,10 @@
1
1
  #!/usr/bin/env ruby
2
+ #
3
+ # Enhanced vim editor launcher with advanced feature
4
+ #
5
+ # This script is a sophisticated wrapper around vim that provides enhanced
6
+ # editing capabilities including server management, git integration, and
7
+ # batch file handling.
2
8
 
3
9
  require 'tins/xt'
4
10
  include Tins::GO
@@ -6,6 +12,13 @@ require 'utils'
6
12
  include Utils
7
13
  require 'tempfile'
8
14
 
15
+ # The usage method displays the command-line interface help text and version
16
+ # information.
17
+ #
18
+ # This method outputs a formatted help message that describes the available
19
+ # options and usage patterns for the command-line tool, including detailed
20
+ # explanations of each flag and their purposes. It also displays the current
21
+ # version of the tool.
9
22
  def usage
10
23
  puts <<-EOT
11
24
  Usage: #{File.basename($0)} [OPTS] [PATHS]
@@ -49,7 +62,7 @@ if $opt[?l]
49
62
  elsif $opt[?s]
50
63
  begin
51
64
  until STDIN.eof?
52
- line = STDIN.gets
65
+ line = STDIN.gets.chomp
53
66
  line = line.sub(/.*?([^:\s]+:)/, '\1')
54
67
  editor.edit(line)
55
68
  end
data/bin/edit_wait CHANGED
@@ -1,3 +1,17 @@
1
1
  #!/usr/bin/env ruby
2
+ #
3
+ # Wait for editor to close files before returning control
4
+ #
5
+ # Usage:
6
+ # edit_wait file1 file2 # Wait for editor to close specified files
7
+ #
8
+ # This script is a simple wrapper that calls 'edit -w' with all provided arguments.
9
+ # The '-w' flag makes the editor wait until the file(s) are closed before returning.
10
+ #
11
+ #
12
+ # Examples:
13
+ # edit_wait README.md # Edit README.md and wait for closure
14
+ # edit_wait file1.txt file2.txt # Edit multiple files and wait for all to close
15
+
2
16
 
3
17
  exec 'edit', '-w', *$*