LSPlugin.ts 22 KB

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