From 30953b31763fbfe8b248281971399bf980a6b50c Mon Sep 17 00:00:00 2001 From: Mateusz Tymek Date: Sat, 10 Jan 2026 16:00:13 +0100 Subject: [PATCH] Configurable location for OpenCode: sidebar or main window --- main.js | 31 ++++++++++++---- .../add-default-view-location/proposal.md | 14 ++++++++ .../specs/001-mvp-opencode-embed/spec.md | 36 +++++++++++++++++++ .../add-default-view-location/tasks.md | 23 ++++++++++++ openspec/specs/001-mvp-opencode-embed/spec.md | 22 +++++++++--- src/SettingsTab.ts | 17 +++++++++ src/main.ts | 28 +++++++++++---- src/types.ts | 4 +++ 8 files changed, 157 insertions(+), 18 deletions(-) create mode 100644 openspec/changes/archive/add-default-view-location/proposal.md create mode 100644 openspec/changes/archive/add-default-view-location/specs/001-mvp-opencode-embed/spec.md create mode 100644 openspec/changes/archive/add-default-view-location/tasks.md diff --git a/main.js b/main.js index 24fd5a9..737000d 100644 --- a/main.js +++ b/main.js @@ -36,7 +36,8 @@ var DEFAULT_SETTINGS = { autoStart: false, opencodePath: "opencode", projectDirectory: "", - startupTimeout: 15e3 + startupTimeout: 15e3, + defaultViewLocation: "sidebar" }; var OPENCODE_VIEW_TYPE = "opencode-view"; @@ -300,6 +301,14 @@ var OpenCodeSettingTab = class extends import_obsidian3.PluginSettingTab { await this.plugin.saveSettings(); }) ); + new import_obsidian3.Setting(containerEl).setName("Default view location").setDesc( + "Where to open the OpenCode panel: sidebar opens in the right panel, main opens as a tab in the editor area" + ).addDropdown( + (dropdown) => dropdown.addOption("sidebar", "Sidebar").addOption("main", "Main window").setValue(this.plugin.settings.defaultViewLocation).onChange(async (value) => { + this.plugin.settings.defaultViewLocation = value; + await this.plugin.saveSettings(); + }) + ); containerEl.createEl("h3", { text: "Server Status" }); const statusContainer = containerEl.createDiv({ cls: "opencode-settings-status" }); this.renderServerStatus(statusContainer); @@ -666,7 +675,12 @@ var OpenCodePlugin = class extends import_obsidian4.Plugin { this.app.workspace.revealLeaf(existingLeaf); return; } - const leaf = this.app.workspace.getRightLeaf(false); + let leaf = null; + if (this.settings.defaultViewLocation === "main") { + leaf = this.app.workspace.getLeaf("tab"); + } else { + leaf = this.app.workspace.getRightLeaf(false); + } if (leaf) { await leaf.setViewState({ type: OPENCODE_VIEW_TYPE, @@ -679,11 +693,16 @@ var OpenCodePlugin = class extends import_obsidian4.Plugin { async toggleView() { const existingLeaf = this.getExistingLeaf(); if (existingLeaf) { - const rightSplit = this.app.workspace.rightSplit; - if (rightSplit && !rightSplit.collapsed) { - existingLeaf.detach(); + const isInSidebar = existingLeaf.getRoot() === this.app.workspace.rightSplit; + if (isInSidebar) { + const rightSplit = this.app.workspace.rightSplit; + if (rightSplit && !rightSplit.collapsed) { + existingLeaf.detach(); + } else { + this.app.workspace.revealLeaf(existingLeaf); + } } else { - this.app.workspace.revealLeaf(existingLeaf); + existingLeaf.detach(); } } else { await this.activateView(); diff --git a/openspec/changes/archive/add-default-view-location/proposal.md b/openspec/changes/archive/add-default-view-location/proposal.md new file mode 100644 index 0000000..1d413ea --- /dev/null +++ b/openspec/changes/archive/add-default-view-location/proposal.md @@ -0,0 +1,14 @@ +# Change: Add Default View Location Setting + +## Why +Users may prefer to have the OpenCode panel open in the main editor area instead of the sidebar, depending on their workflow and screen size. Currently, the view always opens in the right sidebar with no option to change this behavior. + +## What Changes +- Add a new `defaultViewLocation` setting with options: `"sidebar"` or `"main"` +- Update view activation logic to respect this setting when opening the panel +- Sidebar opens in the right leaf (current behavior) +- Main opens in a new tab in the main editor area + +## Impact +- Affected specs: `001-mvp-opencode-embed` (Settings Configuration, Sidebar View Registration, Ribbon Icon) +- Affected code: `src/types.ts`, `src/main.ts`, `src/SettingsTab.ts` diff --git a/openspec/changes/archive/add-default-view-location/specs/001-mvp-opencode-embed/spec.md b/openspec/changes/archive/add-default-view-location/specs/001-mvp-opencode-embed/spec.md new file mode 100644 index 0000000..38d9306 --- /dev/null +++ b/openspec/changes/archive/add-default-view-location/specs/001-mvp-opencode-embed/spec.md @@ -0,0 +1,36 @@ +## MODIFIED Requirements + +### Requirement: Settings Configuration +The plugin SHALL provide configurable settings for server port, hostname, executable path, project directory, auto-start behavior, and default view location. + +#### Scenario: Settings persistence +- **WHEN** the user modifies settings +- **THEN** changes are persisted to plugin data +- **AND** the process manager is updated with new settings + +#### Scenario: Default view location options +- **WHEN** the user configures default view location +- **THEN** the options available are "sidebar" and "main" +- **AND** the default value is "sidebar" + +### Requirement: Sidebar View Registration +The plugin SHALL register an ItemView that displays in either the Obsidian sidebar or main editor area based on user settings. + +#### Scenario: View activation in sidebar +- **WHEN** the user clicks the ribbon icon or runs the toggle command +- **AND** the default view location is set to "sidebar" +- **THEN** the OpenCode view opens in the right sidebar +- **AND** if the view already exists, it is revealed + +#### Scenario: View activation in main area +- **WHEN** the user clicks the ribbon icon or runs the toggle command +- **AND** the default view location is set to "main" +- **THEN** the OpenCode view opens as a new tab in the main editor area +- **AND** if the view already exists in any location, it is revealed + +### Requirement: Ribbon Icon +The plugin SHALL add a ribbon icon that activates the OpenCode view in the configured default location. + +#### Scenario: Ribbon icon click +- **WHEN** the user clicks the OpenCode ribbon icon +- **THEN** the OpenCode view is activated in the location specified by the default view location setting diff --git a/openspec/changes/archive/add-default-view-location/tasks.md b/openspec/changes/archive/add-default-view-location/tasks.md new file mode 100644 index 0000000..5f21d1a --- /dev/null +++ b/openspec/changes/archive/add-default-view-location/tasks.md @@ -0,0 +1,23 @@ +## 1. Implementation + +- [ ] 1.1 Add `defaultViewLocation` type and setting to `src/types.ts` + - Add type: `"sidebar" | "main"` + - Add to `OpenCodeSettings` interface + - Add default value `"sidebar"` to `DEFAULT_SETTINGS` + +- [ ] 1.2 Update `src/main.ts` view activation logic + - Modify `activateView()` method to check `defaultViewLocation` setting + - For "sidebar": use `getLeaf("right")` (existing behavior) + - For "main": use `getLeaf("tab")` to open in main editor area + - Ensure existing view detection works for both locations + +- [ ] 1.3 Add setting UI to `src/SettingsTab.ts` + - Add dropdown setting for "Default view location" + - Options: "Sidebar" and "Main window" + - Description explaining the behavior difference + +- [ ] 1.4 Test the feature + - Verify sidebar mode opens in right sidebar + - Verify main mode opens as a tab in editor area + - Verify toggling reveals existing view regardless of location + - Verify setting persists across plugin reload diff --git a/openspec/specs/001-mvp-opencode-embed/spec.md b/openspec/specs/001-mvp-opencode-embed/spec.md index 88170b5..85c0782 100644 --- a/openspec/specs/001-mvp-opencode-embed/spec.md +++ b/openspec/specs/001-mvp-opencode-embed/spec.md @@ -45,13 +45,20 @@ The plugin SHALL maintain a state machine with states: stopped, starting, runnin - **THEN** the state transitions to `error` ### Requirement: Sidebar View Registration -The plugin SHALL register an ItemView that displays in the Obsidian sidebar. +The plugin SHALL register an ItemView that displays in either the Obsidian sidebar or main editor area based on user settings. -#### Scenario: View activation +#### Scenario: View activation in sidebar - **WHEN** the user clicks the ribbon icon or runs the toggle command +- **AND** the default view location is set to "sidebar" - **THEN** the OpenCode view opens in the right sidebar - **AND** if the view already exists, it is revealed +#### Scenario: View activation in main area +- **WHEN** the user clicks the ribbon icon or runs the toggle command +- **AND** the default view location is set to "main" +- **THEN** the OpenCode view opens as a new tab in the main editor area +- **AND** if the view already exists in any location, it is revealed + ### Requirement: View State Rendering The plugin SHALL render different UI content based on the current process state. @@ -89,13 +96,18 @@ The plugin SHALL start the server automatically when the view is opened if not a - **THEN** the plugin initiates server start ### Requirement: Settings Configuration -The plugin SHALL provide configurable settings for server port, hostname, executable path, project directory, and auto-start behavior. +The plugin SHALL provide configurable settings for server port, hostname, executable path, project directory, auto-start behavior, and default view location. #### Scenario: Settings persistence - **WHEN** the user modifies settings - **THEN** changes are persisted to plugin data - **AND** the process manager is updated with new settings +#### Scenario: Default view location options +- **WHEN** the user configures default view location +- **THEN** the options available are "sidebar" and "main" +- **AND** the default value is "sidebar" + ### Requirement: Project Directory Validation The plugin SHALL validate the project directory setting and support tilde expansion. @@ -131,8 +143,8 @@ The plugin SHALL register commands for toggling the view and controlling the ser - **THEN** the server stops ### Requirement: Ribbon Icon -The plugin SHALL add a ribbon icon that activates the OpenCode view. +The plugin SHALL add a ribbon icon that activates the OpenCode view in the configured default location. #### Scenario: Ribbon icon click - **WHEN** the user clicks the OpenCode ribbon icon -- **THEN** the OpenCode view is activated in the right sidebar +- **THEN** the OpenCode view is activated in the location specified by the default view location setting diff --git a/src/SettingsTab.ts b/src/SettingsTab.ts index 89b9aa6..3b5e297 100644 --- a/src/SettingsTab.ts +++ b/src/SettingsTab.ts @@ -2,6 +2,7 @@ import { App, PluginSettingTab, Setting, Notice } from "obsidian"; import { existsSync, statSync } from "fs"; import { homedir } from "os"; import type OpenCodePlugin from "./main"; +import type { ViewLocation } from "./types"; function expandTilde(path: string): string { if (path === "~") { @@ -108,6 +109,22 @@ export class OpenCodeSettingTab extends PluginSettingTab { }) ); + new Setting(containerEl) + .setName("Default view location") + .setDesc( + "Where to open the OpenCode panel: sidebar opens in the right panel, main opens as a tab in the editor area" + ) + .addDropdown((dropdown) => + dropdown + .addOption("sidebar", "Sidebar") + .addOption("main", "Main window") + .setValue(this.plugin.settings.defaultViewLocation) + .onChange(async (value) => { + this.plugin.settings.defaultViewLocation = value as ViewLocation; + await this.plugin.saveSettings(); + }) + ); + containerEl.createEl("h3", { text: "Server Status" }); const statusContainer = containerEl.createDiv({ cls: "opencode-settings-status" }); diff --git a/src/main.ts b/src/main.ts index d5c7f1e..d0d4a4e 100644 --- a/src/main.ts +++ b/src/main.ts @@ -118,8 +118,14 @@ export default class OpenCodePlugin extends Plugin { return; } - // Create new leaf in right sidebar - const leaf = this.app.workspace.getRightLeaf(false); + // Create new leaf based on defaultViewLocation setting + let leaf: WorkspaceLeaf | null = null; + if (this.settings.defaultViewLocation === "main") { + leaf = this.app.workspace.getLeaf("tab"); + } else { + leaf = this.app.workspace.getRightLeaf(false); + } + if (leaf) { await leaf.setViewState({ type: OPENCODE_VIEW_TYPE, @@ -134,12 +140,20 @@ export default class OpenCodePlugin extends Plugin { const existingLeaf = this.getExistingLeaf(); if (existingLeaf) { - // Check if visible - const rightSplit = this.app.workspace.rightSplit; - if (rightSplit && !rightSplit.collapsed) { - existingLeaf.detach(); + // Check if the view is in the sidebar or main area + const isInSidebar = existingLeaf.getRoot() === this.app.workspace.rightSplit; + + if (isInSidebar) { + // For sidebar views, check if sidebar is collapsed + const rightSplit = this.app.workspace.rightSplit; + if (rightSplit && !rightSplit.collapsed) { + existingLeaf.detach(); + } else { + this.app.workspace.revealLeaf(existingLeaf); + } } else { - this.app.workspace.revealLeaf(existingLeaf); + // For main area views, just detach (close the tab) + existingLeaf.detach(); } } else { await this.activateView(); diff --git a/src/types.ts b/src/types.ts index 60a3eb2..5af8d71 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1,3 +1,5 @@ +export type ViewLocation = "sidebar" | "main"; + export interface OpenCodeSettings { port: number; hostname: string; @@ -5,6 +7,7 @@ export interface OpenCodeSettings { opencodePath: string; projectDirectory: string; startupTimeout: number; + defaultViewLocation: ViewLocation; } export const DEFAULT_SETTINGS: OpenCodeSettings = { @@ -14,6 +17,7 @@ export const DEFAULT_SETTINGS: OpenCodeSettings = { opencodePath: "opencode", projectDirectory: "", startupTimeout: 15000, + defaultViewLocation: "sidebar", }; export const OPENCODE_VIEW_TYPE = "opencode-view";