'use strict' ;
var obsidian = require ( 'obsidian' ) ;
/ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
Copyright ( c ) Microsoft Corporation .
Permission to use , copy , modify , and / or distribute this software for any
purpose with or without fee is hereby granted .
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS . IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL , DIRECT ,
INDIRECT , OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
LOSS OF USE , DATA OR PROFITS , WHETHER IN AN ACTION OF CONTRACT , NEGLIGENCE OR
OTHER TORTIOUS ACTION , ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * /
function _ _awaiter ( thisArg , _arguments , P , generator ) {
function adopt ( value ) { return value instanceof P ? value : new P ( function ( resolve ) { resolve ( value ) ; } ) ; }
return new ( P || ( P = Promise ) ) ( function ( resolve , reject ) {
function fulfilled ( value ) { try { step ( generator . next ( value ) ) ; } catch ( e ) { reject ( e ) ; } }
function rejected ( value ) { try { step ( generator [ "throw" ] ( value ) ) ; } catch ( e ) { reject ( e ) ; } }
function step ( result ) { result . done ? resolve ( result . value ) : adopt ( result . value ) . then ( fulfilled , rejected ) ; }
step ( ( generator = generator . apply ( thisArg , _arguments || [ ] ) ) . next ( ) ) ;
} ) ;
}
function getAllExpandersQuery ( content ) {
let accum = [ ] ;
for ( var i = 0 ; i < content . length ; i ++ ) {
const line = content [ i ] ;
if ( line === '```expander' ) {
for ( var e = 0 ; e < content . length - i ; e ++ ) {
const nextline = content [ i + e ] ;
if ( nextline === '```' ) {
accum . push ( {
start : i ,
end : i + e ,
query : content [ i + 1 ] ,
template : e > 2 ? content . slice ( i + 2 , i + e ) . join ( '\n' ) : ''
} ) ;
break ;
}
}
}
}
return accum ;
}
function getClosestQuery ( queries , lineNumber ) {
if ( queries . length === 0 ) {
return undefined ;
}
return queries . reduce ( ( a , b ) => {
return Math . abs ( b . start - lineNumber ) < Math . abs ( a . start - lineNumber ) ? b : a ;
} ) ;
}
function getLastLineToReplace ( content , query , endline ) {
const lineFrom = query . end ;
for ( var i = lineFrom + 1 ; i < content . length ; i ++ ) {
if ( content [ i ] === endline ) {
return i ;
}
}
return lineFrom + 1 ;
}
const pick = ( obj , arr ) => arr . reduce ( ( acc , curr ) => {
return ( curr in obj )
? Object . assign ( { } , acc , { [ curr ] : obj [ curr ] } )
: acc ;
} , { } ) ;
// Functions for string processing
function splitByLines ( content ) {
return content . split ( '\n' ) ;
}
function removeEmptyLines ( s ) {
const lines = s . split ( '\n' ) . map ( e => e . trim ( ) ) ;
if ( lines . length < 2 ) {
return s ;
}
else if ( lines . indexOf ( '' ) === 0 ) {
return removeEmptyLines ( lines . slice ( 1 ) . join ( '\n' ) ) ;
}
return s ;
}
function removeFrontMatter ( s , lookEnding = false ) {
const lines = s . split ( '\n' ) ;
if ( lookEnding && lines . indexOf ( '---' ) === 0 ) {
return lines . slice ( 1 ) . join ( '\n' ) ;
}
else if ( lookEnding ) {
return removeFrontMatter ( lines . slice ( 1 ) . join ( '\n' ) , true ) ;
}
else if ( lines . indexOf ( '---' ) === 0 ) {
return removeFrontMatter ( lines . slice ( 1 ) . join ( '\n' ) , true ) ;
}
return s ;
}
function trimContent ( content ) {
return removeFrontMatter ( removeEmptyLines ( content ) ) ;
}
function getFrontMatter ( file , plugin , s ) {
const { frontmatter = null } = plugin . app . metadataCache . getCache ( file . path ) ;
if ( frontmatter ) {
return frontmatter [ s . split ( ':' ) [ 1 ] ] || '' ;
}
return '' ;
}
function getFileInfo ( plugin , file ) {
return _ _awaiter ( this , void 0 , void 0 , function * ( ) {
const info = Object . assign ( { } , file , {
content : file . extension === 'md' ? yield plugin . app . vault . cachedRead ( file ) : '' ,
link : plugin . app . fileManager . generateMarkdownLink ( file , file . name ) . replace ( /^!/ , '' )
} , plugin . app . metadataCache . getFileCache ( file ) ) ;
return pick ( info , [
'basename' ,
'content' ,
'extension' ,
'headings' ,
'link' , 'name' ,
'path' , 'sections' , 'stat' ,
'frontmatter' ,
'links' ,
'listItems'
] ) ;
} ) ;
}
function highlight ( lineStart , lineEnd , matchStart , matchEnd , lineContent ) {
return [
... lineContent . slice ( 0 , matchStart - lineStart ) ,
'==' ,
... lineContent . slice ( matchStart - lineStart , ( matchStart - lineStart ) + ( matchEnd - matchStart ) ) ,
'==' ,
... lineContent . slice ( ( matchStart - lineStart ) + ( matchEnd - matchStart ) ) ,
] . join ( '' ) ;
}
const sequences = [
{
name : '\\$count' ,
loop : true ,
format : ( _p , _s , _content , _file , _d , index ) => index ? String ( index + 1 ) : String ( 1 ) ,
desc : 'add index number to each produced file'
} ,
{
name : '\\$filename' ,
loop : true ,
format : ( _p , _s , _content , file ) => file . basename ,
desc : 'name of the founded file'
} ,
{
name : '\\$link' ,
loop : true ,
format : ( p , _s , _content , file ) => p . app . fileManager . generateMarkdownLink ( file , file . path ) . replace ( '![[' , '[[' ) ,
desc : 'link based on Obsidian settings'
} ,
{
name : '\\$lines:\\d+' ,
loop : true ,
readContent : true ,
format : ( p , s , content , _file ) => {
const digits = Number ( s . split ( ':' ) [ 1 ] ) ;
return trimContent ( content )
. split ( '\n' )
. filter ( ( _ , i ) => i < digits )
. join ( '\n' )
. replace ( new RegExp ( p . config . lineEnding , 'g' ) , '' ) ;
} ,
desc : 'specified count of lines from the found file'
} ,
{
name : '\\$characters:\\d+' ,
loop : true ,
readContent : true ,
format : ( p , s , content , _file ) => {
const digits = Number ( s . split ( ':' ) [ 1 ] ) ;
return trimContent ( content )
. split ( '' )
. filter ( ( _ , i ) => i < digits )
. join ( '' )
. replace ( new RegExp ( p . config . lineEnding , 'g' ) , '' ) ;
} ,
desc : 'specified count of lines from the found file'
} ,
{
name : '\\$frontmatter:[\\p\{L\}_-]+' ,
loop : true ,
format : ( p , s , _content , file ) => getFrontMatter ( file , p , s ) ,
desc : 'value from the frontmatter key in the found file'
} ,
{
name : '\\$lines+' ,
loop : true ,
readContent : true ,
format : ( p , s , content , _file ) => content . replace ( new RegExp ( p . config . lineEnding , 'g' ) , '' ) ,
desc : 'all content from the found file'
} ,
{
name : '\\$ext' ,
loop : true ,
format : ( _p , s , content , file ) => file . extension ,
desc : 'return file extension'
} ,
{
name : '\\$created:format:date' ,
loop : true ,
format : ( _p , s , content , file ) => String ( new Date ( file . stat . ctime ) . toISOString ( ) ) . split ( 'T' ) [ 0 ] ,
desc : 'created time formatted'
} ,
{
name : '\\$created:format:time' ,
loop : true ,
format : ( _p , s , content , file ) => String ( new Date ( file . stat . ctime ) . toISOString ( ) ) . split ( /([.T])/ ) [ 2 ] ,
desc : 'created time formatted'
} ,
{
name : '\\$created:format' ,
loop : true ,
format : ( _p , s , content , file ) => String ( new Date ( file . stat . ctime ) . toISOString ( ) ) ,
desc : 'created time formatted'
} ,
{
name : '\\$created' ,
loop : true ,
format : ( _p , s , content , file ) => String ( file . stat . ctime ) ,
desc : 'created time'
} ,
{
name : '\\$size' ,
loop : true ,
format : ( _p , s , content , file ) => String ( file . stat . size ) ,
desc : 'size of the file'
} ,
{
name : '\\$path' ,
loop : true ,
format : ( _p , s , content , file ) => file . path ,
desc : 'path to the found file'
} ,
{
name : '\\$parent' ,
loop : true ,
format : ( _p , s , content , file ) => file . parent . name ,
desc : 'parent folder name'
} ,
{
name : '^(.+|)\\$header:.+' ,
loop : true ,
format : ( p , s , content , file ) => {
var _a ;
const prefix = s . slice ( 0 , s . indexOf ( '$' ) ) ;
const header = s . slice ( s . indexOf ( '$' ) ) . replace ( '$header:' , '' ) . replace ( /"/g , '' ) ;
const neededLevel = header . split ( "#" ) . length - 1 ;
const neededTitle = header . replace ( /^#+/g , '' ) . trim ( ) ;
const metadata = p . app . metadataCache . getFileCache ( file ) ;
return ( ( _a = metadata . headings ) === null || _a === void 0 ? void 0 : _a . filter ( e => {
const tests = [
[ neededTitle , e . heading . includes ( neededTitle ) ] ,
[ neededLevel , e . level === neededLevel ]
] . filter ( e => e [ 0 ] ) ;
if ( tests . length ) {
return tests . map ( e => e [ 1 ] ) . every ( e => e === true ) ;
}
return true ;
} ) . map ( h => p . app . fileManager . generateMarkdownLink ( file , file . basename , '#' + h . heading ) ) . map ( link => prefix + link ) . join ( '\n' ) ) || '' ;
} ,
desc : 'headings from founded files. $header:## - return all level 2 headings. $header:Title - return all heading which match the string. Can be prepended like: - !$header:## to transclude the headings.'
} ,
{
name : '^(.+|)\\$blocks' ,
readContent : true ,
loop : true ,
format : ( p , s , content , file ) => {
const prefix = s . slice ( 0 , s . indexOf ( '$' ) ) ;
return content
. split ( '\n' )
. filter ( e => / \ ^ \ w + $ / . test ( e ) )
. map ( e => prefix + p . app . fileManager . generateMarkdownLink ( file , file . basename , '#' + e . replace ( /^.+?(\^\w+$)/ , '$1' ) ) )
. join ( '\n' ) ;
} ,
desc : 'block ids from the found files. Can be prepended.'
} ,
{
name : '^(.+|)\\$match:header' , loop : true , format : ( p , s , content , file , results ) => {
var _a ;
const prefix = s . slice ( 0 , s . indexOf ( '$' ) ) ;
const metadata = p . app . metadataCache . getFileCache ( file ) ;
const headings = ( _a = metadata . headings ) === null || _a === void 0 ? void 0 : _a . filter ( h => results . result . content . filter ( c => h . position . end . offset < c [ 0 ] ) . some ( e => e ) ) . slice ( - 1 ) ;
return headings
. map ( h => p . app . fileManager . generateMarkdownLink ( file , file . basename , '#' + h . heading ) )
. map ( link => prefix + link )
. join ( '\n' ) || '' ;
} , desc : 'extract found selections'
} ,
{
name : '^(.+|)\\$matchline(:(\\+|-|)\\d+:\\d+|:(\\+|-|)\\d+|)' ,
loop : true ,
format : ( _p , s , content , file , results ) => {
const prefix = s . slice ( 0 , s . indexOf ( '$matchline' ) ) ;
const [ keyword , context , limit ] = s . slice ( s . indexOf ( '$matchline' ) ) . split ( ':' ) ;
const value = context || '' ;
const limitValue = Number ( limit ) ;
const isPlus = value . contains ( '+' ) ;
const isMinus = value . contains ( '-' ) ;
const isContext = ! isPlus && ! isMinus ;
const offset = Number ( value . replace ( /[+-]/ , '' ) ) ;
const lines = results . content . split ( '\n' ) ;
// Grab info about line content, index, text length and start/end character position
const lineInfos = [ ] ;
for ( let i = 0 ; i < lines . length ; i ++ ) {
const text = lines [ i ] ;
if ( i === 0 ) {
lineInfos . push ( {
num : 0 ,
start : 0 ,
end : text . length ,
text
} ) ;
continue ;
}
const start = lineInfos [ i - 1 ] . end + 1 ;
lineInfos . push ( {
num : i ,
start ,
text ,
end : text . length + start
} ) ;
}
return results . result . content . map ( ( [ from , to ] ) => {
const matchedLines = lineInfos
. filter ( ( { start , end } ) => start <= from && end >= to )
. map ( ( line ) => {
return Object . assign ( Object . assign ( { } , line ) , { text : highlight ( line . start , line . end , from , to , line . text ) } ) ;
} ) ;
const resultLines = [ ] ;
for ( const matchedLine of matchedLines ) {
const prevLines = isMinus || isContext
? lineInfos . filter ( l => matchedLine . num - l . num > 0 && matchedLine . num - l . num < offset )
: [ ] ;
const nextLines = isPlus || isContext
? lineInfos . filter ( l => l . num - matchedLine . num > 0 && l . num - matchedLine . num < offset )
: [ ] ;
resultLines . push ( ... prevLines , matchedLine , ... nextLines ) ;
}
return prefix + resultLines . map ( e => e . text ) . join ( '\n' ) ;
} ) . map ( line => limitValue ? line . slice ( 0 , limitValue ) : line ) . join ( '\n' ) ;
} , desc : 'extract line with matches'
} ,
{
name : '^(.+|)\\$searchresult' ,
loop : true ,
desc : '' ,
format : ( _p , s , content , file , results ) => {
const prefix = s . slice ( 0 , s . indexOf ( '$searchresult' ) ) ;
return results . children . map ( matchedFile => {
return prefix + matchedFile . el . innerText ;
} ) . join ( '\n' ) ;
}
} ,
{
name : '^(.+|)\\$match' , loop : true , format : ( _p , s , content , file , results ) => {
if ( ! results . result . content ) {
console . warn ( 'There is no content in results' ) ;
return '' ;
}
function appendPrefix ( prefix , line ) {
return prefix + line ;
}
const prefixContent = s . slice ( 0 , s . indexOf ( '$' ) ) ;
return results . result . content
. map ( ( [ from , to ] ) => results . content . slice ( from , to ) )
. map ( line => appendPrefix ( prefixContent , line ) )
. join ( '\n' ) ;
} , desc : 'extract found selections'
} ,
] ;
function extractFilesFromSearchResults ( searchResults , currentFileName , excludeCurrent = true ) {
const files = Array . from ( searchResults . keys ( ) ) ;
return excludeCurrent
? files . filter ( file => file . basename !== currentFileName )
: files ;
}
var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : { } ;
function createCommonjsModule ( fn , basedir , module ) {
return module = {
path : basedir ,
exports : { } ,
require : function ( path , base ) {
return commonjsRequire ( path , ( base === undefined || base === null ) ? module . path : base ) ;
}
} , fn ( module , module . exports ) , module . exports ;
}
function commonjsRequire ( ) {
throw new Error ( 'Dynamic requires are not currently supported by @rollup/plugin-commonjs' ) ;
}
var eta _min = createCommonjsModule ( function ( module , exports ) {
! function ( e , n ) { n ( exports ) ; } ( commonjsGlobal , ( function ( e ) { function n ( e ) { var t , r , i = new Error ( e ) ; return t = i , r = n . prototype , Object . setPrototypeOf ? Object . setPrototypeOf ( t , r ) : t . _ _proto _ _ = r , i } function t ( e , t , r ) { var i = t . slice ( 0 , r ) . split ( /\n/ ) , a = i . length , o = i [ a - 1 ] . length + 1 ; throw n ( e += " at line " + a + " col " + o + ":\n\n " + t . split ( /\n/ ) [ a - 1 ] + "\n " + Array ( o ) . join ( " " ) + "^" ) } n . prototype = Object . create ( Error . prototype , { name : { value : "Eta Error" , enumerable : ! 1 } } ) ; var r = new Function ( "return this" ) ( ) . Promise ; function i ( e , n ) { for ( var t in n ) r = n , i = t , Object . prototype . hasOwnProperty . call ( r , i ) && ( e [ t ] = n [ t ] ) ; var r , i ; return e } function a ( e , n , t , r ) { var i , a ; return Array . isArray ( n . autoTrim ) ? ( i = n . autoTrim [ 1 ] , a = n . autoTrim [ 0 ] ) : i = a = n . autoTrim , ( t || ! 1 === t ) && ( i = t ) , ( r || ! 1 === r ) && ( a = r ) , a || i ? "slurp" === i && "slurp" === a ? e . trim ( ) : ( "_" === i || "slurp" === i ? e = function ( e ) { return String . prototype . trimLeft ? e . trimLeft ( ) : e . replace ( /^\s+/ , "" ) } ( e ) : "-" !== i && "nl" !== i || ( e = e . replace ( /^(?:\r\n|\n|\r)/ , "" ) ) , "_" === a || "slurp" === a ? e = function ( e ) { return String . prototype . trimRight ? e . trimRight ( ) : e . replace ( /\s+$/ , "" ) } ( e ) : "-" !== a && "nl" !== a || ( e = e . replace ( /(?:\r\n|\n|\r)$/ , "" ) ) , e ) : e } var o = { "&" : "&" , "<" : "<" , ">" : ">" , '"' : """ , "'" : "'" } ; function c ( e ) { return o [ e ] } var s = /`(?:\\[\s\S]|\${(?:[^{}]|{(?:[^{}]|{[^}]*})*})*}|(?!\${)[^\\`])*`/g , l = /'(?:\\[\s\w"'\\`]|[^\n\r'\\])*?'/g , u = /"(?:\\[\s\w"'\\`]|[^\n\r"\\])*?"/g ; function p ( e ) { return e . replace ( /[.*+\-?^${}()|[\]\\]/g , "\\$&" ) } function f ( e , n ) { var r = [ ] , i = ! 1 , o = 0 , c = n . parse ; if ( n . plugins ) for ( var f = 0 ; f < n . plugins . length ; f ++ ) { ( T = n . plugins [ f ] ) . processTemplate && ( e = T . processTemplate ( e , n ) ) ; } function d ( e , t ) { e && ( e = a ( e , n , i , t ) ) && ( e = e . replace ( /\\|'/g , "\\$&" ) . replace ( /\r\n|\n|\r/g , "\\n" ) , r . push ( e ) ) ; } n . rmWhitespace && ( e = e . replace ( /[\r\n]+/g , "\n" ) . replace ( /^\s+|\s+$/gm , "" ) ) , s . lastIndex = 0 , l . lastIndex = 0 , u . lastIndex = 0 ; for ( var g , h = [ c . exec , c . interpolate , c . raw ] . reduce ( ( function ( e , n ) { return e && n ? e + "|" + p ( n ) : n ? p ( n ) : e } ) , "" ) , m = new RegExp ( "([^]*?)" + p ( n . tags [ 0 ] ) + "(-|_)?\\s*(" + h + ")?\\s*" , "g" ) , v = new RegExp ( "'|\"|`|\\/\\*|(\\s*(-|_)?" + p ( n . tags [ 1 ] ) + ")" , "g" ) ; g = m . exec ( e ) ; ) { o = g [ 0 ] . length + g . index ; var y = g [ 1 ] , x = g [ 2 ] , _ = g [ 3 ] || "" ; d ( y , x ) , v . lastIndex = o ; for ( var w = void 0 , b = ! 1 ; w = v . exec ( e ) ; ) { if ( w [ 1 ] ) { var E = e . slice ( o , w . index ) ; m . lastIndex = o = v . lastIndex , i = w [ 2 ] , b = { t : _ === c . exec ? "e" : _ === c . raw ? "r" : _ === c . interpolate ? "i" : "" , val : E } ; break } var I = w [ 0 ] ; if ( "/*" === I ) { var R = e . indexOf ( "*/" , v . lastIndex ) ; - 1 === R && t ( "unclosed comment" , e , w . index ) , v . lastIndex = R ; } else if ( "'" === I ) { l . lastIndex = w . index , l . exec ( e ) ? v . lastIndex = l . lastIndex : t ( "unclosed string" , e , w . index ) ; } else if ( '"' === I ) { u . lastIndex = w . index , u . exec ( e ) ? v . lastIndex = u . lastIndex : t ( "unclosed string" , e , w . index ) ; } else if ( "`" === I ) { s . lastIndex = w . index , s . exec ( e ) ? v . lastIndex = s . lastIndex : t ( "unclosed string" , e , w . index ) ; } } b ? r . push ( b ) : t ( "unclosed tag" , e , g . index + y . length ) ; } if ( d ( e . slice ( o , e . length ) , ! 1 ) , n . plugins ) for ( f = 0 ; f < n . plugins . length ; f ++ ) { var T ; ( T = n . plugins [ f ] ) . processAST && ( r = T . processAST ( r , n ) ) ; } return r } function d ( e , n ) { var t = f ( e , n ) , r = "var tR='',__l,__lP" + ( n . include ? ",include=E.include.bind(E)" : "" ) + ( n . includeFile ? ",includeFile=E.includeFile.bind(E)" : "" ) + "\nfunction layout(p,d){__l=p;__lP=d}\n" + ( n . useWith ? "with(" + n . varName + "||{}){" : "" ) + function ( e , n ) { var t = 0 , r = e . length , i = "" ; for ( ; t < r ; t ++ ) { var a = e [ t ] ; if ( "string" == typeof a ) { i += "tR+='" + a + "'\n" ; } else { var o = a . t , c = a . val || "" ; "r" === o ? ( n . filter && ( c = "E.filter(" + c + ")" ) , i += "tR+=" + c + "\n" ) : "i" === o ? ( n . filter && ( c = "E.filter(" + c + ")" ) , n . autoEscape && ( c = "E.e(" + c + ")" ) , i += "tR+=" + c + "\n" ) : "e" === o && ( i += c + "\n" ) ; } } return i } ( t , n ) + ( n . includeFile ? "if(__l)tR=" + ( n . async ? "await " : "" ) + "includeFile(__l,Object.assign(" + n . varName + ",{body:tR},__lP))\n" : n . include ? "if(__l)tR=" + ( n . async ? "await " : "" ) + "include(__l,Object.assign(" + n . varName + ",{body:tR},__lP))\n" : "" ) + "if(cb){cb(null,tR)} return tR" + ( n . useWith ? "}" : "" ) ; if ( n . plugins ) for ( var i = 0 ; i < n . plugins . length ; i ++ ) { var a = n . plugins [ i ] ; a . processFnString && ( r = a . processFnString ( r , n ) ) ; } return r } var g = new ( function ( ) { function e ( e ) { this . cache = e ; } return e . prototype . define = function ( e , n ) { this . cache [ e ] = n ; } , e . prototype . get = function ( e ) { return this . cache [ e ] } , e . prototype . remove = function ( e ) { delete this . cache [ e ] ; } , e . prototype . reset = function ( ) { thi
} ) ;
class TextExpander extends obsidian . Plugin {
constructor ( app , plugin ) {
super ( app , plugin ) ;
this . config = {
autoExpand : false ,
defaultTemplate : '- $link' ,
delay : 300 ,
excludeCurrent : true ,
lineEnding : '<-->' ,
prefixes : {
header : '^' ,
footer : '>'
}
} ;
this . seqs = sequences ;
this . leftPanelInfo = {
collapsed : false ,
tab : 0 ,
text : ''
} ;
this . search = this . search . bind ( this ) ;
this . init = this . init . bind ( this ) ;
this . autoExpand = this . autoExpand . bind ( this ) ;
}
autoExpand ( ) {
return _ _awaiter ( this , void 0 , void 0 , function * ( ) {
if ( ! this . config . autoExpand ) {
return ;
}
const activeLeaf = this . app . workspace . activeLeaf ;
if ( ! activeLeaf ) {
return ;
}
const activeView = activeLeaf . view ;
const isAllowedView = activeView instanceof obsidian . MarkdownView ;
if ( ! isAllowedView ) {
return ;
}
yield this . init ( true ) ;
} ) ;
}
onload ( ) {
return _ _awaiter ( this , void 0 , void 0 , function * ( ) {
this . addSettingTab ( new SettingTab ( this . app , this ) ) ;
this . registerMarkdownCodeBlockProcessor ( 'expander' , ( source , el , ctx ) => {
el
. createDiv ( )
. createEl ( 'button' , { text : 'Run expand query' } )
. addEventListener ( 'click' , this . init . bind ( this , false , ctx . getSectionInfo ( el ) . lineStart ) ) ;
} ) ;
this . addCommand ( {
id : 'editor-expand' ,
name : 'expand' ,
callback : this . init ,
hotkeys : [ ]
} ) ;
this . addCommand ( {
id : 'editor-expand-all' ,
name : 'expand all' ,
callback : ( ) => this . init ( true ) ,
hotkeys : [ ]
} ) ;
this . app . workspace . on ( 'file-open' , this . autoExpand ) ;
const data = yield this . loadData ( ) ;
if ( data ) {
this . config = Object . assign ( Object . assign ( { } , this . config ) , data ) ;
}
} ) ;
}
onunload ( ) {
console . log ( 'unloading plugin' ) ;
this . app . workspace . off ( 'file-open' , this . autoExpand ) ;
}
saveSettings ( ) {
return _ _awaiter ( this , void 0 , void 0 , function * ( ) {
yield this . saveData ( this . config ) ;
} ) ;
}
init ( proceedAllQueriesOnPage = false , lineToStart ) {
return _ _awaiter ( this , void 0 , void 0 , function * ( ) {
const currentView = this . app . workspace . activeLeaf . view ;
// Is on editable view
if ( ! ( currentView instanceof obsidian . MarkdownView ) ) {
return ;
}
const cmDoc = this . cm = currentView . editor ;
const curNum = lineToStart || cmDoc . getCursor ( ) . line ;
const content = cmDoc . getValue ( ) ;
if ( lineToStart ) {
cmDoc . setCursor ( lineToStart ? lineToStart - 1 : 0 ) ;
}
const formatted = splitByLines ( content ) ;
const findQueries = getAllExpandersQuery ( formatted ) ;
const closestQuery = getClosestQuery ( findQueries , curNum ) ;
if ( proceedAllQueriesOnPage ) {
yield findQueries . reduce ( ( promise , query , i ) => promise . then ( ( ) => {
const newContent = splitByLines ( cmDoc . getValue ( ) ) ;
const updatedQueries = getAllExpandersQuery ( newContent ) ;
return this . runExpanderCodeBlock ( updatedQueries [ i ] , newContent , currentView ) ;
} ) , Promise . resolve ( ) ) ;
}
else {
yield this . runExpanderCodeBlock ( closestQuery , formatted , currentView ) ;
}
} ) ;
}
runExpanderCodeBlock ( query , content , view ) {
return _ _awaiter ( this , void 0 , void 0 , function * ( ) {
const { lineEnding , prefixes } = this . config ;
if ( ! query ) {
new Notification ( 'Expand query not found' ) ;
return Promise . resolve ( ) ;
}
this . clearOldResultsInFile ( content , query , lineEnding ) ;
const newContent = splitByLines ( this . cm . getValue ( ) ) ;
if ( query . query !== '' ) {
this . search ( query . query ) ;
}
return yield this . runTemplateProcessing ( query , getLastLineToReplace ( newContent , query , this . config . lineEnding ) , prefixes , view ) ;
} ) ;
}
runTemplateProcessing ( query , lastLine , prefixes , currentView ) {
var _a ;
return _ _awaiter ( this , void 0 , void 0 , function * ( ) {
let currentFileName = '' ;
const templateContent = query . template . split ( '\n' ) ;
const { heading , footer , repeatableContent } = this . parseTemplate ( prefixes , templateContent ) ;
if ( currentView instanceof obsidian . FileView ) {
currentFileName = currentView . file . basename ;
}
this . saveLeftPanelState ( ) ;
const searchResults = yield this . getFoundAfterDelay ( query . query === '' ) ;
const files = extractFilesFromSearchResults ( searchResults , currentFileName , this . config . excludeCurrent ) ;
this . restoreLeftPanelState ( ) ;
currentView . editor . focus ( ) ;
const currentFileInfo = ( currentView instanceof obsidian . FileView )
? yield getFileInfo ( this , currentView . file )
: { } ;
const filesInfo = yield Promise . all ( files . map ( file => getFileInfo ( this , file ) ) ) ;
let changed ;
if ( query . template . contains ( "<%" ) ) {
const templateToRender = repeatableContent . join ( '\n' ) ;
const dataToRender = {
current : currentFileInfo ,
files : filesInfo
} ;
changed = yield eta _min . render ( templateToRender , dataToRender , { autoEscape : false } ) ;
// changed = doT.template(templateToRender, {strip: false})(dataToRender)
}
else {
changed = yield this . generateTemplateFromSequences ( files , repeatableContent , searchResults ) ;
}
let result = [
heading ,
changed ,
footer ,
this . config . lineEnding
] . filter ( e => e ) . join ( '\n' ) ;
// Do not paste generated content if used changed activeLeaf
const viewBeforeReplace = this . app . workspace . activeLeaf . view ;
if ( ! ( viewBeforeReplace instanceof obsidian . MarkdownView ) || viewBeforeReplace . file . basename !== currentFileName ) {
return ;
}
currentView . editor . replaceRange ( result , { line : query . end + 1 , ch : 0 } , { line : lastLine , ch : ( ( _a = this . cm . getLine ( lastLine ) ) === null || _a === void 0 ? void 0 : _a . length ) || 0 } ) ;
return Promise . resolve ( ) ;
} ) ;
}
generateTemplateFromSequences ( files , repeatableContent , searchResults ) {
return _ _awaiter ( this , void 0 , void 0 , function * ( ) {
if ( ! searchResults ) {
return '' ;
}
const changed = yield Promise . all ( files
. map ( ( file , i ) => _ _awaiter ( this , void 0 , void 0 , function * ( ) {
const result = yield Promise . all ( repeatableContent . map ( ( s ) => _ _awaiter ( this , void 0 , void 0 , function * ( ) { return yield this . applyTemplateToSearchResults ( searchResults , file , s , i ) ; } ) ) ) ;
return result . join ( '\n' ) ;
} ) ) ) ;
return changed . join ( '\n' ) ;
} ) ;
}
parseTemplate ( prefixes , templateContent ) {
const isHeader = ( line ) => line . startsWith ( prefixes . header ) ;
const isFooter = ( line ) => line . startsWith ( prefixes . footer ) ;
const isRepeat = ( line ) => ! isHeader ( line ) && ! isFooter ( line ) ;
const heading = templateContent . filter ( isHeader ) . map ( ( s ) => s . slice ( 1 ) ) . join ( '\n' ) ;
const footer = templateContent . filter ( isFooter ) . map ( ( s ) => s . slice ( 1 ) ) . join ( '\n' ) ;
const repeatableContent = templateContent . filter ( isRepeat ) . filter ( e => e ) . length === 0
? [ this . config . defaultTemplate ]
: templateContent . filter ( isRepeat ) . filter ( e => e ) ;
return { heading , footer , repeatableContent } ;
}
saveLeftPanelState ( ) {
this . leftPanelInfo = {
collapsed : this . app . workspace . leftSplit . collapsed ,
tab : this . getSearchTabIndex ( ) ,
text : this . getSearchValue ( ) ,
} ;
}
restoreLeftPanelState ( ) {
const { collapsed , tab , text } = this . leftPanelInfo ;
const splitChildren = this . getLeftSplitElement ( ) ;
this . getSearchView ( ) . searchComponent . setValue ( text ) ;
if ( tab !== splitChildren . currentTab ) {
splitChildren . selectTabIndex ( tab ) ;
}
if ( collapsed ) {
this . app . workspace . leftSplit . collapse ( ) ;
}
}
search ( s ) {
// @ts-ignore
const globalSearchFn = this . app . internalPlugins . getPluginById ( 'global-search' ) . instance . openGlobalSearch . bind ( this ) ;
const search = ( query ) => globalSearchFn ( query ) ;
search ( s ) ;
}
getLeftSplitElement ( ) {
// @ts-ignore
return this . app . workspace . leftSplit . children [ 0 ] ;
}
getSearchView ( ) {
const view = this . getLeftSplitElement ( ) . children . filter ( e => e . getViewState ( ) . type === 'search' ) [ 0 ] . view ;
if ( 'searchComponent' in view ) {
return view ;
}
return undefined ;
}
getSearchValue ( ) {
const view = this . getSearchView ( ) ;
if ( view ) {
return view . searchComponent . getValue ( ) ;
}
return '' ;
}
getSearchTabIndex ( ) {
const leftTabs = this . getLeftSplitElement ( ) . children ;
let searchTabId ;
this . app . workspace . iterateAllLeaves ( ( leaf ) => {
if ( leaf . getViewState ( ) . type == "search" ) {
searchTabId = leaf . id ;
}
} ) ;
return leftTabs . findIndex ( ( item , _index , _array ) => {
if ( item . id == searchTabId ) {
return true ;
}
} ) ;
}
;
getFoundAfterDelay ( immediate ) {
return _ _awaiter ( this , void 0 , void 0 , function * ( ) {
const searchLeaf = this . app . workspace . getLeavesOfType ( 'search' ) [ 0 ] ;
const view = yield searchLeaf . open ( searchLeaf . view ) ;
if ( immediate ) {
// @ts-ignore
return Promise . resolve ( view . dom . resultDomLookup ) ;
}
return new Promise ( resolve => {
setTimeout ( ( ) => {
// @ts-ignore
return resolve ( view . dom . resultDomLookup ) ;
} , this . config . delay ) ;
} ) ;
} ) ;
}
applyTemplateToSearchResults ( searchResults , file , template , index ) {
return _ _awaiter ( this , void 0 , void 0 , function * ( ) {
const fileContent = ( new RegExp ( this . seqs . filter ( e => e . readContent ) . map ( e => e . name ) . join ( '|' ) ) . test ( template ) )
? yield this . app . vault . cachedRead ( file )
: '' ;
return this . seqs . reduce ( ( acc , seq ) => acc . replace ( new RegExp ( seq . name , 'gu' ) , replace => seq . format ( this , replace , fileContent , file , searchResults . get ( file ) , index ) ) , template ) ;
} ) ;
}
clearOldResultsInFile ( content , query , lineEnding ) {
var _a ;
const lastLine = getLastLineToReplace ( content , query , this . config . lineEnding ) ;
this . cm . replaceRange ( '\n' + lineEnding , { line : query . end + 1 , ch : 0 } , { line : lastLine , ch : ( ( _a = this . cm . getLine ( lastLine ) ) === null || _a === void 0 ? void 0 : _a . length ) || 0 } ) ;
}
}
class SettingTab extends obsidian . PluginSettingTab {
constructor ( app , plugin ) {
super ( app , plugin ) ;
this . app = app ;
this . plugin = plugin ;
}
display ( ) {
let { containerEl } = this ;
containerEl . empty ( ) ;
containerEl . createEl ( 'h2' , { text : 'Settings for Text Expander' } ) ;
new obsidian . Setting ( containerEl )
. setName ( 'Auto Expand' )
. setDesc ( 'Expand all queries in a file once you open it' )
. addToggle ( toggle => {
toggle
. setValue ( this . plugin . config . autoExpand )
. onChange ( value => {
this . plugin . config . autoExpand = value ;
this . plugin . saveSettings ( ) ;
} ) ;
} ) ;
new obsidian . Setting ( containerEl )
. setName ( 'Delay' )
. setDesc ( 'Text expander don\' wait until search completed. It waits for a delay and paste result after that.' )
. addSlider ( slider => {
slider . setLimits ( 100 , 10000 , 100 ) ;
slider . setValue ( this . plugin . config . delay ) ;
slider . onChange ( value => {
this . plugin . config . delay = value ;
this . plugin . saveSettings ( ) ;
} ) ;
slider . setDynamicTooltip ( ) ;
} ) ;
new obsidian . Setting ( containerEl )
. setName ( 'Line ending' )
. setDesc ( 'You can specify the text which will appear at the bottom of the generated text.' )
. addText ( text => {
text . setValue ( this . plugin . config . lineEnding )
. onChange ( val => {
this . plugin . config . lineEnding = val ;
this . plugin . saveSettings ( ) ;
} ) ;
} ) ;
new obsidian . Setting ( containerEl )
. setName ( 'Default template' )
. setDesc ( 'You can specify default template' )
. addTextArea ( text => {
text . setValue ( this . plugin . config . defaultTemplate )
. onChange ( val => {
this . plugin . config . defaultTemplate = val ;
this . plugin . saveSettings ( ) ;
} ) ;
} ) ;
new obsidian . Setting ( containerEl )
. setName ( 'Exclude current file' )
. setDesc ( 'You can specify should text expander exclude results from current file or not' )
. addToggle ( toggle => {
toggle
. setValue ( this . plugin . config . excludeCurrent )
. onChange ( value => {
this . plugin . config . excludeCurrent = value ;
this . plugin . saveSettings ( ) ;
} ) ;
} ) ;
new obsidian . Setting ( containerEl )
. setHeading ( )
. setName ( 'Prefixes' ) ;
new obsidian . Setting ( containerEl )
. setName ( 'Header' )
. setDesc ( 'Line prefixed by this symbol will be recognized as header' )
. addText ( text => {
text . setValue ( this . plugin . config . prefixes . header )
. onChange ( val => {
this . plugin . config . prefixes . header = val ;
this . plugin . saveSettings ( ) ;
} ) ;
} ) ;
new obsidian . Setting ( containerEl )
. setName ( 'Footer' )
. setDesc ( 'Line prefixed by this symbol will be recognized as footer' )
. addText ( text => {
text . setValue ( this . plugin . config . prefixes . footer )
. onChange ( val => {
this . plugin . config . prefixes . footer = val ;
this . plugin . saveSettings ( ) ;
} ) ;
} ) ;
new obsidian . Setting ( containerEl )
. setName ( 'Sequences' )
. setDesc ( 'REGEXP - DESCRIPTION' )
. setDesc ( ( ( ) => {
const fragment = new DocumentFragment ( ) ;
const div = fragment . createEl ( 'div' ) ;
this . plugin . seqs
. map ( e => e . name + ' - ' + ( e . desc || '' ) )
. map ( e => {
const el = fragment . createEl ( 'div' ) ;
el . setText ( e ) ;
el . setAttribute ( 'style' , `
border - bottom : 1 px solid rgba ( 255 , 255 , 255 , 0.1 ) ;
margin - bottom : 0.5 rem ;
padding - bottom : 0.5 rem ;
` );
return el ;
} ) . forEach ( el => {
div . appendChild ( el ) ;
} ) ;
fragment . appendChild ( div ) ;
return fragment ;
} ) ( ) ) ;
}
}
module . exports = TextExpander ;
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibWFpbi5qcyIsInNvdXJjZXMiOlsibm9kZV9tb2R1bGVzL3RzbGliL3RzbGliLmVzNi5qcyIsInNyYy9oZWxwZXJzL2hlbHBlcnMudHMiLCJzcmMvaGVscGVycy9zdHJpbmcudHMiLCJzcmMvaGVscGVycy90ZmlsZS50cyIsInNyYy9zZXF1ZW5jZXMvc2VxdWVuY2VzLnRzIiwic3JjL2hlbHBlcnMvc2VhcmNoLXJlc3VsdHMudHMiLCJub2RlX21vZHVsZXMvZXRhL2Rpc3QvYnJvd3Nlci9ldGEubWluLmpzIiwic3JjL21haW4udHMiXSwic291cmNlc0NvbnRlbnQiOlsiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5Db3B5cmlnaHQgKGMpIE1pY3Jvc29mdCBDb3Jwb3JhdGlvbi5cclxuXHJcblBlcm1pc3Npb24gdG8gdXNlLCBjb3B5LCBtb2RpZnksIGFuZC9vciBkaXN0cmlidXRlIHRoaXMgc29mdHdhcmUgZm9yIGFueVxyXG5wdXJwb3NlIHdpdGggb3Igd2l0aG91dCBmZWUgaXMgaGVyZWJ5IGdyYW50ZWQuXHJcblxyXG5USEUgU09GVFdBUkUgSVMgUFJPVklERUQgXCJBUyBJU1wiIEFORCBUSEUgQVVUSE9SIERJU0NMQUlNUyBBTEwgV0FSUkFOVElFUyBXSVRIXHJcblJFR0FSRCBUTyBUSElTIFNPRlRXQVJFIElOQ0xVRElORyBBTEwgSU1QTElFRCBXQVJSQU5USUVTIE9GIE1FUkNIQU5UQUJJTElUWVxyXG5BTkQgRklUTkVTUy4gSU4gTk8gRVZFTlQgU0hBTEwgVEhFIEFVVEhPUiBCRSBMSUFCTEUgRk9SIEFOWSBTUEVDSUFMLCBESVJFQ1QsXHJcbklORElSRUNULCBPUiBDT05TRVFVRU5USUFMIERBTUFHRVMgT1IgQU5ZIERBTUFHRVMgV0hBVFNPRVZFUiBSRVNVTFRJTkcgRlJPTVxyXG5MT1NTIE9GIFVTRSwgREFUQSBPUiBQUk9GSVRTLCBXSEVUSEVSIElOIEFOIEFDVElPTiBPRiBDT05UUkFDVCwgTkVHTElHRU5DRSBPUlxyXG5PVEhFUiBUT1JUSU9VUyBBQ1RJT04sIEFSSVNJTkcgT1VUIE9GIE9SIElOIENPTk5FQ1RJT04gV0lUSCBUSEUgVVNFIE9SXHJcblBFUkZPUk1BTkNFIE9GIFRISVMgU09GVFdBUkUuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqICovXHJcbi8qIGdsb2JhbCBSZWZsZWN0LCBQcm9taXNlICovXHJcblxyXG52YXIgZXh0ZW5kU3RhdGljcyA9IGZ1bmN0aW9uKGQsIGIpIHtcclxuICAgIGV4dGVuZFN0YXRpY3MgPSBPYmplY3Quc2V0UHJvdG90eXBlT2YgfHxcclxuICAgICAgICAoeyBfX3Byb3RvX186IFtdIH0gaW5zdGFuY2VvZiBBcnJheSAmJiBmdW5jdGlvbiAoZCwgYikgeyBkLl9fcHJvdG9fXyA9IGI7IH0pIHx8XHJcbiAgICAgICAgZnVuY3Rpb24gKGQsIGIpIHsgZm9yICh2YXIgcCBpbiBiKSBpZiAoT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKGIsIHApKSBkW3BdID0gYltwXTsgfTtcclxuICAgIHJldHVybiBleHRlbmRTdGF0aWNzKGQsIGIpO1xyXG59O1xyXG5cclxuZXhwb3J0IGZ1bmN0aW9uIF9fZXh0ZW5kcyhkLCBiKSB7XHJcbiAgICBpZiAodHlwZW9mIGIgIT09IFwiZnVuY3Rpb25cIiAmJiBiICE9PSBudWxsKVxyXG4gICAgICAgIHRocm93IG5ldyBUeXBlRXJyb3IoXCJDbGFzcyBleHRlbmRzIHZhbHVlIFwiICsgU3RyaW5nKGIpICsgXCIgaXMgbm90IGEgY29uc3RydWN0b3Igb3IgbnVsbFwiKTtcclxuICAgIGV4dGVuZFN0YXRpY3MoZCwgYik7XHJcbiAgICBmdW5jdGlvbiBfXygpIHsgdGhpcy5jb25zdHJ1Y3RvciA9IGQ7IH1cclxuICAgIGQucHJvdG90eXBlID0gYiA9PT0gbnVsbCA/IE9iamVjdC5jcmVhdGUoYikgOiAoX18ucHJvdG90eXBlID0gYi5wcm90b3R5cGUsIG5ldyBfXygpKTtcclxufVxyXG5cclxuZXhwb3J0IHZhciBfX2Fzc2lnbiA9IGZ1bmN0aW9uKCkge1xyXG4gICAgX19hc3NpZ24gPSBPYmplY3QuYXNzaWduIHx8IGZ1bmN0aW9uIF9fYXNzaWduKHQpIHtcclxuICAgICAgICBmb3IgKHZhciBzLCBpID0gMSwgbiA9IGFyZ3VtZW50cy5sZW5ndGg7IGkgPCBuOyBpKyspIHtcclxuICAgICAgICAgICAgcyA9IGFyZ3VtZW50c1tpXTtcclxuICAgICAgICAgICAgZm9yICh2YXIgcCBpbiBzKSBpZiAoT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKHMsIHApKSB0W3BdID0gc1twXTtcclxuICAgICAgICB9XHJcbiAgICAgICAgcmV0dXJuIHQ7XHJcbiAgICB9XHJcbiAgICByZXR1cm4gX19hc3NpZ24uYXBwbHkodGhpcywgYXJndW1lbnRzKTtcclxufVxyXG5cclxuZXhwb3J0IGZ1bmN0aW9uIF9fcmVzdChzLCBlKSB7XHJcbiAgICB2YXIgdCA9IHt9O1xyXG4gICAgZm9yICh2YXIgcCBpbiBzKSBpZiAoT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKHMsIHApICYmIGUuaW5kZXhPZihwKSA8IDApXHJcbiAgICAgICAgdFtwXSA9IHNbcF07XHJcbiAgICBpZiAocyAhPSBudWxsICYmIHR5cGVvZiBPYmplY3QuZ2V0T3duUHJvcGVydHlTeW1ib2xzID09PSBcImZ1bmN0aW9uXCIpXHJcbiAgICAgICAgZm9yICh2YXIgaSA9IDAsIHAgPSBPYmplY3QuZ2V0T3duUHJvcGVydHlTeW1ib2xzKHMpOyBpIDwgcC5sZW5ndGg7IGkrKykge1xyXG4gICAgICAgICAgICBpZiAoZS5pbmRleE9mKHBbaV0pIDwgMCAmJiBPYmplY3QucHJvdG90eXBlLnByb3BlcnR5SXNFbnVtZXJhYmxlLmNhbGwocywgcFtpXSkpXHJcbiAgICAgICAgICAgICAgICB0W3BbaV1dID0gc1twW2ldXTtcclxuICAgICAgICB9XHJcbiAgICByZXR1cm4gdDtcclxufVxyXG5cclxuZXhwb3J0IGZ1bmN0aW9uIF9fZGVjb3JhdGUoZGVjb3JhdG9ycywgdGFyZ2V0LCBrZXksIGRlc2MpIHtcclxuICAgIHZhciBjID0gYXJndW1lbnRzLmxlbmd0aCwgciA9IGMgPCAzID8gdGFyZ2V0IDogZGVzYyA9PT0gbnVsbCA/IGRlc2MgPSBPYmplY3QuZ2V0T3duUHJvcGVydHlEZXNjcmlwdG9yKHRhcmdldCwga2V5KSA6IGRlc2MsIGQ7XHJcbiAgICBpZiAodHlwZW9mIFJlZmxlY3QgPT09IFwib2JqZWN0XCIgJiYgdHlwZW9mIFJlZmxlY3QuZGV