25 Commits
1.3.0 ... 1.6.0

Author SHA1 Message Date
Petra Baranski
441ba25550 docs: update changelog with 1.6.0
Some checks failed
run-checks / run-clang-format (push) Has been cancelled
run-tests / test-on-ubuntu (push) Has been cancelled
run-tests / test-on-windows (push) Has been cancelled
run-tests / test-on-osx (push) Has been cancelled
Update dependency versions / update-fetch-content (push) Has been cancelled
2025-07-26 15:28:47 +02:00
Petra Baranski
9143754a23 chore: bump version to 1.6.0 2025-07-26 15:28:47 +02:00
Petra Baranski
de67274233 chore: add cmake find_package test
Some checks failed
run-checks / run-clang-format (push) Has been cancelled
run-tests / test-on-ubuntu (push) Has been cancelled
run-tests / test-on-windows (push) Has been cancelled
run-tests / test-on-osx (push) Has been cancelled
2025-07-25 06:33:24 +02:00
Petra Baranski
28e9a22f9c chore: add MADDY_VERSION_LINE_REPLACEMENT to maddy version lines
Some checks failed
run-tests / test-on-windows (push) Has been cancelled
run-checks / run-clang-format (push) Has been cancelled
run-tests / test-on-ubuntu (push) Has been cancelled
run-tests / test-on-osx (push) Has been cancelled
2025-07-02 23:42:00 +02:00
Petra Baranski
907d6d4a27 chore: add script to update maddy version numbers
Additionaly some cleanup in python code regarding quotes
2025-07-02 23:42:00 +02:00
Petra Baranski
7b8f661079 ci: add more output to the release workflow 2025-07-02 23:42:00 +02:00
offa
36822075bf Add Cmake install and find_package support 2025-07-02 21:17:42 +02:00
Petra Baranski
4f977219c3 Release 1.5.0
Some checks failed
run-checks / run-clang-format (push) Has been cancelled
run-tests / test-on-ubuntu (push) Has been cancelled
run-tests / test-on-windows (push) Has been cancelled
run-tests / test-on-osx (push) Has been cancelled
Update dependency versions / update-fetch-content (push) Has been cancelled
* Use the git tag as release name
* Update version to 1.5.0
* stabilize benchmark code
2025-04-21 12:43:45 +02:00
Petra Baranski
9ec4777a7b Add benchmark
Some checks failed
run-checks / run-clang-format (push) Has been cancelled
run-tests / test-on-ubuntu (push) Has been cancelled
run-tests / test-on-windows (push) Has been cancelled
run-tests / test-on-osx (push) Has been cancelled
* add benchmark option
* updated changelog
* added benchmark info to readme
* add bench folder to format.py
2025-04-21 01:02:07 +02:00
Lucian Smith
2a00c9fb0b Add regex for title text version of links
* Add regex for title text version of links

Original parser matched:
  [name](http:://link)

Add match for:
  [name](http:://link "title text")

* Add tests and improve regex's
* Several new tests in test_maddy_linkparser.cpp  (Some with paths for future improvement, and one to ensure an overzealous future update doesn't disallow actually-used special characters like o-umlaut).
* URLs now ignore leading/trailing spaces.
* URLs now don't match on internal spaces or quotes.
* Small grammar fix in CONTRIBUTING.md
* Updated changelog.
2025-04-20 18:45:27 +02:00
Petra Baranski
af59cd13d4 Update pull_request_template.md
Some checks failed
run-checks / run-clang-format (push) Has been cancelled
run-tests / test-on-ubuntu (push) Has been cancelled
run-tests / test-on-windows (push) Has been cancelled
run-tests / test-on-osx (push) Has been cancelled
2025-04-18 12:52:51 +02:00
Petra Baranski
f7d2e69e44 Create pull_request_template.md 2025-04-18 12:49:42 +02:00
Petra Baranski
261e75f22f Release should use the actual annotated tag message
Some checks failed
run-checks / run-clang-format (push) Has been cancelled
run-tests / test-on-ubuntu (push) Has been cancelled
run-tests / test-on-windows (push) Has been cancelled
run-tests / test-on-osx (push) Has been cancelled
Update dependency versions / update-fetch-content (push) Has been cancelled
2025-03-28 05:22:54 +01:00
Petra Baranski
731827264e Fix workflow indentation 2025-03-28 05:17:38 +01:00
Petra Baranski
100eb59bc8 Release 1.4.0
* up version to 1.4.0
* Remove deprecated code
* change release message
2025-03-28 05:04:55 +01:00
Petra Baranski
4518e402c7 Fix linkparser line handling with multiple parenthesis 2025-03-28 03:37:04 +01:00
github-actions[bot]
a5b18310a8 Update dependency versions (#67)
Some checks failed
run-checks / run-clang-format (push) Has been cancelled
run-tests / test-on-ubuntu (push) Has been cancelled
run-tests / test-on-windows (push) Has been cancelled
run-tests / test-on-osx (push) Has been cancelled
* Update dependency versions
* update changelog

---------

Co-authored-by: github-actions <github-actions@github.com>
Co-authored-by: Petra Baranski <info@progsource.de>
2025-03-01 14:19:35 +01:00
github-actions[bot]
8aa290cd38 Update dependency versions
Co-authored-by: github-actions <github-actions@github.com>

* googletest v1.15.2
2024-11-16 06:46:02 +01:00
Petra Baranski
798863e292 fix: update dependencies pipeline 2024-11-16 06:40:12 +01:00
Petra Baranski
ee4b0cc2e2 ci: Add update dependencies 2024-11-16 06:06:28 +01:00
Petra Baranski
d0dae091e0 chore: Add clang-format 2024-11-16 05:50:22 +01:00
Petra Baranski
1f12bc15b6 Update GoogleTest to v1.15.0 2024-07-20 13:46:24 +02:00
dependabot[bot]
369859f7ed build(deps): bump actions/checkout from 3 to 4 (#61)
Bumps [actions/checkout](https://github.com/actions/checkout) from 3 to 4.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v3...v4)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-07-19 05:30:16 +02:00
Petra Baranski
2e8e538660 Create dependabot.yml 2024-07-19 05:25:12 +02:00
Petra Baranski
0a97ad8079 trigger run tests on any pull request 2024-07-19 05:16:47 +02:00
73 changed files with 2156 additions and 863 deletions

46
.clang-format Normal file
View File

@@ -0,0 +1,46 @@
BasedOnStyle: Google
AccessModifierOffset: -2
BreakBeforeTernaryOperators: true
BreakConstructorInitializers: BeforeComma
ConstructorInitializerIndentWidth: 2
BracedInitializerIndentWidth: 2
ContinuationIndentWidth: 2
Cpp11BracedListStyle: true
IndentAccessModifiers: false
InsertNewlineAtEOF: true
LambdaBodyIndentation: Signature
AlignAfterOpenBracket: BlockIndent
AllowShortIfStatementsOnASingleLine: Never
BinPackArguments: false
BinPackParameters: false
AllowShortLambdasOnASingleLine: All
SpacesBeforeTrailingComments: 1
BreakBeforeBraces: Custom
BraceWrapping:
AfterCaseLabel: true
AfterClass: true
AfterControlStatement: Always
AfterEnum: true
AfterFunction: true
AfterNamespace: false
AfterStruct: true
AfterUnion: true
AfterExternBlock: false
BeforeCatch: true
BeforeElse: true
BeforeLambdaBody: true
IndentBraces: false
BeforeWhile: true
SplitEmptyFunction: false
SplitEmptyRecord: false
SplitEmptyNamespace: false
IncludeCategories:
- Regex: '^<.*>'
Priority: 1
- Regex: '^"maddy/.*'
Priority: 3
- Regex: '.*'
Priority: 2
SortIncludes: true
IncludeBlocks: Regroup
InsertTrailingCommas: Wrapped

View File

@@ -8,5 +8,8 @@ indent_style = space
insert_final_newline = true
trim_trailing_whitespace = true
[*.{h,hh,hpp,c,cc,cpp,cxx,yml}]
[*.{h,hh,hpp,c,cc,cpp,cxx,yml,py,md}]
indent_size = 2
[CMakeLists.txt]
indent_size = 2

View File

@@ -37,7 +37,9 @@ body:
label: maddy version
description: What version of maddy are you using?
options:
- 1.3.0 (latest)
- 1.5.0 (latest)
- 1.4.0
- 1.3.0
- 1.2.1
- 1.2.0
- 1.1.2

View File

@@ -37,7 +37,9 @@ body:
label: maddy version
description: What version of maddy are you using?
options:
- 1.3.0 (latest)
- 1.5.0 (latest)
- 1.4.0
- 1.3.0
- 1.2.1
- 1.2.0
- 1.1.2

11
.github/dependabot.yml vendored Normal file
View File

@@ -0,0 +1,11 @@
# To get started with Dependabot version updates, you'll need to specify which
# package ecosystems to update and where the package manifests are located.
# Please see the documentation for all configuration options:
# https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file
version: 2
updates:
- package-ecosystem: "github-actions" # See documentation for possible values
directory: "/" # Location of package manifests
schedule:
interval: "monthly"

11
.github/pull_request_template.md vendored Normal file
View File

@@ -0,0 +1,11 @@
### Description of the change
*Please describe what has changed and why. If it fixes an open issue, mention it here.*
### Checklist for contributor
* [ ] if you want to be mentioned in the [AUTHORS](https://github.com/progsource/maddy/blob/master/AUTHORS) file, you added yourself
* [ ] added an entry to [CHANGELOG.md](https://github.com/progsource/maddy/blob/master/CHANGELOG.md) at "Upcoming"
* [ ] if any Markdown definition changed, you updated the [definition docs](https://github.com/progsource/maddy/blob/master/docs/definitions.md)
* [ ] your C++ code change is accommodated with a unit/integration test where it makes sense
* [ ] your code meets the code format style (clang-format) of the project (`tools/format.py`)

View File

@@ -11,7 +11,7 @@ jobs:
release:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- uses: lukka/get-cmake@latest
with:
cmakeVersion: "~3.25.0" # <--= optional, use most recent 3.25.x version
@@ -25,10 +25,27 @@ jobs:
cmake -DMADDY_CREATE_PACKAGE=ON ..
make maddy_package
- name: Get current tag message
id: tag-message
run: |
TAG_NAME=${GITHUB_REF#refs/tags/}
echo "TAG_NAME: $TAG_NAME"
TAG_MESSAGE=$(git tag -l --format='%(contents)' "$TAG_NAME")
echo "message<<EOF" >> $GITHUB_OUTPUT
echo "$TAG_MESSAGE" >> $GITHUB_OUTPUT
echo "EOF" >> $GITHUB_OUTPUT
echo "TAG_MESSAGE: $TAG_MESSAGE"
- 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)"
release_name: ${{ github.ref_name }}
body: |
${{ steps.tag-message.outputs.message }}
---
[full changelog](https://github.com/progsource/maddy/blob/master/CHANGELOG.md)

24
.github/workflows/run-checks.yml vendored Normal file
View File

@@ -0,0 +1,24 @@
name: run-checks
run-name: run-checks ${{ github.ref }}
on:
push:
branches:
- master
pull_request:
jobs:
run-clang-format:
runs-on: ubuntu-24.04
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.8'
- name: Run format script with dry_run
run: |
clang-format --version
python tools/format.py dry_run

View File

@@ -4,38 +4,43 @@ on:
push:
branches:
- master
- dev
pull_request:
branches:
- master
- dev
jobs:
test-on-ubuntu:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- 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
cmakeVersion: "~3.25.0"
ninjaVersion: "^1.11.1"
- name: build
run: |
mkdir tmp
cd tmp
cmake -DMADDY_BUILD_WITH_TESTS=ON ..
cmake -DMADDY_BUILD_WITH_TESTS=ON -DCMAKE_INSTALL_PREFIX=./install ..
make -j4
make install
- name: run tests
run: |
./build/MaddyTests
- name: test find_package
run: |
cd tests/cmake/find_package
mkdir tmp
cd tmp
cmake -DCMAKE_PREFIX_PATH=../../../tmp/install ..
make -j4
./maddy_find_package_example
test-on-windows:
runs-on: windows-latest
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- 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
cmakeVersion: "~3.25.0"
ninjaVersion: "^1.11.1"
- name: build
run: |
mkdir tmp
@@ -49,11 +54,11 @@ jobs:
test-on-osx:
runs-on: macos-latest
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- 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
cmakeVersion: "~3.25.0"
ninjaVersion: "^1.11.1"
- name: build
run: |
mkdir tmp

View File

@@ -0,0 +1,54 @@
name: Update dependency versions
permissions:
contents: write
pull-requests: write
on:
schedule:
# This cron expression runs the job at 00:00 UTC on the first day of every month
- cron: '0 0 1 * *'
workflow_dispatch: # Allows manual triggering of the workflow
jobs:
update-fetch-content:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.11'
- name: Install Pipenv
run: pip install pipenv
- name: Install dependencies
run: |
cd tools
pipenv install
- name: Run update scripts
run: |
cd tools
pipenv run python update_dependencies.py .. tmp tools build docs .github
- name: Check for changes
id: check_changes
run: |
git config --local user.name "github-actions"
git config --local user.email "github-actions@github.com"
git add .
git diff --cached --exit-code || echo "changed=true" >> $GITHUB_OUTPUT
- name: Create Pull Request
if: steps.check_changes.outputs.changed == 'true'
run: |
git commit -m "Update dependency versions"
git push origin HEAD:update-dependency-versions
gh pr create --base master --head update-dependency-versions --title "Update dependency versions" --body "This pull request updates the dependency versions in files."
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

View File

@@ -11,3 +11,4 @@ Andrew Mettlach (dmmettlach@gmail.com)
Evan Klitzke (evan@eklitzke.org)
Albert Schwarzkopf (dev-maddy@quitesimple.org)
Ivans Saponenko (ivans.saponenko+maddy@gmail.com)
Lucian Smith (lpsmith@uw.edu)

View File

@@ -14,7 +14,27 @@ maddy uses [semver versioning](https://semver.org/).
## Upcoming
* ?
* ...
## version 1.6.0 2025-07-26
* ![**ADDED**](https://img.shields.io/badge/-ADDED-%23099) Added CMake install and find_package() support.
* ![**ADDED**](https://img.shields.io/badge/-ADDED-%23099) Script to update maddy version number in all files.
## version 1.5.0 2025-04-21
* ![**ADDED**](https://img.shields.io/badge/-ADDED-%23099) Correctly parse links with title text, i.e. `[link](http://example.com "example")`.
* ![**FIXED**](https://img.shields.io/badge/-FIXED-%23090) Do not create invalid URLs from links with spaces, i.e. `[link](/ABC/some file)`.
* ![**FIXED**](https://img.shields.io/badge/-FIXED-%23090) Do not create invalid HTML from links with quotes, i.e. `[link](/ABC/some"file)`.
* ![**ADDED**](https://img.shields.io/badge/-ADDED-%23099) benchmarks.
## version 1.4.0 2025-03-28
* ![**CHANGED**](https://img.shields.io/badge/-CHANGED-%23e90) Updated google test to v1.16.0.
* ![**ADDED**](https://img.shields.io/badge/-ADDED-%23099) clang-format
* ![**ADDED**](https://img.shields.io/badge/-ADDED-%23099) automatic update dependencies ci
* ![**FIXED**](https://img.shields.io/badge/-FIXED-%23090) `(This is a [link](/ABC/some file) (the URL will include this).)` should not put the later parenthesis into the link url.
* ![**REMOVED**](https://img.shields.io/badge/-REMOVED-%23900) config flags `isEmphasizedParserEnabled` and `isHTMLWrappedInParagraph`. Use `config->enabledParsers &= ~maddy::types::EMPHASIZED_PARSER;` and `config->enabledParsers |= maddy::types::HTML_PARSER;` to gain the same behavior as if the previous config flags were set to `false`.
## version 1.3.0 2023-08-26

View File

@@ -3,10 +3,11 @@
cmake_minimum_required(VERSION 3.25)
project(maddy)
project(maddy VERSION 1.6.0) # MADDY_VERSION_LINE_REPLACEMENT
# ------------------------------------------------------------------------------
include(GNUInstallDirs)
set(CMAKE_BINARY_DIR ${CMAKE_CURRENT_SOURCE_DIR}/build)
set(EXECUTABLE_OUTPUT_PATH ${CMAKE_BINARY_DIR})
set(LIBRARY_OUTPUT_PATH ${CMAKE_BINARY_DIR})
@@ -19,6 +20,7 @@ if(${MADDY_BUILD_WITH_TESTS})
enable_testing()
endif()
option(MADDY_BUILD_WITH_BENCH "enable benchmarks" OFF)
option(MADDY_CREATE_PACKAGE "create a package for a version release" OFF)
# ------------------------------------------------------------------------------
@@ -40,7 +42,8 @@ endif()
add_library(maddy INTERFACE)
target_include_directories(maddy INTERFACE
${MADDY_INCLUDE_DIR}
$<BUILD_INTERFACE:${MADDY_INCLUDE_DIR}>
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
)
# ------------------------------------------------------------------------------
@@ -49,13 +52,46 @@ if(${MADDY_BUILD_WITH_TESTS})
add_subdirectory(tests)
endif()
if(${MADDY_BUILD_WITH_BENCH})
add_subdirectory(bench)
endif()
# ------------------------------------------------------------------------------
if(${MADDY_CREATE_PACKAGE})
set(MADDY_PACKAGE_FILES include/ CMakeLists.txt LICENSE)
set(MADDY_PACKAGE_FILES include/ CMakeLists.txt LICENSE AUTHORS)
add_custom_command(OUTPUT ${CMAKE_BINARY_DIR}/${PROJECT_NAME}-src.zip
COMMAND ${CMAKE_COMMAND} -E tar c ${CMAKE_BINARY_DIR}/${PROJECT_NAME}-src.zip --format=zip -- ${MADDY_PACKAGE_FILES}
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()
include(CMakePackageConfigHelpers)
install(DIRECTORY include/
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
)
install(TARGETS ${PROJECT_NAME}
EXPORT ${PROJECT_NAME}Targets
INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
)
install(EXPORT ${PROJECT_NAME}Targets
FILE ${PROJECT_NAME}Targets.cmake
NAMESPACE ${PROJECT_NAME}::
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}
)
write_basic_package_version_file(${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake
VERSION ${PROJECT_VERSION}
COMPATIBILITY SameMinorVersion
)
configure_package_config_file(${CMAKE_CURRENT_SOURCE_DIR}/cmake/${PROJECT_NAME}Config.cmake.in
${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake
INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}
)
install(FILES
${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake
${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}
)

View File

@@ -10,17 +10,10 @@ improve the code? Then [create a GitHub issue](https://github.com/progsource/mad
## 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.
* Feel free to add yourself to the `AUTHORS` file. (optional)
* Use clang-format to format the code.
* Write in your commit messages what/why you did something. Often times a one-liner might be enough.
* 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.
* Make sure that the tests are successful and if you wrote a bugfix, to have a test that highlights the issue.

View File

@@ -1,4 +1,4 @@
Copyright 2017, 2018, 2019, 2020, 2023 M. Petra Baranski
Copyright M. Petra Baranski (for contributors see AUTHORS file)
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

View File

@@ -1,7 +1,7 @@
# maddy
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
[![Version: 1.3.0](https://img.shields.io/badge/Version-1.3.0-brightgreen.svg)](https://semver.org/)
[![Version: 1.6.0](https://img.shields.io/badge/Version-1.6.0-brightgreen.svg)](https://semver.org/) <!-- MADDY_VERSION_LINE_REPLACEMENT -->
maddy is a C++ Markdown to HTML **header-only** parser library.
@@ -30,7 +30,16 @@ 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)
Use `find_package()` which provides `maddy::maddy` target:
```cmake
find_package(maddy REQUIRED)
add_executable(my_exe)
target_link_libraries(my_exe PRIVATE maddy::maddy)
```
Or 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
@@ -70,10 +79,8 @@ std::stringstream markdownInput("");
// config is optional
std::shared_ptr<maddy::ParserConfig> config = std::make_shared<maddy::ParserConfig>();
// config->isEmphasizedParserEnabled = false; // default true - this flag is deprecated
// 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
config->enabledParsers &= ~maddy::types::EMPHASIZED_PARSER; // disable emphasized parser
config->enabledParsers |= maddy::types::HTML_PARSER; // do not wrap HTML in paragraph
std::shared_ptr<maddy::Parser> parser = std::make_shared<maddy::Parser>(config);
std::string htmlOutput = parser->Parse(markdownInput);
@@ -100,6 +107,21 @@ make
make test # or run the executable in ../build/MaddyTests
```
## How to run the benchmarks
To get proper test results, the benchmarks should always be compiled as
release build.
```shell
git clone https://github.com/progsource/maddy.git
cd maddy
mkdir tmp
cd tmp
cmake -DMADDY_BUILD_WITH_BENCH=ON -DCMAKE_BUILD_TYPE=Release ..
make BUILD_TYPE=Release
../build/maddy_benchmark
```
## How to contribute
There are different possibilities:

54
bench/CMakeLists.txt Normal file
View File

@@ -0,0 +1,54 @@
# 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(
nanobench
GIT_REPOSITORY https://github.com/martinus/nanobench.git
GIT_TAG v4.3.11
GIT_SHALLOW TRUE
)
FetchContent_MakeAvailable(nanobench)
# ------------------------------------------------------------------------------
file(GLOB_RECURSE MADDY_BENCHMARK_FILES
${CMAKE_CURRENT_SOURCE_DIR}/main.cpp
)
# ------------------------------------------------------------------------------
add_compile_definitions(CURRENT_FILE_PATH="${CMAKE_CURRENT_SOURCE_DIR}")
# ------------------------------------------------------------------------------
add_executable(
maddy_benchmark
${MADDY_BENCHMARK_FILES}
${CMAKE_CURRENT_SOURCE_DIR}/main.cpp
)
target_include_directories(maddy_benchmark PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}
)
target_link_libraries(maddy_benchmark maddy nanobench::nanobench)
set_target_properties(maddy_benchmark PROPERTIES
CMAKE_CXX_FLAGS
"${CMAKE_CXX_FLAGS} -O2 -Wall -Wno-ignored-qualifiers -Wpedantic -Wextra -Wno-deprecated -fno-exceptions -fno-rtti"
)

14
bench/README.md Normal file
View File

@@ -0,0 +1,14 @@
# maddy benchmarks
## How to run
The benchmarks have to be run in release mode to give proper results.
```shell
# in main folder
mkdir tmp
cd tmp
cmake -DMADDY_BUILD_WITH_BENCH=ON -DCMAKE_BUILD_TYPE=Release ..
make BUILD_TYPE=Release
../build/maddy_benchmark
```

416
bench/benchmark_test.md Normal file
View File

@@ -0,0 +1,416 @@
# Benchmark test file
This file is for the benchmark testing.
---
This specification defines which markdown syntax can be parsed by maddy.
There is no HTML allowed in the markdown syntax - or said otherwise - it might
destroy the output, if there was HTML in your markdown.
The Parser expects you to use spaces and not tabs for indentation in the
markdown.
If a line starts with `<` and `config->enabledParsers |= maddy::types::HTML_PARSER;`
is set, it expects that the upcoming line is HTML and therefor will not be
surrounded by a paragraph.
## Headlines
```
# h1 heading
## h2 heading
### h3 heading
#### h4 heading
##### h5 heading
###### h6 heading
```
results in:
```html
<h1>h1 heading</h1>
<h2>h2 heading</h2>
<h3>h3 heading</h3>
<h4>h4 heading</h4>
<h5>h5 heading</h5>
<h6>h6 heading</h6>
```
## Links
```
[Text of the link](http://example.com)
```
results in
```html
<a href="http://example.com">Text of the link</a>
```
```
[Text of the link](http://example.com "title text")
```
results in
```html
<a href="http://example.com" title="title text">Text of the link</a>
```
## Lists
### unordered
Characters "*", "+" or "-" to make an unordered "bullet" list are equivalent.
```
- unordered
* list
+ items
```
results in
```html
<ul>
<li>unordered</li>
<li>list</li>
<li>items</li>
</ul>
```
```
* unordered
* list
* items
* in
+ an
- hierarchy
```
results in
```html
<ul>
<li>unordered
<ul>
<li>list</li>
<li>items
<ul>
<li>in</li>
<li>an</li>
</ul>
</li>
<li>hierarchy</li>
</ul>
</li>
</ul>
```
### ordered
```
1. ordered
2. list
3. items
```
results in
```html
<ol>
<li>ordered</li>
<li>list</li>
<li>items</li>
</ol>
```
```
1. ordered
* list
* items
```
results in
```html
<ol>
<li>ordered</li>
<li>list</li>
<li>items</li>
</ol>
```
```
1. ordered
* list
1. items
* in
1. an
* hierarchy
```
results in
```html
<ol>
<li>ordered</li>
<li>list
<ol>
<li>items</li>
<li>in
<ol>
<li>an</li>
</ol>
</li>
<li>hierarchy</li>
</ol>
</li>
</ol>
```
### combination
```
* combination
* of
1. unordered and
* ordered
* list
```
results in
```html
<ul>
<li>combination</li>
<li>of
<ol>
<li>unordered and</li>
<li>ordered</li>
</ol>
</li>
<li>list</li>
</ul>
```
### checklist
```
- [ ] some item
- [ ] another item
- [x] some checked item
```
results in
```html
<ul class="checklist">
<li><label><input type="checkbox"/>some item
<ul class="checklist">
<li><label><input type="checkbox"/><span>another item</label></li>
</ul>
</label></li>
<li><label><input type="checkbox" checked="checked"/>some checked item</label></li>
</ul>
```
might not work in combination with other lists
## Code Blocks
```
some code
```
results in
```html
<pre><code>
some code
</code></pre>
```
```cpp
int a = 42;
```
results in
```html
<pre class="cpp"><code>
int a = 42;
</code></pre>
```
## Inline code
some text `some inline code` some other text
results in
```html
some text <code>some inline code</code> some other text
```
## quotes
```
> Some quote
```
results in
```html
<blockqoute>
<p>Some quote</p>
</blockquote>
```
## bold
```
**bold text**
__bold text__
```
results in
```html
<strong>bold text</strong>
<strong>bold text</strong>
```
## italic
```
*italic text*
```
results in
```html
<i>italic text</i>
```
## emphasized
This can be disabled by setting `config->enabledParsers &= ~maddy::types::EMPHASIZED_PARSER;`.
```
_emphasized text_
```
results in
```html
<em>emphasized text</em>
```
## strikethrough
```
~~striked through text~~
```
results in
```html
<s>striked through text</s>
```
## horizontal line
```
---
```
results in
```html
<hr/>
```
## break line
```
New\r\nLine
```
results in
```html
New<br>
Line
```
## Images
```
![Image alt text](http://example.com/example.png)
```
results in
```html
<img src="http://example.com/example.png" alt="Image alt text"/>
```
## Tables
```
|table>
Left header | middle header | last header
- | - | -
cell 1 | cell 2 | cell 3
cell 4 | cell 5 | cell 6
- | - | -
foot a | foot b | foot c
|<table
```
becomes
```html
<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 2</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>
```
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
```

64
bench/main.cpp Normal file
View File

@@ -0,0 +1,64 @@
/*
* This project is licensed under the MIT license. For more information see the
* LICENSE file.
*/
#include <fstream>
#include <iostream>
#include <memory>
#include <sstream>
#include <string>
#define ANKERL_NANOBENCH_IMPLEMENT
#include <nanobench.h>
#include "maddy/parser.h"
int main()
{
static const std::string markdownFile =
std::string(CURRENT_FILE_PATH) + "/benchmark_test.md";
std::stringstream buffer;
{
std::ifstream file(markdownFile);
if (!file.good() || !file.is_open())
{
std::cout << "could not read file at " << markdownFile << std::endl;
return 1;
}
buffer << file.rdbuf();
file.close();
}
if (!buffer.good() || buffer.str().empty())
{
std::cout << "buffer is invalid" << std::endl;
return 2;
}
// maddy 1.*
std::shared_ptr<maddy::Parser> parser = std::make_shared<maddy::Parser>();
// This is the place in the future to compare maddy with other libraries.
// For now it can be used to check if changes in maddy code result in better
// performance.
ankerl::nanobench::Bench()
.title("maddy test")
.warmup(100)
.relative(true)
.run(
"maddy 1.x",
[&]()
{
buffer.clear(); // clear any error flags
buffer.seekg(0, buffer.beg);
ankerl::nanobench::doNotOptimizeAway(parser->Parse(buffer));
}
);
return 0;
}

View File

@@ -0,0 +1,4 @@
@PACKAGE_INIT@
include("${CMAKE_CURRENT_LIST_DIR}/maddyTargets.cmake")
check_required_components(maddy)

View File

@@ -7,9 +7,9 @@ destroy the output, if there was HTML in your markdown.
The Parser expects you to use spaces and not tabs for indentation in the
markdown.
If a line starts with `<` and `config->isHTMLWrappedInParagraph` is false, it
expects that the upcoming line is HTML and therefor will not be surrounded by a
paragraph.
If a line starts with `<` and `config->enabledParsers |= maddy::types::HTML_PARSER;`
is set, it expects that the upcoming line is HTML and therefor will not be
surrounded by a paragraph.
## Headlines
@@ -41,6 +41,14 @@ results in
<a href="http://example.com">Text of the link</a>
```
```
[Text of the link](http://example.com "title text")
```
results in
```html
<a href="http://example.com" title="title text">Text of the link</a>
```
## Lists
### unordered
@@ -279,7 +287,7 @@ results in
## emphasized
This can be disabled by setting `config->isEmphasizedParserEnabled = false`.
This can be disabled by setting `config->enabledParsers &= ~maddy::types::EMPHASIZED_PARSER;`.
```
_emphasized text_

View File

@@ -10,8 +10,8 @@
#include <sstream>
#include <string>
// windows compatibility includes
#include <cctype>
#include <algorithm>
#include <cctype>
// -----------------------------------------------------------------------------
@@ -36,11 +36,13 @@ public:
*
* @method
* @param {std::function<void(std::string&)>} parseLineCallback
* @param {std::function<std::shared_ptr<BlockParser>(const std::string& line)>} getBlockParserForLineCallback
* @param {std::function<std::shared_ptr<BlockParser>(const std::string&
* line)>} getBlockParserForLineCallback
*/
BlockParser(
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
)
: result("", std::ios_base::ate | std::ios_base::in | std::ios_base::out)
, childParser(nullptr)
@@ -64,8 +66,7 @@ public:
* @param {std::string&} line
* @return {void}
*/
virtual void
AddLine(std::string& line)
virtual void AddLine(std::string& line)
{
this->parseBlock(line);
@@ -113,11 +114,7 @@ public:
* @method
* @return {std::stringstream}
*/
std::stringstream&
GetResult()
{
return this->result;
}
std::stringstream& GetResult() { return this->result; }
/**
* Clear
@@ -129,11 +126,7 @@ public:
* @method
* @return {void}
*/
void
Clear()
{
this->result.str("");
}
void Clear() { this->result.str(""); }
protected:
std::stringstream result;
@@ -143,8 +136,7 @@ protected:
virtual bool isLineParserAllowed() const = 0;
virtual void parseBlock(std::string& line) = 0;
void
parseLine(std::string& line)
void parseLine(std::string& line)
{
if (parseLineCallback)
{
@@ -152,38 +144,34 @@ protected:
}
}
uint32_t
getIndentationWidth(const std::string& line) const
uint32_t getIndentationWidth(const std::string& line) const
{
bool hasMetNonSpace = false;
uint32_t indentation = static_cast<uint32_t>(
std::count_if(
line.begin(),
line.end(),
[&hasMetNonSpace](unsigned char c)
uint32_t indentation = static_cast<uint32_t>(std::count_if(
line.begin(),
line.end(),
[&hasMetNonSpace](unsigned char c)
{
if (hasMetNonSpace)
{
if (hasMetNonSpace)
{
return false;
}
if (std::isspace(c))
{
return true;
}
hasMetNonSpace = true;
return false;
}
)
);
if (std::isspace(c))
{
return true;
}
hasMetNonSpace = true;
return false;
}
));
return indentation;
}
std::shared_ptr<BlockParser>
getBlockParserForLine(const std::string& line)
std::shared_ptr<BlockParser> getBlockParserForLine(const std::string& line)
{
if (getBlockParserForLineCallback)
{
@@ -195,7 +183,8 @@ protected:
private:
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;
}; // class BlockParser
// -----------------------------------------------------------------------------

View File

@@ -6,8 +6,8 @@
// -----------------------------------------------------------------------------
#include <string>
#include <regex>
#include <string>
#include "maddy/lineparser.h"
@@ -36,8 +36,7 @@ public:
* @param {std::string&} line The line to interpret
* @return {void}
*/
void
Parse(std::string& line) override
void Parse(std::string& line) override
{
static std::regex re(R"((\r\n|\r))");
static std::string replacement = "<br>";

View File

@@ -31,11 +31,13 @@ public:
*
* @method
* @param {std::function<void(std::string&)>} parseLineCallback
* @param {std::function<std::shared_ptr<BlockParser>(const std::string& line)>} getBlockParserForLineCallback
* @param {std::function<std::shared_ptr<BlockParser>(const std::string&
* line)>} getBlockParserForLineCallback
*/
ChecklistParser(
ChecklistParser(
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
)
: BlockParser(parseLineCallback, getBlockParserForLineCallback)
, isStarted(false)
@@ -51,8 +53,7 @@ public:
* @param {const std::string&} line
* @return {bool}
*/
static bool
IsStartingLine(const std::string& line)
static bool IsStartingLine(const std::string& line)
{
static std::regex re(R"(^- \[[x| ]\] .*)");
return std::regex_match(line, re);
@@ -64,27 +65,14 @@ public:
* @method
* @return {bool}
*/
bool
IsFinished() const override
{
return this->isFinished;
}
bool IsFinished() const override { return this->isFinished; }
protected:
bool
isInlineBlockAllowed() const override
{
return true;
}
bool isInlineBlockAllowed() const override { return true; }
bool
isLineParserAllowed() const override
{
return true;
}
bool isLineParserAllowed() const override { return true; }
void
parseBlock(std::string& line) override
void parseBlock(std::string& line) override
{
bool isStartOfNewListItem = IsStartingLine(line);
uint32_t indentation = getIndentationWidth(line);
@@ -97,7 +85,8 @@ protected:
line = std::regex_replace(line, emptyBoxRegex, emptyBoxReplacement);
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);
if (!this->isStarted)
@@ -113,11 +102,9 @@ protected:
return;
}
if (
line.empty() ||
line.find("</label></li><li><label>") != std::string::npos ||
line.find("</label></li></ul>") != std::string::npos
)
if (line.empty() ||
line.find("</label></li><li><label>") != std::string::npos ||
line.find("</label></li></ul>") != std::string::npos)
{
line = "</label></li></ul>" + line;
this->isFinished = true;

View File

@@ -7,8 +7,8 @@
// -----------------------------------------------------------------------------
#include <functional>
#include <string>
#include <regex>
#include <string>
#include "maddy/blockparser.h"
@@ -47,11 +47,13 @@ public:
*
* @method
* @param {std::function<void(std::string&)>} parseLineCallback
* @param {std::function<std::shared_ptr<BlockParser>(const std::string& line)>} getBlockParserForLineCallback
* @param {std::function<std::shared_ptr<BlockParser>(const std::string&
* line)>} getBlockParserForLineCallback
*/
CodeBlockParser(
CodeBlockParser(
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
)
: BlockParser(parseLineCallback, getBlockParserForLineCallback)
, isStarted(false)
@@ -71,8 +73,7 @@ public:
* @param {const std::string&} line
* @return {bool}
*/
static bool
IsStartingLine(const std::string& line)
static bool IsStartingLine(const std::string& line)
{
static std::regex re("^(?:`){3}(.*)$");
return std::regex_match(line, re);
@@ -84,27 +85,14 @@ public:
* @method
* @return {bool}
*/
bool
IsFinished() const override
{
return this->isFinished;
}
bool IsFinished() const override { return this->isFinished; }
protected:
bool
isInlineBlockAllowed() const override
{
return false;
}
bool isInlineBlockAllowed() const override { return false; }
bool
isLineParserAllowed() const override
{
return false;
}
bool isLineParserAllowed() const override { return false; }
void
parseBlock(std::string& line) override
void parseBlock(std::string& line) override
{
if (line == "```")
{

View File

@@ -6,8 +6,8 @@
// -----------------------------------------------------------------------------
#include <string>
#include <regex>
#include <string>
#include "maddy/lineparser.h"
@@ -38,10 +38,11 @@ public:
* @param {std::string&} line The line to interpret
* @return {void}
*/
void
Parse(std::string& line) override
void Parse(std::string& line) override
{
static std::regex re(R"((?!.*`.*|.*<code>.*)_(?!.*`.*|.*<\/code>.*)([^_]*)_(?!.*`.*|.*<\/code>.*))");
static std::regex re(
R"((?!.*`.*|.*<code>.*)_(?!.*`.*|.*<\/code>.*)([^_]*)_(?!.*`.*|.*<\/code>.*))"
);
static std::string replacement = "<em>$1</em>";
line = std::regex_replace(line, re, replacement);

View File

@@ -7,8 +7,8 @@
// -----------------------------------------------------------------------------
#include <functional>
#include <string>
#include <regex>
#include <string>
#include "maddy/blockparser.h"
@@ -53,11 +53,13 @@ public:
*
* @method
* @param {std::function<void(std::string&)>} parseLineCallback
* @param {std::function<std::shared_ptr<BlockParser>(const std::string& line)>} getBlockParserForLineCallback
* @param {std::function<std::shared_ptr<BlockParser>(const std::string&
* line)>} getBlockParserForLineCallback
*/
HeadlineParser(
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 isInlineParserAllowed = true
)
: BlockParser(parseLineCallback, getBlockParserForLineCallback)
@@ -73,8 +75,7 @@ public:
* @param {const std::string&} line
* @return {bool}
*/
static bool
IsStartingLine(const std::string& line)
static bool IsStartingLine(const std::string& line)
{
static std::regex re("^(?:#){1,6} (.*)");
return std::regex_match(line, re);
@@ -89,43 +90,33 @@ public:
* @method
* @return {bool}
*/
bool
IsFinished() const override
{
return true;
}
bool IsFinished() const override { return true; }
protected:
bool
isInlineBlockAllowed() const override
{
return false;
}
bool isInlineBlockAllowed() const override { return false; }
bool
isLineParserAllowed() const override
bool isLineParserAllowed() const override
{
return this->isInlineParserAllowed;
}
void
parseBlock(std::string& line) override
void parseBlock(std::string& line) override
{
static std::vector<std::regex> hlRegex = {
std::regex("^# (.*)")
, std::regex("^(?:#){2} (.*)")
, std::regex("^(?:#){3} (.*)")
, std::regex("^(?:#){4} (.*)")
, std::regex("^(?:#){5} (.*)")
, std::regex("^(?:#){6} (.*)")
std::regex("^# (.*)"),
std::regex("^(?:#){2} (.*)"),
std::regex("^(?:#){3} (.*)"),
std::regex("^(?:#){4} (.*)"),
std::regex("^(?:#){5} (.*)"),
std::regex("^(?:#){6} (.*)")
};
static std::vector<std::string> hlReplacement = {
"<h1>$1</h1>"
, "<h2>$1</h2>"
, "<h3>$1</h3>"
, "<h4>$1</h4>"
, "<h5>$1</h5>"
, "<h6>$1</h6>"
"<h1>$1</h1>",
"<h2>$1</h2>",
"<h3>$1</h3>",
"<h4>$1</h4>",
"<h5>$1</h5>",
"<h6>$1</h6>"
};
for (uint8_t i = 0; i < 6; ++i)

View File

@@ -7,8 +7,8 @@
// -----------------------------------------------------------------------------
#include <functional>
#include <string>
#include <regex>
#include <string>
#include "maddy/blockparser.h"
@@ -35,11 +35,13 @@ public:
*
* @method
* @param {std::function<void(std::string&)>} parseLineCallback
* @param {std::function<std::shared_ptr<BlockParser>(const std::string& line)>} getBlockParserForLineCallback
* @param {std::function<std::shared_ptr<BlockParser>(const std::string&
* line)>} getBlockParserForLineCallback
*/
HorizontalLineParser(
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
)
: BlockParser(parseLineCallback, getBlockParserForLineCallback)
, lineRegex("^---$")
@@ -54,8 +56,7 @@ public:
* @param {const std::string&} line
* @return {bool}
*/
static bool
IsStartingLine(const std::string& line)
static bool IsStartingLine(const std::string& line)
{
static std::regex re("^---$");
return std::regex_match(line, re);
@@ -70,27 +71,14 @@ public:
* @method
* @return {bool}
*/
bool
IsFinished() const override
{
return true;
}
bool IsFinished() const override { return true; }
protected:
bool
isInlineBlockAllowed() const override
{
return false;
}
bool isInlineBlockAllowed() const override { return false; }
bool
isLineParserAllowed() const override
{
return false;
}
bool isLineParserAllowed() const override { return false; }
void
parseBlock(std::string& line) override
void parseBlock(std::string& line) override
{
static std::string replacement = "<hr/>";

View File

@@ -30,11 +30,13 @@ public:
*
* @method
* @param {std::function<void(std::string&)>} parseLineCallback
* @param {std::function<std::shared_ptr<BlockParser>(const std::string& line)>} getBlockParserForLineCallback
* @param {std::function<std::shared_ptr<BlockParser>(const std::string&
* line)>} getBlockParserForLineCallback
*/
HtmlParser(
HtmlParser(
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
)
: BlockParser(parseLineCallback, getBlockParserForLineCallback)
, isStarted(false)
@@ -52,11 +54,7 @@ public:
* @param {const std::string&} line
* @return {bool}
*/
static bool
IsStartingLine(const std::string& line)
{
return line[0] == '<';
}
static bool IsStartingLine(const std::string& line) { return line[0] == '<'; }
/**
* IsFinished
@@ -66,27 +64,14 @@ public:
* @method
* @return {bool}
*/
bool
IsFinished() const override
{
return this->isFinished;
}
bool IsFinished() const override { return this->isFinished; }
protected:
bool
isInlineBlockAllowed() const override
{
return false;
}
bool isInlineBlockAllowed() const override { return false; }
bool
isLineParserAllowed() const override
{
return false;
}
bool isLineParserAllowed() const override { return false; }
void
parseBlock(std::string& line) override
void parseBlock(std::string& line) override
{
if (!this->isStarted)
{

View File

@@ -6,8 +6,8 @@
// -----------------------------------------------------------------------------
#include <string>
#include <regex>
#include <string>
#include "maddy/lineparser.h"
@@ -38,8 +38,7 @@ public:
* @param {std::string&} line The line to interpret
* @return {void}
*/
void
Parse(std::string& line) override
void Parse(std::string& line) override
{
static std::regex re(R"(\!\[([^\]]*)\]\(([^\]]*)\))");
static std::string replacement = "<img src=\"$2\" alt=\"$1\"/>";

View File

@@ -6,8 +6,8 @@
// -----------------------------------------------------------------------------
#include <string>
#include <regex>
#include <string>
#include "maddy/lineparser.h"
@@ -36,8 +36,7 @@ public:
* @param {std::string&} line The line to interpret
* @return {void}
*/
void
Parse(std::string& line) override
void Parse(std::string& line) override
{
static std::regex re("`([^`]*)`");
static std::string replacement = "<code>$1</code>";

View File

@@ -6,8 +6,8 @@
// -----------------------------------------------------------------------------
#include <string>
#include <regex>
#include <string>
#include "maddy/lineparser.h"
@@ -36,10 +36,11 @@ public:
* @param {std::string&} line The line to interpret
* @return {void}
*/
void
Parse(std::string& line) override
void Parse(std::string& line) override
{
static std::regex re(R"((?!.*`.*|.*<code>.*)\*(?!.*`.*|.*<\/code>.*)([^\*]*)\*(?!.*`.*|.*<\/code>.*))");
static std::regex re(
R"((?!.*`.*|.*<code>.*)\*(?!.*`.*|.*<\/code>.*)([^\*]*)\*(?!.*`.*|.*<\/code>.*))"
);
static std::string replacement = "<i>$1</i>";
line = std::regex_replace(line, re, replacement);
}

View File

@@ -7,8 +7,8 @@
// -----------------------------------------------------------------------------
#include <functional>
#include <string>
#include <regex>
#include <string>
#include "maddy/blockparser.h"
@@ -51,11 +51,13 @@ public:
*
* @method
* @param {std::function<void(std::string&)>} parseLineCallback
* @param {std::function<std::shared_ptr<BlockParser>(const std::string& line)>} getBlockParserForLineCallback
* @param {std::function<std::shared_ptr<BlockParser>(const std::string&
* line)>} getBlockParserForLineCallback
*/
LatexBlockParser(
LatexBlockParser(
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
)
: BlockParser(parseLineCallback, getBlockParserForLineCallback)
, isStarted(false)
@@ -75,8 +77,7 @@ public:
* @param {const std::string&} line
* @return {bool}
*/
static bool
IsStartingLine(const std::string& line)
static bool IsStartingLine(const std::string& line)
{
static std::regex re(R"(^(?:\$){2}(.*)$)");
return std::regex_match(line, re);
@@ -88,27 +89,14 @@ public:
* @method
* @return {bool}
*/
bool
IsFinished() const override
{
return this->isFinished;
}
bool IsFinished() const override { return this->isFinished; }
protected:
bool
isInlineBlockAllowed() const override
{
return false;
}
bool isInlineBlockAllowed() const override { return false; }
bool
isLineParserAllowed() const override
{
return false;
}
bool isLineParserAllowed() const override { return false; }
void
parseBlock(std::string& line) override
void parseBlock(std::string& line) override
{
if (!this->isStarted && line.substr(0, 2) == "$$")
{
@@ -116,7 +104,8 @@ protected:
this->isFinished = false;
}
if (this->isStarted && !this->isFinished && line.size() > 1 && line.substr(line.size() - 2, 2) == "$$")
if (this->isStarted && !this->isFinished && line.size() > 1 &&
line.substr(line.size() - 2, 2) == "$$")
{
this->isFinished = true;
this->isStarted = false;

View File

@@ -6,8 +6,8 @@
// -----------------------------------------------------------------------------
#include <string>
#include <regex>
#include <string>
#include "maddy/lineparser.h"
@@ -38,13 +38,19 @@ public:
* @param {std::string&} line The line to interpret
* @return {void}
*/
void
Parse(std::string& line) override
void Parse(std::string& line) override
{
static std::regex re(R"(\[([^\]]*)\]\(([^\]]*)\))");
static std::string replacement = "<a href=\"$2\">$1</a>";
// Match [name](http:://link "title text")
// NOTE: the 'no quote' bit at the beginning (^") is a hack for now:
// there should eventually be something that replaces it with '%22'.
static std::regex re(R"(\[([^\]]*)\]\( *([^)^ ^"]*) *\"([^\"]*)\" *\))");
static std::string replacement = "<a href=\"$2\" title=\"$3\">$1</a>";
line = std::regex_replace(line, re, replacement);
// Match [name](http:://link)
static std::regex re2(R"(\[([^\]]*)\]\( *([^)^ ^"]*) *\))");
static std::string replacement2 = "<a href=\"$2\">$1</a>";
line = std::regex_replace(line, re2, replacement2);
}
}; // class LinkParser

View File

@@ -31,11 +31,13 @@ public:
*
* @method
* @param {std::function<void(std::string&)>} parseLineCallback
* @param {std::function<std::shared_ptr<BlockParser>(const std::string& line)>} getBlockParserForLineCallback
* @param {std::function<std::shared_ptr<BlockParser>(const std::string&
* line)>} getBlockParserForLineCallback
*/
OrderedListParser(
OrderedListParser(
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
)
: BlockParser(parseLineCallback, getBlockParserForLineCallback)
, isStarted(false)
@@ -51,8 +53,7 @@ public:
* @param {const std::string&} line
* @return {bool}
*/
static bool
IsStartingLine(const std::string& line)
static bool IsStartingLine(const std::string& line)
{
static std::regex re("^1\\. .*");
return std::regex_match(line, re);
@@ -64,27 +65,14 @@ public:
* @method
* @return {bool}
*/
bool
IsFinished() const override
{
return this->isFinished;
}
bool IsFinished() const override { return this->isFinished; }
protected:
bool
isInlineBlockAllowed() const override
{
return true;
}
bool isInlineBlockAllowed() const override { return true; }
bool
isLineParserAllowed() const override
{
return true;
}
bool isLineParserAllowed() const override { return true; }
void
parseBlock(std::string& line) override
void parseBlock(std::string& line) override
{
bool isStartOfNewListItem = this->isStartOfNewListItem(line);
uint32_t indentation = getIndentationWidth(line);
@@ -107,12 +95,9 @@ protected:
return;
}
if (
line.empty() ||
line.find("</li><li>") != std::string::npos ||
line.find("</li></ol>") != std::string::npos ||
line.find("</li></ul>") != std::string::npos
)
if (line.empty() || line.find("</li><li>") != std::string::npos ||
line.find("</li></ol>") != std::string::npos ||
line.find("</li></ul>") != std::string::npos)
{
line = "</li></ol>" + line;
this->isFinished = true;
@@ -129,8 +114,7 @@ private:
bool isStarted;
bool isFinished;
bool
isStartOfNewListItem(const std::string& line) const
bool isStartOfNewListItem(const std::string& line) const
{
static std::regex re(R"(^(?:[1-9]+[0-9]*\. |\* ).*)");
return std::regex_match(line, re);

View File

@@ -30,11 +30,13 @@ public:
*
* @method
* @param {std::function<void(std::string&)>} parseLineCallback
* @param {std::function<std::shared_ptr<BlockParser>(const std::string& line)>} getBlockParserForLineCallback
* @param {std::function<std::shared_ptr<BlockParser>(const std::string&
* line)>} getBlockParserForLineCallback
*/
ParagraphParser(
ParagraphParser(
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)
@@ -54,11 +56,7 @@ public:
* @param {const std::string&} line
* @return {bool}
*/
static bool
IsStartingLine(const std::string& line)
{
return !line.empty();
}
static bool IsStartingLine(const std::string& line) { return !line.empty(); }
/**
* IsFinished
@@ -68,27 +66,14 @@ public:
* @method
* @return {bool}
*/
bool
IsFinished() const override
{
return this->isFinished;
}
bool IsFinished() const override { return this->isFinished; }
protected:
bool
isInlineBlockAllowed() const override
{
return false;
}
bool isInlineBlockAllowed() const override { return false; }
bool
isLineParserAllowed() const override
{
return true;
}
bool isLineParserAllowed() const override { return true; }
void
parseBlock(std::string& line) override
void parseBlock(std::string& line) override
{
if (this->isEnabled && !this->isStarted)
{

View File

@@ -6,8 +6,8 @@
// -----------------------------------------------------------------------------
#include <memory>
#include <functional>
#include <memory>
#include <string>
#include "maddy/parserconfig.h"
@@ -56,8 +56,12 @@ public:
*
* Check https://github.com/progsource/maddy/blob/master/CHANGELOG.md
* for the changelog.
*/
static const std::string& version() { static const std::string v = "1.3.0"; return v; }
*/
static const std::string& version()
{
static const std::string v = "1.6.0"; // MADDY_VERSION_LINE_REPLACEMENT
return v;
}
/**
* ctor
@@ -66,80 +70,52 @@ public:
*
* @method
*/
Parser(std::shared_ptr<ParserConfig> config = nullptr)
: config(config)
Parser(std::shared_ptr<ParserConfig> config = nullptr) : config(config)
{
// deprecated backward compatibility
// will be removed in 1.4.0 latest including the booleans
if (this->config && !this->config->isEmphasizedParserEnabled)
{
this->config->enabledParsers &= ~maddy::types::EMPHASIZED_PARSER;
}
if (this->config && !this->config->isHTMLWrappedInParagraph)
{
this->config->enabledParsers |= maddy::types::HTML_PARSER;
}
if (
!this->config ||
(this->config->enabledParsers & maddy::types::BREAKLINE_PARSER) != 0
)
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
)
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
)
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
)
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
)
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
)
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
)
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
)
if (!this->config ||
(this->config->enabledParsers & maddy::types::STRONG_PARSER) != 0)
{
this->strongParser = std::make_shared<StrongParser>();
}
@@ -152,8 +128,7 @@ public:
* @param {const std::istream&} markdown
* @return {std::string} HTML
*/
std::string
Parse(std::istream& markdown) const
std::string Parse(std::istream& markdown) const
{
std::string result = "";
std::shared_ptr<BlockParser> currentBlockParser = nullptr;
@@ -204,8 +179,7 @@ private:
std::shared_ptr<StrongParser> strongParser;
// block parser have to run before
void
runLineParser(std::string& line) const
void runLineParser(std::string& line) const
{
// Attention! ImageParser has to be before LinkParser
if (this->imageParser)
@@ -250,167 +224,114 @@ private:
}
}
std::shared_ptr<BlockParser>
getBlockParserForLine(const std::string& line) const
std::shared_ptr<BlockParser> getBlockParserForLine(const std::string& line
) const
{
std::shared_ptr<BlockParser> parser;
if (
(
!this->config ||
(this->config->enabledParsers & maddy::types::CODE_BLOCK_PARSER) != 0
) &&
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>(
nullptr,
nullptr
);
parser = std::make_shared<maddy::CodeBlockParser>(nullptr, nullptr);
}
else if (
this->config &&
(this->config->enabledParsers & maddy::types::LATEX_BLOCK_PARSER) != 0 &&
maddy::LatexBlockParser::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
);
parser = std::make_shared<LatexBlockParser>(nullptr, nullptr);
}
else if (
(
!this->config ||
(this->config->enabledParsers & maddy::types::HEADLINE_PARSER) != 0
) &&
maddy::HeadlineParser::IsStartingLine(line)
)
else if ((!this->config || (this->config->enabledParsers &
maddy::types::HEADLINE_PARSER) != 0) &&
maddy::HeadlineParser::IsStartingLine(line))
{
if (!this->config || this->config->isHeadlineInlineParsingEnabled)
{
parser = std::make_shared<maddy::HeadlineParser>(
[this](std::string& line){ this->runLineParser(line); },
[this](std::string& line) { this->runLineParser(line); },
nullptr,
true
);
}
else
{
parser = std::make_shared<maddy::HeadlineParser>(
nullptr,
nullptr,
false
);
parser =
std::make_shared<maddy::HeadlineParser>(nullptr, nullptr, false);
}
}
else if (
(
!this->config ||
(this->config->enabledParsers & maddy::types::HORIZONTAL_LINE_PARSER) != 0
) &&
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>(
nullptr,
nullptr
);
parser = std::make_shared<maddy::HorizontalLineParser>(nullptr, nullptr);
}
else if (
(
!this->config ||
(this->config->enabledParsers & maddy::types::QUOTE_PARSER) != 0
) &&
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>(
[this](std::string& line){ this->runLineParser(line); },
[this](const std::string& line){ return this->getBlockParserForLine(line); }
[this](std::string& line) { this->runLineParser(line); },
[this](const std::string& line)
{ return this->getBlockParserForLine(line); }
);
}
else if (
(
!this->config ||
(this->config->enabledParsers & maddy::types::TABLE_PARSER) != 0
) &&
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>(
[this](std::string& line){ this->runLineParser(line); },
nullptr
[this](std::string& line) { this->runLineParser(line); }, nullptr
);
}
else if (
(
!this->config ||
(this->config->enabledParsers & maddy::types::CHECKLIST_PARSER) != 0
) &&
maddy::ChecklistParser::IsStartingLine(line)
)
else if ((!this->config || (this->config->enabledParsers &
maddy::types::CHECKLIST_PARSER) != 0) &&
maddy::ChecklistParser::IsStartingLine(line))
{
parser = this->createChecklistParser();
}
else if (
(
!this->config ||
(this->config->enabledParsers & maddy::types::ORDERED_LIST_PARSER) != 0
) &&
maddy::OrderedListParser::IsStartingLine(line)
)
else if ((!this->config || (this->config->enabledParsers &
maddy::types::ORDERED_LIST_PARSER) != 0) &&
maddy::OrderedListParser::IsStartingLine(line))
{
parser = this->createOrderedListParser();
}
else if (
(
!this->config ||
(this->config->enabledParsers & maddy::types::UNORDERED_LIST_PARSER) != 0
) &&
maddy::UnorderedListParser::IsStartingLine(line)
)
else if ((!this->config || (this->config->enabledParsers &
maddy::types::UNORDERED_LIST_PARSER) != 0) &&
maddy::UnorderedListParser::IsStartingLine(line))
{
parser = this->createUnorderedListParser();
}
else if (
this->config &&
(this->config->enabledParsers & maddy::types::HTML_PARSER) != 0 &&
maddy::HtmlParser::IsStartingLine(line)
)
else if (this->config &&
(this->config->enabledParsers & maddy::types::HTML_PARSER) != 0 &&
maddy::HtmlParser::IsStartingLine(line))
{
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>(
[this](std::string& line){ this->runLineParser(line); },
[this](std::string& line) { this->runLineParser(line); },
nullptr,
(!this->config || (this->config->enabledParsers & maddy::types::PARAGRAPH_PARSER) != 0)
(!this->config ||
(this->config->enabledParsers & maddy::types::PARAGRAPH_PARSER) != 0)
);
}
return parser;
}
std::shared_ptr<BlockParser>
createChecklistParser() const
std::shared_ptr<BlockParser> createChecklistParser() const
{
return std::make_shared<maddy::ChecklistParser>(
[this](std::string& line){ this->runLineParser(line); },
[this](std::string& line) { this->runLineParser(line); },
[this](const std::string& line)
{
std::shared_ptr<BlockParser> parser;
if (
(
!this->config ||
(this->config->enabledParsers & maddy::types::CHECKLIST_PARSER) != 0
) &&
maddy::ChecklistParser::IsStartingLine(line)
)
if ((!this->config || (this->config->enabledParsers &
maddy::types::CHECKLIST_PARSER) != 0) &&
maddy::ChecklistParser::IsStartingLine(line))
{
parser = this->createChecklistParser();
}
@@ -420,32 +341,24 @@ private:
);
}
std::shared_ptr<BlockParser>
createOrderedListParser() const
std::shared_ptr<BlockParser> createOrderedListParser() const
{
return std::make_shared<maddy::OrderedListParser>(
[this](std::string& line){ this->runLineParser(line); },
[this](std::string& line) { this->runLineParser(line); },
[this](const std::string& line)
{
std::shared_ptr<BlockParser> parser;
if (
(
!this->config ||
(this->config->enabledParsers & maddy::types::ORDERED_LIST_PARSER) != 0
) &&
maddy::OrderedListParser::IsStartingLine(line)
)
if ((!this->config || (this->config->enabledParsers &
maddy::types::ORDERED_LIST_PARSER) != 0) &&
maddy::OrderedListParser::IsStartingLine(line))
{
parser = this->createOrderedListParser();
}
else if (
(
!this->config ||
(this->config->enabledParsers & maddy::types::UNORDERED_LIST_PARSER) != 0
) &&
maddy::UnorderedListParser::IsStartingLine(line)
)
else if ((!this->config || (this->config->enabledParsers &
maddy::types::UNORDERED_LIST_PARSER) != 0
) &&
maddy::UnorderedListParser::IsStartingLine(line))
{
parser = this->createUnorderedListParser();
}
@@ -455,32 +368,24 @@ private:
);
}
std::shared_ptr<BlockParser>
createUnorderedListParser() const
std::shared_ptr<BlockParser> createUnorderedListParser() const
{
return std::make_shared<maddy::UnorderedListParser>(
[this](std::string& line){ this->runLineParser(line); },
[this](std::string& line) { this->runLineParser(line); },
[this](const std::string& line)
{
std::shared_ptr<BlockParser> parser;
if (
(
!this->config ||
(this->config->enabledParsers & maddy::types::ORDERED_LIST_PARSER) != 0
) &&
maddy::OrderedListParser::IsStartingLine(line)
)
if ((!this->config || (this->config->enabledParsers &
maddy::types::ORDERED_LIST_PARSER) != 0) &&
maddy::OrderedListParser::IsStartingLine(line))
{
parser = this->createOrderedListParser();
}
else if (
(
!this->config ||
(this->config->enabledParsers & maddy::types::UNORDERED_LIST_PARSER) != 0
) &&
maddy::UnorderedListParser::IsStartingLine(line)
)
else if ((!this->config || (this->config->enabledParsers &
maddy::types::UNORDERED_LIST_PARSER) != 0
) &&
maddy::UnorderedListParser::IsStartingLine(line))
{
parser = this->createUnorderedListParser();
}

View File

@@ -14,6 +14,7 @@ namespace maddy {
namespace types {
// clang-format off
/**
* PARSER_TYPE
*
@@ -46,6 +47,7 @@ enum PARSER_TYPE : uint32_t
DEFAULT = 0b0111111111110111111,
ALL = 0b1111111111111111111,
};
// clang-format on
} // namespace types
@@ -56,36 +58,20 @@ enum PARSER_TYPE : uint32_t
*/
struct ParserConfig
{
/**
* @deprecated will be removed in 1.4.0 latest
*
* this flag = false == `enabledParsers &= ~maddy::types::EMPHASIZED_PARSER`
*/
bool isEmphasizedParserEnabled;
/**
* @deprecated will be removed in 1.4.0 latest
*
* this flag = false == `enabledParsers |= maddy::types::HTML_PARSER`
*/
bool isHTMLWrappedInParagraph;
/**
* en-/disable headline inline-parsing
*
* default: enabled
*/
*/
bool isHeadlineInlineParsingEnabled;
/**
* enabled parsers bitfield
*/
*/
uint32_t enabledParsers;
ParserConfig()
: isEmphasizedParserEnabled(true)
, isHTMLWrappedInParagraph(true)
, isHeadlineInlineParsingEnabled(true)
: isHeadlineInlineParsingEnabled(true)
, enabledParsers(maddy::types::DEFAULT)
{}
}; // class ParserConfig

View File

@@ -31,11 +31,13 @@ public:
*
* @method
* @param {std::function<void(std::string&)>} parseLineCallback
* @param {std::function<std::shared_ptr<BlockParser>(const std::string& line)>} getBlockParserForLineCallback
* @param {std::function<std::shared_ptr<BlockParser>(const std::string&
* line)>} getBlockParserForLineCallback
*/
QuoteParser(
QuoteParser(
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
)
: BlockParser(parseLineCallback, getBlockParserForLineCallback)
, isStarted(false)
@@ -51,8 +53,7 @@ public:
* @param {const std::string&} line
* @return {bool}
*/
static bool
IsStartingLine(const std::string& line)
static bool IsStartingLine(const std::string& line)
{
static std::regex re(R"(^\>.*)");
return std::regex_match(line, re);
@@ -67,8 +68,7 @@ public:
* @param {std::string&} line
* @return {void}
*/
void
AddLine(std::string& line) override
void AddLine(std::string& line) override
{
if (!this->isStarted)
{
@@ -122,27 +122,14 @@ public:
* @method
* @return {bool}
*/
bool
IsFinished() const override
{
return this->isFinished;
}
bool IsFinished() const override { return this->isFinished; }
protected:
bool
isInlineBlockAllowed() const override
{
return true;
}
bool isInlineBlockAllowed() const override { return true; }
bool
isLineParserAllowed() const override
{
return true;
}
bool isLineParserAllowed() const override { return true; }
void
parseBlock(std::string& line) override
void parseBlock(std::string& line) override
{
static std::regex lineRegexWithSpace(R"(^\> )");
line = std::regex_replace(line, lineRegexWithSpace, "");

View File

@@ -6,8 +6,8 @@
// -----------------------------------------------------------------------------
#include <string>
#include <regex>
#include <string>
#include "maddy/lineparser.h"
@@ -36,10 +36,11 @@ public:
* @param {std::string&} line The line to interpret
* @return {void}
*/
void
Parse(std::string& line) override
void Parse(std::string& line) override
{
static std::regex re(R"((?!.*`.*|.*<code>.*)\~\~(?!.*`.*|.*<\/code>.*)([^\~]*)\~\~(?!.*`.*|.*<\/code>.*))");
static std::regex re(
R"((?!.*`.*|.*<code>.*)\~\~(?!.*`.*|.*<\/code>.*)([^\~]*)\~\~(?!.*`.*|.*<\/code>.*))"
);
static std::string replacement = "<s>$1</s>";
line = std::regex_replace(line, re, replacement);

View File

@@ -6,8 +6,8 @@
// -----------------------------------------------------------------------------
#include <string>
#include <regex>
#include <string>
#include "maddy/lineparser.h"
@@ -38,13 +38,15 @@ public:
* @param {std::string&} line The line to interpret
* @return {void}
*/
void
Parse(std::string& line) override
void Parse(std::string& line) override
{
static std::vector<std::regex> res
{
std::regex{R"((?!.*`.*|.*<code>.*)\*\*(?!.*`.*|.*<\/code>.*)([^\*\*]*)\*\*(?!.*`.*|.*<\/code>.*))"},
std::regex{R"((?!.*`.*|.*<code>.*)__(?!.*`.*|.*<\/code>.*)([^__]*)__(?!.*`.*|.*<\/code>.*))"}
static std::vector<std::regex> res{
std::regex{
R"((?!.*`.*|.*<code>.*)\*\*(?!.*`.*|.*<\/code>.*)([^\*\*]*)\*\*(?!.*`.*|.*<\/code>.*))"
},
std::regex{
R"((?!.*`.*|.*<code>.*)__(?!.*`.*|.*<\/code>.*)([^__]*)__(?!.*`.*|.*<\/code>.*))"
}
};
static std::string replacement = "<strong>$1</strong>";
for (const auto& re : res)

View File

@@ -7,8 +7,8 @@
// -----------------------------------------------------------------------------
#include <functional>
#include <string>
#include <regex>
#include <string>
#include "maddy/blockparser.h"
@@ -33,11 +33,13 @@ public:
*
* @method
* @param {std::function<void(std::string&)>} parseLineCallback
* @param {std::function<std::shared_ptr<BlockParser>(const std::string& line)>} getBlockParserForLineCallback
* @param {std::function<std::shared_ptr<BlockParser>(const std::string&
* line)>} getBlockParserForLineCallback
*/
TableParser(
TableParser(
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
)
: BlockParser(parseLineCallback, getBlockParserForLineCallback)
, isStarted(false)
@@ -55,8 +57,7 @@ public:
* @param {const std::string&} line
* @return {bool}
*/
static bool
IsStartingLine(const std::string& line)
static bool IsStartingLine(const std::string& line)
{
static std::string matchString("|table>");
return line == matchString;
@@ -71,8 +72,7 @@ public:
* @param {std::string&} line
* @return {void}
*/
void
AddLine(std::string& line) override
void AddLine(std::string& line) override
{
if (!this->isStarted && line == "|table>")
{
@@ -124,27 +124,14 @@ public:
* @method
* @return {bool}
*/
bool
IsFinished() const override
{
return this->isFinished;
}
bool IsFinished() const override { return this->isFinished; }
protected:
bool
isInlineBlockAllowed() const override
{
return false;
}
bool isInlineBlockAllowed() const override { return false; }
bool
isLineParserAllowed() const override
{
return true;
}
bool isLineParserAllowed() const override { return true; }
void
parseBlock(std::string&) override
void parseBlock(std::string&) override
{
result << "<table>";

View File

@@ -31,11 +31,13 @@ public:
*
* @method
* @param {std::function<void(std::string&)>} parseLineCallback
* @param {std::function<std::shared_ptr<BlockParser>(const std::string& line)>} getBlockParserForLineCallback
* @param {std::function<std::shared_ptr<BlockParser>(const std::string&
* line)>} getBlockParserForLineCallback
*/
UnorderedListParser(
UnorderedListParser(
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
)
: BlockParser(parseLineCallback, getBlockParserForLineCallback)
, isStarted(false)
@@ -51,8 +53,7 @@ public:
* @param {const std::string&} line
* @return {bool}
*/
static bool
IsStartingLine(const std::string& line)
static bool IsStartingLine(const std::string& line)
{
static std::regex re("^[+*-] .*");
return std::regex_match(line, re);
@@ -64,27 +65,14 @@ public:
* @method
* @return {bool}
*/
bool
IsFinished() const override
{
return this->isFinished;
}
bool IsFinished() const override { return this->isFinished; }
protected:
bool
isInlineBlockAllowed() const override
{
return true;
}
bool isInlineBlockAllowed() const override { return true; }
bool
isLineParserAllowed() const override
{
return true;
}
bool isLineParserAllowed() const override { return true; }
void
parseBlock(std::string& line) override
void parseBlock(std::string& line) override
{
bool isStartOfNewListItem = IsStartingLine(line);
uint32_t indentation = getIndentationWidth(line);
@@ -105,12 +93,9 @@ protected:
return;
}
if (
line.empty() ||
line.find("</li><li>") != std::string::npos ||
line.find("</li></ol>") != std::string::npos ||
line.find("</li></ul>") != std::string::npos
)
if (line.empty() || line.find("</li><li>") != std::string::npos ||
line.find("</li></ol>") != std::string::npos ||
line.find("</li></ul>") != std::string::npos)
{
line = "</li></ul>" + line;
this->isFinished = true;

View File

@@ -21,7 +21,7 @@ include(FetchContent)
FetchContent_Declare(
googletest
GIT_REPOSITORY https://github.com/google/googletest.git
GIT_TAG b796f7d44681514f58a683a3a71ff17c94edb0c1 # v1.13.0
GIT_TAG v1.16.0
)
FetchContent_MakeAvailable(googletest)

View File

@@ -0,0 +1,8 @@
# This project is licensed under the MIT license. For more information see the
# LICENSE file.
cmake_minimum_required(VERSION 3.25)
find_package(maddy REQUIRED)
add_executable(maddy_find_package_example main.cpp)
target_link_libraries(maddy_find_package_example PRIVATE maddy::maddy)

View File

@@ -0,0 +1,25 @@
/*
* This project is licensed under the MIT license. For more information see the
* LICENSE file.
*
* This file is a tiny example project to test if find_package works correctly.
*/
#include <iostream>
#include <memory>
#include <sstream>
#include <string>
#include "maddy/parser.h"
int main(int argc, char** argv)
{
std::shared_ptr<maddy::Parser> parser = std::make_shared<maddy::Parser>();
std::stringstream markdownStream;
markdownStream << "# Hello World\n"
<< "This is a **bold** text and this is *italic* text.\n";
std::cout << parser->Parse(markdownStream) << std::endl;
return 0;
}

View File

@@ -15,10 +15,10 @@ class MADDY_CHECKLISTPARSER : public ::testing::Test
protected:
std::shared_ptr<maddy::ChecklistParser> clParser;
void
SetUp() override
void SetUp() override
{
std::function<std::shared_ptr<maddy::BlockParser>(const std::string& line)> getBlockParserForLineCallback = [](const std::string& line)
std::function<std::shared_ptr<maddy::BlockParser>(const std::string& line)>
getBlockParserForLineCallback = [](const std::string& line)
{
if (maddy::ChecklistParser::IsStartingLine(line))
{
@@ -32,15 +32,16 @@ protected:
};
this->clParser = std::make_shared<maddy::ChecklistParser>(
nullptr,
getBlockParserForLineCallback
nullptr, getBlockParserForLineCallback
);
}
};
// -----------------------------------------------------------------------------
TEST_F(MADDY_CHECKLISTPARSER, IsStartingLineReturnsTrueWhenFacedWithBeginningOfList)
TEST_F(
MADDY_CHECKLISTPARSER, IsStartingLineReturnsTrueWhenFacedWithBeginningOfList
)
{
ASSERT_TRUE(maddy::ChecklistParser::IsStartingLine("- [ ] a"));
ASSERT_TRUE(maddy::ChecklistParser::IsStartingLine("- [x] b"));
@@ -53,12 +54,11 @@ TEST_F(MADDY_CHECKLISTPARSER, IsFinishedAlwaysReturnsFalseInTheBeginning)
TEST_F(MADDY_CHECKLISTPARSER, ItReplacesMarkdownWithAnHtmlChecklist)
{
std::vector<std::string> markdown = {
"- [ ] a"
, "- [x] b"
, ""
};
std::string expected = "<ul class=\"checklist\"><li><label><input type=\"checkbox\"/> a</label></li><li><label><input type=\"checkbox\" checked=\"checked\"/> b</label></li></ul>";
std::vector<std::string> markdown = {"- [ ] a", "- [x] b", ""};
std::string expected =
"<ul class=\"checklist\"><li><label><input type=\"checkbox\"/> "
"a</label></li><li><label><input type=\"checkbox\" checked=\"checked\"/> "
"b</label></li></ul>";
for (std::string md : markdown)
{
@@ -76,14 +76,15 @@ TEST_F(MADDY_CHECKLISTPARSER, ItReplacesMarkdownWithAnHtmlChecklist)
TEST_F(MADDY_CHECKLISTPARSER, ItReplacesMarkdownWithAnHierachicalHtmlList)
{
std::vector<std::string> markdown = {
"- [ ] a"
, " - [ ] d"
, " - [ ] e"
, "- [ ] b"
, " - [x] c"
, ""
"- [ ] a", " - [ ] d", " - [ ] e", "- [ ] b", " - [x] c", ""
};
std::string expected = "<ul class=\"checklist\"><li><label><input type=\"checkbox\"/> a<ul class=\"checklist\"><li><label><input type=\"checkbox\"/> d</label></li><li><label><input type=\"checkbox\"/> e</label></li></ul></label></li><li><label><input type=\"checkbox\"/> b<ul class=\"checklist\"><li><label><input type=\"checkbox\" checked=\"checked\"/> c</label></li></ul></label></li></ul>";
std::string expected =
"<ul class=\"checklist\"><li><label><input type=\"checkbox\"/> a<ul "
"class=\"checklist\"><li><label><input type=\"checkbox\"/> "
"d</label></li><li><label><input type=\"checkbox\"/> "
"e</label></li></ul></label></li><li><label><input type=\"checkbox\"/> "
"b<ul class=\"checklist\"><li><label><input type=\"checkbox\" "
"checked=\"checked\"/> c</label></li></ul></label></li></ul>";
for (std::string md : markdown)
{

View File

@@ -15,13 +15,9 @@ class MADDY_CODEBLOCKPARSER : public ::testing::Test
protected:
std::shared_ptr<maddy::CodeBlockParser> cbParser;
void
SetUp() override
void SetUp() override
{
this->cbParser = std::make_shared<maddy::CodeBlockParser>(
nullptr,
nullptr
);
this->cbParser = std::make_shared<maddy::CodeBlockParser>(nullptr, nullptr);
}
};
@@ -40,13 +36,11 @@ TEST_F(MADDY_CODEBLOCKPARSER, IsFinishedReturnsFalseInTheBeginning)
TEST_F(MADDY_CODEBLOCKPARSER, ItReplacesMarkdownWithAnHtmlCodeBlock)
{
std::vector<std::string> markdown = {
"```"
, "some code"
, "some other code"
, "```"
"```", "some code", "some other code", "```"
};
std::string expected = "<pre><code>\nsome code\nsome other code\n</code></pre>";
std::string expected =
"<pre><code>\nsome code\nsome other code\n</code></pre>";
for (std::string md : markdown)
{
@@ -63,13 +57,11 @@ TEST_F(MADDY_CODEBLOCKPARSER, ItReplacesMarkdownWithAnHtmlCodeBlock)
TEST_F(MADDY_CODEBLOCKPARSER, ItShouldUseAnythingBehindFirstBackticksAsClass)
{
std::vector<std::string> markdown = {
"```cpp"
, "some code"
, "some other code"
, "```"
"```cpp", "some code", "some other code", "```"
};
std::string expected = "<pre class=\"cpp\"><code>\nsome code\nsome other code\n</code></pre>";
std::string expected =
"<pre class=\"cpp\"><code>\nsome code\nsome other code\n</code></pre>";
for (std::string md : markdown)
{

View File

@@ -24,7 +24,8 @@ TEST(MADDY_EMPHASIZEDPARSER, ItReplacesMarkdownWithEmphasizedHTML)
TEST(MADDY_EMPHASIZEDPARSER, ItDoesNotParseInsideInlineCode)
{
std::string text = "some text `*bla*` `/**text*/` testing _it_ out";
std::string expected = "some text `*bla*` `/**text*/` testing <em>it</em> out";
std::string expected =
"some text `*bla*` `/**text*/` testing <em>it</em> out";
auto emphasizedParser = std::make_shared<maddy::EmphasizedParser>();
emphasizedParser->Parse(text);

View File

@@ -15,19 +15,17 @@ class MADDY_HEADLINEPARSER : public ::testing::Test
protected:
std::shared_ptr<maddy::HeadlineParser> hlParser;
void
SetUp() override
void SetUp() override
{
this->hlParser = std::make_shared<maddy::HeadlineParser>(
nullptr,
nullptr
);
this->hlParser = std::make_shared<maddy::HeadlineParser>(nullptr, nullptr);
}
};
// -----------------------------------------------------------------------------
TEST_F(MADDY_HEADLINEPARSER, IsStartingLineReturnsTrueWhenFacedWithOneToSixHashes)
TEST_F(
MADDY_HEADLINEPARSER, IsStartingLineReturnsTrueWhenFacedWithOneToSixHashes
)
{
ASSERT_TRUE(maddy::HeadlineParser::IsStartingLine("# a"));
ASSERT_TRUE(maddy::HeadlineParser::IsStartingLine("## a"));
@@ -45,21 +43,16 @@ TEST_F(MADDY_HEADLINEPARSER, IsFinishedAlwaysReturnsTrue)
TEST_F(MADDY_HEADLINEPARSER, ItReplacesMarkdownWithAnHtmlHeadline)
{
std::vector<std::string> markdown = {
"# a"
, "## a"
, "### a"
, "#### a"
, "##### a"
, "###### a"
"# a", "## a", "### a", "#### a", "##### a", "###### a"
};
std::vector<std::string> expected = {
"<h1>a</h1>"
, "<h2>a</h2>"
, "<h3>a</h3>"
, "<h4>a</h4>"
, "<h5>a</h5>"
, "<h6>a</h6>"
"<h1>a</h1>",
"<h2>a</h2>",
"<h3>a</h3>",
"<h4>a</h4>",
"<h5>a</h5>",
"<h6>a</h6>"
};
for (uint8_t i = 0; i < 6; ++i)

View File

@@ -15,19 +15,18 @@ class MADDY_HORIZONTALLINEPARSER : public ::testing::Test
protected:
std::shared_ptr<maddy::HorizontalLineParser> hlParser;
void
SetUp() override
void SetUp() override
{
this->hlParser = std::make_shared<maddy::HorizontalLineParser>(
nullptr,
nullptr
);
this->hlParser =
std::make_shared<maddy::HorizontalLineParser>(nullptr, nullptr);
}
};
// -----------------------------------------------------------------------------
TEST_F(MADDY_HORIZONTALLINEPARSER, IsStartingLineReturnsTrueWhenFacedWithThreeDashes)
TEST_F(
MADDY_HORIZONTALLINEPARSER, IsStartingLineReturnsTrueWhenFacedWithThreeDashes
)
{
ASSERT_TRUE(maddy::HorizontalLineParser::IsStartingLine("---"));
}

View File

@@ -15,13 +15,9 @@ class MADDY_HTMLPARSER : public ::testing::Test
protected:
std::shared_ptr<maddy::HtmlParser> pParser;
void
SetUp() override
void SetUp() override
{
this->pParser = std::make_shared<maddy::HtmlParser>(
nullptr,
nullptr
);
this->pParser = std::make_shared<maddy::HtmlParser>(nullptr, nullptr);
}
};
@@ -35,11 +31,7 @@ TEST_F(MADDY_HTMLPARSER, IsFinishedReturnsFalseInTheBeginning)
TEST_F(MADDY_HTMLPARSER, IsStartingLineReturnsFalseWhenFacedWithNoSmallerThan)
{
const std::vector<std::string> markdown = {
"> quote"
, "some text"
, "* list"
, "1. numbered list"
, "|table>"
"> quote", "some text", "* list", "1. numbered list", "|table>"
};
for (size_t i = 0; i < markdown.size(); ++i)
@@ -57,17 +49,18 @@ TEST_F(MADDY_HTMLPARSER, IsStartingLineReturnsTrueWhenFacedWithSmallerThan)
TEST_F(MADDY_HTMLPARSER, ItReplacesNoHtml)
{
const std::vector<std::string> markdown {
"some text in a paragraph"
, ""
, "<div> some HTML</div>"
, ""
, "<div>more"
, "HTML"
, "</div>"
, ""
const std::vector<std::string> markdown{
"some text in a paragraph",
"",
"<div> some HTML</div>",
"",
"<div>more",
"HTML",
"</div>",
""
};
const std::string expected = "some text in a paragraph <div> some HTML</div><div>more HTML </div>";
const std::string expected =
"some text in a paragraph <div> some HTML</div><div>more HTML </div>";
for (std::string md : markdown)
{

View File

@@ -13,7 +13,8 @@
TEST(MADDY_IMAGEPARSER, ItReplacesMarkdownWithAnImage)
{
std::string text = "Some text ![Image Title](http://example.com/a.png)";
std::string expected = "Some text <img src=\"http://example.com/a.png\" alt=\"Image Title\"/>";
std::string expected =
"Some text <img src=\"http://example.com/a.png\" alt=\"Image Title\"/>";
auto imageParser = std::make_shared<maddy::ImageParser>();
imageParser->Parse(text);
@@ -23,8 +24,12 @@ TEST(MADDY_IMAGEPARSER, ItReplacesMarkdownWithAnImage)
TEST(MADDY_IMAGEPARSER, ItReplacesMarkdownWithImages)
{
std::string text = "Some text ![Image Title](http://example.com/a.png) bla ![Image Title](http://example.com/a.png)";
std::string expected = "Some text <img src=\"http://example.com/a.png\" alt=\"Image Title\"/> bla <img src=\"http://example.com/a.png\" alt=\"Image Title\"/>";
std::string text =
"Some text ![Image Title](http://example.com/a.png) bla ![Image "
"Title](http://example.com/a.png)";
std::string expected =
"Some text <img src=\"http://example.com/a.png\" alt=\"Image Title\"/> bla "
"<img src=\"http://example.com/a.png\" alt=\"Image Title\"/>";
auto imageParser = std::make_shared<maddy::ImageParser>();
imageParser->Parse(text);

View File

@@ -13,7 +13,8 @@
TEST(MADDY_INLINECODEPARSER, ItReplacesMarkdownWithCodeHTML)
{
std::string text = "some text `bla` text testing `it` out";
std::string expected = "some text <code>bla</code> text testing <code>it</code> out";
std::string expected =
"some text <code>bla</code> text testing <code>it</code> out";
auto emphasizedParser = std::make_shared<maddy::InlineCodeParser>();
emphasizedParser->Parse(text);

View File

@@ -12,7 +12,6 @@
TEST(MADDY_ITALICPARSER, ItReplacesMarkdownWithItalicHTML)
{
std::string text = "some text *bla* text testing *it* out";
std::string expected = "some text <i>bla</i> text testing <i>it</i> out";
auto italicParser = std::make_shared<maddy::ItalicParser>();

View File

@@ -15,13 +15,10 @@ class MADDY_LATEXBLOCKPARSER : public ::testing::Test
protected:
std::shared_ptr<maddy::LatexBlockParser> lbParser;
void
SetUp() override
void SetUp() override
{
this->lbParser = std::make_shared<maddy::LatexBlockParser>(
nullptr,
nullptr
);
this->lbParser =
std::make_shared<maddy::LatexBlockParser>(nullptr, nullptr);
}
};
@@ -60,9 +57,7 @@ TEST_F(MADDY_LATEXBLOCKPARSER, ItReplacesOneLineMarkdownWithALatexBlock)
TEST_F(MADDY_LATEXBLOCKPARSER, ItReplacesABlockMarkdownWithALatexBlock)
{
std::vector<std::string> markdown = {
"$$",
"x = {-b \\pm \\sqrt{b^2-4ac} \\over 2a}.",
"$$"
"$$", "x = {-b \\pm \\sqrt{b^2-4ac} \\over 2a}.", "$$"
};
std::string expected = "$$\nx = {-b \\pm \\sqrt{b^2-4ac} \\over 2a}.\n$$\n";
@@ -82,9 +77,7 @@ TEST_F(MADDY_LATEXBLOCKPARSER, ItReplacesABlockMarkdownWithALatexBlock)
TEST_F(MADDY_LATEXBLOCKPARSER, ItReplacesAMultilineBlockMarkdownWithALatexBlock)
{
std::vector<std::string> markdown = {
"$$",
"x = {-b \\pm \\sqrt{b^2-4ac}",
"\\over 2a}.$$"
"$$", "x = {-b \\pm \\sqrt{b^2-4ac}", "\\over 2a}.$$"
};
std::string expected = "$$\nx = {-b \\pm \\sqrt{b^2-4ac}\n\\over 2a}.$$\n";

View File

@@ -13,7 +13,8 @@
TEST(MADDY_LINKPARSER, ItReplacesMarkdownWithALink)
{
std::string text = "Some text [Link Title](http://example.com)";
std::string expected = "Some text <a href=\"http://example.com\">Link Title</a>";
std::string expected =
"Some text <a href=\"http://example.com\">Link Title</a>";
auto linkParser = std::make_shared<maddy::LinkParser>();
linkParser->Parse(text);
@@ -23,8 +24,12 @@ TEST(MADDY_LINKPARSER, ItReplacesMarkdownWithALink)
TEST(MADDY_LINKPARSER, ItReplacesMarkdownWithLinks)
{
std::string text = "Some text [Link Title](http://example.com) bla [Link Title](http://example.com)";
std::string expected = "Some text <a href=\"http://example.com\">Link Title</a> bla <a href=\"http://example.com\">Link Title</a>";
std::string text =
"Some text [Link Title](http://example.com) bla [Link "
"Title](http://example.com)";
std::string expected =
"Some text <a href=\"http://example.com\">Link Title</a> bla <a "
"href=\"http://example.com\">Link Title</a>";
auto linkParser = std::make_shared<maddy::LinkParser>();
linkParser->Parse(text);
@@ -32,9 +37,152 @@ TEST(MADDY_LINKPARSER, ItReplacesMarkdownWithLinks)
ASSERT_EQ(expected, text);
}
TEST(MADDY_LINKPARSER, ItReplacesMarkdownWithSpacesAfterLink)
{
std::string text =
"Some text [Link Title](http://example.com ) bla [Link "
"Title](http://example.com)";
std::string expected =
"Some text <a href=\"http://example.com\">Link Title</a> bla <a "
"href=\"http://example.com\">Link Title</a>";
auto linkParser = std::make_shared<maddy::LinkParser>();
linkParser->Parse(text);
ASSERT_EQ(expected, text);
}
TEST(MADDY_LINKPARSER, ItHandlesURLsWithOfficiallyIllegalCharacters)
{
// Some links in the real world have characters that are not
// 'official' characters that are supposedly allowed in URLs.
std::string text =
"Wikipedia's [Möbius strip]"
"(https://en.wikipedia.org/wiki/Möbius_strip) link.";
std::string expected =
"Wikipedia's <a "
"href=\"https://en.wikipedia.org/wiki/Möbius_strip\">"
"Möbius strip</a> link.";
auto linkParser = std::make_shared<maddy::LinkParser>();
linkParser->Parse(text);
ASSERT_EQ(expected, text);
}
TEST(
MADDY_LINKPARSER, ItReplacesMarkdownProperlyEvenWithMultipleParenthesisInLine
)
{
std::string text =
"(This is a [link](/ABC/some_file) (the URL will not include this).)";
std::string expected =
"(This is a <a href=\"/ABC/some_file\">link</a> (the URL will not include "
"this).)";
auto linkParser = std::make_shared<maddy::LinkParser>();
linkParser->Parse(text);
ASSERT_EQ(expected, text);
}
TEST(MADDY_LINKPARSER, ItDoesntReplaceMarkdownWithSpaceInURL)
{
// Spaces are not allowed in URLs, so don't match them.
std::string text = "This is an invalid [link](/ABC/some file)";
std::string expected = "This is an invalid [link](/ABC/some file)";
auto linkParser = std::make_shared<maddy::LinkParser>();
linkParser->Parse(text);
ASSERT_EQ(expected, text);
}
TEST(MADDY_LINKPARSER, ItReplacesMarkdownWithTitleText)
{
std::string text = "Link to [name](http:://example.com \"title text\")";
std::string expected =
"Link to <a href=\"http:://example.com\" title=\"title text\">name</a>";
auto linkParser = std::make_shared<maddy::LinkParser>();
linkParser->Parse(text);
ASSERT_EQ(expected, text);
}
TEST(MADDY_LINKPARSER, ItReplacesMarkdownWithSpacesWithTitleText)
{
std::string text = "Link to [name](http:://example.com \"title text\")";
std::string expected =
"Link to <a href=\"http:://example.com\" title=\"title text\">name</a>";
auto linkParser = std::make_shared<maddy::LinkParser>();
linkParser->Parse(text);
ASSERT_EQ(expected, text);
}
TEST(MADDY_LINKPARSER, ItReplacesMarkdownWithMoreSpacesWithTitleText)
{
std::string text =
"Link to [name](http:://example.com \"title text\" )";
std::string expected =
"Link to <a href=\"http:://example.com\" title=\"title text\">name</a>";
auto linkParser = std::make_shared<maddy::LinkParser>();
linkParser->Parse(text);
ASSERT_EQ(expected, text);
}
TEST(MADDY_LINKPARSER, ItReplacesMarkdownWithParentheticalText)
{
std::string text = "Link to [name](http:://example.com \"title (text)\")";
std::string expected =
"Link to <a href=\"http:://example.com\" title=\"title (text)\">name</a>";
auto linkParser = std::make_shared<maddy::LinkParser>();
linkParser->Parse(text);
ASSERT_EQ(expected, text);
}
TEST(MADDY_LINKPARSER, ItDoesntReplaceMarkdownWithTooManyQuotes)
{
// If you have too many quotation marks, don't match:
std::string text =
"This is an invalid [link](/ABC/some_file \"title \" text \")";
std::string expected =
"This is an invalid [link](/ABC/some_file \"title \" text \")";
auto linkParser = std::make_shared<maddy::LinkParser>();
linkParser->Parse(text);
ASSERT_EQ(expected, text);
}
TEST(MADDY_LINKPARSER, ItDoesntReplaceMarkdownWithQuoteInLink)
{
// This is actually legal markdown, but hard to parse with regexes;
// See disabled 'ItReplacesMarkdownWithQuoteInLink' below.
//
// For now, don't try to translate it; it would produce invalid HTML.
std::string text = "Some text [Link Title](http://example.com/\"foo ) bla.";
std::string current_expected =
"Some text [Link Title](http://example.com/\"foo ) bla.";
std::string correct_expected =
"Some text <a href=\"http://example.com/%22foo\">Link Title</a> bla.";
auto linkParser = std::make_shared<maddy::LinkParser>();
linkParser->Parse(text);
ASSERT_EQ(current_expected, text);
}
// -----------------------------------------------------------------------------
class DISABLED_MADDY_LINKPARSER : public ::testing::Test { };
class DISABLED_MADDY_LINKPARSER : public ::testing::Test
{};
// This test is disabled for now, so make sure, to first run the ImageParser
// before using the LinkParser
@@ -48,3 +196,17 @@ TEST_F(DISABLED_MADDY_LINKPARSER, ItReplacesNoImageMarkdownWithLinks)
ASSERT_EQ(expected, text);
}
TEST(DISABLED_MADDY_LINKPARSER, ItReplacesMarkdownWithQuoteInLink)
{
// This is legal markdown, but hard to parse with regexes; dropping it
// here for a future update.
std::string text = "Some text [Link Title](http://example.com/\"foo ) bla.";
std::string expected =
"Some text <a href=\"http://example.com/%22foo\">Link Title</a> bla.";
auto linkParser = std::make_shared<maddy::LinkParser>();
linkParser->Parse(text);
ASSERT_EQ(expected, text);
}

View File

@@ -15,10 +15,10 @@ class MADDY_ORDEREDLISTPARSER : public ::testing::Test
protected:
std::shared_ptr<maddy::OrderedListParser> olParser;
void
SetUp() override
void SetUp() override
{
std::function<std::shared_ptr<maddy::BlockParser>(const std::string& line)> getBlockParserForLineCallback = [](const std::string& line)
std::function<std::shared_ptr<maddy::BlockParser>(const std::string& line)>
getBlockParserForLineCallback = [](const std::string& line)
{
if (maddy::OrderedListParser::IsStartingLine(line))
{
@@ -32,15 +32,16 @@ protected:
};
this->olParser = std::make_shared<maddy::OrderedListParser>(
nullptr,
getBlockParserForLineCallback
nullptr, getBlockParserForLineCallback
);
}
};
// -----------------------------------------------------------------------------
TEST_F(MADDY_ORDEREDLISTPARSER, IsStartingLineReturnsTrueWhenFacedWithBeginningOfList)
TEST_F(
MADDY_ORDEREDLISTPARSER, IsStartingLineReturnsTrueWhenFacedWithBeginningOfList
)
{
ASSERT_TRUE(maddy::OrderedListParser::IsStartingLine("1. a"));
}
@@ -52,11 +53,7 @@ TEST_F(MADDY_ORDEREDLISTPARSER, IsFinishedAlwaysReturnsFalseInTheBeginning)
TEST_F(MADDY_ORDEREDLISTPARSER, ItReplacesMarkdownWithAnHtmlOrderedList)
{
std::vector<std::string> markdown = {
"1. a"
, "* b"
, ""
};
std::vector<std::string> markdown = {"1. a", "* b", ""};
std::string expected = "<ol><li>a</li><li>b</li></ol>";
for (std::string md : markdown)
@@ -75,14 +72,11 @@ TEST_F(MADDY_ORDEREDLISTPARSER, ItReplacesMarkdownWithAnHtmlOrderedList)
TEST_F(MADDY_ORDEREDLISTPARSER, ItReplacesMarkdownWithAnHierachicalHtmlList)
{
std::vector<std::string> markdown = {
"1. a"
, " 1. d"
, " * e"
, "* b"
, " 1. c"
, ""
"1. a", " 1. d", " * e", "* b", " 1. c", ""
};
std::string expected = "<ol><li>a<ol><li>d</li><li>e</li></ol></li><li>b<ol><li>c</li></ol></li></ol>";
std::string expected =
"<ol><li>a<ol><li>d</li><li>e</li></ol></li><li>b<ol><li>c</li></ol></li></"
"ol>";
for (std::string md : markdown)
{
@@ -97,14 +91,11 @@ TEST_F(MADDY_ORDEREDLISTPARSER, ItReplacesMarkdownWithAnHierachicalHtmlList)
ASSERT_EQ(expected, outputString);
}
TEST_F(MADDY_ORDEREDLISTPARSER, ItReplacesNumberedMarkdownListWithAnHtmlOrderedList)
TEST_F(
MADDY_ORDEREDLISTPARSER, ItReplacesNumberedMarkdownListWithAnHtmlOrderedList
)
{
std::vector<std::string> markdown = {
"1. a"
, "94. b"
, "103. c"
, ""
};
std::vector<std::string> markdown = {"1. a", "94. b", "103. c", ""};
std::string expected = "<ol><li>a</li><li>b</li><li>c</li></ol>";
for (std::string md : markdown)

View File

@@ -15,14 +15,10 @@ class MADDY_PARAGRAPHPARSER : public ::testing::Test
protected:
std::shared_ptr<maddy::ParagraphParser> pParser;
void
SetUp() override
void SetUp() override
{
this->pParser = std::make_shared<maddy::ParagraphParser>(
nullptr,
nullptr,
true
);
this->pParser =
std::make_shared<maddy::ParagraphParser>(nullptr, nullptr, true);
}
};
@@ -40,11 +36,7 @@ TEST_F(MADDY_PARAGRAPHPARSER, IsFinishedReturnsFalseInTheBeginning)
TEST_F(MADDY_PARAGRAPHPARSER, ItReplacesMarkdownWithAnHtmlLine)
{
std::vector<std::string> markdown = {
"Some text"
, "and some other text"
, ""
};
std::vector<std::string> markdown = {"Some text", "and some other text", ""};
std::string expected = "<p>Some text and some other text </p>";
for (std::string md : markdown)

View File

@@ -3,10 +3,11 @@
* LICENSE file.
*/
#include "maddy/test_maddy_parser.h"
#include "gmock/gmock.h"
#include "maddy/parser.h"
#include "maddy/test_maddy_parser.h"
// -----------------------------------------------------------------------------
@@ -20,21 +21,6 @@ TEST(MADDY_PARSER, ItShouldParse)
ASSERT_EQ(testHtml, output);
}
TEST(MADDY_PARSER, ItShouldParseWithConfig)
{
auto config = std::make_shared<maddy::ParserConfig>();
config->isEmphasizedParserEnabled = false;
config->isHTMLWrappedInParagraph = false;
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, ItShouldParseWithBitwiseConfig)
{
auto config = std::make_shared<maddy::ParserConfig>();
@@ -53,8 +39,8 @@ TEST(MADDY_PARSER, ItShouldParseWithBitwiseConfig)
TEST(MADDY_PARSER, ItShouldParseWithSmallConfig)
{
auto config = std::make_shared<maddy::ParserConfig>();
config->enabledParsers = maddy::types::EMPHASIZED_PARSER |
maddy::types::STRONG_PARSER;
config->enabledParsers =
maddy::types::EMPHASIZED_PARSER | maddy::types::STRONG_PARSER;
auto parser = std::make_shared<maddy::Parser>(config);
@@ -70,7 +56,8 @@ TEST(MADDY_PARSER, ItShouldParseInlineCodeInHeadlines)
const std::string headlineTest = R"(
# Some **test** markdown
)";
const std::string expectedHTML = "<h1>Some <strong>test</strong> markdown</h1>";
const std::string expectedHTML =
"<h1>Some <strong>test</strong> markdown</h1>";
std::stringstream markdown(headlineTest);
auto parser = std::make_shared<maddy::Parser>();

View File

@@ -6,7 +6,8 @@
#include <string>
const std::string testMarkdown = "# This is a test\n\
const std::string testMarkdown =
"# This is a test\n\
\n\
This should result in a praragraph\n\
it's that simple.\n\
@@ -69,6 +70,71 @@ foot a|foot b|foot c\n\
\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 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/>";
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 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/>";

View File

@@ -15,19 +15,17 @@ class MADDY_QUOTEPARSER : public ::testing::Test
protected:
std::shared_ptr<maddy::QuoteParser> quoteParser;
void
SetUp() override
void SetUp() override
{
this->quoteParser = std::make_shared<maddy::QuoteParser>(
nullptr,
nullptr
);
this->quoteParser = std::make_shared<maddy::QuoteParser>(nullptr, nullptr);
}
};
// -----------------------------------------------------------------------------
TEST_F(MADDY_QUOTEPARSER, IsStartingLineReturnsTrueWhenFacedWithBeginningOfAQuote)
TEST_F(
MADDY_QUOTEPARSER, IsStartingLineReturnsTrueWhenFacedWithBeginningOfAQuote
)
{
ASSERT_TRUE(maddy::QuoteParser::IsStartingLine("> a"));
}
@@ -39,13 +37,7 @@ TEST_F(MADDY_QUOTEPARSER, IsFinishedAlwaysReturnsFalseInTheBeginning)
TEST_F(MADDY_QUOTEPARSER, ItReplacesMarkdownWithAnHtmlBlockQuote)
{
std::vector<std::string> markdown = {
"> a"
, "> b"
, ">"
, "> c"
, ""
};
std::vector<std::string> markdown = {"> a", "> b", ">", "> c", ""};
std::string expected = "<blockquote>a b c </blockquote>";
for (std::string md : markdown)

View File

@@ -23,8 +23,10 @@ TEST(MADDY_STRIKETHROUGHPARSER, ItReplacesMarkdownWithStrikeThroughHTML)
TEST(MADDY_STRIKETHROUGHPARSER, ItDoesNotParseInsideInlineCode)
{
std::string text = "some text `~~bla~~` ` ~~text~~ ` testing <code>~~it~~</code> out";
std::string expected = "some text `~~bla~~` ` ~~text~~ ` testing <code>~~it~~</code> out";
std::string text =
"some text `~~bla~~` ` ~~text~~ ` testing <code>~~it~~</code> out";
std::string expected =
"some text `~~bla~~` ` ~~text~~ ` testing <code>~~it~~</code> out";
auto strikeThroughParser = std::make_shared<maddy::StrikeThroughParser>();
strikeThroughParser->Parse(text);

View File

@@ -18,16 +18,11 @@ TEST(MADDY_STRONGPARSER, ItReplacesMarkdownWithStrongHTML)
std::string expected;
};
std::vector<testIt> tests
{
{
"some text **bla** text testing **it** out",
"some text <strong>bla</strong> text testing <strong>it</strong> out"
},
{
"some text __bla__ text testing __it__ out",
"some text <strong>bla</strong> text testing <strong>it</strong> out"
},
std::vector<testIt> tests{
{"some text **bla** text testing **it** out",
"some text <strong>bla</strong> text testing <strong>it</strong> out"},
{"some text __bla__ text testing __it__ out",
"some text <strong>bla</strong> text testing <strong>it</strong> out"},
};
auto strongParser = std::make_shared<maddy::StrongParser>();
@@ -47,16 +42,11 @@ TEST(MADDY_STRONGPARSER, ItReplacesEmphasizedMarkdownNotWithStrongHTML)
std::string expected;
};
std::vector<testIt> tests
{
{
"some text *bla* text testing **it** out",
"some text *bla* text testing <strong>it</strong> out"
},
{
"some text _bla_ text testing __it__ out",
"some text _bla_ text testing <strong>it</strong> out"
},
std::vector<testIt> tests{
{"some text *bla* text testing **it** out",
"some text *bla* text testing <strong>it</strong> out"},
{"some text _bla_ text testing __it__ out",
"some text _bla_ text testing <strong>it</strong> out"},
};
auto strongParser = std::make_shared<maddy::StrongParser>();
@@ -76,16 +66,13 @@ TEST(MADDY_STRONGPARSER, ItDoesNotParseInsideInlineCode)
std::string expected;
};
std::vector<testIt> tests
{
std::vector<testIt> tests{
{
"some text **bla** `/**text**/` testing `**it**` out",
"some text **bla** `/**text**/` testing `**it**` out",
},
{
"some text _bla_ text testing __it__ out",
"some text _bla_ text testing <strong>it</strong> out"
},
{"some text _bla_ text testing __it__ out",
"some text _bla_ text testing <strong>it</strong> out"},
};
auto strongParser = std::make_shared<maddy::StrongParser>();

View File

@@ -15,19 +15,17 @@ class MADDY_TABLEPARSER : public ::testing::Test
protected:
std::shared_ptr<maddy::TableParser> tableParser;
void
SetUp() override
void SetUp() override
{
this->tableParser = std::make_shared<maddy::TableParser>(
nullptr,
nullptr
);
this->tableParser = std::make_shared<maddy::TableParser>(nullptr, nullptr);
}
};
// -----------------------------------------------------------------------------
TEST_F(MADDY_TABLEPARSER, IsStartingLineReturnsTrueWhenFacedWithTheBeginningOfATable)
TEST_F(
MADDY_TABLEPARSER, IsStartingLineReturnsTrueWhenFacedWithTheBeginningOfATable
)
{
ASSERT_EQ(true, maddy::TableParser::IsStartingLine("|table>"));
}
@@ -40,16 +38,21 @@ TEST_F(MADDY_TABLEPARSER, IsFinishedReturnsFalseInTheBeginning)
TEST_F(MADDY_TABLEPARSER, ItReplacesMarkdownWithAnHtmlTable)
{
std::vector<std::string> markdown = {
"|table>"
, "Left header|middle header|last header"
, "- | - | -"
, "cell 1|cell 2|cell 3"
, "cell 4|cell 5|cell 6"
, "- | - | -"
, "foot a|foot b|foot c"
, "|<table"
"|table>",
"Left header|middle header|last header",
"- | - | -",
"cell 1|cell 2|cell 3",
"cell 4|cell 5|cell 6",
"- | - | -",
"foot a|foot b|foot c",
"|<table"
};
std::string expected = "<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 2</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>";
std::string expected =
"<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 2</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>";
for (std::string md : markdown)
{

View File

@@ -15,10 +15,10 @@ class MADDY_UNORDEREDLISTPARSER : public ::testing::Test
protected:
std::shared_ptr<maddy::UnorderedListParser> ulParser;
void
SetUp() override
void SetUp() override
{
std::function<std::shared_ptr<maddy::BlockParser>(const std::string& line)> getBlockParserForLineCallback = [](const std::string& line)
std::function<std::shared_ptr<maddy::BlockParser>(const std::string& line)>
getBlockParserForLineCallback = [](const std::string& line)
{
if (maddy::UnorderedListParser::IsStartingLine(line))
{
@@ -32,15 +32,17 @@ protected:
};
this->ulParser = std::make_shared<maddy::UnorderedListParser>(
nullptr,
getBlockParserForLineCallback
nullptr, getBlockParserForLineCallback
);
}
};
// -----------------------------------------------------------------------------
TEST_F(MADDY_UNORDEREDLISTPARSER, IsStartingLineReturnsTrueWhenFacedWithBeginningOfList)
TEST_F(
MADDY_UNORDEREDLISTPARSER,
IsStartingLineReturnsTrueWhenFacedWithBeginningOfList
)
{
ASSERT_TRUE(maddy::UnorderedListParser::IsStartingLine("* a"));
}
@@ -53,16 +55,11 @@ TEST_F(MADDY_UNORDEREDLISTPARSER, IsFinishedAlwaysReturnsFalseInTheBeginning)
TEST_F(MADDY_UNORDEREDLISTPARSER, ItReplacesMarkdownWithAnHtmlUnorderedList)
{
std::vector<std::string> markdown = {
"* a"
, "* b"
, "- c"
, "- d"
, "+ e"
, "+ f"
, "* g"
, ""
"* a", "* b", "- c", "- d", "+ e", "+ f", "* g", ""
};
std::string expected = "<ul><li>a</li><li>b</li><li>c</li><li>d</li><li>e</li><li>f</li><li>g</li></ul>";
std::string expected =
"<ul><li>a</li><li>b</li><li>c</li><li>d</li><li>e</li><li>f</li><li>g</"
"li></ul>";
for (std::string md : markdown)
{
@@ -80,17 +77,11 @@ TEST_F(MADDY_UNORDEREDLISTPARSER, ItReplacesMarkdownWithAnHtmlUnorderedList)
TEST_F(MADDY_UNORDEREDLISTPARSER, ItReplacesMarkdownWithAnHierachicalHtmlList)
{
std::vector<std::string> markdown = {
"* a"
, " * d"
, " * e"
, "* b"
, " * c"
, " + x"
, " + y"
, " - z"
, ""
"* a", " * d", " * e", "* b", " * c", " + x", " + y", " - z", ""
};
std::string expected = "<ul><li>a<ul><li>d</li><li>e</li></ul></li><li>b<ul><li>c</li><li>x</li><li>y</li><li>z</li></ul></li></ul>";
std::string expected =
"<ul><li>a<ul><li>d</li><li>e</li></ul></li><li>b<ul><li>c</li><li>x</"
"li><li>y</li><li>z</li></ul></li></ul>";
for (std::string md : markdown)
{

View File

@@ -7,7 +7,8 @@
// -----------------------------------------------------------------------------
int main (int argc, char** argv) {
int main(int argc, char** argv)
{
::testing::GTEST_FLAG(throw_on_failure) = true;
::testing::InitGoogleMock(&argc, argv);
return RUN_ALL_TESTS();

13
tools/Pipfile Normal file
View File

@@ -0,0 +1,13 @@
[[source]]
url = "https://pypi.org/simple"
verify_ssl = true
name = "pypi"
[packages]
requests = "*"
semver = "*"
[dev-packages]
[requires]
python_version = "3.11"

161
tools/Pipfile.lock generated Normal file
View File

@@ -0,0 +1,161 @@
{
"_meta": {
"hash": {
"sha256": "e4eebcb75452247f9b695017353c305be9aa186e543bd0e5a90391b52b337927"
},
"pipfile-spec": 6,
"requires": {
"python_version": "3.11"
},
"sources": [
{
"name": "pypi",
"url": "https://pypi.org/simple",
"verify_ssl": true
}
]
},
"default": {
"certifi": {
"hashes": [
"sha256:2e0c7ce7cb5d8f8634ca55d2ba7e6ec2689a2fd6537d8dec1296a477a4910057",
"sha256:d747aa5a8b9bbbb1bb8c22bb13e22bd1f18e9796defa16bab421f7f7a317323b"
],
"markers": "python_version >= '3.7'",
"version": "==2025.6.15"
},
"charset-normalizer": {
"hashes": [
"sha256:005fa3432484527f9732ebd315da8da8001593e2cf46a3d817669f062c3d9ed4",
"sha256:046595208aae0120559a67693ecc65dd75d46f7bf687f159127046628178dc45",
"sha256:0c29de6a1a95f24b9a1aa7aefd27d2487263f00dfd55a77719b530788f75cff7",
"sha256:0c8c57f84ccfc871a48a47321cfa49ae1df56cd1d965a09abe84066f6853b9c0",
"sha256:0f5d9ed7f254402c9e7d35d2f5972c9bbea9040e99cd2861bd77dc68263277c7",
"sha256:18dd2e350387c87dabe711b86f83c9c78af772c748904d372ade190b5c7c9d4d",
"sha256:1b1bde144d98e446b056ef98e59c256e9294f6b74d7af6846bf5ffdafd687a7d",
"sha256:1c95a1e2902a8b722868587c0e1184ad5c55631de5afc0eb96bc4b0d738092c0",
"sha256:1cad5f45b3146325bb38d6855642f6fd609c3f7cad4dbaf75549bf3b904d3184",
"sha256:21b2899062867b0e1fde9b724f8aecb1af14f2778d69aacd1a5a1853a597a5db",
"sha256:24498ba8ed6c2e0b56d4acbf83f2d989720a93b41d712ebd4f4979660db4417b",
"sha256:25a23ea5c7edc53e0f29bae2c44fcb5a1aa10591aae107f2a2b2583a9c5cbc64",
"sha256:289200a18fa698949d2b39c671c2cc7a24d44096784e76614899a7ccf2574b7b",
"sha256:28a1005facc94196e1fb3e82a3d442a9d9110b8434fc1ded7a24a2983c9888d8",
"sha256:32fc0341d72e0f73f80acb0a2c94216bd704f4f0bce10aedea38f30502b271ff",
"sha256:36b31da18b8890a76ec181c3cf44326bf2c48e36d393ca1b72b3f484113ea344",
"sha256:3c21d4fca343c805a52c0c78edc01e3477f6dd1ad7c47653241cf2a206d4fc58",
"sha256:3fddb7e2c84ac87ac3a947cb4e66d143ca5863ef48e4a5ecb83bd48619e4634e",
"sha256:43e0933a0eff183ee85833f341ec567c0980dae57c464d8a508e1b2ceb336471",
"sha256:4a476b06fbcf359ad25d34a057b7219281286ae2477cc5ff5e3f70a246971148",
"sha256:4e594135de17ab3866138f496755f302b72157d115086d100c3f19370839dd3a",
"sha256:50bf98d5e563b83cc29471fa114366e6806bc06bc7a25fd59641e41445327836",
"sha256:5a9979887252a82fefd3d3ed2a8e3b937a7a809f65dcb1e068b090e165bbe99e",
"sha256:5baececa9ecba31eff645232d59845c07aa030f0c81ee70184a90d35099a0e63",
"sha256:5bf4545e3b962767e5c06fe1738f951f77d27967cb2caa64c28be7c4563e162c",
"sha256:6333b3aa5a12c26b2a4d4e7335a28f1475e0e5e17d69d55141ee3cab736f66d1",
"sha256:65c981bdbd3f57670af8b59777cbfae75364b483fa8a9f420f08094531d54a01",
"sha256:68a328e5f55ec37c57f19ebb1fdc56a248db2e3e9ad769919a58672958e8f366",
"sha256:6a0289e4589e8bdfef02a80478f1dfcb14f0ab696b5a00e1f4b8a14a307a3c58",
"sha256:6b66f92b17849b85cad91259efc341dce9c1af48e2173bf38a85c6329f1033e5",
"sha256:6c9379d65defcab82d07b2a9dfbfc2e95bc8fe0ebb1b176a3190230a3ef0e07c",
"sha256:6fc1f5b51fa4cecaa18f2bd7a003f3dd039dd615cd69a2afd6d3b19aed6775f2",
"sha256:70f7172939fdf8790425ba31915bfbe8335030f05b9913d7ae00a87d4395620a",
"sha256:721c76e84fe669be19c5791da68232ca2e05ba5185575086e384352e2c309597",
"sha256:7222ffd5e4de8e57e03ce2cef95a4c43c98fcb72ad86909abdfc2c17d227fc1b",
"sha256:75d10d37a47afee94919c4fab4c22b9bc2a8bf7d4f46f87363bcf0573f3ff4f5",
"sha256:76af085e67e56c8816c3ccf256ebd136def2ed9654525348cfa744b6802b69eb",
"sha256:770cab594ecf99ae64c236bc9ee3439c3f46be49796e265ce0cc8bc17b10294f",
"sha256:7a6ab32f7210554a96cd9e33abe3ddd86732beeafc7a28e9955cdf22ffadbab0",
"sha256:7c48ed483eb946e6c04ccbe02c6b4d1d48e51944b6db70f697e089c193404941",
"sha256:7f56930ab0abd1c45cd15be65cc741c28b1c9a34876ce8c17a2fa107810c0af0",
"sha256:8075c35cd58273fee266c58c0c9b670947c19df5fb98e7b66710e04ad4e9ff86",
"sha256:8272b73e1c5603666618805fe821edba66892e2870058c94c53147602eab29c7",
"sha256:82d8fd25b7f4675d0c47cf95b594d4e7b158aca33b76aa63d07186e13c0e0ab7",
"sha256:844da2b5728b5ce0e32d863af26f32b5ce61bc4273a9c720a9f3aa9df73b1455",
"sha256:8755483f3c00d6c9a77f490c17e6ab0c8729e39e6390328e42521ef175380ae6",
"sha256:915f3849a011c1f593ab99092f3cecfcb4d65d8feb4a64cf1bf2d22074dc0ec4",
"sha256:926ca93accd5d36ccdabd803392ddc3e03e6d4cd1cf17deff3b989ab8e9dbcf0",
"sha256:982bb1e8b4ffda883b3d0a521e23abcd6fd17418f6d2c4118d257a10199c0ce3",
"sha256:98f862da73774290f251b9df8d11161b6cf25b599a66baf087c1ffe340e9bfd1",
"sha256:9cbfacf36cb0ec2897ce0ebc5d08ca44213af24265bd56eca54bee7923c48fd6",
"sha256:a370b3e078e418187da8c3674eddb9d983ec09445c99a3a263c2011993522981",
"sha256:a955b438e62efdf7e0b7b52a64dc5c3396e2634baa62471768a64bc2adb73d5c",
"sha256:aa6af9e7d59f9c12b33ae4e9450619cf2488e2bbe9b44030905877f0b2324980",
"sha256:aa88ca0b1932e93f2d961bf3addbb2db902198dca337d88c89e1559e066e7645",
"sha256:aaeeb6a479c7667fbe1099af9617c83aaca22182d6cf8c53966491a0f1b7ffb7",
"sha256:aaf27faa992bfee0264dc1f03f4c75e9fcdda66a519db6b957a3f826e285cf12",
"sha256:b2680962a4848b3c4f155dc2ee64505a9c57186d0d56b43123b17ca3de18f0fa",
"sha256:b2d318c11350e10662026ad0eb71bb51c7812fc8590825304ae0bdd4ac283acd",
"sha256:b33de11b92e9f75a2b545d6e9b6f37e398d86c3e9e9653c4864eb7e89c5773ef",
"sha256:b3daeac64d5b371dea99714f08ffc2c208522ec6b06fbc7866a450dd446f5c0f",
"sha256:be1e352acbe3c78727a16a455126d9ff83ea2dfdcbc83148d2982305a04714c2",
"sha256:bee093bf902e1d8fc0ac143c88902c3dfc8941f7ea1d6a8dd2bcb786d33db03d",
"sha256:c72fbbe68c6f32f251bdc08b8611c7b3060612236e960ef848e0a517ddbe76c5",
"sha256:c9e36a97bee9b86ef9a1cf7bb96747eb7a15c2f22bdb5b516434b00f2a599f02",
"sha256:cddf7bd982eaa998934a91f69d182aec997c6c468898efe6679af88283b498d3",
"sha256:cf713fe9a71ef6fd5adf7a79670135081cd4431c2943864757f0fa3a65b1fafd",
"sha256:d11b54acf878eef558599658b0ffca78138c8c3655cf4f3a4a673c437e67732e",
"sha256:d41c4d287cfc69060fa91cae9683eacffad989f1a10811995fa309df656ec214",
"sha256:d524ba3f1581b35c03cb42beebab4a13e6cdad7b36246bd22541fa585a56cccd",
"sha256:daac4765328a919a805fa5e2720f3e94767abd632ae410a9062dff5412bae65a",
"sha256:db4c7bf0e07fc3b7d89ac2a5880a6a8062056801b83ff56d8464b70f65482b6c",
"sha256:dc7039885fa1baf9be153a0626e337aa7ec8bf96b0128605fb0d77788ddc1681",
"sha256:dccab8d5fa1ef9bfba0590ecf4d46df048d18ffe3eec01eeb73a42e0d9e7a8ba",
"sha256:dedb8adb91d11846ee08bec4c8236c8549ac721c245678282dcb06b221aab59f",
"sha256:e45ba65510e2647721e35323d6ef54c7974959f6081b58d4ef5d87c60c84919a",
"sha256:e53efc7c7cee4c1e70661e2e112ca46a575f90ed9ae3fef200f2a25e954f4b28",
"sha256:e635b87f01ebc977342e2697d05b56632f5f879a4f15955dfe8cef2448b51691",
"sha256:e70e990b2137b29dc5564715de1e12701815dacc1d056308e2b17e9095372a82",
"sha256:e8082b26888e2f8b36a042a58307d5b917ef2b1cacab921ad3323ef91901c71a",
"sha256:e8323a9b031aa0393768b87f04b4164a40037fb2a3c11ac06a03ffecd3618027",
"sha256:e92fca20c46e9f5e1bb485887d074918b13543b1c2a1185e69bb8d17ab6236a7",
"sha256:eb30abc20df9ab0814b5a2524f23d75dcf83cde762c161917a2b4b7b55b1e518",
"sha256:eba9904b0f38a143592d9fc0e19e2df0fa2e41c3c3745554761c5f6447eedabf",
"sha256:ef8de666d6179b009dce7bcb2ad4c4a779f113f12caf8dc77f0162c29d20490b",
"sha256:efd387a49825780ff861998cd959767800d54f8308936b21025326de4b5a42b9",
"sha256:f0aa37f3c979cf2546b73e8222bbfa3dc07a641585340179d768068e3455e544",
"sha256:f4074c5a429281bf056ddd4c5d3b740ebca4d43ffffe2ef4bf4d2d05114299da",
"sha256:f69a27e45c43520f5487f27627059b64aaf160415589230992cec34c5e18a509",
"sha256:fb707f3e15060adf5b7ada797624a6c6e0138e2a26baa089df64c68ee98e040f",
"sha256:fcbe676a55d7445b22c10967bceaaf0ee69407fbe0ece4d032b6eb8d4565982a",
"sha256:fdb20a30fe1175ecabed17cbf7812f7b804b8a315a25f24678bcdf120a90077f"
],
"markers": "python_version >= '3.7'",
"version": "==3.4.2"
},
"idna": {
"hashes": [
"sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9",
"sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3"
],
"markers": "python_version >= '3.6'",
"version": "==3.10"
},
"requests": {
"hashes": [
"sha256:27babd3cda2a6d50b30443204ee89830707d396671944c998b5975b031ac2b2c",
"sha256:27d0316682c8a29834d3264820024b62a36942083d52caf2f14c0591336d3422"
],
"index": "pypi",
"markers": "python_version >= '3.8'",
"version": "==2.32.4"
},
"semver": {
"hashes": [
"sha256:9c824d87ba7f7ab4a1890799cec8596f15c1241cb473404ea1cb0c55e4b04746",
"sha256:afc7d8c584a5ed0a11033af086e8af226a9c0b206f313e0301f8dd7b6b589602"
],
"index": "pypi",
"markers": "python_version >= '3.7'",
"version": "==3.0.4"
},
"urllib3": {
"hashes": [
"sha256:3fc47733c7e419d4bc3f6b3dc2b4f890bb743906a30d56ba4a5bfa4bbff92760",
"sha256:e6b01673c0fa6a13e374b50871808eb3bf7046c4b125b216f6bf1cc604cff0dc"
],
"markers": "python_version >= '3.9'",
"version": "==2.5.0"
}
},
"develop": {}
}

149
tools/format.py Normal file
View File

@@ -0,0 +1,149 @@
import glob
import os
import shlex
import subprocess
import sys
# required clang-format version
REQUIRED_VERSION = '18.1.3'
def check_clang_format_version():
"""
Check if the installed clang-format version matches the required version.
Raises:
SystemExit: If the version does not match the required version or if
there is an error checking the version.
"""
try:
result = subprocess.run(
['clang-format', '--version'],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
text=True,
check=True
)
version_out = result.stdout.strip().split()
version_line = '0.0.0'
is_next = False
for vo in version_out:
if vo == 'version':
is_next = True
continue
if is_next:
version_line = vo
break
if version_line != REQUIRED_VERSION:
print(f'Error: Required clang-format version is '
f'{REQUIRED_VERSION}, but found {version_line}.')
sys.exit(1)
else:
print('clang-format version equals the required version.')
except subprocess.CalledProcessError as e:
print(f'Error checking clang-format version: {e.stderr}')
sys.exit(1)
def format_files(dry_run):
"""
Format .h and .cpp files in specified directories using clang-format.
Args:
dry_run (bool): If True, performs a dry run to check for formatting
issues without modifying files. If False, formats
the files in place.
Raises:
subprocess.CalledProcessError: If there is an error running clang-format
during the actual formatting process.
"""
patterns = [
'bench/**/*.h',
'bench/**/*.cpp',
'include/**/*.h',
'tests/**/*.h',
'tests/**/*.cpp',
]
files_to_format = []
for pattern in patterns:
matched_files = glob.glob(pattern, recursive=True)
for file in matched_files:
if '\/tmp\/' in file or '\\tmp\\' in file:
matched_files.remove(file)
files_to_format.extend(matched_files)
if not files_to_format:
print('No files to format.')
return
patterns_arg = ' '.join(file.replace('\\', '/') for file in files_to_format)
cwd = os.getcwd()
if dry_run:
# Check for changes without modifying the files
command = f'clang-format --style=file --dry-run --Werror {patterns_arg}'
result = subprocess.run(
shlex.split(command),
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
text=True,
cwd=cwd
)
if result.returncode != 0:
print('Files that need formatting:')
print(result.stdout)
print('Error output:')
print(result.stderr)
sys.exit(1)
else:
print('no changes found')
else:
# Format the files in place
command = f'clang-format --style=file -i {patterns_arg}'
result = subprocess.run(
shlex.split(command),
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
text=True,
cwd=cwd
)
if result.returncode != 0:
print('Error formatting files:')
print(result.stderr)
sys.exit(1)
else:
print('formatting done')
def main():
"""
Main function to handle command-line arguments and invoke formatting.
Checks for the required command-line argument, verifies the clang-format
version, and calls the format_files function to format the code.
"""
if len(sys.argv) != 2:
print(
'Usage: python format.py <dry_run|format>'
)
sys.exit(1)
else:
print(f'Running format with {sys.argv[1]}')
dry_run = False
if sys.argv[1] == 'dry_run':
dry_run = True
elif sys.argv[1] != 'format':
print('Invalid argument. Use "dry_run" or "format".')
sys.exit(1)
check_clang_format_version()
format_files(dry_run)
if __name__ == '__main__':
main()

View File

@@ -0,0 +1,146 @@
#!/bin/python
#
# maddy update dependencies
#
# This project is licensed under the MIT license. For more information see the
# LICENSE file.
import os
import re
import requests
import sys
def get_cmake_files(directory, ignored_dirs=None):
"""
Recursively searches for all CMakeLists.txt files in the specified directory,
ignoring specified subdirectories.
Args:
directory (str): The path to the directory to search for CMakeLists.txt files.
ignored_dirs (list): A list of directory names to ignore during the search.
Returns:
list: A list of full paths to all found CMakeLists.txt files.
"""
cmakelists_paths = []
ignored_dirs = ignored_dirs or []
for root, dirs, files in os.walk(directory):
# Modify dirs in place to skip ignored directories
dirs[:] = [d for d in dirs if d not in ignored_dirs]
if 'CMakeLists.txt' in files:
cmakelists_paths.append(os.path.join(root, 'CMakeLists.txt'))
return cmakelists_paths
def get_last_dependency_version(url):
"""
Retrieves the latest release version tag from a specified GitHub repository.
Args:
url (str): The URL of the GitHub repository in the format
'https://github.com/owner/repo.git' or 'https://github.com/owner/repo'.
Returns:
str: The latest release version tag (e.g., 'v1.2.3') if found,
or raises an Exception if the repository is not found or
if there is an error in the API request.
Raises:
ValueError: If the provided URL is not in the expected format.
Exception: If there is an error fetching data from the GitHub API.
"""
if url.endswith('.git'):
url = url[:-4]
parts = url.split('/')
if len(parts) < 5 or parts[2] != 'github.com':
raise ValueError(f'Invalid GitHub repository URL {url}')
owner = parts[3]
repo = parts[4]
api_url = f'https://api.github.com/repos/{owner}/{repo}/releases/latest'
response = requests.get(api_url)
if response.status_code == 200:
release_data = response.json()
return release_data['tag_name'] # Return the latest version tag
else:
raise Exception(f'Error fetching data from GitHub API: {response.status_code} - {response.text}')
def get_current_version_from_fetch_content(cmake_code):
"""
Extracts the currently used Git tag from a FetchContent call in CMake code.
Args:
cmake_code (str): The CMake code containing the FetchContent call.
Returns:
str: The Git tag used in the FetchContent call, or None if not found.
"""
# Regular expression to match FetchContent_Declare and capture the GIT_TAG argument
pattern = r'FetchContent_Declare\s*\(\s*[^)]+\s*GIT_TAG\s+([^\s)]+)'
match = re.search(pattern, cmake_code)
if match:
return match.group(1) # Return the captured Git tag
return None
def update_fetch_content_versions(cmake_file_path):
"""
Updates the FetchContent blocks in a CMakeLists.txt file to use the latest
version from the corresponding GitHub repositories.
Args:
cmake_file_path (str): The path to the CMakeLists.txt file to be updated.
"""
with open(cmake_file_path, 'r') as file:
cmake_code = file.read()
fetch_content_pattern = r'FetchContent_Declare\s*\(\s*(.*?)\s*\)'
fetch_content_blocks = re.findall(fetch_content_pattern, cmake_code, re.DOTALL)
for block in fetch_content_blocks:
repo_pattern = r'GIT_REPOSITORY\s+([^\s]+)'
repo_match = re.search(repo_pattern, block)
if repo_match:
repo_url = repo_match.group(1)
current_version = get_current_version_from_fetch_content(block)
latest_version = get_last_dependency_version(repo_url)
if current_version != latest_version:
new_block = re.sub(r'GIT_TAG\s+([^\s]+)', f'GIT_TAG {latest_version}', block)
cmake_code = cmake_code.replace(block, new_block)
with open(cmake_file_path, 'w', encoding='utf-8', newline='\n') as file:
file.write(cmake_code.replace('\r\n', '\n'))
def main():
"""
Main function to update FetchContent versions in CMakeLists.txt files.
It takes a directory path as an argument and processes all CMakeLists.txt files found,
ignoring specified directories.
"""
if len(sys.argv) < 2:
print('Usage: python update_dependencies.py <directory_path> [ignored_dirs...]')
sys.exit(1)
directory_path = sys.argv[1]
ignored_dirs = sys.argv[2:] # Remaining arguments are ignored directories
if not os.path.isdir(directory_path):
print(f'The provided path "{directory_path}" is not a valid directory.')
sys.exit(1)
cmake_files = get_cmake_files(directory_path, ignored_dirs)
for cmake_file in cmake_files:
print(f'Updating {cmake_file}...')
update_fetch_content_versions(cmake_file)
print(f'Updated {cmake_file} successfully.')
if __name__ == '__main__':
main()

89
tools/update_version.py Normal file
View File

@@ -0,0 +1,89 @@
#!/bin/python
#
# maddy update version
#
# Replaces the version in all files in the lines containing
# `MADDY_VERSION_LINE_REPLACEMENT`.
#
# This project is licensed under the MIT license. For more information see the
# LICENSE file.
import mimetypes
import os
import re
from semver import Version
import sys
def update_version_in_file(version, file_path):
"""
Updates the version in the specified file.
Args:
file_path (str): The path to the file where the version needs to be updated.
version (str): The new version string to set in the file.
"""
with open(file_path, 'r') as file:
content = file.read()
new_content = content
lines = new_content.splitlines()
for i, line in enumerate(lines):
if 'MADDY_VERSION_LINE_REPLACEMENT' in line:
lines[i] = re.sub(r'\b\d+\.\d+\.\d+\b', version, line)
new_content = '\n'.join(lines) + '\n'
if new_content != content:
print(f'Updating version in {file_path}')
with open(file_path, 'w', encoding='utf-8', newline='\n') as file:
file.write(new_content.replace('\r\n', '\n'))
def update_version_in_files(version, directory, ignored_dirs):
"""
Updates the version in all files in the specified directory.
Args:
directory (str): The path to the directory containing files.
ignored_dirs (list): A list of directories to ignore during the update.
version (str): The new version string to set in the files.
"""
mimetypes.add_type('text/markdown', '.md')
ignroed_dirs_abs = [os.path.abspath(os.path.join(directory, d)) for d in ignored_dirs]
for root, dirs, files in os.walk(directory):
for file in files:
file_path = os.path.join(root, file)
if any(os.path.abspath(root).startswith(ignored_dir) for ignored_dir in ignroed_dirs_abs):
continue
if mimetypes.guess_type(file_path)[0] and mimetypes.guess_type(file_path)[0].startswith('text'):
update_version_in_file(version, file_path)
def main():
if len(sys.argv) < 3:
print('Usage: python update_version.py <version> <directory> [ignored_dirs...]')
sys.exit(1)
version = sys.argv[1]
directory = sys.argv[2]
ignored_dirs = sys.argv[3:] if len(sys.argv) > 3 else []
if not os.path.isdir(directory):
print(f'Error: The specified directory "{directory}" does not exist.')
sys.exit(1)
if not Version.is_valid(version):
print(f'Error: The specified version "{version}" is not a valid semantic version.')
sys.exit(1)
update_version_in_files(version, directory, ignored_dirs)
print(f'Updated version to {version} in all files in {directory}')
if __name__ == '__main__':
main()