LSPlugin.ts 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938
  1. import EventEmitter from 'eventemitter3'
  2. import * as CSS from 'csstype'
  3. import { LSPluginCaller } from './LSPlugin.caller'
  4. import { LSPluginFileStorage } from './modules/LSPlugin.Storage'
  5. import { LSPluginExperiments } from './modules/LSPlugin.Experiments'
  6. export type PluginLocalIdentity = string
  7. export type ThemeOptions = {
  8. name: string
  9. url: string
  10. description?: string
  11. mode?: 'dark' | 'light'
  12. [key: string]: any
  13. }
  14. export type StyleString = string
  15. export type StyleOptions = {
  16. key?: string
  17. style: StyleString
  18. }
  19. export type UIContainerAttrs = {
  20. draggable: boolean
  21. resizable: boolean
  22. [key: string]: any
  23. }
  24. export type UIBaseOptions = {
  25. key?: string
  26. replace?: boolean
  27. template: string | null
  28. style?: CSS.Properties
  29. attrs?: Record<string, string>
  30. close?: 'outside' | string
  31. reset?: boolean // reset slot content or not
  32. }
  33. export type UIPathIdentity = {
  34. /**
  35. * DOM selector
  36. */
  37. path: string
  38. }
  39. export type UISlotIdentity = {
  40. /**
  41. * Slot key
  42. */
  43. slot: string
  44. }
  45. export type UISlotOptions = UIBaseOptions & UISlotIdentity
  46. export type UIPathOptions = UIBaseOptions & UIPathIdentity
  47. export type UIOptions = UIBaseOptions | UIPathOptions | UISlotOptions
  48. export interface LSPluginPkgConfig {
  49. id: PluginLocalIdentity
  50. main: string
  51. entry: string // alias of main
  52. title: string
  53. mode: 'shadow' | 'iframe'
  54. themes: Array<ThemeOptions>
  55. icon: string
  56. [key: string]: any
  57. }
  58. export interface LSPluginBaseInfo {
  59. id: string // should be unique
  60. mode: 'shadow' | 'iframe'
  61. settings: {
  62. disabled: boolean
  63. [key: string]: any
  64. }
  65. [key: string]: any
  66. }
  67. export type IHookEvent = {
  68. [key: string]: any
  69. }
  70. export type IUserOffHook = () => void
  71. export type IUserHook<E = any, R = IUserOffHook> = (
  72. callback: (e: IHookEvent & E) => void
  73. ) => IUserOffHook
  74. export type IUserSlotHook<E = any> = (
  75. callback: (e: IHookEvent & UISlotIdentity & E) => void
  76. ) => void
  77. export type EntityID = number
  78. export type BlockUUID = string
  79. export type BlockUUIDTuple = ['uuid', BlockUUID]
  80. export type IEntityID = { id: EntityID; [key: string]: any }
  81. export type IBatchBlock = {
  82. content: string
  83. properties?: Record<string, any>
  84. children?: Array<IBatchBlock>
  85. }
  86. export type IDatom = [e: number, a: string, v: any, t: number, added: boolean]
  87. export type IGitResult = { stdout: string; stderr: string; exitCode: number }
  88. export interface AppUserInfo {
  89. [key: string]: any
  90. }
  91. export interface AppInfo {
  92. version: string
  93. [key: string]: any
  94. }
  95. /**
  96. * User's app configurations
  97. */
  98. export interface AppUserConfigs {
  99. preferredThemeMode: 'dark' | 'light'
  100. preferredFormat: 'markdown' | 'org'
  101. preferredDateFormat: string
  102. preferredStartOfWeek: string
  103. preferredLanguage: string
  104. preferredWorkflow: string
  105. currentGraph: string
  106. showBracket: boolean
  107. [key: string]: any
  108. }
  109. /**
  110. * In Logseq, a graph represents a repository of connected pages and blocks
  111. */
  112. export interface AppGraphInfo {
  113. name: string
  114. url: string
  115. path: string
  116. [key: string]: any
  117. }
  118. /**
  119. * Block - Logseq's fundamental data structure.
  120. */
  121. export interface BlockEntity {
  122. id: EntityID // db id
  123. uuid: BlockUUID
  124. left: IEntityID
  125. format: 'markdown' | 'org'
  126. parent: IEntityID
  127. unordered: boolean
  128. content: string
  129. page: IEntityID
  130. // optional fields in dummy page
  131. anchor?: string
  132. body?: any
  133. children?: Array<BlockEntity | BlockUUIDTuple>
  134. container?: string
  135. file?: IEntityID
  136. level?: number
  137. meta?: { timestamps: any; properties: any; startPos: number; endPos: number }
  138. title?: Array<any>
  139. [key: string]: any
  140. }
  141. /**
  142. * Page is just a block with some specific properties.
  143. */
  144. export interface PageEntity {
  145. id: EntityID
  146. uuid: BlockUUID
  147. name: string
  148. originalName: string
  149. 'journal?': boolean
  150. file?: IEntityID
  151. namespace?: IEntityID
  152. children?: Array<PageEntity>
  153. format?: 'markdown' | 'org'
  154. journalDay?: number
  155. }
  156. export type BlockIdentity = BlockUUID | Pick<BlockEntity, 'uuid'>
  157. export type BlockPageName = string
  158. export type PageIdentity = BlockPageName | BlockIdentity
  159. export type SlashCommandActionCmd =
  160. | 'editor/input'
  161. | 'editor/hook'
  162. | 'editor/clear-current-slash'
  163. | 'editor/restore-saved-cursor'
  164. export type SlashCommandAction = [cmd: SlashCommandActionCmd, ...args: any]
  165. export type SimpleCommandCallback = (e: IHookEvent) => void
  166. export type BlockCommandCallback = (
  167. e: IHookEvent & { uuid: BlockUUID }
  168. ) => Promise<void>
  169. export type BlockCursorPosition = {
  170. left: number
  171. top: number
  172. height: number
  173. pos: number
  174. rect: DOMRect
  175. }
  176. export type SimpleCommandKeybinding = {
  177. mode?: 'global' | 'non-editing' | 'editing'
  178. binding: string
  179. mac?: string // special for Mac OS
  180. }
  181. export type SettingSchemaDesc = {
  182. key: string
  183. type: 'string' | 'number' | 'boolean' | 'enum' | 'object'
  184. default: string | number | boolean | Array<any> | object | null
  185. title: string
  186. description: string // support markdown
  187. inputAs?: 'color' | 'date' | 'datetime-local' | 'range'
  188. enumChoices?: Array<string>
  189. enumPicker?: 'select' | 'radio' | 'checkbox' // default: select
  190. }
  191. export type ExternalCommandType =
  192. | 'logseq.command/run'
  193. | 'logseq.editor/cycle-todo'
  194. | 'logseq.editor/down'
  195. | 'logseq.editor/up'
  196. | 'logseq.editor/expand-block-children'
  197. | 'logseq.editor/collapse-block-children'
  198. | 'logseq.editor/open-file-in-default-app'
  199. | 'logseq.editor/open-file-in-directory'
  200. | 'logseq.editor/select-all-blocks'
  201. | 'logseq.editor/toggle-open-blocks'
  202. | 'logseq.editor/zoom-in'
  203. | 'logseq.editor/zoom-out'
  204. | 'logseq.editor/indent'
  205. | 'logseq.editor/outdent'
  206. | 'logseq.editor/copy'
  207. | 'logseq.editor/cut'
  208. | 'logseq.go/home'
  209. | 'logseq.go/journals'
  210. | 'logseq.go/keyboard-shortcuts'
  211. | 'logseq.go/next-journal'
  212. | 'logseq.go/prev-journal'
  213. | 'logseq.go/search'
  214. | 'logseq.go/search-in-page'
  215. | 'logseq.go/tomorrow'
  216. | 'logseq.go/backward'
  217. | 'logseq.go/forward'
  218. | 'logseq.search/re-index'
  219. | 'logseq.sidebar/clear'
  220. | 'logseq.sidebar/open-today-page'
  221. | 'logseq.ui/goto-plugins'
  222. | 'logseq.ui/select-theme-color'
  223. | 'logseq.ui/toggle-brackets'
  224. | 'logseq.ui/toggle-cards'
  225. | 'logseq.ui/toggle-contents'
  226. | 'logseq.ui/toggle-document-mode'
  227. | 'logseq.ui/toggle-help'
  228. | 'logseq.ui/toggle-left-sidebar'
  229. | 'logseq.ui/toggle-right-sidebar'
  230. | 'logseq.ui/toggle-settings'
  231. | 'logseq.ui/toggle-theme'
  232. | 'logseq.ui/toggle-wide-mode'
  233. | 'logseq.command-palette/toggle'
  234. export type UserProxyTags = 'app' | 'editor' | 'db' | 'git' | 'ui' | 'assets'
  235. /**
  236. * App level APIs
  237. */
  238. export interface IAppProxy {
  239. /**
  240. * @added 0.0.4
  241. * @param key
  242. */
  243. getInfo: (key?: keyof AppInfo) => Promise<AppInfo | any>
  244. getUserInfo: () => Promise<AppUserInfo | null>
  245. getUserConfigs: () => Promise<AppUserConfigs>
  246. // commands
  247. registerCommand: (
  248. type: string,
  249. opts: {
  250. key: string
  251. label: string
  252. desc?: string
  253. palette?: boolean
  254. keybinding?: SimpleCommandKeybinding
  255. },
  256. action: SimpleCommandCallback
  257. ) => void
  258. registerCommandPalette: (
  259. opts: {
  260. key: string
  261. label: string
  262. keybinding?: SimpleCommandKeybinding
  263. },
  264. action: SimpleCommandCallback
  265. ) => void
  266. /**
  267. * Supported key names
  268. * @link https://gist.github.com/xyhp915/d1a6d151a99f31647a95e59cdfbf4ddc
  269. * @param keybinding
  270. * @param action
  271. */
  272. registerCommandShortcut: (
  273. keybinding: SimpleCommandKeybinding,
  274. action: SimpleCommandCallback
  275. ) => void
  276. invokeExternalCommand: (
  277. type: ExternalCommandType,
  278. ...args: Array<any>
  279. ) => Promise<void>
  280. /**
  281. * Get state from app store
  282. * valid state is here
  283. * https://github.com/logseq/logseq/blob/master/src/main/frontend/state.cljs#L27
  284. *
  285. * @example
  286. * ```ts
  287. * const isDocMode = await logseq.App.getStateFromStore('document/mode?')
  288. * ```
  289. * @param path
  290. */
  291. getStateFromStore: <T = any>(path: string | Array<string>) => Promise<T>
  292. // native
  293. relaunch: () => Promise<void>
  294. quit: () => Promise<void>
  295. openExternalLink: (url: string) => Promise<void>
  296. /**
  297. * @deprecated Using `logseq.Git.execCommand`
  298. * @link https://github.com/desktop/dugite/blob/master/docs/api/exec.md
  299. * @param args
  300. */
  301. execGitCommand: (args: string[]) => Promise<string>
  302. // graph
  303. getCurrentGraph: () => Promise<AppGraphInfo | null>
  304. // router
  305. pushState: (
  306. k: string,
  307. params?: Record<string, any>,
  308. query?: Record<string, any>
  309. ) => void
  310. replaceState: (
  311. k: string,
  312. params?: Record<string, any>,
  313. query?: Record<string, any>
  314. ) => void
  315. // ui
  316. queryElementById: (id: string) => Promise<string | boolean>
  317. /**
  318. * @added 0.0.5
  319. * @param selector
  320. */
  321. queryElementRect: (selector: string) => Promise<DOMRectReadOnly | null>
  322. /**
  323. * @deprecated
  324. * @param content
  325. * @param status
  326. */
  327. showMsg: (
  328. content: string,
  329. status?: 'success' | 'warning' | 'error' | string
  330. ) => void
  331. setZoomFactor: (factor: number) => void
  332. setFullScreen: (flag: boolean | 'toggle') => void
  333. setLeftSidebarVisible: (flag: boolean | 'toggle') => void
  334. setRightSidebarVisible: (flag: boolean | 'toggle') => void
  335. registerUIItem: (
  336. type: 'toolbar' | 'pagebar',
  337. opts: { key: string; template: string }
  338. ) => void
  339. registerPageMenuItem: (
  340. tag: string,
  341. action: (e: IHookEvent & { page: string }) => void
  342. ) => void
  343. // hook events
  344. onCurrentGraphChanged: IUserHook
  345. onThemeModeChanged: IUserHook<{ mode: 'dark' | 'light' }>
  346. onBlockRendererSlotted: IUserSlotHook<{ uuid: BlockUUID }>
  347. /**
  348. * provide ui slot to block `renderer` macro for `{{renderer arg1, arg2}}`
  349. *
  350. * @example https://github.com/logseq/logseq-plugin-samples/tree/master/logseq-pomodoro-timer
  351. * @example
  352. * ```ts
  353. * // e.g. {{renderer :h1, hello world, green}}
  354. *
  355. * logseq.App.onMacroRendererSlotted(({ slot, payload: { arguments } }) => {
  356. * let [type, text, color] = arguments
  357. * if (type !== ':h1') return
  358. * logseq.provideUI({
  359. * key: 'h1-playground',
  360. * slot, template: `
  361. * <h2 style="color: ${color || 'red'}">${text}</h2>
  362. * `,
  363. * })
  364. * })
  365. * ```
  366. */
  367. onMacroRendererSlotted: IUserSlotHook<{
  368. payload: { arguments: Array<string>; uuid: string; [key: string]: any }
  369. }>
  370. onPageHeadActionsSlotted: IUserSlotHook
  371. onRouteChanged: IUserHook<{ path: string; template: string }>
  372. onSidebarVisibleChanged: IUserHook<{ visible: boolean }>
  373. // internal
  374. _installPluginHook: (pid: string, hook: string) => void
  375. _uninstallPluginHook: (pid: string, hookOrAll: string | boolean) => void
  376. }
  377. /**
  378. * Editor related APIs
  379. */
  380. export interface IEditorProxy extends Record<string, any> {
  381. /**
  382. * register a custom command which will be added to the Logseq slash command list
  383. * @param tag - displayed name of command
  384. * @param action - can be a single callback function to run when the command is called, or an array of fixed commands with arguments
  385. *
  386. *
  387. * @example https://github.com/logseq/logseq-plugin-samples/tree/master/logseq-slash-commands
  388. *
  389. * @example
  390. * ```ts
  391. * logseq.Editor.registerSlashCommand("Say Hi", () => {
  392. * console.log('Hi!')
  393. * })
  394. * ```
  395. *
  396. * @example
  397. * ```ts
  398. * logseq.Editor.registerSlashCommand("💥 Big Bang", [
  399. * ["editor/hook", "customCallback"],
  400. * ["editor/clear-current-slash"],
  401. * ]);
  402. * ```
  403. */
  404. registerSlashCommand: (
  405. tag: string,
  406. action: BlockCommandCallback | Array<SlashCommandAction>
  407. ) => unknown
  408. /**
  409. * register a custom command in the block context menu (triggered by right clicking the block dot)
  410. * @param tag - displayed name of command
  411. * @param action - can be a single callback function to run when the command is called
  412. */
  413. registerBlockContextMenuItem: (
  414. tag: string,
  415. action: BlockCommandCallback
  416. ) => unknown
  417. // block related APIs
  418. checkEditing: () => Promise<BlockUUID | boolean>
  419. insertAtEditingCursor: (content: string) => Promise<void>
  420. restoreEditingCursor: () => Promise<void>
  421. exitEditingMode: (selectBlock?: boolean) => Promise<void>
  422. getEditingCursorPosition: () => Promise<BlockCursorPosition | null>
  423. getEditingBlockContent: () => Promise<string>
  424. getCurrentPage: () => Promise<PageEntity | BlockEntity | null>
  425. getCurrentBlock: () => Promise<BlockEntity | null>
  426. getSelectedBlocks: () => Promise<Array<BlockEntity> | null>
  427. /**
  428. * get all blocks of the current page as a tree structure
  429. *
  430. * @example
  431. * ```ts
  432. * const blocks = await logseq.Editor.getCurrentPageBlocksTree()
  433. * initMindMap(blocks)
  434. * ```
  435. */
  436. getCurrentPageBlocksTree: () => Promise<Array<BlockEntity>>
  437. /**
  438. * get all blocks for the specified page
  439. *
  440. * @param srcPage - the page name or uuid
  441. */
  442. getPageBlocksTree: (srcPage: PageIdentity) => Promise<Array<BlockEntity>>
  443. /**
  444. * get all page/block linked references
  445. * @param srcPage
  446. */
  447. getPageLinkedReferences: (
  448. srcPage: PageIdentity
  449. ) => Promise<Array<[page: PageEntity, blocks: Array<BlockEntity>]> | null>
  450. /**
  451. * get flatten pages from top namespace
  452. * @param namespace
  453. */
  454. getPagesFromNamespace: (
  455. namespace: BlockPageName
  456. ) => Promise<Array<PageEntity> | null>
  457. /**
  458. * construct pages tree from namespace pages
  459. * @param namespace
  460. */
  461. getPagesTreeFromNamespace: (
  462. namespace: BlockPageName
  463. ) => Promise<Array<PageEntity> | null>
  464. /**
  465. * @example https://github.com/logseq/logseq-plugin-samples/tree/master/logseq-reddit-hot-news
  466. *
  467. * @param srcBlock
  468. * @param content
  469. * @param opts
  470. */
  471. insertBlock: (
  472. srcBlock: BlockIdentity,
  473. content: string,
  474. opts?: Partial<{
  475. before: boolean
  476. sibling: boolean
  477. isPageBlock: boolean
  478. properties: {}
  479. }>
  480. ) => Promise<BlockEntity | null>
  481. insertBatchBlock: (
  482. srcBlock: BlockIdentity,
  483. batch: IBatchBlock | Array<IBatchBlock>,
  484. opts?: Partial<{ before: boolean; sibling: boolean }>
  485. ) => Promise<Array<BlockEntity> | null>
  486. updateBlock: (
  487. srcBlock: BlockIdentity,
  488. content: string,
  489. opts?: Partial<{ properties: {} }>
  490. ) => Promise<void>
  491. removeBlock: (srcBlock: BlockIdentity) => Promise<void>
  492. getBlock: (
  493. srcBlock: BlockIdentity | EntityID,
  494. opts?: Partial<{ includeChildren: boolean }>
  495. ) => Promise<BlockEntity | null>
  496. /**
  497. * @example
  498. *
  499. * ```ts
  500. * logseq.Editor.setBlockCollapsed('uuid', true)
  501. * logseq.Editor.setBlockCollapsed('uuid', 'toggle')
  502. * ```
  503. * @param uuid
  504. * @param opts
  505. */
  506. setBlockCollapsed: (
  507. uuid: BlockUUID,
  508. opts: { flag: boolean | 'toggle' } | boolean | 'toggle'
  509. ) => Promise<void>
  510. getPage: (
  511. srcPage: PageIdentity | EntityID,
  512. opts?: Partial<{ includeChildren: boolean }>
  513. ) => Promise<PageEntity | null>
  514. createPage: (
  515. pageName: BlockPageName,
  516. properties?: {},
  517. opts?: Partial<{
  518. redirect: boolean
  519. createFirstBlock: boolean
  520. format: BlockEntity['format']
  521. journal: boolean
  522. }>
  523. ) => Promise<PageEntity | null>
  524. deletePage: (pageName: BlockPageName) => Promise<void>
  525. renamePage: (oldName: string, newName: string) => Promise<void>
  526. getAllPages: (repo?: string) => Promise<any>
  527. prependBlockInPage: (page: PageIdentity, content: string, opts?: Partial<{ properties: {} }>) => Promise<BlockEntity | null>
  528. appendBlockInPage: (page: PageIdentity, content: string, opts?: Partial<{ properties: {} }>) => Promise<BlockEntity | null>
  529. getPreviousSiblingBlock: (
  530. srcBlock: BlockIdentity
  531. ) => Promise<BlockEntity | null>
  532. getNextSiblingBlock: (srcBlock: BlockIdentity) => Promise<BlockEntity | null>
  533. moveBlock: (
  534. srcBlock: BlockIdentity,
  535. targetBlock: BlockIdentity,
  536. opts?: Partial<{ before: boolean; children: boolean }>
  537. ) => Promise<void>
  538. editBlock: (srcBlock: BlockIdentity, opts?: { pos: number }) => Promise<void>
  539. upsertBlockProperty: (
  540. block: BlockIdentity,
  541. key: string,
  542. value: any
  543. ) => Promise<void>
  544. removeBlockProperty: (block: BlockIdentity, key: string) => Promise<void>
  545. getBlockProperty: (block: BlockIdentity, key: string) => Promise<any>
  546. getBlockProperties: (block: BlockIdentity) => Promise<any>
  547. scrollToBlockInPage: (
  548. pageName: BlockPageName,
  549. blockId: BlockIdentity,
  550. opts?: { replaceState: boolean }
  551. ) => void
  552. openInRightSidebar: (uuid: BlockUUID) => void
  553. /**
  554. * @example https://github.com/logseq/logseq-plugin-samples/tree/master/logseq-a-translator
  555. */
  556. onInputSelectionEnd: IUserHook<{
  557. caret: any
  558. point: { x: number; y: number }
  559. start: number
  560. end: number
  561. text: string
  562. }>
  563. }
  564. /**
  565. * Datascript related APIs
  566. */
  567. export interface IDBProxy {
  568. /**
  569. * Run a DSL query
  570. * @link https://docs.logseq.com/#/page/queries
  571. * @param dsl
  572. */
  573. q: <T = any>(dsl: string) => Promise<Array<T> | null>
  574. /**
  575. * Run a datascript query
  576. */
  577. datascriptQuery: <T = any>(query: string, ...inputs: Array<any>) => Promise<T>
  578. /**
  579. * Hook all transaction data of DB
  580. *
  581. * @added 0.0.2
  582. */
  583. onChanged: IUserHook<{
  584. blocks: Array<BlockEntity>
  585. txData: Array<IDatom>
  586. txMeta?: { outlinerOp: string; [key: string]: any }
  587. }>
  588. /**
  589. * Subscribe a specific block changed event
  590. *
  591. * @added 0.0.2
  592. */
  593. onBlockChanged(
  594. uuid: BlockUUID,
  595. callback: (
  596. block: BlockEntity,
  597. txData: Array<IDatom>,
  598. txMeta?: { outlinerOp: string; [key: string]: any }
  599. ) => void
  600. ): IUserOffHook
  601. }
  602. /**
  603. * Git related APIS
  604. */
  605. export interface IGitProxy {
  606. /**
  607. * @added 0.0.2
  608. * @link https://github.com/desktop/dugite/blob/master/docs/api/exec.md
  609. * @param args
  610. */
  611. execCommand: (args: string[]) => Promise<IGitResult>
  612. loadIgnoreFile: () => Promise<string>
  613. saveIgnoreFile: (content: string) => Promise<void>
  614. }
  615. /**
  616. * UI related APIs
  617. */
  618. export type UIMsgOptions = {
  619. key: string
  620. timeout: number // milliseconds. `0` indicate that keep showing
  621. }
  622. export type UIMsgKey = UIMsgOptions['key']
  623. export interface IUIProxy {
  624. /**
  625. * @added 0.0.2
  626. *
  627. * @param content
  628. * @param status
  629. * @param opts
  630. */
  631. showMsg: (
  632. content: string,
  633. status?: 'success' | 'warning' | 'error' | string,
  634. opts?: Partial<UIMsgOptions>
  635. ) => Promise<UIMsgKey>
  636. closeMsg: (key: UIMsgKey) => void
  637. }
  638. /**
  639. * Assets related APIs
  640. */
  641. export interface IAssetsProxy {
  642. /**
  643. * @added 0.0.2
  644. * @param exts
  645. */
  646. listFilesOfCurrentGraph(
  647. exts: string | string[]
  648. ): Promise<{
  649. path: string
  650. size: number
  651. accessTime: number
  652. modifiedTime: number
  653. changeTime: number
  654. birthTime: number
  655. }>
  656. }
  657. export interface ILSPluginThemeManager extends EventEmitter {
  658. themes: Map<PluginLocalIdentity, Array<ThemeOptions>>
  659. registerTheme(id: PluginLocalIdentity, opt: ThemeOptions): Promise<void>
  660. unregisterTheme(id: PluginLocalIdentity): Promise<void>
  661. selectTheme(opt?: ThemeOptions): Promise<void>
  662. }
  663. export type LSPluginUserEvents = 'ui:visible:changed' | 'settings:changed'
  664. export interface ILSPluginUser extends EventEmitter<LSPluginUserEvents> {
  665. /**
  666. * Connection status with the main app
  667. */
  668. connected: boolean
  669. /**
  670. * Duplex message caller
  671. */
  672. caller: LSPluginCaller
  673. /**
  674. * The plugin configurations from package.json
  675. */
  676. baseInfo: LSPluginBaseInfo
  677. /**
  678. * The plugin user settings
  679. */
  680. settings?: LSPluginBaseInfo['settings']
  681. /**
  682. * The main Logseq app is ready to run the plugin
  683. *
  684. * @param model - same as the model in `provideModel`
  685. */
  686. ready(model?: Record<string, any>): Promise<any>
  687. /**
  688. * @param callback - a function to run when the main Logseq app is ready
  689. */
  690. ready(callback?: (e: any) => void | {}): Promise<any>
  691. ready(
  692. model?: Record<string, any>,
  693. callback?: (e: any) => void | {}
  694. ): Promise<any>
  695. beforeunload: (callback: () => Promise<void>) => void
  696. /**
  697. * Create a object to hold the methods referenced in `provideUI`
  698. *
  699. * @example
  700. * ```ts
  701. * logseq.provideModel({
  702. * openCalendar () {
  703. * console.log('Open the calendar!')
  704. * }
  705. * })
  706. * ```
  707. */
  708. provideModel(model: Record<string, any>): this
  709. /**
  710. * Set the theme for the main Logseq app
  711. */
  712. provideTheme(theme: ThemeOptions): this
  713. /**
  714. * Inject custom css for the main Logseq app
  715. *
  716. * @example https://github.com/logseq/logseq-plugin-samples/tree/master/logseq-awesome-fonts
  717. * @example
  718. * ```ts
  719. * logseq.provideStyle(`
  720. * @import url("https://at.alicdn.com/t/font_2409735_r7em724douf.css");
  721. * )
  722. * ```
  723. */
  724. provideStyle(style: StyleString | StyleOptions): this
  725. /**
  726. * Inject custom UI at specific DOM node.
  727. * Event handlers can not be passed by string, so you need to create them in `provideModel`
  728. *
  729. * @example https://github.com/logseq/logseq-plugin-samples/tree/master/logseq-a-translator
  730. * @example
  731. * ```ts
  732. * logseq.provideUI({
  733. * key: 'open-calendar',
  734. * path: '#search',
  735. * template: `
  736. * <a data-on-click="openCalendar" onclick="alert('abc')' style="opacity: .6; display: inline-flex; padding-left: 3px;'>
  737. * <i class="iconfont icon-Calendaralt2"></i>
  738. * </a>
  739. * `
  740. * })
  741. * ```
  742. */
  743. provideUI(ui: UIOptions): this
  744. /**
  745. * @example https://github.com/logseq/logseq-plugin-samples/tree/master/logseq-awesome-fonts
  746. *
  747. * @param schemas
  748. */
  749. useSettingsSchema(schemas: Array<SettingSchemaDesc>): this
  750. /**
  751. * @example https://github.com/logseq/logseq-plugin-samples/tree/master/logseq-awesome-fonts
  752. *
  753. * @param attrs
  754. */
  755. updateSettings(attrs: Record<string, any>): void
  756. onSettingsChanged<T = any>(cb: (a: T, b: T) => void): IUserOffHook
  757. showSettingsUI(): void
  758. hideSettingsUI(): void
  759. setMainUIAttrs(attrs: Record<string, any>): void
  760. /**
  761. * Set the style for the plugin's UI
  762. *
  763. * @example https://github.com/logseq/logseq-plugin-samples/tree/master/logseq-awesome-fonts
  764. * @example
  765. * ```ts
  766. * logseq.setMainUIInlineStyle({
  767. * position: 'fixed',
  768. * zIndex: 11,
  769. * })
  770. * ```
  771. */
  772. setMainUIInlineStyle(style: CSS.Properties): void
  773. /**
  774. * show the plugin's UI
  775. */
  776. showMainUI(opts?: { autoFocus: boolean }): void
  777. /**
  778. * hide the plugin's UI
  779. */
  780. hideMainUI(opts?: { restoreEditingCursor: boolean }): void
  781. /**
  782. * toggle the plugin's UI
  783. */
  784. toggleMainUI(): void
  785. isMainUIVisible: boolean
  786. resolveResourceFullUrl(filePath: string): string
  787. App: IAppProxy & Record<string, any>
  788. Editor: IEditorProxy & Record<string, any>
  789. DB: IDBProxy
  790. Git: IGitProxy
  791. UI: IUIProxy
  792. FileStorage: LSPluginFileStorage
  793. Experiments: LSPluginExperiments
  794. }