如何在Rmarkdown中跨块添加行号?

4
我想在我的Rmarkdown文件的HTML输出中添加代码行编号。我希望任何方法都可以唯一地标识输出中的每一行代码(例如,顺序行号跨整个文档递增,或者代码块由其自己的索引标识,在这些代码块内部,行号从1开始)。但是我一直无法实现这一点。
使用其他stackoverflow答案和这篇博客文章,我已经得到了行号,但是它们会在每个新的代码块中重置。
我有以下Rmd文件:
---
output:
  html_document:
    highlight: kate
---

```{r setup, include=FALSE}
knitr::opts_chunk$set(
  class.source = "numberLines lineAnchors"
  )
```

```{r}
5 + 5
3 * 9
```

```{r}
x <- 5
x * 3
```

编译后生成的代码如下:
您可以看到,当代码被输出或新的代码块开始时,行号会重置。我想要看到的是行号变为1、2、3、4,而不是1、1、1、2。
有人知道如何实现这个功能吗? line numbers reset when chunk is split or new chunk

3
你可以使用startFrom=3,参见 https://pandoc.org/MANUAL.html#fenced-code-blocks#extension-fenced_code_attributes。 - mb21
1
@mb21 那对于第二行没有帮助。 - duckmayr
@richarddmorey 为什么不呢? - mb21
3个回答

3
我通过在Rmd文档末尾添加一些jquery代码,成功地为HTML文档中的行添加了连续行号:
---
output:
  rmdformats::html_clean:
    highlight: kate
    toc: true
    use_bookdown: true
---

```{r setup, include=FALSE}
knitr::opts_chunk$set(
  class.source = "numberLines lineAnchors"
  )
```

```{r}
5 + 5
3 * 9
```

```{r}
x <- 5
x * 3
```

<!-- 
The javascript below will reset the line numbers when
the document loads. 
-->

<script>
$(function() {
  $(".sourceLine").each( function( index ){
    $( this ).attr( "data-line-number", index + 1 );
  });
});
</script>

生成的文档具有如下顺序的行号: sequential line numbers across chunks 这有点 hacky,因为它需要 jquery(可能可以通过包含一些覆盖现有内容的 css 来实现),但它能够工作并且看起来整洁。
截至 2020 年 8 月 4 日的更新:
他们改变了行号的工作方式(现在基于 CSS 计数器)。为了使其在整个文档中按顺序工作,现在您需要插入一些 CSS。下面是一个完整的工作示例。重要的代码在 <style> 块中。它在 body(文档)级别上重置了相关计数器,并防止计数器针对每个代码块重置。
---
output:
  rmdformats::html_clean:
    highlight: kate
    toc: true
    use_bookdown: true
---

<style>
body
  { counter-reset: source-line 0; }
pre.numberSource code
  { counter-reset: none; }
</style>

```{r setup, include=FALSE}
knitr::opts_chunk$set(
  class.source = "numberLines lineAnchors"
  )
```

```{r}
5 + 5
3 * 9
```

```{r}
x <- 5
x * 3
```


2
Hacky?是的。简洁、高效、解决问题……也是的。对于一个令人惊讶的棘手问题,这是一个很好的自我解答。 - duckmayr
@Ferroao,看起来他们改变了行号在底层的工作方式,这破坏了这个修复。我会尽力而为。 - richarddmorey
@Ferroao,看一下我回答的更新内容,有一个新的修复方案。 - richarddmorey
@Ferroao,嗯,你的设置可能与我的不同,因为这个方法对我来说是有效的。你可以尝试发布一个新的问题,并提供所有相关细节。 - richarddmorey

1
如评论中@mb21所指出的,可以通过添加startFrom属性来控制代码块的第一行编号。但是,由于knitr可以根据内容将代码块分成多个块,因此无法手动完成此操作。我们希望以编程方式添加此属性。
我知道的最简单的方法是让pandoc修改结构,因为在pandoc看到它们之前,所有块都已经被评估过了。我们将使用Lua而不是R进行脚本编写,因为这是与pandoc filters一起使用时效率最高的方法。
该脚本将跟踪其已查看的代码行数,并向源代码块添加正确的startFrom属性。我们可以通过检查numberLines类来区分源块和结果块:只有前者具有该类。
-- Number of code lines seen so far.
local total_lines_count = 0

-- Count the number of newlines in a string.
function count_lines (text)
  local count = 0
  local last_pos = 0
  repeat
    last_pos = string.find(text, '\n', last_pos + 1, true)
    count = count + 1
  until not last_pos
  return count
end

function CodeBlock (cb)
  -- do nothing for result blocks
  if not cb.classes:includes 'numberLines' then return nil end

  cb.attributes['startFrom'] = total_lines_count + 1
  total_lines_count = total_lines_count + count_lines(cb.text)
  return cb
end

现在唯一剩下的就是告诉pandoc在转换过程中调用该过滤器。可以通过在pandoc_args中添加--lua-filter选项来实现:
---
output:
  html_document:
    highlight: kate
    pandoc_args: ['--lua-filter=number-lines.lua']
---

文件number-lines.lua应包含上述Lua代码,并放置在与您的文档相同的文件夹中,或者放置在pandoc数据目录下的filters文件夹中(参见pandoc -v)。

这种方法的优点是它适用于HTML和PDF输出。


谢谢!我会接受这个答案,因为它适用于HTML和PDF。 - richarddmorey

0
这是我可以提出的建议:使用行自动编号功能+使用CSS计数器在右侧(“单元格”)显示块编号。然后,您可以引用块+行。
---
title: "ChunkLine numbering"
author: "WeLoveDataScience"
output:
  html_document:
    highlight: pygments
---

```{css, echo=FALSE}
body {
  counter-reset: nchunk;
}


pre.r {
  counter-increment: nchunk;
  position: relative;
  overflow: visible;
}

pre.r::before {
  content: 'C[' counter(nchunk) ']';
  display: inline-block;
  position: absolute;
  right: 0em;
  color: rgb(50, 60, 160);
}
```

```{r cars, class.source = c("numCode", "r", "numberLines")}
summary(cars)
head(cars)
foo=function(x){
  2*x
}
```

```{r other, class.source = c("numCode", "r", "numberLines")}
1+1
```

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接