update
This commit is contained in:
@@ -7,6 +7,8 @@ import { ref, onMounted, onBeforeUnmount, watch } from 'vue';
|
|||||||
import * as monaco from 'monaco-editor';
|
import * as monaco from 'monaco-editor';
|
||||||
|
|
||||||
// Props for the component (will be expanded later)
|
// Props for the component (will be expanded later)
|
||||||
|
const fontSize = ref(14); // 添加字体大小状态,默认 14
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
modelValue: { // Use modelValue for v-model support
|
modelValue: { // Use modelValue for v-model support
|
||||||
type: String,
|
type: String,
|
||||||
@@ -38,6 +40,7 @@ onMounted(() => {
|
|||||||
value: props.modelValue,
|
value: props.modelValue,
|
||||||
language: props.language,
|
language: props.language,
|
||||||
theme: props.theme,
|
theme: props.theme,
|
||||||
|
fontSize: fontSize.value, // 使用 ref 作为初始字体大小
|
||||||
automaticLayout: true, // Auto resize editor on container resize
|
automaticLayout: true, // Auto resize editor on container resize
|
||||||
readOnly: props.readOnly,
|
readOnly: props.readOnly,
|
||||||
// Add more options as needed
|
// Add more options as needed
|
||||||
@@ -73,6 +76,56 @@ onMounted(() => {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Listen for content changes and emit update event for v-model
|
||||||
|
editorInstance.onDidChangeModelContent(() => {
|
||||||
|
if (editorInstance) {
|
||||||
|
const currentValue = editorInstance.getValue();
|
||||||
|
if (currentValue !== props.modelValue) {
|
||||||
|
emit('update:modelValue', currentValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Add Ctrl+S / Cmd+S keybinding for saving
|
||||||
|
editorInstance.addAction({
|
||||||
|
id: 'save-file',
|
||||||
|
label: 'Save File',
|
||||||
|
keybindings: [
|
||||||
|
monaco.KeyMod.CtrlCmd | monaco.KeyCode.KeyS,
|
||||||
|
],
|
||||||
|
precondition: undefined, // Fix: Use undefined instead of null
|
||||||
|
keybindingContext: undefined, // Fix: Use undefined instead of null
|
||||||
|
contextMenuGroupId: 'navigation', // Optional: where to show in context menu
|
||||||
|
contextMenuOrder: 1.5, // Optional: order in context menu
|
||||||
|
run: () => {
|
||||||
|
console.log('[MonacoEditor] Save action triggered (Ctrl+S / Cmd+S)');
|
||||||
|
emit('request-save');
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// 添加鼠标滚轮缩放功能
|
||||||
|
editorContainer.value.addEventListener('wheel', (event: WheelEvent) => {
|
||||||
|
// 只在按下Ctrl键时才触发缩放
|
||||||
|
if (event.ctrlKey) {
|
||||||
|
event.preventDefault(); // 阻止默认的滚动行为
|
||||||
|
|
||||||
|
// 根据滚轮方向调整字体大小
|
||||||
|
if (event.deltaY < 0) {
|
||||||
|
// 向上滚动,增大字体
|
||||||
|
fontSize.value = Math.min(fontSize.value + 1, 40); // 设置最大字体大小为40
|
||||||
|
} else {
|
||||||
|
// 向下滚动,减小字体
|
||||||
|
fontSize.value = Math.max(fontSize.value - 1, 8); // 设置最小字体大小为8
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新编辑器字体大小
|
||||||
|
if (editorInstance) {
|
||||||
|
editorInstance.updateOptions({ fontSize: fontSize.value });
|
||||||
|
console.log(`[MonacoEditor] Font size changed to: ${fontSize.value}`); // 添加日志
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, { passive: false }); // 设置 passive: false 允许 preventDefault
|
||||||
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -114,8 +114,8 @@ onMounted(() => {
|
|||||||
// console.log(`[Terminal ${props.sessionId}] ResizeObserver triggered. Height: ${height}, isActive: ${props.isActive}`);
|
// console.log(`[Terminal ${props.sessionId}] ResizeObserver triggered. Height: ${height}, isActive: ${props.isActive}`);
|
||||||
if (height > 0 && terminal) { // 仅在可见时调整
|
if (height > 0 && terminal) { // 仅在可见时调整
|
||||||
try {
|
try {
|
||||||
fitAddon?.fit(); // 视觉上适应
|
// fitAddon?.fit(); // 视觉上适应 <-- 移除此行,不再强制 fit 内部行数
|
||||||
// 触发防抖的 resize 发送,主要应对窗口 resize
|
// 触发防抖的 resize 发送,通知后端潜在的尺寸变化
|
||||||
debouncedEmitResize(terminal);
|
debouncedEmitResize(terminal);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.warn("Fit addon resize failed (observer):", e);
|
console.warn("Fit addon resize failed (observer):", e);
|
||||||
@@ -166,6 +166,15 @@ onMounted(() => {
|
|||||||
if (done) break;
|
if (done) break;
|
||||||
if (terminal && value) {
|
if (terminal && value) {
|
||||||
terminal.write(value); // 将流数据写入终端
|
terminal.write(value); // 将流数据写入终端
|
||||||
|
// 尝试在写入数据后调用 fit,看是否能触发滚动条
|
||||||
|
nextTick(() => { // 使用 nextTick 确保 DOM 更新后再 fit
|
||||||
|
try {
|
||||||
|
fitAddon?.fit();
|
||||||
|
// 注意:这里可能不需要再 emit resize,因为 fit 主要是为了更新内部布局以适应外部滚动
|
||||||
|
} catch (fitError) {
|
||||||
|
console.warn("Fit addon failed after writing stream data:", fitError);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -182,9 +191,29 @@ onMounted(() => {
|
|||||||
// 聚焦终端
|
// 聚焦终端
|
||||||
terminal.focus();
|
terminal.focus();
|
||||||
|
|
||||||
// 添加鼠标滚轮缩放功能
|
// 重新添加鼠标滚轮缩放功能
|
||||||
if (terminalRef.value) {
|
if (terminalRef.value) {
|
||||||
terminalRef.value.addEventListener('wheel', (event: WheelEvent) => {
|
terminalRef.value.addEventListener('wheel', (event: WheelEvent) => {
|
||||||
|
// // 只在按下Ctrl键时才触发缩放
|
||||||
|
// if (event.ctrlKey) {
|
||||||
|
// event.preventDefault(); // 阻止默认的滚动行为
|
||||||
|
|
||||||
|
// // 根据滚轮方向调整字体大小
|
||||||
|
// if (event.deltaY < 0) {
|
||||||
|
// // 向上滚动,增大字体
|
||||||
|
// fontSize.value = Math.min(fontSize.value + 1, 40); // 设置最大字体大小为40
|
||||||
|
// } else {
|
||||||
|
// // 向下滚动,减小字体
|
||||||
|
// fontSize.value = Math.max(fontSize.value - 1, 8); // 设置最小字体大小为8
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // 更新终端字体大小
|
||||||
|
// if (terminal) {
|
||||||
|
// terminal.options.fontSize = fontSize.value;
|
||||||
|
// // 调整终端大小以适应新的字体大小
|
||||||
|
// fitAddon?.fit();
|
||||||
|
// emit('resize', { cols: terminal.cols, rows: terminal.rows });
|
||||||
|
// }
|
||||||
// 只在按下Ctrl键时才触发缩放
|
// 只在按下Ctrl键时才触发缩放
|
||||||
if (event.ctrlKey) {
|
if (event.ctrlKey) {
|
||||||
event.preventDefault(); // 阻止默认的滚动行为
|
event.preventDefault(); // 阻止默认的滚动行为
|
||||||
@@ -235,26 +264,11 @@ defineExpose({ write });
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
/* 恢复默认样式,让 xterm 内部处理滚动 */
|
||||||
.terminal-container {
|
.terminal-container {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%; /* 高度需要由父容器控制 */
|
height: 100%; /* 高度需要由父容器控制 */
|
||||||
overflow: hidden; /* 防止滚动条出现 */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 终端屏幕样式 - 移除上下间距 */
|
/* 移除之前添加的 :deep 样式 */
|
||||||
.terminal-container :deep(.xterm-screen) {
|
|
||||||
padding: 0; /* 移除内边距,解决上下有间距的问题 */
|
|
||||||
box-sizing: border-box;
|
|
||||||
/* 覆盖 xterm.css 可能设置的 position: absolute */
|
|
||||||
position: relative !important;
|
|
||||||
width: 100% !important;
|
|
||||||
height: 100% !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 确保 viewport 填满容器,隐藏滚动条 */
|
|
||||||
.terminal-container :deep(.xterm-viewport) {
|
|
||||||
width: 100% !important;
|
|
||||||
height: 100% !important;
|
|
||||||
overflow: hidden !important;
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -189,8 +189,7 @@ onBeforeUnmount(() => {
|
|||||||
<splitpanes class="default-theme" :horizontal="false" style="height: 100%">
|
<splitpanes class="default-theme" :horizontal="false" style="height: 100%">
|
||||||
|
|
||||||
<!-- 1. 左侧边栏 Pane (连接列表) -->
|
<!-- 1. 左侧边栏 Pane (连接列表) -->
|
||||||
<pane v-if="paneVisibility.connections" size="15" min-size="10" class="sidebar-pane pane-with-title"> <!-- 使用 v-if 控制, 添加 class -->
|
<pane v-if="paneVisibility.connections" size="15" min-size="10" class="sidebar-pane"> <!-- 移除 pane-with-title class -->
|
||||||
<PaneTitleBar :title="t('layout.pane.connections')" pane-name="connections" />
|
|
||||||
<WorkspaceConnectionListComponent
|
<WorkspaceConnectionListComponent
|
||||||
class="pane-content"
|
class="pane-content"
|
||||||
@connect-request="(id) => { console.log(`[WorkspaceView] Received 'connect-request' event for ID: ${id}`); sessionStore.handleConnectRequest(id); }"
|
@connect-request="(id) => { console.log(`[WorkspaceView] Received 'connect-request' event for ID: ${id}`); sessionStore.handleConnectRequest(id); }"
|
||||||
@@ -205,8 +204,7 @@ onBeforeUnmount(() => {
|
|||||||
<!-- 上下分割 (终端 | 命令栏 | 文件管理器) -->
|
<!-- 上下分割 (终端 | 命令栏 | 文件管理器) -->
|
||||||
<splitpanes :horizontal="true" style="height: 100%" :dbl-click-splitter="false">
|
<splitpanes :horizontal="true" style="height: 100%" :dbl-click-splitter="false">
|
||||||
<!-- 上方 Pane (终端) -->
|
<!-- 上方 Pane (终端) -->
|
||||||
<pane v-if="paneVisibility.terminal" size="55" min-size="20" class="terminal-pane pane-with-title"> <!-- 使用 v-if 控制, 添加 class -->
|
<pane v-if="paneVisibility.terminal" size="55" min-size="20" class="terminal-pane"> <!-- 移除 pane-with-title class -->
|
||||||
<PaneTitleBar :title="t('layout.pane.terminal')" pane-name="terminal" />
|
|
||||||
<div class="pane-content terminal-content-wrapper"> <!-- 添加包裹 div -->
|
<div class="pane-content terminal-content-wrapper"> <!-- 添加包裹 div -->
|
||||||
<div
|
<div
|
||||||
v-for="tabInfo in sessionTabsWithStatus"
|
v-for="tabInfo in sessionTabsWithStatus"
|
||||||
@@ -239,8 +237,7 @@ onBeforeUnmount(() => {
|
|||||||
</pane> <!-- End Command Bar Pane -->
|
</pane> <!-- End Command Bar Pane -->
|
||||||
|
|
||||||
<!-- 下方 Pane (文件管理器区域 - 包含新的水平分割) -->
|
<!-- 下方 Pane (文件管理器区域 - 包含新的水平分割) -->
|
||||||
<pane v-if="paneVisibility.fileManager" size="40" min-size="15" class="file-manager-area-pane pane-with-title"> <!-- 使用 v-if 控制, 添加 class -->
|
<pane v-if="paneVisibility.fileManager" size="40" min-size="15" class="file-manager-area-pane"> <!-- 移除 pane-with-title class -->
|
||||||
<PaneTitleBar :title="t('layout.pane.fileManager')" pane-name="fileManager" />
|
|
||||||
<!-- 新增:内部水平分割,允许未来添加列 -->
|
<!-- 新增:内部水平分割,允许未来添加列 -->
|
||||||
<splitpanes :horizontal="false" style="height: 100%" :dbl-click-splitter="false" class="pane-content"> <!-- 添加 class -->
|
<splitpanes :horizontal="false" style="height: 100%" :dbl-click-splitter="false" class="pane-content"> <!-- 添加 class -->
|
||||||
<!-- 初始的文件管理器 Pane -->
|
<!-- 初始的文件管理器 Pane -->
|
||||||
@@ -274,8 +271,7 @@ onBeforeUnmount(() => {
|
|||||||
</pane> <!-- End Middle Pane -->
|
</pane> <!-- End Middle Pane -->
|
||||||
|
|
||||||
<!-- 3. 右侧区域 1 Pane (文件编辑器) -->
|
<!-- 3. 右侧区域 1 Pane (文件编辑器) -->
|
||||||
<pane v-if="paneVisibility.editor" size="20" min-size="15" class="file-editor-pane pane-with-title"> <!-- 使用 v-if 控制, 添加 class -->
|
<pane v-if="paneVisibility.editor" size="20" min-size="15" class="file-editor-pane"> <!-- 移除 pane-with-title class -->
|
||||||
<PaneTitleBar :title="t('layout.pane.editor')" pane-name="editor" />
|
|
||||||
<FileEditorContainer
|
<FileEditorContainer
|
||||||
class="pane-content"
|
class="pane-content"
|
||||||
:tabs="editorTabs"
|
:tabs="editorTabs"
|
||||||
@@ -289,8 +285,7 @@ onBeforeUnmount(() => {
|
|||||||
</pane>
|
</pane>
|
||||||
|
|
||||||
<!-- 4. 右侧区域 2 Pane (状态监视器) -->
|
<!-- 4. 右侧区域 2 Pane (状态监视器) -->
|
||||||
<pane v-if="paneVisibility.statusMonitor" size="15" min-size="10" class="sidebar-pane status-monitor-pane pane-with-title"> <!-- 使用 v-if 控制, 添加 class -->
|
<pane v-if="paneVisibility.statusMonitor" size="15" min-size="10" class="sidebar-pane status-monitor-pane"> <!-- 移除 pane-with-title class -->
|
||||||
<PaneTitleBar :title="t('layout.pane.statusMonitor')" pane-name="statusMonitor" />
|
|
||||||
<div class="pane-content status-monitor-content-wrapper"> <!-- 添加包裹 div -->
|
<div class="pane-content status-monitor-content-wrapper"> <!-- 添加包裹 div -->
|
||||||
<div
|
<div
|
||||||
v-for="tabInfo in sessionTabsWithStatus"
|
v-for="tabInfo in sessionTabsWithStatus"
|
||||||
@@ -342,11 +337,7 @@ onBeforeUnmount(() => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* 为 Pane 添加一些基本样式 */
|
/* 为 Pane 添加一些基本样式 */
|
||||||
.pane-with-title { /* 给包含标题栏的 Pane 添加基础样式 */
|
/* .pane-with-title 已移除 */
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
.pane-content { /* 让内容区域填充剩余空间 */
|
.pane-content { /* 让内容区域填充剩余空间 */
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
overflow: auto; /* 或者 hidden,根据需要 */
|
overflow: auto; /* 或者 hidden,根据需要 */
|
||||||
@@ -362,7 +353,9 @@ onBeforeUnmount(() => {
|
|||||||
.file-manager-area-pane, /* 文件管理器区域 Pane */
|
.file-manager-area-pane, /* 文件管理器区域 Pane */
|
||||||
.file-manager-pane, /* 内部文件管理器 Pane */
|
.file-manager-pane, /* 内部文件管理器 Pane */
|
||||||
.status-monitor-pane { /* 状态监视器样式 */
|
.status-monitor-pane { /* 状态监视器样式 */
|
||||||
/* display: flex; flex-direction: column; overflow: hidden; 已被 pane-with-title 或 pane-content 处理 */
|
display: flex; /* 确保 flex 布局 */
|
||||||
|
flex-direction: column; /* 确保列方向 */
|
||||||
|
overflow: hidden; /* 默认隐藏溢出 */
|
||||||
background-color: #f8f9fa; /* 默认背景色 */
|
background-color: #f8f9fa; /* 默认背景色 */
|
||||||
}
|
}
|
||||||
.middle-pane {
|
.middle-pane {
|
||||||
@@ -396,7 +389,7 @@ onBeforeUnmount(() => {
|
|||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
overflow: hidden;
|
overflow: hidden; /* <-- 重新添加,隐藏外部滚动条 */
|
||||||
}
|
}
|
||||||
.file-editor-pane {
|
.file-editor-pane {
|
||||||
background-color: #f8f9fa; /* 外层 pane 背景 */
|
background-color: #f8f9fa; /* 外层 pane 背景 */
|
||||||
@@ -440,7 +433,7 @@ onBeforeUnmount(() => {
|
|||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
overflow: hidden;
|
overflow: hidden; /* <-- 重新添加,隐藏外部滚动条 */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 文件管理器包装器 (内部组件应填充) */
|
/* 文件管理器包装器 (内部组件应填充) */
|
||||||
|
|||||||
Reference in New Issue
Block a user