mbeditor 0.12.6 → 0.12.7
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 +24 -0
- data/app/services/mbeditor/code_search_service.rb +21 -7
- data/app/services/mbeditor/search_replace_service.rb +39 -15
- data/lib/mbeditor/configuration.rb +1 -1
- data/lib/mbeditor/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 7e19be096529fa5f410c792379f88395494fa7783964604b2ff07bb5a93d39d8
|
|
4
|
+
data.tar.gz: d491ca7214661784bbb9d6bc78c13da045a2da9529649d088dae1b0171d17868
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 99bbd0a1dd19d7191563ea1586f5c38f9b68d0b70319f412be5439fb1588148b135aed1b8a20b66023129065ea84d71880d80054d6500a8ff1f2b83879f941c0
|
|
7
|
+
data.tar.gz: de0e4dfbb928584209ff4d5f1ace4a0bdb5c3b56a20c9a695c3c4770e2ccfd3a5063d9274f450706e13cabf4edd6ce2fdc3313b8477c6cecd28432eabc877246
|
data/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,30 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.12.7] - 2026-08-06
|
|
11
|
+
|
|
12
|
+
### Fixed
|
|
13
|
+
- **Project search was 10-80x slower than terminal grep on hosts without
|
|
14
|
+
ripgrep.** grep's `--exclude-dir` only accepts plain directory names, so the
|
|
15
|
+
slashed default exclusions (`vendor/bundle`, `public/assets`) never reached
|
|
16
|
+
the command line and grep walked those trees in full on every search, with
|
|
17
|
+
the matches discarded in Ruby afterwards. The grep tier now prunes every
|
|
18
|
+
exclusion with `find` — slashed paths included — and feeds the survivors to
|
|
19
|
+
grep in parallel batches (`xargs -P`), measured 7.2 s → 0.09 s on a 350 MB
|
|
20
|
+
tree with a realistic `vendor/bundle`, 3-4x faster than a plain terminal
|
|
21
|
+
`grep -r`. The same fix applies to `CodeSearchService`, which backs the JS
|
|
22
|
+
definition/global lookups and was reading precompiled `public/assets`
|
|
23
|
+
bundles on every "Cannot find name" the editor reported.
|
|
24
|
+
- **A search query starting with `-` was parsed as grep options.** Queries now
|
|
25
|
+
pass through `-e … --` on the grep tier.
|
|
26
|
+
- **Superseding a search now kills the whole pipeline.** The subprocess is
|
|
27
|
+
spawned in its own process group and the TERM goes to the group, so a
|
|
28
|
+
stacked keystroke cannot leave a find/grep pipeline running behind the
|
|
29
|
+
shell.
|
|
30
|
+
- **`vendor/cache` is excluded from search by default.** `bundle install
|
|
31
|
+
--local` keeps every `.gem` archive there — gigabytes of binary files search
|
|
32
|
+
has no business opening.
|
|
33
|
+
|
|
10
34
|
## [0.12.6] - 2026-08-05
|
|
11
35
|
|
|
12
36
|
### Added
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require "shellwords"
|
|
4
|
+
require "etc"
|
|
5
|
+
|
|
3
6
|
module Mbeditor
|
|
4
7
|
# Line-oriented regex search over the workspace's JS-family files. Backs the
|
|
5
8
|
# JS definition/member lookups. Same three-tier backend as
|
|
@@ -86,15 +89,26 @@ module Mbeditor
|
|
|
86
89
|
lines.map { |l| "#{workspace_root}/#{l}" }
|
|
87
90
|
end
|
|
88
91
|
|
|
92
|
+
# Same shape as SearchReplaceService's grep tier: find prunes every
|
|
93
|
+
# exclusion — slashed ones included, which --exclude-dir cannot express —
|
|
94
|
+
# before the walk, and applies the include/minified globs there too, so
|
|
95
|
+
# grep only ever opens candidate JS files. grep -r --include still walked
|
|
96
|
+
# (and for public/assets, read) the excluded trees on every lookup.
|
|
97
|
+
# ProcessRunner kills the process group, so the sh -c pipeline dies as
|
|
98
|
+
# one unit on timeout.
|
|
89
99
|
def run_grep(pattern, workspace_root, globs)
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
args = ["grep", "-I", "-rn", "--color=never", "-E", pattern] + includes + excludes
|
|
93
|
-
excluded_paths.reject { |p| p.include?("/") }.select { |d| d.match?(/\A[\w.-]+\z/) }.each do |d|
|
|
94
|
-
args << "--exclude-dir=#{d}"
|
|
100
|
+
prune = excluded_paths.flat_map do |p|
|
|
101
|
+
p.include?("/") ? ["-path", File.join(workspace_root, p), "-o"] : ["-name", p, "-o"]
|
|
95
102
|
end
|
|
96
|
-
|
|
97
|
-
|
|
103
|
+
find = ["find", workspace_root]
|
|
104
|
+
find += ["("] + prune[0..-2] + [")", "-prune", "-o"] unless prune.empty?
|
|
105
|
+
find += ["-type", "f", "("] + globs.flat_map { |g| ["-name", g, "-o"] }[0..-2] + [")"]
|
|
106
|
+
MINIFIED_GLOBS.each { |g| find += ["!", "-name", g] }
|
|
107
|
+
find << "-print0"
|
|
108
|
+
xargs = ["xargs", "-0", "-P", Etc.nprocessors.clamp(2, 8).to_s, "-n", "500",
|
|
109
|
+
"grep", "-I", "-Hn", "--line-buffered", "--color=never", "-E", "-e", pattern, "--"]
|
|
110
|
+
cmd = "#{Shellwords.shelljoin(find)} | #{Shellwords.shelljoin(xargs)}"
|
|
111
|
+
run_command(["sh", "-c", cmd], env: { "LC_ALL" => "C" })
|
|
98
112
|
end
|
|
99
113
|
end
|
|
100
114
|
end
|
|
@@ -3,6 +3,8 @@
|
|
|
3
3
|
require "open3"
|
|
4
4
|
require "json"
|
|
5
5
|
require "timeout"
|
|
6
|
+
require "shellwords"
|
|
7
|
+
require "etc"
|
|
6
8
|
|
|
7
9
|
module Mbeditor
|
|
8
10
|
# Project-wide text search and replace-in-files.
|
|
@@ -213,7 +215,9 @@ module Mbeditor
|
|
|
213
215
|
timed_out = false
|
|
214
216
|
timeout_secs = Mbeditor.configuration.search_timeout
|
|
215
217
|
|
|
216
|
-
|
|
218
|
+
# pgroup: the grep tier is a sh -c pipeline; killing only the shell
|
|
219
|
+
# would leave find/xargs/grep running. TERM goes to the whole group.
|
|
220
|
+
io = IO.popen(env, args, err: File::NULL, pgroup: true)
|
|
217
221
|
pid = io.pid
|
|
218
222
|
register_search(root, pid) if supersede
|
|
219
223
|
watchdog = nil
|
|
@@ -301,18 +305,32 @@ module Mbeditor
|
|
|
301
305
|
# for -E, and the UTF-8 locale case-folds non-ASCII correctly.
|
|
302
306
|
[{}, args]
|
|
303
307
|
else
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
308
|
+
grep = ["grep", "-I", "-Hn", "--line-buffered", use_regex ? "-E" : "-F"]
|
|
309
|
+
grep << "-i" unless match_case
|
|
310
|
+
grep << "-w" if whole_word
|
|
311
|
+
# -e + -- so a query starting with "-" can't be parsed as options.
|
|
312
|
+
grep += ["-e", query, "--"]
|
|
313
|
+
if paths
|
|
314
|
+
[{ "LC_ALL" => "C" }, grep + paths.map { |p| File.expand_path(p, root) }]
|
|
315
|
+
else
|
|
316
|
+
# find prunes every exclusion — slashed ones included, which
|
|
317
|
+
# --exclude-dir cannot express — *before* the walk, then feeds the
|
|
318
|
+
# survivors to grep in parallel batches. grep -r with post-filtered
|
|
319
|
+
# exclusions read vendor/bundle and public/assets in full on every
|
|
320
|
+
# search; measured 7.2 s -> 0.09 s on a 350 MB tree. --line-buffered
|
|
321
|
+
# keeps concurrent greps from tearing lines mid-row on the shared
|
|
322
|
+
# pipe.
|
|
323
|
+
prune = exclusions.flat_map do |p|
|
|
324
|
+
p.include?("/") ? ["-path", File.join(root, p), "-o"] : ["-name", p, "-o"]
|
|
325
|
+
end
|
|
326
|
+
find = ["find", root]
|
|
327
|
+
find += ["("] + prune[0..-2] + [")", "-prune", "-o"] unless prune.empty?
|
|
328
|
+
find += ["-type", "f", "-print0"]
|
|
329
|
+
workers = Etc.nprocessors.clamp(2, 8)
|
|
330
|
+
xargs = ["xargs", "-0", "-P", workers.to_s, "-n", "500"] + grep
|
|
331
|
+
cmd = "#{Shellwords.shelljoin(find)} | #{Shellwords.shelljoin(xargs)}"
|
|
332
|
+
[{ "LC_ALL" => "C" }, ["sh", "-c", cmd]]
|
|
333
|
+
end
|
|
316
334
|
end
|
|
317
335
|
end
|
|
318
336
|
|
|
@@ -370,9 +388,15 @@ module Mbeditor
|
|
|
370
388
|
end
|
|
371
389
|
|
|
372
390
|
def kill_quietly(pid)
|
|
373
|
-
|
|
391
|
+
return unless pid
|
|
392
|
+
|
|
393
|
+
Process.kill("TERM", -pid)
|
|
374
394
|
rescue StandardError
|
|
375
|
-
|
|
395
|
+
begin
|
|
396
|
+
Process.kill("TERM", pid)
|
|
397
|
+
rescue StandardError
|
|
398
|
+
nil
|
|
399
|
+
end
|
|
376
400
|
end
|
|
377
401
|
|
|
378
402
|
def monotonic
|
|
@@ -18,7 +18,7 @@ module Mbeditor
|
|
|
18
18
|
def initialize
|
|
19
19
|
@allowed_environments = [:development]
|
|
20
20
|
@workspace_root = nil
|
|
21
|
-
@excluded_paths = %w[.git tmp log node_modules .bundle coverage vendor/bundle public/assets storage]
|
|
21
|
+
@excluded_paths = %w[.git tmp log node_modules .bundle coverage vendor/bundle vendor/cache public/assets storage]
|
|
22
22
|
@rubocop_command = "rubocop"
|
|
23
23
|
@rubocop_server = true # use rubocop's --server daemon (rubocop >= 1.31) for ~10x faster lint; false forces --no-server
|
|
24
24
|
@redmine_enabled = false
|
data/lib/mbeditor/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: mbeditor
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.12.
|
|
4
|
+
version: 0.12.7
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Oliver Noonan
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-08-
|
|
11
|
+
date: 2026-08-06 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: rails
|