28 Commits
1.1.2 ... 1.2.0

Author SHA1 Message Date
Petra Baranski
cc7f95f4c1 fix: cmake fails to create zip file 2023-07-27 19:22:23 +02:00
Petra Baranski
d203e8502c docs: fix version in README.md 2023-07-27 19:11:29 +02:00
Petra Baranski
7624810374 fix: markdown-bug-report template 2023-07-27 19:09:50 +02:00
Petra Baranski
5dd974cca1 chore: fix cpp-bug-report template 2023-07-27 19:08:21 +02:00
Petra Baranski
6015b0c9e9 Merge pull request #43 from progsource/version-1.2.0
Version 1.2.0
2023-07-27 19:05:08 +02:00
Petra Baranski
155fb2c7e6 docs: update changelog for 1.2.0 2023-07-27 18:55:20 +02:00
Petra Baranski
123b921f2a style: make regex strings more readable 2023-07-27 18:48:03 +02:00
Petra Baranski
aecb1b30e6 chore: have prettier issue templates 2023-07-27 18:48:03 +02:00
Petra Baranski
baa5c9ccd0 ci: create release workflow 2023-07-27 18:48:03 +02:00
Petra Baranski
02d3ccaf22 docs: update version number 2023-07-27 18:47:50 +02:00
Petra Baranski
bf64f3e3dc Merge pull request #42 from progsource/latex-support
Latex support
2023-07-27 15:34:47 +02:00
Petra Baranski
9090c41709 chore: remove possible vscode files via gitignore 2023-07-27 14:52:08 +02:00
Petra Baranski
01d1e48d11 feat: add optional latex block support 2023-07-27 14:51:56 +02:00
Petra Baranski
f0c282e0c0 docs: update info about code block with class 2023-07-25 22:23:02 +02:00
Petra Baranski
cbcef933e1 Merge pull request #41 from progsource/codeblock-parser-language-class
Codeblock parser language class
2023-07-24 20:40:57 +02:00
Petra Baranski
a1001cb991 feat: add class to block code 2023-07-24 20:35:05 +02:00
Petra Baranski
d23ba23a4c docs: update changelog with last merged PR changes 2023-07-24 20:19:18 +02:00
Petra Baranski
d12186af8a Merge pull request #40 from progsource/advanced_config
feat: add config options to en-/disable each parser
2023-07-23 17:56:27 +02:00
Petra Baranski
41396ab246 feat: add config options to en-/disable each parser
Also fix cmake line, so that ctest can find the test executable;
update readme.
2023-07-23 17:51:03 +02:00
Petra Baranski
51e1813373 Merge pull request #39 from progsource/build_update
Use GitHub workflow instead of external tools.

Update cmake and gtest and add gtest via cmake instead
of github submodule.
2023-07-23 09:02:39 +02:00
Petra Baranski
823645995e ci: use github workflow instead of travis and appveyor 2023-07-23 08:51:10 +02:00
Petra Baranski
87ec259c28 build: add option for running tests
cmake configuration for running tests is now in the
tests folder.

Add option in main cmake file that has to be set to
ON and only build the tests in that case.

Update appveyor and travis ci configurations accordingly.
2023-07-23 06:04:34 +02:00
Petra Baranski
6dd47f5de5 build: move gtest into cmake and up cmake min version
cmake minimum required version is now 3.25.

Instead of loading gtest via git submodule, it is now loaded
in the cmake files.

gtest version upped to v1.13.0.
2023-07-23 05:37:11 +02:00
Petra Baranski
f3d934d6ec Merge pull request #35 from quitesimpleorg/fix/add_static_italic
italicparser: Parse(): Add static keyword to regex
2021-04-18 20:40:11 +02:00
Albert S
a28769be2b italicparser: Parse(): Add static keyword to regex
In line with the other parsers, add the static keyword to the
regex.
2021-04-18 20:24:26 +02:00
Petra Baranski
adb1a910d4 fixed spelling in README 2020-10-10 08:11:48 +02:00
Petra Baranski
f38b3cf4fa cleaned up Changelog colors 2020-10-10 08:08:35 +02:00
Petra Baranski
6b632abd44 Added CHANGELOG and CONTRIBUTING 2020-10-10 08:03:21 +02:00
39 changed files with 1110 additions and 201 deletions

View File

@@ -0,0 +1,63 @@
name: C++ Bug Report
description: File a bug report regarding C++ problems
title: "[Bug][C++]: "
labels: ["bug", "triage"]
body:
- type: markdown
attributes:
value: |
Thanks for taking the time to fill out this bug report!
- type: input
id: os
attributes:
label: Operating System
description: On which OS are you running maddy?
placeholder: ex. Windows/Linux/OSX
validations:
required: true
- type: input
id: compiler
attributes:
label: Compiler
description: Which compiler do you use?
placeholder: ex. mingw/Visual Studio/clang
validations:
required: true
- type: input
id: compiler_flags
attributes:
label: Compiler flags
description: Which compiler flags do you use?
placeholder: ex. -fno-rtti
validations:
required: true
- type: dropdown
id: maddy_version
attributes:
label: maddy version
description: What version of maddy are you using?
options:
- 1.2.0 (latest)
- 1.1.2
- 1.1.1
- 1.1.0
- 1.0.3
- 1.0.2
- 1.0.1
- 1.0.0
validations:
required: true
- type: textarea
id: example
attributes:
label: Minimal C++ example
description: To be able to reproduce your issue, please give some example C++ code which creates problems.
validations:
required: true
- type: textarea
id: whats-wrong
attributes:
label: What is not working? What did you try?
description: Also, what did you expect to happen?
validations:
required: true

View File

@@ -0,0 +1,15 @@
name: Feature Request
description: Missing some feature?
labels: ["feature"]
body:
- type: markdown
attributes:
value: |
Thanks for taking the time to create a feature request!
- type: textarea
id: feature-description
attributes:
label: What are you missing in maddy?
description: If you want some extra Markdown supported, please also write a Markdown example and an expected HTML output.
validations:
required: true

View File

@@ -0,0 +1,63 @@
name: Markdown Bug Report
description: File a bug report regarding Markdown problems
title: "[Bug][Markdown]: "
labels: ["bug", "triage"]
body:
- type: markdown
attributes:
value: |
Thanks for taking the time to fill out this bug report!
- type: input
id: os
attributes:
label: Operating System
description: On which OS are you running maddy?
placeholder: ex. Windows/Linux/OSX
validations:
required: true
- type: input
id: compiler
attributes:
label: Compiler
description: Which compiler do you use?
placeholder: ex. mingw/Visual Studio/clang
validations:
required: true
- type: input
id: compiler_flags
attributes:
label: Compiler flags
description: Which compiler flags do you use?
placeholder: ex. -fno-rtti
validations:
required: true
- type: dropdown
id: maddy_version
attributes:
label: maddy version
description: What version of maddy are you using?
options:
- 1.2.0 (latest)
- 1.1.2
- 1.1.1
- 1.1.0
- 1.0.3
- 1.0.2
- 1.0.1
- 1.0.0
validations:
required: true
- type: textarea
id: example
attributes:
label: Minimal Mardown example
description: To be able to reproduce your issue, please give some example Markdown which creates problems.
validations:
required: true
- type: textarea
id: whats-wrong
attributes:
label: What is not working? What did you try?
description: Also, what did you expect to happen?
validations:
required: true

View File

@@ -0,0 +1,34 @@
name: release
permissions:
contents: write
on:
push:
tags:
- '*'
jobs:
release:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: lukka/get-cmake@latest
with:
cmakeVersion: "~3.25.0" # <--= optional, use most recent 3.25.x version
ninjaVersion: "^1.11.1" # <--= optional, use most recent 1.x version
- name: create zip
run: |
mkdir build
mkdir tmp
cd tmp
cmake -DMADDY_CREATE_PACKAGE=ON ..
make maddy_package
- name: create release
uses: svenstaro/upload-release-action@v2
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}
file: build/maddy-src.zip
tag: ${{ github.ref }}
body: "You can find all changes of this release in the [changelog](https://github.com/progsource/maddy/blob/master/CHANGELOG.md)"

63
.github/workflows/run-tests.yml vendored Normal file
View File

@@ -0,0 +1,63 @@
name: run-tests
run-name: test ${{ github.ref }}
on:
push:
branches:
- master
pull_request:
branches:
- master
jobs:
test-on-ubuntu:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: lukka/get-cmake@latest
with:
cmakeVersion: "~3.25.0" # <--= optional, use most recent 3.25.x version
ninjaVersion: "^1.11.1" # <--= optional, use most recent 1.x version
- name: build
run: |
mkdir tmp
cd tmp
cmake -DMADDY_BUILD_WITH_TESTS=ON ..
make -j4
- name: run tests
run: |
./build/MaddyTests
test-on-windows:
runs-on: windows-latest
steps:
- uses: actions/checkout@v3
- uses: lukka/get-cmake@latest
with:
cmakeVersion: "~3.25.0" # <--= optional, use most recent 3.25.x version
ninjaVersion: "^1.11.1" # <--= optional, use most recent 1.x version
- name: build
run: |
mkdir tmp
cd tmp
cmake -G "Visual Studio 17 2022" -A x64 -DMADDY_BUILD_WITH_TESTS=ON ..
cmake --build . --config Debug
- name: run tests
run: |
./build/Debug/MaddyTests.exe
test-on-osx:
runs-on: macos-latest
steps:
- uses: actions/checkout@v3
- uses: lukka/get-cmake@latest
with:
cmakeVersion: "~3.25.0" # <--= optional, use most recent 3.25.x version
ninjaVersion: "^1.11.1" # <--= optional, use most recent 1.x version
- name: build
run: |
mkdir tmp
cd tmp
cmake -DMADDY_BUILD_WITH_TESTS=ON ..
make -j4
- name: run tests
run: |
./build/MaddyTests

4
.gitignore vendored
View File

@@ -161,10 +161,6 @@ tags
### VisualStudioCode ### ### VisualStudioCode ###
.vscode/* .vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
.history .history
### Xcode ### ### Xcode ###

3
.gitmodules vendored
View File

@@ -1,3 +0,0 @@
[submodule "libs/gtest"]
path = libs/gtest
url = https://github.com/google/googletest.git

View File

@@ -1,32 +0,0 @@
sudo: false
language: cpp
matrix:
include:
- os: linux
dist: xenial
sudo: require
addons:
apt:
sources:
- sourceline: 'ppa:ubuntu-toolchain-r/test'
packages:
- g++-7
env:
- MATRIX_EVAL="CC=gcc-7 && CXX=g++-7"
- os: osx
osx_image: xcode10
compiler: clang
env:
- MATRIX_EVAL="CC=clang && CXX=clang++"
before_install:
# This is necessary to solve https://github.com/travis-ci/travis-ci/issues/9649
- eval "${MATRIX_EVAL}"
script:
- mkdir tmp
- cd tmp
- cmake ..
- make -j4
- ../build/MaddyTests

View File

@@ -9,3 +9,4 @@ Patrick José Pereira (patrickelectric@gmail.com)
Martin Kopecky (martin.kopecky357@gmail.com) Martin Kopecky (martin.kopecky357@gmail.com)
Andrew Mettlach (dmmettlach@gmail.com) Andrew Mettlach (dmmettlach@gmail.com)
Evan Klitzke (evan@eklitzke.org) Evan Klitzke (evan@eklitzke.org)
Albert Schwarzkopf (dev-maddy@quitesimple.org)

81
CHANGELOG.md Normal file
View File

@@ -0,0 +1,81 @@
# Changelog
This file tries to follow roughly [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
maddy uses [semver versioning](https://semver.org/).
## Badges
* ![**FIXED**](https://img.shields.io/badge/-FIXED-%23090) for any bug fixes.
* ![**SECURITY**](https://img.shields.io/badge/-SECURITY-%23c00) in case of vulnerabilities.
* ![**ADDED**](https://img.shields.io/badge/-ADDED-%23099) for new features.
* ![**CHANGED**](https://img.shields.io/badge/-CHANGED-%23e90) for changes in existing functionality.
* ![**DEPRECATED**](https://img.shields.io/badge/-DEPRECATED-%23666) for soon-to-be removed features.
* ![**REMOVED**](https://img.shields.io/badge/-REMOVED-%23900) for now removed features.
## Upcoming
* ?
## version 1.2.0 2023-07-27
* ![**ADDED**](https://img.shields.io/badge/-ADDED-%23099) Added Changelog
* ![**ADDED**](https://img.shields.io/badge/-ADDED-%23099) Added contribution guideline
* ![**CHANGED**](https://img.shields.io/badge/-CHANGED-%23e90) updated cmake minimum required version to 3.25
* ![**CHANGED**](https://img.shields.io/badge/-CHANGED-%23e90) gtest is now loaded via cmake and not a git submodule any longer - updated gtest version to 1.13.0
* ![**CHANGED**](https://img.shields.io/badge/-CHANGED-%23e90) tests are only run if the cmake option `MADDY_BUILD_WITH_TESTS` is on, moved test cmake code to the `tests` subfolder
* ![**REMOVED**](https://img.shields.io/badge/-REMOVED-%23900) travis CI and appveyor
* ![**ADDED**](https://img.shields.io/badge/-ADDED-%23099) GitHub workflow for tests
* ![**DEPRECATED**](https://img.shields.io/badge/-DEPRECATED-%23666) config flags `isEmphasizedParserEnabled` and `isHTMLWrappedInParagraph`
* ![**ADDED**](https://img.shields.io/badge/-ADDED-%23099) config flag `enabledParsers` to en-/disable each parser separately
* ![**ADDED**](https://img.shields.io/badge/-ADDED-%23099) class attribute to code blocks if there is text after the three backticks like ` ```cpp`
* ![**ADDED**](https://img.shields.io/badge/-ADDED-%23099) optional support for latex blocks - it's off by default
* ![**ADDED**](https://img.shields.io/badge/-ADDED-%23099) version info to the parser class
* ![**ADDED**](https://img.shields.io/badge/-ADDED-%23099) GitHub workflow for release, so that one can include maddy easier via cmake's `FetchContent`
## version 1.1.2 2020-10-04
* ![**ADDED**](https://img.shields.io/badge/-ADDED-%23099) `*`, `+` and `-` are equivalent for making unordered bullet list
* ![**ADDED**](https://img.shields.io/badge/-ADDED-%23099) Parsing support for fully numeric ordered lists
* ![**CHANGED**](https://img.shields.io/badge/-CHANGED-%23e90) make `Parser::Parse` accept istreams instead of stringstream
* ![**CHANGED**](https://img.shields.io/badge/-CHANGED-%23e90) CMake is creating an interface library which you can include in your own `target_link_libraries` and the global include path is untouched from maddy.
## version 1.1.1 2019-12-27
* ![**ADDED**](https://img.shields.io/badge/-ADDED-%23099) BreakLineParser
* ![**ADDED**](https://img.shields.io/badge/-ADDED-%23099) HTMLParser
* ![**ADDED**](https://img.shields.io/badge/-ADDED-%23099) Added optional config with the following options:
* en-/disable the emphasized parser
* wrap/not wrap HTML in markdown within a paragraph in output
* ![**CHANGED**](https://img.shields.io/badge/-CHANGED-%23e90) Updated gtest to release-1.10.0 to fix build issues
## version 1.1.0 2019-02-19
* ![**FIXED**](https://img.shields.io/badge/-FIXED-%23090) Added missing includes to BlockParser
* ![**FIXED**](https://img.shields.io/badge/-FIXED-%23090) Added missing dtor to BlockParser and LineParser
* ![**ADDED**](https://img.shields.io/badge/-ADDED-%23099) `__test__` can also be used to get `<strong>text</strong>`
* ![**ADDED**](https://img.shields.io/badge/-ADDED-%23099) Added AppVeyor CI
* ![**ADDED**](https://img.shields.io/badge/-ADDED-%23099) Added clang for CI
* ![**CHANGED**](https://img.shields.io/badge/-CHANGED-%23e90) Single underscore `_` results in emphasized tag `<em>`, single `*` in italic tag `<i>`
## version 1.0.3 2018-01-18
* ![**FIXED**](https://img.shields.io/badge/-FIXED-%23090) Make sure that all parsers are finished
* ![**FIXED**](https://img.shields.io/badge/-FIXED-%23090) ol documentation
* ![**ADDED**](https://img.shields.io/badge/-ADDED-%23099) Added Travic-CI with gcc
* ![**ADDED**](https://img.shields.io/badge/-ADDED-%23099) Added Howto for running the tests on the README
## version 1.0.2 2017-12-26
* ![**FIXED**](https://img.shields.io/badge/-FIXED-%23090) Fixed inline code for directly following letters (bold, emphasized and strikethrough)
## version 1.0.1 2017-12-25
* ![**FIXED**](https://img.shields.io/badge/-FIXED-%23090) Fixed inline code for bold, emphasized and strikethrough
* ![**FIXED**](https://img.shields.io/badge/-FIXED-%23090) Fixed spelling in README
* ![**ADDED**](https://img.shields.io/badge/-ADDED-%23099) Use Gold Linker on Unix if available for faster compile time
* ![**ADDED**](https://img.shields.io/badge/-ADDED-%23099) Added Github ISSUE_TEMPLATE
## version 1.0.0 2017-12-25
initial release

View File

@@ -1,17 +1,10 @@
# This project is licensed under the MIT license. For more information see the # This project is licensed under the MIT license. For more information see the
# LICENSE file. # LICENSE file.
cmake_minimum_required(VERSION 2.8) cmake_minimum_required(VERSION 3.25)
project(maddy) project(maddy)
enable_testing()
# ------------------------------------------------------------------------------
set(MADDY_CPP_VERSION 14)
add_definitions(-DCPP_VERSION=${MADDY_CPP_VERSION})
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
set(CMAKE_BINARY_DIR ${CMAKE_CURRENT_SOURCE_DIR}/build) set(CMAKE_BINARY_DIR ${CMAKE_CURRENT_SOURCE_DIR}/build)
@@ -20,43 +13,28 @@ set(LIBRARY_OUTPUT_PATH ${CMAKE_BINARY_DIR})
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
option(MADDY_BUILD_WITH_TESTS "enable building tests - does not work with zip download" OFF)
if(${MADDY_BUILD_WITH_TESTS})
enable_testing()
endif()
option(MADDY_CREATE_PACKAGE "create a package for a version release" OFF)
# ------------------------------------------------------------------------------
set(MADDY_INCLUDE_DIR ${PROJECT_SOURCE_DIR}/include) set(MADDY_INCLUDE_DIR ${PROJECT_SOURCE_DIR}/include)
file(GLOB_RECURSE MADDY_TESTS_FILES ${CMAKE_CURRENT_SOURCE_DIR}/tests/maddy/*.cpp)
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
if (UNIX) if(NOT DEFINED CMAKE_CXX_STANDARD)
set( set(CMAKE_CXX_STANDARD 14)
CMAKE_CXX_FLAGS
"${CMAKE_CXX_FLAGS} -g -std=c++${MADDY_CPP_VERSION} -Wall -Wpedantic -Wextra -Wno-ignored-qualifiers -fno-rtti -fno-exceptions -fsanitize=address -fno-omit-frame-pointer"
)
else()
set(
CMAKE_CXX_FLAGS
"${CMAKE_CXX_FLAGS} -std=c++${MADDY_CPP_VERSION}"
)
endif() endif()
set(CMAKE_CXX_STANDARD_REQUIRED ON)
# ------------------------------------------------------------------------------ if(${CMAKE_CXX_STANDARD} LESS 14)
message(FATAL_ERROR "maddy requires >=C++14")
if (UNIX AND NOT APPLE)
execute_process(COMMAND ${CMAKE_CXX_COMPILER}
-fuse-ld=gold -Wl,--version
ERROR_QUIET OUTPUT_VARIABLE ld_version)
if ("${ld_version}" MATCHES "GNU gold")
message(STATUS "Found Gold linker, use faster linker")
set(CMAKE_EXE_LINKER_FLAGS
"${CMAKE_EXE_LINKER_FLAGS} -fuse-ld=gold")
set(CMAKE_SHARED_LINKER_FLAGS
"${CMAKE_SHARED_LINKER_FLAGS} -fuse-ld=gold ")
endif() endif()
endif()
# ------------------------------------------------------------------------------
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/libs/gtest/googlemock)
add_subdirectory(libs)
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
@@ -67,14 +45,17 @@ target_include_directories(maddy INTERFACE
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
add_executable( if(${MADDY_BUILD_WITH_TESTS})
MaddyTests add_subdirectory(tests)
${MADDY_TESTS_FILES} endif()
${CMAKE_CURRENT_SOURCE_DIR}/tests/main.cpp
) # ------------------------------------------------------------------------------
target_include_directories(MaddyTests PUBLIC
${LIBS_INCLUDE_DIRS} if(${MADDY_CREATE_PACKAGE})
${CMAKE_CURRENT_SOURCE_DIR}/tests set(MADDY_PACKAGE_FILES include/ CMakeLists.txt LICENSE)
) add_custom_command(OUTPUT ${CMAKE_BINARY_DIR}/${PROJECT_NAME}-src.zip
target_link_libraries(MaddyTests maddy gmock_main) COMMAND ${CMAKE_COMMAND} -E tar c ${CMAKE_BINARY_DIR}/${PROJECT_NAME}-src.zip --format=zip -- ${MADDY_PACKAGE_FILES}
add_test(MaddyTests ${CMAKE_CURRENT_SOURCE_DIR}/build/MaddyTests) WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
DEPENDS ${MADDY_PACKAGE_FILES})
add_custom_target(${PROJECT_NAME}_package DEPENDS ${CMAKE_BINARY_DIR}/${PROJECT_NAME}-src.zip)
endif()

26
CONTRIBUTING.md Normal file
View File

@@ -0,0 +1,26 @@
# Contribution Guideline
First of all: I am thankful for any contribution this project gets.
## Creating Issues
You found a bug, you miss some feature in the project or have an idea how to
improve the code? Then [create a GitHub issue](https://github.com/progsource/maddy/issues/new).
## Creating Pull-Requests
* Use a branch other than master.
* Add yourself to the `AUTHORS` file.
* Try to stick with the code style the files are having right now.
* Write in your commit messages what/why you did something. Often times a one-liner might be enough, but if you want to write more, make an empty line in between like:
```
Short description
More and longer text for the commit message with some more information.
That can go over multiple lines.
```
Do not include Github issue ticket numbers inside commit messages.
* Explain for what your PR is for - like providing a use-case or something similar.
* Update documentation of the Markdown syntax if anything changed there. (`docs/definitions.md`)
* Add a changelog entry at "Upcoming" inside of `CHANGELOG.md`
* Make sure, that the tests are successful.

View File

@@ -1,17 +0,0 @@
## Minimal Code Example
```
```
## Conditions
. | .
--------------------- | ------------------
**Operating System:** | ?
**Compiler:** | ?
**Compiler flags:** | ?
**maddy version:** | ?
## Description
What did you try? What is not working?

View File

@@ -1,4 +1,4 @@
Copyright 2017, 2018, 2019, 2020 M. Petra Baranski Copyright 2017, 2018, 2019, 2020, 2023 M. Petra Baranski
Permission is hereby granted, free of charge, to any person obtaining a copy of Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in this software and associated documentation files (the "Software"), to deal in

View File

@@ -1,9 +1,7 @@
# maddy # maddy
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
[![Version: 1.1.2](https://img.shields.io/badge/Version-1.1.2-brightgreen.svg)](https://semver.org/) [![Version: 1.2.0](https://img.shields.io/badge/Version-1.2.0-brightgreen.svg)](https://semver.org/)
[![Travis Build Status](https://travis-ci.org/progsource/maddy.svg?branch=master)](https://travis-ci.org/progsource/maddy)
[![Appveyor Build Status](https://ci.appveyor.com/api/projects/status/04m0lg27kigv1pg8/branch/master?svg=true)](https://ci.appveyor.com/project/progsource/maddy/branch/master)
maddy is a C++ Markdown to HTML **header-only** parser library. maddy is a C++ Markdown to HTML **header-only** parser library.
@@ -15,7 +13,7 @@ It is tested to work on:
* Linux (gcc) * Linux (gcc)
* OSX (clang) * OSX (clang)
* Windows (Visual Studio 2017) * Windows (Visual Studio 17 2022, mingw)
## Dependencies ## Dependencies
@@ -23,13 +21,40 @@ It is tested to work on:
## Why maddy? ## Why maddy?
When I was needing a Markdown parser in C++ I couldn't find any, that was When I was looking for a Markdown parser in C++, I couldn't find any, that was
fitting my needs. So I simply wrote my own one. fitting my needs. So I simply wrote my own one.
## Markdown syntax ## Markdown syntax
The supported syntax can be found in the [definitions docs](docs/definitions.md). The supported syntax can be found in the [definitions docs](docs/definitions.md).
## How to add maddy to your cmake project
You can use [FetchContent](https://cmake.org/cmake/help/latest/module/FetchContent.html)
which was introduced in CMake 3.11.
This way you can add
```cmake
include(FetchContent)
FetchContent_Declare(
maddy
URL https://github.com/progsource/maddy/.../maddy-src.zip
)
FetchContent_MakeAvailable(maddy)
add_executable(my_exe)
target_link_libraries(my_exe PUBLIC maddy)
```
to your CMake file to make it work. Check the
[release](https://github.com/progsource/maddy/releases) for the full
zip-file-url.
The zip only contains a `CMakeLists.txt`, the `include` folder and the `LICENSE`
file.
## How to use ## How to use
To use maddy in your project, simply add the include path of maddy to yours To use maddy in your project, simply add the include path of maddy to yours
@@ -45,13 +70,18 @@ std::stringstream markdownInput("");
// config is optional // config is optional
std::shared_ptr<maddy::ParserConfig> config = std::make_shared<maddy::ParserConfig>(); std::shared_ptr<maddy::ParserConfig> config = std::make_shared<maddy::ParserConfig>();
config->isEmphasizedParserEnabled = true; // default // config->isEmphasizedParserEnabled = false; // default true - this flag is deprecated
config->isHTMLWrappedInParagraph = true; // default // config->isHTMLWrappedInParagraph = false; // default true - this flag is deprecated
config->enabledParsers &= ~maddy::types::EMPHASIZED_PARSER; // equivalent to !isEmphasizedParserEnabled
config->enabledParsers |= maddy::types::HTML_PARSER; // equivalent to !isHTMLWrappedInParagraph
std::shared_ptr<maddy::Parser> parser = std::make_shared<maddy::Parser>(config); std::shared_ptr<maddy::Parser> parser = std::make_shared<maddy::Parser>(config);
std::string htmlOutput = parser->Parse(markdownInput); std::string htmlOutput = parser->Parse(markdownInput);
``` ```
You can find all parser flags in
[`include/maddy/parserconfig.h`](include/maddy/parserconfig.h).
## How to run the tests ## How to run the tests
*(tested on Linux with *(tested on Linux with
@@ -63,10 +93,9 @@ Open your preferred terminal and type:
```shell ```shell
git clone https://github.com/progsource/maddy.git git clone https://github.com/progsource/maddy.git
cd maddy cd maddy
git submodule update --init --recursive
mkdir tmp mkdir tmp
cd tmp cd tmp
cmake .. cmake -DMADDY_BUILD_WITH_TESTS=ON ..
make make
make test # or run the executable in ../build/MaddyTests make test # or run the executable in ../build/MaddyTests
``` ```
@@ -76,5 +105,6 @@ make test # or run the executable in ../build/MaddyTests
There are different possibilities: There are different possibilities:
* [Create a GitHub issue](https://github.com/progsource/maddy/issues/new) * [Create a GitHub issue](https://github.com/progsource/maddy/issues/new)
* Create a pull request with an own branch (don't forget to put yourself in the * Create a pull request with an own branch
AUTHORS file)
Please also read [CONTRIBUTING.md](CONTRIBUTING.md).

View File

@@ -1,15 +0,0 @@
image: Visual Studio 2017
install:
- cmd: git submodule update --init --recursive
before_build:
- cmd: mkdir tmp
- cmd: cd tmp
- cmd: cmake -G "Visual Studio 15 Win64" ..
build:
project: $(APPVEYOR_BUILD_FOLDER)\tmp\$(APPVEYOR_PROJECT_NAME).sln
test_script:
- cmd: ctest -VV -C "Debug"

View File

@@ -220,6 +220,18 @@ results in
<pre><code> <pre><code>
some code some code
</code></pre> </code></pre>
```
```cpp
int a = 42;
```
results in
```html
<pre class="cpp"><code>
int a = 42;
</code></pre>
``` ```
## Inline code ## Inline code
@@ -364,3 +376,29 @@ becomes
</table> </table>
``` ```
table header and footer are optional table header and footer are optional
## LaTeX(MathJax) block support
To turn on the LaTeX support - which basically is only a
[MathJax](https://www.mathjax.org/) support and makes sure, that formulas aren't
internally checked for other parsers - it has to be enabled in config:
```cpp
std::shared_ptr<maddy::ParserConfig> config = std::make_shared<maddy::ParserConfig>();
config->enabledParsers |= maddy::types::LATEX_BLOCK_PARSER;
std::shared_ptr<maddy::Parser> parser = std::make_shared<maddy::Parser>(config);
std::string htmlOutput = parser->Parse(markdownInput);
```
After this you can do the following in Markdown:
```
$$x = {-b \\pm \\sqrt{b^2-4ac} \\over 2a}.$$
```
Which results in
```html
$$x = {-b \\pm \\sqrt{b^2-4ac} \\over 2a}.$$\n
```

View File

@@ -54,7 +54,7 @@ public:
static bool static bool
IsStartingLine(const std::string& line) IsStartingLine(const std::string& line)
{ {
static std::regex re("^- \\[[x| ]\\] .*"); static std::regex re(R"(^- \[[x| ]\] .*)");
return std::regex_match(line, re); return std::regex_match(line, re);
} }
@@ -92,11 +92,11 @@ protected:
static std::regex lineRegex("^(- )"); static std::regex lineRegex("^(- )");
line = std::regex_replace(line, lineRegex, ""); line = std::regex_replace(line, lineRegex, "");
static std::regex emptyBoxRegex("^\\[ \\]"); static std::regex emptyBoxRegex(R"(^\[ \])");
static std::string emptyBoxReplacement = "<input type=\"checkbox\"/>"; static std::string emptyBoxReplacement = "<input type=\"checkbox\"/>";
line = std::regex_replace(line, emptyBoxRegex, emptyBoxReplacement); line = std::regex_replace(line, emptyBoxRegex, emptyBoxReplacement);
static std::regex boxRegex("^\\[x\\]"); static std::regex boxRegex(R"(^\[x\])");
static std::string boxReplacement = "<input type=\"checkbox\" checked=\"checked\"/>"; static std::string boxReplacement = "<input type=\"checkbox\" checked=\"checked\"/>";
line = std::regex_replace(line, boxRegex, boxReplacement); line = std::regex_replace(line, boxRegex, boxReplacement);

View File

@@ -74,7 +74,7 @@ public:
static bool static bool
IsStartingLine(const std::string& line) IsStartingLine(const std::string& line)
{ {
static std::regex re("^(?:`){3}$"); static std::regex re("^(?:`){3}(.*)$");
return std::regex_match(line, re); return std::regex_match(line, re);
} }
@@ -123,6 +123,13 @@ protected:
return; return;
} }
} }
else if (!this->isStarted && line.substr(0, 3) == "```")
{
line = "<pre class=\"" + line.substr(3) + "\"><code>\n";
this->isStarted = true;
this->isFinished = false;
return;
}
line += "\n"; line += "\n";
} }

View File

@@ -41,7 +41,7 @@ public:
void void
Parse(std::string& line) override Parse(std::string& line) override
{ {
static std::regex re("(?!.*`.*|.*<code>.*)_(?!.*`.*|.*<\\/code>.*)([^_]*)_(?!.*`.*|.*<\\/code>.*)"); static std::regex re(R"((?!.*`.*|.*<code>.*)_(?!.*`.*|.*<\/code>.*)([^_]*)_(?!.*`.*|.*<\/code>.*))");
static std::string replacement = "<em>$1</em>"; static std::string replacement = "<em>$1</em>";
line = std::regex_replace(line, re, replacement); line = std::regex_replace(line, re, replacement);

View File

@@ -41,7 +41,7 @@ public:
void void
Parse(std::string& line) override Parse(std::string& line) override
{ {
static std::regex re("\\!\\[([^\\]]*)\\]\\(([^\\]]*)\\)"); static std::regex re(R"(\!\[([^\]]*)\]\(([^\]]*)\))");
static std::string replacement = "<img src=\"$2\" alt=\"$1\"/>"; static std::string replacement = "<img src=\"$2\" alt=\"$1\"/>";
line = std::regex_replace(line, re, replacement); line = std::regex_replace(line, re, replacement);

View File

@@ -39,7 +39,7 @@ public:
void void
Parse(std::string& line) override Parse(std::string& line) override
{ {
std::regex re("(?!.*`.*|.*<code>.*)\\*(?!.*`.*|.*<\\/code>.*)([^\\*]*)\\*(?!.*`.*|.*<\\/code>.*)"); static std::regex re(R"((?!.*`.*|.*<code>.*)\*(?!.*`.*|.*<\/code>.*)([^\*]*)\*(?!.*`.*|.*<\/code>.*))");
static std::string replacement = "<i>$1</i>"; static std::string replacement = "<i>$1</i>";
line = std::regex_replace(line, re, replacement); line = std::regex_replace(line, re, replacement);
} }

View File

@@ -0,0 +1,135 @@
/*
* This project is licensed under the MIT license. For more information see the
* LICENSE file.
*/
#pragma once
// -----------------------------------------------------------------------------
#include <functional>
#include <string>
#include <regex>
#include "maddy/blockparser.h"
// -----------------------------------------------------------------------------
namespace maddy {
// -----------------------------------------------------------------------------
/**
* LatexBlockParser
*
* Support for https://www.mathjax.org/
* Be aware, that if you want to make MathJax work, you need also their
* JavaScript library added to your HTML code.
* maddy does not itself add that code to be more flexible in how you write your
* head and full body.
*
* From Markdown: `$$` surrounded text
*
* ```
* $$some formula
* $$
* ```
*
* To HTML:
*
* ```
* $$some formula
* $$
* ```
*
* @class
*/
class LatexBlockParser : public BlockParser
{
public:
/**
* ctor
*
* @method
* @param {std::function<void(std::string&)>} parseLineCallback
* @param {std::function<std::shared_ptr<BlockParser>(const std::string& line)>} getBlockParserForLineCallback
*/
LatexBlockParser(
std::function<void(std::string&)> parseLineCallback,
std::function<std::shared_ptr<BlockParser>(const std::string& line)> getBlockParserForLineCallback
)
: BlockParser(parseLineCallback, getBlockParserForLineCallback)
, isStarted(false)
, isFinished(false)
{}
/**
* IsStartingLine
*
* If the line starts with two dollars, then it is a latex block.
*
* ```
* $$
* ```
*
* @method
* @param {const std::string&} line
* @return {bool}
*/
static bool
IsStartingLine(const std::string& line)
{
static std::regex re(R"(^(?:\$){2}(.*)$)");
return std::regex_match(line, re);
}
/**
* IsFinished
*
* @method
* @return {bool}
*/
bool
IsFinished() const override
{
return this->isFinished;
}
protected:
bool
isInlineBlockAllowed() const override
{
return false;
}
bool
isLineParserAllowed() const override
{
return false;
}
void
parseBlock(std::string& line) override
{
if (!this->isStarted && line.substr(0, 2) == "$$")
{
this->isStarted = true;
this->isFinished = false;
}
if (this->isStarted && !this->isFinished && line.size() > 1 && line.substr(line.size() - 2, 2) == "$$")
{
this->isFinished = true;
this->isStarted = false;
}
line += "\n";
}
private:
bool isStarted;
bool isFinished;
}; // class LatexBlockParser
// -----------------------------------------------------------------------------
} // namespace maddy

View File

@@ -41,7 +41,7 @@ public:
void void
Parse(std::string& line) override Parse(std::string& line) override
{ {
static std::regex re("\\[([^\\]]*)\\]\\(([^\\]]*)\\)"); static std::regex re(R"(\[([^\]]*)\]\(([^\]]*)\))");
static std::string replacement = "<a href=\"$2\">$1</a>"; static std::string replacement = "<a href=\"$2\">$1</a>";
line = std::regex_replace(line, re, replacement); line = std::regex_replace(line, re, replacement);

View File

@@ -89,9 +89,9 @@ protected:
bool isStartOfNewListItem = this->isStartOfNewListItem(line); bool isStartOfNewListItem = this->isStartOfNewListItem(line);
uint32_t indentation = getIndentationWidth(line); uint32_t indentation = getIndentationWidth(line);
static std::regex orderedlineRegex("^[1-9]+[0-9]*\\. "); static std::regex orderedlineRegex(R"(^[1-9]+[0-9]*\. )");
line = std::regex_replace(line, orderedlineRegex, ""); line = std::regex_replace(line, orderedlineRegex, "");
static std::regex unorderedlineRegex("^\\* "); static std::regex unorderedlineRegex(R"(^\* )");
line = std::regex_replace(line, unorderedlineRegex, ""); line = std::regex_replace(line, unorderedlineRegex, "");
if (!this->isStarted) if (!this->isStarted)
@@ -132,7 +132,7 @@ private:
bool bool
isStartOfNewListItem(const std::string& line) const isStartOfNewListItem(const std::string& line) const
{ {
static std::regex re("^(?:[1-9]+[0-9]*\\. |\\* ).*"); static std::regex re(R"(^(?:[1-9]+[0-9]*\. |\* ).*)");
return std::regex_match(line, re); return std::regex_match(line, re);
} }
}; // class OrderedListParser }; // class OrderedListParser

View File

@@ -34,11 +34,13 @@ public:
*/ */
ParagraphParser( ParagraphParser(
std::function<void(std::string&)> parseLineCallback, std::function<void(std::string&)> parseLineCallback,
std::function<std::shared_ptr<BlockParser>(const std::string& line)> getBlockParserForLineCallback std::function<std::shared_ptr<BlockParser>(const std::string& line)> getBlockParserForLineCallback,
bool isEnabled
) )
: BlockParser(parseLineCallback, getBlockParserForLineCallback) : BlockParser(parseLineCallback, getBlockParserForLineCallback)
, isStarted(false) , isStarted(false)
, isFinished(false) , isFinished(false)
, isEnabled(isEnabled)
{} {}
/** /**
@@ -88,19 +90,31 @@ protected:
void void
parseBlock(std::string& line) override parseBlock(std::string& line) override
{ {
if (!this->isStarted) if (this->isEnabled && !this->isStarted)
{ {
line = "<p>" + line + " "; line = "<p>" + line + " ";
this->isStarted = true; this->isStarted = true;
return; return;
} }
else if (!this->isEnabled && !this->isStarted)
{
line += " ";
this->isStarted = true;
return;
}
if (line.empty()) if (this->isEnabled && line.empty())
{ {
line += "</p>"; line += "</p>";
this->isFinished = true; this->isFinished = true;
return; return;
} }
else if (!this->isEnabled && line.empty())
{
line += "<br/>";
this->isFinished = true;
return;
}
line += " "; line += " ";
} }
@@ -108,6 +122,7 @@ protected:
private: private:
bool isStarted; bool isStarted;
bool isFinished; bool isFinished;
bool isEnabled;
}; // class ParagraphParser }; // class ParagraphParser
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------

View File

@@ -18,6 +18,7 @@
#include "maddy/headlineparser.h" #include "maddy/headlineparser.h"
#include "maddy/horizontallineparser.h" #include "maddy/horizontallineparser.h"
#include "maddy/htmlparser.h" #include "maddy/htmlparser.h"
#include "maddy/latexblockparser.h"
#include "maddy/orderedlistparser.h" #include "maddy/orderedlistparser.h"
#include "maddy/paragraphparser.h" #include "maddy/paragraphparser.h"
#include "maddy/quoteparser.h" #include "maddy/quoteparser.h"
@@ -50,6 +51,14 @@ namespace maddy {
class Parser class Parser
{ {
public: public:
/**
* Version info
*
* Check https://github.com/progsource/maddy/blob/master/CHANGELOG.md
* for the changelog.
*/
static const std::string VERSION() { static const std::string v = "1.2.0"; return v; }
/** /**
* ctor * ctor
* *
@@ -59,15 +68,82 @@ public:
*/ */
Parser(std::shared_ptr<ParserConfig> config = nullptr) Parser(std::shared_ptr<ParserConfig> config = nullptr)
: config(config) : config(config)
, breakLineParser(std::make_shared<BreakLineParser>()) {
, emphasizedParser(std::make_shared<EmphasizedParser>()) // deprecated backward compatibility
, imageParser(std::make_shared<ImageParser>()) // will be removed in 1.4.0 latest including the booleans
, inlineCodeParser(std::make_shared<InlineCodeParser>()) if (this->config && !this->config->isEmphasizedParserEnabled)
, italicParser(std::make_shared<ItalicParser>()) {
, linkParser(std::make_shared<LinkParser>()) this->config->enabledParsers &= ~maddy::types::EMPHASIZED_PARSER;
, strikeThroughParser(std::make_shared<StrikeThroughParser>()) }
, strongParser(std::make_shared<StrongParser>()) if (this->config && !this->config->isHTMLWrappedInParagraph)
{} {
this->config->enabledParsers |= maddy::types::HTML_PARSER;
}
if (
!this->config ||
(this->config->enabledParsers & maddy::types::BREAKLINE_PARSER) != 0
)
{
this->breakLineParser = std::make_shared<BreakLineParser>();
}
if (
!this->config ||
(this->config->enabledParsers & maddy::types::EMPHASIZED_PARSER) != 0
)
{
this->emphasizedParser = std::make_shared<EmphasizedParser>();
}
if (
!this->config ||
(this->config->enabledParsers & maddy::types::IMAGE_PARSER) != 0
)
{
this->imageParser = std::make_shared<ImageParser>();
}
if (
!this->config ||
(this->config->enabledParsers & maddy::types::INLINE_CODE_PARSER) != 0
)
{
this->inlineCodeParser = std::make_shared<InlineCodeParser>();
}
if (
!this->config ||
(this->config->enabledParsers & maddy::types::ITALIC_PARSER) != 0
)
{
this->italicParser = std::make_shared<ItalicParser>();
}
if (
!this->config ||
(this->config->enabledParsers & maddy::types::LINK_PARSER) != 0
)
{
this->linkParser = std::make_shared<LinkParser>();
}
if (
!this->config ||
(this->config->enabledParsers & maddy::types::STRIKETHROUGH_PARSER) != 0
)
{
this->strikeThroughParser = std::make_shared<StrikeThroughParser>();
}
if (
!this->config ||
(this->config->enabledParsers & maddy::types::STRONG_PARSER) != 0
)
{
this->strongParser = std::make_shared<StrongParser>();
}
}
/** /**
* Parse * Parse
@@ -132,91 +208,175 @@ private:
runLineParser(std::string& line) const runLineParser(std::string& line) const
{ {
// Attention! ImageParser has to be before LinkParser // Attention! ImageParser has to be before LinkParser
if (this->imageParser)
{
this->imageParser->Parse(line); this->imageParser->Parse(line);
}
if (this->linkParser)
{
this->linkParser->Parse(line); this->linkParser->Parse(line);
}
// Attention! StrongParser has to be before EmphasizedParser // Attention! StrongParser has to be before EmphasizedParser
if (this->strongParser)
{
this->strongParser->Parse(line); this->strongParser->Parse(line);
}
if (!this->config || this->config->isEmphasizedParserEnabled) if (this->emphasizedParser)
{ {
this->emphasizedParser->Parse(line); this->emphasizedParser->Parse(line);
} }
if (this->strikeThroughParser)
{
this->strikeThroughParser->Parse(line); this->strikeThroughParser->Parse(line);
}
if (this->inlineCodeParser)
{
this->inlineCodeParser->Parse(line); this->inlineCodeParser->Parse(line);
}
if (this->italicParser)
{
this->italicParser->Parse(line); this->italicParser->Parse(line);
}
if (this->breakLineParser)
{
this->breakLineParser->Parse(line); this->breakLineParser->Parse(line);
} }
}
std::shared_ptr<BlockParser> std::shared_ptr<BlockParser>
getBlockParserForLine(const std::string& line) const getBlockParserForLine(const std::string& line) const
{ {
std::shared_ptr<BlockParser> parser; std::shared_ptr<BlockParser> parser;
if (maddy::CodeBlockParser::IsStartingLine(line)) if (
(
!this->config ||
(this->config->enabledParsers & maddy::types::CODE_BLOCK_PARSER) != 0
) &&
maddy::CodeBlockParser::IsStartingLine(line)
)
{ {
parser = std::make_shared<maddy::CodeBlockParser>( parser = std::make_shared<maddy::CodeBlockParser>(
nullptr, nullptr,
nullptr nullptr
); );
} }
else if (maddy::HeadlineParser::IsStartingLine(line)) else if (
this->config &&
(this->config->enabledParsers & maddy::types::LATEX_BLOCK_PARSER) != 0 &&
maddy::LatexBlockParser::IsStartingLine(line)
)
{
parser = std::make_shared<LatexBlockParser>(
nullptr,
nullptr
);
}
else if (
(
!this->config ||
(this->config->enabledParsers & maddy::types::HEADLINE_PARSER) != 0
) &&
maddy::HeadlineParser::IsStartingLine(line)
)
{ {
parser = std::make_shared<maddy::HeadlineParser>( parser = std::make_shared<maddy::HeadlineParser>(
nullptr, nullptr,
nullptr nullptr
); );
} }
else if (maddy::HorizontalLineParser::IsStartingLine(line)) else if (
(
!this->config ||
(this->config->enabledParsers & maddy::types::HORIZONTAL_LINE_PARSER) != 0
) &&
maddy::HorizontalLineParser::IsStartingLine(line)
)
{ {
parser = std::make_shared<maddy::HorizontalLineParser>( parser = std::make_shared<maddy::HorizontalLineParser>(
nullptr, nullptr,
nullptr nullptr
); );
} }
else if (maddy::QuoteParser::IsStartingLine(line)) else if (
(
!this->config ||
(this->config->enabledParsers & maddy::types::QUOTE_PARSER) != 0
) &&
maddy::QuoteParser::IsStartingLine(line)
)
{ {
parser = std::make_shared<maddy::QuoteParser>( parser = std::make_shared<maddy::QuoteParser>(
[this](std::string& line){ this->runLineParser(line); }, [this](std::string& line){ this->runLineParser(line); },
[this](const std::string& line){ return this->getBlockParserForLine(line); } [this](const std::string& line){ return this->getBlockParserForLine(line); }
); );
} }
else if (maddy::TableParser::IsStartingLine(line)) else if (
(
!this->config ||
(this->config->enabledParsers & maddy::types::TABLE_PARSER) != 0
) &&
maddy::TableParser::IsStartingLine(line)
)
{ {
parser = std::make_shared<maddy::TableParser>( parser = std::make_shared<maddy::TableParser>(
[this](std::string& line){ this->runLineParser(line); }, [this](std::string& line){ this->runLineParser(line); },
nullptr nullptr
); );
} }
else if (maddy::ChecklistParser::IsStartingLine(line)) else if (
(
!this->config ||
(this->config->enabledParsers & maddy::types::CHECKLIST_PARSER) != 0
) &&
maddy::ChecklistParser::IsStartingLine(line)
)
{ {
parser = this->createChecklistParser(); parser = this->createChecklistParser();
} }
else if (maddy::OrderedListParser::IsStartingLine(line)) else if (
(
!this->config ||
(this->config->enabledParsers & maddy::types::ORDERED_LIST_PARSER) != 0
) &&
maddy::OrderedListParser::IsStartingLine(line)
)
{ {
parser = this->createOrderedListParser(); parser = this->createOrderedListParser();
} }
else if (maddy::UnorderedListParser::IsStartingLine(line)) else if (
(
!this->config ||
(this->config->enabledParsers & maddy::types::UNORDERED_LIST_PARSER) != 0
) &&
maddy::UnorderedListParser::IsStartingLine(line)
)
{ {
parser = this->createUnorderedListParser(); parser = this->createUnorderedListParser();
} }
else if ( else if (
this->config && this->config &&
!this->config->isHTMLWrappedInParagraph && (this->config->enabledParsers & maddy::types::HTML_PARSER) != 0 &&
maddy::HtmlParser::IsStartingLine(line) maddy::HtmlParser::IsStartingLine(line)
) )
{ {
parser = std::make_shared<maddy::HtmlParser>(nullptr, nullptr); parser = std::make_shared<maddy::HtmlParser>(nullptr, nullptr);
} }
else if (maddy::ParagraphParser::IsStartingLine(line)) else if (
maddy::ParagraphParser::IsStartingLine(line)
)
{ {
parser = std::make_shared<maddy::ParagraphParser>( parser = std::make_shared<maddy::ParagraphParser>(
[this](std::string& line){ this->runLineParser(line); }, [this](std::string& line){ this->runLineParser(line); },
nullptr nullptr,
(!this->config || (this->config->enabledParsers & maddy::types::PARAGRAPH_PARSER) != 0)
); );
} }
@@ -232,7 +392,13 @@ private:
{ {
std::shared_ptr<BlockParser> parser; std::shared_ptr<BlockParser> parser;
if (maddy::ChecklistParser::IsStartingLine(line)) if (
(
!this->config ||
(this->config->enabledParsers & maddy::types::CHECKLIST_PARSER) != 0
) &&
maddy::ChecklistParser::IsStartingLine(line)
)
{ {
parser = this->createChecklistParser(); parser = this->createChecklistParser();
} }
@@ -251,11 +417,23 @@ private:
{ {
std::shared_ptr<BlockParser> parser; std::shared_ptr<BlockParser> parser;
if (maddy::OrderedListParser::IsStartingLine(line)) if (
(
!this->config ||
(this->config->enabledParsers & maddy::types::ORDERED_LIST_PARSER) != 0
) &&
maddy::OrderedListParser::IsStartingLine(line)
)
{ {
parser = this->createOrderedListParser(); parser = this->createOrderedListParser();
} }
else if (maddy::UnorderedListParser::IsStartingLine(line)) else if (
(
!this->config ||
(this->config->enabledParsers & maddy::types::UNORDERED_LIST_PARSER) != 0
) &&
maddy::UnorderedListParser::IsStartingLine(line)
)
{ {
parser = this->createUnorderedListParser(); parser = this->createUnorderedListParser();
} }
@@ -274,11 +452,23 @@ private:
{ {
std::shared_ptr<BlockParser> parser; std::shared_ptr<BlockParser> parser;
if (maddy::OrderedListParser::IsStartingLine(line)) if (
(
!this->config ||
(this->config->enabledParsers & maddy::types::ORDERED_LIST_PARSER) != 0
) &&
maddy::OrderedListParser::IsStartingLine(line)
)
{ {
parser = this->createOrderedListParser(); parser = this->createOrderedListParser();
} }
else if (maddy::UnorderedListParser::IsStartingLine(line)) else if (
(
!this->config ||
(this->config->enabledParsers & maddy::types::UNORDERED_LIST_PARSER) != 0
) &&
maddy::UnorderedListParser::IsStartingLine(line)
)
{ {
parser = this->createUnorderedListParser(); parser = this->createUnorderedListParser();
} }

View File

@@ -4,12 +4,51 @@
*/ */
#pragma once #pragma once
#include <stdint.h>
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
namespace maddy { namespace maddy {
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
namespace types {
/**
* PARSER_TYPE
*
* Bitwise flags to turn on/off each parser
*/
enum PARSER_TYPE : uint32_t
{
NONE = 0,
BREAKLINE_PARSER = 0b1,
CHECKLIST_PARSER = 0b10,
CODE_BLOCK_PARSER = 0b100,
EMPHASIZED_PARSER = 0b1000,
HEADLINE_PARSER = 0b10000,
HORIZONTAL_LINE_PARSER = 0b100000,
HTML_PARSER = 0b1000000,
IMAGE_PARSER = 0b10000000,
INLINE_CODE_PARSER = 0b100000000,
ITALIC_PARSER = 0b1000000000,
LINK_PARSER = 0b10000000000,
ORDERED_LIST_PARSER = 0b100000000000,
PARAGRAPH_PARSER = 0b1000000000000,
QUOTE_PARSER = 0b10000000000000,
STRIKETHROUGH_PARSER = 0b100000000000000,
STRONG_PARSER = 0b1000000000000000,
TABLE_PARSER = 0b10000000000000000,
UNORDERED_LIST_PARSER = 0b100000000000000000,
LATEX_BLOCK_PARSER = 0b1000000000000000000,
DEFAULT = 0b0111111111110111111,
ALL = 0b1111111111111111111,
};
} // namespace types
/** /**
* ParserConfig * ParserConfig
* *
@@ -17,12 +56,22 @@ namespace maddy {
*/ */
struct ParserConfig struct ParserConfig
{ {
/**
* @deprecated will be removed in 1.4.0 latest
*/
bool isEmphasizedParserEnabled; bool isEmphasizedParserEnabled;
/**
* @deprecated will be removed in 1.4.0 latest
*/
bool isHTMLWrappedInParagraph; bool isHTMLWrappedInParagraph;
uint32_t enabledParsers;
ParserConfig() ParserConfig()
: isEmphasizedParserEnabled(true) : isEmphasizedParserEnabled(true)
, isHTMLWrappedInParagraph(true) , isHTMLWrappedInParagraph(true)
, enabledParsers(maddy::types::DEFAULT)
{} {}
}; // class ParserConfig }; // class ParserConfig

View File

@@ -54,7 +54,7 @@ public:
static bool static bool
IsStartingLine(const std::string& line) IsStartingLine(const std::string& line)
{ {
static std::regex re("^\\>.*"); static std::regex re(R"(^\>.*)");
return std::regex_match(line, re); return std::regex_match(line, re);
} }
@@ -144,9 +144,9 @@ protected:
void void
parseBlock(std::string& line) override parseBlock(std::string& line) override
{ {
static std::regex lineRegexWithSpace("^\\> "); static std::regex lineRegexWithSpace(R"(^\> )");
line = std::regex_replace(line, lineRegexWithSpace, ""); line = std::regex_replace(line, lineRegexWithSpace, "");
static std::regex lineRegexWithoutSpace("^\\>"); static std::regex lineRegexWithoutSpace(R"(^\>)");
line = std::regex_replace(line, lineRegexWithoutSpace, ""); line = std::regex_replace(line, lineRegexWithoutSpace, "");
if (!line.empty()) if (!line.empty())

View File

@@ -39,7 +39,7 @@ public:
void void
Parse(std::string& line) override Parse(std::string& line) override
{ {
static std::regex re("(?!.*`.*|.*<code>.*)\\~\\~(?!.*`.*|.*<\\/code>.*)([^\\~]*)\\~\\~(?!.*`.*|.*<\\/code>.*)"); static std::regex re(R"((?!.*`.*|.*<code>.*)\~\~(?!.*`.*|.*<\/code>.*)([^\~]*)\~\~(?!.*`.*|.*<\/code>.*))");
static std::string replacement = "<s>$1</s>"; static std::string replacement = "<s>$1</s>";
line = std::regex_replace(line, re, replacement); line = std::regex_replace(line, re, replacement);

View File

@@ -43,8 +43,8 @@ public:
{ {
static std::vector<std::regex> res static std::vector<std::regex> res
{ {
std::regex{"(?!.*`.*|.*<code>.*)\\*\\*(?!.*`.*|.*<\\/code>.*)([^\\*\\*]*)\\*\\*(?!.*`.*|.*<\\/code>.*)"}, std::regex{R"((?!.*`.*|.*<code>.*)\*\*(?!.*`.*|.*<\/code>.*)([^\*\*]*)\*\*(?!.*`.*|.*<\/code>.*))"},
std::regex{"(?!.*`.*|.*<code>.*)__(?!.*`.*|.*<\\/code>.*)([^__]*)__(?!.*`.*|.*<\\/code>.*)"} std::regex{R"((?!.*`.*|.*<code>.*)__(?!.*`.*|.*<\/code>.*)([^__]*)__(?!.*`.*|.*<\/code>.*))"}
}; };
static std::string replacement = "<strong>$1</strong>"; static std::string replacement = "<strong>$1</strong>";
for (const auto& re : res) for (const auto& re : res)

View File

@@ -1,14 +0,0 @@
# This project is licensed under the MIT license. For more information see the
# LICENSE file.
cmake_minimum_required(VERSION 2.8)
set(LIBS_INCLUDE_DIRS
# -- googletest / -mock --------------------------------------------------------
${CMAKE_CURRENT_SOURCE_DIR}/gtest/googletest/include
${CMAKE_CURRENT_SOURCE_DIR}/gtest/googlemock/include
# ------------------------------------------------------------------------------
PARENT_SCOPE)
set(LIBS_SRC_FILES
PARENT_SCOPE)

Submodule libs/gtest deleted from 703bd9caab

47
tests/CMakeLists.txt Normal file
View File

@@ -0,0 +1,47 @@
# This project is licensed under the MIT license. For more information see the
# LICENSE file.
if (UNIX AND NOT APPLE)
execute_process(COMMAND ${CMAKE_CXX_COMPILER}
-fuse-ld=gold -Wl,--version
ERROR_QUIET OUTPUT_VARIABLE ld_version)
if ("${ld_version}" MATCHES "GNU gold")
message(STATUS "Found Gold linker, use faster linker")
set(CMAKE_EXE_LINKER_FLAGS
"${CMAKE_EXE_LINKER_FLAGS} -fuse-ld=gold")
set(CMAKE_SHARED_LINKER_FLAGS
"${CMAKE_SHARED_LINKER_FLAGS} -fuse-ld=gold ")
endif()
endif()
# ------------------------------------------------------------------------------
include(FetchContent)
FetchContent_Declare(
googletest
GIT_REPOSITORY https://github.com/google/googletest.git
GIT_TAG b796f7d44681514f58a683a3a71ff17c94edb0c1 # v1.13.0
)
FetchContent_MakeAvailable(googletest)
# ------------------------------------------------------------------------------
file(GLOB_RECURSE MADDY_TESTS_FILES ${CMAKE_CURRENT_SOURCE_DIR}/maddy/*.cpp)
# ------------------------------------------------------------------------------
add_executable(
MaddyTests
${MADDY_TESTS_FILES}
${CMAKE_CURRENT_SOURCE_DIR}/main.cpp
)
target_include_directories(MaddyTests PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}
)
target_link_libraries(MaddyTests maddy gmock_main)
set_target_properties(MaddyTests PROPERTIES
CMAKE_CXX_FLAGS
"${CMAKE_CXX_FLAGS} -g -Wall -Wpedantic -Wextra -Wno-ignored-qualifiers -fno-rtti -fno-exceptions -fsanitize=address -fno-omit-frame-pointer"
)
add_test(NAME MaddyTests COMMAND MaddyTests)

View File

@@ -59,3 +59,26 @@ TEST_F(MADDY_CODEBLOCKPARSER, ItReplacesMarkdownWithAnHtmlCodeBlock)
ASSERT_EQ(expected, outputString); ASSERT_EQ(expected, outputString);
} }
TEST_F(MADDY_CODEBLOCKPARSER, ItShouldUseAnythingBehindFirstBackticksAsClass)
{
std::vector<std::string> markdown = {
"```cpp"
, "some code"
, "some other code"
, "```"
};
std::string expected = "<pre class=\"cpp\"><code>\nsome code\nsome other code\n</code></pre>";
for (std::string md : markdown)
{
cbParser->AddLine(md);
}
ASSERT_TRUE(cbParser->IsFinished());
std::stringstream& output(cbParser->GetResult());
const std::string& outputString = output.str();
ASSERT_EQ(expected, outputString);
}

View File

@@ -0,0 +1,102 @@
/*
* This project is licensed under the MIT license. For more information see the
* LICENSE file.
*/
#include <memory>
#include "gmock/gmock.h"
#include "maddy/latexblockparser.h"
// -----------------------------------------------------------------------------
class MADDY_LATEXBLOCKPARSER : public ::testing::Test
{
protected:
std::shared_ptr<maddy::LatexBlockParser> lbParser;
void
SetUp() override
{
this->lbParser = std::make_shared<maddy::LatexBlockParser>(
nullptr,
nullptr
);
}
};
// -----------------------------------------------------------------------------
TEST_F(MADDY_LATEXBLOCKPARSER, IsStartingLineReturnsTrueWhenFacedWithTwoDollars)
{
ASSERT_TRUE(maddy::LatexBlockParser::IsStartingLine("$$"));
}
TEST_F(MADDY_LATEXBLOCKPARSER, IsFinishedReturnsFalseInTheBeginning)
{
ASSERT_FALSE(lbParser->IsFinished());
}
TEST_F(MADDY_LATEXBLOCKPARSER, ItReplacesOneLineMarkdownWithALatexBlock)
{
std::vector<std::string> markdown = {
"$$x = {-b \\pm \\sqrt{b^2-4ac} \\over 2a}.$$"
};
std::string expected = "$$x = {-b \\pm \\sqrt{b^2-4ac} \\over 2a}.$$\n";
for (std::string md : markdown)
{
lbParser->AddLine(md);
}
ASSERT_TRUE(lbParser->IsFinished());
std::stringstream& output(lbParser->GetResult());
const std::string& outputString = output.str();
ASSERT_EQ(expected, outputString);
}
TEST_F(MADDY_LATEXBLOCKPARSER, ItReplacesABlockMarkdownWithALatexBlock)
{
std::vector<std::string> markdown = {
"$$",
"x = {-b \\pm \\sqrt{b^2-4ac} \\over 2a}.",
"$$"
};
std::string expected = "$$\nx = {-b \\pm \\sqrt{b^2-4ac} \\over 2a}.\n$$\n";
for (std::string md : markdown)
{
lbParser->AddLine(md);
}
ASSERT_TRUE(lbParser->IsFinished());
std::stringstream& output(lbParser->GetResult());
const std::string& outputString = output.str();
ASSERT_EQ(expected, outputString);
}
TEST_F(MADDY_LATEXBLOCKPARSER, ItReplacesAMultilineBlockMarkdownWithALatexBlock)
{
std::vector<std::string> markdown = {
"$$",
"x = {-b \\pm \\sqrt{b^2-4ac}",
"\\over 2a}.$$"
};
std::string expected = "$$\nx = {-b \\pm \\sqrt{b^2-4ac}\n\\over 2a}.$$\n";
for (std::string md : markdown)
{
lbParser->AddLine(md);
}
ASSERT_TRUE(lbParser->IsFinished());
std::stringstream& output(lbParser->GetResult());
const std::string& outputString = output.str();
ASSERT_EQ(expected, outputString);
}

View File

@@ -20,7 +20,8 @@ protected:
{ {
this->pParser = std::make_shared<maddy::ParagraphParser>( this->pParser = std::make_shared<maddy::ParagraphParser>(
nullptr, nullptr,
nullptr nullptr,
true
); );
} }
}; };

View File

@@ -34,3 +34,33 @@ TEST(MADDY_PARSER, ItShouldParseWithConfig)
ASSERT_EQ(testHtml2, output); ASSERT_EQ(testHtml2, output);
} }
TEST(MADDY_PARSER, ItShouldParseWithBitwiseConfig)
{
auto config = std::make_shared<maddy::ParserConfig>();
config->enabledParsers &= ~maddy::types::EMPHASIZED_PARSER;
config->enabledParsers |= maddy::types::HTML_PARSER;
auto parser = std::make_shared<maddy::Parser>(config);
std::stringstream markdown(testMarkdown);
const std::string output = parser->Parse(markdown);
ASSERT_EQ(testHtml2, output);
}
TEST(MADDY_PARSER, ItShouldParseWithSmallConfig)
{
auto config = std::make_shared<maddy::ParserConfig>();
config->enabledParsers = maddy::types::EMPHASIZED_PARSER |
maddy::types::STRONG_PARSER;
auto parser = std::make_shared<maddy::Parser>(config);
std::stringstream markdown(testMarkdown);
const std::string output = parser->Parse(markdown);
ASSERT_EQ(testHtml3, output);
}

View File

@@ -71,3 +71,4 @@ foot a|foot b|foot c\n\
const std::string testHtml = "<h1>This is a test</h1><p>This should result in a praragraph it's that simple. </p><ul><li>an <i>unordered</i> list<ul><li>with some <strong>hierarchy</strong><ol><li>and an <em>ordered</em></li><li>list</li><li>directly</li></ol></li><li>inside</li></ul></li></ul><pre><code>\nvar c = 'blub';\n</code></pre><blockquote><p>A Quote </p><p>With some <s>text</s> blocks inside </p><ul><li>even a list </li><li>should be </li><li>possible </li></ul></blockquote><p>And well <code>inline code</code> should also work. </p><h2>Another Headline</h2><p>And not to forget <a href=\"http://progsource.de\">link to progsource</a> should work. And well - let's see how an image would be shown: </p><p><img src=\"http://progsource.de/img/progsource.png\" alt=\"an image\"/> </p><hr/><p><a name=\"to top\"></a> </p><h3>and more headlines</h3><ul class=\"checklist\"><li><label><input type=\"checkbox\"/> how</label></li><li><label><input type=\"checkbox\"/> about<ul class=\"checklist\"><li><label><input type=\"checkbox\"/> a</label></li><li><label><input type=\"checkbox\" checked=\"checked\"/> nice</label></li></ul></label></li><li><label><input type=\"checkbox\" checked=\"checked\"/> check</label></li><li><label><input type=\"checkbox\"/> list</label></li></ul><h4>even a table</h4><table><thead><tr><th>Left header</th><th>middle header</th><th>last header</th></tr></thead><tbody><tr><td>cell 1</td><td>cell <strong>2</strong></td><td>cell 3</td></tr><tr><td>cell 4</td><td>cell 5</td><td>cell 6</td></tr></tbody><tfoot><tr><td>foot a</td><td>foot b</td><td>foot c</td></tr></tfoot></table><h5>h5</h5><h6>h6</h6>"; const std::string testHtml = "<h1>This is a test</h1><p>This should result in a praragraph it's that simple. </p><ul><li>an <i>unordered</i> list<ul><li>with some <strong>hierarchy</strong><ol><li>and an <em>ordered</em></li><li>list</li><li>directly</li></ol></li><li>inside</li></ul></li></ul><pre><code>\nvar c = 'blub';\n</code></pre><blockquote><p>A Quote </p><p>With some <s>text</s> blocks inside </p><ul><li>even a list </li><li>should be </li><li>possible </li></ul></blockquote><p>And well <code>inline code</code> should also work. </p><h2>Another Headline</h2><p>And not to forget <a href=\"http://progsource.de\">link to progsource</a> should work. And well - let's see how an image would be shown: </p><p><img src=\"http://progsource.de/img/progsource.png\" alt=\"an image\"/> </p><hr/><p><a name=\"to top\"></a> </p><h3>and more headlines</h3><ul class=\"checklist\"><li><label><input type=\"checkbox\"/> how</label></li><li><label><input type=\"checkbox\"/> about<ul class=\"checklist\"><li><label><input type=\"checkbox\"/> a</label></li><li><label><input type=\"checkbox\" checked=\"checked\"/> nice</label></li></ul></label></li><li><label><input type=\"checkbox\" checked=\"checked\"/> check</label></li><li><label><input type=\"checkbox\"/> list</label></li></ul><h4>even a table</h4><table><thead><tr><th>Left header</th><th>middle header</th><th>last header</th></tr></thead><tbody><tr><td>cell 1</td><td>cell <strong>2</strong></td><td>cell 3</td></tr><tr><td>cell 4</td><td>cell 5</td><td>cell 6</td></tr></tbody><tfoot><tr><td>foot a</td><td>foot b</td><td>foot c</td></tr></tfoot></table><h5>h5</h5><h6>h6</h6>";
const std::string testHtml2 = "<h1>This is a test</h1><p>This should result in a praragraph it's that simple. </p><ul><li>an <i>unordered</i> list<ul><li>with some <strong>hierarchy</strong><ol><li>and an _ordered_</li><li>list</li><li>directly</li></ol></li><li>inside</li></ul></li></ul><pre><code>\nvar c = 'blub';\n</code></pre><blockquote><p>A Quote </p><p>With some <s>text</s> blocks inside </p><ul><li>even a list </li><li>should be </li><li>possible </li></ul></blockquote><p>And well <code>inline code</code> should also work. </p><h2>Another Headline</h2><p>And not to forget <a href=\"http://progsource.de\">link to progsource</a> should work. And well - let's see how an image would be shown: </p><p><img src=\"http://progsource.de/img/progsource.png\" alt=\"an image\"/> </p><hr/><a name=\"to top\"></a><h3>and more headlines</h3><ul class=\"checklist\"><li><label><input type=\"checkbox\"/> how</label></li><li><label><input type=\"checkbox\"/> about<ul class=\"checklist\"><li><label><input type=\"checkbox\"/> a</label></li><li><label><input type=\"checkbox\" checked=\"checked\"/> nice</label></li></ul></label></li><li><label><input type=\"checkbox\" checked=\"checked\"/> check</label></li><li><label><input type=\"checkbox\"/> list</label></li></ul><h4>even a table</h4><table><thead><tr><th>Left header</th><th>middle header</th><th>last header</th></tr></thead><tbody><tr><td>cell 1</td><td>cell <strong>2</strong></td><td>cell 3</td></tr><tr><td>cell 4</td><td>cell 5</td><td>cell 6</td></tr></tbody><tfoot><tr><td>foot a</td><td>foot b</td><td>foot c</td></tr></tfoot></table><h5>h5</h5><h6>h6</h6>"; const std::string testHtml2 = "<h1>This is a test</h1><p>This should result in a praragraph it's that simple. </p><ul><li>an <i>unordered</i> list<ul><li>with some <strong>hierarchy</strong><ol><li>and an _ordered_</li><li>list</li><li>directly</li></ol></li><li>inside</li></ul></li></ul><pre><code>\nvar c = 'blub';\n</code></pre><blockquote><p>A Quote </p><p>With some <s>text</s> blocks inside </p><ul><li>even a list </li><li>should be </li><li>possible </li></ul></blockquote><p>And well <code>inline code</code> should also work. </p><h2>Another Headline</h2><p>And not to forget <a href=\"http://progsource.de\">link to progsource</a> should work. And well - let's see how an image would be shown: </p><p><img src=\"http://progsource.de/img/progsource.png\" alt=\"an image\"/> </p><hr/><a name=\"to top\"></a><h3>and more headlines</h3><ul class=\"checklist\"><li><label><input type=\"checkbox\"/> how</label></li><li><label><input type=\"checkbox\"/> about<ul class=\"checklist\"><li><label><input type=\"checkbox\"/> a</label></li><li><label><input type=\"checkbox\" checked=\"checked\"/> nice</label></li></ul></label></li><li><label><input type=\"checkbox\" checked=\"checked\"/> check</label></li><li><label><input type=\"checkbox\"/> list</label></li></ul><h4>even a table</h4><table><thead><tr><th>Left header</th><th>middle header</th><th>last header</th></tr></thead><tbody><tr><td>cell 1</td><td>cell <strong>2</strong></td><td>cell 3</td></tr><tr><td>cell 4</td><td>cell 5</td><td>cell 6</td></tr></tbody><tfoot><tr><td>foot a</td><td>foot b</td><td>foot c</td></tr></tfoot></table><h5>h5</h5><h6>h6</h6>";
const std::string testHtml3 = "# This is a test <br/>This should result in a praragraph it's that simple. <br/>* an *unordered* list * with some <strong>hierarchy</strong> 1. and an <em>ordered</em> * list * directly * inside <br/>``` var c = 'blub'; ``` <br/>> A Quote > > With some ~~text~~ blocks inside > > * even a list > * should be > * possible > <br/>And well `inline code` should also work. <br/>## Another Headline <br/>And not to forget [link to progsource](http://progsource.de) should work. And well - let's see how an image would be shown: <br/>![an image](http://progsource.de/img/progsource.png) <br/>--- <br/><a name=\"to top\"></a> <br/>### and more headlines <br/>- [ ] how - [ ] about - [ ] a - [x] nice - [x] check - [ ] list <br/>#### even a table <br/>|table> Left header|middle header|last header - | - | - cell 1|cell <strong>2</strong>|cell 3 cell 4|cell 5|cell 6 - | - | - foot a|foot b|foot c |<table <br/>##### h5 ###### h6 <br/>";