mirror of
https://github.com/jesse-r-s-hines/obsidian-open-tab-settings.git
synced 2026-07-22 05:43:41 +00:00
commit
a8701b8fd0
8 changed files with 4941 additions and 2509 deletions
23
.eslintrc
23
.eslintrc
|
|
@ -1,23 +0,0 @@
|
|||
{
|
||||
"root": true,
|
||||
"parser": "@typescript-eslint/parser",
|
||||
"env": { "node": true },
|
||||
"plugins": [
|
||||
"@typescript-eslint"
|
||||
],
|
||||
"extends": [
|
||||
"eslint:recommended",
|
||||
"plugin:@typescript-eslint/eslint-recommended",
|
||||
"plugin:@typescript-eslint/recommended"
|
||||
],
|
||||
"parserOptions": {
|
||||
"sourceType": "module"
|
||||
},
|
||||
"rules": {
|
||||
"no-unused-vars": "off",
|
||||
"@typescript-eslint/no-unused-vars": ["error", { "args": "none" }],
|
||||
"@typescript-eslint/ban-ts-comment": "off",
|
||||
"no-prototype-builtins": "off",
|
||||
"@typescript-eslint/no-empty-function": "off"
|
||||
}
|
||||
}
|
||||
|
|
@ -1,51 +1,35 @@
|
|||
// @ts-check
|
||||
import eslint from '@eslint/js';
|
||||
import tseslint from 'typescript-eslint';
|
||||
import obsidianmd from "eslint-plugin-obsidianmd";
|
||||
import globals from "globals";
|
||||
import { globalIgnores } from "eslint/config";
|
||||
|
||||
export default tseslint.config(
|
||||
eslint.configs.recommended,
|
||||
tseslint.configs.recommendedTypeChecked,
|
||||
{
|
||||
languageOptions: {
|
||||
globals: {
|
||||
...globals.browser,
|
||||
},
|
||||
parserOptions: {
|
||||
projectService: true,
|
||||
projectService: {
|
||||
allowDefaultProject: [
|
||||
'eslint.config.js',
|
||||
'manifest.json'
|
||||
]
|
||||
},
|
||||
tsconfigRootDir: import.meta.dirname,
|
||||
extraFileExtensions: ['.json']
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
rules: {
|
||||
"no-prototype-builtins": "off",
|
||||
'no-undef': 'off',
|
||||
"no-empty": "off",
|
||||
"@typescript-eslint/no-this-alias": "off",
|
||||
"@typescript-eslint/no-explicit-any": "off",
|
||||
"@typescript-eslint/no-unsafe-argument": "off",
|
||||
"@typescript-eslint/no-unsafe-assignment": "off",
|
||||
"@typescript-eslint/no-unsafe-member-access": "off",
|
||||
"@typescript-eslint/no-unsafe-return": "off",
|
||||
"@typescript-eslint/no-unsafe-call": "off",
|
||||
"@typescript-eslint/no-namespace": "off",
|
||||
'@typescript-eslint/no-require-imports': 'off',
|
||||
"@typescript-eslint/restrict-plus-operands": "off",
|
||||
"@typescript-eslint/require-await": "off",
|
||||
"@typescript-eslint/no-empty-object-type": "off",
|
||||
"@typescript-eslint/restrict-template-expressions": "off",
|
||||
"@typescript-eslint/no-misused-promises": ["error", {
|
||||
checksVoidReturn: false,
|
||||
}],
|
||||
"@typescript-eslint/no-floating-promises": ["error", {
|
||||
checkThenables: true,
|
||||
allowForKnownSafeCalls: [
|
||||
{from: 'package', package: "expect", name: ["expect", "toEqual", "toMatch", "toMatchObject"]},
|
||||
],
|
||||
}],
|
||||
"@typescript-eslint/no-unused-vars": ["error", {
|
||||
args: "none",
|
||||
varsIgnorePattern: "^_",
|
||||
destructuredArrayIgnorePattern: ".*",
|
||||
ignoreRestSiblings: true,
|
||||
}],
|
||||
},
|
||||
},
|
||||
);
|
||||
...obsidianmd.configs.recommended,
|
||||
globalIgnores([
|
||||
"node_modules",
|
||||
"dist",
|
||||
"esbuild.config.mjs",
|
||||
"eslint.config.js",
|
||||
"eslint.config.mjs",
|
||||
"version-bump.mjs",
|
||||
"versions.json",
|
||||
"main.js",
|
||||
]),
|
||||
);
|
||||
7279
package-lock.json
generated
7279
package-lock.json
generated
File diff suppressed because it is too large
Load diff
31
package.json
31
package.json
|
|
@ -8,7 +8,7 @@
|
|||
"build": "tsc -noEmit -skipLibCheck && node esbuild.config.mjs production",
|
||||
"build-dev": "tsc -noEmit -skipLibCheck && node esbuild.config.mjs development",
|
||||
"version": "node version-bump.mjs && git add manifest.json versions.json",
|
||||
"lint": "eslint src test",
|
||||
"lint": "eslint src",
|
||||
"test": "run-s test:*",
|
||||
"test:unit": "tsc --noEmit && mocha",
|
||||
"test:e2e": "npx wdio run ./wdio.conf.mts",
|
||||
|
|
@ -18,31 +18,32 @@
|
|||
"author": "",
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"@eslint/js": "^9.39.4",
|
||||
"@eslint/js": "^10.0.1",
|
||||
"@types/chai": "^5.2.3",
|
||||
"@types/mocha": "^10.0.10",
|
||||
"@types/node": "^25.5.0",
|
||||
"@wdio/appium-service": "^9.27.0",
|
||||
"@wdio/cli": "^9.27.0",
|
||||
"@wdio/local-runner": "^9.27.0",
|
||||
"@wdio/mocha-framework": "^9.27.0",
|
||||
"@wdio/spec-reporter": "^9.27.0",
|
||||
"appium": "^3.2.2",
|
||||
"appium-uiautomator2-driver": "^7.1.0",
|
||||
"builtin-modules": "^5.0.0",
|
||||
"@types/node": "^25.7.0",
|
||||
"@wdio/appium-service": "^9.27.1",
|
||||
"@wdio/cli": "^9.27.1",
|
||||
"@wdio/local-runner": "^9.27.1",
|
||||
"@wdio/mocha-framework": "^9.27.1",
|
||||
"@wdio/spec-reporter": "^9.27.1",
|
||||
"appium": "^3.4.2",
|
||||
"appium-uiautomator2-driver": "^7.2.3",
|
||||
"builtin-modules": "^5.2.0",
|
||||
"chai": "^6.2.2",
|
||||
"esbuild": "^0.27.4",
|
||||
"eslint": "^9.39.4",
|
||||
"esbuild": "^0.28.0",
|
||||
"eslint": "^10.3.0",
|
||||
"eslint-plugin-obsidianmd": "^0.3.0",
|
||||
"lodash.merge": "^4.6.2",
|
||||
"mocha": "^11.7.5",
|
||||
"npm-run-all": "^4.1.5",
|
||||
"obsidian": "latest",
|
||||
"obsidian-launcher": "^3.0.2",
|
||||
"obsidian-typings": "^5.18.0",
|
||||
"obsidian-typings": "^5.21.0",
|
||||
"tslib": "^2.8.1",
|
||||
"tsx": "^4.21.0",
|
||||
"typescript": "^5.9.3",
|
||||
"typescript-eslint": "^8.58.0",
|
||||
"typescript-eslint": "^8.59.3",
|
||||
"wdio-obsidian-reporter": "^3.0.2",
|
||||
"wdio-obsidian-service": "^3.0.2"
|
||||
},
|
||||
|
|
|
|||
42
src/main.ts
42
src/main.ts
|
|
@ -1,6 +1,6 @@
|
|||
import {
|
||||
Plugin, Workspace, WorkspaceLeaf, WorkspaceRoot, WorkspaceFloating, View, TFile, PaneType, WorkspaceTabs,
|
||||
WorkspaceItem, Platform, Keymap, Notice,
|
||||
WorkspaceItem, Platform, Keymap, Notice, App,
|
||||
} from 'obsidian';
|
||||
import * as monkeyAround from 'monkey-around';
|
||||
import {
|
||||
|
|
@ -49,7 +49,7 @@ function parseOverride(override?: string|boolean): [PaneType|false, Partial<Open
|
|||
} else {
|
||||
const [mode, ...rest] = override.split(":");
|
||||
const json = rest.join(":") || "{}";
|
||||
return [(mode || false) as PaneType|false, JSON.parse(json)];
|
||||
return [(mode || false) as PaneType|false, JSON.parse(json) as Partial<OpenTabSettingsPluginSettings>];
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -151,13 +151,14 @@ export default class OpenTabSettingsPlugin extends Plugin {
|
|||
}
|
||||
|
||||
registerMonkeyPatches() {
|
||||
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
||||
const plugin = this;
|
||||
|
||||
this.register(monkeyAround.around(Workspace.prototype, {
|
||||
/**
|
||||
* Patch getLeaf to open leaves in new tab by default, based on settings.
|
||||
*/
|
||||
getLeaf(oldMethod: any) {
|
||||
getLeaf(oldMethod) {
|
||||
return function(this: Workspace, openModeIn?: string|boolean, ...args) {
|
||||
const [openMode, override] = parseOverride(openModeIn);
|
||||
const settings = {...plugin.settings, ...override};
|
||||
|
|
@ -170,7 +171,7 @@ export default class OpenTabSettingsPlugin extends Plugin {
|
|||
} else if (!openMode) {
|
||||
leaf = plugin.getUnpinnedLeaf(true, settings);
|
||||
} else {
|
||||
leaf = oldMethod.call(this, openMode, ...args);
|
||||
leaf = (oldMethod as (...args: unknown[]) => WorkspaceLeaf).call(this, openMode, ...args);
|
||||
}
|
||||
|
||||
// we set these to be used in openFile so we can tell when to deduplicate files.
|
||||
|
|
@ -190,7 +191,7 @@ export default class OpenTabSettingsPlugin extends Plugin {
|
|||
* Note that as of 1.9.10, getUnpinnedLeaf takes an undocumented "focus" boolean. Obsidian uses this param
|
||||
* when using ctrl and arrow keys in the file explorer to open files.
|
||||
*/
|
||||
getUnpinnedLeaf(oldMethod: any) {
|
||||
getUnpinnedLeaf(oldMethod) {
|
||||
return function(this: Workspace, focus?: boolean) {
|
||||
if (plugin.settings.openInNewTab) {
|
||||
return this.getLeaf("tab");
|
||||
|
|
@ -203,10 +204,10 @@ export default class OpenTabSettingsPlugin extends Plugin {
|
|||
|
||||
// Patch openFile to deduplicate tabs
|
||||
this.register(monkeyAround.around(WorkspaceLeaf.prototype, {
|
||||
openFile(oldMethod: any) {
|
||||
openFile(oldMethod) {
|
||||
return async function(this: WorkspaceLeaf, file, openState, ...args) {
|
||||
// openFile doesn't return anything, but just in case that changes.
|
||||
let result: any;
|
||||
let result: void;
|
||||
let match: WorkspaceLeaf|undefined;
|
||||
|
||||
// these values are only valid immediately after creating a leaf. We clear them after openFile,
|
||||
|
|
@ -290,11 +291,11 @@ export default class OpenTabSettingsPlugin extends Plugin {
|
|||
// We could have used isModEvent to implement openInNewTab instead of getLeaf, but there's quite a few places
|
||||
// that call getLeaf without isModEvent, such as the graph view.
|
||||
this.register(monkeyAround.around(Keymap, {
|
||||
isModEvent(oldMethod: any) {
|
||||
return function(this: any, ...args) {
|
||||
isModEvent(oldMethod) {
|
||||
return function(this: unknown, ...args) {
|
||||
let result = oldMethod.call(this, ...args);
|
||||
if (result == "tab") {
|
||||
result = OVERRIDES[plugin.settings.modClickBehavior];
|
||||
result = OVERRIDES[plugin.settings.modClickBehavior] as boolean|PaneType;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
|
@ -303,7 +304,7 @@ export default class OpenTabSettingsPlugin extends Plugin {
|
|||
}
|
||||
|
||||
async loadSettings() {
|
||||
const dataFile = await this.loadData() ?? {};
|
||||
const dataFile = await this.loadData() as object ?? {};
|
||||
this.settings = Object.assign({}, DEFAULT_SETTINGS, dataFile);
|
||||
|
||||
if (Object.keys(dataFile).length == 0) {
|
||||
|
|
@ -356,10 +357,9 @@ export default class OpenTabSettingsPlugin extends Plugin {
|
|||
* @param focus Whether to focus the new tab. If undefined focus based on focusNewTab config
|
||||
*/
|
||||
private createNewLeaf(focus?: boolean, override: Partial<OpenTabSettingsPluginSettings> = {}) {
|
||||
const plugin = this;
|
||||
const workspace = plugin.app.workspace;
|
||||
focus = focus ?? plugin.app.vault.getConfig('focusNewTab') as boolean;
|
||||
const settings = {...plugin.settings, ...override};
|
||||
const workspace = this.app.workspace;
|
||||
focus = focus ?? this.app.vault.getConfig('focusNewTab') as boolean;
|
||||
const settings = {...this.settings, ...override};
|
||||
|
||||
const activeLeaf = workspace.getMostRecentLeaf();
|
||||
if (!activeLeaf) throw new Error("No tab group found.");
|
||||
|
|
@ -375,7 +375,7 @@ export default class OpenTabSettingsPlugin extends Plugin {
|
|||
let index: number|undefined;
|
||||
|
||||
if (settings.newTabTabGroupPlacement != "same" && !Platform.isPhone) {
|
||||
const tabGroups = plugin.getAllTabGroups(activeLeaf.getRoot());
|
||||
const tabGroups = this.getAllTabGroups(activeLeaf.getRoot());
|
||||
const otherTabGroup = tabGroups.filter(g => g !== activeTabGroup).at(-1);
|
||||
if (settings.newTabTabGroupPlacement == "opposite" && otherTabGroup) {
|
||||
group = otherTabGroup;
|
||||
|
|
@ -415,7 +415,7 @@ export default class OpenTabSettingsPlugin extends Plugin {
|
|||
if (isEmptyLeaf(leafToDisplace)) {
|
||||
newLeaf = leafToDisplace;
|
||||
} else {
|
||||
newLeaf = new (WorkspaceLeaf as any)(this.app);
|
||||
newLeaf = new (WorkspaceLeaf as new (app: App) => WorkspaceLeaf)(this.app);
|
||||
const currentTab = group.currentTab;
|
||||
// If new tab is inserted before the currently tab in a group, and we aren't setting the new tab active, we
|
||||
// need to update the selected tab so that group.currentTab index still points to the original active tab
|
||||
|
|
@ -437,10 +437,10 @@ export default class OpenTabSettingsPlugin extends Plugin {
|
|||
* e.g. when the active tab is pinned.
|
||||
*/
|
||||
private getUnpinnedLeaf(focus = true, override: Partial<OpenTabSettingsPluginSettings> = {}) {
|
||||
const plugin = this;
|
||||
const workspace = plugin.app.workspace;
|
||||
const settings = {...plugin.settings, ...override};
|
||||
const workspace = this.app.workspace;
|
||||
const settings = {...this.settings, ...override};
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-deprecated
|
||||
const activeLeaf = workspace.activeLeaf;
|
||||
if (activeLeaf?.canNavigate()) {
|
||||
return activeLeaf;
|
||||
|
|
@ -463,7 +463,7 @@ export default class OpenTabSettingsPlugin extends Plugin {
|
|||
});
|
||||
|
||||
if (!leaf) {
|
||||
leaf = plugin.createNewLeaf(focus, settings);
|
||||
leaf = this.createNewLeaf(focus, settings);
|
||||
} else if (focus) {
|
||||
workspace.setActiveLeaf(leaf);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -141,7 +141,7 @@ export class OpenTabSettingsPluginSettingTab extends PluginSettingTab {
|
|||
|
||||
new Setting(this.containerEl)
|
||||
.setName('Mod click behavior')
|
||||
.setDesc('On Ctrl/Cmd/middle click open links...')
|
||||
.setDesc('On ctrl/cmd/middle click open links...')
|
||||
.addDropdown(dropdown => {
|
||||
dropdown.addOption("tab", MOD_CLICK_BEHAVIOR['tab']);
|
||||
if (this.plugin.settings.openInNewTab) {
|
||||
|
|
@ -154,7 +154,6 @@ export class OpenTabSettingsPluginSettingTab extends PluginSettingTab {
|
|||
dropdown
|
||||
.setValue(this.plugin.settings.modClickBehavior)
|
||||
.onChange(async value => {
|
||||
console.log("modClickBehavior onChange")
|
||||
await this.plugin.updateSettings({
|
||||
modClickBehavior: value as keyof typeof MOD_CLICK_BEHAVIOR,
|
||||
});
|
||||
|
|
|
|||
2
src/types.d.ts
vendored
2
src/types.d.ts
vendored
|
|
@ -1,4 +1,4 @@
|
|||
import { PaneType, WorkspaceTabs, WorkspaceMobileDrawer } from 'obsidian';
|
||||
import { PaneType, WorkspaceTabs, WorkspaceMobileDrawer, WorkspaceItem } from 'obsidian';
|
||||
import { OpenTabSettingsPluginSettings } from './settings';
|
||||
|
||||
declare module "obsidian" {
|
||||
|
|
|
|||
|
|
@ -75,9 +75,11 @@ export const config: WebdriverIO.Config = {
|
|||
mochaOpts: {
|
||||
ui: 'bdd',
|
||||
timeout: 60 * 1000,
|
||||
retries: 4,
|
||||
retries: 2,
|
||||
bail: true,
|
||||
},
|
||||
specFileRetries: 2,
|
||||
|
||||
waitforInterval: 250,
|
||||
waitforTimeout: 5 * 1000,
|
||||
logLevel: "warn",
|
||||
|
|
|
|||
Loading…
Reference in a new issue