diff --git a/README.md b/README.md index 7559c98..ceba9dc 100644 --- a/README.md +++ b/README.md @@ -38,17 +38,25 @@ Import external code files in your Obsidian notes using `@import` syntax (compat ### Parameters -| Parameter | Description | Example | -|-----------|-------------|---------| -| `line_begin` | Start line (0-based index) | `line_begin=4` starts from 5th line | -| `line_end` | End line (exclusive, supports negative) | `line_end=14` or `line_end=-1` | +| Parameter | Description (0-based) | Description (1-based) | +|-----------|----------------------|----------------------| +| `line_begin` | Start line, 0-based index | Start line, 1-based index | +| `line_end` | End line, exclusive (supports negative) | End line, inclusive (supports negative) | ### Line Index Examples +**0-based mode** (default, Foam-compatible): + - `{line_begin=0 line_end=10}` → Lines 1-10 (indices 0-9) - `{line_begin=5}` → From line 6 to end - `{line_end=-2}` → From start, excluding last 2 lines +**1-based mode:** + +- `{line_begin=1 line_end=10}` → Lines 1-10 +- `{line_begin=5}` → From line 5 to end +- `{line_end=-2}` → From start, excluding last 2 lines + ## Installation ### From Community Plugins @@ -85,6 +93,7 @@ In your markdown file: |---------|-------------|---------| | Show file name | Display filename header above code block | On | | Wrap code | Wrap long lines instead of horizontal scrolling | Off | +| Line number base | 0-based (Foam-compatible) or 1-based indexing for `line_begin`/`line_end` | 0-based | ## License diff --git a/src/main.ts b/src/main.ts index c058139..3a5c321 100644 --- a/src/main.ts +++ b/src/main.ts @@ -122,6 +122,7 @@ export default class CodeImportPlugin extends Plugin { { showFileName: this.settings.showFileName, wrapCode: this.settings.wrapCode, + lineNumberBase: this.settings.lineNumberBase, }, this ); diff --git a/src/renderer.ts b/src/renderer.ts index e20848e..bf29363 100644 --- a/src/renderer.ts +++ b/src/renderer.ts @@ -1,9 +1,11 @@ import { MarkdownRenderer, App, Component } from 'obsidian'; import { ImportDirective, extractLines, getFileExtension, extensionToLanguage } from './parser'; +import type { LineNumberBase } from './settings'; export interface RenderOptions { showFileName: boolean; wrapCode: boolean; + lineNumberBase: LineNumberBase; } /** @@ -56,8 +58,21 @@ export async function renderCodeBlock( const ext = getFileExtension(directive.filePath); const language = extensionToLanguage(ext); + // Convert 1-based line numbers to 0-based for extractLines + let internalBegin = directive.lineBegin; + let internalEnd = directive.lineEnd; + + if (options.lineNumberBase === '1') { + // Convert 1-based begin to 0-based: line 1 → index 0 + if (internalBegin !== undefined) { + internalBegin = internalBegin - 1; + } + // 1-based inclusive end N == 0-based exclusive end N, so no adjustment needed + // Negative values remain unchanged (they count from the end) + } + // Extract lines if specified - const extractedContent = extractLines(content, directive.lineBegin, directive.lineEnd); + const extractedContent = extractLines(content, internalBegin, internalEnd); // Create wrapper for visual styling const wrapper = document.createElement('div'); @@ -73,19 +88,24 @@ export async function renderCodeBlock( header.appendChild(fileName); - // Add line range info if specified (display as 1-based for readability) + // Add line range info if specified if (directive.lineBegin !== undefined || directive.lineEnd !== undefined) { const lineInfo = document.createElement('span'); lineInfo.className = 'code-import-line-info'; const parts: string[] = []; if (directive.lineBegin !== undefined) { - // Convert 0-based to 1-based for display - parts.push(`L${directive.lineBegin + 1}`); + if (options.lineNumberBase === '1') { + // Already 1-based, display as-is + parts.push(`L${directive.lineBegin}`); + } else { + // Convert 0-based to 1-based for display + parts.push(`L${directive.lineBegin + 1}`); + } } if (directive.lineEnd !== undefined) { // Negative values show as-is (e.g., -1 means "exclude last") - // Positive values: exclusive end in 0-based equals last line number in 1-based + // Positive values: display as-is for both modes (0-based exclusive end == 1-based inclusive end) parts.push(`L${directive.lineEnd}`); } lineInfo.textContent = parts.join('-'); diff --git a/src/settings.ts b/src/settings.ts index 32dd297..a2d9693 100644 --- a/src/settings.ts +++ b/src/settings.ts @@ -1,14 +1,18 @@ import { App, PluginSettingTab, Setting } from 'obsidian'; import type CodeImportPlugin from './main'; +export type LineNumberBase = '0' | '1'; + export interface CodeImportSettings { showFileName: boolean; wrapCode: boolean; + lineNumberBase: LineNumberBase; } export const DEFAULT_SETTINGS: CodeImportSettings = { showFileName: true, wrapCode: false, + lineNumberBase: '0', }; export class CodeImportSettingTab extends PluginSettingTab { @@ -47,5 +51,19 @@ export class CodeImportSettingTab extends PluginSettingTab { await this.plugin.saveSettings(); }) ); + + new Setting(containerEl) + .setName('Line number base') + .setDesc('Whether line_begin and line_end use 0-based or 1-based indexing') + .addDropdown((dropdown) => + dropdown + .addOption('0', '0-based (default)') + .addOption('1', '1-based') + .setValue(this.plugin.settings.lineNumberBase) + .onChange(async (value) => { + this.plugin.settings.lineNumberBase = value as LineNumberBase; + await this.plugin.saveSettings(); + }) + ); } }