commit fe8a832d744b56d4488dba17826e0bc4b9a0ac3b Author: Aaron Manning Date: Sun Jul 9 07:47:52 2023 +1000 initial commit diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json new file mode 100644 index 0000000..b9b06ce --- /dev/null +++ b/.config/dotnet-tools.json @@ -0,0 +1,12 @@ +{ + "version": 1, + "isRoot": true, + "tools": { + "fable": { + "version": "4.1.4", + "commands": [ + "fable" + ] + } + } +} \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..6ad00fa --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +bin/ +obj/ +out/ +fable_modules/ + +*.fs.js diff --git a/Obsidian.fs b/Obsidian.fs new file mode 100644 index 0000000..fe9a8c3 --- /dev/null +++ b/Obsidian.fs @@ -0,0 +1,1700 @@ +module rec Obsidian +open System +open Fable.Core +open Fable.Core.JS +open Browser.Types + +open System.Drawing + +type Array<'T> = System.Collections.Generic.IList<'T> +type Function = System.Action +type RegExp = System.Text.RegularExpressions.Regex + + +type [] IExports = + abstract isBoolean: obj: obj option -> bool + abstract fish: selector: string -> HTMLElement option + abstract fishAll: selector: string -> ResizeArray + abstract createDiv: ?o: U2 * ?callback: (HTMLDivElement -> unit) -> HTMLDivElement + abstract createSpan: ?o: U2 * ?callback: (HTMLSpanElement -> unit) -> HTMLSpanElement + abstract createFragment: ?callback: (DocumentFragment -> unit) -> DocumentFragment + abstract ajax: options: AjaxOptions -> unit + abstract ajaxPromise: options: AjaxOptions -> Promise + abstract ready: fn: (unit -> obj option) -> unit + abstract AbstractTextComponent: AbstractTextComponentStatic + /// Adds an icon to the library + /// - the icon ID + /// - the content of the SVG, without the . Must fit viewBox="0 0 100 100". + abstract addIcon: iconId: string * svgContent: string -> unit + abstract App: AppStatic + abstract BaseComponent: BaseComponentStatic + abstract ButtonComponent: ButtonComponentStatic + abstract Component: ComponentStatic + abstract Constructor: ConstructorStatic + /// A standard debounce function. + /// - The function to call. + /// - The timeout to wait. + /// - Whether to reset the timeout when the debouncer is called again. + abstract debounce: cb: (obj -> obj option) * ?timeout: float * ?resetTimer: bool -> Debouncer<'T> + abstract DropdownComponent: DropdownComponentStatic + abstract EditableFileView: EditableFileViewStatic + abstract Editor: EditorStatic + abstract EditorSuggest: EditorSuggestStatic + abstract Events: EventsStatic + abstract ExtraButtonComponent: ExtraButtonComponentStatic + abstract FileManager: FileManagerStatic + abstract FileSystemAdapter: FileSystemAdapterStatic + abstract FileView: FileViewStatic + /// Flush the MathJax stylesheet. + abstract finishRenderMath: unit -> Promise + abstract fuzzySearch: q: PreparedQuery * text: string -> SearchResult option + abstract FuzzySuggestModal: FuzzySuggestModalStatic + abstract getAllTags: cache: CachedMetadata -> ResizeArray option + abstract getLinkpath: linktext: string -> string + abstract HoverPopover: HoverPopoverStatic + /// Converts HTML to Markdown using Turndown Service. + abstract htmlToMarkdown: html: string -> string + abstract ItemView: ItemViewStatic + /// Iterate links and embeds. If callback returns true, the iteration process will be interrupted. + abstract iterateCacheRefs: cache: CachedMetadata * cb: (ReferenceCache -> U2) -> bool + abstract iterateRefs: refs: ResizeArray * cb: (ReferenceCache -> U2) -> bool + abstract Keymap: KeymapStatic + /// Load MathJax. + abstract loadMathJax: unit -> Promise + /// Load Mermaid and return a promise to the global mermaid object. + /// Can also use `mermaid` after this promise resolves to get the same reference. + abstract loadMermaid: unit -> Promise + /// Load PDF.js and return a promise to the global pdfjsLib object. + /// Can also use `window.pdfjsLib` after this promise resolves to get the same reference. + abstract loadPdfJs: unit -> Promise + /// Load Prism.js and return a promise to the global Prism object. + /// Can also use `Prism` after this promise resolves to get the same reference. + abstract loadPrism: unit -> Promise + abstract MarkdownEditView: MarkdownEditViewStatic + abstract MarkdownPreviewRenderer: MarkdownPreviewRendererStatic + abstract MarkdownPreviewView: MarkdownPreviewViewStatic + abstract MarkdownRenderChild: MarkdownRenderChildStatic + abstract MarkdownRenderer: MarkdownRendererStatic + abstract MarkdownSourceView: MarkdownSourceViewStatic + abstract MarkdownView: MarkdownViewStatic + abstract Menu: MenuStatic + abstract MenuItem: MenuItemStatic + abstract MetadataCache: MetadataCacheStatic + abstract Modal: ModalStatic + abstract MomentFormatComponent: MomentFormatComponentStatic + abstract normalizePath: path: string -> string + abstract Notice: NoticeStatic + abstract parseFrontMatterAliases: frontmatter: obj option option -> ResizeArray option + abstract parseFrontMatterEntry: frontmatter: obj option option * key: U2 -> obj option option + abstract parseFrontMatterStringArray: frontmatter: obj option option * key: U2 * ?nospaces: bool -> ResizeArray option + abstract parseFrontMatterTags: frontmatter: obj option option -> ResizeArray option + abstract parseLinktext: linktext: string -> ParseLinktextReturn + abstract parseYaml: yaml: string -> obj option + abstract Plugin: PluginStatic + abstract PluginSettingTab: PluginSettingTabStatic + abstract PopoverSuggest: PopoverSuggestStatic + /// Construct a fuzzy search callback that runs on a target string. + /// Performance may be an issue if you are running the search for more than a few thousand times. + /// If performance is a problem, consider using `prepareSimpleSearch` instead. + /// - the fuzzy query. + abstract prepareFuzzySearch: query: string -> (string -> SearchResult option) + abstract prepareQuery: query: string -> PreparedQuery + /// Construct a simple search callback that runs on a target string. + /// - the space-separated words + abstract prepareSimpleSearch: query: string -> (string -> SearchResult option) + abstract renderMatches: el: U2 * text: string * matches: SearchMatches option * ?offset: float -> unit + /// Render some LaTeX math using the MathJax engine. Returns an HTMLElement. + /// Requires calling `finishRenderMath` when rendering is all done to flush the MathJax stylesheet. + abstract renderMath: source: string * display: bool -> HTMLElement + abstract renderResults: el: HTMLElement * text: string * result: SearchResult * ?offset: float -> unit + /// Similar to `fetch()`, request a URL using HTTP/HTTPS, without any CORS restrictions. + /// Returns the text value of the response. + abstract request: request: RequestUrlParam -> Promise + /// Similar to `fetch()`, request a URL using HTTP/HTTPS, without any CORS restrictions. + abstract requestUrl: request: RequestUrlParam -> Promise + /// Returns true if the API version is equal or higher than the requested version. + /// Use this to limit functionality that require specific API versions to avoid + /// crashing on older Obsidian builds. + abstract requireApiVersion: version: string -> bool + abstract resolveSubpath: cache: CachedMetadata * subpath: string -> U2 + abstract sanitizeHTMLToDom: html: string -> DocumentFragment + abstract Scope: ScopeStatic + abstract SearchComponent: SearchComponentStatic + /// - the HTML element to insert the icon + /// - the icon ID + /// - the pixel size for width and height, defaults to 16 + abstract setIcon: parent: HTMLElement * iconId: string * ?size: float -> unit + abstract Setting: SettingStatic + abstract SettingTab: SettingTabStatic + abstract SliderComponent: SliderComponentStatic + abstract sortSearchResults: results: ResizeArray -> unit + abstract stringifyYaml: obj: obj option -> string + /// This function normalizes headings for link matching by stripping out special characters and shrinking consecutive spaces. + abstract stripHeading: heading: string -> string + abstract SuggestModal: SuggestModalStatic + abstract TAbstractFile: TAbstractFileStatic + abstract Tasks: TasksStatic + abstract TextAreaComponent: TextAreaComponentStatic + abstract TextComponent: TextComponentStatic + abstract TextFileView: TextFileViewStatic + abstract TFile: TFileStatic + abstract TFolder: TFolderStatic + abstract ToggleComponent: ToggleComponentStatic + abstract ValueComponent: ValueComponentStatic + abstract Vault: VaultStatic + abstract View: ViewStatic + abstract Workspace: WorkspaceStatic + abstract WorkspaceItem: WorkspaceItemStatic + abstract WorkspaceLeaf: WorkspaceLeafStatic + abstract WorkspaceMobileDrawer: WorkspaceMobileDrawerStatic + abstract WorkspaceParent: WorkspaceParentStatic + abstract WorkspaceRibbon: WorkspaceRibbonStatic + abstract WorkspaceSidedock: WorkspaceSidedockStatic + abstract WorkspaceSplit: WorkspaceSplitStatic + abstract WorkspaceTabs: WorkspaceTabsStatic + +type [] ParseLinktextReturn = + abstract path: string with get, set + abstract subpath: string with get, set + + +type [] ObjectConstructor = + + abstract each: ``object``: ObjectConstructorEachObject * callback: ('T -> string -> U2) * ?context: obj -> bool + abstract assign: target: obj option * [] sources: obj option -> obj option + abstract entries: obj: obj option -> ResizeArray + +type [] ObjectConstructorEachObject = + [] abstract Item: key: string -> obj with get, set + +type [] Math = + abstract clamp: value: float * min: float * max: float -> float + abstract square: value: float -> float + +type [] StringConstructor = + abstract isString: obj: obj option -> bool + +type [] String = + abstract contains: target: string -> bool + abstract startsWith: searchString: string * ?position: float -> bool + abstract endsWith: target: string * ?length: float -> bool + abstract format: [] args: ResizeArray -> string + +type [] NumberConstructor = + abstract isNumber: obj: obj option -> bool + +type [] Window = + inherit EventTarget + inherit GlobalEventHandlers + inherit WindowLocalStorage + inherit WindowSessionStorage + abstract isBoolean: obj: obj option -> bool + abstract fish: selector: string -> HTMLElement option + abstract fishAll: selector: string -> ResizeArray + abstract ElementList: obj option with get, set + +type [] Element = + inherit Node + abstract getText: unit -> string + abstract setText: ``val``: U2 -> unit + abstract addClass: [] classes: ResizeArray -> unit + abstract addClasses: classes: ResizeArray -> unit + abstract removeClass: [] classes: ResizeArray -> unit + abstract removeClasses: classes: ResizeArray -> unit + abstract toggleClass: classes: U2> * value: bool -> unit + abstract hasClass: cls: string -> bool + abstract setAttr: qualifiedName: string * value: U3 option -> unit + abstract setAttrs: obj: ElementSetAttrsObj -> unit + abstract getAttr: qualifiedName: string -> string option + abstract matchParent: selector: string * ?lastParent: Element -> Element option + abstract find: selector: string -> Element option + abstract findAll: selector: string -> ResizeArray + abstract findAllSelf: selector: string -> ResizeArray + +type [] ElementSetAttrsObj = + [] abstract Item: key: string -> U3 option with get, set + +type [] Node = + abstract detach: unit -> unit + abstract empty: unit -> unit + abstract insertAfter: other: Node -> unit + abstract indexOf: other: Node -> float + abstract setChildrenInPlace: children: ResizeArray -> unit + abstract appendText: ``val``: string -> unit + /// Create an element and append it to this node. + abstract createEl: tag: 'K * ?o: U2 * ?callback: (obj -> unit) -> obj + abstract createDiv: ?o: U2 * ?callback: (HTMLDivElement -> unit) -> HTMLDivElement + abstract createSpan: ?o: U2 * ?callback: (HTMLSpanElement -> unit) -> HTMLSpanElement + +type [] HTMLElement = + inherit Element + abstract show: unit -> unit + abstract hide: unit -> unit + abstract toggle: show: bool -> unit + abstract toggleVisibility: visible: bool -> unit + /// Returns whether this element is shown, when the element is attached to the DOM and + /// none of the parent and ancestor elements are hidden with `display: none`. + /// + /// Exception: Does not work on and , or on elements with `position: fixed`. + abstract isShown: unit -> bool + abstract find: selector: string -> HTMLElement + abstract findAll: selector: string -> ResizeArray + abstract findAllSelf: selector: string -> ResizeArray + abstract _EVENTS: obj option with get, set + abstract on: this: HTMLElement * ``type``: 'K * selector: string * listener: (HTMLElement -> obj -> HTMLElement -> obj option) * ?options: U2 -> unit + abstract off: this: HTMLElement * ``type``: 'K * selector: string * listener: (HTMLElement -> obj -> HTMLElement -> obj option) * ?options: U2 -> unit + abstract onClickEvent: this: HTMLElement * listener: (HTMLElement -> MouseEvent -> obj option) * ?options: U2 -> unit + /// - the callback to call when this node is inserted into the DOM. + /// - if true, this will only fire once and then unhook itself. + abstract onNodeInserted: this: HTMLElement * listener: (unit -> obj option) * ?once: bool -> (unit -> unit) + abstract trigger: eventType: string -> unit + +type [] DomElementInfo = + /// The class to be assigned. Can be a space-separated string or an array of strings. + abstract cls: U2> option with get, set + /// The textContent to be assigned. + abstract text: U2 option with get, set + /// HTML attributes to be added. + abstract attr: DomElementInfoAttr option with get, set + /// HTML title (for hover tooltip). + abstract title: string option with get, set + /// The parent element to be assigned to. + abstract parent: Node option with get, set + abstract value: string option with get, set + abstract ``type``: string option with get, set + abstract prepend: bool option with get, set + abstract href: string option with get, set + +type [] Document = + abstract _EVENTS: obj option with get, set + abstract on: this: Document * ``type``: 'K * selector: string * listener: (Document -> obj -> HTMLElement -> obj option) * ?options: U2 -> unit + abstract off: this: Document * ``type``: 'K * selector: string * listener: (Document -> obj -> HTMLElement -> obj option) * ?options: U2 -> unit + +type [] EventListenerInfo = + abstract selector: string with get, set + abstract listener: Function with get, set + abstract options: U2 option with get, set + abstract callback: Function with get, set + +type [] AjaxOptions = + abstract ``method``: AjaxOptionsMethod option with get, set + abstract url: string with get, set + abstract success: (obj option -> XMLHttpRequest -> obj option) option with get, set + abstract error: (obj option -> XMLHttpRequest -> obj option) option with get, set + abstract data: U3 option with get, set + abstract headers: obj option with get, set + abstract withCredentials: bool option with get, set + abstract req: XMLHttpRequest option with get, set + +type [] AbstractTextComponent<'T> = + inherit ValueComponent + abstract inputEl: 'T with get, set + abstract setDisabled: disabled: bool -> AbstractTextComponent<'T> + abstract getValue: unit -> string + abstract setValue: value: string -> AbstractTextComponent<'T> + abstract setPlaceholder: placeholder: string -> AbstractTextComponent<'T> + abstract onChanged: unit -> unit + abstract onChange: callback: (string -> obj option) -> AbstractTextComponent<'T> + +type [] AbstractTextComponentStatic = + [] abstract Create: inputEl: 'T -> AbstractTextComponent<'T> + +type [] App = + abstract keymap: Keymap with get, set + abstract scope: Scope with get, set + abstract workspace: Workspace with get, set + abstract vault: Vault with get, set + abstract metadataCache: MetadataCache with get, set + abstract fileManager: FileManager with get, set + /// The last known user interaction event, to help commands find out what modifier keys are pressed. + abstract lastEvent: UserEvent option with get, set + +type [] AppStatic = + [] abstract Create: unit -> App + +type [] BaseComponent = + abstract disabled: bool with get, set + /// Facilitates chaining + abstract ``then``: cb: (BaseComponent -> obj option) -> BaseComponent + abstract setDisabled: disabled: bool -> BaseComponent + +type [] BaseComponentStatic = + [] abstract Create: unit -> BaseComponent + +type [] BlockCache = + inherit CacheItem + abstract id: string with get, set + +type [] BlockSubpathResult = + inherit SubpathResult + abstract ``type``: string with get, set + abstract block: BlockCache with get, set + abstract list: ListItemCache option with get, set + +type [] ButtonComponent = + inherit BaseComponent + abstract buttonEl: HTMLButtonElement with get, set + abstract setDisabled: disabled: bool -> ButtonComponent + abstract setCta: unit -> ButtonComponent + abstract removeCta: unit -> ButtonComponent + abstract setWarning: unit -> ButtonComponent + abstract setTooltip: tooltip: string -> ButtonComponent + abstract setButtonText: name: string -> ButtonComponent + abstract setIcon: icon: string -> ButtonComponent + abstract setClass: cls: string -> ButtonComponent + abstract onClick: callback: (MouseEvent -> obj option) -> ButtonComponent + +type [] ButtonComponentStatic = + [] abstract Create: containerEl: HTMLElement -> ButtonComponent + +type [] CachedMetadata = + abstract links: ResizeArray option with get, set + abstract embeds: ResizeArray option with get, set + abstract tags: ResizeArray option with get, set + abstract headings: ResizeArray option with get, set + /// Sections are root level markdown blocks, which can be used to divide the document up. + abstract sections: ResizeArray option with get, set + abstract listItems: ResizeArray option with get, set + abstract frontmatter: FrontMatterCache option with get, set + abstract blocks: obj option with get, set + +type [] CacheItem = + abstract position: Pos with get, set + +type [] CloseableComponent = + abstract close: unit -> obj option + +type [] Command = + /// Globally unique ID to identify this command. + abstract id: string with get, set + /// Human friendly name for searching. + abstract name: string with get, set + /// Icon ID to be used in the toolbar. + abstract icon: string option with get, set + abstract mobileOnly: bool option with get, set + /// Simple callback, triggered globally. + abstract callback: (unit -> obj option) option with get, set + /// Complex callback, overrides the simple callback. + /// Used to "check" whether your command can be performed in the current circumstances. + /// For example, if your command requires the active focused pane to be a MarkdownSourceView, then + /// you should only return true if the condition is satisfied. Returning false or undefined causes + /// the command to be hidden from the command palette. + abstract checkCallback: (bool -> U2) option with get, set + /// A command callback that is only triggered when the user is in an editor. + /// Overrides `callback` and `checkCallback` + abstract editorCallback: (Editor -> MarkdownView -> obj option) option with get, set + /// A command callback that is only triggered when the user is in an editor. + /// Overrides `editorCallback`, `callback` and `checkCallback` + abstract editorCheckCallback: (bool -> Editor -> MarkdownView -> U2) option with get, set + /// Sets the default hotkey. It is recommended for plugins to avoid setting default hotkeys if possible, + /// to avoid conflicting hotkeys with one that's set by the user, even though customized hotkeys have higher priority. + abstract hotkeys: ResizeArray option with get, set + +type [] Component = + /// Load this component and its children + abstract load: unit -> unit + /// Override this to load your component + abstract onload: unit -> unit + /// Unload this component and its children + abstract unload: unit -> unit + /// Override this to unload your component + abstract onunload: unit -> unit + /// Adds a child component, loading it if this component is loaded + abstract addChild: ``component``: 'T -> 'T + /// Removes a child component, unloading it + abstract removeChild: ``component``: 'T -> 'T + /// Registers a callback to be called when unloading + abstract register: cb: (unit -> obj option) -> unit + /// Registers an event to be detached when unloading + abstract registerEvent: eventRef: EventRef -> unit + /// Registers an DOM event to be detached when unloading + abstract registerDomEvent: el: HTMLElement * ``type``: 'K * callback: (HTMLElement -> obj -> obj option) -> unit + /// Registers an key event to be detached when unloading + abstract registerScopeEvent: keyHandler: KeymapEventHandler -> unit + /// Registers an interval (from setInterval) to be cancelled when unloading + /// Use {@link window.setInterval} instead of {@link setInterval} to avoid TypeScript confusing between NodeJS vs Browser API + abstract registerInterval: id: float -> float + +type [] ComponentStatic = + [] abstract Create: unit -> Component + +type [] Constructor<'T> = + interface end + +type [] ConstructorStatic = + [] abstract Create: [] args: ResizeArray -> Constructor<'T> + +type [] DataAdapter = + abstract getName: unit -> string + abstract exists: normalizedPath: string * ?sensitive: bool -> Promise + abstract stat: normalizedPath: string -> Promise + abstract list: normalizedPath: string -> Promise + abstract read: normalizedPath: string -> Promise + abstract readBinary: normalizedPath: string -> Promise + abstract write: normalizedPath: string * data: string * ?options: DataWriteOptions -> Promise + abstract writeBinary: normalizedPath: string * data: ArrayBuffer * ?options: DataWriteOptions -> Promise + abstract append: normalizedPath: string * data: string * ?options: DataWriteOptions -> Promise + abstract getResourcePath: normalizedPath: string -> string + abstract mkdir: normalizedPath: string -> Promise + abstract trashSystem: normalizedPath: string -> Promise + abstract trashLocal: normalizedPath: string -> Promise + abstract rmdir: normalizedPath: string * recursive: bool -> Promise + abstract remove: normalizedPath: string -> Promise + abstract rename: normalizedPath: string * normalizedNewPath: string -> Promise + abstract copy: normalizedPath: string * normalizedNewPath: string -> Promise + +type [] DataWriteOptions = + abstract ctime: float option with get, set + abstract mtime: float option with get, set + +type [] Debouncer<'T> = + [] abstract Invoke: [] args: obj -> unit + abstract cancel: unit -> Debouncer<'T> + +type [] DropdownComponent = + inherit ValueComponent + abstract selectEl: HTMLSelectElement with get, set + abstract setDisabled: disabled: bool -> DropdownComponent + abstract addOption: value: string * display: string -> DropdownComponent + abstract addOptions: options: obj -> DropdownComponent + abstract getValue: unit -> string + abstract setValue: value: string -> DropdownComponent + abstract onChange: callback: (string -> obj option) -> DropdownComponent + +type [] DropdownComponentStatic = + [] abstract Create: containerEl: HTMLElement -> DropdownComponent + +type [] EditableFileView = + inherit FileView + +type [] EditableFileViewStatic = + [] abstract Create: unit -> EditableFileView + +/// A common interface that bridges the gap between CodeMirror 5 and CodeMirror 6. +type [] Editor = + abstract getDoc: unit -> Editor + abstract refresh: unit -> unit + abstract getValue: unit -> string + abstract setValue: content: string -> unit + /// Get the text at line (0-indexed) + abstract getLine: line: float -> string + abstract setLine: n: float * text: string -> unit + /// Gets the number of lines in the document + abstract lineCount: unit -> float + abstract lastLine: unit -> float + abstract getSelection: unit -> string + abstract somethingSelected: unit -> bool + abstract getRange: from: EditorPosition * ``to``: EditorPosition -> string + abstract replaceSelection: replacement: string * ?origin: string -> unit + abstract replaceRange: replacement: string * from: EditorPosition * ?``to``: EditorPosition * ?origin: string -> unit + abstract getCursor: ?string: EditorGetCursorString -> EditorPosition + abstract listSelections: unit -> ResizeArray + abstract setCursor: pos: U2 * ?ch: float -> unit + abstract setSelection: anchor: EditorPosition * ?head: EditorPosition -> unit + abstract setSelections: ranges: ResizeArray * ?main: float -> unit + abstract focus: unit -> unit + abstract blur: unit -> unit + abstract hasFocus: unit -> bool + abstract getScrollInfo: unit -> EditorGetScrollInfoReturn + abstract scrollTo: ?x: float * ?y: float -> unit + abstract scrollIntoView: range: EditorRange * ?center: bool -> unit + abstract undo: unit -> unit + abstract redo: unit -> unit + abstract exec: command: EditorCommandName -> unit + abstract transaction: tx: EditorTransaction * ?origin: string -> unit + abstract wordAt: pos: EditorPosition -> EditorRange option + abstract posToOffset: pos: EditorPosition -> float + abstract offsetToPos: offset: float -> EditorPosition + abstract processLines: read: (float -> string -> 'T option) * write: (float -> string -> 'T option -> U2) * ?ignoreEmpty: bool -> unit + +type [] [] EditorGetCursorString = + | From + | To + | Head + | Anchor + +type [] EditorGetScrollInfoReturn = + abstract top: float with get, set + abstract left: float with get, set + +/// A common interface that bridges the gap between CodeMirror 5 and CodeMirror 6. +type [] EditorStatic = + [] abstract Create: unit -> Editor + +type [] EditorChange = + inherit EditorRangeOrCaret + abstract text: string with get, set + +type [] [] EditorCommandName = + | GoUp + | GoDown + | GoLeft + | GoRight + | GoStart + | GoEnd + | IndentMore + | IndentLess + | NewlineAndIndent + | SwapLineUp + | SwapLineDown + | DeleteLine + | ToggleFold + | FoldAll + | UnfoldAll + +type [] EditorPosition = + abstract line: float with get, set + abstract ch: float with get, set + +type [] EditorRange = + abstract from: EditorPosition with get, set + abstract ``to``: EditorPosition with get, set + +type [] EditorRangeOrCaret = + abstract from: EditorPosition with get, set + abstract ``to``: EditorPosition option with get, set + +type [] EditorSelection = + abstract anchor: EditorPosition with get, set + abstract head: EditorPosition with get, set + +type [] EditorSelectionOrCaret = + abstract anchor: EditorPosition with get, set + abstract head: EditorPosition option with get, set + +type [] EditorSuggest<'T> = + inherit PopoverSuggest<'T> + /// Current suggestion context, containing the result of `onTrigger`. + /// This will be null any time the EditorSuggest is not supposed to run. + abstract context: EditorSuggestContext option with get, set + /// Override this to use a different limit for suggestion items + abstract limit: float with get, set + abstract setInstructions: instructions: ResizeArray -> unit + /// Based on the editor line and cursor position, determine if this EditorSuggest should be triggered at this moment. + /// Typically, you would run a regular expression on the current line text before the cursor. + /// Return null to indicate that this editor suggest is not supposed to be triggered. + /// + /// Please be mindful of performance when implementing this function, as it will be triggered very often (on each keypress). + /// Keep it simple, and return null as early as possible if you determine that it is not the right time. + abstract onTrigger: cursor: EditorPosition * editor: Editor * file: TFile -> EditorSuggestTriggerInfo option + /// Generate suggestion items based on this context. Can be async, but preferably sync. + /// When generating async suggestions, you should pass the context along. + abstract getSuggestions: context: EditorSuggestContext -> U2, Promise>> + +type [] EditorSuggestStatic = + [] abstract Create: app: App -> EditorSuggest<'T> + +type [] EditorSuggestContext = + inherit EditorSuggestTriggerInfo + abstract editor: Editor with get, set + abstract file: TFile with get, set + +type [] EditorSuggestTriggerInfo = + /// The start position of the triggering text. This is used to position the popover. + abstract start: EditorPosition with get, set + /// The end position of the triggering text. This is used to position the popover. + abstract ``end``: EditorPosition with get, set + /// They query string (usually the text between start and end) that will be used to generate the suggestion content. + abstract query: string with get, set + +type [] EditorTransaction = + abstract replaceSelection: string option with get, set + abstract changes: ResizeArray option with get, set + /// Multiple selections, overrides `selection`. + abstract selections: ResizeArray option with get, set + abstract selection: EditorRangeOrCaret option with get, set + +type [] EmbedCache = + inherit ReferenceCache + +type [] EventRef = + interface end + +type [] Events = + abstract on: name: string * callback: (obj option -> obj option) * ?ctx: obj -> EventRef + abstract off: name: string * callback: (obj option -> obj option) -> unit + abstract offref: ref: EventRef -> unit + abstract trigger: name: string * [] data: ResizeArray -> unit + abstract tryTrigger: evt: EventRef * args: ResizeArray -> unit + +type [] EventsStatic = + [] abstract Create: unit -> Events + +type [] ExtraButtonComponent = + inherit BaseComponent + abstract extraSettingsEl: HTMLElement with get, set + abstract setDisabled: disabled: bool -> ExtraButtonComponent + abstract setTooltip: tooltip: string -> ExtraButtonComponent + abstract setIcon: icon: string -> ExtraButtonComponent + abstract onClick: callback: (unit -> obj option) -> ExtraButtonComponent + +type [] ExtraButtonComponentStatic = + [] abstract Create: containerEl: HTMLElement -> ExtraButtonComponent + +/// Manage the creation, deletion and renaming of files from the UI. +type [] FileManager = + /// Gets the folder that new files should be saved to, given the user's preferences. + /// - The path to the current open/focused file, + /// used when the user wants new files to be created "in the same folder". + /// Use an empty string if there is no active file. + abstract getNewFileParent: sourcePath: string -> TFolder + /// Rename or move a file safely, and update all links to it depending on the user's preferences. + /// - the file to rename + /// - the new path for the file + abstract renameFile: file: TAbstractFile * newPath: string -> Promise + /// Generate a markdown link based on the user's preferences. + /// - the file to link to. + /// - where the link is stored in, used to compute relative links. + /// - A subpath, starting with `#`, used for linking to headings or blocks. + /// - The display text if it's to be different than the file name. Pass empty string to use file name. + abstract generateMarkdownLink: file: TFile * sourcePath: string * ?subpath: string * ?alias: string -> string + +/// Manage the creation, deletion and renaming of files from the UI. +type [] FileManagerStatic = + [] abstract Create: unit -> FileManager + +type [] FileStats = + abstract ctime: float with get, set + abstract mtime: float with get, set + abstract size: float with get, set + +type [] FileSystemAdapter = + inherit DataAdapter + abstract getName: unit -> string + abstract getBasePath: unit -> string + abstract mkdir: normalizedPath: string -> Promise + abstract trashSystem: normalizedPath: string -> Promise + abstract trashLocal: normalizedPath: string -> Promise + abstract rmdir: normalizedPath: string * recursive: bool -> Promise + abstract read: normalizedPath: string -> Promise + abstract readBinary: normalizedPath: string -> Promise + abstract write: normalizedPath: string * data: string * ?options: DataWriteOptions -> Promise + abstract writeBinary: normalizedPath: string * data: ArrayBuffer * ?options: DataWriteOptions -> Promise + abstract append: normalizedPath: string * data: string * ?options: DataWriteOptions -> Promise + abstract getResourcePath: normalizedPath: string -> string + abstract remove: normalizedPath: string -> Promise + abstract rename: normalizedPath: string * normalizedNewPath: string -> Promise + abstract copy: normalizedPath: string * normalizedNewPath: string -> Promise + abstract exists: normalizedPath: string * ?sensitive: bool -> Promise + abstract stat: normalizedPath: string -> Promise + abstract list: normalizedPath: string -> Promise + abstract getFullPath: normalizedPath: string -> string + +type [] FileSystemAdapterStatic = + [] abstract Create: unit -> FileSystemAdapter + abstract readLocalFile: path: string -> Promise + abstract mkdir: path: string -> Promise + +type [] FileView = + inherit ItemView + abstract allowNoFile: bool with get, set + abstract file: TFile with get, set + abstract getDisplayText: unit -> string + /// Override this to load your component + abstract onload: unit -> unit + abstract getState: unit -> obj option + abstract setState: state: obj option * result: ViewStateResult -> Promise + abstract onLoadFile: file: TFile -> Promise + abstract onUnloadFile: file: TFile -> Promise + abstract onMoreOptionsMenu: menu: Menu -> unit + abstract onHeaderMenu: menu: Menu -> unit + abstract canAcceptExtension: extension: string -> bool + +type [] FileViewStatic = + [] abstract Create: leaf: WorkspaceLeaf -> FileView + +type [] FrontMatterCache = + inherit CacheItem + [] abstract Item: key: string -> obj option with get, set + +type [] FuzzyMatch<'T> = + abstract item: 'T with get, set + abstract ``match``: SearchResult with get, set + +type [] FuzzySuggestModal<'T> = + inherit SuggestModal> + abstract getSuggestions: query: string -> ResizeArray> + /// Render the suggestion item into DOM. + abstract renderSuggestion: item: FuzzyMatch<'T> * el: HTMLElement -> unit + abstract onChooseSuggestion: item: FuzzyMatch<'T> * evt: U2 -> unit + abstract getItems: unit -> ResizeArray<'T> + abstract getItemText: item: 'T -> string + abstract onChooseItem: item: 'T * evt: U2 -> unit + +type [] FuzzySuggestModalStatic = + [] abstract Create: unit -> FuzzySuggestModal<'T> + +type [] HeadingCache = + inherit CacheItem + abstract heading: string with get, set + abstract level: float with get, set + +type [] HeadingSubpathResult = + inherit SubpathResult + abstract ``type``: string with get, set + abstract current: HeadingCache with get, set + abstract next: HeadingCache with get, set + +type [] Hotkey = + abstract modifiers: ResizeArray with get, set + abstract key: string with get, set + +type [] HoverParent = + abstract hoverPopover: HoverPopover option with get, set + +type [] HoverPopover = + inherit Component + abstract state: obj with get, set + +type [] HoverPopoverStatic = + [] abstract Create: parent: HoverParent * targetEl: HTMLElement option * ?waitTime: float -> HoverPopover + +type [] Instruction = + abstract command: string with get, set + abstract purpose: string with get, set + +type [] ISuggestOwner<'T> = + /// Render the suggestion item into DOM. + abstract renderSuggestion: value: 'T * el: HTMLElement -> unit + /// Called when the user makes a selection. + abstract selectSuggestion: value: 'T * evt: U2 -> unit + +type [] ItemView = + inherit View + abstract contentEl: HTMLElement with get, set + abstract onMoreOptionsMenu: menu: Menu -> unit + abstract addAction: icon: string * title: string * callback: (MouseEvent -> obj option) * ?size: float -> HTMLElement + abstract onHeaderMenu: menu: Menu -> unit + +type [] ItemViewStatic = + [] abstract Create: leaf: WorkspaceLeaf -> ItemView + +type [] Keymap = + abstract pushScope: scope: Scope -> unit + abstract popScope: scope: Scope -> unit + +type [] KeymapStatic = + [] abstract Create: unit -> Keymap + /// Checks whether the modifier key is pressed during this event + abstract isModifier: evt: U3 * modifier: Modifier -> bool + /// Returns true if the modifier key Cmd/Ctrl is pressed OR if this is a middle-click MouseEvent. + abstract isModEvent: ?evt: UserEvent -> bool + +type [] KeymapContext = + inherit KeymapInfo + abstract vkey: string with get, set + +type [] KeymapEventHandler = + inherit KeymapInfo + abstract scope: Scope with get, set + +type [] KeymapEventListener = + [] abstract Invoke: evt: KeyboardEvent * ctx: KeymapContext -> U2 + +type [] KeymapInfo = + abstract modifiers: string option with get, set + abstract key: string option with get, set + +type [] LinkCache = + inherit ReferenceCache + +type [] ListedFiles = + abstract files: ResizeArray with get, set + abstract folders: ResizeArray with get, set + +type [] ListItemCache = + inherit CacheItem + /// The block ID of this list item, if defined. + abstract id: string option with get, set + /// A single character indicating the checked status of a task. + /// The space character `' '` is interpreted as an incomplete task. + /// An other character is interpreted as completed task. + /// `undefined` if this item isn't a task. + abstract task: string option with get, set + /// Line number of the parent list item (position.start.line). + /// If this item has no parent (e.g. it's a root level list), + /// then this value is the negative of the line number of the first list item (start of the list). + /// + /// Can be used to deduce which list items belongs to the same group (item1.parent === item2.parent). + /// Can be used to reconstruct hierarchy information (parentItem.position.start.line === childItem.parent). + abstract parent: float with get, set + +type [] Loc = + abstract line: float with get, set + abstract col: float with get, set + abstract offset: float with get, set + +/// This is the editor for Obsidian Mobile as well as the upcoming WYSIWYG editor. +type [] MarkdownEditView = + inherit MarkdownSubView + inherit HoverParent + abstract hoverPopover: HoverPopover with get, set + abstract clear: unit -> unit + abstract get: unit -> string + abstract set: data: string * clear: bool -> unit + abstract getSelection: unit -> string + abstract getScroll: unit -> float + abstract applyScroll: scroll: float -> unit + +/// This is the editor for Obsidian Mobile as well as the upcoming WYSIWYG editor. +type [] MarkdownEditViewStatic = + [] abstract Create: view: MarkdownView -> MarkdownEditView + +/// A post processor receives an element which is a section of the preview. +/// +/// Post processors can mutate the DOM to render various things, such as mermaid graphs, latex equations, or custom controls. +/// +/// If your post processor requires lifecycle management, for example, to clear an interval, kill a subprocess, etc when this element is +/// removed from the app, look into {@link MarkdownPostProcessorContext#addChild} +type [] MarkdownPostProcessor = + /// The processor function itself. + [] abstract Invoke: el: HTMLElement * ctx: MarkdownPostProcessorContext -> U2, unit> + /// An optional integer sort order. Defaults to 0. Lower number runs before higher numbers. + abstract sortOrder: float option with get, set + +type [] MarkdownPostProcessorContext = + abstract docId: string with get, set + abstract sourcePath: string with get, set + abstract frontmatter: obj option option with get, set + /// Adds a child component that will have its lifecycle managed by the renderer. + /// + /// Use this to add a dependent child to the renderer such that if the containerEl + /// of the child is ever removed, the component's unload will be called. + abstract addChild: child: MarkdownRenderChild -> unit + /// Gets the section information of this element at this point in time. + /// Only call this function right before you need this information to get the most up-to-date version. + /// This function may also return null in many circumstances; if you use it, you must be prepared to deal with nulls. + abstract getSectionInfo: el: HTMLElement -> MarkdownSectionInformation option + +type [] MarkdownPreviewEvents = + inherit Component + +type [] MarkdownPreviewRenderer = + interface end + +type [] MarkdownPreviewRendererStatic = + [] abstract Create: unit -> MarkdownPreviewRenderer + abstract registerPostProcessor: postProcessor: MarkdownPostProcessor * ?sortOrder: float -> unit + abstract unregisterPostProcessor: postProcessor: MarkdownPostProcessor -> unit + abstract createCodeBlockPostProcessor: language: string * handler: (string -> HTMLElement -> MarkdownPostProcessorContext -> U2, unit>) -> (HTMLElement -> MarkdownPostProcessorContext -> unit) + +type [] MarkdownPreviewView = + inherit MarkdownRenderer + inherit MarkdownSubView + inherit MarkdownPreviewEvents + abstract containerEl: HTMLElement with get, set + abstract get: unit -> string + abstract set: data: string * clear: bool -> unit + abstract clear: unit -> unit + abstract rerender: ?full: bool -> unit + abstract getScroll: unit -> float + abstract applyScroll: scroll: float -> unit + +type [] MarkdownPreviewViewStatic = + [] abstract Create: unit -> MarkdownPreviewView + +type [] MarkdownRenderChild = + inherit Component + abstract containerEl: HTMLElement with get, set + +type [] MarkdownRenderChildStatic = + /// - This HTMLElement will be used to test whether this component is still alive. + /// It should be a child of the markdown preview sections, and when it's no longer attached + /// (for example, when it is replaced with a new version because the user edited the markdown source code), + /// this component will be unloaded. + [] abstract Create: containerEl: HTMLElement -> MarkdownRenderChild + +type [] MarkdownRenderer = + inherit MarkdownRenderChild + inherit MarkdownPreviewEvents + inherit HoverParent + abstract hoverPopover: HoverPopover with get, set + +type [] MarkdownRendererStatic = + [] abstract Create: unit -> MarkdownRenderer + /// Renders markdown string to an HTML element. + /// - The markdown source code + /// - The element to append to + /// - The normalized path of this markdown file, used to resolve relative internal links + /// - A parent component to manage the lifecycle of the rendered child components, if any + abstract renderMarkdown: markdown: string * el: HTMLElement * sourcePath: string * ``component``: Component -> Promise + +type [] MarkdownSectionInformation = + abstract text: string with get, set + abstract lineStart: float with get, set + abstract lineEnd: float with get, set + +type [] MarkdownSourceView = + inherit MarkdownSubView + inherit HoverParent + abstract cmEditor: obj with get, set + abstract hoverPopover: HoverPopover with get, set + abstract clear: unit -> unit + abstract get: unit -> string + abstract set: data: string * clear: bool -> unit + abstract getSelection: unit -> string + abstract getScroll: unit -> float + abstract applyScroll: scroll: float -> unit + +type [] MarkdownSourceViewStatic = + [] abstract Create: view: MarkdownView -> MarkdownSourceView + +type [] MarkdownSubView = + abstract getScroll: unit -> float + abstract applyScroll: scroll: float -> unit + abstract get: unit -> string + abstract set: data: string * clear: bool -> unit + +type [] MarkdownView = + inherit TextFileView + abstract editor: Editor with get, set + abstract previewMode: MarkdownPreviewView with get, set + abstract currentMode: MarkdownSubView with get, set + abstract getViewType: unit -> string + abstract getMode: unit -> MarkdownViewModeType + /// Gets the data from the editor. This will be called to save the editor contents to the file. + abstract getViewData: unit -> string + /// Clear the editor. This is usually called when we're about to open a completely + /// different file, so it's best to clear any editor states like undo-redo history, + /// and any caches/indexes associated with the previous file contents. + abstract clear: unit -> unit + /// Set the data to the editor. This is used to load the file contents. + /// + /// If clear is set, then it means we're opening a completely different file. + /// In that case, you should call clear(), or implement a slightly more efficient + /// clearing mechanism given the new data to be set. + abstract setViewData: data: string * clear: bool -> unit + abstract showSearch: ?replace: bool -> unit + +type [] MarkdownViewStatic = + [] abstract Create: leaf: WorkspaceLeaf -> MarkdownView + +type [] [] MarkdownViewModeType = + | Source + | Preview + +type [] Menu = + inherit Component + abstract setNoIcon: unit -> Menu + abstract addItem: cb: (MenuItem -> obj option) -> Menu + abstract addSeparator: unit -> Menu + abstract showAtMouseEvent: evt: MouseEvent -> Menu + abstract showAtPosition: position: Point -> Menu + abstract hide: unit -> Menu + abstract onHide: callback: (unit -> obj option) -> unit + +type [] MenuStatic = + [] abstract Create: app: App -> Menu + +type [] MenuItem = + abstract setTitle: title: U2 -> MenuItem + abstract setIcon: icon: string option * ?size: float -> MenuItem + abstract setActive: active: bool -> MenuItem + abstract setDisabled: disabled: bool -> MenuItem + abstract setIsLabel: isLabel: bool -> MenuItem + abstract onClick: callback: (U2 -> obj option) -> MenuItem + +type [] MenuItemStatic = + [] abstract Create: menu: Menu -> MenuItem + +/// Linktext is any internal link that is composed of a path and a subpath, such as "My note#Heading" +/// Linkpath (or path) is the path part of a linktext +/// Subpath is the heading/block ID part of a linktext. +type [] MetadataCache = + inherit Events + /// Get the best match for a linkpath. + abstract getFirstLinkpathDest: linkpath: string * sourcePath: string -> TFile option + abstract getFileCache: file: TFile -> CachedMetadata option + abstract getCache: path: string -> CachedMetadata + /// Generates a linktext for a file. + /// + /// If file name is unique, use the filename. + /// If not unique, use full path. + abstract fileToLinktext: file: TFile * sourcePath: string * ?omitMdExtension: bool -> string + /// Contains all resolved links. This object maps each source file's path to an object of destination file paths with the link count. + /// Source and destination paths are all vault absolute paths that comes from `TFile.path` and can be used with `Vault.getAbstractFileByPath(path)`. + abstract resolvedLinks: obj with get, set + /// Contains all unresolved links. This object maps each source file to an object of unknown destinations with count. + /// Source paths are all vault absolute paths, similar to `resolvedLinks`. + abstract unresolvedLinks: obj with get, set + /// Called when a file has been indexed, and its (updated) cache is now available. + [] abstract on_changed: callback: (TFile -> string -> CachedMetadata -> obj option) * ?ctx: obj -> EventRef + /// Called when a file has been deleted. A best-effort previous version of the cached metadata is presented, + /// but it could be null in case the file was not successfully cached previously. + [] abstract on_deleted: callback: (TFile -> CachedMetadata option -> obj option) * ?ctx: obj -> EventRef + /// Called when a file has been resolved for `resolvedLinks` and `unresolvedLinks`. + /// This happens sometimes after a file has been indexed. + [] abstract on_resolve: callback: (TFile -> obj option) * ?ctx: obj -> EventRef + /// Called when all files has been resolved. This will be fired each time files get modified after the initial load. + [] abstract on_resolved: callback: (unit -> obj option) * ?ctx: obj -> EventRef + +/// Linktext is any internal link that is composed of a path and a subpath, such as "My note#Heading" +/// Linkpath (or path) is the path part of a linktext +/// Subpath is the heading/block ID part of a linktext. +type [] MetadataCacheStatic = + [] abstract Create: unit -> MetadataCache + +type [] Modal = + inherit CloseableComponent + abstract app: App with get, set + abstract scope: Scope with get, set + abstract containerEl: HTMLElement with get, set + abstract modalEl: HTMLElement with get, set + abstract titleEl: HTMLElement with get, set + abstract contentEl: HTMLElement with get, set + abstract shouldRestoreSelection: bool with get, set + abstract ``open``: unit -> unit + abstract close: unit -> unit + abstract onOpen: unit -> unit + abstract onClose: unit -> unit + +type [] ModalStatic = + [] abstract Create: app: App -> Modal + +type [] [] Modifier = + | [] Mod + | [] Ctrl + | [] Meta + | [] Shift + | [] Alt + +type [] MomentFormatComponent = + inherit TextComponent + abstract sampleEl: HTMLElement with get, set + /// Sets the default format when input is cleared. Also used for placeholder. + abstract setDefaultFormat: defaultFormat: string -> MomentFormatComponent + abstract setSampleEl: sampleEl: HTMLElement -> MomentFormatComponent + abstract setValue: value: string -> MomentFormatComponent + abstract onChanged: unit -> unit + abstract updateSample: unit -> unit + +type [] MomentFormatComponentStatic = + [] abstract Create: unit -> MomentFormatComponent + +type [] Notice = + /// Change the message of this notice. + abstract setMessage: message: U2 -> Notice + abstract hide: unit -> unit + +type [] NoticeStatic = + [] abstract Create: message: U2 * ?timeout: float -> Notice + +type [] ObsidianProtocolData = + abstract action: string with get, set + [] abstract Item: key: string -> string with get, set + +type [] ObsidianProtocolHandler = + [] abstract Invoke: ``params``: ObsidianProtocolData -> obj option + +type [] OpenViewState = + interface end + +type [] Plugin = + inherit Component + abstract app: App with get, set + abstract manifest: PluginManifest with get, set + /// Adds a ribbon icon to the left bar. + /// - The icon name to be used. See {@link addIcon} + /// - The title to be displayed in the tooltip. + /// - The `click` callback. + abstract addRibbonIcon: icon: string * title: string * callback: (MouseEvent -> obj option) -> HTMLElement + abstract addStatusBarItem: unit -> HTMLElement + /// Register a command globally. The command id and name will be automatically prefixed with this plugin's id and name. + abstract addCommand: command: Command -> Command + abstract addSettingTab: settingTab: PluginSettingTab -> unit + abstract registerView: ``type``: string * viewCreator: ViewCreator -> unit + abstract registerExtensions: extensions: ResizeArray * viewType: string -> unit + abstract registerMarkdownPostProcessor: postProcessor: MarkdownPostProcessor * ?sortOrder: float -> MarkdownPostProcessor + /// Register a special post processor that handles fenced code given a language and a handler. + /// This special post processor takes care of removing the
 and create a 
that + /// will be passed to your handler, and is expected to be filled with your custom elements. + abstract registerMarkdownCodeBlockProcessor: language: string * handler: (string -> HTMLElement -> MarkdownPostProcessorContext -> U2, unit>) * ?sortOrder: float -> MarkdownPostProcessor + /// Runs callback on all currently loaded instances of CodeMirror, + /// then registers the callback for all future CodeMirror instances. + abstract registerCodeMirror: callback: (obj -> obj option) -> unit + /// Registers a CodeMirror 6 extension. + /// To reconfigure cm6 extensions for your plugin on the fly, you can pass an array here and dynamically + /// modify it. Once this array is modified, call `Workspace.updateOptions()` to have the changes applied. + /// - must be a CodeMirror 6 `Extension`, or an array of Extensions. + abstract registerEditorExtension: extension: obj -> unit + /// Register a handler for obsidian:// URLs. + /// - the action string. For example, "open" corresponds to `obsidian://open`. + /// - the callback to trigger. You will be passed the key-value pair that is decoded from the query. + /// For example, `obsidian://open?key=value` would generate `{"action": "open", "key": "value"}`. + abstract registerObsidianProtocolHandler: action: string * handler: ObsidianProtocolHandler -> unit + /// Register an EditorSuggest which can provide live suggestions while the user is typing. + abstract registerEditorSuggest: editorSuggest: EditorSuggest -> unit + abstract loadData: unit -> Promise + abstract saveData: data: obj option -> Promise + +type [] PluginStatic = + [] abstract Create: app: App * manifest: PluginManifest -> Plugin + +type [] PluginManifest = + abstract dir: string option with get, set + abstract id: string with get, set + abstract name: string with get, set + abstract author: string with get, set + abstract version: string with get, set + abstract minAppVersion: string with get, set + abstract description: string with get, set + abstract authorUrl: string option with get, set + abstract isDesktopOnly: bool option with get, set + +type [] PluginSettingTab = + inherit SettingTab + +type [] PluginSettingTabStatic = + [] abstract Create: app: App * plugin: Plugin -> PluginSettingTab + +type [] Point = + abstract x: float with get, set + abstract y: float with get, set + + +type [] PopoverSuggest<'T> = + inherit ISuggestOwner<'T> + inherit CloseableComponent + abstract ``open``: unit -> unit + abstract close: unit -> unit + /// Render the suggestion item into DOM. + abstract renderSuggestion: value: 'T * el: HTMLElement -> unit + /// Called when the user makes a selection. + abstract selectSuggestion: value: 'T * evt: U2 -> unit + +type [] PopoverSuggestStatic = + [] abstract Create: app: App * ?scope: Scope -> PopoverSuggest<'T> + +type [] Pos = + abstract start: Loc with get, set + abstract ``end``: Loc with get, set + +type [] PreparedQuery = + abstract query: string with get, set + abstract tokens: ResizeArray with get, set + abstract fuzzy: ResizeArray with get, set + +type [] Rect_2 = + abstract x: float with get, set + abstract y: float with get, set + abstract w: float with get, set + abstract h: float with get, set + +type [] ReferenceCache = + inherit CacheItem + abstract link: string with get, set + abstract original: string with get, set + /// if title is different than link text, in the case of [[page name|display name]] + abstract displayText: string option with get, set + +type [] RequestUrlParam = + abstract url: string with get, set + abstract ``method``: string option with get, set + abstract contentType: string option with get, set + abstract body: U2 option with get, set + abstract headers: obj with get, set + +type [] RequestUrlResponse = + abstract status: float with get, set + abstract headers: obj with get, set + abstract arrayBuffer: ArrayBuffer with get, set + abstract json: obj option with get, set + abstract text: string with get, set + +type [] Scope = + /// - `Mod`, `Ctrl`, `Meta`, `Shift`, or `Alt`. `Mod` translates to `Meta` on macOS and `Ctrl` otherwise. + /// - Keycode from https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key/Key_Values + /// - the callback + abstract register: modifiers: ResizeArray * key: string option * func: KeymapEventListener -> KeymapEventHandler + abstract unregister: handler: KeymapEventHandler -> unit + +type [] ScopeStatic = + [] abstract Create: ?parent: Scope -> Scope + +type [] SearchComponent = + inherit AbstractTextComponent + abstract clearButtonEl: HTMLElement with get, set + abstract onChanged: unit -> unit + +type [] SearchComponentStatic = + [] abstract Create: containerEl: HTMLElement -> SearchComponent + +type SearchMatches = + ResizeArray + +type SearchMatchPart = + float * float + +type [] SearchResult = + abstract score: float with get, set + abstract matches: SearchMatches with get, set + +type [] SearchResultContainer = + abstract ``match``: SearchResult with get, set + +type [] SectionCache = + inherit CacheItem + /// The block ID of this section, if defined. + abstract id: string option with get, set + /// The type string generated by the parser. + abstract ``type``: string with get, set + +type [] Setting = + abstract settingEl: HTMLElement with get, set + abstract infoEl: HTMLElement with get, set + abstract nameEl: HTMLElement with get, set + abstract descEl: HTMLElement with get, set + abstract controlEl: HTMLElement with get, set + abstract components: ResizeArray with get, set + abstract setName: name: U2 -> Setting + abstract setDesc: desc: U2 -> Setting + abstract setClass: cls: string -> Setting + abstract setTooltip: tooltip: string -> Setting + abstract setHeading: unit -> Setting + abstract setDisabled: disabled: bool -> Setting + abstract addButton: cb: (ButtonComponent -> obj option) -> Setting + abstract addExtraButton: cb: (ExtraButtonComponent -> obj option) -> Setting + abstract addToggle: cb: (ToggleComponent -> obj option) -> Setting + abstract addText: cb: (TextComponent -> obj option) -> Setting + abstract addSearch: cb: (SearchComponent -> obj option) -> Setting + abstract addTextArea: cb: (TextAreaComponent -> obj option) -> Setting + abstract addMomentFormat: cb: (MomentFormatComponent -> obj option) -> Setting + abstract addDropdown: cb: (DropdownComponent -> obj option) -> Setting + abstract addSlider: cb: (SliderComponent -> obj option) -> Setting + /// Facilitates chaining + abstract ``then``: cb: (Setting -> obj option) -> Setting + abstract clear: unit -> Setting + +type [] SettingStatic = + [] abstract Create: containerEl: HTMLElement -> Setting + +type [] SettingTab = + abstract app: App with get, set + abstract containerEl: HTMLElement with get, set + abstract display: unit -> obj option + abstract hide: unit -> obj option + +type [] SettingTabStatic = + [] abstract Create: unit -> SettingTab + +type [] SliderComponent = + inherit ValueComponent + abstract sliderEl: HTMLInputElement with get, set + abstract setDisabled: disabled: bool -> SliderComponent + abstract setLimits: min: float * max: float * step: U2 -> SliderComponent + abstract getValue: unit -> float + abstract setValue: value: float -> SliderComponent + abstract getValuePretty: unit -> string + abstract setDynamicTooltip: unit -> SliderComponent + abstract showTooltip: unit -> unit + abstract onChange: callback: (float -> obj option) -> SliderComponent + +type [] SliderComponentStatic = + [] abstract Create: containerEl: HTMLElement -> SliderComponent + +type [] [] SplitDirection = + | Vertical + | Horizontal + +type [] Stat = + abstract ``type``: StatType with get, set + abstract ctime: float with get, set + abstract mtime: float with get, set + abstract size: float with get, set + +type [] SubpathResult = + abstract start: Loc with get, set + abstract ``end``: Loc option with get, set + +type [] SuggestModal<'T> = + inherit Modal + inherit ISuggestOwner<'T> + abstract limit: float with get, set + abstract emptyStateText: string with get, set + abstract inputEl: HTMLInputElement with get, set + abstract resultContainerEl: HTMLElement with get, set + abstract setPlaceholder: placeholder: string -> unit + abstract setInstructions: instructions: ResizeArray -> unit + abstract onNoSuggestion: unit -> unit + /// Called when the user makes a selection. + abstract selectSuggestion: value: 'T * evt: U2 -> unit +// abstract getSuggestions: query: string -> U2, Promise>> //TODO: set thisd + abstract getSuggestions: query: string -> U2, Promise>> + /// Render the suggestion item into DOM. + abstract renderSuggestion: value: 'T * el: HTMLElement -> obj option + abstract onChooseSuggestion: item: 'T * evt: U2 -> obj option + +type [] SuggestModalStatic = + [] abstract Create: app: App -> SuggestModal<'T> + +/// This can be either a `TFile` or a `TFolder`. +type [] TAbstractFile = + abstract vault: Vault with get, set + abstract path: string with get, set + abstract name: string with get, set + abstract parent: TFolder with get, set + +/// This can be either a `TFile` or a `TFolder`. +type [] TAbstractFileStatic = + [] abstract Create: unit -> TAbstractFile + +type [] TagCache = + inherit CacheItem + abstract tag: string with get, set + +type [] Tasks = + abstract add: callback: (unit -> Promise) -> unit + abstract addPromise: promise: Promise -> unit + abstract isEmpty: unit -> bool + abstract promise: unit -> Promise + +type [] TasksStatic = + [] abstract Create: unit -> Tasks + +type [] TextAreaComponent = + inherit AbstractTextComponent + +type [] TextAreaComponentStatic = + [] abstract Create: containerEl: HTMLElement -> TextAreaComponent + +type [] TextComponent = + inherit AbstractTextComponent + +type [] TextComponentStatic = + [] abstract Create: containerEl: HTMLElement -> TextComponent + +/// This class implements a plaintext-based editable file view, which can be loaded and saved given an editor. +/// +/// Note that by default, this view only saves when it's closing. To implement auto-save, your editor should +/// call `this.requestSave()` when the content is changed. +type [] TextFileView = + inherit EditableFileView + /// In memory data + abstract data: string with get, set + /// Debounced save in 2 seconds from now + abstract requestSave: (unit -> unit) with get, set + abstract onUnloadFile: file: TFile -> Promise + abstract onLoadFile: file: TFile -> Promise + abstract save: ?clear: bool -> Promise + /// Gets the data from the editor. This will be called to save the editor contents to the file. + abstract getViewData: unit -> string + /// Set the data to the editor. This is used to load the file contents. + /// + /// If clear is set, then it means we're opening a completely different file. + /// In that case, you should call clear(), or implement a slightly more efficient + /// clearing mechanism given the new data to be set. + abstract setViewData: data: string * clear: bool -> unit + /// Clear the editor. This is usually called when we're about to open a completely + /// different file, so it's best to clear any editor states like undo-redo history, + /// and any caches/indexes associated with the previous file contents. + abstract clear: unit -> unit + +/// This class implements a plaintext-based editable file view, which can be loaded and saved given an editor. +/// +/// Note that by default, this view only saves when it's closing. To implement auto-save, your editor should +/// call `this.requestSave()` when the content is changed. +type [] TextFileViewStatic = + [] abstract Create: leaf: WorkspaceLeaf -> TextFileView + +type [] TFile = + inherit TAbstractFile + abstract stat: FileStats with get, set + abstract basename: string with get, set + abstract extension: string with get, set + +type [] TFileStatic = + [] abstract Create: unit -> TFile + +type [] TFolder = + inherit TAbstractFile + abstract children: ResizeArray with get, set + abstract isRoot: unit -> bool + +type [] TFolderStatic = + [] abstract Create: unit -> TFolder + +type [] ToggleComponent = + inherit ValueComponent + abstract toggleEl: HTMLElement with get, set + abstract setDisabled: disabled: bool -> ToggleComponent + abstract getValue: unit -> bool + abstract setValue: on: bool -> ToggleComponent + abstract setTooltip: tooltip: string -> ToggleComponent + abstract onClick: unit -> unit + abstract onChange: callback: (bool -> obj option) -> ToggleComponent + +type [] ToggleComponentStatic = + [] abstract Create: containerEl: HTMLElement -> ToggleComponent + +type UserEvent = + U4 + +type [] ValueComponent<'T> = + inherit BaseComponent + abstract registerOptionListener: listeners: obj * key: string -> ValueComponent<'T> + abstract getValue: unit -> 'T + abstract setValue: value: 'T -> ValueComponent<'T> + +type [] ValueComponentStatic = + [] abstract Create: unit -> ValueComponent<'T> + +type [] Vault = + inherit Events + abstract adapter: DataAdapter with get, set + /// Gets the path to the config folder. + /// This value is typically `.obsidian` but it could be different. + abstract configDir: string with get, set + /// Gets the name of the vault + abstract getName: unit -> string + abstract getAbstractFileByPath: path: string -> TAbstractFile option + abstract getRoot: unit -> TFolder + abstract create: path: string * data: string * ?options: DataWriteOptions -> Promise + abstract createBinary: path: string * data: ArrayBuffer * ?options: DataWriteOptions -> Promise + abstract createFolder: path: string -> Promise + abstract read: file: TFile -> Promise + abstract cachedRead: file: TFile -> Promise + abstract readBinary: file: TFile -> Promise + abstract getResourcePath: file: TFile -> string + /// - The file or folder to be deleted + /// - Should attempt to delete folder even if it has hidden children + abstract delete: file: TAbstractFile * ?force: bool -> Promise + /// Tries to move to system trash. If that isn't successful/allowed, use local trash + /// - The file or folder to be deleted + /// - Should move to system trash + abstract trash: file: TAbstractFile * system: bool -> Promise + abstract rename: file: TAbstractFile * newPath: string -> Promise + abstract modify: file: TFile * data: string * ?options: DataWriteOptions -> Promise + abstract modifyBinary: file: TFile * data: ArrayBuffer * ?options: DataWriteOptions -> Promise + abstract append: file: TFile * data: string * ?options: DataWriteOptions -> Promise + abstract copy: file: TFile * newPath: string -> Promise + abstract getAllLoadedFiles: unit -> ResizeArray + abstract getMarkdownFiles: unit -> ResizeArray + abstract getFiles: unit -> ResizeArray + [] abstract on_create: callback: (TAbstractFile -> obj option) * ?ctx: obj -> EventRef + [] abstract on_modify: callback: (TAbstractFile -> obj option) * ?ctx: obj -> EventRef + [] abstract on_delete: callback: (TAbstractFile -> obj option) * ?ctx: obj -> EventRef + [] abstract on_rename: callback: (TAbstractFile -> string -> obj option) * ?ctx: obj -> EventRef + [] abstract on_closed: callback: (unit -> obj option) * ?ctx: obj -> EventRef + +type [] VaultStatic = + [] abstract Create: unit -> Vault + abstract recurseChildren: root: TFolder * cb: (TAbstractFile -> obj option) -> unit + +type [] View = + inherit Component + abstract app: App with get, set + abstract icon: string with get, set + abstract navigation: bool with get, set + abstract leaf: WorkspaceLeaf with get, set + abstract containerEl: HTMLElement with get, set + abstract onOpen: unit -> Promise + abstract onClose: unit -> Promise + abstract getViewType: unit -> string + abstract getState: unit -> obj option + abstract setState: state: obj option * result: ViewStateResult -> Promise + abstract getEphemeralState: unit -> obj option + abstract setEphemeralState: state: obj option -> unit + abstract getIcon: unit -> string + /// Called when the size of this view is changed. + abstract onResize: unit -> unit + abstract getDisplayText: unit -> string + abstract onHeaderMenu: menu: Menu -> unit + +type [] ViewStatic = + [] abstract Create: leaf: WorkspaceLeaf -> View + +type [] ViewCreator = + [] abstract Invoke: leaf: WorkspaceLeaf -> View + +type [] ViewState = + abstract ``type``: string with get, set + abstract state: obj option with get, set + abstract active: bool option with get, set + abstract pinned: bool option with get, set + abstract group: WorkspaceLeaf option with get, set + +type [] ViewStateResult = + interface end + +type [] Workspace = + inherit Events + abstract leftSplit: U2 with get, set + abstract rightSplit: U2 with get, set + abstract leftRibbon: WorkspaceRibbon with get, set + abstract rightRibbon: WorkspaceRibbon with get, set + abstract rootSplit: WorkspaceSplit with get, set + abstract activeLeaf: WorkspaceLeaf option with get, set + abstract containerEl: HTMLElement with get, set + abstract layoutReady: bool with get, set + abstract requestSaveLayout: (unit -> unit) with get, set + abstract requestSaveHistory: (unit -> unit) with get, set + /// Runs the callback function right away if layout is already ready, + /// or push it to a queue to be called later when layout is ready. + abstract onLayoutReady: callback: (unit -> obj option) -> unit + abstract changeLayout: workspace: obj option -> Promise + abstract getLayout: unit -> obj option + abstract createLeafInParent: parent: WorkspaceSplit * index: float -> WorkspaceLeaf + abstract splitLeaf: source: WorkspaceItem * newLeaf: WorkspaceItem * ?direction: SplitDirection * ?before: bool -> unit + abstract createLeafBySplit: leaf: WorkspaceLeaf * ?direction: SplitDirection * ?before: bool -> WorkspaceLeaf + abstract splitActiveLeaf: ?direction: SplitDirection -> WorkspaceLeaf + abstract splitLeafOrActive: ?leaf: WorkspaceLeaf * ?direction: SplitDirection -> WorkspaceLeaf + abstract duplicateLeaf: leaf: WorkspaceLeaf * ?direction: SplitDirection -> Promise + abstract getUnpinnedLeaf: ?``type``: string -> WorkspaceLeaf + abstract getLeaf: ?newLeaf: bool -> WorkspaceLeaf + abstract openLinkText: linktext: string * sourcePath: string * ?newLeaf: bool * ?openViewState: OpenViewState -> Promise + /// Sets the active leaf + /// - The new active leaf + /// - Whether to push the navigation history, or replace the current navigation history. + /// - Whether to ask the leaf to focus. + abstract setActiveLeaf: leaf: WorkspaceLeaf * ?pushHistory: bool * ?focus: bool -> unit + abstract getLeafById: id: string -> WorkspaceLeaf + abstract getGroupLeaves: group: string -> ResizeArray + abstract getMostRecentLeaf: unit -> WorkspaceLeaf + abstract getLeftLeaf: split: bool -> WorkspaceLeaf + abstract getRightLeaf: split: bool -> WorkspaceLeaf + abstract getActiveViewOfType: ``type``: Constructor<'T> -> 'T option + abstract getActiveFile: unit -> TFile option + abstract iterateRootLeaves: callback: (WorkspaceLeaf -> obj option) -> unit + abstract iterateAllLeaves: callback: (WorkspaceLeaf -> obj option) -> unit + abstract getLeavesOfType: viewType: string -> ResizeArray + abstract detachLeavesOfType: viewType: string -> unit + abstract revealLeaf: leaf: WorkspaceLeaf -> unit + abstract getLastOpenFiles: unit -> ResizeArray + /// Calling this function will update/reconfigure the options of all markdown panes. + /// It is fairly expensive, so it should not be called frequently. + abstract updateOptions: unit -> unit + abstract iterateCodeMirrors: callback: (obj -> obj option) -> unit + [] abstract ``on_quick-preview``: callback: (TFile -> string -> obj option) * ?ctx: obj -> EventRef + [] abstract on_resize: callback: (unit -> obj option) * ?ctx: obj -> EventRef + [] abstract on_click: callback: (MouseEvent -> obj option) * ?ctx: obj -> EventRef + [] abstract ``on_active-leaf-change``: callback: (WorkspaceLeaf option -> obj option) * ?ctx: obj -> EventRef + [] abstract ``on_file-open``: callback: (TFile option -> obj option) * ?ctx: obj -> EventRef + [] abstract ``on_layout-change``: callback: (unit -> obj option) * ?ctx: obj -> EventRef + /// Triggered when the CSS of the app has changed. + [] abstract ``on_css-change``: callback: (unit -> obj option) * ?ctx: obj -> EventRef + /// Triggered when the user opens the context menu on a file. + [] abstract ``on_file-menu``: callback: (Menu -> TAbstractFile -> string -> WorkspaceLeaf -> obj option) * ?ctx: obj -> EventRef + /// Triggered when the user opens the context menu on an editor. + [] abstract ``on_editor-menu``: callback: (Menu -> Editor -> MarkdownView -> obj option) * ?ctx: obj -> EventRef + /// Triggered when changes to an editor has been applied, either programmatically or from a user event. + [] abstract ``on_editor-change``: callback: (Editor -> MarkdownView -> obj option) * ?ctx: obj -> EventRef + /// Triggered when the editor receives a paste event. + /// Check for `evt.defaultPrevented` before attempting to handle this event, and return if it has been already handled. + /// Use `evt.preventDefault()` to indicate that you've handled the event. + [] abstract ``on_editor-paste``: callback: (ClipboardEvent -> Editor -> MarkdownView -> obj option) * ?ctx: obj -> EventRef + /// Triggered when the editor receives a drop event. + /// Check for `evt.defaultPrevented` before attempting to handle this event, and return if it has been already handled. + /// Use `evt.preventDefault()` to indicate that you've handled the event. + [] abstract ``on_editor-drop``: callback: (DragEvent -> Editor -> MarkdownView -> obj option) * ?ctx: obj -> EventRef + [] abstract on_codemirror: callback: (obj -> obj option) * ?ctx: obj -> EventRef + /// Triggered when the app is about to quit. Not guaranteed to actually run. + /// Perform some best effort cleanup here. + [] abstract on_quit: callback: (Tasks -> obj option) * ?ctx: obj -> EventRef + +type [] WorkspaceStatic = + [] abstract Create: unit -> Workspace + +type [] WorkspaceItem = + inherit Events + abstract getRoot: unit -> WorkspaceItem + +type [] WorkspaceItemStatic = + [] abstract Create: unit -> WorkspaceItem + +type [] WorkspaceLeaf = + inherit WorkspaceItem + abstract view: View with get, set + abstract openFile: file: TFile * ?openState: OpenViewState -> Promise + abstract ``open``: view: View -> Promise + abstract getViewState: unit -> ViewState + abstract setViewState: viewState: ViewState * ?eState: obj -> Promise + abstract getEphemeralState: unit -> obj option + abstract setEphemeralState: state: obj option -> unit + abstract togglePinned: unit -> unit + abstract setPinned: pinned: bool -> unit + abstract setGroupMember: other: WorkspaceLeaf -> unit + abstract setGroup: group: string -> unit + abstract detach: unit -> unit + abstract getIcon: unit -> string + abstract getDisplayText: unit -> string + abstract onResize: unit -> unit + [] abstract ``on_pinned-change``: callback: (bool -> obj option) * ?ctx: obj -> EventRef + [] abstract ``on_group-change``: callback: (string -> obj option) * ?ctx: obj -> EventRef + +type [] WorkspaceLeafStatic = + [] abstract Create: unit -> WorkspaceLeaf + +type [] WorkspaceMobileDrawer = + inherit WorkspaceParent + abstract collapsed: bool with get, set + abstract expand: unit -> unit + abstract collapse: unit -> unit + abstract toggle: unit -> unit + +type [] WorkspaceMobileDrawerStatic = + [] abstract Create: unit -> WorkspaceMobileDrawer + +type [] WorkspaceParent = + inherit WorkspaceItem + +type [] WorkspaceParentStatic = + [] abstract Create: unit -> WorkspaceParent + +type [] WorkspaceRibbon = + interface end + +type [] WorkspaceRibbonStatic = + [] abstract Create: unit -> WorkspaceRibbon + +type [] WorkspaceSidedock = + inherit WorkspaceSplit + abstract collapsed: bool with get, set + abstract toggle: unit -> unit + abstract collapse: unit -> unit + abstract expand: unit -> unit + +type [] WorkspaceSidedockStatic = + [] abstract Create: unit -> WorkspaceSidedock + +type [] WorkspaceSplit = + inherit WorkspaceParent + +type [] WorkspaceSplitStatic = + [] abstract Create: unit -> WorkspaceSplit + +type [] WorkspaceTabs = + inherit WorkspaceParent + +type [] WorkspaceTabsStatic = + [] abstract Create: unit -> WorkspaceTabs + +type [] Platform = + /// The UI is in desktop mode. + abstract isDesktop: bool with get, set + /// The UI is in mobile mode. + abstract isMobile: bool with get, set + /// We're running the electron-based desktop app. + abstract isDesktopApp: bool with get, set + /// We're running the capacitor-js mobile app. + abstract isMobileApp: bool with get, set + /// We're running the iOS app. + abstract isIosApp: bool with get, set + /// We're running the Android app. + abstract isAndroidApp: bool with get, set + /// We're on a macOS device, or a device that pretends to be one (like iPhones and iPads). + /// Typically used to detect whether to use command-based hotkeys vs ctrl-based hotkeys. + abstract isMacOS: bool with get, set + /// We're running in Safari. + /// Typically used to provide workarounds for Safari bugs. + abstract isSafari: bool with get, set + +type [] DomElementInfoAttr = + [] abstract Item: key: string -> U3 option with get, set + +type [] [] AjaxOptionsMethod = + | [] GET + | [] POST + +type [] [] StatType = + | File + | Folder diff --git a/Program.fs b/Program.fs new file mode 100644 index 0000000..fb6580b --- /dev/null +++ b/Program.fs @@ -0,0 +1,266 @@ +module Program +open Obsidian +open Fable.Core +open Fable.Core.JsInterop + +[] +let obsidian : Obsidian.IExports = jsNative + +type SamplePluginSettings = { + mutable mySetting : string +} + +let defaultSettings : SamplePluginSettings = { + mySetting = "default" +} + +[] +type DefaultCommand() = + do () + +let defaultCommand () = + let mutable mid = "" + let mutable mname = "" + let mutable _cb = None + let mutable _ccb = None + let mutable _hotkeys = None + let mutable _editorCallback = None + let mutable _editorCheckCallback = None + + { new Command with + member this.callback + with get () = _cb + and set v = _cb <- v + + member this.checkCallback + with get () = _ccb + and set v = _ccb <- v + + member this.editorCallback + with get () = _editorCallback + and set v = _editorCallback <- v + + member this.editorCheckCallback + with get () = _editorCheckCallback + and set v = _editorCheckCallback <- v + + member this.hotkeys + with get () = _hotkeys + and set v = _hotkeys <- v + + member this.icon: string option = None + + member this.icon + with set (v: string option): unit = () + + member this.id: string = mid + + member this.id + with set (v: string): unit = mid <- v + + member this.mobileOnly: bool option = None + + member this.mobileOnly + with set (v: bool option): unit = () + + member this.name: string = mname + + member this.name + with set (v: string): unit = mname <- v + } + +[] +type DefaultPluginSettingTab(app, plugin) = + do () + +type SamplePluginSettingTab(app, plugin) as instance = + inherit DefaultPluginSettingTab(app, plugin) + + let settings = + instance :> obj :?> PluginSettingTab + + let init () = + settings?plugin <- plugin + + instance?display <- fun () -> + let containerEl : HTMLElement = settings?containerEl + containerEl.empty () + + let mutable setting : Setting = obsidian.Setting.Create(containerEl) + + setting <- setting + .setName(U2.Case1 "Setting #1") + .setDesc(U2.Case1 "It's a secret") + .addText(fun text -> + text + .setPlaceholder("Enter your secret") + .setValue(plugin?settings.mySetting) + .onChange(fun value -> + settings?plugin?settings.mySetting <- value + settings?plugin?saveSettings () + Some () + ) |> ignore + + Some () + ) + + do init () + + +[] +type DefaultModal(app) = + do () + +type SampleModal(app) as instance = + inherit DefaultModal(app) + + let modal = + instance :> obj :?> Modal + + let init () = + + modal?onOpen <- fun () -> + let contentEl : HTMLElement = modal?contentEl + U2.Case1 "Woah!" |> contentEl.setText + + modal?onClose <- fun () -> + let contentEl : HTMLElement = modal?contentEl + contentEl.empty () + + do init () + + +// This workaround allows the members to be defined dynamically, without implementing +// the whole interface. +[] +type DefaultPlugin(app, manifest) = + do () + +// Note: This cannot be named "Plugin", or the import from the Obsidian API will be renamed +type SamplePlugin(app, manifest) as instance = + inherit DefaultPlugin(app, manifest) + + // This is what is actually holding the plugin data + // It would be better to have the main plugin implement this interface, but I can't quite + // get it to work right without an absurd amount of boilerplate + let plugin = + instance :> obj :?> Plugin + + let init () : unit = + plugin?loadSettings <- (fun _ -> + promise { + let! data = plugin.loadData () + + match data with + | None -> plugin?settings <- defaultSettings + | Some v -> + try + plugin?settings <- v :?> SamplePluginSettings + with + | _ -> + plugin?settings <- defaultSettings + } + ) + + plugin?saveSettings <- (fun () -> + promise { + do! plugin.saveData (Some(!!plugin?settings)) + } + ) + + // This creates an icon in the left ribbon. + plugin?ribbonIconEl <- + // Called when the user clicks the icon. + let callback (evt : Browser.Types.MouseEvent) : Obsidian.Notice = + obsidian.Notice.Create(U2.Case1 "This is a notice!") + in + + plugin?addRibbonIcon("dice", "Sample Plugin", callback) + + // Perform additional things with the ribbon + (plugin?ribbonIconEl : Element).addClass ( + let array = new ResizeArray(1) + array.Add("my-plugin-ribbon-class") + array + ) + + // This adds a status bar item to the bottom of the app. Does not work on mobile apps. + let statusBarItemEl : Element = plugin?addStatusBarItem () + "Status Bar Text" |> U2.Case1 |> statusBarItemEl.setText + + + // This adds a simple command that can be triggered anywhere + plugin?addCommand ( + let mutable cmd = defaultCommand () + cmd.id <- "open-sample-modal-simple" + cmd.name <- "Open sample modal (simple)" + cmd.callback <- Some (fun _ -> + Some((new SampleModal(plugin?app) :> obj :?> Modal).``open`` ()) + ) + cmd + ) + + // This adds an editor command that can perform some operation on the current editor instance + plugin?addCommand ( + let mutable cmd = defaultCommand () + cmd.id <- "sample-editor-command" + cmd.name <- "Sample editor command" + cmd.editorCallback <- Some (fun (editor : Editor) (view : MarkdownView) -> + printf "%A" (editor.getSelection ()) + let replacement = editor.replaceSelection ("Sample Editor Command") + Some replacement + ) + cmd + ) + + // This adds a complex command that can check whether the current state of the app allows execution of the command + plugin?addCommand ( + let mutable cmd = defaultCommand () + cmd.id <- "open-sample-modal-complex" + cmd.name <- "Open sample modal (complex)" + cmd.checkCallback <- Some (fun checking -> + // Conditions to check + let app : App = plugin?app + let markdownView = + obsidian.MarkdownView :?> Constructor + |> app.workspace.getActiveViewOfType + match markdownView with + | Some markdownView -> + // If checking is true, we're simply "checking" if the command can be run. + // If checking is false, then we want to actually perform the operation. + if checking |> not then + Some((new SampleModal(plugin?app) :> obj :?> Modal).``open`` ()) + |> ignore + + // This command will only show up in Command Palette when the check function returns true + true |> U2.Case1 + | None -> + false |> U2.Case1 + + ) + cmd + ) + + // This adds a settings tab so the user can configure various aspects of the plugin + plugin?addSettingTab (new SamplePluginSettingTab (plugin?app, plugin)) + + // If the plugin hooks up any global DOM events (on parts of the app that doesn't belong to this plugin) + // Using this function will automatically remove the event listener when this plugin is disabled. + plugin?registerDomEvent (Browser.Dom.document, "click", fun (evt : Browser.Types.MouseEvent) -> ( + printfn "click: %A" evt + )) + + // When registering intervals, this function will automatically clear the interval when the plugin is disabled. + plugin?registerInterval Browser.Dom.window.setInterval (fun () -> printfn "setInterval") (5 * 60 * 1000) + + () + + let onload: unit -> unit = fun _ -> plugin?settings <- plugin?loadSettings () + + do init () + + do plugin?onload <- onload + +// DO NOT REMOVE +// Change the name here to match the type name used above +emitJsStatement "" "module.exports = SamplePlugin"; diff --git a/README.md b/README.md new file mode 100644 index 0000000..9eb20f7 --- /dev/null +++ b/README.md @@ -0,0 +1,3 @@ +# Obsidian Sample Plugin F\# + +This is a recreation of the [official Obsidian sample plugin](https://github.com/obsidianmd/obsidian-sample-plugin) in F\# using Fable as a proof of concept. diff --git a/justfile b/justfile new file mode 100755 index 0000000..87d9e5c --- /dev/null +++ b/justfile @@ -0,0 +1,11 @@ +build: + dotnet fable --lang javascript --noCache + esbuild ./Program.fs.js --bundle --external:obsidian --outfile=./out/main.js --format=cjs + cp -a ./meta/. ./out/ + +clean: + rm -rf ./fable_modules/ ./bin/ ./obj/ ./out/ *.fs.js + + + + diff --git a/meta/manifest.json b/meta/manifest.json new file mode 100644 index 0000000..088bb4e --- /dev/null +++ b/meta/manifest.json @@ -0,0 +1,10 @@ +{ + "id": "obsidian-sample-plugin-fs", + "name": "FSharp Sample Plugin", + "version": "1.0.0", + "minAppVersion": "0.15.0", + "description": "Sample project to demonstrate how to use F# and Fable to create an Obsidian plugin.", + "author": "Aaron Manning", + "authorUrl": "https://aaronmanning.net", + "isDesktopOnly": false +} diff --git a/meta/versions.json b/meta/versions.json new file mode 100644 index 0000000..26382a1 --- /dev/null +++ b/meta/versions.json @@ -0,0 +1,3 @@ +{ + "1.0.0": "0.15.0" +} diff --git a/obsidian-sample-plugin-fs.fsproj b/obsidian-sample-plugin-fs.fsproj new file mode 100644 index 0000000..c3ac38d --- /dev/null +++ b/obsidian-sample-plugin-fs.fsproj @@ -0,0 +1,22 @@ + + + + Exe + net7.0 + obsidian_sample_plugin_fs + + + + + + + + + + + + + + + +