Configurable location for OpenCode: sidebar or main window

This commit is contained in:
Mateusz Tymek
2026-01-10 16:00:13 +01:00
parent b8081e70fa
commit 30953b3176
8 changed files with 157 additions and 18 deletions

31
main.js
View File

@@ -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();

View File

@@ -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`

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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" });

View File

@@ -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();

View File

@@ -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";