Как выделить все имена R-функций с помощью highlight.js? - PullRequest
0 голосов
/ 30 июня 2018

Я хочу расширить возможности highlight.js для языка R, чтобы (1) все имена функций, за которыми следуют открывающие скобки ( и (2) все имена пакетов, за которыми следуют операторы :: и :::, будут выделены (как в RStudio, см. рис. 1). Круглые скобки (, ) и операторы ::, ::: не должны выделяться.

Fig.1. Desired highlighting. Рис.1. Желаемое выделение R частей кода (имена функций и пакетов).

Мой пример состоит из двух файлов: index.html и r.min.js.

HTML-файл:

<html lang="en-us">
<head> <meta charset="utf-8">
    <link href='https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/styles/agate.min.css' rel='stylesheet' type='text/css' />
</head>

<body>

<pre class="r"><code>doc_name &lt;-
    officer::read_docx() %&gt;% 
    flextable:::body_add_flextable(table_to_save) %&gt;% 
    print(target = &quot;word.docx&quot;)

.libPaths()

c("a", "b")

package::function()$field
* +1032 * hljs.initHighlightingOnLoad ();

r.min.js файл:

hljs.registerLanguage("r",function(e){var r="([a-zA-Z]|\\.[a-zA-Z.])[a-zA-Z0-9._]*";return{c:[e.HCM,{b:r,l:r,k:{keyword:"function if in break next repeat else for return switch while try tryCatch stop warning require library attach detach source setMethod setGeneric setGroupGeneric setClass ...",literal:"NULL NA TRUE FALSE T F Inf NaN NA_integer_|10 NA_real_|10 NA_character_|10 NA_complex_|10"},r:0},{cN:"number",b:"0[xX][0-9a-fA-F]+[Li]?\\b",r:0},{cN:"number",b:"\\d+(?:[eE][+\\-]?\\d*)?L\\b",r:0},{cN:"number",b:"\\d+\\.(?!\\d)(?:i\\b)?",r:0},{cN:"number",b:"\\d+(?:\\.\\d*)?(?:[eE][+\\-]?\\d*)?i?\\b",r:0},{cN:"number",b:"\\.\\d+(?:[eE][+\\-]?\\d*)?i?\\b",r:0},{b:"`",e:"`",r:0},{cN:"string",c:[e.BE],v:[{b:'"',e:'"'},{b:"'",e:"'"}]},

/* My attempt... */
/* ... to highlight function names between double 
and triple colons and opening parenthesis (in red as symbol): */
{cN:"symbol",b:":::|::",e:"\\(",eB:!0,eE:!0},

/* ... to highlight other function names (in red as symbol): */
{cN:"symbol",  b:"([a-zA-Z]|\.[a-zA-Z.])[a-zA-Z0-9._]*",e:"\\(",eE:!0},

/* ... to highlight package names (in cyan as variable): */
{cN:"variable",b:"(?<!\w)",e:":::|::",eE:!0},

]}});

r.min.js основан на ( этот файл ) и содержит highlight.js правил для идентификации r элементов кода. Строки, которые я добавил, находятся ниже комментария «Моя попытка». Значения сокращений: cN - имя класса css, b - "beggins", e - "заканчивается", eB - "исключить начало", eE - "исключить конец", другие значения объяснил здесь .

Результат, который я получаю (рис.2.), Не является удовлетворительным. Похоже, что используемые мной регулярные выражения не находят правильных начала и конца нужных частей кода R.

imager.min.js">
Рис.2. Результат с использованием модифицированного r.min.js

Каким должен быть правильный код highlight.js в r.min.js, чтобы подсвечивать части кода R, как в RStudio?

1 Ответ

0 голосов
/ 01 июля 2018

Звучит как стоящее улучшение, поэтому я немного поработал с ним.

Это должно быть довольно просто,

Регулярное выражение для захвата префиксов имени пакета может быть записано так ( demo ):

\w+(?=:::?)

и для имен функций, подобных этому ( demo ):

\.?\w+(?=\()

к сожалению, это не так легко применить к правилам синтаксического анализа языка highlight.js.

После некоторой ошибки, я согласился со следующим кодом, который дает довольно последовательное выделение:

/* ... to highlight other function names (in orange as a keyword): */
{
    cN: "keyword",
    b: /(^|\s*)(:::?|\.)\w+(?=\(|$)/
},
/* ... to highlight package names (in red as meta): */
{
    cN: "meta",
    b: /(^|\s*)\w+(?=:::?|$)/,
    r: 0
},
  • Я использую cN | className keyword для функций, это то, что есть, и это меньше мешает предопределенному стилю для функций.
  • То же самое касается имен пакетов, где я предлагаю использовать cN meta. Это то, что другие пакеты используют для аналогичных конструкций, и опять же, это дает более согласованный результат для встроенных стилей, например число.
  • Я также добавил print и c в список ключевых слов. Список для языка R, очевидно, несколько неполон. Возможно, каждое имя функции (даже из сторонних пакетов) должно быть добавлено в качестве ключевого слова - так делают некоторые другие языки - но это не очень практично).

Это то, что я получаю .

Пример кода:

hljs.registerLanguage("r",function(e){var r="([a-zA-Z]|\\.[a-zA-Z.])[a-zA-Z0-9._]*";return{c:[e.HCM,{b:r,l:r,k:{keyword:"function if in break next repeat else for return switch while try tryCatch stop warning require library attach detach source setMethod setGeneric setGroupGeneric setClass c print ...",literal:"NULL NA TRUE FALSE T F Inf NaN NA_integer_|10 NA_real_|10 NA_character_|10 NA_complex_|10"},r:0},{cN:"number",b:"0[xX][0-9a-fA-F]+[Li]?\\b",r:0},{cN:"number",b:"\\d+(?:[eE][+\\-]?\\d*)?L\\b",r:0},{cN:"number",b:"\\d+\\.(?!\\d)(?:i\\b)?",r:0},{cN:"number",b:"\\d+(?:\\.\\d*)?(?:[eE][+\\-]?\\d*)?i?\\b",r:0},{cN:"number",b:"\\.\\d+(?:[eE][+\\-]?\\d*)?i?\\b",r:0},{b:"`",e:"`",r:0},{cN:"string",c:[e.BE],v:[{b:'"',e:'"'},{b:"'",e:"'"}]},
{cN: "keyword", b: /(^|\s*)(:::?|\.)\w+(?=\(|$)/},
{cN: "meta",b: /(^|\s*)\w+(?=:::?|$)/,r: 0 }, ]}});

hljs.initHighlightingOnLoad();
<html lang="en-us">
<head> <meta charset="utf-8"><link href='https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/styles/agate.min.css' rel='stylesheet' type='text/css' />
</head><body>

    <pre class="r"><code>library(officer)
doc_name &lt;-
    officer::read_docx() %&gt;% 
    flextable:::body_add_flextable(table_to_save) %&gt;% 
    print(target = &quot;word.docx&quot;)

.libPaths()
x = 4
c("a", "b")

package::function()$field

Довольно близко, но далеко не идеально. Основным препятствием здесь является то, что я изо всех сил пытаюсь полностью понять, как синтаксический анализатор интерпретирует шаблоны. Некоторые результаты просто не имеют смысла для меня, но все еще работает .

...