Couscous icon indicating copy to clipboard operation
Couscous copied to clipboard

Adding include tag/shortcode to include markdown files

Open errogaht opened this issue 7 years ago • 1 comments

Hello! im using couscous to generate docs and it will be great to use something like this {% include ../parts/api-rules.md %} so i want to change content of partial and cous cous will update all html with this partial

errogaht avatar Jun 07 '17 15:06 errogaht

Hi there.

Ready to get this working?

Skip all of this riffraff and scroll down to get to the PHP code.

Your original MD files will remain intact

Your original *.md files will NOT be overwritten with the included file. Instead, Couscous includes these files into memory, so the update I made edits the contents before it goes into Memory, parsing these Short Tags and including your requested file.

Folder path for includes

Your includes should be in the folder relative to your current *.md file. Optionally if you provide a / leading slash, it acts as an absolute path and should prevent using the relative path. This may be broken/vary between windows/linux, I would stick to relative paths.

Include syntax

[include('includes/request/subscribers.mdd')] You can use ' or ", they should automatically unwrap to pull out the include path.

Example Markdown using Includes

The extension for my includes is .mdd so the files are not parsed by Couscous and turned into HTML. These file extension can be anything you want as long as they are not ending in .md

# My Markdown is hot now.

**Check out this cool stuff below.**

# Subscribers REQUEST json
[include('includes/request/subscribers.mdd')]

# Subscribers RESPONSE json
[include('includes/response/subscribers.mdd')]

Nested includes

Since this code performs a "while" statement on content while it's being replaced, it should automatically handle nested includes (such as an included file containing an include to another file).

Replace file contents with PHP below

src/Module/Markdown/Step/LoadMarkdownFiles.php

<?php

namespace Couscous\Module\Markdown\Step;

use Couscous\Model\Project;
use Couscous\Module\Markdown\Model\MarkdownFile;
use Couscous\Step;
use Symfony\Component\Finder\SplFileInfo;

/**
 * Loads Markdown files in memory.
 *
 * @author Matthieu Napoli <[email protected]>
 */
class LoadMarkdownFiles implements Step
{
    public function __invoke(Project $project)
    {
        $files = $project->sourceFiles();
        $files->name('*.md');

        foreach ($files as $file) {
            /** @var SplFileInfo $file */
            $content = $this->importIncludes(file_get_contents($file->getPathname()), $file->getPath());

            $project->addFile(new MarkdownFile($file->getRelativePathname(), $content));
        }

        $project->watchlist->watchFiles($files);
    }

    private function importIncludes($content, $base_path)
    {
        $open  = '[include(';
        $close = ')]';

        if ( ! strstr($content, $open) || ! strstr($content, $close) )
        {
            return $content;
        }

        while ( strstr($content, $open) && strstr($content, $close) )
        {
            $statement    = substr($content, strpos($content, $open));
            $statement    = trim(substr($statement, 0, strpos($statement, $close) + strlen($close)));
            $file_include = substr($statement, strpos($statement, '(') + 1);
            $file_include = substr($file_include, 0, strpos($file_include, $close));
            $file_include = $this->unwrap($file_include, ["'", '"']);

            if ( substr($file_include, 0, 1) != '/' )
            {
                $file_include = $base_path . '/' . $file_include;
            }

            $file_contents = "# File Not Found: {$file_include}";

            if ( is_file($file_include) )
            {
                $file_contents = file_get_contents($file_include);
            }

            $content = str_replace($statement, $file_contents, $content);
        }

        return $content;
    }

    private function unwrap($str, $encapsulated = [])
    {
        $str          = trim($str);
        $encapsulated = ! is_array($encapsulated) ? [$encapsulated] : $encapsulated;

        foreach ( $encapsulated as $unwrap )
        {
            if ( substr($str, 0, 1) == $unwrap )
            {
                $str = substr($str, 1);
                $str = $this->unwrap($str, $encapsulated);
            }
            if ( substr($str, -1) == $unwrap )
            {
                $str = substr($str, 0, -1);
                $str = $this->unwrap($str, $encapsulated);
            }
        }

        return $str;
    }

}

Recompile Couscous from Source

Run this command in a Linux command prompt:

bin/compile

You will run it from a directory that looks like this:

image

How to get source installed

Go to the main page on this repo - perform a git clone on the repository. When you get it cloned, you should see folder like the one I showed you. You will need to run composer install (if you don't have composer, apt-get install composer should do the trick on an ubuntu/debian environment).

I hope some of this helps. If you can get the PHP file updated, recompile the couscous.phar file using the bin/compile command, you can then have a couscous.phar capable of including using shortcodes.

NHuebner1983 avatar Apr 19 '18 23:04 NHuebner1983