我开始使用标记来做笔记。

我用标记来查看我的笔记,它很漂亮。

但是随着我的笔记变长,我发现很难找到我想要的东西。

我知道markdown可以创建表,但它是否能够创建目录,跳转到部分,或定义页面部分markdown?

或者,是否有降价阅读器/编辑器可以做这些事情。搜索也是一个不错的功能。

简而言之,我想让它成为我很棒的笔记工具,功能就像写一本书一样。


当前回答

正如在其他回答中提到的,有多种方法可以自动生成目录。大多数都是开源软件,可以根据您的需要进行调整。

然而,我所缺少的是,使用Markdown提供的有限选项,在视觉上吸引人的目录格式。我们得出了以下结论:

Code

## Content

**[1. Markdown](#heading--1)**

  * [1.1. Markdown formatting cheatsheet](#heading--1-1)
  * [1.2. Markdown formatting details](#heading--1-2)

**[2. BBCode formatting](#heading--2)**

  * [2.1. Basic text formatting](#heading--2-1)

      * [2.1.1. Not so basic text formatting](#heading--2-1-1)

  * [2.2. Lists, Images, Code](#heading--2-2)
  * [2.3. Special features](#heading--2-3)

----

在你的文档中,你可以像这样放置目标子部分标记:

<div id="heading--1-1"/>
### 1.1. Markdown formatting cheatsheet

根据你在哪里以及如何使用Markdown,以下也应该工作,并提供了更好看Markdown代码:

### 1.1. Markdown formatting cheatsheet <a name="heading--1-1"/>

例子呈现

内容 1. 减价 1.1. 折算格式备忘单 1.2. 折扣价格式细节 2. BBCode格式化 2.1. 基本文本格式 2.1.1. 不是最基本的文本格式 2.2. 列表,图像,代码 2.3. 特殊功能

优势

You can add as many levels of chapters and sub-chapters as you need. In the Table of Contents, these would appear as nested unordered lists on deeper levels. No use of ordered lists. These would create an indentation, would not link the number, and cannot be used to create decimal classification numbering like "1.1.". No use of lists for the first level. Here, using an unordered list is possible, but not necessary: the indentation and bullet just add visual clutter and no function here, so we don't use a list for the first ToC level at all. Visual emphasis on the first-level sections in the table of content by bold print. Short, meaningful subpart markers that look "beautiful" in the browser's URL bar such as #heading--1-1 rather than markers containing transformed pieces of the actual heading. The code uses H2 headings (## …) for sections, H3 headings (### …) for sub-headings etc.. This makes the source code easier to read because ## … provides a stronger visual clue when scrolling through compared to the case where sections would start with H1 headings (# …). It is still logically consistent as you use the H1 heading for the document title itself. Finally, we add a nice horizontal rule to separate the table of contents from the actual content.

有关这项技术以及我们如何在论坛软件Discourse中使用它的更多信息,请参见这里。

其他回答

由不同Markdown解析器生成的锚标记是不相等的。

如果你正在使用Markdown解析器GFM (GitHub调味Markdown)或Redcarpet,我写了一个Vim插件来处理目录。

特性

生成Markdown文件的目录。 支持的Markdown解析器: GFM (GitHub调味Markdown) Redcarpet 更新现有的目录。 自动更新现有的目录保存。

截图

使用

生成目录

将光标移动到要添加目录的行,然后在下面键入适合您的命令。该命令将在光标进入目录后生成标题。

: GenTocGFM 生成GFM链接样式的目录。 此命令适用于GitHub存储库中的Markdown文件,如README。和Markdown文件的GitBook。 : GenTocRedcarpet 生成红地毯链接样式的目录。 这个命令适用于Jekyll或任何其他使用Redcarpet作为Markdown解析器的地方。 你可以在这里查看GFM和Redcarpet风格的toc链接之间的区别。

手动更新现有的目录

通常你不需要这样做,现有的目录将自动更新保存默认情况下。如果您想手动执行,只需使用:updatettoc命令。

下载和文档

https://github.com/mzlogin/vim-markdown-toc

MultiMarkdown Composer似乎生成了一个目录来辅助编辑。

也可能存在这样或那样的库,它们可以生成TOC:参见Python Markdown TOC扩展。

对我来说,@Tum提出的解决方案对于2个层次的目录来说非常有效。然而,对于第3个关卡,这种方法却不起作用。它没有像前两层那样显示链接,而是显示纯文本3.5.1。[bla blabla](#blablabla) <br>代替。

我的解决方案是@Tum解决方案(非常简单)的补充,适用于需要3级或以上目录的人。

在第二层,一个简单的制表符将为您正确地完成缩进。但它不支持2个标签。相反,你必须使用一个标签,并添加尽可能多的&nbsp;根据你自己的需要来正确对齐第三层。

下面是一个使用4个关卡的例子(关卡越高,它就变得越糟糕):

# Table of Contents
1. [Title](#title) <br>
    1.1. [sub-title](#sub_title) <br>
    &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;1.1.1. [sub-sub-title](#sub_sub_title)
    &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;1.1.1.1. [sub-sub-sub-title](#sub_sub_sub_title)

# Title <a name="title"></a>
Heading 1

## Sub-Title <a name="sub_title"></a>
Heading 2

### Sub-Sub-Title <a name="sub_sub_title"></a>
Heading 3

#### Sub-Sub-Sub-Title <a name="sub_sub_sub_title"></a>
Heading 4

这将给出以下结果,其中目录表的每个元素都是到其相应部分的链接。还要注意<br>,以便添加新行,而不是在同一行上。

目录

标题 1.1. 字幕 1.1.1。Sub-Sub-Title                   1.1.1.1。Sub-Sub-Sub-Title

标题

标题1

字幕

标题2

Sub-Sub-Title

标题3

Sub-Sub-Sub-Title

标题4

这是一个小的nodejs脚本,它生成目录,并考虑重复的标题:

const fs = require('fs')
const { mdToPdf } = require('md-to-pdf');

const stringtoreplace = '<toc/>'

const processTitleRepetitions = (contents, titleMap) => {
  for (const content of contents) {
    titleMap[content.link] = typeof titleMap[content.link] === 'undefined'
      ? 0
      : titleMap[content.link] + 1
    if (titleMap[content.link] > 0) {
      content.link = `${content.link}-${titleMap[content.link]}`
    }
  }
}

const convertContentToPdf = async (targetFile) => {
  const pdf = await mdToPdf({path: targetFile}).catch(console.error)
  if(pdf) {
    const pdfFile = `${targetFile.replace(/\.md/, '')}.pdf`
    fs.writeFileSync(pdfFile, pdf.content)
    return pdfFile
  }
  throw new Error("PDF generation failed.")
}

const generateTOC = (file, targetFile) => {
  // Extract headers
  const fileContent = fs.readFileSync(file, 'utf-8')
  const titleLine = /((?<=^)#+)\s(.+)/
  const contents = fileContent.split(/\r?\n/).
    map(line => line.match(titleLine)).
    filter(match => match).
    filter(match => match[1].length > 1).
    map(regExpMatchArray => {
      return {
        level: regExpMatchArray[1].length, text: regExpMatchArray[2],
        link: '#' + regExpMatchArray[2].replace(/(\s+|[.,\/#!$%^&*;:{}=\-_`~()]+)/g, '-').toLowerCase(),
      }
    })
  const titleMap = {}
  processTitleRepetitions(contents, titleMap)
  // Write content
  let toctext = '## Table of Contents\n'
  // Find the toplevel to adjust the level of the table of contents.
  const topLevel = contents.reduce((maxLevel, content) => Math.min(content['level'], maxLevel), 1000)
  levelCounter = {}
  contents.forEach(item => {
    let currentLevel = parseInt(item.level)
    levelCounter[currentLevel] = levelCounter[currentLevel] ? levelCounter[currentLevel] + 1 : 1
    Object.entries(levelCounter).forEach(e => {
      if(currentLevel < parseInt(e[0])) {
        levelCounter[e[0]] = 0
      }
    })
    const level = Array(currentLevel - topLevel).fill('\t').join('')
    const text = `${levelCounter[currentLevel]}. [${item['text']}](${item['link']}) \n`
    toctext += level + text
  })

  const updatedContent = fileContent.toString().replace(stringtoreplace, toctext)
  fs.writeFileSync(targetFile, updatedContent)
  convertContentToPdf(targetFile).then((pdfFile) => {
    console.info(`${pdfFile} has been generated.`)
  })
}

const args = process.argv.slice(2)

if(args.length < 2) {
  console.error("Please provide the name of the markdown file from which the headers should be extracted and the name of the file with the new table of contents")
  console.info("Example: node MD_TOC.js <source_md> <target_md>")
  process.exit(1)
}

const source_md = args[0]
const target_md = args[1]

generateTOC(source_md, target_md)

要使用它,您需要在markdown文件中注入<toc/>。

下面是你如何使用它:

generateTOC('../README.md', '../README_toc.md')

第一个参数是源markdown文件,第二个参数是带有markdown的文件。

只需使用带有插件的文本编辑器。

你的编辑器很可能有一个包/插件来为你处理这个问题。例如,在Emacs中,可以安装markdown-toc TOC生成器。然后在编辑时,只需反复调用M-x markdown-toc-generate-or-refresh-toc。如果你想经常这样做,那就值得一个键绑定。它擅长生成一个简单的TOC,而不会用HTML锚污染您的文档。

其他编辑器也有类似的插件,所以流行的列表是这样的:

器name: markdown-toc Vim: markdown-toc Atom: markdown-toc VSCode: markdown-toc