mbeditor 0.1.4 → 0.1.5

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 45f561cf7e36141944025bc54ce679c4492a7c7315902532e350eab44b138361
4
- data.tar.gz: 7612a0802d9c8e65d0539b621362b0adc3f09866bf131b14b707efafcd35e752
3
+ metadata.gz: 414b42474453e80d58cfafbab5db7d5381dd8ebb22ba1e852a10e720eb246d8a
4
+ data.tar.gz: 0fbaffaedc1aed6196589975816fb9b009df7f4a810dcc41e3aa428d8e19ee37
5
5
  SHA512:
6
- metadata.gz: c896888e924acc1d11e38a0efcdf6f7caec6013eb02426e4d4a0ee847accb3eb5872e5a40e1d4ca7551892352d9fce72ae4667a9585c8265ec7ffc7927e85341
7
- data.tar.gz: d8cbae4ecfd6b3ec04fd5fde655a52cd176830ff38d02c89bd76e7b09372be63b0f227261ec3dcfda2cd79edbe9811a0a2bfddff58a51b2c5d1d36ac199fc3c5
6
+ metadata.gz: 4bab09aab7ae92d7835838d3c4b240915d0c3ff0c3fc32516a69bdad24430246c86c0da3f508946e9c738ca94a0966d7457903ba9095000a4f01643ca298dbe7
7
+ data.tar.gz: 522f1e56c9c280ccf9078f9f960ad1c3e3f1d1f99fafc2e9d80c18d539cd6ba409d18cb596b434037e551403623b74c54c7f2f4dfe8c03c90760eebe8b51862c
@@ -1,4 +1,5 @@
1
1
  //= require mbeditor/editor_store
2
+ //= require mbeditor/file_icon
2
3
  //= require mbeditor/file_service
3
4
  //= require mbeditor/git_service
4
5
  //= require mbeditor/search_service
@@ -83,10 +83,12 @@ var DiffViewer = function DiffViewer(_ref) {
83
83
 
84
84
  function getLanguageForPath(filePath) {
85
85
  if (!filePath) return 'plaintext';
86
+ var fileName = filePath.split('/').pop().toLowerCase();
87
+ if (fileName === 'gemfile' || fileName === 'gemfile.lock' || fileName === 'rakefile') return 'ruby';
86
88
  var ext = filePath.split('.').pop().toLowerCase();
87
89
  var map = {
88
90
  'rb': 'ruby', 'js': 'javascript', 'jsx': 'javascript',
89
- 'ts': 'javascript', 'tsx': 'javascript',
91
+ 'ts': 'typescript', 'tsx': 'typescript',
90
92
  'json': 'json', 'yml': 'yaml', 'yaml': 'yaml',
91
93
  'css': 'css', 'scss': 'scss', 'html': 'html',
92
94
  'xml': 'xml', 'md': 'markdown', 'sh': 'shell'
@@ -75,16 +75,23 @@ var EditorPanel = function EditorPanel(_ref) {
75
75
  window.MbeditorEditorPlugins.registerGlobalExtensions(window.monaco);
76
76
  }
77
77
 
78
- var parts = tab.path.split('.');
78
+ var fileName = tab.path.split('/').pop() || '';
79
+ var parts = fileName.split('.');
79
80
  var extension = parts.length > 1 ? parts.pop().toLowerCase() : '';
80
81
  var language = 'plaintext';
81
- switch (extension) {
82
- case 'rb':case 'ruby':case 'gemspec':case 'rakefile':
82
+ switch (fileName.toLowerCase()) {
83
+ case 'gemfile':
84
+ case 'gemfile.lock':
85
+ case 'rakefile':
83
86
  language = 'ruby';break;
87
+ default:
88
+ switch (extension) {
89
+ case 'rb':case 'ruby':case 'gemspec':
90
+ language = 'ruby';break;
84
91
  case 'js':case 'jsx':
85
92
  language = 'javascript';break;
86
93
  case 'ts':case 'tsx':
87
- language = 'javascript';break;
94
+ language = 'typescript';break;
88
95
  case 'css':case 'scss':case 'sass':
89
96
  language = 'css';break;
90
97
  case 'html':case 'erb':
@@ -101,6 +108,7 @@ var EditorPanel = function EditorPanel(_ref) {
101
108
  language = 'shell';break;
102
109
  case 'png':case 'jpg':case 'jpeg':case 'gif':case 'svg':case 'ico':case 'webp':case 'bmp':case 'avif':
103
110
  language = 'image';break;
111
+ }
104
112
  }
105
113
 
106
114
  if (language === 'image') return;
@@ -109,23 +109,6 @@ var FileTree = function FileTree(_ref) {
109
109
  return { badge: key || '?', cssKey: key || 'Q', title: titleMap[key] || 'Status' };
110
110
  };
111
111
 
112
- window.getFileIcon = function (name) {
113
- var ext = name.split('.').pop().toLowerCase();
114
- var lName = name.toLowerCase();
115
- if (lName === 'gemfile' || ext === 'gemspec' || ext === 'lock') return 'fas fa-gem ruby-icon';
116
- if (ext === 'rb' || ext === 'rake' || lName === 'rakefile') return 'far fa-gem ruby-icon';
117
- if (ext === 'jsx' || name.endsWith('.js.jsx')) return 'fas fa-atom react-icon';
118
- if (ext === 'js' || ext === 'mjs' || ext === 'cjs') return 'fa-brands fa-js js-icon';
119
- if (ext === 'html') return 'fa-brands fa-html5 html-icon';
120
- if (ext === 'erb') return 'fa-brands fa-html5 erb-icon';
121
- if (ext === 'css' || ext === 'scss' || ext === 'sass') return 'fa-brands fa-css3-alt css-icon';
122
- if (['png', 'jpg', 'jpeg', 'gif', 'svg', 'ico', 'webp', 'bmp', 'avif'].includes(ext)) return 'far fa-file-image image-icon';
123
- if (ext === 'json') return 'fas fa-code json-icon';
124
- if (ext === 'md' || ext === 'txt') return 'fas fa-file-alt md-icon';
125
- if (ext === 'yml' || ext === 'yaml') return 'fas fa-cogs yml-icon';
126
- return 'far fa-file-code';
127
- };
128
-
129
112
  var handleInlineKeyDown = function handleInlineKeyDown(e) {
130
113
  var isRename = !!pendingRename;
131
114
  if (e.key === 'Enter') {
@@ -16,6 +16,7 @@ var GitPanel = function GitPanel(_ref) {
16
16
  var _s4 = useState({}); var expandedCommits = _s4[0]; var setExpandedCommits = _s4[1];
17
17
  // { [hash]: { loading, files: [{status,path}], error } }
18
18
  var _s5 = useState({}); var commitFiles = _s5[0]; var setCommitFiles = _s5[1];
19
+ var _s6 = useState(false); var refreshing = _s6[0]; var setRefreshing = _s6[1];
19
20
 
20
21
  var workingTree = gitInfo && gitInfo.workingTree || [];
21
22
  var unpushedFiles = gitInfo && gitInfo.unpushedFiles || [];
@@ -46,36 +47,7 @@ var GitPanel = function GitPanel(_ref) {
46
47
  };
47
48
 
48
49
  var fileIcon = function fileIcon(filename) {
49
- var ext = (filename || '').split('.').pop().toLowerCase();
50
- var iconMap = {
51
- 'rb': { cls: 'fas fa-gem', color: '#cc342d' },
52
- 'gemspec': { cls: 'fas fa-gem', color: '#cc342d' },
53
- 'js': { cls: 'fab fa-js', color: '#f0db4f' },
54
- 'ts': { cls: 'fas fa-code', color: '#3178c6' },
55
- 'jsx': { cls: 'fab fa-js', color: '#61dafb' },
56
- 'tsx': { cls: 'fas fa-code', color: '#61dafb' },
57
- 'html': { cls: 'fab fa-html5', color: '#e34f26' },
58
- 'htm': { cls: 'fab fa-html5', color: '#e34f26' },
59
- 'erb': { cls: 'fab fa-html5', color: '#cc342d' },
60
- 'css': { cls: 'fab fa-css3-alt', color: '#1572b6' },
61
- 'scss': { cls: 'fab fa-sass', color: '#cc6699' },
62
- 'sass': { cls: 'fab fa-sass', color: '#cc6699' },
63
- 'md': { cls: 'fab fa-markdown', color: '#7f8b97' },
64
- 'json': { cls: 'fas fa-code', color: '#ffe082' },
65
- 'yml': { cls: 'fas fa-cog', color: '#888' },
66
- 'yaml': { cls: 'fas fa-cog', color: '#888' },
67
- 'png': { cls: 'fas fa-image', color: '#aaa' },
68
- 'jpg': { cls: 'fas fa-image', color: '#aaa' },
69
- 'jpeg': { cls: 'fas fa-image', color: '#aaa' },
70
- 'gif': { cls: 'fas fa-image', color: '#aaa' },
71
- 'svg': { cls: 'fas fa-image', color: '#aaa' },
72
- 'txt': { cls: 'fas fa-file-alt', color: '#888' },
73
- 'sh': { cls: 'fas fa-terminal', color: '#89d185' },
74
- 'lock': { cls: 'fas fa-lock', color: '#888' },
75
- 'pdf': { cls: 'fas fa-file-pdf', color: '#f48771' },
76
- };
77
- var icon = iconMap[ext] || { cls: 'fas fa-file-code', color: '#7f8b97' };
78
- return React.createElement('i', { className: icon.cls + ' git-file-type-icon', style: { color: icon.color } });
50
+ return React.createElement('i', { className: (window.getFileIcon ? window.getFileIcon(filename) : 'far fa-file-code') + ' git-file-type-icon' });
79
51
  };
80
52
 
81
53
  // Renders a file row used in Local Changes and Changes in Branch sections
@@ -148,6 +120,23 @@ var GitPanel = function GitPanel(_ref) {
148
120
  }
149
121
  };
150
122
 
123
+ var handleRefresh = function handleRefresh() {
124
+ if (!onRefresh || refreshing) return;
125
+
126
+ var result;
127
+ try {
128
+ setRefreshing(true);
129
+ result = onRefresh();
130
+ } catch (err) {
131
+ setRefreshing(false);
132
+ throw err;
133
+ }
134
+
135
+ return Promise.resolve(result).finally(function () {
136
+ setRefreshing(false);
137
+ });
138
+ };
139
+
151
140
  var renderCommit = function renderCommit(commit, idx) {
152
141
  var isFirst = idx === 0;
153
142
  var isLast = idx === branchCommits.length - 1;
@@ -305,8 +294,8 @@ var GitPanel = function GitPanel(_ref) {
305
294
  { className: 'ide-git-panel-actions' },
306
295
  onRefresh && React.createElement(
307
296
  'button',
308
- { className: 'git-header-btn', onClick: onRefresh, title: 'Refresh' },
309
- React.createElement('i', { className: 'fas fa-sync-alt' })
297
+ { className: 'git-header-btn', onClick: handleRefresh, title: 'Refresh', disabled: refreshing, 'aria-busy': refreshing },
298
+ React.createElement('i', { className: 'fas fa-sync-alt' + (refreshing ? ' fa-spin' : '') })
310
299
  ),
311
300
  onClose && React.createElement(
312
301
  'button',
@@ -121,6 +121,13 @@ var MbeditorApp = function MbeditorApp() {
121
121
  var searchQuery = _useState72[0];
122
122
  var setSearchQuery = _useState72[1];
123
123
 
124
+ var _useState33 = useState(false);
125
+ var _useState332 = _slicedToArray(_useState33, 2);
126
+ var searchLoading = _useState332[0];
127
+ var setSearchLoading = _useState332[1];
128
+
129
+ var searchRequestIdRef = useRef(0);
130
+
124
131
  var _useState8 = useState("explorer");
125
132
 
126
133
  var _useState82 = _slicedToArray(_useState8, 2);
@@ -1067,12 +1074,22 @@ var MbeditorApp = function MbeditorApp() {
1067
1074
 
1068
1075
  var _debouncedSearch = useRef(window._.debounce(function (q) {
1069
1076
  if (!q.trim()) {
1077
+ searchRequestIdRef.current += 1;
1078
+ setSearchLoading(false);
1070
1079
  EditorStore.setState({ searchResults: [] });
1071
1080
  return;
1072
1081
  }
1082
+ var requestId = ++searchRequestIdRef.current;
1083
+ setSearchLoading(true);
1073
1084
  EditorStore.setStatus("Searching project...", "info");
1074
1085
  SearchService.projectSearch(q).then(function (res) {
1075
- EditorStore.setStatus("Found " + res.length + " results", "success");
1086
+ if (searchRequestIdRef.current === requestId) {
1087
+ EditorStore.setStatus("Found " + res.length + " results", "success");
1088
+ }
1089
+ }).finally(function () {
1090
+ if (searchRequestIdRef.current === requestId) {
1091
+ setSearchLoading(false);
1092
+ }
1076
1093
  });
1077
1094
  }, 400)).current;
1078
1095
 
@@ -1082,6 +1099,14 @@ var MbeditorApp = function MbeditorApp() {
1082
1099
  _debouncedSearch(val);
1083
1100
  };
1084
1101
 
1102
+ var clearSearch = function clearSearch() {
1103
+ searchRequestIdRef.current += 1;
1104
+ if (_debouncedSearch.cancel) _debouncedSearch.cancel();
1105
+ setSearchQuery("");
1106
+ setSearchLoading(false);
1107
+ EditorStore.setState({ searchResults: [] });
1108
+ };
1109
+
1085
1110
  var execSearch = function execSearch(e) {
1086
1111
  e.preventDefault();
1087
1112
  _debouncedSearch(searchQuery);
@@ -1765,16 +1790,31 @@ var MbeditorApp = function MbeditorApp() {
1765
1790
  React.createElement(
1766
1791
  "div",
1767
1792
  { className: "search-input-wrap" },
1768
- React.createElement("input", {
1769
- className: "search-input",
1770
- placeholder: "Find in files...",
1771
- value: searchQuery,
1772
- onChange: handleSearchChange
1773
- }),
1793
+ React.createElement(
1794
+ "div",
1795
+ { className: "search-input-shell" },
1796
+ React.createElement("input", {
1797
+ className: "search-input",
1798
+ placeholder: "Find in files...",
1799
+ value: searchQuery,
1800
+ onChange: handleSearchChange
1801
+ }),
1802
+ searchQuery && React.createElement(
1803
+ "button",
1804
+ {
1805
+ type: "button",
1806
+ className: "search-clear-btn",
1807
+ onClick: clearSearch,
1808
+ title: "Clear search",
1809
+ "aria-label": "Clear search"
1810
+ },
1811
+ React.createElement("i", { className: "fas fa-times" })
1812
+ )
1813
+ ),
1774
1814
  React.createElement(
1775
1815
  "button",
1776
- { type: "submit", className: "search-btn" },
1777
- React.createElement("i", { className: "fas fa-search" })
1816
+ { type: "submit", className: "search-btn", disabled: searchLoading, title: searchLoading ? "Searching..." : "Search" },
1817
+ React.createElement("i", { className: searchLoading ? "fas fa-spinner fa-spin" : "fas fa-search" })
1778
1818
  )
1779
1819
  ),
1780
1820
  React.createElement(
@@ -1797,28 +1837,35 @@ var MbeditorApp = function MbeditorApp() {
1797
1837
  "No results"
1798
1838
  ),
1799
1839
  state.searchResults.map(function (res, i) {
1840
+ var fileName = res.file.split('/').pop();
1800
1841
  return React.createElement(
1801
1842
  "div",
1802
1843
  { key: i, className: "search-result-item", onClick: function () {
1803
1844
  return handleSelectFile(res.file, res.file.split('/').pop(), res.line);
1804
1845
  } },
1846
+ React.createElement("i", { className: (window.getFileIcon ? window.getFileIcon(fileName) : 'far fa-file-code') + " search-result-icon" }),
1805
1847
  React.createElement(
1806
1848
  "div",
1807
- { className: "search-result-file" },
1808
- res.file,
1809
- " ",
1849
+ { className: "search-result-body" },
1810
1850
  React.createElement(
1811
- "span",
1812
- { className: "search-result-line-num" },
1813
- ":",
1814
- res.line
1851
+ "div",
1852
+ { className: "search-result-file" },
1853
+ fileName,
1854
+ React.createElement(
1855
+ "span",
1856
+ { className: "search-result-line-num" },
1857
+ " ",
1858
+ res.file,
1859
+ ":",
1860
+ res.line
1861
+ )
1862
+ ),
1863
+ React.createElement(
1864
+ "div",
1865
+ { className: "search-result-text" },
1866
+ res.text
1815
1867
  )
1816
1868
  ),
1817
- React.createElement(
1818
- "div",
1819
- { className: "search-result-text" },
1820
- res.text
1821
- )
1822
1869
  );
1823
1870
  })
1824
1871
  )
@@ -34,6 +34,18 @@ var QuickOpenDialog = function QuickOpenDialog(_ref) {
34
34
 
35
35
  var inputRef = useRef(null);
36
36
 
37
+ var clearQuery = function clearQuery() {
38
+ setQuery('');
39
+ setResults([]);
40
+ setSelectedIndex(0);
41
+ if (inputRef.current) inputRef.current.focus();
42
+ };
43
+
44
+ var getQuickOpenIcon = function getQuickOpenIcon(path, name) {
45
+ var iconClass = window.getFileIcon ? window.getFileIcon(path || name || '') : 'far fa-file-code';
46
+ return React.createElement('i', { className: iconClass + ' quick-open-result-icon', 'aria-hidden': 'true' });
47
+ };
48
+
37
49
  useEffect(function () {
38
50
  if (inputRef.current) inputRef.current.focus();
39
51
  }, []);
@@ -66,17 +78,32 @@ var QuickOpenDialog = function QuickOpenDialog(_ref) {
66
78
  { className: "quick-open-box", onClick: function (e) {
67
79
  return e.stopPropagation();
68
80
  } },
69
- React.createElement("input", {
70
- ref: inputRef,
71
- type: "text",
72
- className: "quick-open-input",
73
- placeholder: "Search files by name (Ctrl+P)...",
74
- value: query,
75
- onChange: function (e) {
76
- return setQuery(e.target.value);
77
- },
78
- onKeyDown: handleKeyDown
79
- }),
81
+ React.createElement(
82
+ "div",
83
+ { className: "quick-open-input-wrap" },
84
+ React.createElement("input", {
85
+ ref: inputRef,
86
+ type: "text",
87
+ className: "quick-open-input",
88
+ placeholder: "Search files by name (Ctrl+P)...",
89
+ value: query,
90
+ onChange: function (e) {
91
+ return setQuery(e.target.value);
92
+ },
93
+ onKeyDown: handleKeyDown
94
+ }),
95
+ query && React.createElement(
96
+ "button",
97
+ {
98
+ type: "button",
99
+ className: "quick-open-clear-btn",
100
+ onClick: clearQuery,
101
+ title: "Clear search",
102
+ "aria-label": "Clear search"
103
+ },
104
+ React.createElement("i", { className: "fas fa-times" })
105
+ )
106
+ ),
80
107
  React.createElement(
81
108
  "div",
82
109
  { className: "quick-open-results" },
@@ -93,15 +120,20 @@ var QuickOpenDialog = function QuickOpenDialog(_ref) {
93
120
  return setSelectedIndex(i);
94
121
  }
95
122
  },
123
+ getQuickOpenIcon(res.path, res.name),
96
124
  React.createElement(
97
125
  "div",
98
- { className: "quick-open-result-name" },
99
- res.name
100
- ),
101
- React.createElement(
102
- "div",
103
- { className: "quick-open-result-path" },
104
- res.path
126
+ { className: "quick-open-result-body" },
127
+ React.createElement(
128
+ "div",
129
+ { className: "quick-open-result-name" },
130
+ res.name
131
+ ),
132
+ React.createElement(
133
+ "div",
134
+ { className: "quick-open-result-path" },
135
+ res.path
136
+ )
105
137
  )
106
138
  );
107
139
  }),
@@ -0,0 +1,30 @@
1
+ var MbeditorFileIcon = (function () {
2
+ function getFileIcon(name) {
3
+ var value = String(name || '');
4
+ var lower = value.toLowerCase();
5
+ var parts = lower.split('.');
6
+ var ext = parts.length > 1 ? parts.pop() : '';
7
+
8
+ if (lower === 'gemfile' || ext === 'gemspec' || ext === 'lock') return 'fas fa-gem ruby-icon';
9
+ if (ext === 'rb' || ext === 'rake' || lower === 'rakefile') return 'far fa-gem ruby-icon';
10
+ if (ext === 'jsx' || lower.endsWith('.js.jsx')) return 'fas fa-atom react-icon';
11
+ if (ext === 'js' || ext === 'mjs' || ext === 'cjs') return 'fa-brands fa-js js-icon';
12
+ if (ext === 'ts' || ext === 'tsx') return 'fas fa-code typescript-icon';
13
+ if (ext === 'html' || ext === 'htm') return 'fa-brands fa-html5 html-icon';
14
+ if (ext === 'erb') return 'fa-brands fa-html5 erb-icon';
15
+ if (ext === 'css' || ext === 'scss' || ext === 'sass') return 'fa-brands fa-css3-alt css-icon';
16
+ if (['png', 'jpg', 'jpeg', 'gif', 'svg', 'ico', 'webp', 'bmp', 'avif'].includes(ext)) return 'far fa-file-image image-icon';
17
+ if (ext === 'json') return 'fas fa-code json-icon';
18
+ if (ext === 'md' || ext === 'txt') return 'fas fa-file-alt md-icon';
19
+ if (ext === 'yml' || ext === 'yaml') return 'fas fa-cogs yml-icon';
20
+ if (ext === 'sh' || ext === 'bash' || ext === 'zsh') return 'fas fa-terminal shell-icon';
21
+ if (ext === 'pdf') return 'far fa-file-pdf pdf-icon';
22
+
23
+ return 'far fa-file-code';
24
+ }
25
+
26
+ return { getFileIcon: getFileIcon };
27
+ })();
28
+
29
+ window.MbeditorFileIcon = MbeditorFileIcon;
30
+ window.getFileIcon = window.getFileIcon || MbeditorFileIcon.getFileIcon;
@@ -663,19 +663,47 @@ html, body, #mbeditor-root {
663
663
  gap: 6px;
664
664
  }
665
665
 
666
- .search-input {
666
+ .search-input-shell {
667
+ position: relative;
667
668
  flex: 1;
669
+ min-width: 0;
670
+ }
671
+
672
+ .search-input {
673
+ width: 100%;
668
674
  background: #3c3c3c;
669
675
  border: 1px solid #555;
670
676
  border-radius: 4px;
671
677
  color: #ccc;
672
- padding: 4px 8px;
678
+ padding: 4px 28px 4px 8px;
673
679
  font-size: 12px;
674
680
  outline: none;
675
681
  }
676
682
 
677
683
  .search-input:focus { border-color: #4ec9b0; }
678
684
 
685
+ .search-clear-btn {
686
+ position: absolute;
687
+ right: 4px;
688
+ top: 50%;
689
+ transform: translateY(-50%);
690
+ width: 20px;
691
+ height: 20px;
692
+ border: none;
693
+ border-radius: 3px;
694
+ background: transparent;
695
+ color: #aaa;
696
+ cursor: pointer;
697
+ display: flex;
698
+ align-items: center;
699
+ justify-content: center;
700
+ }
701
+
702
+ .search-clear-btn:hover {
703
+ background: #2a2d2e;
704
+ color: #ddd;
705
+ }
706
+
679
707
  .search-btn {
680
708
  background: #094771;
681
709
  border: none;
@@ -689,6 +717,11 @@ html, body, #mbeditor-root {
689
717
 
690
718
  .search-btn:hover { background: #0e639c; }
691
719
 
720
+ .search-btn:disabled {
721
+ cursor: progress;
722
+ opacity: 0.85;
723
+ }
724
+
692
725
  .search-results {
693
726
  flex: 1;
694
727
  overflow-y: auto;
@@ -700,10 +733,26 @@ html, body, #mbeditor-root {
700
733
  border-radius: 3px;
701
734
  transition: background 0.1s;
702
735
  border-bottom: 1px solid #2d2d2d;
736
+ display: flex;
737
+ align-items: flex-start;
738
+ gap: 8px;
703
739
  }
704
740
 
705
741
  .search-result-item:hover { background: #2a2d2e; }
706
742
 
743
+ .search-result-icon {
744
+ flex-shrink: 0;
745
+ width: 16px;
746
+ margin-top: 2px;
747
+ text-align: center;
748
+ color: #78b4e0;
749
+ }
750
+
751
+ .search-result-body {
752
+ min-width: 0;
753
+ flex: 1;
754
+ }
755
+
707
756
  .search-result-file {
708
757
  font-size: 11px;
709
758
  color: #4ec9b0;
@@ -883,6 +932,7 @@ html, body, #mbeditor-root {
883
932
  display: flex;
884
933
  flex-direction: column;
885
934
  flex-shrink: 0;
935
+ min-height: 0;
886
936
  }
887
937
 
888
938
  /* Only stretch when the graph section is open */
@@ -893,6 +943,7 @@ html, body, #mbeditor-root {
893
943
 
894
944
  .ide-git-right-panel .git-history-graph-wrap {
895
945
  flex: 1;
946
+ min-height: 0;
896
947
  overflow-y: auto;
897
948
  overflow-x: hidden;
898
949
  }
@@ -1211,17 +1262,43 @@ html, body, #mbeditor-root {
1211
1262
  overflow: hidden;
1212
1263
  }
1213
1264
 
1265
+ .quick-open-input-wrap {
1266
+ position: relative;
1267
+ }
1268
+
1214
1269
  .quick-open-input {
1215
1270
  background: transparent;
1216
1271
  border: none;
1217
1272
  border-bottom: 1px solid #3c3c3c;
1218
1273
  color: #ccc;
1219
- padding: 12px 16px;
1274
+ padding: 12px 34px 12px 16px;
1220
1275
  font-size: 14px;
1221
1276
  outline: none;
1222
1277
  width: 100%;
1223
1278
  }
1224
1279
 
1280
+ .quick-open-clear-btn {
1281
+ position: absolute;
1282
+ right: 6px;
1283
+ top: 50%;
1284
+ transform: translateY(-50%);
1285
+ width: 22px;
1286
+ height: 22px;
1287
+ border: none;
1288
+ border-radius: 4px;
1289
+ background: transparent;
1290
+ color: #999;
1291
+ cursor: pointer;
1292
+ display: flex;
1293
+ align-items: center;
1294
+ justify-content: center;
1295
+ }
1296
+
1297
+ .quick-open-clear-btn:hover {
1298
+ background: #2a2d2e;
1299
+ color: #ddd;
1300
+ }
1301
+
1225
1302
  .quick-open-results {
1226
1303
  overflow-y: auto;
1227
1304
  flex: 1;
@@ -1237,11 +1314,27 @@ html, body, #mbeditor-root {
1237
1314
  transition: background 0.1s;
1238
1315
  }
1239
1316
 
1317
+ .quick-open-result-icon {
1318
+ flex-shrink: 0;
1319
+ width: 16px;
1320
+ text-align: center;
1321
+ color: #78b4e0;
1322
+ }
1323
+
1324
+ .quick-open-result-body {
1325
+ min-width: 0;
1326
+ flex: 1;
1327
+ }
1328
+
1240
1329
  .quick-open-result:hover,
1241
1330
  .quick-open-result.selected { background: #094771; }
1242
1331
 
1243
- .quick-open-result-name { color: #ccc; flex: 1; }
1244
- .quick-open-result-path { color: #666; font-size: 11px; }
1332
+ .quick-open-result-name { color: #ccc; }
1333
+ .quick-open-result-path { color: #666; font-size: 11px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
1334
+
1335
+ .typescript-icon { color: #3178c6 !important; }
1336
+ .shell-icon { color: #89d185 !important; }
1337
+ .pdf-icon { color: #f48771 !important; }
1245
1338
 
1246
1339
  /* ── Scrollbars ────────────────────────────────────────────── */
1247
1340
  ::-webkit-scrollbar { width: 8px; height: 8px; }
@@ -292,7 +292,7 @@ module Mbeditor
292
292
  unpushed_commits = parse_git_log(unpushed_log_output) if unpushed_log_status.success?
293
293
  end
294
294
 
295
- branch_log_output, branch_log_status = Open3.capture2("git", "-C", repo, "log", branch, "-n", "100", "--pretty=format:%H%x1f%s%x1f%an%x1f%aI%x1e")
295
+ branch_log_output, branch_log_status = Open3.capture2("git", "-C", repo, "log", "--first-parent", branch, "-n", "100", "--pretty=format:%H%x1f%s%x1f%an%x1f%aI%x1e")
296
296
  branch_commits = branch_log_status.success? ? parse_git_log(branch_log_output) : []
297
297
 
298
298
  render json: {
@@ -1,3 +1,3 @@
1
1
  module Mbeditor
2
- VERSION = "0.1.4"
2
+ VERSION = "0.1.5"
3
3
  end
@@ -0,0 +1,41 @@
1
+ define("vs/basic-languages/shell/shell", [], function () {
2
+ "use strict";
3
+
4
+ return {
5
+ conf: {
6
+ comments: { lineComment: "#" },
7
+ brackets: [["{", "}"], ["[", "]"], ["(", ")"]],
8
+ autoClosingPairs: [
9
+ { open: "{", close: "}" },
10
+ { open: "[", close: "]" },
11
+ { open: "(", close: ")" },
12
+ { open: '"', close: '"' },
13
+ { open: "'", close: "'" }
14
+ ],
15
+ surroundingPairs: [
16
+ { open: "{", close: "}" },
17
+ { open: "[", close: "]" },
18
+ { open: "(", close: ")" },
19
+ { open: '"', close: '"' },
20
+ { open: "'", close: "'" }
21
+ ]
22
+ },
23
+ language: {
24
+ defaultToken: "",
25
+ tokenPostfix: ".sh",
26
+ keywords: ["if", "then", "else", "elif", "fi", "for", "while", "until", "do", "done", "case", "esac", "function", "select", "in", "time", "coproc"],
27
+ tokenizer: {
28
+ root: [
29
+ [/#.*$/, "comment"],
30
+ [/"([^"\\]|\\.)*"/, "string"],
31
+ [/'([^'\\]|\\.)*'/, "string"],
32
+ [/\b(?:if|then|else|elif|fi|for|while|until|do|done|case|esac|function|select|in|time|coproc)\b/, "keyword"],
33
+ [/[{}()\[\]]/, "@brackets"],
34
+ [/\$\{?[a-zA-Z_][\w-]*\}?/, "variable"],
35
+ [/[a-zA-Z_][\w-]*/, "identifier"],
36
+ [/\s+/, ""]
37
+ ]
38
+ }
39
+ }
40
+ };
41
+ });
@@ -0,0 +1,10 @@
1
+ define("vs/basic-languages/typescript/typescript", ["vs/basic-languages/javascript/javascript"], function (javascript) {
2
+ "use strict";
3
+
4
+ return {
5
+ conf: javascript.conf,
6
+ language: Object.assign({}, javascript.language, {
7
+ tokenPostfix: ".ts"
8
+ })
9
+ };
10
+ });
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mbeditor
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.4
4
+ version: 0.1.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Oliver Noonan
@@ -69,6 +69,7 @@ files:
69
69
  - app/assets/javascripts/mbeditor/components/TabBar.js
70
70
  - app/assets/javascripts/mbeditor/editor_plugins.js
71
71
  - app/assets/javascripts/mbeditor/editor_store.js
72
+ - app/assets/javascripts/mbeditor/file_icon.js
72
73
  - app/assets/javascripts/mbeditor/file_service.js
73
74
  - app/assets/javascripts/mbeditor/git_service.js
74
75
  - app/assets/javascripts/mbeditor/search_service.js
@@ -112,6 +113,8 @@ files:
112
113
  - public/monaco-editor/vs/basic-languages/restructuredtext/restructuredtext.js
113
114
  - public/monaco-editor/vs/basic-languages/ruby/ruby.js
114
115
  - public/monaco-editor/vs/basic-languages/sb/sb.js
116
+ - public/monaco-editor/vs/basic-languages/shell/shell.js
117
+ - public/monaco-editor/vs/basic-languages/typescript/typescript.js
115
118
  - public/monaco-editor/vs/basic-languages/typespec/typespec.js
116
119
  - public/monaco-editor/vs/basic-languages/yaml/yaml.js
117
120
  - public/monaco-editor/vs/editor/editor.main.css