codex-lens 0.1.23 → 0.1.25
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.
package/dist/public/index.html
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
<meta charset="UTF-8" />
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
6
|
<title>Codex Lens</title>
|
|
7
|
-
<script type="module" crossorigin src="./assets/main-
|
|
7
|
+
<script type="module" crossorigin src="./assets/main-DJ9sK-1n.js"></script>
|
|
8
8
|
<link rel="stylesheet" crossorigin href="./assets/main-CYNmzqDG.css">
|
|
9
9
|
</head>
|
|
10
10
|
<body>
|
package/package.json
CHANGED
package/src/components/App.jsx
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React, { useState, useEffect, useRef
|
|
1
|
+
import React, { useState, useEffect, useRef } from 'react';
|
|
2
2
|
import { TerminalPanel } from './TerminalPanel';
|
|
3
3
|
import { CodeViewer } from './CodeViewer';
|
|
4
4
|
|
|
@@ -15,6 +15,7 @@ export function App() {
|
|
|
15
15
|
const wsRef = useRef(null);
|
|
16
16
|
const activeTabIdRef = useRef(null);
|
|
17
17
|
const tabsRef = useRef([]);
|
|
18
|
+
const saveCurrentFileRef = useRef(null);
|
|
18
19
|
|
|
19
20
|
useEffect(() => {
|
|
20
21
|
activeTabIdRef.current = activeTabId;
|
|
@@ -24,79 +25,7 @@ export function App() {
|
|
|
24
25
|
tabsRef.current = tabs;
|
|
25
26
|
}, [tabs]);
|
|
26
27
|
|
|
27
|
-
|
|
28
|
-
fetchStatus();
|
|
29
|
-
connectWebSocket();
|
|
30
|
-
document.addEventListener('click', handleDocumentClick);
|
|
31
|
-
document.addEventListener('keydown', handleKeyDown);
|
|
32
|
-
|
|
33
|
-
const preventBrowserSave = (e) => {
|
|
34
|
-
if (e.ctrlKey && e.key === 's') {
|
|
35
|
-
e.preventDefault();
|
|
36
|
-
e.stopPropagation();
|
|
37
|
-
}
|
|
38
|
-
};
|
|
39
|
-
window.addEventListener('keydown', preventBrowserSave, true);
|
|
40
|
-
|
|
41
|
-
return () => {
|
|
42
|
-
document.removeEventListener('click', handleDocumentClick);
|
|
43
|
-
document.removeEventListener('keydown', handleKeyDown);
|
|
44
|
-
window.removeEventListener('keydown', preventBrowserSave, true);
|
|
45
|
-
if (wsRef.current) {
|
|
46
|
-
wsRef.current.close();
|
|
47
|
-
}
|
|
48
|
-
};
|
|
49
|
-
}, []);
|
|
50
|
-
|
|
51
|
-
async function fetchStatus() {
|
|
52
|
-
try {
|
|
53
|
-
const port = window.location.port === '5173' ? '5174' : window.location.port;
|
|
54
|
-
const protocol = window.location.protocol === 'https:' ? 'https:' : 'http:';
|
|
55
|
-
const response = await fetch(`${protocol}//${window.location.hostname}:${port}/api/status`);
|
|
56
|
-
if (response.ok) {
|
|
57
|
-
const data = await response.json();
|
|
58
|
-
setVersion(data.version);
|
|
59
|
-
setLatestVersion(data.latestVersion);
|
|
60
|
-
setHasUpdate(data.hasUpdate);
|
|
61
|
-
if (data.projectRoot) {
|
|
62
|
-
const parts = data.projectRoot.split(/[/\\]/);
|
|
63
|
-
setProjectName(parts[parts.length - 1] || data.projectRoot);
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
} catch (error) {
|
|
67
|
-
console.error('Failed to fetch status:', error);
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
function handleDocumentClick() {
|
|
72
|
-
setContextMenu(null);
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
function handleKeyDown(e) {
|
|
76
|
-
if (e.ctrlKey && e.key === 's') {
|
|
77
|
-
e.preventDefault();
|
|
78
|
-
if (activeTabId) {
|
|
79
|
-
saveCurrentFile();
|
|
80
|
-
}
|
|
81
|
-
return;
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
if (!activeTabId) return;
|
|
85
|
-
|
|
86
|
-
if (e.ctrlKey && e.key === 'w') {
|
|
87
|
-
e.preventDefault();
|
|
88
|
-
closeTab(activeTabId);
|
|
89
|
-
} else if (e.ctrlKey && e.key === 'Tab') {
|
|
90
|
-
e.preventDefault();
|
|
91
|
-
if (e.shiftKey) {
|
|
92
|
-
switchToPrevTab();
|
|
93
|
-
} else {
|
|
94
|
-
switchToNextTab();
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
const saveCurrentFile = useCallback(() => {
|
|
28
|
+
function saveCurrentFile() {
|
|
100
29
|
const currentTabId = activeTabIdRef.current;
|
|
101
30
|
const currentTabs = tabsRef.current;
|
|
102
31
|
const activeTab = currentTabs.find(t => t.id === currentTabId);
|
|
@@ -131,6 +60,84 @@ export function App() {
|
|
|
131
60
|
.catch(error => {
|
|
132
61
|
console.error('Failed to save file:', error);
|
|
133
62
|
});
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
useEffect(() => {
|
|
66
|
+
saveCurrentFileRef.current = saveCurrentFile;
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
async function fetchStatus() {
|
|
70
|
+
try {
|
|
71
|
+
const port = window.location.port === '5173' ? '5174' : window.location.port;
|
|
72
|
+
const protocol = window.location.protocol === 'https:' ? 'https:' : 'http:';
|
|
73
|
+
const response = await fetch(`${protocol}//${window.location.hostname}:${port}/api/status`);
|
|
74
|
+
if (response.ok) {
|
|
75
|
+
const data = await response.json();
|
|
76
|
+
setVersion(data.version);
|
|
77
|
+
setLatestVersion(data.latestVersion);
|
|
78
|
+
setHasUpdate(data.hasUpdate);
|
|
79
|
+
if (data.projectRoot) {
|
|
80
|
+
const parts = data.projectRoot.split(/[/\\]/);
|
|
81
|
+
setProjectName(parts[parts.length - 1] || data.projectRoot);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
} catch (error) {
|
|
85
|
+
console.error('Failed to fetch status:', error);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function handleDocumentClick() {
|
|
90
|
+
setContextMenu(null);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
useEffect(() => {
|
|
94
|
+
fetchStatus();
|
|
95
|
+
connectWebSocket();
|
|
96
|
+
|
|
97
|
+
function handleKeyDown(e) {
|
|
98
|
+
if (e.ctrlKey && e.key === 's') {
|
|
99
|
+
e.preventDefault();
|
|
100
|
+
console.log('Ctrl+S pressed, activeTabId:', activeTabIdRef.current);
|
|
101
|
+
if (saveCurrentFileRef.current) {
|
|
102
|
+
saveCurrentFileRef.current();
|
|
103
|
+
}
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
if (!activeTabIdRef.current) return;
|
|
108
|
+
|
|
109
|
+
if (e.ctrlKey && e.key === 'w') {
|
|
110
|
+
e.preventDefault();
|
|
111
|
+
closeTab(activeTabIdRef.current);
|
|
112
|
+
} else if (e.ctrlKey && e.key === 'Tab') {
|
|
113
|
+
e.preventDefault();
|
|
114
|
+
if (e.shiftKey) {
|
|
115
|
+
switchToPrevTab();
|
|
116
|
+
} else {
|
|
117
|
+
switchToNextTab();
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
document.addEventListener('click', handleDocumentClick);
|
|
123
|
+
document.addEventListener('keydown', handleKeyDown);
|
|
124
|
+
|
|
125
|
+
const preventBrowserSave = (e) => {
|
|
126
|
+
if (e.ctrlKey && e.key === 's') {
|
|
127
|
+
e.preventDefault();
|
|
128
|
+
e.stopPropagation();
|
|
129
|
+
}
|
|
130
|
+
};
|
|
131
|
+
window.addEventListener('keydown', preventBrowserSave, true);
|
|
132
|
+
|
|
133
|
+
return () => {
|
|
134
|
+
document.removeEventListener('click', handleDocumentClick);
|
|
135
|
+
document.removeEventListener('keydown', handleKeyDown);
|
|
136
|
+
window.removeEventListener('keydown', preventBrowserSave, true);
|
|
137
|
+
if (wsRef.current) {
|
|
138
|
+
wsRef.current.close();
|
|
139
|
+
}
|
|
140
|
+
};
|
|
134
141
|
}, []);
|
|
135
142
|
|
|
136
143
|
function handleContentChange(newContent) {
|
|
@@ -261,7 +268,8 @@ export function App() {
|
|
|
261
268
|
function closeTab(tabId) {
|
|
262
269
|
setTabs(prev => {
|
|
263
270
|
const newTabs = prev.filter(t => t.id !== tabId);
|
|
264
|
-
|
|
271
|
+
const currentActiveId = activeTabIdRef.current;
|
|
272
|
+
if (currentActiveId === tabId) {
|
|
265
273
|
const newActiveId = newTabs.length > 0 ? newTabs[newTabs.length - 1].id : null;
|
|
266
274
|
setActiveTabId(newActiveId);
|
|
267
275
|
}
|
|
@@ -284,20 +292,24 @@ export function App() {
|
|
|
284
292
|
}
|
|
285
293
|
|
|
286
294
|
function switchToNextTab() {
|
|
287
|
-
const
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
setActiveTabId(
|
|
295
|
+
const currentTabs = tabsRef.current;
|
|
296
|
+
const currentActiveId = activeTabIdRef.current;
|
|
297
|
+
const currentIndex = currentTabs.findIndex(t => t.id === currentActiveId);
|
|
298
|
+
if (currentIndex < currentTabs.length - 1) {
|
|
299
|
+
setActiveTabId(currentTabs[currentIndex + 1].id);
|
|
300
|
+
} else if (currentTabs.length > 0) {
|
|
301
|
+
setActiveTabId(currentTabs[0].id);
|
|
292
302
|
}
|
|
293
303
|
}
|
|
294
304
|
|
|
295
305
|
function switchToPrevTab() {
|
|
296
|
-
const
|
|
306
|
+
const currentTabs = tabsRef.current;
|
|
307
|
+
const currentActiveId = activeTabIdRef.current;
|
|
308
|
+
const currentIndex = currentTabs.findIndex(t => t.id === currentActiveId);
|
|
297
309
|
if (currentIndex > 0) {
|
|
298
|
-
setActiveTabId(
|
|
299
|
-
} else if (
|
|
300
|
-
setActiveTabId(
|
|
310
|
+
setActiveTabId(currentTabs[currentIndex - 1].id);
|
|
311
|
+
} else if (currentTabs.length > 0) {
|
|
312
|
+
setActiveTabId(currentTabs[currentTabs.length - 1].id);
|
|
301
313
|
}
|
|
302
314
|
}
|
|
303
315
|
|
|
@@ -365,7 +377,12 @@ export function App() {
|
|
|
365
377
|
<ContextMenu
|
|
366
378
|
x={contextMenu.x}
|
|
367
379
|
y={contextMenu.y}
|
|
380
|
+
tabId={contextMenu.tabId}
|
|
368
381
|
onClose={() => setContextMenu(null)}
|
|
382
|
+
onSave={() => {
|
|
383
|
+
saveCurrentFile();
|
|
384
|
+
setContextMenu(null);
|
|
385
|
+
}}
|
|
369
386
|
onCloseTab={() => {
|
|
370
387
|
closeTab(contextMenu.tabId);
|
|
371
388
|
setContextMenu(null);
|
|
@@ -419,9 +436,14 @@ function TabBar({ tabs, activeTabId, onTabClick, onTabClose, onContextMenu }) {
|
|
|
419
436
|
);
|
|
420
437
|
}
|
|
421
438
|
|
|
422
|
-
function ContextMenu({ x, y, onClose, onCloseTab, onCloseOtherTabs, onCloseAllTabs }) {
|
|
439
|
+
function ContextMenu({ x, y, tabId, onClose, onSave, onCloseTab, onCloseOtherTabs, onCloseAllTabs }) {
|
|
440
|
+
const tabs = tabsRef.current;
|
|
441
|
+
const tab = tabs.find(t => t.id === tabId);
|
|
442
|
+
const canSave = tab && !tab.isDiff;
|
|
443
|
+
|
|
423
444
|
return (
|
|
424
445
|
<div className="context-menu" style={{ left: x, top: y }} onClick={(e) => e.stopPropagation()}>
|
|
446
|
+
{canSave && <div className="context-menu-item" onClick={onSave}>保存</div>}
|
|
425
447
|
<div className="context-menu-item" onClick={onCloseTab}>关闭</div>
|
|
426
448
|
<div className="context-menu-item" onClick={onCloseOtherTabs}>关闭其他</div>
|
|
427
449
|
<div className="context-menu-item" onClick={onCloseAllTabs}>关闭所有</div>
|