Browse Source

vault backup: 2024-07-02 14:32:59

master
Julio Biason 3 months ago
parent
commit
7fecb795f8
  1. 3
      .obsidian/community-plugins.json
  2. 291
      .obsidian/plugins/automatic-table-of-contents/main.js
  3. 10
      .obsidian/plugins/automatic-table-of-contents/manifest.json
  4. 30
      .obsidian/workspace.json
  5. 39
      Kanban Pages/V&V.md
  6. 18
      Kanban Pages/Work Kanban.md

3
.obsidian/community-plugins.json

@ -1,4 +1,5 @@
[
"obsidian-kanban",
"obsidian-git"
"obsidian-git",
"automatic-table-of-contents"
]

291
.obsidian/plugins/automatic-table-of-contents/main.js

@ -0,0 +1,291 @@
let Plugin = class {}
let MarkdownRenderer = {}
let MarkdownRenderChild = class {}
let htmlToMarkdown = (html) => html
if (isObsidian()) {
const obsidian = require('obsidian')
Plugin = obsidian.Plugin
MarkdownRenderer = obsidian.MarkdownRenderer
MarkdownRenderChild = obsidian.MarkdownRenderChild
htmlToMarkdown = obsidian.htmlToMarkdown
}
const codeblockId = 'table-of-contents'
const codeblockIdShort = 'toc'
const availableOptions = {
title: {
type: 'string',
default: '',
comment: '',
},
style: {
type: 'value',
default: 'nestedList',
values: ['nestedList', 'nestedOrderedList', 'inlineFirstLevel'],
comment: 'TOC style (nestedList|nestedOrderedList|inlineFirstLevel)',
},
minLevel: {
type: 'number',
default: 0,
comment: 'Include headings from the specified level',
},
maxLevel: {
type: 'number',
default: 0,
comment: 'Include headings up to the specified level',
},
includeLinks: {
type: 'boolean',
default: true,
comment: 'Make headings clickable',
},
debugInConsole: {
type: 'boolean',
default: false,
comment: 'Print debug info in Obsidian console',
},
}
class ObsidianAutomaticTableOfContents extends Plugin {
async onload() {
const handler = (sourceText, element, context) => {
context.addChild(new Renderer(this.app, element, context.sourcePath, sourceText))
}
this.registerMarkdownCodeBlockProcessor(codeblockId, handler)
this.registerMarkdownCodeBlockProcessor(codeblockIdShort, handler)
this.addCommand({
id: 'insert-automatic-table-of-contents',
name: 'Insert table of contents',
editorCallback: onInsertToc,
})
this.addCommand({
id: 'insert-automatic-table-of-contents-docs',
name: 'Insert table of contents (documented)',
editorCallback: onInsertTocWithDocs,
})
}
}
function onInsertToc(editor) {
const markdown = '```' + codeblockId + '\n```'
editor.replaceRange(markdown, editor.getCursor())
}
function onInsertTocWithDocs(editor) {
let markdown = ['```' + codeblockId]
Object.keys(availableOptions).forEach((optionName) => {
const option = availableOptions[optionName]
const comment = option.comment.length > 0 ? ` # ${option.comment}` : ''
markdown.push(`${optionName}: ${option.default}${comment}`)
})
markdown.push('```')
editor.replaceRange(markdown.join('\n'), editor.getCursor())
}
class Renderer extends MarkdownRenderChild {
constructor(app, element, sourcePath, sourceText) {
super(element)
this.app = app
this.element = element
this.sourcePath = sourcePath
this.sourceText = sourceText
}
// Render on load
onload() {
this.render()
this.registerEvent(this.app.metadataCache.on('changed', this.onMetadataChange.bind(this)))
}
// Render on file change
onMetadataChange() {
this.render()
}
render() {
try {
const options = parseOptionsFromSourceText(this.sourceText)
if (options.debugInConsole) debug('Options', options)
const metadata = this.app.metadataCache.getCache(this.sourcePath)
const headings = metadata && metadata.headings ? metadata.headings : []
if (options.debugInConsole) debug('Headings', headings)
const markdown = getMarkdownFromHeadings(headings, options)
if (options.debugInConsole) debug('Markdown', markdown)
this.element.empty()
MarkdownRenderer.renderMarkdown(markdown, this.element, this.sourcePath, this)
} catch(error) {
const readableError = `_💥 Could not render table of contents (${error.message})_`
MarkdownRenderer.renderMarkdown(readableError, this.element, this.sourcePath, this)
}
}
}
function getMarkdownFromHeadings(headings, options) {
const markdownHandlersByStyle = {
nestedList: getMarkdownNestedListFromHeadings,
nestedOrderedList: getMarkdownNestedOrderedListFromHeadings,
inlineFirstLevel: getMarkdownInlineFirstLevelFromHeadings,
}
let markdown = ''
if (options.title && options.title.length > 0) {
markdown += options.title + '\n'
}
const noHeadingMessage = '_Table of contents: no headings found_'
markdown += markdownHandlersByStyle[options.style](headings, options) || noHeadingMessage
return markdown
}
function getMarkdownNestedListFromHeadings(headings, options) {
return getMarkdownListFromHeadings(headings, false, options)
}
function getMarkdownNestedOrderedListFromHeadings(headings, options) {
return getMarkdownListFromHeadings(headings, true, options)
}
function getMarkdownListFromHeadings(headings, isOrdered, options) {
const prefix = isOrdered ? '1.' : '-'
const lines = []
const minLevel = options.minLevel > 0
? options.minLevel
: Math.min(...headings.map((heading) => heading.level))
headings.forEach((heading) => {
if (heading.level < minLevel) return
if (options.maxLevel > 0 && heading.level > options.maxLevel) return
lines.push(`${'\t'.repeat(heading.level - minLevel)}${prefix} ${getMarkdownHeading(heading, options)}`)
})
return lines.length > 0 ? lines.join('\n') : null
}
function getMarkdownInlineFirstLevelFromHeadings(headings, options) {
const minLevel = options.minLevel > 0
? options.minLevel
: Math.min(...headings.map((heading) => heading.level))
const items = headings
.filter((heading) => heading.level === minLevel)
.map((heading) => {
return getMarkdownHeading(heading, options)
})
return items.length > 0 ? items.join(' | ') : null
}
function getMarkdownHeading(heading, options) {
const stripMarkdown = (text) => {
text = text.replaceAll('*', '').replaceAll('_', '').replaceAll('`', '')
text = text.replaceAll('==', '').replaceAll('~~', '')
text = text.replace(/\[([^\]]+)\]\([^)]+\)/g, '$1') // Strip markdown links
return text
}
const stripHtml = (text) => stripMarkdown(htmlToMarkdown(text))
const stripWikilinks = (text, isForLink) => {
// Strip [[link|text]] format
// For the text part of the final link we only keep "text"
// For the link part we need the text + link
// Example: "# Some [[file.md|heading]]" must be translated to "[[#Some file.md heading|Some heading]]"
text = text.replace(/\[\[([^\]]+)\|([^\]]+)\]\]/g, isForLink ? '$1 $2' : '$2')
text = text.replace(/\[\[([^\]]+)\]\]/g, '$1') // Strip [[link]] format
// Replace malformed links & reserved wikilinks chars
text = text.replaceAll('[[', '').replaceAll('| ', isForLink ? '' : '- ').replaceAll('|', isForLink ? ' ' : '-')
return text
}
const stripTags = (text) => text.replaceAll('#', '')
if (options.includeLinks) {
// Remove markdown, HTML & wikilinks from text for readability, as they are not rendered in a wikilink
let text = heading.heading
text = stripMarkdown(text)
text = stripHtml(text)
text = stripWikilinks(text, false)
// Remove wikilinks & tags from link or it won't be clickable (on the other hand HTML & markdown must stay)
let link = heading.heading
link = stripWikilinks(link, true)
link = stripTags(link)
// Return wiklink style link
return `[[#${link}|${text}]]`
// Why not markdown links? Because even if it looks like the text part would have a better compatibility
// with complex headings (as it would support HTML, markdown, etc) the link part is messy,
// because it requires some encoding that looks buggy and undocumented; official docs state the link must be URL encoded
// (https://help.obsidian.md/Linking+notes+and+files/Internal+links#Supported+formats+for+internal+links)
// but it doesn't work properly, example: "## Some <em>heading</em> with simple HTML" must be encoded as:
// [Some <em>heading</em> with simple HTML](#Some%20<em>heading</em>%20with%20simpler%20HTML)
// and not
// [Some <em>heading</em> with simple HTML](#Some%20%3Cem%3Eheading%3C%2Fem%3E%20with%20simpler%20HTML)
// Also it won't be clickable at all if the heading contains #tags or more complex HTML
// (example: ## Some <em style="background: red">heading</em> #with-a-tag)
// (unless there is a way to encode these use cases that I didn't find)
}
return heading.heading
}
function parseOptionsFromSourceText(sourceText = '') {
const options = {}
Object.keys(availableOptions).forEach((option) => {
options[option] = availableOptions[option].default
})
sourceText.split('\n').forEach((line) => {
const option = parseOptionFromSourceLine(line)
if (option !== null) {
options[option.name] = option.value
}
})
return options
}
function parseOptionFromSourceLine(line) {
const matches = line.match(/([a-zA-Z0-9._ ]+):(.*)/)
if (line.startsWith('#') || !matches) return null
const possibleName = matches[1].trim()
const optionParams = availableOptions[possibleName]
let possibleValue = matches[2].trim()
if (!optionParams || optionParams.type !== 'string') {
// Strip comments from values except for strings (as a string may contain markdown)
possibleValue = possibleValue.replace(/#[^#]*$/, '').trim()
}
const valueError = new Error(`Invalid value for \`${possibleName}\``)
if (optionParams && optionParams.type === 'number') {
const value = parseInt(possibleValue)
if (value < 0) throw valueError
return { name: possibleName, value }
}
if (optionParams && optionParams.type === 'boolean') {
if (!['true', 'false'].includes(possibleValue)) throw valueError
return { name: possibleName, value: possibleValue === 'true' }
}
if (optionParams && optionParams.type === 'value') {
if (!optionParams.values.includes(possibleValue)) throw valueError
return { name: possibleName, value: possibleValue }
}
if (optionParams && optionParams.type === 'string') {
return { name: possibleName, value: possibleValue }
}
return null
}
function debug(type, data) {
console.log(...[
`%cAutomatic Table Of Contents %c${type}:\n`,
'color: orange; font-weight: bold',
'font-weight: bold',
data,
])
}
function isObsidian() {
if (typeof process !== 'object') {
return true // Obsidian mobile doesn't have a global process object
}
return !process.env || !process.env.JEST_WORKER_ID // Jest runtime is not Obsidian
}
if (isObsidian()) {
module.exports = ObsidianAutomaticTableOfContents
} else {
module.exports = {
parseOptionsFromSourceText,
getMarkdownFromHeadings,
}
}

10
.obsidian/plugins/automatic-table-of-contents/manifest.json

@ -0,0 +1,10 @@
{
"id": "automatic-table-of-contents",
"name": "Automatic Table Of Contents",
"version": "1.4.0",
"minAppVersion": "1.3.0",
"description": "Create a table of contents in a note, that updates itself when the note changes",
"author": "Johan Satgé",
"authorUrl": "https://github.com/johansatge",
"isDesktopOnly": false
}

30
.obsidian/workspace.json

@ -13,19 +13,7 @@
"state": {
"type": "markdown",
"state": {
"file": "Meetings/DevOps/2024-06-01.md",
"mode": "source",
"source": false
}
}
},
{
"id": "baccd079c408fe2f",
"type": "leaf",
"state": {
"type": "markdown",
"state": {
"file": "Kanban Pages/HelyxVerify.md",
"file": "Kanban Pages/V&V.md",
"mode": "source",
"source": false
}
@ -97,7 +85,7 @@
"state": {
"type": "backlink",
"state": {
"file": "Meetings/DevOps/2024-06-01.md",
"file": "Kanban Pages/V&V.md",
"collapseAll": true,
"extraContext": false,
"sortOrder": "alphabetical",
@ -114,7 +102,7 @@
"state": {
"type": "outgoing-link",
"state": {
"file": "Meetings/DevOps/2024-06-01.md",
"file": "Kanban Pages/V&V.md",
"linksCollapsed": false,
"unlinkedCollapsed": true
}
@ -137,7 +125,7 @@
"state": {
"type": "outline",
"state": {
"file": "Meetings/DevOps/2024-06-01.md"
"file": "Kanban Pages/V&V.md"
}
}
}
@ -158,16 +146,16 @@
"obsidian-kanban:Create new board": false
}
},
"active": "2f56f8d2c998700c",
"active": "676a3e53a7c36034",
"lastOpenFiles": [
"Meetings/QA/2024-07-01.md",
"Kanban Pages/Work Kanban.md",
"Kanban Pages/V&V.md",
"Kanban Pages/HelyxVerify.md",
"Meetings/DevOps/2024-06-01.md",
"Meetings/QA/2024-07-01.md",
"Meetings/DevOps",
"Kanban Pages/Work Kanban.md",
"Meetings/QA",
"Meetings",
"Kanban Pages/HelyxVerify.md",
"Kanban Pages/V&V.md",
"Kanban Pages/QA.md",
"Windows Compilation.md",
"Kanban Pages/Windows Native Compilation.md",

39
Kanban Pages/V&V.md

@ -1,3 +1,11 @@
```table-of-contents
title:
style: nestedList # TOC style (nestedList|nestedOrderedList|inlineFirstLevel)
minLevel: 0 # Include headings from the specified level
maxLevel: 0 # Include headings up to the specified level
includeLinks: true # Make headings clickable
debugInConsole: false # Print debug info in Obsidian console
```
# Docker Container
`docker build . -t vv:latest`
@ -7,12 +15,13 @@
- Core: `/core`
`vv init --collection_path=/collection/`
## Error 1
# Pipeline
Looks like AndrewC is also working on something like this.
# Error 1
`CommandSequence.__init__() got an unexpected keyword argument 'mode'`
Found out that CommandSequence doesn't have a "mode" parameter, but all the configurations in vv-collection have it in their commands.
Fix was to add the property, although it's clear things are now broken
## Error 2
# Error 2
```
Traceback (most recent call last):
File "/usr/local/bin/vv", line 8, in <module>
@ -43,7 +52,7 @@ Traceback (most recent call last):
AttributeError: 'dict' object has no attribute 'parameters'
```
## Ruan
# Ruan
[2:24 PM] Ruan Engelbrecht
Ah yes so at the bottom there's the list of cases specified under the run_cases key
@ -55,3 +64,25 @@ Uncomment the last two lines of my file, and source the mid-sized-ci collection,
[2:26 PM] Ruan Engelbrecht
And source your core
# MPI in docker
mpirun has detected an attempt to run as root.
Running as root is *strongly* discouraged as any mistake (e.g., in
defining TMPDIR) or bug can result in catastrophic damage to the OS
file system, leaving your system in an unusable state.
We strongly suggest that you run mpirun as a non-root user.
You can override this protection by adding the --allow-run-as-root option
to the cmd line or by setting two environment variables in the following way:
the variable OMPI_ALLOW_RUN_AS_ROOT=1 to indicate the desire to override this
protection, and OMPI_ALLOW_RUN_AS_ROOT_CONFIRM=1 to confirm the choice and
add one more layer of certainty that you want to do so.
We reiterate our advice against doing so - please proceed at your own risk.
# HPC03 machine
$ cat /etc/centos-release
CentOS Linux release 7.9.2009 (Core)
# Important collections
- customers_report
- engys/automotive
- mid-sized-ci

18
Kanban Pages/Work Kanban.md

@ -31,13 +31,13 @@ kanban-plugin: board
## Working
- [ ] Create V&V pipeline
[[V&V]]
#jenkins#vv
- [ ] Allow helyxVerify cases not to be reduced
https://engys.atlassian.net/browse/DO-1198
[[HelyxVerify#Not reducing]]
#helyxVerify
- [ ] Create V&V pipeline
[[V&V]]
#jenkins
- [ ] verificationDict
[[HelyxVerify#system/validationDict]]
#helyxVerify
@ -53,6 +53,16 @@ kanban-plugin: board
[[Windows Native Compilation]]
## DevOps Dec24 - A7
- [ ] Run all cases to completion, instead of stopping in the first failure.
https://engys.atlassian.net/browse/DO-1211
#qa
- [ ] On nightly, change the version to have the GUI commit
https://engys.atlassian.net/browse/DO-1210
#packager
## DevOps Dec24 - A6
- [ ] Python Testing Pipeline
@ -92,6 +102,6 @@ kanban-plugin: board
%% kanban:settings
```
{"kanban-plugin":"board","list-collapse":[false,false,false,false]}
{"kanban-plugin":"board","list-collapse":[false,false,false,false,true]}
```
%%
Loading…
Cancel
Save