mui-fzf 0.1.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 321b6f6ee6029ab32b87d375e399c916ed02ab31c7585771a19af848419e6d7f
4
+ data.tar.gz: b8b15902af7fce3559a9c476ea068de35a6cbbe7f3ea8f5bde1cc64949661a41
5
+ SHA512:
6
+ metadata.gz: ef073888aa00a55e59d07959691c8564550afc05e140c29023fdf82c8e4aecd0cabef33e99a810a90c48e61609afad66469b371ec2125314feb1e1b5a3e151b8
7
+ data.tar.gz: cb14ea1b678606039894ced0176b05d3e0a8215df42df155de420a26803933ae0898c6e42f0035680793c6ac305b086bd855808915f910fd0312d520a4e83955
data/CHANGELOG.md ADDED
@@ -0,0 +1,18 @@
1
+ ## [Unreleased]
2
+
3
+ ## [0.1.0] - 2025-12-11
4
+
5
+ ### Added
6
+ - Initial release of mui-fzf plugin
7
+ - `:Fzf` command for fuzzy file finding with preview (`head -100`)
8
+ - `:Rg` command for interactive ripgrep search:
9
+ - Without arguments: Opens fzf with empty query, type to search file contents in real-time
10
+ - With arguments (`:Rg pattern`): Pre-populates search query, allows further refinement
11
+ - Opens selected file at the matching line number
12
+ - `:Ag` command for interactive The Silver Searcher:
13
+ - Same behavior as `:Rg` but uses `ag` instead of `rg`
14
+ - Without arguments: Opens fzf with empty query for interactive search
15
+ - With arguments (`:Ag pattern`): Pre-populates search query
16
+ - Opens selected file at the matching line number
17
+ - Automatic plugin registration with Mui via `Mui.plugin_manager.register`
18
+ - ANSI color support for search result highlighting in fzf
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2025 S-H-GAMELINKS
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,103 @@
1
+ # Mui::Fzf
2
+
3
+ fzf integration plugin for [Mui](https://github.com/S-H-GAMELINKS/mui) editor.
4
+
5
+ Provides `:Fzf`, `:Rg`, and `:Ag` commands for fuzzy file searching.
6
+
7
+ ## Requirements
8
+
9
+ - [fzf](https://github.com/junegunn/fzf) must be installed
10
+ - For `:Rg` command: [ripgrep](https://github.com/BurntSushi/ripgrep)
11
+ - For `:Ag` command: [The Silver Searcher](https://github.com/ggreer/the_silver_searcher)
12
+
13
+ ## Installation
14
+
15
+ Add this line to your application's Gemfile:
16
+
17
+ ```ruby
18
+ gem 'mui-fzf'
19
+ ```
20
+
21
+ And then execute:
22
+
23
+ ```sh
24
+ $ bundle install
25
+ ```
26
+
27
+ Or install it yourself as:
28
+
29
+ ```sh
30
+ $ gem install mui-fzf
31
+ ```
32
+
33
+ ## Usage
34
+
35
+ Add the following to your `~/.muirc`:
36
+
37
+ ```ruby
38
+ Mui.use "mui-fzf"
39
+ ```
40
+
41
+ ### Commands
42
+
43
+ | Command | Description |
44
+ |---------|-------------|
45
+ | `:Fzf` | Open fzf file finder with preview |
46
+ | `:Rg` | Interactive ripgrep search (type to search file contents) |
47
+ | `:Rg [query]` | Interactive ripgrep search with initial query |
48
+ | `:Ag` | Interactive ag search (type to search file contents) |
49
+ | `:Ag [query]` | Interactive ag search with initial query |
50
+
51
+ ### Interactive Search (`:Rg` and `:Ag`)
52
+
53
+ The `:Rg` and `:Ag` commands provide interactive grep functionality:
54
+
55
+ 1. **Without arguments** (`:Rg` or `:Ag`):
56
+ - Opens fzf with an empty search field
57
+ - Start typing to search file contents in real-time
58
+ - Results update as you type
59
+
60
+ 2. **With arguments** (`:Rg pattern` or `:Ag pattern`):
61
+ - Opens fzf with the pattern pre-filled
62
+ - Initial results are shown immediately
63
+ - Modify the query to refine results
64
+
65
+ 3. **Opening files**:
66
+ - Select a result and press Enter
67
+ - The file opens at the matching line number
68
+ - Status line shows the opened file and line number
69
+
70
+ ### Key Mappings
71
+
72
+ You can add custom key mappings in your `~/.muirc`:
73
+
74
+ ```ruby
75
+ # Ctrl-P to open fzf
76
+ Mui.keymap :normal, "<C-p>" do |ctx|
77
+ ctx.run_command :Fzf
78
+ end
79
+
80
+ # Space + f for fzf
81
+ Mui.keymap :normal, "<Space>f" do |ctx|
82
+ ctx.run_command :Fzf
83
+ end
84
+
85
+ # Space + r for ripgrep
86
+ Mui.keymap :normal, "<Space>r" do |ctx|
87
+ ctx.run_command :Rg
88
+ end
89
+ ```
90
+
91
+ ## Development
92
+
93
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
94
+
95
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
96
+
97
+ ## Contributing
98
+
99
+ Bug reports and pull requests are welcome on GitHub at https://github.com/S-H-GAMELINKS/mui-fzf.
100
+
101
+ ## License
102
+
103
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/gem_tasks"
4
+ require "minitest/test_task"
5
+
6
+ Minitest::TestTask.create
7
+
8
+ require "rubocop/rake_task"
9
+
10
+ RuboCop::RakeTask.new
11
+
12
+ task default: %i[test rubocop]
@@ -0,0 +1,187 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Mui
4
+ module Fzf
5
+ # fzf integration plugin for Mui editor
6
+ # Provides :Fzf, :Rg, and :Ag commands for fuzzy file searching
7
+ class Plugin < Mui::Plugin
8
+ name "fzf"
9
+
10
+ FZF_CANCEL_EXIT_CODE = 130
11
+ FZF_PREVIEW_COMMAND = "head -100 {}"
12
+ # Preview command for grep results (file:line:content format)
13
+ # Extract filename with cut -d: -f1, line number with cut -d: -f2
14
+ GREP_PREVIEW_COMMAND = "head -100 $(echo {} | cut -d: -f1)"
15
+
16
+ def setup
17
+ register_fzf_command
18
+ register_rg_command
19
+ register_ag_command
20
+ end
21
+
22
+ private
23
+
24
+ def register_fzf_command
25
+ plugin = self
26
+ Mui.command(:Fzf) do |context, _args|
27
+ plugin.execute_fzf(context, plugin.build_fzf_command, grep_mode: false)
28
+ end
29
+ end
30
+
31
+ def register_rg_command
32
+ plugin = self
33
+ Mui.command(:Rg) do |context, args|
34
+ plugin.execute_rg(context, args)
35
+ end
36
+ end
37
+
38
+ def register_ag_command
39
+ plugin = self
40
+ Mui.command(:Ag) do |context, args|
41
+ plugin.execute_ag(context, args)
42
+ end
43
+ end
44
+
45
+ public
46
+
47
+ def execute_fzf(context, cmd, grep_mode: false)
48
+ unless context.command_exists?("fzf")
49
+ context.set_message("Error: fzf is not installed")
50
+ return
51
+ end
52
+
53
+ result = context.run_interactive_command(cmd)
54
+ handle_result(context, result, grep_mode:)
55
+ end
56
+
57
+ def execute_rg(context, args)
58
+ unless context.command_exists?("rg")
59
+ context.set_message("Error: rg (ripgrep) is not installed")
60
+ return
61
+ end
62
+
63
+ query = args&.strip || ""
64
+ # Always use interactive grep mode (start empty or with initial query)
65
+ execute_fzf(context, build_rg_command(query), grep_mode: true)
66
+ end
67
+
68
+ def execute_ag(context, args)
69
+ unless context.command_exists?("ag")
70
+ context.set_message("Error: ag (the_silver_searcher) is not installed")
71
+ return
72
+ end
73
+
74
+ query = args&.strip || ""
75
+ # Always use interactive grep mode (start empty or with initial query)
76
+ execute_fzf(context, build_ag_command(query), grep_mode: true)
77
+ end
78
+
79
+ def build_fzf_command
80
+ "fzf --preview '#{FZF_PREVIEW_COMMAND}'"
81
+ end
82
+
83
+ def build_file_list_command(list_cmd)
84
+ "#{list_cmd} | fzf --preview '#{FZF_PREVIEW_COMMAND}'"
85
+ end
86
+
87
+ def build_rg_command(query)
88
+ initial_query = escape_query(query)
89
+ rg_cmd = "rg --color=always --line-number --no-heading"
90
+ if initial_query.empty?
91
+ # No initial query: start with empty list, search on input
92
+ "echo '' | fzf --ansi --disabled " \
93
+ "--bind 'change:reload:#{rg_cmd} {q} || true' " \
94
+ "--preview '#{GREP_PREVIEW_COMMAND}'"
95
+ else
96
+ # With initial query: run rg first, then allow filtering
97
+ "#{rg_cmd} '#{initial_query}' | " \
98
+ "fzf --ansi --disabled --query '#{initial_query}' " \
99
+ "--bind 'change:reload:#{rg_cmd} {q} || true' " \
100
+ "--preview '#{GREP_PREVIEW_COMMAND}'"
101
+ end
102
+ end
103
+
104
+ def build_ag_command(query)
105
+ initial_query = escape_query(query)
106
+ ag_cmd = "ag --color --nogroup"
107
+ if initial_query.empty?
108
+ # No initial query: start with empty list, search on input
109
+ "echo '' | fzf --ansi --disabled " \
110
+ "--bind 'change:reload:#{ag_cmd} {q} || true' " \
111
+ "--preview '#{GREP_PREVIEW_COMMAND}'"
112
+ else
113
+ # With initial query: run ag first, then allow filtering
114
+ "#{ag_cmd} '#{initial_query}' | " \
115
+ "fzf --ansi --disabled --query '#{initial_query}' " \
116
+ "--bind 'change:reload:#{ag_cmd} {q} || true' " \
117
+ "--preview '#{GREP_PREVIEW_COMMAND}'"
118
+ end
119
+ end
120
+
121
+ private
122
+
123
+ def handle_result(context, result, grep_mode: false)
124
+ # User cancelled (Esc or Ctrl-C)
125
+ return if cancelled?(result)
126
+
127
+ # fzf error
128
+ unless result[:success]
129
+ context.set_message("fzf error: #{result[:stderr]}")
130
+ return
131
+ end
132
+
133
+ # Open selected file
134
+ selected = result[:stdout].strip
135
+ return if selected.empty?
136
+
137
+ if grep_mode
138
+ open_grep_result(context, selected)
139
+ else
140
+ open_selected_file(context, selected)
141
+ end
142
+ end
143
+
144
+ def cancelled?(result)
145
+ result[:exit_status] == FZF_CANCEL_EXIT_CODE ||
146
+ result[:stdout].strip.empty?
147
+ end
148
+
149
+ def open_selected_file(context, file_path)
150
+ buffer = Mui::Buffer.new
151
+ buffer.load(file_path)
152
+ context.window.buffer = buffer
153
+ context.set_message("\"#{file_path}\" opened")
154
+ rescue SystemCallError => e
155
+ context.set_message("Error: #{e.message}")
156
+ end
157
+
158
+ def open_grep_result(context, selected)
159
+ # Parse "file:line:content" format (handle ANSI codes)
160
+ clean = selected.gsub(/\e\[[0-9;]*m/, "")
161
+ parts = clean.split(":", 3)
162
+ return if parts.length < 2
163
+
164
+ file_path = parts[0]
165
+ line_number = parts[1].to_i
166
+
167
+ buffer = Mui::Buffer.new
168
+ buffer.load(file_path)
169
+ context.window.buffer = buffer
170
+
171
+ # Move cursor to the matched line
172
+ if line_number.positive?
173
+ context.window.cursor_row = line_number - 1
174
+ context.window.ensure_cursor_visible
175
+ end
176
+
177
+ context.set_message("\"#{file_path}\" opened at line #{line_number}")
178
+ rescue SystemCallError => e
179
+ context.set_message("Error: #{e.message}")
180
+ end
181
+
182
+ def escape_query(query)
183
+ query.gsub("'") { "'\\''" }
184
+ end
185
+ end
186
+ end
187
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Mui
4
+ module Fzf
5
+ VERSION = "0.1.0"
6
+ end
7
+ end
data/lib/mui/fzf.rb ADDED
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "mui"
4
+
5
+ require_relative "fzf/version"
6
+ require_relative "fzf/plugin"
7
+
8
+ module Mui
9
+ module Fzf
10
+ class Error < StandardError; end
11
+ end
12
+ end
13
+
14
+ # Register the plugin with Mui
15
+ Mui.plugin_manager.register(:fzf, Mui::Fzf::Plugin)
data/lib/mui_fzf.rb ADDED
@@ -0,0 +1,3 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "mui/fzf"
data/sig/mui/fzf.rbs ADDED
@@ -0,0 +1,6 @@
1
+ module Mui
2
+ module Fzf
3
+ VERSION: String
4
+ # See the writing guide of rbs: https://github.com/ruby/rbs#guides
5
+ end
6
+ end
metadata ADDED
@@ -0,0 +1,69 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: mui-fzf
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - S-H-GAMELINKS
8
+ bindir: exe
9
+ cert_chain: []
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
+ dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: mui
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - "~>"
17
+ - !ruby/object:Gem::Version
18
+ version: '0.1'
19
+ type: :runtime
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - "~>"
24
+ - !ruby/object:Gem::Version
25
+ version: '0.1'
26
+ description: Provides :Fzf, :Rg, and :Ag commands for fuzzy file searching in Mui
27
+ editor
28
+ email:
29
+ - gamelinks007@gmail.com
30
+ executables: []
31
+ extensions: []
32
+ extra_rdoc_files: []
33
+ files:
34
+ - CHANGELOG.md
35
+ - LICENSE.txt
36
+ - README.md
37
+ - Rakefile
38
+ - lib/mui/fzf.rb
39
+ - lib/mui/fzf/plugin.rb
40
+ - lib/mui/fzf/version.rb
41
+ - lib/mui_fzf.rb
42
+ - sig/mui/fzf.rbs
43
+ homepage: https://github.com/S-H-GAMELINKS/mui-fzf
44
+ licenses:
45
+ - MIT
46
+ metadata:
47
+ allowed_push_host: https://rubygems.org
48
+ homepage_uri: https://github.com/S-H-GAMELINKS/mui-fzf
49
+ source_code_uri: https://github.com/S-H-GAMELINKS/mui-fzf
50
+ changelog_uri: https://github.com/S-H-GAMELINKS/mui-fzf/blob/main/CHANGELOG.md
51
+ rubygems_mfa_required: 'true'
52
+ rdoc_options: []
53
+ require_paths:
54
+ - lib
55
+ required_ruby_version: !ruby/object:Gem::Requirement
56
+ requirements:
57
+ - - ">="
58
+ - !ruby/object:Gem::Version
59
+ version: 3.2.0
60
+ required_rubygems_version: !ruby/object:Gem::Requirement
61
+ requirements:
62
+ - - ">="
63
+ - !ruby/object:Gem::Version
64
+ version: '0'
65
+ requirements: []
66
+ rubygems_version: 4.0.0.beta2
67
+ specification_version: 4
68
+ summary: fzf integration plugin for Mui editor
69
+ test_files: []