mbeditor 0.3.8 → 0.3.9
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 +10 -0
- data/app/assets/javascripts/mbeditor/application_iife_head.js +7 -0
- data/app/assets/javascripts/mbeditor/components/CodeReviewPanel.js +1 -1
- data/app/assets/javascripts/mbeditor/components/EditorPanel.js +52 -11
- data/app/assets/javascripts/mbeditor/components/GitPanel.js +14 -4
- data/app/assets/javascripts/mbeditor/components/MbeditorApp.js +316 -133
- data/app/assets/javascripts/mbeditor/components/QuickOpenDialog.js +25 -1
- data/app/assets/javascripts/mbeditor/editor_store.js +10 -2
- data/app/assets/javascripts/mbeditor/file_service.js +23 -23
- data/app/assets/javascripts/mbeditor/git_service.js +7 -11
- data/app/assets/javascripts/mbeditor/search_service.js +45 -12
- data/app/assets/javascripts/mbeditor/tab_manager.js +3 -3
- data/app/assets/stylesheets/mbeditor/editor.css +12 -5
- data/app/controllers/mbeditor/editors_controller.rb +134 -128
- data/app/controllers/mbeditor/git_controller.rb +5 -40
- data/app/services/mbeditor/git_blame_service.rb +6 -0
- data/app/services/mbeditor/git_commit_graph_service.rb +2 -0
- data/app/services/mbeditor/git_service.rb +97 -28
- data/app/services/mbeditor/redmine_service.rb +7 -0
- data/app/services/mbeditor/ruby_definition_service.rb +23 -2
- data/lib/mbeditor/configuration.rb +7 -1
- data/lib/mbeditor/engine.rb +27 -0
- data/lib/mbeditor/version.rb +3 -1
- data/lib/mbeditor.rb +2 -0
- 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: 3e496861ff75f2bb3c09388afbc609c07230ad8a914de28040b867ccb922a04d
|
|
4
|
+
data.tar.gz: f5825193b830cca72f626a86a15483eb46ccb4cd335388a6ccaed088841ff313
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: dd1ed23cefc9609ca7d99d77410104b63107dc0e72f80e72279adc4a01cba1a6da3fe2d6e0467ec23b7db1166d3ccbdfcf380d4057c5644008ab4a9fa87e5092
|
|
7
|
+
data.tar.gz: 0b6bc8dcec6f206fc3867c19bc7ffe028230b8503109dc8473e10997abe41c56db0fd3970f88c23bbf6fd69873c1d905cc0ce11a2010c6205cccc891ee511982
|
data/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,16 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [0.3.9] - 2026-04-21
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
- Search responses now include a total result count; background counting runs for the first page to populate it without blocking.
|
|
12
|
+
- Editor preferences expanded with line height, letter spacing, cursor style, and auto-closing bracket/quote settings.
|
|
13
|
+
|
|
14
|
+
### Fixed
|
|
15
|
+
- Multi-line tab indentation corrected; added regression test to prevent recurrence.
|
|
16
|
+
- 8 correctness, security, and reliability fixes surfaced by ultrareview.
|
|
17
|
+
|
|
8
18
|
## [0.3.8] - 2026-04-16
|
|
9
19
|
|
|
10
20
|
### Fixed
|
|
@@ -1,4 +1,11 @@
|
|
|
1
1
|
// Mbeditor app IIFE — React and ReactDOM are injected from window.MbeditorRuntime
|
|
2
2
|
// so that mbeditor never reads from or writes to window.React / window.ReactDOM,
|
|
3
3
|
// protecting the host application's globals.
|
|
4
|
+
|
|
5
|
+
// Shared helper — returns the engine mount path with no trailing slash.
|
|
6
|
+
// All service modules and components use this instead of inlining the lookup.
|
|
7
|
+
window.mbeditorBasePath = function() {
|
|
8
|
+
return (window.MBEDITOR_BASE_PATH || '/mbeditor').replace(/\/$/, '');
|
|
9
|
+
};
|
|
10
|
+
|
|
4
11
|
(function(React, ReactDOM) {
|
|
@@ -27,7 +27,7 @@ var CodeReviewPanel = function CodeReviewPanel(_ref) {
|
|
|
27
27
|
setIsRedmineLoading(true);
|
|
28
28
|
|
|
29
29
|
// Call the redmine endpoint. It will 503 if disabled via config.
|
|
30
|
-
axios.get(
|
|
30
|
+
axios.get(window.mbeditorBasePath() + '/redmine/issue/' + issueId)
|
|
31
31
|
.then(function (res) {
|
|
32
32
|
setRedmineIssue(res.data);
|
|
33
33
|
setIsRedmineLoading(false);
|
|
@@ -480,24 +480,34 @@ var EditorPanel = function EditorPanel(_ref) {
|
|
|
480
480
|
theme: editorPrefs.theme || 'vs-dark',
|
|
481
481
|
automaticLayout: true,
|
|
482
482
|
minimap: { enabled: !!(editorPrefs.minimap) },
|
|
483
|
-
renderLineHighlight: 'none',
|
|
483
|
+
renderLineHighlight: editorPrefs.renderLineHighlight || 'none',
|
|
484
484
|
bracketPairColorization: { enabled: editorPrefs.bracketPairColorization !== false },
|
|
485
485
|
fontFamily: editorPrefs.fontFamily || "'JetBrains Mono', 'Fira Code', Consolas, 'Courier New', monospace",
|
|
486
486
|
fontSize: editorPrefs.fontSize || 13,
|
|
487
|
+
lineHeight: editorPrefs.lineHeight || 0,
|
|
488
|
+
letterSpacing: editorPrefs.letterSpacing || 0,
|
|
487
489
|
tabSize: editorPrefs.tabSize || 4,
|
|
488
490
|
insertSpaces: typeof editorPrefs.insertSpaces === 'boolean' ? editorPrefs.insertSpaces : false,
|
|
489
491
|
wordWrap: editorPrefs.wordWrap || 'off',
|
|
490
492
|
lineNumbers: editorPrefs.lineNumbers || 'on',
|
|
491
493
|
renderWhitespace: editorPrefs.renderWhitespace || 'none',
|
|
492
494
|
scrollBeyondLastLine: !!(editorPrefs.scrollBeyondLastLine),
|
|
493
|
-
|
|
495
|
+
cursorStyle: editorPrefs.cursorStyle || 'line',
|
|
496
|
+
cursorBlinking: editorPrefs.cursorBlinking || 'blink',
|
|
497
|
+
folding: editorPrefs.folding !== false,
|
|
498
|
+
smoothScrolling: !!(editorPrefs.smoothScrolling),
|
|
499
|
+
mouseWheelZoom: !!(editorPrefs.mouseWheelZoom),
|
|
500
|
+
autoClosingBrackets: editorPrefs.autoClosingBrackets || 'always',
|
|
501
|
+
autoClosingQuotes: editorPrefs.autoClosingQuotes || 'always',
|
|
502
|
+
autoIndent: editorPrefs.autoIndent || 'full',
|
|
503
|
+
formatOnPaste: editorPrefs.formatOnPaste !== false,
|
|
504
|
+
formatOnType: editorPrefs.formatOnType !== false,
|
|
505
|
+
quickSuggestions: editorPrefs.quickSuggestions !== false,
|
|
506
|
+
wordBasedSuggestions: editorPrefs.wordBasedSuggestions || 'matchingDocuments',
|
|
507
|
+
acceptSuggestionOnEnter: editorPrefs.acceptSuggestionOnEnter || 'on',
|
|
508
|
+
linkedEditing: true,
|
|
494
509
|
fixedOverflowWidgets: true,
|
|
495
|
-
hover: { above: false }
|
|
496
|
-
autoClosingBrackets: 'always',
|
|
497
|
-
autoClosingQuotes: 'always',
|
|
498
|
-
autoIndent: 'full',
|
|
499
|
-
formatOnPaste: true,
|
|
500
|
-
formatOnType: true
|
|
510
|
+
hover: { above: false }
|
|
501
511
|
});
|
|
502
512
|
|
|
503
513
|
if (tab.viewState) {
|
|
@@ -700,6 +710,8 @@ var EditorPanel = function EditorPanel(_ref) {
|
|
|
700
710
|
monacoRef.current.updateOptions({
|
|
701
711
|
fontSize: editorPrefs.fontSize || 13,
|
|
702
712
|
fontFamily: editorPrefs.fontFamily || "'JetBrains Mono', 'Fira Code', Consolas, 'Courier New', monospace",
|
|
713
|
+
lineHeight: editorPrefs.lineHeight || 0,
|
|
714
|
+
letterSpacing: editorPrefs.letterSpacing || 0,
|
|
703
715
|
tabSize: editorPrefs.tabSize || 4,
|
|
704
716
|
insertSpaces: typeof editorPrefs.insertSpaces === 'boolean' ? editorPrefs.insertSpaces : false,
|
|
705
717
|
wordWrap: editorPrefs.wordWrap || 'off',
|
|
@@ -707,7 +719,21 @@ var EditorPanel = function EditorPanel(_ref) {
|
|
|
707
719
|
renderWhitespace: editorPrefs.renderWhitespace || 'none',
|
|
708
720
|
minimap: { enabled: !!(editorPrefs.minimap) },
|
|
709
721
|
scrollBeyondLastLine: !!(editorPrefs.scrollBeyondLastLine),
|
|
710
|
-
bracketPairColorization: { enabled: editorPrefs.bracketPairColorization !== false }
|
|
722
|
+
bracketPairColorization: { enabled: editorPrefs.bracketPairColorization !== false },
|
|
723
|
+
renderLineHighlight: editorPrefs.renderLineHighlight || 'none',
|
|
724
|
+
cursorStyle: editorPrefs.cursorStyle || 'line',
|
|
725
|
+
cursorBlinking: editorPrefs.cursorBlinking || 'blink',
|
|
726
|
+
folding: editorPrefs.folding !== false,
|
|
727
|
+
smoothScrolling: !!(editorPrefs.smoothScrolling),
|
|
728
|
+
mouseWheelZoom: !!(editorPrefs.mouseWheelZoom),
|
|
729
|
+
autoClosingBrackets: editorPrefs.autoClosingBrackets || 'always',
|
|
730
|
+
autoClosingQuotes: editorPrefs.autoClosingQuotes || 'always',
|
|
731
|
+
autoIndent: editorPrefs.autoIndent || 'full',
|
|
732
|
+
formatOnPaste: editorPrefs.formatOnPaste !== false,
|
|
733
|
+
formatOnType: editorPrefs.formatOnType !== false,
|
|
734
|
+
quickSuggestions: editorPrefs.quickSuggestions !== false,
|
|
735
|
+
wordBasedSuggestions: editorPrefs.wordBasedSuggestions || 'matchingDocuments',
|
|
736
|
+
acceptSuggestionOnEnter: editorPrefs.acceptSuggestionOnEnter || 'on'
|
|
711
737
|
});
|
|
712
738
|
}
|
|
713
739
|
}, [editorPrefs]);
|
|
@@ -1157,6 +1183,22 @@ var EditorPanel = function EditorPanel(_ref) {
|
|
|
1157
1183
|
renderer.html = function (token) {
|
|
1158
1184
|
return '<pre>' + escapeHtml(typeof token === 'object' ? token.text : token) + '</pre>';
|
|
1159
1185
|
};
|
|
1186
|
+
// Sanitize link/image hrefs to block javascript: and data: schemes.
|
|
1187
|
+
var _origLink = renderer.link.bind(renderer);
|
|
1188
|
+
var _origImage = renderer.image.bind(renderer);
|
|
1189
|
+
var SAFE_HREF_SCHEME = /^(https?:|mailto:|#|\/)/i;
|
|
1190
|
+
var safeHref = function(href) {
|
|
1191
|
+
if (!href) return href;
|
|
1192
|
+
return SAFE_HREF_SCHEME.test(href.trim()) ? href : '#';
|
|
1193
|
+
};
|
|
1194
|
+
renderer.link = function(token) {
|
|
1195
|
+
if (token && typeof token === 'object') { token = Object.assign({}, token, { href: safeHref(token.href) }); }
|
|
1196
|
+
return _origLink(token);
|
|
1197
|
+
};
|
|
1198
|
+
renderer.image = function(token) {
|
|
1199
|
+
if (token && typeof token === 'object') { token = Object.assign({}, token, { href: safeHref(token.href) }); }
|
|
1200
|
+
return _origImage(token);
|
|
1201
|
+
};
|
|
1160
1202
|
setMarkup(window.marked.parse(markdownContent, { renderer: renderer }));
|
|
1161
1203
|
})();
|
|
1162
1204
|
}
|
|
@@ -1192,11 +1234,10 @@ var EditorPanel = function EditorPanel(_ref) {
|
|
|
1192
1234
|
}
|
|
1193
1235
|
|
|
1194
1236
|
if (isImage) {
|
|
1195
|
-
var basePath = (window.MBEDITOR_BASE_PATH || '/mbeditor').replace(/\/$/, '');
|
|
1196
1237
|
return React.createElement(
|
|
1197
1238
|
'div',
|
|
1198
1239
|
{ className: 'monaco-container', style: { display: 'flex', alignItems: 'center', justifyContent: 'center', background: '#1e1e1e' } },
|
|
1199
|
-
React.createElement('img', { src:
|
|
1240
|
+
React.createElement('img', { src: window.mbeditorBasePath() + '/raw?path=' + encodeURIComponent(tab.path), style: { maxWidth: '90%', maxHeight: '90%', objectFit: 'contain' }, alt: tab.name })
|
|
1200
1241
|
);
|
|
1201
1242
|
}
|
|
1202
1243
|
|
|
@@ -14,8 +14,19 @@ var GitPanel = function GitPanel(_ref) {
|
|
|
14
14
|
var _s1 = useState(true); var localExpanded = _s1[0]; var setLocalExpanded = _s1[1];
|
|
15
15
|
var _s2 = useState(true); var branchExpanded = _s2[0]; var setBranchExpanded = _s2[1];
|
|
16
16
|
var _s3 = useState(true); var historyExpanded= _s3[0]; var setHistoryExpanded= _s3[1];
|
|
17
|
-
|
|
18
|
-
|
|
17
|
+
|
|
18
|
+
// { [hash]: true|false } — persisted to localStorage keyed by root path so
|
|
19
|
+
// users don't need to re-expand commits on every page load.
|
|
20
|
+
var _lsKey = 'mbeditor_expanded_commits_' + (window.MBEDITOR_BASE_PATH || '');
|
|
21
|
+
var _lsInitial = (function() {
|
|
22
|
+
try { return JSON.parse(localStorage.getItem(_lsKey)) || {}; } catch(e) { return {}; }
|
|
23
|
+
})();
|
|
24
|
+
var _s4 = useState(_lsInitial); var expandedCommits = _s4[0]; var setExpandedCommits = _s4[1];
|
|
25
|
+
|
|
26
|
+
// Persist expandedCommits whenever it changes.
|
|
27
|
+
useEffect(function() {
|
|
28
|
+
try { localStorage.setItem(_lsKey, JSON.stringify(expandedCommits)); } catch(e) {}
|
|
29
|
+
}, [expandedCommits]);
|
|
19
30
|
// { [hash]: { loading, files: [{status,path}], error } }
|
|
20
31
|
var _s5 = useState({}); var commitFiles = _s5[0]; var setCommitFiles = _s5[1];
|
|
21
32
|
var _s6 = useState(false); var refreshing = _s6[0]; var setRefreshing = _s6[1];
|
|
@@ -55,8 +66,7 @@ var GitPanel = function GitPanel(_ref) {
|
|
|
55
66
|
setRedmineLoading(true);
|
|
56
67
|
setRedmineIssue(null);
|
|
57
68
|
setRedmineError(null);
|
|
58
|
-
|
|
59
|
-
axios.get(basePath + '/redmine/issue/' + redmineTicketId)
|
|
69
|
+
axios.get(window.mbeditorBasePath() + '/redmine/issue/' + redmineTicketId)
|
|
60
70
|
.then(function (res) {
|
|
61
71
|
setRedmineIssue(res.data);
|
|
62
72
|
setRedmineLoading(false);
|