code - вставка фрагментов кода

Описание

Вставка фрагментов кода из файлов проекта.

Формат:

@@code file=FILENAME part=PARTNAME lang=LANG title=ЗАГОЛОВОК

где:

  • file - имя файла из проекта, откуда вставлять текст. Может быть абсолютным и относительным (см: Ссылки). Если содержит '#', то считается что указывает на файл с groovy-классом (или java-классом) для генерации текста файла (см: Генерация файлов для вставки). Кроме того, может быть именем класса.
  • part - имя поименнованного фрагмента из файла (см. ниже). Если не указан, вставляется весь текст файла
  • lang - имя языка для подсветки синтаксиса. Если не указано, определяется по расширению файла
  • title - заголовок. Обычно тут указывается имя файла.
  • mode - режим вывода при генерации (см: Генерация файлов для вставки).

Особые соглашения по имени файла:

  • если файл не абсолютный (не имеет / в начале), то он последовательно ищется в каталогах:
    • _inc/ИМЯ-ФАЙЛА-СТАТЬИ
    • _inc/ИМЯ_ФАЙЛА_СТАТЬИ
    • _inc
    • относительно текущего каталога
  • если файл - это имя класса, то ищется файл .java или .groovy, соответствующий классу

Например, мы имеем статью folder1/my-doc1.md и в ней описана вставка кода:

@@code file=file1.java 

Тогда будут искаться следующие файлы:

  • folder1/_inc/my-doc1/file.java
  • folder1/_inc/my_doc1/file.java
  • folder1/_inc/file.java
  • folder1/file.java

Первый найденный будет использован.

В случае, если в качестве файла указано имя класса:

@@code file=pak1.pak2.Class1 

Будут искаться следующие файлы:

  • /pak1/pak2/Class1.java
  • /pak1/pak2/Class1.groovy

Поименнованные фрагменты файла

В некоторых типах файлов можно определять поименнованные фрагменты, которые позволяют вставлять не весь текст файла, а только его часть.

java/groovy/js

Начало фрагмента определяется коментарием //= PART-NAME, конец фрагмента - //=. Начало фрагмента является концом предыдущего, поэтому если фрагменты идут один за другим, конец фрагмента можно не указывать.

Пример:

def s = "hello"
//= part1
def n1 = 1
//= part2
def n2 = 2
//=
def n0 = 0
//= part3
def n3 = 3
//=

В этом примере определены 3 фрагмента со следующим содержимым:

Фрагмент part1:
  def n1 = 1

Фрагмент part2:
  def n2 = 2

Фрагмент part3:
  def n3 = 3

В качестве имени фрагмента можно указать имя метода. В этом случае в качестве фрагмента будет использоватся тело метода. Если тело метода содержит фрагмент body, то этот фрагмент будет использоватся в качестве тела метода. Фрагмент с именем имяМетода-all содержит полное тело метода, без учета фрагмента body.

Пример:

class A1 {
    void m1() {
        def n1 = 1        
    }
    void m2() {
        def n2 = 2
        //= body        
        def n3 = 3
        //=         
        def n4 = 4
    }
}

В этом примере определены фрагменты:

Фрагмент m1:
  def n1 = 1

Фрагмент m2:
  def n3 = 3

Фрагмент m2-all:
  def n2 = 2
  def n3 = 3
  def n4 = 4

xml/html

Начало фрагмента определяется коментарием <!-- = PART-NAME -->, конец фрагмента - <!-- = -->. Начало фрагмента является концом предыдущего, поэтому если фрагменты идут один за другим, конец фрагмента можно не указывать.

Если PART-NAME указан в формате PART-NAME:PATH, то фрагмент будет обернут в xml, который соответствует пути.

Например для такого файла:

<?xml version="1.0" encoding="utf-8"?>
<root>
    <node1>
        <node2>
            <!-- = node3 -->
            <node3/>
            <!-- = -->
            <!-- = node4:root/example -->
            <node4/>
            <!-- = -->
        </node2>
    </node1>
</root>

Будут такие фрагменты:

part=node3
<node3/>
part=node4
<root>
    <example>
        <node4/>
    </example>
</root>

vue

Для vue-файла опредляются фрагменты: template, script, style. Текст фрагмента - тело соответсвующего раздела vue-файла. Внутри скриптов и шаблона можно определять свои фрагменты. В скрипте - по правилам фрагментов 'js', в шаблоне - по правилам фрагментов 'xml'.

Например для такого файла:

<template>
    <div>
    </div>
</template>

<script>
export default {
    props: {},
    //= data1
    data() {
        return {}
    },
    //=
    methods: {},
}
</script>

<style>
.a {
  color: red;
}
</style>

Будут такие фрагменты:

template
<div>
</div>
script
export default {
    props: {},
    data() {
        return {}
    },
    methods: {},
}
style
.a {
  color: red;
}
data1
data() {
    return {}
},

Генерация файлов для вставки

Для генерации файлов для вставки, создайте файл groovy (или java) в проекте с классом, наследником от jandcode.mdoc.cm.BaseCodeGen.

Любой публичный метод без параметров в таком классе - код генерации текста.

Для использования генератора укажите в атрибуте file имя файла с генератором и после знака '#' имя его метода.

Если расширение файла не указано, подразумевается расширение .groovy или .java.

Дополнительно доступен атрибут mode со значениями:

  • out - (по умолчанию) показывается то, что выводит outText.
  • body - тело метода
  • bodyout - тело метода в перемешку с выводом

Пример:

_inc/CodeGen1.groovy
import jandcode.commons.variant.*
import jandcode.mdoc.builder.*
import jandcode.mdoc.cm.*

/**
 * Пример генератора файлов для команды @@code
 */
class CodeGen1 extends BaseCodeGen {

    /**
     * Метод генерации.
     * Должен вернуть строку с содержимым виртуального файла.
     */
    void gen1() {
        // Доступно:

        // Атрибуты, переданные в команде @@code (IVariantMap с расширениями).
        // Из списка атрибутов исключены file, part, lang, title (они обрабатываются
        // командой @@code).
        Attrs attrs = getAttrs()    // class: jandcode.mdoc.cm.BaseCodeGen.Attrs

        // Установить расширение генерируемого файла.
        // По умолчанию - txt
        setExt("txt")

        // В контексте какого OutBuilder выполняется.
        OutBuilder builder = getOutBuilder()
        // class: jandcode.mdoc.builder.OutBuilder

        // В контексте какого OutFile выполняется.
        OutFile outFile = getOutFile() // class: jandcode.mdoc.builder.OutFile

        // Общий кеш, который существует все время работы outBuilder.
        IVariantMap cache = getCache()

        // Кеш для текущего класса, который существует все время работы outBuilder.
        IVariantMap cacheThis = getCacheThis()

        // возвращаем текст для вставки в @@code
        outText("generated text for attrs: ${attrs}")
    }

    /**
     * Еще один метод генерации.
     */
    void gen2() {
        outText("generated 2 text for attrs: ${attrs}")
    }

}

Использование:

@@code file=CodeGen1#gen1 attr1=1 attr2=2

Результат:

generated text for attrs: [attr1:1, attr2:2, $list:[file=CodeGen1#gen1, attr1=1, attr2=2]]

Использование mode=body:

@@code file=CodeGen1#gen1 attr1=1 attr2=2 mode=body

Результат:

// Доступно:

// Атрибуты, переданные в команде @@code (IVariantMap с расширениями).
// Из списка атрибутов исключены file, part, lang, title (они обрабатываются
// командой @@code).
Attrs attrs = getAttrs()    // class: jandcode.mdoc.cm.BaseCodeGen.Attrs

// Установить расширение генерируемого файла.
// По умолчанию - txt
setExt("txt")

// В контексте какого OutBuilder выполняется.
OutBuilder builder = getOutBuilder()
// class: jandcode.mdoc.builder.OutBuilder

// В контексте какого OutFile выполняется.
OutFile outFile = getOutFile() // class: jandcode.mdoc.builder.OutFile

// Общий кеш, который существует все время работы outBuilder.
IVariantMap cache = getCache()

// Кеш для текущего класса, который существует все время работы outBuilder.
IVariantMap cacheThis = getCacheThis()

// возвращаем текст для вставки в @@code
outText("generated text for attrs: ${attrs}")

Использование mode=bodyout:

@@code file=CodeGen1#gen1 attr1=1 attr2=2 mode=bodyout

Результат:

// Доступно:

// Атрибуты, переданные в команде @@code (IVariantMap с расширениями).
// Из списка атрибутов исключены file, part, lang, title (они обрабатываются
// командой @@code).
Attrs attrs = getAttrs()    // class: jandcode.mdoc.cm.BaseCodeGen.Attrs

// Установить расширение генерируемого файла.
// По умолчанию - txt
setExt("txt")

// В контексте какого OutBuilder выполняется.
OutBuilder builder = getOutBuilder()
// class: jandcode.mdoc.builder.OutBuilder

// В контексте какого OutFile выполняется.
OutFile outFile = getOutFile() // class: jandcode.mdoc.builder.OutFile

// Общий кеш, который существует все время работы outBuilder.
IVariantMap cache = getCache()

// Кеш для текущего класса, который существует все время работы outBuilder.
IVariantMap cacheThis = getCacheThis()

// возвращаем текст для вставки в @@code
// generated text for attrs: [attr1:1, attr2:2, mode:bodyout, $list:[file=CodeGen1#gen1, attr1=1, attr2=2, mode=bodyout]]