Hotkey to Open Daily Note to the last line of the Notes Section (end of the bullet list)

What I’m trying to do

I’m trying to create a hotkey to open my daily note and go to a specific heading (“### Notes”) and go to the end of the section (usually a bullet list of journal thoughts for the day).

Things I have tried

I have a hotkey already set up to open my daily note. Then I can scroll to the bottom of the Notes section and starting adding bullets.

I also used the QuickAdd plugin to add a single note to my daily note at the end of a section. This works OK, but I have to use the pop-up box to enter the note content before I can keep adding notes.

But what if I just want to go to the end of the Notes section quickly with a hotkey and start adding bullets (without a pop up content entry)? Is there an easy way to do this?

But what if I just want to go to the end of the Notes section quickly with a hotkey and start adding bullets (without a pop up content entry)? Is there an easy way to do this?

For me, hitting the hotkey to open the daily note then Ctrl+End quickly brings me to the end of the daily note.

Is it to be understood that there are more sections under that notes section? If so you might consider using an outline plugin and skipping to the next section and go one line up.

Or if you like coding you could make a command to do:

  • find daily note, and check if already opened
  • open if not open already
  • use the metadata on sections to locate the Notes section
  • switch editing mode, and set line to the end of this section

As far as I know this is not a standard function, but as illustrated it shouldn’t be that hard to do either…

I haven’t scripted in Obsidian before. Can anyone point me to instruction on how to get started? What language would I use? What tools would I use to create it as a command in Obsidian once I create the script? Does anyone have an example of a similar-ish (or any kinds of script) I could work off of (copy and modify to suit my needs)? Where would I get information about the scripting and objects available within the scripting langauge?

Found this as a potential good start: Automating Your Obsidian Workspace | ThoughtAsylum, (basically using QuickAdd macros to trigger a .js script file) but still need to find more info about the actions available to the script automated the editor to do these things:

  • find daily note, and check if already opened
  • open if not open already
  • use the metadata on sections to locate the Notes section
  • switch editing mode, and set line to the end of this section

I started playing around with RunJS as an alternative to QuickAdd. I found this in the documentation of the RunJS plugin with an example about how to do something very similar. It appears to accomplish some of these items, but not all.

:white_check_mark: find daily note, and check if already opened
:white_check_mark: open if not open already
:ballot_box_with_check: use the metadata on sections to locate the Notes section - would need to add code to do this
:white_check_mark: (sorta) switch editing mode, and set line to the end of this section - partially solved - it’s switching editing mode, but adding a timestamp (a functionality I hadn’t thought of, but kinda like) at the very bottom of the note, rather than at the bottom of the Notes section.

Maybe I’ll just use this and reformat my Daily Note to have Notes always be at the end of the note, so I don’t have to do the above part, and I can re-use this out of the box. Although if I do this, there are probably other plugins I could use to do this without having to use the JS.

To get to the heading of your choice, you’ve got a least two options, and that is either to read the entire file scanning for the heading syntax, and then matching against your wanted heading, or use the metadata.

If you use getCache(filepath), you get access to the CachedMetadata, where you could get a record like the following:

image

This now shows that there is a heading at line 50, which you can easily get to when you’ve got a Editor view of your file. You could use getRange to find the heading text, and if you in addition also get the starting line of the next heading you know where to insert your text in front of, or where to set the cursor position with some accuracy.

Example showing code blocks

This code snippet is not directly related, but it could help you get started at navigating the metadata. In this variant I scan all of the files (picking out the first 15) and the show where there are code blocks in those files.

```dataviewjs

const result = []

for (let [fname, fcache] of Object.entries(dv.app.metadataCache.fileCache)) {
  // fname is the filename
  // fcache is the entry from metadataCache.fileCache
  // mcache is the actual metadataCache.metadataCache entry
  const mcache = dv.app.metadataCache.metadataCache[fcache.hash]
  console.log(fcache)
  // console.log(mcache.sections)
  if ( mcache && !mcache.frontmatter &&
       mcache.hasOwnProperty("sections") &&
       mcache["sections"].some(s => s.type == "code")
     ) {
     
     for (const section of mcache["sections"]) {
       if (section.type == "code")
          result.push([fname, section.position.start.line, section.position.end.line])
     }
     // console.log(mcache.sections)
  }   
  //console.log(fname, " » ", fcache, "\n  »» ", mcache)
  
  // Bail out after the first 15 entries
  if (result.length > 15) break
}

dv.table(["Filename", "Code start line", "Code end line"], result)
```
Example on changing a line

As part of a multi-menu of mine, I need to change the status of a given line (using a position object, orgPos), where I also set the clipboard to the old line. It showcases one way of changing a line. Similar code could be used to set the cursor position at a given liven.

async function migrateTask(params, selected) {

  const dv = params.app.plugins.plugins.dataview.api
  const currFile = await params.app.workspace.getActiveFile()
  const activeView =  app.workspace.getActiveViewOfType(params.obsidian.MarkdownView)
  
  if ( !activeView || !currFile ) {
    window.alert("Couldn't find an active file/editor")
    return -1
  }
  let orgPos = activeView.editor.getCursor()
  const orgLine = activeView.editor.getLine(orgPos.line)

  const today = moment().format("YYYY-MM-DD")
  activeView.editor.setLine(orgPos.line, 
    orgLine.replace(/^(\s*-\s*)\[.\](.*?)\s*?/, "$1[" + selected.status + "]$2") + ` [[${ today }|🔜]]`)
  params.quickAddApi.utility.setClipboard(
    "\n" + orgLine + " " + dv.fileLink(currFile.path, false, "🔙").toString())

  return " "
}

The last two lines of setting the clipboard, and returning " " is just part of the inner workings of my multi-menu, so they can be ignored.

I’m glad to see that you’re finding your way, and please feel free to ask if there is something in particular you’re stuck on doing.

I was feeling a little strange when posting the previous post, as I kind of felt like I had seen the headings listed in the metadata somewhere. And surely enough when I was reviewing another question I came across this section of code:

```dataviewjs

const tp = app.plugins.plugins['templater-obsidian'].templater.current_functions_object
const candidate = dv.current().myHeading

const linkedPages = await Promise.all(await dv.pages('"ForumStuff/f73/f73565"')
  .where( p => p.file.outlinks?.length )
  .filter( p => dv.func.contains(p.file.outlinks, candidate) )
  .forEach(async p => {
    const theFile = await tp.file.find_tfile(p.file.name)
    const theMetadata = await app.metadataCache.getFileCache(theFile)
    console.log("theMeta: ", theMetadata.headings)
    // Check if the headings has a link to our candidate
    // ...
    
    // If so, produce an embed of that and all other sub-headings
    // console.log(dv.func.filter(dv.array(theMetadata.headings), p=> p.heading.includes(candidate.file.name)))
    })
  )
```

This query looks for a linked heading, used in Collecting all text under linked headings and allowing it be rendered as Markdown, but what’s interesting in the context of this thread, is that doing these lines:

const theMetadata = await app.metadataCache.getFileCache(theFile)
console.log("theMeta: ", theMetadata.headings)

Shows that theMetadata.headings holds the headings with their position for that file, so the first entry for a random file in my test set shows:

image

So using similar code to this, combined with stuff from my previous post, you should rather easily be able to pick out both the “Notes section” heading, and the next one, and then find the line before that as your starting point for inserting new stuff.