Files
infio-copilot-dev/src/utils/obsidian.ts
2025-01-07 14:18:18 +08:00

128 lines
3.0 KiB
TypeScript

import { App, Editor, MarkdownView, TFile, TFolder, Vault, WorkspaceLeaf } from 'obsidian'
import { MentionableBlockData } from '../types/mentionable'
export async function readTFileContent(
file: TFile,
vault: Vault,
): Promise<string> {
return await vault.cachedRead(file)
}
export async function readMultipleTFiles(
files: TFile[],
vault: Vault,
): Promise<string[]> {
// Read files in parallel
const readPromises = files.map((file) => readTFileContent(file, vault))
return await Promise.all(readPromises)
}
export function getNestedFiles(folder: TFolder, vault: Vault): TFile[] {
const files: TFile[] = []
for (const child of folder.children) {
if (child instanceof TFile) {
files.push(child)
} else if (child instanceof TFolder) {
files.push(...getNestedFiles(child, vault))
}
}
return files
}
export async function getMentionableBlockData(
editor: Editor,
view: MarkdownView,
): Promise<MentionableBlockData | null> {
const file = view.file
if (!file) return null
const selection = editor.getSelection()
if (!selection) return null
const startLine = editor.getCursor('from').line
const endLine = editor.getCursor('to').line
const selectionContent = editor
.getValue()
.split('\n')
.slice(startLine, endLine + 1)
.join('\n')
return {
content: selectionContent,
file,
startLine: startLine + 1, // +1 because startLine is 0-indexed
endLine: endLine + 1, // +1 because startLine is 0-indexed
}
}
export function getOpenFiles(app: App): TFile[] {
try {
const leaves = app.workspace.getLeavesOfType('markdown')
return leaves
.filter((v): v is WorkspaceLeaf & { view: MarkdownView & { file: TFile } } =>
v.view instanceof MarkdownView && !!v.view.file
)
.map((v) => v.view.file)
} catch (e) {
return []
}
}
export function calculateFileDistance(
file1: TFile | TFolder,
file2: TFile | TFolder,
): number | null {
const path1 = file1.path.split('/')
const path2 = file2.path.split('/')
// Check if files are in different top-level folders
if (path1[0] !== path2[0]) {
return null
}
let distance = 0
let i = 0
// Find the common ancestor
while (i < path1.length && i < path2.length && path1[i] === path2[i]) {
i++
}
// Calculate distance from common ancestor to each file
distance += path1.length - i
distance += path2.length - i
return distance
}
export function openMarkdownFile(
app: App,
filePath: string,
startLine?: number,
) {
const file = app.vault.getFileByPath(filePath)
if (!file) return
const existingLeaf = app.workspace
.getLeavesOfType('markdown')
.find(
(leaf) =>
leaf.view instanceof MarkdownView && leaf.view.file?.path === file.path,
)
if (existingLeaf) {
app.workspace.setActiveLeaf(existingLeaf, { focus: true })
if (startLine && existingLeaf.view instanceof MarkdownView) {
existingLeaf.view.setEphemeralState({ line: startLine - 1 }) // -1 because line is 0-indexed
}
} else {
const leaf = app.workspace.getLeaf('tab')
leaf.openFile(file, {
eState: startLine ? { line: startLine - 1 } : undefined, // -1 because line is 0-indexed
})
}
}