Gif presentation

v0.1

How to use
- Type
{{tag:#tag}}in your note. - Put a cursor on that line
- Open command palette and find “Expander:” commands (you can attach hotkeys in settings menu)
It should remove the {{tag:#tag}} line and add notes which was found.
Notes
The expander do not do the current file title exclusion. Please, be careful and remove the embedded self note before running preview mode (it can cause a recursion).Was fixed in v0.2. Thanks @GreenChocho for testing.
Install
- You need Obsidian v0.9.7+
- Get Latest release
- Extract files and place them to your vault’s plugins folder: /.obsidian/plugins/
- Reload Obsidian
For version below 0.3.0
To enable the plugin run this snippet in your console:
v0.2.1
!function() {
const DELAY = 2000
const config = [
{
id: 'editor:expandEmbeds',
name: 'Expander: embed',
format: e => '![[' + e + ']]'
},
{
id: 'editor:expandLinks',
name: 'Expander: links',
format: e => '[[' + e + ']]'
},
{
id: 'editor:expandList',
name: 'Expander: list of links',
format: e => '- [[' + e + ']]'
},
{
id: 'editor:expandTODO',
name: 'Expander: list of TODO',
format: e => '- [ ] [[' + e + ']]'
},
]
function reformatLinks(links, mapFunc) {
return links.map(e => e.file.name)
.filter(e => app.workspace.activeLeaf.view.file.name !== e)
.map(mapFunc).join('\n')
}
function getLastLineNum(doc, line = 0) {
const lineNum = line === 0
? doc.getCursor().line
: line
if (doc.lineCount() === lineNum) {
return doc.getCursor().line + 1
}
return doc.getLine(lineNum) === '---'
? lineNum
: getLastLineNum(doc, lineNum + 1)
}
function initExpander(mapFunc) {
// Search files
const search = query => app.globalSearch.openGlobalSearch(query)
const getFoundFilenames = (mapFunc, callback) => {
const searchLeaf = app.workspace.getLeavesOfType('search')[0]
searchLeaf.open(searchLeaf.view)
.then(view => setTimeout(()=> {
const result = reformatLinks(view.dom.resultDoms, mapFunc)
callback(result)
}, DELAY))
}
const cmDoc = app.workspace.activeLeaf.view.sourceMode.cmEditor.doc
const hasFormulaRegexp = /^\{\{.+\}\}$/
const curNum = cmDoc.getCursor().line
const curText = cmDoc.getLine(curNum)
if (!hasFormulaRegexp.test(curText)) {
return
}
const isEmbed = cmDoc.getLine(curNum - 1) === '```expander'
&& cmDoc.getLine(curNum + 1) === '```'
const fstLineNumToReplace = isEmbed
? curNum - 1
: curNum
const lstLineNumToReplace = isEmbed
? getLastLineNum(cmDoc)
: curNum
const searchQuery = curText.replace('{{', '').replace('}}', '')
const embedFormula = '```expander\n' +
'{{' + searchQuery + '}}\n' +
'```\n'
const log = content => console.log(content) || content
const replaceLine = content => cmDoc.replaceRange(log(embedFormula + content + '\n\n---'),
{line: fstLineNumToReplace, ch: 0},
{line: lstLineNumToReplace, ch: cmDoc.getLine(lstLineNumToReplace).length}
)
search(searchQuery)
getFoundFilenames(mapFunc, replaceLine)
}
config.forEach(e => {
app.commands.addCommand({
id: e.id,
name: e.name,
callback: () => initExpander(e.format),
hotkeys: []
})
})
}()
v0.2
!function() {
const DELAY = 2000
const config = [
{
id: 'editor:expandEmbeds',
name: 'Expander: embed',
format: e => '![[' + e + ']]'
},
{
id: 'editor:expandLinks',
name: 'Expander: links',
format: e => '[[' + e + ']]'
},
{
id: 'editor:expandList',
name: 'Expander: list of links',
format: e => '- [[' + e + ']]'
},
{
id: 'editor:expandTODO',
name: 'Expander: list of TODO',
format: e => '- [ ] [[' + e + ']]'
},
]
function reformatLinks(links, mapFunc) {
return links.map(e => e.file.name)
.filter(e => app.workspace.activeLeaf.view.file.name !== e)
.map(mapFunc).join('\n')
}
function getLastLineNum(cmInst, line = 0) {
const lineNum = line === 0
? cmInst.getCursor().line
: line
if (cmInst.lastLine() === lineNum) {
return cmInst.getCursor().line + 1
}
return cmInst.getLine(lineNum) === '---'
? lineNum
: getLastLineNum(cmInst, lineNum + 1)
}
function initExpander(mapFunc) {
// Search files
const search = query => app.globalSearch.openGlobalSearch(query)
const getFoundFilenames = (mapFunc, callback) => {
const searchLeaf = app.workspace.getLeavesOfType('search')[0]
searchLeaf.open(searchLeaf.view)
.then(view => setTimeout(()=> {
const result = reformatLinks(view.dom.resultDoms, mapFunc)
callback(result)
}, DELAY))
}
const cmDoc = app.workspace.activeLeaf.view.sourceMode.cmEditor.doc
const hasFormulaRegexp = /^\{\{.+\}\}$/
const curNum = cmDoc.getCursor().line
const curText = cmDoc.getLine(curNum)
if (!hasFormulaRegexp.test(curText)) {
return
}
const isEmbed = cmDoc.getLine(curNum - 1) === '```expander'
&& cmDoc.getLine(curNum + 1) === '```'
const fstLineNumToReplace = isEmbed
? curNum - 1
: curNum
const lstLineNumToReplace = isEmbed
? getLastLineNum(cmDoc)
: curNum
const searchQuery = curText.replace('{{', '').replace('}}', '')
const embedFormula = '```expander\n' +
'{{' + searchQuery + '}}\n' +
'```\n'
const log = content => console.log(content) || content
const replaceLine = content => cmDoc.replaceRange(log(embedFormula + content + '\n\n---'),
{line: fstLineNumToReplace, ch: 0},
{line: lstLineNumToReplace, ch: cmDoc.getLine(lstLineNumToReplace).length}
)
search(searchQuery)
getFoundFilenames(mapFunc, replaceLine)
}
config.forEach(e => {
app.commands.addCommand({
id: e.id,
name: e.name,
callback: () => initExpander(e.format),
hotkeys: []
})
})
}()
v0.1
!function() {
const DELAY = 2000
const config = [
{
id: 'editor:expandEmbeds',
name: 'Expander: embed',
format: e => '![[' + e + ']]'
},
{
id: 'editor:expandLinks',
name: 'Expander: links',
format: e => '[[' + e + ']]'
},
{
id: 'editor:expandList',
name: 'Expander: list of links',
format: e => '- [[' + e + ']]'
},
{
id: 'editor:expandTODO',
name: 'Expander: list of TODO',
format: e => '- [ ] [[' + e + ']]'
},
]
function initExpander(mapFunc) {
// Search files
const search = query => app.globalSearch.openGlobalSearch(query)
// const getFoundFilenames = () => Array.from(document.querySelectorAll('.mod-global-search .search-result-file-title>span:nth-child(2)')).map(e => e.textContent)
const getFoundFilenames = (mapFunc, callback) => {
const searchLeaf = app.workspace.getLeavesOfType('search')[0]
searchLeaf.open(searchLeaf.view)
.then(view => setTimeout(()=> {
callback(view.dom.resultDoms.map(e => e.file.name).map(mapFunc).join('\n'))
}, DELAY))
}
const doc = app.workspace.activeLeaf.view.sourceMode.cmEditor.doc
const curLineNum = doc.getCursor().line
const lineContent = doc.getLine(curLineNum)
if (!/^\{\{.+\}\}$/.test(lineContent)) {
return
}
const searchQuery = lineContent.replace('{{', '').replace('}}', '')
const replaceLine = content => doc.replaceRange(content, {line: curLineNum, ch: 0}, {line: curLineNum, ch: lineContent.length})
search(searchQuery)
getFoundFilenames(mapFunc, replaceLine)
}
config.forEach(e => {
app.commands.addCommand({
id: e.id,
name: e.name,
callback: () => initExpander(e.format),
hotkeys: []
})
})
}()
What’s next
I see potential for improvements like:
- Done in 0.2
Save snippet and update results on command trigger - Expand all snippets on page by command
- Fix hacky search implementation when Search API will be provided
Latest changes
0.3
Available for official API Alpha
0.2.1
- [FIXED] Skips check for
---if it’s last line in file.
0.2
- Saves a formula snippet and wraps it into reusable code block
```extender
{{tag:#tag}}
```
- You can use snippet to “refresh” already added search results
- You can hide snippet code block from preview using CSS snippet below
.language-extender {
display: none;
}
- [FIXED] Remove parent note from search results
0.1
- Proof of concept added




