✨ feat(vscode): 设置可关新开终端分屏

This commit is contained in:
cruldra committed 2026-09-01 17:38:06 +08:00
1 parent 7463113170
commit ffae9ce2b8
11 files changed
+66 -7

No files matched your search

+2
View File
@@ -932,6 +932,7 @@ export class KanbanWebviewPanel {
worktreePreRemoveScript: s.worktreePreRemoveScript,
implTabPreCreateScript: s.implTabPreCreateScript,
implTabPostCloseScript: s.implTabPostCloseScript,
splitNewTerminals: s.splitNewTerminals,
conflictResolutionProfilePath: s.conflictResolutionProfilePath,
commitProfilePath: await getEffectiveCommitProfilePath(this.context),
prDiffSummaryProfilePath: await getEffectivePrDiffSummaryProfilePath(this.context),
@@ -1010,6 +1011,7 @@ export class KanbanWebviewPanel {
worktreePreRemoveScript: s.worktreePreRemoveScript,
implTabPreCreateScript: s.implTabPreCreateScript,
implTabPostCloseScript: s.implTabPostCloseScript,
splitNewTerminals: s.splitNewTerminals,
conflictResolutionProfilePath: s.conflictResolutionProfilePath,
commitProfilePath: await getEffectiveCommitProfilePath(this.context),
prDiffSummaryProfilePath: await getEffectivePrDiffSummaryProfilePath(this.context),
+4
View File
@@ -38,6 +38,7 @@ export async function handleSettingsSave(panel: KanbanWebviewPanel, payload: {
worktreePreRemoveScript: string
implTabPreCreateScript: string
implTabPostCloseScript: string
splitNewTerminals: boolean
conflictResolutionProfilePath: string
commitProfilePath: string
prDiffSummaryProfilePath: string
@@ -116,6 +117,7 @@ export async function handleSettingsSave(panel: KanbanWebviewPanel, payload: {
worktreePreRemoveScript: trimmedPreRemove,
implTabPreCreateScript: trimmedImplPre,
implTabPostCloseScript: trimmedImplPost,
splitNewTerminals: payload.splitNewTerminals,
conflictResolutionProfilePath: trimmedConflictProfile,
commitProfilePath: trimmedCommitProfile,
prDiffSummaryProfilePath: trimmedPrDiffSummaryProfile,
@@ -144,6 +146,7 @@ export async function handleSettingsSave(panel: KanbanWebviewPanel, payload: {
worktreePreRemoveScript: trimmedPreRemove,
implTabPreCreateScript: trimmedImplPre,
implTabPostCloseScript: trimmedImplPost,
splitNewTerminals: payload.splitNewTerminals,
conflictResolutionProfilePath: trimmedConflictProfile,
commitProfilePath: trimmedCommitProfile,
prDiffSummaryProfilePath: trimmedPrDiffSummaryProfile,
@@ -249,6 +252,7 @@ export async function handleEditSettingsRequest(panel: KanbanWebviewPanel): Prom
worktreePreRemoveScript: s.worktreePreRemoveScript,
implTabPreCreateScript: s.implTabPreCreateScript,
implTabPostCloseScript: s.implTabPostCloseScript,
splitNewTerminals: s.splitNewTerminals,
conflictResolutionProfilePath: s.conflictResolutionProfilePath,
commitProfilePath,
prDiffSummaryProfilePath,
@@ -0,0 +1,11 @@
import { describe, expect, it } from 'vitest'
import { terminalEditorColumn } from '../terminalColumn'
describe('terminalEditorColumn', () => {
it('分屏 → 右侧第 2 栏', () => {
expect(terminalEditorColumn(true)).toBe(2)
})
it('不分屏 → 当前栏(只加标签)', () => {
expect(terminalEditorColumn(false)).toBe(-1)
})
})
+5 -7
View File
@@ -4,16 +4,14 @@ import type {
} from 'vscode'
import type { Issue } from '../../gitea/types'
import type { KanbanWebviewPanel } from '../KanbanPanel'
import { ViewColumn, window } from 'vscode'
import { window } from 'vscode'
import { logger } from '../../logging/logger'
import { getSettings } from '../../settings/store'
import { terminalEditorColumn } from '../terminalColumn'
export function resolveTerminalLocation(panel: KanbanWebviewPanel | null, preserveFocus: boolean): TerminalEditorLocationOptions {
void panel
// Pin all plugin-managed terminals to editor group 2 (right side of the
// kanban panel in column 1). VS Code creates the group on demand if it
// doesn't exist yet, and stacks new terminals as tabs in that group when
// it does — exactly what we want, no manual scan of existing tabs needed.
return { viewColumn: ViewColumn.Two, preserveFocus }
const split = panel ? getSettings(panel.context).splitNewTerminals : true
return { viewColumn: terminalEditorColumn(split), preserveFocus }
}
/**
+2
View File
@@ -84,6 +84,7 @@ export type ExtensionToWebview
worktreePreRemoveScript: string
implTabPreCreateScript: string
implTabPostCloseScript: string
splitNewTerminals: boolean
conflictResolutionProfilePath: string
commitProfilePath: string
prDiffSummaryProfilePath: string
@@ -162,6 +163,7 @@ export type WebviewToExtension
worktreePreRemoveScript: string
implTabPreCreateScript: string
implTabPostCloseScript: string
splitNewTerminals: boolean
conflictResolutionProfilePath: string
commitProfilePath: string
prDiffSummaryProfilePath: string
+7
View File
@@ -0,0 +1,7 @@
/**
* 会话终端落在编辑区哪一栏。
* 数值对齐 VS Code ViewColumn:2 = Two(右侧分屏),-1 = Active(当前栏只加标签)。
*/
export function terminalEditorColumn(split: boolean): 2 | -1 {
return split ? 2 : -1
}
+9
View File
@@ -159,6 +159,10 @@ export interface Settings {
* Same env vars as the worktree hooks.
*/
implTabPostCloseScript: string
/**
* 新开会话终端是否分到右侧一栏。关掉则在当前编辑组加标签,适合小屏。
*/
splitNewTerminals: boolean
/**
* YouTrack instance base URL (e.g. `https://ziwuxian.youtrack.cloud`). Empty
* string means "YouTrack source disabled" — the loader returns no issues.
@@ -264,6 +268,7 @@ function defaults(ctx: ExtensionContext): Settings {
worktreePreRemoveScript: '',
implTabPreCreateScript: '',
implTabPostCloseScript: '',
splitNewTerminals: true,
youtrackBaseUrl: '',
youtrackProjectShortName: '',
youtrackCloseCommand: '',
@@ -350,6 +355,9 @@ export function getSettings(ctx: ExtensionContext): Settings {
const implTabPostCloseScript = typeof stored.implTabPostCloseScript === 'string'
? stored.implTabPostCloseScript
: base.implTabPostCloseScript
const splitNewTerminals = typeof stored.splitNewTerminals === 'boolean'
? stored.splitNewTerminals
: base.splitNewTerminals
// YouTrack config: '' is meaningful (= "source disabled" / "auto-detect close
// command"), so don't coerce. Non-string legacy values collapse to ''.
const youtrackBaseUrl = typeof stored.youtrackBaseUrl === 'string'
@@ -405,6 +413,7 @@ export function getSettings(ctx: ExtensionContext): Settings {
worktreePreRemoveScript,
implTabPreCreateScript,
implTabPostCloseScript,
splitNewTerminals,
youtrackBaseUrl,
youtrackProjectShortName,
youtrackCloseCommand,
+1
View File
@@ -534,6 +534,7 @@ export function App() {
initialWorktreePreRemoveScript={settings?.worktreePreRemoveScript ?? ''}
initialImplTabPreCreateScript={settings?.implTabPreCreateScript ?? ''}
initialImplTabPostCloseScript={settings?.implTabPostCloseScript ?? ''}
initialSplitNewTerminals={settings?.splitNewTerminals ?? true}
initialConflictResolutionProfilePath={settings?.conflictResolutionProfilePath ?? ''}
initialCommitProfilePath={settings?.commitProfilePath ?? ''}
initialPrDiffSummaryProfilePath={settings?.prDiffSummaryProfilePath ?? ''}
@@ -36,6 +36,7 @@ interface SubmitValues {
worktreePreRemoveScript: string
implTabPreCreateScript: string
implTabPostCloseScript: string
splitNewTerminals: boolean
conflictResolutionProfilePath: string
commitProfilePath: string
prDiffSummaryProfilePath: string
@@ -85,6 +86,7 @@ export interface SettingsModalProps {
initialWorktreePreRemoveScript: string
initialImplTabPreCreateScript: string
initialImplTabPostCloseScript: string
initialSplitNewTerminals: boolean
initialConflictResolutionProfilePath: string
initialCommitProfilePath: string
initialPrDiffSummaryProfilePath: string
@@ -170,6 +172,7 @@ export function SettingsModal({
initialWorktreePreRemoveScript,
initialImplTabPreCreateScript,
initialImplTabPostCloseScript,
initialSplitNewTerminals,
initialConflictResolutionProfilePath,
initialCommitProfilePath,
initialPrDiffSummaryProfilePath,
@@ -207,6 +210,7 @@ export function SettingsModal({
const [worktreePreRemoveScript, setWorktreePreRemoveScript] = useState(initialWorktreePreRemoveScript)
const [implTabPreCreateScript, setImplTabPreCreateScript] = useState(initialImplTabPreCreateScript)
const [implTabPostCloseScript, setImplTabPostCloseScript] = useState(initialImplTabPostCloseScript)
const [splitNewTerminals, setSplitNewTerminals] = useState(initialSplitNewTerminals)
const [conflictResolutionProfilePath, setConflictResolutionProfilePath] = useState(initialConflictResolutionProfilePath)
const [commitProfilePath, setCommitProfilePath] = useState(initialCommitProfilePath)
const [prDiffSummaryProfilePath, setPrDiffSummaryProfilePath] = useState(initialPrDiffSummaryProfilePath)
@@ -246,6 +250,7 @@ export function SettingsModal({
setWorktreePreRemoveScript(initialWorktreePreRemoveScript)
setImplTabPreCreateScript(initialImplTabPreCreateScript)
setImplTabPostCloseScript(initialImplTabPostCloseScript)
setSplitNewTerminals(initialSplitNewTerminals)
setConflictResolutionProfilePath(initialConflictResolutionProfilePath)
setCommitProfilePath(initialCommitProfilePath)
setPrDiffSummaryProfilePath(initialPrDiffSummaryProfilePath)
@@ -336,6 +341,7 @@ export function SettingsModal({
worktreePreRemoveScript: worktreePreRemoveScript.trim(),
implTabPreCreateScript: implTabPreCreateScript.trim(),
implTabPostCloseScript: implTabPostCloseScript.trim(),
splitNewTerminals,
// 冲突解决 profile:空串 = 用 DEFAULT_PROFILE_PATH
conflictResolutionProfilePath: conflictResolutionProfilePath.trim(),
// 提交代码 profile:空串 = 未配置 → 提交严格失败
@@ -910,6 +916,19 @@ export function SettingsModal({
{activeGroup === 'hooks' && (
<>
<Field
label="新开终端分屏"
hint="关掉后,会话终端和看板在同一组里只加标签,不再劈成左右两栏。小屏建议关。"
>
<label className="inline-flex cursor-pointer items-center gap-2 text-xs">
<input
type="checkbox"
checked={splitNewTerminals}
onChange={e => setSplitNewTerminals(e.target.checked)}
/>
<span className="opacity-80">分到右侧一栏</span>
</label>
</Field>
<Field
label="工作树目录"
hint={(
+4
View File
@@ -54,6 +54,7 @@ export interface SettingsValues {
worktreePreRemoveScript: string
implTabPreCreateScript: string
implTabPostCloseScript: string
splitNewTerminals: boolean
conflictResolutionProfilePath: string
commitProfilePath: string
prDiffSummaryProfilePath: string
@@ -89,6 +90,7 @@ export interface SettingsOverlayState {
worktreePreRemoveScript: string
implTabPreCreateScript: string
implTabPostCloseScript: string
splitNewTerminals: boolean
conflictResolutionProfilePath: string
commitProfilePath: string
prDiffSummaryProfilePath: string
@@ -403,6 +405,7 @@ export function useIssues(): UseIssuesResult {
worktreePreRemoveScript: values.worktreePreRemoveScript,
implTabPreCreateScript: values.implTabPreCreateScript,
implTabPostCloseScript: values.implTabPostCloseScript,
splitNewTerminals: values.splitNewTerminals,
conflictResolutionProfilePath: values.conflictResolutionProfilePath,
commitProfilePath: values.commitProfilePath,
prDiffSummaryProfilePath: values.prDiffSummaryProfilePath,
@@ -796,6 +799,7 @@ export function useIssues(): UseIssuesResult {
worktreePreRemoveScript: msg.worktreePreRemoveScript,
implTabPreCreateScript: msg.implTabPreCreateScript,
implTabPostCloseScript: msg.implTabPostCloseScript,
splitNewTerminals: msg.splitNewTerminals,
conflictResolutionProfilePath: msg.conflictResolutionProfilePath,
commitProfilePath: msg.commitProfilePath,
prDiffSummaryProfilePath: msg.prDiffSummaryProfilePath,
+2
View File
@@ -113,6 +113,7 @@ export type ExtensionToWebview
worktreePreRemoveScript: string
implTabPreCreateScript: string
implTabPostCloseScript: string
splitNewTerminals: boolean
conflictResolutionProfilePath: string
commitProfilePath: string
prDiffSummaryProfilePath: string
@@ -191,6 +192,7 @@ export type WebviewToExtension
worktreePreRemoveScript: string
implTabPreCreateScript: string
implTabPostCloseScript: string
splitNewTerminals: boolean
conflictResolutionProfilePath: string
commitProfilePath: string
prDiffSummaryProfilePath: string