mbeditor 0.5.3 → 0.7.1

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 (54) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +77 -0
  3. data/README.md +7 -0
  4. data/app/assets/javascripts/mbeditor/application.js +3 -0
  5. data/app/assets/javascripts/mbeditor/components/ChangelogView.js +145 -0
  6. data/app/assets/javascripts/mbeditor/components/DiffViewer.js +1 -1
  7. data/app/assets/javascripts/mbeditor/components/EditorPanel.js +359 -31
  8. data/app/assets/javascripts/mbeditor/components/FileTree.js +177 -116
  9. data/app/assets/javascripts/mbeditor/components/MbeditorApp.js +952 -143
  10. data/app/assets/javascripts/mbeditor/components/TabBar.js +9 -0
  11. data/app/assets/javascripts/mbeditor/conflict_parser.js +48 -0
  12. data/app/assets/javascripts/mbeditor/editor_plugins.js +420 -67
  13. data/app/assets/javascripts/mbeditor/editor_store.js +1 -0
  14. data/app/assets/javascripts/mbeditor/file_service.js +34 -6
  15. data/app/assets/javascripts/mbeditor/git_service.js +2 -1
  16. data/app/assets/javascripts/mbeditor/history_service.js +177 -0
  17. data/app/assets/javascripts/mbeditor/search_service.js +1 -0
  18. data/app/assets/javascripts/mbeditor/tab_manager.js +8 -5
  19. data/app/assets/stylesheets/mbeditor/application.css +112 -0
  20. data/app/assets/stylesheets/mbeditor/editor.css +443 -78
  21. data/app/channels/mbeditor/editor_channel.rb +5 -41
  22. data/app/controllers/mbeditor/application_controller.rb +8 -1
  23. data/app/controllers/mbeditor/editors_controller.rb +276 -654
  24. data/app/controllers/mbeditor/git_controller.rb +2 -61
  25. data/app/services/mbeditor/availability_probe.rb +83 -0
  26. data/app/services/mbeditor/code_search_service.rb +42 -0
  27. data/app/services/mbeditor/editor_state_service.rb +91 -0
  28. data/app/services/mbeditor/exclusion_matcher.rb +23 -0
  29. data/app/services/mbeditor/file_operation_service.rb +68 -0
  30. data/app/services/mbeditor/file_tree_service.rb +69 -0
  31. data/app/services/mbeditor/git_combined_diff_service.rb +43 -0
  32. data/app/services/mbeditor/git_commit_detail_service.rb +46 -0
  33. data/app/services/mbeditor/git_info_service.rb +151 -0
  34. data/app/services/mbeditor/git_service.rb +36 -26
  35. data/app/services/mbeditor/js_definition_service.rb +59 -0
  36. data/app/services/mbeditor/js_members_service.rb +62 -0
  37. data/app/services/mbeditor/process_runner.rb +48 -0
  38. data/app/services/mbeditor/rails_related_files_service.rb +282 -0
  39. data/app/services/mbeditor/ruby_definition_service.rb +77 -101
  40. data/app/services/mbeditor/schema_service.rb +270 -0
  41. data/app/services/mbeditor/search_replace_service.rb +184 -0
  42. data/app/services/mbeditor/test_runner_service.rb +5 -27
  43. data/app/views/layouts/mbeditor/application.html.erb +2 -2
  44. data/config/routes.rb +8 -1
  45. data/lib/mbeditor/configuration.rb +4 -2
  46. data/lib/mbeditor/version.rb +1 -1
  47. data/public/monaco-editor/vs/language/css/cssMode.js +13 -0
  48. data/public/monaco-editor/vs/language/css/cssWorker.js +77 -0
  49. data/public/monaco-editor/vs/language/html/htmlMode.js +13 -0
  50. data/public/monaco-editor/vs/language/html/htmlWorker.js +454 -0
  51. data/public/monaco-editor/vs/language/json/jsonMode.js +19 -0
  52. data/public/monaco-editor/vs/language/json/jsonWorker.js +42 -0
  53. metadata +26 -3
  54. data/app/services/mbeditor/unused_methods_service.rb +0 -139
@@ -1,139 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "open3"
4
- require "timeout"
5
-
6
- module Mbeditor
7
- # Finds method definitions in a file that have no call-sites anywhere in the
8
- # workspace. Uses a single ripgrep (or grep) subprocess with an alternation
9
- # pattern so cost is O(1) subprocesses regardless of how many methods the
10
- # file contains.
11
- #
12
- # Results are cached per-file; entries are invalidated when the file's mtime
13
- # changes OR when the entry is older than CACHE_TTL_SECONDS (handles edits
14
- # to other files that may add or remove call-sites).
15
- #
16
- # Usage:
17
- # UnusedMethodsService.call(workspace_root, abs_path,
18
- # excluded_dirnames: [], excluded_paths: [])
19
- # → [{ name: "my_method", line: 42 }, ...]
20
- class UnusedMethodsService
21
- CACHE_TTL_SECONDS = 30
22
- RG_TIMEOUT = 10
23
- GREP_TIMEOUT = 30
24
-
25
- @cache = {}
26
- @cache_mutex = Mutex.new
27
-
28
- class << self
29
- def call(workspace_root, file_path, excluded_dirnames: [], excluded_paths: [])
30
- file_path = file_path.to_s
31
-
32
- begin
33
- mtime = File.mtime(file_path).to_f
34
- rescue StandardError
35
- return []
36
- end
37
-
38
- # Return cached result if file mtime matches and the entry is fresh.
39
- cached = @cache_mutex.synchronize { @cache[file_path] }
40
- if cached && cached[:mtime] == mtime &&
41
- (Process.clock_gettime(Process::CLOCK_MONOTONIC) - cached[:ts]) < CACHE_TTL_SECONDS
42
- return cached[:result]
43
- end
44
-
45
- # Ensure the file is indexed (populates module_names / include_calls too).
46
- defs = RubyDefinitionService.defs_in_file(file_path)
47
- if defs.empty?
48
- # File not yet in cache; trigger a parse of just this one file by
49
- # calling the definition service with a dummy symbol.
50
- RubyDefinitionService.call(workspace_root, "__mbeditor_warmup__",
51
- excluded_dirnames: excluded_dirnames,
52
- excluded_paths: excluded_paths)
53
- defs = RubyDefinitionService.defs_in_file(file_path)
54
- end
55
- return [] if defs.empty?
56
-
57
- method_names = defs.keys
58
- counts = count_occurrences(method_names, workspace_root.to_s,
59
- excluded_dirnames: excluded_dirnames,
60
- excluded_paths: excluded_paths)
61
-
62
- # A method with ≤1 total occurrence has only its own `def` line; no call-sites.
63
- unused = method_names.select { |n| counts.fetch(n, 0) <= 1 }
64
- result = unused.filter_map do |name|
65
- entries = defs[name]
66
- next unless entries&.any?
67
- { name: name, line: entries.first[:line] }
68
- end
69
-
70
- ts = Process.clock_gettime(Process::CLOCK_MONOTONIC)
71
- @cache_mutex.synchronize do
72
- @cache[file_path] = { mtime: mtime, ts: ts, result: result }
73
- end
74
-
75
- result
76
- rescue StandardError
77
- []
78
- end
79
-
80
- # Exposed for tests.
81
- def clear_cache!
82
- @cache_mutex.synchronize { @cache.clear }
83
- end
84
-
85
- private
86
-
87
- RG_AVAILABLE = system("which rg > /dev/null 2>&1")
88
-
89
- def count_occurrences(method_names, workspace_root, excluded_dirnames:, excluded_paths:)
90
- # Build one alternation pattern matching any of the method names as
91
- # whole identifiers. We escape each name and join with |.
92
- escaped = method_names.map { |n| Regexp.escape(n) }
93
- pattern = "\\b(#{escaped.join('|')})\\b"
94
-
95
- if RG_AVAILABLE
96
- run_ripgrep(pattern, method_names, workspace_root, excluded_paths)
97
- else
98
- run_grep(pattern, method_names, workspace_root, excluded_dirnames)
99
- end
100
- end
101
-
102
- # ripgrep: --only-matching outputs one match per line (just the matched text).
103
- def run_ripgrep(pattern, method_names, workspace_root, excluded_paths)
104
- args = %w[rg --only-matching --no-filename --no-ignore --glob **/*.rb]
105
- excluded_paths.each { |p| args += ["--glob", "!#{p}"] }
106
- args += ["-e", pattern, workspace_root]
107
-
108
- counts = Hash.new(0)
109
- name_set = method_names.to_set
110
- Timeout.timeout(RG_TIMEOUT) do
111
- IO.popen(args, err: File::NULL) do |io|
112
- io.each_line { |line| name = line.chomp; counts[name] += 1 if name_set.include?(name) }
113
- end
114
- end
115
- counts
116
- rescue StandardError
117
- {}
118
- end
119
-
120
- # grep -oh: -o outputs only the matching part, -h suppresses filenames.
121
- def run_grep(pattern, method_names, workspace_root, excluded_dirnames)
122
- args = ["grep", "-roh", "-E", pattern, "--include=*.rb"]
123
- excluded_dirnames.each { |d| args += ["--exclude-dir=#{d}"] }
124
- args << workspace_root
125
-
126
- counts = Hash.new(0)
127
- name_set = method_names.to_set
128
- Timeout.timeout(GREP_TIMEOUT) do
129
- IO.popen(args, err: File::NULL) do |io|
130
- io.each_line { |line| name = line.chomp; counts[name] += 1 if name_set.include?(name) }
131
- end
132
- end
133
- counts
134
- rescue StandardError
135
- {}
136
- end
137
- end
138
- end
139
- end